summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--context/data/cont-pe-scite.properties97
-rw-r--r--context/data/context-bbedit-pe.xml1
-rw-r--r--context/data/context-jedit-pe.xml2
-rw-r--r--context/data/context.properties30
-rw-r--r--doc/context/bib/bibmod-doc.pdfbin281102 -> 284752 bytes
-rw-r--r--doc/context/bib/bibmod-doc.tex8
-rw-r--r--fonts/enc/dvips/context/lm-ec-os.enc258
-rw-r--r--fonts/enc/dvips/context/lm-qx-os.enc258
-rw-r--r--fonts/enc/dvips/context/lm-qxtt-os.enc258
-rw-r--r--fonts/enc/dvips/context/lm-t5-os.enc258
-rw-r--r--fonts/enc/dvips/context/q-8r.enc (renamed from fonts/enc/dvips/context/lm-texnansi-os.enc)136
-rw-r--r--fonts/map/dvips/context/contnav.map1
-rw-r--r--fonts/map/dvips/jmn/hans.map2
-rw-r--r--fonts/map/pdftex/context/cs-qbk.map15
-rw-r--r--fonts/map/pdftex/context/cs-qcs.map15
-rw-r--r--fonts/map/pdftex/context/cs-qpl.map15
-rw-r--r--fonts/map/pdftex/context/cs-qtm.map15
-rw-r--r--fonts/map/pdftex/context/ec-public-lm.map3
-rw-r--r--fonts/map/pdftex/context/ec-qbk.map15
-rw-r--r--fonts/map/pdftex/context/ec-qcs.map15
-rw-r--r--fonts/map/pdftex/context/ec-qpl.map15
-rw-r--r--fonts/map/pdftex/context/ec-qtm.map15
-rw-r--r--fonts/map/pdftex/context/el-public-lm.map3
-rw-r--r--fonts/map/pdftex/context/el-qbk.map15
-rw-r--r--fonts/map/pdftex/context/el-qcs.map15
-rw-r--r--fonts/map/pdftex/context/el-qpl.map15
-rw-r--r--fonts/map/pdftex/context/el-qtm.map15
-rw-r--r--fonts/map/pdftex/context/l7x-qbk.map15
-rw-r--r--fonts/map/pdftex/context/l7x-qcs.map15
-rw-r--r--fonts/map/pdftex/context/l7x-qpl.map15
-rw-r--r--fonts/map/pdftex/context/l7x-qtm.map15
-rw-r--r--fonts/map/pdftex/context/original-youngryu-px.map17
-rw-r--r--fonts/map/pdftex/context/original-youngryu-tx.map31
-rw-r--r--fonts/map/pdftex/context/qx-public-lm.map3
-rw-r--r--fonts/map/pdftex/context/qx-qbk.map15
-rw-r--r--fonts/map/pdftex/context/qx-qcs.map15
-rw-r--r--fonts/map/pdftex/context/qx-qpl.map15
-rw-r--r--fonts/map/pdftex/context/qx-qtm.map15
-rw-r--r--fonts/map/pdftex/context/rm-qbk.map15
-rw-r--r--fonts/map/pdftex/context/rm-qcs.map15
-rw-r--r--fonts/map/pdftex/context/rm-qpl.map15
-rw-r--r--fonts/map/pdftex/context/rm-qtm.map15
-rw-r--r--fonts/map/pdftex/context/t2a-qbk.map11
-rw-r--r--fonts/map/pdftex/context/t2a-qcs.map11
-rw-r--r--fonts/map/pdftex/context/t2a-qpl.map11
-rw-r--r--fonts/map/pdftex/context/t2a-qtm.map11
-rw-r--r--fonts/map/pdftex/context/t2b-qbk.map11
-rw-r--r--fonts/map/pdftex/context/t2b-qcs.map11
-rw-r--r--fonts/map/pdftex/context/t2b-qpl.map11
-rw-r--r--fonts/map/pdftex/context/t2b-qtm.map11
-rw-r--r--fonts/map/pdftex/context/t2c-qbk.map11
-rw-r--r--fonts/map/pdftex/context/t2c-qcs.map11
-rw-r--r--fonts/map/pdftex/context/t2c-qpl.map11
-rw-r--r--fonts/map/pdftex/context/t2c-qtm.map11
-rw-r--r--fonts/map/pdftex/context/t5-public-lm.map3
-rw-r--r--fonts/map/pdftex/context/t5-qbk.map15
-rw-r--r--fonts/map/pdftex/context/t5-qcs.map15
-rw-r--r--fonts/map/pdftex/context/t5-qpl.map15
-rw-r--r--fonts/map/pdftex/context/t5-qtm.map15
-rw-r--r--fonts/map/pdftex/context/texnansi-public-lm.map3
-rw-r--r--fonts/map/pdftex/context/texnansi-qbk.map15
-rw-r--r--fonts/map/pdftex/context/texnansi-qcs.map15
-rw-r--r--fonts/map/pdftex/context/texnansi-qpl.map15
-rw-r--r--fonts/map/pdftex/context/texnansi-qtm.map15
-rw-r--r--fonts/map/pdftex/context/ts1-qbk.map11
-rw-r--r--fonts/map/pdftex/context/ts1-qcs.map11
-rw-r--r--fonts/map/pdftex/context/ts1-qpl.map11
-rw-r--r--fonts/map/pdftex/context/ts1-qtm.map11
-rw-r--r--metapost/context/base/metafun.mp2
-rw-r--r--metapost/context/base/mp-chem.mp729
-rw-r--r--metapost/context/base/mp-core.mp125
-rw-r--r--metapost/context/base/mp-mlib.mp90
-rw-r--r--metapost/context/base/mp-page.mp2
-rw-r--r--metapost/context/base/mp-text.mp3
-rw-r--r--metapost/context/base/mp-tool.mp58
-rw-r--r--scripts/context/lua/luatools.lua7435
-rw-r--r--scripts/context/lua/mtx-babel.lua18
-rw-r--r--scripts/context/lua/mtx-cache.lua4
-rw-r--r--scripts/context/lua/mtx-chars.lua306
-rw-r--r--scripts/context/lua/mtx-check.lua43
-rw-r--r--scripts/context/lua/mtx-context.lua979
-rw-r--r--scripts/context/lua/mtx-convert.lua8
-rw-r--r--scripts/context/lua/mtx-fonts.lua117
-rw-r--r--scripts/context/lua/mtx-grep.lua106
-rw-r--r--scripts/context/lua/mtx-interface.lua64
-rw-r--r--scripts/context/lua/mtx-metatex.lua69
-rw-r--r--scripts/context/lua/mtx-mptopdf.lua24
-rw-r--r--scripts/context/lua/mtx-package.lua68
-rw-r--r--scripts/context/lua/mtx-patterns.lua101
-rw-r--r--scripts/context/lua/mtx-profile.lua164
-rw-r--r--scripts/context/lua/mtx-server-ctx-fonttest.lua681
-rw-r--r--scripts/context/lua/mtx-server-ctx-help.lua648
-rw-r--r--scripts/context/lua/mtx-server-ctx-startup.lua53
-rw-r--r--scripts/context/lua/mtx-server.lua132
-rw-r--r--scripts/context/lua/mtx-timing.lua201
-rw-r--r--scripts/context/lua/mtx-unzip.lua101
-rw-r--r--scripts/context/lua/mtx-update.lua419
-rw-r--r--scripts/context/lua/mtx-watch.lua24
-rw-r--r--scripts/context/lua/mtxrun.lua11027
-rw-r--r--scripts/context/lua/x-ldx.lua4
-rw-r--r--scripts/context/ruby/base/exa.rb9
-rw-r--r--scripts/context/ruby/base/file.rb7
-rw-r--r--scripts/context/ruby/base/kpse.rb8
-rw-r--r--scripts/context/ruby/base/state.rb4
-rw-r--r--scripts/context/ruby/base/tex.rb176
-rw-r--r--scripts/context/ruby/base/texutil.rb33
-rw-r--r--scripts/context/ruby/base/tool.rb15
-rw-r--r--scripts/context/ruby/ctxtools.rb4
-rw-r--r--scripts/context/ruby/fcd_start.rb19
-rw-r--r--scripts/context/ruby/graphics/gs.rb20
-rw-r--r--scripts/context/ruby/pdftools.rb3
-rw-r--r--scripts/context/ruby/rlxtools.rb3
-rw-r--r--scripts/context/ruby/rsfiltool.rb3
-rw-r--r--scripts/context/ruby/runtools.rb3
-rw-r--r--scripts/context/ruby/texexec.rb8
-rw-r--r--scripts/context/ruby/texmfstart.rb1261
-rw-r--r--scripts/context/ruby/textools.rb3
-rw-r--r--scripts/context/ruby/www/admin.rb215
-rw-r--r--scripts/context/ruby/www/common.rb80
-rw-r--r--scripts/context/ruby/www/dir.rb155
-rw-r--r--scripts/context/ruby/www/exa.rb387
-rw-r--r--scripts/context/ruby/www/lib.rb1405
-rw-r--r--scripts/context/ruby/www/login.rb13
-rw-r--r--scripts/context/ruby/wwwclient.rb677
-rw-r--r--scripts/context/ruby/wwwserver.rb293
-rw-r--r--scripts/context/ruby/wwwwatch.rb497
-rwxr-xr-xscripts/context/stubs/mswin/ctxtools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/exatools.bat2
-rw-r--r--scripts/context/stubs/mswin/luatools.lua6977
-rwxr-xr-xscripts/context/stubs/mswin/makempy.bat5
-rw-r--r--scripts/context/stubs/mswin/metatex.cmd5
-rwxr-xr-xscripts/context/stubs/mswin/mpstools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/mptopdf.bat5
-rw-r--r--scripts/context/stubs/mswin/mtxrun.lua10190
-rwxr-xr-xscripts/context/stubs/mswin/mtxtools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/pdftools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/pdftrimwhite.bat2
-rwxr-xr-xscripts/context/stubs/mswin/pstopdf.bat5
-rwxr-xr-xscripts/context/stubs/mswin/rlxtools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/runtools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/texexec.bat5
-rw-r--r--scripts/context/stubs/mswin/texexec.cmd5
-rwxr-xr-xscripts/context/stubs/mswin/texfind.bat2
-rwxr-xr-xscripts/context/stubs/mswin/texfont.bat5
-rw-r--r--scripts/context/stubs/mswin/texmfstart.cmd5
-rwxr-xr-xscripts/context/stubs/mswin/texshow.bat2
-rwxr-xr-xscripts/context/stubs/mswin/textools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/texutil.bat5
-rwxr-xr-xscripts/context/stubs/mswin/tmftools.bat5
-rwxr-xr-xscripts/context/stubs/mswin/xmltools.bat5
-rwxr-xr-xscripts/context/stubs/unix/ctxtools2
-rwxr-xr-xscripts/context/stubs/unix/exatools2
-rwxr-xr-xscripts/context/stubs/unix/luatools6977
-rwxr-xr-xscripts/context/stubs/unix/makempy2
-rwxr-xr-xscripts/context/stubs/unix/metatex2
-rwxr-xr-xscripts/context/stubs/unix/mpstools2
-rwxr-xr-xscripts/context/stubs/unix/mptopdf2
-rwxr-xr-xscripts/context/stubs/unix/mtxrun10190
-rwxr-xr-xscripts/context/stubs/unix/mtxtools2
-rwxr-xr-xscripts/context/stubs/unix/pdftools2
-rwxr-xr-xscripts/context/stubs/unix/pdftrimwhite2
-rwxr-xr-xscripts/context/stubs/unix/pstopdf2
-rwxr-xr-xscripts/context/stubs/unix/rlxtools2
-rwxr-xr-xscripts/context/stubs/unix/runtools2
-rwxr-xr-xscripts/context/stubs/unix/texexec2
-rwxr-xr-xscripts/context/stubs/unix/texfind2
-rwxr-xr-xscripts/context/stubs/unix/texfont2
-rwxr-xr-xscripts/context/stubs/unix/texmfstart2
-rwxr-xr-xscripts/context/stubs/unix/texshow2
-rwxr-xr-xscripts/context/stubs/unix/textools2
-rwxr-xr-xscripts/context/stubs/unix/texutil2
-rwxr-xr-xscripts/context/stubs/unix/tmftools2
-rwxr-xr-xscripts/context/stubs/unix/xmltools2
-rw-r--r--tex/context/base/attr-ini.lua853
-rw-r--r--tex/context/base/attr-ini.tex163
-rw-r--r--tex/context/base/back-ini.lua75
-rw-r--r--tex/context/base/back-ini.tex896
-rw-r--r--tex/context/base/back-pdf.lua189
-rw-r--r--tex/context/base/back-pdf.tex3226
-rw-r--r--tex/context/base/bibl-bib.lua233
-rw-r--r--tex/context/base/bibl-bib.tex29
-rw-r--r--tex/context/base/bibl-tst.lua21
-rw-r--r--tex/context/base/catc-act.tex61
-rw-r--r--tex/context/base/catc-ctx.tex207
-rw-r--r--tex/context/base/catc-def.tex142
-rw-r--r--tex/context/base/catc-ini.lua28
-rw-r--r--tex/context/base/catc-ini.mkii229
-rw-r--r--tex/context/base/catc-ini.mkiv255
-rw-r--r--tex/context/base/catc-sym.tex (renamed from tex/context/base/syst-chr.tex)111
-rw-r--r--tex/context/base/char-cmp.lua2
-rw-r--r--tex/context/base/char-def.lua1248
-rw-r--r--tex/context/base/char-enc.lua (renamed from tex/context/base/char-syn.lua)23
-rw-r--r--tex/context/base/char-enc.tex18
-rw-r--r--tex/context/base/char-ini.lua619
-rw-r--r--tex/context/base/char-ini.tex40
-rw-r--r--tex/context/base/char-map.lua19
-rw-r--r--tex/context/base/char-utf.lua146
-rw-r--r--tex/context/base/char-utf.tex26
-rw-r--r--tex/context/base/chem-ini.lua74
-rw-r--r--tex/context/base/chem-ini.mkiv42
-rw-r--r--tex/context/base/chem-str-test.tex560
-rw-r--r--tex/context/base/chem-str.lua488
-rw-r--r--tex/context/base/chem-str.mkiv526
-rw-r--r--tex/context/base/colo-ext.mkii (renamed from tex/context/base/colo-ext.tex)2
-rw-r--r--tex/context/base/colo-ext.mkiv57
-rw-r--r--tex/context/base/colo-hex.mkii115
-rw-r--r--tex/context/base/colo-hex.mkiv115
-rw-r--r--tex/context/base/colo-hex.tex120
-rw-r--r--tex/context/base/colo-ini.lua181
-rw-r--r--tex/context/base/colo-ini.mkii922
-rw-r--r--tex/context/base/colo-ini.mkiv983
-rw-r--r--tex/context/base/colo-ini.tex1051
-rw-r--r--tex/context/base/colo-run.tex3
-rw-r--r--tex/context/base/cont-cs.tex10
-rw-r--r--tex/context/base/cont-de.tex10
-rw-r--r--tex/context/base/cont-en.tex8
-rw-r--r--tex/context/base/cont-fil.tex2
-rw-r--r--tex/context/base/cont-fr.tex10
-rw-r--r--tex/context/base/cont-gb.tex10
-rw-r--r--tex/context/base/cont-it.tex10
-rw-r--r--tex/context/base/cont-log.tex71
-rw-r--r--tex/context/base/cont-new.mkiv88
-rw-r--r--tex/context/base/cont-new.tex100
-rw-r--r--tex/context/base/cont-nl.tex10
-rw-r--r--tex/context/base/cont-old.tex2
-rw-r--r--tex/context/base/cont-pe.tex10
-rw-r--r--tex/context/base/cont-ro.tex10
-rw-r--r--tex/context/base/cont-sys.ori9
-rw-r--r--tex/context/base/cont-usr.ori2
-rw-r--r--tex/context/base/context-base.lmx38
-rw-r--r--tex/context/base/context-characters.lmx66
-rw-r--r--tex/context/base/context-debug.lmx66
-rw-r--r--tex/context/base/context-error.lmx46
-rw-r--r--tex/context/base/context-fonttest.lmx47
-rw-r--r--tex/context/base/context-help.lmx88
-rw-r--r--tex/context/base/context-timing.lmx52
-rw-r--r--tex/context/base/context.css15
-rw-r--r--tex/context/base/context.mkii198
-rw-r--r--tex/context/base/context.mkiv422
-rw-r--r--tex/context/base/context.rme85
-rw-r--r--tex/context/base/context.tex15
-rw-r--r--tex/context/base/core-bar.tex2
-rw-r--r--tex/context/base/core-blk.tex130
-rw-r--r--tex/context/base/core-box.tex3
-rw-r--r--tex/context/base/core-buf.lua194
-rw-r--r--tex/context/base/core-buf.mkii326
-rw-r--r--tex/context/base/core-buf.mkiv308
-rw-r--r--tex/context/base/core-buf.tex250
-rw-r--r--tex/context/base/core-con.lua281
-rw-r--r--tex/context/base/core-con.mkii775
-rw-r--r--tex/context/base/core-con.mkiv831
-rw-r--r--tex/context/base/core-con.tex744
-rw-r--r--tex/context/base/core-ctx.lua41
-rw-r--r--tex/context/base/core-ctx.mkii2
-rw-r--r--tex/context/base/core-ctx.mkiv3
-rw-r--r--tex/context/base/core-ctx.tex22
-rw-r--r--tex/context/base/core-dat.tex66
-rw-r--r--tex/context/base/core-def.mkii77
-rw-r--r--tex/context/base/core-def.mkiv74
-rw-r--r--tex/context/base/core-def.tex27
-rw-r--r--tex/context/base/core-des.tex7
-rw-r--r--tex/context/base/core-env.mkii (renamed from tex/context/base/core-new.tex)339
-rw-r--r--tex/context/base/core-env.mkiv472
-rw-r--r--tex/context/base/core-fig.tex4
-rw-r--r--tex/context/base/core-fil.tex56
-rw-r--r--tex/context/base/core-fld.mkii (renamed from tex/context/base/core-fld.tex)4
-rw-r--r--tex/context/base/core-fld.mkiv1079
-rw-r--r--tex/context/base/core-fnt.mkii (renamed from tex/context/base/core-fnt.tex)4
-rw-r--r--tex/context/base/core-fnt.mkiv498
-rw-r--r--tex/context/base/core-gen.tex137
-rw-r--r--tex/context/base/core-grd.tex2
-rw-r--r--tex/context/base/core-inc.lua608
-rw-r--r--tex/context/base/core-inc.mkii95
-rw-r--r--tex/context/base/core-inc.mkiv12
-rw-r--r--tex/context/base/core-inc.tex18
-rw-r--r--tex/context/base/core-ini.tex2
-rw-r--r--tex/context/base/core-ins.tex42
-rw-r--r--tex/context/base/core-int.mkii (renamed from tex/context/base/core-int.tex)144
-rw-r--r--tex/context/base/core-int.mkiv2036
-rw-r--r--tex/context/base/core-itm.tex36
-rw-r--r--tex/context/base/core-job.lua154
-rw-r--r--tex/context/base/core-job.mkii316
-rw-r--r--tex/context/base/core-job.mkiv333
-rw-r--r--tex/context/base/core-job.tex368
-rw-r--r--tex/context/base/core-lme.tex2
-rw-r--r--tex/context/base/core-lnt.tex2
-rw-r--r--tex/context/base/core-lst.tex3
-rw-r--r--tex/context/base/core-mak.tex2
-rw-r--r--tex/context/base/core-mar.tex5
-rw-r--r--tex/context/base/core-mat.tex60
-rw-r--r--tex/context/base/core-mis.mkii (renamed from tex/context/base/core-mis.tex)235
-rw-r--r--tex/context/base/core-mis.mkiv2606
-rw-r--r--tex/context/base/core-nav.mkii (renamed from tex/context/base/core-nav.tex)2
-rw-r--r--tex/context/base/core-nav.mkiv425
-rw-r--r--tex/context/base/core-not.tex8
-rw-r--r--tex/context/base/core-num.tex2
-rw-r--r--tex/context/base/core-obj.lua7
-rw-r--r--tex/context/base/core-obj.mkii309
-rw-r--r--tex/context/base/core-obj.mkiv220
-rw-r--r--tex/context/base/core-obj.tex365
-rw-r--r--tex/context/base/core-par.tex2
-rw-r--r--tex/context/base/core-pgr.tex12
-rw-r--r--tex/context/base/core-pos.lua4
-rw-r--r--tex/context/base/core-pos.mkii759
-rw-r--r--tex/context/base/core-pos.mkiv789
-rw-r--r--tex/context/base/core-pos.tex767
-rw-r--r--tex/context/base/core-ref.lua106
-rw-r--r--tex/context/base/core-ref.mkii90
-rw-r--r--tex/context/base/core-ref.mkiv107
-rw-r--r--tex/context/base/core-ref.tex261
-rw-r--r--tex/context/base/core-reg.lua186
-rw-r--r--tex/context/base/core-reg.mkii33
-rw-r--r--tex/context/base/core-reg.mkiv40
-rw-r--r--tex/context/base/core-reg.tex55
-rw-r--r--tex/context/base/core-rul.lua1
-rw-r--r--tex/context/base/core-rul.mkii3562
-rw-r--r--tex/context/base/core-rul.mkiv3635
-rw-r--r--tex/context/base/core-rul.tex3590
-rw-r--r--tex/context/base/core-sec.mkiv2621
-rw-r--r--tex/context/base/core-sec.tex (renamed from tex/context/base/core-sec.mkii)62
-rw-r--r--tex/context/base/core-snc.tex4
-rw-r--r--tex/context/base/core-spa.lua1979
-rw-r--r--tex/context/base/core-spa.mkii4648
-rw-r--r--tex/context/base/core-spa.mkiv4168
-rw-r--r--tex/context/base/core-spa.tex4637
-rw-r--r--tex/context/base/core-stg.tex4
-rw-r--r--tex/context/base/core-syn.lua127
-rw-r--r--tex/context/base/core-syn.mkii28
-rw-r--r--tex/context/base/core-syn.mkiv34
-rw-r--r--tex/context/base/core-syn.tex42
-rw-r--r--tex/context/base/core-sys.mkii384
-rw-r--r--tex/context/base/core-sys.mkiv373
-rw-r--r--tex/context/base/core-sys.tex401
-rw-r--r--tex/context/base/core-trf.tex28
-rw-r--r--tex/context/base/core-two.lua20
-rw-r--r--tex/context/base/core-two.mkii65
-rw-r--r--tex/context/base/core-two.mkiv77
-rw-r--r--tex/context/base/core-two.tex103
-rw-r--r--tex/context/base/core-uti.lua253
-rw-r--r--tex/context/base/core-uti.mkii305
-rw-r--r--tex/context/base/core-uti.mkiv95
-rw-r--r--tex/context/base/core-uti.tex382
-rw-r--r--tex/context/base/core-var.tex568
-rw-r--r--tex/context/base/core-ver.mkii1124
-rw-r--r--tex/context/base/core-ver.mkiv1084
-rw-r--r--tex/context/base/core-ver.tex1120
-rw-r--r--tex/context/base/core-vis.tex32
-rw-r--r--tex/context/base/data-aux.lua57
-rw-r--r--tex/context/base/data-bin.lua26
-rw-r--r--tex/context/base/data-con.lua122
-rw-r--r--tex/context/base/data-crl.lua58
-rw-r--r--tex/context/base/data-ctx.lua29
-rw-r--r--tex/context/base/data-gen.lua9
-rw-r--r--tex/context/base/data-inp.lua15
-rw-r--r--tex/context/base/data-kps.lua101
-rw-r--r--tex/context/base/data-lst.lua58
-rw-r--r--tex/context/base/data-lua.lua55
-rw-r--r--tex/context/base/data-out.lua10
-rw-r--r--tex/context/base/data-pre.lua90
-rw-r--r--tex/context/base/data-res.lua2029
-rw-r--r--tex/context/base/data-tex.lua220
-rw-r--r--tex/context/base/data-tmf.lua72
-rw-r--r--tex/context/base/data-tmp.lua174
-rw-r--r--tex/context/base/data-tre.lua43
-rw-r--r--tex/context/base/data-use.lua127
-rw-r--r--tex/context/base/data-zip.lua241
-rw-r--r--tex/context/base/enco-cyr.tex2
-rw-r--r--tex/context/base/enco-def.tex6
-rw-r--r--tex/context/base/enco-fpl.tex2
-rw-r--r--tex/context/base/enco-ini.mkii1125
-rw-r--r--tex/context/base/enco-ini.mkiv583
-rw-r--r--tex/context/base/enco-ini.tex1228
-rw-r--r--tex/context/base/enco-mis.tex37
-rw-r--r--tex/context/base/enco-pfr.mkii20
-rw-r--r--tex/context/base/enco-pfr.mkiv22
-rw-r--r--tex/context/base/enco-pfr.tex18
-rw-r--r--tex/context/base/enco-run.tex52
-rw-r--r--tex/context/base/enco-t5.tex4
-rw-r--r--tex/context/base/enco-utf.tex3126
-rw-r--r--tex/context/base/enco-x5.tex34
-rw-r--r--tex/context/base/filt-ini.tex62
-rw-r--r--tex/context/base/font-afm.lua344
-rw-r--r--tex/context/base/font-bfm.tex2
-rw-r--r--tex/context/base/font-chi.tex2
-rw-r--r--tex/context/base/font-chk.lua80
-rw-r--r--tex/context/base/font-cid.lua143
-rw-r--r--tex/context/base/font-col.lua98
-rw-r--r--tex/context/base/font-col.mkiv (renamed from tex/context/base/font-col.tex)4
-rw-r--r--tex/context/base/font-ctx.lua387
-rw-r--r--tex/context/base/font-def.lua624
-rw-r--r--tex/context/base/font-dum.lua113
-rw-r--r--tex/context/base/font-enc.lua16
-rw-r--r--tex/context/base/font-ext.lua304
-rw-r--r--tex/context/base/font-fbk.lua102
-rw-r--r--tex/context/base/font-ini.lua53
-rw-r--r--tex/context/base/font-ini.mkii671
-rw-r--r--tex/context/base/font-ini.mkiv2513
-rw-r--r--tex/context/base/font-jap.tex2
-rw-r--r--tex/context/base/font-log.lua53
-rw-r--r--tex/context/base/font-map.lua32
-rw-r--r--tex/context/base/font-mis.lua91
-rw-r--r--tex/context/base/font-ota.lua320
-rw-r--r--tex/context/base/font-otb.lua364
-rw-r--r--tex/context/base/font-otc.lua238
-rw-r--r--tex/context/base/font-otd.lua78
-rw-r--r--tex/context/base/font-otf.lua5965
-rw-r--r--tex/context/base/font-oti.lua57
-rw-r--r--tex/context/base/font-otn.lua2496
-rw-r--r--tex/context/base/font-otp.lua420
-rw-r--r--tex/context/base/font-ott.lua935
-rw-r--r--tex/context/base/font-pat.lua53
-rw-r--r--tex/context/base/font-run.tex3
-rw-r--r--tex/context/base/font-syn.lua417
-rw-r--r--tex/context/base/font-tfm.lua977
-rw-r--r--tex/context/base/font-tra.mkiv113
-rw-r--r--tex/context/base/font-uni.mkii (renamed from tex/context/base/font-uni.tex)47
-rw-r--r--tex/context/base/font-uni.mkiv26
-rw-r--r--tex/context/base/font-unk.mkii (renamed from tex/context/base/font-unk.tex)4
-rw-r--r--tex/context/base/font-unk.mkiv162
-rw-r--r--tex/context/base/font-vf.lua72
-rw-r--r--tex/context/base/font-xtx.lua115
-rw-r--r--tex/context/base/font-xtx.tex357
-rw-r--r--tex/context/base/hand-ini.mkii91
-rw-r--r--tex/context/base/hand-ini.mkiv2
-rw-r--r--tex/context/base/hand-ini.tex18
-rw-r--r--tex/context/base/java-ini.mkii (renamed from tex/context/base/java-ini.tex)67
-rw-r--r--tex/context/base/java-ini.mkiv688
-rw-r--r--tex/context/base/l-aux.lua128
-rw-r--r--tex/context/base/l-boolean.lua17
-rw-r--r--tex/context/base/l-dimen.lua13
-rw-r--r--tex/context/base/l-dir.lua447
-rw-r--r--tex/context/base/l-file.lua142
-rw-r--r--tex/context/base/l-io.lua211
-rw-r--r--tex/context/base/l-lpeg.lua58
-rw-r--r--tex/context/base/l-math.lua30
-rw-r--r--tex/context/base/l-md5.lua78
-rw-r--r--tex/context/base/l-number.lua27
-rw-r--r--tex/context/base/l-os.lua88
-rw-r--r--tex/context/base/l-set.lua87
-rw-r--r--tex/context/base/l-string.lua270
-rw-r--r--tex/context/base/l-table.lua328
-rw-r--r--tex/context/base/l-unicode.lua79
-rw-r--r--tex/context/base/l-url.lua54
-rw-r--r--tex/context/base/l-utils.lua62
-rw-r--r--tex/context/base/l-xml.lua134
-rw-r--r--tex/context/base/lang-alt.tex5
-rw-r--r--tex/context/base/lang-ana.tex6
-rw-r--r--tex/context/base/lang-ara.tex5
-rw-r--r--tex/context/base/lang-art.tex6
-rw-r--r--tex/context/base/lang-bal.tex6
-rw-r--r--tex/context/base/lang-cel.tex6
-rw-r--r--tex/context/base/lang-chi.tex6
-rw-r--r--tex/context/base/lang-cjk.tex328
-rw-r--r--tex/context/base/lang-ctx.tex37
-rw-r--r--tex/context/base/lang-cyr.tex14
-rw-r--r--tex/context/base/lang-dis.tex8
-rw-r--r--tex/context/base/lang-frq.tex4
-rw-r--r--tex/context/base/lang-ger.tex44
-rw-r--r--tex/context/base/lang-grk.tex9
-rw-r--r--tex/context/base/lang-ind.tex2
-rw-r--r--tex/context/base/lang-ini.lua131
-rw-r--r--tex/context/base/lang-ini.mkii588
-rw-r--r--tex/context/base/lang-ini.mkiv565
-rw-r--r--tex/context/base/lang-ini.tex692
-rw-r--r--tex/context/base/lang-ita.tex57
-rw-r--r--tex/context/base/lang-jap.tex5
-rw-r--r--tex/context/base/lang-lab.mkii (renamed from tex/context/base/lang-lab.tex)55
-rw-r--r--tex/context/base/lang-lab.mkiv266
-rw-r--r--tex/context/base/lang-mis.tex6
-rw-r--r--tex/context/base/lang-sla.tex23
-rw-r--r--tex/context/base/lang-spa.tex2
-rw-r--r--tex/context/base/lang-spe.mkii (renamed from tex/context/base/lang-spe.tex)44
-rw-r--r--tex/context/base/lang-spe.mkiv111
-rw-r--r--tex/context/base/lang-ura.tex6
-rw-r--r--tex/context/base/lang-url.lua10
-rw-r--r--tex/context/base/lang-url.mkii74
-rw-r--r--tex/context/base/lang-url.mkiv50
-rw-r--r--tex/context/base/lang-url.tex70
-rw-r--r--tex/context/base/lang-vn.tex5
-rw-r--r--tex/context/base/luat-bas.tex64
-rw-r--r--tex/context/base/luat-cbk.lua13
-rw-r--r--tex/context/base/luat-cnf.lua114
-rw-r--r--tex/context/base/luat-cod.tex161
-rw-r--r--tex/context/base/luat-crl.lua53
-rw-r--r--tex/context/base/luat-dum.lua60
-rw-r--r--tex/context/base/luat-env.lua304
-rw-r--r--tex/context/base/luat-env.tex172
-rw-r--r--tex/context/base/luat-exe.lua13
-rw-r--r--tex/context/base/luat-fio.lua81
-rw-r--r--tex/context/base/luat-ini.lua129
-rw-r--r--tex/context/base/luat-ini.tex222
-rw-r--r--tex/context/base/luat-inp.lua2300
-rw-r--r--tex/context/base/luat-iop.lua18
-rw-r--r--tex/context/base/luat-kps.lua102
-rw-r--r--tex/context/base/luat-lib.lua174
-rw-r--r--tex/context/base/luat-lib.tex86
-rw-r--r--tex/context/base/luat-log.lua155
-rw-r--r--tex/context/base/luat-lua.lua2
-rw-r--r--tex/context/base/luat-run.lua69
-rw-r--r--tex/context/base/luat-soc.lua11
-rw-r--r--tex/context/base/luat-sta.lua44
-rw-r--r--tex/context/base/luat-sto.lua134
-rw-r--r--tex/context/base/luat-tex.lua588
-rw-r--r--tex/context/base/luat-tmp.lua433
-rw-r--r--tex/context/base/luat-tre.lua45
-rw-r--r--tex/context/base/luat-uni.lua21
-rw-r--r--tex/context/base/luat-uni.tex33
-rw-r--r--tex/context/base/luat-zip.lua249
-rw-r--r--tex/context/base/lxml-ent.lua115
-rw-r--r--tex/context/base/lxml-ini.lua588
-rw-r--r--tex/context/base/lxml-ini.tex71
-rw-r--r--tex/context/base/lxml-mis.lua106
-rw-r--r--tex/context/base/lxml-pth.lua1555
-rw-r--r--tex/context/base/lxml-tab.lua783
-rw-r--r--tex/context/base/m-arabtex.tex2
-rw-r--r--tex/context/base/m-chemic.mkii21
-rw-r--r--tex/context/base/m-chemic.mkiv19
-rw-r--r--tex/context/base/m-chemic.tex10
-rw-r--r--tex/context/base/m-database.tex2
-rw-r--r--tex/context/base/m-educat.tex33
-rw-r--r--tex/context/base/m-gamma.tex230
-rw-r--r--tex/context/base/m-mkii.mkiv21
-rw-r--r--tex/context/base/m-newmat.tex14
-rw-r--r--tex/context/base/m-pictex.tex11
-rw-r--r--tex/context/base/m-subsub.tex47
-rw-r--r--tex/context/base/m-timing.tex197
-rw-r--r--tex/context/base/m-track.tex5
-rw-r--r--tex/context/base/m-translate.tex6
-rw-r--r--tex/context/base/m-visual.tex1
-rw-r--r--tex/context/base/math-ali.mkiv1059
-rw-r--r--tex/context/base/math-ams.tex4
-rw-r--r--tex/context/base/math-arr.mkii391
-rw-r--r--tex/context/base/math-arr.mkiv (renamed from tex/context/base/math-ext.tex)22
-rw-r--r--tex/context/base/math-def.mkiv338
-rw-r--r--tex/context/base/math-del.mkiv63
-rw-r--r--tex/context/base/math-dim.lua310
-rw-r--r--tex/context/base/math-dis.mkiv20
-rw-r--r--tex/context/base/math-ext.lua143
-rw-r--r--tex/context/base/math-for.mkiv73
-rw-r--r--tex/context/base/math-frc.mkii66
-rw-r--r--tex/context/base/math-frc.mkiv209
-rw-r--r--tex/context/base/math-ini.lua637
-rw-r--r--tex/context/base/math-ini.mkii679
-rw-r--r--tex/context/base/math-ini.mkiv544
-rw-r--r--tex/context/base/math-ini.tex688
-rw-r--r--tex/context/base/math-inl.mkiv357
-rw-r--r--tex/context/base/math-int.mkiv87
-rw-r--r--tex/context/base/math-lbr.tex8
-rw-r--r--tex/context/base/math-map.lua365
-rw-r--r--tex/context/base/math-mis.tex49
-rw-r--r--tex/context/base/math-noa.lua336
-rw-r--r--tex/context/base/math-pln.mkii (renamed from tex/context/base/math-pln.tex)155
-rw-r--r--tex/context/base/math-pln.mkiv298
-rw-r--r--tex/context/base/math-run.mkii (renamed from tex/context/base/math-run.tex)2
-rw-r--r--tex/context/base/math-scr.mkiv215
-rw-r--r--tex/context/base/math-tex.tex23
-rw-r--r--tex/context/base/math-tim.tex106
-rw-r--r--tex/context/base/math-vfu.lua1534
-rw-r--r--tex/context/base/meta-ini.mkii91
-rw-r--r--tex/context/base/meta-ini.mkiv431
-rw-r--r--tex/context/base/meta-pdf.lua737
-rw-r--r--tex/context/base/meta-pdf.mkii936
-rw-r--r--tex/context/base/meta-pdf.mkiv833
-rw-r--r--tex/context/base/meta-pdf.tex1020
-rw-r--r--tex/context/base/meta-pdh.lua630
-rw-r--r--tex/context/base/meta-tex.mkii2
-rw-r--r--tex/context/base/metatex.tex145
-rw-r--r--tex/context/base/mlib-ctx.lua16
-rw-r--r--tex/context/base/mlib-pdf.lua209
-rw-r--r--tex/context/base/mlib-pdf.tex6
-rw-r--r--tex/context/base/mlib-pps.lua177
-rw-r--r--tex/context/base/mlib-pps.tex16
-rw-r--r--tex/context/base/mlib-run.lua161
-rw-r--r--tex/context/base/mtx-context-arrange.tex105
-rw-r--r--tex/context/base/mtx-context-combine.tex146
-rw-r--r--tex/context/base/mtx-context-ideas.tex54
-rw-r--r--tex/context/base/mtx-context-listing.tex76
-rw-r--r--tex/context/base/mtx-context-timing.tex46
-rw-r--r--tex/context/base/mult-chk.lua66
-rw-r--r--tex/context/base/mult-chk.mkii26
-rw-r--r--tex/context/base/mult-chk.mkiv103
-rw-r--r--tex/context/base/mult-de.tex57
-rw-r--r--tex/context/base/mult-def.lua270
-rw-r--r--tex/context/base/mult-def.tex10
-rw-r--r--tex/context/base/mult-en.tex57
-rw-r--r--tex/context/base/mult-fr.tex57
-rw-r--r--tex/context/base/mult-his.tex19
-rw-r--r--tex/context/base/mult-ini.lua31
-rw-r--r--tex/context/base/mult-ini.mkii15
-rw-r--r--tex/context/base/mult-ini.mkiv34
-rw-r--r--tex/context/base/mult-it.tex57
-rw-r--r--tex/context/base/mult-mcs.tex198
-rw-r--r--tex/context/base/mult-mde.tex198
-rw-r--r--tex/context/base/mult-men.tex198
-rw-r--r--tex/context/base/mult-mes.lua2005
-rw-r--r--tex/context/base/mult-mfr.tex198
-rw-r--r--tex/context/base/mult-mit.tex198
-rw-r--r--tex/context/base/mult-mnl.tex198
-rw-r--r--tex/context/base/mult-mno.tex198
-rw-r--r--tex/context/base/mult-mpe.tex198
-rw-r--r--tex/context/base/mult-mro.tex198
-rw-r--r--tex/context/base/mult-nl.tex57
-rw-r--r--tex/context/base/mult-ro.tex57
-rw-r--r--tex/context/base/mult-sys.tex116
-rw-r--r--tex/context/base/node-dum.lua24
-rw-r--r--tex/context/base/node-ext.lua30
-rw-r--r--tex/context/base/node-fin.lua363
-rw-r--r--tex/context/base/node-fin.tex78
-rw-r--r--tex/context/base/node-fnt.lua206
-rw-r--r--tex/context/base/node-ini.lua1254
-rw-r--r--tex/context/base/node-ini.tex59
-rw-r--r--tex/context/base/node-inj.lua608
-rw-r--r--tex/context/base/node-par.lua2
-rw-r--r--tex/context/base/node-par.tex6
-rw-r--r--tex/context/base/node-pro.lua155
-rw-r--r--tex/context/base/node-res.lua110
-rw-r--r--tex/context/base/node-seq.lua47
-rw-r--r--tex/context/base/node-ser.lua274
-rw-r--r--tex/context/base/node-shp.lua66
-rw-r--r--tex/context/base/node-tex.lua54
-rw-r--r--tex/context/base/node-tra.lua399
-rw-r--r--tex/context/base/node-tsk.lua113
-rw-r--r--tex/context/base/node-tst.lua108
-rw-r--r--tex/context/base/norm-alo.tex36
-rw-r--r--tex/context/base/norm-ctx.tex16
-rw-r--r--tex/context/base/norm-etx.tex79
-rw-r--r--tex/context/base/norm-ltx.tex177
-rw-r--r--tex/context/base/norm-ptx.tex130
-rw-r--r--tex/context/base/norm-tex.tex351
-rw-r--r--tex/context/base/norm-xtx.tex (renamed from tex/context/base/sort-def.mkiv)14
-rw-r--r--tex/context/base/page-app.tex4
-rw-r--r--tex/context/base/page-bck.mkii (renamed from tex/context/base/page-bck.tex)46
-rw-r--r--tex/context/base/page-bck.mkiv521
-rw-r--r--tex/context/base/page-flt.tex460
-rw-r--r--tex/context/base/page-flw.tex4
-rw-r--r--tex/context/base/page-imp.tex29
-rw-r--r--tex/context/base/page-ini.mkii (renamed from tex/context/base/page-ini.tex)553
-rw-r--r--tex/context/base/page-ini.mkiv1549
-rw-r--r--tex/context/base/page-lay.tex5
-rw-r--r--tex/context/base/page-lin.lua299
-rw-r--r--tex/context/base/page-lin.mkii2
-rw-r--r--tex/context/base/page-lin.mkiv16
-rw-r--r--tex/context/base/page-log.tex34
-rw-r--r--tex/context/base/page-lyr.tex8
-rw-r--r--tex/context/base/page-mak.tex9
-rw-r--r--tex/context/base/page-mar.tex10
-rw-r--r--tex/context/base/page-mis.tex268
-rw-r--r--tex/context/base/page-mul.tex8
-rw-r--r--tex/context/base/page-not.tex2
-rw-r--r--tex/context/base/page-num.tex15
-rw-r--r--tex/context/base/page-one.mkii (renamed from tex/context/base/page-one.tex)4
-rw-r--r--tex/context/base/page-one.mkiv662
-rw-r--r--tex/context/base/page-par.tex4
-rw-r--r--tex/context/base/page-plg.tex4
-rw-r--r--tex/context/base/page-run.tex2
-rw-r--r--tex/context/base/page-set.tex24
-rw-r--r--tex/context/base/page-sid.tex4
-rw-r--r--tex/context/base/page-spr.tex2
-rw-r--r--tex/context/base/page-str.tex6
-rw-r--r--tex/context/base/page-txt.mkii (renamed from tex/context/base/page-txt.tex)6
-rw-r--r--tex/context/base/page-txt.mkiv808
-rw-r--r--tex/context/base/ppchtex.mkii (renamed from tex/context/base/ppchtex.tex)41
-rw-r--r--tex/context/base/ppchtex.mkiv3359
-rw-r--r--tex/context/base/prop-ini.mkii (renamed from tex/context/base/prop-ini.tex)23
-rw-r--r--tex/context/base/prop-ini.mkiv150
-rw-r--r--tex/context/base/prop-lay.mkii99
-rw-r--r--tex/context/base/prop-lay.mkiv109
-rw-r--r--tex/context/base/prop-lay.tex105
-rw-r--r--tex/context/base/prop-mis.mkii34
-rw-r--r--tex/context/base/prop-mis.mkiv34
-rw-r--r--tex/context/base/prop-mis.tex53
-rw-r--r--tex/context/base/prop-run.tex39
-rw-r--r--tex/context/base/regi-ini.lua88
-rw-r--r--tex/context/base/regi-ini.mkii167
-rw-r--r--tex/context/base/regi-ini.mkiv54
-rw-r--r--tex/context/base/regi-ini.tex182
-rw-r--r--tex/context/base/regi-syn.tex2
-rw-r--r--tex/context/base/regi-utf.tex12
-rw-r--r--tex/context/base/s-fnt-01.tex4
-rw-r--r--tex/context/base/s-fnt-10.tex100
-rw-r--r--tex/context/base/s-fnt-11.tex61
-rw-r--r--tex/context/base/s-fnt-20.tex140
-rw-r--r--tex/context/base/s-fnt-21.tex46
-rw-r--r--tex/context/base/s-fnt-23.tex272
-rw-r--r--tex/context/base/s-fnt-24.tex83
-rw-r--r--tex/context/base/s-fnt-25.tex162
-rw-r--r--tex/context/base/s-fnt-30.tex42
-rw-r--r--tex/context/base/s-pre-60.tex46
-rw-r--r--tex/context/base/s-pre-61.tex14
-rw-r--r--tex/context/base/s-pre-62.tex20
-rw-r--r--tex/context/base/s-pre-66.tex133
-rw-r--r--tex/context/base/s-pre-71.tex8
-rw-r--r--tex/context/base/s-reg-01.tex50
-rw-r--r--tex/context/base/scrp-cjk.lua576
-rw-r--r--tex/context/base/scrp-ini.lua386
-rw-r--r--tex/context/base/scrp-ini.tex91
-rw-r--r--tex/context/base/sort-def.mkii450
-rw-r--r--tex/context/base/sort-def.tex432
-rw-r--r--tex/context/base/sort-ini.lua135
-rw-r--r--tex/context/base/sort-ini.mkii16
-rw-r--r--tex/context/base/sort-ini.mkiv8
-rw-r--r--tex/context/base/sort-ini.tex32
-rw-r--r--tex/context/base/sort-lan.lua19
-rw-r--r--tex/context/base/sort-lan.mkii203
-rw-r--r--tex/context/base/sort-lan.mkiv16
-rw-r--r--tex/context/base/sort-lan.tex189
-rw-r--r--tex/context/base/spec-def.mkii20
-rw-r--r--tex/context/base/spec-def.mkiv23
-rw-r--r--tex/context/base/spec-def.tex8
-rw-r--r--tex/context/base/spec-dpx.tex4
-rw-r--r--tex/context/base/spec-fdf.mkii146
-rw-r--r--tex/context/base/spec-fdf.mkiv31
-rw-r--r--tex/context/base/spec-fdf.tex205
-rw-r--r--tex/context/base/spec-ini.tex154
-rw-r--r--tex/context/base/spec-mis.tex26
-rw-r--r--tex/context/base/spec-pdf.lua67
-rw-r--r--tex/context/base/spec-tpd.mkii18
-rw-r--r--tex/context/base/spec-tpd.mkiv37
-rw-r--r--tex/context/base/spec-tpd.tex40
-rw-r--r--tex/context/base/spec-var.tex2
-rw-r--r--tex/context/base/strc-bkm.lua133
-rw-r--r--tex/context/base/strc-bkm.tex90
-rw-r--r--tex/context/base/strc-blk.lua (renamed from tex/context/base/core-blk.lua)56
-rw-r--r--tex/context/base/strc-blk.tex (renamed from tex/context/base/core-blk.mkiv)17
-rw-r--r--tex/context/base/strc-def.tex302
-rw-r--r--tex/context/base/strc-des.lua9
-rw-r--r--tex/context/base/strc-des.tex1018
-rw-r--r--tex/context/base/strc-doc.lua569
-rw-r--r--tex/context/base/strc-doc.tex166
-rw-r--r--tex/context/base/strc-flt.lua9
-rw-r--r--tex/context/base/strc-flt.tex2173
-rw-r--r--tex/context/base/strc-ini.lua276
-rw-r--r--tex/context/base/strc-ini.tex88
-rw-r--r--tex/context/base/strc-itm.lua24
-rw-r--r--tex/context/base/strc-itm.tex1195
-rw-r--r--tex/context/base/strc-lst.lua392
-rw-r--r--tex/context/base/strc-lst.tex944
-rw-r--r--tex/context/base/strc-mar.lua18
-rw-r--r--tex/context/base/strc-mar.tex493
-rw-r--r--tex/context/base/strc-mat.lua51
-rw-r--r--tex/context/base/strc-mat.tex933
-rw-r--r--tex/context/base/strc-not.lua248
-rw-r--r--tex/context/base/strc-not.tex1154
-rw-r--r--tex/context/base/strc-num.lua457
-rw-r--r--tex/context/base/strc-num.tex440
-rw-r--r--tex/context/base/strc-pag.lua206
-rw-r--r--tex/context/base/strc-pag.tex506
-rw-r--r--tex/context/base/strc-prc.lua9
-rw-r--r--tex/context/base/strc-prc.tex84
-rw-r--r--tex/context/base/strc-ref.lua875
-rw-r--r--tex/context/base/strc-ref.tex1905
-rw-r--r--tex/context/base/strc-reg.lua578
-rw-r--r--tex/context/base/strc-reg.tex907
-rw-r--r--tex/context/base/strc-ren.tex467
-rw-r--r--tex/context/base/strc-sbe.tex137
-rw-r--r--tex/context/base/strc-sec.tex667
-rw-r--r--tex/context/base/strc-syn.lua185
-rw-r--r--tex/context/base/strc-syn.tex392
-rw-r--r--tex/context/base/strc-xml.tex87
-rw-r--r--tex/context/base/supp-box.tex357
-rw-r--r--tex/context/base/supp-dir.mkii41
-rw-r--r--tex/context/base/supp-dir.mkiv21
-rw-r--r--tex/context/base/supp-dir.tex70
-rw-r--r--tex/context/base/supp-eps.tex2
-rw-r--r--tex/context/base/supp-fil.lua49
-rw-r--r--tex/context/base/supp-fil.mkii621
-rw-r--r--tex/context/base/supp-fil.mkiv616
-rw-r--r--tex/context/base/supp-fil.tex655
-rw-r--r--tex/context/base/supp-fun.tex10
-rw-r--r--tex/context/base/supp-ini.tex18
-rw-r--r--tex/context/base/supp-lan.tex4
-rw-r--r--tex/context/base/supp-mat.tex13
-rw-r--r--tex/context/base/supp-mis.tex3
-rw-r--r--tex/context/base/supp-mpe.tex2
-rw-r--r--tex/context/base/supp-mps.tex24
-rw-r--r--tex/context/base/supp-mrk.tex27
-rw-r--r--tex/context/base/supp-num.tex31
-rw-r--r--tex/context/base/supp-pat.tex6
-rw-r--r--tex/context/base/supp-pdf.tex2
-rw-r--r--tex/context/base/supp-ran.lua46
-rw-r--r--tex/context/base/supp-ran.mkii (renamed from tex/context/base/supp-ran.tex)76
-rw-r--r--tex/context/base/supp-ran.mkiv30
-rw-r--r--tex/context/base/supp-spe.tex94
-rw-r--r--tex/context/base/supp-tpi.tex6
-rw-r--r--tex/context/base/supp-vis.tex48
-rw-r--r--tex/context/base/symb-ini.tex42
-rw-r--r--tex/context/base/symb-jmn.tex1
-rw-r--r--tex/context/base/symb-mis.tex7
-rw-r--r--tex/context/base/syst-aux.tex6841
-rw-r--r--tex/context/base/syst-cat.mkii61
-rw-r--r--tex/context/base/syst-cat.mkiv124
-rw-r--r--tex/context/base/syst-cat.tex517
-rw-r--r--tex/context/base/syst-con.lua28
-rw-r--r--tex/context/base/syst-con.mkii109
-rw-r--r--tex/context/base/syst-con.mkiv132
-rw-r--r--tex/context/base/syst-con.tex144
-rw-r--r--tex/context/base/syst-etx.tex298
-rw-r--r--tex/context/base/syst-ext.tex165
-rw-r--r--tex/context/base/syst-fnt.mkii46
-rw-r--r--tex/context/base/syst-fnt.mkiv46
-rw-r--r--tex/context/base/syst-fnt.tex43
-rw-r--r--tex/context/base/syst-gen.tex358
-rw-r--r--tex/context/base/syst-ini.tex879
-rw-r--r--tex/context/base/syst-lua.lua91
-rw-r--r--tex/context/base/syst-lua.tex37
-rw-r--r--tex/context/base/syst-mtx.tex80
-rw-r--r--tex/context/base/syst-new.tex21
-rw-r--r--tex/context/base/syst-omg.tex79
-rw-r--r--tex/context/base/syst-pdt.tex50
-rw-r--r--tex/context/base/syst-pln.tex510
-rw-r--r--tex/context/base/syst-prm.tex227
-rw-r--r--tex/context/base/syst-rtp.tex22
-rw-r--r--tex/context/base/syst-str.mkii7
-rw-r--r--tex/context/base/syst-str.mkiv9
-rw-r--r--tex/context/base/syst-str.tex40
-rw-r--r--tex/context/base/syst-var.tex18
-rw-r--r--tex/context/base/syst-xtx.tex36
-rw-r--r--tex/context/base/tabl-ltb.tex (renamed from tex/context/base/core-ltb.tex)4
-rw-r--r--tex/context/base/tabl-ntb.mkii (renamed from tex/context/base/core-ntb.tex)47
-rw-r--r--tex/context/base/tabl-ntb.mkiv1571
-rw-r--r--tex/context/base/tabl-nte.tex107
-rw-r--r--tex/context/base/tabl-pln.tex91
-rw-r--r--tex/context/base/tabl-tab.tex (renamed from tex/context/base/core-tab.tex)44
-rw-r--r--tex/context/base/tabl-tbl.tex (renamed from tex/context/base/core-tbl.tex)59
-rw-r--r--tex/context/base/tabl-tsp.tex (renamed from tex/context/base/core-tsp.tex)8
-rw-r--r--tex/context/base/task-ini.lua45
-rw-r--r--tex/context/base/task-ini.tex22
-rw-r--r--tex/context/base/thrd-ran.tex4
-rw-r--r--tex/context/base/thrd-tab.tex50
-rw-r--r--tex/context/base/thrd-trg.tex9
-rw-r--r--tex/context/base/toks-ini.lua43
-rw-r--r--tex/context/base/toks-ini.tex6
-rw-r--r--tex/context/base/trac-deb.lua (renamed from tex/context/base/luat-deb.lua)70
-rw-r--r--tex/context/base/trac-deb.tex (renamed from tex/context/base/luat-deb.tex)24
-rw-r--r--tex/context/base/trac-inf.lua149
-rw-r--r--tex/context/base/trac-lmx.lua (renamed from tex/context/base/luat-lmx.lua)79
-rw-r--r--tex/context/base/trac-lmx.tex (renamed from tex/context/base/luat-lmx.tex)10
-rw-r--r--tex/context/base/trac-log.lua285
-rw-r--r--tex/context/base/trac-tim.lua163
-rw-r--r--tex/context/base/trac-tra.lua (renamed from tex/context/base/luat-tra.lua)98
-rw-r--r--tex/context/base/type-cow.tex4
-rw-r--r--tex/context/base/type-gyr.tex252
-rw-r--r--tex/context/base/type-ini.mkii (renamed from tex/context/base/type-ini.tex)170
-rw-r--r--tex/context/base/type-ini.mkiv705
-rw-r--r--tex/context/base/type-mac.mkii220
-rw-r--r--tex/context/base/type-mac.mkiv220
-rw-r--r--tex/context/base/type-mac.tex434
-rw-r--r--tex/context/base/type-map.tex48
-rw-r--r--tex/context/base/type-one.tex494
-rw-r--r--tex/context/base/type-otf.mkii535
-rw-r--r--tex/context/base/type-otf.mkiv628
-rw-r--r--tex/context/base/type-otf.tex739
-rw-r--r--tex/context/base/type-siz.mkii583
-rw-r--r--tex/context/base/type-siz.mkiv375
-rw-r--r--tex/context/base/type-siz.tex688
-rw-r--r--tex/context/base/type-syn.tex1
-rw-r--r--tex/context/base/type-tmf.tex103
-rw-r--r--tex/context/base/type-win.tex120
-rw-r--r--tex/context/base/type-xtx.tex2
-rw-r--r--tex/context/base/typo-brk.lua186
-rw-r--r--tex/context/base/typo-brk.tex77
-rw-r--r--tex/context/base/typo-cap.lua203
-rw-r--r--tex/context/base/typo-cap.tex214
-rw-r--r--tex/context/base/typo-ini.tex2
-rw-r--r--tex/context/base/typo-krn.lua218
-rw-r--r--tex/context/base/typo-krn.tex59
-rw-r--r--tex/context/base/typo-mir.lua409
-rw-r--r--tex/context/base/typo-mir.tex144
-rw-r--r--tex/context/base/typo-spa.lua149
-rw-r--r--tex/context/base/typo-spa.tex69
-rw-r--r--tex/context/base/unic-035.tex32
-rw-r--r--tex/context/base/unic-exp.tex4
-rw-r--r--tex/context/base/unic-ini.mkii10
-rw-r--r--tex/context/base/unic-ini.mkiv19
-rw-r--r--tex/context/base/verb-c.tex2
-rw-r--r--tex/context/base/verb-eif.tex24
-rw-r--r--tex/context/base/verb-ini.tex2
-rw-r--r--tex/context/base/verb-js.tex18
-rw-r--r--tex/context/base/verb-jv.tex50
-rw-r--r--tex/context/base/verb-lua.lua10
-rw-r--r--tex/context/base/verb-mp.lua6
-rw-r--r--tex/context/base/verb-mp.tex2
-rw-r--r--tex/context/base/verb-pas.tex6
-rw-r--r--tex/context/base/verb-pl.tex58
-rw-r--r--tex/context/base/verb-sql.tex2
-rw-r--r--tex/context/base/verb-tex.lua6
-rw-r--r--tex/context/base/verb-tex.tex2
-rw-r--r--tex/context/base/verb-xml.tex2
-rw-r--r--tex/context/base/x-calcmath.lua191
-rw-r--r--tex/context/base/x-cals.mkiv15
-rw-r--r--tex/context/base/x-chemml.mkiv2
-rw-r--r--tex/context/base/x-ct.mkiv2
-rw-r--r--tex/context/base/x-fo.tex8
-rw-r--r--tex/context/base/x-mathml.lua77
-rw-r--r--tex/context/base/x-mathml.mkiv88
-rw-r--r--tex/context/base/x-newcml.tex8
-rw-r--r--tex/context/base/x-newmme.tex4
-rw-r--r--tex/context/base/x-newmml.mkii23
-rw-r--r--tex/context/base/x-newmml.tex2
-rw-r--r--tex/context/base/x-newmmo.tex2
-rw-r--r--tex/context/base/x-newpml.tex2
-rw-r--r--tex/context/base/x-set-02.tex11
-rw-r--r--tex/context/base/x-set-11.mkii2
-rw-r--r--tex/context/base/x-set-11.mkiv2
-rw-r--r--tex/context/base/x-set-11.tex2
-rw-r--r--tex/context/base/xetx-chr.tex1167
-rw-r--r--tex/context/base/xetx-cls.tex378
-rw-r--r--tex/context/base/xetx-ini.tex132
-rw-r--r--tex/context/base/xetx-utf.tex1989
-rw-r--r--tex/context/base/xtag-cml.tex2
-rw-r--r--tex/context/base/xtag-ent.tex2
-rw-r--r--tex/context/base/xtag-exp.tex6
-rw-r--r--tex/context/base/xtag-ext.tex4
-rw-r--r--tex/context/base/xtag-hyp.tex6
-rw-r--r--tex/context/base/xtag-ini.mkii6
-rw-r--r--tex/context/base/xtag-ini.mkiv2
-rw-r--r--tex/context/base/xtag-ini.tex24
-rw-r--r--tex/context/base/xtag-map.tex4
-rw-r--r--tex/context/base/xtag-mmc.tex8
-rw-r--r--tex/context/base/xtag-mml.tex8
-rw-r--r--tex/context/base/xtag-mmp.tex31
-rw-r--r--tex/context/base/xtag-pml.tex3
-rw-r--r--tex/context/base/xtag-pmu.tex4
-rw-r--r--tex/context/base/xtag-pre.tex4
-rw-r--r--tex/context/base/xtag-prs.tex2
-rw-r--r--tex/context/base/xtag-raw.tex6
-rw-r--r--tex/context/base/xtag-rng.tex14
-rw-r--r--tex/context/base/xtag-run.tex4
-rw-r--r--tex/context/base/xtag-stk.tex4
-rw-r--r--tex/context/base/xtag-utf.tex6
-rw-r--r--tex/context/bib/bibl-apa-fr.tex2
-rw-r--r--tex/context/bib/bibl-apa.tex6
-rw-r--r--tex/context/bib/t-bib.mkii5
-rw-r--r--tex/context/bib/t-bib.mkiv64
-rw-r--r--tex/context/bib/t-bib.tex74
-rw-r--r--tex/context/config/cont-usr.tex2
-rw-r--r--tex/context/interface/cont-cs.xml32
-rw-r--r--tex/context/interface/cont-cz.xml10033
-rw-r--r--tex/context/interface/cont-de.xml32
-rw-r--r--tex/context/interface/cont-en.xml32
-rw-r--r--tex/context/interface/cont-fr.xml32
-rw-r--r--tex/context/interface/cont-it.xml32
-rw-r--r--tex/context/interface/cont-nl.xml32
-rw-r--r--tex/context/interface/cont-pe.xml32
-rw-r--r--tex/context/interface/cont-ro.xml32
-rw-r--r--tex/context/interface/keys-cs.xml57
-rw-r--r--tex/context/interface/keys-de.xml57
-rw-r--r--tex/context/interface/keys-en.xml57
-rw-r--r--tex/context/interface/keys-fr.xml57
-rw-r--r--tex/context/interface/keys-it.xml57
-rw-r--r--tex/context/interface/keys-nl.xml57
-rw-r--r--tex/context/interface/keys-pe.xml57
-rw-r--r--tex/context/interface/keys-ro.xml57
-rw-r--r--tex/context/interface/t-bib.xml3
-rw-r--r--tex/context/patterns/lang-de.hyp4
-rw-r--r--tex/context/patterns/lang-de.pat5446
-rw-r--r--tex/context/patterns/lang-de.rme8
-rw-r--r--tex/context/patterns/lang-deo.hyp4
-rw-r--r--tex/context/patterns/lang-deo.pat5446
-rw-r--r--tex/context/patterns/lang-deo.rme8
-rw-r--r--tex/context/patterns/lang-uk.hyp8
-rw-r--r--tex/context/patterns/lang-uk.pat1905
-rw-r--r--tex/context/patterns/lang-uk.rme70
-rw-r--r--tex/context/test/context-test.tex27
-rw-r--r--tex/context/user/cont-sys.rme9
-rw-r--r--tex/generic/context/luatex-basics.tex21
-rw-r--r--tex/generic/context/luatex-fonts-merged.lua11070
-rw-r--r--tex/generic/context/luatex-fonts.lua139
-rw-r--r--tex/generic/context/luatex-fonts.tex139
-rw-r--r--tex/generic/context/luatex-mplib.lua469
-rw-r--r--tex/generic/context/luatex-mplib.tex118
-rw-r--r--tex/generic/context/luatex-plain.tex25
-rw-r--r--tex/generic/context/luatex-test.tex47
-rw-r--r--tex/generic/context/ppchtex.noc4
-rw-r--r--tpm/t-bib.tpm8
-rw-r--r--web2c/context.cnf87
976 files changed, 211020 insertions, 91234 deletions
diff --git a/context/data/cont-pe-scite.properties b/context/data/cont-pe-scite.properties
new file mode 100644
index 000000000..a9756b04c
--- /dev/null
+++ b/context/data/cont-pe-scite.properties
@@ -0,0 +1,97 @@
+keywordclass.macros.context.pe=\
+CAP Cap Caps Character Characters MONTH \
+Romannumerals WEEKDAY WORD WORDS Word Words \
+appendix cap chapter chem completecombinedlist completelistoffloats \
+completelistofsorts completelistofsynonyms coupledregister crlf definebodyfontDEF definebodyfontREF \
+definedfont definefontfeature definefonthandling definetypeface description enumeration \
+framedtext indentation its labeling loadsorts loadsynonyms \
+mapfontsize mediaeval name nextsection nocap paragraph \
+part placelistoffloats placelistofsorts placelistofsynonyms ran register \
+reservefloat resettextcontent section seeregister setupcapitals setupfonthandling \
+setupfontsynonym setupinterlinespace2 setuplistalternative setupurl sort startalignment \
+startbuffer startbuffer startcolumns startcombination startdescription startdocument \
+startenumeration startfigure startfloattext startformula startframedtext starthiding \
+startitemgroup startlegend startline startlinecorrection startlinenumbering startlines \
+startlocal startlocalenvironment startlocalfootnotes startmakeup startmarginblock startnamemakeup \
+startnarrower startopposite startoverlay startoverview startparagraph startpositioning \
+startpostponing startprofile startregister startsymbolset startsynchronization starttable \
+starttables starttabulate starttyping startunpacked startتوضیح startتولید \
+startحقیقت startخط‌حاشیه startخط‌متن startرنگ startفشرده startمحیط \
+startمنوی‌پانل startمولفه startنسخه startنقل‌قول startپروژه startپس‌زمینه \
+stopalignment stopbuffer stopbuffer stopcolumns stopcombination stopdescription \
+stopdocument stopenumeration stopfigure stopfloattext stopformula stopframedtext \
+stophiding stopitemgroup stoplegend stopline stoplinecorrection stoplinenumbering \
+stoplines stoplocal stoplocalenvironment stoplocalfootnotes stopmakeup stopmarginblock \
+stopnamemakeup stopnarrower stopopposite stopoverlay stopoverview stopparagraph \
+stoppositioning stoppostponing stopprofile stopsymbolset stopsynchronization stoptable \
+stoptables stoptabulate stoptyping stopunpacked stopتوضیح stopتولید \
+stopحقیقت stopخط‌حاشیه stopخط‌متن stopرنگ stopفشرده stopمحیط \
+stopمنوی‌پانل stopمولفه stopنسخه stopنقل‌قول stopپروژه stopپس‌زمینه \
+sub subject subsection subsubject subsubsection subsubsubject \
+synonym title tooltip typ useURL usedirectory \
+آیتم آیتمها آینه اجباربلوکها از ازکارانداختن‌منوی‌پانل \
+استفاده‌بلوکها استفاده‌دستخط‌تایپ استفاده‌رمزینه استفاده‌شکل‌خارجی استفاده‌فرمانها استفاده‌قطعه‌موزیک‌خارجی \
+استفاده‌مدول استفاده‌مرجعها استفاده‌نمادها استفاده‌نوشتارخارجی استفاده‌ویژگیها استفاده‌پرونده‌خارجی \
+استفاده‌پرونده‌دستخط‌تایپ استفاده‌پرونده‌های‌خارجی اعدادلاتین اما انتخاب‌برگ انتخاب‌بلوکها \
+انتخاب‌نسخه انتقال‌به‌توری بارگذاری‌آرایش بارگذاری‌آیتمها بارگذاری‌ارجاع بارگذاری‌اندازه‌برگ \
+بارگذاری‌باریکتر بارگذاری‌بافر بارگذاری‌بالا بارگذاری‌بخش بارگذاری‌بردباری بارگذاری‌برنامه‌ها \
+بارگذاری‌برگ بارگذاری‌بست بارگذاری‌بلوک بارگذاری‌بلوکهای‌حاشیه بارگذاری‌بلوک‌بخش بارگذاری‌تایپ \
+بارگذاری‌تایپ‌کردن بارگذاری‌تب بارگذاری‌ترتیب بارگذاری‌ترتیب بارگذاری‌ترکیب‌ها بارگذاری‌تطابق \
+بارگذاری‌تعریف‌پانوشت بارگذاری‌تنظیم بارگذاری‌ته‌برگ بارگذاری‌تورفتگی بارگذاری‌تورفتگیها بارگذاری‌توضیح \
+بارگذاری‌ثبت بارگذاری‌جدولها بارگذاری‌جدول‌بندی بارگذاری‌خالی بارگذاری‌خروجی بارگذاری‌خطها \
+بارگذاری‌خطهای‌حاشیه بارگذاری‌خطهای‌سیاه بارگذاری‌خطهای‌متن بارگذاری‌خطها‌ی‌نازک بارگذاری‌درج‌درخطها بارگذاری‌درج‌مخالف \
+بارگذاری‌درون‌حاشیه بارگذاری‌دوران بارگذاری‌دکمه‌ها بارگذاری‌راهنما بارگذاری‌رنگ بارگذاری‌رنگها \
+بارگذاری‌زبان بارگذاری‌ستونها بارگذاری‌سر بارگذاری‌سربرگ بارگذاری‌سرها بارگذاری‌سیستم \
+بارگذاری‌شرح بارگذاری‌شرح بارگذاری‌شرحها بارگذاری‌شماره‌زیرصفحه بارگذاری‌شماره‌سر بارگذاری‌شماره‌صفحه \
+بارگذاری‌شماره‌گذاری بارگذاری‌شماره‌گذاریها بارگذاری‌شماره‌گذاری‌صفحه بارگذاری‌شماره‌گذاری‌پاراگراف بارگذاری‌شماره‌‌گذاری‌خط بارگذاری‌شناور \
+بارگذاری‌شناورها بارگذاری‌شکافتن‌شناورها بارگذاری‌شکلهای‌خارجی بارگذاری‌طرح بارگذاری‌طرح‌بندی بارگذاری‌عرض‌خط \
+بارگذاری‌فاصله‌بین‌خط بارگذاری‌فرمولها بارگذاری‌فضای‌سفید بارگذاری‌فضا‌گذاری بارگذاری‌قالبی بارگذاری‌قلم‌متن \
+بارگذاری‌لوح بارگذاری‌لیست بارگذاری‌لیست‌ترکیبی بارگذاری‌لیست‌مرجع بارگذاری‌مترادفها بارگذاری‌متن \
+بارگذاری‌متنهای‌بالا بارگذاری‌متن‌سر بارگذاری‌متن‌سربرگ بارگذاری‌متن‌قالبی بارگذاری‌متن‌متنها بارگذاری‌متن‌پانوشت \
+بارگذاری‌متن‌پایین بارگذاری‌مجموعه‌نماد بارگذاری‌محیط‌قلم‌متن بارگذاری‌منوی‌پانل بارگذاری‌مکان‌گذاری بارگذاری‌میدان \
+بارگذاری‌میدانها بارگذاری‌میله‌تطابق بارگذاری‌میله‌زیر بارگذاری‌میله‌پانل بارگذاری‌نسخه‌ها بارگذاری‌نشانه‌شکستن \
+بارگذاری‌نشانه‌گذاری بارگذاری‌نشرها بارگذاری‌نقل بارگذاری‌پاراگرافها بارگذاری‌پانل بارگذاری‌پانوشتها \
+بارگذاری‌پایین بارگذاری‌پرده‌ها بارگذاری‌پرده‌پانل بارگذاری‌پروفایلها بارگذاری‌پرکردن‌خطها بارگذاری‌پس‌زمینه \
+بارگذاری‌پس‌زمینه‌ها بارگذاری‌چیدن بارگذاری‌گذارصفحه بارگذاری‌گروه‌آیتم بازنشانی بازنشانی‌نشانه‌گذاری \
+باگذاری‌متن‌برچسب بدون‌بلوکهای‌بیشتر بدون‌تورفتگی بدون‌خط‌بالاوپایین بدون‌خط‌سروته‌برگ بدون‌فایلهای‌بیشتر \
+بدون‌فضا بدون‌فضای‌سفید بدون‌لیست بدون‌نشانه‌گذاری برنامه بروبه \
+بروبه‌جعبه بروپایین برچسبها بلند بلوکهای‌پردازش بلوکها‌پنهان \
+بنویس‌بین‌لیست بنویس‌درثبت بنویس‌درلیست‌مرجع بنویس‌در‌لیست تاریخ تاریخ‌جاری \
+تاریخ‌رجوع تایپ تایپ‌بافر تایپ‌پرونده تب ترجمه \
+تطابق تعریف تعریف‌آرایش تعریف‌آرم تعریف‌الگوی‌جدول تعریف‌اندازه‌برگ \
+تعریف‌بافر تعریف‌بخش تعریف‌برنامه تعریف‌برچسب تعریف‌بلوک تعریف‌بلوک‌بخش \
+تعریف‌تایپ تعریف‌تایپ‌کردن تعریف‌تبدیل تعریف‌ترتیب تعریف‌توده‌میدان تعریف‌تورفتگی \
+تعریف‌ثبت تعریف‌جدول‌بندی تعریف‌خالی تعریف‌خروجی تعریف‌رنگ تعریف‌زیرمیدان \
+تعریف‌سر تعریف‌شرح تعریف‌شروع‌پایان تعریف‌شماره‌بندی تعریف‌شمایل‌مرجع تعریف‌شناور \
+تعریف‌قالبی تعریف‌قلم تعریف‌قلم‌متن تعریف‌لوح تعریف‌لیست تعریف‌لیست‌ترکیبی \
+تعریف‌لیست‌مرجع تعریف‌مترادفها تعریف‌مترادف‌قلم تعریف‌متن تعریف‌متن‌قالبی تعریف‌محیط‌قلم‌بدنه \
+تعریف‌مرجع تعریف‌منوی‌پانل تعریف‌منوی‌پانل تعریف‌میدان تعریف‌نسخه تعریف‌نشانه‌گذاری \
+تعریف‌نماد تعریف‌نمادشکل تعریف‌پاراگرافها تعریف‌پروفایل تعریف‌پوشش تعریف‌گروه‌رنگ \
+تعیین‌شماره‌سر تعیین‌محتوای‌متن تعیین‌مشخصات‌لیست تغییربه‌قلم‌بدنه تنظیم‌راست تنظیم‌طرح‌بندی \
+تنظیم‌وسط تورفتگی توری توضیح تک ثبت‌زوج \
+ثبت‌کامل جداسازی‌نشانه‌گذاری حاش حرف حرفها حفظ‌بلوکها \
+خالی خطهای‌سیاه خطهای‌نازک خطها‌خالی خط‌حاشیه خط‌زدن \
+خط‌زدنها خط‌سیاه خط‌متن خط‌مو خط‌نازک خ‌ا \
+خ‌ع در درج‌آرمها درج‌ثبت درج‌ثبت درج‌درخط \
+درج‌درخطها درج‌درمتن درج‌درمیدان درج‌در‌بالای‌یکدیگر درج‌در‌توری درج‌راهنما \
+درج‌زیرفرمول درج‌شناور درج‌فرمول درج‌لیست درج‌لیست‌مختلط درج‌لیست‌مختلط \
+درج‌لیست‌مرجع درج‌پانوشتها درج‌پانوشتهای‌موضعی درج‌چوب‌خط درج‌کنار‌به‌کنار درحاشیه \
+درحاشیه‌دیگر درخارجی درخط درداخلی درراست درصفحه \
+درقالبی درمورد درون درچپ دریافت‌بافر دریافت‌نشانه \
+دوران دکمه دکمه‌پانل رج رجوع رنگ \
+رنگ‌خاکستری روزهفته ریاضی زبان زبان‌اصلی ستون \
+سر شماره‌سر شماره‌سرجاری شماره‌مبدل شماره‌ها شکافتن‌شناور \
+شکل‌خارجی صفحه صفحه‌زوج صفحه‌پردازش عبوربلوکها فشرده \
+فضا فضاهای‌ثابت فضای‌سفید فضای‌سفیدصحیح قالبی لوح‌مقایسه \
+ماه متن‌برچسب متن‌حاشیه متن‌سر متن‌پانوشت مرجع \
+مرجع‌صفحه مرجع‌متن مقایسه‌گروه‌رنگ مقیاس منفی مکان \
+میدان میدانهای‌گزارش میدان‌شبیه‌سازی میدان‌پشته میدان‌کپی میله‌تطابق \
+میله‌رو میله‌زیر میله‌ها‌رو میله‌پانل میله‌‌های‌زیر نسخه \
+نسخه‌نشانه نشانه‌گذاری نشانه‌گذاری‌زوج نشر نصب‌زبان نقطه‌ها \
+نقل نقل‌قول نم نماد نمادلیست نمایش‌آرایش \
+نمایش‌بارگذاریها نمایش‌بستها نمایش‌توری نمایش‌رنگ نمایش‌شکلهای‌خارجی نمایش‌طرح‌بندی \
+نمایش‌قالب نمایش‌قلم‌بدنه نمایش‌لوح نمایش‌مجموعه‌علامت نمایش‌محیط‌قلم‌بدنه نمایش‌میدانها \
+نمایش‌چاپ نمایش‌گروه‌رنگ نوشتارزوج نوع‌صفحه پابا پانوشت \
+پایین پرده پرکردن‌میدان پس‌زمینه پیروی‌نسخه پیروی‌نسخه‌پروفایل \
+پیروی‌پروفایل چوبخط چپ‌چین کاغذزوج کسر کشیده \
+کلمه‌راست گیره یادداشت یک‌جا یک‌خط \ No newline at end of file
diff --git a/context/data/context-bbedit-pe.xml b/context/data/context-bbedit-pe.xml
new file mode 100644
index 000000000..168e79256
--- /dev/null
+++ b/context/data/context-bbedit-pe.xml
@@ -0,0 +1 @@
+<?xml version='1.0'?><key>BBLMKeywordList</key><array> <string>\CAP</string> <string>\Cap</string> <string>\Caps</string> <string>\Character</string> <string>\Characters</string> <string>\MONTH</string> <string>\Romannumerals</string> <string>\WEEKDAY</string> <string>\WORD</string> <string>\WORDS</string> <string>\Word</string> <string>\Words</string> <string>\appendix</string> <string>\cap</string> <string>\chapter</string> <string>\chem</string> <string>\completecombinedlist</string> <string>\completelistoffloats</string> <string>\completelistofsorts</string> <string>\completelistofsynonyms</string> <string>\coupledregister</string> <string>\crlf</string> <string>\definebodyfontDEF</string> <string>\definebodyfontREF</string> <string>\definedfont</string> <string>\definefontfeature</string> <string>\definefonthandling</string> <string>\definetypeface</string> <string>\description</string> <string>\enumeration</string> <string>\framedtext</string> <string>\indentation</string> <string>\its</string> <string>\labeling</string> <string>\loadsorts</string> <string>\loadsynonyms</string> <string>\mapfontsize</string> <string>\mediaeval</string> <string>\name</string> <string>\nextsection</string> <string>\nocap</string> <string>\paragraph</string> <string>\part</string> <string>\placelistoffloats</string> <string>\placelistofsorts</string> <string>\placelistofsynonyms</string> <string>\ran</string> <string>\register</string> <string>\reservefloat</string> <string>\resettextcontent</string> <string>\section</string> <string>\seeregister</string> <string>\setupcapitals</string> <string>\setupfonthandling</string> <string>\setupfontsynonym</string> <string>\setupinterlinespace2</string> <string>\setuplistalternative</string> <string>\setupurl</string> <string>\sort</string> <string>\startalignment</string> <string>\startbuffer</string> <string>\startbuffer</string> <string>\startcolumns</string> <string>\startcombination</string> <string>\startdescription</string> <string>\startdocument</string> <string>\startenumeration</string> <string>\startfigure</string> <string>\startfloattext</string> <string>\startformula</string> <string>\startframedtext</string> <string>\starthiding</string> <string>\startitemgroup</string> <string>\startlegend</string> <string>\startline</string> <string>\startlinecorrection</string> <string>\startlinenumbering</string> <string>\startlines</string> <string>\startlocal</string> <string>\startlocalenvironment</string> <string>\startlocalfootnotes</string> <string>\startmakeup</string> <string>\startmarginblock</string> <string>\startnamemakeup</string> <string>\startnarrower</string> <string>\startopposite</string> <string>\startoverlay</string> <string>\startoverview</string> <string>\startparagraph</string> <string>\startpositioning</string> <string>\startpostponing</string> <string>\startprofile</string> <string>\startregister</string> <string>\startsymbolset</string> <string>\startsynchronization</string> <string>\starttable</string> <string>\starttables</string> <string>\starttabulate</string> <string>\starttyping</string> <string>\startunpacked</string> <string>\startتوضیح</string> <string>\startتولید</string> <string>\startحقیقت</string> <string>\startخط‌حاشیه</string> <string>\startخط‌متن</string> <string>\startرنگ</string> <string>\startفشرده</string> <string>\startمحیط</string> <string>\startمنوی‌پانل</string> <string>\startمولفه</string> <string>\startنسخه</string> <string>\startنقل‌قول</string> <string>\startپروژه</string> <string>\startپس‌زمینه</string> <string>\stopalignment</string> <string>\stopbuffer</string> <string>\stopbuffer</string> <string>\stopcolumns</string> <string>\stopcombination</string> <string>\stopdescription</string> <string>\stopdocument</string> <string>\stopenumeration</string> <string>\stopfigure</string> <string>\stopfloattext</string> <string>\stopformula</string> <string>\stopframedtext</string> <string>\stophiding</string> <string>\stopitemgroup</string> <string>\stoplegend</string> <string>\stopline</string> <string>\stoplinecorrection</string> <string>\stoplinenumbering</string> <string>\stoplines</string> <string>\stoplocal</string> <string>\stoplocalenvironment</string> <string>\stoplocalfootnotes</string> <string>\stopmakeup</string> <string>\stopmarginblock</string> <string>\stopnamemakeup</string> <string>\stopnarrower</string> <string>\stopopposite</string> <string>\stopoverlay</string> <string>\stopoverview</string> <string>\stopparagraph</string> <string>\stoppositioning</string> <string>\stoppostponing</string> <string>\stopprofile</string> <string>\stopsymbolset</string> <string>\stopsynchronization</string> <string>\stoptable</string> <string>\stoptables</string> <string>\stoptabulate</string> <string>\stoptyping</string> <string>\stopunpacked</string> <string>\stopتوضیح</string> <string>\stopتولید</string> <string>\stopحقیقت</string> <string>\stopخط‌حاشیه</string> <string>\stopخط‌متن</string> <string>\stopرنگ</string> <string>\stopفشرده</string> <string>\stopمحیط</string> <string>\stopمنوی‌پانل</string> <string>\stopمولفه</string> <string>\stopنسخه</string> <string>\stopنقل‌قول</string> <string>\stopپروژه</string> <string>\stopپس‌زمینه</string> <string>\sub</string> <string>\subject</string> <string>\subsection</string> <string>\subsubject</string> <string>\subsubsection</string> <string>\subsubsubject</string> <string>\synonym</string> <string>\title</string> <string>\tooltip</string> <string>\typ</string> <string>\useURL</string> <string>\usedirectory</string> <string>\آیتم</string> <string>\آیتمها</string> <string>\آینه</string> <string>\اجباربلوکها</string> <string>\از</string> <string>\ازکارانداختن‌منوی‌پانل</string> <string>\استفاده‌بلوکها</string> <string>\استفاده‌دستخط‌تایپ</string> <string>\استفاده‌رمزینه</string> <string>\استفاده‌شکل‌خارجی</string> <string>\استفاده‌فرمانها</string> <string>\استفاده‌قطعه‌موزیک‌خارجی</string> <string>\استفاده‌مدول</string> <string>\استفاده‌مرجعها</string> <string>\استفاده‌نمادها</string> <string>\استفاده‌نوشتارخارجی</string> <string>\استفاده‌ویژگیها</string> <string>\استفاده‌پرونده‌خارجی</string> <string>\استفاده‌پرونده‌دستخط‌تایپ</string> <string>\استفاده‌پرونده‌های‌خارجی</string> <string>\اعدادلاتین</string> <string>\اما</string> <string>\انتخاب‌برگ</string> <string>\انتخاب‌بلوکها</string> <string>\انتخاب‌نسخه</string> <string>\انتقال‌به‌توری</string> <string>\بارگذاری‌آرایش</string> <string>\بارگذاری‌آیتمها</string> <string>\بارگذاری‌ارجاع</string> <string>\بارگذاری‌اندازه‌برگ</string> <string>\بارگذاری‌باریکتر</string> <string>\بارگذاری‌بافر</string> <string>\بارگذاری‌بالا</string> <string>\بارگذاری‌بخش</string> <string>\بارگذاری‌بردباری</string> <string>\بارگذاری‌برنامه‌ها</string> <string>\بارگذاری‌برگ</string> <string>\بارگذاری‌بست</string> <string>\بارگذاری‌بلوک</string> <string>\بارگذاری‌بلوکهای‌حاشیه</string> <string>\بارگذاری‌بلوک‌بخش</string> <string>\بارگذاری‌تایپ</string> <string>\بارگذاری‌تایپ‌کردن</string> <string>\بارگذاری‌تب</string> <string>\بارگذاری‌ترتیب</string> <string>\بارگذاری‌ترتیب</string> <string>\بارگذاری‌ترکیب‌ها</string> <string>\بارگذاری‌تطابق</string> <string>\بارگذاری‌تعریف‌پانوشت</string> <string>\بارگذاری‌تنظیم</string> <string>\بارگذاری‌ته‌برگ</string> <string>\بارگذاری‌تورفتگی</string> <string>\بارگذاری‌تورفتگیها</string> <string>\بارگذاری‌توضیح</string> <string>\بارگذاری‌ثبت</string> <string>\بارگذاری‌جدولها</string> <string>\بارگذاری‌جدول‌بندی</string> <string>\بارگذاری‌خالی</string> <string>\بارگذاری‌خروجی</string> <string>\بارگذاری‌خطها</string> <string>\بارگذاری‌خطهای‌حاشیه</string> <string>\بارگذاری‌خطهای‌سیاه</string> <string>\بارگذاری‌خطهای‌متن</string> <string>\بارگذاری‌خطها‌ی‌نازک</string> <string>\بارگذاری‌درج‌درخطها</string> <string>\بارگذاری‌درج‌مخالف</string> <string>\بارگذاری‌درون‌حاشیه</string> <string>\بارگذاری‌دوران</string> <string>\بارگذاری‌دکمه‌ها</string> <string>\بارگذاری‌راهنما</string> <string>\بارگذاری‌رنگ</string> <string>\بارگذاری‌رنگها</string> <string>\بارگذاری‌زبان</string> <string>\بارگذاری‌ستونها</string> <string>\بارگذاری‌سر</string> <string>\بارگذاری‌سربرگ</string> <string>\بارگذاری‌سرها</string> <string>\بارگذاری‌سیستم</string> <string>\بارگذاری‌شرح</string> <string>\بارگذاری‌شرح</string> <string>\بارگذاری‌شرحها</string> <string>\بارگذاری‌شماره‌زیرصفحه</string> <string>\بارگذاری‌شماره‌سر</string> <string>\بارگذاری‌شماره‌صفحه</string> <string>\بارگذاری‌شماره‌گذاری</string> <string>\بارگذاری‌شماره‌گذاریها</string> <string>\بارگذاری‌شماره‌گذاری‌صفحه</string> <string>\بارگذاری‌شماره‌گذاری‌پاراگراف</string> <string>\بارگذاری‌شماره‌‌گذاری‌خط</string> <string>\بارگذاری‌شناور</string> <string>\بارگذاری‌شناورها</string> <string>\بارگذاری‌شکافتن‌شناورها</string> <string>\بارگذاری‌شکلهای‌خارجی</string> <string>\بارگذاری‌طرح</string> <string>\بارگذاری‌طرح‌بندی</string> <string>\بارگذاری‌عرض‌خط</string> <string>\بارگذاری‌فاصله‌بین‌خط</string> <string>\بارگذاری‌فرمولها</string> <string>\بارگذاری‌فضای‌سفید</string> <string>\بارگذاری‌فضا‌گذاری</string> <string>\بارگذاری‌قالبی</string> <string>\بارگذاری‌قلم‌متن</string> <string>\بارگذاری‌لوح</string> <string>\بارگذاری‌لیست</string> <string>\بارگذاری‌لیست‌ترکیبی</string> <string>\بارگذاری‌لیست‌مرجع</string> <string>\بارگذاری‌مترادفها</string> <string>\بارگذاری‌متن</string> <string>\بارگذاری‌متنهای‌بالا</string> <string>\بارگذاری‌متن‌سر</string> <string>\بارگذاری‌متن‌سربرگ</string> <string>\بارگذاری‌متن‌قالبی</string> <string>\بارگذاری‌متن‌متنها</string> <string>\بارگذاری‌متن‌پانوشت</string> <string>\بارگذاری‌متن‌پایین</string> <string>\بارگذاری‌مجموعه‌نماد</string> <string>\بارگذاری‌محیط‌قلم‌متن</string> <string>\بارگذاری‌منوی‌پانل</string> <string>\بارگذاری‌مکان‌گذاری</string> <string>\بارگذاری‌میدان</string> <string>\بارگذاری‌میدانها</string> <string>\بارگذاری‌میله‌تطابق</string> <string>\بارگذاری‌میله‌زیر</string> <string>\بارگذاری‌میله‌پانل</string> <string>\بارگذاری‌نسخه‌ها</string> <string>\بارگذاری‌نشانه‌شکستن</string> <string>\بارگذاری‌نشانه‌گذاری</string> <string>\بارگذاری‌نشرها</string> <string>\بارگذاری‌نقل</string> <string>\بارگذاری‌پاراگرافها</string> <string>\بارگذاری‌پانل</string> <string>\بارگذاری‌پانوشتها</string> <string>\بارگذاری‌پایین</string> <string>\بارگذاری‌پرده‌ها</string> <string>\بارگذاری‌پرده‌پانل</string> <string>\بارگذاری‌پروفایلها</string> <string>\بارگذاری‌پرکردن‌خطها</string> <string>\بارگذاری‌پس‌زمینه</string> <string>\بارگذاری‌پس‌زمینه‌ها</string> <string>\بارگذاری‌چیدن</string> <string>\بارگذاری‌گذارصفحه</string> <string>\بارگذاری‌گروه‌آیتم</string> <string>\بازنشانی</string> <string>\بازنشانی‌نشانه‌گذاری</string> <string>\باگذاری‌متن‌برچسب</string> <string>\بدون‌بلوکهای‌بیشتر</string> <string>\بدون‌تورفتگی</string> <string>\بدون‌خط‌بالاوپایین</string> <string>\بدون‌خط‌سروته‌برگ</string> <string>\بدون‌فایلهای‌بیشتر</string> <string>\بدون‌فضا</string> <string>\بدون‌فضای‌سفید</string> <string>\بدون‌لیست</string> <string>\بدون‌نشانه‌گذاری</string> <string>\برنامه</string> <string>\بروبه</string> <string>\بروبه‌جعبه</string> <string>\بروپایین</string> <string>\برچسبها</string> <string>\بلند</string> <string>\بلوکهای‌پردازش</string> <string>\بلوکها‌پنهان</string> <string>\بنویس‌بین‌لیست</string> <string>\بنویس‌درثبت</string> <string>\بنویس‌درلیست‌مرجع</string> <string>\بنویس‌در‌لیست</string> <string>\تاریخ</string> <string>\تاریخ‌جاری</string> <string>\تاریخ‌رجوع</string> <string>\تایپ</string> <string>\تایپ‌بافر</string> <string>\تایپ‌پرونده</string> <string>\تب</string> <string>\ترجمه</string> <string>\تطابق</string> <string>\تعریف</string> <string>\تعریف‌آرایش</string> <string>\تعریف‌آرم</string> <string>\تعریف‌الگوی‌جدول</string> <string>\تعریف‌اندازه‌برگ</string> <string>\تعریف‌بافر</string> <string>\تعریف‌بخش</string> <string>\تعریف‌برنامه</string> <string>\تعریف‌برچسب</string> <string>\تعریف‌بلوک</string> <string>\تعریف‌بلوک‌بخش</string> <string>\تعریف‌تایپ</string> <string>\تعریف‌تایپ‌کردن</string> <string>\تعریف‌تبدیل</string> <string>\تعریف‌ترتیب</string> <string>\تعریف‌توده‌میدان</string> <string>\تعریف‌تورفتگی</string> <string>\تعریف‌ثبت</string> <string>\تعریف‌جدول‌بندی</string> <string>\تعریف‌خالی</string> <string>\تعریف‌خروجی</string> <string>\تعریف‌رنگ</string> <string>\تعریف‌زیرمیدان</string> <string>\تعریف‌سر</string> <string>\تعریف‌شرح</string> <string>\تعریف‌شروع‌پایان</string> <string>\تعریف‌شماره‌بندی</string> <string>\تعریف‌شمایل‌مرجع</string> <string>\تعریف‌شناور</string> <string>\تعریف‌قالبی</string> <string>\تعریف‌قلم</string> <string>\تعریف‌قلم‌متن</string> <string>\تعریف‌لوح</string> <string>\تعریف‌لیست</string> <string>\تعریف‌لیست‌ترکیبی</string> <string>\تعریف‌لیست‌مرجع</string> <string>\تعریف‌مترادفها</string> <string>\تعریف‌مترادف‌قلم</string> <string>\تعریف‌متن</string> <string>\تعریف‌متن‌قالبی</string> <string>\تعریف‌محیط‌قلم‌بدنه</string> <string>\تعریف‌مرجع</string> <string>\تعریف‌منوی‌پانل</string> <string>\تعریف‌منوی‌پانل</string> <string>\تعریف‌میدان</string> <string>\تعریف‌نسخه</string> <string>\تعریف‌نشانه‌گذاری</string> <string>\تعریف‌نماد</string> <string>\تعریف‌نمادشکل</string> <string>\تعریف‌پاراگرافها</string> <string>\تعریف‌پروفایل</string> <string>\تعریف‌پوشش</string> <string>\تعریف‌گروه‌رنگ</string> <string>\تعیین‌شماره‌سر</string> <string>\تعیین‌محتوای‌متن</string> <string>\تعیین‌مشخصات‌لیست</string> <string>\تغییربه‌قلم‌بدنه</string> <string>\تنظیم‌راست</string> <string>\تنظیم‌طرح‌بندی</string> <string>\تنظیم‌وسط</string> <string>\تورفتگی</string> <string>\توری</string> <string>\توضیح</string> <string>\تک</string> <string>\ثبت‌زوج</string> <string>\ثبت‌کامل</string> <string>\جداسازی‌نشانه‌گذاری</string> <string>\حاش</string> <string>\حرف</string> <string>\حرفها</string> <string>\حفظ‌بلوکها</string> <string>\خالی</string> <string>\خطهای‌سیاه</string> <string>\خطهای‌نازک</string> <string>\خطها‌خالی</string> <string>\خط‌حاشیه</string> <string>\خط‌زدن</string> <string>\خط‌زدنها</string> <string>\خط‌سیاه</string> <string>\خط‌متن</string> <string>\خط‌مو</string> <string>\خط‌نازک</string> <string>\خ‌ا</string> <string>\خ‌ع</string> <string>\در</string> <string>\درج‌آرمها</string> <string>\درج‌ثبت</string> <string>\درج‌ثبت</string> <string>\درج‌درخط</string> <string>\درج‌درخطها</string> <string>\درج‌درمتن</string> <string>\درج‌درمیدان</string> <string>\درج‌در‌بالای‌یکدیگر</string> <string>\درج‌در‌توری</string> <string>\درج‌راهنما</string> <string>\درج‌زیرفرمول</string> <string>\درج‌شناور</string> <string>\درج‌فرمول</string> <string>\درج‌لیست</string> <string>\درج‌لیست‌مختلط</string> <string>\درج‌لیست‌مختلط</string> <string>\درج‌لیست‌مرجع</string> <string>\درج‌پانوشتها</string> <string>\درج‌پانوشتهای‌موضعی</string> <string>\درج‌چوب‌خط</string> <string>\درج‌کنار‌به‌کنار</string> <string>\درحاشیه</string> <string>\درحاشیه‌دیگر</string> <string>\درخارجی</string> <string>\درخط</string> <string>\درداخلی</string> <string>\درراست</string> <string>\درصفحه</string> <string>\درقالبی</string> <string>\درمورد</string> <string>\درون</string> <string>\درچپ</string> <string>\دریافت‌بافر</string> <string>\دریافت‌نشانه</string> <string>\دوران</string> <string>\دکمه</string> <string>\دکمه‌پانل</string> <string>\رج</string> <string>\رجوع</string> <string>\رنگ</string> <string>\رنگ‌خاکستری</string> <string>\روزهفته</string> <string>\ریاضی</string> <string>\زبان</string> <string>\زبان‌اصلی</string> <string>\ستون</string> <string>\سر</string> <string>\شماره‌سر</string> <string>\شماره‌سرجاری</string> <string>\شماره‌مبدل</string> <string>\شماره‌ها</string> <string>\شکافتن‌شناور</string> <string>\شکل‌خارجی</string> <string>\صفحه</string> <string>\صفحه‌زوج</string> <string>\صفحه‌پردازش</string> <string>\عبوربلوکها</string> <string>\فشرده</string> <string>\فضا</string> <string>\فضاهای‌ثابت</string> <string>\فضای‌سفید</string> <string>\فضای‌سفیدصحیح</string> <string>\قالبی</string> <string>\لوح‌مقایسه</string> <string>\ماه</string> <string>\متن‌برچسب</string> <string>\متن‌حاشیه</string> <string>\متن‌سر</string> <string>\متن‌پانوشت</string> <string>\مرجع</string> <string>\مرجع‌صفحه</string> <string>\مرجع‌متن</string> <string>\مقایسه‌گروه‌رنگ</string> <string>\مقیاس</string> <string>\منفی</string> <string>\مکان</string> <string>\میدان</string> <string>\میدانهای‌گزارش</string> <string>\میدان‌شبیه‌سازی</string> <string>\میدان‌پشته</string> <string>\میدان‌کپی</string> <string>\میله‌تطابق</string> <string>\میله‌رو</string> <string>\میله‌زیر</string> <string>\میله‌ها‌رو</string> <string>\میله‌پانل</string> <string>\میله‌‌های‌زیر</string> <string>\نسخه</string> <string>\نسخه‌نشانه</string> <string>\نشانه‌گذاری</string> <string>\نشانه‌گذاری‌زوج</string> <string>\نشر</string> <string>\نصب‌زبان</string> <string>\نقطه‌ها</string> <string>\نقل</string> <string>\نقل‌قول</string> <string>\نم</string> <string>\نماد</string> <string>\نمادلیست</string> <string>\نمایش‌آرایش</string> <string>\نمایش‌بارگذاریها</string> <string>\نمایش‌بستها</string> <string>\نمایش‌توری</string> <string>\نمایش‌رنگ</string> <string>\نمایش‌شکلهای‌خارجی</string> <string>\نمایش‌طرح‌بندی</string> <string>\نمایش‌قالب</string> <string>\نمایش‌قلم‌بدنه</string> <string>\نمایش‌لوح</string> <string>\نمایش‌مجموعه‌علامت</string> <string>\نمایش‌محیط‌قلم‌بدنه</string> <string>\نمایش‌میدانها</string> <string>\نمایش‌چاپ</string> <string>\نمایش‌گروه‌رنگ</string> <string>\نوشتارزوج</string> <string>\نوع‌صفحه</string> <string>\پابا</string> <string>\پانوشت</string> <string>\پایین</string> <string>\پرده</string> <string>\پرکردن‌میدان</string> <string>\پس‌زمینه</string> <string>\پیروی‌نسخه</string> <string>\پیروی‌نسخه‌پروفایل</string> <string>\پیروی‌پروفایل</string> <string>\چوبخط</string> <string>\چپ‌چین</string> <string>\کاغذزوج</string> <string>\کسر</string> <string>\کشیده</string> <string>\کلمه‌راست</string> <string>\گیره</string> <string>\یادداشت</string> <string>\یک‌جا</string> <string>\یک‌خط</string></array> \ No newline at end of file
diff --git a/context/data/context-jedit-pe.xml b/context/data/context-jedit-pe.xml
new file mode 100644
index 000000000..4667614f3
--- /dev/null
+++ b/context/data/context-jedit-pe.xml
@@ -0,0 +1,2 @@
+<?xml version='1.0'?><!DOCTYPE MODE SYSTEM 'xmode.dtd'>
+<MODE> <RULES> <KEYWORDS> <KEYWORD2>CAP</KEYWORD2> <KEYWORD2>Cap</KEYWORD2> <KEYWORD2>Caps</KEYWORD2> <KEYWORD2>Character</KEYWORD2> <KEYWORD2>Characters</KEYWORD2> <KEYWORD2>MONTH</KEYWORD2> <KEYWORD2>Romannumerals</KEYWORD2> <KEYWORD2>WEEKDAY</KEYWORD2> <KEYWORD2>WORD</KEYWORD2> <KEYWORD2>WORDS</KEYWORD2> <KEYWORD2>Word</KEYWORD2> <KEYWORD2>Words</KEYWORD2> <KEYWORD2>appendix</KEYWORD2> <KEYWORD2>cap</KEYWORD2> <KEYWORD2>chapter</KEYWORD2> <KEYWORD2>chem</KEYWORD2> <KEYWORD2>completecombinedlist</KEYWORD2> <KEYWORD2>completelistoffloats</KEYWORD2> <KEYWORD2>completelistofsorts</KEYWORD2> <KEYWORD2>completelistofsynonyms</KEYWORD2> <KEYWORD2>coupledregister</KEYWORD2> <KEYWORD2>crlf</KEYWORD2> <KEYWORD2>definebodyfontDEF</KEYWORD2> <KEYWORD2>definebodyfontREF</KEYWORD2> <KEYWORD2>definedfont</KEYWORD2> <KEYWORD2>definefontfeature</KEYWORD2> <KEYWORD2>definefonthandling</KEYWORD2> <KEYWORD2>definetypeface</KEYWORD2> <KEYWORD2>description</KEYWORD2> <KEYWORD2>enumeration</KEYWORD2> <KEYWORD2>framedtext</KEYWORD2> <KEYWORD2>indentation</KEYWORD2> <KEYWORD2>its</KEYWORD2> <KEYWORD2>labeling</KEYWORD2> <KEYWORD2>loadsorts</KEYWORD2> <KEYWORD2>loadsynonyms</KEYWORD2> <KEYWORD2>mapfontsize</KEYWORD2> <KEYWORD2>mediaeval</KEYWORD2> <KEYWORD2>name</KEYWORD2> <KEYWORD2>nextsection</KEYWORD2> <KEYWORD2>nocap</KEYWORD2> <KEYWORD2>paragraph</KEYWORD2> <KEYWORD2>part</KEYWORD2> <KEYWORD2>placelistoffloats</KEYWORD2> <KEYWORD2>placelistofsorts</KEYWORD2> <KEYWORD2>placelistofsynonyms</KEYWORD2> <KEYWORD2>ran</KEYWORD2> <KEYWORD2>register</KEYWORD2> <KEYWORD2>reservefloat</KEYWORD2> <KEYWORD2>resettextcontent</KEYWORD2> <KEYWORD2>section</KEYWORD2> <KEYWORD2>seeregister</KEYWORD2> <KEYWORD2>setupcapitals</KEYWORD2> <KEYWORD2>setupfonthandling</KEYWORD2> <KEYWORD2>setupfontsynonym</KEYWORD2> <KEYWORD2>setupinterlinespace2</KEYWORD2> <KEYWORD2>setuplistalternative</KEYWORD2> <KEYWORD2>setupurl</KEYWORD2> <KEYWORD2>sort</KEYWORD2> <KEYWORD2>startalignment</KEYWORD2> <KEYWORD2>startbuffer</KEYWORD2> <KEYWORD2>startbuffer</KEYWORD2> <KEYWORD2>startcolumns</KEYWORD2> <KEYWORD2>startcombination</KEYWORD2> <KEYWORD2>startdescription</KEYWORD2> <KEYWORD2>startdocument</KEYWORD2> <KEYWORD2>startenumeration</KEYWORD2> <KEYWORD2>startfigure</KEYWORD2> <KEYWORD2>startfloattext</KEYWORD2> <KEYWORD2>startformula</KEYWORD2> <KEYWORD2>startframedtext</KEYWORD2> <KEYWORD2>starthiding</KEYWORD2> <KEYWORD2>startitemgroup</KEYWORD2> <KEYWORD2>startlegend</KEYWORD2> <KEYWORD2>startline</KEYWORD2> <KEYWORD2>startlinecorrection</KEYWORD2> <KEYWORD2>startlinenumbering</KEYWORD2> <KEYWORD2>startlines</KEYWORD2> <KEYWORD2>startlocal</KEYWORD2> <KEYWORD2>startlocalenvironment</KEYWORD2> <KEYWORD2>startlocalfootnotes</KEYWORD2> <KEYWORD2>startmakeup</KEYWORD2> <KEYWORD2>startmarginblock</KEYWORD2> <KEYWORD2>startnamemakeup</KEYWORD2> <KEYWORD2>startnarrower</KEYWORD2> <KEYWORD2>startopposite</KEYWORD2> <KEYWORD2>startoverlay</KEYWORD2> <KEYWORD2>startoverview</KEYWORD2> <KEYWORD2>startparagraph</KEYWORD2> <KEYWORD2>startpositioning</KEYWORD2> <KEYWORD2>startpostponing</KEYWORD2> <KEYWORD2>startprofile</KEYWORD2> <KEYWORD2>startregister</KEYWORD2> <KEYWORD2>startsymbolset</KEYWORD2> <KEYWORD2>startsynchronization</KEYWORD2> <KEYWORD2>starttable</KEYWORD2> <KEYWORD2>starttables</KEYWORD2> <KEYWORD2>starttabulate</KEYWORD2> <KEYWORD2>starttyping</KEYWORD2> <KEYWORD2>startunpacked</KEYWORD2> <KEYWORD2>startتوضیح</KEYWORD2> <KEYWORD2>startتولید</KEYWORD2> <KEYWORD2>startحقیقت</KEYWORD2> <KEYWORD2>startخط‌حاشیه</KEYWORD2> <KEYWORD2>startخط‌متن</KEYWORD2> <KEYWORD2>startرنگ</KEYWORD2> <KEYWORD2>startفشرده</KEYWORD2> <KEYWORD2>startمحیط</KEYWORD2> <KEYWORD2>startمنوی‌پانل</KEYWORD2> <KEYWORD2>startمولفه</KEYWORD2> <KEYWORD2>startنسخه</KEYWORD2> <KEYWORD2>startنقل‌قول</KEYWORD2> <KEYWORD2>startپروژه</KEYWORD2> <KEYWORD2>startپس‌زمینه</KEYWORD2> <KEYWORD2>stopalignment</KEYWORD2> <KEYWORD2>stopbuffer</KEYWORD2> <KEYWORD2>stopbuffer</KEYWORD2> <KEYWORD2>stopcolumns</KEYWORD2> <KEYWORD2>stopcombination</KEYWORD2> <KEYWORD2>stopdescription</KEYWORD2> <KEYWORD2>stopdocument</KEYWORD2> <KEYWORD2>stopenumeration</KEYWORD2> <KEYWORD2>stopfigure</KEYWORD2> <KEYWORD2>stopfloattext</KEYWORD2> <KEYWORD2>stopformula</KEYWORD2> <KEYWORD2>stopframedtext</KEYWORD2> <KEYWORD2>stophiding</KEYWORD2> <KEYWORD2>stopitemgroup</KEYWORD2> <KEYWORD2>stoplegend</KEYWORD2> <KEYWORD2>stopline</KEYWORD2> <KEYWORD2>stoplinecorrection</KEYWORD2> <KEYWORD2>stoplinenumbering</KEYWORD2> <KEYWORD2>stoplines</KEYWORD2> <KEYWORD2>stoplocal</KEYWORD2> <KEYWORD2>stoplocalenvironment</KEYWORD2> <KEYWORD2>stoplocalfootnotes</KEYWORD2> <KEYWORD2>stopmakeup</KEYWORD2> <KEYWORD2>stopmarginblock</KEYWORD2> <KEYWORD2>stopnamemakeup</KEYWORD2> <KEYWORD2>stopnarrower</KEYWORD2> <KEYWORD2>stopopposite</KEYWORD2> <KEYWORD2>stopoverlay</KEYWORD2> <KEYWORD2>stopoverview</KEYWORD2> <KEYWORD2>stopparagraph</KEYWORD2> <KEYWORD2>stoppositioning</KEYWORD2> <KEYWORD2>stoppostponing</KEYWORD2> <KEYWORD2>stopprofile</KEYWORD2> <KEYWORD2>stopsymbolset</KEYWORD2> <KEYWORD2>stopsynchronization</KEYWORD2> <KEYWORD2>stoptable</KEYWORD2> <KEYWORD2>stoptables</KEYWORD2> <KEYWORD2>stoptabulate</KEYWORD2> <KEYWORD2>stoptyping</KEYWORD2> <KEYWORD2>stopunpacked</KEYWORD2> <KEYWORD2>stopتوضیح</KEYWORD2> <KEYWORD2>stopتولید</KEYWORD2> <KEYWORD2>stopحقیقت</KEYWORD2> <KEYWORD2>stopخط‌حاشیه</KEYWORD2> <KEYWORD2>stopخط‌متن</KEYWORD2> <KEYWORD2>stopرنگ</KEYWORD2> <KEYWORD2>stopفشرده</KEYWORD2> <KEYWORD2>stopمحیط</KEYWORD2> <KEYWORD2>stopمنوی‌پانل</KEYWORD2> <KEYWORD2>stopمولفه</KEYWORD2> <KEYWORD2>stopنسخه</KEYWORD2> <KEYWORD2>stopنقل‌قول</KEYWORD2> <KEYWORD2>stopپروژه</KEYWORD2> <KEYWORD2>stopپس‌زمینه</KEYWORD2> <KEYWORD2>sub</KEYWORD2> <KEYWORD2>subject</KEYWORD2> <KEYWORD2>subsection</KEYWORD2> <KEYWORD2>subsubject</KEYWORD2> <KEYWORD2>subsubsection</KEYWORD2> <KEYWORD2>subsubsubject</KEYWORD2> <KEYWORD2>synonym</KEYWORD2> <KEYWORD2>title</KEYWORD2> <KEYWORD2>tooltip</KEYWORD2> <KEYWORD2>typ</KEYWORD2> <KEYWORD2>useURL</KEYWORD2> <KEYWORD2>usedirectory</KEYWORD2> <KEYWORD2>آیتم</KEYWORD2> <KEYWORD2>آیتمها</KEYWORD2> <KEYWORD2>آینه</KEYWORD2> <KEYWORD2>اجباربلوکها</KEYWORD2> <KEYWORD2>از</KEYWORD2> <KEYWORD2>ازکارانداختن‌منوی‌پانل</KEYWORD2> <KEYWORD2>استفاده‌بلوکها</KEYWORD2> <KEYWORD2>استفاده‌دستخط‌تایپ</KEYWORD2> <KEYWORD2>استفاده‌رمزینه</KEYWORD2> <KEYWORD2>استفاده‌شکل‌خارجی</KEYWORD2> <KEYWORD2>استفاده‌فرمانها</KEYWORD2> <KEYWORD2>استفاده‌قطعه‌موزیک‌خارجی</KEYWORD2> <KEYWORD2>استفاده‌مدول</KEYWORD2> <KEYWORD2>استفاده‌مرجعها</KEYWORD2> <KEYWORD2>استفاده‌نمادها</KEYWORD2> <KEYWORD2>استفاده‌نوشتارخارجی</KEYWORD2> <KEYWORD2>استفاده‌ویژگیها</KEYWORD2> <KEYWORD2>استفاده‌پرونده‌خارجی</KEYWORD2> <KEYWORD2>استفاده‌پرونده‌دستخط‌تایپ</KEYWORD2> <KEYWORD2>استفاده‌پرونده‌های‌خارجی</KEYWORD2> <KEYWORD2>اعدادلاتین</KEYWORD2> <KEYWORD2>اما</KEYWORD2> <KEYWORD2>انتخاب‌برگ</KEYWORD2> <KEYWORD2>انتخاب‌بلوکها</KEYWORD2> <KEYWORD2>انتخاب‌نسخه</KEYWORD2> <KEYWORD2>انتقال‌به‌توری</KEYWORD2> <KEYWORD2>بارگذاری‌آرایش</KEYWORD2> <KEYWORD2>بارگذاری‌آیتمها</KEYWORD2> <KEYWORD2>بارگذاری‌ارجاع</KEYWORD2> <KEYWORD2>بارگذاری‌اندازه‌برگ</KEYWORD2> <KEYWORD2>بارگذاری‌باریکتر</KEYWORD2> <KEYWORD2>بارگذاری‌بافر</KEYWORD2> <KEYWORD2>بارگذاری‌بالا</KEYWORD2> <KEYWORD2>بارگذاری‌بخش</KEYWORD2> <KEYWORD2>بارگذاری‌بردباری</KEYWORD2> <KEYWORD2>بارگذاری‌برنامه‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌برگ</KEYWORD2> <KEYWORD2>بارگذاری‌بست</KEYWORD2> <KEYWORD2>بارگذاری‌بلوک</KEYWORD2> <KEYWORD2>بارگذاری‌بلوکهای‌حاشیه</KEYWORD2> <KEYWORD2>بارگذاری‌بلوک‌بخش</KEYWORD2> <KEYWORD2>بارگذاری‌تایپ</KEYWORD2> <KEYWORD2>بارگذاری‌تایپ‌کردن</KEYWORD2> <KEYWORD2>بارگذاری‌تب</KEYWORD2> <KEYWORD2>بارگذاری‌ترتیب</KEYWORD2> <KEYWORD2>بارگذاری‌ترتیب</KEYWORD2> <KEYWORD2>بارگذاری‌ترکیب‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌تطابق</KEYWORD2> <KEYWORD2>بارگذاری‌تعریف‌پانوشت</KEYWORD2> <KEYWORD2>بارگذاری‌تنظیم</KEYWORD2> <KEYWORD2>بارگذاری‌ته‌برگ</KEYWORD2> <KEYWORD2>بارگذاری‌تورفتگی</KEYWORD2> <KEYWORD2>بارگذاری‌تورفتگیها</KEYWORD2> <KEYWORD2>بارگذاری‌توضیح</KEYWORD2> <KEYWORD2>بارگذاری‌ثبت</KEYWORD2> <KEYWORD2>بارگذاری‌جدولها</KEYWORD2> <KEYWORD2>بارگذاری‌جدول‌بندی</KEYWORD2> <KEYWORD2>بارگذاری‌خالی</KEYWORD2> <KEYWORD2>بارگذاری‌خروجی</KEYWORD2> <KEYWORD2>بارگذاری‌خطها</KEYWORD2> <KEYWORD2>بارگذاری‌خطهای‌حاشیه</KEYWORD2> <KEYWORD2>بارگذاری‌خطهای‌سیاه</KEYWORD2> <KEYWORD2>بارگذاری‌خطهای‌متن</KEYWORD2> <KEYWORD2>بارگذاری‌خطها‌ی‌نازک</KEYWORD2> <KEYWORD2>بارگذاری‌درج‌درخطها</KEYWORD2> <KEYWORD2>بارگذاری‌درج‌مخالف</KEYWORD2> <KEYWORD2>بارگذاری‌درون‌حاشیه</KEYWORD2> <KEYWORD2>بارگذاری‌دوران</KEYWORD2> <KEYWORD2>بارگذاری‌دکمه‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌راهنما</KEYWORD2> <KEYWORD2>بارگذاری‌رنگ</KEYWORD2> <KEYWORD2>بارگذاری‌رنگها</KEYWORD2> <KEYWORD2>بارگذاری‌زبان</KEYWORD2> <KEYWORD2>بارگذاری‌ستونها</KEYWORD2> <KEYWORD2>بارگذاری‌سر</KEYWORD2> <KEYWORD2>بارگذاری‌سربرگ</KEYWORD2> <KEYWORD2>بارگذاری‌سرها</KEYWORD2> <KEYWORD2>بارگذاری‌سیستم</KEYWORD2> <KEYWORD2>بارگذاری‌شرح</KEYWORD2> <KEYWORD2>بارگذاری‌شرح</KEYWORD2> <KEYWORD2>بارگذاری‌شرحها</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌زیرصفحه</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌سر</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌صفحه</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌گذاری</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌گذاریها</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌گذاری‌صفحه</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌گذاری‌پاراگراف</KEYWORD2> <KEYWORD2>بارگذاری‌شماره‌‌گذاری‌خط</KEYWORD2> <KEYWORD2>بارگذاری‌شناور</KEYWORD2> <KEYWORD2>بارگذاری‌شناورها</KEYWORD2> <KEYWORD2>بارگذاری‌شکافتن‌شناورها</KEYWORD2> <KEYWORD2>بارگذاری‌شکلهای‌خارجی</KEYWORD2> <KEYWORD2>بارگذاری‌طرح</KEYWORD2> <KEYWORD2>بارگذاری‌طرح‌بندی</KEYWORD2> <KEYWORD2>بارگذاری‌عرض‌خط</KEYWORD2> <KEYWORD2>بارگذاری‌فاصله‌بین‌خط</KEYWORD2> <KEYWORD2>بارگذاری‌فرمولها</KEYWORD2> <KEYWORD2>بارگذاری‌فضای‌سفید</KEYWORD2> <KEYWORD2>بارگذاری‌فضا‌گذاری</KEYWORD2> <KEYWORD2>بارگذاری‌قالبی</KEYWORD2> <KEYWORD2>بارگذاری‌قلم‌متن</KEYWORD2> <KEYWORD2>بارگذاری‌لوح</KEYWORD2> <KEYWORD2>بارگذاری‌لیست</KEYWORD2> <KEYWORD2>بارگذاری‌لیست‌ترکیبی</KEYWORD2> <KEYWORD2>بارگذاری‌لیست‌مرجع</KEYWORD2> <KEYWORD2>بارگذاری‌مترادفها</KEYWORD2> <KEYWORD2>بارگذاری‌متن</KEYWORD2> <KEYWORD2>بارگذاری‌متنهای‌بالا</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌سر</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌سربرگ</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌قالبی</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌متنها</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌پانوشت</KEYWORD2> <KEYWORD2>بارگذاری‌متن‌پایین</KEYWORD2> <KEYWORD2>بارگذاری‌مجموعه‌نماد</KEYWORD2> <KEYWORD2>بارگذاری‌محیط‌قلم‌متن</KEYWORD2> <KEYWORD2>بارگذاری‌منوی‌پانل</KEYWORD2> <KEYWORD2>بارگذاری‌مکان‌گذاری</KEYWORD2> <KEYWORD2>بارگذاری‌میدان</KEYWORD2> <KEYWORD2>بارگذاری‌میدانها</KEYWORD2> <KEYWORD2>بارگذاری‌میله‌تطابق</KEYWORD2> <KEYWORD2>بارگذاری‌میله‌زیر</KEYWORD2> <KEYWORD2>بارگذاری‌میله‌پانل</KEYWORD2> <KEYWORD2>بارگذاری‌نسخه‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌نشانه‌شکستن</KEYWORD2> <KEYWORD2>بارگذاری‌نشانه‌گذاری</KEYWORD2> <KEYWORD2>بارگذاری‌نشرها</KEYWORD2> <KEYWORD2>بارگذاری‌نقل</KEYWORD2> <KEYWORD2>بارگذاری‌پاراگرافها</KEYWORD2> <KEYWORD2>بارگذاری‌پانل</KEYWORD2> <KEYWORD2>بارگذاری‌پانوشتها</KEYWORD2> <KEYWORD2>بارگذاری‌پایین</KEYWORD2> <KEYWORD2>بارگذاری‌پرده‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌پرده‌پانل</KEYWORD2> <KEYWORD2>بارگذاری‌پروفایلها</KEYWORD2> <KEYWORD2>بارگذاری‌پرکردن‌خطها</KEYWORD2> <KEYWORD2>بارگذاری‌پس‌زمینه</KEYWORD2> <KEYWORD2>بارگذاری‌پس‌زمینه‌ها</KEYWORD2> <KEYWORD2>بارگذاری‌چیدن</KEYWORD2> <KEYWORD2>بارگذاری‌گذارصفحه</KEYWORD2> <KEYWORD2>بارگذاری‌گروه‌آیتم</KEYWORD2> <KEYWORD2>بازنشانی</KEYWORD2> <KEYWORD2>بازنشانی‌نشانه‌گذاری</KEYWORD2> <KEYWORD2>باگذاری‌متن‌برچسب</KEYWORD2> <KEYWORD2>بدون‌بلوکهای‌بیشتر</KEYWORD2> <KEYWORD2>بدون‌تورفتگی</KEYWORD2> <KEYWORD2>بدون‌خط‌بالاوپایین</KEYWORD2> <KEYWORD2>بدون‌خط‌سروته‌برگ</KEYWORD2> <KEYWORD2>بدون‌فایلهای‌بیشتر</KEYWORD2> <KEYWORD2>بدون‌فضا</KEYWORD2> <KEYWORD2>بدون‌فضای‌سفید</KEYWORD2> <KEYWORD2>بدون‌لیست</KEYWORD2> <KEYWORD2>بدون‌نشانه‌گذاری</KEYWORD2> <KEYWORD2>برنامه</KEYWORD2> <KEYWORD2>بروبه</KEYWORD2> <KEYWORD2>بروبه‌جعبه</KEYWORD2> <KEYWORD2>بروپایین</KEYWORD2> <KEYWORD2>برچسبها</KEYWORD2> <KEYWORD2>بلند</KEYWORD2> <KEYWORD2>بلوکهای‌پردازش</KEYWORD2> <KEYWORD2>بلوکها‌پنهان</KEYWORD2> <KEYWORD2>بنویس‌بین‌لیست</KEYWORD2> <KEYWORD2>بنویس‌درثبت</KEYWORD2> <KEYWORD2>بنویس‌درلیست‌مرجع</KEYWORD2> <KEYWORD2>بنویس‌در‌لیست</KEYWORD2> <KEYWORD2>تاریخ</KEYWORD2> <KEYWORD2>تاریخ‌جاری</KEYWORD2> <KEYWORD2>تاریخ‌رجوع</KEYWORD2> <KEYWORD2>تایپ</KEYWORD2> <KEYWORD2>تایپ‌بافر</KEYWORD2> <KEYWORD2>تایپ‌پرونده</KEYWORD2> <KEYWORD2>تب</KEYWORD2> <KEYWORD2>ترجمه</KEYWORD2> <KEYWORD2>تطابق</KEYWORD2> <KEYWORD2>تعریف</KEYWORD2> <KEYWORD2>تعریف‌آرایش</KEYWORD2> <KEYWORD2>تعریف‌آرم</KEYWORD2> <KEYWORD2>تعریف‌الگوی‌جدول</KEYWORD2> <KEYWORD2>تعریف‌اندازه‌برگ</KEYWORD2> <KEYWORD2>تعریف‌بافر</KEYWORD2> <KEYWORD2>تعریف‌بخش</KEYWORD2> <KEYWORD2>تعریف‌برنامه</KEYWORD2> <KEYWORD2>تعریف‌برچسب</KEYWORD2> <KEYWORD2>تعریف‌بلوک</KEYWORD2> <KEYWORD2>تعریف‌بلوک‌بخش</KEYWORD2> <KEYWORD2>تعریف‌تایپ</KEYWORD2> <KEYWORD2>تعریف‌تایپ‌کردن</KEYWORD2> <KEYWORD2>تعریف‌تبدیل</KEYWORD2> <KEYWORD2>تعریف‌ترتیب</KEYWORD2> <KEYWORD2>تعریف‌توده‌میدان</KEYWORD2> <KEYWORD2>تعریف‌تورفتگی</KEYWORD2> <KEYWORD2>تعریف‌ثبت</KEYWORD2> <KEYWORD2>تعریف‌جدول‌بندی</KEYWORD2> <KEYWORD2>تعریف‌خالی</KEYWORD2> <KEYWORD2>تعریف‌خروجی</KEYWORD2> <KEYWORD2>تعریف‌رنگ</KEYWORD2> <KEYWORD2>تعریف‌زیرمیدان</KEYWORD2> <KEYWORD2>تعریف‌سر</KEYWORD2> <KEYWORD2>تعریف‌شرح</KEYWORD2> <KEYWORD2>تعریف‌شروع‌پایان</KEYWORD2> <KEYWORD2>تعریف‌شماره‌بندی</KEYWORD2> <KEYWORD2>تعریف‌شمایل‌مرجع</KEYWORD2> <KEYWORD2>تعریف‌شناور</KEYWORD2> <KEYWORD2>تعریف‌قالبی</KEYWORD2> <KEYWORD2>تعریف‌قلم</KEYWORD2> <KEYWORD2>تعریف‌قلم‌متن</KEYWORD2> <KEYWORD2>تعریف‌لوح</KEYWORD2> <KEYWORD2>تعریف‌لیست</KEYWORD2> <KEYWORD2>تعریف‌لیست‌ترکیبی</KEYWORD2> <KEYWORD2>تعریف‌لیست‌مرجع</KEYWORD2> <KEYWORD2>تعریف‌مترادفها</KEYWORD2> <KEYWORD2>تعریف‌مترادف‌قلم</KEYWORD2> <KEYWORD2>تعریف‌متن</KEYWORD2> <KEYWORD2>تعریف‌متن‌قالبی</KEYWORD2> <KEYWORD2>تعریف‌محیط‌قلم‌بدنه</KEYWORD2> <KEYWORD2>تعریف‌مرجع</KEYWORD2> <KEYWORD2>تعریف‌منوی‌پانل</KEYWORD2> <KEYWORD2>تعریف‌منوی‌پانل</KEYWORD2> <KEYWORD2>تعریف‌میدان</KEYWORD2> <KEYWORD2>تعریف‌نسخه</KEYWORD2> <KEYWORD2>تعریف‌نشانه‌گذاری</KEYWORD2> <KEYWORD2>تعریف‌نماد</KEYWORD2> <KEYWORD2>تعریف‌نمادشکل</KEYWORD2> <KEYWORD2>تعریف‌پاراگرافها</KEYWORD2> <KEYWORD2>تعریف‌پروفایل</KEYWORD2> <KEYWORD2>تعریف‌پوشش</KEYWORD2> <KEYWORD2>تعریف‌گروه‌رنگ</KEYWORD2> <KEYWORD2>تعیین‌شماره‌سر</KEYWORD2> <KEYWORD2>تعیین‌محتوای‌متن</KEYWORD2> <KEYWORD2>تعیین‌مشخصات‌لیست</KEYWORD2> <KEYWORD2>تغییربه‌قلم‌بدنه</KEYWORD2> <KEYWORD2>تنظیم‌راست</KEYWORD2> <KEYWORD2>تنظیم‌طرح‌بندی</KEYWORD2> <KEYWORD2>تنظیم‌وسط</KEYWORD2> <KEYWORD2>تورفتگی</KEYWORD2> <KEYWORD2>توری</KEYWORD2> <KEYWORD2>توضیح</KEYWORD2> <KEYWORD2>تک</KEYWORD2> <KEYWORD2>ثبت‌زوج</KEYWORD2> <KEYWORD2>ثبت‌کامل</KEYWORD2> <KEYWORD2>جداسازی‌نشانه‌گذاری</KEYWORD2> <KEYWORD2>حاش</KEYWORD2> <KEYWORD2>حرف</KEYWORD2> <KEYWORD2>حرفها</KEYWORD2> <KEYWORD2>حفظ‌بلوکها</KEYWORD2> <KEYWORD2>خالی</KEYWORD2> <KEYWORD2>خطهای‌سیاه</KEYWORD2> <KEYWORD2>خطهای‌نازک</KEYWORD2> <KEYWORD2>خطها‌خالی</KEYWORD2> <KEYWORD2>خط‌حاشیه</KEYWORD2> <KEYWORD2>خط‌زدن</KEYWORD2> <KEYWORD2>خط‌زدنها</KEYWORD2> <KEYWORD2>خط‌سیاه</KEYWORD2> <KEYWORD2>خط‌متن</KEYWORD2> <KEYWORD2>خط‌مو</KEYWORD2> <KEYWORD2>خط‌نازک</KEYWORD2> <KEYWORD2>خ‌ا</KEYWORD2> <KEYWORD2>خ‌ع</KEYWORD2> <KEYWORD2>در</KEYWORD2> <KEYWORD2>درج‌آرمها</KEYWORD2> <KEYWORD2>درج‌ثبت</KEYWORD2> <KEYWORD2>درج‌ثبت</KEYWORD2> <KEYWORD2>درج‌درخط</KEYWORD2> <KEYWORD2>درج‌درخطها</KEYWORD2> <KEYWORD2>درج‌درمتن</KEYWORD2> <KEYWORD2>درج‌درمیدان</KEYWORD2> <KEYWORD2>درج‌در‌بالای‌یکدیگر</KEYWORD2> <KEYWORD2>درج‌در‌توری</KEYWORD2> <KEYWORD2>درج‌راهنما</KEYWORD2> <KEYWORD2>درج‌زیرفرمول</KEYWORD2> <KEYWORD2>درج‌شناور</KEYWORD2> <KEYWORD2>درج‌فرمول</KEYWORD2> <KEYWORD2>درج‌لیست</KEYWORD2> <KEYWORD2>درج‌لیست‌مختلط</KEYWORD2> <KEYWORD2>درج‌لیست‌مختلط</KEYWORD2> <KEYWORD2>درج‌لیست‌مرجع</KEYWORD2> <KEYWORD2>درج‌پانوشتها</KEYWORD2> <KEYWORD2>درج‌پانوشتهای‌موضعی</KEYWORD2> <KEYWORD2>درج‌چوب‌خط</KEYWORD2> <KEYWORD2>درج‌کنار‌به‌کنار</KEYWORD2> <KEYWORD2>درحاشیه</KEYWORD2> <KEYWORD2>درحاشیه‌دیگر</KEYWORD2> <KEYWORD2>درخارجی</KEYWORD2> <KEYWORD2>درخط</KEYWORD2> <KEYWORD2>درداخلی</KEYWORD2> <KEYWORD2>درراست</KEYWORD2> <KEYWORD2>درصفحه</KEYWORD2> <KEYWORD2>درقالبی</KEYWORD2> <KEYWORD2>درمورد</KEYWORD2> <KEYWORD2>درون</KEYWORD2> <KEYWORD2>درچپ</KEYWORD2> <KEYWORD2>دریافت‌بافر</KEYWORD2> <KEYWORD2>دریافت‌نشانه</KEYWORD2> <KEYWORD2>دوران</KEYWORD2> <KEYWORD2>دکمه</KEYWORD2> <KEYWORD2>دکمه‌پانل</KEYWORD2> <KEYWORD2>رج</KEYWORD2> <KEYWORD2>رجوع</KEYWORD2> <KEYWORD2>رنگ</KEYWORD2> <KEYWORD2>رنگ‌خاکستری</KEYWORD2> <KEYWORD2>روزهفته</KEYWORD2> <KEYWORD2>ریاضی</KEYWORD2> <KEYWORD2>زبان</KEYWORD2> <KEYWORD2>زبان‌اصلی</KEYWORD2> <KEYWORD2>ستون</KEYWORD2> <KEYWORD2>سر</KEYWORD2> <KEYWORD2>شماره‌سر</KEYWORD2> <KEYWORD2>شماره‌سرجاری</KEYWORD2> <KEYWORD2>شماره‌مبدل</KEYWORD2> <KEYWORD2>شماره‌ها</KEYWORD2> <KEYWORD2>شکافتن‌شناور</KEYWORD2> <KEYWORD2>شکل‌خارجی</KEYWORD2> <KEYWORD2>صفحه</KEYWORD2> <KEYWORD2>صفحه‌زوج</KEYWORD2> <KEYWORD2>صفحه‌پردازش</KEYWORD2> <KEYWORD2>عبوربلوکها</KEYWORD2> <KEYWORD2>فشرده</KEYWORD2> <KEYWORD2>فضا</KEYWORD2> <KEYWORD2>فضاهای‌ثابت</KEYWORD2> <KEYWORD2>فضای‌سفید</KEYWORD2> <KEYWORD2>فضای‌سفیدصحیح</KEYWORD2> <KEYWORD2>قالبی</KEYWORD2> <KEYWORD2>لوح‌مقایسه</KEYWORD2> <KEYWORD2>ماه</KEYWORD2> <KEYWORD2>متن‌برچسب</KEYWORD2> <KEYWORD2>متن‌حاشیه</KEYWORD2> <KEYWORD2>متن‌سر</KEYWORD2> <KEYWORD2>متن‌پانوشت</KEYWORD2> <KEYWORD2>مرجع</KEYWORD2> <KEYWORD2>مرجع‌صفحه</KEYWORD2> <KEYWORD2>مرجع‌متن</KEYWORD2> <KEYWORD2>مقایسه‌گروه‌رنگ</KEYWORD2> <KEYWORD2>مقیاس</KEYWORD2> <KEYWORD2>منفی</KEYWORD2> <KEYWORD2>مکان</KEYWORD2> <KEYWORD2>میدان</KEYWORD2> <KEYWORD2>میدانهای‌گزارش</KEYWORD2> <KEYWORD2>میدان‌شبیه‌سازی</KEYWORD2> <KEYWORD2>میدان‌پشته</KEYWORD2> <KEYWORD2>میدان‌کپی</KEYWORD2> <KEYWORD2>میله‌تطابق</KEYWORD2> <KEYWORD2>میله‌رو</KEYWORD2> <KEYWORD2>میله‌زیر</KEYWORD2> <KEYWORD2>میله‌ها‌رو</KEYWORD2> <KEYWORD2>میله‌پانل</KEYWORD2> <KEYWORD2>میله‌‌های‌زیر</KEYWORD2> <KEYWORD2>نسخه</KEYWORD2> <KEYWORD2>نسخه‌نشانه</KEYWORD2> <KEYWORD2>نشانه‌گذاری</KEYWORD2> <KEYWORD2>نشانه‌گذاری‌زوج</KEYWORD2> <KEYWORD2>نشر</KEYWORD2> <KEYWORD2>نصب‌زبان</KEYWORD2> <KEYWORD2>نقطه‌ها</KEYWORD2> <KEYWORD2>نقل</KEYWORD2> <KEYWORD2>نقل‌قول</KEYWORD2> <KEYWORD2>نم</KEYWORD2> <KEYWORD2>نماد</KEYWORD2> <KEYWORD2>نمادلیست</KEYWORD2> <KEYWORD2>نمایش‌آرایش</KEYWORD2> <KEYWORD2>نمایش‌بارگذاریها</KEYWORD2> <KEYWORD2>نمایش‌بستها</KEYWORD2> <KEYWORD2>نمایش‌توری</KEYWORD2> <KEYWORD2>نمایش‌رنگ</KEYWORD2> <KEYWORD2>نمایش‌شکلهای‌خارجی</KEYWORD2> <KEYWORD2>نمایش‌طرح‌بندی</KEYWORD2> <KEYWORD2>نمایش‌قالب</KEYWORD2> <KEYWORD2>نمایش‌قلم‌بدنه</KEYWORD2> <KEYWORD2>نمایش‌لوح</KEYWORD2> <KEYWORD2>نمایش‌مجموعه‌علامت</KEYWORD2> <KEYWORD2>نمایش‌محیط‌قلم‌بدنه</KEYWORD2> <KEYWORD2>نمایش‌میدانها</KEYWORD2> <KEYWORD2>نمایش‌چاپ</KEYWORD2> <KEYWORD2>نمایش‌گروه‌رنگ</KEYWORD2> <KEYWORD2>نوشتارزوج</KEYWORD2> <KEYWORD2>نوع‌صفحه</KEYWORD2> <KEYWORD2>پابا</KEYWORD2> <KEYWORD2>پانوشت</KEYWORD2> <KEYWORD2>پایین</KEYWORD2> <KEYWORD2>پرده</KEYWORD2> <KEYWORD2>پرکردن‌میدان</KEYWORD2> <KEYWORD2>پس‌زمینه</KEYWORD2> <KEYWORD2>پیروی‌نسخه</KEYWORD2> <KEYWORD2>پیروی‌نسخه‌پروفایل</KEYWORD2> <KEYWORD2>پیروی‌پروفایل</KEYWORD2> <KEYWORD2>چوبخط</KEYWORD2> <KEYWORD2>چپ‌چین</KEYWORD2> <KEYWORD2>کاغذزوج</KEYWORD2> <KEYWORD2>کسر</KEYWORD2> <KEYWORD2>کشیده</KEYWORD2> <KEYWORD2>کلمه‌راست</KEYWORD2> <KEYWORD2>گیره</KEYWORD2> <KEYWORD2>یادداشت</KEYWORD2> <KEYWORD2>یک‌جا</KEYWORD2> <KEYWORD2>یک‌خط</KEYWORD2> </KEYWORDS> </RULES></MODE> \ No newline at end of file
diff --git a/context/data/context.properties b/context/data/context.properties
index 48a8d0efe..cd1e8b367 100644
--- a/context/data/context.properties
+++ b/context/data/context.properties
@@ -75,20 +75,24 @@ if PLAT_GTK
name.metafun.console=$(name.context.console)
name.example.console=$(name.context.console)
-name.context.concheck=texmfstart concheck
-name.context.texexec=texmfstart texexec $(name.texexec.flag.pdfopen)
-name.context.texshow=texmfstart texshow
-name.context.purge=texmfstart ctxtools --purge --all
-name.context.update=texmfstart ctxtools --update
-name.context.showcase=texmfstart --file=showcase.pdf --program=context
+if PLAT_WIN
+ name.context.mtxrun=mtxrun.cmd --autogenerate
+
+if PLAT_GTK
+ name.context.mtxrun=mtxrun --autogenerate
-# name.context.examplap=texmfstart --browser --file=http://localhost:8061/exalogin
+name.context.concheck=$(name.context.mtxrun) --script check
+name.context.texexec=$(name.context.mtxrun) --script context $(name.texexec.flag.pdfopen)
+name.context.texshow=$(name.context.mtxrun) texshow
+name.context.purge=$(name.context.mtxrun) ctxtools --purge --all
+name.context.update=$(name.context.mtxrun) texshow --update --force
+name.context.showcase=$(name.context.mtxrun) --launch showcase.pdf
name.context.backend=pdf
name.example.xmlcheck=tidy -quiet -utf8 -xml -errors
-name.metafun.mptopdf=texmfstart mptopdf.pl
+name.metafun.mptopdf=$(name.context.mtxrun) --script mptopdf
# wwwserver --start --port=8061 --url=http://localhost:8061 --forcetemp --direct
# wwwserver.rb --direct
@@ -96,10 +100,10 @@ name.metafun.mptopdf=texmfstart mptopdf.pl
# if needed one can set MTX_SERVER_ROOT to the root of the documentation
if PLAT_WIN
- name.context.wwwserver=cmd /c start /min "Context Documentation" mtxrun --script server --start
+ name.context.wwwserver=cmd /c start /min "Context Documentation" $(name.context.mtxrun) --script server --start
if PLAT_GTK
- name.context.wwwserver=texmfstart mtxrun --script server --start > ~/context-wwwserver.log &
+ name.context.wwwserver=$(name.context.mtxrun) --script server --start > ~/context-wwwserver.log &
# Commands: help info, e:\websites\www.pragma-ade.com\showcase.pdf / todo: manuals
@@ -137,7 +141,6 @@ command.compile.*.fo=$(name.example.xmlcheck) $(FileNameExt)
#command.compile.subsystem.$(file.patterns.example)=1
command.build.$(file.patterns.context)=$(name.context.texexec) --$(name.context.backend) $(FileNameExt)
-# command.build.$(file.patterns.metafun)=$(name.context.texexec) --$(name.context.backend) --mptex $(FileNameExt)
command.build.$(file.patterns.metafun)=$(name.metafun.mptopdf) $(FileNameExt)
command.build.$(file.patterns.example)=$(name.context.texexec) --$(name.context.backend) --xml $(FileNameExt)
command.build.*.fo=$(name.context.texexec) --$(name.context.backend) $(name.texexec.flag.pdfopen) --xml --use=foxet $(FileNameExt)
@@ -381,6 +384,11 @@ if PLAT_GTK
font.monospace=font:!lm mono 10 regular,size:14
font.errorfont=font:!lm mono 10 regular,size:12
+#~ if PLAT_WIN
+ #~ font.monospace=font:Lucida Console,size:12
+ #~ font.monospace=font:Lucida Sans Unicode,size:12
+ #~ font.monospace=font:OpenSymbol,size:17
+
font.base=$(font.monospace)
#~ font.small=$(font.monospace)
font.comment=$(font.monospace)
diff --git a/doc/context/bib/bibmod-doc.pdf b/doc/context/bib/bibmod-doc.pdf
index 7e122fbb1..ea1db3160 100644
--- a/doc/context/bib/bibmod-doc.pdf
+++ b/doc/context/bib/bibmod-doc.pdf
Binary files differ
diff --git a/doc/context/bib/bibmod-doc.tex b/doc/context/bib/bibmod-doc.tex
index a2b246ee4..2ffdfa9f2 100644
--- a/doc/context/bib/bibmod-doc.tex
+++ b/doc/context/bib/bibmod-doc.tex
@@ -6,7 +6,6 @@
\usemodule[bib,set-11,mod-01]
-\setuppublications[alternative=num]
\startXMLmapping[zero]
\processXMLfilegrouped{t-bib.xml}
@@ -60,7 +59,7 @@
The bibliographic module (\type{t-bib.tex}) takes care of references
to publications and the typesetting of publication lists, as well as
providing an interface between \BIBTEX and \CONTEXT. This manual
-documents version 2006.09.15.
+documents version 2009.03.02.
The bibliographic subsystem consists of the main module
\type{t-bib.tex}; four \BIBTEX\ styles (\type{cont-xx.bst}); and a set
@@ -303,6 +302,7 @@ their own options:
\starttabulate[|l|p|]
\NC andtext \NC separation between two authors (for \type{\cite[author]} styles)\NC \NR
\NC otherstext \NC text used for `et.al.' (for \type{\cite[author]} styles)\NC \NR
+\NC namesep \NC the separation between consecutive authors (for \type{\cite[author]} styles)\NC \NR
\NC pubsep \NC separator between publication references in a
\type{\cite} command.\NC \NR
\NC lastpubsep \NC same, but for the
@@ -359,7 +359,7 @@ and select the parts that are needed for the current article.
Starting with version 2006.08.08, the module registers \BIBTEX\ as a
program to be run by texexec, so you no longer need to run \BIBTEX\ by
-hand.
+hand (and in MkIV, the module runs \BIBTEX\ on the fly using Lua).
Still, you may want to create the \type{\jobname.bbl} yourself. The
\type{.bbl} syntax is explained below. There is no default
@@ -747,4 +747,4 @@ point.
\stopmodule
-\stoptext \ No newline at end of file
+\stoptext
diff --git a/fonts/enc/dvips/context/lm-ec-os.enc b/fonts/enc/dvips/context/lm-ec-os.enc
deleted file mode 100644
index 6bb22f319..000000000
--- a/fonts/enc/dvips/context/lm-ec-os.enc
+++ /dev/null
@@ -1,258 +0,0 @@
-/enclmec[
-/grave
-/acute
-/circumflex
-/tilde
-/dieresis
-/hungarumlaut
-/ring
-/caron
-/breve
-/macron
-/dotaccent
-/cedilla
-/ogonek
-/quotesinglbase
-/guilsinglleft
-/guilsinglright
-/quotedblleft
-/quotedblright
-/quotedblbase
-/guillemotleft
-/guillemotright
-/endash
-/emdash
-/cwm
-/perthousandzero
-/dotlessi
-/dotlessj
-/ff
-/fi
-/fl
-/ffi
-/ffl
-/visiblespace
-/exclam
-/quotedbl
-/numbersign
-/dollar
-/percent
-/ampersand
-/quoteright
-/parenleft
-/parenright
-/asterisk
-/plus
-/comma
-/hyphen
-/period
-/slash
-/zero.oldstyle
-/one.oldstyle
-/two.oldstyle
-/three.oldstyle
-/four.oldstyle
-/five.oldstyle
-/six.oldstyle
-/seven.oldstyle
-/eight.oldstyle
-/nine.oldstyle
-/colon
-/semicolon
-/less
-/equal
-/greater
-/question
-/at
-/A
-/B
-/C
-/D
-/E
-/F
-/G
-/H
-/I
-/J
-/K
-/L
-/M
-/N
-/O
-/P
-/Q
-/R
-/S
-/T
-/U
-/V
-/W
-/X
-/Y
-/Z
-/bracketleft
-/backslash
-/bracketright
-/asciicircum
-/underscore
-/quoteleft
-/a
-/b
-/c
-/d
-/e
-/f
-/g
-/h
-/i
-/j
-/k
-/l
-/m
-/n
-/o
-/p
-/q
-/r
-/s
-/t
-/u
-/v
-/w
-/x
-/y
-/z
-/braceleft
-/bar
-/braceright
-/asciitilde
-/hyphenchar
-/Abreve
-/Aogonek
-/Cacute
-/Ccaron
-/Dcaron
-/Ecaron
-/Eogonek
-/Gbreve
-/Lacute
-/Lcaron
-/Lslash
-/Nacute
-/Ncaron
-/Eng
-/Ohungarumlaut
-/Racute
-/Rcaron
-/Sacute
-/Scaron
-/Scedilla
-/Tcaron
-/Tcedilla
-/Uhungarumlaut
-/Uring
-/Ydieresis
-/Zacute
-/Zcaron
-/Zdotaccent
-/IJ
-/Idotaccent
-/dcroat
-/section
-/abreve
-/aogonek
-/cacute
-/ccaron
-/dcaron
-/ecaron
-/eogonek
-/gbreve
-/lacute
-/lcaron
-/lslash
-/nacute
-/ncaron
-/eng
-/ohungarumlaut
-/racute
-/rcaron
-/sacute
-/scaron
-/scedilla
-/tcaron
-/tcedilla
-/uhungarumlaut
-/uring
-/ydieresis
-/zacute
-/zcaron
-/zdotaccent
-/ij
-/exclamdown
-/questiondown
-/sterling
-/Agrave
-/Aacute
-/Acircumflex
-/Atilde
-/Adieresis
-/Aring
-/AE
-/Ccedilla
-/Egrave
-/Eacute
-/Ecircumflex
-/Edieresis
-/Igrave
-/Iacute
-/Icircumflex
-/Idieresis
-/Eth
-/Ntilde
-/Ograve
-/Oacute
-/Ocircumflex
-/Otilde
-/Odieresis
-/OE
-/Oslash
-/Ugrave
-/Uacute
-/Ucircumflex
-/Udieresis
-/Yacute
-/Thorn
-/Germandbls
-/agrave
-/aacute
-/acircumflex
-/atilde
-/adieresis
-/aring
-/ae
-/ccedilla
-/egrave
-/eacute
-/ecircumflex
-/edieresis
-/igrave
-/iacute
-/icircumflex
-/idieresis
-/eth
-/ntilde
-/ograve
-/oacute
-/ocircumflex
-/otilde
-/odieresis
-/oe
-/oslash
-/ugrave
-/uacute
-/ucircumflex
-/udieresis
-/yacute
-/thorn
-/germandbls
-] def
diff --git a/fonts/enc/dvips/context/lm-qx-os.enc b/fonts/enc/dvips/context/lm-qx-os.enc
deleted file mode 100644
index 6f4fd6bfc..000000000
--- a/fonts/enc/dvips/context/lm-qx-os.enc
+++ /dev/null
@@ -1,258 +0,0 @@
-/enclmqx[
-/.notdef
-/Delta
-/.notdef
-/.notdef
-/.notdef
-/Pi
-/Sigma
-/mu
-/ellipsis
-/f_k
-/Omega
-/ff
-/fi
-/fl
-/ffi
-/ffl
-/dotlessi
-/dotlessj
-/grave
-/acute
-/caron
-/breve
-/macron
-/ring
-/cedilla
-/germandbls
-/ae
-/oe
-/oslash
-/AE
-/OE
-/Oslash
-/space
-/exclam
-/quotedblright
-/numbersign
-/dollar
-/percent
-/ampersand
-/quoteright
-/parenleft
-/parenright
-/asterisk
-/plus
-/comma
-/hyphen
-/period
-/slash
-/zero.oldstyle
-/one.oldstyle
-/two.oldstyle
-/three.oldstyle
-/four.oldstyle
-/five.oldstyle
-/six.oldstyle
-/sevev.oldstyle
-/eight.oldstyle
-/nine.oldstyle
-/colon
-/semicolon
-/exclamdown
-/equal
-/questiondown
-/question
-/at
-/A
-/B
-/C
-/D
-/E
-/F
-/G
-/H
-/I
-/J
-/K
-/L
-/M
-/N
-/O
-/P
-/Q
-/R
-/S
-/T
-/U
-/V
-/W
-/X
-/Y
-/Z
-/bracketleft
-/quotedblleft
-/bracketright
-/circumflex
-/dotaccent
-/quoteleft
-/a
-/b
-/c
-/d
-/e
-/f
-/g
-/h
-/i
-/j
-/k
-/l
-/m
-/n
-/o
-/p
-/q
-/r
-/s
-/t
-/u
-/v
-/w
-/x
-/y
-/z
-/endash
-/emdash
-/hungarumlaut
-/tilde
-/dieresis
-/Euro
-/Aogonek
-/Cacute
-/greater
-/.notdef
-/.notdef
-/Eogonek
-/Iogonek
-/less
-/.notdef
-/Lslash
-/Nacute
-/asciitilde
-/asciicircum
-/.notdef
-/dagger
-/daggerdbl
-/Sacute
-/Scaron
-/Scommaaccent
-/degree
-/Tcommaaccent
-/ogonek
-/Uogonek
-/Ydieresis
-/Zacute
-/Zcaron
-/Zdotaccent
-/IJ
-/braceleft
-/braceright
-/section
-/.notdef
-/aogonek
-/cacute
-/registered
-/copyright
-/divide
-/eogonek
-/iogonek
-/minus
-/multiply
-/lslash
-/nacute
-/plusminus
-/.notdef
-/guillemotleft
-/guillemotright
-/paragraph
-/sacute
-/scaron
-/scommaaccent
-/bullet
-/tcommaaccent
-/threequartersemdash
-/uogonek
-/ydieresis
-/zacute
-/zcaron
-/zdotaccent
-/ij
-/periodcentered
-/quotedbl
-/quotesingle
-/Agrave
-/Aacute
-/Acircumflex
-/Atilde
-/Adieresis
-/Aring
-/backslash
-/Ccedilla
-/Egrave
-/Eacute
-/Ecircumflex
-/Edieresis
-/Igrave
-/Iacute
-/Icircumflex
-/Idieresis
-/Eth
-/Ntilde
-/Ograve
-/Oacute
-/Ocircumflex
-/Otilde
-/Odieresis
-/currency
-/perthousand
-/Ugrave
-/Uacute
-/Ucircumflex
-/Udieresis
-/Yacute
-/Thorn
-/bar
-/agrave
-/aacute
-/acircumflex
-/atilde
-/adieresis
-/aring
-/underscore
-/ccedilla
-/egrave
-/eacute
-/ecircumflex
-/edieresis
-/igrave
-/iacute
-/icircumflex
-/idieresis
-/eth
-/ntilde
-/ograve
-/oacute
-/ocircumflex
-/otilde
-/odieresis
-/anglearc
-/diameter
-/ugrave
-/uacute
-/ucircumflex
-/udieresis
-/yacute
-/thorn
-/quotedblbase
-] def
diff --git a/fonts/enc/dvips/context/lm-qxtt-os.enc b/fonts/enc/dvips/context/lm-qxtt-os.enc
deleted file mode 100644
index 905a34fd9..000000000
--- a/fonts/enc/dvips/context/lm-qxtt-os.enc
+++ /dev/null
@@ -1,258 +0,0 @@
-/enclmqxtt[
-/.notdef
-/Delta
-/.notdef
-/.notdef
-/.notdef
-/Pi
-/Sigma
-/mu
-/ellipsis
-/.notdef
-/Omega
-/.notdef
-/.notdef
-/.notdef
-/.notdef
-/.notdef
-/dotlessi
-/dotlessj
-/grave
-/acute
-/caron
-/breve
-/macron
-/ring
-/cedilla
-/germandbls
-/ae
-/oe
-/oslash
-/AE
-/OE
-/Oslash
-/visiblespace
-/exclam
-/quotedbl
-/numbersign
-/dollar
-/percent
-/ampersand
-/quoteright
-/parenleft
-/parenright
-/asterisk
-/plus
-/comma
-/hyphen
-/period
-/slash
-/zero.oldstyle
-/one.oldstyle
-/two.oldstyle
-/three.oldstyle
-/four.oldstyle
-/five.oldstyle
-/six.oldstyle
-/seven.oldstyle
-/eight.oldstyle
-/nine.oldstyle
-/colon
-/semicolon
-/less
-/equal
-/greater
-/question
-/at
-/A
-/B
-/C
-/D
-/E
-/F
-/G
-/H
-/I
-/J
-/K
-/L
-/M
-/N
-/O
-/P
-/Q
-/R
-/S
-/T
-/U
-/V
-/W
-/X
-/Y
-/Z
-/bracketleft
-/backslash
-/bracketright
-/asciicircum
-/underscore
-/quoteleft
-/a
-/b
-/c
-/d
-/e
-/f
-/g
-/h
-/i
-/j
-/k
-/l
-/m
-/n
-/o
-/p
-/q
-/r
-/s
-/t
-/u
-/v
-/w
-/x
-/y
-/z
-/braceleft
-/bar
-/braceright
-/asciitilde
-/dieresis
-/Euro
-/Aogonek
-/Cacute
-/.notdef
-/.notdef
-/.notdef
-/Eogonek
-/Iogonek
-/.notdef
-/.notdef
-/Lslash
-/Nacute
-/.notdef
-/.notdef
-/.notdef
-/dagger
-/daggerdbl
-/Sacute
-/Scaron
-/Scommaaccent
-/degree
-/Tcommaaccent
-/ogonek
-/Uogonek
-/Ydieresis
-/Zacute
-/Zcaron
-/Zdotaccent
-/.notdef
-/.notdef
-/.notdef
-/section
-/.notdef
-/aogonek
-/cacute
-/registered
-/copyright
-/divide
-/eogonek
-/iogonek
-/minus
-/multiply
-/lslash
-/nacute
-/plusminus
-/.notdef
-/guillemotleft
-/guillemotright
-/paragraph
-/sacute
-/scaron
-/scommaaccent
-/bullet
-/tcommaaccent
-/threequartersemdash
-/uogonek
-/ydieresis
-/zacute
-/zcaron
-/zdotaccent
-/.notdef
-/periodcentered
-/.notdef
-/quotesingle
-/Agrave
-/Aacute
-/Acircumflex
-/Atilde
-/Adieresis
-/Aring
-/.notdef
-/Ccedilla
-/Egrave
-/Eacute
-/Ecircumflex
-/Edieresis
-/Igrave
-/Iacute
-/Icircumflex
-/Idieresis
-/Eth
-/Ntilde
-/Ograve
-/Oacute
-/Ocircumflex
-/Otilde
-/Odieresis
-/currency
-/perthousand
-/Ugrave
-/Uacute
-/Ucircumflex
-/Udieresis
-/Yacute
-/Thorn
-/.notdef
-/agrave
-/aacute
-/acircumflex
-/atilde
-/adieresis
-/aring
-/.notdef
-/ccedilla
-/egrave
-/eacute
-/ecircumflex
-/edieresis
-/igrave
-/iacute
-/icircumflex
-/idieresis
-/eth
-/ntilde
-/ograve
-/oacute
-/ocircumflex
-/otilde
-/odieresis
-/anglearc
-/diameter
-/ugrave
-/uacute
-/ucircumflex
-/udieresis
-/yacute
-/thorn
-/quotedblbase
-] def
diff --git a/fonts/enc/dvips/context/lm-t5-os.enc b/fonts/enc/dvips/context/lm-t5-os.enc
deleted file mode 100644
index 4ff792fb7..000000000
--- a/fonts/enc/dvips/context/lm-t5-os.enc
+++ /dev/null
@@ -1,258 +0,0 @@
-/enclmt5[
-/grave
-/acute
-/circumflex
-/tilde
-/dieresis
-/dotbelow
-/ring
-/caron
-/breve
-/macron
-/dotaccent
-/cedilla
-/hookabove
-/quotesinglbase
-/guilsinglleft
-/guilsinglright
-/quotedblleft
-/quotedblright
-/quotedblbase
-/guillemotleft
-/guillemotright
-/endash
-/emdash
-/cwm
-/perthousandzero
-/dotlessi
-/Yhookabove
-/yhookabove
-/Ydotbelow
-/ydotbelow
-/Dcroat
-/dcroat
-/visiblespace
-/exclam
-/quotedbl
-/numbersign
-/dollar
-/percent
-/ampersand
-/quoteright
-/parenleft
-/parenright
-/asterisk
-/plus
-/comma
-/hyphen
-/period
-/slash
-/zero.oldstyle
-/one.oldstyle
-/two.oldstyle
-/three.oldstyle
-/four.oldstyle
-/five.oldstyle
-/six.oldstyle
-/seven.oldstyle
-/eight.oldstyle
-/nine.oldstyle
-/colon
-/semicolon
-/less
-/equal
-/greater
-/question
-/at
-/A
-/B
-/C
-/D
-/E
-/F
-/G
-/H
-/I
-/J
-/K
-/L
-/M
-/N
-/O
-/P
-/Q
-/R
-/S
-/T
-/U
-/V
-/W
-/X
-/Y
-/Z
-/bracketleft
-/backslash
-/bracketright
-/asciicircum
-/underscore
-/quoteleft
-/a
-/b
-/c
-/d
-/e
-/f
-/g
-/h
-/i
-/j
-/k
-/l
-/m
-/n
-/o
-/p
-/q
-/r
-/s
-/t
-/u
-/v
-/w
-/x
-/y
-/z
-/braceleft
-/bar
-/braceright
-/asciitilde
-/sfthyphen
-/Agrave
-/Aacute
-/Atilde
-/Ahookabove
-/Adotbelow
-/Acircumflex
-/Acircumflexgrave
-/Acircumflexacute
-/Acircumflextilde
-/Acircumflexhookabove
-/Acircumflexdotbelow
-/Abreve
-/Abrevegrave
-/Abreveacute
-/Abrevetilde
-/Abrevehookabove
-/Abrevedotbelow
-/Egrave
-/Eacute
-/Etilde
-/Ehookabove
-/Edotbelow
-/Ecircumflex
-/Ecircumflexgrave
-/Ecircumflexacute
-/Ecircumflextilde
-/Ecircumflexhookabove
-/Ecircumflexdotbelow
-/Igrave
-/Iacute
-/Itilde
-/Ihookabove
-/agrave
-/aacute
-/atilde
-/ahookabove
-/adotbelow
-/acircumflex
-/acircumflexgrave
-/acircumflexacute
-/acircumflextilde
-/acircumflexhookabove
-/acircumflexdotbelow
-/abreve
-/abrevegrave
-/abreveacute
-/abrevetilde
-/abrevehookabove
-/abrevedotbelow
-/egrave
-/eacute
-/etilde
-/ehookabove
-/edotbelow
-/ecircumflex
-/ecircumflexgrave
-/ecircumflexacute
-/ecircumflextilde
-/ecircumflexhookabove
-/ecircumflexdotbelow
-/igrave
-/iacute
-/itilde
-/ihookabove
-/Idotbelow
-/Ograve
-/Oacute
-/Otilde
-/Ohookabove
-/Odotbelow
-/Ocircumflex
-/Ocircumflexgrave
-/Ocircumflexacute
-/Ocircumflextilde
-/Ocircumflexhookabove
-/Ocircumflexdotbelow
-/Ohorn
-/Ohorngrave
-/Ohornacute
-/Ohorntilde
-/Ohornhookabove
-/Ohorndotbelow
-/Ugrave
-/Uacute
-/Utilde
-/Uhookabove
-/Udotbelow
-/Uhorn
-/Uhorngrave
-/Uhornacute
-/Uhorntilde
-/Uhornhookabove
-/Uhorndotbelow
-/Ygrave
-/Yacute
-/Ytilde
-/idotbelow
-/ograve
-/oacute
-/otilde
-/ohookabove
-/odotbelow
-/ocircumflex
-/ocircumflexgrave
-/ocircumflexacute
-/ocircumflextilde
-/ocircumflexhookabove
-/ocircumflexdotbelow
-/ohorn
-/ohorngrave
-/ohornacute
-/ohorntilde
-/ohornhookabove
-/ohorndotbelow
-/ugrave
-/uacute
-/utilde
-/uhookabove
-/udotbelow
-/uhorn
-/uhorngrave
-/uhornacute
-/uhorntilde
-/uhornhookabove
-/uhorndotbelow
-/ygrave
-/yacute
-/ytilde
-] def
diff --git a/fonts/enc/dvips/context/lm-texnansi-os.enc b/fonts/enc/dvips/context/q-8r.enc
index 059dd788b..be8b32613 100644
--- a/fonts/enc/dvips/context/lm-texnansi-os.enc
+++ b/fonts/enc/dvips/context/q-8r.enc
@@ -1,36 +1,42 @@
-/enclmtexnansi[
+% This file could belong to the TeX Gyre collection of fonts,
+% but is only needed and thus distributed with ConTeXt macro package.
+%
+% It provides 8r encoding compatible with TeX Gyre fonts and is used to enable
+% substituting Adobe fonts by TeX Gyre in pxfonts & txfonts.
+%
+/encq8r [
/.notdef
-/Euro
-/.notdef
-/.notdef
-/fraction
/dotaccent
+/fi
+/fl
+/fraction
/hungarumlaut
+/Lslash
+/lslash
/ogonek
-/fl
+/ring
/.notdef
-/cwm
-/ff
-/fi
+/breve
+/minus
/.notdef
-/ffi
-/ffl
+/Zcaron
+/zcaron
+/caron
/dotlessi
/dotlessj
+/ff
+/ffi
+/ffl
+/notequal
+/infinity
+/lessequal
+/greaterequal
+/partialdiff
+/summation
+/product
+/pi
/grave
-/acute
-/caron
-/breve
-/macron
-/ring
-/cedilla
-/germandbls
-/ae
-/oe
-/oslash
-/AE
-/OE
-/Oslash
+/quotesingle
/space
/exclam
/quotedbl
@@ -47,16 +53,16 @@
/hyphen
/period
/slash
-/zero.oldstyle
-/one.oldstyle
-/two.oldstyle
-/three.oldstyle
-/four.oldstyle
-/five.oldstyle
-/six.oldstyle
-/seven.oldstyle
-/eight.oldstyle
-/nine.oldstyle
+/zero
+/one
+/two
+/three
+/four
+/five
+/six
+/seven
+/eight
+/nine
/colon
/semicolon
/less
@@ -93,7 +99,7 @@
/bracketleft
/backslash
/bracketright
-/circumflex
+/asciicircum
/underscore
/quoteleft
/a
@@ -125,41 +131,41 @@
/braceleft
/bar
/braceright
-/tilde
-/dieresis
-/Lslash
-/quotesingle
+/asciitilde
+/.notdef
+/Euro
+/integral
/quotesinglbase
/florin
/quotedblbase
/ellipsis
/dagger
/daggerdbl
-/circumflex.dup
+/circumflex
/perthousand
/Scaron
/guilsinglleft
-/OE.dup
-/Zcaron
-/asciicircum
-/minus
-/lslash
-/quoteleft.dup
-/quoteright.dup
+/OE
+/Omega
+/radical
+/approxequal
+/.notdef
+/.notdef
+/.notdef
/quotedblleft
/quotedblright
/bullet
/endash
/emdash
-/tilde.dup
+/tilde
/trademark
/scaron
/guilsinglright
-/oe.dup
-/zcaron
-/asciitilde
+/oe
+/Delta
+/lozenge
/Ydieresis
-/nbspace
+/.notdef
/exclamdown
/cent
/sterling
@@ -167,24 +173,24 @@
/yen
/brokenbar
/section
-/dieresis.dup
+/dieresis
/copyright
/ordfeminine
/guillemotleft
/logicalnot
-/sfthyphen
+/hyphen
/registered
-/macron.dup
+/macron
/degree
/plusminus
-/twosuperior
-/threesuperior
-/acute.dup
+/two.superior
+/three.superior
+/acute
/mu
/paragraph
/periodcentered
-/cedilla.dup
-/onesuperior
+/cedilla
+/one.superior
/ordmasculine
/guillemotright
/onequarter
@@ -197,7 +203,7 @@
/Atilde
/Adieresis
/Aring
-/AE.dup
+/AE
/Ccedilla
/Egrave
/Eacute
@@ -215,21 +221,21 @@
/Otilde
/Odieresis
/multiply
-/Oslash.dup
+/Oslash
/Ugrave
/Uacute
/Ucircumflex
/Udieresis
/Yacute
/Thorn
-/germandbls.dup
+/germandbls
/agrave
/aacute
/acircumflex
/atilde
/adieresis
/aring
-/ae.dup
+/ae
/ccedilla
/egrave
/eacute
@@ -247,7 +253,7 @@
/otilde
/odieresis
/divide
-/oslash.dup
+/oslash
/ugrave
/uacute
/ucircumflex
diff --git a/fonts/map/dvips/context/contnav.map b/fonts/map/dvips/context/contnav.map
new file mode 100644
index 000000000..942798c57
--- /dev/null
+++ b/fonts/map/dvips/context/contnav.map
@@ -0,0 +1 @@
+contnav ContextNavigation <contnav.pfb
diff --git a/fonts/map/dvips/jmn/hans.map b/fonts/map/dvips/jmn/hans.map
new file mode 100644
index 000000000..8d283c0f6
--- /dev/null
+++ b/fonts/map/dvips/jmn/hans.map
@@ -0,0 +1,2 @@
+hans Hans-Regular "enchans ReEncodeFont" <hans.enc <hans.pfb
+hans-sh Hans-sh-Regular "enchans ReEncodeFont" <hans.enc <hans-sh.pfb
diff --git a/fonts/map/pdftex/context/cs-qbk.map b/fonts/map/pdftex/context/cs-qbk.map
deleted file mode 100644
index 93acb1250..000000000
--- a/fonts/map/pdftex/context/cs-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-cs-qbkr TeXGyreBonum-Regular "encqcs ReEncodeFont" <q-cs.enc <qbkr.pfb
-cs-qbkri TeXGyreBonum-Italic "encqcs ReEncodeFont" <q-cs.enc <qbkri.pfb
-cs-qbkb TeXGyreBonum-Bold "encqcs ReEncodeFont" <q-cs.enc <qbkb.pfb
-cs-qbkbi TeXGyreBonum-BoldItalic "encqcs ReEncodeFont" <q-cs.enc <qbkbi.pfb
-cs-qbkr-sc TeXGyreBonum-Regular "encqcssc ReEncodeFont" <q-cs-sc.enc <qbkr.pfb
-cs-qbkri-sc TeXGyreBonum-Italic "encqcssc ReEncodeFont" <q-cs-sc.enc <qbkri.pfb
-cs-qbkb-sc TeXGyreBonum-Bold "encqcssc ReEncodeFont" <q-cs-sc.enc <qbkb.pfb
-cs-qbkbi-sc TeXGyreBonum-BoldItalic "encqcssc ReEncodeFont" <q-cs-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/cs-qcs.map b/fonts/map/pdftex/context/cs-qcs.map
deleted file mode 100644
index 5433beef3..000000000
--- a/fonts/map/pdftex/context/cs-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-cs-qcsr TeXGyreSchola-Regular "encqcs ReEncodeFont" <q-cs.enc <qcsr.pfb
-cs-qcsri TeXGyreSchola-Italic "encqcs ReEncodeFont" <q-cs.enc <qcsri.pfb
-cs-qcsb TeXGyreSchola-Bold "encqcs ReEncodeFont" <q-cs.enc <qcsb.pfb
-cs-qcsbi TeXGyreSchola-BoldItalic "encqcs ReEncodeFont" <q-cs.enc <qcsbi.pfb
-cs-qcsr-sc TeXGyreSchola-Regular "encqcssc ReEncodeFont" <q-cs-sc.enc <qcsr.pfb
-cs-qcsri-sc TeXGyreSchola-Italic "encqcssc ReEncodeFont" <q-cs-sc.enc <qcsri.pfb
-cs-qcsb-sc TeXGyreSchola-Bold "encqcssc ReEncodeFont" <q-cs-sc.enc <qcsb.pfb
-cs-qcsbi-sc TeXGyreSchola-BoldItalic "encqcssc ReEncodeFont" <q-cs-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/cs-qpl.map b/fonts/map/pdftex/context/cs-qpl.map
deleted file mode 100644
index bdc0bffa6..000000000
--- a/fonts/map/pdftex/context/cs-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-cs-qplr TeXGyrePagella-Regular "encqcs ReEncodeFont" <q-cs.enc <qplr.pfb
-cs-qplri TeXGyrePagella-Italic "encqcs ReEncodeFont" <q-cs.enc <qplri.pfb
-cs-qplb TeXGyrePagella-Bold "encqcs ReEncodeFont" <q-cs.enc <qplb.pfb
-cs-qplbi TeXGyrePagella-BoldItalic "encqcs ReEncodeFont" <q-cs.enc <qplbi.pfb
-cs-qplr-sc TeXGyrePagella-Regular "encqcssc ReEncodeFont" <q-cs-sc.enc <qplr.pfb
-cs-qplri-sc TeXGyrePagella-Italic "encqcssc ReEncodeFont" <q-cs-sc.enc <qplri.pfb
-cs-qplb-sc TeXGyrePagella-Bold "encqcssc ReEncodeFont" <q-cs-sc.enc <qplb.pfb
-cs-qplbi-sc TeXGyrePagella-BoldItalic "encqcssc ReEncodeFont" <q-cs-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/cs-qtm.map b/fonts/map/pdftex/context/cs-qtm.map
deleted file mode 100644
index 7be549dc0..000000000
--- a/fonts/map/pdftex/context/cs-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-cs-qtmr TeXGyreTermes-Regular "encqcs ReEncodeFont" <q-cs.enc <qtmr.pfb
-cs-qtmri TeXGyreTermes-Italic "encqcs ReEncodeFont" <q-cs.enc <qtmri.pfb
-cs-qtmb TeXGyreTermes-Bold "encqcs ReEncodeFont" <q-cs.enc <qtmb.pfb
-cs-qtmbi TeXGyreTermes-BoldItalic "encqcs ReEncodeFont" <q-cs.enc <qtmbi.pfb
-cs-qtmr-sc TeXGyreTermes-Regular "encqcssc ReEncodeFont" <q-cs-sc.enc <qtmr.pfb
-cs-qtmri-sc TeXGyreTermes-Italic "encqcssc ReEncodeFont" <q-cs-sc.enc <qtmri.pfb
-cs-qtmb-sc TeXGyreTermes-Bold "encqcssc ReEncodeFont" <q-cs-sc.enc <qtmb.pfb
-cs-qtmbi-sc TeXGyreTermes-BoldItalic "encqcssc ReEncodeFont" <q-cs-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/ec-public-lm.map b/fonts/map/pdftex/context/ec-public-lm.map
deleted file mode 100644
index 9f21b7107..000000000
--- a/fonts/map/pdftex/context/ec-public-lm.map
+++ /dev/null
@@ -1,3 +0,0 @@
-% Being an early adopter, we used this name for the map file. The first
-% latin modern font sets had *-lm.map which unfortunately was changed to
-% lm-*.map names.
diff --git a/fonts/map/pdftex/context/ec-qbk.map b/fonts/map/pdftex/context/ec-qbk.map
deleted file mode 100644
index efceaae97..000000000
--- a/fonts/map/pdftex/context/ec-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ec-qbkr TeXGyreBonum-Regular "encqec ReEncodeFont" <q-ec.enc <qbkr.pfb
-ec-qbkri TeXGyreBonum-Italic "encqec ReEncodeFont" <q-ec.enc <qbkri.pfb
-ec-qbkb TeXGyreBonum-Bold "encqec ReEncodeFont" <q-ec.enc <qbkb.pfb
-ec-qbkbi TeXGyreBonum-BoldItalic "encqec ReEncodeFont" <q-ec.enc <qbkbi.pfb
-ec-qbkr-sc TeXGyreBonum-Regular "encqecsc ReEncodeFont" <q-ec-sc.enc <qbkr.pfb
-ec-qbkri-sc TeXGyreBonum-Italic "encqecsc ReEncodeFont" <q-ec-sc.enc <qbkri.pfb
-ec-qbkb-sc TeXGyreBonum-Bold "encqecsc ReEncodeFont" <q-ec-sc.enc <qbkb.pfb
-ec-qbkbi-sc TeXGyreBonum-BoldItalic "encqecsc ReEncodeFont" <q-ec-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/ec-qcs.map b/fonts/map/pdftex/context/ec-qcs.map
deleted file mode 100644
index 093ae18f8..000000000
--- a/fonts/map/pdftex/context/ec-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ec-qcsr TeXGyreSchola-Regular "encqec ReEncodeFont" <q-ec.enc <qcsr.pfb
-ec-qcsri TeXGyreSchola-Italic "encqec ReEncodeFont" <q-ec.enc <qcsri.pfb
-ec-qcsb TeXGyreSchola-Bold "encqec ReEncodeFont" <q-ec.enc <qcsb.pfb
-ec-qcsbi TeXGyreSchola-BoldItalic "encqec ReEncodeFont" <q-ec.enc <qcsbi.pfb
-ec-qcsr-sc TeXGyreSchola-Regular "encqecsc ReEncodeFont" <q-ec-sc.enc <qcsr.pfb
-ec-qcsri-sc TeXGyreSchola-Italic "encqecsc ReEncodeFont" <q-ec-sc.enc <qcsri.pfb
-ec-qcsb-sc TeXGyreSchola-Bold "encqecsc ReEncodeFont" <q-ec-sc.enc <qcsb.pfb
-ec-qcsbi-sc TeXGyreSchola-BoldItalic "encqecsc ReEncodeFont" <q-ec-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/ec-qpl.map b/fonts/map/pdftex/context/ec-qpl.map
deleted file mode 100644
index e1bb1f811..000000000
--- a/fonts/map/pdftex/context/ec-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ec-qplr TeXGyrePagella-Regular "encqec ReEncodeFont" <q-ec.enc <qplr.pfb
-ec-qplri TeXGyrePagella-Italic "encqec ReEncodeFont" <q-ec.enc <qplri.pfb
-ec-qplb TeXGyrePagella-Bold "encqec ReEncodeFont" <q-ec.enc <qplb.pfb
-ec-qplbi TeXGyrePagella-BoldItalic "encqec ReEncodeFont" <q-ec.enc <qplbi.pfb
-ec-qplr-sc TeXGyrePagella-Regular "encqecsc ReEncodeFont" <q-ec-sc.enc <qplr.pfb
-ec-qplri-sc TeXGyrePagella-Italic "encqecsc ReEncodeFont" <q-ec-sc.enc <qplri.pfb
-ec-qplb-sc TeXGyrePagella-Bold "encqecsc ReEncodeFont" <q-ec-sc.enc <qplb.pfb
-ec-qplbi-sc TeXGyrePagella-BoldItalic "encqecsc ReEncodeFont" <q-ec-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/ec-qtm.map b/fonts/map/pdftex/context/ec-qtm.map
deleted file mode 100644
index 557219415..000000000
--- a/fonts/map/pdftex/context/ec-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ec-qtmr TeXGyreTermes-Regular "encqec ReEncodeFont" <q-ec.enc <qtmr.pfb
-ec-qtmri TeXGyreTermes-Italic "encqec ReEncodeFont" <q-ec.enc <qtmri.pfb
-ec-qtmb TeXGyreTermes-Bold "encqec ReEncodeFont" <q-ec.enc <qtmb.pfb
-ec-qtmbi TeXGyreTermes-BoldItalic "encqec ReEncodeFont" <q-ec.enc <qtmbi.pfb
-ec-qtmr-sc TeXGyreTermes-Regular "encqecsc ReEncodeFont" <q-ec-sc.enc <qtmr.pfb
-ec-qtmri-sc TeXGyreTermes-Italic "encqecsc ReEncodeFont" <q-ec-sc.enc <qtmri.pfb
-ec-qtmb-sc TeXGyreTermes-Bold "encqecsc ReEncodeFont" <q-ec-sc.enc <qtmb.pfb
-ec-qtmbi-sc TeXGyreTermes-BoldItalic "encqecsc ReEncodeFont" <q-ec-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/el-public-lm.map b/fonts/map/pdftex/context/el-public-lm.map
deleted file mode 100644
index 9f21b7107..000000000
--- a/fonts/map/pdftex/context/el-public-lm.map
+++ /dev/null
@@ -1,3 +0,0 @@
-% Being an early adopter, we used this name for the map file. The first
-% latin modern font sets had *-lm.map which unfortunately was changed to
-% lm-*.map names.
diff --git a/fonts/map/pdftex/context/el-qbk.map b/fonts/map/pdftex/context/el-qbk.map
deleted file mode 100644
index 65fea636b..000000000
--- a/fonts/map/pdftex/context/el-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-el-qbkr TeXGyreBonum-Regular "encqel ReEncodeFont" <q-el.enc <qbkr.pfb
-el-qbkri TeXGyreBonum-Italic "encqel ReEncodeFont" <q-el.enc <qbkri.pfb
-el-qbkb TeXGyreBonum-Bold "encqel ReEncodeFont" <q-el.enc <qbkb.pfb
-el-qbkbi TeXGyreBonum-BoldItalic "encqel ReEncodeFont" <q-el.enc <qbkbi.pfb
-el-qbkr-sc TeXGyreBonum-Regular "encqelsc ReEncodeFont" <q-el-sc.enc <qbkr.pfb
-el-qbkri-sc TeXGyreBonum-Italic "encqelsc ReEncodeFont" <q-el-sc.enc <qbkri.pfb
-el-qbkb-sc TeXGyreBonum-Bold "encqelsc ReEncodeFont" <q-el-sc.enc <qbkb.pfb
-el-qbkbi-sc TeXGyreBonum-BoldItalic "encqelsc ReEncodeFont" <q-el-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/el-qcs.map b/fonts/map/pdftex/context/el-qcs.map
deleted file mode 100644
index d6ed26bb9..000000000
--- a/fonts/map/pdftex/context/el-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-el-qcsr TeXGyreSchola-Regular "encqel ReEncodeFont" <q-el.enc <qcsr.pfb
-el-qcsri TeXGyreSchola-Italic "encqel ReEncodeFont" <q-el.enc <qcsri.pfb
-el-qcsb TeXGyreSchola-Bold "encqel ReEncodeFont" <q-el.enc <qcsb.pfb
-el-qcsbi TeXGyreSchola-BoldItalic "encqel ReEncodeFont" <q-el.enc <qcsbi.pfb
-el-qcsr-sc TeXGyreSchola-Regular "encqelsc ReEncodeFont" <q-el-sc.enc <qcsr.pfb
-el-qcsri-sc TeXGyreSchola-Italic "encqelsc ReEncodeFont" <q-el-sc.enc <qcsri.pfb
-el-qcsb-sc TeXGyreSchola-Bold "encqelsc ReEncodeFont" <q-el-sc.enc <qcsb.pfb
-el-qcsbi-sc TeXGyreSchola-BoldItalic "encqelsc ReEncodeFont" <q-el-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/el-qpl.map b/fonts/map/pdftex/context/el-qpl.map
deleted file mode 100644
index 7b42cc756..000000000
--- a/fonts/map/pdftex/context/el-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-el-qplr TeXGyrePagella-Regular "encqel ReEncodeFont" <q-el.enc <qplr.pfb
-el-qplri TeXGyrePagella-Italic "encqel ReEncodeFont" <q-el.enc <qplri.pfb
-el-qplb TeXGyrePagella-Bold "encqel ReEncodeFont" <q-el.enc <qplb.pfb
-el-qplbi TeXGyrePagella-BoldItalic "encqel ReEncodeFont" <q-el.enc <qplbi.pfb
-el-qplr-sc TeXGyrePagella-Regular "encqelsc ReEncodeFont" <q-el-sc.enc <qplr.pfb
-el-qplri-sc TeXGyrePagella-Italic "encqelsc ReEncodeFont" <q-el-sc.enc <qplri.pfb
-el-qplb-sc TeXGyrePagella-Bold "encqelsc ReEncodeFont" <q-el-sc.enc <qplb.pfb
-el-qplbi-sc TeXGyrePagella-BoldItalic "encqelsc ReEncodeFont" <q-el-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/el-qtm.map b/fonts/map/pdftex/context/el-qtm.map
deleted file mode 100644
index 2c5d5bef8..000000000
--- a/fonts/map/pdftex/context/el-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-el-qtmr TeXGyreTermes-Regular "encqel ReEncodeFont" <q-el.enc <qtmr.pfb
-el-qtmri TeXGyreTermes-Italic "encqel ReEncodeFont" <q-el.enc <qtmri.pfb
-el-qtmb TeXGyreTermes-Bold "encqel ReEncodeFont" <q-el.enc <qtmb.pfb
-el-qtmbi TeXGyreTermes-BoldItalic "encqel ReEncodeFont" <q-el.enc <qtmbi.pfb
-el-qtmr-sc TeXGyreTermes-Regular "encqelsc ReEncodeFont" <q-el-sc.enc <qtmr.pfb
-el-qtmri-sc TeXGyreTermes-Italic "encqelsc ReEncodeFont" <q-el-sc.enc <qtmri.pfb
-el-qtmb-sc TeXGyreTermes-Bold "encqelsc ReEncodeFont" <q-el-sc.enc <qtmb.pfb
-el-qtmbi-sc TeXGyreTermes-BoldItalic "encqelsc ReEncodeFont" <q-el-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/l7x-qbk.map b/fonts/map/pdftex/context/l7x-qbk.map
deleted file mode 100644
index b4be9e526..000000000
--- a/fonts/map/pdftex/context/l7x-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-l7x-qbkr TeXGyreBonum-Regular "encql7x ReEncodeFont" <q-l7x.enc <qbkr.pfb
-l7x-qbkri TeXGyreBonum-Italic "encql7x ReEncodeFont" <q-l7x.enc <qbkri.pfb
-l7x-qbkb TeXGyreBonum-Bold "encql7x ReEncodeFont" <q-l7x.enc <qbkb.pfb
-l7x-qbkbi TeXGyreBonum-BoldItalic "encql7x ReEncodeFont" <q-l7x.enc <qbkbi.pfb
-l7x-qbkr-sc TeXGyreBonum-Regular "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qbkr.pfb
-l7x-qbkri-sc TeXGyreBonum-Italic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qbkri.pfb
-l7x-qbkb-sc TeXGyreBonum-Bold "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qbkb.pfb
-l7x-qbkbi-sc TeXGyreBonum-BoldItalic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/l7x-qcs.map b/fonts/map/pdftex/context/l7x-qcs.map
deleted file mode 100644
index 0cd1af27c..000000000
--- a/fonts/map/pdftex/context/l7x-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-l7x-qcsr TeXGyreSchola-Regular "encql7x ReEncodeFont" <q-l7x.enc <qcsr.pfb
-l7x-qcsri TeXGyreSchola-Italic "encql7x ReEncodeFont" <q-l7x.enc <qcsri.pfb
-l7x-qcsb TeXGyreSchola-Bold "encql7x ReEncodeFont" <q-l7x.enc <qcsb.pfb
-l7x-qcsbi TeXGyreSchola-BoldItalic "encql7x ReEncodeFont" <q-l7x.enc <qcsbi.pfb
-l7x-qcsr-sc TeXGyreSchola-Regular "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qcsr.pfb
-l7x-qcsri-sc TeXGyreSchola-Italic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qcsri.pfb
-l7x-qcsb-sc TeXGyreSchola-Bold "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qcsb.pfb
-l7x-qcsbi-sc TeXGyreSchola-BoldItalic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/l7x-qpl.map b/fonts/map/pdftex/context/l7x-qpl.map
deleted file mode 100644
index 95c69ffc5..000000000
--- a/fonts/map/pdftex/context/l7x-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-l7x-qplr TeXGyrePagella-Regular "encql7x ReEncodeFont" <q-l7x.enc <qplr.pfb
-l7x-qplri TeXGyrePagella-Italic "encql7x ReEncodeFont" <q-l7x.enc <qplri.pfb
-l7x-qplb TeXGyrePagella-Bold "encql7x ReEncodeFont" <q-l7x.enc <qplb.pfb
-l7x-qplbi TeXGyrePagella-BoldItalic "encql7x ReEncodeFont" <q-l7x.enc <qplbi.pfb
-l7x-qplr-sc TeXGyrePagella-Regular "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qplr.pfb
-l7x-qplri-sc TeXGyrePagella-Italic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qplri.pfb
-l7x-qplb-sc TeXGyrePagella-Bold "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qplb.pfb
-l7x-qplbi-sc TeXGyrePagella-BoldItalic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/l7x-qtm.map b/fonts/map/pdftex/context/l7x-qtm.map
deleted file mode 100644
index 9b05886e6..000000000
--- a/fonts/map/pdftex/context/l7x-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-l7x-qtmr TeXGyreTermes-Regular "encql7x ReEncodeFont" <q-l7x.enc <qtmr.pfb
-l7x-qtmri TeXGyreTermes-Italic "encql7x ReEncodeFont" <q-l7x.enc <qtmri.pfb
-l7x-qtmb TeXGyreTermes-Bold "encql7x ReEncodeFont" <q-l7x.enc <qtmb.pfb
-l7x-qtmbi TeXGyreTermes-BoldItalic "encql7x ReEncodeFont" <q-l7x.enc <qtmbi.pfb
-l7x-qtmr-sc TeXGyreTermes-Regular "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qtmr.pfb
-l7x-qtmri-sc TeXGyreTermes-Italic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qtmri.pfb
-l7x-qtmb-sc TeXGyreTermes-Bold "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qtmb.pfb
-l7x-qtmbi-sc TeXGyreTermes-BoldItalic "encql7xsc ReEncodeFont" <q-l7x-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/original-youngryu-px.map b/fonts/map/pdftex/context/original-youngryu-px.map
index 87c1f48cf..6a27e357d 100644
--- a/fonts/map/pdftex/context/original-youngryu-px.map
+++ b/fonts/map/pdftex/context/original-youngryu-px.map
@@ -1,16 +1,17 @@
% This file a (slightly adapted) copy of the map file
% that comes with the PX fonts by Young Ryu.
-% tx8r.enc replaced by 8r.enc
+% URW fonts replaced by TeX Gyre
-% URW Palatino
+% TeX Gyre Pagella (Palatino)
-rpxpplb URWPalladioL-Bold <8r.enc <uplb8a.pfb
-rpxpplbo URWPalladioL-Bold ".167 SlantFont" <8r.enc <uplb8a.pfb
-rpxpplbi URWPalladioL-BoldItal <8r.enc <uplbi8a.pfb
-rpxpplr URWPalladioL-Roma <8r.enc <uplr8a.pfb
-rpxpplro URWPalladioL-Roma ".167 SlantFont" <8r.enc <uplr8a.pfb
-rpxpplri URWPalladioL-Ital <8r.enc <uplri8a.pfb
+rpxpplr TeXGyrePagella-Regular "encq8r ReEncodeFont" <q-8r.enc <qplr.pfb
+rpxpplb TeXGyrePagella-Bold "encq8r ReEncodeFont" <q-8r.enc <qplb.pfb
+rpxpplri TeXGyrePagella-Italic "encq8r ReEncodeFont" <q-8r.enc <qplri.pfb
+rpxpplbi TeXGyrePagella-BoldItalic "encq8r ReEncodeFont" <q-8r.enc <qplbi.pfb
+% no idea why these were added
+rpxpplro TeXGyrePagella-Oblique ".167 SlantFont encq8r ReEncodeFont" <q-8r.enc <qplr.pfb
+rpxpplbo TeXGyrePagella-BoldOblique ".167 SlantFont encq8r ReEncodeFont" <q-8r.enc <qplb.pfb
% PX Text
diff --git a/fonts/map/pdftex/context/original-youngryu-tx.map b/fonts/map/pdftex/context/original-youngryu-tx.map
index 5618ee8bc..d2600fa78 100644
--- a/fonts/map/pdftex/context/original-youngryu-tx.map
+++ b/fonts/map/pdftex/context/original-youngryu-tx.map
@@ -1,23 +1,28 @@
% This file is a (slightly adapted) copy of the map file
% that comes with the TX fonts by Young Ryu.
-% tx8r.enc replaced by 8r.enc
+% URW fonts replaced by TeX Gyre
-% URW times
+% TeX Gyre Termes (Times)
-rtxptmb NimbusRomNo9L-Medi <8r.enc <utmb8a.pfb
-rtxptmbo NimbusRomNo9L-Medi ".167 SlantFont" <8r.enc <utmb8a.pfb
-rtxptmbi NimbusRomNo9L-MediItal <8r.enc <utmbi8a.pfb
-rtxptmr NimbusRomNo9L-Regu <8r.enc <utmr8a.pfb
-rtxptmro NimbusRomNo9L-Regu ".167 SlantFont" <8r.enc <utmr8a.pfb
-rtxptmri NimbusRomNo9L-ReguItal <8r.enc <utmri8a.pfb
+rtxptmr TeXGyreTermes-Regular "encq8r ReEncodeFont" <q-8r.enc <qtmr.pfb
+rtxptmb TeXGyreTermes-Bold "encq8r ReEncodeFont" <q-8r.enc <qtmb.pfb
+rtxptmri TeXGyreTermes-Italic "encq8r ReEncodeFont" <q-8r.enc <qtmri.pfb
+rtxptmbi TeXGyreTermes-BoldItalic "encq8r ReEncodeFont" <q-8r.enc <qtmbi.pfb
+% no idea why these were added
+rtxptmro TeXGyreTermes-Oblique ".167 SlantFont encq8r ReEncodeFont" <q-8r.enc <qtmr.pfb
+rtxptmbo TeXGyreTermes-BoldOblique ".167 SlantFont encq8r ReEncodeFont" <q-8r.enc <qtmb.pfb
-% URW Helvetica
+% TeX Gyre Heros (Helvetica)
-rtxphvr NimbusSanL-Regu <8r.enc <uhv8a.pfb
-rtxphvro NimbusSanL-Regu ".167 SlantFont" <8r.enc <uhv8a.pfb
-rtxphvb NimbusSanL-Bold <8r.enc <uhvb8a.pfb
-rtxphvbo NimbusSanL-Bold ".167 SlantFont" <8r.enc <uhvb8a.pfb
+rtxphvr TeXGyreHeros-Regular "encqrm ReEncodeFont" <q-rm.enc <qtmr.pfb
+rtxphvb TeXGyreHeros-Bold "encqrm ReEncodeFont" <q-rm.enc <qtmb.pfb
+% probably not used by txfonts
+% rtxphvri TeXGyreHeros-Italic "encqrm ReEncodeFont" <q-rm.enc <qtmri.pfb
+% rtxphvbi TeXGyreHeros-BoldItalic "encqrm ReEncodeFont" <q-rm.enc <qtmbi.pfb
+% followed original definitions; one could also use the italic version
+rtxphvro TeXGyreHeros-Oblique ".167 SlantFont encqrm ReEncodeFont" <q-rm.enc <qtmr.pfb
+rtxphvbo TeXGyreHeros-BoldOblique ".167 SlantFont encqrm ReEncodeFont" <q-rm.enc <qtmb.pfb
% TX Text
diff --git a/fonts/map/pdftex/context/qx-public-lm.map b/fonts/map/pdftex/context/qx-public-lm.map
deleted file mode 100644
index 9f21b7107..000000000
--- a/fonts/map/pdftex/context/qx-public-lm.map
+++ /dev/null
@@ -1,3 +0,0 @@
-% Being an early adopter, we used this name for the map file. The first
-% latin modern font sets had *-lm.map which unfortunately was changed to
-% lm-*.map names.
diff --git a/fonts/map/pdftex/context/qx-qbk.map b/fonts/map/pdftex/context/qx-qbk.map
deleted file mode 100644
index f49992dbf..000000000
--- a/fonts/map/pdftex/context/qx-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-qx-qbkr TeXGyreBonum-Regular "encqqx ReEncodeFont" <q-qx.enc <qbkr.pfb
-qx-qbkri TeXGyreBonum-Italic "encqqx ReEncodeFont" <q-qx.enc <qbkri.pfb
-qx-qbkb TeXGyreBonum-Bold "encqqx ReEncodeFont" <q-qx.enc <qbkb.pfb
-qx-qbkbi TeXGyreBonum-BoldItalic "encqqx ReEncodeFont" <q-qx.enc <qbkbi.pfb
-qx-qbkr-sc TeXGyreBonum-Regular "encqqxsc ReEncodeFont" <q-qx-sc.enc <qbkr.pfb
-qx-qbkri-sc TeXGyreBonum-Italic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qbkri.pfb
-qx-qbkb-sc TeXGyreBonum-Bold "encqqxsc ReEncodeFont" <q-qx-sc.enc <qbkb.pfb
-qx-qbkbi-sc TeXGyreBonum-BoldItalic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/qx-qcs.map b/fonts/map/pdftex/context/qx-qcs.map
deleted file mode 100644
index e3ced4e76..000000000
--- a/fonts/map/pdftex/context/qx-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-qx-qcsr TeXGyreSchola-Regular "encqqx ReEncodeFont" <q-qx.enc <qcsr.pfb
-qx-qcsri TeXGyreSchola-Italic "encqqx ReEncodeFont" <q-qx.enc <qcsri.pfb
-qx-qcsb TeXGyreSchola-Bold "encqqx ReEncodeFont" <q-qx.enc <qcsb.pfb
-qx-qcsbi TeXGyreSchola-BoldItalic "encqqx ReEncodeFont" <q-qx.enc <qcsbi.pfb
-qx-qcsr-sc TeXGyreSchola-Regular "encqqxsc ReEncodeFont" <q-qx-sc.enc <qcsr.pfb
-qx-qcsri-sc TeXGyreSchola-Italic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qcsri.pfb
-qx-qcsb-sc TeXGyreSchola-Bold "encqqxsc ReEncodeFont" <q-qx-sc.enc <qcsb.pfb
-qx-qcsbi-sc TeXGyreSchola-BoldItalic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/qx-qpl.map b/fonts/map/pdftex/context/qx-qpl.map
deleted file mode 100644
index f276cfd04..000000000
--- a/fonts/map/pdftex/context/qx-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-qx-qplr TeXGyrePagella-Regular "encqqx ReEncodeFont" <q-qx.enc <qplr.pfb
-qx-qplri TeXGyrePagella-Italic "encqqx ReEncodeFont" <q-qx.enc <qplri.pfb
-qx-qplb TeXGyrePagella-Bold "encqqx ReEncodeFont" <q-qx.enc <qplb.pfb
-qx-qplbi TeXGyrePagella-BoldItalic "encqqx ReEncodeFont" <q-qx.enc <qplbi.pfb
-qx-qplr-sc TeXGyrePagella-Regular "encqqxsc ReEncodeFont" <q-qx-sc.enc <qplr.pfb
-qx-qplri-sc TeXGyrePagella-Italic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qplri.pfb
-qx-qplb-sc TeXGyrePagella-Bold "encqqxsc ReEncodeFont" <q-qx-sc.enc <qplb.pfb
-qx-qplbi-sc TeXGyrePagella-BoldItalic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/qx-qtm.map b/fonts/map/pdftex/context/qx-qtm.map
deleted file mode 100644
index 1ffd29aad..000000000
--- a/fonts/map/pdftex/context/qx-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-qx-qtmr TeXGyreTermes-Regular "encqqx ReEncodeFont" <q-qx.enc <qtmr.pfb
-qx-qtmri TeXGyreTermes-Italic "encqqx ReEncodeFont" <q-qx.enc <qtmri.pfb
-qx-qtmb TeXGyreTermes-Bold "encqqx ReEncodeFont" <q-qx.enc <qtmb.pfb
-qx-qtmbi TeXGyreTermes-BoldItalic "encqqx ReEncodeFont" <q-qx.enc <qtmbi.pfb
-qx-qtmr-sc TeXGyreTermes-Regular "encqqxsc ReEncodeFont" <q-qx-sc.enc <qtmr.pfb
-qx-qtmri-sc TeXGyreTermes-Italic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qtmri.pfb
-qx-qtmb-sc TeXGyreTermes-Bold "encqqxsc ReEncodeFont" <q-qx-sc.enc <qtmb.pfb
-qx-qtmbi-sc TeXGyreTermes-BoldItalic "encqqxsc ReEncodeFont" <q-qx-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/rm-qbk.map b/fonts/map/pdftex/context/rm-qbk.map
deleted file mode 100644
index c889b8cdb..000000000
--- a/fonts/map/pdftex/context/rm-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-rm-qbkr TeXGyreBonum-Regular "encqrm ReEncodeFont" <q-rm.enc <qbkr.pfb
-rm-qbkri TeXGyreBonum-Italic "encqrm ReEncodeFont" <q-rm.enc <qbkri.pfb
-rm-qbkb TeXGyreBonum-Bold "encqrm ReEncodeFont" <q-rm.enc <qbkb.pfb
-rm-qbkbi TeXGyreBonum-BoldItalic "encqrm ReEncodeFont" <q-rm.enc <qbkbi.pfb
-rm-qbkr-sc TeXGyreBonum-Regular "encqrmsc ReEncodeFont" <q-rm-sc.enc <qbkr.pfb
-rm-qbkri-sc TeXGyreBonum-Italic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qbkri.pfb
-rm-qbkb-sc TeXGyreBonum-Bold "encqrmsc ReEncodeFont" <q-rm-sc.enc <qbkb.pfb
-rm-qbkbi-sc TeXGyreBonum-BoldItalic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/rm-qcs.map b/fonts/map/pdftex/context/rm-qcs.map
deleted file mode 100644
index df7d4539f..000000000
--- a/fonts/map/pdftex/context/rm-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-rm-qcsr TeXGyreSchola-Regular "encqrm ReEncodeFont" <q-rm.enc <qcsr.pfb
-rm-qcsri TeXGyreSchola-Italic "encqrm ReEncodeFont" <q-rm.enc <qcsri.pfb
-rm-qcsb TeXGyreSchola-Bold "encqrm ReEncodeFont" <q-rm.enc <qcsb.pfb
-rm-qcsbi TeXGyreSchola-BoldItalic "encqrm ReEncodeFont" <q-rm.enc <qcsbi.pfb
-rm-qcsr-sc TeXGyreSchola-Regular "encqrmsc ReEncodeFont" <q-rm-sc.enc <qcsr.pfb
-rm-qcsri-sc TeXGyreSchola-Italic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qcsri.pfb
-rm-qcsb-sc TeXGyreSchola-Bold "encqrmsc ReEncodeFont" <q-rm-sc.enc <qcsb.pfb
-rm-qcsbi-sc TeXGyreSchola-BoldItalic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/rm-qpl.map b/fonts/map/pdftex/context/rm-qpl.map
deleted file mode 100644
index 487876951..000000000
--- a/fonts/map/pdftex/context/rm-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-rm-qplr TeXGyrePagella-Regular "encqrm ReEncodeFont" <q-rm.enc <qplr.pfb
-rm-qplri TeXGyrePagella-Italic "encqrm ReEncodeFont" <q-rm.enc <qplri.pfb
-rm-qplb TeXGyrePagella-Bold "encqrm ReEncodeFont" <q-rm.enc <qplb.pfb
-rm-qplbi TeXGyrePagella-BoldItalic "encqrm ReEncodeFont" <q-rm.enc <qplbi.pfb
-rm-qplr-sc TeXGyrePagella-Regular "encqrmsc ReEncodeFont" <q-rm-sc.enc <qplr.pfb
-rm-qplri-sc TeXGyrePagella-Italic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qplri.pfb
-rm-qplb-sc TeXGyrePagella-Bold "encqrmsc ReEncodeFont" <q-rm-sc.enc <qplb.pfb
-rm-qplbi-sc TeXGyrePagella-BoldItalic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/rm-qtm.map b/fonts/map/pdftex/context/rm-qtm.map
deleted file mode 100644
index 89c7734c0..000000000
--- a/fonts/map/pdftex/context/rm-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-rm-qtmr TeXGyreTermes-Regular "encqrm ReEncodeFont" <q-rm.enc <qtmr.pfb
-rm-qtmri TeXGyreTermes-Italic "encqrm ReEncodeFont" <q-rm.enc <qtmri.pfb
-rm-qtmb TeXGyreTermes-Bold "encqrm ReEncodeFont" <q-rm.enc <qtmb.pfb
-rm-qtmbi TeXGyreTermes-BoldItalic "encqrm ReEncodeFont" <q-rm.enc <qtmbi.pfb
-rm-qtmr-sc TeXGyreTermes-Regular "encqrmsc ReEncodeFont" <q-rm-sc.enc <qtmr.pfb
-rm-qtmri-sc TeXGyreTermes-Italic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qtmri.pfb
-rm-qtmb-sc TeXGyreTermes-Bold "encqrmsc ReEncodeFont" <q-rm-sc.enc <qtmb.pfb
-rm-qtmbi-sc TeXGyreTermes-BoldItalic "encqrmsc ReEncodeFont" <q-rm-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/t2a-qbk.map b/fonts/map/pdftex/context/t2a-qbk.map
deleted file mode 100644
index bbf662c78..000000000
--- a/fonts/map/pdftex/context/t2a-qbk.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2a-qbkr TeXGyreBonum-Regular "encqt2a ReEncodeFont" <q-t2a.enc <qbkr.pfb
-t2a-qbkri TeXGyreBonum-Italic "encqt2a ReEncodeFont" <q-t2a.enc <qbkri.pfb
-t2a-qbkb TeXGyreBonum-Bold "encqt2a ReEncodeFont" <q-t2a.enc <qbkb.pfb
-t2a-qbkbi TeXGyreBonum-BoldItalic "encqt2a ReEncodeFont" <q-t2a.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/t2a-qcs.map b/fonts/map/pdftex/context/t2a-qcs.map
deleted file mode 100644
index 6f8d1c944..000000000
--- a/fonts/map/pdftex/context/t2a-qcs.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2a-qcsr TeXGyreSchola-Regular "encqt2a ReEncodeFont" <q-t2a.enc <qcsr.pfb
-t2a-qcsri TeXGyreSchola-Italic "encqt2a ReEncodeFont" <q-t2a.enc <qcsri.pfb
-t2a-qcsb TeXGyreSchola-Bold "encqt2a ReEncodeFont" <q-t2a.enc <qcsb.pfb
-t2a-qcsbi TeXGyreSchola-BoldItalic "encqt2a ReEncodeFont" <q-t2a.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/t2a-qpl.map b/fonts/map/pdftex/context/t2a-qpl.map
deleted file mode 100644
index a963a9027..000000000
--- a/fonts/map/pdftex/context/t2a-qpl.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2a-qplr TeXGyrePagella-Regular "encqt2a ReEncodeFont" <q-t2a.enc <qplr.pfb
-t2a-qplri TeXGyrePagella-Italic "encqt2a ReEncodeFont" <q-t2a.enc <qplri.pfb
-t2a-qplb TeXGyrePagella-Bold "encqt2a ReEncodeFont" <q-t2a.enc <qplb.pfb
-t2a-qplbi TeXGyrePagella-BoldItalic "encqt2a ReEncodeFont" <q-t2a.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/t2a-qtm.map b/fonts/map/pdftex/context/t2a-qtm.map
deleted file mode 100644
index 3d433f2ec..000000000
--- a/fonts/map/pdftex/context/t2a-qtm.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2a-qtmr TeXGyreTermes-Regular "encqt2a ReEncodeFont" <q-t2a.enc <qtmr.pfb
-t2a-qtmri TeXGyreTermes-Italic "encqt2a ReEncodeFont" <q-t2a.enc <qtmri.pfb
-t2a-qtmb TeXGyreTermes-Bold "encqt2a ReEncodeFont" <q-t2a.enc <qtmb.pfb
-t2a-qtmbi TeXGyreTermes-BoldItalic "encqt2a ReEncodeFont" <q-t2a.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/t2b-qbk.map b/fonts/map/pdftex/context/t2b-qbk.map
deleted file mode 100644
index 2ddd898b1..000000000
--- a/fonts/map/pdftex/context/t2b-qbk.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2b-qbkr TeXGyreBonum-Regular "encqt2b ReEncodeFont" <q-t2b.enc <qbkr.pfb
-t2b-qbkri TeXGyreBonum-Italic "encqt2b ReEncodeFont" <q-t2b.enc <qbkri.pfb
-t2b-qbkb TeXGyreBonum-Bold "encqt2b ReEncodeFont" <q-t2b.enc <qbkb.pfb
-t2b-qbkbi TeXGyreBonum-BoldItalic "encqt2b ReEncodeFont" <q-t2b.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/t2b-qcs.map b/fonts/map/pdftex/context/t2b-qcs.map
deleted file mode 100644
index 3bf23d11e..000000000
--- a/fonts/map/pdftex/context/t2b-qcs.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2b-qcsr TeXGyreSchola-Regular "encqt2b ReEncodeFont" <q-t2b.enc <qcsr.pfb
-t2b-qcsri TeXGyreSchola-Italic "encqt2b ReEncodeFont" <q-t2b.enc <qcsri.pfb
-t2b-qcsb TeXGyreSchola-Bold "encqt2b ReEncodeFont" <q-t2b.enc <qcsb.pfb
-t2b-qcsbi TeXGyreSchola-BoldItalic "encqt2b ReEncodeFont" <q-t2b.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/t2b-qpl.map b/fonts/map/pdftex/context/t2b-qpl.map
deleted file mode 100644
index efd0760b8..000000000
--- a/fonts/map/pdftex/context/t2b-qpl.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2b-qplr TeXGyrePagella-Regular "encqt2b ReEncodeFont" <q-t2b.enc <qplr.pfb
-t2b-qplri TeXGyrePagella-Italic "encqt2b ReEncodeFont" <q-t2b.enc <qplri.pfb
-t2b-qplb TeXGyrePagella-Bold "encqt2b ReEncodeFont" <q-t2b.enc <qplb.pfb
-t2b-qplbi TeXGyrePagella-BoldItalic "encqt2b ReEncodeFont" <q-t2b.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/t2b-qtm.map b/fonts/map/pdftex/context/t2b-qtm.map
deleted file mode 100644
index a38009c36..000000000
--- a/fonts/map/pdftex/context/t2b-qtm.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2b-qtmr TeXGyreTermes-Regular "encqt2b ReEncodeFont" <q-t2b.enc <qtmr.pfb
-t2b-qtmri TeXGyreTermes-Italic "encqt2b ReEncodeFont" <q-t2b.enc <qtmri.pfb
-t2b-qtmb TeXGyreTermes-Bold "encqt2b ReEncodeFont" <q-t2b.enc <qtmb.pfb
-t2b-qtmbi TeXGyreTermes-BoldItalic "encqt2b ReEncodeFont" <q-t2b.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/t2c-qbk.map b/fonts/map/pdftex/context/t2c-qbk.map
deleted file mode 100644
index 41855359a..000000000
--- a/fonts/map/pdftex/context/t2c-qbk.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2c-qbkr TeXGyreBonum-Regular "encqt2c ReEncodeFont" <q-t2c.enc <qbkr.pfb
-t2c-qbkri TeXGyreBonum-Italic "encqt2c ReEncodeFont" <q-t2c.enc <qbkri.pfb
-t2c-qbkb TeXGyreBonum-Bold "encqt2c ReEncodeFont" <q-t2c.enc <qbkb.pfb
-t2c-qbkbi TeXGyreBonum-BoldItalic "encqt2c ReEncodeFont" <q-t2c.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/t2c-qcs.map b/fonts/map/pdftex/context/t2c-qcs.map
deleted file mode 100644
index 16276d5c6..000000000
--- a/fonts/map/pdftex/context/t2c-qcs.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2c-qcsr TeXGyreSchola-Regular "encqt2c ReEncodeFont" <q-t2c.enc <qcsr.pfb
-t2c-qcsri TeXGyreSchola-Italic "encqt2c ReEncodeFont" <q-t2c.enc <qcsri.pfb
-t2c-qcsb TeXGyreSchola-Bold "encqt2c ReEncodeFont" <q-t2c.enc <qcsb.pfb
-t2c-qcsbi TeXGyreSchola-BoldItalic "encqt2c ReEncodeFont" <q-t2c.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/t2c-qpl.map b/fonts/map/pdftex/context/t2c-qpl.map
deleted file mode 100644
index 8b3647e9c..000000000
--- a/fonts/map/pdftex/context/t2c-qpl.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2c-qplr TeXGyrePagella-Regular "encqt2c ReEncodeFont" <q-t2c.enc <qplr.pfb
-t2c-qplri TeXGyrePagella-Italic "encqt2c ReEncodeFont" <q-t2c.enc <qplri.pfb
-t2c-qplb TeXGyrePagella-Bold "encqt2c ReEncodeFont" <q-t2c.enc <qplb.pfb
-t2c-qplbi TeXGyrePagella-BoldItalic "encqt2c ReEncodeFont" <q-t2c.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/t2c-qtm.map b/fonts/map/pdftex/context/t2c-qtm.map
deleted file mode 100644
index 3755ae476..000000000
--- a/fonts/map/pdftex/context/t2c-qtm.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t2c-qtmr TeXGyreTermes-Regular "encqt2c ReEncodeFont" <q-t2c.enc <qtmr.pfb
-t2c-qtmri TeXGyreTermes-Italic "encqt2c ReEncodeFont" <q-t2c.enc <qtmri.pfb
-t2c-qtmb TeXGyreTermes-Bold "encqt2c ReEncodeFont" <q-t2c.enc <qtmb.pfb
-t2c-qtmbi TeXGyreTermes-BoldItalic "encqt2c ReEncodeFont" <q-t2c.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/t5-public-lm.map b/fonts/map/pdftex/context/t5-public-lm.map
deleted file mode 100644
index 9f21b7107..000000000
--- a/fonts/map/pdftex/context/t5-public-lm.map
+++ /dev/null
@@ -1,3 +0,0 @@
-% Being an early adopter, we used this name for the map file. The first
-% latin modern font sets had *-lm.map which unfortunately was changed to
-% lm-*.map names.
diff --git a/fonts/map/pdftex/context/t5-qbk.map b/fonts/map/pdftex/context/t5-qbk.map
deleted file mode 100644
index 387f8a9f2..000000000
--- a/fonts/map/pdftex/context/t5-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t5-qbkr TeXGyreBonum-Regular "encqt5 ReEncodeFont" <q-t5.enc <qbkr.pfb
-t5-qbkri TeXGyreBonum-Italic "encqt5 ReEncodeFont" <q-t5.enc <qbkri.pfb
-t5-qbkb TeXGyreBonum-Bold "encqt5 ReEncodeFont" <q-t5.enc <qbkb.pfb
-t5-qbkbi TeXGyreBonum-BoldItalic "encqt5 ReEncodeFont" <q-t5.enc <qbkbi.pfb
-t5-qbkr-sc TeXGyreBonum-Regular "encqt5sc ReEncodeFont" <q-t5-sc.enc <qbkr.pfb
-t5-qbkri-sc TeXGyreBonum-Italic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qbkri.pfb
-t5-qbkb-sc TeXGyreBonum-Bold "encqt5sc ReEncodeFont" <q-t5-sc.enc <qbkb.pfb
-t5-qbkbi-sc TeXGyreBonum-BoldItalic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/t5-qcs.map b/fonts/map/pdftex/context/t5-qcs.map
deleted file mode 100644
index da8f5d563..000000000
--- a/fonts/map/pdftex/context/t5-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t5-qcsr TeXGyreSchola-Regular "encqt5 ReEncodeFont" <q-t5.enc <qcsr.pfb
-t5-qcsri TeXGyreSchola-Italic "encqt5 ReEncodeFont" <q-t5.enc <qcsri.pfb
-t5-qcsb TeXGyreSchola-Bold "encqt5 ReEncodeFont" <q-t5.enc <qcsb.pfb
-t5-qcsbi TeXGyreSchola-BoldItalic "encqt5 ReEncodeFont" <q-t5.enc <qcsbi.pfb
-t5-qcsr-sc TeXGyreSchola-Regular "encqt5sc ReEncodeFont" <q-t5-sc.enc <qcsr.pfb
-t5-qcsri-sc TeXGyreSchola-Italic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qcsri.pfb
-t5-qcsb-sc TeXGyreSchola-Bold "encqt5sc ReEncodeFont" <q-t5-sc.enc <qcsb.pfb
-t5-qcsbi-sc TeXGyreSchola-BoldItalic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/t5-qpl.map b/fonts/map/pdftex/context/t5-qpl.map
deleted file mode 100644
index de6fb85cb..000000000
--- a/fonts/map/pdftex/context/t5-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t5-qplr TeXGyrePagella-Regular "encqt5 ReEncodeFont" <q-t5.enc <qplr.pfb
-t5-qplri TeXGyrePagella-Italic "encqt5 ReEncodeFont" <q-t5.enc <qplri.pfb
-t5-qplb TeXGyrePagella-Bold "encqt5 ReEncodeFont" <q-t5.enc <qplb.pfb
-t5-qplbi TeXGyrePagella-BoldItalic "encqt5 ReEncodeFont" <q-t5.enc <qplbi.pfb
-t5-qplr-sc TeXGyrePagella-Regular "encqt5sc ReEncodeFont" <q-t5-sc.enc <qplr.pfb
-t5-qplri-sc TeXGyrePagella-Italic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qplri.pfb
-t5-qplb-sc TeXGyrePagella-Bold "encqt5sc ReEncodeFont" <q-t5-sc.enc <qplb.pfb
-t5-qplbi-sc TeXGyrePagella-BoldItalic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/t5-qtm.map b/fonts/map/pdftex/context/t5-qtm.map
deleted file mode 100644
index 559fc6dcc..000000000
--- a/fonts/map/pdftex/context/t5-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-t5-qtmr TeXGyreTermes-Regular "encqt5 ReEncodeFont" <q-t5.enc <qtmr.pfb
-t5-qtmri TeXGyreTermes-Italic "encqt5 ReEncodeFont" <q-t5.enc <qtmri.pfb
-t5-qtmb TeXGyreTermes-Bold "encqt5 ReEncodeFont" <q-t5.enc <qtmb.pfb
-t5-qtmbi TeXGyreTermes-BoldItalic "encqt5 ReEncodeFont" <q-t5.enc <qtmbi.pfb
-t5-qtmr-sc TeXGyreTermes-Regular "encqt5sc ReEncodeFont" <q-t5-sc.enc <qtmr.pfb
-t5-qtmri-sc TeXGyreTermes-Italic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qtmri.pfb
-t5-qtmb-sc TeXGyreTermes-Bold "encqt5sc ReEncodeFont" <q-t5-sc.enc <qtmb.pfb
-t5-qtmbi-sc TeXGyreTermes-BoldItalic "encqt5sc ReEncodeFont" <q-t5-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/texnansi-public-lm.map b/fonts/map/pdftex/context/texnansi-public-lm.map
deleted file mode 100644
index 9f21b7107..000000000
--- a/fonts/map/pdftex/context/texnansi-public-lm.map
+++ /dev/null
@@ -1,3 +0,0 @@
-% Being an early adopter, we used this name for the map file. The first
-% latin modern font sets had *-lm.map which unfortunately was changed to
-% lm-*.map names.
diff --git a/fonts/map/pdftex/context/texnansi-qbk.map b/fonts/map/pdftex/context/texnansi-qbk.map
deleted file mode 100644
index 6b418d83f..000000000
--- a/fonts/map/pdftex/context/texnansi-qbk.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-texnansi-qbkr TeXGyreBonum-Regular "encqtexnansi ReEncodeFont" <q-texnansi.enc <qbkr.pfb
-texnansi-qbkri TeXGyreBonum-Italic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qbkri.pfb
-texnansi-qbkb TeXGyreBonum-Bold "encqtexnansi ReEncodeFont" <q-texnansi.enc <qbkb.pfb
-texnansi-qbkbi TeXGyreBonum-BoldItalic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qbkbi.pfb
-texnansi-qbkr-sc TeXGyreBonum-Regular "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qbkr.pfb
-texnansi-qbkri-sc TeXGyreBonum-Italic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qbkri.pfb
-texnansi-qbkb-sc TeXGyreBonum-Bold "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qbkb.pfb
-texnansi-qbkbi-sc TeXGyreBonum-BoldItalic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/texnansi-qcs.map b/fonts/map/pdftex/context/texnansi-qcs.map
deleted file mode 100644
index 5394f7a8f..000000000
--- a/fonts/map/pdftex/context/texnansi-qcs.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-texnansi-qcsr TeXGyreSchola-Regular "encqtexnansi ReEncodeFont" <q-texnansi.enc <qcsr.pfb
-texnansi-qcsri TeXGyreSchola-Italic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qcsri.pfb
-texnansi-qcsb TeXGyreSchola-Bold "encqtexnansi ReEncodeFont" <q-texnansi.enc <qcsb.pfb
-texnansi-qcsbi TeXGyreSchola-BoldItalic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qcsbi.pfb
-texnansi-qcsr-sc TeXGyreSchola-Regular "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qcsr.pfb
-texnansi-qcsri-sc TeXGyreSchola-Italic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qcsri.pfb
-texnansi-qcsb-sc TeXGyreSchola-Bold "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qcsb.pfb
-texnansi-qcsbi-sc TeXGyreSchola-BoldItalic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/texnansi-qpl.map b/fonts/map/pdftex/context/texnansi-qpl.map
deleted file mode 100644
index b496a42ee..000000000
--- a/fonts/map/pdftex/context/texnansi-qpl.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-texnansi-qplr TeXGyrePagella-Regular "encqtexnansi ReEncodeFont" <q-texnansi.enc <qplr.pfb
-texnansi-qplri TeXGyrePagella-Italic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qplri.pfb
-texnansi-qplb TeXGyrePagella-Bold "encqtexnansi ReEncodeFont" <q-texnansi.enc <qplb.pfb
-texnansi-qplbi TeXGyrePagella-BoldItalic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qplbi.pfb
-texnansi-qplr-sc TeXGyrePagella-Regular "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qplr.pfb
-texnansi-qplri-sc TeXGyrePagella-Italic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qplri.pfb
-texnansi-qplb-sc TeXGyrePagella-Bold "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qplb.pfb
-texnansi-qplbi-sc TeXGyrePagella-BoldItalic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/texnansi-qtm.map b/fonts/map/pdftex/context/texnansi-qtm.map
deleted file mode 100644
index 373555f3f..000000000
--- a/fonts/map/pdftex/context/texnansi-qtm.map
+++ /dev/null
@@ -1,15 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-texnansi-qtmr TeXGyreTermes-Regular "encqtexnansi ReEncodeFont" <q-texnansi.enc <qtmr.pfb
-texnansi-qtmri TeXGyreTermes-Italic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qtmri.pfb
-texnansi-qtmb TeXGyreTermes-Bold "encqtexnansi ReEncodeFont" <q-texnansi.enc <qtmb.pfb
-texnansi-qtmbi TeXGyreTermes-BoldItalic "encqtexnansi ReEncodeFont" <q-texnansi.enc <qtmbi.pfb
-texnansi-qtmr-sc TeXGyreTermes-Regular "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qtmr.pfb
-texnansi-qtmri-sc TeXGyreTermes-Italic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qtmri.pfb
-texnansi-qtmb-sc TeXGyreTermes-Bold "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qtmb.pfb
-texnansi-qtmbi-sc TeXGyreTermes-BoldItalic "encqtexnansisc ReEncodeFont" <q-texnansi-sc.enc <qtmbi.pfb
diff --git a/fonts/map/pdftex/context/ts1-qbk.map b/fonts/map/pdftex/context/ts1-qbk.map
deleted file mode 100644
index c85e04d00..000000000
--- a/fonts/map/pdftex/context/ts1-qbk.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Bonum.txt
-% and README-TeX-Gyre-Bonum.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ts1-qbkr TeXGyreBonum-Regular "encqts1 ReEncodeFont" <q-ts1.enc <qbkr.pfb
-ts1-qbkri TeXGyreBonum-Italic "encqts1 ReEncodeFont" <q-ts1.enc <qbkri.pfb
-ts1-qbkb TeXGyreBonum-Bold "encqts1 ReEncodeFont" <q-ts1.enc <qbkb.pfb
-ts1-qbkbi TeXGyreBonum-BoldItalic "encqts1 ReEncodeFont" <q-ts1.enc <qbkbi.pfb
diff --git a/fonts/map/pdftex/context/ts1-qcs.map b/fonts/map/pdftex/context/ts1-qcs.map
deleted file mode 100644
index 418eb94e7..000000000
--- a/fonts/map/pdftex/context/ts1-qcs.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Schola.txt
-% and README-TeX-Gyre-Schola.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ts1-qcsr TeXGyreSchola-Regular "encqts1 ReEncodeFont" <q-ts1.enc <qcsr.pfb
-ts1-qcsri TeXGyreSchola-Italic "encqts1 ReEncodeFont" <q-ts1.enc <qcsri.pfb
-ts1-qcsb TeXGyreSchola-Bold "encqts1 ReEncodeFont" <q-ts1.enc <qcsb.pfb
-ts1-qcsbi TeXGyreSchola-BoldItalic "encqts1 ReEncodeFont" <q-ts1.enc <qcsbi.pfb
diff --git a/fonts/map/pdftex/context/ts1-qpl.map b/fonts/map/pdftex/context/ts1-qpl.map
deleted file mode 100644
index e09358b1d..000000000
--- a/fonts/map/pdftex/context/ts1-qpl.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Pagella.txt
-% and README-TeX-Gyre-Pagella.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ts1-qplr TeXGyrePagella-Regular "encqts1 ReEncodeFont" <q-ts1.enc <qplr.pfb
-ts1-qplri TeXGyrePagella-Italic "encqts1 ReEncodeFont" <q-ts1.enc <qplri.pfb
-ts1-qplb TeXGyrePagella-Bold "encqts1 ReEncodeFont" <q-ts1.enc <qplb.pfb
-ts1-qplbi TeXGyrePagella-BoldItalic "encqts1 ReEncodeFont" <q-ts1.enc <qplbi.pfb
diff --git a/fonts/map/pdftex/context/ts1-qtm.map b/fonts/map/pdftex/context/ts1-qtm.map
deleted file mode 100644
index 7118c34fb..000000000
--- a/fonts/map/pdftex/context/ts1-qtm.map
+++ /dev/null
@@ -1,11 +0,0 @@
-% This file belongs to the TeX Gyre collection of fonts. The work is released
-% under the GUST Font License. See the MANIFEST-TeX-Gyre-Termes.txt
-% and README-TeX-Gyre-Termes.txt files for the details.
-% For the most recent version of this license see
-% http://www.gust.org.pl/fonts/licenses/GUST-FONT-LICENSE.txt or
-% http://tug.org/fonts/licenses/GUST-FONT-LICENSE.txt
-%
-ts1-qtmr TeXGyreTermes-Regular "encqts1 ReEncodeFont" <q-ts1.enc <qtmr.pfb
-ts1-qtmri TeXGyreTermes-Italic "encqts1 ReEncodeFont" <q-ts1.enc <qtmri.pfb
-ts1-qtmb TeXGyreTermes-Bold "encqts1 ReEncodeFont" <q-ts1.enc <qtmb.pfb
-ts1-qtmbi TeXGyreTermes-BoldItalic "encqts1 ReEncodeFont" <q-ts1.enc <qtmbi.pfb
diff --git a/metapost/context/base/metafun.mp b/metapost/context/base/metafun.mp
index b828b8b9e..00011c8be 100644
--- a/metapost/context/base/metafun.mp
+++ b/metapost/context/base/metafun.mp
@@ -49,6 +49,8 @@ input mp-figs.mp ;
input mp-mlib.mp ;
+if known context_mlib : input mp-chem.mp ; fi ; % only when mkiv
+
% mp-form.mp ;
input mp-grid.mp ;
input mp-func.mp ;
diff --git a/metapost/context/base/mp-chem.mp b/metapost/context/base/mp-chem.mp
new file mode 100644
index 000000000..1a5be8416
--- /dev/null
+++ b/metapost/context/base/mp-chem.mp
@@ -0,0 +1,729 @@
+%D \module
+%D [ file=mp-chem.mp,
+%D version=2009.05.13,
+%D title=\CONTEXT\ \METAPOST\ graphics,
+%D subtitle=chemicals,
+%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 licen-en.pdf for
+%C details.
+
+%D This module in incomplete and experimental.
+
+% either consistent setting or not
+
+if known chem_reset : endinput ; fi ;
+
+numeric
+ chem_width, chem_radical_min, chem_radical_max, chem_text_max, chem_circle_radius,
+ chem_rotation, chem_adjacent, chem_stack, chem_substituent, chem_direction, chem_setting_scale,
+ chem_setting_offset, chem_text_offset, chem_picture_offset, chem_center_offset, chem_substituent_offset,
+ chem_setting_l, chem_setting_r, chem_setting_t, chem_setting_b ;
+
+boolean
+ chem_setting_axis,
+ chem_setting_fixedwidth, chem_setting_fixedheight,
+ chem_doing_pb, chem_text_trace ;
+
+path
+ chem_setting_bbox ;
+
+pair
+ chem_shift,
+ chem_adjacent_p, chem_substituent_p, chem_direction_p, chem_move_p ;
+
+numeric
+ chem_width[], chem_angle[], chem_start[], chem_initialrot[], chem_initialmov[] ;
+
+pair
+ chem_stack_d[],
+ chem_b_zero[], chem_n_zero[],
+ chem_r_max[], chem_r_min[],
+ chem_r_zero[], chem_mr_zero[], chem_pr_zero[], chem_crz_zero[],
+ chem_rt_zero[], chem_rtt_zero[], chem_rbt_zero[],
+ chem_mid_zero[] ;
+
+path
+ chem_b_path[], chem_bx_path[], chem_eb_path[], chem_sr_path[], chem_br_path[],
+ chem_sb_path[], chem_msb_path[], chem_psb_path[],
+ chem_s_path[], chem_ss_path[], chem_mss_path[], chem_pss_path[],
+ chem_e_path[], chem_sd_path[], chem_bb_path[], chem_oe_path[],
+ chem_ddt_path[], chem_ddb_path[], chem_ldt_path[], chem_ldb_path[], chem_rdt_path[], chem_rdb_path[],
+ chem_dbl_path[], chem_dbr_path[],
+ chem_ad_path[], chem_au_path[],
+ chem_r_path[], chem_rl_path[], chem_rr_path[],
+ chem_rb_path[], chem_prb_path[], chem_mrb_path[],
+ chem_srl_path[], chem_srr_path[],
+ chem_msr_path[], chem_psr_path[],
+ chem_mr_path[], chem_pr_path[],
+ chem_c_path[], chem_cc_path[],
+ chem_midt_path[], chem_midb_path[], chem_midst_path[], chem_midsb_path[] ;
+
+chem_setting_scale := 1 ;
+chem_base_width := 40pt ;
+chem_text_offset := 3pt ;
+chem_center_offset := 6pt ;
+chem_picture_offset := 10pt ;
+chem_substituent_offset := 10pt ;
+chem_radical_min := 1.25 ;
+chem_radical_max := 1.50 ;
+chem_text_min := 0.75 ;
+chem_text_max := 1.75 ;
+chem_circle_radius := 0.80 ;
+chem_rotation := 1 ;
+chem_adjacent := 0 ;
+chem_substituent := 0 ;
+chem_direction := 0 ;
+chem_stack_n := 0 ;
+chem_doing_pb := false ;
+chem_shift := origin ;
+chem_dot_factor := 4 ;
+chem_text_trace := false ;
+
+vardef chem_start_structure(expr n, l, r, t, b, scale, axis, fixedwidth, fixedheight, offset) =
+ chem_setting_axis := axis ;
+ chem_setting_l := l * scale ;
+ chem_setting_r := r * scale ;
+ chem_setting_t := t * scale ;
+ chem_setting_b := b * scale ;
+ chem_setting_fixedwidth := fixedwidth ;
+ chem_setting_fixedheight := fixedheight ;
+ chem_setting_offset := offset ;
+ if scale <> chem_setting_scale :
+ chem_setting_scale := scale ;
+ chem_init_all ;
+ fi ;
+ chem_rotation := 1 ;
+ chem_adjacent := 0 ;
+ chem_substituent := 0 ;
+ chem_direction := 0 ;
+ chem_stack_n := 0 ;
+ chem_doing_pb := false ;
+ chem_shift := origin ;
+enddef ;
+
+def chem_stop_structure =
+ currentpicture := currentpicture shifted - chem_shift ;
+ % axis here
+ if chem_setting_fixedwidth :
+ chem_setting_l := - xpart llcorner currentpicture ;
+ chem_setting_r := xpart urcorner currentpicture ;
+ fi ;
+ if chem_setting_fixedheight :
+ chem_setting_t := ypart urcorner currentpicture ;
+ chem_setting_b := - ypart llcorner currentpicture ;
+ fi ;
+ chem_setting_bbox :=
+ (-chem_setting_l,-chem_setting_b) -- ( chem_setting_r,-chem_setting_b) --
+ ( chem_setting_r, chem_setting_t) -- (-chem_setting_l, chem_setting_t) -- cycle ;
+ % maybe put it behind the picture
+ if chem_setting_axis :
+ save stp ; stp := chem_base_width/ 2 * chem_setting_scale ;
+ save siz ; siz := chem_base_width/10 * chem_setting_scale ;
+ draw (-chem_setting_l,0) -- (chem_setting_r,0) withcolor blue ;
+ draw (0,-chem_setting_b) -- (0,chem_setting_t) withcolor blue ;
+ for i = 0 step stp until chem_setting_r : draw (i,-siz) -- (i,siz) withcolor blue ; endfor ;
+ for i = 0 step -stp until -chem_setting_l : draw (i,-siz) -- (i,siz) withcolor blue ; endfor ;
+ for i = 0 step stp until chem_setting_t : draw (-siz,i) -- (siz,i) withcolor blue ; endfor ;
+ for i = 0 step -stp until -chem_setting_b : draw (-siz,i) -- (siz,i) withcolor blue ; endfor ;
+ draw chem_setting_bbox withcolor blue ;
+ fi ;
+ setbounds currentpicture to chem_setting_bbox ;
+enddef ;
+
+def chem_start_component =
+enddef ;
+def chem_stop_component =
+enddef ;
+
+def chem_pb =
+% draw boundingbox currentpicture withpen pencircle scaled 1mm withcolor blue ;
+% draw origin withpen pencircle scaled 2mm withcolor blue ;
+ chem_doing_pb := true ;
+enddef ;
+def chem_pe =
+% draw boundingbox currentpicture withpen pencircle scaled .5mm withcolor red ;
+% draw origin withpen pencircle scaled 1mm withcolor red ;
+ currentpicture := currentpicture shifted - chem_shift ;
+% draw origin withpen pencircle scaled .5mm withcolor green ;
+ chem_shift := origin ;
+ chem_doing_pb := false ;
+enddef ;
+
+vardef chem_do (expr p) =
+ if chem_doing_pb :
+ chem_doing_pb := false ;
+% save pp ; pair pp ; pp := point 1 of ((origin -- p) enlonged chem_picture_offset) ;
+% currentpicture := currentpicture shifted - pp ;
+% chem_shift := chem_shift - center pp ;
+ currentpicture := currentpicture shifted - p ;
+ chem_shift := chem_shift - p ;
+ origin % nullpicture
+ else :
+ p
+ fi
+enddef ;
+
+vardef chem_b (expr n, f, t, r, c) =
+ chem_draw (n, chem_b_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_sb (expr n, f, t, r, c) =
+ chem_draw (n, chem_sb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_s (expr n, f, t, r, c) =
+ chem_draw (n, chem_s_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_ss (expr n, f, t, r, c) =
+ chem_draw (n, chem_ss_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_mid (expr n, r, c) =
+ chem_draw_fixed (n, chem_midt_path[n], r, c) ;
+ chem_draw_fixed (n, chem_midb_path[n], r, c) ;
+enddef ;
+vardef chem_mids (expr n, r, c) =
+ chem_draw_fixed (n, chem_midst_path[n], r, c) ;
+ chem_draw_fixed (n, chem_midsb_path[n], r, c) ;
+enddef ;
+vardef chem_mss (expr n, f, t, r, c) =
+ chem_draw (n, chem_mss_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_pss (expr n, f, t, r, c) =
+ chem_draw (n, chem_pss_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_msb (expr n, f, t, r, c) =
+ chem_draw (n, chem_msb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_psb (expr n, f, t, r, c) =
+ chem_draw (n, chem_psb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_eb (expr n, f, t, r, c) =
+ chem_draw (n, chem_eb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_db (expr n, f, t, r, c) =
+ if n = 1 :
+ chem_draw (n, chem_msb_path [n], f, t, r, c) ;
+ chem_draw (n, chem_psb_path [n], f, t, r, c) ;
+ else :
+ chem_draw (n, chem_dbl_path [n], f, t, r, c) ;
+ chem_draw (n, chem_dbr_path [n], f, t, r, c) ;
+ fi ;
+enddef ;
+vardef chem_er (expr n, f, t, r, c) =
+ chem_draw (n, chem_rl_path[n], f, t, r, c) ;
+ chem_draw (n, chem_rr_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_dr (expr n, f, t, r, c) =
+ chem_draw (n, chem_srl_path[n], f, t, r, c) ;
+ chem_draw (n, chem_srr_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_ad (expr n, f, t, r, c) =
+ chem_draw_arrow(n, chem_ad_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_au (expr n, f, t, r, c) =
+ chem_draw_arrow(n, chem_au_path[n], f, t, r, c)
+enddef ;
+vardef chem_r (expr n, f, t, r, c) =
+ if n < 0 :
+ chem_draw_vertical (n, chem_r_path[n], f, t, r, c) ;
+ else :
+ chem_draw (n, chem_r_path[n], f, t, r, c) ;
+ fi ;
+enddef ;
+vardef chem_rd (expr n, f, t, r, c) =
+ chem_dashed_normal (n, chem_r_path[n], f, t, r, c)
+enddef ;
+vardef chem_mrd (expr n, f, t, r, c) =
+ chem_dashed_normal (n, chem_mr_path[n], f, t, r, c)
+enddef ;
+vardef chem_prd (expr n, f, t, r, c) =
+ chem_dashed_normal (n, chem_pr_path[n], f, t, r, c)
+enddef ;
+vardef chem_br (expr n, f, t, r, c) =
+ chem_fill (n, chem_br_path[n], f, t, r, c )
+enddef ;
+vardef chem_rb (expr n, f, t, r, c) =
+ chem_fill (n, chem_rb_path[n], f, t, r, c)
+enddef ;
+vardef chem_mrb (expr n, f, t, r, c) =
+ chem_fill (n, chem_mrb_path[n], f, t, r, c)
+enddef ;
+vardef chem_prb (expr n, f, t, r, c) =
+ chem_fill (n, chem_prb_path[n], f, t, r, c)
+enddef ;
+vardef chem_mr (expr n, f, t, r, c) =
+ if n < 0 :
+ chem_draw_vertical(n, chem_mr_path[n], f, t, r, c)
+ else :
+ chem_draw (n, chem_mr_path[n], f, t, r, c)
+ fi
+enddef ;
+vardef chem_pr (expr n, f, t, r, c) =
+ if n < 0 :
+ chem_draw_vertical(n, chem_pr_path[n], f, t, r, c)
+ else :
+ chem_draw (n, chem_pr_path[n], f, t, r, c)
+ fi
+enddef ;
+vardef chem_sr (expr n, f, t, r, c) =
+ chem_draw (n, chem_sr_path[n], f, t, r, c)
+enddef ;
+vardef chem_msr (expr n, f, t, r, c) =
+ chem_draw (n, chem_msr_path[n], f, t, r, c)
+enddef ;
+vardef chem_psr (expr n, f, t, r, c) =
+ chem_draw (n, chem_psr_path[n], f, t, r, c)
+enddef ;
+vardef chem_c (expr n, f, t, r, c) =
+ chem_draw (n, chem_c_path[n], f, t, r, c)
+enddef ;
+vardef chem_cc (expr n, f, t, r, c) =
+ chem_draw (n, chem_cc_path[n], f, f, r, c)
+enddef ;
+vardef chem_cd (expr n, f, t, r, c) =
+ chem_dashed_connected (n, chem_c_path[n], f, t, r, c)
+enddef ;
+vardef chem_ccd (expr n, f, t, r, c) =
+ chem_dashed_normal (n, chem_cc_path[n], f, f, r, c)
+enddef ;
+vardef chem_rn (expr n, i, t) =
+ chem_rt (n,i,t) ;
+enddef ;
+vardef chem_rtn (expr n, i, t) =
+ chem_rtt(n,i,t) ;
+enddef ;
+vardef chem_rbn (expr n, i, t) =
+ chem_rbt(n,i,t) ;
+enddef ;
+vardef chem_tb (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_msb_path[n], f, t, r, c) ;
+ chem_draw (n, chem_sb_path [n], f, t, r, c) ;
+ chem_draw (n, chem_psb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_ep (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_e_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_es (expr n, f, t, r, c) = % one
+ chem_draw_dot (n, center chem_e_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_ed (expr n, f, t, r, c) = % one
+ chem_draw_dot (n, point 0 of chem_e_path[n], f, t, r, c) ;
+ chem_draw_dot (n, point 1 of chem_e_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_et (expr n, f, t, r, c) = % one
+ chem_draw_dot (n, point 0 of chem_e_path[n], f, t, r, c) ;
+ chem_draw_dot (n, center chem_e_path[n], f, t, r, c) ;
+ chem_draw_dot (n, point 1 of chem_e_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_sd (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_ddt_path[n], f, t, r, c) ;
+ chem_draw (n, chem_ddb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_rdd (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_ldt_path[n], f, t, r, c) ;
+ chem_draw (n, chem_ldb_path[n], f, t, r, c) ;
+ chem_draw (n, chem_psb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_ldd (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_msb_path[n], f, t, r, c) ;
+ chem_draw (n, chem_rdt_path[n], f, t, r, c) ;
+ chem_draw (n, chem_rdb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_hb (expr n, f, t, r, c) = % one
+ chem_draw_dot (n, point 0 of chem_sb_path[n], f, t, r, c) ;
+ chem_draw_dot (n, center chem_sb_path[n], f, t, r, c) ;
+ chem_draw_dot (n, point 1 of chem_sb_path[n], f, t, r, c) ;
+enddef ;
+vardef chem_bb (expr n, f, t, r, c) = % one
+ if n < 0 :
+ chem_fill (n, chem_bb_path[n], 1, 1, r, c) ;
+ chem_b (n, f, t, r, c) ;
+ else :
+ chem_fill (n, chem_bb_path[n], f, t, r, c) ;
+ fi ;
+enddef ;
+vardef chem_oe (expr n, f, t, r, c) = % one
+ chem_draw (n, chem_oe_path[n], f, t, r, c) ;
+enddef ;
+
+vardef chem_z_zero@#(text t) =
+ chem_text@#(t, chem_do(origin)) ;
+enddef ;
+vardef chem_cz_zero@#(text t) =
+ chem_text@#(t, chem_do(origin)) ;
+enddef ;
+vardef chem_z@#(expr n, p) (text t) =
+ if p = 0 :
+ chem_text@#(t, chem_do(origin)) ;
+ else :
+ chem_text@#(t, chem_do(chem_b_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_cz@#(expr n, p) (text t) =
+ if n = 1 :
+ chem_c_text(t, chem_do(chem_crz_zero[n] rotated chem_ang(n,p))) ;
+ else :
+ chem_text@#(t, chem_do(chem_b_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_midz@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_mid_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_rz@#(expr n, p) (text t) =
+ if n < 0 :
+ % quite special
+ chem_text@#(t, chem_do(chem_r_zero[n] shifted (chem_b_zero[n] rotated chem_ang(n,p)))) ;
+ else :
+ chem_text@#(t, chem_do(chem_r_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_crz@#(expr n, p) (text tx) =
+ chem_text(tx, chem_do(chem_crz_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_mrz@#(expr n, p) (text t) =
+ if n < 0 :
+ % quite special
+ chem_text@#(t, chem_do(chem_mr_zero[n] shifted (chem_b_zero[n] rotated chem_ang(n,p)))) ;
+ else :
+ chem_text@#(t, chem_do(chem_mr_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_prz@#(expr n, p) (text t) =
+ if n < 0 :
+ % quite special
+ chem_text@#(t, chem_do(chem_pr_zero[n] shifted (chem_b_zero[n] rotated chem_ang(n,p)))) ;
+ else :
+ chem_text@#(t, chem_do(chem_pr_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_rt@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_rtt@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rtt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_rbt@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rbt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_zt@#(expr n, p) (text t) =
+ if n = 1 :
+ chem_text@#(t, chem_do(chem_rt_zero[n] rotated chem_ang(n,p))) ;
+ else :
+ chem_text@#(t, chem_do(chem_n_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_zn@#(expr n, p) (text t) =
+ if n = 1 :
+ chem_text@#(t, chem_do(chem_rt_zero[n] rotated chem_ang(n,p))) ;
+ else :
+ chem_text@#(t, chem_do(chem_n_zero[n] rotated chem_ang(n,p))) ;
+ fi ;
+enddef ;
+vardef chem_zbt@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rtt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_zbn@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rtt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_ztt@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rbt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+vardef chem_ztn@#(expr n, p) (text t) =
+ chem_text@#(t, chem_do(chem_rbt_zero[n] rotated chem_ang(n,p))) ;
+enddef ;
+
+vardef chem_symbol(expr t) =
+ draw textext(t) ;
+enddef ;
+
+vardef chem_text@#(expr txt, z) = % adapted copy of thelabel@
+ save p ; picture p ;
+ p := textext(txt) ;
+ p := p
+ if (labtype@# >= 10) : shifted (0,ypart center p) fi
+ shifted (z + chem_text_offset*laboff@# - (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p)) ;
+ if chem_text_trace :
+ draw z withpen pencircle scaled 2pt withcolor red ;
+ draw boundingbox p withpen pencircle scaled 1pt withcolor red ;
+ fi ;
+ draw p
+enddef ;
+
+vardef chem_c_text(expr txt, z) = % adapted copy of thelabel@
+ save p ; picture p ; p := textext(txt) ;
+ save b ; path b ; b := (boundingbox p) shifted z ;
+ save a ; pair a ; a := (origin--z) intersection_point b ;
+ if intersection_found :
+ draw p shifted (z enlonged arclength(a -- center b)) ;
+ else :
+ draw p shifted z ;
+ fi
+% draw b withcolor green ;
+% draw a withcolor red ;
+enddef ;
+
+vardef chem_ang (expr n, d) =
+ ((-1 * (d-1) * chem_angle[n]) + (-chem_rotation+1) * 90 + chem_start[n]) % no ;
+enddef ;
+vardef chem_rot (expr n, d) =
+ chem_rotation := d ;
+enddef ;
+vardef chem_adj (expr n, d) =
+ chem_adjacent := d ;
+enddef ;
+vardef chem_sub (expr n, d) =
+ chem_substituent := d ;
+enddef ;
+vardef chem_dir (expr n, d) =
+ if n = 1 :
+ chem_direction_p := (origin - 2*center(chem_b_path[n] rotated chem_ang(n,d+1))) ;
+ currentpicture := currentpicture shifted chem_direction_p ;
+ chem_shift := chem_shift + chem_direction_p ;
+ fi ;
+enddef ;
+vardef chem_mov (expr n, d) =
+ if d = 0 :
+ currentpicture := currentpicture shifted - chem_shift ;
+ chem_shift := origin ;
+ else :
+ chem_move_p := (origin - 2*center(chem_b_path[n] rotated chem_ang(n,d+chem_initialmov[n]))) ;
+ currentpicture := currentpicture shifted chem_move_p ;
+ chem_shift := chem_shift + chem_move_p ;
+ fi ;
+enddef ;
+vardef chem_off (expr n, d) =
+ if (d = 1) or (d = 2) or (d = 8) : % positive
+ currentpicture := currentpicture shifted (-chem_setting_offset,0) ;
+ chem_shift := chem_shift + (-chem_setting_offset,0)
+ elseif (d = 4) or (d = 5) or (d = 6) : % negative
+ currentpicture := currentpicture shifted ( chem_setting_offset,0) ;
+ chem_shift := chem_shift + ( chem_setting_offset,0)
+ fi ;
+enddef ;
+
+vardef chem_set(expr n, m) =
+ if chem_adjacent > 0 :
+ chem_adjacent_d := xpart chem_b_zero[n] + xpart chem_b_zero[m] ;
+ if chem_adjacent = 1 : chem_adjacent_p := (-chem_adjacent_d, 0) ;
+ elseif chem_adjacent = 2 : chem_adjacent_p := (0, -chem_adjacent_d) ;
+ elseif chem_adjacent = 3 : chem_adjacent_p := ( chem_adjacent_d, 0) ;
+ elseif chem_adjacent = 4 : chem_adjacent_p := (0, chem_adjacent_d) ;
+ else : chem_adjacent_p := origin ;
+ fi ;
+ currentpicture := currentpicture shifted chem_adjacent_p ;
+ chem_shift := chem_shift + chem_adjacent_p ;
+ chem_adjacent := 0 ;
+ fi ;
+ if chem_substituent > 0 :
+ if m = 1 :
+ chem_substituent_d := xpart chem_crz_zero[n] + chem_substituent_offset ;
+ else :
+ chem_substituent_d := xpart chem_crz_zero[n] + xpart chem_b_zero[m] ;
+ fi ;
+ if chem_substituent = 1 : chem_substituent_p := (-chem_substituent_d, 0) ; % - ?
+ elseif chem_substituent = 2 : chem_substituent_p := (0, chem_substituent_d) ;
+ elseif chem_substituent = 3 : chem_substituent_p := ( chem_substituent_d, 0) ;
+ elseif chem_substituent = 4 : chem_substituent_p := (0, -chem_substituent_d) ;
+ else : chem_substituent_p := origin ;
+ fi ;
+ currentpicture := currentpicture shifted chem_substituent_p ;
+ chem_shift := chem_shift + chem_substituent_p ;
+ chem_substituent := 0 ;
+ fi ;
+ chem_rotation := chem_initialrot[m] ;
+enddef ;
+
+vardef chem_draw (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ for i:=from_point upto to_point:
+ draw (path_fragment rotated chem_ang(n,i)) withpen pencircle scaled linewidth withcolor linecolor ;
+ endfor ;
+enddef ;
+vardef chem_fill (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ for i:=from_point upto to_point:
+ fill (path_fragment rotated chem_ang(n,i)) withpen pencircle scaled 0 withcolor linecolor ;
+ endfor ;
+enddef ;
+
+vardef chem_dashed_normal (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ for i:=from_point upto to_point:
+ draw (path_fragment rotated chem_ang(n,i)) withpen pencircle scaled linewidth withcolor linecolor dashed evenly ;
+ endfor ;
+enddef ;
+vardef chem_dashed_connected (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ draw for i:=from_point upto to_point:
+ (path_fragment rotated chem_ang(n,i)) if i < to_point : -- fi
+ endfor withpen pencircle scaled linewidth withcolor linecolor dashed evenly ;
+enddef ;
+vardef chem_draw_dot (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ for i:=from_point upto to_point:
+ draw (path_fragment rotated chem_ang(n,i)) withpen pencircle scaled (chem_dot_factor*linewidth) withcolor linecolor ;
+ endfor ;
+enddef ;
+vardef chem_draw_fixed (expr n, path_fragment, linewidth, linecolor) =
+ draw (path_fragment rotated chem_ang(n,1)) withpen pencircle scaled linewidth withcolor linecolor ;
+enddef ;
+vardef chem_draw_arrow (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ for i:=from_point upto to_point:
+ drawarrow (path_fragment rotated chem_ang(n,i)) withpen pencircle scaled linewidth withcolor linecolor ;
+ endfor ;
+enddef ;
+vardef chem_draw_vertical (expr n, path_fragment, from_point, to_point, linewidth, linecolor) =
+ % quite special
+ for i:=from_point upto to_point:
+ draw (path_fragment shifted (chem_b_zero[n] rotated chem_ang(n,i))) withpen pencircle scaled linewidth withcolor linecolor ;
+ endfor ;
+enddef ;
+
+picture chem_stack_p[] ;
+pair chem_stack_shift[] ;
+
+vardef chem_save =
+ chem_stack_n := chem_stack_n + 1 ;
+ chem_stack_p[chem_stack_n] := currentpicture ;
+ chem_stack_shift[chem_stack_n] := chem_shift ;
+ chem_shift := origin ;
+% chem_adjacent := 0 ;
+% chem_substituent := 0 ;
+% chem_rotation := 1 ;
+ currentpicture := nullpicture ;
+enddef ;
+vardef chem_restore =
+ if chem_stack_n > 0 :
+ currentpicture := currentpicture shifted - chem_shift ;
+ addto chem_stack_p[chem_stack_n] also currentpicture ;
+ currentpicture := chem_stack_p[chem_stack_n] ;
+ chem_stack_p[chem_stack_n] := nullpicture ;
+ chem_shift := chem_stack_shift[chem_stack_n] ;
+ chem_stack_n := chem_stack_n - 1 ;
+ fi ;
+enddef ;
+
+def chem_init_some(expr n, ratio, angle, start, initialrot, initialmov) =
+ chem_width [n] := ratio * chem_base_width * chem_setting_scale ;
+ chem_angle [n] := angle ;
+ chem_start [n] := start ;
+ chem_initialrot[n] := initialrot ;
+ chem_initialmov[n] := initialmov ;
+ chem_b_zero [n] := (chem_width[n],0) rotated (angle/2) ;
+ chem_n_zero [n] := (chem_text_min*chem_width[n],0) rotated (angle/2) ;
+ chem_r_max [n] := chem_radical_max*chem_b_zero[n] ;
+ chem_r_path [n] := chem_b_zero[n] -- chem_r_max[n] ;
+ chem_mr_path [n] := chem_r_path [n] rotatedaround(chem_b_zero[n], (180-angle)/2) ;
+ chem_pr_path [n] := chem_r_path [n] rotatedaround(chem_b_zero[n],-(180-angle)/2) ;
+ chem_r_zero [n] := point 1 of chem_r_path [n] ;
+ chem_mr_zero [n] := point 1 of chem_mr_path[n] ;
+ chem_pr_zero [n] := point 1 of chem_pr_path[n] ;
+ chem_crz_zero [n] := point 1 of (chem_r_path[n] enlonged chem_center_offset) ;
+ chem_au_path [n] := subpath (0.2,0.8) of (chem_r_max[n] -- (chem_r_max[n] rotated angle)) ;
+ chem_ad_path [n] := reverse(chem_au_path[n]) ;
+ chem_rt_zero [n] := (((chem_radical_max+chem_radical_min)/2)*chem_width[n],0) rotated (angle/2) ;
+ chem_rtt_zero [n] := chem_rt_zero[n] rotated + 10 ;
+ chem_rbt_zero [n] := chem_rt_zero[n] rotated - 10 ;
+ chem_b_path [n] := reverse(chem_b_zero[n] -- (chem_b_zero[n] rotated -angle)) ;
+ chem_bx_path [n] := reverse(chem_b_zero[n] -- (chem_b_zero[n] rotated -angle)) ; % ?
+ chem_sb_path [n] := subpath (0.25,0.75) of chem_b_path[n] ;
+ chem_s_path [n] := point 0 of chem_b_path[n] -- point 0 of (chem_b_path[n] rotated (2angle)) ;
+ chem_ss_path [n] := subpath (0.25,0.75) of (chem_s_path[n]) ;
+ chem_pss_path [n] := subpath (0.00,0.75) of (chem_s_path[n]) ;
+ chem_mss_path [n] := subpath (0.25,1.00) of (chem_s_path[n]) ;
+ chem_mid_zero [n] := origin shifted (-.25chem_width[n],0) ;
+ chem_midst_path[n] := chem_mid_zero[n] -- (chem_width[n],0) rotated ( angle + angle/2) ;
+ chem_midsb_path[n] := chem_mid_zero[n] -- (chem_width[n],0) rotated (-angle - angle/2) ;
+ chem_midt_path [n] := subpath (0.25,1.00) of chem_midst_path [n] ;
+ chem_midb_path [n] := subpath (0.25,1.00) of chem_midsb_path [n] ;
+ chem_msb_path [n] := subpath (0.00,0.75) of chem_b_path[n] ;
+ chem_psb_path [n] := subpath (0.25,1.00) of chem_b_path[n] ;
+ chem_dbl_path [n] := chem_sb_path[n] shifted - (0.05[origin,center chem_sb_path[n]]) ; % parallel
+ chem_dbr_path [n] := chem_sb_path[n] shifted + (0.05[origin,center chem_sb_path[n]]) ;
+ chem_eb_path [n] := chem_sb_path[n] shifted - (0.25[origin,center chem_sb_path[n]]) ;
+ chem_sr_path [n] := chem_radical_min*chem_b_zero[n] -- chem_r_max[n] ;
+ chem_rl_path [n] := chem_r_path[n] paralleled (chem_base_width/20) ;
+ chem_rr_path [n] := chem_r_path[n] paralleled -(chem_base_width/20) ;
+ chem_srl_path [n] := chem_sr_path[n] paralleled (chem_base_width/20) ;
+ chem_srr_path [n] := chem_sr_path[n] paralleled -(chem_base_width/20) ;
+ chem_br_path [n] := point 1 of chem_sb_path[n] --
+ point 0 of chem_sb_path[n] rotatedaround(point 1 of chem_sb_path[n], -4) --
+ point 0 of chem_sb_path[n] rotatedaround(point 1 of chem_sb_path[n], 4) -- cycle ;
+ chem_rb_path [n] := chem_b_zero[n] -- chem_r_max[n] rotated -2 -- chem_r_max[n] -- chem_r_max[n] rotated 2 -- cycle ;
+ chem_mrb_path [n] := chem_rb_path[n] rotatedaround(chem_b_zero[n], (180-angle)/2) ;
+ chem_prb_path [n] := chem_rb_path[n] rotatedaround(chem_b_zero[n],-(180-angle)/2) ;
+ chem_msr_path [n] := chem_sr_path[n] rotatedaround(chem_b_zero[n], (180-angle)/2) ;
+ chem_psr_path [n] := chem_sr_path[n] rotatedaround(chem_b_zero[n],-(180-angle)/2) ;
+ % not yet ok:
+ chem_c_path [n] := subpath (30/45, -30/45) of (fullcircle scaled (1.25*chem_circle_radius*chem_width[n]));
+ chem_cc_path [n] := subpath (30/45,8-30/45) of (fullcircle rotated 90 scaled (1.25*chem_circle_radius*chem_width[n]));
+enddef ;
+
+def chem_init_three = chem_init_some(3,30/52 ,120,-60,1,2) ; enddef ; % 60
+def chem_init_four = chem_init_some(4,30/42.5, 90, 0,1,0) ; enddef ; % 45
+def chem_init_five = chem_init_some(5,30/35 , 72, 0,1,0) ; enddef ; % 36
+def chem_init_six = chem_init_some(6, 1 , 60, 0,1,0) ; enddef ; % 30
+def chem_init_eight = chem_init_some(8,30/22.5, 45, 0,1,0) ; enddef ; % 22.5
+
+% bb R -R R Z -RZ +RZ
+
+def chem_init_some_front(expr n, ratio, angle, start, initialrot, initialmov) =
+ chem_init_some(n, ratio, angle, start, initialrot, initialmov) ;
+ chem_bb_path [n] := chem_b_path[n] rotated -angle -- chem_b_path[n] -- chem_b_path[n] rotated angle --
+ (reverse(chem_b_path[n] shortened (chem_base_width/20))) paralleled (chem_base_width/20) --
+ cycle ;
+ chem_r_max [n] := chem_radical_max*chem_b_zero[n] ;
+ chem_mr_path [n] := origin -- origin shifted (0,-.25chem_base_width) ;
+ chem_pr_path [n] := origin -- origin shifted (0, .25*chem_base_width) ;
+ chem_r_path [n] := point 1 of chem_mr_path[n] -- point 1 of chem_pr_path[n] ;
+ chem_mr_zero [n] := point 1 of chem_mr_path[n] ;
+ chem_pr_zero [n] := point 1 of chem_pr_path[n] ;
+enddef ;
+
+def chem_init_five_front = chem_init_some_front(-5,30/35,72,0,2,0) ; enddef ; % 36
+def chem_init_six_front = chem_init_some_front(-6, 1 ,60,0,2,0) ; enddef ; % 30
+
+def chem_init_one =
+ chem_width [1] := .75 * chem_base_width * chem_setting_scale ;
+ chem_angle [1] := 45 ;
+ chem_start [1] := 0 ;
+ chem_initialrot[1] := 1 ;
+ chem_initialmov[1] := 1 ;
+ chem_b_zero [1] := (1.75*chem_width[1],0) ;
+ chem_r_min [1] := chem_radical_min*chem_b_zero[1] ;
+ chem_r_max [1] := chem_radical_max*chem_b_zero[1] ;
+ chem_r_path [1] := (.5*chem_width[1],0) -- (1.25*chem_width[1],0) ;
+ chem_r_zero [1] := point 1 of chem_r_path [1] ;
+ chem_b_path [1] := chem_r_path[1] rotated + (chem_angle[1]) ; % used for move here
+ chem_b_zero [1] := chem_r_zero[1] ;
+ chem_crz_zero [1] := chem_r_zero[1] enlonged chem_center_offset ;
+ chem_e_path [1] := (.5*chem_width[1],-.25*chem_width[1]) -- (.5*chem_width[1],.25*chem_width[1]) ;
+ chem_sb_path [1] := chem_r_path [1] ;
+ chem_msb_path [1] := chem_r_path [1] shifted (0,-.1chem_width[1]) ;
+ chem_psb_path [1] := chem_r_path [1] shifted (0, .1chem_width[1]) ;
+ chem_ddt_path [1] := subpath(0,.4) of chem_r_path [1] ;
+ chem_ddb_path [1] := subpath(.6,1) of chem_r_path [1] ;
+ chem_ldt_path [1] := chem_ddt_path [1] shifted (0,-.1chem_width[1]) ; % parallel
+ chem_ldb_path [1] := chem_ddb_path [1] shifted (0,-.1chem_width[1]) ;
+ chem_rdt_path [1] := chem_ddt_path [1] shifted (0, .1chem_width[1]) ;
+ chem_rdb_path [1] := chem_ddb_path [1] shifted (0, .1chem_width[1]) ;
+ chem_bb_path [1] := point 0 of chem_r_path[1] --
+ point 1 of chem_r_path[1] rotatedaround(point 0 of chem_r_path[1], -4) --
+ point 1 of chem_r_path[1] rotatedaround(point 0 of chem_r_path[1], 4) -- cycle ;
+ chem_oe_path [1] := ((-20,0)--(10,0){up}..(20,10)..(30,0)..(40,-10)..(50.0,0)..(60,10)..(70,0)..(80,-10)..{up}(90,0)--(120,0))
+ xsized (.75*chem_width[1]) shifted point 0 of chem_r_path[1] ;
+ chem_rt_zero [1] := point .5 of chem_r_path[1] ;
+ chem_rtt_zero [1] := chem_rt_zero[1] rotated + (chem_angle[1]/2) ;
+ chem_rbt_zero [1] := chem_rt_zero[1] rotated - (chem_angle[1]/2) ;
+enddef ;
+
+def chem_init_all =
+ chem_init_one ;
+ chem_init_three ;
+ chem_init_four ;
+ chem_init_five ;
+ chem_init_six ;
+ chem_init_eight ;
+ chem_init_five_front ;
+ chem_init_six_front ;
+enddef ;
+
+chem_init_all ;
+
diff --git a/metapost/context/base/mp-core.mp b/metapost/context/base/mp-core.mp
index 0bf19b8a5..6720fe90d 100644
--- a/metapost/context/base/mp-core.mp
+++ b/metapost/context/base/mp-core.mp
@@ -346,6 +346,8 @@ boolean force_multi_par_chain ; force_multi_par_chain := true ;
boolean one_piece_multi_par ; one_piece_multi_par := false ;
boolean check_multi_par_chain ; check_multi_par_chain := true ; % extra page check
+boolean multi_column_first_page_hack; multi_column_first_page_hack := false ;
+
def simplify_multi_pars = % boundingbox ipv shape als optie
for i := 1 upto nofmultipars :
multipars[i] := boundingbox multipars[i] ;
@@ -428,8 +430,6 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
numeric multi_par_pages ; multi_par_pages := nxy[tpos]-nxy[fpos]+1 ;
- ii := 0 ; nn := NOfTextAreas+1 ; nofmultipars := 0 ;
-
vardef snapped_multi_pos (expr p) =
if snap_multi_par_tops :
if abs(ypart p - ypart ulcorner multipar) < par_line_height :
@@ -502,7 +502,7 @@ def prepare_multi_pars (expr fn,fx,fy,fw,fh,fd,
vardef left_top_hang (expr same_area) =
-par_hang_after := ra + estimated_par_lines(py-fy) ;
+ par_hang_after := ra + estimated_par_lines(py-fy) ;
if (par_hang_indent>0) and (par_hang_after<0) and obey_multi_par_hang :
pair _ul_ ; _ul_ := (xpart ulcorner multipar, ypart snapped_multi_pos(ulxy[fpos]));
@@ -525,7 +525,7 @@ par_hang_after := ra + estimated_par_lines(py-fy) ;
vardef right_top_hang (expr same_area) =
-par_hang_after := ra + estimated_par_lines(py-fy) ;
+ par_hang_after := ra + estimated_par_lines(py-fy) ;
if (par_hang_indent<0) and (par_hang_after<0) and obey_multi_par_hang :
pair _ur_ ; _ur_ := (xpart urcorner multipar, ypart snapped_multi_pos(urxy[fpos])) ;
@@ -552,17 +552,15 @@ par_hang_after := ra + estimated_par_lines(py-fy) ;
pair _ul_ ; _ul_ := ulcorner multipar ;
pair _pa_ ; _pa_ := _ul_ shifted (0,par_hang_after*par_line_height) ;
_pa_ := (xpart _pa_,max(ypart _pa_,ypart llcorner multipar)) ;
-
-if t :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
-fi ;
-if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
- _pa_ := (xpart _pa_,ypart llxy[tpos]);
-fi ;
-if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
- _pa_ := (xpart _pa_,ypart llcorner multipar);
-fi ;
-
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart llxy[tpos]));
+ fi ;
+ if abs(ypart _pa_-ypart llxy[tpos])<par_line_height :
+ _pa_ := (xpart _pa_,ypart llxy[tpos]);
+ fi ;
+ if abs(ypart _pa_-ypart llcorner multipar)<par_line_height :
+ _pa_ := (xpart _pa_,ypart llcorner multipar);
+ fi ;
(xpart _ul_, ypart _pa_) --
(xpart _ul_ + par_hang_indent, ypart _pa_) --
(xpart _ul_ + par_hang_indent, ypart _ul_)
@@ -571,18 +569,15 @@ fi ;
fi
enddef ;
-
vardef x_right_top_hang (expr i, t) =
par_hang_after := min(0,ra + estimated_multi_par_height(i,t)) ;
if (par_hang_indent<0) and (par_hang_after<0) :
pair _ur_ ; _ur_ := urcorner multipar ;
pair _pa_ ; _pa_ := _ur_ shifted (0,par_hang_after*par_line_height) ;
_pa_ := (xpart _pa_,max(ypart _pa_,ypart lrcorner multipar)) ;
-if t :
- _pa_ := (xpart _pa_,max(ypart _pa_,ypart snapped_multi_pos(urxy[tpos]))) ;
-fi ;
-
-
+ if t :
+ _pa_ := (xpart _pa_,max(ypart _pa_,ypart snapped_multi_pos(urxy[tpos]))) ;
+ fi ;
(xpart _ur_ + par_hang_indent, ypart _ur_) --
(xpart _ur_ + par_hang_indent, ypart _pa_) --
(xpart _ur_, ypart _pa_)
@@ -681,6 +676,8 @@ fi ;
% first loop
+ ii := 0 ; nn := NOfTextAreas+1 ; nofmultipars := 0 ;
+
if enable_multi_par_fallback and
(nxy[fpos]=RealPageNumber) and
(nxy[tpos]=RealPageNumber) and not
@@ -876,7 +873,7 @@ fi ;
x_left_top_hang(i,true) --
x_right_top_hang(i,true) --
x_right_bottom_hang(i,true) --
-snapped_multi_pos(ulxy[tpos]) --
+ snapped_multi_pos(ulxy[tpos]) --
llxy[tpos] --
x_left_bottom_hang(i,true) --
cycle ;
@@ -887,7 +884,7 @@ snapped_multi_pos(ulxy[tpos]) --
ulcorner multipar --
urcorner multipar --
(xpart lrcorner multipar, ypart urxy[tpos]) --
-snapped_multi_pos(ulxy[tpos]) --
+ snapped_multi_pos(ulxy[tpos]) --
llxy[tpos] --
(xpart llcorner multipar, ypart llxy[tpos]) --
cycle ;
@@ -896,45 +893,50 @@ snapped_multi_pos(ulxy[tpos]) --
save_multipar (i,3,multipar) ;
- else :
+ elseif multi_column_first_page_hack and ((nxy[fpos]=RealPageNumber) and (nxy[tpos]>=RealPageNumber) and (NOfTextColumns>1)) :
- % handled later
+ save_multipar (i,2,multipar) ;
+ else :
+ % handled later
fi ;
endfor ;
% second loop
-if force_multi_par_chain or (ii > 1) :
+ if force_multi_par_chain or (ii > 1) :
- for i=ii+1 upto nn-1 :
+ for i=ii+1 upto nn-1 :
- % rest of chain / todo : hang
+ % rest of chain / todo : hang
+% hm, the second+ column in column sets now gets lost in a NOfTextColumns
-if (not check_multi_par_chain) or ((nxy[fpos]<RealPageNumber) and (nxy[tpos]>RealPageNumber)) :
+ if (not check_multi_par_chain) or
+ ((nxy[fpos]<RealPageNumber) and (nxy[tpos]>RealPageNumber))
+ :
- multipar := set_multipar(i) ;
+ multipar := set_multipar(i) ;
- if obey_multi_par_hang and obey_multi_par_more :
+ if obey_multi_par_hang and obey_multi_par_more :
- multipar :=
- x_left_top_hang(i,false) --
- x_right_top_hang(i,false) --
- x_right_bottom_hang(i,false) --
- x_left_bottom_hang(i,false) --
- cycle ;
+ multipar :=
+ x_left_top_hang(i,false) --
+ x_right_top_hang(i,false) --
+ x_right_bottom_hang(i,false) --
+ x_left_bottom_hang(i,false) --
+ cycle ;
- fi ;
+ fi ;
- save_multipar(i,2,multipar) ;
+ save_multipar(i,2,multipar) ;
-fi ;
+ fi ;
- endfor ;
+ endfor ;
-fi ;
+ fi ;
% end of normal/fallback
@@ -1375,3 +1377,42 @@ enddef ;
endinput ;
end
+
+% for Jelle Huisman
+%
+% \setupcolors[state=start]
+% \dontcomplain
+% \definecolumnset[example][n=3,distance=5mm]
+% \startMPextensions
+% multi_column_first_page_hack := true ;
+% \stopMPextensions
+% \startuseMPgraphic{mpos:par:trick}
+% for i=1 upto nofmultipars-1 : draw (rightboundary multipars[i]) shifted (2.5mm, 0) ; endfor ;
+% \stopuseMPgraphic
+% \definetextbackground[test][mp=mpos:par:trick,method=mpos:par:columnset]
+% \starttext
+% \definecolumnsetspan[chapter][n=3]
+% \startcolumnset[example]
+% \startcolumnsetspan[chapter]
+% \chapter{Chapter One}
+% \stopcolumnsetspan
+% \starttextbackground[test] \dorecurse {3}{\input knuth } \stoptextbackground
+% \stopcolumnset
+% \startcolumnset[example]
+% \startcolumnsetspan[chapter]
+% \chapter{Chapter One}
+% \stopcolumnsetspan
+% \starttextbackground[test] \dorecurse {10}{\input knuth } \stoptextbackground
+% \stopcolumnset
+% \stoptext
+%
+% fast variant:
+%
+% \startuseMPgraphic{whatever}
+% for i=1 upto NOfTextColumns-1 :
+% draw (rightboundary TextColumns[i]) shifted (2.5mm,0) shifted -\MPxy\textanchor ;
+% endfor ;
+% setbounds currentpicture to OverlayBox ;
+% \stopuseMPgraphic
+% \defineoverlay[whatever][\useMPgraphic{whatever}]
+% \setupbackgrounds[text][background=whatever]
diff --git a/metapost/context/base/mp-mlib.mp b/metapost/context/base/mp-mlib.mp
index 134cd12a3..893222473 100644
--- a/metapost/context/base/mp-mlib.mp
+++ b/metapost/context/base/mp-mlib.mp
@@ -30,7 +30,9 @@ extra_endfig := ";addto currentpicture also _tt_p_; " & extra_endfig; % was dr
extra_beginfig := extra_beginfig & "resettextexts;";
vardef rawtextext(expr str) =
- if _trial_run_ :
+ if str = "" :
+ nullpicture
+ elseif _trial_run_ :
image (
_tt_n_ := _tt_n_ + 1 ;
_tt_p_ := image (
@@ -51,6 +53,8 @@ vardef rawtextext(expr str) =
fi
enddef ;
+% not ok yet
+
pair laboff.d, laboff.dlft, laboff.drt ; % new positional suffixes
pair laboff.origin, laboff.raw ; % graph mess
@@ -67,10 +71,66 @@ labtype.origin := 0 ; labtype.raw := 0 ;
laboff.origin = (infinity,infinity) ; labxf.origin := 0 ; labyf.origin := 0 ;
laboff.raw = (infinity,infinity) ; labxf.raw := 0 ; labyf.raw := 0 ;
+pair laboff.l ; laboff.l = laboff.lft ;
+pair laboff.r ; laboff.r = laboff.rt ;
+pair laboff.b ; laboff.b = laboff.bot ;
+pair laboff.t ; laboff.t = laboff.top ;
+pair laboff.l_t ; laboff.l_t = laboff.ulft ;
+pair laboff.r_t ; laboff.r_t = laboff.urt ;
+pair laboff.l_b ; laboff.l_b = laboff.llft ;
+pair laboff.r_b ; laboff.r_b = laboff.lrt ;
+pair laboff.t_l ; laboff.t_l = laboff.ulft ;
+pair laboff.t_r ; laboff.t_r = laboff.urt ;
+pair laboff.b_l ; laboff.b_l = laboff.llft ;
+pair laboff.b_r ; laboff.b_r = laboff.lrt ;
+
+labxf.l ; labxf.l = labxf.lft ;
+labxf.r ; labxf.r = labxf.rt ;
+labxf.b ; labxf.b = labxf.bot ;
+labxf.t ; labxf.t = labxf.top ;
+labxf.l_t ; labxf.l_t = labxf.ulft ;
+labxf.r_t ; labxf.r_t = labxf.urt ;
+labxf.l_b ; labxf.l_b = labxf.llft ;
+labxf.r_b ; labxf.r_b = labxf.lrt ;
+labxf.t_l ; labxf.t_l = labxf.ulft ;
+labxf.t_r ; labxf.t_r = labxf.urt ;
+labxf.b_l ; labxf.b_l = labxf.llft ;
+labxf.b_r ; labxf.b_r = labxf.lrt ;
+
+labyf.l ; labyf.l = labyf.lft ;
+labyf.r ; labyf.r = labyf.rt ;
+labyf.b ; labyf.b = labyf.bot ;
+labyf.t ; labyf.t = labyf.top ;
+labyf.l_t ; labyf.l_t = labyf.ulft ;
+labyf.r_t ; labyf.r_t = labyf.urt ;
+labyf.l_b ; labyf.l_b = labyf.llft ;
+labyf.r_b ; labyf.r_b = labyf.lrt ;
+labyf.t_l ; labyf.t_l = labyf.ulft ;
+labyf.t_r ; labyf.t_r = labyf.urt ;
+labyf.b_l ; labyf.b_l = labyf.llft ;
+labyf.b_r ; labyf.b_r = labyf.lrt ;
+
+labtype.l ; labtype.l = labtype.lft ;
+labtype.r ; labtype.r = labtype.rt ;
+labtype.b ; labtype.b = labtype.bot ;
+labtype.t ; labtype.t = labtype.top ;
+labtype.l_t ; labtype.l_t = labtype.ulft ;
+labtype.r_t ; labtype.r_t = labtype.urt ;
+labtype.l_b ; labtype.l_b = labtype.llft ;
+labtype.r_b ; labtype.r_b = labtype.lrt ;
+labtype.t_l ; labtype.t_l = labtype.ulft ;
+labtype.t_r ; labtype.t_r = labtype.urt ;
+labtype.b_l ; labtype.b_l = labtype.llft ;
+labtype.b_r ; labtype.b_r = labtype.lrt ;
+
vardef thetextext@#(expr p,z) = % adapted copy of thelabel@
- p
- if (labtype@# >= 10) : shifted (0,ypart center p) fi
- shifted (z + labeloffset*laboff@# - (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p))
+ if string p :
+ thetextext@#(rawtextext(p),z)
+ else :
+ p
+ if (labtype@# >= 10) : shifted (0,ypart center p) fi
+ shifted (z + labeloffset*laboff@# - (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p))
+ fi
enddef;
vardef textext@#(expr txt) =
@@ -82,6 +142,28 @@ vardef textext@#(expr txt) =
fi
enddef ;
+% \starttext
+% \startMPpage
+% numeric value ; value = 123 ;
+% label.lft(decimal value,origin) ;
+% draw "oeps" infont defaultfont ;
+% \stopMPpage
+% \stoptext
+
+vardef thelabel@#(expr s, z) =
+ save p ; picture p ;
+ if picture s :
+ p = s ;
+ else :
+ p = textext("\definedfont[" & defaultfont & "]" & s) scaled defaultscale ;
+ fi ;
+ p shifted (z + labeloffset*laboff@# - (labxf@#*lrcorner p + labyf@#*ulcorner p + (1-labxf@#-labyf@#)*llcorner p))
+enddef;
+
+primarydef str infont name = % very naughty !
+ textext("\definedfont[" & name & "]" & str)
+enddef ;
+
def circular_shade (expr p, n, ca, cb) =
begingroup ;
save ab, r ; pair ab ; numeric r ;
diff --git a/metapost/context/base/mp-page.mp b/metapost/context/base/mp-page.mp
index e3750b55b..71ca12aa0 100644
--- a/metapost/context/base/mp-page.mp
+++ b/metapost/context/base/mp-page.mp
@@ -444,4 +444,4 @@ def Enlarged (expr p, d) =
ulEnlarged (p,d) -- cycle)
enddef ;
-endinput ; \ No newline at end of file
+endinput ;
diff --git a/metapost/context/base/mp-text.mp b/metapost/context/base/mp-text.mp
index c1f9c80e9..292b79b4f 100644
--- a/metapost/context/base/mp-text.mp
+++ b/metapost/context/base/mp-text.mp
@@ -86,8 +86,9 @@ string laboff_l ; laboff_l := ".lft" ;
string laboff_r ; laboff_r := ".rt" ;
string laboff_b ; laboff_b := ".bot" ;
string laboff_t ; laboff_t := ".top" ;
+
string laboff_lt ; laboff_lt := ".ulft" ;
-string laboff_rt ; laboff_rt := ".urt" ;
+string laboff_rt ; laboff_rt := ".urt" ; % bugged, conflict with r
string laboff_lb ; laboff_lb := ".llft" ;
string laboff_rb ; laboff_rb := ".lrt" ;
string laboff_tl ; laboff_tl := ".ulft" ;
diff --git a/metapost/context/base/mp-tool.mp b/metapost/context/base/mp-tool.mp
index ccec2f3c8..817f237b0 100644
--- a/metapost/context/base/mp-tool.mp
+++ b/metapost/context/base/mp-tool.mp
@@ -828,6 +828,15 @@ primarydef p crossed d =
center p shifted ( 0,+d) -- ulcorner p -- cycle)
enddef ;
+%D Also handy (math ladders):
+
+vardef laddered expr p =
+ point 0 of p
+ for i=1 upto length(p) :
+ -- (xpart (point i of p), ypart (point (i-1) of p)) -- (point i of p)
+ endfor
+enddef ;
+
%D Saves typing:
% vardef bottomboundary primary p = (llcorner p -- lrcorner p) enddef ;
@@ -975,6 +984,10 @@ enddef ;
% endgroup
%enddef ;
+primarydef p paralleled d =
+ p shifted if d < 0 : - fi ((point abs(d) on (p rotatedaround(point 0 of p,90))) - point 0 of p)
+enddef ;
+
vardef punked primary p =
(point 0 of p for i=1 upto length(p)-1 : -- point i of p endfor
if cycle p : -- cycle else : -- point length(p) of p fi)
@@ -1746,12 +1759,55 @@ def condition primary b = if b : "true" else : "false" fi enddef ;
primarydef p stretched s =
begingroup
-% save pp ; path pp ; pp := p scaled s ;
save pp ; path pp ; pp := p xyscaled s ;
(pp shifted ((point 0 of p) - (point 0 of pp)))
endgroup
enddef ;
+% primarydef p enlonged len =
+% begingroup
+% save al ; al := arclength(p) ;
+% if al > 0 :
+% if pair p :
+% point 1 of ((origin -- p) stretched ((al+len)/al))
+% else :
+% p stretched ((al+len)/al)
+% fi
+% else :
+% p
+% fi
+% endgroup
+% enddef ;
+
+primarydef p enlonged len =
+ begingroup
+ if pair p :
+ save q ; path q ; q := origin -- p ;
+ save al ; al := arclength(q) ;
+ if al > 0 :
+ point 1 of (q stretched ((al+len)/al))
+ else :
+ p
+ fi
+ else :
+ save al ; al := arclength(p) ;
+ if al > 0 :
+ p stretched ((al+len)/al)
+ else :
+ p
+ fi
+ fi
+ endgroup
+enddef ;
+
+% path p ; p := (0,0) -- (10cm,5cm) ;
+% drawarrow p withcolor red ;
+% drawarrow p shortened 1cm withcolor green ;
+
+primarydef p shortened d =
+ reverse ( ( reverse (p enlonged -d) ) enlonged -d )
+enddef ;
+
% yes or no, untested -)
def xshifted expr dx = shifted(dx,0) enddef ;
diff --git a/scripts/context/lua/luatools.lua b/scripts/context/lua/luatools.lua
index 1e38edeab..aacdbd16d 100644
--- a/scripts/context/lua/luatools.lua
+++ b/scripts/context/lua/luatools.lua
@@ -1,25 +1,26 @@
#!/usr/bin/env texlua
+if not modules then modules = { } end modules ['luatools'] = {
+ version = 1.001,
+ comment = "companion to context.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
-- one can make a stub:
--
-- #!/bin/sh
-- env LUATEXDIR=/....../texmf/scripts/context/lua texlua luatools.lua "$@"
--- filename : luatools.lua
--- comment : companion to context.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-- Although this script is part of the ConTeXt distribution it is
-- relatively indepent of ConTeXt. The same is true for some of
-- the luat files. We may may make them even less dependent in
-- the future. As long as Luatex is under development the
-- interfaces and names of functions may change.
-banner = "version 1.2.2 - 2006+ - PRAGMA ADE / CONTEXT"
-texlua = true
-
-- For the sake of independence we optionally can merge the library
-- code here. It's too much code, but that does not harm. Much of the
-- library code is used elsewhere. We don't want dependencies on
@@ -28,141 +29,42 @@ texlua = true
-- needed when texmfstart is used, or when the proper stub is used or
-- when (windows) suffix binding is active.
+texlua = true
+
-- begin library merge
--- filename : l-string.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['l-string'] = 1.001
-
---~ function string.split(str, pat) -- taken from the lua wiki
---~ local t = {n = 0} -- so this table has a length field, traverse with ipairs then!
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = string.find(str, fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ table.insert(t,cap)
---~ end
---~ last_end = e+1
---~ s, e, cap = string.find(str, fpat, last_end)
---~ end
---~ if last_end<=string.len(str) then
---~ table.insert(t,(string.sub(str,last_end)))
---~ end
---~ return t
---~ end
---~ function string:split(pat) -- taken from the lua wiki but adapted
---~ local t = { } -- self and colon usage (faster)
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = self:find(fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ t[#t+1] = cap
---~ end
---~ last_end = e+1
---~ s, e, cap = self:find(fpat, last_end)
---~ end
---~ if last_end <= #self then
---~ t[#t+1] = self:sub(last_end)
---~ end
---~ return t
---~ end
---~ a piece of brilliant code by Rici Lake (posted on lua list) -- only names changed
---~
---~ function string:splitter(pat)
---~ local st, g = 1, self:gmatch("()"..pat.."()")
---~ local function splitter(self)
---~ if st then
---~ local s, f = g()
---~ local rv = self:sub(st, (s or 0)-1)
---~ st = f
---~ return rv
---~ end
---~ end
---~ return splitter, self
---~ end
-function string:splitter(pat)
- -- by Rici Lake (posted on lua list) -- only names changed
- -- p 79 ref man: () returns position of match
- local st, g = 1, self:gmatch("()("..pat..")")
- local function strgetter(self, segs, seps, sep, cap1, ...)
- st = sep and seps + #sep
- return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
- end
- local function strsplitter(self)
- if st then return strgetter(self, st, g()) end
- end
- return strsplitter, self
-end
+do -- create closure to overcome 200 locals limit
-function string:split(separator)
- local t = {}
- for k in self:splitter(separator) do t[#t+1] = k end
- return t
-end
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
--- faster than a string:split:
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
-function string:splitchr(chr)
- if #self > 0 then
- local t = { }
- for s in (self..chr):gmatch("(.-)"..chr) do
- t[#t+1] = s
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
end
- return t
- else
- return { }
end
-end
-function string.piecewise(str, pat, fnc) -- variant of split
- for k in string.splitter(str,pat) do fnc(k) end
end
---~ function string.piecewise(str, pat, fnc) -- variant of split
---~ for k in str:splitter(pat) do fnc(k) end
---~ end
-
---~ do if lpeg then
-
---~ -- this alternative is 30% faster esp when we cache them
---~ -- problem: no expressions
-
---~ splitters = { }
-
---~ function string:split(separator)
---~ if #self > 0 then
---~ local split = splitters[separator]
---~ if not split then
---~ -- based on code by Roberto
---~ local p = lpeg.P(separator)
---~ local c = lpeg.C((1-p)^0)
---~ split = lpeg.Ct(c*(p*c)^0)
---~ splitters[separator] = split
---~ end
---~ return split:match(self)
---~ else
---~ return { }
---~ end
---~ end
-
---~ string.splitchr = string.split
-
---~ function string:piecewise(separator,fnc)
---~ for _,v in pairs(self:split(separator)) do
---~ fnc(v)
---~ end
---~ end
-
---~ end end
-
local chr_to_esc = {
["%"] = "%%",
["."] = "%.",
@@ -176,20 +78,20 @@ local chr_to_esc = {
string.chr_to_esc = chr_to_esc
function string:esc() -- variant 2
- return (self:gsub("(.)",chr_to_esc))
+ return (gsub(self,"(.)",chr_to_esc))
end
function string:unquote()
- return (self:gsub("^([\"\'])(.*)%1$","%2"))
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
end
-function string:quote()
+function string:quote() -- we could use format("%q")
return '"' .. self:unquote() .. '"'
end
function string:count(pattern) -- variant 3
local n = 0
- for _ in self:gmatch(pattern) do
+ for _ in gmatch(self,pattern) do
n = n + 1
end
return n
@@ -198,29 +100,25 @@ end
function string:limit(n,sentinel)
if #self > n then
sentinel = sentinel or " ..."
- return self:sub(1,(n-#sentinel)) .. sentinel
+ return sub(self,1,(n-#sentinel)) .. sentinel
else
return self
end
end
function string:strip()
- return (self:gsub("^%s*(.-)%s*$", "%1"))
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
end
---~ function string.strip(str) -- slightly different
---~ return (string.gsub(string.gsub(str,"^%s*(.-)%s*$","%1"),"%s+"," "))
---~ end
-
function string:is_empty()
- return not self:find("%S")
+ return not find(find,"%S")
end
function string:enhance(pattern,action)
local ok, n = true, 0
while ok do
ok = false
- self = self:gsub(pattern, function(...)
+ self = gsub(self,pattern, function(...)
ok, n = true, n + 1
return action(...)
end)
@@ -228,59 +126,19 @@ function string:enhance(pattern,action)
return self, n
end
---~ function string:enhance(pattern,action)
---~ local ok, n = 0, 0
---~ repeat
---~ self, ok = self:gsub(pattern, function(...)
---~ n = n + 1
---~ return action(...)
---~ end)
---~ until ok == 0
---~ return self, n
---~ end
-
---~ function string:to_hex()
---~ if self then
---~ return (self:gsub("(.)",function(c)
---~ return string.format("%02X",c:byte())
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
---~ function string:from_hex()
---~ if self then
---~ return (self:gsub("(..)",function(c)
---~ return string.char(tonumber(c,16))
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
-string.chr_to_hex = { }
-string.hex_to_chr = { }
+local chr_to_hex, hex_to_chr = { }, { }
for i=0,255 do
- local c, h = string.char(i), string.format("%02X",i)
- string.chr_to_hex[c], string.hex_to_chr[h] = h, c
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
end
---~ function string:to_hex()
---~ if self then return (self:gsub("(.)",string.chr_to_hex)) else return "" end
---~ end
-
---~ function string:from_hex()
---~ if self then return (self:gsub("(..)",string.hex_to_chr)) else return "" end
---~ end
-
function string:to_hex()
- return ((self or ""):gsub("(.)",string.chr_to_hex))
+ return (gsub(self or "","(.)",chr_to_hex))
end
function string:from_hex()
- return ((self or ""):gsub("(..)",string.hex_to_chr))
+ return (gsub(self or "","(..)",hex_to_chr))
end
if not string.characters then
@@ -294,7 +152,7 @@ if not string.characters then
end
local function nextbyte(str, index)
index = index + 1
- return (index <= #str) and index or nil, string.byte(str:sub(index,index))
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
end
function string:bytes()
return nextbyte, self, 0
@@ -302,9 +160,7 @@ if not string.characters then
end
---~ function string:padd(n,chr)
---~ return self .. self.rep(chr or " ",n-#self)
---~ end
+-- we can use format for this (neg n)
function string:rpadd(n,chr)
local m = n-#self
@@ -326,8 +182,8 @@ end
string.padd = string.rpadd
-function is_number(str)
- return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
end
--~ print(is_number("1"))
@@ -339,9 +195,9 @@ end
--~ print(is_number("+.1"))
function string:split_settings() -- no {} handling, see l-aux for lpeg variant
- if self:find("=") then
+ if find(self,"=") then
local t = { }
- for k,v in self:gmatch("(%a+)=([^%,]*)") do
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
t[k] = v
end
return t
@@ -363,24 +219,67 @@ local patterns_escapes = {
}
function string:pattesc()
- return (self:gsub(".",patterns_escapes))
+ return (gsub(self,".",patterns_escapes))
end
function string:tohash()
local t = { }
- for s in self:gmatch("([^, ]+)") do -- lpeg
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
t[s] = true
end
return t
end
+local pattern = lpeg.Ct(lpeg.C(1)^0)
--- filename : l-lpeg.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+function string:totable()
+ return pattern:match(self)
+end
-if not versions then versions = { } end versions['l-lpeg'] = 1.001
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
--~ l-lpeg.lua :
@@ -404,36 +303,40 @@ if not versions then versions = { } end versions['l-lpeg'] = 1.001
local hash = { }
function lpeg.anywhere(pattern) --slightly adapted from website
- return lpeg.P { lpeg.P(pattern) + 1 * lpeg.V(1) }
+ return P { P(pattern) + 1 * lpeg.V(1) }
end
function lpeg.startswith(pattern) --slightly adapted
- return lpeg.P(pattern)
+ return P(pattern)
end
---~ g = lpeg.splitter(" ",function(s) ... end) -- gmatch:lpeg = 3:2
-
function lpeg.splitter(pattern, action)
- return (((1-lpeg.P(pattern))^1)/action+1)^0
+ return (((1-P(pattern))^1)/action+1)^0
end
-local crlf = lpeg.P("\r\n")
-local cr = lpeg.P("\r")
-local lf = lpeg.P("\n")
-local space = lpeg.S(" \t\f\v")
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
local newline = crlf + cr + lf
local spacing = space^0 * newline
-local empty = spacing * lpeg.Cc("")
-local nonempty = lpeg.Cs((1-spacing)^1) * spacing^-1
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
local content = (empty + nonempty)^1
-local capture = lpeg.Ct(content^0)
+local capture = Ct(content^0)
function string:splitlines()
return capture:match(self)
end
+lpeg.linebyline = content -- better make a sublibrary
+
--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
@@ -441,16 +344,16 @@ end
local splitters_s, splitters_m = { }, { }
-function lpeg.splitat(separator,single)
+local function splitat(separator,single)
local splitter = (single and splitters_s[separator]) or splitters_m[separator]
if not splitter then
- separator = lpeg.P(separator)
+ separator = P(separator)
if single then
- local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
- splitter = other * (separator * lpeg.C(any^0) + "")
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
splitters_s[separator] = splitter
else
- local other = lpeg.C((1 - separator)^0)
+ local other = C((1 - separator)^0)
splitter = other * (separator * other)^0
splitters_m[separator] = splitter
end
@@ -458,26 +361,43 @@ function lpeg.splitat(separator,single)
return splitter
end
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
--- filename : l-table.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+do -- create closure to overcome 200 locals limit
-if not versions then versions = { } end versions['l-table'] = 1.001
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
table.join = table.concat
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
-local format = string.format
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
local getmetatable, setmetatable = getmetatable, setmetatable
-local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring
+local type, next, tostring, ipairs = type, next, tostring, ipairs
function table.strip(tab)
local lst = { }
for i=1,#tab do
- local s = tab[i]:gsub("^%s*(.-)%s*$","%1")
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
if s == "" then
-- skip this one
else
@@ -489,7 +409,7 @@ end
local function sortedkeys(tab)
local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
if kind == 3 then
-- no further check
@@ -516,7 +436,7 @@ end
local function sortedhashkeys(tab) -- fast one
local srt = { }
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
end
sort(srt)
@@ -526,14 +446,25 @@ end
table.sortedkeys = sortedkeys
table.sortedhashkeys = sortedhashkeys
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
function table.append(t, list)
- for _,v in pairs(list) do
+ for _,v in next, list do
insert(t,v)
end
end
function table.prepend(t, list)
- for k,v in pairs(list) do
+ for k,v in next, list do
insert(t,k,v)
end
end
@@ -542,7 +473,7 @@ function table.merge(t, ...) -- first one is target
t = t or {}
local lst = {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
t[k] = v
end
end
@@ -552,7 +483,7 @@ end
function table.merged(...)
local tmp, lst = { }, {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
tmp[k] = v
end
end
@@ -584,13 +515,14 @@ end
local function fastcopy(old) -- fast one
if old then
local new = { }
- for k,v in pairs(old) do
+ for k,v in next, old do
if type(v) == "table" then
new[k] = fastcopy(v) -- was just table.copy
else
new[k] = v
end
end
+ -- optional second arg
local mt = getmetatable(old)
if mt then
setmetatable(new,mt)
@@ -607,7 +539,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
if not tables[t] then
tables[t] = tcopy
end
- for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+ for i,v in next, t do -- brrr, what happens with sparse indexed
if type(i) == "table" then
if tables[i] then
i = tables[i]
@@ -640,7 +572,7 @@ function table.sub(t,i,j)
end
function table.replace(a,b)
- for k,v in pairs(b) do
+ for k,v in next, b do
a[k] = v
end
end
@@ -662,16 +594,18 @@ end
function table.tohash(t,value)
local h = { }
- if value == nil then value = true end
- for _, v in pairs(t) do -- no ipairs here
- h[v] = value
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
end
return h
end
function table.fromhash(t)
local h = { }
- for k, v in pairs(t) do -- no ipairs here
+ for k, v in next, t do -- no ipairs here
if v then h[#h+1] = k end
end
return h
@@ -695,24 +629,10 @@ local reserved = table.tohash { -- intercept a language flaw, no reserved words
'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
}
-local function key(k)
- if type(k) == "number" then -- or k:find("^%d+$") then
- if hexify then
- return ("[0x%04X]"):format(k)
- else
- return "["..k.."]"
- end
- elseif noquotes and not reserved[k] and k:find("^%a[%a%d%_]*$") then
- return k
- else
- return '["'..k..'"]'
- end
-end
-
local function simple_table(t)
if #t > 0 then
local n = 0
- for _,v in pairs(t) do
+ for _,v in next, t do
n = n + 1
end
if n == #t then
@@ -722,14 +642,14 @@ local function simple_table(t)
local tv = type(v)
if tv == "number" then
if hexify then
- tt[#tt+1] = ("0x%04X"):format(v)
+ tt[#tt+1] = format("0x%04X",v)
else
- tt[#tt+1] = tostring(v)
+ tt[#tt+1] = tostring(v) -- tostring not needed
end
elseif tv == "boolean" then
tt[#tt+1] = tostring(v)
elseif tv == "string" then
- tt[#tt+1] = ("%q"):format(v)
+ tt[#tt+1] = format("%q",v)
else
tt = nil
break
@@ -741,51 +661,72 @@ local function simple_table(t)
return nil
end
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
local function do_serialize(root,name,depth,level,indexed)
if level > 0 then
depth = depth .. " "
if indexed then
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
elseif name then
- handle(("%s%s={"):format(depth,key(name)))
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
else
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
end
end
if root and next(root) then
local first, last = nil, 0 -- #root cannot be trusted here
if compact then
- for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil)
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
if not first then first = k end
last = last + 1
end
end
- --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster:
local sk = sortedkeys(root)
for i=1,#sk do
local k = sk[i]
local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
local t = type(v)
if compact and first and type(k) == "number" and k >= first and k <= last then
if t == "number" then
if hexify then
- handle(("%s 0x%04X,"):format(depth,v))
+ handle(format("%s 0x%04X,",depth,v))
else
- handle(("%s %s,"):format(depth,v))
+ handle(format("%s %s,",depth,v))
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s,"):format(depth,v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
else
- handle(("%s %q,"):format(depth,v))
+ handle(format("%s %q,",depth,v))
end
elseif t == "table" then
if not next(v) then
- handle(("%s {},"):format(depth))
- elseif inline then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
local st = simple_table(v)
if st then
- handle(("%s { %s },"):format(depth,concat(st,", ")))
+ handle(format("%s { %s },",depth,concat(st,", ")))
else
do_serialize(v,k,depth,level+1,true)
end
@@ -793,39 +734,102 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1,true)
end
elseif t == "boolean" then
- handle(("%s %s,"):format(depth,tostring(v)))
+ handle(format("%s %s,",depth,tostring(v)))
elseif t == "function" then
if functions then
- handle(('%s loadstring(%q),'):format(depth,v:dump()))
+ handle(format('%s loadstring(%q),',depth,dump(v)))
else
- handle(('%s "function",'):format(depth))
+ handle(format('%s "function",',depth))
end
else
- handle(("%s %q,"):format(depth,tostring(v)))
+ handle(format("%s %q,",depth,tostring(v)))
end
elseif k == "__p__" then -- parent
if false then
- handle(("%s __p__=nil,"):format(depth))
+ handle(format("%s __p__=nil,",depth))
end
elseif t == "number" then
- if hexify then
- handle(("%s %s=0x%04X,"):format(depth,key(k),v))
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%q,"):format(depth,key(k),v))
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
end
elseif t == "table" then
if not next(v) then
- handle(("%s %s={},"):format(depth,key(k)))
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
elseif inline then
local st = simple_table(v)
if st then
- handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", ")))
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
else
do_serialize(v,k,depth,level+1)
end
@@ -833,24 +837,58 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1)
end
elseif t == "boolean" then
- handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
elseif t == "function" then
if functions then
- handle(('%s %s=loadstring(%q),'):format(depth,key(k),v:dump()))
- else
- handle(('%s %s="function",'):format(depth,key(k)))
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
end
else
- handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
- -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
end
+ --~ end
end
end
if level > 0 then
- handle(("%s},"):format(depth))
+ handle(format("%s},",depth))
end
end
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
noquotes = _noquotes
hexify = _hexify
@@ -868,7 +906,7 @@ local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
end
elseif tname == "number" then
if hexify then
- handle(("[0x%04X]={"):format(name))
+ handle(format("[0x%04X]={",name))
else
handle("[" .. name .. "]={")
end
@@ -1019,14 +1057,18 @@ function table.insert_after_value(t,value,str)
end
end
-function table.are_equal(a,b,n,m)
+local function are_equal(a,b,n,m) -- indexed
if #a == #b then
n = n or 1
m = m or #a
for i=n,m do
local ai, bi = a[i], b[i]
- if (ai==bi) or (type(ai)=="table" and type(bi)=="table" and table.are_equal(ai,bi)) then
- -- continue
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
else
return false
end
@@ -1037,9 +1079,30 @@ function table.are_equal(a,b,n,m)
end
end
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
function table.compact(t)
if t then
- for k,v in pairs(t) do
+ for k,v in next, t do
if not next(v) then
t[k] = nil
end
@@ -1068,7 +1131,7 @@ end
function table.swapped(t)
local s = { }
- for k, v in pairs(t) do
+ for k, v in next, t do
s[v] = k
end
return s
@@ -1090,14 +1153,14 @@ end
function table.hexed(t,seperator)
local tt = { }
- for i=1,#t do tt[i] = ("0x%04X"):format(t[i]) end
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
return concat(tt,seperator or " ")
end
function table.reverse_hash(h)
local r = { }
- for k,v in pairs(h) do
- r[v] = (k:gsub(" ","")):lower()
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
end
return r
end
@@ -1112,14 +1175,36 @@ 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
--- filename : l-io.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-if not versions then versions = { } end versions['l-io'] = 1.001
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
if string.find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator = "\\", ";"
@@ -1127,8 +1212,8 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-function io.loaddata(filename)
- local f = io.open(filename,'rb')
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
if f then
local data = f:read('*all')
-- garbagecollector.check(data)
@@ -1186,146 +1271,83 @@ function io.noflines(f)
return n
end
-do
-
- local sb = string.byte
-
- local nextchar = {
- [ 4] = function(f)
- return f:read(1,1,1,1)
- end,
- [ 2] = function(f)
- return f:read(1,1)
- end,
- [ 1] = function(f)
- return f:read(1)
- end,
- [-2] = function(f)
- local a, b = f:read(1,1)
- return b, a
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- return d, c, b, a
- end
- }
-
- function io.characters(f,n)
- if f then
- return nextchar[n or 1], f
- else
- return nil, nil
- end
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
end
+}
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
end
-do
-
- local sb = string.byte
-
---~ local nextbyte = {
---~ [4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(a), sb(b), sb(c), sb(d)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end,
---~ [2] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(a), sb(b)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [1] = function (f)
---~ local a = f:read(1)
---~ if a then
---~ return sb(a)
---~ else
---~ return nil
---~ end
---~ end,
---~ [-2] = function (f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(b), sb(a)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [-4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(d), sb(c), sb(b), sb(a)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end
---~ }
-
- local nextbyte = {
- [4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(a), sb(b), sb(c), sb(d)
- else
- return nil, nil, nil, nil
- end
- end,
- [2] = function(f)
- local a, b = f:read(1,1)
- if b then
- return sb(a), sb(b)
- else
- return nil, nil
- end
- end,
- [1] = function (f)
- local a = f:read(1)
- if a then
- return sb(a)
- else
- return nil
- end
- end,
- [-2] = function (f)
- local a, b = f:read(1,1)
- if b then
- return sb(b), sb(a)
- else
- return nil, nil
- end
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(d), sb(c), sb(b), sb(a)
- else
- return nil, nil, nil, nil
- end
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
end
- }
-
- function io.bytes(f,n)
- if f then
- return nextbyte[n or 1], f
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
else
return nil, nil
end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
end
+}
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
end
function io.ask(question,default,options)
@@ -1361,15 +1383,21 @@ function io.ask(question,default,options)
end
--- filename : l-number.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-number'] = 1.001
+do -- create closure to overcome 200 locals limit
-if not number then number = { } end
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+number = number or { }
-- a,b,c,d,e,f = number.toset(100101)
@@ -1377,8 +1405,6 @@ function number.toset(n)
return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
end
-local format = string.format
-
function number.toevenhex(n)
local s = format("%X",n)
if #s % 2 == 0 then
@@ -1399,72 +1425,72 @@ end
--
-- of course dedicated "(.)(.)(.)(.)" matches are even faster
-do
- local one = lpeg.C(1-lpeg.S(''))^1
+local one = lpeg.C(1-lpeg.S(''))^1
- function number.toset(n)
- return one:match(tostring(n))
- end
+function number.toset(n)
+ return one:match(tostring(n))
end
--- filename : l-set.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-if not versions then versions = { } end versions['l-set'] = 1.001
+end -- of closure
-if not set then set = { } end
+do -- create closure to overcome 200 locals limit
-do
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
- local nums = { }
- local tabs = { }
- local concat = table.concat
+set = set or { }
- set.create = table.tohash
+local nums = { }
+local tabs = { }
+local concat = table.concat
- function set.tonumber(t)
- if next(t) then
- local s = ""
- -- we could save mem by sorting, but it slows down
- for k, v in pairs(t) do
- if v then
- -- why bother about the leading space
- s = s .. " " .. k
- end
- end
- if not nums[s] then
- tabs[#tabs+1] = t
- nums[s] = #tabs
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
end
- return nums[s]
- else
- return 0
end
- end
-
- function set.totable(n)
- if n == 0 then
- return { }
- else
- return tabs[n] or { }
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
end
+ return nums[s]
+ else
+ return 0
end
+end
- function set.contains(n,s)
- if type(n) == "table" then
- return n[s]
- elseif n == 0 then
- return false
- else
- local t = tabs[n]
- return t and t[s]
- end
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
end
+end
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
end
--~ local c = set.create{'aap','noot','mies'}
@@ -1481,16 +1507,19 @@ end
--- filename : l-os.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
+do -- create closure to overcome 200 locals limit
---~ print(table.serialize(os.uname()))
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-os'] = 1.001
+local find = string.find
function os.resultof(command)
return io.popen(command,"r"):read("*all")
@@ -1503,7 +1532,7 @@ if not os.spawn then os.spawn = os.execute end
--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
if not io.fileseparator then
- if string.find(os.getenv("PATH"),";") then
+ if find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
else
io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
@@ -1541,11 +1570,10 @@ end
os.gettimeofday = os.gettimeofday or os.clock
-do
- local startuptime = os.gettimeofday()
- function os.runtime()
- return os.gettimeofday() - startuptime
- end
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
end
--~ print(os.gettimeofday()-os.time())
@@ -1554,47 +1582,92 @@ end
--~ print(os.date("%H:%M:%S",os.gettimeofday()))
--~ print(os.date("%H:%M:%S",os.time()))
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
--- filename : l-md5.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['l-md5'] = 1.001
-
-if md5 then do
+local platform
- local function convert(str,fmt)
- return (string.gsub(md5.sum(str),".",function(chr) return string.format(fmt,string.byte(chr)) end))
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
end
+ return platform
+end
- if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
- if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
- if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
-end end
+end -- of closure
+do -- create closure to overcome 200 locals limit
--- filename : l-file.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-file'] = 1.001
+-- needs a cleanup
-if not file then file = { } end
+file = file or { }
local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
function file.removesuffix(filename)
- return (filename:gsub("%.[%a%d]+$",""))
+ return (gsub(filename,"%.[%a%d]+$",""))
end
-file.stripsuffix = file.removesuffix
-
function file.addsuffix(filename, suffix)
- if not filename:find("%.[%a%d]+$") then
+ if not find(filename,"%.[%a%d]+$") then
return filename .. "." .. suffix
else
return filename
@@ -1602,23 +1675,23 @@ function file.addsuffix(filename, suffix)
end
function file.replacesuffix(filename, suffix)
- return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
end
function file.dirname(name)
- return name:match("^(.+)[/\\].-$") or ""
+ return match(name,"^(.+)[/\\].-$") or ""
end
function file.basename(name)
- return name:match("^.+[/\\](.-)$") or name
+ return match(name,"^.+[/\\](.-)$") or name
end
function file.nameonly(name)
- return ((name:match("^.+[/\\](.-)$") or name):gsub("%..*$",""))
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
end
function file.extname(name)
- return name:match("^.+%.([^/\\]-)$") or ""
+ return match(name,"^.+%.([^/\\]-)$") or ""
end
file.suffix = file.extname
@@ -1631,66 +1704,47 @@ file.suffix = file.extname
function file.join(...)
local pth = concat({...},"/")
- pth = pth:gsub("\\","/")
- local a, b = pth:match("^(.*://)(.*)$")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
+ return a .. gsub(b,"//+","/")
end
- a, b = pth:match("^(//)(.*)$")
+ a, b = match(pth,"^(//)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
+ return a .. gsub(b,"//+","/")
end
- return (pth:gsub("//+","/"))
+ return (gsub(pth,"//+","/"))
end
-function file.is_writable(name)
- local f = io.open(name, 'w')
- if f then
- f:close()
- return true
- else
- return false
- end
-end
-
-function file.is_readable(name)
- local f = io.open(name,'r')
- if f then
- f:close()
+function file.iswritable(name)
+ local a = lfs.attributes(name)
+ if a and a.permissions:sub(2,2) == "w" then
return true
else
- return false
+ name = file.dirname(name) or "."
+ if name == "" then name = "." end
+ a = lfs.attributes(name)
+ return a and a.permissions:sub(2,2) == "w"
end
end
-function file.iswritable(name)
- local a = lfs.attributes(name)
- return a and a.permissions:sub(2,2) == "w"
-end
-
function file.isreadable(name)
local a = lfs.attributes(name)
return a and a.permissions:sub(1,1) == "r"
end
---~ function file.split_path(str)
---~ if str:find(';') then
---~ return str:splitchr(";")
---~ else
---~ return str:splitchr(io.pathseparator)
---~ end
---~ end
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
-- todo: lpeg
function file.split_path(str)
local t = { }
- str = str:gsub("\\", "/")
- str = str:gsub("(%a):([;/])", "%1\001%2")
- for name in str:gmatch("([^;:]+)") do
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
if name ~= "" then
- name = name:gsub("\001",":")
- t[#t+1] = name
+ t[#t+1] = gsub(name,"\001",":")
end
end
return t
@@ -1701,15 +1755,15 @@ function file.join_path(tab)
end
function file.collapse_path(str)
- str = str:gsub("/%./","/")
+ str = gsub(str,"/%./","/")
local n, m = 1, 1
while n > 0 or m > 0 do
- str, n = str:gsub("[^/%.]+/%.%.$","")
- str, m = str:gsub("[^/%.]+/%.%./","")
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
end
- str = str:gsub("([^/])/$","%1")
- str = str:gsub("^%./","")
- str = str:gsub("/%.$","")
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
if str == "" then str = "." end
return str
end
@@ -1722,7 +1776,7 @@ end
--~ print(file.collapse_path("a/b/c/../.."))
function file.robustname(str)
- return (str:gsub("[^%a%d%/%-%.\\]+","-"))
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
end
file.readdata = io.loaddata
@@ -1752,8 +1806,6 @@ end
--~ return pattern:match(name)
--~ end
---~ file.stripsuffix = file.removesuffix
-
--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
--~ function file.basename(name)
@@ -1807,7 +1859,6 @@ end
--~ end
--~ local test = file.extname
---~ local test = file.stripsuffix
--~ local test = file.basename
--~ local test = file.dirname
--~ local test = file.addsuffix
@@ -1824,14 +1875,117 @@ end
--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+-- also rewrite previous
--- filename : l-url.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
-if not versions then versions = { } end versions['l-url'] = 1.001
-if not url then url = { } end
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEXsum(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-url'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local char, gmatch = string.char, string.gmatch
+local tonumber, type = tonumber, type
-- from the spec (on the web):
--
@@ -1843,29 +1997,28 @@ if not url then url = { } end
-- / \ / \
-- urn:example:animal:ferret:nose
-do
+url = url or { }
- local function tochar(s)
- return string.char(tonumber(s,16))
- end
+local function tochar(s)
+ return char(tonumber(s,16))
+end
- local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
+local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
- local hexdigit = lpeg.R("09","AF","af")
- local escaped = percent * lpeg.C(hexdigit * hexdigit) / tochar
+local hexdigit = lpeg.R("09","AF","af")
+local plus = lpeg.P("+")
+local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar)
- local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
- local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
- local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
- local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
- local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
+local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
+local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
+local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
+local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
+local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
- local parser = lpeg.Ct(scheme * authority * path * query * fragment)
-
- function url.split(str)
- return (type(str) == "string" and parser:match(str)) or str
- end
+local parser = lpeg.Ct(scheme * authority * path * query * fragment)
+function url.split(str)
+ return (type(str) == "string" and parser:match(str)) or str
end
function url.hashed(str)
@@ -1888,7 +2041,7 @@ end
function url.query(str)
if type(str) == "string" then
local t = { }
- for k, v in str:gmatch("([^&=]*)=([^&=]*)") do
+ for k, v in gmatch(str,"([^&=]*)=([^&=]*)") do
t[k] = v
end
return t
@@ -1903,12 +2056,12 @@ end
--~ print(url.filename("file:///etc/test.txt"))
--~ print(url.filename("/oeps.txt"))
--- from the spec on the web (sort of):
+--~ from the spec on the web (sort of):
--~
--~ function test(str)
--~ print(table.serialize(url.hashed(str)))
--~ end
----~
+--~
--~ test("%56pass%20words")
--~ test("file:///c:/oeps.txt")
--~ test("file:///c|/oeps.txt")
@@ -1930,205 +2083,210 @@ end
--~ test("zip:///oeps/oeps.zip?bla/bla.tex")
--- filename : l-dir.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-dir'] = 1.001
+do -- create closure to overcome 200 locals limit
-dir = { }
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
--- optimizing for no string.find (*) does not save time
+local type = type
+local find, gmatch = string.find, string.gmatch
-if lfs then do
+dir = dir or { }
- local attributes = lfs.attributes
- local walkdir = lfs.dir
+-- optimizing for no string.find (*) does not save time
- local function glob_pattern(path,patt,recurse,action)
- local ok, scanner
- if path == "/" then
- ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
- else
- ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
- end
- if ok and type(scanner) == "function" then
- if not path:find("/$") then path = path .. '/' end
- for name in scanner do
- local full = path .. name
- local mode = attributes(full,'mode')
- if mode == 'file' then
- if full:find(patt) then
- action(full)
- end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- glob_pattern(full,patt,recurse,action)
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
end
end
end
+end
- dir.glob_pattern = glob_pattern
+dir.glob_pattern = glob_pattern
- local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
- local pattern = Ct {
- [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
- [2] = C(((1-S("*?/"))^0 * P("/"))^0),
- [3] = C(P(1)^0)
- }
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
- local filter = Cs ( (
- P("**") / ".*" +
- P("*") / "[^/]*" +
- P("?") / "[^/]" +
- P(".") / "%%." +
- P("+") / "%%+" +
- P("-") / "%%-" +
- P(1)
- )^0 )
-
- local function glob(str,t)
- if type(str) == "table" then
- local t = t or { }
- for _, s in ipairs(str) do
- glob(s,t)
- end
- return t
- elseif lfs.isfile(str) then
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
local t = t or { }
- t[#t+1] = str
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
return t
else
- local split = pattern:match(str)
- if split then
- local t = t or { }
- local action = action or function(name) t[#t+1] = name end
- local root, path, base = split[1], split[2], split[3]
- local recurse = base:find("%*%*")
- local start = root .. path
- local result = filter:match(start .. base)
- glob_pattern(start,result,recurse,action)
- return t
- else
- return { }
- end
+ return { }
end
end
+end
- dir.glob = glob
+dir.glob = glob
- --~ list = dir.glob("**/*.tif")
- --~ list = dir.glob("/**/*.tif")
- --~ list = dir.glob("./**/*.tif")
- --~ list = dir.glob("oeps/**/*.tif")
- --~ list = dir.glob("/oeps/**/*.tif")
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
- local function globfiles(path,recurse,func,files) -- func == pattern or function
- if type(func) == "string" then
- local s = func -- alas, we need this indirect way
- func = function(name) return name:find(s) end
- end
- files = files or { }
- for name in walkdir(path) do
- if name:find("^%.") then
- --- skip
- else
- local mode = attributes(name,'mode')
- if mode == "directory" then
- if recurse then
- globfiles(path .. "/" .. name,recurse,func,files)
- end
- elseif mode == "file" then
- if func then
- if func(name) then
- files[#files+1] = path .. "/" .. name
- end
- else
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
files[#files+1] = path .. "/" .. name
end
+ else
+ files[#files+1] = path .. "/" .. name
end
end
end
- return files
end
+ return files
+end
- dir.globfiles = globfiles
+dir.globfiles = globfiles
- -- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
- -- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
- -- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
- -- t = dir.glob("f:/minimal/tex/**/*")
- -- print(dir.ls("f:/minimal/tex/**/*"))
- -- print(dir.ls("*.tex"))
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
- function dir.ls(pattern)
- return table.concat(glob(pattern),"\n")
- end
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
- --~ mkdirs("temp")
- --~ mkdirs("a/b/c")
- --~ mkdirs(".","/a/b/c")
- --~ mkdirs("a","b","c")
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
- local make_indeed = true -- false
+local make_indeed = true -- false
- if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- local first, middle, last
- local drive = false
- first, middle, last = str:match("^(//)(//*)(.*)$")
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
if first then
- -- empty network path == local path
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
else
- first, last = str:match("^(//)/*(.-)$")
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
if first then
- middle, last = str:match("([^/]+)/+(.-)$")
- if middle then
- pth = "//" .. middle
- else
- pth = "//" .. last
- last = ""
- end
+ pth, drive = first .. middle, true
else
- first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
- if first then
- pth, drive = first .. middle, true
- else
- middle, last = str:match("^(/*)(.-)$")
- if not middle then
- last = str
- end
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
end
end
end
- for s in last:gmatch("[^/]+") do
- if pth == "" then
- pth = s
- elseif drive then
- pth, drive = pth .. s, false
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -2142,79 +2300,79 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- local first, nothing, last = str:match("^(//)(//*)(.*)$")
- if first then
- first = lfs.currentdir() .. "/"
- first = first:gsub("\\","/")
- end
- if not first then
- first, last = str:match("^(//)/*(.*)$")
- end
- if not first then
- first, last = str:match("^([a-zA-Z]:)(.*)$")
- if first and not last:find("^/") then
- local d = lfs.currentdir()
- if lfs.chdir(first) then
- first = lfs.currentdir()
- first = first:gsub("\\","/")
- end
- lfs.chdir(d)
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
end
+ lfs.chdir(d)
end
- if not first then
- first, last = lfs.currentdir(), str
- first = first:gsub("\\","/")
- end
- last = last:gsub("//","/")
- last = last:gsub("/%./","/")
- last = last:gsub("^/*","")
- first = first:gsub("/*$","")
- if last == "" then
- return first
- else
- return first .. "/" .. last
- end
end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
- else
+else
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- str = str:gsub("/+","/")
- if str:find("^/") then
- pth = "/"
- for s in str:gmatch("[^/]+") do
- local first = (pth == "/")
- if first then
- pth = pth .. s
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not first and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
- end
- else
- pth = "."
- for s in str:gmatch("[^/]+") do
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
pth = pth .. "/" .. s
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -2224,30 +2382,35 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- if not str:find("^/") then
- str = lfs.currentdir() .. "/" .. str
- end
- str = str:gsub("//","/")
- str = str:gsub("/%./","/")
- return str
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
end
-
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
end
- dir.makedirs = dir.mkdirs
+end
-end end
+dir.makedirs = dir.mkdirs
--- filename : l-boolean.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-boolean'] = 1.001
-if not boolean then boolean = { } end
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
function boolean.tonumber(b)
if b then return 1 else return 0 end
@@ -2294,24 +2457,24 @@ function boolean.falsetrue()
end
--- filename : l-unicode.lua
--- comment : split off from luat-inp
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-unicode'] = 1.001
-if not unicode then unicode = { } end
+do -- create closure to overcome 200 locals limit
-local concat, utfchar, utfgsub = table.concat, unicode.utf8.char, unicode.utf8.gsub
-local char, byte = string.char, string.byte
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not garbagecollector then
- garbagecollector = {
- push = function() collectgarbage("stop") end,
- pop = function() collectgarbage("restart") end,
- }
-end
+utf = utf or unicode.utf8
+
+local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
+local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
+
+unicode = unicode or { }
-- 0 EF BB BF UTF-8
-- 1 FF FE UTF-16-little-endian
@@ -2332,17 +2495,17 @@ function unicode.utftype(f) -- \000 fails !
if not str then
f:seek('set')
return 0
- elseif str:find("^%z%z\254\255") then
+ elseif find(str,"^%z%z\254\255") then
return 4
- elseif str:find("^\255\254%z%z") then
+ elseif find(str,"^\255\254%z%z") then
return 3
- elseif str:find("^\254\255") then
+ elseif find(str,"^\254\255") then
f:seek('set',2)
return 2
- elseif str:find("^\255\254") then
+ elseif find(str,"^\255\254") then
f:seek('set',2)
return 1
- elseif str:find("^\239\187\191") then
+ elseif find(str,"^\239\187\191") then
f:seek('set',3)
return 0
else
@@ -2352,18 +2515,17 @@ function unicode.utftype(f) -- \000 fails !
end
function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
---~ garbagecollector.push()
local result, tmp, n, m, p = { }, { }, 0, 0, 0
-- lf | cr | crlf / (cr:13, lf:10)
local function doit()
if n == 10 then
if p ~= 13 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
tmp = { }
p = 0
end
elseif n == 13 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
tmp = { }
p = n
else
@@ -2371,7 +2533,7 @@ function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
p = 0
end
end
- for l,r in str:bytepairs() do
+ for l,r in bytepairs(str) do
if r then
if endian then
n = l*256 + r
@@ -2390,26 +2552,24 @@ function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
end
end
if #tmp > 0 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
end
---~ garbagecollector.pop()
return result
end
function unicode.utf32_to_utf8(str, endian)
---~ garbagecollector.push()
local result = { }
local tmp, n, m, p = { }, 0, -1, 0
-- lf | cr | crlf / (cr:13, lf:10)
local function doit()
if n == 10 then
if p ~= 13 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
tmp = { }
p = 0
end
elseif n == 13 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
tmp = { }
p = n
else
@@ -2417,7 +2577,7 @@ function unicode.utf32_to_utf8(str, endian)
p = 0
end
end
- for a,b in str:bytepairs() do
+ for a,b in bytepairs(str) do
if a and b then
if m < 0 then
if endian then
@@ -2439,48 +2599,55 @@ function unicode.utf32_to_utf8(str, endian)
end
end
if #tmp > 0 then
- result[#result+1] = concat(tmp,"")
+ result[#result+1] = concat(tmp)
end
---~ garbagecollector.pop()
return result
end
+local function little(c)
+ local b = byte(c) -- b = c:byte()
+ if b < 0x10000 then
+ return char(b%256,b/256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1%256,b1/256,b2%256,b2/256)
+ end
+end
+
+local function big(c)
+ local b = byte(c)
+ if b < 0x10000 then
+ return char(b/256,b%256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1/256,b1%256,b2/256,b2%256)
+ end
+end
+
function unicode.utf8_to_utf16(str,littleendian)
if littleendian then
- return char(255,254) .. utfgsub(str,".",function(c)
- local b = byte(c)
- if b < 0x10000 then
- return char(b%256,b/256)
- else
- b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1%256,b1/256,b2%256,b2/256)
- end
- end)
+ return char(255,254) .. utfgsub(str,".",little)
else
- return char(254,255) .. utfgsub(str,".",function(c)
- local b = byte(c)
- if b < 0x10000 then
- return char(b/256,b%256)
- else
- b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1/256,b1%256,b2/256,b2%256)
- end
- end)
+ return char(254,255) .. utfgsub(str,".",big)
end
end
--- filename : l-math.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-math'] = 1.001
+do -- create closure to overcome 200 locals limit
-local floor = math.floor
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
if not math.round then
function math.round(x)
@@ -2500,14 +2667,34 @@ if not math.mod then
end
end
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
--- filename : l-utils.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-utils'] = 1.001
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
if not utils then utils = { } end
if not utils.merger then utils.merger = { } end
@@ -2572,24 +2759,52 @@ function utils.merger._self_swap_(data,code)
end
end
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
function utils.merger._self_libs_(libs,list)
- local result, f = { }, nil
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
if type(libs) == 'string' then libs = { libs } end
if type(list) == 'string' then list = { list } end
+ local foundpath = nil
for _, lib in ipairs(libs) do
for _, pth in ipairs(list) do
- local name = string.gsub(pth .. "/" .. lib,"\\","/")
- f = io.open(name)
- if f then
- utils.report("merging library %s",name)
- result[#result+1] = f:read("*all")
- f:close()
- list = { pth } -- speed up the search
- break
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
else
- utils.report("no library %s",name)
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
end
end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
end
return table.concat(result, "\n\n")
end
@@ -2643,15 +2858,257 @@ end
-if not modules then modules = { } end modules ['luat-lib'] = {
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
version = 1.001,
+ comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
+ end
+ end
+ grandtotal = grandtotal + count
+ functions = functions + 1
+ end
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+end
+
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
+ end
+end
+
+function debugger.enable()
+ debug.sethook(hook,"c")
+end
+
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
+end
+
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
+ end
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
}
--- most code already moved to the l-*.lua and other luat-*.lua files
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
@@ -2659,15 +3116,27 @@ function os.setlocale()
-- no way you can mess with it
end
+-- dirty tricks
+
if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
end
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
environment = environment or { }
environment.arguments = { }
environment.files = { }
environment.sortedflags = nil
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
function environment.initialize_arguments(arg)
local arguments, files = { }, { }
environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
@@ -2689,24 +3158,20 @@ function environment.initialize_arguments(arg)
environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
end
-function environment.showarguments()
- for k,v in pairs(environment.arguments) do
- print(k .. " : " .. tostring(v))
- end
- if #environment.files > 0 then
- print("files : " .. table.concat(environment.files, " "))
- end
-end
-
function environment.setargument(name,value)
environment.arguments[name] = value
end
-function environment.argument(name) -- todo: default (plus typecheck on default)
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
local arguments, sortedflags = environment.arguments, environment.sortedflags
if arguments[name] then
return arguments[name]
- else
+ elseif partial then
if not sortedflags then
sortedflags = { }
for _,v in pairs(table.sortedkeys(arguments)) do
@@ -2714,6 +3179,7 @@ function environment.argument(name) -- todo: default (plus typecheck on default)
end
environment.sortedflags = sortedflags
end
+ -- example of potential clash: ^mode ^modefile
for _,v in ipairs(sortedflags) do
if name:find(v) then
return arguments[v:sub(2,#v)]
@@ -2737,43 +3203,17 @@ function environment.split_arguments(separator) -- rather special, cut-off befor
return before, after
end
---~ function environment.reconstruct_commandline(arg)
---~ if not arg then arg = environment.original_arguments end
---~ local result = { }
---~ for _,a in ipairs(arg) do -- ipairs 1 .. #n
---~ local kk, vv = a:match("^(%-+.-)=(.+)$")
---~ if kk and vv then
---~ if vv:find(" ") then
---~ vv = vv:unquote()
---~ vv = vv:gsub('"','\\"')
---~ result[#result+1] = kk .. "=" .. vv:quote()
---~ else
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a
---~ end
---~ elseif a:find(" ") then
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a:quote()
---~ else
---~ result[#result+1] = a
---~ end
---~ end
---~ return table.join(result," ")
---~ end
-
function environment.reconstruct_commandline(arg,noquote)
- if not arg then arg = environment.original_arguments end
+ arg = arg or environment.original_arguments
if noquote and #arg == 1 then
local a = arg[1]
- a = input.resolve(a)
+ a = resolvers.resolve(a)
a = a:unquote()
return a
- elseif #arg == 1 then
+ elseif next(arg) then
local result = { }
for _,a in ipairs(arg) do -- ipairs 1 .. #n
- a = input.resolve(a)
+ a = resolvers.resolve(a)
a = a:unquote()
a = a:gsub('"','\\"') -- tricky
if a:find(" ") then
@@ -2783,6 +3223,8 @@ function environment.reconstruct_commandline(arg,noquote)
end
end
return table.join(result," ")
+ else
+ return ""
end
end
@@ -2818,8 +3260,563 @@ if arg then
end
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
-if not modules then modules = { } end modules ['luat-inp'] = {
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
version = 1.001,
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -2827,12 +3824,20 @@ if not modules then modules = { } end modules ['luat-inp'] = {
comment = "companion to luat-lib.tex",
}
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
-- TODO: os.getenv -> os.env[]
-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
-- TODO: check escaping in find etc, too much, too slow
-- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
+-- additional functionality becomes available. We will split thislogs.report("fileio",
-- module in components once we're done with prototyping. This is the
-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
-- something in this module one can best check with Taco or Hans first; there
@@ -2846,82 +3851,205 @@ if not modules then modules = { } end modules ['luat-inp'] = {
-- Beware, loading and saving is overloaded in luat-tmp!
-if not input then input = { } end
-if not input.suffixes then input.suffixes = { } end
-if not input.formats then input.formats = { } end
-if not input.aux then input.aux = { } end
-
-if not input.suffixmap then input.suffixmap = { } end
-
-if not input.locators then input.locators = { } end -- locate databases
-if not input.hashers then input.hashers = { } end -- load databases
-if not input.generators then input.generators = { } end -- generate databases
-if not input.filters then input.filters = { } end -- conversion filters
-
-local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
-
-input.locators.notfound = { nil }
-input.hashers.notfound = { nil }
-input.generators.notfound = { nil }
-
-input.cacheversion = '1.0.1'
-input.banner = nil
-input.verbose = false
-input.debug = false
-input.cnfname = 'texmf.cnf'
-input.luaname = 'texmfcnf.lua'
-input.lsrname = 'ls-R'
-input.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
-
---~ input.luasuffix = 'tma'
---~ input.lucsuffix = 'tmc'
-
--- for the moment we have .local but this will disappear
-input.cnfdefault = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- chances are low that the cnf file is in the bin path
-input.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- we use a cleaned up list / format=any is a wildcard, as is *name
-
-input.formats['afm'] = 'AFMFONTS' input.suffixes['afm'] = { 'afm' }
-input.formats['enc'] = 'ENCFONTS' input.suffixes['enc'] = { 'enc' }
-input.formats['fmt'] = 'TEXFORMATS' input.suffixes['fmt'] = { 'fmt' }
-input.formats['map'] = 'TEXFONTMAPS' input.suffixes['map'] = { 'map' }
-input.formats['mp'] = 'MPINPUTS' input.suffixes['mp'] = { 'mp' }
-input.formats['ocp'] = 'OCPINPUTS' input.suffixes['ocp'] = { 'ocp' }
-input.formats['ofm'] = 'OFMFONTS' input.suffixes['ofm'] = { 'ofm', 'tfm' }
-input.formats['otf'] = 'OPENTYPEFONTS' input.suffixes['otf'] = { 'otf' } -- 'ttf'
-input.formats['opl'] = 'OPLFONTS' input.suffixes['opl'] = { 'opl' }
-input.formats['otp'] = 'OTPINPUTS' input.suffixes['otp'] = { 'otp' }
-input.formats['ovf'] = 'OVFFONTS' input.suffixes['ovf'] = { 'ovf', 'vf' }
-input.formats['ovp'] = 'OVPFONTS' input.suffixes['ovp'] = { 'ovp' }
-input.formats['tex'] = 'TEXINPUTS' input.suffixes['tex'] = { 'tex' }
-input.formats['tfm'] = 'TFMFONTS' input.suffixes['tfm'] = { 'tfm' }
-input.formats['ttf'] = 'TTFONTS' input.suffixes['ttf'] = { 'ttf', 'ttc' }
-input.formats['pfb'] = 'T1FONTS' input.suffixes['pfb'] = { 'pfb', 'pfa' }
-input.formats['vf'] = 'VFFONTS' input.suffixes['vf'] = { 'vf' }
-
-input.formats['fea'] = 'FONTFEATURES' input.suffixes['fea'] = { 'fea' }
-input.formats['cid'] = 'FONTCIDMAPS' input.suffixes['cid'] = { 'cid', 'cidmap' }
-
-input.formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
-input.suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
-
-input.formats ['lua'] = 'LUAINPUTS' -- new
-input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
-- here we catch a few new thingies (todo: add these paths to context.tmf)
--
-- FONTFEATURES = .;$TEXMF/fonts/fea//
-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
-function input.checkconfigdata() -- not yet ok, no time for debugging now
- local instance = input.instance
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
local function fix(varname,default)
local proname = varname .. "." .. instance.progname or "crap"
- local p = instance.environment[proname]
- local v = instance.environment[varname]
+ local p, v = ie[proname], ie[varname]
if not ((p and p ~= "") or (v and v ~= "")) then
instance.variables[varname] = default -- or environment?
end
@@ -2937,207 +4065,198 @@ function input.checkconfigdata() -- not yet ok, no time for debugging now
fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
end
--- backward compatible ones
-
-input.alternatives = { }
-
-input.alternatives['map files'] = 'map'
-input.alternatives['enc files'] = 'enc'
-input.alternatives['cid files'] = 'cid'
-input.alternatives['fea files'] = 'fea'
-input.alternatives['opentype fonts'] = 'otf'
-input.alternatives['truetype fonts'] = 'ttf'
-input.alternatives['truetype collections'] = 'ttc'
-input.alternatives['type1 fonts'] = 'pfb'
-
--- obscure ones
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
-input.formats ['misc fonts'] = ''
-input.suffixes['misc fonts'] = { }
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
-input.formats ['sfd'] = 'SFDFONTS'
-input.suffixes ['sfd'] = { 'sfd' }
-input.alternatives['subfont definition files'] = 'sfd'
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
--- In practice we will work within one tds tree, but i want to keep
--- the option open to build tools that look at multiple trees, which is
--- why we keep the tree specific data in a table. We used to pass the
--- instance but for practical pusposes we now avoid this and use a
--- instance variable.
-
-function input.newinstance()
-
- local instance = { }
-
- instance.rootpath = ''
- instance.treepath = ''
- instance.progname = 'context'
- instance.engine = 'luatex'
- instance.format = ''
- instance.environment = { }
- instance.variables = { }
- instance.expansions = { }
- instance.files = { }
- instance.remap = { }
- instance.configuration = { }
- instance.setup = { }
- instance.order = { }
- instance.found = { }
- instance.foundintrees = { }
- instance.kpsevars = { }
- instance.hashes = { }
- instance.cnffiles = { }
- instance.luafiles = { }
- instance.lists = { }
- instance.remember = true
- instance.diskcache = true
- instance.renewcache = false
- instance.scandisk = true
- instance.cachepath = nil
- instance.loaderror = false
- instance.smallcache = false
- instance.sortdata = false
- instance.savelists = true
- instance.cleanuppaths = true
- instance.allresults = false
- instance.pattern = nil -- lists
- instance.kpseonly = false -- lists
- instance.loadtime = 0
- instance.starttime = 0
- instance.stoptime = 0
- instance.validfile = function(path,name) return true end
- instance.data = { } -- only for loading
- instance.force_suffixes = true
- instance.dummy_path_expr = "^!*unset/*$"
- instance.fakepaths = { }
- instance.lsrmode = false
-
- -- store once, freeze and faster (once reset we can best use instance.environment)
-
- for k,v in pairs(os.env) do
- instance.environment[k] = input.bare_variable(v)
- end
-
- -- cross referencing, delayed because we can add suffixes
-
- for k, v in pairs(input.suffixes) do
- for _, vv in pairs(v) do
- if vv then
- input.suffixmap[vv] = k
- end
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
end
+ ie[key] = value
end
-
- return instance
-
+ return value or ""
end
-input.instance = input.instance or nil
-
-function input.reset()
- input.instance = input.newinstance()
- return input.instance
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
end
-function input.reset_hashes()
- input.instance.lists = { }
- input.instance.found = { }
-end
+--
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
- return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
end
-function input.settrace(n)
- input.trace = tonumber(n or 0)
- if input.trace > 0 then
- input.verbose = true
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
end
-input.log = (texio and texio.write_nl) or print
-
-function input.report(...)
- if input.verbose then
- input.log("<<"..format(...)..">>")
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
end
+ return ""
end
-function input.report(...)
- if input.trace > 0 then -- extra test
- input.log("<<"..format(...)..">>")
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
end
end
-input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
-
--- These functions can be used to test the performance, especially
--- loading the database files.
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
-do
- local clock = os.gettimeofday or os.clock
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
- function input.starttiming(instance)
- if instance then
- instance.starttime = clock()
- if not instance.loadtime then
- instance.loadtime = 0
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
end
end
+ return "{" .. concat(t,",") .. "}"
end
-
- function input.stoptiming(instance, report)
- if instance then
- local starttime = instance.starttime
- if starttime then
- local stoptime = clock()
- local loadtime = stoptime - starttime
- instance.stoptime = stoptime
- instance.loadtime = instance.loadtime + loadtime
- if report then
- input.report("load time %0.3f",loadtime)
- end
- return loadtime
- end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
end
- return 0
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
end
-
-end
-
-function input.elapsedtime(instance)
- return format("%0.3f",(instance and instance.loadtime) or 0)
-end
-
-function input.report_loadtime(instance)
- if instance then
- input.report('total load time %s', input.elapsedtime(instance))
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
end
+ return t
end
-input.loadtime = input.elapsedtime
-
-function input.env(key)
- return input.instance.environment[key] or input.osenv(key)
-end
-
-function input.osenv(key)
- local ie = input.instance.environment
- local value = ie[key]
- if value == nil then
- -- local e = os.getenv(key)
- local e = os.env[key]
- if e == nil then
- -- value = "" -- false
- else
- value = input.bare_variable(e)
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
end
- ie[key] = value
end
- return value or ""
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
end
-- we follow a rather traditional approach:
@@ -3148,20 +4267,20 @@ end
-- also we now follow the stupid route: if not set then just assume *one*
-- cnf file under texmf (i.e. distribution)
-input.ownpath = input.ownpath or nil
-input.ownbin = input.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
-input.autoselfdir = true -- false may be handy for debugging
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
-function input.getownpath()
- if not input.ownpath then
- if input.autoselfdir and os.selfdir then
- input.ownpath = os.selfdir
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
else
- local binary = input.ownbin
+ local binary = resolvers.ownbin
if os.platform == "windows" then
binary = file.replacesuffix(binary,"exe")
end
- for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
local b = file.join(p,binary)
if lfs.isfile(b) then
-- we assume that after changing to the path the currentdir function
@@ -3171,162 +4290,91 @@ function input.getownpath()
local olddir = lfs.currentdir()
if lfs.chdir(p) then
local pp = lfs.currentdir()
- if input.verbose and p ~= pp then
- input.report("following symlink %s to %s",p,pp)
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
end
- input.ownpath = pp
+ resolvers.ownpath = pp
lfs.chdir(olddir)
else
- if input.verbose then
- input.report("unable to check path %s",p)
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
end
- input.ownpath = p
+ resolvers.ownpath = p
end
break
end
end
end
- if not input.ownpath then input.ownpath = '.' end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
end
- return input.ownpath
+ return resolvers.ownpath
end
-function input.identify_own()
- local instance = input.instance
- local ownpath = input.getownpath() or lfs.currentdir()
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
local ie = instance.environment
if ownpath then
- if input.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
- if input.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
- if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
else
- input.verbose = true
- input.report("error: unable to locate ownpath")
+ logs.report("fileio","error: unable to locate ownpath")
os.exit()
end
- if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
- if input.env('TEXOS') == "" then os.env['TEXOS'] = input.env('SELFAUTODIR') end
- if input.env('TEXROOT') == "" then os.env['TEXROOT'] = input.env('SELFAUTOPARENT') end
- if input.verbose then
- for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
- input.report("variable %s set to %s",v,input.env(v) or "unknown")
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
end
end
- function input.identify_own() end
+ identify_own = function() end
end
-function input.identify_cnf()
- local instance = input.instance
+function resolvers.identify_cnf()
if #instance.cnffiles == 0 then
-- fallback
- input.identify_own()
+ identify_own()
-- the real search
- input.expand_variables()
- local t = input.split_path(input.env('TEXMFCNF'))
- t = input.aux.expanded_path(t)
- input.aux.expand_vars(t) -- redundant
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
local function locate(filename,list)
- for _,v in ipairs(t) do
- local texmfcnf = input.normalize_name(file.join(v,filename))
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
if lfs.isfile(texmfcnf) then
- table.insert(list,texmfcnf)
- end
- end
- end
- locate(input.luaname,instance.luafiles)
- locate(input.cnfname,instance.cnffiles)
- end
-end
-
-function input.load_cnf()
- local instance = input.instance
- local function loadoldconfigdata()
- for _, fname in ipairs(instance.cnffiles) do
- input.aux.load_cnf(fname)
- end
- end
- -- instance.cnffiles contain complete names now !
- if #instance.cnffiles == 0 then
- input.report("no cnf files found (TEXMFCNF may not be set/known)")
- else
- instance.rootpath = instance.cnffiles[1]
- for k,fname in ipairs(instance.cnffiles) do
- instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- if instance.lsrmode then
- loadoldconfigdata()
- elseif instance.diskcache and not instance.renewcache then
- input.loadoldconfig(instance.cnffiles)
- if instance.loaderror then
- loadoldconfigdata()
- input.saveoldconfig()
- end
- else
- loadoldconfigdata()
- if instance.renewcache then
- input.saveoldconfig()
- end
- end
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.load_lua()
- local instance = input.instance
- if #instance.luafiles == 0 then
- -- yet harmless
- else
- instance.rootpath = instance.luafiles[1]
- for k,fname in ipairs(instance.luafiles) do
- instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- input.loadnewconfig()
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
- local instance = input.instance
- for _,c in ipairs(instance.order) do
- for k,v in pairs(c) do
- if not instance.variables[k] then
- if instance.environment[k] then
- instance.variables[k] = instance.environment[k]
- else
- instance.kpsevars[k] = true
- instance.variables[k] = input.bare_variable(v)
+ list[#list+1] = texmfcnf
end
end
end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
end
end
-function input.aux.load_cnf(fname)
- local instance = input.instance
- fname = input.clean_path(fname)
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
local lname = file.replacesuffix(fname,'lua')
local f = io.open(lname)
if f then -- this will go
f:close()
local dname = file.dirname(fname)
if not instance.configuration[dname] then
- input.aux.load_configuration(dname,lname)
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
instance.order[#instance.order+1] = instance.configuration[dname]
end
else
f = io.open(fname)
if f then
- input.report("loading %s", fname)
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
local line, data, n, k, v
local dname = file.dirname(fname)
if not instance.configuration[dname] then
@@ -3338,17 +4386,19 @@ function input.aux.load_cnf(fname)
local line, n = f:read(), 0
if line then
while true do -- join lines
- line, n = line:gsub("\\%s*$", "")
+ line, n = gsub(line,"\\%s*$", "")
if n > 0 then
line = line .. f:read()
else
break
end
end
- if not line:find("^[%%#]") then
- local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$")
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
if k and v and not data[k] then
- data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME")
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
instance.kpsevars[k] = true
end
end
@@ -3357,53 +4407,119 @@ function input.aux.load_cnf(fname)
end
end
f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
else
- input.report("skipping %s", fname)
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
end
+ collapse_cnf_data()
end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
end
-- database loading
-function input.load_hash()
- local instance = input.instance
- input.locatelists()
- if instance.lsrmode then
- input.loadlists()
- elseif instance.diskcache and not instance.renewcache then
- input.loadfiles()
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
if instance.loaderror then
- input.loadlists()
- input.savefiles()
+ resolvers.loadlists()
+ resolvers.savefiles()
end
else
- input.loadlists()
+ resolvers.loadlists()
if instance.renewcache then
- input.savefiles()
+ resolvers.savefiles()
end
end
end
-function input.aux.append_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash append: %s",tag)
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
end
- table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
end
-function input.aux.prepend_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash prepend: %s",tag)
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
end
- table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
end
-function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
- local instance = input.instance
--- local t = input.expanded_path_list('TEXMF') -- full expansion
- local t = input.split_path(input.env('TEXMF'))
- table.insert(t,1,specification)
- local newspec = table.join(t,";")
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
if instance.environment["TEXMF"] then
instance.environment["TEXMF"] = newspec
elseif instance.variables["TEXMF"] then
@@ -3411,182 +4527,142 @@ function input.aux.extend_texmf_var(specification) -- crap, we could better prep
else
-- weird
end
- input.expand_variables()
- input.reset_hashes()
+ resolvers.expand_variables()
+ reset_hashes()
end
-- locators
-function input.locatelists()
- local instance = input.instance
- for _, path in pairs(input.clean_path_list('TEXMF')) do
- input.report("locating list of %s",path)
- input.locatedatabase(input.normalize_name(path))
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
end
end
-function input.locatedatabase(specification)
- return input.methodhandler('locators', specification)
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
end
-function input.locators.tex(specification)
+function resolvers.locators.tex(specification)
if specification and specification ~= '' and lfs.isdir(specification) then
- if input.trace > 0 then
- input.logger('! tex locator found: %s',specification)
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
end
- input.aux.append_hash('file',specification,filename)
- elseif input.trace > 0 then
- input.logger('? tex locator not found: %s',specification)
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
end
end
-- hashers
-function input.hashdatabase(tag,name)
- return input.methodhandler('hashers',tag,name)
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
end
-function input.loadfiles()
- local instance = input.instance
+function resolvers.loadfiles()
instance.loaderror = false
instance.files = { }
if not instance.renewcache then
for _, hash in ipairs(instance.hashes) do
- input.hashdatabase(hash.tag,hash.name)
+ resolvers.hashdatabase(hash.tag,hash.name)
if instance.loaderror then break end
end
end
end
-function input.hashers.tex(tag,name)
- input.aux.load_files(tag)
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
end
-- generators:
-function input.loadlists()
- for _, hash in ipairs(input.instance.hashes) do
- input.generatedatabase(hash.tag)
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
end
end
-function input.generatedatabase(specification)
- return input.methodhandler('generators', specification)
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
end
-local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-function input.generators.tex(specification)
- local instance = input.instance
+function resolvers.generators.tex(specification)
local tag = specification
- if not instance.lsrmode and lfs.dir then
- input.report("scanning path %s",specification)
- instance.files[tag] = { }
- local files = instance.files[tag]
- local n, m, r = 0, 0, 0
- local spec = specification .. '/'
- local attributes = lfs.attributes
- local directory = lfs.dir
- local small = instance.smallcache
- local function action(path)
- local mode, full
- if path then
- full = spec .. path .. '/'
- else
- full = spec
- end
- for name in directory(full) do
- if name:find("^%.") then
- -- skip
- -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
- elseif weird:match(name) then
- -- texio.write_nl("skipping " .. name)
- -- skip
- else
- mode = attributes(full..name,'mode')
- if mode == 'directory' then
- m = m + 1
- if path then
- action(path..'/'..name)
- else
- action(name)
- end
- elseif path and mode == 'file' then
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
n = n + 1
local f = files[name]
if f then
- if not small then
- if type(f) == 'string' then
- files[name] = { f, path }
- else
- f[#f+1] = path
- end
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
end
- else
+ else -- probably unique anyway
files[name] = path
- local lower = name:lower()
+ local lower = lower(name)
if name ~= lower then
files["remap:"..lower] = name
r = r + 1
end
end
end
- end
- end
- end
- action()
- input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
- else
- local fullname = file.join(specification,input.lsrname)
- local path = '.'
- local f = io.open(fullname)
- if f then
- instance.files[tag] = { }
- local files = instance.files[tag]
- local small = instance.smallcache
- input.report("loading lsr file %s",fullname)
- -- for line in f:lines() do -- much slower then the next one
- for line in (f:read("*a")):gmatch("(.-)\n") do
- if line:find("^[%a%d]") then
- local fl = files[line]
- if fl then
- if not small then
- if type(fl) == 'string' then
- files[line] = { fl, path } -- table
- else
- fl[#fl+1] = path
- end
- end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
else
- files[line] = path -- string
- local lower = line:lower()
- if line ~= lower then
- files["remap:"..lower] = line
- end
+ action(name)
end
- else
- path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
end
end
- f:close()
end
end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
end
-- savers, todo
-function input.savefiles()
- input.aux.save_data('files', function(k,v)
- return input.instance.validfile(k,v) -- path, name
- end)
+function resolvers.savefiles()
+ resolvers.save_data('files')
end
-- A config (optionally) has the paths split in tables. Internally
-- we join them and split them after the expansion has taken place. This
-- is more convenient.
-function input.splitconfig()
- for i,c in ipairs(input.instance) do
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
for k,v in pairs(c) do
if type(v) == 'string' then
local t = file.split_path(v)
@@ -3598,23 +4674,23 @@ function input.splitconfig()
end
end
-function input.joinconfig()
- for i,c in ipairs(input.instance.order) do
- for k,v in pairs(c) do
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
if type(v) == 'table' then
c[k] = file.join_path(v)
end
end
end
end
-function input.split_path(str)
+function resolvers.split_path(str)
if type(str) == 'table' then
return str
else
return file.split_path(str)
end
end
-function input.join_path(str)
+function resolvers.join_path(str)
if type(str) == 'table' then
return file.join_path(str)
else
@@ -3622,11 +4698,11 @@ function input.join_path(str)
end
end
-function input.splitexpansions()
- local ie = input.instance.expansions
- for k,v in pairs(ie) do
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
local t, h = { }, { }
- for _,vv in pairs(file.split_path(v)) do
+ for _,vv in ipairs(file.split_path(v)) do
if vv ~= "" and not h[vv] then
t[#t+1] = vv
h[vv] = true
@@ -3642,27 +4718,27 @@ end
-- end of split/join code
-function input.saveoldconfig()
- input.splitconfig()
- input.aux.save_data('configuration', nil)
- input.joinconfig()
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
end
-input.configbanner = [[
+resolvers.configbanner = [[
-- This is a Luatex configuration file created by 'luatools.lua' or
-- 'luatex.exe' directly. For comment, suggestions and questions you can
-- contact the ConTeXt Development Team. This configuration file is
-- not copyrighted. [HH & TH]
]]
-function input.serialize(files)
+function resolvers.serialize(files)
-- This version is somewhat optimized for the kind of
-- tables that we deal with, so it's much faster than
-- the generic serializer. This makes sense because
-- luatools and mtxtools are called frequently. Okay,
-- we pay a small price for properly tabbed tables.
local t = { }
- local function dump(k,v,m)
+ local function dump(k,v,m) -- could be moved inline
if type(v) == 'string' then
return m .. "['" .. k .. "']='" .. v .. "',"
elseif #v == 1 then
@@ -3672,12 +4748,12 @@ function input.serialize(files)
end
end
t[#t+1] = "return {"
- if input.instance.sortdata then
- for _, k in pairs(sortedkeys(files)) do
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
local fk = files[k]
if type(fk) == 'table' then
t[#t+1] = "\t['" .. k .. "']={"
- for _, kk in pairs(sortedkeys(fk)) do
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
t[#t+1] = dump(kk,fk[kk],"\t\t")
end
t[#t+1] = "\t},"
@@ -3686,10 +4762,10 @@ function input.serialize(files)
end
end
else
- for k, v in pairs(files) do
+ for k, v in next, files do
if type(v) == 'table' then
t[#t+1] = "\t['" .. k .. "']={"
- for kk,vv in pairs(v) do
+ for kk,vv in next, v do
t[#t+1] = dump(kk,vv,"\t\t")
end
t[#t+1] = "\t},"
@@ -3702,62 +4778,67 @@ function input.serialize(files)
return concat(t,"\n")
end
-if not texmf then texmf = {} end -- no longer needed, at least not here
-
-function input.aux.save_data(dataname, check, makename) -- untested without cache overload
- for cachename, files in pairs(input.instance[dataname]) do
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
local name = (makename or file.join)(cachename,dataname)
local luaname, lucname = name .. ".lua", name .. ".luc"
- input.report("preparing %s for %s",dataname,cachename)
- for k, v in pairs(files) do
- if not check or check(v,k) then -- path, name
- if type(v) == "table" and #v == 1 then
- files[k] = v[1]
- end
- else
- files[k] = nil -- false
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
end
end
local data = {
type = dataname,
root = cachename,
- version = input.cacheversion,
+ version = resolvers.cacheversion,
date = os.date("%Y-%m-%d"),
time = os.date("%H:%M:%S"),
content = files,
}
- local ok = io.savedata(luaname,input.serialize(data))
+ local ok = io.savedata(luaname,resolvers.serialize(data))
if ok then
- input.report("%s saved in %s",dataname,luaname)
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
- input.report("%s compiled to %s",dataname,lucname)
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
else
- input.report("compiling failed for %s, deleting file %s",dataname,lucname)
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
os.remove(lucname)
end
- else
- input.report("unable to save %s in %s (access error)",dataname,luaname)
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
end
end
end
-function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
- local instance = input.instance
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
filename = ((not filename or (filename == "")) and dataname) or filename
filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
if blob then
local data = blob()
- if data and data.content and data.type == dataname and data.version == input.cacheversion then
- input.report("loading %s for %s from %s",dataname,pathname,filename)
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
instance[dataname][pathname] = data.content
else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
instance[dataname][pathname] = { }
instance.loaderror = true
end
- else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
end
end
@@ -3770,195 +4851,139 @@ end
-- TEXMFBOGUS = 'effe checken of dit werkt',
-- }
-function input.aux.load_texmfcnf(dataname,pathname)
- local instance = input.instance
- local filename = file.join(pathname,input.luaname)
- local blob = loadfile(filename)
- if blob then
- local data = blob()
- if data then
- input.report("loading configuration file %s",filename)
- if true then
- -- flatten to variable.progname
- local t = { }
- for k, v in pairs(data) do -- v = progname
- if type(v) == "string" then
- t[k] = v
- else
- for kk, vv in pairs(v) do -- vv = variable
- if type(vv) == "string" then
- t[vv.."."..v] = kk
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
end
end
end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
end
- instance[dataname][pathname] = t
else
- instance[dataname][pathname] = data
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
end
- else
- input.report("skipping configuration file %s",filename)
- instance[dataname][pathname] = { }
- instance.loaderror = true
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
end
- else
- input.report("skipping configuration file %s",filename)
- end
-end
-
-function input.aux.load_configuration(dname,lname)
- input.aux.load_data(dname,'configuration',lname and file.basename(lname))
-end
-function input.aux.load_files(tag)
- input.aux.load_data(tag,'files')
-end
-
-function input.resetconfig()
- input.identify_own()
- local instance = input.instance
- instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
-end
-
-function input.loadnewconfig()
- local instance = input.instance
- for _, cnf in ipairs(instance.luafiles) do
- local dname = file.dirname(cnf)
- input.aux.load_texmfcnf('setup',dname)
- instance.order[#instance.order+1] = instance.setup[dname]
+ instance.order[#instance.order+1] = instance.setup[pathname]
if instance.loaderror then break end
end
end
-function input.loadoldconfig()
- local instance = input.instance
+function resolvers.loadoldconfig()
if not instance.renewcache then
for _, cnf in ipairs(instance.cnffiles) do
local dname = file.dirname(cnf)
- input.aux.load_configuration(dname)
+ resolvers.load_data(dname,'configuration')
instance.order[#instance.order+1] = instance.configuration[dname]
if instance.loaderror then break end
end
end
- input.joinconfig()
+ resolvers.joinconfig()
end
-function input.expand_variables()
- local instance = input.instance
+function resolvers.expand_variables()
local expansions, environment, variables = { }, instance.environment, instance.variables
- local env = input.env
+ local env = resolvers.env
instance.expansions = expansions
if instance.engine ~= "" then environment['engine'] = instance.engine end
if instance.progname ~= "" then environment['progname'] = instance.progname end
- for k,v in pairs(environment) do
- local a, b = k:match("^(%a+)%_(.*)%s*$")
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
if a and b then
expansions[a..'.'..b] = v
else
expansions[k] = v
end
end
- for k,v in pairs(environment) do -- move environment to expansions
+ for k,v in next, environment do -- move environment to expansions
if not expansions[k] then expansions[k] = v end
end
- for k,v in pairs(variables) do -- move variables to expansions
+ for k,v in next, variables do -- move variables to expansions
if not expansions[k] then expansions[k] = v end
end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
while true do
- local busy = false
- for k,v in pairs(expansions) do
- local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
- local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
if n > 0 or m > 0 then
expansions[k]= s
end
end
if not busy then break end
end
- for k,v in pairs(expansions) do
- expansions[k] = v:gsub("\\", '/')
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
end
end
-function input.aux.expand_vars(lst) -- simple vars
- local instance = input.instance
- local variables, env = instance.variables, input.env
- for k,v in pairs(lst) do
- lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
- return variables[a] or env(a)
- end)
- end
+function resolvers.variable(name)
+ return entry(instance.variables,name)
end
-function input.aux.expanded_var(var) -- simple vars
- local instance = input.instance
- return var:gsub("%$([%a%d%_%-]+)", function(a)
- return instance.variables[a] or input.env(a)
- end)
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
end
-function input.aux.entry(entries,name)
- if name and (name ~= "") then
- local instance = input.instance
- name = name:gsub('%$','')
- local result = entries[name..'.'..instance.progname] or entries[name]
- if result then
- return result
- else
- result = input.env(name)
- if result then
- instance.variables[name] = result
- input.expand_variables()
- return instance.expansions[name] or ""
- end
- end
- end
- return ""
-end
-function input.variable(name)
- return input.aux.entry(input.instance.variables,name)
-end
-function input.expansion(name)
- return input.aux.entry(input.instance.expansions,name)
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
end
-function input.aux.is_entry(entries,name)
- if name and name ~= "" then
- name = name:gsub('%$','')
- return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
- else
- return false
- end
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
end
-function input.is_variable(name)
- return input.aux.is_entry(input.instance.variables,name)
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
end
-function input.is_expansion(name)
- return input.aux.is_entry(input.instance.expansions,name)
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
end
-function input.unexpanded_path_list(str)
- local pth = input.variable(str)
- local lst = input.split_path(pth)
- return input.aux.expanded_path(lst)
-end
-
-function input.unexpanded_path(str)
- return file.join_path(input.unexpanded_path_list(str))
-end
+do -- no longer needed
-do
local done = { }
- function input.reset_extra_path()
- local instance = input.instance
+ function resolvers.reset_extra_path()
local ep = instance.extra_paths
if not ep then
ep, done = { }, { }
@@ -3968,26 +4993,25 @@ do
end
end
- function input.register_extra_path(paths,subpaths)
- local instance = input.instance
+ function resolvers.register_extra_path(paths,subpaths)
local ep = instance.extra_paths or { }
local n = #ep
if paths and paths ~= "" then
if subpaths and subpaths ~= "" then
- for p in paths:gmatch("[^,]+") do
+ for p in gmatch(paths,"[^,]+") do
-- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
+ for s in gmatch(subpaths,"[^,]+") do
local ps = p .. "/" .. s
if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
+ ep[#ep+1] = resolvers.clean_path(ps)
done[ps] = true
end
end
end
else
- for p in paths:gmatch("[^,]+") do
+ for p in gmatch(paths,"[^,]+") do
if not done[p] then
- ep[#ep+1] = input.clean_path(p)
+ ep[#ep+1] = resolvers.clean_path(p)
done[p] = true
end
end
@@ -3995,10 +5019,10 @@ do
elseif subpaths and subpaths ~= "" then
for i=1,n do
-- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
+ for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
+ ep[#ep+1] = resolvers.clean_path(ps)
done[ps] = true
end
end
@@ -4014,306 +5038,196 @@ do
end
-function input.expanded_path_list(str)
- local instance = input.instance
- local function made_list(list)
- local ep = instance.extra_paths
- if not ep or #ep == 0 then
- return list
- else
- local done, new = { }, { }
- -- honour . .. ../.. but only when at the start
- for k, v in ipairs(list) do
- if not done[v] then
- if v:find("^[%.%/]$") then
- done[v] = true
- new[#new+1] = v
- else
- break
- end
- end
- end
- -- first the extra paths
- for k, v in ipairs(ep) do
- if not done[v] then
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
done[v] = true
new[#new+1] = v
+ else
+ break
end
end
- -- next the formal paths
- for k, v in ipairs(list) do
- if not done[v] then
- done[v] = true
- new[#new+1] = v
- end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
end
- return new
end
- end
- if not str then
- return ep or { }
- elseif instance.savelists then
- -- engine+progname hash
- str = str:gsub("%$","")
- if not instance.lists[str] then -- cached
- local lst = made_list(input.split_path(input.expansion(str)))
- instance.lists[str] = input.aux.expanded_path(lst)
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
end
- return instance.lists[str]
- else
- local lst = input.split_path(input.expansion(str))
- return made_list(input.aux.expanded_path(lst))
+ return new
end
end
-
-function input.clean_path_list(str)
- local t = input.expanded_path_list(str)
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
if t then
for i=1,#t do
- t[i] = file.collapse_path(input.clean_path(t[i]))
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
end
end
return t
end
-function input.expand_path(str)
- return file.join_path(input.expanded_path_list(str))
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
end
-function input.expanded_path_list_from_var(str) -- brrr
- local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
if tmp ~= "" then
- return input.expanded_path_list(str)
+ return resolvers.expanded_path_list(str)
else
- return input.expanded_path_list(tmp)
+ return resolvers.expanded_path_list(tmp)
end
end
-function input.expand_path_from_var(str)
- return file.join_path(input.expanded_path_list_from_var(str))
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
end
-function input.format_of_var(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
end
-function input.format_of_suffix(str)
- return input.suffixmap[file.extname(str)] or 'tex'
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
end
-function input.variable_of_format(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
end
-function input.var_of_format_or_suffix(str)
- local v = input.formats[str]
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
if v then
return v
end
- v = input.formats[input.alternatives[str]]
+ v = formats[alternatives[str]]
if v then
return v
end
- v = input.suffixmap[file.extname(str)]
+ v = suffixmap[file.extname(str)]
if v then
- return input.formats[isf]
+ return formats[isf]
end
return ''
end
-function input.expand_braces(str) -- output variable and brace expansion of STRING
- local ori = input.variable(str)
- local pth = input.aux.expanded_path(input.split_path(ori))
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
return file.join_path(pth)
end
--- {a,b,c,d}
--- a,b,c/{p,q,r},d
--- a,b,c/{p,q,r}/d/{x,y,z}//
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a{b,c}{d,e}f
--- {a,b,c,d}
--- {a,b,c/{p,q,r},d}
--- {a,b,c/{p,q,r}/d/{x,y,z}//}
--- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
--- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
--- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
-
--- this one is better and faster, but it took me a while to realize
--- that this kind of replacement is cleaner than messy parsing and
--- fuzzy concatenating we can probably gain a bit with selectively
--- applying lpeg, but experiments with lpeg parsing this proved not to
--- work that well; the parsing is ok, but dealing with the resulting
--- table is a pain because we need to work inside-out recursively
-
-function input.aux.splitpathexpr(str, t, validate)
- -- no need for optimization, only called a few times, we can use lpeg for the sub
- t = t or { }
- str = str:gsub(",}",",@}")
- str = str:gsub("{,","{@,")
- -- str = "@" .. str .. "@"
- while true do
- local done = false
- while true do
- local ok = false
- str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
- local t = { }
- for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
- local t = { }
- for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
- local t = { }
- for sa in a:gmatch("[^,]+") do
- for sb in b:gmatch("[^,]+") do
- t[#t+1] = sa .. sb
- end
- end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
- done = true
- return a .. b.. c
- end)
- if not done then break end
- end
- str = str:gsub("[{}]", "")
- str = str:gsub("@","")
- if validate then
- for s in str:gmatch("[^,]+") do
- s = validate(s)
- if s then t[#t+1] = s end
- end
- else
- for s in str:gmatch("[^,]+") do
- t[#t+1] = s
- end
- end
- return t
-end
-
-function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
- local instance = input.instance
- -- a previous version fed back into pathlist
- local newlist, ok = { }, false
- for _,v in ipairs(pathlist) do
- if v:find("[{}]") then
- ok = true
- break
- end
- end
- if ok then
- for _, v in ipairs(pathlist) do
- input.aux.splitpathexpr(v, newlist, function(s)
- s = file.collapse_path(s)
- return s ~= "" and not s:find(instance.dummy_path_expr) and s
- end)
- end
- else
- for _,v in ipairs(pathlist) do
- for vv in string.gmatch(v..',',"(.-),") do
- vv = file.collapse_path(v)
- if vv ~= "" then newlist[#newlist+1] = vv end
- end
- end
- end
- return newlist
-end
+resolvers.isreadable = { }
-input.is_readable = { }
-
-function input.aux.is_readable(readable, name)
- if input.trace > 2 then
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
if readable then
- input.logger("+ readable: %s",name)
+ logs.report("fileio","+ readable: %s",name)
else
- input.logger("- readable: %s", name)
+ logs.report("fileio","- readable: %s", name)
end
end
return readable
end
-function input.is_readable.file(name)
- return input.aux.is_readable(lfs.isfile(name), name)
-end
-
-input.is_readable.tex = input.is_readable.file
+resolvers.isreadable.tex = resolvers.isreadable.file
-- name
-- name/name
-function input.aux.collect_files(names)
- local instance = input.instance
+local function collect_files(names)
local filelist = { }
- for _, fname in pairs(names) do
- if fname then
- if input.trace > 2 then
- input.logger("? blobpath asked: %s",fname)
- end
- local bname = file.basename(fname)
- local dname = file.dirname(fname)
- if dname == "" or dname:find("^%.") then
- dname = false
- else
- dname = "/" .. dname .. "$"
- end
- for _, hash in ipairs(instance.hashes) do
- local blobpath = hash.tag
- local files = blobpath and instance.files[blobpath]
- if files then
- if input.trace > 2 then
- input.logger('? blobpath do: %s (%s)',blobpath,bname)
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
end
- local blobfile = files[bname]
- if not blobfile then
- local rname = "remap:"..bname
- blobfile = files[rname]
- if blobfile then
- bname = files[rname]
- blobfile = files[bname]
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
end
- end
- if blobfile then
- if type(blobfile) == 'string' then
- if not dname or blobfile:find(dname) then
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
filelist[#filelist+1] = {
hash.type,
- file.join(blobpath,blobfile,bname), -- search
- input.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
}
end
- else
- for _, vv in pairs(blobfile) do
- if not dname or vv:find(dname) then
- filelist[#filelist+1] = {
- hash.type,
- file.join(blobpath,vv,bname), -- search
- input.concatinators[hash.type](blobpath,vv,bname) -- result
- }
- end
- end
end
end
- elseif input.trace > 1 then
- input.logger('! blobpath no: %s (%s)',blobpath,bname)
end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
end
end
end
@@ -4324,102 +5238,95 @@ function input.aux.collect_files(names)
end
end
-function input.suffix_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str][1]
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
else
return ""
end
end
-function input.suffixes_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str]
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
else
return {}
end
end
-do
-
- -- called about 700 times for an empty doc (font initializations etc)
- -- i need to weed the font files for redundant calls
-
- local letter = lpeg.R("az","AZ")
- local separator = lpeg.P("://")
-
- local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator
- local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-
- -- ./name ../name /name c: ://
- function input.aux.qualified_path(filename)
- return qualified:match(filename)
- end
- function input.aux.rootbased_path(filename)
- return rootbased:match(filename)
- end
-
- function input.normalize_name(original)
- return original
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
end
-
- input.normalize_name = file.collapse_path
-
end
-function input.aux.register_in_trees(name)
- if not name:find("^%.") then
- local instance = input.instance
- instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
end
+ return (fakepaths[name] == 1)
end
--- split the next one up, better for jit
-
-function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
- local instance = input.instance
- local result = { }
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
local stamp = nil
- filename = input.normalize_name(filename) -- elsewhere
- filename = file.collapse_path(filename:gsub("\\","/")) -- elsewhere
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
-- speed up / beware: format problem
if instance.remember then
stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
if instance.found[stamp] then
- if input.trace > 0 then
- input.logger('! remembered: %s',filename)
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
end
return instance.found[stamp]
end
end
- if filename:find('%*') then
- if input.trace > 0 then
- input.logger('! wildcard: %s', filename)
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
end
- result = input.find_wildcard_files(filename)
- elseif input.aux.qualified_path(filename) then
- if input.is_readable.file(filename) then
- if input.trace > 0 then
- input.logger('! qualified: %s', filename)
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
end
result = { filename }
else
- local forcedname, ok = "", false
- if file.extname(filename) == "" then
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
if instance.format == "" then
forcedname = filename .. ".tex"
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing standard filetype: tex')
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
end
result, ok = { forcedname }, true
end
else
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
forcedname = filename .. "." .. s
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing format filetype: %s', s)
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
end
result, ok = { forcedname }, true
break
@@ -4427,8 +5334,49 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
end
end
- if not ok and input.trace > 0 then
- input.logger('? qualified: %s', filename)
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
end
end
else
@@ -4445,45 +5393,47 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
if ext == "" then
local forcedname = filename .. '.tex'
wantedfiles[#wantedfiles+1] = forcedname
- filetype = input.format_of_suffix(forcedname)
- if input.trace > 0 then
- input.logger('! forcing filetype: %s',filetype)
- end
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
else
- filetype = input.format_of_suffix(filename)
- if input.trace > 0 then
- input.logger('! using suffix based filetype: %s',filetype)
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
end
end
else
if ext == "" then
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
wantedfiles[#wantedfiles+1] = filename .. "." .. s
end
end
filetype = instance.format
- if input.trace > 0 then
- input.logger('! using given filetype: %s',filetype)
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
end
end
- local typespec = input.variable_of_format(filetype)
- local pathlist = input.expanded_path_list(typespec)
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
if not pathlist or #pathlist == 0 then
-- no pathlist, access check only / todo == wildcard
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- input.logger('? filetype: %s',filetype or '?')
- input.logger('? wanted files: %s',concat(wantedfiles," | "))
- end
- for _, fname in pairs(wantedfiles) do
- if fname and input.is_readable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
filename, done = fname, true
result[#result+1] = file.join('.',fname)
break
end
end
-- this is actually 'other text files' or 'any' or 'whatever'
- local filelist = input.aux.collect_files(wantedfiles)
+ local filelist = collect_files(wantedfiles)
local fl = filelist and filelist[1]
if fl then
filename = fl[3]
@@ -4492,56 +5442,53 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
else
-- list search
- local filelist = input.aux.collect_files(wantedfiles)
+ local filelist = collect_files(wantedfiles)
local doscan, recurse
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- -- if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
- -- if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
end
-- a bit messy ... esp the doscan setting here
- for _, path in pairs(pathlist) do
- if path:find("^!!") then doscan = false else doscan = true end
- if path:find("//$") then recurse = true else recurse = false end
- local pathname = path:gsub("^!+", '')
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
done = false
-- using file list
if filelist and not (done and not instance.allresults) and recurse then
-- compare list entries with permitted pattern
- pathname = pathname:gsub("([%-%.])","%%%1") -- this also influences
- pathname = pathname:gsub("/+$", '/.*') -- later usage of pathname
- pathname = pathname:gsub("//", '/.-/') -- not ok for /// but harmless
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
local expr = "^" .. pathname
- -- input.debug('?',expr)
- for _, fl in ipairs(filelist) do
+ for k=1,#filelist do
+ local fl = filelist[k]
local f = fl[2]
- if f:find(expr) then
- -- input.debug('T',' '..f)
- if input.trace > 2 then
- input.logger('= found in hash: %s',f)
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
end
--- todo, test for readable
result[#result+1] = fl[3]
- input.aux.register_in_trees(f) -- for tracing used files
+ resolvers.register_in_trees(f) -- for tracing used files
done = true
if not instance.allresults then break end
- else
- -- input.debug('F',' '..f)
end
end
end
if not done and doscan then
-- check if on disk / unchecked / does not work at all / also zips
- if input.method_is_file(pathname) then -- ?
- local pname = pathname:gsub("%.%*$",'')
- if not pname:find("%*") then
- local ppname = pname:gsub("/+$","")
- if input.aux.can_be_dir(ppname) then
- for _, w in pairs(wantedfiles) do
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
local fname = file.join(ppname,w)
- if input.is_readable.file(fname) then
- if input.trace > 2 then
- input.logger('= found by scanning: %s',fname)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
end
result[#result+1] = fname
done = true
@@ -4561,8 +5508,8 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
end
end
- for k,v in pairs(result) do
- result[k] = file.collapse_path(v)
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
end
if instance.remember then
instance.found[stamp] = result
@@ -4570,38 +5517,12 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
return result
end
-input.aux._find_file_ = input.aux.find_file -- frozen variant
+if not resolvers.concatinators then resolvers.concatinators = { } end
-function input.aux.find_file(filename) -- maybe make a lowres cache too
- local result = input.aux._find_file_(filename)
- if #result == 0 then
- local lowered = filename:lower()
- if filename ~= lowered then
- return input.aux._find_file_(lowered)
- end
- end
- return result
-end
-
-function input.aux.can_be_dir(name)
- local instance = input.instance
- if not instance.fakepaths[name] then
- if lfs.isdir(name) then
- instance.fakepaths[name] = 1 -- directory
- else
- instance.fakepaths[name] = 2 -- no directory
- end
- end
- return (instance.fakepaths[name] == 1)
-end
-
-if not input.concatinators then input.concatinators = { } end
-
-input.concatinators.tex = file.join
-input.concatinators.file = input.concatinators.tex
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
-function input.find_files(filename,filetype,mustexist)
- local instance = input.instance
+function resolvers.find_files(filename,filetype,mustexist)
if type(mustexist) == boolean then
-- all set
elseif type(filetype) == 'boolean' then
@@ -4610,19 +5531,26 @@ function input.find_files(filename,filetype,mustexist)
filetype, mustexist = nil, false
end
instance.format = filetype or ''
- local t = input.aux.find_file(filename,true)
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
instance.format = ''
- return t
+ return result
end
-function input.find_file(filename,filetype,mustexist)
- return (input.find_files(filename,filetype,mustexist)[1] or "")
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
end
-function input.find_given_files(filename)
- local instance = input.instance
+function resolvers.find_given_files(filename)
local bname, result = file.basename(filename), { }
- for k, hash in ipairs(instance.hashes) do
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
local files = instance.files[hash.tag]
local blist = files[bname]
if not blist then
@@ -4635,11 +5563,12 @@ function input.find_given_files(filename)
end
if blist then
if type(blist) == 'string' then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
if not instance.allresults then break end
else
- for kk,vv in pairs(blist) do
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
if not instance.allresults then break end
end
end
@@ -4648,61 +5577,68 @@ function input.find_given_files(filename)
return result
end
-function input.find_given_file(filename)
- return (input.find_given_files(filename)[1] or "")
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
end
-function input.find_wildcard_files(filename) -- todo: remap:
- local instance = input.instance
+function resolvers.find_wildcard_files(filename) -- todo: remap:
local result = { }
local bname, dname = file.basename(filename), file.dirname(filename)
- local path = dname:gsub("^*/","")
- path = path:gsub("*",".*")
- path = path:gsub("-","%%-")
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
if dname == "" then
path = ".*"
end
local name = bname
- name = name:gsub("*",".*")
- name = name:gsub("-","%%-")
- path = path:lower()
- name = name:lower()
- local function doit(blist,bname,hash,allresults)
- local done = false
- if blist then
- if type(blist) == 'string' then
- -- make function and share code
- if (blist:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
- done = true
- end
- else
- for kk,vv in pairs(blist) do
- if (vv:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
- done = true
- if not allresults then break end
- end
- end
- end
- end
- return done
- end
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
local files, allresults, done = instance.files, instance.allresults, false
- if name:find("%*") then
- for k, hash in ipairs(instance.hashes) do
- for kk, hh in pairs(files[hash.tag]) do
- if not kk:find("^remap:") then
- if (kk:lower()):find(name) then
- if doit(hh,kk,hash,allresults) then done = true end
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
if done and not allresults then break end
end
end
end
end
else
- for k, hash in ipairs(instance.hashes) do
- if doit(files[hash.tag][bname],bname,hash,allresults) then done = true end
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
if done and not allresults then break end
end
end
@@ -4711,67 +5647,49 @@ function input.find_wildcard_files(filename) -- todo: remap:
return result
end
-function input.find_wildcard_file(filename)
- return (input.find_wildcard_files(filename)[1] or "")
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
end
-- main user functions
-function input.save_used_files_in_trees(filename,jobname)
- local instance = input.instance
- if not filename then filename = 'luatex.jlg' end
- local f = io.open(filename,'w')
- if f then
- f:write("<?xml version='1.0' standalone='yes'?>\n")
- f:write("<rl:job>\n")
- if jobname then
- f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
- end
- f:write("\t<rl:files>\n")
- for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
- f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
- end
- f:write("\t</rl:files>\n")
- f:write("</rl:usedfiles>\n")
- f:close()
- end
-end
-
-function input.automount()
+function resolvers.automount()
-- implemented later
end
-function input.load()
- input.starttiming(input.instance)
- input.resetconfig()
- input.identify_cnf()
- input.load_lua()
- input.expand_variables()
- input.load_cnf()
- input.expand_variables()
- input.load_hash()
- input.automount()
- input.stoptiming(input.instance)
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
end
-function input.for_files(command, files, filetype, mustexist)
+function resolvers.for_files(command, files, filetype, mustexist)
if files and #files > 0 then
local function report(str)
- if input.verbose then
- input.report(str) -- has already verbose
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
else
print(str)
end
end
- if input.verbose then
+ if trace_verbose then
report('')
end
- for _, file in pairs(files) do
+ for _, file in ipairs(files) do
local result = command(file,filetype,mustexist)
if type(result) == 'string' then
report(result)
else
- for _,v in pairs(result) do
+ for _,v in ipairs(result) do
report(v)
end
end
@@ -4781,19 +5699,19 @@ end
-- strtab
-input.var_value = input.variable -- output the value of variable $STRING.
-input.expand_var = input.expansion -- output variable expansion of STRING.
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
-function input.show_path(str) -- output search path for file type NAME
- return file.join_path(input.expanded_path_list(input.format_of_var(str)))
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
end
--- input.find_file(filename)
--- input.find_file(filename, filetype, mustexist)
--- input.find_file(filename, mustexist)
--- input.find_file(filename, filetype)
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
-function input.aux.register_file(files, name, path)
+function resolvers.register_file(files, name, path)
if files[name] then
if type(files[name]) == 'string' then
files[name] = { files[name], path }
@@ -4805,170 +5723,77 @@ function input.aux.register_file(files, name, path)
end
end
-if not input.finders then input.finders = { } end
-if not input.openers then input.openers = { } end
-if not input.loaders then input.loaders = { } end
-
-input.finders.notfound = { nil }
-input.openers.notfound = { nil }
-input.loaders.notfound = { false, nil, 0 }
-
-function input.splitmethod(filename)
+function resolvers.splitmethod(filename)
if not filename then
return { } -- safeguard
elseif type(filename) == "table" then
return filename -- already split
- elseif not filename:find("://") then
+ elseif not find(filename,"://") then
return { scheme="file", path = filename, original=filename } -- quick hack
else
return url.hashed(filename)
end
end
-function input.method_is_file(filename)
- return input.splitmethod(filename).scheme == 'file'
-end
-
function table.sequenced(t,sep) -- temp here
local s = { }
- for k, v in pairs(t) do
+ for k, v in pairs(t) do -- pairs?
s[#s+1] = k .. "=" .. v
end
return concat(s, sep or " | ")
end
-function input.methodhandler(what, filename, filetype) -- ...
- local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
local scheme = specification.scheme
- if input[what][scheme] then
- if input.trace > 0 then
- input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
end
- return input[what][scheme](filename,filetype) -- todo: specification
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
else
- return input[what].tex(filename,filetype) -- todo: specification
- end
-end
-
--- also inside next test?
-
-function input.findtexfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.opentexfile(filename)
- return input.methodhandler('openers',input.normalize_name(filename))
-end
-
-function input.findbinfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.openbinfile(filename)
- return input.methodhandler('loaders',input.normalize_name(filename))
-end
-
-function input.loadbinfile(filename, filetype)
- local fname = input.findbinfile(input.normalize_name(filename), filetype)
- if fname and fname ~= "" then
- return input.openbinfile(fname)
- else
- return unpack(input.loaders.notfound)
- end
-end
-
-function input.texdatablob(filename, filetype)
- local ok, data, size = input.loadbinfile(filename, filetype)
- return data or ""
-end
-
-input.loadtexfile = input.texdatablob
-
-function input.openfile(filename)
- local fullname = input.findtexfile(filename)
- if fullname and (fullname ~= "") then
- return input.opentexfile(fullname)
- else
- return nil
+ return resolvers[what].tex(filename,filetype) -- todo: specification
end
end
-function input.logmode()
- return (os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"):lower()
-end
-
--- this is a prelude to engine/progname specific configuration files
--- in which case we can omit files meant for other programs and
--- packages
-
---- ctx
-
--- maybe texinputs + font paths
--- maybe positive selection tex/context fonts/tfm|afm|vf|opentype|type1|map|enc
-
-input.validators = { }
-input.validators.visibility = { }
-
-function input.validators.visibility.default(path, name)
- return true
-end
-
-function input.validators.visibility.context(path, name)
- path = path[1] or path -- some day a loop
- return not (
- path:find("latex") or
--- path:find("doc") or
- path:find("tex4ht") or
- path:find("source") or
--- path:find("config") or
--- path:find("metafont") or
- path:find("lists$") or
- name:find("%.tpm$") or
- name:find("%.bak$")
- )
-end
-
--- todo: describe which functions are public (maybe input.private. ... )
-
--- beware: i need to check where we still need a / on windows:
-
-function input.clean_path(str)
+function resolvers.clean_path(str)
if str then
- str = str:gsub("\\","/")
- str = str:gsub("^!+","")
- str = str:gsub("^~",input.homedir)
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
return str
else
return nil
end
end
-function input.do_with_path(name,func)
- for _, v in pairs(input.expanded_path_list(name)) do
- func("^"..input.clean_path(v))
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
end
end
-function input.do_with_var(name,func)
- func(input.aux.expanded_var(name))
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
end
-function input.with_files(pattern,handle)
- local instance = input.instance
+function resolvers.with_files(pattern,handle)
for _, hash in ipairs(instance.hashes) do
local blobpath = hash.tag
local blobtype = hash.type
if blobpath then
local files = instance.files[blobpath]
if files then
- for k,v in pairs(files) do
- if k:find("^remap:") then
+ for k,v in next, files do
+ if find(k,"^remap:") then
k = files[k]
v = files[k] -- chained
end
- if k:find(pattern) then
+ if find(k,pattern) then
if type(v) == "string" then
handle(blobtype,blobpath,v,k)
else
- for _,vv in pairs(v) do
+ for _,vv in pairs(v) do -- ipairs?
handle(blobtype,blobpath,vv,k)
end
end
@@ -4979,122 +5804,32 @@ function input.with_files(pattern,handle)
end
end
-function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
- local scriptpath = "scripts/context/lua"
- newname = file.addsuffix(newname,"lua")
- local oldscript = input.clean_path(oldname)
- input.report("to be replaced old script %s", oldscript)
- local newscripts = input.find_files(newname) or { }
- if #newscripts == 0 then
- input.report("unable to locate new script")
- else
- for _, newscript in ipairs(newscripts) do
- newscript = input.clean_path(newscript)
- input.report("checking new script %s", newscript)
- if oldscript == newscript then
- input.report("old and new script are the same")
- elseif not newscript:find(scriptpath) then
- input.report("new script should come from %s",scriptpath)
- elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
- input.report("invalid new script name")
- else
- local newdata = io.loaddata(newscript)
- if newdata then
- input.report("old script content replaced by new content")
- io.savedata(oldscript,newdata)
- break
- else
- input.report("unable to load new script")
- end
- end
- end
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
end
-end
-
-
---~ print(table.serialize(input.aux.splitpathexpr("/usr/share/texmf-{texlive,tetex}", {})))
-
--- command line resolver:
-
---~ print(input.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
-
-do
-
- local resolvers = { }
-
- resolvers.environment = function(str)
- return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
- end
- resolvers.relative = function(str,n)
- if io.exists(str) then
- -- nothing
- elseif io.exists("./" .. str) then
- str = "./" .. str
- else
- local p = "../"
- for i=1,n or 2 do
- if io.exists(p .. str) then
- str = p .. str
- break
- else
- p = p .. "../"
- end
- end
- end
- return input.clean_path(str)
- end
- resolvers.locate = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path((fullname ~= "" and fullname) or str)
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
end
- resolvers.filename = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
- end
- resolvers.pathname = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
- end
-
- resolvers.env = resolvers.environment
- resolvers.rel = resolvers.relative
- resolvers.loc = resolvers.locate
- resolvers.kpse = resolvers.locate
- resolvers.full = resolvers.locate
- resolvers.file = resolvers.filename
- resolvers.path = resolvers.pathname
-
- local function resolve(str)
- if type(str) == "table" then
- for k, v in pairs(str) do
- str[k] = resolve(v) or v
- end
- elseif str and str ~= "" then
- str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
- if resolvers[method] then
- return resolvers[method](target)
- else
- return method .. ":" .. target
- end
- end)
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
end
- return str
end
-
- if os.uname then
- for k, v in pairs(os.uname()) do
- if not resolvers[k] then
- resolvers[k] = function() return v end
- end
- end
- end
-
- input.resolve = resolve
-
+ return nil, nil
end
-function input.boolean_variable(str,default)
- local b = input.expansion(str)
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
if b == "" then
return default
else
@@ -5103,165 +5838,20 @@ function input.boolean_variable(str,default)
end
end
+texconfig.kpse_init = false
-if not modules then modules = { } end modules ['luat-log'] = {
- version = 1.001,
- comment = "companion to luat-lib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
-
--- input.logger -> special tracing, driven by log level (only input)
--- input.report -> goes to terminal, depends on verbose, has banner
--- logs.report -> module specific tracing and reporting, no banner but class
-
-
-input = input or { }
-logs = logs or { }
-
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
-
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4
-}
-
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
-}
+-- for a while
-logs.callbacks = {
- 'start_page_number',
- 'stop_page_number',
- 'report_output_pages',
- 'report_output_log'
-}
+input = resolvers
-logs.tracers = {
-}
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
+end -- of closure
-logs.level = 0
-
-local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+do -- create closure to overcome 200 locals limit
-if texlua then
- write_nl = print
- write = io.write
-end
-
-function logs.xml.report(category,fmt,...) -- new
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
-end
-function logs.xml.line(fmt,...) -- new
- write_nl(format("<r>%s</r>",format(fmt,...)))
-end
-
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
-
-function logs.tex.report(category,fmt,...) -- new
- -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
- write_nl(category .. " | " .. format(fmt,...))
-end
-function logs.tex.line(fmt,...) -- new
- write_nl(format(fmt,...))
-end
-
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
-end
-
-function logs.set_method(method)
- for _, v in pairs(logs.functions) do
- logs[v] = logs[method][v] or function() end
- end
- if callback and input[method] then
- for _, cb in pairs(logs.callbacks) do
- callback.register(cb, input[method][cb])
- end
- end
-end
-
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
-end
-
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
-end
-
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
-end
-
-function logs.xml.report_output_log()
-end
-
-function input.logger(...) -- assumes test for input.trace > n
- if input.trace > 0 then
- logs.report(...)
- end
-end
-
-function input.report(fmt,...)
- if input.verbose then
- logs.report(input.banner or "report",format(fmt,...))
- end
-end
-
-function input.reportlines(str) -- todo: <lines></lines>
- for line in str:gmatch("(.-)[\n\r]") do
- logs.report(input.banner or "report",line)
- end
-end
-
-input.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
-
-function input.help(banner,message)
- if not input.verbose then
- input.verbose = true
- -- input.report(banner,"\n")
- end
- input.report(banner,"\n")
- input.report("")
- input.reportlines(message)
- if input.moreinfo and input.moreinfo ~= "" then
- input.report("")
- input.reportlines(input.moreinfo)
- end
-end
-
-logs.set_level('error')
-logs.set_method('tex')
-
-
-if not modules then modules = { } end modules ['luat-tmp'] = {
+if not modules then modules = { } end modules ['data-tmp'] = {
version = 1.001,
comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -5285,33 +5875,37 @@ being written at the same time is small. We also need to extend
luatools with a recache feature.</p>
--ldx]]--
-local format = string.format
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
caches = caches or { }
-dir = dir or { }
-texmf = texmf or { }
caches.path = caches.path or nil
caches.base = caches.base or "luatex-cache"
caches.more = caches.more or "context"
caches.direct = false -- true is faster but may need huge amounts of memory
-caches.trace = false
caches.tree = false
caches.paths = caches.paths or nil
caches.force = false
caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+function caches.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
function caches.temp()
local cachepath = nil
local function check(list,isenv)
if not cachepath then
- for _, v in ipairs(list) do
+ for k=1,#list do
+ local v = list[k]
cachepath = (isenv and (os.env[v] or "")) or v or ""
if cachepath == "" then
-- next
else
- cachepath = input.clean_path(cachepath)
- if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
break
elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
dir.mkdirs(cachepath)
@@ -5324,7 +5918,7 @@ function caches.temp()
end
end
end
- check(input.clean_path_list("TEXMFCACHE") or { })
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
check(caches.defaults,true)
if not cachepath then
print("\nfatal error: there is no valid (writable) cache path defined\n")
@@ -5333,7 +5927,7 @@ function caches.temp()
print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
os.exit()
end
- cachepath = input.normalize_name(cachepath)
+ cachepath = file.collapse_path(cachepath)
function caches.temp()
return cachepath
end
@@ -5341,24 +5935,13 @@ function caches.temp()
end
function caches.configpath()
- return table.concat(input.instance.cnffiles,";")
+ return table.concat(resolvers.instance.cnffiles,";")
end
function caches.hashed(tree)
- return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
end
---~ tracing:
-
---~ function caches.hashed(tree)
---~ tree = (tree:lower()):gsub("[\\\/]+","/")
---~ local hash = md5.hex(tree)
---~ if input.verbose then -- temp message
---~ input.report("hashing %s => %s",tree,hash)
---~ end
---~ return hash
---~ end
-
function caches.treehash()
local tree = caches.configpath()
if not tree or tree == "" then
@@ -5373,21 +5956,19 @@ function caches.setpath(...)
if not caches.path then
caches.path = caches.temp()
end
- caches.path = input.clean_path(caches.path) -- to be sure
- if lfs then
- caches.tree = caches.tree or caches.treehash()
- if caches.tree then
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
- else
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
- end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
end
end
if not caches.path then
caches.path = '.'
end
- caches.path = input.clean_path(caches.path)
- if lfs and not table.is_empty({...}) then
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
local pth = dir.mkdirs(caches.path,...)
return pth
end
@@ -5415,9 +5996,14 @@ function caches.loaddata(path,name)
end
end
-function caches.is_writable(filepath,filename)
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
local tmaname, tmcname = caches.setluanames(filepath,filename)
- return file.is_writable(tmaname)
+ return file.iswritable(tmaname)
end
function caches.savedata(filepath,filename,data,raw)
@@ -5427,23 +6013,81 @@ function caches.savedata(filepath,filename,data,raw)
reduce, simplify = false, false
end
if caches.direct then
- file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
else
- table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
end
- local cleanup = input.boolean_variable("PURGECACHE", false)
- local strip = input.boolean_variable("LUACSTRIP", true)
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
utils.lua.compile(tmaname, tmcname, cleanup, strip)
end
-- here we use the cache for format loading (texconfig.[formatname|jobname])
--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
-if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
- texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
end
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
--[[ldx--
<p>Once we found ourselves defining similar cache constructs
several times, containers were introduced. Containers are used
@@ -5457,126 +6101,141 @@ table structures without bothering about the disk cache.</p>
<p>Examples of usage can be found in the font related code.</p>
--ldx]]--
-containers = { }
-containers.trace = false
+containers = containers or { }
-do -- local report
+containers.usecache = true
- local function report(container,tag,name)
- if caches.trace or containers.trace or container.trace then
- logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
- end
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
end
+end
- local allocated = { }
+local allocated = { }
- -- tracing
+-- tracing
- function containers.define(category, subcategory, version, enabled)
- return function()
- if category and subcategory then
- local c = allocated[category]
- if not c then
- c = { }
- allocated[category] = c
- end
- local s = c[subcategory]
- if not s then
- s = {
- category = category,
- subcategory = subcategory,
- storage = { },
- enabled = enabled,
- version = version or 1.000,
- trace = false,
- path = caches.setpath(category,subcategory),
- }
- c[subcategory] = s
- end
- return s
- else
- return nil
- end
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
end
end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
- function containers.is_usable(container, name)
- return container.enabled and caches.is_writable(container.path, name)
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
end
+end
- function containers.is_valid(container, name)
- if name and name ~= "" then
- local storage = container.storage[name]
- return storage and not table.is_empty(storage) and storage.cache_version == container.version
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
else
- return false
+ container.storage[name] = nil
end
end
-
- function containers.read(container,name)
- if container.enabled and not container.storage[name] then
- container.storage[name] = caches.loaddata(container.path,name)
- if containers.is_valid(container,name) then
- report(container,"loaded",name)
- else
- container.storage[name] = nil
- end
- end
- if container.storage[name] then
- report(container,"reusing",name)
- end
- return container.storage[name]
+ if container.storage[name] then
+ report(container,"reusing",name)
end
+ return container.storage[name]
+end
- function containers.write(container, name, data)
- if data then
- data.cache_version = container.version
- if container.enabled then
- local unique, shared = data.unique, data.shared
- data.unique, data.shared = nil, nil
- caches.savedata(container.path, name, data)
- report(container,"saved",name)
- data.unique, data.shared = unique, shared
- end
- report(container,"stored",name)
- container.storage[name] = data
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
end
- return data
- end
-
- function containers.content(container,name)
- return container.storage[name]
+ report(container,"stored",name)
+ container.storage[name] = data
end
+ return data
+end
+function containers.content(container,name)
+ return container.storage[name]
end
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
-- since we want to use the cache instead of the tree, we will now
-- reimplement the saver.
-local save_data = input.aux.save_data
-local load_data = input.aux.load_data
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
-input.cachepath = nil -- public, for tracing
-input.usecache = true -- public, for tracing
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
-function input.aux.save_data(dataname, check)
- save_data(dataname, check, function(cachename,dataname)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(cachename))
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
else
return file.join(cachename,dataname)
end
end)
end
-function input.aux.load_data(pathname,dataname,filename)
+function resolvers.load_data(pathname,dataname,filename)
load_data(pathname,dataname,filename,function(dataname,filename)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(pathname))
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
else
if not filename or (filename == "") then
filename = dataname
@@ -5588,15 +6247,15 @@ end
-- we will make a better format, maybe something xml or just text or lua
-input.automounted = input.automounted or { }
+resolvers.automounted = resolvers.automounted or { }
-function input.automount(usecache)
- local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT'))
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
if table.is_empty(mountpaths) and usecache then
mountpaths = { caches.setpath("mount") }
end
if not table.is_empty(mountpaths) then
- input.starttiming(input.instance)
+ statistics.starttiming(resolvers.instance)
for k, root in pairs(mountpaths) do
local f = io.open(root.."/url.tmi")
if f then
@@ -5605,1007 +6264,302 @@ function input.automount(usecache)
if line:find("^[%%#%-]") then -- or %W
-- skip
elseif line:find("^zip://") then
- input.report("mounting %s",line)
- table.insert(input.automounted,line)
- input.usezipfile(line)
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
end
end
end
f:close()
end
end
- input.stoptiming(input.instance)
+ statistics.stoptiming(resolvers.instance)
end
end
--- store info in format
+-- status info
-input.storage = { }
-input.storage.data = { }
-input.storage.min = 0 -- 500
-input.storage.max = input.storage.min - 1
-input.storage.trace = false -- true
-input.storage.done = input.storage.done or 0
-input.storage.evaluators = { }
--- (evaluate,message,names)
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
-function input.storage.register(...)
- input.storage.data[#input.storage.data+1] = { ... }
-end
+-- experiment (code will move)
-function input.storage.evaluate(name)
- input.storage.evaluators[#input.storage.evaluators+1] = name
-end
-
-function input.storage.finalize() -- we can prepend the string with "evaluate:"
- for _, t in ipairs(input.storage.evaluators) do
- for i, v in pairs(t) do
- if type(v) == "string" then
- t[i] = loadstring(v)()
- elseif type(v) == "table" then
- for _, vv in pairs(v) do
- if type(vv) == "string" then
- t[i] = loadstring(vv)()
- end
- end
- end
- end
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
end
end
-function input.storage.dump()
- for name, data in ipairs(input.storage.data) do
- local evaluate, message, original, target = data[1], data[2], data[3] ,data[4]
- local name, initialize, finalize, code = nil, "", "", ""
- for str in target:gmatch("([^%.]+)") do
- if name then
- name = name .. "." .. str
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
else
- name = str
+ return "invalid status file"
end
- initialize = format("%s %s = %s or {} ", initialize, name, name)
- end
- if evaluate then
- finalize = "input.storage.evaluate(" .. name .. ")"
- end
- input.storage.max = input.storage.max + 1
- if input.storage.trace then
- logs.report('storage','saving %s in slot %s',message,input.storage.max)
- code =
- initialize ..
- format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
- table.serialize(original,name) ..
- finalize
else
- code = initialize .. table.serialize(original,name) .. finalize
+ return "missing status file"
end
- lua.bytecode[input.storage.max] = loadstring(code)
end
+ return true
end
--- we also need to count at generation time (nicer for message)
-
-if lua.bytecode then -- from 0 upwards
- local i = input.storage.min
- while lua.bytecode[i] do
- lua.bytecode[i]()
- lua.bytecode[i] = nil
- i = i + 1
- end
- input.storage.done = i
-end
-
-
--- filename : luat-zip.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-zip'] = 1.001
-
-local format = string.format
-
-if zip and input then
- zip.supported = true
-else
- zip = { }
- zip.supported = false
-end
-
-if not zip.supported then
- if not input then input = { } end -- will go away
+end -- of closure
- function zip.openarchive (...) return nil end -- needed ?
- function zip.closenarchive (...) end -- needed ?
- function input.usezipfile (...) end -- needed ?
+do -- create closure to overcome 200 locals limit
-else
-
- -- zip:///oeps.zip?name=bla/bla.tex
- -- zip:///oeps.zip?tree=tex/texmf-local
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
- local function validzip(str)
- if not str:find("^zip://") then
- return "zip:///" .. str
- else
- return str
- end
- end
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
- zip.archives = { }
- zip.registeredfiles = { }
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
- function zip.openarchive(name)
- if not name or name == "" then
- return nil
- else
- local arch = zip.archives[name]
- if arch then
- return arch
- else
- local full = input.find_file(name) or ""
- local arch = (full ~= "" and zip.open(full)) or false
- zip.archives[name] = arch
- return arch
- end
- end
- end
+<p>How about just forgetting about them?</p>
+--ldx]]--
- function zip.closearchive(name)
- if not name or name == "" and zip.archives[name] then
- zip.close(zip.archives[name])
- zip.archives[name] = nil
- end
- end
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
- -- zip:///texmf.zip?tree=/tex/texmf
- -- zip:///texmf.zip?tree=/tex/texmf-local
- -- zip:///texmf-mine.zip?tree=/tex/texmf-projects
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
- function input.locators.zip(specification) -- where is this used? startup zips (untested)
- specification = input.splitmethod(specification)
- local zipfile = specification.path
- local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
- if input.trace > 0 then
- if zfile then
- input.logger('! zip locator, found: %s',specification.original)
- else
- input.logger('? zip locator, not found: %s',specification.original)
- end
- end
- end
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
- function input.hashers.zip(tag,name)
- input.report("loading zip file %s as %s",name,tag)
- input.usezipfile(tag .."?tree=" .. name)
- end
+local find = string.find
- function input.concatinators.zip(tag,path,name)
- if not path or path == "" then
- return tag .. '?name=' .. name
- else
- return tag .. '?name=' .. path .. "/" .. name
- end
- end
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
- function input.is_readable.zip(name)
- return true
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
end
-
- function input.finders.zip(specification,filetype)
- specification = input.splitmethod(specification)
- if specification.path then
- local q = url.query(specification.query)
- if q.name then
- local zfile = zip.openarchive(specification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('! zip finder, path: %s',specification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- dfile = zfile:close()
- if input.trace > 0 then
- input.logger('+ zip finder, name: %s',q.name)
- end
- return specification.original
- end
- elseif input.trace > 0 then
- input.logger('? zip finder, path %s',specification.path)
- end
- end
- end
- if input.trace > 0 then
- input.logger('- zip finder, name: %s',filename)
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
end
- return unpack(input.finders.notfound)
- end
-
- function input.openers.zip(specification)
- local zipspecification = input.splitmethod(specification)
- if zipspecification.path then
- local q = url.query(zipspecification.query)
- if q.name then
- local zfile = zip.openarchive(zipspecification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('+ zip starter, path: %s',zipspecification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- input.show_open(specification)
- return input.openers.text_opener(specification,dfile,'zip')
- end
- elseif input.trace > 0 then
- input.logger('- zip starter, path %s',zipspecification.path)
- end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
end
- end
- if input.trace > 0 then
- input.logger('- zip opener, name: %s',filename)
- end
- return unpack(input.openers.notfound)
- end
-
- function input.loaders.zip(specification)
- specification = input.splitmethod(specification)
- if specification.path then
- local q = url.query(specification.query)
- if q.name then
- local zfile = zip.openarchive(specification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('+ zip starter, path: %s',specification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- input.show_load(filename)
- if input.trace > 0 then
- input.logger('+ zip loader, name: %s',filename)
- end
- local s = dfile:read("*all")
- dfile:close()
- return true, s, #s
- end
- elseif input.trace > 0 then
- input.logger('- zip starter, path: %s',specification.path)
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
end
- end
- end
- if input.trace > 0 then
- input.logger('- zip loader, name: %s',filename)
- end
- return unpack(input.openers.notfound)
- end
-
- -- zip:///somefile.zip
- -- zip:///somefile.zip?tree=texmf-local -> mount
-
- function input.usezipfile(zipname)
- zipname = validzip(zipname)
- if input.trace > 0 then
- input.logger('! zip use, file: %s',zipname)
- end
- local specification = input.splitmethod(zipname)
- local zipfile = specification.path
- if zipfile and not zip.registeredfiles[zipname] then
- local tree = url.query(specification.query).tree or ""
- if input.trace > 0 then
- input.logger('! zip register, file: %s',zipname)
- end
- local z = zip.openarchive(zipfile)
- if z then
- local instance = input.instance
- if input.trace > 0 then
- input.logger("= zipfile, registering: %s",zipname)
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
end
- input.starttiming(instance)
- input.aux.prepend_hash('zip',zipname,zipfile)
- input.aux.extend_texmf_var(zipname) -- resets hashes too
- zip.registeredfiles[zipname] = z
- instance.files[zipname] = input.aux.register_zip_file(z,tree or "")
- input.stoptiming(instance)
- elseif input.trace > 0 then
- input.logger("? zipfile, unknown: %s",zipname)
- end
- elseif input.trace > 0 then
- input.logger('! zip register, no file: %s',zipname)
- end
- end
-
- function input.aux.register_zip_file(z,tree)
- local files, filter = { }, ""
- if tree == "" then
- filter = "^(.+)/(.-)$"
- else
- filter = "^"..tree.."/(.+)/(.-)$"
- end
- if input.trace > 0 then
- input.logger('= zip filter: %s',filter)
- end
- local register, n = input.aux.register_file, 0
- for i in z:files() do
- local path, name = i.filename:match(filter)
- if path then
- if name and name ~= '' then
- register(files, name, path)
- n = n + 1
- else
- -- directory
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
end
else
- register(files, i.filename, '')
- n = n + 1
- end
- end
- input.logger('= zip entries: %s',n)
- return files
- end
-
-end
-
-
--- filename : luat-zip.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-tex'] = 1.001
-
--- special functions that deal with io
-
-local format = string.format
-
-if texconfig and not texlua then
-
- input.level = input.level or 0
-
- if input.logmode() == 'xml' then
- function input.show_open(name)
- input.level = input.level + 1
- texio.write_nl("<f l='"..input.level.."' n='"..name.."'>")
- end
- function input.show_close(name)
- texio.write("</f> ")
- input.level = input.level - 1
- end
- function input.show_load(name)
- texio.write_nl("<f l='"..(input.level+1).."' n='"..name.."'/>") -- level?
- end
- else
- function input.show_open () end
- function input.show_close() end
- function input.show_load () end
- end
-
- function input.finders.generic(tag,filename,filetype)
- local foundname = input.find_file(filename,filetype)
- if foundname and foundname ~= "" then
- if input.trace > 0 then
- input.logger('+ finder: %s, file: %s', tag,filename)
- end
- return foundname
- else
- if input.trace > 0 then
- input.logger('- finder: %s, file: %s', tag,filename)
- end
- return unpack(input.finders.notfound)
- end
- end
-
- input.filters.dynamic_translator = nil
- input.filters.frozen_translator = nil
- input.filters.utf_translator = nil
-
- function input.openers.text_opener(filename,file_handle,tag)
- local u = unicode.utftype(file_handle)
- local t = { }
- if u > 0 then
- if input.trace > 0 then
- input.logger('+ opener: %s (%s), file: %s',tag,unicode.utfname[u],filename)
- end
- local l
- if u > 2 then
- l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
- else
- l = unicode.utf16_to_utf8(file_handle:read("*a"),u==2)
- end
- file_handle:close()
- t = {
- utftype = u, -- may go away
- lines = l,
- current = 0, -- line number, not really needed
- handle = nil,
- noflines = #l,
- close = function()
- if input.trace > 0 then
- input.logger('= closer: %s (%s), file: %s',tag,unicode.utfname[u],filename)
- end
- input.show_close(filename)
- t = nil
- end,
---~ getline = function(n)
---~ local line = t.lines[n]
---~ if not line or line == "" then
---~ return ""
---~ else
---~ local translator = input.filters.utf_translator
---~ return (translator and translator(line)) or line
---~ end
---~ end,
- reader = function(self)
- self = self or t
- local current, lines = self.current, self.lines
- if current >= #lines then
- return nil
- else
- current = current + 1
- self.current = current
- local line = lines[current]
- if line == "" then
- return ""
- else
- local translator = input.filters.utf_translator
- -- return (translator and translator(line)) or line
- if translator then
- return translator(line)
- else
- return line
- end
- end
- end
- end
- }
- else
- if input.trace > 0 then
- input.logger('+ opener: %s, file: %s',tag,filename)
- end
- -- todo: file;name -> freeze / eerste regel scannen -> freeze
- local filters = input.filters
- t = {
- reader = function(self)
- local line = file_handle:read()
- if line == "" then
- return ""
- end
- local translator = filters.utf_translator
- if translator then
- return translator(line)
- end
- translator = filters.dynamic_translator
- if translator then
- return translator(line)
- end
- return line
- end,
- close = function()
- if input.trace > 0 then
- input.logger('= closer: %s, file: %s',tag,filename)
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
end
- input.show_close(filename)
- file_handle:close()
- t = nil
- end,
- handle = function()
- return file_handle
- end,
- noflines = function()
- t.noflines = io.noflines(file_handle)
- return t.noflines
- end
- }
- end
- return t
- end
-
- function input.openers.generic(tag,filename)
- if filename and filename ~= "" then
- local f = io.open(filename,"r")
- if f then
- input.show_open(filename)
- return input.openers.text_opener(filename,f,tag)
- end
- end
- if input.trace > 0 then
- input.logger('- opener: %s, file: %s',tag,filename)
- end
- return unpack(input.openers.notfound)
- end
-
- function input.loaders.generic(tag,filename)
- if filename and filename ~= "" then
- local f = io.open(filename,"rb")
- if f then
- input.show_load(filename)
- if input.trace > 0 then
- input.logger('+ loader: %s, file: %s',tag,filename)
- end
- local s = f:read("*a")
- garbagecollector.check(s)
- f:close()
- if s then
- return true, s, #s
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
end
end
end
- if input.trace > 0 then
- input.logger('- loader: %s, file: %s',tag,filename)
- end
- return unpack(input.loaders.notfound)
- end
-
- function input.finders.tex(filename,filetype)
- return input.finders.generic('tex',filename,filetype)
end
- function input.openers.tex(filename)
- return input.openers.generic('tex',filename)
- end
- function input.loaders.tex(filename)
- return input.loaders.generic('tex',filename)
- end
-
end
--- callback into the file io and related things; disabling kpse
-
-
-if texconfig and not texlua then do
- -- this is not the right place, because we refer to quite some not yet defined tables, but who cares ...
+end -- of closure
- ctx = ctx or { }
+do -- create closure to overcome 200 locals limit
- function ctx.writestatus(a,b,c,...)
- if c then
- texio.write_nl(("%-15s: %s\n"):format(a,b:format(c,...)))
- else
- texio.write_nl(("%-15s: %s\n"):format(a,b)) -- b can have %'s
- end
- end
+if not modules then modules = { } end modules ['data-lst'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
- -- this will become: ctx.install_statistics(fnc() return ..,.. end) etc
+-- used in mtxrun
- local statusinfo, n = { }, 0
+local find, concat, upper, format = string.find, table.concat, string.upper, string.format
- function ctx.register_statistics(tag,pattern,fnc)
- statusinfo[#statusinfo+1] = { tag, pattern, fnc }
- if #tag > n then n = #tag end
- end
+resolvers.listers = resolvers.listers or { }
- function ctx.memused()
- -- collectgarbage("collect")
- return string.format("%s MB (ctx: %s MB)",math.round(collectgarbage("count")), math.round(status.luastate_bytes/1000))
- end
-
- function ctx.show_statistics() -- todo: move calls
- local loadtime, register_statistics = input.loadtime, ctx.register_statistics
- if caches then
- register_statistics("used config path", "%s", function() return caches.configpath() end)
- register_statistics("used cache path", "%s", function() return caches.temp() or "?" end)
- end
- if status.luabytecodes > 0 and input.storage and input.storage.done then
- register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end)
- end
- if input.instance then
- register_statistics("input load time", "%s seconds", function() return loadtime(input.instance) end)
- end
- if fonts then
- register_statistics("fonts load time","%s seconds", function() return loadtime(fonts) end)
- end
- if xml then
- register_statistics("xml load time", "%s seconds, lpath calls: %s, cached calls: %s", function()
- local stats = xml.statistics()
- return loadtime(xml), stats.lpathcalls, stats.lpathcached
- end)
- register_statistics("lxml load time", "%s seconds preparation, backreferences: %i", function()
- return loadtime(lxml), #lxml.self
- end)
- end
- if mptopdf then
- register_statistics("mps conversion time", "%s seconds", function() return loadtime(mptopdf) end)
- end
- if nodes then
- register_statistics("node processing time", "%s seconds including kernel", function() return loadtime(nodes) end)
- end
- if kernel then
- register_statistics("kernel processing time", "%s seconds", function() return loadtime(kernel) end)
- end
- if attributes then
- register_statistics("attribute processing time", "%s seconds", function() return loadtime(attributes) end)
- end
- if languages then
- register_statistics("language load time", "%s seconds, n=%s", function() return loadtime(languages), languages.hyphenation.n() end)
- end
- if figures then
- register_statistics("graphics processing time", "%s seconds including tex, n=%s", function() return loadtime(figures), figures.n or "?" end)
- end
- if metapost then
- register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return loadtime(metapost), loadtime(mplib), loadtime(metapost.exectime), metapost.n end)
- end
- if status.luastate_bytes and ctx.memused then
- register_statistics("current memory usage", "%s", ctx.memused)
- end
- if nodes then
- register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack
- end
- if status.node_mem_usage then
- register_statistics("node memory usage", "%s", function() return status.node_mem_usage end)
- end
- if languages then
- register_statistics("loaded patterns", "%s", function() return languages.logger.report() end)
- end
- if fonts then
- register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end)
- end
- if xml then -- so we are in mkiv, we need a different check
- register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function()
- input.stoptiming(input.instance)
- local runtime = loadtime(input.instance)
- local shipped = tex.count['nofshipouts']
- local pages = tex.count['realpageno'] - 1
- local persecond = shipped / runtime
- return runtime, pages, shipped, persecond
- end)
- end
- for _, t in ipairs(statusinfo) do
- local tag, pattern, fnc = t[1], t[2], t[3]
- ctx.writestatus("mkiv lua stats", "%s - %s", tag:rpadd(n," "), pattern:format(fnc()))
- end-- input.expanded_path_list("osfontdir")
+local function tabstr(str)
+ if type(str) == 'table' then
+ return concat(str," | ")
+ else
+ return str
end
+end
-end end
-
-if texconfig and not texlua then
-
- texconfig.kpse_init = false
- texconfig.trace_file_names = input.logmode() == 'tex'
- texconfig.max_print_line = 100000
-
- -- if still present, we overload kpse (put it off-line so to say)
-
- input.starttiming(input.instance)
-
- if not input.instance then
-
- if not input.instance then -- prevent a second loading
-
- input.instance = input.reset()
- input.instance.progname = 'context'
- input.instance.engine = 'luatex'
- input.instance.validfile = input.validctxfile
-
- input.load()
-
- end
-
- if callback then
- callback.register('find_read_file' , function(id,name) return input.findtexfile(name) end)
- callback.register('open_read_file' , function( name) return input.opentexfile(name) end)
- end
-
- if callback then
- callback.register('find_data_file' , function(name) return input.findbinfile(name,"tex") end)
- callback.register('find_enc_file' , function(name) return input.findbinfile(name,"enc") end)
- callback.register('find_font_file' , function(name) return input.findbinfile(name,"tfm") end)
- callback.register('find_format_file' , function(name) return input.findbinfile(name,"fmt") end)
- callback.register('find_image_file' , function(name) return input.findbinfile(name,"tex") end)
- callback.register('find_map_file' , function(name) return input.findbinfile(name,"map") end)
- callback.register('find_ocp_file' , function(name) return input.findbinfile(name,"ocp") end)
- callback.register('find_opentype_file' , function(name) return input.findbinfile(name,"otf") end)
- callback.register('find_output_file' , function(name) return name end)
- callback.register('find_pk_file' , function(name) return input.findbinfile(name,"pk") end)
- callback.register('find_sfd_file' , function(name) return input.findbinfile(name,"sfd") end)
- callback.register('find_truetype_file' , function(name) return input.findbinfile(name,"ttf") end)
- callback.register('find_type1_file' , function(name) return input.findbinfile(name,"pfb") end)
- callback.register('find_vf_file' , function(name) return input.findbinfile(name,"vf") end)
-
- callback.register('read_data_file' , function(file) return input.loadbinfile(file,"tex") end)
- callback.register('read_enc_file' , function(file) return input.loadbinfile(file,"enc") end)
- callback.register('read_font_file' , function(file) return input.loadbinfile(file,"tfm") end)
- -- format
- -- image
- callback.register('read_map_file' , function(file) return input.loadbinfile(file,"map") end)
- callback.register('read_ocp_file' , function(file) return input.loadbinfile(file,"ocp") end)
- callback.register('read_opentype_file' , function(file) return input.loadbinfile(file,"otf") end)
- -- output
- callback.register('read_pk_file' , function(file) return input.loadbinfile(file,"pk") end)
- callback.register('read_sfd_file' , function(file) return input.loadbinfile(file,"sfd") end)
- callback.register('read_truetype_file' , function(file) return input.loadbinfile(file,"ttf") end)
- callback.register('read_type1_file' , function(file) return input.loadbinfile(file,"pfb") end)
- callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"vf" ) end)
- end
-
- if input.aleph_mode == nil then environment.aleph_mode = true end -- some day we will drop omega font support
-
- if callback and input.aleph_mode then
- callback.register('find_font_file' , function(name) return input.findbinfile(name,"ofm") end)
- callback.register('read_font_file' , function(file) return input.loadbinfile(file,"ofm") end)
- callback.register('find_vf_file' , function(name) return input.findbinfile(name,"ovf") end)
- callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"ovf") end)
- end
-
- if callback then
- callback.register('find_write_file' , function(id,name) return name end)
- end
-
- if callback and (not config or (#config == 0)) then
- callback.register('find_format_file' , function(name) return name end)
- end
-
- if callback and false then
- for k, v in pairs(callback.list()) do
- if not v then texio.write_nl("<w>callback "..k.." is not set</w>") end
- end
- end
-
- if callback then
-
- input.start_actions = { }
- input.stop_actions = { }
-
- function input.register_start_actions(f) table.insert(input.start_actions, f) end
- function input.register_stop_actions (f) table.insert(input.stop_actions, f) end
-
- --~ callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
- --~ callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end end)
-
- end
-
- if callback then
-
- if input.logmode() == 'xml' then
-
- function input.start_page_number()
- texio.write_nl("<p real='" .. tex.count[0] .. "' page='"..tex.count[1].."' sub='"..tex.count[2].."'")
- end
- function input.stop_page_number()
- texio.write("/>")
- texio.write_nl("")
- end
-
- callback.register('start_page_number' , input.start_page_number)
- callback.register('stop_page_number' , input.stop_page_number )
-
- function input.report_output_pages(p,b)
- texio.write_nl("<v k='pages'>"..p.."</v>")
- texio.write_nl("<v k='bytes'>"..b.."</v>")
- texio.write_nl("")
- end
- function input.report_output_log()
- end
-
- callback.register('report_output_pages', input.report_output_pages)
- callback.register('report_output_log' , input.report_output_log )
-
- function input.start_run()
- texio.write_nl("<?xml version='1.0' standalone='yes'?>")
- texio.write_nl("<job xmlns='www.tug.org/luatex/schemas/context-job.rng'>")
- texio.write_nl("")
- end
- function input.stop_run()
- texio.write_nl("</job>")
- end
- function input.show_statistics()
- for k,v in pairs(status.list()) do
- texio.write_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
- end
+local function list(list,report)
+ local instance = resolvers.instance
+ local pat = upper(pattern or "","")
+ local report = report or texio.write_nl
+ for _,key in pairs(table.sortedkeys(list)) do
+ if instance.pattern == "" or find(upper(key),pat) then
+ if instance.kpseonly then
+ if instance.kpsevars[key] then
+ report(format("%s=%s",key,tabstr(list[key])))
end
-
- table.insert(input.start_actions, input.start_run)
- table.insert(input.stop_actions , input.show_statistics)
- table.insert(input.stop_actions , input.stop_run)
-
else
- table.insert(input.stop_actions , input.show_statistics)
+ report(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
end
-
- callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
- callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end ctx.show_statistics() end)
-
- end
-
- end
-
- if kpse then
-
- function kpse.find_file(filename,filetype,mustexist)
- return input.find_file(filename,filetype,mustexist)
- end
- function kpse.expand_path(variable)
- return input.expand_path(variable)
- end
- function kpse.expand_var(variable)
- return input.expand_var(variable)
end
- function kpse.expand_braces(variable)
- return input.expand_braces(variable)
- end
-
end
-
end
--- program specific configuration (memory settings and alike)
-
-if texconfig and not texlua then
+function resolvers.listers.variables () list(resolvers.instance.variables ) end
+function resolvers.listers.expansions() list(resolvers.instance.expansions) end
- luatex = luatex or { }
-
- luatex.variablenames = {
- 'main_memory', 'extra_mem_bot', 'extra_mem_top',
- 'buf_size','expand_depth',
- 'font_max', 'font_mem_size',
- 'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
- 'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
- 'nest_size', 'param_size', 'save_size', 'stack_size',
- 'trie_size', 'hyph_size', 'max_in_open',
- 'ocp_stack_size', 'ocp_list_size', 'ocp_buf_size'
- }
-
- function luatex.variables()
- local t, x = { }, nil
- for _,v in pairs(luatex.variablenames) do
- x = input.var_value(v)
- if x and x:find("^%d+$") then
- t[v] = tonumber(x)
+function resolvers.listers.configurations(report)
+ local report = report or texio.write_nl
+ local instance = resolvers.instance
+ for _,key in ipairs(table.sortedkeys(instance.kpsevars)) do
+ if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
+ report(format("%s\n",key))
+ for i,c in ipairs(instance.order) do
+ local str = c[key]
+ if str then
+ report(format("\t%s\t%s",i,str))
+ end
end
- end
- return t
- end
-
- function luatex.setvariables(tab)
- for k,v in pairs(luatex.variables()) do
- tab[k] = v
- end
- end
-
- if not luatex.variables_set then
- luatex.setvariables(texconfig)
- luatex.variables_set = true
- end
-
- texconfig.max_print_line = 100000
- texconfig.max_in_open = 127
-
-end
-
--- some tex basics, maybe this will move to ctx
-
-if tex then
-
- local texsprint, texwrite = tex.sprint, tex.write
-
- if not cs then cs = { } end
-
- function cs.def(k,v)
- texsprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}")
- end
-
- function cs.chardef(k,v)
- texsprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax")
- end
-
- function cs.boolcase(b)
- if b then texwrite(1) else texwrite(0) end
- end
-
- function cs.testcase(b)
- if b then
- texsprint(tex.texcatcodes, "\\firstoftwoarguments")
- else
- texsprint(tex.texcatcodes, "\\secondoftwoarguments")
+ report("")
end
end
-
end
-if not modules then modules = { } end modules ['luat-kps'] = {
- version = 1.001,
- comment = "companion to luatools.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This file is used when we want the input handlers to behave like
-<type>kpsewhich</type>. What to do with the following:</p>
-
-<typing>
-{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
-$SELFAUTOLOC : /usr/tex/bin/platform
-$SELFAUTODIR : /usr/tex/bin
-$SELFAUTOPARENT : /usr/tex
-</typing>
-
-<p>How about just forgetting abou them?</p>
---ldx]]--
-
-input = input or { }
-input.suffixes = input.suffixes or { }
-input.formats = input.formats or { }
-
-input.suffixes['gf'] = { '<resolution>gf' }
-input.suffixes['pk'] = { '<resolution>pk' }
-input.suffixes['base'] = { 'base' }
-input.suffixes['bib'] = { 'bib' }
-input.suffixes['bst'] = { 'bst' }
-input.suffixes['cnf'] = { 'cnf' }
-input.suffixes['mem'] = { 'mem' }
-input.suffixes['mf'] = { 'mf' }
-input.suffixes['mfpool'] = { 'pool' }
-input.suffixes['mft'] = { 'mft' }
-input.suffixes['mppool'] = { 'pool' }
-input.suffixes['graphic/figure'] = { 'eps', 'epsi' }
-input.suffixes['texpool'] = { 'pool' }
-input.suffixes['PostScript header'] = { 'pro' }
-input.suffixes['ist'] = { 'ist' }
-input.suffixes['web'] = { 'web', 'ch' }
-input.suffixes['cweb'] = { 'w', 'web', 'ch' }
-input.suffixes['cmap files'] = { 'cmap' }
-input.suffixes['lig files'] = { 'lig' }
-input.suffixes['bitmap font'] = { }
-input.suffixes['MetaPost support'] = { }
-input.suffixes['TeX system documentation'] = { }
-input.suffixes['TeX system sources'] = { }
-input.suffixes['dvips config'] = { }
-input.suffixes['type42 fonts'] = { }
-input.suffixes['web2c files'] = { }
-input.suffixes['other text files'] = { }
-input.suffixes['other binary files'] = { }
-input.suffixes['opentype fonts'] = { 'otf' }
-
-input.suffixes['fmt'] = { 'fmt' }
-input.suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
-
-input.suffixes['pdftex config'] = { }
-input.suffixes['Troff fonts'] = { }
-
-input.suffixes['ls-R'] = { }
-
---[[ldx--
-<p>If you wondered abou tsome of the previous mappings, how about
-the next bunch:</p>
---ldx]]--
-
-input.formats['bib'] = ''
-input.formats['bst'] = ''
-input.formats['mft'] = ''
-input.formats['ist'] = ''
-input.formats['web'] = ''
-input.formats['cweb'] = ''
-input.formats['MetaPost support'] = ''
-input.formats['TeX system documentation'] = ''
-input.formats['TeX system sources'] = ''
-input.formats['Troff fonts'] = ''
-input.formats['dvips config'] = ''
-input.formats['graphic/figure'] = ''
-input.formats['ls-R'] = ''
-input.formats['other text files'] = ''
-input.formats['other binary files'] = ''
-
-input.formats['gf'] = ''
-input.formats['pk'] = ''
-input.formats['base'] = 'MFBASES'
-input.formats['cnf'] = ''
-input.formats['mem'] = 'MPMEMS'
-input.formats['mf'] = 'MFINPUTS'
-input.formats['mfpool'] = 'MFPOOL'
-input.formats['mppool'] = 'MPPOOL'
-input.formats['texpool'] = 'TEXPOOL'
-input.formats['PostScript header'] = 'TEXPSHEADERS'
-input.formats['cmap files'] = 'CMAPFONTS'
-input.formats['type42 fonts'] = 'T42FONTS'
-input.formats['web2c files'] = 'WEB2C'
-input.formats['pdftex config'] = 'PDFTEXCONFIG'
-input.formats['texmfscripts'] = 'TEXMFSCRIPTS'
-input.formats['bitmap font'] = ''
-input.formats['lig files'] = 'LIGFONTS'
-
+end -- of closure
-- end library merge
-- We initialize some characteristics of this program. We need to
@@ -6623,21 +6577,33 @@ own.libs = { -- todo: check which ones are really needed
'l-number.lua',
'l-set.lua',
'l-os.lua',
- 'l-md5.lua',
'l-file.lua',
+ 'l-md5.lua',
'l-url.lua',
'l-dir.lua',
'l-boolean.lua',
'l-unicode.lua',
'l-math.lua',
'l-utils.lua',
- 'luat-lib.lua',
- 'luat-inp.lua',
- 'luat-log.lua',
- 'luat-tmp.lua',
- 'luat-zip.lua',
- 'luat-tex.lua',
- 'luat-kps.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+-- 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-lst.lua', -- lister
}
-- We need this hack till luatex is fixed.
@@ -6674,11 +6640,11 @@ function locate_libs()
end
end
-if not input then
+if not resolvers then
locate_libs()
end
-if not input then
+if not resolvers then
print("")
print("Luatools is unable to start up due to lack of libraries. You may")
print("try to run 'lua luatools.lua --selfmerge' in the path where this")
@@ -6687,63 +6653,65 @@ if not input then
os.exit()
end
-input.instance = input.reset()
-input.verbose = environment.arguments["verbose"] or false
-input.banner = 'LuaTools'
-utils.report = input.report
-
-input.defaultlibs = { -- not all are needed
- 'l-string.lua', 'l-lpeg.lua', 'l-table.lua', 'l-boolean.lua', 'l-number.lua', 'l-set.lua', 'l-unicode.lua',
- 'l-md5.lua', 'l-os.lua', 'l-io.lua', 'l-file.lua', 'l-url.lua', 'l-dir.lua', 'l-utils.lua', 'l-dimen.lua',
- 'luat-lib.lua', 'luat-inp.lua', 'luat-env.lua', 'luat-tmp.lua', 'luat-zip.lua', 'luat-tex.lua'
-}
+logs.setprogram('LuaTools',"TDS Management Tool 1.31",environment.arguments["verbose"] or false)
--- todo: use environment.argument() instead of environment.arguments[]
+local instance = resolvers.reset()
-local instance = input.instance
+resolvers.defaultlibs = { -- not all are needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-boolean.lua',
+ 'l-number.lua',
+ 'l-unicode.lua',
+ 'l-os.lua',
+ 'l-io.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-url.lua',
+ 'l-dir.lua',
+ 'l-utils.lua',
+ 'l-dimen.lua',
+ 'trac-inf.lua',
+ 'trac-tra.lua',
+ 'trac-log.lua',
+ 'luat-env.lua', -- here ?
+ 'data-res.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-tmp.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-pre.lua',
+ 'data-tex.lua',
+ 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-clr.lua',
+ 'data-lua.lua',
+ 'data-ctx.lua',
+ 'luat-fio.lua',
+ 'luat-cnf.lua',
+}
instance.engine = environment.arguments["engine"] or 'luatex'
instance.progname = environment.arguments["progname"] or 'context'
instance.luaname = environment.arguments["luafile"] or "" -- environment.ownname or ""
-instance.lualibs = environment.arguments["lualibs"] or table.concat(input.defaultlibs,",")
+instance.lualibs = environment.arguments["lualibs"] or table.concat(resolvers.defaultlibs,",")
instance.allresults = environment.arguments["all"] or false
instance.pattern = environment.arguments["pattern"] or nil
instance.sortdata = environment.arguments["sort"] or false
instance.kpseonly = not environment.arguments["all"] or false
instance.my_format = environment.arguments["format"] or instance.format
-instance.lsrmode = environment.arguments["lsr"] or false
if type(instance.pattern) == 'boolean' then
- input.report("invalid pattern specification") -- toto, force verbose for one message
+ logs.simple("invalid pattern specification")
instance.pattern = nil
end
-if environment.arguments["trace"] then input.settrace(environment.arguments["trace"]) end
+if environment.arguments["trace"] then resolvers.settrace(environment.arguments["trace"]) end
-if environment.arguments["minimize"] then
- if input.validators.visibility[instance.progname] then
- instance.validfile = input.validators.visibility[instance.progname]
- end
-end
-
-function input.my_prepare_a()
- input.resetconfig()
- input.identify_cnf()
- input.load_lua()
- input.expand_variables()
- input.load_cnf()
- input.expand_variables()
-end
-
-function input.my_prepare_b()
- input.my_prepare_a()
- input.load_hash()
- input.automount()
-end
-
--- barename
-
-if not messages then messages = { } end
+runners = runners or { }
+messages = messages or { }
messages.no_ini_file = [[
There is no lua initialization file found. This file can be forced by the
@@ -6769,21 +6737,18 @@ messages.help = [[
--luafile=str lua inifile (default is <progname>.lua)
--lualibs=list libraries to assemble (optional when --compile)
--compile assemble and compile lua inifile
---mkii force context mkii mode (only for testing, not usable!)
--verbose give a bit more info
---minimize optimize lists for format
--all show all found files
--sort sort cached data
--engine=str target engine
--progname=str format or backend
--pattern=str filter variables
---lsr use lsr and cnf directly
]]
-function input.my_make_format(texname)
- local instance = input.instance
+function runners.make_format(texname)
+ local instance = resolvers.instance
if texname and texname ~= "" then
- if input.usecache then
+ if resolvers.usecache then
local path = file.join(caches.setpath("formats")) -- maybe platform
if path and lfs then
lfs.chdir(path)
@@ -6793,22 +6758,22 @@ function input.my_make_format(texname)
if barename == texname then
texname = texname .. ".tex"
end
- local fullname = input.find_files(texname)[1] or ""
+ local fullname = resolvers.find_files(texname)[1] or ""
if fullname == "" then
- input.report("no tex file with name: %s",texname)
+ logs.simple("no tex file with name: %s",texname)
else
local luaname, lucname, luapath, lualibs = "", "", "", { }
-- the following is optional, since context.lua can also
-- handle this collect and compile business
if environment.arguments["compile"] then
if luaname == "" then luaname = barename end
- input.report("creating initialization file: %s",luaname)
+ logs.simple("creating initialization file: %s",luaname)
luapath = file.dirname(luaname)
if luapath == "" then
luapath = file.dirname(texname)
end
if luapath == "" then
- luapath = file.dirname(input.find_files(texname)[1] or "")
+ luapath = file.dirname(resolvers.find_files(texname)[1] or "")
end
lualibs = string.split(instance.lualibs,",")
luaname = file.basename(barename .. ".lua")
@@ -6818,83 +6783,86 @@ function input.my_make_format(texname)
if lualibs[1] then
local firstlib = file.join(luapath,lualibs[1])
if not lfs.isfile(firstlib) then
- local foundname = input.find_files(lualibs[1])[1]
+ local foundname = resolvers.find_files(lualibs[1])[1]
if foundname then
- input.report("located library path: %s",luapath)
+ logs.simple("located library path: %s",luapath)
luapath = file.dirname(foundname)
end
end
end
- input.report("using library path: %s",luapath)
- input.report("using lua libraries: %s",table.join(lualibs," "))
+ logs.simple("using library path: %s",luapath)
+ logs.simple("using lua libraries: %s",table.join(lualibs," "))
utils.merger.selfcreate(lualibs,luapath,luaname)
- local strip = input.boolean_variable("LUACSTRIP", true)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
if utils.lua.compile(luaname,lucname,false,strip) and io.exists(lucname) then
luaname = lucname
- input.report("using compiled initialization file: %s",lucname)
+ logs.simple("using compiled initialization file: %s",lucname)
else
- input.report("using uncompiled initialization file: %s",luaname)
+ logs.simple("using uncompiled initialization file: %s",luaname)
end
else
for _, v in pairs({instance.luaname, instance.progname, barename}) do
v = string.gsub(v..".lua","%.lua%.lua$",".lua")
if v and (v ~= "") then
- luaname = input.find_files(v)[1] or ""
+ luaname = resolvers.find_files(v)[1] or ""
if luaname ~= "" then
break
end
end
end
end
+ if environment.arguments["noluc"] then
+ luaname = luaname:gsub("%.luc$",".lua") -- make this an option
+ end
if luaname == "" then
- input.reportlines(messages.no_ini_file)
- input.report("texname : %s",texname)
- input.report("luaname : %s",instance.luaname)
- input.report("progname: %s",instance.progname)
- input.report("barename: %s",barename)
+ if logs.verbose then
+ logs.simplelines(messages.no_ini_file)
+ logs.simple("texname : %s",texname)
+ logs.simple("luaname : %s",instance.luaname)
+ logs.simple("progname: %s",instance.progname)
+ logs.simple("barename: %s",barename)
+ end
else
- input.report("using lua initialization file: %s",luaname)
- local mp = dir.glob(file.stripsuffix(file.basename(luaname)).."-*.mem")
+ logs.simple("using lua initialization file: %s",luaname)
+ local mp = dir.glob(file.removesuffix(file.basename(luaname)).."-*.mem")
if mp and #mp > 0 then
for _, name in ipairs(mp) do
- input.report("removing related mplib format %s", file.basename(name))
+ logs.simple("removing related mplib format %s", file.basename(name))
os.remove(name)
end
end
- local flags = { "--ini" }
- if environment.arguments["mkii"] then
- flags[#flags+1] = "--progname=" .. instance.progname
- else
- flags[#flags+1] = "--lua=" .. string.quote(luaname)
- end
+ local flags = {
+ "--ini",
+ "--lua=" .. string.quote(luaname)
+ }
local bs = (os.platform == "unix" and "\\\\") or "\\" -- todo: make a function
local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " " .. bs .. "dump"
- input.report("running command: %s\n",command)
+ logs.simple("running command: %s\n",command)
os.spawn(command)
-- todo: do a dummy run that generates the related metafun and mfplain formats
end
end
else
- input.report("no tex file given")
+ logs.simple("no tex file given")
end
end
-function input.my_run_format(name,data,more)
+function runners.run_format(name,data,more)
-- hm, rather old code here; we can now use the file.whatever functions
if name and (name ~= "") then
local barename = name:gsub("%.%a+$","")
local fmtname = ""
- if input.usecache then
+ if resolvers.usecache then
local path = file.join(caches.setpath("formats")) -- maybe platform
fmtname = file.join(path,barename..".fmt") or ""
end
if fmtname == "" then
- fmtname = input.find_files(barename..".fmt")[1] or ""
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
end
- fmtname = input.clean_path(fmtname)
+ fmtname = resolvers.clean_path(fmtname)
barename = fmtname:gsub("%.%a+$","")
if fmtname == "" then
- input.report("no format with name: %s",name)
+ logs.simple("no format with name: %s",name)
else
local luaname = barename .. ".luc"
local f = io.open(luaname)
@@ -6904,151 +6872,104 @@ function input.my_run_format(name,data,more)
end
if f then
f:close()
- local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. string.quote(more)
- input.report("running command: %s",command)
+ local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. (more ~= "" and string.quote(more) or "")
+ logs.simple("running command: %s",command)
os.spawn(command)
else
- input.report("using format name: %s",fmtname)
- input.report("no luc/lua with name: %s",barename)
- end
- end
- end
-end
-
--- helpers for verbose lists
-
-input.listers = input.listers or { }
-
-local function tabstr(str)
- if type(str) == 'table' then
- return table.concat(str," | ")
- else
- return str
- end
-end
-
-local function list(list)
- local instance = input.instance
- local pat = string.upper(pattern or "","")
- for _,key in pairs(table.sortedkeys(list)) do
- if instance.pattern == "" or string.find(key:upper(),pat) then
- if instance.kpseonly then
- if instance.kpsevars[key] then
- print(format("%s=%s",key,tabstr(list[key])))
- end
- else
- print(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
+ logs.simple("using format name: %s",fmtname)
+ logs.simple("no luc/lua with name: %s",barename)
end
end
end
end
-function input.listers.variables () list(input.instance.variables ) end
-function input.listers.expansions() list(input.instance.expansions) end
-
-function input.listers.configurations()
- local instance = input.instance
- for _,key in pairs(table.sortedkeys(instance.kpsevars)) do
- if not instance.pattern or (instance.pattern=="") or key:find(instance.pattern) then
- print(key.."\n")
- for i,c in ipairs(instance.order) do
- local str = c[key]
- if str then
- print(format("\t%s\t%s",i,str))
- end
- end
- print()
- end
- end
-end
-
-input.report("%s\n",banner)
-
local ok = true
+-- private option --noluc for testing errors in the stub
+
if environment.arguments["find-file"] then
- input.my_prepare_b()
+ resolvers.load()
instance.format = environment.arguments["format"] or instance.format
if instance.pattern then
instance.allresults = true
- input.for_files(input.find_files, { instance.pattern }, instance.my_format)
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
else
- input.for_files(input.find_files, environment.files, instance.my_format)
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
end
elseif environment.arguments["find-path"] then
- input.my_prepare_b()
- local path = input.find_file(environment.files[1], instance.my_format)
- if input.verbose then
- input.report(file.dirname(path))
+ resolvers.load()
+ local path = resolvers.find_file(environment.files[1], instance.my_format)
+ if logs.verbose then
+ logs.simple(file.dirname(path))
else
print(file.dirname(path))
end
elseif environment.arguments["run"] then
- input.my_prepare_a() -- ! no need for loading databases
- input.verbose = true
- input.my_run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
elseif environment.arguments["fmt"] then
- input.my_prepare_a() -- ! no need for loading databases
- input.verbose = true
- input.my_run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
elseif environment.arguments["expand-braces"] then
- input.my_prepare_a()
- input.for_files(input.expand_braces, environment.files)
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_braces, environment.files)
elseif environment.arguments["expand-path"] then
- input.my_prepare_a()
- input.for_files(input.expand_path, environment.files)
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_path, environment.files)
elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then
- input.my_prepare_a()
- input.for_files(input.expand_var, environment.files)
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_var, environment.files)
elseif environment.arguments["show-path"] or environment.arguments["path-value"] then
- input.my_prepare_a()
- input.for_files(input.show_path, environment.files)
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.show_path, environment.files)
elseif environment.arguments["var-value"] or environment.arguments["show-value"] then
- input.my_prepare_a()
- input.for_files(input.var_value, environment.files)
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.var_value, environment.files)
elseif environment.arguments["format-path"] then
- input.my_prepare_b()
- input.report(caches.setpath("format"))
+ resolvers.load()
+ logs.simple(caches.setpath("format"))
elseif instance.pattern then -- brrr
- input.my_prepare_b()
+ resolvers.load()
instance.format = environment.arguments["format"] or instance.format
instance.allresults = true
- input.for_files(input.find_files, { instance.pattern }, instance.my_format)
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
elseif environment.arguments["generate"] then
instance.renewcache = true
- input.verbose = true
- input.my_prepare_b(instance)
+ logs.setverbose(true)
+ resolvers.load()
elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then
- input.my_prepare_b(instance)
- input.verbose = true
- input.my_make_format(environment.files[1] or "")
+ resolvers.load()
+ logs.setverbose(true)
+ runners.make_format(environment.files[1] or "")
elseif environment.arguments["selfmerge"] then
utils.merger.selfmerge(own.name,own.libs,own.list)
elseif environment.arguments["selfclean"] then
utils.merger.selfclean(own.name)
elseif environment.arguments["selfupdate"] then
- input.my_prepare_b()
- input.verbose = true
- input.update_script(own.name,"luatools")
+ resolvers.load()
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"luatools")
elseif environment.arguments["variables"] or environment.arguments["show-variables"] then
- input.my_prepare_a()
- input.listers.variables()
+ resolvers.load("nofiles")
+ resolvers.listers.variables()
elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then
- input.my_prepare_a()
- input.listers.expansions()
+ resolvers.load("nofiles")
+ resolvers.listers.expansions()
elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then
- input.my_prepare_a()
- input.listers.configurations()
+ resolvers.load("nofiles")
+ resolvers.listers.configurations()
elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then
- input.help(banner,messages.help)
+ logs.help(messages.help)
else
- input.my_prepare_b()
- input.for_files(input.find_files, environment.files, instance.my_format)
+ resolvers.load()
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
end
-if input.verbose then
- input.report("")
- input.report("runtime: %0.3f seconds",os.runtime())
+if logs.verbose then
+ logs.simpleline()
+ logs.simple("runtime: %0.3f seconds",os.runtime())
end
if os.platform == "unix" then
diff --git a/scripts/context/lua/mtx-babel.lua b/scripts/context/lua/mtx-babel.lua
index 92b1cd597..8d7765643 100644
--- a/scripts/context/lua/mtx-babel.lua
+++ b/scripts/context/lua/mtx-babel.lua
@@ -385,22 +385,22 @@ do
local structure = environment.argument("structure") or "document"
converter = converter[structure]
if converter then
- input.report("converting '%s' using language '%s' with structure '%s'", filename, language, structure)
+ logs.simple("converting '%s' using language '%s' with structure '%s'", filename, language, structure)
data = converter:match(data)
local newfilename = filename .. ".utf"
io.savedata(newfilename, data)
- input.report("converted data saved in '%s'", newfilename)
+ logs.simple("converted data saved in '%s'", newfilename)
else
- input.report("unknown structure '%s' language '%s'", structure, language)
+ logs.simple("unknown structure '%s' language '%s'", structure, language)
end
else
- input.report("no converter for language '%s'", language)
+ logs.simple("no converter for language '%s'", language)
end
else
- input.report("provide language")
+ logs.simple("provide language")
end
else
- input.report("no data in '%s'",filename)
+ logs.simple("no data in '%s'",filename)
end
end
end
@@ -413,7 +413,7 @@ do
end
-banner = banner .. " | babel conversion tools | version 1.2"
+logs.extendbanner("Babel Conversion Tools 1.2",true)
messages.help = [[
--language=string conversion language (e.g. greek)
@@ -421,10 +421,8 @@ messages.help = [[
--convert convert babel codes into utf
]]
-input.verbose = true
-
if environment.argument("convert") then
scripts.babel.convert(environment.files[1] or "")
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-cache.lua b/scripts/context/lua/mtx-cache.lua
index 0432168ee..a1fbed825 100644
--- a/scripts/context/lua/mtx-cache.lua
+++ b/scripts/context/lua/mtx-cache.lua
@@ -76,7 +76,7 @@ function scripts.cache.list(all)
end)
end
-banner = banner .. " | cache tools "
+logs.extendbanner("Cache Tools 0.10")
messages.help = [[
--purge remove not used files
@@ -93,5 +93,5 @@ elseif environment.argument("erase") then
elseif environment.argument("list") then
scripts.cache.list(environment.argument("all"))
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-chars.lua b/scripts/context/lua/mtx-chars.lua
index f4f751377..d4330ca30 100644
--- a/scripts/context/lua/mtx-chars.lua
+++ b/scripts/context/lua/mtx-chars.lua
@@ -6,38 +6,12 @@ if not modules then modules = { } end modules ['mtx-chars'] = {
license = "see context related readme files"
}
-local format, concat = string.format, table.concat
+local format, concat, utfchar, upper = string.format, table.concat, unicode.utf8.char, string.upper
scripts = scripts or { }
scripts.chars = scripts.chars or { }
-function scripts.chars.stixtomkiv(inname,outname)
- if inname == "" then
- logs.report("aquiring math data","invalid datafilename")
- end
- local f = io.open(inname)
- if not f then
- logs.report("aquiring math data","invalid datafile")
- else
- logs.report("aquiring math data","processing " .. inname)
- if not outname or outname == "" then
- outname = "char-mth.lua"
- end
- local classes = {
- N = "normal",
- A = "alphabetic",
- D = "diacritic",
- P = "punctuation",
- B = "binary",
- R = "relation",
- L = "large",
- O = "opening",
- C = "closing",
- F = "fence"
- }
- local valid, done = false, { }
- local g = io.open(outname,'w')
- g:write([[
+local banner = [[
-- filename : char-mth.lua
-- comment : companion to char-mth.tex (in ConTeXt)
-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
@@ -46,38 +20,70 @@ function scripts.chars.stixtomkiv(inname,outname)
if not versions then versions = { } end versions['char-mth'] = 1.001
if not characters then characters = { } end
- ]])
- g:write(format("\ncharacters.math = {\n"))
- for l in f:lines() do
- if not valid then
- valid = l:find("AMS/TeX name")
- end
- if valid then
- local unicode = l:sub(2,6)
- if unicode:sub(1,1) ~= " " and unicode ~= "" and not done[unicode] then
- local mathclass, adobename, texname = l:sub(57,57) or "", l:sub(13,36) or "", l:sub(84,109) or ""
- texname, adobename = texname:gsub("[\\ ]",""), adobename:gsub("[\\ ]","")
- local t = { }
- if mathclass ~= "" then t[#t+1] = format("mathclass='%s'", classes[mathclass] or "unknown") end
- if adobename ~= "" then t[#t+1] = format("adobename='%s'", adobename ) end
- if texname ~= "" then t[#t+1] = format("texname='%s'" , texname ) end
- if #t > 0 then
- g:write(format("\t[0x%s] = { %s },\n",unicode, concat(t,", ")))
- end
- done[unicode] = true
- end
- end
- end
- if not valid then
- g:write("\t-- The data file is corrupt, invalid or maybe the format has changed.\n")
- logs.report("aquiring math data","problems with data table")
- else
- logs.report("aquiring math data","table saved in " .. outname)
- end
- g:write("}\n")
- g:close()
- f:close()
- end
+]]
+
+--~ function scripts.chars.stixtomkiv(inname,outname)
+--~ if inname == "" then
+--~ logs.report("aquiring math data","invalid datafilename")
+--~ end
+--~ local f = io.open(inname)
+--~ if not f then
+--~ logs.report("aquiring math data","invalid datafile")
+--~ else
+--~ logs.report("aquiring math data","processing " .. inname)
+--~ if not outname or outname == "" then
+--~ outname = "char-mth.lua"
+--~ end
+--~ local classes = {
+--~ N = "normal",
+--~ A = "alphabetic",
+--~ D = "diacritic",
+--~ P = "punctuation",
+--~ B = "binary",
+--~ R = "relation",
+--~ L = "large",
+--~ O = "opening",
+--~ C = "closing",
+--~ F = "fence"
+--~ }
+--~ local valid, done = false, { }
+--~ local g = io.open(outname,'w')
+--~ g:write(banner)
+--~ g:write(format("\ncharacters.math = {\n"))
+--~ for l in f:lines() do
+--~ if not valid then
+--~ valid = l:find("AMS/TeX name")
+--~ end
+--~ if valid then
+--~ local unicode = l:sub(2,6)
+--~ if unicode:sub(1,1) ~= " " and unicode ~= "" and not done[unicode] then
+--~ local mathclass, adobename, texname = l:sub(57,57) or "", l:sub(13,36) or "", l:sub(84,109) or ""
+--~ texname, adobename = texname:gsub("[\\ ]",""), adobename:gsub("[\\ ]","")
+--~ local t = { }
+--~ if mathclass ~= "" then t[#t+1] = format("mathclass='%s'", classes[mathclass] or "unknown") end
+--~ if adobename ~= "" then t[#t+1] = format("adobename='%s'", adobename ) end
+--~ if texname ~= "" then t[#t+1] = format("texname='%s'" , texname ) end
+--~ if #t > 0 then
+--~ g:write(format("\t[0x%s] = { %s },\n",unicode, concat(t,", ")))
+--~ end
+--~ done[unicode] = true
+--~ end
+--~ end
+--~ end
+--~ if not valid then
+--~ g:write("\t-- The data file is corrupt, invalid or maybe the format has changed.\n")
+--~ logs.report("aquiring math data","problems with data table")
+--~ else
+--~ logs.report("aquiring math data","table saved in " .. outname)
+--~ end
+--~ g:write("}\n")
+--~ g:close()
+--~ f:close()
+--~ end
+--~ end
+
+function scripts.chars.stixtomkiv(inname,outname)
+ logs.report("we no longer use this options but use our own tables instead")
end
local banner_pdf_1 = [[
@@ -95,7 +101,7 @@ local banner_pdf_2 = [[
]]
function scripts.chars.makepdfr()
- local chartable = input.find_file("char-def.lua") or ""
+ local chartable = resolvers.find_file("char-def.lua") or ""
if chartable ~= "" then
dofile(chartable)
if characters and characters.data then
@@ -117,93 +123,189 @@ function scripts.chars.makepdfr()
end
end
-local banner_utf_1 = [[
-% filename : enco-utf.tex
-% comment : generated by mtxrun --script chars --utf
-% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
-% copyright: PRAGMA ADE / ConTeXt Development Team
-% license : see context related readme files
+local banner_utf_module = [[
+%% filename : %s
+%% comment : generated by mtxrun --script chars --xtx
+%% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+%% copyright: PRAGMA ADE / ConTeXt Development Team
+%% license : see context related readme files
+]]
-\ifx\setcclcucx\undefined
+local banner_utf_mappings = [[
- \def\setcclcucx #1 #2 #3 %
- {\global\catcode"#1=11
- \global\lccode "#1="#2
- \global\uccode "#1="#3 }
+% lc/uc/catcode mappings
-\fi
]]
-local banner_utf_2 = [[
+local banner_utf_patch = [[
-% lc/uc/catcode mappings
+% patch needed for turkish
+\setXTXcharcodes "201C "201C "201C
+\setXTXcharcodes "201D "201D "201D
]]
-local banner_utf_3 = [[
+local banner_utf_names = [[
% named characters mapped onto utf (\\char is needed for accents)
]]
-local banner_utf_4 = [[
+local banner_utf_classes = [[
+
+% some character classes for xetex; seems to be rather hard coded, these numbers
+% and also a mix of several classes; here we do linebreaks
+
+]]
+
+local banner_utf_finish = [[
\endinput
]]
+local xtxclasses = {
+ id = 1,
+ ex = 3,
+ is = 3,
+ cm = 256,
+ op = 2,
+ ns = 3,
+ cl = 3,
+}
+
function scripts.chars.makeencoutf()
- local chartable = input.find_file("char-def.lua") or ""
+ local chartable = resolvers.find_file("char-def.lua") or ""
if chartable ~= "" then
dofile(chartable)
- if characters and characters.data then
- local f = io.open("enco-utf.tex", 'w')
+ local function open(name,banner)
+ local f = io.open(name,'w')
+ if f then
+ logs.simple("writing '%s'",name)
+ f:write(format(banner_utf_module,name))
+ f:write(banner)
+ f:write()
+ return f
+ end
+ end
+ local function close(f)
+ f:write(banner_utf_finish)
+ f:close()
+ end
+ local data = characters and characters.data
+ if data then
+ local list = table.sortedkeys(characters.data)
+ local f = open("xetx-utf.tex",banner_utf_mappings)
if f then
- f:write(banner_utf_1)
- f:write(banner_utf_2)
- local list = table.sortedkeys(characters.data)
- local length = 0
for i=1,#list do
local code = list[i]
if code <= 0xFFFF then
- local chr = characters.data[code]
+ local chr = data[code]
local cc = chr.category
if cc == 'll' or cc == 'lu' or cc == 'lt' then
if not chr.lccode then chr.lccode = code end
if not chr.uccode then chr.uccode = code end
- f:write(format("\\setcclcucx %04X %04X %04X %% %s\n",code,chr.lccode,chr.uccode,chr.description))
+ f:write(format('\\setXTXcharcodes "%05X "%05X "%05X %% %s\n',code,chr.lccode,chr.uccode,chr.description))
+ end
+ end
+ end
+ f:write("\n")
+ for i=1,#list do
+ local code = list[i]
+ local chr = data[code]
+ if chr and chr.range then
+ local cc = chr.category
+ if cc == 'lo' then
+ f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharcodes\\recurselevel\\recurselevel\\recurselevel}\n',code,chr.range))
end
- if #(chr.contextname or "") > length then
+ end
+ end
+ f:write(banner_utf_patch)
+ close(f)
+ end
+ local f = open("xetx-chr.tex",banner_utf_names)
+ if f then
+ local length = 0
+ for i=1,#list do
+ local code = list[i]
+ if code > 0x5B and code <= 0xFFFF then
+ local chr = data[code]
+ if chr and #(chr.contextname or "") > length then
length = #chr.contextname
end
end
end
- f:write(banner_utf_3)
for i=1,#list do
local code = list[i]
if code > 0x5B and code <= 0xFFFF then
- local chr = characters.data[code]
- if chr.contextname then
- local ch = char(code)
---~ if ch:find("[~#$%%^&{}\\]") then
- f:write(format("\\def\\%s{\\char\"%04X } %% %s: %s\n", chr.contextname:rpadd(length," "), code, chr.description, ch))
---~ else
---~ f:write(format("\\def\\%s{%s} %% %s\n", chr.contextname:rpadd(length," "), ch,chr.description))
---~ end
+ local chr = data[code]
+ if chr and chr.contextname then
+ local ch = utfchar(code)
+ f:write(format("\\def\\%s{\\char\"%05X } %% %s: %s\n", chr.contextname:rpadd(length," "), code, chr.description, ch))
end
end
end
- f:write(banner_utf_4)
- f:close()
+ close(f)
+ end
+ local f = open("xetx-cls.tex",banner_utf_classes)
+ if f then
+ for k, v in pairs(xtxclasses) do
+ f:write(format("\\defineXTXcharinjectionclass[lb:%s]\n",k))
+ end
+ f:write("\n")
+ local i_first, i_last, i_clb = nil, nil, nil
+ local function flush()
+ if i_first then
+ if i_first == i_last then
+ f:write(format('\\dosetXTXcharacterclass{"%05X}{lb:%s}\n',i_first,i_clb))
+ else
+ f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',i_first,i_last,i_clb))
+ end
+ end
+ i_first, i_last, i_clb = nil, nil, nil
+ end
+ for i=1,#list do
+ local code = list[i]
+ local code_next = list[i+1]
+ local chr = data[code]
+ local chr_next = data[code_next]
+ local clb = chr and chr.linebreak
+ local lbc = xtxclasses[clb]
+ if not lbc then
+ flush()
+ elseif clb == i_clb then
+ if i_first then
+ i_last = code
+ else
+ i_first, i_last, i_clb = code, code, clb
+ end
+ else
+ flush()
+ i_first, i_last, i_clb = code, code, clb
+ end
+ end
+ flush()
+ f:write("\n")
+ for i=1,#list do
+ local code = list[i]
+ local chr = data[code]
+ if chr and chr.range then
+ local lbc = chr.linebreak
+ if xtxclasses[lbc] then
+ f:write(format('\\dofastrecurse{"%05X}{"%05X}{1}{\\dosetXTXcharacterclass\\fastrecursecounter{lb:%s}}\n',code,chr.range,lbc))
+ end
+ end
+ end
+ close(f)
end
end
end
end
-banner = banner .. " | character tools "
+logs.extendbanner("Character Tools 0.10")
messages.help = [[
--stix convert stix table to math table
---utf generate enco-utf.tex (used by xetex)
+--xtx generate xetx-*.tex (used by xetex)
--pdf generate pdfr-def.tex (used by pdftex)
]]
@@ -211,10 +313,10 @@ if environment.argument("stix") then
local inname = environment.files[1] or ""
local outname = environment.files[2] or ""
scripts.chars.stixtomkiv(inname,outname)
-elseif environment.argument("utf") then
+elseif environment.argument("xtx") then
scripts.chars.makeencoutf()
elseif environment.argument("pdf") then
scripts.chars.makepdfr()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-check.lua b/scripts/context/lua/mtx-check.lua
index 7c44fa855..6be7f2765 100644
--- a/scripts/context/lua/mtx-check.lua
+++ b/scripts/context/lua/mtx-check.lua
@@ -34,7 +34,7 @@ do
end
end
- local P, S, V, C, CP, CC = lpeg.P, lpeg.S, lpeg.V, lpeg.C, lpeg.Cp, lpeg.Cc
+ local P, R, S, V, C, CP, CC = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.C, lpeg.Cp, lpeg.Cc
local i_m, d_m = P("$"), P("$$")
local l_s, r_s = P("["), P("]")
@@ -49,22 +49,27 @@ do
local line = newline / function() validator.n = validator.n + 1 end
- local grammar = P { "tokens",
- ["tokens"] = (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0,
- ["whatever"] = line + esc * 1 + C(P("%") * (1-line)^0),
- ["grouped"] = CP() * C(l_g * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_g - r_g))^0 * r_g) * CC("group") / progress,
- ["setup"] = CP() * C(l_s * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_s - r_s))^0 * r_s) * CC("setup") / progress,
- ["display"] = CP() * C(d_m * (V("whatever") + V("grouped") + (1 - d_m))^0 * d_m) * CC("display") / progress,
- ["inline"] = CP() * C(i_m * (V("whatever") + V("grouped") + (1 - i_m))^0 * i_m) * CC("inline") / progress,
- ["errors"] = (V("gerror") + V("serror") + V("derror") + V("ierror")) * true,
- ["gerror"] = CP() * (l_g + r_g) * CC("grouping") / message,
- ["serror"] = CP() * (l_s + r_g) * CC("setup error") / message,
- ["derror"] = CP() * d_m * CC("display math error") / message,
- ["ierror"] = CP() * i_m * CC("inline math error") / message,
- }
+ -- local grammar = P { "tokens",
+ -- ["tokens"] = (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0,
+ -- ["whatever"] = line + esc * 1 + C(P("%") * (1-line)^0),
+ -- ["grouped"] = CP() * C(l_g * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_g - r_g))^0 * r_g) * CC("group") / progress,
+ -- ["setup"] = CP() * C(l_s * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_s - r_s))^0 * r_s) * CC("setup") / progress,
+ -- ["display"] = CP() * C(d_m * (V("whatever") + V("grouped") + (1 - d_m))^0 * d_m) * CC("display") / progress,
+ -- ["inline"] = CP() * C(i_m * (V("whatever") + V("grouped") + (1 - i_m))^0 * i_m) * CC("inline") / progress,
+ -- ["errors"] = (V("gerror") + V("serror") + V("derror") + V("ierror")) * true,
+ -- ["gerror"] = CP() * (l_g + r_g) * CC("grouping") / message,
+ -- ["serror"] = CP() * (l_s + r_g) * CC("setup error") / message,
+ -- ["derror"] = CP() * d_m * CC("display math error") / message,
+ -- ["ierror"] = CP() * i_m * CC("inline math error") / message,
+ -- }
+
+ local startluacode = P("\\startluacode")
+ local stopluacode = P("\\stopluacode")
+
+ local somecode = startluacode * (1-stopluacode)^1 * stopluacode
local grammar = P { "tokens",
- ["tokens"] = (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0,
+ ["tokens"] = (V("ignore") + V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + V("errors") + 1)^0,
["whatever"] = line + esc * 1 + C(P("%") * (1-line)^0),
["grouped"] = l_g * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_g - r_g))^0 * r_g,
["setup"] = l_s * (V("whatever") + V("grouped") + V("setup") + V("display") + V("inline") + (1 - l_s - r_s))^0 * r_s,
@@ -75,6 +80,7 @@ do
["serror"] = CP() * (l_s + r_g) * CC("setup error") / message,
["derror"] = CP() * d_m * CC("display math error") / message,
["ierror"] = CP() * i_m * CC("inline math error") / message,
+ ["ignore"] = somecode,
}
function validator.check(str)
@@ -117,19 +123,16 @@ function scripts.checker.check(filename)
end
end
-
-banner = banner .. " | tex check tools "
+logs.extendbanner("Syntax Checking 0.10",true)
messages.help = [[
--convert check tex file for errors
]]
-input.verbose = true
-
if environment.argument("check") then
scripts.checker.check(environment.files[1])
elseif environment.argument("help") then
- input.help(banner,messages.help)
+ logs.help(messages.help)
elseif environment.files[1] then
scripts.checker.check(environment.files[1])
end
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 7d5eb7e80..2bae51501 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -23,30 +23,6 @@ function io.copydata(fromfile,tofile)
io.savedata(tofile,io.loaddata(fromfile) or "")
end
--- luat-inp
-
-function input.locate_format(name) -- move this to core / luat-xxx
- local barename, fmtname = name:gsub("%.%a+$",""), ""
- if input.usecache then
- local path = file.join(caches.setpath("formats")) -- maybe platform
- fmtname = file.join(path,barename..".fmt") or ""
- end
- if fmtname == "" then
- fmtname = input.find_files(barename..".fmt")[1] or ""
- end
- fmtname = input.clean_path(fmtname)
- if fmtname ~= "" then
- barename = fmtname:gsub("%.%a+$","")
- local luaname, lucname = barename .. ".lua", barename .. ".luc"
- if lfs.isfile(lucname) then
- return barename, luaname
- elseif lfs.isfile(luaname) then
- return barename, luaname
- end
- end
- return nil, nil
-end
-
-- ctx
ctxrunner = { }
@@ -135,15 +111,15 @@ do
elseif ctxdata.ctxname then
ctlname = file.replacesuffix(ctxdata.ctxname,'ctl')
else
- input.report("invalid ctl name: %s",ctlname or "?")
+ logs.simple("invalid ctl name: %s",ctlname or "?")
return
end
end
if table.is_empty(ctxdata.prepfiles) then
- input.report("nothing prepared, no ctl file saved")
+ logs.simple("nothing prepared, no ctl file saved")
os.remove(ctlname)
else
- input.report("saving logdata in: %s",ctlname)
+ logs.simple("saving logdata in: %s",ctlname)
f = io.open(ctlname,'w')
if f then
f:write("<?xml version='1.0' standalone='yes'?>\n\n")
@@ -188,8 +164,8 @@ do
ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex')
ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx')
- input.report("jobname: %s",ctxdata.jobname)
- input.report("ctxname: %s",ctxdata.ctxname)
+ logs.simple("jobname: %s",ctxdata.jobname)
+ logs.simple("ctxname: %s",ctxdata.ctxname)
-- mtxrun should resolve kpse: and file:
@@ -206,7 +182,7 @@ do
end
end
- if not found and defaultname and defaultname ~= "" and file.exists(defaultname) then
+ if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then
usedname, found = defaultname, true
end
@@ -236,7 +212,7 @@ do
ctxdata.flags = ctxrunner.reflag(ctxdata.flags)
for _, message in ipairs(ctxdata.messages) do
- input.report("ctx comment: %s", xml.tostring(message))
+ logs.simple("ctx comment: %s", xml.tostring(message))
end
xml.each(ctxdata.xmldata,"ctx:value[@name='job']", function(ek,e,k)
@@ -326,10 +302,10 @@ do
-- potential optimization: when mtxrun run internal
command = xml.text(command)
command = ctxrunner.justtext(command) -- command is still xml element here
- input.report("command: %s",command)
+ logs.simple("command: %s",command)
local result = os.spawn(command) or 0
if result > 0 then
- input.report("error, return code: %s",result)
+ logs.simple("error, return code: %s",result)
end
if ctxdata.runlocal then
oldfile = file.basename(oldfile)
@@ -340,11 +316,11 @@ do
file.syncmtimes(oldfile,newfile)
ctxdata.prepfiles[oldfile] = true
else
- input.report("error, check target location of new file: %s", newfile)
+ logs.simple("error, check target location of new file: %s", newfile)
ctxdata.prepfiles[oldfile] = false
end
else
- input.report("old file needs no preprocessing")
+ logs.simple("old file needs no preprocessing")
ctxdata.prepfiles[oldfile] = lfs.isfile(newfile)
end
end
@@ -362,7 +338,8 @@ end
-- rest
scripts.context.multipass = {
- suffixes = { ".tuo", ".tuc" },
+-- suffixes = { ".tuo", ".tuc" },
+ suffixes = { ".tuc" },
nofruns = 8,
}
@@ -394,6 +371,7 @@ scripts.context.backends = {
function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,currentrun,finalrun)
-- take jobname from ctx
+ jobname = file.removesuffix(jobname)
local f = io.open(jobname..".top","w")
if f then
local function someflag(flag)
@@ -433,74 +411,124 @@ function scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,curr
local function setalways(format,...)
f:write(format:format(...),"\n")
end
+ --
+ setalways("%% runtime options files (command line driven)")
+ --
setalways("\\unprotect")
- setvalue('output' , "\\setupoutput[%s]", scripts.context.backends, 'pdftex')
- setalways( "\\setupsystem[\\c!n=%s,\\c!m=%s]", kindofrun or 0, currentrun or 0)
- setalways( "\\setupsystem[\\c!type=%s]",os.platform)
+ --
+ setalways("%% special commands, mostly for the ctx development team")
+ --
+ if environment.argument("dumpdelta") then
+ setalways("\\tracersdumpdelta")
+ elseif environment.argument("dumphash") then
+ setalways("\\tracersdumphash")
+ end
+ setalways("%% feedback and basic job control")
+ if type(environment.argument("track")) == "string" then
+ setvalue ("track" , "\\enabletrackers[%s]")
+ end
+ setfixed ("timing" , "\\usemodule[timing]")
setfixed ("batchmode" , "\\batchmode")
setfixed ("nonstopmode" , "\\nonstopmode")
setfixed ("tracefiles" , "\\tracefilestrue")
+ setfixed ("nostats" , "\\nomkivstatistics")
setfixed ("paranoid" , "\\def\\maxreadlevel{1}")
- setvalues("modefile" , "\\readlocfile{%s}{}{}")
+ --
+ setalways("%% handy for special styles")
+ --
+ setalways("\\startluacode")
+ setalways("document = document or { }")
+ setalways(table.serialize(environment.arguments, "document.arguments"))
+ setalways(table.serialize(environment.files, "document.files"))
+ setalways("\\stopluacode")
+ --
+ setalways("%% process info")
+ --
+ setalways( "\\setupsystem[\\c!n=%s,\\c!m=%s]", kindofrun or 0, currentrun or 0)
+ setalways( "\\setupsystem[\\c!type=%s]",os.platform)
setvalue ("inputfile" , "\\setupsystem[inputfile=%s]")
setvalue ("result" , "\\setupsystem[file=%s]")
setvalues("path" , "\\usepath[%s]")
+ setvalue ("setuppath" , "\\setupsystem[\\c!directory={%s}]")
+ setvalue ("randomseed" , "\\setupsystem[\\c!random=%s]")
+ setvalue ("arguments" , "\\setupenv[%s]")
+ setalways("%% modes")
+ setvalues("modefile" , "\\readlocfile{%s}{}{}")
+ setvalues("mode" , "\\enablemode[%s]", true)
+ if ctxdata then
+ setvalues(ctxdata.modes, "\\enablemode[%s]")
+ end
+ --
+ setalways("%% options (not that important)")
+ --
+ setalways("\\startsetups *runtime:options")
+ setvalue ('output' , "\\setupoutput[%s]", scripts.context.backends, 'pdftex')
setfixed ("color" , "\\setupcolors[\\c!state=\\v!start]")
- -- setfixed ("nompmode" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics
- -- setfixed ("nomprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics
- -- setfixed ("automprun" , "\\runMPgraphicsfalse") -- obsolete, we assume runtime mp graphics
- setfixed ("fast" , "\\fastmode\n")
- setfixed ("silentmode" , "\\silentmode\n")
- setfixed ("nostats" , "\\nomkivstatistics\n")
setvalue ("separation" , "\\setupcolors[\\c!split=%s]")
- setvalue ("setuppath" , "\\setupsystem[\\c!directory={%s}]")
setfixed ("noarrange" , "\\setuparranging[\\v!disable]")
if environment.argument('arrange') and not finalrun then
setalways( "\\setuparranging[\\v!disable]")
end
- setvalue ("randomseed" , "\\setupsystem[\\c!random=%s]")
- setvalue ("arguments" , "\\setupenv[%s]")
- -- singular and plural
- setvalues("mode" , "\\enablemode[%s]", true)
+ setalways("\\stopsetups")
+ --
+ setalways("%% styles and modules")
+ --
+ setalways("\\startsetups *runtime:modules")
setvalues("filter" , "\\useXMLfilter[%s]", true)
setvalues("usemodule" , "\\usemodule[%s]", true)
setvalues("environment" , "\\environment %s ", true)
- -- ctx stuff
if ctxdata then
- setvalues(ctxdata.modes, "\\enablemode[%s]")
setvalues(ctxdata.modules, "\\usemodule[%s]")
setvalues(ctxdata.environments, "\\environment %s ")
end
- -- done
- setalways("\\protect")
- setalways("\\endinput")
+ setalways("\\stopsetups")
+ --
+ setalways("%% done")
+ --
+ setalways("\\protect \\endinput")
f:close()
end
end
function scripts.context.multipass.copyluafile(jobname)
- io.savedata(jobname..".tuc",io.loaddata(jobname..".tua") or "")
-end
-
-function scripts.context.multipass.copytuifile(jobname)
- local f, g = io.open(jobname..".tui"), io.open(jobname..".tuo",'w')
- if f and g then
- g:write("% traditional utility file, only commands written by mtxrun/context\n%\n")
- for line in f:lines() do
- if line:find("^c ") then
- g:write((line:gsub("^c ","")),"%\n")
- end
- end
- g:write("\\endinput\n")
- f:close()
- g:close()
+-- io.savedata(jobname..".tuc",io.loaddata(jobname..".tua") or "")
+ local tuaname, tucname = jobname..".tua", jobname..".tuc"
+ if lfs.isfile(tuaname) then
+ os.remove(tucname)
+ os.rename(tuaname,tucname)
end
end
+-- obsolete:
+--
+-- function scripts.context.multipass.copytuifile(jobname)
+-- local tuiname, tuoname = jobname .. ".tui", jobname .. ".tuo"
+-- if lfs.isfile(tuiname) then
+-- local f, g = io.open(tuiname), io.open(tuoname,'w')
+-- if f and g then
+-- g:write("% traditional utility file, only commands written by mtxrun/context\n%\n")
+-- for line in f:lines() do
+-- if line:find("^c ") then
+-- g:write((line:gsub("^c ","")),"%\n")
+-- end
+-- end
+-- g:write("\\endinput\n")
+-- f:close()
+-- g:close()
+-- end
+-- else
+-- -- os.remove(tuoname)
+-- end
+-- end
+
scripts.context.xmlsuffixes = table.tohash {
"xml",
}
+scripts.context.luasuffixes = table.tohash {
+ "lua",
+}
+
scripts.context.beforesuffixes = {
"tuo", "tuc"
}
@@ -518,12 +546,17 @@ scripts.context.interfaces = {
it = "cont-it",
ro = "cont-ro",
pe = "cont-pe",
+ -- for taco and me
+ -- xp = "cont-xp",
}
scripts.context.defaultformats = {
"cont-en",
"cont-nl",
+-- "cont-xp",
"mptopdf",
+-- "metatex",
+ "metafun",
"plain"
}
@@ -532,7 +565,7 @@ local function analyze(filename)
if f then
local t = { }
local line = f:read("*line") or ""
- local preamble = line:match("^%% *(.*)$")
+ local preamble = line:match("[\254\255]*%%%s+(.+)$") -- there can be an utf bomb in front
if preamble then
for key, value in preamble:gmatch("(%S+)=(%S+)") do
t[key] = value
@@ -541,42 +574,53 @@ local function analyze(filename)
elseif line:find("^<?xml ") then
t.type = "xml"
end
+ if not t.engine then
+ t.engine = 'luatex'
+ end
f:close()
return t
end
return nil
end
-function scripts.context.run(ctxdata)
- local function makestub(format,filename)
- local stubname = file.replacesuffix(file.basename(filename),'run')
- local f = io.open(stubname,'w')
- if f then
- f:write("\\starttext\n")
- f:write(string.format(format,filename),"\n")
- f:write("\\stoptext\n")
- f:close()
- filename = stubname
- end
- return filename
+local function makestub(format,filename)
+ local stubname = file.replacesuffix(file.basename(filename),'run')
+ local f = io.open(stubname,'w')
+ if f then
+ f:write("\\starttext\n")
+ f:write(string.format(format,filename),"\n")
+ f:write("\\stoptext\n")
+ f:close()
+ filename = stubname
end
+ return filename
+end
+
+function scripts.context.run(ctxdata,filename)
+ -- filename overloads environment.files
+ local files = (filename and { filename }) or environment.files
if ctxdata then
-- todo: interface
for k,v in pairs(ctxdata.flags) do
environment.setargument(k,v)
end
end
- local files = environment.files
if #files > 0 then
- input.identify_cnf()
- input.load_cnf()
- input.expand_variables()
+ --
local interface = environment.argument("interface")
-- todo: environment.argument("interface","en")
interface = (type(interface) == "string" and interface) or "en"
--
local formatname = scripts.context.interfaces[interface] or "cont-en"
- local formatfile, scriptfile = input.locate_format(formatname)
+ local formatfile, scriptfile = resolvers.locate_format(formatname)
+ -- this catches the command line
+ if not formatfile or not scriptfile then
+ logs.simple("warning: no format found, forcing remake (commandline driven)")
+ scripts.context.generate()
+ scripts.context.make(formatname)
+ formatfile, scriptfile = resolvers.locate_format(formatname)
+ end
+ --
if formatfile and scriptfile then
for _, filename in ipairs(files) do
local basename, pathname = file.basename(filename), file.dirname(filename)
@@ -584,137 +628,275 @@ function scripts.context.run(ctxdata)
if pathname == "" then
filename = "./" .. filename
end
+ -- look at the first line
local a = analyze(filename)
- if a then
- if a.interface and a.interface ~= interface then
+ if a and (a.engine == 'pdftex' or a.engine == 'xetex' or environment.argument("pdftex") or environment.argument("xetex")) then
+ local texexec = resolvers.find_file("texexec.rb") or ""
+ if texexec ~= "" then
+ local command = string.format("ruby %s %s",texexec,environment.reconstruct_commandline(environment.arguments_after))
+ os.exec(command)
+ end
+ else
+ if a and a.interface and a.interface ~= interface then
formatname = scripts.context.interfaces[a.interface] or formatname
- formatfile, scriptfile = input.locate_format(formatname)
+ formatfile, scriptfile = resolvers.locate_format(formatname)
end
- end
- -- we default to mkiv xml !
- if scripts.context.xmlsuffixes[file.extname(filename) or "?"] or environment.argument("forcexml") then
- if environment.argument("mkii") then
- filename = makestub("\\processXMLfilegrouped{%s}",filename)
- else
- filename = makestub("\\xmlprocess{\\xmldocument}{%s}{}",filename)
+ -- this catches the command line
+ if not formatfile or not scriptfile then
+ logs.simple("warning: no format found, forcing remake (source driven)")
+ scripts.context.generate()
+ scripts.context.make(formatname)
+ formatfile, scriptfile = resolvers.locate_format(formatname)
end
- end
- --
- -- todo: also other stubs
- --
- local resultname, oldbase, newbase = environment.argument("result"), "", ""
- if type(resultname) == "string" then
- oldbase = file.removesuffix(jobname)
- newbase = file.removesuffix(resultname)
- if oldbase ~= newbase then
- for _, suffix in pairs(scripts.context.beforesuffixes) do
- local oldname = file.addsuffix(oldbase,suffix)
- local newname = file.addsuffix(newbase,suffix)
- local tmpname = "keep-"..oldname
- os.remove(tmpname)
- os.rename(oldname,tmpname)
- os.remove(oldname)
- os.rename(newname,oldname)
+ if formatfile and scriptfile then
+ -- we default to mkiv xml !
+ local suffix = file.extname(filename) or "?"
+ if scripts.context.xmlsuffixes[suffix] or environment.argument("forcexml") then
+ if environment.argument("mkii") then
+ filename = makestub("\\processXMLfilegrouped{%s}",filename)
+ else
+ filename = makestub("\\xmlprocess{\\xmldocument}{%s}{}",filename)
+ end
+ elseif scripts.context.luasuffixes[suffix] then
+ filename = makestub("\\ctxlua{dofile('%s')}",filename)
end
- else
- resultname = nil
- end
- else
- resultname = nil
- end
- --
- if environment.argument("autopdf") then
- os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(filename,"pdf")))
- if resultname then
- os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(resultname,"pdf")))
- end
- end
- --
- local flags = { }
- if environment.argument("batchmode") then
- flags[#flags+1] = "--interaction=batchmode"
- end
- flags[#flags+1] = "--fmt=" .. string.quote(formatfile)
- flags[#flags+1] = "--lua=" .. string.quote(scriptfile)
- local command = string.format("luatex %s %s", table.concat(flags," "), string.quote(filename))
- local oldhash, newhash = scripts.context.multipass.hashfiles(jobname), { }
- local once = environment.argument("once")
- local maxnofruns = (once and 1) or scripts.context.multipass.nofruns
- for i=1,maxnofruns do
- -- 1:first run, 2:successive run, 3:once, 4:last of maxruns
- local kindofrun = (once and 3) or (i==1 and 1) or (i==maxnofruns and 4) or 2
- scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,false) -- kindofrun, currentrun, final
- input.report("run %s: %s",i,command)
- local returncode, errorstring = os.spawn(command)
- if not returncode then
- input.report("fatal error, message: %s",errorstring or "?")
- os.exit(1)
- break
- elseif returncode > 0 then
- input.report("fatal error, code: %s",returncode or "?")
- os.exit(returncode)
- break
- else
- scripts.context.multipass.copyluafile(jobname)
- scripts.context.multipass.copytuifile(jobname)
- newhash = scripts.context.multipass.hashfiles(jobname)
- if scripts.context.multipass.changed(oldhash,newhash) then
- oldhash = newhash
+ --
+ -- todo: also other stubs
+ --
+ local resultname, oldbase, newbase = environment.argument("result"), "", ""
+ if type(resultname) == "string" then
+ oldbase = file.removesuffix(jobname)
+ newbase = file.removesuffix(resultname)
+ if oldbase ~= newbase then
+ for _, suffix in pairs(scripts.context.beforesuffixes) do
+ local oldname = file.addsuffix(oldbase,suffix)
+ local newname = file.addsuffix(newbase,suffix)
+ local tmpname = "keep-"..oldname
+ os.remove(tmpname)
+ os.rename(oldname,tmpname)
+ os.remove(oldname)
+ os.rename(newname,oldname)
+ end
+ else
+ resultname = nil
+ end
else
- break
+ resultname = nil
+ end
+ --
+ if environment.argument("autopdf") then
+ os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(filename,"pdf")))
+ if resultname then
+ os.spawn(string.format('pdfclose --file "%s" 2>&1', file.replacesuffix(resultname,"pdf")))
+ end
+ end
+ --
+ local okay = statistics.check_fmt_status(formatfile)
+ if okay ~= true then
+ logs.simple("warning: %s, forcing remake",tostring(okay))
+ scripts.context.generate()
+ scripts.context.make(formatname)
+ end
+ --
+ local flags = { }
+ if environment.argument("batchmode") then
+ flags[#flags+1] = "--interaction=batchmode"
+ end
+ flags[#flags+1] = "--fmt=" .. string.quote(formatfile)
+ flags[#flags+1] = "--lua=" .. string.quote(scriptfile)
+ flags[#flags+1] = "--backend=pdf"
+ local command = string.format("luatex %s %s", table.concat(flags," "), string.quote(filename))
+ local oldhash, newhash = scripts.context.multipass.hashfiles(jobname), { }
+ local once = environment.argument("once")
+ local maxnofruns = (once and 1) or scripts.context.multipass.nofruns
+ local arrange = environment.argument("arrange")
+ for i=1,maxnofruns do
+ -- 1:first run, 2:successive run, 3:once, 4:last of maxruns
+ local kindofrun = (once and 3) or (i==1 and 1) or (i==maxnofruns and 4) or 2
+ scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,false) -- kindofrun, currentrun, final
+ logs.simple("run %s: %s",i,command)
+ local returncode, errorstring = os.spawn(command)
+ --~ if returncode == 3 then
+ --~ scripts.context.generate()
+ --~ scripts.context.make(formatname)
+ --~ returncode, errorstring = os.spawn(command)
+ --~ if returncode == 3 then
+ --~ logs.simple("fatal error, return code 3, message: %s",errorstring or "?")
+ --~ os.exit(1)
+ --~ end
+ --~ end
+ if not returncode then
+ logs.simple("fatal error, no return code, message: %s",errorstring or "?")
+ os.exit(1)
+ break
+ elseif returncode > 0 then
+ logs.simple("fatal error, return code: %s",returncode or "?")
+ os.exit(returncode)
+ break
+ else
+ scripts.context.multipass.copyluafile(jobname)
+ -- scripts.context.multipass.copytuifile(jobname)
+ newhash = scripts.context.multipass.hashfiles(jobname)
+ if scripts.context.multipass.changed(oldhash,newhash) then
+ oldhash = newhash
+ else
+ break
+ end
+ end
+ end
+ --
+ if arrange then
+ local kindofrun = 3
+ scripts.context.multipass.makeoptionfile(jobname,ctxdata,kindofrun,i,true) -- kindofrun, currentrun, final
+ logs.simple("arrange run: %s",command)
+ local returncode, errorstring = os.spawn(command)
+ if not returncode then
+ logs.simple("fatal error, no return code, message: %s",errorstring or "?")
+ os.exit(1)
+ elseif returncode > 0 then
+ logs.simple("fatal error, return code: %s",returncode or "?")
+ os.exit(returncode)
+ end
+ end
+ --
+ if environment.argument("purge") then
+ scripts.context.purge_job(filename)
+ elseif environment.argument("purgeall") then
+ scripts.context.purge_job(filename,true)
+ end
+ --
+ os.remove(jobname..".top")
+ --
+ if resultname then
+ for _, suffix in pairs(scripts.context.aftersuffixes) do
+ local oldname = file.addsuffix(oldbase,suffix)
+ local newname = file.addsuffix(newbase,suffix)
+ local tmpname = "keep-"..oldname
+ os.remove(newname)
+ os.rename(oldname,newname)
+ os.rename(tmpname,oldname)
+ end
+ logs.simple("result renamed to: %s",newbase)
+ end
+ --
+ if environment.argument("purge") then
+ scripts.context.purge_job(resultname)
+ elseif environment.argument("purgeall") then
+ scripts.context.purge_job(resultname,true)
+ end
+ --
+ if environment.argument("autopdf") then
+ if resultname then
+ os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(resultname,"pdf")))
+ else
+ os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(filename,"pdf")))
+ end
+ end
+ --
+ if environment.argument("timing") then
+ logs.line()
+ logs.simple("you can process (timing) statistics with:",jobname)
+ logs.line()
+ logs.simple("context --extra=timing '%s'",jobname)
+ logs.simple("mtxrun --script timing --xhtml [--launch --remove] '%s'",jobname)
+ logs.line()
end
- end
- end
- --
- -- todo: extra arrange run
- --
- if environment.argument("purge") then
- scripts.context.purge_job(filename)
- elseif environment.argument("purgeall") then
- scripts.context.purge_job(filename,true)
- end
- --
- if resultname then
- for _, suffix in pairs(scripts.context.aftersuffixes) do
- local oldname = file.addsuffix(oldbase,suffix)
- local newname = file.addsuffix(newbase,suffix)
- local tmpname = "keep-"..oldname
- os.remove(newname)
- os.rename(oldname,newname)
- os.rename(tmpname,oldname)
- end
- input.report("result renamed to: %s",newbase)
- end
- if environment.argument("autopdf") then
- if resultname then
- os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(resultname,"pdf")))
else
- os.spawn(string.format('pdfopen --file "%s" 2>&1', file.replacesuffix(filename,"pdf")))
+ if formatname then
+ logs.simple("error, no format found with name: %s, skipping",formatname)
+ else
+ logs.simple("error, no format found (provide formatname or interface)")
+ end
+ break
end
end
- --
end
else
- input.verbose = true
- input.report("error, no format found with name: %s",formatname)
+ if formatname then
+ logs.simple("error, no format found with name: %s, aborting",formatname)
+ else
+ logs.simple("error, no format found (provide formatname or interface)")
+ end
end
end
end
-function scripts.context.make()
- local list = (environment.files[1] and environment.files) or scripts.context.defaultformats
+function scripts.context.pipe()
+ -- context --pipe
+ -- context --pipe --purge --dummyfile=whatever.tmp
+ local interface = environment.argument("interface")
+ interface = (type(interface) == "string" and interface) or "en"
+ local formatname = scripts.context.interfaces[interface] or "cont-en"
+ local formatfile, scriptfile = resolvers.locate_format(formatname)
+ if not formatfile or not scriptfile then
+ logs.simple("warning: no format found, forcing remake (commandline driven)")
+ scripts.context.generate()
+ scripts.context.make(formatname)
+ formatfile, scriptfile = resolvers.locate_format(formatname)
+ end
+ if formatfile and scriptfile then
+ local okay = statistics.check_fmt_status(formatfile)
+ if okay ~= true then
+ logs.simple("warning: %s, forcing remake",tostring(okay))
+ scripts.context.generate()
+ scripts.context.make(formatname)
+ end
+ local flags = {
+ "--interaction=scrollmode",
+ "--fmt=" .. string.quote(formatfile),
+ "--lua=" .. string.quote(scriptfile),
+ "--backend=pdf",
+ }
+ local filename = environment.argument("dummyfile") or ""
+ if filename == "" then
+ filename = "\\relax"
+ logs.simple("entering scrollmode, end job with \\end")
+ else
+ filename = file.addsuffix(filename,"tmp")
+ io.savedata(filename,"\\relax")
+ scripts.context.multipass.makeoptionfile(filename,{ flags = flags },3,1,false) -- kindofrun, currentrun, final
+ logs.simple("entering scrollmode using '%s' with optionfile, end job with \\end",filename)
+ end
+ local command = string.format("luatex %s %s", table.concat(flags," "), string.quote(filename))
+ os.spawn(command)
+ if environment.argument("purge") then
+ scripts.context.purge_job(filename)
+ elseif environment.argument("purgeall") then
+ scripts.context.purge_job(filename,true)
+ os.remove(filename)
+ end
+ else
+ if formatname then
+ logs.simple("error, no format found with name: %s, aborting",formatname)
+ else
+ logs.simple("error, no format found (provide formatname or interface)")
+ end
+ end
+end
+
+function scripts.context.make(name)
+ local runners = {
+ "luatools --make --compile ",
+ (environment.argument("pdftex") and "mtxrun texexec.rb --make --pdftex ") or false,
+ (environment.argument("xetex") and "mtxrun texexec.rb --make --xetex " ) or false,
+ }
+ local list = (name and { name }) or (environment.files[1] and environment.files) or scripts.context.defaultformats
for _, name in ipairs(list) do
name = scripts.context.interfaces[name] or name
- local command = "luatools --make --compile " .. name
- input.report("running command: %s",command)
- os.spawn(command)
+ for _, runner in ipairs(runners) do
+ if runner then
+ local command = runner .. name
+ logs.simple("running command: %s",command)
+ os.spawn(command)
+ end
+ end
end
end
function scripts.context.generate()
-- hack, should also be a shared function
local command = "luatools --generate "
- input.report("running command: %s",command)
+ logs.simple("running command: %s",command)
os.spawn(command)
end
@@ -725,23 +907,81 @@ function scripts.context.ctx()
scripts.context.run(ctxdata)
end
+function scripts.context.autoctx()
+ local ctxdata = nil
+ local files = (filename and { filename }) or environment.files
+ local firstfile = #files > 0 and files[1]
+ if firstfile and file.extname(firstfile) == "xml" then
+ local f = io.open(firstfile)
+ if f then
+ local chunk = f:read(512) or ""
+ f:close()
+ local ctxname = string.match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>")
+ if ctxname then
+ ctxdata = ctxrunner.new()
+ ctxdata.jobname = firstfile
+ ctxrunner.manipulate(ctxdata,ctxname)
+ end
+ end
+ end
+ scripts.context.run(ctxdata)
+end
+
+-- todo: quite after first image
+
+local template = [[
+ \starttext
+ \startMPpage %% %s
+ input "%s" ;
+ \stopMPpage
+ \stoptext
+]]
+
+local loaded = false
+
+function scripts.context.metapost()
+ local filename = environment.files[1] or ""
+--~ local tempname = "mtx-context-metapost.tex"
+--~ local tempdata = string.format(template,"metafun",filename)
+--~ io.savedata(tempname,tempdata)
+--~ environment.files[1] = tempname
+--~ environment.setargument("result",file.removesuffix(filename))
+--~ environment.setargument("once",true)
+--~ scripts.context.run()
+ if not loaded then
+ dofile(resolvers.find_file("mlib-run.lua"))
+ loaded = true
+ commands = commands or { }
+ commands.writestatus = logs.report
+ end
+ local formatname = environment.arguments("format") or "metafun"
+ if formatname == "" or type(format) == "boolean" then
+ formatname = "metafun"
+ end
+ if environment.arguments("svg") then
+ metapost.directrun(formatname,filename,"svg")
+ else
+ metapost.directrun(formatname,filename,"mps")
+ end
+end
+
function scripts.context.version()
- local name = input.find_file("context.tex")
+ local name = resolvers.find_file("context.tex")
if name ~= "" then
- input.report("main context file: %s",name)
+ logs.simple("main context file: %s",name)
local data = io.loaddata(name)
if data then
local version = data:match("\\edef\\contextversion{(.-)}")
if version then
- input.report("current version: %s",version)
+ logs.simple("current version: %s",version)
else
- input.report("context version: unknown, no timestamp found")
+ logs.simple("context version: unknown, no timestamp found")
end
else
- input.report("context version: unknown, load error")
+ logs.simple("context version: unknown, load error")
end
else
- input.report("main context file: unknown, 'context.tex' not found")
+ logs.simple("main context file: unknown, 'context.tex' not found")
end
end
@@ -780,6 +1020,7 @@ local function purge_file(dfile,cfile)
end
function scripts.context.purge_job(jobname,all)
+ jobname = file.basename(jobname)
local filebase = file.removesuffix(jobname)
local deleted = { }
for _, suffix in ipairs(obsolete_results) do
@@ -794,7 +1035,7 @@ function scripts.context.purge_job(jobname,all)
end
end
if #deleted > 0 then
- input.report("purged files: %s", table.join(deleted,", "))
+ logs.simple("purged files: %s", table.join(deleted,", "))
end
end
@@ -815,56 +1056,260 @@ function scripts.context.purge(all)
end
end
if #deleted > 0 then
- input.report("purged files: %s", table.join(deleted,", "))
+ logs.simple("purged files: %s", table.join(deleted,", "))
end
end
--~ purge_for_files("test",true)
--~ purge_all_files()
+local function touch(name,pattern)
+ local name = resolvers.find_file(name)
+ local olddata = io.loaddata(name)
+ if olddata then
+ local oldversion, newversion = "", os.date("%Y.%m.%d %H:%M")
+ local newdata, ok = olddata:gsub(pattern,function(pre,mid,post)
+ oldversion = mid
+ return pre .. newversion .. post
+ end)
+ if ok > 0 then
+ local backup = file.replacesuffix(name,"tmp")
+ os.remove(backup)
+ os.rename(name,backup)
+ io.savedata(name,newdata)
+ return true, oldversion, newversion, name
+ else
+ return false
+ end
+ end
+end
+
function scripts.context.touch()
if environment.argument("expert") then
- local function touch(name,pattern)
- local name = input.find_file(name)
- local olddata = io.loaddata(name)
- if olddata then
- local oldversion, newversion = "", os.date("%Y.%M.%d %H:%m")
- local newdata, ok = olddata:gsub(pattern,function(pre,mid,post)
- oldversion = mid
- return pre .. newversion .. post
- end)
- if ok > 0 then
- local backup = file.replacesuffix(name,"tmp")
- os.remove(backup)
- os.rename(name,backup)
- io.savedata(name,newdata)
- return true, oldversion, newversion, name
- else
- return false
- end
- end
- end
local done, oldversion, newversion, foundname = touch("context.tex", "(\\edef\\contextversion{)(.-)(})")
if done then
- input.report("old version : %s", oldversion)
- input.report("new version : %s", newversion)
- input.report("touched file: %s", foundname)
+ logs.simple("old version : %s", oldversion)
+ logs.simple("new version : %s", newversion)
+ logs.simple("touched file: %s", foundname)
local ok, _, _, foundname = touch("cont-new.tex", "(\\newcontextversion{)(.-)(})")
if ok then
- input.report("touched file: %s", foundname)
+ logs.simple("touched file: %s", foundname)
+ end
+ local ok, _, _, foundname = touch("cont-xp.tex", "(\\edef\\contextversion{)(.-)(})")
+ if ok then
+ logs.simple("touched file: %s", foundname)
+ end
+ end
+ end
+end
+
+-- extras
+
+function scripts.context.extras(pattern)
+ local found = resolvers.find_file("context.tex")
+ if found == "" then
+ logs.simple("unknown extra: %s", extra)
+ else
+ pattern = file.join(dir.expand_name(file.dirname(found)),string.format("mtx-context-%s.tex",pattern or "*"))
+ local list = dir.glob(pattern)
+ if not extra or extra == "" then
+ logs.extendbanner("extras")
+ else
+ logs.extendbanner(extra)
+ end
+ for k,v in ipairs(list) do
+ local data = io.loaddata(v) or ""
+ data = string.match(data,"begin help(.-)end help")
+ if data then
+ local h = { string.format("extra: %s (%s)",string.gsub(v,"^.*mtx%-context%-(.-)%.tex$","%1"),v) }
+ for s in string.gmatch(data,"%% *(.-)[\n\r]") do
+ h[#h+1] = s
+ end
+ logs.help(table.concat(h,"\n"),"nomoreinfo")
+ end
+ end
+ end
+end
+
+function scripts.context.extra()
+ local extra = environment.argument("extra")
+ if type(extra) == "string" then
+ if environment.argument("help") then
+ scripts.context.extras(extra)
+ else
+ local fullextra = extra
+ if not string.find(fullextra,"mtx%-context%-") then
+ fullextra = "mtx-context-" .. extra
+ end
+ local foundextra = resolvers.find_file(fullextra)
+ if foundextra == "" then
+ scripts.context.extras()
+ return
+ else
+ logs.simple("processing extra: %s", foundextra)
end
+ environment.setargument("purgeall",true)
+ local result = environment.setargument("result") or ""
+ if result == "" then
+ environment.setargument("result","context-extra")
+ end
+ scripts.context.run(nil,foundextra)
end
+ else
+ scripts.context.extras()
end
end
+-- todo: we need to do a dummy run
+
+function scripts.context.track()
+ environment.files = { "m-track" }
+ scripts.context.multipass.nofruns = 1
+ scripts.context.run()
+ -- maybe filter from log
+end
+
function scripts.context.timed(action)
- input.starttiming(scripts.context)
- action()
- input.stoptiming(scripts.context)
- input.report("total runtime: %s",input.elapsedtime(scripts.context))
+ statistics.timed(action)
end
-banner = banner .. " | context tools "
+local zipname = "cont-tmf.zip"
+local mainzip = "http://www.pragma-ade.com/context/latest/" .. zipname
+local validtrees = { "texmf-local", "texmf-context" }
+
+function zip.loaddata(zipfile,filename) -- should be in zip lib
+ local f = zipfile:open(filename)
+ if f then
+ local data = f:read("*a")
+ f:close()
+ return data
+ end
+ return nil
+end
+
+function scripts.context.update()
+ local force = environment.argument("force")
+ local socket = require("socket")
+ local http = require("socket.http")
+ local basepath = resolvers.find_file("context.tex") or ""
+ if basepath == "" then
+ logs.simple("quiting, no 'context.tex' found")
+ return
+ end
+ local basetree = basepath.match(basepath,"^(.-)tex/context/base/context.tex$") or ""
+ if basetree == "" then
+ logs.simple("quiting, no proper tds structure (%s)",basepath)
+ return
+ end
+ local function is_okay(basetree)
+ for _, tree in next, validtrees do
+ local pattern = string.gsub(tree,"%-","%%-")
+ if basetree:find(pattern) then
+ return tree
+ end
+ end
+ return false
+ end
+ local okay = is_okay(basetree)
+ if not okay then
+ logs.simple("quiting, tree '%s' is protected",okay)
+ return
+ else
+ logs.simple("updating tree '%s'",okay)
+ end
+ if not lfs.chdir(basetree) then
+ logs.simple("quiting, unable to change to '%s'",okay)
+ return
+ end
+ logs.simple("fetching '%s'",mainzip)
+ local latest = http.request(mainzip)
+ if not latest then
+ logs.simple("context tree '%s' can be updated, use --force",okay)
+ return
+ end
+ io.savedata("cont-tmf.zip",latest)
+ if false then
+ -- variant 1
+ os.execute("mtxrun --script unzip cont-tmf.zip")
+ else
+ -- variant 2
+ local zipfile = zip.open(zipname)
+ if not zipfile then
+ logs.simple("quiting, unable to open '%s'",zipname)
+ return
+ end
+ local newfile = zip.loaddata(zipfile,"tex/context/base/context.tex")
+ if not newfile then
+ logs.simple("quiting, unable to open '%s'","context.tex")
+ return
+ end
+ local oldfile = io.loaddata(resolvers.find_file("context.tex")) or ""
+ local function versiontonumber(what,str)
+ local version = str:match("\\edef\\contextversion{(.-)}") or ""
+ local year, month, day, hour, minute = str:match("\\edef\\contextversion{(%d+)%.(%d+)%.(%d+) *(%d+)%:(%d+)}")
+ if year and minute then
+ local time = os.time { year=year,month=month,day=day,hour=hour,minute=minute}
+ logs.simple("%s version: %s (%s)",what,version,time)
+ return time
+ else
+ logs.simple("%s version: %s (unknown)",what,version)
+ return nil
+ end
+ end
+ local oldversion = versiontonumber("old",oldfile)
+ local newversion = versiontonumber("new",newfile)
+ if not oldversion or not newversion then
+ logs.simple("quiting, version cannot be determined")
+ return
+ elseif oldversion == newversion then
+ logs.simple("quiting, your current version is up-to-date")
+ return
+ elseif oldversion > newversion then
+ logs.simple("quiting, your current version is newer")
+ return
+ end
+ for k in zipfile:files() do
+ local filename = k.filename
+ if filename:find("/$") then
+ lfs.mkdir(filename)
+ else
+ local data = zip.loaddata(zipfile,filename)
+ if data then
+ if force then
+ io.savedata(filename,data)
+ end
+ logs.simple(filename)
+ end
+ end
+ end
+ for _, scriptname in next, { "luatools.lua", "mtxrun.lua" } do
+ local oldscript = resolvers.find_file(scriptname) or ""
+ if oldscript ~= "" and is_okay(oldscript) then
+ local newscript = "./scripts/context/lua/" .. scriptname
+ local data = io.loaddata(newscript) or ""
+ if data ~= "" then
+ logs.simple("replacing script '%s' by '%s'",oldscript,newscript)
+ if force then
+ io.savedata(oldscript,data)
+ end
+ end
+ else
+ logs.simple("keeping script '%s'",oldscript)
+ end
+ end
+ if force then
+ os.execute("context --generate")
+ os.execute("context --make")
+ end
+ end
+ if force then
+ logs.simple("context tree '%s' has been updated",okay)
+ else
+ logs.simple("context tree '%s' can been updated (use --force)",okay)
+ end
+end
+
+logs.extendbanner("ConTeXt Tools 0.51",true)
messages.help = [[
--run process (one or more) files (default action)
@@ -877,41 +1322,82 @@ messages.help = [[
--once only one run
--purge(all) purge files (--pattern=...)
--result=name rename result to given name
+--arrange run extra arrange pass
--expert expert options
--interface use specified user interface
]]
messages.expert = [[
-expert options: also provide --expert
+expert options:
+
+--touch update context version number (remake needed afterwards, also provide --expert)
+--update update context from website (not to be confused with contextgarden)
+--profile profile job (use: mtxrun --script profile --analyse)
+--track show/set tracker variables
+--timing generate timing and statistics overview
+--extra=name process extra (mtx-context-<name> in distribution)
+]]
+
+messages.private = [[
+private options:
---touch update context version (remake needed afterwards)
+--dumphash dump hash table afterwards
+--dumpdelta dump hash table afterwards (only new entries)
]]
-input.verbose = true
+messages.special = [[
+special options:
+
+--pdftex process file with texexec using pdftex
+--xetex process file with texexec using xetex
+
+--pipe don't check for file and enter scroll mode (--dummyfile=whatever.tmp)
+]]
if environment.argument("once") then
scripts.context.multipass.nofruns = 1
end
+if environment.argument("profile") then
+ os.setenv("MTX_PROFILE_RUN","YES")
+end
+
if environment.argument("run") then
- scripts.context.timed(scripts.context.run)
-elseif environment.argument("make") then
- scripts.context.timed(scripts.context.make)
-elseif environment.argument("generate") then
- scripts.context.timed(scripts.context.generate)
+-- scripts.context.timed(scripts.context.run)
+ scripts.context.timed(scripts.context.autoctx)
+elseif environment.argument("make") or environment.argument("generate") then
+ scripts.context.timed(function()
+ if environment.argument("generate") then
+ scripts.context.generate()
+ end
+ if environment.argument("make") then
+ scripts.context.make()
+ end
+ end)
elseif environment.argument("ctx") then
scripts.context.timed(scripts.context.ctx)
+elseif environment.argument("mp") or environment.argument("metapost") then
+ scripts.context.timed(scripts.context.metapost)
elseif environment.argument("version") then
scripts.context.version()
elseif environment.argument("touch") then
scripts.context.touch()
+elseif environment.argument("update") then
+ scripts.context.update()
elseif environment.argument("expert") then
- input.help(banner,messages.expert)
+ logs.help(table.join({ messages.expert, messages.private, messages.special },"\n"))
+elseif environment.argument("extra") then
+ scripts.context.extra()
elseif environment.argument("help") then
- input.help(banner,messages.help)
+ logs.help(messages.help)
+elseif environment.argument("track") and type(environment.argument("track")) == "boolean" then
+ scripts.context.track()
elseif environment.files[1] then
- scripts.context.timed(scripts.context.run)
+-- scripts.context.timed(scripts.context.run)
+ scripts.context.timed(scripts.context.autoctx)
+elseif environment.argument("pipe") then
+ scripts.context.timed(scripts.context.pipe)
elseif environment.argument("purge") then
-- only when no filename given, supports --pattern
scripts.context.purge()
@@ -919,6 +1405,9 @@ elseif environment.argument("purgeall") then
-- only when no filename given, supports --pattern
scripts.context.purge(true)
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
+if environment.argument("profile") then
+ os.setenv("MTX_PROFILE_RUN","NO")
+end
diff --git a/scripts/context/lua/mtx-convert.lua b/scripts/context/lua/mtx-convert.lua
index eca050f29..cf1d640c5 100644
--- a/scripts/context/lua/mtx-convert.lua
+++ b/scripts/context/lua/mtx-convert.lua
@@ -51,7 +51,7 @@ do
dir.mkdirs(outputpath)
local tmpname = file.replacesuffix(newname,"tmp")
local command = graphics.converters[suffix](oldname,tmpname)
- input.report("command: %s",command)
+ logs.simple("command: %s",command)
io.flush()
os.spawn(command)
os.remove(newname)
@@ -88,7 +88,7 @@ function scripts.convert.convertall()
end
end
-banner = banner .. " | graphic conversion tools "
+logs.extendbanner("Graphic Conversion Tools 0.10",true)
messages.help = [[
--convertall convert all graphics on path
@@ -98,10 +98,8 @@ messages.help = [[
--delay time between sweeps
]]
-input.verbose = true
-
if environment.argument("convertall") then
scripts.convert.convertall()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua
index ef9e37258..befba924e 100644
--- a/scripts/context/lua/mtx-fonts.lua
+++ b/scripts/context/lua/mtx-fonts.lua
@@ -6,7 +6,11 @@ if not modules then modules = { } end modules ['mtx-fonts'] = {
license = "see context related readme files"
}
-dofile(input.find_file("font-syn.lua"))
+if not fontloader then fontloader = fontforge end
+
+dofile(resolvers.find_file("font-otp.lua","tex"))
+dofile(resolvers.find_file("font-syn.lua","tex"))
+dofile(resolvers.find_file("font-mis.lua","tex"))
scripts = scripts or { }
scripts.fonts = scripts.fonts or { }
@@ -15,57 +19,55 @@ function scripts.fonts.reload(verbose)
fonts.names.load(true,verbose)
end
+function scripts.fonts.names(name)
+ name = name or "luatex-fonts-names.lua"
+ fonts.names.identify(true)
+ local data = fonts.names.data
+ if data then
+ data.fallback_mapping = nil
+ logs.report("fontnames","saving names in '%s'",name)
+ io.savedata(name,table.serialize(data,true))
+ elseif lfs.isfile(name) then
+ os.remove(name)
+ end
+end
+
local function showfeatures(v,n,f,s,t)
- local iv = input.verbose
- input.verbose = true
- input.report("fontname: %s",v)
- input.report("fullname: %s",n)
- input.report("filename: %s",f)
- if t == "otf" or t == "ttf" then
- local filename = input.find_file(f,t) or ""
- if filename ~= "" then
- local ff = fontforge.open(filename)
- if ff then
- local data = fontforge.to_table(ff)
- fontforge.close(ff)
- local features = { }
- local function collect(what)
- if data[what] then
- for _, d in ipairs(data[what]) do
- if d.features then
- for _, df in ipairs(d.features) do
- features[df.tag] = features[df.tag] or { }
- for _, ds in ipairs(df.scripts) do
- features[df.tag][ds.script] = features[df.tag][ds.script] or { }
- for _, lang in ipairs(ds.langs) do
- features[df.tag][ds.script][lang] = true
- end
- end
- end
- end
+ logs.simple("fontname: %s",v)
+ logs.simple("fullname: %s",n)
+ logs.simple("filename: %s",f)
+ local features = fonts.get_features(f,t)
+ if features then
+ for what, v in table.sortedpairs(features) do
+ local data = features[what]
+ if data and next(data) then
+ logs.simple()
+ logs.simple("%s features:",what)
+ logs.simple()
+ logs.simple("feature script languages")
+ logs.simple()
+ for f,ff in table.sortedpairs(data) do
+ local done = false
+ for s, ss in table.sortedpairs(ff) do
+ if s == "*" then s = "all" end
+ if ss ["*"] then ss["*"] = nil ss.all = true end
+ if done then
+ f = ""
+ else
+ done = true
end
- end
- end
- collect('gsub')
- collect('gpos')
- input.report("")
- for _, f in ipairs(table.sortedkeys(features)) do
- local ff = features[f]
- for _, s in ipairs(table.sortedkeys(ff)) do
- local ss = ff[s]
- input.report("feature: %s, script: %s, language: %s",f:lower(),s:lower(),(table.concat(table.sortedkeys(ss), " ")):lower())
+ logs.simple("% -8s % -8s % -8s",f,s,table.concat(table.sortedkeys(ss), " "))
end
end
end
end
end
- input.report("")
- input.verbose = iv
+ logs.reportline()
end
function scripts.fonts.list(pattern,reload,all,info)
if reload then
- input.report("fontnames, reloading font database")
+ logs.simple("fontnames, reloading font database")
end
-- make a function for this
pattern = pattern:lower()
@@ -81,7 +83,7 @@ function scripts.fonts.list(pattern,reload,all,info)
--
local t = fonts.names.list(pattern,reload)
if reload then
- input.report("fontnames, done\n\n")
+ logs.simple("fontnames, done\n\n")
end
if t then
local s, w = table.sortedkeys(t), { 0, 0, 0 }
@@ -112,51 +114,52 @@ function scripts.fonts.save(name,sub)
local function save(savename,fontblob)
if fontblob then
savename = savename:lower() .. ".lua"
- input.report("fontsave, saving data in %s",savename)
- table.tofile(savename,fontforge.to_table(fontblob),"return")
- fontforge.close(fontblob)
+ logs.simple("fontsave, saving data in %s",savename)
+ table.tofile(savename,fontloader.to_table(fontblob),"return")
+ fontloader.close(fontblob)
end
end
if name and name ~= "" then
- local filename = input.find_file(name) -- maybe also search for opentype
+ local filename = resolvers.find_file(name) -- maybe also search for opentype
if filename and filename ~= "" then
local suffix = file.extname(filename)
if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' then
- local fontinfo = fontforge.info(filename)
+ local fontinfo = fontloader.info(filename)
if fontinfo then
+ logs.simple("font: %s located as %s",name,filename)
if fontinfo[1] then
for _, v in ipairs(fontinfo) do
- save(v.fontname,fontforge.open(filename,v.fullname))
+ save(v.fontname,fontloader.open(filename,v.fullname))
end
else
- save(fontinfo.fullname,fontforge.open(filename))
+ save(fontinfo.fullname,fontloader.open(filename))
end
end
else
- input.verbose = true
- input.report("font: %s not saved",filename)
+ logs.simple("font: %s not saved",filename)
end
else
- input.verbose = true
- input.report("font: %s not found",name)
+ logs.simple("font: %s not found",name)
end
end
end
-banner = banner .. " | font tools "
+logs.extendbanner("Font Tools 0.20",true)
messages.help = [[
--reload generate new font database
--list [--info] list installed fonts (show info)
--save save open type font in raw table
+--names generate 'luatex-fonts-names.lua' (not for context!)
--pattern=str filter files
--all provide alternatives
]]
if environment.argument("reload") then
- local verbose = environment.argument("verbose")
- scripts.fonts.reload(verbose)
+ scripts.fonts.reload(true)
+elseif environment.argument("names") then
+ scripts.fonts.names()
elseif environment.argument("list") then
local pattern = environment.argument("pattern") or environment.files[1] or ""
local all = environment.argument("all")
@@ -168,5 +171,5 @@ elseif environment.argument("save") then
local sub = environment.files[2] or ""
scripts.fonts.save(name,sub)
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-grep.lua b/scripts/context/lua/mtx-grep.lua
index 18e36d2ea..82a80314a 100644
--- a/scripts/context/lua/mtx-grep.lua
+++ b/scripts/context/lua/mtx-grep.lua
@@ -9,54 +9,85 @@ if not modules then modules = { } end modules ['mtx-babel'] = {
scripts = scripts or { }
scripts.grep = scripts.grep or { }
-banner = banner .. " | simple grepper "
+logs.extendbanner("Simple Grepper 0.10",true)
+
+local find, format = string.find, string.format
+
+local cr = lpeg.P("\r")
+local lf = lpeg.P("\n")
+local crlf = cr * lf
+local newline = crlf + cr + lf
+local content = lpeg.C((1-newline)^0) * newline
+
+local write_nl = texio.write_nl
function scripts.grep.find(pattern, files, offset)
if pattern and pattern ~= "" then
- local format = string.format
- input.starttiming(scripts.grep)
- local count, nofmatches, noffiles, nofmatchedfiles = environment.argument("count"), 0, 0, 0
- local function grep(name)
- local data = io.loaddata(name)
- if data then
- noffiles = noffiles + 1
- local n, m = 0, 0
- for line in data:gmatch("[^\n]+") do -- faster than loop over lines
+ statistics.starttiming(scripts.grep)
+ local nofmatches, noffiles, nofmatchedfiles = 0, 0, 0
+ local n, m, name, check = 0, 0, "", nil
+ local count, nocomment = environment.argument("count"), environment.argument("nocomment")
+ if nocomment then
+ if count then
+ check = function(line)
n = n + 1
- if line:find(pattern) then
+ if find(line,"^[%%#]") then
+ -- skip
+ elseif find(line,pattern) then
m = m + 1
- if not count then
- input.log(format("%s %s: %s",name,n,line))
- io.flush()
- end
end
end
- if count and m > 0 then
- nofmatches = nofmatches + m
- nofmatchedfiles = nofmatchedfiles + 1
- input.log(format("%s: %s",name,m))
- io.flush()
+ else
+ check = function(line)
+ n = n + 1
+ if find(line,"^[%%#]") then
+ -- skip
+ elseif find(line,pattern) then
+ m = m + 1
+ write_nl(format("%s %s: %s",name,n,line))
+ io.flush()
+ end
+ end
+ end
+ else
+ if count then
+ check = function(line)
+ n = n + 1
+ if find(line,pattern) then
+ m = m + 1
+ end
+ end
+ else
+ check = function(line)
+ n = n + 1
+ if find(line,pattern) then
+ m = m + 1
+ write_nl(format("%s %s: %s",name,n,line))
+ io.flush()
+ end
end
end
end
---~ for i=offset or 1, #files do
---~ local filename = files[i]
---~ if filename:find("%*") then
---~ for _, name in ipairs(dir.glob(filename)) do
---~ grep(name)
---~ end
---~ else
---~ grep(filename)
---~ end
---~ end
+ local capture = (content/check)^0
for i=offset or 1, #files do
- for _, name in ipairs(dir.glob(files[i])) do
- grep(name)
+ for _, nam in ipairs(dir.glob(files[i])) do
+ name = nam
+ local data = io.loaddata(name)
+ if data then
+ n, m, noffiles = 0, 0, noffiles + 1
+ capture:match(data)
+ if count and m > 0 then
+ nofmatches = nofmatches + m
+ nofmatchedfiles = nofmatchedfiles + 1
+ write_nl(format("%s: %s",name,m))
+ io.flush()
+ end
+ end
end
end
- input.stoptiming(scripts.grep)
+ statistics.stoptiming(scripts.grep)
if count and nofmatches > 0 then
- input.log(format("\nfiles: %s, matches: %s, matched files: %s, runtime: %0.3f seconds",noffiles,nofmatches,nofmatchedfiles,input.loadtime(scripts.grep)))
+ write_nl(format("\nfiles: %s, matches: %s, matched files: %s, runtime: %0.3f seconds",noffiles,nofmatches,nofmatchedfiles,statistics.elapsedtime(scripts.grep)))
end
end
end
@@ -64,9 +95,10 @@ end
messages.help = [[
--pattern search for pattern (optional)
--count count matches only
-]]
+--nocomment skip lines that start with %% or #
-input.verbose = true
+patterns are lua patterns and need to be escaped accordingly
+]]
local pattern = environment.argument("pattern")
local files = environment.files and #environment.files > 0 and environment.files
@@ -76,5 +108,5 @@ if pattern and files then
elseif files then
scripts.grep.find(files[1], files, 2)
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-interface.lua b/scripts/context/lua/mtx-interface.lua
index b57617846..264a2dbe4 100644
--- a/scripts/context/lua/mtx-interface.lua
+++ b/scripts/context/lua/mtx-interface.lua
@@ -11,7 +11,9 @@ local format = string.format
scripts = scripts or { }
scripts.interface = scripts.interface or { }
-local flushers = { }
+local flushers = { }
+local userinterfaces = { 'en','cs','de','it','nl','ro','fr','pe' }
+local messageinterfaces = { 'en','cs','de','it','nl','ro','fr','pe','no' }
function flushers.scite(interface,collection)
local result, i = {}, 0
@@ -59,25 +61,23 @@ end
function flushers.raw(interface,collection)
for _, command in ipairs(collection) do
- input.report(command)
+ logs.simple(command)
end
end
function scripts.interface.editor(editor)
local interfaces= environment.files
if #interfaces == 0 then
- interfaces= { 'en','cs','de','it','nl','ro','fr' }
+ interfaces= userinterfaces
end
- local xmlfile = input.find_file("cont-en.xml") or ""
+ local xmlfile = resolvers.find_file("cont-en.xml") or ""
if xmlfile == "" then
- input.verbose = true
- input.report("unable to locate cont-en.xml")
+ logs.simple("unable to locate cont-en.xml")
end
for _, interface in ipairs(interfaces) do
- local keyfile = input.find_file(format("keys-%s.xml",interface)) or ""
+ local keyfile = resolvers.find_file(format("keys-%s.xml",interface)) or ""
if keyfile == "" then
- input.verbose = true
- input.report("unable to locate keys-*.xml")
+ logs.simple("unable to locate keys-*.xml")
else
local collection = { }
local mappings = { }
@@ -112,7 +112,7 @@ function scripts.interface.editor(editor)
end
function scripts.interface.check()
- local xmlfile = input.find_file("cont-en.xml") or ""
+ local xmlfile = resolvers.find_file("cont-en.xml") or ""
if xmlfile ~= "" then
local f = io.open("cont-en-check.tex","w")
if f then
@@ -138,14 +138,12 @@ function scripts.interface.check()
end
function scripts.interface.context()
- local verbose = input.verbose
- input.verbose = true
- local filename = input.find_file("mult-def.lua") or ""
+ local filename = resolvers.find_file("mult-def.lua") or ""
if filename ~= "" then
local interface = dofile(filename)
if interface and next(interface) then
local variables, constants, commands, elements = interface.variables, interface.constants, interface.commands, interface.elements
- local filename = input.find_file("cont-en.xml") or ""
+ local filename = resolvers.find_file("cont-en.xml") or ""
local xmldata = filename ~= "" and (io.loaddata(filename) or "")
local function flush(texresult,xmlresult,language,what,tag)
local t = interface[what]
@@ -156,7 +154,7 @@ function scripts.interface.context()
local v = t[key]
local value = v[language] or v["en"]
if not value then
- input.report(format("warning, no value for key '%s' for language '%s'",key,language))
+ logs.simple(format("warning, no value for key '%s' for language '%s'",key,language))
else
local value = t[key][language] or t[key].en
texresult[#texresult+1] = format("\\setinterface%s{%s}{%s}",tag,key,value)
@@ -194,9 +192,9 @@ function scripts.interface.context()
local texfilename = format("mult-%s.tex",language)
local xmlfilename = format("keys-%s.xml",language)
io.savedata(texfilename,table.concat(texresult,"\n"))
- input.report(format("saving interface definitions '%s'",texfilename))
+ logs.simple(format("saving interface definitions '%s'",texfilename))
io.savedata(xmlfilename,table.concat(xmlresult,"\n"))
- input.report(format("saving interface translations '%s'",xmlfilename))
+ logs.simple(format("saving interface translations '%s'",xmlfilename))
if language ~= "en" and xmldata ~= "" then
local newdata = xmldata:gsub("(<cd:interface.*language=.)en(.)","%1"..language.."%2",1)
newdata = replace(newdata, 'cd:string', 'value', interface.commands, interface.elements, language)
@@ -207,17 +205,36 @@ function scripts.interface.context()
newdata = replace(newdata, 'cd:inherit', 'name', interface.commands, interface.elements, language)
local xmlfilename = format("cont-%s.xml",language)
io.savedata(xmlfilename,newdata)
- input.report(format("saving interface specification '%s'",xmlfilename))
+ logs.simple(format("saving interface specification '%s'",xmlfilename))
end
end
end
end
- input.verbose = verbose
end
+function scripts.interface.messages()
+ local filename = resolvers.find_file("mult-mes.lua") or ""
+ if filename ~= "" then
+ local messages = dofile(filename)
+ for _, interface in ipairs(messageinterfaces) do
+ local texresult = { }
+ for category, data in next, messages do
+ for tag, message in next, data do
+ if tag ~= "files" then
+ local msg = message[interface] or message["all"] or message["en"]
+ if msg then
+ texresult[#texresult+1] = format("\\setinterfacemessage{%s}{%s}{%s}",category,tag,msg)
+ end
+ end
+ end
+ end
+ texresult[#texresult+1] = format("%%\n\\endinput")
+ io.savedata(format("mult-m%s.tex",interface),table.concat(texresult,"\n"))
+ end
+ end
+end
-
-banner = banner .. " | interface tools "
+logs.extendbanner("Interface Tools 0.11",true)
messages.help = [[
--scite generate scite interface
@@ -225,10 +242,13 @@ messages.help = [[
--jedit generate scite interface
--check generate check file
--context generate context definition files
+--messages generate context message files
]]
if environment.argument("context") then
scripts.interface.context()
+elseif environment.argument("messages") then
+ scripts.interface.messages()
elseif environment.argument("scite") or environment.argument("bbedit") or environment.argument("jedit") then
if environment.argument("scite") then
scripts.interface.editor("scite")
@@ -242,5 +262,5 @@ elseif environment.argument("scite") or environment.argument("bbedit") or enviro
elseif environment.argument("check") then
scripts.interface.check()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-metatex.lua b/scripts/context/lua/mtx-metatex.lua
new file mode 100644
index 000000000..f8c871a7b
--- /dev/null
+++ b/scripts/context/lua/mtx-metatex.lua
@@ -0,0 +1,69 @@
+if not modules then modules = { } end modules ['mtx-metatex'] = {
+ version = 1.001,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- future versions will deal with specific variants of metatex
+
+scripts = scripts or { }
+scripts.metatex = scripts.metatex or { }
+
+-- metatex
+
+function scripts.metatex.make()
+ local command = "luatools --make --compile metatex"
+ logs.simple("running command: %s",command)
+ os.spawn(command)
+end
+
+--~ function scripts.metatex.run()
+--~ local name = environment.files[1] or ""
+--~ if name ~= "" then
+--~ local command = "luatools --fmt=metatex " .. name
+--~ logs.simple("running command: %s",command)
+--~ os.spawn(command)
+--~ end
+--~ end
+
+function scripts.metatex.run(ctxdata,filename)
+ local filename = environment.files[1] or ""
+ if filename ~= "" then
+ local formatfile, scriptfile = resolvers.locate_format("metatex")
+ if formatfile and scriptfile then
+ local command = string.format("luatex --fmt=%s --lua=%s %s",
+ string.quote(formatfile), string.quote(scriptfile), string.quote(filename))
+ logs.simple("running command: %s",command)
+ os.spawn(command)
+ elseif formatname then
+ logs.simple("error, no format found with name: %s",formatname)
+ else
+ logs.simple("error, no format found (provide formatname or interface)")
+ end
+ end
+end
+
+function scripts.metatex.timed(action)
+ statistics.timed(action)
+end
+
+logs.extendbanner("MetaTeX Tools 0.10",true)
+
+messages.help = [[
+--run process (one or more) files (default action)
+--make create metatex format(s)
+]]
+
+if environment.argument("run") then
+ scripts.metatex.timed(scripts.metatex.run)
+elseif environment.argument("make") then
+ scripts.metatex.timed(scripts.metatex.make)
+elseif environment.argument("help") then
+ logs.help(messages.help,false)
+elseif environment.files[1] then
+ scripts.metatex.timed(scripts.metatex.run)
+else
+ logs.help(messages.help,false)
+end
diff --git a/scripts/context/lua/mtx-mptopdf.lua b/scripts/context/lua/mtx-mptopdf.lua
index 0c685a249..4243625ad 100644
--- a/scripts/context/lua/mtx-mptopdf.lua
+++ b/scripts/context/lua/mtx-mptopdf.lua
@@ -74,7 +74,7 @@ do
end
end
local runner = mpbin .. rest .. fn
- input.report("running: %s\n", runner)
+ logs.simple("running: %s\n", runner)
return (os.execute(runner))
end
@@ -93,7 +93,7 @@ function scripts.mptopdf.convertall()
if scripts.mptopdf.aux.make_mps(fn,latex,rawmp,metafun) then
files = dir.glob(file.nameonly(fn) .. ".*") -- reset
else
- input.report("error while processing mp file '%s'", fn)
+ logs.simple("error while processing mp file '%s'", fn)
exit(1)
end
local report = { }
@@ -104,20 +104,20 @@ function scripts.mptopdf.convertall()
end
end
if #report > 0 then
- input.report("number of converted files: %i", #report)
- input.report("")
+ logs.simple("number of converted files: %i", #report)
+ logs.simple("")
for _, r in ipairs(report) do
- input.report("%s => %s", r[1], r[2])
+ logs.simple("%s => %s", r[1], r[2])
end
else
- input.report("no input files match %s", table.concat(files,' '))
+ logs.simple("no input files match %s", table.concat(files,' '))
end
else
- input.report("no files match %s", table.concat(environment.files,' '))
+ logs.simple("no files match %s", table.concat(environment.files,' '))
end
end
-banner = banner .. " | mptopdf converter "
+logs.extendbanner("MetaPost to PDF Converter 0.51",true)
messages.help = [[
--rawmp raw metapost run
@@ -125,14 +125,12 @@ messages.help = [[
--latex force --tex=latex
]]
-input.verbose = true
-
if environment.files[1] then
scripts.mptopdf.convertall()
else
if not environment.arguments.help then
- input.report("provide MP output file (or pattern)")
- input.report("")
+ logs.simple("provide MP output file (or pattern)")
+ logs.simple("")
end
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtx-package.lua b/scripts/context/lua/mtx-package.lua
new file mode 100644
index 000000000..06c89907a
--- /dev/null
+++ b/scripts/context/lua/mtx-package.lua
@@ -0,0 +1,68 @@
+if not modules then modules = { } end modules ['mtx-package'] = {
+ version = 1.002,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gsub, gmatch = string.format, string.gsub, string.gmatch
+
+scripts = scripts or { }
+messages = messages or { }
+scripts.package = scripts.package or { }
+
+function scripts.package.merge_luatex_files(name,strip)
+ local oldname = resolvers.find_file(name) or ""
+ oldname = file.replacesuffix(oldname,"lua")
+ if oldname == "" then
+ logs.simple("missing '%s'",name)
+ else
+ local newname = file.removesuffix(oldname) .. "-merged.lua"
+ local data = io.loaddata(oldname) or ""
+ if data == "" then
+ logs.simple("missing '%s'",newname)
+ else
+ logs.simple("loading '%s'",oldname)
+ local collected = { }
+ collected[#collected+1] = format("-- merged file : %s\n",newname)
+ collected[#collected+1] = format("-- parent file : %s\n",oldname)
+ collected[#collected+1] = format("-- merge date : %s\n",os.date())
+ -- loadmodule can have extra arguments
+ for lib in gmatch(data,"loadmodule *%([\'\"](.-)[\'\"]") do
+ if file.basename(lib) ~= file.basename(newname) then
+ local fullname = resolvers.find_file(lib) or ""
+ if fullname == "" then
+ logs.simple("missing '%s'",lib)
+ else
+ logs.simple("fetching '%s'",fullname)
+ local data = io.loaddata(fullname)
+ if strip then
+ data = gsub(data,"%-%-%[%[ldx%-%-.-%-%-%ldx%]%]%-%-[\n\r]*","")
+ data = gsub(data,"%-%-%~[^\n\r]*[\n\r]*","\n")
+ data = gsub(data,"%s+%-%-[^\n\r]*[\n\r]*","\n")
+ data = gsub(data,"[\n\r]+","\n")
+ end
+ collected[#collected+1] = "\ndo -- begin closure to overcome local limits and interference\n\n"
+ collected[#collected+1] = data
+ collected[#collected+1] = "\nend -- closure\n"
+ end
+ end
+ end
+ logs.simple("saving '%s'",newname)
+ io.savedata(newname,table.concat(collected))
+ end
+ end
+end
+
+logs.extendbanner("Package Tools 0.1",true)
+
+messages.help = [[
+--merge merge 'loadmodule' into merge file
+]]
+
+if environment.argument("merge") then
+ scripts.package.merge_luatex_files(environment.files[1] or "")
+else
+ logs.help(messages.help)
+end
diff --git a/scripts/context/lua/mtx-patterns.lua b/scripts/context/lua/mtx-patterns.lua
index 7fda6900c..7f130465b 100644
--- a/scripts/context/lua/mtx-patterns.lua
+++ b/scripts/context/lua/mtx-patterns.lua
@@ -19,8 +19,8 @@ scripts.patterns.list = {
{ "cs", "hyph-cs.tex", "czech" },
{ "??", "hyph-cy.tex", "welsh" },
{ "da", "hyph-da.tex", "danish" },
- { "de", "hyph-de-1901.tex", "german, old spelling" },
- { "deo", "hyph-de-1996.tex", "german, new spelling" },
+ { "deo", "hyph-de-1901.tex", "german, old spelling" },
+ { "de", "hyph-de-1996.tex", "german, new spelling" },
--~ { "??", "hyph-el-monoton.tex", "" },
--~ { "??", "hyph-el-polyton.tex", "" },
--~ { "agr", "hyph-grc", "ancient greek" },
@@ -60,7 +60,7 @@ scripts.patterns.list = {
{ "??", "hyph-sr-cyrl.tex", "serbian" },
{ "sv", "hyph-sv.tex", "swedish" },
{ "tr", "hyph-tr.tex", "turkish" },
- { "??", "hyph-uk.tex", "ukrainian" },
+ { "uk", "hyph-uk.tex", "ukrainian" },
{ "??", "hyph-zh-latn.tex", "zh-latn, chinese Pinyin" },
}
@@ -91,6 +91,7 @@ local permitted_characters = table.tohash {
0x0009, -- tab
0x0027, -- apostrofe
0x002D, -- hyphen
+ 0x200C, --
}
function scripts.patterns.load(path,name,mnemonic,fullcheck)
@@ -104,9 +105,9 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
local subdata = io.loaddata(subfull) or ""
if subdata == "" then
if mnemonic then
- input.report("no subfile %s for language %s",subname,mnemonic)
+ logs.simple("no subfile %s for language %s",subname,mnemonic)
else
- input.report("no subfile %s",name)
+ logs.simple("no subfile %s",name)
end
end
return previous .. subdata
@@ -122,15 +123,15 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
line = line:gsub("%%","%%%%")
if fullcheck then
if mnemonic then
- input.report("invalid utf in language %s, file %s, line %s: %s",mnemonic,name,n,line)
+ logs.simple("invalid utf in language %s, file %s, line %s: %s",mnemonic,name,n,line)
else
- input.report("invalid utf in file %s, line %s: %s",name,n,line)
+ logs.simple("invalid utf in file %s, line %s: %s",name,n,line)
end
else
if mnemonic then
- input.report("file %s for %s contains invalid utf",name,mnemonic)
+ logs.simple("file %s for %s contains invalid utf",name,mnemonic)
else
- input.report("file %s contains invalid utf",name)
+ logs.simple("file %s contains invalid utf",name)
end
break
end
@@ -154,17 +155,17 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
for k, v in pairs(h) do
if not permitted_commands[k] then okay = false end
if mnemonic then
- input.report("command \\%s found in language %s, file %s, n=%s",k,mnemonic,name,v)
+ logs.simple("command \\%s found in language %s, file %s, n=%s",k,mnemonic,name,v)
else
- input.report("command \\%s found in file %s, n=%s",k,name,v)
+ logs.simple("command \\%s found in file %s, n=%s",k,name,v)
end
end
if not environment.argument("fast") then
for k, v in pairs(c) do
if mnemonic then
- input.report("command \\%s found in comment of language %s, file %s, n=%s",k,mnemonic,name,v)
+ logs.simple("command \\%s found in comment of language %s, file %s, n=%s",k,mnemonic,name,v)
else
- input.report("command \\%s found in comment of file %s, n=%s",k,name,v)
+ logs.simple("command \\%s found in comment of file %s, n=%s",k,name,v)
end
end
end
@@ -222,9 +223,9 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
local stripped = { }
for k, v in pairs(p) do
if mnemonic then
- input.report("invalid character %s (0x%04X) in patterns of language %s, file %s, n=%s",char(k),k,mnemonic,name,v)
+ logs.simple("invalid character %s (0x%04X) in patterns of language %s, file %s, n=%s",char(k),k,mnemonic,name,v)
else
- input.report("invalid character %s (0x%04X) in patterns of file %s, n=%s",char(k),k,name,v)
+ logs.simple("invalid character %s (0x%04X) in patterns of file %s, n=%s",char(k),k,name,v)
end
if not permitted_characters[k] then
okay = false
@@ -234,9 +235,9 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
end
for k, v in pairs(h) do
if mnemonic then
- input.report("invalid character %s (0x%04X) in exceptions of language %s, file %s, n=%s",char(k),k,mnemonic,name,v)
+ logs.simple("invalid character %s (0x%04X) in exceptions of language %s, file %s, n=%s",char(k),k,mnemonic,name,v)
else
- input.report("invalid character %s (0x%04X) in exceptions of file %s, n=%s",char(k),k,name,v)
+ logs.simple("invalid character %s (0x%04X) in exceptions of file %s, n=%s",char(k),k,name,v)
end
if not permitted_characters[k] then
okay = false
@@ -246,15 +247,15 @@ function scripts.patterns.load(path,name,mnemonic,fullcheck)
end
local stripset = ""
for k, v in pairs(stripped) do
- input.report("entries that contain character %s will be omitted",char(k))
+ logs.simple("entries that contain character %s will be omitted",char(k))
stripset = stripset .. "%" .. char(k)
end
return okay, pats, hyps, comment, stripset, pused, hused
else
if mnemonic then
- input.report("no file %s for language %s",fullname,mnemonic)
+ logs.simple("no file %s for language %s",fullname,mnemonic)
else
- input.report("no file %s",fullname)
+ logs.simple("no file %s",fullname)
end
return false, { }, { }, "", "", { }, { }
end
@@ -265,14 +266,14 @@ function scripts.patterns.save(destination,mnemonic,patterns,hyphenations,commen
local nofhyphenations = #hyphenations
local pu = table.concat(table.sortedkeys(pused), " ")
local hu = table.concat(table.sortedkeys(hused), " ")
- input.report("language %s has %s patterns and %s exceptions",mnemonic,nofpatterns,nofhyphenations)
+ logs.simple("language %s has %s patterns and %s exceptions",mnemonic,nofpatterns,nofhyphenations)
if mnemonic ~= "??" then
local rmefile = file.join(destination,"lang-"..mnemonic..".rme")
local patfile = file.join(destination,"lang-"..mnemonic..".pat")
local hypfile = file.join(destination,"lang-"..mnemonic..".hyp")
local topline = "% generated by mtxrun --script pattern --convert"
local banner = "% for comment and copyright, see " .. rmefile
- input.report("saving language data for %s",mnemonic)
+ logs.simple("saving language data for %s",mnemonic)
if not comment or comment == "" then comment = "% no comment" end
if not type(destination) == "string" then destination = "." end
os.remove(rmefile)
@@ -285,60 +286,58 @@ function scripts.patterns.save(destination,mnemonic,patterns,hyphenations,commen
end
function scripts.patterns.prepare()
- dofile(input.find_file("char-def.lua"))
+ dofile(resolvers.find_file("char-def.lua"))
end
function scripts.patterns.check()
local path = environment.argument("path") or "."
local found = false
- local verbose = input.verbose
- input.verbose = true
if #environment.files > 0 then
for _, name in ipairs(environment.files) do
- input.report("checking language file %s", name)
+ logs.simple("checking language file %s", name)
local okay = scripts.patterns.load(path,name,nil,not environment.argument("fast"))
if #environment.files > 1 then
- input.report("")
+ logs.simple("")
end
end
else
for k, v in pairs(scripts.patterns.list) do
local mnemonic, name = v[1], v[2]
- input.report("checking language %s, file %s", mnemonic, name)
+ logs.simple("checking language %s, file %s", mnemonic, name)
local okay = scripts.patterns.load(path,name,mnemonic,not environment.argument("fast"))
if not okay then
- input.report("there are errors that need to be fixed")
+ logs.simple("there are errors that need to be fixed")
end
- input.report("")
+ logs.simple("")
end
end
- input.verbose = verbose
end
function scripts.patterns.convert()
local path = environment.argument("path") or "."
- local destination = environment.argument("destination") or "."
- if path == destination then
- input.report("source path and destination path should differ (use --path and/or --destination)")
+ if path == "" then
+ logs.simple("provide sourcepath using --path ")
else
- local verbose = input.verbose
- input.verbose = true
- for k, v in pairs(scripts.patterns.list) do
- local mnemonic, name = v[1], v[2]
- input.report("converting language %s, file %s", mnemonic, name)
- local okay, patterns, hyphenations, comment, stripped, pused, hused = scripts.patterns.load(path,name,false)
- if okay then
- scripts.patterns.save(destination,mnemonic,patterns,hyphenations,comment,stripped,pused,hused)
- else
- input.report("convertion aborted due to error(s)")
+ local destination = environment.argument("destination") or "."
+ if path == destination then
+ logs.simple("source path and destination path should differ (use --path and/or --destination)")
+ else
+ for k, v in pairs(scripts.patterns.list) do
+ local mnemonic, name = v[1], v[2]
+ logs.simple("converting language %s, file %s", mnemonic, name)
+ local okay, patterns, hyphenations, comment, stripped, pused, hused = scripts.patterns.load(path,name,false)
+ if okay then
+ scripts.patterns.save(destination,mnemonic,patterns,hyphenations,comment,stripped,pused,hused)
+ else
+ logs.simple("convertion aborted due to error(s)")
+ end
+ logs.simple("")
end
- input.report("")
end
end
- input.verbose = verbose
end
-banner = banner .. " | pattern tools "
+logs.extendbanner("Pattern Tools 0.20",true)
messages.help = [[
--convert generate context language files (mnemonic driven, if not given then all)
@@ -354,10 +353,10 @@ elseif environment.argument("convert") then
scripts.patterns.prepare()
scripts.patterns.convert()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
-- mtxrun --script pattern --check hyph-*.tex
--- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns
--- mtxrun --script pattern --check --fast --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns
--- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --destination e:/tmp/patterns
+-- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns
+-- mtxrun --script pattern --check --fast --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns
+-- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns --destination=e:/tmp/patterns
diff --git a/scripts/context/lua/mtx-profile.lua b/scripts/context/lua/mtx-profile.lua
new file mode 100644
index 000000000..d99f7e926
--- /dev/null
+++ b/scripts/context/lua/mtx-profile.lua
@@ -0,0 +1,164 @@
+if not modules then modules = { } end modules ['mtx-profile'] = {
+ version = 1.000,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: also line number
+-- todo: sort runtime as option
+
+local match, format, find = string.match, string.format, string.find
+
+scripts = scripts or { }
+scripts.profiler = scripts.profiler or { }
+
+local timethreshold = 0
+local callthreshold = 2500
+local countthreshold = 2500
+
+local functiontemplate = "%12s %03.4f %9i %s"
+local calltemplate = "%9i %s"
+local totaltemplate = "%i internal calls, %i function calls taking %3.4f seconds"
+local thresholdtemplate = "thresholds: %i internal calls, %i function calls, %i seconds"
+
+function scripts.profiler.analyse(filename)
+ local f = io.open(filename)
+ if f then
+ local times, counts, calls = { }, { }, { }
+ local totalruntime, totalcount, totalcalls = 0, 0, 0
+ while true do
+ local line = f:read()
+ if line then
+ local stacklevel, filename, functionname, linenumber, currentline, localtime, totaltime = line:match("^(%d+)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)")
+ if not filename then
+ -- next
+ elseif filename == "=[C]" then
+ if not functionname:find("^%(") then
+ calls[functionname] = (calls[functionname] or 0) + 1
+ end
+ else
+ local filename = filename:match("^@(.*)$")
+ if filename then
+ local fi = times[filename]
+ if not fi then fi = { } times[filename] = fi end
+ fi[functionname] = (fi[functionname] or 0) + tonumber(localtime)
+ counts[functionname] = (counts[functionname] or 0) + 1
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ print("")
+ local loaded = { }
+ for _, filename in ipairs(table.sortedkeys(times)) do
+ local functions = times[filename]
+ for _, functionname in ipairs(table.sortedkeys(functions)) do
+ local totaltime = functions[functionname]
+ local count = counts[functionname]
+ totalcount = totalcount + count
+ if totaltime > timethreshold or count > countthreshold then
+ totalruntime = totalruntime + totaltime
+ local functionfile, somenumber = functionname:match("^@(.+):(.-)$")
+ if functionfile then
+ local number = tonumber(somenumber)
+ if number then
+ if not loaded[functionfile] then
+ loaded[functionfile] = string.splitlines(io.loaddata(functionfile) or "")
+ end
+ functionname = loaded[functionfile][number] or functionname
+ functionname = functionname:gsub("^%s*","")
+ functionname = functionname:gsub("%s*%-%-.*$","")
+ functionname = number .. ": " .. functionname
+ end
+ end
+ filename = file.basename(filename)
+ print(functiontemplate:format(filename,totaltime,count,functionname))
+ end
+ end
+ end
+ print("")
+ for _, call in ipairs(table.sortedkeys(calls)) do
+ local n = calls[call]
+ totalcalls = totalcalls + n
+ if n > callthreshold then
+ print(calltemplate:format(n,call))
+ end
+ end
+ print("")
+ print(totaltemplate:format(totalcalls,totalcount,totalruntime))
+ print("")
+ print(thresholdtemplate:format(callthreshold,countthreshold,timethreshold))
+ end
+end
+
+function scripts.profiler.analyse(filename)
+ local f = io.open(filename)
+ local calls = { }
+ local lines = 0
+ if f then
+ while true do
+ local line = f:read()
+ if line then
+ lines = lines + 1
+ local c = match(line,"\\([a-zA-Z%!%?@]+) *%->")
+ if c then
+ local cc = calls[c]
+ if not cc then
+ calls[c] = 1
+ else
+ calls[c] = cc + 1
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ local noc = 0
+local criterium = 100
+ for name, n in next, calls do
+ if n > criterium then
+ if find(name,"^@@[a-z][a-z]") then
+ -- parameter
+ elseif find(name,"^[cvserft]%!") then
+ -- variables and constants
+ elseif find(name,"^%?%?[a-z][a-z]$") then
+ -- prefix
+ elseif find(name,"^%!%!") then
+ -- reserved
+ elseif find(name,"^@.+@$") then
+ -- weird
+ else
+ noc = noc + n
+ print(format("%6i: %s",n,name))
+ end
+ end
+ end
+ print("")
+ print(format("number of lines: %s",lines))
+ print(format("number of calls: %s",noc))
+ print(format("criterium calls: %s",criterium))
+ end
+end
+
+--~ scripts.profiler.analyse("t:/manuals/mk/mk-fonts-profile.lua")
+--~ scripts.profiler.analyse("t:/manuals/mk/mk-introduction-profile.lua")
+
+logs.extendbanner("LuaTeX Profiler 1.00",true)
+
+messages.help = [[
+--analyse analyse lua calls
+--trace analyse tex calls
+]]
+
+if environment.argument("analyse") then
+ scripts.profiler.analyse(environment.files[1] or "luatex-profile.log")
+elseif environment.argument("trace") then
+ scripts.profiler.analyse(environment.files[1] or "temp.log")
+else
+ logs.help(messages.help)
+end
diff --git a/scripts/context/lua/mtx-server-ctx-fonttest.lua b/scripts/context/lua/mtx-server-ctx-fonttest.lua
new file mode 100644
index 000000000..efaae66e3
--- /dev/null
+++ b/scripts/context/lua/mtx-server-ctx-fonttest.lua
@@ -0,0 +1,681 @@
+if not modules then modules = { } end modules ['mtx-server-ctx-fonttest'] = {
+ version = 1.001,
+ comment = "Font Feature Tester",
+ author = "Hans Hagen",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+dofile(resolvers.find_file("l-aux.lua","tex"))
+dofile(resolvers.find_file("trac-lmx.lua","tex"))
+dofile(resolvers.find_file("font-ott.lua","tex"))
+dofile(resolvers.find_file("font-syn.lua","tex"))
+dofile(resolvers.find_file("font-mis.lua","tex"))
+dofile(resolvers.find_file("font-otp.lua","tex"))
+
+local format, gsub, concat, match, find = string.format, string.gsub, table.concat, string.match, string.find
+
+local sample_line = "This is a sample line!"
+local tempname = "mtx-server-ctx-fonttest-temp"
+local temppath = caches.setpath("temp","mtx-server-ctx-fonttest")
+local basename = "mtx-server-ctx-fonttest-data.lua"
+local basepath = temppath
+
+for _, suffix in ipairs { "tex", "pdf", "log" } do
+ os.remove(file.join(temppath,file.addsuffix(tempname,suffix)))
+end
+
+local process_templates = { }
+
+process_templates.default = [[
+\starttext
+ \setcharactermirroring[1]
+ \definefontfeature[sample][%s]
+ \definedfont[name:%s*sample]
+ \startTEXpage[offset=3pt]
+ \detokenize{%s}
+ \stopTEXpage
+\stoptext
+]]
+
+process_templates.cache = [[
+\starttext
+ \definedfont[name:%s]
+ \startTEXpage[offset=3pt]
+ cached: \detokenize{%s}
+ \stopTEXpage
+\stoptext
+]]
+
+process_templates.trace = [[
+\usemodule[fnt-20]
+
+\definefontfeature[sample][%s]
+
+\setupcolors[state=start]
+
+\setcharactermirroring[1]
+
+\setvariables
+ [otftracker]
+ [title=Test Run,
+ font=name:%s,
+ direction=0,
+ features=sample,
+ sample={‍\detokenize{%s}}]
+]]
+
+local javascripts = [[
+function selected_radio(name) {
+ var form = document.forms["main-form"] ;
+ var script = form.elements[name] ;
+ if (script) {
+ var n = script.length ;
+ if (n) {
+ for (var i=0; i<n; i++) {
+ if (script[i].checked) {
+ return script[i].value ;
+ }
+ }
+ }
+ }
+ return "" ;
+}
+
+function reset_valid() {
+ var fields = document.getElementsByTagName("span") ;
+ for (var i=0; i<fields.length; i++) {
+ var e = fields[i]
+ if (e) {
+ if (e.className == "valid") {
+ e.className = "" ;
+ }
+ }
+ }
+}
+
+function set_valid() {
+ var script = selected_radio("script") ;
+ var language = selected_radio("language") ;
+ if (script && language) {
+ var s = feature_hash[script] ;
+ if (s) {
+ for (l in s) {
+ var e = document.getElementById("t-l-" + l) ;
+ if (e) {
+ e.className = "valid" ;
+ }
+ }
+ var l = s[language] ;
+ if (l) {
+ for (i in l) {
+ var e = document.getElementById("t-f-" + i) ;
+ if (e) {
+ e.className = "valid" ;
+ }
+ }
+ }
+ var e = document.getElementById("t-s-" + script) ;
+ if (e) {
+ e.className = "valid" ;
+ }
+ }
+ }
+}
+
+function check_form() {
+ reset_valid() ;
+ set_valid() ;
+}
+
+function check_script() {
+ reset_valid() ;
+ set_valid() ;
+}
+
+function check_language() {
+ reset_valid() ;
+ set_valid() ;
+}
+
+function check_feature() {
+ // not needed
+}
+]]
+
+local cache = { }
+
+local function showfeatures(f)
+ if f then
+ local features = cache[f]
+ if features == nil then
+ features = fonts.get_features(f)
+ if not features then
+ logs.simple("building cache for '%s'",f)
+ io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f))
+ os.execute(format("mtxrun --path=%s --script context --once --batchmode --mode=*nofonts %s",temppath,tempname))
+ features = fonts.get_features(f)
+ end
+ cache[f] = features or false
+ logs.simple("caching info of '%s'",f)
+ else
+ logs.simple("using cached info of '%s'",f)
+ end
+ if features then
+ local scr, lan, fea, rev = { }, { }, { }, { }
+ local function show(what)
+ local data = features[what]
+ if data and next(data) then
+ for f,ff in pairs(data) do
+ if find(f,"<") then
+ -- ignore aat for the moment
+ else
+ fea[f] = true
+ for s, ss in pairs(ff) do
+ if find(s,"%*") then
+ -- ignore *
+ else
+ scr[s] = true
+ local rs = rev[s] if not rs then rs = {} rev[s] = rs end
+ for k, l in pairs(ss) do
+ if find(k,"%*") then
+ -- ignore *
+ else
+ lan[k] = true
+ local rsk = rs[k] if not rsk then rsk = { } rs[k] = rsk end
+ rsk[f] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ for what, v in table.sortedpairs(features) do
+ show(what)
+ end
+ local stupid = { }
+ stupid[#stupid+1] = "var feature_hash = new Array ;"
+ for s, sr in pairs(rev) do
+ stupid[#stupid+1] = format("feature_hash['%s'] = new Array ;",s)
+ for l, lr in pairs(sr) do
+ stupid[#stupid+1] = format("feature_hash['%s']['%s'] = new Array ;",s,l)
+ for f, fr in pairs(lr) do
+ stupid[#stupid+1] = format("feature_hash['%s']['%s']['%s'] = true ;",s,l,f)
+ end
+ end
+ end
+ -- gpos feature script languages
+ return {
+ scripts = scr,
+ languages = lan,
+ features = fea,
+ javascript = concat(stupid,"\n")
+ }
+ end
+ end
+end
+
+local function select_font()
+ local t = fonts.names.list(".*")
+ if t then
+ local listoffonts = { }
+ local t = fonts.names.list(".*")
+ if t then
+ listoffonts[#listoffonts+1] = "<table>"
+ listoffonts[#listoffonts+1] = "<tr><th>safe name</th><th>font name</th><th>filename</th><th>sub font&nbsp;</th><th>type</th></tr>"
+ for k, id in ipairs(table.sortedkeys(t)) do
+ local ti = t[id]
+ local type, name, file, sub = ti[1], ti[2], ti[3], ti[4]
+ if type == "otf" or type == "ttf" or type == "ttc" then
+ if sub then sub = "(sub)" else sub = "" end
+ listoffonts[#listoffonts+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a></td><td>%s</td><td>%s</td><td>%s</td><td>%s</td></tr>",id,id,name,file,sub,type)
+ end
+ end
+ listoffonts[#listoffonts+1] = "</table>"
+ return concat(listoffonts,"\n")
+ end
+ end
+ return "<b>no fonts</b>"
+end
+
+local edit_template = [[
+ <textarea name='sampletext' rows='5' cols='100'>%s</textarea>
+ <br/> <br/>name:&nbsp;<input type='text' name='name' size='20' value=%q/>&nbsp;&nbsp; title:&nbsp;<input type='text' name='title' size='40' value=%q/>
+ <br/> <br/>scripts:&nbsp;%s
+ <br/> <br/>languages:&nbsp;%s
+ <br/> <br/>features:&nbsp;%s
+ <br/> <br/>options:&nbsp;%s
+]]
+
+local result_template = [[
+ <br/> <br/>
+ <embed src="%s#toolbar=0&amp;navpanes=0&amp;scrollbar=0" width="100%%"/>
+ <br/> <br/> results:
+ <a href='%s' target="source">tex file</a>
+ <a href='%s' target="result">pdf file</a>
+ <br/> <br/>
+]]
+
+scripts.webserver.registerpath(temppath)
+
+local function edit_font(currentfont,detail,tempname)
+ local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+ local htmldata = showfeatures(fontfile)
+ if htmldata then
+ local features, languages, scripts, options = { }, { }, { }, { }
+ for k,v in ipairs(table.sortedkeys(htmldata.scripts)) do
+ local s = fonts.otf.tables.scripts[v] or v
+ if detail and v == detail.script then
+ scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/>&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
+ else
+ scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' />&nbsp;<span id='t-s-%s'>%s</span>",s,v,v,v,v)
+ end
+ end
+ for k,v in ipairs(table.sortedkeys(htmldata.languages)) do
+ local l = fonts.otf.tables.languages[v] or v
+ if detail and v == detail.language then
+ languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/>&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
+ else
+ languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' />&nbsp;<span id='t-l-%s'>%s</span>",l,v,v,v,v)
+ end
+ end
+ for k,v in ipairs(table.sortedkeys(htmldata.features)) do
+ local f = fonts.otf.tables.features[v] or v
+ if detail and detail["f-"..v] then
+ features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/>&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
+ else
+ features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' />&nbsp;<span id='t-f-%s'>%s</span>",f,v,v,v,v)
+ end
+ end
+ for k, v in ipairs { "trace", "basemode" } do
+ if detail and detail["o-"..v] then
+ options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/>&nbsp;%s",v,v,v)
+ else
+ options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/>&nbsp;%s",v,v,v)
+ end
+ end
+ local e = format(edit_template,
+ (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "",
+ concat(scripts," "),concat(languages," "),concat(features," "),concat(options," "))
+ if tempname then
+ local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex")
+ local r = format(result_template,pdffile,texfile,pdffile)
+ return e .. r, htmldata.javascript or ""
+ else
+ return e, htmldata.javascript or ""
+ end
+ else
+ return "error, nothing set up yet"
+ end
+end
+
+local function process_font(currentfont,detail) -- maybe just fontname
+ local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+ local features = {
+ "mode=node",
+ format("language=%s",detail.language or "dflt"),
+ format("script=%s",detail.script or "dflt"),
+ }
+ for k,v in pairs(detail) do
+ local f = match(k,"^f%-(.*)$")
+ if f then
+ features[#features+1] = format("%s=yes",f)
+ end
+ end
+ local variant = process_templates.default
+ if detail["o-trace"] then
+ variant = process_templates.trace
+ end
+ local sample = string.strip(detail.sampletext or "")
+ if sample == "" then sample = sample_line end
+ logs.simple("sample text: %s",sample)
+ io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(variant,concat(features,","),currentfont,sample))
+ os.execute(format("mtxrun --path=%s --script context --once --batchmode --mode=*nofonts %s",temppath,tempname))
+ return edit_font(currentfont,detail,tempname)
+end
+
+local tex_template = [[
+<pre><tt>
+%s
+</tt></pre>
+]]
+
+local function show_source(currentfont,detail)
+ if tempname and tempname ~= "" then
+ return format(tex_template,io.loaddata(file.join(temppath,file.addsuffix(tempname,"tex"))) or "no source yet")
+ else
+ return "no source file"
+ end
+end
+
+local function show_log(currentfont,detail)
+ if tempname and tempname ~= "" then
+ local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,'log'))) or "no log file yet"
+ data = gsub(data,"[%s%%]*begin of optionfile.-end of optionfile[%s%%]*","\n")
+ return format(tex_template,data)
+ else
+ return "no log file"
+ end
+end
+
+local function show_font(currentfont,detail)
+ local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+ local features = fonts.get_features(fontfile)
+ local result = { }
+ result[#result+1] = format("<h1>names</h1>",what)
+ result[#result+1] = "<table>"
+ result[#result+1] = format("<tr><td class='tc'>fontname:</td><td>%s</td></tr>",currentfont)
+ result[#result+1] = format("<tr><td class='tc'>fullname:</td><td>%s</td></tr>",fontname)
+ result[#result+1] = format("<tr><td class='tc'>filename:</td><td>%s</td></tr>",fontfile)
+ result[#result+1] = "</table>"
+ if features then
+ for what, v in table.sortedpairs(features) do
+ local data = features[what]
+ if data and next(data) then
+ result[#result+1] = format("<h1>%s features</h1>",what)
+ result[#result+1] = "<table>"
+ result[#result+1] = "<tr><th>feature</th><th>tag&nbsp;</th><th>script&nbsp;</th><th>languages&nbsp;</th></tr>"
+ for f,ff in table.sortedpairs(data) do
+ local done = false
+ for s, ss in table.sortedpairs(ff) do
+ if s == "*" then s = "all" end
+ if ss ["*"] then ss["*"] = nil ss.all = true end
+ if done then
+ f = ""
+ else
+ done = true
+ end
+ local title = fonts.otf.tables.features[f] or ""
+ result[#result+1] = format("<tr><td width='50%%'>%s&nbsp;&nbsp;</td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td><td><tt>%s&nbsp;&nbsp;</tt></td></tr>",title,f,s,concat(table.sortedkeys(ss)," "))
+ end
+ end
+ result[#result+1] = "</table>"
+ end
+ end
+ else
+ result[#result+1] = "<br/><br/>This font has no features."
+ end
+ return concat(result,"\n")
+end
+
+
+local info_template = [[
+<pre><tt>
+version : %s
+comment : %s
+author : %s
+copyright : %s
+
+maillist : ntg-context at ntg.nl
+webpage : www.pragma-ade.nl
+wiki : contextgarden.net
+</tt></pre>
+]]
+
+local function info_about()
+ local m = modules ['mtx-server-ctx-fonttest']
+ return format(info_template,m.version,m.comment,m.author,m.copyright)
+end
+
+local save_template = [[
+ the current setup has been saved:
+ <br/> <br/>
+ <table>
+ <tr><td class='tc'>name&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>title&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>font&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>script&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>language&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>features&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>options&nbsp; </td><td>%s</td></tr>
+ <tr><td class='tc'>sampletext&nbsp;</td><td>%s</td></tr>
+ </table>
+]]
+
+local function loadbase()
+ local datafile = file.join(basepath,basename)
+ local storage = io.loaddata(datafile) or ""
+ if storage == "" then
+ storage = { }
+ else
+ logs.simple("loading '%s'",datafile)
+ storage = loadstring(storage)
+ storage = (storage and storage()) or { }
+ end
+ return storage
+end
+
+local function loadstored(detail,currentfont,name)
+ local storage = loadbase()
+ storage = storage and storage[name]
+ if storage then
+ currentfont = storage.font
+ detail.script = storage.script or detail.script
+ detail.language = storage.language or detail.language
+ detail.title = storage.title or detail.title
+ detail.sampletext = storage.text or detail.sampletext
+ detail.name = name or "no name"
+ for k,v in pairs(storage.features) do
+ detail["f-"..k] = v
+ end
+ for k,v in pairs(storage.options) do
+ detail["o-"..k] = v
+ end
+ end
+ detail.loadname = nil
+ return detail, currentfont
+end
+
+local function savebase(storage,name)
+ local datafile = file.join(basepath,basename)
+ logs.simple("saving '%s' in '%s'",name or "data",datafile)
+ io.savedata(datafile,table.serialize(storage,true))
+end
+
+local function deletestored(detail,currentfont,name)
+ local storage = loadbase()
+ if storage and name and storage[name] then
+ logs.simple("deleting '%s' from base",name)
+ storage[name] = nil
+ savebase(storage)
+ end
+ detail.deletename = nil
+ return detail, ""
+end
+
+local function save_font(currentfont,detail)
+ local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+ local name, title, script, language, features, options, text = currentfont, "", "dflt", "dflt", { }, { }, ""
+ if detail then
+ local htmldata = showfeatures(fontfile)
+ script = detail.script or script
+ language = detail.language or language
+ text = string.strip(detail.sampletext or text)
+ name = string.strip(detail.name or name)
+ title = string.strip(detail.title or title)
+ for k,v in pairs(htmldata.features) do
+ if detail["f-"..k] then features[k] = true end
+ end
+ for k,v in ipairs { "trace", "basemode" } do
+ if detail["o-"..v] then options[k] = true end
+ end
+ end
+ if name == "" then
+ name = "no name"
+ end
+ local storage = loadbase()
+ storage[name] = {
+ font = currentfont, title = title, script = script, language = language, features = features, options = options, text = text,
+ }
+ savebase(storage,name)
+ return format(save_template,name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text)
+end
+
+local function load_font(currentfont)
+ local datafile = file.join(basepath,basename)
+ local storage = loadbase(datafile)
+ local result = {}
+ result[#result+1] = format("<tr><th>del&nbsp;</th><th>name&nbsp;</th><th>font&nbsp;</th><th>fontname&nbsp;</th><th>script&nbsp;</th><th>language&nbsp;</th><th>features&nbsp;</th><th>title&nbsp;</th><th>sampletext&nbsp;</th></tr>")
+ for k,v in table.sortedpairs(storage) do
+ local fontname, fontfile, issub = fonts.names.specification(v.font or "")
+ result[#result+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?deletename=%s'>x</a>&nbsp;</td><td><a href='mtx-server-ctx-fonttest.lua?loadname=%s'>%s</a>&nbsp;</td><td>%s&nbsp;</td<td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td><td>%s&nbsp;</td></tr>",
+ k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "")
+ end
+ if #result == 1 then
+ return "nothing saved yet"
+ else
+ return format("<table>%s</table>",concat(result,"\n"))
+ end
+end
+
+local function reset_font(currentfont)
+ return edit_font(currentfont)
+end
+
+local extras_template = [[
+ <a href='mtx-server-ctx-fonttest.lua?extra=reload'>remake font database</a> (take some time)<br/><br/>
+]]
+
+local function do_extras(detail,currentfont,extra)
+ return extras_template
+end
+
+local extras = { }
+
+local function do_extra(detail,currentfont,extra)
+ local e = extras[extra]
+ if e then e(detail,currentfont,extra) end
+ return do_extras(detail,currentfont,extra)
+end
+
+function extras.reload()
+ local command = "mtxrun --script font --reload"
+ logs.simple("run command: %s",command)
+ os.execute(command)
+ return do_extras()
+end
+
+
+local status_template = [[
+ <input type="hidden" name="currentfont" value="%s" />
+]]
+
+function doit(configuration,filename,hashed)
+
+ local start = os.clock()
+
+ local detail = url.query(hashed.query or "")
+
+ local currentfont = detail.currentfont
+ local action = detail.action
+ local selection = detail.selection
+
+ local loadname = detail.loadname
+ local deletename = detail.deletename
+ local extra = detail.extra
+
+ if loadname and loadname ~= "" then
+ detail, currentfont = loadstored(detail,currentfont,loadname)
+ action = "process"
+ elseif deletename and deletename ~= "" then
+ detail, currentfont = deletestored(detail,currentfont,deletename)
+ action = "load"
+ elseif selection and selection ~= "" then
+ currentfont = selection
+ elseif extra and extra ~= "" then
+ do_extra(detail,currentfont,extra)
+ action = "extras"
+ end
+
+ lmx.restore()
+
+ local fontname, fontfile, issub = fonts.names.specification(currentfont or "")
+
+ if fontfile then
+ lmx.variables['title-default'] = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile)
+ else
+ lmx.variables['title-default'] = 'ConTeXt Font Tester'
+ end
+
+ lmx.variables['color-background-green'] = '#4F6F6F'
+ lmx.variables['color-background-blue'] = '#6F6F8F'
+ lmx.variables['color-background-yellow'] = '#8F8F6F'
+ lmx.variables['color-background-purple'] = '#8F6F8F'
+
+ lmx.variables['color-background-body'] = '#808080'
+ lmx.variables['color-background-main'] = '#3F3F3F'
+ lmx.variables['color-background-one'] = lmx.variables['color-background-green']
+ lmx.variables['color-background-two'] = lmx.variables['color-background-blue']
+
+ lmx.variables['title'] = lmx.variables['title-default']
+
+ lmx.set('title', lmx.get('title'))
+ lmx.set('color-background-one', lmx.get('color-background-green'))
+ lmx.set('color-background-two', lmx.get('color-background-blue'))
+
+ -- lua table and adapt
+
+ lmx.set('formaction', "mtx-server-ctx-fonttest.lua")
+
+ local menu = { }
+ for k, v in ipairs { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} do
+ menu[#menu+1] = format("<button name='action' value='%s' type='submit'>%s</button>",v,v)
+ end
+ lmx.set('menu', concat(menu,"&nbsp;"))
+
+ logs.simple("action: %s",action or "no action")
+
+ lmx.set("status",format(status_template,currentfont or ""))
+
+ local result
+
+ if action == "select" then
+ lmx.set('maintext',select_font())
+ elseif action == "info" then
+ lmx.set('maintext',info_about())
+ elseif action == "extras" then
+ lmx.set('maintext',do_extras())
+ elseif currentfont and currentfont ~= "" then
+ if action == "save" then
+ lmx.set('maintext',save_font(currentfont,detail))
+ elseif action == "load" then
+ lmx.set('maintext',load_font(currentfont,detail))
+ elseif action == "source" then
+ lmx.set('maintext',show_source(currentfont,detail))
+ elseif action == "log" then
+ lmx.set('maintext',show_log(currentfont,detail))
+ elseif action == "features" then
+ lmx.set('maintext',show_font(currentfont,detail))
+ else
+ local e, s
+ if action == "process" then
+ e, s = process_font(currentfont,detail)
+ elseif action == "reset" then
+ e, s = reset_font(currentfont)
+ elseif action == "edit" then
+ e, s = edit_font(currentfont,detail)
+ else
+ e, s = process_font(currentfont,detail)
+ end
+ lmx.set('maintext',e)
+ lmx.set('javascriptdata',s)
+ lmx.set('javascripts',javascripts)
+ lmx.set('javascriptinit', "check_form()")
+ end
+ else
+ lmx.set('maintext',select_font())
+ end
+
+ result = { content = lmx.convert('context-fonttest.lmx') }
+
+ logs.simple("time spent on page: %0.03f seconds",os.clock()-start)
+
+ return result
+
+end
+
+return doit, true
+
+--~ make_lmx_page("test")
diff --git a/scripts/context/lua/mtx-server-ctx-help.lua b/scripts/context/lua/mtx-server-ctx-help.lua
new file mode 100644
index 000000000..c53d9f6e0
--- /dev/null
+++ b/scripts/context/lua/mtx-server-ctx-help.lua
@@ -0,0 +1,648 @@
+if not modules then modules = { } end modules ['mtx-server-ctx-help'] = {
+ version = 1.001,
+ comment = "Basic Definition Browser",
+ author = "Hans Hagen",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ dofile(resolvers.find_file("l-xml.lua","tex"))
+dofile(resolvers.find_file("l-aux.lua","tex"))
+dofile(resolvers.find_file("trac-lmx.lua","tex"))
+
+-- problem ... serialize parent stack
+
+local format = string.format
+local concat = table.concat
+
+-- -- -- make this a module: cont-xx.lua
+
+document = document or { }
+document.setups = document.setups or { }
+
+document.setups.div = {
+ pe = "<div dir='rtl' lang='arabic'>%s</div>"
+}
+
+document.setups.span = {
+ pe = "<span dir='rtl' lang='arabic'>%s</span>"
+}
+
+document.setups.translations = document.setups.translations or {
+
+ nl = {
+ ["title"] = "setup",
+ ["formula"] = "formule",
+ ["number"] = "getal",
+ ["list"] = "lijst",
+ ["dimension"] = "maat",
+ ["mark"] = "markering",
+ ["reference"] = "verwijzing",
+ ["command"] = "commando",
+ ["file"] = "file",
+ ["name"] = "naam",
+ ["identifier"] = "naam",
+ ["text"] = "tekst",
+ ["section"] = "sectie",
+ ["singular"] = "naam enkelvoud",
+ ["plural"] = "naam meervoud",
+ ["matrix"] = "n*m",
+ ["see"] = "zie",
+ ["inherits"] = "erft van",
+ ["optional"] = "optioneel",
+ ["displaymath"] = "formule",
+ ["index"] = "ingang",
+ ["math"] = "formule",
+ ["nothing"] = "leeg",
+ ["file"] = "file",
+ ["position"] = "positie",
+ ["reference"] = "verwijzing",
+ ["csname"] = "naam",
+ ["destination"] = "bestemming",
+ ["triplet"] = "triplet",
+ ["word"] = "woord",
+ ["content"] = "tekst",
+ },
+
+ en = {
+ ["title"] = "setup",
+ ["formula"] = "formula",
+ ["number"] = "number",
+ ["list"] = "list",
+ ["dimension"] = "dimension",
+ ["mark"] = "mark",
+ ["reference"] = "reference",
+ ["command"] = "command",
+ ["file"] = "file",
+ ["name"] = "name",
+ ["identifier"] = "identifier",
+ ["text"] = "text",
+ ["section"] = "section",
+ ["singular"] = "singular name",
+ ["plural"] = "plural name",
+ ["matrix"] = "n*m",
+ ["see"] = "see",
+ ["inherits"] = "inherits from",
+ ["optional"] = "optional",
+ ["displaymath"] = "formula",
+ ["index"] = "entry",
+ ["math"] = "formula",
+ ["nothing"] = "empty",
+ ["file"] = "file",
+ ["position"] = "position",
+ ["reference"] = "reference",
+ ["csname"] = "name",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "word",
+ ["content"] = "text",
+
+ ["noargument"] = "\\cs",
+ ["oneargument"] = "\\cs#1{..}",
+ ["twoarguments"] = "\\cs#1#2{..}{..}",
+ ["threearguments"] = "\\cs#1#2#3{..}{..}{..}",
+
+ },
+
+ de = {
+ ["title"] = "Setup",
+ ["formula"] = "Formel",
+ ["number"] = "Nummer",
+ ["list"] = "Liste",
+ ["dimension"] = "Dimension",
+ ["mark"] = "Beschriftung",
+ ["reference"] = "Referenz",
+ ["command"] = "Befehl",
+ ["file"] = "Datei",
+ ["name"] = "Name",
+ ["identifier"] = "Name",
+ ["text"] = "Text",
+ ["section"] = "Abschnitt",
+ ["singular"] = "singular",
+ ["plural"] = "plural",
+ ["matrix"] = "n*m",
+ ["see"] = "siehe",
+ ["inherits"] = "inherits from",
+ ["optional"] = "optioneel",
+ ["displaymath"] = "formula",
+ ["index"] = "entry",
+ ["math"] = "formula",
+ ["nothing"] = "empty",
+ ["file"] = "file",
+ ["position"] = "position",
+ ["reference"] = "reference",
+ ["csname"] = "name",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "word",
+ ["content"] = "text",
+ },
+
+ cz = {
+ ["title"] = "setup",
+ ["formula"] = "rovnice",
+ ["number"] = "cislo",
+ ["list"] = "seznam",
+ ["dimension"] = "dimenze",
+ ["mark"] = "znacka",
+ ["reference"] = "reference",
+ ["command"] = "prikaz",
+ ["file"] = "soubor",
+ ["name"] = "jmeno",
+ ["identifier"] = "jmeno",
+ ["text"] = "text",
+ ["section"] = "sekce",
+ ["singular"] = "jmeno v singularu",
+ ["plural"] = "jmeno v pluralu",
+ ["matrix"] = "n*m",
+ ["see"] = "viz",
+ ["inherits"] = "inherits from",
+ ["optional"] = "optioneel",
+ ["displaymath"] = "formula",
+ ["index"] = "entry",
+ ["math"] = "formula",
+ ["nothing"] = "empty",
+ ["file"] = "file",
+ ["position"] = "position",
+ ["reference"] = "reference",
+ ["csname"] = "name",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "word",
+ ["content"] = "text",
+ },
+
+ it = {
+ ["title"] = "setup",
+ ["formula"] = "formula",
+ ["number"] = "number",
+ ["list"] = "list",
+ ["dimension"] = "dimension",
+ ["mark"] = "mark",
+ ["reference"] = "reference",
+ ["command"] = "command",
+ ["file"] = "file",
+ ["name"] = "name",
+ ["identifier"] = "name",
+ ["text"] = "text",
+ ["section"] = "section",
+ ["singular"] = "singular name",
+ ["plural"] = "plural name",
+ ["matrix"] = "n*m",
+ ["see"] = "see",
+ ["inherits"] = "inherits from",
+ ["optional"] = "optioneel",
+ ["displaymath"] = "formula",
+ ["index"] = "entry",
+ ["math"] = "formula",
+ ["nothing"] = "empty",
+ ["file"] = "file",
+ ["position"] = "position",
+ ["reference"] = "reference",
+ ["csname"] = "name",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "word",
+ ["content"] = "text",
+ },
+
+ ro = {
+ ["title"] = "setari",
+ ["formula"] = "formula",
+ ["number"] = "numar",
+ ["list"] = "lista",
+ ["dimension"] = "dimensiune",
+ ["mark"] = "marcaj",
+ ["reference"] = "referinta",
+ ["command"] = "comanda",
+ ["file"] = "fisier",
+ ["name"] = "nume",
+ ["identifier"] = "nume",
+ ["text"] = "text",
+ ["section"] = "sectiune",
+ ["singular"] = "nume singular",
+ ["plural"] = "nume pluram",
+ ["matrix"] = "n*m",
+ ["see"] = "vezi",
+ ["inherits"] = "inherits from",
+ ["optional"] = "optioneel",
+ ["displaymath"] = "formula",
+ ["index"] = "entry",
+ ["math"] = "formula",
+ ["nothing"] = "empty",
+ ["file"] = "file",
+ ["position"] = "position",
+ ["reference"] = "reference",
+ ["csname"] = "name",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "word",
+ ["content"] = "text",
+ },
+
+ fr = {
+ ["title"] = "réglage",
+ ["formula"] = "formule",
+ ["number"] = "numéro",
+ ["list"] = "liste",
+ ["dimension"] = "dimension",
+ ["mark"] = "marquage",
+ ["reference"] = "reference",
+ ["command"] = "commande",
+ ["file"] = "fichier",
+ ["name"] = "nom",
+ ["identifier"] = "identificateur",
+ ["text"] = "texte",
+ ["section"] = "section",
+ ["singular"] = "nom singulier",
+ ["plural"] = "nom pluriel",
+ ["matrix"] = "n*m",
+ ["see"] = "vois",
+ ["inherits"] = "herite de",
+ ["optional"] = "optionel",
+ ["displaymath"] = "formule",
+ ["index"] = "entrée",
+ ["math"] = "formule",
+ ["nothing"] = "vide",
+ ["file"] = "fichier",
+ ["position"] = "position",
+ ["reference"] = "réference",
+ ["csname"] = "nom",
+ ["destination"] = "destination",
+ ["triplet"] = "triplet",
+ ["word"] = "mot",
+ ["content"] = "texte",
+ }
+
+}
+
+document.setups.formats = {
+ interface = [[<a href='mtx-server-ctx-help.lua?interface=%s'>%s</a>]],
+ href = [[<a href='mtx-server-ctx-help.lua?command=%s'>%s</a>]],
+ source = [[<a href='mtx-server-ctx-help.lua?source=%s'>%s</a>]],
+ optional_single = "[optional string %s]",
+ optional_list = "[optional list %s]",
+ mandate_single = "[mandate string %s]",
+ mandate_list = "[mandate list %s]",
+ parameter = [[<tr><td width='15%%'>%s</td><td width='15%%'>%s</td><td width='70%%'>%s</td></tr>]],
+ parameters = [[<table width='100%%'>%s</table>]],
+ listing = [[<pre><t>%s</t></listing>]],
+ special = "<i>%s</i>",
+ default = "<u>%s</u>",
+}
+
+local function translate(tag,int,noformat)
+ local t = document.setups.translations
+ local te = t["en"]
+ local ti = t[int] or te
+ if noformat then
+ return ti[tag] or te[tag] or tag
+ else
+ return document.setups.formats.special:format(ti[tag] or te[tag] or tag)
+ end
+end
+
+local function translated(e,int)
+ local attributes = e.at
+ local s = attributes.type or "?"
+ local tag = s:match("^cd:(.*)$")
+ if attributes.default == "yes" then
+ return document.setups.formats.default:format(tag)
+ elseif tag then
+ return translate(tag,int)
+ else
+ return s
+ end
+end
+
+document.setups.loaded = document.setups.loaded or { }
+
+document.setups.current = { }
+document.setups.showsources = false
+
+function document.setups.load(filename)
+ filename = resolvers.find_file(filename) or ""
+ if filename ~= "" then
+ local current = document.setups.loaded[filename]
+ if not current then
+ local loaded = xml.load(filename)
+ if loaded then
+ -- xml.inject(document.setups.root,"/",loaded)
+ current = {
+ file = filename,
+ root = loaded,
+ names = { },
+ used = { },
+ }
+ document.setups.loaded[filename] = current
+ end
+ end
+ document.setups.current = current or { }
+ end
+end
+
+function document.setups.name(ek)
+ local at = ek.at
+ local name = at.name
+ if at.type == 'environment' then
+ name = "start" .. name
+ end
+ if at.variant then
+ name = name .. ":" .. at.variant
+ end
+ if at.generated == "yes" then
+ name = name .. "*"
+ end
+ return name:lower()
+end
+
+function document.setups.csname(ek,int)
+ local cs = ""
+ local at = ek.at
+ if at.type == 'environment' then
+ cs = translate("start",int,true) .. cs
+ end
+ for r, d, k in xml.elements(ek,'cd:sequence/(cd:string|variable)') do
+ local dk = d[k]
+ if dk.tg == "string" then
+ cs = cs .. dk.at.value
+ else
+ cs = cs .. dk.at.value -- to be translated
+ end
+ end
+ return cs
+end
+
+function document.setups.names()
+ local current = document.setups.current
+ local names = current.names
+ if not names or #names == 0 then
+ names = { }
+ local name = document.setups.name
+ local csname = document.setups.csname
+ for r, d, k in xml.elements(current.root,'cd:command') do
+ local dk = d[k]
+ names[#names+1] = { dk.at.name, csname(dk,int) }
+ end
+ table.sort(names, function(a,b) return a[2]:lower() < b[2]:lower() end)
+ current.names = names
+ end
+ return names
+end
+
+function document.setups.show(name)
+ local current = document.setups.current
+ if current.root then
+ local name = name:gsub("[<>]","")
+ local setup = xml.first(current.root,"cd:command[@name='" .. name .. "']")
+ current.used[#current.used+1] = setup
+ xml.sprint(setup)
+ end
+end
+
+function document.setups.showused()
+ local current = document.setups.current
+ if current.root and next(current.used) then
+ for k,v in ipairs(table.sortedkeys(current.used)) do
+ xml.sprint(current.used[v])
+ end
+ end
+end
+function document.setups.showall()
+ local current = document.setups.current
+ if current.root then
+ local list = { }
+ xml.each_element(current.root,"cd:command", function(r,d,t)
+ local ek = d[t]
+ list[document.setups.name(ek)] = ek
+ end )
+ for k,v in ipairs(table.sortedkeys(list)) do
+ xml.sprint(list[v])
+ end
+ end
+end
+function document.setups.resolve(name)
+ local current = document.setups.current
+ if current.root then
+ local e = xml.filter(current.root,format("cd:define[@name='%s']/text()",name))
+ if e then
+ xml.sprint(e)
+ end
+ end
+end
+
+function document.setups.collect(name,int)
+ local current = document.setups.current
+ local formats = document.setups.formats
+ local command = xml.filter(current.root,format("cd:command[@name='%s']",name))
+ if command then
+ local attributes = command.at
+ local data = {
+ command = command,
+ category = attributes.category or "",
+ }
+ if document.setups.showsources then
+ data.source = (attributes.file and formats.source:format(attributes.file,attributes.file)) or ""
+ else
+ data.source = attributes.file or ""
+ end
+ local sequence, n = { "\\" .. document.setups.csname(command,int) }, 0
+ local arguments = { }
+ for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
+ n = n + 1
+ local attributes = d[k].at
+ if attributes.optional == 'yes' then
+ if attributes.list == 'yes' then
+ sequence[#sequence+1] = formats.optional_list:format(n)
+ else
+ sequence[#sequence+1] = formats.optional_single:format(n)
+ end
+ else
+ if attributes.list == 'yes' then
+ sequence[#sequence+1] = formats.mandate_list:format(n)
+ else
+ sequence[#sequence+1] = formats.mandate_single:format(n)
+ end
+ end
+ end
+ data.sequence = concat(sequence, " ")
+ local parameters, n = { }, 0
+ for r, d, k in xml.elements(command,"(cd:keywords|cd:assignments)") do
+ n = n + 1
+ if d[k].tg == "keywords" then
+ local left = sequence[n+1]
+ local right = { }
+ for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do
+ local tag = d[k].tg
+ if tag == "resolve" then
+ local name = d[k].at.name or ""
+ if name ~= "" then
+ local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name))
+ for r, d, k in xml.elements(resolved,"cd:constant") do
+ right[#right+1] = translated(d[k],int)
+ end
+ end
+ else
+ right[#right+1] = translated(d[k],int)
+ end
+ end
+ parameters[#parameters+1] = formats.parameter:format(left,"",concat(right, ", "))
+ else
+ local what = sequence[n+1]
+ for r, d, k in xml.elements(d[k],"(cd:parameter|cd:inherit)") do
+ local tag = d[k].tg
+ local left, right = d[k].at.name or "?", { }
+ if tag == "inherit" then
+ local name = d[k].at.name or "?"
+ local goto = document.setups.formats.href:format(name,"\\"..name)
+ if #parameters > 0 and not parameters[#parameters]:find("<br/>") then
+ parameters[#parameters+1] = formats.parameter:format("<br/>","","")
+ end
+ parameters[#parameters+1] = formats.parameter:format(what,formats.special:format(translate("inherits",int)),goto)
+ else
+ for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do
+ local tag = d[k].tg
+ if tag == "resolve" then
+ local name = d[k].at.name or ""
+ if name ~= "" then
+ local resolved = xml.filter(current.root,format("cd:define[@name='%s']",name))
+ for r, d, k in xml.elements(resolved,"cd:constant") do
+ right[#right+1] = translated(d[k],int)
+ end
+ end
+ else
+ right[#right+1] = translated(d[k],int)
+ end
+ end
+ parameters[#parameters+1] = formats.parameter:format(what,left,concat(right, ", "))
+ end
+ what = ""
+ end
+ end
+ parameters[#parameters+1] = formats.parameter:format("<br/>","","")
+ end
+ data.parameters = parameters
+ return data
+ else
+ return nil
+ end
+end
+
+-- -- --
+
+tex = tex or { }
+
+lmx.variables['color-background-green'] = '#4F6F6F'
+lmx.variables['color-background-blue'] = '#6F6F8F'
+lmx.variables['color-background-yellow'] = '#8F8F6F'
+lmx.variables['color-background-purple'] = '#8F6F8F'
+
+lmx.variables['color-background-body'] = '#808080'
+lmx.variables['color-background-main'] = '#3F3F3F'
+lmx.variables['color-background-main-left'] = '#3F3F3F'
+lmx.variables['color-background-main-right'] = '#5F5F5F'
+lmx.variables['color-background-one'] = lmx.variables['color-background-green']
+lmx.variables['color-background-two'] = lmx.variables['color-background-blue']
+
+lmx.variables['title-default'] = 'ConTeXt Help Information'
+lmx.variables['title'] = lmx.variables['title-default']
+
+function lmx.loadedfile(filename)
+ return io.loaddata(resolvers.find_file(filename)) -- return resolvers.texdatablob(filename)
+end
+
+-- -- --
+
+local interfaces = {
+ czech = 'cz',
+ dutch = 'nl',
+ english = 'en',
+ french = 'fr',
+ german = 'de',
+ italian = 'it',
+ persian = 'pe',
+ romanian = 'ro',
+}
+
+local lastinterface, lastcommand, lastsource = "en", "", ""
+
+local function doit(configuration,filename,hashed)
+
+ local formats = document.setups.formats
+
+ local start = os.clock()
+
+ local detail = aux.settings_to_hash(hashed.query or "")
+
+ lastinterface, lastcommand, lastsource = detail.interface or lastinterface, detail.command or lastcommand, detail.source or lastsource
+
+ if lastinterface then
+ logs.simple("checking interface: %s",lastinterface)
+ document.setups.load(format("cont-%s.xml",lastinterface))
+ end
+
+ local div = document.setups.div[lastinterface]
+ local span = document.setups.span[lastinterface]
+
+ local result = { content = "error" }
+
+ local names, refs, ints = document.setups.names(lastinterface), { }, { }
+ for k,v in ipairs(names) do
+ refs[k] = document.setups.formats.href:format(v[1],v[2])
+ end
+ for k,v in ipairs(table.sortedkeys(interfaces)) do
+ ints[k] = document.setups.formats.interface:format(interfaces[v],v)
+ end
+
+ lmx.restore()
+ lmx.set('title', 'ConTeXt Help Information')
+ lmx.set('color-background-one', lmx.get('color-background-green'))
+ lmx.set('color-background-two', lmx.get('color-background-blue'))
+
+ local n = concat(refs,"<br/>")
+ local i = concat(ints,"<br/><br/>")
+
+ if div then
+ lmx.set('names',div:format(n))
+ lmx.set('interfaces',div:format(i))
+ else
+ lmx.set('names', n)
+ lmx.set('interfaces', i)
+ end
+
+ -- first we need to add information about mkii/mkiv
+
+ if document.setups.showsources and lastsource and lastsource ~= "" then
+ -- todo: mkii, mkiv, tex (can be different)
+ local data = io.loaddata(resolvers.find_file(lastsource))
+ lmx.set('maintitle', lastsource)
+ lmx.set('maintext', formats.listing:format(data))
+ lastsource = ""
+ elseif lastcommand and lastcommand ~= "" then
+ local data = document.setups.collect(lastcommand,lastinterface)
+ if data then
+ lmx.set('maintitle', data.sequence)
+ local extra = { }
+ for k, v in ipairs { "environment", "category", "source" } do
+ if data[v] and data[v] ~= "" then
+ lmx.set(v, data[v])
+ extra[#extra+1] = v .. ": " .. data[v]
+ end
+ end
+ lmx.set('extra', concat(extra,", "))
+ lmx.set('maintext', formats.parameters:format(concat(data.parameters)))
+ else
+ lmx.set('maintext', "select command")
+ end
+ else
+ lmx.set('maintext', "no definition")
+ end
+
+ local content = lmx.convert('context-help.lmx')
+
+ logs.simple("time spent on page: %0.03f seconds",os.clock()-start)
+
+ return { content = content }
+end
+
+return doit, true
diff --git a/scripts/context/lua/mtx-server-ctx-startup.lua b/scripts/context/lua/mtx-server-ctx-startup.lua
new file mode 100644
index 000000000..fcb757b3e
--- /dev/null
+++ b/scripts/context/lua/mtx-server-ctx-startup.lua
@@ -0,0 +1,53 @@
+if not modules then modules = { } end modules ['mtx-server-ctx-startup'] = {
+ version = 1.001,
+ comment = "Overview Of Goodies",
+ author = "Hans Hagen",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+dofile(resolvers.find_file("trac-lmx.lua","tex"))
+
+function doit(configuration,filename,hashed)
+
+ lmx.restore()
+
+ lmx.variables['color-background-green'] = '#4F6F6F'
+ lmx.variables['color-background-blue'] = '#6F6F8F'
+ lmx.variables['color-background-yellow'] = '#8F8F6F'
+ lmx.variables['color-background-purple'] = '#8F6F8F'
+
+ lmx.variables['color-background-body'] = '#808080'
+ lmx.variables['color-background-main'] = '#3F3F3F'
+ lmx.variables['color-background-one'] = lmx.variables['color-background-green']
+ lmx.variables['color-background-two'] = lmx.variables['color-background-blue']
+
+ lmx.variables['title'] = "Overview Of Goodies"
+
+ lmx.set('title', lmx.get('title'))
+ lmx.set('color-background-one', lmx.get('color-background-green'))
+ lmx.set('color-background-two', lmx.get('color-background-blue'))
+
+
+ local list = { }
+ local root = file.dirname(resolvers.find_file("mtx-server.lua") or ".")
+ if root == "" then root = "." end
+ local pattern = root .. "/mtx-server-ctx-*.lua"
+ local files = dir.glob(pattern)
+ for i=1,#files do
+ local filename = file.basename(files[i])
+ local name = string.match(filename,"mtx%-server%-ctx%-(.-)%.lua$")
+ if name and name ~= "startup" then
+ list[#list+1] = string.format("<a href='%s' target='ctx-%s'>%s</a><br/><br/>",filename,name,name)
+ end
+ end
+
+ lmx.set('maintext',table.concat(list,"\n"))
+
+ result = { content = lmx.convert('context-base.lmx') }
+
+ return result
+
+end
+
+return doit, true
diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua
index d9eb355f6..74f0ed924 100644
--- a/scripts/context/lua/mtx-server.lua
+++ b/scripts/context/lua/mtx-server.lua
@@ -9,9 +9,10 @@ if not modules then modules = { } end modules ['mtx-server'] = {
scripts = scripts or { }
scripts.webserver = scripts.webserver or { }
-dofile(input.find_file("l-url.lua"))
+dofile(resolvers.find_file("l-url.lua","tex"))
+dofile(resolvers.find_file("luat-soc.lua","tex"))
-local socket = require("socket")
+local socket = socket or require("socket") -- redundant in future version
local format = string.format
-- The following two lists are taken from webrick (ruby) and
@@ -126,13 +127,39 @@ local handlers = { }
local function errormessage(client,configuration,n)
local data = format("<head><title>%s %s</title></head><html><h2>%s %s</h2></html>",n,messages[n],n,messages[n])
- input.report("handling error %s: %s",n,messages[n])
+ logs.simple("handling error %s: %s",n,messages[n])
handlers.generic(client,configuration,data,nil,true)
end
+local validpaths, registered = { }, { }
+
+function scripts.webserver.registerpath(name)
+ if not registered[name] then
+ local cleanname = string.gsub(name,"%.%.","deleted-parent")
+ logs.simple("registering path '%s'",cleanname)
+ validpaths[#validpaths+1] = cleanname
+ registered[name] = true
+ end
+end
+
function handlers.generic(client,configuration,data,suffix,iscontent)
if not iscontent then
- data = io.loaddata(file.join(configuration.root,data))
+ local name = data
+ logs.simple("requested file '%s'",name)
+ local fullname = file.join(configuration.root,name)
+ data = io.loaddata(fullname) or ""
+ if data == "" then
+ for n=1,#validpaths do
+ local fullname = file.join(validpaths[n],name)
+ data = io.loaddata(fullname) or ""
+ if data ~= "" then
+ logs.simple("sending generic file '%s'",fullname)
+ break
+ end
+ end
+ else
+ logs.simple("sending generic file '%s'",fullname)
+ end
end
if data and data ~= "" then
client:send("HTTP/1.1 200 OK\r\n")
@@ -155,21 +182,37 @@ end
--~ return { content = filename }
--~ end
+local loaded = { }
+
function handlers.lua(client,configuration,filename,suffix,iscontent,hashed) -- filename will disappear, and become hashed.filename
local filename = file.join(configuration.scripts,filename)
- if not input.aux.qualified_path(filename) then
+ if not file.is_qualified_path(filename) then
filename = file.join(configuration.root,filename)
end
-- todo: split url in components, see l-url; rather trivial
- input.report("locating script: %s",filename)
- if lfs.isfile(filename) then
- local result = loadfile(filename)
- input.report("return type: %s",type(result))
- if result and type(result) == "function" then
- -- result() should return a table { [type=,] [length=,] content= }, function or string
- result = result()
+ local result, keep = loaded[filename], false
+ if result then
+ logs.simple("reusing script: %s",filename)
+ else
+ logs.simple("locating script: %s",filename)
+ if lfs.isfile(filename) then
+ logs.simple("loading script: %s",filename)
+ result = loadfile(filename)
+ logs.simple("return type: %s",type(result))
+ if result and type(result) == "function" then
+ -- result() should return a table { [type=,] [length=,] content= }, function or string
+ result, keep = result()
+ if keep then
+ logs.simple("saving script: %s",type(result))
+ loaded[filename] = result
+ end
+ end
+ else
+ errormessage(client,configuration,404)
end
- if result and type(result) == "function" then
+ end
+ if result then
+ if type(result) == "function" then
result = result(configuration,filename,hashed) -- second argument will become query
end
if result and type(result) == "string" then
@@ -181,9 +224,9 @@ function handlers.lua(client,configuration,filename,suffix,iscontent,hashed) --
local action = handlers[suffix] or handlers.generic
action(client,configuration,result.content,suffix,true) -- content
elseif result.filename then
- local suffix = file.extname(filename) or "text/html"
+ local suffix = file.extname(result.filename) or "text/html"
local action = handlers[suffix] or handlers.generic
- action(client,configuration,filename,suffix,false) -- filename
+ action(client,configuration,result.filename,suffix,false) -- filename
else
errormessage(client,configuration,404)
end
@@ -198,18 +241,19 @@ end
handlers.luc = handlers.lua
handlers.html = handlers.htm
-local indices = { "index.htm", "index.html" }
+local indices = { "index.htm", "index.html" }
+local portnumber = 31415 -- pi suits tex
function scripts.webserver.run(configuration)
-- check configuration
- configuration.port = tonumber(configuration.port or os.getenv("MTX_SERVER_PORT") or 8080) or 8080
+ configuration.port = tonumber(configuration.port or os.getenv("MTX_SERVER_PORT") or portnumber) or portnumber
if not configuration.root or not lfs.isdir(configuration.root) then
configuration.root = os.getenv("MTX_SERVER_ROOT") or "."
end
-- locate root and index file in tex tree
if not lfs.isdir(configuration.root) then
for _, name in ipairs(indices) do
- local root = input.resolve("path:" .. name) or ""
+ local root = resolvers.resolve("path:" .. name) or ""
if root ~= "" then
configuration.root = root
configuration.index = configuration.index or name
@@ -217,6 +261,7 @@ function scripts.webserver.run(configuration)
end
end
end
+ configuration.root = dir.expand_name(configuration.root)
if not configuration.index then
for _, name in ipairs(indices) do
if lfs.isfile(file.join(configuration.root,name)) then
@@ -226,14 +271,17 @@ function scripts.webserver.run(configuration)
end
configuration.index = configuration.index or "unknown"
end
- configuration.scripts = configuration.scripts or "cgi"
+ if not configuration.scripts or configuration.scripts == "" then
+ configuration.scripts = dir.expand_name(file.join(configuration.root or ".",configuration.scripts or "."))
+ end
-- so far for checks
- input.report("running at port: %s",configuration.port)
- input.report("document root: %s",configuration.root)
- input.report("main index file: %s",configuration.index)
- input.report("scripts subpath: %s",configuration.scripts)
+ logs.simple("running at port: %s",configuration.port)
+ logs.simple("document root: %s",configuration.root or resolvers.ownpath)
+ logs.simple("main index file: %s",configuration.index)
+ logs.simple("scripts subpath: %s",configuration.scripts)
local server = assert(socket.bind("*", configuration.port))
while true do -- no multiple clients
+ local start = os.clock()
local client = server:accept()
client:settimeout(configuration.timeout or 60)
local request, e = client:receive()
@@ -241,26 +289,26 @@ function scripts.webserver.run(configuration)
errormessage(client,configuration,404)
else
local from = client:getpeername()
- input.report("request from: %s",tostring(from))
+ logs.simple("request from: %s",tostring(from))
local fullurl = request:match("GET (.+) HTTP/.*$") -- todo: more clever
-fullurl = socket.url.unescape(fullurl)
-local hashed = url.hashed(fullurl)
-local query = url.query(hashed.query)
-filename = hashed.path
+ fullurl = socket.url.unescape(fullurl)
+ local hashed = url.hashed(fullurl)
+ local query = url.query(hashed.query)
+ local filename = hashed.path
if filename then
filename = socket.url.unescape(filename)
- input.report("requested action: %s",filename)
+ logs.simple("requested action: %s",filename)
if filename:find("%.%.") then
filename = nil -- invalid path
end
if filename == nil or filename == "" or filename == "/" then
filename = configuration.index
- input.report("invalid filename, forcing: %s",filename)
+ logs.simple("invalid filename, forcing: %s",filename)
end
local suffix = file.extname(filename)
local action = handlers[suffix] or handlers.generic
if action then
- input.report("performing action: %s",filename)
+ logs.simple("performing action: %s",filename)
action(client,configuration,filename,suffix,false,hashed) -- filename and no content
else
errormessage(client,configuration,404)
@@ -270,10 +318,11 @@ filename = hashed.path
end
end
client:close()
+ logs.simple("time spent with client: %0.03f seconds",os.clock()-start)
end
end
-banner = banner .. " | webserver "
+logs.extendbanner("Simple Webserver 0.10")
messages.help = [[
--start start server
@@ -281,15 +330,26 @@ messages.help = [[
--root server root
--scripts scripts sub path
--index index file
+--auto start on own path
]]
-if environment.argument("start") then
+if environment.argument("auto") then
+ local path = resolvers.find_file("mtx-server.lua") or "."
scripts.webserver.run {
port = environment.argument("port"),
- root = environment.argument("root"), -- "e:/websites/www.pragma-ade.com",
+ root = environment.argument("root") or file.dirname(path) or ".",
+ scripts = environment.argument("scripts") or file.dirname(path) or ".",
+ }
+elseif environment.argument("start") then
+ scripts.webserver.run {
+ port = environment.argument("port"),
+ root = environment.argument("root") or ".", -- "e:/websites/www.pragma-ade.com",
index = environment.argument("index"),
- scripts = environment.argument("scripts") or "cgi",
+ scripts = environment.argument("scripts"),
}
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
+
+
+-- mtxrun --script server --start => http://localhost:8080/mtx-server-ctx-help.lua
diff --git a/scripts/context/lua/mtx-timing.lua b/scripts/context/lua/mtx-timing.lua
new file mode 100644
index 000000000..1dcb9aa0e
--- /dev/null
+++ b/scripts/context/lua/mtx-timing.lua
@@ -0,0 +1,201 @@
+if not modules then modules = { } end modules ['mtx-timing'] = {
+ version = 1.002,
+ comment = "companion to mtxrun.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gsub, concat = string.format, string.gsub, table.concat
+
+dofile(resolvers.find_file("trac-tim.lua","tex"))
+dofile(resolvers.find_file("trac-lmx.lua","tex"))
+
+local meta = [[
+ beginfig(%s) ;
+ begingroup ;
+ save p, q, b, h, w ;
+ path p, q, b ; numeric h, w ;
+ linecap := butt ;
+ h := 100 ;
+ w := 800pt ;
+ p := %s ;
+ q := %s ;
+ p := p shifted -llcorner p ;
+ q := q shifted -llcorner q ;
+ q := q xstretched w ;
+ p := p xstretched w ;
+ b := boundingbox (llcorner p -- llcorner p shifted (w,h)) ;
+ draw b withcolor white withpen pencircle scaled 4pt ;
+ draw p withcolor red withpen pencircle scaled 4pt ;
+ draw q withcolor blue withpen pencircle scaled 2pt ;
+ endgroup ;
+ endfig ;
+]]
+
+local html_graphic = [[
+ <h1><a name='graphic-%s'>%s (red) %s (blue)</a></h1>
+ <table>
+ <tr>
+ <td>%s</td>
+ <td valign='top'>
+ &nbsp;&nbsp;min: %s<br/>
+ &nbsp;&nbsp;max: %s<br/>
+ &nbsp;&nbsp;pages: %s<br/>
+ &nbsp;&nbsp;average: %s<br/>
+ </td>
+ </tr>
+ </table>
+ <br/>
+]]
+
+local html_menu = [[
+ <a href='#graphic-%s'>%s</a>
+]]
+
+local directrun = true
+
+function goodies.progress.make_svg(filename,other)
+ local metadata, menudata, c = { }, { }, 0
+ metadata[#metadata+1] = 'outputformat := "svg" ;'
+ for _, kind in pairs { "parameters", "nodes" } do
+ local mdk = { }
+ menudata[kind] = mdk
+ for n, name in pairs(goodies.progress[kind](filename)) do
+ local first = goodies.progress.path(filename,name)
+ local second = goodies.progress.path(filename,other)
+ c = c + 1
+ metadata[#metadata+1] = format(meta,c,first,second)
+ mdk[#mdk+1] = { name, c }
+ end
+ end
+ metadata[#metadata+1] = "end ."
+ metadata = concat(metadata,"\n\n")
+ if directrun then
+ dofile(resolvers.find_file("mlib-run.lua","tex"))
+ commands = commands or { }
+ commands.writestatus = logs.report
+ local result = metapost.directrun("metafun","timing data","svg",true,metadata)
+ return menudata, result
+ else
+ local mpname = file.replacesuffix(filename,"mp")
+ io.savedata(mpname,metadata)
+ os.execute(format("mpost --progname=context --mem=metafun.mem %s",mpname))
+ os.remove(mpname)
+ os.remove(file.removesuffix(filename).."-mpgraph.mpo") -- brr
+ os.remove(file.removesuffix(filename)..".log") -- brr
+ return menudata
+ end
+end
+
+function goodies.progress.makehtml(filename,other,menudata,metadata)
+ local graphics = { }
+ local result = { graphics = graphics }
+ for _, kind in pairs { "parameters", "nodes" } do
+ local md = menudata[kind]
+ local menu = { }
+ result[kind] = menu
+ for k, v in ipairs(md) do
+ local name, number = v[1], v[2]
+ local min = goodies.progress.bot(filename,name)
+ local max = goodies.progress.top(filename,name)
+ local pages = goodies.progress.pages(filename)
+ local average = math.round(max/pages)
+ if directrun then
+ local data = metadata[number]
+ menu[#menu+1] = format(html_menu,name,name)
+ graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average)
+ else
+ local mpname = file.replacesuffix(filename,number)
+ local data = io.loaddata(mpname) or ""
+ -- data = gsub(data,"<!%-%-(.-)%-%->[\n\r]*","")
+ data = gsub(data,"<%?xml.->","")
+ menu[#menu+1] = format(html_menu,name,name)
+ graphics[#graphics+1] = format(html_graphic,name,name,other,data,min,max,pages,average)
+ os.remove(mpname)
+ end
+ end
+ end
+ return result
+end
+
+function goodies.progress.valid_file(name)
+ return name and name ~= "" and lfs.isfile(name .. "-luatex-progress.lut")
+end
+
+function goodies.progress.make_lmx_page(name,launch,remove)
+ local filename = name .. "-luatex-progress"
+ local other = "elapsed_time"
+ local template = 'context-timing.lmx'
+
+ lmx.variables['color-background-green'] = '#4F6F6F'
+ lmx.variables['color-background-blue'] = '#6F6F8F'
+ lmx.variables['color-background-yellow'] = '#8F8F6F'
+ lmx.variables['color-background-purple'] = '#8F6F8F'
+
+ lmx.variables['color-background-body'] = '#808080'
+ lmx.variables['color-background-main'] = '#3F3F3F'
+ lmx.variables['color-background-one'] = lmx.variables['color-background-green']
+ lmx.variables['color-background-two'] = lmx.variables['color-background-blue']
+
+ lmx.variables['title-default'] = 'ConTeXt Timing Information'
+ lmx.variables['title'] = lmx.variables['title-default']
+
+ lmx.htmfile = function(name) return name .. "-timing.xhtml" end
+ lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end
+
+ lmx.set('title', format('ConTeXt Timing Information: %s',file.basename(name)))
+ lmx.set('color-background-one', lmx.get('color-background-green'))
+ lmx.set('color-background-two', lmx.get('color-background-blue'))
+
+ goodies.progress.convert(filename)
+
+ local menudata, metadata = goodies.progress.make_svg(filename,other)
+ local htmldata = goodies.progress.makehtml(filename,other,menudata,metadata)
+
+ lmx.set('parametersmenu', concat(htmldata.parameters, "&nbsp;&nbsp;"))
+ lmx.set('nodesmenu', concat(htmldata.nodes, "&nbsp;&nbsp;"))
+ lmx.set('graphics', concat(htmldata.graphics, "\n\n"))
+
+ if launch then
+ local htmfile = lmx.show(template)
+ if remove then
+ os.sleep(1) -- give time to launch
+ os.remove(htmfile)
+ end
+ else
+ lmx.make(template)
+ end
+
+ lmx.restore()
+end
+
+scripts = scripts or { }
+scripts.timings = scripts.timings or { }
+
+function scripts.timings.xhtml(filename)
+ if filename == "" then
+ logs.simple("provide filename")
+ elseif not goodies.progress.valid_file(filename) then
+ logs.simple("first run context again with the --timing option")
+ else
+ local basename = file.removesuffix(filename)
+ local launch = environment.argument("launch")
+ local remove = environment.argument("remove")
+ goodies.progress.make_lmx_page(basename,launch,remove)
+ end
+end
+
+logs.extendbanner("ConTeXt Timing Tools 0.1",true)
+
+messages.help = [[
+--xhtml make xhtml file
+--launch launch after conversion
+--remove remove after launching
+]]
+
+if environment.argument("xhtml") then
+ scripts.timings.xhtml(environment.files[1] or "")
+else
+ logs.help(messages.help)
+end
diff --git a/scripts/context/lua/mtx-unzip.lua b/scripts/context/lua/mtx-unzip.lua
new file mode 100644
index 000000000..f990f4210
--- /dev/null
+++ b/scripts/context/lua/mtx-unzip.lua
@@ -0,0 +1,101 @@
+-- maybe --pattern
+
+logs.extendbanner("Simple Unzipper 0.10")
+
+messages.help = [[
+--list list files in archive
+--junk flatten unzipped directory structure
+--extract extract files
+]]
+
+scripts = scripts or { }
+scripts.unzipper = scripts.unzipper or { }
+
+function scripts.unzipper.help()
+ logs.help(messages.help)
+end
+
+function scripts.unzipper.opened()
+ local filename = environment.files[1]
+ if filename and filename ~= "" then
+ filename = file.addsuffix(filename,'zip')
+ local zipfile = zip.open(filename)
+ if zipfile then
+ return zipfile
+ end
+ end
+ logs.report("unzip", "no zip file: " .. filename)
+ return false
+end
+
+function scripts.unzipper.list()
+ local zipfile = scripts.unzipper.opened()
+ if zipfile then
+ local n = 0
+ for k in zipfile:files() do
+ if #k.filename > n then n = #k.filename end
+ end
+ local files, paths, compressed, uncompressed = 0, 0, 0, 0
+ for k in zipfile:files() do
+ if k.filename:find("/$") then
+ paths = paths + 1
+ print(string.format("%s", k.filename:rpadd(n," ")))
+ else
+ files = files + 1
+ local cs, us = k.compressed_size, k.uncompressed_size
+ if cs > compressed then
+ compressed = cs
+ end
+ if us > uncompressed then
+ uncompressed = us
+ end
+ print(string.format("%s % 9i % 9i", k.filename:rpadd(n," "),cs,us))
+ end
+ end
+ print(string.format("\n%s % 9i % 9i", (files .. " files, " .. paths .. " directories"):rpadd(n," "),compressed,uncompressed))
+ end
+end
+
+function zip.loaddata(zipfile,filename)
+ local f = zipfile:open(filename)
+ if f then
+ local data = f:read("*a")
+ f:close()
+ return data
+ end
+ return nil
+end
+
+function scripts.unzipper.extract()
+ local zipfile = scripts.unzipper.opened()
+ if zipfile then
+ local junk = environment.arguments["j"] or environment.arguments["junk"]
+ for k in zipfile:files() do
+ local filename = k.filename
+ if filename:find("/$") then
+ if not junk then
+ lfs.mkdir(filename)
+ end
+ else
+ local data = zip.loaddata(zipfile,filename)
+ if data then
+ if junk then
+ filename = file.basename(filename)
+ end
+ io.savedata(filename,data)
+ print(filename)
+ end
+ end
+ end
+ end
+end
+
+if environment.arguments["h"] or environment.arguments["help"] then
+ scripts.unzipper.help()
+elseif environment.arguments["l"] or environment.arguments["list"] then
+ scripts.unzipper.list(zipfile)
+elseif environment.files[1] then -- implicit --extract
+ scripts.unzipper.extract(zipfile)
+else
+ scripts.unzipper.help()
+end
diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua
index b56780c68..66f6898d3 100644
--- a/scripts/context/lua/mtx-update.lua
+++ b/scripts/context/lua/mtx-update.lua
@@ -1,5 +1,5 @@
if not modules then modules = { } end modules ['mtx-update'] = {
- version = 1.001,
+ version = 1.002,
comment = "companion to mtxrun.lua",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -11,15 +11,20 @@ if not modules then modules = { } end modules ['mtx-update'] = {
-- Together with Arthur Reutenauer she made sure that it worked well on all
-- platforms that matter.
+local format, concat, gmatch = string.format, table.concat, string.gmatch
+
scripts = scripts or { }
scripts.update = scripts.update or { }
minimals = minimals or { }
minimals.config = minimals.config or { }
+-- this is needed under windows
+-- else rsync fails to set the right chmod flags to files
+
os.setenv("CYGWIN","nontsec")
-scripts.update.allformats = {
+scripts.update.texformats = {
"cont-en",
"cont-nl",
"cont-cz",
@@ -28,125 +33,105 @@ scripts.update.allformats = {
"cont-it",
"cont-ro",
"cont-uk",
- "metafun",
+ "cont-pe",
+ "cont-xp",
"mptopdf",
"plain"
}
-scripts.update.fewformats = {
- "cont-en",
- "cont-nl",
+scripts.update.mpformats = {
"metafun",
- "mptopdf",
- "plain"
+ "mpost",
}
+-- experimental is not functional at the moment
+
scripts.update.repositories = {
"current",
"experimental"
}
+-- more options than just these two are available (no idea why this is here)
+
scripts.update.versions = {
"current",
"latest"
}
+-- list of basic folders that are needed to make a functional distribution
+
+scripts.update.base = {
+ { "base/tex/", "texmf" },
+ { "base/metapost/", "texmf" },
+ { "fonts/common/", "texmf" },
+ { "fonts/other/", "texmf" }, -- not *really* needed, but helpful
+ { "context/<version>/", "texmf-context" },
+ { "context/img/", "texmf-context" },
+ { "misc/setuptex/", "." },
+ { "misc/web2c", "texmf" },
+ { "bin/common/<platform>/", "texmf-<platform>" },
+ { "bin/context/<platform>/", "texmf-<platform>" },
+ { "bin/metapost/<platform>/", "texmf-<platform>" },
+ { "bin/man/", "texmf-<platform>" },
+}
+
+-- binaries and font-related files
+-- for pdftex we don't need OpenType fonts, for LuaTeX/XeTeX we don't need TFM files
+
scripts.update.engines = {
["luatex"] = {
- { "base/tex/", "texmf" },
- { "base/metapost/", "texmf" },
{ "fonts/new/", "texmf" },
- { "fonts/common/", "texmf" },
- { "fonts/other/", "texmf" },
- { "context/<version>/", "texmf-context" },
- { "context/img/", "texmf-context" },
- { "context/config/", "texmf-context" },
- { "misc/setuptex/", "." },
- { "misc/web2c", "texmf" },
- { "bin/common/<platform>/", "texmf-<platform>" },
- { "bin/context/<platform>/", "texmf-<platform>" },
- { "bin/metapost/<platform>/", "texmf-<platform>" },
{ "bin/luatex/<platform>/", "texmf-<platform>" },
- { "bin/man/", "texmf-<platform>" }
},
["xetex"] = {
- { "base/tex/", "texmf" },
- { "base/metapost/", "texmf" },
{ "base/xetex/", "texmf" },
{ "fonts/new/", "texmf" },
- { "fonts/common/", "texmf" },
- { "fonts/other/", "texmf" },
- { "context/<version>/", "texmf-context" },
- { "context/img/", "texmf-context" },
- { "context/config/", "texmf-context" },
- { "misc/setuptex/", "." },
- { "misc/web2c", "texmf" },
- { "bin/common/<platform>/", "texmf-<platform>" },
- { "bin/context/<platform>/", "texmf-<platform>" },
- { "bin/metapost/<platform>/", "texmf-<platform>" },
{ "bin/xetex/<platform>/", "texmf-<platform>" },
- { "bin/man/", "texmf-<platform>" }
},
["pdftex"] = {
- { "base/tex/", "texmf" },
- { "base/metapost/", "texmf" },
{ "fonts/old/", "texmf" },
- { "fonts/common/", "texmf" },
- { "fonts/other/", "texmf" },
- { "context/<version>/", "texmf-context" },
- { "context/img/", "texmf-context" },
- { "context/config/", "texmf-context" },
- { "misc/setuptex/", "." },
- { "misc/web2c", "texmf" },
- { "bin/common/<platform>/", "texmf-<platform>" },
- { "bin/context/<platform>/", "texmf-<platform>" },
- { "bin/metapost/<platform>/", "texmf-<platform>" },
{ "bin/pdftex/<platform>/", "texmf-<platform>" },
- { "bin/man/", "texmf-<platform>" }
},
["all"] = {
- { "base/tex/", "texmf" },
- { "base/metapost/", "texmf" },
- { "base/xetex/", "texmf" },
- { "fonts/old/", "texmf" },
{ "fonts/new/", "texmf" },
- { "fonts/common/", "texmf" },
- { "fonts/other/", "texmf" },
- { "context/<version>/", "texmf-context" },
- { "context/img/", "texmf-context" },
- { "context/config/", "texmf-context" },
- { "misc/setuptex/", "." },
- { "misc/web2c", "texmf" },
- { "bin/common/<platform>/", "texmf-<platform>" },
- { "bin/context/<platform>/", "texmf-<platform>" },
- { "bin/metapost/<platform>/", "texmf-<platform>" },
+ { "fonts/old/", "texmf" },
+ { "base/xetex/", "texmf" },
{ "bin/luatex/<platform>/", "texmf-<platform>" },
{ "bin/xetex/<platform>/", "texmf-<platform>" },
{ "bin/pdftex/<platform>/", "texmf-<platform>" },
- { "bin/man/", "texmf-<platform>" }
},
}
scripts.update.platforms = {
- ["mswin"] = "mswin",
- ["windows"] = "mswin",
- ["win32"] = "mswin",
- ["win"] = "mswin",
- ["linux"] = "linux",
- ["freebsd"] = "freebsd",
- ["linux-32"] = "linux",
- ["linux-64"] = "linux-64",
- ["linux32"] = "linux",
- ["linux64"] = "linux-64",
- ["linux-ppc"] = "linux-ppc",
- ["ppc"] = "linux-ppc",
- ["osx"] = "osx-intel",
- ["osx-intel"] = "osx-intel",
- ["osx-ppc"] = "osx-ppc",
- ["osx-powerpc"] = "osx-ppc",
- ["osxintel"] = "osx-intel",
- ["osxppc"] = "osx-ppc",
- ["osxpowerpc"] = "osx-ppc",
+ ["mswin"] = "mswin",
+ ["windows"] = "mswin",
+ ["win32"] = "mswin",
+ ["win"] = "mswin",
+ ["linux"] = "linux",
+ ["freebsd"] = "freebsd",
+ ["freebsd-amd64"] = "freebsd-amd64",
+ ["linux-32"] = "linux",
+ ["linux-64"] = "linux-64",
+ ["linux32"] = "linux",
+ ["linux64"] = "linux-64",
+ ["linux-ppc"] = "linux-ppc",
+ ["ppc"] = "linux-ppc",
+ ["osx"] = "osx-intel",
+ ["macosx"] = "osx-intel",
+ ["osx-intel"] = "osx-intel",
+ ["osx-ppc"] = "osx-ppc",
+ ["osx-powerpc"] = "osx-ppc",
+ ["osxintel"] = "osx-intel",
+ ["osxppc"] = "osx-ppc",
+ ["osxpowerpc"] = "osx-ppc",
+ ["solaris-intel"] = "solaris-intel",
+ ["solaris-sparc"] = "solaris-sparc",
+ ["solaris"] = "solaris-sparc",
+}
+
+-- the list is filled up later (when we know what modules to download)
+
+scripts.update.modules = {
}
function scripts.update.run(str)
@@ -160,7 +145,7 @@ function scripts.update.run(str)
end
function scripts.update.fullpath(path)
- if input.aux.rootbased_path(path) then
+ if file.is_rootbased_path(path) then
return path
else
return lfs.currentdir() .. "/" .. path
@@ -168,47 +153,138 @@ function scripts.update.fullpath(path)
end
function scripts.update.synchronize()
+
logs.report("update","start")
+
local texroot = scripts.update.fullpath(states.get("paths.root"))
- local engines = states.get('engines')
- local platforms = states.get('platforms')
- local repositories = states.get('repositories')
- local bin = states.get("rsync.program")
- local url = states.get("rsync.server")
- local version = states.get("context.version")
+ local engines = states.get('engines') or { }
+ local platforms = states.get('platforms') or { }
+ local repositories = states.get('repositories') -- minimals
+ local bin = states.get("rsync.program") -- rsync
+ local url = states.get("rsync.server") -- contextgarden.net
+ local version = states.get("context.version") -- current (or beta)
+ local extras = states.get("extras") -- extra goodies (like modules)
local force = environment.argument("force")
+
+ bin = string.gsub(bin,"\\","/")
+
if not url:find("::$") then url = url .. "::" end
local ok = lfs.attributes(texroot,"mode") == "directory"
if not ok and force then
dir.mkdirs(texroot)
ok = lfs.attributes(texroot,"mode") == "directory"
end
+
+ if force then
+ dir.mkdirs(format("%s/%s", texroot, "texmf-cache"))
+ dir.mkdirs(format("%s/%s", texroot, "texmf-local"))
+ end
+
if ok or not force then
- if force then
- dir.mkdirs(string.format("%s/%s", texroot, "texmf-cache"))
+
+ local fetched, individual, osplatform = { }, { }, os.currentplatform()
+
+ -- takes a collection as argument and returns a list of folders
+
+ local function collection_to_list_of_folders(collection, platform)
+ local archives = {}
+ for _, c in ipairs(collection) do
+ local archive = c[1]
+ archive = archive:gsub("<platform>", platform)
+ archive = archive:gsub("<version>", version)
+ archives[#archives+1] = archive
+ end
+ return archives
end
- local fetched, individual = { }, { }
- for engine, _ in pairs(engines) do
- local collections = scripts.update.engines[engine]
- if collections then
- for _, collection in ipairs(collections) do
- for platform, _ in pairs(platforms) do
- platform = scripts.update.platforms[platform]
- if platform then
- local archive = collection[1]:gsub("<platform>", platform)
- local destination = string.format("%s/%s", texroot, collection[2]:gsub("<platform>", platform))
- destination = destination:gsub("\\","/")
- archive = archive:gsub("<version>",version)
---~ if platform == "windows" or platform == "mswin" then
- if os.currentplatform() == "windows" or os.currentplatform() == "mswin" then
- destination = destination:gsub("([a-zA-Z]):/", "/cygdrive/%1/")
- end
- individual[#individual+1] = { archive, destination }
+
+ -- takes a list of folders as argument and returns a string for rsync
+ -- sample input:
+ -- {'bin/common', 'bin/context'}
+ -- output:
+ -- 'minimals/current/bin/common minimals/current/bin/context'
+
+ local function list_of_folders_to_rsync_string(list_of_folders)
+ local repository = 'current'
+ local prefix = format("%s/%s/", states.get('rsync.module'), repository) -- minimals/current/
+
+ return prefix .. concat(list_of_folders, format(" %s", prefix))
+ end
+
+ -- example of usage: print(list_of_folders_to_rsync_string(collection_to_list_of_folders(scripts.update.base, os.currentplatform)))
+
+ -- rename function and add some more functionality:
+ -- * recursive/non-recursive (default: non-recursive)
+ -- * filter folders or regular files only (default: no filter)
+ -- * grep for size of included files (with --stats switch)
+
+ local function get_list_of_files_from_rsync(list_of_folders)
+ -- temporary file to store the output of rsync (could be a more random name; watch for overwrites)
+ local temp_file = "rsync.tmp.txt"
+ -- a set of folders
+ local folders = {}
+ local command = format("%s %s'%s' > %s", bin, url, list_of_folders_to_rsync_string(list_of_folders), temp_file)
+ os.execute(command)
+ -- read output of rsync
+ local data = io.loaddata(temp_file) or ""
+ -- for every line extract the filename
+ for chmod, s in data:gmatch("([d%-][rwx%-]+).-(%S+)[\n\r]") do
+ -- skip "current" folder
+ if s ~= '.' and chmod:len() == 10 then
+ folders[#folders+1] = s
+ end
+ end
+ -- delete the file to which we have put output of rsync
+ os.remove(temp_file)
+ return folders
+ end
+
+ -- rsync://contextgarden.net/minimals/current/modules/
+
+ if extras and type(extras) == "table" then
+ -- fetch the list of available modules from rsync server
+ local available_modules = get_list_of_files_from_rsync({"modules/"})
+ -- hash of requested modules
+ -- local h = table.tohash(extras:split(","))
+ for _, s in ipairs(available_modules) do
+ -- if extras == "all" or h[s] then
+ if extras.all or extras[s] then
+ scripts.update.modules[#scripts.update.modules+1] = { format("modules/%s/",s), "texmf-context" }
+ end
+ end
+ -- TODO: check if every module from the list has been added and issue warning otherwise
+ -- one idea to do it: remove every value from h once added and then check if anything is left in h
+ end
+
+ local function add_collection(collection,platform)
+ if collection and platform then
+ platform = scripts.update.platforms[platform]
+ if platform then
+ for _, c in ipairs(collection) do
+ local archive = c[1]:gsub("<platform>", platform)
+ local destination = format("%s/%s", texroot, c[2]:gsub("<platform>", platform))
+ destination = destination:gsub("\\","/")
+ archive = archive:gsub("<version>",version)
+ if osplatform == "windows" or osplatform == "mswin" then
+ destination = destination:gsub("([a-zA-Z]):/", "/cygdrive/%1/")
end
+ individual[#individual+1] = { archive, destination }
end
end
end
end
+
+ for platform, _ in pairs(platforms) do
+ add_collection(scripts.update.base,platform)
+ end
+ for platform, _ in pairs(platforms) do
+ add_collection(scripts.update.modules,platform)
+ end
+ for engine, _ in pairs(engines) do
+ for platform, _ in pairs(platforms) do
+ add_collection(scripts.update.engines[engine],platform)
+ end
+ end
+
local combined = { }
for _, repository in ipairs(scripts.update.repositories) do
if repositories[repository] then
@@ -219,11 +295,11 @@ function scripts.update.synchronize()
cd = { }
combined[destination] = cd
end
- cd[#cd+1] = string.format("%s/%s/%s",states.get('rsync.module'),repository,archive)
+ cd[#cd+1] = format("%s/%s/%s",states.get('rsync.module'),repository,archive)
end
end
end
- if input.verbose then
+ if logs.verbose then
for k, v in pairs(combined) do
logs.report("update", k)
for k,v in ipairs(v) do
@@ -232,24 +308,53 @@ function scripts.update.synchronize()
end
end
for destination, archive in pairs(combined) do
- local archives, command = table.concat(archive," "), ""
- local normalflags, deleteflags = states.get("rsync.flags.normal"), states.get("rsync.flags.delete")
- if true then -- environment.argument("keep") or destination:find("%.$") then
- command = string.format("%s %s %s'%s' '%s'", bin, normalflags, url, archives, destination)
- else
- command = string.format("%s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, url, archives, destination)
+ local archives, command = concat(archive," "), ""
+ -- local normalflags, deleteflags = states.get("rsync.flags.normal"), states.get("rsync.flags.delete")
+ -- if environment.argument("keep") or destination:find("%.$") then
+ -- command = format("%s %s %s'%s' '%s'", bin, normalflags, url, archives, destination)
+ -- else
+ -- command = format("%s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, url, archives, destination)
+ -- end
+ local normalflags, deleteflags = states.get("rsync.flags.normal"), ""
+ if (destination:find("texmf$") or destination:find("texmf%-context$")) and (not environment.argument("keep")) then
+ deleteflags = states.get("rsync.flags.delete")
end
- logs.report("mtx update", string.format("running command: %s",command))
+ command = format("%s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, url, archives, destination)
+ logs.report("mtx update", format("running command: %s",command))
if not fetched[command] then
scripts.update.run(command)
fetched[command] = command
end
end
+
+ local function update_script(script, platform)
+ local bin = bin:gsub("\\","/")
+ local texroot = texroot:gsub("\\","/")
+ platform = scripts.update.platforms[platform]
+ if platform then
+ local command
+ if platform == 'mswin' then
+ bin = bin:gsub("([a-zA-Z]):/", "/cygdrive/%1/")
+ texroot = texroot:gsub("([a-zA-Z]):/", "/cygdrive/%1/")
+ command = string.format("%s -t %s/texmf-context/scripts/context/lua/%s.lua %s/texmf-mswin/bin/", bin, texroot, script, texroot)
+ else
+ command = string.format("%s -tgo --chmod=a+x %s/texmf-context/scripts/context/lua/%s.lua %s/texmf-%s/bin/%s", bin, texroot, script, texroot, platform, script)
+ end
+ logs.report("mtx update", format("updating %s for %s: %s", script, platform, command))
+ scripts.update.run(command)
+ end
+ end
+
+ for platform, _ in pairs(platforms) do
+ update_script('luatools',platform)
+ update_script('mtxrun',platform)
+ end
+
else
- logs.report("mtx update", string.format("no valid texroot: %s",texroot))
+ logs.report("mtx update", format("no valid texroot: %s",texroot))
end
if not force then
- logs.report("update", "use --force to really update")
+ logs.report("update", "use --force to really update files")
end
logs.report("update","done")
end
@@ -262,32 +367,59 @@ function table.fromhash(t)
return h
end
-
+-- make the ConTeXt formats
function scripts.update.make()
+
logs.report("make","start")
+
local force = environment.argument("force")
local texroot = scripts.update.fullpath(states.get("paths.root"))
- local engines = states.get('engines')
+ local engines= states.get('engines')
local platforms = states.get('platforms')
local formats = states.get('formats')
- input.load_tree(texroot)
+
+ resolvers.load_tree(texroot)
+ -- update filename database for pdftex/xetex
scripts.update.run("mktexlsr")
+ -- update filename database for luatex
scripts.update.run("luatools --generate")
- local formatlist = table.concat(table.fromhash(formats), " ")
+ local askedformats = formats
+ local texformats = table.tohash(scripts.update.texformats)
+ local mpformats = table.tohash(scripts.update.mpformats)
+ for k,v in pairs(texformats) do
+ if not askedformats[k] then
+ texformats[k] = nil
+ end
+ end
+ for k,v in pairs(mpformats) do
+ if not askedformats[k] then
+ mpformats[k] = nil
+ end
+ end
+ local formatlist = concat(table.fromhash(texformats), " ")
if formatlist ~= "" then
for engine in pairs(engines) do
- -- todo: just handle make here or in mtxrun --script context --make
---~ os.execute("set")
- scripts.update.run(string.format("texexec --make --all --fast --%s %s",engine,formatlist))
+ if engine == "luatex" then
+ scripts.update.run(format("context --make")) -- maybe also formatlist
+ else
+ -- todo: just handle make here or in mtxrun --script context --make
+ scripts.update.run(format("texexec --make --all --fast --%s %s",engine,formatlist))
+ end
end
end
+ local formatlist = concat(table.fromhash(mpformats), " ")
+ if formatlist ~= "" then
+ scripts.update.run(format("texexec --make --all --fast %s",formatlist))
+ end
if not force then
- logs.report("make", "use --force to really make")
+ logs.report("make", "use --force to really make formats")
end
+ scripts.update.run("mktexlsr")
+ scripts.update.run("luatools --generate")
logs.report("make","done")
end
-banner = banner .. " | download tools "
+logs.extendbanner("Download Tools 0.20",true)
messages.help = [[
--platform=string platform (windows, linux, linux-64, osx-intel, osx-ppc, linux-ppc)
@@ -296,8 +428,9 @@ messages.help = [[
--repository=string specify version (current, experimental)
--context=string specify version (current, latest, yyyy.mm.dd)
--rsync=string rsync binary (rsync)
---texroot installation directory (not guessed for the moment)
---engine tex engine (luatex, pdftex, xetex)
+--texroot=string installation directory (not guessed for the moment)
+--engine=string tex engine (luatex, pdftex, xetex)
+--extras=string extra modules (can be list or 'all')
--force instead of a dryrun, do the real thing
--update update minimal tree
--make also make formats and generate file databases
@@ -305,8 +438,6 @@ messages.help = [[
--state update tree using saved state
]]
-input.verbose = true
-
scripts.savestate = true
if scripts.savestate then
@@ -315,7 +446,7 @@ if scripts.savestate then
-- tag, value, default, persistent
- input.starttiming(states)
+ statistics.starttiming(states)
states.set("info.version",0.1) -- ok
states.set("info.count",(states.get("info.count") or 0) + 1,1,false) -- ok
@@ -333,11 +464,11 @@ if scripts.savestate then
states.set("context.version", environment.argument("context"), "current", true) -- ok
local valid = table.tohash(scripts.update.repositories)
- for r in string.gmatch(environment.argument("repository") or "current","([^, ]+)") do
+ for r in gmatch(environment.argument("repository") or "current","([^, ]+)") do
if valid[r] then states.set("repositories." .. r, true) end
end
local valid = scripts.update.engines
- for r in string.gmatch(environment.argument("engine") or "all","([^, ]+)") do
+ for r in gmatch(environment.argument("engine") or "all","([^, ]+)") do
if r == "all" then
for k, v in pairs(valid) do
if k ~= "all" then
@@ -349,12 +480,16 @@ if scripts.savestate then
end
end
local valid = scripts.update.platforms
- for r in string.gmatch(environment.argument("platform") or os.currentplatform(),"([^, ]+)") do
+ for r in gmatch(environment.argument("platform") or os.currentplatform(),"([^, ]+)") do
if valid[r] then states.set("platforms." .. r, true) end
end
- local valid = table.tohash(scripts.update.allformats)
- for r in string.gmatch(environment.argument("formats") or "","([^, ]+)") do
+ local valid = table.tohash(scripts.update.texformats)
+ for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
+ if valid[r] then states.set("formats." .. r, true) end
+ end
+ local valid = table.tohash(scripts.update.mpformats)
+ for r in gmatch(environment.argument("formats") or "","([^, ]+)") do
if valid[r] then states.set("formats." .. r, true) end
end
@@ -362,7 +497,9 @@ if scripts.savestate then
states.set("formats.cont-nl", true)
states.set("formats.metafun", true)
- -- modules
+ for r in gmatch(environment.argument("extras") or "","([^, ]+)") do
+ states.set("extras." .. r, true)
+ end
logs.report("state","loaded")
@@ -382,12 +519,12 @@ if environment.argument("update") then
elseif environment.argument("make") then
scripts.update.make()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
if scripts.savestate then
- input.stoptiming(states)
- states.set("info.runtime",tonumber(input.elapsedtime(states)))
+ statistics.stoptiming(states)
+ states.set("info.runtime",tonumber(statistics.elapsedtime(states)))
if environment.argument("force") then
states.save()
logs.report("state","saved")
diff --git a/scripts/context/lua/mtx-watch.lua b/scripts/context/lua/mtx-watch.lua
index b7b6fb77b..2e4dcf6ef 100644
--- a/scripts/context/lua/mtx-watch.lua
+++ b/scripts/context/lua/mtx-watch.lua
@@ -58,6 +58,20 @@ do
end
end
end
+ local function toset(t)
+ if type(t) == "table" then
+ return table.concat(t,",")
+ else
+ return t
+ end
+ end
+ local function noset(t)
+ if type(t) == "table" then
+ return t[1]
+ else
+ return t
+ end
+ end
local function process()
local done = false
for _, path in ipairs(environment.files) do
@@ -77,8 +91,8 @@ do
local command = joblog.command
if command then
local replacements = {
- inputpath = (joblog.paths and joblog.paths.input ) or ".",
- outputpath = (joblog.paths and joblog.paths.output) or ".",
+ inputpath = toset((joblog.paths and joblog.paths.input ) or "."),
+ outputpath = noset((joblog.paths and joblog.paths.output) or "."),
filename = joblog.filename or "",
}
command = command:gsub("%%(.-)%%", replacements)
@@ -225,7 +239,7 @@ function scripts.watch.show_logs(path) -- removes duplicates
end
end
-banner = banner .. " | watchdog"
+logs.extendbanner("Watchdog 1.00",true)
messages.help = [[
--logpath optional path for log files
@@ -236,8 +250,6 @@ messages.help = [[
--showlog show log data
]]
-input.verbose = true
-
if environment.argument("watch") then
scripts.watch.watch()
elseif environment.argument("collect") then
@@ -245,5 +257,5 @@ elseif environment.argument("collect") then
elseif environment.argument("showlog") then
scripts.watch.show_logs()
else
- input.help(banner,messages.help)
+ logs.help(messages.help)
end
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua
index 6c68ec51a..0af429bf1 100644
--- a/scripts/context/lua/mtxrun.lua
+++ b/scripts/context/lua/mtxrun.lua
@@ -8,6 +8,7 @@ if not modules then modules = { } end modules ['mtxrun'] = {
license = "see context related readme files"
}
+
-- one can make a stub:
--
-- #!/bin/sh
@@ -26,7 +27,7 @@ if not modules then modules = { } end modules ['mtxrun'] = {
-- one. Interesting is that using a scripting language instead of c does
-- not have a speed penalty. Actually the lua variant is more efficient,
-- especially when multiple calls to kpsewhich are involved. The lua
--- library also gives way more ocntrol.
+-- library also gives way more control.
-- to be done / considered
--
@@ -37,144 +38,42 @@ if not modules then modules = { } end modules ['mtxrun'] = {
-- remember for subruns: _CTX_K_S_#{original}_
-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
-banner = "version 1.1.2 - 2007+ - PRAGMA ADE / CONTEXT" -- not local
texlua = true
-- begin library merge
--- filename : l-string.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-if not versions then versions = { } end versions['l-string'] = 1.001
---~ function string.split(str, pat) -- taken from the lua wiki
---~ local t = {n = 0} -- so this table has a length field, traverse with ipairs then!
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = string.find(str, fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ table.insert(t,cap)
---~ end
---~ last_end = e+1
---~ s, e, cap = string.find(str, fpat, last_end)
---~ end
---~ if last_end<=string.len(str) then
---~ table.insert(t,(string.sub(str,last_end)))
---~ end
---~ return t
---~ end
---~ function string:split(pat) -- taken from the lua wiki but adapted
---~ local t = { } -- self and colon usage (faster)
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = self:find(fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ t[#t+1] = cap
---~ end
---~ last_end = e+1
---~ s, e, cap = self:find(fpat, last_end)
---~ end
---~ if last_end <= #self then
---~ t[#t+1] = self:sub(last_end)
---~ end
---~ return t
---~ end
+do -- create closure to overcome 200 locals limit
---~ a piece of brilliant code by Rici Lake (posted on lua list) -- only names changed
---~
---~ function string:splitter(pat)
---~ local st, g = 1, self:gmatch("()"..pat.."()")
---~ local function splitter(self)
---~ if st then
---~ local s, f = g()
---~ local rv = self:sub(st, (s or 0)-1)
---~ st = f
---~ return rv
---~ end
---~ end
---~ return splitter, self
---~ end
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-function string:splitter(pat)
- -- by Rici Lake (posted on lua list) -- only names changed
- -- p 79 ref man: () returns position of match
- local st, g = 1, self:gmatch("()("..pat..")")
- local function strgetter(self, segs, seps, sep, cap1, ...)
- st = sep and seps + #sep
- return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
- end
- local function strsplitter(self)
- if st then return strgetter(self, st, g()) end
- end
- return strsplitter, self
-end
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
-function string:split(separator)
- local t = {}
- for k in self:splitter(separator) do t[#t+1] = k end
- return t
-end
+if not string.split then
--- faster than a string:split:
+ -- this will be overloaded by a faster lpeg variant
-function string:splitchr(chr)
- if #self > 0 then
- local t = { }
- for s in (self..chr):gmatch("(.-)"..chr) do
- t[#t+1] = s
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
end
- return t
- else
- return { }
end
-end
-function string.piecewise(str, pat, fnc) -- variant of split
- for k in string.splitter(str,pat) do fnc(k) end
end
---~ function string.piecewise(str, pat, fnc) -- variant of split
---~ for k in str:splitter(pat) do fnc(k) end
---~ end
-
---~ do if lpeg then
-
---~ -- this alternative is 30% faster esp when we cache them
---~ -- problem: no expressions
-
---~ splitters = { }
-
---~ function string:split(separator)
---~ if #self > 0 then
---~ local split = splitters[separator]
---~ if not split then
---~ -- based on code by Roberto
---~ local p = lpeg.P(separator)
---~ local c = lpeg.C((1-p)^0)
---~ split = lpeg.Ct(c*(p*c)^0)
---~ splitters[separator] = split
---~ end
---~ return split:match(self)
---~ else
---~ return { }
---~ end
---~ end
-
---~ string.splitchr = string.split
-
---~ function string:piecewise(separator,fnc)
---~ for _,v in pairs(self:split(separator)) do
---~ fnc(v)
---~ end
---~ end
-
---~ end end
-
local chr_to_esc = {
["%"] = "%%",
["."] = "%.",
@@ -188,20 +87,20 @@ local chr_to_esc = {
string.chr_to_esc = chr_to_esc
function string:esc() -- variant 2
- return (self:gsub("(.)",chr_to_esc))
+ return (gsub(self,"(.)",chr_to_esc))
end
function string:unquote()
- return (self:gsub("^([\"\'])(.*)%1$","%2"))
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
end
-function string:quote()
+function string:quote() -- we could use format("%q")
return '"' .. self:unquote() .. '"'
end
function string:count(pattern) -- variant 3
local n = 0
- for _ in self:gmatch(pattern) do
+ for _ in gmatch(self,pattern) do
n = n + 1
end
return n
@@ -210,29 +109,25 @@ end
function string:limit(n,sentinel)
if #self > n then
sentinel = sentinel or " ..."
- return self:sub(1,(n-#sentinel)) .. sentinel
+ return sub(self,1,(n-#sentinel)) .. sentinel
else
return self
end
end
function string:strip()
- return (self:gsub("^%s*(.-)%s*$", "%1"))
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
end
---~ function string.strip(str) -- slightly different
---~ return (string.gsub(string.gsub(str,"^%s*(.-)%s*$","%1"),"%s+"," "))
---~ end
-
function string:is_empty()
- return not self:find("%S")
+ return not find(find,"%S")
end
function string:enhance(pattern,action)
local ok, n = true, 0
while ok do
ok = false
- self = self:gsub(pattern, function(...)
+ self = gsub(self,pattern, function(...)
ok, n = true, n + 1
return action(...)
end)
@@ -240,59 +135,19 @@ function string:enhance(pattern,action)
return self, n
end
---~ function string:enhance(pattern,action)
---~ local ok, n = 0, 0
---~ repeat
---~ self, ok = self:gsub(pattern, function(...)
---~ n = n + 1
---~ return action(...)
---~ end)
---~ until ok == 0
---~ return self, n
---~ end
-
---~ function string:to_hex()
---~ if self then
---~ return (self:gsub("(.)",function(c)
---~ return string.format("%02X",c:byte())
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
---~ function string:from_hex()
---~ if self then
---~ return (self:gsub("(..)",function(c)
---~ return string.char(tonumber(c,16))
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
-string.chr_to_hex = { }
-string.hex_to_chr = { }
+local chr_to_hex, hex_to_chr = { }, { }
for i=0,255 do
- local c, h = string.char(i), string.format("%02X",i)
- string.chr_to_hex[c], string.hex_to_chr[h] = h, c
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
end
---~ function string:to_hex()
---~ if self then return (self:gsub("(.)",string.chr_to_hex)) else return "" end
---~ end
-
---~ function string:from_hex()
---~ if self then return (self:gsub("(..)",string.hex_to_chr)) else return "" end
---~ end
-
function string:to_hex()
- return ((self or ""):gsub("(.)",string.chr_to_hex))
+ return (gsub(self or "","(.)",chr_to_hex))
end
function string:from_hex()
- return ((self or ""):gsub("(..)",string.hex_to_chr))
+ return (gsub(self or "","(..)",hex_to_chr))
end
if not string.characters then
@@ -306,7 +161,7 @@ if not string.characters then
end
local function nextbyte(str, index)
index = index + 1
- return (index <= #str) and index or nil, string.byte(str:sub(index,index))
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
end
function string:bytes()
return nextbyte, self, 0
@@ -314,9 +169,7 @@ if not string.characters then
end
---~ function string:padd(n,chr)
---~ return self .. self.rep(chr or " ",n-#self)
---~ end
+-- we can use format for this (neg n)
function string:rpadd(n,chr)
local m = n-#self
@@ -338,8 +191,8 @@ end
string.padd = string.rpadd
-function is_number(str)
- return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
end
--~ print(is_number("1"))
@@ -351,9 +204,9 @@ end
--~ print(is_number("+.1"))
function string:split_settings() -- no {} handling, see l-aux for lpeg variant
- if self:find("=") then
+ if find(self,"=") then
local t = { }
- for k,v in self:gmatch("(%a+)=([^%,]*)") do
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
t[k] = v
end
return t
@@ -375,24 +228,67 @@ local patterns_escapes = {
}
function string:pattesc()
- return (self:gsub(".",patterns_escapes))
+ return (gsub(self,".",patterns_escapes))
end
function string:tohash()
local t = { }
- for s in self:gmatch("([^, ]+)") do -- lpeg
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
t[s] = true
end
return t
end
+local pattern = lpeg.Ct(lpeg.C(1)^0)
--- filename : l-lpeg.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+function string:totable()
+ return pattern:match(self)
+end
-if not versions then versions = { } end versions['l-lpeg'] = 1.001
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
--~ l-lpeg.lua :
@@ -416,36 +312,40 @@ if not versions then versions = { } end versions['l-lpeg'] = 1.001
local hash = { }
function lpeg.anywhere(pattern) --slightly adapted from website
- return lpeg.P { lpeg.P(pattern) + 1 * lpeg.V(1) }
+ return P { P(pattern) + 1 * lpeg.V(1) }
end
function lpeg.startswith(pattern) --slightly adapted
- return lpeg.P(pattern)
+ return P(pattern)
end
---~ g = lpeg.splitter(" ",function(s) ... end) -- gmatch:lpeg = 3:2
-
function lpeg.splitter(pattern, action)
- return (((1-lpeg.P(pattern))^1)/action+1)^0
+ return (((1-P(pattern))^1)/action+1)^0
end
-local crlf = lpeg.P("\r\n")
-local cr = lpeg.P("\r")
-local lf = lpeg.P("\n")
-local space = lpeg.S(" \t\f\v")
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
local newline = crlf + cr + lf
local spacing = space^0 * newline
-local empty = spacing * lpeg.Cc("")
-local nonempty = lpeg.Cs((1-spacing)^1) * spacing^-1
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
local content = (empty + nonempty)^1
-local capture = lpeg.Ct(content^0)
+local capture = Ct(content^0)
function string:splitlines()
return capture:match(self)
end
+lpeg.linebyline = content -- better make a sublibrary
+
--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
@@ -453,16 +353,16 @@ end
local splitters_s, splitters_m = { }, { }
-function lpeg.splitat(separator,single)
+local function splitat(separator,single)
local splitter = (single and splitters_s[separator]) or splitters_m[separator]
if not splitter then
- separator = lpeg.P(separator)
+ separator = P(separator)
if single then
- local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
- splitter = other * (separator * lpeg.C(any^0) + "")
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
splitters_s[separator] = splitter
else
- local other = lpeg.C((1 - separator)^0)
+ local other = C((1 - separator)^0)
splitter = other * (separator * other)^0
splitters_m[separator] = splitter
end
@@ -470,26 +370,43 @@ function lpeg.splitat(separator,single)
return splitter
end
+lpeg.splitat = splitat
--- filename : l-table.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
-if not versions then versions = { } end versions['l-table'] = 1.001
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
table.join = table.concat
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
-local format = string.format
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
local getmetatable, setmetatable = getmetatable, setmetatable
-local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring
+local type, next, tostring, ipairs = type, next, tostring, ipairs
function table.strip(tab)
local lst = { }
for i=1,#tab do
- local s = tab[i]:gsub("^%s*(.-)%s*$","%1")
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
if s == "" then
-- skip this one
else
@@ -501,7 +418,7 @@ end
local function sortedkeys(tab)
local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
if kind == 3 then
-- no further check
@@ -528,7 +445,7 @@ end
local function sortedhashkeys(tab) -- fast one
local srt = { }
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
end
sort(srt)
@@ -538,14 +455,25 @@ end
table.sortedkeys = sortedkeys
table.sortedhashkeys = sortedhashkeys
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
function table.append(t, list)
- for _,v in pairs(list) do
+ for _,v in next, list do
insert(t,v)
end
end
function table.prepend(t, list)
- for k,v in pairs(list) do
+ for k,v in next, list do
insert(t,k,v)
end
end
@@ -554,7 +482,7 @@ function table.merge(t, ...) -- first one is target
t = t or {}
local lst = {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
t[k] = v
end
end
@@ -564,7 +492,7 @@ end
function table.merged(...)
local tmp, lst = { }, {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
tmp[k] = v
end
end
@@ -596,13 +524,14 @@ end
local function fastcopy(old) -- fast one
if old then
local new = { }
- for k,v in pairs(old) do
+ for k,v in next, old do
if type(v) == "table" then
new[k] = fastcopy(v) -- was just table.copy
else
new[k] = v
end
end
+ -- optional second arg
local mt = getmetatable(old)
if mt then
setmetatable(new,mt)
@@ -619,7 +548,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
if not tables[t] then
tables[t] = tcopy
end
- for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+ for i,v in next, t do -- brrr, what happens with sparse indexed
if type(i) == "table" then
if tables[i] then
i = tables[i]
@@ -652,7 +581,7 @@ function table.sub(t,i,j)
end
function table.replace(a,b)
- for k,v in pairs(b) do
+ for k,v in next, b do
a[k] = v
end
end
@@ -674,16 +603,18 @@ end
function table.tohash(t,value)
local h = { }
- if value == nil then value = true end
- for _, v in pairs(t) do -- no ipairs here
- h[v] = value
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
end
return h
end
function table.fromhash(t)
local h = { }
- for k, v in pairs(t) do -- no ipairs here
+ for k, v in next, t do -- no ipairs here
if v then h[#h+1] = k end
end
return h
@@ -707,24 +638,10 @@ local reserved = table.tohash { -- intercept a language flaw, no reserved words
'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
}
-local function key(k)
- if type(k) == "number" then -- or k:find("^%d+$") then
- if hexify then
- return ("[0x%04X]"):format(k)
- else
- return "["..k.."]"
- end
- elseif noquotes and not reserved[k] and k:find("^%a[%a%d%_]*$") then
- return k
- else
- return '["'..k..'"]'
- end
-end
-
local function simple_table(t)
if #t > 0 then
local n = 0
- for _,v in pairs(t) do
+ for _,v in next, t do
n = n + 1
end
if n == #t then
@@ -734,14 +651,14 @@ local function simple_table(t)
local tv = type(v)
if tv == "number" then
if hexify then
- tt[#tt+1] = ("0x%04X"):format(v)
+ tt[#tt+1] = format("0x%04X",v)
else
- tt[#tt+1] = tostring(v)
+ tt[#tt+1] = tostring(v) -- tostring not needed
end
elseif tv == "boolean" then
tt[#tt+1] = tostring(v)
elseif tv == "string" then
- tt[#tt+1] = ("%q"):format(v)
+ tt[#tt+1] = format("%q",v)
else
tt = nil
break
@@ -753,51 +670,72 @@ local function simple_table(t)
return nil
end
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
local function do_serialize(root,name,depth,level,indexed)
if level > 0 then
depth = depth .. " "
if indexed then
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
elseif name then
- handle(("%s%s={"):format(depth,key(name)))
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
else
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
end
end
if root and next(root) then
local first, last = nil, 0 -- #root cannot be trusted here
if compact then
- for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil)
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
if not first then first = k end
last = last + 1
end
end
- --~ for _,k in pairs(sortedkeys(root)) do -- 1% faster:
local sk = sortedkeys(root)
for i=1,#sk do
local k = sk[i]
local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
local t = type(v)
if compact and first and type(k) == "number" and k >= first and k <= last then
if t == "number" then
if hexify then
- handle(("%s 0x%04X,"):format(depth,v))
+ handle(format("%s 0x%04X,",depth,v))
else
- handle(("%s %s,"):format(depth,v))
+ handle(format("%s %s,",depth,v))
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s,"):format(depth,v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
else
- handle(("%s %q,"):format(depth,v))
+ handle(format("%s %q,",depth,v))
end
elseif t == "table" then
if not next(v) then
- handle(("%s {},"):format(depth))
- elseif inline then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
local st = simple_table(v)
if st then
- handle(("%s { %s },"):format(depth,concat(st,", ")))
+ handle(format("%s { %s },",depth,concat(st,", ")))
else
do_serialize(v,k,depth,level+1,true)
end
@@ -805,39 +743,102 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1,true)
end
elseif t == "boolean" then
- handle(("%s %s,"):format(depth,tostring(v)))
+ handle(format("%s %s,",depth,tostring(v)))
elseif t == "function" then
if functions then
- handle(('%s loadstring(%q),'):format(depth,v:dump()))
+ handle(format('%s loadstring(%q),',depth,dump(v)))
else
- handle(('%s "function",'):format(depth))
+ handle(format('%s "function",',depth))
end
else
- handle(("%s %q,"):format(depth,tostring(v)))
+ handle(format("%s %q,",depth,tostring(v)))
end
elseif k == "__p__" then -- parent
if false then
- handle(("%s __p__=nil,"):format(depth))
+ handle(format("%s __p__=nil,",depth))
end
elseif t == "number" then
- if hexify then
- handle(("%s %s=0x%04X,"):format(depth,key(k),v))
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%q,"):format(depth,key(k),v))
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
end
elseif t == "table" then
if not next(v) then
- handle(("%s %s={},"):format(depth,key(k)))
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
elseif inline then
local st = simple_table(v)
if st then
- handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", ")))
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
else
do_serialize(v,k,depth,level+1)
end
@@ -845,24 +846,58 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1)
end
elseif t == "boolean" then
- handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
elseif t == "function" then
if functions then
- handle(('%s %s=loadstring(%q),'):format(depth,key(k),v:dump()))
- else
- handle(('%s %s="function",'):format(depth,key(k)))
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
end
else
- handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
- -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
end
+ --~ end
end
end
if level > 0 then
- handle(("%s},"):format(depth))
+ handle(format("%s},",depth))
end
end
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
noquotes = _noquotes
hexify = _hexify
@@ -880,7 +915,7 @@ local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
end
elseif tname == "number" then
if hexify then
- handle(("[0x%04X]={"):format(name))
+ handle(format("[0x%04X]={",name))
else
handle("[" .. name .. "]={")
end
@@ -1031,14 +1066,18 @@ function table.insert_after_value(t,value,str)
end
end
-function table.are_equal(a,b,n,m)
+local function are_equal(a,b,n,m) -- indexed
if #a == #b then
n = n or 1
m = m or #a
for i=n,m do
local ai, bi = a[i], b[i]
- if (ai==bi) or (type(ai)=="table" and type(bi)=="table" and table.are_equal(ai,bi)) then
- -- continue
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
else
return false
end
@@ -1049,9 +1088,30 @@ function table.are_equal(a,b,n,m)
end
end
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
function table.compact(t)
if t then
- for k,v in pairs(t) do
+ for k,v in next, t do
if not next(v) then
t[k] = nil
end
@@ -1080,7 +1140,7 @@ end
function table.swapped(t)
local s = { }
- for k, v in pairs(t) do
+ for k, v in next, t do
s[v] = k
end
return s
@@ -1102,14 +1162,14 @@ end
function table.hexed(t,seperator)
local tt = { }
- for i=1,#t do tt[i] = ("0x%04X"):format(t[i]) end
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
return concat(tt,seperator or " ")
end
function table.reverse_hash(h)
local r = { }
- for k,v in pairs(h) do
- r[v] = (k:gsub(" ","")):lower()
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
end
return r
end
@@ -1124,14 +1184,36 @@ 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
--- filename : l-io.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+--~ function table.keys_as_string(t)
+--~ local k = { }
+--~ for k,_ in next, t do
+--~ k[#k+1] = k
+--~ end
+--~ return concat(k,"")
+--~ end
-if not versions then versions = { } end versions['l-io'] = 1.001
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
if string.find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator = "\\", ";"
@@ -1139,8 +1221,8 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-function io.loaddata(filename)
- local f = io.open(filename,'rb')
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
if f then
local data = f:read('*all')
-- garbagecollector.check(data)
@@ -1198,146 +1280,83 @@ function io.noflines(f)
return n
end
-do
-
- local sb = string.byte
-
- local nextchar = {
- [ 4] = function(f)
- return f:read(1,1,1,1)
- end,
- [ 2] = function(f)
- return f:read(1,1)
- end,
- [ 1] = function(f)
- return f:read(1)
- end,
- [-2] = function(f)
- local a, b = f:read(1,1)
- return b, a
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- return d, c, b, a
- end
- }
-
- function io.characters(f,n)
- if f then
- return nextchar[n or 1], f
- else
- return nil, nil
- end
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
end
+}
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
end
-do
-
- local sb = string.byte
-
---~ local nextbyte = {
---~ [4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(a), sb(b), sb(c), sb(d)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end,
---~ [2] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(a), sb(b)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [1] = function (f)
---~ local a = f:read(1)
---~ if a then
---~ return sb(a)
---~ else
---~ return nil
---~ end
---~ end,
---~ [-2] = function (f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(b), sb(a)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [-4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(d), sb(c), sb(b), sb(a)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end
---~ }
-
- local nextbyte = {
- [4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(a), sb(b), sb(c), sb(d)
- else
- return nil, nil, nil, nil
- end
- end,
- [2] = function(f)
- local a, b = f:read(1,1)
- if b then
- return sb(a), sb(b)
- else
- return nil, nil
- end
- end,
- [1] = function (f)
- local a = f:read(1)
- if a then
- return sb(a)
- else
- return nil
- end
- end,
- [-2] = function (f)
- local a, b = f:read(1,1)
- if b then
- return sb(b), sb(a)
- else
- return nil, nil
- end
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(d), sb(c), sb(b), sb(a)
- else
- return nil, nil, nil, nil
- end
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
end
- }
-
- function io.bytes(f,n)
- if f then
- return nextbyte[n or 1], f
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
else
return nil, nil
end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
end
+}
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
end
function io.ask(question,default,options)
@@ -1373,35 +1392,21 @@ function io.ask(question,default,options)
end
--- filename : l-md5.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['l-md5'] = 1.001
-
-if md5 then do
-
- local function convert(str,fmt)
- return (string.gsub(md5.sum(str),".",function(chr) return string.format(fmt,string.byte(chr)) end))
- end
-
- if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
- if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
- if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
-
-end end
+end -- of closure
+do -- create closure to overcome 200 locals limit
--- filename : l-number.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-number'] = 1.001
+local format = string.format
-if not number then number = { } end
+number = number or { }
-- a,b,c,d,e,f = number.toset(100101)
@@ -1409,8 +1414,6 @@ function number.toset(n)
return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
end
-local format = string.format
-
function number.toevenhex(n)
local s = format("%X",n)
if #s % 2 == 0 then
@@ -1431,72 +1434,72 @@ end
--
-- of course dedicated "(.)(.)(.)(.)" matches are even faster
-do
- local one = lpeg.C(1-lpeg.S(''))^1
+local one = lpeg.C(1-lpeg.S(''))^1
- function number.toset(n)
- return one:match(tostring(n))
- end
+function number.toset(n)
+ return one:match(tostring(n))
end
--- filename : l-set.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-if not versions then versions = { } end versions['l-set'] = 1.001
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
-if not set then set = { } end
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-do
+set = set or { }
- local nums = { }
- local tabs = { }
- local concat = table.concat
+local nums = { }
+local tabs = { }
+local concat = table.concat
- set.create = table.tohash
+set.create = table.tohash
- function set.tonumber(t)
- if next(t) then
- local s = ""
- -- we could save mem by sorting, but it slows down
- for k, v in pairs(t) do
- if v then
- -- why bother about the leading space
- s = s .. " " .. k
- end
- end
- if not nums[s] then
- tabs[#tabs+1] = t
- nums[s] = #tabs
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
end
- return nums[s]
- else
- return 0
end
- end
-
- function set.totable(n)
- if n == 0 then
- return { }
- else
- return tabs[n] or { }
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
end
+ return nums[s]
+ else
+ return 0
end
+end
- function set.contains(n,s)
- if type(n) == "table" then
- return n[s]
- elseif n == 0 then
- return false
- else
- local t = tabs[n]
- return t and t[s]
- end
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
end
+end
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
end
--~ local c = set.create{'aap','noot','mies'}
@@ -1513,16 +1516,19 @@ end
--- filename : l-os.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
+do -- create closure to overcome 200 locals limit
---~ print(table.serialize(os.uname()))
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-os'] = 1.001
+local find = string.find
function os.resultof(command)
return io.popen(command,"r"):read("*all")
@@ -1535,7 +1541,7 @@ if not os.spawn then os.spawn = os.execute end
--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
if not io.fileseparator then
- if string.find(os.getenv("PATH"),";") then
+ if find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
else
io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
@@ -1573,11 +1579,10 @@ end
os.gettimeofday = os.gettimeofday or os.clock
-do
- local startuptime = os.gettimeofday()
- function os.runtime()
- return os.gettimeofday() - startuptime
- end
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
end
--~ print(os.gettimeofday()-os.time())
@@ -1586,27 +1591,92 @@ end
--~ print(os.date("%H:%M:%S",os.gettimeofday()))
--~ print(os.date("%H:%M:%S",os.time()))
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
--- filename : l-file.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-if not versions then versions = { } end versions['l-file'] = 1.001
+end -- of closure
-if not file then file = { } end
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
function file.removesuffix(filename)
- return (filename:gsub("%.[%a%d]+$",""))
+ return (gsub(filename,"%.[%a%d]+$",""))
end
-file.stripsuffix = file.removesuffix
-
function file.addsuffix(filename, suffix)
- if not filename:find("%.[%a%d]+$") then
+ if not find(filename,"%.[%a%d]+$") then
return filename .. "." .. suffix
else
return filename
@@ -1614,23 +1684,23 @@ function file.addsuffix(filename, suffix)
end
function file.replacesuffix(filename, suffix)
- return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
end
-function file.dirname(name)
- return name:match("^(.+)[/\\].-$") or ""
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
end
function file.basename(name)
- return name:match("^.+[/\\](.-)$") or name
+ return match(name,"^.+[/\\](.-)$") or name
end
function file.nameonly(name)
- return ((name:match("^.+[/\\](.-)$") or name):gsub("%..*$",""))
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
end
function file.extname(name)
- return name:match("^.+%.([^/\\]-)$") or ""
+ return match(name,"^.+%.([^/\\]-)$") or ""
end
file.suffix = file.extname
@@ -1643,40 +1713,20 @@ file.suffix = file.extname
function file.join(...)
local pth = concat({...},"/")
- pth = pth:gsub("\\","/")
- local a, b = pth:match("^(.*://)(.*)$")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
+ return a .. gsub(b,"//+","/")
end
- a, b = pth:match("^(//)(.*)$")
+ a, b = match(pth,"^(//)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
- end
- return (pth:gsub("//+","/"))
-end
-
-function file.is_writable(name)
- local f = io.open(name, 'w')
- if f then
- f:close()
- return true
- else
- return false
- end
-end
-
-function file.is_readable(name)
- local f = io.open(name,'r')
- if f then
- f:close()
- return true
- else
- return false
+ return a .. gsub(b,"//+","/")
end
+ return (gsub(pth,"//+","/"))
end
function file.iswritable(name)
- local a = lfs.attributes(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
return a and a.permissions:sub(2,2) == "w"
end
@@ -1685,24 +1735,18 @@ function file.isreadable(name)
return a and a.permissions:sub(1,1) == "r"
end
---~ function file.split_path(str)
---~ if str:find(';') then
---~ return str:splitchr(";")
---~ else
---~ return str:splitchr(io.pathseparator)
---~ end
---~ end
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
-- todo: lpeg
function file.split_path(str)
local t = { }
- str = str:gsub("\\", "/")
- str = str:gsub("(%a):([;/])", "%1\001%2")
- for name in str:gmatch("([^;:]+)") do
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
if name ~= "" then
- name = name:gsub("\001",":")
- t[#t+1] = name
+ t[#t+1] = gsub(name,"\001",":")
end
end
return t
@@ -1713,15 +1757,15 @@ function file.join_path(tab)
end
function file.collapse_path(str)
- str = str:gsub("/%./","/")
+ str = gsub(str,"/%./","/")
local n, m = 1, 1
while n > 0 or m > 0 do
- str, n = str:gsub("[^/%.]+/%.%.$","")
- str, m = str:gsub("[^/%.]+/%.%./","")
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
end
- str = str:gsub("([^/])/$","%1")
- str = str:gsub("^%./","")
- str = str:gsub("/%.$","")
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
if str == "" then str = "." end
return str
end
@@ -1734,7 +1778,7 @@ end
--~ print(file.collapse_path("a/b/c/../.."))
function file.robustname(str)
- return (str:gsub("[^%a%d%/%-%.\\]+","-"))
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
end
file.readdata = io.loaddata
@@ -1764,8 +1808,6 @@ end
--~ return pattern:match(name)
--~ end
---~ file.stripsuffix = file.removesuffix
-
--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
--~ function file.basename(name)
@@ -1819,7 +1861,6 @@ end
--~ end
--~ local test = file.extname
---~ local test = file.stripsuffix
--~ local test = file.basename
--~ local test = file.dirname
--~ local test = file.addsuffix
@@ -1836,206 +1877,307 @@ end
--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+-- also rewrite previous
--- filename : l-dir.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
-if not versions then versions = { } end versions['l-dir'] = 1.001
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-dir = { }
+-- ./name ../name /name c: :// name/name
--- optimizing for no string.find (*) does not save time
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
-if lfs then do
- local attributes = lfs.attributes
- local walkdir = lfs.dir
+end -- of closure
- local function glob_pattern(path,patt,recurse,action)
- local ok, scanner
- if path == "/" then
- ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
- else
- ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEX(data)
end
- if ok and type(scanner) == "function" then
- if not path:find("/$") then path = path .. '/' end
- for name in scanner do
- local full = path .. name
- local mode = attributes(full,'mode')
- if mode == 'file' then
- if full:find(patt) then
- action(full)
- end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- glob_pattern(full,patt,recurse,action)
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local find, gmatch = string.find, string.gmatch
+
+dir = dir or { }
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
end
end
end
+end
- dir.glob_pattern = glob_pattern
+dir.glob_pattern = glob_pattern
- local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
- local pattern = Ct {
- [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
- [2] = C(((1-S("*?/"))^0 * P("/"))^0),
- [3] = C(P(1)^0)
- }
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
- local filter = Cs ( (
- P("**") / ".*" +
- P("*") / "[^/]*" +
- P("?") / "[^/]" +
- P(".") / "%%." +
- P("+") / "%%+" +
- P("-") / "%%-" +
- P(1)
- )^0 )
-
- local function glob(str,t)
- if type(str) == "table" then
- local t = t or { }
- for _, s in ipairs(str) do
- glob(s,t)
- end
- return t
- elseif lfs.isfile(str) then
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
local t = t or { }
- t[#t+1] = str
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
return t
else
- local split = pattern:match(str)
- if split then
- local t = t or { }
- local action = action or function(name) t[#t+1] = name end
- local root, path, base = split[1], split[2], split[3]
- local recurse = base:find("%*%*")
- local start = root .. path
- local result = filter:match(start .. base)
- glob_pattern(start,result,recurse,action)
- return t
- else
- return { }
- end
+ return { }
end
end
+end
- dir.glob = glob
+dir.glob = glob
- --~ list = dir.glob("**/*.tif")
- --~ list = dir.glob("/**/*.tif")
- --~ list = dir.glob("./**/*.tif")
- --~ list = dir.glob("oeps/**/*.tif")
- --~ list = dir.glob("/oeps/**/*.tif")
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
- local function globfiles(path,recurse,func,files) -- func == pattern or function
- if type(func) == "string" then
- local s = func -- alas, we need this indirect way
- func = function(name) return name:find(s) end
- end
- files = files or { }
- for name in walkdir(path) do
- if name:find("^%.") then
- --- skip
- else
- local mode = attributes(name,'mode')
- if mode == "directory" then
- if recurse then
- globfiles(path .. "/" .. name,recurse,func,files)
- end
- elseif mode == "file" then
- if func then
- if func(name) then
- files[#files+1] = path .. "/" .. name
- end
- else
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
files[#files+1] = path .. "/" .. name
end
+ else
+ files[#files+1] = path .. "/" .. name
end
end
end
- return files
end
+ return files
+end
- dir.globfiles = globfiles
+dir.globfiles = globfiles
- -- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
- -- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
- -- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
- -- t = dir.glob("f:/minimal/tex/**/*")
- -- print(dir.ls("f:/minimal/tex/**/*"))
- -- print(dir.ls("*.tex"))
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
- function dir.ls(pattern)
- return table.concat(glob(pattern),"\n")
- end
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
- --~ mkdirs("temp")
- --~ mkdirs("a/b/c")
- --~ mkdirs(".","/a/b/c")
- --~ mkdirs("a","b","c")
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
- local make_indeed = true -- false
+local make_indeed = true -- false
- if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- local first, middle, last
- local drive = false
- first, middle, last = str:match("^(//)(//*)(.*)$")
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
if first then
- -- empty network path == local path
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
else
- first, last = str:match("^(//)/*(.-)$")
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
if first then
- middle, last = str:match("([^/]+)/+(.-)$")
- if middle then
- pth = "//" .. middle
- else
- pth = "//" .. last
- last = ""
- end
+ pth, drive = first .. middle, true
else
- first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
- if first then
- pth, drive = first .. middle, true
- else
- middle, last = str:match("^(/*)(.-)$")
- if not middle then
- last = str
- end
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
end
end
end
- for s in last:gmatch("[^/]+") do
- if pth == "" then
- pth = s
- elseif drive then
- pth, drive = pth .. s, false
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -2049,79 +2191,79 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- local first, nothing, last = str:match("^(//)(//*)(.*)$")
- if first then
- first = lfs.currentdir() .. "/"
- first = first:gsub("\\","/")
- end
- if not first then
- first, last = str:match("^(//)/*(.*)$")
- end
- if not first then
- first, last = str:match("^([a-zA-Z]:)(.*)$")
- if first and not last:find("^/") then
- local d = lfs.currentdir()
- if lfs.chdir(first) then
- first = lfs.currentdir()
- first = first:gsub("\\","/")
- end
- lfs.chdir(d)
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
end
+ lfs.chdir(d)
end
- if not first then
- first, last = lfs.currentdir(), str
- first = first:gsub("\\","/")
- end
- last = last:gsub("//","/")
- last = last:gsub("/%./","/")
- last = last:gsub("^/*","")
- first = first:gsub("/*$","")
- if last == "" then
- return first
- else
- return first .. "/" .. last
- end
end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
- else
+else
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- str = str:gsub("/+","/")
- if str:find("^/") then
- pth = "/"
- for s in str:gmatch("[^/]+") do
- local first = (pth == "/")
- if first then
- pth = pth .. s
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not first and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
- end
- else
- pth = "."
- for s in str:gmatch("[^/]+") do
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
pth = pth .. "/" .. s
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -2131,30 +2273,35 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- if not str:find("^/") then
- str = lfs.currentdir() .. "/" .. str
- end
- str = str:gsub("//","/")
- str = str:gsub("/%./","/")
- return str
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
end
-
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
end
- dir.makedirs = dir.mkdirs
+end
-end end
+dir.makedirs = dir.mkdirs
--- filename : l-boolean.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-boolean'] = 1.001
-if not boolean then boolean = { } end
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
function boolean.tonumber(b)
if b then return 1 else return 0 end
@@ -2201,15 +2348,19 @@ function boolean.falsetrue()
end
--- filename : l-math.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-math'] = 1.001
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-local floor = math.floor
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
if not math.round then
function math.round(x)
@@ -2229,23 +2380,213 @@ if not math.mod then
end
end
+local pipi = 2*math.pi/360
-if not modules then modules = { } end modules ['l-xml'] = {
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
version = 1.001,
- comment = "this module is the basis for the lxml-* ones",
+ comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
--- RJ: key=value ... lpeg.Ca(lpeg.Cc({}) * (pattern-producing-key-and-value / rawset)^0)
+-- hm, quite unreadable
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
--- some code may move to l-xmlext
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (data:gsub(utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for _, lib in ipairs(libs) do
+ for _, pth in ipairs(list) do
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return table.concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-tab'] = {
+ 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"
+}
--[[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
-parent access; a first version used different tricky but was less optimized to we
+parent access; a first version used different trickery but was less optimized to we
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>
@@ -2267,17 +2608,30 @@ optimize the code.</p>
--ldx]]--
xml = xml or { }
-tex = tex or { }
-xml.trace_lpath = false
-xml.trace_print = false
-xml.trace_remap = false
+--~ local xml = xml
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, setmetatable = type, next, setmetatable
+local format, lower, find = string.format, string.lower, string.find
-local format, concat, remove, insert, type, next = string.format, table.concat, table.remove, table.insert, type, next
+--[[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 pairs, next, type = pairs, next, type
+local trace_remap = false
--- todo: some things per xml file, like namespace remapping
+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
--[[ldx--
<p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -2289,65 +2643,61 @@ much cleaner.</p>
xml.xmlns = xml.xmlns or { }
-do
-
- local check = lpeg.P(false)
- local parse = check
+local check = lpeg.P(false)
+local parse = check
- --[[ldx--
- <p>The next function associates a namespace prefix with an <l n='url'/>. This
- normally happens independent of parsing.</p>
+--[[ldx--
+<p>The next function associates a namespace prefix with an <l n='url'/>. This
+normally happens independent of parsing.</p>
- <typing>
- xml.registerns("mml","mathml")
- </typing>
- --ldx]]--
+<typing>
+xml.registerns("mml","mathml")
+</typing>
+--ldx]]--
- function xml.registerns(namespace, pattern) -- pattern can be an lpeg
- check = check + lpeg.C(lpeg.P(pattern:lower())) / namespace
- parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
- end
+function xml.registerns(namespace, pattern) -- pattern can be an lpeg
+ check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
+ parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+end
- --[[ldx--
- <p>The next function also registers a namespace, but this time we map a
- given namespace prefix onto a registered one, using the given
- <l n='url'/>. This used for attributes like <t>xmlns:m</t>.</p>
+--[[ldx--
+<p>The next function also registers a namespace, but this time we map a
+given namespace prefix onto a registered one, using the given
+<l n='url'/>. This used for attributes like <t>xmlns:m</t>.</p>
- <typing>
- xml.checkns("m","http://www.w3.org/mathml")
- </typing>
- --ldx]]--
+<typing>
+xml.checkns("m","http://www.w3.org/mathml")
+</typing>
+--ldx]]--
- function xml.checkns(namespace,url)
- local ns = parse:match(url:lower())
- if ns and namespace ~= ns then
- xml.xmlns[namespace] = ns
- end
+function xml.checkns(namespace,url)
+ local ns = parse:match(lower(url))
+ if ns and namespace ~= ns then
+ xml.xmlns[namespace] = ns
end
+end
- --[[ldx--
- <p>Next we provide a way to turn an <l n='url'/> into a registered
- namespace. This used for the <t>xmlns</t> attribute.</p>
-
- <typing>
- resolvedns = xml.resolvens("http://www.w3.org/mathml")
- </typing>
-
- This returns <t>mml</t>.
- --ldx]]--
+--[[ldx--
+<p>Next we provide a way to turn an <l n='url'/> into a registered
+namespace. This used for the <t>xmlns</t> attribute.</p>
- function xml.resolvens(url)
- return parse:match(url:lower()) or ""
- end
+<typing>
+resolvedns = xml.resolvens("http://www.w3.org/mathml")
+</typing>
- --[[ldx--
- <p>A namespace in an element can be remapped onto the registered
- one efficiently by using the <t>xml.xmlns</t> table.</p>
- --ldx]]--
+This returns <t>mml</t>.
+--ldx]]--
+function xml.resolvens(url)
+ return parse:match(lower(url)) or ""
end
--[[ldx--
+<p>A namespace in an element can be remapped onto the registered
+one efficiently by using the <t>xml.xmlns</t> table.</p>
+--ldx]]--
+
+--[[ldx--
<p>This version uses <l n='lpeg'/>. We follow the same approach as before, stack and top and
such. This version is about twice as fast which is mostly due to the fact that
we don't have to prepare the stream for cdata, doctype etc etc. This variant is
@@ -2382,247 +2732,253 @@ element.</p>
xml.strip_cm_and_dt = false -- an extra global flag, in case we have many includes
-do
+-- not just one big nested table capture (lpeg overflow)
- -- not just one big nested table capture (lpeg overflow)
+local nsremap, resolvens = xml.xmlns, xml.resolvens
- local nsremap, resolvens = xml.xmlns, xml.resolvens
+local stack, top, dt, at, xmlns, errorstr, entities = {}, {}, {}, {}, {}, nil, {}
- local stack, top, dt, at, xmlns, errorstr, entities = {}, {}, {}, {}, {}, nil, {}
+local mt = { __tostring = xml.text }
- local mt = { __tostring = xml.text }
+function xml.check_error(top,toclose)
+ return ""
+end
- function xml.check_error(top,toclose)
- return ""
- end
+local strip = false
+local cleanup = false
- local strip = false
- local cleanup = false
+function xml.set_text_cleanup(fnc)
+ cleanup = fnc
+end
- function xml.set_text_cleanup(fnc)
- cleanup = fnc
+local function add_attribute(namespace,tag,value)
+ if cleanup and #value > 0 then
+ value = cleanup(value) -- new
+ end
+ if tag == "xmlns" then
+ xmlns[#xmlns+1] = resolvens(value)
+ at[tag] = value
+ elseif namespace == "xmlns" then
+ xml.checkns(tag,value)
+ at["xmlns:" .. tag] = value
+ else
+ at[tag] = value
end
+end
- local function add_attribute(namespace,tag,value)
- if tag == "xmlns" then
- xmlns[#xmlns+1] = resolvens(value)
- at[tag] = value
- elseif namespace == "xmlns" then
- xml.checkns(tag,value)
- at["xmlns:" .. tag] = value
- else
- at[tag] = value
- end
- end
- local function add_begin(spacing, namespace, tag)
- if #spacing > 0 then
- dt[#dt+1] = spacing
- end
- local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
- top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
- setmetatable(top, mt)
- dt = top.dt
- stack[#stack+1] = top
- at = { }
- end
- local function add_end(spacing, namespace, tag)
- if #spacing > 0 then
- dt[#dt+1] = spacing
- end
- local toclose = remove(stack)
- top = stack[#stack]
- if #stack < 1 then
- errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
- elseif toclose.tg ~= tag then -- no namespace check
- errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
- end
- dt = top.dt
- dt[#dt+1] = toclose
- 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)
- else
- dt[#dt+1] = text
- end
+local function add_begin(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
end
- local function add_special(what, spacing, text)
- if #spacing > 0 then
- dt[#dt+1] = spacing
- end
- if strip and (what == "@cm@" or what == "@dt@") then
- -- forget it
- else
- dt[#dt+1] = { special=true, ns="", tg=what, dt={text} }
- end
- end
- local function set_message(txt)
- errorstr = "garbage at the end of the file: " .. txt:gsub("([ \n\r\t]*)","")
- end
-
- local P, S, R, C, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V
-
- local space = S(' \r\n\t')
- local open = P('<')
- local close = P('>')
- local squote = S("'")
- local dquote = S('"')
- local equal = P('=')
- local slash = P('/')
- local colon = P(':')
- local valid = R('az', 'AZ', '09') + S('_-.')
- local name_yes = C(valid^1) * colon * C(valid^1)
- local name_nop = C(P(true)) * C(valid^1)
- local name = name_yes + name_nop
-
- 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 somespace = space^1
- local optionalspace = space^0
-
- local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
- local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
- local attributes = attribute^0
-
- local text = justtext / 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
- local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
- local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
-
- local begincomment = open * P("!--")
- local endcomment = P("--") * close
- local begininstruction = open * P("?")
- local endinstruction = P("?") * close
- local begincdata = open * P("![CDATA[")
- local endcdata = P("]]") * close
-
- local someinstruction = C((1 - endinstruction)^0)
- local somecomment = C((1 - endcomment )^0)
- local somecdata = C((1 - endcdata )^0)
-
- function entity(k,v) entities[k] = v end
-
- local begindoctype = open * P("!DOCTYPE")
- local enddoctype = close
- local beginset = P("[")
- local endset = P("]")
- local doctypename = C((1-somespace)^0)
- local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close
- local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close
- local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace
- local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace
- local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset
- local simpledoctype = (1-close)^1 -- * balanced^0
- local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
-
- local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
- local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end
- local cdata = (spacing * begincdata * somecdata * endcdata ) / function(...) add_special("@cd@",...) end
- local doctype = (spacing * begindoctype * somedoctype * enddoctype ) / function(...) add_special("@dt@",...) end
-
- -- nicer but slower:
- --
- -- local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
- -- local comment = (lpeg.Cc("@cm@") * spacing * begincomment * somecomment * endcomment ) / add_special
- -- 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
-
- -- 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",
- 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,
- }
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ setmetatable(top, mt)
+ dt = top.dt
+ stack[#stack+1] = top
+ at = { }
+end
- -- todo: xml.new + properties like entities and strip and such (store in root)
-
- function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear)
- strip = strip_cm_and_dt or xml.strip_cm_and_dt
- stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
- stack[#stack+1] = top
- top.dt = { }
- dt = top.dt
- if not data or data == "" then
- errorstr = "empty xml file"
- elseif not grammar:match(data) then
- errorstr = "invalid xml file"
- else
- errorstr = ""
- end
- if errorstr and errorstr ~= "" then
- result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
- setmetatable(stack, mt)
- if xml.error_handler then xml.error_handler("load",errorstr) end
- else
- result = stack[1]
- end
- if not no_root then
- result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
- setmetatable(result, mt)
- local rdt = result.dt
- for k=1,#rdt do
- local v = rdt[k]
- if type(v) == "table" and not v.special then -- always table -)
- result.ri = k -- rootindex
- break
- end
- end
- end
- return result
+local function add_end(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local toclose = remove(stack)
+ top = stack[#stack]
+ if #stack < 1 then
+ errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
+ elseif toclose.tg ~= tag then -- no namespace check
+ errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
end
+ dt = top.dt
+ dt[#dt+1] = toclose
+ dt[0] = top
+ if toclose.at.xmlns then
+ remove(xmlns)
+ end
+end
- --[[ldx--
- <p>Packaging data in an xml like table is done with the following
- function. Maybe it will go away (when not used).</p>
- --ldx]]--
+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
- function xml.is_valid(root)
- return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+local function add_text(text)
+ if cleanup and #text > 0 then
+ dt[#dt+1] = cleanup(text)
+ else
+ dt[#dt+1] = text
end
+end
- function xml.package(tag,attributes,data)
- local ns, tg = tag:match("^(.-):?([^:]+)$")
- local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
- setmetatable(t, mt)
- return t
+local function add_special(what, spacing, text)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
end
+ if strip and (what == "@cm@" or what == "@dt@") then
+ -- forget it
+ else
+ dt[#dt+1] = { special=true, ns="", tg=what, dt={text} }
+ end
+end
+
+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 space = S(' \r\n\t')
+local open = P('<')
+local close = P('>')
+local squote = S("'")
+local dquote = S('"')
+local equal = P('=')
+local slash = P('/')
+local colon = P(':')
+local valid = R('az', 'AZ', '09') + S('_-.')
+local name_yes = C(valid^1) * colon * C(valid^1)
+local name_nop = C(P(true)) * C(valid^1)
+local name = name_yes + name_nop
+
+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 somespace = space^1
+local optionalspace = space^0
+
+local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
+local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
+local attributes = attribute^0
+
+local text = justtext / 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
+local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
+local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
+
+local begincomment = open * P("!--")
+local endcomment = P("--") * close
+local begininstruction = open * P("?")
+local endinstruction = P("?") * close
+local begincdata = open * P("![CDATA[")
+local endcdata = P("]]") * close
+
+local someinstruction = C((1 - endinstruction)^0)
+local somecomment = C((1 - endcomment )^0)
+local somecdata = C((1 - endcdata )^0)
+
+local function entity(k,v) entities[k] = v end
+
+local begindoctype = open * P("!DOCTYPE")
+local enddoctype = close
+local beginset = P("[")
+local endset = P("]")
+local doctypename = C((1-somespace)^0)
+local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close
+local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close
+local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace
+local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace
+local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset
+local simpledoctype = (1-close)^1 -- * balanced^0
+local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
+
+local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
+local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end
+local cdata = (spacing * begincdata * somecdata * endcdata ) / function(...) add_special("@cd@",...) end
+local doctype = (spacing * begindoctype * somedoctype * enddoctype ) / function(...) add_special("@dt@",...) end
+
+-- nicer but slower:
+--
+-- local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+-- local comment = (lpeg.Cc("@cm@") * spacing * begincomment * somecomment * endcomment ) / add_special
+-- 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
+
+-- 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",
+ 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,
+}
- function xml.is_valid(root)
- return root and not root.error
+-- todo: xml.new + properties like entities and strip and such (store in root)
+
+function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear)
+ strip = strip_cm_and_dt or xml.strip_cm_and_dt
+ stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
+ stack[#stack+1] = top
+ top.dt = { }
+ dt = top.dt
+ if not data or data == "" then
+ errorstr = "empty xml file"
+ elseif not grammar:match(data) then
+ errorstr = "invalid xml file"
+ else
+ errorstr = ""
end
+ if errorstr and errorstr ~= "" then
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
+ setmetatable(stack, mt)
+ if xml.error_handler then xml.error_handler("load",errorstr) end
+ else
+ result = stack[1]
+ end
+ if not no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
+ setmetatable(result, mt)
+ local rdt = result.dt
+ for k=1,#rdt do
+ local v = rdt[k]
+ if type(v) == "table" and not v.special then -- always table -)
+ result.ri = k -- rootindex
+ break
+ end
+ end
+ end
+ return result
+end
+
+--[[ldx--
+<p>Packaging data in an xml like table is done with the following
+function. Maybe it will go away (when not used).</p>
+--ldx]]--
- xml.error_handler = (logs and logs.report) or (input and input.report) or print
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+end
+
+function xml.package(tag,attributes,data)
+ local ns, tg = tag:match("^(.-):?([^:]+)$")
+ local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
+ setmetatable(t, mt)
+ return t
+end
+function xml.is_valid(root)
+ return root and not root.error
end
+xml.error_handler = (logs and logs.report) or (input and logs.report) or print
+
--[[ldx--
<p>We cannot load an <l n='lpeg'/> from a filehandle so we need to load
the whole file first. The function accepts a string representing
@@ -2666,32 +3022,28 @@ generic table copier. Since we know what we're dealing with we
can speed up things a bit. The second argument is not to be used!</p>
--ldx]]--
-do
-
- function copy(old,tables)
- if old then
- tables = tables or { }
- local new = { }
- if not tables[old] then
- tables[old] = new
- end
- for k,v in pairs(old) do
- new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
- end
- local mt = getmetatable(old)
- if mt then
- setmetatable(new,mt)
- end
- return new
- else
- return { }
+function copy(old,tables)
+ if old then
+ tables = tables or { }
+ local new = { }
+ if not tables[old] then
+ tables[old] = new
end
+ for k,v in pairs(old) do
+ new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
end
-
- xml.copy = copy
-
end
+xml.copy = copy
+
--[[ldx--
<p>In <l n='context'/> serializing the tree or parts of the tree is a major
actitivity which is why the following function is pretty optimized resulting
@@ -2700,207 +3052,204 @@ function for all components is about 15% slower than the concatinating
alternative.</p>
--ldx]]--
-do
-
- -- todo: add <?xml version='1.0' standalone='yes'?> when not present
-
- local fallbackhandle = (tex and tex.sprint) or io.write
-
- 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
- local xc = xml.command
- if xc then
- xc(e,ec)
- return
- end
- end
- end
- handle = handle or fallbackhandle
- local etg = e.tg
- if etg then
+-- todo: add <?xml version='1.0' standalone='yes'?> when not present
+
+local fallbackhandle = (tex and tex.sprint) or io.write
+
+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 edt = e.dt
+ 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
- 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
- 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 pairs(eat) do
- ats[#ats+1] = format('%s=%q',k,attributeconverter(v))
- end
- else
- for k,v in pairs(eat) do
- ats[#ats+1] = format('%s=%q',k,v)
- end
- end
+ end
+ local xc = xml.command
+ if xc then
+ xc(e,ec)
+ return
+ end
+ 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)
+ else
+ -- no need to handle any further
end
- if ern and xml.trace_remap and ern ~= ens then
- ens = ern
+ 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
+ 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
- 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
+ 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(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
- serialize(e,handle,textconverter,attributeconverter,specialconverter,nocommands)
+ handle(e)
end
- end
- -- handle(format("</%s:%s>",ens,etg))
- handle("</" .. ens .. ":" .. etg .. ">")
- 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 .. "/>")
+ serialize(e,handle,textconverter,attributeconverter,specialconverter,nocommands)
end
end
+ -- handle(format("</%s:%s>",ens,etg))
+ handle("</" .. ens .. ":" .. etg .. ">")
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
+ 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
+ end
+ 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
- serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
+ handle(ei)
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 .. "/>")
+ 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
end
- elseif type(e) == "string" then
- if textconverter then
- handle(textconverter(e))
- else
- handle(e)
- end
+ end
+ elseif type(e) == "string" then
+ if textconverter then
+ handle(textconverter(e))
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
+ handle(e)
+ end
+ else
+ for i=1,#e do
+ local ei = e[i]
+ if type(ei) == "string" then
+ if textconverter then
+ handle(textconverter(ei))
else
- serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
+ handle(ei)
end
+ else
+ serialize(ei,handle,textconverter,attributeconverter,specialconverter,nocommands)
end
end
end
+end
- xml.serialize = serialize
+xml.serialize = serialize
- function xml.checkbom(root) -- can be made faster
- if root.ri then
- local dt, found = root.dt, false
- for k,v in ipairs(dt) do
- if type(v) == "table" and v.special and v.tg == "@pi" and v.dt:find("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" )
+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
+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]]--
+--[[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]]--
- function xml.tostring(root) -- 25% overhead due to collecting
- if root then
- if type(root) == 'string' then
- return root
- elseif next(root) then -- next is faster than type (and >0 test)
- local result = { }
- serialize(root,function(s) result[#result+1] = s end)
- return concat(result,"")
- end
+function xml.tostring(root) -- 25% overhead due to collecting
+ if root then
+ if type(root) == 'string' then
+ return root
+ elseif next(root) then -- next is faster than type (and >0 test)
+ local result = { }
+ serialize(root,function(s) result[#result+1] = s end)
+ return concat(result,"")
end
- return ""
end
-
+ return ""
end
--[[ldx--
@@ -3010,355 +3359,394 @@ function xml.assign(dt,k,root)
end
end
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+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 = string.format, string.lower, string.gmatch, string.gsub, 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. Here we overload a previously defined
+function.</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 -- statisctics
-local lpathcached = 0 -- statisctics
-
-do
-
- xml.functions = xml.functions or { }
- xml.expressions = xml.expressions or { }
-
- local functions = xml.functions
- local expressions = xml.expressions
-
- 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",
- [27] = "has attribute",
- [28] = "has value",
- [29] = "fast match",
- [30] = "select",
- [31] = "expression",
- [40] = "processing instruction",
- }
+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
+
+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",
+ [27] = "has attribute",
+ [28] = "has value",
+ [29] = "fast match",
+ [30] = "select",
+ [31] = "expression",
+ [40] = "processing instruction",
+}
- -- a rather dumb lpeg
+-- a rather dumb lpeg
- local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
+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
+-- instead of using functions we just parse a few names which saves a call
+-- later on
- 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_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_lua_function = C(R("az","AZ","--","__")^1 * (P(".") * R("az","AZ","--","__")^1)^1) * P("(") / function(t) -- todo: better . handling
- return t .. "("
+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 lp_function = C(R("az","AZ","--","__")^1) * P("(") / function(t) -- todo: better . handling
- if expressions[t] then
- return "expressions." .. t .. "("
+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)*")"}
+
+-- if we use a dedicated namespace then we don't need to pass rt and k
+
+local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
+ if expressions[t] then
+ if s then
+ return "expressions." .. t .. "(r,k," .. s ..")"
else
- return "expressions.error("
+ return "expressions." .. t .. "(r,k)"
end
+ else
+ return "expressions.error(" .. t .. ")"
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 converter = lpeg.Cs ( (
+ lp_position +
+ lp_index +
+ lp_text + lp_name + -- fast one
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_attribute +
+ lp_lua_function +
+ lp_function +
+1 )^1 )
- -- if we use a dedicated namespace then we don't need to pass rt and k
+-- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
- local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
- if expressions[t] then
- if s then
- return "expressions." .. t .. "(r,k," .. s ..")"
- else
- return "expressions." .. t .. "(r,k)"
- end
- else
- return "expressions.error(" .. t .. ")"
- end
- end
-
- local converter = lpeg.Cs ( (
- lp_position +
- lp_index +
- lp_text + lp_name + -- fast one
- lp_special +
- lp_noequal + lp_doequal +
- lp_attribute +
- lp_lua_function +
- lp_function +
- 1 )^1 )
-
- -- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
-
- local template = [[
- 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)
- str = converter:match(str)
- return str, loadstring(format(template,str))()
- end
-
- local map = { }
-
- 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 = C(P(true)) * C(valid^1)
- 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 is_eq = lbracket * atsign * name * eq * value * rbracket
- local is_ne = lbracket * atsign * name * ne * value * rbracket
- local is_attribute = lbracket * atsign * name * rbracket
- local is_value = lbracket * value * rbracket
- local is_number = lbracket * number * rbracket
-
- local nobracket = 1-(lbracket+rbracket) -- must be improved
- local is_expression = lbracket * C(((C(nobracket^1))/make_expression)) * rbracket
-
- local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
-
- 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 = (period )
- local parent = (period * period ) / function( ) map[#map+1] = { 11 } end
- local subtreeroot = (slash + hat ) / function( ) map[#map+1] = { 12 } end
- local documentroot = (hat * hat ) / function( ) map[#map+1] = { 13 } end
- local any = (star ) / function( ) map[#map+1] = { 14 } end
- local many = (star * star ) / function( ) map[#map+1] = { 15 } end
- local initial = (hat * hat * hat ) / function( ) map[#map+1] = { 16 } end
-
- local match = (is_one ) / function(...) map[#map+1] = { 20, true , ... } end
- local match_one_of = (is_one_of ) / function(...) map[#map+1] = { 21, true , ... } end
- local dont_match = (is_none ) / function(...) map[#map+1] = { 20, false, ... } end
- local dont_match_one_of = (is_none_of ) / function(...) map[#map+1] = { 21, false, ... } end
-
- local match_and_eq = (is_one * is_eq ) / function(...) map[#map+1] = { 22, true , ... } end
- local match_and_ne = (is_one * is_ne ) / function(...) map[#map+1] = { 23, true , ... } end
- local dont_match_and_eq = (is_none * is_eq ) / function(...) map[#map+1] = { 22, false, ... } end
- local dont_match_and_ne = (is_none * is_ne ) / function(...) map[#map+1] = { 23, false, ... } end
-
- local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) map[#map+1] = { 24, true , ... } end
- local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) map[#map+1] = { 25, true , ... } end
- local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) map[#map+1] = { 24, false, ... } end
- local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) map[#map+1] = { 25, false, ... } end
-
- local has_attribute = (is_one * is_attribute) / function(...) map[#map+1] = { 27, true , ... } end
- local has_value = (is_one * is_value ) / function(...) map[#map+1] = { 28, true , ... } end
- local dont_has_attribute = (is_none * is_attribute) / function(...) map[#map+1] = { 27, false, ... } end
- local dont_has_value = (is_none * is_value ) / function(...) map[#map+1] = { 28, false, ... } end
- local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
- local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
-
- local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
- local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
-
- local self_expression = ( is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
- map[#map+1] = { 31, true, "*", "*", ... } end
- local dont_self_expression = (exclam * is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
- map[#map+1] = { 31, false, "*", "*", ... } end
-
- local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
- local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
- local crap = (1-slash)^1
-
- -- a few ugly goodies:
-
- local docroottag = P('^^') / function( ) map[#map+1] = { 12 } end
- local subroottag = P('^') / function( ) map[#map+1] = { 13 } end
- local roottag = P('root::') / function( ) map[#map+1] = { 12 } end
- local parenttag = P('parent::') / function( ) map[#map+1] = { 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 +
- 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 +
- has_attribute + has_value +
- dont_match_one_of + match_one_of +
- dont_match + match +
- many + any +
- crap + empty
- )
+local template = [[
+ 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 grammar = P { "startup",
- startup = (initial + documentroot + subtreeroot + roottag + docroottag + subroottag)^0 * V("followup"),
- followup = ((slash + parenttag + childtag + selftag)^0 * selector)^1,
- }
+local function make_expression(str)
+ str = converter:match(str)
+ return str, loadstring(format(template,str))()
+end
+
+local map = { }
+
+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 is_eq = lbracket * atsign * name * eq * value * rbracket
+local is_ne = lbracket * atsign * name * ne * value * rbracket
+local is_attribute = lbracket * atsign * name * rbracket
+local is_value = lbracket * value * rbracket
+local is_number = lbracket * number * rbracket
+
+local nobracket = 1-(lbracket+rbracket) -- must be improved
+local is_expression = lbracket * C(((C(nobracket^1))/make_expression)) * rbracket
+
+local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
+
+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 = (period )
+local parent = (period * period ) / function( ) map[#map+1] = { 11 } end
+local subtreeroot = (slash + hat ) / function( ) map[#map+1] = { 12 } end
+local documentroot = (hat * hat ) / function( ) map[#map+1] = { 13 } end
+local any = (star ) / function( ) map[#map+1] = { 14 } end
+local many = (star * star ) / function( ) map[#map+1] = { 15 } end
+local initial = (hat * hat * hat ) / function( ) map[#map+1] = { 16 } end
+
+local match = (is_one ) / function(...) map[#map+1] = { 20, true , ... } end
+local match_one_of = (is_one_of ) / function(...) map[#map+1] = { 21, true , ... } end
+local dont_match = (is_none ) / function(...) map[#map+1] = { 20, false, ... } end
+local dont_match_one_of = (is_none_of ) / function(...) map[#map+1] = { 21, false, ... } end
+
+local match_and_eq = (is_one * is_eq ) / function(...) map[#map+1] = { 22, true , ... } end
+local match_and_ne = (is_one * is_ne ) / function(...) map[#map+1] = { 23, true , ... } end
+local dont_match_and_eq = (is_none * is_eq ) / function(...) map[#map+1] = { 22, false, ... } end
+local dont_match_and_ne = (is_none * is_ne ) / function(...) map[#map+1] = { 23, false, ... } end
+
+local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) map[#map+1] = { 24, true , ... } end
+local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) map[#map+1] = { 25, true , ... } end
+local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) map[#map+1] = { 24, false, ... } end
+local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) map[#map+1] = { 25, false, ... } end
+
+local has_attribute = (is_one * is_attribute) / function(...) map[#map+1] = { 27, true , ... } end
+local has_value = (is_one * is_value ) / function(...) map[#map+1] = { 28, true , ... } end
+local dont_has_attribute = (is_none * is_attribute) / function(...) map[#map+1] = { 27, false, ... } end
+local dont_has_value = (is_none * is_value ) / function(...) map[#map+1] = { 28, false, ... } end
+local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
+local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
+
+local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
+local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
+
+local self_expression = ( is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, true, "*", "*", ... } end
+local dont_self_expression = (exclam * is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, false, "*", "*", ... } end
+
+local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
+local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
+local crap = (1-slash)^1
+
+-- a few ugly goodies:
+
+local docroottag = P('^^') / function( ) map[#map+1] = { 12 } end
+local subroottag = P('^') / function( ) map[#map+1] = { 13 } end
+local roottag = P('root::') / function( ) map[#map+1] = { 12 } end
+local parenttag = P('parent::') / function( ) map[#map+1] = { 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 +
+ 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 +
+ has_attribute + has_value +
+ dont_match_one_of + match_one_of +
+ dont_match + match +
+ many + any +
+ crap + empty
+)
+
+local grammar = P { "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
+local function compose(str)
+ if not str or str == "" then
+ -- wildcard
+ return true
+ elseif str == '/' then
+ -- root
+ return false
+ else
+ map = { }
+ grammar:match(str)
+ if #map == 0 then
return true
- elseif str == '/' then
- -- root
- return false
else
- map = { }
- grammar:match(str)
- if #map == 0 then
- return true
- else
- 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
- -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
- map[2][1] = 29
- return { map[2] }
- end
- if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
- insert(map, 1, { 16 })
+ 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
- -- print((table.serialize(map)):gsub("[ \n]+"," "))
- return map
+ elseif #map == 2 and m == 12 and map[2][1] == 20 then
+ -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
+ map[2][1] = 29
+ return { map[2] }
+ end
+ if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
+ insert(map, 1, { 16 })
end
+ -- print(gsub(table.serialize(map),"[ \n]+"," "))
+ return map
end
end
+end
- local cache = { }
+local cache = { }
- function xml.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 xml.trace_lpath then
- xml.lshow(result)
- end
- return result
- else
- return pattern
+function xml.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
- function lpath_cached_patterns()
- return cache
- end
-
- local fallbackreport = (texio and texio.write) or io.write
+function xml.cached_patterns()
+ return cache
+end
- function xml.lshow(pattern,report)
- report = report or fallbackreport
- local lp = xml.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,v in ipairs(lp) do
- 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
+-- 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 = xml.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
- 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
+ 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
- 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
+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--
@@ -3376,161 +3764,174 @@ advance what we want to do with the found element the handle gets three argument
functions.</p>
--ldx]]--
-do
-
- local functions = xml.functions
- local expressions = xml.expressions
+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.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
+expressions.oneof = function(s,...) -- slow
+ local t = {...} for i=1,#t do if s == t[i] then return true end end 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
+expressions.error = function(str)
+ xml.error_handler("unknown function in lpath expression",str or "?")
+ return false
+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
+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
- 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
+ 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
- if found then
- local ns, tg = found.rn or found.ns or "", found.tg
- if ns ~= "" then
- return ns .. ":" .. tg
- else
- return tg
- end
+ end
+ if found then
+ local ns, tg = found.rn or found.ns or "", found.tg
+ if ns ~= "" then
+ return ns .. ":" .. tg
else
- return ""
+ 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
+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
- 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
+ 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
- return (found and found.tg) or ""
end
+ return (found and found.tg) or ""
+end
- expressions.text = functions.text
- expressions.name = functions.name
- expressions.tag = functions.tag
+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
+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
- 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
+ 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
- elseif command == 11 then -- parent
+ 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(root,rootdt,k) then
+ return false
+ 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
@@ -3538,41 +3939,51 @@ do
return false
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(root,rootdt,k) then
- return false
- 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
+ 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
- local idx = 0
- local hsh = { } -- this 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
+ elseif reverse and index == #pattern then
+ start, stop, step = stop, start, -1
+ end
+ local idx = 0
+ local hsh = { } -- this 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
@@ -3582,193 +3993,166 @@ do
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
+ 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
- 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 == 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[5]]
- elseif command == 28 then -- has value
- 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
+ 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
- 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
- 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
+ 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
- -- 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
+ 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
- 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
+ if not action[2] then matched = not matched end
+ matched = matched and e.at[action[#action-1]] ~= action[#action]
+ elseif command == 27 then -- has attribute
+ local 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[5]]
+ elseif command == 28 then -- has value
+ 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
- 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
+ else
+ 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
- end
- else
-- not here : 11
- if command == 11 then -- parent
+ elseif 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
+ 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
- break -- else loop
+ 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(root,rootdt,k) then
+ return false
+ end
+ break -- else loop
+ end
end
end
end
end
- return true
end
-
- xml.traverse = traverse
-
+ return true
end
+xml.traverse = traverse
+
--[[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
@@ -3779,399 +4163,414 @@ local r, d, k = xml.filter(root,"/a/b/c/position(4)"
</typing>
--ldx]]--
-do
+local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
- local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
+xml.filters = { }
- xml.filters = { }
+function xml.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 xml.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 xml.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
+function xml.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 { }, rt, dt, dk
+ return ekat, rt, dt, dk
end
+ else
+ return { }, rt, dt, dk
end
- function xml.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 xml.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
- function xml.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 xml.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 xml.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 xml.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 xml.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 xml.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
+
+function xml.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 xml.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 xml.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 xml.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 xml.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
- function xml.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 xml.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 ekat[arguments:gsub("^([\"\'])(.*)%1$","%2")])) or ""
- end
- function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
- local dtk, rt, dt, dk = xml.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 nil, nil, nil, nil
+end
+
+function xml.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 ekat[gsub(arguments,"^([\"\'])(.*)%1$","%2")])) or ""
+end
+
+function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
+ local dtk, rt, dt, dk = xml.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
- function xml.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 xml.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
+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]]--
+function xml.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
- -- not faster but hipper ... although ... i can't get rid of the trailing / in the path
+function xml.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
- local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
+--[[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]]--
- 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
+-- not faster but hipper ... although ... i can't get rid of the trailing / in the path
- local parser = direct + action + attribute
+local P, S, R, C, V, Cc = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc
- local filters = xml.filters
- local attribute_filter = xml.filters.attributes
- local default_filter = xml.filters.default
+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
- -- todo: also hash, could be gc'd
+local parser = direct + action + attribute
- function xml.filter(root,pattern)
- local kind, a, b, c = parser:match(pattern)
---~ if xml.trace_lpath then
---~ print(pattern,kind,a,b,c)
---~ end
- if kind == 1 or kind == 3 then
- return (filters[b] or default_filter)(root,a,c)
- elseif kind == 2 then
- 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
+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)
- 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] = ""
- 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] = tx or ""
+ t[#t+1] = ""
end
else
- t[#t+1] = ""
+ t[#t+1] = tx or ""
end
- end)
- return t
- end
+ else
+ t[#t+1] = ""
+ end
+ end)
+ return t
+end
- function xml.collect_tags(root, pattern, nonamespace)
- local t = { }
- xml.traverse(root, xml.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
+function xml.collect_tags(root, pattern, nonamespace)
+ local t = { }
+ xml.traverse(root, xml.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)
- return #t > 0 and {}
- 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>
+--[[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>
+<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>
+<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
+<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
- </typing>
+ return nil, nil, nil, nil
+end
+</typing>
- <p>We use the function variants in the filters.</p>
- --ldx]]--
+<p>We use the function variants in the filters.</p>
+--ldx]]--
- local wrap, yield = coroutine.wrap, coroutine.yield
+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(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.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
+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
- 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
+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
+ 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
+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]]--
+--[[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
+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
- element = element.dt
+ be, af = edt, xml.copy(element)
end
- if r.ri then
- edt = r.dt[r.ri].dt
- else
- edt = d and d[k] and d[k].dt
+ for i=1,#af do
+ be[#be+1] = af[i]
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
+ if r.ri then
+ r.dt[r.ri].dt = be
else
- -- r.dt = element.dt -- todo
+ d[k].dt = be
end
+ else
+ -- r.dt = element.dt -- todo
end
end
end
end
+end
- -- todo: copy !
+-- 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)
+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
@@ -4180,176 +4579,176 @@ do
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
+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] = table.remove(m[2],m[3])
- end
- return deleted
+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
+function xml.replace_element(root, pattern, element)
+ if type(element) == "string" then
+ element = convert(element,true)
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
+ 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
- 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 (attribute or "href"):gmatch("([^|]+)") do
- name = ek.at[a]
- if name then break 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
- local data = (name and name ~= "" and loaddata(name)) or ""
- if data == "" then
+ 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
+ local xi = xml.convert(data)
+ if not xi then
xml.empty(d,k)
- elseif ek.at["parse"] == "text" then -- for the moment hard coded
- d[k] = xml.escaped(data)
else
- local xi = xml.convert(data)
- 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)
+ if recursive then
+ xml.include(xi,pattern,attribute,recursive,loaddata)
end
+ xml.assign(d,k,xi)
end
end
- xml.each_element(xmldata, pattern, include)
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
+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
- if nolines then
- str = str:gsub("[ \n\r\t]+"," ")
- end
- if str == "" then
- -- stripped
- else
- t[#t+1] = str
- end
+ t[#t+1] = str
end
- else
- t[#t+1] = str
end
+ else
+ t[#t+1] = str
end
- d[k].dt = t
end
- end)
- end
+ d[k].dt = t
+ end
+ end)
+end
- function xml.rename_space(root, oldspace, newspace) -- fast variant
- local ndt = #root.dt
- local rename = xml.rename_space
- 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(edt, oldspace, newspace)
+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
- 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
+xml.rename_space = rename_space
- 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
+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--
@@ -4387,10 +4786,12 @@ put them here instead of loading mode modules there then needed.</p>
--ldx]]--
function xml.gsub(t,old,new)
- if t.dt then
- for k,v in ipairs(t.dt) do
+ local dt = t.dt
+ if dt then
+ for k=1,#dt do
+ local v = dt[k]
if type(v) == "string" then
- t.dt[k] = v:gsub(old,new)
+ dt[k] = gsub(v,old,new)
else
xml.gsub(v,old,new)
end
@@ -4415,45 +4816,41 @@ end
--~ xml.escapes = { ['&'] = '&amp;', ['<'] = '&lt;', ['>'] = '&gt;', ['"'] = '&quot;' }
--~ xml.unescapes = { } for k,v in pairs(xml.escapes) do xml.unescapes[v] = k end
---~ function xml.escaped (str) return str:gsub("(.)" , xml.escapes ) end
---~ function xml.unescaped(str) return str:gsub("(&.-;)", xml.unescapes) end
---~ function xml.cleansed (str) return str:gsub("<.->" , '' ) end -- "%b<>"
+--~ function xml.escaped (str) return (gsub(str,"(.)" , xml.escapes )) end
+--~ function xml.unescaped(str) return (gsub(str,"(&.-;)", xml.unescapes)) end
+--~ function xml.cleansed (str) return (gsub(str,"<.->" , '' )) end -- "%b<>"
-do
+local P, S, R, C, V, Cc, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.Cc, lpeg.Cs
- 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
+-- 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)
+-- 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)
+-- 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)
+-- 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)
+-- 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)
+-- 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)
+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
-
-end
+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
@@ -4471,115 +4868,6 @@ function xml.join(t,separator,lastseparator)
end
end
-
---[[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>
---ldx]]--
-
-do if unicode and unicode.utf8 then
-
- xml.entities = xml.entities or { } -- xml.entity_handler == function
-
- function xml.entity_handler(e)
- return format("[%s]",e)
- end
-
- local char = unicode.utf8.char
-
- local function toutf(s)
- return char(tonumber(s,16))
- end
-
- 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 dk:find("&#x.-;") then
- d[k] = dk:gsub("&#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 e:find("#x") then
- return char(tonumber(e:sub(3),16))
- 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 dk:find("&.-;") then
- d[k] = dk:gsub("&(.-);",resolve)
- end
- else
- resolve_entities(dk)
- end
- end
- end
- end
-
- xml.resolve_entities = resolve_entities
-
- function xml.utfize_text(str)
- if str:find("&#") then
- return (str:gsub("&#x(.-);",toutf))
- else
- return str
- end
- end
-
- function xml.resolve_text_entities(str) -- maybe an lpeg. maybe resolve inline
- if str:find("&") then
- return (str:gsub("&(.-);",resolve))
- else
- return str
- end
- end
-
- function xml.show_text_entities(str)
- if str:find("&") then
- return (str:gsub("&(.-);","[%1]"))
- else
- return str
- end
- end
-
- -- experimental, this will be done differently
-
- function xml.merge_entities(root)
- local documententities = root.entities
- local allentities = xml.entities
- if documententities then
- for k, v in pairs(documententities) do
- allentities[k] = v
- end
- end
- end
-
-end end
-
function xml.statistics()
return {
lpathcalls = lpathcalls,
@@ -4606,7 +4894,7 @@ end
--~ </a>
--~ ]])
---~ xml.trace_lpath = true
+--~ 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')]"))
@@ -4633,157 +4921,490 @@ end
--~ print(xml.filter(x,"b/tag(1)"))
--- filename : l-utils.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+end -- of closure
-if not versions then versions = { } end versions['l-utils'] = 1.001
+do -- create closure to overcome 200 locals limit
-if not utils then utils = { } end
-if not utils.merger then utils.merger = { } end
-if not utils.lua then utils.lua = { } end
+if not modules then modules = { } end modules ['lxml-ent'] = {
+ 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"
+}
-utils.merger.m_begin = "begin library merge"
-utils.merger.m_end = "end library merge"
-utils.merger.pattern =
- "%c+" ..
- "%-%-%s+" .. utils.merger.m_begin ..
- "%c+(.-)%c+" ..
- "%-%-%s+" .. utils.merger.m_end ..
- "%c+"
+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
-function utils.merger._self_fake_()
- return
- "-- " .. "created merged file" .. "\n\n" ..
- "-- " .. utils.merger.m_begin .. "\n\n" ..
- "-- " .. utils.merger.m_end .. "\n\n"
+--[[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>
+--ldx]]--
+
+xml.entities = xml.entities or { } -- xml.entity_handler == function
+
+function xml.entity_handler(e)
+ return format("[%s]",e)
end
-function utils.report(...)
- print(...)
+local function toutf(s)
+ return utfchar(tonumber(s,16))
end
-utils.merger.strip_comment = true
+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
-function utils.merger._self_load_(name)
- local f, data = io.open(name), ""
- if f then
- utils.report("reading merge from %s",name)
- data = f:read("*all")
- f:close()
+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
- utils.report("unknown file to merge %s",name)
+ 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
- if data and utils.merger.strip_comment then
- -- saves some 20K
- data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+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
- return data or ""
end
-function utils.merger._self_save_(name, data)
- if data ~= "" then
- local f = io.open(name,'w')
- if f then
- utils.report("saving merge from %s",name)
- f:write(data)
- f:close()
+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)
+ local documententities = root.entities
+ local allentities = xml.entities
+ if documententities then
+ for k, v in next, documententities do
+ allentities[k] = v
end
end
end
-function utils.merger._self_swap_(data,code)
- if data ~= "" then
- return (data:gsub(utils.merger.pattern, function(s)
- return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
- end, 1))
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-mis'] = {
+ 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 = table.concat
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, gsub = string.format, string.gsub
+
+--[[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"..string.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)
+
+xml.escaped_pattern = escaped
+xml.unescaped_pattern = unescaped
+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
-function utils.merger._self_libs_(libs,list)
- local result, f = { }, nil
- if type(libs) == 'string' then libs = { libs } end
- if type(list) == 'string' then list = { list } end
- for _, lib in ipairs(libs) do
- for _, pth in ipairs(list) do
- local name = string.gsub(pth .. "/" .. lib,"\\","/")
- f = io.open(name)
- if f then
- utils.report("merging library %s",name)
- result[#result+1] = f:read("*all")
- f:close()
- list = { pth } -- speed up the search
- break
- else
- utils.report("no library %s",name)
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
end
end
+ grandtotal = grandtotal + count
+ functions = functions + 1
end
- return table.concat(result, "\n\n")
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
end
-function utils.merger.selfcreate(libs,list,target)
- if target then
- utils.merger._self_save_(
- target,
- utils.merger._self_swap_(
- utils.merger._self_fake_(),
- utils.merger._self_libs_(libs,list)
- )
- )
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
end
end
-function utils.merger.selfmerge(name,libs,list,target)
- utils.merger._self_save_(
- target or name,
- utils.merger._self_swap_(
- utils.merger._self_load_(name),
- utils.merger._self_libs_(libs,list)
- )
- )
+function debugger.enable()
+ debug.sethook(hook,"c")
end
-function utils.merger.selfclean(name)
- utils.merger._self_save_(
- name,
- utils.merger._self_swap_(
- utils.merger._self_load_(name),
- ""
- )
- )
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
end
-function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
- -- utils.report("compiling",luafile,"into",lucfile)
- os.remove(lucfile)
- local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
- if strip ~= false then
- command = "-s " .. command
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
end
- local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
- if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
- -- utils.report("removing",luafile)
- os.remove(luafile)
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
end
- return done
end
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+do -- create closure to overcome 200 locals limit
-if not modules then modules = { } end modules ['luat-lib'] = {
+if not modules then modules = { } end modules ['luat-env'] = {
version = 1.001,
+ comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
- comment = "companion to luat-lib.tex",
+ license = "see context related readme files"
}
--- most code already moved to the l-*.lua and other luat-*.lua files
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
@@ -4791,15 +5412,27 @@ function os.setlocale()
-- no way you can mess with it
end
+-- dirty tricks
+
if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
end
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
environment = environment or { }
environment.arguments = { }
environment.files = { }
environment.sortedflags = nil
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
function environment.initialize_arguments(arg)
local arguments, files = { }, { }
environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
@@ -4821,24 +5454,20 @@ function environment.initialize_arguments(arg)
environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
end
-function environment.showarguments()
- for k,v in pairs(environment.arguments) do
- print(k .. " : " .. tostring(v))
- end
- if #environment.files > 0 then
- print("files : " .. table.concat(environment.files, " "))
- end
-end
-
function environment.setargument(name,value)
environment.arguments[name] = value
end
-function environment.argument(name) -- todo: default (plus typecheck on default)
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
local arguments, sortedflags = environment.arguments, environment.sortedflags
if arguments[name] then
return arguments[name]
- else
+ elseif partial then
if not sortedflags then
sortedflags = { }
for _,v in pairs(table.sortedkeys(arguments)) do
@@ -4846,6 +5475,7 @@ function environment.argument(name) -- todo: default (plus typecheck on default)
end
environment.sortedflags = sortedflags
end
+ -- example of potential clash: ^mode ^modefile
for _,v in ipairs(sortedflags) do
if name:find(v) then
return arguments[v:sub(2,#v)]
@@ -4869,43 +5499,17 @@ function environment.split_arguments(separator) -- rather special, cut-off befor
return before, after
end
---~ function environment.reconstruct_commandline(arg)
---~ if not arg then arg = environment.original_arguments end
---~ local result = { }
---~ for _,a in ipairs(arg) do -- ipairs 1 .. #n
---~ local kk, vv = a:match("^(%-+.-)=(.+)$")
---~ if kk and vv then
---~ if vv:find(" ") then
---~ vv = vv:unquote()
---~ vv = vv:gsub('"','\\"')
---~ result[#result+1] = kk .. "=" .. vv:quote()
---~ else
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a
---~ end
---~ elseif a:find(" ") then
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a:quote()
---~ else
---~ result[#result+1] = a
---~ end
---~ end
---~ return table.join(result," ")
---~ end
-
function environment.reconstruct_commandline(arg,noquote)
- if not arg then arg = environment.original_arguments end
+ arg = arg or environment.original_arguments
if noquote and #arg == 1 then
local a = arg[1]
- a = input.resolve(a)
+ a = resolvers.resolve(a)
a = a:unquote()
return a
- elseif #arg == 1 then
+ elseif next(arg) then
local result = { }
for _,a in ipairs(arg) do -- ipairs 1 .. #n
- a = input.resolve(a)
+ a = resolvers.resolve(a)
a = a:unquote()
a = a:gsub('"','\\"') -- tricky
if a:find(" ") then
@@ -4915,6 +5519,8 @@ function environment.reconstruct_commandline(arg,noquote)
end
end
return table.join(result," ")
+ else
+ return ""
end
end
@@ -4950,8 +5556,563 @@ if arg then
end
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
-if not modules then modules = { } end modules ['luat-inp'] = {
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
version = 1.001,
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -4959,12 +6120,20 @@ if not modules then modules = { } end modules ['luat-inp'] = {
comment = "companion to luat-lib.tex",
}
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
-- TODO: os.getenv -> os.env[]
-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
-- TODO: check escaping in find etc, too much, too slow
-- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
+-- additional functionality becomes available. We will split thislogs.report("fileio",
-- module in components once we're done with prototyping. This is the
-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
-- something in this module one can best check with Taco or Hans first; there
@@ -4978,82 +6147,205 @@ if not modules then modules = { } end modules ['luat-inp'] = {
-- Beware, loading and saving is overloaded in luat-tmp!
-if not input then input = { } end
-if not input.suffixes then input.suffixes = { } end
-if not input.formats then input.formats = { } end
-if not input.aux then input.aux = { } end
-
-if not input.suffixmap then input.suffixmap = { } end
-
-if not input.locators then input.locators = { } end -- locate databases
-if not input.hashers then input.hashers = { } end -- load databases
-if not input.generators then input.generators = { } end -- generate databases
-if not input.filters then input.filters = { } end -- conversion filters
-
-local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
-
-input.locators.notfound = { nil }
-input.hashers.notfound = { nil }
-input.generators.notfound = { nil }
-
-input.cacheversion = '1.0.1'
-input.banner = nil
-input.verbose = false
-input.debug = false
-input.cnfname = 'texmf.cnf'
-input.luaname = 'texmfcnf.lua'
-input.lsrname = 'ls-R'
-input.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
-
---~ input.luasuffix = 'tma'
---~ input.lucsuffix = 'tmc'
-
--- for the moment we have .local but this will disappear
-input.cnfdefault = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- chances are low that the cnf file is in the bin path
-input.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- we use a cleaned up list / format=any is a wildcard, as is *name
-
-input.formats['afm'] = 'AFMFONTS' input.suffixes['afm'] = { 'afm' }
-input.formats['enc'] = 'ENCFONTS' input.suffixes['enc'] = { 'enc' }
-input.formats['fmt'] = 'TEXFORMATS' input.suffixes['fmt'] = { 'fmt' }
-input.formats['map'] = 'TEXFONTMAPS' input.suffixes['map'] = { 'map' }
-input.formats['mp'] = 'MPINPUTS' input.suffixes['mp'] = { 'mp' }
-input.formats['ocp'] = 'OCPINPUTS' input.suffixes['ocp'] = { 'ocp' }
-input.formats['ofm'] = 'OFMFONTS' input.suffixes['ofm'] = { 'ofm', 'tfm' }
-input.formats['otf'] = 'OPENTYPEFONTS' input.suffixes['otf'] = { 'otf' } -- 'ttf'
-input.formats['opl'] = 'OPLFONTS' input.suffixes['opl'] = { 'opl' }
-input.formats['otp'] = 'OTPINPUTS' input.suffixes['otp'] = { 'otp' }
-input.formats['ovf'] = 'OVFFONTS' input.suffixes['ovf'] = { 'ovf', 'vf' }
-input.formats['ovp'] = 'OVPFONTS' input.suffixes['ovp'] = { 'ovp' }
-input.formats['tex'] = 'TEXINPUTS' input.suffixes['tex'] = { 'tex' }
-input.formats['tfm'] = 'TFMFONTS' input.suffixes['tfm'] = { 'tfm' }
-input.formats['ttf'] = 'TTFONTS' input.suffixes['ttf'] = { 'ttf', 'ttc' }
-input.formats['pfb'] = 'T1FONTS' input.suffixes['pfb'] = { 'pfb', 'pfa' }
-input.formats['vf'] = 'VFFONTS' input.suffixes['vf'] = { 'vf' }
-
-input.formats['fea'] = 'FONTFEATURES' input.suffixes['fea'] = { 'fea' }
-input.formats['cid'] = 'FONTCIDMAPS' input.suffixes['cid'] = { 'cid', 'cidmap' }
-
-input.formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
-input.suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
-
-input.formats ['lua'] = 'LUAINPUTS' -- new
-input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
-- here we catch a few new thingies (todo: add these paths to context.tmf)
--
-- FONTFEATURES = .;$TEXMF/fonts/fea//
-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
-function input.checkconfigdata() -- not yet ok, no time for debugging now
- local instance = input.instance
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
local function fix(varname,default)
local proname = varname .. "." .. instance.progname or "crap"
- local p = instance.environment[proname]
- local v = instance.environment[varname]
+ local p, v = ie[proname], ie[varname]
if not ((p and p ~= "") or (v and v ~= "")) then
instance.variables[varname] = default -- or environment?
end
@@ -5069,207 +6361,198 @@ function input.checkconfigdata() -- not yet ok, no time for debugging now
fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
end
--- backward compatible ones
-
-input.alternatives = { }
-
-input.alternatives['map files'] = 'map'
-input.alternatives['enc files'] = 'enc'
-input.alternatives['cid files'] = 'cid'
-input.alternatives['fea files'] = 'fea'
-input.alternatives['opentype fonts'] = 'otf'
-input.alternatives['truetype fonts'] = 'ttf'
-input.alternatives['truetype collections'] = 'ttc'
-input.alternatives['type1 fonts'] = 'pfb'
-
--- obscure ones
-
-input.formats ['misc fonts'] = ''
-input.suffixes['misc fonts'] = { }
-
-input.formats ['sfd'] = 'SFDFONTS'
-input.suffixes ['sfd'] = { 'sfd' }
-input.alternatives['subfont definition files'] = 'sfd'
-
--- In practice we will work within one tds tree, but i want to keep
--- the option open to build tools that look at multiple trees, which is
--- why we keep the tree specific data in a table. We used to pass the
--- instance but for practical pusposes we now avoid this and use a
--- instance variable.
-
-function input.newinstance()
-
- local instance = { }
-
- instance.rootpath = ''
- instance.treepath = ''
- instance.progname = 'context'
- instance.engine = 'luatex'
- instance.format = ''
- instance.environment = { }
- instance.variables = { }
- instance.expansions = { }
- instance.files = { }
- instance.remap = { }
- instance.configuration = { }
- instance.setup = { }
- instance.order = { }
- instance.found = { }
- instance.foundintrees = { }
- instance.kpsevars = { }
- instance.hashes = { }
- instance.cnffiles = { }
- instance.luafiles = { }
- instance.lists = { }
- instance.remember = true
- instance.diskcache = true
- instance.renewcache = false
- instance.scandisk = true
- instance.cachepath = nil
- instance.loaderror = false
- instance.smallcache = false
- instance.sortdata = false
- instance.savelists = true
- instance.cleanuppaths = true
- instance.allresults = false
- instance.pattern = nil -- lists
- instance.kpseonly = false -- lists
- instance.loadtime = 0
- instance.starttime = 0
- instance.stoptime = 0
- instance.validfile = function(path,name) return true end
- instance.data = { } -- only for loading
- instance.force_suffixes = true
- instance.dummy_path_expr = "^!*unset/*$"
- instance.fakepaths = { }
- instance.lsrmode = false
-
- -- store once, freeze and faster (once reset we can best use instance.environment)
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
- for k,v in pairs(os.env) do
- instance.environment[k] = input.bare_variable(v)
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
end
+end
- -- cross referencing, delayed because we can add suffixes
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
- for k, v in pairs(input.suffixes) do
- for _, vv in pairs(v) do
- if vv then
- input.suffixmap[vv] = k
- end
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
end
+ ie[key] = value
end
-
- return instance
-
+ return value or ""
end
-input.instance = input.instance or nil
-
-function input.reset()
- input.instance = input.newinstance()
- return input.instance
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
end
-function input.reset_hashes()
- input.instance.lists = { }
- input.instance.found = { }
-end
+--
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
- return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
end
-function input.settrace(n)
- input.trace = tonumber(n or 0)
- if input.trace > 0 then
- input.verbose = true
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
end
-input.log = (texio and texio.write_nl) or print
-
-function input.report(...)
- if input.verbose then
- input.log("<<"..format(...)..">>")
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
end
+ return ""
end
-function input.report(...)
- if input.trace > 0 then -- extra test
- input.log("<<"..format(...)..">>")
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
end
end
-input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
-
--- These functions can be used to test the performance, especially
--- loading the database files.
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
-do
- local clock = os.gettimeofday or os.clock
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
- function input.starttiming(instance)
- if instance then
- instance.starttime = clock()
- if not instance.loadtime then
- instance.loadtime = 0
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
end
end
+ return "{" .. concat(t,",") .. "}"
end
-
- function input.stoptiming(instance, report)
- if instance then
- local starttime = instance.starttime
- if starttime then
- local stoptime = clock()
- local loadtime = stoptime - starttime
- instance.stoptime = stoptime
- instance.loadtime = instance.loadtime + loadtime
- if report then
- input.report("load time %0.3f",loadtime)
- end
- return loadtime
- end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
end
- return 0
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
end
-
-end
-
-function input.elapsedtime(instance)
- return format("%0.3f",(instance and instance.loadtime) or 0)
-end
-
-function input.report_loadtime(instance)
- if instance then
- input.report('total load time %s', input.elapsedtime(instance))
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
end
+ return t
end
-input.loadtime = input.elapsedtime
-
-function input.env(key)
- return input.instance.environment[key] or input.osenv(key)
-end
-
-function input.osenv(key)
- local ie = input.instance.environment
- local value = ie[key]
- if value == nil then
- -- local e = os.getenv(key)
- local e = os.env[key]
- if e == nil then
- -- value = "" -- false
- else
- value = input.bare_variable(e)
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
end
- ie[key] = value
end
- return value or ""
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
end
-- we follow a rather traditional approach:
@@ -5280,20 +6563,20 @@ end
-- also we now follow the stupid route: if not set then just assume *one*
-- cnf file under texmf (i.e. distribution)
-input.ownpath = input.ownpath or nil
-input.ownbin = input.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
-input.autoselfdir = true -- false may be handy for debugging
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
-function input.getownpath()
- if not input.ownpath then
- if input.autoselfdir and os.selfdir then
- input.ownpath = os.selfdir
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
else
- local binary = input.ownbin
+ local binary = resolvers.ownbin
if os.platform == "windows" then
binary = file.replacesuffix(binary,"exe")
end
- for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
local b = file.join(p,binary)
if lfs.isfile(b) then
-- we assume that after changing to the path the currentdir function
@@ -5303,162 +6586,91 @@ function input.getownpath()
local olddir = lfs.currentdir()
if lfs.chdir(p) then
local pp = lfs.currentdir()
- if input.verbose and p ~= pp then
- input.report("following symlink %s to %s",p,pp)
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
end
- input.ownpath = pp
+ resolvers.ownpath = pp
lfs.chdir(olddir)
else
- if input.verbose then
- input.report("unable to check path %s",p)
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
end
- input.ownpath = p
+ resolvers.ownpath = p
end
break
end
end
end
- if not input.ownpath then input.ownpath = '.' end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
end
- return input.ownpath
+ return resolvers.ownpath
end
-function input.identify_own()
- local instance = input.instance
- local ownpath = input.getownpath() or lfs.currentdir()
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
local ie = instance.environment
if ownpath then
- if input.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
- if input.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
- if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
else
- input.verbose = true
- input.report("error: unable to locate ownpath")
+ logs.report("fileio","error: unable to locate ownpath")
os.exit()
end
- if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
- if input.env('TEXOS') == "" then os.env['TEXOS'] = input.env('SELFAUTODIR') end
- if input.env('TEXROOT') == "" then os.env['TEXROOT'] = input.env('SELFAUTOPARENT') end
- if input.verbose then
- for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
- input.report("variable %s set to %s",v,input.env(v) or "unknown")
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
end
end
- function input.identify_own() end
+ identify_own = function() end
end
-function input.identify_cnf()
- local instance = input.instance
+function resolvers.identify_cnf()
if #instance.cnffiles == 0 then
-- fallback
- input.identify_own()
+ identify_own()
-- the real search
- input.expand_variables()
- local t = input.split_path(input.env('TEXMFCNF'))
- t = input.aux.expanded_path(t)
- input.aux.expand_vars(t) -- redundant
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
local function locate(filename,list)
- for _,v in ipairs(t) do
- local texmfcnf = input.normalize_name(file.join(v,filename))
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
if lfs.isfile(texmfcnf) then
- table.insert(list,texmfcnf)
+ list[#list+1] = texmfcnf
end
end
end
- locate(input.luaname,instance.luafiles)
- locate(input.cnfname,instance.cnffiles)
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
end
end
-function input.load_cnf()
- local instance = input.instance
- local function loadoldconfigdata()
- for _, fname in ipairs(instance.cnffiles) do
- input.aux.load_cnf(fname)
- end
- end
- -- instance.cnffiles contain complete names now !
- if #instance.cnffiles == 0 then
- input.report("no cnf files found (TEXMFCNF may not be set/known)")
- else
- instance.rootpath = instance.cnffiles[1]
- for k,fname in ipairs(instance.cnffiles) do
- instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- if instance.lsrmode then
- loadoldconfigdata()
- elseif instance.diskcache and not instance.renewcache then
- input.loadoldconfig(instance.cnffiles)
- if instance.loaderror then
- loadoldconfigdata()
- input.saveoldconfig()
- end
- else
- loadoldconfigdata()
- if instance.renewcache then
- input.saveoldconfig()
- end
- end
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.load_lua()
- local instance = input.instance
- if #instance.luafiles == 0 then
- -- yet harmless
- else
- instance.rootpath = instance.luafiles[1]
- for k,fname in ipairs(instance.luafiles) do
- instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- input.loadnewconfig()
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
- local instance = input.instance
- for _,c in ipairs(instance.order) do
- for k,v in pairs(c) do
- if not instance.variables[k] then
- if instance.environment[k] then
- instance.variables[k] = instance.environment[k]
- else
- instance.kpsevars[k] = true
- instance.variables[k] = input.bare_variable(v)
- end
- end
- end
- end
-end
-
-function input.aux.load_cnf(fname)
- local instance = input.instance
- fname = input.clean_path(fname)
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
local lname = file.replacesuffix(fname,'lua')
local f = io.open(lname)
if f then -- this will go
f:close()
local dname = file.dirname(fname)
if not instance.configuration[dname] then
- input.aux.load_configuration(dname,lname)
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
instance.order[#instance.order+1] = instance.configuration[dname]
end
else
f = io.open(fname)
if f then
- input.report("loading %s", fname)
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
local line, data, n, k, v
local dname = file.dirname(fname)
if not instance.configuration[dname] then
@@ -5470,17 +6682,19 @@ function input.aux.load_cnf(fname)
local line, n = f:read(), 0
if line then
while true do -- join lines
- line, n = line:gsub("\\%s*$", "")
+ line, n = gsub(line,"\\%s*$", "")
if n > 0 then
line = line .. f:read()
else
break
end
end
- if not line:find("^[%%#]") then
- local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$")
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
if k and v and not data[k] then
- data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME")
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
instance.kpsevars[k] = true
end
end
@@ -5489,53 +6703,119 @@ function input.aux.load_cnf(fname)
end
end
f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
else
- input.report("skipping %s", fname)
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
end
+ collapse_cnf_data()
end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
end
-- database loading
-function input.load_hash()
- local instance = input.instance
- input.locatelists()
- if instance.lsrmode then
- input.loadlists()
- elseif instance.diskcache and not instance.renewcache then
- input.loadfiles()
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
if instance.loaderror then
- input.loadlists()
- input.savefiles()
+ resolvers.loadlists()
+ resolvers.savefiles()
end
else
- input.loadlists()
+ resolvers.loadlists()
if instance.renewcache then
- input.savefiles()
+ resolvers.savefiles()
end
end
end
-function input.aux.append_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash append: %s",tag)
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
end
- table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
end
-function input.aux.prepend_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash prepend: %s",tag)
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
end
- table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
end
-function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
- local instance = input.instance
--- local t = input.expanded_path_list('TEXMF') -- full expansion
- local t = input.split_path(input.env('TEXMF'))
- table.insert(t,1,specification)
- local newspec = table.join(t,";")
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
if instance.environment["TEXMF"] then
instance.environment["TEXMF"] = newspec
elseif instance.variables["TEXMF"] then
@@ -5543,182 +6823,142 @@ function input.aux.extend_texmf_var(specification) -- crap, we could better prep
else
-- weird
end
- input.expand_variables()
- input.reset_hashes()
+ resolvers.expand_variables()
+ reset_hashes()
end
-- locators
-function input.locatelists()
- local instance = input.instance
- for _, path in pairs(input.clean_path_list('TEXMF')) do
- input.report("locating list of %s",path)
- input.locatedatabase(input.normalize_name(path))
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
end
end
-function input.locatedatabase(specification)
- return input.methodhandler('locators', specification)
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
end
-function input.locators.tex(specification)
+function resolvers.locators.tex(specification)
if specification and specification ~= '' and lfs.isdir(specification) then
- if input.trace > 0 then
- input.logger('! tex locator found: %s',specification)
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
end
- input.aux.append_hash('file',specification,filename)
- elseif input.trace > 0 then
- input.logger('? tex locator not found: %s',specification)
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
end
end
-- hashers
-function input.hashdatabase(tag,name)
- return input.methodhandler('hashers',tag,name)
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
end
-function input.loadfiles()
- local instance = input.instance
+function resolvers.loadfiles()
instance.loaderror = false
instance.files = { }
if not instance.renewcache then
for _, hash in ipairs(instance.hashes) do
- input.hashdatabase(hash.tag,hash.name)
+ resolvers.hashdatabase(hash.tag,hash.name)
if instance.loaderror then break end
end
end
end
-function input.hashers.tex(tag,name)
- input.aux.load_files(tag)
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
end
-- generators:
-function input.loadlists()
- for _, hash in ipairs(input.instance.hashes) do
- input.generatedatabase(hash.tag)
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
end
end
-function input.generatedatabase(specification)
- return input.methodhandler('generators', specification)
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
end
-local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-function input.generators.tex(specification)
- local instance = input.instance
+function resolvers.generators.tex(specification)
local tag = specification
- if not instance.lsrmode and lfs.dir then
- input.report("scanning path %s",specification)
- instance.files[tag] = { }
- local files = instance.files[tag]
- local n, m, r = 0, 0, 0
- local spec = specification .. '/'
- local attributes = lfs.attributes
- local directory = lfs.dir
- local small = instance.smallcache
- local function action(path)
- local mode, full
- if path then
- full = spec .. path .. '/'
- else
- full = spec
- end
- for name in directory(full) do
- if name:find("^%.") then
- -- skip
- -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
- elseif weird:match(name) then
- -- texio.write_nl("skipping " .. name)
- -- skip
- else
- mode = attributes(full..name,'mode')
- if mode == 'directory' then
- m = m + 1
- if path then
- action(path..'/'..name)
- else
- action(name)
- end
- elseif path and mode == 'file' then
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
n = n + 1
local f = files[name]
if f then
- if not small then
- if type(f) == 'string' then
- files[name] = { f, path }
- else
- f[#f+1] = path
- end
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
end
- else
+ else -- probably unique anyway
files[name] = path
- local lower = name:lower()
+ local lower = lower(name)
if name ~= lower then
files["remap:"..lower] = name
r = r + 1
end
end
end
- end
- end
- end
- action()
- input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
- else
- local fullname = file.join(specification,input.lsrname)
- local path = '.'
- local f = io.open(fullname)
- if f then
- instance.files[tag] = { }
- local files = instance.files[tag]
- local small = instance.smallcache
- input.report("loading lsr file %s",fullname)
- -- for line in f:lines() do -- much slower then the next one
- for line in (f:read("*a")):gmatch("(.-)\n") do
- if line:find("^[%a%d]") then
- local fl = files[line]
- if fl then
- if not small then
- if type(fl) == 'string' then
- files[line] = { fl, path } -- table
- else
- fl[#fl+1] = path
- end
- end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
else
- files[line] = path -- string
- local lower = line:lower()
- if line ~= lower then
- files["remap:"..lower] = line
- end
+ action(name)
end
- else
- path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
end
end
- f:close()
end
end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
end
-- savers, todo
-function input.savefiles()
- input.aux.save_data('files', function(k,v)
- return input.instance.validfile(k,v) -- path, name
- end)
+function resolvers.savefiles()
+ resolvers.save_data('files')
end
-- A config (optionally) has the paths split in tables. Internally
-- we join them and split them after the expansion has taken place. This
-- is more convenient.
-function input.splitconfig()
- for i,c in ipairs(input.instance) do
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
for k,v in pairs(c) do
if type(v) == 'string' then
local t = file.split_path(v)
@@ -5730,23 +6970,23 @@ function input.splitconfig()
end
end
-function input.joinconfig()
- for i,c in ipairs(input.instance.order) do
- for k,v in pairs(c) do
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
if type(v) == 'table' then
c[k] = file.join_path(v)
end
end
end
end
-function input.split_path(str)
+function resolvers.split_path(str)
if type(str) == 'table' then
return str
else
return file.split_path(str)
end
end
-function input.join_path(str)
+function resolvers.join_path(str)
if type(str) == 'table' then
return file.join_path(str)
else
@@ -5754,11 +6994,11 @@ function input.join_path(str)
end
end
-function input.splitexpansions()
- local ie = input.instance.expansions
- for k,v in pairs(ie) do
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
local t, h = { }, { }
- for _,vv in pairs(file.split_path(v)) do
+ for _,vv in ipairs(file.split_path(v)) do
if vv ~= "" and not h[vv] then
t[#t+1] = vv
h[vv] = true
@@ -5774,27 +7014,27 @@ end
-- end of split/join code
-function input.saveoldconfig()
- input.splitconfig()
- input.aux.save_data('configuration', nil)
- input.joinconfig()
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
end
-input.configbanner = [[
+resolvers.configbanner = [[
-- This is a Luatex configuration file created by 'luatools.lua' or
-- 'luatex.exe' directly. For comment, suggestions and questions you can
-- contact the ConTeXt Development Team. This configuration file is
-- not copyrighted. [HH & TH]
]]
-function input.serialize(files)
+function resolvers.serialize(files)
-- This version is somewhat optimized for the kind of
-- tables that we deal with, so it's much faster than
-- the generic serializer. This makes sense because
-- luatools and mtxtools are called frequently. Okay,
-- we pay a small price for properly tabbed tables.
local t = { }
- local function dump(k,v,m)
+ local function dump(k,v,m) -- could be moved inline
if type(v) == 'string' then
return m .. "['" .. k .. "']='" .. v .. "',"
elseif #v == 1 then
@@ -5804,12 +7044,12 @@ function input.serialize(files)
end
end
t[#t+1] = "return {"
- if input.instance.sortdata then
- for _, k in pairs(sortedkeys(files)) do
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
local fk = files[k]
if type(fk) == 'table' then
t[#t+1] = "\t['" .. k .. "']={"
- for _, kk in pairs(sortedkeys(fk)) do
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
t[#t+1] = dump(kk,fk[kk],"\t\t")
end
t[#t+1] = "\t},"
@@ -5818,10 +7058,10 @@ function input.serialize(files)
end
end
else
- for k, v in pairs(files) do
+ for k, v in next, files do
if type(v) == 'table' then
t[#t+1] = "\t['" .. k .. "']={"
- for kk,vv in pairs(v) do
+ for kk,vv in next, v do
t[#t+1] = dump(kk,vv,"\t\t")
end
t[#t+1] = "\t},"
@@ -5834,62 +7074,67 @@ function input.serialize(files)
return concat(t,"\n")
end
-if not texmf then texmf = {} end -- no longer needed, at least not here
-
-function input.aux.save_data(dataname, check, makename) -- untested without cache overload
- for cachename, files in pairs(input.instance[dataname]) do
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
local name = (makename or file.join)(cachename,dataname)
local luaname, lucname = name .. ".lua", name .. ".luc"
- input.report("preparing %s for %s",dataname,cachename)
- for k, v in pairs(files) do
- if not check or check(v,k) then -- path, name
- if type(v) == "table" and #v == 1 then
- files[k] = v[1]
- end
- else
- files[k] = nil -- false
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
end
end
local data = {
type = dataname,
root = cachename,
- version = input.cacheversion,
+ version = resolvers.cacheversion,
date = os.date("%Y-%m-%d"),
time = os.date("%H:%M:%S"),
content = files,
}
- local ok = io.savedata(luaname,input.serialize(data))
+ local ok = io.savedata(luaname,resolvers.serialize(data))
if ok then
- input.report("%s saved in %s",dataname,luaname)
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
- input.report("%s compiled to %s",dataname,lucname)
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
else
- input.report("compiling failed for %s, deleting file %s",dataname,lucname)
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
os.remove(lucname)
end
- else
- input.report("unable to save %s in %s (access error)",dataname,luaname)
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
end
end
end
-function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
- local instance = input.instance
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
filename = ((not filename or (filename == "")) and dataname) or filename
filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
if blob then
local data = blob()
- if data and data.content and data.type == dataname and data.version == input.cacheversion then
- input.report("loading %s for %s from %s",dataname,pathname,filename)
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
instance[dataname][pathname] = data.content
else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
instance[dataname][pathname] = { }
instance.loaderror = true
end
- else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
end
end
@@ -5902,195 +7147,139 @@ end
-- TEXMFBOGUS = 'effe checken of dit werkt',
-- }
-function input.aux.load_texmfcnf(dataname,pathname)
- local instance = input.instance
- local filename = file.join(pathname,input.luaname)
- local blob = loadfile(filename)
- if blob then
- local data = blob()
- if data then
- input.report("loading configuration file %s",filename)
- if true then
- -- flatten to variable.progname
- local t = { }
- for k, v in pairs(data) do -- v = progname
- if type(v) == "string" then
- t[k] = v
- else
- for kk, vv in pairs(v) do -- vv = variable
- if type(vv) == "string" then
- t[vv.."."..v] = kk
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
end
end
end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
end
- instance[dataname][pathname] = t
else
- instance[dataname][pathname] = data
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
end
- else
- input.report("skipping configuration file %s",filename)
- instance[dataname][pathname] = { }
- instance.loaderror = true
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
end
- else
- input.report("skipping configuration file %s",filename)
- end
-end
-
-function input.aux.load_configuration(dname,lname)
- input.aux.load_data(dname,'configuration',lname and file.basename(lname))
-end
-function input.aux.load_files(tag)
- input.aux.load_data(tag,'files')
-end
-
-function input.resetconfig()
- input.identify_own()
- local instance = input.instance
- instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
-end
-
-function input.loadnewconfig()
- local instance = input.instance
- for _, cnf in ipairs(instance.luafiles) do
- local dname = file.dirname(cnf)
- input.aux.load_texmfcnf('setup',dname)
- instance.order[#instance.order+1] = instance.setup[dname]
+ instance.order[#instance.order+1] = instance.setup[pathname]
if instance.loaderror then break end
end
end
-function input.loadoldconfig()
- local instance = input.instance
+function resolvers.loadoldconfig()
if not instance.renewcache then
for _, cnf in ipairs(instance.cnffiles) do
local dname = file.dirname(cnf)
- input.aux.load_configuration(dname)
+ resolvers.load_data(dname,'configuration')
instance.order[#instance.order+1] = instance.configuration[dname]
if instance.loaderror then break end
end
end
- input.joinconfig()
+ resolvers.joinconfig()
end
-function input.expand_variables()
- local instance = input.instance
+function resolvers.expand_variables()
local expansions, environment, variables = { }, instance.environment, instance.variables
- local env = input.env
+ local env = resolvers.env
instance.expansions = expansions
if instance.engine ~= "" then environment['engine'] = instance.engine end
if instance.progname ~= "" then environment['progname'] = instance.progname end
- for k,v in pairs(environment) do
- local a, b = k:match("^(%a+)%_(.*)%s*$")
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
if a and b then
expansions[a..'.'..b] = v
else
expansions[k] = v
end
end
- for k,v in pairs(environment) do -- move environment to expansions
+ for k,v in next, environment do -- move environment to expansions
if not expansions[k] then expansions[k] = v end
end
- for k,v in pairs(variables) do -- move variables to expansions
+ for k,v in next, variables do -- move variables to expansions
if not expansions[k] then expansions[k] = v end
end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
while true do
- local busy = false
- for k,v in pairs(expansions) do
- local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
- local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
if n > 0 or m > 0 then
expansions[k]= s
end
end
if not busy then break end
end
- for k,v in pairs(expansions) do
- expansions[k] = v:gsub("\\", '/')
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
end
end
-function input.aux.expand_vars(lst) -- simple vars
- local instance = input.instance
- local variables, env = instance.variables, input.env
- for k,v in pairs(lst) do
- lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
- return variables[a] or env(a)
- end)
- end
+function resolvers.variable(name)
+ return entry(instance.variables,name)
end
-function input.aux.expanded_var(var) -- simple vars
- local instance = input.instance
- return var:gsub("%$([%a%d%_%-]+)", function(a)
- return instance.variables[a] or input.env(a)
- end)
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
end
-function input.aux.entry(entries,name)
- if name and (name ~= "") then
- local instance = input.instance
- name = name:gsub('%$','')
- local result = entries[name..'.'..instance.progname] or entries[name]
- if result then
- return result
- else
- result = input.env(name)
- if result then
- instance.variables[name] = result
- input.expand_variables()
- return instance.expansions[name] or ""
- end
- end
- end
- return ""
-end
-function input.variable(name)
- return input.aux.entry(input.instance.variables,name)
-end
-function input.expansion(name)
- return input.aux.entry(input.instance.expansions,name)
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
end
-function input.aux.is_entry(entries,name)
- if name and name ~= "" then
- name = name:gsub('%$','')
- return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
- else
- return false
- end
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
end
-function input.is_variable(name)
- return input.aux.is_entry(input.instance.variables,name)
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
end
-function input.is_expansion(name)
- return input.aux.is_entry(input.instance.expansions,name)
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
end
-function input.unexpanded_path_list(str)
- local pth = input.variable(str)
- local lst = input.split_path(pth)
- return input.aux.expanded_path(lst)
-end
+do -- no longer needed
-function input.unexpanded_path(str)
- return file.join_path(input.unexpanded_path_list(str))
-end
-
-do
local done = { }
- function input.reset_extra_path()
- local instance = input.instance
+ function resolvers.reset_extra_path()
local ep = instance.extra_paths
if not ep then
ep, done = { }, { }
@@ -6100,26 +7289,25 @@ do
end
end
- function input.register_extra_path(paths,subpaths)
- local instance = input.instance
+ function resolvers.register_extra_path(paths,subpaths)
local ep = instance.extra_paths or { }
local n = #ep
if paths and paths ~= "" then
if subpaths and subpaths ~= "" then
- for p in paths:gmatch("[^,]+") do
+ for p in gmatch(paths,"[^,]+") do
-- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
+ for s in gmatch(subpaths,"[^,]+") do
local ps = p .. "/" .. s
if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
+ ep[#ep+1] = resolvers.clean_path(ps)
done[ps] = true
end
end
end
else
- for p in paths:gmatch("[^,]+") do
+ for p in gmatch(paths,"[^,]+") do
if not done[p] then
- ep[#ep+1] = input.clean_path(p)
+ ep[#ep+1] = resolvers.clean_path(p)
done[p] = true
end
end
@@ -6127,10 +7315,10 @@ do
elseif subpaths and subpaths ~= "" then
for i=1,n do
-- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
+ for s in gmatch(subpaths,"[^,]+") do
local ps = ep[i] .. "/" .. s
if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
+ ep[#ep+1] = resolvers.clean_path(ps)
done[ps] = true
end
end
@@ -6146,306 +7334,196 @@ do
end
-function input.expanded_path_list(str)
- local instance = input.instance
- local function made_list(list)
- local ep = instance.extra_paths
- if not ep or #ep == 0 then
- return list
- else
- local done, new = { }, { }
- -- honour . .. ../.. but only when at the start
- for k, v in ipairs(list) do
- if not done[v] then
- if v:find("^[%.%/]$") then
- done[v] = true
- new[#new+1] = v
- else
- break
- end
- end
- end
- -- first the extra paths
- for k, v in ipairs(ep) do
- if not done[v] then
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
done[v] = true
new[#new+1] = v
+ else
+ break
end
end
- -- next the formal paths
- for k, v in ipairs(list) do
- if not done[v] then
- done[v] = true
- new[#new+1] = v
- end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
end
- return new
end
- end
- if not str then
- return ep or { }
- elseif instance.savelists then
- -- engine+progname hash
- str = str:gsub("%$","")
- if not instance.lists[str] then -- cached
- local lst = made_list(input.split_path(input.expansion(str)))
- instance.lists[str] = input.aux.expanded_path(lst)
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
end
- return instance.lists[str]
- else
- local lst = input.split_path(input.expansion(str))
- return made_list(input.aux.expanded_path(lst))
+ return new
end
end
-
-function input.clean_path_list(str)
- local t = input.expanded_path_list(str)
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
if t then
for i=1,#t do
- t[i] = file.collapse_path(input.clean_path(t[i]))
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
end
end
return t
end
-function input.expand_path(str)
- return file.join_path(input.expanded_path_list(str))
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
end
-function input.expanded_path_list_from_var(str) -- brrr
- local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
if tmp ~= "" then
- return input.expanded_path_list(str)
+ return resolvers.expanded_path_list(str)
else
- return input.expanded_path_list(tmp)
+ return resolvers.expanded_path_list(tmp)
end
end
-function input.expand_path_from_var(str)
- return file.join_path(input.expanded_path_list_from_var(str))
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
end
-function input.format_of_var(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
end
-function input.format_of_suffix(str)
- return input.suffixmap[file.extname(str)] or 'tex'
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
end
-function input.variable_of_format(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
end
-function input.var_of_format_or_suffix(str)
- local v = input.formats[str]
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
if v then
return v
end
- v = input.formats[input.alternatives[str]]
+ v = formats[alternatives[str]]
if v then
return v
end
- v = input.suffixmap[file.extname(str)]
+ v = suffixmap[file.extname(str)]
if v then
- return input.formats[isf]
+ return formats[isf]
end
return ''
end
-function input.expand_braces(str) -- output variable and brace expansion of STRING
- local ori = input.variable(str)
- local pth = input.aux.expanded_path(input.split_path(ori))
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
return file.join_path(pth)
end
--- {a,b,c,d}
--- a,b,c/{p,q,r},d
--- a,b,c/{p,q,r}/d/{x,y,z}//
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a{b,c}{d,e}f
--- {a,b,c,d}
--- {a,b,c/{p,q,r},d}
--- {a,b,c/{p,q,r}/d/{x,y,z}//}
--- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
--- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
--- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+resolvers.isreadable = { }
--- this one is better and faster, but it took me a while to realize
--- that this kind of replacement is cleaner than messy parsing and
--- fuzzy concatenating we can probably gain a bit with selectively
--- applying lpeg, but experiments with lpeg parsing this proved not to
--- work that well; the parsing is ok, but dealing with the resulting
--- table is a pain because we need to work inside-out recursively
-
-function input.aux.splitpathexpr(str, t, validate)
- -- no need for optimization, only called a few times, we can use lpeg for the sub
- t = t or { }
- str = str:gsub(",}",",@}")
- str = str:gsub("{,","{@,")
- -- str = "@" .. str .. "@"
- while true do
- local done = false
- while true do
- local ok = false
- str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
- local t = { }
- for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
- local t = { }
- for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
- local t = { }
- for sa in a:gmatch("[^,]+") do
- for sb in b:gmatch("[^,]+") do
- t[#t+1] = sa .. sb
- end
- end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
- done = true
- return a .. b.. c
- end)
- if not done then break end
- end
- str = str:gsub("[{}]", "")
- str = str:gsub("@","")
- if validate then
- for s in str:gmatch("[^,]+") do
- s = validate(s)
- if s then t[#t+1] = s end
- end
- else
- for s in str:gmatch("[^,]+") do
- t[#t+1] = s
- end
- end
- return t
-end
-
-function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
- local instance = input.instance
- -- a previous version fed back into pathlist
- local newlist, ok = { }, false
- for _,v in ipairs(pathlist) do
- if v:find("[{}]") then
- ok = true
- break
- end
- end
- if ok then
- for _, v in ipairs(pathlist) do
- input.aux.splitpathexpr(v, newlist, function(s)
- s = file.collapse_path(s)
- return s ~= "" and not s:find(instance.dummy_path_expr) and s
- end)
- end
- else
- for _,v in ipairs(pathlist) do
- for vv in string.gmatch(v..',',"(.-),") do
- vv = file.collapse_path(v)
- if vv ~= "" then newlist[#newlist+1] = vv end
- end
- end
- end
- return newlist
-end
-
-input.is_readable = { }
-
-function input.aux.is_readable(readable, name)
- if input.trace > 2 then
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
if readable then
- input.logger("+ readable: %s",name)
+ logs.report("fileio","+ readable: %s",name)
else
- input.logger("- readable: %s", name)
+ logs.report("fileio","- readable: %s", name)
end
end
return readable
end
-function input.is_readable.file(name)
- return input.aux.is_readable(lfs.isfile(name), name)
-end
-
-input.is_readable.tex = input.is_readable.file
+resolvers.isreadable.tex = resolvers.isreadable.file
-- name
-- name/name
-function input.aux.collect_files(names)
- local instance = input.instance
+local function collect_files(names)
local filelist = { }
- for _, fname in pairs(names) do
- if fname then
- if input.trace > 2 then
- input.logger("? blobpath asked: %s",fname)
- end
- local bname = file.basename(fname)
- local dname = file.dirname(fname)
- if dname == "" or dname:find("^%.") then
- dname = false
- else
- dname = "/" .. dname .. "$"
- end
- for _, hash in ipairs(instance.hashes) do
- local blobpath = hash.tag
- local files = blobpath and instance.files[blobpath]
- if files then
- if input.trace > 2 then
- input.logger('? blobpath do: %s (%s)',blobpath,bname)
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
end
- local blobfile = files[bname]
- if not blobfile then
- local rname = "remap:"..bname
- blobfile = files[rname]
- if blobfile then
- bname = files[rname]
- blobfile = files[bname]
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
end
- end
- if blobfile then
- if type(blobfile) == 'string' then
- if not dname or blobfile:find(dname) then
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
filelist[#filelist+1] = {
hash.type,
- file.join(blobpath,blobfile,bname), -- search
- input.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
}
end
- else
- for _, vv in pairs(blobfile) do
- if not dname or vv:find(dname) then
- filelist[#filelist+1] = {
- hash.type,
- file.join(blobpath,vv,bname), -- search
- input.concatinators[hash.type](blobpath,vv,bname) -- result
- }
- end
- end
end
end
- elseif input.trace > 1 then
- input.logger('! blobpath no: %s (%s)',blobpath,bname)
end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
end
end
end
@@ -6456,102 +7534,95 @@ function input.aux.collect_files(names)
end
end
-function input.suffix_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str][1]
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
else
return ""
end
end
-function input.suffixes_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str]
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
else
return {}
end
end
-do
-
- -- called about 700 times for an empty doc (font initializations etc)
- -- i need to weed the font files for redundant calls
-
- local letter = lpeg.R("az","AZ")
- local separator = lpeg.P("://")
-
- local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator
- local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-
- -- ./name ../name /name c: ://
- function input.aux.qualified_path(filename)
- return qualified:match(filename)
- end
- function input.aux.rootbased_path(filename)
- return rootbased:match(filename)
- end
-
- function input.normalize_name(original)
- return original
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
end
-
- input.normalize_name = file.collapse_path
-
end
-function input.aux.register_in_trees(name)
- if not name:find("^%.") then
- local instance = input.instance
- instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
end
+ return (fakepaths[name] == 1)
end
--- split the next one up, better for jit
-
-function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
- local instance = input.instance
- local result = { }
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
local stamp = nil
- filename = input.normalize_name(filename) -- elsewhere
- filename = file.collapse_path(filename:gsub("\\","/")) -- elsewhere
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
-- speed up / beware: format problem
if instance.remember then
stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
if instance.found[stamp] then
- if input.trace > 0 then
- input.logger('! remembered: %s',filename)
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
end
return instance.found[stamp]
end
end
- if filename:find('%*') then
- if input.trace > 0 then
- input.logger('! wildcard: %s', filename)
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
end
- result = input.find_wildcard_files(filename)
- elseif input.aux.qualified_path(filename) then
- if input.is_readable.file(filename) then
- if input.trace > 0 then
- input.logger('! qualified: %s', filename)
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
end
result = { filename }
else
- local forcedname, ok = "", false
- if file.extname(filename) == "" then
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
if instance.format == "" then
forcedname = filename .. ".tex"
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing standard filetype: tex')
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
end
result, ok = { forcedname }, true
end
else
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
forcedname = filename .. "." .. s
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing format filetype: %s', s)
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
end
result, ok = { forcedname }, true
break
@@ -6559,8 +7630,49 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
end
end
- if not ok and input.trace > 0 then
- input.logger('? qualified: %s', filename)
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
end
end
else
@@ -6577,45 +7689,47 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
if ext == "" then
local forcedname = filename .. '.tex'
wantedfiles[#wantedfiles+1] = forcedname
- filetype = input.format_of_suffix(forcedname)
- if input.trace > 0 then
- input.logger('! forcing filetype: %s',filetype)
- end
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
else
- filetype = input.format_of_suffix(filename)
- if input.trace > 0 then
- input.logger('! using suffix based filetype: %s',filetype)
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
end
end
else
if ext == "" then
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
wantedfiles[#wantedfiles+1] = filename .. "." .. s
end
end
filetype = instance.format
- if input.trace > 0 then
- input.logger('! using given filetype: %s',filetype)
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
end
end
- local typespec = input.variable_of_format(filetype)
- local pathlist = input.expanded_path_list(typespec)
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
if not pathlist or #pathlist == 0 then
-- no pathlist, access check only / todo == wildcard
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- input.logger('? filetype: %s',filetype or '?')
- input.logger('? wanted files: %s',concat(wantedfiles," | "))
- end
- for _, fname in pairs(wantedfiles) do
- if fname and input.is_readable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
filename, done = fname, true
result[#result+1] = file.join('.',fname)
break
end
end
-- this is actually 'other text files' or 'any' or 'whatever'
- local filelist = input.aux.collect_files(wantedfiles)
+ local filelist = collect_files(wantedfiles)
local fl = filelist and filelist[1]
if fl then
filename = fl[3]
@@ -6624,56 +7738,53 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
else
-- list search
- local filelist = input.aux.collect_files(wantedfiles)
+ local filelist = collect_files(wantedfiles)
local doscan, recurse
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- -- if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
- -- if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
end
-- a bit messy ... esp the doscan setting here
- for _, path in pairs(pathlist) do
- if path:find("^!!") then doscan = false else doscan = true end
- if path:find("//$") then recurse = true else recurse = false end
- local pathname = path:gsub("^!+", '')
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
done = false
-- using file list
if filelist and not (done and not instance.allresults) and recurse then
-- compare list entries with permitted pattern
- pathname = pathname:gsub("([%-%.])","%%%1") -- this also influences
- pathname = pathname:gsub("/+$", '/.*') -- later usage of pathname
- pathname = pathname:gsub("//", '/.-/') -- not ok for /// but harmless
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
local expr = "^" .. pathname
- -- input.debug('?',expr)
- for _, fl in ipairs(filelist) do
+ for k=1,#filelist do
+ local fl = filelist[k]
local f = fl[2]
- if f:find(expr) then
- -- input.debug('T',' '..f)
- if input.trace > 2 then
- input.logger('= found in hash: %s',f)
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
end
--- todo, test for readable
result[#result+1] = fl[3]
- input.aux.register_in_trees(f) -- for tracing used files
+ resolvers.register_in_trees(f) -- for tracing used files
done = true
if not instance.allresults then break end
- else
- -- input.debug('F',' '..f)
end
end
end
if not done and doscan then
-- check if on disk / unchecked / does not work at all / also zips
- if input.method_is_file(pathname) then -- ?
- local pname = pathname:gsub("%.%*$",'')
- if not pname:find("%*") then
- local ppname = pname:gsub("/+$","")
- if input.aux.can_be_dir(ppname) then
- for _, w in pairs(wantedfiles) do
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
local fname = file.join(ppname,w)
- if input.is_readable.file(fname) then
- if input.trace > 2 then
- input.logger('= found by scanning: %s',fname)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
end
result[#result+1] = fname
done = true
@@ -6693,8 +7804,8 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
end
end
end
- for k,v in pairs(result) do
- result[k] = file.collapse_path(v)
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
end
if instance.remember then
instance.found[stamp] = result
@@ -6702,38 +7813,12 @@ function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
return result
end
-input.aux._find_file_ = input.aux.find_file -- frozen variant
+if not resolvers.concatinators then resolvers.concatinators = { } end
-function input.aux.find_file(filename) -- maybe make a lowres cache too
- local result = input.aux._find_file_(filename)
- if #result == 0 then
- local lowered = filename:lower()
- if filename ~= lowered then
- return input.aux._find_file_(lowered)
- end
- end
- return result
-end
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
-function input.aux.can_be_dir(name)
- local instance = input.instance
- if not instance.fakepaths[name] then
- if lfs.isdir(name) then
- instance.fakepaths[name] = 1 -- directory
- else
- instance.fakepaths[name] = 2 -- no directory
- end
- end
- return (instance.fakepaths[name] == 1)
-end
-
-if not input.concatinators then input.concatinators = { } end
-
-input.concatinators.tex = file.join
-input.concatinators.file = input.concatinators.tex
-
-function input.find_files(filename,filetype,mustexist)
- local instance = input.instance
+function resolvers.find_files(filename,filetype,mustexist)
if type(mustexist) == boolean then
-- all set
elseif type(filetype) == 'boolean' then
@@ -6742,19 +7827,26 @@ function input.find_files(filename,filetype,mustexist)
filetype, mustexist = nil, false
end
instance.format = filetype or ''
- local t = input.aux.find_file(filename,true)
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
instance.format = ''
- return t
+ return result
end
-function input.find_file(filename,filetype,mustexist)
- return (input.find_files(filename,filetype,mustexist)[1] or "")
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
end
-function input.find_given_files(filename)
- local instance = input.instance
+function resolvers.find_given_files(filename)
local bname, result = file.basename(filename), { }
- for k, hash in ipairs(instance.hashes) do
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
local files = instance.files[hash.tag]
local blist = files[bname]
if not blist then
@@ -6767,11 +7859,12 @@ function input.find_given_files(filename)
end
if blist then
if type(blist) == 'string' then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
if not instance.allresults then break end
else
- for kk,vv in pairs(blist) do
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
if not instance.allresults then break end
end
end
@@ -6780,61 +7873,68 @@ function input.find_given_files(filename)
return result
end
-function input.find_given_file(filename)
- return (input.find_given_files(filename)[1] or "")
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
end
-function input.find_wildcard_files(filename) -- todo: remap:
- local instance = input.instance
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
local result = { }
local bname, dname = file.basename(filename), file.dirname(filename)
- local path = dname:gsub("^*/","")
- path = path:gsub("*",".*")
- path = path:gsub("-","%%-")
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
if dname == "" then
path = ".*"
end
local name = bname
- name = name:gsub("*",".*")
- name = name:gsub("-","%%-")
- path = path:lower()
- name = name:lower()
- local function doit(blist,bname,hash,allresults)
- local done = false
- if blist then
- if type(blist) == 'string' then
- -- make function and share code
- if (blist:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
- done = true
- end
- else
- for kk,vv in pairs(blist) do
- if (vv:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
- done = true
- if not allresults then break end
- end
- end
- end
- end
- return done
- end
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
local files, allresults, done = instance.files, instance.allresults, false
- if name:find("%*") then
- for k, hash in ipairs(instance.hashes) do
- for kk, hh in pairs(files[hash.tag]) do
- if not kk:find("^remap:") then
- if (kk:lower()):find(name) then
- if doit(hh,kk,hash,allresults) then done = true end
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
if done and not allresults then break end
end
end
end
end
else
- for k, hash in ipairs(instance.hashes) do
- if doit(files[hash.tag][bname],bname,hash,allresults) then done = true end
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
if done and not allresults then break end
end
end
@@ -6843,67 +7943,49 @@ function input.find_wildcard_files(filename) -- todo: remap:
return result
end
-function input.find_wildcard_file(filename)
- return (input.find_wildcard_files(filename)[1] or "")
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
end
-- main user functions
-function input.save_used_files_in_trees(filename,jobname)
- local instance = input.instance
- if not filename then filename = 'luatex.jlg' end
- local f = io.open(filename,'w')
- if f then
- f:write("<?xml version='1.0' standalone='yes'?>\n")
- f:write("<rl:job>\n")
- if jobname then
- f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
- end
- f:write("\t<rl:files>\n")
- for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
- f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
- end
- f:write("\t</rl:files>\n")
- f:write("</rl:usedfiles>\n")
- f:close()
- end
-end
-
-function input.automount()
+function resolvers.automount()
-- implemented later
end
-function input.load()
- input.starttiming(input.instance)
- input.resetconfig()
- input.identify_cnf()
- input.load_lua()
- input.expand_variables()
- input.load_cnf()
- input.expand_variables()
- input.load_hash()
- input.automount()
- input.stoptiming(input.instance)
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
end
-function input.for_files(command, files, filetype, mustexist)
+function resolvers.for_files(command, files, filetype, mustexist)
if files and #files > 0 then
local function report(str)
- if input.verbose then
- input.report(str) -- has already verbose
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
else
print(str)
end
end
- if input.verbose then
+ if trace_verbose then
report('')
end
- for _, file in pairs(files) do
+ for _, file in ipairs(files) do
local result = command(file,filetype,mustexist)
if type(result) == 'string' then
report(result)
else
- for _,v in pairs(result) do
+ for _,v in ipairs(result) do
report(v)
end
end
@@ -6913,19 +7995,19 @@ end
-- strtab
-input.var_value = input.variable -- output the value of variable $STRING.
-input.expand_var = input.expansion -- output variable expansion of STRING.
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
-function input.show_path(str) -- output search path for file type NAME
- return file.join_path(input.expanded_path_list(input.format_of_var(str)))
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
end
--- input.find_file(filename)
--- input.find_file(filename, filetype, mustexist)
--- input.find_file(filename, mustexist)
--- input.find_file(filename, filetype)
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
-function input.aux.register_file(files, name, path)
+function resolvers.register_file(files, name, path)
if files[name] then
if type(files[name]) == 'string' then
files[name] = { files[name], path }
@@ -6937,170 +8019,77 @@ function input.aux.register_file(files, name, path)
end
end
-if not input.finders then input.finders = { } end
-if not input.openers then input.openers = { } end
-if not input.loaders then input.loaders = { } end
-
-input.finders.notfound = { nil }
-input.openers.notfound = { nil }
-input.loaders.notfound = { false, nil, 0 }
-
-function input.splitmethod(filename)
+function resolvers.splitmethod(filename)
if not filename then
return { } -- safeguard
elseif type(filename) == "table" then
return filename -- already split
- elseif not filename:find("://") then
+ elseif not find(filename,"://") then
return { scheme="file", path = filename, original=filename } -- quick hack
else
return url.hashed(filename)
end
end
-function input.method_is_file(filename)
- return input.splitmethod(filename).scheme == 'file'
-end
-
function table.sequenced(t,sep) -- temp here
local s = { }
- for k, v in pairs(t) do
+ for k, v in pairs(t) do -- pairs?
s[#s+1] = k .. "=" .. v
end
return concat(s, sep or " | ")
end
-function input.methodhandler(what, filename, filetype) -- ...
- local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
local scheme = specification.scheme
- if input[what][scheme] then
- if input.trace > 0 then
- input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
end
- return input[what][scheme](filename,filetype) -- todo: specification
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
else
- return input[what].tex(filename,filetype) -- todo: specification
+ return resolvers[what].tex(filename,filetype) -- todo: specification
end
end
--- also inside next test?
-
-function input.findtexfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.opentexfile(filename)
- return input.methodhandler('openers',input.normalize_name(filename))
-end
-
-function input.findbinfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.openbinfile(filename)
- return input.methodhandler('loaders',input.normalize_name(filename))
-end
-
-function input.loadbinfile(filename, filetype)
- local fname = input.findbinfile(input.normalize_name(filename), filetype)
- if fname and fname ~= "" then
- return input.openbinfile(fname)
- else
- return unpack(input.loaders.notfound)
- end
-end
-
-function input.texdatablob(filename, filetype)
- local ok, data, size = input.loadbinfile(filename, filetype)
- return data or ""
-end
-
-input.loadtexfile = input.texdatablob
-
-function input.openfile(filename)
- local fullname = input.findtexfile(filename)
- if fullname and (fullname ~= "") then
- return input.opentexfile(fullname)
- else
- return nil
- end
-end
-
-function input.logmode()
- return (os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"):lower()
-end
-
--- this is a prelude to engine/progname specific configuration files
--- in which case we can omit files meant for other programs and
--- packages
-
---- ctx
-
--- maybe texinputs + font paths
--- maybe positive selection tex/context fonts/tfm|afm|vf|opentype|type1|map|enc
-
-input.validators = { }
-input.validators.visibility = { }
-
-function input.validators.visibility.default(path, name)
- return true
-end
-
-function input.validators.visibility.context(path, name)
- path = path[1] or path -- some day a loop
- return not (
- path:find("latex") or
--- path:find("doc") or
- path:find("tex4ht") or
- path:find("source") or
--- path:find("config") or
--- path:find("metafont") or
- path:find("lists$") or
- name:find("%.tpm$") or
- name:find("%.bak$")
- )
-end
-
--- todo: describe which functions are public (maybe input.private. ... )
-
--- beware: i need to check where we still need a / on windows:
-
-function input.clean_path(str)
+function resolvers.clean_path(str)
if str then
- str = str:gsub("\\","/")
- str = str:gsub("^!+","")
- str = str:gsub("^~",input.homedir)
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
return str
else
return nil
end
end
-function input.do_with_path(name,func)
- for _, v in pairs(input.expanded_path_list(name)) do
- func("^"..input.clean_path(v))
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
end
end
-function input.do_with_var(name,func)
- func(input.aux.expanded_var(name))
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
end
-function input.with_files(pattern,handle)
- local instance = input.instance
+function resolvers.with_files(pattern,handle)
for _, hash in ipairs(instance.hashes) do
local blobpath = hash.tag
local blobtype = hash.type
if blobpath then
local files = instance.files[blobpath]
if files then
- for k,v in pairs(files) do
- if k:find("^remap:") then
+ for k,v in next, files do
+ if find(k,"^remap:") then
k = files[k]
v = files[k] -- chained
end
- if k:find(pattern) then
+ if find(k,pattern) then
if type(v) == "string" then
handle(blobtype,blobpath,v,k)
else
- for _,vv in pairs(v) do
+ for _,vv in pairs(v) do -- ipairs?
handle(blobtype,blobpath,vv,k)
end
end
@@ -7111,122 +8100,32 @@ function input.with_files(pattern,handle)
end
end
-function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
- local scriptpath = "scripts/context/lua"
- newname = file.addsuffix(newname,"lua")
- local oldscript = input.clean_path(oldname)
- input.report("to be replaced old script %s", oldscript)
- local newscripts = input.find_files(newname) or { }
- if #newscripts == 0 then
- input.report("unable to locate new script")
- else
- for _, newscript in ipairs(newscripts) do
- newscript = input.clean_path(newscript)
- input.report("checking new script %s", newscript)
- if oldscript == newscript then
- input.report("old and new script are the same")
- elseif not newscript:find(scriptpath) then
- input.report("new script should come from %s",scriptpath)
- elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
- input.report("invalid new script name")
- else
- local newdata = io.loaddata(newscript)
- if newdata then
- input.report("old script content replaced by new content")
- io.savedata(oldscript,newdata)
- break
- else
- input.report("unable to load new script")
- end
- end
- end
- end
-end
-
-
---~ print(table.serialize(input.aux.splitpathexpr("/usr/share/texmf-{texlive,tetex}", {})))
-
--- command line resolver:
-
---~ print(input.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
-
-do
-
- local resolvers = { }
-
- resolvers.environment = function(str)
- return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
- end
- resolvers.relative = function(str,n)
- if io.exists(str) then
- -- nothing
- elseif io.exists("./" .. str) then
- str = "./" .. str
- else
- local p = "../"
- for i=1,n or 2 do
- if io.exists(p .. str) then
- str = p .. str
- break
- else
- p = p .. "../"
- end
- end
- end
- return input.clean_path(str)
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
end
- resolvers.locate = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path((fullname ~= "" and fullname) or str)
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
end
- resolvers.filename = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
- end
- resolvers.pathname = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
- end
-
- resolvers.env = resolvers.environment
- resolvers.rel = resolvers.relative
- resolvers.loc = resolvers.locate
- resolvers.kpse = resolvers.locate
- resolvers.full = resolvers.locate
- resolvers.file = resolvers.filename
- resolvers.path = resolvers.pathname
-
- local function resolve(str)
- if type(str) == "table" then
- for k, v in pairs(str) do
- str[k] = resolve(v) or v
- end
- elseif str and str ~= "" then
- str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
- if resolvers[method] then
- return resolvers[method](target)
- else
- return method .. ":" .. target
- end
- end)
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
end
- return str
end
-
- if os.uname then
- for k, v in pairs(os.uname()) do
- if not resolvers[k] then
- resolvers[k] = function() return v end
- end
- end
- end
-
- input.resolve = resolve
-
+ return nil, nil
end
-function input.boolean_variable(str,default)
- local b = input.expansion(str)
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
if b == "" then
return default
else
@@ -7235,165 +8134,20 @@ function input.boolean_variable(str,default)
end
end
+texconfig.kpse_init = false
-if not modules then modules = { } end modules ['luat-log'] = {
- version = 1.001,
- comment = "companion to luat-lib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
-
--- input.logger -> special tracing, driven by log level (only input)
--- input.report -> goes to terminal, depends on verbose, has banner
--- logs.report -> module specific tracing and reporting, no banner but class
-
-
-input = input or { }
-logs = logs or { }
-
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
-
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4
-}
-
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
-}
-
-logs.callbacks = {
- 'start_page_number',
- 'stop_page_number',
- 'report_output_pages',
- 'report_output_log'
-}
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
-logs.tracers = {
-}
+-- for a while
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
+input = resolvers
-logs.level = 0
-local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+end -- of closure
-if texlua then
- write_nl = print
- write = io.write
-end
-
-function logs.xml.report(category,fmt,...) -- new
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
-end
-function logs.xml.line(fmt,...) -- new
- write_nl(format("<r>%s</r>",format(fmt,...)))
-end
-
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
-
-function logs.tex.report(category,fmt,...) -- new
- -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
- write_nl(category .. " | " .. format(fmt,...))
-end
-function logs.tex.line(fmt,...) -- new
- write_nl(format(fmt,...))
-end
-
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
-end
-
-function logs.set_method(method)
- for _, v in pairs(logs.functions) do
- logs[v] = logs[method][v] or function() end
- end
- if callback and input[method] then
- for _, cb in pairs(logs.callbacks) do
- callback.register(cb, input[method][cb])
- end
- end
-end
+do -- create closure to overcome 200 locals limit
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
-end
-
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
-end
-
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
-end
-
-function logs.xml.report_output_log()
-end
-
-function input.logger(...) -- assumes test for input.trace > n
- if input.trace > 0 then
- logs.report(...)
- end
-end
-
-function input.report(fmt,...)
- if input.verbose then
- logs.report(input.banner or "report",format(fmt,...))
- end
-end
-
-function input.reportlines(str) -- todo: <lines></lines>
- for line in str:gmatch("(.-)[\n\r]") do
- logs.report(input.banner or "report",line)
- end
-end
-
-input.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
-
-function input.help(banner,message)
- if not input.verbose then
- input.verbose = true
- -- input.report(banner,"\n")
- end
- input.report(banner,"\n")
- input.report("")
- input.reportlines(message)
- if input.moreinfo and input.moreinfo ~= "" then
- input.report("")
- input.reportlines(input.moreinfo)
- end
-end
-
-logs.set_level('error')
-logs.set_method('tex')
-
-
-if not modules then modules = { } end modules ['luat-tmp'] = {
+if not modules then modules = { } end modules ['data-tmp'] = {
version = 1.001,
comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -7417,17 +8171,16 @@ being written at the same time is small. We also need to extend
luatools with a recache feature.</p>
--ldx]]--
-local format = string.format
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
caches = caches or { }
-dir = dir or { }
-texmf = texmf or { }
caches.path = caches.path or nil
caches.base = caches.base or "luatex-cache"
caches.more = caches.more or "context"
caches.direct = false -- true is faster but may need huge amounts of memory
-caches.trace = false
caches.tree = false
caches.paths = caches.paths or nil
caches.force = false
@@ -7437,13 +8190,14 @@ function caches.temp()
local cachepath = nil
local function check(list,isenv)
if not cachepath then
- for _, v in ipairs(list) do
+ for k=1,#list do
+ local v = list[k]
cachepath = (isenv and (os.env[v] or "")) or v or ""
if cachepath == "" then
-- next
else
- cachepath = input.clean_path(cachepath)
- if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
break
elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
dir.mkdirs(cachepath)
@@ -7456,7 +8210,7 @@ function caches.temp()
end
end
end
- check(input.clean_path_list("TEXMFCACHE") or { })
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
check(caches.defaults,true)
if not cachepath then
print("\nfatal error: there is no valid (writable) cache path defined\n")
@@ -7465,7 +8219,7 @@ function caches.temp()
print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
os.exit()
end
- cachepath = input.normalize_name(cachepath)
+ cachepath = file.collapse_path(cachepath)
function caches.temp()
return cachepath
end
@@ -7473,24 +8227,13 @@ function caches.temp()
end
function caches.configpath()
- return table.concat(input.instance.cnffiles,";")
+ return table.concat(resolvers.instance.cnffiles,";")
end
function caches.hashed(tree)
- return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
end
---~ tracing:
-
---~ function caches.hashed(tree)
---~ tree = (tree:lower()):gsub("[\\\/]+","/")
---~ local hash = md5.hex(tree)
---~ if input.verbose then -- temp message
---~ input.report("hashing %s => %s",tree,hash)
---~ end
---~ return hash
---~ end
-
function caches.treehash()
local tree = caches.configpath()
if not tree or tree == "" then
@@ -7505,21 +8248,19 @@ function caches.setpath(...)
if not caches.path then
caches.path = caches.temp()
end
- caches.path = input.clean_path(caches.path) -- to be sure
- if lfs then
- caches.tree = caches.tree or caches.treehash()
- if caches.tree then
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
- else
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
- end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
end
end
if not caches.path then
caches.path = '.'
end
- caches.path = input.clean_path(caches.path)
- if lfs and not table.is_empty({...}) then
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
local pth = dir.mkdirs(caches.path,...)
return pth
end
@@ -7547,9 +8288,14 @@ function caches.loaddata(path,name)
end
end
-function caches.is_writable(filepath,filename)
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
local tmaname, tmcname = caches.setluanames(filepath,filename)
- return file.is_writable(tmaname)
+ return file.iswritable(tmaname)
end
function caches.savedata(filepath,filename,data,raw)
@@ -7559,23 +8305,177 @@ function caches.savedata(filepath,filename,data,raw)
reduce, simplify = false, false
end
if caches.direct then
- file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
else
- table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
end
- local cleanup = input.boolean_variable("PURGECACHE", false)
- local strip = input.boolean_variable("LUACSTRIP", true)
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
utils.lua.compile(tmaname, tmcname, cleanup, strip)
end
-- here we use the cache for format loading (texconfig.[formatname|jobname])
--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
-if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
- texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-res'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
+
+local upper, lower, gsub = string.upper, string.lower, string.gsub
+
+local prefixes = { }
+
+prefixes.environment = function(str)
+ return resolvers.clean_path(os.getenv(str) or os.getenv(upper(str)) or os.getenv(lower(str)) or "")
+end
+
+prefixes.relative = function(str,n)
+ if io.exists(str) then
+ -- nothing
+ elseif io.exists("./" .. str) then
+ str = "./" .. str
+ else
+ local p = "../"
+ for i=1,n or 2 do
+ if io.exists(p .. str) then
+ str = p .. str
+ break
+ else
+ p = p .. "../"
+ end
+ end
+ end
+ return resolvers.clean_path(str)
+end
+
+prefixes.locate = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path((fullname ~= "" and fullname) or str)
+end
+
+prefixes.filename = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.basename((fullname ~= "" and fullname) or str))
+end
+
+prefixes.pathname = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.dirname((fullname ~= "" and fullname) or str))
end
+prefixes.env = prefixes.environment
+prefixes.rel = prefixes.relative
+prefixes.loc = prefixes.locate
+prefixes.kpse = prefixes.locate
+prefixes.full = prefixes.locate
+prefixes.file = prefixes.filename
+prefixes.path = prefixes.pathname
+
+local function _resolve_(method,target)
+ if prefixes[method] then
+ return prefixes[method](target)
+ else
+ return method .. ":" .. target
+ end
+end
+
+local function resolve(str)
+ if type(str) == "table" then
+ for k, v in pairs(str) do -- ipairs
+ str[k] = resolve(v) or v
+ end
+ elseif str and str ~= "" then
+ str = gsub(str,"([a-z]+):([^ \"\']*)",_resolve_)
+ end
+ return str
+end
+
+resolvers.resolve = resolve
+
+if os.uname then
+
+ for k, v in pairs(os.uname()) do
+ if not prefixes[k] then
+ prefixes[k] = function() return v end
+ end
+ end
+
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
--[[ldx--
<p>Once we found ourselves defining similar cache constructs
several times, containers were introduced. Containers are used
@@ -7589,126 +8489,145 @@ table structures without bothering about the disk cache.</p>
<p>Examples of usage can be found in the font related code.</p>
--ldx]]--
-containers = { }
-containers.trace = false
+containers = containers or { }
-do -- local report
+containers.usecache = true
- local function report(container,tag,name)
- if caches.trace or containers.trace or container.trace then
- logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
- end
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
end
+end
- local allocated = { }
+local allocated = { }
- -- tracing
+-- tracing
- function containers.define(category, subcategory, version, enabled)
- return function()
- if category and subcategory then
- local c = allocated[category]
- if not c then
- c = { }
- allocated[category] = c
- end
- local s = c[subcategory]
- if not s then
- s = {
- category = category,
- subcategory = subcategory,
- storage = { },
- enabled = enabled,
- version = version or 1.000,
- trace = false,
- path = caches.setpath(category,subcategory),
- }
- c[subcategory] = s
- end
- return s
- else
- return nil
- end
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
end
end
+end
- function containers.is_usable(container, name)
- return container.enabled and caches.is_writable(container.path, name)
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
end
+end
- function containers.is_valid(container, name)
- if name and name ~= "" then
- local storage = container.storage[name]
- return storage and not table.is_empty(storage) and storage.cache_version == container.version
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
else
- return false
+ container.storage[name] = nil
end
end
-
- function containers.read(container,name)
- if container.enabled and not container.storage[name] then
- container.storage[name] = caches.loaddata(container.path,name)
- if containers.is_valid(container,name) then
- report(container,"loaded",name)
- else
- container.storage[name] = nil
- end
- end
- if container.storage[name] then
- report(container,"reusing",name)
- end
- return container.storage[name]
+ if container.storage[name] then
+ report(container,"reusing",name)
end
+ return container.storage[name]
+end
- function containers.write(container, name, data)
- if data then
- data.cache_version = container.version
- if container.enabled then
- local unique, shared = data.unique, data.shared
- data.unique, data.shared = nil, nil
- caches.savedata(container.path, name, data)
- report(container,"saved",name)
- data.unique, data.shared = unique, shared
- end
- report(container,"stored",name)
- container.storage[name] = data
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
end
- return data
+ report(container,"stored",name)
+ container.storage[name] = data
end
+ return data
+end
- function containers.content(container,name)
- return container.storage[name]
- end
+function containers.content(container,name)
+ return container.storage[name]
+end
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
end
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
-- since we want to use the cache instead of the tree, we will now
-- reimplement the saver.
-local save_data = input.aux.save_data
-local load_data = input.aux.load_data
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
-input.cachepath = nil -- public, for tracing
-input.usecache = true -- public, for tracing
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
-function input.aux.save_data(dataname, check)
- save_data(dataname, check, function(cachename,dataname)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(cachename))
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
else
return file.join(cachename,dataname)
end
end)
end
-function input.aux.load_data(pathname,dataname,filename)
+function resolvers.load_data(pathname,dataname,filename)
load_data(pathname,dataname,filename,function(dataname,filename)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(pathname))
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
else
if not filename or (filename == "") then
filename = dataname
@@ -7720,15 +8639,15 @@ end
-- we will make a better format, maybe something xml or just text or lua
-input.automounted = input.automounted or { }
+resolvers.automounted = resolvers.automounted or { }
-function input.automount(usecache)
- local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT'))
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
if table.is_empty(mountpaths) and usecache then
mountpaths = { caches.setpath("mount") }
end
if not table.is_empty(mountpaths) then
- input.starttiming(input.instance)
+ statistics.starttiming(resolvers.instance)
for k, root in pairs(mountpaths) do
local f = io.open(root.."/url.tmi")
if f then
@@ -7737,98 +8656,72 @@ function input.automount(usecache)
if line:find("^[%%#%-]") then -- or %W
-- skip
elseif line:find("^zip://") then
- input.report("mounting %s",line)
- table.insert(input.automounted,line)
- input.usezipfile(line)
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
end
end
end
f:close()
end
end
- input.stoptiming(input.instance)
+ statistics.stoptiming(resolvers.instance)
end
end
--- store info in format
+-- status info
-input.storage = { }
-input.storage.data = { }
-input.storage.min = 0 -- 500
-input.storage.max = input.storage.min - 1
-input.storage.trace = false -- true
-input.storage.done = input.storage.done or 0
-input.storage.evaluators = { }
--- (evaluate,message,names)
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
-function input.storage.register(...)
- input.storage.data[#input.storage.data+1] = { ... }
-end
+-- experiment (code will move)
-function input.storage.evaluate(name)
- input.storage.evaluators[#input.storage.evaluators+1] = name
-end
-
-function input.storage.finalize() -- we can prepend the string with "evaluate:"
- for _, t in ipairs(input.storage.evaluators) do
- for i, v in pairs(t) do
- if type(v) == "string" then
- t[i] = loadstring(v)()
- elseif type(v) == "table" then
- for _, vv in pairs(v) do
- if type(vv) == "string" then
- t[i] = loadstring(vv)()
- end
- end
- end
- end
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
end
end
-function input.storage.dump()
- for name, data in ipairs(input.storage.data) do
- local evaluate, message, original, target = data[1], data[2], data[3] ,data[4]
- local name, initialize, finalize, code = nil, "", "", ""
- for str in target:gmatch("([^%.]+)") do
- if name then
- name = name .. "." .. str
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
else
- name = str
+ return "invalid status file"
end
- initialize = format("%s %s = %s or {} ", initialize, name, name)
- end
- if evaluate then
- finalize = "input.storage.evaluate(" .. name .. ")"
- end
- input.storage.max = input.storage.max + 1
- if input.storage.trace then
- logs.report('storage','saving %s in slot %s',message,input.storage.max)
- code =
- initialize ..
- format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
- table.serialize(original,name) ..
- finalize
else
- code = initialize .. table.serialize(original,name) .. finalize
+ return "missing status file"
end
- lua.bytecode[input.storage.max] = loadstring(code)
end
+ return true
end
--- we also need to count at generation time (nicer for message)
-if lua.bytecode then -- from 0 upwards
- local i = input.storage.min
- while lua.bytecode[i] do
- lua.bytecode[i]()
- lua.bytecode[i] = nil
- i = i + 1
- end
- input.storage.done = i
-end
+end -- of closure
+do -- create closure to overcome 200 locals limit
-if not modules then modules = { } end modules ['luat-log'] = {
+if not modules then modules = { } end modules ['data-zip'] = {
version = 1.001,
comment = "companion to luat-lib.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -7836,154 +8729,556 @@ if not modules then modules = { } end modules ['luat-log'] = {
license = "see context related readme files"
}
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
+local format, find = string.format, string.find
--- input.logger -> special tracing, driven by log level (only input)
--- input.report -> goes to terminal, depends on verbose, has banner
--- logs.report -> module specific tracing and reporting, no banner but class
+local trace_locating, trace_verbose = false, false
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trace_verbose = v end)
-input = input or { }
-logs = logs or { }
+zip = zip or { }
+zip.archives = zip.archives or { }
+zip.registeredfiles = zip.registeredfiles or { }
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4
-}
+local archives = zip.archives
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
-}
-
-logs.callbacks = {
- 'start_page_number',
- 'stop_page_number',
- 'report_output_pages',
- 'report_output_log'
-}
+-- zip:///oeps.zip?name=bla/bla.tex
+-- zip:///oeps.zip?tree=tex/texmf-local
-logs.tracers = {
-}
+local function validzip(str) -- todo: use url splitter
+ if not find(str,"^zip://") then
+ return "zip:///" .. str
+ else
+ return str
+ end
+end
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
+function zip.openarchive(name)
+ if not name or name == "" then
+ return nil
+ else
+ local arch = archives[name]
+ if not arch then
+ local full = resolvers.find_file(name) or ""
+ arch = (full ~= "" and zip.open(full)) or false
+ archives[name] = arch
+ end
+ return arch
+ end
+end
-logs.level = 0
+function zip.closearchive(name)
+ if not name or (name == "" and archives[name]) then
+ zip.close(archives[name])
+ archives[name] = nil
+ end
+end
-local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+-- zip:///texmf.zip?tree=/tex/texmf
+-- zip:///texmf.zip?tree=/tex/texmf-local
+-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
-if texlua then
- write_nl = print
- write = io.write
+function locators.zip(specification) -- where is this used? startup zips (untested)
+ specification = resolvers.splitmethod(specification)
+ local zipfile = specification.path
+ local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+ if trace_locating then
+ if zfile then
+ logs.report("fileio",'! zip locator, found: %s',specification.original)
+ else
+ logs.report("fileio",'? zip locator, not found: %s',specification.original)
+ end
+ end
end
-function logs.xml.report(category,fmt,...) -- new
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+function hashers.zip(tag,name)
+ if trace_verbose then
+ logs.report("fileio","loading zip file %s as %s",name,tag)
+ end
+ resolvers.usezipfile(format("%s?tree=%s",tag,name))
end
-function logs.xml.line(fmt,...) -- new
- write_nl(format("<r>%s</r>",format(fmt,...)))
+
+function concatinators.zip(tag,path,name)
+ if not path or path == "" then
+ return format('%s?name=%s',tag,name)
+ else
+ return format('%s?name=%s/%s',tag,path,name)
+ end
end
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+function resolvers.isreadable.zip(name)
+ return true
+end
-function logs.tex.report(category,fmt,...) -- new
- -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
- write_nl(category .. " | " .. format(fmt,...))
+function finders.zip(specification,filetype)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'! zip finder, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ dfile = zfile:close()
+ if trace_locating then
+ logs.report("fileio",'+ zip finder, name: %s',q.name)
+ end
+ return specification.original
+ end
+ elseif trace_locating then
+ logs.report("fileio",'? zip finder, path %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip finder, name: %s',filename)
+ end
+ return unpack(finders.notfound)
end
-function logs.tex.line(fmt,...) -- new
- write_nl(format(fmt,...))
+
+function openers.zip(specification)
+ local zipspecification = resolvers.splitmethod(specification)
+ if zipspecification.path then
+ local q = url.query(zipspecification.query)
+ if q.name then
+ local zfile = zip.openarchive(zipspecification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',zipspecification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_open(specification)
+ return openers.text_opener(specification,dfile,'zip')
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path %s',zipspecification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip opener, name: %s',filename)
+ end
+ return unpack(openers.notfound)
end
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
+function loaders.zip(specification)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio",'+ zip loader, name: %s',filename)
+ end
+ local s = dfile:read("*all")
+ dfile:close()
+ return true, s, #s
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path: %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip loader, name: %s',filename)
+ end
+ return unpack(openers.notfound)
end
-function logs.set_method(method)
- for _, v in pairs(logs.functions) do
- logs[v] = logs[method][v] or function() end
+-- zip:///somefile.zip
+-- zip:///somefile.zip?tree=texmf-local -> mount
+
+function resolvers.usezipfile(zipname)
+ zipname = validzip(zipname)
+ if trace_locating then
+ logs.report("fileio",'! zip use, file: %s',zipname)
end
- if callback and input[method] then
- for _, cb in pairs(logs.callbacks) do
- callback.register(cb, input[method][cb])
+ local specification = resolvers.splitmethod(zipname)
+ local zipfile = specification.path
+ if zipfile and not zip.registeredfiles[zipname] then
+ local tree = url.query(specification.query).tree or ""
+ if trace_locating then
+ logs.report("fileio",'! zip register, file: %s',zipname)
+ end
+ local z = zip.openarchive(zipfile)
+ if z then
+ local instance = resolvers.instance
+ if trace_locating then
+ logs.report("fileio","= zipfile, registering: %s",zipname)
+ end
+ statistics.starttiming(instance)
+ resolvers.prepend_hash('zip',zipname,zipfile)
+ resolvers.extend_texmf_var(zipname) -- resets hashes too
+ zip.registeredfiles[zipname] = z
+ instance.files[zipname] = resolvers.register_zip_file(z,tree or "")
+ statistics.stoptiming(instance)
+ elseif trace_locating then
+ logs.report("fileio","? zipfile, unknown: %s",zipname)
end
+ elseif trace_locating then
+ logs.report("fileio",'! zip register, no file: %s',zipname)
end
end
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
+function resolvers.register_zip_file(z,tree)
+ local files, filter = { }, ""
+ if tree == "" then
+ filter = "^(.+)/(.-)$"
+ else
+ filter = format("^%s/(.+)/(.-)$",tree)
+ end
+ if trace_locating then
+ logs.report("fileio",'= zip filter: %s',filter)
+ end
+ local register, n = resolvers.register_file, 0
+ for i in z:files() do
+ local path, name = i.filename:match(filter)
+ if path then
+ if name and name ~= '' then
+ register(files, name, path)
+ n = n + 1
+ else
+ -- directory
+ end
+ else
+ register(files, i.filename, '')
+ n = n + 1
+ end
+ end
+ logs.report("fileio",'= zip entries: %s',n)
+ return files
end
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-crl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+curl = curl or { }
+
+curl.cached = { }
+curl.cachepath = caches.definepath("curl")
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function curl.fetch(protocol, name)
+ local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-")
+-- cachename = cachename:gsub("[\\/]", io.fileseparator)
+ cachename = cachename:gsub("[\\]", "/") -- cleanup
+ if not curl.cached[name] then
+ if not io.exists(cachename) then
+ curl.cached[name] = cachename
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+ end
+ if io.exists(cachename) then
+ curl.cached[name] = cachename
+ else
+ curl.cached[name] = ""
+ end
+ end
+ return curl.cached[name]
end
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
+function finders.curl(protocol,filename)
+ local foundname = curl.fetch(protocol, filename)
+ return finders.generic(protocol,foundname,filetype)
end
-function logs.xml.report_output_log()
+function openers.curl(protocol,filename)
+ return openers.generic(protocol,filename)
end
-function input.logger(...) -- assumes test for input.trace > n
- if input.trace > 0 then
- logs.report(...)
- end
+function loaders.curl(protocol,filename)
+ return loaders.generic(protocol,filename)
end
-function input.report(fmt,...)
- if input.verbose then
- logs.report(input.banner or "report",format(fmt,...))
- end
+-- todo: metamethod
+
+function curl.install(protocol)
+ finders[protocol] = function (filename,filetype) return finders.curl(protocol,filename) end
+ openers[protocol] = function (filename) return openers.curl(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.curl(protocol,filename) end
end
-function input.reportlines(str) -- todo: <lines></lines>
- for line in str:gmatch("(.-)[\n\r]") do
- logs.report(input.banner or "report",line)
+curl.install('http')
+curl.install('https')
+curl.install('ftp')
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
end
end
-input.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- loads *.tmf files in minimal tree roots (to be optimized and documented)
+
+function resolvers.check_environment(tree)
+ logs.simpleline()
+ os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
+ os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+ os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
+ os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
+ logs.simpleline()
+ logs.simple("preset : TEXPATH => %s", os.getenv('TEXPATH'))
+ logs.simple("preset : TEXOS => %s", os.getenv('TEXOS'))
+ logs.simple("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
+ logs.simple("preset : TMP => %s", os.getenv('TMP'))
+ logs.simple('')
+end
-function input.help(banner,message)
- if not input.verbose then
- input.verbose = true
- -- input.report(banner,"\n")
+function resolvers.load_environment(name) -- todo: key=value as well as lua
+ local f = io.open(name)
+ if f then
+ for line in f:lines() do
+ if line:find("^[%%%#]") then
+ -- skip comment
+ else
+ local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ os.setenv(key,value)
+ elseif how == "?" or how == "??" then
+ os.setenv(key,os.getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if os.getenv(key) then
+ os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
+ else
+ os.setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if os.getenv(key) then
+ os.setenv(key,value .. io.pathseparator .. os.getenv(key))
+ else
+ os.setenv(key,value)
+ end
+ end
+ end
+ end
+ end
+ f:close()
end
- input.report(banner,"\n")
- input.report("")
- input.reportlines(message)
- if input.moreinfo and input.moreinfo ~= "" then
- input.report("")
- input.reportlines(input.moreinfo)
+end
+
+function resolvers.load_tree(tree)
+ if tree and tree ~= "" then
+ local setuptex = 'setuptex.tmf'
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
+ setuptex = tree .. "/" .. setuptex
+ else
+ setuptex = tree
+ end
+ if io.exists(setuptex) then
+ resolvers.check_environment(tree)
+ resolvers.load_environment(setuptex)
+ end
end
end
-logs.set_level('error')
-logs.set_method('tex')
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
if not modules then modules = { } end modules ['luat-sta'] = {
version = 1.001,
@@ -7992,6 +9287,8 @@ if not modules then modules = { } end modules ['luat-sta'] = {
license = "see context related readme files"
}
+-- this code is used in the updater
+
states = states or { }
states.data = states.data or { }
states.hash = states.hash or { }
@@ -8018,27 +9315,32 @@ end
function states.set_by_tag(tag,key,value,default,persistent)
local d, h = states.data[tag], states.hash[tag]
if d then
- local dkey, hkey = key, key
- local pre, post = key:match("(.+)%.([^%.]+)$")
- if pre and post then
- for k in pre:gmatch("[^%.]+") do
- local dk = d[k]
- if not dk then
- dk = { }
- d[k] = dk
+ if type(d) == "table" then
+ local dkey, hkey = key, key
+ local pre, post = key:match("(.+)%.([^%.]+)$")
+ if pre and post then
+ for k in pre:gmatch("[^%.]+") do
+ local dk = d[k]
+ if not dk then
+ dk = { }
+ d[k] = dk
+ end
+ d = dk
end
- d = dk
+ dkey, hkey = post, key
end
- dkey, hkey = post, key
- end
- if type(value) == nil then
- value = value or default
- elseif persistent then
- value = value or d[dkey] or default
- else
- value = value or default
+ if type(value) == nil then
+ value = value or default
+ elseif persistent then
+ value = value or d[dkey] or default
+ else
+ value = value or default
+ end
+ d[dkey], h[hkey] = value, value
+ elseif type(d) == "string" then
+ -- weird
+ states.data[tag], states.hash[tag] = value, value
end
- d[dkey], h[hkey] = value, value
end
end
@@ -8158,7 +9460,6 @@ end
--~ },
--~ }
-
--~ states.save("teststate", "update")
--~ states.load("teststate", "update")
@@ -8169,6 +9470,8 @@ end
--~ states.load("teststate", "update")
--~ print(states.get_by_tag("update","rsync.server","unknown"))
+
+end -- of closure
-- end library merge
own = { } -- not local
@@ -8178,27 +9481,43 @@ own.libs = { -- todo: check which ones are really needed
'l-lpeg.lua',
'l-table.lua',
'l-io.lua',
- 'l-md5.lua',
'l-number.lua',
'l-set.lua',
'l-os.lua',
'l-file.lua',
+ 'l-md5.lua',
'l-dir.lua',
'l-boolean.lua',
'l-math.lua',
- 'l-xml.lua',
-- 'l-unicode.lua',
- 'l-utils.lua',
-- 'l-tex.lua',
- 'luat-lib.lua',
- 'luat-inp.lua',
- 'luat-log.lua',
--- 'luat-zip.lua',
--- 'luat-tex.lua',
--- 'luat-kps.lua',
- 'luat-tmp.lua',
- 'luat-log.lua',
- 'luat-sta.lua',
+ 'l-utils.lua',
+-- 'l-xml.lua',
+ 'lxml-tab.lua',
+ 'lxml-pth.lua',
+ 'lxml-ent.lua',
+ 'lxml-mis.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+ 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+ 'data-zip.lua',
+ 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-tmf.lua', -- tree files
+ -- needed ?
+ 'luat-sta.lua', -- states
}
-- We need this hack till luatex is fixed.
@@ -8236,11 +9555,11 @@ local function locate_libs()
end
end
-if not input then
+if not resolvers then
locate_libs()
end
-if not input then
+if not resolvers then
print("")
print("Mtxrun is unable to start up due to lack of libraries. You may")
print("try to run 'lua mtxrun.lua --selfmerge' in the path where this")
@@ -8249,216 +9568,12 @@ if not input then
os.exit()
end
-input.instance = input.reset()
-input.banner = 'MtxRun'
-utils.report = input.report
-
-local instance = input.instance
-
-
--- use os.env or environment when available
-
-function input.check_environment(tree)
- input.report('')
- os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
- os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
- os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
- os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
- input.report('')
- input.report("preset : TEXPATH => %s", os.getenv('TEXPATH'))
- input.report("preset : TEXOS => %s", os.getenv('TEXOS'))
- input.report("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
- input.report("preset : TMP => %s", os.getenv('TMP'))
- input.report('')
-end
-
-function input.load_environment(name) -- todo: key=value as well as lua
- local f = io.open(name)
- if f then
- for line in f:lines() do
- if line:find("^[%%%#]") then
- -- skip comment
- else
- local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
- if how then
- value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
- if how == "=" or how == "<<" then
- os.setenv(key,value)
- elseif how == "?" or how == "??" then
- os.setenv(key,os.getenv(key) or value)
- elseif how == "<" or how == "+=" then
- if os.getenv(key) then
- os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
- else
- os.setenv(key,value)
- end
- elseif how == ">" or how == "=+" then
- if os.getenv(key) then
- os.setenv(key,value .. io.pathseparator .. os.getenv(key))
- else
- os.setenv(key,value)
- end
- end
- end
- end
- end
- f:close()
- end
-end
-
-function input.load_tree(tree)
- if tree and tree ~= "" then
- local setuptex = 'setuptex.tmf'
- if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
- setuptex = tree .. "/" .. setuptex
- else
- setuptex = tree
- end
- if io.exists(setuptex) then
- input.check_environment(tree)
- input.load_environment(setuptex)
- end
- end
-end
-
--- md5 extensions
-
--- maybe md.md5 md.md5hex md.md5HEX
-
-if not md5 then md5 = { } end
-
-if not md5.sum then
- function md5.sum(k)
- return string.rep("x",16)
- end
-end
-
-function md5.hexsum(k)
- return (string.gsub(md5.sum(k), ".", function(c) return string.format("%02x", string.byte(c)) end))
-end
-
-function md5.HEXsum(k)
- return (string.gsub(md5.sum(k), ".", function(c) return string.format("%02X", string.byte(c)) end))
-end
-
--- file extensions
+logs.setprogram('MTXrun',"TDS Runner Tool 1.22",environment.arguments["verbose"] or false)
-file.needs_updating_threshold = 1
+local instance = resolvers.reset()
-function file.needs_updating(oldname,newname) -- size modification access change
- local oldtime = lfs.attributes(oldname, modification)
- local newtime = lfs.attributes(newname, modification)
- if newtime >= oldtime then
- return false
- elseif oldtime - newtime < file.needs_updating_threshold then
- return false
- else
- return true
- end
-end
-
-function file.checksum(name)
- if md5 then
- local data = io.loaddata(name)
- if data then
- return md5.HEXsum(data)
- end
- end
- return nil
-end
-
-function file.loadchecksum(name)
- if md5 then
- local data = io.loaddata(name .. ".md5")
- return data and data:gsub("%s","")
- end
- return nil
-end
-
-function file.savechecksum(name, checksum)
- if not checksum then checksum = file.checksum(name) end
- if checksum then
- io.savedata(name .. ".md5",checksum)
- return checksum
- end
- return nil
-end
-
-os.arch = os.arch or function()
- return os.resultof("uname -m") or "linux"
-end
-
-function os.currentplatform(name, default)
- local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
- if name then
- if name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
- return "mswin"
- elseif name == "linux" then
- local architecture = os.arch()
- if architecture:find("x86_64") then
- return "linux-64"
- elseif architecture:find("ppc") then
- return "linux-ppc"
- else
- return "linux"
- end
- elseif name == "macosx" then
- local architecture = os.arch()
- if architecture:find("i386") then
- return "osx-intel"
- else
- return "osx-ppc"
- end
- elseif name == "freebsd" then
- return "freebsd"
- end
- end
- return default or name
-end
-
--- it starts here
-
-input.runners = { }
-input.runners.applications = { }
-
-input.runners.applications.lua = "luatex --luaonly"
-input.runners.applications.pl = "perl"
-input.runners.applications.py = "python"
-input.runners.applications.rb = "ruby"
-
-input.runners.suffixes = {
- 'rb', 'lua', 'py', 'pl'
-}
-
-input.runners.registered = {
- texexec = { 'texexec.rb', true },
- texutil = { 'texutil.rb', true },
- texfont = { 'texfont.pl', true },
- texshow = { 'texshow.pl', false },
-
- makempy = { 'makempy.pl', true },
- mptopdf = { 'mptopdf.pl', true },
- pstopdf = { 'pstopdf.rb', true },
-
--- examplex = { 'examplex.rb', false },
- concheck = { 'concheck.rb', false },
-
- runtools = { 'runtools.rb', true },
- textools = { 'textools.rb', true },
- tmftools = { 'tmftools.rb', true },
- ctxtools = { 'ctxtools.rb', true },
- rlxtools = { 'rlxtools.rb', true },
- pdftools = { 'pdftools.rb', true },
- mpstools = { 'mpstools.rb', true },
- exatools = { 'exatools.rb', true },
- xmltools = { 'xmltools.rb', true },
- luatools = { 'luatools.lua', true },
- mtxtools = { 'mtxtools.rb', true },
-
- pdftrimwhite = { 'pdftrimwhite.pl', false }
-}
-
-if not messages then messages = { } end
+runners = runners or { } -- global
+messages = messages or { }
messages.help = [[
--script run an mtx script (--noquotes)
@@ -8488,43 +9603,78 @@ messages.help = [[
--launch (--all) launch files like manuals, assumes os support
--intern run script using built in libraries
+
+--usekpse use kpse as fallback (when no mkiv and cache installed, often slower)
+--forcekpse force using kpse (handy when no mkiv and cache installed but less functionality)
]]
-function input.runners.my_prepare_a()
- input.resetconfig()
- input.identify_cnf()
- input.load_lua()
- input.expand_variables()
- input.load_cnf()
- input.expand_variables()
-end
+runners.applications = {
+ ["lua"] = "luatex --luaonly",
+ ["luc"] = "luatex --luaonly",
+ ["pl"] = "perl",
+ ["py"] = "python",
+ ["rb"] = "ruby",
+}
-function input.runners.my_prepare_b()
- input.runners.my_prepare_a()
- input.load_hash()
- input.automount()
-end
+runners.suffixes = {
+ 'rb', 'lua', 'py', 'pl'
+}
-function input.runners.prepare()
+runners.registered = {
+ texexec = { 'texexec.rb', true }, -- context mkii runner (only tool not to be luafied)
+ texutil = { 'texutil.rb', true }, -- old perl based index sorter for mkii (old versions need it)
+ texfont = { 'texfont.pl', true }, -- perl script that makes mkii font metric files
+ texfind = { 'texfind.pl', false }, -- perltk based tex searching tool, mostly used at pragma
+ texshow = { 'texshow.pl', false }, -- perltk based context help system, will be luafied
+ -- texwork = { \texwork.pl', false }, -- perltk based editing environment, only used at pragma
+
+ makempy = { 'makempy.pl', true },
+ mptopdf = { 'mptopdf.pl', true },
+ pstopdf = { 'pstopdf.rb', true }, -- converts ps (and some more) images, does some cleaning (replaced)
+
+-- examplex = { 'examplex.rb', false },
+ concheck = { 'concheck.rb', false },
+
+ runtools = { 'runtools.rb', true },
+ textools = { 'textools.rb', true },
+ tmftools = { 'tmftools.rb', true },
+ ctxtools = { 'ctxtools.rb', true },
+ rlxtools = { 'rlxtools.rb', true },
+ pdftools = { 'pdftools.rb', true },
+ mpstools = { 'mpstools.rb', true },
+-- exatools = { 'exatools.rb', true },
+ xmltools = { 'xmltools.rb', true },
+-- luatools = { 'luatools.lua', true },
+ mtxtools = { 'mtxtools.rb', true },
+
+ pdftrimwhite = { 'pdftrimwhite.pl', false }
+}
+
+runners.launchers = {
+ windows = { },
+ unix = { }
+}
+
+function runners.prepare()
local checkname = environment.argument("ifchanged")
if checkname and checkname ~= "" then
local oldchecksum = file.loadchecksum(checkname)
local newchecksum = file.checksum(checkname)
if oldchecksum == newchecksum then
- input.report("file '%s' is unchanged",checkname)
+ logs.simple("file '%s' is unchanged",checkname)
return "skip"
else
- input.report("file '%s' is changed, processing started",checkname)
+ logs.simple("file '%s' is changed, processing started",checkname)
end
file.savechecksum(checkname)
end
local oldname, newname = string.split(environment.argument("iftouched") or "", ",")
if oldname and newname and oldname ~= "" and newname ~= "" then
if not file.needs_updating(oldname,newname) then
- input.report("file '%s' and '%s' have same age",oldname,newname)
+ logs.simple("file '%s' and '%s' have same age",oldname,newname)
return "skip"
else
- input.report("file '%s' is older than '%s'",oldname,newname)
+ logs.simple("file '%s' is older than '%s'",oldname,newname)
end
end
local tree = environment.argument('tree') or ""
@@ -8532,28 +9682,27 @@ function input.runners.prepare()
tree = os.getenv('TEXMFSTART_TREE') or os.getenv('TEXMFSTARTTREE') or tree
end
if tree and tree ~= "" then
- input.load_tree(tree)
+ resolvers.load_tree(tree)
end
local env = environment.argument('environment') or ""
if env and env ~= "" then
for _,e in pairs(string.split(env)) do
-- maybe force suffix when not given
- input.load_tree(e)
+ resolvers.load_tree(e)
end
end
local runpath = environment.argument("path")
- if runpath and not dir.chdir(runpath) then
- input.report("unable to change to path '%s'",runpath)
+ if runpath and not lfs.chdir(runpath) then
+ logs.simple("unable to change to path '%s'",runpath)
return "error"
end
return "run"
end
-function input.runners.execute_script(fullname,internal)
- local instance = input.instance
+function runners.execute_script(fullname,internal)
local noquote = environment.argument("noquotes")
if fullname and fullname ~= "" then
- local state = input.runners.prepare()
+ local state = runners.prepare()
if state == 'error' then
return false
elseif state == 'skip' then
@@ -8570,41 +9719,44 @@ function input.runners.execute_script(fullname,internal)
return ""
end )
name = name:gsub("^script:","")
- if suffix == "" and input.runners.registered[name] and input.runners.registered[name][1] then
- name = input.runners.registered[name][1]
+ if suffix == "" and runners.registered[name] and runners.registered[name][1] then
+ name = runners.registered[name][1]
suffix = file.extname(name)
end
if suffix == "" then
-- loop over known suffixes
- for _,s in pairs(input.runners.suffixes) do
- result = input.find_file(name .. "." .. s, 'texmfscripts')
+ for _,s in pairs(runners.suffixes) do
+ result = resolvers.find_file(name .. "." .. s, 'texmfscripts')
if result ~= "" then
break
end
end
- elseif input.runners.applications[suffix] then
- result = input.find_file(name, 'texmfscripts')
+ elseif runners.applications[suffix] then
+ result = resolvers.find_file(name, 'texmfscripts')
else
-- maybe look on path
- result = input.find_file(name, 'other text files')
+ result = resolvers.find_file(name, 'other text files')
end
end
if result and result ~= "" then
+ local before, after = environment.split_arguments(fullname) -- already done
+ environment.arguments_before, environment.arguments_after = before, after
if internal then
- local before, after = environment.split_arguments(fullname)
arg = { } for _,v in pairs(after) do arg[#arg+1] = v end
dofile(result)
else
- local binary = input.runners.applications[file.extname(result)]
+ local binary = runners.applications[file.extname(result)]
if binary and binary ~= "" then
result = binary .. " " .. result
end
- local before, after = environment.split_arguments(fullname)
local command = result .. " " .. environment.reconstruct_commandline(after,noquote)
- input.report("")
- input.report("executing: %s",command)
- input.report("\n \n")
- io.flush()
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
+ io.flush()
+ end
local code = os.exec(command) -- maybe spawn
return code == 0
end
@@ -8614,10 +9766,10 @@ function input.runners.execute_script(fullname,internal)
return false
end
-function input.runners.execute_program(fullname)
+function runners.execute_program(fullname)
local noquote = environment.argument("noquotes")
if fullname and fullname ~= "" then
- local state = input.runners.prepare()
+ local state = runners.prepare()
if state == 'error' then
return false
elseif state == 'skip' then
@@ -8627,9 +9779,10 @@ function input.runners.execute_program(fullname)
environment.initialize_arguments(after)
fullname = fullname:gsub("^bin:","")
local command = fullname .. " " .. (environment.reconstruct_commandline(after or "",noquote) or "")
- input.report("")
- input.report("executing: %s",command)
- input.report("\n \n")
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
io.flush()
local code = os.exec(command) -- (fullname,unpack(after)) does not work / maybe spawn
return code == 0
@@ -8638,8 +9791,13 @@ function input.runners.execute_program(fullname)
return false
end
-function input.runners.handle_stubs(create)
- local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer supported
+-- the --usekpse flag will fallback on kpse
+
+local windows_stub = '@echo off\013\010setlocal\013\010set ownpath=%%~dp0%%\013\010texlua "%%ownpath%%mtxrun.lua" --usekpse --execute %s %%*\013\010endlocal\013\010'
+local unix_stub = '#!/bin/sh\010mtxrun --usekpse --execute %s \"$@\"\010'
+
+function runners.handle_stubs(create)
+ local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer subpathssupported
local windows = environment.argument('windows') or environment.argument('mswin') or false
local unix = environment.argument('unix') or environment.argument('linux') or false
if not windows and not unix then
@@ -8649,77 +9807,77 @@ function input.runners.handle_stubs(create)
windows = true
end
end
- for _,v in pairs(input.runners.registered) do
+ for _,v in pairs(runners.registered) do
local name, doit = v[1], v[2]
if doit then
local base = string.gsub(file.basename(name), "%.(.-)$", "")
if create then
- -- direct local command = input.runners.applications[file.extname(name)] .. " " .. name
- local command = "luatex --luaonly mtxrun.lua " .. name
if windows then
- io.savedata(base..".bat", {"@echo off", command.." %*"}, "\013\010")
- input.report("windows stub for '%s' created",base)
+ io.savedata(file.join(stubpath,base..".bat"),string.format(windows_stub,name))
+ logs.simple("windows stub for '%s' created",base)
end
if unix then
- io.savedata(base, {"#!/bin/sh", command..' "$@"'}, "\010")
- input.report("unix stub for '%s' created",base)
+ io.savedata(file.join(stubpath,base),string.format(unix_stub,name))
+ logs.simple("unix stub for '%s' created",base)
end
else
- if windows and (os.remove(base..'.bat') or os.remove(base..'.cmd')) then
- input.report("windows stub for '%s' removed", base)
+ if windows and (os.remove(file.join(stubpath,base..'.bat')) or os.remove(file.join(stubpath,base..'.cmd'))) then
+ logs.simple("windows stub for '%s' removed", base)
end
- if unix and (os.remove(base) or os.remove(base..'.sh')) then
- input.report("unix stub for '%s' removed",base)
+ if unix and (os.remove(file.join(stubpath,base)) or os.remove(file.join(stubpath,base..'.sh'))) then
+ logs.simple("unix stub for '%s' removed",base)
end
end
end
end
end
-function input.runners.resolve_string(filename)
+function runners.resolve_string(filename)
if filename and filename ~= "" then
- input.runners.report_location(input.resolve(filename))
+ runners.report_location(resolvers.resolve(filename))
end
end
-function input.runners.locate_file(filename)
+function runners.locate_file(filename)
+ -- differs from texmfstart where locate appends .com .exe .bat ... todo
if filename and filename ~= "" then
- input.runners.report_location(input.find_given_file(filename))
+ runners.report_location(resolvers.find_given_file(filename))
end
end
-function input.runners.locate_platform()
- input.runners.report_location(os.currentplatform())
+function runners.locate_platform()
+ runners.report_location(os.currentplatform())
end
-function input.runners.report_location(result)
- if input.verbose then
- input.report("")
+function runners.report_location(result)
+ if logs.verbose then
+ logs.simpleline()
if result and result ~= "" then
- input.report(result)
+ logs.simple(result)
else
- input.report("not found")
+ logs.simple("not found")
end
else
io.write(result)
end
end
-function input.runners.edit_script(filename) -- we assume that vim is present on most systems
+function runners.edit_script(filename) -- we assume that vim is present on most systems
local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'vim'
- local rest = input.resolve(filename)
+ local rest = resolvers.resolve(filename)
if rest ~= "" then
local command = editor .. " " .. rest
- if input.verbose then
- input.report("")
- input.report("starting editor: %s",command)
- input.report("\n \n")
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("starting editor: %s",command)
+ logs.simple_line()
+ logs.simple_line()
end
os.launch(command)
end
end
-function input.runners.save_script_session(filename, list)
+function runners.save_script_session(filename, list)
local t = { }
for _, key in ipairs(list) do
t[key] = environment.arguments[key]
@@ -8727,7 +9885,7 @@ function input.runners.save_script_session(filename, list)
io.savedata(filename,table.serialize(t,true))
end
-function input.runners.load_script_session(filename)
+function runners.load_script_session(filename)
if lfs.isfile(filename) then
local t = io.loaddata(filename)
if t then
@@ -8740,15 +9898,10 @@ function input.runners.load_script_session(filename)
end
end
-input.runners.launchers = {
- windows = { },
- unix = { }
-}
-
-function input.launch(str)
+function resolvers.launch(str)
-- maybe we also need to test on mtxrun.launcher.suffix environment
-- variable or on windows consult the assoc and ftype vars and such
- local launchers = input.runners.launchers[os.platform] if launchers then
+ local launchers = runners.launchers[os.platform] if launchers then
local suffix = file.extname(str) if suffix then
local runner = launchers[suffix] if runner then
str = runner .. " " .. str
@@ -8758,41 +9911,40 @@ function input.launch(str)
os.launch(str)
end
-function input.runners.launch_file(filename)
- local instance = input.instance
+function runners.launch_file(filename)
instance.allresults = true
- input.verbose = true
+ logs.setverbose(true)
local pattern = environment.arguments["pattern"]
if not pattern or pattern == "" then
pattern = filename
end
if not pattern or pattern == "" then
- input.report("provide name or --pattern=")
+ logs.simple("provide name or --pattern=")
else
- local t = input.find_files(pattern)
+ local t = resolvers.find_files(pattern)
if not t or #t == 0 then
- t = input.aux.find_file("*/" .. pattern,true)
+ t = resolvers.find_files("*/" .. pattern)
end
if not t or #t == 0 then
- t = input.aux.find_file("*/" .. pattern .. "*",true)
+ t = resolvers.find_files("*/" .. pattern .. "*")
end
if t and #t > 0 then
if environment.arguments["all"] then
for _, v in pairs(t) do
- input.report("launching %s", v)
- input.launch(v)
+ logs.simple("launching %s", v)
+ resolvers.launch(v)
end
else
- input.report("launching %s", t[1])
- input.launch(t[1])
+ logs.simple("launching %s", t[1])
+ resolvers.launch(t[1])
end
else
- input.report("no match for %s", pattern)
+ logs.simple("no match for %s", pattern)
end
end
end
-function input.runners.find_mtx_script(filename)
+function runners.find_mtx_script(filename)
local function found(name)
local path = file.dirname(name)
if path and path ~= "" then
@@ -8803,10 +9955,10 @@ function input.runners.find_mtx_script(filename)
end
end
filename = file.addsuffix(filename,"lua")
- local basename = file.stripsuffix(file.basename(filename))
+ local basename = file.removesuffix(file.basename(filename))
local suffix = file.extname(filename)
-- qualified path, raw name
- local fullname = input.aux.qualified_path(filename) and io.exists(filename) and filename
+ local fullname = file.is_qualified_path(filename) and io.exists(filename) and filename
if fullname and fullname ~= "" then
return fullname
end
@@ -8818,74 +9970,84 @@ function input.runners.find_mtx_script(filename)
end
-- context namespace, mtx-<filename>
fullname = "mtx-" .. filename
- fullname = found(fullname) or input.find_file(fullname)
+ fullname = found(fullname) or resolvers.find_file(fullname)
if fullname and fullname ~= "" then
return fullname
end
-- context namespace, mtx-<filename>s
fullname = "mtx-" .. basename .. "s" .. "." .. suffix
- fullname = found(fullname) or input.find_file(fullname)
+ fullname = found(fullname) or resolvers.find_file(fullname)
if fullname and fullname ~= "" then
return fullname
end
-- context namespace, mtx-<filename minus trailing s>
fullname = "mtx-" .. basename:gsub("s$","") .. "." .. suffix
- fullname = found(fullname) or input.find_file(fullname)
+ fullname = found(fullname) or resolvers.find_file(fullname)
if fullname and fullname ~= "" then
return fullname
end
-- context namespace, just <filename>
- fullname = input.find_file(fullname)
+ fullname = resolvers.find_file(filename)
return fullname
end
-function input.runners.execute_ctx_script(filename,arguments)
- local fullname = input.runners.find_mtx_script(filename)
+function runners.execute_ctx_script(filename,arguments)
+ local fullname = runners.find_mtx_script(filename) or ""
+ -- retyr after generate but only if --autogenerate
+ if fullname == "" and environment.argument("autogenerate") then -- might become the default
+ instance.renewcache = true
+ logs.setverbose(true)
+ resolvers.load()
+ --
+ fullname = runners.find_mtx_script(filename) or ""
+ end
-- that should do it
- if fullname and fullname ~= "" then
- local state = input.runners.prepare()
+ if fullname ~= "" then
+ local state = runners.prepare()
if state == 'error' then
return false
elseif state == 'skip' then
return true
elseif state == "run" then
-- load and save ... kind of undocumented
- arg = { } for _,v in pairs(arguments) do arg[#arg+1] = v end
+ arg = { } for _,v in pairs(arguments) do arg[#arg+1] = resolvers.resolve(v) end
environment.initialize_arguments(arg)
local loadname = environment.arguments['load']
if loadname then
if type(loadname) ~= "string" then loadname = file.basename(fullname) end
loadname = file.replacesuffix(loadname,"cfg")
- input.runners.load_script_session(loadname)
+ runners.load_script_session(loadname)
end
filename = environment.files[1]
- if input.verbose then
- input.report("using script: %s\n",fullname)
+ if logs.verbose then
+ logs.simple("using script: %s\n",fullname)
end
dofile(fullname)
local savename = environment.arguments['save']
- if savename and input.runners.save_list and not table.is_empty(input.runners.save_list or { }) then
+ if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
if type(savename) ~= "string" then savename = file.basename(fullname) end
savename = file.replacesuffix(savename,"cfg")
- input.runners.save_script_session(savename, input.runners.save_list)
+ runners.save_script_session(savename, runners.save_list)
end
return true
end
else
- input.verbose = true
+ logs.setverbose(true)
filename = file.addsuffix(filename,"lua")
if filename == "" then
- input.report("unknown script, no name given")
- elseif input.aux.qualified_path(filename) then
- input.report("unknown script '%s'",filename)
+ logs.simple("unknown script, no name given")
+ elseif file.is_qualified_path(filename) then
+ logs.simple("unknown script '%s'",filename)
else
- input.report("unknown script '%s' or 'mtx-%s'",filename,filename)
+ logs.simple("unknown script '%s' or 'mtx-%s'",filename,filename)
end
return false
end
end
-input.report("%s\n",banner)
+function runners.timed(action)
+ statistics.timed(action)
+end
-- this is a bit dirty ... first we store the first filename and next we
-- split the arguments so that we only see the ones meant for this script
@@ -8895,14 +10057,79 @@ local filename = environment.files[1] or ""
local ok = true
local before, after = environment.split_arguments(filename)
+environment.arguments_before, environment.arguments_after = before, after
environment.initialize_arguments(before)
instance.engine = environment.argument("engine") or 'luatex'
instance.progname = environment.argument("progname") or 'context'
instance.lsrmode = environment.argument("lsr") or false
-input.verbose = environment.argument("verbose") or false
-input.runners.my_prepare_b()
+-- maybe the unset has to go to this level
+
+if environment.argument("usekpse") or environment.argument("forcekpse") then
+
+ os.setenv("engine","")
+ os.setenv("progname","")
+
+ local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ pfb = "type1 fonts",
+ other = "other text files",
+ }
+
+ local function kpse_initialized()
+ texconfig.kpse_init = true
+ local t = os.clock()
+ local k = kpse.original.new("luatex",instance.progname)
+ local dummy = k:find_file("mtxrun.lua") -- so that we're initialized
+ logs.simple("kpse fallback with progname '%s' initialized in %s seconds",instance.progname,os.clock()-t)
+ kpse_initialized = function() return k end
+ return k
+ end
+
+ local find_file = resolvers.find_file
+ local show_path = resolvers.show_path
+
+ if environment.argument("forcekpse") then
+
+ function resolvers.find_file(name,kind)
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ function resolvers.show_path(name)
+ return (kpse_initialized():show_path(name)) or ""
+ end
+
+ elseif environment.argument("usekpse") then
+
+ resolvers.load()
+
+ function resolvers.find_file(name,kind)
+ local found = find_file(name,kind) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ end
+ function resolvers.show_path(name)
+ local found = show_path(name) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():show_path(name)) or ""
+ end
+ end
+
+ end
+
+else
+
+ resolvers.load()
+
+end
+
if environment.argument("selfmerge") then
-- embed used libraries
@@ -8911,47 +10138,47 @@ elseif environment.argument("selfclean") then
-- remove embedded libraries
utils.merger.selfclean(own.name)
elseif environment.argument("selfupdate") then
- input.verbose = true
- input.update_script(own.name,"mtxrun")
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"mtxrun")
elseif environment.argument("ctxlua") or environment.argument("internal") then
-- run a script by loading it (using libs)
- ok = input.runners.execute_script(filename,true)
-elseif environment.argument("script") then
+ ok = runners.execute_script(filename,true)
+elseif environment.argument("script") or environment.argument("s") then
-- run a script by loading it (using libs), pass args
- ok = input.runners.execute_ctx_script(filename,after)
+ ok = runners.execute_ctx_script(filename,after)
elseif environment.argument("execute") then
-- execute script
- ok = input.runners.execute_script(filename)
+ ok = runners.execute_script(filename)
elseif environment.argument("direct") then
-- equals bin:
- ok = input.runners.execute_program(filename)
+ ok = runners.execute_program(filename)
elseif environment.argument("edit") then
-- edit file
- input.runners.edit_script(filename)
+ runners.edit_script(filename)
elseif environment.argument("launch") then
- input.runners.launch_file(filename)
+ runners.launch_file(filename)
elseif environment.argument("make") then
-- make stubs
- input.runners.handle_stubs(true)
+ runners.handle_stubs(true)
elseif environment.argument("remove") then
-- remove stub
- input.runners.handle_stubs(false)
+ runners.handle_stubs(false)
elseif environment.argument("resolve") then
-- resolve string
- input.runners.resolve_string(filename)
+ runners.resolve_string(filename)
elseif environment.argument("locate") then
-- locate file
- input.runners.locate_file(filename)
+ runners.locate_file(filename)
elseif environment.argument("platform")then
-- locate platform
- input.runners.locate_platform()
+ runners.locate_platform()
elseif environment.argument("help") or filename=='help' or filename == "" then
- input.help(banner,messages.help)
+ logs.help(messages.help)
-- execute script
elseif filename:find("^bin:") then
- ok = input.runners.execute_program(filename)
+ ok = runners.execute_program(filename)
else
- ok = input.runners.execute_script(filename)
+ ok = runners.execute_script(filename)
end
if os.platform == "unix" then
diff --git a/scripts/context/lua/x-ldx.lua b/scripts/context/lua/x-ldx.lua
index 67d5f925c..af5c9c0c8 100644
--- a/scripts/context/lua/x-ldx.lua
+++ b/scripts/context/lua/x-ldx.lua
@@ -335,10 +335,10 @@ The next function wraps it all in one call:
--ldx]]--
function ldx.convert(luaname,ldxname)
- if not file.is_readable(luaname) then
+ if not file.isreadable(luaname) then
luaname = luaname .. ".lua"
end
- if file.is_readable(luaname) then
+ if file.isreadable(luaname) then
if not ldxname then
ldxname = file.replacesuffix(luaname,"ldx")
end
diff --git a/scripts/context/ruby/base/exa.rb b/scripts/context/ruby/base/exa.rb
index 5a094351e..7ba990cf9 100644
--- a/scripts/context/ruby/base/exa.rb
+++ b/scripts/context/ruby/base/exa.rb
@@ -3,8 +3,9 @@
# tex.setup.setuplayout.width.[integer|real|dimension|string|key]
# tex.[mp]var.whatever.width.[integer|real|dimension|string|key]
-require 'ftools'
-require 'md5'
+require 'fileutils'
+# require 'ftools'
+require 'digest/md5'
# this can become a lua thing
@@ -40,7 +41,7 @@ module ExaEncrypt
pre, password, post = $1, $2, $3
unless password =~ /MD5:/i then
done = true
- password = "MD5:" + MD5.new(password).hexdigest.upcase
+ password = "MD5:" + Digest::MD5.hexdigest(password).upcase
end
"#{pre}#{password}#{post}"
end
@@ -49,7 +50,7 @@ module ExaEncrypt
attributes, password = $1, $2
unless password =~ /^([0-9A-F][0-9A-F])+$/ then
done = true
- password = MD5.new(password).hexdigest.upcase
+ password = Digest::MD5.hexdigest(password).upcase
attributes = " encryption='md5'#{attributes}"
end
"<exa:password#{attributes}>#{password}</exa:password>"
diff --git a/scripts/context/ruby/base/file.rb b/scripts/context/ruby/base/file.rb
index 39bb7d467..1aeac5fd6 100644
--- a/scripts/context/ruby/base/file.rb
+++ b/scripts/context/ruby/base/file.rb
@@ -8,7 +8,8 @@
# info : j.hagen@xs4all.nl
# www : www.pragma-ade.com
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
class File
@@ -110,7 +111,7 @@ class File
def File.silentcopy(oldname,newname)
return if File.expand_path(oldname) == File.expand_path(newname)
- File.makedirs(File.dirname(newname)) rescue false
+ FileUtils.makedirs(File.dirname(newname)) rescue false
File.copy(oldname,newname) rescue false
end
@@ -123,7 +124,7 @@ class File
begin
File.rename(oldname,newname)
rescue
- File.makedirs(File.dirname(newname)) rescue false
+ FileUtils.makedirs(File.dirname(newname)) rescue false
File.copy(oldname,newname) rescue false
end
end
diff --git a/scripts/context/ruby/base/kpse.rb b/scripts/context/ruby/base/kpse.rb
index 0e185b5b8..0f9868784 100644
--- a/scripts/context/ruby/base/kpse.rb
+++ b/scripts/context/ruby/base/kpse.rb
@@ -13,6 +13,7 @@
# todo: web2c vs miktex module and include in kpse
require 'rbconfig'
+require 'fileutils'
# beware $engine is lowercase in kpse
#
@@ -185,6 +186,7 @@ module Kpse
return results
end
+
def Kpse.formatpaths
# maybe we should check for writeability
unless @@paths.key?('formatpaths') then
@@ -272,7 +274,7 @@ module Kpse
unless done then
formatpaths.each do |fp|
fpp = fp.sub(/#{engine}\/*$/o,'')
- File.makedirs(fpp) rescue false # maybe we don't have an path yet
+ FileUtils.makedirs(fpp) rescue false # maybe we don't have an path yet
if FileTest.directory?(fpp) && FileTest.writable?(fpp) then
# use this path
formatpath, done = fp.dup, true
@@ -285,12 +287,12 @@ module Kpse
end
end
# needed !
- File.makedirs(formatpath) rescue false
+ FileUtils.makedirs(formatpath) rescue false
# fall back to current path
formatpath = '.' if formatpath.empty? || ! FileTest.writable?(formatpath)
# append engine but prevent duplicates
formatpath = File.join(formatpath.sub(/\/*#{engine}\/*$/,''), engine) if enginepath
- File.makedirs(formatpath) rescue false
+ FileUtils.makedirs(formatpath) rescue false
setpath(engine,formatpath)
# ENV['engine'] = savedengine
end
diff --git a/scripts/context/ruby/base/state.rb b/scripts/context/ruby/base/state.rb
index 4b2088128..76ef50b25 100644
--- a/scripts/context/ruby/base/state.rb
+++ b/scripts/context/ruby/base/state.rb
@@ -1,4 +1,4 @@
-require "md5"
+require 'digest/md5'
# todo: register omissions per file
@@ -57,7 +57,7 @@ class FileState
begin
if FileTest.file?(filename) && (data = IO.read(filename)) then
data.gsub!(/\n.*?(#{[omit].flatten.join('|')}).*?\n/) do "\n" end if omit
- sum = MD5.new(data).hexdigest.upcase
+ sum = Digest::MD5.hexdigest(data).upcase
end
rescue
sum = ''
diff --git a/scripts/context/ruby/base/tex.rb b/scripts/context/ruby/base/tex.rb
index 4f3e51299..c14cb840f 100644
--- a/scripts/context/ruby/base/tex.rb
+++ b/scripts/context/ruby/base/tex.rb
@@ -16,6 +16,8 @@
# report ?
+require 'fileutils'
+
require 'base/variables'
require 'base/kpse'
require 'base/system'
@@ -128,11 +130,12 @@ class TEX
['cont-ro','ro','romanian'] .each do |f| @@texformats[f] = 'cont-ro' end
['cont-gb','gb','cont-uk','uk','british'] .each do |f| @@texformats[f] = 'cont-gb' end
['cont-pe','pe','persian'] .each do |f| @@texformats[f] = 'cont-pe' end
+ ['cont-xp','xp','experimental'] .each do |f| @@texformats[f] = 'cont-xp' end
['mptopdf'] .each do |f| @@texformats[f] = 'mptopdf' end
['latex'] .each do |f| @@texformats[f] = 'latex.ltx' end
- ['plain','mpost'] .each do |f| @@mpsformats[f] = 'plain' end
+ ['plain','mpost'] .each do |f| @@mpsformats[f] = 'mpost' end
['metafun','context','standard'] .each do |f| @@mpsformats[f] = 'metafun' end
['pdftex','pdfetex','aleph','omega','petex',
@@ -143,7 +146,7 @@ class TEX
['plain','default','standard','mptopdf'] .each do |f| @@texmethods[f] = 'plain' end
['cont-en','cont-nl','cont-de','cont-it',
'cont-fr','cont-cs','cont-ro','cont-gb',
- 'cont-pe'] .each do |f| @@texmethods[f] = 'context' end
+ 'cont-pe','cont-xp'] .each do |f| @@texmethods[f] = 'context' end
['latex','pdflatex'] .each do |f| @@texmethods[f] = 'latex' end
['plain','default','standard'] .each do |f| @@mpsmethods[f] = 'plain' end
@@ -154,7 +157,7 @@ class TEX
['cont-en','cont-nl','cont-de','cont-it',
'cont-fr','cont-cs','cont-ro','cont-gb',
- 'cont-pe'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end
+ 'cont-pe','cont-xp'] .each do |f| @@texprocstr[f] = @@platformslash + "emergencyend" end
@@runoptions['aleph'] = ['--8bit']
@@runoptions['luatex'] = ['--file-line-error']
@@ -166,7 +169,7 @@ class TEX
@@tcxflag['aleph'] = true
@@tcxflag['luatex'] = false
- @@tcxflag['mpost'] = true
+ @@tcxflag['mpost'] = false
@@tcxflag['pdfetex'] = true
@@tcxflag['pdftex'] = true
@@tcxflag['petex'] = false
@@ -174,8 +177,8 @@ class TEX
@@draftoptions['pdftex'] = ['--draftmode']
- @@booleanvars = [
- 'batchmode', 'nonstopmode', 'fast', 'fastdisabled', 'silentmode', 'final',
+ @@mainbooleanvars = [
+ 'batchmode', 'nonstopmode', 'fast', 'final',
'paranoid', 'notparanoid', 'nobanner', 'once', 'allpatterns', 'draft',
'nompmode', 'nomprun', 'automprun', 'combine',
'nomapfiles', 'local',
@@ -187,19 +190,19 @@ class TEX
'globalfile', 'autopath',
'purge', 'purgeall', 'keep', 'autopdf', 'xpdf', 'simplerun', 'verbose',
'nooptionfile', 'nobackend', 'noctx', 'utfbom',
- 'mkii',
+ 'mkii','mkiv',
]
- @@stringvars = [
+ @@mainstringvars = [
'modefile', 'result', 'suffix', 'response', 'path',
'filters', 'usemodules', 'environments', 'separation', 'setuppath',
'arguments', 'input', 'output', 'randomseed', 'modes', 'mode', 'filename',
'ctxfile', 'printformat', 'paperformat', 'paperoffset',
'timeout', 'passon'
]
- @@standardvars = [
+ @@mainstandardvars = [
'mainlanguage', 'bodyfont', 'language'
]
- @@knownvars = [
+ @@mainknownvars = [
'engine', 'distribution', 'texformats', 'mpsformats', 'progname', 'interface',
'runs', 'backend'
]
@@ -208,29 +211,31 @@ class TEX
@@extrastringvars = []
def booleanvars
- [@@booleanvars,@@extrabooleanvars].flatten.uniq
+ [@@mainbooleanvars,@@extrabooleanvars].flatten.uniq
end
def stringvars
- [@@stringvars,@@extrastringvars].flatten.uniq
+ [@@mainstringvars,@@extrastringvars].flatten.uniq
end
def standardvars
- [@@standardvars].flatten.uniq
+ [@@mainstandardvars].flatten.uniq
end
def knownvars
- [@@knownvars].flatten.uniq
+ [@@mainknownvars].flatten.uniq
end
def allbooleanvars
- [@@booleanvars,@@extrabooleanvars].flatten.uniq
+ [@@mainbooleanvars,@@extrabooleanvars].flatten.uniq
end
def allstringvars
- [@@stringvars,@@extrastringvars,@@standardvars,@@knownvars].flatten.uniq
+ [@@mainstringvars,@@extrastringvars,@@mainstandardvars,@@mainknownvars].flatten.uniq
end
def setextrastringvars(vars)
- @@extrastringvars << vars
+ # @@extrastringvars << vars -- problems in 1.9
+ @@extrastringvars = [@@extrastringvars,vars].flatten
end
def setextrabooleanvars(vars)
- @@extrabooleanvars << vars
+ # @@extrabooleanvars << vars -- problems in 1.9
+ @@extrabooleanvars = [@@extrabooleanvars,vars].flatten
end
# def jobvariables(names=nil)
@@ -580,7 +585,7 @@ class TEX
if data = (IO.readlines(@@luafiles) rescue nil) then
report("compiling lua files (using #{File.expand_path(@@luafiles)})")
begin
- File.makedirs(@@luatarget) rescue false
+ FileUtils.makedirs(@@luatarget) rescue false
data.each do |line|
luafile = line.chomp
lucfile = File.basename(luafile).gsub(/\..*?$/,'') + ".luc"
@@ -686,7 +691,8 @@ class TEX
mpsformats.each do |mpsformat|
report("generating mps format #{mpsformat}")
progname = validprogname([getvariable('progname'),mpsformat,mpsengine])
- if not runcommand([quoted(mpsengine),prognameflag(progname),iniflag,tcxflag(mpsengine),runoptions(mpsengine),mpsformat,mpsmakeextras(mpsformat)]) then
+ # if not runcommand([quoted(mpsengine),prognameflag(progname),iniflag,tcxflag(mpsengine),runoptions(mpsengine),mpsformat,mpsmakeextras(mpsformat)]) then
+ if not runcommand([quoted(mpsengine),prognameflag(progname),iniflag,runoptions(mpsengine),mpsformat,mpsmakeextras(mpsformat)]) then
setvariable('error','no format made')
end
end
@@ -1009,7 +1015,11 @@ end
tmp << "\\starttext\n"
if forcexml then
# tmp << checkxmlfile(rawname)
- tmp << "\\processXMLfilegrouped{#{rawname}}\n"
+ if getvariable('mkiv') then
+ tmp << "\\xmlprocess{\\xmldocument}{#{rawname}}{}\n"
+ else
+ tmp << "\\processXMLfilegrouped{#{rawname}}\n"
+ end
else
tmp << "\\processfile{#{rawname}}\n"
end
@@ -1329,12 +1339,9 @@ class TEX
# local handies
opt << "\% #{topname}\n"
opt << "\\unprotect\n"
- if getvariable('utfbom') then
- opt << "\\enableregime[utf]"
- end
- opt << "\\setupsystem[\\c!n=#{kindofrun},\\c!m=#{currentrun}]\n"
- progname = validprogname(['metafun']) # [getvariable('progname'),mpsformat,mpsengine]
- opt << "\\def\\MPOSTformatswitch\{#{prognameflag(progname)} #{formatflag('mpost')}=\}\n"
+ #
+ # feedback and basic control
+ #
if getvariable('batchmode') then
opt << "\\batchmode\n"
end
@@ -1344,6 +1351,21 @@ class TEX
if getvariable('paranoid') then
opt << "\\def\\maxreadlevel{1}\n"
end
+ if getvariable('nomapfiles') then
+ opt << "\\disablemapfiles\n"
+ end
+ if getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then
+ opt << "\\runMPgraphicsfalse\n"
+ end
+ if getvariable('utfbom') then
+ opt << "\\enableregime[utf]"
+ end
+ progname = validprogname(['metafun']) # [getvariable('progname'),mpsformat,mpsengine]
+ opt << "\\def\\MPOSTformatswitch\{#{prognameflag(progname)} #{formatflag('mpost')}=\}\n"
+ #
+ # process info
+ #
+ opt << "\\setupsystem[\\c!n=#{kindofrun},\\c!m=#{currentrun}]\n"
if (str = File.unixfied(getvariable('modefile'))) && ! str.empty? then
opt << "\\readlocfile{#{str}}{}{}\n"
end
@@ -1360,6 +1382,35 @@ class TEX
if (str = getvariable('mainlanguage').downcase) && ! str.empty? && ! str.standard? then
opt << "\\setuplanguage[#{str}]\n"
end
+ if (str = getvariable('arguments')) && ! str.empty? then
+ opt << "\\setupenv[#{str}]\n"
+ end
+ if (str = getvariable('setuppath')) && ! str.empty? then
+ opt << "\\setupsystem[\\c!directory=\{#{str}\}]\n"
+ end
+ if (str = getvariable('randomseed')) && ! str.empty? then
+ report("using randomseed #{str}")
+ opt << "\\setupsystem[\\c!random=#{str}]\n"
+ end
+ if (str = getvariable('input')) && ! str.empty? then
+ opt << "\\setupsystem[inputfile=#{str}]\n"
+ else
+ opt << "\\setupsystem[inputfile=#{rawname}]\n"
+ end
+ #
+ # modes
+ #
+ # we handle both "--mode" and "--modes", else "--mode" is mapped onto "--modefile"
+ if (str = getvariable('modes')) && ! str.empty? then
+ opt << "\\enablemode[#{str}]\n"
+ end
+ if (str = getvariable('mode')) && ! str.empty? then
+ opt << "\\enablemode[#{str}]\n"
+ end
+ #
+ # options
+ #
+ opt << "\\startsetups *runtime:options\n"
if str = validbackend(getvariable('backend')) then
opt << "\\setupoutput[#{str}]\n"
elsif str = validbackend(getvariable('output')) then
@@ -1368,21 +1419,9 @@ class TEX
if getvariable('color') then
opt << "\\setupcolors[\\c!state=\\v!start]\n"
end
- if getvariable('nompmode') || getvariable('nomprun') || getvariable('automprun') then
- opt << "\\runMPgraphicsfalse\n"
- end
- if getvariable('fast') && ! getvariable('fastdisabled') then
- opt << "\\fastmode\n"
- end
- if getvariable('silentmode') then
- opt << "\\silentmode\n"
- end
if (str = getvariable('separation')) && ! str.empty? then
opt << "\\setupcolors[\\c!split=#{str}]\n"
end
- if (str = getvariable('setuppath')) && ! str.empty? then
- opt << "\\setupsystem[\\c!directory=\{#{str}\}]\n"
- end
if (str = getvariable('paperformat')) && ! str.empty? && ! str.standard? then
if str =~ /^([a-z]+\d+)([a-z]+\d+)$/io then # A5A4 A4A3 A2A1 ...
opt << "\\setuppapersize[#{$1.upcase}][#{$2.upcase}]\n"
@@ -1399,9 +1438,6 @@ class TEX
if getvariable('centerpage') then
opt << "\\setuplayout[\\c!location=\\v!middle,\\c!marking=\\v!on]\n"
end
- if getvariable('nomapfiles') then
- opt << "\\disablemapfiles\n"
- end
if getvariable('noarrange') then
opt << "\\setuparranging[\\v!disable]\n"
elsif getvariable('arrange') then
@@ -1419,26 +1455,6 @@ class TEX
end
opt << "\\setuparranging[#{arrangement.flatten.join(',')}]\n" if arrangement.size > 0
end
- # we handle both "--mode" and "--modes", else "--mode" is
- # mapped onto "--modefile"
- if (str = getvariable('modes')) && ! str.empty? then
- opt << "\\enablemode[#{str}]\n"
- end
- if (str = getvariable('mode')) && ! str.empty? then
- opt << "\\enablemode[#{str}]\n"
- end
- if (str = getvariable('arguments')) && ! str.empty? then
- opt << "\\setupenv[#{str}]\n"
- end
- if (str = getvariable('randomseed')) && ! str.empty? then
- report("using randomseed #{str}")
- opt << "\\setupsystem[\\c!random=#{str}]\n"
- end
- if (str = getvariable('input')) && ! str.empty? then
- opt << "\\setupsystem[inputfile=#{str}]\n"
- else
- opt << "\\setupsystem[inputfile=#{rawname}]\n"
- end
if (str = getvariable('pages')) && ! str.empty? then
if str.downcase == 'odd' then
opt << "\\chardef\\whichpagetoshipout=1\n"
@@ -1459,14 +1475,18 @@ class TEX
opt << "\\def\\pagestoshipout\{#{pagelist.join(',')}\}\n";
end
end
- opt << "\\protect\n";
- # begin getvariable('modes' ).split(',').uniq.each do |e| opt << "\\enablemode [#{e}]\n" end ; rescue ; end
+ opt << "\\stopsetups\n"
+ #
+ # styles and modules
+ #
+ opt << "\\startsetups *runtime:modules\n"
begin getvariable('filters' ).split(',').uniq.each do |f| opt << "\\useXMLfilter[#{f}]\n" end ; rescue ; end
begin getvariable('usemodules' ).split(',').uniq.each do |m| opt << "\\usemodule [#{m}]\n" end ; rescue ; end
begin getvariable('environments').split(',').uniq.each do |e| opt << "\\environment #{e} \n" end ; rescue ; end
- # this will become:
- # begin getvariable('environments').split(',').uniq.each do |e| opt << "\\useenvironment[#{e}]\n" end ; rescue ; end
- opt << "\\endinput\n"
+ opt << "\\stopsetups\n"
+ #
+ opt << "\\protect \\endinput\n"
+ #
opt.close
else
report("unable to write option file #{topname}")
@@ -1579,7 +1599,9 @@ end
if mpsengine && mpsformat then
ENV["MPXCOMMAND"] = "0" unless mpx
progname = validprogname([getvariable('progname'),mpsformat,mpsengine])
- runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),tcxflag(mpsengine),runoptions(mpsengine),mpname,mpsprocextras(mpsformat)])
+ mpname.gsub!(/\.mp$/,"") # temp bug in mp
+ # runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),tcxflag(mpsengine),runoptions(mpsengine),mpname,mpsprocextras(mpsformat)])
+ runcommand([quoted(mpsengine),prognameflag(progname),formatflag(mpsengine,mpsformat),runoptions(mpsengine),mpname,mpsprocextras(mpsformat)])
true
else
false
@@ -1589,7 +1611,7 @@ end
def runtexmp(filename,filetype='',purge=true)
checktestversion
mpname = File.suffixed(filename,filetype,'mp')
- if File.atleast?(mpname,25) then
+ if File.atleast?(mpname,10) then
# first run needed
File.silentdelete(File.suffixed(mpname,'mpt'))
doruntexmp(mpname,nil,true,purge)
@@ -1627,7 +1649,7 @@ end
end
def runtexutil(filename=[], options=['--ref','--ij','--high'], old=false)
- filename.each do |fname|
+ [filename].flatten.each do |fname|
if old then
Kpse.runscript('texutil',fname,options)
else
@@ -2065,7 +2087,7 @@ end
setvariable('mp.line','')
setvariable('mp.error','')
if mpdata = File.silentread(mpname) then
- mpdata.gsub!(/^\%.*\n/o,'')
+ # mpdata.gsub!(/^\%.*\n/o,'')
File.silentrename(mpname,mpcopy)
texfound = mergebe || (mpdata =~ /btex .*? etex/mo)
if mp = openedfile(mpname) then
@@ -2082,10 +2104,11 @@ end
mp << mergebe['0'] if mergebe.key?('0')
end
end
- mp << MPTools::splitmplines(mpdata)
- mp << "\n"
- mp << "end"
+ # mp << MPTools::splitmplines(mpdata)
+ mp << mpdata
mp << "\n"
+ # mp << "end"
+ # mp << "\n"
mp.close
end
processmpx(mpname,true,true,purge) if texfound
@@ -2097,7 +2120,10 @@ end
options = ''
end
# todo plain|mpost|metafun
- ok = runmp(mpname)
+ begin
+ ok = runmp(mpname)
+ rescue
+ end
if f = File.silentopen(File.suffixed(mpname,'log')) then
while str = f.gets do
if str =~ /^l\.(\d+)\s(.*?)\n/o then
diff --git a/scripts/context/ruby/base/texutil.rb b/scripts/context/ruby/base/texutil.rb
index 9e66aecff..3775469ed 100644
--- a/scripts/context/ruby/base/texutil.rb
+++ b/scripts/context/ruby/base/texutil.rb
@@ -475,24 +475,37 @@ class TeXUtil
@@debug = false
def initialize(t, c, k, d)
- @type, @command, @key, @sortkey, @data = t, c, k, k, d
+ @type, @command, @key, @sortkey, @data = t, c, k, c, d
end
attr_reader :type, :command, :key, :data
attr_reader :sortkey
attr_writer :sortkey
+ # def build(sorter)
+ # if @key then
+ # @sortkey = sorter.normalize(sorter.tokenize(@sortkey))
+ # @sortkey = sorter.remap(sorter.simplify(@key.downcase)) # ??
+ # if @sortkey.empty? then
+ # @sortkey = sorter.remap(@command.downcase)
+ # end
+ # else
+ # @key = ""
+ # @sortkey = ""
+ # end
+ # end
+
def build(sorter)
- if @key then
+ if @sortkey and not @sortkey.empty? then
@sortkey = sorter.normalize(sorter.tokenize(@sortkey))
- @sortkey = sorter.remap(sorter.simplify(@key.downcase)) # ??
- if @sortkey.empty? then
- @sortkey = sorter.remap(@command.downcase)
- end
- else
- @key = ""
- @sortkey = ""
- # weird
+ @sortkey = sorter.remap(sorter.simplify(@sortkey.downcase)) # ??
+ end
+ if not @sortkey or @sortkey.empty? then
+ @sortkey = sorter.normalize(sorter.tokenize(@key))
+ @sortkey = sorter.remap(sorter.simplify(@sortkey.downcase)) # ??
+ end
+ if not @sortkey or @sortkey.empty? then
+ @sortkey = @key.dup
end
end
diff --git a/scripts/context/ruby/base/tool.rb b/scripts/context/ruby/base/tool.rb
index 5ccedfec1..abf0d5ed0 100644
--- a/scripts/context/ruby/base/tool.rb
+++ b/scripts/context/ruby/base/tool.rb
@@ -24,10 +24,15 @@ module Tool
t = Time.now
u = t.usec.to_s % [1..2] [0..3]
pth = t.strftime("#{mainpath}%Y%m%d-%H%M%S-#{u}-#{Process.pid}")
- if pth == $constructedtempdir
- # sleep(0.01)
- retry
- end
+ #
+ # problems with 1.9
+ #
+ # if pth == $constructedtempdir
+ # # sleep(0.01)
+ # retry
+ # end
+ pth == $constructedtempdir
+ #
Dir.mkdir(pth) if create
$constructedtempdir = pth
return pth
@@ -216,7 +221,7 @@ module Tool
def Tool.checksuffix(old)
- return old unless test(?f,old)
+ return old unless FileTest.file?(old)
new = old
diff --git a/scripts/context/ruby/ctxtools.rb b/scripts/context/ruby/ctxtools.rb
index b5e231e27..ecdc4c128 100644
--- a/scripts/context/ruby/ctxtools.rb
+++ b/scripts/context/ruby/ctxtools.rb
@@ -56,7 +56,8 @@ require 'base/file'
require 'rexml/document'
require 'net/http'
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
require 'kconv'
exit if defined?(REQUIRE2LIB)
@@ -2279,6 +2280,7 @@ class TexDeps
report("loading files")
report('')
n = 0
+# try tex and mkiv
@files.each do |filename|
if File.file?(filename) and f = File.open(filename) then
defs, uses, l = 0, 0, 0
diff --git a/scripts/context/ruby/fcd_start.rb b/scripts/context/ruby/fcd_start.rb
index 348ac75ba..28f407c76 100644
--- a/scripts/context/ruby/fcd_start.rb
+++ b/scripts/context/ruby/fcd_start.rb
@@ -260,6 +260,7 @@ class FastCD
puts(Dir.pwd.gsub(/\\/o, '/'))
end
rescue
+ puts("some error")
end
end
@@ -272,6 +273,7 @@ class FastCD
else
f.puts("cd #{dir.gsub("\\",'/')}")
end
+ f.close
end
@result = dir
report("changing to #{dir}",true)
@@ -283,6 +285,7 @@ class FastCD
end
def choose(args=[])
+ offset = 97
unless @pattern.empty? then
begin
case @result.size
@@ -301,7 +304,7 @@ class FastCD
return
end
else
- index = answer[0] - ?a
+ index = answer[0] - offset
if dir = list[index] then
chdir(dir)
return
@@ -309,21 +312,27 @@ class FastCD
end
end
rescue
+ puts("some error")
end
loop do
print("\n")
list.each_index do |i|
+begin
if i < @@maxlength then
- puts("#{(i+?a).chr} #{list[i]}")
+ # puts("#{(i+?a).chr} #{list[i]}")
+ puts("#{(i+offset).chr} #{list[i]}")
else
puts("\n there are #{list.length-@@maxlength} entries more")
break
end
+rescue
+ puts("some error")
+end
end
print("\n>> ")
if answer = wait then
- if answer >= ?a and answer <= ?z then
- index = answer - ?a
+ if answer >= offset and answer <= offset+25 then
+ index = answer - offset
if dir = list[index] then
print("#{answer.chr} ")
chdir(dir)
@@ -350,7 +359,7 @@ class FastCD
end
end
rescue
- # report($!)
+ report($!)
end
end
end
diff --git a/scripts/context/ruby/graphics/gs.rb b/scripts/context/ruby/graphics/gs.rb
index cb3d016f4..6143c8812 100644
--- a/scripts/context/ruby/graphics/gs.rb
+++ b/scripts/context/ruby/graphics/gs.rb
@@ -13,7 +13,8 @@
require 'base/variables'
require 'base/system'
-require 'ftools'
+require 'fileutils'
+# Require 'ftools'
class GhostScript
@@ -218,15 +219,15 @@ class GhostScript
rescue
report("job aborted due to some error: #{$!}")
begin
- File.delete(resultfile) if test(?e,resultfile)
+ File.delete(resultfile) if FileTest.file?(resultfile)
rescue
report("unable to delete faulty #{resultfile}")
end
ok = false
ensure
deleteprofile(getvariable('profile'))
- File.delete(@@pstempfile) if test(?e,@@pstempfile)
- File.delete(@@pdftempfile) if test(?e,@@pdftempfile)
+ File.delete(@@pstempfile) if FileTest.file?(@@pstempfile)
+ File.delete(@@pdftempfile) if FileTest.file?(@@pdftempfile)
end
return ok
end
@@ -243,13 +244,14 @@ class GhostScript
def pdfmethod? (str)
case method(str).to_i
- when 3, 4, 5 then return true
+ when 1, 3, 4, 5 then return true
end
return false
end
def pdfprefix (str)
case method(str).to_i
+ when 1 then return 'raw-'
when 4 then return 'lowres-'
when 5 then return 'normal-'
end
@@ -383,7 +385,7 @@ class GhostScript
debug('piping data')
unless pipebounded(tmp,eps) then
debug('something went wrong in the pipe')
- File.delete(outfile) if test(?e,outfile)
+ File.delete(outfile) if FileTest.file?(outfile)
end
debug('closing pipe')
eps.close_write
@@ -412,7 +414,7 @@ class GhostScript
unless ok then
begin
report('no output file due to error')
- File.delete(outfile) if test(?e,outfile)
+ File.delete(outfile) if FileTest.file?(outfile)
rescue
# debug("fatal error: #{$!}")
debug('file',outfile,'may be invalid')
@@ -421,7 +423,7 @@ class GhostScript
debug('deleting temp file')
begin
- File.delete(@@pstempfile) if test(?e,@@pstempfile)
+ File.delete(@@pstempfile) if FileTest.file?(@@pstempfile)
rescue
end
@@ -467,7 +469,7 @@ class GhostScript
# def convertcropped (inpfile, outfile)
# report("converting #{inpfile} cropped")
# do_convertbounded(inpfile, @@pdftempfile)
- # return unless test(?e,@@pdftempfile)
+ # return unless FileTest.file?(@@pdftempfile)
# arguments = " --offset=#{@offset} #{@@pdftempfile} #{outfile}"
# report("calling #{@@pdftrimwhite}")
# unless ok = System.run(@@pdftrimwhite,arguments) then
diff --git a/scripts/context/ruby/pdftools.rb b/scripts/context/ruby/pdftools.rb
index 23edfeca2..8ad74ec4f 100644
--- a/scripts/context/ruby/pdftools.rb
+++ b/scripts/context/ruby/pdftools.rb
@@ -20,7 +20,8 @@ $: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.u
require 'base/switch'
require 'base/logger'
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
class File
diff --git a/scripts/context/ruby/rlxtools.rb b/scripts/context/ruby/rlxtools.rb
index 1617fcad4..36bc9f790 100644
--- a/scripts/context/ruby/rlxtools.rb
+++ b/scripts/context/ruby/rlxtools.rb
@@ -19,7 +19,8 @@ require 'base/logger'
require 'base/system'
require 'base/kpse'
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
require 'rexml/document'
class Commands
diff --git a/scripts/context/ruby/rsfiltool.rb b/scripts/context/ruby/rsfiltool.rb
index f3abfdfc7..6d7c7aba0 100644
--- a/scripts/context/ruby/rsfiltool.rb
+++ b/scripts/context/ruby/rsfiltool.rb
@@ -18,7 +18,8 @@ end
# todo : split session stuff from xmpl/base into an xmpl/session module and "include xmpl/session" into base and here and ...
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
require 'xmpl/base'
require 'xmpl/switch'
require 'xmpl/request'
diff --git a/scripts/context/ruby/runtools.rb b/scripts/context/ruby/runtools.rb
index 9c504845a..5565748e2 100644
--- a/scripts/context/ruby/runtools.rb
+++ b/scripts/context/ruby/runtools.rb
@@ -1,5 +1,6 @@
require 'timeout'
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
require 'rbconfig'
class File
diff --git a/scripts/context/ruby/texexec.rb b/scripts/context/ruby/texexec.rb
index a09572c6c..a549659ef 100644
--- a/scripts/context/ruby/texexec.rb
+++ b/scripts/context/ruby/texexec.rb
@@ -1,8 +1,9 @@
-banner = ['TeXExec', 'version 6.2.0', '1997-2006', 'PRAGMA ADE/POD']
+banner = ['TeXExec', 'version 6.2.1', '1997-2009', 'PRAGMA ADE/POD']
$: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq!
-require 'ftools' # needed ?
+require 'fileutils'
+# require 'ftools' # needed ?
require 'base/switch'
require 'base/logger'
@@ -277,6 +278,7 @@ class Commands
info = `pdfinfo #{filename}`
if info =~ /Pages:\s*(\d+)/ then
nofpages = $1.to_i
+ result = @commandline.checkedoption('result','texexec')
nofpages.times do |i|
if f = File.open(tempfile,"w") then
n = i + 1
@@ -285,8 +287,10 @@ class Commands
f << "\\externalfigure[#{filename}][object=no,page=#{n}]\n"
f << "\\stopTEXpage\\stoptext\n"
f.close
+ job.setvariable('result',"#{result}-#{n}")
job.setvariable('interface','english') # redundant
job.setvariable('simplerun',true)
+ job.setvariable('purge',true)
job.setvariable('files',[tempfile])
job.processtex
end
diff --git a/scripts/context/ruby/texmfstart.rb b/scripts/context/ruby/texmfstart.rb
index 388bef85b..4976f7fd0 100644
--- a/scripts/context/ruby/texmfstart.rb
+++ b/scripts/context/ruby/texmfstart.rb
@@ -1,5 +1,9 @@
#!/usr/bin/env ruby
+# We have removed the fast, server and client variants and no longer
+# provide the distributed 'serve trees' option. After all, we're now
+# using luatex.
+
# program : texmfstart
# copyright : PRAGMA Advanced Document Engineering
# version : 1.9.0 - 2003/2006
@@ -18,8 +22,6 @@
# Of couse I can make this into a nice class, which i'll undoubtely will
# do when I feel the need. In that case it will be part of a bigger game.
-# turning this into a service would be nice, so some day ...
-
# --locate => provides location
# --exec => exec instead of system
# --iftouched=a,b => only if timestamp a<>b
@@ -34,30 +36,17 @@
$: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq!
require "rbconfig"
-require "md5"
+require "fileutils"
-# funny, selfmergs was suddenly broken to case problems
-
-# kpse_merge_done: require 'base/kpseremote'
-# kpse_merge_done: require 'base/kpsedirect'
-# kpse_merge_done: require 'base/kpsefast'
-# kpse_merge_done: require 'base/merge'
+require "digest/md5"
# kpse_merge_start
-# kpse_merge_file: 't:/ruby/base/kpsefast.rb'
-
-# module : base/kpsefast
-# copyright : PRAGMA Advanced Document Engineering
-# version : 2005
-# author : Hans Hagen
-#
-# project : ConTeXt / eXaMpLe
-# concept : Hans Hagen
-# info : j.hagen@xs4all.nl
-
-# todo: multiple cnf files
-#
+class File
+ def File::makedirs(*x)
+ FileUtils.makedirs(x)
+ end
+end
class String
@@ -106,1147 +95,6 @@ class File
end
-module KpseUtil
-
- # to be adapted, see loading cnf file
-
- @@texmftrees = ['texmf-local','texmf.local','../..','texmf'] # '../..' is for gwtex
- @@texmfcnf = 'texmf.cnf'
-
- def KpseUtil::identify
- # we mainly need to identify the local tex stuff and wse assume that
- # the texmfcnf variable is set; otherwise we need to expand the
- # TEXMF variable and that takes time since it may involve more
- ownpath = File.expand_path($0)
- if ownpath.gsub!(/texmf.*?$/o, '') then
- ENV['SELFAUTOPARENT'] = ownpath
- else
- ENV['SELFAUTOPARENT'] = '.' # fall back
- # may be too tricky:
- #
- # (ENV['PATH'] ||'').split_path.each do |p|
- # if p.gsub!(/texmf.*?$/o, '') then
- # ENV['SELFAUTOPARENT'] = p
- # break
- # end
- # end
- end
- filenames = Array.new
- if ENV['TEXMFCNF'] && ! ENV['TEXMFCNF'].empty? then
- ENV['TEXMFCNF'].to_s.split_path.each do |path|
- filenames << File.join(path,@@texmfcnf)
- end
- elsif ENV['SELFAUTOPARENT'] == '.' then
- filenames << File.join('.',@@texmfcnf)
- else
- @@texmftrees.each do |tree|
- filenames << File.join(ENV['SELFAUTOPARENT'],tree,'web2c',@@texmfcnf)
- end
- end
- loop do
- busy = false
- filenames.collect! do |f|
- f.gsub(/\$([a-zA-Z0-9\_\-]+)/o) do
- if (! ENV[$1]) || (ENV[$1] == $1) then
- "$#{$1}"
- else
- busy = true
- ENV[$1]
- end
- end
- end
- break unless busy
- end
- filenames.delete_if do |f|
- ! FileTest.file?(f)
- end
- return filenames
- end
-
- def KpseUtil::environment
- Hash.new.merge(ENV)
- end
-
-end
-
-class KpseFast
-
- # formats are an incredible inconsistent mess
-
- @@suffixes = Hash.new
- @@formats = Hash.new
- @@suffixmap = Hash.new
-
- @@texmfcnf = 'texmf.cnf'
-
- @@suffixes['gf'] = ['.<resolution>gf'] # todo
- @@suffixes['pk'] = ['.<resolution>pk'] # todo
- @@suffixes['tfm'] = ['.tfm']
- @@suffixes['afm'] = ['.afm']
- @@suffixes['base'] = ['.base']
- @@suffixes['bib'] = ['.bib']
- @@suffixes['bst'] = ['.bst']
- @@suffixes['cnf'] = ['.cnf']
- @@suffixes['ls-R'] = ['ls-R', 'ls-r']
- @@suffixes['fmt'] = ['.fmt', '.efmt', '.efm', '.ofmt', '.ofm', '.oft', '.eofmt', '.eoft', '.eof', '.pfmt', '.pfm', '.epfmt', '.epf', '.xpfmt', '.xpf', '.afmt', '.afm']
- @@suffixes['map'] = ['.map']
- @@suffixes['mem'] = ['.mem']
- @@suffixes['mf'] = ['.mf']
- @@suffixes['mfpool'] = ['.pool']
- @@suffixes['mft'] = ['.mft']
- @@suffixes['mp'] = ['.mp']
- @@suffixes['mppool'] = ['.pool']
- @@suffixes['ocp'] = ['.ocp']
- @@suffixes['ofm'] = ['.ofm', '.tfm']
- @@suffixes['opl'] = ['.opl']
- @@suffixes['otp'] = ['.otp']
- @@suffixes['ovf'] = ['.ovf']
- @@suffixes['ovp'] = ['.ovp']
- @@suffixes['graphic/figure'] = ['.eps', '.epsi']
- @@suffixes['tex'] = ['.tex']
- @@suffixes['texpool'] = ['.pool']
- @@suffixes['PostScript header'] = ['.pro']
- @@suffixes['type1 fonts'] = ['.pfa', '.pfb']
- @@suffixes['vf'] = ['.vf']
- @@suffixes['ist'] = ['.ist']
- @@suffixes['truetype fonts'] = ['.ttf', '.ttc']
- @@suffixes['web'] = ['.web', '.ch']
- @@suffixes['cweb'] = ['.w', '.web', '.ch']
- @@suffixes['enc files'] = ['.enc']
- @@suffixes['cmap files'] = ['.cmap']
- @@suffixes['subfont definition files'] = ['.sfd']
- @@suffixes['lig files'] = ['.lig']
- @@suffixes['bitmap font'] = []
- @@suffixes['MetaPost support'] = []
- @@suffixes['TeX system documentation'] = []
- @@suffixes['TeX system sources'] = []
- @@suffixes['Troff fonts'] = []
- @@suffixes['dvips config'] = []
- @@suffixes['type42 fonts'] = []
- @@suffixes['web2c files'] = []
- @@suffixes['other text files'] = []
- @@suffixes['other binary files'] = []
- @@suffixes['misc fonts'] = []
- @@suffixes['opentype fonts'] = []
- @@suffixes['pdftex config'] = []
- @@suffixes['texmfscripts'] = []
-
- # replacements
-
- @@suffixes['fmt'] = ['.fmt']
- @@suffixes['type1 fonts'] = ['.pfa', '.pfb', '.pfm']
- @@suffixes['tex'] = ['.tex', '.xml']
- @@suffixes['texmfscripts'] = ['rb','lua','py','pl']
-
- @@suffixes.keys.each do |k| @@suffixes[k].each do |s| @@suffixmap[s] = k end end
-
- # TTF2TFMINPUTS
- # MISCFONTS
- # TEXCONFIG
- # DVIPDFMINPUTS
- # OTFFONTS
-
- @@formats['gf'] = ''
- @@formats['pk'] = ''
- @@formats['tfm'] = 'TFMFONTS'
- @@formats['afm'] = 'AFMFONTS'
- @@formats['base'] = 'MFBASES'
- @@formats['bib'] = ''
- @@formats['bst'] = ''
- @@formats['cnf'] = ''
- @@formats['ls-R'] = ''
- @@formats['fmt'] = 'TEXFORMATS'
- @@formats['map'] = 'TEXFONTMAPS'
- @@formats['mem'] = 'MPMEMS'
- @@formats['mf'] = 'MFINPUTS'
- @@formats['mfpool'] = 'MFPOOL'
- @@formats['mft'] = ''
- @@formats['mp'] = 'MPINPUTS'
- @@formats['mppool'] = 'MPPOOL'
- @@formats['ocp'] = 'OCPINPUTS'
- @@formats['ofm'] = 'OFMFONTS'
- @@formats['opl'] = 'OPLFONTS'
- @@formats['otp'] = 'OTPINPUTS'
- @@formats['ovf'] = 'OVFFONTS'
- @@formats['ovp'] = 'OVPFONTS'
- @@formats['graphic/figure'] = ''
- @@formats['tex'] = 'TEXINPUTS'
- @@formats['texpool'] = 'TEXPOOL'
- @@formats['PostScript header'] = 'TEXPSHEADERS'
- @@formats['type1 fonts'] = 'T1FONTS'
- @@formats['vf'] = 'VFFONTS'
- @@formats['ist'] = ''
- @@formats['truetype fonts'] = 'TTFONTS'
- @@formats['web'] = ''
- @@formats['cweb'] = ''
- @@formats['enc files'] = 'ENCFONTS'
- @@formats['cmap files'] = 'CMAPFONTS'
- @@formats['subfont definition files'] = 'SFDFONTS'
- @@formats['lig files'] = 'LIGFONTS'
- @@formats['bitmap font'] = ''
- @@formats['MetaPost support'] = ''
- @@formats['TeX system documentation'] = ''
- @@formats['TeX system sources'] = ''
- @@formats['Troff fonts'] = ''
- @@formats['dvips config'] = ''
- @@formats['type42 fonts'] = 'T42FONTS'
- @@formats['web2c files'] = 'WEB2C'
- @@formats['other text files'] = ''
- @@formats['other binary files'] = ''
- @@formats['misc fonts'] = ''
- @@formats['opentype fonts'] = 'OPENTYPEFONTS'
- @@formats['pdftex config'] = 'PDFTEXCONFIG'
- @@formats['texmfscripts'] = 'TEXMFSCRIPTS'
-
- attr_accessor :progname, :engine, :format, :rootpath, :treepath,
- :verbose, :remember, :scandisk, :diskcache, :renewcache
-
- @@cacheversion = '1'
-
- def initialize
- @rootpath = ''
- @treepath = ''
- @progname = 'kpsewhich'
- @engine = 'pdftex'
- @variables = Hash.new
- @expansions = Hash.new
- @files = Hash.new
- @found = Hash.new
- @kpsevars = Hash.new
- @lsrfiles = Array.new
- @cnffiles = Array.new
- @verbose = true
- @remember = true
- @scandisk = true
- @diskcache = true
- @renewcache = false
- @isolate = false
-
- @diskcache = false
- @cachepath = nil
- @cachefile = 'tmftools.log'
-
- @environment = ENV
- end
-
- def set(key,value)
- case key
- when 'progname' then @progname = value
- when 'engine' then @engine = value
- when 'format' then @format = value
- end
- end
-
- def push_environment(env)
- @environment = env
- end
-
- # {$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
- #
- # $SELFAUTOLOC : /usr/tex/bin/platform
- # $SELFAUTODIR : /usr/tex/bin
- # $SELFAUTOPARENT : /usr/tex
- #
- # since we live in scriptpath we need a slightly different method
-
- def load_cnf(filenames=nil)
- unless filenames then
- ownpath = File.expand_path($0)
- if ownpath.gsub!(/texmf.*?$/o, '') then
- @environment['SELFAUTOPARENT'] = ownpath
- else
- @environment['SELFAUTOPARENT'] = '.'
- end
- unless @treepath.empty? then
- unless @rootpath.empty? then
- @treepath = @treepath.split(',').collect do |p| File.join(@rootpath,p) end.join(',')
- end
- @environment['TEXMF'] = @treepath
- # only the first one
- @environment['TEXMFCNF'] = File.join(@treepath.split(',').first,'texmf/web2c')
- end
- unless @rootpath.empty? then
- @environment['TEXMFCNF'] = File.join(@rootpath,'texmf/web2c')
- @environment['SELFAUTOPARENT'] = @rootpath
- @isolate = true
- end
- filenames = Array.new
- if @environment['TEXMFCNF'] and not @environment['TEXMFCNF'].empty? then
- @environment['TEXMFCNF'].to_s.split_path.each do |path|
- filenames << File.join(path,@@texmfcnf)
- end
- elsif @environment['SELFAUTOPARENT'] == '.' then
- filenames << File.join('.',@@texmfcnf)
- else
- ['texmf-local','texmf'].each do |tree|
- filenames << File.join(@environment['SELFAUTOPARENT'],tree,'web2c',@@texmfcnf)
- end
- end
- end
- # <root>/texmf/web2c/texmf.cnf
- filenames = _expanded_path_(filenames)
- @rootpath = filenames.first
- 3.times do
- @rootpath = File.dirname(@rootpath)
- end
- filenames.collect! do |f|
- f.gsub("\\", '/')
- end
- filenames.each do |fname|
- if FileTest.file?(fname) and f = File.open(fname) then
- @cnffiles << fname
- while line = f.gets do
- loop do
- # concatenate lines ending with \
- break unless line.sub!(/\\\s*$/o) do
- f.gets || ''
- end
- end
- case line
- when /^[\%\#]/o then
- # comment
- when /^\s*(.*?)\s*\=\s*(.*?)\s*$/o then
- key, value = $1, $2
- unless @variables.key?(key) then
- value.sub!(/\%.*$/,'')
- value.sub!(/\~/, "$HOME")
- @variables[key] = value
- end
- @kpsevars[key] = true
- end
- end
- f.close
- end
- end
- end
-
- def load_lsr
- @lsrfiles = []
- simplified_list(expansion('TEXMF')).each do |p|
- ['ls-R','ls-r'].each do |f|
- filename = File.join(p,f)
- if FileTest.file?(filename) then
- @lsrfiles << [filename,File.size(filename)]
- break
- end
- end
- end
- @files = Hash.new
- if @diskcache then
- ['HOME','TEMP','TMP','TMPDIR'].each do |key|
- if @environment[key] then
- if FileTest.directory?(@environment[key]) then
- @cachepath = @environment[key]
- @cachefile = [@rootpath.gsub(/[^A-Z0-9]/io, '-').gsub(/\-+/,'-'),File.basename(@cachefile)].join('-')
- break
- end
- end
- end
- if @cachepath and not @renewcache and FileTest.file?(File.join(@cachepath,@cachefile)) then
- begin
- if f = File.open(File.join(@cachepath,@cachefile)) then
- cacheversion = Marshal.load(f)
- if cacheversion == @@cacheversion then
- lsrfiles = Marshal.load(f)
- if lsrfiles == @lsrfiles then
- @files = Marshal.load(f)
- end
- end
- f.close
- end
- rescue
- @files = Hash.new
- end
- end
- end
- return if @files.size > 0
- @lsrfiles.each do |filedata|
- filename, filesize = filedata
- filepath = File.dirname(filename)
- begin
- path = '.'
- data = IO.readlines(filename)
- if data[0].chomp =~ /% ls\-R \-\- filename database for kpathsea\; do not change this line\./io then
- data.each do |line|
- case line
- when /^[a-zA-Z0-9]/o then
- line.chomp!
- if @files[line] then
- @files[line] << path
- else
- @files[line] = [path]
- end
- when /^\.\/(.*?)\:$/o then
- path = File.join(filepath,$1)
- end
- end
- end
- rescue
- # sorry
- end
- end
- if @diskcache and @cachepath and f = File.open(File.join(@cachepath,@cachefile),'wb') then
- f << Marshal.dump(@@cacheversion)
- f << Marshal.dump(@lsrfiles)
- f << Marshal.dump(@files)
- f.close
- end
- end
-
- def expand_variables
- @expansions = Hash.new
- if @isolate then
- @variables['TEXMFCNF'] = @environment['TEXMFCNF'].dup
- @variables['SELFAUTOPARENT'] = @environment['SELFAUTOPARENT'].dup
- else
- @environment.keys.each do |e|
- if e =~ /^([a-zA-Z]+)\_(.*)\s*$/o then
- @expansions["#{$1}.#{$2}"] = (@environment[e] ||'').dup
- else
- @expansions[e] = (@environment[e] ||'').dup
- end
- end
- end
- @variables.keys.each do |k|
- @expansions[k] = @variables[k].dup unless @expansions[k]
- end
- loop do
- busy = false
- @expansions.keys.each do |k|
- @expansions[k].gsub!(/\$([a-zA-Z0-9\_\-]*)/o) do
- busy = true
- @expansions[$1] || ''
- end
- @expansions[k].gsub!(/\$\{([a-zA-Z0-9\_\-]*)\}/o) do
- busy = true
- @expansions[$1] || ''
- end
- end
- break unless busy
- end
- @expansions.keys.each do |k|
- @expansions[k] = @expansions[k].gsub("\\", '/')
- end
- end
-
- def variable(name='')
- (name and not name.empty? and @variables[name.sub('$','')]) or ''
- end
-
- def expansion(name='')
- (name and not name.empty? and @expansions[name.sub('$','')]) or ''
- end
-
- def variable?(name='')
- name and not name.empty? and @variables.key?(name.sub('$',''))
- end
-
- def expansion?(name='')
- name and not name.empty? and @expansions.key?(name.sub('$',''))
- end
-
- def simplified_list(str)
- lst = str.gsub(/^\{/o,'').gsub(/\}$/o,'').split(",")
- lst.collect do |l|
- l.sub(/^[\!]*/,'').sub(/[\/\\]*$/o,'')
- end
- end
-
- def original_variable(variable)
- if variable?("#{@progname}.#{variable}") then
- variable("#{@progname}.#{variable}")
- elsif variable?(variable) then
- variable(variable)
- else
- ''
- end
- end
-
- def expanded_variable(variable)
- if expansion?("#{variable}.#{@progname}") then
- expansion("#{variable}.#{@progname}")
- elsif expansion?(variable) then
- expansion(variable)
- else
- ''
- end
- end
-
- def original_path(filename='')
- _expanded_path_(original_variable(var_of_format_or_suffix(filename)).split(";"))
- end
-
- def expanded_path(filename='')
- _expanded_path_(expanded_variable(var_of_format_or_suffix(filename)).split(";"))
- end
-
- def _expanded_path_(pathlist)
- i, n = 0, 0
- pathlist.collect! do |mainpath|
- mainpath.gsub(/([\{\}])/o) do
- if $1 == "{" then
- i += 1 ; n = i if i > n ; "<#{i}>"
- else
- i -= 1 ; "</#{i+1}>"
- end
- end
- end
- n.times do |i|
- loop do
- more = false
- newlist = []
- pathlist.each do |path|
- unless path.sub!(/^(.*?)<(#{n-i})>(.*?)<\/\2>(.*?)$/) do
- pre, mid, post = $1, $3, $4
- mid.gsub!(/\,$/,',.')
- mid.split(',').each do |m|
- more = true
- if m == '.' then
- newlist << "#{pre}#{post}"
- else
- newlist << "#{pre}#{m}#{post}"
- end
- end
- end then
- newlist << path
- end
- end
- if more then
- pathlist = [newlist].flatten # copy -)
- else
- break
- end
- end
- end
- pathlist = pathlist.uniq.collect do |path|
- p = path
- # p.gsub(/^\/+/o) do '' end
- # p.gsub!(/(.)\/\/(.)/o) do "#{$1}/#{$2}" end
- # p.gsub!(/\/\/+$/o) do '//' end
- p.gsub!(/\/\/+/o) do '//' end
- p
- end
- pathlist
- end
-
- # todo: ignore case
-
- def var_of_format(str)
- @@formats[str] || ''
- end
-
- def var_of_suffix(str) # includes .
- if @@suffixmap.key?(str) then @@formats[@@suffixmap[str]] else '' end
- end
-
- def var_of_format_or_suffix(str)
- if @@formats.key?(str) then
- @@formats[str]
- elsif @@suffixmap.key?(File.extname(str)) then # extname includes .
- @@formats[@@suffixmap[File.extname(str)]] # extname includes .
- else
- ''
- end
- end
-
-end
-
-class KpseFast
-
- # test things
-
- def list_variables(kpseonly=true)
- @variables.keys.sort.each do |k|
- if kpseonly then
- puts("#{k} = #{@variables[k]}") if @kpsevars[k]
- else
- puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@variables[k]}")
- end
- end
- end
-
- def list_expansions(kpseonly=true)
- @expansions.keys.sort.each do |k|
- if kpseonly then
- puts("#{k} = #{@expansions[k]}") if @kpsevars[k]
- else
- puts("#{if @kpsevars[k] then 'K' else 'E' end} #{k} = #{@expansions[k]}")
- end
- end
- end
-
- def list_lsr
- puts("files = #{@files.size}")
- end
-
- def set_test_patterns
- @variables["KPSE_TEST_PATTERN_A"] = "foo/{1,2}/bar//"
- @variables["KPSE_TEST_PATTERN_B"] = "!!x{A,B{1,2}}y"
- @variables["KPSE_TEST_PATTERN_C"] = "x{A,B//{1,2}}y"
- @variables["KPSE_TEST_PATTERN_D"] = "x{A,B//{1,2,}}//y"
- end
-
- def show_test_patterns
- ['A','B','D'].each do |i|
- puts ""
- puts @variables ["KPSE_TEST_PATTERN_#{i}"]
- puts ""
- puts expand_path("KPSE_TEST_PATTERN_#{i}").split_path
- puts ""
- end
- end
-
-end
-
-class KpseFast
-
- # kpse stuff
-
- def expand_braces(str) # output variable and brace expansion of STRING.
- _expanded_path_(original_variable(str).split_path).join_path
- end
-
- def expand_path(str) # output complete path expansion of STRING.
- _expanded_path_(expanded_variable(str).split_path).join_path
- end
-
- def expand_var(str) # output variable expansion of STRING.
- expanded_variable(str)
- end
-
- def show_path(str) # output search path for file type NAME
- expanded_path(str).join_path
- end
-
- def var_value(str) # output the value of variable $STRING.
- original_variable(str)
- end
-
-end
-
-class KpseFast
-
- def _is_cnf_?(filename)
- filename == File.basename((@cnffiles.first rescue @@texmfcnf) || @@texmfcnf)
- end
-
- def find_file(filename)
- if _is_cnf_?(filename) then
- @cnffiles.first rescue ''
- else
- [find_files(filename,true)].flatten.first || ''
- end
- end
-
- def find_files(filename,first=false)
- if _is_cnf_?(filename) then
- result = @cnffiles.dup
- else
- if @remember then
- # stamp = "#{filename}--#{@format}--#{@engine}--#{@progname}"
- stamp = "#{filename}--#{@engine}--#{@progname}"
- return @found[stamp] if @found.key?(stamp)
- end
- pathlist = expanded_path(filename)
- result = []
- filelist = if @files.key?(filename) then @files[filename].uniq else nil end
- done = false
- if pathlist.size == 0 then
- if FileTest.file?(filename) then
- done = true
- result << '.'
- end
- else
- pathlist.each do |path|
- doscan = if path =~ /^\!\!/o then false else true end
- recurse = if path =~ /\/\/$/o then true else false end
- pathname = path.dup
- pathname.gsub!(/^\!+/o, '')
- done = false
- if not done and filelist then
- # checking for exact match
- if filelist.include?(pathname) then
- result << pathname
- done = true
- end
- if not done and recurse then
- # checking for fuzzy //
- pathname.gsub!(/\/+$/o, '/.*')
- # pathname.gsub!(/\/\//o,'/[\/]*/')
- pathname.gsub!(/\/\//o,'/.*?/')
- re = /^#{pathname}/
- filelist.each do |f|
- if re =~ f then
- result << f # duplicates will be filtered later
- done = true
- end
- break if done
- end
- end
- end
- if not done and doscan then
- # checking for path itself
- pname = pathname.sub(/\.\*$/,'')
- if not pname =~ /\*/o and FileTest.file?(File.join(pname,filename)) then
- result << pname
- done = true
- end
- end
- break if done and first
- end
- end
- if not done and @scandisk then
- pathlist.each do |path|
- pathname = path.dup
- unless pathname.gsub!(/^\!+/o, '') then # !! prevents scan
- recurse = pathname.gsub!(/\/+$/o, '')
- complex = pathname.gsub!(/\/\//o,'/*/')
- if recurse then
- if complex then
- if ok = File.glob_file("#{pathname}/**/#{filename}") then
- result << File.dirname(ok)
- done = true
- end
- elsif ok = File.locate_file(pathname,filename) then
- result << File.dirname(ok)
- done = true
- end
- elsif complex then
- if ok = File.glob_file("#{pathname}/#{filename}") then
- result << File.dirname(ok)
- done = true
- end
- elsif FileTest.file?(File.join(pathname,filename)) then
- result << pathname
- done = true
- end
- break if done and first
- end
- end
- end
- result = result.uniq.collect do |pathname|
- File.join(pathname,filename)
- end
- @found[stamp] = result if @remember
- end
- return result # redundant
- end
-
-end
-
-class KpseFast
-
- class FileData
- attr_accessor :tag, :name, :size, :date
- def initialize(tag=0,name=nil,size=nil,date=nil)
- @tag, @name, @size, @date = tag, name, size, date
- end
- def FileData.sizes(a)
- a.collect do |aa|
- aa.size
- end
- end
- def report
- case @tag
- when 1 then "deleted | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
- when 2 then "present | #{@size.to_s.rjust(8)} | #{@date.strftime('%m/%d/%Y %I:%M')} | #{@name}"
- when 3 then "obsolete | #{' '*8} | #{' '*16} | #{@name}"
- end
- end
- end
-
- def analyze_files(filter='',strict=false,sort='',delete=false)
- puts("command line = #{ARGV.join(' ')}")
- puts("number of files = #{@files.size}")
- puts("filter pattern = #{filter}")
- puts("loaded cnf files = #{@cnffiles.join(' ')}")
- puts('')
- if filter.gsub!(/^not:/,'') then
- def the_same(filter,filename)
- not filter or filter.empty? or /#{filter}/ !~ filename
- end
- else
- def the_same(filter,filename)
- not filter or filter.empty? or /#{filter}/ =~ filename
- end
- end
- @files.keys.each do |name|
- if @files[name].size > 1 then
- data = Array.new
- @files[name].each do |path|
- filename = File.join(path,name)
- # if not filter or filter.empty? or /#{filter}/ =~ filename then
- if the_same(filter,filename) then
- if FileTest.file?(filename) then
- if delete then
- data << FileData.new(1,filename,File.size(filename),File.mtime(filename))
- begin
- File.delete(filename) if delete
- rescue
- end
- else
- data << FileData.new(2,filename,File.size(filename),File.mtime(filename))
- end
- else
- # data << FileData.new(3,filename)
- end
- end
- end
- if data.length > 1 then
- if strict then
- # if data.collect do |d| d.size end.uniq! then
- # data.sort! do |a,b| b.size <=> a.size end
- # data.each do |d| puts d.report end
- # puts ''
- # end
- data.sort! do |a,b|
- if a.size and b.size then
- b.size <=> a.size
- else
- 0
- end
- end
- bunch = Array.new
- done = false
- data.each do |d|
- if bunch.size == 0 then
- bunch << d
- elsif bunch[0].size == d.size then
- bunch << d
- else
- if bunch.size > 1 then
- bunch.each do |b|
- puts b.report
- end
- done = true
- end
- bunch = [d]
- end
- end
- puts '' if done
- else
- case sort
- when 'size' then data.sort! do |a,b| a.size <=> b.size end
- when 'revsize' then data.sort! do |a,b| b.size <=> a.size end
- when 'date' then data.sort! do |a,b| a.date <=> b.date end
- when 'revdate' then data.sort! do |a,b| b.date <=> a.date end
- end
- data.each do |d| puts d.report end
- puts ''
- end
- end
- end
- end
- end
-
-end
-
-
- # k = KpseFast.new # (root)
- # k.set_test_patterns
- # k.load_cnf
- # k.expand_variables
- # k.load_lsr
-
- # k.show_test_patterns
-
- # puts k.list_variables
- # puts k.list_expansions
- # k.list_lsr
- # puts k.expansion("$TEXMF")
- # puts k.expanded_path("TEXINPUTS","context")
-
- # k.progname, k.engine, k.format = 'context', 'pdftex', 'tfm'
- # k.scandisk = false # == must_exist
- # k.expand_variables
-
- # 10.times do |i| puts k.find_file('texnansi-lmr10.tfm') end
-
- # puts "expand braces $TEXMF"
- # puts k.expand_braces("$TEXMF")
- # puts "expand path $TEXMF"
- # puts k.expand_path("$TEXMF")
- # puts "expand var $TEXMF"
- # puts k.expand_var("$TEXMF")
- # puts "expand path $TEXMF"
- # puts k.show_path('tfm')
- # puts "expand value $TEXINPUTS"
- # puts k.var_value("$TEXINPUTS")
- # puts "expand value $TEXINPUTS.context"
- # puts k.var_value("$TEXINPUTS.context")
-
- # exit
-
-
-
-# kpse_merge_file: 't:/ruby/base/kpse/trees.rb'
-
-require 'monitor'
-# kpse_merge_done: require 'base/kpsefast'
-
-class KpseTrees < Monitor
-
- def initialize
- @trees = Hash.new
- end
-
- def pattern(filenames)
- filenames.join('|').gsub(/\\+/o,'/').downcase
- end
-
- def choose(filenames,environment)
- current = pattern(filenames)
- load(filenames,environment) unless @trees[current]
- puts "enabling tree #{current}"
- current
- end
-
- def fetch(filenames,environment) # will send whole object !
- current = pattern(filenames)
- load(filenames,environment) unless @trees[current]
- puts "fetching tree #{current}"
- @trees[current]
- end
-
- def load(filenames,environment)
- current = pattern(filenames)
- puts "loading tree #{current}"
- @trees[current] = KpseFast.new
- @trees[current].push_environment(environment)
- @trees[current].load_cnf(filenames)
- @trees[current].expand_variables
- @trees[current].load_lsr
- end
-
- def set(tree,key,value)
- case key
- when 'progname' then @trees[tree].progname = value
- when 'engine' then @trees[tree].engine = value
- when 'format' then @trees[tree].format = value
- end
- end
- def get(tree,key)
- case key
- when 'progname' then @trees[tree].progname
- when 'engine' then @trees[tree].engine
- when 'format' then @trees[tree].format
- end
- end
-
- def load_cnf(tree)
- @trees[tree].load_cnf
- end
- def load_lsr(tree)
- @trees[tree].load_lsr
- end
- def expand_variables(tree)
- @trees[tree].expand_variables
- end
- def expand_braces(tree,str)
- @trees[tree].expand_braces(str)
- end
- def expand_path(tree,str)
- @trees[tree].expand_path(str)
- end
- def expand_var(tree,str)
- @trees[tree].expand_var(str)
- end
- def show_path(tree,str)
- @trees[tree].show_path(str)
- end
- def var_value(tree,str)
- @trees[tree].var_value(str)
- end
- def find_file(tree,filename)
- @trees[tree].find_file(filename)
- end
- def find_files(tree,filename,first)
- @trees[tree].find_files(filename,first)
- end
-
-end
-
-
-# kpse_merge_file: 't:/ruby/base/kpse/drb.rb'
-
-require 'drb'
-# kpse_merge_done: require 'base/kpse/trees'
-
-class KpseServer
-
- attr_accessor :port
-
- def initialize(port=7000)
- @port = port
- end
-
- def start
- puts "starting drb service at port #{@port}"
- DRb.start_service("druby://localhost:#{@port}", KpseTrees.new)
- trap(:INT) do
- DRb.stop_service
- end
- DRb.thread.join
- end
-
- def stop
- # todo
- end
-
-end
-
-class KpseClient
-
- attr_accessor :port
-
- def initialize(port=7000)
- @port = port
- @kpse = nil
- end
-
- def start
- # only needed when callbacks are used / slow, due to Socket::getaddrinfo
- # DRb.start_service
- end
-
- def object
- @kpse = DRbObject.new(nil,"druby://localhost:#{@port}")
- end
-
-end
-
-
-# SERVER_URI="druby://localhost:8787"
-#
-# # Start a local DRbServer to handle callbacks.
-# #
-# # Not necessary for this small example, but will be required
-# # as soon as we pass a non-marshallable object as an argument
-# # to a dRuby call.
-# DRb.start_service
-#
-
-
-# kpse_merge_file: 't:/ruby/base/kpseremote.rb'
-
-# kpse_merge_done: require 'base/kpsefast'
-
-case ENV['KPSEMETHOD']
- when /soap/o then # kpse_merge_done: require 'base/kpse/soap'
- when /drb/o then # kpse_merge_done: require 'base/kpse/drb'
- else # kpse_merge_done: require 'base/kpse/drb'
-end
-
-class KpseRemote
-
- @@port = ENV['KPSEPORT'] || 7000
- @@method = ENV['KPSEMETHOD'] || 'drb'
-
- def KpseRemote::available?
- @@method && @@port
- end
-
- def KpseRemote::start_server(port=nil)
- kpse = KpseServer.new(port || @@port)
- kpse.start
- end
-
- def KpseRemote::start_client(port=nil) # keeps object in server
- kpseclient = KpseClient.new(port || @@port)
- kpseclient.start
- kpse = kpseclient.object
- tree = kpse.choose(KpseUtil::identify, KpseUtil::environment)
- [kpse, tree]
- end
-
- def KpseRemote::fetch(port=nil) # no need for defining methods but slower, send whole object
- kpseclient = KpseClient.new(port || @@port)
- kpseclient.start
- kpseclient.object.fetch(KpseUtil::identify, KpseUtil::environment) rescue nil
- end
-
- def initialize(port=nil)
- if KpseRemote::available? then
- begin
- @kpse, @tree = KpseRemote::start_client(port)
- rescue
- @kpse, @tree = nil, nil
- end
- else
- @kpse, @tree = nil, nil
- end
- end
-
- def progname=(value)
- @kpse.set(@tree,'progname',value)
- end
- def format=(value)
- @kpse.set(@tree,'format',value)
- end
- def engine=(value)
- @kpse.set(@tree,'engine',value)
- end
-
- def progname
- @kpse.get(@tree,'progname')
- end
- def format
- @kpse.get(@tree,'format')
- end
- def engine
- @kpse.get(@tree,'engine')
- end
-
- def load
- @kpse.load(KpseUtil::identify, KpseUtil::environment)
- end
- def okay?
- @kpse && @tree
- end
- def set(key,value)
- @kpse.set(@tree,key,value)
- end
- def load_cnf
- @kpse.load_cnf(@tree)
- end
- def load_lsr
- @kpse.load_lsr(@tree)
- end
- def expand_variables
- @kpse.expand_variables(@tree)
- end
- def expand_braces(str)
- clean_name(@kpse.expand_braces(@tree,str))
- end
- def expand_path(str)
- clean_name(@kpse.expand_path(@tree,str))
- end
- def expand_var(str)
- clean_name(@kpse.expand_var(@tree,str))
- end
- def show_path(str)
- clean_name(@kpse.show_path(@tree,str))
- end
- def var_value(str)
- clean_name(@kpse.var_value(@tree,str))
- end
- def find_file(filename)
- clean_name(@kpse.find_file(@tree,filename))
- end
- def find_files(filename,first=false)
- # dodo: each filename
- @kpse.find_files(@tree,filename,first)
- end
-
- private
-
- def clean_name(str)
- str.gsub(/\\/,'/')
- end
-
-end
-
-
# kpse_merge_file: 't:/ruby/base/kpsedirect.rb'
class KpseDirect
@@ -1284,14 +132,11 @@ class KpseDirect
end
-
# kpse_merge_stop
-
-
$mswindows = Config::CONFIG['host_os'] =~ /mswin/
$separator = File::PATH_SEPARATOR
-$version = "2.0.3"
+$version = "2.1.0"
$ownpath = File.dirname($0)
if $mswindows then
@@ -1335,7 +180,7 @@ $predefined['ctxtools'] = 'ctxtools.rb'
$predefined['rlxtools'] = 'rlxtools.rb'
$predefined['pdftools'] = 'pdftools.rb'
$predefined['mpstools'] = 'mpstools.rb'
-$predefined['exatools'] = 'exatools.rb'
+# $predefined['exatools'] = 'exatools.rb'
$predefined['xmltools'] = 'xmltools.rb'
# $predefined['luatools'] = 'luatools.lua'
# $predefined['mtxtools'] = 'mtxtools.rb'
@@ -1412,22 +257,7 @@ def check_kpse
if $kpse then
# already done
else
- begin
- if KpseRemote::available? then
- $kpse = KpseRemote.new
- if $kpse.okay? then
- puts("kpse : remote") if $verbose
- else
- $kpse = KpseDirect.new
- puts("kpse : direct (forced)") if $verbose
- end
- else
- $kpse = KpseDirect.new
- puts("kpse : direct") if $verbose
- end
- rescue
- puts("kpse : direct (fallback)") if $verbose
- end
+ $kpse = KpseDirect.new
end
end
@@ -1488,18 +318,6 @@ end
class File
- # def File.needsupdate(oldname,newname)
- # begin
- # if $mswindows then
- # return File.stat(oldname).mtime > File.stat(newname).mtime
- # else
- # return File.stat(oldname).mtime != File.stat(newname).mtime
- # end
- # rescue
- # return true
- # end
- # end
-
@@update_eps = 1
def File.needsupdate(oldname,newname)
@@ -1543,33 +361,6 @@ class File
end
-# def hashed (arr=[])
- # arg = if arr.class == String then arr.split(' ') else arr.dup end
- # hsh = Hash.new
- # if arg.length > 0
- # hsh['arguments'] = ''
- # done = false
- # arg.each do |s|
- # if done then
- # if s =~ / / then
- # hsh['arguments'] += " \"#{s}\"" # maybe split on =
- # else
- # hsh['arguments'] += " #{s}"
- # end
- # else
- # kvl = s.split('=')
- # if kvl[0].sub!(/^\-+/,'') then
- # hsh[kvl[0]] = if kvl.length > 1 then kvl[1] else true end
- # else
- # hsh['file'] = s
- # done = true
- # end
- # end
- # end
- # end
- # return hsh
-# end
-
def hashed (arr=[])
arg = if arr.class == String then arr.split(' ') else arr.dup end
hsh = Hash.new
@@ -2115,12 +906,6 @@ end
def make(filename,windows=false,linux=false,remove=false)
basename = File.basename(filename).gsub(/\.[^.]+?$/, '')
-# if @kpse.find_file(@tree,filename+".lua") or @kpse.find_file(@tree,filename+".rb") or @kpse.find_file(@tree,filename+".pl") then
- # make stub indeed
-# else
- # report("no stub needed for '#{basename}'")
- # return
-# end
if $stubpath == 'auto' then
basename = File.dirname($0) + '/' + basename
else
@@ -2203,7 +988,7 @@ def process(&block)
checkname = filename + ".md5"
oldchecksum, newchecksum = "old", "new"
begin
- newchecksum = MD5.new(IO.read(filename)).hexdigest.upcase
+ newchecksum = Digest::MD5.hexdigest(IO.read(filename)).upcase
rescue
newchecksum = "new"
else
@@ -2423,22 +1208,6 @@ def execute(arguments) # br global
elsif $selfcleanup then
output("ruby libraries are cleaned up") if SelfMerge::cleanup
return true
- elsif $serve then
- if ENV['KPSEMETHOD'] && ENV['KPSEPORT'] then
- # # kpse_merge_done: require 'base/kpseremote'
- begin
- KpseRemote::start_server
- rescue
- return false
- else
- return true
- end
- else
- usage
- puts("")
- puts("message : set 'KPSEMETHOD' and 'KPSEPORT' variables")
- return false
- end
elsif $help || ! $filename || $filename.empty? then
usage
loadtree($tree)
diff --git a/scripts/context/ruby/textools.rb b/scripts/context/ruby/textools.rb
index 442dc1924..a5858c5ca 100644
--- a/scripts/context/ruby/textools.rb
+++ b/scripts/context/ruby/textools.rb
@@ -20,7 +20,8 @@ $: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.u
require 'base/switch'
require 'base/logger'
-require 'ftools'
+require 'fileutils'
+# require 'ftools'
# Remark
#
diff --git a/scripts/context/ruby/www/admin.rb b/scripts/context/ruby/www/admin.rb
deleted file mode 100644
index 8983ca2b7..000000000
--- a/scripts/context/ruby/www/admin.rb
+++ /dev/null
@@ -1,215 +0,0 @@
-require 'fileutils'
-
-require 'www/lib'
-require 'www/dir'
-require 'www/common'
-
-class WWW
-
- include Common
-
- # klopt nog niet, twee keer task met een verschillend doel
-
- def handle_exatask
- # case @session.check('task', request_variable('task'))
- task, options, option = @session.get('task'), @session.get('option').split(@@re_bar), request_variable('option')
- option = (options.first || '') if option.empty?
- case task
- when 'exaadmin'
- @session.set('status', 'admin') # admin: status|dir
- touch_session(@session.get('id'))
- if options.include?(option) then
- case option
- when 'status' then handle_exaadmin_status
- when 'dir' then handle_exaadmin_dir
- else handle_exaadmin_status
- end
- elsif option.empty? then
- message('Status', "unknown option")
- else
- message('Status', "option '#{option}' not permitted #{options.inspect}")
- end
- else
- message('Status', "unknown task '#{task}'")
- end
- end
-
- def handle_exaadmin
- if id = valid_session() then
- handle_exatask
- else
- message('Status', 'no login')
- end
- end
-
- def handle_exaadmin_dir
- check_template_file('exalogin','exalogin-template.htm')
- @interface.set('path:docroot', work_root)
- @interface.set('dir:uri', 'exaadmin') # forces the dir handler into cgi mode
- @interface.set('dir:task', 'exaadmin') # forces the dir handler into cgi mode
- @interface.set('dir:option', 'dir') # forces the dir handler into cgi mode
- filename = "#{@@session_prefix}#{request_variable('path')}"
- fullname = File.join(work_root,filename)
- if request_variable('path').empty? then
- handle_exaadmin_status
- elsif FileTest.directory?(fullname) then
- handle_dir(filename, [], false)
- elsif File.zero?(fullname) then
- message('Error', "The file '#{filename}' is empty")
- elsif File.size?(fullname) > (4 * 1024 * 1024) then
- if FileTest.file?(File.expand_path(File.join(cache_root,filename))) then
- str = "<br/><br/>Cached alternative: <a href=\"#{File.join('cache',filename)}\">#{File.basename(filename)}</a>"
- else
- str = ''
- end
- message('Error', "The file '#{filename}' is too big to serve over cgi." + str)
- else
- send_file(fullname)
- end
- end
-
- def handle_exaadmin_status
- check_template_file('exalogin','exalogin-template.htm')
- begin
- n, str, lines, list, start, most, least, cached = 0, '', '', Hash.new, Time.now, 0, 0, false
- filename = File.join(tmp_path(dirname),'sessions.rbd')
- begin
- File.open(filename) do |f|
- list = Marshal.load(f)
- end
- rescue
- cached, list = false, Hash.new
- else
- cached = true
- end
- files = Dir.glob("{#{work_roots.join(',')}}/#{@@session_prefix}*.ses")
- list.keys.each do |l|
- list.delete(l) unless files.include?(l) # slow
- end
- files.each do |f|
- ctime = File.ctime(f)
- stime = list[f][0] == ctime rescue 0
- unless ctime == stime then
- begin
- hash = load_session_file(f)
- rescue
- else
- list[f] = [ctime,hash]
- end
- end
- end
- begin
- File.open(filename,'w') do |f|
- f << Marshal.dump(list)
- end
- rescue
- # no save
- end
- begin
- keys = list.keys.sort do |a,b|
- case list[b][0] <=> list[a][0]
- when -1 then -1
- when +1 then +1
- else
- a <=> b
- end
- end
- rescue
- keys = list.keys.sort
- end
- totaltime, totaldone = 0.0, 0
- if keys.length > 0 then
- keys.each do |entry|
- s, t, session = entry, list[entry][0], list[entry][1]
- status = session['status'] || ''
- runtime = (session['runtime'] || '').to_f rescue 0
- starttime = (start.to_i-session['starttime'].to_i).to_s rescue ''
- requesttime = session['endtime'].to_i-session['starttime'].to_i rescue 0
- requesttime = if requesttime > 0 then requesttime.to_s else '' end
- if runtime > 0.0 then
- totaltime += runtime
- totaldone += 1
- if least > 0 then
- if runtime < least then least = runtime end
- else
- least = runtime
- end
- if most > 0 then
- if runtime > most then most = runtime end
- else
- most = runtime
- end
- end
- if status.empty? then
- # skip, garbage
- elsif status =~ /^(|exa)admin/o then
- # skip, useless
- else
- begin
- lines << "<tr>\n"
- lines << td("<a href=\"exaadmin?option=dir&path=#{session['id']}.dir\">#{session['id']}</a>")
- lines << td(status)
- lines << td(session['timeout'])
- lines << td(starttime)
- lines << td(session['runtime'])
- lines << td(requesttime)
- lines << td(t.strftime("%H:%M:%S %Y-%m-%d"))
- lines << td(session['domain'])
- lines << td(session['project'])
- lines << td(session['username'])
- lines << td(File.basename(File.dirname(s)))
- lines << "</tr>\n"
- rescue
- else
- n += 1
- end
- end
- end
- if n > 0 then
- str = "<table cellpadding='0'>\n"
- str << "<tr>\n"
- str << th('session identifier')
- str << th('status')
- str << th('timeout')
- str << th('time')
- str << th('runtime')
- str << th('total')
- str << th('modification&nbsp;time')
- str << th('domain')
- str << th('project')
- str << th('username')
- str << th('process')
- str << "</tr>\n"
- str << lines
- str << "</table>\n"
- end
- end
- rescue
- message('Status', "#{$!} There is currently no status available.", false, @@admin_refresh, 'exaadmin')
- else
- if n > 0 then
- # r = if n > 100 then 60 else @@admin_refresh.to_i end # scanning takes long
- r = @@admin_refresh
- average = "average = #{if totaldone > 0 then sprintf('%.02f',totaltime/totaldone) else '0' end} (#{sprintf('%.02f',least)} .. #{sprintf('%.02f',most)})"
- sessions = "sessions = #{n}"
- refresh = "refresh = #{r.to_s} sec"
- loadtime = "loadtime = #{sprintf('%.04f',Time.now-start)} sec"
- cached = if cached then "cached" else "not cached" end
- message("Status | #{sessions} | #{refresh} | #{loadtime} - #{cached} | #{average} |", str, false, r, 'exaadmin')
- else
- message('Status', "There are no sessions registered.", false, @@admin_refresh, 'exaadmin')
- end
- end
- end
-
- private
-
- def th(str)
- "<th align='left'>#{str}&nbsp;&nbsp;&nbsp;</th>\n"
- end
-
- def td(str)
- "<td><code>#{str || ''}&nbsp;&nbsp;&nbsp</code></td>\n"
- end
-
-end
diff --git a/scripts/context/ruby/www/common.rb b/scripts/context/ruby/www/common.rb
deleted file mode 100644
index 9c3832294..000000000
--- a/scripts/context/ruby/www/common.rb
+++ /dev/null
@@ -1,80 +0,0 @@
-# We cannot chdir in threads because it is something
-# process wide, so we will run into problems with the
-# other threads. The same is true for the global ENV
-# pseudo hash, so we cannot communicate the runpath
-# via an anvironment either. This leaves texmfstart
-# in combination with a path directive and an tmf file.
-
-module Common # can be a mixin
-
- # we assume that the hash.subset method is defined
-
- @@re_texmfstart = /^(texmfstart|ruby\s*texmfstart.rb)\s*(.*)$/
- @@re_texmfpath = /^\-\-path\=/
-
- def command_string(path,command,log='')
- runner = "texmfstart --path=#{File.expand_path(path)}"
- if command =~ @@re_texmfstart then
- cmd, arg = $1, $2
- if arg =~ @@re_texmfpath then
- # there is already an --path (first switch)
- else
- command = "#{runner} #{arg}"
- end
- else
- command = "#{runner} bin:#{command}"
- end
- if log && ! log.empty? then
- return "#{command} 2>&1 > #{File.expand_path(File.join(path,log))}"
- else
- return command
- end
- end
-
- def set_os_vars
- begin
- ENV['TEXOS'] = ENV['TEXOS'] || platform
- rescue
- ENV['TEXOS'] = 'texmf-linux'
- else
- ENV['TEXOS'] = 'texmf-' + ENV['TEXOS'] unless ENV['TEXOS'] =~ /^texmf\-/
- ensure
- ENV['EXA:TEXOS'] = ENV['TEXOS']
- end
- end
-
- def set_environment(hash)
- set_os_vars
- paths = ENV['PATH'].split(File::PATH_SEPARATOR)
- hash.subset('binpath:').keys.each do |key|
- begin
- paths << File.expand_path(hash[key])
- rescue
- end
- end
- ENV['PATH'] = paths.uniq.join(File::PATH_SEPARATOR)
- hash.subset('path:').keys.each do |path|
- key, value = "EXA:#{path.upcase}", File.expand_path(hash[path])
- ENV[key] = value
- end
- end
-
- def save_environment(hash,path,filename='request.tmf')
- begin
- File.open(File.join(path,filename),'w') do |f|
- set_os_vars
- ['EXA:TEXOS','TEXOS'].each do |key|
- f.puts("#{key} = #{ENV[key]}")
- end
- hash.subset('binpath:').keys.each do |key|
- f.puts("PATH < #{File.expand_path(@interface.get(key))}")
- end
- hash.subset('path:').keys.each do |path|
- f.puts("EXA:#{path.upcase} = #{File.expand_path(@interface.get(path))}")
- end
- end
- rescue
- end
- end
-
-end
diff --git a/scripts/context/ruby/www/dir.rb b/scripts/context/ruby/www/dir.rb
deleted file mode 100644
index 115fd8911..000000000
--- a/scripts/context/ruby/www/dir.rb
+++ /dev/null
@@ -1,155 +0,0 @@
-require 'www/lib'
-
-# dir handling
-
-class WWW
-
- # borrowed code from webrick demo, patched
-
- @@dir_name_width = 25
-
- def handle_dir(dirpath=@variables.get('path'),hidden=[],showdirs=true)
- check_template_file('dir','text-template.htm')
- docroot = @interface.get('path:docroot')
- dirpath = dirpath || ''
- hidden = [] unless hidden
- local_path = dirpath.dup
- title, str = "Index of #{escaped(dirpath)}", ''
- begin
- local_path.gsub!(/[\/\\]+/,'/')
- local_path.gsub!(/\/$/, '')
- if local_path !~ /^(\.|\.\.|\/|[a-zA-Z]\:)$/io then # maybe also /...
- full_path = File.join(docroot,local_path)
- @interface.set('log:dir', full_path)
- begin
- list = Dir::entries(full_path)
- rescue
- str << "unable to parse #{local_path}"
- else
- if list then
- list.collect! do |name|
- if name =~ /^\.+/o then
- nil # no . and ..
- else
- st = (File::stat(File.join(docroot,local_path,name)) rescue nil)
- if st.nil? then
- [name, nil, -1, false]
- elsif st.directory? then
- if showdirs then [name + "/", st.mtime, -1, true] else nil end
- elsif hidden.length > 0 then
- if hidden.include?(name) then nil else [name, st.mtime, st.size, false] end
- else
- [name, st.mtime, st.size, false]
- end
- end
- end
- list.compact!
- n, m, s = @variables.get('n'), @variables.get('m'), @variables.get('s')
- if ! n.empty? then
- idx, d0 = 0, n
- elsif ! m.empty? then
- idx, d0 = 1, m
- elsif ! s.empty? then
- idx, d0 = 2, s
- else
- idx, d0 = 0, 'a'
- end
- d1 = if d0 == 'a' then 'd' else 'a' end
- if d0 == 'a' then
- list.sort! do |a,b| a[idx] <=> b[idx] end
- else
- list.sort! do |a,b| b[idx] <=> a[idx] end
- end
- u = dir_uri(@variables.get('path') || '.')
- str << "<div class='dir-view'>\n<pre>\n"
- str << "<a href=\"#{u}&n=#{d1}\">name</a>".ljust(49+u.length)
- str << "<a href=\"#{u}&m=#{d1}\">last modified</a>".ljust(41+u.length)
- str << "<a href=\"#{u}&s=#{d1}\">size</a>".rjust(31+u.length) << "\n" << "\n"
- # parent path
- if showdirs && ! hidden.include?('..') then
- dname = "parent directory"
- fname = "#{File.dirname(dirpath)}"
- time = File::mtime(File.join(docroot,local_path,"/.."))
- str << dir_entry(fname,dname,time,-1,true)
- str << "\n"
- end
- # directories
- done = false
- list.each do |name, time, size, dir|
- if dir then
- if name.size > @@dir_name_width then
- dname = name.sub(/^(.#{@@dir_name_width-2})(.*)/) do $1 + ".." end
- else
- dname = name
- end
- fname = "#{escaped(dirpath)}/#{escaped(name)}"
- str << dir_entry(fname,dname,time,size,dir)
- done = true
- end
- end
- str << "\n" if done
- # files
- list.each do |name, time, size, dir|
- unless dir then
- if name.size > @@dir_name_width then
- dname = name.sub(/^(.#{@@dir_name_width-2})(.*)/) do $1 + ".." end
- else
- dname = name
- end
- fname = "#{escaped(dirpath)}/#{escaped(name)}"
- str << dir_entry(fname,dname,time,size,dir)
- end
- end
- str << "\n"
- str << '</pre></div>'
- else
- str << 'no info'
- end
- end
- else
- str << 'no access'
- end
- rescue
- str << "error #{$!}<br/><pre>"
- str << $@.join("\n")
- str << "</pre>"
- end
- message(title,str)
- end
- def dir_uri(f='.')
- u, t, o = @interface.get('dir:uri'), @interface.get('dir:task'), @interface.get('dir:option') # takes precedence, in case we run under cgi control
- if u.empty? then
- u, t, o = @interface.get('process:uri'), '', ''
- elsif ! t.empty? then
- t = "task=#{t}&"
- o = "option=#{o}&"
- end
- if u && ! u.empty? then
- u = u.sub(/\?.*$/,'') # frozen string
- if f =~ /^\.+$/ then
- "#{u}?#{t}#{o}path="
- else
- "#{u}?#{t}#{o}path=#{f}"
- end
- else
- ''
- end
- end
-
- def dir_entry(fname,dname,time,size,dir=false)
- if dir then
- f = fname.sub(/\/+$/,'').sub(/^\/+/,'')
- s = "<a href=\"#{dir_uri(f)}\">#{dname}</a>"
- elsif ! @interface.get('dir:uri').empty? then # takes precedence, in case we run under cgi control
- s = "<a href=\"#{dir_uri(fname.gsub(/\/+/,'/'))}\">#{dname}</a>"
- else
- s = "<a href=\"#{fname.gsub(/\/+/,'/')}\">#{dname}</a>"
- end
- # s << " " * (30 - dname.size)
- s << " " * (@@dir_name_width + 5 - dname.size)
- s << (time ? time.strftime("%Y/%m/%d %H:%M ") : " " * 22)
- s << (size >= 0 ? size.to_s : "-").rjust(12) << "\n"
- return s
- end
-
-end
diff --git a/scripts/context/ruby/www/exa.rb b/scripts/context/ruby/www/exa.rb
deleted file mode 100644
index 20a40fc7b..000000000
--- a/scripts/context/ruby/www/exa.rb
+++ /dev/null
@@ -1,387 +0,0 @@
-require 'fileutils'
-require 'www/lib'
-require 'www/dir'
-require 'www/common'
-require 'www/admin'
-
-class WWW
-
- include Common
-
- def handle_exadefault
- check_template_file('exalogin','exalogin-template.htm')
- if id = logged_in_session(true) then
- finish_login
- else
- message('Error', 'No default login permitted.')
- end
- end
-
- def handle_exalogin
- check_template_file('exalogin','exalogin-template.htm')
- if id = logged_in_session(false) then
- finish_login
- else
- message('Error', 'No default login permitted.')
- end
- end
-
- def finish_login
- get_gui()
- filename, path, task = @session.get('gui'), @session.checked('path','.'), @session.get('task')
- if ! task.empty? then
- save_session
- handle_exatask
- elsif filename and not filename.empty? then
- save_session
- fullname = filename.gsub(/\.\./,'')
- fullname = File.join(path,filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'), filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'), path, filename) unless FileTest.file?(fullname)
- if FileTest.file?(fullname) then
- send_file(fullname,true)
- else
- message('Interface', 'Invalid interface request, no valid interface file.' )
- end
- else
- message('Interface', 'Invalid interface request, no default interface file.')
- end
- end
-
- def handle_exainterface()
- check_template_file('text','exalogin-template.htm')
- if id = valid_session() then
- filename = @interface.get('process:uri').to_s # kind of dup
- if ! filename.empty? && filename.sub!(/^.*\//,'') then
- path = @session.checked('path', '.')
- fullname = filename.gsub(/\.\./,'')
- fullname = File.join(path,filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'),filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'),path,filename) unless FileTest.file?(fullname)
- if FileTest.file?(fullname) then
- save_session
- send_file(fullname,true)
- else
- get_file(filename)
- filename, path = @session.get('gui'), @session.checked('path','.')
- if filename and not filename.empty? then
- save_session
- fullname = filename.gsub(/\.\./,'')
- fullname = File.join(path,filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'),filename) unless FileTest.file?(fullname)
- fullname = File.join(@interface.get('path:interfaces'),path,filename) unless FileTest.file?(fullname)
- send_file(fullname,true) if FileTest.file?(fullname)
- else
- message('Interface', 'Invalid interface request, no interface file.')
- end
- end
- else
- message('Interface', 'Invalid interface request, no resource file.')
- end
- else
- message('Interface', 'Invalid interface request, no login.')
- end
- end
-
- def handle_exarequest() # todo: check if request is 'command'
- check_template_file('exalogin','exalogin-template.htm')
- if id = client_session() then
- client = true
- @interface.set('log:kind', "remote client request: #{id}")
- elsif id = valid_session() then
- client = false
- @interface.set('log:kind', "remote browser request: #{id}")
- else
- client, id = false, nil
- @interface.set('log:kind', 'unknown kind of request')
- end
- if id then
- dir, tmp = dirname, tmp_path(dirname)
- requestname, replyname = 'request.exa', 'reply.exa'
- requestfile, replyfile = File.join(tmp,requestname), File.join(tmp,replyname)
- lockfile = File.join(dirname,lckname)
- action, filename, command, url, req = '', '', '', '', ''
- extract_sent_files(tmp)
- @variables.each do |key, value|
- case key
- when 'exa:request' then
- req = value.dup
- when 'exa:action' then
- action = value.dup
- # when 'exa:command' then
- # command = value.dup
- # when 'exa:url' then
- # url = value.dup
- when 'exa:filename' then
- filename = value.dup
- when 'exa:threshold' then
- @interface.set('process:threshold', value.dup)
- when /^fakename/o then
- @variables.set(key, File.basename(value))
- when /^filename\-/o then
- @variables.set(key, filename = File.basename(value))
- when /^dataname\-/o then
- @variables.set(key)
- else # remove varname- prefix from value
- @variables.set(key, @variables.get(key).sub(/#{key}\-/,''))
- end
- end
- @variables.check('exa:filename', filename)
- @variables.check('exa:action', action)
- if @variables.empty?('exa:filename') then
- @variables.set('exa:filename', @interface.get('log:attachments').split('|').first || '')
- end
- req.gsub!(/<exa:data\s*\/>/i, '')
- dat = "<exa:data>\n"
- @variables.each do |key, value|
- if ['password','exa:request'].include?(key) then
- # skip
- elsif ! value || value.empty? then
- dat << "<exa:variable label='#{key}'/>\n"
- else # todo: escape 'm
- dat << "<exa:variable label='#{key}'>#{value}</exa:variable>\n"
- end
- end
- dat << "</exa:data>\n"
- if req.empty? then
- req << "<?xml version='1.0' ?>\n"
- req << "<exa:request xmlns:exa='#{@@namespace}'>\n"
- req << "<exa:application>\n"
- req << "<exa:action>'#{action}</exa:action>\n" unless action.empty?
- # req << "<exa:command>'#{command}</exa:command>\n" unless command.empty?
- # req << "<exa:url>'#{url}</exa:url>\n" unless url.empty?
- req << "</exa:application>\n"
- req << "<exa:comment>constructed request</exa:comment>\n"
- req << dat
- req << "</exa:request>\n"
- else
- # better use rexml but slower
- if req =~ /<exa:request[^>]*>.*?\s*<exa:threshold>\s*(.*?)\s*<\/exa:threshold>\s*.*?<\/exa:request>/moi then
- threshold = $1
- unless threshold.empty? then
- @interface.set('process:threshold', threshold)
- @session.set('threshold', threshold)
- end
- end
- req.sub!(/(<exa:request[^>]*>.*?)\s*<exa:option>\s*\-\-action\=(.*?)\s*<\/exa:option>\s*(.*?<\/exa:request>)/moi) do
- pre, act, pos = $1, $2, $3
- action = act.sub(/\.exa$/,'') if action.empty?
- str = "#{pre}<exa:action>#{action}</exa:action>#{pos}"
- str.sub(/\s*<exa:command>.*?<\/exa:command>\s*/moi ,'')
- end
- req.sub!(/(<exa:request[^>]*>.*?)<exa:action>\s*(.*?)\s*<\/exa:action>(.*?<\/exa:request>)/moi) do
- pre, act, pos = $1, $2, $3
- action = act.sub(/\.exa$/,'') if action.empty?
- str = "#{pre}<exa:action>#{action}</exa:action>#{pos}"
- str.sub(/\s*<exa:command>.*?<\/exa:command>\s*/moi ,'')
- end
- unless req =~ /<exa:data>(.*?)<\/exa:data>/moi then
- req.sub!(/(<\/exa:request>)/) do dat + $1 end
- end
- end
- req.sub!(/<exa:filename>.*?<\/exa:filename>/moi, '')
- unless @variables.empty?('exa:filename') then
- req.sub!(/(<\/exa:application>)/moi) do
- "<exa:filename>#{@variables.get('exa:filename')}<\/exa:filename>" + $1
- end
- end
- @variables.set('exa:action', action)
- @interface.set("log:#{requestname}", req)
- begin
- File.open(requestfile,'w') do |f|
- f << req
- end
- rescue
- message('Error', 'There is a problem in handling this request (working path access).')
- return
- end
- File.delete(replyfile) rescue false
- @interface.set('log:action',action)
- get_command(action)
- logdata = ''
- begin
- command = @session.get('command')
- @interface.set('log:command',if command.empty? then '[no command]' else command end)
- if ! command.empty? then
- @session.set('starttime', Time.now.to_i.to_s) # can be variables and in save list
- if @interface.true?('process:background') then
- # background
- @session.set('status', 'running: background')
- @session.set('maxtime', @interface.get('process:timeout'))
- @session.set('threshold', @interface.get('process:threshold'))
- save_session
- timeout(@@watch_delay) do
- save_environment(@interface,tmp)
- begin
- starttime = File.mtime(@session_file)
- # crap
- loop do
- sleep(1)
- if starttime != File.mtime(@session_file) then
- break unless FileTest.file?(lockfile)
- end
- end
- rescue TimeoutError
- if client then
- send_reply()
- else
- message('Status', 'Processing your request takes a while',true,5,'exastatus')
- end
- return
- rescue
- end
- end
- if client then send_reply() else send_result() end
- else
- # foreground
- status = 'running: foreground'
- @session.set('status', status)
- @session.set('maxtime', @interface.get('process:timeout'))
- @session.set('threshold', @interface.get('process:threshold'))
- save_session
- timeout(@interface.get('process:timeout').to_i) do
- begin
- status = 'running: foreground'
- set_environment(@interface)
- save_environment(@interface,tmp)
- command = command_string(tmp,command)
- logdata = `#{command}`
- rescue TimeoutError
- status = 'running: timeout'
- logdata = "timeout: #{@interface.get('process:timeout')} seconds"
- rescue
- status = 'running: aborted'
- logdata = 'fatal runtime error'
- else
- @session.set('endtime', Time.now.to_i.to_s)
- status = 'running: finished'
- end
- end
- @session.set('status', status)
- save_session
- case @session.get('status')
- when 'running: finished' then
- if client then send_reply(logdata) else send_result(logdata) end
- when 'running: timeout' then
- message('Error', 'There is a problem in handling this request (timeout).')
- when 'running: aborted' then
- message('Error', 'There is a problem in handling this request (aborted).')
- else
- message('Error', 'There is a problem in handling this request (unknown).')
- end
- end
- else
- message('Error', 'There is a problem in handling this request (no runner).')
- end
- rescue
- message('Error', 'There is a problem in handling this request (no run).' + $!)
- end
- else
- message('Error', 'Invalid session.')
- end
- end
-
- def handle_exacommand() # shares code with exarequest
- check_template_file('exalogin','exalogin-template.htm')
- if id = client_session() then
- client = true
- @interface.set('log:kind', "remote client request: #{id}")
- elsif id = valid_session() then
- client = false
- @interface.set('log:kind', "remote browser request: #{id}")
- else
- client, id = false, nil
- @interface.set('log:kind', 'unknown kind of request')
- end
- if id then
- dir, tmp = dirname, tmp_path(dirname)
- requestname, replyname = 'request.exa', 'reply.exa'
- requestfile, replyfile = File.join(tmp,requestname), File.join(tmp,replyname)
- req, command, url = '', '', ''
- @variables.each do |key, value|
- case key
- when 'exa:request' then
- req = value.dup
- when 'exa:command' then
- command = value.dup
- when 'exa:threshold' then
- @interface.set('process:threshold', value.dup)
- when 'exa:url' then
- url = value.dup
- end
- end
- unless req.empty? then
- # better use rexml but slower / reuse these : command = filter_from_request('exa:command')
- if req =~ /<exa:request[^>]*>.*?\s*<exa:command>\s*(.*?)\s*<\/exa:command>\s*.*?<\/exa:request>/moi then
- command = $1
- end
- if req =~ /<exa:request[^>]*>.*?\s*<exa:url>\s*(.*?)\s*<\/exa:url>\s*.*?<\/exa:request>/moi then
- url = $1
- end
- if req =~ /<exa:request[^>]*>.*?\s*<exa:threshold>\s*(.*?)\s*<\/exa:threshold>\s*.*?<\/exa:request>/moi then
- threshold = $1
- unless threshold.empty? then
- @interface.set('process:threshold', threshold)
- @session.set('threshold', threshold)
- end
- end
- end
- @variables.check('exa:command', command)
- @variables.check('exa:url', url)
- File.delete(replyfile) rescue false
- case @variables.get('exa:command')
- when 'fetch' then
- if @variables.empty?('exa:url') then
- message('Error', "Problems with fetching, no file given")
- else
- # the action starts here
- filename = @variables.get('exa:url').to_s # kind of dup
- unless filename.empty? then
- get_path(filename) # also registers filename as url
- path = @session.checked('path', '')
- fullname = filename.gsub(/\.\./,'')
- fullname = File.join(path,fullname) unless path.empty?
- if FileTest.file?(fullname) then
- if client then
- send_url(fullname)
- else
- send_file(fullname,true)
- end
- @session.set('threshold', @interface.get('process:threshold'))
- @session.set('url',filename)
- save_session
- else
- message('Error', "Problems with fetching, unknown file #{fullname}.")
- # message('Error', "Problems with fetching, unknown file #{filename}.")
- end
- else
- message('Error', "Problems with fetching, invalid file #{filename}.")
- end
- # and ends here
- end
- else
- message('Error', "Invalid command #{command}.")
- end
- else
- message('Error', 'Invalid session.')
- end
- end
-
- def handle_exastatus
- get_cfg() # weird, needed for apache, but not for wwwserver
- if request_variable('id').empty? then
- if id = valid_session() then
- send_result()
- else
- message('Error', 'Invalid session.')
- end
- else
- if id = valid_session() then
- send_reply()
- else
- send_reply('invalid session')
- end
- end
- end
-
-end
diff --git a/scripts/context/ruby/www/lib.rb b/scripts/context/ruby/www/lib.rb
deleted file mode 100644
index b9a44c9f6..000000000
--- a/scripts/context/ruby/www/lib.rb
+++ /dev/null
@@ -1,1405 +0,0 @@
-#!/usr/bin/env ruby
-
-# This is just a simple environment for remote processing of context
-# files. It's not a framework, nor an example of how that should be done.
-# Nowadays there are environments like Rails or Nitro. Maybe some day I'll
-# give one of them a try.
-
-# <META Http-Equiv="Cache-Control" Content="no-cache">
-# <META Http-Equiv="Pragma" Content="no-cache">
-# <META Http-Equiv="Expires" Content="0">
-
-# we make limited use of cgi methods because we also need to handle webrick
-
-# %var% as well as $(var) are supported
-
-# paths need to be expanded before they enter apache, since .. is not
-# handled by default
-
-require 'base/variables'
-
-require 'ftools'
-require 'fileutils'
-require 'tempfile'
-require 'timeout'
-require 'md5'
-require 'digest/md5'
-require 'cgi' # we also need escaping for webrick (could move it here)
-
-# beware, namespaces have to match !
-
-module XML
-
- def XML::element(tag,attributes=nil)
- if attributes.class == Hash then
- if block_given? then
- XML::element(tag,XML::attributes(attributes)) do yield end
- else
- XML::element(tag,XML::attributes(attributes))
- end
- else
- if block_given? then
- "<#{tag}#{if attributes && ! attributes.empty? then ' ' + attributes end}>#{yield}</#{tag}>"
- else
- "<#{tag}#{if attributes && ! attributes.empty? then ' ' + attributes end}/>"
- end
- end
- end
-
- def XML::attributes(hash)
- str = ''
- hash.each do |k,v|
- str << ' ' unless str.empty?
- if v =~ /\'/ then
- str << "#{k}=\"#{v}\""
- else
- str << "#{k}=\'#{v}\'"
- end
- end
- return str
- end
-
- def XML::create(version='1.0')
- "<?version='#{version}'?>#{yield || ''}"
- end
-
- def XML::line
- "\n"
- end
-
-end
-
-# str =
- # XML::create do
- # XML::element('test') do
- # XML::element('test') do
- # 'text a'
- # end +
- # XML::element('test',XML::attributes({'a'=>'b'})) do
- # XML::element('nested',XML::attributes({'a'=>'b'})) do
- # 'text b-1'
- # end +
- # XML::element('nested',XML::attributes({'a'=>'b'})) do
- # 'text b-2'
- # end
- # end +
- # XML::element('nested',{'a'=>'b'}) do
- # 'text c'
- # end
- # end
- # end
-
-class ExtendedHash
-
- DEFAULT = 'default'
-
- @@re_default = /^(default|)$/i
-
- def default?(key)
- self[key] =~ @@re_default rescue true # unset, empty or 'default'
- end
-
- def default(key)
- self[key] = DEFAULT
- end
-
- def match?(key,value)
- value == '*' || value == self[key]
- end
-
-
-end
-
-class WWW
-
- @@session_prefix = ''
- @@data_file = 'example.cfg'
- @@session_max_age = 60*60
- @@watch_delay = 30
- @@send_threshold = 2*1024*1024
- @@admin_refresh = 10
- @@namespace = "http://www.pragma-ade.com/schemas/example.rng"
-
- @@re_bar = /\s*\|\s*/
- @@re_lst = /\s*\,\s*/
- @@re_var_a = /\%(.*?)\%/
- @@re_var_b = /\$\((.*?)\)/
-
- attr_reader :variables
- attr_writer :variables
-
- @@paths = [
- 'configurations',
- 'data',
- 'distributions',
- 'documents',
- 'interfaces',
- 'logs',
- 'resources',
- 'runners',
- 'scripts',
- 'templates',
- 'work']
-
- @@re_true = /^\s*(YES|ON|TRUE|1)\s*$/io
- @@re_false = /^\s*(NO|OFF|FALSE|0)\s*$/io
-
- def initialize(webrick_daemon=nil,webrick_request=nil,webrick_response=nil)
- @session_id, @session_file = '', ''
- @cgi, @cgi_cookie = nil, nil
- @webrick_daemon, @webrick_request, @webrick_response = webrick_daemon, webrick_request, webrick_response
-
- @interface = ExtendedHash.new
- @variables = ExtendedHash.new
- @session = ExtendedHash.new
-
- @checked = false
-
- analyze_request()
- update_interface()
-
- @interface.set('template:message' , 'exalogin-template.htm')
- @interface.set('template:status' , 'exalogin-template.htm')
- @interface.set('template:login' , 'exalogin.htm')
- @interface.set('process:timeout' , @@session_max_age)
- @interface.set('process:threshold' , @@send_threshold)
- @interface.set('process:background', 'yes') # this demands a watchdog being active
- @interface.set('process:indirect' , 'no') # indirect download, no direct feed
- @interface.set('process:autologin' , 'yes') # provide default interface when applicable
- @interface.set('process:exaurl' , '') # this one will be used as replacement in templates
- @interface.set('trace:run' , 'no')
- @interface.set('trace:errors' , 'no')
- @interface.set('process:os' , platform)
- @interface.set('process:texos' , 'texmf-' + platform)
-
- @interface.set('trace:run' , 'yes') if (ENV['EXA_TRACE_RUN'] || '') =~ @@re_true
- @interface.set('trace:errors' , 'yes') if (ENV['EXA_TRACE_ERRORS'] || '') =~ @@re_true
-
- yield self if block_given?
- end
-
- def set(key,value)
- @interface.set(key,value)
- end
- def get(key)
- @interface.get(key,value)
- end
-
- def platform
- case RUBY_PLATFORM
- when /(mswin|bccwin|mingw|cygwin)/i then 'mswin'
- when /(linux)/i then 'linux'
- when /(netbsd|unix)/i then 'unix'
- when /(darwin|rhapsody|nextstep)/i then 'macosx'
- else 'unix'
- end
- end
-
- def check_cgi
- # when mod_ruby is used, we need to close
- # the cgi session explicitly
- unless @webrick_request then
- unless @cgi then
- @cgi = CGI.new('html4')
- at_exit do
- begin
- @cgi.close
- rescue
- end
- end
- end
- end
- end
-
- def request_variable(key)
- begin
- if @webrick_request then
- [@webrick_request.query[key]].flatten.first.to_s
- else
- check_cgi
- [@cgi.params[key]].flatten.first.to_s
- end
- rescue
- ''
- end
- end
-
- def request_cookie(key)
- begin
- if @cgi then
- if str = @cgi.cookies[key] then
- return str.first || ''
- end
- elsif @webrick_request then
- @webrick_request.cookies.flatten.each do |cookie|
- if cookie.name == key then
- return cookie.value unless cookie.value.empty?
- end
- end
- end
- rescue
- end
- return ''
- end
-
- def analyze_request
- if @webrick_request then
- @interface.set('path:docroot', @webrick_daemon.config[:DocumentRoot] || './documents')
- @interface.set('process:uri', @webrick_request.request_uri.to_s)
- # @interface.set('process.url', [@webrick_request.host,@webrick_request.request_port].join(':'))
- @cgi = nil
- @webrick_request.query.each do |key, value|
- # todo: filename
- @variables.set(key, [value].flatten.first)
- end
- else
- @interface.set('path:docroot', ENV['DOCUMENT_ROOT'] || './documents')
- @interface.set('process:uri', ENV['REQUEST_URI'] || '')
- # @interface.set('process.url', [ENV['SERVER_NAME'],ENV['SERVER:PORT']].join(':'))
- ARGV[0] = '' # get rid of terminal mode
- check_cgi
- # quite fragile, due to changes between 1.6 and 1.8
- @cgi.params.keys.each do |p|
- if @cgi[p].respond_to?(:original_filename) then
- @interface.set('log:method','post')
- if @cgi[p].original_filename && ! @cgi[p].original_filename.empty? then
- @variables.set(p, File.basename(@cgi[p].original_filename))
- else
- case @cgi.params[p].class
- when StringIO.class then @variables.set(p, @cgi[p].read)
- when Array.class then @variables.set(p, @cgi[p].first.to_s)
- when String.class then @variables.set(p, @cgi[p])
- when Tempfile.class then @variables.set(p, '[data blob]')
- end
- end
- else
- @interface.set('log:method','get') unless @interface.get('log:method') == 'post'
- @variables.set(p, [@cgi.params[p]].flatten.first.to_s)
- end
- end
- end
- @interface.set('path:root', File.dirname(@interface.get('path:docroot')))
- end
-
- # name in calling script takes precedence
- # one can set template:whatever as well
- # todo: in config
-
- def check_template_file(tag='',filename='exalogin-template.htm')
- @interface.set('file:template', filename) if @interface.get('file:template').empty?
- @interface.set('tag:template', tag)
- @interface.set('file:template', @interface.get('tag:template')) unless @interface.get('tag:template').empty?
- end
-
- def update_interface()
- root = @interface.get('path:docroot')
- @interface.set('path:docroot', File.expand_path("#{root}"))
- @@paths.each do |path|
- @interface.set("path:#{path}", File.expand_path("#{root}/../#{path}"))
- end
- @interface.set('file:template', @interface.get('tag:template')) unless @interface.get('tag:template').empty?
- end
-
- def indirect?(result)
- size = FileTest.size?(result) || 0
- @interface.true?('trace:errors') || @interface.true?('trace:run') || @interface.true?('process:indirect') ||
- ((! @interface.empty?('process:threshold')) && (size > @interface.get('process:threshold').to_i)) ||
- ((! @session.empty?('threshold')) && (size > @session.get('threshold').to_i))
- end
-
-end
-
-# files
-
-class WWW
-
- def sesname
- File.basename(@session_file)
- end
- def dirname
- File.basename(@session_file.sub(/ses$/,'dir'))
- end
- def lckname
- File.basename(@session_file.sub(/ses$/,'lck'))
- end
-
- def work_root(expand=true)
- p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
- if @interface.true?('process:background') then
- File.join(@interface.get('path:work'),'watch')
- else
- File.join(@interface.get('path:work'),'direct')
- end
- end
-
- def work_roots(expand=true)
- p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
- [File.join(@interface.get('path:work'),'watch'),File.join(@interface.get('path:work'),'direct')]
- end
-
- def cache_root(expand=true)
- p = if expand then File.expand_path(@interface.get('path:work')) else @interface.get('path:work') end
- File.join(@interface.get('path:work'),'cache')
- end
-
- def cleanup_path(dir)
- FileUtils::rm_r(pth) rescue false
- end
-
- def tmp_path(dir)
- @interface.set('path:templates', File.expand_path(@interface.get('path:templates'))) # to be sure; here ? ? ?
- pth = File.join(work_root,dir)
- File.makedirs(pth) rescue false
- pth
- end
-
- def locked?(lck)
- FileTest.file?(lck)
- end
-
-end
-
-# sessions
-
-class WWW
-
- @@session_tags = ['id','domain','project','username','password','gui','path','process','command','filename','action','status', 'starttime','endtime','runtime','task','option','threshold','url'].sort
- @@session_keep = ['id','domain','project','username','password','process'].sort
- @@session_reset = @@session_tags - @@session_keep
-
- def new_session()
- if @variables.empty?('exa:session') then
- @session_id = new_session_id
- else
- @session_id = @variables.get('exa:session')
- end
- if @session_id == 'default' then # ???
- @session_id = new_session_id
- end
- @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
- register_session
- return @session_id
- end
-
- def reset_session(all=false)
- (if all then @@session_tags else @@session_reset end).each do |k|
- @session.set(k)
- end
- end
-
- def valid_session
- @session_id = request_variable('id')
- if @session_id.empty? then
- begin
- if @cgi then
- if @session_id = @cgi.cookies['session_id'] then
- @session_id = @session_id.first || ''
- else
- @session_id = ''
- end
- elsif @webrick_request then
- @webrick_request.cookies.flatten.each do |cookie|
- if cookie.name == 'session_id' then
- unless cookie.value.empty? then
- @session_id = cookie.value
- # break
- end
- end
- end
- else
- @session_id = ''
- end
- rescue
- @interface.set('log:session',"[error in request #{$!}]")
- return false
- end
- end
- if @session_id.empty? then
- @interface.set('log:session','[no id, check work dir permissions]')
- return false
- else
- @interface.set('log:session',@session_id)
- load_session
- if ! @session.empty?('domain') && ! @session.empty?('project') && ! @session.empty?('username') then
- register_session
- return @session_id
- else
- return false
- end
- end
- end
-
- def touch_session(id=nil)
- begin
- t = Time.now
- File.utime(t,t,File.join(work_root,"#{@@session_prefix}#{id || @session_id}.ses")) rescue false
- rescue
- false
- end
- end
-
- def forced_session
- @session_id = new_session
- if @session_id.empty? then
- @interface.set('log:session','[no id, check work dir permissions]')
- return false
- else
- return check_session
- end
- end
-
- def client_session
- request, done = @variables.get('exa:request'), false
- request.sub!(/(^.*<exa:request[^>]*>.*?)\s*<exa:client>\s*(.*)\s*<\/exa:client>\s*(.*?<\/exa:request>.*$)/mio) do
- pre, client, post = $1, $2, $3
- client.scan(/<exa:(domain|project|username|password)>(.*?)<\/exa:\1>/mio) do
- @variables.set($1, $2)
- end
- done = true
- pre + post
- end
- if done then
- return forced_session
- else
- return nil
- end
- end
-
- def register_session
- if @cgi then
- @cgi_cookie = CGI::Cookie::new(
- 'name' => 'session_id',
- 'value' => @session_id,
- 'expires' => Time.now + @interface.get('process:timeout').to_i
- )
- # @cgi_cookie = CGI::Cookie::new('session_id',@session_id)
- elsif @webrick_response then
- if cookie = WEBrick::Cookie.new('session_id', @session_id) then
- cookie.expires = Time.now + @interface.get('process:timeout').to_i
- cookie.max_age = @interface.get('process:timeout').to_i
- cookie.comment = 'exa identifier'
- @webrick_response.cookies.clear
- @webrick_response.cookies << cookie
- end
- end
- end
-
- def new_session_id # taken from cgi
- md5 = Digest::MD5::new
- now = Time::now
- md5.update(now.to_s)
- md5.update(String(now.usec))
- md5.update(String(rand(0)))
- md5.update(String($$))
- md5.update('foobar')
- @new_session = true
- md5.hexdigest[0,32] # was 16
- end
-
- @@hide_passwords = true
- HIDDEN = 'hidden'
-
- def same_passwords(password) # password in cfg file
- if @@hide_passwords && (@session.get('password') == HIDDEN) && (@session_id == @session.get('id')) then
- # this condition is only true when a same session id is found and
- # the password is checked once and set to HIDDEN
- same = true
- elsif password =~ /^MD5:/ then
- # so, one cannot send a known encrypted password since it will be
- # encrypted twice then
- same = (password == "MD5:" + MD5.new(@session.get('password')).hexdigest.upcase)
- else
- if (@session.default?('domain') && @session.default?('project') && @session.default?('username')) then
- @session.default('password') # is this safe enough?
- end
- same = (password == @session.get('password'))
- end
- if @@hide_passwords && same then
- @session.set('password', HIDDEN)
- save_session # next time this session is ok anyway
- end
- return same
- end
-
- @@session_line = /^\s*(?![\#\%])(.*?)\s*\=\s*(.*?)\s*$/o
- @@session_begin = 'begin exa session'
- @@session_end = 'end exa session'
-
- def loaded_session_data(filename)
- begin
- if data = IO.readlines(filename) then
- return data if (data.first =~ /^[\#\%]\s*#{@@session_begin}/o) && (data.last =~ /^[\#\%]\s*#{@@session_end}/o)
- end
- rescue
- end
- return nil
- end
-
- def load_session()
- begin
- @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
- if data = loaded_session_data(@session_file) then
- data.each do |line|
- if line =~ @@session_line then
- @session.set($1, $2 || '')
- end
- end
- else
- return false
- end
- rescue
- return false
- else
- return true
- end
- end
-
- def load_session_file(filename)
- begin
- if data = loaded_session_data(filename) then
- session = Hash.new
- data.each do |line|
- if line =~ @@session_line then
- session[$1] = $2 || ''
- end
- end
- else
- Hash.new
- end
- rescue
- Hash.new
- else
- session
- end
- end
-
- def save_session
- begin
- unless @session_id.empty? then
- @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
- @session_file = File.join(work_root,"#{@@session_prefix}#{@session_id}.ses")
- File.open(@session_file,'w') do |f|
- f << "\# #{@@session_begin}\n"
- @@session_tags.each do |tag|
- if @session && @session.key?(tag) then
- if ! @session.get(tag).empty? then # no one liner, fails
- f << "#{tag}=#{@session.get(tag)}\n"
- end
- elsif @variables.key?(tag) && ! @variables.empty?(key) then
- f << "#{tag}=#{@variables.get(tag)}\n"
- end
- end
- @session.subset("ENV").keys.each do |tag|
- f << "#{tag}=#{@session.get(tag)}\n"
- end
- f << "\# #{@@session_end}\n"
- end
- end
- rescue
- return false
- else
- return true
- end
- end
-
- def logged_in_session(force_default=false)
- if force_default || (@variables.default?('domain') && @variables.default?('project') && @variables.default?('username')) then
- id = default_session
- else
- id = check_session
- end
- end
-
- def default_session
- if @interface.true?('process:autologin') then
- @variables.default('domain')
- @variables.default('project')
- @variables.default('username')
- @variables.default('password')
- check_session
- else
- @session_id = nil
- end
- end
-
- def check_session
- @session.set('domain', @variables.get('domain').downcase)
- @session.set('project', @variables.get('project').downcase)
- @session.set('username', @variables.get('username').downcase)
- @session.set('password', @variables.get('password').downcase)
- new_session
- @session.set('id', @session_id)
- save_session
- return @session_id
- end
-
- def delete_session(id=nil)
- File.delete(work_root,"#{@@session_prefix}#{id || @session_id}.ses") rescue false
- end
-
- def cleanup_sessions(max_age=nil)
- begin
- now, age = Time.now, (max_age||@interface.get('process:timeout')).to_i
- Dir.glob("{#{work_root},#{cache_root}/#{@@session_prefix}*").each do |s|
- begin
- if (now - File.mtime(s)) > age then
- if FileTest.directory?(s) then
- FileUtils::rm_r(s)
- else
- File.delete(s)
- end
- end
- rescue
- # maybe purged in the meantime
- end
- end
- rescue
- # maybe another process is busy
- end
- end
-
-end
-
-# templates
-
-class WWW
-
- def filled_template(title,text,showtime=false,refresh=0,refreshurl=nil)
- template = @interface.get("template:#{@interface.get('tag:template')}")
- template = @interface.get("template:status") if template.empty?
- fullname = File.join(@interface.get('path:templates'),template)
- @interface.set('log:templatename',template)
- @interface.set('log:templatefile',fullname)
- append_status(text)
- htmreply = ''
- if FileTest.file?(fullname) then
- begin
- htmreply = IO.read(fullname)
- rescue
- htmreply = ''
- end
- end
- if refresh>0 then
- if refreshurl then
- metadata = "<meta http-equiv='refresh' content='#{refresh};#{refreshurl}'>"
- else
- metadata = "<meta http-equiv='refresh' content='#{refresh}'>"
- end
- else
- metadata = ''
- end
- if ! htmreply || htmreply.empty? then
- # in head: <link rel='stylesheet' href='/exaresource/exastyle.css'>
- htmreply = <<-EOD
- <html>
- #{metadata}
- <head>
- <title>#{title}</title>
- </head>
- <body>
- <h2>#{title}</h2>
- <h4>#{Time.now}</h4>
- #{text}
- </body>
- </html>
- EOD
- else
- if showtime then
- exa_template = "<h1>#{title}</h1>\n<h2>#{Time.now}</h2>\n#{text}\n"
- else
- exa_template = "<h1>#{title}</h1>#{text}\n"
- end
- htmreply = replace_template_placeholder(htmreply,exa_template,metadata)
- end
- htmreply
- end
-
- def message(title,str='',showtime=false,refresh=0,refreshurl=nil)
- if @cgi then
- @cgi.out("cookie"=>[@cgi_cookie]) do
- filled_template(title,str,showtime,refresh,refreshurl)
- end
- elsif @webrick_response then
- @webrick_response['content-type'] = 'text/html'
- @webrick_response.body = filled_template(title,str,showtime,refresh,refreshurl)
- else
- filled_template(title,str,showtime,refresh,refreshurl)
- end
- end
-
- def plaintext(str)
- if @cgi then
- @cgi.out('cookie'=>[@cgi_cookie],'content-type'=>'text/plain') do
- str
- end
- elsif @webrick_response then
- @webrick_response['content-type'] = 'text/plain'
- @webrick_response.body = str
- else
- str
- end
- end
-
- def exareply(status='',url='',size='',comment='')
- exaurl = @interface.get('process:exaurl')
- str = "<?xml version='1.0'?>\n\n"
- str << "<exa:reply xmlns:exa='#{@@namespace}'>\n"
- str << " <exa:session>#{@session_id}</exa:session>\n" unless @session_id.empty?
- str << " <exa:status>#{status}</exa:status>\n" unless (status || '').empty?
- str << " <exa:url>#{exaurl}/#{url}</exa:url>\n" unless (url || '').empty?
- str << " <exa:size>#{size}</exa:size>\n" unless (size || '').empty?
- str << " <exa:comment>#{comment}</exa:comment>\n" unless (comment|| '').empty?
- str << "</exa:reply>\n"
- return str
- end
-
- def append_status(str='')
- if @interface.true?('trace:errors') then
- if $! && $@ then
- str << "<br/><br/><br/><em>Error:</em><br/><pre>#{$!}</pre><pre>"
- str << $@.join("\n")
- end
- str << '<br/><br/><br/>'
- str << status_data
- str << '<em>Paths</em><br/>'
- str << '<pre>'
- @interface.subset('path:').each do |k,v|
- if FileTest.directory?(v) then
- if FileTest.writable?(v) then
- str << "#{v} exists and is writable\n"
- else
- str << "#{v} is not writable\n"
- end
- else
- str << "#{v} does not exist\n"
- end
- end
- str << '</pre>'
- end
- str
- end
-
- def simpleurl(url)
- if url then url.sub(/(:80|:443)$/,'') else '' end
- end
-
- def replace_exa_placeholders(data)
- data.gsub(/([\"\'])\@exa\_([a-zA-Z0-9\-\_]+)\1/) do
- quot, key, value = $1, $2, ''
- begin
- value = @variables.get(key)
- rescue
- value = ''
- end
- quot + value + quot
- end
- end
-
- def replace_url_placeholder(data)
- data.gsub!(/(http:\/\/|\/+)*\@exa\_main\_url/, @interface.get('process:exaurl'))
- replace_exa_placeholders(data)
- end
-
- def replace_template_placeholder(data,template='',metadata='')
- data.gsub!(/(http:\/\/|\/+)*\@exa\_main\_url/, @interface.get('process:exaurl'))
- data.gsub!(/\@exa\_template/, template)
- data.gsub!(/\@exa\_metadata/, metadata)
- replace_exa_placeholders(data)
- end
-
- def escaped(str)
- str
- end
-
-end
-
-# send files
-
-class WWW
-
- def send_file(filename,parse=false) # this can take a lot of memory, look for alternative (fastcgi ?)
- begin
- if filename =~ /\.pdf$/ then
- mimetype, parse = 'application/pdf', false
- elsif filename =~ /\.(html|htm)$/ then
- mimetype, parse = 'text/html', true
- else
- mimetype, parse = 'text/plain', false
- end
- if FileTest.file?(filename) then
- if @webrick_response then
- begin
- @webrick_response['content-type'] = mimetype
- @webrick_response['content-length'] = FileTest.size?(filename)
- if parse then
- File.open(filename, 'rb') do |f|
- @webrick_response.body = replace_url_placeholder(f.read)
- end
- else
- @webrick_response.body = File.open(filename, 'rb')
- end
- rescue
- else
- return
- end
- elsif @cgi then
- begin
- # the following works ok, but stores the whole file in memory (see @cgi.out)
- #
- # File.open(filename, 'rb') do |f|
- # @cgi.out('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype) do
- # if parse then replace_url_placeholder(f.read) else f.read end
- # end
- # end
- if parse then
- File.open(filename, 'rb') do |f|
- @cgi.out('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype) do
- replace_url_placeholder(f.read)
- end
- end
- else
- @cgi.print(@cgi.header('cookie'=>[@cgi_cookie],'connection'=>'close', 'length'=>File.size(filename), 'type'=>mimetype))
- File.open(filename, 'rb') do |f|
- while str = f.gets do
- @cgi.print(str)
- end
- end
- end
- rescue
- else
- return
- end
- end
- end
- rescue
- end
- message('Error', "There is a problem with sending file #{File.basename(filename)}.")
- end
-
- def send_htmlfile(filename,parse=false)
- send_file(filename,parse)
- end
- def send_pdffile(filename) # this can take a lot of memory, look for alternative (fastcgi ?)
- send_file(filename,false)
- end
-
-end
-
-# tracing
-
-class WWW
-
- def show_vars(a=@variables,title='')
- if a && a.length > 0 then
- if title.empty? then
- str = ''
- else
- str = "<em>#{title}</em>"
- end
- str << "<br/><pre>\n"
- a.keys.sort.each do |k|
- if k && a[k] && ! a[k].empty? then
- if k == 'password' then
- val = if a[k] == 'default' then 'default' else '******' end
- else
- # str << "#{k} => #{a[k].sub(/^\s+/moi,'').sub(/\s+$/moi,'')}\n"
- val = a[k].to_s.strip
- val.gsub!("&","&amp;")
- val.gsub!("<","&lt;")
- val.gsub!(">","&gt;")
- val.gsub!("\n","\n ")
- end
- str << "#{k} => #{val}\n"
- end
- end
- str << "</pre><br/>\n"
- return str
- else
- return ''
- end
- end
-
- def status_data
- show_vars(@session , 'Session' ) +
- show_vars(@variables, 'Variables' ) +
- show_vars(@interface, 'Interface' ) +
- show_vars(ENV , 'Environment')
- end
-
- def report_status
- check_template_file('status')
- message('Status',status_data)
- end
-
-end
-
-# attachments
-
-class WWW
-
- def extract_sent_files(dir)
- files = Array.new
- if @cgi then
- @cgi.params.keys.each do |tag|
- begin
- if filename = @cgi[tag].original_filename then
- files << extract_file_content(dir,filename,@cgi[tag]) unless filename.empty?
- end
- rescue
- end
- end
- elsif @webrick_request then
- @webrick_request.query.keys.each do |tag|
- begin
- if filename = @webrick_request.query[tag].filename then
- files << extract_file_content(dir,filename,@webrick_request.query[tag]) unless filename.empty?
- end
- rescue
- end
- end
- end
- @interface.set('log:attachments', files.compact.uniq.join('|'))
- end
-
- def extract_file_content(dir,filename,data)
- filename = File.join(dir,File.basename(filename))
- begin
- @interface.set('log:attachclass', data.class.inspect)
- if data.class == Tempfile then
- begin
- File.copy(data.path,filename)
- rescue
- begin
- File.open(filename,'wb') do |f|
- File.open(data.path,'rb') do |g|
- while str = g.gets do
- f.write(str)
- end
- end
- end
- rescue
- @interface.set('log:attachstate', "saving tempfile #{filename} failed (#{$!})")
- else
- @interface.set('log:attachstate', "tempfile #{filename} has been saved")
- end
- else
- @interface.set('log:attachstate', "#{data.path} copied to #{filename}")
- end
- elsif data.class == String then
- begin
- File.open(filename,'wb') do |f|
- f.write(data)
- end
- rescue
- @interface.set('log:attachstate', "saving string #{filename} failed (#{$!})")
- else
- @interface.set('log:attachstate', "string #{filename} has been saved")
- end
- elsif data.class == StringIO then
- begin
- File.open(filename,'wb') do |f|
- f.write(data.read)
- end
- rescue
- @interface.set('log:attachstate', "saving stringio #{filename} failed (#{$!})")
- else
- @interface.set('log:attachstate', "stringio #{filename} has been saved")
- end
- else
- @interface.set('log:attachstate', "unknown attachment class #{data.class.to_s}")
- end
- rescue
- begin File.delete(filename) ; rescue ; end
- else
- begin File.delete(filename) if FileTest.size(filename) == 0 ; rescue ; end
- end
- return File.basename(filename)
- end
-
-end
-
-# configuration
-
-class WWW
-
- def interface_base_name(str)
- str.sub(/\.(pdf|htm|html)$/, '')
- end
-
- def located_interface_file(filename)
- ['configurations', 'runners', 'scripts'].each do |tag|
- datafile = File.join(@interface.get("path:#{tag}"),filename)
- if FileTest.file?(datafile+'.encrypted') then
- return datafile + '.encrypted'
- elsif FileTest.file?(datafile) then
- return datafile
- end
- end
- return nil
- end
-
- def load_interface_file(filename=@@data_file)
- reset_session() # no save yet
- if datafile = located_interface_file(filename) then
- nestedfiles = Array.new
- begin
- data = IO.read(datafile) || ''
- unless data.empty? then
- loop do # we need to load them recursively
- done = false
- data.gsub!(/^include\s*:\s*(.*?)\s*$/) do
- includedname, done = $1, true
- if nestedname = located_interface_file(includedname) then
- begin
- str = ("\n" + IO.read(nestedname) + "\n") || ''
- rescue
- nestedfiles << File.basename('-'+includedname)
- ''
- else
- nestedfiles << File.basename('+'+includedname)
- str
- end
- else
- nestedfiles << File.basename('-'+includedname)
- ''
- end
- end
- break unless done
- end
- end
- @interface.set('log:configurationfile', datafile + ' [' + nestedfiles.join(' ') + ']')
- return data
- rescue
- end
- end
- @interface.set('log:configurationfile', filename + ' [not loaded]')
- return nil
- end
-
- def fetch_session_interface_variables(data)
- data.scan(/^variable\s*:\s*(.*?)\s*\=\s*(.*?)\s*$/) do
- @interface.set($1, $2)
- end
- return true
- end
-
- def fetch_session_project_list(data)
- projectlist, permitted = Array.new, false
- data.scan(/^user\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*\,\s*(.*?)\s*$/) do
- domain, username, password, projects = $1, $2, $3, $4
- if @session.match?('domain',domain) && @session.match?('username',username) then
- if same_passwords(password) then
- projectlist, permitted = @interface.resolved(projects).split(@@re_bar), true
- break
- end
- end
- end
- if permitted then
- @interface.set('log:projectlist', '['+projectlist.join(' ')+']')
- if projectlist.length == 0 then
- return nil
- else
- return projectlist
- end
- else
- @interface.set('log:projectlist', '[no projects]')
- return nil
- end
- end
-
- def fetch_session_command(data)
- data.scan(/^process\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*$/) do
- domain, process, command = $1, $2, $3
- if @session.match?('domain',domain) && @session.match?('process',process) then
- @session.set('command', @interface.resolved(command))
- end
- end
- return @session.get('command')
- end
-
- def fetch_session_settings(data)
- data.scan(/^setting\s*:\s*(.*?)\s*\,\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*$/) do
- domain, process, variable, value = $1, $2, $3, $4
- if @session.match?('domain',domain) && @session.match?('process',process) then
- @interface.set(variable,value)
- end
- end
- end
-
- def get_command(action)
- # @session.set('action', action)
- # if @session.get('process') == 'none' then
- # @interface.set('log:child','yes')
- # @session.set('process', action)
- # end
- if data = load_interface_file() then
- fetch_session_interface_variables(data)
- if projectlist = fetch_session_project_list(data) then
- data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
- domain, project, gui, path, process = $1, $2, $3, $4, $5
- if @session.match?('domain',domain) then
- if @session.match?('project',project) then
- if projectlist.include?(project) then
- @session.set('process', @interface.resolved(process))
- # break # no, else we end up in the parent (e.g. examplap instead of impose)
- end
- elsif ! action.empty? && project == action then
- if projectlist.include?(action) then
- @session.set('process', @interface.resolved(process))
- # break # no, else we end up in the parent (e.g. examplap instead of impose)
- end
- end
- end
- end
- fetch_session_command(data)
- fetch_session_settings(data)
- end
- end
- return ! @session.nothing?('command')
- end
-
- def get_file(filename)
- @session.set('filename', filename)
- if data = load_interface_file() then
- fetch_session_interface_variables(data)
- if projectlist = fetch_session_project_list(data) then
- data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
- domain, project, gui, path, process = $1, $2, $3, $4, $5
- if @session.match?('domain',domain) then
- guilist = @interface.resolved(gui).split(@@re_bar)
- guilist.each do |g|
- if /#{filename}$/ =~ g then
- @session.set('gui', File.expand_path(@interface.resolved(g)))
- @session.set('path', File.expand_path(@interface.resolved(path)))
- @session.set('process', process)
- break # take first matching interface
- end
- end
- end
- end
- end
- end
- return ! (@session.nothing?('gui') && @session.nothing?('path') && @session.nothing?('process'))
- end
-
- def get_path(url='')
- if data = load_interface_file() then
- fetch_session_interface_variables(data)
- if projectlist = fetch_session_project_list(data) then
- data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
- domain, project, gui, path, process = $1, $2, $3, $4, $5
- if @session.match?('domain',domain) && @session.match?('project',project) then
- @session.set('url', url)
- @session.set('gui', '')
- @session.set('path', File.expand_path(@interface.resolved(path)))
- @session.set('process', '')
- end
- end
- end
- end
- return ! @session.nothing?('path')
- end
-
- def get_gui()
- if data = load_interface_file() then
- fetch_session_interface_variables(data)
- if projectlist = fetch_session_project_list(data) then
- data.scan(/^project\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*,\s*(.*?)\s*,\s*(.*?)\s*$/) do
- domain, project, gui, path, process = $1, $2, $3, $4, $5
- if @session.match?('domain',domain) && @session.match?('project',project) && projectlist.include?(project) then
- @session.set('gui', File.expand_path(@interface.resolved(gui)))
- @session.set('path', File.expand_path(@interface.resolved(path)))
- @session.set('process', process) unless process == 'none'
- break # take first matching interface
- end
- end
- data.scan(/^admin\s*:\s*(.*?)\s*\,\s*(.*?)\s*\=\s*(.*?)\s*\,\s*(.*?)\s*$/) do
- domain, project, task, option = $1, $2, $3, $4
- if @session.match?('domain',domain) && @session.match?('project',project) && projectlist.include?(project) then
- @session.set('task', task)
- @session.set('option', option)
- break # take first matching task
- end
- end
- end
- end
- return ! (@session.nothing?('gui') && @session.nothing?('path') && @session.nothing?('process'))
- end
-
- def get_cfg()
- if data = load_interface_file() then
- fetch_session_interface_variables(data)
- end
- end
-
-end
-
-class WWW
-
- def send_reply(logdata='')
- if @interface.true?('trace:run') then
- send_result(logdata)
- else
- dir, tmp = dirname, tmp_path(dirname)
- case @session.get('status')
- when 'running: finished' then
- resultname, replyname = 'result.pdf', 'reply.exa'
- replyfile = File.join(tmp,replyname)
- if FileTest.file?(replyfile) then
- begin
- data = IO.read(replyfile)
- resultname = if data =~ /<exa:output>(.*?)<\/exa:output>/ then $1 else resultname end
- rescue
- plaintext(exareply('error in reply'))
- return
- end
- end
- resultfile = File.join(tmp,resultname)
- if FileTest.file?(resultfile) then
- if indirect?(resultfile) then
- begin
- File.makedirs(File.join(cache_root,dir))
- FileUtils::mv(resultfile,File.join(cache_root,dir,resultname))
- rescue
- plaintext(exareply('unable to access cache'))
- else
- plaintext(exareply('big file', "cache/#{dir}/#{resultname}", "#{File.size?(resultfile)}"))
- end
- else
- send_file(resultfile)
- end
- else
- plaintext(exareply('no result'))
- end
- else # background, running, aborted
- plaintext(exareply(@session.get('status')))
- end
- end
- end
-
- def send_url(fullname)
- dir, tmp = dirname, tmp_path(dirname)
- resultname, replyname = 'result.pdf', 'reply.exa'
- replyfile = File.join(tmp,replyname)
- resultfile = File.join(tmp,resultname)
- targetname = File.join(cache_root,dir,resultname)
- # make sure that there is no target left in case of an
- # error; needed in case of given session name
- if FileTest.directory?(File.join(cache_root,dir)) then
- File.delete(targetname) rescue false
- end
- # now try to locate the file
- if FileTest.file?(fullname) then
- if indirect?(fullname) then
- begin
- # check if directory exists and (if so) delete left overs
- File.makedirs(File.join(cache_root,dir))
- File.delete(targetname) rescue false
- File.symlink(fullname,targetname) rescue message('Status',$!)
- unless FileTest.file?(targetname) then
- FileUtils::cp(fullname,targetname) rescue false
- end
- rescue
- plaintext(exareply('unable to access cache'))
- else
- plaintext(exareply('big file', "cache/#{dir}/#{resultname}", "#{File.size?(fullname)}"))
- end
- else
- send_file(fullname)
- end
- else
- message('Status', 'The file is not found')
- end
- end
-
- def send_result(logdata='')
- check_template_file('exalogin','exalogin-template.htm')
- dir, tmp = dirname, tmp_path(dirname)
- resultname, replyname, logname = 'result.pdf', 'reply.exa', 'log.htm'
- case @session.get('status')
- when 'running: background' then
- if st = @session.get('starttime') then # fuzzy
- st = Time.now.to_i if st.empty?
- if (Time.now.to_i - st.to_i) > @interface.get('process:timeout').to_i then
- message('Status', 'Your request has been aborted (timeout)',true)
- else
- message('Status', 'Your request is queued',true,5,'exastatus')
- end
- end
- when 'running: busy' then
- if st = @session.get('starttime') then # fuzzy
- st = Time.now.to_i if st.empty?
- if (Time.now.to_i - st.to_i) > @interface.get('process:timeout').to_i then
- message('Status', 'Your request has been aborted (timeout)',true)
- else
- message('Status', 'Your request is being processed',true,5,'exastatus')
- end
- end
- when 'running: aborted' then
- message('Status', 'Your request has been aborted (timeout)',true)
- when 'running: finished' then
- if @interface.true?('trace:run') then
- logfile = File.join(tmp,logname)
- begin
- if f = File.open(logname,'w') then
- if logdata.empty? then
- begin
- logdata = IO.read('www-watch.out')
- rescue
- logdata = 'no log data'
- end
- end
- f << filled_template('Log',"<pre>#{CGI::escapeHTML(logdata)}</pre>")
- f.close
- end
- rescue
- message('Error', '')
- end
- if FileTest.file?(logfile) then
- begin
- File.makedirs(File.join(cache_root,dir))
- FileUtils::mv(logfile,File.join(cache_root,dir,logname))
- rescue
- logdata = "<br/><br/>unable to access cache</a>"
- else
- logdata = "<br/><br/><a href='/cache/#{dir}/#{logname}'>#{logname}</a>"
- end
- else
- logdata = ''
- end
- else
- logdata = ''
- end
- # todo: generate reply.exa if no reply
- replyfile = File.join(tmp,replyname)
- if FileTest.file?(replyfile) then
- begin
- data = IO.read(replyfile)
- resultname = if data =~ /<exa:output>(.*?)<\/exa:output>/ then $1 else resultname end
- rescue
- message('Error','There is a problem in handling this request (invalid reply).')
- return
- end
- end
- resultfile = File.join(tmp,resultname)
- if FileTest.file?(resultfile) then
- if indirect?(resultfile) then
- begin
- File.makedirs(File.join(cache_root,dir))
- FileUtils::mv(resultfile,File.join(cache_root,dir,resultname))
- rescue
- str = "<br/><br/>unable to access cache</a>"
- else
- str = "<br/><br/><a href='/cache/#{dir}/#{resultname}'>#{resultname}</a>&nbsp;&nbsp;(#{File.size?(resultname)} bytes)"
- end
- message('Result', 'You can pick up the result here:' + str + logdata)
- else
- send_file(resultfile)
- end
- else
- message('Error', 'There is a problem in handling this request (no result file).' + logdata)
- end
- end
- end
-
-end
diff --git a/scripts/context/ruby/www/login.rb b/scripts/context/ruby/www/login.rb
deleted file mode 100644
index 1c88a97e6..000000000
--- a/scripts/context/ruby/www/login.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require 'www/lib'
-
-# basic login
-
-class WWW
-
- def handle_login()
- check_template_file('login','exalogin.htm')
- set('password', '')
- message('Login','')
- end
-
-end
diff --git a/scripts/context/ruby/wwwclient.rb b/scripts/context/ruby/wwwclient.rb
deleted file mode 100644
index d41541a09..000000000
--- a/scripts/context/ruby/wwwclient.rb
+++ /dev/null
@@ -1,677 +0,0 @@
-#!/usr/bin/env ruby
-
-# a direct request is just passed on
-#
-# exaclient --direct --request=somerequest.exa --result=somefile.pdf
-#
-# in an extended request the filename in the template file is replaced by the filename
-# given on the command line; templates are located on the current path and at parent
-# directories (two levels); the filename is expanded to a full path
-#
-# exaclient --extend --template=tmicare-l-h.exa --file=somefile.xml --result=somefile.pdf
-#
-# a constructed request is build out of the provided filename and action; the filename is
-# expanded to a full path
-#
-# exaclient --construct --action=tmicare-s-h.exa --file=somefile.xml --result=somefile.pdf
-#
-# in all cases, the result is either determined by a switch or taken from a reply file
-
-banner = ['WWWClient', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
-
-$: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq!
-
-require 'base/switch'
-require 'base/logger'
-
-require 'timeout'
-require 'thread'
-require 'rexml/document'
-require 'net/http'
-
-class File
-
- def File.backtracked(filename,level=3)
- if level > 0 && filename && ! filename.empty? then
- if FileTest.file?(filename) then
- filename
- else
- File.backtracked('../'+filename,level-1)
- end
- else
- filename
- end
- end
-
- def File.expanded(filename)
- File.expand_path(filename)
- end
-
-end
-
-class Commands
-
- include CommandBase
-
-end
-
-class Commands
-
- @@namespace = "xmlns:exa='http://www.pragma-ade.com/schemas/example.rng'"
- @@randchars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "0123456789" + "abcdefghijklmnopqrstuvwxyz"
-
- def traceback
- "(error: #{$!})" + "\n -- " + $@.join("\n >>")
- end
-
- def pdf(action,filename,enabled)
- if enabled && FileTest.file?(filename) then
- begin
- report("pdf action #{action} on #{filename}")
- case action
- when 'close' then system("pdfclose --all")
- when 'open' then system("pdfopen --file #{filename}")
- end
- rescue
- # forget about it
- end
- end
- end
-
- def status(replyfile,str) # when block, then ok
- begin
- # def status(*whatever)
- # end
- File.open(replyfile,'w') do |f|
- report("saving reply info in '#{replyfile}'")
- f.puts("<?xml version='1.0'?>\n\n")
- f.puts("<exa:reply #{@@namespace}>\n")
- if block_given? then
- f.puts(" <exa:status>ok</exa:status>\n")
- f.puts(" #{yield}\n")
- else
- f.puts(" <exa:status>error</exa:status>\n")
- end
- f.puts(" <exa:comment>" + str + "</exa:comment>\n")
- f.puts("</exa:reply>\n")
- f.close
- report("saving status: #{str}")
- end
- rescue
- report("saving reply info in '#{replyfile}' fails")
- ensure
- exit
- end
- exit # to be real sure
- end
-
-
- def boundary_string (length) # copied from webrick/utils
- rand_max = @@randchars.size
- ret = ""
- length.times do
- ret << @@randchars[rand(rand_max)]
- end
- ret.upcase
- end
-
-end
-
-class Commands
-
- @@connecttimeout = 10*60 # ten minutes
- @@processtimeout = 60*60 # an hour
- @@polldelay = 5 # 5 seconds
-
- def main
-
- datatemplate = @commandline.option('template')
- datafile = @commandline.option('file')
- dataaction = @commandline.option('action')
-
- if ! datatemplate.empty? then
- report("template '#{datatemplate}' specified without --construct")
- report("aborting")
- elsif ! dataaction.empty? then
- report("action data '#{dataaction}' specified without --construct or --extend")
- report("aborting")
- elsif ! datafile.empty? then
- report("action file '#{datafile}' specified without --construct or --extend")
- report("aborting")
- else
- report("assuming --direct")
- direct()
- end
-
- end
-
- def construct
-
- requestfile = @commandline.option('request')
- replyfile = @commandline.option('reply')
-
- datatemplate = @commandline.option('template')
- datafile = @commandline.option('file')
- dataaction = @commandline.option('action')
-
- domain = @commandline.option('domain')
- project = @commandline.option('project')
- username = @commandline.option('username')
- password = @commandline.option('password')
-
- threshold = @commandline.option('threshold')
-
- datablob = ''
-
- begin
- datablob = IO.read(datatemplate)
- rescue
- datablob = ''
- else
- begin
- request = REXML::Document.new(datablob)
- if e = REXML::XPath.match(request.root,"/exa:request/exa:data") then
- datablob = e.to_s.chomp
- end
- rescue
- datablob = ''
- end
- end
-
- begin
- File.open(requestfile,'w') do |f|
- f.puts "<?xml version='1.0'?>\n"
- f.puts "<exa:request #{@@namespace}>\n"
- f.puts " <exa:application>\n"
- f.puts " <exa:action>#{dataaction}</exa:action>\n" unless dataaction.empty?
- f.puts " <exa:filename>#{datafile}</exa:filename>\n" unless datafile.empty?
- f.puts " <exa:threshold>#{threshold}</exa:threshold>\n" unless threshold.empty?
- f.puts " </exa:application>\n"
- f.puts " <exa:client>\n"
- f.puts " <exa:domain>#{domain}</exa:domain>\n"
- f.puts " <exa:project>#{project}</exa:project>\n"
- f.puts " <exa:username>#{username}</exa:username>\n"
- f.puts " <exa:password>#{password}</exa:password>\n"
- f.puts " </exa:client>\n"
- if datablob.empty? then
- f.puts " <exa:data/>\n"
- else
- f.puts " #{datablob.chomp}\n"
- end
- f.puts "</exa:request>"
- end
- rescue
- status(replyfile,"unable to create '#{requestfile}'")
- end
-
- direct()
-
- end
-
- def extend
-
- requestfile = @commandline.option('request')
- replyfile = @commandline.option('reply')
-
- datatemplate = @commandline.option('template')
- datafile = @commandline.option('file')
- dataaction = @commandline.option('action')
-
- threshold = @commandline.option('threshold')
-
- if datatemplate.empty? then
- status(replyfile,"invalid data template '#{datatemplate}'")
- else
- begin
- if FileTest.file?(datatemplate) && oldrequest = IO.read(datatemplate) then
- request, done = REXML::Document.new(oldrequest), false
- if ! threshold.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:threshold") then
- e.text, done = threshold, true
- end
- if ! dataaction.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:action") then
- e.text, done = dataaction, true
- end
- if ! datafile.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application/exa:filename") then
- e.text, done = datafile, true
- end
- #
- if ! threshold.empty? && e = REXML::XPath.match(request.root,"/exa:request/exa:application") then
- e = e.add_element('exa:threshold')
- e.add_text(threshold.to_s)
- done = true
- end
- #
- report("nothing replaced in template file") unless done
- begin
- File.open(requestfile,'w') do |f|
- f.puts(newrequest.to_s)
- end
- rescue
- status(replyfile,"unable to create '#{requestfile}'")
- end
- else
- status(replyfile,"unable to read data template '#{datatemplate}'")
- end
- rescue
- status(replyfile,"unable to handle data template '#{datatemplate}'")
- end
- end
-
- direct()
-
- end
-
- def direct
-
- requestpath = @commandline.option('path')
- requestfile = @commandline.option('request')
- replyfile = @commandline.option('reply')
- resultfile = @commandline.option('result')
- datatemplate = @commandline.option('template')
- datafile = @commandline.option('file')
- threshold = @commandline.option('threshold')
- address = @commandline.option('address')
- port = @commandline.option('port')
- session_id = @commandline.option('session')
- exaurl = @commandline.option('exaurl')
-
- exaurl = "/#{exaurl}" unless exaurl =~ /^\//
-
- address.sub!(/^http\:\/\//io) do
- ''
- end
- address.sub!(/\:(\d+)$/io) do
- port = $1
- ''
- end
-
- autopdf = @commandline.option('autopdf')
-
- dialogue = nil
-
- resultfile.sub!(/\.[a-z]+?$/, '') # don't overwrite the source
-
- unless requestpath.empty? then
- begin
- if FileTest.directory?(requestpath) then
- if Dir.chdir(requestpath) then
- report("gone to path '#{requestpath}'")
- else
- status(replyfile,"unable to go to path '#{requestpath}")
- end
- else
- status(replyfile,"unable to locate '#{requestpath}'")
- end
- rescue
- status(replyfile,"unable to handle '#{requestpath}'")
- end
- end
-
- datafile = File.expand_path(datafile) unless datafile.empty?
- datatemplate = File.backtracked(datatemplate,3) unless datatemplate.empty?
-
- # request must be valid
-
- status(replyfile,'no request file') if requestfile.empty?
- status(replyfile,"invalid request file '#{requestfile}'") unless FileTest.file?(requestfile)
-
- begin
- request = IO.readlines(requestfile).join('')
- request = REXML::Document.new(request)
- status(replyfile,'invalid request (no request)') unless request.root.fully_expanded_name=='exa:request'
- status(replyfile,'invalid request (no application block)') unless request.elements['exa:request'].elements['exa.application'] == nil # explicit nil test needed
- rescue REXML::ParseException
- status(replyfile,'invalid request (invalid xml file)')
- rescue
- status(replyfile,'invalid request (invalid file)')
- else
- report("using request file '#{requestfile}'")
- end
-
- # request can force session_id
-
- if session_id && session_id.empty? then
- begin
- id = request.elements['exa:request'].elements['exa:application'].elements['exa:session'].text
- rescue Exception
- id = ''
- ensure
- if id && ! id.empty? then
- session_id = id
- end
- end
- end
-
- # request can overload reply name
-
- begin
- rreplyfile = request.elements['exa:request'].elements['exa:application'].elements['exa:output'].text
- rescue Exception
- rreplyfile = nil
- ensure
- if rreplyfile && ! rreplyfile.empty? then
- replyfile = rreplyfile
- report("reply file '#{replyfile} set by request'")
- else
- report("using reply file '#{replyfile}'")
- end
- end
-
- # request can overload result name
-
- begin
- rresultfile = request.elements['exa:request'].elements['exa:application'].elements['exa:result']
- rescue Exception
- rresultfile = nil
- ensure
- if rresultfile && ! rresultfile.empty? then
- resultfile = rresultfile
- report("result file '#{resultfile}' set by request")
- else
- report("using result file '#{resultfile}'")
- end
- end
-
- # try to connect to server
-
- start_time = Time.now
-
- processtimeout = begin @commandline.option('timeout').to_i rescue @@processtimeout end
- processtimeout = @@processtimeout if processtimeout == 0 # 'xx'.to_i => 0
-
- dialogue = start_dialogue(address, port, processtimeout)
-
- if dialogue then
- # continue
- else
- status(replyfile,'no connection')
- end
-
- # post request
-
- timeout (@@processtimeout-10) do # -10 so that we run into this one first
- begin
- report("posting request of type '#{exaurl}'")
- report("using session id '#{session_id}'") if session_id && ! session_id.empty?
- firstline, chunks, total = nil, 0, 0
- body, boundary, crlf = '', boundary_string(32), "\x0d\x0a"
- body << '--' + boundary + crlf
- body << "Content-Disposition: form-data; name=\"exa:request\""
- body << crlf
- body << "Content-Type: text/plain"
- body << crlf + crlf
- body << request.to_s
- body << crlf + '--' + boundary + crlf
-if session_id && ! session_id.empty? then
- body << "Content-Disposition: form-data; name=\"exa:session\""
- body << "Content-Type: text/plain"
- body << crlf + crlf
- body << session_id
- body << crlf + '--' + boundary + crlf
-end
- begin
- File.open(datafile,'rb') do |df|
- body << "Content-Disposition: form-data; name=\"filename\""
- body << "Content-Type: text/plain"
- body << crlf + crlf
- body << datafile
- body << crlf + '--' + boundary + crlf
- body << "Content-Disposition: form-data; name=\"fakename\" ; filename=\"#{datafile}\""
- body << "Content-Type: application/octetstream"
- body << "Content-Transfer-Encoding: binary"
- body << crlf + crlf
- body << df.read
- body << crlf + '--' + boundary + '--' + crlf
- end
- rescue
- # skip
- end
- headers = Hash.new
- headers['content-type'] = "multipart/form-data; boundary=#{boundary}"
- headers['content-length'] = body.length.to_s
- begin
- File.open(resultfile,'wb') do |rf|
- begin
- # firstline is max 1024 but ok for reply
- dialogue.post(exaurl,body,headers) do |str|
- if ! firstline || firstline.empty? then
- report('receiving result') if total == 0
- firstline = str
- end
- total += 1
- rf.write(str)
- end
- rescue
- report("forced close #{traceback}")
- end
- end
- rescue
- status(replyfile,'cannot open file')
- end
- begin
- File.delete(resultfile) if File.zero?(resultfile)
- rescue
- end
- unless FileTest.file?(resultfile) then
- report("deleting empty resultfile")
- begin
- File.delete(resultfile)
- rescue
- # nice try, an error anyway
- end
- status(replyfile,'empty file')
- else
- n, id, status = 0, '', ''
- loop do
- again = false
- if ! dialogue then
- again = true
- elsif firstline =~ /(\<exa:reply)/moi then
- begin
- reply = REXML::Document.new(firstline)
- id = (REXML::XPath.match(reply.root,"/exa:reply/exa:session/text()") || '').to_s
- status = (REXML::XPath.match(reply.root,"/exa:reply/exa:status/text()") || '').to_s
- rescue
- report("error in parsing reply #{traceback}")
- break
- else
- report("status: #{status}")
- if (status =~ /^running\s*\:\s*(background|busy)$/i) && (! id.empty?) then
- report("waiting for status reply (#{n*@@polldelay})")
- again = true
- end
- end
- end
- if again then
- n += 1
- sleep(@@polldelay) # todo: duplicate when n > 1
- unless dialogue then
- report('reestablishing connection')
- dialogue = start_dialogue(address, port, processtimeout)
- end
- if dialogue then
- begin
- File.open(resultfile,'wb') do |rf|
- begin
- body = "id=#{id}"
- headers = Hash.new
- headers['content-type'] = "application/x-www-form-urlencoded"
- headers['content-length'] = body.length.to_s
- total, firstline = 0, ''
- dialogue.post("/exastatus",body,headers) do |str|
- if ! firstline || firstline.empty? then
- firstline = str
- end
- total += 1
- rf.write(str)
- end
- rescue
- report("forced close #{traceback}")
- dialogue = nil
- again = true
- end
- end
- begin
- File.delete(resultfile) if File.zero?(resultfile)
- rescue
- end
- rescue
- report("error in opening file #{traceback}")
- status(replyfile,'cannot open file')
- end
- else
- report("unable to make a connection")
- status(replyfile,'unable to make a connection') # exit
- end
- else
- break
- end
- end
- case firstline
- when /<\?xml\s*version=.*?\?>\s*<exa:reply/moi then
- begin
- File.delete(replyfile) if FileTest.file?(replyfile)
- resultfile = replyfile if File.rename(resultfile,replyfile)
- rescue
- end
- report("reply saved in '#{resultfile}'")
- when /\%PDF\-/io then
- report("done, file #{resultfile}, type pdf, #{total} chunks, #{File.size? rescue 0} bytes")
- if resultfile =~ /\.pdf$/i then
- report("file identified as 'pdf'")
- elsif resultfile =~ /\..*$/o
- report("result file suffix should be 'pdf'")
- else
- newresultfile = resultfile + '.pdf'
- newresultfile.sub!(/\.pdf\.pdf/io, '.pdf')
- pdf('close',newresultfile,autopdf)
- begin
- File.delete(newresultfile) if FileTest.file?(newresultfile)
- resultfile = newresultfile if File.rename(resultfile,newresultfile)
- rescue
- report("adding 'pdf' suffix to result name failed")
- else
- report("'pdf' suffix added to result name")
- end
- end
- report("result saved in '#{resultfile}'")
- pdf('open',resultfile,autopdf)
- status(replyfile,'ok') do
- "<exa:filename>#{resultfile}</exa:filename>"
- end
- when /html/io then
- report("done, file #{resultfile}, type html, #{total} chunks, #{File.size? rescue 0} bytes")
- if resultfile =~ /\.(htm|html)$/i then
- report("file identified as 'html'")
- elsif resultfile =~ /\..*$/o
- report("result file suffix should be 'htm'")
- else
- newresultfile = resultfile + '.htm'
- begin
- File.delete(newresultfile) if FileTest.file?(newresultfile)
- resultfile = newresultfile if File.rename(resultfile,newresultfile)
- rescue
- report("adding 'htm' suffix to result name failed")
- else
- report("'htm' suffix added to result name")
- end
- end
- report("result saved in '#{resultfile}'")
- status(replyfile,'ok') do
- "<exa:filename>#{resultfile}</exa:filename>"
- end
- else
- report("no result file, first line #{firstline}")
- status(replyfile,'no result file')
- end
- end
- rescue TimeoutError
- report("aborted due to time out")
- status(replyfile,'time out')
- rescue
- report("aborted due to some problem #{traceback}")
- status(replyfile,"no answer #{traceback}")
- end
- end
-
- begin
- report("run time: #{Time.now-start_time} seconds")
- rescue
- end
-
- end
-
- def start_dialogue(address, port, processtimeout)
- timeout(@@connecttimeout) do
- report("trying to connect to #{address}:#{port}")
- begin
- begin
- if dialogue = Net::HTTP.new(address, port) then
- # dialogue.set_debug_output $stderr
- dialogue.read_timeout = processtimeout # set this before start
- if dialogue.start then
- report("connected to #{address}:#{port}, timeout: #{processtimeout}")
- else
- retry
- end
- else
- retry
- end
- rescue
- sleep(2)
- retry
- else
- return dialogue
- end
- rescue TimeoutError
- return nil
- rescue
- return nil
- end
- end
- end
-
-end
-
-logger = Logger.new(banner.shift)
-commandline = CommandLine.new
-
-commandline.registerflag('autopdf')
-
-commandline.registervalue('path' , '')
-
-commandline.registervalue('request' , 'request.exa')
-commandline.registervalue('reply' , 'reply.exa')
-commandline.registervalue('result' , 'result')
-
-commandline.registervalue('template' , '')
-commandline.registervalue('file' , '')
-commandline.registervalue('action' , '')
-commandline.registervalue('timeout' , '')
-
-commandline.registervalue('domain' , 'default')
-commandline.registervalue('project' , 'default')
-commandline.registervalue('username' , 'guest')
-commandline.registervalue('password' , 'anonymous')
-commandline.registervalue('exaurl' , 'exarequest')
-commandline.registervalue('threshold' , '0')
-commandline.registervalue('session' , '')
-
-commandline.registervalue('address' , 'localhost')
-commandline.registervalue('port' , '80')
-
-commandline.registeraction('direct' , '[--path --request --reply --result --autopdf]')
-commandline.registeraction('construct', '[--path --request --reply --result --autopdf] --file --action')
-commandline.registeraction('extend' , '[--path --request --reply --result --autopdf] --file --action --template')
-
-commandline.registeraction('direct')
-commandline.registeraction('construct')
-commandline.registeraction('extend')
-
-commandline.registerflag('verbose')
-commandline.registeraction('help')
-commandline.registeraction('version')
-
-commandline.expand
-
-Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/scripts/context/ruby/wwwserver.rb b/scripts/context/ruby/wwwserver.rb
deleted file mode 100644
index 13d5d1312..000000000
--- a/scripts/context/ruby/wwwserver.rb
+++ /dev/null
@@ -1,293 +0,0 @@
-#!/usr/bin/env ruby
-
-banner = ['WWWServer', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
-
-$: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq!
-
-require 'base/switch'
-require 'base/logger'
-
-require 'monitor'
-
-# class WWW < Monitor
-# end
-# class Server < Monitor
-# end
-
-require 'www/lib'
-require 'www/dir'
-require 'www/login'
-require 'www/exa'
-
-require 'tempfile'
-require 'ftools'
-require 'webrick'
-
-class Server
-
- attr_accessor :document_root, :work_path, :logs_path, :port_number, :exa_url, :verbose, :trace, :direct
-
- def initialize(logger)
- @httpd = nil
- @document_root = ''
- @work_path = ''
- @logs_path = ''
- @port_number = 8061
- @exa_url = 'http://localhost:8061'
- @logger = logger
- @n_of_clients = 500
- @request_timeout = 5*60
- @verbose = false
- @trace = false
- @direct = false
- end
-
- def report(str)
- @logger.report(str) if @logger
- end
-
- def setup
- if @document_root.empty? then
- rootpath = File.expand_path($0)
- @document_root = File.expand_path(File.join(File.dirname(rootpath),'..','documents'))
- unless FileTest.directory?(@document_root) then # todo: optional
- loop do
- prevpath = rootpath.dup
- rootpath = File.dirname(rootpath)
- if prevpath == rootpath then
- break
- else
- checkpath = File.join(rootpath,'documents')
- # report("locating: #{checkpath}")
- if FileTest.directory?(checkpath) then
- @document_root = checkpath
- break
- else
- checkpath = File.join(rootpath,'docroot/documents')
- # report("locating: #{checkpath}")
- if FileTest.directory?(checkpath) then
- @document_root = checkpath
- break
- end
- end
- end
- end
- end
- end
- @document_root = File.join(Dir.pwd, 'documents') unless FileTest.directory?(@document_root)
- unless FileTest.directory?(@document_root) then
- report("invalid document root: #{@document_root}")
- exit
- else
- report("using document root: #{@document_root}")
- end
- #
- @work_path = File.expand_path(File.join(@document_root,'..','work')) if @work_path.empty?
- # begin File.makedirs(@work_path) ; rescue ; end # no, let's auto-temp
- if ! FileTest.directory?(@work_path) || ! FileTest.writable?(@work_path) then
- @work_path = File.expand_path(File.join(Dir.tmpdir,'exaserver','work'))
- begin File.makedirs(@logs_path) ; rescue ; end
- end
- report("using work path: #{@work_path}")
- #
- @logs_path = File.expand_path(File.join(@document_root,'..','logs')) if @logs_path.empty?
- # begin File.makedirs(@logs_path) ; rescue ; end # no, let's auto-temp
- if ! FileTest.directory?(@logs_path) || ! FileTest.writable?(@logs_path) then
- @logs_path = File.expand_path(File.join(Dir.tmpdir,'exaserver','logs'))
- begin File.makedirs(@logs_path) ; rescue ; end
- end
- report("using log path: #{@logs_path}")
- #
- if @logs_path.empty? then
- @logfile = $stderr
- @accfile = $stderr
- else
- @logfile = File.join(@logs_path,'exa-info.log')
- @accfile = File.join(@logs_path,'exa-access.log')
- begin File.delete(@logfile) ; rescue ; end
- begin File.delete(@accfile) ; rescue ; end
- end
- #
- begin
- @httpd = WEBrick::HTTPServer.new(
- :DocumentRoot => @document_root,
- :DocumentRootOptions => { :FancyIndexing => false },
- :DirectoryIndex => ['index.html','index.htm','showcase.pdf'],
- :Port => @port_number.to_i,
- :Logger => WEBrick::Log.new(@logfile, WEBrick::Log::INFO), # DEBUG
- :RequestTimeout => @request_timeout,
- :MaxClients => @n_of_clients,
- :AccessLog => [
- [ @accfile, WEBrick::AccessLog::COMMON_LOG_FORMAT ],
- [ @accfile, WEBrick::AccessLog::REFERER_LOG_FORMAT ],
- [ @accfile, WEBrick::AccessLog::AGENT_LOG_FORMAT ],
- # :CGIPathEnv => ENV["PATH"] # PATH environment variable for CGI.
- ]
- )
- rescue
- report("starting server at port: #{@port_number} failed")
- exit
- else
- report("running server at port: #{@port_number}")
- end
-
- begin
- #
- @httpd.mount_proc("/dir") do |request,reply|
- report("accepting /dir") if @verbose
- web_session(request,reply).handle_dir
- end
- @httpd.mount_proc("/login") do |request,reply|
- report("accepting /login") if @verbose
- web_session(request,reply).handle_login
- end
- @httpd.mount("/cache", WEBrick::HTTPServlet::FileHandler, File.join(@work_path,'cache'))
- # @httpd.mount_proc("/cache") do |request,reply|
- # WEBrick::HTTPServlet::FileHandler(@httpd,@work_path) # not ok
- # end
- @httpd.mount_proc("/exalogin") do |request,reply|
- report("accepting /exalogin") if @verbose
- web_session(request,reply).handle_exalogin
- end
- @httpd.mount_proc("/exadefault") do |request,reply|
- report("accepting /exadefault") if @verbose
- web_session(request,reply).handle_exadefault
- end
- @httpd.mount_proc("/exainterface") do |request,reply|
- report("accepting /exainterface") if @verbose
- web_session(request,reply).handle_exainterface
- end
- @httpd.mount_proc("/exarequest") do |request,reply|
- report("accepting /exarequest") if @verbose
- web_session(request,reply).handle_exarequest
- end
- @httpd.mount_proc("/exacommand") do |request,reply|
- report("accepting /exacommand") if @verbose
- web_session(request,reply).handle_exacommand
- end
- @httpd.mount_proc("/exastatus") do |request,reply|
- report("accepting /exastatus") if @verbose
- web_session(request,reply).handle_exastatus
- end
- @httpd.mount_proc("/exaadmin") do |request,reply|
- report("accepting /exaadmin") if @verbose
- web_session(request,reply).handle_exaadmin
- end
- #
- rescue
- report("problem in starting server: #{$!}")
- end
- [:INT, :TERM, :EXIT].each do |signal|
- trap(signal) do
- @httpd.shutdown
- end
- end
- end
-
- def start
- unless @httpd then
- setup
- @httpd.start
- end
- end
-
- def stop
- @httpd.shutdown if @httpd
- end
-
- def restart
- stop
- start
- end
-
- private
-
- def web_session(request,reply)
- www = WWW.new(@httpd,request,reply)
- www.set('path:work', @work_path)
- www.set('path:logs', @logs_path)
- www.set('path:root', File.dirname(@document_root))
- www.set('process:exaurl', @exa_url)
- www.set('trace:errors','yes') if @trace
- www.set('process:background', 'no') if @direct
- return www
- end
-
-end
-
-class Commands
-
- include CommandBase
-
- def start
- if server = setup then server.start end
- end
-
- def stop
- if server = setup then server.stop end
- end
-
- def restart
- if server = setup then server.restart end
- end
-
- private
-
- def setup
- server = Server.new(logger)
- server.document_root = @commandline.option('root')
- server.verbose = @commandline.option('verbose')
- if @commandline.option('forcetemp') then
- server.work_path = Dir.tmpdir + '/exa/work'
- server.logs_path = Dir.tmpdir + '/exa/logs'
- [server.work_path,server.logs_path].each do |d|
- begin
- File.makedirs(d) unless FileTest.directory?(d)
- rescue
- report("unable to create #{d}")
- exit
- end
- unless FileTest.writable?(d) then
- report("unable to access #{d}")
- exit
- end
- end
- else
- server.work_path = @commandline.option('work')
- server.logs_path = @commandline.option('logs')
- end
- server.port_number = @commandline.option('port')
- server.exa_url = @commandline.option('url')
- server.trace = @commandline.option('trace')
- server.direct = @commandline.option('direct')
- return server
- end
-
-end
-
-logger = Logger.new(banner.shift)
-commandline = CommandLine.new
-
-commandline.registervalue('root' , '')
-commandline.registervalue('work' , '')
-commandline.registervalue('logs' , '')
-commandline.registervalue('address', 'localhost')
-commandline.registervalue('port' , '8061')
-commandline.registervalue('url' , 'http://localhost:8061')
-
-commandline.registeraction('start' , 'start the server [--root --forcetemp --work --logs --address --port --url]')
-commandline.registeraction('stop' , 'stop the server')
-commandline.registeraction('restart', 'restart the server')
-
-commandline.registerflag('forcetemp')
-commandline.registerflag('direct')
-commandline.registerflag('verbose')
-commandline.registerflag('trace')
-
-commandline.registeraction('help')
-commandline.registeraction('version')
-
-commandline.expand
-
-Commands.new(commandline,logger,banner).send(commandline.action || 'start')
-
diff --git a/scripts/context/ruby/wwwwatch.rb b/scripts/context/ruby/wwwwatch.rb
deleted file mode 100644
index 0faa45aec..000000000
--- a/scripts/context/ruby/wwwwatch.rb
+++ /dev/null
@@ -1,497 +0,0 @@
-#!/usr/bin/env ruby
-
-banner = ['WWWWatch', 'version 1.0.0', '2003-2006', 'PRAGMA ADE/POD']
-
-$: << File.expand_path(File.dirname($0)) ; $: << File.join($:.last,'lib') ; $:.uniq!
-
-require 'base/switch'
-require 'base/logger'
-
-require 'www/common'
-
-require 'monitor'
-require 'fileutils'
-require 'ftools'
-require 'tempfile'
-require 'timeout'
-require 'thread'
-
-class Watch < Monitor
-
- include Common
-
- @@session_prefix = ''
- @@check_factor = 4
- @@process_timeout = 1*60*60
- @@fast_wait_loop = false
-
- @@session_line = /^\s*(?![\#\%])(.*?)\s*\=\s*(.*?)\s*$/o
- @@session_begin = 'begin exa session'
- @@session_end = 'end exa session'
-
- attr_accessor :root_path, :work_path, :create, :cache_path, :delay, :max_threads, :max_age, :verbose
-
- def initialize(logger) # we need to register all @vars here becase of the monitor
- @threads = Hash.new
- @files = Array.new
- @stats = Hash.new
- @skips = Hash.new
- @root_path = ''
- @work_path = Dir.tmpdir
- @cache_path = @work_path
- @last_action = Time.now
- @delay = 1
- @max_threads = 5
- @max_age = @@process_timeout
- @logger = logger
- @verbose = false
- @create = false
- @onlyonerun = false
- # [:INT, :TERM, :EXIT].each do |signal|
- # trap(signal) do
- # kill
- # exit # rescue false
- # end
- # end
- # at_exit do
- # kill
- # end
- end
-
- def trace
- if @verbose && @logger then
- @logger.report("exception: #{$!})")
- $@.each do |t|
- @logger.report(">> #{t}")
- end
- end
- end
-
- def report(str)
- @logger.report(str) if @logger
- end
-
- def setup
- @threads = Hash.new
- @files = Array.new
- @stats = Hash.new
- @skips = Hash.new
- @root_path = File.expand_path(File.join(File.dirname(Dir.pwd),'.')) if @root_path.empty?
- @work_path = File.expand_path(File.join(@root_path,'work','watch')) if @work_path.empty?
- # @cache_path = File.expand_path(File.join(@root_path,'work','cache')) if @cache_path.empty?
- @cache_path = File.expand_path(File.join(File.dirname(@work_path),'cache')) if @cache_path.empty?
- if @create then
- begin File.makedirs(@work_path) ; rescue ; end
- begin File.makedirs(@cache_path) ; rescue ; end
- end
- unless File.writable?(@work_path) then
- @work_path = File.expand_path(File.join(Dir.tmpdir,'work','watch'))
- if @create then
- begin File.makedirs(@work_path) ; rescue ; end
- end
- end
- unless File.writable?(@cache_path) then
- @cache_path = File.expand_path(File.join(Dir.tmpdir,'work','cache'))
- if @create then
- begin File.makedirs(@cache_path) ; rescue ; end
- end
- end
- unless File.writable?(@work_path) then
- puts "no valid work path: #{@work_path}"
- exit! rescue false # no checking, no at_exit done
- end
- unless File.writable?(@cache_path) then
- puts "no valid cache path: #{@cache_path}" ; # no reason to exit
- end
- @last_action = Time.now
- report("watching path #{@work_path}") if @verbose
- end
-
- def lock(lck)
- begin
- report("watchdog: locking #{lck}") if @verbose
- File.open(lck,'w') do |f|
- f << Time.now
- end
- rescue
- trace
- end
- end
-
- def unlock(lck)
- begin
- report("watchdog: unlocking #{lck}") if @verbose
- File.delete(lck)
- rescue
- trace
- end
- end
-
- def kill
- @threads.each do |t|
- t.kill rescue false
- end
- end
-
- def restart
- @files = Array.new
- @skips = Hash.new
- @stats = Hash.new
- kill # threads
- end
-
- def collect
- begin
- @files = Array.new
- Dir.glob("#{@work_path}/#{@@session_prefix}*.ses").each do |sessionfile|
- sessionfile = File.expand_path(sessionfile)
- begin
- if @threads.key?(sessionfile) then
- # leave alone
- elsif (Time.now - File.mtime(sessionfile)) > @max_age.to_i then
- # delete
- FileUtils::rm_r(sessionfile) rescue false
- FileUtils::rm_r(sessionfile.sub(/ses$/,'dir')) rescue false
- FileUtils::rm_r(sessionfile.sub(/ses$/,'lck')) rescue false
- begin
- FileUtils::rm_r(File.join(@cache_path, File.basename(sessionfile.sub(/ses$/,'dir'))))
- rescue
- report("watchdog: problems in cache cleanup #{$!}") # if @verbose
- end
- @stats.delete(sessionfile) rescue false
- @skips.delete(sessionfile) rescue false
- report("watchdog: removing session #{sessionfile}") if @verbose
- elsif ! @skips.key?(sessionfile) then
- @files << sessionfile
- report("watchdog: checking session #{sessionfile}") if @verbose
- end
- rescue
- # maybe purged in the meantime
- end
- end
- rescue
- if File.directory?(@work_path) then
- @files = Array.new
- else
- # maybe dir is deleted (manual cleanup)
- restart
- end
- end
- begin
- Dir.glob("#{@cache_path}/*.dir").each do |dirname|
- begin
- if (Time.now - File.mtime(dirname)) > @max_age.to_i then
- begin
- FileUtils::rm_r(dirname)
- rescue
- report("watchdog: problems in cache cleanup #{$!}") # if @verbose
- end
- end
- rescue
- # maybe purged in the meantime
- end
- end
- rescue
- end
- end
-
- def purge
- begin
- Dir.glob("#{@work_path}/#{@@session_prefix}*").each do |sessionfile|
- sessionfile = File.expand_path(sessionfile)
- begin
- if (Time.now - File.mtime(sessionfile)) > @max_age.to_i then
- begin
- if FileTest.directory?(sessionfile) then
- FileUtils::rm_r(sessionfile)
- else
- File.delete(sessionfile)
- end
- rescue
- end
- begin
- @stats.delete(sessionfile)
- @skips.delete(sessionfile)
- rescue
- end
- report("watchdog: purging session #{sessionfile}") if @verbose
- end
- rescue
- # maybe purged in the meantime
- end
- end
- rescue
- end
- end
-
- def loaded_session_data(filename)
- begin
- if data = IO.readlines(filename) then
- return data if (data.first =~ /^[\#\%]\s*#{@@session_begin}/o) && (data.last =~ /^[\#\%]\s*#{@@session_end}/o)
- end
- rescue
- trace
- end
- return nil
- end
-
- def load(sessionfile)
- # we assume that we get an exception when the file is locked
- begin
- if data = loaded_session_data(sessionfile) then
- report("watchdog: loading session #{sessionfile}") if @verbose
- vars = Hash.new
- data.each do |line|
- begin
- if line.chomp =~ /^(.*?)\s*\=\s*(.*?)\s*$/o then
- key, value = $1, $2
- vars[key] = value
- end
- rescue
- end
- end
- return vars
- else
- return nil
- end
- rescue
- trace
- return nil
- end
- end
-
- def save(sessionfile, vars)
- begin
- report("watchdog: saving session #{sessionfile}") if @verbose
- if @stats.key?(sessionfile) then
- @stats[sessionfile] = File.mtime(sessionfile)
- elsif @stats[sessionfile] == File.mtime(sessionfile) then
- else
- # construct data first
- str = "\# #{@@session_begin}\n"
- for k,v in vars do
- str << "#{k}=#{v}\n"
- end
- str << "\# #{@@session_end}\n"
- # save as fast as possible
- File.open(sessionfile,'w') do |f|
- f.puts(str)
- end
- end
- rescue
- report("watchdog: unable to save session #{sessionfile}") if @verbose
- trace
- return false
- else
- return true
- end
- end
-
- def launch
- begin
- @files.each do |sessionfile|
- if @threads.length < @max_threads then
- begin
- if ! @skips.key?(sessionfile) && (vars = load(sessionfile)) then
- if (id = vars['id']) && vars['status'] then
- if vars['status'] == 'running: background' then
- @last_action = Time.now
- @threads[sessionfile] = Thread.new(vars, sessionfile) do |vars, sessionfile|
- begin
- report("watchdog: starting thread #{sessionfile}") if @verbose
- dir = File.expand_path(sessionfile.sub(/ses$/,'dir'))
- lck = File.expand_path(sessionfile.sub(/ses$/,'lck'))
- start_of_run = Time.now
- start_of_job = start_of_run.dup
- max_time = @max_age
- begin
- start_of_job = vars['starttime'].to_i || start_of_run
- start_of_job = start_of_run if start_of_job == 0
- rescue
- start_of_job = Time.now
- end
- begin
- max_runtime = vars['maxtime'].to_i || @max_age
- max_runtime = @max_age if max_runtime == 0
- max_runtime = max_runtime - (Time.now.to_i - start_of_job.to_i)
- rescue
- max_runtime = @max_age
- end
- lock(lck)
- if max_runtime > 0 then
- command = vars['command'] || ''
- if ! command.empty? then
- vars['status'] = 'running: busy'
- vars['timeout'] = max_runtime.to_s
- save(sessionfile,vars)
- timeout(max_runtime) do
- begin
- command = command_string(dir,command,'process.log')
- report("watchdog: #{command}") if @verbose
- system(command)
- rescue TimeoutError
- vars['status'] = 'running: timeout'
- rescue
- trace
- vars['status'] = 'running: aborted'
- else
- vars['status'] = 'running: finished'
- vars['runtime'] = sprintf("%.02f",(Time.now - start_of_run))
- vars['endtime'] = Time.now.to_i.to_s
- end
- end
- else
- vars['status'] = 'running: aborted' # no command
- end
- else
- vars['status'] = 'running: aborted' # not enough time
- end
- save(sessionfile,vars)
- unlock(lck)
- report("watchdog: ending thread #{sessionfile}") if @verbose
- @threads.delete(sessionfile)
- rescue
- trace
- end
- end
- else
- report("watchdog: skipping - id (#{vars['id']}) / status (#{vars['status']})") if @verbose
- end
- if @onlyonerun then
- @skips[sessionfile] = true
- else
- @skips.delete(sessionfile)
- end
- else
- # not yet ok
- end
- else
- # maybe a lock
- end
- rescue
- trace
- end
- else
- break
- end
- end
- rescue
- trace
- end
- end
-
- def wait
- begin
- # report(Time.now.to_s) if @verbose
- loop do
- @threads.delete_if do |k,v|
- begin
- v == nil || v.stop?
- rescue
- true
- else
- false
- end
- end
- if @threads.length == @max_threads then
- if @delay > @max_threads then
- sleep(@delay)
- else
- sleep(@max_threads)
- end
- break if @@fast_wait_loop
- else
- sleep(@delay)
- break
- end
- end
- rescue
- trace
- end
- end
-
- def check
- begin
- time = Time.now
- if (time - @last_action) > @@check_factor*@max_age then
- report("watchdog: cleanup") if @verbose
- @stats = Hash.new
- @last_action = time
- kill
- end
- rescue
- trace
- end
- end
-
- def cycle
- loop do
- begin
- collect
- launch
- wait
- check
- rescue
- trace
- report("watchdog: some problem, restarting loop")
- end
- end
- end
-
-end
-
-class Commands
-
- include CommandBase
-
- def watch
- if watch = setup then
- watch.cycle
- else
- report("provide valid work path")
- end
- end
- def main
- watch
- end
-
- private
-
- def setup
- if watch = Watch.new(logger) then
- watch.root_path = @commandline.option('root')
- watch.work_path = @commandline.option('work')
- watch.cache_path = @commandline.option('cache')
- watch.create = @commandline.option('create')
- watch.verbose = @commandline.option('verbose')
- begin
- watch.max_threads = @commandline.option('threads').to_i
- rescue
- watch.max_threads = 5
- end
- watch.setup
- end
- return watch
- end
-
-end
-
-logger = Logger.new(banner.shift)
-commandline = CommandLine.new
-
-commandline.registervalue('root', '')
-commandline.registervalue('work', '')
-commandline.registervalue('cache', '')
-commandline.registervalue('threads', '5')
-
-commandline.registerflag('create')
-
-commandline.registeraction('watch', '[--work=path] [--root=path] [--create]')
-
-commandline.registerflag('verbose')
-commandline.registeraction('help')
-commandline.registeraction('version')
-
-commandline.expand
-
-Commands.new(commandline,logger,banner).send(commandline.action || 'main')
diff --git a/scripts/context/stubs/mswin/ctxtools.bat b/scripts/context/stubs/mswin/ctxtools.bat
index f1f5e019e..8047c9b68 100755
--- a/scripts/context/stubs/mswin/ctxtools.bat
+++ b/scripts/context/stubs/mswin/ctxtools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart ctxtools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute ctxtools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/exatools.bat b/scripts/context/stubs/mswin/exatools.bat
deleted file mode 100755
index 57f798e82..000000000
--- a/scripts/context/stubs/mswin/exatools.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart exatools.rb %*
diff --git a/scripts/context/stubs/mswin/luatools.lua b/scripts/context/stubs/mswin/luatools.lua
new file mode 100644
index 000000000..aacdbd16d
--- /dev/null
+++ b/scripts/context/stubs/mswin/luatools.lua
@@ -0,0 +1,6977 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['luatools'] = {
+ version = 1.001,
+ comment = "companion to context.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+-- one can make a stub:
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua texlua luatools.lua "$@"
+
+-- Although this script is part of the ConTeXt distribution it is
+-- relatively indepent of ConTeXt. The same is true for some of
+-- the luat files. We may may make them even less dependent in
+-- the future. As long as Luatex is under development the
+-- interfaces and names of functions may change.
+
+-- For the sake of independence we optionally can merge the library
+-- code here. It's too much code, but that does not harm. Much of the
+-- library code is used elsewhere. We don't want dependencies on
+-- Lua library paths simply because these scripts are located in the
+-- texmf tree and not in some Lua path. Normally this merge is not
+-- needed when texmfstart is used, or when the proper stub is used or
+-- when (windows) suffix binding is active.
+
+texlua = true
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+function string:quote() -- we could use format("%q")
+ return '"' .. self:unquote() .. '"'
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+function string:strip()
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
+end
+
+function string:is_empty()
+ return not find(find,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, str:sub(index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. self.rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+local hash = { }
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return P(pattern)
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local newline = crlf + cr + lf
+local spacing = space^0 * newline
+
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return capture:match(self)
+end
+
+lpeg.linebyline = content -- better make a sublibrary
+
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, ipairs = type, next, tostring, ipairs
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+function table.one_entry(t)
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+function table.starts_at(t)
+ return ipairs(t,1)(t,0)
+end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete)
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end })
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ 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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data)
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+number = number or { }
+
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+function number.toevenhex(n)
+ local s = format("%X",n)
+ if #s % 2 == 0 then
+ return s
+ else
+ return "0" .. s
+ end
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+local one = lpeg.C(1-lpeg.S(''))^1
+
+function number.toset(n)
+ return one:match(tostring(n))
+end
+
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+set = set or { }
+
+local nums = { }
+local tabs = { }
+local concat = table.concat
+
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
+ end
+ end
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
+ end
+ return nums[s]
+ else
+ return 0
+ end
+end
+
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
+ end
+end
+
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
+end
+
+--~ local c = set.create{'aap','noot','mies'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ local c = set.create{'zus','wim','jet'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ print(t['jet'])
+--~ print(set.contains(t,'jet'))
+--~ print(set.contains(t,'aap'))
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+function os.resultof(command)
+ return io.popen(command,"r"):read("*all")
+end
+
+if not os.exec then os.exec = os.execute end
+if not os.spawn then os.spawn = os.execute end
+
+--~ os.type : windows | unix (new, we already guessed os.platform)
+--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
+
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
+ else
+ io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
+ end
+end
+
+os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
+
+function os.launch(str)
+ if os.platform == "windows" then
+ os.execute("start " .. str) -- os.spawn ?
+ else
+ os.execute(str .. " &") -- os.spawn ?
+ end
+end
+
+if not os.setenv then
+ function os.setenv() return false end
+end
+
+if not os.times then
+ -- utime = user time
+ -- stime = system time
+ -- cutime = children user time
+ -- cstime = children system time
+ function os.times()
+ return {
+ utime = os.gettimeofday(), -- user
+ stime = 0, -- system
+ cutime = 0, -- children user
+ cstime = 0, -- children system
+ }
+ end
+end
+
+os.gettimeofday = os.gettimeofday or os.clock
+
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
+end
+
+--~ print(os.gettimeofday()-os.time())
+--~ os.sleep(1.234)
+--~ print (">>",os.runtime())
+--~ print(os.date("%H:%M:%S",os.gettimeofday()))
+--~ print(os.date("%H:%M:%S",os.time()))
+
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name)
+ return match(name,"^(.+)[/\\].-$") or ""
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name)
+ return match(name,"^.+%.([^/\\]-)$") or ""
+end
+
+file.suffix = file.extname
+
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.join(...)
+ local pth = concat({...},"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ return (gsub(pth,"//+","/"))
+end
+
+function file.iswritable(name)
+ local a = lfs.attributes(name)
+ if a and a.permissions:sub(2,2) == "w" then
+ return true
+ else
+ name = file.dirname(name) or "."
+ if name == "" then name = "." end
+ a = lfs.attributes(name)
+ return a and a.permissions:sub(2,2) == "w"
+ end
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and a.permissions:sub(1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+function file.split_path(str)
+ local t = { }
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
+ if name ~= "" then
+ t[#t+1] = gsub(name,"\001",":")
+ end
+ end
+ return t
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+function file.collapse_path(str)
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return pattern:match(name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = pattern:match(name)
+--~ if b then
+--~ return name:sub(a,b-2)
+--~ elseif a then
+--~ return name:sub(a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEXsum(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-url'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local char, gmatch = string.char, string.gmatch
+local tonumber, type = tonumber, type
+
+-- from the spec (on the web):
+--
+-- foo://example.com:8042/over/there?name=ferret#nose
+-- \_/ \______________/\_________/ \_________/ \__/
+-- | | | | |
+-- scheme authority path query fragment
+-- | _____________________|__
+-- / \ / \
+-- urn:example:animal:ferret:nose
+
+url = url or { }
+
+local function tochar(s)
+ return char(tonumber(s,16))
+end
+
+local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
+
+local hexdigit = lpeg.R("09","AF","af")
+local plus = lpeg.P("+")
+local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar)
+
+local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
+local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
+local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
+local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
+local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
+
+local parser = lpeg.Ct(scheme * authority * path * query * fragment)
+
+function url.split(str)
+ return (type(str) == "string" and parser:match(str)) or str
+end
+
+function url.hashed(str)
+ local s = url.split(str)
+ return {
+ scheme = (s[1] ~= "" and s[1]) or "file",
+ authority = s[2],
+ path = s[3],
+ query = s[4],
+ fragment = s[5],
+ original = str
+ }
+end
+
+function url.filename(filename)
+ local t = url.hashed(filename)
+ return (t.scheme == "file" and t.path:gsub("^/([a-zA-Z])([:|])/)","%1:")) or filename
+end
+
+function url.query(str)
+ if type(str) == "string" then
+ local t = { }
+ for k, v in gmatch(str,"([^&=]*)=([^&=]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return str
+ end
+end
+
+--~ print(url.filename("file:///c:/oeps.txt"))
+--~ print(url.filename("c:/oeps.txt"))
+--~ print(url.filename("file:///oeps.txt"))
+--~ print(url.filename("file:///etc/test.txt"))
+--~ print(url.filename("/oeps.txt"))
+
+--~ from the spec on the web (sort of):
+--~
+--~ function test(str)
+--~ print(table.serialize(url.hashed(str)))
+--~ end
+--~
+--~ test("%56pass%20words")
+--~ test("file:///c:/oeps.txt")
+--~ test("file:///c|/oeps.txt")
+--~ test("file:///etc/oeps.txt")
+--~ test("file://./etc/oeps.txt")
+--~ test("file:////etc/oeps.txt")
+--~ test("ftp://ftp.is.co.za/rfc/rfc1808.txt")
+--~ test("http://www.ietf.org/rfc/rfc2396.txt")
+--~ test("ldap://[2001:db8::7]/c=GB?objectClass?one#what")
+--~ test("mailto:John.Doe@example.com")
+--~ test("news:comp.infosystems.www.servers.unix")
+--~ test("tel:+1-816-555-1212")
+--~ test("telnet://192.0.2.16:80/")
+--~ test("urn:oasis:names:specification:docbook:dtd:xml:4.1.2")
+--~ test("/etc/passwords")
+--~ test("http://www.pragma-ade.com/spaced%20name")
+
+--~ test("zip:///oeps/oeps.zip#bla/bla.tex")
+--~ test("zip:///oeps/oeps.zip?bla/bla.tex")
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local find, gmatch = string.find, string.gmatch
+
+dir = dir or { }
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
+ end
+ end
+ end
+end
+
+dir.glob_pattern = glob_pattern
+
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
+
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
+ local t = t or { }
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
+ return t
+ else
+ return { }
+ end
+ end
+end
+
+dir.glob = glob
+
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
+
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
+ files[#files+1] = path .. "/" .. name
+ end
+ else
+ files[#files+1] = path .. "/" .. name
+ end
+ end
+ end
+ end
+ return files
+end
+
+dir.globfiles = globfiles
+
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
+
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
+
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
+
+local make_indeed = true -- false
+
+if string.find(os.getenv("PATH"),";") then
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
+ if first then
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
+ else
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
+ if first then
+ pth, drive = first .. middle, true
+ else
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
+ end
+ end
+ end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("a:"))
+--~ print(dir.mkdirs("a:/b/c"))
+--~ print(dir.mkdirs("a:b/c"))
+--~ print(dir.mkdirs("a:/bbb/c"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
+ end
+ lfs.chdir(d)
+ end
+ end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
+
+else
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
+ end
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
+ end
+
+end
+
+dir.makedirs = dir.mkdirs
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+function boolean.alwaystrue()
+ return true
+end
+
+function boolean.falsetrue()
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+utf = utf or unicode.utf8
+
+local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
+local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
+
+unicode = unicode or { }
+
+-- 0 EF BB BF UTF-8
+-- 1 FF FE UTF-16-little-endian
+-- 2 FE FF UTF-16-big-endian
+-- 3 FF FE 00 00 UTF-32-little-endian
+-- 4 00 00 FE FF UTF-32-big-endian
+
+unicode.utfname = {
+ [0] = 'utf-8',
+ [1] = 'utf-16-le',
+ [2] = 'utf-16-be',
+ [3] = 'utf-32-le',
+ [4] = 'utf-32-be'
+}
+
+function unicode.utftype(f) -- \000 fails !
+ local str = f:read(4)
+ if not str then
+ f:seek('set')
+ return 0
+ elseif find(str,"^%z%z\254\255") then
+ return 4
+ elseif find(str,"^\255\254%z%z") then
+ return 3
+ elseif find(str,"^\254\255") then
+ f:seek('set',2)
+ return 2
+ elseif find(str,"^\255\254") then
+ f:seek('set',2)
+ return 1
+ elseif find(str,"^\239\187\191") then
+ f:seek('set',3)
+ return 0
+ else
+ f:seek('set')
+ return 0
+ end
+end
+
+function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
+ local result, tmp, n, m, p = { }, { }, 0, 0, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for l,r in bytepairs(str) do
+ if r then
+ if endian then
+ n = l*256 + r
+ else
+ n = r*256 + l
+ end
+ if m > 0 then
+ n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000
+ m = 0
+ doit()
+ elseif n >= 0xD800 and n <= 0xDBFF then
+ m = n
+ else
+ doit()
+ end
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+function unicode.utf32_to_utf8(str, endian)
+ local result = { }
+ local tmp, n, m, p = { }, 0, -1, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for a,b in bytepairs(str) do
+ if a and b then
+ if m < 0 then
+ if endian then
+ m = a*256*256*256 + b*256*256
+ else
+ m = b*256 + a
+ end
+ else
+ if endian then
+ n = m + a*256 + b
+ else
+ n = m + b*256*256*256 + a*256*256
+ end
+ m = -1
+ doit()
+ end
+ else
+ break
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+local function little(c)
+ local b = byte(c) -- b = c:byte()
+ if b < 0x10000 then
+ return char(b%256,b/256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1%256,b1/256,b2%256,b2/256)
+ end
+end
+
+local function big(c)
+ local b = byte(c)
+ if b < 0x10000 then
+ return char(b/256,b%256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1/256,b1%256,b2/256,b2%256)
+ end
+end
+
+function unicode.utf8_to_utf16(str,littleendian)
+ if littleendian then
+ return char(255,254) .. utfgsub(str,".",little)
+ else
+ return char(254,255) .. utfgsub(str,".",big)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
+
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (data:gsub(utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for _, lib in ipairs(libs) do
+ for _, pth in ipairs(list) do
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return table.concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
+ end
+ end
+ grandtotal = grandtotal + count
+ functions = functions + 1
+ end
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+end
+
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
+ end
+end
+
+function debugger.enable()
+ debug.sethook(hook,"c")
+end
+
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
+end
+
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
+ end
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
+
+-- dirty tricks
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
+
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index, argument in pairs(arg) do
+ if index > 0 then
+ local flag, value = argument:match("^%-+(.+)=(.-)$")
+ if flag then
+ arguments[flag] = string.unquote(value or "")
+ else
+ flag = argument:match("^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = { }
+ for _,v in pairs(table.sortedkeys(arguments)) do
+ sortedflags[#sortedflags+1] = "^" .. v
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for _,v in ipairs(sortedflags) do
+ if name:find(v) then
+ return arguments[v:sub(2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ for _,v in ipairs(environment.original_arguments) do
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ return a
+ elseif next(arg) then
+ local result = { }
+ for _,a in ipairs(arg) do -- ipairs 1 .. #n
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ a = a:gsub('"','\\"') -- tricky
+ if a:find(" ") then
+ result[#result+1] = a:quote()
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index, argument in ipairs(arg) do
+ if argument:find("^\"") then
+ newarg[#newarg+1] = argument:gsub("^\"","")
+ if not argument:find("\"$") then
+ instring = true
+ end
+ elseif argument:find("\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "companion to luat-lib.tex",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ instance.variables[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
+
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
+ else
+ local binary = resolvers.ownbin
+ if os.platform == "windows" then
+ binary = file.replacesuffix(binary,"exe")
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
+ end
+ resolvers.ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
+ end
+ resolvers.ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
+ end
+ return resolvers.ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ local f = io.open(lname)
+ if f then -- this will go
+ f:close()
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
+ for k,v in pairs(c) do
+ if type(v) == 'string' then
+ local t = file.split_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return file.split_path(str)
+ end
+end
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h = { }, { }
+ for _,vv in ipairs(file.split_path(v)) do
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ for _, cnf in ipairs(instance.cnffiles) do
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(str)
+ else
+ return resolvers.expanded_path_list(tmp)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","+ readable: %s",name)
+ else
+ logs.report("fileio","- readable: %s", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local doscan, recurse
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist and not (done and not instance.allresults) and recurse then
+ -- compare list entries with permitted pattern
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
+ local expr = "^" .. pathname
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
+ end
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag]
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_verbose then
+ report('')
+ end
+ for _, file in ipairs(files) do
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for _,v in ipairs(result) do
+ report(v)
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in pairs(t) do -- pairs?
+ s[#s+1] = k .. "=" .. v
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ for _, hash in ipairs(instance.hashes) do
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in pairs(v) do -- ipairs?
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.</p>
+
+</code>
+TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
+</code>
+
+<p>Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.</p>
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ return loader()
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if table.is_empty(mountpaths) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if not table.is_empty(mountpaths) then
+ statistics.starttiming(resolvers.instance)
+ for k, root in pairs(mountpaths) do
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if line:find("^[%%#%-]") then -- or %W
+ -- skip
+ elseif line:find("^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-lst'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- used in mtxrun
+
+local find, concat, upper, format = string.find, table.concat, string.upper, string.format
+
+resolvers.listers = resolvers.listers or { }
+
+local function tabstr(str)
+ if type(str) == 'table' then
+ return concat(str," | ")
+ else
+ return str
+ end
+end
+
+local function list(list,report)
+ local instance = resolvers.instance
+ local pat = upper(pattern or "","")
+ local report = report or texio.write_nl
+ for _,key in pairs(table.sortedkeys(list)) do
+ if instance.pattern == "" or find(upper(key),pat) then
+ if instance.kpseonly then
+ if instance.kpsevars[key] then
+ report(format("%s=%s",key,tabstr(list[key])))
+ end
+ else
+ report(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
+ end
+ end
+ end
+end
+
+function resolvers.listers.variables () list(resolvers.instance.variables ) end
+function resolvers.listers.expansions() list(resolvers.instance.expansions) end
+
+function resolvers.listers.configurations(report)
+ local report = report or texio.write_nl
+ local instance = resolvers.instance
+ for _,key in ipairs(table.sortedkeys(instance.kpsevars)) do
+ if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
+ report(format("%s\n",key))
+ for i,c in ipairs(instance.order) do
+ local str = c[key]
+ if str then
+ report(format("\t%s\t%s",i,str))
+ end
+ end
+ report("")
+ end
+ end
+end
+
+
+end -- of closure
+-- end library merge
+
+-- We initialize some characteristics of this program. We need to
+-- do this before we load the libraries, else own.name will not be
+-- properly set (handy for selfcleaning the file). It's an ugly
+-- looking piece of code.
+
+own = { }
+
+own.libs = { -- todo: check which ones are really needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-io.lua',
+ 'l-number.lua',
+ 'l-set.lua',
+ 'l-os.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-url.lua',
+ 'l-dir.lua',
+ 'l-boolean.lua',
+ 'l-unicode.lua',
+ 'l-math.lua',
+ 'l-utils.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+-- 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-lst.lua', -- lister
+}
+
+-- We need this hack till luatex is fixed.
+
+if arg and arg[0] == 'luatex' and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+-- End of hack.
+
+own.name = (environment and environment.ownname) or arg[0] or 'luatools.lua'
+own.path = string.match(own.name,"^(.+)[\\/].-$") or "."
+own.list = { '.' }
+
+if own.path ~= '.' then
+ table.insert(own.list,own.path)
+end
+
+table.insert(own.list,own.path.."/../../../tex/context/base")
+table.insert(own.list,own.path.."/mtx")
+table.insert(own.list,own.path.."/../sources")
+
+function locate_libs()
+ for _, lib in pairs(own.libs) do
+ for _, pth in pairs(own.list) do
+ local filename = string.gsub(pth .. "/" .. lib,"\\","/")
+ local codeblob = loadfile(filename)
+ if codeblob then
+ codeblob()
+ own.list = { pth } -- speed up te search
+ break
+ end
+ end
+ end
+end
+
+if not resolvers then
+ locate_libs()
+end
+
+if not resolvers then
+ print("")
+ print("Luatools is unable to start up due to lack of libraries. You may")
+ print("try to run 'lua luatools.lua --selfmerge' in the path where this")
+ print("script is located (normally under ..../scripts/context/lua) which")
+ print("will make luatools library independent.")
+ os.exit()
+end
+
+logs.setprogram('LuaTools',"TDS Management Tool 1.31",environment.arguments["verbose"] or false)
+
+local instance = resolvers.reset()
+
+resolvers.defaultlibs = { -- not all are needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-boolean.lua',
+ 'l-number.lua',
+ 'l-unicode.lua',
+ 'l-os.lua',
+ 'l-io.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-url.lua',
+ 'l-dir.lua',
+ 'l-utils.lua',
+ 'l-dimen.lua',
+ 'trac-inf.lua',
+ 'trac-tra.lua',
+ 'trac-log.lua',
+ 'luat-env.lua', -- here ?
+ 'data-res.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-tmp.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-pre.lua',
+ 'data-tex.lua',
+ 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-clr.lua',
+ 'data-lua.lua',
+ 'data-ctx.lua',
+ 'luat-fio.lua',
+ 'luat-cnf.lua',
+}
+
+instance.engine = environment.arguments["engine"] or 'luatex'
+instance.progname = environment.arguments["progname"] or 'context'
+instance.luaname = environment.arguments["luafile"] or "" -- environment.ownname or ""
+instance.lualibs = environment.arguments["lualibs"] or table.concat(resolvers.defaultlibs,",")
+instance.allresults = environment.arguments["all"] or false
+instance.pattern = environment.arguments["pattern"] or nil
+instance.sortdata = environment.arguments["sort"] or false
+instance.kpseonly = not environment.arguments["all"] or false
+instance.my_format = environment.arguments["format"] or instance.format
+
+if type(instance.pattern) == 'boolean' then
+ logs.simple("invalid pattern specification")
+ instance.pattern = nil
+end
+
+if environment.arguments["trace"] then resolvers.settrace(environment.arguments["trace"]) end
+
+runners = runners or { }
+messages = messages or { }
+
+messages.no_ini_file = [[
+There is no lua initialization file found. This file can be forced by the
+"--progname" directive, or specified with "--luaname", or it is derived
+automatically from the formatname (aka jobname). It may be that you have
+to regenerate the file database using "luatools --generate".
+]]
+
+messages.help = [[
+--generate generate file database
+--variables show configuration variables
+--expansions show expanded variables
+--configurations show configuration order
+--expand-braces expand complex variable
+--expand-path expand variable (resolve paths)
+--expand-var expand variable (resolve references)
+--show-path show path expansion of ...
+--var-value report value of variable
+--find-file report file location
+--find-path report path of file
+--make or --ini make luatex format
+--run or --fmt= run luatex format
+--luafile=str lua inifile (default is <progname>.lua)
+--lualibs=list libraries to assemble (optional when --compile)
+--compile assemble and compile lua inifile
+--verbose give a bit more info
+--all show all found files
+--sort sort cached data
+--engine=str target engine
+--progname=str format or backend
+--pattern=str filter variables
+]]
+
+function runners.make_format(texname)
+ local instance = resolvers.instance
+ if texname and texname ~= "" then
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ if path and lfs then
+ lfs.chdir(path)
+ end
+ end
+ local barename = texname:gsub("%.%a+$","")
+ if barename == texname then
+ texname = texname .. ".tex"
+ end
+ local fullname = resolvers.find_files(texname)[1] or ""
+ if fullname == "" then
+ logs.simple("no tex file with name: %s",texname)
+ else
+ local luaname, lucname, luapath, lualibs = "", "", "", { }
+ -- the following is optional, since context.lua can also
+ -- handle this collect and compile business
+ if environment.arguments["compile"] then
+ if luaname == "" then luaname = barename end
+ logs.simple("creating initialization file: %s",luaname)
+ luapath = file.dirname(luaname)
+ if luapath == "" then
+ luapath = file.dirname(texname)
+ end
+ if luapath == "" then
+ luapath = file.dirname(resolvers.find_files(texname)[1] or "")
+ end
+ lualibs = string.split(instance.lualibs,",")
+ luaname = file.basename(barename .. ".lua")
+ lucname = file.basename(barename .. ".luc")
+ -- todo: when this fails, we can just copy the merged libraries from
+ -- luatools since they are normally the same, at least for context
+ if lualibs[1] then
+ local firstlib = file.join(luapath,lualibs[1])
+ if not lfs.isfile(firstlib) then
+ local foundname = resolvers.find_files(lualibs[1])[1]
+ if foundname then
+ logs.simple("located library path: %s",luapath)
+ luapath = file.dirname(foundname)
+ end
+ end
+ end
+ logs.simple("using library path: %s",luapath)
+ logs.simple("using lua libraries: %s",table.join(lualibs," "))
+ utils.merger.selfcreate(lualibs,luapath,luaname)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ if utils.lua.compile(luaname,lucname,false,strip) and io.exists(lucname) then
+ luaname = lucname
+ logs.simple("using compiled initialization file: %s",lucname)
+ else
+ logs.simple("using uncompiled initialization file: %s",luaname)
+ end
+ else
+ for _, v in pairs({instance.luaname, instance.progname, barename}) do
+ v = string.gsub(v..".lua","%.lua%.lua$",".lua")
+ if v and (v ~= "") then
+ luaname = resolvers.find_files(v)[1] or ""
+ if luaname ~= "" then
+ break
+ end
+ end
+ end
+ end
+ if environment.arguments["noluc"] then
+ luaname = luaname:gsub("%.luc$",".lua") -- make this an option
+ end
+ if luaname == "" then
+ if logs.verbose then
+ logs.simplelines(messages.no_ini_file)
+ logs.simple("texname : %s",texname)
+ logs.simple("luaname : %s",instance.luaname)
+ logs.simple("progname: %s",instance.progname)
+ logs.simple("barename: %s",barename)
+ end
+ else
+ logs.simple("using lua initialization file: %s",luaname)
+ local mp = dir.glob(file.removesuffix(file.basename(luaname)).."-*.mem")
+ if mp and #mp > 0 then
+ for _, name in ipairs(mp) do
+ logs.simple("removing related mplib format %s", file.basename(name))
+ os.remove(name)
+ end
+ end
+ local flags = {
+ "--ini",
+ "--lua=" .. string.quote(luaname)
+ }
+ local bs = (os.platform == "unix" and "\\\\") or "\\" -- todo: make a function
+ local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " " .. bs .. "dump"
+ logs.simple("running command: %s\n",command)
+ os.spawn(command)
+ -- todo: do a dummy run that generates the related metafun and mfplain formats
+ end
+ end
+ else
+ logs.simple("no tex file given")
+ end
+end
+
+function runners.run_format(name,data,more)
+ -- hm, rather old code here; we can now use the file.whatever functions
+ if name and (name ~= "") then
+ local barename = name:gsub("%.%a+$","")
+ local fmtname = ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ barename = fmtname:gsub("%.%a+$","")
+ if fmtname == "" then
+ logs.simple("no format with name: %s",name)
+ else
+ local luaname = barename .. ".luc"
+ local f = io.open(luaname)
+ if not f then
+ luaname = barename .. ".lua"
+ f = io.open(luaname)
+ end
+ if f then
+ f:close()
+ local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. (more ~= "" and string.quote(more) or "")
+ logs.simple("running command: %s",command)
+ os.spawn(command)
+ else
+ logs.simple("using format name: %s",fmtname)
+ logs.simple("no luc/lua with name: %s",barename)
+ end
+ end
+ end
+end
+
+local ok = true
+
+-- private option --noluc for testing errors in the stub
+
+if environment.arguments["find-file"] then
+ resolvers.load()
+ instance.format = environment.arguments["format"] or instance.format
+ if instance.pattern then
+ instance.allresults = true
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
+ else
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
+ end
+elseif environment.arguments["find-path"] then
+ resolvers.load()
+ local path = resolvers.find_file(environment.files[1], instance.my_format)
+ if logs.verbose then
+ logs.simple(file.dirname(path))
+ else
+ print(file.dirname(path))
+ end
+elseif environment.arguments["run"] then
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
+elseif environment.arguments["fmt"] then
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
+elseif environment.arguments["expand-braces"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_braces, environment.files)
+elseif environment.arguments["expand-path"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_path, environment.files)
+elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_var, environment.files)
+elseif environment.arguments["show-path"] or environment.arguments["path-value"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.show_path, environment.files)
+elseif environment.arguments["var-value"] or environment.arguments["show-value"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.var_value, environment.files)
+elseif environment.arguments["format-path"] then
+ resolvers.load()
+ logs.simple(caches.setpath("format"))
+elseif instance.pattern then -- brrr
+ resolvers.load()
+ instance.format = environment.arguments["format"] or instance.format
+ instance.allresults = true
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
+elseif environment.arguments["generate"] then
+ instance.renewcache = true
+ logs.setverbose(true)
+ resolvers.load()
+elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then
+ resolvers.load()
+ logs.setverbose(true)
+ runners.make_format(environment.files[1] or "")
+elseif environment.arguments["selfmerge"] then
+ utils.merger.selfmerge(own.name,own.libs,own.list)
+elseif environment.arguments["selfclean"] then
+ utils.merger.selfclean(own.name)
+elseif environment.arguments["selfupdate"] then
+ resolvers.load()
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"luatools")
+elseif environment.arguments["variables"] or environment.arguments["show-variables"] then
+ resolvers.load("nofiles")
+ resolvers.listers.variables()
+elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then
+ resolvers.load("nofiles")
+ resolvers.listers.expansions()
+elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then
+ resolvers.load("nofiles")
+ resolvers.listers.configurations()
+elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then
+ logs.help(messages.help)
+else
+ resolvers.load()
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
+end
+
+if logs.verbose then
+ logs.simpleline()
+ logs.simple("runtime: %0.3f seconds",os.runtime())
+end
+
+if os.platform == "unix" then
+ io.write("\n")
+end
diff --git a/scripts/context/stubs/mswin/makempy.bat b/scripts/context/stubs/mswin/makempy.bat
index e339058c6..03eaa8a28 100755
--- a/scripts/context/stubs/mswin/makempy.bat
+++ b/scripts/context/stubs/mswin/makempy.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart makempy.pl %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute makempy.pl %*
+endlocal
diff --git a/scripts/context/stubs/mswin/metatex.cmd b/scripts/context/stubs/mswin/metatex.cmd
new file mode 100644
index 000000000..858f28f8f
--- /dev/null
+++ b/scripts/context/stubs/mswin/metatex.cmd
@@ -0,0 +1,5 @@
+@echo off
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --script metatex %*
+endlocal
diff --git a/scripts/context/stubs/mswin/mpstools.bat b/scripts/context/stubs/mswin/mpstools.bat
index df1732e17..8bd25674c 100755
--- a/scripts/context/stubs/mswin/mpstools.bat
+++ b/scripts/context/stubs/mswin/mpstools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart mpstools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute mpstools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/mptopdf.bat b/scripts/context/stubs/mswin/mptopdf.bat
index 242854337..f29881763 100755
--- a/scripts/context/stubs/mswin/mptopdf.bat
+++ b/scripts/context/stubs/mswin/mptopdf.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart mptopdf.pl %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute mptopdf.pl %*
+endlocal
diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua
new file mode 100644
index 000000000..0af429bf1
--- /dev/null
+++ b/scripts/context/stubs/mswin/mtxrun.lua
@@ -0,0 +1,10190 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['mtxrun'] = {
+ version = 1.001,
+ comment = "runner, lua replacement for texmfstart.rb",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
+-- one can make a stub:
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@"
+
+-- filename : mtxrun.lua
+-- comment : companion to context.tex
+-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license : see context related readme files
+
+-- This script is based on texmfstart.rb but does not use kpsewhich to
+-- locate files. Although kpse is a library it never came to opening up
+-- its interface to other programs (esp scripting languages) and so we
+-- do it ourselves. The lua variant evolved out of an experimental ruby
+-- one. Interesting is that using a scripting language instead of c does
+-- not have a speed penalty. Actually the lua variant is more efficient,
+-- especially when multiple calls to kpsewhich are involved. The lua
+-- library also gives way more control.
+
+-- to be done / considered
+--
+-- support for --exec or make it default
+-- support for jar files (or maybe not, never used, too messy)
+-- support for $RUBYINPUTS cum suis (if still needed)
+-- remember for subruns: _CTX_K_V_#{original}_
+-- remember for subruns: _CTX_K_S_#{original}_
+-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
+
+texlua = true
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+function string:quote() -- we could use format("%q")
+ return '"' .. self:unquote() .. '"'
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+function string:strip()
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
+end
+
+function string:is_empty()
+ return not find(find,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, str:sub(index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. self.rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+local hash = { }
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return P(pattern)
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local newline = crlf + cr + lf
+local spacing = space^0 * newline
+
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return capture:match(self)
+end
+
+lpeg.linebyline = content -- better make a sublibrary
+
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, ipairs = type, next, tostring, ipairs
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+function table.one_entry(t)
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+function table.starts_at(t)
+ return ipairs(t,1)(t,0)
+end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete)
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end })
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ 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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data)
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+number = number or { }
+
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+function number.toevenhex(n)
+ local s = format("%X",n)
+ if #s % 2 == 0 then
+ return s
+ else
+ return "0" .. s
+ end
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+local one = lpeg.C(1-lpeg.S(''))^1
+
+function number.toset(n)
+ return one:match(tostring(n))
+end
+
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+set = set or { }
+
+local nums = { }
+local tabs = { }
+local concat = table.concat
+
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
+ end
+ end
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
+ end
+ return nums[s]
+ else
+ return 0
+ end
+end
+
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
+ end
+end
+
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
+end
+
+--~ local c = set.create{'aap','noot','mies'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ local c = set.create{'zus','wim','jet'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ print(t['jet'])
+--~ print(set.contains(t,'jet'))
+--~ print(set.contains(t,'aap'))
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+function os.resultof(command)
+ return io.popen(command,"r"):read("*all")
+end
+
+if not os.exec then os.exec = os.execute end
+if not os.spawn then os.spawn = os.execute end
+
+--~ os.type : windows | unix (new, we already guessed os.platform)
+--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
+
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
+ else
+ io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
+ end
+end
+
+os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
+
+function os.launch(str)
+ if os.platform == "windows" then
+ os.execute("start " .. str) -- os.spawn ?
+ else
+ os.execute(str .. " &") -- os.spawn ?
+ end
+end
+
+if not os.setenv then
+ function os.setenv() return false end
+end
+
+if not os.times then
+ -- utime = user time
+ -- stime = system time
+ -- cutime = children user time
+ -- cstime = children system time
+ function os.times()
+ return {
+ utime = os.gettimeofday(), -- user
+ stime = 0, -- system
+ cutime = 0, -- children user
+ cstime = 0, -- children system
+ }
+ end
+end
+
+os.gettimeofday = os.gettimeofday or os.clock
+
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
+end
+
+--~ print(os.gettimeofday()-os.time())
+--~ os.sleep(1.234)
+--~ print (">>",os.runtime())
+--~ print(os.date("%H:%M:%S",os.gettimeofday()))
+--~ print(os.date("%H:%M:%S",os.time()))
+
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name)
+ return match(name,"^.+%.([^/\\]-)$") or ""
+end
+
+file.suffix = file.extname
+
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.join(...)
+ local pth = concat({...},"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ return (gsub(pth,"//+","/"))
+end
+
+function file.iswritable(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
+ return a and a.permissions:sub(2,2) == "w"
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and a.permissions:sub(1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+function file.split_path(str)
+ local t = { }
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
+ if name ~= "" then
+ t[#t+1] = gsub(name,"\001",":")
+ end
+ end
+ return t
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+function file.collapse_path(str)
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return pattern:match(name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = pattern:match(name)
+--~ if b then
+--~ return name:sub(a,b-2)
+--~ elseif a then
+--~ return name:sub(a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEX(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local find, gmatch = string.find, string.gmatch
+
+dir = dir or { }
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
+ end
+ end
+ end
+end
+
+dir.glob_pattern = glob_pattern
+
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
+
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
+ local t = t or { }
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
+ return t
+ else
+ return { }
+ end
+ end
+end
+
+dir.glob = glob
+
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
+
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
+ files[#files+1] = path .. "/" .. name
+ end
+ else
+ files[#files+1] = path .. "/" .. name
+ end
+ end
+ end
+ end
+ return files
+end
+
+dir.globfiles = globfiles
+
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
+
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
+
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
+
+local make_indeed = true -- false
+
+if string.find(os.getenv("PATH"),";") then
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
+ if first then
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
+ else
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
+ if first then
+ pth, drive = first .. middle, true
+ else
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
+ end
+ end
+ end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("a:"))
+--~ print(dir.mkdirs("a:/b/c"))
+--~ print(dir.mkdirs("a:b/c"))
+--~ print(dir.mkdirs("a:/bbb/c"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
+ end
+ lfs.chdir(d)
+ end
+ end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
+
+else
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
+ end
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
+ end
+
+end
+
+dir.makedirs = dir.mkdirs
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+function boolean.alwaystrue()
+ return true
+end
+
+function boolean.falsetrue()
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
+
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (data:gsub(utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for _, lib in ipairs(libs) do
+ for _, pth in ipairs(list) do
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return table.concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-tab'] = {
+ 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"
+}
+
+--[[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
+parent access; a first version used different trickery but was less optimized to we
+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>
+--ldx]]--
+
+xml = xml or { }
+
+--~ local xml = xml
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, setmetatable = type, next, setmetatable
+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
+
+--[[ldx--
+<p>First a hack to enable namespace resolving. A namespace is characterized by
+a <l n='url'/>. The following function associates a namespace prefix with a
+pattern. We use <l n='lpeg'/>, which in this case is more than twice as fast as a
+find based solution where we loop over an array of patterns. Less code and
+much cleaner.</p>
+--ldx]]--
+
+xml.xmlns = xml.xmlns or { }
+
+local check = lpeg.P(false)
+local parse = check
+
+--[[ldx--
+<p>The next function associates a namespace prefix with an <l n='url'/>. This
+normally happens independent of parsing.</p>
+
+<typing>
+xml.registerns("mml","mathml")
+</typing>
+--ldx]]--
+
+function xml.registerns(namespace, pattern) -- pattern can be an lpeg
+ check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
+ parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+end
+
+--[[ldx--
+<p>The next function also registers a namespace, but this time we map a
+given namespace prefix onto a registered one, using the given
+<l n='url'/>. This used for attributes like <t>xmlns:m</t>.</p>
+
+<typing>
+xml.checkns("m","http://www.w3.org/mathml")
+</typing>
+--ldx]]--
+
+function xml.checkns(namespace,url)
+ local ns = parse:match(lower(url))
+ if ns and namespace ~= ns then
+ xml.xmlns[namespace] = ns
+ end
+end
+
+--[[ldx--
+<p>Next we provide a way to turn an <l n='url'/> into a registered
+namespace. This used for the <t>xmlns</t> attribute.</p>
+
+<typing>
+resolvedns = xml.resolvens("http://www.w3.org/mathml")
+</typing>
+
+This returns <t>mml</t>.
+--ldx]]--
+
+function xml.resolvens(url)
+ return parse:match(lower(url)) or ""
+end
+
+--[[ldx--
+<p>A namespace in an element can be remapped onto the registered
+one efficiently by using the <t>xml.xmlns</t> table.</p>
+--ldx]]--
+
+--[[ldx--
+<p>This version uses <l n='lpeg'/>. We follow the same approach as before, stack and top and
+such. This version is about twice as fast which is mostly due to the fact that
+we don't have to prepare the stream for cdata, doctype etc etc. This variant is
+is dedicated to Luigi Scarso, who challenged me with 40 megabyte <l n='xml'/> files that
+took 12.5 seconds to load (1.5 for file io and the rest for tree building). With
+the <l n='lpeg'/> implementation we got that down to less 7.3 seconds. Loading the 14
+<l n='context'/> interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.</p>
+
+<p>Next comes the parser. The rather messy doctype definition comes in many
+disguises so it is no surprice that later on have to dedicate quite some
+<l n='lpeg'/> code to it.</p>
+
+<typing>
+<!DOCTYPE Something PUBLIC "... ..." "..." [ ... ] >
+<!DOCTYPE Something PUBLIC "... ..." "..." >
+<!DOCTYPE Something SYSTEM "... ..." [ ... ] >
+<!DOCTYPE Something SYSTEM "... ..." >
+<!DOCTYPE Something [ ... ] >
+<!DOCTYPE Something >
+</typing>
+
+<p>The code may look a bit complex but this is mostly due to the fact that we
+resolve namespaces and attach metatables. There is only one public function:</p>
+
+<typing>
+local x = xml.convert(somestring)
+</typing>
+
+<p>An optional second boolean argument tells this function not to create a root
+element.</p>
+--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 mt = { __tostring = xml.text }
+
+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
+ end
+ if tag == "xmlns" then
+ xmlns[#xmlns+1] = resolvens(value)
+ at[tag] = value
+ elseif namespace == "xmlns" then
+ xml.checkns(tag,value)
+ at["xmlns:" .. tag] = value
+ else
+ at[tag] = value
+ end
+end
+
+local function add_begin(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ setmetatable(top, mt)
+ dt = top.dt
+ stack[#stack+1] = top
+ at = { }
+end
+
+local function add_end(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local toclose = remove(stack)
+ top = stack[#stack]
+ if #stack < 1 then
+ errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
+ elseif toclose.tg ~= tag then -- no namespace check
+ errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
+ end
+ dt = top.dt
+ dt[#dt+1] = toclose
+ dt[0] = top
+ 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)
+ else
+ dt[#dt+1] = text
+ end
+end
+
+local function add_special(what, spacing, text)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ if strip and (what == "@cm@" or what == "@dt@") then
+ -- forget it
+ else
+ dt[#dt+1] = { special=true, ns="", tg=what, dt={text} }
+ end
+end
+
+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 space = S(' \r\n\t')
+local open = P('<')
+local close = P('>')
+local squote = S("'")
+local dquote = S('"')
+local equal = P('=')
+local slash = P('/')
+local colon = P(':')
+local valid = R('az', 'AZ', '09') + S('_-.')
+local name_yes = C(valid^1) * colon * C(valid^1)
+local name_nop = C(P(true)) * C(valid^1)
+local name = name_yes + name_nop
+
+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 somespace = space^1
+local optionalspace = space^0
+
+local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
+local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
+local attributes = attribute^0
+
+local text = justtext / 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
+local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
+local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
+
+local begincomment = open * P("!--")
+local endcomment = P("--") * close
+local begininstruction = open * P("?")
+local endinstruction = P("?") * close
+local begincdata = open * P("![CDATA[")
+local endcdata = P("]]") * close
+
+local someinstruction = C((1 - endinstruction)^0)
+local somecomment = C((1 - endcomment )^0)
+local somecdata = C((1 - endcdata )^0)
+
+local function entity(k,v) entities[k] = v end
+
+local begindoctype = open * P("!DOCTYPE")
+local enddoctype = close
+local beginset = P("[")
+local endset = P("]")
+local doctypename = C((1-somespace)^0)
+local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close
+local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close
+local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace
+local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace
+local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset
+local simpledoctype = (1-close)^1 -- * balanced^0
+local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
+
+local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
+local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end
+local cdata = (spacing * begincdata * somecdata * endcdata ) / function(...) add_special("@cd@",...) end
+local doctype = (spacing * begindoctype * somedoctype * enddoctype ) / function(...) add_special("@dt@",...) end
+
+-- nicer but slower:
+--
+-- local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+-- local comment = (lpeg.Cc("@cm@") * spacing * begincomment * somecomment * endcomment ) / add_special
+-- 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
+
+-- 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",
+ 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,
+}
+
+-- todo: xml.new + properties like entities and strip and such (store in root)
+
+function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear)
+ strip = strip_cm_and_dt or xml.strip_cm_and_dt
+ stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
+ stack[#stack+1] = top
+ top.dt = { }
+ dt = top.dt
+ if not data or data == "" then
+ errorstr = "empty xml file"
+ elseif not grammar:match(data) then
+ errorstr = "invalid xml file"
+ else
+ errorstr = ""
+ end
+ if errorstr and errorstr ~= "" then
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
+ setmetatable(stack, mt)
+ if xml.error_handler then xml.error_handler("load",errorstr) end
+ else
+ result = stack[1]
+ end
+ if not no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
+ setmetatable(result, mt)
+ local rdt = result.dt
+ for k=1,#rdt do
+ local v = rdt[k]
+ if type(v) == "table" and not v.special then -- always table -)
+ result.ri = k -- rootindex
+ break
+ end
+ end
+ end
+ return result
+end
+
+--[[ldx--
+<p>Packaging data in an xml like table is done with the following
+function. Maybe it will go away (when not used).</p>
+--ldx]]--
+
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+end
+
+function xml.package(tag,attributes,data)
+ local ns, tg = tag:match("^(.-):?([^:]+)$")
+ local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
+ setmetatable(t, mt)
+ return t
+end
+
+function xml.is_valid(root)
+ return root and not root.error
+end
+
+xml.error_handler = (logs and logs.report) or (input and logs.report) or print
+
+--[[ldx--
+<p>We cannot load an <l n='lpeg'/> from a filehandle so we need to load
+the whole file first. The function accepts a string representing
+a filename or a file handle.</p>
+--ldx]]--
+
+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"))
+ f:close()
+ return root
+ else
+ return xml.convert("")
+ end
+ elseif filename then -- filehandle
+ return xml.convert(filename:read("*all"))
+ else
+ return xml.convert("")
+ end
+end
+
+--[[ldx--
+<p>When we inject new elements, we need to convert strings to
+valid trees, which is what the next function does.</p>
+--ldx]]--
+
+function xml.toxml(data)
+ if type(data) == "string" then
+ local root = { xml.convert(data,true) }
+ return (#root > 1 and root) or root[1]
+ else
+ return data
+ end
+end
+
+--[[ldx--
+<p>For copying a tree we use a dedicated function instead of the
+generic table copier. Since we know what we're dealing with we
+can speed up things a bit. The second argument is not to be used!</p>
+--ldx]]--
+
+function copy(old,tables)
+ if old then
+ tables = tables or { }
+ local new = { }
+ if not tables[old] then
+ tables[old] = new
+ end
+ for k,v in pairs(old) do
+ new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+xml.copy = copy
+
+--[[ldx--
+<p>In <l n='context'/> serializing the tree or parts of the tree is a major
+actitivity which is why the following function is pretty optimized resulting
+in a few more lines of code than needed. The variant that uses the formatting
+function for all components is about 15% slower than the concatinating
+alternative.</p>
+--ldx]]--
+
+-- todo: add <?xml version='1.0' standalone='yes'?> when not present
+
+local fallbackhandle = (tex and tex.sprint) or io.write
+
+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
+ local xc = xml.command
+ if xc then
+ xc(e,ec)
+ return
+ end
+ 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)
+ else
+ -- no need to handle any further
+ 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
+ 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
+ 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(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 .. ">")
+ 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
+ end
+ 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
+ end
+ end
+ elseif type(e) == "string" then
+ if textconverter then
+ handle(textconverter(e))
+ else
+ handle(e)
+ 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
+end
+
+xml.serialize = serialize
+
+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
+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]]--
+
+function xml.tostring(root) -- 25% overhead due to collecting
+ if root then
+ if type(root) == 'string' then
+ return root
+ elseif next(root) then -- next is faster than type (and >0 test)
+ local result = { }
+ serialize(root,function(s) result[#result+1] = s end)
+ return concat(result,"")
+ end
+ end
+ return ""
+end
+
+--[[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)
+ 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)
+ end
+ end
+ else
+ handle(e)
+ 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
+
+--[[ldx--
+<p>A few helpers:</p>
+--ldx]]--
+
+function xml.body(root)
+ return (root.ri and root.dt[root.ri]) or root
+end
+
+function xml.text(root)
+ return (root and xml.tostring(root)) or ""
+end
+
+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 ""
+ end
+end
+
+--[[ldx--
+<p>The next helper assigns a tree (or string). Usage:</p>
+
+<typing>
+dt[k] = xml.assign(root) or xml.assign(dt,k,root)
+</typing>
+--ldx]]--
+
+function xml.assign(dt,k,root)
+ if dt and k then
+ dt[k] = (type(root) == "table" and xml.body(root)) or root
+ return dt[k]
+ else
+ return xml.body(root)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+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 = string.format, string.lower, string.gmatch, string.gsub, 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. Here we overload a previously defined
+function.</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
+
+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",
+ [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
+
+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_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)*")"}
+
+-- if we use a dedicated namespace then we don't need to pass rt and k
+
+local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
+ if expressions[t] then
+ if s then
+ return "expressions." .. t .. "(r,k," .. s ..")"
+ else
+ return "expressions." .. t .. "(r,k)"
+ end
+ else
+ return "expressions.error(" .. t .. ")"
+ end
+end
+
+local converter = lpeg.Cs ( (
+ lp_position +
+ lp_index +
+ lp_text + lp_name + -- fast one
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_attribute +
+ lp_lua_function +
+ lp_function +
+1 )^1 )
+
+-- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
+
+local template = [[
+ 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)
+ str = converter:match(str)
+ return str, loadstring(format(template,str))()
+end
+
+local map = { }
+
+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 is_eq = lbracket * atsign * name * eq * value * rbracket
+local is_ne = lbracket * atsign * name * ne * value * rbracket
+local is_attribute = lbracket * atsign * name * rbracket
+local is_value = lbracket * value * rbracket
+local is_number = lbracket * number * rbracket
+
+local nobracket = 1-(lbracket+rbracket) -- must be improved
+local is_expression = lbracket * C(((C(nobracket^1))/make_expression)) * rbracket
+
+local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
+
+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 = (period )
+local parent = (period * period ) / function( ) map[#map+1] = { 11 } end
+local subtreeroot = (slash + hat ) / function( ) map[#map+1] = { 12 } end
+local documentroot = (hat * hat ) / function( ) map[#map+1] = { 13 } end
+local any = (star ) / function( ) map[#map+1] = { 14 } end
+local many = (star * star ) / function( ) map[#map+1] = { 15 } end
+local initial = (hat * hat * hat ) / function( ) map[#map+1] = { 16 } end
+
+local match = (is_one ) / function(...) map[#map+1] = { 20, true , ... } end
+local match_one_of = (is_one_of ) / function(...) map[#map+1] = { 21, true , ... } end
+local dont_match = (is_none ) / function(...) map[#map+1] = { 20, false, ... } end
+local dont_match_one_of = (is_none_of ) / function(...) map[#map+1] = { 21, false, ... } end
+
+local match_and_eq = (is_one * is_eq ) / function(...) map[#map+1] = { 22, true , ... } end
+local match_and_ne = (is_one * is_ne ) / function(...) map[#map+1] = { 23, true , ... } end
+local dont_match_and_eq = (is_none * is_eq ) / function(...) map[#map+1] = { 22, false, ... } end
+local dont_match_and_ne = (is_none * is_ne ) / function(...) map[#map+1] = { 23, false, ... } end
+
+local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) map[#map+1] = { 24, true , ... } end
+local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) map[#map+1] = { 25, true , ... } end
+local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) map[#map+1] = { 24, false, ... } end
+local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) map[#map+1] = { 25, false, ... } end
+
+local has_attribute = (is_one * is_attribute) / function(...) map[#map+1] = { 27, true , ... } end
+local has_value = (is_one * is_value ) / function(...) map[#map+1] = { 28, true , ... } end
+local dont_has_attribute = (is_none * is_attribute) / function(...) map[#map+1] = { 27, false, ... } end
+local dont_has_value = (is_none * is_value ) / function(...) map[#map+1] = { 28, false, ... } end
+local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
+local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
+
+local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
+local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
+
+local self_expression = ( is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, true, "*", "*", ... } end
+local dont_self_expression = (exclam * is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, false, "*", "*", ... } end
+
+local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
+local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
+local crap = (1-slash)^1
+
+-- a few ugly goodies:
+
+local docroottag = P('^^') / function( ) map[#map+1] = { 12 } end
+local subroottag = P('^') / function( ) map[#map+1] = { 13 } end
+local roottag = P('root::') / function( ) map[#map+1] = { 12 } end
+local parenttag = P('parent::') / function( ) map[#map+1] = { 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 +
+ 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 +
+ has_attribute + has_value +
+ dont_match_one_of + match_one_of +
+ dont_match + match +
+ many + any +
+ crap + empty
+)
+
+local grammar = P { "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
+ map = { }
+ grammar:match(str)
+ if #map == 0 then
+ return true
+ else
+ 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
+ -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
+ map[2][1] = 29
+ return { map[2] }
+ end
+ if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
+ insert(map, 1, { 16 })
+ end
+ -- print(gsub(table.serialize(map),"[ \n]+"," "))
+ return map
+ end
+ end
+end
+
+local cache = { }
+
+function xml.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
+
+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 = xml.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(root,rootdt,k) then
+ return false
+ 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(root,rootdt,k) then
+ return false
+ 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 = 0
+ local hsh = { } -- this 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 == 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[5]]
+ elseif command == 28 then -- has value
+ 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
+ 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(root,rootdt,k) then
+ return false
+ end
+ break -- else loop
+ end
+ end
+ end
+ end
+ end
+ end
+ return true
+end
+
+xml.traverse = traverse
+
+--[[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]]--
+
+local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
+
+xml.filters = { }
+
+function xml.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 xml.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
+
+function xml.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 xml.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
+
+function xml.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 xml.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 xml.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 xml.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 xml.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 xml.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 ekat[gsub(arguments,"^([\"\'])(.*)%1$","%2")])) or ""
+end
+
+function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
+ local dtk, rt, dt, dk = xml.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 xml.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 xml.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] = ""
+ end
+ else
+ t[#t+1] = tx or ""
+ end
+ else
+ t[#t+1] = ""
+ end
+ end)
+ return t
+end
+
+function xml.collect_tags(root, pattern, nonamespace)
+ local t = { }
+ xml.traverse(root, xml.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
+
+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
+ local xi = xml.convert(data)
+ 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"..string.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")
+
+--~ 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)"))
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-ent'] = {
+ 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 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
+
+--[[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>
+--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)
+ local documententities = root.entities
+ local allentities = xml.entities
+ if documententities then
+ for k, v in next, documententities do
+ allentities[k] = v
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-mis'] = {
+ 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 = table.concat
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, gsub = string.format, string.gsub
+
+--[[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"..string.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)
+
+xml.escaped_pattern = escaped
+xml.unescaped_pattern = unescaped
+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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
+ end
+ end
+ grandtotal = grandtotal + count
+ functions = functions + 1
+ end
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+end
+
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
+ end
+end
+
+function debugger.enable()
+ debug.sethook(hook,"c")
+end
+
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
+end
+
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
+ end
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
+
+-- dirty tricks
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
+
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index, argument in pairs(arg) do
+ if index > 0 then
+ local flag, value = argument:match("^%-+(.+)=(.-)$")
+ if flag then
+ arguments[flag] = string.unquote(value or "")
+ else
+ flag = argument:match("^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = { }
+ for _,v in pairs(table.sortedkeys(arguments)) do
+ sortedflags[#sortedflags+1] = "^" .. v
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for _,v in ipairs(sortedflags) do
+ if name:find(v) then
+ return arguments[v:sub(2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ for _,v in ipairs(environment.original_arguments) do
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ return a
+ elseif next(arg) then
+ local result = { }
+ for _,a in ipairs(arg) do -- ipairs 1 .. #n
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ a = a:gsub('"','\\"') -- tricky
+ if a:find(" ") then
+ result[#result+1] = a:quote()
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index, argument in ipairs(arg) do
+ if argument:find("^\"") then
+ newarg[#newarg+1] = argument:gsub("^\"","")
+ if not argument:find("\"$") then
+ instring = true
+ end
+ elseif argument:find("\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "companion to luat-lib.tex",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ instance.variables[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
+
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
+ else
+ local binary = resolvers.ownbin
+ if os.platform == "windows" then
+ binary = file.replacesuffix(binary,"exe")
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
+ end
+ resolvers.ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
+ end
+ resolvers.ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
+ end
+ return resolvers.ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ local f = io.open(lname)
+ if f then -- this will go
+ f:close()
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
+ for k,v in pairs(c) do
+ if type(v) == 'string' then
+ local t = file.split_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return file.split_path(str)
+ end
+end
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h = { }, { }
+ for _,vv in ipairs(file.split_path(v)) do
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ for _, cnf in ipairs(instance.cnffiles) do
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(str)
+ else
+ return resolvers.expanded_path_list(tmp)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","+ readable: %s",name)
+ else
+ logs.report("fileio","- readable: %s", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local doscan, recurse
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist and not (done and not instance.allresults) and recurse then
+ -- compare list entries with permitted pattern
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
+ local expr = "^" .. pathname
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
+ end
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag]
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_verbose then
+ report('')
+ end
+ for _, file in ipairs(files) do
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for _,v in ipairs(result) do
+ report(v)
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in pairs(t) do -- pairs?
+ s[#s+1] = k .. "=" .. v
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ for _, hash in ipairs(instance.hashes) do
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in pairs(v) do -- ipairs?
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.</p>
+
+</code>
+TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
+</code>
+
+<p>Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.</p>
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ return loader()
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-res'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
+
+local upper, lower, gsub = string.upper, string.lower, string.gsub
+
+local prefixes = { }
+
+prefixes.environment = function(str)
+ return resolvers.clean_path(os.getenv(str) or os.getenv(upper(str)) or os.getenv(lower(str)) or "")
+end
+
+prefixes.relative = function(str,n)
+ if io.exists(str) then
+ -- nothing
+ elseif io.exists("./" .. str) then
+ str = "./" .. str
+ else
+ local p = "../"
+ for i=1,n or 2 do
+ if io.exists(p .. str) then
+ str = p .. str
+ break
+ else
+ p = p .. "../"
+ end
+ end
+ end
+ return resolvers.clean_path(str)
+end
+
+prefixes.locate = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path((fullname ~= "" and fullname) or str)
+end
+
+prefixes.filename = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.basename((fullname ~= "" and fullname) or str))
+end
+
+prefixes.pathname = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.dirname((fullname ~= "" and fullname) or str))
+end
+
+prefixes.env = prefixes.environment
+prefixes.rel = prefixes.relative
+prefixes.loc = prefixes.locate
+prefixes.kpse = prefixes.locate
+prefixes.full = prefixes.locate
+prefixes.file = prefixes.filename
+prefixes.path = prefixes.pathname
+
+local function _resolve_(method,target)
+ if prefixes[method] then
+ return prefixes[method](target)
+ else
+ return method .. ":" .. target
+ end
+end
+
+local function resolve(str)
+ if type(str) == "table" then
+ for k, v in pairs(str) do -- ipairs
+ str[k] = resolve(v) or v
+ end
+ elseif str and str ~= "" then
+ str = gsub(str,"([a-z]+):([^ \"\']*)",_resolve_)
+ end
+ return str
+end
+
+resolvers.resolve = resolve
+
+if os.uname then
+
+ for k, v in pairs(os.uname()) do
+ if not prefixes[k] then
+ prefixes[k] = function() return v end
+ end
+ end
+
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if table.is_empty(mountpaths) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if not table.is_empty(mountpaths) then
+ statistics.starttiming(resolvers.instance)
+ for k, root in pairs(mountpaths) do
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if line:find("^[%%#%-]") then -- or %W
+ -- skip
+ elseif line:find("^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-zip'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, find = string.format, string.find
+
+local trace_locating, trace_verbose = false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trace_verbose = v end)
+
+zip = zip or { }
+zip.archives = zip.archives or { }
+zip.registeredfiles = zip.registeredfiles or { }
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators
+
+local archives = zip.archives
+
+-- zip:///oeps.zip?name=bla/bla.tex
+-- zip:///oeps.zip?tree=tex/texmf-local
+
+local function validzip(str) -- todo: use url splitter
+ if not find(str,"^zip://") then
+ return "zip:///" .. str
+ else
+ return str
+ end
+end
+
+function zip.openarchive(name)
+ if not name or name == "" then
+ return nil
+ else
+ local arch = archives[name]
+ if not arch then
+ local full = resolvers.find_file(name) or ""
+ arch = (full ~= "" and zip.open(full)) or false
+ archives[name] = arch
+ end
+ return arch
+ end
+end
+
+function zip.closearchive(name)
+ if not name or (name == "" and archives[name]) then
+ zip.close(archives[name])
+ archives[name] = nil
+ end
+end
+
+-- zip:///texmf.zip?tree=/tex/texmf
+-- zip:///texmf.zip?tree=/tex/texmf-local
+-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
+
+function locators.zip(specification) -- where is this used? startup zips (untested)
+ specification = resolvers.splitmethod(specification)
+ local zipfile = specification.path
+ local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+ if trace_locating then
+ if zfile then
+ logs.report("fileio",'! zip locator, found: %s',specification.original)
+ else
+ logs.report("fileio",'? zip locator, not found: %s',specification.original)
+ end
+ end
+end
+
+function hashers.zip(tag,name)
+ if trace_verbose then
+ logs.report("fileio","loading zip file %s as %s",name,tag)
+ end
+ resolvers.usezipfile(format("%s?tree=%s",tag,name))
+end
+
+function concatinators.zip(tag,path,name)
+ if not path or path == "" then
+ return format('%s?name=%s',tag,name)
+ else
+ return format('%s?name=%s/%s',tag,path,name)
+ end
+end
+
+function resolvers.isreadable.zip(name)
+ return true
+end
+
+function finders.zip(specification,filetype)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'! zip finder, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ dfile = zfile:close()
+ if trace_locating then
+ logs.report("fileio",'+ zip finder, name: %s',q.name)
+ end
+ return specification.original
+ end
+ elseif trace_locating then
+ logs.report("fileio",'? zip finder, path %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip finder, name: %s',filename)
+ end
+ return unpack(finders.notfound)
+end
+
+function openers.zip(specification)
+ local zipspecification = resolvers.splitmethod(specification)
+ if zipspecification.path then
+ local q = url.query(zipspecification.query)
+ if q.name then
+ local zfile = zip.openarchive(zipspecification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',zipspecification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_open(specification)
+ return openers.text_opener(specification,dfile,'zip')
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path %s',zipspecification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip opener, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.zip(specification)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio",'+ zip loader, name: %s',filename)
+ end
+ local s = dfile:read("*all")
+ dfile:close()
+ return true, s, #s
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path: %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip loader, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+-- zip:///somefile.zip
+-- zip:///somefile.zip?tree=texmf-local -> mount
+
+function resolvers.usezipfile(zipname)
+ zipname = validzip(zipname)
+ if trace_locating then
+ logs.report("fileio",'! zip use, file: %s',zipname)
+ end
+ local specification = resolvers.splitmethod(zipname)
+ local zipfile = specification.path
+ if zipfile and not zip.registeredfiles[zipname] then
+ local tree = url.query(specification.query).tree or ""
+ if trace_locating then
+ logs.report("fileio",'! zip register, file: %s',zipname)
+ end
+ local z = zip.openarchive(zipfile)
+ if z then
+ local instance = resolvers.instance
+ if trace_locating then
+ logs.report("fileio","= zipfile, registering: %s",zipname)
+ end
+ statistics.starttiming(instance)
+ resolvers.prepend_hash('zip',zipname,zipfile)
+ resolvers.extend_texmf_var(zipname) -- resets hashes too
+ zip.registeredfiles[zipname] = z
+ instance.files[zipname] = resolvers.register_zip_file(z,tree or "")
+ statistics.stoptiming(instance)
+ elseif trace_locating then
+ logs.report("fileio","? zipfile, unknown: %s",zipname)
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! zip register, no file: %s',zipname)
+ end
+end
+
+function resolvers.register_zip_file(z,tree)
+ local files, filter = { }, ""
+ if tree == "" then
+ filter = "^(.+)/(.-)$"
+ else
+ filter = format("^%s/(.+)/(.-)$",tree)
+ end
+ if trace_locating then
+ logs.report("fileio",'= zip filter: %s',filter)
+ end
+ local register, n = resolvers.register_file, 0
+ for i in z:files() do
+ local path, name = i.filename:match(filter)
+ if path then
+ if name and name ~= '' then
+ register(files, name, path)
+ n = n + 1
+ else
+ -- directory
+ end
+ else
+ register(files, i.filename, '')
+ n = n + 1
+ end
+ end
+ logs.report("fileio",'= zip entries: %s',n)
+ return files
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-crl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+curl = curl or { }
+
+curl.cached = { }
+curl.cachepath = caches.definepath("curl")
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function curl.fetch(protocol, name)
+ local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-")
+-- cachename = cachename:gsub("[\\/]", io.fileseparator)
+ cachename = cachename:gsub("[\\]", "/") -- cleanup
+ if not curl.cached[name] then
+ if not io.exists(cachename) then
+ curl.cached[name] = cachename
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+ end
+ if io.exists(cachename) then
+ curl.cached[name] = cachename
+ else
+ curl.cached[name] = ""
+ end
+ end
+ return curl.cached[name]
+end
+
+function finders.curl(protocol,filename)
+ local foundname = curl.fetch(protocol, filename)
+ return finders.generic(protocol,foundname,filetype)
+end
+
+function openers.curl(protocol,filename)
+ return openers.generic(protocol,filename)
+end
+
+function loaders.curl(protocol,filename)
+ return loaders.generic(protocol,filename)
+end
+
+-- todo: metamethod
+
+function curl.install(protocol)
+ finders[protocol] = function (filename,filetype) return finders.curl(protocol,filename) end
+ openers[protocol] = function (filename) return openers.curl(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.curl(protocol,filename) end
+end
+
+curl.install('http')
+curl.install('https')
+curl.install('ftp')
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- loads *.tmf files in minimal tree roots (to be optimized and documented)
+
+function resolvers.check_environment(tree)
+ logs.simpleline()
+ os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
+ os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+ os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
+ os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
+ logs.simpleline()
+ logs.simple("preset : TEXPATH => %s", os.getenv('TEXPATH'))
+ logs.simple("preset : TEXOS => %s", os.getenv('TEXOS'))
+ logs.simple("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
+ logs.simple("preset : TMP => %s", os.getenv('TMP'))
+ logs.simple('')
+end
+
+function resolvers.load_environment(name) -- todo: key=value as well as lua
+ local f = io.open(name)
+ if f then
+ for line in f:lines() do
+ if line:find("^[%%%#]") then
+ -- skip comment
+ else
+ local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ os.setenv(key,value)
+ elseif how == "?" or how == "??" then
+ os.setenv(key,os.getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if os.getenv(key) then
+ os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
+ else
+ os.setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if os.getenv(key) then
+ os.setenv(key,value .. io.pathseparator .. os.getenv(key))
+ else
+ os.setenv(key,value)
+ end
+ end
+ end
+ end
+ end
+ f:close()
+ end
+end
+
+function resolvers.load_tree(tree)
+ if tree and tree ~= "" then
+ local setuptex = 'setuptex.tmf'
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
+ setuptex = tree .. "/" .. setuptex
+ else
+ setuptex = tree
+ end
+ if io.exists(setuptex) then
+ resolvers.check_environment(tree)
+ resolvers.load_environment(setuptex)
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-sta'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code is used in the updater
+
+states = states or { }
+states.data = states.data or { }
+states.hash = states.hash or { }
+states.tag = states.tag or ""
+states.filename = states.filename or ""
+
+function states.save(filename,tag)
+ tag = tag or states.tag
+ filename = file.addsuffix(filename or states.filename,'lus')
+ io.savedata(filename,
+ "-- generator : luat-sta.lua\n" ..
+ "-- state tag : " .. tag .. "\n\n" ..
+ table.serialize(states.data[tag or states.tag] or {},true)
+ )
+end
+
+function states.load(filename,tag)
+ states.filename = filename
+ states.tag = tag or "whatever"
+ states.filename = file.addsuffix(states.filename,'lus')
+ states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }
+end
+
+function states.set_by_tag(tag,key,value,default,persistent)
+ local d, h = states.data[tag], states.hash[tag]
+ if d then
+ if type(d) == "table" then
+ local dkey, hkey = key, key
+ local pre, post = key:match("(.+)%.([^%.]+)$")
+ if pre and post then
+ for k in pre:gmatch("[^%.]+") do
+ local dk = d[k]
+ if not dk then
+ dk = { }
+ d[k] = dk
+ end
+ d = dk
+ end
+ dkey, hkey = post, key
+ end
+ if type(value) == nil then
+ value = value or default
+ elseif persistent then
+ value = value or d[dkey] or default
+ else
+ value = value or default
+ end
+ d[dkey], h[hkey] = value, value
+ elseif type(d) == "string" then
+ -- weird
+ states.data[tag], states.hash[tag] = value, value
+ end
+ end
+end
+
+function states.get_by_tag(tag,key,default)
+ local h = states.hash[tag]
+ if h and h[key] then
+ return h[key]
+ else
+ local d = states.data[tag]
+ if d then
+ for k in key:gmatch("[^%.]+") do
+ local dk = d[k]
+ if dk then
+ d = dk
+ else
+ return default
+ end
+ end
+ return d or default
+ end
+ end
+end
+
+function states.set(key,value,default,persistent)
+ states.set_by_tag(states.tag,key,value,default,persistent)
+end
+
+function states.get(key,default)
+ return states.get_by_tag(states.tag,key,default)
+end
+
+--~ states.data.update = {
+--~ ["version"] = {
+--~ ["major"] = 0,
+--~ ["minor"] = 1,
+--~ },
+--~ ["rsync"] = {
+--~ ["server"] = "contextgarden.net",
+--~ ["module"] = "minimals",
+--~ ["repository"] = "current",
+--~ ["flags"] = "-rpztlv --stats",
+--~ },
+--~ ["tasks"] = {
+--~ ["update"] = true,
+--~ ["make"] = true,
+--~ ["delete"] = false,
+--~ },
+--~ ["platform"] = {
+--~ ["host"] = true,
+--~ ["other"] = {
+--~ ["mswin"] = false,
+--~ ["linux"] = false,
+--~ ["linux-64"] = false,
+--~ ["osx-intel"] = false,
+--~ ["osx-ppc"] = false,
+--~ ["sun"] = false,
+--~ },
+--~ },
+--~ ["context"] = {
+--~ ["available"] = {"current", "beta", "alpha", "experimental"},
+--~ ["selected"] = "current",
+--~ },
+--~ ["formats"] = {
+--~ ["cont-en"] = true,
+--~ ["cont-nl"] = true,
+--~ ["cont-de"] = false,
+--~ ["cont-cz"] = false,
+--~ ["cont-fr"] = false,
+--~ ["cont-ro"] = false,
+--~ },
+--~ ["engine"] = {
+--~ ["pdftex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["pdftex"] = true,
+--~ },
+--~ },
+--~ ["luatex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ },
+--~ },
+--~ ["xetex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["xetex"] = false,
+--~ },
+--~ },
+--~ ["metapost"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["mpost"] = true,
+--~ ["metafun"] = true,
+--~ },
+--~ },
+--~ },
+--~ ["fonts"] = {
+--~ },
+--~ ["doc"] = {
+--~ },
+--~ ["modules"] = {
+--~ ["f-urwgaramond"] = false,
+--~ ["f-urwgothic"] = false,
+--~ ["t-bnf"] = false,
+--~ ["t-chromato"] = false,
+--~ ["t-cmscbf"] = false,
+--~ ["t-cmttbf"] = false,
+--~ ["t-construction-plan"] = false,
+--~ ["t-degrade"] = false,
+--~ ["t-french"] = false,
+--~ ["t-lettrine"] = false,
+--~ ["t-lilypond"] = false,
+--~ ["t-mathsets"] = false,
+--~ ["t-tikz"] = false,
+--~ ["t-typearea"] = false,
+--~ ["t-vim"] = false,
+--~ },
+--~ }
+
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.set_by_tag("update","rsync.server","oeps")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+
+
+end -- of closure
+-- end library merge
+
+own = { } -- not local
+
+own.libs = { -- todo: check which ones are really needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-io.lua',
+ 'l-number.lua',
+ 'l-set.lua',
+ 'l-os.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-dir.lua',
+ 'l-boolean.lua',
+ 'l-math.lua',
+-- 'l-unicode.lua',
+-- 'l-tex.lua',
+ 'l-utils.lua',
+-- 'l-xml.lua',
+ 'lxml-tab.lua',
+ 'lxml-pth.lua',
+ 'lxml-ent.lua',
+ 'lxml-mis.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+ 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+ 'data-zip.lua',
+ 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-tmf.lua', -- tree files
+ -- needed ?
+ 'luat-sta.lua', -- states
+}
+
+-- We need this hack till luatex is fixed.
+--
+-- for k,v in pairs(arg) do print(k,v) end
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+-- End of hack.
+
+own.name = (environment and environment.ownname) or arg[0] or 'luatools.lua'
+
+own.path = string.match(own.name,"^(.+)[\\/].-$") or "."
+own.list = { '.' }
+if own.path ~= '.' then
+ table.insert(own.list,own.path)
+end
+table.insert(own.list,own.path.."/../../../tex/context/base")
+table.insert(own.list,own.path.."/mtx")
+table.insert(own.list,own.path.."/../sources")
+
+local function locate_libs()
+ for _, lib in pairs(own.libs) do
+ for _, pth in pairs(own.list) do
+ local filename = string.gsub(pth .. "/" .. lib,"\\","/")
+ local codeblob = loadfile(filename)
+ if codeblob then
+ codeblob()
+ own.list = { pth } -- speed up te search
+ break
+ end
+ end
+ end
+end
+
+if not resolvers then
+ locate_libs()
+end
+
+if not resolvers then
+ print("")
+ print("Mtxrun is unable to start up due to lack of libraries. You may")
+ print("try to run 'lua mtxrun.lua --selfmerge' in the path where this")
+ print("script is located (normally under ..../scripts/context/lua) which")
+ print("will make this script library independent.")
+ os.exit()
+end
+
+logs.setprogram('MTXrun',"TDS Runner Tool 1.22",environment.arguments["verbose"] or false)
+
+local instance = resolvers.reset()
+
+runners = runners or { } -- global
+messages = messages or { }
+
+messages.help = [[
+--script run an mtx script (--noquotes)
+--execute run a script or program (--noquotes)
+--resolve resolve prefixed arguments
+--ctxlua run internally (using preloaded libs)
+--locate locate given filename
+
+--autotree use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree'
+--tree=pathtotree use given texmf tree (default file: 'setuptex.tmf')
+--environment=name use given (tmf) environment file
+--path=runpath go to given path before execution
+--ifchanged=filename only execute when given file has changed (md checksum)
+--iftouched=old,new only execute when given file has changed (time stamp)
+
+--make create stubs for (context related) scripts
+--remove remove stubs (context related) scripts
+--stubpath=binpath paths where stubs wil be written
+--windows create windows (mswin) stubs
+--unix create unix (linux) stubs
+
+--verbose give a bit more info
+--engine=str target engine
+--progname=str format or backend
+
+--edit launch editor with found file
+--launch (--all) launch files like manuals, assumes os support
+
+--intern run script using built in libraries
+
+--usekpse use kpse as fallback (when no mkiv and cache installed, often slower)
+--forcekpse force using kpse (handy when no mkiv and cache installed but less functionality)
+]]
+
+runners.applications = {
+ ["lua"] = "luatex --luaonly",
+ ["luc"] = "luatex --luaonly",
+ ["pl"] = "perl",
+ ["py"] = "python",
+ ["rb"] = "ruby",
+}
+
+runners.suffixes = {
+ 'rb', 'lua', 'py', 'pl'
+}
+
+runners.registered = {
+ texexec = { 'texexec.rb', true }, -- context mkii runner (only tool not to be luafied)
+ texutil = { 'texutil.rb', true }, -- old perl based index sorter for mkii (old versions need it)
+ texfont = { 'texfont.pl', true }, -- perl script that makes mkii font metric files
+ texfind = { 'texfind.pl', false }, -- perltk based tex searching tool, mostly used at pragma
+ texshow = { 'texshow.pl', false }, -- perltk based context help system, will be luafied
+ -- texwork = { \texwork.pl', false }, -- perltk based editing environment, only used at pragma
+
+ makempy = { 'makempy.pl', true },
+ mptopdf = { 'mptopdf.pl', true },
+ pstopdf = { 'pstopdf.rb', true }, -- converts ps (and some more) images, does some cleaning (replaced)
+
+-- examplex = { 'examplex.rb', false },
+ concheck = { 'concheck.rb', false },
+
+ runtools = { 'runtools.rb', true },
+ textools = { 'textools.rb', true },
+ tmftools = { 'tmftools.rb', true },
+ ctxtools = { 'ctxtools.rb', true },
+ rlxtools = { 'rlxtools.rb', true },
+ pdftools = { 'pdftools.rb', true },
+ mpstools = { 'mpstools.rb', true },
+-- exatools = { 'exatools.rb', true },
+ xmltools = { 'xmltools.rb', true },
+-- luatools = { 'luatools.lua', true },
+ mtxtools = { 'mtxtools.rb', true },
+
+ pdftrimwhite = { 'pdftrimwhite.pl', false }
+}
+
+runners.launchers = {
+ windows = { },
+ unix = { }
+}
+
+function runners.prepare()
+ local checkname = environment.argument("ifchanged")
+ if checkname and checkname ~= "" then
+ local oldchecksum = file.loadchecksum(checkname)
+ local newchecksum = file.checksum(checkname)
+ if oldchecksum == newchecksum then
+ logs.simple("file '%s' is unchanged",checkname)
+ return "skip"
+ else
+ logs.simple("file '%s' is changed, processing started",checkname)
+ end
+ file.savechecksum(checkname)
+ end
+ local oldname, newname = string.split(environment.argument("iftouched") or "", ",")
+ if oldname and newname and oldname ~= "" and newname ~= "" then
+ if not file.needs_updating(oldname,newname) then
+ logs.simple("file '%s' and '%s' have same age",oldname,newname)
+ return "skip"
+ else
+ logs.simple("file '%s' is older than '%s'",oldname,newname)
+ end
+ end
+ local tree = environment.argument('tree') or ""
+ if environment.argument('autotree') then
+ tree = os.getenv('TEXMFSTART_TREE') or os.getenv('TEXMFSTARTTREE') or tree
+ end
+ if tree and tree ~= "" then
+ resolvers.load_tree(tree)
+ end
+ local env = environment.argument('environment') or ""
+ if env and env ~= "" then
+ for _,e in pairs(string.split(env)) do
+ -- maybe force suffix when not given
+ resolvers.load_tree(e)
+ end
+ end
+ local runpath = environment.argument("path")
+ if runpath and not lfs.chdir(runpath) then
+ logs.simple("unable to change to path '%s'",runpath)
+ return "error"
+ end
+ return "run"
+end
+
+function runners.execute_script(fullname,internal)
+ local noquote = environment.argument("noquotes")
+ if fullname and fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ instance.progname = environment.argument("progname") or instance.progname
+ instance.format = environment.argument("format") or instance.format
+ local path, name, suffix, result = file.dirname(fullname), file.basename(fullname), file.extname(fullname), ""
+ if path ~= "" then
+ result = fullname
+ elseif name then
+ name = name:gsub("^int[%a]*:",function()
+ internal = true
+ return ""
+ end )
+ name = name:gsub("^script:","")
+ if suffix == "" and runners.registered[name] and runners.registered[name][1] then
+ name = runners.registered[name][1]
+ suffix = file.extname(name)
+ end
+ if suffix == "" then
+ -- loop over known suffixes
+ for _,s in pairs(runners.suffixes) do
+ result = resolvers.find_file(name .. "." .. s, 'texmfscripts')
+ if result ~= "" then
+ break
+ end
+ end
+ elseif runners.applications[suffix] then
+ result = resolvers.find_file(name, 'texmfscripts')
+ else
+ -- maybe look on path
+ result = resolvers.find_file(name, 'other text files')
+ end
+ end
+ if result and result ~= "" then
+ local before, after = environment.split_arguments(fullname) -- already done
+ environment.arguments_before, environment.arguments_after = before, after
+ if internal then
+ arg = { } for _,v in pairs(after) do arg[#arg+1] = v end
+ dofile(result)
+ else
+ local binary = runners.applications[file.extname(result)]
+ if binary and binary ~= "" then
+ result = binary .. " " .. result
+ end
+ local command = result .. " " .. environment.reconstruct_commandline(after,noquote)
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
+ io.flush()
+ end
+ local code = os.exec(command) -- maybe spawn
+ return code == 0
+ end
+ end
+ end
+ end
+ return false
+end
+
+function runners.execute_program(fullname)
+ local noquote = environment.argument("noquotes")
+ if fullname and fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ local before, after = environment.split_arguments(fullname)
+ environment.initialize_arguments(after)
+ fullname = fullname:gsub("^bin:","")
+ local command = fullname .. " " .. (environment.reconstruct_commandline(after or "",noquote) or "")
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
+ io.flush()
+ local code = os.exec(command) -- (fullname,unpack(after)) does not work / maybe spawn
+ return code == 0
+ end
+ end
+ return false
+end
+
+-- the --usekpse flag will fallback on kpse
+
+local windows_stub = '@echo off\013\010setlocal\013\010set ownpath=%%~dp0%%\013\010texlua "%%ownpath%%mtxrun.lua" --usekpse --execute %s %%*\013\010endlocal\013\010'
+local unix_stub = '#!/bin/sh\010mtxrun --usekpse --execute %s \"$@\"\010'
+
+function runners.handle_stubs(create)
+ local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer subpathssupported
+ local windows = environment.argument('windows') or environment.argument('mswin') or false
+ local unix = environment.argument('unix') or environment.argument('linux') or false
+ if not windows and not unix then
+ if os.platform == "unix" then
+ unix = true
+ else
+ windows = true
+ end
+ end
+ for _,v in pairs(runners.registered) do
+ local name, doit = v[1], v[2]
+ if doit then
+ local base = string.gsub(file.basename(name), "%.(.-)$", "")
+ if create then
+ if windows then
+ io.savedata(file.join(stubpath,base..".bat"),string.format(windows_stub,name))
+ logs.simple("windows stub for '%s' created",base)
+ end
+ if unix then
+ io.savedata(file.join(stubpath,base),string.format(unix_stub,name))
+ logs.simple("unix stub for '%s' created",base)
+ end
+ else
+ if windows and (os.remove(file.join(stubpath,base..'.bat')) or os.remove(file.join(stubpath,base..'.cmd'))) then
+ logs.simple("windows stub for '%s' removed", base)
+ end
+ if unix and (os.remove(file.join(stubpath,base)) or os.remove(file.join(stubpath,base..'.sh'))) then
+ logs.simple("unix stub for '%s' removed",base)
+ end
+ end
+ end
+ end
+end
+
+function runners.resolve_string(filename)
+ if filename and filename ~= "" then
+ runners.report_location(resolvers.resolve(filename))
+ end
+end
+
+function runners.locate_file(filename)
+ -- differs from texmfstart where locate appends .com .exe .bat ... todo
+ if filename and filename ~= "" then
+ runners.report_location(resolvers.find_given_file(filename))
+ end
+end
+
+function runners.locate_platform()
+ runners.report_location(os.currentplatform())
+end
+
+function runners.report_location(result)
+ if logs.verbose then
+ logs.simpleline()
+ if result and result ~= "" then
+ logs.simple(result)
+ else
+ logs.simple("not found")
+ end
+ else
+ io.write(result)
+ end
+end
+
+function runners.edit_script(filename) -- we assume that vim is present on most systems
+ local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'vim'
+ local rest = resolvers.resolve(filename)
+ if rest ~= "" then
+ local command = editor .. " " .. rest
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("starting editor: %s",command)
+ logs.simple_line()
+ logs.simple_line()
+ end
+ os.launch(command)
+ end
+end
+
+function runners.save_script_session(filename, list)
+ local t = { }
+ for _, key in ipairs(list) do
+ t[key] = environment.arguments[key]
+ end
+ io.savedata(filename,table.serialize(t,true))
+end
+
+function runners.load_script_session(filename)
+ if lfs.isfile(filename) then
+ local t = io.loaddata(filename)
+ if t then
+ t = loadstring(t)
+ if t then t = t() end
+ for key, value in pairs(t) do
+ environment.arguments[key] = value
+ end
+ end
+ end
+end
+
+function resolvers.launch(str)
+ -- maybe we also need to test on mtxrun.launcher.suffix environment
+ -- variable or on windows consult the assoc and ftype vars and such
+ local launchers = runners.launchers[os.platform] if launchers then
+ local suffix = file.extname(str) if suffix then
+ local runner = launchers[suffix] if runner then
+ str = runner .. " " .. str
+ end
+ end
+ end
+ os.launch(str)
+end
+
+function runners.launch_file(filename)
+ instance.allresults = true
+ logs.setverbose(true)
+ local pattern = environment.arguments["pattern"]
+ if not pattern or pattern == "" then
+ pattern = filename
+ end
+ if not pattern or pattern == "" then
+ logs.simple("provide name or --pattern=")
+ else
+ local t = resolvers.find_files(pattern)
+ if not t or #t == 0 then
+ t = resolvers.find_files("*/" .. pattern)
+ end
+ if not t or #t == 0 then
+ t = resolvers.find_files("*/" .. pattern .. "*")
+ end
+ if t and #t > 0 then
+ if environment.arguments["all"] then
+ for _, v in pairs(t) do
+ logs.simple("launching %s", v)
+ resolvers.launch(v)
+ end
+ else
+ logs.simple("launching %s", t[1])
+ resolvers.launch(t[1])
+ end
+ else
+ logs.simple("no match for %s", pattern)
+ end
+ end
+end
+
+function runners.find_mtx_script(filename)
+ local function found(name)
+ local path = file.dirname(name)
+ if path and path ~= "" then
+ return false
+ else
+ local fullname = own and own.path and file.join(own.path,name)
+ return io.exists(fullname) and fullname
+ end
+ end
+ filename = file.addsuffix(filename,"lua")
+ local basename = file.removesuffix(file.basename(filename))
+ local suffix = file.extname(filename)
+ -- qualified path, raw name
+ local fullname = file.is_qualified_path(filename) and io.exists(filename) and filename
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- current path, raw name
+ fullname = "./" .. filename
+ fullname = io.exists(fullname) and fullname
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename>
+ fullname = "mtx-" .. filename
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename>s
+ fullname = "mtx-" .. basename .. "s" .. "." .. suffix
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename minus trailing s>
+ fullname = "mtx-" .. basename:gsub("s$","") .. "." .. suffix
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, just <filename>
+ fullname = resolvers.find_file(filename)
+ return fullname
+end
+
+function runners.execute_ctx_script(filename,arguments)
+ local fullname = runners.find_mtx_script(filename) or ""
+ -- retyr after generate but only if --autogenerate
+ if fullname == "" and environment.argument("autogenerate") then -- might become the default
+ instance.renewcache = true
+ logs.setverbose(true)
+ resolvers.load()
+ --
+ fullname = runners.find_mtx_script(filename) or ""
+ end
+ -- that should do it
+ if fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ -- load and save ... kind of undocumented
+ arg = { } for _,v in pairs(arguments) do arg[#arg+1] = resolvers.resolve(v) end
+ environment.initialize_arguments(arg)
+ local loadname = environment.arguments['load']
+ if loadname then
+ if type(loadname) ~= "string" then loadname = file.basename(fullname) end
+ loadname = file.replacesuffix(loadname,"cfg")
+ runners.load_script_session(loadname)
+ end
+ filename = environment.files[1]
+ if logs.verbose then
+ logs.simple("using script: %s\n",fullname)
+ end
+ dofile(fullname)
+ local savename = environment.arguments['save']
+ if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
+ if type(savename) ~= "string" then savename = file.basename(fullname) end
+ savename = file.replacesuffix(savename,"cfg")
+ runners.save_script_session(savename, runners.save_list)
+ end
+ return true
+ end
+ else
+ logs.setverbose(true)
+ filename = file.addsuffix(filename,"lua")
+ if filename == "" then
+ logs.simple("unknown script, no name given")
+ elseif file.is_qualified_path(filename) then
+ logs.simple("unknown script '%s'",filename)
+ else
+ logs.simple("unknown script '%s' or 'mtx-%s'",filename,filename)
+ end
+ return false
+ end
+end
+
+function runners.timed(action)
+ statistics.timed(action)
+end
+
+-- this is a bit dirty ... first we store the first filename and next we
+-- split the arguments so that we only see the ones meant for this script
+-- ... later we will use the second half
+
+local filename = environment.files[1] or ""
+local ok = true
+
+local before, after = environment.split_arguments(filename)
+environment.arguments_before, environment.arguments_after = before, after
+environment.initialize_arguments(before)
+
+instance.engine = environment.argument("engine") or 'luatex'
+instance.progname = environment.argument("progname") or 'context'
+instance.lsrmode = environment.argument("lsr") or false
+
+-- maybe the unset has to go to this level
+
+if environment.argument("usekpse") or environment.argument("forcekpse") then
+
+ os.setenv("engine","")
+ os.setenv("progname","")
+
+ local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ pfb = "type1 fonts",
+ other = "other text files",
+ }
+
+ local function kpse_initialized()
+ texconfig.kpse_init = true
+ local t = os.clock()
+ local k = kpse.original.new("luatex",instance.progname)
+ local dummy = k:find_file("mtxrun.lua") -- so that we're initialized
+ logs.simple("kpse fallback with progname '%s' initialized in %s seconds",instance.progname,os.clock()-t)
+ kpse_initialized = function() return k end
+ return k
+ end
+
+ local find_file = resolvers.find_file
+ local show_path = resolvers.show_path
+
+ if environment.argument("forcekpse") then
+
+ function resolvers.find_file(name,kind)
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ function resolvers.show_path(name)
+ return (kpse_initialized():show_path(name)) or ""
+ end
+
+ elseif environment.argument("usekpse") then
+
+ resolvers.load()
+
+ function resolvers.find_file(name,kind)
+ local found = find_file(name,kind) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ end
+ function resolvers.show_path(name)
+ local found = show_path(name) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():show_path(name)) or ""
+ end
+ end
+
+ end
+
+else
+
+ resolvers.load()
+
+end
+
+
+if environment.argument("selfmerge") then
+ -- embed used libraries
+ utils.merger.selfmerge(own.name,own.libs,own.list)
+elseif environment.argument("selfclean") then
+ -- remove embedded libraries
+ utils.merger.selfclean(own.name)
+elseif environment.argument("selfupdate") then
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"mtxrun")
+elseif environment.argument("ctxlua") or environment.argument("internal") then
+ -- run a script by loading it (using libs)
+ ok = runners.execute_script(filename,true)
+elseif environment.argument("script") or environment.argument("s") then
+ -- run a script by loading it (using libs), pass args
+ ok = runners.execute_ctx_script(filename,after)
+elseif environment.argument("execute") then
+ -- execute script
+ ok = runners.execute_script(filename)
+elseif environment.argument("direct") then
+ -- equals bin:
+ ok = runners.execute_program(filename)
+elseif environment.argument("edit") then
+ -- edit file
+ runners.edit_script(filename)
+elseif environment.argument("launch") then
+ runners.launch_file(filename)
+elseif environment.argument("make") then
+ -- make stubs
+ runners.handle_stubs(true)
+elseif environment.argument("remove") then
+ -- remove stub
+ runners.handle_stubs(false)
+elseif environment.argument("resolve") then
+ -- resolve string
+ runners.resolve_string(filename)
+elseif environment.argument("locate") then
+ -- locate file
+ runners.locate_file(filename)
+elseif environment.argument("platform")then
+ -- locate platform
+ runners.locate_platform()
+elseif environment.argument("help") or filename=='help' or filename == "" then
+ logs.help(messages.help)
+ -- execute script
+elseif filename:find("^bin:") then
+ ok = runners.execute_program(filename)
+else
+ ok = runners.execute_script(filename)
+end
+
+if os.platform == "unix" then
+ io.write("\n")
+end
+
+if ok == false then ok = 1 elseif ok == true then ok = 0 end
+
+os.exit(ok)
diff --git a/scripts/context/stubs/mswin/mtxtools.bat b/scripts/context/stubs/mswin/mtxtools.bat
new file mode 100755
index 000000000..9554220c4
--- /dev/null
+++ b/scripts/context/stubs/mswin/mtxtools.bat
@@ -0,0 +1,5 @@
+@echo off
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute mtxtools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/pdftools.bat b/scripts/context/stubs/mswin/pdftools.bat
index adc48eacf..5e893fb2a 100755
--- a/scripts/context/stubs/mswin/pdftools.bat
+++ b/scripts/context/stubs/mswin/pdftools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart pdftools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute pdftools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/pdftrimwhite.bat b/scripts/context/stubs/mswin/pdftrimwhite.bat
deleted file mode 100755
index a7034b400..000000000
--- a/scripts/context/stubs/mswin/pdftrimwhite.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart pdftrimwhite.pl %*
diff --git a/scripts/context/stubs/mswin/pstopdf.bat b/scripts/context/stubs/mswin/pstopdf.bat
index 248e34caf..f8d4325f4 100755
--- a/scripts/context/stubs/mswin/pstopdf.bat
+++ b/scripts/context/stubs/mswin/pstopdf.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart pstopdf.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute pstopdf.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/rlxtools.bat b/scripts/context/stubs/mswin/rlxtools.bat
index b78dec13b..82f09665a 100755
--- a/scripts/context/stubs/mswin/rlxtools.bat
+++ b/scripts/context/stubs/mswin/rlxtools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart rlxtools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute rlxtools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/runtools.bat b/scripts/context/stubs/mswin/runtools.bat
index 68a7b4f97..f471e747d 100755
--- a/scripts/context/stubs/mswin/runtools.bat
+++ b/scripts/context/stubs/mswin/runtools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart runtools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute runtools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texexec.bat b/scripts/context/stubs/mswin/texexec.bat
index 02b297b9c..acbe41fd8 100755
--- a/scripts/context/stubs/mswin/texexec.bat
+++ b/scripts/context/stubs/mswin/texexec.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart texexec.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute texexec.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texexec.cmd b/scripts/context/stubs/mswin/texexec.cmd
new file mode 100644
index 000000000..acbe41fd8
--- /dev/null
+++ b/scripts/context/stubs/mswin/texexec.cmd
@@ -0,0 +1,5 @@
+@echo off
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute texexec.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texfind.bat b/scripts/context/stubs/mswin/texfind.bat
deleted file mode 100755
index b7c11cbca..000000000
--- a/scripts/context/stubs/mswin/texfind.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart texfind %*
diff --git a/scripts/context/stubs/mswin/texfont.bat b/scripts/context/stubs/mswin/texfont.bat
index 3134bf14c..98e9f7c76 100755
--- a/scripts/context/stubs/mswin/texfont.bat
+++ b/scripts/context/stubs/mswin/texfont.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart texfont.pl %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute texfont.pl %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texmfstart.cmd b/scripts/context/stubs/mswin/texmfstart.cmd
new file mode 100644
index 000000000..47a10cc54
--- /dev/null
+++ b/scripts/context/stubs/mswin/texmfstart.cmd
@@ -0,0 +1,5 @@
+@echo off
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texshow.bat b/scripts/context/stubs/mswin/texshow.bat
deleted file mode 100755
index 2060846ad..000000000
--- a/scripts/context/stubs/mswin/texshow.bat
+++ /dev/null
@@ -1,2 +0,0 @@
-@echo off
-texmfstart texshow.pl %*
diff --git a/scripts/context/stubs/mswin/textools.bat b/scripts/context/stubs/mswin/textools.bat
index 727b4a36d..3b047ba7d 100755
--- a/scripts/context/stubs/mswin/textools.bat
+++ b/scripts/context/stubs/mswin/textools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart textools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute textools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/texutil.bat b/scripts/context/stubs/mswin/texutil.bat
index 1e63639bb..f01ced1a3 100755
--- a/scripts/context/stubs/mswin/texutil.bat
+++ b/scripts/context/stubs/mswin/texutil.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart texutil.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute texutil.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/tmftools.bat b/scripts/context/stubs/mswin/tmftools.bat
index c9c0c08bd..689a93c65 100755
--- a/scripts/context/stubs/mswin/tmftools.bat
+++ b/scripts/context/stubs/mswin/tmftools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart tmftools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute tmftools.rb %*
+endlocal
diff --git a/scripts/context/stubs/mswin/xmltools.bat b/scripts/context/stubs/mswin/xmltools.bat
index 2de0e4457..572cc9b8b 100755
--- a/scripts/context/stubs/mswin/xmltools.bat
+++ b/scripts/context/stubs/mswin/xmltools.bat
@@ -1,2 +1,5 @@
@echo off
-texmfstart xmltools.rb %*
+setlocal
+set ownpath=%~dp0%
+texlua "%ownpath%mtxrun.lua" --usekpse --execute xmltools.rb %*
+endlocal
diff --git a/scripts/context/stubs/unix/ctxtools b/scripts/context/stubs/unix/ctxtools
index 84e47bbee..4658a345a 100755
--- a/scripts/context/stubs/unix/ctxtools
+++ b/scripts/context/stubs/unix/ctxtools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart ctxtools.rb "$@"
+mtxrun --usekpse --execute ctxtools.rb "$@"
diff --git a/scripts/context/stubs/unix/exatools b/scripts/context/stubs/unix/exatools
deleted file mode 100755
index 50ff0f07e..000000000
--- a/scripts/context/stubs/unix/exatools
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-texmfstart exatools.rb "$@"
diff --git a/scripts/context/stubs/unix/luatools b/scripts/context/stubs/unix/luatools
new file mode 100755
index 000000000..aacdbd16d
--- /dev/null
+++ b/scripts/context/stubs/unix/luatools
@@ -0,0 +1,6977 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['luatools'] = {
+ version = 1.001,
+ comment = "companion to context.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+-- one can make a stub:
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua texlua luatools.lua "$@"
+
+-- Although this script is part of the ConTeXt distribution it is
+-- relatively indepent of ConTeXt. The same is true for some of
+-- the luat files. We may may make them even less dependent in
+-- the future. As long as Luatex is under development the
+-- interfaces and names of functions may change.
+
+-- For the sake of independence we optionally can merge the library
+-- code here. It's too much code, but that does not harm. Much of the
+-- library code is used elsewhere. We don't want dependencies on
+-- Lua library paths simply because these scripts are located in the
+-- texmf tree and not in some Lua path. Normally this merge is not
+-- needed when texmfstart is used, or when the proper stub is used or
+-- when (windows) suffix binding is active.
+
+texlua = true
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+function string:quote() -- we could use format("%q")
+ return '"' .. self:unquote() .. '"'
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+function string:strip()
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
+end
+
+function string:is_empty()
+ return not find(find,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, str:sub(index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. self.rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+local hash = { }
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return P(pattern)
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local newline = crlf + cr + lf
+local spacing = space^0 * newline
+
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return capture:match(self)
+end
+
+lpeg.linebyline = content -- better make a sublibrary
+
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, ipairs = type, next, tostring, ipairs
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+function table.one_entry(t)
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+function table.starts_at(t)
+ return ipairs(t,1)(t,0)
+end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete)
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end })
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ 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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data)
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+number = number or { }
+
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+function number.toevenhex(n)
+ local s = format("%X",n)
+ if #s % 2 == 0 then
+ return s
+ else
+ return "0" .. s
+ end
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+local one = lpeg.C(1-lpeg.S(''))^1
+
+function number.toset(n)
+ return one:match(tostring(n))
+end
+
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+set = set or { }
+
+local nums = { }
+local tabs = { }
+local concat = table.concat
+
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
+ end
+ end
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
+ end
+ return nums[s]
+ else
+ return 0
+ end
+end
+
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
+ end
+end
+
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
+end
+
+--~ local c = set.create{'aap','noot','mies'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ local c = set.create{'zus','wim','jet'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ print(t['jet'])
+--~ print(set.contains(t,'jet'))
+--~ print(set.contains(t,'aap'))
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+function os.resultof(command)
+ return io.popen(command,"r"):read("*all")
+end
+
+if not os.exec then os.exec = os.execute end
+if not os.spawn then os.spawn = os.execute end
+
+--~ os.type : windows | unix (new, we already guessed os.platform)
+--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
+
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
+ else
+ io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
+ end
+end
+
+os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
+
+function os.launch(str)
+ if os.platform == "windows" then
+ os.execute("start " .. str) -- os.spawn ?
+ else
+ os.execute(str .. " &") -- os.spawn ?
+ end
+end
+
+if not os.setenv then
+ function os.setenv() return false end
+end
+
+if not os.times then
+ -- utime = user time
+ -- stime = system time
+ -- cutime = children user time
+ -- cstime = children system time
+ function os.times()
+ return {
+ utime = os.gettimeofday(), -- user
+ stime = 0, -- system
+ cutime = 0, -- children user
+ cstime = 0, -- children system
+ }
+ end
+end
+
+os.gettimeofday = os.gettimeofday or os.clock
+
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
+end
+
+--~ print(os.gettimeofday()-os.time())
+--~ os.sleep(1.234)
+--~ print (">>",os.runtime())
+--~ print(os.date("%H:%M:%S",os.gettimeofday()))
+--~ print(os.date("%H:%M:%S",os.time()))
+
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name)
+ return match(name,"^(.+)[/\\].-$") or ""
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name)
+ return match(name,"^.+%.([^/\\]-)$") or ""
+end
+
+file.suffix = file.extname
+
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.join(...)
+ local pth = concat({...},"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ return (gsub(pth,"//+","/"))
+end
+
+function file.iswritable(name)
+ local a = lfs.attributes(name)
+ if a and a.permissions:sub(2,2) == "w" then
+ return true
+ else
+ name = file.dirname(name) or "."
+ if name == "" then name = "." end
+ a = lfs.attributes(name)
+ return a and a.permissions:sub(2,2) == "w"
+ end
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and a.permissions:sub(1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+function file.split_path(str)
+ local t = { }
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
+ if name ~= "" then
+ t[#t+1] = gsub(name,"\001",":")
+ end
+ end
+ return t
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+function file.collapse_path(str)
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return pattern:match(name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = pattern:match(name)
+--~ if b then
+--~ return name:sub(a,b-2)
+--~ elseif a then
+--~ return name:sub(a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEXsum(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-url'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local char, gmatch = string.char, string.gmatch
+local tonumber, type = tonumber, type
+
+-- from the spec (on the web):
+--
+-- foo://example.com:8042/over/there?name=ferret#nose
+-- \_/ \______________/\_________/ \_________/ \__/
+-- | | | | |
+-- scheme authority path query fragment
+-- | _____________________|__
+-- / \ / \
+-- urn:example:animal:ferret:nose
+
+url = url or { }
+
+local function tochar(s)
+ return char(tonumber(s,16))
+end
+
+local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
+
+local hexdigit = lpeg.R("09","AF","af")
+local plus = lpeg.P("+")
+local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar)
+
+local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
+local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
+local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
+local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
+local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
+
+local parser = lpeg.Ct(scheme * authority * path * query * fragment)
+
+function url.split(str)
+ return (type(str) == "string" and parser:match(str)) or str
+end
+
+function url.hashed(str)
+ local s = url.split(str)
+ return {
+ scheme = (s[1] ~= "" and s[1]) or "file",
+ authority = s[2],
+ path = s[3],
+ query = s[4],
+ fragment = s[5],
+ original = str
+ }
+end
+
+function url.filename(filename)
+ local t = url.hashed(filename)
+ return (t.scheme == "file" and t.path:gsub("^/([a-zA-Z])([:|])/)","%1:")) or filename
+end
+
+function url.query(str)
+ if type(str) == "string" then
+ local t = { }
+ for k, v in gmatch(str,"([^&=]*)=([^&=]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return str
+ end
+end
+
+--~ print(url.filename("file:///c:/oeps.txt"))
+--~ print(url.filename("c:/oeps.txt"))
+--~ print(url.filename("file:///oeps.txt"))
+--~ print(url.filename("file:///etc/test.txt"))
+--~ print(url.filename("/oeps.txt"))
+
+--~ from the spec on the web (sort of):
+--~
+--~ function test(str)
+--~ print(table.serialize(url.hashed(str)))
+--~ end
+--~
+--~ test("%56pass%20words")
+--~ test("file:///c:/oeps.txt")
+--~ test("file:///c|/oeps.txt")
+--~ test("file:///etc/oeps.txt")
+--~ test("file://./etc/oeps.txt")
+--~ test("file:////etc/oeps.txt")
+--~ test("ftp://ftp.is.co.za/rfc/rfc1808.txt")
+--~ test("http://www.ietf.org/rfc/rfc2396.txt")
+--~ test("ldap://[2001:db8::7]/c=GB?objectClass?one#what")
+--~ test("mailto:John.Doe@example.com")
+--~ test("news:comp.infosystems.www.servers.unix")
+--~ test("tel:+1-816-555-1212")
+--~ test("telnet://192.0.2.16:80/")
+--~ test("urn:oasis:names:specification:docbook:dtd:xml:4.1.2")
+--~ test("/etc/passwords")
+--~ test("http://www.pragma-ade.com/spaced%20name")
+
+--~ test("zip:///oeps/oeps.zip#bla/bla.tex")
+--~ test("zip:///oeps/oeps.zip?bla/bla.tex")
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local find, gmatch = string.find, string.gmatch
+
+dir = dir or { }
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
+ end
+ end
+ end
+end
+
+dir.glob_pattern = glob_pattern
+
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
+
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
+ local t = t or { }
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
+ return t
+ else
+ return { }
+ end
+ end
+end
+
+dir.glob = glob
+
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
+
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
+ files[#files+1] = path .. "/" .. name
+ end
+ else
+ files[#files+1] = path .. "/" .. name
+ end
+ end
+ end
+ end
+ return files
+end
+
+dir.globfiles = globfiles
+
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
+
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
+
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
+
+local make_indeed = true -- false
+
+if string.find(os.getenv("PATH"),";") then
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
+ if first then
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
+ else
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
+ if first then
+ pth, drive = first .. middle, true
+ else
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
+ end
+ end
+ end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("a:"))
+--~ print(dir.mkdirs("a:/b/c"))
+--~ print(dir.mkdirs("a:b/c"))
+--~ print(dir.mkdirs("a:/bbb/c"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
+ end
+ lfs.chdir(d)
+ end
+ end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
+
+else
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
+ end
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
+ end
+
+end
+
+dir.makedirs = dir.mkdirs
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+function boolean.alwaystrue()
+ return true
+end
+
+function boolean.falsetrue()
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+utf = utf or unicode.utf8
+
+local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
+local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
+
+unicode = unicode or { }
+
+-- 0 EF BB BF UTF-8
+-- 1 FF FE UTF-16-little-endian
+-- 2 FE FF UTF-16-big-endian
+-- 3 FF FE 00 00 UTF-32-little-endian
+-- 4 00 00 FE FF UTF-32-big-endian
+
+unicode.utfname = {
+ [0] = 'utf-8',
+ [1] = 'utf-16-le',
+ [2] = 'utf-16-be',
+ [3] = 'utf-32-le',
+ [4] = 'utf-32-be'
+}
+
+function unicode.utftype(f) -- \000 fails !
+ local str = f:read(4)
+ if not str then
+ f:seek('set')
+ return 0
+ elseif find(str,"^%z%z\254\255") then
+ return 4
+ elseif find(str,"^\255\254%z%z") then
+ return 3
+ elseif find(str,"^\254\255") then
+ f:seek('set',2)
+ return 2
+ elseif find(str,"^\255\254") then
+ f:seek('set',2)
+ return 1
+ elseif find(str,"^\239\187\191") then
+ f:seek('set',3)
+ return 0
+ else
+ f:seek('set')
+ return 0
+ end
+end
+
+function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
+ local result, tmp, n, m, p = { }, { }, 0, 0, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for l,r in bytepairs(str) do
+ if r then
+ if endian then
+ n = l*256 + r
+ else
+ n = r*256 + l
+ end
+ if m > 0 then
+ n = (m-0xD800)*0x400 + (n-0xDC00) + 0x10000
+ m = 0
+ doit()
+ elseif n >= 0xD800 and n <= 0xDBFF then
+ m = n
+ else
+ doit()
+ end
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+function unicode.utf32_to_utf8(str, endian)
+ local result = { }
+ local tmp, n, m, p = { }, 0, -1, 0
+ -- lf | cr | crlf / (cr:13, lf:10)
+ local function doit()
+ if n == 10 then
+ if p ~= 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = 0
+ end
+ elseif n == 13 then
+ result[#result+1] = concat(tmp)
+ tmp = { }
+ p = n
+ else
+ tmp[#tmp+1] = utfchar(n)
+ p = 0
+ end
+ end
+ for a,b in bytepairs(str) do
+ if a and b then
+ if m < 0 then
+ if endian then
+ m = a*256*256*256 + b*256*256
+ else
+ m = b*256 + a
+ end
+ else
+ if endian then
+ n = m + a*256 + b
+ else
+ n = m + b*256*256*256 + a*256*256
+ end
+ m = -1
+ doit()
+ end
+ else
+ break
+ end
+ end
+ if #tmp > 0 then
+ result[#result+1] = concat(tmp)
+ end
+ return result
+end
+
+local function little(c)
+ local b = byte(c) -- b = c:byte()
+ if b < 0x10000 then
+ return char(b%256,b/256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1%256,b1/256,b2%256,b2/256)
+ end
+end
+
+local function big(c)
+ local b = byte(c)
+ if b < 0x10000 then
+ return char(b/256,b%256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1/256,b1%256,b2/256,b2%256)
+ end
+end
+
+function unicode.utf8_to_utf16(str,littleendian)
+ if littleendian then
+ return char(255,254) .. utfgsub(str,".",little)
+ else
+ return char(254,255) .. utfgsub(str,".",big)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
+
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (data:gsub(utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for _, lib in ipairs(libs) do
+ for _, pth in ipairs(list) do
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return table.concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
+ end
+ end
+ grandtotal = grandtotal + count
+ functions = functions + 1
+ end
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+end
+
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
+ end
+end
+
+function debugger.enable()
+ debug.sethook(hook,"c")
+end
+
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
+end
+
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
+ end
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
+
+-- dirty tricks
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
+
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index, argument in pairs(arg) do
+ if index > 0 then
+ local flag, value = argument:match("^%-+(.+)=(.-)$")
+ if flag then
+ arguments[flag] = string.unquote(value or "")
+ else
+ flag = argument:match("^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = { }
+ for _,v in pairs(table.sortedkeys(arguments)) do
+ sortedflags[#sortedflags+1] = "^" .. v
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for _,v in ipairs(sortedflags) do
+ if name:find(v) then
+ return arguments[v:sub(2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ for _,v in ipairs(environment.original_arguments) do
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ return a
+ elseif next(arg) then
+ local result = { }
+ for _,a in ipairs(arg) do -- ipairs 1 .. #n
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ a = a:gsub('"','\\"') -- tricky
+ if a:find(" ") then
+ result[#result+1] = a:quote()
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index, argument in ipairs(arg) do
+ if argument:find("^\"") then
+ newarg[#newarg+1] = argument:gsub("^\"","")
+ if not argument:find("\"$") then
+ instring = true
+ end
+ elseif argument:find("\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "companion to luat-lib.tex",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ instance.variables[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
+
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
+ else
+ local binary = resolvers.ownbin
+ if os.platform == "windows" then
+ binary = file.replacesuffix(binary,"exe")
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
+ end
+ resolvers.ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
+ end
+ resolvers.ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
+ end
+ return resolvers.ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ local f = io.open(lname)
+ if f then -- this will go
+ f:close()
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
+ for k,v in pairs(c) do
+ if type(v) == 'string' then
+ local t = file.split_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return file.split_path(str)
+ end
+end
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h = { }, { }
+ for _,vv in ipairs(file.split_path(v)) do
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ for _, cnf in ipairs(instance.cnffiles) do
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(str)
+ else
+ return resolvers.expanded_path_list(tmp)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","+ readable: %s",name)
+ else
+ logs.report("fileio","- readable: %s", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local doscan, recurse
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist and not (done and not instance.allresults) and recurse then
+ -- compare list entries with permitted pattern
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
+ local expr = "^" .. pathname
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
+ end
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag]
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_verbose then
+ report('')
+ end
+ for _, file in ipairs(files) do
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for _,v in ipairs(result) do
+ report(v)
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in pairs(t) do -- pairs?
+ s[#s+1] = k .. "=" .. v
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ for _, hash in ipairs(instance.hashes) do
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in pairs(v) do -- ipairs?
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.</p>
+
+</code>
+TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
+</code>
+
+<p>Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.</p>
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ return loader()
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if table.is_empty(mountpaths) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if not table.is_empty(mountpaths) then
+ statistics.starttiming(resolvers.instance)
+ for k, root in pairs(mountpaths) do
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if line:find("^[%%#%-]") then -- or %W
+ -- skip
+ elseif line:find("^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-lst'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- used in mtxrun
+
+local find, concat, upper, format = string.find, table.concat, string.upper, string.format
+
+resolvers.listers = resolvers.listers or { }
+
+local function tabstr(str)
+ if type(str) == 'table' then
+ return concat(str," | ")
+ else
+ return str
+ end
+end
+
+local function list(list,report)
+ local instance = resolvers.instance
+ local pat = upper(pattern or "","")
+ local report = report or texio.write_nl
+ for _,key in pairs(table.sortedkeys(list)) do
+ if instance.pattern == "" or find(upper(key),pat) then
+ if instance.kpseonly then
+ if instance.kpsevars[key] then
+ report(format("%s=%s",key,tabstr(list[key])))
+ end
+ else
+ report(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
+ end
+ end
+ end
+end
+
+function resolvers.listers.variables () list(resolvers.instance.variables ) end
+function resolvers.listers.expansions() list(resolvers.instance.expansions) end
+
+function resolvers.listers.configurations(report)
+ local report = report or texio.write_nl
+ local instance = resolvers.instance
+ for _,key in ipairs(table.sortedkeys(instance.kpsevars)) do
+ if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
+ report(format("%s\n",key))
+ for i,c in ipairs(instance.order) do
+ local str = c[key]
+ if str then
+ report(format("\t%s\t%s",i,str))
+ end
+ end
+ report("")
+ end
+ end
+end
+
+
+end -- of closure
+-- end library merge
+
+-- We initialize some characteristics of this program. We need to
+-- do this before we load the libraries, else own.name will not be
+-- properly set (handy for selfcleaning the file). It's an ugly
+-- looking piece of code.
+
+own = { }
+
+own.libs = { -- todo: check which ones are really needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-io.lua',
+ 'l-number.lua',
+ 'l-set.lua',
+ 'l-os.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-url.lua',
+ 'l-dir.lua',
+ 'l-boolean.lua',
+ 'l-unicode.lua',
+ 'l-math.lua',
+ 'l-utils.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+-- 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-lst.lua', -- lister
+}
+
+-- We need this hack till luatex is fixed.
+
+if arg and arg[0] == 'luatex' and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+-- End of hack.
+
+own.name = (environment and environment.ownname) or arg[0] or 'luatools.lua'
+own.path = string.match(own.name,"^(.+)[\\/].-$") or "."
+own.list = { '.' }
+
+if own.path ~= '.' then
+ table.insert(own.list,own.path)
+end
+
+table.insert(own.list,own.path.."/../../../tex/context/base")
+table.insert(own.list,own.path.."/mtx")
+table.insert(own.list,own.path.."/../sources")
+
+function locate_libs()
+ for _, lib in pairs(own.libs) do
+ for _, pth in pairs(own.list) do
+ local filename = string.gsub(pth .. "/" .. lib,"\\","/")
+ local codeblob = loadfile(filename)
+ if codeblob then
+ codeblob()
+ own.list = { pth } -- speed up te search
+ break
+ end
+ end
+ end
+end
+
+if not resolvers then
+ locate_libs()
+end
+
+if not resolvers then
+ print("")
+ print("Luatools is unable to start up due to lack of libraries. You may")
+ print("try to run 'lua luatools.lua --selfmerge' in the path where this")
+ print("script is located (normally under ..../scripts/context/lua) which")
+ print("will make luatools library independent.")
+ os.exit()
+end
+
+logs.setprogram('LuaTools',"TDS Management Tool 1.31",environment.arguments["verbose"] or false)
+
+local instance = resolvers.reset()
+
+resolvers.defaultlibs = { -- not all are needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-boolean.lua',
+ 'l-number.lua',
+ 'l-unicode.lua',
+ 'l-os.lua',
+ 'l-io.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-url.lua',
+ 'l-dir.lua',
+ 'l-utils.lua',
+ 'l-dimen.lua',
+ 'trac-inf.lua',
+ 'trac-tra.lua',
+ 'trac-log.lua',
+ 'luat-env.lua', -- here ?
+ 'data-res.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-tmp.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-pre.lua',
+ 'data-tex.lua',
+ 'data-bin.lua',
+-- 'data-zip.lua',
+-- 'data-clr.lua',
+ 'data-lua.lua',
+ 'data-ctx.lua',
+ 'luat-fio.lua',
+ 'luat-cnf.lua',
+}
+
+instance.engine = environment.arguments["engine"] or 'luatex'
+instance.progname = environment.arguments["progname"] or 'context'
+instance.luaname = environment.arguments["luafile"] or "" -- environment.ownname or ""
+instance.lualibs = environment.arguments["lualibs"] or table.concat(resolvers.defaultlibs,",")
+instance.allresults = environment.arguments["all"] or false
+instance.pattern = environment.arguments["pattern"] or nil
+instance.sortdata = environment.arguments["sort"] or false
+instance.kpseonly = not environment.arguments["all"] or false
+instance.my_format = environment.arguments["format"] or instance.format
+
+if type(instance.pattern) == 'boolean' then
+ logs.simple("invalid pattern specification")
+ instance.pattern = nil
+end
+
+if environment.arguments["trace"] then resolvers.settrace(environment.arguments["trace"]) end
+
+runners = runners or { }
+messages = messages or { }
+
+messages.no_ini_file = [[
+There is no lua initialization file found. This file can be forced by the
+"--progname" directive, or specified with "--luaname", or it is derived
+automatically from the formatname (aka jobname). It may be that you have
+to regenerate the file database using "luatools --generate".
+]]
+
+messages.help = [[
+--generate generate file database
+--variables show configuration variables
+--expansions show expanded variables
+--configurations show configuration order
+--expand-braces expand complex variable
+--expand-path expand variable (resolve paths)
+--expand-var expand variable (resolve references)
+--show-path show path expansion of ...
+--var-value report value of variable
+--find-file report file location
+--find-path report path of file
+--make or --ini make luatex format
+--run or --fmt= run luatex format
+--luafile=str lua inifile (default is <progname>.lua)
+--lualibs=list libraries to assemble (optional when --compile)
+--compile assemble and compile lua inifile
+--verbose give a bit more info
+--all show all found files
+--sort sort cached data
+--engine=str target engine
+--progname=str format or backend
+--pattern=str filter variables
+]]
+
+function runners.make_format(texname)
+ local instance = resolvers.instance
+ if texname and texname ~= "" then
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ if path and lfs then
+ lfs.chdir(path)
+ end
+ end
+ local barename = texname:gsub("%.%a+$","")
+ if barename == texname then
+ texname = texname .. ".tex"
+ end
+ local fullname = resolvers.find_files(texname)[1] or ""
+ if fullname == "" then
+ logs.simple("no tex file with name: %s",texname)
+ else
+ local luaname, lucname, luapath, lualibs = "", "", "", { }
+ -- the following is optional, since context.lua can also
+ -- handle this collect and compile business
+ if environment.arguments["compile"] then
+ if luaname == "" then luaname = barename end
+ logs.simple("creating initialization file: %s",luaname)
+ luapath = file.dirname(luaname)
+ if luapath == "" then
+ luapath = file.dirname(texname)
+ end
+ if luapath == "" then
+ luapath = file.dirname(resolvers.find_files(texname)[1] or "")
+ end
+ lualibs = string.split(instance.lualibs,",")
+ luaname = file.basename(barename .. ".lua")
+ lucname = file.basename(barename .. ".luc")
+ -- todo: when this fails, we can just copy the merged libraries from
+ -- luatools since they are normally the same, at least for context
+ if lualibs[1] then
+ local firstlib = file.join(luapath,lualibs[1])
+ if not lfs.isfile(firstlib) then
+ local foundname = resolvers.find_files(lualibs[1])[1]
+ if foundname then
+ logs.simple("located library path: %s",luapath)
+ luapath = file.dirname(foundname)
+ end
+ end
+ end
+ logs.simple("using library path: %s",luapath)
+ logs.simple("using lua libraries: %s",table.join(lualibs," "))
+ utils.merger.selfcreate(lualibs,luapath,luaname)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ if utils.lua.compile(luaname,lucname,false,strip) and io.exists(lucname) then
+ luaname = lucname
+ logs.simple("using compiled initialization file: %s",lucname)
+ else
+ logs.simple("using uncompiled initialization file: %s",luaname)
+ end
+ else
+ for _, v in pairs({instance.luaname, instance.progname, barename}) do
+ v = string.gsub(v..".lua","%.lua%.lua$",".lua")
+ if v and (v ~= "") then
+ luaname = resolvers.find_files(v)[1] or ""
+ if luaname ~= "" then
+ break
+ end
+ end
+ end
+ end
+ if environment.arguments["noluc"] then
+ luaname = luaname:gsub("%.luc$",".lua") -- make this an option
+ end
+ if luaname == "" then
+ if logs.verbose then
+ logs.simplelines(messages.no_ini_file)
+ logs.simple("texname : %s",texname)
+ logs.simple("luaname : %s",instance.luaname)
+ logs.simple("progname: %s",instance.progname)
+ logs.simple("barename: %s",barename)
+ end
+ else
+ logs.simple("using lua initialization file: %s",luaname)
+ local mp = dir.glob(file.removesuffix(file.basename(luaname)).."-*.mem")
+ if mp and #mp > 0 then
+ for _, name in ipairs(mp) do
+ logs.simple("removing related mplib format %s", file.basename(name))
+ os.remove(name)
+ end
+ end
+ local flags = {
+ "--ini",
+ "--lua=" .. string.quote(luaname)
+ }
+ local bs = (os.platform == "unix" and "\\\\") or "\\" -- todo: make a function
+ local command = "luatex ".. table.concat(flags," ") .. " " .. string.quote(fullname) .. " " .. bs .. "dump"
+ logs.simple("running command: %s\n",command)
+ os.spawn(command)
+ -- todo: do a dummy run that generates the related metafun and mfplain formats
+ end
+ end
+ else
+ logs.simple("no tex file given")
+ end
+end
+
+function runners.run_format(name,data,more)
+ -- hm, rather old code here; we can now use the file.whatever functions
+ if name and (name ~= "") then
+ local barename = name:gsub("%.%a+$","")
+ local fmtname = ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ barename = fmtname:gsub("%.%a+$","")
+ if fmtname == "" then
+ logs.simple("no format with name: %s",name)
+ else
+ local luaname = barename .. ".luc"
+ local f = io.open(luaname)
+ if not f then
+ luaname = barename .. ".lua"
+ f = io.open(luaname)
+ end
+ if f then
+ f:close()
+ local command = "luatex --fmt=" .. string.quote(barename) .. " --lua=" .. string.quote(luaname) .. " " .. string.quote(data) .. " " .. (more ~= "" and string.quote(more) or "")
+ logs.simple("running command: %s",command)
+ os.spawn(command)
+ else
+ logs.simple("using format name: %s",fmtname)
+ logs.simple("no luc/lua with name: %s",barename)
+ end
+ end
+ end
+end
+
+local ok = true
+
+-- private option --noluc for testing errors in the stub
+
+if environment.arguments["find-file"] then
+ resolvers.load()
+ instance.format = environment.arguments["format"] or instance.format
+ if instance.pattern then
+ instance.allresults = true
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
+ else
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
+ end
+elseif environment.arguments["find-path"] then
+ resolvers.load()
+ local path = resolvers.find_file(environment.files[1], instance.my_format)
+ if logs.verbose then
+ logs.simple(file.dirname(path))
+ else
+ print(file.dirname(path))
+ end
+elseif environment.arguments["run"] then
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.files[1] or "",environment.files[2] or "",environment.files[3] or "")
+elseif environment.arguments["fmt"] then
+ resolvers.load("nofiles") -- ! no need for loading databases
+ logs.setverbose(true)
+ runners.run_format(environment.arguments["fmt"], environment.files[1] or "",environment.files[2] or "")
+elseif environment.arguments["expand-braces"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_braces, environment.files)
+elseif environment.arguments["expand-path"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_path, environment.files)
+elseif environment.arguments["expand-var"] or environment.arguments["expand-variable"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.expand_var, environment.files)
+elseif environment.arguments["show-path"] or environment.arguments["path-value"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.show_path, environment.files)
+elseif environment.arguments["var-value"] or environment.arguments["show-value"] then
+ resolvers.load("nofiles")
+ resolvers.for_files(resolvers.var_value, environment.files)
+elseif environment.arguments["format-path"] then
+ resolvers.load()
+ logs.simple(caches.setpath("format"))
+elseif instance.pattern then -- brrr
+ resolvers.load()
+ instance.format = environment.arguments["format"] or instance.format
+ instance.allresults = true
+ resolvers.for_files(resolvers.find_files, { instance.pattern }, instance.my_format)
+elseif environment.arguments["generate"] then
+ instance.renewcache = true
+ logs.setverbose(true)
+ resolvers.load()
+elseif environment.arguments["make"] or environment.arguments["ini"] or environment.arguments["compile"] then
+ resolvers.load()
+ logs.setverbose(true)
+ runners.make_format(environment.files[1] or "")
+elseif environment.arguments["selfmerge"] then
+ utils.merger.selfmerge(own.name,own.libs,own.list)
+elseif environment.arguments["selfclean"] then
+ utils.merger.selfclean(own.name)
+elseif environment.arguments["selfupdate"] then
+ resolvers.load()
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"luatools")
+elseif environment.arguments["variables"] or environment.arguments["show-variables"] then
+ resolvers.load("nofiles")
+ resolvers.listers.variables()
+elseif environment.arguments["expansions"] or environment.arguments["show-expansions"] then
+ resolvers.load("nofiles")
+ resolvers.listers.expansions()
+elseif environment.arguments["configurations"] or environment.arguments["show-configurations"] then
+ resolvers.load("nofiles")
+ resolvers.listers.configurations()
+elseif environment.arguments["help"] or (environment.files[1]=='help') or (#environment.files==0) then
+ logs.help(messages.help)
+else
+ resolvers.load()
+ resolvers.for_files(resolvers.find_files, environment.files, instance.my_format)
+end
+
+if logs.verbose then
+ logs.simpleline()
+ logs.simple("runtime: %0.3f seconds",os.runtime())
+end
+
+if os.platform == "unix" then
+ io.write("\n")
+end
diff --git a/scripts/context/stubs/unix/makempy b/scripts/context/stubs/unix/makempy
index 4bf7a1af2..34892b284 100755
--- a/scripts/context/stubs/unix/makempy
+++ b/scripts/context/stubs/unix/makempy
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart makempy.pl "$@"
+mtxrun --usekpse --execute makempy.pl "$@"
diff --git a/scripts/context/stubs/unix/metatex b/scripts/context/stubs/unix/metatex
new file mode 100755
index 000000000..f0c6b65d4
--- /dev/null
+++ b/scripts/context/stubs/unix/metatex
@@ -0,0 +1,2 @@
+#!/bin/sh
+mtxrun --script metatex "$@"
diff --git a/scripts/context/stubs/unix/mpstools b/scripts/context/stubs/unix/mpstools
index b4c8f6345..1a64d90b0 100755
--- a/scripts/context/stubs/unix/mpstools
+++ b/scripts/context/stubs/unix/mpstools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart mpstools.rb "$@"
+mtxrun --usekpse --execute mpstools.rb "$@"
diff --git a/scripts/context/stubs/unix/mptopdf b/scripts/context/stubs/unix/mptopdf
index 980a3123d..f57a8b7a7 100755
--- a/scripts/context/stubs/unix/mptopdf
+++ b/scripts/context/stubs/unix/mptopdf
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart mptopdf.pl "$@"
+mtxrun --usekpse --execute mptopdf.pl "$@"
diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun
new file mode 100755
index 000000000..0af429bf1
--- /dev/null
+++ b/scripts/context/stubs/unix/mtxrun
@@ -0,0 +1,10190 @@
+#!/usr/bin/env texlua
+
+if not modules then modules = { } end modules ['mtxrun'] = {
+ version = 1.001,
+ comment = "runner, lua replacement for texmfstart.rb",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+
+-- one can make a stub:
+--
+-- #!/bin/sh
+-- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@"
+
+-- filename : mtxrun.lua
+-- comment : companion to context.tex
+-- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+-- copyright: PRAGMA ADE / ConTeXt Development Team
+-- license : see context related readme files
+
+-- This script is based on texmfstart.rb but does not use kpsewhich to
+-- locate files. Although kpse is a library it never came to opening up
+-- its interface to other programs (esp scripting languages) and so we
+-- do it ourselves. The lua variant evolved out of an experimental ruby
+-- one. Interesting is that using a scripting language instead of c does
+-- not have a speed penalty. Actually the lua variant is more efficient,
+-- especially when multiple calls to kpsewhich are involved. The lua
+-- library also gives way more control.
+
+-- to be done / considered
+--
+-- support for --exec or make it default
+-- support for jar files (or maybe not, never used, too messy)
+-- support for $RUBYINPUTS cum suis (if still needed)
+-- remember for subruns: _CTX_K_V_#{original}_
+-- remember for subruns: _CTX_K_S_#{original}_
+-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
+
+texlua = true
+
+-- begin library merge
+
+
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+function string:quote() -- we could use format("%q")
+ return '"' .. self:unquote() .. '"'
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+function string:strip()
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
+end
+
+function string:is_empty()
+ return not find(find,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, str:sub(index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. self.rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+local hash = { }
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return P(pattern)
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local newline = crlf + cr + lf
+local spacing = space^0 * newline
+
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return capture:match(self)
+end
+
+lpeg.linebyline = content -- better make a sublibrary
+
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, ipairs = type, next, tostring, ipairs
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+function table.one_entry(t)
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+function table.starts_at(t)
+ return ipairs(t,1)(t,0)
+end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete)
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end })
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ 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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data)
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+number = number or { }
+
+-- a,b,c,d,e,f = number.toset(100101)
+
+function number.toset(n)
+ return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+end
+
+function number.toevenhex(n)
+ local s = format("%X",n)
+ if #s % 2 == 0 then
+ return s
+ else
+ return "0" .. s
+ end
+end
+
+-- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- on
+--
+-- for i=1,1000000 do
+-- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- local a,b,c,d = number.toset(1234)
+-- local a,b,c = number.toset(123)
+-- end
+--
+-- of course dedicated "(.)(.)(.)(.)" matches are even faster
+
+local one = lpeg.C(1-lpeg.S(''))^1
+
+function number.toset(n)
+ return one:match(tostring(n))
+end
+
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+set = set or { }
+
+local nums = { }
+local tabs = { }
+local concat = table.concat
+
+set.create = table.tohash
+
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
+ end
+ end
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
+ end
+ return nums[s]
+ else
+ return 0
+ end
+end
+
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
+ end
+end
+
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
+end
+
+--~ local c = set.create{'aap','noot','mies'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ local c = set.create{'zus','wim','jet'}
+--~ local s = set.tonumber(c)
+--~ local t = set.totable(s)
+--~ print(t['aap'])
+--~ print(t['jet'])
+--~ print(set.contains(t,'jet'))
+--~ print(set.contains(t,'aap'))
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+function os.resultof(command)
+ return io.popen(command,"r"):read("*all")
+end
+
+if not os.exec then os.exec = os.execute end
+if not os.spawn then os.spawn = os.execute end
+
+--~ os.type : windows | unix (new, we already guessed os.platform)
+--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
+
+if not io.fileseparator then
+ if find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
+ else
+ io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
+ end
+end
+
+os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix"
+
+function os.launch(str)
+ if os.platform == "windows" then
+ os.execute("start " .. str) -- os.spawn ?
+ else
+ os.execute(str .. " &") -- os.spawn ?
+ end
+end
+
+if not os.setenv then
+ function os.setenv() return false end
+end
+
+if not os.times then
+ -- utime = user time
+ -- stime = system time
+ -- cutime = children user time
+ -- cstime = children system time
+ function os.times()
+ return {
+ utime = os.gettimeofday(), -- user
+ stime = 0, -- system
+ cutime = 0, -- children user
+ cstime = 0, -- children system
+ }
+ end
+end
+
+os.gettimeofday = os.gettimeofday or os.clock
+
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
+end
+
+--~ print(os.gettimeofday()-os.time())
+--~ os.sleep(1.234)
+--~ print (">>",os.runtime())
+--~ print(os.date("%H:%M:%S",os.gettimeofday()))
+--~ print(os.date("%H:%M:%S",os.time()))
+
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name)
+ return match(name,"^.+%.([^/\\]-)$") or ""
+end
+
+file.suffix = file.extname
+
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.join(...)
+ local pth = concat({...},"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ return (gsub(pth,"//+","/"))
+end
+
+function file.iswritable(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
+ return a and a.permissions:sub(2,2) == "w"
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and a.permissions:sub(1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+function file.split_path(str)
+ local t = { }
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
+ if name ~= "" then
+ t[#t+1] = gsub(name,"\001",":")
+ end
+ end
+ return t
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+function file.collapse_path(str)
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return pattern:match(name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = pattern:match(name)
+--~ if b then
+--~ return name:sub(a,b-2)
+--~ elseif a then
+--~ return name:sub(a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This also provides file checksums and checkers.
+
+local gsub, format, byte = string.gsub, string.format, string.byte
+
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
+ end
+end
+
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEX(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
+
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type = type
+local find, gmatch = string.find, string.gmatch
+
+dir = dir or { }
+
+-- optimizing for no string.find (*) does not save time
+
+local attributes = lfs.attributes
+local walkdir = lfs.dir
+
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
+ end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
+ end
+ end
+ end
+end
+
+dir.glob_pattern = glob_pattern
+
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
+
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
+
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
+ local t = t or { }
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
+ return t
+ else
+ return { }
+ end
+ end
+end
+
+dir.glob = glob
+
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
+
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
+ files[#files+1] = path .. "/" .. name
+ end
+ else
+ files[#files+1] = path .. "/" .. name
+ end
+ end
+ end
+ end
+ return files
+end
+
+dir.globfiles = globfiles
+
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
+
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
+
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
+
+local make_indeed = true -- false
+
+if string.find(os.getenv("PATH"),";") then
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
+ if first then
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
+ else
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
+ if first then
+ pth, drive = first .. middle, true
+ else
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
+ end
+ end
+ end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("a:"))
+--~ print(dir.mkdirs("a:/b/c"))
+--~ print(dir.mkdirs("a:b/c"))
+--~ print(dir.mkdirs("a:/bbb/c"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
+ end
+ lfs.chdir(d)
+ end
+ end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
+
+else
+
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
+ end
+ end
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ end
+ return pth, (lfs.isdir(pth) == true)
+ end
+
+--~ print(dir.mkdirs("","","a","c"))
+--~ print(dir.mkdirs("a"))
+--~ print(dir.mkdirs("/a/b/c"))
+--~ print(dir.mkdirs("/aaa/b/c"))
+--~ print(dir.mkdirs("//a/b/c"))
+--~ print(dir.mkdirs("///a/b/c"))
+--~ print(dir.mkdirs("a/bbb//ccc/"))
+
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
+ end
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
+ end
+
+end
+
+dir.makedirs = dir.mkdirs
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+function boolean.alwaystrue()
+ return true
+end
+
+function boolean.falsetrue()
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- hm, quite unreadable
+
+if not utils then utils = { } end
+if not utils.merger then utils.merger = { } end
+if not utils.lua then utils.lua = { } end
+
+utils.merger.m_begin = "begin library merge"
+utils.merger.m_end = "end library merge"
+utils.merger.pattern =
+ "%c+" ..
+ "%-%-%s+" .. utils.merger.m_begin ..
+ "%c+(.-)%c+" ..
+ "%-%-%s+" .. utils.merger.m_end ..
+ "%c+"
+
+function utils.merger._self_fake_()
+ return
+ "-- " .. "created merged file" .. "\n\n" ..
+ "-- " .. utils.merger.m_begin .. "\n\n" ..
+ "-- " .. utils.merger.m_end .. "\n\n"
+end
+
+function utils.report(...)
+ print(...)
+end
+
+utils.merger.strip_comment = true
+
+function utils.merger._self_load_(name)
+ local f, data = io.open(name), ""
+ if f then
+ utils.report("reading merge from %s",name)
+ data = f:read("*all")
+ f:close()
+ else
+ utils.report("unknown file to merge %s",name)
+ end
+ if data and utils.merger.strip_comment then
+ -- saves some 20K
+ data = data:gsub("%-%-~[^\n\r]*[\r\n]", "")
+ end
+ return data or ""
+end
+
+function utils.merger._self_save_(name, data)
+ if data ~= "" then
+ local f = io.open(name,'w')
+ if f then
+ utils.report("saving merge from %s",name)
+ f:write(data)
+ f:close()
+ end
+ end
+end
+
+function utils.merger._self_swap_(data,code)
+ if data ~= "" then
+ return (data:gsub(utils.merger.pattern, function(s)
+ return "\n\n" .. "-- "..utils.merger.m_begin .. "\n" .. code .. "\n" .. "-- "..utils.merger.m_end .. "\n\n"
+ end, 1))
+ else
+ return ""
+ end
+end
+
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
+function utils.merger._self_libs_(libs,list)
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
+ if type(libs) == 'string' then libs = { libs } end
+ if type(list) == 'string' then list = { list } end
+ local foundpath = nil
+ for _, lib in ipairs(libs) do
+ for _, pth in ipairs(list) do
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
+ else
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
+ end
+ end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
+ end
+ return table.concat(result, "\n\n")
+end
+
+function utils.merger.selfcreate(libs,list,target)
+ if target then
+ utils.merger._self_save_(
+ target,
+ utils.merger._self_swap_(
+ utils.merger._self_fake_(),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+ end
+end
+
+function utils.merger.selfmerge(name,libs,list,target)
+ utils.merger._self_save_(
+ target or name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ utils.merger._self_libs_(libs,list)
+ )
+ )
+end
+
+function utils.merger.selfclean(name)
+ utils.merger._self_save_(
+ name,
+ utils.merger._self_swap_(
+ utils.merger._self_load_(name),
+ ""
+ )
+ )
+end
+
+function utils.lua.compile(luafile, lucfile, cleanup, strip) -- defaults: cleanup=false strip=true
+ -- utils.report("compiling",luafile,"into",lucfile)
+ os.remove(lucfile)
+ local command = "-o " .. string.quote(lucfile) .. " " .. string.quote(luafile)
+ if strip ~= false then
+ command = "-s " .. command
+ end
+ local done = (os.spawn("texluac " .. command) == 0) or (os.spawn("luac " .. command) == 0)
+ if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then
+ -- utils.report("removing",luafile)
+ os.remove(luafile)
+ end
+ return done
+end
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-tab'] = {
+ 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"
+}
+
+--[[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
+parent access; a first version used different trickery but was less optimized to we
+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>
+--ldx]]--
+
+xml = xml or { }
+
+--~ local xml = xml
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, setmetatable = type, next, setmetatable
+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
+
+--[[ldx--
+<p>First a hack to enable namespace resolving. A namespace is characterized by
+a <l n='url'/>. The following function associates a namespace prefix with a
+pattern. We use <l n='lpeg'/>, which in this case is more than twice as fast as a
+find based solution where we loop over an array of patterns. Less code and
+much cleaner.</p>
+--ldx]]--
+
+xml.xmlns = xml.xmlns or { }
+
+local check = lpeg.P(false)
+local parse = check
+
+--[[ldx--
+<p>The next function associates a namespace prefix with an <l n='url'/>. This
+normally happens independent of parsing.</p>
+
+<typing>
+xml.registerns("mml","mathml")
+</typing>
+--ldx]]--
+
+function xml.registerns(namespace, pattern) -- pattern can be an lpeg
+ check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
+ parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+end
+
+--[[ldx--
+<p>The next function also registers a namespace, but this time we map a
+given namespace prefix onto a registered one, using the given
+<l n='url'/>. This used for attributes like <t>xmlns:m</t>.</p>
+
+<typing>
+xml.checkns("m","http://www.w3.org/mathml")
+</typing>
+--ldx]]--
+
+function xml.checkns(namespace,url)
+ local ns = parse:match(lower(url))
+ if ns and namespace ~= ns then
+ xml.xmlns[namespace] = ns
+ end
+end
+
+--[[ldx--
+<p>Next we provide a way to turn an <l n='url'/> into a registered
+namespace. This used for the <t>xmlns</t> attribute.</p>
+
+<typing>
+resolvedns = xml.resolvens("http://www.w3.org/mathml")
+</typing>
+
+This returns <t>mml</t>.
+--ldx]]--
+
+function xml.resolvens(url)
+ return parse:match(lower(url)) or ""
+end
+
+--[[ldx--
+<p>A namespace in an element can be remapped onto the registered
+one efficiently by using the <t>xml.xmlns</t> table.</p>
+--ldx]]--
+
+--[[ldx--
+<p>This version uses <l n='lpeg'/>. We follow the same approach as before, stack and top and
+such. This version is about twice as fast which is mostly due to the fact that
+we don't have to prepare the stream for cdata, doctype etc etc. This variant is
+is dedicated to Luigi Scarso, who challenged me with 40 megabyte <l n='xml'/> files that
+took 12.5 seconds to load (1.5 for file io and the rest for tree building). With
+the <l n='lpeg'/> implementation we got that down to less 7.3 seconds. Loading the 14
+<l n='context'/> interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.</p>
+
+<p>Next comes the parser. The rather messy doctype definition comes in many
+disguises so it is no surprice that later on have to dedicate quite some
+<l n='lpeg'/> code to it.</p>
+
+<typing>
+<!DOCTYPE Something PUBLIC "... ..." "..." [ ... ] >
+<!DOCTYPE Something PUBLIC "... ..." "..." >
+<!DOCTYPE Something SYSTEM "... ..." [ ... ] >
+<!DOCTYPE Something SYSTEM "... ..." >
+<!DOCTYPE Something [ ... ] >
+<!DOCTYPE Something >
+</typing>
+
+<p>The code may look a bit complex but this is mostly due to the fact that we
+resolve namespaces and attach metatables. There is only one public function:</p>
+
+<typing>
+local x = xml.convert(somestring)
+</typing>
+
+<p>An optional second boolean argument tells this function not to create a root
+element.</p>
+--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 mt = { __tostring = xml.text }
+
+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
+ end
+ if tag == "xmlns" then
+ xmlns[#xmlns+1] = resolvens(value)
+ at[tag] = value
+ elseif namespace == "xmlns" then
+ xml.checkns(tag,value)
+ at["xmlns:" .. tag] = value
+ else
+ at[tag] = value
+ end
+end
+
+local function add_begin(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ setmetatable(top, mt)
+ dt = top.dt
+ stack[#stack+1] = top
+ at = { }
+end
+
+local function add_end(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local toclose = remove(stack)
+ top = stack[#stack]
+ if #stack < 1 then
+ errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
+ elseif toclose.tg ~= tag then -- no namespace check
+ errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
+ end
+ dt = top.dt
+ dt[#dt+1] = toclose
+ dt[0] = top
+ 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)
+ else
+ dt[#dt+1] = text
+ end
+end
+
+local function add_special(what, spacing, text)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ if strip and (what == "@cm@" or what == "@dt@") then
+ -- forget it
+ else
+ dt[#dt+1] = { special=true, ns="", tg=what, dt={text} }
+ end
+end
+
+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 space = S(' \r\n\t')
+local open = P('<')
+local close = P('>')
+local squote = S("'")
+local dquote = S('"')
+local equal = P('=')
+local slash = P('/')
+local colon = P(':')
+local valid = R('az', 'AZ', '09') + S('_-.')
+local name_yes = C(valid^1) * colon * C(valid^1)
+local name_nop = C(P(true)) * C(valid^1)
+local name = name_yes + name_nop
+
+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 somespace = space^1
+local optionalspace = space^0
+
+local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
+local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
+local attributes = attribute^0
+
+local text = justtext / 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
+local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
+local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
+
+local begincomment = open * P("!--")
+local endcomment = P("--") * close
+local begininstruction = open * P("?")
+local endinstruction = P("?") * close
+local begincdata = open * P("![CDATA[")
+local endcdata = P("]]") * close
+
+local someinstruction = C((1 - endinstruction)^0)
+local somecomment = C((1 - endcomment )^0)
+local somecdata = C((1 - endcdata )^0)
+
+local function entity(k,v) entities[k] = v end
+
+local begindoctype = open * P("!DOCTYPE")
+local enddoctype = close
+local beginset = P("[")
+local endset = P("]")
+local doctypename = C((1-somespace)^0)
+local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close
+local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close
+local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace
+local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace
+local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset
+local simpledoctype = (1-close)^1 -- * balanced^0
+local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
+
+local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
+local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end
+local cdata = (spacing * begincdata * somecdata * endcdata ) / function(...) add_special("@cd@",...) end
+local doctype = (spacing * begindoctype * somedoctype * enddoctype ) / function(...) add_special("@dt@",...) end
+
+-- nicer but slower:
+--
+-- local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+-- local comment = (lpeg.Cc("@cm@") * spacing * begincomment * somecomment * endcomment ) / add_special
+-- 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
+
+-- 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",
+ 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,
+}
+
+-- todo: xml.new + properties like entities and strip and such (store in root)
+
+function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear)
+ strip = strip_cm_and_dt or xml.strip_cm_and_dt
+ stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
+ stack[#stack+1] = top
+ top.dt = { }
+ dt = top.dt
+ if not data or data == "" then
+ errorstr = "empty xml file"
+ elseif not grammar:match(data) then
+ errorstr = "invalid xml file"
+ else
+ errorstr = ""
+ end
+ if errorstr and errorstr ~= "" then
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
+ setmetatable(stack, mt)
+ if xml.error_handler then xml.error_handler("load",errorstr) end
+ else
+ result = stack[1]
+ end
+ if not no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
+ setmetatable(result, mt)
+ local rdt = result.dt
+ for k=1,#rdt do
+ local v = rdt[k]
+ if type(v) == "table" and not v.special then -- always table -)
+ result.ri = k -- rootindex
+ break
+ end
+ end
+ end
+ return result
+end
+
+--[[ldx--
+<p>Packaging data in an xml like table is done with the following
+function. Maybe it will go away (when not used).</p>
+--ldx]]--
+
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+end
+
+function xml.package(tag,attributes,data)
+ local ns, tg = tag:match("^(.-):?([^:]+)$")
+ local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
+ setmetatable(t, mt)
+ return t
+end
+
+function xml.is_valid(root)
+ return root and not root.error
+end
+
+xml.error_handler = (logs and logs.report) or (input and logs.report) or print
+
+--[[ldx--
+<p>We cannot load an <l n='lpeg'/> from a filehandle so we need to load
+the whole file first. The function accepts a string representing
+a filename or a file handle.</p>
+--ldx]]--
+
+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"))
+ f:close()
+ return root
+ else
+ return xml.convert("")
+ end
+ elseif filename then -- filehandle
+ return xml.convert(filename:read("*all"))
+ else
+ return xml.convert("")
+ end
+end
+
+--[[ldx--
+<p>When we inject new elements, we need to convert strings to
+valid trees, which is what the next function does.</p>
+--ldx]]--
+
+function xml.toxml(data)
+ if type(data) == "string" then
+ local root = { xml.convert(data,true) }
+ return (#root > 1 and root) or root[1]
+ else
+ return data
+ end
+end
+
+--[[ldx--
+<p>For copying a tree we use a dedicated function instead of the
+generic table copier. Since we know what we're dealing with we
+can speed up things a bit. The second argument is not to be used!</p>
+--ldx]]--
+
+function copy(old,tables)
+ if old then
+ tables = tables or { }
+ local new = { }
+ if not tables[old] then
+ tables[old] = new
+ end
+ for k,v in pairs(old) do
+ new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+xml.copy = copy
+
+--[[ldx--
+<p>In <l n='context'/> serializing the tree or parts of the tree is a major
+actitivity which is why the following function is pretty optimized resulting
+in a few more lines of code than needed. The variant that uses the formatting
+function for all components is about 15% slower than the concatinating
+alternative.</p>
+--ldx]]--
+
+-- todo: add <?xml version='1.0' standalone='yes'?> when not present
+
+local fallbackhandle = (tex and tex.sprint) or io.write
+
+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
+ local xc = xml.command
+ if xc then
+ xc(e,ec)
+ return
+ end
+ 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)
+ else
+ -- no need to handle any further
+ 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
+ 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
+ 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(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 .. ">")
+ 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
+ end
+ 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
+ end
+ end
+ elseif type(e) == "string" then
+ if textconverter then
+ handle(textconverter(e))
+ else
+ handle(e)
+ 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
+end
+
+xml.serialize = serialize
+
+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
+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]]--
+
+function xml.tostring(root) -- 25% overhead due to collecting
+ if root then
+ if type(root) == 'string' then
+ return root
+ elseif next(root) then -- next is faster than type (and >0 test)
+ local result = { }
+ serialize(root,function(s) result[#result+1] = s end)
+ return concat(result,"")
+ end
+ end
+ return ""
+end
+
+--[[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)
+ 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)
+ end
+ end
+ else
+ handle(e)
+ 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
+
+--[[ldx--
+<p>A few helpers:</p>
+--ldx]]--
+
+function xml.body(root)
+ return (root.ri and root.dt[root.ri]) or root
+end
+
+function xml.text(root)
+ return (root and xml.tostring(root)) or ""
+end
+
+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 ""
+ end
+end
+
+--[[ldx--
+<p>The next helper assigns a tree (or string). Usage:</p>
+
+<typing>
+dt[k] = xml.assign(root) or xml.assign(dt,k,root)
+</typing>
+--ldx]]--
+
+function xml.assign(dt,k,root)
+ if dt and k then
+ dt[k] = (type(root) == "table" and xml.body(root)) or root
+ return dt[k]
+ else
+ return xml.body(root)
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+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 = string.format, string.lower, string.gmatch, string.gsub, 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. Here we overload a previously defined
+function.</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
+
+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",
+ [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
+
+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_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)*")"}
+
+-- if we use a dedicated namespace then we don't need to pass rt and k
+
+local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
+ if expressions[t] then
+ if s then
+ return "expressions." .. t .. "(r,k," .. s ..")"
+ else
+ return "expressions." .. t .. "(r,k)"
+ end
+ else
+ return "expressions.error(" .. t .. ")"
+ end
+end
+
+local converter = lpeg.Cs ( (
+ lp_position +
+ lp_index +
+ lp_text + lp_name + -- fast one
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_attribute +
+ lp_lua_function +
+ lp_function +
+1 )^1 )
+
+-- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
+
+local template = [[
+ 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)
+ str = converter:match(str)
+ return str, loadstring(format(template,str))()
+end
+
+local map = { }
+
+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 is_eq = lbracket * atsign * name * eq * value * rbracket
+local is_ne = lbracket * atsign * name * ne * value * rbracket
+local is_attribute = lbracket * atsign * name * rbracket
+local is_value = lbracket * value * rbracket
+local is_number = lbracket * number * rbracket
+
+local nobracket = 1-(lbracket+rbracket) -- must be improved
+local is_expression = lbracket * C(((C(nobracket^1))/make_expression)) * rbracket
+
+local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
+
+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 = (period )
+local parent = (period * period ) / function( ) map[#map+1] = { 11 } end
+local subtreeroot = (slash + hat ) / function( ) map[#map+1] = { 12 } end
+local documentroot = (hat * hat ) / function( ) map[#map+1] = { 13 } end
+local any = (star ) / function( ) map[#map+1] = { 14 } end
+local many = (star * star ) / function( ) map[#map+1] = { 15 } end
+local initial = (hat * hat * hat ) / function( ) map[#map+1] = { 16 } end
+
+local match = (is_one ) / function(...) map[#map+1] = { 20, true , ... } end
+local match_one_of = (is_one_of ) / function(...) map[#map+1] = { 21, true , ... } end
+local dont_match = (is_none ) / function(...) map[#map+1] = { 20, false, ... } end
+local dont_match_one_of = (is_none_of ) / function(...) map[#map+1] = { 21, false, ... } end
+
+local match_and_eq = (is_one * is_eq ) / function(...) map[#map+1] = { 22, true , ... } end
+local match_and_ne = (is_one * is_ne ) / function(...) map[#map+1] = { 23, true , ... } end
+local dont_match_and_eq = (is_none * is_eq ) / function(...) map[#map+1] = { 22, false, ... } end
+local dont_match_and_ne = (is_none * is_ne ) / function(...) map[#map+1] = { 23, false, ... } end
+
+local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) map[#map+1] = { 24, true , ... } end
+local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) map[#map+1] = { 25, true , ... } end
+local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) map[#map+1] = { 24, false, ... } end
+local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) map[#map+1] = { 25, false, ... } end
+
+local has_attribute = (is_one * is_attribute) / function(...) map[#map+1] = { 27, true , ... } end
+local has_value = (is_one * is_value ) / function(...) map[#map+1] = { 28, true , ... } end
+local dont_has_attribute = (is_none * is_attribute) / function(...) map[#map+1] = { 27, false, ... } end
+local dont_has_value = (is_none * is_value ) / function(...) map[#map+1] = { 28, false, ... } end
+local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
+local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
+
+local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
+local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
+
+local self_expression = ( is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, true, "*", "*", ... } end
+local dont_self_expression = (exclam * is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, false, "*", "*", ... } end
+
+local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
+local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
+local crap = (1-slash)^1
+
+-- a few ugly goodies:
+
+local docroottag = P('^^') / function( ) map[#map+1] = { 12 } end
+local subroottag = P('^') / function( ) map[#map+1] = { 13 } end
+local roottag = P('root::') / function( ) map[#map+1] = { 12 } end
+local parenttag = P('parent::') / function( ) map[#map+1] = { 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 +
+ 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 +
+ has_attribute + has_value +
+ dont_match_one_of + match_one_of +
+ dont_match + match +
+ many + any +
+ crap + empty
+)
+
+local grammar = P { "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
+ map = { }
+ grammar:match(str)
+ if #map == 0 then
+ return true
+ else
+ 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
+ -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
+ map[2][1] = 29
+ return { map[2] }
+ end
+ if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
+ insert(map, 1, { 16 })
+ end
+ -- print(gsub(table.serialize(map),"[ \n]+"," "))
+ return map
+ end
+ end
+end
+
+local cache = { }
+
+function xml.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
+
+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 = xml.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(root,rootdt,k) then
+ return false
+ 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(root,rootdt,k) then
+ return false
+ 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 = 0
+ local hsh = { } -- this 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 == 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[5]]
+ elseif command == 28 then -- has value
+ 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
+ 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(root,rootdt,k) then
+ return false
+ end
+ break -- else loop
+ end
+ end
+ end
+ end
+ end
+ end
+ return true
+end
+
+xml.traverse = traverse
+
+--[[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]]--
+
+local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
+
+xml.filters = { }
+
+function xml.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 xml.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
+
+function xml.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 xml.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
+
+function xml.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 xml.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 xml.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 xml.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 xml.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 xml.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 ekat[gsub(arguments,"^([\"\'])(.*)%1$","%2")])) or ""
+end
+
+function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
+ local dtk, rt, dt, dk = xml.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 xml.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 xml.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] = ""
+ end
+ else
+ t[#t+1] = tx or ""
+ end
+ else
+ t[#t+1] = ""
+ end
+ end)
+ return t
+end
+
+function xml.collect_tags(root, pattern, nonamespace)
+ local t = { }
+ xml.traverse(root, xml.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
+
+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
+ local xi = xml.convert(data)
+ 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"..string.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")
+
+--~ 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)"))
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-ent'] = {
+ 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 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
+
+--[[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>
+--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)
+ local documententities = root.entities
+ local allentities = xml.entities
+ if documententities then
+ for k, v in next, documententities do
+ allentities[k] = v
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['lxml-mis'] = {
+ 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 = table.concat
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, gsub = string.format, string.gsub
+
+--[[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"..string.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)
+
+xml.escaped_pattern = escaped
+xml.unescaped_pattern = unescaped
+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
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- the <anonymous> tag is kind of generic and used for functions that are not
+-- bound to a variable, like node.new, node.copy etc (contrary to for instance
+-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
+
+debugger = debugger or { }
+
+local counters = { }
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
+
+-- one
+
+local function hook()
+ local f = getinfo(2,"f").func
+ local n = getinfo(2,"Sn")
+-- if n.what == "C" and n.name then print (n.namewhat .. ': ' .. n.name) end
+ if f then
+ local cf = counters[f]
+ if cf == nil then
+ counters[f] = 1
+ names[f] = n
+ else
+ counters[f] = cf + 1
+ end
+ end
+end
+local function getname(func)
+ local n = names[func]
+ if n then
+ if n.what == "C" then
+ return n.name or '<anonymous>'
+ else
+ -- source short_src linedefined what name namewhat nups func
+ local name = n.name or n.namewhat or n.what
+ if not name or name == "" then name = "?" end
+ return format("%s : %s : %s", n.short_src or "unknown source", n.linedefined or "--", name)
+ end
+ else
+ return "unknown"
+ end
+end
+function debugger.showstats(printer,threshold)
+ printer = printer or texio.write or print
+ threshold = threshold or 0
+ local total, grandtotal, functions = 0, 0, 0
+ printer("\n") -- ugly but ok
+ -- table.sort(counters)
+ for func, count in pairs(counters) do
+ if count > threshold then
+ local name = getname(func)
+ if not name:find("for generator") then
+ printer(format("%8i %s", count, name))
+ total = total + count
+ end
+ end
+ grandtotal = grandtotal + count
+ functions = functions + 1
+ end
+ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+end
+
+-- two
+
+--~ local function hook()
+--~ local n = getinfo(2)
+--~ if n.what=="C" and not n.name then
+--~ local f = tostring(debug.traceback())
+--~ local cf = counters[f]
+--~ if cf == nil then
+--~ counters[f] = 1
+--~ names[f] = n
+--~ else
+--~ counters[f] = cf + 1
+--~ end
+--~ end
+--~ end
+--~ function debugger.showstats(printer,threshold)
+--~ printer = printer or texio.write or print
+--~ threshold = threshold or 0
+--~ local total, grandtotal, functions = 0, 0, 0
+--~ printer("\n") -- ugly but ok
+--~ -- table.sort(counters)
+--~ for func, count in pairs(counters) do
+--~ if count > threshold then
+--~ printer(format("%8i %s", count, func))
+--~ total = total + count
+--~ end
+--~ grandtotal = grandtotal + count
+--~ functions = functions + 1
+--~ end
+--~ printer(format("functions: %s, total: %s, grand total: %s, threshold: %s\n", functions, total, grandtotal, threshold))
+--~ end
+
+-- rest
+
+function debugger.savestats(filename,threshold)
+ local f = io.open(filename,'w')
+ if f then
+ debugger.showstats(function(str) f:write(str) end,threshold)
+ f:close()
+ end
+end
+
+function debugger.enable()
+ debug.sethook(hook,"c")
+end
+
+function debugger.disable()
+ debug.sethook()
+--~ counters[debug.getinfo(2,"f").func] = nil
+end
+
+function debugger.tracing()
+ local n = tonumber(os.env['MTX.TRACE.CALLS']) or tonumber(os.env['MTX_TRACE_CALLS']) or 0
+ if n > 0 then
+ function debugger.tracing() return true end ; return true
+ else
+ function debugger.tracing() return false end ; return false
+ end
+end
+
+--~ debugger.enable()
+
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+--~ print(math.sin(1*.5))
+
+--~ debugger.disable()
+
+--~ print("")
+--~ debugger.showstats()
+--~ print("")
+--~ debugger.showstats(print,3)
+
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- A former version provided functionality for non embeded core
+-- scripts i.e. runtime library loading. Given the amount of
+-- Lua code we use now, this no longer makes sense. Much of this
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+local format = string.format
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
+
+-- dirty tricks
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
+
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
+
+if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
+if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index, argument in pairs(arg) do
+ if index > 0 then
+ local flag, value = argument:match("^%-+(.+)=(.-)$")
+ if flag then
+ arguments[flag] = string.unquote(value or "")
+ else
+ flag = argument:match("^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = { }
+ for _,v in pairs(table.sortedkeys(arguments)) do
+ sortedflags[#sortedflags+1] = "^" .. v
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for _,v in ipairs(sortedflags) do
+ if name:find(v) then
+ return arguments[v:sub(2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ for _,v in ipairs(environment.original_arguments) do
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ return a
+ elseif next(arg) then
+ local result = { }
+ for _,a in ipairs(arg) do -- ipairs 1 .. #n
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ a = a:gsub('"','\\"') -- tricky
+ if a:find(" ") then
+ result[#result+1] = a:quote()
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index, argument in ipairs(arg) do
+ if argument:find("^\"") then
+ newarg[#newarg+1] = argument:gsub("^\"","")
+ if not argument:find("\"$") then
+ instring = true
+ end
+ elseif argument:find("\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
+
+function environment.texfile(filename)
+ return resolvers.find_file(filename,'tex')
+end
+
+function environment.luafile(filename)
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
+end
+
+environment.loadedluacode = loadfile -- can be overloaded
+
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
+function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
+ filename = file.replacesuffix(filename, "lua")
+ local fullname = environment.luafile(filename)
+ if fullname and fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
+ return environment.loadedluacode(fullname)
+ else
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ return nil
+ end
+end
+
+-- the next ones can use the previous ones / combine
+
+function environment.loadluafile(filename, version)
+ local lucname, luaname, chunk
+ local basename = file.removesuffix(filename)
+ if basename == filename then
+ lucname, luaname = basename .. ".luc", basename .. ".lua"
+ else
+ lucname, luaname = nil, basename -- forced suffix
+ end
+ -- when not overloaded by explicit suffix we look for a luc file first
+ local fullname = (lucname and environment.luafile(lucname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ end
+ if chunk then
+ assert(chunk)()
+ if version then
+ -- we check of the version number of this chunk matches
+ local v = version -- can be nil
+ if modules and modules[filename] then
+ v = modules[filename].version -- new method
+ elseif versions and versions[filename] then
+ v = versions[filename] -- old method
+ end
+ if v == version then
+ return true
+ else
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
+ environment.loadluafile(filename)
+ end
+ else
+ return true
+ end
+ end
+ fullname = (luaname and environment.luafile(luaname)) or ""
+ if fullname ~= "" then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
+ chunk = loadfile(fullname) -- this way we don't need a file exists check
+ if not chunk then
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
+ else
+ assert(chunk)()
+ return true
+ end
+ end
+ return false
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "companion to luat-lib.tex",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ instance.variables[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
+
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
+ else
+ local binary = resolvers.ownbin
+ if os.platform == "windows" then
+ binary = file.replacesuffix(binary,"exe")
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
+ end
+ resolvers.ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
+ end
+ resolvers.ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
+ end
+ return resolvers.ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ local f = io.open(lname)
+ if f then -- this will go
+ f:close()
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
+ for k,v in pairs(c) do
+ if type(v) == 'string' then
+ local t = file.split_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return file.split_path(str)
+ end
+end
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h = { }, { }
+ for _,vv in ipairs(file.split_path(v)) do
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ for _, cnf in ipairs(instance.cnffiles) do
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(str)
+ else
+ return resolvers.expanded_path_list(tmp)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","+ readable: %s",name)
+ else
+ logs.report("fileio","- readable: %s", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local doscan, recurse
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist and not (done and not instance.allresults) and recurse then
+ -- compare list entries with permitted pattern
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
+ local expr = "^" .. pathname
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
+ end
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag]
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_verbose then
+ report('')
+ end
+ for _, file in ipairs(files) do
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for _,v in ipairs(result) do
+ report(v)
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in pairs(t) do -- pairs?
+ s[#s+1] = k .. "=" .. v
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ for _, hash in ipairs(instance.hashes) do
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in pairs(v) do -- ipairs?
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.</p>
+
+</code>
+TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
+</code>
+
+<p>Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.</p>
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ return loader()
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-res'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
+
+local upper, lower, gsub = string.upper, string.lower, string.gsub
+
+local prefixes = { }
+
+prefixes.environment = function(str)
+ return resolvers.clean_path(os.getenv(str) or os.getenv(upper(str)) or os.getenv(lower(str)) or "")
+end
+
+prefixes.relative = function(str,n)
+ if io.exists(str) then
+ -- nothing
+ elseif io.exists("./" .. str) then
+ str = "./" .. str
+ else
+ local p = "../"
+ for i=1,n or 2 do
+ if io.exists(p .. str) then
+ str = p .. str
+ break
+ else
+ p = p .. "../"
+ end
+ end
+ end
+ return resolvers.clean_path(str)
+end
+
+prefixes.locate = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path((fullname ~= "" and fullname) or str)
+end
+
+prefixes.filename = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.basename((fullname ~= "" and fullname) or str))
+end
+
+prefixes.pathname = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.dirname((fullname ~= "" and fullname) or str))
+end
+
+prefixes.env = prefixes.environment
+prefixes.rel = prefixes.relative
+prefixes.loc = prefixes.locate
+prefixes.kpse = prefixes.locate
+prefixes.full = prefixes.locate
+prefixes.file = prefixes.filename
+prefixes.path = prefixes.pathname
+
+local function _resolve_(method,target)
+ if prefixes[method] then
+ return prefixes[method](target)
+ else
+ return method .. ":" .. target
+ end
+end
+
+local function resolve(str)
+ if type(str) == "table" then
+ for k, v in pairs(str) do -- ipairs
+ str[k] = resolve(v) or v
+ end
+ elseif str and str ~= "" then
+ str = gsub(str,"([a-z]+):([^ \"\']*)",_resolve_)
+ end
+ return str
+end
+
+resolvers.resolve = resolve
+
+if os.uname then
+
+ for k, v in pairs(os.uname()) do
+ if not prefixes[k] then
+ prefixes[k] = function() return v end
+ end
+ end
+
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if table.is_empty(mountpaths) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if not table.is_empty(mountpaths) then
+ statistics.starttiming(resolvers.instance)
+ for k, root in pairs(mountpaths) do
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if line:find("^[%%#%-]") then -- or %W
+ -- skip
+ elseif line:find("^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-zip'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, find = string.format, string.find
+
+local trace_locating, trace_verbose = false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trace_verbose = v end)
+
+zip = zip or { }
+zip.archives = zip.archives or { }
+zip.registeredfiles = zip.registeredfiles or { }
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators
+
+local archives = zip.archives
+
+-- zip:///oeps.zip?name=bla/bla.tex
+-- zip:///oeps.zip?tree=tex/texmf-local
+
+local function validzip(str) -- todo: use url splitter
+ if not find(str,"^zip://") then
+ return "zip:///" .. str
+ else
+ return str
+ end
+end
+
+function zip.openarchive(name)
+ if not name or name == "" then
+ return nil
+ else
+ local arch = archives[name]
+ if not arch then
+ local full = resolvers.find_file(name) or ""
+ arch = (full ~= "" and zip.open(full)) or false
+ archives[name] = arch
+ end
+ return arch
+ end
+end
+
+function zip.closearchive(name)
+ if not name or (name == "" and archives[name]) then
+ zip.close(archives[name])
+ archives[name] = nil
+ end
+end
+
+-- zip:///texmf.zip?tree=/tex/texmf
+-- zip:///texmf.zip?tree=/tex/texmf-local
+-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
+
+function locators.zip(specification) -- where is this used? startup zips (untested)
+ specification = resolvers.splitmethod(specification)
+ local zipfile = specification.path
+ local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+ if trace_locating then
+ if zfile then
+ logs.report("fileio",'! zip locator, found: %s',specification.original)
+ else
+ logs.report("fileio",'? zip locator, not found: %s',specification.original)
+ end
+ end
+end
+
+function hashers.zip(tag,name)
+ if trace_verbose then
+ logs.report("fileio","loading zip file %s as %s",name,tag)
+ end
+ resolvers.usezipfile(format("%s?tree=%s",tag,name))
+end
+
+function concatinators.zip(tag,path,name)
+ if not path or path == "" then
+ return format('%s?name=%s',tag,name)
+ else
+ return format('%s?name=%s/%s',tag,path,name)
+ end
+end
+
+function resolvers.isreadable.zip(name)
+ return true
+end
+
+function finders.zip(specification,filetype)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'! zip finder, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ dfile = zfile:close()
+ if trace_locating then
+ logs.report("fileio",'+ zip finder, name: %s',q.name)
+ end
+ return specification.original
+ end
+ elseif trace_locating then
+ logs.report("fileio",'? zip finder, path %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip finder, name: %s',filename)
+ end
+ return unpack(finders.notfound)
+end
+
+function openers.zip(specification)
+ local zipspecification = resolvers.splitmethod(specification)
+ if zipspecification.path then
+ local q = url.query(zipspecification.query)
+ if q.name then
+ local zfile = zip.openarchive(zipspecification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',zipspecification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_open(specification)
+ return openers.text_opener(specification,dfile,'zip')
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path %s',zipspecification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip opener, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.zip(specification)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio",'+ zip loader, name: %s',filename)
+ end
+ local s = dfile:read("*all")
+ dfile:close()
+ return true, s, #s
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path: %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip loader, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+-- zip:///somefile.zip
+-- zip:///somefile.zip?tree=texmf-local -> mount
+
+function resolvers.usezipfile(zipname)
+ zipname = validzip(zipname)
+ if trace_locating then
+ logs.report("fileio",'! zip use, file: %s',zipname)
+ end
+ local specification = resolvers.splitmethod(zipname)
+ local zipfile = specification.path
+ if zipfile and not zip.registeredfiles[zipname] then
+ local tree = url.query(specification.query).tree or ""
+ if trace_locating then
+ logs.report("fileio",'! zip register, file: %s',zipname)
+ end
+ local z = zip.openarchive(zipfile)
+ if z then
+ local instance = resolvers.instance
+ if trace_locating then
+ logs.report("fileio","= zipfile, registering: %s",zipname)
+ end
+ statistics.starttiming(instance)
+ resolvers.prepend_hash('zip',zipname,zipfile)
+ resolvers.extend_texmf_var(zipname) -- resets hashes too
+ zip.registeredfiles[zipname] = z
+ instance.files[zipname] = resolvers.register_zip_file(z,tree or "")
+ statistics.stoptiming(instance)
+ elseif trace_locating then
+ logs.report("fileio","? zipfile, unknown: %s",zipname)
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! zip register, no file: %s',zipname)
+ end
+end
+
+function resolvers.register_zip_file(z,tree)
+ local files, filter = { }, ""
+ if tree == "" then
+ filter = "^(.+)/(.-)$"
+ else
+ filter = format("^%s/(.+)/(.-)$",tree)
+ end
+ if trace_locating then
+ logs.report("fileio",'= zip filter: %s',filter)
+ end
+ local register, n = resolvers.register_file, 0
+ for i in z:files() do
+ local path, name = i.filename:match(filter)
+ if path then
+ if name and name ~= '' then
+ register(files, name, path)
+ n = n + 1
+ else
+ -- directory
+ end
+ else
+ register(files, i.filename, '')
+ n = n + 1
+ end
+ end
+ logs.report("fileio",'= zip entries: %s',n)
+ return files
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-crl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+curl = curl or { }
+
+curl.cached = { }
+curl.cachepath = caches.definepath("curl")
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function curl.fetch(protocol, name)
+ local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-")
+-- cachename = cachename:gsub("[\\/]", io.fileseparator)
+ cachename = cachename:gsub("[\\]", "/") -- cleanup
+ if not curl.cached[name] then
+ if not io.exists(cachename) then
+ curl.cached[name] = cachename
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+ end
+ if io.exists(cachename) then
+ curl.cached[name] = cachename
+ else
+ curl.cached[name] = ""
+ end
+ end
+ return curl.cached[name]
+end
+
+function finders.curl(protocol,filename)
+ local foundname = curl.fetch(protocol, filename)
+ return finders.generic(protocol,foundname,filetype)
+end
+
+function openers.curl(protocol,filename)
+ return openers.generic(protocol,filename)
+end
+
+function loaders.curl(protocol,filename)
+ return loaders.generic(protocol,filename)
+end
+
+-- todo: metamethod
+
+function curl.install(protocol)
+ finders[protocol] = function (filename,filetype) return finders.curl(protocol,filename) end
+ openers[protocol] = function (filename) return openers.curl(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.curl(protocol,filename) end
+end
+
+curl.install('http')
+curl.install('https')
+curl.install('ftp')
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['data-tmf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- loads *.tmf files in minimal tree roots (to be optimized and documented)
+
+function resolvers.check_environment(tree)
+ logs.simpleline()
+ os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
+ os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+ os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
+ os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
+ logs.simpleline()
+ logs.simple("preset : TEXPATH => %s", os.getenv('TEXPATH'))
+ logs.simple("preset : TEXOS => %s", os.getenv('TEXOS'))
+ logs.simple("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
+ logs.simple("preset : TMP => %s", os.getenv('TMP'))
+ logs.simple('')
+end
+
+function resolvers.load_environment(name) -- todo: key=value as well as lua
+ local f = io.open(name)
+ if f then
+ for line in f:lines() do
+ if line:find("^[%%%#]") then
+ -- skip comment
+ else
+ local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ os.setenv(key,value)
+ elseif how == "?" or how == "??" then
+ os.setenv(key,os.getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if os.getenv(key) then
+ os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
+ else
+ os.setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if os.getenv(key) then
+ os.setenv(key,value .. io.pathseparator .. os.getenv(key))
+ else
+ os.setenv(key,value)
+ end
+ end
+ end
+ end
+ end
+ f:close()
+ end
+end
+
+function resolvers.load_tree(tree)
+ if tree and tree ~= "" then
+ local setuptex = 'setuptex.tmf'
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
+ setuptex = tree .. "/" .. setuptex
+ else
+ setuptex = tree
+ end
+ if io.exists(setuptex) then
+ resolvers.check_environment(tree)
+ resolvers.load_environment(setuptex)
+ end
+ end
+end
+
+
+end -- of closure
+
+do -- create closure to overcome 200 locals limit
+
+if not modules then modules = { } end modules ['luat-sta'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code is used in the updater
+
+states = states or { }
+states.data = states.data or { }
+states.hash = states.hash or { }
+states.tag = states.tag or ""
+states.filename = states.filename or ""
+
+function states.save(filename,tag)
+ tag = tag or states.tag
+ filename = file.addsuffix(filename or states.filename,'lus')
+ io.savedata(filename,
+ "-- generator : luat-sta.lua\n" ..
+ "-- state tag : " .. tag .. "\n\n" ..
+ table.serialize(states.data[tag or states.tag] or {},true)
+ )
+end
+
+function states.load(filename,tag)
+ states.filename = filename
+ states.tag = tag or "whatever"
+ states.filename = file.addsuffix(states.filename,'lus')
+ states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { }
+end
+
+function states.set_by_tag(tag,key,value,default,persistent)
+ local d, h = states.data[tag], states.hash[tag]
+ if d then
+ if type(d) == "table" then
+ local dkey, hkey = key, key
+ local pre, post = key:match("(.+)%.([^%.]+)$")
+ if pre and post then
+ for k in pre:gmatch("[^%.]+") do
+ local dk = d[k]
+ if not dk then
+ dk = { }
+ d[k] = dk
+ end
+ d = dk
+ end
+ dkey, hkey = post, key
+ end
+ if type(value) == nil then
+ value = value or default
+ elseif persistent then
+ value = value or d[dkey] or default
+ else
+ value = value or default
+ end
+ d[dkey], h[hkey] = value, value
+ elseif type(d) == "string" then
+ -- weird
+ states.data[tag], states.hash[tag] = value, value
+ end
+ end
+end
+
+function states.get_by_tag(tag,key,default)
+ local h = states.hash[tag]
+ if h and h[key] then
+ return h[key]
+ else
+ local d = states.data[tag]
+ if d then
+ for k in key:gmatch("[^%.]+") do
+ local dk = d[k]
+ if dk then
+ d = dk
+ else
+ return default
+ end
+ end
+ return d or default
+ end
+ end
+end
+
+function states.set(key,value,default,persistent)
+ states.set_by_tag(states.tag,key,value,default,persistent)
+end
+
+function states.get(key,default)
+ return states.get_by_tag(states.tag,key,default)
+end
+
+--~ states.data.update = {
+--~ ["version"] = {
+--~ ["major"] = 0,
+--~ ["minor"] = 1,
+--~ },
+--~ ["rsync"] = {
+--~ ["server"] = "contextgarden.net",
+--~ ["module"] = "minimals",
+--~ ["repository"] = "current",
+--~ ["flags"] = "-rpztlv --stats",
+--~ },
+--~ ["tasks"] = {
+--~ ["update"] = true,
+--~ ["make"] = true,
+--~ ["delete"] = false,
+--~ },
+--~ ["platform"] = {
+--~ ["host"] = true,
+--~ ["other"] = {
+--~ ["mswin"] = false,
+--~ ["linux"] = false,
+--~ ["linux-64"] = false,
+--~ ["osx-intel"] = false,
+--~ ["osx-ppc"] = false,
+--~ ["sun"] = false,
+--~ },
+--~ },
+--~ ["context"] = {
+--~ ["available"] = {"current", "beta", "alpha", "experimental"},
+--~ ["selected"] = "current",
+--~ },
+--~ ["formats"] = {
+--~ ["cont-en"] = true,
+--~ ["cont-nl"] = true,
+--~ ["cont-de"] = false,
+--~ ["cont-cz"] = false,
+--~ ["cont-fr"] = false,
+--~ ["cont-ro"] = false,
+--~ },
+--~ ["engine"] = {
+--~ ["pdftex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["pdftex"] = true,
+--~ },
+--~ },
+--~ ["luatex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ },
+--~ },
+--~ ["xetex"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["xetex"] = false,
+--~ },
+--~ },
+--~ ["metapost"] = {
+--~ ["install"] = true,
+--~ ["formats"] = {
+--~ ["mpost"] = true,
+--~ ["metafun"] = true,
+--~ },
+--~ },
+--~ },
+--~ ["fonts"] = {
+--~ },
+--~ ["doc"] = {
+--~ },
+--~ ["modules"] = {
+--~ ["f-urwgaramond"] = false,
+--~ ["f-urwgothic"] = false,
+--~ ["t-bnf"] = false,
+--~ ["t-chromato"] = false,
+--~ ["t-cmscbf"] = false,
+--~ ["t-cmttbf"] = false,
+--~ ["t-construction-plan"] = false,
+--~ ["t-degrade"] = false,
+--~ ["t-french"] = false,
+--~ ["t-lettrine"] = false,
+--~ ["t-lilypond"] = false,
+--~ ["t-mathsets"] = false,
+--~ ["t-tikz"] = false,
+--~ ["t-typearea"] = false,
+--~ ["t-vim"] = false,
+--~ },
+--~ }
+
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.set_by_tag("update","rsync.server","oeps")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+--~ states.save("teststate", "update")
+--~ states.load("teststate", "update")
+--~ print(states.get_by_tag("update","rsync.server","unknown"))
+
+
+end -- of closure
+-- end library merge
+
+own = { } -- not local
+
+own.libs = { -- todo: check which ones are really needed
+ 'l-string.lua',
+ 'l-lpeg.lua',
+ 'l-table.lua',
+ 'l-io.lua',
+ 'l-number.lua',
+ 'l-set.lua',
+ 'l-os.lua',
+ 'l-file.lua',
+ 'l-md5.lua',
+ 'l-dir.lua',
+ 'l-boolean.lua',
+ 'l-math.lua',
+-- 'l-unicode.lua',
+-- 'l-tex.lua',
+ 'l-utils.lua',
+-- 'l-xml.lua',
+ 'lxml-tab.lua',
+ 'lxml-pth.lua',
+ 'lxml-ent.lua',
+ 'lxml-mis.lua',
+ 'trac-tra.lua',
+ 'luat-env.lua',
+ 'trac-inf.lua',
+ 'trac-log.lua',
+ 'data-res.lua',
+ 'data-tmp.lua',
+ 'data-pre.lua',
+ 'data-inp.lua',
+ 'data-out.lua',
+ 'data-con.lua',
+ 'data-use.lua',
+-- 'data-tex.lua',
+-- 'data-bin.lua',
+ 'data-zip.lua',
+ 'data-crl.lua',
+-- 'data-lua.lua',
+ 'data-kps.lua', -- so that we can replace kpsewhich
+ 'data-aux.lua', -- updater
+ 'data-tmf.lua', -- tree files
+ -- needed ?
+ 'luat-sta.lua', -- states
+}
+
+-- We need this hack till luatex is fixed.
+--
+-- for k,v in pairs(arg) do print(k,v) end
+
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+-- End of hack.
+
+own.name = (environment and environment.ownname) or arg[0] or 'luatools.lua'
+
+own.path = string.match(own.name,"^(.+)[\\/].-$") or "."
+own.list = { '.' }
+if own.path ~= '.' then
+ table.insert(own.list,own.path)
+end
+table.insert(own.list,own.path.."/../../../tex/context/base")
+table.insert(own.list,own.path.."/mtx")
+table.insert(own.list,own.path.."/../sources")
+
+local function locate_libs()
+ for _, lib in pairs(own.libs) do
+ for _, pth in pairs(own.list) do
+ local filename = string.gsub(pth .. "/" .. lib,"\\","/")
+ local codeblob = loadfile(filename)
+ if codeblob then
+ codeblob()
+ own.list = { pth } -- speed up te search
+ break
+ end
+ end
+ end
+end
+
+if not resolvers then
+ locate_libs()
+end
+
+if not resolvers then
+ print("")
+ print("Mtxrun is unable to start up due to lack of libraries. You may")
+ print("try to run 'lua mtxrun.lua --selfmerge' in the path where this")
+ print("script is located (normally under ..../scripts/context/lua) which")
+ print("will make this script library independent.")
+ os.exit()
+end
+
+logs.setprogram('MTXrun',"TDS Runner Tool 1.22",environment.arguments["verbose"] or false)
+
+local instance = resolvers.reset()
+
+runners = runners or { } -- global
+messages = messages or { }
+
+messages.help = [[
+--script run an mtx script (--noquotes)
+--execute run a script or program (--noquotes)
+--resolve resolve prefixed arguments
+--ctxlua run internally (using preloaded libs)
+--locate locate given filename
+
+--autotree use texmf tree cf. env 'texmfstart_tree' or 'texmfstarttree'
+--tree=pathtotree use given texmf tree (default file: 'setuptex.tmf')
+--environment=name use given (tmf) environment file
+--path=runpath go to given path before execution
+--ifchanged=filename only execute when given file has changed (md checksum)
+--iftouched=old,new only execute when given file has changed (time stamp)
+
+--make create stubs for (context related) scripts
+--remove remove stubs (context related) scripts
+--stubpath=binpath paths where stubs wil be written
+--windows create windows (mswin) stubs
+--unix create unix (linux) stubs
+
+--verbose give a bit more info
+--engine=str target engine
+--progname=str format or backend
+
+--edit launch editor with found file
+--launch (--all) launch files like manuals, assumes os support
+
+--intern run script using built in libraries
+
+--usekpse use kpse as fallback (when no mkiv and cache installed, often slower)
+--forcekpse force using kpse (handy when no mkiv and cache installed but less functionality)
+]]
+
+runners.applications = {
+ ["lua"] = "luatex --luaonly",
+ ["luc"] = "luatex --luaonly",
+ ["pl"] = "perl",
+ ["py"] = "python",
+ ["rb"] = "ruby",
+}
+
+runners.suffixes = {
+ 'rb', 'lua', 'py', 'pl'
+}
+
+runners.registered = {
+ texexec = { 'texexec.rb', true }, -- context mkii runner (only tool not to be luafied)
+ texutil = { 'texutil.rb', true }, -- old perl based index sorter for mkii (old versions need it)
+ texfont = { 'texfont.pl', true }, -- perl script that makes mkii font metric files
+ texfind = { 'texfind.pl', false }, -- perltk based tex searching tool, mostly used at pragma
+ texshow = { 'texshow.pl', false }, -- perltk based context help system, will be luafied
+ -- texwork = { \texwork.pl', false }, -- perltk based editing environment, only used at pragma
+
+ makempy = { 'makempy.pl', true },
+ mptopdf = { 'mptopdf.pl', true },
+ pstopdf = { 'pstopdf.rb', true }, -- converts ps (and some more) images, does some cleaning (replaced)
+
+-- examplex = { 'examplex.rb', false },
+ concheck = { 'concheck.rb', false },
+
+ runtools = { 'runtools.rb', true },
+ textools = { 'textools.rb', true },
+ tmftools = { 'tmftools.rb', true },
+ ctxtools = { 'ctxtools.rb', true },
+ rlxtools = { 'rlxtools.rb', true },
+ pdftools = { 'pdftools.rb', true },
+ mpstools = { 'mpstools.rb', true },
+-- exatools = { 'exatools.rb', true },
+ xmltools = { 'xmltools.rb', true },
+-- luatools = { 'luatools.lua', true },
+ mtxtools = { 'mtxtools.rb', true },
+
+ pdftrimwhite = { 'pdftrimwhite.pl', false }
+}
+
+runners.launchers = {
+ windows = { },
+ unix = { }
+}
+
+function runners.prepare()
+ local checkname = environment.argument("ifchanged")
+ if checkname and checkname ~= "" then
+ local oldchecksum = file.loadchecksum(checkname)
+ local newchecksum = file.checksum(checkname)
+ if oldchecksum == newchecksum then
+ logs.simple("file '%s' is unchanged",checkname)
+ return "skip"
+ else
+ logs.simple("file '%s' is changed, processing started",checkname)
+ end
+ file.savechecksum(checkname)
+ end
+ local oldname, newname = string.split(environment.argument("iftouched") or "", ",")
+ if oldname and newname and oldname ~= "" and newname ~= "" then
+ if not file.needs_updating(oldname,newname) then
+ logs.simple("file '%s' and '%s' have same age",oldname,newname)
+ return "skip"
+ else
+ logs.simple("file '%s' is older than '%s'",oldname,newname)
+ end
+ end
+ local tree = environment.argument('tree') or ""
+ if environment.argument('autotree') then
+ tree = os.getenv('TEXMFSTART_TREE') or os.getenv('TEXMFSTARTTREE') or tree
+ end
+ if tree and tree ~= "" then
+ resolvers.load_tree(tree)
+ end
+ local env = environment.argument('environment') or ""
+ if env and env ~= "" then
+ for _,e in pairs(string.split(env)) do
+ -- maybe force suffix when not given
+ resolvers.load_tree(e)
+ end
+ end
+ local runpath = environment.argument("path")
+ if runpath and not lfs.chdir(runpath) then
+ logs.simple("unable to change to path '%s'",runpath)
+ return "error"
+ end
+ return "run"
+end
+
+function runners.execute_script(fullname,internal)
+ local noquote = environment.argument("noquotes")
+ if fullname and fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ instance.progname = environment.argument("progname") or instance.progname
+ instance.format = environment.argument("format") or instance.format
+ local path, name, suffix, result = file.dirname(fullname), file.basename(fullname), file.extname(fullname), ""
+ if path ~= "" then
+ result = fullname
+ elseif name then
+ name = name:gsub("^int[%a]*:",function()
+ internal = true
+ return ""
+ end )
+ name = name:gsub("^script:","")
+ if suffix == "" and runners.registered[name] and runners.registered[name][1] then
+ name = runners.registered[name][1]
+ suffix = file.extname(name)
+ end
+ if suffix == "" then
+ -- loop over known suffixes
+ for _,s in pairs(runners.suffixes) do
+ result = resolvers.find_file(name .. "." .. s, 'texmfscripts')
+ if result ~= "" then
+ break
+ end
+ end
+ elseif runners.applications[suffix] then
+ result = resolvers.find_file(name, 'texmfscripts')
+ else
+ -- maybe look on path
+ result = resolvers.find_file(name, 'other text files')
+ end
+ end
+ if result and result ~= "" then
+ local before, after = environment.split_arguments(fullname) -- already done
+ environment.arguments_before, environment.arguments_after = before, after
+ if internal then
+ arg = { } for _,v in pairs(after) do arg[#arg+1] = v end
+ dofile(result)
+ else
+ local binary = runners.applications[file.extname(result)]
+ if binary and binary ~= "" then
+ result = binary .. " " .. result
+ end
+ local command = result .. " " .. environment.reconstruct_commandline(after,noquote)
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
+ io.flush()
+ end
+ local code = os.exec(command) -- maybe spawn
+ return code == 0
+ end
+ end
+ end
+ end
+ return false
+end
+
+function runners.execute_program(fullname)
+ local noquote = environment.argument("noquotes")
+ if fullname and fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ local before, after = environment.split_arguments(fullname)
+ environment.initialize_arguments(after)
+ fullname = fullname:gsub("^bin:","")
+ local command = fullname .. " " .. (environment.reconstruct_commandline(after or "",noquote) or "")
+ logs.simpleline()
+ logs.simple("executing: %s",command)
+ logs.simpleline()
+ logs.simpleline()
+ io.flush()
+ local code = os.exec(command) -- (fullname,unpack(after)) does not work / maybe spawn
+ return code == 0
+ end
+ end
+ return false
+end
+
+-- the --usekpse flag will fallback on kpse
+
+local windows_stub = '@echo off\013\010setlocal\013\010set ownpath=%%~dp0%%\013\010texlua "%%ownpath%%mtxrun.lua" --usekpse --execute %s %%*\013\010endlocal\013\010'
+local unix_stub = '#!/bin/sh\010mtxrun --usekpse --execute %s \"$@\"\010'
+
+function runners.handle_stubs(create)
+ local stubpath = environment.argument('stubpath') or '.' -- 'auto' no longer subpathssupported
+ local windows = environment.argument('windows') or environment.argument('mswin') or false
+ local unix = environment.argument('unix') or environment.argument('linux') or false
+ if not windows and not unix then
+ if os.platform == "unix" then
+ unix = true
+ else
+ windows = true
+ end
+ end
+ for _,v in pairs(runners.registered) do
+ local name, doit = v[1], v[2]
+ if doit then
+ local base = string.gsub(file.basename(name), "%.(.-)$", "")
+ if create then
+ if windows then
+ io.savedata(file.join(stubpath,base..".bat"),string.format(windows_stub,name))
+ logs.simple("windows stub for '%s' created",base)
+ end
+ if unix then
+ io.savedata(file.join(stubpath,base),string.format(unix_stub,name))
+ logs.simple("unix stub for '%s' created",base)
+ end
+ else
+ if windows and (os.remove(file.join(stubpath,base..'.bat')) or os.remove(file.join(stubpath,base..'.cmd'))) then
+ logs.simple("windows stub for '%s' removed", base)
+ end
+ if unix and (os.remove(file.join(stubpath,base)) or os.remove(file.join(stubpath,base..'.sh'))) then
+ logs.simple("unix stub for '%s' removed",base)
+ end
+ end
+ end
+ end
+end
+
+function runners.resolve_string(filename)
+ if filename and filename ~= "" then
+ runners.report_location(resolvers.resolve(filename))
+ end
+end
+
+function runners.locate_file(filename)
+ -- differs from texmfstart where locate appends .com .exe .bat ... todo
+ if filename and filename ~= "" then
+ runners.report_location(resolvers.find_given_file(filename))
+ end
+end
+
+function runners.locate_platform()
+ runners.report_location(os.currentplatform())
+end
+
+function runners.report_location(result)
+ if logs.verbose then
+ logs.simpleline()
+ if result and result ~= "" then
+ logs.simple(result)
+ else
+ logs.simple("not found")
+ end
+ else
+ io.write(result)
+ end
+end
+
+function runners.edit_script(filename) -- we assume that vim is present on most systems
+ local editor = os.getenv("MTXRUN_EDITOR") or os.getenv("TEXMFSTART_EDITOR") or os.getenv("EDITOR") or 'vim'
+ local rest = resolvers.resolve(filename)
+ if rest ~= "" then
+ local command = editor .. " " .. rest
+ if logs.verbose then
+ logs.simpleline()
+ logs.simple("starting editor: %s",command)
+ logs.simple_line()
+ logs.simple_line()
+ end
+ os.launch(command)
+ end
+end
+
+function runners.save_script_session(filename, list)
+ local t = { }
+ for _, key in ipairs(list) do
+ t[key] = environment.arguments[key]
+ end
+ io.savedata(filename,table.serialize(t,true))
+end
+
+function runners.load_script_session(filename)
+ if lfs.isfile(filename) then
+ local t = io.loaddata(filename)
+ if t then
+ t = loadstring(t)
+ if t then t = t() end
+ for key, value in pairs(t) do
+ environment.arguments[key] = value
+ end
+ end
+ end
+end
+
+function resolvers.launch(str)
+ -- maybe we also need to test on mtxrun.launcher.suffix environment
+ -- variable or on windows consult the assoc and ftype vars and such
+ local launchers = runners.launchers[os.platform] if launchers then
+ local suffix = file.extname(str) if suffix then
+ local runner = launchers[suffix] if runner then
+ str = runner .. " " .. str
+ end
+ end
+ end
+ os.launch(str)
+end
+
+function runners.launch_file(filename)
+ instance.allresults = true
+ logs.setverbose(true)
+ local pattern = environment.arguments["pattern"]
+ if not pattern or pattern == "" then
+ pattern = filename
+ end
+ if not pattern or pattern == "" then
+ logs.simple("provide name or --pattern=")
+ else
+ local t = resolvers.find_files(pattern)
+ if not t or #t == 0 then
+ t = resolvers.find_files("*/" .. pattern)
+ end
+ if not t or #t == 0 then
+ t = resolvers.find_files("*/" .. pattern .. "*")
+ end
+ if t and #t > 0 then
+ if environment.arguments["all"] then
+ for _, v in pairs(t) do
+ logs.simple("launching %s", v)
+ resolvers.launch(v)
+ end
+ else
+ logs.simple("launching %s", t[1])
+ resolvers.launch(t[1])
+ end
+ else
+ logs.simple("no match for %s", pattern)
+ end
+ end
+end
+
+function runners.find_mtx_script(filename)
+ local function found(name)
+ local path = file.dirname(name)
+ if path and path ~= "" then
+ return false
+ else
+ local fullname = own and own.path and file.join(own.path,name)
+ return io.exists(fullname) and fullname
+ end
+ end
+ filename = file.addsuffix(filename,"lua")
+ local basename = file.removesuffix(file.basename(filename))
+ local suffix = file.extname(filename)
+ -- qualified path, raw name
+ local fullname = file.is_qualified_path(filename) and io.exists(filename) and filename
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- current path, raw name
+ fullname = "./" .. filename
+ fullname = io.exists(fullname) and fullname
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename>
+ fullname = "mtx-" .. filename
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename>s
+ fullname = "mtx-" .. basename .. "s" .. "." .. suffix
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, mtx-<filename minus trailing s>
+ fullname = "mtx-" .. basename:gsub("s$","") .. "." .. suffix
+ fullname = found(fullname) or resolvers.find_file(fullname)
+ if fullname and fullname ~= "" then
+ return fullname
+ end
+ -- context namespace, just <filename>
+ fullname = resolvers.find_file(filename)
+ return fullname
+end
+
+function runners.execute_ctx_script(filename,arguments)
+ local fullname = runners.find_mtx_script(filename) or ""
+ -- retyr after generate but only if --autogenerate
+ if fullname == "" and environment.argument("autogenerate") then -- might become the default
+ instance.renewcache = true
+ logs.setverbose(true)
+ resolvers.load()
+ --
+ fullname = runners.find_mtx_script(filename) or ""
+ end
+ -- that should do it
+ if fullname ~= "" then
+ local state = runners.prepare()
+ if state == 'error' then
+ return false
+ elseif state == 'skip' then
+ return true
+ elseif state == "run" then
+ -- load and save ... kind of undocumented
+ arg = { } for _,v in pairs(arguments) do arg[#arg+1] = resolvers.resolve(v) end
+ environment.initialize_arguments(arg)
+ local loadname = environment.arguments['load']
+ if loadname then
+ if type(loadname) ~= "string" then loadname = file.basename(fullname) end
+ loadname = file.replacesuffix(loadname,"cfg")
+ runners.load_script_session(loadname)
+ end
+ filename = environment.files[1]
+ if logs.verbose then
+ logs.simple("using script: %s\n",fullname)
+ end
+ dofile(fullname)
+ local savename = environment.arguments['save']
+ if savename and runners.save_list and not table.is_empty(runners.save_list or { }) then
+ if type(savename) ~= "string" then savename = file.basename(fullname) end
+ savename = file.replacesuffix(savename,"cfg")
+ runners.save_script_session(savename, runners.save_list)
+ end
+ return true
+ end
+ else
+ logs.setverbose(true)
+ filename = file.addsuffix(filename,"lua")
+ if filename == "" then
+ logs.simple("unknown script, no name given")
+ elseif file.is_qualified_path(filename) then
+ logs.simple("unknown script '%s'",filename)
+ else
+ logs.simple("unknown script '%s' or 'mtx-%s'",filename,filename)
+ end
+ return false
+ end
+end
+
+function runners.timed(action)
+ statistics.timed(action)
+end
+
+-- this is a bit dirty ... first we store the first filename and next we
+-- split the arguments so that we only see the ones meant for this script
+-- ... later we will use the second half
+
+local filename = environment.files[1] or ""
+local ok = true
+
+local before, after = environment.split_arguments(filename)
+environment.arguments_before, environment.arguments_after = before, after
+environment.initialize_arguments(before)
+
+instance.engine = environment.argument("engine") or 'luatex'
+instance.progname = environment.argument("progname") or 'context'
+instance.lsrmode = environment.argument("lsr") or false
+
+-- maybe the unset has to go to this level
+
+if environment.argument("usekpse") or environment.argument("forcekpse") then
+
+ os.setenv("engine","")
+ os.setenv("progname","")
+
+ local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ pfb = "type1 fonts",
+ other = "other text files",
+ }
+
+ local function kpse_initialized()
+ texconfig.kpse_init = true
+ local t = os.clock()
+ local k = kpse.original.new("luatex",instance.progname)
+ local dummy = k:find_file("mtxrun.lua") -- so that we're initialized
+ logs.simple("kpse fallback with progname '%s' initialized in %s seconds",instance.progname,os.clock()-t)
+ kpse_initialized = function() return k end
+ return k
+ end
+
+ local find_file = resolvers.find_file
+ local show_path = resolvers.show_path
+
+ if environment.argument("forcekpse") then
+
+ function resolvers.find_file(name,kind)
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ function resolvers.show_path(name)
+ return (kpse_initialized():show_path(name)) or ""
+ end
+
+ elseif environment.argument("usekpse") then
+
+ resolvers.load()
+
+ function resolvers.find_file(name,kind)
+ local found = find_file(name,kind) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():find_file(resolvers.clean_path(name),(kind ~= "" and (remapper[kind] or kind)) or "tex") or "") or ""
+ end
+ end
+ function resolvers.show_path(name)
+ local found = show_path(name) or ""
+ if found ~= "" then
+ return found
+ else
+ return (kpse_initialized():show_path(name)) or ""
+ end
+ end
+
+ end
+
+else
+
+ resolvers.load()
+
+end
+
+
+if environment.argument("selfmerge") then
+ -- embed used libraries
+ utils.merger.selfmerge(own.name,own.libs,own.list)
+elseif environment.argument("selfclean") then
+ -- remove embedded libraries
+ utils.merger.selfclean(own.name)
+elseif environment.argument("selfupdate") then
+ logs.setverbose(true)
+ resolvers.update_script(own.name,"mtxrun")
+elseif environment.argument("ctxlua") or environment.argument("internal") then
+ -- run a script by loading it (using libs)
+ ok = runners.execute_script(filename,true)
+elseif environment.argument("script") or environment.argument("s") then
+ -- run a script by loading it (using libs), pass args
+ ok = runners.execute_ctx_script(filename,after)
+elseif environment.argument("execute") then
+ -- execute script
+ ok = runners.execute_script(filename)
+elseif environment.argument("direct") then
+ -- equals bin:
+ ok = runners.execute_program(filename)
+elseif environment.argument("edit") then
+ -- edit file
+ runners.edit_script(filename)
+elseif environment.argument("launch") then
+ runners.launch_file(filename)
+elseif environment.argument("make") then
+ -- make stubs
+ runners.handle_stubs(true)
+elseif environment.argument("remove") then
+ -- remove stub
+ runners.handle_stubs(false)
+elseif environment.argument("resolve") then
+ -- resolve string
+ runners.resolve_string(filename)
+elseif environment.argument("locate") then
+ -- locate file
+ runners.locate_file(filename)
+elseif environment.argument("platform")then
+ -- locate platform
+ runners.locate_platform()
+elseif environment.argument("help") or filename=='help' or filename == "" then
+ logs.help(messages.help)
+ -- execute script
+elseif filename:find("^bin:") then
+ ok = runners.execute_program(filename)
+else
+ ok = runners.execute_script(filename)
+end
+
+if os.platform == "unix" then
+ io.write("\n")
+end
+
+if ok == false then ok = 1 elseif ok == true then ok = 0 end
+
+os.exit(ok)
diff --git a/scripts/context/stubs/unix/mtxtools b/scripts/context/stubs/unix/mtxtools
new file mode 100755
index 000000000..3803c1c6f
--- /dev/null
+++ b/scripts/context/stubs/unix/mtxtools
@@ -0,0 +1,2 @@
+#!/bin/sh
+mtxrun --usekpse --execute mtxtools.rb "$@"
diff --git a/scripts/context/stubs/unix/pdftools b/scripts/context/stubs/unix/pdftools
index 92ee803a8..da7bd64cf 100755
--- a/scripts/context/stubs/unix/pdftools
+++ b/scripts/context/stubs/unix/pdftools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart pdftools.rb "$@"
+mtxrun --usekpse --execute pdftools.rb "$@"
diff --git a/scripts/context/stubs/unix/pdftrimwhite b/scripts/context/stubs/unix/pdftrimwhite
deleted file mode 100755
index 00b5f525a..000000000
--- a/scripts/context/stubs/unix/pdftrimwhite
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-texmfstart pdftrimwhite.pl "$@"
diff --git a/scripts/context/stubs/unix/pstopdf b/scripts/context/stubs/unix/pstopdf
index 5b38ed426..059812cce 100755
--- a/scripts/context/stubs/unix/pstopdf
+++ b/scripts/context/stubs/unix/pstopdf
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart pstopdf.rb "$@"
+mtxrun --usekpse --execute pstopdf.rb "$@"
diff --git a/scripts/context/stubs/unix/rlxtools b/scripts/context/stubs/unix/rlxtools
index 41cea40fc..d01987b3c 100755
--- a/scripts/context/stubs/unix/rlxtools
+++ b/scripts/context/stubs/unix/rlxtools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart rlxtools.rb "$@"
+mtxrun --usekpse --execute rlxtools.rb "$@"
diff --git a/scripts/context/stubs/unix/runtools b/scripts/context/stubs/unix/runtools
index ff9a33379..e21c1a244 100755
--- a/scripts/context/stubs/unix/runtools
+++ b/scripts/context/stubs/unix/runtools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart runtools.rb "$@"
+mtxrun --usekpse --execute runtools.rb "$@"
diff --git a/scripts/context/stubs/unix/texexec b/scripts/context/stubs/unix/texexec
index 215817290..083e500c6 100755
--- a/scripts/context/stubs/unix/texexec
+++ b/scripts/context/stubs/unix/texexec
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart texexec.rb "$@"
+mtxrun --usekpse --execute texexec.rb "$@"
diff --git a/scripts/context/stubs/unix/texfind b/scripts/context/stubs/unix/texfind
deleted file mode 100755
index c054bdf52..000000000
--- a/scripts/context/stubs/unix/texfind
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-texmfstart texfind "$@"
diff --git a/scripts/context/stubs/unix/texfont b/scripts/context/stubs/unix/texfont
index a91f786e3..bc811a640 100755
--- a/scripts/context/stubs/unix/texfont
+++ b/scripts/context/stubs/unix/texfont
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart texfont.pl "$@"
+mtxrun --usekpse --execute texfont.pl "$@"
diff --git a/scripts/context/stubs/unix/texmfstart b/scripts/context/stubs/unix/texmfstart
new file mode 100755
index 000000000..1799b3579
--- /dev/null
+++ b/scripts/context/stubs/unix/texmfstart
@@ -0,0 +1,2 @@
+#!/bin/sh
+mtxrun --usekpse "$@"
diff --git a/scripts/context/stubs/unix/texshow b/scripts/context/stubs/unix/texshow
deleted file mode 100755
index afd62c339..000000000
--- a/scripts/context/stubs/unix/texshow
+++ /dev/null
@@ -1,2 +0,0 @@
-#!/bin/sh
-texmfstart texshow.pl "$@"
diff --git a/scripts/context/stubs/unix/textools b/scripts/context/stubs/unix/textools
index 7445eac37..76087ca57 100755
--- a/scripts/context/stubs/unix/textools
+++ b/scripts/context/stubs/unix/textools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart textools.rb "$@"
+mtxrun --usekpse --execute textools.rb "$@"
diff --git a/scripts/context/stubs/unix/texutil b/scripts/context/stubs/unix/texutil
index 607154af0..f5d9b6f1d 100755
--- a/scripts/context/stubs/unix/texutil
+++ b/scripts/context/stubs/unix/texutil
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart texutil.rb "$@"
+mtxrun --usekpse --execute texutil.rb "$@"
diff --git a/scripts/context/stubs/unix/tmftools b/scripts/context/stubs/unix/tmftools
index 7531a9663..48d32f0fd 100755
--- a/scripts/context/stubs/unix/tmftools
+++ b/scripts/context/stubs/unix/tmftools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart tmftools.rb "$@"
+mtxrun --usekpse --execute tmftools.rb "$@"
diff --git a/scripts/context/stubs/unix/xmltools b/scripts/context/stubs/unix/xmltools
index 03086d043..a673d1e7a 100755
--- a/scripts/context/stubs/unix/xmltools
+++ b/scripts/context/stubs/unix/xmltools
@@ -1,2 +1,2 @@
#!/bin/sh
-texmfstart xmltools.rb "$@"
+mtxrun --usekpse --execute xmltools.rb "$@"
diff --git a/tex/context/base/attr-ini.lua b/tex/context/base/attr-ini.lua
index 204cabce1..3b2ed7791 100644
--- a/tex/context/base/attr-ini.lua
+++ b/tex/context/base/attr-ini.lua
@@ -6,146 +6,23 @@ if not modules then modules = { } end modules ['attr-ini'] = {
license = "see context related readme files"
}
--- todo: document this
-
--- nb: attributes: color etc is much slower than normal (marks + literals) but ...
--- nb. too many "0 g"s
-
---
--- nodes
---
-
-nodes = nodes or { }
-
-local format, concat, texsprint = string.format, table.concat, tex.sprint
-
--- This is not the most ideal place, but it will do. Maybe we need to move
--- attributes to node-att.lua.
-
-do
-
- -- just for testing
-
- local reserved = { }
-
- function nodes.register(n)
- reserved[#reserved+1] = n
- end
-
- function nodes.cleanup_reserved(nofboxes) -- todo
- local nr, free = #reserved, node.free
- for i=1,nr do
- free(reserved[i])
- end
- local nl, tb, flush = 0, tex.box, node.flush_list
- if nofboxes then
- for i=1,nofboxes do
- local l = tb[i]
- if l then
- free(tb[i])
- nl = nl + 1
- end
- end
- end
- reserved = { }
- return nr, nl, nofboxes
- end
-
-end
+-- this module is being reconstructed
-do
-
- local pdfliteral = node.new("whatsit",8) pdfliteral.next, pdfliteral.prev = nil, nil pdfliteral.mode = 1
- local disc = node.new("disc") disc.next, disc.prev = nil, nil
- local kern = node.new("kern",1) kern.next, kern.prev = nil, nil
- local penalty = node.new("penalty") penalty.next, penalty.prev = nil, nil
- local glue = node.new("glue") glue.next, glue.prev = nil, nil
- local glue_spec = node.new("glue_spec")
- local glyph = node.new("glyph",0) glyph.next, glyph.prev = nil, nil
- local textdir = node.new("whatsit",7) textdir.next, textdir.prev = nil, nil
-
- nodes.register(pdfliteral)
- nodes.register(disc)
- nodes.register(kern)
- nodes.register(penalty)
- nodes.register(glue)
- nodes.register(glue_spec)
- nodes.register(glyph)
- nodes.register(textdir)
-
- local copy = node.copy
-
- function nodes.glyph(fnt,chr)
- local n = copy(glyph)
- if fnt then n.font = fnt end
- if chr then n.char = chr end
- return n
- end
- function nodes.penalty(p)
- local n = copy(penalty)
- n.penalty = p
- return n
- end
- function nodes.kern(k)
- local n = copy(kern)
- n.kern = k
- return n
- end
- function nodes.glue(width,stretch,shrink)
- local n = copy(glue)
- local s = copy(glue_spec)
- s.width, s.stretch, s.shrink = width, stretch, shrink
- n.spec = s
- return n
- end
- function nodes.glue_spec(width,stretch,shrink)
- local s = copy(glue_spec)
- s.width, s.stretch, s.shrink = width, stretch, shrink
- return s
- end
- function nodes.disc()
- return copy(disc)
- end
- function nodes.pdfliteral(str)
- local t = copy(pdfliteral)
- t.data = str
- return t
- end
- function nodes.textdir(dir)
- local t = copy(textdir)
- t.dir = dir
- return t
- end
-
-end
-
-function tex.node_mem_status()
- -- todo: lpeg
- local s = status.node_mem_usage
- local t = { }
- for n, tag in s:gmatch("(%d+) ([a-z_]+)") do
- t[tag] = n
- end
- return t
-end
-
---
--- attributes
---
+local type = type
+local format, gmatch = string.format, string.gmatch
+local concat = table.concat
+local texsprint = tex.sprint
-attributes = attributes or { }
+local ctxcatcodes = tex.ctxcatcodes
-attributes.names = attributes.names or { }
-attributes.numbers = attributes.numbers or { }
-attributes.list = attributes.list or { }
+-- todo: document this
-input.storage.register(false, "attributes/names", attributes.names, "attributes.names")
-input.storage.register(false, "attributes/numbers", attributes.numbers, "attributes.numbers")
-input.storage.register(false, "attributes/list", attributes.list, "attributes.list")
+-- nb: attributes: color etc is much slower than normal (marks + literals) but ...
+-- nb. too many "0 g"s
-function attributes.define(name,number)
- attributes.numbers[name], attributes.names[number], attributes.list[number] = number, name, { }
-end
+nodes = nodes or { }
+states = states or { }
+shipouts = shipouts or { }
-- We can distinguish between rules and glyphs but it's not worth the trouble. A
-- first implementation did that and while it saves a bit for glyphs and rules, it
@@ -156,342 +33,6 @@ end
-- i will do the resource stuff later, when we have an interface to pdf (ok, i can
-- fake it with tokens but it will take some coding
-function totokens(str)
- local t = { }
---~ for c in string.bytes(str) do
- for c in str:bytes() do
- t[#t+1] = { 12, c }
- end
- return t
-end
-
--- temp hack, will be proper driver stuff
-
-backends = backends or { }
-backends.pdf = backends.pdf or { }
-backend = backend or backends.pdf
-
-do
-
- local pdfliteral, register = nodes.pdfliteral, nodes.register
-
- function backends.pdf.literal(str)
- local t = pdfliteral(str)
- register(t)
- return t
- end
-
-end
-
--- shipouts
-
-shipouts = shipouts or { }
-
-do
-
- local pairs = pairs -- in theory faster
-
- local hlist, vlist = node.id('hlist'), node.id('vlist')
-
- local has_attribute = node.has_attribute
-
- nodes.trigger = nodes.trigger or false
- nodes.triggering = nodes.triggering or false
-
- -- we used to do the main processor loop here and call processor for each node
- -- but eventually this was too much a slow down (1 sec on 23 for 120 pages mk)
- -- so that we moved looping to the processor itself; this may lead to a bit of
- -- duplicate code once that we have more state handlers
-
- local starttiming, stoptiming = input.starttiming, input.stoptiming
- local trigger, numbers = nodes.trigger, attributes.numbers
-
- local function process_attribute(head,plugin) -- head,attribute,enabled,initializer,resolver,processor,finalizer
- starttiming(attributes)
- local done, used, ok = false, nil, false
- local name = plugin.name
- local attribute = numbers[name]
- local namespace = plugin.namespace
- if namespace.enabled then
- local processor = plugin.processor
- if processor then
- local initializer = plugin.initializer
- local resolver = plugin.resolver
- local inheritance = (resolver and resolver()) or -1
- if initializer then
- initializer(namespace,attribute,head)
- end
- head, ok = processor(namespace,attribute,head,inheritance)
- if ok then
- local finalizer = plugin.finalizer
- if finalizer then
- head, ok, used = finalizer(namespace,attribute,head)
- if used then
- local flusher = plugin.flusher
- if flusher then
- local h, d = flusher(namespace,attribute,head,used)
- head = h
- end
- end
- end
- done = true
- end
- end
- end
- stoptiming(attributes)
- return head, done
- end
-
- nodes.process_attribute = process_attribute
-
- function nodes.install_attribute_handler(plugin)
- return function(head)
- return process_attribute(head,plugin)
- end
- end
-
-end
-
---
--- generic handlers
---
-
-states = { }
-
-do
-
- local glyph, glue, rule, whatsit, hlist, vlist = node.id('glyph'), node.id('glue'), node.id('rule'), node.id('whatsit'), node.id('hlist'), node.id('vlist')
-
- local has_attribute, copy = node.has_attribute, node.copy
-
- local current, current_selector, used, done = 0, 0, { }, false
-
- function states.initialize(what, attribute, stack)
- current, current_selector, used, done = 0, 0, { }, false
- end
-
- local function insert(n,stack,previous,head) -- there is a helper, we need previous because we are not slided
- if n then
- if type(n) == "function" then
- n = n()
- end
- n = copy(n)
- n.next = stack
- if previous then
- previous.next = n
- else
- head = n
- end
- previous = n
- end
- return stack, head
- end
-
- function states.finalize(namespace,attribute,head) -- is this one ok?
- if current > 0 then
- local nn = namespace.none
- if nn then
- local id = head.id
- if id == hlist or id == vlist then
- local list = head.list
- if list then
- local _, h = insert(nn,list,nil,list)
- head.list = h
- end
- else
- stack, head = insert(nn,head,nil,head)
- end
- return head, true, true
- end
- end
- return head, false, false
- end
-
- local function process(namespace,attribute,head,inheritance,default) -- one attribute
- local trigger = namespace.triggering and nodes.triggering and nodes.trigger
- local stack, previous, done = head, nil, false
- local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
- while stack do
- local id = stack.id
- -- if id == glyph or (id == whatsit and stack.subtype == 8) or id == rule or (id == glue and stack.leader) then -- or disc
- if id == glyph or id == rule or (id == glue and stack.leader) then -- or disc
- local c = has_attribute(stack,attribute)
- if c then
- if default and c == inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data,stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current ~= c then
- local data = nsdata[c] or nsreviver(c)
- stack, head = insert(data,stack,previous,head)
- current, done, used[c] = c, true, true
- end
- if id == glue then --leader
- -- same as *list
- local content = stack.leader
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.leader, ok = process(namespace,attribute,content,inheritance,outer)
- else
- stack.leader, ok = process(namespace,attribute,content,inheritance,default)
- end
- else
- stack.leader, ok = process(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- elseif default and inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data,stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current > 0 then
- stack, head = insert(nsnone,stack,previous,head)
- current, done, used[0] = 0, true, true
- end
- elseif id == hlist or id == vlist then
- local content = stack.list
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.list, ok = process(namespace,attribute,content,inheritance,outer)
- else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
- end
- else
- stack.list, ok = process(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- previous = stack
- stack = stack.next
- end
- return head, done
- end
-
- states.process = process
-
- -- we can force a selector, e.g. document wide color spaces, saves a little
- -- watch out, we need to check both the selector state (like colorspace) and
- -- the main state (like color), otherwise we get into troubles when a selector
- -- state changes while the main state stays the same (like two glyphs following
- -- each other with the same color but different color spaces e.g. \showcolor)
-
- local function selective(namespace,attribute,head,inheritance,default) -- two attributes
- local trigger = namespace.triggering and nodes.triggering and nodes.trigger
- local stack, previous, done = head, nil, false
- -- local nsselector, nsforced, nsselector = namespace.default, namespace.forced, namespace.selector
- local nsforced, nsselector = namespace.forced, namespace.selector
- local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
- while stack do
- local id = stack.id
- -- if id == glyph or (id == whatsit and stack.subtype == 8) or id == rule or (id == glue and stack.leader) then -- or disc
- if id == glyph or id == rule or (id == glue and stack.leader) then -- or disc
- local c = has_attribute(stack,attribute)
- if c then
- if default and c == inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, done, used[default] = default, true, true
- end
- else
- local s = has_attribute(stack,nsselector)
- if current ~= c or current_selector ~= s then
- local data = nsdata[c] or nsreviver(c)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, current_selector, done, used[c] = c, s, true, true
- end
- end
- elseif default and inheritance then
- if current ~= default then
- local data = nsdata[default] or nsreviver(default)
- stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
- current, done, used[default] = default, true, true
- end
- elseif current > 0 then
- stack, head = insert(nsnone,stack,previous,head)
- current, current_selector, done, used[0] = 0, 0, true, true
- end
- if id == glue then -- leader
- -- same as *list
- local content = stack.leader
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.leader, ok = selective(namespace,attribute,content,inheritance,outer)
- else
- stack.leader, ok = selective(namespace,attribute,content,inheritance,default)
- end
- else
- stack.leader, ok = selective(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- elseif id == hlist or id == vlist then
- local content = stack.list
- if content then
- local ok = false
- if trigger and has_attribute(stack,trigger) then
- local outer = has_attribute(stack,attribute)
- if outer ~= inheritance then
- stack.list, ok = selective(namespace,attribute,content,inheritance,outer)
- else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
- end
- else
- stack.list, ok = selective(namespace,attribute,content,inheritance,default)
- end
- done = done or ok
- end
- end
- previous = stack
- stack = stack.next
- end
- return head, done
- end
-
- states.selective = selective
-
-end
-
-states = states or { }
-states.collected = states.collected or { }
-
-input.storage.register(false,"states/collected", states.collected, "states.collected")
-
-function states.collect(str)
- local collected = states.collected
- collected[#collected+1] = str
-end
-
-function states.flush()
- local collected = states.collected
- if #collected > 0 then
- for i=1,#collected do
- texsprint(tex.ctxcatcodes,collected[i]) -- we're in context mode anyway
- end
- states.collected = { }
- end
-end
-
-function states.check()
- texio.write_nl(concat(states.collected,"\n"))
-end
-
--
-- colors
--
@@ -500,21 +41,9 @@ end
-- at the tex end add 0, 1, 2, but this is not faster and less
-- flexible (since sometimes we freeze color attribute values at
-- the lua end of the game
-
+--
-- we also need to store the colorvalues because we need then in mp
-
-colors = colors or { }
-colors.data = colors.data or { }
-colors.values = colors.values or { }
-colors.registered = colors.registered or { }
-colors.enabled = true
-colors.weightgray = true
-colors.attribute = 0
-colors.selector = 0
-colors.default = 1
-colors.main = nil
-colors.triggering = true
-
+--
-- This is a compromis between speed and simplicity. We used to store the
-- values and data in one array, which made in neccessary to store the
-- converters that need node constructor into strings and evaluate them
@@ -526,21 +55,33 @@ colors.triggering = true
-- colors.strings[color] = "return colors." .. colorspace .. "(" .. concat({...},",") .. ")"
-- end
--
--- input.storage.register(true,"colors/data", colors.strings, "colors.data") -- evaluated
+-- storage.register("colors/data", colors.strings, "colors.data") -- evaluated
--
-- We assume that only processcolors are defined in the format.
-input.storage.register(false,"colors/values", colors.values, "colors.values")
-input.storage.register(false,"colors/registered", colors.registered, "colors.registered")
+colors = colors or { }
+colors.data = colors.data or { }
+colors.values = colors.values or { }
+colors.registered = colors.registered or { }
+colors.enabled = true
+colors.weightgray = true
+colors.attribute = 0
+colors.selector = 0
+colors.default = 1
+colors.main = nil
+colors.triggering = true
+
+storage.register("colors/values", colors.values, "colors.values")
+storage.register("colors/registered", colors.registered, "colors.registered")
-colors.stamps = {
+local templates = {
rgb = "r:%s:%s:%s",
cmyk = "c:%s:%s:%s:%s",
gray = "s:%s",
spot = "p:%s:%s:%s:%s"
}
-colors.models = {
+local models = {
all = 1,
gray = 2,
rgb = 3,
@@ -549,158 +90,146 @@ colors.models = {
colors.model = "all"
-do
+local data = colors.data
+local values = colors.values
+local registered = colors.registered
- local min = math.min
- local max = math.max
+local numbers = attributes.numbers
+local list = attributes.list
- local function rgbdata(r,g,b) -- dodo: backends.pdf.rgbdata
- return backends.pdf.literal(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b))
- end
+local min = math.min
+local max = math.max
- local function cmykdata(c,m,y,k)
- return backends.pdf.literal(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k))
- end
+local nodeinjections = backends.nodeinjections
+local codeinjections = backends.codeinjections
+local registrations = backends.registrations
- local function graydata(s)
- return backends.pdf.literal(format("%s g %s G",s,s))
- end
-
- local function spotdata(n,f,d,p)
- if type(p) == "string" then
- p = p:gsub(","," ") -- brr misuse of spot
- end
- return backends.pdf.literal(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p))
- end
+local function rgbtocmyk(r,g,b) -- we could reduce
+ return 1-r, 1-g, 1-b, 0
+end
- local function rgbtocmyk(r,g,b) -- we could reduce
- return 1-r, 1-g, 1-b, 0
- end
+local function cmyktorgb(c,m,y,k)
+ return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+end
- local function cmyktorgb(c,m,y,k)
- return 1.0 - min(1.0,c+k), 1.0 - min(1.0,m+k), 1.0 - min(1.0,y+k)
+local function rgbtogray(r,g,b)
+ if colors.weightgray then
+ return .30*r+.59*g+.11*b
+ else
+ return r/3+g/3+b/3
end
+end
- local function rgbtogray(r,g,b)
- if colors.weightgray then
- return .30*r+.59*g+.11*b
- else
- return r/3+g/3+b/3
- end
- end
+local function cmyktogray(c,m,y,k)
+ return rgbtogray(cmyktorgb(c,m,y,k))
+end
- local function cmyktogray(c,m,y,k)
- return rgbtogray(cmyktorgb(c,m,y,k))
- end
+colors.rgbtocmyk = rgbtocmyk
+colors.rgbtogray = rgbtogray
+colors.cmyktorgb = cmyktorgb
+colors.cmyktogray = cmyktogray
- colors.rgbtocmyk = rgbtocmyk
- colors.rgbtogray = rgbtogray
- colors.cmyktorgb = cmyktorgb
- colors.cmyktogray = cmyktogray
+-- we can share some *data by using s, rgb and cmyk hashes, but
+-- normally the amount of colors is not that large; storing the
+-- components costs a bit of extra runtime, but we expect to gain
+-- some back because we have them at hand; the number indicates the
+-- default color space
- -- we can share some *data by using s, rgb and cmyk hashes, but
- -- normally the amount of colors is not that large; storing the
- -- components costs a bit of extra runtime, but we expect to gain
- -- some back because we have them at hand; the number indicates the
- -- default color space
+function colors.gray(s)
+ return { 2, s, s, s, s, 0, 0, 0, 1-s }
+end
- function colors.gray(s)
- return { 2, s, s, s, s, 0, 0, 0, 1-s }
- end
+function colors.rgb(r,g,b)
+ local s = rgbtogray(r,g,b)
+ local c, m, y, k = rgbtocmyk(r,g,b)
+ return { 3, s, r, g, b, c, m, y, k }
+end
- function colors.rgb(r,g,b)
- local s = rgbtogray(r,g,b)
- local c, m, y, k = rgbtocmyk(r,g,b)
- return { 3, s, r, g, b, c, m, y, k }
- end
+function colors.cmyk(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ local r, g, b = cmyktorgb(c,m,y,k)
+ return { 4, s, r, g, b, c, m, y, k }
+end
- function colors.cmyk(c,m,y,k)
- local s = cmyktogray(c,m,y,k)
- local r, g, b = cmyktorgb(c,m,y,k)
- return { 4, s, r, g, b, c, m, y, k }
- end
+--~ function colors.spot(parent,f,d,p)
+--~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+--~ end
- --~ function colors.spot(parent,f,d,p)
- --~ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
- --~ end
-
- function colors.spot(parent,f,d,p)
- if type(p) == "number" then
- local n = attributes.list[attributes.numbers.color][parent] -- hard coded ref to color number
- if n then
- local v = colors.values[n]
- if v then
- -- the via cmyk hack is dirty, but it scales better
- local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8]
- local r, g, b = cmyktorgb(c,m,y,k)
- local s = cmyktogray(c,m,y,k)
- return { 5, s, r, g, b, c, m, y, k, parent, f, d, p }
- end
+function colors.spot(parent,f,d,p)
+ if type(p) == "number" then
+ local n = list[numbers.color][parent] -- hard coded ref to color number
+ if n then
+ local v = values[n]
+ if v then
+ -- the via cmyk hack is dirty, but it scales better
+ local c, m, y, k = p*v[6], p*v[7], p*v[8], p*v[8]
+ local r, g, b = cmyktorgb(c,m,y,k)
+ local s = cmyktogray(c,m,y,k)
+ return { 5, s, r, g, b, c, m, y, k, parent, f, d, p }
end
- else
- -- todo, multitone (maybe p should be a table)
end
- return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+ else
+ -- todo, multitone (maybe p should be a table)
end
+ return { 5, .5, .5, .5, .5, 0, 0, 0, .5, parent, f, d, p }
+end
- function colors.reviver(n)
- local d = colors.data[n]
- if not d then
- local v = colors.values[n]
- if not v then
- local gray = graydata(0)
+function colors.reviver(n)
+ local d = data[n]
+ if not d then
+ local v = values[n]
+ if not v then
+ local gray = nodeinjections.graycolor(0)
+ d = { gray, gray, gray, gray }
+ logs.report("attributes","unable to revive color %s",n or "?")
+ else
+ local kind, gray, rgb, cmyk = v[1], nodeinjections.graycolor(v[2]), nodeinjections.rgbcolor(v[3],v[4],v[5]), nodeinjections.cmykcolor(v[6],v[7],v[8],v[9])
+ if kind == 2 then
d = { gray, gray, gray, gray }
- logs.report("attributes","unable to revive color %s",n or "?")
- else
- local kind, gray, rgb, cmyk = v[1], graydata(v[2]), rgbdata(v[3],v[4],v[5]), cmykdata(v[6],v[7],v[8],v[9])
- if kind == 2 then
- d = { gray, gray, gray, gray }
- elseif kind == 3 then
- d = { rgb, gray, rgb, cmyk }
- elseif kind == 4 then
- d = { cmyk, gray, rgb, cmyk }
- elseif kind == 5 then
- local spot = spotdata(v[10],v[11],v[12],v[13])
- d = { spot, gray, rgb, cmyk }
- end
+ elseif kind == 3 then
+ d = { rgb, gray, rgb, cmyk }
+ elseif kind == 4 then
+ d = { cmyk, gray, rgb, cmyk }
+ elseif kind == 5 then
+ local spot = nodeinjections.spotcolor(v[10],v[11],v[12],v[13])
+ d = { spot, gray, rgb, cmyk }
end
- colors.data[n] = d
end
- return d
+ data[n] = d
end
+ return d
+end
- function colors.filter(n)
- return concat(colors.data[n],":",5)
- end
-
- colors.none = graydata(0)
-
+function colors.filter(n)
+ return concat(data[n],":",5)
end
+colors.none = nodeinjections.graycolor(0)
+
function colors.setmodel(attribute,name)
colors.model = name
- colors.selector = attributes.numbers[attribute]
- colors.default = colors.models[name] or 1
+ colors.selector = numbers[attribute]
+ colors.default = models[name] or 1
return colors.default
end
function colors.register(attribute, name, colorspace, ...) -- passing 9 vars is faster
- local stamp = format(colors.stamps[colorspace], ...)
- local color = colors.registered[stamp]
+ local stamp = format(templates[colorspace],...)
+ local color = registered[stamp]
if not color then
- color = #colors.values+1
- colors.values[color] = colors[colorspace](...)
- colors.registered[stamp] = color
+ color = #values+1
+ values[color] = colors[colorspace](...)
+ registered[stamp] = color
colors.reviver(color)
end
if name then
- attributes.list[attributes.numbers[attribute]][name] = color -- not grouped, so only global colors
+ list[numbers[attribute]][name] = color -- not grouped, so only global colors
end
- return colors.registered[stamp]
+ return registered[stamp]
end
function colors.value(id)
- return colors.values[id]
+ return values[id]
end
shipouts.handle_color = nodes.install_attribute_handler {
@@ -709,7 +238,7 @@ shipouts.handle_color = nodes.install_attribute_handler {
initializer = states.initialize,
finalizer = states.finalize,
processor = states.selective,
- resolver = function(...) return colors.main end,
+ resolver = function() return colors.main end,
}
-- transparencies
@@ -722,51 +251,56 @@ transparencies.registered = transparencies.registered or { }
transparencies.data = transparencies.data or { }
transparencies.values = transparencies.values or { }
transparencies.enabled = false
-transparencies.template = "%s:%s"
transparencies.triggering = true
-input.storage.register(false, "transparencies/registered", transparencies.registered, "transparencies.registered")
-input.storage.register(false, "transparencies/values", transparencies.values, "transparencies.values")
+storage.register("transparencies/registered", transparencies.registered, "transparencies.registered")
+storage.register("transparencies/values", transparencies.values, "transparencies.values")
-function transparencies.reference(n)
- return backends.pdf.literal(format("/Tr%s gs",n))
+local registered = transparencies.registered
+local data = transparencies.data
+local values = transparencies.values
+local template = "%s:%s"
+
+local function reference(n)
+ reference = nodeinjections.transparency
+ return reference(n)
end
function transparencies.register(name,a,t)
- local stamp = format(transparencies.template,a,t)
- local n = transparencies.registered[stamp]
+ local stamp = format(template,a,t)
+ local n = registered[stamp]
if not n then
- n = #transparencies.data+1
- transparencies.data[n] = transparencies.reference(n)
- transparencies.values[n] = { a, t }
- transparencies.registered[stamp] = n
- states.collect(format("\\presetPDFtransparencybynumber{%s}{%s}{%s}",n,a,t)) -- too many, but experimental anyway
+ n = #data+1
+ data[n] = reference(n)
+ values[n] = { a, t }
+ registered[stamp] = n
+ registrations.transparency(n,a,t)
end
- return transparencies.registered[stamp]
+ return registered[stamp]
end
function transparencies.reviver(n)
- local d = transparencies.data[n]
+ local d = data[n]
if not d then
- local v = transparencies.values[n]
+ local v = values[n]
if not v then
- d = transparencies.reference(0)
+ d = reference(0)
logs.report("attributes","unable to revive transparency %s",n or "?")
else
- d = transparencies.reference(n)
- states.collect(format("\\presetPDFtransparencybynumber{%s}{%s}{%s}",n,v[1],v[2]))
+ d = reference(n)
+ registrations.transparency(n,v[1],v[2])
end
- transparencies.data[n] = d
+ data[n] = d
end
return d
end
-- check if there is an identity
-transparencies.none = transparencies.reference(0) -- for the moment the pdf backend does this
+transparencies.none = reference(0) -- for the moment the pdf backend does this
function transparencies.value(id)
- return transparencies.values[id]
+ return values[id]
end
shipouts.handle_transparency = nodes.install_attribute_handler {
@@ -783,8 +317,8 @@ overprints = overprints or { }
overprints.data = overprints.data or { }
overprints.enabled = false
-overprints.data[1] = backends.pdf.literal(format("/GSoverprint gs"))
-overprints.data[2] = backends.pdf.literal(format("/GSknockout gs"))
+overprints.data[1] = nodeinjections.overprint()
+overprints.data[2] = nodeinjections.knockout()
overprints.none = overprints.data[2]
@@ -793,12 +327,14 @@ overprints.registered = {
knockout = 2,
}
---~ input.storage.register(false, "overprints/registered", overprints.registered, "overprints.registered")
---~ input.storage.register(false, "overprints/data", overprints.data, "overprints.data")
+--~ storage.register("overprints/registered", overprints.registered, "overprints.registered")
+--~ storage.register("overprints/data", overprints.data, "overprints.data")
+
+local data = overprints.data
+local registered = overprints.registered
function overprints.register(stamp)
--- states.collect(texsprint(tex.ctxcatcodes,"\\initializePDFoverprint")) -- to be testd
- return overprints.registered[stamp] or overprints.registered.overprint
+ return registered[stamp] or registered.overprint
end
shipouts.handle_overprint = nodes.install_attribute_handler {
@@ -815,8 +351,8 @@ negatives = negatives or { }
negatives.data = negatives.data or { }
negatives.enabled = false
-negatives.data[1] = backends.pdf.literal(format("/GSpositive gs"))
-negatives.data[2] = backends.pdf.literal(format("/GSnegative gs"))
+negatives.data[1] = nodeinjections.positive()
+negatives.data[2] = nodeinjections.negative()
negatives.none = negatives.data[1]
@@ -826,7 +362,6 @@ negatives.registered = {
}
function negatives.register(stamp)
--- states.collect(texsprint(tex.ctxcatcodes,"\\initializePDFnegative")) -- to be testd
return negatives.registered[stamp] or negatives.registered.positive
end
@@ -838,7 +373,7 @@ shipouts.handle_negative = nodes.install_attribute_handler {
processor = states.process,
}
--- effects
+-- effects -- can be optimized
effects = effects or { }
effects.data = effects.data or { }
@@ -846,8 +381,8 @@ effects.registered = effects.registered or { }
effects.enabled = false
effects.stamp = "%s:%s:%s"
-input.storage.register(false, "effects/registered", effects.registered, "effects.registered")
-input.storage.register(false, "effects/data", effects.data, "effects.data")
+storage.register("effects/registered", effects.registered, "effects.registered")
+storage.register("effects/data", effects.data, "effects.data")
function effects.register(effect,stretch,rulethickness)
local stamp = format(effects.stamp,effect,stretch,rulethickness)
@@ -856,27 +391,18 @@ function effects.register(effect,stretch,rulethickness)
n = #effects.data+1
effects.data[n] = effects.reference(effect,stretch,rulethickness)
effects.registered[stamp] = n
- -- states.collect("") -- nothing
end
return effects.registered[stamp]
end
-backends.pdf.effects = {
- normal = 0,
- inner = 0,
- outer = 1,
- both = 2,
- hidden = 3,
-}
+-- valid effects: normal inner outer both hidden
function effects.reference(effect,stretch,rulethickness)
- -- always, no zero test (removed)
- rulethickness = number.dimenfactors["bp"]*rulethickness
- effect = backends.pdf.effects[effect] or backends.pdf.effects['normal']
- return backends.pdf.literal(format("%s Tc %s w %s Tr",stretch,rulethickness,effect)) -- watch order
+ effects.reference = nodeinjections.effect
+ return nodeinjections.effect(stretch,rulethickness,effect)
end
-effects.none = effects.reference(0,0,0) -- faster: backends.pdf.literal("0 Tc 0 w 0 Tr")
+effects.none = effects.reference(0,0,0)
shipouts.handle_effect = nodes.install_attribute_handler {
name = "effect",
@@ -891,15 +417,18 @@ shipouts.handle_effect = nodes.install_attribute_handler {
viewerlayers = viewerlayers or { }
viewerlayers.data = viewerlayers.data or { }
viewerlayers.registered = viewerlayers.registered or { }
-viewerlayers.stamp = "%s"
viewerlayers.enabled = false
-input.storage.register(false, "viewerlayers/registered", viewerlayers.registered, "viewerlayers.registered")
---~ input.storage.register(false, "viewerlayers/data", viewerlayers.data, "viewerlayers.data")
+storage.register("viewerlayers/registered", viewerlayers.registered, "viewerlayers.registered")
+--~ storage.register("viewerlayers/data", viewerlayers.data, "viewerlayers.data")
+
+local data = viewerlayers.data
+local registered = viewerlayers.registered
+local template = "%s"
local somedone = false
local somedata = { }
-local nonedata = backends.pdf.literal("EMC")
+local nonedata = nodeinjections.stoplayer()
function viewerlayers.none() -- no local
if somedone then
@@ -914,8 +443,8 @@ local function some(name)
local sd = somedata[name]
if not sd then
sd = {
- backends.pdf.literal(format("EMC /OC /%s BDC",name)),
- backends.pdf.literal(format( "/OC /%s BDC",name)),
+ nodeinjections.switchlayer(name),
+ nodeinjections.startlayer(name),
}
somedata[name] = sd
end
@@ -933,14 +462,14 @@ local function initializer(...)
end
viewerlayers.register = function(name)
- local stamp = format(viewerlayers.stamp,name)
- local n = viewerlayers.registered[stamp]
+ local stamp = format(template,name)
+ local n = registered[stamp]
if not n then
- n = #viewerlayers.data + 1
- viewerlayers.data[n] = function() return some(name) end
- viewerlayers.registered[stamp] = n
+ n = #data + 1
+ data[n] = function() return some(name) end -- slow but for the moment we don't store things in the format
+ registered[stamp] = n
end
- return viewerlayers.registered[stamp]
+ return registered[stamp] -- == n
end
shipouts.handle_viewerlayer = nodes.install_attribute_handler {
@@ -950,5 +479,3 @@ shipouts.handle_viewerlayer = nodes.install_attribute_handler {
finalizer = states.finalize,
processor = states.process,
}
-
---~ nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_viewerlayer", nil, "notail")
diff --git a/tex/context/base/attr-ini.tex b/tex/context/base/attr-ini.tex
index c9e4110e5..3997d546b 100644
--- a/tex/context/base/attr-ini.tex
+++ b/tex/context/base/attr-ini.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Attribute Macros / initialization}
+\writestatus{loading}{ConTeXt Attribute Macros / Initialization}
%D Although it's still somewhat experimental, here we introduce code
%D related to attributes.
@@ -20,63 +20,21 @@
\registerctxluafile{attr-ini}{1.001}
-\newcount\attdefcounter
-
-% \def\newattribute#1%
-% {\global\advance\attdefcounter\plusone
-% \global\attributedef#1\attdefcounter
-% \ctxlua{attributes.define("\strippedcsname#1",\number\attdefcounter)}}
-
-% \newattribute\statusattribute
-% \newattribute\colorattribute
-% \newattribute\skipattribute
-% \newattribute\penaltyattribute
-
-\newtoks \attributesresetlist
-
-\def\defineattribute[#1]% alternatively we can let lua do the housekeeping
- {\global\advance\attdefcounter\plusone
- \expandafter \xdef\csname :attr:#1\endcsname{\number\attdefcounter}%
- \global\expandafter\attributedef\csname @attr@#1\endcsname \attdefcounter
- \writestatus\m!systems{defining attribute #1 with number \the\attdefcounter}%
- \appendetoks\csname @attr@#1\endcsname\minusone\to\attributesresetlist
- \ctxlua{attributes.define("#1",\number\attdefcounter)}}
-
-% expandable so we can \edef them for speed
-
-\def\dosetattribute#1#2{\csname @attr@#1\endcsname#2\relax}
-\def\doresetattribute#1{\csname @attr@#1\endcsname\minusone}
-\def\dogetattribute #1{\number\csname @attr@#1\endcsname}
-\def\dogetattributeid#1{\csname :attr:#1\endcsname}
-
-\let\dompattribute\gobbletwoarguments
-
-\defineattribute[mark]
-% \defineattribute[status] % used ? maybe combine with
-\defineattribute[state]
-\defineattribute[trigger] % feature inheritance
-\defineattribute[skip]
-\defineattribute[penalty]
-
-\startruntimectxluacode
- nodes.trigger = \dogetattributeid{trigger}
-\stopruntimectxluacode
-
-% \defineattribute[ignore]
+\definesystemattribute[state]
+\definesystemattribute[skip]
+\definesystemattribute[penalty]
+\definesystemattribute[colormodel][global] % no reset
+\definesystemattribute[color]
+\definesystemattribute[transparency]
+\definesystemattribute[overprint]
+\definesystemattribute[negative]
+\definesystemattribute[effect]
+\definesystemattribute[viewerlayer]
+
+% \definesystemattribute[ignore]
%
% \edef\startignorecontent{\dosetattribute{ignore}\plusone}
% \edef\stopignorecontent {\doresetattribute{ignore}}
-%
-% \startruntimectxluacode
-% nodes.ignore = \dogetattributeid{ignore}
-% \stopruntimectxluacode
-
-% \dosetattribute{status}{1}
-
-% temp here / will be indirect ! just for testing
-
-\defineattribute[colormodel]
-\defineattribute[color]
% todo: no need for 'color' argument, we can set that once at startup; currently
% a bit inconsistent
@@ -106,8 +64,6 @@
% transparency
-\defineattribute[transparency]
-
\def\registertransparency#1#2#3%
{\setevalue{(ts:#1)}{\dosetattribute{transparency}{\ctxlua{tex.print(transparencies.register(#2,#3))}}}}
@@ -123,8 +79,6 @@
% overprint
-\defineattribute[overprint]
-
\def\registeroverprint#1#2%
{\setevalue{(os:#1)}{\dosetattribute{overprint}{\ctxlua{tex.print(overprints.register('#2'))}}}}
@@ -139,8 +93,6 @@
% negative
-\defineattribute[negative]
-
\def\registernegative#1#2%
{\setevalue{(ns:#1)}{\dosetattribute{negative}{\ctxlua{tex.print(negatives.register('#2'))}}}}
@@ -155,8 +107,6 @@
% effect
-\defineattribute[effect]
-
\def\registereffect#1#2#3% #2=stretch #3=rulethickness
{\setxvalue{(es:#1:#2:\number\dimexpr#3\relax)}%
{\dosetattribute{effect}{\ctxlua{tex.print(effects.register('#1',#2,\number\dimexpr#3\relax))}}}}
@@ -176,90 +126,25 @@
% viewerlayers
-\defineattribute[viewerlayer]
+% \def\registerviewerlayer#1#2% global !
+% {\setxvalue{(vl:#1)}{\dosetattribute{viewerlayer}{\ctxlua{tex.print(viewerlayers.register('#2'))}}}}
+%
+% \setevalue{(vl:)}{\doresetattribute{viewerlayer}}
+%
+% needs to work over stopitemize grouping etc
+
+\def\registerviewerlayer#1#2% global !
+ {\setxvalue{(vl:#1)}{\global\dosetattribute{viewerlayer}{\ctxlua{tex.print(viewerlayers.register('#2'))}}}}
-\def\registerviewerlayer#1#2%
- {\setevalue{(vl:#1)}{\dosetattribute{viewerlayer}{\ctxlua{tex.print(viewerlayers.register('#2'))}}}}
+\setevalue{(vl:)}{\global\doresetattribute{viewerlayer}}
-\setevalue{(vl:)}{\doresetattribute{viewerlayer}}
+%
\def\dotriggerviewerlayer
{\ctxlua{viewerlayers.enabled=true}%
\gdef\dotriggerviewerlayer##1{\csname(vl:##1)\endcsname}%
\dotriggerviewerlayer}
-% ugly solution for backend handling
-
-% \def\shipout
-% {%\writestatus{SHIPOUT}{CALLED AT PAGE \realfolio}%
-% \dowithnextbox
-% {\ctxlua{callbacks.push('hpack_filter',nodes.process_page)}%
-% %\writestatus{SHIPOUT}{START PACKAGING}%
-% \setbox\nextbox\hbox{\box\nextbox}%
-% %\writestatus{SHIPOUT}{STOP PACKAGING}%
-% \ctxlua{callbacks.pop('hpack_filter')}%
-% \primitive\shipout\box\nextbox}}
-
-% \def\shipout
-% {\dowithnextbox
-% {\ctxlua{nodes.process_page(tex.box[\number\nextbox])}%
-% \primitive\shipout\box\nextbox}}
-
-% Objects are processed indepently \unknown\ actually we may need a proper callback.
-
-\newbox\finalizedshipoutbox
-
-\def\finalizeobjectbox#1{\ctxlua{nodes.process_page(tex.box[\number#1])}}
-
-\def\finalizeshipoutbox#1% % hack till we have access to pdf backend
- {\global\setbox\finalizedshipoutbox\hbox{#1}%
- \finalizeobjectbox\finalizedshipoutbox
- \hbox{\ctxlua{states.flush()}\box\finalizedshipoutbox}}
-
-\let\normalshipout\shipout
-
-% tricky stuff:
-
-\newcount\attributeboxcount
-
-\edef\startinheritattributes{\dosetattribute {trigger}{1}}
-\edef\stopinheritattributes {\doresetattribute{trigger}}
-
-\def\doattributedcopy {\afterassignment\dodoattributedcopy\attributeboxcount}
-\def\doattributedbox {\afterassignment\dodoattributedbox \attributeboxcount}
-
-\def\dodoattributedcopy
- {\startinheritattributes
- \ifvbox\attributeboxcount
- \vbox{\unvcopy\attributeboxcount}%
- \else
- \hbox{\unhcopy\attributeboxcount}%
- \fi
- \stopinheritattributes}
-
-\def\dodoattributedbox
- {\startinheritattributes
- \ifvbox\attributeboxcount
- \vbox{\unvbox\attributeboxcount}%
- \else
- \hbox{\unhbox\attributeboxcount}%
- \fi
- \stopinheritattributes}
-
-\def\enableattributeinheritance
- {\ctxlua{nodes.triggering=true}%
- \let\attributedcopy\doattributedcopy
- \let\attributedbox \doattributedbox}
-
-\def\disableattributeinheritance
- {\ctxlua{nodes.triggering=false}%
- \let\attributedcopy\copy
- \let\attributedbox \box}
-
-\disableattributeinheritance
-
-% \enableattributeinheritance % will become default
-
\protect \endinput
% test case
diff --git a/tex/context/base/back-ini.lua b/tex/context/base/back-ini.lua
new file mode 100644
index 000000000..0a11c2ef7
--- /dev/null
+++ b/tex/context/base/back-ini.lua
@@ -0,0 +1,75 @@
+if not modules then modules = { } end modules ['back-ini'] = {
+ version = 1.001,
+ comment = "companion to back-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+backends = backends or { }
+
+local function nothing() return nil end
+
+backends.nodeinjections = {
+ rgbcolor = nothing,
+ cmykcolor = nothing,
+ graycolor = nothing,
+ spotcolor = nothing,
+ transparency = nothing,
+ overprint = nothing,
+ knockout = nothing,
+ positive = nothing,
+ negative = nothing,
+ effect = nothing,
+ startlayer = nothing,
+ stoplayer = nothing,
+ switchlayer = nothing,
+}
+
+backends.codeinjections = {
+ insertmovie = nothing,
+}
+
+backends.registrations = {
+ grayspotcolor = nothing,
+ rgbspotcolor = nothing,
+ cmykspotcolor = nothing,
+ grayindexcolor = nothing,
+ rgbindexcolor = nothing,
+ cmykindexcolor = nothing,
+ spotcolorname = nothing,
+ transparency = nothing,
+}
+
+local nodeinjections = backends.nodeinjections
+local codeinjections = backends.codeinjections
+local registrations = backends.registrations
+
+backends.current = "unknown"
+
+function backends.install(what)
+ if type(what) == "string" then
+ backends.current = what
+ what = backends[what]
+ if what then
+ local wi = what.nodeinjections
+ if wi then
+ for k, v in next, wi do
+ nodeinjections[k] = v
+ end
+ end
+ local wi = what.codeinjections
+ if wi then
+ for k, v in next, wi do
+ codeinjections[k] = v
+ end
+ end
+ local wi = what.registrations
+ if wi then
+ for k, v in next, wi do
+ registrations[k] = v
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/back-ini.tex b/tex/context/base/back-ini.tex
new file mode 100644
index 000000000..a60b6a329
--- /dev/null
+++ b/tex/context/base/back-ini.tex
@@ -0,0 +1,896 @@
+%D \module
+%D [ file=back-ini,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=Initialization,
+%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.
+
+\writestatus{loading}{ConTeXt Backend Macros / Initialization}
+
+\registerctxluafile{back-ini}{1.001}
+
+%D We currently have a curious mix between tex and lua backend
+%D handling but eventually most will move to lua.
+
+\unprotect
+
+%D Right from the start \CONTEXT\ had a backend system based on
+%D runtime pluggable code. As most backend issues involved specials
+%D and since postprocessors had not that much in common, we ended up
+%D with a system where we could switch backend as well as output code
+%D for multiple backends at the same time.
+%D
+%D Because \LUATEX\ has the backend built in, and since some backend
+%D issues have been moved to the frontend I decided to provide new
+%D backend code for \MKIV, starting with what was actually used.
+%D
+%D At this moment \DVI\ is no longer used for advanced document
+%D output and we therefore dropped support for this format. Future
+%D versions might support more backends again, but this has a low
+%D priority.
+%D
+%D The big question is: what is to be considered a backend issue and
+%D what not. For the moment we treat image inclusion, object reuse,
+%D position tracking and color as frontend issues, if only because we
+%D deal with them via \LUA\ code and as such we don't depend too much
+%D on macro calls that need to inject code for the backend.
+%D
+%D Not everything here makes sense and the content of this file will
+%D definitely change.
+
+%D We use a couple of (global) variables because it saves us the
+%D trouble of dealing with arguments.
+
+\letempty \@@DriverFieldName
+\letempty \@@DriverFieldWidth
+\letempty \@@DriverFieldHeight
+\letempty \@@DriverFieldDefault
+\letempty \@@DriverFieldNumber
+\letempty \@@DriverFieldNumber
+\letempty \@@DriverFieldStyle
+\letempty \@@DriverFieldColor
+\letempty \@@DriverFieldBackgroundColor
+\letempty \@@DriverFieldFrameColor
+\letempty \@@DriverFieldLayer
+\letempty \@@DriverFieldOption
+\letempty \@@DriverFieldAlign
+\letempty \@@DriverFieldClickIn
+\letempty \@@DriverFieldClickOut
+\letempty \@@DriverFieldRegionIn
+\letempty \@@DriverFieldRegionOut
+\letempty \@@DriverFieldAfterKey
+\letempty \@@DriverFieldFormat
+\letempty \@@DriverFieldValidate
+\letempty \@@DriverFieldCalculate
+\letempty \@@DriverFieldFocusIn
+\letempty \@@DriverFieldFocusOut
+
+\letempty \@@DriverCommentLayer
+\letempty \@@DriverAttachmentLayer
+
+\letempty \@@DriverImageBox
+\letempty \@@DriverImageOptions
+\letempty \@@DriverImageWidth
+\letempty \@@DriverImageHeight
+\letempty \@@DriverImageFile
+\letempty \@@DriverImageLabel
+\letempty \@@DriverImageType
+\letempty \@@DriverImageMethod
+\letempty \@@DriverImagePage
+
+\newif\ifcollectreferenceactions
+
+%D \macros
+%D {dostartgraymode,dostopgraymode,
+%D dostartrgbcolormode,dostartcmykcolormode,dostartgraycolormode,dostopcolormode}
+%D
+%D Switching to and from color can be done in two ways:
+%D
+%D \startitemize[packed,n]
+%D \item insert driver specific commands
+%D \item pass instructions to the output device
+%D \stopitemize
+%D
+%D The first approach is more general and lays the
+%D responsibility at the driver side. Probably due to the fact
+%D that \TEX\ does not directly support color, we have been
+%D confronted for the last few years with changing special
+%D definitions. The need for support depends on how a macro
+%D package handles colored text that crosses the page boundary.
+%D Again, there are two approaches.
+%D
+%D \startitemize[packed,n]
+%D \item let \TEX\ do the job
+%D \item let the driver handle things
+%D \stopitemize
+%D
+%D The first approach is as driver independant as possible and
+%D can easily be accomplished by using \TEX's mark mechanism.
+%D In \CONTEXT\ we follow this approach. More and more, drivers
+%D are starting to support color, including stacking them.
+%D
+%D Colors as well as grayscales can be represented in scales
+%D from~0 to~1. When drivers use values in the range 0..255,
+%D this value has to be adapted in the translation process.
+%D Technically it's possible to get a grayscale from combining
+%D colors. In the \cap{RGB} color system, a color with Red,
+%D Green and Blue components of 0.80 show the same gray as a
+%D Gray Scale specified 0.80. The \cap{CMYK} color system
+%D supports a Black component apart from Cyan, Magenta and
+%D Yellow.
+%D
+%D Depending on the target format, color support differs from
+%D gray support. PostScript for example offers different
+%D operators for setting gray and color. This is because
+%D printing something using three colors is someting else than
+%D printing with just black.
+%D
+%D In \CONTEXT\ we have implemented a color subsystem that
+%D supports the use of well defined colors that, when printed
+%D in black and white, still can be distinguished. This
+%D approach enables us to serve both printed and electronic
+%D versions, using colored text and illustrations. More on the
+%D fundamentals of this topic can be found in the \cap{MAPS} of
+%D the Dutch User Group, 14 (95.1).
+%D
+%D To satisfy all those needs, we define four specials which
+%D supply enough information for drivers to act upon. We
+%D could have used more general commands with the keywords
+%D 'rgb' and 'gray', but because these specials are used often,
+%D we prefer the more direct and shorter alternative.
+%D
+%D We start with the installation of color and grayscale
+%D specials. The values are in the range 0..1 (e.g. 0.25).
+%D
+%D \starttyping
+%D \dostartgraymode {gray} ... \dostopgraymode
+%D \dostartrgbcolormode {red} {green} {blue} ... \dostopcolormode
+%D \dostartcmykcolormode {cyan} {magenta} {yellow} {black} ... \dostopcolormode
+%D \dostartgraycolormode {gray} ... \dostopcolormode
+%D \stoptyping
+%D
+%D Because we can expect conflicts between drivers, we
+%D implement them as category \type{or}. In previous versions
+%D of \DVIPSONE\ the use of their color||specials did not
+%D interfere with the PostScript ones, but recent versions do.
+
+\let \dostartgraymode \gobbleoneargument
+\let \dostopgraymode \donothing
+\let \dostartrgbcolormode \gobblethreearguments
+\let \dostartcmykcolormode \gobblefourarguments
+\let \dostartgraycolormode \gobbleoneargument
+\let \dostopcolormode \donothing
+\let \dostartspotcolormode \gobbletwoarguments
+\let \doregisterrgbspotcolor \gobblesevenarguments
+\let \doregistercmykspotcolor \gobbleeightarguments
+\let \doregistergrayspotcolor \gobblefourarguments
+\let \doregisterrgbindexcolor \gobblesevenarguments
+\let \doregistercmykindexcolor \gobbleeightarguments
+\let \doregistergrayindexcolor \gobblefourarguments
+\let \doregisterspotcolorname \gobbletwoarguments
+\let \dostartnonecolormode \donothing
+\let \doregisternonecolor \donothing
+
+%D \macros
+%D {doinsertsoundtrack}
+%D
+%D Sounds are (for the moment) just files with
+%D associated options.
+%D
+%D \starttyping
+%D \doinsertsoundtrack {file} {label} {options}
+%D \stoptyping
+
+\let \doinsertsoundtrack \gobblethreearguments
+
+%D \macros
+%D {dostartrotation,dostoprotation,
+%D dostartscaling,dostopscaling,
+%D dostartmirroring,dostopmirroring,
+%D dostartnegative,dostopnegative}
+%D dostartoverprint,dostopoverprint}
+%D
+%D We support a couple of transformations and renderings:
+%D
+%D \starttyping
+%D \dostartrotation {angle} ... \dostoprotation
+%D \dostartscaling {x} {y} ... \dostopscaling
+%D \dostartmirroring {x} {y} ... \dostopmirroring
+%D \stoptyping
+
+\let \dostartrotation \gobbleoneargument
+\let \dostoprotation \donothing
+\let \dostartscaling \gobbletwoarguments
+\let \dostopscaling \donothing
+\let \dostartmirroring \donothing
+\let \dostopmirroring \donothing
+
+\let \dostartnegative \donothing
+\let \dostopnegative \donothing
+\let \dostartoverprint \donothing
+\let \dostopoverprint \donothing
+
+%D The following two specials are used in for instance \type
+%D {\vadjust}'d margin material inside colored paragraphs.
+
+\let \dostartgraphicgroup \donothing
+\let \dostopgraphicgroup \donothing
+
+%D \macros
+%D {doselectfirstpaperbin,
+%D doselectsecondpaperbin}
+%D
+%D Here are some very printer||specific ones. No further
+%D comment.
+
+\let \doselectfirstpaperbin \donothing
+\let \doselectsecondpaperbin \donothing
+
+%D \macros
+%D {doovalbox}
+%D
+%D When we look at the implementation, this is a complicated
+%D one. There are seven arguments.
+%D
+%D \starttyping
+%D \doovalbox {w} {h} {d} {linewidth} {radius} {stroke} {fill} {variant}
+%D \stoptyping
+%D
+%D This command has to return a \type{\vbox} which can be used
+%D to lay over another one (with text). The radius is in
+%D degrees, the stroke and fill are~\type{1} (true) of~\type{0}
+%D (false).
+
+\let \doovalbox \gobbleeightarguments
+
+%D \macros
+%D {dostartclipping,dostopclipping}
+%D
+%D Clipping is implemented in such a way that an arbitrary code
+%D can be fed.
+%D
+%D \starttyping
+%D \dostartclipping {pathname} {width} {height}
+%D \dostopclipping
+%D \stoptyping
+
+\let \dostartclipping \gobblethreearguments
+\let \dostopclipping \donothing
+
+%D \macros
+%D {dosetupidentity}
+%D
+%D We can declare some characteristics of the document with
+%D
+%D \starttyping
+%D \dosetupidentity {title} {subject} {author} {creator} {date} {keys}
+%D \stoptyping
+%D
+%D All data is in string format.
+
+\let \dosetupidentity \gobblesixarguments
+
+%D \macros
+%D {dosetuppaper}
+%D
+%D This special can be used to tell the driver what page size
+%D to use. The special takes three arguments.
+%D
+%D \starttyping
+%D \dosetuppaper {type} {width} {height}
+%D \stoptyping
+%D
+%D The type is one of the common identifiers, like A4, A5 or
+%D B2.
+
+\let \dosetuppaper \gobblethreearguments
+
+%D \macros
+%D {dosetupprinter}
+%D
+%D Some drivers enable the user to specify the paper type
+%D used and/or page dimensions to be taken into account.
+%D
+%D \starttyping
+%D \dosetupprinter {type} {hoffset} {voffset} {width} {height}
+%D \stoptyping
+%D
+%D The first argument is one of \type{letter}, \type{legal},
+%D \type{A4}, \type{A5} etc. The dimensions are in
+%D basepoints.
+
+\let \dosetupprinter \gobblefourarguments
+
+%D \macros
+%D {dosetupopenaction, dosetupclosaction,
+%D dosetupopenpageaction, dosetupclospageaction,
+%D dosetupinteraction,
+%D dosetupscreen,
+%D dosetupviewmode}
+%D
+%D Here come some obscure interactive commands. Probably the
+%D specs will change with the development of the macros that
+%D use them.
+%D
+%D The first ones can be used to set up the interaction.
+%D
+%D \starttyping
+%D \dosetupinteraction
+%D \stoptyping
+%D
+%D Normally this command does nothing but giving a message
+%D that some scheme is supported.
+%D
+%D \starttyping
+%D \dosetupstartaction
+%D \dosetupstopaction
+%D \stoptyping
+%D
+%D These two setup the actions to be executed when the document
+%D is opened and closed.
+%D
+%D The next commands sets up the page and screen. They are
+%D kind of related.
+%D
+%D \starttyping
+%D \dosetuppage {hoffset} {voffset} {width} {height} {options}
+%D \dosetupscreen {hoffset} {voffset} {width} {height} {options}
+%D \stoptyping
+%D
+%D The first four arguments are in points. Option~1 results in a
+%D full screen launch.
+%D
+%D \starttyping
+%D \dosetuppageview {keyword}
+%D \stoptyping
+%D
+%D For the moment we only support \type{fit}.
+
+\let \dosetupinteraction \donothing
+\let \dosetupopenaction \donothing
+\let \dosetupscreen \gobblefourarguments
+\let \dosetuppageview \gobbleoneargument
+\let \dosetupcloseaction \donothing
+\let \dosetupopenpageaction \donothing
+\let \dosetupclosepageaction \donothing
+\let \dosetuprenderingopenpageaction \donothing
+\let \dosetuprenderingclosepageaction \donothing
+\let \dosetupcropbox \gobblefourarguments
+\let \dosetuptrimbox \gobblefourarguments
+\let \dosetupartbox \gobblefourarguments
+\let \dosetupbleedbox \gobblefourarguments
+
+%D \macros
+%D {dostarthide,
+%D dostophide}
+%D
+%D Not every part of the screen is suitable for paper. Menus
+%D for instance have no meaning on an non||interactive medium.
+%D These elements are hidden by means of:
+%D
+%D \starttyping
+%D \dostarthide .. \dostophide
+%D \stoptyping
+
+\let \dostarthide \donothing
+\let \dostophide \donothing
+
+%D \macros
+%D {dostartgotolocation, dostopgotolocation,
+%D dostartgotorealpage, dostopgotorealpage}
+%D
+%D When we want to support hypertext buttons, again we have
+%D to deal with two concepts.
+%D
+%D \startitemize[packed,n]
+%D \item let \TEX\ highlight the text
+%D \item let the driver show us where to click
+%D \stopitemize
+%D
+%D The first approach is the most secure one. It gives us
+%D complete control over the visual appearance of hyper
+%D buttons. The second alternative lets the driver guess what
+%D part of the text needs highlighting. As long as we deal with
+%D not too complicated textual buttons, this is no problem.
+%D It's even a bit more efficient when we take long mid
+%D paragraph active regions into account. When we let \TEX\
+%D handle active sentences {\em for instance marked like this
+%D one}, we have to take care of line- and pagebreaks ourselve.
+%D However, it's no trivial matter to let a driver find out
+%D where things begin and end. Because most hyperlinks can be
+%D found in tables of contents and registers, the saving in
+%D terms of bytes can be neglected and the first approach is a
+%D clear winner.
+%D
+%D The most convenient way of cross||referencing is using named
+%D destinations. A more simple scheme is using page numbers as
+%D destinations. Because the latter alternative can often be
+%D implemented more efficient, and because we cannot be sure
+%D what scheme a driver supports, we always have to supply a
+%D pagenumber, even when we use named destinations.
+%D
+%D To enable a driver to find out what to make active, we have
+%D to provide begin and endpoints, so like with color, we use
+%D pairs of specials. The first scheme can be satisfied with
+%D proper dimensions of the areas to be made active.
+%D
+%D The interactive real work is done by the following four
+%D specials. The reason for providing the first one with both
+%D a label and a number, is a result of the quite poor
+%D implementation of \type{pdfmarks} in version 1.0 of
+%D Acrobat. Because only pagenumbers were supported as
+%D destination, we had to provide both labels (\DVIWINDO) and
+%D pagenumbers (\PDF). Some drivers use start stop pairs.
+%D
+%D \starttyping
+%D \dostartgotolocation {w} {h} {url} {file} {label} {page}
+%D \dostartgotorealpage {w} {h} {url} {file} {page}
+%D \stoptyping
+%D
+%D Their counterparts are:
+%D
+%D \starttyping
+%D \dostopgotolocation
+%D \dostopgotorealpage
+%D \stoptyping
+%D
+%D The internal alternative is used for system||generated
+%D links, the external one for user||generated links. The
+%D Uniform Resource Locator can be used to let the reader
+%D surf the net.
+
+\let \dostartgotolocation \gobblesixarguments
+\let \dostopgotolocation \donothing
+\let \dostartgotorealpage \gobblefourarguments
+\let \dostopgotorealpage \donothing
+
+%D One may wonder why jumps to page and location are not
+%D combined. By splitting them, we enable macro||packages to
+%D force the prefered alternative, while on the other hand
+%D drivers can pick up the alternative desired most.
+
+%D \macros
+%D {dostartgotoJS, doflushJSpreamble}
+%D
+%D Rather special is the option to include and execute
+%D JavaScript code. This is a typical \PDF\ option.
+%D
+%D \starttyping
+%D \dostartgotoJS {w} {h} {script}
+%D \stoptyping
+%D
+%D This not so standard \TEX\ feature should be used with
+%D care. Preamble scripts are flushed by
+%D
+%D \doflushJSpreamble {script}
+
+\let \dostartgotoJS \gobblethreearguments
+\let \dostopgotoJS \donothing
+\let \doflushJSpreamble \gobbleoneargument
+
+%D \macros
+%D {dostartthisislocation, dostopthisislocation,
+%D dostartthisisrealpage, dostopthisisrealpage}
+%D
+%D Before we can goto some location or page, we have to tell
+%D the system where it can be found. Because some drivers
+%D follow the \SGML\ approach of begin||end tags, we have to
+%D support pairs. A possible extension to this scheme is
+%D supplying coordinates for viewing the text.
+%D
+%D The opposite commands of \type{\dogotosomething} have only
+%D one argument:
+%D
+%D \starttyping
+%D \dostartthisislocation {label}
+%D \dostartthisisrealpage {page}
+%D \stoptyping
+%D
+%D These commands are accompanied by:
+%D
+%D \starttyping
+%D \dostopthisislocation
+%D \dostopthisisrealpage
+%D \stoptyping
+%D
+%D As with all interactive commands's they are installed as
+%D \type{and} category specials.
+
+\let \dostartthisislocation \gobbleoneargument
+\let \dostopthisislocation \donothing
+\let \dostartthisisrealpage \gobbleoneargument
+\let \dostopthisisrealpage \donothing
+
+%D In \CONTEXT\ we don't use the \type{\stopsomething}
+%D macros because we let \TEX\ take care of typographic
+%D issues.
+
+%D \macros
+%D {doresetgotowhereever}
+%D
+%D These and others need:
+
+\let \doresetgotowhereever \donothing
+
+%D \macros
+%D {dostartexecutecommand, dostopexecutecommand}
+%D
+%D The actual behavior of the next pair of commands depends
+%D much on the viewing engine. Therefore one cannot depend
+%D too much on their support.
+%D
+%D \starttyping
+%D \dostartexecutecommand {w} {h} {command} {options}
+%D \stoptyping
+%D
+%D At least the next commands are supported (more examples
+%D can be found in \type {spec-fdf.tex}:
+%D
+%D \startlinecorrection\setupalign[middle]\leavevmode
+%D \starttable[|l|l|]
+%D \HL
+%D \NC \bf command \NC \bf action \NC\SR
+%D \HL
+%D \NC first \NC go to the first page \NC\FR
+%D \NC previous \NC go to the previous page \NC\MR
+%D \NC next \NC go to the next page \NC\MR
+%D \NC last \NC go to the last page \NC\MR
+%D \NC backward \NC go back to the link list \NC\MR
+%D \NC forward \NC go forward in the link list \NC\MR
+%D \NC print \NC enter print mode \NC\MR
+%D \NC exit \NC exit viewer \NC\MR
+%D \NC close \NC close document \NC\MR
+%D \NC enter \NC enter viewer \NC\MR
+%D \NC help \NC show help on the viewer \NC\LR
+%D \HL
+%D \stoptable
+%D \stoplinecorrection
+%D
+%D Options are to be passed as a comma separated list of
+%D assignments.
+
+\let \dostartexecutecommand \gobblefourarguments
+\let \dostopexecutecommand \donothing
+
+%D \macros
+%D {dostartobject,
+%D dostopobject,
+%D doresetobjects,
+%D doinsertobject}
+%D
+%D Reuse of object can reduce the output filesize
+%D considerably. Reusable objects are implemented with:
+%D
+%D \starttyping
+%D \dostartobject{class}{name}{width}{height}{depth}
+%D some typeset material
+%D \dostopobject
+%D \stoptyping
+%D
+%D \starttyping
+%D \doinsertobject{class}{name}
+%D \stoptyping
+%D
+%D The savings can be huge in interactive texts. The next macro needs
+%D to be called after a graphic is inserted (in order to clean up
+%D global references).
+%D
+%D \starttyping
+%D \doresetobjects
+%D \stoptyping
+
+\let \dostartobject \gobblefourarguments
+\let \dostopobject \donothing
+\let \doinsertobject \gobbletwoarguments
+\let \doresetobjects \donothing
+
+%D \macros
+%D {doregisterfigure, doregisterfigurecolor}
+%D
+%D Images can be objects as well and it's up to the driver to
+%D handle this. Alternative images are also up to the driver,
+%D and the next macro tells the driver that the previous image
+%D is somehow followed by another and that both have to be
+%D handled together. This is a rather fuzzy model, but for the
+%D moment it suits its purpose: low res screen versions combined
+%D with high res printable ones.
+
+\let \doregisterfigure \gobbletwoarguments
+\let \doregisterfigurecolor \gobbleoneargument
+
+% %D \macros
+% %D {dogetobjectreference}
+% %D
+% %D For very special purposes, one can ask for the internal
+% %D reference to the object. Beware!
+%
+% \let \dogetobjectreference \gobblethreearguments
+%
+% %D The first argument is the name, the second a macro that
+% %D gets the associated value.
+
+%D \macros
+%D {dostartrunprogram, dostoprunprogram,
+%D dostartgotoprofile, dostopgotoprofile,
+%D dobeginofprofile,
+%D doendofprofile}
+%D
+%D These specials are still experimental. They are not yet
+%D supported by the programs the way they should be.
+%D
+%D {\em --- still undocumented ---}
+
+\let \dostartrunprogram \gobblefourarguments
+\let \dostoprunprogram \donothing
+\let \dostartgotoprofile \gobblethreearguments
+\let \dostopgotoprofile \donothing
+\let \dobeginofprofile \gobblefourarguments
+\let \doendofprofile \donothing
+
+%D \macros
+%D {doinsertbookmark}
+%D
+%D Bookmarks, that is viewer generated tables of contents, are
+%D a strange phenomena, mainly because \TEX\ can provide
+%D whatever kind of table in much better quality.
+
+\let \doinsertbookmark \gobblefourarguments
+
+%D This special is called as:
+%D
+%D \starttyping
+%D \doinstallbookmark {level} {nofsubentries} {text} {page} {open}
+%D \stoptyping
+%D
+%D This definition is very \PDF\ oriented, so for more
+%D information we kindly refer to the \PDF\ manuals.
+
+%D \macros
+%D {dosetpagetransition}
+%D
+%D In presentations, fancy page transitions can, at least for a
+%D short moment, let the audience focus at the screen. Like the
+%D previous one, this special is very \PDF.
+%D
+%D \starttyping
+%D \dosetpagetransition{dissolve}{0}
+%D \stoptyping
+%D
+%D Transitions have symbolic names, like dissolve, box, split,
+%D blinds, wipe and glitter. The second argument determines
+%D the wait time (unless zero).
+
+\let \dosetpagetransition \gobbletwoarguments
+
+%D \macros
+%D {dopresettextfield,dopresetlinefield,
+%D dopresetchoicefield,dopresetpopupfield,dopresetcombofield,
+%D dopresetbuttonfield,dopresetcheckfield,
+%D dopresetradiofield,dopresetradiorecord}
+%D
+%D The special drivers are programmed independant from their
+%D calling macros are thereby use the standard \TEX\ way of
+%D passing parameters. Unfortunately fields often have more
+%D than nine characteristics, so we pack some arguments in one.
+%D
+%D \starttyping
+%D \dopresettextfield / \dopresetlinefield
+%D {name} {width} {height} {default} {length}
+%D {style,color} {options} {alignment} {actions}
+%D
+%D \dopresetchoicefield / \dopresetpopupfield / \dopresetcombofield
+%D {name} {width} {height} {default}
+%D {style,color} {options} {values} {actions}
+%D
+%D \dopresetpushfield
+%D {name} {width} {height} {default}
+%D {options} {values} {actions}
+%D
+%D \dopresetcheckfield
+%D {name} {width} {height} {default}
+%D {options} {values} {actions}
+%D
+%D \dopresetradiofield
+%D {name} {width} {height} {default}
+%D {options} {parent} {values} {actions}
+%D
+%D \dopresetradiorecord
+%D {name} {top} {options} {kids} {actions}
+%D \stoptyping
+
+\let \dopresetlinefield \gobbleninearguments
+\let \dopresettextfield \gobbleninearguments
+\let \dopresetchoicefield \gobbleeightarguments
+\let \dopresetpopupfield \gobbleeightarguments
+\let \dopresetcombofield \gobbleeightarguments
+\let \dopresetpushfield \gobblesevenarguments
+\let \dopresetcheckfield \gobblesevenarguments
+\let \dopresetradiofield \gobbleeightarguments
+\let \dopresetradiorecord \gobblefourarguments
+
+%D \macros
+%D {dodefinefieldset,dogetfieldset,doiffieldset}
+%D
+%D Field sets, used in resetting and submitting, are handled
+%D by:
+
+\let \dodefinefieldset \gobbletwoarguments
+\let \dogetfieldset \gobbleoneargument
+\let \doiffieldset \gobbletwoarguments
+
+%D \macros
+%D {dosetfieldstatus}
+%D
+%D For practical reasons we set some field characteristics
+%D using:
+%D
+%D \starttyping
+%D \dosetfieldstatus {mode} {parent} {kids} {root}
+%D \stoptyping
+
+\let \dosetfieldstatus \gobblefourarguments
+
+%D with:
+
+\def\fieldlonermode {0} % no \chardef here
+\def\fieldparentmode{1} % no \chardef here
+\def\fieldchildmode {2} % no \chardef here
+\def\fieldcopymode {3} % no \chardef here
+
+%D \macros
+%D {doregistercalculationset}
+%D
+%D We can define a calculation order list with:
+%D
+%D \starttyping
+%D \doregistercalculationset {set identifier}
+%D \stoptyping
+
+\let \doregistercalculationset \gobbleoneargument
+
+%D \macros
+%D {doinsertcomment, doflushcomments}
+%D
+%D Not so much out of need, but to be complete, we also
+%D implement text annotations, so called comment:
+%D
+%D \starttyping
+%D \doinsertcomment
+%D {title} {width} {height} {color} {open} {symbol} {collect} {data}
+%D \stoptyping
+%D
+%D When enables, comments can be collected and flushed:
+%D
+%D \starttyping
+%D \doflushcomments
+%D \stoptyping
+
+\let \doinsertcomment \gobbleeightarguments
+\let \doflushcomments \donothing
+
+%D \macros
+%D {dostarttransparency,dostoptransparency}
+%D
+%D \starttyping
+%D \dostarttransparency{fraction}{type}
+%D \dostoptransparency
+%D \stoptyping
+%D
+%D Although in \CONTEXT\ transparency is closely integrated
+%D in the color drivers, in the end it is an independent
+%D feature.
+
+\let \dostarttransparency \gobbletwoarguments
+\let \dostoptransparency \donothing
+
+%D \macros
+%D {doattachfile}
+%D
+%D \starttyping
+%D \doattachfile{title}{width}{height}{depth}{color}{symbol}{filename}{source}
+%D \stoptyping
+
+\let \doattachfile \gobbleeightarguments
+
+%D Experimental (properties):
+
+\let \dostartviewerlayer \gobbleoneargument
+\let \dostopviewerlayer \donothing
+\let \dodefineviewerlayer \gobblefivearguments
+\let \domakeviewerlayerlist \gobbleoneargument
+
+\let \doinsertrenderingwindow \gobblefourarguments
+\let \doinsertrendering \gobblefourarguments
+\let \doinsertrenderingobject \gobblefourarguments
+\let \doinsertrenderingobject \gobblefourarguments
+
+\let \dostartfonteffect \gobblethreearguments
+\let \dostopfonteffect \donothing
+
+%D From now on, mapfile loading is also a special; we assume the
+%D more or less standard dvips syntax.
+
+\let \doresetmapfilelist \donothing
+\let \doloadmapfile \gobbletwoarguments % + - = | filename
+\let \doloadmapline \gobbletwoarguments % + - = | fileline
+
+%D \macros
+%D {ifusepagedestinations}
+%D
+%D In \PDF\ version 1.0 only page references were supported,
+%D while in \DVIWINDO\ 1.N only named references were accepted.
+%D Therefore \CONTEXT\ supports both methods of referencing. In
+%D \PDF\ version 1.1 named destinations arrived. Lack of
+%D continuous support of version 1.1 viewers for \MSDOS\
+%D therefore sometimes forces us to prefer page references. As
+%D a bonus, they are faster too and have no limitations. How
+%D fortunate we were having both mechanisms available when the
+%D version 3.0 (\PDF\ version 1.2) viewers proved to be too
+%D bugged to support named destinations.
+
+\newif\ifusepagedestinations
+
+%D \macros
+%D {ifhighlighthyperlinks}
+%D
+%D The next switch can be used to make user hyperlinks are
+%D not highlighted when clicked on.
+
+\newif\ifhighlighthyperlinks
+
+%D \macros
+%D {ifgotonewwindow}
+%D
+%D To make the {\em goto previous jump} feature more
+%D convenient when using more than one file, it makes sense
+%D to force the viewer to open a new window for each file
+%D opened.
+
+\newif\ifgotonewwindow
+
+%D \macros
+%D {jobsuffix}
+%D
+%D By default, \TEX\ produces \DVI\ files which can be
+%D converted to other filetypes. Sometimes it is handy to
+%D know what the target file will be. In other driver
+%D modules we wil set \type {\jobsuffix} to \type {pdf}.
+
+% this will become a mode
+
+\def\jobsuffix{pdf}
+
+\ifdefined\resetsystemmode \else
+ \let\setsystemmode \gobbleoneargument
+ \let\resetsystemmode\gobbleoneargument
+\fi
+
+\def\setjobsuffix#1%
+ {\resetsystemmode\jobsuffix
+ \edef\jobsuffix{#1}%
+ \setsystemmode\jobsuffix}
+
+%D \macros
+%D {everyresetspecials}
+%D
+%D Now what will this one do? We'll see in a few lines.
+
+\newtoks\everyresetspecials
+
+\appendtoksonce
+ \ifdefined\setjobsuffix\setjobsuffix{pdf}\fi
+\to \everyresetspecials
+
+\def\defineoutput{\dodoubleargument\dodefineoutput}
+
+\def\usespecials [#1]{}
+\def\dodefineoutput[#1][#2]{}
+\def\setupoutput [#1]{}
+
+\protect \endinput
diff --git a/tex/context/base/back-pdf.lua b/tex/context/base/back-pdf.lua
new file mode 100644
index 000000000..2488db7f7
--- /dev/null
+++ b/tex/context/base/back-pdf.lua
@@ -0,0 +1,189 @@
+if not modules then modules = { } end modules ['back-pdf'] = {
+ version = 1.001,
+ comment = "companion to back-pdf.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module implements a couple of cleanup methods. We need these
+in order to meet the <l n='pdf'/> specification. Watch the double
+parenthesis; they are needed because otherwise we would pass more
+than one argument to <l n='tex'/>.</p>
+--ldx]]--
+
+local type, next = type, next
+local char, byte, format, gsub = string.char, string.byte, string.format, string.gsub
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+local texsprint, texwrite = tex.sprint, tex.write
+
+ctxcatcodes = tex.ctxcatcodes
+
+pdf = pdf or { } -- global
+
+backends.pdf = pdf -- registered
+
+function pdf.cleandestination(str)
+ texsprint((gsub(str,"[%/%#%<%>%[%]%(%)%-%s]+","-")))
+end
+
+function pdf.cleandestination(str)
+ texsprint((gsub(str,"[%/%#%<%>%[%]%(%)%-%s]+","-")))
+end
+
+function pdf.sanitizedstring(str)
+ texsprint((gsub(str,"([\\/#<>%[%]%(%)])","\\%1")))
+end
+
+function pdf.hexify(str)
+ texwrite("feff")
+ for b in utfvalues(str) do
+ if b < 0x10000 then
+ texwrite(format("%04x",b))
+ else
+ texwrite(format("%04x%04x",b/1024+0xD800,b%1024+0xDC00))
+ end
+ end
+end
+
+function pdf.utf8to16(s,offset) -- derived from j. sauter's post on the list
+ offset = (offset and 0x110000) or 0 -- so, only an offset when true
+ texwrite(char(offset+254,offset+255))
+ for c in utfvalues(s) do
+ if c < 0x10000 then
+ texwrite(char(offset+c/256,offset+c%256))
+ else
+ c = c - 0x10000
+ local c1, c2 = c / 1024 + 0xD800, c % 1024 + 0xDC00
+ texwrite(char(offset+c1/256,offset+c1%256,offset+c2/256,offset+c2%256))
+ end
+ end
+end
+
+pdf.nodeinjections = pdf.nodeinjections or { } -- we hash elsewhere
+pdf.codeinjections = pdf.codeinjections or { } -- we hash elsewhere
+pdf.registrations = pdf.registrations or { } -- we hash elsewhere
+
+local pdfliteral, register = nodes.pdfliteral, nodes.register
+
+local nodeinjections = pdf.nodeinjections
+local codeinjections = pdf.codeinjections
+local registrations = pdf.registrations
+
+function nodeinjections.rgbcolor(r,g,b)
+ return register(pdfliteral(format("%s %s %s rg %s %s %s RG",r,g,b,r,g,b)))
+end
+
+function nodeinjections.cmykcolor(c,m,y,k)
+ return register(pdfliteral(format("%s %s %s %s k %s %s %s %s K",c,m,y,k,c,m,y,k)))
+end
+
+function nodeinjections.graycolor(s)
+ return register(pdfliteral(format("%s g %s G",s,s)))
+end
+
+function nodeinjections.spotcolor(n,f,d,p)
+ if type(p) == "string" then
+ p = p:gsub(","," ") -- brr misuse of spot
+ end
+ return register(pdfliteral(format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)))
+end
+
+function nodeinjections.transparency(n)
+ return register(pdfliteral(format("/Tr%s gs",n)))
+end
+
+function nodeinjections.overprint()
+ return register(pdfliteral("/GSoverprint gs"))
+end
+
+function nodeinjections.knockout()
+ return register(pdfliteral("/GSknockout gs"))
+end
+
+function nodeinjections.positive()
+ return register(pdfliteral("/GSpositive gs"))
+end
+
+function nodeinjections.negative()
+ return register(pdfliteral("/GSnegative gs"))
+end
+
+local effects = {
+ normal = 0,
+ inner = 0,
+ outer = 1,
+ both = 2,
+ hidden = 3,
+}
+
+function nodeinjections.effect(stretch,rulethickness,effect)
+ -- always, no zero test (removed)
+ rulethickness = number.dimenfactors["bp"]*rulethickness
+ effect = effects[effect] or effects['normal']
+ return register(pdfliteral(format("%s Tc %s w %s Tr",stretch,rulethickness,effect))) -- watch order
+end
+
+function nodeinjections.startlayer(name)
+ return register(pdfliteral(format("/OC /%s BDC",name)))
+end
+
+function nodeinjections.stoplayer()
+ return register(pdfliteral("EMC"))
+end
+
+function nodeinjections.switchlayer(name)
+ return register(pdfliteral(format("EMC /OC /%s BDC",name)))
+end
+
+-- code
+
+function codeinjections.insertmovie(spec) -- width, height, factor, repeat, controls, preview, label, foundname
+ local width, height = spec.width, spec.height
+ local options, actions = "", ""
+ if spec["repeat"] then
+ actions = actions .. "/Mode /Repeat "
+ end
+ if spec.controls then
+ actions = actions .. "/ShowControls true "
+ else
+ actions = actions .. "/ShowControls false "
+ end
+ if spec.preview then
+ options = options .. "/Poster true "
+ end
+ if actions ~= "" then
+ actions= "/A <<" .. actions .. ">>"
+ end
+ return format( -- todo: doPDFannotation
+ "\\doPDFannotation{%ssp}{%ssp}{/Subtype /Movie /Border [0 0 0] /T (movie %s) /Movie << /F (%s) /Aspect [%s %s] %s>> %s}",
+ width, height, spec.label, spec.foundname, factor * width, factor * height, options, actions
+ )
+end
+
+local s_template_g = "\\dodoPDFregistergrayspotcolor{%s}{%s}{%s}{%s}{%s}" -- n f d p s (p can go away)
+local s_template_r = "\\dodoPDFregisterrgbspotcolor {%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p r g b
+local s_template_c = "\\dodoPDFregistercmykspotcolor{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p c m y k
+local m_template_g = "\\doPDFregistergrayindexcolor{%s}{%s}{%s}{%s}{%s}" -- n f d p s (p can go away)
+local m_template_r = "\\doPDFregisterrgbindexcolor {%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p r g b
+local m_template_c = "\\doPDFregistercmykindexcolor{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p c m y k
+local s_template_e = "\\doPDFregisterspotcolorname{%s}{%s}" -- name, e -- todo in new backend: gsub(e," ","#20")
+local t_template = "\\presetPDFtransparencybynumber{%s}{%s}{%s}" -- n, a, t
+
+function registrations.grayspotcolor (n,f,d,p,s) states.collect(format(s_template_g,n,f,d,p,s)) end
+function registrations.rgbspotcolor (n,f,d,p,r,g,b) states.collect(format(s_template_r,n,f,d,p,r,g,b)) end
+function registrations.cmykspotcolor (n,f,d,p,c,m,y,k) states.collect(format(s_template_c,n,f,d,p,c,m,y,k)) end
+function registrations.grayindexcolor(n,f,d,p,s) states.collect(format(m_template_g,n,f,d,p,s)) end
+function registrations.rgbindexcolor (n,f,d,p,r,g,b) states.collect(format(m_template_r,n,f,d,p,r,g,b)) end
+function registrations.cmykindexcolor(n,f,d,p,c,m,y,k) states.collect(format(m_template_c,n,f,d,p,c,m,y,k)) end
+function registrations.spotcolorname (name,e) states.collect(format(s_template_e,name,e)) end -- texsprint(ctxcatcodes,format(s_template_e,name,e))
+function registrations.transparency (n,a,t) states.collect(format(t_template ,n,a,t)) end -- too many, but experimental anyway
+
+-- eventually we need to load this runtime
+--
+-- backends.install((environment and environment.arguments and environment.arguments.backend) or "pdf")
+--
+-- but now we need to force this as we also load the pdf tex part which hooks into all kind of places
+
+backends.install("pdf")
diff --git a/tex/context/base/back-pdf.tex b/tex/context/base/back-pdf.tex
new file mode 100644
index 000000000..b7de1051f
--- /dev/null
+++ b/tex/context/base/back-pdf.tex
@@ -0,0 +1,3226 @@
+%D \module
+%D [ file=back-pdf,
+%D version=2009.04.15,
+%D title=\CONTEXT\ Backend Macros,
+%D subtitle=\PDF,
+%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.
+
+\writestatus{loading}{ConTeXt Backend Macros / PDF}
+
+\registerctxluafile{back-pdf}{1.001}
+
+\unprotect
+
+%D When dealing with resources, we share the resource dictionaries
+%D between all xforms. This is inefficent in the sense that when no
+%D resources are used, redundant entries take space, but on the other
+%D hand we save redundant dictionaries so it's a nice compromise. Maybe
+%D that in \LUATEX\ I will reimplement most of the code here anyway.
+
+%D Initialization of fields is tricky. If a field has no
+%D value, it is kind of not there. If ResetForm is used, the
+%D default is assigned, but pushbuttons are spoiled. Adding a
+%D \type {/MK} dictionary helps, but gives ugly down
+%D appearances (displaced with background). What a mess.
+%D Also, in order to get at least something, the \type {/AS}
+%D key should be provided.
+
+%D A couple of variables:
+
+\newtoks \everybackendshipout
+\newtoks \everylastbackendshipout
+
+\let\lastPDFaction\empty
+
+\ifdefined\everyPDFximage \else \newtoks\everyPDFximage \fi
+\ifdefined\everyPDFxform \else \newtoks\everyPDFxform \fi
+\ifdefined\everygoto \else \newtoks\everygoto \fi
+\ifdefined\everysetfield \else \newtoks\everysetfield \fi
+
+%D A few helpers:
+
+\let\PDFcode \pdfliteral
+\def\PDFcontentcode{\pdfliteral}
+\def\PDFdirectcode {\pdfliteral direct}
+
+%D \macros
+%D {PDFobjref}
+%D
+%D Just a shortcut.
+
+% Watch out, \def\PDFobjref#1{\purenumber#1 0 R} also works, but not when
+% #1 == \the\whatever
+
+\def\PDFobjref#1{\purenumber{#1} 0 R}
+
+%D \macros
+%D {PDFswapdir}
+
+\let\PDFswapdir\empty \def\PDFswapdir{\ifcase\inlinedirection\or\or-\fi}
+
+% the pdf spec changed cq. viewers started behaving differently / 5+
+
+\chardef\overcomePDFpage\plusone % page numbers/ beware: optimizers remove this one
+\chardef\overcomePDFpage\plustwo % page:number
+\chardef\overcomePDFpage\plusthree % pdftex page ref feature
+
+%D \macros
+%D {setPDFdestination}
+%D
+%D \PDF\ destinations should obey the specifications laid down
+%D in the \PDF\ reference manual. The next macro strips illegal
+%D characters from the destination name.
+
+\def\setPDFdestination #1{\xdef\PDFdestination{\ctxlua{pdf.cleandestination("\luaescapestring{#1}")}}}
+\def\hexifiedPDFstring #1{\ctxlua{pdf.hexify("\luaescapestring{#1}")}}
+\def\sanitizePDFencoding#1\to#2{\xdef#2{\ctxlua{pdf.hexify("\luaescapestring{#1}")}}}
+
+%D
+
+\def\appendtopdfpageresources #1{\normalexpanded{\global\pdfpageresources{#1\the\pdfpageresources}}}
+\def\appendtopdfpageattributes #1{\normalexpanded{\global\pdfpageattr {#1\the\pdfpageattr }}}
+\def\appendtopdfpagesattributes#1{\normalexpanded{\global\pdfpagesattr {#1\the\pdfpagesattr }}}
+\def\appendtopdfcatalog {\pdfcatalog}
+\def\appendtopdfinfo {\pdfinfo}
+
+\def\resetpdfpageattributes{\global\pdfpageattr\emptytoks}
+\def\resetpdfpageresources {\global\pdfpageresources\emptytoks}
+
+%D Due to the fact that \PDFTEX\ has a different concept of
+%D page attributes, we need:
+
+\appendtoksonce
+ \resetpdfpageattributes
+ \resetpdfpageresources
+\to \everyaftershipout
+
+%D \macros
+%D {insertpdfaction,
+%D insertpdfannotation,
+%D insertpdfannotationobject,
+%D createpdfdictionaryobject,
+%D createpdfarrayobject,
+%D defaultobjectreference,
+%D doPDFgetobjectreference}
+%D
+%D This module deals with \PDF\ support, including fill||in
+%D forms. Before we present the largely unreadable bunch of
+%D macros, we introduce the here||not||defined low level
+%D interface macros. These must be provided by the special
+%D drivers \type{pdf} (\ACROBAT) and \type{tpd} (\PDFTEX).
+%D
+%D \starttyping
+%D \insertpdfaction #1#2#3 width height action
+%D \insertpdfannotation #1#2#3 width height data
+%D \createpdfannotationobject #1#2#3#4#5 class name width height data
+%D \createpdfdictionaryobject #1#2#3 class name data
+%D \createpdfarrayobject #1#2#3 class name data
+%D
+%D \defaultobjectreference #1#2 class name
+%D \doPDFgetobjectreference #1#2#3 class name \PDFobjectreference
+%D \doPDFgetobjectpagereference #1#2#3 class name \PDFobjectreference
+%D \stoptyping
+%D
+%D The keywords reflect their use. For the moment we stick to
+%D keywords, because that way at we get an indication of what
+%D we're doing.
+
+\def\createpdfdictionaryobject#1#2#3%
+ {\flushatshipout
+ {\immediate\pdfobj{<< #3 >>}%
+ \dosetobjectreference{#1}{#2}{\the\pdflastobj}}}
+
+\def\createpdfarrayobject#1#2#3%
+ {\flushatshipout
+ {\immediate\pdfobj{[ #3 ]}%
+ \dosetobjectreference{#1}{#2}{\the\pdflastobj}}}
+
+\def\createpdfannotationobject#1#2#3#4#5%
+ {\insertpdfannotation{#3}{#4}{#5}%
+ \dosetobjectreference{#1}{#2}{\the\pdflastannot}}
+
+\def\createpdfactionobject#1#2#3#4#5%
+ {\insertpdfaction{#3}{#4}{#5}%
+ \dosetobjectreference{#1}{#2}{\the\pdflastannot}}
+
+%D \macros
+%D {insertpdfaction,insertpdfannotation,ifsharePDFactions}
+%D
+%D Next we handle annotations. All link annotations are
+%D implemented using the action dictionary. This enables us to
+%D use multiple actions. The second macro is for instance
+%D used for movie inclusion.
+
+\newif\ifsharePDFactions \sharePDFactionstrue
+
+\def\insertpdfaction#1#2#3%
+ {\xdef\lastPDFcontent{#3}%
+ \ifcollectreferenceactions
+ \global\let\lastPDFaction\lastPDFcontent
+ \else
+ \ifsharePDFactions
+ \ifcase\similarreference\relax
+ \xdef\lastPDFaction{<<\lastPDFcontent>>}%
+ \or
+ \immediate\pdfobj{<<\lastPDFcontent>>}%
+ \xdef\lastPDFaction{\PDFobjref\pdflastobj}%
+ \else
+ % leave \lastPDFaction untouched
+ \fi
+ \else
+ \xdef\lastPDFaction{<<\lastPDFcontent>>}%
+ \fi
+ \pdfannot
+ width #1 height #2 depth \zeropoint
+ {/Subtype /Link
+ /Border [0 0 0]
+ \ifhighlighthyperlinks \else /H /N \fi
+ /A \lastPDFaction}%
+ \fi}
+
+\def\insertpdfannotation#1#2#3%
+ {\pdfannot width #1 height #2 depth \zeropoint{#3}}
+
+%D \macros
+%D {doPDFbookmark}
+%D
+%D Well, isn't the next one ugly? Thanks to the \PDF\
+%D standard.
+
+\def\doPDFbookmark#1#2#3#4#5% to be renamed
+ {\doPDFgetpagereference{#4}\PDFobjectreference
+ \pdfoutline
+ user {<</S /GoTo /D [\PDFobjectreference\space\PDFpageviewwrd]>>}%
+ \ifcase#2 \else count \ifcase#5-\fi#2 \fi
+ {#3}}
+
+%D For special (\METAPOST) effects, we need to build
+%D resource dictionaries. Here is the framework.
+
+\let\docuPDFextgstates \empty
+\let\docuPDFcolorspaces\empty
+\let\docuPDFshades \empty
+
+\def\checkPDFextgstates
+ {\ifx\docuPDFextgstates\empty \else
+ \ifnum\realpageno=\lastpage\relax
+ \createpdfdictionaryobject{FDF}{docuextgstates}{\docuPDFextgstates}%
+ \fi
+ \doPDFgetobjectreference{FDF}{docuextgstates}\PDFobjectreference
+ \appendtopdfpageresources{/ExtGState \PDFobjectreference}%
+ \fi}
+
+\def\checkPDFcolorspaces
+ {\ifx\docuPDFcolorspaces\empty \else
+ \ifnum\realpageno=\lastpage\relax
+ \createpdfdictionaryobject{FDF}{colorspaces}{\docuPDFcolorspaces}%
+ \fi
+ \doPDFgetobjectreference{FDF}{colorspaces}\PDFobjectreference
+ \appendtopdfpageresources{/ColorSpace \PDFobjectreference}%
+ \fi}
+
+\def\checkPDFshades
+ {\ifx\docuPDFshades\empty \else
+ \ifnum\realpageno=\lastpage\relax
+ \createpdfdictionaryobject{FDF}{docushades}{\docuPDFshades}%
+ \fi
+ \doPDFgetobjectreference{FDF}{docushades}\PDFobjectreference
+ \appendtopdfpageresources{/Shading \PDFobjectreference}%
+ \fi}
+
+\def\appendtoPDFdocumentextgstates #1{\xdef\docuPDFextgstates {\docuPDFextgstates \space#1}}
+\def\appendtoPDFdocumentcolorspaces#1{\xdef\docuPDFcolorspaces{\docuPDFcolorspaces\space#1}}
+\def\appendtoPDFdocumentshades #1{\xdef\docuPDFshades {\docuPDFshades \space#1}}
+
+%D Page actions:
+
+\let\lastpdfopenaction \empty
+\let\lastpdfcloseaction\empty
+
+\def\dosetupopenaction {\appendtopdfcatalog{/OpenAction <<\lastPDFaction>>}}
+\def\dosetupcloseaction{\appendtopdfcatalog{/CloseAction <<\lastPDFaction>>}}
+
+\def\dosetupopenpageaction {\glet\lastpdfopenaction \lastPDFaction}
+\def\dosetupclosepageaction{\glet\lastpdfcloseaction\lastPDFaction}
+
+\def\checkPDFpageactions
+ {\iflocation % important since direct
+ \donefalse
+ \ifx\lastpdfopenaction \empty\!!doneafalse\else\donetrue\!!doneatrue\fi
+ \ifx\lastpdfcloseaction\empty\!!donebfalse\else\donetrue\!!donebtrue\fi
+ \ifdone
+ \appendtopdfpageattributes
+ {/AA <<\if!!donea/O <<\lastpdfopenaction >> \fi
+ \if!!doneb/C <<\lastpdfcloseaction>> \fi>>}%
+ \fi
+ \glet\lastpdfopenaction \empty
+ \glet\lastpdfcloseaction\empty
+ \fi}
+
+%D \macros
+%D {ifPDFstrokecolor}
+%D
+%D We can reduce the filesize a bit by setting the next switch
+%D to false. The amount of reduction depends on the use of
+%D color, but don't expect more than a few percent. Zip
+%D compression is already rather efficient in itself.
+
+\newif\ifPDFstrokecolor \PDFstrokecolortrue
+
+%D When submitting forms, we need to communicate the format.
+
+\chardef\submitoutputformat=0 % 0=unknown 1=HTML 2=FDF 3=XML
+
+\def\setsubmitoutputformat#1%
+ {\doifinsetelse{#1}{FDF,fdf}
+ {\chardef\submitoutputformat2}
+ {\doifinsetelse{#1}{XML,xml}
+ {\chardef\submitoutputformat3}
+ {\chardef\submitoutputformat1}}%
+ \relax}
+
+%D Handy to have this available asap:
+
+\ifdefined\everyPDFxform \newtoks\everyPDFxform \fi
+\ifdefined\everyPDFximage \newtoks\everyPDFximage \fi
+
+% once we can be sure that the latest versions of pdftex are
+% available we can use:
+%
+% \pdfobj reserveobjnum \edef\one{\the\pdflastobj}
+% \pdfobj reserveobjnum \edef\two{\the\pdflastobj}
+%
+% \pdfobj useobjnum \one {x}
+% \pdfobj useobjnum \two {x}
+%
+% we then can rewrite part of spec-fdf because the other drivers
+% already support symbolic references
+
+%D \macros
+%D {jobsuffix}
+%D
+%D Being one of the first typographical systems able to support
+%D advances \PDF\ support, \TEX\ is also one of the first
+%D systems to produce high quality \PDF\ code directly. Thanks
+%D to Han The Thanh c.s. the \TEX\ community can leap forward
+%D once again.
+%D
+%D One important characteristic of \PDFTEX\ is that is can
+%D produce standard \DVI\ code as well as \PDF\ code. This
+%D enables us to use one format file to support both output
+%D formats.
+
+%D All modules in this group use specials to tell drivers what
+%D non||\TEX\ actions to take. Because from the \TEX\ point of
+%D view, there is no difference between \DVI\ and \PDF, we
+%D therefore only have to bend the \DVI\ driver support into
+%D \PDF\ support. Technically spoken, specials no longer serve
+%D a purpose, except from ending up as comment in the \PDF\
+%D file.
+%D
+%D Before we continue we need to make sure if indeed those
+%D \PDFTEX\ primitives are permitted. If no primitives are
+%D available, we just stop reading any further.
+
+\pdfoutput = 1
+\pdfhorigin = 1 true in
+\pdfvorigin = 1 true in
+\pdfimageresolution = 300
+\pdfpkresolution = 600
+\pdfdecimaldigits = 10
+\pdfinclusionerrorlevel = 0
+\pdfminorversion = 5
+%pdfuniqueresname = 1
+
+\def\PDFversion{1.\number\pdfminorversion}
+
+%D For some internal testing we need to know the output
+%D suffix.
+
+\setjobsuffix{pdf}
+
+%D \macros
+%D {dosetuppaper}
+%D
+%D If we don't set the paper size, \PDFTEX\ will certainly do
+%D it in a way we don't want, therefore we need:
+
+\def\dosetuppaper#1#2#3%
+ {\global\pdfpagewidth #2\relax
+ \global\pdfpageheight#3\relax}
+
+%D \macros
+%D {doloadmapfile,doloadmapline,doresetmapfilelist}
+
+\def\doresetmapfilelist
+ {\global\let\doresetmapfilelist\relax
+ \pdfmapfile{original-empty.map}}
+
+\def\doloadmapfile #1#2{\pdfmapfile{#1#2}}
+\def\doloadmapline #1#2{\pdfmapline{#1#2}}
+
+%D nasty but needed
+
+\appendtoksonce \loadallfontmapfiles \to \everyPDFximage
+\appendtoksonce \loadallfontmapfiles \to \everyPDFxform
+
+%D left overs:
+
+ \let\currentmovie\s!unknown
+
+ \def\doPDFinsertmov
+ {\bgroup
+ \xdef\currentmovie{\@@DriverImageLabel}%
+ \PointsToBigPoints\@@DriverImageWidth \width
+ \PointsToBigPoints\@@DriverImageHeight\height
+ \let\pdf@@options\empty
+ \let\pdf@@actions\empty
+ \donefalse
+ \expanded{\processallactionsinset[\@@DriverImageOptions]}
+ [\v!controls=>\donetrue,
+ \v!repeat=>\edef\pdf@@actions{\pdf@@actions /Mode /Repeat },
+ \v!preview=>\edef\pdf@@options{\pdf@@options /Poster true }]%
+ \edef\pdf@@actions{\pdf@@actions /ShowControls \ifdone true\else false\fi}%
+ \insertpdfannotation\@@DriverImageWidth\@@DriverImageHeight
+ {/Subtype /Movie
+ /Border [0 0 0]
+ /T (movie \currentmovie)
+ /Movie << /F (\@@DriverImageFile) /Aspect [\width\space\height] \pdf@@options >>
+ /A << \pdf@@actions >>}%
+ \egroup}
+
+%D \macros
+%D {doinsertsoundtrack}
+%D
+%D We use numbers instead of labels to keep track of sounds.
+
+\let\currentsound\s!unknown
+
+\def\doinsertsoundtrack#1#2#3%
+ {\bgroup
+ \xdef\currentsound{#2}%
+ \let\pdf@@actions\empty
+ \@EA\processallactionsinset\@EA
+ [#3]
+ [\v!repeat=>\edef\pdf@@actions{\pdf@@actions /Mode /Repeat }]%
+ \collectdriverresource
+ %\flushatshipout % since it can be buried in a chained box
+ {\insertpdfannotation{0pt}{0pt}
+ {/Subtype /Movie
+ /Border [0 0 0]
+ /T (sound \currentsound)
+ /Movie <</F (#1)>>%
+ \ifx\pdf@@actions\empty\else/A << \pdf@@actions >>\fi}}%
+ \egroup}
+
+%D \macros
+%D {doPDFattachfile}
+
+\def\doPDFfilestreamobject#1#2#3#4%
+ {}
+
+\def\doPDFfilestreamidentifier#1%
+ {0}
+
+\def\doPDFgetfilestreamreference#1#2%
+ {0 0 R}
+
+\def\doattachfile#1#2#3#4#5#6#7#8%
+ {\bgroup % title width height color symbol file
+ \edefconvertedargument\PDFfile{#8}%
+ % beware: the symbol may (indirectly) use the file
+ % reference when typesetting the object number;
+ \presetPDFsymbolappearance{#5}{#6}{#2}{#3}{#4}% sets width/height
+ \startPDFsymbolappearance
+ \doPDFembedfile\PDFfile{#7}{#8}%
+ \doPDFgetembeddedfilereference\PDFfile\PDFobjectreference
+ \setFDFlayer\@@DriverAttachmentLayer
+ \insertpdfannotation{\width}{\totalheight}
+ {/Subtype /FileAttachment
+ /FS \PDFobjectreference\space
+ /Contents (#1)
+ \PDFsymbol
+ \FDFlayer
+ \PDFattributes}%
+ \stopPDFsymbolappearance
+ \egroup}
+
+% semi-public
+
+\def\doPDFembedfile#1#2#3% symbolic name | filename | user name
+ {\edefconvertedargument\PDFfile{#1}%
+ \doifnotflagged{a:\PDFfile}%
+ {\doPDFfilestreamobject{PDFEF}{\PDFfile}{#2}{#3}%
+ \doglobal\setflag{a:\PDFfile}}}
+
+\def\doPDFgetembeddedfilereference#1#2%
+ {\edefconvertedargument\PDFfile{#1}%
+ \doPDFgetobjectreference{PDFEF}\PDFfile#2}
+
+\def\doPDFgetembeddedfilestreamreference#1#2%
+ {\edefconvertedargument\PDFfile{#1}%
+ \doPDFgetfilestreamreference\PDFfile#2} % == \doPDFgetobjectreference{PDFFS}\PDFfile#2
+
+% requested by Jens-Uwe Morawski: permits usage of pdftosrc
+% in viewers that don't support attachments:
+%
+% \definesymbol
+% [ObjectNumber]
+% % [object number {\PDFattachmentnumber[xx]}] % named
+% [object number \PDFattachmentnumber] % current
+%
+% \useattachment[test][xx][test.tex]
+% \setupattachments[symbol=ObjectNumber]
+% \attachment[test]
+
+\def\PDFattachmentnumber
+ {\dosingleargument\doPDFattachmentnumber}
+
+\def\doPDFattachmentnumber[#1]%
+ {\iffirstargument
+ \doPDFfilestreamidentifier{#1}%
+ \else
+ \doPDFfilestreamidentifier\PDFfile
+ \fi}
+
+%D \macros
+%D {...}
+%D
+%D Rather preliminary. We have to wait till the complete specs
+%D show up. As usual, we cannot really check it (Acrobat 6.0
+%D has a bug that inhibits us to make a test file). Half a day
+%D of testing made clear that trying to control the plugin fails
+%D in most cases (we need plugin specs -). We also miss a feature
+%D to let acrobat wait with proceeding (action processing) till
+%D the media clip is ready.
+
+% aiff audio/aiff
+% au audio/basic
+% avi video/avi
+% mid audio/midi
+% mov video/quicktime
+% mp3 audio/x-mp3 (mpeg)
+% mp4 audio/mp4
+% mp4 video/mp4
+% mpeg video/mpeg
+% smil application/smil
+% swf application/x-shockwave-flash
+
+% beware, this is preliminary code, should be improved
+
+\def\PDFrenderingspecs#1{\executeifdefined{PDFMR:#1}\empty}
+
+\def\PDFexecutestartrendering {/Rendition /OP 0 \PDFrenderingspecs\argumentA}
+\def\PDFexecutestoprendering {/Rendition /OP 1 \PDFrenderingspecs\argumentA}
+\def\PDFexecutepauserendering {/Rendition /OP 2 \PDFrenderingspecs\argumentA}
+\def\PDFexecuteresumerendering {/Rendition /OP 3 \PDFrenderingspecs\argumentA}
+
+% todo : sub files
+%
+% \doPDFembedfile{pier-39.png}{pier-39.png}{pier-39.png}%
+% \doPDFgetembeddedfilestreamreference{pier-39.png}\xPDFobjectreference
+% \edef\xxxx{/RF [(pier-39.png) \xPDFobjectreference]}%
+
+% todo: alternative renderings
+%
+% object_1 -> <</Type /Rendition /S /MR /C << /Type /MediaClip ... >> >>
+% object_2 -> <</Type /Rendition /S /MR /C << /Type /MediaClip ... >> >>
+% rendering -> <</Type /Rendition /S /MS [objref_1 objref_2]>>
+
+\def\doinsertrendering#1#2#3#4% tag mime file options
+ {\ifundefined{PDFMR:#1}%
+ \doifinstringelse{://}{#3}\donetrue\donefalse % evt url as keyword
+ \createpdfdictionaryobject{PDFMF}{#1}
+ {/Type /Rendition
+ /S /MR
+ % does not work: /SP << /Type /MediaScreenParam /BE << /B [1 0 0] /O 0.5 >> >>
+ /C << /Type /MediaClip
+ /S /MCD
+ /N (#1)
+ /Alt [() (file not found)] % language id + message
+ /D << /Type /Filespec
+ /F (#3)
+ \ifdone/FS /URL\fi >>
+ /CT (#2) >>}%
+ % common code
+ \doifobjectreferencefoundelse{PDFMS}{#1}
+ {\doPDFgetobjectreference{PDFMS}{#1}\PDFobjectreferenceB}
+ {\doPDFgetobjectreference{PDFMU}{#1}\PDFobjectreferenceB}%
+ \doPDFgetobjectreference{PDFMF}{#1}\PDFobjectreferenceA
+ \setxvalue{PDFMR:#1}% needed /AA actions in /Screen
+ {/R \PDFobjectreferenceA
+ /AN \PDFobjectreferenceB}%
+ \doifobjectreferencefoundelse{PDFMS}{#1}\donothing
+ {\dodoinsertrenderingwindow{PDFMU}{#1}\zeropoint\zeropoint{#4}}%
+ \fi}
+
+\def\doinsertrenderingobject#1#2#3#4% tag class objectname options
+ {\ifundefined{PDFMR:#1}%
+ \doPDFgetobjectreference{#2}{#3}\PDFobjectreference
+ \createpdfdictionaryobject{PDFMF}{#1}
+ {/Type /Rendition
+ /S /MR
+ /C << /Type /MediaClip
+ /S /MCD
+ /N (#1)
+ /D \PDFobjectreference>>}%
+ % common code
+ \doifobjectreferencefoundelse{PDFMS}{#1}
+ {\doPDFgetobjectreference{PDFMS}{#1}\PDFobjectreferenceB}
+ {\doPDFgetobjectreference{PDFMU}{#1}\PDFobjectreferenceB}%
+ \doPDFgetobjectreference{PDFMF}{#1}\PDFobjectreferenceA
+ \setxvalue{PDFMR:#1}% needed /AA actions in /Screen
+ {/R \PDFobjectreferenceA
+ /AN \PDFobjectreferenceB}%
+ \doifobjectreferencefoundelse{PDFMS}{#1}\donothing
+ {\dodoinsertrenderingwindow{PDFMU}{#1}\zeropoint\zeropoint{#4}}%
+ \fi}
+
+\def\doinsertrenderingwindow
+ {\dodoinsertrenderingwindow{PDFMS}}
+
+\def\dodoinsertrenderingwindow#1#2#3#4#5%
+ {\vbox to #4 \bgroup
+ \checkPDFscreenactions{#2}{#5}%
+ \doPDFgetobjectpagereference{PDFMF}{#2}\PDFobjectreferenceA
+ \doPDFgetobjectreference {PDFMF}{#2}\PDFobjectreferenceB
+ \vss
+ \hbox to #3 \bgroup
+ \createpdfannotationobject{#1}{#2}{#3}{#4}
+ {/Subtype /Screen
+ /P \PDFobjectreferenceA
+ /A \PDFobjectreferenceB
+ \PDFattributes
+ /Border [0 0 0]}%
+ \hss
+ \egroup
+ \egroup}
+
+\global\let\PDFrenderingopenpageaction \empty
+\global\let\PDFrenderingclosepageaction\empty
+
+\def\checkPDFscreenactions#1#2%
+ {\let\PDFattributes\empty
+ \iflocation % important since direct -)
+ % the action can either (already) be set by the window handler
+ % or (normally when no window [i.e a zero dimensions one] is present) by keyword
+ \doifinset\v!auto{#2}
+ {% brrr, here instead of in navigation module, must move and become special
+ % now two sided dependency
+ \let\checkrendering\gobbleoneargument
+ \ifx\PDFrenderingopenpageaction \empty
+ \handlereferenceactions{\v!StartRendering{#1}}\dosetuprenderingopenpageaction
+ \fi
+ \ifx\PDFrenderingclosepageaction\empty
+ \handlereferenceactions{\v!StopRendering {#1}}\dosetuprenderingclosepageaction
+ \fi
+ }%
+ \donefalse
+ \ifx\PDFrenderingopenpageaction \empty\!!doneafalse\else\donetrue\!!doneatrue\fi
+ \ifx\PDFrenderingclosepageaction\empty\!!donebfalse\else\donetrue\!!donebtrue\fi
+ \ifdone
+ \edef\PDFattributes
+ {/AA <<\if!!donea/PO <<\PDFrenderingopenpageaction >> \fi
+ \if!!doneb/PC <<\PDFrenderingclosepageaction>> \fi>>}%
+ \fi
+ \global\let\PDFrenderingopenpageaction \empty
+ \global\let\PDFrenderingclosepageaction\empty
+ \fi}
+
+\def\dosetuprenderingopenpageaction {\global\let\PDFrenderingopenpageaction \lastPDFaction}
+\def\dosetuprenderingclosepageaction{\global\let\PDFrenderingclosepageaction\lastPDFaction}
+
+%D For the moment we don't test for alternatives that
+%D themselves have alternatives, especially cylcic
+%D dependencies.
+
+% \def\pdfimmediateximage{\immediate\pdfximage}
+%
+% \def\checkpdfimageattributes
+% {\ifx\PDFfigurereference\empty
+% \global\let\pdfimageattributes\empty
+% \else
+% \immediate\pdfobj
+% {[ << /Image \PDFobjref\PDFfigurereference
+% /DefaultForPrinting true >> ]}%
+% \xdef\pdfimageattributes
+% {attr {/Alternates \PDFobjref\pdflastobj}}%
+% \fi}
+%
+% \global\let\PDFimagecolorreference\empty
+%
+% \def\checkpdfimagecolorspecs
+% {\ifx\pdflastximagecolordepth \undefined
+% \global\let\pdfimagecolorspecs\empty
+% \else\ifx\PDFimagecolorreference\empty
+% \global\let\pdfimagecolorspecs\empty
+% \else
+% \xdef\pdfimagecolorspecs{colorspace \PDFimagecolorreference\space}%
+% \fi\fi
+% \global\let\PDFimagecolorreference\empty}
+
+%D \macros
+%D {doregisterfigure}
+%D
+%D Here is the fuzzy, very special dependant figure
+%D registration special. We need to refer to the innermost
+%D object (ximage).
+
+ \def\doregisterfigure#1#2%
+ {\doifundefined{IM::#1::#2}
+ {\setxvalue{IM::#1::#2}{\the\pdflastximage}}%
+ \xdef\PDFfigurereference{\getvalue{IM::#1::#2}}}
+
+%D \macros
+%D {doovalbox}
+%D
+%D Drawing frames with round corners is inherited from the
+%D main module.
+%D
+%D For drawing ovals we use quite raw \PDF\ code. The next
+%D implementation does not differ that much from the one
+%D implemented in the \POSTSCRIPT\ driver.
+
+\def\doPDFovalcalc#1#2#3%
+ {\PointsToBigPoints{\dimexpr#1+#2\relax}#3}
+
+\def\doovalbox#1#2#3#4#5#6#7#8% todo: \scratchdimen/\scatchbox
+ {\forcecolorhack
+ \bgroup
+ \dimen0=#4\divide\dimen0 \plustwo
+ \doPDFovalcalc{0pt}{+\dimen0}\xmin
+ \doPDFovalcalc{#1}{-\dimen0}\xmax
+ \doPDFovalcalc{#2}{-\dimen0}\ymax
+ \doPDFovalcalc{-#3}{+\dimen0}\ymin
+ \advance\dimen0 by #5%
+ \doPDFovalcalc{0pt}{+\dimen0}\xxmin
+ \doPDFovalcalc{#1}{-\dimen0}\xxmax
+ \doPDFovalcalc{#2}{-\dimen0}\yymax
+ \doPDFovalcalc{-#3}{+\dimen0}\yymin
+ \doPDFovalcalc{#4}{\zeropoint}\stroke
+ \doPDFovalcalc{#5}{\zeropoint}\radius
+ \edef\dostroke{#6}%
+ \edef\dofill{#7}%
+ \edef\mode{\number#8 \space}%
+ % no \ifcase, else \relax in pdfcode
+ \setbox\scratchbox\hbox
+ {\ifnum\dostroke\dofill>\zerocount
+ \ifPDFstrokecolor\else\ifnum\dostroke=\plusone
+ \writestatus\m!colors{pdf stroke color will fail}\wait
+ \fi\fi
+ \PDFcode
+ {q
+ \stroke\space w
+ \ifcase\mode
+ \xxmin\space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 1
+ \xxmin\space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 2
+ \xxmin\space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or % 3
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ h
+ \or % 4
+ \xmin \space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xmin \space \ymax \space l
+ \xmin \space \ymin\space l
+ h
+ \or % 5
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax\space \ymax \space y
+ \xmin \space \ymax \space l
+ \xmin \space \ymin \space l
+ h
+ \or % 6
+ \xmin \space \ymin \space m
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \ymin \space l
+ h
+ \or
+ \xxmin\space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xmin \space \ymax \space l
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ h
+ \or
+ \xmin \space \ymin \space m
+ \xmax \space \ymin \space l
+ \xmax \space \ymax \space l
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ h
+ \or % 9 top open
+ \xmin \space \ymax \space m
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ \xxmax\space \ymin \space l
+ \xmax \space \ymin \space \xmax \space \yymin\space y
+ \xmax \space \ymax \space l
+ \or % 10 right open
+ \xmax \space \ymax \space m
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \yymin\space l
+ \xmin \space \ymin \space \xxmin\space \ymin \space y
+ \xmax\space \ymin \space l
+ \or % 11 bottom open
+ \xmax \space \ymin \space m
+ \xmax \space \yymax\space l
+ \xmax \space \ymax \space \xxmax \space \ymax\space y
+ \xxmin\space \ymax \space l
+ \xmin \space \ymax \space \xmin \space \yymax\space y
+ \xmin \space \ymin \space l
+ \or % 12 left open
+ \xmin \space \ymax \space m
+ \xxmax\space \ymax \space l
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space l
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \ymin \space l
+ \or % 13
+ \xmin \space \ymax \space m
+ \xxmax\space \ymax \space l
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax\space \ymin \space l
+ \or % 14
+ \xmax \space \ymax \space m
+ \xmax \space \yymin\space l
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \ymin \space l
+ \or % 15
+ \xmax \space \ymin \space m
+ \xxmin\space \ymin \space l
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \ymax \space l
+ \or % 16
+ \xmin \space \ymin \space m
+ \xmin \space \yymax\space l
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \xmax \space \ymax \space l
+ \or % 17
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \or % 18
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \or % 19
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 20
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 21
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 22
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \or % 23
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 24
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 25
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 26
+ \xmax \space \yymin\space m
+ \xmax \space \ymin \space \xxmax\space \ymin \space y
+ \xmin \space \yymax\space m
+ \xmin \space \ymax \space \xxmin\space \ymax \space y
+ \or % 27
+ \xxmax\space \ymax \space m
+ \xmax \space \ymax \space \xmax \space \yymax\space y
+ \xxmin\space \ymin \space m
+ \xmin \space \ymin \space \xmin \space \yymin\space y
+ \or % 28
+ \fi
+ \ifnum\mode>8
+ S
+ \else
+ \ifnum\dostroke=\plusone S \fi
+ \ifnum\dofill =\plusone f \fi
+ \fi
+ Q}%
+ \fi}%
+ \wd\scratchbox#1\ht\scratchbox#2\dp\scratchbox#3\box\scratchbox
+ \egroup}
+
+%D \macros
+%D {dostartgraymode,dostopgraymode,
+%D dostartrgbcolormode,dostartcmykcolormode,dostartgraycolormode,
+%D dostopcolormode,
+%D dostartrotation,dostoprotation,
+%D dostartscaling,dostopscaling,
+%D dostartmirroring,dostopmirroring,
+%D dostartnegative,dostopnegative,
+%D dostartoverprint,dostopoverprint}
+
+\def\dostartrotation#1% grouped
+ {\setcalculatedcos\cos{#1}%
+ \setcalculatedsin\sin{#1}%
+ \forcecolorhack
+ \PDFcode{q \cos\space\sin\space\negated\sin\space\cos\space0 0 cm}}
+
+\def\dostoprotation
+ {\PDFcode{Q}}
+
+\def\@@PDFzeroscale{.0001}
+
+\def\dostartscaling#1#2% the test is needed because acrobat is bugged!
+ {\forcecolorhack
+ \PDFcode{q \ifdim#1\points=\zeropoint\@@PDFzeroscale\else#1\fi\space 0 0
+ \ifdim#2\points=\zeropoint\@@PDFzeroscale\else#2\fi\space 0 0 cm}}
+
+\def\dostopscaling
+ {\PDFcode{Q}}
+
+\def\dostartmirroring{\PDFcode{-1 0 0 1 0 0 cm}}
+\def\dostopmirroring {\PDFcode{-1 0 0 1 0 0 cm}}
+
+\def\dostartnegative {\ifdefined\initializePDFnegative \initializePDFnegative \PDFcode{/GSnegative gs}\fi}
+\def\dostopnegative {\ifdefined\initializePDFnegative \initializePDFnegative \PDFcode{/GSpositive gs}\fi}
+\def\dostartoverprint{\ifdefined\initializePDFoverprint\initializePDFoverprint\PDFcode{/GSoverprint gs}\fi}
+\def\dostopoverprint {\ifdefined\initializePDFoverprint\initializePDFoverprint\PDFcode{/GSknockout gs}\fi} % wrong
+
+%D \macros
+%D {doPDFstartgraymode,doPDFstopgraymode,
+%D doPDFstartrgbcolormode,doPDFstartcmykcolormode,doPDFstartgraycolormode,
+%D doPDFstopcolormode}
+%D
+%D In \PDF\ there are two color states, one for strokes and one
+%D for fills. This means that we have to set the color in a
+%D rather redundant looking way. Unfortunately this makes the
+%D \PDF\ file much larger than needed. We can save few bytes
+%D by not setting the stroke color. Due to zip compression we
+%D only save a few percent.
+
+\def\dostartgraymode #1{\PDFcode{#1 g\ifPDFstrokecolor\space#1 G\fi}}
+\def\dostopgraymode {\PDFcode{0 g\ifPDFstrokecolor\space 0 G\fi}}
+\def\dostartrgbcolormode #1#2#3{\PDFcode{#1 #2 #3 rg\ifPDFstrokecolor\space#1 #2 #3 RG\fi}}
+\def\dostartcmykcolormode#1#2#3#4{\PDFcode{#1 #2 #3 #4 k\ifPDFstrokecolor\space#1 #2 #3 #4 K\fi}}
+\def\dostartgraycolormode #1{\PDFcode{#1 g\ifPDFstrokecolor\space#1 G\fi}}
+\def\dostopcolormode {\PDFcode{0 g\ifPDFstrokecolor\space0 G\fi}}
+
+\def\dostartspotcolormode#1#2% redefining spotcolors is not possible anyway
+ {\ifundefined{pdf:scs:#2}%
+ \bgroup
+ \getcommacommandsize[#2]%
+ \ifcase\commalistsize\or
+ \setxvalue{pdf:scs:#2}{#2 SCN #2 scn}% \setxvalue{pdf:scs:#2}{#2 SC #2 sc}%
+ \else
+ \let\PDFspotcolorspecs\empty
+ \def\dospotcolorcommand##1{\edef\PDFspotcolorspecs{\PDFspotcolorspecs##1\space}}%
+ \processcommacommand[#2]\dospotcolorcommand
+ \setxvalue{pdf:scs:#2}{\PDFspotcolorspecs SCN \PDFspotcolorspecs scn}%
+ \fi
+ \egroup
+ \fi
+ \PDFcode{/#1 cs /#1 CS \PDFgetspotcolorspec{#2}}}
+
+\def\PDFgetspotcolorspec#1%
+ {\executeifdefined{pdf:scs:#1}\empty} % better no default than one with too less args
+
+\def\dostartnonecolormode
+ {\PDFcode{/None CS 1 SC /None cs 1 sc}}
+
+%D We need to register the spot colors and their fallbacks.
+
+% we cannot use /DeviceN since GS <=7.21 breaks on it
+% and Jaws does not handle it at all {[/DeviceN [/All|/None]
+% /Device#2 \PDFobjref\pdflastobj]} so we use separation
+% colors that work and print ok
+
+\def\doPDFregistersomespotcolor#1#2#3#4% implemented in the driver
+ {\writestatus\m!systems{missing spot color definition}\wait}
+
+\def\doregisternonecolor % internal command
+ {\doregistergrayspotcolor{None}{1}%
+ \globallet\doregisternonecolor\relax}
+
+\def\dodoPDFregisterrgbspotcolor#1#2#3#4#5#6#7% name noffractions names p's r g b
+ {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{RGB}{0.0 1.0 0.0 1.0 0.0 1.0}%
+ {\ifcase#2\or dup #5 mul exch dup #6 mul exch #7 mul\else#5 #6 #7\fi}}
+
+\def\dodoPDFregistercmykspotcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k
+ {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{CMYK}{0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0}%
+ {\ifcase#2\or dup #5 mul exch dup #6 mul exch dup #7 mul exch #8 mul\else #5 #6 #7 #8\fi}}
+
+\def\dodoPDFregistergrayspotcolor#1#2#3#4#5% name noffractions names p's s
+ {\doPDFregistersomespotcolor{#1}{#2}{#3}{#4}{Gray}{0.0 1.0}%
+ {\ifcase#2\or #5 mul\else #5\fi}}
+
+\def\doregisterrgbspotcolor#1#2#3#4#5#6#7% name noffractions names p's r g b
+ {\ifRGBsupported
+ \dodoPDFregisterrgbspotcolor{#1}{#2}{#3}{#4}{#5}{#6}{#7}%
+ \else
+ \edef\@@cl@@r{#5}\edef\@@cl@@g{#6}\edef\@@cl@@b{#7}%
+ \ifCMYKsupported
+ \convertRGBtoCMYK\@@cl@@r\@@cl@@g\@@cl@@b
+ \dodoPDFregistercmykspotcolor{#1}{#2}{#3}{#4}\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \else
+ \convertRGBtoGRAY\@@cl@@r\@@cl@@g\@@cl@@b
+ \dodoPDFregistergrayspotcolor{#1}{#2}{#3}{#4}\@@cl@@s
+ \fi
+ \fi}
+
+\def\doregistercmykspotcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k
+ {\ifCMYKsupported
+ \dodoPDFregistercmykspotcolor{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}%
+ \else
+ \edef\@@cl@@c{#5}\edef\@@cl@@m{#6}\edef\@@cl@@y{#7}\edef\@@cl@@k{#8}%
+ \ifRGBsupported
+ \convertCMYKtoRGB\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \dodoPDFregisterrgbspotcolor{#1}{#2}{#3}{#4}\@@cl@@r\@@cl@@g\@@cl@@b
+ \else
+ \convertCMYKtoGRAY\@@cl@@c\@@cl@@m\@@cl@@y\@@cl@@k
+ \dodoPDFregistergrayspotcolor{#1}{#2}{#3}{#4}\@@cl@@s
+ \fi
+ \fi}
+
+\def\doregistergrayspotcolor{\dodoPDFregistergrayspotcolor}
+
+%D New and very experimental.
+
+\def\doregistercmykindexcolor#1#2#3#4#5#6#7#8% name noffractions names p's c m y k
+ {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{CMYK}{0.0 1.0 0.0 1.0 0.0 1.0 0.0 1.0}%
+ {dup #5 mul exch dup #6 mul exch dup #7 mul exch #8 mul}}
+
+\def\doregisterrgbindexcolor#1#2#3#4#5#6#7% name noffractions names p's r g b
+ {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{RGB}{0.0 1.0 0.0 1.0 0.0 1.0}%
+ {dup #5 mul exch dup #6 mul exch #7 mul}}
+
+\def\doregistergrayindexcolor#1#2#3#4#5% name noffractions names p's s
+ {\doPDFregistersomeindexcolor{#1}{#2}{#3}{#4}{Gray}{0.0 1.0}%
+ {pop}}
+
+\let\checkpredefinedcolor\predefineindexcolor % we need an index in order to negate bitmaps
+
+\def\doregisterfigurecolor#1% always an index color
+ {\dogetobjectreference{PDFIX}{\internalspotcolorname{#1}}\PDFimagecolorreference}
+
+\def\doregisterspotcolorname#1#2% no need for escape in luatex
+ {\bgroup
+ \let\ascii\empty
+ \def\docommand##1%
+ {\edef\ascii{\ascii
+ \ifx\nexthandledtoken\space
+ \letterhash20%
+ \else\ifx\nexthandledtoken\blankspace
+ \letterhash20%
+ \else
+ ##1%
+ \fi\fi}}%
+ \expanded{\handletokens#2}\with\docommand
+ \letgvalue{@@pdf@@scn@@#1}\ascii
+ \egroup}
+
+\def\doPDFregistersomespotcolor#1#2#3#4#5#6#7% name fractions names p's space domain function
+ {\bgroup
+ \let\spotpops\empty
+ \ifcase#2\or
+ %def\PDFspotcolornames{/Separation /#1}%
+ \edef\PDFspotcolornames{/Separation /\executeifdefined{@@pdf@@scn@@#1}{#1}}%
+ \def\PDFspotcolordomain{0.0 1.0}%
+ \else
+ \dorecurse{#2}{\edef\spotpops{\spotpops pop }}%
+ \let\PDFspotcolornames \empty
+ \let\PDFspotcolordomain\empty
+ \def\dospotcolorcommand##1%
+ {\edef\PDFspotcolornames {\PDFspotcolornames/\executeifdefined{@@pdf@@scn@@##1}{##1}\space}%
+ \edef\PDFspotcolordomain{\PDFspotcolordomain 0.0 1.0\space}}%
+ \processcommacommand[#3]\dospotcolorcommand
+ \edef\PDFspotcolornames{/DeviceN [\PDFspotcolornames]}%
+ \fi
+ \immediate \pdfobj stream attr
+ {/FunctionType 4 /Domain [\PDFspotcolordomain] /Range [#6]}{{\spotpops#7}}%
+ \immediate \pdfobj
+ {[\PDFspotcolornames\space /Device#5 \PDFobjref\pdflastobj]}%
+ \dosetobjectreference{PDFCS}{#1}{\the\pdflastobj}%
+ \appendtoPDFdocumentcolorspaces{/#1 \PDFobjref\pdflastobj}%
+ \egroup}
+
+%D New and very experimental.
+
+\def\doPDFregistersomeindexcolor#1#2#3#4#5#6#7% name fractions names p's space domain function
+ {\bgroup
+ \let\spotpops\empty
+ \dorecurse{#2}{\edef\spotpops{\spotpops exch pop\space}}%
+ \let\PDFspotcolornames \empty
+ \let\PDFspotcolordomain\empty
+ \def\docommand##1%
+ {%\edef\PDFspotcolornames {\PDFspotcolornames/##1\space}%
+ \edef\PDFspotcolornames{\PDFspotcolornames/\executeifdefined{@@pdf@@scn@@##1}{##1}\space}%
+ \edef\PDFspotcolordomain{\PDFspotcolordomain 0.0 1.0\space}}%
+ \processcommacommand[#3,None]\docommand
+ \let\PDFcolorindexvector\empty
+ \def\docommand##1%
+ {\scratchdimen##1\points
+ \scratchdimen\recurselevel\scratchdimen
+ \scratchcounter\scratchdimen
+ \divide\scratchcounter \maxcard
+ \edef\PDFcolorindexvector{\PDFcolorindexvector\uchexnumbers\scratchcounter}}%
+ %\dostepwiserecurse\zerocount{255}\plusone
+ \dostepwiserecurse{255}\zerocount\minusone % we need to negate
+ {\rawprocesscommacommand[#4,1]\docommand
+ \xdef\PDFcolorindexvector{\PDFcolorindexvector\space}}%
+ \immediate \pdfobj stream attr
+ {/FunctionType 4 /Domain [\PDFspotcolordomain] /Range [#6]}{{\spotpops#7}}%
+ \immediate \pdfobj
+ {[/Indexed
+ [/DeviceN [\PDFspotcolornames] /Device#5 \the\pdflastobj\space0 R] %
+ 255 <\PDFcolorindexvector>]}%
+ \dosetobjectreference{PDFIX}{#1}{\the\pdflastobj}%
+ \appendtoPDFdocumentcolorspaces{/#1_INDEXED \the\pdflastobj\space0 R}%
+ \egroup}
+
+%D \macros
+%D {dostarttransparency,dostoptransparency}
+%D
+%D For transparency, we need to implement a couple of
+%D auxiliary macros. If needed, we will generalize them later.
+
+\def\@@PDT{@PDT@}
+
+\ifx\PDFcurrenttransparency\undefined
+ \newcount\PDFcurrenttransparency \PDFcurrenttransparency=0 % -1
+\fi
+
+\def\assignPDFtransparency#1#2%
+ {\edef\PDFtransparencyidentifier{/Tr#1}%
+ \edef\PDFtransparencyreference{\PDFobjref{#2}}}
+
+\def\presetPDFtransparency#1#2%
+ {\initializePDFtransparency
+ \executeifdefined{\@@PDT#1:#2}{\dopresetPDFtransparency{#1}{#2}}}
+
+\def\dopresetPDFtransparency#1#2%
+ {\global\advance\PDFcurrenttransparency \plusone
+ \immediate\pdfobj{\PDFtransparancydictionary{#1}{#2}{}}%
+ \edef\PDFtransparencyidentifier{/Tr\the\PDFcurrenttransparency}%
+ \edef\PDFtransparencyreference {\PDFobjref\pdflastobj}%
+ \setxvalue{\@@PDT#1:#2}%
+ {\noexpand\assignPDFtransparency{\the\PDFcurrenttransparency}{\the\pdflastobj}}%
+ \appendtoPDFdocumentextgstates
+ {\PDFtransparencyidentifier\space
+ \PDFtransparencyreference\space}}
+
+\def\initializePDFtransparency
+ {\immediate\pdfobj{\PDFtransparancydictionary{1}{1}{/AIS false}}%
+ \xdef\PDFtransparencyresetidentifier{/Tr0}%
+ \xdef\PDFtransparencyresetreference{\PDFobjref\pdflastobj}%
+ \setxvalue{\@@PDT0:0}%
+ {\noexpand\assignPDFtransparency{0}{\the\pdflastobj}}%
+ \appendtoPDFdocumentextgstates
+ {\PDFtransparencyresetidentifier\space
+ \PDFtransparencyresetreference\space}%
+ \global\let\initializePDFtransparency\relax}
+
+%D Transparency support:
+
+\def\PDFtransparancydictionary#1#2#3% type fraction extras
+ {<</Type /ExtGState
+ /ca #2 /CA #2
+ /BM /\ifcase#1 Normal\or Normal\or Multiply\or Screen\or
+ Overlay\or SoftLight\or HardLight\or ColorDodge\or
+ ColorBurn\or Darken\or Lighten\or Difference\or
+ Exclusion\else Compatible\fi
+ #3>>}
+
+\def\dodoPDFstarttransparency#1#2%
+ {\presetPDFtransparency{#1}{#2}%
+ \PDFcode{\PDFtransparencyidentifier\space gs }}
+
+\def\dodoPDFstoptransparency
+ {\PDFcode{/Tr0 gs }}
+
+\def\dostarttransparency
+ {\global\let\dostarttransparency\dodoPDFstarttransparency
+ \global\let\dostoptransparency \dodoPDFstoptransparency
+ \initializetransparency
+ \dostarttransparency}
+
+% This is tricky: because a text stream is handled before
+% the page body is built, we can run into stops that will
+% match an outer start; however, the stop is needed in case
+% of a text color: [text color text] [other color text] on a
+% first page combined with color splitting will go wrong if
+% we stick to the relaxing method.
+
+% \def\dostoptransparency
+% {\initializetransparency
+% \dodoPDFstoptransparency}
+
+%D These use:
+
+\let\initializetransparency\relax
+
+\let\PDFtransparencyresetreference \empty
+\let\PDFtransparencyresetidentifier\empty
+
+\let\PDFtransparencyreference \empty
+\let\PDFtransparencyidentifier\empty
+
+%D New trickery:
+
+\def\dostartgraphicgroup{\PDFcode{q}}
+\def\dostopgraphicgroup {\PDFcode{Q}}
+
+%D \macros
+%D {dostartclipping,dostopclipping}
+%D
+%D Clipping in \PDFTEX\ is rather trivial. We can even hook
+%D in \METAPOST\ without problems.
+
+\def\dostartclipping#1#2#3%
+ {\PointsToBigPoints{#2}\width
+ \PointsToBigPoints{#3}\height
+ \grabMPclippath{#1}{1}\width\height
+ {0 0 m \width\space 0 l \width \height l 0 \height l}%
+ \pdfliteral % PDFcode ?
+ {q 0 w \MPclippath\space W n}}
+
+\def\dostopclipping
+ {\pdfliteral{Q n}} % PDFcode
+
+%D \macros
+%D {dosetupinteraction}
+%D
+%D Nothing special is needed to enable \PDF\ commands and
+%D interaction. We stick with a message.
+
+\def\dosetupinteraction
+ {\showmessage\m!interactions{21}{pdftex}}
+
+%D \macros
+%D {doresetgotowhereever,
+%D dostartthisisrealpage,dostartthisislocation,
+%D dostartgotorealpage,dostartgotolocation,dostartgotoJS}
+%D
+%D The interactions macros are the core of this module. We
+%D support both page destinations and named ones. We don't
+%D need the \type{\stop}||alternatives. We also don't need
+%D to set the special that sets the real page number.
+
+%D In the goto specials we took care of secondary references.
+%D Here we define the macros used.
+
+\def\doresetgotowhereever
+ {\global\let\secondaryPDFreferences\empty}
+
+\doresetgotowhereever % just to be sure
+
+% we can (in etex) share more by testing on this
+
+\def\savesecondaryPDFreference#1%
+ {\@EA\xdef\csname PDF-SR:\the\nofsecondaryreferences\endcsname{#1}}
+
+\def\savesecondaryPDFreference % #1 == \action
+ {\global\@EA\let\csname PDF-SR:\the\nofsecondaryreferences\endcsname}
+
+% test should happen in core-ref
+
+\def\getsecondaryPDFreferences
+ {\ifcase\nofsecondaryreferences\else
+ \ifcsname PDF-SR:\the\nofsecondaryreferences\endcsname
+ \xdef\secondaryPDFreferences{/Next <<\csname PDF-SR:\the\nofsecondaryreferences\endcsname\space\secondaryPDFreferences>>}%
+ \fi
+ \global\advance\nofsecondaryreferences \minusone
+ \expandafter\getsecondaryPDFreferences
+ \fi}
+
+%D \macros
+%D {dostartthisislocation}
+%D
+%D Next we define the macros that deal with hyperreferencing,
+%D graphic inclusion and general document features. These are
+%D the olderst ones. I won't comment much because one needs
+%D knowledge of \PDF\ itself, and explaning \PDF\ is beyond
+%D this documentation.
+
+\def\dostartthisislocation#1%
+ {\bgroup
+ \setPDFdestination{#1}%
+ \ifx\PDFdestination\empty \else
+ \pdfdest name {\PDFdestination}\PDFpageviewkey
+ \fi
+ \egroup}
+
+\def\locationfilesuffix{pdf}
+
+\def\dostartgotolocation#1#2#3#4#5#6%
+ {\bgroup
+ \doifelsenothing{#3}
+ {\setPDFdestination{#5}%
+ \doifelsenothing\PDFdestination
+ {\let\action\empty}
+ {\doifelsenothing{#4}
+ {\let\PDFfile\empty}
+ {\expanded{\beforesplitstring#4}\at.\to\PDFfile
+ \doifparentfileelse\PDFfile % {#4}
+ {\let\PDFfile\empty}
+ %{\setreferencefilename#4.\locationfilesuffix\to\PDFfile
+ {\@EA\setreferencefilename\PDFfile.\locationfilesuffix\to\PDFfile
+ \edef\PDFfile
+ {R /F (\PDFfile)\ifgotonewwindow\space/NewWindow true \fi}}}%
+ \edef\action%
+ {/S /GoTo\PDFfile\space /D (\PDFdestination)}}}
+ {\doifelsenothing{#4}
+ {\let\PDFfile\empty
+ \let\PDFdestination\empty}
+ {\setreferencefilename/#4\to\PDFfile
+ \setPDFdestination{#5}%
+ \doifsomething\PDFdestination
+ {\edef\PDFdestination{\letterhash\PDFdestination}}}%
+ \edef\action{/S /URI /URI (#3\PDFfile\PDFdestination)}}%
+ \ifx\action\empty\else
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi
+ \fi
+ \egroup}
+
+\def\PDFgotonewwindow{\ifgotonewwindow\space/NewWindow true \fi}
+
+% optimization in tpd driver
+%
+% \edef\PDFdestination{(page:\the\scratchcounter)}%
+%
+% ==>
+%
+% \advance\scratchcounter 1
+% \edef\PDFdestination{[\pdfpageref \PDFobjref\scratchcounter\PDFpageviewwrd]}%
+%
+% \doPDFgetpagedestination#1#2% pagenumber macro % % fuzzy hack
+
+\def\dostartgotorealpage#1#2#3#4#5% watch the R append trick
+ {\bgroup
+ \doifelsenothing{#3}% #1 = url
+ {\scratchcounter0#5\relax
+ \ifnum\scratchcounter>0
+ \doifelsenothing{#4}
+ {\let\PDFfile\empty}
+ {\expanded{\beforesplitstring#4}\at.\to\PDFfile
+ \doifparentfileelse\PDFfile % {#4}
+ {\let\PDFfile\empty}
+ %{\setreferencefilename#4.\locationfilesuffix\to\PDFfile
+ {\@EA\setreferencefilename\PDFfile.\locationfilesuffix\to\PDFfile
+ \edef\PDFfile{R /F (\PDFfile)\PDFgotonewwindow}}}%
+ \ifx\PDFfile\empty
+ \ifcase\overcomePDFpage
+ \or % pdf starts numbering at zero
+ \advance\scratchcounter \minusone
+ \edef\PDFdestination{[\the\scratchcounter\space\PDFpageviewwrd]}%
+ \or % pdf starts numbering at zero
+ \advance\scratchcounter \minusone
+ \edef\PDFdestination{(page:\the\scratchcounter)}%
+ \or % pdftex starts numbering at one
+ \edef\PDFdestination{[\pdfpageref\scratchcounter\space0 R \PDFpageviewwrd]}%
+ \fi
+ \else % across files it's a page number / pdf starts numbering at zero
+ \advance\scratchcounter \minusone
+ \edef\PDFdestination{[\the\scratchcounter\space\PDFpageviewwrd]}%
+ \fi
+ \edef\action{/S /GoTo\PDFfile\space /D \PDFdestination}%
+ \else
+ \let\action\empty
+ \fi}
+ {\doifelsenothing{#4}
+ {\let\PDFfile\empty}
+ {\setreferencefilename/#4\to\PDFfile}%
+ \edef\action{/S /URI /URI (#3\PDFfile)}}%
+ \ifx\action\empty\else
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi
+ \fi
+ \egroup}
+
+\let\lastfakedPDFpage\!!zerocount
+
+\def\fakePDFpagedestination % as in pdf, we start numbering at zero
+ {\iflocation \ifarrangingpages \ifnum\overcomePDFpage=\plustwo \else
+ \ifnum\lastfakedPDFpage<\realpageno
+ \bgroup
+ \xdef\lastfakedPDFpage{\realfolio}%
+ \advance\realpageno \minusone % is \expanded needed ?
+ \normalexpanded{\noexpand\pdfdest name {page:\realfolio}\PDFpageviewkey}%
+ \egroup
+ \fi
+ \fi \fi \fi}
+
+\def\dostartgotoJS#1#2#3%
+ {\bgroup
+ \doPSsanitizeJScode#3\to\sanitizedJScode
+ \edef\action{/S /JavaScript /JS (\sanitizedJScode)}%
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi
+ \egroup}
+
+%D When going to a location, we obey the time and space saving
+%D boolean \type{\ifusepagedestination}. Named destinations are
+%D stripped and made robust. This all happens in the macros
+%D called for.
+
+%D \macros
+%D {doflushJSpreamble}
+%D
+%D It does not make sense to duplicate common \JAVASCRIPT\
+%D functions, and therefore they can be predefined and must be
+%D output separately. Currently this special is not shared
+%D with the \ACROBAT\ one, simply because \DISTILLER\ does not
+%D yet support something \type{\pdfnames}.
+
+% \oneJSpreamblefalse % buggy in acrobat
+
+\def\doflushJSpreamble#1%
+ {\bgroup
+ \let\compositeJScode\empty
+ \def\docommand##1%
+ {\edef\sanitizedJScode{\getJSpreamble{##1}}%
+ \@EA\doPSsanitizeJScode\sanitizedJScode\to\sanitizedJScode
+ \immediate\pdfobj {<< /S /JavaScript /JS (\sanitizedJScode) >>}%
+ \edef\compositeJScode
+ {\compositeJScode\space (##1) \PDFobjref\pdflastobj}}%
+ \processcommalist[#1]\docommand
+ \immediate\pdfobj{<< /Names [ \compositeJScode ] >>}%
+ \pdfnames{/JavaScript \PDFobjref\pdflastobj}%
+ \egroup}
+
+%D \macros
+%D {dostarthide,dostophide}
+%D
+%D Hiding parts of the document for printing is not yet
+%D supported by \PDF\ and therefore \PDFTEX.
+
+\let\dostarthide\donothing
+\let\dostophide \donothing
+
+%D \macros
+%D {doPDFsetupscreen,doPDFsetupidentity}
+%D
+%D Opposite to \DVI\ drivers, \PDF\ ones must know which what
+%D page dimensions they are dealing. We also use the
+%D opportunity to launch full screen (1) or show bookmarks (2).
+%D
+%D Setting of the screen boundingbox involves some
+%D calculations. Here we also take care of (non) full screen
+%D startup. The dimensions are rounded. Because \PDFTEX\ and
+%D \ACROBAT\ handle setting the page dimensions in a
+%D different way, we do not share this special.
+
+\def\dosetupscreen{\doPDFsetupscreen\pdfpageheight}
+
+\let\currentPDFpagemode \empty % document catalog
+\let\currentPDFviewerprefs\empty % document catalog
+
+\let\currentPDFcropbox \empty % page attributes
+\let\currentPDFbleedbox \empty % page attributes
+\let\currentPDFartbox \empty % page attributes
+\let\currentPDFtrimbox \empty % page attributes
+
+\def\doPDFsetupscreen#1#2#3#4#5#6% watch the extra argument
+ {\bgroup
+ \xdef\currentPDFpagemode
+ {\ifnum#6=4
+ /PageLayout /TwoColumnRight
+ \else
+ /PageMode \ifcase#6
+ /UseNone\or/FullScreen\or/UseOutlines\else/UseNone\fi
+ \fi}%
+ \xdef\currentPDFviewerprefs % space after #6 needed, else \relax
+ {\ifcase#6 \or\or\else /ViewerPreferences << /FitWindow true >>\fi}%
+ \egroup}
+
+\def\addPDFdocumentinfo
+ {\appendtopdfcatalog{\currentPDFpagemode\currentPDFviewerprefs}%
+ \appendtopdfcatalog{/Version \ifdim\PDFversion00\points>100\points 1.\fi\PDFversion}%
+ \appendtopdfinfo{/Trapped /False}%
+ \appendtopdfinfo{/ConTeXt.Version (\contextversion)}%
+ \appendtopdfinfo{/ConTeXt.Time (\number\normalyear.\twodigits\normalmonth.\twodigits\normalday\space \twodigits\currenthour:\twodigits\currentminute)}%
+ \appendtopdfinfo{/ConTeXt.Jobname (\jobname)}%
+ \appendtopdfinfo{/ConTeXt.Url (www.pragma-ade.com)}%
+ \glet\addPDFdocumentinfo\relax}
+
+\def\PDFversion{1.5}
+
+\appendtoksonce
+ \def\PDFversion{1.5}%
+\to \everyresetspecials
+
+\def\doPDFsetupwhateverbox#1#2#3#4#5#6% watch the extra arguments
+ {\bgroup
+ \!!widtha \dimexpr#5+#3\relax
+ \!!heightb\dimexpr#2-#4\relax
+ \!!heighta\dimexpr\!!heightb-#6\relax
+ % sometimes whole values give better results
+ % \PointsToWholeBigPoints{#3}\left
+ % \PointsToWholeBigPoints\!!heighta\bottom
+ % \PointsToWholeBigPoints\!!widtha \width
+ % \PointsToWholeBigPoints\!!heightb\height
+ % but since pdf/x does not round when checking if
+ % the boxes fit inside the media box ...
+ \PointsToBigPoints{#3}\left
+ \PointsToBigPoints\!!heighta\bottom
+ \PointsToBigPoints\!!widtha \width
+ \PointsToBigPoints\!!heightb\height
+ \xdef#1{[\left\space\bottom\space\width\space\height]}%
+ \egroup}
+
+\gdef\currentPDFtrimbox{\currentPDFcropbox} % default, needed for pdf/x
+
+\def\dosetupartbox {\doPDFsetupwhateverbox\currentPDFartbox \pdfpageheight}
+\def\dosetupcropbox {\doPDFsetupwhateverbox\currentPDFcropbox \pdfpageheight}
+\def\dosetupbleedbox{\doPDFsetupwhateverbox\currentPDFbleedbox\pdfpageheight}
+\def\dosetuptrimbox {\doPDFsetupwhateverbox\currentPDFtrimbox \pdfpageheight}
+
+\def\flushPDFpageboxes
+ {\edef\currentPDFtrimbox{\currentPDFtrimbox}%
+ \ifx\currentPDFartbox \empty\else\appendtopdfpageattributes{/ArtBox \currentPDFartbox }\fi
+ \ifx\currentPDFcropbox \empty\else\appendtopdfpageattributes{/CropBox \currentPDFcropbox }\fi
+ \ifx\currentPDFbleedbox\empty\else\appendtopdfpageattributes{/BleedBox \currentPDFbleedbox}\fi
+ \ifx\currentPDFtrimbox \empty\else\appendtopdfpageattributes{/TrimBox \currentPDFtrimbox }\fi}
+
+%D \macros
+%D {dostartexecutecommand}
+%D
+%D \PDF\ viewers enable us to navigate using menus and shortcut
+%D keys. These navigational tools can also be accessed by using
+%D annotations. The next special takes care of inserting them.
+%D
+%D At the cost of much auxiliary placeholders, we can pretty
+%D fast convert the command asked for. This is how the \PDF\
+%D code looks like.
+
+\def\PDFmoviecode#1#2#3%
+ {/Movie
+ /T (\ifcase#1movie \else sound \fi\ifx\argumentA\empty#2\else\argumentA\fi)
+ /Operation /\ifcase#3Play\or Stop\or Pause\or Resume\fi\space}
+
+\def\PDFexecutestartmovie {\PDFmoviecode0\currentmovie0}
+\def\PDFexecutestopmovie {\PDFmoviecode0\currentmovie1}
+\def\PDFexecutepausemovie {\PDFmoviecode0\currentmovie2}
+\def\PDFexecuteresumemovie {\PDFmoviecode0\currentmovie3}
+
+\def\PDFexecutestartsound {\PDFmoviecode1\currentsound0}
+\def\PDFexecutestopsound {\PDFmoviecode1\currentsound1}
+\def\PDFexecutepausesound {\PDFmoviecode1\currentsound2}
+\def\PDFexecuteresumesound {\PDFmoviecode1\currentsound3}
+
+\def\PDFformcode#1%
+ {\doiffieldset{#1}{/Field [\dogetfieldset{#1}]}}
+
+% bit 3 = html
+% bit 6 = xml
+% bit 4 = get
+
+\ifx\PDFsubmitfiller\undefined \let\PDFsubmitfiller\empty \fi
+
+\chardef\PDFformmethod=1 % 0=GET 1=POST
+
+\def\PDFformflag#1#2{\ifcase\PDFformmethod#1\else#2\fi}
+
+\def\PDFexecuteimportform {/Named /N /AcroForm:ImportFDF}
+\def\PDFexecuteexportform {/Named /N /AcroForm:ExportFDF}
+\def\PDFexecuteresetform {/ResetForm \PDFformcode\argumentA}
+\def\PDFexecutesubmitform {/SubmitForm \PDFformcode\argumentB
+ /Flags \ifcase\submitoutputformat\space
+ \PDFformflag{12} {4} % 0=unknown
+ \or \PDFformflag{12} {4} % 1=HTML
+ \or \PDFformflag {8} {0} % 2=FDF
+ \or \PDFformflag{40}{32} % 3=XML
+ \else \PDFformflag{12} {4} % ?=unknown
+ \fi
+ /F (\argumentA)\PDFsubmitfiller}
+
+% urifill permits url substitution
+
+\def\PDFexecutehide {/Hide /T (\argumentA) /H true}
+\def\PDFexecuteshow {/Hide /T (\argumentA) /H false}
+
+\def\PDFexecutefirst {/Named /N /FirstPage}
+\def\PDFexecuteprevious {/Named /N /PrevPage}
+\def\PDFexecutenext {/Named /N /NextPage}
+\def\PDFexecutelast {/Named /N /LastPage}
+\def\PDFexecutebackward {/Named /N /GoBack}
+\def\PDFexecuteforward {/Named /N /GoForward}
+\def\PDFexecuteprint {/Named /N /Print}
+\def\PDFexecuteexit {/Named /N /Quit}
+\def\PDFexecuteclose {/Named /N /Close}
+\def\PDFexecutesave {/Named /N /Save}
+\def\PDFexecutesavenamed {/Named /N /SaveAs}
+\def\PDFexecuteopennamed {/Named /N /Open}
+\def\PDFexecutehelp {/Named /N /HelpUserGuide}
+\def\PDFexecutetoggle {/Named /N /FullScreen}
+\def\PDFexecutesearch {/Named /N /Find}
+\def\PDFexecutesearchagain {/Named /N /FindAgain}
+\def\PDFexecutegotopage {/Named /N /GoToPage}
+\def\PDFexecutequery {/Named /N /AcroSrch:Query}
+\def\PDFexecutequeryagain {/Named /N /AcroSrch:NextHit}
+\def\PDFexecutefitwidth {/Named /N /FitWidth}
+\def\PDFexecutefitheight {/Named /N /FitHeight}
+
+\let\PDFobjectclass\empty
+\let\PDFobjectname \empty
+
+\def\dostartexecutecommand#1#2#3#4%
+ {\doifdefined{PDFexecute#3}
+ {\bgroup
+ \edef\argument{#4}%
+ \ifx\argument\empty
+ \let\argumentA\empty
+ \let\argumentB\empty
+ \else
+ \@EA\dogetcommalistelement\@EA1\@EA\from#4\to\argumentA
+ \@EA\dogetcommalistelement\@EA2\@EA\from#4\to\argumentB
+ \fi
+ \edef\action%
+ {/S \getvalue{PDFexecute#3}}%
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+% \ifx\PDFobjectclass\empty
+% \let\next\insertpdfaction
+% \else
+% \edef\next{\createpdfactionobject{\PDFobjectclass}{\PDFobjectname}}%
+% \globalletempty\PDFobjectclass
+% \globalletempty\PDFobjectname
+% \fi
+% \next
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi
+ \egroup}}
+
+%D \macros
+%D {dosetupidentity}
+%D
+%D Documents can be tagged with an application accessible title
+%D and subtitle, the authorname, a date, the creator, keywords
+%D etc. For the moment \PDFTEX\ only supports the first three
+%D of these.
+
+\def\dosetupidentity#1#2#3#4#5#6%
+ {\normalexpanded{\noexpand\appendtopdfinfo
+ {/Title <\hexifiedPDFstring{#1}>
+ /Subject <\hexifiedPDFstring{#2}>
+ /Author <\hexifiedPDFstring{#3}>
+ /Creator <\hexifiedPDFstring{#4}>
+ /ModDate (#4)
+ /ID (\jobname.#5) % needed for pdf/x
+ /Keywords <\hexifiedPDFstring{#6}>}}}
+
+%D \macros
+%D {dostartrunprogam}
+%D
+%D We can run a program form within a document, although this
+%D feature is rather weak, due to path problems and buggy
+%D argument passing.
+
+\def\dostartrunprogram#1#2#3#4% new: #3 => #3#4
+ {\bgroup
+ %\edef\string{#3}%
+ %\@EA\beforesplitstring\string\at{ }\to\program
+ %\@EA\aftersplitstring \string\at{ }\to\parameters
+ %\edef\action%
+ % {/S /Launch /F (\program) /P (\parameters) /D (.)}%
+ \edef\action
+ {/S /Launch /F (#3) /P (#4) /D (.)}%
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi
+ \egroup}
+
+%D \macros
+%D {dostartgotoprofile, dostopgotoprofile,
+%D dobeginofprofile, doendofprofile}
+%D
+%D \CONTEXT\ user profiles and version control fall back on
+%D \PDF\ article threads. Unfortunately one cannot influence
+%D the view yet in an (for me) acceptable way.
+
+\def\dostartgotoprofile#1#2#3% to be done: file
+ {\bgroup
+ \setPDFdestination{#3}%
+ \doifsomething\PDFdestination
+ {\edef\action
+ {/S /Thread /D (\PDFdestination)}%
+ \ifsecondaryreference
+ \savesecondaryPDFreference\action
+ \else
+ \getsecondaryPDFreferences
+ \insertpdfaction{\PDFswapdir#1}{#2}{\action \secondaryPDFreferences}%
+ \fi}%
+ \egroup}
+
+%D Some day, I'll reimplement threading in a useful way.
+%D Currently the viewers handle threads rather diffuse.
+
+\def\dobeginofprofile#1#2#3#4%
+ {\setPDFdestination{#1}%
+ \doifsomething\PDFdestination
+ {\pdfthread
+ width #2 height #3
+ attr {/Title (\PDFdestination)} % can be omitted
+ name {\PDFdestination}}}
+
+\def\doendofprofile
+ {}
+
+%D \macros
+%D {doinsertbookmark}
+%D
+%D In \PDF\ bookmarks are the building blocks of a viewer
+%D provided sort of table of contents. \TEX\ has to provide
+%D the entry as well as the number of child entries. Strings
+%D need to be sanatized as good as possible to suit the default
+%D encoding. In \CONTEXT\ users can overrule this string by
+%D supplying an alternative one. Look at the macro called for
+%D to see how funny these bookmarks are defined.
+
+\def\doinsertbookmark#1#2#3#4#5% level sublevels text page open=1
+ {\bgroup
+ \doPDFgetpagereference{#4}\PDFobjectreference
+ \pdfoutline
+ user {<</S /GoTo /D [\PDFobjectreference\space\PDFpageviewwrd]>>}%
+ \ifcase#2 \else count \ifcase#5-\fi#2 \fi
+% {<\hexifiedPDFstring{#3}>}% goes wrong
+ {<#3>}%
+ \egroup}
+
+%D \macros
+%D {dostartobject,dostopobject,doinsertobject}
+%D
+%D Due to \PDF's object oriented character, we can include and
+%D reuse objects. These can be compared with \TEX's boxes. The
+%D \TEX\ counterpart is defined in the module \type{spec-dvi}.
+%D We don't use the dimensions here.
+%D
+%D The next solution is not that beautiful. Because objects are
+%D containers for whatever kind of content, graphics can be
+%D part of this content, and a graphic object can be part of
+%D the more general type. In practice this means that an ximage
+%D would be embedded in an xform, which in itself is not that
+%D big a problem, apart from a few bytes overhead. However, for
+%D reasons unknown to me alternative images must be pure
+%D ximages |<|indeed, somehow one cannot use a vector graphic
+%D as alternative|>| that are not embedded into forms, so this
+%D is why the object handler treats them different. This
+%D implies knowledge of the calling routines, especially the
+%D \type{FIG} trigger, that signals that we just embedded an
+%D image. Alternatively I could have introduced a dual object
+%D system, but the overhead in duplicate specials is currently
+%D not what we want. I'd rather implement a more mature
+%D object support system from scratch.
+
+\let\currentPDFresources\empty
+\let\PDFimageattributes \empty
+\let\PDFfigurereference \empty
+\let\PDFimagereference \empty
+
+\def\dostartobject#1#2#3#4#5%
+ {\bgroup
+ \setbox\nextbox\vbox\bgroup
+ \def\dodostopobject
+ {\egroup
+ \ifx\PDFimagereference\empty
+ % We also flush page resources, since shared
+ % resources end up there; otherwise transparencies
+ % won't work in xforms; some day I will optimize
+ % this.
+ \the\everyPDFxform
+ \finalizeobjectbox\nextbox
+ \immediate\pdfxform
+ resources {\currentPDFresources\the\pdfpageresources}%
+ \nextbox
+ \global\let\currentPDFresources\empty
+ \dosetobjectreference{#1}{#2}{\the\pdflastxform}%
+ \else
+ \dosetobjectreference{#1}{#2}{-\PDFimagereference}%
+ \global\let\PDFimagereference\empty
+ \fi}}
+
+\def\dostopobject
+ {\dodostopobject
+ \egroup}
+
+\def\doresetobjects
+ {\global\let\PDFimagereference\empty}
+
+\def\doinsertobject#1#2%
+ {\bgroup
+ \doifobjectreferencefoundelse{#1}{#2}
+ {\dogetobjectreference{#1}{#2}\PDFobjectreference
+ \ifnum\PDFobjectreference<0
+ \@EA\@EA\@EA\pdfrefximage\@EA\gobbleoneargument\PDFobjectreference
+ \else
+ \pdfrefxform\PDFobjectreference
+ \fi}%
+ {}%
+ \egroup}
+
+\appendtoksonce
+ \collectPDFresources
+ \global\let\currentPDFresources\collectedPDFresources
+\to \everyPDFxform
+
+%D \macros
+%D {dosetpagetransition}
+%D
+%D Page transitions only make sence in presentations. They are
+%D passed as raw \PDF\ code to the page object. Take a look
+%D at the implementation to get an impression of the rubish
+%D passed on.
+%D
+%D This array holds a reasonable selection of transitions
+%D (watch out: \type{replace} is not in this list). Most of
+%D the transitions look awful anyway. By the way, \CONTEXT\ is
+%D able to select transitions randomly.
+
+\def\pagetransitions
+ {{split,in,vertical},{split,in,horizontal},
+ {split,out,vertical},{split,out,horizontal},
+ {blinds,horizontal},{blinds,vertical},
+ {box,in},{box,out},
+ {wipe,east},{wipe,west},{wipe,north},{wipe,south},
+ dissolve,
+ {glitter,east},{glitter,south},
+ {fly,in,east},{fly,in,west},{fly,in,north},{fly,in,south},
+ {fly,out,east},{fly,out,west},{fly,out,north},{fly,out,south},
+ {push,east},{push,west},{push,north},{push,south},
+ {cover,east},{cover,west},{cover,north},{cover,south},
+ {uncover,east},{uncover,west},{uncover,north},{uncover,south},
+ fade}
+
+%D Again, we use macros as placeholders for \PDF\ key||value
+%D pairs.
+
+\def\PDFpagesplit {/S /Split }
+\def\PDFpageblinds {/S /Blinds }
+\def\PDFpagebox {/S /Box }
+\def\PDFpagewipe {/S /Wipe }
+\def\PDFpagedissolve {/S /Dissolve }
+\def\PDFpageglitter {/S /Glitter }
+\def\PDFpagereplace {/S /R }
+
+\def\PDFpagefly {/S /Fly } % 1.5
+\def\PDFpagepush {/S /Push } % 1.5
+\def\PDFpagecover {/S /Cover } % 1.5
+\def\PDFpageuncover {/S /Uncover } % 1.5
+\def\PDFpagefade {/S /Fade } % 1.5
+
+\def\PDFpagehorizontal {/Dm /H }
+\def\PDFpagevertical {/Dm /V }
+\def\PDFpagein {/M /I }
+\def\PDFpageout {/M /O }
+\def\PDFpageeast {/Di 0 }
+\def\PDFpagenorth {/Di 90 }
+\def\PDFpagewest {/Di 180 }
+\def\PDFpagesouth {/Di 270 }
+
+\def\dodoPDFsetpagetransition#1%
+ {\doifdefined{PDFpage#1}
+ {\edef\PDFpagetransitions{\PDFpagetransitions\getvalue{PDFpage#1}}}}
+
+\def\dosetpagetransition#1#2%
+ {\let\PDFpagetransitions\empty
+ \processcommalist[#1]\dodoPDFsetpagetransition
+ \appendtopdfpageattributes
+ %{\ifnum#2>0 /Dur #2 \fi
+ {\ifnum0<0#2 /Dur #2 \fi
+ \ifx\PDFpagetransitions\empty\else/Trans <<\PDFpagetransitions>>\fi}}
+
+%D The expansion is needed because else the \type{\pdfpageattr}
+%D token list flushes an unexpanded \type{\csname}. The
+%D \type{\global} is needed because the assignment can take
+%D place deeply buried (for instance in the \type{\shipout}
+%D box.
+
+%D \macros
+%D {doinsertcomment, doflushcomments}
+%D
+%D Text annotation, or comments, are provided too:
+
+%D \macros
+%D {dopresetlinefield,dopresettextfield,
+%D dopresetchoicefield,dopresetpopupfield,dopresetcombofield,
+%D dopresetpushfield,dopresetcheckfield,
+%D dopresetradiofield,dopresetradiorecord}
+%D
+%D \PDF\ offers extensive field support. The next bunch of
+%D definitions map the specials.
+
+%D \macros
+%D {dodefinefieldset,dogetfieldset,doiffieldset}
+%D
+%D Field sets, needed for reset and submit handling, are
+%D taken care of by:
+
+%D The next section of this module is dedicated to form
+%D support. These macros are complicated by the fact that
+%D cloning is possible.
+
+%D \macros
+%D {FDFflag...,FDFplus...}
+%D
+%D The \type{/FT} key determines the type of field: text,
+%D button or choice. The latter two come in several disguises,
+%D which are set by flipping bits in the \type{/Ff}. Other bits
+%D are used to set states. Personally I hate this bitty way of
+%D doing things. The next six bit determine the field sub type:
+
+\def\FDFflagMultiLine {4096} % 13
+\def\FDFflagNoToggleToOff {16384} % 15
+\def\FDFflagRadio {32768} % 16
+\def\FDFflagPushButton {65536} % 17
+\def\FDFflagPopUp {131072} % 18
+\def\FDFflagEdit {262144} % 19
+
+% bugged anyway, so we need to drop it:
+
+\def\FDFflagRadiosInUnison {33554432} % 26
+
+%D A few more (pdf 1.4) flags, what the spell check one: for
+%D obscure reasons for Adobe downward compatibility means
+%D enabling features that harm old applications like testing.
+
+\def\FDFflagDoNotSpellCheck {4194304} % 23
+\def\FDFflagDoNotScroll {8388608} % 24
+
+%D The next bits (watch how strange the bits are organized)
+%D take care of the states:
+
+\def\FDFflagReadOnly {1} % 1
+\def\FDFflagRequired {2} % 2
+\def\FDFflagNoExport {4} % 3
+\def\FDFflagPassword {8192} % 14
+\def\FDFflagSort {524288} % 20
+\def\FDFflagFileSelect {1048576} % 21
+
+%D There is a second, again bitset oriented, \type{/F} flag:
+
+\def\FDFplusInvisible {1} % 1
+\def\FDFplusHidden {2} % 2
+\def\FDFplusPrintable {4} % 3
+
+%def\FDFplusNoView {32} % 6
+%def\FDFplusToggleNoView {256} % 9
+
+\def\FDFplusAutoView {256} % {288} % 6+9
+
+%D \macros
+%D {setFDFswitches}
+%D
+%D The non||type bits are mapped onto user||interface
+%D swithes, to be used later on:
+
+\def\@@FDFflag{FDFflag}
+\def\@@FDFplus{FDFplus}
+
+\letvalue {\@@FDFflag\v!readonly}=\FDFflagReadOnly
+\letvalue {\@@FDFflag\v!required}=\FDFflagRequired
+\letvalue {\@@FDFflag\v!protected}=\FDFflagPassword
+\letvalue {\@@FDFflag\v!sorted}=\FDFflagSort
+\letvalue {\@@FDFflag\v!unavailable}=\FDFflagNoExport
+\letvalue {\@@FDFflag\v!nocheck}=\FDFflagDoNotSpellCheck
+\letvalue {\@@FDFflag\v!fixed}=\FDFflagDoNotScroll
+\letvalue {\@@FDFflag\v!file}=\FDFflagFileSelect
+
+\letvalue {\@@FDFplus\v!hidden}=\FDFplusHidden
+\letvalue {\@@FDFplus\v!printable}=\FDFplusPrintable
+
+\letvalue {\@@FDFplus\v!auto}=\FDFplusAutoView
+
+%D A set of switches is collected into the flags we mentioned
+%D before by the next macro (we don't handle negations yet,
+%D but do take care of redundancy):
+
+\def\FDFflag{0}
+\def\FDFplus{0}
+
+\def\setFDFswitches[#1]%
+ {\bgroup
+ \!!counta\zerocount
+ \!!countb\zerocount
+ \def\docommand##1%
+ {\doifsomething{##1}
+ {\advance\!!counta 0\getvalue{\@@FDFflag##1}%
+ \setvalue{\@@FDFflag##1}{0}%
+ \advance\!!countb 0\getvalue{\@@FDFplus##1}%
+ \setvalue{\@@FDFplus##1}{0}}}%
+ \processcommacommand[#1]\docommand
+ \xdef\FDFflag{\the\!!counta}%
+ \xdef\FDFplus{\the\!!countb}%
+ \egroup}
+
+%D \macros
+%D {setFDFvalues}
+%D
+%D Menu items are passed as an array of \type{(string)}'s and
+%D the content of this array is build with:
+
+\let\FDFvalues \empty
+\let\FDFfirstvalues \empty
+\let\FDFsecondvalues\empty
+\let\FDFkidlist \empty
+\let\FDFdefaultindex\!!zerocount
+\let\FDFdefaultvalue\empty
+
+% Why do we need to tweak this mechanism each time acrobat updates ...
+% it would make sense to have version specific sections in pdf files
+% since my guess is that it never will be done right since each year
+% new programmers have new ideas about what is supposed to happen with
+% kids. So .. best is not to trust this feature esp not for radio
+% widgets. (new flags, different interpretation of AS etc etc)
+
+\def\setFDFvalues[#1][#2]% #1 = list (item=>value) #2 = default
+ {\let\FDFvalues \empty
+ %when radio opt works ok
+ %\let\FDFfirstvalues \empty
+ %\let\FDFsecondvalues\empty
+ \let\FDFkidlist \empty
+ %\let\FDFdefaultindex\!!zerocount
+ %\let\FDFdefaultvalue\empty
+ %\scratchcounter\zerocount
+ \def\dodocommand##1=>##2=>##3\end
+ {\addtocommalist{##1}\FDFkidlist
+ %\edef\FDFfirstvalues{\FDFfirstvalues(##1)}%
+ %\doif{##1}{#2}{\edef\FDFdefaultindex{\the\scratchcounter}}%
+ %\advance\scratchcounter\plusone
+ \doifelsenothing{##2}
+ {\doif{##1}{#2}{\edef\FDFdefaultvalue{##1}}%
+ %\edef\FDFsecondvalues{\FDFsecondvalues(##1)}%
+ \edef\FDFvalues{\FDFvalues [(##1)(##1)] }}
+ {\doif{##1}{#2}{\edef\FDFdefaultvalue{##2}}%
+ %\edef\FDFsecondvalues{\FDFsecondvalues(##2)}%
+ \edef\FDFvalues{\FDFvalues [(##2)(##1)] }}}% ! ##1 is shown
+ \def\docommand##1%
+ {\dodocommand##1=>=>\end}%
+ \expanded{\processcommalist[#1]}\docommand}
+
+%D This macro accepts comma separated \type{visual=>result}
+%D pairs.
+
+%D \macros
+%D {setFDFalignment}
+%D
+%D Text and line fields can be entered and showed in three
+%D alternative alingments, indicated by a digit:
+
+\def\FDFalign{0}
+
+\def\setFDFalignment[#1]%
+ {\processaction
+ [#1]
+ [ \v!left=>\edef\FDFalign{2}, % raggedleft
+ \v!middle=>\edef\FDFalign{1}, % raggedcenter
+ \v!right=>\edef\FDFalign{0}]} % raggedright
+
+%D \macros
+%D {setFDFattributes}
+%D
+%D The weak part of (at least version 2.1 \PDF) is that only
+%D default fonts are handled well. Another restriction is that
+%D the encoding vector must be the standard \PDF\ document one.
+%D Although the \PDF\ reference explictly states that one could
+%D use the normal text operators, leading is not yet handled.
+%D
+%D For the moment the current \CONTEXT\ font is mapped onto
+%D one best suitable default font. The color attribute is
+%D less problematic and is directly derived from the \CONTEXT\
+%D color.
+
+\def\FDFattributes{/Helv 12 Tf 0 g 14.4 TL}
+
+\def\FDFrm {TiRo} \def\FDFss {Helv} \def\FDFtt {Cour}
+\def\FDFrmtf{TiRo} \def\FDFsstf{Helv} \def\FDFtttf{Cour}
+\def\FDFrmbf{TiBo} \def\FDFssbf{HeBo} \def\FDFttbf{CoBo}
+\def\FDFrmit{TiIt} \def\FDFssit{HeOb} \def\FDFttit{CoOb}
+\def\FDFrmsl{TiIt} \def\FDFsssl{HeOb} \def\FDFttsl{CoOb}
+\def\FDFrmbi{TiBI} \def\FDFssbi{HeBO} \def\FDFttbi{CoBO}
+\def\FDFrmbs{TiBI} \def\FDFssbs{HeBO} \def\FDFttbs{CoBO}
+
+\let\FDFusedfonts=\FDFsstf
+
+\def\setFDFattributes[#1,#2,#3,#4]% style, color, backgroundcolor, framecolor
+ {\bgroup % nog interlinie: n TL
+ \setbox\scratchbox\hbox
+ \bgroup
+ \doconvertfont{#1}{}%
+ \PointsToBigPoints\bodyfontsize\size % x/xx, so better the actual size
+ \doifdefinedelse{FDF\fontstyle\fontalternative}
+ {\xdef\FDFattributes{\getvalue{FDF\fontstyle\fontalternative}}}
+ {\doifdefinedelse{FDF\fontstyle}
+ {\xdef\FDFattributes{\getvalue{FDF\fontstyle}}}
+ {\xdef\FDFattributes{\FDFrm}}}%
+ \doglobal\addtocommalist\FDFattributes\FDFusedfonts
+ \xdef\FDFattributes% move up with "x.y Ts"
+ {/\FDFattributes\space\size\space Tf\space\PDFcolor{#2}}%
+ \doifelsenothing{#3}
+ {\global\let\FDFsurroundings\empty}
+ {\xdef\FDFsurroundings{/BG \FDFcolor{#3}}}%
+ \doifsomething{#4}
+ {\xdef\FDFsurroundings{\FDFsurroundings\space /BC \FDFcolor{#4}}}%
+ \ifx\FDFsurroundings\empty \else
+ \xdef\FDFsurroundings{/MK << \FDFsurroundings\space>>}%
+ \fi
+ \egroup
+ \egroup}
+
+%D \macros
+%D {setFDFactions}
+%D
+%D Depending on the type of the field, one can assign
+%D \JAVASCRIPT\ code to a mouse event or keystroke. The next
+%D preparation macro shows what events are handled.
+
+\let\FDFactions\empty
+
+\def\setFDFactions[#1,#2,#3,#4,#5,#6,#7,#8,%
+ {\global\let\FDFactions\empty
+ \setFDFaction D#1% mousedown
+ \setFDFaction U#2% mouseup
+ \setFDFaction E#3% enterregion
+ \setFDFaction X#4% exitregion
+ \setFDFaction K#5% afterkeystroke
+ \setFDFaction F#6% formatresult
+ \setFDFaction V#7% validateresult
+ \setFDFaction C#8% calculatewhatever
+ \setFDFactionsmore}
+
+\def\setFDFactionsmore#1,#2]%
+ {\setFDFaction{Fo}#1% focusin
+ \setFDFaction{Bl}#2% focusout % was I (now pdf ref manual explicitly talks about lowercase l)
+ \ifx\FDFactions\empty\else
+ \xdef\FDFactions{/AA << \FDFactions >>}% since 1.3 no longer inherited
+ \fi}
+
+% todo, when new var scheme is implemented
+%
+% \setFDFaction{PO}\@@DriverFieldPageOpen
+% \setFDFaction{PC}\@@DriverFieldPageClose
+% \setFDFaction{PV}\@@DriverFieldPageVisible
+% \setFDFaction{PI}\@@DriverFieldPageInVisible
+
+%D The event handler becomes something:
+%D
+%D \starttyping
+%D /AA << /D << /S ... >> ... /C << /S ... >>
+%D /A << /S /JavaScript /JS (...) >>
+%D \stoptyping
+
+\def\setFDFaction#1#2%
+ {\bgroup
+ \def\docommand{\xdef\FDFactions{\FDFactions /#1 << \lastPDFaction >> }}%
+ \@EA\handlereferenceactions\@EA{#2}\docommand % one level expansion
+ \egroup}
+
+%D \macros
+%D {testFDFactions}
+%D
+%D This rather confusion prone series of script can be tested
+%D with:
+%D
+%D \starttyping
+%D \testFDFactions
+%D \stoptyping
+%D
+%D which simply redefined the previous macro to one that prints
+%D a message to the console.
+
+\def\testFDFactions
+ {\def\setFDFaction##1##2%
+ {\doPSsanitizeJScode console.show();console.println("executing:##1"); \to\sanitizedJScode
+ \edef\FDFactions{\FDFactions /##1 << /S /JavaScript /JS (\sanitizedJScode) >> }}}
+
+%D \macros
+%D {doregistercalculationset}
+%D
+%D There is at most one calculation order list, which defines
+%D the order in which fields are calculated. The calculation
+%D order is defined using:
+
+\let\PDFcalculationset\empty
+
+\def\doregistercalculationset#1%
+ {\def\PDFcalculationset{#1}}
+
+%D \macros
+%D {registerFDFobject,everylastshipout}
+%D
+%D Officially one needs to embed some general datastructures
+%D that tell the viewer what fields are present in the file, as
+%D well as what resources they use. The next mechanism does that
+%D job automatically when one registers the field.
+
+\def\flushFDFnames
+ {\ifx\FDFcollection\empty\else
+ \defineFDFfonts
+ \createpdfarrayobject{FDF}{local:fields}{\FDFcollection}%
+ \doPDFgetobjectreference{FDF}{local:fields}\PDFobjectreference
+ % The /NeedAppearances is pretty important because
+ % otherwise Acrobat 5 blows up on cloned radio widgets
+ \createpdfdictionaryobject{FDF}{local:acroform}
+ {/Fields \PDFobjectreference\space
+ /NeedAppearances true
+ \doiffieldset\PDFcalculationset{/CO [\dogetfieldset\PDFcalculationset]}
+ /DR << /Font << \FDFfonts >> >>
+ /DA (/Helv 10 Tf 0 g)}%
+ \doPDFgetobjectreference{FDF}{local:acroform}\PDFobjectreference
+ \appendtopdfcatalog
+ {/AcroForm \PDFobjectreference}%
+ \global\let\FDFcollection\empty
+ \global\let\flushFDFnames\relax
+ \fi}
+
+\let\FDFcollection\empty
+
+\def\registerFDFobject#1%
+ {\ifx\flushFDFnames\relax
+ \writestatus{FDF}{second run needed for field list (#1)}%
+ \fi
+ \doPDFgetobjectreference{FDF}{#1}\PDFobjectreference
+ \xdef\FDFcollection{\FDFcollection\space\PDFobjectreference}}
+
+\appendtoksonce \flushFDFnames \to \everylastshipout % test \everybye / was \prependtoksonce
+
+%D \macros
+%D {defineFDFfonts}
+%D
+%D Another datastruture concerns the fonts used. We only
+%D define the fonts we use.
+
+\def\defineFDFfonts
+ {\let\FDFfonts\empty
+ \processcommacommand[\FDFusedfonts]\defineFDFfont}
+
+\def\defineFDFfont#1%
+ {\createpdfdictionaryobject{FDF}{local:#1}
+ {/Type /Font
+ /Subtype /Type1
+ /Name /#1
+ /BaseFont /\getvalue{FDFname#1}}%
+ \doPDFgetobjectreference{FDF}{local:#1}\PDFobjectreference
+ \edef\FDFfonts{\FDFfonts \space/#1 \PDFobjectreference}}
+
+%D Another list of constants:
+
+\def\FDFnameTiRo {Times-Roman}
+\def\FDFnameTiBo {Times-Bold}
+\def\FDFnameTiIt {Times-Italic}
+\def\FDFnameTiBI {Times-BoldItalic}
+\def\FDFnameHelv {Helvetica}
+\def\FDFnameHeBo {Helvetica-Bold}
+\def\FDFnameHeOb {Helvetica-Oblique}
+\def\FDFnameHeBO {Helvetica-BoldOblique}
+\def\FDFnameCour {Courier}
+\def\FDFnameCoBo {Courier-Bold}
+\def\FDFnameCoOb {Courier-Oblique}
+\def\FDFnameCoBO {Courier-BoldOblique}
+
+%D \macros
+%D {currentFDFmode,currentFDFparent,currentFDFkids,currenrFDFroot}
+%D
+%D There are three more quasi global interfacing variables
+%D that need to be set.
+
+\let\currentFDFmode \fieldlonermode
+\let\currentFDFkids \empty
+\let\currentFDFparent\empty
+\let\currentFDFroot \empty
+
+%D \macros
+%D {dosetfieldstatus}
+%D
+%D And here comes the special that deals with them.
+
+\def\dosetfieldstatus#1#2#3#4%
+ {\chardef\currentFDFmode #1%
+ \edef\currentFDFparent {#2}%
+ \edef\currentFDFkids {#3}%
+ \edef\currentFDFroot {#4}}
+
+%D We already dealt with the encoding vector. Conversion from
+%D \TEX\ \ASCII\ encoding to the other one, is accomplished by
+%D the next few macros. Wach out: we don't group here.
+
+\appendtoksonce
+ \simplifycommands
+\to \everysetfield
+
+%D \macros
+%D {doPDFinsertcomment}
+%D
+%D An example its use is the next special, one that deals with
+%D text annotations.
+
+\newcounter\nofFDFcomments
+
+\newif\ifPDFpopupcomments \PDFpopupcommentstrue
+
+\def\doflushcomments
+ {\box\PDFsymbolbox}
+
+\long\def\doinsertcomment#1#2#3#4#5#6#7#8% % \@@DriverCommentLayer set otherwise
+ {\bgroup % title width height color open symbol collect data
+ \presetPDFsymbolappearance{#4}{#6}{#2}{#3}\!!zeropoint% sets width/height
+ \doifelsenothing{#1}
+ {\let\PDFidentifier\empty}
+ {\sanitizePDFencoding#1\to\PDFcommenttitle
+ \def\PDFidentifier{/T <\PDFcommenttitle>}}%
+ \sanitizePDFencoding#8\to\PDFdata
+ \setFDFlayer\@@DriverCommentLayer
+ \startPDFsymbolappearance
+ \ifPDFpopupcomments
+ \doglobal\increment\nofFDFcomments
+ \doifobjectreferencefoundelse{FDF}{c:\nofFDFcomments}
+ {\doPDFgetobjectreference{FDF}{c:\nofFDFcomments}\PDFobjectreference
+ \donetrue}
+ \donefalse
+ \ifdone
+ \setbox\scratchbox\hbox
+ {\createpdfannotationobject{FDF}{c::\nofFDFcomments}{#2}{#3}% text window, size does not work
+ {/Subtype /Popup
+ /Parent \PDFobjectreference}}%
+ \ifcase#7\relax
+ \vbox to \height{\forgetall\vskip#3\box\scratchbox\vss}%
+ \else % incredible trial and error hack
+ % it's quite a mess, the annot width cannot be set, well, it can
+ % but the appearance and text sizes get mixed up
+% \setbox\scratchbox\vbox to \height{\forgetall\vskip#3\box\scratchbox\vss}%
+% \global\setbox\PDFsymbolbox\vbox
+% {\hsize#2%
+% \forgetall
+% \vsmash{\box\PDFsymbolbox}
+% \box\scratchbox}%
+ % this may change when acrobat gets less bugged
+ \setbox\scratchbox\vbox to #3{\forgetall\vss\box\scratchbox}%
+ \wd\scratchbox#2%
+ \global\setbox\PDFsymbolbox\vbox
+ {\startoverlay{\box\PDFsymbolbox}{\box\scratchbox}\stopoverlay}%
+ \fi
+ \fi
+ % generic
+ \doifobjectreferencefoundelse{FDF}{c::\nofFDFcomments}
+ {\doPDFgetobjectreference{FDF}{c::\nofFDFcomments}\PDFobjectreference
+ \donetrue}
+ \donefalse
+ \createpdfannotationobject{FDF}{c:\nofFDFcomments}{\width}{\height}
+ {/Subtype /Text
+ \ifcase#5 \else/Open true\fi
+ % pdftex (efficient)
+ % \ifdone /Popup \PDFobjref\pdflastannot\fi
+ % generic (less efficient)
+ \ifdone /Popup \PDFobjectreference\fi
+ /Contents <\PDFdata>
+ \PDFidentifier
+ \FDFlayer
+ \PDFsymbol
+ \PDFattributes}%
+ \else
+ \insertpdfannotation{#2}{#3}
+ {/Subtype /Text
+ \ifcase#5 \else/Open true\fi
+ /Contents <\PDFdata>
+ \FDFlayer
+ \PDFsymbol
+ \PDFidentifier
+ \PDFattributes}%
+ \fi
+ \stopPDFsymbolappearance
+ \egroup}
+
+% symbols with a reasonable default of 18/24 pt
+
+\newbox\PDFsymbolbox
+
+\def\PDFsymbolNew {/Insert}
+\def\PDFsymbolBalloon {/Comment}
+\def\PDFsymbolAddition {/NewParagraph}
+\def\PDFsymbolHelp {/Help}
+\def\PDFsymbolParagraph {/Paragraph}
+\def\PDFsymbolKey {/Key }
+
+\def\PDFsymbolGraph {/Graph}
+\def\PDFsymbolPaperclip {/Paperclip}
+\def\PDFsymbolAttachment{/Attachment}
+\def\PDFsymbolTag {/Tag}
+
+\def\startPDFsymbolappearance
+ {\setbox\scratchbox\vbox to \totalheight \bgroup \vfill}
+
+\def\stopPDFsymbolappearance
+ {\egroup
+ \setbox\scratchbox\hbox{\lower\depth\box\scratchbox}%
+ \wd\scratchbox\width
+ \ht\scratchbox\height
+ \dp\scratchbox\depth
+ \box\scratchbox}
+
+\def\presetPDFsymbolappearance#1#2#3#4#5% symbol color width height depth
+ {\doifelsenothing{#1}
+ {\let\PDFattributes\empty}
+ {\def\PDFattributes{/C \FDFcolor{#1}}}%
+ \scratchdimen#3\edef\width {\the\scratchdimen}%
+ \scratchdimen#4\edef\height{\the\scratchdimen}%
+ \scratchdimen#5\edef\depth {\the\scratchdimen}%
+ \advance\scratchdimen\height\edef\totalheight{\the\scratchdimen}%
+ \doifelsenothing{#2}
+ {\let\PDFsymbol\empty}
+ {\ifundefined{PDFsymbol#2}%
+ \getfromcommacommand[#2][1]\let\PDFsymbolnormalsymbol\commalistelement
+ \getfromcommacommand[#2][2]\let\PDFsymboldownsymbol \commalistelement
+ \doifsymboldefinedelse\PDFsymbolnormalsymbol
+ {\doifsymboldefinedelse\PDFsymboldownsymbol
+ {\dopresetPDFsymbolappearance
+ \PDFsymbolnormalsymbol\PDFsymboldownsymbol}
+ {\dopresetPDFsymbolappearance
+ \PDFsymbolnormalsymbol\PDFsymbolnormalsymbol}}
+ {\doifsymboldefinedelse\PDFsymboldownsymbol
+ {\dopresetPDFsymbolappearance
+ \PDFsymboldownsymbol\PDFsymboldownsymbol}
+ {\let\PDFsymbol\empty}}%
+ \else
+ \def\PDFsymbol{/Name \getvalue{PDFsymbol#2} }%
+ \fi}}
+
+\def\dopresetPDFsymbolappearance#1#2%
+ {\dopresetfieldsymbol{#1}%
+ \dopresetfieldsymbol{#2}%
+ \setbox\scratchbox\hbox{\symbol[#1]}%
+ \edef\width {\the\wd\scratchbox}%
+ \edef\height{\the\ht\scratchbox}%
+ \edef\depth {\the\dp\scratchbox}%
+ \scratchdimen\height \advance\scratchdimen\depth
+ \edef\totalheight{\the\scratchdimen}%
+ \doPDFgetobjectreference{SYM}{#1}\FDFsymbolNappearance
+ \doPDFgetobjectreference{SYM}{#2}\FDFsymbolDappearance
+ \edef\PDFsymbol
+ {/AP <</N \FDFsymbolNappearance /D \FDFsymbolDappearance>>}}
+
+%D Hooked into \CONTEXT, this special supports
+%D
+%D \starttyping
+%D \startcomment
+%D hello beautiful\\world
+%D \stopcomment
+%D
+%D \startcomment[hello]
+%D de \'e\'erste keer
+%D the f\'irst time
+%D \stopcommen
+%D
+%D \startcommentaar[hallo][color=green,width=4cm,height=3cm]
+%D first
+%D
+%D second
+%D \stopcommentaar
+%D \stoptyping
+%D
+%D So, special characters, forced linebreaks using \type{\\}
+%D and \type{\par} are handled in the appropriate way.
+
+%D \macros
+%D {dosetuppageview}
+%D
+%D Because this command will seldom be called, we can permit
+%D slow action processing. We need three settings, one for
+%D direct \PDF\ inclusion, the other as \PDFTEX\ keyword, an
+%D a last one for form. All determine in what way the
+%D screen is adapted when going to a destination. Watch the
+%D space.
+
+\def\PDFpageviewkey{fit}
+\def\PDFpageviewwrd{/Fit}
+\def\PDFpageview {/View [\PDFpageviewwrd] }
+\def\PDFpagexyzspec{0 0 0} % hack, pdftex does handle this
+\let\PDFpagexyzspec\empty % hack, pdftex does not accept spec
+
+\def\dosetuppageview#1% watch the v-h swapping here
+ {\processaction
+ [#1]
+ [ \v!fit=>\def\PDFpageviewkey {fit}\def\PDFpageviewwrd{/Fit},
+ \v!width=>\def\PDFpageviewkey {fith}\def\PDFpageviewwrd{/FitH},
+ \v!height=>\def\PDFpageviewkey {fitv}\def\PDFpageviewwrd{/FitV},
+ \v!minwidth=>\def\PDFpageviewkey{fitbh}\def\PDFpageviewwrd{/FitBH},
+ \v!minheight=>\def\PDFpageviewkey{fitbv}\def\PDFpageviewwrd{/FitBV},
+ \v!standard=>\def\PDFpageviewkey{xyz \PDFpagexyzspec}\def\PDFpageviewwrd{/XYZ \PDFpagexyzspec},
+ \s!unknown=>\def\PDFpageviewkey {fit}\def\PDFpageviewwrd{/Fit}]%
+ \edef\PDFpageview{/View [\PDFpageviewwrd]}}
+
+%D \macros
+%D {setFDFkids}
+%D
+%D Clones as well as radiofields (which themselves can have
+%D cloned components) need a list of kids. The next macro
+%D builds one.
+
+\def\setFDFkids[#1][#2]% tag commalist
+ {\let\FDFkids\empty
+ \def\docommand##1%
+ {\doPDFgetobjectreference{FDF}{#1##1}\PDFobjectreference
+ \edef\FDFkids{\FDFkids\PDFobjectreference\space}}%
+ \@EA\processcommalist\@EA[#2]\docommand
+ \ifx\FDFkids\empty\else\edef\FDFkids{/Kids [\FDFkids]}\fi}
+
+%D \macros
+%D {dopresetlinefield,dopresettextfield,
+%D dopresetchoicefield,dopresetpopupfield,dopresetcombofield,
+%D dopresetpushfield,dopresetcheckfield,
+%D dopresetfield,dopresetradiorecord}
+%D
+%D I would say: read the \PDF\ reference manual first and see
+%D what happens here next. Lucky us that they have so much in
+%D common.
+
+\def\dopresetlinefield#1#2#3#4#5#6#7#8#9%
+ {\bgroup
+ \setFDFlayer\@@DriverFieldLayer
+ \setFDFswitches[#7]%
+ \setFDFattributes[#6]%
+ \setFDFalignment[#8]%
+ \setFDFactions[#9]%
+ \edef\FDFtext{\hexifiedPDFstring{#4}}%
+ \ifcase\currentFDFmode
+ \createpdfannotationobject{FDF}{#1}{#2}{#3}
+ {/Subtype /Widget /T (#1) /FT /Tx
+ /MaxLen \ifcase0#5 1000 \else#5 \fi
+ %/DV (#4) /V (#4) % value added
+ /DV <\FDFtext> /V <\FDFtext>
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ /Q \FDFalign\space
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \setFDFkids[kids:][\currentFDFkids]%
+ \createpdfdictionaryobject{FDF}{#1}
+ {/T (#1) /FT /Tx
+ /MaxLen \ifcase0#5 1000 \else#5 \fi
+ \FDFkids\space
+ %/DV (#4) /V (#4) % value added
+ /DV <\FDFtext> /V <\FDFtext>
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ /Q \FDFalign\space
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ /Q \FDFalign\space
+ \FDFactions}%
+ \or
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference
+ /F \FDFplus
+ \FDFactions}%
+ \fi
+ \egroup}
+
+\def\dopresettextfield#1#2#3#4#5#6#7#8#9%
+ {\dopresetlinefield{#1}{#2}{#3}{#4}{#5}{#6}{MultiLine,#7}{#8}{#9}}
+
+\def\dopresetchoicefield#1#2#3#4#5#6#7#8%
+ {\bgroup
+ \setFDFlayer\@@DriverFieldLayer
+ \setFDFswitches[#6]%
+ \setFDFattributes[#5]%
+ \setFDFvalues[#7][#4]%
+ \setFDFactions[#8]%
+ \ifcase\currentFDFmode
+ \createpdfannotationobject{FDF}{#1}{#2}{#3}
+ {/Subtype /Widget
+ /T (#1) /FT /Ch
+ /DV (#4) /V (#4)
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ /Opt [\FDFvalues]
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \setFDFkids[kids:][\currentFDFkids]%
+ \createpdfdictionaryobject{FDF}{#1}
+ {/T (#1) /FT /Ch
+ \FDFkids\space
+ /DV (#4) /V (#4)
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ /Opt [\FDFvalues]
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ /DA (\FDFattributes)
+ \FDFlayer\space
+ \FDFsurroundings\space
+ \FDFactions}%
+ \or
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference
+ /F \FDFplus
+ \FDFactions}%
+ \fi
+ \egroup}
+
+\def\dopresetpopupfield#1#2#3#4#5#6#7#8%
+ {\dopresetchoicefield{#1}{#2}{#3}{#4}{#5}{PopUp,#6}{#7}{#8}}
+
+\def\dopresetcombofield#1#2#3#4#5#6#7#8%
+ {\dopresetchoicefield{#1}{#2}{#3}{#4}{#5}{PopUp,Edit,#6}{#7}{#8}}
+
+\newif\ifFDFvalues
+
+\def\doFDFpresetpushcheckfield#1#2#3#4#5#6#7#8% in acro<5 (\FDFdefault)
+ {\bgroup % in acro>5 /\FDFdefault
+ \setFDFlayer\@@DriverFieldLayer
+ \ifcase#8\relax\FDFvaluesfalse\else\FDFvaluestrue\fi
+ \setFDFswitches[#5]%
+ \setFDFactions[#7]%
+ \doifelse{#4}{1}
+ {\def\FDFdefault{On}}
+ {\def\FDFdefault{Off}}%
+ \ifcase\currentFDFmode
+ \doFDFappearance{On}{#6}{#8}%
+ \createpdfannotationobject{FDF}{#1}{#2}{#3}
+ {/Subtype /Widget /T (#1) /FT /Btn
+ \ifFDFvalues
+ /DV /\FDFdefault\space
+ /V /\FDFdefault\space
+ /AS /\FDFdefault\space
+ \fi
+ \FDFlayer
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ \FDFlayer\space
+ \FDFappearance\space
+% /IF << /SW /N >> % strange, only works for stupid buttons
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or % no appearance and layer ?
+ \setFDFkids[kids:][\currentFDFkids]%
+ \createpdfdictionaryobject{FDF}{#1}
+ {/T (#1) /FT /Btn
+ \FDFkids\space
+ \ifFDFvalues
+ /DV /\FDFdefault\space
+ /V /\FDFdefault\space
+ /AS /\FDFdefault\space
+ \fi
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \doFDFappearance{On}{#6}{#8}%
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference\space
+ \ifFDFvalues
+ /DV /\FDFdefault\space
+ /V /\FDFdefault\space
+ /AS /\FDFdefault\space
+ \fi
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ \FDFlayer\space
+ \FDFappearance\space
+ \FDFactions}%
+ \or
+ \doFDFappearance{On}{#6}{#8}%
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference\space
+ /F \FDFplus\space
+ \ifFDFvalues
+ /DV /\FDFdefault\space
+ /V /\FDFdefault\space
+ /AS /\FDFdefault\space
+ \fi
+ \FDFlayer\space
+ \FDFappearance
+ \FDFactions}%
+ \fi
+ \egroup}
+
+\def\dopresetpushfield#1#2#3#4#5#6#7%
+ {\doFDFpresetpushcheckfield{#1}{#2}{#3}{#4}{PushButton,#5}{#6}{#7}{0}}
+
+\def\dopresetcheckfield#1#2#3#4#5#6#7%
+ {\doFDFpresetpushcheckfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{1}}
+
+\def\dopresetradiofield#1#2#3#4#5#6#7#8%
+ {\bgroup
+ \setFDFlayer\@@DriverFieldLayer
+ \FDFvaluestrue
+ \setFDFswitches[#5]%
+ \setFDFactions[#8]%
+ \doifelsenothing{#4}
+ {\def\FDFdefault{Off}}
+ {\def\FDFdefault{#4}}%
+ \@EA\aftersplitstring\FDFdefault\at=>\to\FDFdefaultvalue
+ \ifx\FDFdefaultvalue\empty\else\let\FDFdefault\FDFdefaultvalue\fi
+ \ifcase\currentFDFmode
+ \doFDFappearance{#1}{#7}{1}%
+ \doPDFgetobjectreference{FDF}{#6}\PDFobjectreference
+ \createpdfannotationobject{FDF}{#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference\space
+ /F \FDFplus\space
+ /AS /\FDFdefault\space
+ \FDFlayer\space
+ \FDFappearance\space
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ \setFDFkids[kids:][\currentFDFkids]%
+ \doPDFgetobjectreference{FDF}{#6}\PDFobjectreference
+ \createpdfdictionaryobject{FDF}{#1}
+ {/Parent \PDFobjectreference\space
+ \FDFkids\space
+ /F \FDFplus\space
+ \FDFactions}%
+ \registerFDFobject{#1}%
+ \or
+ %\doFDFappearance{#1}{#7}{1}%
+ \doFDFappearance{\currentFDFparent}{#7}{1}%
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue % nb
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference\space
+ /AS /\FDFdefault\space
+ /F \FDFplus\space
+ \FDFlayer\space
+ \FDFappearance\space
+ \FDFactions}%
+ \or
+ %\doFDFappearance{#1}{#7}{1}%
+ \doFDFappearance{\currentFDFparent}{#7}{1}%
+ \doPDFgetobjectreference{FDF}\currentFDFparent\PDFobjectreference
+ %\global\objectreferencingtrue
+ \createpdfannotationobject{FDF}{kids:#1}{#2}{#3}
+ {/Subtype /Widget
+ /Parent \PDFobjectreference\space
+ /AS /\FDFdefault\space
+ /F \FDFplus\space
+ \FDFlayer\space
+ \FDFappearance\space
+ \FDFactions}%
+ \fi
+ \egroup}
+
+% Beware, RadiosInUnison is really needed in the pre 1.5/6 time this
+% was the default but out of a sudden it's no longer the case. Also
+% the NoToggleToOff interferes with kids of kids and both it will
+% break older documents, i.e. so much for pdf as standard. With
+% features like widgets we can probably best wait till adobe tools
+% themselves support it because that's probably the moment that
+% functionality gets frozen/becomes definitive. Actually, acrobat
+% flattens the kids tree, so that's yet another situation. The
+% interesting thing is that it worked ok in acrobat 2/3 but got bugged
+% in later versions. [The rationale is in html compatibility, which
+% seems to be more important than compatibility of documents, which in
+% turn renders acrobat useless for forms.] Anyway, synchronization is
+% broken or not depending on the combination pdfversion/acrobatversion.
+
+\def\dopresetradiorecord#1#2#3#4#5%
+ {\bgroup
+ % < pdf 1.5 (1.5 was broken)
+ % \setFDFswitches[Radio,NoToggleToOff,RadiosInUnison,#3]%
+ % > pdf 1.5
+ \setFDFswitches[Radio,RadiosInUnison,#3]%
+ % older, else fatal error
+ % \setFDFkids[#4][]%
+ % newer
+ \setFDFvalues[#4][#2]% inits kidlist
+ \expanded{\setFDFkids[][\FDFkidlist]}%
+ %
+ \setFDFactions[#5]%
+ \createpdfdictionaryobject{FDF}{#1}
+ {%/Subtype /Widget
+ /FT /Btn /T (#1) /Rect [0 0 0 0]
+ % used to be this
+ % /V (#2)
+ % then this
+ % /DV (#2)
+ % since this bomded in 5
+ % /V (#2)
+ % and now finally this works
+ /H /N
+ % /opt is buggy in 5.05, only works once, sigh
+ %\ifx\FDFfirstvalues\FDFsecondvalues
+ /V /#2
+ %\else
+ % /V /\FDFdefaultindex\space
+ % /Opt [\FDFsecondvalues]
+ %\fi
+ /Ff \FDFflag\space
+ /F \FDFplus\space
+ \FDFkids\space
+ \FDFactions}%
+ \egroup}
+
+%D At the cost of some more references, we can save bytes,
+%D by sharing appearance dictionaries. This code needs more
+%D documentation. Surprise:
+
+\def\dodoFDFappearance#1#2%
+ {\ifx#2\empty\else
+ \dogetcommacommandelement1\from#2\to\commalistelement
+ \ifx\commalistelement\empty\else
+ \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference
+ \edef\N{\ifFDFvalues\N /#1 \fi\PDFobjectreference\space}%
+ \fi
+ \dogetcommacommandelement2\from#2\to\commalistelement
+ \ifx\commalistelement\empty\else
+ \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference
+ \edef\R{\ifFDFvalues\R /#1 \fi\PDFobjectreference\space}%
+ \fi
+ \dogetcommacommandelement3\from#2\to\commalistelement
+ \ifx\commalistelement\empty\else
+ \doPDFgetobjectreference{SYM}\commalistelement\PDFobjectreference
+ \edef\D{\ifFDFvalues\D /#1 \fi\PDFobjectreference\space}%
+ \def\FDFappearance{/H /P }%
+ \fi
+ \fi}
+
+\def\redoFDFappearance#1%
+ {\ifx#1\empty\else
+ \dogetcommacommandelement3\from#1\to\commalistelement
+ \ifx\commalistelement\empty\else
+ \def\FDFappearance{/H /P }%
+ \fi
+ \fi}
+
+\def\doFDFappearance#1#2#3%
+ {\ifcase#3\relax % push only field
+ \edef\yes{#2}%
+ \let\no\empty
+ \else % on / off field
+ \dogetcommacommandelement1\from#2,\to\yes
+ \dogetcommacommandelement2\from#2,\to\no
+ \fi
+ \def\FDFappearance{/H /N}%
+ \doifobjectfoundelse{FDF}{ap:#1:\yes:\no}
+ {\redoFDFappearance\yes
+ \redoFDFappearance\no}
+ {\presetobject{FDF}{ap:#1:\yes:\no}% funny hack
+ \let\N\empty\let\R\empty\let\D\empty
+ \dodoFDFappearance{#1}\yes
+ \dodoFDFappearance{Off}\no
+ \createpdfdictionaryobject{FDF}{ap:#1:\yes:\no}
+ {\ifx\N\empty\else/N \ifFDFvalues<<\N>>\else\N\fi\fi
+ \ifx\R\empty\else/R \ifFDFvalues<<\R>>\else\R\fi\fi
+ \ifx\D\empty\else/D \ifFDFvalues<<\D>>\else\D\fi\fi}}%
+ \doPDFgetobjectreference{FDF}{ap:#1:\yes:\no}\PDFobjectreference
+ \edef\FDFappearance{\FDFappearance /AP \PDFobjectreference}}
+
+\def\doFDFdefault#1#2%
+ {\doifelse{#2}{1}{\def\FDFdefault{On}}{\def\FDFdefault{Off}}}
+
+%D Layer support:
+
+\def\setFDFlayer#1% todo : \ifx\PDFobjectreference\noPDFobjectreference ipv found
+ {\letempty\FDFlayer
+ \doifsomething{#1}%
+ {\checkproperty[#1]% == \dodocheckproperty\@@DriverFieldLayer
+ \doifobjectreferencefoundelse{PDLN}{#1}
+ {\doPDFgetobjectreference{PDLN}{#1}\!!stringa % we need to avoid a clash with other macros
+ \edef\FDFlayer{/OC \!!stringa}}%
+ \donothing}}
+
+%D The three appearances {\em normal}, \type{roll over} and
+%D \type{push down} are passed as comma separated triplets,
+%D that is, the second argument can look like:
+%D
+%D \starttyping
+%D {yes,ok,fine},{no,rubish,awful}
+%D \stoptyping
+
+%D \macros
+%D {dodefinefieldset,dogetfieldset,doiffieldset}
+%D
+%D Field sets, the ones we use in submitting and resetting
+%D fields, are implemented using the next low level specials:
+%D
+%D \starttyping
+%D \doFDFdefinefieldset{TAG}{name,name,...}
+%D \doFDFgetfieldset{TAG}
+%D \doiffieldset{TAG}{sequence}
+%D \stoptyping
+
+\def\dodefinefieldset#1#2% tag commalist
+ {\let\FDFfieldset\empty
+ \def\docommand##1%
+ {\doPDFgetobjectreference{FDF}{##1}\PDFobjectreference
+ \edef\FDFfieldset{\FDFfieldset\PDFobjectreference\space}}%
+ \processcommacommand[#2]\docommand % nb: command
+ \setevalue{FDF:set:#1}{\FDFfieldset}}
+
+\def\dogetfieldset#1%
+ {\getvalue{FDF:set:#1}}
+
+\def\doiffieldset#1#2%
+ {\ifundefined{FDF:set:#1}\else#2\fi}
+
+%D \macros
+%D {defaultobjectreference,doPDFgetobjectreference}
+%D
+%D Because in \PDFTEX\ we have to construct the object
+%D references \type{N 0 R}, we can default to the non existing
+%D zero object number.
+
+\def\defaultobjectreference#1#2%
+ {0}
+
+\def\doPDFgetobjectreference#1#2#3%
+ {\dogetobjectreference{#1}{#2}#3%
+ \edef#3{\ifx#3\empty null\else\PDFobjref{#3}\fi}}
+
+\def\doPDFgetobjectnumber#1#2#3%
+ {\dogetobjectreference{#1}{#2}#3%
+ \edef#3{\ifx#3\empty 0\else#3\fi}}
+
+\def\doPDFgetobjectpage#1#2#3%
+ {\dogetobjectreferencepage{#1}{#2}#3%
+ \ifx#3\empty\def#3{1}\fi}
+
+\def\doPDFgetobjectpagereference#1#2#3%
+ {\dogetobjectreferencepage{#1}{#2}#3%
+ \ifx#3\empty
+ \doPDFgetpagereference\realfolio#3%
+ \else
+ \doPDFgetpagereference#3#3% we assume that #3 gets expanded
+ \fi}
+
+\def\doPDFgetpagereference#1#2% number macro
+ {\edef#2{\ifnum#1>\zerocount\PDFobjref{\pdfpageref#1}\else null\fi}}
+
+\def\thePDFpagereference#1#2% number macro
+ {\ifnum#1>\zerocount\PDFobjref{\pdfpageref#1}\else null\fi}
+
+%D \macros
+%D {initializePDFnegative,initializePDFoverprint}
+%D
+%D Here follow some rather obscure macros. They will only
+%D come into action when one wants negated output.
+
+\def\initializePDFnegative
+ {\immediate\pdfobj stream attr {/FunctionType 4 /Range [0 1] /Domain [0 1]} {{1 exch sub}}%
+ \immediate\pdfobj{<</Type /ExtGState /TR \PDFobjref\pdflastobj>>}%
+ \appendtoPDFdocumentextgstates{/GSnegative \PDFobjref\pdflastobj}%
+ \immediate\pdfobj{<</Type /ExtGState /TR /Identity>>}%
+ \appendtoPDFdocumentextgstates{/GSpositive \PDFobjref\pdflastobj}%
+ \global\let\initializePDFnegative\relax}
+
+\def\initializePDFoverprint
+ {\immediate\pdfobj{<</Type /ExtGState /OP false /OPM 0>>}% /op defaults to /OP
+ \appendtoPDFdocumentextgstates{/GSknockout \PDFobjref\pdflastobj}%
+ \immediate\pdfobj{<</Type /ExtGState /OP true /OPM 1>>}% /op defaults to /OP
+ \edef\PDFobjectreferenceB{\the\pdflastobj}%
+ \appendtoPDFdocumentextgstates{/GSoverprint \PDFobjref\pdflastobj}%
+ \global\let\initializePDFoverprint\relax}
+
+%D File embedding. Storing the stream identifier is needed
+%D to get access to the number. When typeset, the user can
+%D feed this number to \type {pdftosrc} and filter the
+%D file from the \PDF\ file.
+
+\let\PDFlaststreamobject \s!unknown
+%def\PDFlaststreamreference{0 0 R}
+
+\def\doPDFfilestreamobject#1#2#3#4%
+ {\immediate\pdfobj stream file{#4}%
+ \edef\PDFlaststreamobject{\the\pdflastobj}%
+ \dosetobjectreference{PDFFS}{#2}{\PDFlaststreamobject}%
+ \createpdfdictionaryobject{#1}{#2}{/Type /Filespec /F (#3) /EF <</F \PDFobjref\PDFlaststreamobject>>}}
+
+\def\doPDFgetfilestreamreference#1#2%
+ {\doPDFgetobjectreference{PDFFS}{#1}#2}
+
+\def\doPDFfilestreamidentifier#1%
+ {\doifsomething{#1}
+ {\doPDFgetfilestreamreference{#1}\PDFobjectreference
+ \@EA\beforesplitstring\PDFobjectreference\at{ }\to\PDFlaststreamobject
+ \PDFlaststreamobject}}
+
+% MP ?
+
+ \def\setMPPDFobject#1#2% resources boxnumber
+ {\the\everyPDFxform
+ \finalizeobjectbox{#2}%
+ \immediate\pdfxform resources{#1}#2%
+ \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}}
+
+ \let\getMPPDFobject\relax
+
+ \def\doinsertMPfile#1%
+ {\doiffileelse{./#1}{\includeMPasPDF{./#1}}{\message{[MP #1]}}}
+
+%D Even newer trickery:
+
+% resource -> prop -> mc's -> OCG|OCMD (nested)
+% ocg:
+% /Intent/Design
+% ocmd
+% /P /AllOn
+% kan zelf ocmd bevatten
+
+\let\PDFtextlayers\empty
+\let\PDFpagelayers\empty
+\let\PDFhidelayers\empty
+\let\PDFvidelayers\empty
+
+\def\dostartlayer#1{\PDFcode{/OC /#1 BDC}}
+\def\dostoplayer {\PDFcode {EMC}}
+
+\def\dodefineviewerlayer#1#2#3#4#5% tag title visible type printable
+ {\createpdfdictionaryobject{PDLN}{#1}
+ {/Type /OCG
+ \ifcase#4 \or
+ /Intent /Design % disable layer hiding by user
+ \fi
+ \ifnum#5=\zerocount
+ /Usage << /Print << /PrintState /OFF >> >> % printable or not
+ \fi
+ /Name (#2)}%
+ \doPDFgetobjectreference{PDLN}{#1}\PDFobjectreference
+ \xdef\PDFtextlayers{\PDFtextlayers\space\PDFobjectreference}%
+ \doifelse{#3}\v!start
+ {\xdef\PDFvidelayers{\PDFvidelayers\space\PDFobjectreference}}%
+ {\xdef\PDFhidelayers{\PDFhidelayers\space\PDFobjectreference}}%
+ \createpdfdictionaryobject{PDLD}{#1}
+ {/Type /OCMD
+ /OCGs [\PDFobjectreference]}%
+ \doPDFgetobjectreference{PDLD}{#1}\PDFobjectreference
+ \xdef\PDFpagelayers{\PDFpagelayers\space /#1 \PDFobjectreference}}
+
+\def\flushPDFtextlayers
+ {\ifx\PDFtextlayers\empty \else
+ \driverreferenced \createpdfarrayobject{PDF}{textlayers}{\PDFtextlayers}%
+ \doPDFgetobjectreference{PDF}{textlayers}\!!stringa
+ \ifx\PDFvidelayers\empty
+ \def\!!stringb{[null]}%
+ \else
+ \driverreferenced \createpdfarrayobject{PDF}{videlayers}{\PDFvidelayers}%
+ \doPDFgetobjectreference{PDF}{videlayers}\!!stringb
+ \fi
+ \ifx\PDFhidelayers\empty
+ \def\!!stringc{[null]}%
+ \else
+ \driverreferenced \createpdfarrayobject{PDF}{hidelayers}{\PDFhidelayers}%
+ \doPDFgetobjectreference{PDF}{hidelayers}\!!stringc
+ \fi
+ \appendtopdfcatalog
+ {/OCProperties
+ << % display in menu
+ /D << /Order \!!stringa
+ /ON \!!stringb
+ /OFF \!!stringc >>
+ % used properties
+ /OCGs \!!stringa >>}%
+ \globallet\flushPDFtextlayers\relax
+ \fi}
+
+\def\flushPDFpagelayers
+ {\ifx\PDFpagelayers\empty \else
+ \appendtopdfpageresources{/Properties <<\PDFpagelayers>>}%
+ \fi}
+
+\def\PDFlayeractionlist{null}
+
+\def\PDFexecutehidelayer {/SetOCGState /State [/OFF \PDFlayeractionlist]}
+\def\PDFexecutevidelayer {/SetOCGState /State [/ON \PDFlayeractionlist]}
+\def\PDFexecutetogglelayer {/SetOCGState /State [/Toggle \PDFlayeractionlist]}
+
+\def\domakeviewerlayerlist#1%
+ {\bgroup
+ \globallet\PDFlayeractionlist\empty
+ \def\docommand##1%
+ {\doPDFgetobjectreference{PDLN}{##1}\PDFobjectreference
+ \xdef\PDFlayeractionlist{\PDFlayeractionlist\space\PDFobjectreference}}%
+ \processcommalist[#1]\docommand
+ \egroup}
+
+%D Something rather pdf dependent:
+
+% #1 => 1=fill 2=stroke 3=strokedfill 4=invisible
+% #2 => linewidth
+% #3 => spacing (beware, one needs to set the hsize as well)
+
+\def\dostartfonteffect#1#2#3%
+ {\ifdim#2>\zeropoint
+ \PointsToBigPoints{#2}\ascii
+ \PDFcode{\ascii\space w}%
+ \fi
+ \ifdim#3\points=\onepoint\else
+ \scratchdimen#3\points
+ \PDFcode{\withoutpt{\the\scratchdimen}\space Tc}%
+ \fi
+ \PDFcode{\purenumber#1 Tr}}
+
+\def\dostopfonteffect
+ {\PDFcode{1 w 0 Tc 0 Tr}}
+
+%D Handy for the \METAPOST\ to \PDF\ converter:
+
+\appendtoksonce
+ \collectPDFresources
+ \global\let\currentPDFresources\collectedPDFresources
+\to \everyPDFxform
+
+\let\collectedPDFresources\empty
+
+\def\collectPDFresources % suboptimal
+ {\doifobjectreferencefoundelse{FDF}{docushades} % redundant, we have an reserved object now
+ {\doPDFgetobjectreference{FDF}{docushades}\PDFobjectreference
+ \xdef\collectedPDFresources{\collectedPDFresources/Shading \PDFobjectreference}}\donothing
+ \doifobjectreferencefoundelse{FDF}{docuextgstates}
+ {\doPDFgetobjectreference{FDF}{docuextgstates}\PDFobjectreference
+ \xdef\collectedPDFresources{\collectedPDFresources/ExtGState \PDFobjectreference}}\donothing
+ \doifobjectreferencefoundelse{FDF}{colorspaces}
+ {\doPDFgetobjectreference{FDF}{colorspaces}\PDFobjectreference
+ \xdef\collectedPDFresources{\collectedPDFresources/ColorSpace \PDFobjectreference}}\donothing
+ \global\let\collectPDFresources\relax}
+
+\appendtoks
+ \flushPDFpagelayers
+ \flushJSpreamble
+ \flushJSpreamble
+ \checkPDFextgstates
+ \checkPDFcolorspaces
+ \checkPDFshades
+ \checkPDFpageactions
+ \fakePDFpagedestination
+ \flushPDFpageboxes
+ \addPDFdocumentinfo
+\to \everybackendshipout
+
+\appendtoks
+ \flushPDFtextlayers
+ \finalflushJSpreamble
+\to \everylastbackendshipout
+
+%D Temporary hack:
+
+\def\TransparencyHack % png: /CS /DeviceRGB /I true
+ {\appendtoksonce
+ \appendtopdfpageattributes{/Group << /S /Transparency /I true /K true>>}%
+ \to \everyPDFxform
+ \appendtoksonce
+ \appendtopdfpageattributes{/Group << /S /Transparency /I true /K true>>}%
+ \to \everyshipout}
+
+\protect \endinput
diff --git a/tex/context/base/bibl-bib.lua b/tex/context/base/bibl-bib.lua
new file mode 100644
index 000000000..028202ec2
--- /dev/null
+++ b/tex/context/base/bibl-bib.lua
@@ -0,0 +1,233 @@
+if not modules then modules = { } end modules ['bibl-bib'] = {
+ 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"
+}
+
+--[[ldx--
+<p>This is a prelude to integrated bibliography support. This file just loads
+bibtex files and converts them to xml so that the we access the content
+in a convenient way. Actually handling the data takes place elsewhere.</p>
+--ldx]]--
+
+local lower, format = string.lower, string.format
+local next = next
+
+bibtex = bibtex or { }
+
+bibtex.size = 0
+bibtex.definitions = 0
+bibtex.shortcuts = 0
+
+local shortcuts = { }
+local data = { }
+local entries
+
+local function do_shortcut(tag,key,value)
+ bibtex.shortcuts = bibtex.shortcuts + 1
+ if lower(tag) == "@string" then
+ shortcuts[key] = value
+ end
+end
+
+local function do_definition(tag,key,tab) -- maybe check entries here (saves memory)
+ if not entries or entries[key] then
+ bibtex.definitions = bibtex.definitions + 1
+ local t = { }
+ for i=1,#tab,2 do
+ t[tab[i]] = tab[i+1]
+ end
+ local p = data[tag]
+ if not p then
+ data[tag] = { [key] = t }
+ else
+ p[key] = t
+ end
+ end
+end
+
+local function resolve(s)
+ return shortcuts[s] or ""
+end
+
+local percent = lpeg.P("%")
+local start = lpeg.P("@")
+local comma = lpeg.P(",")
+local hash = lpeg.P("#")
+local escape = lpeg.P("\\")
+local single = lpeg.P("'")
+local double = lpeg.P('"')
+local left = lpeg.P('{')
+local right = lpeg.P('}')
+local both = left + right
+local lineending = lpeg.S("\n\r")
+local space = lpeg.S(" \t\n\r\f")
+local spacing = space^0
+local equal = lpeg.P("=")
+local collapsed = (space^1)/ " "
+
+local function add(a,b) if b then return a..b else return a end end
+
+local keyword = lpeg.C((lpeg.R("az","AZ","09") + lpeg.S("@_:-"))^1) -- lpeg.C((1-space)^1)
+local s_quoted = ((escape*single) + collapsed + (1-single))^0
+local d_quoted = ((escape*double) + collapsed + (1-double))^0
+local balanced = lpeg.P {
+ [1] = ((escape * (left+right)) + (1 - (left+right)) + lpeg.V(2))^0,
+ [2] = left * lpeg.V(1) * right
+}
+
+local s_value = (single/"") * s_quoted * (single/"")
+local d_value = (double/"") * d_quoted * (double/"")
+local b_value = (left /"") * balanced * (right /"")
+local r_value = keyword/resolve
+
+local somevalue = s_value + d_value + b_value + r_value
+local value = lpeg.Cs((somevalue * ((spacing * hash * spacing)/"" * somevalue)^0))
+
+local assignment = spacing * keyword * spacing * equal * spacing * value * spacing
+local shortcut = keyword * spacing * left * spacing * (assignment * comma^0)^0 * spacing * right
+local definition = keyword * spacing * left * spacing * keyword * comma * lpeg.Ct((assignment * comma^0)^0) * spacing * right
+local comment = keyword * spacing * left * (1-right)^0 * spacing * right
+local forget = percent^1 * (1-lineending)^0
+
+-- todo \%
+
+local grammar = (space + forget + shortcut/do_shortcut + definition/do_definition + comment + 1)^0
+
+function bibtex.convert(session,content)
+ statistics.starttiming(bibtex)
+ data, shortcuts, entries = session.data, session.shortcuts, session.entries
+ -- session.size = session.size + #content
+ bibtex.size = bibtex.size + #content
+ grammar:match(content or "")
+ statistics.stoptiming(bibtex)
+end
+
+function bibtex.load(session,filename)
+ local filename = resolvers.find_file(filename,"bib")
+ if filename ~= "" then
+ bibtex.convert(session,io.loaddata(filename) or "")
+ end
+end
+
+function bibtex.new()
+ return {
+ data = { },
+ shortcuts = { },
+ xml = xml.convert("<?xml version='1.0' standalone='yes'?>\n<bibtex></bibtex>"),
+ size = 0,
+ entries = nil,
+ }
+end
+
+local escaped_pattern = xml.escaped_pattern
+
+function bibtex.toxml(session)
+ -- we can always speed this up if needed
+ -- format slows down things a bit but who cares
+ statistics.starttiming(bibtex)
+ local result = { }
+ local entries = session.entries
+ result[#result+1] = format("<?xml version='1.0' standalone='yes'?>")
+ result[#result+1] = format("<bibtex>")
+ for id, categories in next, session.data do
+ result[#result+1] = format(" <c n='%s'>",id)
+ for name, entry in next, categories do
+ if not entries or entries[name] then
+ result[#result+1] = format(" <e n='%s'>",name)
+ for key, value in next, entry do
+ value = escaped_pattern:match(value)
+ if value ~= "" then
+ result[#result+1] = format(" <v n='%s'>%s</v>",key,value)
+ end
+ end
+ result[#result+1] = format(" </e>")
+ end
+ end
+ result[#result+1] = format(" </c>")
+ end
+ result[#result+1] = format("</bibtex>")
+ session.xml = xml.convert(table.concat(result,"\n"))
+ statistics.stoptiming(bibtex)
+end
+
+statistics.register("bibtex load time", function()
+ local size = bibtex.size
+ if size > 0 then
+ return format("%s seconds (%s bytes, %s definitions, %s shortcuts)",
+ statistics.elapsedtime(bibtex),size,bibtex.definitions,bibtex.shortcuts)
+ else
+ return nil
+ end
+end)
+
+--~ str = [[
+--~ @COMMENT { CRAP }
+--~ @STRING{ hans = "h a n s" }
+--~ @STRING{ taco = "t a c o" }
+--~ @SOMETHING{ key1, abc = "t a c o" , def = "h a n s" }
+--~ @SOMETHING{ key2, abc = hans # taco }
+--~ @SOMETHING{ key3, abc = "hans" # taco }
+--~ @SOMETHING{ key4, abc = hans # "taco" }
+--~ @SOMETHING{ key5, abc = hans # taco # "hans" # "taco"}
+--~ @SOMETHING{ key6, abc = {oeps {oeps} oeps} }
+--~ ]]
+
+--~ local session = bibtex.new()
+--~ bibtex.convert(session,str)
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"IEEEabrv.bib")
+--~ bibtex.load(session,"IEEEfull.bib")
+--~ bibtex.load(session,"IEEEexample.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ local session = bibtex.new()
+--~ bibtex.load(session,"gut.bib")
+--~ bibtex.load(session,"komoedie.bib")
+--~ bibtex.load(session,"texbook1.bib")
+--~ bibtex.load(session,"texbook2.bib")
+--~ bibtex.load(session,"texbook3.bib")
+--~ bibtex.load(session,"texgraph.bib")
+--~ bibtex.load(session,"texjourn.bib")
+--~ bibtex.load(session,"texnique.bib")
+--~ bibtex.load(session,"tugboat.bib")
+--~ bibtex.toxml(session)
+--~ print(session.size,statistics.elapsedtime(bibtex))
+
+--~ print(table.serialize(session.data))
+--~ print(table.serialize(session.shortcuts))
+--~ print(xml.serialize(session.xml))
+
+-- this will move:
+
+if commands then
+
+ local sessions = { }
+
+ function commands.definebibtexsession(name)
+ sessions[name] = bibtex.new()
+ end
+ function commands.preparebibtexsession(name)
+ bibtex.toxml(sessions[name])
+ lxml.register("bibtex:"..name,sessions[name].xml)
+ end
+ function commands.registerbibtexfile(name,filename)
+ bibtex.load(sessions[name],filename)
+ end
+ function commands.registerbibtexentry(name,entry)
+ local session = sessions[name]
+ local entries = session.entries
+ if not entries then
+ session.entries = { [entry] = true }
+ else
+ entries[entry] = true
+ end
+ end
+
+end
diff --git a/tex/context/base/bibl-bib.tex b/tex/context/base/bibl-bib.tex
new file mode 100644
index 000000000..51db67ed7
--- /dev/null
+++ b/tex/context/base/bibl-bib.tex
@@ -0,0 +1,29 @@
+%D \module
+%D [ file=bibl-bib,
+%D version=2007.08.17,
+%D title=\CONTEXT\ Bibliography Support,
+%D subtitle=Initialization,
+%D author=Hans Hagen \& Taco Hoekwater,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Bibliography Support / BibTeX}
+
+\registerctxluafile{bibl-bib}{1.001}
+
+\unprotect
+
+\def\definebibtexsession [#1]{\ctxlua{commands.definebibtexsession("#1")}}
+\def\preparebibtexsession [#1]{\ctxlua{commands.preparebibtexsession("#1")}}
+\def\registerbibtexfile {\dodoubleargument\doregisterbibtexfile}
+\def\doregisterbibtexfile [#1][#2]{\ctxlua{commands.registerbibtexfile("#1","#2")}} % also the fast one
+\def\registerbibtexentry {\dodoubleargument\doregisterbibtexentry}
+\def\doregisterbibtexentry [#1][#2]{\ctxlua{commands.registerbibtexentry("#1","#2")}} % also the fast one
+\def\applytobibtexsession {\dodoubleargument\doapplytobibtexsession}
+\def\doapplytobibtexsession[#1][#2]{\xmlprocessregistered{bibtex:#1}{#2}{#2}}
+
+\protect \endinput
diff --git a/tex/context/base/bibl-tst.lua b/tex/context/base/bibl-tst.lua
new file mode 100644
index 000000000..a1b85b0f7
--- /dev/null
+++ b/tex/context/base/bibl-tst.lua
@@ -0,0 +1,21 @@
+dofile("bibl-bib.lua")
+
+local session = bibtex.new()
+
+bibtex.load(session,"gut.bib")
+bibtex.load(session,"komoedie.bib")
+bibtex.load(session,"texbook1.bib")
+bibtex.load(session,"texbook2.bib")
+bibtex.load(session,"texbook3.bib")
+bibtex.load(session,"texgraph.bib")
+bibtex.load(session,"texjourn.bib")
+bibtex.load(session,"texnique.bib")
+bibtex.load(session,"tugboat.bib")
+bibtex.toxml(session)
+
+print(bibtex.size,statistics.elapsedtime(bibtex))
+
+--~ print(table.serialize(session.data))
+--~ print(table.serialize(session.shortcuts))
+--~ print(xml.serialize(session.xml))
+
diff --git a/tex/context/base/catc-act.tex b/tex/context/base/catc-act.tex
new file mode 100644
index 000000000..5aecb2493
--- /dev/null
+++ b/tex/context/base/catc-act.tex
@@ -0,0 +1,61 @@
+%D \module
+%D [ file=catc-act,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Default Catcode Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module deals with some active character handling. Use
+%D with care.
+
+%D \macros
+%D {installactivecharacter}
+
+\def\installactivecharacter#1 %
+ {\edef\temp{\detokenize{#1}}%
+ \cctcounterc\expandafter`\temp\relax % relax needed
+ \expandafter\startextendcatcodetable
+ \expandafter\ctxcatcodes\expandafter\catcode\the\cctcounterc=13
+ \stopextendcatcodetable
+ \letcatcodecommand \ctxcatcodes \cctcounterc \temp \relax
+ \ifnum\currentcatcodetable=\ctxcatcodes \setcatcodetable\ctxcatcodes \fi}
+
+%D \macros
+%D {defineactivecharacter}
+%D
+%D Use this one with care, esp in combination with catcode
+%D vectors. There are better ways now.
+
+\chardef\activehackcode=`~
+
+\def\defineactivecharacter #1#2 #3%
+ {\cctcounterc\uccode\activehackcode
+ \if#1"\uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty #1#2\else
+ \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty`#1#2\fi
+ \catcode\uccode\activehackcode13
+ \uppercase{\def\next{~}}%
+ \uccode\activehackcode\cctcounterc
+ \expandafter\expandafter\expandafter\def\expandafter\next\expandafter
+ {\expandafter\dohandleactivecharacter\next{#3}}}
+
+\chardef\activecharactermode\plusone % overloading still backward compatible
+
+\def\dodohandleactivecharacter#1#2{#2}
+\def\donthandleactivecharacter#1#2{\noexpand#1}
+
+\def\dohandleactivecharacter
+ {\ifcase\activecharactermode
+ \expandafter\donthandleactivecharacter
+ \else
+ \expandafter\dodohandleactivecharacter
+ \fi}
+
+\def\makecharacteractive #1 {\catcode`#1\active}
+
+\endinput
diff --git a/tex/context/base/catc-ctx.tex b/tex/context/base/catc-ctx.tex
new file mode 100644
index 000000000..028ae496c
--- /dev/null
+++ b/tex/context/base/catc-ctx.tex
@@ -0,0 +1,207 @@
+%D \module
+%D [ file=catc-cys,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Extra Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%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 % < >
+
+\startcatcodetable \ctxcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ % \catcode`\^^J = 10 % new
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \prtcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\@ = 11
+ \catcode`\! = 11
+ \catcode`\? = 11
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \mthcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ %\catcode`\^^J = 10 % new
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ %\catcode`\~ = 13
+ %\catcode`\| = 13
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodesn
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\" = 12 % probably not needed any more
+ \catcode`\/ = 12 % probably not needed any more
+ \catcode`\' = 12 % probably not needed any more
+ \catcode`\~ = 12 % probably not needed any more
+ \catcode`\# = 12 % probably not needed any more
+ \catcode`\\ = 12 % probably not needed any more
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodese
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\# = 13
+ \catcode`\$ = 13
+ \catcode`\% = 13
+ \catcode`\\ = 13
+ \catcode`\^ = 13
+ \catcode`\_ = 13
+ \catcode`\{ = 13
+ \catcode`\} = 13
+ \catcode`\| = 13
+ \catcode`\~ = 13
+\stopcatcodetable
+
+\startcatcodetable \xmlcatcodesr
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\& = 13 % entity
+ \catcode`\< = 13 % element
+ \catcode`\> = 12
+ \catcode`\# = 13
+ \catcode`\$ = 13
+ \catcode`\% = 13
+ \catcode`\\ = 13
+ \catcode`\^ = 13
+ \catcode`\_ = 13
+ \catcode`\{ = 13
+ \catcode`\} = 13
+ \catcode`\| = 13
+ \catcode`\~ = 13
+\stopcatcodetable
+
+\startcatcodetable \typcatcodesa
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+ \catcode`\{ = 1
+ \catcode`\} = 2
+\stopcatcodetable
+
+\startcatcodetable \typcatcodesb
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+ \catcode`\< = 1
+ \catcode`\> = 2
+\stopcatcodetable
+
+\letcatcodecommand \ctxcatcodes `\| \relax
+\letcatcodecommand \ctxcatcodes `\~ \relax
+
+%letcatcodecommand \prtcatcodes `\| \relax % falls back on ctx
+%letcatcodecommand \prtcatcodes `\~ \relax % falls back on ctx
+
+\letcatcodecommand \xmlcatcodesn `\& \relax
+\letcatcodecommand \xmlcatcodesn `\< \relax
+
+\letcatcodecommand \xmlcatcodese `\& \relax
+\letcatcodecommand \xmlcatcodese `\< \relax
+
+\letcatcodecommand \xmlcatcodesr `\& \relax
+\letcatcodecommand \xmlcatcodesr `\< \relax
+
+\letcatcodecommand \xmlcatcodese `\# \relax
+\letcatcodecommand \xmlcatcodese `\$ \relax
+\letcatcodecommand \xmlcatcodese `\% \relax
+\letcatcodecommand \xmlcatcodese `\\ \relax
+\letcatcodecommand \xmlcatcodese `\^ \relax
+\letcatcodecommand \xmlcatcodese `\_ \relax
+\letcatcodecommand \xmlcatcodese `\{ \relax
+\letcatcodecommand \xmlcatcodese `\} \relax
+\letcatcodecommand \xmlcatcodese `\| \relax
+\letcatcodecommand \xmlcatcodese `\~ \relax
+
+\letcatcodecommand \xmlcatcodesr `\# \relax
+\letcatcodecommand \xmlcatcodesr `\$ \relax
+\letcatcodecommand \xmlcatcodesr `\% \relax
+\letcatcodecommand \xmlcatcodesr `\\ \relax
+\letcatcodecommand \xmlcatcodesr `\^ \relax
+\letcatcodecommand \xmlcatcodesr `\_ \relax
+\letcatcodecommand \xmlcatcodesr `\{ \relax
+\letcatcodecommand \xmlcatcodesr `\} \relax
+\letcatcodecommand \xmlcatcodesr `\| \relax
+\letcatcodecommand \xmlcatcodesr `\~ \relax
+
+ \catcodetable \ctxcatcodes
+\let\defaultcatcodetable\ctxcatcodes
+\let\xmlcatcodes \xmlcatcodesn
+
+\endinput
diff --git a/tex/context/base/catc-def.tex b/tex/context/base/catc-def.tex
new file mode 100644
index 000000000..0346f6dae
--- /dev/null
+++ b/tex/context/base/catc-def.tex
@@ -0,0 +1,142 @@
+%D \module
+%D [ file=catc-def,
+%D version=2006.09.18,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Default Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%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
+
+\startcatcodetable \nilcatcodes
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+\stopcatcodetable
+
+\startcatcodetable \texcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+\stopcatcodetable
+
+\startcatcodetable \luacatcodes
+ \catcode`\^^I = 12 % ascii tab is a blank space
+ \catcode`\^^M = 12 % ascii return is end-line
+ \catcode`\^^L = 12 % ascii form-feed
+ \catcode`\ = 12 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\\ = 0
+ \catcode`\% = 12
+ \catcode`\# = 12
+ \catcode`\_ = 12
+ \catcode`\^ = 12
+ \catcode`\& = 12
+ \catcode`\| = 12
+ \catcode`\{ = 12
+ \catcode`\} = 12
+ \catcode`\~ = 12
+ \catcode`\$ = 12
+\stopcatcodetable
+
+\startcatcodetable \notcatcodes
+ \catcode`\^^I = 10 % ascii tab is a blank space
+ \catcode`\^^M = 5 % ascii return is end-line
+ \catcode`\^^L = 5 % ascii form-feed
+ \catcode`\ = 10 % ascii space is blank space
+ \catcode`\^^Z = 9 % ascii eof is ignored
+ \catcode`\~ = 12
+ \catcode`\# = 12 % probably too much, in principle
+ \catcode`\$ = 12 % nilcatcodes would be ok too
+ \catcode`\% = 12
+ \catcode`\^ = 12
+ \catcode`\& = 12
+ \catcode`\_ = 12
+ \catcode`\< = 12
+ \catcode`\> = 12
+ \catcode`\{ = 12
+ \catcode`\} = 12
+ \catcode`\" = 12
+ \catcode`\' = 12
+ \catcode`\/ = 12
+ \catcode`\\ = 12
+ \catcode`\| = 12
+\stopcatcodetable
+
+\startcatcodetable \vrbcatcodes % probably less needed
+ \catcode`\^^I = 12
+ \catcode`\^^M = 12
+ \catcode`\^^L = 12
+ \catcode`\ = 12
+ \catcode`\^^Z = 12
+\stopcatcodetable
+
+\startcatcodetable \prtcatcodes
+ \catcode`\^^I = 10
+ \catcode`\^^M = 5
+ \catcode`\^^L = 5
+ \catcode`\ = 10
+ \catcode`\^^Z = 9
+ \catcode`\\ = 0
+ \catcode`\{ = 1
+ \catcode`\} = 2
+ \catcode`\$ = 3
+ \catcode`\& = 4
+ \catcode`\# = 6
+ \catcode`\^ = 7
+ \catcode`\_ = 8
+ \catcode`\% = 14
+ \catcode`\@ = 11
+ \catcode`\! = 11
+ \catcode`\? = 11
+ \catcode`\~ = 13
+ \catcode`\| = 13
+\stopcatcodetable
+
+%D Because some characters have a special meaning, we provide
+%D shortcuts to their character representation.
+
+\chardef\%=`\%
+\chardef\&=`\&
+\chardef\#=`\#
+\chardef\$=`\$
+\chardef\{=`\{
+\chardef\}=`\}
+\chardef\\=`\\
+\chardef\^=`\^
+\chardef\_=`\_ % but way too wide in lm, so ... until that's fixed:
+
+%def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}
+\def\_{\dontleavehmode \kern.06em \vbox{\hrule width.3em}}
+
+%D From now on we can use the protection mechanisms.
+
+\def\unprotect {\pushcatcodetable\setcatcodetable\prtcatcodes}
+\def\protect {\popcatcodetable}
+
+\endinput
diff --git a/tex/context/base/catc-ini.lua b/tex/context/base/catc-ini.lua
new file mode 100644
index 000000000..e1558b459
--- /dev/null
+++ b/tex/context/base/catc-ini.lua
@@ -0,0 +1,28 @@
+if not modules then modules = { } end modules ['catc-ini'] = {
+ version = 1.001,
+ comment = "companion to catc-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+catcodes = catcodes or { }
+catcodes.numbers = catcodes.numbers or { }
+catcodes.names = catcodes.names or { }
+
+storage.register("catcodes/numbers", catcodes.numbers, "catcodes.numbers")
+storage.register("catcodes/names", catcodes.names, "catcodes.names")
+
+-- this only happens at initime
+
+function catcodes.register(name,number)
+ catcodes.numbers[name] = number
+ catcodes.names[number] = name
+ tex[name] = number
+end
+
+-- this only happens at runtime
+
+for k, v in next, catcodes.numbers do
+ tex[k] = v
+end
diff --git a/tex/context/base/catc-ini.mkii b/tex/context/base/catc-ini.mkii
new file mode 100644
index 000000000..60b7528dd
--- /dev/null
+++ b/tex/context/base/catc-ini.mkii
@@ -0,0 +1,229 @@
+%D \module
+%D [ file=catc-ini,
+%D version=2006.09.18,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Catcode Handling,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We've split the functionality of syst-cat.* over more files
+%D now so that we can load more selectively.
+
+%D A long standing wish has been the availability of catcode
+%D arrays. Because traditional \TEX\ does ot provide this we
+%D implement a fake method in the Mark II file.
+
+\ifx\zerocount\undefined \chardef \zerocount= 0 \fi
+\ifx\plusone \undefined \chardef \plusone = 1 \fi
+\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi
+
+\newif \ifrecatcodeuppercharacters % only used in good old tex
+
+% \newcount\cctdefcounter \cctdefcounter\plusone % 0 = signal
+\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate
+
+\newcount\cctcountera
+\newcount\cctcounterb
+\newcount\cctcounterc
+
+\def\newcatcodetable#1%
+ {\global\advance\cctdefcounter\plusone
+ \global\mathchardef#1\cctdefcounter
+ \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
+ \expandafter\newtoks\csname @@cct:\number\cctdefcounter\endcsname}
+
+\mathchardef\currentcatcodetable\zerocount
+
+\newtoks \setdefaultlowercatcodes
+\newtoks \setdefaultuppercatcodes
+
+\def\next#1% we don't have a proper loop defined yet
+ {\edef\nextnext{#1{\the#1\catcode\the\cctcountera\space\ifnum\catcode\cctcountera=11 11\else12\fi}}%
+ \nextnext\ifnum\cctcountera<\cctcounterb \advance\cctcountera\plusone \expandafter\next\expandafter#1\fi}
+
+\cctcountera 0 \cctcounterb 127 \next\setdefaultlowercatcodes
+\cctcountera 128 \cctcounterb 255 \next\setdefaultuppercatcodes
+
+\recatcodeuppercharactersfalse
+
+\def\catcodetable#1%
+ {\mathchardef\currentcatcodetable#1%
+ \the\setdefaultlowercatcodes
+ \ifrecatcodeuppercharacters\the\setdefaultuppercatcodes\fi
+ \the\csname @@cct:\number#1\endcsname}
+
+\long\def\startcatcodetable#1#2\stopcatcodetable
+ {\global\csname @@cct:\number#1\endcsname{#2}}
+
+\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
+ {\global\csname @@cct:\number#1\endcsname\expandafter{\the\csname @@cct:\number#1\endcsname#2}}
+
+%D The next command can be defined in a cleaner way in the
+%D Mk IV file but we want to have a fast one with a minimal
+%D chance for interference.
+
+\chardef\activehackcode=`\~
+
+%D Once a catcode is assigned, the next assignments will happen faster.
+
+% (expandable) let
+
+\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
+\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}
+
+\def\letcatcodecommandb % each time
+ {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\letcatcodecommandc
+ \fi}
+
+\def\letcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
+ {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
+ \reinstatecatcodecommanda
+ \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% expandable def
+
+\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
+\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}
+
+\def\defcatcodecommandb % each time
+ {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\defcatcodecommandc
+ \fi}
+
+\def\defcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% un expandable def (e.g. used for discretionaries)
+
+\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
+\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}
+
+\def\uedcatcodecommandb % each time
+ {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\uedcatcodecommandc
+ \fi}
+
+\def\uedcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\unexpanded\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}
+
+\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}
+
+\def\reinstatecatcodecommanda % can be used when a direct definition has been done
+ {\bgroup % and the selector has been lost
+ \uccode\activehackcode\cctcounterb
+ \catcode\uccode\activehackcode13
+ \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
+ \egroup}
+
+\chardef\defaultcatcodetable\zerocount
+
+\def\catcodecommand#1%
+ {\csname CCC:\number
+ \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
+ \currentcatcodetable \else \defaultcatcodetable
+ \fi
+ :\number#1\endcsname}
+
+%D \macros
+%D {restorecatcodes,
+%D beginrestorecatcodes,endrestorecatcodes}
+%D
+%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
+%D use only one auxiliary file, which deals with tables of
+%D contents, registers, two pass tracking, references etc. This
+%D file, as well as files concerning graphics, is processed when
+%D needed, which can be in the mid of typesetting verbatim.
+%D However, when reading in data in verbatim mode, we should
+%D temporary restore the normal \CATCODES, and that's exactly
+%D what the next macros do. Saving the catcodes can be
+%D disabled by saying \type{\localcatcodestrue}.
+
+\let\savedcatcodetable\relax
+
+\newcount\catcoderestorelevel
+
+\def\pushcatcodetable
+ {\advance\catcoderestorelevel\plusone
+ \tracepushcatcodetable
+ \expandafter\mathchardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}
+
+\def\popcatcodetable
+ {\ifcase\catcoderestorelevel
+ \immediate\write16{}%
+ \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
+ \immediate\write16{}%
+ \else
+ \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
+ \tracepopcatcodetable
+ \advance\catcoderestorelevel\minusone
+ \fi}
+
+\def\restorecatcodes % takes previous level
+ {\ifnum\catcoderestorelevel>\plusone
+ \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
+ \fi}
+
+\newtoks\everycatcodetable
+
+\def\setcatcodetable#1%
+ {\catcodetable#1%
+ \the\everycatcodetable
+ \tracesetcatcodetable}
+
+\def\dotracecatcodetable#1{\immediate\write16{[#1]}}
+
+\def\tracecatcodetables
+ {\def\tracesetcatcodetable {\dotracecatcodetable{set \catcodetablename\space at \number\catcoderestorelevel}}%
+ \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
+ \def\tracepopcatcodetable {\dotracecatcodetable{pop \catcodetablename\space to \catcodetableprev\space at \number\catcoderestorelevel}}}
+
+\def\catcodetableprev
+ {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
+ \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
+ \else
+ -%
+ \fi}
+
+\def\catcodetablename
+ {\ifnum\currentcatcodetable>\zerocount
+ \csname @@ccn:\number\currentcatcodetable\endcsname
+ \else
+ -%
+ \fi}
+
+\ifx\empty\undefined \def\empty{} \fi
+
+\let\tracesetcatcodetable \empty
+\let\tracepushcatcodetable\empty
+\let\tracepopcatcodetable \empty
+
+\def\beginrestorecatcodes{\pushcatcodetable}
+\def\endrestorecatcodes {\popcatcodetable}
+
+%D Handy for debugging:
+
+% \tracecatcodetables
+
+\endinput
+
diff --git a/tex/context/base/catc-ini.mkiv b/tex/context/base/catc-ini.mkiv
new file mode 100644
index 000000000..085b82005
--- /dev/null
+++ b/tex/context/base/catc-ini.mkiv
@@ -0,0 +1,255 @@
+%D \module
+%D [ file=catc-ini,
+%D version=2006.09.18,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Catcode Handling,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We've split the functionality of syst-cat.* over more files
+%D now so that we can load more selectively.
+
+\registerctxluafile{catc-ini} {1.001}
+
+%D A long standing wish has been the availability of catcode
+%D arrays. Because traditional \TEX\ does not provide this we
+%D implement a fake method in the \MKII\ file. There is some
+%D overlap in code with \MKII\ but we take that for granted.
+
+\ifx\zerocount\undefined \chardef \zerocount= 0 \fi
+\ifx\plusone \undefined \chardef \plusone = 1 \fi
+\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi
+
+\ifx\gobbleoneargument\undefined \long\def\gobbleoneargument#1{} \fi
+
+\newif \ifrecatcodeuppercharacters % only used in good old tex
+
+\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate
+
+\newcount\cctcountera
+\newcount\cctcounterb
+\newcount\cctcounterc
+
+\def\newcatcodetable#1%
+ {\global\advance\cctdefcounter\plusone
+ \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
+ \global\mathchardef#1\cctdefcounter
+ \ctxlua{catcodes.register("\expandafter\gobbleoneargument\string#1",\number#1)}%
+ % we have two ways to access catcodetable numbers
+ \startruntimectxluacode tex.\expandafter\gobbleoneargument\string#1 = \number#1 ;\stopruntimectxluacode}
+
+\newcatcodetable \scratchcatcodes \initcatcodetable\scratchcatcodes
+
+\newtoks \setdefaultcatcodes
+
+\setdefaultcatcodes
+ {\catcode`\\ 12
+ \catcode`\^^M 12
+ \catcode`\ 12
+ \catcode`\% 12
+ \catcode127 12 }
+
+\long\def\startcatcodetable#1#2\stopcatcodetable
+ {\bgroup
+ \catcodetable\scratchcatcodes
+ \the\setdefaultcatcodes
+ #2%
+ \savecatcodetable#1\relax
+ \egroup}
+
+\newcatcodetable\dummycatcodes
+
+\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
+ {\bgroup
+ \catcodetable#1\relax
+ \globaldefs\plusone
+ #2%
+ \globaldefs\zerocount
+ \egroup}
+
+% ==
+%
+% \long\def\startextendcatcodetable#1#2\stopextendcatcodetable
+% {\bgroup
+% \scratchcounter\the\catcodetable
+% \catcodetable #1 #2
+% \catcodetable\scratchcounter
+% \egroup}
+
+\def\letcatcodecommand
+ {\afterassignment\letcatcodecommanda\cctcountera}
+
+\def\letcatcodecommanda
+ {\afterassignment\letcatcodecommandb\cctcounterb}
+
+\let\currentcatcodetable\catcodetable
+
+%D The next command can be defined in a cleaner way in the
+%D Mk IV file but we want to have a fast one with a minimal
+%D chance for interference.
+
+\chardef\activehackcode=`\~
+
+%D Once a catcode is assigned, the next assignments will happen faster.
+
+% (expandable) let
+
+\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
+\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}
+
+\def\letcatcodecommandb % each time
+ {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\letcatcodecommandc
+ \fi}
+
+\def\letcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
+ {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
+ \reinstatecatcodecommanda
+ \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% expandable def
+
+\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
+\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}
+
+\def\defcatcodecommandb % each time
+ {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\defcatcodecommandc
+ \fi}
+
+\def\defcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}
+
+% unexpandable def (e.g. used for discretionaries)
+
+\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
+\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}
+
+\def\uedcatcodecommandb % each time
+ {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
+ \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \else
+ \expandafter\uedcatcodecommandc
+ \fi}
+
+\def\uedcatcodecommandc % only first time
+ {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
+ \expandafter##\expandafter1\expandafter
+ {\expandafter\unexpanded\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
+ \reinstatecatcodecommanda
+ \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}
+
+\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}
+
+\def\reinstatecatcodecommanda % can be used when a direct definition has been done
+ {\bgroup % and the selector has been lost
+ \uccode\activehackcode\cctcounterb
+ \catcode\uccode\activehackcode13
+ \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
+ \egroup}
+
+\chardef\defaultcatcodetable\zerocount
+
+\def\catcodecommand#1%
+ {\csname CCC:\number
+ \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
+ \currentcatcodetable \else \defaultcatcodetable
+ \fi
+ :\number#1\endcsname}
+
+%D \macros
+%D {restorecatcodes,
+%D beginrestorecatcodes,endrestorecatcodes}
+%D
+%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
+%D use only one auxiliary file, which deals with tables of
+%D contents, registers, two pass tracking, references etc. This
+%D file, as well as files concerning graphics, is processed when
+%D needed, which can be in the mid of typesetting verbatim.
+%D However, when reading in data in verbatim mode, we should
+%D temporary restore the normal \CATCODES, and that's exactly
+%D what the next macros do. Saving the catcodes can be
+%D disabled by saying \type{\localcatcodestrue}.
+
+\let\savedcatcodetable\relax
+
+\newcount\catcoderestorelevel
+
+\def\pushcatcodetable
+ {\advance\catcoderestorelevel\plusone
+ \tracepushcatcodetable
+ \expandafter\mathchardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}
+
+\def\popcatcodetable
+ {\ifcase\catcoderestorelevel
+ \immediate\write16{}%
+ \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
+ \immediate\write16{}%
+ \else
+ \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
+ \tracepopcatcodetable
+ \advance\catcoderestorelevel\minusone
+ \fi}
+
+\def\restorecatcodes % takes previous level
+ {\ifnum\catcoderestorelevel>\plusone
+ \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
+ \fi}
+
+\newtoks\everycatcodetable
+
+\def\setcatcodetable#1%
+ {\catcodetable#1%
+ \the\everycatcodetable
+ \tracesetcatcodetable}
+
+\def\dotracecatcodetable#1{\immediate\write16{[#1]}}
+
+\def\tracecatcodetables
+ {\def\tracesetcatcodetable {\dotracecatcodetable{set \catcodetablename\space at \number\catcoderestorelevel}}%
+ \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
+ \def\tracepopcatcodetable {\dotracecatcodetable{pop \catcodetablename\space to \catcodetableprev\space at \number\catcoderestorelevel}}}
+
+\def\catcodetableprev
+ {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
+ \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
+ \else
+ -%
+ \fi}
+
+\def\catcodetablename
+ {\ifnum\currentcatcodetable>\zerocount
+ \csname @@ccn:\number\currentcatcodetable\endcsname
+ \else
+ -%
+ \fi}
+
+\ifx\empty\undefined \def\empty{} \fi
+
+\let\tracesetcatcodetable \empty
+\let\tracepushcatcodetable\empty
+\let\tracepopcatcodetable \empty
+
+\def\beginrestorecatcodes{\pushcatcodetable}
+\def\endrestorecatcodes {\popcatcodetable}
+
+%D Handy for debugging:
+
+% \tracecatcodetables
+
+\endinput
+
diff --git a/tex/context/base/syst-chr.tex b/tex/context/base/catc-sym.tex
index 085d7429f..49d94815c 100644
--- a/tex/context/base/syst-chr.tex
+++ b/tex/context/base/catc-sym.tex
@@ -1,11 +1,11 @@
%D \module
-%D [ file=syst-chr,
+%D [ file=catc-sym,
%D version=1997.01.03, % moved code
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Character Related Things,
+%D title=\CONTEXT\ Catcode Macros,
+%D subtitle=Some Handy Constants,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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
@@ -53,30 +53,15 @@
.egroup
-%D \macros % check this one
-%D {setcatcodes,uncatcodespecials,
-%D uncatcodecharacters,uncatcodespacetokens,
-%D setnaturalcatcodes,
-%D setverbosecscharacters}
+%D \macros
+%D {uncatcodespecials,setnaturalcatcodes,setnormalcatcodes,
+%D uncatcodecharacters,uncatcodeallcharacters,
+%D uncatcodespacetokens}
%D
-%D As its name says, \type{\uncatcodecharacters} resets the
-%D \CATCODE\ of characters. When we use an upper bound of
-%D 127 or 255, depending in \type{\ifeightbitcharacters}. By
-%D counting down, we only have to use one counter. The
-%D macro \type{\setcatcodes} can be uses to set alternative
-%D values. The macro \type{\resetspecialcharacters} resets
-%D characters with special meanings. This macro is not used
-%D in the verbatim macros, but is best defined in this module.
-
-\newtoks\everycommoncatcodes % gone
-\newtoks\everynaturalcatcodes % gone
-\newtoks\everynormalcatcodes % gone
-
-\def\uncatcodespacetokens
- {\catcode`\ =\@@space
- \catcode`\^^L=\@@ignore
- \catcode`\^^M=\@@endofline
- \catcode`\^^?=\@@ignore}
+%D The following macros are more or less replaced by switching
+%D to a catcode table (which we simulate in \MKII) but we keep
+%D them for convenience and compatibility. Some old engine code
+%D has been removed.
\def\uncatcodespecials {\setcatcodetable\nilcatcodes \uncatcodespacetokens}
\def\setnaturalcatcodes {\setcatcodetable\nilcatcodes}
@@ -84,48 +69,50 @@
\def\uncatcodecharacters {\setcatcodetable\nilcatcodes} % was fast version, gone now
\def\uncatcodeallcharacters{\setcatcodetable\nilcatcodes} % was slow one, with restore
+\def\uncatcodespacetokens
+ {\catcode`\ =\@@space
+ \catcode`\^^L=\@@ignore
+ \catcode`\^^M=\@@endofline
+ \catcode`\^^?=\@@ignore}
+
+%D \macros
+%D {setverbosecharacter,setverbosecscharacters}
+%D
%D Next follows a definition that lets some shortcuts expand to
-%D themselves.
+%D themselves. This macro is meant for \POSTSCRIPT\ and \PDF\
+%D code passed on to the backend.
+
+\newtoks\everyverbosechacters
\def\setverbosecscharacter#1%
{\edef#1{\string#1}}
-\bgroup \catcode`\|=13 \catcode`\~=13
-
-\gdef\setverbosecscharacters % temporary hack
- {\setverbosecscharacter |\setverbosecscharacter ~% context specific
- \setverbosecscharacter\|\setverbosecscharacter\~%
- \setverbosecscharacter\:\setverbosecscharacter\;%
- \setverbosecscharacter\+\setverbosecscharacter\-%
- \setverbosecscharacter\[\setverbosecscharacter\]%
- \setverbosecscharacter\.\setverbosecscharacter\\%
- \setverbosecscharacter\)\setverbosecscharacter\(%
- \setverbosecscharacter\0\setverbosecscharacter\1%
- \setverbosecscharacter\2\setverbosecscharacter\3%
- \setverbosecscharacter\4\setverbosecscharacter\5%
- \setverbosecscharacter\6\setverbosecscharacter\7%
- \setverbosecscharacter\8\setverbosecscharacter\9%
- \setverbosecscharacter\n\setverbosecscharacter\s%
- \setverbosecscharacter\/}
-
-\egroup
+\def\setverbosecscharacters
+ {\the\everyverbosechacters}
-%D \macros
-%D {frenchspacing,nonfrenchspacing}
-%D
-%D This code should move.
-
-\def\setfrenchspacing#1%
- {\sfcode`\.#1 \sfcode`\,#1\relax
- \sfcode`\?#1 \sfcode`\!#1\relax
- \sfcode`\:#1 \sfcode`\;#1\relax}
+\bgroup
-\def\frenchspacing
- {\setfrenchspacing{1000}}
+ % if used often we can move the code inline
+
+ \catcode`\|=\@@active
+ \catcode`\~=\@@active
+
+ \global \everyverbosechacters =
+ {\setverbosecscharacter |\setverbosecscharacter ~% context specific
+ \setverbosecscharacter\|\setverbosecscharacter\~%
+ \setverbosecscharacter\:\setverbosecscharacter\;%
+ \setverbosecscharacter\+\setverbosecscharacter\-%
+ \setverbosecscharacter\[\setverbosecscharacter\]%
+ \setverbosecscharacter\.\setverbosecscharacter\\%
+ \setverbosecscharacter\)\setverbosecscharacter\(%
+ \setverbosecscharacter\0\setverbosecscharacter\1%
+ \setverbosecscharacter\2\setverbosecscharacter\3%
+ \setverbosecscharacter\4\setverbosecscharacter\5%
+ \setverbosecscharacter\6\setverbosecscharacter\7%
+ \setverbosecscharacter\8\setverbosecscharacter\9%
+ \setverbosecscharacter\n\setverbosecscharacter\s%
+ \setverbosecscharacter\/}
-\def\resetfrenchspacing
- {\sfcode`\.3000 \sfcode`\,1250
- \sfcode`\?3000 \sfcode`\!3000
- \sfcode`\:2000 \sfcode`\;1500 }
+\egroup
\protect \endinput
diff --git a/tex/context/base/char-cmp.lua b/tex/context/base/char-cmp.lua
index e995f510f..bd3360499 100644
--- a/tex/context/base/char-cmp.lua
+++ b/tex/context/base/char-cmp.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['char-cmp'] = {
license = "see context related readme files"
}
+local utf = unicode.utf8
+
characters = characters or { }
characters.uncomposed = characters.uncomposed or { }
diff --git a/tex/context/base/char-def.lua b/tex/context/base/char-def.lua
index 701eadfe6..1c7c25944 100644
--- a/tex/context/base/char-def.lua
+++ b/tex/context/base/char-def.lua
@@ -1,11 +1,18 @@
if not modules then modules = { } end modules ['char-def'] = {
version = 1.001,
- comment = "much (but not all) data is derived from unicode tables",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
+--[[
+The first version of this table was generated from unicode tables
+but after that was mostly updated manual using data present in
+ConTeXt and elsewhere. I did my best to make this table as complete
+as needed for proper use in ConTeXt MkIV. All errors are mine. If
+you find an error or ommision, just let me know.
+]]--
+
characters = characters or { }
characters.data={
@@ -259,6 +266,7 @@ characters.data={
contextname="quotedbl",
description="QUOTATION MARK",
direction="on",
+ mathclass="default",
linebreak="qu",
unicodeslot=0x0022,
},
@@ -275,6 +283,7 @@ characters.data={
adobename="dollar",
category="sc",
cjkwd="na",
+ contextname="textdollar",
description="DOLLAR SIGN",
direction="et",
linebreak="pr",
@@ -303,9 +312,11 @@ characters.data={
adobename="quotesingle",
category="po",
cjkwd="na",
+ contextname="quotesingle",
description="APOSTROPHE",
direction="on",
linebreak="qu",
+ mathclass="default",
unicodeslot=0x0027,
},
{
@@ -340,6 +351,7 @@ characters.data={
direction="on",
linebreak="al",
mathclass="binary",
+ mathname="ast",
unicodeslot=0x002A,
},
{
@@ -360,6 +372,10 @@ characters.data={
direction="cs",
linebreak="is",
mathclass="punctuation",
+ mathspec={
+ { class="punctuation", name="textcomma" },
+ { class="ord", name="mathcomma" },
+ },
unicodeslot=0x002C,
},
{
@@ -369,7 +385,7 @@ characters.data={
description="HYPHEN-MINUS",
direction="es",
linebreak="hy",
- mathclass="binary",
+ mathsymbol=0x2212,
unicodeslot=0x002D,
},
{
@@ -379,17 +395,23 @@ characters.data={
description="FULL STOP",
direction="cs",
linebreak="is",
- mathclass="punctuation",
+ mathclass="ord",
+ mathspec={
+ { class="ord", name="mathperiod" },
+ { class="punctuation", name="textperiod" },
+ { class="punctuation", name="ldotp" },
+ },
unicodeslot=0x002E,
},
{
adobename="slash",
category="po",
cjkwd="na",
+ contextname="textslash",
description="SOLIDUS",
direction="cs",
linebreak="sy",
- mathclass="binary",
+ mathsymbol=0x2044,
unicodeslot=0x002F,
},
{
@@ -500,6 +522,7 @@ characters.data={
direction="cs",
linebreak="is",
mathclass="punctuation",
+ mathname="colon",
unicodeslot=0x003A,
},
{
@@ -860,6 +883,7 @@ characters.data={
direction="on",
linebreak="op",
mathclass="open",
+ mathname="lbracket",
mirror=0x005D,
unicodeslot=0x005B,
},
@@ -871,7 +895,8 @@ characters.data={
description="REVERSE SOLIDUS",
direction="on",
linebreak="pr",
- mathclass="binary",
+ mathclass="nothing",
+ mathname="backslash",
unicodeslot=0x005C,
},
{
@@ -882,6 +907,7 @@ characters.data={
direction="on",
linebreak="cl",
mathclass="close",
+ mathname="rbracket",
mirror=0x005B,
unicodeslot=0x005D,
},
@@ -894,8 +920,6 @@ characters.data={
direction="on",
linebreak="al",
mathclass="accent",
- mathname="widehat",
- mathstretch="h",
unicodeslot=0x005E,
},
{
@@ -914,6 +938,8 @@ characters.data={
cjkwd="na",
contextname="textgrave",
description="GRAVE ACCENT",
+ mathclass="accent",
+ mathname="grave",
direction="on",
linebreak="al",
unicodeslot=0x0060,
@@ -1010,6 +1036,7 @@ characters.data={
adobename="i",
category="ll",
cjkwd="na",
+ contextname="idotaccent",
description="LATIN SMALL LETTER I",
direction="l",
linebreak="al",
@@ -1213,7 +1240,7 @@ characters.data={
direction="on",
linebreak="op",
mathclass="open",
- mathname=false, -- "lbrace",
+ mathname="lbrace", -- was false
mirror=0x007D,
unicodeslot=0x007B,
},
@@ -1225,8 +1252,14 @@ characters.data={
description="VERTICAL LINE",
direction="on",
linebreak="ba",
- mathclass="binary",
- mathname="bar",
+ mathspec={
+-- { class="binary", name="bar" },
+ { class="nothing", name="arrowvert" },
+ { class="delimiter", name="vert" },
+ { class="open", name="lvert" },
+ { class="close", name="rvert" },
+ { class="relation", name="mid" },
+ },
unicodeslot=0x007C,
},
{
@@ -1238,7 +1271,7 @@ characters.data={
direction="on",
linebreak="cl",
mathclass="close",
- mathname=false, -- "rbrace",
+ mathname="rbrace", -- was false
mirror=0x007B,
unicodeslot=0x007D,
},
@@ -1250,9 +1283,6 @@ characters.data={
description="TILDE",
direction="on",
linebreak="al",
- mathclass="accent",
- mathname="widetilde",
- mathstretch="h",
unicodeslot=0x007E,
},
{
@@ -1543,6 +1573,8 @@ characters.data={
description="YEN SIGN",
direction="et",
linebreak="pr",
+ mathclass="nothing",
+ mathname="yen",
unicodeslot=0x00A5,
},
{
@@ -1563,6 +1595,8 @@ characters.data={
description="SECTION SIGN",
direction="on",
linebreak="ai",
+ mathclass="box",
+ mathname="S",
unicodeslot=0x00A7,
},
{
@@ -1573,6 +1607,8 @@ characters.data={
description="DIAERESIS",
direction="on",
linebreak="ai",
+ mathclass="accent",
+ mathname="ddot",
specials={ "compat", 0x0020, 0x0308 },
unicodeslot=0x00A8,
},
@@ -1614,8 +1650,10 @@ characters.data={
description="NOT SIGN",
direction="on",
linebreak="al",
- mathclass="ord",
- mathname="lnot",
+ mathspec={
+ { class="ord", name="lnot" },
+ { class="ord", name="neg" },
+ },
unicodeslot=0x00AC,
},
{
@@ -1645,6 +1683,8 @@ characters.data={
description="MACRON",
direction="on",
linebreak="al",
+ mathclass="accent",
+ mathname="bar",
specials={ "compat", 0x0020, 0x0304 },
unicodeslot=0x00AF,
},
@@ -1698,6 +1738,8 @@ characters.data={
description="ACUTE ACCENT",
direction="on",
linebreak="bb",
+ mathclass="accent",
+ mathname="acute",
specials={ "compat", 0x0020, 0x0301 },
unicodeslot=0x00B4,
},
@@ -1720,6 +1762,8 @@ characters.data={
description="PILCROW SIGN",
direction="on",
linebreak="ai",
+ mathclass="box",
+ mathname="P",
unicodeslot=0x00B6,
},
{
@@ -1731,6 +1775,7 @@ characters.data={
direction="on",
linebreak="ai",
mathclass="binary",
+ mathname="centerdot",
unicodeslot=0x00B7,
},
{
@@ -2402,10 +2447,12 @@ characters.data={
adobename="eth",
category="ll",
cjkwd="a",
- contextname="eth",
+ --~ contextname="eth", -- AM: Should this be defined in text mode?
description="LATIN SMALL LETTER ETH",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="eth",
uccode=0x00D0,
unicodeslot=0x00F0,
},
@@ -3071,6 +3118,8 @@ characters.data={
description="LATIN SMALL LETTER H WITH STROKE",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="hbar",
shcode=0x0068,
uccode=0x0126,
unicodeslot=0x0127,
@@ -7108,6 +7157,8 @@ characters.data={
description="MODIFIER LETTER CIRCUMFLEX ACCENT",
direction="on",
linebreak="al",
+ mathclass="accent",
+ mathname="hat",
specials={ "compat", 0x0020, 0x0302 },
unicodeslot=0x02C6,
},
@@ -7119,6 +7170,8 @@ characters.data={
description="CARON",
direction="on",
linebreak="ai",
+ mathclass="accent",
+ mathname="check",
specials={ "compat", 0x0020, 0x030C },
unicodeslot=0x02C7,
},
@@ -7247,6 +7300,8 @@ characters.data={
description="BREVE",
direction="on",
linebreak="ai",
+ mathclass="accent",
+ mathname="breve",
specials={ "compat", 0x0020, 0x0306 },
unicodeslot=0x02D8,
},
@@ -7258,6 +7313,8 @@ characters.data={
description="DOT ABOVE",
direction="on",
linebreak="ai",
+ mathclass="accent",
+ mathname="dot",
specials={ "compat", 0x0020, 0x0307 },
unicodeslot=0x02D9,
},
@@ -7269,6 +7326,8 @@ characters.data={
description="RING ABOVE",
direction="on",
linebreak="ai",
+ mathclass="accent",
+ mathname="mathring",
specials={ "compat", 0x0020, 0x030A },
unicodeslot=0x02DA,
},
@@ -7290,6 +7349,8 @@ characters.data={
description="SMALL TILDE",
direction="on",
linebreak="al",
+ mathclass="accent",
+ mathname="tilde",
specials={ "compat", 0x0020, 0x0303 },
unicodeslot=0x02DC,
},
@@ -7572,6 +7633,7 @@ characters.data={
description="COMBINING CIRCUMFLEX ACCENT",
direction="nsm",
linebreak="cm",
+ mathstretch="h",
unicodeslot=0x0302,
},
{
@@ -7581,6 +7643,7 @@ characters.data={
description="COMBINING TILDE",
direction="nsm",
linebreak="cm",
+ mathstretch="h",
unicodeslot=0x0303,
},
{
@@ -7836,6 +7899,7 @@ characters.data={
adobename="dotbelowcomb",
category="mn",
cjkwd="a",
+ contextname="textbottomdot",
description="COMBINING DOT BELOW",
direction="nsm",
linebreak="cm",
@@ -7860,6 +7924,7 @@ characters.data={
{
category="mn",
cjkwd="a",
+ contextname="textbottomcomma",
description="COMBINING COMMA BELOW",
direction="nsm",
linebreak="cm",
@@ -8007,6 +8072,8 @@ characters.data={
description="COMBINING LONG SOLIDUS OVERLAY",
direction="nsm",
linebreak="cm",
+ mathclass="relation",
+ mathname="not",
unicodeslot=0x0338,
},
{
@@ -8642,8 +8709,6 @@ characters.data={
direction="l",
lccode=0x03B1,
linebreak="al",
- mathclass="variable",
- mathname="Alpha",
unicodeslot=0x0391,
},
[0x0392]={
@@ -8655,8 +8720,6 @@ characters.data={
direction="l",
lccode=0x03B2,
linebreak="al",
- mathclass="variable",
- mathname="Beta",
unicodeslot=0x0392,
},
[0x0393]={
@@ -8668,8 +8731,6 @@ characters.data={
direction="l",
lccode=0x03B3,
linebreak="al",
- mathclass="variable",
- mathname="Gamma",
unicodeslot=0x0393,
},
[0x0394]={
@@ -8680,8 +8741,6 @@ characters.data={
direction="l",
lccode=0x03B4,
linebreak="al",
- mathclass="variable",
- mathname="Delta",
unicodeslot=0x0394,
},
[0x0395]={
@@ -8693,8 +8752,6 @@ characters.data={
direction="l",
lccode=0x03B5,
linebreak="al",
- mathclass="variable",
- mathname="Epsilon",
unicodeslot=0x0395,
},
[0x0396]={
@@ -8706,8 +8763,6 @@ characters.data={
direction="l",
lccode=0x03B6,
linebreak="al",
- mathclass="variable",
- mathname="Zeta",
unicodeslot=0x0396,
},
[0x0397]={
@@ -8719,8 +8774,6 @@ characters.data={
direction="l",
lccode=0x03B7,
linebreak="al",
- mathclass="variable",
- mathname="Eta",
unicodeslot=0x0397,
},
[0x0398]={
@@ -8732,8 +8785,6 @@ characters.data={
direction="l",
lccode=0x03B8,
linebreak="al",
- mathclass="variable",
- mathname="Theta",
unicodeslot=0x0398,
},
[0x0399]={
@@ -8745,8 +8796,6 @@ characters.data={
direction="l",
lccode=0x03B9,
linebreak="al",
- mathclass="variable",
- mathname="Iota",
unicodeslot=0x0399,
},
[0x039A]={
@@ -8758,8 +8807,6 @@ characters.data={
direction="l",
lccode=0x03BA,
linebreak="al",
- mathclass="variable",
- mathname="Kappa",
unicodeslot=0x039A,
},
[0x039B]={
@@ -8771,8 +8818,6 @@ characters.data={
direction="l",
lccode=0x03BB,
linebreak="al",
- mathclass="variable",
- mathname="Lambda",
unicodeslot=0x039B,
},
[0x039C]={
@@ -8784,8 +8829,6 @@ characters.data={
direction="l",
lccode=0x03BC,
linebreak="al",
- mathclass="variable",
- mathname="Mu",
unicodeslot=0x039C,
},
[0x039D]={
@@ -8797,8 +8840,6 @@ characters.data={
direction="l",
lccode=0x03BD,
linebreak="al",
- mathclass="variable",
- mathname="Nu",
unicodeslot=0x039D,
},
[0x039E]={
@@ -8810,8 +8851,6 @@ characters.data={
direction="l",
lccode=0x03BE,
linebreak="al",
- mathclass="variable",
- mathname="Xi",
unicodeslot=0x039E,
},
[0x039F]={
@@ -8823,8 +8862,6 @@ characters.data={
direction="l",
lccode=0x03BF,
linebreak="al",
- mathclass="variable",
- mathname="Omicron",
unicodeslot=0x039F,
},
[0x03A0]={
@@ -8836,8 +8873,6 @@ characters.data={
direction="l",
lccode=0x03C0,
linebreak="al",
- mathclass="variable",
- mathname="Pi",
unicodeslot=0x03A0,
},
[0x03A1]={
@@ -8849,8 +8884,6 @@ characters.data={
direction="l",
lccode=0x03C1,
linebreak="al",
- mathclass="variable",
- mathname="Rho",
unicodeslot=0x03A1,
},
[0x03A3]={
@@ -8862,8 +8895,6 @@ characters.data={
direction="l",
lccode=0x03C3,
linebreak="al",
- mathclass="variable",
- mathname="Sigma",
unicodeslot=0x03A3,
},
[0x03A4]={
@@ -8875,8 +8906,6 @@ characters.data={
direction="l",
lccode=0x03C4,
linebreak="al",
- mathclass="variable",
- mathname="Tau",
unicodeslot=0x03A4,
},
[0x03A5]={
@@ -8888,8 +8917,6 @@ characters.data={
direction="l",
lccode=0x03C5,
linebreak="al",
- mathclass="variable",
- mathname="Upsilon",
unicodeslot=0x03A5,
},
[0x03A6]={
@@ -8901,8 +8928,6 @@ characters.data={
direction="l",
lccode=0x03C6,
linebreak="al",
- mathclass="variable",
- mathname="Phi",
unicodeslot=0x03A6,
},
[0x03A7]={
@@ -8914,8 +8939,6 @@ characters.data={
direction="l",
lccode=0x03C7,
linebreak="al",
- mathclass="variable",
- mathname="Chi",
unicodeslot=0x03A7,
},
[0x03A8]={
@@ -8927,8 +8950,6 @@ characters.data={
direction="l",
lccode=0x03C8,
linebreak="al",
- mathclass="variable",
- mathname="Psi",
unicodeslot=0x03A8,
},
[0x03A9]={
@@ -8939,8 +8960,6 @@ characters.data={
direction="l",
lccode=0x03C9,
linebreak="al",
- mathclass="variable",
- mathname="Omega",
unicodeslot=0x03A9,
},
[0x03AA]={
@@ -9034,8 +9053,6 @@ characters.data={
description="GREEK SMALL LETTER ALPHA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="alpha",
uccode=0x0391,
unicodeslot=0x03B1,
},
@@ -9047,8 +9064,6 @@ characters.data={
description="GREEK SMALL LETTER BETA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="beta",
uccode=0x0392,
unicodeslot=0x03B2,
},
@@ -9060,8 +9075,6 @@ characters.data={
description="GREEK SMALL LETTER GAMMA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="gamma",
uccode=0x0393,
unicodeslot=0x03B3,
},
@@ -9073,8 +9086,6 @@ characters.data={
description="GREEK SMALL LETTER DELTA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="delta",
uccode=0x0394,
unicodeslot=0x03B4,
},
@@ -9086,8 +9097,6 @@ characters.data={
description="GREEK SMALL LETTER EPSILON",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="epsilon",
uccode=0x0395,
unicodeslot=0x03B5,
},
@@ -9099,8 +9108,6 @@ characters.data={
description="GREEK SMALL LETTER ZETA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="zeta",
uccode=0x0396,
unicodeslot=0x03B6,
},
@@ -9112,8 +9119,6 @@ characters.data={
description="GREEK SMALL LETTER ETA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="eta",
uccode=0x0397,
unicodeslot=0x03B7,
},
@@ -9125,8 +9130,6 @@ characters.data={
description="GREEK SMALL LETTER THETA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="theta",
uccode=0x0398,
unicodeslot=0x03B8,
},
@@ -9138,8 +9141,6 @@ characters.data={
description="GREEK SMALL LETTER IOTA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="iota",
uccode=0x0399,
unicodeslot=0x03B9,
},
@@ -9151,8 +9152,6 @@ characters.data={
description="GREEK SMALL LETTER KAPPA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="kappa",
uccode=0x039A,
unicodeslot=0x03BA,
},
@@ -9164,8 +9163,6 @@ characters.data={
description="GREEK SMALL LETTER LAMDA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="lambda",
uccode=0x039B,
unicodeslot=0x03BB,
},
@@ -9176,8 +9173,6 @@ characters.data={
description="GREEK SMALL LETTER MU",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="mu",
uccode=0x039C,
unicodeslot=0x03BC,
},
@@ -9189,8 +9184,6 @@ characters.data={
description="GREEK SMALL LETTER NU",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="nu",
uccode=0x039D,
unicodeslot=0x03BD,
},
@@ -9202,8 +9195,6 @@ characters.data={
description="GREEK SMALL LETTER XI",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="xi",
uccode=0x039E,
unicodeslot=0x03BE,
},
@@ -9215,8 +9206,6 @@ characters.data={
description="GREEK SMALL LETTER OMICRON",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="omicron",
uccode=0x039F,
unicodeslot=0x03BF,
},
@@ -9228,8 +9217,6 @@ characters.data={
description="GREEK SMALL LETTER PI",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="pi",
uccode=0x03A0,
unicodeslot=0x03C0,
},
@@ -9241,8 +9228,6 @@ characters.data={
description="GREEK SMALL LETTER RHO",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="rho",
uccode=0x03A1,
unicodeslot=0x03C1,
},
@@ -9253,8 +9238,6 @@ characters.data={
description="GREEK SMALL LETTER FINAL SIGMA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="varsigma",
uccode=0x03A3,
unicodeslot=0x03C2,
},
@@ -9266,8 +9249,6 @@ characters.data={
description="GREEK SMALL LETTER SIGMA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="sigma",
uccode=0x03A3,
unicodeslot=0x03C3,
},
@@ -9279,8 +9260,6 @@ characters.data={
description="GREEK SMALL LETTER TAU",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="tau",
uccode=0x03A4,
unicodeslot=0x03C4,
},
@@ -9292,8 +9271,6 @@ characters.data={
description="GREEK SMALL LETTER UPSILON",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="upsilon",
uccode=0x03A5,
unicodeslot=0x03C5,
},
@@ -9305,8 +9282,6 @@ characters.data={
description="GREEK SMALL LETTER PHI",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="varphi",
uccode=0x03A6,
unicodeslot=0x03C6,
},
@@ -9318,8 +9293,6 @@ characters.data={
description="GREEK SMALL LETTER CHI",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="chi",
uccode=0x03A7,
unicodeslot=0x03C7,
},
@@ -9331,8 +9304,6 @@ characters.data={
description="GREEK SMALL LETTER PSI",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="psi",
uccode=0x03A8,
unicodeslot=0x03C8,
},
@@ -9344,8 +9315,6 @@ characters.data={
description="GREEK SMALL LETTER OMEGA",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="omega",
uccode=0x03A9,
unicodeslot=0x03C9,
},
@@ -9425,8 +9394,6 @@ characters.data={
description="GREEK THETA SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="vartheta",
specials={ "compat", 0x03B8 },
uccode=0x0398,
unicodeslot=0x03D1,
@@ -9463,8 +9430,6 @@ characters.data={
description="GREEK PHI SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="phi",
specials={ "compat", 0x03C6 },
uccode=0x03A6,
unicodeslot=0x03D5,
@@ -9476,8 +9441,6 @@ characters.data={
description="GREEK PI SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="varpi",
specials={ "compat", 0x03C0 },
uccode=0x03A0,
unicodeslot=0x03D6,
@@ -9529,6 +9492,8 @@ characters.data={
direction="l",
lccode=0x03DD,
linebreak="al",
+ mathclass="variable",
+ mathname="digamma",
unicodeslot=0x03DC,
},
[0x03DD]={
@@ -9692,6 +9657,8 @@ characters.data={
direction="l",
linebreak="al",
specials={ "compat", 0x03BA },
+ mathclass="ord",
+ mathname="varkappa",
uccode=0x039A,
unicodeslot=0x03F0,
},
@@ -9701,8 +9668,6 @@ characters.data={
description="GREEK RHO SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="varrho",
specials={ "compat", 0x03C1 },
uccode=0x03A1,
unicodeslot=0x03F1,
@@ -9739,8 +9704,6 @@ characters.data={
description="GREEK LUNATE EPSILON SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
- mathname="varepsilon",
specials={ "compat", 0x03B5 },
uccode=0x0395,
unicodeslot=0x03F5,
@@ -9750,6 +9713,8 @@ characters.data={
description="GREEK REVERSED LUNATE EPSILON SYMBOL",
direction="on",
linebreak="al",
+ mathclass="variable",
+ mathname="backepsilon",
unicodeslot=0x03F6,
},
[0x03F7]={
@@ -48951,6 +48916,10 @@ characters.data={
description="DAGGER",
direction="on",
linebreak="ai",
+ mathspec={
+ { class="binary", name="dagger" },
+ { class="box", name="dag" },
+ },
unicodeslot=0x2020,
},
[0x2021]={
@@ -48961,6 +48930,10 @@ characters.data={
description="DOUBLE DAGGER",
direction="on",
linebreak="ai",
+ mathspec={
+ { class="binary", name="ddagger" },
+ { class="box", name="ddag" },
+ },
unicodeslot=0x2021,
},
[0x2022]={
@@ -49010,6 +48983,8 @@ characters.data={
description="HORIZONTAL ELLIPSIS",
direction="on",
linebreak="in",
+ mathclass="inner",
+ mathname="ldots",
specials={ "compat", 0x002E, 0x002E, 0x002E },
unicodeslot=0x2026,
},
@@ -49106,6 +49081,8 @@ characters.data={
description="PRIME",
direction="et",
linebreak="po",
+ mathclass="nothing",
+ mathname="prime",
unicodeslot=0x2032,
},
[0x2033]={
@@ -49248,9 +49225,14 @@ characters.data={
[0x2044]={
adobename="fraction",
category="sm",
+ contextname="textfraction",
description="FRACTION SLASH",
direction="cs",
linebreak="is",
+ mathspec={
+ { class="binary", name="slash" },
+ { class="close", name="solidus" },
+ },
unicodeslot=0x2044,
},
[0x2045]={
@@ -50024,6 +50006,8 @@ characters.data={
description="COMBINING RIGHT ARROW ABOVE",
direction="nsm",
linebreak="cm",
+ mathclass="accent",
+ mathname="vec",
unicodeslot=0x20D7,
},
[0x20D8]={
@@ -50066,6 +50050,10 @@ characters.data={
description="COMBINING ENCLOSING CIRCLE",
direction="nsm",
linebreak="cm",
+ mathspec={
+ { class="default",name="bigcircle" },
+ { class="binary",name="bigcircle" },
+ },
unicodeslot=0x20DD,
},
[0x20DE]={
@@ -50073,6 +50061,8 @@ characters.data={
description="COMBINING ENCLOSING SQUARE",
direction="nsm",
linebreak="cm",
+ mathclass="default",
+ mathname="bigsquare",
unicodeslot=0x20DE,
},
[0x20DF]={
@@ -50080,6 +50070,8 @@ characters.data={
description="COMBINING ENCLOSING DIAMOND",
direction="nsm",
linebreak="cm",
+ mathclass="default",
+ mathname="bigdiamond",
unicodeslot=0x20DF,
},
[0x20E0]={
@@ -50150,6 +50142,7 @@ characters.data={
description="COMBINING WIDE BRIDGE ABOVE",
direction="nsm",
linebreak="cm",
+ mathclass="accent",
unicodeslot=0x20E9,
},
[0x20EA]={
@@ -50224,6 +50217,7 @@ characters.data={
category="so",
cjkwd="a",
description="DEGREE CELSIUS",
+ contextname="textcelsius",
direction="on",
linebreak="po",
specials={ "compat", 0x00B0, 0x0043 },
@@ -50342,7 +50336,7 @@ characters.data={
description="BLACK-LETTER CAPITAL I",
direction="l",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="Im",
specials={ "font", 0x0049 },
unicodeslot=0x2111,
@@ -50362,7 +50356,7 @@ characters.data={
description="SCRIPT SMALL L",
direction="l",
linebreak="ai",
- mathclass="variable",
+ mathclass="default",
mathname="ell",
specials={ "font", 0x006C },
unicodeslot=0x2113,
@@ -50397,6 +50391,7 @@ characters.data={
},
[0x2117]={
category="so",
+ contextname="textcircledP",
description="SOUND RECORDING COPYRIGHT",
direction="on",
linebreak="al",
@@ -50408,7 +50403,7 @@ characters.data={
description="SCRIPT CAPITAL P",
direction="on",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="wp",
unicodeslot=0x2118,
},
@@ -50446,7 +50441,7 @@ characters.data={
description="BLACK-LETTER CAPITAL R",
direction="l",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="Re",
specials={ "font", 0x0052 },
unicodeslot=0x211C,
@@ -50523,6 +50518,7 @@ characters.data={
},
[0x2125]={
category="so",
+ contextname="textounce",
description="OUNCE SIGN",
direction="on",
linebreak="al",
@@ -50533,17 +50529,19 @@ characters.data={
category="lu",
cjkwd="a",
description="OHM SIGN",
+ contextname="textohm",
direction="l",
- lccode=0x03C9,
+ lccode=0x03C9, --AM: Not sure?
linebreak="al",
mathclass="variable",
- mathname="Omega", --AM: Should we do this or does specials take care of it
+ mathname="ohm", --AM: Should we do this or does specials take care of it
specials={ "char", 0x03A9 },
unicodeslot=0x2126,
},
[0x2127]={
category="so",
description="INVERTED OHM SIGN",
+ contextname="textmho",
direction="on",
linebreak="al",
mathclass="variable",
@@ -50569,6 +50567,7 @@ characters.data={
category="lu",
description="KELVIN SIGN",
direction="l",
+ contextname="textkelvin",
lccode=0x006B,
linebreak="al",
specials={ "char", 0x004B },
@@ -50579,6 +50578,7 @@ characters.data={
cjkwd="a",
description="ANGSTROM SIGN",
direction="l",
+ contextname="textAngstrom",
lccode=0x00E5,
linebreak="ai",
mathclass="variable",
@@ -50640,6 +50640,8 @@ characters.data={
direction="l",
lccode=0x214E,
linebreak="al",
+ mathclass="ord",
+ mathname="Finv",
unicodeslot=0x2132,
},
[0x2133]={
@@ -50664,7 +50666,7 @@ characters.data={
description="ALEF SYMBOL",
direction="l",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="aleph",
specials={ "compat", 0x05D0 },
unicodeslot=0x2135,
@@ -50674,6 +50676,8 @@ characters.data={
description="BET SYMBOL",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="beth",
specials={ "compat", 0x05D1 },
unicodeslot=0x2136,
},
@@ -50682,6 +50686,8 @@ characters.data={
description="GIMEL SYMBOL",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="gimel",
specials={ "compat", 0x05D2 },
unicodeslot=0x2137,
},
@@ -50690,6 +50696,8 @@ characters.data={
description="DALET SYMBOL",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="daleth",
specials={ "compat", 0x05D3 },
unicodeslot=0x2138,
},
@@ -50761,6 +50769,8 @@ characters.data={
description="TURNED SANS-SERIF CAPITAL G",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="Game",
unicodeslot=0x2141,
},
[0x2142]={
@@ -50829,6 +50839,8 @@ characters.data={
description="DOUBLE-STRUCK ITALIC SMALL J",
direction="l",
linebreak="al",
+ mathclass="nothing",
+ mathname="imaginaryj",
specials={ "font", 0x006A },
unicodeslot=0x2149,
},
@@ -51382,8 +51394,12 @@ characters.data={
description="LEFTWARDS ARROW",
direction="on",
linebreak="ai",
- mathclass="relation",
- mathname="leftarrow",
+ mathspec={
+ { class="relation", name="leftarrow" },
+ { class="relation", name="gets" },
+ { class="under", name="underleftarrow" },
+ { class="over", name="overleftarrow" },
+ },
mathstretch="h",
unicodeslot=0x2190,
},
@@ -51395,7 +51411,7 @@ characters.data={
direction="on",
linebreak="ai",
mathclass="relation",
- mathname="uparraow",
+ mathname="uparrow",
unicodeslot=0x2191,
},
[0x2192]={
@@ -51405,9 +51421,12 @@ characters.data={
description="RIGHTWARDS ARROW",
direction="on",
linebreak="ai",
- mathclass="relation",
- mathfiller="rightarrowfill",
- mathname="rightarrow",
+ mathspec={
+ { class="relation",name="rightarrow" },
+ { class="relation",name="to" },
+ { class="under", name="underrightarrow" },
+ { class="over", name="overrightarrow" },
+ },
mathstretch="h",
unicodeslot=0x2192,
},
@@ -51489,6 +51508,8 @@ characters.data={
description="LEFTWARDS ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nleftarrow",
specials={ "char", 0x2190, 0x0338 },
unicodeslot=0x219A,
},
@@ -51497,6 +51518,8 @@ characters.data={
description="RIGHTWARDS ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nrightarrow",
specials={ "char", 0x2192, 0x0338 },
unicodeslot=0x219B,
},
@@ -51519,6 +51542,8 @@ characters.data={
description="LEFTWARDS TWO HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="twoheadleftarrow",
unicodeslot=0x219E,
},
[0x219F]={
@@ -51526,6 +51551,8 @@ characters.data={
description="UPWARDS TWO HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="twoheadupleftarrow",
unicodeslot=0x219F,
},
[0x21A0]={
@@ -51533,6 +51560,8 @@ characters.data={
description="RIGHTWARDS TWO HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="twoheadrightarrow",
unicodeslot=0x21A0,
},
[0x21A1]={
@@ -51540,6 +51569,8 @@ characters.data={
description="DOWNWARDS TWO HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="twoheaddownleftarrow",
unicodeslot=0x21A1,
},
[0x21A2]={
@@ -51547,6 +51578,8 @@ characters.data={
description="LEFTWARDS ARROW WITH TAIL",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftarrowtail",
unicodeslot=0x21A2,
},
[0x21A3]={
@@ -51554,6 +51587,8 @@ characters.data={
description="RIGHTWARDS ARROW WITH TAIL",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightarrowtail",
unicodeslot=0x21A3,
},
[0x21A4]={
@@ -51575,6 +51610,9 @@ characters.data={
description="RIGHTWARDS ARROW FROM BAR",
direction="on",
linebreak="al",
+ fallback=[[\mapstochar\rightarrow]],
+ mathclass="relation",
+ mathname="mapsto",
unicodeslot=0x21A6,
},
[0x21A7]={
@@ -51597,6 +51635,9 @@ characters.data={
description="LEFTWARDS ARROW WITH HOOK",
direction="on",
linebreak="al",
+ fallback=[[\leftarrow\joinrel\rhook]],
+ mathclass="relation",
+ mathname="hookleftarrow",
unicodeslot=0x21A9,
},
[0x21AA]={
@@ -51604,6 +51645,9 @@ characters.data={
description="RIGHTWARDS ARROW WITH HOOK",
direction="on",
linebreak="al",
+ fallback=[[\lhook\joinrel\rightarrow]],
+ mathclass="relation",
+ mathname="hookrightarrow",
unicodeslot=0x21AA,
},
[0x21AB]={
@@ -51611,6 +51655,8 @@ characters.data={
description="LEFTWARDS ARROW WITH LOOP",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="looparrowleft",
unicodeslot=0x21AB,
},
[0x21AC]={
@@ -51618,6 +51664,8 @@ characters.data={
description="RIGHTWARDS ARROW WITH LOOP",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="looparrowright",
unicodeslot=0x21AC,
},
[0x21AD]={
@@ -51625,6 +51673,8 @@ characters.data={
description="LEFT RIGHT WAVE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftrightsquigarrow",
unicodeslot=0x21AD,
},
[0x21AE]={
@@ -51632,6 +51682,8 @@ characters.data={
description="LEFT RIGHT ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nleftrightarrow",
specials={ "char", 0x2194, 0x0338 },
unicodeslot=0x21AE,
},
@@ -51647,6 +51699,8 @@ characters.data={
description="UPWARDS ARROW WITH TIP LEFTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Lsh",
unicodeslot=0x21B0,
},
[0x21B1]={
@@ -51654,6 +51708,8 @@ characters.data={
description="UPWARDS ARROW WITH TIP RIGHTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Rsh",
unicodeslot=0x21B1,
},
[0x21B2]={
@@ -51661,6 +51717,8 @@ characters.data={
description="DOWNWARDS ARROW WITH TIP LEFTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dlsh", -- from mathabx
unicodeslot=0x21B2,
},
[0x21B3]={
@@ -51668,6 +51726,8 @@ characters.data={
description="DOWNWARDS ARROW WITH TIP RIGHTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="drsh", -- from mathabx
unicodeslot=0x21B3,
},
[0x21B4]={
@@ -51679,6 +51739,7 @@ characters.data={
},
[0x21B5]={
adobename="carriagereturn",
+ contextname="carriagereturn",
category="so",
description="DOWNWARDS ARROW WITH CORNER LEFTWARDS",
direction="on",
@@ -51690,6 +51751,8 @@ characters.data={
description="ANTICLOCKWISE TOP SEMICIRCLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="curvearrowleft",
unicodeslot=0x21B6,
},
[0x21B7]={
@@ -51697,6 +51760,8 @@ characters.data={
description="CLOCKWISE TOP SEMICIRCLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="curvearrowright",
unicodeslot=0x21B7,
},
[0x21B8]={
@@ -51720,6 +51785,8 @@ characters.data={
description="ANTICLOCKWISE OPEN CIRCLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="circlearrowright",
unicodeslot=0x21BA,
},
[0x21BB]={
@@ -51727,6 +51794,8 @@ characters.data={
description="CLOCKWISE OPEN CIRCLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="circlearrowleft",
unicodeslot=0x21BB,
},
[0x21BC]={
@@ -51734,6 +51803,8 @@ characters.data={
description="LEFTWARDS HARPOON WITH BARB UPWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftharpoonup",
unicodeslot=0x21BC,
},
[0x21BD]={
@@ -51741,6 +51812,8 @@ characters.data={
description="LEFTWARDS HARPOON WITH BARB DOWNWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftharpoondown",
unicodeslot=0x21BD,
},
[0x21BE]={
@@ -51748,6 +51821,10 @@ characters.data={
description="UPWARDS HARPOON WITH BARB RIGHTWARDS",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="upharpoonright" },
+ { class="relation", name="restriction" },
+ },
unicodeslot=0x21BE,
},
[0x21BF]={
@@ -51755,6 +51832,8 @@ characters.data={
description="UPWARDS HARPOON WITH BARB LEFTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="upharpoonleft",
unicodeslot=0x21BF,
},
[0x21C0]={
@@ -51762,6 +51841,8 @@ characters.data={
description="RIGHTWARDS HARPOON WITH BARB UPWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightharpoonup",
unicodeslot=0x21C0,
},
[0x21C1]={
@@ -51769,6 +51850,8 @@ characters.data={
description="RIGHTWARDS HARPOON WITH BARB DOWNWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightharpoondown",
unicodeslot=0x21C1,
},
[0x21C2]={
@@ -51776,6 +51859,8 @@ characters.data={
description="DOWNWARDS HARPOON WITH BARB RIGHTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="downharpoonright",
unicodeslot=0x21C2,
},
[0x21C3]={
@@ -51783,6 +51868,8 @@ characters.data={
description="DOWNWARDS HARPOON WITH BARB LEFTWARDS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="downharpoonleft",
unicodeslot=0x21C3,
},
[0x21C4]={
@@ -51790,6 +51877,8 @@ characters.data={
description="RIGHTWARDS ARROW OVER LEFTWARDS ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightleftarrows",
unicodeslot=0x21C4,
},
[0x21C5]={
@@ -51797,6 +51886,8 @@ characters.data={
description="UPWARDS ARROW LEFTWARDS OF DOWNWARDS ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="updownarrows",
unicodeslot=0x21C5,
},
[0x21C6]={
@@ -51804,6 +51895,8 @@ characters.data={
description="LEFTWARDS ARROW OVER RIGHTWARDS ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftrightarrows",
unicodeslot=0x21C6,
},
[0x21C7]={
@@ -51811,6 +51904,8 @@ characters.data={
description="LEFTWARDS PAIRED ARROWS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftleftarrows",
unicodeslot=0x21C7,
},
[0x21C8]={
@@ -51818,6 +51913,8 @@ characters.data={
description="UPWARDS PAIRED ARROWS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="upuparrows",
unicodeslot=0x21C8,
},
[0x21C9]={
@@ -51825,6 +51922,8 @@ characters.data={
description="RIGHTWARDS PAIRED ARROWS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightrightarrows",
unicodeslot=0x21C9,
},
[0x21CA]={
@@ -51832,6 +51931,8 @@ characters.data={
description="DOWNWARDS PAIRED ARROWS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="downdownarrows",
unicodeslot=0x21CA,
},
[0x21CB]={
@@ -51839,6 +51940,8 @@ characters.data={
description="LEFTWARDS HARPOON OVER RIGHTWARDS HARPOON",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftrightharpoons",
unicodeslot=0x21CB,
},
[0x21CC]={
@@ -51846,6 +51949,8 @@ characters.data={
description="RIGHTWARDS HARPOON OVER LEFTWARDS HARPOON",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightleftharpoons",
unicodeslot=0x21CC,
},
[0x21CD]={
@@ -51853,6 +51958,8 @@ characters.data={
description="LEFTWARDS DOUBLE ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nLeftarrow",
specials={ "char", 0x21D0, 0x0338 },
unicodeslot=0x21CD,
},
@@ -51861,6 +51968,8 @@ characters.data={
description="LEFT RIGHT DOUBLE ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nLeftrightarrow",
specials={ "char", 0x21D4, 0x0338 },
unicodeslot=0x21CE,
},
@@ -51869,6 +51978,8 @@ characters.data={
description="RIGHTWARDS DOUBLE ARROW WITH STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nRightarrow",
specials={ "char", 0x21D2, 0x0338 },
unicodeslot=0x21CF,
},
@@ -51888,6 +51999,8 @@ characters.data={
description="UPWARDS DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Uparrow",
unicodeslot=0x21D1,
},
[0x21D2]={
@@ -51907,6 +52020,8 @@ characters.data={
description="DOWNWARDS DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Downarrow",
unicodeslot=0x21D3,
},
[0x21D4]={
@@ -51925,6 +52040,8 @@ characters.data={
description="UP DOWN DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Updownarrow",
unicodeslot=0x21D5,
},
[0x21D6]={
@@ -51932,6 +52049,8 @@ characters.data={
description="NORTH WEST DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Nwarrow",
unicodeslot=0x21D6,
},
[0x21D7]={
@@ -51939,6 +52058,8 @@ characters.data={
description="NORTH EAST DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Nearrow",
unicodeslot=0x21D7,
},
[0x21D8]={
@@ -51946,6 +52067,8 @@ characters.data={
description="SOUTH EAST DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Searrow",
unicodeslot=0x21D8,
},
[0x21D9]={
@@ -51953,6 +52076,8 @@ characters.data={
description="SOUTH WEST DOUBLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Swarrow",
unicodeslot=0x21D9,
},
[0x21DA]={
@@ -51960,6 +52085,8 @@ characters.data={
description="LEFTWARDS TRIPLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Lleftarrow",
unicodeslot=0x21DA,
},
[0x21DB]={
@@ -51967,6 +52094,8 @@ characters.data={
description="RIGHTWARDS TRIPLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Rrightarrow",
unicodeslot=0x21DB,
},
[0x21DC]={
@@ -51974,6 +52103,8 @@ characters.data={
description="LEFTWARDS SQUIGGLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftsquigarrow",
unicodeslot=0x21DC,
},
[0x21DD]={
@@ -51981,6 +52112,10 @@ characters.data={
description="RIGHTWARDS SQUIGGLE ARROW",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation",name="rightsquigarrow" },
+ { class="relation",name="leadsto" },
+ },
unicodeslot=0x21DD,
},
[0x21DE]={
@@ -52002,6 +52137,8 @@ characters.data={
description="LEFTWARDS DASHED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashleftarrow",
unicodeslot=0x21E0,
},
[0x21E1]={
@@ -52009,6 +52146,8 @@ characters.data={
description="UPWARDS DASHED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashuparrow",
unicodeslot=0x21E1,
},
[0x21E2]={
@@ -52016,6 +52155,10 @@ characters.data={
description="RIGHTWARDS DASHED ARROW",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="dashrightarrow" } ,
+ { class="relation", name="dasharrow" } ,
+ },
unicodeslot=0x21E2,
},
[0x21E3]={
@@ -52023,6 +52166,8 @@ characters.data={
description="DOWNWARDS DASHED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashdownarrow",
unicodeslot=0x21E3,
},
[0x21E4]={
@@ -52206,6 +52351,8 @@ characters.data={
description="LEFTWARDS OPEN-HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftarrowtriangle",
unicodeslot=0x21FD,
},
[0x21FE]={
@@ -52213,6 +52360,8 @@ characters.data={
description="RIGHTWARDS OPEN-HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rightarrowtriangle",
unicodeslot=0x21FE,
},
[0x21FF]={
@@ -52220,6 +52369,8 @@ characters.data={
description="LEFT RIGHT OPEN-HEADED ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leftrightarrowtriangle",
unicodeslot=0x21FF,
},
[0x2200]={
@@ -52238,6 +52389,8 @@ characters.data={
description="COMPLEMENT",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="complement",
unicodeslot=0x2201,
},
[0x2202]={
@@ -52247,7 +52400,7 @@ characters.data={
description="PARTIAL DIFFERENTIAL",
direction="on",
linebreak="ai",
- mathclass="variable",
+ mathclass="default",
mathname="partial",
unicodeslot=0x2202,
},
@@ -52267,6 +52420,8 @@ characters.data={
description="THERE DOES NOT EXIST",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="nexists",
specials={ "char", 0x2203, 0x0338 },
unicodeslot=0x2204,
},
@@ -52276,7 +52431,7 @@ characters.data={
description="EMPTY SET",
direction="on",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="emptyset",
unicodeslot=0x2205,
},
@@ -52295,8 +52450,6 @@ characters.data={
description="NABLA",
direction="on",
linebreak="ai",
- mathclass="variable",
- mathname="nabla",
unicodeslot=0x2207,
},
[0x2208]={
@@ -52307,7 +52460,7 @@ characters.data={
direction="on",
linebreak="ai",
mathclass="relation",
- mathname=false, -- in
+ mathname="in",
mirror=0x220B,
unicodeslot=0x2208,
},
@@ -52317,9 +52470,9 @@ characters.data={
description="NOT AN ELEMENT OF",
direction="on",
linebreak="al",
- mathclass="relation",
- mathname="ni",
mirror=0x220C,
+ mathclass="relation",
+ mathname="nin",
specials={ "char", 0x2208, 0x0338 },
unicodeslot=0x2209,
},
@@ -52338,6 +52491,10 @@ characters.data={
description="CONTAINS AS MEMBER",
direction="on",
linebreak="ai",
+ mathspec={
+ { class="relation", name="ni" },
+ { class="relation", name="owns" },
+ },
mirror=0x2208,
unicodeslot=0x220B,
},
@@ -52348,6 +52505,10 @@ characters.data={
linebreak="al",
mirror=0x2209,
specials={ "char", 0x220B, 0x0338 },
+ mathspec={
+ { class="relation", name="nni" },
+ { class="relation", name="nowns" },
+ },
unicodeslot=0x220C,
},
[0x220D]={
@@ -52376,12 +52537,12 @@ characters.data={
mathname="prod",
unicodeslot=0x220F,
},
- [0x2210]={
+[0x2210]={
category="sm",
description="N-ARY COPRODUCT",
direction="on",
linebreak="al",
- mathclass="relation",
+ mathclass="limop",
mathname="coprod",
unicodeslot=0x2210,
},
@@ -52419,6 +52580,8 @@ characters.data={
description="DOT PLUS",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="dotplus",
unicodeslot=0x2214,
},
[0x2215]={
@@ -52427,16 +52590,22 @@ characters.data={
description="DIVISION SLASH",
direction="on",
linebreak="ai",
+ --~ mathclass="ord",
+ --~ mathname="diagup",
mirror=0x29F5,
unicodeslot=0x2215,
},
+ -- AM: diagup and diagdown are mapped to 2215 and 2216 by Tralics,
+ -- but ams uses different symbols for setminus and diagdown.
[0x2216]={
category="sm",
description="SET MINUS",
direction="on",
linebreak="al",
- mathclass="binary",
- mathname="setminus",
+ mathspec={
+ { class="binary", name="setminus" },
+ --~ { class="ord", name="diagdown" },
+ },
unicodeslot=0x2216,
},
[0x2217]={
@@ -52474,6 +52643,8 @@ characters.data={
description="SQUARE ROOT",
direction="on",
linebreak="ai",
+ mathclass="radical",
+ mathname="surd",
unicodeslot=0x221A,
},
[0x221B]={
@@ -52508,7 +52679,7 @@ characters.data={
description="INFINITY",
direction="on",
linebreak="ai",
- mathclass="variable",
+ mathclass="default",
mathname="infty",
unicodeslot=0x221E,
},
@@ -52518,6 +52689,8 @@ characters.data={
cjkwd="a",
description="RIGHT ANGLE",
direction="on",
+ mathclass="ord",
+ mathname="rightangle",
linebreak="ai",
unicodeslot=0x221F,
},
@@ -52556,6 +52729,8 @@ characters.data={
description="DIVIDES",
direction="on",
linebreak="ai",
+ mathclass="binary",
+ mathname="divides",
unicodeslot=0x2223,
},
[0x2224]={
@@ -52564,6 +52739,10 @@ characters.data={
direction="on",
linebreak="al",
specials={ "char", 0x2223, 0x0338 },
+ mathspec={
+ { class="binary", name="ndivides", },
+ { class="relation", name="nmid", },
+ },
unicodeslot=0x2224,
},
[0x2225]={
@@ -52572,8 +52751,13 @@ characters.data={
description="PARALLEL TO",
direction="on",
linebreak="ai",
- mathclass="relation",
- mathname="parallel",
+ mathspec={
+ { class="relation", name="parallel" },
+ { class="delimiter", name="Vert" },
+ { class="nothing", name="Arrowvert" },
+ { class="open", name="lVert" },
+ { class="close", name="rVert" },
+ },
unicodeslot=0x2225,
},
[0x2226]={
@@ -52581,6 +52765,8 @@ characters.data={
description="NOT PARALLEL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nparallel",
specials={ "char", 0x2225, 0x0338 },
unicodeslot=0x2226,
},
@@ -52591,8 +52777,10 @@ characters.data={
description="LOGICAL AND",
direction="on",
linebreak="ai",
- mathclass="limop",
- mathname="wedge",
+ mathspec={
+ { class="binary", name="wedge" },
+ { class="binary", name="land" },
+ },
unicodeslot=0x2227,
},
[0x2228]={
@@ -52602,8 +52790,10 @@ characters.data={
description="LOGICAL OR",
direction="on",
linebreak="ai",
- mathclass="limop",
- mathname="vee",
+ mathspec={
+ { class="bin",name="vee" },
+ { class="bin",name="lor" },
+ },
unicodeslot=0x2228,
},
[0x2229]={
@@ -52613,7 +52803,7 @@ characters.data={
description="INTERSECTION",
direction="on",
linebreak="ai",
- mathclass="limop",
+ mathclass="binary",
mathname="cap",
unicodeslot=0x2229,
},
@@ -52624,7 +52814,7 @@ characters.data={
description="UNION",
direction="on",
linebreak="ai",
- mathclass="limop",
+ mathclass="binary",
mathname="cup",
unicodeslot=0x222A,
},
@@ -52635,8 +52825,10 @@ characters.data={
description="INTEGRAL",
direction="on",
linebreak="ai",
- mathclass="limop",
- mathname="intop",
+ mathspec={
+ { class="nothing", name="intop" },
+ { class="limop" , name="int" },
+ },
unicodeslot=0x222B,
},
[0x222C]={
@@ -52646,6 +52838,10 @@ characters.data={
direction="on",
linebreak="ai",
specials={ "compat", 0x222B, 0x222B },
+ mathspec={
+ { class="nothing", name="iintop" },
+ { class="limop" , name="iint" },
+ },
unicodeslot=0x222C,
},
[0x222D]={
@@ -52654,6 +52850,10 @@ characters.data={
direction="on",
linebreak="al",
specials={ "compat", 0x222B, 0x222B, 0x222B },
+ mathspec={
+ { class="nothing", name="iiintop" },
+ { class="limop" , name="iiint" },
+ },
unicodeslot=0x222D,
},
[0x222E]={
@@ -52662,6 +52862,8 @@ characters.data={
description="CONTOUR INTEGRAL",
direction="on",
linebreak="ai",
+ mathclass="limop",
+ mathname="oint",
unicodeslot=0x222E,
},
[0x222F]={
@@ -52669,6 +52871,8 @@ characters.data={
description="SURFACE INTEGRAL",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="oiint",
specials={ "compat", 0x222E, 0x222E },
unicodeslot=0x222F,
},
@@ -52677,6 +52881,8 @@ characters.data={
description="VOLUME INTEGRAL",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="oiiint",
specials={ "compat", 0x222E, 0x222E, 0x222E },
unicodeslot=0x2230,
},
@@ -52685,6 +52891,8 @@ characters.data={
description="CLOCKWISE INTEGRAL",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="intclockwise",
unicodeslot=0x2231,
},
[0x2232]={
@@ -52692,6 +52900,8 @@ characters.data={
description="CLOCKWISE CONTOUR INTEGRAL",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="ointclockwise",
unicodeslot=0x2232,
},
[0x2233]={
@@ -52699,6 +52909,8 @@ characters.data={
description="ANTICLOCKWISE CONTOUR INTEGRAL",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="ointctrclockwise",
unicodeslot=0x2233,
},
[0x2234]={
@@ -52708,6 +52920,8 @@ characters.data={
description="THEREFORE",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="therefore",
unicodeslot=0x2234,
},
[0x2235]={
@@ -52716,6 +52930,8 @@ characters.data={
description="BECAUSE",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="because",
unicodeslot=0x2235,
},
[0x2236]={
@@ -52734,6 +52950,8 @@ characters.data={
description="PROPORTION",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="squaredots",
unicodeslot=0x2237,
},
[0x2238]={
@@ -52741,6 +52959,8 @@ characters.data={
description="DOT MINUS",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="dotminus",
unicodeslot=0x2238,
},
[0x2239]={
@@ -52748,6 +52968,8 @@ characters.data={
description="EXCESS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="minuscolon",
unicodeslot=0x2239,
},
[0x223A]={
@@ -52782,6 +53004,8 @@ characters.data={
description="REVERSED TILDE",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="backsim",
mirror=0x223C,
unicodeslot=0x223D,
},
@@ -52804,6 +53028,8 @@ characters.data={
description="WREATH PRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="wr",
unicodeslot=0x2240,
},
[0x2241]={
@@ -52811,6 +53037,8 @@ characters.data={
description="NOT TILDE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsim",
specials={ "char", 0x223C, 0x0338 },
unicodeslot=0x2241,
},
@@ -52819,6 +53047,8 @@ characters.data={
description="MINUS TILDE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqsim",
unicodeslot=0x2242,
},
[0x2243]={
@@ -52837,6 +53067,8 @@ characters.data={
direction="on",
linebreak="al",
specials={ "char", 0x2243, 0x0338 },
+ mathclass="relation",
+ mathname="nsimeq",
unicodeslot=0x2244,
},
[0x2245]={
@@ -52845,8 +53077,10 @@ characters.data={
description="APPROXIMATELY EQUAL TO",
direction="on",
linebreak="al",
- mathclass="relation",
- mathname="approxeq",
+ mathspec={
+ { class="relation", name="approxEq"},
+ { class="relation", name="cong"},
+ },
unicodeslot=0x2245,
},
[0x2246]={
@@ -52854,6 +53088,10 @@ characters.data={
description="APPROXIMATELY BUT NOT ACTUALLY EQUAL TO",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="napproxEq"},
+ { class="relation", name="ncong"},
+ },
unicodeslot=0x2246,
},
[0x2247]={
@@ -52861,6 +53099,8 @@ characters.data={
description="NEITHER APPROXIMATELY NOR ACTUALLY EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="approxnEq",
specials={ "char", 0x2245, 0x0338 },
unicodeslot=0x2247,
},
@@ -52880,6 +53120,8 @@ characters.data={
description="NOT ALMOST EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="napprox",
specials={ "char", 0x2248, 0x0338 },
unicodeslot=0x2249,
},
@@ -52887,6 +53129,8 @@ characters.data={
category="sm",
description="ALMOST EQUAL OR EQUAL TO",
direction="on",
+ mathclass="relation",
+ mathname="approxeq",
linebreak="al",
unicodeslot=0x224A,
},
@@ -52904,7 +53148,6 @@ characters.data={
direction="on",
linebreak="ai",
mathclass="relation",
- mathname="equiv",
unicodeslot=0x224C,
},
[0x224D]={
@@ -52912,6 +53155,8 @@ characters.data={
description="EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="asymp",
unicodeslot=0x224D,
},
[0x224E]={
@@ -52919,6 +53164,8 @@ characters.data={
description="GEOMETRICALLY EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Bumpeq",
unicodeslot=0x224E,
},
[0x224F]={
@@ -52940,6 +53187,10 @@ characters.data={
description="GEOMETRICALLY EQUAL TO",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="doteqdot" },
+ { class="relation", name="Doteq" },
+ },
unicodeslot=0x2251,
},
[0x2252]={
@@ -52949,6 +53200,8 @@ characters.data={
direction="on",
linebreak="ai",
mirror=0x2253,
+ mathclass="relation",
+ mathname="fallingdotseq",
unicodeslot=0x2252,
},
[0x2253]={
@@ -52957,6 +53210,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2252,
+ mathclass="relation",
+ mathname="risingdotseq",
unicodeslot=0x2253,
},
[0x2254]={
@@ -52965,6 +53220,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2255,
+ mathclass="relation",
+ mathname="colonequals",
unicodeslot=0x2254,
},
[0x2255]={
@@ -52973,6 +53230,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2254,
+ mathclass="relation",
+ mathname="equalscolon",
unicodeslot=0x2255,
},
[0x2256]={
@@ -52980,6 +53239,8 @@ characters.data={
description="RING IN EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqcirc",
unicodeslot=0x2256,
},
[0x2257]={
@@ -52987,6 +53248,8 @@ characters.data={
description="RING EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="circeq",
unicodeslot=0x2257,
},
[0x2258]={
@@ -53004,13 +53267,15 @@ characters.data={
linebreak="al",
unicodeslot=0x2259,
mathclass="relation",
- mathname="wedgeq",
+ mathname="wedgeeq",
},
[0x225A]={
category="sm",
description="EQUIANGULAR TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="veeeq",
unicodeslot=0x225A,
},
[0x225B]={
@@ -53018,6 +53283,8 @@ characters.data={
description="STAR EQUALS",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="stareq",
unicodeslot=0x225B,
},
[0x225C]={
@@ -53034,6 +53301,8 @@ characters.data={
description="EQUAL TO BY DEFINITION",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="definedeq",
unicodeslot=0x225D,
},
[0x225E]={
@@ -53041,6 +53310,8 @@ characters.data={
description="MEASURED BY",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="measuredeq",
unicodeslot=0x225E,
},
[0x225F]={
@@ -53048,6 +53319,8 @@ characters.data={
description="QUESTIONED EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="questionedeq",
unicodeslot=0x225F,
},
[0x2260]={
@@ -53056,10 +53329,11 @@ characters.data={
cjkwd="a",
description="NOT EQUAL TO",
direction="on",
- fallback=[[\not=]],
linebreak="ai",
- mathclass="relation",
- mathname="neq",
+ mathspec={
+ { class="relation", name="neq" },
+ { class="relation", name="ne" },
+ },
specials={ "char", 0x003D, 0x0338 },
unicodeslot=0x2260,
},
@@ -53079,6 +53353,8 @@ characters.data={
description="NOT IDENTICAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nequiv",
specials={ "char", 0x2261, 0x0338 },
unicodeslot=0x2262,
},
@@ -53096,8 +53372,10 @@ characters.data={
description="LESS-THAN OR EQUAL TO",
direction="on",
linebreak="ai",
- mathclass="relation",
- mathname="leq",
+ mathspec={
+ { class="relation", name="leq" },
+ { class="relation", name="le" },
+ },
mirror=0x2265,
unicodeslot=0x2264,
},
@@ -53108,8 +53386,10 @@ characters.data={
description="GREATER-THAN OR EQUAL TO",
direction="on",
linebreak="ai",
- mathclass="relation",
- mathname="geq",
+ mathspec={
+ { class="relation", name="geq" },
+ { class="relation", name="ge" },
+ },
mirror=0x2264,
unicodeslot=0x2265,
},
@@ -53119,6 +53399,8 @@ characters.data={
description="LESS-THAN OVER EQUAL TO",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="leqq",
mirror=0x2267,
unicodeslot=0x2266,
},
@@ -53128,6 +53410,8 @@ characters.data={
description="GREATER-THAN OVER EQUAL TO",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="geqq",
mirror=0x2266,
unicodeslot=0x2267,
},
@@ -53136,6 +53420,8 @@ characters.data={
description="LESS-THAN BUT NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lneqq",
mirror=0x2269,
unicodeslot=0x2268,
},
@@ -53144,6 +53430,8 @@ characters.data={
description="GREATER-THAN BUT NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gneqq",
mirror=0x2268,
unicodeslot=0x2269,
},
@@ -53174,6 +53462,8 @@ characters.data={
description="BETWEEN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="between",
unicodeslot=0x226C,
},
[0x226D]={
@@ -53181,6 +53471,8 @@ characters.data={
description="NOT EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nasymp",
specials={ "char", 0x224D, 0x0338 },
unicodeslot=0x226D,
},
@@ -53190,6 +53482,8 @@ characters.data={
description="NOT LESS-THAN",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="nless",
mirror=0x226F,
specials={ "char", 0x003C, 0x0338 },
unicodeslot=0x226E,
@@ -53200,6 +53494,8 @@ characters.data={
description="NOT GREATER-THAN",
direction="on",
linebreak="ai",
+ mathclass="relation",
+ mathname="ngtr",
mirror=0x226E,
specials={ "char", 0x003E, 0x0338 },
unicodeslot=0x226F,
@@ -53209,6 +53505,8 @@ characters.data={
description="NEITHER LESS-THAN NOR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nleq",
mirror=0x2271,
specials={ "char", 0x2264, 0x0338 },
unicodeslot=0x2270,
@@ -53218,6 +53516,8 @@ characters.data={
description="NEITHER GREATER-THAN NOR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ngeq",
mirror=0x2270,
specials={ "char", 0x2265, 0x0338 },
unicodeslot=0x2271,
@@ -53227,6 +53527,8 @@ characters.data={
description="LESS-THAN OR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lesssim",
mirror=0x2273,
unicodeslot=0x2272,
},
@@ -53235,6 +53537,8 @@ characters.data={
description="GREATER-THAN OR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gtrsim",
mirror=0x2272,
unicodeslot=0x2273,
},
@@ -53243,6 +53547,8 @@ characters.data={
description="NEITHER LESS-THAN NOR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nlesssim",
mirror=0x2275,
specials={ "char", 0x2272, 0x0338 },
unicodeslot=0x2274,
@@ -53252,6 +53558,8 @@ characters.data={
description="NEITHER GREATER-THAN NOR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ngtrsim",
mirror=0x2274,
specials={ "char", 0x2273, 0x0338 },
unicodeslot=0x2275,
@@ -53261,6 +53569,8 @@ characters.data={
description="LESS-THAN OR GREATER-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lessgtr",
mirror=0x2277,
unicodeslot=0x2276,
},
@@ -53269,6 +53579,8 @@ characters.data={
description="GREATER-THAN OR LESS-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gtrless",
mirror=0x2276,
unicodeslot=0x2277,
},
@@ -53277,6 +53589,8 @@ characters.data={
description="NEITHER LESS-THAN NOR GREATER-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nlessgtr",
mirror=0x2279,
specials={ "char", 0x2276, 0x0338 },
unicodeslot=0x2278,
@@ -53286,6 +53600,8 @@ characters.data={
description="NEITHER GREATER-THAN NOR LESS-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ngtrless",
mirror=0x2278,
specials={ "char", 0x2277, 0x0338 },
unicodeslot=0x2279,
@@ -53315,6 +53631,8 @@ characters.data={
description="PRECEDES OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="preccurlyeq",
mirror=0x227D,
unicodeslot=0x227C,
},
@@ -53323,6 +53641,8 @@ characters.data={
description="SUCCEEDS OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succcurlyeq",
mirror=0x227C,
unicodeslot=0x227D,
},
@@ -53331,6 +53651,8 @@ characters.data={
description="PRECEDES OR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precsim",
mirror=0x227F,
unicodeslot=0x227E,
},
@@ -53339,6 +53661,8 @@ characters.data={
description="SUCCEEDS OR EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succsim",
mirror=0x227E,
unicodeslot=0x227F,
},
@@ -53347,6 +53671,8 @@ characters.data={
description="DOES NOT PRECEDE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nprec",
mirror=0x2281,
specials={ "char", 0x227A, 0x0338 },
unicodeslot=0x2280,
@@ -53356,6 +53682,8 @@ characters.data={
description="DOES NOT SUCCEED",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsucc",
mirror=0x2280,
specials={ "char", 0x227B, 0x0338 },
unicodeslot=0x2281,
@@ -53368,7 +53696,7 @@ characters.data={
direction="on",
linebreak="ai",
mathclass="relation",
- mathname="subset",
+ mathname="subset", -- Subset
mirror=0x2283,
unicodeslot=0x2282,
},
@@ -53390,7 +53718,8 @@ characters.data={
description="NOT A SUBSET OF",
direction="on",
fallback=[[\not\subset]],
--- mathclass="relation",
+ mathclass="relation",
+ mathname="nsubset",
linebreak="al",
mirror=0x2285,
specials={ "char", 0x2282, 0x0338 },
@@ -53403,6 +53732,7 @@ characters.data={
fallback=[[\not\supset]],
linebreak="al",
mathclass="relation",
+ mathname="nsupset",
mirror=0x2284,
specials={ "char", 0x2283, 0x0338 },
unicodeslot=0x2285,
@@ -53436,6 +53766,8 @@ characters.data={
description="NEITHER A SUBSET OF NOR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsubseteq",
mirror=0x2289,
specials={ "char", 0x2286, 0x0338 },
unicodeslot=0x2288,
@@ -53445,6 +53777,8 @@ characters.data={
description="NEITHER A SUPERSET OF NOR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsupseteq",
mirror=0x2288,
specials={ "char", 0x2287, 0x0338 },
unicodeslot=0x2289,
@@ -53454,6 +53788,8 @@ characters.data={
description="SUBSET OF WITH NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="subsetneq",
mirror=0x228B,
unicodeslot=0x228A,
},
@@ -53462,6 +53798,8 @@ characters.data={
description="SUPERSET OF WITH NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="supsetneq",
mirror=0x228A,
unicodeslot=0x228B,
},
@@ -53484,6 +53822,8 @@ characters.data={
description="MULTISET UNION",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="uplus",
unicodeslot=0x228E,
},
[0x228F]={
@@ -53491,6 +53831,8 @@ characters.data={
description="SQUARE IMAGE OF",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="sqsubset",
mirror=0x2290,
unicodeslot=0x228F,
},
@@ -53499,6 +53841,8 @@ characters.data={
description="SQUARE ORIGINAL OF",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="sqsupset",
mirror=0x228F,
unicodeslot=0x2290,
},
@@ -53507,6 +53851,8 @@ characters.data={
description="SQUARE IMAGE OF OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="sqsubseteq",
mirror=0x2292,
unicodeslot=0x2291,
},
@@ -53515,6 +53861,8 @@ characters.data={
description="SQUARE ORIGINAL OF OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="sqsupseteq",
mirror=0x2291,
unicodeslot=0x2292,
},
@@ -53523,7 +53871,7 @@ characters.data={
description="SQUARE CAP",
direction="on",
linebreak="al",
- mathclass="relation",
+ mathclass="binary",
mathname="sqcap",
unicodeslot=0x2293,
},
@@ -53532,7 +53880,7 @@ characters.data={
description="SQUARE CUP",
direction="on",
linebreak="al",
- mathclass="relation",
+ mathclass="binary",
mathname="sqcup",
unicodeslot=0x2294,
},
@@ -53591,6 +53939,8 @@ characters.data={
description="CIRCLED RING OPERATOR",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="circledcirc",
unicodeslot=0x229A,
},
[0x229B]={
@@ -53598,6 +53948,8 @@ characters.data={
description="CIRCLED ASTERISK OPERATOR",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="circledast",
unicodeslot=0x229B,
},
[0x229C]={
@@ -53605,6 +53957,8 @@ characters.data={
description="CIRCLED EQUALS",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="circledequals",
unicodeslot=0x229C,
},
[0x229D]={
@@ -53612,6 +53966,8 @@ characters.data={
description="CIRCLED DASH",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="circleddash",
unicodeslot=0x229D,
},
[0x229E]={
@@ -53619,6 +53975,8 @@ characters.data={
description="SQUARED PLUS",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="boxplus",
unicodeslot=0x229E,
},
[0x229F]={
@@ -53626,6 +53984,8 @@ characters.data={
description="SQUARED MINUS",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="boxminus",
unicodeslot=0x229F,
},
[0x22A0]={
@@ -53633,6 +53993,8 @@ characters.data={
description="SQUARED TIMES",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="boxtimes",
unicodeslot=0x22A0,
},
[0x22A1]={
@@ -53640,6 +54002,8 @@ characters.data={
description="SQUARED DOT OPERATOR",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="boxdot",
unicodeslot=0x22A1,
},
[0x22A2]={
@@ -53647,6 +54011,8 @@ characters.data={
description="RIGHT TACK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="vdash",
mirror=0x22A3,
unicodeslot=0x22A2,
},
@@ -53655,6 +54021,8 @@ characters.data={
description="LEFT TACK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashv",
mirror=0x22A2,
unicodeslot=0x22A3,
},
@@ -53663,8 +54031,8 @@ characters.data={
description="DOWN TACK",
direction="on",
linebreak="al",
- mathclass="variable",
- mathname="bot",
+ mathclass="default",
+ mathname="top",
unicodeslot=0x22A4,
},
[0x22A5]={
@@ -53674,8 +54042,10 @@ characters.data={
description="UP TACK",
direction="on",
linebreak="ai",
- mathclass="variable",
- mathname="top",
+ mathspec={
+ { class="default", name="bot" },
+ { class="relation", name="perp" },
+ },
unicodeslot=0x22A5,
},
[0x22A6]={
@@ -53691,6 +54061,9 @@ characters.data={
description="MODELS",
direction="on",
linebreak="al",
+ fallback=[[\mathrel|\joinrel=]],
+ mathclass="relation",
+ mathname="models",
unicodeslot=0x22A7,
},
[0x22A8]={
@@ -53699,6 +54072,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2AE4,
+ mathclass="relation",
+ mathname="vDash",
unicodeslot=0x22A8,
},
[0x22A9]={
@@ -53707,6 +54082,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2AE3,
+ mathclass="relation",
+ mathname="Vdash",
unicodeslot=0x22A9,
},
[0x22AA]={
@@ -53714,6 +54091,8 @@ characters.data={
description="TRIPLE VERTICAL BAR RIGHT TURNSTILE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Vvdash",
unicodeslot=0x22AA,
},
[0x22AB]={
@@ -53722,6 +54101,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x2AE5,
+ mathclass="relation",
+ mathname="VDash",
unicodeslot=0x22AB,
},
[0x22AC]={
@@ -53729,6 +54110,8 @@ characters.data={
description="DOES NOT PROVE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nvdash",
specials={ "char", 0x22A2, 0x0338 },
unicodeslot=0x22AC,
},
@@ -53737,6 +54120,8 @@ characters.data={
description="NOT TRUE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nvDash",
specials={ "char", 0x22A8, 0x0338 },
unicodeslot=0x22AD,
},
@@ -53745,6 +54130,8 @@ characters.data={
description="DOES NOT FORCE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nVdash",
specials={ "char", 0x22A9, 0x0338 },
unicodeslot=0x22AE,
},
@@ -53753,6 +54140,8 @@ characters.data={
description="NEGATED DOUBLE VERTICAL BAR DOUBLE RIGHT TURNSTILE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nVDash",
specials={ "char", 0x22AB, 0x0338 },
unicodeslot=0x22AF,
},
@@ -53777,6 +54166,8 @@ characters.data={
description="NORMAL SUBGROUP OF",
direction="on",
linebreak="al",
+ mathclass="bin",
+ mathname="triangleleft",
mirror=0x22B3,
unicodeslot=0x22B2,
},
@@ -53785,6 +54176,8 @@ characters.data={
description="CONTAINS AS NORMAL SUBGROUP",
direction="on",
linebreak="al",
+ mathclass="bin",
+ mathname="triangleright",
mirror=0x22B2,
unicodeslot=0x22B3,
},
@@ -53825,6 +54218,8 @@ characters.data={
description="MULTIMAP",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="multimap",
unicodeslot=0x22B8,
},
[0x22B9]={
@@ -53839,6 +54234,8 @@ characters.data={
description="INTERCALATE",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="intercal",
unicodeslot=0x22BA,
},
[0x22BB]={
@@ -53846,6 +54243,8 @@ characters.data={
description="XOR",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="veebar",
unicodeslot=0x22BB,
},
[0x22BC]={
@@ -53853,6 +54252,8 @@ characters.data={
description="NAND",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="barwedge",
unicodeslot=0x22BC,
},
[0x22BD]={
@@ -53928,8 +54329,10 @@ characters.data={
description="DOT OPERATOR",
direction="on",
linebreak="al",
- mathclass="binary",
- mathname="cdot",
+ mathspec={
+ { class="binary", name="cdot" },
+ { class="punctuation", name="cdotp" },
+ },
unicodeslot=0x22C5,
},
[0x22C6]={
@@ -53946,6 +54349,8 @@ characters.data={
description="DIVISION TIMES",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="divideontimes",
unicodeslot=0x22C7,
},
[0x22C8]={
@@ -53953,6 +54358,11 @@ characters.data={
description="BOWTIE",
direction="on",
linebreak="al",
+ fallback=[[\mathrel\triangleright\joinrel\mathrel\triangleleft]],
+ mathspec={
+ { class="relation", name="bowtie" },
+ { class="relation", name="Join" }, -- AM: Maybe wrong
+ },
unicodeslot=0x22C8,
},
[0x22C9]={
@@ -53960,6 +54370,8 @@ characters.data={
description="LEFT NORMAL FACTOR SEMIDIRECT PRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="ltimes",
mirror=0x22CA,
unicodeslot=0x22C9,
},
@@ -53968,6 +54380,8 @@ characters.data={
description="RIGHT NORMAL FACTOR SEMIDIRECT PRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="rtimes",
mirror=0x22C9,
unicodeslot=0x22CA,
},
@@ -53976,6 +54390,8 @@ characters.data={
description="LEFT SEMIDIRECT PRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="leftthreetimes",
mirror=0x22CC,
unicodeslot=0x22CB,
},
@@ -53984,6 +54400,8 @@ characters.data={
description="RIGHT SEMIDIRECT PRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="rightthreetimes",
mirror=0x22CB,
unicodeslot=0x22CC,
},
@@ -54000,6 +54418,8 @@ characters.data={
description="CURLY LOGICAL OR",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="curlyvee",
unicodeslot=0x22CE,
},
[0x22CF]={
@@ -54007,6 +54427,8 @@ characters.data={
description="CURLY LOGICAL AND",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="curlywedge",
unicodeslot=0x22CF,
},
[0x22D0]={
@@ -54014,6 +54436,8 @@ characters.data={
description="DOUBLE SUBSET",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Subset",
mirror=0x22D1,
unicodeslot=0x22D0,
},
@@ -54022,6 +54446,8 @@ characters.data={
description="DOUBLE SUPERSET",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Supset",
mirror=0x22D0,
unicodeslot=0x22D1,
},
@@ -54030,6 +54456,10 @@ characters.data={
description="DOUBLE INTERSECTION",
direction="on",
linebreak="al",
+ mathspec={
+ { class="binary", name="Cap" },
+ { class="binary", name="doublecap"},
+ },
unicodeslot=0x22D2,
},
[0x22D3]={
@@ -54037,6 +54467,10 @@ characters.data={
description="DOUBLE UNION",
direction="on",
linebreak="al",
+ mathspec={
+ { class="binary", name="Cup" },
+ { class="binary", name="doublecup"},
+ },
unicodeslot=0x22D3,
},
[0x22D4]={
@@ -54044,6 +54478,8 @@ characters.data={
description="PITCHFORK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="pitchfork",
unicodeslot=0x22D4,
},
[0x22D5]={
@@ -54058,6 +54494,8 @@ characters.data={
description="LESS-THAN WITH DOT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="lessdot",
mirror=0x22D7,
unicodeslot=0x22D6,
},
@@ -54066,6 +54504,8 @@ characters.data={
description="GREATER-THAN WITH DOT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="gtrdot",
mirror=0x22D6,
unicodeslot=0x22D7,
},
@@ -54074,6 +54514,10 @@ characters.data={
description="VERY MUCH LESS-THAN",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="lll"},
+ { class="relation", name="llless"},
+ },
mirror=0x22D9,
unicodeslot=0x22D8,
},
@@ -54082,6 +54526,10 @@ characters.data={
description="VERY MUCH GREATER-THAN",
direction="on",
linebreak="al",
+ mathspec={
+ { class="relation", name="ggg"},
+ { class="relation", name="gggtr"},
+ },
mirror=0x22D8,
unicodeslot=0x22D9,
},
@@ -54091,6 +54539,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22DB,
+ mathclass="relation",
+ mathname="lesseqgtr",
unicodeslot=0x22DA,
},
[0x22DB]={
@@ -54099,6 +54549,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22DA,
+ mathclass="relation",
+ mathname="gtreqless",
unicodeslot=0x22DB,
},
[0x22DC]={
@@ -54106,6 +54558,8 @@ characters.data={
description="EQUAL TO OR LESS-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqless",
mirror=0x22DD,
unicodeslot=0x22DC,
},
@@ -54114,6 +54568,8 @@ characters.data={
description="EQUAL TO OR GREATER-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqgtr",
mirror=0x22DC,
unicodeslot=0x22DD,
},
@@ -54123,6 +54579,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22DF,
+ mathclass="relation",
+ mathname="curlyeqprec",
unicodeslot=0x22DE,
},
[0x22DF]={
@@ -54131,6 +54589,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22DE,
+ mathclass="relation",
+ mathname="curlyeqsucc",
unicodeslot=0x22DF,
},
[0x22E0]={
@@ -54139,6 +54599,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22E1,
+ mathclass="relation",
+ mathname="npreccurlyeq",
specials={ "char", 0x227C, 0x0338 },
unicodeslot=0x22E0,
},
@@ -54148,6 +54610,8 @@ characters.data={
direction="on",
linebreak="al",
mirror=0x22E0,
+ mathclass="relation",
+ mathname="nsucccurlyeq",
specials={ "char", 0x227D, 0x0338 },
unicodeslot=0x22E1,
},
@@ -54156,6 +54620,8 @@ characters.data={
description="NOT SQUARE IMAGE OF OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsqsubseteq",
mirror=0x22E3,
specials={ "char", 0x2291, 0x0338 },
unicodeslot=0x22E2,
@@ -54165,6 +54631,8 @@ characters.data={
description="NOT SQUARE ORIGINAL OF OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nsqsupseteq",
mirror=0x22E2,
specials={ "char", 0x2292, 0x0338 },
unicodeslot=0x22E3,
@@ -54174,6 +54642,8 @@ characters.data={
description="SQUARE IMAGE OF OR NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="sqsubsetneq",
mirror=0x22E5,
unicodeslot=0x22E4,
},
@@ -54182,6 +54652,8 @@ characters.data={
description="SQUARE ORIGINAL OF OR NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="sqsupsetneq",
mirror=0x22E4,
unicodeslot=0x22E5,
},
@@ -54190,6 +54662,8 @@ characters.data={
description="LESS-THAN BUT NOT EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lnsim",
mirror=0x22E7,
unicodeslot=0x22E6,
},
@@ -54198,6 +54672,8 @@ characters.data={
description="GREATER-THAN BUT NOT EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gnsim",
mirror=0x22E6,
unicodeslot=0x22E7,
},
@@ -54206,6 +54682,8 @@ characters.data={
description="PRECEDES BUT NOT EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precnsim",
mirror=0x22E9,
unicodeslot=0x22E8,
},
@@ -54214,6 +54692,8 @@ characters.data={
description="SUCCEEDS BUT NOT EQUIVALENT TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succnsim",
mirror=0x22E8,
unicodeslot=0x22E9,
},
@@ -54222,6 +54702,8 @@ characters.data={
description="NOT NORMAL SUBGROUP OF",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ntriangleright",
mirror=0x22EB,
specials={ "char", 0x22B2, 0x0338 },
unicodeslot=0x22EA,
@@ -54231,6 +54713,8 @@ characters.data={
description="DOES NOT CONTAIN AS NORMAL SUBGROUP",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ntriangleleft",
mirror=0x22EA,
specials={ "char", 0x22B3, 0x0338 },
unicodeslot=0x22EB,
@@ -54240,6 +54724,8 @@ characters.data={
description="NOT NORMAL SUBGROUP OF OR EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ntrianglelefteq",
mirror=0x22ED,
specials={ "char", 0x22B4, 0x0338 },
unicodeslot=0x22EC,
@@ -54249,6 +54735,8 @@ characters.data={
description="DOES NOT CONTAIN AS NORMAL SUBGROUP OR EQUAL",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="ntrianglerighteq",
mirror=0x22EC,
specials={ "char", 0x22B5, 0x0338 },
unicodeslot=0x22ED,
@@ -54258,6 +54746,8 @@ characters.data={
description="VERTICAL ELLIPSIS",
direction="on",
linebreak="al",
+ mathclass="inner",
+ mathname="vdots",
unicodeslot=0x22EE,
},
[0x22EF]={
@@ -54265,6 +54755,8 @@ characters.data={
description="MIDLINE HORIZONTAL ELLIPSIS",
direction="on",
linebreak="al",
+ mathclass="inner",
+ mathname="cdots",
unicodeslot=0x22EF,
},
[0x22F0]={
@@ -54272,6 +54764,8 @@ characters.data={
description="UP RIGHT DIAGONAL ELLIPSIS",
direction="on",
linebreak="al",
+ mathclass="inner",
+ mathname="udots",
mirror=0x22F1,
unicodeslot=0x22F0,
},
@@ -54280,6 +54774,8 @@ characters.data={
description="DOWN RIGHT DIAGONAL ELLIPSIS",
direction="on",
linebreak="al",
+ mathclass="inner",
+ mathname="ddots",
mirror=0x22F0,
unicodeslot=0x22F1,
},
@@ -54396,6 +54892,8 @@ characters.data={
description="DIAMETER SIGN",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="varnothing",
unicodeslot=0x2300,
},
[0x2301]={
@@ -54453,6 +54951,8 @@ characters.data={
description="LEFT CEILING",
direction="on",
linebreak="al",
+ mathclass="open",
+ mathname="lceil",
mirror=0x2309,
unicodeslot=0x2308,
},
@@ -54461,6 +54961,8 @@ characters.data={
description="RIGHT CEILING",
direction="on",
linebreak="al",
+ mathclass="close",
+ mathname="rceil",
mirror=0x2308,
unicodeslot=0x2309,
},
@@ -54469,6 +54971,8 @@ characters.data={
description="LEFT FLOOR",
direction="on",
linebreak="al",
+ mathclass="open",
+ mathname="lfloor",
mirror=0x230B,
unicodeslot=0x230A,
},
@@ -54477,6 +54981,8 @@ characters.data={
description="RIGHT FLOOR",
direction="on",
linebreak="al",
+ mathclass="close",
+ mathname="rfloor",
mirror=0x230A,
unicodeslot=0x230B,
},
@@ -54599,6 +55105,8 @@ characters.data={
description="TOP LEFT CORNER",
direction="on",
linebreak="al",
+ mathclass="open",
+ mathname="ulcorner",
unicodeslot=0x231C,
},
[0x231D]={
@@ -54606,6 +55114,8 @@ characters.data={
description="TOP RIGHT CORNER",
direction="on",
linebreak="al",
+ mathclass="close",
+ mathname="urcorner",
unicodeslot=0x231D,
},
[0x231E]={
@@ -54613,6 +55123,8 @@ characters.data={
description="BOTTOM LEFT CORNER",
direction="on",
linebreak="al",
+ mathclass="open",
+ mathname="llcorner",
unicodeslot=0x231E,
},
[0x231F]={
@@ -54620,6 +55132,8 @@ characters.data={
description="BOTTOM RIGHT CORNER",
direction="on",
linebreak="al",
+ mathclass="close",
+ mathname="lrcorner",
unicodeslot=0x231F,
},
[0x2320]={
@@ -54643,6 +55157,8 @@ characters.data={
description="FROWN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="frown",
unicodeslot=0x2322,
},
[0x2323]={
@@ -54650,6 +55166,8 @@ characters.data={
description="SMILE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="smile",
unicodeslot=0x2323,
},
[0x2324]={
@@ -55645,6 +56163,8 @@ characters.data={
description="UPPER LEFT OR LOWER RIGHT CURLY BRACKET SECTION",
direction="on",
linebreak="al",
+ mathclass="open",
+ mathname="lmoustache",
unicodeslot=0x23B0,
},
[0x23B1]={
@@ -55652,6 +56172,8 @@ characters.data={
description="UPPER RIGHT OR LOWER LEFT CURLY BRACKET SECTION",
direction="on",
linebreak="al",
+ mathclass="close",
+ mathname="rmoustache",
unicodeslot=0x23B1,
},
[0x23B2]={
@@ -55953,6 +56475,8 @@ characters.data={
description="TOP PARENTHESIS",
direction="on",
linebreak="al",
+ mathclass="topaccent",
+ mathname="overparent",
unicodeslot=0x23DC,
},
[0x23DD]={
@@ -55960,6 +56484,8 @@ characters.data={
description="BOTTOM PARENTHESIS",
direction="on",
linebreak="al",
+ mathclass="botaccent",
+ mathname="underparent",
unicodeslot=0x23DD,
},
[0x23DE]={
@@ -55967,6 +56493,8 @@ characters.data={
description="TOP CURLY BRACKET",
direction="on",
linebreak="al",
+ mathclass="topaccent",
+ mathname="overbrace",
unicodeslot=0x23DE,
},
[0x23DF]={
@@ -55974,6 +56502,8 @@ characters.data={
description="BOTTOM CURLY BRACKET",
direction="on",
linebreak="al",
+ mathclass="botaccent",
+ mathname="underbrace",
unicodeslot=0x23DF,
},
[0x23E0]={
@@ -55981,6 +56511,7 @@ characters.data={
description="TOP TORTOISE SHELL BRACKET",
direction="on",
linebreak="al",
+ mathclass="accent",
unicodeslot=0x23E0,
},
[0x23E1]={
@@ -55988,6 +56519,7 @@ characters.data={
description="BOTTOM TORTOISE SHELL BRACKET",
direction="on",
linebreak="al",
+ mathclass="accent",
unicodeslot=0x23E1,
},
[0x23E2]={
@@ -57333,6 +57865,8 @@ characters.data={
direction="l",
lccode=0x24E1,
linebreak="ai",
+ mathclass="ord",
+ mathname="circledR",
specials={ "circle", 0x0052 },
unicodeslot=0x24C7,
},
@@ -57343,6 +57877,8 @@ characters.data={
direction="l",
lccode=0x24E2,
linebreak="ai",
+ mathclass="ord",
+ mathname="circledS",
specials={ "circle", 0x0053 },
unicodeslot=0x24C8,
},
@@ -59168,6 +59704,10 @@ characters.data={
description="WHITE SQUARE",
direction="on",
linebreak="ai",
+ mathspec={
+ { class="ord", name="square" },
+ { class="ord", name="Box" },
+ },
unicodeslot=0x25A1,
},
[0x25A2]={
@@ -59175,6 +59715,8 @@ characters.data={
description="WHITE SQUARE WITH ROUNDED CORNERS",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="blacksquare",
unicodeslot=0x25A2,
},
[0x25A3]={
@@ -59307,8 +59849,10 @@ characters.data={
description="WHITE UP-POINTING TRIANGLE",
direction="on",
linebreak="ai",
- mathclass="ord",
- mathname="triangle",
+ mathspec={
+ { class="ord", name="triangle" },
+ { class="binary", name="bigtriangleup" },
+ },
unicodeslot=0x25B3,
},
[0x25B4]={
@@ -59385,6 +59929,8 @@ characters.data={
description="WHITE DOWN-POINTING TRIANGLE",
direction="on",
linebreak="ai",
+ mathclass="binary",
+ mathname="bigtriangledown",
unicodeslot=0x25BD,
},
[0x25BE]={
@@ -59483,6 +60029,8 @@ characters.data={
description="LOZENGE",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="lozenge",
unicodeslot=0x25CA,
},
[0x25CB]={
@@ -59757,6 +60305,8 @@ characters.data={
description="LARGE CIRCLE",
direction="on",
linebreak="ai",
+ mathclass="binary",
+ mathname="bigcirc",
unicodeslot=0x25EF,
},
[0x25F0]={
@@ -59912,6 +60462,8 @@ characters.data={
description="BLACK STAR",
direction="on",
linebreak="ai",
+ mathclass="ord",
+ mathname="bigstar",
unicodeslot=0x2605,
},
[0x2606]={
@@ -60566,6 +61118,8 @@ characters.data={
description="BLACK SPADE SUIT",
direction="on",
linebreak="ai",
+ mathclass="default",
+ mathname="spadesuit",
unicodeslot=0x2660,
},
[0x2661]={
@@ -60574,6 +61128,8 @@ characters.data={
description="WHITE HEART SUIT",
direction="on",
linebreak="ai",
+ mathclass="default",
+ mathname="heartsuit",
unicodeslot=0x2661,
},
[0x2662]={
@@ -60581,6 +61137,8 @@ characters.data={
description="WHITE DIAMOND SUIT",
direction="on",
linebreak="al",
+ mathclass="default",
+ mathname="diamondsuit",
unicodeslot=0x2662,
},
[0x2663]={
@@ -60590,6 +61148,8 @@ characters.data={
description="BLACK CLUB SUIT",
direction="on",
linebreak="ai",
+ mathclass="default",
+ mathname="clubsuit",
unicodeslot=0x2663,
},
[0x2664]={
@@ -60672,6 +61232,8 @@ characters.data={
description="MUSIC FLAT SIGN",
direction="on",
linebreak="ai",
+ mathclass="default",
+ mathname="flat",
unicodeslot=0x266D,
},
[0x266E]={
@@ -60679,6 +61241,8 @@ characters.data={
description="MUSIC NATURAL SIGN",
direction="on",
linebreak="al",
+ mathclass="default",
+ mathname="natural",
unicodeslot=0x266E,
},
[0x266F]={
@@ -60687,6 +61251,8 @@ characters.data={
description="MUSIC SHARP SIGN",
direction="on",
linebreak="ai",
+ mathclass="default",
+ mathname="sharp",
unicodeslot=0x266F,
},
[0x2670]={
@@ -61247,6 +61813,8 @@ characters.data={
description="CHECK MARK",
direction="on",
linebreak="al",
+ mathclass="nothing",
+ mathname="checkmark",
unicodeslot=0x2713,
},
[0x2714]={
@@ -61338,6 +61906,8 @@ characters.data={
description="MALTESE CROSS",
direction="on",
linebreak="al",
+ mathclass="nothing",
+ mathname="maltese",
unicodeslot=0x2720,
},
[0x2721]={
@@ -62631,6 +63201,8 @@ characters.data={
description="MATHEMATICAL LEFT WHITE SQUARE BRACKET",
direction="on",
linebreak="op",
+ mathclass="open",
+ mathname="llbracket",
mirror=0x27E7,
unicodeslot=0x27E6,
},
@@ -62640,6 +63212,8 @@ characters.data={
description="MATHEMATICAL RIGHT WHITE SQUARE BRACKET",
direction="on",
linebreak="cl",
+ mathclass="close",
+ mathname="rrbracket",
mirror=0x27E6,
unicodeslot=0x27E7,
},
@@ -62649,6 +63223,8 @@ characters.data={
description="MATHEMATICAL LEFT ANGLE BRACKET",
direction="on",
linebreak="op",
+ mathclass="open",
+ mathname="langle",
mirror=0x27E9,
unicodeslot=0x27E8,
},
@@ -62658,6 +63234,8 @@ characters.data={
description="MATHEMATICAL RIGHT ANGLE BRACKET",
direction="on",
linebreak="cl",
+ mathclass="close",
+ mathname="rangle",
mirror=0x27E8,
unicodeslot=0x27E9,
},
@@ -62667,6 +63245,8 @@ characters.data={
description="MATHEMATICAL LEFT DOUBLE ANGLE BRACKET",
direction="on",
linebreak="op",
+ mathclass="open",
+ mathname="llangle",
mirror=0x27EB,
unicodeslot=0x27EA,
},
@@ -62676,6 +63256,8 @@ characters.data={
description="MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET",
direction="on",
linebreak="cl",
+ mathclass="close",
+ mathname="rrangle",
mirror=0x27EA,
unicodeslot=0x27EB,
},
@@ -62719,6 +63301,9 @@ characters.data={
description="LONG LEFTWARDS ARROW",
direction="on",
linebreak="al",
+ fallback=[[\leftarrow\joinrel\relbar]],
+ mathclass="relation",
+ mathname="longleftarrow",
unicodeslot=0x27F5,
},
[0x27F6]={
@@ -62726,6 +63311,9 @@ characters.data={
description="LONG RIGHTWARDS ARROW",
direction="on",
linebreak="al",
+ fallback=[[\relbar\joinrel\rightarrow]],
+ mathclass="relation",
+ mathname="longrightarrow",
unicodeslot=0x27F6,
},
[0x27F7]={
@@ -62733,6 +63321,9 @@ characters.data={
description="LONG LEFT RIGHT ARROW",
direction="on",
linebreak="al",
+ fallback=[[\leftarrow\joinrel\rightarrow]],
+ mathclass="relation",
+ mathname="longleftrightarrow",
unicodeslot=0x27F7,
},
[0x27F8]={
@@ -62740,6 +63331,9 @@ characters.data={
description="LONG LEFTWARDS DOUBLE ARROW",
direction="on",
linebreak="al",
+ fallback=[[\Leftarrow\joinrel\Relbar]],
+ mathclass="relation",
+ mathname="Longleftarrow",
unicodeslot=0x27F8,
},
[0x27F9]={
@@ -62747,6 +63341,9 @@ characters.data={
description="LONG RIGHTWARDS DOUBLE ARROW",
direction="on",
linebreak="al",
+ fallback=[[\Relbar\joinrel\Rightarrow]],
+ mathclass="relation",
+ mathname="Longrightarrow",
unicodeslot=0x27F9,
},
[0x27FA]={
@@ -62754,6 +63351,9 @@ characters.data={
description="LONG LEFT RIGHT DOUBLE ARROW",
direction="on",
linebreak="al",
+ fallback=[[\Leftarrow\joinrel\Rightarrow]],
+ mathclass="relation",
+ mathname="Longleftrightarrow",
unicodeslot=0x27FA,
},
[0x27FB]={
@@ -62761,6 +63361,9 @@ characters.data={
description="LONG LEFTWARDS ARROW FROM BAR",
direction="on",
linebreak="al",
+ fallback=[[\longleftarrow\mapstochar]], -- untested
+ mathclass="relation",
+ mathname="longmapsfrom",
unicodeslot=0x27FB,
},
[0x27FC]={
@@ -62768,6 +63371,9 @@ characters.data={
description="LONG RIGHTWARDS ARROW FROM BAR",
direction="on",
linebreak="al",
+ fallback=[[\mapstochar\longrightarrow]],
+ mathclass="relation",
+ mathname="longmapsto",
unicodeslot=0x27FC,
},
[0x27FD]={
@@ -62775,6 +63381,8 @@ characters.data={
description="LONG LEFTWARDS DOUBLE ARROW FROM BAR",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Longmapsfrom",
unicodeslot=0x27FD,
},
[0x27FE]={
@@ -62782,6 +63390,8 @@ characters.data={
description="LONG RIGHTWARDS DOUBLE ARROW FROM BAR",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Longmapsto",
unicodeslot=0x27FE,
},
[0x27FF]={
@@ -62789,6 +63399,8 @@ characters.data={
description="LONG RIGHTWARDS SQUIGGLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="longrightsquigarrow",
unicodeslot=0x27FF,
},
[0x2800]={
@@ -64630,6 +65242,8 @@ characters.data={
description="LEFTWARDS DOUBLE ARROW FROM BAR",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Mapsfrom",
unicodeslot=0x2906,
},
[0x2907]={
@@ -64637,6 +65251,8 @@ characters.data={
description="RIGHTWARDS DOUBLE ARROW FROM BAR",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Mapsto",
unicodeslot=0x2907,
},
[0x2908]={
@@ -64658,6 +65274,8 @@ characters.data={
description="UPWARDS TRIPLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Uuparrow",
unicodeslot=0x290A,
},
[0x290B]={
@@ -64665,6 +65283,8 @@ characters.data={
description="DOWNWARDS TRIPLE ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="Ddownarrow",
unicodeslot=0x290B,
},
[0x290C]={
@@ -64672,6 +65292,8 @@ characters.data={
description="LEFTWARDS DOUBLE DASH ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashedleftarrow",
unicodeslot=0x290C,
},
[0x290D]={
@@ -64679,6 +65301,8 @@ characters.data={
description="RIGHTWARDS DOUBLE DASH ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dashedrightarrow",
unicodeslot=0x290D,
},
[0x290E]={
@@ -64707,6 +65331,8 @@ characters.data={
description="RIGHTWARDS ARROW WITH DOTTED STEM",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="dottedrightarrow",
unicodeslot=0x2911,
},
[0x2912]={
@@ -64742,6 +65368,8 @@ characters.data={
description="RIGHTWARDS TWO-HEADED ARROW WITH TAIL",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="twoheadrightarrowtail",
unicodeslot=0x2916,
},
[0x2917]={
@@ -64749,6 +65377,7 @@ characters.data={
description="RIGHTWARDS TWO-HEADED ARROW WITH TAIL WITH VERTICAL STROKE",
direction="on",
linebreak="al",
+ mathclass="relation",
unicodeslot=0x2917,
},
[0x2918]={
@@ -64819,6 +65448,8 @@ characters.data={
description="NORTH WEST AND SOUTH EAST ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="nwsearrow",
unicodeslot=0x2921,
},
[0x2922]={
@@ -64826,6 +65457,8 @@ characters.data={
description="NORTH EAST AND SOUTH WEST ARROW",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="neswarrow",
unicodeslot=0x2922,
},
[0x2923]={
@@ -64833,6 +65466,8 @@ characters.data={
description="NORTH WEST ARROW WITH HOOK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lhooknwarrow",
unicodeslot=0x2923,
},
[0x2924]={
@@ -64840,6 +65475,8 @@ characters.data={
description="NORTH EAST ARROW WITH HOOK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rhooknearrow",
unicodeslot=0x2924,
},
[0x2925]={
@@ -64847,6 +65484,8 @@ characters.data={
description="SOUTH EAST ARROW WITH HOOK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lhooksearrow",
unicodeslot=0x2925,
},
[0x2926]={
@@ -64854,6 +65493,8 @@ characters.data={
description="SOUTH WEST ARROW WITH HOOK",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rhookswarrow",
unicodeslot=0x2926,
},
[0x2927]={
@@ -66272,6 +66913,8 @@ characters.data={
description="BLACK LOZENGE",
direction="on",
linebreak="al",
+ mathclass="ord",
+ mathname="blacklozenge",
unicodeslot=0x29EB,
},
[0x29EC]={
@@ -66431,6 +67074,8 @@ characters.data={
description="N-ARY CIRCLED PLUS OPERATOR",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigoplus",
unicodeslot=0x2A01,
},
[0x2A02]={
@@ -66438,6 +67083,8 @@ characters.data={
description="N-ARY CIRCLED TIMES OPERATOR",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigotimes",
unicodeslot=0x2A02,
},
[0x2A03]={
@@ -66445,6 +67092,8 @@ characters.data={
description="N-ARY UNION OPERATOR WITH DOT",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigodot",
unicodeslot=0x2A03,
},
[0x2A04]={
@@ -66452,6 +67101,8 @@ characters.data={
description="N-ARY UNION OPERATOR WITH PLUS",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="biguplus",
unicodeslot=0x2A04,
},
[0x2A05]={
@@ -66459,6 +67110,8 @@ characters.data={
description="N-ARY SQUARE INTERSECTION OPERATOR",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigsqcap",
unicodeslot=0x2A05,
},
[0x2A06]={
@@ -66466,6 +67119,8 @@ characters.data={
description="N-ARY SQUARE UNION OPERATOR",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigsqcup",
unicodeslot=0x2A06,
},
[0x2A07]={
@@ -66487,6 +67142,8 @@ characters.data={
description="N-ARY TIMES OPERATOR",
direction="on",
linebreak="al",
+ mathclass="limop",
+ mathname="bigtimes",
unicodeslot=0x2A09,
},
[0x2A0A]={
@@ -66874,6 +67531,8 @@ characters.data={
description="AMALGAMATION OR COPRODUCT",
direction="on",
linebreak="al",
+ mathclass="binary",
+ mathname="amalg",
unicodeslot=0x2A3F,
},
[0x2A40]={
@@ -67315,6 +67974,8 @@ characters.data={
description="LESS-THAN OR SLANTED EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="leqslant",
mirror=0x2A7E,
unicodeslot=0x2A7D,
},
@@ -67323,6 +67984,8 @@ characters.data={
description="GREATER-THAN OR SLANTED EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="geqslant",
mirror=0x2A7D,
unicodeslot=0x2A7E,
},
@@ -67379,6 +68042,8 @@ characters.data={
description="LESS-THAN OR APPROXIMATE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lessapprox",
unicodeslot=0x2A85,
},
[0x2A86]={
@@ -67386,6 +68051,8 @@ characters.data={
description="GREATER-THAN OR APPROXIMATE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gtrapprox",
unicodeslot=0x2A86,
},
[0x2A87]={
@@ -67393,6 +68060,8 @@ characters.data={
description="LESS-THAN AND SINGLE-LINE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lneq",
unicodeslot=0x2A87,
},
[0x2A88]={
@@ -67400,6 +68069,8 @@ characters.data={
description="GREATER-THAN AND SINGLE-LINE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="rneq",
unicodeslot=0x2A88,
},
[0x2A89]={
@@ -67407,6 +68078,8 @@ characters.data={
description="LESS-THAN AND NOT APPROXIMATE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lnapprox",
unicodeslot=0x2A89,
},
[0x2A8A]={
@@ -67414,6 +68087,8 @@ characters.data={
description="GREATER-THAN AND NOT APPROXIMATE",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gnapprox",
unicodeslot=0x2A8A,
},
[0x2A8B]={
@@ -67421,6 +68096,8 @@ characters.data={
description="LESS-THAN ABOVE DOUBLE-LINE EQUAL ABOVE GREATER-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="lesseqqgtr",
mirror=0x2A8C,
unicodeslot=0x2A8B,
},
@@ -67429,6 +68106,8 @@ characters.data={
description="GREATER-THAN ABOVE DOUBLE-LINE EQUAL ABOVE LESS-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="gtreqqless",
mirror=0x2A8B,
unicodeslot=0x2A8C,
},
@@ -67497,6 +68176,8 @@ characters.data={
description="SLANTED EQUAL TO OR LESS-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqslantless",
mirror=0x2A96,
unicodeslot=0x2A95,
},
@@ -67505,6 +68186,8 @@ characters.data={
description="SLANTED EQUAL TO OR GREATER-THAN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="eqslantgtr",
mirror=0x2A95,
unicodeslot=0x2A96,
},
@@ -67717,6 +68400,8 @@ characters.data={
description="PRECEDES ABOVE SINGLE-LINE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precneq",
unicodeslot=0x2AB1,
},
[0x2AB2]={
@@ -67724,6 +68409,8 @@ characters.data={
description="SUCCEEDS ABOVE SINGLE-LINE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succneq",
unicodeslot=0x2AB2,
},
[0x2AB3]={
@@ -67731,6 +68418,8 @@ characters.data={
description="PRECEDES ABOVE EQUALS SIGN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="preceqq",
mirror=0x2AB4,
unicodeslot=0x2AB3,
},
@@ -67739,6 +68428,8 @@ characters.data={
description="SUCCEEDS ABOVE EQUALS SIGN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succeqq",
mirror=0x2AB3,
unicodeslot=0x2AB4,
},
@@ -67747,6 +68438,8 @@ characters.data={
description="PRECEDES ABOVE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precneqq",
unicodeslot=0x2AB5,
},
[0x2AB6]={
@@ -67754,6 +68447,8 @@ characters.data={
description="SUCCEEDS ABOVE NOT EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succneqq",
unicodeslot=0x2AB6,
},
[0x2AB7]={
@@ -67761,6 +68456,8 @@ characters.data={
description="PRECEDES ABOVE ALMOST EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precapprox",
unicodeslot=0x2AB7,
},
[0x2AB8]={
@@ -67768,6 +68465,8 @@ characters.data={
description="SUCCEEDS ABOVE ALMOST EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succapprox",
unicodeslot=0x2AB8,
},
[0x2AB9]={
@@ -67775,6 +68474,8 @@ characters.data={
description="PRECEDES ABOVE NOT ALMOST EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="precnapprox",
unicodeslot=0x2AB9,
},
[0x2ABA]={
@@ -67782,6 +68483,8 @@ characters.data={
description="SUCCEEDS ABOVE NOT ALMOST EQUAL TO",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="succnapprox",
unicodeslot=0x2ABA,
},
[0x2ABB]={
@@ -67869,6 +68572,8 @@ characters.data={
description="SUBSET OF ABOVE EQUALS SIGN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="subseteqq",
mirror=0x2AC6,
unicodeslot=0x2AC5,
},
@@ -67877,6 +68582,8 @@ characters.data={
description="SUPERSET OF ABOVE EQUALS SIGN",
direction="on",
linebreak="al",
+ mathclass="relation",
+ mathname="supseteqq",
mirror=0x2AC5,
unicodeslot=0x2AC6,
},
@@ -67912,6 +68619,8 @@ characters.data={
category="sm",
description="SUBSET OF ABOVE NOT EQUAL TO",
direction="on",
+ mathclass="relation",
+ mathname="subsetneqq",
linebreak="al",
unicodeslot=0x2ACB,
},
@@ -67919,6 +68628,8 @@ characters.data={
category="sm",
description="SUPERSET OF ABOVE NOT EQUAL TO",
direction="on",
+ mathclass="relation",
+ mathname="supsetneqq",
linebreak="al",
unicodeslot=0x2ACC,
},
@@ -74873,6 +75584,8 @@ characters.data={
direction="on",
linebreak="op",
mirror=0x3015,
+ mathclass="open",
+ mathname="lgroup",
unicodeslot=0x3014,
},
[0x3015]={
@@ -74882,6 +75595,8 @@ characters.data={
direction="on",
linebreak="cl",
mirror=0x3014,
+ mathclass="close",
+ mathname="rgroup",
unicodeslot=0x3015,
},
[0x3016]={
@@ -83044,18 +83759,11 @@ characters.data={
[0x3400]={
category="lo",
cjkwd="w",
- description="<CJK Ideograph Extension A, First>",
+ description="<CJK Ideograph Extension A>",
direction="l",
linebreak="id",
unicodeslot=0x3400,
- },
- [0x4DB5]={
- category="lo",
- cjkwd="w",
- description="<CJK Ideograph Extension A, Last>",
- direction="l",
- linebreak="id",
- unicodeslot=0x4DB5,
+ range= 0x4DB5,
},
[0x4DC0]={
category="so",
@@ -83508,17 +84216,11 @@ characters.data={
[0x4E00]={
category="lo",
cjkwd="w",
- description="<CJK Ideograph, First>",
+ description="<CJK Ideograph>",
direction="l",
linebreak="id",
unicodeslot=0x4E00,
- },
- [0x9FBB]={
- category="lo",
- cjkwd="w",
- description="<CJK Ideograph, Last>",
- linebreak="id",
- unicodeslot=0x9FBB,
+ range=0x9FBB,
},
[0xA000]={
category="lo",
@@ -94186,18 +94888,11 @@ characters.data={
[0xAC00]={
category="lo",
cjkwd="w",
- description="<Hangul Syllable, First>",
+ description="<Hangul Syllable>",
direction="l",
linebreak="h2",
unicodeslot=0xAC00,
- },
- [0xD7A3]={
- category="lo",
- cjkwd="w",
- description="<Hangul Syllable, Last>",
- direction="l",
- linebreak="h3",
- unicodeslot=0xD7A3,
+ range=0xD7A3,
},
[0xD800]={
category="cs",
@@ -104026,7 +104721,7 @@ characters.data={
description="PRESENTATION FORM FOR VERTICAL LEFT CURLY BRACKET",
direction="on",
linebreak="op",
- mathfiller="downbracefill",
+ mathfiller="downbracefill", -- funny, chinese, no math, wrong but for the moment we need it for buggy mathml
specials={ "vertical", 0x007B },
unicodeslot=0xFE37,
},
@@ -104036,7 +104731,7 @@ characters.data={
description="PRESENTATION FORM FOR VERTICAL RIGHT CURLY BRACKET",
direction="on",
linebreak="cl",
- mathfiller="upbracefill",
+ mathfiller="upbracefill", -- funny, chinese, no math, wrong but for the moment we need it for buggy mathml
specials={ "vertical", 0x007D },
unicodeslot=0xFE38,
},
@@ -113814,6 +114509,8 @@ characters.data={
description="CUNEIFORM SIGN ARAD TIMES KUR",
direction="l",
linebreak="al",
+ mathclass="ord",
+ mathname="backprime",
unicodeslot=0x12035,
},
[0x12036]={
@@ -130026,7 +130723,7 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL DOTLESS I",
direction="l",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="imath",
specials={ "font", 0x0131 },
unicodeslot=0x1D6A4,
@@ -130036,7 +130733,7 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL DOTLESS J",
direction="l",
linebreak="al",
- mathclass="variable",
+ mathclass="default",
mathname="jmath",
specials={ "font", 0x0237 },
unicodeslot=0x1D6A5,
@@ -130510,6 +131207,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL ALPHA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Alpha",
specials={ "font", 0x0391 },
unicodeslot=0x1D6E2,
},
@@ -130518,6 +131217,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL BETA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Beta",
specials={ "font", 0x0392 },
unicodeslot=0x1D6E3,
},
@@ -130526,6 +131227,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL GAMMA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Gamma",
specials={ "font", 0x0393 },
unicodeslot=0x1D6E4,
},
@@ -130534,6 +131237,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL DELTA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Delta",
specials={ "font", 0x0394 },
unicodeslot=0x1D6E5,
},
@@ -130542,6 +131247,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL EPSILON",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Epsilon",
specials={ "font", 0x0395 },
unicodeslot=0x1D6E6,
},
@@ -130550,6 +131257,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL ZETA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Zeta",
specials={ "font", 0x0396 },
unicodeslot=0x1D6E7,
},
@@ -130558,6 +131267,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL ETA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Eta",
specials={ "font", 0x0397 },
unicodeslot=0x1D6E8,
},
@@ -130566,6 +131277,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL THETA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Theta",
specials={ "font", 0x0398 },
unicodeslot=0x1D6E9,
},
@@ -130574,6 +131287,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL IOTA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Iota",
specials={ "font", 0x0399 },
unicodeslot=0x1D6EA,
},
@@ -130582,6 +131297,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL KAPPA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Kappa",
specials={ "font", 0x039A },
unicodeslot=0x1D6EB,
},
@@ -130590,6 +131307,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL LAMDA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Lambda",
specials={ "font", 0x039B },
unicodeslot=0x1D6EC,
},
@@ -130598,6 +131317,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL MU",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Mu",
specials={ "font", 0x039C },
unicodeslot=0x1D6ED,
},
@@ -130606,6 +131327,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL NU",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Nu",
specials={ "font", 0x039D },
unicodeslot=0x1D6EE,
},
@@ -130614,6 +131337,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL XI",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Xi",
specials={ "font", 0x039E },
unicodeslot=0x1D6EF,
},
@@ -130622,6 +131347,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL OMICRON",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Omicron",
specials={ "font", 0x039F },
unicodeslot=0x1D6F0,
},
@@ -130630,6 +131357,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL PI",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Pi",
specials={ "font", 0x03A0 },
unicodeslot=0x1D6F1,
},
@@ -130638,6 +131367,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL RHO",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Rho",
specials={ "font", 0x03A1 },
unicodeslot=0x1D6F2,
},
@@ -130646,6 +131377,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL THETA SYMBOL",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="varTheta",
specials={ "font", 0x03F4 },
unicodeslot=0x1D6F3,
},
@@ -130654,6 +131387,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL SIGMA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Sigma",
specials={ "font", 0x03A3 },
unicodeslot=0x1D6F4,
},
@@ -130662,6 +131397,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL TAU",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Tau",
specials={ "font", 0x03A4 },
unicodeslot=0x1D6F5,
},
@@ -130670,6 +131407,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL UPSILON",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Upsilon",
specials={ "font", 0x03A5 },
unicodeslot=0x1D6F6,
},
@@ -130678,6 +131417,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL PHI",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Phi",
specials={ "font", 0x03A6 },
unicodeslot=0x1D6F7,
},
@@ -130686,6 +131427,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL CHI",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Chi",
specials={ "font", 0x03A7 },
unicodeslot=0x1D6F8,
},
@@ -130694,6 +131437,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL PSI",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Psi",
specials={ "font", 0x03A8 },
unicodeslot=0x1D6F9,
},
@@ -130702,6 +131447,8 @@ characters.data={
description="MATHEMATICAL ITALIC CAPITAL OMEGA",
direction="l",
linebreak="al",
+ mathclass="variable",
+ mathname="Omega",
specials={ "font", 0x03A9 },
unicodeslot=0x1D6FA,
},
@@ -130710,6 +131457,8 @@ characters.data={
description="MATHEMATICAL ITALIC NABLA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="nabla",
specials={ "font", 0x2207 },
unicodeslot=0x1D6FB,
},
@@ -130718,6 +131467,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL ALPHA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="alpha",
specials={ "font", 0x03B1 },
unicodeslot=0x1D6FC,
},
@@ -130726,6 +131477,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL BETA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="beta",
specials={ "font", 0x03B2 },
unicodeslot=0x1D6FD,
},
@@ -130734,6 +131487,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL GAMMA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="gamma",
specials={ "font", 0x03B3 },
unicodeslot=0x1D6FE,
},
@@ -130742,6 +131497,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL DELTA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="delta",
specials={ "font", 0x03B4 },
unicodeslot=0x1D6FF,
},
@@ -130750,6 +131507,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL EPSILON",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varepsilon",
specials={ "font", 0x03B5 },
unicodeslot=0x1D700,
},
@@ -130758,6 +131517,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL ZETA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="zeta",
specials={ "font", 0x03B6 },
unicodeslot=0x1D701,
},
@@ -130766,6 +131527,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL ETA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="eta",
specials={ "font", 0x03B7 },
unicodeslot=0x1D702,
},
@@ -130774,6 +131537,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL THETA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="theta",
specials={ "font", 0x03B8 },
unicodeslot=0x1D703,
},
@@ -130782,6 +131547,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL IOTA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="iota",
specials={ "font", 0x03B9 },
unicodeslot=0x1D704,
},
@@ -130790,6 +131557,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL KAPPA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="kappa",
specials={ "font", 0x03BA },
unicodeslot=0x1D705,
},
@@ -130798,6 +131567,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL LAMDA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="lambda",
specials={ "font", 0x03BB },
unicodeslot=0x1D706,
},
@@ -130806,6 +131577,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL MU",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="mu",
specials={ "font", 0x03BC },
unicodeslot=0x1D707,
},
@@ -130814,6 +131587,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL NU",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="nu",
specials={ "font", 0x03BD },
unicodeslot=0x1D708,
},
@@ -130822,6 +131597,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL XI",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="xi",
specials={ "font", 0x03BE },
unicodeslot=0x1D709,
},
@@ -130830,6 +131607,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL OMICRON",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="omicron",
specials={ "font", 0x03BF },
unicodeslot=0x1D70A,
},
@@ -130838,6 +131617,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL PI",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="pi",
specials={ "font", 0x03C0 },
unicodeslot=0x1D70B,
},
@@ -130846,6 +131627,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL RHO",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="rho",
specials={ "font", 0x03C1 },
unicodeslot=0x1D70C,
},
@@ -130854,6 +131637,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL FINAL SIGMA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varsigma",
specials={ "font", 0x03C2 },
unicodeslot=0x1D70D,
},
@@ -130862,6 +131647,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL SIGMA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="sigma",
specials={ "font", 0x03C3 },
unicodeslot=0x1D70E,
},
@@ -130870,6 +131657,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL TAU",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="tau",
specials={ "font", 0x03C4 },
unicodeslot=0x1D70F,
},
@@ -130878,6 +131667,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL UPSILON",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="upsilon",
specials={ "font", 0x03C5 },
unicodeslot=0x1D710,
},
@@ -130886,6 +131677,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL PHI",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varphi",
specials={ "font", 0x03C6 },
unicodeslot=0x1D711,
},
@@ -130894,6 +131687,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL CHI",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="chi",
specials={ "font", 0x03C7 },
unicodeslot=0x1D712,
},
@@ -130902,6 +131697,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL PSI",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="psi",
specials={ "font", 0x03C8 },
unicodeslot=0x1D713,
},
@@ -130910,6 +131707,8 @@ characters.data={
description="MATHEMATICAL ITALIC SMALL OMEGA",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="omega",
specials={ "font", 0x03C9 },
unicodeslot=0x1D714,
},
@@ -130926,6 +131725,8 @@ characters.data={
description="MATHEMATICAL ITALIC EPSILON SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="epsilon",
specials={ "font", 0x03F5 },
unicodeslot=0x1D716,
},
@@ -130934,6 +131735,8 @@ characters.data={
description="MATHEMATICAL ITALIC THETA SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="vartheta",
specials={ "font", 0x03D1 },
unicodeslot=0x1D717,
},
@@ -130942,6 +131745,8 @@ characters.data={
description="MATHEMATICAL ITALIC KAPPA SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varkappa",
specials={ "font", 0x03F0 },
unicodeslot=0x1D718,
},
@@ -130950,6 +131755,8 @@ characters.data={
description="MATHEMATICAL ITALIC PHI SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="phi",
specials={ "font", 0x03D5 },
unicodeslot=0x1D719,
},
@@ -130958,6 +131765,8 @@ characters.data={
description="MATHEMATICAL ITALIC RHO SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varrho",
specials={ "font", 0x03F1 },
unicodeslot=0x1D71A,
},
@@ -130966,6 +131775,8 @@ characters.data={
description="MATHEMATICAL ITALIC PI SYMBOL",
direction="l",
linebreak="al",
+ mathclass="default",
+ mathname="varpi",
specials={ "font", 0x03D6 },
unicodeslot=0x1D71B,
},
@@ -132780,18 +133591,11 @@ characters.data={
[0x20000]={
category="lo",
cjkwd="w",
- description="<CJK Ideograph Extension B, First>",
+ description="<CJK Ideograph Extension B>",
direction="l",
linebreak="id",
unicodeslot=0x20000,
- },
- [0x2A6D6]={
- category="lo",
- cjkwd="w",
- description="<CJK Ideograph Extension B, Last>",
- direction="l",
- linebreak="id",
- unicodeslot=0x2A6D6,
+ range=0x2A6D6,
},
[0x2F800]={
category="lo",
diff --git a/tex/context/base/char-syn.lua b/tex/context/base/char-enc.lua
index a779e1a58..a4e5ac77d 100644
--- a/tex/context/base/char-syn.lua
+++ b/tex/context/base/char-enc.lua
@@ -8,6 +8,8 @@ if not modules then modules = { } end modules ['char-syn'] = {
-- thanks to tex4ht for these mappings
+characters = characters or { }
+
characters.synonyms = {
angle = 0x2220,
anticlockwise = 0x21BA,
@@ -138,3 +140,24 @@ characters.synonyms = {
uprise = 0x22CF,
Yen = 0x00A5,
}
+
+if not characters.enccodes then
+
+ local enccodes = { }
+
+ for unicode, data in next, characters.data do
+ local encname = data.adobename or data.contextname
+ if encname then
+ enccodes[encname] = unicode
+ end
+ end
+
+ for name, unicode in next, characters.synonyms do
+ if not enccodes[name] then enccodes[name] = unicode end
+ end
+
+ characters.enccodes = enccodes
+
+end
+
+storage.register("characters.enccodes", characters.enccodes, "characters.enccodes")
diff --git a/tex/context/base/char-enc.tex b/tex/context/base/char-enc.tex
new file mode 100644
index 000000000..9fe9a363b
--- /dev/null
+++ b/tex/context/base/char-enc.tex
@@ -0,0 +1,18 @@
+%D \module
+%D [ file=char-enc,
+%D version=2006.08.20,
+%D title=\CONTEXT\ Character Support,
+%D subtitle=Encodings,
+%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.
+
+\writestatus{loading}{ConTeXt Character Support / Encodings}
+
+\registerctxluafile{char-enc}{1.001}
+
+\endinput
diff --git a/tex/context/base/char-ini.lua b/tex/context/base/char-ini.lua
index 0dd7a266a..974366b7a 100644
--- a/tex/context/base/char-ini.lua
+++ b/tex/context/base/char-ini.lua
@@ -9,202 +9,238 @@ if not modules then modules = { } end modules ['char-ini'] = {
tex = tex or { }
xml = xml or { }
-local format, texsprint, utfchar, utfbyte, concat = string.format, tex.sprint, unicode.utf8.char, unicode.utf8.byte, table.concat
+local utf = unicode.utf8
+
+local utfchar, utfbyte = utf.char, utf.byte
+local concat = table.concat
+local next, tonumber = next, tonumber
+local texsprint, texprint = tex.sprint, tex.print
+local format, lower, gsub, match, gmatch = string.format, string.lower, string.gsub, string.match, string.match, string.gmatch
+
+local ctxcatcodes = tex.ctxcatcodes
+local texcatcodes = tex.texcatcodes
--[[ldx--
<p>This module implements some methods and creates additional datastructured
from the big character table that we use for all kind of purposes:
<type>char-def.lua</type>.</p>
+
+<p>We assume that at this point <type>characters.data</type> is already
+loaded!</p>
--ldx]]--
-characters = characters or { }
-characters.data = characters.data or { }
-characters.synonyms = characters.synonyms or { }
-characters.context = characters.context or { }
-
-characters.blocks={
- ["aegeannumbers"] = { 0x10100, 0x1013F, "Aegean Numbers" },
- ["alphabeticpresentationforms"] = { 0xFB00, 0xFB4F, "Alphabetic Presentation Forms" },
- ["ancientgreekmusicalnotation"] = { 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" },
- ["ancientgreeknumbers"] = { 0x10140, 0x1018F, "Ancient Greek Numbers" },
- ["ancientsymbols"] = { 0x10190, 0x101CF, "Ancient Symbols" },
- ["arabic"] = { 0x0600, 0x06FF, "Arabic" },
- ["arabicpresentationformsa"] = { 0xFB50, 0xFDFF, "Arabic Presentation Forms-A" },
- ["arabicpresentationformsb"] = { 0xFE70, 0xFEFF, "Arabic Presentation Forms-B" },
- ["arabicsupplement"] = { 0x0750, 0x077F, "Arabic Supplement" },
- ["armenian"] = { 0x0530, 0x058F, "Armenian" },
- ["arrows"] = { 0x2190, 0x21FF, "Arrows" },
- ["balinese"] = { 0x1B00, 0x1B7F, "Balinese" },
- ["basiclatin"] = { 0x0000, 0x007F, "Basic Latin" },
- ["bengali"] = { 0x0980, 0x09FF, "Bengali" },
- ["blockelements"] = { 0x2580, 0x259F, "Block Elements" },
- ["bopomofo"] = { 0x3100, 0x312F, "Bopomofo" },
- ["bopomofoextended"] = { 0x31A0, 0x31BF, "Bopomofo Extended" },
- ["boxdrawing"] = { 0x2500, 0x257F, "Box Drawing" },
- ["braillepatterns"] = { 0x2800, 0x28FF, "Braille Patterns" },
- ["buginese"] = { 0x1A00, 0x1A1F, "Buginese" },
- ["buhid"] = { 0x1740, 0x175F, "Buhid" },
- ["byzantinemusicalsymbols"] = { 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" },
- ["carian"] = { 0x102A0, 0x102DF, "Carian" },
- ["cham"] = { 0xAA00, 0xAA5F, "Cham" },
- ["cherokee"] = { 0x13A0, 0x13FF, "Cherokee" },
- ["cjkcompatibility"] = { 0x3300, 0x33FF, "CJK Compatibility" },
- ["cjkcompatibilityforms"] = { 0xFE30, 0xFE4F, "CJK Compatibility Forms" },
- ["cjkcompatibilityideographs"] = { 0xF900, 0xFAFF, "CJK Compatibility Ideographs" },
+characters = characters or { }
+characters.data = characters.data or { }
+
+local data = characters.data
+
+if not characters.ranges then
+ characters.ranges = { }
+ for k, v in next, data do
+ characters.ranges[#characters.ranges+1] = k
+ end
+end
+
+storage.register("characters/ranges",characters.ranges,"characters.ranges")
+
+local ranges = characters.ranges
+
+setmetatable(data, {
+ __index = function(t,k)
+ for r=1,#ranges do
+ local rr = ranges[r] -- first in range
+ if k > rr and k <= data[rr].range then
+ t[k] = t[rr]
+ return t[k]
+ end
+ end
+ return nil
+ end
+})
+
+characters.blocks = {
+ ["aegeannumbers"] = { 0x10100, 0x1013F, "Aegean Numbers" },
+ ["alphabeticpresentationforms"] = { 0x0FB00, 0x0FB4F, "Alphabetic Presentation Forms" },
+ ["ancientgreekmusicalnotation"] = { 0x1D200, 0x1D24F, "Ancient Greek Musical Notation" },
+ ["ancientgreeknumbers"] = { 0x10140, 0x1018F, "Ancient Greek Numbers" },
+ ["ancientsymbols"] = { 0x10190, 0x101CF, "Ancient Symbols" },
+ ["arabic"] = { 0x00600, 0x006FF, "Arabic" },
+ ["arabicpresentationformsa"] = { 0x0FB50, 0x0FDFF, "Arabic Presentation Forms-A" },
+ ["arabicpresentationformsb"] = { 0x0FE70, 0x0FEFF, "Arabic Presentation Forms-B" },
+ ["arabicsupplement"] = { 0x00750, 0x0077F, "Arabic Supplement" },
+ ["armenian"] = { 0x00530, 0x0058F, "Armenian" },
+ ["arrows"] = { 0x02190, 0x021FF, "Arrows" },
+ ["balinese"] = { 0x01B00, 0x01B7F, "Balinese" },
+ ["basiclatin"] = { 0x00000, 0x0007F, "Basic Latin" },
+ ["bengali"] = { 0x00980, 0x009FF, "Bengali" },
+ ["blockelements"] = { 0x02580, 0x0259F, "Block Elements" },
+ ["bopomofo"] = { 0x03100, 0x0312F, "Bopomofo" },
+ ["bopomofoextended"] = { 0x031A0, 0x031BF, "Bopomofo Extended" },
+ ["boxdrawing"] = { 0x02500, 0x0257F, "Box Drawing" },
+ ["braillepatterns"] = { 0x02800, 0x028FF, "Braille Patterns" },
+ ["buginese"] = { 0x01A00, 0x01A1F, "Buginese" },
+ ["buhid"] = { 0x01740, 0x0175F, "Buhid" },
+ ["byzantinemusicalsymbols"] = { 0x1D000, 0x1D0FF, "Byzantine Musical Symbols" },
+ ["carian"] = { 0x102A0, 0x102DF, "Carian" },
+ ["cham"] = { 0x0AA00, 0x0AA5F, "Cham" },
+ ["cherokee"] = { 0x013A0, 0x013FF, "Cherokee" },
+ ["cjkcompatibility"] = { 0x03300, 0x033FF, "CJK Compatibility" },
+ ["cjkcompatibilityforms"] = { 0x0FE30, 0x0FE4F, "CJK Compatibility Forms" },
+ ["cjkcompatibilityideographs"] = { 0x0F900, 0x0FAFF, "CJK Compatibility Ideographs" },
["cjkcompatibilityideographssupplement"] = { 0x2F800, 0x2FA1F, "CJK Compatibility Ideographs Supplement" },
- ["cjkradicalssupplement"] = { 0x2E80, 0x2EFF, "CJK Radicals Supplement" },
- ["cjkstrokes"] = { 0x31C0, 0x31EF, "CJK Strokes" },
- ["cjksymbolsandpunctuation"] = { 0x3000, 0x303F, "CJK Symbols and Punctuation" },
- ["cjkunifiedideographs"] = { 0x4E00, 0x9FFF, "CJK Unified Ideographs" },
- ["cjkunifiedideographsextensiona"] = { 0x3400, 0x4DBF, "CJK Unified Ideographs Extension A" },
- ["cjkunifiedideographsextensionb"] = { 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" },
- ["combiningdiacriticalmarks"] = { 0x0300, 0x036F, "Combining Diacritical Marks" },
- ["combiningdiacriticalmarksforsymbols"] = { 0x20D0, 0x20FF, "Combining Diacritical Marks for Symbols" },
- ["combiningdiacriticalmarkssupplement"] = { 0x1DC0, 0x1DFF, "Combining Diacritical Marks Supplement" },
- ["combininghalfmarks"] = { 0xFE20, 0xFE2F, "Combining Half Marks" },
- ["controlpictures"] = { 0x2400, 0x243F, "Control Pictures" },
- ["coptic"] = { 0x2C80, 0x2CFF, "Coptic" },
- ["countingrodnumerals"] = { 0x1D360, 0x1D37F, "Counting Rod Numerals" },
- ["cuneiform"] = { 0x12000, 0x123FF, "Cuneiform" },
- ["cuneiformnumbersandpunctuation"] = { 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
- ["currencysymbols"] = { 0x20A0, 0x20CF, "Currency Symbols" },
- ["cypriotsyllabary"] = { 0x10800, 0x1083F, "Cypriot Syllabary" },
- ["cyrillic"] = { 0x0400, 0x04FF, "Cyrillic" },
- ["cyrillicextendeda"] = { 0x2DE0, 0x2DFF, "Cyrillic Extended-A" },
- ["cyrillicextendedb"] = { 0xA640, 0xA69F, "Cyrillic Extended-B" },
- ["cyrillicsupplement"] = { 0x0500, 0x052F, "Cyrillic Supplement" },
- ["deseret"] = { 0x10400, 0x1044F, "Deseret" },
- ["devanagari"] = { 0x0900, 0x097F, "Devanagari" },
- ["dingbats"] = { 0x2700, 0x27BF, "Dingbats" },
- ["dominotiles"] = { 0x1F030, 0x1F09F, "Domino Tiles" },
- ["enclosedalphanumerics"] = { 0x2460, 0x24FF, "Enclosed Alphanumerics" },
- ["enclosedcjklettersandmonths"] = { 0x3200, 0x32FF, "Enclosed CJK Letters and Months" },
- ["ethiopic"] = { 0x1200, 0x137F, "Ethiopic" },
- ["ethiopicextended"] = { 0x2D80, 0x2DDF, "Ethiopic Extended" },
- ["ethiopicsupplement"] = { 0x1380, 0x139F, "Ethiopic Supplement" },
- ["generalpunctuation"] = { 0x2000, 0x206F, "General Punctuation" },
- ["geometricshapes"] = { 0x25A0, 0x25FF, "Geometric Shapes" },
- ["georgian"] = { 0x10A0, 0x10FF, "Georgian" },
- ["georgiansupplement"] = { 0x2D00, 0x2D2F, "Georgian Supplement" },
- ["glagolitic"] = { 0x2C00, 0x2C5F, "Glagolitic" },
- ["gothic"] = { 0x10330, 0x1034F, "Gothic" },
- ["greekandcoptic"] = { 0x0370, 0x03FF, "Greek and Coptic" },
- ["greekextended"] = { 0x1F00, 0x1FFF, "Greek Extended" },
- ["gujarati"] = { 0x0A80, 0x0AFF, "Gujarati" },
- ["gurmukhi"] = { 0x0A00, 0x0A7F, "Gurmukhi" },
- ["halfwidthandfullwidthforms"] = { 0xFF00, 0xFFEF, "Halfwidth and Fullwidth Forms" },
- ["hangulcompatibilityjamo"] = { 0x3130, 0x318F, "Hangul Compatibility Jamo" },
- ["hanguljamo"] = { 0x1100, 0x11FF, "Hangul Jamo" },
- ["hangulsyllables"] = { 0xAC00, 0xD7AF, "Hangul Syllables" },
- ["hanunoo"] = { 0x1720, 0x173F, "Hanunoo" },
- ["hebrew"] = { 0x0590, 0x05FF, "Hebrew" },
- ["highprivateusesurrogates"] = { 0xDB80, 0xDBFF, "High Private Use Surrogates" },
- ["highsurrogates"] = { 0xD800, 0xDB7F, "High Surrogates" },
- ["hiragana"] = { 0x3040, 0x309F, "Hiragana" },
- ["ideographicdescriptioncharacters"] = { 0x2FF0, 0x2FFF, "Ideographic Description Characters" },
- ["ipaextensions"] = { 0x0250, 0x02AF, "IPA Extensions" },
- ["kanbun"] = { 0x3190, 0x319F, "Kanbun" },
- ["kangxiradicals"] = { 0x2F00, 0x2FDF, "Kangxi Radicals" },
- ["kannada"] = { 0x0C80, 0x0CFF, "Kannada" },
- ["katakana"] = { 0x30A0, 0x30FF, "Katakana" },
- ["katakanaphoneticextensions"] = { 0x31F0, 0x31FF, "Katakana Phonetic Extensions" },
- ["kayahli"] = { 0xA900, 0xA92F, "Kayah Li" },
- ["kharoshthi"] = { 0x10A00, 0x10A5F, "Kharoshthi" },
- ["khmer"] = { 0x1780, 0x17FF, "Khmer" },
- ["khmersymbols"] = { 0x19E0, 0x19FF, "Khmer Symbols" },
- ["lao"] = { 0x0E80, 0x0EFF, "Lao" },
- ["latinextendeda"] = { 0x0100, 0x017F, "Latin Extended-A" },
- ["latinextendedadditional"] = { 0x1E00, 0x1EFF, "Latin Extended Additional" },
- ["latinextendedb"] = { 0x0180, 0x024F, "Latin Extended-B" },
- ["latinextendedc"] = { 0x2C60, 0x2C7F, "Latin Extended-C" },
- ["latinextendedd"] = { 0xA720, 0xA7FF, "Latin Extended-D" },
- ["latinsupplement"] = { 0x0080, 0x00FF, "Latin-1 Supplement" },
- ["lepcha"] = { 0x1C00, 0x1C4F, "Lepcha" },
- ["letterlikesymbols"] = { 0x2100, 0x214F, "Letterlike Symbols" },
- ["limbu"] = { 0x1900, 0x194F, "Limbu" },
- ["linearbideograms"] = { 0x10080, 0x100FF, "Linear B Ideograms" },
- ["linearbsyllabary"] = { 0x10000, 0x1007F, "Linear B Syllabary" },
- ["lowsurrogates"] = { 0xDC00, 0xDFFF, "Low Surrogates" },
- ["lycian"] = { 0x10280, 0x1029F, "Lycian" },
- ["lydian"] = { 0x10920, 0x1093F, "Lydian" },
- ["mahjongtiles"] = { 0x1F000, 0x1F02F, "Mahjong Tiles" },
- ["malayalam"] = { 0x0D00, 0x0D7F, "Malayalam" },
- ["mathematicalalphanumericsymbols"] = { 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" },
- ["mathematicaloperators"] = { 0x2200, 0x22FF, "Mathematical Operators" },
- ["miscellaneousmathematicalsymbolsa"] = { 0x27C0, 0x27EF, "Miscellaneous Mathematical Symbols-A" },
- ["miscellaneousmathematicalsymbolsb"] = { 0x2980, 0x29FF, "Miscellaneous Mathematical Symbols-B" },
- ["miscellaneoussymbols"] = { 0x2600, 0x26FF, "Miscellaneous Symbols" },
- ["miscellaneoussymbolsandarrows"] = { 0x2B00, 0x2BFF, "Miscellaneous Symbols and Arrows" },
- ["miscellaneoustechnical"] = { 0x2300, 0x23FF, "Miscellaneous Technical" },
- ["modifiertoneletters"] = { 0xA700, 0xA71F, "Modifier Tone Letters" },
- ["mongolian"] = { 0x1800, 0x18AF, "Mongolian" },
- ["musicalsymbols"] = { 0x1D100, 0x1D1FF, "Musical Symbols" },
- ["myanmar"] = { 0x1000, 0x109F, "Myanmar" },
- ["newtailue"] = { 0x1980, 0x19DF, "New Tai Lue" },
- ["nko"] = { 0x07C0, 0x07FF, "NKo" },
- ["numberforms"] = { 0x2150, 0x218F, "Number Forms" },
- ["ogham"] = { 0x1680, 0x169F, "Ogham" },
- ["olchiki"] = { 0x1C50, 0x1C7F, "Ol Chiki" },
- ["olditalic"] = { 0x10300, 0x1032F, "Old Italic" },
- ["oldpersian"] = { 0x103A0, 0x103DF, "Old Persian" },
- ["opticalcharacterrecognition"] = { 0x2440, 0x245F, "Optical Character Recognition" },
- ["oriya"] = { 0x0B00, 0x0B7F, "Oriya" },
- ["osmanya"] = { 0x10480, 0x104AF, "Osmanya" },
- ["phagspa"] = { 0xA840, 0xA87F, "Phags-pa" },
- ["phaistosdisc"] = { 0x101D0, 0x101FF, "Phaistos Disc" },
- ["phoenician"] = { 0x10900, 0x1091F, "Phoenician" },
- ["phoneticextensions"] = { 0x1D00, 0x1D7F, "Phonetic Extensions" },
- ["phoneticextensionssupplement"] = { 0x1D80, 0x1DBF, "Phonetic Extensions Supplement" },
- ["privateusearea"] = { 0xE000, 0xF8FF, "Private Use Area" },
- ["rejang"] = { 0xA930, 0xA95F, "Rejang" },
- ["runic"] = { 0x16A0, 0x16FF, "Runic" },
- ["saurashtra"] = { 0xA880, 0xA8DF, "Saurashtra" },
- ["shavian"] = { 0x10450, 0x1047F, "Shavian" },
- ["sinhala"] = { 0x0D80, 0x0DFF, "Sinhala" },
- ["smallformvariants"] = { 0xFE50, 0xFE6F, "Small Form Variants" },
- ["spacingmodifierletters"] = { 0x02B0, 0x02FF, "Spacing Modifier Letters" },
- ["specials"] = { 0xFFF0, 0xFFFF, "Specials" },
- ["sundanese"] = { 0x1B80, 0x1BBF, "Sundanese" },
- ["superscriptsandsubscripts"] = { 0x2070, 0x209F, "Superscripts and Subscripts" },
- ["supplementalarrowsa"] = { 0x27F0, 0x27FF, "Supplemental Arrows-A" },
- ["supplementalarrowsb"] = { 0x2900, 0x297F, "Supplemental Arrows-B" },
- ["supplementalmathematicaloperators"] = { 0x2A00, 0x2AFF, "Supplemental Mathematical Operators" },
- ["supplementalpunctuation"] = { 0x2E00, 0x2E7F, "Supplemental Punctuation" },
- ["supplementaryprivateuseareaa"] = { 0xF0000, 0xFFFFF, "Supplementary Private Use Area-A" },
- ["supplementaryprivateuseareab"] = { 0x100000, 0x10FFFF, "Supplementary Private Use Area-B" },
- ["sylotinagri"] = { 0xA800, 0xA82F, "Syloti Nagri" },
- ["syriac"] = { 0x0700, 0x074F, "Syriac" },
- ["tagalog"] = { 0x1700, 0x171F, "Tagalog" },
- ["tagbanwa"] = { 0x1760, 0x177F, "Tagbanwa" },
- ["tags"] = { 0xE0000, 0xE007F, "Tags" },
- ["taile"] = { 0x1950, 0x197F, "Tai Le" },
- ["taixuanjingsymbols"] = { 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
- ["tamil"] = { 0x0B80, 0x0BFF, "Tamil" },
- ["telugu"] = { 0x0C00, 0x0C7F, "Telugu" },
- ["thaana"] = { 0x0780, 0x07BF, "Thaana" },
- ["thai"] = { 0x0E00, 0x0E7F, "Thai" },
- ["tibetan"] = { 0x0F00, 0x0FFF, "Tibetan" },
- ["tifinagh"] = { 0x2D30, 0x2D7F, "Tifinagh" },
- ["ugaritic"] = { 0x10380, 0x1039F, "Ugaritic" },
- ["unifiedcanadianaboriginalsyllabics"] = { 0x1400, 0x167F, "Unified Canadian Aboriginal Syllabics" },
- ["vai"] = { 0xA500, 0xA63F, "Vai" },
- ["variationselectors"] = { 0xFE00, 0xFE0F, "Variation Selectors" },
- ["variationselectorssupplement"] = { 0xE0100, 0xE01EF, "Variation Selectors Supplement" },
- ["verticalforms"] = { 0xFE10, 0xFE1F, "Vertical Forms" },
- ["yijinghexagramsymbols"] = { 0x4DC0, 0x4DFF, "Yijing Hexagram Symbols" },
- ["yiradicals"] = { 0xA490, 0xA4CF, "Yi Radicals" },
- ["yisyllables"] = { 0xA000, 0xA48F, "Yi Syllables" },
+ ["cjkradicalssupplement"] = { 0x02E80, 0x02EFF, "CJK Radicals Supplement" },
+ ["cjkstrokes"] = { 0x031C0, 0x031EF, "CJK Strokes" },
+ ["cjksymbolsandpunctuation"] = { 0x03000, 0x0303F, "CJK Symbols and Punctuation" },
+ ["cjkunifiedideographs"] = { 0x04E00, 0x09FFF, "CJK Unified Ideographs" },
+ ["cjkunifiedideographsextensiona"] = { 0x03400, 0x04DBF, "CJK Unified Ideographs Extension A" },
+ ["cjkunifiedideographsextensionb"] = { 0x20000, 0x2A6DF, "CJK Unified Ideographs Extension B" },
+ ["combiningdiacriticalmarks"] = { 0x00300, 0x0036F, "Combining Diacritical Marks" },
+ ["combiningdiacriticalmarksforsymbols"] = { 0x020D0, 0x020FF, "Combining Diacritical Marks for Symbols" },
+ ["combiningdiacriticalmarkssupplement"] = { 0x01DC0, 0x01DFF, "Combining Diacritical Marks Supplement" },
+ ["combininghalfmarks"] = { 0x0FE20, 0x0FE2F, "Combining Half Marks" },
+ ["controlpictures"] = { 0x02400, 0x0243F, "Control Pictures" },
+ ["coptic"] = { 0x02C80, 0x02CFF, "Coptic" },
+ ["countingrodnumerals"] = { 0x1D360, 0x1D37F, "Counting Rod Numerals" },
+ ["cuneiform"] = { 0x12000, 0x123FF, "Cuneiform" },
+ ["cuneiformnumbersandpunctuation"] = { 0x12400, 0x1247F, "Cuneiform Numbers and Punctuation" },
+ ["currencysymbols"] = { 0x020A0, 0x020CF, "Currency Symbols" },
+ ["cypriotsyllabary"] = { 0x10800, 0x1083F, "Cypriot Syllabary" },
+ ["cyrillic"] = { 0x00400, 0x004FF, "Cyrillic" },
+ ["cyrillicextendeda"] = { 0x02DE0, 0x02DFF, "Cyrillic Extended-A" },
+ ["cyrillicextendedb"] = { 0x0A640, 0x0A69F, "Cyrillic Extended-B" },
+ ["cyrillicsupplement"] = { 0x00500, 0x0052F, "Cyrillic Supplement" },
+ ["deseret"] = { 0x10400, 0x1044F, "Deseret" },
+ ["devanagari"] = { 0x00900, 0x0097F, "Devanagari" },
+ ["dingbats"] = { 0x02700, 0x027BF, "Dingbats" },
+ ["dominotiles"] = { 0x1F030, 0x1F09F, "Domino Tiles" },
+ ["enclosedalphanumerics"] = { 0x02460, 0x024FF, "Enclosed Alphanumerics" },
+ ["enclosedcjklettersandmonths"] = { 0x03200, 0x032FF, "Enclosed CJK Letters and Months" },
+ ["ethiopic"] = { 0x01200, 0x0137F, "Ethiopic" },
+ ["ethiopicextended"] = { 0x02D80, 0x02DDF, "Ethiopic Extended" },
+ ["ethiopicsupplement"] = { 0x01380, 0x0139F, "Ethiopic Supplement" },
+ ["generalpunctuation"] = { 0x02000, 0x0206F, "General Punctuation" },
+ ["geometricshapes"] = { 0x025A0, 0x025FF, "Geometric Shapes" },
+ ["georgian"] = { 0x010A0, 0x010FF, "Georgian" },
+ ["georgiansupplement"] = { 0x02D00, 0x02D2F, "Georgian Supplement" },
+ ["glagolitic"] = { 0x02C00, 0x02C5F, "Glagolitic" },
+ ["gothic"] = { 0x10330, 0x1034F, "Gothic" },
+ ["greekandcoptic"] = { 0x00370, 0x003FF, "Greek and Coptic" },
+ ["greekextended"] = { 0x01F00, 0x01FFF, "Greek Extended" },
+ ["gujarati"] = { 0x00A80, 0x00AFF, "Gujarati" },
+ ["gurmukhi"] = { 0x00A00, 0x00A7F, "Gurmukhi" },
+ ["halfwidthandfullwidthforms"] = { 0x0FF00, 0x0FFEF, "Halfwidth and Fullwidth Forms" },
+ ["hangulcompatibilityjamo"] = { 0x03130, 0x0318F, "Hangul Compatibility Jamo" },
+ ["hanguljamo"] = { 0x01100, 0x011FF, "Hangul Jamo" },
+ ["hangulsyllables"] = { 0x0AC00, 0x0D7AF, "Hangul Syllables" },
+ ["hanunoo"] = { 0x01720, 0x0173F, "Hanunoo" },
+ ["hebrew"] = { 0x00590, 0x005FF, "Hebrew" },
+ ["highprivateusesurrogates"] = { 0x0DB80, 0x0DBFF, "High Private Use Surrogates" },
+ ["highsurrogates"] = { 0x0D800, 0x0DB7F, "High Surrogates" },
+ ["hiragana"] = { 0x03040, 0x0309F, "Hiragana" },
+ ["ideographicdescriptioncharacters"] = { 0x02FF0, 0x02FFF, "Ideographic Description Characters" },
+ ["ipaextensions"] = { 0x00250, 0x02AF, "IPA Extensions" },
+ ["kanbun"] = { 0x03190, 0x0319F, "Kanbun" },
+ ["kangxiradicals"] = { 0x02F00, 0x02FDF, "Kangxi Radicals" },
+ ["kannada"] = { 0x00C80, 0x00CFF, "Kannada" },
+ ["katakana"] = { 0x030A0, 0x030FF, "Katakana" },
+ ["katakanaphoneticextensions"] = { 0x031F0, 0x031FF, "Katakana Phonetic Extensions" },
+ ["kayahli"] = { 0x0A900, 0x0A92F, "Kayah Li" },
+ ["kharoshthi"] = { 0x10A00, 0x10A5F, "Kharoshthi" },
+ ["khmer"] = { 0x01780, 0x017FF, "Khmer" },
+ ["khmersymbols"] = { 0x019E0, 0x019FF, "Khmer Symbols" },
+ ["lao"] = { 0x00E80, 0x00EFF, "Lao" },
+ ["latinextendeda"] = { 0x00100, 0x0017F, "Latin Extended-A" },
+ ["latinextendedadditional"] = { 0x01E00, 0x01EFF, "Latin Extended Additional" },
+ ["latinextendedb"] = { 0x00180, 0x0024F, "Latin Extended-B" },
+ ["latinextendedc"] = { 0x02C60, 0x02C7F, "Latin Extended-C" },
+ ["latinextendedd"] = { 0x0A720, 0x0A7FF, "Latin Extended-D" },
+ ["latinsupplement"] = { 0x00080, 0x000FF, "Latin-1 Supplement" },
+ ["lepcha"] = { 0x01C00, 0x01C4F, "Lepcha" },
+ ["letterlikesymbols"] = { 0x02100, 0x0214F, "Letterlike Symbols" },
+ ["limbu"] = { 0x01900, 0x0194F, "Limbu" },
+ ["linearbideograms"] = { 0x10080, 0x100FF, "Linear B Ideograms" },
+ ["linearbsyllabary"] = { 0x10000, 0x1007F, "Linear B Syllabary" },
+ ["lowsurrogates"] = { 0x0DC00, 0x0DFFF, "Low Surrogates" },
+ ["lycian"] = { 0x10280, 0x1029F, "Lycian" },
+ ["lydian"] = { 0x10920, 0x1093F, "Lydian" },
+ ["mahjongtiles"] = { 0x1F000, 0x1F02F, "Mahjong Tiles" },
+ ["malayalam"] = { 0x00D00, 0x00D7F, "Malayalam" },
+ ["mathematicalalphanumericsymbols"] = { 0x1D400, 0x1D7FF, "Mathematical Alphanumeric Symbols" },
+ ["mathematicaloperators"] = { 0x02200, 0x022FF, "Mathematical Operators" },
+ ["miscellaneousmathematicalsymbolsa"] = { 0x027C0, 0x027EF, "Miscellaneous Mathematical Symbols-A" },
+ ["miscellaneousmathematicalsymbolsb"] = { 0x02980, 0x029FF, "Miscellaneous Mathematical Symbols-B" },
+ ["miscellaneoussymbols"] = { 0x02600, 0x026FF, "Miscellaneous Symbols" },
+ ["miscellaneoussymbolsandarrows"] = { 0x02B00, 0x02BFF, "Miscellaneous Symbols and Arrows" },
+ ["miscellaneoustechnical"] = { 0x02300, 0x023FF, "Miscellaneous Technical" },
+ ["modifiertoneletters"] = { 0x0A700, 0x0A71F, "Modifier Tone Letters" },
+ ["mongolian"] = { 0x01800, 0x018AF, "Mongolian" },
+ ["musicalsymbols"] = { 0x1D100, 0x1D1FF, "Musical Symbols" },
+ ["myanmar"] = { 0x01000, 0x0109F, "Myanmar" },
+ ["newtailue"] = { 0x01980, 0x019DF, "New Tai Lue" },
+ ["nko"] = { 0x007C0, 0x007FF, "NKo" },
+ ["numberforms"] = { 0x02150, 0x0218F, "Number Forms" },
+ ["ogham"] = { 0x01680, 0x0169F, "Ogham" },
+ ["olchiki"] = { 0x01C50, 0x01C7F, "Ol Chiki" },
+ ["olditalic"] = { 0x10300, 0x1032F, "Old Italic" },
+ ["oldpersian"] = { 0x103A0, 0x103DF, "Old Persian" },
+ ["opticalcharacterrecognition"] = { 0x02440, 0x0245F, "Optical Character Recognition" },
+ ["oriya"] = { 0x00B00, 0x00B7F, "Oriya" },
+ ["osmanya"] = { 0x10480, 0x104AF, "Osmanya" },
+ ["phagspa"] = { 0x0A840, 0x0A87F, "Phags-pa" },
+ ["phaistosdisc"] = { 0x101D0, 0x101FF, "Phaistos Disc" },
+ ["phoenician"] = { 0x10900, 0x1091F, "Phoenician" },
+ ["phoneticextensions"] = { 0x01D00, 0x01D7F, "Phonetic Extensions" },
+ ["phoneticextensionssupplement"] = { 0x01D80, 0x01DBF, "Phonetic Extensions Supplement" },
+ ["privateusearea"] = { 0x0E000, 0x0F8FF, "Private Use Area" },
+ ["rejang"] = { 0x0A930, 0x0A95F, "Rejang" },
+ ["runic"] = { 0x016A0, 0x016FF, "Runic" },
+ ["saurashtra"] = { 0x0A880, 0x0A8DF, "Saurashtra" },
+ ["shavian"] = { 0x10450, 0x1047F, "Shavian" },
+ ["sinhala"] = { 0x00D80, 0x00DFF, "Sinhala" },
+ ["smallformvariants"] = { 0x0FE50, 0x0FE6F, "Small Form Variants" },
+ ["spacingmodifierletters"] = { 0x002B0, 0x002FF, "Spacing Modifier Letters" },
+ ["specials"] = { 0x0FFF0, 0x0FFFF, "Specials" },
+ ["sundanese"] = { 0x01B80, 0x01BBF, "Sundanese" },
+ ["superscriptsandsubscripts"] = { 0x02070, 0x0209F, "Superscripts and Subscripts" },
+ ["supplementalarrowsa"] = { 0x027F0, 0x027FF, "Supplemental Arrows-A" },
+ ["supplementalarrowsb"] = { 0x02900, 0x0297F, "Supplemental Arrows-B" },
+ ["supplementalmathematicaloperators"] = { 0x02A00, 0x02AFF, "Supplemental Mathematical Operators" },
+ ["supplementalpunctuation"] = { 0x02E00, 0x02E7F, "Supplemental Punctuation" },
+ ["supplementaryprivateuseareaa"] = { 0xF0000, 0xFFFFF, "Supplementary Private Use Area-A" },
+ ["supplementaryprivateuseareab"] = { 0x100000,0x10FFFF,"Supplementary Private Use Area-B" },
+ ["sylotinagri"] = { 0x0A800, 0x0A82F, "Syloti Nagri" },
+ ["syriac"] = { 0x00700, 0x0074F, "Syriac" },
+ ["tagalog"] = { 0x01700, 0x0171F, "Tagalog" },
+ ["tagbanwa"] = { 0x01760, 0x0177F, "Tagbanwa" },
+ ["tags"] = { 0xE0000, 0xE007F, "Tags" },
+ ["taile"] = { 0x01950, 0x0197F, "Tai Le" },
+ ["taixuanjingsymbols"] = { 0x1D300, 0x1D35F, "Tai Xuan Jing Symbols" },
+ ["tamil"] = { 0x00B80, 0x00BFF, "Tamil" },
+ ["telugu"] = { 0x00C00, 0x00C7F, "Telugu" },
+ ["thaana"] = { 0x00780, 0x007BF, "Thaana" },
+ ["thai"] = { 0x00E00, 0x00E7F, "Thai" },
+ ["tibetan"] = { 0x00F00, 0x00FFF, "Tibetan" },
+ ["tifinagh"] = { 0x02D30, 0x02D7F, "Tifinagh" },
+ ["ugaritic"] = { 0x10380, 0x1039F, "Ugaritic" },
+ ["unifiedcanadianaboriginalsyllabics"] = { 0x01400, 0x0167F, "Unified Canadian Aboriginal Syllabics" },
+ ["vai"] = { 0x0A500, 0x0A63F, "Vai" },
+ ["variationselectors"] = { 0x0FE00, 0x0FE0F, "Variation Selectors" },
+ ["variationselectorssupplement"] = { 0xE0100, 0xE01EF, "Variation Selectors Supplement" },
+ ["verticalforms"] = { 0x0FE10, 0x0FE1F, "Vertical Forms" },
+ ["yijinghexagramsymbols"] = { 0x04DC0, 0x04DFF, "Yijing Hexagram Symbols" },
+ ["yiradicals"] = { 0x0A490, 0x0A4CF, "Yi Radicals" },
+ ["yisyllables"] = { 0x0A000, 0x0A48F, "Yi Syllables" },
}
function characters.getrange(name)
- local tag = name:lower()
- tag = name:gsub("[^a-z]", "")
+ local tag = lower(name)
+ tag = gsub(name,"[^a-z]", "")
local range = characters.blocks[tag]
if range then
return range[1], range[2], range[3]
end
- name = name:gsub('"',"0x") -- goodie: tex hex notation
- local start, stop = name:match("^(.-)[%-%:](.-)$")
+ name = gsub(name,'"',"0x") -- goodie: tex hex notation
+ local start, stop = match(name,"^(.-)[%-%:](.-)$")
if start and stop then
start, stop = tonumber(start,16) or tonumber(start), tonumber(stop,16) or tonumber(stop)
if start and stop then
@@ -252,7 +288,16 @@ characters.categories = {
--~ characters: ll lm lo lt lu mn nl no pc pd pe pf pi po ps sc sk sm so
characters.is_character = table.tohash {
- "ll","lm","lo","lt","lu","mn","nl","no","pc","pd","pe","pf","pi","po","ps","sc","sk","sm","so"
+ "lu","ll","lt","lm","lo",
+ "nd","nl","no",
+ "mn",
+ "nl","no",
+ "pc","pd","ps","pe","pi","pf","po",
+ "sm","sc","sk","so"
+}
+
+characters.is_letter = table.tohash {
+ "ll","lm","lo","lt","lu"
}
characters.is_command = table.tohash {
@@ -296,34 +341,23 @@ function table.set_empty_metatable(t)
setmetatable(t,_empty_table_)
end
-table.set_empty_metatable(characters.data)
+table.set_empty_metatable(data)
--[[ldx--
<p>At this point we assume that the big data table is loaded. From this
table we derive a few more.</p>
--ldx]]--
--- used ?
-
-characters.unicodes = characters.unicodes or { }
-characters.utfcodes = characters.utfcodes or { }
-characters.enccodes = characters.enccodes or { }
-characters.fallbacks = characters.fallbacks or { }
-characters.directions = characters.directions or { }
-
-function characters.context.rehash()
- local unicodes, utfcodes, enccodes, fallbacks, directions = characters.unicodes, characters.utfcodes, characters.enccodes, characters.fallbacks, characters.directions
- for k,v in pairs(characters.data) do
- local contextname, adobename, specials = v.contextname, v.adobename, v.specials
- if contextname then
- local slot = v.unicodeslot
- unicodes[contextname] = slot
- utfcodes[contextname] = utfchar(slot)
- end
- local encname = adobename or contextname
- if encname then
- enccodes[encname] = k
- end
+if not characters.fallbacks then
+
+ characters.fallbacks = { }
+ characters.directions = { }
+
+ local fallbacks = characters.fallbacks
+ local directions = characters.directions
+
+ for k,v in next, data do
+ local specials = v.specials
if specials and specials[1] == "compat" and specials[2] == 0x0020 and specials[3] then
local s = specials[3]
fallbacks[k] = s
@@ -331,101 +365,92 @@ function characters.context.rehash()
end
directions[k] = v.direction
end
- for name,code in pairs(characters.synonyms) do
- if not enccodes[name] then enccodes[name] = code end
- end
-end
--- maybe some day, no significate speed up now
+end
---~ input.storage.register(false, "characters.unicodes", characters.unicodes, "characters.unicodes")
---~ input.storage.register(false, "characters.utfcodes", characters.utfcodes, "characters.utfcodes")
---~ input.storage.register(false, "characters.enccodes", characters.enccodes, "characters.enccodes")
---~ input.storage.register(false, "characters.fallbacks", characters.fallbacks, "characters.fallbacks")
---~ input.storage.register(false, "characters.directions", characters.directions, "characters.directions")
+storage.register("characters.fallbacks", characters.fallbacks, "characters.fallbacks")
+storage.register("characters.directions", characters.directions, "characters.directions")
--[[ldx--
<p>The <type>context</type> namespace is used to store methods and data
which is rather specific to <l n='context'/>.</p>
--ldx]]--
-function characters.context.show(n)
- local n = characters.number(n)
- local d = characters.data[n]
- if d then
- local function entry(label,name)
- texsprint(tex.ctxcatcodes,format("\\NC %s\\NC %s\\NC\\NR",label,characters.valid(d[name])))
- end
- texsprint(tex.ctxcatcodes,"\\starttabulate[|Tl|Tl|]")
- entry("unicode index" , "unicodeslot")
- entry("context name" , "contextname")
- entry("adobe name" , "adobename")
- entry("category" , "category")
- entry("description" , "description")
- entry("uppercase code", "uccode")
- entry("lowercase code", "lccode")
- entry("specials" , "specials")
- texsprint(tex.ctxcatcodes,"\\stoptabulate ")
- end
-end
-
--[[ldx--
<p>Instead of using a <l n='tex'/> file to define the named glyphs, we
use the table. After all, we have this information available anyway.</p>
--ldx]]--
function characters.makeactive(n,name) -- let ?
- texsprint(tex.ctxcatcodes,format("\\catcode%s=13\\unexpanded\\def %s{\\%s}",n,utfchar(n),name))
+ texsprint(ctxcatcodes,format("\\catcode%s=13\\unexpanded\\def %s{\\%s}",n,utfchar(n),name))
end
function tex.uprint(n)
- texsprint(tex.ctxcatcodes,utfchar(n))
+ texsprint(ctxcatcodes,utfchar(n))
end
-function characters.context.define(tobelettered, tobeactivated)
- local unicodes, utfcodes = characters.unicodes, characters.utfcodes
- local tc = tex.ctxcatcodes
- local is_character, is_command = characters.is_character, characters.is_command
+local template_a = "\\startextendcatcodetable{%s}\\chardef\\l=11\\chardef\\a=13\\let\\c\\catcode%s\\let\\a\\undefined\\let\\l\\undefined\\let\\c\\undefined\\stopextendcatcodetable"
+local template_b = "\\chardef\\l=11\\chardef\\a=13\\let\\c\\catcode%s\\let\\a\\undefined\\let\\l\\undefined\\let\\c\\undefined"
+
+-- we need a function for setting the codes ....
+
+function characters.define(tobelettered, tobeactivated) -- catcodetables
+ local is_character, is_command, is_letter = characters.is_character, characters.is_command, characters.is_letter
local lettered, activated = { }, { }
- for u, chr in pairs(characters.data) do
+ for u, chr in next, data do
+ -- we can use a macro instead of direct settings
local fallback = chr.fallback
if fallback then
- texsprint("{\\catcode"..u.."=13\\unexpanded\\gdef "..utfchar(u).."{\\checkedchar{"..u.."}{"..fallback.."}}}")
- activated[#activated+1] = "\\c"..u.."=".."13"
+ texprint("{\\catcode",u,"=13\\unexpanded\\gdef ",utfchar(u),"{\\checkedchar{",u,"}{",fallback,"}}}")
+ activated[#activated+1] = "\\c"..u.."\\a"
else
local contextname = chr.contextname
local category = chr.category
if contextname then
if is_character[category] then
-- by this time, we're still in normal catcode mode
+ -- subtle: not "\\",contextname but "\\"..contextname
if chr.unicodeslot < 128 then
- texsprint(tc, "\\chardef\\" .. contextname .. "=" .. u) -- unicodes[contextname])
+ texprint(ctxcatcodes, "\\chardef\\"..contextname,"=",u)
else
- texsprint(tc, "\\let\\" .. contextname .. "=" .. utfchar(u)) -- utfcodes[contextname])
- lettered[#lettered+1] = "\\c"..u.."=".."11"
+ texprint(ctxcatcodes, "\\let\\"..contextname,"=",utfchar(u))
+ if is_letter[category] then
+ lettered[#lettered+1] = "\\c"..u.."\\l"
+ end
end
elseif is_command[category] then
- texsprint("{\\catcode"..u.."=13\\unexpanded\\gdef "..utfchar(u).."{\\"..contextname.."}}")
- activated[#activated+1] = "\\c"..u.."=".."13"
+ texprint("{\\catcode",u,"=13\\unexpanded\\gdef ",utfchar(u),"{\\"..contextname,"}}")
+ activated[#activated+1] = "\\c"..u.."\\a"
end
- else
- if is_character[category] then
- if u >= 128 and u <= 65536 then
- lettered[#lettered+1] = "\\c"..u.."=".."11"
- end
+ elseif is_letter[category] then
+ if u >= 128 and u <= 65536 then -- catch private mess
+ lettered[#lettered+1] = "\\c"..u.."\\l"
end
end
end
+ if chr.range then
+ lettered[#lettered+1] = format('\\dofastrecurse{"%05X}{"%05X}{1}{\\c\\fastrecursecounter\\l}',u,chr.range)
+ end
end
- lettered[#lettered+1] = "\\c"..0x200C.."=".."11" -- non-joiner
- lettered[#lettered+1] = "\\c"..0x200D.."=".."11" -- joiner
- lettered = concat(lettered)
- for _, i in ipairs(tobelettered or { }) do
- texsprint(tc,format("\\startextendcatcodetable{%s}\\let\\c\\catcode%s\\stopextendcatcodetable",i,lettered))
+ -- if false then
+ lettered[#lettered+1] = "\\c"..0x200C.."\\l" -- non-joiner
+ lettered[#lettered+1] = "\\c"..0x200D.."\\l" -- joiner
+ -- fi
+ if tobelettered then
+ lettered = concat(lettered)
+ if true then
+ texsprint(ctxcatcodes,format(template_b,lettered))
+ else
+ for l=1,#tobelettered do
+ texsprint(ctxcatcodes,format(template_a,tobelettered[l],lettered))
+ end
+ end
end
- activated = concat(activated)
- for _, i in ipairs(tobeactivated or { } ) do
- texsprint(tc,format("\\startextendcatcodetable{%s}\\let\\c\\catcode%s\\stopextendcatcodetable",i,activated))
+ if tobeactivated then
+ activated = concat(activated)
+ for a=1,#tobeactivated do
+ texsprint(ctxcatcodes,format(template_a,tobeactivated[a],activated))
+ end
end
end
@@ -439,15 +464,22 @@ end
<p>Setting the lccodes is also done in a loop over the data table.</p>
--ldx]]--
+-- we need a function ...
+
function characters.setcodes()
- local tc = tex.ctxcatcodes
- for code, chr in pairs(characters.data) do
+ for code, chr in next, data do
local cc = chr.category
if cc == 'll' or cc == 'lu' or cc == 'lt' then
local lc, uc = chr.lccode, chr.uccode
if not lc then chr.lccode, lc = code, code end
if not uc then chr.uccode, uc = code, code end
- texsprint(tc, format("\\setcclcuc %i %i %i ",code,lc,uc))
+ texsprint(ctxcatcodes,format("\\setcclcuc{%i}{%i}{%i}",code,lc,uc))
+ end
+ if cc == "lu" then
+ texprint(ctxcatcodes,"\\sfcode ",code,"999 ")
+ end
+ if cc == "lo" and chr.range then
+ texsprint(ctxcatcodes,format('\\dofastrecurse{"%05X}{"%05X}{1}{\\setcclcucself\\fastrecursecounter}',code,chr.range))
end
end
end
@@ -480,21 +512,12 @@ end
characters.valid = characters.is_valid
--[[ldx--
-<p>The next method is used when constructing the main table, although nowadays
-we do this in one step. The index can be a string or a number.</p>
---ldx]]--
-
-function characters.define(c)
- characters.data[characters.number(c.unicodeslot)] = c
-end
-
---[[ldx--
<p></p>
--ldx]]--
-- set a table entry; index is number (can be different from unicodeslot)
function characters.set(n, c)
- characters.data[characters.number(n)] = c
+ data[characters.number(n)] = c
end
--[[ldx--
@@ -503,7 +526,7 @@ can be different (not likely).</p>
--ldx]]--
function characters.get(n)
- return characters.data[characters.number(n)]
+ return data[characters.number(n)]
end
--[[ldx--
@@ -512,43 +535,43 @@ to the checking.</p>
--ldx]]--
function characters.hexindex(n)
- return format("%04X", characters.valid(characters.data[characters.number(n)].unicodeslot))
+ return format("%04X", characters.valid(data[characters.number(n)].unicodeslot))
end
function characters.contextname(n)
- return characters.valid(characters.data[characters.number(n)].contextname)
+ return characters.valid(data[characters.number(n)].contextname)
end
function characters.adobename(n)
- return characters.valid(characters.data[characters.number(n)].adobename)
+ return characters.valid(data[characters.number(n)].adobename)
end
function characters.description(n)
- return characters.valid(characters.data[characters.number(n)].description)
+ return characters.valid(data[characters.number(n)].description)
end
function characters.category(n)
- return characters.valid(characters.data[characters.number(n)].category)
+ return characters.valid(data[characters.number(n)].category)
end
--[[ldx--
<p>Requesting lower and uppercase codes:</p>
--ldx]]--
-function characters.uccode(n) return characters.data[n].uccode or n end
-function characters.lccode(n) return characters.data[n].lccode or n end
+function characters.uccode(n) return data[n].uccode or n end
+function characters.lccode(n) return data[n].lccode or n end
function characters.flush(n)
- local c = characters.data[n]
+ local c = data[n]
if c and c.contextname then
- texsprint(tex.texcatcodes, "\\"..c.contextname)
+ texsprint(texcatcodes, "\\"..c.contextname)
else
- texsprint(unicode.utf8.char(n))
+ texsprint(utfchar(n))
end
end
function characters.shape(n)
- local shcode = characters.data[n].shcode
+ local shcode = data[n].shcode
if not shcode then
return n, nil
elseif type(shcode) == "table" then
@@ -564,43 +587,29 @@ end
function characters.is_of_category(token,category)
if type(token) == "string" then
- return characters.data[utfbyte(token)].category == category
+ return data[utfbyte(token)].category == category
else
- return characters.data[token].category == category
+ return data[token].category == category
end
end
function characters.i_is_of_category(i,category) -- by index (number)
- local cd = characters.data[i]
+ local cd = data[i]
return cd and cd.category == category
end
function characters.n_is_of_category(n,category) -- by name (string)
- local cd = characters.data[utfbyte(n)]
+ local cd = data[utfbyte(n)]
return cd and cd.category == category
end
---[[ldx--
-<p>The following code is kind of messy. It is used to generate the right
-unicode reference tables.</p>
---ldx]]--
-
-function characters.setpdfunicodes()
---~ local tc = tex.ctxcatcodes
---~ for _,v in pairs(characters.data) do
---~ if v.adobename then
---~ texsprint(tc,format("\\pdfglyphtounicode{%s}{%04X}", v.adobename, v.unicodeslot))
---~ end
---~ end
-end
-
-- xml support
characters.active_offset = 0x10000
xml.entities = xml.entities or { }
-input.storage.register(false,"xml/entities",xml.entities,"xml.entities") -- this will move to lxml
+storage.register("xml/entities",xml.entities,"xml.entities") -- this will move to lxml
function characters.remapentity(chr,slot)
texsprint(format("{\\catcode%s=13\\xdef%s{\\string%s}}",slot,utfchar(slot),chr))
diff --git a/tex/context/base/char-ini.tex b/tex/context/base/char-ini.tex
index ba1ecf15b..b79e44857 100644
--- a/tex/context/base/char-ini.tex
+++ b/tex/context/base/char-ini.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=char-ini,
%D version=2006.08.20,
-%D title=\CONTEXT\ Character Macros,
-%D subtitle=Character Support (Initialization),
+%D title=\CONTEXT\ Character Support,
+%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,14 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Character Support (initialization)}
+\writestatus{loading}{ConTeXt Character Support / Initialization}
\registerctxluafile{char-def}{1.001} % let's load this one first
\registerctxluafile{char-ini}{1.001}
\registerctxluafile{char-cmp}{1.001} % maybe we will load this someplace else
-\registerctxluafile{char-tok}{1.001} % maybe we will load this someplace else
-\registerctxluafile{char-map}{1.001}
-\registerctxluafile{char-syn}{1.001}
+\registerctxluafile{char-map}{1.001} % maybe we will load this someplace else
\unprotect
@@ -31,18 +29,15 @@
\def\checkedchar {\relax\ifmmode\expandafter\checkedmathchar\else\expandafter\checkedtextchar\fi} % #1#2
\def\checkedmathchar#1#2{#2}
\def\checkedtextchar #1{\iffontchar\font#1 \expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi{\char#1}}
-\def\setcclcuc #1 #2 #3 {\global\catcode#1=11 \global\lccode #1=#2 \global\uccode #1=#3 }
%D The codes are stored in the format, so we don't need to reinitialize
-%D them (unless of course we have adapted the table).
+%D them (unless of course we have adapted the table). It is on the agenda
+%D to do this with \type {tex.lccode} cum suis once they're available.
-\ctxlua{characters.setcodes()}
+\def\setcclcuc#1#2#3{\global\catcode#1=11 \global\lccode #1=#2 \global\uccode #1=#3 }
+\def\setcclcucself#1{\global\catcode#1=11 \global\lccode #1=#1 \global\uccode #1=#1 }
-% obsolete
-%
-% \startruntimeluacode
-% \ctxlua{characters.setpdfunicodes()}% pdftounicode mappings can only be done runtime
-% \stopruntimeluacode
+\ctxlua{characters.setcodes()}
%D There may be a problem with the turkisch patterns. By now it's taken care of in
%D ctxtools (thanks to Mojca). There seems to be a bug in the patterns (^^11 refers
@@ -51,16 +46,8 @@
% \setcclcuc "201C "201C "201C
% \setcclcuc "201D "201D "201D
-% definitions
-
-\startruntimectxluacode
- characters.context.rehash()
-\stopruntimectxluacode
-
-% \ctxlua{characters.context.rehash()}
-
\ctxlua {
- characters.context.define(
+ characters.define(
{ % letter catcodes
\number\texcatcodes,
\number\ctxcatcodes,
@@ -85,10 +72,3 @@
}
\protect \endinput
-
-% \ctxlua{characters.context.show(123)}
-% \ctxlua{characters.context.show(0x7B)}
-% \ctxlua{characters.context.show("7B")}
-
-% \dostepwiserecurse{`A}{`Z}{1}
-% {\ctxlua{characters.context.show(\recurselevel)}}
diff --git a/tex/context/base/char-map.lua b/tex/context/base/char-map.lua
index e463158c5..0d8422bc2 100644
--- a/tex/context/base/char-map.lua
+++ b/tex/context/base/char-map.lua
@@ -1,15 +1,12 @@
--- filename : char-map.lua
--- comment : companion to char-def.tex (in ConTeXt)
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
--- remark : derived from 'specialcasing.txt', se Arthurs comments in char-map.txt
-
-
-if not versions then versions = { } end versions['char-map'] = 1.001
-if not characters then characters = { } end
+if not modules then modules = { } end modules ['char-map'] = {
+ version = 1.001,
+ comment = "companion to char-ini.tex",
+ author = "Hans Hagen & Arthur Reutenauer",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+characters = characters or { }
characters.casemap={
[0x0049]={
diff --git a/tex/context/base/char-utf.lua b/tex/context/base/char-utf.lua
index 273923c36..7dd5d914f 100644
--- a/tex/context/base/char-utf.lua
+++ b/tex/context/base/char-utf.lua
@@ -1,6 +1,6 @@
if not modules then modules = { } end modules ['char-utf'] = {
version = 1.001,
- comment = "companion to char-ini.tex",
+ comment = "companion to char-utf.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
@@ -19,9 +19,11 @@ in special kinds of output (for instance <l n='pdf'/>).</p>
over a string.</p>
--ldx]]--
-local concat = table.concat
+local utf = unicode.utf8
+local concat, gmatch = table.concat, string.gmatch
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
-utf = utf or unicode.utf8
+local ctxcatcodes = tex.ctxcatcodes
characters = characters or { }
characters.graphemes = characters.graphemes or { }
@@ -38,17 +40,12 @@ local utfchar, utfbyte, utfgsub = utf.char, utf.byte, utf.gsub
--[[ldx--
<p>It only makes sense to collapse at runtime, since we don't expect
-source code to depend on collapsing:</p>
-
-<typing>
-characters.filters.utf.collapsing = true
-input.filters.utf_translator = characters.filters.utf.collapse
-</typing>
+source code to depend on collapsing.</p>
--ldx]]--
function utffilters.initialize()
if utffilters.collapsing and not utffilters.initialized then
- for k,v in pairs(characters.data) do
+ for k,v in next, characters.data do
-- using vs and first testing for length is faster (.02->.01 s)
local vs = v.specials
if vs and #vs == 3 and vs[1] == 'char' then
@@ -86,7 +83,7 @@ function utffilters.collapse(str) -- old one
utffilters.initialize()
end
local tokens, first, done = { }, false, false
- for second in str:utfcharacters() do
+ for second in utfcharacters(str) do
local cgf = graphemes[first]
if cgf and cgf[second] then
first, done = cgf[second], true
@@ -132,7 +129,7 @@ utffilters.private = {
local low = utffilters.private.low
local high = utffilters.private.high
local escapes = utffilters.private.escapes
-local special = "~#$%^&_{}\\"
+local special = "~#$%^&_{}\\|"
function utffilters.private.set(ch)
local cb
@@ -154,7 +151,7 @@ function utffilters.private.escape(str) return utfgsub(str,"(.)", escapes) end
local set = utffilters.private.set
-for ch in special:gmatch(".") do set(ch) end
+for ch in gmatch(special,".") do set(ch) end
--[[ldx--
<p>We get a more efficient variant of this when we integrate
@@ -186,7 +183,7 @@ function utffilters.collapse(str) -- not really tested (we could preallocate a t
cf.initialize()
end
local tokens, first, done, n = { }, false, false, 0
- for second in str:utfcharacters() do
+ for second in utfcharacters(str) do
if done then
local crs = cr[second]
if crs then
@@ -208,7 +205,7 @@ function utffilters.collapse(str) -- not really tested (we could preallocate a t
else
local crs = cr[second]
if crs then
- for s in str:utfcharacters() do
+ for s in utfcharacters(str) do
if n == 1 then
break
else
@@ -222,7 +219,7 @@ function utffilters.collapse(str) -- not really tested (we could preallocate a t
else
local cgf = graphemes[first]
if cgf and cgf[second] then
- for s in str:utfcharacters() do
+ for s in utfcharacters(str) do
if n == 1 then
break
else
@@ -248,120 +245,29 @@ function utffilters.collapse(str) -- not really tested (we could preallocate a t
end
--[[ldx--
-<p>In the beginning of <l n='luatex'/> we experimented with a sequence
-of filters so that we could manipulate the input stream. However, since
-this is a partial solution (not taking macro expansion into account)
-and since it may interfere with non-text, we will not use this feature
-by default.</p>
-
-<typing>
-utffilters.collapsing = true
-characters.filters.append(utffilters.collapse)
-characters.filters.activated = true
-callback.register('process_input_buffer', characters.filters.process)
-</typing>
-
-<p>The following helper functions may disappear (or become optional)
-in the future. Well, they are now.</p>
+<p>Next we implement some commands that are used in the user interface.</p>
--ldx]]--
---[[obsolete--
-
-characters.filters.sequences = characters.filters.sequences or { }
-characters.filters.activated = false
-
-function characters.filters.append(name)
- table.insert(characters.filters.sequences,name)
-end
-
-function characters.filters.prepend(name)
- table.insert(characters.filters.sequences,1,name)
-end
-
-function characters.filters.remove(name)
- for k,v in ipairs(characters.filters.sequences) do
- if v == name then
- table.remove(characters.filters.sequences,k)
- end
- end
-end
-
-function characters.filters.replace(name_1,name_2)
- for k,v in ipairs(characters.filters.sequences) do
- if v == name_1 then
- characters.filters.sequences[k] = name_2
- break
- end
- end
-end
-
-function characters.filters.insert_before(name_1,name_2)
- for k,v in ipairs(characters.filters.sequences) do
- if v == name_1 then
- table.insert(characters.filters.sequences,k,name_2)
- break
- end
- end
-end
+commands = commands or { }
-function characters.filters.insert_after(name_1,name_2)
- for k,v in ipairs(characters.filters.sequences) do
- if v == name_1 then
- table.insert(characters.filters.sequences,k+1,name_2)
- break
- end
- end
+function commands.uchar(first,second)
+ tex.sprint(ctxcatcodes,utfchar(first*256+second))
end
-function characters.filters.list(separator)
- concat(characters.filters.sequences,seperator or ' ')
-end
-
-function characters.filters.process(str)
- if characters.filters.activated then
- for _,v in ipairs(characters.filters.sequences) do
- str = v(str)
- end
- return str
- else
- return nil -- luatex callback optimalisation
- end
-end
-
---obsolete]]--
-
--[[ldx--
-<p>The following code is no longer needed and replaced by token
-collectors somehwere else.</p>
+<p>A few helpers (used to be <t>luat-uni<t/>).</p>
--ldx]]--
---[[obsolete--
-
-characters.filters.collector = { }
-characters.filters.collector.data = { }
-characters.filters.collector.collecting = false
-
-function characters.filters.collector.reset()
- characters.filters.collector.data = { }
-end
-
-function characters.filters.collector.flush(separator)
- tex.sprint(concat(characters.filters.collector.data,separator))
-end
-
-function characters.filters.collector.prune(n)
- for i=1,n do
- table.remove(characters.filters.collector.data,-1)
+function utf.split(str)
+ local t = { }
+ for snippet in utfcharacters(str) do
+ t[#t+1] = snippet
end
+ return t
end
-function characters.filters.collector.numerate(str)
- if characters.filters.collector.collecting then
- table.insert(characters.filters.collector.data,(unicode.utf8.gsub(str,"(.)", function(c)
- return ("0x%04X "):format(unicode.utf8.byte(c))
- end)))
+function utf.each(str,fnc)
+ for snippet in utfcharacters(str) do
+ fnc(snippet)
end
- return str
end
-
---obsolete]]--
diff --git a/tex/context/base/char-utf.tex b/tex/context/base/char-utf.tex
index 2e7156962..d21cd842c 100644
--- a/tex/context/base/char-utf.tex
+++ b/tex/context/base/char-utf.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=char-utf,
%D version=2006.12.05,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=Unicode Support (UTF),
+%D title=\CONTEXT\ Character Support,
+%D subtitle=Unicode UTF,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Unicode Support (utf)}
+\writestatus{loading}{ConTeXt Character Support / Unicode UTF}
%D After a bit of experimenting we reached a clean state where \UTF\
%D 8, 16 and 32 were supported as well as collapsing (combining
@@ -31,28 +31,10 @@
\appendtoks
\ctxlua {
characters.filters.utf.collapsing = true
- input.filters.utf_translator = characters.filters.utf.collapse
+ resolvers.install_text_filter('utf',characters.filters.utf.collapse)
}%
\to \everyjob
-% %D This is a hack, and only meant for special situations. We don't
-% %D support this in for instance verbatim. The active characters map
-% %D onto the \CONTEXT\ names and font handling etc. is up to the user.
-%
-% %D This feature is obsolete.
-%
-% \registerctxluafile{char-act}{1.001}
-%
-% \def\enableactiveutf {\ctxlua{characters.active.enable()}}
-% \def\disableactiveutf{\ctxlua{characters.active.disable()}}
-% \def\testactiveutf #1{\ctxlua{characters.active.test("#1")}}
-
-%D Usage:
-%D
-%D \starttyping
-%D \enableactiveutf \testactiveutf{eacute}
-%D \stoptyping
-
%D The next one influences input parsing.
%D
%D \starttyping
diff --git a/tex/context/base/chem-ini.lua b/tex/context/base/chem-ini.lua
new file mode 100644
index 000000000..27b734840
--- /dev/null
+++ b/tex/context/base/chem-ini.lua
@@ -0,0 +1,74 @@
+if not modules then modules = { } end modules ['chem-ini'] = {
+ version = 1.001,
+ comment = "companion to chem-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, texsprint = string.format, tex.sprint
+
+local trace_molecules = false trackers.register("chemistry.molecules", function(v) trace_molecules = v end)
+
+local ctxcatcodes = tex.ctxcatcodes
+
+chemicals = chemicals or { }
+
+--[[
+<p>The next code is an adaptation of code from Wolfgang Schuster
+as posted on the mailing list. This version supports nested
+braces and unbraced integers as scripts. We could consider
+spaces as terminals for them but first let collect a bunch
+of input then.</p>
+]]--
+
+-- some lpeg, maybe i'll make an syst-lpg module
+
+local lowercase = lpeg.R("az")
+local uppercase = lpeg.R("AZ")
+local backslash = lpeg.P("\\")
+local csname = backslash * lpeg.P(1) * (1-backslash)^0
+local plus = lpeg.P("+") / "\\textplus "
+local minus = lpeg.P("-") / "\\textminus "
+local digit = lpeg.R("09")
+local sign = plus + minus
+local cardinal = digit^1
+local integer = sign^0 * cardinal
+
+local leftbrace = lpeg.P("{")
+local rightbrace = lpeg.P("}")
+local nobrace = 1 - (leftbrace + rightbrace)
+local nested = lpeg.P { leftbrace * (csname + sign + nobrace + lpeg.V(1))^0 * rightbrace }
+local any = lpeg.P(1)
+
+local subscript = lpeg.P("_")
+local superscript = lpeg.P("^")
+local somescript = subscript + superscript
+
+--~ local content = lpeg.Cs(nested + integer + sign + any)
+local content = lpeg.Cs(csname + nested + sign + any)
+
+-- could be made more efficient
+
+local lowhigh = lpeg.Cc("\\lohi{%s}{%s}") * subscript * content * superscript * content / format
+local highlow = lpeg.Cc("\\hilo{%s}{%s}") * superscript * content * subscript * content / format
+local low = lpeg.Cc("\\low{%s}") * subscript * content / format
+local high = lpeg.Cc("\\high{%s}") * superscript * content / format
+local justtext = (1 - somescript)^1
+local parser = lpeg.Cs((csname + lowhigh + highlow + low + high + sign + any)^0)
+
+chemicals.moleculeparser = parser -- can be used to avoid functioncall
+
+function chemicals.molecule(str)
+ return parser:match(str)
+end
+
+function commands.molecule(str)
+ if trace_molecules then
+ local rep = parser:match(str)
+ logs.report("chemistry", "molecule %s => %s",str,rep)
+ texsprint(ctxcatcodes,rep)
+ else
+ texsprint(ctxcatcodes,parser:match(str))
+ end
+end
diff --git a/tex/context/base/chem-ini.mkiv b/tex/context/base/chem-ini.mkiv
new file mode 100644
index 000000000..b28e73e42
--- /dev/null
+++ b/tex/context/base/chem-ini.mkiv
@@ -0,0 +1,42 @@
+%D \module
+%D [ file=chem-ini,
+%D version=2008.03.06,
+%D subtitle=Chemistry,
+%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.
+
+\writestatus{loading}{ConTeXt Chemistry Macros / Initialization} % might become Inline
+
+\registerctxluafile{chem-ini}{1.001}
+
+\unprotect
+
+%D \macros
+%D {\molecule}
+%D
+%D Quick and dirty:
+%D
+%D \starttyping
+%D \def\molecule#1{$\enablesupersub\tf#1$}
+%D \stoptyping
+%D
+%D Using \LUA:
+%D
+%D \startbuffer
+%D \molecule{H_2SO_4^-2}
+%D \molecule{H_2SO_4^{-2}}
+%D \molecule{H_2SO_4^{-2{x}}}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\molecule#1{\ctxlua{commands.molecule(\!!bs#1\!!es)}}
+
+\protect \endinput
+
+
diff --git a/tex/context/base/chem-str-test.tex b/tex/context/base/chem-str-test.tex
new file mode 100644
index 000000000..fd6a8227a
--- /dev/null
+++ b/tex/context/base/chem-str-test.tex
@@ -0,0 +1,560 @@
+% Beware, integrated ppchtex support is incomplete and under
+% construction so when you depend on the full functionality
+% you need to use the module!
+%
+% For testing new functionality:
+%
+% \startMPextensions
+% input "mp-chem.mp" ;
+% \stopMPextensions
+% \startluacode
+% dofile(resolvers.find_file("chem-str.lua","tex"))
+% \stopluacode
+% \setbox\scratchbox\hbox{\startMPcode\stopMPcode}
+
+\enabletrackers[chemistry.structure]
+
+\starttext
+
+\defineprocessor[ch:r][color=red]
+\defineprocessor[ch:g][color=green]
+\defineprocessor[ch:b][color=blue]
+
+\setupchemical[frame=on,offset=3pt]
+
+\startbuffer[test-set]
+
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV1,B] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV2,B] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV3,B] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV4,B] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV5,B] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,MOV6,B] \stopchemical \quad
+
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,AU] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,AD] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,EB] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,DB] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,ER] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,DR] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,BR] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,SB] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,-SB] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,+SB] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,C] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,CC] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,CD] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,CCD] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,SB,SR] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,SB,-SR] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,SB,+SR] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,RD] \stopchemical \quad
+
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,SB,Z] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RZ] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,+R,+RZ] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,-R,-RZ] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,RB,RZ] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,+RB,+RZ][a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,-RB,-RZ][a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RT] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RTT] [a,b,c,d,e,f] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RBT] [a,b,c,d,e,f] \stopchemical \quad
+
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RN] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RTN] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RBN] \stopchemical \quad
+
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,B,R,RN] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,ROT1,B,R,RN] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,ROT2,B,R,RN] \stopchemical \quad
+ \dontleavehmode \startchemical \chemical[\ChemicalKind,ROT3,B,R,RN] \stopchemical \quad
+
+\stopbuffer
+
+\dontcomplain
+
+% \startTEXpage
+
+\setupchemicalframed[frame=on]
+
+% \startTEXpage
+% \noindent \startchemical \chemical[THREE, B,R,RZ][RZ_1,RZ_2,RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT1,B,R,RZ][RZ_1,RZ_2,RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B,R,RZ][RZ_1,RZ_2,RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B,R,RZ][RZ_1,RZ_2,RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B,R,RZ][RZ_1,RZ_2,RZ_3]\stopchemical
+
+% \noindent \startchemical \chemical[THREE, B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3]\stopchemical
+
+% \noindent \startchemical \chemical[THREE, B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3]\stopchemical
+% \stopTEXpage
+
+% \startTEXpage
+% \noindent \startchemical \chemical[SIX,ROT1,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT2,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT3,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT4,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[SIX,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[SIX,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[SIX,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \stopTEXpage
+
+% \startTEXpage
+% \noindent \startchemical \chemical[FIVE,ROT1,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT2,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT3,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT4,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[FIVE,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[FIVE,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FIVE,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \stopTEXpage
+
+% \startTEXpage
+% \noindent \startchemical \chemical[FOUR,ROT1,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT2,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT3,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT4,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[FOUR,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[FOUR,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[FOUR,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \stopTEXpage
+
+% \startTEXpage
+% \noindent \startchemical \chemical[THREE,ROT1,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[THREE,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6]\stopchemical
+
+% \noindent \startchemical \chemical[THREE,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \noindent \startchemical \chemical[THREE,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6]\stopchemical
+% \stopTEXpage
+
+% \startTEXpage
+% \noindent \startchemical \chemical[EIGHT,ROT1,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6,RZ_7,RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT2,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6,RZ_7,RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT3,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6,RZ_7,RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT4,B, R, RZ, AU][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6,RZ_7,RZ_8]\stopchemical
+
+% \noindent \startchemical \chemical[EIGHT,ROT1,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6,-RZ_7,-RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT2,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6,-RZ_7,-RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT3,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6,-RZ_7,-RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT4,B,-R,-RZ][-RZ_1,-RZ_2,-RZ_3,-RZ_4,-RZ_5,-RZ_6,-RZ_7,-RZ_8]\stopchemical
+
+% \noindent \startchemical \chemical[EIGHT,ROT1,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6,+RZ_7,+RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT2,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6,+RZ_7,+RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT3,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6,+RZ_7,+RZ_8]\stopchemical
+% \noindent \startchemical \chemical[EIGHT,ROT4,B,+R,+RZ][+RZ_1,+RZ_2,+RZ_3,+RZ_4,+RZ_5,+RZ_6,+RZ_7,+RZ_8]\stopchemical
+% \stopTEXpage
+
+% \enabletrackers[chemistry.molecules]
+
+% \startchemicalformula
+% \chemical{S}
+% \chemical{+}
+% \chemical{O_2}
+% \chemical{GIVES}
+% \chemical{\+{4}{S}}
+% \chemical{\+{4}{S}\-{2}{O_2}}
+% \chemical{\-{2}{O_2}}
+% \stopchemicalformula
+
+% \startformula
+% \chemical{S}
+% \chemical{+}
+% \chemical{O_2}
+% \chemical{GIVES}
+% \chemical{\+{4}{S}}
+% \chemical{\+{4}{S}\-{2}{O_2}}
+% \chemical{\-{2}{O_2}}
+% \stopformula
+
+
+\startTEXpage[offset=2cm]
+
+\startchemical[width=fit,size=small,scale=small,frame=on]
+ \chemical[SIX,B]
+\stopchemical
+
+% \startchemical[width=fit,size=small,scale=small,frame=on]
+% \chemical[ONE,SB258]
+% \stopchemical
+
+% \startchemical[width=fit,size=small,scale=small,frame=on]
+% \chemical[ONE,ROT3,SB258]
+% \stopchemical
+
+% \startchemical[width=fit,size=small,scale=small,frame=on]
+% \chemical[FIVE,ROT3,SB34,+SB2,-SB5,Z345,DR35,SR4,CRZ35,SUB1,ONE,SB258,Z0,Z28][C,N,C,O,O,CH,COOC_2H_5,COOC_2H_5]
+% \stopchemical
+
+% \startchemical[scale=small,width=8000,height=8000,frame=on]
+% \chemical[SIX,SB2356,DB14,Z2346,SR36,RZ36] [C,N,C,C,H,H_2]
+% \chemical[PB:Z1,ONE,Z0,DIR8,Z0,SB24,DB7,Z27,PE][C,C,CH_3,O]
+% \chemical[PB:Z5,ONE,Z0,DIR6,Z0,SB24,DB7,Z47,PE][C,C,H_3C,O]
+% \chemical[SR24,RZ24] [CH_3,H_3C]
+% \stopchemical
+
+% \startchemical[scale=small,width=6000,height=6000,frame=on]
+% \chemical[SIX,SB2356,DB14,Z,SR36,RZ36,SR1245,RZ24][C,C,N,C,C,C,H,H_2,CH_3,H_3C]
+% \chemical[PB:RZ1,ONE,Z0,SB2,DB7,Z27,PE][C,CH_3,O]
+% \chemical[PB:RZ5,ONE,Z0,SB4,DB7,Z47,PE][C,H_3C,O]
+% \stopchemical
+
+% \startchemical[width=fit,size=small,scale=small,frame=on]
+% \chemical
+% [SIX,B,C,ADJ1,FIVE,ROT3,SB34,+SB2,-SB5,Z345,DR35,SR4,CRZ35,SUB1,ONE,OFF1,SB258,Z0,Z28]
+% [C,N,C,O,O,CH,COOC_2H_5,COOC_2H_5]
+% \stopchemical
+
+% \startchemical[width=fit,height=fit,frame=on,scale=small]
+% \chemical
+% [ONE,SB15,DB7,Z057,3OFF1,MOV1,Z0,3OFF1,MOV1,
+% Z017,SB1357,MOV3,Z0,MOV3,SB1357,Z013,3OFF5,
+% MOV5,Z0,3OFF5,SB5,Z5]
+% [C,H_2N,NH,(CH_2)_3,C,COOH,H,\SL{NH},C,COOH,H,
+% (CH_2)_2,HOOC]
+% \stopchemical
+
+% \startchemical[width=fit,height=fit,frame=on,scale=small]
+% \chemical
+% [ONE,SB15,DB7,Z057,3OFF1,MOV1,Z0,3OFF1,MOV1,Z017,SB1357,MOV3,Z0,MOV3,SB1357,Z013,3OFF5,MOV5,Z0,3OFF5,SB5,Z5]
+% [C,H_2N,NH,(CH_2)_3,C,COOH,H,\SL{NH},C,COOH,H,(CH_2)_2,HOOC]
+% \stopchemical
+
+% \startchemical
+% \chemical[ONE,Z0,DB,Z][C_0,C_1,C_1,C_3,C_4,C_5,C_6,C_7,C_8]
+% \stopchemical
+
+% \startchemical
+% \chemical[ONE,Z0,SB,Z][C_0,C_1,C_1,C_3,C_4,C_5,C_6,C_7,C_8]
+% \stopchemical
+
+% \startchemical
+% \chemical[ONE,Z0,DB,CZ][C_0,C_1,C_1,C_3,C_4,C_5,C_6,C_7,C_8]
+% \stopchemical
+
+% \startchemical
+% [width=fit,top=2000,bottom=2000,
+% scale=small,size=small]%
+% \chemical
+% [ONE,
+% SAVE,
+% Z0,SB731,MOV1,Z0,SB1,MOV1,Z0,DB8,CZ8,SB1,Z1,
+% RESTORE,
+% SAVE,
+% SUB4,ONE,Z0,SB3,SB1,MOV1,Z0,SB1,MOV1,Z0,DB8,CZ8,SB1,Z1,
+% RESTORE,
+% SUB2,ONE,Z0,SB7,SB1,MOV1,Z0,SB1,MOV1,Z0,DB8,CZ8,SB1,Z1]
+% [\SR{HC},O,C,O,C_{19}H_{39},
+% \SR{H_{2}C},O,C,O,C_{17}H_{29},
+% \SR{H_{2}C},O,C,O,C_{21}H_{41}]
+% \stopchemical
+
+% \chemical[width=fit,height=fit,frame=on,scale=small]
+% [ONE,Z0,MOV7,SB1357,Z017,3OFF5,MOV5,Z0,3OFF5,MOV5,SB15,DB7,Z057,MOV0,MOV3,SB1357,Z013,MOV5,3OFF5,Z0,6OFF5,SB5,Z5]
+% [\SL{NH},C,COOH,H,(CH_2)_3,C,H_2H,NH,C,COOH,H,(CH_2)_2,HOOC]
+% \stopchemical
+
+% \chemical[width=fit,height=fit,frame=on,scale=small]
+% [ONE,Z0,MOV7,SB1357,Z017,3OFF5,MOV5,Z0,3OFF5,MOV5,SB15,DB7,Z057,MOV0,MOV3,SB1357,Z013,MOV5,3OFF5,Z0,6OFF5,SB5,Z5]
+% [\SL{NH},C,COOH,H,(CH_2)_3,C,H_2H,NH,C,COOH,H,(CH_2)_2,HOOC]
+% \stopchemical
+
+% \startchemical[width=fit,top=1500,bottom=3500]
+% \chemical[ONE,Z0,DB1,SB3,SB7,Z7,MOV1,Z0,SB3,SB7,Z3,Z7,MOV0,SUB2,SIX,B,R6,C][C,H,C,H,H]
+% \chemical[ONE,Z0,DB1,SB3,SB7,Z7,MOV1,Z0,SB3,SB7,Z3,Z7,MOV0,SUB2,SIX,B,R6,C][C,H,C,H,H]
+% \bottext{styreen}
+% \stopchemical
+
+% \startchemical
+% \chemical[SPACE,PLUS,SPACE]
+% \stopchemical
+% \startchemical[right=600]
+% \chemical[ONE,CZ0][3CH_{3}OH]
+% \stopchemical
+% \startchemical
+% \chemical[SPACE,GIVES,SPACE,SPACE][H^+/H_2O]
+% \stopchemical
+% \startchemical
+% \chemical
+% [ONE,
+% SAVE,
+% Z0,SB7,SB3,SB1,Z1,
+% RESTORE,
+% SAVE,
+% SUB4,ONE,Z0,SB3,SB1,Z1,
+% RESTORE,
+% SUB2,ONE,Z0,SB7,SB1,Z1]
+% [\SR{HC},OH,
+% \SR{H_{2}C},OH,
+% \SR{H_{2}C},OH]
+% \stopchemical
+% \startchemical
+% \chemical[SPACE,PLUS,SPACE]
+% \stopchemical
+
+% \startchemical
+% \chemical
+% [ONE,
+% SAVE,
+% Z0,DB8,CZ8,SB1,SB5,Z5,MOV1,Z0,SB1,Z1,
+% RESTORE,
+% SAVE,
+% SUB4,ONE,Z0,DB8,CZ8,SB1,SB5,Z5,MOV1,Z0,SB1,Z1,
+% RESTORE,
+% SUB2,ONE,Z0,DB8,CZ8,SB1,SB5,Z5,MOV1,Z0,SB1,Z1]
+% [C,O,C_{19}H_{39},O,CH_{3},
+% C,O,C_{17}H_{29},O,CH_{3},
+% C,O,C_{21}H_{41},O,CH_{3}]
+% \stopchemical
+
+% \startchemical[height=4500,bottom=2500]
+% \bottext{$\beta$-D-Fructopyranose}
+% \chemical[SIX,FRONT,BB,B1236,+SB4,-SB5,Z5,+R12346,+RZ12346,-R12346,-RZ12346][Z_0,+R_1,+R_2,+R_3,+R_4,+R_6,-R_1,-R_2,-R_3,-R_4,-R_6]
+% \stopchemical
+
+% \startchemical[height=4500,bottom=2500]
+% \chemical[SIX,FRONT,BB,B]
+% \stopchemical
+
+% \startchemical
+% [width=fit,height=fit,frame=on]
+% \chemical
+% [SIX,DB135,SB246,Z,SR6,RZ6][C,C,N,\SR{HC},N,C,NH_2]
+% \chemical
+% [SIX,MOV1,DB1,SB23,SS6,Z1..3,SR3,RZ3][N,\SL{CH},N,H]
+% \stopchemical
+
+% \startchemical \chemical[SIX,B,R,RZ1=a] \stopchemical
+% \startchemical \chemical[SIX,B,R,RZ1..3=a] \stopchemical
+% \startchemical \chemical[SIX,B,R,RZ135=a] \stopchemical
+% \startchemical \chemical[SIX,B,R,RZ] [a] \stopchemical
+% \startchemical \chemical[SIX,B,R,RZ] [a,b] \stopchemical
+% \startchemical \chemical[SIX,B,R,RZ=a] \stopchemical
+
+% \definechemical[molecule]
+% {\chemical
+% [ONE,Z0,SB1357,
+% SAVE,SUB2,SIX,B,R6,C,RESTORE,
+% MOV1,Z0,SB137,MOV1,Z0,SB37,MOV1]
+% [C,C,C]}
+
+% \startchemical[width=fit,height=fit]
+% \chemical[molecule,molecule,molecule]
+% \stopchemical
+
+% \definechemical[molecule]
+% {\chemical
+% [ONE,Z0,SB1357,
+% SAVE,SUB2,SIX,B,R6,C,RESTORE,
+% MOV1,Z0,SB137,MOV1,Z0,SB37,MOV1]}
+
+% \startchemical[width=fit,height=fit]
+% \chemical[molecule,molecule,molecule][A,B,C,D,E,F,G,H,I]
+% \stopchemical
+
+\stopTEXpage
+
+% \noindent \startchemical
+% \chemical[SIX,B1..3]
+% \stopchemical
+
+% \noindent \startchemical[width=fit,height=fit] % auto5 ipb off5
+% \chemical[SIX,B,C,R,RZ][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]
+% \stopchemical
+% \noindent \startchemical[width=fit,height=fit] % auto5 ipb off5
+% \chemical[SIX,ROT1,B,C,R,RZ][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]
+% \stopchemical
+% \startchemical[width=fit,height=fit] % auto5 ipb off5
+% \chemical[SIX,ROT2,B,C,R,RZ][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]
+% \stopchemical
+% \startchemical[width=fit,height=fit] % auto5 ipb off5
+% \chemical[SIX,ROT3,B,C,R,RZ][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]
+% \stopchemical
+% \startchemical[width=fit,height=fit] % auto5 ipb off5
+% \chemical[SIX,ROT4,B,C,R,RZ][RZ_1,RZ_2,RZ_3,RZ_4,RZ_5,RZ_6]
+% \stopchemical
+
+% \startchemical[width=fit,height=fit,axis=on] % auto5 ipb off5
+% \chemical[SIX,B,C,R6,PB:RZ6,ONE,CZ0,OE1,SB5,MOV5,CZ0,OFF5,OE5,PE][CH,CH_2]
+% \stopchemical
+
+% \dontleavehmode \startchemical \chemical[SIX,B,R,RZ][1,2,3,4,5,6,] \stopchemical
+
+% \start
+% \setupchemicalframed[frame=off]
+% \dontleavehmode \startchemical[scale=medium,style=slanted,color=red,rulecolor=green,left=2000,right=4000,top=2000,bottom=2000,axis=on] \chemical[SIX,B,R,RZ][1,2,3,4,5,6,] \stopchemical
+
+% \dontleavehmode
+% \startchemical[width=fit,height=fit]
+% \chemical[SIX,B][1,2,3,4,5,6]
+% \start
+% \setupchemical[rulecolor=red]
+% \chemical[SIX,R][1,2,3,4,5,6]
+% \stop
+% \chemical[SIX,RZ][1,2,3,4,5,6]
+% \stopchemical
+% \stop
+
+% \stopTEXpage
+
+% \stoptext
+
+% \startTEXpage
+
+% \dontleavehmode \startchemical \chemical[ONE,SB,Z0,Z][0,1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,DB,Z0,Z][0,1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,TB,Z0,Z][0,1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,EP,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,ES,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,ED,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,ET,Z0][0] \stopchemical \quad
+
+
+% \dontleavehmode \startchemical \chemical[ONE,SD,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,LDD,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,RDD,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,HB,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,BB,Z0][0] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,OE,Z0][0] \stopchemical \quad
+
+
+% \dontleavehmode \startchemical \chemical[ONE,SB,Z] [1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,CZ][1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZT][a,b,c,d,e,f,g,h] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZN][1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZBT][1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZBN][1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZTT][1,2,3,4,5,6,7,8] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,ZTN][1,2,3,4,5,6,7,8] \stopchemical \quad
+
+% \dontleavehmode \startchemical \chemical[ONE,SB,MOV1,SB] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[ONE,SB,MOV1,SB,MOV3,SB] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,MOV1,B] \stopchemical \quad
+
+
+% \dontleavehmode \startchemical \chemical[ONE,SB,Z0,Z][0,1,2,3,4,5,6] \stopchemical \quad
+% \stopTEXpage
+
+
+% \dorecurse{1000}{\dontleavehmode \startchemical \chemical[SIX,B,R,RZ][a,b,c,d,e,f] \stopchemical \quad}
+
+% \dontleavehmode \startchemical \chemical[SIX,B,R,RT] [a,b,c,d,e,f] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,R,RTT] [a,b,c,d,e,f] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,R,RBT] [a,b,c,d,e,f] \stopchemical \quad
+
+% \dontleavehmode \startchemical \chemical[SIX,B,R,+R,-R] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B1..4] \stopchemical \quad
+
+% \dontleavehmode \startchemical \chemical[SIX,B,ZN] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,ZT][A,B,C,D,E,F] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,R,AU] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,R,AD] \stopchemical \quad
+
+% \dontleavehmode \startchemical \chemical[SIX,B,ADJ1,SIX,B] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,ADJ1,FIVE,ROT1,B] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,ADJ1,FOUR,B] \stopchemical \quad
+% \dontleavehmode \startchemical \chemical[SIX,B,ADJ1,THREE,B] \stopchemical \quad
+
+% \definechemical[sixring]
+% {\chemical[SIX,B,R]}
+
+% \startchemical[frame=on,width=6000]
+% \chemical[sixring,RZ][A,B,C,D,E,F]
+% \stopchemical
+
+% \definechemical[test]
+% {\chemical[SIX,SB,Z][A,B,C,D,E,F]}
+
+% \startchemical
+% \chemical[SIX,SB,Z,ADJ1,test,ADJ1,SIX,SB,Z][a,b,c,d,e,f,g,h,j,k,l,m,P,Q,R,S,T,U,W]
+% \chemical[ADJ1,SIX,SB,Z][1,2,3,4,5,6]
+% \stopchemical
+
+% \definechemical[test]{\chemical[SIX,SB,Z]}
+
+% \startchemical
+% \chemical[SIX,SB,Z,ADJ1,test,ADJ1,SIX,SB,Z][a,b,c,d,e,f,g,h,j,k,l,m,P,Q,R,S,T,U,W]
+% \chemical[ADJ1,SIX,SB,Z][1,2,3,4,5,6]
+% \stopchemical
+
+% \startchemical
+% \chemical[ADJ1,SIX,SB,Z][a_1,a_2,a_3,a_4,a_5,\ominus]
+% \stopchemical
+
+% \startchemical
+% \chemical[SIX,SB,Z,SAVE,ADJ1,SIX,SB,Z,ADJ1,SIX,SB,Z,RESTORE,ADJ3,SIX,SB,Z][1,2,3,4,5,6,a,b,c,d,e,f,A,B,C,D,E,F,!,!,!,!,!,!]
+% \stopchemical
+
+% $$
+% \startchemical
+% \chemical[OPENCOMPLEX]
+% \stopchemical
+% \startchemical
+% \chemical[SIX,SB,Z][1,2,3,4,5,6]
+% \stopchemical
+% \startchemical
+% \chemical[SPACE,GIVES,SPACE][a,b]
+% \stopchemical
+% \startchemical
+% \chemical[SIX,SB,Z][1,2,3,4,5,6]
+% \stopchemical
+% \startchemical
+% \chemical[CLOSECOMPLEX]
+% \stopchemical
+% $$
+
+% \stoptext
+
+% \page
+
+% \def\ChemicalKind{SIX} \getbuffer[test-set]
+% \def\ChemicalKind{FIVE} \getbuffer[test-set]
+% \def\ChemicalKind{FOUR} \getbuffer[test-set]
+% \def\ChemicalKind{THREE} \getbuffer[test-set]
+
+% \startchemical
+% \chemical[SIX,SB,C135,SR,Z0,Z,RZ][X,ch:r->A,ch:g->B,ch:b->C,D,E,F,a,b,c,d,e,f]
+% \chemical[MOV1,SIX,SB,C135,SR,Z0,Z,RZ][X,ch:r->A,ch:g->B,ch:b->C,D,E,F,a,b,c,d,e,f]
+% \chemical[MOV3,SIX,SB,C135,SR,Z0,Z,RZ][X,ch:r->A,ch:g->B,ch:b->C,D,E,F,a,b,c,d,e,f]
+% \stopchemical
+
+\stoptext
diff --git a/tex/context/base/chem-str.lua b/tex/context/base/chem-str.lua
new file mode 100644
index 000000000..8ab48fca2
--- /dev/null
+++ b/tex/context/base/chem-str.lua
@@ -0,0 +1,488 @@
+if not modules then modules = { } end modules ['chem-str'] = {
+ version = 1.001,
+ comment = "companion to chem-str.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This module in incomplete and experimental.
+
+-- We can push snippets into an mp instance.
+
+local trace_structure = false trackers.register("chemistry.structure", function(v) trace_structure = v end)
+local trace_textstack = false trackers.register("chemistry.textstack", function(v) trace_textstack = v end)
+
+local format, gmatch, match, lower, gsub = string.format, string.gmatch, string.match, string.lower, string.gsub
+local concat, insert, remove = table.concat, table.insert, table.remove
+local apply = structure.processors.apply
+local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
+
+local variables = interfaces.variables
+
+chemicals = chemicals or { }
+
+chemicals.instance = "metafun" -- "ppchtex"
+chemicals.format = "metafun"
+chemicals.structures = 0
+
+local remapper = {
+ ["+"] = "p",
+ ["-"] = "m",
+}
+
+local common_keys = {
+ b = "line", eb = "line", db = "line", er = "line", dr = "line", br = "line",
+ sb = "line", msb = "line", psb = "line",
+ r = "line", pr = "line", mr = "line",
+ au = "line", ad = "line",
+ rb = "line", mrb = "line", prb = "line",
+ rd = "line", mrd = "line", prd = "line",
+ sr = "line", msr = "line", psr = "line",
+ c = "line", cc = "line", cd = "line", ccd = "line",
+ rn = "number", rtn = "number", rbn = "number",
+ s = "line", ss = "line", pss = "line", mss = "line",
+ mid = "fixed", mids = "fixed", midz = "text",
+ z = "text", rz = "text", mrz = "text", prz = "text", crz = "text",
+ rt = "text", rtt = "text", rbt = "text", zt = "text", zn = "number",
+ mov = "transform", rot = "transform", adj = "transform", dir = "transform", sub = "transform",
+}
+
+local front_keys = {
+ b = "line", bb= "line",
+ sb = "line", msb = "line", psb = "line",
+ r = "line", pr = "line", mr = "line",
+ z = "text", mrz = "text", prz = "text",
+}
+
+local one_keys = {
+ sb = "line", db = "line", tb = "line",
+ ep = "line", es = "line", ed = "line", et = "line",
+ sd = "line", ldd = "line", rdd = "line",
+ hb = "line", bb = "line", oe = "line",
+ z = "text", cz = "text", zt = "text", zn = "number",
+ zbt = "text", zbn = "number", ztt = "text", ztn = "number",
+ mov = "transform", sub = "transform", dir = "transform", off = "transform",
+}
+
+local front_align = {
+ mrz = { { "b","b","b","b","b","b" } },
+ prz = { { "t","t","t","t","t","t" } },
+}
+
+local syntax = {
+ one = {
+ n = 1, max = 8, keys = one_keys,
+ align = {
+ z = { { "r", "r_b", "b", "l_b", "l", "l_t", "t", "r_t" } },
+--~ z = { { "r", "r", "b", "l", "l", "l", "t", "r" } },
+ }
+ },
+ three = {
+ n = 3, max = 3, keys = common_keys,
+ align = {
+ mrz = { { "r","b","l" }, { "b","l","t" }, { "l","t","r" }, { "t","r","b" } },
+ rz = { { "r","l_b","l_t" }, { "b","l_t","r_t" }, { "l","r_t","r_b" }, { "t","r_b","l_b" } },
+ prz = { { "r","l","t" }, { "b","t","r" }, { "l","r","b" }, { "t","b","l" } },
+ }
+ },
+ four = {
+ n = 4, max = 4, keys = common_keys,
+ align = {
+ mrz = { { "t","r","b","l" }, { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" } },
+ rz = { { "r_t","r_b","l_b","l_t" }, { "r_b","l_b","l_t","r_t" }, { "l_b","l_t","r_t","r_b" }, { "l_t","r_t","r_b","l_b" } },
+ prz = { { "r","b","l","t" }, { "b","l","t","r" }, { "l","t","r","b" }, { "t","r","b","l" } },
+ }
+ },
+ five = {
+ n = 5, max = 5, keys = common_keys,
+ align = {
+ mrz = { { "t","r","b","b","l" }, { "r","b","l","l","t" }, { "b","l","t","r","r" }, { "l","t","r","r","b" } },
+ rz = { { "r","r","b","l","t" }, { "b","b","l","t","r" }, { "l","l","t","r","b" }, { "t","t","r","b","l" } },
+ prz = { { "r","b","l","t","t" }, { "b","l","t","r","r" }, { "l","t","r","b","b" }, { "t","r","b","l","l" } },
+ }
+ },
+ six = {
+ n = 6, max = 6, keys = common_keys,
+ align = {
+ mrz = { { "t","t","r","b","b","l" }, { "r","b","b","l","t","t" }, { "b","b","l","t","t","r" }, { "l","t","t","r","b","b" } },
+ rz = { { "r","r","b","l","l","t" }, { "b","b","l","t","t","r" }, { "l","l","t","r","r","b" }, { "t","t","r","b","b","l" } },
+ prz = { { "r","b","l","l","t","r" }, { "b","l","t","t","r","b" }, { "l","t","r","r","b","l" }, { "t","r","b","b","l","t" } },
+ }
+ },
+ eight = {
+ n = 8, max = 8, keys = common_keys,
+ align = { -- todo
+ mrz = { { "t","r","r","b","b","l","l","t" }, { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" } },
+ rz = { { "r","r","b","b","l","l","t","t" }, { "b","b","l","l","t","t","r","r" }, { "l","l","t","t","r","r","b","b" }, { "t","t","r","r","b","b","l","l" } },
+ prz = { { "r","b","b","l","l","t","t","r" }, { "b","l","l","t","t","r","r","b" }, { "l","t","t","r","r","b","b","l" }, { "t","r","r","b","b","l","l","t" } },
+ }
+ },
+ five_front = {
+ n = -5, max = 5, keys = front_keys, align = front_align,
+ },
+ six_front = {
+ n = -6, max = 6, keys = front_keys, align = front_align,
+ },
+ pb = { direct = 'chem_pb ;' },
+ pe = { direct = 'chem_pe ;' },
+ save = { direct = 'chem_save ;' },
+ restore = { direct = 'chem_restore ;' },
+ space = { direct = 'chem_symbol("\\chemicalsymbol[space]") ;' },
+ plus = { direct = 'chem_symbol("\\chemicalsymbol[plus]") ;' },
+ minus = { direct = 'chem_symbol("\\chemicalsymbol[minus]") ;' },
+ gives = { direct = 'chem_symbol("\\chemicalsymbol[gives]{%s}{%s}") ;', arguments = 2 },
+ equilibrium = { direct = 'chem_symbol("\\chemicalsymbol[equilibrium]{%s}{%s}") ;', arguments = 2 },
+ mesomeric = { direct = 'chem_symbol("\\chemicalsymbol[mesomeric]{%s}{%s}") ;', arguments = 2 },
+ opencomplex = { direct = 'chem_symbol("\\chemicalsymbol[opencomplex]") ;' },
+ closecomplex = { direct = 'chem_symbol("\\chemicalsymbol[closecomplex]") ;' },
+}
+
+local definitions = { }
+
+function chemicals.undefine(name)
+ definitions[name] = nil
+end
+
+function chemicals.define(name,spec,text)
+ local dn = definitions[name]
+ if not dn then dn = { } definitions[name] = dn end
+ dn[#dn+1] = {
+ spec = aux.settings_to_array(lower(spec)),
+ text = aux.settings_to_array(text),
+ }
+end
+
+local metacode, kind, keys, bonds, max, txt, textsize, rot, pstack
+local molecule = chemicals.molecule -- or use chemicals.moleculeparser:match(...)
+
+local function fetch(txt)
+ local st = stack[txt]
+ local t = st.text[st.n]
+--~ st.n = st.n + 1
+ while not t and txt > 1 do
+ txt = txt - 1
+ st = stack[txt]
+ t = st.text[st.n]
+--~ st.n = st.n + 1
+ end
+ if t then
+ if trace_textstack then
+ logs.report("chemical", "fetching from stack %s slot %s: %s",txt,st.n,t)
+ end
+st.n = st.n + 1
+ end
+ return txt, t
+end
+
+local digit = lpeg.R("09")/tonumber
+local colon = lpeg.P(":")
+local equal = lpeg.P("=")
+local other = 1 - digit - colon - equal
+local remapped = lpeg.S("+-") / remapper
+local operation = lpeg.Cs((remapped^0 * other)^1)
+local amount = digit
+local single = digit
+local special = (colon * lpeg.C(other^1)) + lpeg.Cc("")
+local range = digit * lpeg.P("..") * digit
+local set = lpeg.Ct(digit^2)
+local text = (equal * lpeg.C(lpeg.P(1)^0)) + lpeg.Cc(false)
+local pattern =
+ (amount + lpeg.Cc(1)) *
+ operation *
+ special * (
+ range * lpeg.Cc(false) * text +
+ lpeg.Cc(false) * lpeg.Cc(false) * set * text +
+ single * lpeg.Cc(false) * lpeg.Cc(false) * text +
+ lpeg.Cc(false) * lpeg.Cc(false) * lpeg.Cc(false) * text
+ )
+
+--~ local n, operation, index, upto, set, text = pattern:match("RZ1357")
+
+--~ print(pattern:match("RZ=x")) 1 RZ false false false x
+--~ print(pattern:match("RZ1=x")) 1 RZ 1 false false x
+--~ print(pattern:match("RZ1..3=x")) 1 RZ 1 3 false x
+--~ print(pattern:match("RZ13=x")) 1 RZ false false table x
+
+local function process(spec,text,n,rulethickness,rulecolor,offset)
+ insert(stack,{ spec=spec, text=text, n=n })
+ local txt = #stack
+ for i=1,#spec do
+ local s = spec[i]
+ local d = definitions[s]
+ if d then
+ for i=1,#d do
+ local di = d[i]
+ process(di.spec,di.text,1,rulethickness,rulecolor)
+ end
+ else
+ local rep, operation, special, index, upto, set, text = pattern:match(s)
+ if operation == "pb" then
+ insert(pstack,kind)
+ metacode[#metacode+1] = syntax.pb.direct
+ if keys[special] == "text" and index then
+ if keys["c"..special] == "text" then -- can be option: auto ...
+ metacode[#metacode+1] = format('chem_c%s(%s,%s,"");',special,bonds,index)
+ else
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"");',special,bonds,index)
+ end
+ end
+ elseif operation == "save" then
+ insert(pstack,kind)
+ metacode[#metacode+1] = syntax.save.direct
+ elseif operation == "pe" or operation == "restore" then
+ kind = remove(pstack)
+ local ss = syntax[kind]
+ local prev = bonds or 6
+ keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = syntax[operation].direct
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ elseif operation == "front" then
+ if syntax[kind .. "_front"] then
+ kind = kind .. "_front"
+ local ss = syntax[kind]
+ local prev = bonds or 6
+ keys, bonds, max, rot = ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ end
+ elseif operation then
+ local ss = syntax[operation]
+ if ss then
+ local ds = ss.direct
+ if ds then
+ local sa = ss.arguments
+ if sa == 1 then
+ local one ; txt, one = fetch(txt)
+ metacode[#metacode+1] = format(ds,one or "")
+ elseif sa ==2 then
+ local one ; txt, one = fetch(txt)
+ local two ; txt, two = fetch(txt)
+ metacode[#metacode+1] = format(ds,one or "",two or "")
+ else
+ metacode[#metacode+1] = ds
+ end
+ elseif ss.keys then
+ local prev = bonds or 6
+ kind, keys, bonds, max, rot = s, ss.keys, ss.n, ss.max, 1
+ metacode[#metacode+1] = format("chem_set(%s,%s) ;",prev,bonds)
+ end
+ else
+ local what = keys[operation]
+ if what == "line" then
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,si,si,rulethickness,rulecolor)
+ end
+ elseif upto then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,upto,rulethickness,rulecolor)
+ elseif index then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,index,index,rulethickness,rulecolor)
+ else
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s,%s,%s);",operation,bonds,1,max,rulethickness,rulecolor)
+ end
+ elseif what == "number" then
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,si,si)
+ end
+ elseif upto then
+ for i=index,upto do
+ local si = set[i]
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,si,si)
+ end
+ elseif index then
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,index,index)
+ else
+ for i=1,max do
+ metacode[#metacode+1] = format('chem_%s(%s,%s,"\\dochemicaltext{%s}");',operation,bonds,i,i)
+ end
+ end
+ elseif what == "text" then
+ local align = syntax[kind].align
+ align = align and align[operation]
+ align = align and align[rot]
+ if set then
+ for i=1,#set do
+ local si = set[i]
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local a = align and align[si]
+ if a then a = "." .. a else a = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,a,bonds,si,molecule(apply(t)))
+ end
+ end
+ elseif upto then
+ for i=index,upto do
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[i]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,i,molecule(apply(t)))
+ end
+ end
+ elseif index == 0 then
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ metacode[#metacode+1] = format('chem_%s_zero("\\dochemicaltext{%s}");',operation,molecule(apply(t)))
+ end
+ elseif index then
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[index]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,index,molecule(apply(t)))
+ end
+ else
+ for i=1,max do
+ local t = text
+ if not t then txt, t = fetch(txt) end
+ if t then
+ local s = align and align[i]
+ if s then s = "." .. s else s = "" end
+ metacode[#metacode+1] = format('chem_%s%s(%s,%s,"\\dochemicaltext{%s}");',operation,s,bonds,i,molecule(apply(t)))
+ end
+ end
+ end
+ elseif what == "transform" then
+ if index then
+ for r=1,rep do
+ metacode[#metacode+1] = format('chem_%s(%s,%s);',operation,bonds,index)
+ end
+ if operation == "rot" then
+ rot = index
+ end
+ end
+ elseif what == "fixed" then
+ metacode[#metacode+1] = format("chem_%s(%s,%s,%s);",operation,bonds,rulethickness,rulecolor)
+ end
+ end
+ end
+ end
+ end
+ remove(stack)
+end
+
+-- the size related values are somewhat special but we want to be
+-- compatible
+--
+-- maybe we should default to fit
+--
+-- rulethickness in points
+
+function chemicals.start(settings)
+ chemicals.structures = chemicals.structures + 1
+ local textsize, rulethickness, rulecolor = settings.size, settings.rulethickness, settings.rulecolor
+ local width, height, scale, offset = settings.width or 0, settings.height or 0, settings.scale or "medium", settings.offset or 0
+ local l, r, t, b = settings.left or 0, settings.right or 0, settings.top or 0, settings.bottom or 0
+ if scale == variables.small then
+ scale = 500
+ elseif scale == variables.medium or scale == 0 then
+ scale = 625
+ elseif scale == variables.big then
+ scale = 750
+ else
+ scale = tonumber(scale)
+ if not scale or scale == 0 then
+ scale = 750
+ elseif scale < 500 then
+ scale = 500
+ end
+ end
+ if width == variables.fit then
+ width = true
+ else
+ width = tonumber(width) or 0
+ if l == 0 then
+ if r == 0 then
+ l = (width == 0 and 2000) or width/2
+ r = l
+ elseif width ~= 0 then
+ l = width - r
+ end
+ elseif r == 0 and width ~= 0 then
+ r = width - l
+ end
+ width = false
+ end
+ if height == variables.fit then
+ height = true
+ else
+ height = tonumber(height) or 0
+ if t == 0 then
+ if b == 0 then
+ t = (height == 0 and 2000) or height/2
+ b = t
+ elseif height ~= 0 then
+ t = height - b
+ end
+ elseif b == 0 and height ~= 0 then
+ b = height - t
+ end
+ height = false
+ end
+ scale = 0.75 * scale/625
+ metacode = { format("chem_start_structure(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s) ;",
+ chemicals.structures,
+ l/25, r/25, t/25, b/25, scale,
+ tostring(settings.axis == variables.on), tostring(width), tostring(height), tostring(offset)
+ ) }
+ kind, keys, bonds, stack, rot, pstack = "six", { }, 6, { }, 1, { }
+end
+
+function chemicals.stop()
+ metacode[#metacode+1] = "chem_stop_structure ;"
+ local mpcode = concat(metacode,"\n")
+ if trace_structure then
+ logs.report("chemical", "metapost code:\n%s", mpcode)
+ end
+ metapost.graphic(chemicals.instance,chemicals.format,mpcode,"")
+ metacode = nil
+end
+
+function chemicals.component(spec,text,settings)
+ rulethickness, rulecolor, offset = settings.rulethickness, settings.rulecolor
+ local spec = aux.settings_to_array(lower(spec))
+ local text = aux.settings_to_array(text)
+ metacode[#metacode+1] = "chem_start_component ;"
+ process(spec,text,1,rulethickness,rulecolor)
+ metacode[#metacode+1] = "chem_stop_component ;"
+end
+
+local inline = {
+ ["single"] = "\\chemicalsinglebond", ["-"] = "\\chemicalsinglebond",
+ ["double"] = "\\chemicaldoublebond", ["--"] = "\\chemicaldoublebond",
+ ["triple"] = "\\chemicaltriplebond", ["---"] = "\\chemicaltriplebond",
+ ["gives"] = "\\chemicalgives", ["->"] = "\\chemicalgives",
+ ["equilibrium"] = "\\chemicalequilibrium", ["<->"] = "\\chemicalequilibrium",
+ ["mesomeric"] = "\\chemicalmesomeric", ["<>"] = "\\chemicalmesomeric",
+ ["plus"] = "\\chemicalsplus", ["+"] = "\\chemicalsplus",
+ ["minus"] = "\\chemicalsminus",
+ ["space"] = "\\chemicalsspace",
+}
+
+-- todo: top / bottom
+
+function chemicals.inline(spec)
+ local spec = aux.settings_to_array(spec)
+ for i=1,#spec do
+ local s = spec[i]
+ local inl = inline[lower(s)]
+ if inl then
+ texsprint(ctxcatcodes,inl)
+ else
+ texsprint(ctxcatcodes,format("\\chemicalinline{%s}",molecule(s)))
+ end
+ end
+end
+
+statistics.register("chemical formulas", function()
+ if chemicals.structures > 0 then
+ return format("%s chemical structure formulas",chemicals.structures) -- no timing needed, part of metapost
+ end
+end)
diff --git a/tex/context/base/chem-str.mkiv b/tex/context/base/chem-str.mkiv
new file mode 100644
index 000000000..29c6fe939
--- /dev/null
+++ b/tex/context/base/chem-str.mkiv
@@ -0,0 +1,526 @@
+%D \module
+%D [ file=chem-ini,
+%D version=2009.05.13,
+%D subtitle=Chemistry,
+%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 This module in incomplete and experimental. Eventually this code
+%D will replace \PPCHTEX.
+
+\writestatus{loading}{ConTeXt Chemistry Macros / Structure}
+
+\registerctxluafile{chem-str}{1.001}
+
+% We have a slightly different interface. This is unchanged:
+%
+% \startchemical[axis=on]
+% \chemical[SIX,ROT2,B,R6,SUB1,FIVE,ROT1,B][1]
+% \stopchemical
+%
+% Here we use chemicalformula instead, so no longer a mix:
+%
+% \startchemicalformula
+% \chemical{H_2}{top}{bottom}
+% \chemical{PLUS}{top}{bottom}
+% \chemical{O}{top}{bottom}
+% \chemical{GIVES}{top}{bottom}
+% \chemical{H_2O}{top}{bottom}
+% \stopchemicalformula
+%
+% \startchemicalformula
+% \chemical{H_2}
+% \chemical{PLUS}
+% \chemical{O}
+% \chemical{GIVES}
+% \chemical{H_2O}
+% \stopchemicalformula
+%
+% The inline variant has only one argument:
+%
+% \chemical{H_2,PLUS,O,GIVES,H_2O}
+
+% todo: seven | eight | frontsix | fontfive | carbon | newmans | chair
+
+\unprotect
+
+\def\setupchemical
+ {\dosingleempty\dosetupchemical}
+
+\def\dosetupchemical
+ {\getparameters[\??cm]}
+
+\let\setupchemicals\setupchemical
+
+\def\setupchemicalframed
+ {\dosingleempty\dosetupchemicalframed}
+
+\def\dosetupchemicalframed
+ {\getparameters[\??cm:\c!frame]}
+
+\def\chemicalparameter#1{\csname\??cm#1\endcsname}
+
+\def\definechemical
+ {\dosingleargument\dodefinechemical} % global
+
+\def\dodefinechemical[#1]#2%
+ {\startnointerference
+ \ctxlua{chemicals.undefine("#1")}%
+ \def\chemical{\dodoubleempty\dostructurechemical}%
+ \def\dostructurechemical[##1][##2]{\ctxlua{chemicals.define("#1",\!!bs##1\!!es,\!!bs\detokenize{##2}\!!es)}}%
+ #2% flush
+ \stopnointerference}
+
+\def\definechemicalsymbol
+ {\dodoubleempty\dodefinechemicalsymbol}
+
+\def\dodefinechemicalsymbol[#1][#2]%
+ {\setvalue{\??cm::#1}{#2}}
+
+\def\chemicalsymbol[#1]%
+ {\getvalue{\??cm::#1}}
+
+% size (small medium big)
+
+\def\dosetchemicaltext
+ {\dosetfontattribute \??cm\c!style
+ \dosetcolorattribute\??cm\c!color}
+
+\def\dochemicaltext#1%
+ {\dosetchemicaltext\strut#1} % maybe also \setstrut
+
+\edef\chemicaltoplocation{t}
+\edef\chemicalbotlocation{b}
+
+\def\dochemicaltext#1% in ppchtex we had a more clever alignment
+ {\dosetchemicaltext\strut#1} % maybe also \setstrut
+
+\newconditional\indisplaychemical
+
+\unexpanded\def\startchemical
+ {\dosingleempty\dostartchemical}
+
+\setvalue{\??cm:\c!size:\v!small }{\txx}
+\setvalue{\??cm:\c!size:\v!medium}{\tx}
+\setvalue{\??cm:\c!size:\v!big }{}
+
+\newtoks \everychemical
+\newtoks \everystructurechemical
+\newtoks \withchemicalbox
+\newbox \chemicalbox
+\newconditional\somechemicaltext
+\newdimen \chemicalwidth
+\newdimen \chemicalheight
+\newdimen \chemicaldepth
+
+\def\dostartchemical[#1]%
+ {\ifmmode\vcenter\else\vbox\fi
+ \bgroup
+ \dontcomplain
+ \settrue\indisplaychemical
+ \forgetall
+ \getparameters[\??cm][#1]%
+ \the\everystructurechemical
+ \setbox\chemicalbox\hbox\bgroup
+ \ctxlua{chemicals.start {
+ width = "\chemicalparameter\c!width",
+ height = "\chemicalparameter\c!height",
+ left = \chemicalparameter\c!left,
+ right = \chemicalparameter\c!right,
+ top = \chemicalparameter\c!top,
+ bottom = \chemicalparameter\c!bottom,
+ scale = "\chemicalparameter\c!scale",
+ axis = "\chemicalparameter\c!axis",
+ offset = "\the\dimexpr.25em\relax",
+ } }%
+ \startnointerference}
+
+\unexpanded\def\stopchemical
+ {\stopnointerference
+ \ctxlua{chemicals.stop()}%
+ \egroup
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+ \the\withchemicalbox
+ \doifelsenothing{\chemicalparameter\c!frame}\handlechemicalframednop\handlechemicalframedyes
+ \egroup}
+
+\def\handlechemicalframedyes
+ {\localframed%
+ [\??cm:\c!frame]%
+ [\c!frame=\chemicalparameter\c!frame,\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\chemicalbox\vss}}} % remove depth
+
+\def\handlechemicalframednop
+ {\localframed%
+ [\??cm:\c!frame]%
+ [\c!align=\v!normal,\c!strut=\v!no]{\vbox{\box\chemicalbox\vss}}} % remove depth
+
+\let\startstructurechemical\startchemical
+\let\stopstructurechemical \stopchemical
+
+\unexpanded\def\structurechemical
+ {\dotripleempty\dostructurechemical}
+
+\appendtoks
+ \let\chemical\structurechemical
+\to\everystructurechemical
+
+\def\dostructurechemical
+ {\ifthirdargument
+ \expandafter\dostructurechemicalthree
+ \else
+ \expandafter\dostructurechemicaltwo
+ \fi}
+
+\def\dostructurechemicalthree[#1][#2][#3]%
+ {\writestatus\m!chemicals{hyperlinked chemicals not yet supported}% todo reference, for the moment ignored
+ \ctxlua{chemicals.component(\!!bs#2\!!es, \!!bs\detokenize{#3}\!!es, { % maybe also pass first two args this way
+ rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points
+ rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup
+ } ) }%
+ \ignorespaces}
+
+\def\dostructurechemicaltwo[#1][#2]%
+ {\ctxlua{chemicals.component(\!!bs#1\!!es,\!!bs\detokenize{#2}\!!es, { % maybe also pass first two args this way
+ rulethickness = "\the\dimexpr\chemicalparameter\c!rulethickness\relax", % todo: scaled points
+ rulecolor = "\MPcolor{\chemicalparameter\c!rulecolor}" % we can precalculate this for speedup
+ } ) }%
+ \ignorespaces}
+
+\appendtoks
+ \setbox\chemicalbox\hbox{\raise\MPlly\onebasepoint\box\chemicalbox}%
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+\to \withchemicalbox
+
+% kind of compatible, but text sizes instead of math sizes (i.e. tx is larger than scriptsize)
+
+\appendtoks
+ \edef\chemicalbodyfont{\chemicalparameter\c!bodyfont}%
+ \doifnot\chemicalbodyfont\fontbody{\switchtobodyfont[\chemicalbodyfont]}% \fontbody is not expanded (yet)
+ \getvalue{\??cm:\c!size:\chemicalparameter\c!size}%
+% \to \everystructurechemical
+\to \everychemical
+
+\def\chemicaltoptext#1{\global\settrue\somechemicaltext\gdef\thetoptext{#1}\ignorespaces}
+\def\chemicalbottext#1{\global\settrue\somechemicaltext\gdef\thebottext{#1}\ignorespaces}
+\def\chemicalmidtext#1{\global\settrue\somechemicaltext\gdef\themidtext{#1}\ignorespaces}
+
+\appendtoks
+ \let\toptext\chemicaltoptext \glet\thetoptext\empty
+ \let\bottext\chemicalbottext \glet\thebottext\empty
+ \let\midtext\chemicalmidtext \glet\themidtext\empty
+ \global\setfalse\somechemicaltext
+\to \everystructurechemical
+
+\def\doaddchemicaltexts
+ {\setbox2\hbox to \chemicalwidth{\strut\hss\hbox{\strut\themidtext}\hss}%
+ \setbox4\hbox to \chemicalwidth{\strut\hss\hbox{\strut\thetoptext}\hss}%
+ \setbox6\hbox to \chemicalwidth{\strut\hss\hbox{\strut\thebottext}\hss}%
+ \setbox\chemicalbox\hbox \bgroup
+ \box\chemicalbox
+ \hskip-\chemicalwidth
+ \raise\chemicalheight\hbox{\lower\ht4\box4}%
+ \hskip-\chemicalwidth
+ \lower.5\dimexpr\ht2-\dp2\relax\box2%
+ \hskip-\chemicalwidth
+ \lower\chemicaldepth \hbox{\raise\dp6\box6}%
+ \hss
+ \egroup} % text on top of chemicals
+
+\appendtoks
+ \ifconditional\somechemicaltext
+ \doaddchemicaltexts
+ \chemicalwidth \wd\chemicalbox
+ \chemicalheight\ht\chemicalbox
+ \chemicaldepth \dp\chemicalbox
+ \fi
+\to \withchemicalbox
+
+% todo: enspace or emspace
+
+\definechemicalsymbol[space] [\enspace\quad\enspace]
+\definechemicalsymbol[plus] [\enspace+\enspace]
+\definechemicalsymbol[minus] [\enspace-\enspace]
+\definechemicalsymbol[gives] [\dochemicalarrow\xrightarrow]
+\definechemicalsymbol[equilibrium] [\dochemicalarrow\xrightoverleftarrow]
+\definechemicalsymbol[mesomeric] [\dochemicalarrow\xleftrightarrow]
+\definechemicalsymbol[opencomplex] [\mathematics{\Bigg[}] % not yet ok
+\definechemicalsymbol[closecomplex][\mathematics{\Bigg]}] % not yet ok
+
+\definechemicalsymbol[SPACE] [{\chemicalsymbol[space]}]
+\definechemicalsymbol[PLUS] [{\chemicalsymbol[plus]}]
+\definechemicalsymbol[MINUS] [{\chemicalsymbol[minus]}]
+\definechemicalsymbol[GIVES] [{\chemicalsymbol[gives]}]
+\definechemicalsymbol[EQUILIBRIUM] [{\chemicalsymbol[equilibrium]}]
+\definechemicalsymbol[MESOMERIC] [{\chemicalsymbol[mesomeric]}]
+\definechemicalsymbol[OPENCOMPLEX] [{\chemicalsymbol[opencomplex]}]
+\definechemicalsymbol[CLOSECOMPLEX][{\chemicalsymbol[closecomplex]}]
+
+\def\dochemicalarrow#1#2#3%
+ {\enspace
+ \mathematics{#1%
+ {\strut\hbox \!!spread 2em{\hss\ctxlua{chemicals.inline(\!!bs#2\!!es)}\hss}}%
+ {\strut\hbox \!!spread 2em{\hss\ctxlua{chemicals.inline(\!!bs#3\!!es)}\hss}}}%
+ \enspace}
+
+% special macros (probably needs some more work)
+
+\def\dochemicaltop#1#2#3#4%
+ {\begingroup
+ \setbox0\hbox{\tx\setstrut\strut#3}%
+ \setbox2\hbox{\setstrut\strut\molecule{#4}}%
+ \setbox0\hbox{\raise\dimexpr\dp0+\ht2\relax\hbox to \wd2{#1\box0#2}}%
+ \smashbox0
+ \hbox{\box0\box2}%
+ \endgroup}%
+
+\def\dochemicalbottom#1#2#3#4%
+ {\begingroup
+ \setbox0\hbox{\tx\setstrut\strut#3}%
+ \setbox2\hbox{\setstrut\strut#4}%
+ \setbox0\hbox{\lower\dimexpr\dp2+\ht0\relax\hbox to \wd2{#1\box0#2}}%
+ \smashbox0
+ \hbox{\box0\box2}%
+ \endgroup}%
+
+\unexpanded\def\chemicalleft#1#2%
+ {\begingroup
+ \hbox{\llap{\tx\setstrut\strut#1}\setstrut\strut#2}%
+ \endgroup}%
+
+\unexpanded\def\chemicalright#1#2%
+ {\begingroup
+ \hbox{\setstrut\strut#2\rlap{\tx\setstrut\strut#1}}%
+ \endgroup}%
+
+\unexpanded\def\chemicaltop {\dochemicaltop \hss \hss }
+\unexpanded\def\chemicallefttop {\dochemicaltop \relax \hss }
+\unexpanded\def\chemicalrighttop {\dochemicaltop \hss \relax}
+\unexpanded\def\chemicalbottom {\dochemicalbottom \hss \hss }
+\unexpanded\def\chemicalleftbottom {\dochemicalbottom \relax \hss }
+\unexpanded\def\chemicalrightbottom {\dochemicalbottom \hss \relax}
+
+\unexpanded\def\chemicaltopleft #1{\chemicalleft {\chemicalrighttop {#1}{}}}
+\unexpanded\def\chemicalbottomleft #1{\chemicalleft {\chemicalrightbottom{#1}{}}}
+\unexpanded\def\chemicaltopright #1{\chemicalright{\chemicallefttop {#1}{}}}
+\unexpanded\def\chemicalbottomright #1{\chemicalright{\chemicalleftbottom {#1}{}}}
+
+\unexpanded\def\chemicalcentered #1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut\hss#1\hss}}
+\unexpanded\def\chemicalleftcentered #1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut #1\hss}}
+\unexpanded\def\chemicalrightcentered#1{\setbox\scratchbox\hbox{C}\hbox to \wd\scratchbox{\setstrut\strut\hss#1}}
+
+\let\chemicalsmashedmiddle\chemicalcentered
+\let\chemicalsmashedleft \chemicalleftcentered
+\let\chemicalsmashedright \chemicalrightcentered
+
+\unexpanded\def\chemicaloxidation#1#2#3%
+ {\chemicaltop{\txx\ifcase#2\relax0\else#1\uppercase\expandafter{\romannumeral#2}\fi}{#3}}
+
+\unexpanded\def\chemicaloxidationplus {\dotriplegroupempty\chemicaloxidation{\textplus }} % {} needed!
+\unexpanded\def\chemicaloxidationminus{\dotriplegroupempty\chemicaloxidation{\textminus}} % {} needed!
+\unexpanded\def\chemicalforeveropen {\dotriplegroupempty\chemicalleft {$\big[$}} % {} needed!
+\unexpanded\def\chemicalforeverclose {\dotriplegroupempty\chemicalright {$\big]$}} % {} needed!
+\unexpanded\def\chemicaloxidationone {\chemicaloxidation\relax1}
+\unexpanded\def\chemicaloxidationtwo {\chemicaloxidation\relax2}
+\unexpanded\def\chemicaloxidationthree{\chemicaloxidation\relax3}
+\unexpanded\def\chemicaloxidationfour {\chemicaloxidation\relax4}
+\unexpanded\def\chemicaloxidationfive {\chemicaloxidation\relax5}
+\unexpanded\def\chemicaloxidationsix {\chemicaloxidation\relax6}
+\unexpanded\def\chemicaloxidationseven{\chemicaloxidation\relax7}
+
+\appendtoks
+ \let \+\chemicaloxidationplus
+ \let \-\chemicaloxidationminus
+ \let \[\chemicalforeveropen
+ \let \]\chemicalforeverclose
+ \let \1\chemicaloxidationone
+ \let \2\chemicaloxidationtwo
+ \let \3\chemicaloxidationthree
+ \let \4\chemicaloxidationfour
+ \let \5\chemicaloxidationfive
+ \let \6\chemicaloxidationsix
+ \let \7\chemicaloxidationseven
+ \let \X\chemicaltighttext
+ \let \T\chemicaltop
+ \let \B\chemicalbottom
+ \let \L\chemicalleft
+ \let\LC\chemicalleftcentered
+ \let \R\chemicalright
+ \let\RC\chemicalrightcentered
+ \let\TL\chemicaltopleft
+ \let\BL\chemicalbottomleft
+ \let\TR\chemicaltopright
+ \let\BR\chemicalbottomright
+ \let\LT\chemicallefttop
+ \let\LB\chemicalleftbottom
+ \let\RT\chemicalrighttop
+ \let\RB\chemicalrightbottom
+ \let\SL\chemicalsmashedleft
+ \let\SM\chemicalsmashedmiddle
+ \let\SR\chemicalsmashedright
+\to \everychemical
+
+\appendtoks
+ \the\everychemical
+\to \everystructurechemical
+
+% inline
+
+\unexpanded\def\chemical
+ {\ifinformula
+ \expandafter\displaychemical
+ \else
+ \expandafter\inlinechemical
+ \fi}
+
+\def\displaychemical
+ {\dotriplegroupempty\dodisplaychemical}
+
+\def\dodisplaychemical#1#2#3% todo:
+ {\the\everychemical \everychemical\emptytoks
+ \quad
+ \vcenter\bgroup
+ \ifthirdargument
+ \ifsecondargument
+ \halign{&\hss##\hss\cr#2\cr\molecule{#1}\cr#3\cr}%
+ \else
+ \halign{&\hss##\hss\cr\molecule{#1}\cr#2\cr}%
+ \fi
+ \else
+ \hbox{\molecule{#1}}%
+ \fi
+ \egroup
+ \quad}
+
+\def\inlinechemical#1%
+ {\dontleavehmode\hbox{\ctxlua{chemicals.inline(\!!bs#1\!!es)}}}
+
+\def\chemicalbondrule{\hbox{\vrule\!!height.75ex\!!depth-\dimexpr.75ex-\linewidth\relax\!!width1em\relax}}
+
+\definechemicalsymbol[i:space] [\enspace\quad\enspace]
+\definechemicalsymbol[i:plus] [\enspace\mathematics{+}\enspace]
+\definechemicalsymbol[i:minus] [\enspace\mathematics{-}\enspace]
+\definechemicalsymbol[i:gives] [\enspace\mathematics{\xrightarrow{}{}}\enspace]
+\definechemicalsymbol[i:equilibrium] [\enspace\mathematics{\xrightpverleftarrow{}{}}\enspace]
+\definechemicalsymbol[i:mesomeric] [\enspace\mathematics{\xleftrightarrow{}{}}\enspace]
+\definechemicalsymbol[i:single] [\chemicalbondrule]
+\definechemicalsymbol[i:tripple] [\hbox{\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}]
+\definechemicalsymbol[i:double] [\hbox{\chemicalbondrule\hskip-1em\lower.5ex\chemicalbondrule\hskip-1em\raise.5ex\chemicalbondrule}]
+
+\def\chemicalsinglebond {\chemicalsymbol[i:single]}
+\def\chemicaldoublebond {\chemicalsymbol[i:tripple]}
+\def\chemicaltriplebond {\chemicalsymbol[i:double]}
+\def\chemicalgives {\chemicalsymbol[i:gives]}
+\def\chemicalmesomeric {\chemicalsymbol[i:mesomeric]}
+\def\chemicalequilibrium{\chemicalsymbol[i:equilibrium]}
+\def\chemicalsplus {\chemicalsymbol[i:plus]}
+\def\chemicalsminus {\chemicalsymbol[i:minus]}
+\def\chemicalsspace {\chemicalsymbol[i:space]}
+\def\chemicalinline #1{#1}
+
+% display
+
+\newconditional\formulachemicalhastop
+\newconditional\formulachemicalhasbot
+
+\newtoks\formulachemicaltop
+\newtoks\formulachemicalmid
+\newtoks\formulachemicalbot
+
+\newif\ifinchemicalformula
+
+\def\startchemicalformula
+ {\mathortext\vcenter\vbox\bgroup
+ \forgetall
+ \inchemicalformulatrue
+ \the\everychemical
+ \everychemical\emptytoks
+ \formulachemicaltop\emptytoks % not needed
+ \formulachemicalmid\emptytoks % not needed
+ \formulachemicalbot\emptytoks % not needed
+ \let\chemical\formulachemical
+ \setfalse\formulachemicalhastop
+ \setfalse\formulachemicalhasbot }
+
+\def\stopchemicalformula
+ {\tabskip1em\relax
+ \nointerlineskip
+ \ifconditional\formulachemicalhastop
+ \ifconditional\formulachemicalhasbot
+ \halign{&\hss##\hss\cr\the\formulachemicaltop\cr\the\formulachemicalmid\cr\the\formulachemicalbot\cr}%
+ \else
+ \halign{&\hss##\hss\cr\the\formulachemicaltop\cr\the\formulachemicalmid\cr}%
+ \fi
+ \else
+ \ifconditional\formulachemicalhasbot
+ \halign{&\hss##\hss\cr\the\formulachemicalmid\cr\the\formulachemicalbot\cr}%
+ \else
+ \halign{&\hss##\hss\cr\the\formulachemicalmid\cr}%
+ \fi
+ \fi
+ \egroup}
+
+\unexpanded\def\formulachemical
+ {\relax\dotriplegroupempty\doformulachemical}
+
+\def\doformulachemical#1#2#3%
+ {\ifthirdargument
+ \doifelsenothing{#2}\noformulachemicaltop{\doformulachemicaltop{#2}}%
+ \doifelsenothing{#3}\noformulachemicalbot{\doformulachemicalbot{#3}}%
+ \else\ifsecondargument
+ \noformulachemicaltop
+ \doifelsenothing{#2}\noformulachemicalbot{\doformulachemicalbot{#2}}%
+ \else
+ \noformulachemicaltop
+ \noformulachemicalbot
+ \fi\fi
+ \formulachemicalmid\expandafter{\the\formulachemicalmid\dodochemicalformulamid{#1}&}}
+
+\def\noformulachemicaltop {\formulachemicaltop\expandafter{\the\formulachemicaltop&}}
+\def\noformulachemicalbot {\formulachemicalbot\expandafter{\the\formulachemicalbot&}}
+\def\doformulachemicaltop#1{\formulachemicaltop\expandafter{\the\formulachemicaltop\dodochemicalformulatop{#1}&}\settrue\formulachemicalhastop}
+\def\doformulachemicalbot#1{\formulachemicalbot\expandafter{\the\formulachemicalbot\dodochemicalformulabot{#1}&}\settrue\formulachemicalhasbot}
+
+\def\dodochemicalformulamid#1%
+ {\ifcsname\??cm::\detokenize{#1}\endcsname\csname\??cm::\detokenize{#1}\expandafter\endcsname\else\molecule{#1}\fi{}{}}
+
+\def\dodochemicalformulatop#1{\strut#1}
+\def\dodochemicalformulabot#1{\strut#1}
+
+% gone: state option resolution offset (now frame offset) alternative
+
+\setupchemicalframed
+ [\c!align=\v!normal,
+ \c!strut=\v!no,
+ \c!offset=\v!overlay,
+ \c!frame=off]
+
+\setupchemical
+ [\c!frame=,
+ \c!width=0,
+ \c!height=0,
+ \c!left=0,
+ \c!right=0,
+ \c!top=0,
+ \c!bottom=0,
+ \c!bodyfont=\the\bodyfontsize,
+ \c!scale=\v!medium,
+ \c!size=\v!medium,
+ \c!textsize=\v!big,
+ \c!axis=\v!off,
+ \c!style=\rm,
+ \c!location=,
+ \c!color=,
+ \c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!factor=1]
+
+\protect \endinput
diff --git a/tex/context/base/colo-ext.tex b/tex/context/base/colo-ext.mkii
index 33e87459d..06facd34e 100644
--- a/tex/context/base/colo-ext.tex
+++ b/tex/context/base/colo-ext.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Color Macros / extras}
+\writestatus{loading}{ConTeXt Color Macros / Extras}
\unprotect
diff --git a/tex/context/base/colo-ext.mkiv b/tex/context/base/colo-ext.mkiv
new file mode 100644
index 000000000..06facd34e
--- /dev/null
+++ b/tex/context/base/colo-ext.mkiv
@@ -0,0 +1,57 @@
+%D \module
+%D [ file=colo-ext, % mostof thsi code used to be in colo-ini.tex
+%D version=1997.04.01,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Extras,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Color Macros / Extras}
+
+\unprotect
+
+%D \macros
+%D {negatecolorcomponent, negativecolorbox}
+%D
+%D Sometimes, especially when we deal with typesetting
+%D devices, we want to reverse the color scheme. Instead of
+%D recalculating all those colors, we use a quick and dirty
+%D approach:
+%D
+%D \starttyping
+%D \negativecolorbox0
+%D \stoptyping
+%D
+%D will negate the colors in box zero.
+
+\def\negatecolorbox#1%
+ {\setbox#1\hbox
+ {\dostartnegative
+ \localstartcolor[white]\vrule\!!height\ht#1\!!depth\dp#1\!!width\wd#1\localstopcolor
+ \hskip-\wd#1%
+ \box#1%
+ \dostopnegative}}
+
+%D There are in principle two ways to handle overprint: bound to colors
+%D or independent. For the moment we only support independent overprint
+%D handling. Here we deal with a per-document setting.
+
+\setupcolors
+ [\c!overprint=\v!no]
+
+\def\starttextoverprint
+ {\doifelse\@@cloverprint\v!yes
+ {\let\stoptextoverprint\dostopoverprint\dostartoverprint}
+ {\let\stoptextoverprint\donothing}}
+
+\let\stoptextoverprint\donothing
+
+\appendtoks \starttextoverprint \to \everystarttextproperties
+\appendtoks \stoptextoverprint \to \everystoptextproperties
+
+\protect \endinput
diff --git a/tex/context/base/colo-hex.mkii b/tex/context/base/colo-hex.mkii
new file mode 100644
index 000000000..dac2e46d0
--- /dev/null
+++ b/tex/context/base/colo-hex.mkii
@@ -0,0 +1,115 @@
+%D \module
+%D [ file=colo-hex,
+%D version=2004.06.23,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Hex Colors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifx\dodododefinecolor\undefined \else
+ \endinput
+\fi
+
+\writestatus{loading}{ConTeXt Color Macros / Hexadecimal}
+
+% \edef\testcolor{\string#FFC0C0}
+% \edef\testcolor{\string#55}
+%
+% \setupcolors[state=start]
+%
+% \expanded{\definecolor[thehexcolor][\hexcolorspec\testcolor]}
+%
+% \checkhexcolor[\testcolor]
+%
+% \definecolor[thehexcolor][\testcolor]
+%
+% \starttext
+%
+% test \color[thehexcolor]{rood}
+% test \color[red]{rood}
+% test \color[\testcolor]{rood}
+%
+% \stoptext
+
+\unprotect
+
+\newdimen\hexcolorfraction \hexcolorfraction=\dimexpr(1pt/256)
+
+\chardef\hexcolorprefix=`#
+
+\def\hexcolorspec #1{\expandafter\dohexcolorspec #1\empty\empty\empty\empty\relax}
+\def\hexcolorpattern#1{\expandafter\dohexcolorpattern#1\empty\empty\empty\empty\relax}
+
+\ifx\dohexstringtonumber\undefined \def\dohexstringtonumber{"} \fi
+
+\def\hexcolorcomponent#1#2%
+ {\ifnum\dohexstringtonumber#1#2=\zerocount0\else\ifnum\dohexstringtonumber#1#2=\plusone1\else
+ \expandafter\withoutpt\the\dimexpr(\dohexstringtonumber#1#2\hexcolorfraction)%
+ \fi\fi}
+
+\def\dohexcolorspec#1#2#3#4#5#6#7#8\relax
+ {\ifx#4\empty
+ s=\hexcolorcomponent#2#3%
+ \else
+ r=\hexcolorcomponent#2#3,g=\hexcolorcomponent#4#5,b=\hexcolorcomponent#6#7%
+ \fi}
+
+\def\dohexcolorpattern#1#2#3#4#5#6#7#8\relax
+ {0\ifx#4\empty
+ S:\hexcolorcomponent#2#3%
+ \else
+ R:\hexcolorcomponent#2#3:\hexcolorcomponent#4#5:\hexcolorcomponent#6#7%
+ \fi:0:0}
+
+\def\doifhexcolorelse#1%
+ {\expandafter\dodoifhexcolorelse#10\od} % 0 is a dirty trick to catch an empty #1
+
+\def\dodoifhexcolorelse#1#2\od
+ {\ifnum`#1=\hexcolorprefix
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\docheckhexcolor#1%
+ {\doifhexcolorelse{#1}{\doifundefined{#1}{\setxvalue{\??cr#1}{\hexcolorpattern{#1}}}}\donothing}
+
+\def\checkhexcolor[#1]%
+ {\expanded{\docheckhexcolor{#1}}}
+
+\def\colorHpattern{\@EA\hexcolorpattern\@EA{\@EA*\@@cl@@h}} % * == dummy placeholder
+
+\let\dodododefinecolor\dododefinecolor % we will overload this one
+
+\def\dododefinecolor#1#2#3#4[#5][#6]%
+ {\doifhexcolorelse{#6}
+ {\setxvalue{\??cr#5}{\hexcolorpattern{#6}}}
+ {\dodododefinecolor#1#2#3#4[#5][#6]}}
+
+%D For Adam Lindsay and his XeTeX special driver:
+
+% because we intercept the zero condition, the .23pt in 1.23pt will disappear in the
+% ifcase zero part branch
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<.005\points
+ 00\else\lchexnumbers{\the\dimexpr(255\dimexpr(#1\points)\relax+.5\points)\relax}%
+ \fi}
+
+% the faster one
+
+\newdimen\hex@color@a \hex@color@a=.005pt
+\newdimen\hex@color@b \hex@color@b=.5pt
+\chardef \hex@color@c =255
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<\hex@color@a
+ 00\else\lchexnumbers{\the\dimexpr(#1\points*\hex@color@c+\hex@color@b)\relax}%
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/colo-hex.mkiv b/tex/context/base/colo-hex.mkiv
new file mode 100644
index 000000000..b31321b7e
--- /dev/null
+++ b/tex/context/base/colo-hex.mkiv
@@ -0,0 +1,115 @@
+%D \module
+%D [ file=colo-hex,
+%D version=2004.06.23,
+%D title=\CONTEXT\ Color Macros,
+%D subtitle=Hex Colors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Not yet supported in \MKIV.
+
+\endinput
+
+\writestatus{loading}{ConTeXt Color Macros / Hexadecimal}
+
+% \edef\testcolor{\string#FFC0C0}
+% \edef\testcolor{\string#55}
+%
+% \setupcolors[state=start]
+%
+% \expanded{\definecolor[thehexcolor][\hexcolorspec\testcolor]}
+%
+% \checkhexcolor[\testcolor]
+%
+% \definecolor[thehexcolor][\testcolor]
+%
+% \starttext
+%
+% test \color[thehexcolor]{rood}
+% test \color[red]{rood}
+% test \color[\testcolor]{rood}
+%
+% \stoptext
+
+\unprotect
+
+\newdimen\hexcolorfraction \hexcolorfraction=\dimexpr1pt/256\relax
+
+\chardef\hexcolorprefix=`#
+
+\def\hexcolorspec #1{\expandafter\dohexcolorspec #1\empty\empty\empty\empty\relax}
+\def\hexcolorpattern#1{\expandafter\dohexcolorpattern#1\empty\empty\empty\empty\relax}
+
+\ifx\dohexstringtonumber\undefined \def\dohexstringtonumber{"} \fi
+
+\def\hexcolorcomponent#1#2%
+ {\ifnum\dohexstringtonumber#1#2=\zerocount0\else\ifnum\dohexstringtonumber#1#2=\plusone1\else
+ \expandafter\withoutpt\the\dimexpr(\dohexstringtonumber#1#2\hexcolorfraction)%
+ \fi\fi}
+
+\def\dohexcolorspec#1#2#3#4#5#6#7#8\relax
+ {\ifx#4\empty
+ s=\hexcolorcomponent#2#3%
+ \else
+ r=\hexcolorcomponent#2#3,g=\hexcolorcomponent#4#5,b=\hexcolorcomponent#6#7%
+ \fi}
+
+\def\dohexcolorpattern#1#2#3#4#5#6#7#8\relax
+ {0\ifx#4\empty
+ S:\hexcolorcomponent#2#3%
+ \else
+ R:\hexcolorcomponent#2#3:\hexcolorcomponent#4#5:\hexcolorcomponent#6#7%
+ \fi:0:0}
+
+\def\doifhexcolorelse#1%
+ {\expandafter\dodoifhexcolorelse#10\od} % 0 is a dirty trick to catch an empty #1
+
+\def\dodoifhexcolorelse#1#2\od
+ {\ifnum`#1=\hexcolorprefix
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\docheckhexcolor#1%
+ {\doifhexcolorelse{#1}{\doifundefined{#1}{\setxvalue{\??cr#1}{\hexcolorpattern{#1}}}}\donothing}
+
+\def\checkhexcolor[#1]%
+ {\expanded{\docheckhexcolor{#1}}}
+
+\def\colorHpattern{\@EA\hexcolorpattern\@EA{\@EA*\@@cl@@h}} % * == dummy placeholder
+
+\let\dodododefinecolor\dododefinecolor % we will overload this one
+
+\def\dododefinecolor#1#2#3#4[#5][#6]%
+ {\doifhexcolorelse{#6}
+ {\setxvalue{\??cr#5}{\hexcolorpattern{#6}}}
+ {\dodododefinecolor#1#2#3#4[#5][#6]}}
+
+%D For Adam Lindsay and his XeTeX special driver:
+
+% because we intercept the zero condition, the .23pt in 1.23pt will disappear in the
+% ifcase zero part branch
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<.005\points
+ 00\else\lchexnumbers{\the\dimexpr(255\dimexpr(#1\points)\relax+.5\points)\relax}%
+ \fi}
+
+% the faster one
+
+\newdimen\hex@color@a \hex@color@a=.005pt
+\newdimen\hex@color@b \hex@color@b=.5pt
+\chardef \hex@color@c =255
+
+\def\colorhexcomponent#1%
+ {\ifdim#1\points<\hex@color@a
+ 00\else\lchexnumbers{\the\dimexpr(#1\points*\hex@color@c+\hex@color@b)\relax}%
+ \fi}
+
+\protect \endinput
diff --git a/tex/context/base/colo-hex.tex b/tex/context/base/colo-hex.tex
index 8d5c3f86f..7d223c131 100644
--- a/tex/context/base/colo-hex.tex
+++ b/tex/context/base/colo-hex.tex
@@ -1,119 +1,3 @@
-%D \module
-%D [ file=colo-hex,
-%D version=2004.06.23,
-%D title=\CONTEXT\ Color Macros,
-%D subtitle=Hex Colors,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+% this is just a stub
-\beginLUATEX
- \endinput
-\endLUATEX
-
-\ifx\dodododefinecolor\undefined \else
- \endinput
-\fi
-
-\writestatus{loading}{Context Color Macros / hexadecimal}
-
-% \edef\testcolor{\string#FFC0C0}
-% \edef\testcolor{\string#55}
-%
-% \setupcolors[state=start]
-%
-% \expanded{\definecolor[thehexcolor][\hexcolorspec\testcolor]}
-%
-% \checkhexcolor[\testcolor]
-%
-% \definecolor[thehexcolor][\testcolor]
-%
-% \starttext
-%
-% test \color[thehexcolor]{rood}
-% test \color[red]{rood}
-% test \color[\testcolor]{rood}
-%
-% \stoptext
-
-\unprotect
-
-\newdimen\hexcolorfraction \hexcolorfraction=\dimexpr(1pt/256)
-
-\chardef\hexcolorprefix=`#
-
-\def\hexcolorspec #1{\expandafter\dohexcolorspec #1\empty\empty\empty\empty\relax}
-\def\hexcolorpattern#1{\expandafter\dohexcolorpattern#1\empty\empty\empty\empty\relax}
-
-\ifx\dohexstringtonumber\undefined \def\dohexstringtonumber{"} \fi
-
-\def\hexcolorcomponent#1#2%
- {\ifnum\dohexstringtonumber#1#2=\zerocount0\else\ifnum\dohexstringtonumber#1#2=\plusone1\else
- \expandafter\withoutpt\the\dimexpr(\dohexstringtonumber#1#2\hexcolorfraction)%
- \fi\fi}
-
-\def\dohexcolorspec#1#2#3#4#5#6#7#8\relax
- {\ifx#4\empty
- s=\hexcolorcomponent#2#3%
- \else
- r=\hexcolorcomponent#2#3,g=\hexcolorcomponent#4#5,b=\hexcolorcomponent#6#7%
- \fi}
-
-\def\dohexcolorpattern#1#2#3#4#5#6#7#8\relax
- {0\ifx#4\empty
- S:\hexcolorcomponent#2#3%
- \else
- R:\hexcolorcomponent#2#3:\hexcolorcomponent#4#5:\hexcolorcomponent#6#7%
- \fi:0:0}
-
-\def\doifhexcolorelse#1%
- {\expandafter\dodoifhexcolorelse#10\od} % 0 is a dirty trick to catch an empty #1
-
-\def\dodoifhexcolorelse#1#2\od
- {\ifnum`#1=\hexcolorprefix
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-\def\docheckhexcolor#1%
- {\doifhexcolorelse{#1}{\doifundefined{#1}{\setxvalue{\??cr#1}{\hexcolorpattern{#1}}}}\donothing}
-
-\def\checkhexcolor[#1]%
- {\expanded{\docheckhexcolor{#1}}}
-
-\def\colorHpattern{\@EA\hexcolorpattern\@EA{\@EA*\@@cl@@h}} % * == dummy placeholder
-
-\let\dodododefinecolor\dododefinecolor % we will overload this one
-
-\def\dododefinecolor#1#2#3#4[#5][#6]%
- {\doifhexcolorelse{#6}
- {\setxvalue{\??cr#5}{\hexcolorpattern{#6}}}
- {\dodododefinecolor#1#2#3#4[#5][#6]}}
-
-%D For Adam Lindsay and his XeTeX special driver:
-
-% because we intercept the zero condition, the .23pt in 1.23pt will disappear in the
-% ifcase zero part branch
-
-\def\colorhexcomponent#1%
- {\ifdim#1\points<.005\points
- 00\else\lchexnumbers{\the\dimexpr(255\dimexpr(#1\points)\relax+.5\points)\relax}%
- \fi}
-
-% the faster one
-
-\newdimen\hex@color@a \hex@color@a=.005pt
-\newdimen\hex@color@b \hex@color@b=.5pt
-\chardef \hex@color@c =255
-
-\def\colorhexcomponent#1%
- {\ifdim#1\points<\hex@color@a
- 00\else\lchexnumbers{\the\dimexpr(#1\points*\hex@color@c+\hex@color@b)\relax}%
- \fi}
-
-\protect \endinput
+\loadmarkfile{colo-hex}
diff --git a/tex/context/base/colo-ini.lua b/tex/context/base/colo-ini.lua
index 777c88572..c615aad7f 100644
--- a/tex/context/base/colo-ini.lua
+++ b/tex/context/base/colo-ini.lua
@@ -18,38 +18,20 @@ if not modules then modules = { } end modules ['colo-ini'] = {
-- todo: %s -> %f
-backends = backends or { }
-backends.pdf = backends.pdf or { }
-backend = backends.pdf
+local texsprint = tex.sprint
+local concat =table.concat
+local format, gmatch, gsub, lower = string.format, string.gmatch, string.gsub, string.lower
-local texsprint, format, concat = tex.sprint, string.format, table.concat
-
-local s_template_g = "\\dodoPDFregistergrayspotcolor{%s}{%s}{%s}{%s}{%s}" -- n f d p s (p can go away)
-local s_template_r = "\\dodoPDFregisterrgbspotcolor {%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p r g b
-local s_template_c = "\\dodoPDFregistercmykspotcolor{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p c m y k
-
-function backends.pdf.registergrayspotcolor(n,f,d,p,s) states.collect(s_template_g:format(n,f,d,p,s)) end
-function backends.pdf.registerrgbspotcolor (n,f,d,p,r,g,b) states.collect(s_template_r:format(n,f,d,p,r,g,b)) end
-function backends.pdf.registercmykspotcolor(n,f,d,p,c,m,y,k) states.collect(s_template_c:format(n,f,d,p,c,m,y,k)) end
-
-local m_template_g = "\\doPDFregistergrayindexcolor{%s}{%s}{%s}{%s}{%s}" -- n f d p s (p can go away)
-local m_template_r = "\\doPDFregisterrgbindexcolor {%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p r g b
-local m_template_c = "\\doPDFregistercmykindexcolor{%s}{%s}{%s}{%s}{%s}{%s}{%s}{%s}" -- n f d p c m y k
-
-function backends.pdf.registergrayindexcolor(n,f,d,p,s) states.collect(m_template_g:format(n,f,d,p,s)) end
-function backends.pdf.registerrgbindexcolor (n,f,d,p,r,g,b) states.collect(m_template_r:format(n,f,d,p,r,g,b)) end
-function backends.pdf.registercmykindexcolor(n,f,d,p,c,m,y,k) states.collect(m_template_c:format(n,f,d,p,c,m,y,k)) end
+ctx = ctx or { }
+ctx.aux = ctx.aux or { }
-local s_template_e = "\\doPDFregisterspotcolorname{%s}{%s}" -- name, e
+local ctxcatcodes = tex.ctxcatcodes
-function backends.pdf.registerspotcolorname(name,e)
- if e and e ~= "" then
- texsprint(tex.ctxcatcodes,format(s_template_e,name,e)) -- todo in new backend: e:gsub(" ","#20")
- end
-end
+local registrations = backends.registrations
-ctx = ctx or { }
-ctx.aux = ctx.aux or { }
+local a_color = attributes.private('color')
+local a_transparency = attributes.private('transparency')
+local a_colorspace = attributes.private('colorspace')
local a_l_c_template = "\\setevalue{(ca:%s)}{%s}" ..
"\\setevalue{(cs:%s)}{\\dosetattribute{color}{%s}}"
@@ -59,10 +41,10 @@ local f_l_c_template = "\\setvalue {(ca:%s)}{\\doinheritca{%s}}" ..
"\\setvalue {(cs:%s)}{\\doinheritcs{%s}}"
local f_g_c_template = "\\setgvalue{(ca:%s)}{\\doinheritca{%s}}" ..
"\\setgvalue{(cs:%s)}{\\doinheritcs{%s}}"
-local r_l_c_template = "\\letbeundefined{(ca:%s)}" ..
- "\\letbeundefined{(cs:%s)}"
-local r_g_c_template = "\\global\\letbeundefined{(ca:%s)}" ..
- "\\global\\letbeundefined{(cs:%s)}"
+local r_l_c_template = "\\localundefine{(ca:%s)}" ..
+ "\\localundefine{(cs:%s)}"
+local r_g_c_template = "\\globalundefine{(ca:%s)}" ..
+ "\\globalundefine{(cs:%s)}"
local a_l_t_template = "\\setevalue{(ta:%s)}{%s}" ..
"\\setevalue{(ts:%s)}{\\dosetattribute{transparency}{%s}}"
@@ -72,68 +54,68 @@ local f_l_t_template = "\\setvalue {(ta:%s)}{\\doinheritta{%s}}" ..
"\\setvalue {(ts:%s)}{\\doinheritts{%s}}"
local f_g_t_template = "\\setgvalue{(ta:%s)}{\\doinheritta{%s}}" ..
"\\setgvalue{(ts:%s)}{\\doinheritts{%s}}"
-local r_l_t_template = "\\letbeundefined{(ta:%s)}" ..
- "\\letbeundefined{(ts:%s)}"
-local r_g_t_template = "\\global\\letbeundefined{(ta:%s)}" ..
- "\\global\\letbeundefined{(ts:%s)}"
+local r_l_t_template = "\\localundefine{(ta:%s)}" ..
+ "\\localundefine{(ts:%s)}"
+local r_g_t_template = "\\globalundefine{(ta:%s)}" ..
+ "\\globalundefine{(ts:%s)}"
function ctx.aux.definecolor(name, ca, global)
if ca and ca > 0 then
if global then
- texsprint(tex.ctxcatcodes,a_g_c_template:format(name, ca, name, ca))
+ texsprint(ctxcatcodes,format(a_g_c_template, name, ca, name, ca))
else
- texsprint(tex.ctxcatcodes,a_l_c_template:format(name, ca, name, ca))
+ texsprint(ctxcatcodes,format(a_l_c_template, name, ca, name, ca))
end
else
if global then
- texsprint(tex.ctxcatcodes,r_g_c_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_g_c_template, name, name))
else
- texsprint(tex.ctxcatcodes,r_l_c_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_l_c_template, name, name))
end
end
end
function ctx.aux.inheritcolor(name, ca, global)
if ca and ca ~= "" then
if global then
- texsprint(tex.ctxcatcodes,f_g_c_template:format(name, ca, name, ca))
+ texsprint(ctxcatcodes,format(f_g_c_template, name, ca, name, ca))
else
- texsprint(tex.ctxcatcodes,f_l_c_template:format(name, ca, name, ca))
+ texsprint(ctxcatcodes,format(f_l_c_template, name, ca, name, ca))
end
else
if global then
- texsprint(tex.ctxcatcodes,r_g_c_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_g_c_template, name, name))
else
- texsprint(tex.ctxcatcodes,r_l_c_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_l_c_template, name, name))
end
end
end
function ctx.aux.definetransparent(name, ta, global)
if ta and ta > 0 then
if global then
- texsprint(tex.ctxcatcodes,a_g_t_template:format(name, ta, name, ta))
+ texsprint(ctxcatcodes,format(a_g_t_template, name, ta, name, ta))
else
- texsprint(tex.ctxcatcodes,a_l_t_template:format(name, ta, name, ta))
+ texsprint(ctxcatcodes,format(a_l_t_template, name, ta, name, ta))
end
else
if global then
- texsprint(tex.ctxcatcodes,r_g_t_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_g_t_template, name, name))
else
- texsprint(tex.ctxcatcodes,r_l_t_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_l_t_template, name, name))
end
end
end
function ctx.aux.inherittransparent(name, ta, global)
if ta and ta ~= "" then
if global then
- texsprint(tex.ctxcatcodes,f_g_t_template:format(name, ta, name, ta))
+ texsprint(ctxcatcodes,format(f_g_t_template, name, ta, name, ta))
else
- texsprint(tex.ctxcatcodes,f_l_t_template:format(name, ta, name, ta))
+ texsprint(ctxcatcodes,format(f_l_t_template, name, ta, name, ta))
end
else
if global then
- texsprint(tex.ctxcatcodes,r_g_t_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_g_t_template, name, name))
else
- texsprint(tex.ctxcatcodes,r_l_t_template:format(name, name))
+ texsprint(ctxcatcodes,format(r_l_t_template, name, name))
end
end
end
@@ -173,13 +155,15 @@ local function registerspotcolor(parent,name,parentnumber,e,f,d,p)
local kind = colors.default -- else problems with shading etc
if kind == 1 then kind = v[1] end
if kind == 2 then -- name noffractions names p's r g b
- backend.registergrayspotcolor(parent,f,d,p,v[2])
+ registrations.grayspotcolor(parent,f,d,p,v[2])
elseif kind == 3 then
- backend.registerrgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
+ registrations.rgbspotcolor (parent,f,d,p,v[3],v[4],v[5])
elseif kind == 4 then
- backend.registercmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
+ registrations.cmykspotcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
+ end
+ if e and e ~= "" then
+ registrations.spotcolorname(parent,e)
end
- backends.pdf.registerspotcolorname(parent,e)
end
registered[parentnumber] = true
end
@@ -192,11 +176,11 @@ local function registermultitonecolor(parent,name,parentnumber,e,f,d,p) -- same
local kind = colors.default -- else problems with shading etc
if kind == 1 then kind = v[1] end
if kind == 2 then
- backend.registergrayindexcolor(parent,f,d,p,v[2])
+ registrations.grayindexcolor(parent,f,d,p,v[2])
elseif kind == 3 then
- backend.registerrgbindexcolor (parent,f,d,p,v[3],v[4],v[5])
+ registrations.rgbindexcolor (parent,f,d,p,v[3],v[4],v[5])
elseif kind == 4 then
- backend.registercmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
+ registrations.cmykindexcolor(parent,f,d,p,v[6],v[7],v[8],v[9])
end
end
registered[parentnumber] = true
@@ -227,8 +211,8 @@ function ctx.defineprocesscolor(name,str,global,freeze) -- still inconsistent co
ctx.aux.definetransparent(name, 0, global) -- can be sped up
end
elseif freeze then
- local ca = attributes.list[attributes.numbers['color']] [str]
- local ta = attributes.list[attributes.numbers['transparency']][str]
+ local ca = attributes.list[a_color] [str]
+ local ta = attributes.list[a_transparency][str]
if ca then
ctx.aux.definecolor(name, ca, global)
end
@@ -239,8 +223,8 @@ function ctx.defineprocesscolor(name,str,global,freeze) -- still inconsistent co
ctx.aux.inheritcolor(name, str, global)
ctx.aux.inherittransparent(name, str, global)
-- if global and str ~= "" then -- For Peter Rolf who wants access to the numbers in Lua. (Currently only global is supported.)
- -- attributes.list[attributes.numbers['color']] [name] = attributes.list[attributes.numbers['color']] [str] or -1 -- reset
- -- attributes.list[attributes.numbers['transparency']][name] = attributes.list[attributes.numbers['transparency']][str] or -1 -- reset
+ -- attributes.list[a_color] [name] = attributes.list[a_color] [str] or attributes.unsetvalue -- reset
+ -- attributes.list[a_transparency][name] = attributes.list[a_transparency][str] or attributes.unsetvalue
-- end
end
end
@@ -250,20 +234,11 @@ function ctx.isblack(ca) -- maybe commands
return (cv and cv[2] == 0) or false
end
--- function ctx.aux.colorattribute(name)
--- local al = attributes.list[attributes.numbers['color']]
--- return al[name] or 0
--- end
--- function ctx.aux.transparencyattribute(name)
--- local al = attributes.list[attributes.numbers['transparency']]
--- return al[name] or 0
--- end
-
function ctx.definespotcolor(name,parent,str,global)
if parent == "" or parent:find("=") then
ctx.registerspotcolor(name, parent)
elseif name ~= parent then
- local cp = attributes.list[attributes.numbers['color']][parent]
+ local cp = attributes.list[a_color][parent]
if cp then
local t = str:split_settings()
if t then
@@ -284,7 +259,7 @@ function ctx.definespotcolor(name,parent,str,global)
end
function ctx.registerspotcolor(parent, str)
- local cp = attributes.list[attributes.numbers['color']][parent]
+ local cp = attributes.list[a_color][parent]
if cp then
local e = ""
if str then
@@ -297,7 +272,7 @@ end
function ctx.definemultitonecolor(name,multispec,colorspec,selfspec)
local dd, pp, nn = { }, { }, { }
- for k,v in multispec:gmatch("(%a+)=([^%,]*)") do
+ for k,v in gmatch(multispec,"(%a+)=([^%,]*)") do
dd[#dd+1] = k
pp[#pp+1] = v
nn[#nn+1] = k
@@ -307,9 +282,9 @@ function ctx.definemultitonecolor(name,multispec,colorspec,selfspec)
local nof = #dd
if nof > 0 then
dd, pp, nn = concat(dd,','), concat(pp,','), concat(nn,'_')
- local parent = (nn:lower()):gsub("[^%d%a%.]+","_")
+ local parent = gsub(lower(nn),"[^%d%a%.]+","_")
ctx.defineprocesscolor(parent,colorspec..","..selfspec,true,true)
- local cp = attributes.list[attributes.numbers['color']][parent]
+ local cp = attributes.list[a_color][parent]
if cp then
registerspotcolor (parent, name, cp, "", nof, dd, pp)
registermultitonecolor(parent, name, cp, "", nof, dd, pp)
@@ -362,28 +337,26 @@ end
function ctx.formatcolor(ca,separator)
local cv = colors.value(ca)
if cv then
- local model = cv[1]
+ local c, f, t, model = { }, 13, 13, cv[1]
if model == 2 then
- return tostring(cv[2])
+ f, t = 2, 2
elseif model == 3 then
- return concat(cv,separator,3,5)
+ f, t = 3, 5
elseif model == 4 then
- return concat(cv,separator,6,9)
- else
- return tostring(cv[13])
+ f, t = 6, 9
end
+ for i=f,t do
+ c[#c+1] = format("%0.3f",cv[i])
+ end
+ return concat(c,separator)
else
- return tostring(0)
+ return format("%0.3f",0)
end
end
function ctx.formatgray(ca,separator)
local cv = colors.value(ca)
- if cv then
- return tostring(cv[2])
- else
- return tostring(0)
- end
+ return format("%0.3f",(cv and cv[2]) or 0)
end
function ctx.colorcomponents(ca)
@@ -433,7 +406,7 @@ function ctx.pdfcolor(model,ca,default) -- todo: use gray when no color
else
local n,f,d,p = cv[10],cv[11],cv[12],cv[13]
if type(p) == "string" then
- p = p:gsub(","," ") -- brr misuse of spot
+ p = gsub(p,","," ") -- brr misuse of spot
end
return format("/%s cs /%s CS %s SCN %s scn",n,n,p,p)
end
@@ -519,23 +492,23 @@ end
function ctx.resolvempgraycolor(csa,csb,model,s)
local ca = colors.register('color',nil,'gray',s)
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
end
function ctx.resolvemprgbcolor(csa,csb,model,r,g,b)
local ca = colors.register('color',nil,'rgb',r,g,b)
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
end
function ctx.resolvempcmykcolor(csa,csb,model,c,m,y,k)
local ca = colors.register('color',nil,'cmyk',c,m,y,k)
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
end
function ctx.resolvempspotcolor(csa,csb,model,n,f,d,p)
local ca = colors.register('color',nil,'spot',n,f,d,p)
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
- texsprint(tex.ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csa,ctx.pdfcolorvalue(model,ca)))
+ texsprint(ctxcatcodes,format("\\setxvalue{%s}{%s}",csb,ctx.pdfcolorspace(model,ca)))
end
-- literals needed to inject code in the mp stream, we cannot use attributes there
@@ -544,24 +517,24 @@ end
local intransparency = false
function ctx.pdfrgbliteral(model,r,g,b)
- texsprint(tex.ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'rgb',r,g,b))))
+ texsprint(ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'rgb',r,g,b))))
end
function ctx.pdfcmykliteral(model,c,m,y,k)
- texsprint(tex.ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'cmyk',c,m,y,k))))
+ texsprint(ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'cmyk',c,m,y,k))))
end
function ctx.pdfgrayliteral(model,s)
- texsprint(tex.ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'gray',s))))
+ texsprint(ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'gray',s))))
end
function ctx.pdfspotliteral(model,n,f,d,p)
- texsprint(tex.ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'spot',n,f,d,p)))) -- incorrect
+ texsprint(ctxcatcodes,format("\\pdfliteral{%s}",ctx.pdfcolor(model,colors.register('color',nil,'spot',n,f,d,p)))) -- incorrect
end
function ctx.pdftransparencyliteral(a,t)
intransparency = true
- texsprint(tex.ctxcatcodes,format("\\pdfliteral{/Tr%s gs}",transparencies.register(nil,a,t)))
+ texsprint(ctxcatcodes,format("\\pdfliteral{/Tr%s gs}",transparencies.register(nil,a,t)))
end
function ctx.pdffinishtransparency()
if intransparency then
intransparency = false
- texsprint(tex.ctxcatcodes,"\\pdfliteral{/Tr0 gs}") -- we happen to know this -)
+ texsprint(ctxcatcodes,"\\pdfliteral{/Tr0 gs}") -- we happen to know this -)
end
end
diff --git a/tex/context/base/colo-ini.mkii b/tex/context/base/colo-ini.mkii
index 745bb1679..2d2a7bdaa 100644
--- a/tex/context/base/colo-ini.mkii
+++ b/tex/context/base/colo-ini.mkii
@@ -1,6 +1,6 @@
%D \module
%D [ file=colo-ini,
-%D version=1997.04.01,
+%D version=2007.08.08,
%D title=\CONTEXT\ Color Macros,
%D subtitle=Initialization,
%D author=Hans Hagen,
@@ -11,8 +11,872 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D We need to clean this up further but first we hav eto make sure that mkiv
+%D code works ok.
+
+\writestatus{loading}{ConTeXt Color Macros / Initialization}
+
+%D This module implements color. Since \MKII\ and \MKIV\ use a completely
+%D different approach, this module only implements a few generic mechanisms.
+
\unprotect
+\chardef\colorversion=1 % temp, needed for tracing purposes, mkiv transition
+
+%D We use a couple of local registers. That way we don't have
+%D to group when converting colors. By the way, this is not
+%D really faster. We can sqeeze half a second runtime for 50K
+%D switches on a 1G machine, but the macros will become rather
+%D ugly then. To mention one such improvement: no colon
+%D after the key character (.25 sec).
+
+\newdimen\colordimen
+\newcount\colorcount
+
+%D When typesetting for paper, we prefer using the \cap{CMYK}
+%D color space, but for on||screen viewing we prefer \cap{RGB}
+%D (the previous implementation supported only this scheme).
+%D Independant of such specifications, we support some automatic
+%D conversions:
+%D
+%D \startitemize[packed]
+%D \item convert all colors to \cap{RGB}
+%D \item convert all colors to \cap{CMYK}
+%D \item convert all colors to gray scales
+%D \stopitemize
+%D
+%D We also support optimization of colors to gray scales.
+%D
+%D \startitemize[continue]
+%D \item reduce gray colors to gray scales
+%D \item reduce \cap{CMY} components to \cap{K}
+%D \stopitemize
+%D
+%D These options are communicated by means of:
+
+\newif\ifRGBsupported
+\newif\ifCMYKsupported
+\newif\ifSPOTsupported
+\newif\ifpreferGRAY
+\newif\ifGRAYprefered
+\newif\ifreduceCMYK
+\newif\ifconverttoGRAY
+\newif\ifweightGRAY \weightGRAYtrue
+
+\newif\ifconvertMPcolors
+\newif\ifreduceMPcolors
+\newif\ifforcegrayMPcolors
+
+%D The last boolean controls reduction of \cap{CMYK} to
+%D \cap{CMY} colors. When set to true, the black component
+%D is added to the other ones.
+%D
+%D Prefering gray is not the same as converting to gray.
+%D Conversion treats each color components in a different way,
+%D while prefering is just a reduction and thus a
+%D space||saving option.
+
+\newif\iffreezecolors \freezecolorsfalse
+\newif\ifincolor % true if colors enabled
+\newif\iflocalcolor
+
+\let\colorlist \empty
+\let\currentspotcolor \empty
+\let\allspotcolors \empty
+\let\usedspotcolors \empty
+\let\usedcolorchannels\empty
+\let\currentpalet \empty
+
+%D \macros
+%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor}
+%D
+%D \startbuffer
+%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%D
+%D \definespotcolor [blue-100] [blue] [p=1]
+%D \definespotcolor [yellow-100] [yellow] [p=1]
+%D
+%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%D
+%D \useexternalfigure[demofig][mill.png][object=no]
+%D
+%D \startcombination[4*1]
+%D {\externalfigure[demofig]} {no color}
+%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
+%D {\externalfigure[demofig][color=blue-100]} {spot color}
+%D {\externalfigure[demofig][color=yellow-100]} {spot color}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\def\definecolor {\dodoubleargument\dodefinecolor}
+\def\defineglobalcolor {\dodoubleargument\dodefineglobalcolor}
+\def\definenamedcolor {\dodoubleargument\dodefinenamedcolor}
+\def\definespotcolor {\dotripleargument\dodefinespotcolor}
+\def\definemultitonecolor{\doquadrupleempty\dodefinemultitonecolor}
+
+% check: registerusedspotcolors
+% check: registerusedcolorchannels
+
+%D \macros
+%D {doifcolorelse, doifcolor}
+%D
+%D Switching to a color is done by means of the following
+%D command. Later on we will explain the use of palets. We
+%D define ourselves a color conditional first.
+
+\ifx\doifcolorelse\undefined
+ \let\doifcolorelse\secondoftwoarguments
+ \let\doifcolor \gobbleoneargument
+\fi
+
+%D \macros
+%D {localstartcolor,localstopcolor}
+%D
+%D Simple color support, that is without nesting, is provided
+%D by:
+
+\ifx\localstartcolor\undefined
+ \let\localstartcolor\undefined
+ \let\localstopcolor \undefined
+\fi
+
+%D \macros
+%D {faststartcolor,faststopcolor}
+%D
+%D No checking for arguments and such:
+
+\ifx\faststartcolor\undefined
+ \def\faststartcolor[#1]{}
+ \def\faststopcolor {}
+\fi
+
+%D These local ones may go away in future versions.
+
+%D \macros
+%D {startcolor,stopcolor}
+%D
+%D The more save method, the one that saves the current color
+%D state and returns to this state afterward, is activated by:
+%D
+%D \showsetup{startcolor}
+
+\ifx\startcolor\undefined
+ \let\startcolor\undefined
+ \let\stopcolor \undefined
+\fi
+
+%D \macros
+%D {startcurrentcolor,stopcurrentcolor}
+
+\def\startcurrentcolor{\startcolor[\outercolorname]}
+\def\stopcurrentcolor {\stopcolor}
+
+%D \macros
+%D {color,graycolor}
+%D
+%D This leaves the simple color command:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+
+\ifx\color\undefined
+ \def\color [#1]{}
+ \def\graycolor[#1]{}
+ \def\gray {\graycolor}
+\fi
+
+%D \macros
+%D {localstartraster,localstopraster,
+%D startraster,stopraster,raster}
+%D
+%D The previous conversions are not linear and treat each color
+%D component according to human perception curves. Pure gray
+%D (we call them rasters) has equal color components. In
+%D \CONTEXT\ rasters are only used as backgrounds and these
+%D don't cross page boundaries in the way color does. Therefore
+%D we don't need stacks and marks. Just to be compatible with
+%D color support we offer both 'global' and 'local' commands.
+
+\ifx\startraster\undefined
+ \def\startraster [#1]{}
+ \def\stopraster {}
+ \def\raster [#1]{}
+ \def\localstartraster[#1]{}
+ \def\localstopraster {}
+\fi
+
+%D \macros
+%D {colorvalue, grayvalue}
+%D
+%D We can typeset the color components using \type{\colorvalue} and
+%D \type{\grayvalue}. The commands:
+%D
+%D \startbuffer
+%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
+%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D show us:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+
+\def\colorformatseparator{ }
+
+\ifx\colorvalue\undefined
+ \let\colorvalue\gobbleoneargument
+ \let\grayvalue \gobbleoneargument
+\fi
+
+% check: \currentcolorname
+% check: \outercolorname
+
+%D \macros
+%D {setupcolor}
+%D
+%D Color definitions can be grouped in files with the name:
+%D
+%D \starttyping
+%D \f!colorprefix-identifier.tex
+%D \stoptyping
+%D
+%D where \type{\f!colorprefix} is \unprotect {\tttf \f!colorprefix}.
+%D Loading such a file is done by \protect
+%D
+%D \showsetup{setupcolor}
+%D
+%D Some default colors are specified in \type{colo-rgb.tex},
+%D which is loaded into the format by:
+%D
+%D \starttyping
+%D \setupcolor[rgb]
+%D \stoptyping
+
+\let\colorstyle\empty
+
+\def\setupcolor
+ {\dosingleargument\dosetupcolor}
+
+\def\dosetupcolor[#1]%
+ {\doifnot{#1}\colorstyle
+ {\def\colorstyle{#1}%
+ \processcommalist[#1]\dodosetupcolor}}
+
+\def\dodosetupcolor#1%
+ {\makeshortfilename[\truefilename{\f!colorprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!colors4\colorstyle}
+ {\showmessage\m!colors5\colorstyle}%
+ \stopreadingfile}
+
+\let\usecolors\setupcolor
+
+% check: \chardef\currentcolorchannel=0
+% check: \startcolormode
+% check: \newif\iffilterspotcolor \filterspotcolorfalse
+% check: \newif\ifdoingspotcolor \doingspotcolorfalse
+% check: \registercolorchannel
+
+%D \macros
+%D {definetransparency}
+%D
+%D This command numbers to names:
+
+\def\definetransparency
+ {\dodoubleargument\dodefinetransparency}
+
+\def\setupcolors
+ {\dosingleargument\dosetupcolors}
+
+\def\resetcolorsplitting
+ {\chardef\currentcolorchannel\zerocount
+ \let\currentspotcolor\empty
+ \filterspotcolorfalse}
+
+\def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplit\fi}
+\def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplit-\fi}
+
+\def\setcolorsplitting
+ {\resetsystemmode{\v!color\colorsplitsuffix}%
+ \resetcolorsplitting
+ \processaction
+ [\@@clsplit]
+ [ c=>\chardef\currentcolorchannel1,%
+ m=>\chardef\currentcolorchannel2,%
+ y=>\chardef\currentcolorchannel3,%
+ k=>\chardef\currentcolorchannel4,%
+ r=>\chardef\currentcolorchannel5,%
+ g=>\chardef\currentcolorchannel6,%
+ b=>\chardef\currentcolorchannel7,%
+ s=>\chardef\currentcolorchannel8,%
+ \v!no=>,% \currentcolorchannel0,% all colors
+ \s!default=>,% \currentcolorchannel0,% all colors
+ \s!unknown=>\filterspotcolortrue
+ \edef\currentspotcolor{\commalistelement}]%
+ \setsystemmode{\v!color\colorsplitsuffix}%
+ \iffilterspotcolor \let\@@clrgb\v!no \fi}
+
+\ifx\dosetupcolormodel\undefined
+ \let\dosetupcolormodel\relax
+\fi
+
+\def\dosetupcolors[#1]% some no longer make sense in MkIV
+ {\getparameters[\??cl][#1]%
+ \doifelse\@@clspot\v!yes
+ \SPOTsupportedtrue
+ \SPOTsupportedfalse
+ \doifelsenothing\@@clsplit
+ \resetcolorsplitting
+ \setcolorsplitting
+ \doifelse\@@clreduction\v!yes
+ \reduceCMYKtrue
+ \reduceCMYKfalse
+ \doifelse\@@clexpansion\v!yes
+ \freezecolorstrue
+ \freezecolorsfalse
+ \doifelse\@@clcriterium\v!all
+ \hidesplitcolortrue
+ \hidesplitcolorfalse
+ \doifelse\@@clrgb\v!no
+ {\ifRGBsupported \ifproductionrun\showmessage\m!colors {9}\v!rgb \fi\RGBsupportedfalse \fi}
+ {\ifRGBsupported \else\ifproductionrun\showmessage\m!colors{10}\v!rgb \fi\RGBsupportedtrue \fi}%
+ \doifelse\@@clcmyk\v!no
+ {\ifCMYKsupported \ifproductionrun\showmessage\m!colors {9}\v!cmyk \fi\CMYKsupportedfalse\fi}
+ {\ifCMYKsupported\else\ifproductionrun\showmessage\m!colors{10}\v!cmyk \fi\CMYKsupportedtrue \fi}%
+ \doifelse\@@clmpcmyk\v!no
+ {\ifMPcmykcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!cmyk}\fi\MPcmykcolorsfalse \fi}
+ {\ifMPcmykcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!cmyk}\fi\MPcmykcolorstrue \fi}%
+ \doifelse\@@clmpspot\v!no
+ {\ifMPspotcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!spot}\fi\MPspotcolorsfalse \fi}
+ {\ifMPspotcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!spot}\fi\MPspotcolorstrue \fi}%
+ \preferGRAYfalse
+ \processaction
+ [\@@clconversion]
+ [ \v!yes=>\preferGRAYtrue,
+ \v!always=>\preferGRAYtrue\RGBsupportedfalse\CMYKsupportedfalse]%
+ \ifRGBsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \else\ifCMYKsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \convertMPcolorstrue
+ \ifreduceCMYK
+ \reduceMPcolorstrue
+ \fi
+ \else
+ \ifconverttoGRAY\else\showmessage\m!colors{11}\empty\fi
+ \converttoGRAYtrue
+ \forcegrayMPcolorstrue
+ \convertMPcolorsfalse
+ \reduceMPcolorsfalse
+ \fi\fi
+ \processaction
+ [\@@clstate]
+ [ \v!global=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse,
+ \v!local=>\ifincolor\else\showmessage\m!colors2\colorstyle\fi
+ \incolortrue\localcolortrue,
+ \v!start=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse
+ \let\@@clstate\v!global,
+ \v!stop=>\incolorfalse\localcolorfalse
+ \forcegrayMPcolorstrue]%
+ \dosetupcolormodel
+ \initializemaintextcolor}
+
+%D \macros
+%D {startregistercolor,stopregistercolor,permitcolormode}
+%D
+%D If you only want to register a color, the switch \type
+%D {\ifpermitcolormode} can be used. That way the nested
+%D colors know where to go back to.
+
+\ifx\startregistercolor\undefined
+ \def\startregistercolor[#1]{}
+ \def\stopregistercolor {}
+\fi
+
+%D We use these macros for implementing text colors
+%D (actually, the first application was in foreground
+%D colors).
+%D
+%D \starttyping
+%D \starttextcolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stoptextcolor
+%D \stoptyping
+%D
+%D This is more efficient than the alternative:
+%D
+%D \starttyping
+%D \setupbackgrounds[text][foregroundcolor=red]
+%D \startregistercolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stopregistercolor
+%D \stoptyping
+
+\def\maintextcolor {}
+\def\defaulttextcolor {black}
+\def\@@themaintextcolor{themaintextcolor}
+
+\ifx\initializemaintextcolor\undefined
+ \def\starttextcolor [#1]{}
+ \def\stoptextcolor {}
+ \def\initializemaintextcolor {}
+\fi
+
+\ifx\restoretextcolor\undefined % to be redone
+ \let\restoretextcolor \firstofoneargument
+ \let\localstarttextcolor\relax
+ \let\localstoptextcolor \relax
+\fi
+
+%D In this documentation we will not go into too much details
+%D on palets. Curious users can find more information on this
+%D topic in \from[use of color].
+%D
+%D At the moment we implemented color in \CONTEXT\ color
+%D printing was not yet on the desktop. In spite of this lack our
+%D graphics designer made colorfull illustrations. When printed
+%D on a black and white printer, distinctive colors can come
+%D out equally gray. We therefore decided to use only colors
+%D that were distinctive in colors as well as in black and
+%D white print.
+%D
+%D Although none of the graphic packages we used supported
+%D logical colors and global color redefition, we build this
+%D support into \CONTEXT. This enabled us to experiment and
+%D also prepared us for the future.
+
+%D \macros
+%D {definepalet}
+%D
+%D Colors are grouped in palets. The colors in such a palet can
+%D have colorful names, but best is to use names that specify
+%D their use, like {\em important} or {\em danger}. As a sort
+%D of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was
+%D reading 'A hort history of time' of S.~Hawkins, so that's
+%D why we stuck to quarks.}
+%D
+%D \starttyping
+%D \definepalet
+%D [alfa]
+%D [ top=rood:7,
+%D bottom=groen:6,
+%D up=blauw:5,
+%D down=cyaan:4,
+%D strange=magenta:3,
+%D charm=geel:2]
+%D \stoptyping
+%D
+%D It's formal definition is:
+%D
+%D \showsetup{definepalet}
+%D
+%D Visualized, such a palet looks like:
+%D
+%D \startbuffer[palet]
+%D \showpalet [alfa] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \startlinecorrection
+%D \getbuffer[palet]
+%D \stoplinecorrection
+%D
+%D This bar shows both the color and gray alternatives of the
+%D palet components (not visible in black and white print).
+%D
+%D When needed, one can copy a palet by saying:
+%D
+%D \starttyping
+%D \definepalet [TEXcolorpretty] [colorpretty]
+%D \stoptyping
+%D
+%D This saves us some typing in for instance the modules that
+%D deal with pretty verbatim typesetting.
+
+\def\definepalet
+ {\dodoubleargument\dodefinepalet}
+
+\def\dodefinepalet[#1][#2]%
+ {\doifassignmentelse{#2}
+ {%\showmessage\m!colors6{#1}%
+ \letvalue{\??pa#1}\empty
+ \setevalue{\??pa\??pa#1}{#2}%
+ \def\dodododefinepalet[##1=##2]%
+ {\doifvaluesomething{\??pa#1}
+ {\setevalue{\??pa#1}{\csname\??pa#1\endcsname,}}%
+ \setevalue{\??pa#1}{\csname\??pa#1\endcsname##1}%
+ \dodefinepaletcolor{#1}{##1}{##2}}%
+ \def\dododefinepalet##1%
+ {\dodododefinepalet[##1]}%
+ \processcommalist[#2]\dododefinepalet}
+ {\doifdefined{\??pa#2}
+ {\expanded{\dodefinepalet[#1][\csname\??pa\??pa#2\endcsname]}}}}
+
+\ifx\dodefinepaletcolor\undefined
+ \let\dodefinepaletcolor\gobblethreearguments
+\fi
+
+\let\paletsize\!!zerocount
+
+\def\getpaletsize[#1]%
+ {\getcommacommandsize[\csname\??pa\??pa#1\endcsname]%
+ \edef\paletsize{\number\commalistsize}}
+
+%D Instead of refering to colors, one can also directly specify
+%D a color:
+%D
+%D \starttyping
+%D \definepalet[test][xx=green]
+%D \definepalet[test][xx={y=.4}]
+%D \stoptyping
+
+%D \macros
+%D {setuppalet}
+%D
+%D Colors are taken from the current palet, if defined.
+%D Setting the current palet is done by:
+%D
+%D \showsetup{setuppalet}
+
+\let\currentpalet\empty
+
+\def\setuppalet
+ {\dosingleempty\dosetuppalet}
+
+\def\dosetuppalet[#1]%
+ {\edef\currentpalet{#1}%
+ \ifx\currentpalet\empty
+ % seems to be a reset
+ \else\ifcsname\??pa\currentpalet\endcsname
+ \edef\currentpalet{#1:}%
+ \else
+ \showmessage\m!colors7\currentpalet
+ \let\currentpalet\empty
+ \fi\fi}
+
+%D \macros
+%D {showpalet}
+%D
+%D The previous visualization was typeset with:
+%D
+%D \typebuffer[palet]
+%D
+%D This commands is defined as:
+%D
+%D \showsetup{showpalet}
+
+\fetchruntimecommand \showpalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolorcomponents}
+%D
+%D \starttyping
+%D \showcolorcomponents[color-1,color-2]
+%D \stoptyping
+
+\fetchruntimecommand \showcolorcomponents {\f!colorprefix\s!run}
+
+%D \macros
+%D {definecolorgroup}
+%D
+%D The naming of the colors in this palet suggests some
+%D ordening, which in turn is suported by color grouping.
+%D
+%D \starttyping
+%D \definecolorgroup
+%D [red]
+%D [1.00:0.90:0.90,
+%D 1.00:0.80:0.80,
+%D 1.00:0.70:0.70,
+%D 1.00:0.55:0.55,
+%D 1.00:0.40:0.40,
+%D 1.00:0.25:0.25,
+%D 1.00:0.15:0.15,
+%D 0.90:0.00:0.00]
+%D \stoptyping
+%D
+%D In such a color group colors are numbered from~$1$ to~$n$.
+%D
+%D \showsetup{definecolorgroup}
+%D
+%D This kind of specification is not only more compact than
+%D defining each color separate, it also loads faster and takes
+%D less bytes.
+
+\def\definecolorgroup
+ {\dotripleempty\dodefinecolorgroup}
+
+\def\dododefinecolorgroupgray [#1][#2:#3]{\definecolor [#1:\the\colorcount][s=#2]}
+\def\dododefinecolorgrouprgb [#1][#2:#3:#4:#5]{\definecolor [#1:\the\colorcount][r=#2,g=#3,b=#4]}
+\def\dododefinecolorgroupcmyk[#1][#2:#3:#4:#5:#6]{\definecolor [#1:\the\colorcount][c=#2,m=#3=,y=#4,k=#5]}
+\def\dododefinecolorgroupspot [#1][#2:#3:#4]{\definespotcolor[#1:\the\colorcount][#2][p=#3]}
+
+\def\dododefinecolorgroup#1#2%
+ {\advance\colorcount\plusone
+ \getvalue{dododefinecolorgroup\currentcolorspace}[#1][#2:0:0:0:0]}
+
+\def\dodefinecolorgroup[#1][#2][#3]% obsolete, just use palets
+ {\ifthirdargument
+ \doifelsenothing{#2}{\let\currentcolorspace\v!rgb}{\def\currentcolorspace{#2}}%
+ \colorcount\zerocount
+ \processcommalist[#3]{\dododefinecolorgroup{#1}}%
+ \else
+ \doifinstringelse{:}{#2}
+ {\definecolorgroup[#1][\v!rgb][#2]}
+ {\doloop
+ {\doifdefinedelse{\??cr#2:\recurselevel}
+ {\setevalue{\??cr#1:\recurselevel}{\csname\??cr#2:\recurselevel\endcsname}}
+ {\exitloop}}}%
+ \fi}
+
+%D \macros
+%D {showcolorgroup}
+%D
+%D We can show the group by:
+%D
+%D \startbuffer
+%D \showcolorgroup [blue] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or in color:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D which uses:
+%D
+%D \showsetup{showcolorgroup}
+
+\fetchruntimecommand \showcolorgroup {\f!colorprefix\s!run}
+
+%D There are ten predefined color groups, like
+%D \color[green]{\em groen}, \color[red]{\em rood},
+%D \color[blue]{\em blauw}, \color[cyan]{\em cyaan},
+%D \color[magenta]{\em magenta} and \color[yellow]{\em geel}.
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\hss
+%D \showcolorgroup [red] [vertical,name,number]\hss
+%D \showcolorgroup [green] [vertical,name]\hss
+%D \showcolorgroup [blue] [vertical,name]\hss
+%D \showcolorgroup [cyan] [vertical,name]\hss
+%D \showcolorgroup [magenta][vertical,name]\hss
+%D \showcolorgroup [yellow] [vertical,name]\hss}
+%D \stoplinecorrection
+%D
+%D These groups are used to define palets {\em alfa} upto {\em
+%D zeta}. As long as we don't use colors from the same row, we
+%D get ourselves distinctive palets. By activating such a palet
+%D one gains access to its members {\em top} to {\em charm} (of
+%D course one should use more suitable names than these).
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\showpalet [alfa] [vertical,name,number]\hss
+%D \showpalet [beta] [vertical,name]\hss
+%D \showpalet [gamma] [vertical,name]\hss
+%D \showpalet [delta] [vertical,name]\hss
+%D \showpalet [epsilon] [vertical,name]\hss
+%D \showpalet [zeta] [vertical,name]}
+%D \stoplinecorrection
+%D
+%D By using the keyword \type {value} the individual color
+%D components are shown too. When printed in color, these
+%D showcases show both the colors and the gray value.
+
+%D \macros
+%D {comparepalet}
+%D
+%D There are some more testing macros available:
+%D
+%D \startbuffer
+%D \comparepalet [alfa]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows the palet colors against a background:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{comparepalet}
+
+\fetchruntimecommand \comparepalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {comparecolorgroup}
+%D
+%D The similar command:
+%D
+%D \startbuffer
+%D \comparecolorgroup [blue]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows color groups:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D this commands are defined as:
+%D
+%D \showsetup{comparecolorgroup}
+
+\fetchruntimecommand \comparecolorgroup {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolor}
+%D
+%D But let's not forget that we also have the more traditional
+%D non||related colors. These show up after:
+%D
+%D \starttyping
+%D \showcolor [name]
+%D \stoptyping
+%D
+%D Where \type{name} for instance can be \type{rgb}.
+%D
+%D \showsetup{showcolor}
+
+\fetchruntimecommand \showcolor {\f!colorprefix\s!run}
+
+%D It would make sense to put the following code in \type
+%D {colo-mps}, but it it rather low level.
+
+%D \macros
+%D {negatecolorcomponent,negatedcolorcomponent}
+%D
+%D These speak for themselves. See \type {colo-ext} for usage.
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\scratchdimen\onepoint\advance\scratchdimen-#1\onepoint
+ \ifdim\scratchdimen<\zeropoint\scratchdimen\zeropoint\fi
+ \edef#1{\withoutpt\the\scratchdimen}}
+
+\let\negatedcolorcomponent\firstofoneargument
+
+\def\negatedcolorcomponent#1%
+ {\ifdim\dimexpr\onepoint-#1\onepoint\relax<\zeropoint
+ \!!zerocount
+ \else
+ \expandafter\withoutpt\the\dimexpr\onepoint-#1\onepoint\relax
+ \fi}
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\edef#1{\negatedcolorcomponent{#1}}}
+
+%D \macros
+%D {ifMPgraphics, ifMPcmykcolors, MPcolor}
+%D
+%D A very special macro is \type{\MPcolor}. This one can be
+%D used to pass a \CONTEXT\ color to \METAPOST.
+%D
+%D \starttyping
+%D \MPcolor{my own red}
+%D \stoptyping
+%D
+%D This macro returns a \METAPOST\ triplet \type{(R,G,B)}.
+%D Unless \CMYK\ color support is turned on with \type
+%D {MPcmyk}, only \cap{RGB} colors and gray scales are
+%D supported.
+
+\newif\ifMPcmykcolors % \MPcmykcolorsfalse
+\newif\ifMPspotcolors % \MPspotcolorsfalse
+
+\ifx\MPcolor\undefined
+ \def\MPcolor#1{(0,0,0)}
+\fi
+
+%D \macros
+%D {PDFcolor,FDFcolor}
+%D
+%D Similar alternatives are avaliable for \PDF:
+
+%D For the moment we keep the next downward compatibility
+%D switch, i.e.\ expanded colors. However, predefined colors
+%D and palets are no longer expanded (which is what I wanted
+%D in the first place).
+%D
+%D Well, in case we want to do color separation and use CMYK
+%D colors only, this is dangerous since unwanted remapping may
+%D take place. Especially when we redefine already defined
+%D colors in another color space (e.g. darkgreen is
+%D predefined in RGB color space, so a redefinition in CMYK
+%D coordinates before RGB mode is disabled, would give
+%D unexpected results due to the already frozen color spec.)
+%D
+%D So, from now on, colors are not frozen any more!
+
+\chardef\currentcolorchannel=0
+
+\newif\iffilterspotcolor \filterspotcolorfalse
+\newif\ifdoingspotcolor \doingspotcolorfalse
+
+\def\registercolorchannel#1%
+ {\ifdoingspotcolor \else
+ \global\expandafter\chardef\csname\??cs#1\endcsname\zerocount
+ \fi}
+
+\newif\ifhidesplitcolor \hidesplitcolortrue
+
+%D The next macro is for instance used in figure splitting:
+
+\def\doifseparatingcolorselse
+ {\iffilterspotcolor
+ \@EA\firstoftwoarguments
+ \else\ifcase\currentcolorchannel
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi\fi}
+
+\def\doifcolorchannelelse#1%
+ {\doifseparatingcolorselse
+ {\doifelsenothing{#1}
+ \secondoftwoarguments
+ {\doifelse{#1}\@@clsplit
+ \firstoftwoarguments
+ \secondoftwoarguments}}
+ \secondoftwoarguments}
+
+\def\resetcolorseparation
+ {\filterspotcolorfalse
+ \chardef\currentcolorchannel\zerocount}
+
+%D These can be used in selecting specific files (like
+%D figuredatabases).
+
+% we already have:
+%
+% \def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplitsen\fi}
+% \def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplitsen-\fi}
+
+\def\colorchannelprefix{\doifseparatingcolorselse\@@clsplit\empty-}
+\def\colorchannelsuffix{-\doifseparatingcolorselse\@@clsplit\empty}
+
+%D We now define the low level macros:
+
\chardef\colorversion=1
%D Color support is not present in \TEX. Colorful output can
@@ -165,8 +1029,12 @@
\def\dodefineglobalcolor{\dododefinecolor\doglobal\setgvalue\setxvalue1}
\def\dodefinenamedcolor {\dododefinecolor\doglobal\setvalue \setevalue0}
+\let\colorlist\empty % not really used, only for colo-run
+\setfalse\collectcolorsinlist
+\def\collectcolorinlist#1{\doglobal\addtocommalist{#1}\colorlist}
+
\def\dododefinecolor#1#2#3#4[#5][#6]% #2==set(g)value #3==set[e|x]value
- {#1\addtocommalist{#5}\colorlist % optional
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#5}\fi
\doifassignmentelse{#6}
{\@@resetcolorparameters
\getparameters[\??cl @@][#6]%
@@ -218,7 +1086,7 @@
\def\dodefinespotcolor[#1][#2][#3]% todo: always global
{\doifnot{#1}{#2}
{\@@resetcolorparameters
- \doglobal\addtocommalist{#1}\colorlist % optional
+ \ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\edef\@@cl@@n{#2}%
\getparameters[\??cl @@][#3]%
\doifnothing\@@cl@@p{\let\@@cl@@p\!!plusone}%
@@ -312,7 +1180,7 @@
\def\dodefinespotcolor[#1][#2][#3]% todo: always global (REDEFINED)
{\doifnot{#1}{#2}
{\@@resetcolorparameters
- \doglobal\addtocommalist{#1}\colorlist % optional
+ \ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\edef\@@cl@@n{#2}%
\getparameters[\??cl @@][#3]%
\doifnothing \@@cl@@p{\let\@@cl@@p\!!plusone}%
@@ -1859,4 +2727,50 @@
\appendtoks \localcolortrue \to \everyshapebox
+%D \macros
+%D {forcecolorhack}
+%D
+%D Awful \unknown
+
+\let\forcecolorhack\relax
+
+%D We default to the colors defined in \module{colo-rgb} and
+%D support both \cap{RGB} and \cap{CMYK} output. As you can
+%D see, color support is turned off by default. Reduction of
+%D gray colors to gray scales is turned on.
+
+\definecolor[black][s=0]
+\definecolor[white][s=1]
+
+\definetransparency [none] [0]
+\definetransparency [normal] [1]
+\definetransparency [multiply] [2]
+\definetransparency [screen] [3]
+\definetransparency [overlay] [4]
+\definetransparency [softlight] [5]
+\definetransparency [hardlight] [6]
+\definetransparency [colordodge] [7]
+\definetransparency [colorburn] [8]
+\definetransparency [darken] [9]
+\definetransparency [lighten] [10]
+\definetransparency [difference] [11]
+\definetransparency [exclusion] [12]
+
+\setupcolors
+ [\c!state=\v!stop,
+ \c!conversion=\v!yes,
+ \c!reduction=\v!no,
+ \c!rgb=\v!yes,
+ \c!cmyk=\v!yes,
+ \c!spot=\v!yes,
+ \c!mp\c!cmyk=\@@clcmyk,
+ \c!mp\c!spot=\@@clspot,
+ \c!expansion=\v!no,
+ \c!textcolor=,
+ \c!split=\v!no,
+ \c!criterium=\v!all]
+
+\setupcolor
+ [\v!rgb]
+
\protect \endinput
diff --git a/tex/context/base/colo-ini.mkiv b/tex/context/base/colo-ini.mkiv
index 7f79cdfad..cf7f2446a 100644
--- a/tex/context/base/colo-ini.mkiv
+++ b/tex/context/base/colo-ini.mkiv
@@ -11,8 +11,874 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D We need to clean this up further but first we hav eto make sure that mkiv
+%D code works ok.
+
+\writestatus{loading}{ConTeXt Color Macros / Initialization}
+
+%D This module implements color. Since \MKII\ and \MKIV\ use a completely
+%D different approach, this module only implements a few generic mechanisms.
+
+\registerctxluafile{colo-ini}{1.000}
+
\unprotect
+\chardef\colorversion=1 % temp, needed for tracing purposes, mkiv transition
+
+%D We use a couple of local registers. That way we don't have
+%D to group when converting colors. By the way, this is not
+%D really faster. We can sqeeze half a second runtime for 50K
+%D switches on a 1G machine, but the macros will become rather
+%D ugly then. To mention one such improvement: no colon
+%D after the key character (.25 sec).
+
+\newdimen\colordimen
+\newcount\colorcount
+
+%D When typesetting for paper, we prefer using the \cap{CMYK}
+%D color space, but for on||screen viewing we prefer \cap{RGB}
+%D (the previous implementation supported only this scheme).
+%D Independant of such specifications, we support some automatic
+%D conversions:
+%D
+%D \startitemize[packed]
+%D \item convert all colors to \cap{RGB}
+%D \item convert all colors to \cap{CMYK}
+%D \item convert all colors to gray scales
+%D \stopitemize
+%D
+%D We also support optimization of colors to gray scales.
+%D
+%D \startitemize[continue]
+%D \item reduce gray colors to gray scales
+%D \item reduce \cap{CMY} components to \cap{K}
+%D \stopitemize
+%D
+%D These options are communicated by means of:
+
+\newif\ifRGBsupported
+\newif\ifCMYKsupported
+\newif\ifSPOTsupported
+\newif\ifpreferGRAY
+\newif\ifGRAYprefered
+\newif\ifreduceCMYK
+\newif\ifconverttoGRAY
+\newif\ifweightGRAY \weightGRAYtrue
+
+\newif\ifconvertMPcolors
+\newif\ifreduceMPcolors
+\newif\ifforcegrayMPcolors
+
+%D The last boolean controls reduction of \cap{CMYK} to
+%D \cap{CMY} colors. When set to true, the black component
+%D is added to the other ones.
+%D
+%D Prefering gray is not the same as converting to gray.
+%D Conversion treats each color components in a different way,
+%D while prefering is just a reduction and thus a
+%D space||saving option.
+
+\newif\iffreezecolors \freezecolorsfalse
+\newif\ifincolor % true if colors enabled
+\newif\iflocalcolor
+
+\let\colorlist \empty
+\let\currentspotcolor \empty
+\let\allspotcolors \empty
+\let\usedspotcolors \empty
+\let\usedcolorchannels\empty
+\let\currentpalet \empty
+
+%D \macros
+%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor}
+%D
+%D \startbuffer
+%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
+%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
+%D
+%D \definespotcolor [blue-100] [blue] [p=1]
+%D \definespotcolor [yellow-100] [yellow] [p=1]
+%D
+%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
+%D
+%D \useexternalfigure[demofig][mill.png][object=no]
+%D
+%D \startcombination[4*1]
+%D {\externalfigure[demofig]} {no color}
+%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
+%D {\externalfigure[demofig][color=blue-100]} {spot color}
+%D {\externalfigure[demofig][color=yellow-100]} {spot color}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
+\def\definecolor {\dodoubleargument\dodefinecolor}
+\def\defineglobalcolor {\dodoubleargument\dodefineglobalcolor}
+\def\definenamedcolor {\dodoubleargument\dodefinenamedcolor}
+\def\definespotcolor {\dotripleargument\dodefinespotcolor}
+\def\definemultitonecolor{\doquadrupleempty\dodefinemultitonecolor}
+
+% check: registerusedspotcolors
+% check: registerusedcolorchannels
+
+%D \macros
+%D {doifcolorelse, doifcolor}
+%D
+%D Switching to a color is done by means of the following
+%D command. Later on we will explain the use of palets. We
+%D define ourselves a color conditional first.
+
+\ifx\doifcolorelse\undefined
+ \let\doifcolorelse\secondoftwoarguments
+ \let\doifcolor \gobbleoneargument
+\fi
+
+%D \macros
+%D {localstartcolor,localstopcolor}
+%D
+%D Simple color support, that is without nesting, is provided
+%D by:
+
+\ifx\localstartcolor\undefined
+ \let\localstartcolor\undefined
+ \let\localstopcolor \undefined
+\fi
+
+%D \macros
+%D {faststartcolor,faststopcolor}
+%D
+%D No checking for arguments and such:
+
+\ifx\faststartcolor\undefined
+ \def\faststartcolor[#1]{}
+ \def\faststopcolor {}
+\fi
+
+%D These local ones may go away in future versions.
+
+%D \macros
+%D {startcolor,stopcolor}
+%D
+%D The more save method, the one that saves the current color
+%D state and returns to this state afterward, is activated by:
+%D
+%D \showsetup{startcolor}
+
+\ifx\startcolor\undefined
+ \let\startcolor\undefined
+ \let\stopcolor \undefined
+\fi
+
+%D \macros
+%D {startcurrentcolor,stopcurrentcolor}
+
+\def\startcurrentcolor{\startcolor[\outercolorname]}
+\def\stopcurrentcolor {\stopcolor}
+
+%D \macros
+%D {color,graycolor}
+%D
+%D This leaves the simple color command:
+%D
+%D \showsetup{color}
+%D \showsetup{graycolor}
+
+\ifx\color\undefined
+ \def\color [#1]{}
+ \def\graycolor[#1]{}
+ \def\gray {\graycolor}
+\fi
+
+%D \macros
+%D {localstartraster,localstopraster,
+%D startraster,stopraster,raster}
+%D
+%D The previous conversions are not linear and treat each color
+%D component according to human perception curves. Pure gray
+%D (we call them rasters) has equal color components. In
+%D \CONTEXT\ rasters are only used as backgrounds and these
+%D don't cross page boundaries in the way color does. Therefore
+%D we don't need stacks and marks. Just to be compatible with
+%D color support we offer both 'global' and 'local' commands.
+
+\ifx\startraster\undefined
+ \def\startraster [#1]{}
+ \def\stopraster {}
+ \def\raster [#1]{}
+ \def\localstartraster[#1]{}
+ \def\localstopraster {}
+\fi
+
+%D \macros
+%D {colorvalue, grayvalue}
+%D
+%D We can typeset the color components using \type{\colorvalue} and
+%D \type{\grayvalue}. The commands:
+%D
+%D \startbuffer
+%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
+%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D show us:
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+
+\def\colorformatseparator{ }
+
+\ifx\colorvalue\undefined
+ \let\colorvalue\gobbleoneargument
+ \let\grayvalue \gobbleoneargument
+\fi
+
+% check: \currentcolorname
+% check: \outercolorname
+
+%D \macros
+%D {setupcolor}
+%D
+%D Color definitions can be grouped in files with the name:
+%D
+%D \starttyping
+%D \f!colorprefix-identifier.tex
+%D \stoptyping
+%D
+%D where \type{\f!colorprefix} is \unprotect {\tttf \f!colorprefix}.
+%D Loading such a file is done by \protect
+%D
+%D \showsetup{setupcolor}
+%D
+%D Some default colors are specified in \type{colo-rgb.tex},
+%D which is loaded into the format by:
+%D
+%D \starttyping
+%D \setupcolor[rgb]
+%D \stoptyping
+
+\let\colorstyle\empty
+
+\def\setupcolor
+ {\dosingleargument\dosetupcolor}
+
+\def\dosetupcolor[#1]%
+ {\doifnot{#1}\colorstyle
+ {\def\colorstyle{#1}%
+ \processcommalist[#1]\dodosetupcolor}}
+
+\def\dodosetupcolor#1%
+ {\makeshortfilename[\truefilename{\f!colorprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!colors4\colorstyle}
+ {\showmessage\m!colors5\colorstyle}%
+ \stopreadingfile}
+
+\let\usecolors\setupcolor
+
+% check: \chardef\currentcolorchannel=0
+% check: \startcolormode
+% check: \newif\iffilterspotcolor \filterspotcolorfalse
+% check: \newif\ifdoingspotcolor \doingspotcolorfalse
+% check: \registercolorchannel
+
+%D \macros
+%D {definetransparency}
+%D
+%D This command numbers to names:
+
+\def\definetransparency
+ {\dodoubleargument\dodefinetransparency}
+
+\def\setupcolors
+ {\dosingleargument\dosetupcolors}
+
+\def\resetcolorsplitting
+ {\chardef\currentcolorchannel\zerocount
+ \let\currentspotcolor\empty
+ \filterspotcolorfalse}
+
+\def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplit\fi}
+\def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplit-\fi}
+
+\def\setcolorsplitting
+ {\resetsystemmode{\v!color\colorsplitsuffix}%
+ \resetcolorsplitting
+ \processaction
+ [\@@clsplit]
+ [ c=>\chardef\currentcolorchannel1,%
+ m=>\chardef\currentcolorchannel2,%
+ y=>\chardef\currentcolorchannel3,%
+ k=>\chardef\currentcolorchannel4,%
+ r=>\chardef\currentcolorchannel5,%
+ g=>\chardef\currentcolorchannel6,%
+ b=>\chardef\currentcolorchannel7,%
+ s=>\chardef\currentcolorchannel8,%
+ \v!no=>,% \currentcolorchannel0,% all colors
+ \s!default=>,% \currentcolorchannel0,% all colors
+ \s!unknown=>\filterspotcolortrue
+ \edef\currentspotcolor{\commalistelement}]%
+ \setsystemmode{\v!color\colorsplitsuffix}%
+ \iffilterspotcolor \let\@@clrgb\v!no \fi}
+
+\ifx\dosetupcolormodel\undefined
+ \let\dosetupcolormodel\relax
+\fi
+
+\def\dosetupcolors[#1]% some no longer make sense in MkIV
+ {\getparameters[\??cl][#1]%
+ \doifelse\@@clspot\v!yes
+ \SPOTsupportedtrue
+ \SPOTsupportedfalse
+ \doifelsenothing\@@clsplit
+ \resetcolorsplitting
+ \setcolorsplitting
+ \doifelse\@@clreduction\v!yes
+ \reduceCMYKtrue
+ \reduceCMYKfalse
+ \doifelse\@@clexpansion\v!yes
+ \freezecolorstrue
+ \freezecolorsfalse
+ \doifelse\@@clcriterium\v!all
+ \hidesplitcolortrue
+ \hidesplitcolorfalse
+ \doifelse\@@clrgb\v!no
+ {\ifRGBsupported \ifproductionrun\showmessage\m!colors {9}\v!rgb \fi\RGBsupportedfalse \fi}
+ {\ifRGBsupported \else\ifproductionrun\showmessage\m!colors{10}\v!rgb \fi\RGBsupportedtrue \fi}%
+ \doifelse\@@clcmyk\v!no
+ {\ifCMYKsupported \ifproductionrun\showmessage\m!colors {9}\v!cmyk \fi\CMYKsupportedfalse\fi}
+ {\ifCMYKsupported\else\ifproductionrun\showmessage\m!colors{10}\v!cmyk \fi\CMYKsupportedtrue \fi}%
+ \doifelse\@@clmpcmyk\v!no
+ {\ifMPcmykcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!cmyk}\fi\MPcmykcolorsfalse \fi}
+ {\ifMPcmykcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!cmyk}\fi\MPcmykcolorstrue \fi}%
+ \doifelse\@@clmpspot\v!no
+ {\ifMPspotcolors \ifproductionrun\showmessage\m!colors {9}{\v!mp\v!spot}\fi\MPspotcolorsfalse \fi}
+ {\ifMPspotcolors \else\ifproductionrun\showmessage\m!colors{10}{\v!mp\v!spot}\fi\MPspotcolorstrue \fi}%
+ \preferGRAYfalse
+ \processaction
+ [\@@clconversion]
+ [ \v!yes=>\preferGRAYtrue,
+ \v!always=>\preferGRAYtrue\RGBsupportedfalse\CMYKsupportedfalse]%
+ \ifRGBsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \else\ifCMYKsupported
+ \converttoGRAYfalse
+ \forcegrayMPcolorsfalse
+ \convertMPcolorstrue
+ \ifreduceCMYK
+ \reduceMPcolorstrue
+ \fi
+ \else
+ \ifconverttoGRAY\else\showmessage\m!colors{11}\empty\fi
+ \converttoGRAYtrue
+ \forcegrayMPcolorstrue
+ \convertMPcolorsfalse
+ \reduceMPcolorsfalse
+ \fi\fi
+ \processaction
+ [\@@clstate]
+ [ \v!global=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse,
+ \v!local=>\ifincolor\else\showmessage\m!colors2\colorstyle\fi
+ \incolortrue\localcolortrue,
+ \v!start=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
+ \incolortrue\localcolorfalse
+ \let\@@clstate\v!global,
+ \v!stop=>\incolorfalse\localcolorfalse
+ \forcegrayMPcolorstrue]%
+ \dosetupcolormodel
+ \initializemaintextcolor}
+
+%D \macros
+%D {startregistercolor,stopregistercolor,permitcolormode}
+%D
+%D If you only want to register a color, the switch \type
+%D {\ifpermitcolormode} can be used. That way the nested
+%D colors know where to go back to.
+
+\ifx\startregistercolor\undefined
+ \def\startregistercolor[#1]{}
+ \def\stopregistercolor {}
+\fi
+
+%D We use these macros for implementing text colors
+%D (actually, the first application was in foreground
+%D colors).
+%D
+%D \starttyping
+%D \starttextcolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stoptextcolor
+%D \stoptyping
+%D
+%D This is more efficient than the alternative:
+%D
+%D \starttyping
+%D \setupbackgrounds[text][foregroundcolor=red]
+%D \startregistercolor[red]
+%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
+%D \stopregistercolor
+%D \stoptyping
+
+\def\maintextcolor {}
+\def\defaulttextcolor {black}
+\def\@@themaintextcolor{themaintextcolor}
+
+\ifx\initializemaintextcolor\undefined
+ \def\starttextcolor [#1]{}
+ \def\stoptextcolor {}
+ \def\initializemaintextcolor {}
+\fi
+
+\ifx\restoretextcolor\undefined % to be redone
+ \let\restoretextcolor \firstofoneargument
+ \let\localstarttextcolor\relax
+ \let\localstoptextcolor \relax
+\fi
+
+%D In this documentation we will not go into too much details
+%D on palets. Curious users can find more information on this
+%D topic in \from[use of color].
+%D
+%D At the moment we implemented color in \CONTEXT\ color
+%D printing was not yet on the desktop. In spite of this lack our
+%D graphics designer made colorfull illustrations. When printed
+%D on a black and white printer, distinctive colors can come
+%D out equally gray. We therefore decided to use only colors
+%D that were distinctive in colors as well as in black and
+%D white print.
+%D
+%D Although none of the graphic packages we used supported
+%D logical colors and global color redefition, we build this
+%D support into \CONTEXT. This enabled us to experiment and
+%D also prepared us for the future.
+
+%D \macros
+%D {definepalet}
+%D
+%D Colors are grouped in palets. The colors in such a palet can
+%D have colorful names, but best is to use names that specify
+%D their use, like {\em important} or {\em danger}. As a sort
+%D of example \CONTEXT\ has some palets predefined,
+%D like:\footnote{At the time I wrote the palet support, I was
+%D reading 'A hort history of time' of S.~Hawkins, so that's
+%D why we stuck to quarks.}
+%D
+%D \starttyping
+%D \definepalet
+%D [alfa]
+%D [ top=rood:7,
+%D bottom=groen:6,
+%D up=blauw:5,
+%D down=cyaan:4,
+%D strange=magenta:3,
+%D charm=geel:2]
+%D \stoptyping
+%D
+%D It's formal definition is:
+%D
+%D \showsetup{definepalet}
+%D
+%D Visualized, such a palet looks like:
+%D
+%D \startbuffer[palet]
+%D \showpalet [alfa] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \startlinecorrection
+%D \getbuffer[palet]
+%D \stoplinecorrection
+%D
+%D This bar shows both the color and gray alternatives of the
+%D palet components (not visible in black and white print).
+%D
+%D When needed, one can copy a palet by saying:
+%D
+%D \starttyping
+%D \definepalet [TEXcolorpretty] [colorpretty]
+%D \stoptyping
+%D
+%D This saves us some typing in for instance the modules that
+%D deal with pretty verbatim typesetting.
+
+\def\definepalet
+ {\dodoubleargument\dodefinepalet}
+
+\def\dodefinepalet[#1][#2]%
+ {\doifassignmentelse{#2}
+ {%\showmessage\m!colors6{#1}%
+ \letvalue{\??pa#1}\empty
+ \setevalue{\??pa\??pa#1}{#2}%
+ \def\dodododefinepalet[##1=##2]%
+ {\doifvaluesomething{\??pa#1}
+ {\setevalue{\??pa#1}{\csname\??pa#1\endcsname,}}%
+ \setevalue{\??pa#1}{\csname\??pa#1\endcsname##1}%
+ \dodefinepaletcolor{#1}{##1}{##2}}%
+ \def\dododefinepalet##1%
+ {\dodododefinepalet[##1]}%
+ \processcommalist[#2]\dododefinepalet}
+ {\doifdefined{\??pa#2}
+ {\expanded{\dodefinepalet[#1][\csname\??pa\??pa#2\endcsname]}}}}
+
+\ifx\dodefinepaletcolor\undefined
+ \let\dodefinepaletcolor\gobblethreearguments
+\fi
+
+\let\paletsize\!!zerocount
+
+\def\getpaletsize[#1]%
+ {\getcommacommandsize[\csname\??pa\??pa#1\endcsname]%
+ \edef\paletsize{\number\commalistsize}}
+
+%D Instead of refering to colors, one can also directly specify
+%D a color:
+%D
+%D \starttyping
+%D \definepalet[test][xx=green]
+%D \definepalet[test][xx={y=.4}]
+%D \stoptyping
+
+%D \macros
+%D {setuppalet}
+%D
+%D Colors are taken from the current palet, if defined.
+%D Setting the current palet is done by:
+%D
+%D \showsetup{setuppalet}
+
+\let\currentpalet\empty
+
+\def\setuppalet
+ {\dosingleempty\dosetuppalet}
+
+\def\dosetuppalet[#1]%
+ {\edef\currentpalet{#1}%
+ \ifx\currentpalet\empty
+ % seems to be a reset
+ \else\ifcsname\??pa\currentpalet\endcsname
+ \edef\currentpalet{#1:}%
+ \else
+ \showmessage\m!colors7\currentpalet
+ \let\currentpalet\empty
+ \fi\fi}
+
+%D \macros
+%D {showpalet}
+%D
+%D The previous visualization was typeset with:
+%D
+%D \typebuffer[palet]
+%D
+%D This commands is defined as:
+%D
+%D \showsetup{showpalet}
+
+\fetchruntimecommand \showpalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolorcomponents}
+%D
+%D \starttyping
+%D \showcolorcomponents[color-1,color-2]
+%D \stoptyping
+
+\fetchruntimecommand \showcolorcomponents {\f!colorprefix\s!run}
+
+%D \macros
+%D {definecolorgroup}
+%D
+%D The naming of the colors in this palet suggests some
+%D ordening, which in turn is suported by color grouping.
+%D
+%D \starttyping
+%D \definecolorgroup
+%D [red]
+%D [1.00:0.90:0.90,
+%D 1.00:0.80:0.80,
+%D 1.00:0.70:0.70,
+%D 1.00:0.55:0.55,
+%D 1.00:0.40:0.40,
+%D 1.00:0.25:0.25,
+%D 1.00:0.15:0.15,
+%D 0.90:0.00:0.00]
+%D \stoptyping
+%D
+%D In such a color group colors are numbered from~$1$ to~$n$.
+%D
+%D \showsetup{definecolorgroup}
+%D
+%D This kind of specification is not only more compact than
+%D defining each color separate, it also loads faster and takes
+%D less bytes.
+
+\def\definecolorgroup
+ {\dotripleempty\dodefinecolorgroup}
+
+\def\dododefinecolorgroupgray [#1][#2:#3]{\definecolor [#1:\the\colorcount][s=#2]}
+\def\dododefinecolorgrouprgb [#1][#2:#3:#4:#5]{\definecolor [#1:\the\colorcount][r=#2,g=#3,b=#4]}
+\def\dododefinecolorgroupcmyk[#1][#2:#3:#4:#5:#6]{\definecolor [#1:\the\colorcount][c=#2,m=#3=,y=#4,k=#5]}
+\def\dododefinecolorgroupspot [#1][#2:#3:#4]{\definespotcolor[#1:\the\colorcount][#2][p=#3]}
+
+\def\dododefinecolorgroup#1#2%
+ {\advance\colorcount\plusone
+ \getvalue{dododefinecolorgroup\currentcolorspace}[#1][#2:0:0:0:0]}
+
+\def\dodefinecolorgroup[#1][#2][#3]% obsolete, just use palets
+ {\ifthirdargument
+ \doifelsenothing{#2}{\let\currentcolorspace\v!rgb}{\def\currentcolorspace{#2}}%
+ \colorcount\zerocount
+ \processcommalist[#3]{\dododefinecolorgroup{#1}}%
+ \else
+ \doifinstringelse{:}{#2}
+ {\definecolorgroup[#1][\v!rgb][#2]}
+ {\doloop
+ {\doifdefinedelse{\??cr#2:\recurselevel}
+ {\setevalue{\??cr#1:\recurselevel}{\csname\??cr#2:\recurselevel\endcsname}}
+ {\exitloop}}}%
+ \fi}
+
+%D \macros
+%D {showcolorgroup}
+%D
+%D We can show the group by:
+%D
+%D \startbuffer
+%D \showcolorgroup [blue] [horizontal,name,number,value]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or in color:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D which uses:
+%D
+%D \showsetup{showcolorgroup}
+
+\fetchruntimecommand \showcolorgroup {\f!colorprefix\s!run}
+
+%D There are ten predefined color groups, like
+%D \color[green]{\em groen}, \color[red]{\em rood},
+%D \color[blue]{\em blauw}, \color[cyan]{\em cyaan},
+%D \color[magenta]{\em magenta} and \color[yellow]{\em geel}.
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\hss
+%D \showcolorgroup [red] [vertical,name,number]\hss
+%D \showcolorgroup [green] [vertical,name]\hss
+%D \showcolorgroup [blue] [vertical,name]\hss
+%D \showcolorgroup [cyan] [vertical,name]\hss
+%D \showcolorgroup [magenta][vertical,name]\hss
+%D \showcolorgroup [yellow] [vertical,name]\hss}
+%D \stoplinecorrection
+%D
+%D These groups are used to define palets {\em alfa} upto {\em
+%D zeta}. As long as we don't use colors from the same row, we
+%D get ourselves distinctive palets. By activating such a palet
+%D one gains access to its members {\em top} to {\em charm} (of
+%D course one should use more suitable names than these).
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\showpalet [alfa] [vertical,name,number]\hss
+%D \showpalet [beta] [vertical,name]\hss
+%D \showpalet [gamma] [vertical,name]\hss
+%D \showpalet [delta] [vertical,name]\hss
+%D \showpalet [epsilon] [vertical,name]\hss
+%D \showpalet [zeta] [vertical,name]}
+%D \stoplinecorrection
+%D
+%D By using the keyword \type {value} the individual color
+%D components are shown too. When printed in color, these
+%D showcases show both the colors and the gray value.
+
+%D \macros
+%D {comparepalet}
+%D
+%D There are some more testing macros available:
+%D
+%D \startbuffer
+%D \comparepalet [alfa]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows the palet colors against a background:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{comparepalet}
+
+\fetchruntimecommand \comparepalet {\f!colorprefix\s!run}
+
+%D \macros
+%D {comparecolorgroup}
+%D
+%D The similar command:
+%D
+%D \startbuffer
+%D \comparecolorgroup [blue]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D shows color groups:
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D this commands are defined as:
+%D
+%D \showsetup{comparecolorgroup}
+
+\fetchruntimecommand \comparecolorgroup {\f!colorprefix\s!run}
+
+%D \macros
+%D {showcolor}
+%D
+%D But let's not forget that we also have the more traditional
+%D non||related colors. These show up after:
+%D
+%D \starttyping
+%D \showcolor [name]
+%D \stoptyping
+%D
+%D Where \type{name} for instance can be \type{rgb}.
+%D
+%D \showsetup{showcolor}
+
+\fetchruntimecommand \showcolor {\f!colorprefix\s!run}
+
+%D It would make sense to put the following code in \type
+%D {colo-mps}, but it it rather low level.
+
+%D \macros
+%D {negatecolorcomponent,negatedcolorcomponent}
+%D
+%D These speak for themselves. See \type {colo-ext} for usage.
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\scratchdimen\onepoint\advance\scratchdimen-#1\onepoint
+ \ifdim\scratchdimen<\zeropoint\scratchdimen\zeropoint\fi
+ \edef#1{\withoutpt\the\scratchdimen}}
+
+\let\negatedcolorcomponent\firstofoneargument
+
+\def\negatedcolorcomponent#1%
+ {\ifdim\dimexpr\onepoint-#1\onepoint\relax<\zeropoint
+ \!!zerocount
+ \else
+ \expandafter\withoutpt\the\dimexpr\onepoint-#1\onepoint\relax
+ \fi}
+
+\def\negatecolorcomponent#1% #1 = \macro
+ {\edef#1{\negatedcolorcomponent{#1}}}
+
+%D \macros
+%D {ifMPgraphics, ifMPcmykcolors, MPcolor}
+%D
+%D A very special macro is \type{\MPcolor}. This one can be
+%D used to pass a \CONTEXT\ color to \METAPOST.
+%D
+%D \starttyping
+%D \MPcolor{my own red}
+%D \stoptyping
+%D
+%D This macro returns a \METAPOST\ triplet \type{(R,G,B)}.
+%D Unless \CMYK\ color support is turned on with \type
+%D {MPcmyk}, only \cap{RGB} colors and gray scales are
+%D supported.
+
+\newif\ifMPcmykcolors % \MPcmykcolorsfalse
+\newif\ifMPspotcolors % \MPspotcolorsfalse
+
+\ifx\MPcolor\undefined
+ \def\MPcolor#1{(0,0,0)}
+\fi
+
+%D \macros
+%D {PDFcolor,FDFcolor}
+%D
+%D Similar alternatives are avaliable for \PDF:
+
+%D For the moment we keep the next downward compatibility
+%D switch, i.e.\ expanded colors. However, predefined colors
+%D and palets are no longer expanded (which is what I wanted
+%D in the first place).
+%D
+%D Well, in case we want to do color separation and use CMYK
+%D colors only, this is dangerous since unwanted remapping may
+%D take place. Especially when we redefine already defined
+%D colors in another color space (e.g. darkgreen is
+%D predefined in RGB color space, so a redefinition in CMYK
+%D coordinates before RGB mode is disabled, would give
+%D unexpected results due to the already frozen color spec.)
+%D
+%D So, from now on, colors are not frozen any more!
+
+\chardef\currentcolorchannel=0
+
+\newif\iffilterspotcolor \filterspotcolorfalse
+\newif\ifdoingspotcolor \doingspotcolorfalse
+
+\def\registercolorchannel#1%
+ {\ifdoingspotcolor \else
+ \global\expandafter\chardef\csname\??cs#1\endcsname\zerocount
+ \fi}
+
+\newif\ifhidesplitcolor \hidesplitcolortrue
+
+%D The next macro is for instance used in figure splitting:
+
+\def\doifseparatingcolorselse
+ {\iffilterspotcolor
+ \@EA\firstoftwoarguments
+ \else\ifcase\currentcolorchannel
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi\fi}
+
+\def\doifcolorchannelelse#1%
+ {\doifseparatingcolorselse
+ {\doifelsenothing{#1}
+ \secondoftwoarguments
+ {\doifelse{#1}\@@clsplit
+ \firstoftwoarguments
+ \secondoftwoarguments}}
+ \secondoftwoarguments}
+
+\def\resetcolorseparation
+ {\filterspotcolorfalse
+ \chardef\currentcolorchannel\zerocount}
+
+%D These can be used in selecting specific files (like
+%D figuredatabases).
+
+% we already have:
+%
+% \def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplitsen\fi}
+% \def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplitsen-\fi}
+
+\def\colorchannelprefix{\doifseparatingcolorselse\@@clsplit\empty-}
+\def\colorchannelsuffix{-\doifseparatingcolorselse\@@clsplit\empty}
+
+%D We now define the low level macros:
+
\chardef\colorversion=2
% todo: palets in definecolor
@@ -37,8 +903,6 @@
% draw btex test etex withprescript \mptexcolor{blue} ;
% \stopMPpage
-\registerctxluafile{colo-ini}{1.000}
-
\ifx\currentcolormodel\undefined \newcount\currentcolormodel \fi
\def\setcolormodel#1%
@@ -79,28 +943,9 @@
% Since we couple definitions, we could stick to one test. Todo. Same for mpcolor.
-% \def\doactivatecolor#1% : in currentpalet, maybe not, ugly
-% {\ifcsname(cs:\currentpalet#1)\endcsname
-% \csname(cs:\currentpalet#1)\endcsname
-% \csname(ts:\currentpalet#1)\endcsname
-% \else
-% \csname(cs:#1)\endcsname
-% \csname(ts:#1)\endcsname
-% \fi}
-
-% \def\doactivatecolor#1% : in currentpalet, maybe not, ugly
-% {\csname(cs:\ifcsname(cs:\currentpalet#1)\endcsname\currentpalet\fi#1)\endcsname}
-% \csname(ts:\ifcsname(ts:\currentpalet#1)\endcsname\currentpalet\fi#1)\endcsname}
-%
-% more robust test, else we get \relaxed non-colors which may confuse e.g. mpcolor
-
\letvalue{(cs:-}\empty
\letvalue{(ts:-}\empty
-% \def\doactivatecolor#1% : in currentpalet, maybe not, ugly
-% {\csname(cs:\ifcsname(cs:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(cs:#1)\endcsname#1\else-\fi\fi)\endcsname
-% \csname(ts:\ifcsname(ts:\currentpalet#1)\endcsname\currentpalet#1\else\ifcsname(ts:#1)\endcsname#1\else-\fi\fi)\endcsname}
-
\def\doactivatecolor#1% : in currentpalet, maybe not, ugly
{\ifcsname(cs:\currentpalet#1)\endcsname
\csname(cs:\currentpalet#1)\endcsname
@@ -131,29 +976,27 @@
\def\dodefinecolorcommand#1#2%
{\unexpanded#1{#2}{\doactivatecolor{#2}}}
-% todo: \allspotcolors
-
-\def\colorlist % not really used, only for colo-run
- {\ctxlua{tex.sprint(table.concat(table.sortedkeys(attributes.list[attributes.numbers.color]),","))}}
+\let\colorlist\empty % not really used, only for colo-run
+\setfalse\collectcolorsinlist
+\def\collectcolorinlist#1{\doglobal\addtocommalist{#1}\colorlist}
\def\dodefinecolor[#1][#2]%
- {%\addtocommalist{#1}\colorlist
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\ctxlua{ctx.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}%
\dodefinecolorcommand\setvalue{#1}}
\def\dodefineglobalcolor[#1][#2]%
- {%\doglobal\addtocommalist{#1}\colorlist
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\ctxlua{ctx.defineprocesscolor("#1","#2",true,\iffreezecolors true\else false\fi)}%
\dodefinecolorcommand\setgvalue{#1}}
\def\dodefinenamedcolor[#1][#2]%
- {%\doglobal\addtocommalist{#1}\colorlist
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\ctxlua{ctx.defineprocesscolor("#1","#2",false,\iffreezecolors true\else false\fi)}%
\dodefinecolorcommand\setvalue{#1}}
\def\dodefinespotcolor[#1][#2][#3]%
- {%\doglobal\addtocommalist{#1}\colorlist % optional
- \doglobal\addtocommalist{#2}\allspotcolors
+ {\ifconditional\collectcolorsinlist\collectcolorinlist{#1}\fi
\ctxlua{ctx.definespotcolor("#1","#2","#3",true)}%
\dodefinecolorcommand\setxvalue{#1}}
@@ -293,7 +1136,7 @@
\appendtoks \initializemaintextcolor \to \everyjob
-\def\localstarttextcolor{\expanded{\startcolor[\ifx\maintextcolor\empty\defaulttextcolor\else\maintextcolor\fi]}}
+\def\localstarttextcolor{\normalexpanded{\noexpand\startcolor[\ifx\maintextcolor\empty\defaulttextcolor\else\maintextcolor\fi]}}
\let\localstoptextcolor \stopcolor
\let\restoretextcolor \firstofoneargument
@@ -302,11 +1145,14 @@
{\definecolor[\??pa#1:#2][#3]%
\iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(cs:#1:#2)}{\csname(cs:\??pa#1:#2)\endcsname}%
\iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(ca:#1:#2)}{\csname(ca:\??pa#1:#2)\endcsname}}
- {\doifdefinedelse{(cs:#3)}% \definepalet[test][xx=green]
- {\iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(cs:#1:#2)}{\csname(cs:#3)\endcsname}%
- \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(ca:#1:#2)}{\csname(ca:#3)\endcsname}}
- {\letvalue{(cs:#1:#2)}\undefined
- \letvalue{(ca:#1:#2)}\undefined}}}
+ {\ifcsname(cs:#3)\endcsname % \definepalet[test][xx=green]
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(cs:#1:#2)}{\csname(cs:#3)\endcsname}%
+ \iffreezecolors\@EA\setevalue\else\@EA\setvalue\fi{(ca:#1:#2)}{\csname(ca:#3)\endcsname}%
+ \else
+ % not entered when making format
+ \localundefine{(cs:#1:#2)}% \letvalue{(cs:#1:#2)}\undefined
+ \localundefine{(ca:#1:#2)}% \letvalue{(ca:#1:#2)}\undefined
+ \fi}}
\setvalue{(cs:)}{} \setvalue{(ca:)}{0}
\setvalue{(ts:)}{} \setvalue{(ta:)}{0}
@@ -352,7 +1198,25 @@
\presetPDFtransparency{#2}{#3}%
\fi}
-\protect \endinput
+%D \macros
+%D {forcecolorhack}
+%D
+%D We can out this in front of (for instance) a special and so force color
+%D to be applied (only glyphs, rules and leaders are handled).
+%D
+%D \startbuffer
+%D \framed
+%D [background=color,backgroundcolor=yellow,framecolor=red,corner=round]
+%D {test}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% ignores in attribute handler
+%
+% \def\forcecolorhack{\vrule\!!width\zeropoint\!!height\zeropoint\!!depth\zeropoint}
+
+\def\forcecolorhack{\leaders\hrule\hskip\zeropoint}
% \setupcolors[state=start]
%
@@ -368,3 +1232,48 @@
% \ctxlua{tex.print(ctx.aux.colorattribute("green"))}
% \ctxlua{tex.print(ctx.aux.colorattribute("black"))}
% \stoptext
+
+%D We default to the colors defined in \module{colo-rgb} and
+%D support both \cap{RGB} and \cap{CMYK} output. As you can
+%D see, color support is turned off by default. Reduction of
+%D gray colors to gray scales is turned on.
+
+\definecolor[black][s=0]
+\definecolor[white][s=1]
+
+\definetransparency [none] [0]
+\definetransparency [normal] [1]
+\definetransparency [multiply] [2]
+\definetransparency [screen] [3]
+\definetransparency [overlay] [4]
+\definetransparency [softlight] [5]
+\definetransparency [hardlight] [6]
+\definetransparency [colordodge] [7]
+\definetransparency [colorburn] [8]
+\definetransparency [darken] [9]
+\definetransparency [lighten] [10]
+\definetransparency [difference] [11]
+\definetransparency [exclusion] [12]
+
+\appendtoks
+ \setupcolors[\c!state=\v!start]% later direct
+\to \everyjob
+
+\setupcolors
+ [\c!state=\v!stop, % in mkii: \v!stop
+ \c!conversion=\v!yes,
+ \c!reduction=\v!no,
+ \c!rgb=\v!yes,
+ \c!cmyk=\v!yes,
+ \c!spot=\v!yes,
+ \c!mp\c!cmyk=\@@clcmyk,
+ \c!mp\c!spot=\@@clspot,
+ \c!expansion=\v!no,
+ \c!textcolor=,
+ \c!split=\v!no,
+ \c!criterium=\v!all]
+
+\setupcolor
+ [\v!rgb]
+
+\protect \endinput
diff --git a/tex/context/base/colo-ini.tex b/tex/context/base/colo-ini.tex
deleted file mode 100644
index 0136596a5..000000000
--- a/tex/context/base/colo-ini.tex
+++ /dev/null
@@ -1,1051 +0,0 @@
-%D \module
-%D [ file=colo-ini,
-%D version=2007.08.08,
-%D title=\CONTEXT\ Color Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D We need to clean this up further but first we hav eto make sure that mkiv
-%D code works ok.
-
-\writestatus{loading}{Context Color Macros / initialization}
-
-%D This module implements color. Since \MKII\ and \MKIV\ use a completely
-%D different approach, this module only implements a few generic mechanisms.
-
-\startmessages dutch library: colors
- title: kleur
- 1: systeem -- is globaal actief
- 2: systeem -- is lokaal actief
- 3: -- is niet gedefinieerd --
- 4: systeem -- wordt geladen
- 5: onbekend systeem --
- 6: palet -- is beschikbaar
- 7: palet -- is niet beschikbaar
- 8: specificatie -- bij -- wordt zwart
- 9: -- kleurruimte wordt niet ondersteund
- 10: -- kleurruimte wordt ondersteund
- 11: kleur wordt vertaald in grijs
- 12: -- is geregistreerd
-\stopmessages
-
-\startmessages english library: colors
- title: color
- 1: system -- is global activated
- 2: system -- is local activated
- 3: -- is not defined --
- 4: system -- is loaded
- 5: unknown system --
- 6: palette -- is available
- 7: palette -- is not available
- 8: specification -- at color -- becomes black
- 9: -- color space is not supported
- 10: -- color space is supported
- 11: color is converted to gray
- 12: -- is registered
-\stopmessages
-
-\startmessages german library: colors
- title: farbe
- 1: system -- ist global aktiviert
- 2: system -- ist lokal aktiviert
- 3: -- ist undefiniert --
- 4: system -- ist geladen
- 5: unbekanntes System --
- 6: palette -- ist verfuegbar
- 7: palette -- ist nicht verfuegbar
- 8: Spezifikation -- bei Farbe -- wird schwarz
- 9: -- Farbraum wird nicht unterstuetzt
- 10: -- Farbraum wird unterstuetzt
- 11: Farbe wird in Grau umgewandelt
- 12: -- is registered
-\stopmessages
-
-\startmessages czech library: colors
- title: barva
- 1: system -- je globalne aktivovana
- 2: system -- je lokalne activovana
- 3: -- neni definovana --
- 4: system -- je nacten
- 5: neznamy system --
- 6: palette -- je k dispozici
- 7: palette -- neni k dispozici
- 8: specifikace -- v barve -- bude cerna
- 9: -- prostor barev neni podporovan
- 10: -- prostor barev je podporovan
- 11: barva je prevedena na sed
- 12: -- is registered
-\stopmessages
-
-\startmessages italian library: colors
- title: colore
- 1: sistema -- attivato globalmente
- 2: sistema -- attivato localmente
- 3: -- non definito --
- 4: sistema -- caricato
- 5: sistema -- sconosciuto
- 6: tavolozza -- resa disponibile
- 7: tavolozza -- non disponibile
- 8: specifica -- del colore -- convertita in nero
- 9: spazio dei colori -- non supportato
- 10: spazio dei colori -- supportato
- 11: il colore ø convertito in grigio
- 12: -- is registered
-\stopmessages
-
-\startmessages norwegian library: colors
- title: farge
- 1: system -- er aktivert globalt
- 2: system -- er aktivert lokalt
- 3: -- er udefinert --
- 4: system -- er lest inn
- 5: ukjent system --
- 6: palett -- er tilgjengelig
- 7: palett -- er ikke tilgjengelig
- 8: spesifikasjon -- for farge -- gir kun svart
- 9: -- fargerom er ikke støttet
- 10: -- fargerom er støttet
- 11: fargen vil bli vist som grø
- 12: -- is registered
-\stopmessages
-
-\startmessages romanian library: colors
- title: culori
- 1: sistem -- este activata global
- 2: sistem -- este activata local
- 3: -- nu este definita --
- 4: sistem -- este incarcata
- 5: sistem -- necunoscuta
- 6: paleta -- este disponibila
- 7: palette -- nu este disponibila
- 8: specificatia -- la culoarea -- devine neagra
- 9: spatiul de culoare -- nu este suportat
- 10: spatiul de culoare -- este suportat
- 11: culoarea este convertita la gri
- 12: -- is registered
-\stopmessages
-
-\startmessages french library: colors
- title: couleurs
- 1: le système -- est globalement activé
- 2: le système -- est localement activé
- 3: -- n'est pas défini --
- 4: le système -- est chargé
- 5: système -- inconnu
- 6: la palette -- est disponible
- 7: le palette -- n'est pas disponible
- 8: la spécification -- de la couleur -- devient noire
- 9: l'espace de couleur -- n'est pas supporté
- 10: -- l'espace de couleur est supporté
- 11: la couleur est convertie en niveau de gris
- 12: -- est enregistré
-\stopmessages
-
-\unprotect
-
-\chardef\colorversion=1 % temp, needed for tracing purposes, mkiv transition
-
-%D We use a couple of local registers. That way we don't have
-%D to group when converting colors. By the way, this is not
-%D really faster. We can sqeeze half a second runtime for 50K
-%D switches on a 1G machine, but the macros will become rather
-%D ugly then. To mention one such improvement: no colon
-%D after the key character (.25 sec).
-
-\newdimen\colordimen
-\newcount\colorcount
-
-%D When typesetting for paper, we prefer using the \cap{CMYK}
-%D color space, but for on||screen viewing we prefer \cap{RGB}
-%D (the previous implementation supported only this scheme).
-%D Independant of such specifications, we support some automatic
-%D conversions:
-%D
-%D \startitemize[packed]
-%D \item convert all colors to \cap{RGB}
-%D \item convert all colors to \cap{CMYK}
-%D \item convert all colors to gray scales
-%D \stopitemize
-%D
-%D We also support optimization of colors to gray scales.
-%D
-%D \startitemize[continue]
-%D \item reduce gray colors to gray scales
-%D \item reduce \cap{CMY} components to \cap{K}
-%D \stopitemize
-%D
-%D These options are communicated by means of:
-
-\newif\ifRGBsupported
-\newif\ifCMYKsupported
-\newif\ifSPOTsupported
-\newif\ifpreferGRAY
-\newif\ifGRAYprefered
-\newif\ifreduceCMYK
-\newif\ifconverttoGRAY
-\newif\ifweightGRAY \weightGRAYtrue
-
-\newif\ifconvertMPcolors
-\newif\ifreduceMPcolors
-\newif\ifforcegrayMPcolors
-
-%D The last boolean controls reduction of \cap{CMYK} to
-%D \cap{CMY} colors. When set to true, the black component
-%D is added to the other ones.
-%D
-%D Prefering gray is not the same as converting to gray.
-%D Conversion treats each color components in a different way,
-%D while prefering is just a reduction and thus a
-%D space||saving option.
-
-\newif\iffreezecolors \freezecolorsfalse
-\newif\ifincolor % true if colors enabled
-\newif\iflocalcolor
-
-\let\colorlist \empty
-\let\currentspotcolor \empty
-\let\allspotcolors \empty
-\let\usedspotcolors \empty
-\let\usedcolorchannels\empty
-\let\currentpalet \empty
-
-%D \macros
-%D {definecolor,defineglobalcolor,definenamedcolor,definespotcolor,definemultitonecolor}
-%D
-%D \startbuffer
-%D \definecolor [blue] [c=1,m=.38,y=0,k=.64] % pantone pms 2965 uncoated m
-%D \definecolor [yellow] [c=0,m=.28,y=1,k=.06] % pantone pms 124 uncoated m
-%D
-%D \definespotcolor [blue-100] [blue] [p=1]
-%D \definespotcolor [yellow-100] [yellow] [p=1]
-%D
-%D \definemultitonecolor [pdftoolscolor] [blue=.12,yellow=.28] [c=.1,m=.1,y=.3,k=.1]
-%D
-%D \useexternalfigure[demofig][mill.png][object=no]
-%D
-%D \startcombination[4*1]
-%D {\externalfigure[demofig]} {no color}
-%D {\externalfigure[demofig][color=pdftoolscolor]} {indexed duotone}
-%D {\externalfigure[demofig][color=blue-100]} {spot color}
-%D {\externalfigure[demofig][color=yellow-100]} {spot color}
-%D \stopcombination
-%D \stopbuffer
-%D
-%D \getbuffer \typebuffer
-
-\def\definecolor {\dodoubleargument\dodefinecolor}
-\def\defineglobalcolor {\dodoubleargument\dodefineglobalcolor}
-\def\definenamedcolor {\dodoubleargument\dodefinenamedcolor}
-\def\definespotcolor {\dotripleargument\dodefinespotcolor}
-\def\definemultitonecolor{\doquadrupleempty\dodefinemultitonecolor}
-
-% check: registerusedspotcolors
-% check: registerusedcolorchannels
-
-%D \macros
-%D {doifcolorelse, doifcolor}
-%D
-%D Switching to a color is done by means of the following
-%D command. Later on we will explain the use of palets. We
-%D define ourselves a color conditional first.
-
-\ifx\doifcolorelse\undefined
- \let\doifcolorelse\secondoftwoarguments
- \let\doifcolor \gobbleoneargument
-\fi
-
-%D \macros
-%D {localstartcolor,localstopcolor}
-%D
-%D Simple color support, that is without nesting, is provided
-%D by:
-
-\ifx\localstartcolor\undefined
- \let\localstartcolor\undefined
- \let\localstopcolor \undefined
-\fi
-
-%D \macros
-%D {faststartcolor,faststopcolor}
-%D
-%D No checking for arguments and such:
-
-\ifx\faststartcolor\undefined
- \def\faststartcolor[#1]{}
- \def\faststopcolor {}
-\fi
-
-%D These local ones may go away in future versions.
-
-%D \macros
-%D {startcolor,stopcolor}
-%D
-%D The more save method, the one that saves the current color
-%D state and returns to this state afterward, is activated by:
-%D
-%D \showsetup{startcolor}
-
-\ifx\startcolor\undefined
- \let\startcolor\undefined
- \let\stopcolor \undefined
-\fi
-
-%D \macros
-%D {startcurrentcolor,stopcurrentcolor}
-
-\def\startcurrentcolor{\startcolor[\outercolorname]}
-\def\stopcurrentcolor {\stopcolor}
-
-%D \macros
-%D {color,graycolor}
-%D
-%D This leaves the simple color command:
-%D
-%D \showsetup{color}
-%D \showsetup{graycolor}
-
-\ifx\color\undefined
- \def\color [#1]{}
- \def\graycolor[#1]{}
- \def\gray {\graycolor}
-\fi
-
-%D \macros
-%D {localstartraster,localstopraster,
-%D startraster,stopraster,raster}
-%D
-%D The previous conversions are not linear and treat each color
-%D component according to human perception curves. Pure gray
-%D (we call them rasters) has equal color components. In
-%D \CONTEXT\ rasters are only used as backgrounds and these
-%D don't cross page boundaries in the way color does. Therefore
-%D we don't need stacks and marks. Just to be compatible with
-%D color support we offer both 'global' and 'local' commands.
-
-\ifx\startraster\undefined
- \def\startraster [#1]{}
- \def\stopraster {}
- \def\raster [#1]{}
- \def\localstartraster[#1]{}
- \def\localstopraster {}
-\fi
-
-%D \macros
-%D {colorvalue, grayvalue}
-%D
-%D We can typeset the color components using \type{\colorvalue} and
-%D \type{\grayvalue}. The commands:
-%D
-%D \startbuffer
-%D color value of SomeKindOfRed: \colorvalue{SomeKindOfRed} \crlf
-%D gray value of SomeKindOfRed: \grayvalue{SomeKindOfRed}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D show us:
-%D
-%D \startvoorbeeld
-%D \getbuffer
-%D \stopvoorbeeld
-
-\def\colorformatseparator{ }
-
-\ifx\colorvalue\undefined
- \let\colorvalue\gobbleoneargument
- \let\grayvalue \gobbleoneargument
-\fi
-
-% check: \currentcolorname
-% check: \outercolorname
-
-%D \macros
-%D {setupcolor}
-%D
-%D Color definitions can be grouped in files with the name:
-%D
-%D \starttyping
-%D \f!colorprefix-identifier.tex
-%D \stoptyping
-%D
-%D where \type{\f!colorprefix} is \unprotect {\tttf \f!colorprefix}.
-%D Loading such a file is done by \protect
-%D
-%D \showsetup{setupcolor}
-%D
-%D Some default colors are specified in \type{colo-rgb.tex},
-%D which is loaded into the format by:
-%D
-%D \starttyping
-%D \setupcolor[rgb]
-%D \stoptyping
-
-\let\colorstyle\empty
-
-\def\setupcolor
- {\dosingleargument\dosetupcolor}
-
-\def\dosetupcolor[#1]%
- {\doifnot{#1}\colorstyle
- {\def\colorstyle{#1}%
- \processcommalist[#1]\dodosetupcolor}}
-
-\def\dodosetupcolor#1%
- {\makeshortfilename[\truefilename{\f!colorprefix#1}]%
- \startreadingfile
- \readsysfile\shortfilename
- {\showmessage\m!colors4\colorstyle}
- {\showmessage\m!colors5\colorstyle}%
- \stopreadingfile}
-
-\let\usecolors\setupcolor
-
-% check: \chardef\currentcolorchannel=0
-% check: \startcolormode
-% check: \newif\iffilterspotcolor \filterspotcolorfalse
-% check: \newif\ifdoingspotcolor \doingspotcolorfalse
-% check: \registercolorchannel
-
-%D \macros
-%D {definetransparency}
-%D
-%D This command numbers to names:
-
-\def\definetransparency
- {\dodoubleargument\dodefinetransparency}
-
-\def\setupcolors
- {\dosingleargument\dosetupcolors}
-
-\def\resetcolorsplitting
- {\chardef\currentcolorchannel\zerocount
- \let\currentspotcolor\empty
- \filterspotcolorfalse}
-
-\def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplit\fi}
-\def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplit-\fi}
-
-\def\setcolorsplitting
- {\resetsystemmode{\v!color\colorsplitsuffix}%
- \resetcolorsplitting
- \processaction
- [\@@clsplit]
- [ c=>\chardef\currentcolorchannel1,%
- m=>\chardef\currentcolorchannel2,%
- y=>\chardef\currentcolorchannel3,%
- k=>\chardef\currentcolorchannel4,%
- r=>\chardef\currentcolorchannel5,%
- g=>\chardef\currentcolorchannel6,%
- b=>\chardef\currentcolorchannel7,%
- s=>\chardef\currentcolorchannel8,%
- \v!no=>,% \currentcolorchannel0,% all colors
- \s!default=>,% \currentcolorchannel0,% all colors
- \s!unknown=>\filterspotcolortrue
- \edef\currentspotcolor{\commalistelement}]%
- \setsystemmode{\v!color\colorsplitsuffix}%
- \iffilterspotcolor \let\@@clrgb\v!no \fi}
-
-\ifx\dosetupcolormodel\undefined
- \let\dosetupcolormodel\relax
-\fi
-
-\def\dosetupcolors[#1]% some no longer make sense in MkIV
- {\getparameters[\??cl][#1]%
- \doifelse\@@clspot\v!yes
- \SPOTsupportedtrue
- \SPOTsupportedfalse
- \doifelsenothing\@@clsplit
- \resetcolorsplitting
- \setcolorsplitting
- \doifelse\@@clreduction\v!yes
- \reduceCMYKtrue
- \reduceCMYKfalse
- \doifelse\@@clexpansion\v!yes
- \freezecolorstrue
- \freezecolorsfalse
- \doifelse\@@clcriterium\v!all
- \hidesplitcolortrue
- \hidesplitcolorfalse
- \doifelse\@@clrgb\v!no
- {\ifRGBsupported \showmessage\m!colors {9}\v!rgb\RGBsupportedfalse\fi}
- {\ifRGBsupported\else\showmessage\m!colors{10}\v!rgb\RGBsupportedtrue \fi}%
- \doifelse\@@clcmyk\v!no
- {\ifCMYKsupported \showmessage\m!colors {9}\v!cmyk\CMYKsupportedfalse\fi}
- {\ifCMYKsupported\else\showmessage\m!colors{10}\v!cmyk\CMYKsupportedtrue \fi}%
- \doifelse\@@clmpcmyk\v!no
- {\ifMPcmykcolors \showmessage\m!colors {9}{\v!mp\v!cmyk}\MPcmykcolorsfalse\fi}
- {\ifMPcmykcolors\else\showmessage\m!colors{10}{\v!mp\v!cmyk}\MPcmykcolorstrue \fi}%
- \doifelse\@@clmpspot\v!no
- {\ifMPspotcolors \showmessage\m!colors {9}{\v!mp\v!spot}\MPspotcolorsfalse\fi}
- {\ifMPspotcolors\else\showmessage\m!colors{10}{\v!mp\v!spot}\MPspotcolorstrue \fi}%
- \preferGRAYfalse
- \processaction
- [\@@clconversion]
- [ \v!yes=>\preferGRAYtrue,
- \v!always=>\preferGRAYtrue\RGBsupportedfalse\CMYKsupportedfalse]%
- \ifRGBsupported
- \converttoGRAYfalse
- \forcegrayMPcolorsfalse
- \else\ifCMYKsupported
- \converttoGRAYfalse
- \forcegrayMPcolorsfalse
- \convertMPcolorstrue
- \ifreduceCMYK
- \reduceMPcolorstrue
- \fi
- \else
- \ifconverttoGRAY\else\showmessage\m!colors{11}\empty\fi
- \converttoGRAYtrue
- \forcegrayMPcolorstrue
- \convertMPcolorsfalse
- \reduceMPcolorsfalse
- \fi\fi
- \processaction
- [\@@clstate]
- [ \v!global=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
- \incolortrue\localcolorfalse,
- \v!local=>\ifincolor\else\showmessage\m!colors2\colorstyle\fi
- \incolortrue\localcolortrue,
- \v!start=>\ifincolor\else\showmessage\m!colors1\colorstyle\fi
- \incolortrue\localcolorfalse
- \let\@@clstate\v!global,
- \v!stop=>\incolorfalse\localcolorfalse
- \forcegrayMPcolorstrue]%
- \dosetupcolormodel
- \initializemaintextcolor}
-
-%D \macros
-%D {startregistercolor,stopregistercolor,permitcolormode}
-%D
-%D If you only want to register a color, the switch \type
-%D {\ifpermitcolormode} can be used. That way the nested
-%D colors know where to go back to.
-
-\ifx\startregistercolor\undefined
- \def\startregistercolor[#1]{}
- \def\stopregistercolor {}
-\fi
-
-%D We use these macros for implementing text colors
-%D (actually, the first application was in foreground
-%D colors).
-%D
-%D \starttyping
-%D \starttextcolor[red]
-%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
-%D \stoptextcolor
-%D \stoptyping
-%D
-%D This is more efficient than the alternative:
-%D
-%D \starttyping
-%D \setupbackgrounds[text][foregroundcolor=red]
-%D \startregistercolor[red]
-%D \dorecurse{10}{\input tufte \color[green]{oeps} \par}
-%D \stopregistercolor
-%D \stoptyping
-
-\def\maintextcolor {}
-\def\defaulttextcolor {black}
-\def\@@themaintextcolor{themaintextcolor}
-
-\ifx\initializemaintextcolor\undefined
- \def\starttextcolor [#1]{}
- \def\stoptextcolor {}
- \def\initializemaintextcolor {}
-\fi
-
-\ifx\restoretextcolor\undefined % to be redone
- \let\restoretextcolor \firstofoneargument
- \let\localstarttextcolor\relax
- \let\localstoptextcolor \relax
-\fi
-
-%D In this documentation we will not go into too much details
-%D on palets. Curious users can find more information on this
-%D topic in \from[use of color].
-%D
-%D At the moment we implemented color in \CONTEXT\ color
-%D printing was not yet on the desktop. In spite of this lack our
-%D graphics designer made colorfull illustrations. When printed
-%D on a black and white printer, distinctive colors can come
-%D out equally gray. We therefore decided to use only colors
-%D that were distinctive in colors as well as in black and
-%D white print.
-%D
-%D Although none of the graphic packages we used supported
-%D logical colors and global color redefition, we build this
-%D support into \CONTEXT. This enabled us to experiment and
-%D also prepared us for the future.
-
-%D \macros
-%D {definepalet}
-%D
-%D Colors are grouped in palets. The colors in such a palet can
-%D have colorful names, but best is to use names that specify
-%D their use, like {\em important} or {\em danger}. As a sort
-%D of example \CONTEXT\ has some palets predefined,
-%D like:\footnote{At the time I wrote the palet support, I was
-%D reading 'A hort history of time' of S.~Hawkins, so that's
-%D why we stuck to quarks.}
-%D
-%D \starttyping
-%D \definepalet
-%D [alfa]
-%D [ top=rood:7,
-%D bottom=groen:6,
-%D up=blauw:5,
-%D down=cyaan:4,
-%D strange=magenta:3,
-%D charm=geel:2]
-%D \stoptyping
-%D
-%D It's formal definition is:
-%D
-%D \showsetup{definepalet}
-%D
-%D Visualized, such a palet looks like:
-%D
-%D \startbuffer[palet]
-%D \showpalet [alfa] [horizontal,name,number,value]
-%D \stopbuffer
-%D
-%D \startlinecorrection
-%D \getbuffer[palet]
-%D \stoplinecorrection
-%D
-%D This bar shows both the color and gray alternatives of the
-%D palet components (not visible in black and white print).
-%D
-%D When needed, one can copy a palet by saying:
-%D
-%D \starttyping
-%D \definepalet [TEXcolorpretty] [colorpretty]
-%D \stoptyping
-%D
-%D This saves us some typing in for instance the modules that
-%D deal with pretty verbatim typesetting.
-
-\def\definepalet
- {\dodoubleargument\dodefinepalet}
-
-\def\dodefinepalet[#1][#2]%
- {\doifassignmentelse{#2}
- {%\showmessage\m!colors6{#1}%
- \letvalue{\??pa#1}\empty
- \setevalue{\??pa\??pa#1}{#2}%
- \def\dodododefinepalet[##1=##2]%
- {\doifvaluesomething{\??pa#1}
- {\setevalue{\??pa#1}{\csname\??pa#1\endcsname,}}%
- \setevalue{\??pa#1}{\csname\??pa#1\endcsname##1}%
- \dodefinepaletcolor{#1}{##1}{##2}}%
- \def\dododefinepalet##1%
- {\dodododefinepalet[##1]}%
- \processcommalist[#2]\dododefinepalet}
- {\doifdefined{\??pa#2}
- {\expanded{\dodefinepalet[#1][\csname\??pa\??pa#2\endcsname]}}}}
-
-\ifx\dodefinepaletcolor\undefined
- \let\dodefinepaletcolor\gobblethreearguments
-\fi
-
-\let\paletsize\!!zerocount
-
-\def\getpaletsize[#1]%
- {\getcommacommandsize[\csname\??pa\??pa#1\endcsname]%
- \edef\paletsize{\number\commalistsize}}
-
-%D Instead of refering to colors, one can also directly specify
-%D a color:
-%D
-%D \starttyping
-%D \definepalet[test][xx=green]
-%D \definepalet[test][xx={y=.4}]
-%D \stoptyping
-
-%D \macros
-%D {setuppalet}
-%D
-%D Colors are taken from the current palet, if defined.
-%D Setting the current palet is done by:
-%D
-%D \showsetup{setuppalet}
-
-\let\currentpalet\empty
-
-\def\setuppalet
- {\dosingleempty\dosetuppalet}
-
-\def\dosetuppalet[#1]%
- {\edef\currentpalet{#1}%
- \ifx\currentpalet\empty
- % seems to be a reset
- \else\ifcsname\??pa\currentpalet\endcsname
- \edef\currentpalet{#1:}%
- \else
- \showmessage\m!colors7\currentpalet
- \let\currentpalet\empty
- \fi\fi}
-
-%D \macros
-%D {showpalet}
-%D
-%D The previous visualization was typeset with:
-%D
-%D \typebuffer[palet]
-%D
-%D This commands is defined as:
-%D
-%D \showsetup{showpalet}
-
-\fetchruntimecommand \showpalet {\f!colorprefix\s!run}
-
-%D \macros
-%D {showcolorcomponents}
-%D
-%D \starttyping
-%D \showcolorcomponents[color-1,color-2]
-%D \stoptyping
-
-\fetchruntimecommand \showcolorcomponents {\f!colorprefix\s!run}
-
-%D \macros
-%D {definecolorgroup}
-%D
-%D The naming of the colors in this palet suggests some
-%D ordening, which in turn is suported by color grouping.
-%D
-%D \starttyping
-%D \definecolorgroup
-%D [red]
-%D [1.00:0.90:0.90,
-%D 1.00:0.80:0.80,
-%D 1.00:0.70:0.70,
-%D 1.00:0.55:0.55,
-%D 1.00:0.40:0.40,
-%D 1.00:0.25:0.25,
-%D 1.00:0.15:0.15,
-%D 0.90:0.00:0.00]
-%D \stoptyping
-%D
-%D In such a color group colors are numbered from~$1$ to~$n$.
-%D
-%D \showsetup{definecolorgroup}
-%D
-%D This kind of specification is not only more compact than
-%D defining each color separate, it also loads faster and takes
-%D less bytes.
-
-\def\definecolorgroup
- {\dotripleempty\dodefinecolorgroup}
-
-\def\dododefinecolorgroupgray [#1][#2:#3]{\definecolor [#1:\the\colorcount][s=#2]}
-\def\dododefinecolorgrouprgb [#1][#2:#3:#4:#5]{\definecolor [#1:\the\colorcount][r=#2,g=#3,b=#4]}
-\def\dododefinecolorgroupcmyk[#1][#2:#3:#4:#5:#6]{\definecolor [#1:\the\colorcount][c=#2,m=#3=,y=#4,k=#5]}
-\def\dododefinecolorgroupspot [#1][#2:#3:#4]{\definespotolor[#1:\the\colorcount][#2][p=#3]}
-
-\def\dododefinecolorgroup#1#2%
- {\advance\colorcount\plusone
- \getvalue{dododefinecolorgroup\currentcolorspace}[#1][#2:0:0:0:0]}
-
-\def\dodefinecolorgroup[#1][#2][#3]% obsolete, just use palets
- {\ifthirdargument
- \doifelsenothing{#2}{\let\currentcolorspace\v!rgb}{\def\currentcolorspace{#2}}%
- \colorcount\zerocount
- \processcommalist[#3]{\dododefinecolorgroup{#1}}%
- \else
- \doifinstringelse{:}{#2}
- {\definecolorgroup[#1][\v!rgb][#2]}
- {\doloop
- {\doifdefinedelse{\??cr#2:\recurselevel}
- {\setevalue{\??cr#1:\recurselevel}{\csname\??cr#2:\recurselevel\endcsname}}
- {\exitloop}}}%
- \fi}
-
-%D \macros
-%D {showcolorgroup}
-%D
-%D We can show the group by:
-%D
-%D \startbuffer
-%D \showcolorgroup [blue] [horizontal,name,number,value]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D or in color:
-%D
-%D \startlinecorrection
-%D \getbuffer
-%D \stoplinecorrection
-%D
-%D which uses:
-%D
-%D \showsetup{showcolorgroup}
-
-\fetchruntimecommand \showcolorgroup {\f!colorprefix\s!run}
-
-%D There are ten predefined color groups, like
-%D \color[green]{\em groen}, \color[red]{\em rood},
-%D \color[blue]{\em blauw}, \color[cyan]{\em cyaan},
-%D \color[magenta]{\em magenta} and \color[yellow]{\em geel}.
-%D
-%D \startlinecorrection
-%D \hbox to \hsize
-%D {\hss
-%D \showcolorgroup [red] [vertical,name,number]\hss
-%D \showcolorgroup [green] [vertical,name]\hss
-%D \showcolorgroup [blue] [vertical,name]\hss
-%D \showcolorgroup [cyan] [vertical,name]\hss
-%D \showcolorgroup [magenta][vertical,name]\hss
-%D \showcolorgroup [yellow] [vertical,name]\hss}
-%D \stoplinecorrection
-%D
-%D These groups are used to define palets {\em alfa} upto {\em
-%D zeta}. As long as we don't use colors from the same row, we
-%D get ourselves distinctive palets. By activating such a palet
-%D one gains access to its members {\em top} to {\em charm} (of
-%D course one should use more suitable names than these).
-%D
-%D \startlinecorrection
-%D \hbox to \hsize
-%D {\showpalet [alfa] [vertical,name,number]\hss
-%D \showpalet [beta] [vertical,name]\hss
-%D \showpalet [gamma] [vertical,name]\hss
-%D \showpalet [delta] [vertical,name]\hss
-%D \showpalet [epsilon] [vertical,name]\hss
-%D \showpalet [zeta] [vertical,name]}
-%D \stoplinecorrection
-%D
-%D By using the keyword \type {value} the individual color
-%D components are shown too. When printed in color, these
-%D showcases show both the colors and the gray value.
-
-%D \macros
-%D {comparepalet}
-%D
-%D There are some more testing macros available:
-%D
-%D \startbuffer
-%D \comparepalet [alfa]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D shows the palet colors against a background:
-%D
-%D \startlinecorrection
-%D \getbuffer
-%D \stoplinecorrection
-%D
-%D The formal definition is:
-%D
-%D \showsetup{comparepalet}
-
-\fetchruntimecommand \comparepalet {\f!colorprefix\s!run}
-
-%D \macros
-%D {comparecolorgroup}
-%D
-%D The similar command:
-%D
-%D \startbuffer
-%D \comparecolorgroup [blue]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D shows color groups:
-%D
-%D \startlinecorrection
-%D \getbuffer
-%D \stoplinecorrection
-%D
-%D this commands are defined as:
-%D
-%D \showsetup{comparecolorgroup}
-
-\fetchruntimecommand \comparecolorgroup {\f!colorprefix\s!run}
-
-%D \macros
-%D {showcolor}
-%D
-%D But let's not forget that we also have the more traditional
-%D non||related colors. These show up after:
-%D
-%D \starttyping
-%D \showcolor [name]
-%D \stoptyping
-%D
-%D Where \type{name} for instance can be \type{rgb}.
-%D
-%D \showsetup{showcolor}
-
-\fetchruntimecommand \showcolor {\f!colorprefix\s!run}
-
-%D It would make sense to put the following code in \type
-%D {colo-mps}, but it it rather low level.
-
-%D \macros
-%D {negatecolorcomponent,negatedcolorcomponent}
-%D
-%D These speak for themselves. See \type {colo-ext} for usage.
-
-\def\negatecolorcomponent#1% #1 = \macro
- {\scratchdimen\onepoint\advance\scratchdimen-#1\onepoint
- \ifdim\scratchdimen<\zeropoint\scratchdimen\zeropoint\fi
- \edef#1{\withoutpt\the\scratchdimen}}
-
-\let\negatedcolorcomponent\firstofoneargument
-
-\def\negatedcolorcomponent#1%
- {\ifdim\dimexpr\onepoint-#1\onepoint\relax<\zeropoint
- \!!zerocount
- \else
- \expandafter\withoutpt\the\dimexpr\onepoint-#1\onepoint\relax
- \fi}
-
-\def\negatecolorcomponent#1% #1 = \macro
- {\edef#1{\negatedcolorcomponent{#1}}}
-
-%D \macros
-%D {ifMPgraphics, ifMPcmykcolors, MPcolor}
-%D
-%D A very special macro is \type{\MPcolor}. This one can be
-%D used to pass a \CONTEXT\ color to \METAPOST.
-%D
-%D \starttyping
-%D \MPcolor{my own red}
-%D \stoptyping
-%D
-%D This macro returns a \METAPOST\ triplet \type{(R,G,B)}.
-%D Unless \CMYK\ color support is turned on with \type
-%D {MPcmyk}, only \cap{RGB} colors and gray scales are
-%D supported.
-
-\newif\ifMPcmykcolors % \MPcmykcolorsfalse
-\newif\ifMPspotcolors % \MPspotcolorsfalse
-
-\ifx\MPcolor\undefined
- \def\MPcolor#1{(0,0,0)}
-\fi
-
-%D \macros
-%D {PDFcolor,FDFcolor}
-%D
-%D Similar alternatives are avaliable for \PDF:
-
-%D For the moment we keep the next downward compatibility
-%D switch, i.e.\ expanded colors. However, predefined colors
-%D and palets are no longer expanded (which is what I wanted
-%D in the first place).
-%D
-%D Well, in case we want to do color separation and use CMYK
-%D colors only, this is dangerous since unwanted remapping may
-%D take place. Especially when we redefine already defined
-%D colors in another color space (e.g. darkgreen is
-%D predefined in RGB color space, so a redefinition in CMYK
-%D coordinates before RGB mode is disabled, would give
-%D unexpected results due to the already frozen color spec.)
-%D
-%D So, from now on, colors are not frozen any more!
-
-% \appendtoks\setupcolors[\c!expansie=\v!ja]\to\everyjob
-
-\chardef\currentcolorchannel=0
-
-\newif\iffilterspotcolor \filterspotcolorfalse
-\newif\ifdoingspotcolor \doingspotcolorfalse
-
-\def\registercolorchannel#1%
- {\ifdoingspotcolor \else
- \global\expandafter\chardef\csname\??cs#1\endcsname\zerocount
- \fi}
-
-\newif\ifhidesplitcolor \hidesplitcolortrue
-
-%D The next macro is for instance used in figure splitting:
-
-\def\doifseparatingcolorselse
- {\iffilterspotcolor
- \@EA\firstoftwoarguments
- \else\ifcase\currentcolorchannel
- \@EAEAEA\secondoftwoarguments
- \else
- \@EAEAEA\firstoftwoarguments
- \fi\fi}
-
-\def\doifcolorchannelelse#1%
- {\doifseparatingcolorselse
- {\doifelsenothing{#1}
- \secondoftwoarguments
- {\doifelse{#1}\@@clsplit
- \firstoftwoarguments
- \secondoftwoarguments}}
- \secondoftwoarguments}
-
-\def\resetcolorseparation
- {\filterspotcolorfalse
- \chardef\currentcolorchannel\zerocount}
-
-%D These can be used in selecting specific files (like
-%D figuredatabases).
-
-% we already have:
-%
-% \def\colorsplitsuffix{\ifcase\currentcolorchannel\else-\@@clsplitsen\fi}
-% \def\colorsplitprefix{\ifcase\currentcolorchannel\else\@@clsplitsen-\fi}
-
-\def\colorchannelprefix{\doifseparatingcolorselse\@@clsplit\empty-}
-\def\colorchannelsuffix{-\doifseparatingcolorselse\@@clsplit\empty}
-
-%D We now load the low level macros:
-
-\loadmarkfile{colo-ini}
-
-%D We default to the colors defined in \module{colo-rgb} and
-%D support both \cap{RGB} and \cap{CMYK} output. As you can
-%D see, color support is turned off by default. Reduction of
-%D gray colors to gray scales is turned on.
-
-\definecolor[black][s=0]
-\definecolor[white][s=1]
-
-\definetransparency [none] [0]
-\definetransparency [normal] [1]
-\definetransparency [multiply] [2]
-\definetransparency [screen] [3]
-\definetransparency [overlay] [4]
-\definetransparency [softlight] [5]
-\definetransparency [hardlight] [6]
-\definetransparency [colordodge] [7]
-\definetransparency [colorburn] [8]
-\definetransparency [darken] [9]
-\definetransparency [lighten] [10]
-\definetransparency [difference] [11]
-\definetransparency [exclusion] [12]
-
-\setupcolors
- [\c!state=\v!stop,
- \c!conversion=\v!yes,
- \c!reduction=\v!no,
- \c!rgb=\v!yes,
- \c!cmyk=\v!yes,
- \c!spot=\v!yes,
- \c!mp\c!cmyk=\@@clcmyk,
- \c!mp\c!spot=\@@clspot,
- \c!expansion=\v!no,
- \c!textcolor=,
- \c!split=\v!no,
- \c!criterium=\v!all]
-
-\setupcolor
- [\v!rgb]
-
-\protect \endinput
diff --git a/tex/context/base/colo-run.tex b/tex/context/base/colo-run.tex
index 6313255c3..d94ea9801 100644
--- a/tex/context/base/colo-run.tex
+++ b/tex/context/base/colo-run.tex
@@ -155,8 +155,9 @@
\gdef\doshowcolor[#1]%
{\bgroup
\iffirstargument
- \let\colorlist\empty
+ \let\colorlist\empty % not really used, only for colo-run
\let\colorstyle\empty
+ \settrue\collectcolorsinlist
\setupcolor[#1]%
\fi
\def\rule
diff --git a/tex/context/base/cont-cs.tex b/tex/context/base/cont-cs.tex
index 94235a8b3..f878920aa 100644
--- a/tex/context/base/cont-cs.tex
+++ b/tex/context/base/cont-cs.tex
@@ -26,6 +26,14 @@
\installlanguage [\s!sk] [\c!state=\v!start]
\installlanguage [\s!cs] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-de.tex b/tex/context/base/cont-de.tex
index 95976e815..460ca7eca 100644
--- a/tex/context/base/cont-de.tex
+++ b/tex/context/base/cont-de.tex
@@ -31,6 +31,14 @@
\installlanguage [deo] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-en.tex b/tex/context/base/cont-en.tex
index e3275845c..e2b09ecbe 100644
--- a/tex/context/base/cont-en.tex
+++ b/tex/context/base/cont-en.tex
@@ -35,6 +35,12 @@
\installlanguage [\s!sk] [\c!state=\v!start]
\installlanguage [\s!pl] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+% \prependtoks
+% \the \everysetupdocument
+% \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-fil.tex b/tex/context/base/cont-fil.tex
index a0712a42f..28b6b6f55 100644
--- a/tex/context/base/cont-fil.tex
+++ b/tex/context/base/cont-fil.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context File Synonyms}
+\writestatus{loading}{ConTeXt File Synonyms}
\definefilesynonym [chemie] [chemic]
\definefilesynonym [chemics] [chemic]
diff --git a/tex/context/base/cont-fr.tex b/tex/context/base/cont-fr.tex
index c6cf11ff1..d812b28f9 100644
--- a/tex/context/base/cont-fr.tex
+++ b/tex/context/base/cont-fr.tex
@@ -29,6 +29,14 @@
\installlanguage [\s!nl] [\c!state=\v!start]
\installlanguage [\s!it] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-gb.tex b/tex/context/base/cont-gb.tex
index 6e60cd1bc..99d297425 100644
--- a/tex/context/base/cont-gb.tex
+++ b/tex/context/base/cont-gb.tex
@@ -29,6 +29,14 @@
\installlanguage [\s!nl] [\c!state=\v!start]
\installlanguage [\s!it] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-it.tex b/tex/context/base/cont-it.tex
index d3141a4ae..2141e3bc9 100644
--- a/tex/context/base/cont-it.tex
+++ b/tex/context/base/cont-it.tex
@@ -28,6 +28,14 @@
\installlanguage [\s!es] [\c!state=\v!start]
\installlanguage [\s!it] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-log.tex b/tex/context/base/cont-log.tex
index fb821331d..8419394c4 100644
--- a/tex/context/base/cont-log.tex
+++ b/tex/context/base/cont-log.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context TeX Logos}
+\writestatus{loading}{ConTeXt TeX Logos}
%D The system that is used to typeset this text is called \TEX,
%D typeset with an lowered~E. From te beginning of \TEX,
@@ -228,6 +228,7 @@
\def\pdfTeX {pdf\TeX}
\def\pdfeTeX {pdfe-\TeX}
\def\luaTeX {lua\TeX}
+\def\metaTeX {meta\TeX}
\unexpanded\def\XeTeX {X\lower.5ex\hbox{\kern-.15em\mirror{E}}\kern-.1667em\TeX}
% Better, since lm has a mirrored E (don't ask me why)
@@ -251,41 +252,39 @@
{\setbox\scratchbox\hbox{E}%
\raise\dimexpr\ht\scratchbox+\dp\scratchbox\relax\hbox{\rotate[\c!rotation=180]{\box\scratchbox}}}
-\beginNEWTEX
-
-\unexpanded\def\XeTeX
- {X\lower.5ex
- \hbox
- {\kern-.15em
- \iffontchar\font"018E\relax
- \char"018E%
- \else
- \ifx\fontalternative\c!bf\mirror{E}\else
- \ifx\fontalternative\c!it \@XeTeX@\else
- \ifx\fontalternative\c!sl \@XeTeX@\else
- \ifx\fontalternative\c!bi \@XeTeX@\else
- \ifx\fontalternative\c!bs \@XeTeX@\else
- \mirror{E}\fi\fi\fi\fi\fi
- \fi}%
- \kern-.1667em \TeX}
-
-\endNEWTEX
-
-\beginOLDTEX
-
-\unexpanded\def\XeTeX
- {X\lower.5ex
- \hbox
- {\kern-.15em
- \ifx\fontalternative\c!bf\mirror{E}\else
- \ifx\fontalternative\c!it \@XeTeX@\else
- \ifx\fontalternative\c!sl \@XeTeX@\else
- \ifx\fontalternative\c!bi \@XeTeX@\else
- \ifx\fontalternative\c!bs \@XeTeX@\else
- \mirror{E}\fi\fi\fi\fi\fi}%
- \kern-.1667em \TeX}
-
-\endOLDTEX
+\ifnum\texengine=\pdftexengine
+
+ \unexpanded\def\XeTeX
+ {X\lower.5ex
+ \hbox
+ {\kern-.15em
+ \ifx\fontalternative\c!bf\mirror{E}\else
+ \ifx\fontalternative\c!it \@XeTeX@\else
+ \ifx\fontalternative\c!sl \@XeTeX@\else
+ \ifx\fontalternative\c!bi \@XeTeX@\else
+ \ifx\fontalternative\c!bs \@XeTeX@\else
+ \mirror{E}\fi\fi\fi\fi\fi}%
+ \kern-.1667em \TeX}
+
+\else
+
+ \unexpanded\def\XeTeX
+ {X\lower.5ex
+ \hbox
+ {\kern-.15em
+ \iffontchar\font"018E\relax
+ \char"018E%
+ \else
+ \ifx\fontalternative\c!bf\mirror{E}\else
+ \ifx\fontalternative\c!it \@XeTeX@\else
+ \ifx\fontalternative\c!sl \@XeTeX@\else
+ \ifx\fontalternative\c!bi \@XeTeX@\else
+ \ifx\fontalternative\c!bs \@XeTeX@\else
+ \mirror{E}\fi\fi\fi\fi\fi
+ \fi}%
+ \kern-.1667em \TeX}
+
+\fi
\let\ETEX \eTeX
\let\PDFTEX \pdfTeX
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 20813c37b..9e2ca49c0 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -24,8 +24,32 @@
\unprotect
+% we need to figure this out (to be discussed)
+
+\unexpanded\def\textminus
+ {\char \iffontchar\font"2012 "2012 % figuredash
+ \else\iffontchar\font"2013 "2013 % endash
+ \else\iffontchar\font"2212 "2212 % math minus
+ "002D % hyphen
+ \fi\fi\fi}
+
+\unexpanded\def\textplus
+ {\char"002B } % plus
+
+% \def\registerviewerlayer#1#2% global !
+% {\setxvalue{(vl:#1)}{\global\dosetattribute{viewerlayer}{\ctxlua{tex.print(viewerlayers.register('#2'))}}}}
+
+% \setevalue{(vl:)}{\global\doresetattribute{viewerlayer}}
+
+\let\\=\crlf % till we fixed all styles
+
+% \def\pagedir{\expandafter\gobblethreearguments}
+% \def\bodydir{\expandafter\gobblethreearguments}
+
% we have to make an mkii/mkiv core-not
+\ifx\definestructurecounter\undefined
+
\def\dochecknote % only to be called locally, some bools will become class-ones
{% for the moment no mixed text/endnotes modes, so we use
% \footnoteparameter and not \noteparameter (**)
@@ -79,22 +103,24 @@
\skip \currentnoteins\zeropoint
\fi}
-%
-
-\def\writestatus#1#2{\ctxlua{ctx.writestatus(\!!bs#1\!!es,\!!bs#2\!!es)}}
+\fi
\ifx\clearmarks\undefined
\def\clearmarks {\begingroup\afterassignment\doclearmarks\scratchcounter}
\def\doclearmarks{\normalmarks\scratchcounter{}\endgroup}
\fi
-\def\resetmark#1% we cannot use \normalmarks#1{}
- {\global\@EA\chardef\csname\@@mrk\string#1\endcsname\zerocount
- \@EA\clearmarks\csname\@@prk\string#1\endcsname
- \global\@EA\let\csname\@@trk\string#1\endcsname\empty
- \global\@EA\let\csname\@@frk\string#1\endcsname\empty
- \global\@EA\let\csname\@@brk\string#1\endcsname\empty
- \global\@EA\let\csname\@@crk\string#1\endcsname\empty}
+\ifx\@@trk\undefined \else
+
+ \def\resetmark#1% we cannot use \normalmarks#1{}
+ {\global\@EA\chardef\csname\@@mrk\string#1\endcsname\zerocount
+ \@EA\clearmarks\csname\@@prk\string#1\endcsname
+ \global\@EA\let\csname\@@trk\string#1\endcsname\empty
+ \global\@EA\let\csname\@@frk\string#1\endcsname\empty
+ \global\@EA\let\csname\@@brk\string#1\endcsname\empty
+ \global\@EA\let\csname\@@crk\string#1\endcsname\empty}
+
+\fi
%D Since this can be a showstopper, we report the path at the beginning
%D as well as at the end of a run.
@@ -102,15 +128,26 @@
% \writestatus\m!lua{used config path - \ctxlua{tex.print(caches.configpath())}}
% \writestatus\m!lua{used cache path - \ctxlua{tex.print(caches.path)}}
+\startluacode
+ statistics.register("result saved in file", function()
+ return string.format( "%s.%s", "\outputfilename", (tex.pdfoutput>0 and "pdf") or "dvi")
+ end)
+\stopluacode
+
%D For the moment we report some statistics. Later this will become an option,
%D but for now we need this information.
-\def\nomkivstatistics{\ctxlua{function ctx.show_statistics() end}} % for taco
+\def\nomkivstatistics{\ctxlua{statistics.enable = false}} % for taco
\def\resettimer {\ctxlua{environment.starttime = os.clock()}}
\def\elapsedtime {\ctxlua{tex.sprint(os.clock()-environment.starttime)}}
\let\elapsedseconds \elapsedtime
+% we will have a bunch of extra tracers (--dumphash --dumpdelta)
+
+\def\tracersdumphash {\ctxlua{tracers.register_dump_hash(false)}}
+\def\tracersdumpdelta{\ctxlua{tracers.register_dump_hash(true)}}
+
\resettimer
%D For me.
@@ -145,44 +182,33 @@
% texio.write_nl("CREATING "..pth)
% os.execute("mkdir " .. pth)
% end
-% input.output_files = { }
+% resolvers.output_files = { }
% callback.register('find_write_file', function(id,name)
-% input.output_files[name] = file.join(".","tmp","\jobname",name)
-% texio.write_nl("REDIRECTING OUTPUT "..name.. " TO " .. input.output_files[name])
-% return input.output_files[name]
+% resolvers.output_files[name] = file.join(".","tmp","\jobname",name)
+% texio.write_nl("REDIRECTING OUTPUT "..name.. " TO " .. resolvers.output_files[name])
+% return resolvers.output_files[name]
% end)
% callback.register('find_read_file', function(id,name)
% local sname = string.gsub(name,"^\letterpercent./","")
-% if input.output_files[sname] then
-% return input.output_files[name]
+% if resolvers.output_files[sname] then
+% return resolvers.output_files[name]
% elseif string.find(sname,"^\jobname[\letterpercent.\letterpercent-]") then
% local n = file.join(".","tmp","\jobname",sname)
% local f = io.open(n)
% if f then
-% input.output_files[name] = n
+% resolvers.output_files[name] = n
% texio.write_nl("REDIRECTING INPUT "..sname.. " TO " .. n)
% f:close()
% return n
% else
-% return input.findtexfile(name)
+% return resolvers.findtexfile(name)
% end
% else
-% return input.findtexfile(name)
+% return resolvers.findtexfile(name)
% end
% end)
% }
-% The following commands need to be taken care of, e.g. because there is not yet
-% a mkiv module for them. (Currently they're overloaded so we need to redefine them.)
-
-\def\WORD {\groupedcommand{\setcharactercasing[\plusone ]}{}}
-\def\word {\groupedcommand{\setcharactercasing[\plustwo ]}{}}
-\def\Word {\groupedcommand{\setcharactercasing[\plusthree]}{}}
-\def\Words{\groupedcommand{\setcharactercasing[\plusfour]}{}}
-
-\let\WORDS\WORD
-\let\words\word
-
\definestartstop[randomized][\c!before=\dosetattribute{case}{8},\c!after=]
\protect \endinput
diff --git a/tex/context/base/cont-new.tex b/tex/context/base/cont-new.tex
index ee047599b..b8e2a6f95 100644
--- a/tex/context/base/cont-new.tex
+++ b/tex/context/base/cont-new.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2008.10.31 13:58}
+\newcontextversion{2009.05.28 11:23}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
@@ -21,7 +21,7 @@
% it's about time to clean up this file ...
-\writestatus{\m!systems}{beware: some patches loaded from cont-new.tex}
+\writestatus\m!systems{beware: some patches loaded from cont-new.tex}
% \ifx\pdfmapfile \undefined \else \pdfmapfile{ } \fi
@@ -31,13 +31,16 @@
\let\then\relax % \ifnum1>2\then -)
-\def\TransparencyHack % png: /CS /DeviceRGB /I true
- {\appendtoks
- \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}%
- \to \everyPDFxform
- \appendtoks
- \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}%
- \to \everyshipout}
+\def\fastscale#1%
+ {\begingroup
+ \ifnum#1=1000\relax
+ \setfalse\scaleboxdone
+ \else
+ \settrue\scaleboxdone
+ \edef\finalscaleboxxscale{\withoutpt\the\dimexpr#1pt/1000\relax}%
+ \let\finalscaleboxyscale\finalscaleboxxscale
+ \fi
+ \dowithnextbox{\doscaleboxindeed\flushnextbox\endgroup}\hbox}
% \setupcaption [figure] [align=flushleft]
% \setupcaption [figure-1] [align=flushleft,leftmargin=10mm]
@@ -96,9 +99,9 @@
% normally one does not want this to happen nested, maybe there
% is more; non public vars btw, will become conditionals
-\appendtoks \writetoregisterfalse \to \everybeforeutilityread
-\appendtoks \writetolistfalse \to \everybeforeutilityread
-\appendtoks \notesenabledfalse \to \everybeforeutilityread
+\ifx\writetoregisterfalse\undefined \else \appendtoks \writetoregisterfalse \to \everybeforeutilityread \fi
+\ifx\writetolistfalse \undefined \else \appendtoks \writetolistfalse \to \everybeforeutilityread \fi
+\ifx\notesenabledfalse \undefined \else \appendtoks \notesenabledfalse \to \everybeforeutilityread \fi
% \setuplabeltext[\s!itemcount1={{I(},{)}}]
% \def\labeledcountervalue#1{\labeltexts{#1}{\countervalue{#1}}}
@@ -515,69 +518,6 @@
\egroup
-% todo : test low level translation (nl->en) and optimize script
-
-% \definestylecollection[mine]
-
-% \definestyleinstance[mine][default][sorry]
-% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
-% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
-% \definestyleinstance[mine][bf][\sl]
-% \definestyleinstance[mine][sl][\tt]
-
-% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
-
-\definesystemvariable{sx}
-
-\def\definestylecollection
- {\dosingleargument\dodefinestylecollection}
-
-\def\dodefinestylecollection[#1]%
- {\iffirstargument
- \unexpanded\setvalue{#1}{\styleinstance[#1]}%
- \def\docommand##1%
- {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
- \processcommacommand[\alternativelist,\s!default]\dodocommand}%
- \processcommacommand[\stylelist,\s!default]\docommand
- \fi}
-
-\def\definestyleinstance
- {\doquadrupleargument\dodefinestyleinstance}
-
-\def\dodefinestyleinstance[#1][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
- {\iffirstargument
- \doifundefined{#1}{\definestylecollection[#1]}%
- \fi
- \iffourthargument
- \setvalue{\??sx#1:#2:#3}{#4}%
- \else\ifthirdargument
- \setvalue{\??sx#1::#2}{#3}%
- \else\ifsecondargument
- \letvalue{\??sx#1::#2}\empty
- \fi\fi\fi}
-
-\unexpanded\def\styleinstance[#1]% will be faster
- {%\begingroup\expanded{\infofont[#1:\fontstyle:\fontalternative]}\endgroup
- \executeifdefined{\??sx#1:\fontstyle:\fontalternative}%
- {\executeifdefined{\??sx#1:\fontstyle:\s!default}%
- {\executeifdefined{\??sx#1::\fontalternative}
- {\getvalue {\??sx#1::\s!default}}}}}
-
-% \unexpanded\def\styleinstance[#1]%
-% {\csname\??sx#1%
-% \ifcsname:\fontstyle:\fontalternative\endcsname
-% :\fontstyle:\fontalternative
-% \else\ifcsname:\fontstyle:\s!default\endcsname
-% :\fontstyle:\s!default
-% \else\ifcsname::\fontalternative\endcsname
-% ::\fontalternative
-% \else\ifcsname::\s!default\endcsname
-% ::\s!default
-% \else
-% % nothing, \relax
-% \fi\fi\fi\fi
-% \endcsname}
-
% no, wrong! never!
%
% \def\tightlayer[#1]%
@@ -849,16 +789,6 @@
% externfiguur -> grid =ja|hoogte|diepte|halveregel|passend -> helemaal in details
% stelplaatsblokin -> zijuitlijnen=hoogte|diepte|regel|halveregel|grid -> halveregel in 'details'
-% TODO: TEST FIRST, NO CORRECTION NEEDED IN GRID MODE, EVT OPTION
-
-\def\OTRONEsomeherefloat[#1]% spacing between two successive must be better
- {\baselinecorrection % not really needed in grid mode:
- %\ifgridsnapping \else \baselinecorrection \fi % ! ! ! test test test ! ! ! !
- \doplacefloatbox
- \doinsertfloatinfo
- \dochecknextindentation\??bk
- \dorechecknextindentation}
-
% todo: switch koppelen aan par scheelt pos
% to be documented: \startspread .. \stopspread
diff --git a/tex/context/base/cont-nl.tex b/tex/context/base/cont-nl.tex
index 4635d750d..32b82b01a 100644
--- a/tex/context/base/cont-nl.tex
+++ b/tex/context/base/cont-nl.tex
@@ -29,6 +29,14 @@
\installlanguage [\s!nl] [\c!state=\v!start]
\installlanguage [\s!it] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-old.tex b/tex/context/base/cont-old.tex
index f8b4b6062..360b5f2e6 100644
--- a/tex/context/base/cont-old.tex
+++ b/tex/context/base/cont-old.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Old Macros}
+\writestatus{loading}{ConTeXt Old Macros}
\unprotect
diff --git a/tex/context/base/cont-pe.tex b/tex/context/base/cont-pe.tex
index ab2b30bcd..fdf47d680 100644
--- a/tex/context/base/cont-pe.tex
+++ b/tex/context/base/cont-pe.tex
@@ -32,6 +32,14 @@
\installlanguage [\s!nl] [\c!state=\v!start]
\installlanguage [\s!pe] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-ro.tex b/tex/context/base/cont-ro.tex
index e6b2eadf3..9be9b1162 100644
--- a/tex/context/base/cont-ro.tex
+++ b/tex/context/base/cont-ro.tex
@@ -25,6 +25,14 @@
\installlanguage [\s!de] [\c!state=\v!start]
\installlanguage [\s!ro] [\c!state=\v!start]
-\setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\ifnum\texengine=\luatexengine
+ % will be runtime option: typeface
+ \appendtoks
+ \usetypescript[modern]
+ \setuptypeface[modern]
+ \to \everyjob
+\else
+ \setupencoding[default=ec] \usetypescript[fallback][\defaultencoding] \setupbodyfont[rm,12pt]
+\fi
\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/cont-sys.ori b/tex/context/base/cont-sys.ori
index 335a7d984..11c0141e7 100644
--- a/tex/context/base/cont-sys.ori
+++ b/tex/context/base/cont-sys.ori
@@ -14,8 +14,8 @@
\unprotect
% Speed up typescript loading, but at the cost of much memory:
-%
-% \preloadtypescripts
+
+\preloadtypescripts
% If you want another default font:
%
@@ -121,7 +121,6 @@
% When you have your own fonts installed, you may want to predefine:
%
% \usetypescriptfile[type-buy]
-% \usetypescriptfile [type-gyr]
% Some styles default to Lucida Bright. You can overload
% Lucida by Times cum suis. Watch out, the pos collection
@@ -158,8 +157,8 @@
% Enabling run time \METAPOST\ (also enable \write18 in
% texmf.cnf):
-% \runMPgraphicstrue
-% \runMPTEXgraphicstrue
+\runMPgraphicstrue
+\runMPTEXgraphicstrue
% This saves some runtime, but needs a format, which you can
% make with 'texexec --make --alone metafun'. Make sure that
diff --git a/tex/context/base/cont-usr.ori b/tex/context/base/cont-usr.ori
index dab420e3e..5a3070362 100644
--- a/tex/context/base/cont-usr.ori
+++ b/tex/context/base/cont-usr.ori
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{User Settings}
+\writestatus{loading}{ConTeXt User Settings}
\unprotect
diff --git a/tex/context/base/context-base.lmx b/tex/context/base/context-base.lmx
new file mode 100644
index 000000000..5c96b4979
--- /dev/null
+++ b/tex/context/base/context-base.lmx
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!--
+ filename : context-base.xml
+ comment : companion to mtx-server-ctx-startup.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <title><?lua pv('title') ?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <?lmx-include context.css ?>
+ </style>
+ </head>
+ <body>
+ <div id="top"><div id="top-one"><div id="top-two">
+ <?lua pv('title') ?>
+ </div></div></div>
+ <div id="left"><div id="left-one"><div id="left-two">
+ <?lua pv('lefttext') ?>
+ </div></div></div>
+ <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
+ <?lua pv('righttext') ?>
+ </div></div></div></div></div></div></div>
+ <div id="main"><div id='main-settings'>
+ <div class='title'><?lua pv('maintext') ?></div>
+ </div></div>
+ <div id="bottom"><div id="bottom-one"><div id="bottom-two">
+ <?lua pv('bottomtext') ?>
+ </div></div></div>
+ </body>
+</html>
diff --git a/tex/context/base/context-characters.lmx b/tex/context/base/context-characters.lmx
index b992d30b8..b2ddee64e 100644
--- a/tex/context/base/context-characters.lmx
+++ b/tex/context/base/context-characters.lmx
@@ -1,35 +1,41 @@
-<!--
- -- filename : comm-deb.xml
- -- comment : companion to comm-xml.tex
- -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
- -- copyright: PRAGMA ADE / ConTeXt Development Team
- -- license : see context related readme files
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+ filename : context-characters.lmx
+ comment : companion to context.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
-->
-<html>
- <title><?lua pv('title') ?></title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <style type="text/css">
- <!--
- <?lmx-include context.css ?>
- #type {
- text-align: center ;
- }
- #variable {
- width: 10em ;
- text-align: right ;
- margin-right: 1em ;
- }
- #value {
- text-align: left ;
- }
- -->
- </style>
- <script language="JavaScript">
- <!--
- window.focus();
- -->
- </script>
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script language="JavaScript">
+ <!--
+ window.focus();
+ -->
+ </script>
+ <title><?lua pv('title') ?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <!--
+ <?lmx-include context.css ?>
+ #type {
+ text-align: center ;
+ }
+ #variable {
+ width: 10em ;
+ text-align: right ;
+ margin-right: 1em ;
+ }
+ #value {
+ text-align: left ;
+ }
+ -->
+ </style>
+ </head>
<body> <!-- onclick="location.reload()" -->
<div id="top"><div id="top-one"><div id="top-two">
<?lua pv('title') ?>
diff --git a/tex/context/base/context-debug.lmx b/tex/context/base/context-debug.lmx
index 593f35672..8ca2573a9 100644
--- a/tex/context/base/context-debug.lmx
+++ b/tex/context/base/context-debug.lmx
@@ -1,36 +1,41 @@
-<!--
- -- filename : comm-deb.xml
- -- comment : companion to comm-xml.tex
- -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
- -- copyright: PRAGMA ADE / ConTeXt Development Team
- -- license : see context related readme files
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+ filename : context-debug.lmx
+ comment : companion to context.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
-->
-<html>
- <title><?lua pv('title') ?></title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
- <style type="text/css">
- <!--
- <?lmx-include context.css ?>
- #type {
- text-align: center ;
- }
- #variable {
- width: 10em ;
- text-align: right ;
- margin-right: 1em ;
- }
- #value {
- text-align: left ;
- }
- -->
- </style>
- <script language="JavaScript">
- <!--
- window.focus();
- -->
- </script>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script language="JavaScript">
+ <!--
+ window.focus();
+ -->
+ </script>
+ <title><?lua pv('title') ?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <!--
+ <?lmx-include context.css ?>
+ #type {
+ text-align: center ;
+ }
+ #variable {
+ width: 10em ;
+ text-align: right ;
+ margin-right: 1em ;
+ }
+ #value {
+ text-align: left ;
+ }
+ -->
+ </style>
+ </head>
<body>
<div id="top"><div id="top-one"><div id="top-two">
<?lua pv('title') ?>
@@ -41,7 +46,6 @@
<div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
<!-- empty -->
</div></div></div></div></div></div></div>
- <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five"></div></div></div></div></div></div></div>
<div id="main"><div id='main-settings'>
<?lua if tracers.knownlist('scratch') then ?>
<h1>Scratch Variables</h1>
diff --git a/tex/context/base/context-error.lmx b/tex/context/base/context-error.lmx
index df3ad9090..015d74c9f 100644
--- a/tex/context/base/context-error.lmx
+++ b/tex/context/base/context-error.lmx
@@ -1,26 +1,30 @@
-<!--
- -- filename : comm-err.xml
- -- comment : companion to comm-xml.tex
- -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
- -- copyright: PRAGMA ADE / ConTeXt Development Team
- -- license : see context related readme files
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<!--
+ filename : context-error.lmx
+ comment : companion to context.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
-->
-<html>
- <title><?lua pv('title')?></title>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <style type="text/css">
- <!--
- <?lmx-include context.css ?>
- -->
- </style>
- <script language="JavaScript">
- <!--
- window.focus();
- parent.close();
- -->
- </script>
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script language="JavaScript">
+ <!--
+ window.focus();
+ -->
+ </script>
+ <title><?lua pv('title')?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <!--
+ <?lmx-include context.css ?>
+ -->
+ </style>
+ </head>
<body>
<div id="top"><div id="top-one"><div id="top-two">
<?lua pv('title')?>
@@ -40,7 +44,7 @@
<tr><td>File </td><td>&nbsp;&nbsp;&nbsp;<?lua tv('filename') ?></td></tr>
<tr><td>Line </td><td>&nbsp;&nbsp;&nbsp;<?lua tv('linenumber') ?></td></tr>
</table>
- </br>
+ <br/>
<pre>
<?lua pv('errorcontext')?>
</pre>
diff --git a/tex/context/base/context-fonttest.lmx b/tex/context/base/context-fonttest.lmx
new file mode 100644
index 000000000..b90af179d
--- /dev/null
+++ b/tex/context/base/context-fonttest.lmx
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!--
+ filename : context-fonttest.lmx
+ comment : companion to mtx-server-ctx-fonttest.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script type="text/javascript">
+ <!--
+ window.focus() ;
+ <?lua pv('javascripts')?> ;
+ <?lua pv('javascriptdata')?> ;
+ -->
+ </script>
+ <title><?lua pv('title')?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <?lmx-include context.css ?>
+ </style>
+ </head>
+ <body onLoad="<?lua pv('javascriptinit')?>">
+ <form action="<?lua pv('formaction')?>" name="main-form">
+ <div id="top"><div id="top-one"><div id="top-two">
+ <?lua pv('title')?>
+ </div></div></div>
+ <div id="left"><div id="left-one"><div id="left-two">
+ <?lua pv('status')?>
+ </div></div></div>
+ <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
+ <!-- empty -->
+ </div></div></div></div></div></div></div>
+ <div id="main"><div id="main-settings">
+ <?lua pv('maintext')?>
+ </div></div>
+ <div id="bottom"><div id="bottom-one"><div id="bottom-two">
+ <?lua pv('menu')?>
+ </div></div></div>
+ </form>
+ </body>
+</html>
diff --git a/tex/context/base/context-help.lmx b/tex/context/base/context-help.lmx
new file mode 100644
index 000000000..3c663b0ac
--- /dev/null
+++ b/tex/context/base/context-help.lmx
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!--
+ filename : comm-deb.xml
+ comment : companion to comm-xml.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
+-->
+
+<html>
+ <head>
+ <script language="JavaScript">
+ <!--
+ window.focus();
+ -->
+ </script>
+ <title><?lua pv('title') ?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <!--
+<?lmx-include context.css ?>
+
+#main-left {
+ position: absolute;
+ left: 0% ;
+ top: 0% ;
+ right: 0% ;
+ bottom: 0% ;
+ z-index: 2 ;
+ width: 75% ;
+ height: 100% ;
+ padding: 0% ;
+ margin: 0% ;
+ overflow: auto ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: <?lua pv('color-background-main-left')?> ;
+}
+#main-right {
+ position: absolute;
+ left: 75% ;
+ top: 0% ;
+ right: 0% ;
+ bottom: 0% ;
+ z-index: 2 ;
+ width: 25% ;
+ height: 100% ;
+ padding: 0% ;
+ margin: 0% ;
+ overflow: auto ;
+ border-style: none ;
+ border-width: 0 ;
+ background-color: <?lua pv('color-background-main-right')?> ;
+}
+#main-common-settings {
+ padding: 1em ;
+}
+
+ -->
+ </style>
+ </head>
+ <body>
+ <div id="top"><div id="top-one"><div id="top-two">
+ <?lua pv('title') ?>
+ </div></div></div>
+ <div id="left"><div id="left-one"><div id="left-two">
+ <!-- empty -->
+ </div></div></div>
+ <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
+ <?lua pv('interfaces') ?>
+ </div></div></div></div></div></div></div>
+ <div id="main"><div id='main-settings'>
+ <div id="main-right"><div id="main-common-settings">
+ <?lua pv('names') ?>
+ </div></div>
+ <div id="main-left"><div id="main-common-settings">
+ <h1><?lua pv('maintitle') ?></h1>
+ <?lua pv('maintext') ?>
+ </div></div>
+ </div></div>
+ <div id="bottom"><div id="bottom-one"><div id="bottom-two">
+ <?lua pv('extra') ?>
+ </div></div></div>
+ </body>
+</html>
diff --git a/tex/context/base/context-timing.lmx b/tex/context/base/context-timing.lmx
new file mode 100644
index 000000000..eea9db822
--- /dev/null
+++ b/tex/context/base/context-timing.lmx
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+
+<!--
+ filename : context-timing.xml
+ comment : companion to mtx-timing.tex
+ author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+ copyright: PRAGMA ADE / ConTeXt Development Team
+ license : see context related readme files
+-->
+
+<!--
+ beware: xhtml, so no comment around css
+-->
+
+<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
+ <head>
+ <script language="JavaScript">
+ <!--
+ window.focus();
+ -->
+ </script>
+ <title><?lua pv('title')?></title>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
+ <style type="text/css">
+ <?lmx-include context.css ?>
+ </style>
+ </head>
+ <body>
+ <div id="top"><div id="top-one"><div id="top-two">
+ <?lua pv('title')?>
+ </div></div></div>
+ <div id="left"><div id="left-one"><div id="left-two">
+ <!-- empty -->
+ </div></div></div>
+ <div id="right"><div id="right-safari"><div id="right-one"><div id="right-two"><div id="right-three"><div id="right-four"><div id="right-five">
+ <!-- empty -->
+ </div></div></div></div></div></div></div>
+ <div id="main"><div id="main-settings">
+ <?lua pv('graphics')?>
+ </div></div>
+ <div id="bottom"><div id="bottom-one"><div id="bottom-two">
+ <small>
+ <br/> <br/>
+ <?lua pv('parametersmenu')?>
+ <br/>
+ <?lua pv('nodesmenu')?>
+ </small>
+ </div></div></div>
+ </body>
+</html>
diff --git a/tex/context/base/context.css b/tex/context/base/context.css
index ef4a44cea..f332ae242 100644
--- a/tex/context/base/context.css
+++ b/tex/context/base/context.css
@@ -12,6 +12,12 @@ a.dir-view:link, a.dir-view:active, a.dir-view:visited {
color: #FFFFFF ;
text-decoration: underline ;
}
+.valid {
+ color: #00FF00 ;
+}
+.invalid {
+ color: #FF0000 ;
+}
h1, .title {
font-style: normal ;
font-weight: normal ;
@@ -31,6 +37,15 @@ table {
font-size: 12px ;
margin: 0 ;
}
+th {
+ font-weight: bold ;
+ text-align: left ;
+ padding-bottom: 6px ;
+}
+.tc {
+ font-weight: bold ;
+ text-align: left ;
+}
p, li {
max-width: 60em ;
}
diff --git a/tex/context/base/context.mkii b/tex/context/base/context.mkii
index d58ba7ad7..1a2fa4abb 100644
--- a/tex/context/base/context.mkii
+++ b/tex/context/base/context.mkii
@@ -15,37 +15,46 @@
%D manipulation macros. The first one loads \PLAIN\ \TEX, as
%D minimal as possible.
+\loadcorefile{syst-ini.tex}
+\loadcorefile{norm-tex.tex}
+\loadcorefile{norm-etx.tex}
+\loadcorefile{norm-ptx.tex}
+\loadcorefile{norm-xtx.tex}
+\loadcorefile{norm-ctx.tex}
\loadcorefile{syst-pln.tex}
-\loadcorefile{syst-prm.tex}
-\loadcorefile{syst-cat.tex}
-
-\loadcorefile{syst-etx.tex}
-\loadcorefile{syst-pdt.tex}
-\loadcorefile{syst-omg.tex}
-\loadcorefile{syst-xtx.tex}
-\loadcorefile{syst-mtx.tex}
+\loadmarkfile{catc-ini}
+\loadcorefile{catc-act.tex}
+\loadcorefile{catc-def.tex}
+\loadcorefile{catc-ctx.tex}
+\loadcorefile{catc-sym.tex}
\loadcorefile{syst-gen.tex}
\loadcorefile{syst-ext.tex}
-\loadcorefile{syst-chr.tex}
-\loadcorefile{syst-fnt.tex}
\loadcorefile{syst-new.tex}
-\loadcorefile{syst-con.tex}
-\loadcorefile{syst-var.tex}
-\loadcorefile{syst-str.tex}
-\loadcorefile{syst-rtp.tex}
+\loadmarkfile{syst-con}
+\loadcorefile{thrd-trg.tex} % based on: David Carlisle
+
+\loadmarkfile{syst-fnt}
+\loadmarkfile{syst-str}
+\loadmarkfile{syst-rtp}
+
+\ifnum\texengine=\xetexengine
+ \loadcorefile{xetx-ini.tex}
+ \loadcorefile{xetx-utf.tex}
+ \loadcorefile{xetx-chr.tex}
+ \loadcorefile{xetx-cls.tex}
+\fi
%D To enable selective loading, we say:
-\CONTEXTtrue
+\newif\ifCONTEXT \CONTEXTtrue % will disappear
%D In order to conveniently load files, we need a few
%D support modules.
-\loadcorefile{supp-ini.tex}
-\loadcorefile{supp-fil.tex}
-\loadcorefile{supp-dir.tex}
+\loadmarkfile{supp-fil}
+\loadmarkfile{supp-dir}
%D After this we're ready for the multi||lingual interface
%D modules.
@@ -54,17 +63,13 @@
\loadcorefile{mult-fst.tex}
\loadcorefile{mult-sys.tex}
\loadcorefile{mult-def.tex}
-
-%D We also use some third party macros. These are loaded by
-%D saying:
-
-\loadcorefile{thrd-ran.tex} % based on: Donald Arseneau
-\loadcorefile{thrd-trg.tex} % based on: David Carlisle
+\loadmarkfile{mult-chk}
%D Now we're ready for some general support modules. These
%D modules implement some basic typesetting functionality.
\loadcorefile{core-var.tex}
+\loadmarkfile{core-env}
\loadcorefile{supp-box.tex}
\loadcorefile{supp-mrk.tex}
@@ -72,7 +77,7 @@
\loadcorefile{supp-fun.tex}
%loadcorefile{supp-eps.tex}
\loadcorefile{supp-spe.tex}
-\loadcorefile{supp-ran.tex}
+\loadmarkfile{supp-ran}
%loadcorefile{supp-mps.tex}
\loadmkiifile{supp-mps.tex}
\loadmkiifile{supp-tpi.tex}
@@ -101,7 +106,7 @@
\loadcorefile{core-ins.tex}
\loadcorefile{core-fil.tex}
-\loadcorefile{core-con.tex}
+\loadmarkfile{core-con}
%D We already need some synonyms (patterns). At runtime this
%D file will be reloaded.
@@ -122,43 +127,40 @@
%D The next few modules do what their names state. They
%D load additional definition modules when needed.
-\loadcorefile{regi-ini.tex}
-\loadcorefile{enco-ini.tex}
-\loadcorefile{filt-ini.tex}
-\loadcorefile{hand-ini.tex}
+\loadmarkfile{regi-ini}
\loadcorefile{regi-syn.tex}
-\loadcorefile{lang-ini.tex}
-\loadcorefile{lang-ctx.tex}
-\loadcorefile{lang-dis.tex}
+\loadmarkfile{enco-ini}
+%loadcorefile{filt-ini.tex}
+\loadmarkfile{hand-ini}
+
+\loadmarkfile{lang-ini}
+\loadmarkfile{lang-spe}
+\loadmarkfile{lang-lab}
\loadmarkfile{unic-ini}
\loadcorefile{core-gen.tex}
-\loadcorefile{core-new.tex}
-\loadcorefile{core-uti.tex}
-\loadcorefile{core-two.tex}
+\loadmarkfile{core-uti}
+\loadmarkfile{core-two}
\loadcorefile{core-stg.tex}
-\loadcorefile{spec-mis.tex}
\loadcorefile{spec-ini.tex}
+\loadcorefile{spec-mis.tex}
\loadcorefile{spec-def.tex}
\loadcorefile{spec-var.tex}
-\loadcorefile{colo-ini.tex}
-\loadcorefile{colo-ext.tex}
+\loadmarkfile{colo-ini}
+\loadmarkfile{colo-ext}
%D For the moment we load a lot of languages. In the future
%D we'll have to be more space conservative.
\loadcorefile{lang-mis.tex}
-\loadcorefile{lang-url.tex}
-\loadcorefile{lang-spe.tex}
-\loadcorefile{lang-lab.tex}
+\loadmarkfile{lang-url}
\loadcorefile{lang-ger.tex}
\loadcorefile{lang-ita.tex}
\loadcorefile{lang-sla.tex}
-
\loadcorefile{lang-alt.tex}
\loadcorefile{lang-ana.tex}
\loadcorefile{lang-art.tex}
@@ -167,10 +169,9 @@
\loadcorefile{lang-grk.tex}
\loadcorefile{lang-ind.tex}
\loadcorefile{lang-ura.tex}
-
\loadcorefile{lang-vn.tex}
-
\loadcorefile{lang-ara.tex}
+\loadcorefile{lang-cyr.tex}
%D All kind of symbols are handled in:
@@ -178,43 +179,45 @@
%D Sorting:
-\loadcorefile{sort-ini.tex}
+\loadmarkfile{sort-ini}
%D Next we load some core macro's. These implement the
%D macros' that are seen by the users. The order of loading
%D is important, due to dependancies.
-\loadcorefile{core-spa.tex}
+\loadmarkfile{core-spa}
\loadcorefile{core-grd.tex}
\loadcorefile{core-mar.tex}
-\loadcorefile{core-pos.tex}
+\loadmarkfile{core-pos}
\loadcorefile{core-mak.tex}
\loadcorefile{core-dat.tex}
-\loadcorefile{core-ver.tex}
-\loadcorefile{core-rul.tex}
+\loadmarkfile{core-ver}
+\loadmarkfile{core-rul}
\loadcorefile{core-vis.tex}
\loadcorefile{core-num.tex}
-\loadcorefile{core-tsp.tex}
-\loadcorefile{core-tab.tex}
-\loadcorefile{core-nav.tex}
+\loadcorefile{tabl-pln.tex}
+\loadcorefile{tabl-tab.tex}
+\loadcorefile{tabl-tsp.tex}
+\loadmarkfile{core-nav}
\loadcorefile{core-ref.tex}
-\loadcorefile{core-obj.tex}
+\loadmarkfile{core-obj}
\loadcorefile{core-lst.tex}
\loadcorefile{core-itm.tex}
\loadcorefile{core-des.tex}
-\loadcorefile{core-mat.tex}
+\loadcorefile{core-mat.tex} % should come after math-pln etc
\loadcorefile{core-syn.tex}
-\loadcorefile{core-sys.tex}
+\loadmarkfile{core-sys}
-\loadcorefile{page-ini.tex}
-\loadcorefile{page-bck.tex}
+\loadmarkfile{page-ini}
+\loadmarkfile{page-bck}
\loadcorefile{page-not.tex}
-\loadcorefile{page-one.tex}
+\loadmarkfile{page-one}
\loadcorefile{page-lay.tex}
\loadmkiifile{page-log.tex}
-\loadcorefile{page-txt.tex}
+\loadmarkfile{page-txt}
\loadcorefile{page-sid.tex}
\loadcorefile{page-flt.tex}
+\loadcorefile{page-mis.tex}
\loadcorefile{page-mul.tex}
\loadcorefile{page-set.tex}
\loadcorefile{page-lyr.tex}
@@ -224,19 +227,20 @@
\loadcorefile{page-par.tex}
\loadcorefile{page-mar.tex}
-\loadcorefile{core-job.tex} % why so late?
+\loadmarkfile{core-job} % why so late?
% so far
-\loadmarkfile{core-sec}
+\loadcorefile{core-sec.tex}
\loadcorefile{core-swd.tex}
-\loadcorefile{core-buf.tex}
+\loadmarkfile{core-buf}
\loadcorefile{core-blk.tex}
\loadcorefile{page-imp.tex}
-\loadcorefile{core-tbl.tex}
-\loadcorefile{core-int.tex}
-\loadcorefile{core-ntb.tex}
-\loadcorefile{core-ltb.tex}
+\loadcorefile{tabl-tbl.tex}
+\loadmarkfile{core-int}
+\loadmarkfile{tabl-ntb}
+\loadcorefile{tabl-nte.tex}
+\loadcorefile{tabl-ltb.tex}
%D A few more languages, that have specifics using core
%D functionality:
@@ -246,8 +250,8 @@
%D How about fill||in fields and related stuff?
-\loadcorefile{java-ini.tex}
-\loadcorefile{core-fld.tex}
+\loadmarkfile{java-ini}
+\loadmarkfile{core-fld}
\loadcorefile{core-hlp.tex}
%D Registers can depend on fields, so we load that now.
@@ -260,27 +264,33 @@
%D instead of italian.
\loadmarkfile{font-ini}
-\loadcorefile{font-uni.tex}
+
+\ifnum\texengine=\xetexengine
+ \loadcorefile{font-xtx.tex}
+\fi
+
+\loadmarkfile{font-unk}
+\loadmarkfile{font-uni}
\loadcorefile{font-bfm.tex}
\loadcorefile{enco-pfr.tex}
-\loadcorefile{type-ini.tex}
+\loadmarkfile{type-ini}
\loadcorefile{type-def.tex}
%D Properties. Don't ask.
-\loadcorefile{prop-ini.tex}
-\loadcorefile{prop-lay.tex}
-\loadcorefile{prop-mis.tex}
+\loadmarkfile{prop-ini}
+\loadmarkfile{prop-lay}
+\loadmarkfile{prop-mis}
%D Like languages, fonts, encodings and symbols, \METAPOST\
%D support is also organized in its own class of modules.
\loadmarkfile{meta-ini}
\loadmarkfile{meta-tex}
+\loadmarkfile{meta-pdf}
-\loadcorefile{meta-pdf.tex}
\loadcorefile{meta-pag.tex}
%D Special page handling (maybe even later)
@@ -299,20 +309,21 @@
%D Math.
-\loadcorefile{math-pln.tex}
-\loadcorefile{math-ini.tex}
-\loadcorefile{math-ext.tex}
+\loadmarkfile{math-pln}
+\loadmarkfile{math-ini}
+\loadmarkfile{math-arr}
+\loadmarkfile{math-frc}
%D Now we're ready for more core modules.
-\loadcorefile{core-fnt.tex}
+\loadmarkfile{core-fnt}
\loadcorefile{core-not.tex}
\loadcorefile{core-lnt.tex}
-\loadcorefile{core-mis.tex}
+\loadmarkfile{core-mis}
\loadcorefile{core-trf.tex}
-\loadcorefile{core-inc.tex}
+\loadmarkfile{core-inc}
\loadcorefile{core-fig.tex}
\loadcorefile{core-par.tex}
@@ -330,14 +341,10 @@
\loadcorefile{xtag-ini.tex}
\loadcorefile{xtag-ext.tex}
-\loadcorefile{xtag-prs.tex}
-\loadcorefile{xtag-map.tex}
-\loadcorefile{xtag-stk.tex}
\loadcorefile{xtag-exp.tex}
\loadcorefile{xtag-pre.tex}
\loadcorefile{xtag-xsd.tex}
\loadcorefile{xtag-rng.tex}
-%loadcorefile{xtag-ent.tex}
%D How about this:
@@ -350,14 +357,14 @@
%D This one overloads af few things:
-\loadcorefile{core-ctx.tex}
+\loadmarkfile{core-ctx}
%D Defaults go here (more will be moved to this module
%D later):
\loadcorefile{core-lme.tex}
\loadcorefile{core-ini.tex}
-\loadcorefile{core-def.tex}
+\loadmarkfile{core-def}
%D Preloaded modules (some need xml support):
@@ -374,23 +381,6 @@
%D \item \type{cont-fil}: filename and module synonyms
%D \stopitemize
-\unprotect
-
-\beginLUATEX
- \prependtoks
- \ctxlua{input.starttiming(ctx)}%
- \to \everyjob
- \appendtoks
- \ctxlua{input.stoptiming(ctx)}%
- \to \everyjob
- \appendtoks
- \writestatus\m!lua{used config path - \ctxlua{tex.print(caches.configpath())}}%
- \writestatus\m!lua{used cache path - \ctxlua{tex.print(caches.path)}}%
- \to \everydump
-\endLUATEX
-
-\protect
-
% %D Except from english, no hyphenation patterns are loaded
% %D yet. Users can specify their needs in the next module:
%
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index fb130e5ea..b3542fb21 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -11,171 +11,119 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% syst-cat -> catc-ini + vectors
+% spec-* -> special backends for luatex
+
%D First we load the system modules. These implement a lot of
%D manipulation macros. The first one loads \PLAIN\ \TEX, as
%D minimal as possible.
+\loadcorefile{syst-ini.tex}
+\loadcorefile{norm-ctx.tex}
\loadcorefile{syst-pln.tex}
-\loadcorefile{syst-prm.tex}
-\loadmkivfile{luat-env.tex}
+\loadmkivfile{luat-cod.tex}
+\loadmkivfile{luat-bas.tex}
\loadmkivfile{luat-lib.tex}
-\loadcorefile{syst-cat.tex}
-
-\loadcorefile{syst-etx.tex}
-\loadcorefile{syst-pdt.tex}
-\loadcorefile{syst-omg.tex}
-\loadcorefile{syst-xtx.tex}
-\loadcorefile{syst-mtx.tex}
-\loadcorefile{syst-gen.tex}
-\loadcorefile{syst-ext.tex}
-\loadcorefile{syst-chr.tex}
-\loadcorefile{syst-fnt.tex}
-\loadcorefile{syst-new.tex}
-\loadcorefile{syst-con.tex}
-\loadcorefile{syst-var.tex}
-\loadcorefile{syst-str.tex}
-\loadcorefile{syst-rtp.tex}
+\loadmarkfile{catc-ini}
+\loadcorefile{catc-act.tex}
+\loadcorefile{catc-def.tex}
+\loadcorefile{catc-ctx.tex}
+\loadcorefile{catc-sym.tex}
-%D To enable selective loading, we say:
+\newif\ifCONTEXT \CONTEXTtrue % will disappear
-\CONTEXTtrue
+\loadcorefile{syst-aux.tex}
+\loadcorefile{syst-lua.tex}
+\loadmarkfile{syst-con}
-%D In order to conveniently load files, we need a few
-%D support modules.
+\loadmarkfile{syst-fnt}
+\loadmarkfile{syst-str}
+\loadmarkfile{syst-rtp}
-\loadcorefile{supp-ini.tex}
-\loadcorefile{supp-fil.tex}
-\loadcorefile{supp-dir.tex}
-
-%D We need to initialize characters.
+\loadmarkfile{supp-fil}
+\loadmarkfile{supp-dir}
\loadmkivfile{char-ini.tex}
\loadmkivfile{char-utf.tex}
-%D After this we're ready for the multi||lingual interface
-%D modules.
-
\loadmarkfile{mult-ini}
\loadcorefile{mult-fst.tex}
\loadcorefile{mult-sys.tex}
\loadcorefile{mult-def.tex}
+\loadmarkfile{mult-chk}
\loadmkivfile{luat-ini.tex}
-\loadmkivfile{luat-lmx.tex}
-
-\loadmkivfile{luat-uni.tex}
\loadmkivfile{toks-ini.tex}
-\loadmkivfile{attr-ini.tex}
\loadmkivfile{node-ini.tex}
+\loadmkivfile{node-fin.tex}
\loadmkivfile{node-par.tex}
-%D We also use some third party macros. These are loaded by
-%D saying:
+\loadcorefile{core-var.tex}
-\loadcorefile{thrd-ran.tex} % based on: Donald Arseneau
-\loadcorefile{thrd-trg.tex} % based on: David Carlisle
+\loadcorefile{back-ini.tex}
+\loadcorefile{back-pdf.tex}
-%D Now we're ready for some general support modules. These
-%D modules implement some basic typesetting functionality.
+\loadmkivfile{attr-ini.tex}
-\loadcorefile{core-var.tex}
-\loadmkivfile{luat-deb.tex}
+\loadmarkfile{core-env}
+
+\loadmkivfile{trac-lmx.tex}
+\loadmkivfile{trac-deb.tex}
\loadcorefile{supp-box.tex}
-\loadcorefile{supp-mrk.tex}
+
\loadcorefile{supp-vis.tex}
\loadcorefile{supp-fun.tex}
-\loadcorefile{supp-spe.tex}
-\loadcorefile{supp-ran.tex}
+
+\loadmarkfile{supp-ran}
\loadcorefile{supp-mat.tex}
\loadcorefile{supp-ali.tex}
\loadcorefile{supp-num.tex}
-%D The next module deals with language specific typographic
-%D extensions.
-
\loadcorefile{typo-ini.tex}
-%D Verbatim typesetting is implemented in a separate class of
-%D modules. The pretty typesetting modules are loaded at run
-%D time.
-
\loadcorefile{verb-ini.tex}
-%D The following modules are not sequentially dependent,
-%D i.e. they have ugly dependencies, which will be cleaned
-%D up by adding more overloading.
-
-%D When loading the font, color and special modules, we need a
-%D bit more advanced file handling as well as some general
-%D variables, and features, so next we load:
-
\loadcorefile{core-ins.tex}
\loadcorefile{core-fil.tex}
-\loadcorefile{core-con.tex}
-
-%D We already need some synonyms (patterns). At runtime this
-%D file will be reloaded.
+\loadmarkfile{core-con}
\loadcorefile{cont-fil.tex}
-%D \CONTEXT\ does not implement its own table handling. We
-%D just go for the best there is and load \TABLE. Just to be
-%D sure we do it here, before we redefine \type{|}.
-
-\loadcorefile{thrd-tab.tex} % based on: Michael Wichura / will be reimplemented
-
-%D Here comes the last support modules. They take care of
-%D some language specific things.
-
-\loadcorefile{supp-pat.tex}
-
-%D The next few modules do what their names state. They
-%D load additional definition modules when needed.
-
-\loadcorefile{regi-ini.tex}
-\loadcorefile{enco-ini.tex}
-\loadcorefile{filt-ini.tex}
-\loadcorefile{hand-ini.tex}
+\loadmarkfile{regi-ini}
\loadcorefile{regi-syn.tex}
-\loadcorefile{lang-ini.tex}
-\loadcorefile{lang-ctx.tex}
-\loadcorefile{lang-dis.tex}
+\loadmarkfile{enco-ini}
+\loadmarkfile{hand-ini}
-\loadmarkfile{unic-ini}
+\loadmarkfile{lang-ini}
+\loadmarkfile{lang-spe}
+\loadmarkfile{lang-lab}
-% \readfile{lang-url.pat}{}{} % test
+\loadmarkfile{unic-ini}
\loadcorefile{core-gen.tex}
-\loadcorefile{core-new.tex}
-\loadcorefile{core-uti.tex}
-\loadcorefile{core-two.tex}
+\loadmarkfile{core-uti}
+\loadmarkfile{core-two}
\loadcorefile{core-stg.tex}
-\loadcorefile{spec-mis.tex}
-\loadcorefile{spec-ini.tex}
-\loadcorefile{spec-def.tex}
-\loadcorefile{spec-var.tex}
+% \loadcorefile{spec-ini.tex}
+% \loadcorefile{spec-mis.tex}
+% \loadcorefile{spec-def.tex}
+% \loadcorefile{spec-var.tex}
-\loadcorefile{colo-ini.tex}
-\loadcorefile{colo-ext.tex}
-
-%D For the moment we load a lot of languages. In the future
-%D we'll have to be more space conservative.
+\loadmarkfile{colo-ini}
+\loadmarkfile{colo-ext}
\loadcorefile{lang-mis.tex}
-\loadcorefile{lang-url.tex}
-\loadcorefile{lang-spe.tex}
-\loadcorefile{lang-lab.tex}
+\loadmarkfile{lang-url}
\loadcorefile{lang-ger.tex}
\loadcorefile{lang-ita.tex}
\loadcorefile{lang-sla.tex}
-
\loadcorefile{lang-alt.tex}
\loadcorefile{lang-ana.tex}
\loadcorefile{lang-art.tex}
@@ -184,113 +132,118 @@
\loadcorefile{lang-grk.tex}
\loadcorefile{lang-ind.tex}
\loadcorefile{lang-ura.tex}
-
+\loadcorefile{lang-cjk.tex}
\loadcorefile{lang-vn.tex}
-
\loadcorefile{lang-ara.tex}
-
-%D All kind of symbols are handled in:
+\loadcorefile{lang-cyr.tex}
\loadcorefile{symb-ini.tex}
-%D Sorting:
+\loadmarkfile{sort-ini}
-\loadcorefile{sort-ini.tex}
+\loadmarkfile{core-rul}
-%D Next we load some core macro's. These implement the
-%D macros' that are seen by the users. The order of loading
-%D is important, due to dependancies.
+\loadcorefile{lxml-ini}
-\loadcorefile{core-spa.tex}
+\loadcorefile{strc-ini}
+\loadcorefile{strc-doc}
+\loadcorefile{strc-mar}
+\loadcorefile{strc-prc}
+\loadcorefile{strc-sbe}
+\loadcorefile{strc-lst}
+\loadcorefile{strc-sec}
+\loadcorefile{strc-num}
+\loadcorefile{strc-ren}
+\loadcorefile{strc-xml}
+\loadcorefile{strc-pag} % hm, depends on core-num
+\loadcorefile{strc-def} % might happen later
+\loadcorefile{strc-ref}
+\loadcorefile{strc-reg}
+
+\loadcorefile{bibl-bib}
+
+\loadmarkfile{core-spa}
\loadcorefile{core-grd.tex}
-\loadcorefile{core-mar.tex}
-\loadcorefile{core-pos.tex}
+
+\loadmarkfile{core-pos}
\loadcorefile{core-mak.tex}
-\loadcorefile{core-dat.tex}
-\loadcorefile{core-ver.tex}
-\loadcorefile{core-rul.tex}
+\loadmarkfile{core-ver}
+
\loadcorefile{core-vis.tex}
-\loadcorefile{core-num.tex}
-\loadcorefile{core-tsp.tex}
-\loadcorefile{core-tab.tex}
-\loadcorefile{core-nav.tex}
-\loadcorefile{core-ref.tex}
-\loadcorefile{core-obj.tex}
-\loadcorefile{core-lst.tex}
-\loadcorefile{core-itm.tex}
-\loadcorefile{core-des.tex}
-\loadcorefile{core-mat.tex}
-\loadcorefile{core-syn.tex}
-\loadcorefile{core-sys.tex}
-
-\loadcorefile{page-ini.tex}
-\loadcorefile{page-bck.tex}
+\loadmarkfile{core-nav}
+\loadmarkfile{core-obj}
+
+\loadcorefile{strc-itm.tex}
+\loadcorefile{strc-des.tex}
+\loadcorefile{strc-syn.tex}
+
+\loadmarkfile{core-sys}
+
+\loadmarkfile{page-ini}
+\loadmarkfile{page-bck}
\loadcorefile{page-not.tex}
-\loadcorefile{page-one.tex}
+\loadmarkfile{page-one}
\loadcorefile{page-lay.tex}
-\loadcorefile{page-txt.tex}
+\loadmarkfile{page-txt}
\loadcorefile{page-sid.tex}
-\loadcorefile{page-flt.tex}
+
+\loadcorefile{strc-flt.tex}
+
+\loadcorefile{page-mis.tex}
\loadcorefile{page-mul.tex}
\loadcorefile{page-set.tex}
\loadcorefile{page-lyr.tex}
\loadcorefile{page-mak.tex}
-\loadcorefile{page-num.tex}
+
\loadmarkfile{page-lin}
\loadcorefile{page-par.tex}
\loadcorefile{page-mar.tex}
-\loadcorefile{core-job.tex} % why so late?
+\loadmarkfile{core-job} % why so late?
-% so far
+\loadmarkfile{core-buf}
-\loadmarkfile{core-sec}
-\loadcorefile{core-swd.tex}
-\loadcorefile{core-buf.tex}
-\loadcorefile{core-blk.tex}
-\loadcorefile{page-imp.tex}
-\loadcorefile{core-tbl.tex}
-\loadcorefile{core-int.tex}
-\loadcorefile{core-ntb.tex}
-\loadcorefile{core-ltb.tex}
+\loadcorefile{strc-blk.tex}
-%D A few more languages, that have specifics using core
-%D functionality:
+\loadcorefile{page-imp.tex}
-\loadcorefile{lang-chi.tex}
-\loadcorefile{lang-jap.tex}
+\loadmarkfile{core-int}
+\loadcorefile{strc-bkm.tex} % bookmarks
-%D How about fill||in fields and related stuff?
+\loadcorefile{tabl-pln.tex}
+\loadcorefile{thrd-tab.tex}
+\loadcorefile{tabl-tab.tex}
+\loadcorefile{tabl-tbl.tex}
+\loadmarkfile{tabl-ntb}
+\loadcorefile{tabl-nte.tex}
+\loadcorefile{tabl-ltb.tex}
+\loadcorefile{tabl-tsp.tex}
-\loadcorefile{java-ini.tex}
-\loadcorefile{core-fld.tex}
+\loadmarkfile{java-ini}
+\loadmarkfile{core-fld}
\loadcorefile{core-hlp.tex}
-%D Registers can depend on fields, so we load that now.
-
-\loadcorefile{core-reg.tex}
-
-%D Of course we do need fonts. There are no \TFM\ files
-%D loaded yet, so the format file is independant of their
-%D content. Here we also redefine \type{\it} as {\it italic}
-%D instead of italian.
-
+\loadcorefile{char-enc.tex}
\loadmarkfile{font-ini}
-\loadcorefile{font-uni.tex}
-\loadcorefile{font-bfm.tex}
-\loadmkivfile{font-col.tex}
-
-\loadcorefile{type-ini.tex}
+\loadmarkfile{font-unk}
+\loadmarkfile{font-tra}
+\loadmarkfile{font-uni}
+\loadmarkfile{font-col}
+
+\loadcorefile{typo-spa.tex}
+\loadcorefile{typo-krn.tex}
+\loadcorefile{typo-mir.tex}
+\loadcorefile{typo-brk.tex}
+\loadcorefile{typo-cap.tex}
+
+\loadmarkfile{type-ini}
\loadcorefile{type-def.tex}
-%D Properties. Don't ask.
+\loadcorefile{scrp-ini.tex}
-\loadcorefile{prop-ini.tex}
-\loadcorefile{prop-lay.tex}
-\loadcorefile{prop-mis.tex}
-
-%D Like languages, fonts, encodings and symbols, \METAPOST\
-%D support is also organized in its own class of modules.
+\loadmarkfile{prop-ini}
+\loadmarkfile{prop-lay}
+\loadmarkfile{prop-mis}
\loadmkivfile{mlib-ctx.tex}
\loadmkivfile{mlib-pdf.tex}
@@ -298,121 +251,100 @@
\loadmarkfile{meta-ini}
\loadmarkfile{meta-tex}
+\loadmarkfile{meta-pdf}
-\loadcorefile{meta-pdf.tex}
\loadcorefile{meta-pag.tex}
-%D Special page handling (maybe even later)
-
\loadcorefile{page-flw.tex}
\loadcorefile{page-spr.tex}
\loadcorefile{page-plg.tex}
\loadcorefile{page-str.tex}
-%D Hm.
-
\loadcorefile{core-pgr.tex}
\loadcorefile{core-bar.tex}
\loadcorefile{core-snc.tex}
+\loadmarkfile{math-pln}
+\loadmarkfile{math-ini}
+\loadmarkfile{math-for}
+\loadmarkfile{math-def}
+\loadmarkfile{math-ali}
+\loadmarkfile{math-arr}
+\loadmarkfile{math-frc}
+\loadmarkfile{math-scr}
+\loadmarkfile{math-int}
+\loadmarkfile{math-del}
+\loadmarkfile{math-inl}
+\loadmarkfile{math-dis}
+
+\loadcorefile{strc-mat.tex}
-%D Math.
+\loadmarkfile{chem-ini}
+\loadmarkfile{chem-str}
-\loadcorefile{math-pln.tex}
-\loadcorefile{math-ini.tex}
-\loadcorefile{math-ext.tex}
+\loadmarkfile{core-fnt}
-%D Now we're ready for more core modules.
+\loadcorefile{strc-not.tex}
-\loadcorefile{core-fnt.tex}
-\loadcorefile{core-not.tex}
\loadcorefile{core-lnt.tex}
-\loadcorefile{core-mis.tex}
+\loadmarkfile{core-mis}
\loadcorefile{core-trf.tex}
-\loadcorefile{core-inc.tex}
+\loadmarkfile{core-inc}
\loadcorefile{core-fig.tex}
-\loadcorefile{core-par.tex}
\loadcorefile{core-box.tex}
\loadcorefile{page-app.tex}
\loadmarkfile{meta-fig}
-%D Language specific spacing.
-
\loadcorefile{lang-spa.tex}
-%D Only the basic XML parser and remapper are part of the core.
-%D These macros are loaded last since they overload and|/|or
-%D extend previously defined ones.
-
-\loadmkivfile{lxml-ini.tex}
-
\loadcorefile{xtag-ini.tex}
\loadcorefile{xtag-ext.tex}
-\loadcorefile{xtag-prs.tex}
-\loadcorefile{xtag-map.tex}
-\loadcorefile{xtag-stk.tex}
\loadcorefile{xtag-exp.tex}
\loadcorefile{xtag-pre.tex}
\loadcorefile{xtag-xsd.tex}
\loadcorefile{xtag-rng.tex}
-%loadcorefile{xtag-ent.tex}
-
-%D How about this:
\loadcorefile{meta-xml.tex}
-%D \TEX\ related logo's are always typeset in a special way.
-%D Here they come:
-
\loadcorefile{cont-log.tex}
-%D This one overloads af few things:
+\loadcorefile{task-ini.tex}
-\loadcorefile{core-ctx.tex}
-
-%D Defaults go here (more will be moved to this module
-%D later):
+\loadmarkfile{core-ctx}
\loadcorefile{core-lme.tex}
\loadcorefile{core-ini.tex}
-\loadcorefile{core-def.tex}
-
-%D Preloaded modules (some need xml support):
+\loadmarkfile{core-def}
%usemodule[x][res-04] % xml resource libraries
%usemodule[x][res-08] % rlx runtime conversion
-\usemodule[x][res-12] % rli external indentification
-
-%D At run time, a few more files are loaded, like:
-%D
-%D \startitemize[packed]
-%D \item \type{cont-sys}: local (system dependant) defaults
-%D \item \type{cont-old}: substitutes for old (obsolete) macros
-%D \item \type{cont-new}: new macro implementations (for testing)
-%D \item \type{cont-fil}: filename and module synonyms
-%D \stopitemize
+% \usemodule[x][res-12] % rli external indentification
\unprotect
-\beginLUATEX
- \prependtoks
- \ctxlua{input.starttiming(ctx)}%
- \to \everyjob
- \appendtoks
- \ctxlua{input.stoptiming(ctx)}%
- \to \everyjob
- \appendtoks
- \writestatus\m!lua{used config path - \ctxlua{tex.print(caches.configpath())}}%
- \writestatus\m!lua{used cache path - \ctxlua{tex.print(caches.path)}}%
- \to \everydump
-\endLUATEX
-
-\protect
-
-% %D Except from english, no hyphenation patterns are loaded
-% %D yet. Users can specify their needs in the next module:
-%
-% \input cont-usr.tex
+\prependtoks
+ \ctxlua{statistics.starttiming(ctx)}%
+\to \everyjob
+\appendtoks
+ \ctxlua{statistics.stoptiming(ctx)}%
+\to \everyjob
+\appendtoks
+ \writestatus\m!lua{used config path - \ctxlua{tex.print(caches.configpath())}}%
+ \writestatus\m!lua{used cache path - \ctxlua{tex.print(caches.path)}}%
+\to \everydump
+
+\setupcurrentlanguage[\s!en]
+
+\appendtoks
+ \ctxlua {
+ statistics.report_storage("log")
+ statistics.save_fmt_status("\jobname","\contextversion","context.tex")
+ }%
+\to \everydump
+
+\setsystemmode{experimental} % test with *experimental
+
+\protect \errorstopmode \dump \endinput
diff --git a/tex/context/base/context.rme b/tex/context/base/context.rme
new file mode 100644
index 000000000..1b1e48902
--- /dev/null
+++ b/tex/context/base/context.rme
@@ -0,0 +1,85 @@
+Some Basic information
+----------------------
+
+There are currently three interfaces available:
+
+ cont-en the english version
+ cont-de the german version
+ cont-nl the dutch version
+ cont-cz the czech version
+ cont-ro the romanian version
+ cont-it the italian version
+
+One should compile one of these (or all) into a fmt file.
+When one uses the main file,
+
+ context the undefined version
+
+TeX ask for an interface language as well as a message
+language. Here one has to specify the full name (english,
+german, dutch, etc.) or use the default (enter). The \
+savest way to update the TeX and MetaPost format files
+is to use TeXExec:
+
+texexec --make --alone en nl metafun
+
+In the TeXExec manual you can read how to generate a format
+with specific fonts and patterns.
+
+By default only the english hyphenation patterns are loaded,
+unless more are enabled in:
+
+ cont-usr the typesetting language specifications
+
+Furthermore, users can preset commands etc in the file
+
+ cont-sys a system file loaded at runtime
+
+For questions and remarks on ConTeXt, one can subscribe to
+the list:
+
+ ntg-context@ntg.nl
+
+by sending the message
+
+ subscribe ntg-context
+
+to the list server:
+
+ majordomo@ntg.nl
+
+One can find more info at:
+
+ www.pragma-ade.com
+
+or at the mirror sites mentioned there.
+
+Don't hesitate to ask questions. ConTeXt can do a lot, and
+the manuals are always a bit behind and incomplete. Also take
+a look at the files
+
+ mreadme.pdf
+ minstall.pdf
+ mtexexec.pdf
+ mtexutil.pdf
+
+The teTeX, fpTeX, and 4TeX distributions demonstrate how
+ConTeXt can be integrated in a TeX directory structure.
+
+-------------------------
+
+functionality removed from mkiv:
+
+page-log : layers can do teh same and are more flexible
+core-dat : just use lua for database purposes
+core-swd : this was a temporary solution
+
+functionality changed in mkii and mkiv:
+
+xtag-map : no longer preloaded
+xtag-stk : no longer preloaded
+xtag-prs : no longer preloaded
+
+-------------------------
+
+Hans Hagen, pragma@wxs.nl
diff --git a/tex/context/base/context.tex b/tex/context/base/context.tex
index 875779ef4..08ffc3a60 100644
--- a/tex/context/base/context.tex
+++ b/tex/context/base/context.tex
@@ -13,15 +13,6 @@
\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
-%D For many years \CONTEXT\ supported both good old \TEX\ and \ETEX, but
-%D the time has come (August 2006) to advance, especially now that all
-%D engines provide \ETEX\ functionality and more is on the horizon.
-
-\ifx\eTeXversion\undefined
- \immediate\write16{SORRY CONTEXT NOW NEEDS ETEX}
- \expandafter \end
-\fi
-
%D From the next string (which is set by the script that assembles the
%D distribution) later on we will calculate a number that can be used
%D by use modules to identify the feature level. Starting with version
@@ -29,12 +20,12 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2008.10.31 13:58}
+\edef\contextversion{2009.05.28 11:23}
%D For those who want to use this:
-\def\fmtname {context}
-\def\fmtversion{3.1415926}
+\let\fmtname \contextformat
+\let\fmtversion\contextversion
\let\showcontextbanner\relax
diff --git a/tex/context/base/core-bar.tex b/tex/context/base/core-bar.tex
index 9b7acf17f..5b28afb9d 100644
--- a/tex/context/base/core-bar.tex
+++ b/tex/context/base/core-bar.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Plus Macros / Margin Bars etc}
+\writestatus{loading}{ConTeXt Core Macros / Margin Bars}
\unprotect
diff --git a/tex/context/base/core-blk.tex b/tex/context/base/core-blk.tex
index 8de1099e6..b224bf18e 100644
--- a/tex/context/base/core-blk.tex
+++ b/tex/context/base/core-blk.tex
@@ -13,135 +13,7 @@
% investigate etex's \readline and \scantokens
-\writestatus{loading}{Context Core Macros / Blockmoves}
-
-\startmessages dutch library: textblocks
- title: tekstblokken
- 1: nieuwe versie, tweede run nodig
- 2: wegschrijven blokken naar --
- 3: inlezen blokken uit --
- 4: er is een tweede run nodig
- 5: -- niet verborgen
- 6: -- verborgen en verwerkt
- 7: -- verborgen
- 8: -- gehandhaafd
- 9: -- niet gehandhaafd
- 10: -- geladen en verwerkt
- 11: -- geladen en geplaatst
- 12: -- overgeslagen
-\stopmessages
-
-\startmessages english library: textblocks
- title: textblocks
- 1: new version, second pass needed
- 2: writing blocks to --
- 3: reading blocks from --
- 4: second pass needed
- 5: -- not hidden
- 6: -- hidden and processed
- 7: -- hidden
- 8: -- typeset
- 9: -- not typeset
- 10: -- loaded and processed
- 11: -- loaded and typeset
- 12: -- skipped
-\stopmessages
-
-\startmessages german library: textblocks
- title: textblock
- 1: neue Version, zweiter Durchlauf benoetigt
- 2: schreibe Bloecke zu --
- 3: lese Bloecke von --
- 4: zweiter Durchlauf benoetigt
- 5: -- nicht verborgen
- 6: -- verborgen und verarbeitet
- 7: -- verborgen
- 8: -- gesetzt
- 9: -- nicht gesetzt
- 10: -- geladen und verarbeitet
- 11: -- geladen und gesetzt
- 12: -- ausgelassen
-\stopmessages
-
-\startmessages czech library: textblocks
- title: textovyblok
- 1: nova verze, je treba druhy beh
- 2: zapisuji bloky do --
- 3: ctu bloky z --
- 4: je treba druhy beh
- 5: -- neni skryto
- 6: -- skryto a zpracovano
- 7: -- skryto
- 8: -- vysazeno
- 9: -- nevysazeno
- 10: -- nacteno a zpracovano
- 11: -- nacteno a vysazeno
- 12: -- preskoceno
-\stopmessages
-
-\startmessages italian library: textblocks
- title: blocchi di testo
- 1: nuova versione, seconda passata necessaria
- 2: scrittura dei blocchi su --
- 3: lettura dei blocchi da --
- 4: seconda passata necessaria
- 5: -- non nascosto
- 6: -- nascosto ed elaborato
- 7: -- nascosto
- 8: -- composto
- 9: -- non composto
- 10: -- caricato ed elaborato
- 11: -- caricato e composto
- 12: -- saltato
-\stopmessages
-
-\startmessages norwegian library: textblocks
- title: tekstblokker
- 1: ny versjon, andre gjennomkjøring nødvendig
- 2: skriver blokker til --
- 3: leser blokker fra --
- 4: andre gjennomkjøring nødvendig
- 5: -- ikke skjult
- 6: -- skjult og behandlet
- 7: -- skjult
- 8: -- tegnsatt
- 9: -- ikke tegnsatt
- 10: -- lest inn og behandlet
- 11: -- lest inn og tegnsatt
- 12: -- utelatt
-\stopmessages
-
-\startmessages romanian library: textblocks
- title: blocuri de text
- 1: o noua versiune, este nevoie de inca o trecere
- 2: se scriu blocurile in --
- 3: se citesc blocurile din --
- 4: este nevoie de inca o trecere
- 5: -- nu este ascuns
- 6: -- ascuns si procesat
- 7: -- ascuns
- 8: -- cules
- 9: -- nu este cules
- 10: -- incarcat si procesat
- 11: -- incarcat si cules
- 12: -- sarit peste
-\stopmessages
-
-\startmessages french library: textblocks
- title: blocs de texte
- 1: nouvelle version, une seconde passe est nécessaire
- 2: ecriture des blocs vers --
- 3: lecture des blocs en provenance de --
- 4: seconde passe nécessaire
- 5: -- non caché
- 6: -- caché et traité
- 7: -- caché
- 8: -- composé
- 9: -- non composé
- 10: -- chargé et traité
- 11: -- chargé et composé
- 12: -- sauté
-\stopmessages
+\writestatus{loading}{ConTeXt Core Macros / Blockmoves}
\unprotect
diff --git a/tex/context/base/core-box.tex b/tex/context/base/core-box.tex
index bbcfe451d..97811e78f 100644
--- a/tex/context/base/core-box.tex
+++ b/tex/context/base/core-box.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Boxes}
+\writestatus{loading}{ConTeXt Core Macros / Boxes}
%D This module contains all kind of macros for moving content
%D around. Many macros here come from other modules, but
@@ -274,7 +274,6 @@
\global\ht\collectorbox\scratchdimen
\egroup}
-
%\definecollector[test]
%\setcollector[test]
% [location=rb]
diff --git a/tex/context/base/core-buf.lua b/tex/context/base/core-buf.lua
index a43c33054..389ebde35 100644
--- a/tex/context/base/core-buf.lua
+++ b/tex/context/base/core-buf.lua
@@ -1,17 +1,17 @@
--- filename : core-buf.lua
--- comment : companion to core-buf.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['core-buf'] = {
+ version = 1.001,
+ comment = "companion to core-buf.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-- ctx lua reference model / hooks and such
-- to be optimized
-- redefine buffers.get
-if not versions then versions = { } end versions['core-buf'] = 1.001
-
-if unicode and not utf then utf = unicode.utf8 end
+utf = unicode.utf8
buffers = { }
buffers.data = { }
@@ -22,9 +22,15 @@ buffers.visualizers = { }
-- if needed we can make 'm local
+local utf = unicode.utf8
+
local concat, texsprint, texprint, texwrite = table.concat, tex.sprint, tex.print, tex.write
local utfbyte, utffind, utfgsub = utf.byte, utf.find, utf.gsub
-local byte, sub, find, char, gsub, rep = string.byte, string.sub, string.find, string.char, string.gsub, string.rep
+local byte, sub, find, char, gsub, rep, lower = string.byte, string.sub, string.find, string.char, string.gsub, string.rep, string.lower
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
+local vrbcatcodes = tex.vrbcatcodes
+local ctxcatcodes = tex.ctxcatcodes
local data, commands, flags, hooks, visualizers = buffers.data, buffers.commands, buffers.flags, buffers.hooks, buffers.visualizers
@@ -132,31 +138,19 @@ function buffers.type(name)
end
end
---~ function buffers.typefile(name) -- keep this one, uses tex reader
---~ local t = input.openfile(name)
---~ local action = buffers.typeline
---~ if t then
---~ local lines = { }
---~ while true do
---~ local str = t.reader()
---~ if str then
---~ lines[#lines+1] = str
---~ else
---~ break
---~ end
---~ end
---~ t.close()
---~ local line, n = 0, 0
---~ local first, last, m = buffers.strip(lines)
---~ for i=first,last do
---~ n, line = action(lines[i], n, m, line)
---~ end
---~ end
---~ end
-
-function buffers.typefile(name)
- local str = io.loaddata(name)
- if str then
+function buffers.loaddata(filename) -- this one might go away
+ -- this will be cleaned up when we have split supp-fil completely
+ -- instead of half-half
+ local ok, str, n = resolvers.loaders.tex(filename)
+ if not str then
+ ok, str, n = resolvers.loaders.tex(file.addsuffix(filename,'tex'))
+ end
+ return str or ""
+end
+
+function buffers.typefile(name) -- still somewhat messy, since name can be be suffixless
+ local str = buffers.loaddata(name)
+ if str and str~= "" then
local lines = str:splitlines()
local line, n, action = 0, 0, buffers.typeline
local first, last, m = buffers.strip(lines)
@@ -192,21 +186,6 @@ function buffers.save(name)
io.savedata(f,b)
end
--- todo, use more locals
-
---~ function buffers.get(name)
---~ local b = data[name]
---~ if b then
---~ if type(b) == "table" then
---~ for i=1,#b do
---~ texprint(b[i])
---~ end
---~ else
---~ string.piecewise(b, " *[\010\013]", texprint) -- hm, can be faster
---~ end
---~ end
---~ end
-
local printer = (lpeg.linebyline/texprint)^0
function buffers.get(name)
@@ -217,17 +196,16 @@ function buffers.get(name)
texprint(b[i])
end
else
- -- b:piecewise(" *[\010\013]", texprint) -- hm, can be faster
printer:match(b)
end
end
end
-function buffers.content(name) -- no print
+local function content(name,separator) -- no print
local b = data[name]
if b then
if type(b) == "table" then
- return concat(b," ")
+ return concat(b,separator or "\n")
else
return b
end
@@ -236,24 +214,30 @@ function buffers.content(name) -- no print
end
end
+buffers.content = content
+
function buffers.collect(names,separator) -- no print
local t = { }
if type(names) == "table" then
for i=1,#names do
- local c = buffers.content(names[i])
+ local c = content(names[i],separator)
if c ~= "" then
t[#t+1] = c
end
end
else
for name in names:gmatch("[^,]+") do
- local c = buffers.content(name)
+ local c = content(name,separator)
if c ~= "" then
t[#t+1] = c
end
end
end
- return concat(t,separator or " ") -- maybe this will change to "\n"
+ return concat(t,separator or "\n") -- "\n" is safer due to comments and such
+end
+
+local function tobyte(c)
+ return " [" .. byte(c) .. "] "
end
function buffers.inspect(name)
@@ -262,17 +246,13 @@ function buffers.inspect(name)
if type(b) == "table" then
for _,v in ipairs(b) do
if v == "" then
- texsprint(tex.ctxcatcodes,"[crlf]\\par ")
+ texsprint(ctxcatcodes,"[crlf]\\par ") -- space ?
else
- texsprint(tex.ctxcatcodes,(b:gsub("(.)",function(c)
- return " [" .. byte(c) .. "] "
- end)) .. "\\par")
+ texsprint(ctxcatcodes,(gsub(b,"(.)",tobyte)),"\\par")
end
end
else
- texsprint(tex.ctxcatcodes,(b:gsub("(.)",function(c)
- return " [" .. byte(c) .. "] "
- end)))
+ texsprint(ctxcatcodes,(gsub(b,"(.)",tobyte)))
end
end
end
@@ -286,7 +266,7 @@ visualizers.mp = { }
visualizers.escapetoken = nil
visualizers.tablength = 7
-visualizers.enabletab = false
+visualizers.enabletab = true -- false
visualizers.enableescape = false
visualizers.obeyspace = true
@@ -299,19 +279,18 @@ end
buffers.currentvisualizer = 'default'
function buffers.setvisualizer(str)
- buffers.currentvisualizer = str:lower()
+ buffers.currentvisualizer = lower(str)
if not visualizers[buffers.currentvisualizer] then
buffers.currentvisualizer = 'default'
end
end
function buffers.doifelsevisualizer(str)
- cs.testcase((str ~= "") and (visualizers[str:lower()] ~= nil))
+ cs.testcase((str ~= "") and (visualizers[lower(str)] ~= nil))
end
-- calling routines, don't change
-
function hooks.flush_line(str,nesting)
str = str:gsub(" *[\n\r]+ *"," ")
local flush_line = visualizers[buffers.currentvisualizer].flush_line
@@ -350,7 +329,12 @@ function hooks.empty_line()
end
function hooks.line(str)
- local empty_line = visualizers[buffers.currentvisualizer].line
+ local line = visualizers[buffers.currentvisualizer].line
+ if visualizers.enabletab then
+ str = string.tabtospace(str,visualizers.tablength)
+ else
+ str = gsub(str,"\t"," ")
+ end
if line then
return line(str)
else
@@ -361,19 +345,19 @@ end
-- defaults
function visualizers.default.flush_line(str)
- texsprint(tex.ctxcatcodes,buffers.escaped(str))
+ texsprint(ctxcatcodes,buffers.escaped(str))
end
function visualizers.default.begin_of_line(n)
- texsprint(tex.ctxcatcodes, commands.begin_of_line_command .. "{" .. n .. "}")
+ texsprint(ctxcatcodes, commands.begin_of_line_command,"{",n,"}")
end
function visualizers.default.end_of_line()
- texsprint(tex.ctxcatcodes,commands.end_of_line_command)
+ texsprint(ctxcatcodes,commands.end_of_line_command)
end
function visualizers.default.empty_line()
- texsprint(tex.ctxcatcodes,commands.empty_line_command)
+ texsprint(ctxcatcodes,commands.empty_line_command)
end
function visualizers.default.line(str)
@@ -418,7 +402,7 @@ function visualizers.flush_nested(str, enable) -- no utf, kind of obsolete mess
end
end
result = result .. "\\char" .. byte(sub(str,i,i)) .. " " .. string.rep("}",nested)
- texsprint(tex.ctxcatcodes,result)
+ texsprint(ctxcatcodes,result)
end
-- handy helpers
@@ -461,14 +445,16 @@ buffers.open_nested = rep("\\char"..byte('<').." ",2)
buffers.close_nested = rep("\\char"..byte('>').." ",2)
function buffers.replace_nested(result)
- return (gsub(result:gsub(buffers.open_nested,"{"),buffers.close_nested,"}"))
+ result = gsub(result,buffers.open_nested, "{")
+ result = gsub(result,buffers.close_nested,"}")
+ return result
end
function buffers.flush_result(result,nested)
if nested then
- texsprint(tex.ctxcatcodes,buffers.replace_nested(concat(result,"")))
+ texsprint(ctxcatcodes,buffers.replace_nested(concat(result,"")))
else
- texsprint(tex.ctxcatcodes,concat(result,""))
+ texsprint(ctxcatcodes,concat(result,""))
end
end
@@ -489,15 +475,6 @@ function buffers.escaped(str)
return (utfgsub(str,"(.)", escaped_token))
end
---~ function buffers.escaped_chr(ch)
---~ local b = utfbyte(ch)
---~ if b == 32 then
---~ return "\\obs "
---~ else
---~ return "\\char" .. b .. " "
---~ end
---~ end
-
function buffers.escaped_chr(ch)
if ch == " " then
return "\\obs "
@@ -506,58 +483,17 @@ function buffers.escaped_chr(ch)
end
end
--- redone
-
---~ function visualizers.default.flush_line(str)
---~ local tc = tex.ctxcatcodes
---~ for u in str:utfcharacters() do
---~ texsprint(tc,escaped_token(u))
---~ end
---~ end
-
---~ local a, z, A, Z, zero, nine = byte("a"), byte("z"), byte("A"), byte("Z"), byte("0"), byte("9")
-
---~ function visualizers.default.flush_line(str)
---~ local tc = tex.ctxcatcodes
---~ for b in str:utfvalues() do
---~ if (b>=a and b<=z) or (b>=A and b<=Z) or (b>=zero and b<=nine) then
---~ texsprint(tc,char(b))
---~ elseif b == 32 then
---~ texsprint(tc,"\\obs ")
---~ else
---~ texsprint(tc,"\\char",b," ")
---~ end
---~ end
---~ end
-
---~ function visualizers.default.flush_line(str)
---~ local tc = tex.ctxcatcodes
---~ local vc = tex.vrbcatcodes
---~ local vs = visualizers.obeyspace
---~ for ch in str:utfcharacters() do
---~ if ch == "{" or ch == "}" then
---~ texsprint(tc,"\\char",ch:byte()," ")
---~ elseif vs and ch == " " then
---~ texsprint(tc,"\\obs ")
---~ else
---~ texsprint(vc,ch)
---~ end
---~ end
---~ end
-
function visualizers.default.flush_line(str)
str = str:gsub(" *[\n\r]+ *"," ")
- local vc = tex.vrbcatcodes
if visualizers.obeyspace then
- local tc = tex.ctxcatcodes
- for c in str:utfcharacters() do
+ for c in utfcharacters(str) do
if c == " " then
- texsprint(tc,"\\obs ")
+ texsprint(ctxcatcodes,"\\obs ")
else
- texsprint(vc,c)
+ texsprint(vrbcatcodes,c)
end
end
else
- texsprint(vc,str)
+ texsprint(vrbcatcodes,str)
end
end
diff --git a/tex/context/base/core-buf.mkii b/tex/context/base/core-buf.mkii
index 206992e9b..9937fae01 100644
--- a/tex/context/base/core-buf.mkii
+++ b/tex/context/base/core-buf.mkii
@@ -11,69 +11,14 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
-
-\def\mkresetbuffer
- {\unlinkfile{\TEXbufferfile\currentbuffer}}
-
-\long\def\mksetbuffer#1%
- {\edef\bufferfilename{\TEXbufferfile{\currentbuffer}}%
- \immediate\openout\tmpblocks\bufferfilename
- \defconvertedargument\ascii{#1}%
- \immediate\write\tmpblocks{\ascii}%
- \immediate\closeout\tmpblocks}
-
-\def\mkstartbuffer#1#2#3#4#5% ook grabben a la mkiv / no, we need to add par anchors
- {\doifelsenothing{#4}
- {\letbeundefined{\e!stop\v!buffer}% % \let\stopbuffer=\relax % \undefined
- \edefconvertedargument\beginofblock{\e!start\v!buffer}%
- \edefconvertedargument\endofblock {\e!stop \v!buffer}%
- \ifcase\buffernestmode
- \let\processnextbufferline\processnextbufferlineB
- \else
- \let\processnextbufferline\processnextbufferlineA
- \fi}
- {\letbeundefined{#4}% \letvalue{#4}=\relax % \undefined
- \@EA\defconvertedargument\@EA\beginofblock\@EA{\csname#3\endcsname}% we could use defconvertedcommand here (no \@EA)
- \@EA\defconvertedargument\@EA\endofblock \@EA{\csname#4\endcsname}% we could use defconvertedcommand here (no \@EA)
- \ifcase\buffernestmode
- \let\processnextbufferline\processnextbufferlineB
- \or
- \let\processnextbufferline\processnextbufferlineB
- \else
- \let\processnextbufferline\processnextbufferlineA
- \fi}%
- \def\closebufferfile
- {\ifsegmentatebuffer
- \immediate\write\tmpblocks{\string\stopbufferparagraph}%
- \fi
- \immediate\closeout\tmpblocks
- #5% \egroup
- \getvalue{#4}}%
- \doifelsenothing{#2}
- {\edef\bufferfilename{\TEXbufferfile\jobname}}%
- {\edef\bufferfilename{\TEXbufferfile{#2}}}%
- \immediate\openout\tmpblocks\bufferfilename
- \ifsegmentatebuffer
- \immediate\write\tmpblocks{\string\startbufferparagraph}%
- \fi
- \newcounter\nestedbufferlevel
- \recatcodeuppercharacterstrue
- \setcatcodetable\vrbcatcodes
- \obeylines
- \copybufferline}
+\writestatus{loading}{ConTeXt Core Macros / Buffers}
-\def\mkdobuffer#1% command
- {\beginrestorecatcodes
- #1%
- \endrestorecatcodes}
+\unprotect
-\def\mkgetbuffer {\readjobfile{\TEXbufferfile{\currentbuffer}}\donothing\donothing}
-\def\mktypebuffer{\typefile{\TEXbufferfile{\currentbuffer}}}
+% Helpers:
-% support macros
+\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested
-% \expandafter \convertargument \gobbleoneargument @ \to \emptybufferline
\edefconvertedargument\emptybufferline{ }
\ifx\tmpblocks\undefined \newwrite\tmpblocks \fi
@@ -133,12 +78,271 @@
{\processnextbufferline{#1}\closebufferfile{\flushbufferline{#1}\copybufferline}}
\egroup
-% kind of obsolete with mkiv
+\newif\ifsegmentatebuffer
+\newif\ifemptybufferline
+
+\def\currentbuffer{\jobname}
-\def\mkstartmemorybuffer
+\def\setcurrentbuffer#1%
+ {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}
+
+\def\resetbuffer
+ {\dosingleempty\doresetbuffer}
+
+\def\doresetbuffer[#1]%
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \unlinkfile{\TEXbufferfile\currentbuffer}%
+ \endgroup}
+
+\def\dostartbuffer
+ {\bgroup
+ \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
+ \doquadrupleempty\dodostartbuffer}
+
+\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
+ {\iffourthargument
+ \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
+ \else
+ \def\next{\dododostartbuffer {}{#1}{#2}{#3}}%
+ \fi
+ \next}
+
+\def\dododostartbuffer#1#2#3#4%
+ {%\showmessage\m!systems{15}{#2}%
+ \doifelsevalue{\??bu#1\c!paragraph}\v!yes
+ {\segmentatebuffertrue} % todo in mkiv
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
+ \doifvalue{\??bu#1\c!local}\v!yes
+ {\chardef\buffernestmode\plustwo}% permit nesting
+ \setcurrentbuffer{#2}%
+ \doifelsenothing{#4}
+ {\letbeundefined{\e!stop\v!buffer}% % \let\stopbuffer=\relax % \undefined
+ \edefconvertedargument\beginofblock{\e!start\v!buffer}%
+ \edefconvertedargument\endofblock {\e!stop \v!buffer}%
+ \ifcase\buffernestmode
+ \let\processnextbufferline\processnextbufferlineB
+ \else
+ \let\processnextbufferline\processnextbufferlineA
+ \fi}
+ {\letbeundefined{#4}% \letvalue{#4}=\relax % \undefined
+ \@EA\defconvertedargument\@EA\beginofblock\@EA{\csname#3\endcsname}% we could use defconvertedcommand here (no \@EA)
+ \@EA\defconvertedargument\@EA\endofblock \@EA{\csname#4\endcsname}% we could use defconvertedcommand here (no \@EA)
+ \ifcase\buffernestmode
+ \let\processnextbufferline\processnextbufferlineB
+ \or
+ \let\processnextbufferline\processnextbufferlineB
+ \else
+ \let\processnextbufferline\processnextbufferlineA
+ \fi}%
+ \def\closebufferfile
+ {\ifsegmentatebuffer
+ \immediate\write\tmpblocks{\string\stopbufferparagraph}%
+ \fi
+ \immediate\closeout\tmpblocks
+ \egroup
+ \getvalue{#4}}%
+ \doifelsenothing{#2}
+ {\edef\bufferfilename{\TEXbufferfile\jobname}}%
+ {\edef\bufferfilename{\TEXbufferfile{#2}}}%
+ \immediate\openout\tmpblocks\bufferfilename
+ \ifsegmentatebuffer
+ \immediate\write\tmpblocks{\string\startbufferparagraph}%
+ \fi
+ \newcounter\nestedbufferlevel
+ \recatcodeuppercharacterstrue
+ \setcatcodetable\vrbcatcodes
+ \obeylines
+ \copybufferline}
+
+\letvalue{\e!start\v!buffer}\dostartbuffer
+
+\let\endbuffer\undefined % to please the dep parser
+
+\def\setbuffer
+ {\dosingleempty\dosetbuffer}
+
+\long\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \edef\bufferfilename{\TEXbufferfile{\currentbuffer}}%
+ \immediate\openout\tmpblocks\bufferfilename
+ \defconvertedargument\ascii{#2}%
+ \immediate\write\tmpblocks{\ascii}%
+ \immediate\closeout\tmpblocks
+ \endgroup}
+
+\def\setupbuffer
+ {\dodoubleempty\dosetupbuffer}
+
+\def\dosetupbuffer[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??bu#1][#2]%
+ \else
+ \getparameters[\??bu][#1]%
+ \fi}
+
+\def\dodefinebuffer[#1][#2]%
+ {\iffirstargument % else problems
+ \doglobal\increment\nofdefinedbuffers
+ \letvalue{\??bu#1\c!number }\nofdefinedbuffers
+ \letvalue{\??bu#1\c!paragraph}\v!no
+ \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
+ \setevalue{\e!get #1}{\noexpand\dogetbuffer [#1][def-\nofdefinedbuffers]}%
+ \setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
+ \getparameters[\??bu#1][#2]%
+ \fi}
+
+\def\definebuffer
+ {\dodoubleempty\dodefinebuffer}
+
+\def\getbuffer
+ {\dodoubleempty\dogetbuffer}
+
+\def\dogetbuffer[#1][#2]%
+ {\ifsecondargument
+ \dodogetbuffer[#1][#2]%
+ \else
+ \dodogetbuffer[][#1]%
+ \fi}
+
+\def\dogetbufferasis{\readjobfile{\TEXbufferfile{\currentbuffer}}\donothing\donothing}%
+
+\def\dodogetbuffer[#1][#2]%
+ {\getvalue{\??bu#1\c!before}%
+ \dobuffer{16}{#2}\dogetbufferasis
+ \getvalue{\??bu#1\c!after}}
+
+\def\typebuffer
+ {\dodoubleempty\dotypebuffer}
+
+\def\dogetfilebuffer{\typefile{\TEXbufferfile{\currentbuffer}}}
+
+\def\dotypebuffer[#1][#2]%
+ {\iffirstargument
+ \dobuffer{17}{#1}\dogetfilebuffer
+ \else
+ \dobuffer{17}{#2}\dogetfilebuffer
+ \fi}
+
+\def\dobuffer#1#2#3%
+ {\doifelsenothing{#2}
+ {\dodobuffer#3\jobname}
+ {\processcommalist[#2]{\dodobuffer#3}}}
+
+\def\dodobuffer#1#2% command name
+ {\pushmacro\currentbuffer
+ \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
+ \beginrestorecatcodes
+ #1%
+ \endrestorecatcodes
+ \popmacro\currentbuffer}
+
+\def\processTEXbuffer{\getbuffer} % handy
+
+% seldom used, only in a few projects that demanded more speed
+
+\def\dostartmemorybuffer
{\dosingleempty\dostartmemorybuffer}
\long\def\dostartmemorybuffer[#1]#2\stopbuffer
{\setbuffer[#1]#2\endbuffer}
+\let\dostartfilebuffer\startbuffer
+
+\def\usememorybuffers{\let\startbuffer\dostartmemorybuffer}
+\def\usefilebuffers {\let\startbuffer\dostartfilebuffer}
+
+% this features is soldom used (complex examns where we need to fetch
+% special parts of a text
+%
+% this is not yet supported in mkiv (relatively easy to do but there
+% we don't have the par tags but need to grab 'm
+
+\def\skippedbufferparagraphs{0}
+
+\let\startbufferparagraph\relax
+\let\stopbufferparagraph \par % \relax
+
+\newcount\currentbufferparagraph
+
+\def\getbufferparagraphs
+ {\dodoubleempty\dogetbufferparagraphs}
+
+\def\dosetbufferoffset#1%
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph \zerocount}%
+ \relax}
+
+\def\dogetbufferparagraphs[#1][#2]%
+ {\iffirstargument
+ \ifsecondargument
+ \dosetbufferoffset{#1}%
+ \doifelse{#2}\v!all
+ {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
+ {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
+ \def\next{\getparagraphedbuffer[#1]}%
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\normalbufferparagraph{}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \next}
+
+\def\dogetparagraphbuffer{\readjobfile{\TEXbufferfile{\currentbuffer}}\donothing\donothing}
+
+\def\getparagraphedbuffer[#1]%
+ {\dobuffer{16}{#1}\dogetparagraphbuffer}
+
+\def\dostopbufferparagraph#1%
+ {\getvalue{\??bu#1\c!after}\par}
+
+\def\dostartbufferparagraph#1%
+ {\par\getvalue{\??bu#1\c!before}}
+
+\def\normalbufferparagraph
+ {\advance\currentbufferparagraph \plusone
+ \ifnum\currentbufferparagraph>\zerocount
+ \expandafter\dostartbufferparagraph
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\filterbufferparagraph#1#2%
+ {\advance\currentbufferparagraph \plusone
+ \ifcase\currentbufferparagraph
+ \@EA\gobblebufferparagraph
+ \else
+ \doifinsetelse{\the\currentbufferparagraph}{#2}
+ {\@EA\dostartbufferparagraph}
+ {\@EA\fakebufferparagraph}%
+ \fi
+ {#1}}
+
+\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
+ {}
+
+\def\fakebufferparagraph#1%
+ {\bgroup
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
+ \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}
+
+% definitions
+
+\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]
+
+\setupbuffer
+ [\c!paragraph=\v!no,
+ \c!before=,
+ \c!after=]
+
\protect \endinput
diff --git a/tex/context/base/core-buf.mkiv b/tex/context/base/core-buf.mkiv
index c4f13839d..8b69616b9 100644
--- a/tex/context/base/core-buf.mkiv
+++ b/tex/context/base/core-buf.mkiv
@@ -11,75 +11,80 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-% this will become a proper new verbatim module
+\writestatus{loading}{ConTeXt Core Macros / Buffers}
+
+\registerctxluafile{core-buf}{1.001}
+
+\ifdefined\doinitializeverbatim \else% temp hack
+ \ifdefined\mkinitializeverbatim
+ \let\doinitializeverbatim\mkinitializeverbatim
+ \else
+ \def\doinitializeverbatim{\tttf}
+ \fi
+\fi
\unprotect
-\registerctxluafile{core-buf}{1.001}
+\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested
+
+\newif\ifsegmentatebuffer
+\newif\ifemptybufferline
-\def\mkresetbuffer
- {\ctxlua{buffers.erase("\currentbuffer")}}
+\def\currentbuffer{\jobname}
-\long\def\mksetbuffer#1%
- {\ctxlua{buffers.set("\currentbuffer", \!!bs\detokenize{#1}\!!es)}}
+\def\setcurrentbuffer#1%
+ {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}
-\long\def\mkstartbuffer#1#2#3#4#5%
- {\doifelsenothing{#4}
- {\expanded{\setbuffercapsules{\e!start\v!buffer}{\e!stop\v!buffer}}%
+\def\resetbuffer
+ {\dosingleempty\doresetbuffer}
+
+\def\doresetbuffer[#1]%
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \ctxlua{buffers.erase("\currentbuffer")}%
+ \endgroup}
+
+\def\dostartbuffer
+ {\bgroup
+ \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
+ \doquadrupleempty\dodostartbuffer}
+
+\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
+ {\iffourthargument
+ \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
+ \else
+ \def\next{\dododostartbuffer {}{#1}{#2}{#3}}%
+ \fi
+ \next}
+
+\def\dododostartbuffer#1#2#3#4%
+ {%\showmessage\m!systems{15}{#2}%
+ \doifelsevalue{\??bu#1\c!paragraph}\v!yes
+ {\segmentatebuffertrue} % todo in mkiv
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
+ \doifvalue{\??bu#1\c!local}\v!yes
+ {\chardef\buffernestmode\plustwo}% permit nesting
+ \setcurrentbuffer{#2}%
+ \doifelsenothing{#4}
+ {\normalexpanded{\noexpand\setbuffercapsules{\e!start\v!buffer}{\e!stop\v!buffer}}%
\letvalue\bufferstop\relax}
%{\@EA\setbuffercapsules\@EA{\csname#3\@EA\endcsname\@EA}\@EA{\csname#4\endcsname}}% if we strip later
{\setbuffercapsules{#3}{#4}}%
- \expanded{\dodowithbuffer
+ \normalexpanded{\noexpand\dodowithbuffer
{\currentbuffer}
{\bufferstart}
{\bufferstop}
{\donothing}
- {#5% \egroup
+ {\egroup
\noexpand\getvalue{\bufferstop}}}}
-\def\mkdobuffer#1%
- {#1}
-
-\def\mkdoifelsebuffer#1%
- {\ctxlua{buffers.doifelsebuffer("#1")}}
-
-\def\mkgetbuffer
- {\ctxlua{buffers.get("\currentbuffer")}}
-
-% will move
-
-\ifx\mkinitializeverbatim\undefined \def\mkinitializeverbatim{\tttf} \fi
-
-\def\mktypebuffer
- {\mkdotypebuffer{\v!file}{}{\currentbuffer}}
-
-\def\mkprocessbufferverbatim
- {\mkinitializeverbatim
- \ctxlua{buffers.type("\currentbuffer")}}
-
-\def\mkprocessbufferlinesverbatim#1#2#3%
- {#2%
- % todo, set up numbers
- \mkinitializeverbatim
- \ctxlua{buffers.type("\currentbuffer")}
- #3}
-
-\def\mkdotypebuffer#1#2#3% see dodotypefile
- {\mkdoifelsebuffer{#3}
- {\dosometyping{#1}{#2}{#3}\mkprocessbufferverbatim\mkprocessbufferlinesverbatim}
- {\reporttypingerror{#3}}}
-
-% \def\setbuffercapsules#1#2%
-% {\edef\bufferstart{\strippedcsname#1}\edef\bufferstart{\scantextokens\expandafter{\bufferstart}}%
-% \edef\bufferstop {\strippedcsname#2}\edef\bufferstop {\scantextokens\expandafter{\bufferstop }}}
+\letvalue{\e!start\v!buffer}\dostartbuffer
-\def\setbuffercapsules#1#2% \scantextokens not needed (had a reason at some point)
- {\edef\bufferstart{#1}\edef\bufferstart{\scantextokens\expandafter{\bufferstart}}%
- \edef\bufferstop {#2}\edef\bufferstop {\scantextokens\expandafter{\bufferstop }}}
+\let\endbuffer\undefined % to please the dep parser
\def\dowithbuffer#1#2#3% name, startsequence, stopsequence, before, after
{\setbuffercapsules{#2}{#3}%
- \expanded{\dodowithbuffer{#1}{\bufferstart}{\bufferstop}}}
+ \normalexpanded{\noexpand\dodowithbuffer{#1}{\bufferstart}{\bufferstop}}}
\long\def\dodowithbuffer#1#2#3#4#5% name, startsequence, stopsequence, before, after
{#4%
@@ -97,12 +102,105 @@
\nododowithbuffer}%
\dododowithbuffer}
-% kind of redundant in mkiv
+\def\setbuffercapsules#1#2% \scantextokens not needed (had a reason at some point)
+ {\edef\bufferstart{#1}\edef\bufferstart{\scantextokens\expandafter{\bufferstart}}%
+ \edef\bufferstop {#2}\edef\bufferstop {\scantextokens\expandafter{\bufferstop }}}
+
+\def\setbuffer
+ {\dosingleempty\dosetbuffer}
+
+\long\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
+ {\begingroup
+ \setcurrentbuffer{#1}%
+ \ctxlua{buffers.set("\currentbuffer", \!!bs\detokenize{#2}\!!es)}%
+ \endgroup}
+
+\def\setupbuffer
+ {\dodoubleempty\dosetupbuffer}
+
+\def\dosetupbuffer[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??bu#1][#2]%
+ \else
+ \getparameters[\??bu][#1]%
+ \fi}
+
+\def\dodefinebuffer[#1][#2]%
+ {\iffirstargument % else problems
+ \doglobal\increment\nofdefinedbuffers
+ \letvalue{\??bu#1\c!number }\nofdefinedbuffers
+ \letvalue{\??bu#1\c!paragraph}\v!no
+ \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
+ \setevalue{\e!get #1}{\noexpand\dogetbuffer [#1][def-\nofdefinedbuffers]}%
+ \setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
+ \getparameters[\??bu#1][#2]%
+ \fi}
+
+\def\definebuffer
+ {\dodoubleempty\dodefinebuffer}
+
+\def\getbuffer
+ {\dodoubleempty\dogetbuffer}
+
+\def\dogetbuffer[#1][#2]%
+ {\ifsecondargument
+ \dodogetbuffer[#1][#2]%
+ \else
+ \dodogetbuffer[][#1]%
+ \fi}
-\let\mkstartmemorybuffer\startbuffer
-\let\mkstartfilebuffer \startbuffer
+\def\dogetbufferasis{\ctxlua{buffers.get("\currentbuffer")}}
-% bonus
+\def\dodogetbuffer[#1][#2]%
+ {\getvalue{\??bu#1\c!before}%
+ \dobuffer{16}{#2}\dogetbufferasis
+ \getvalue{\??bu#1\c!after}}
+
+\def\typebuffer
+ {\dodoubleempty\dotypebuffer}
+
+\def\doprocessbufferverbatim
+ {\doinitializeverbatim
+ \ctxlua{buffers.type("\currentbuffer")}}
+
+\def\doprocessbufferlinesverbatim#1#2#3%
+ {#2%
+ % todo, set up numbers
+ \doinitializeverbatim
+ \ctxlua{buffers.type("\currentbuffer")}
+ #3}
+
+\def\doifelsebuffer#1%
+ {\ctxlua{buffers.doifelsebuffer("#1")}}
+
+\def\dodotypebuffer#1#2#3% see dodotypefile
+ {\doifelsebuffer{#3}
+ {\dosometyping{#1}{#2}{#3}\doprocessbufferverbatim\doprocessbufferlinesverbatim}
+ {\reporttypingerror{#3}}}
+
+\def\dotypefilebuffer{\dodotypebuffer{\v!file}{}{\currentbuffer}}%
+
+\def\dotypebuffer[#1][#2]%
+ {\iffirstargument
+ \dobuffer{17}{#1}\dotypefilebuffer
+ \else
+ \dobuffer{17}{#2}\dotypefilebuffer
+ \fi}
+
+\def\dobuffer#1#2#3%
+ {\doifelsenothing{#2}
+ {\dodobuffer#3\jobname}
+ {\processcommalist[#2]{\dodobuffer#3}}}
+
+\def\dodobuffer#1#2% command name
+ {\pushmacro\currentbuffer
+ \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
+ #1%
+ \popmacro\currentbuffer}
+
+\def\processTEXbuffer{\getbuffer} % handy
+
+% extras:
\def\inspectbuffer
{\dosingleempty\doinspectbuffer}
@@ -110,5 +208,107 @@
\def\doinspectbuffer[#1]%
{\setcurrentbuffer{#1}%
\ctxlua{buffers.inspect("\currentbuffer")}}
+
+% seldom used, only in a few projects that demanded more speed
+
+\let\usememorybuffers\relax
+\let\usefilebuffers \relax
+
+% this features is soldom used (complex examns where we need to fetch
+% special parts of a text
+%
+% this is not yet supported in mkiv (relatively easy to do but there
+% we don't have the par tags but need to grab 'm
+
+\def\skippedbufferparagraphs{0}
+
+\let\startbufferparagraph\relax
+\let\stopbufferparagraph \par % \relax
+
+\newcount\currentbufferparagraph
+
+\def\getbufferparagraphs
+ {\dodoubleempty\dogetbufferparagraphs}
+
+\def\dosetbufferoffset#1%
+ {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
+ {\currentbufferparagraph \zerocount}%
+ \relax}
+
+\def\dogetbufferparagraphs[#1][#2]%
+ {\iffirstargument
+ \ifsecondargument
+ \dosetbufferoffset{#1}%
+ \doifelse{#2}\v!all
+ {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
+ {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
+ \def\next{\getparagraphedbuffer[#1]}%
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \else
+ \dosetbufferoffset\empty
+ \def\startbufferparagraph{\normalbufferparagraph{}}%
+ \def\stopbufferparagraph{\dostopbufferparagraph{}}%
+ \def\next{\getparagraphedbuffer[]}%
+ \fi
+ \next}
+
+\def\dotypeparagraphbuffer{\ctxlua{buffers.get("\currentbuffer")}}
+
+\def\getparagraphedbuffer[#1]%
+ {\dobuffer{16}{#1}\dotypeparagraphbuffer}
+
+\def\dostopbufferparagraph#1%
+ {\getvalue{\??bu#1\c!after}\par}
+
+\def\dostartbufferparagraph#1%
+ {\par\getvalue{\??bu#1\c!before}}
+
+\def\normalbufferparagraph
+ {\advance\currentbufferparagraph \plusone
+ \ifnum\currentbufferparagraph>\zerocount
+ \expandafter\dostartbufferparagraph
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\filterbufferparagraph#1#2%
+ {\advance\currentbufferparagraph \plusone
+ \ifcase\currentbufferparagraph
+ \@EA\gobblebufferparagraph
+ \else
+ \doifinsetelse{\the\currentbufferparagraph}{#2}
+ {\@EA\dostartbufferparagraph}
+ {\@EA\fakebufferparagraph}%
+ \fi
+ {#1}}
+
+\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
+ {}
+
+\def\fakebufferparagraph#1%
+ {\bgroup
+ \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
+ \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}
+
+% definitions
+
+\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]
+
+\setupbuffer
+ [\c!paragraph=\v!no,
+ \c!before=,
+ \c!after=]
+
+% only mkiv:
+
+\def\savebuffer{\dosingleempty\dosavebuffer}
+\def\dosavebuffer[#1]{\ctxlua{buffers.save("#1")}}
\protect \endinput
diff --git a/tex/context/base/core-buf.tex b/tex/context/base/core-buf.tex
deleted file mode 100644
index efc0b7973..000000000
--- a/tex/context/base/core-buf.tex
+++ /dev/null
@@ -1,250 +0,0 @@
-%D \module
-%D [ file=core-buf, % blocks are moved to core-blk
-%D version=2000.01.05,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Buffers,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Buffers}
-
-\unprotect
-
-\let\mkresetbuffer \donothing
-\let\mksetbuffer \gobbleoneargument
-\let\mkstartbuffer \gobblefivearguments
-\let\mkdobuffer \gobbleoneargument
-\let\mkstartmemorybuffer\startbuffer
-\let\mkstartfilebuffer \startbuffer
-\let\mkgetbuffer \donothing
-\let\mktypebuffer \donothing
-
-\chardef\buffernestmode\plusone % 0: not nested, 1: startbuffer nested, 2: all buffers nested
-
-\newif\ifsegmentatebuffer
-\newif\ifemptybufferline
-
-\def\currentbuffer{\jobname}
-
-\def\setcurrentbuffer#1%
- {\doifelsenothing{#1}{\edef\currentbuffer{\jobname}}{\edef\currentbuffer{#1}}}
-
-\def\resetbuffer
- {\dosingleempty\doresetbuffer}
-
-\def\doresetbuffer[#1]%
- {\begingroup
- \setcurrentbuffer{#1}%
- \mkresetbuffer
- \endgroup}
-
-\def\dostartbuffer
- {\bgroup
- \obeylines % nodig, anders gaat 't fout als direct \starttable (bv)
- \doquadrupleempty\dodostartbuffer}
-
-\def\dodostartbuffer[#1][#2][#3][#4]% upward compatible
- {\iffourthargument
- \def\next{\dododostartbuffer{#1}{#2}{#3}{#4}}%
- \else
- \def\next{\dododostartbuffer {}{#1}{#2}{#3}}%
- \fi
- \next}
-
-\def\dododostartbuffer#1#2#3#4%
- {%\showmessage\m!systems{15}{#2}%
- \doifelsevalue{\??bu#1\c!paragraph}\v!yes
- {\segmentatebuffertrue} % todo in mkiv
- {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}\segmentatebuffertrue\segmentatebufferfalse}%
- \doifvalue{\??bu#1\c!local}\v!yes
- {\chardef\buffernestmode\plustwo}% permit nesting
- \setcurrentbuffer{#2}%
- \mkstartbuffer{#1}{#2}{#3}{#4}{\egroup}}
-
-\letvalue{\e!start\v!buffer}\dostartbuffer
-
-\let\endbuffer\undefined % to please the dep parser
-
-\def\setbuffer
- {\dosingleempty\dosetbuffer}
-
-\def\dosetbuffer[#1]#2\endbuffer % seldom used so we just pass #2
- {\begingroup
- \setcurrentbuffer{#1}%
- \mksetbuffer{#2}%
- \endgroup}
-
-\def\setupbuffer
- {\dodoubleempty\dosetupbuffer}
-
-\def\dosetupbuffer[#1][#2]%
- {\ifsecondargument
- \getparameters[\??bu#1][#2]%
- \else
- \getparameters[\??bu][#1]%
- \fi}
-
-\def\dodefinebuffer[#1][#2]%
- {\iffirstargument % else problems
- \doglobal\increment\nofdefinedbuffers
- \letvalue{\??bu#1\c!number }\nofdefinedbuffers
- \letvalue{\??bu#1\c!paragraph}\v!no
- \setevalue{\e!start#1}{\noexpand\dostartbuffer[#1][def-\nofdefinedbuffers][\e!start#1][\e!stop#1]}%
- \setevalue{\e!get #1}{\noexpand\dogetbuffer [#1][def-\nofdefinedbuffers]}%
- \setevalue{\e!type #1}{\noexpand\dotypebuffer [#1][def-\nofdefinedbuffers]}%
- \getparameters[\??bu#1][#2]%
- \fi}
-
-\def\definebuffer
- {\dodoubleempty\dodefinebuffer}
-
-\def\getbuffer
- {\dodoubleempty\dogetbuffer}
-
-\def\dogetbuffer[#1][#2]%
- {\ifsecondargument
- \dodogetbuffer[#1][#2]%
- \else
- \dodogetbuffer[][#1]%
- \fi}
-
-\def\dodogetbuffer[#1][#2]%
- {\getvalue{\??bu#1\c!before}%
- \dobuffer{16}{#2}\mkgetbuffer
- \getvalue{\??bu#1\c!after}}
-
-\def\typebuffer
- {\dodoubleempty\dotypebuffer}
-
-\def\dotypebuffer[#1][#2]%
- {\iffirstargument
- \dobuffer{17}{#1}\mktypebuffer
- \else
- \dobuffer{17}{#2}\mktypebuffer
- \fi}
-
-\def\dobuffer#1#2#3%
- {\doifelsenothing{#2}
- {\dodobuffer#3\jobname}
- {\processcommalist[#2]{\dodobuffer#3}}}
-
-\def\dodobuffer#1#2% command name
- {\pushmacro\currentbuffer
- \edef\currentbuffer{\ifcsname\??bu#2\c!number\endcsname def-\csname\??bu#2\c!number\endcsname\else#2\fi}%
- \mkdobuffer#1%
- \popmacro\currentbuffer}
-
-\def\processTEXbuffer{\getbuffer} % handy
-
-% seldom used, only in a few projects that demanded more speed
-
-\def\usememorybuffers{\let\startbuffer\mkstartmemorybuffer}
-\def\usefilebuffers {\let\startbuffer\mkstartfilebuffer}
-
-% this features is soldom used (complex examns where we need to fetch
-% special parts of a text
-%
-% this is not yet supported in mkiv (relatively easy to do but there
-% we don't have the par tags but need to grab 'm
-
-\def\skippedbufferparagraphs{0}
-
-\let\startbufferparagraph\relax
-\let\stopbufferparagraph \par % \relax
-
-\newcount\currentbufferparagraph
-
-\def\getbufferparagraphs
- {\dodoubleempty\dogetbufferparagraphs}
-
-\def\dosetbufferoffset#1%
- {\doifnumberelse{\getvalue{\??bu#1\c!paragraph}}
- {\currentbufferparagraph-\getvalue{\??bu#1\c!paragraph}}
- {\currentbufferparagraph \zerocount}%
- \relax}
-
-\def\dogetbufferparagraphs[#1][#2]%
- {\iffirstargument
- \ifsecondargument
- \dosetbufferoffset{#1}%
- \doifelse{#2}\v!all
- {\def\startbufferparagraph{\normalbufferparagraph{#1}}}
- {\def\startbufferparagraph{\filterbufferparagraph{#1}{#2}}}%
- \def\stopbufferparagraph{\dostopbufferparagraph{#1}}%
- \def\next{\getparagraphedbuffer[#1]}%
- \else
- \dosetbufferoffset\empty
- \def\startbufferparagraph{\filterbufferparagraph{}{#1}}%
- \def\stopbufferparagraph{\dostopbufferparagraph{}}%
- \def\next{\getparagraphedbuffer[]}%
- \fi
- \else
- \dosetbufferoffset\empty
- \def\startbufferparagraph{\normalbufferparagraph{}}%
- \def\stopbufferparagraph{\dostopbufferparagraph{}}%
- \def\next{\getparagraphedbuffer[]}%
- \fi
- \next}
-
-\def\getparagraphedbuffer[#1]%
- {\dobuffer{16}{#1}\mkgetbuffer}
-
-\def\dostopbufferparagraph#1%
- {\getvalue{\??bu#1\c!after}\par}
-
-\def\dostartbufferparagraph#1%
- {\par\getvalue{\??bu#1\c!before}}
-
-\def\normalbufferparagraph
- {\advance\currentbufferparagraph \plusone
- \ifnum\currentbufferparagraph>\zerocount
- \expandafter\dostartbufferparagraph
- \else
- \expandafter\gobbleoneargument
- \fi}
-
-\def\filterbufferparagraph#1#2%
- {\advance\currentbufferparagraph \plusone
- \ifcase\currentbufferparagraph
- \@EA\gobblebufferparagraph
- \else
- \doifinsetelse{\the\currentbufferparagraph}{#2}
- {\@EA\dostartbufferparagraph}
- {\@EA\fakebufferparagraph}%
- \fi
- {#1}}
-
-\long\def\gobblebufferparagraph#1#2\stopbufferparagraph
- {}
-
-\def\fakebufferparagraph#1%
- {\bgroup
- \def\stopbufferparagraph{\dostopbufferparagraph{#1}\egroup\egroup}%
- \setbox\scratchbox\vbox\bgroup\dostartbufferparagraph{#1}}
-
-% only mkiv
-
-\beginLUATEX
- \def\savebuffer{\dosingleempty\dosavebuffer}
- \def\dosavebuffer[#1]{\ctxlua{buffers.save("#1")}}
-\endLUATEX
-
-% plugins
-
-\loadmarkfile{core-buf}
-
-% definitions
-
-\definebuffer[\v!hiding] \setupbuffer[\v!hiding][\c!local=\v!yes]
-
-\setupbuffer
- [\c!paragraph=\v!no,
- \c!before=,
- \c!after=]
-
-\protect \endinput
diff --git a/tex/context/base/core-con.lua b/tex/context/base/core-con.lua
index 20bfef32a..1b1657957 100644
--- a/tex/context/base/core-con.lua
+++ b/tex/context/base/core-con.lua
@@ -14,11 +14,25 @@ slower but look nicer this way.</p>
<p>Some code may move to a module in the language namespace.</p>
--ldx]]--
-local texsprint, floor, mod, format, date, time = tex.sprint, math.floor, math.mod, string.format, os.date, os.time
+local utf = unicode.utf8
+
+local floor, mod, date, time, concat, format = math.floor, math.mod, os.date, os.time, table.concat, string.format
+local texsprint, utfchar = tex.sprint, utf.char
+
+local ctxcatcodes = tex.ctxcatcodes
converters = converters or { }
languages = languages or { }
+--~ ['arabic-digits'] = {
+--~ 0x0660, 0x0661, 0x0662, 0x0663, 0x0664,
+--~ 0x0665, 0x0666, 0x0667, 0x0668, 0x0669
+--~ },
+--~ ['persian-digits'] = {
+--~ 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4,
+--~ 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9
+--~ },
+
languages.counters = {
['**'] = {
0x0061, 0x0062, 0x0063, 0x0064, 0x0065,
@@ -43,12 +57,20 @@ languages.counters = {
0x03A6, 0x03A7, 0x03A8, 0x03A9
},
['arabic'] = {
- 0x0660, 0x0661, 0x0662, 0x0663, 0x0664,
- 0x0665, 0x0666, 0x0667, 0x0668, 0x0669
+ 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
+ 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
+ 0x0643, 0x0644, 0x0645, 0x0646, 0x0633,
+ 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
+ 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
+ 0x0636, 0x0638, 0x063A,
},
['persian'] = {
- 0x06F0, 0x06F1, 0x06F2, 0x06F3, 0x06F4,
- 0x06F5, 0x06F6, 0x06F7, 0x06F8, 0x06F9
+ 0x0627, 0x0628, 0x062C, 0x062F, 0x0647,
+ 0x0648, 0x0632, 0x062D, 0x0637, 0x0649,
+ 0x06A9, 0x0644, 0x0645, 0x0646, 0x0633,
+ 0x0639, 0x0641, 0x0635, 0x0642, 0x0631,
+ 0x0634, 0x062A, 0x062B, 0x062E, 0x0630,
+ 0x0636, 0x0638, 0x063A,
},
['thai'] = {
0xE050, 0xE051, 0xE052, 0xE053, 0xE054,
@@ -69,16 +91,34 @@ languages.counters = {
['tibetan'] = {
0x0F20, 0x0F21, 0x0F22, 0x0F23, 0x0F24,
0x0F25, 0x0F26, 0x0F27, 0x0F28, 0x0F29
- }
+ },
+ ['korean'] = {
+ 0x3131, 0x3134, 0x3137, 0x3139, 0x3141,
+ 0x3142, 0x3145, 0x3147, 0x3148, 0x314A,
+ 0x314B, 0x314C, 0x314D, 0x314E
+ },
+ ['korean-parent'] = { -- parenthesed
+ 0x3200, 0x3201, 0x3202, 0x3203, 0x3204,
+ 0x3205, 0x3206, 0x3207, 0x3208, 0x3209,
+ 0x320A, 0x320B, 0x320C, 0x320D
+ },
+ ['korean-circle'] = { -- circled
+ 0x3260, 0x3261, 0x3262, 0x3263, 0x3264,
+ 0x3265, 0x3266, 0x3267, 0x3268, 0x3269,
+ 0x326A, 0x326B, 0x326C, 0x326D
+ },
}
local counters = languages.counters
-counters['gr'] = counters['greek']
-counters['g'] = counters['greek']
-counters['sl'] = counters['slovenian']
+counters['ar'] = counters['arabic']
+counters['gr'] = counters['greek']
+counters['g'] = counters['greek']
+counters['sl'] = counters['slovenian']
+counters['kr'] = counters['korean']
+counters['kr-p'] = counters['korean-parent']
+counters['kr-c'] = counters['korean-circle']
-local utfchar = utf.char
local fallback = utf.byte('0')
function converters.chr(n,m)
@@ -92,7 +132,7 @@ function converters.maxchrs(n,m,cmd)
converters.maxchrs(floor((n-1)/m),m,cmd)
n = (n-1)%m + 1
end
- texsprint(tex.ctxcatcodes, format("%s{%s}",cmd,n))
+ texsprint(ctxcatcodes, format("%s{%s}",cmd,n))
end
function converters.chrs(n,m)
if n > 26 then
@@ -219,3 +259,222 @@ end
function converters.abjadnumerals (n) return texsprint(converters.toabjad(n,false)) end
function converters.abjadnodotnumerals(n) return texsprint(converters.toabjad(n,true)) end
+
+local vector = {
+ normal = {
+ [0] = "○",
+ [1] = "一",
+ [2] = "二",
+ [3] = "三",
+ [4] = "四",
+ [5] = "五",
+ [6] = "六",
+ [7] = "七",
+ [8] = "八",
+ [9] = "九",
+ [10] = "十",
+ [100] = "百",
+ [1000] = "千",
+ [10000] = "万",
+ [100000000] = "亿",
+ },
+ cap = {
+ [0] = "零",
+ [1] = "壹",
+ [2] = "贰",
+ [3] = "叁",
+ [4] = "肆",
+ [5] = "伍",
+ [6] = "陆",
+ [7] = "柒",
+ [8] = "捌",
+ [9] = "玖",
+ [10] = "拾",
+ [100] = "佰",
+ [1000] = "仟",
+ [10000] = "萬",
+ [100000000] = "亿",
+ },
+ all = {
+ [0] = "○",
+ [1] = "一",
+ [2] = "二",
+ [3] = "三",
+ [4] = "四",
+ [5] = "五",
+ [6] = "六",
+ [7] = "七",
+ [8] = "八",
+ [9] = "九",
+ [10] = "十",
+ [20] = "廿",
+ [30] = "卅",
+ [100] = "百",
+ [1000] = "千",
+ [10000] = "万",
+ [100000000] = "亿",
+ }
+}
+
+function tochinese(n,name) -- normal, caps, all
+ local result = { }
+ local vector = vector[name] or vector.normal
+ while true do
+ if n == 0 then
+ break
+ elseif n >= 100000000 then
+ local m = floor(n/100000000)
+ if m > 1 then result[#result+1] = tochinese(m) end
+ result[#result+1] = vector[100000000]
+ n = n % 100000000
+ elseif n >= 10000000 then
+ result[#result+1] = tochinese(floor(n/10000))
+ result[#result+1] = vector[10000]
+ n = n % 10000
+ elseif n >= 1000000 then
+ result[#result+1] = tochinese(floor(n/10000))
+ result[#result+1] = vector[10000]
+ n = n % 10000
+ elseif n >= 100000 then
+ result[#result+1] = tochinese(floor(n/10000))
+ result[#result+1] = vector[10000]
+ n = n % 10000
+ elseif n >= 10000 then
+ local m = floor(n/10000)
+ if m > 1 then result[#result+1] = vector[m] end
+ result[#result+1] = vector[10000]
+ n = n % 10000
+ elseif n >= 1000 then
+ local m = floor(n/1000)
+ if m > 1 then result[#result+1] = vector[m] end
+ result[#result+1] = vector[1000]
+ n = n % 1000
+ elseif n >= 100 then
+ local m = floor(n/100)
+ if m > 1 then result[#result+1] = vector[m] end
+ result[#result+1] = vector[100]
+ n = n % 100
+ elseif n >= 10 then
+ local m = floor(n/10)
+ if vector[m*10] then
+ result[#result+1] = vector[m*10]
+ else
+ result[#result+1] = vector[m]
+ result[#result+1] = vector[10]
+ end
+ n = n % 10
+ else
+ result[#result+1] = vector[n]
+ break
+ end
+ end
+ return concat(result)
+end
+
+--~ for k, v in ipairs { 1,10,15,25,35,45,11,100,111,1111,10000,11111,100000,111111,1111111,11111111,111111111,100000000,1111111111,11111111111,111111111111,1111111111111 } do
+--~ print(v,tochinese(v),tochinese(v,"all"),tochinese(v,"cap"))
+--~ end
+
+function converters.chinesenumerals (n) return texsprint(tochinese(n,"normal")) end
+function converters.chinesecapnumerals(n) return texsprint(tochinese(n,"cap" )) end
+function converters.chineseallnumerals(n) return texsprint(tochinese(n,"all" )) end
+
+--~ Well, since the one asking for this didn't test it the following code is not
+--~ enabled.
+--~
+--~ -- This Lua version is based on a Javascript by Behdad Esfahbod which in turn
+--~ -- is based on GPL'd code by Roozbeh Pournader of the The FarsiWeb Project
+--~ -- Group: http://www.farsiweb.info/jalali/jalali.js.
+--~ --
+--~ -- We start tables at one, I kept it zero based in order to stay close to
+--~ -- the original.
+--~ --
+--~ -- Conversion by Hans Hagen
+--~
+--~ local g_days_in_month = { [0]=31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+--~ local j_days_in_month = { [0]=31, 31, 31, 31, 31, 31, 30, 30, 30, 30, 30, 29 }
+--~
+--~ local function div(a,b)
+--~ return math.floor(a/b)
+--~ end
+--~
+--~ local function remainder(a,b)
+--~ return a - div(a,b)*b
+--~ end
+--~
+--~ function gregorian_to_jalali(gy,gm,gd)
+--~ local jy, jm, jd, g_day_no, j_day_no, j_np, i
+--~ gy, gm, gd = gy - 1600, gm - 1, gd - 1
+--~ g_day_no = 365*gy + div((gy+3),4) - div((gy+99),100) + div((gy+399),400)
+--~ i = 0
+--~ while i < gm do
+--~ g_day_no = g_day_no + g_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ if (gm>1 and ((gy%4==0 and gy%100~=0) or (gy%400==0))) then
+--~ g_day_no = g_day_no + 1
+--~ end
+--~ g_day_no = g_day_no + gd
+--~ j_day_no = g_day_no - 79
+--~ j_np = div(j_day_no,12053)
+--~ j_day_no = remainder(j_day_no,12053)
+--~ jy = 979 + 33*j_np + 4*div(j_day_no,1461)
+--~ j_day_no = remainder(j_day_no,1461)
+--~ if j_day_no >= 366 then
+--~ jy = jy + div((j_day_no-1),365)
+--~ j_day_no = remainder((j_day_no-1),365)
+--~ end
+--~ i = 0
+--~ while i < 11 and j_day_no >= j_days_in_month[i] do
+--~ j_day_no = j_day_no - j_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ jm = i + 1
+--~ jd = j_day_no + 1
+--~ return jy, jm, jd
+--~ end
+--~
+--~ function jalali_to_gregorian(jy,jm,jd)
+--~ local gy, gm, gd, g_day_no, j_day_no, leap, i
+--~ jy, jm, jd = jy - 979, jm - 1, jd - 1
+--~ j_day_no = 365*jy + div(jy,33)*8 + div((remainder(jy,33)+3),4)
+--~ i = 0
+--~ while i < jm do
+--~ j_day_no = j_day_no + j_days_in_month[i]
+--~ i = i + 1
+--~ end
+--~ j_day_no = j_day_no + jd
+--~ g_day_no = j_day_no + 79
+--~ gy = 1600 + 400*div(g_day_no,146097)
+--~ g_day_no = remainder (g_day_no, 146097)
+--~ leap = 1
+--~ if g_day_no >= 36525 then
+--~ g_day_no = g_day_no - 1
+--~ gy = gy + 100*div(g_day_no,36524)
+--~ g_day_no = remainder (g_day_no, 36524)
+--~ if g_day_no >= 365 then
+--~ g_day_no = g_day_no + 1
+--~ else
+--~ leap = 0
+--~ end
+--~ end
+--~ gy = gy + 4*div(g_day_no,1461)
+--~ g_day_no = remainder (g_day_no, 1461)
+--~ if g_day_no >= 366 then
+--~ leap = 0
+--~ g_day_no = g_day_no - 1
+--~ gy = gy + div(g_day_no, 365)
+--~ g_day_no = remainder(g_day_no, 365)
+--~ end
+--~ i = 0
+--~ while g_day_no >= g_days_in_month[i] + ((i == 1 and leap) or 0) do
+--~ g_day_no = g_day_no - g_days_in_month[i] + ((i == 1 and leap) or 0)
+--~ i = i + 1
+--~ end
+--~ gm = i + 1
+--~ gd = g_day_no + 1
+--~ return gy, gm, gd
+--~ end
+--~
+--~ print(gregorian_to_jalali(2009,02,24))
+--~ print(jalali_to_gregorian(1387,12,06))
diff --git a/tex/context/base/core-con.mkii b/tex/context/base/core-con.mkii
index d9347b475..c39bdd9d4 100644
--- a/tex/context/base/core-con.mkii
+++ b/tex/context/base/core-con.mkii
@@ -2,7 +2,7 @@
%D [ file=core-con,
%D version=1997.26.08,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Conversion Macros,
+%D subtitle=Conversion,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,8 +11,67 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Conversion}
+
\unprotect
+\ifx\currentlanguage\undefined \let\currentlanguage\empty \fi
+\ifx\labeltext \undefined \let\labeltext\firstofoneargument \fi
+
+%D This module deals with all kind of conversions from numbers
+%D and dates. I considered splitting this module in a support
+%D one and a core one, but to keep things simple as well as
+%D preserve the overview, I decided against splitting.
+
+\let\spr\firstofoneargument % separator
+\let\stp\firstofoneargument % stopper
+
+% cleaner, some day:
+%
+% \def\isolateseparators % etex only, even works with list separator overloading
+% {\unexpanded\def\spr##1{{##1}}%
+% \unexpanded\def\stp##1{{##1}}}
+
+% needed for arab :
+
+\def\isolateseparators % even works with list separator overloading
+ {\def\spr##1{{##1}}%
+ \def\stp##1{{##1}}}
+
+%D \macros
+%D {numbers}
+%D
+%D First we deal with the dummy conversion of numbers using the
+%D \TEX\ primitive \type{\number}. The uppercase alternative is
+%D only there for compatibility with the other conversion
+%D macros. We could do without \type{#1} but this way we get
+%D rid of unwanted braces. For the savety we also define a
+%D non||sence uppercase alternative.
+%D
+%D \showsetup{numbers}
+%D
+%D \starttyping
+%D \def\numbers#1{\number#1}
+%D \def\Numbers#1{\number#1}
+%D \stoptyping
+%D
+%D Due to read ahead, as in \type{[\pagenumber\space]} the space will
+%D disappear, unless we use:
+
+\def\numbers#1{\purenumber{#1}}
+\def\Numbers#1{\purenumber{#1}}
+
+%D \macros
+%D {romannumerals,Romannumerals}
+%D
+%D \TEX\ the program uses a rather tricky conversion from
+%D numbers to their roman counterparts. This conversion could
+%D of course be programmed in \TEX\ itself, but I guess Knuth
+%D found the programming trick worth presenting.
+%D
+%D \showsetup{romannumerals}
+%D \showsetup{Romannumerals}
+
%D When upcasing the result, we just follow the text book rules
%D of expansion. Later on we'll see some more uppercase tricks.
@@ -50,6 +109,24 @@
\uppercase\expandafter{\romannumeral#1#2}%
\fi\fi\fi\fi}
+%D \macros
+%D {character,Character}
+%D
+%D Converting a number into a character can of course only
+%D be done with numbers less or equal to~26. At the cost of
+%D much more macros a faster conversion is possible, using:
+%D
+%D \starttyping
+%D \setvalue{char1}{a} \def\character#1{\getvalue{char#1}}
+%D \stoptyping
+%D
+%D But we prefer a simpel \type{\case}.
+%D
+%D \showsetup{character}
+%D \showsetup{Character}
+
+\def\unknowncharacter{-} % else in lists \relax
+
%D Big case statements but pretty fast:
\def\character#1%
@@ -68,6 +145,38 @@
\unknowncharacter
\fi}
+%D \macros
+%D {characters,Characters}
+%D
+%D Converting large numbers is supported by the next two
+%D macros. This time we just count on: $\cdots$~x, y, z, aa,
+%D ab, ac~$\cdots$.
+%D
+%D \showsetup{characters}
+%D \showsetup{Characters}
+
+%D The fully expandable alternative:
+
+\def\dodoconvertcharacters#1#2#3%
+ {\ifcase#3\else
+ \ifnum#3>#1
+ \expandafter\doconvertcharacters\expandafter#2\expandafter{\the\numexpr(#3+12)/#1-1\relax}%
+ \expandafter#2\expandafter{\the\numexpr#3-((#3+12)/#1-1)*#1\relax}%
+ \else
+ \expandafter#2\expandafter{\number#3}%
+ \fi
+ \fi}
+
+\def\doconvertcharacters{\dodoconvertcharacters{26}}
+
+\def\characters{\doconvertcharacters\character}
+\def\Characters{\doconvertcharacters\Character}
+
+%D \macros
+%D {greeknumerals,Greeknumerals}
+%D
+%D Why should we only honour the romans, and not the greek?
+
\def\greeknumerals#1%
{% no longer needed: \mathematics
{\ifcase#1\unknowncharacter\or
@@ -94,22 +203,115 @@
\unknowncharacter
\fi}}
-%D The fully expandable alternative:
+%D \macros
+%D {oldstylenumerals,oldstyleromannumerals}
+%D
+%D These conversions are dedicated to Frans Goddijn.
-\def\dodoconvertcharacters#1#2#3%
- {\ifcase#3\else
- \ifnum#3>#1
- \expandafter\doconvertcharacters\expandafter#2\expandafter{\the\numexpr(#3+12)/#1-1\relax}%
- \expandafter#2\expandafter{\the\numexpr#3-((#3+12)/#1-1)*#1\relax}%
- \else
- \expandafter#2\expandafter{\number#3}%
- \fi
+\unexpanded\def\oldstylenumerals#1%
+ {{\os\number#1}}
+
+\unexpanded\def\oldstyleromannumerals#1%
+ {{\leftrulefalse\rightrulefalse\ss\txx\boxrulewidth.15ex
+ \ruledhbox spread .15em{\hss\uppercased{\romannumerals{#1}}\hss}}}
+
+%D \macros
+%D {protectconversion}
+%D
+%D The previous two commands are not robust enough to be
+%D passed to \type{\write} en \type{\message}. That's why we
+%D introduce:
+
+\def\protectconversion
+ {\def\doconvertcharacters##1{##1}} % was \relax
+ %{\def\doconvertcharacters##1{\ifcase0##1 0\else##1\fi}} more save
+
+%D \macros
+%D {normaltime,normalyear,normalmonth,normalday}
+%D
+%D The last part of this module is dedicated to converting
+%D dates. Because we want to use as meaningful commands as
+%D possible, and because \TEX\ already uses up some of those,
+%D we save the original meanings.
+
+\savenormalmeaning\time
+\savenormalmeaning\year
+\savenormalmeaning\month
+\savenormalmeaning\day
+
+%D \macros
+%D {month,MONTH}
+%D
+%D Converting the month number into a month name is done
+%D using a case statement, abstact values and the label
+%D mechanism. This way users can easily redefine a label from
+%D for instance german into austrian.
+%D
+%D \starttyping
+%D \setuplabeltext [de] [january=J\"anner]
+%D \stoptyping
+%D
+%D Anyhow, the conversion looks like:
+
+\def\domonthtag#1%
+ {\ifcase#1%
+ \or \v!january \or \v!february \or \v!march \or \v!april
+ \or \v!may \or \v!june \or \v!july \or \v!august
+ \or \v!september \or \v!october \or \v!november \or \v!december
+ \else
+ \v!unknown
\fi}
-\def\doconvertcharacters{\dodoconvertcharacters{26}}
+\def\doconvertmonthlong #1{\labeltext{\domonthtag{#1}}}
+\def\doconvertmonthshort#1{\labeltext{\domonthtag{#1}:\s!mnem}}
-\def\characters{\doconvertcharacters\character}
-\def\Characters{\doconvertcharacters\Character}
+\let\doconvertmonth\doconvertmonthlong
+
+%D We redefine the \TEX\ primitive \type{\month} as:
+%D
+%D \showsetup{month}
+%D \showsetup{MONTH}
+
+\def\monthlong {\doconvertmonthlong}
+\def\monthshort{\doconvertmonthshort}
+\def\month {\doconvertmonth}
+
+\def\MONTH #1{{\let\labeltext\LABELTEXT\month {#1}}}
+\def\MONTHLONG #1{{\let\labeltext\LABELTEXT\monthlong {#1}}}
+\def\MONTHSHORT#1{{\let\labeltext\LABELTEXT\monthshort{#1}}}
+
+%D We never explicitly needed this, but Tobias Burnus pointed
+%D out that it would be handy to convert to the day of the
+%D week. In doing so, we have to calculate the total number of
+%D days, taking leapyears into account. For those who are
+%D curious:
+%D
+%D \startitemize[packed]
+%D \item years that can be divided by 4 are leapyears
+%D \item exept years that can be divided by 100
+%D \item unless years can be divided by 400
+%D \stopitemize
+%D
+%D This makes the year 1900 into a normal year and 1996 and
+%D 2000 into leap years, right? Well, converting to string
+%D looks familiar:
+
+\def\doconvertday#1%
+ {\labeltext
+ {\ifcase#1
+ \or \v!sunday \or \v!monday \or \v!tuesday \or \v!wednesday
+ \or \v!thursday \or \v!friday \or \v!saturday \fi}}
+
+%D \macros
+%D {getdayoftheweek, dayoftheweek}
+%D
+%D The conversion algoritm is an old one and a translation from
+%D a procedure written in MODULA~2 back in the 80's. I finaly
+%D found the 4--100-400 rules in some enclopedia. Look at this
+%D messy low level routine that takes the day, month and year
+%D as arguments:
+
+\newcount\normalweekday
\def\getdayoftheweek#1#2#3%
{\bgroup
@@ -140,6 +342,77 @@
\def\dayoftheweek#1#2#3%
{\getdayoftheweek{#1}{#2}{#3}\doconvertday{\normalweekday}}
+%D Using this macro in
+%D
+%D \startbuffer
+%D monday: \dayoftheweek {4} {5} {1992}
+%D friday: \dayoftheweek {16} {6} {1995}
+%D monday: \dayoftheweek {25} {8} {1997}
+%D saturday: \dayoftheweek {30} {8} {1997}
+%D tuesday: \dayoftheweek {2} {1} {1996}
+%D tuesday: \dayoftheweek {7} {1} {1997}
+%D tuesday: \dayoftheweek {13} {1} {1998}
+%D friday: \dayoftheweek {1} {1} {2000}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The macro \type {\getdayoftheweek} can be used to calculate
+%D the number \type {\normalweekday}.
+
+%D \macros
+%D {weekday,WEEKDAY}
+%D
+%D The first one is sort of redundant. It takes the day
+%D number argument.
+%D
+%D \showsetup{weekday}
+%D \showsetup{WEEKDAY}
+
+\def\weekday
+ {\doconvertday}
+
+\def\WEEKDAY#1%
+ {{\let\labeltext\LABELTEXT\doconvertday{#1}}}
+
+%D \macros
+%D {weekoftheday}
+%D
+%D {\em not yet implemented:}
+%D
+%D \starttyping
+%D \def\weekoftheday#1#2#3%
+%D {}
+%D \stoptyping
+
+%D \macros
+%D {doifleapyearelse,
+%D getdayspermonth}
+%D
+%D Sometimes we need to know if we're dealing with a
+%D leapyear, so here is a testmacro:
+%D
+%D \starttyping
+%D \doifleapyearelse{year}{yes}{no}
+%D \stoptyping
+%D
+%D An example of its use can be seen in the macro
+%D
+%D \starttyping
+%D \getdayspermonth{year}{month}
+%D \stoptyping
+%D
+%D The number of days is available in the macro \type
+%D {\numberofdays}.
+
\def\doifleapyearelse#1% #2#3%
{\bgroup
\!!doneafalse
@@ -185,12 +458,450 @@
{\ifcase#2 \or31\or\numberofdays\or31\or30\or
31\or30\or31\or31\or30\or31\or30\or31\fi}}
+%D \macros
+%D {currentdate, date}
+%D
+%D We use these conversion macros in the date formatting
+%D macro:
+%D
+%D \showsetup{currentdate}
+%D
+%D This macro takes care of proper spacing and delivers for
+%D instance:
+%D
+%D \startbuffer
+%D \currentdate[weekday,day,month,year] % still dutch example
+%D \currentdate[WEEKDAY,day,MONTH,year] % still dutch example
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D depending of course on the keywords. Here we gave:
+%D
+%D \typebuffer
+%D
+%D If needed one can also add non||keywords, like in
+%D
+%D \startbuffer
+%D \currentdate[dd,--,mm,--,yy]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or typeset: \getbuffer.
+%D
+%D When no argument is passed, the current date is given as
+%D specified per language (using \type{\installlanguage}).
+%D
+%D \showsetup{currentdate}
+%D
+%D \startbuffer
+%D \date
+%D \date[d=12,m=12,y=1998][weekday]
+%D \date[d=12,m=12,y=1998]
+%D \stopbuffer
+%D
+%D We can also typeset arbitrary dates, using the previous
+%D command.
+%D
+%D \typebuffer
+%D
+%D The date is specified by one character keys. When no date
+%D is given, we get the current date.
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\def\kenmerkdatumpatroon{j,mm,dd} % jj,mm,dd changed at januari 1-1-2000
+
+\newsignal\datesignal
+
+\def\dobetweendates
+ {\ifdim\lastskip=\datesignal\relax\else
+ \unskip\space
+ \hskip\datesignal\relax
+ \fi}
+
+\newtoks \everycurrentdate
+
+\def\complexcurrentdate[#1]%
+ {\bgroup
+ \the\everycurrentdate
+ \def\betweendates{\let\betweendates\dobetweendates}%
+ % was \processcommacommandp[#1]\docomplexcurrentdate
+ \safeedef\ascii{\empty#1}% keep encoded chars
+ \@EA\processcommalist\@EA[\ascii]\docomplexcurrentdate
+ \ifdim\lastskip=\datesignal\relax
+ \unskip
+ \fi
+ \egroup}
+
+\def\docomplexcurrentdate#1%
+ {\lowercase{\edef\!!stringa{#1}}% permits usage in \smallcapped
+ \expanded{\processaction[\!!stringa]}% [#1]
+ [ \v!day=>\betweendates\the\normalday,
+ %\v!day+=>\betweendates\ordinaldaynumber\normalday,
+ \v!day+=>\betweendates\convertnumber{\v!day+}\normalday,
+ \v!month=>\betweendates\month\normalmonth,
+ \v!year=>\betweendates\the\normalyear,
+ \v!space=>\unskip\ \hskip\datesignal,% optimization -)
+ \ =>\unskip\ \hskip\datesignal,% optimization -)
+ d=>\convertnumber\v!day\normalday,
+ %d+=>\ordinaldaynumber\normalday,
+ d+=>\convertnumber{\v!day+}\normalday,
+ m=>\convertnumber\v!month\normalmonth,
+ j=>\convertnumber\v!year\normalyear,
+ y=>\convertnumber\v!year\normalyear,
+ w=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ dd=>\ifnum\normalday >9 \else0\fi\the\normalday,
+ %dd+=>\ordinaldaynumber{\ifnum\normalday >9 \else0\fi\the\normalday},
+ dd+=>\convertnumber{\v!day+}{\ifnum\normalday >9 \else0\fi\the\normalday},
+ mm=>\ifnum\normalmonth>9 \else0\fi\the\normalmonth,
+ jj=>\expandafter\gobbletwoarguments\the\normalyear,
+ yy=>\expandafter\gobbletwoarguments\the\normalyear,
+ \v!weekday=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ \v!referral=>\expanded{\complexcurrentdate[\kenmerkdatumpatroon]},
+ \s!unknown=>\unskip
+ % #1 and not the lowercased \commalistelement, vietnamese has text
+ % {} because #1 can have comma, like: {\ ,}
+ {#1}%
+ \hskip\datesignal
+ \def\betweendates{\let\betweendates\dobetweendates}]}
+
+\def\simplecurrentdate
+ {\expanded{\complexcurrentdate[\currentdatespecification]}}
+
+\definecomplexorsimple\currentdate
+
+\def\dodate[#1][#2]%
+ {\bgroup
+ \iffirstargument
+ \getparameters[\??da][d=\normalday,m=\normalmonth,y=\normalyear,#1]%
+ \normalday \@@dad\relax
+ \normalmonth\@@dam\relax
+ \normalyear \@@day\relax
+ \ifsecondargument
+ \currentdate[#2]%
+ \else
+ \currentdate
+ \fi
+ \else
+ \currentdate
+ \fi
+ \egroup}
+
+\def\date
+ {\dodoubleempty\dodate}
+
+%D \macros
+%D {currenttime}
+%D
+%D The currenttime is actually the jobtime. You can specify
+%D a pattern similar to the previous date macro using the
+%D keys \type {h}, \type {m} and a separator.
+
\def\calculatecurrenttime
{\dosetdivision\time{60}\scratchcounter
\edef\currenthour {\ifnum\scratchcounter<10 0\fi \the\scratchcounter}%
\dosetmodulo \time{60}\scratchcounter
\edef\currentminute{\ifnum\scratchcounter<10 0\fi \the\scratchcounter}}
+\let\currenthour \!!plusone
+\let\currentminute\!!plusone
+
+\def\currenttimespecification{h,:,m}
+
+\def\complexcurrenttime[#1]%
+ {\calculatecurrenttime
+ \processallactionsinset[#1]
+ [h=>\currenthour,m=>\currentminute,\s!unknown=>\commalistelement]}
+
+\def\simplecurrenttime
+ {\expanded{\complexcurrenttime[\currenttimespecification]}}
+
+\definecomplexorsimple\currenttime
+
+%D Because we're dealing with dates, we also introduce a few
+%D day loops:
+%D
+%D \starttyping
+%D \processmonth{year}{month}{command}
+%D \processyear{year}{command}{before}{after}
+%D \stoptyping
+%D
+%D The counters \type {\normalyear}, \type {\normalmonth} and
+%D \type{\normalday} can be used for for date manipulations.
+
+\long\def\processmonth#1#2#3% year month command
+ {\bgroup
+ \getdayspermonth{#1}{#2}%
+ \dostepwiserecurse1\numberofdays1%
+ {\normalyear #1\relax
+ \normalmonth#2\relax
+ \normalday \recurselevel\relax
+ #3}%
+ \egroup}
+
+\def\lastmonth{12} % can be set to e.g. 1 when testing
+
+\long\def\processyear#1#2#3#4% year command before after
+ {\bgroup
+ \dorecurse\lastmonth
+ {\normalyear #1\relax
+ \normalmonth\recurselevel\relax
+ #3\processmonth\normalyear\normalmonth{#2}#4}%
+ \egroup}
+
+%D \macros
+%D {defineconversion, convertnumber}
+%D
+%D Conversion involves the macros that we implemented earlier
+%D in this module.
+%D
+%D \showsetup{defineconversion}
+%D \showsetup{convertnumber}
+%D
+%D We can feed this command with conversion macros as well as
+%D a set of conversion symbols. Both need a bit different
+%D treatment.
+%D
+%D \starttyping
+%D \defineconversion [roman] [\romannumerals]
+%D \defineconversion [set 1] [$\star$,$\bullet$,$\ast$]
+%D \stoptyping
+%D
+%D You can define a language dependent conversion with:
+%D
+%D \starttyping
+%D \defineconversion [en] [whatever] [\something]
+%D \stoptyping
+
+% \def\dodefineconversion[#1][#2]%
+% {\ConvertConstantAfter\doifinstringelse{,}{#2}
+% {\scratchcounter=0
+% \def\docommand##1%
+% {\advance\scratchcounter 1
+% \setvalue{\??cv#1\the\scratchcounter}{##1}}%
+% \processcommalist[#2]\docommand
+% \setvalue{\??cv#1}##1{\csname\??cv#1##1\endcsname}}
+% {\setvalue{\??cv#1}{#2}}}
+%
+% \def\defineconversion%
+% {\dodoubleargument\dodefineconversion}
+
+\def\defineconversion
+ {\dotripleempty\dodefineconversion}
+
+\def\dodefineconversion[#1][#2][#3]%
+ {\ifthirdargument
+ \dododefineconversion[#1][#2][#3]%
+ \else
+ \dododefineconversion[][#1][#2]%
+ \fi}
+
+%D \starttyping
+%D \def\dododefineconversion[#1][#2][#3]%
+%D {\ConvertConstantAfter\doifinstringelse{,}{#3}
+%D {\scratchcounter\zerocount
+%D \def\docommand##1%
+%D {\advance\scratchcounter \plusone
+%D \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+%D \processcommalist[#3]\docommand
+%D \setvalue{\??cv#1#2}##1{\executeifdefined{\??cv#1#2##1}\unknown}} % catch out-of-range numbers
+%D {\setvalue{\??cv#1#2}{#3}}}
+%D \stoptyping
+
+%D This approach has the disadvantage that when you run out of
+%D symbols you get unknown results. The following implementation
+%D permits overloading of the converter:
+
+\def\dododefineconversion[#1][#2][#3]%
+ {\ConvertConstantAfter\doifinstringelse{,}{#3}
+ {\scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+ \processcommalist[#3]\docommand
+ \setevalue{\??cv#1#2}##1%
+ {\noexpand\docheckedconversion{#1#2}{\the\scratchcounter}{##1}}}
+ {\setvalue{\??cv#1#2}{#3}}}
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1#3}\unknown}
+
+%D When Gerben reported problems with footnote numbering per page,
+%D Taco came with the following wrap around solution. So, let's
+%D overload the checked conversion macro:
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1\modulatednumber{#2}{#3}}\unknown}
+
+%D Taco's modulo code is implemented in the system module
+%D \type {syst-con}.
+
+%D If a conversion is just a font switch then we need to make sure
+%D that the number is indeed end up as number in the input, so we
+%D need to handle the second argument.
+
+\def\convertnumber#1#2%
+ {\csname\??cv
+ \ifcsname\??cv\currentlanguage#1\endcsname
+ \currentlanguage#1%
+ \else\ifcsname\??cv#1\endcsname
+ #1%
+ \else
+ \s!default
+ \fi\fi
+ \endcsname{\number#2}}
+
+\def\doifconversiondefinedelse#1%
+ {\ifcsname\??cv\currentlanguage#1\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??cv#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifelseconversionnumber#1#2% slow but seldom used
+ {\doifdefinedelse{\??cv#1#2}}
+
+%D Handy.
+
+\setvalue{\??cv:\c!n:\v!one }{1}
+\setvalue{\??cv:\c!n:\v!two }{2}
+\setvalue{\??cv:\c!n:\v!three}{3}
+\setvalue{\??cv:\c!n:\v!four }{4}
+\setvalue{\??cv:\c!n:\v!five }{5}
+
+\def\wordtonumber#1#2{\ifcsname\??cv:\c!n:#1\endcsname\csname\??cv:\c!n:#1\endcsname\else#2\fi}
+
+% \defineconversion[ctx][c,o,n,t,e,x,t]
+%
+% \doloop{\doifelseconversionnumber{ctx}{\recurselevel}{[\recurselevel]}{\exitloop}}
+
+\defineconversion [\s!default] [\numbers]
+
+%D As longs as symbols are linked to levels or numbers, we can
+%D also use the conversion mechanism, but in for instance the
+%D itemization macros, we prefer symbols because they can more
+%D easier be (partially) redefined. Symbols are implemented
+%D in another module.
+
+\defineconversion [] [\numbers] % the default conversion
+
+\defineconversion [a] [\characters]
+\defineconversion [A] [\Characters]
+\defineconversion [AK] [\smallcapped\characters]
+\defineconversion [KA] [\smallcapped\characters]
+
+\defineconversion [n] [\numbers]
+\defineconversion [N] [\Numbers]
+\defineconversion [m] [\mediaeval]
+
+\defineconversion [i] [\romannumerals]
+\defineconversion [I] [\Romannumerals]
+\defineconversion [r] [\romannumerals]
+\defineconversion [R] [\Romannumerals]
+\defineconversion [KR] [\smallcapped\romannumerals]
+\defineconversion [RK] [\smallcapped\romannumerals]
+
+\defineconversion [g] [\greeknumerals]
+\defineconversion [G] [\Greeknumerals]
+
+\defineconversion [o] [\oldstylenumerals]
+\defineconversion [O] [\oldstylenumerals]
+\defineconversion [or] [\oldstyleromannumerals]
+
+\defineconversion [\v!character] [\character]
+\defineconversion [\v!Character] [\Character]
+
+\defineconversion [\v!characters] [\characters]
+\defineconversion [\v!Characters] [\Characters]
+
+\defineconversion [\v!numbers] [\numbers]
+\defineconversion [\v!Numbers] [\Numbers]
+\defineconversion [\v!mediaeval] [\mediaeval]
+
+\defineconversion [\v!romannumerals] [\romannumerals]
+\defineconversion [\v!Romannumerals] [\Romannumerals]
+
+\defineconversion [\v!greek] [\greeknumerals]
+\defineconversion [\v!Greek] [\Greeknumerals]
+
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\arabicnumerals]
+
+\defineconversion [month] [\doconvertmonthlong]
+\defineconversion [month:mnem] [\doconvertmonthshort]
+
+% Some bonus ones:
+
+\defineconversion [\v!empty] [\gobbleoneargument]
+\defineconversion [\v!none] [\numbers]
+
+\ifx\symbol\undefined \def\symbol[#1]{#1} \fi % todo
+
+\defineconversion
+ [set 0]
+ [{\symbol[bullet]},
+ {\symbol[dash]},
+ {\symbol[star]},
+ {\symbol[triangle]},
+ {\symbol[circle]},
+ {\symbol[medcircle]},
+ {\symbol[bigcircle]},
+ {\symbol[square]}]
+
+\defineconversion
+ [set 1]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+\defineconversion
+ [set 2]
+ [\mathematics{*},
+ \mathematics{\dag},
+ \mathematics{\ddag},
+ \mathematics{**},
+ \mathematics{\dag\dag},
+ \mathematics{\ddag\ddag},
+ \mathematics{***},
+ \mathematics{\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag},
+ \mathematics{****},
+ \mathematics{\dag\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag\ddag}]
+
+\defineconversion
+ [set 3]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\P},
+ \mathematics{\P\P},
+ \mathematics{\P\P\P},
+ \mathematics{\S},
+ \mathematics{\S\S},
+ \mathematics{\S\S\S},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
%D \macros
%D {defineconversionvector,conversionnumber} % bad names so no danger for clash
@@ -235,24 +946,24 @@
% actually mkiii code
-\beginXETEX
-
-\defineconversionvector{arabicnumerals} {"0660}
-\defineconversionvector{persiannumerals} {"06F0}
-\defineconversionvector{thainumerals} {"0E50}
-\defineconversionvector{devanagarinumerals}{"0966}
-\defineconversionvector{gurmurkhinumerals} {"0A66}
-\defineconversionvector{gujaratinumerals} {"0AE6}
-\defineconversionvector{tibetannumerals} {"0F20} % also "half numerals?"
-
-\defineconversion[arabicnumerals] [\conversionnumber{arabicnumerals}]
-\defineconversion[persiannumerals] [\conversionnumber{persiannumerals}]
-\defineconversion[thainumerals] [\conversionnumber{thainumerals}]
-\defineconversion[devanagarinumerals][\conversionnumber{devanagarinumerals}]
-\defineconversion[gurmurkhinumerals] [\conversionnumber{gurmurkhinumerals}]
-\defineconversion[gujaratinumerals] [\conversionnumber{gujaratinumerals}]
-\defineconversion[tibetannumerals] [\conversionnumber{tibetannumerals}]
-
-\endXETEX
+\ifnum\texengine=\xetexengine
+
+ \defineconversionvector{arabicnumerals} {"0660}
+ \defineconversionvector{persiannumerals} {"06F0}
+ \defineconversionvector{thainumerals} {"0E50}
+ \defineconversionvector{devanagarinumerals}{"0966}
+ \defineconversionvector{gurmurkhinumerals} {"0A66}
+ \defineconversionvector{gujaratinumerals} {"0AE6}
+ \defineconversionvector{tibetannumerals} {"0F20} % also "half numerals?"
+
+ \defineconversion[arabicnumerals] [\conversionnumber{arabicnumerals}]
+ \defineconversion[persiannumerals] [\conversionnumber{persiannumerals}]
+ \defineconversion[thainumerals] [\conversionnumber{thainumerals}]
+ \defineconversion[devanagarinumerals][\conversionnumber{devanagarinumerals}]
+ \defineconversion[gurmurkhinumerals] [\conversionnumber{gurmurkhinumerals}]
+ \defineconversion[gujaratinumerals] [\conversionnumber{gujaratinumerals}]
+ \defineconversion[tibetannumerals] [\conversionnumber{tibetannumerals}]
+
+\fi
\protect \endinput
diff --git a/tex/context/base/core-con.mkiv b/tex/context/base/core-con.mkiv
index 70ddc6991..5568fc78c 100644
--- a/tex/context/base/core-con.mkiv
+++ b/tex/context/base/core-con.mkiv
@@ -1,8 +1,8 @@
%D \module
%D [ file=core-con,
-%D version=2006.09.16,
+%D version=1997.26.08,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Conversion Macros,
+%D subtitle=Conversion,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,33 +11,331 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+\writestatus{loading}{ConTeXt Core Macros / Conversion}
\registerctxluafile{core-con}{1.001}
-\def\romannumerals #1{\ctxlua{converters.romannumerals(\number#1)}}
-\def\Romannumerals #1{\ctxlua{converters.Romannumerals(\number#1)}}
-\def\abjadnumerals #1{\ctxlua{converters.arabicnumerals(\number#1)}}
-\def\abjadnodotnumerals#1{\ctxlua{converters.arabicnodotnumerals(\number#1)}}
-\def\abjadnaivenumerals#1{\ctxlua{converters.arabicnaivenumerals(\number#1)}}
+\unprotect
-\defineconversion [romannumerals] [\romannumerals]
-\defineconversion [Romannumerals] [\Romannumerals]
-\defineconversion [abjadnumerals] [\abjadnumerals]
-\defineconversion [abjadnodotnumerals] [\adjadnodotnumerals]
-\defineconversion [abjadnaivenumerals] [\adjadnaivenumerals]
+\ifx\currentlanguage\undefined \let\currentlanguage\empty \fi
+\ifx\labeltext \undefined \let\labeltext\firstofoneargument \fi
-\def\character #1{\ctxlua{converters.character (\number#1)}}
-\def\Character #1{\ctxlua{converters.Character (\number#1)}}
-\def\characters#1{\ctxlua{converters.characters(\number#1)}}
-\def\Characters#1{\ctxlua{converters.Characters(\number#1)}}
+%D This module deals with all kind of conversions from numbers
+%D and dates. I considered splitting this module in a support
+%D one and a core one, but to keep things simple as well as
+%D preserve the overview, I decided against splitting.
+
+\let\spr\firstofoneargument % separator
+\let\stp\firstofoneargument % stopper
+
+% cleaner, some day:
+%
+% \def\isolateseparators % etex only, even works with list separator overloading
+% {\unexpanded\def\spr##1{{##1}}%
+% \unexpanded\def\stp##1{{##1}}}
+
+% needed for arab :
+
+\def\isolateseparators % even works with list separator overloading
+ {\def\spr##1{{##1}}%
+ \def\stp##1{{##1}}}
+
+%D \macros
+%D {numbers}
+%D
+%D First we deal with the dummy conversion of numbers using the
+%D \TEX\ primitive \type{\number}. The uppercase alternative is
+%D only there for compatibility with the other conversion
+%D macros. We could do without \type{#1} but this way we get
+%D rid of unwanted braces. For the savety we also define a
+%D non||sence uppercase alternative.
+%D
+%D \showsetup{numbers}
+%D
+%D \starttyping
+%D \def\numbers#1{\number#1}
+%D \def\Numbers#1{\number#1}
+%D \stoptyping
+%D
+%D Due to read ahead, as in \type{[\pagenumber\space]} the space will
+%D disappear, unless we use:
+
+\def\numbers#1{\purenumber{#1}}
+\def\Numbers#1{\purenumber{#1}}
+
+%D \macros
+%D {romannumerals,Romannumerals}
+%D
+%D \TEX\ the program uses a rather tricky conversion from
+%D numbers to their roman counterparts. This conversion could
+%D of course be programmed in \TEX\ itself, but I guess Knuth
+%D found the programming trick worth presenting.
+%D
+%D \showsetup{romannumerals}
+%D \showsetup{Romannumerals}
+
+\def\romannumerals#1{\ctxlua{converters.romannumerals(\number#1)}}
+\def\Romannumerals#1{\ctxlua{converters.Romannumerals(\number#1)}}
+
+%D Arabic etc:
+
+\def\abjadnumerals #1{\ctxlua{converters.abjadnumerals (\number#1)}}
+\def\abjadnodotnumerals#1{\ctxlua{converters.abjadnodotnumerals(\number#1)}}
+\def\abjadnaivenumerals#1{\ctxlua{converters.arabicnumerals (\number#1)}}
\def\languagecharacters#1{\ctxlua{converters.alphabetic(\number#1,"\currentlanguage")}} % new
\def\languageCharacters#1{\ctxlua{converters.Alphabetic(\number#1,"\currentlanguage")}} % new
+% we could use an auxiliary macro to save some bytes in the format
+%
+% \def\dolanguagecharacters#1#2{\ctxlua{converters.alphabetic(\number#2,"#1")}}
+
+\def\thainumerals #1{\ctxlua{converters.alphabetic(\number#1,"thai")}}
+\def\devanagarinumerals#1{\ctxlua{converters.alphabetic(\number#1,"devanagari")}}
+\def\gurmurkhinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gurmurkhi")}}
+\def\gujaratinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gujarati")}}
+\def\tibetannumerals #1{\ctxlua{converters.alphabetic(\number#1,"tibetan")}}
+\def\greeknumerals #1{\ctxlua{converters.alphabetic(\number#1,"greek")}}
+\def\Greeknumerals #1{\ctxlua{converters.Alphabetic(\number#1,"greek")}}
+\def\arabicnumerals #1{\ctxlua{converters.alphabetic(\number#1,"arabic")}}
+\def\persiannumerals #1{\ctxlua{converters.alphabetic(\number#1,"persian")}}
+
+\let\arabicexnumerals \persiannumerals
+
+\def\koreannumerals #1{\ctxlua{converters.alphabetic(\number#1,"korean")}}
+\def\koreannumeralsp#1{\ctxlua{converters.alphabetic(\number#1,"korean-parent")}}
+\def\koreannumeralsc#1{\ctxlua{converters.alphabetic(\number#1,"korean-circle")}}
+
+\def\chinesenumerals #1{\ctxlua{converters.chinesenumerals (\number#1)}}
+\def\chinesecapnumerals#1{\ctxlua{converters.chinesecapnumerals(\number#1,"cap")}}
+\def\chineseallnumerals#1{\ctxlua{converters.chineseallnumerals(\number#1,"all")}}
+
+%D \macros
+%D {character,Character}
+%D
+%D Converting a number into a character can of course only
+%D be done with numbers less or equal to~26. At the cost of
+%D much more macros a faster conversion is possible, using:
+%D
+%D \starttyping
+%D \setvalue{char1}{a} \def\character#1{\getvalue{char#1}}
+%D \stoptyping
+%D
+%D But we prefer a simpel \type{\case}.
+%D
+%D \showsetup{character}
+%D \showsetup{Character}
+
+\def\unknowncharacter{-} % else in lists \relax
+
+\def\character#1{\ctxlua{converters.character (\number#1)}}
+\def\Character#1{\ctxlua{converters.Character (\number#1)}}
+
+%D \macros
+%D {characters,Characters}
+%D
+%D Converting large numbers is supported by the next two
+%D macros. This time we just count on: $\cdots$~x, y, z, aa,
+%D ab, ac~$\cdots$.
+%D
+%D \showsetup{characters}
+%D \showsetup{Characters}
+
+\def\characters#1{\ctxlua{converters.characters(\number#1)}}
+\def\Characters#1{\ctxlua{converters.Characters(\number#1)}}
+
+%D \macros
+%D {greeknumerals,Greeknumerals}
+%D
+%D Why should we only honour the romans, and not the greek?
+
+\let\greeknumerals\gobbleoneargument
+\let\Greeknumerals\gobbleoneargument
+
+%D \macros
+%D {oldstylenumerals,oldstyleromannumerals}
+%D
+%D These conversions are dedicated to Frans Goddijn.
+
+\unexpanded\def\oldstylenumerals#1%
+ {{\os\number#1}}
+
+\unexpanded\def\oldstyleromannumerals#1%
+ {{\leftrulefalse\rightrulefalse\ss\txx\boxrulewidth.15ex
+ \ruledhbox spread .15em{\hss\uppercased{\romannumerals{#1}}\hss}}}
+
+%D \macros
+%D {protectconversion}
+%D
+%D The previous two commands are not robust enough to be
+%D passed to \type{\write} en \type{\message}. That's why we
+%D introduce:
+
+\def\protectconversion
+ {\def\doconvertcharacters##1{##1}} % was \relax
+ %{\def\doconvertcharacters##1{\ifcase0##1 0\else##1\fi}} more save
+
+%D \macros
+%D {normaltime,normalyear,normalmonth,normalday}
+%D
+%D The last part of this module is dedicated to converting
+%D dates. Because we want to use as meaningful commands as
+%D possible, and because \TEX\ already uses up some of those,
+%D we save the original meanings.
+
+\savenormalmeaning\time
+\savenormalmeaning\year
+\savenormalmeaning\month
+\savenormalmeaning\day
+
+%D \macros
+%D {month,MONTH}
+%D
+%D Converting the month number into a month name is done
+%D using a case statement, abstact values and the label
+%D mechanism. This way users can easily redefine a label from
+%D for instance german into austrian.
+%D
+%D \starttyping
+%D \setuplabeltext [de] [january=J\"anner]
+%D \stoptyping
+%D
+%D Anyhow, the conversion looks like:
+
+\def\domonthtag#1%
+ {\ifcase#1%
+ \or \v!january \or \v!february \or \v!march \or \v!april
+ \or \v!may \or \v!june \or \v!july \or \v!august
+ \or \v!september \or \v!october \or \v!november \or \v!december
+ \else
+ \v!unknown
+ \fi}
+
+\def\doconvertmonthlong #1{\labeltext{\domonthtag{#1}}}
+\def\doconvertmonthshort#1{\labeltext{\domonthtag{#1}:\s!mnem}}
+
+\let\doconvertmonth\doconvertmonthlong
+
+%D We redefine the \TEX\ primitive \type{\month} as:
+%D
+%D \showsetup{month}
+%D \showsetup{MONTH}
+
+\def\monthlong {\doconvertmonthlong}
+\def\monthshort{\doconvertmonthshort}
+\def\month {\doconvertmonth}
+
+\def\MONTH #1{{\let\labeltext\LABELTEXT\month {#1}}}
+\def\MONTHLONG #1{{\let\labeltext\LABELTEXT\monthlong {#1}}}
+\def\MONTHSHORT#1{{\let\labeltext\LABELTEXT\monthshort{#1}}}
+
+%D We never explicitly needed this, but Tobias Burnus pointed
+%D out that it would be handy to convert to the day of the
+%D week. In doing so, we have to calculate the total number of
+%D days, taking leapyears into account. For those who are
+%D curious:
+%D
+%D \startitemize[packed]
+%D \item years that can be divided by 4 are leapyears
+%D \item exept years that can be divided by 100
+%D \item unless years can be divided by 400
+%D \stopitemize
+%D
+%D This makes the year 1900 into a normal year and 1996 and
+%D 2000 into leap years, right? Well, converting to string
+%D looks familiar:
+
+\def\doconvertday#1%
+ {\labeltext
+ {\ifcase#1
+ \or \v!sunday \or \v!monday \or \v!tuesday \or \v!wednesday
+ \or \v!thursday \or \v!friday \or \v!saturday \fi}}
+
+%D \macros
+%D {getdayoftheweek, dayoftheweek}
+%D
+%D The conversion algoritm is an old one and a translation from
+%D a procedure written in MODULA~2 back in the 80's. I finaly
+%D found the 4--100-400 rules in some enclopedia. Look at this
+%D messy low level routine that takes the day, month and year
+%D as arguments:
+
+\newcount\normalweekday
+
\def\getdayoftheweek#1#2#3{\normalweekday\ctxlua{converters.weekday(\number#1,\number#2,\number#3)}}
\def\dayoftheweek #1#2#3{\doconvertday{\ctxlua{converters.weekday(\number#1,\number#2,\number#3)}}}
+%D Using this macro in
+%D
+%D \startbuffer
+%D monday: \dayoftheweek {4} {5} {1992}
+%D friday: \dayoftheweek {16} {6} {1995}
+%D monday: \dayoftheweek {25} {8} {1997}
+%D saturday: \dayoftheweek {30} {8} {1997}
+%D tuesday: \dayoftheweek {2} {1} {1996}
+%D tuesday: \dayoftheweek {7} {1} {1997}
+%D tuesday: \dayoftheweek {13} {1} {1998}
+%D friday: \dayoftheweek {1} {1} {2000}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The macro \type {\getdayoftheweek} can be used to calculate
+%D the number \type {\normalweekday}.
+
+%D \macros
+%D {weekday,WEEKDAY}
+%D
+%D The first one is sort of redundant. It takes the day
+%D number argument.
+%D
+%D \showsetup{weekday}
+%D \showsetup{WEEKDAY}
+
+\def\weekday
+ {\doconvertday}
+
+\def\WEEKDAY#1%
+ {{\let\labeltext\LABELTEXT\doconvertday{#1}}}
+
+%D \macros
+%D {weekoftheday}
+%D
+%D {\em not yet implemented:}
+%D
+%D \starttyping
+%D \def\weekoftheday#1#2#3%
+%D {}
+%D \stoptyping
+
+%D \macros
+%D {doifleapyearelse,
+%D getdayspermonth}
+%D
+%D Sometimes we need to know if we're dealing with a
+%D leapyear, so here is a testmacro:
+%D
+%D \starttyping
+%D \doifleapyearelse{year}{yes}{no}
+%D \stoptyping
+%D
+%D An example of its use can be seen in the macro
+%D
+%D \starttyping
+%D \getdayspermonth{year}{month}
+%D \stoptyping
+%D
+%D The number of days is available in the macro \type
+%D {\numberofdays}.
+
\def\doifleapyearelse#1%
{\ifcase\ctxlua{converters.leapyear(\number#1)}
\@EA\secondoftwoarguments
@@ -51,11 +349,6 @@
\def\dayspermonth#1#2%
{\ctxlua{converters.nofdays(\number#1,\number#2)}}
-\def\calculatecurrenttime
- {\edef\currenthour {\ctxlua{converters.hour ()}}%
- \edef\currentminute{\ctxlua{converters.minute()}}%
- \edef\currentsecond{\ctxlua{converters.second()}}}
-
% problem is that we calculate with those numbers
%
% \def\time {\numexpr\ctxlua{converters.textime()}\relax}
@@ -71,33 +364,481 @@
% \dayspermonth{2000}{2}
% [\the\normaltime=\the\time]
-% we could use an auxiliary macro to save some bytes in the format
+%D \macros
+%D {currentdate, date}
+%D
+%D We use these conversion macros in the date formatting
+%D macro:
+%D
+%D \showsetup{currentdate}
+%D
+%D This macro takes care of proper spacing and delivers for
+%D instance:
+%D
+%D \startbuffer
+%D \currentdate[weekday,day,month,year] % still dutch example
+%D \currentdate[WEEKDAY,day,MONTH,year] % still dutch example
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D depending of course on the keywords. Here we gave:
+%D
+%D \typebuffer
+%D
+%D If needed one can also add non||keywords, like in
+%D
+%D \startbuffer
+%D \currentdate[dd,--,mm,--,yy]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or typeset: \getbuffer.
+%D
+%D When no argument is passed, the current date is given as
+%D specified per language (using \type{\installlanguage}).
+%D
+%D \showsetup{currentdate}
+%D
+%D \startbuffer
+%D \date
+%D \date[d=12,m=12,y=1998][weekday]
+%D \date[d=12,m=12,y=1998]
+%D \stopbuffer
+%D
+%D We can also typeset arbitrary dates, using the previous
+%D command.
+%D
+%D \typebuffer
+%D
+%D The date is specified by one character keys. When no date
+%D is given, we get the current date.
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\def\kenmerkdatumpatroon{j,mm,dd} % jj,mm,dd changed at januari 1-1-2000
+
+\newsignal\datesignal
+
+\def\dobetweendates
+ {\ifdim\lastskip=\datesignal\relax\else
+ \unskip\space
+ \hskip\datesignal\relax
+ \fi}
+
+\newtoks \everycurrentdate
+
+\def\complexcurrentdate[#1]%
+ {\bgroup
+ \the\everycurrentdate
+ \def\betweendates{\let\betweendates\dobetweendates}%
+ % was \processcommacommandp[#1]\docomplexcurrentdate
+ \safeedef\ascii{\empty#1}% keep encoded chars
+ \@EA\processcommalist\@EA[\ascii]\docomplexcurrentdate
+ \ifdim\lastskip=\datesignal\relax
+ \unskip
+ \fi
+ \egroup}
+
+\def\docomplexcurrentdate#1%
+ {\lowercase{\edef\!!stringa{#1}}% permits usage in \smallcapped
+ \expanded{\processaction[\!!stringa]}% [#1]
+ [ \v!day=>\betweendates\the\normalday,
+ %\v!day+=>\betweendates\ordinaldaynumber\normalday,
+ \v!day+=>\betweendates\convertnumber{\v!day+}\normalday,
+ \v!month=>\betweendates\month\normalmonth,
+ \v!year=>\betweendates\the\normalyear,
+ \v!space=>\unskip\ \hskip\datesignal,% optimization -)
+ \ =>\unskip\ \hskip\datesignal,% optimization -)
+ d=>\convertnumber\v!day\normalday,
+ %d+=>\ordinaldaynumber\normalday,
+ d+=>\convertnumber{\v!day+}\normalday,
+ m=>\convertnumber\v!month\normalmonth,
+ j=>\convertnumber\v!year\normalyear,
+ y=>\convertnumber\v!year\normalyear,
+ w=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ dd=>\ifnum\normalday >9 \else0\fi\the\normalday,
+ %dd+=>\ordinaldaynumber{\ifnum\normalday >9 \else0\fi\the\normalday},
+ dd+=>\convertnumber{\v!day+}{\ifnum\normalday >9 \else0\fi\the\normalday},
+ mm=>\ifnum\normalmonth>9 \else0\fi\the\normalmonth,
+ jj=>\expandafter\gobbletwoarguments\the\normalyear,
+ yy=>\expandafter\gobbletwoarguments\the\normalyear,
+ \v!weekday=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
+ \v!referral=>\expanded{\complexcurrentdate[\kenmerkdatumpatroon]},
+ \s!unknown=>\unskip
+ % #1 and not the lowercased \commalistelement, vietnamese has text
+ % {} because #1 can have comma, like: {\ ,}
+ {#1}%
+ \hskip\datesignal
+ \def\betweendates{\let\betweendates\dobetweendates}]}
+
+\def\simplecurrentdate
+ {\expanded{\complexcurrentdate[\currentdatespecification]}}
+
+\definecomplexorsimple\currentdate
+
+\def\dodate[#1][#2]%
+ {\bgroup
+ \iffirstargument
+ \getparameters[\??da][d=\normalday,m=\normalmonth,y=\normalyear,#1]%
+ \normalday \@@dad\relax
+ \normalmonth\@@dam\relax
+ \normalyear \@@day\relax
+ \ifsecondargument
+ \currentdate[#2]%
+ \else
+ \currentdate
+ \fi
+ \else
+ \currentdate
+ \fi
+ \egroup}
+
+\def\date
+ {\dodoubleempty\dodate}
+
+%D \macros
+%D {currenttime}
+%D
+%D The currenttime is actually the jobtime. You can specify
+%D a pattern similar to the previous date macro using the
+%D keys \type {h}, \type {m} and a separator.
+
+\def\calculatecurrenttime
+ {\edef\currenthour {\ctxlua{converters.hour ()}}%
+ \edef\currentminute{\ctxlua{converters.minute()}}%
+ \edef\currentsecond{\ctxlua{converters.second()}}}
+
+\let\currenthour \!!plusone
+\let\currentminute\!!plusone
+
+\def\currenttimespecification{h,:,m}
+
+\def\complexcurrenttime[#1]%
+ {\calculatecurrenttime
+ \processallactionsinset[#1]
+ [h=>\currenthour,m=>\currentminute,\s!unknown=>\commalistelement]}
+
+\def\simplecurrenttime
+ {\expanded{\complexcurrenttime[\currenttimespecification]}}
+
+\definecomplexorsimple\currenttime
+
+%D Because we're dealing with dates, we also introduce a few
+%D day loops:
+%D
+%D \starttyping
+%D \processmonth{year}{month}{command}
+%D \processyear{year}{command}{before}{after}
+%D \stoptyping
+%D
+%D The counters \type {\normalyear}, \type {\normalmonth} and
+%D \type{\normalday} can be used for for date manipulations.
+
+\long\def\processmonth#1#2#3% year month command
+ {\bgroup
+ \getdayspermonth{#1}{#2}%
+ \dostepwiserecurse1\numberofdays1%
+ {\normalyear #1\relax
+ \normalmonth#2\relax
+ \normalday \recurselevel\relax
+ #3}%
+ \egroup}
+
+\def\lastmonth{12} % can be set to e.g. 1 when testing
+
+\long\def\processyear#1#2#3#4% year command before after
+ {\bgroup
+ \dorecurse\lastmonth
+ {\normalyear #1\relax
+ \normalmonth\recurselevel\relax
+ #3\processmonth\normalyear\normalmonth{#2}#4}%
+ \egroup}
+
+%D \macros
+%D {defineconversion, convertnumber}
+%D
+%D Conversion involves the macros that we implemented earlier
+%D in this module.
+%D
+%D \showsetup{defineconversion}
+%D \showsetup{convertnumber}
+%D
+%D We can feed this command with conversion macros as well as
+%D a set of conversion symbols. Both need a bit different
+%D treatment.
+%D
+%D \starttyping
+%D \defineconversion [roman] [\romannumerals]
+%D \defineconversion [set 1] [$\star$,$\bullet$,$\ast$]
+%D \stoptyping
+%D
+%D You can define a language dependent conversion with:
+%D
+%D \starttyping
+%D \defineconversion [en] [whatever] [\something]
+%D \stoptyping
+
+% \def\dodefineconversion[#1][#2]%
+% {\ConvertConstantAfter\doifinstringelse{,}{#2}
+% {\scratchcounter=0
+% \def\docommand##1%
+% {\advance\scratchcounter 1
+% \setvalue{\??cv#1\the\scratchcounter}{##1}}%
+% \processcommalist[#2]\docommand
+% \setvalue{\??cv#1}##1{\csname\??cv#1##1\endcsname}}
+% {\setvalue{\??cv#1}{#2}}}
%
-% \def\dolanguagecharacters#1#2{\ctxlua{converters.alphabetic(\number#2,"#1")}}
+% \def\defineconversion%
+% {\dodoubleargument\dodefineconversion}
-% this does not belong here, but in a lang-module
+\def\defineconversion
+ {\dotripleempty\dodefineconversion}
-\def\thainumerals #1{\ctxlua{converters.alphabetic(\number#1,"thai")}}
-\def\devanagarinumerals#1{\ctxlua{converters.alphabetic(\number#1,"devanagari")}}
-\def\gurmurkhinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gurmurkhi")}}
-\def\gujaratinumerals #1{\ctxlua{converters.alphabetic(\number#1,"gujarati")}}
-\def\tibetannumerals #1{\ctxlua{converters.alphabetic(\number#1,"tibetan")}}
-\def\greeknumerals #1{\ctxlua{converters.alphabetic(\number#1,"greek")}}
-\def\Greeknumerals #1{\ctxlua{converters.Alphabetic(\number#1,"greek")}}
-\def\arabicnumerals #1{\ctxlua{converters.alphabetic(\number#1,"arabic")}}
-\def\persiannumerals #1{\ctxlua{converters.alphabetic(\number#1,"persian")}}
+\def\dodefineconversion[#1][#2][#3]%
+ {\ifthirdargument
+ \dododefineconversion[#1][#2][#3]%
+ \else
+ \dododefineconversion[][#1][#2]%
+ \fi}
-\let\arabicexnumerals \persiannumerals
+%D \starttyping
+%D \def\dododefineconversion[#1][#2][#3]%
+%D {\ConvertConstantAfter\doifinstringelse{,}{#3}
+%D {\scratchcounter\zerocount
+%D \def\docommand##1%
+%D {\advance\scratchcounter \plusone
+%D \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+%D \processcommalist[#3]\docommand
+%D \setvalue{\??cv#1#2}##1{\executeifdefined{\??cv#1#2##1}\unknown}} % catch out-of-range numbers
+%D {\setvalue{\??cv#1#2}{#3}}}
+%D \stoptyping
+
+%D This approach has the disadvantage that when you run out of
+%D symbols you get unknown results. The following implementation
+%D permits overloading of the converter:
+
+\def\dododefineconversion[#1][#2][#3]%
+ {\ConvertConstantAfter\doifinstringelse{,}{#3}
+ {\scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
+ \processcommalist[#3]\docommand
+ \setevalue{\??cv#1#2}##1%
+ {\noexpand\docheckedconversion{#1#2}{\the\scratchcounter}{##1}}}
+ {\setvalue{\??cv#1#2}{#3}}}
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1#3}\unknown}
+
+%D When Gerben reported problems with footnote numbering per page,
+%D Taco came with the following wrap around solution. So, let's
+%D overload the checked conversion macro:
+
+\def\docheckedconversion#1#2#3% class maxnumber number
+ {\executeifdefined{\??cv#1\modulatednumber{#2}{#3}}\unknown}
+
+%D Taco's modulo code is implemented in the system module
+%D \type {syst-con}.
+
+%D If a conversion is just a font switch then we need to make sure
+%D that the number is indeed end up as number in the input, so we
+%D need to handle the second argument.
+
+\def\convertnumber#1#2%
+ {\csname\??cv
+ \ifcsname\??cv\currentlanguage#1\endcsname
+ \currentlanguage#1%
+ \else\ifcsname\??cv#1\endcsname
+ #1%
+ \else
+ \s!default
+ \fi\fi
+ \endcsname{\number#2}}
+
+\def\doifconversiondefinedelse#1%
+ {\ifcsname\??cv\currentlanguage#1\endcsname
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??cv#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifelseconversionnumber#1#2% slow but seldom used
+ {\doifdefinedelse{\??cv#1#2}}
+
+%D Handy.
+
+\setvalue{\??cv:\c!n:\v!one }{1}
+\setvalue{\??cv:\c!n:\v!two }{2}
+\setvalue{\??cv:\c!n:\v!three}{3}
+\setvalue{\??cv:\c!n:\v!four }{4}
+\setvalue{\??cv:\c!n:\v!five }{5}
+
+\def\wordtonumber#1#2{\ifcsname\??cv:\c!n:#1\endcsname\csname\??cv:\c!n:#1\endcsname\else#2\fi}
+
+% \defineconversion[ctx][c,o,n,t,e,x,t]
+%
+% \doloop{\doifelseconversionnumber{ctx}{\recurselevel}{[\recurselevel]}{\exitloop}}
+
+%D As longs as symbols are linked to levels or numbers, we can
+%D also use the conversion mechanism, but in for instance the
+%D itemization macros, we prefer symbols because they can more
+%D easier be (partially) redefined. Symbols are implemented
+%D in another module.
+
+\def\smallcappedromannumerals#1{\smallcapped{\romannumerals{#1}}}
+\def\smallcappedcharacters #1{\smallcapped{\characters {#1}}}
+
+\defineconversion [] [\numbers] % the default conversion
+\defineconversion [\v!empty] [\gobbleoneargument]
+\defineconversion [\v!none] [\numbers]
+\defineconversion [\s!default] [\numbers]
+
+\defineconversion [month] [\doconvertmonthlong]
+\defineconversion [month:mnem] [\doconvertmonthshort]
+
+\defineconversion [\v!character] [\character]
+\defineconversion [\v!Character] [\Character]
+
+\defineconversion [\v!characters] [\characters]
+\defineconversion [\v!Characters] [\Characters]
+
+\defineconversion [a] [\characters]
+\defineconversion [A] [\Characters]
+\defineconversion [AK] [\smallcappedcharacters]
+\defineconversion [KA] [\smallcappedcharacters]
+
+\defineconversion [\v!numbers] [\numbers]
+\defineconversion [\v!Numbers] [\Numbers]
+\defineconversion [\v!mediaeval] [\mediaeval]
+
+\defineconversion [n] [\numbers]
+\defineconversion [N] [\Numbers]
+\defineconversion [m] [\mediaeval]
+\defineconversion [o] [\oldstylenumerals]
+\defineconversion [O] [\oldstylenumerals]
+\defineconversion [or] [\oldstyleromannumerals]
+
+\defineconversion [\v!romannumerals] [\romannumerals]
+\defineconversion [\v!Romannumerals] [\Romannumerals]
+
+\defineconversion [i] [\romannumerals]
+\defineconversion [I] [\Romannumerals]
+\defineconversion [r] [\romannumerals]
+\defineconversion [R] [\Romannumerals]
+
+\defineconversion [KR] [\smallcappedromannumerals]
+\defineconversion [RK] [\smallcappedromannumerals]
+
+\defineconversion [\v!greek] [\greeknumerals]
+\defineconversion [\v!Greek] [\Greeknumerals]
+
+\defineconversion [g] [\greeknumerals]
+\defineconversion [G] [\Greeknumerals]
+
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\persiannumerals]
+
+\defineconversion [abjadnumerals] [\abjadnumerals]
+\defineconversion [abjadnodotnumerals] [\adjadnodotnumerals]
+\defineconversion [abjadnaivenumerals] [\adjadnaivenumerals]
+
+\defineconversion [thainumerals] [\thainumerals]
+\defineconversion [devanagarinumerals] [\devanagarinumerals]
+\defineconversion [gurmurkhinumerals] [\gurmurkhinumerals]
+\defineconversion [gujaratinumerals] [\gujaratinumerals]
+\defineconversion [tibetannumerals] [\tibetannumerals]
+\defineconversion [greeknumerals] [\greeknumerals]
+\defineconversion [Greeknumerals] [\Greeknumerals]
+\defineconversion [arabicnumerals] [\arabicnumerals]
+\defineconversion [persiannumerals] [\persiannumerals]
+\defineconversion [arabicexnumerals] [\arabicexnumerals]
+
+
+\defineconversion [koreannumerals] [\koreannumerals]
+\defineconversion [koreanparentnumerals] [\koreanparentnumerals]
+\defineconversion [koreancirclenumerals] [\koreancirclenumerals]
+
+\defineconversion [kr] [\koreannumerals]
+\defineconversion [kr-p] [\koreanparentnumerals]
+\defineconversion [kr-c] [\koreancirclenumerals]
+
+\defineconversion [chinesenumerals] [\chinesenumerals]
+\defineconversion [chinesecapnumeralscn] [\chinesecapnumerals]
+\defineconversion [chineseallnumeralscn] [\chineseallnumerals]
+
+\defineconversion [cn] [\chinesenumerals]
+\defineconversion [cn-c] [\chinesecapnumerals]
+\defineconversion [cn-a] [\chineseallnumerals]
+
+%D Symbol sets:
+
+\ifx\symbol\undefined \def\symbol[#1]{#1} \fi % todo
+
+\defineconversion
+ [set 0]
+ [{\symbol[bullet]},
+ {\symbol[dash]},
+ {\symbol[star]},
+ {\symbol[triangle]},
+ {\symbol[circle]},
+ {\symbol[medcircle]},
+ {\symbol[bigcircle]},
+ {\symbol[square]}]
+
+\defineconversion
+ [set 1]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
+
+\defineconversion
+ [set 2]
+ [\mathematics{*},
+ \mathematics{\dag},
+ \mathematics{\ddag},
+ \mathematics{**},
+ \mathematics{\dag\dag},
+ \mathematics{\ddag\ddag},
+ \mathematics{***},
+ \mathematics{\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag},
+ \mathematics{****},
+ \mathematics{\dag\dag\dag\dag},
+ \mathematics{\ddag\ddag\ddag\ddag}]
-\defineconversion [thainumerals] [\thainumerals]
-\defineconversion [devanagarinumerals] [\devanagarinumerals]
-\defineconversion [gurmurkhinumerals] [\gurmurkhinumerals]
-\defineconversion [gujaratinumerals] [\gujaratinumerals]
-\defineconversion [tibetannumerals] [\tibetannumerals]
-\defineconversion [greeknumerals] [\greeknumerals]
-\defineconversion [Greeknumerals] [\Greeknumerals]
-\defineconversion [arabicnumerals] [\arabicnumerals]
-\defineconversion [persiannumerals] [\persiannumerals]
-\defineconversion [arabicexnumerals] [\arabicexnumerals]
+\defineconversion
+ [set 3]
+ [\mathematics{\star},
+ \mathematics{\star\star},
+ \mathematics{\star\star\star},
+ \mathematics{\ddagger},
+ \mathematics{\ddagger\ddagger},
+ \mathematics{\ddagger\ddagger\ddagger},
+ \mathematics{\P},
+ \mathematics{\P\P},
+ \mathematics{\P\P\P},
+ \mathematics{\S},
+ \mathematics{\S\S},
+ \mathematics{\S\S\S},
+ \mathematics{\ast},
+ \mathematics{\ast\ast},
+ \mathematics{\ast\ast\ast}]
\protect \endinput
diff --git a/tex/context/base/core-con.tex b/tex/context/base/core-con.tex
deleted file mode 100644
index 13d59ecc6..000000000
--- a/tex/context/base/core-con.tex
+++ /dev/null
@@ -1,744 +0,0 @@
-%D \module
-%D [ file=core-con,
-%D version=1997.26.08,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Conversion Macros,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Conversion Macros}
-
-\unprotect
-
-\ifx\currentlanguage\undefined \let\currentlanguage\empty \fi
-\ifx\labeltext \undefined \let\labeltext\firstofoneargument \fi
-
-%D This module deals with all kind of conversions from numbers
-%D and dates. I considered splitting this module in a support
-%D one and a core one, but to keep things simple as well as
-%D preserve the overview, I decided against splitting.
-
-\let\spr\firstofoneargument % separator
-\let\stp\firstofoneargument % stopper
-
-% cleaner, some day:
-%
-% \def\isolateseparators % etex only, even works with list separator overloading
-% {\unexpanded\def\spr##1{{##1}}%
-% \unexpanded\def\stp##1{{##1}}}
-
-% needed for arab :
-
-\def\isolateseparators % even works with list separator overloading
- {\def\spr##1{{##1}}%
- \def\stp##1{{##1}}}
-
-%D \macros
-%D {numbers}
-%D
-%D First we deal with the dummy conversion of numbers using the
-%D \TEX\ primitive \type{\number}. The uppercase alternative is
-%D only there for compatibility with the other conversion
-%D macros. We could do without \type{#1} but this way we get
-%D rid of unwanted braces. For the savety we also define a
-%D non||sence uppercase alternative.
-%D
-%D \showsetup{numbers}
-%D
-%D \starttyping
-%D \def\numbers#1{\number#1}
-%D \def\Numbers#1{\number#1}
-%D \stoptyping
-%D
-%D Due to read ahead, as in \type{[\pagenumber\space]} the space will
-%D disappear, unless we use:
-
-\def\numbers#1{\purenumber{#1}}
-\def\Numbers#1{\purenumber{#1}}
-
-%D \macros
-%D {romannumerals,Romannumerals}
-%D
-%D \TEX\ the program uses a rather tricky conversion from
-%D numbers to their roman counterparts. This conversion could
-%D of course be programmed in \TEX\ itself, but I guess Knuth
-%D found the programming trick worth presenting.
-%D
-%D \showsetup{romannumerals}
-%D \showsetup{Romannumerals}
-
-\let\romannumerals\gobbleoneargument
-\let\Romannumerals\gobbleoneargument
-
-%D \macros
-%D {character,Character}
-%D
-%D Converting a number into a character can of course only
-%D be done with numbers less or equal to~26. At the cost of
-%D much more macros a faster conversion is possible, using:
-%D
-%D \starttyping
-%D \setvalue{char1}{a} \def\character#1{\getvalue{char#1}}
-%D \stoptyping
-%D
-%D But we prefer a simpel \type{\case}.
-%D
-%D \showsetup{character}
-%D \showsetup{Character}
-
-\def\unknowncharacter{-} % else in lists \relax
-
-\let\character\gobbleoneargument
-\let\Character\gobbleoneargument
-
-%D \macros
-%D {characters,Characters}
-%D
-%D Converting large numbers is supported by the next two
-%D macros. This time we just count on: $\cdots$~x, y, z, aa,
-%D ab, ac~$\cdots$.
-%D
-%D \showsetup{characters}
-%D \showsetup{Characters}
-
-\let\characters\gobbleoneargument
-\let\Characters\gobbleoneargument
-
-%D \macros
-%D {greeknumerals,Greeknumerals}
-%D
-%D Why should we only honour the romans, and not the greek?
-
-\let\greeknumerals\gobbleoneargument
-\let\Greeknumerals\gobbleoneargument
-
-%D \macros
-%D {oldstylenumerals,oldstyleromannumerals}
-%D
-%D These conversions are dedicated to Frans Goddijn.
-
-\unexpanded\def\oldstylenumerals#1%
- {{\os\number#1}}
-
-\unexpanded\def\oldstyleromannumerals#1%
- {{\leftrulefalse\rightrulefalse\ss\txx\boxrulewidth.15ex
- \ruledhbox spread .15em{\hss\uppercased{\romannumerals{#1}}\hss}}}
-
-%D \macros
-%D {protectconversion}
-%D
-%D The previous two commands are not robust enough to be
-%D passed to \type{\write} en \type{\message}. That's why we
-%D introduce:
-
-\def\protectconversion
- {\def\doconvertcharacters##1{##1}} % was \relax
- %{\def\doconvertcharacters##1{\ifcase0##1 0\else##1\fi}} more save
-
-%D \macros
-%D {normaltime,normalyear,normalmonth,normalday}
-%D
-%D The last part of this module is dedicated to converting
-%D dates. Because we want to use as meaningful commands as
-%D possible, and because \TEX\ already uses up some of those,
-%D we save the original meanings.
-
-\savenormalmeaning\time
-\savenormalmeaning\year
-\savenormalmeaning\month
-\savenormalmeaning\day
-
-%D \macros
-%D {month,MONTH}
-%D
-%D Converting the month number into a month name is done
-%D using a case statement, abstact values and the label
-%D mechanism. This way users can easily redefine a label from
-%D for instance german into austrian.
-%D
-%D \starttyping
-%D \setuplabeltext [de] [january=J\"anner]
-%D \stoptyping
-%D
-%D Anyhow, the conversion looks like:
-
-\def\domonthtag#1%
- {\ifcase#1%
- \or \v!january \or \v!february \or \v!march \or \v!april
- \or \v!may \or \v!june \or \v!july \or \v!august
- \or \v!september \or \v!october \or \v!november \or \v!december
- \else
- \v!unknown
- \fi}
-
-\def\doconvertmonthlong #1{\labeltext{\domonthtag{#1}}}
-\def\doconvertmonthshort#1{\labeltext{\domonthtag{#1}:\s!mnem}}
-
-\let\doconvertmonth\doconvertmonthlong
-
-%D We redefine the \TEX\ primitive \type{\month} as:
-%D
-%D \showsetup{month}
-%D \showsetup{MONTH}
-
-\def\monthlong {\doconvertmonthlong}
-\def\monthshort{\doconvertmonthshort}
-\def\month {\doconvertmonth}
-
-\def\MONTH #1{{\let\labeltext\LABELTEXT\month {#1}}}
-\def\MONTHLONG #1{{\let\labeltext\LABELTEXT\monthlong {#1}}}
-\def\MONTHSHORT#1{{\let\labeltext\LABELTEXT\monthshort{#1}}}
-
-%D We never explicitly needed this, but Tobias Burnus pointed
-%D out that it would be handy to convert to the day of the
-%D week. In doing so, we have to calculate the total number of
-%D days, taking leapyears into account. For those who are
-%D curious:
-%D
-%D \startitemize[packed]
-%D \item years that can be divided by 4 are leapyears
-%D \item exept years that can be divided by 100
-%D \item unless years can be divided by 400
-%D \stopitemize
-%D
-%D This makes the year 1900 into a normal year and 1996 and
-%D 2000 into leap years, right? Well, converting to string
-%D looks familiar:
-
-\def\doconvertday#1%
- {\labeltext
- {\ifcase#1
- \or \v!sunday \or \v!monday \or \v!tuesday \or \v!wednesday
- \or \v!thursday \or \v!friday \or \v!saturday \fi}}
-
-%D \macros
-%D {getdayoftheweek, dayoftheweek}
-%D
-%D The conversion algoritm is an old one and a translation from
-%D a procedure written in MODULA~2 back in the 80's. I finaly
-%D found the 4--100-400 rules in some enclopedia. Look at this
-%D messy low level routine that takes the day, month and year
-%D as arguments:
-
-\newcount\normalweekday
-
-\let\getdayoftheweek\gobblethreearguments
-\let\dayoftheweek \gobblethreearguments
-
-%D Using this macro in
-%D
-%D \startbuffer
-%D monday: \dayoftheweek {4} {5} {1992}
-%D friday: \dayoftheweek {16} {6} {1995}
-%D monday: \dayoftheweek {25} {8} {1997}
-%D saturday: \dayoftheweek {30} {8} {1997}
-%D tuesday: \dayoftheweek {2} {1} {1996}
-%D tuesday: \dayoftheweek {7} {1} {1997}
-%D tuesday: \dayoftheweek {13} {1} {1998}
-%D friday: \dayoftheweek {1} {1} {2000}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives
-%D
-%D \startvoorbeeld
-%D \startlines
-%D \getbuffer
-%D \stoplines
-%D \stopvoorbeeld
-%D
-%D The macro \type {\getdayoftheweek} can be used to calculate
-%D the number \type {\normalweekday}.
-
-%D \macros
-%D {weekday,WEEKDAY}
-%D
-%D The first one is sort of redundant. It takes the day
-%D number argument.
-%D
-%D \showsetup{weekday}
-%D \showsetup{WEEKDAY}
-
-\def\weekday
- {\doconvertday}
-
-\def\WEEKDAY#1%
- {{\let\labeltext\LABELTEXT\doconvertday{#1}}}
-
-%D \macros
-%D {weekoftheday}
-%D
-%D {\em not yet implemented:}
-%D
-%D \starttyping
-%D \def\weekoftheday#1#2#3%
-%D {}
-%D \stoptyping
-
-%D \macros
-%D {doifleapyearelse,
-%D getdayspermonth}
-%D
-%D Sometimes we need to know if we're dealing with a
-%D leapyear, so here is a testmacro:
-%D
-%D \starttyping
-%D \doifleapyearelse{year}{yes}{no}
-%D \stoptyping
-%D
-%D An example of its use can be seen in the macro
-%D
-%D \starttyping
-%D \getdayspermonth{year}{month}
-%D \stoptyping
-%D
-%D The number of days is available in the macro \type
-%D {\numberofdays}.
-
-\def\doifleapyearelse #1{\firstoftwoarguments}
-\def\getdayspermonth#1#2{\let\numberofdays\!!zerocount}
-
-%D \macros
-%D {currentdate, date}
-%D
-%D We use these conversion macros in the date formatting
-%D macro:
-%D
-%D \showsetup{currentdate}
-%D
-%D This macro takes care of proper spacing and delivers for
-%D instance:
-%D
-%D \startbuffer
-%D \currentdate[weekday,day,month,year] % still dutch example
-%D \currentdate[WEEKDAY,day,MONTH,year] % still dutch example
-%D \stopbuffer
-%D
-%D \startvoorbeeld
-%D \startlines
-%D \getbuffer
-%D \stoplines
-%D \stopvoorbeeld
-%D
-%D depending of course on the keywords. Here we gave:
-%D
-%D \typebuffer
-%D
-%D If needed one can also add non||keywords, like in
-%D
-%D \startbuffer
-%D \currentdate[dd,--,mm,--,yy]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D or typeset: \getbuffer.
-%D
-%D When no argument is passed, the current date is given as
-%D specified per language (using \type{\installlanguage}).
-%D
-%D \showsetup{currentdate}
-%D
-%D \startbuffer
-%D \date
-%D \date[d=12,m=12,y=1998][weekday]
-%D \date[d=12,m=12,y=1998]
-%D \stopbuffer
-%D
-%D We can also typeset arbitrary dates, using the previous
-%D command.
-%D
-%D \typebuffer
-%D
-%D The date is specified by one character keys. When no date
-%D is given, we get the current date.
-%D
-%D \startlines
-%D \getbuffer
-%D \stoplines
-
-\def\kenmerkdatumpatroon{j,mm,dd} % jj,mm,dd changed at januari 1-1-2000
-
-\newsignal\datesignal
-
-\def\dobetweendates
- {\ifdim\lastskip=\datesignal\relax\else
- \unskip\space
- \hskip\datesignal\relax
- \fi}
-
-\newtoks \everycurrentdate
-
-\def\complexcurrentdate[#1]%
- {\bgroup
- \the\everycurrentdate
- \def\betweendates{\let\betweendates\dobetweendates}%
- % was \processcommacommandp[#1]\docomplexcurrentdate
- \safeedef\ascii{\empty#1}% keep encoded chars
- \@EA\processcommalist\@EA[\ascii]\docomplexcurrentdate
- \ifdim\lastskip=\datesignal\relax
- \unskip
- \fi
- \egroup}
-
-\def\docomplexcurrentdate#1%
- {\lowercase{\edef\!!stringa{#1}}% permits usage in \smallcapped
- \expanded{\processaction[\!!stringa]}% [#1]
- [ \v!day=>\betweendates\the\normalday,
- %\v!day+=>\betweendates\ordinaldaynumber\normalday,
- \v!day+=>\betweendates\convertnumber{\v!day+}\normalday,
- \v!month=>\betweendates\month\normalmonth,
- \v!year=>\betweendates\the\normalyear,
- \v!space=>\unskip\ \hskip\datesignal,% optimization -)
- \ =>\unskip\ \hskip\datesignal,% optimization -)
- d=>\convertnumber\v!day\normalday,
- %d+=>\ordinaldaynumber\normalday,
- d+=>\convertnumber{\v!day+}\normalday,
- m=>\convertnumber\v!month\normalmonth,
- j=>\convertnumber\v!year\normalyear,
- y=>\convertnumber\v!year\normalyear,
- w=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
- dd=>\ifnum\normalday >9 \else0\fi\the\normalday,
- %dd+=>\ordinaldaynumber{\ifnum\normalday >9 \else0\fi\the\normalday},
- dd+=>\convertnumber{\v!day+}{\ifnum\normalday >9 \else0\fi\the\normalday},
- mm=>\ifnum\normalmonth>9 \else0\fi\the\normalmonth,
- jj=>\expandafter\gobbletwoarguments\the\normalyear,
- yy=>\expandafter\gobbletwoarguments\the\normalyear,
- \v!weekday=>\betweendates\dayoftheweek\normalday\normalmonth\normalyear,
- \v!referral=>\expanded{\complexcurrentdate[\kenmerkdatumpatroon]},
- \s!unknown=>\unskip
- % #1 and not the lowercased \commalistelement, vietnamese has text
- % {} because #1 can have comma, like: {\ ,}
- {#1}%
- \hskip\datesignal
- \def\betweendates{\let\betweendates\dobetweendates}]}
-
-\def\simplecurrentdate
- {\expanded{\complexcurrentdate[\currentdatespecification]}}
-
-\definecomplexorsimple\currentdate
-
-\def\dodate[#1][#2]%
- {\bgroup
- \iffirstargument
- \getparameters[\??da][d=\normalday,m=\normalmonth,y=\normalyear,#1]%
- \normalday \@@dad\relax
- \normalmonth\@@dam\relax
- \normalyear \@@day\relax
- \ifsecondargument
- \currentdate[#2]%
- \else
- \currentdate
- \fi
- \else
- \currentdate
- \fi
- \egroup}
-
-\def\date
- {\dodoubleempty\dodate}
-
-%D \macros
-%D {currenttime}
-%D
-%D The currenttime is actually the jobtime. You can specify
-%D a pattern similar to the previous date macro using the
-%D keys \type {h}, \type {m} and a separator.
-
-\let\calculatecurrenttime\relax
-
-\let\currenthour \!!plusone
-\let\currentminute\!!plusone
-
-\appendtoks \calculatecurrenttime \to \everyjob
-
-\def\currenttimespecification{h,:,m}
-
-\def\complexcurrenttime[#1]%
- {\calculatecurrenttime
- \processallactionsinset[#1]
- [h=>\currenthour,m=>\currentminute,\s!unknown=>\commalistelement]}
-
-\def\simplecurrenttime
- {\expanded{\complexcurrenttime[\currenttimespecification]}}
-
-\definecomplexorsimple\currenttime
-
-%D Because we're dealing with dates, we also introduce a few
-%D day loops:
-%D
-%D \starttyping
-%D \processmonth{year}{month}{command}
-%D \processyear{year}{command}{before}{after}
-%D \stoptyping
-%D
-%D The counters \type {\normalyear}, \type {\normalmonth} and
-%D \type{\normalday} can be used for for date manipulations.
-
-\long\def\processmonth#1#2#3% year month command
- {\bgroup
- \getdayspermonth{#1}{#2}%
- \dostepwiserecurse1\numberofdays1%
- {\normalyear #1\relax
- \normalmonth#2\relax
- \normalday \recurselevel\relax
- #3}%
- \egroup}
-
-\def\lastmonth{12} % can be set to e.g. 1 when testing
-
-\long\def\processyear#1#2#3#4% year command before after
- {\bgroup
- \dorecurse\lastmonth
- {\normalyear #1\relax
- \normalmonth\recurselevel\relax
- #3\processmonth\normalyear\normalmonth{#2}#4}%
- \egroup}
-
-%D \macros
-%D {defineconversion, convertnumber}
-%D
-%D Conversion involves the macros that we implemented earlier
-%D in this module.
-%D
-%D \showsetup{defineconversion}
-%D \showsetup{convertnumber}
-%D
-%D We can feed this command with conversion macros as well as
-%D a set of conversion symbols. Both need a bit different
-%D treatment.
-%D
-%D \starttyping
-%D \defineconversion [roman] [\romannumerals]
-%D \defineconversion [set 1] [$\star$,$\bullet$,$\ast$]
-%D \stoptyping
-%D
-%D You can define a language dependent conversion with:
-%D
-%D \starttyping
-%D \defineconversion [en] [whatever] [\something]
-%D \stoptyping
-
-% \def\dodefineconversion[#1][#2]%
-% {\ConvertConstantAfter\doifinstringelse{,}{#2}
-% {\scratchcounter=0
-% \def\docommand##1%
-% {\advance\scratchcounter 1
-% \setvalue{\??cv#1\the\scratchcounter}{##1}}%
-% \processcommalist[#2]\docommand
-% \setvalue{\??cv#1}##1{\csname\??cv#1##1\endcsname}}
-% {\setvalue{\??cv#1}{#2}}}
-%
-% \def\defineconversion%
-% {\dodoubleargument\dodefineconversion}
-
-\def\defineconversion
- {\dotripleempty\dodefineconversion}
-
-\def\dodefineconversion[#1][#2][#3]%
- {\ifthirdargument
- \dododefineconversion[#1][#2][#3]%
- \else
- \dododefineconversion[][#1][#2]%
- \fi}
-
-%D \starttyping
-%D \def\dododefineconversion[#1][#2][#3]%
-%D {\ConvertConstantAfter\doifinstringelse{,}{#3}
-%D {\scratchcounter\zerocount
-%D \def\docommand##1%
-%D {\advance\scratchcounter \plusone
-%D \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
-%D \processcommalist[#3]\docommand
-%D \setvalue{\??cv#1#2}##1{\executeifdefined{\??cv#1#2##1}\unknown}} % catch out-of-range numbers
-%D {\setvalue{\??cv#1#2}{#3}}}
-%D \stoptyping
-
-%D This approach has the disadvantage that when you run out of
-%D symbols you get unknown results. The following implementation
-%D permits overloading of the converter:
-
-\def\dododefineconversion[#1][#2][#3]%
- {\ConvertConstantAfter\doifinstringelse{,}{#3}
- {\scratchcounter\zerocount
- \def\docommand##1%
- {\advance\scratchcounter \plusone
- \setvalue{\??cv#1#2\the\scratchcounter}{##1}}%
- \processcommalist[#3]\docommand
- \setevalue{\??cv#1#2}##1%
- {\noexpand\docheckedconversion{#1#2}{\the\scratchcounter}{##1}}}
- {\setvalue{\??cv#1#2}{#3}}}
-
-\def\docheckedconversion#1#2#3% class maxnumber number
- {\executeifdefined{\??cv#1#3}\unknown}
-
-%D When Gerben reported problems with footnote numbering per page,
-%D Taco came with the following wrap around solution. So, let's
-%D overload the checked conversion macro:
-
-\def\docheckedconversion#1#2#3% class maxnumber number
- {\executeifdefined{\??cv#1\modulatednumber{#2}{#3}}\unknown}
-
-%D Taco's modulo code is implemented in the system module
-%D \type {syst-con}.
-
-%D If a conversion is just a font switch then we need to make sure
-%D that the number is indeed end up as number in the input, so we
-%D need to handle the second argument.
-
-\def\convertnumber#1#2%
- {\csname\??cv
- \ifcsname\??cv\currentlanguage#1\endcsname
- \currentlanguage#1%
- \else\ifcsname\??cv#1\endcsname
- #1%
- \else
- \s!default
- \fi\fi
- \endcsname{\number#2}}
-
-\def\doifconversiondefinedelse#1%
- {\ifcsname\??cv\currentlanguage#1\endcsname
- \@EA\firstoftwoarguments
- \else\ifcsname\??cv#1\endcsname
- \@EAEAEA\firstoftwoarguments
- \else
- \@EAEAEA\secondoftwoarguments
- \fi\fi}
-
-\def\doifelseconversionnumber#1#2% slow but seldom used
- {\doifdefinedelse{\??cv#1#2}}
-
-% \defineconversion[ctx][c,o,n,t,e,x,t]
-%
-% \doloop{\doifelseconversionnumber{ctx}{\recurselevel}{[\recurselevel]}{\exitloop}}
-
-\defineconversion [\s!default] [\numbers]
-
-%D As longs as symbols are linked to levels or numbers, we can
-%D also use the conversion mechanism, but in for instance the
-%D itemization macros, we prefer symbols because they can more
-%D easier be (partially) redefined. Symbols are implemented
-%D in another module.
-
-\defineconversion [] [\numbers] % the default conversion
-
-\defineconversion [a] [\characters]
-\defineconversion [A] [\Characters]
-\defineconversion [AK] [\smallcapped\characters]
-\defineconversion [KA] [\smallcapped\characters]
-
-\defineconversion [n] [\numbers]
-\defineconversion [N] [\Numbers]
-\defineconversion [m] [\mediaeval]
-
-\defineconversion [i] [\romannumerals]
-\defineconversion [I] [\Romannumerals]
-\defineconversion [r] [\romannumerals]
-\defineconversion [R] [\Romannumerals]
-\defineconversion [KR] [\smallcapped\romannumerals]
-\defineconversion [RK] [\smallcapped\romannumerals]
-
-\defineconversion [g] [\greeknumerals]
-\defineconversion [G] [\Greeknumerals]
-
-\defineconversion [o] [\oldstylenumerals]
-\defineconversion [O] [\oldstylenumerals]
-\defineconversion [or] [\oldstyleromannumerals]
-
-\defineconversion [\v!character] [\character]
-\defineconversion [\v!Character] [\Character]
-
-\defineconversion [\v!characters] [\characters]
-\defineconversion [\v!Characters] [\Characters]
-
-\defineconversion [\v!numbers] [\numbers]
-\defineconversion [\v!Numbers] [\Numbers]
-\defineconversion [\v!mediaeval] [\mediaeval]
-
-\defineconversion [\v!romannumerals] [\romannumerals]
-\defineconversion [\v!Romannumerals] [\Romannumerals]
-
-\defineconversion [\v!greek] [\greeknumerals]
-\defineconversion [\v!Greek] [\Greeknumerals]
-
-\defineconversion [arabicnumerals] [\arabicnumerals]
-\defineconversion [persiannumerals] [\arabicnumerals]
-
-\defineconversion [month] [\doconvertmonthlong]
-\defineconversion [month:mnem] [\doconvertmonthshort]
-
-% Some bonus ones:
-
-\defineconversion [\v!empty] [\gobbleoneargument]
-\defineconversion [\v!none] [\numbers]
-
-\ifx\symbol\undefined \def\symbol[#1]{#1} \fi % todo
-
-\defineconversion
- [set 0]
- [{\symbol[bullet]},
- {\symbol[dash]},
- {\symbol[star]},
- {\symbol[triangle]},
- {\symbol[circle]},
- {\symbol[medcircle]},
- {\symbol[bigcircle]},
- {\symbol[square]}]
-
-\defineconversion
- [set 1]
- [\mathematics{\star},
- \mathematics{\star\star},
- \mathematics{\star\star\star},
- \mathematics{\ddagger},
- \mathematics{\ddagger\ddagger},
- \mathematics{\ddagger\ddagger\ddagger},
- \mathematics{\ast},
- \mathematics{\ast\ast},
- \mathematics{\ast\ast\ast}]
-
-\defineconversion
- [set 2]
- [\mathematics{*},
- \mathematics{\dag},
- \mathematics{\ddag},
- \mathematics{**},
- \mathematics{\dag\dag},
- \mathematics{\ddag\ddag},
- \mathematics{***},
- \mathematics{\dag\dag\dag},
- \mathematics{\ddag\ddag\ddag},
- \mathematics{****},
- \mathematics{\dag\dag\dag\dag},
- \mathematics{\ddag\ddag\ddag\ddag}]
-
-\defineconversion
- [set 3]
- [\mathematics{\star},
- \mathematics{\star\star},
- \mathematics{\star\star\star},
- \mathematics{\ddagger},
- \mathematics{\ddagger\ddagger},
- \mathematics{\ddagger\ddagger\ddagger},
- \mathematics{\P},
- \mathematics{\P\P},
- \mathematics{\P\P\P},
- \mathematics{\S},
- \mathematics{\S\S},
- \mathematics{\S\S\S},
- \mathematics{\ast},
- \mathematics{\ast\ast},
- \mathematics{\ast\ast\ast}]
-
-%D Plugins:
-
-\loadmarkfile{core-con}
-
-\protect \endinput
diff --git a/tex/context/base/core-ctx.lua b/tex/context/base/core-ctx.lua
index 90cd4cb3b..eb9003bf1 100644
--- a/tex/context/base/core-ctx.lua
+++ b/tex/context/base/core-ctx.lua
@@ -6,8 +6,9 @@ if not modules then modules = { } end modules ['supp-fil'] = {
license = "see context related readme files"
}
-commands = commands or { }
-commands.trace_prepfiles = false
+local trace_prepfiles = false trackers.register("resolvers.prepfiles", function(v) trace_prepfiles = v end)
+
+commands = commands or { }
local list, suffix, islocal, found = { }, "prep", false, false
@@ -17,11 +18,11 @@ function commands.loadctxpreplist()
local x = xml.load(ctlname)
if x then
islocal = xml.found(x,"ctx:preplist[@local=='yes']")
- if commands.trace_prepfiles then
+ if trace_prepfiles then
if islocal then
- ctx.writestatus("systems","loading ctx log file (local)") -- todo: m!systems
+ commands.writestatus("systems","loading ctx log file (local)") -- todo: m!systems
else
- ctx.writestatus("systems","loading ctx log file (specified)") -- todo: m!systems
+ commands.writestatus("systems","loading ctx log file (specified)") -- todo: m!systems
end
end
for r, d, k in xml.elements(x,"ctx:prepfile") do
@@ -31,8 +32,8 @@ function commands.loadctxpreplist()
name = file.basename(name)
end
local done = dk.at['done'] or 'no'
- if commands.trace_prepfiles then
- ctx.writestatus("systems","registering %s -> %s",done)
+ if trace_prepfiles then
+ commands.writestatus("systems","registering %s -> %s",done)
end
found = true
list[name] = done -- 'yes' or 'no'
@@ -41,26 +42,26 @@ function commands.loadctxpreplist()
end
end
-local function resolve(name)
- local function found(name)
- local prepname = name .. "." .. suffix
- local done = list[name]
- if done then
- if lfs.isfile(prepname) then
- if commands.trace_prepfiles then
- ctx.writestatus("systems", "preprocessing: using %s",prepname)
- end
- return prepname
- end
+-- -- --
+
+local function found(name) -- used in resolve
+ local prepname = name .. "." .. suffix
+ if list[name] and lfs.isfile(prepname) then
+ if trace_prepfiles then
+ commands.writestatus("systems", "preprocessing: using %s",prepname)
end
- return false
+ return prepname
end
+ return false
+end
+
+local function resolve(name) -- used a few times later on
local filename = file.collapse_path(name)
local prepname = islocal and found(file.basename(name))
if prepname then
return prepname
end
- local prepname = found(filename)
+ prepname = found(filename)
if prepname then
return prepname
end
diff --git a/tex/context/base/core-ctx.mkii b/tex/context/base/core-ctx.mkii
index 673d69c09..93cf8b4be 100644
--- a/tex/context/base/core-ctx.mkii
+++ b/tex/context/base/core-ctx.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Ctx Job Files}
+\writestatus{loading}{ConTeXt Core Macros / Job Control}
\unprotect
diff --git a/tex/context/base/core-ctx.mkiv b/tex/context/base/core-ctx.mkiv
index f2447ffd0..c401b09f0 100644
--- a/tex/context/base/core-ctx.mkiv
+++ b/tex/context/base/core-ctx.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Ctx Job Files}
+\writestatus{loading}{ConTeXt Core Macros / Job Control}
\unprotect
@@ -23,5 +23,4 @@
\appendtoks\loadctxpreplist\to\everystarttext % will become: \prependtoks\loadctxpreplist\to\everyjob
-
\protect \endinput
diff --git a/tex/context/base/core-ctx.tex b/tex/context/base/core-ctx.tex
deleted file mode 100644
index 6eb70f029..000000000
--- a/tex/context/base/core-ctx.tex
+++ /dev/null
@@ -1,22 +0,0 @@
-%D \module
-%D [ file=core-ctx,
-%D version=2006.08.16, % old stuff
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Job Control,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Ctx Job Files}
-
-%D After some experimenting this code moved into the core. It
-%D overloades a few file reading macros and permits runtime
-%D conversion and job control.
-
-\loadmarkfile{core-ctx}
-
-\endinput
diff --git a/tex/context/base/core-dat.tex b/tex/context/base/core-dat.tex
index dc39f979f..44a82e1f3 100644
--- a/tex/context/base/core-dat.tex
+++ b/tex/context/base/core-dat.tex
@@ -13,73 +13,25 @@
% THIS WILL DISAPPEAR, I.E. BE MOVED TO A MODULE
-\writestatus{loading}{Context Database Support}
+\writestatus{loading}{ConTeXt Core Macros / Database Support}
-\startmessages dutch library: databases
- title: database
- 1: --
- 2: lokaal bestand --
- 3: globaal bestand --
- 4: onbekend bestand --
-\stopmessages
+% messages moved
-\startmessages english library: databases
- title: databases
- 1: --
- 2: local file --
- 3: global file --
- 4: unknown file --
-\stopmessages
+% messages moved
-\startmessages german library: databases
- title: Datenbank
- 1: --
- 2: lokale Datei --
- 3: globale Datei --
- 4: unbekannte Datei --
-\stopmessages
+% messages moved
% TOM :
-\startmessages czech library: databases
- title: databases
- 1: --
- 2: local file --
- 3: global file --
- 4: unknown file --
-\stopmessages
+% messages moved
-\startmessages italian library: databases
- title: database
- 1: --
- 2: file locale --
- 3: file globale --
- 4: file sconosciuto --
-\stopmessages
+% messages moved
-\startmessages norwegian library: databases
- title: databaser
- 1: --
- 2: lokal fil --
- 3: global fil --
- 4: ukjent fil --
-\stopmessages
+% messages moved
-\startmessages romanian library: databases
- title: baze de date
- 1: --
- 2: fisier local --
- 3: fisier global --
- 4: fisier necunoscut --
-\stopmessages
+% messages moved
-\startmessages french library: databases
- title: bases de données
- 1: --
- 2: fichier local --
- 3: fichier global --
- 4: fichier inconnu --
-\stopmessages
+% messages moved
\unprotect
diff --git a/tex/context/base/core-def.mkii b/tex/context/base/core-def.mkii
new file mode 100644
index 000000000..ea2d0ff15
--- /dev/null
+++ b/tex/context/base/core-def.mkii
@@ -0,0 +1,77 @@
+%D \module
+%D [ file=core-def,
+%D version=2002.05.07,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Defaults,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Defaults}
+
+%D Here we collect settings that cannot be done earlier due to
+%D depedencies. More code will moved to this module later.
+
+\unprotect
+
+\usesymbols[mis,mvs] % 'glm' no longer needed due to lm
+
+\usesymbols[nav] \setupsymbolset[navigation 1]
+
+\setupinteraction[\c!symbolset=navigation 1]
+
+% initialization order:
+
+%appendtoks \initializeluainstances \to \everyjob
+\appendtoks \showcontextbanner \to \everyjob
+\appendtoks \initializenewlinechar \to \everyjob
+\appendtoks \checksystemcommandmode \to \everyjob
+\appendtoks \calculatecurrenttime \to \everyjob
+\appendtoks \loadsystemfiles \to \everyjob
+
+\appendtoks \loadoptionfile \to \everyjob % can load files !
+
+\appendtoks \preloadfonts \to \everyjob
+\appendtoks \settopskip \to \everyjob
+\appendtoks \preloadlanguages \to \everyjob
+\appendtoks \preloadspecials \to \everyjob
+\appendtoks \openspecialfile \to \everyjob
+\appendtoks \openutilities \to \everyjob
+\appendtoks \splitjobfilename \to \everyjob
+\appendtoks \checknotes \to \everyjob % depends on bodyfont
+\appendtoks \initializeMPgraphics \to \everyjob % after loading system files
+\appendtoks \reportsystemcommandmode \to \everyjob
+\appendtoks \initializemainlanguage \to \everyjob
+\appendtoks \settrue\trackfilenames \to \everyjob
+\appendtoks \newbackgroundfalse \to \everyjob % global
+
+\ifdefined\initializepagecounters
+ \appendtoks \initializepagecounters \to \everyjob
+\fi
+
+\appendtoks \directsetup{*runtime:options} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \directsetup{*runtime:modules} \to \everyjob % we could erase them afterwards % order can change
+
+\appendtoks \checkpreprocessor \to \everyjob
+
+%appendtoks \page[\v!last] \page \to \everybye % moved to core-job, we need to do this cleaner
+\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye
+\appendtoks \registerfileinfo[end]\jobname \to \everybye
+\appendtoks \savenofpages \to \everybye
+\appendtoks \savenofsubpages \to \everybye
+
+\appendtoks \closeutilities \to \everygoodbye
+\appendtoks \stopcopyingblocks \to \everygoodbye
+\appendtoks \closespecialfile \to \everygoodbye
+
+\prependtoks \resetutilities \to \everystarttext % moved 28-02-2002
+\prependtoks \loadtwopassdata \to \everystarttext % moved 28-02-2002
+\appendtoks \checkreferences \to \everystarttext % new 04-12-1999
+
+% \appendtoks\everyjob\expandafter{\the\everyjob\checkpreprocessor}\to\everydump
+
+\protect \endinput
diff --git a/tex/context/base/core-def.mkiv b/tex/context/base/core-def.mkiv
new file mode 100644
index 000000000..380b733bc
--- /dev/null
+++ b/tex/context/base/core-def.mkiv
@@ -0,0 +1,74 @@
+%D \module
+%D [ file=core-def,
+%D version=2002.05.07,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Defaults,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Defaults}
+
+%D Here we collect settings that cannot be done earlier due to
+%D depedencies. More code will moved to this module later.
+
+\unprotect
+
+\usesymbols[mis,mvs,nav]
+
+\setupsymbolset[navigation 1]
+
+\setupinteraction[\c!symbolset=navigation 1]
+
+% initialization order:
+
+\appendtoks \showcontextbanner \to \everyjob
+\appendtoks \initializenewlinechar \to \everyjob
+\appendtoks \checksystemcommandmode \to \everyjob
+\appendtoks \calculatecurrenttime \to \everyjob
+\appendtoks \loadsystemfiles \to \everyjob
+\appendtoks \loadoptionfile \to \everyjob % can load files !
+\appendtoks \preloadfonts \to \everyjob
+\appendtoks \settopskip \to \everyjob
+\appendtoks \preloadlanguages \to \everyjob
+\appendtoks \preloadspecials \to \everyjob
+\appendtoks \splitjobfilename \to \everyjob
+\appendtoks \checknotes \to \everyjob % depends on bodyfont
+\appendtoks \initializeMPgraphics \to \everyjob % after loading system files
+\appendtoks \reportsystemcommandmode \to \everyjob
+\appendtoks \initializemainlanguage \to \everyjob
+\appendtoks \MPLIBregister \to \everyjob
+\appendtoks \xmlinitialize \to \everyjob
+\appendtoks \settrue\trackfilenames \to \everyjob
+\appendtoks \newbackgroundfalse \to \everyjob % global
+\appendtoks \initializepagecounters \to \everyjob
+\appendtoks \directsetup{*runtime:options} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \directsetup{*runtime:modules} \to \everyjob % we could erase them afterwards % order can change
+\appendtoks \checkpreprocessor \to \everyjob
+
+%appendtoks \page[\v!last] \page \to \everybye % moved to core-job, we need to do this cleaner
+\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye
+\appendtoks \registerfileinfo[end]\jobname \to \everybye
+
+\prependtoks \resetutilities \to \everystarttext % moved 28-02-2002
+
+\appendtoks \MPLIBallocate{1000} \to \everydump
+
+\prependtoks \resetallattributes \to \everybeforeoutput
+
+\appendtoks \the\everybackendshipout \to \everyshipout
+\prependtoks \the\everylastbackendshipout \to \everylastshipout
+
+% temporary here:
+
+\ifx\in \undefined\else \let\normalmathin \in \unexpanded\def\in {\mathortext\normalmathin \dospecialin } \fi
+\ifx\at \undefined\else \let\normalmathat \at \unexpanded\def\at {\mathortext\normalmathat \dospecialat } \fi
+\ifx\about\undefined\else \let\normalmathabout\about \unexpanded\def\about{\mathortext\normalmathabout\dospecialabout} \fi
+\ifx\from \undefined\else \let\normalmathfrom \from \unexpanded\def\from {\mathortext\normalmathfrom \dospecialfrom } \fi
+\ifx\over \undefined\else \let\normalmathover \over \unexpanded\def\over {\mathortext\normalmathover \dospecialabout} \fi
+
+\protect \endinput
diff --git a/tex/context/base/core-def.tex b/tex/context/base/core-def.tex
deleted file mode 100644
index c7c49858e..000000000
--- a/tex/context/base/core-def.tex
+++ /dev/null
@@ -1,27 +0,0 @@
-%D \module
-%D [ file=core-def,
-%D version=2002.05.07,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Defaults,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Defaults}
-
-%D Here we collect settings that cannot be done earlier due to
-%D depedencies. More code will moved to this module later.
-
-\unprotect
-
-\usesymbols[mis,mvs] % 'glm' no longer needed due to lm
-
-\usesymbols[nav] \setupsymbolset[navigation 1]
-
-\setupinteraction[\c!symbolset=navigation 1]
-
-\protect \endinput
diff --git a/tex/context/base/core-des.tex b/tex/context/base/core-des.tex
index 1794800a4..dc7136c40 100644
--- a/tex/context/base/core-des.tex
+++ b/tex/context/base/core-des.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Descriptions}
+\writestatus{loading}{ConTeXt Core Macros / Descriptions}
%D In order to be more flexible with theorems Aditya Mahajan added
%D support for titles and endsymbols. At the same time we some more
@@ -394,7 +394,7 @@
% which calls:
\def\@@makedescription#1%
- {\postponefootnotes % new, assumes grouping
+ {\postponenotes % new, assumes grouping
\def\currentdescription{#1}%
\executeifdefined
{@@description\descriptionparameter\c!location}
@@ -829,8 +829,7 @@
\def\do@@label[#1][#2]%
{\numberparameter{#1}\c!before
- \numberparameter{#1}\c!command
- {\doattributes{\@@thenumber{#1}}\c!headstyle\c!headcolor{\getvalue{\e!next#1}[#2]}}%
+ \numberparameter{#1}\c!command{\doattributes{\@@thenumber{#1}}\c!headstyle\c!headcolor{\getvalue{\e!next#1}[#2]}}%
\numberparameter{#1}\c!after}%
\def\do@@nextlabel[#1][#2]%
diff --git a/tex/context/base/core-new.tex b/tex/context/base/core-env.mkii
index e96039d10..a22594b27 100644
--- a/tex/context/base/core-new.tex
+++ b/tex/context/base/core-env.mkii
@@ -1,6 +1,6 @@
%D \module
-%D [ file=core-nav,
-%D version=1995.01.01,
+%D [ file=core-env, % was core-new
+%D version=1995.01.01, % wrong
%D title=\CONTEXT\ Core Macros,
%D subtitle=New ones,
%D author=Hans Hagen,
@@ -11,23 +11,210 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / New Ones}
+\writestatus{loading}{ConTeXt Core Macros / Environments}
\unprotect
+% Clean labels:
+
+\bgroup % some day this will go away / we could use detokenize as well
+
+% actually we should handle all discretionaries here
+
+\catcode`:=\@@active
+
+\gdef\cleanuplabel#1%
+ {\begingroup
+ \let:\lettercolon
+ \xdef\cleanlabel{#1}%
+ \endgroup}
+
+\gdef\cleanupprefixedlabel#1#2%
+ {\begingroup
+ \let:\lettercolon
+ \xdef\cleanprefix{#1}%
+ \xdef\cleanlabel {#2}%
+ \endgroup}
+
+\gdef\protectlabels
+ {\let:\lettercolon}
+
+\global\def\blabelgroup {\begingroup \let:\lettercolon}
+\global\let\elabelgroup \endgroup
+
+\gdef\labelcsname
+ {\begingroup\let:\lettercolon
+ \expandafter\endgroup\csname}
+
+\gdef\labelvalue#1%
+ {\labelcsname#1\endcsname}
+
+\egroup
+
+%D Modes:
+%D
+%D \starttyping
+%D \enablemode[screen,paper,bound]
+%D
+%D \doifmodeelse {paper} {this} {that}
+%D \doifmode {paper,screen} {this}
+%D \doifnotmode {paper,bound} {that}
+%D
+%D \startmode [list]
+%D \stopmode
+%D
+%D \startnotmode [list]
+%D \stopnotmode
+%D \stoptyping
+%D
+%D system modes have a * as prefix
+%D
+%D Sometimes, we want to prevent a mode for being set. Think
+%D of situations where a style enables a mode, but an outer
+%D level style does not want that. Preventing can be
+%D considered a permanent disabling on forehand.
+
+\def\@mode@{@md@}
+
+\def\systemmodeprefix{*}
+
+\def\disabledmode {0}
+\def\enabledmode {1}
+\def\preventedmode {2}
+
+% fast internal ones
+
+\def\setmode #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
+\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}
+
+\def\setsystemmode #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
+\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}
+
+% user ones
+
+\def\preventmode{\unprotect\dopreventmode}
+\def\enablemode {\unprotect\doenablemode }
+\def\disablemode{\unprotect\dodisablemode}
+
+\def\dopreventmode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodopreventmode}
+\def\doenablemode [#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodoenablemode }
+\def\dodisablemode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dododisablemode}
+
+\def\dodopreventmode#1%
+ {\@EA\let\csname\@mode@#1\endcsname\preventedmode}
+
+\def\dodoenablemode#1% mode can be relax
+ {\ifcase0\csname\@mode@#1\endcsname\relax
+ \@EA\let\csname\@mode@#1\endcsname\enabledmode
+ \fi}
+
+\def\dododisablemode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or
+ \@EA\let\csname\@mode@#1\endcsname\disabledmode
+ \fi}
+
+% handy for mp
+
+\def\booleanmodevalue#1% can be \relax
+ {\expandafter\ifx\csname\@mode@#1\endcsname\relax
+ fals%
+ \else\ifnum0\csname\@mode@#1\endcsname=0
+ fals%
+ \else
+ tru%
+ \fi\fi e}
+
+% check macros
+
+\newif\ifcheckedmode
+
+\def\dodocheckformode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}
+
+\def\docheckformode#1#2#3% will be sped up with a quit
+ {\cleanuplabel{#3}%
+ \protect\checkedmodefalse\rawprocesscommacommand[\cleanlabel]\dodocheckformode
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+\def\dodocheckforallmodes#1%
+ {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}
+
+\def\docheckforallmodes#1#2#3% will be sped up with a quit
+ {\cleanuplabel{#3}%
+ \protect\checkedmodetrue\rawprocesscommacommand[\cleanlabel]\dodocheckforallmodes
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+% simple ones
+
+\def\doifmodeelse{\unprotect\dodoifmodeelse}
+\def\doifmode {\unprotect\dodoifmode}
+\def\doifnotmode {\unprotect\dodoifnotmode}
+\def\startmode {\unprotect\dostartmode}
+\def\startnotmode{\unprotect\dostartnotmode}
+
+\def\dodoifmodeelse
+ {\docheckformode\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifmode
+ {\docheckformode\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotmode
+ {\docheckformode\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartmode[#1]%
+ {\docheckformode\donothing\dostopmode{#1}}
+
+\long\def\dostartnotmode[#1]%
+ {\docheckformode\dostopnotmode\donothing{#1}}
+
+\let\stopmode \donothing
+\let\stopnotmode\donothing
+
+\long\def\dostopmode #1\stopmode {}
+\long\def\dostopnotmode#1\stopnotmode{}
+
+\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
+\def\doifallmodes {\unprotect\dodoifallmodes}
+\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
+\def\startallmodes {\unprotect\dostartallmodes}
+\def\startnotallmodes{\unprotect\dostartnotallmodes}
+
+\def\dodoifallmodeselse
+ {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifallmodes
+ {\docheckforallmodes\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotallmodes
+ {\docheckforallmodes\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartallmodes[#1]%
+ {\docheckforallmodes\donothing\dostopallmodes{#1}}
+
+\long\def\dostartnotallmodes[#1]%
+ {\docheckforallmodes\dostopnotallmodes\donothing{#1}}
+
+\let\stopallmodes \donothing
+\let\stopnotallmodes\donothing
+
+\long\def\dostopallmodes #1\stopallmodes {}
+\long\def\dostopnotallmodes#1\stopnotallmodes{}
+
+% Setups
+
\let\startsetups\relax % to please dep checker
\let\stopsetups \relax % to please dep checker
\expanded
{\long\def\@EA\noexpand\csname\e!start\v!setups\endcsname
- {\begingroup\noexpand\doifnextcharelse[%
+ {\begingroup\noexpand\doifnextoptionalelse
{\noexpand\startsetupsA\@EA\noexpand\csname\e!stop\v!setups\endcsname}
{\noexpand\startsetupsB\@EA\noexpand\csname\e!stop\v!setups\endcsname}}}
\letvalue{\e!stop\v!setups}\relax
-\unexpanded \def\setups{\doifnextcharelse\bgroup\dosetupsA\dosetupsB} % {..} or [..]
-\unexpanded \def\setup {\doifnextcharelse\bgroup\dosetups \dosetupsC} % {..} or [..]
+\unexpanded \def\setups{\doifnextbgroupelse\dosetupsA\dosetupsB} % {..} or [..]
+\unexpanded \def\setup {\doifnextbgroupelse\dosetups \dosetupsC} % {..} or [..]
\def\dosetupsA #1{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % {..}
\def\dosetupsB[#1]{\cleanuplabel{#1}\processcommacommand[\cleanlabel]\dosetups} % [..]
@@ -94,7 +281,7 @@
\def\startxmlsetups {\xxstartsetups\plustwo \stopxmlsetups } \let\stopxmlsetups \relax
\def\xxstartsetups#1#2%
- {\begingroup\chardef\setupseolmode#1\doifnextcharelse[{\startsetupsA#2}{\startsetupsB#2}}
+ {\begingroup\chardef\setupseolmode#1\doifnextoptionalelse{\startsetupsA#2}{\startsetupsB#2}}
\def\startsetupsA#1% [ ] delimited
{\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
@@ -149,55 +336,14 @@
% \ifundefined{\??su\ifgridsnapping\v!grid\fi:#1}#1\else\ifgridsnapping\v!grid\fi%
% #1}}
-%D new and beta
-
-% \def\defineshortcut
-% {\dodoubleargument\dodefineshortcut}
-%
-% \bgroup
-%
-% \catcode`\<=\@@active
-%
-% \gdef\dodefineshortcut[#1][#2]%
-% {\ifsecondargument
-% \catcode`\<=\@@active
-% \def<{\ifmmode\expandafter\normalless\else\expandafter\doshortcut\fi}%
-% \getparameters[\??te#1][\c!commands=,\c!command=,\c!style=,\c!color=,#2]%
-% \else
-% \defineshortcut[][#1]%
-% \fi}
-%
-% \egroup
-%
-% \def\doshortcut
-% {\bgroup
-% \catcode`\>=\@@other
-% \dodoshortcut}
-%
-% \def\dodoshortcut#1>%
-% {\def\shortcut{#1}%
-% \dododoshortcut#1:\end}
-%
-% \def\dododoshortcut#1:#2\end
-% {\doifelsenothing{#2}
-% {\doifundefinedelse{\??te\c!commands}
-% {\shortcut}
-% {\@EA\dodododoshortcut\@EA\??te\@EA:\shortcut:\end}}
-% {\doifundefinedelse{\??te#1\c!commands}
-% {\shortcut}
-% {\dodododoshortcut\??te#1:#2\end}}%
-% \egroup}
-%
-% \def\dodododoshortcut#1:#2:\end
-% {\getvalue{#1\c!commands}%
-% \doattributes{#1}\c!style\c!color{\getvalue{#1\c!command}{#2}}}
+%D new and beta and will become a module instead
\def\defineshortcut
{\dotripleargument\dodefineshortcut}
\def\dodefineshortcut[#1][#2][#3]%
{\ifthirdargument
- \ConvertConstantAfter\doifelse{#1}{}
+ \doifelsenothing{#1}
{\dododefineshortcut[<>][#2][#3]}
{\dododefineshortcut[#1][#2][#3]}%
\else\ifsecondargument
@@ -276,6 +422,99 @@
%D it seems -a:to work- well
%D \stoplines
+%D \macros
+%D {setvariables,getvariable,getvariabledefault}
+%D
+%D \starttyping
+%D \setvariables[xx][title=]
+%D \setvariables[xx][title=test test]
+%D \setvariables[xx][title=test $x=1$ test] % fatal error reported
+%D \setvariables[xx][title=test {$x=1$} test]
+%D \setvariables[xx][title] % fatal error reported
+%D \setvariables[xx][titletitel=e]
+%D \stoptyping
+
+\def\??vars{@@vars}
+
+\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
+\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
+\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
+\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}
+
+\def\globalsetvariables % obsolete
+ {\dotripleargument\dosetvariables[\globalgetrawparameters]}
+
+\long\def\dosetvariables[#1][#2][#3]% tricky, test on s-pre-60
+ {\errorisfataltrue
+ \doifelse{#2}\currentvariableclass
+ {#1[\??vars:#2:][#3]}%
+ {\pushmacro\currentvariableclass
+ \def\currentvariableclass{#2}%
+ \getvariable{#2}\s!reset
+ #1[\??vars:#2:][#3]%
+ \getvariable{#2}\s!set
+ \popmacro\currentvariableclass}%
+ \errorisfatalfalse}
+
+\long\def\setvariable #1#2#3{\long\setvalue {\??vars:#1:#2}{#3}}
+\long\def\setevariable#1#2#3{\long\setevalue{\??vars:#1:#2}{#3}}
+\long\def\setgvariable#1#2#3{\long\setgvalue{\??vars:#1:#2}{#3}}
+\long\def\setxvariable#1#2#3{\long\setxvalue{\??vars:#1:#2}{#3}}
+
+\def\getvariable#1#2% to be sped up
+ {\csname
+ \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
+ \endcsname}
+
+\def\showvariable#1#2%
+ {\showvalue{\ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi}}
+
+\let\currentvariableclass\empty
+
+%D \macros
+%D {doifelsevariable,doifvariable,doifnotvariable}
+%D
+%D A few trivial macros:
+
+\def\doifelsevariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\getvariabledefault#1#2% #3% can be command, so no ifcsname here
+ {\executeifdefined{\??vars:#1:#2}}% {#3}
+
+%D \macros
+%D {checkvariables}
+%D
+%D I'll probably forget that this on exists.
+
+\def\checkvariables
+ {\dodoubleargument\docheckvariables}
+
+\def\docheckvariables
+ {\dogetparameters\docheckrawvalue}
+
+\def\docheckrawvalue#1#2#3%
+ {\doifundefined {\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}
+ {\doifvaluenothing{\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}}}
+
% \def\setupenv{\dodoubleargument\rawgetparameters[\??en]}
%
% \def\doifenvelse#1{\doifdefinedelse{\??en#1}} % speed up
diff --git a/tex/context/base/core-env.mkiv b/tex/context/base/core-env.mkiv
new file mode 100644
index 000000000..47bd7549d
--- /dev/null
+++ b/tex/context/base/core-env.mkiv
@@ -0,0 +1,472 @@
+%D \module
+%D [ file=core-env, % was core-new
+%D version=1995.01.01, % wrong
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=New ones,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Environments}
+
+\unprotect
+
+%D Clean labels (no longer needed in \MKIV\ but we keep the grouping
+%D till we hav ea full separation of code.):
+
+\def\cleanuplabel#1%
+ {\xdef\cleanlabel{#1}}
+
+\def\cleanupprefixedlabel#1#2%
+ {\xdef\cleanprefix{#1}%
+ \xdef\cleanlabel {#2}}
+
+\let\protectlabels\donothing
+\let\blabelgroup \begingroup % obsolete
+\let\elabelgroup \endgroup % obsolete
+\let\labelcsname \csname
+\let\labelvalue \getvalue
+
+%D Modes:
+%D
+%D \starttyping
+%D \enablemode[screen,paper,bound]
+%D
+%D \doifmodeelse {paper} {this} {that}
+%D \doifmode {paper,screen} {this}
+%D \doifnotmode {paper,bound} {that}
+%D
+%D \startmode [list]
+%D \stopmode
+%D
+%D \startnotmode [list]
+%D \stopnotmode
+%D \stoptyping
+%D
+%D system modes have a * as prefix
+%D
+%D Sometimes, we want to prevent a mode for being set. Think
+%D of situations where a style enables a mode, but an outer
+%D level style does not want that. Preventing can be
+%D considered a permanent disabling on forehand.
+
+\def\@mode@{@md@}
+
+\def\systemmodeprefix{*}
+
+\def\disabledmode {0} % no chardefs
+\def\enabledmode {1}
+\def\preventedmode{2}
+
+% fast internal ones
+
+\def\setmode #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
+\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}
+
+\def\setsystemmode #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
+\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}
+
+% user ones
+
+\def\preventmode{\unprotect\dopreventmode}
+\def\enablemode {\unprotect\doenablemode }
+\def\disablemode{\unprotect\dodisablemode}
+
+\def\dopreventmode[#1]{\protect\rawprocesscommacommand[#1]\dodopreventmode}
+\def\doenablemode [#1]{\protect\rawprocesscommacommand[#1]\dodoenablemode }
+\def\dodisablemode[#1]{\protect\rawprocesscommacommand[#1]\dododisablemode}
+
+\def\dodopreventmode#1%
+ {\@EA\let\csname\@mode@#1\endcsname\preventedmode}
+
+\def\dodoenablemode#1% mode can be relax
+ {\ifcase0\csname\@mode@#1\endcsname\relax
+ \@EA\let\csname\@mode@#1\endcsname\enabledmode
+ \fi}
+
+\def\dododisablemode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or
+ \@EA\let\csname\@mode@#1\endcsname\disabledmode
+ \fi}
+
+% handy for mp
+
+\def\booleanmodevalue#1% can be \relax
+ {\expandafter\ifx\csname\@mode@#1\endcsname\relax
+ fals%
+ \else\ifnum0\csname\@mode@#1\endcsname=0
+ fals%
+ \else
+ tru%
+ \fi\fi e}
+
+% check macros
+
+\newif\ifcheckedmode
+
+\def\dodocheckformode#1%
+ {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}
+
+\def\docheckformode#1#2#3% will be sped up with a quit
+ {\protect\checkedmodefalse\rawprocesscommacommand[#3]\dodocheckformode
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+\def\dodocheckforallmodes#1%
+ {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}
+
+\def\docheckforallmodes#1#2#3% will be sped up with a quit
+ {\protect\checkedmodetrue\rawprocesscommacommand[#3]\dodocheckforallmodes
+ \ifcheckedmode\@EA#1\else\@EA#2\fi}
+
+% simple ones
+
+\def\doifmodeelse{\unprotect\dodoifmodeelse}
+\def\doifmode {\unprotect\dodoifmode}
+\def\doifnotmode {\unprotect\dodoifnotmode}
+\def\startmode {\unprotect\dostartmode}
+\def\startnotmode{\unprotect\dostartnotmode}
+
+\def\dodoifmodeelse
+ {\docheckformode\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifmode
+ {\docheckformode\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotmode
+ {\docheckformode\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartmode[#1]%
+ {\docheckformode\donothing\dostopmode{#1}}
+
+\long\def\dostartnotmode[#1]%
+ {\docheckformode\dostopnotmode\donothing{#1}}
+
+\let\stopmode \donothing
+\let\stopnotmode\donothing
+
+\long\def\dostopmode #1\stopmode {}
+\long\def\dostopnotmode#1\stopnotmode{}
+
+\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
+\def\doifallmodes {\unprotect\dodoifallmodes}
+\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
+\def\startallmodes {\unprotect\dostartallmodes}
+\def\startnotallmodes{\unprotect\dostartnotallmodes}
+
+\def\dodoifallmodeselse
+ {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}
+
+\def\dodoifallmodes
+ {\docheckforallmodes\firstofoneargument\gobbleoneargument}
+
+\def\dodoifnotallmodes
+ {\docheckforallmodes\gobbleoneargument\firstofoneargument}
+
+\long\def\dostartallmodes[#1]%
+ {\docheckforallmodes\donothing\dostopallmodes{#1}}
+
+\long\def\dostartnotallmodes[#1]%
+ {\docheckforallmodes\dostopnotallmodes\donothing{#1}}
+
+\let\stopallmodes \donothing
+\let\stopnotallmodes\donothing
+
+\long\def\dostopallmodes #1\stopallmodes {}
+\long\def\dostopnotallmodes#1\stopnotallmodes{}
+
+%D Setups:
+
+\let\startsetups\relax % to please dep checker
+\let\stopsetups \relax % to please dep checker
+
+\expanded
+ {\long\def\@EA\noexpand\csname\e!start\v!setups\endcsname
+ {\begingroup\noexpand\doifnextoptionalelse
+ {\noexpand\startsetupsA\@EA\noexpand\csname\e!stop\v!setups\endcsname}
+ {\noexpand\startsetupsB\@EA\noexpand\csname\e!stop\v!setups\endcsname}}}
+
+\letvalue{\e!stop\v!setups}\relax
+
+\unexpanded \def\setups{\doifnextbgroupelse\dosetupsA\dosetupsB} % {..} or [..]
+\unexpanded \def\setup {\doifnextbgroupelse\dosetups \dosetupsC} % {..} or [..]
+
+\def\dosetupsA #1{\processcommacommand[#1]\dosetups} % {..}
+\def\dosetupsB[#1]{\processcommacommand[#1]\dosetups} % [..]
+\def\dosetupsC[#1]{\dosetups{#1}} % [..]
+
+\letvalue{\??su:\letterpercent}\gobbleoneargument
+
+\def\dosetups#1% the grid option will be extended to other main modes
+ {\csname\??su
+ \ifgridsnapping
+ \ifcsname\??su\v!grid:#1\endcsname\v!grid:#1\else\ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi\fi
+ \else
+ \ifcsname\??su:#1\endcsname:#1\else:\letterpercent\fi
+ \fi
+ \endcsname\empty} % takes one argument
+
+\def\setupwithargument#1% the grid option will be extended to other main modes
+ {\csname\??su:\ifcsname\??su:#1\endcsname#1\else\letterpercent\fi\endcsname}
+
+\let\directsetup\dosetups
+
+\def\doifsetupselse#1% to be done: grid
+ {\doifdefinedelse{\??su:#1}}
+
+\chardef\setupseolmode\plusone
+
+\def\startsetups {\xxstartsetups\plusone \stopsetups } \let\stopsetups \relax
+\def\startlocalsetups{\xxstartsetups\plusone \stoplocalsetups} \let\stoplocalsetups\relax
+\def\startrawsetups {\xxstartsetups\zerocount\stoprawsetups } \let\stoprawsetups \relax
+\def\startxmlsetups {\xxstartsetups\plustwo \stopxmlsetups } \let\stopxmlsetups \relax
+
+\def\xxstartsetups#1#2%
+ {\begingroup\let\setupseolmode#1\doifnextoptionalelse{\startsetupsA#2}{\startsetupsB#2}}
+
+\def\startsetupsA#1% [ ] delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dotripleempty\dostartsetups[#1]}
+
+\def\startsetupsB#1#2 % space delimited
+ {\ifcase\setupseolmode\or\catcode`\^^M\@@ignore\or\catcode`\^^M\@@ignore\catcode`\|\@@other\fi
+ \dodostartsetups#1\empty{#2}}
+
+\def\startsetupsC[#1][#2][#3]{\dodostartsetups#1{#2}{#3}} % [..] [..]
+\def\startsetupsD[#1][#2][#3]{\dodostartsetups#1\empty{#2}} % [..]
+
+\def\dostartsetups
+ {\ifthirdargument\@EA\startsetupsC\else\@EA\startsetupsD\fi}
+
+\long\def\dodostartsetups#1#2#3%
+ {\long\def\dododostartsetups##1#1%
+ {\endgroup
+ \dodoglobal % bah
+ \long\expandafter\def\csname\??su#2:#3\expandafter\endcsname\expandafter####\expandafter1\expandafter{##1}}%
+ \dododostartsetups\empty} % the empty trick prevents the { } in {arg} from being eaten up
+
+\def\systemsetupsprefix{*}
+
+\def\systemsetups#1{\dosetups{\systemsetupsprefix#1}}
+
+\def\resetsetups[#1]% see x-fo for usage
+ {\ifcsname\??su\ifgridsnapping\v!grid\fi:#1\endcsname
+ \dodoglobal\letbeundefined{\??su\ifgridsnapping\v!grid\fi:#1}%
+ \else
+ \dodoglobal\letbeundefined{\??su:#1}%
+ \fi}
+
+%D \defineshortcut [style=type]
+%D \defineshortcut [b] [style=bold]
+%D \defineshortcut [e] [style=\em]
+%D \defineshortcut [t] [style=type]
+%D \defineshortcut [c] [style=cap]
+%D \defineshortcut [k] [style=cap]
+%D \defineshortcut [u] [style=type,command=\hyphenatedurl]
+%D
+%D \startlines
+%D test <ziezo> test
+%D test test <t:ziezo>
+%D test test <b:ziezo>
+%D test test <w:ziezo>
+%D zus<>zo zus<:>zo zus<::>zo
+%D test test <t:ziezo> dat (ziezo)
+%D test test <t::ziezo> dat (:ziezo)
+%D test test <t:ziezo:> dat (ziezo:)
+%D test test <t:zi:ezo:> dat (zi:ezo:)
+%D well, <u:http://www.pragma-ade.nl> looks fuzzy
+%D $10<20$
+%D \stoplines
+%D
+%D \defineshortcut [<>] [i] [style=\it]
+%D \defineshortcut [()] [b] [style=\bf]
+%D \defineshortcut [++] [s] [style=\sl]
+%D \defineshortcut [//] [u] [style=\underbars]
+%D \defineshortcut [--] [a] [style=\overstrike]
+%D
+%D \startlines
+%D it seems <i:to work> well
+%D it seems (b:to work) well
+%D it seems +s:to work+ well
+%D it seems /u:to work/ well
+%D it seems -a:to work- well
+%D \stoplines
+
+\def\defineshortcut
+ {\dotripleargument\dodefineshortcut}
+
+\def\dodefineshortcut[#1][#2][#3]%
+ {\ifthirdargument
+ \doifelsenothing{#1}
+ {\dododefineshortcut[<>][#2][#3]}
+ {\dododefineshortcut[#1][#2][#3]}%
+ \else\ifsecondargument
+ \dododefineshortcut[<>][#1][#2]%
+ \else
+ \dododefineshortcut[<>][][#1]%
+ \fi\fi}
+
+\def\dododefineshortcut[#1#2][#3][#4]% #1 is the trigger, #2 the delimiter/tag
+ {\doifundefined{\??te\??te\string#2}{\letvalue{\??te\??te\string#2}=#1}%
+ \defineactivecharacter #1 {\@EA\doshortcut\string#2} % we need to deactivate in math
+ \getparameters
+ [\??te\string#2#3]
+ [\c!commands=,\c!command=,\c!style=,\c!color=,#4]}
+
+\def\doshortcut#1%
+ {\ifmmode
+ \getvalue{\??te\??te#1}%
+ \else
+ \bgroup
+ \catcode`#1=\@@other
+ \def\dodoshortcut##1#1%
+ {\def\shorttag{\??te#1}%
+ \def\shortcut{##1}%
+ \dododoshortcut##1:\end}%
+ \@EA\dodoshortcut
+ \fi}
+
+\def\dododoshortcut#1:#2\end
+ {\doifelsenothing{#2}
+ {\doifundefinedelse{\shorttag\c!commands}
+ {\shortcut}
+ {\@EA\dodododoshortcut\@EA\shorttag\@EA:\shortcut:\end}}
+ {\doifundefinedelse{\shorttag#1\c!commands}
+ {\shortcut}
+ {\dodododoshortcut\shorttag#1:#2\end}}%
+ \egroup}
+
+\def\dodododoshortcut#1:#2:\end
+ {\getvalue{#1\c!commands}%
+ \doattributes{#1}\c!style\c!color{\getvalue{#1\c!command}{#2}}}
+
+%D \macros
+%D {setvariables,getvariable,getvariabledefault}
+%D
+%D \starttyping
+%D \setvariables[xx][title=]
+%D \setvariables[xx][title=test test]
+%D \setvariables[xx][title=test $x=1$ test] % fatal error reported
+%D \setvariables[xx][title=test {$x=1$} test]
+%D \setvariables[xx][title] % fatal error reported
+%D \setvariables[xx][titletitel=e]
+%D \stoptyping
+
+\def\??vars{@@vars}
+
+\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
+\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
+\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
+\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}
+
+\def\globalsetvariables % obsolete
+ {\dotripleargument\dosetvariables[\globalgetrawparameters]}
+
+\long\def\dosetvariables[#1][#2][#3]% tricky, test on s-pre-60
+ {\errorisfataltrue
+ \doifelse{#2}\currentvariableclass
+ {#1[\??vars:#2:][#3]}%
+ {\pushmacro\currentvariableclass
+ \def\currentvariableclass{#2}%
+ \getvariable{#2}\s!reset
+ #1[\??vars:#2:][#3]%
+ \getvariable{#2}\s!set
+ \popmacro\currentvariableclass}%
+ \errorisfatalfalse}
+
+\long\def\setvariable #1#2#3{\long\expandafter\def \csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setevariable#1#2#3{\long\expandafter\edef\csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setgvariable#1#2#3{\long\expandafter\gdef\csname\??vars:#1:#2\endcsname{#3}}
+\long\def\setxvariable#1#2#3{\long\expandafter\xdef\csname\??vars:#1:#2\endcsname{#3}}
+
+\def\getvariable#1#2%
+ {\csname
+ \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
+ \endcsname}
+
+\def\showvariable#1#2%
+ {\showvalue{\ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi}}
+
+\let\currentvariableclass\empty
+
+%D \macros
+%D {checkvariables}
+%D
+%D I'll probably forget that this on exists.
+
+\def\checkvariables
+ {\dodoubleargument\docheckvariables}
+
+\def\docheckvariables
+ {\dogetparameters\docheckrawvalue}
+
+\long\def\docheckrawvalue#1#2#3%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \edef\checkedrawvalue{\csname\??vars:#1:#2\endcsname}%
+ \ifx\checkedrawvalue\empty
+ \long\expandafter\def\csname\??vars:#1:#2\endcsname{#3}%
+ \fi
+ \else
+ \long\expandafter\def\csname\??vars:#1:#2\endcsname{#3}%
+ \fi}
+
+%D \macros
+%D {doifelsevariable,doifvariable,doifnotvariable}
+%D
+%D A few trivial macros:
+
+\def\doifelsevariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotvariable#1#2%
+ {\ifcsname\??vars:#1:#2\endcsname
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\getvariabledefault#1#2% #3% can be command, so no ifcsname here
+ {\executeifdefined{\??vars:#1:#2}}% {#3}
+
+% \def\setupenv{\dodoubleargument\rawgetparameters[\??en]}
+%
+% \def\doifenvelse#1{\doifdefinedelse{\??en#1}} % speed up
+% \def\doifenv #1{\doifdefined {\??en#1}} % speed up
+% \def\doifnotenv #1{\doifundefined {\??en#1}} % speed up
+%
+% \def\env#1{\csname\??en#1\endcsname}
+%
+% \def\envvar#1#2%
+% {\ifcsname\??en#1\endcsname
+% \csname\??en#1\endcsname\else#2%
+% \fi}
+%
+% low level change, now also accessible as \getvariable
+% {environment}{...}; the next macros will become obsolete
+% some day in favor of normal variables in the environment
+% namespace
+
+\def\s!environment{environment}
+
+\def\setupenv {\dotripleargument\dosetvariables[\getrawparameters][\s!environment]}
+\def\doifenvelse{\doifelsevariable \s!environment}
+\def\doifenv {\doifvariable \s!environment}
+\def\doifnotenv {\doifnotvariable \s!environment}
+\def\env {\getvariable \s!environment}
+\def\envvar {\getvariabledefault\s!environment}
+
+\protect \endinput
diff --git a/tex/context/base/core-fig.tex b/tex/context/base/core-fig.tex
index 714a85e49..63aa1d193 100644
--- a/tex/context/base/core-fig.tex
+++ b/tex/context/base/core-fig.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Figure Handling}
+\writestatus{loading}{ConTeXt Core Macros / Figure Handling}
\unprotect
@@ -491,8 +491,6 @@
\doglobal\beforesplitstring#3\at.\to\typesetfilename
\externalfigure[\typesetfilename.pdf][#2,#4]}
-\appendtoks \setupexternalfigures[\c!option=\v!empty] \to \everyfastmode
-
\setupexternalfigures
[\c!option=,
\c!object=\v!yes, % we only check for no
diff --git a/tex/context/base/core-fil.tex b/tex/context/base/core-fil.tex
index eda055a96..fca253a7b 100644
--- a/tex/context/base/core-fil.tex
+++ b/tex/context/base/core-fil.tex
@@ -11,54 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / File Support}
+\writestatus{loading}{ConTeXt Core Macros / File Support}
\unprotect
-% NOT YET DOCUMENTED !!
-%
-% overal \normalinput
-
-\startmessages dutch library: files
- title: files
- 1: file synoniem -- is al in gebruik voor --
-\stopmessages
-
-\startmessages english library: files
- title: files
- 1: file synonym -- is already used for --
-\stopmessages
-
-\startmessages german library: files
- title: files
- 1: Dateisynonym -- wird bereits fuer -- benutzt
-\stopmessages
-
-\startmessages czech library: files
- title: soubory
- 1: synonymum souboru -- je jiz pouzito pro --
-\stopmessages
-
-\startmessages italian library: files
- title: file
- 1: sinonimo file -- già in uso per --
-\stopmessages
-
-\startmessages norwegian library: files
- title: filer
- 1: filesynonym -- er allerede brukt for --
-\stopmessages
-
-\startmessages romanian library: files
- title: fisiere
- 1: sinonimul fisierelor -- este folosit deja pentru --
-\stopmessages
-
-\startmessages french library: files
- title: fichiers
- 1: le synonyme de fichier -- est déjà utilisé pour --
-\stopmessages
-
%D Files registered as temporary files will be deleted after a
%D run by texexec:
@@ -100,6 +56,8 @@
%D \usemodules[pictex,chemie,unit]
%D \stoptyping
+% will be redone in mkiv
+
\def\definefilesynonym
{\dodoubleempty\dodefinefilesynonym}
@@ -207,6 +165,7 @@
{\dododousemodules{#1-}{#2}}%
\ifconditional\moduleisloaded\else
\showmessage\m!systems6{#2}%
+ \appendtoks\showmessage\m!systems6{#2}\to\everynotabene
\fi}
% \def\usemodules
@@ -254,7 +213,7 @@
\let\currentmodule \s!unknown
\def\startmodule
- {\doifnextcharelse[\dostartmodule\nostartmodule}
+ {\doifnextoptionalelse\dostartmodule\nostartmodule}
\def\nostartmodule #1 %
{\dostartmodule[#1]}
@@ -339,7 +298,7 @@
% The following filenames are defined here:
\def\TEXbufferfile #1{\bufferprefix#1.\f!temporaryextension}
-\def\MPgraphicfile {\bufferprefix mp\ifMPrun run\else graph\fi}
+\def\MPgraphicfile {\bufferprefix mp\ifMPrun run\else graph\fi} % not needed in luatex
\def\convertMPcolorfile{\bufferprefix metacmyk.tmp}
%D To save memory, we implement some seldomly used commands
@@ -373,9 +332,6 @@
\let\checkpreprocessor\relax
-% \appendtoks\relax{\appendtoks \checkpreprocessor \to \everyjob}\to\everydump
-\appendtoks\everyjob\expandafter{\the\everyjob\checkpreprocessor}\to\everydump
-
%D To be documented and probably moved
\def\documentresources{\@@erurl}
diff --git a/tex/context/base/core-fld.tex b/tex/context/base/core-fld.mkii
index 3b1ce9b3f..2b177c916 100644
--- a/tex/context/base/core-fld.tex
+++ b/tex/context/base/core-fld.mkii
@@ -2,7 +2,7 @@
%D [ file=core-fld,
%D version=1997.05.18,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Fill in fields,
+%D subtitle=Fields,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -20,7 +20,7 @@
% internal string truncated, (3) second time truncated
% string is sent.
-\writestatus{loading}{Context Field Macros}
+\writestatus{loading}{ConTeXt Core Macros / Fields}
% messages
diff --git a/tex/context/base/core-fld.mkiv b/tex/context/base/core-fld.mkiv
new file mode 100644
index 000000000..96ecf6b54
--- /dev/null
+++ b/tex/context/base/core-fld.mkiv
@@ -0,0 +1,1079 @@
+%D \module
+%D [ file=core-fld,
+%D version=1997.05.18,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Fields,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% \appendtocommalist versus \addtocommalist
+%
+% * as default trigger in radiofields ?
+%
+% beware: weblink plugin truncates on length, while save as doesn't;
+% more precise: (1) first time right string is sent, (2)
+% internal string truncated, (3) second time truncated
+% string is sent.
+
+\writestatus{loading}{ConTeXt Core Macros / Fields}
+
+% messages
+
+\definemessageconstant{fields}
+
+\unprotect
+
+%D First we hook fields into the (viewer based) layering mechanism
+%D (implemented as properties).
+
+\ifx\currentlayerproperty\undefined\else \let\currentlayerproperty\empty\fi
+
+\appendtoks
+ \doif\@@iafieldlayer\v!auto
+ {\def\@@iafieldlayer{\currentlayerproperty}}%
+\to \everysetupinteraction
+
+\setupinteraction
+ [\c!fieldlayer=\v!auto] % auto by default
+
+%D Internal command, linked to \type{\definesymbol}.
+
+\def\dogetfieldsymbol#1%
+ {\getobject{SYM}{#1}}
+
+\def\dopresetfieldsymbol#1%
+ {\doifobjectfoundelse{SYM}{#1}
+ {}
+ {\settightobject{SYM}{#1}\hbox{\symbol[#1]}%
+ \flushatshipout
+ {\setbox0\hbox{\hskip-\maxdimen\getobject{SYM}{#1}}%
+ \smashbox0\box0}}}
+
+\def\presetfieldsymbols[#1]% slow
+ {\def\dopresetfieldsymbols##1%
+ {\processcommalist[##1]\dopresetfieldsymbol}%
+ \@EA\processcommalist\@EA[#1]\dopresetfieldsymbols}
+
+\def\definedefaultsymbols
+ {\definesymbol[defaultyes][$\times$]%
+ \definesymbol[defaultno][$\cdot$]}
+
+\def\resetfieldsymbol[#1]% for experimental usage only
+ {\resetobject{SYM}{#1}}
+
+%D The interface to the specials. DEFAULT NOG ANDERS
+
+\def\preparefieldvariables % evt \def's at the outer level (test) or \edef's here for fast testing
+ {\let\@@DriverFieldNumber \@@fdn
+ \let\@@DriverFieldStyle \@@fdstyle
+ \let\@@DriverFieldColor \@@fdcolor
+ \let\@@DriverFieldBackgroundColor\@@fdfieldbackgroundcolor
+ \let\@@DriverFieldFrameColor \@@fdfieldframecolor
+ \let\@@DriverFieldLayer \@@fdfieldlayer
+ \let\@@DriverFieldOption \@@fdoption
+ \let\@@DriverFieldAlign \@@fdalign
+ \let\@@DriverFieldClickIn \@@fdclickin
+ \let\@@DriverFieldClickOut \@@fdclickout
+ \let\@@DriverFieldRegionIn \@@fdregionin
+ \let\@@DriverFieldRegionOut \@@fdregionout
+ \let\@@DriverFieldAfterKey \@@fdafterkey
+ \let\@@DriverFieldFormat \@@fdformat
+ \let\@@DriverFieldValidate \@@fdvalidate
+ \let\@@DriverFieldCalculate \@@fdcalculate
+ \let\@@DriverFieldFocusIn \@@fdfocusin
+ \let\@@DriverFieldFocusOut \@@fdfocusout}
+
+% todo : remove arguments, consider DriverField a namespace
+
+\def\presetlinefield
+ {\preparefieldvariables
+ \dopresetlinefield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldNumber}
+ {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldAlign}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presettextfield
+ {\preparefieldvariables
+ \dopresettextfield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldNumber}
+ {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldAlign}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetchoicefield
+ {\preparefieldvariables
+ \dopresetchoicefield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetpopupfield
+ {\preparefieldvariables
+ \dopresetpopupfield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetcombofield
+ {\preparefieldvariables
+ \dopresetcombofield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldStyle,\@@DriverFieldColor,\@@DriverFieldBackgroundColor,\@@DriverFieldFrameColor}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetcheckfield
+ {\preparefieldvariables
+ \presetfieldsymbols[\@@DriverFieldValues]%
+ \dopresetcheckfield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetpushfield
+ {\preparefieldvariables
+ %\edef\@@DriverFieldValues{{\@@DriverFieldValues}}% makes sure {a,b,c} is passed
+ \presetfieldsymbols[\@@DriverFieldValues]%
+ \dopresetpushfield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetradiofield
+ {\preparefieldvariables
+ \presetfieldsymbols[\@@DriverFieldValues]%
+ \dopresetradiofield
+ {\@@DriverFieldName}
+ {\@@DriverFieldWidth}
+ {\@@DriverFieldHeight}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldRoot}
+ {\@@DriverFieldValues}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\presetradiorecord
+ {\preparefieldvariables
+ \dopresetradiorecord
+ {\@@DriverFieldName}
+ {\@@DriverFieldDefault}
+ {\@@DriverFieldOption}
+ {\@@DriverFieldKids}
+ {\@@DriverFieldClickIn,\@@DriverFieldClickOut,\@@DriverFieldRegionIn,\@@DriverFieldRegionOut,%
+ \@@DriverFieldAfterKey,\@@DriverFieldFormat,\@@DriverFieldValidate,\@@DriverFieldCalculate,%
+ \@@DriverFieldFocusIn,\@@DriverFieldFocusOut}}
+
+\def\setfieldmodes#1#2#3%
+ {\xdef\@@DriverFieldMode{#1}% % 0 1 2 3
+ \xdef\@@DriverFieldFree{#2}% % 0 1
+ \xdef\@@DriverFieldAuto{#3}} % 0 1
+
+\newevery\everysetfield\relax
+
+\def\doiffieldelse#1{\doifdefinedelse{fielddata#1}}
+
+\def\setfield#1#2#3#4#5#6#7#8#9%
+ {\bgroup
+ \doglobal\increment\numberoffields
+ \iftracefields
+ \doglobal\addtocommalist{#1}\collectedfields
+ \fi
+ \the\everysetfield
+ \setxvalue{fielddata#1}% kortere tag #7 needs expansion etc
+ {\noexpand\dosetfield{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}{#9}}%
+ \egroup}
+
+\def\dosetfield#1#2#3#4#5#6#7#8#9%
+ {\xdef\@@DriverFieldName {#1}%
+ \xdef\@@DriverFieldType {#2}%
+ \xdef\@@DriverFieldRoot {#3}%
+ \xdef\@@DriverFieldParent {#4}%
+ \xdef\@@DriverFieldKids {#5}%
+ \xdef\@@DriverFieldGroup {#6}%
+ \setfieldmodes #7%
+ \bgroup
+ \def\par{\string\n\string\n}%
+ \xdef\@@DriverFieldValues {#8}%
+ \xdef\@@DriverFieldDefault{#9}%
+ \egroup}
+
+\def\changefield#1%
+ {\setfield{#1}\@@DriverFieldType\@@DriverFieldRoot\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldGroup
+ {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}\@@DriverFieldValues\@@DriverFieldDefault}
+
+\def\getfield#1% name
+ {\doifundefinedelse{fielddata#1}
+ {\dosetfield{#1}\empty\empty\empty\empty\empty{\empty00}\empty\empty}
+ {\getvalue{fielddata#1}}}
+
+\newif\iftracefields \tracefieldsfalse
+
+\let\tracefields\tracefieldstrue
+
+\def\doshowfields[#1]% todo: tabulate van maken en runtime
+ {\bgroup
+ \switchtobodyfont[8pt,tt]%
+ \doifsomething{#1}{\def\collectedfields{#1}}%
+ \ifx\collectedfields\empty
+ \par specify [fieldlist] or say \type{\tracefieldstrue} first\par
+ \else
+ \def\normalizedfieldmode##1##2##3%
+ {\ifcase0##2 \else\sl\fi
+ \ifcase0##1 loner\or parent\or clone\or copy\fi}%
+ \def\dosetfield##1##2##3##4##5##6##7##8##9%
+ {##1&##2&##3&##4&##5&##6&\normalizedfieldmode##7&##8&##9\cr}%
+ \halign
+ {&##\strut\hss\quad\cr
+ \noalign{\hrule}%
+ NAME &TYPE &ROOT &
+ PARENT&KIDS &GROUP &
+ MODE &VALUES&DEFAULT\cr
+ \noalign{\hrule}%
+ \@EA\globalprocesscommalist\@EA[\collectedfields]\getfield
+ \noalign{\hrule}}%
+ \fi
+ \egroup}
+
+\def\showfields
+ {\dosingleempty\doshowfields}
+
+\def\dologfields[#1]%
+ {\bgroup
+ \immediate\openout\scratchwrite=fields.log
+ \doifsomething{#1}{\def\collectedfields{#1}}%
+ \ifx\colledtedfields\empty
+ \immediate\write\scratchwrite{use \tracefieldstrue}%
+ \else
+ \def\normalizedfieldmode##1##2##3%
+ {\edef\@@DriverFieldMode
+ {\ifcase##1 loner \or parent \or clone \or copy \fi
+ \ifcase##2 \else(done)\fi}}%
+ \def\dosetfield##1##2##3##4##5##6##7##8##9%
+ {\normalizedfieldmode##7%
+ \immediate\write\scratchwrite
+ {N=##1 / T=##2 / R=##3 / P=##4 / K=##5 / G=##6 /
+ M=\@@DriverFieldMode\space/ V=##8 / D=##9}}%
+ \processcommacommand[\collectedfields]\getfield
+ \fi
+ \immediate\closeout\scratchwrite
+ \egroup}
+
+\def\logfields
+ {\dosingleempty\doLogFields}
+
+%D \starttyping
+%D \definefield [name] [type] [group] [values] [default]
+%D
+%D \definefield [WWWW] [text] [textsetup] [default text]
+%D \definefield [XXXX] [push] [pushsetup] [yes,no] [yes]
+%D \definefield [XXXX] [check] [checksetup] [yes,no] [yes]
+%D \definefield [YYYY] [combo] [combosetup] [a,b,c,d] [b]
+%D \definefield [ZZZZ] [radio] [radiosetup] [W,X,Y,Z] [Y]
+%D
+%D \definesubfield [W] [subsetup] [p,q]
+%D \definesubfield [X,Y] [subsetup] [p,r]
+%D \definesubfield [Z] [subsetup] [y,z]
+%D
+%D evt \definemainfield ... wanneer geplaatst voor subs gegeven
+%D
+%D \clonefield [XXXX] [XX,YY] [mysetup] [on,off]
+%D \clonefield [Z] [AA,BB] [somesetup] [true,false]
+%D \clonefield [Z] [CC,DD] [anothersetup]
+%D
+%D \copyfield [XXXX] [PP,QQ,RR]
+%D
+%D \field[XXXX]
+%D \fitfield[XXXX]
+%D \stoptyping
+
+\newif\ifdefinemainfield \definemainfieldfalse
+
+%D We need to keep track of cloned (related) fields and so by
+%D maintaining lists of field clones.
+%D
+%D The first alternative used a two pass data list and was
+%D implemented as follows:
+%D
+%D \starttyping
+%D \def\getmainfieldkids#1%
+%D {\let\@@DriverFieldKids\empty
+%D \ifdefinemainfield
+%D \definetwopasslist{fld:#1}% defined by system
+%D \doloop
+%D {\gettwopassdata{fld:#1}%
+%D \iftwopassdatafound
+%D %\addtocommalist\twopassdata\@@DriverFieldKids
+%D \appendtocommalist\twopassdata\@@DriverFieldKids
+%D \else
+%D \exitloop
+%D \fi}%
+%D \fi}
+%D \stoptyping
+%D
+%D However, the next alternative is much faster when we have
+%D a field with thousands of clones, something not that
+%D imaginary.
+%D
+%D \starttyping
+%D \def\getmainfieldkids#1%
+%D {\let\@@DriverFieldKids\empty
+%D \ifdefinemainfield
+%D \definetwopasslist{fld:#1}% runtime defined by system
+%D \getnamedtwopassdatalist{fld:#1}\@@DriverFieldKids
+%D \fi}
+%D \stoptyping
+%D
+%D The data is written by file using:
+%D
+%D \starttyping
+%D \newcounter\nofmainfieldkids
+%D
+%D \def\setmainfieldkid#1#2%
+%D {\doglobal\increment\nofmainfieldkids
+%D \savetwopassdata{fld:#1}{\nofmainfieldkids}{#2}}
+%D \stoptyping
+%D
+%D The trade of of this mechanism is that for each cloned or
+%D copied field, the uitlity file is to be read in order to
+%D fetch the data.
+%D
+%D The next, much faster alternative uses a dedicated %
+%D reference mechanism.
+
+\def\setmainfieldkid#1#2%
+ {\immediatewriteutilitycommand{\fieldreference{#1}{#2}}}
+
+\def\checkfieldreferences
+ {\startnointerference
+ \protectlabels
+ \doutilities{fieldreferences}\jobname\empty\relax\relax
+ \global\let\checkfieldreferences\relax
+ \stopnointerference}
+
+\def\setfieldreferences
+ {\def\fieldreference##1##2%
+ {\ifundefined{\r!widget##1}%
+ \setxvalue{\r!widget##1}{##2}%
+ \else
+ \edef\!!stringa{\getvalue{\r!widget##1}}%
+ \setxvalue{\r!widget##1}{\!!stringa,##2}%
+ \fi}}
+
+\def\resetfieldreferences
+ {\let\fieldreference\gobbletwoarguments}
+
+\def\getmainfieldkids#1%
+ {\checkfieldreferences
+ \ifdefinemainfield
+ \doifundefinedelse{\r!widget#1}%
+ {\let\@@DriverFieldKids\empty}
+ {\@EA\let\@EA\@@DriverFieldKids\csname\r!widget#1\endcsname}%
+ \else
+ \let\@@DriverFieldKids\empty
+ \fi}
+
+\resetfieldreferences
+
+%D Of course it costs a few more tokens to implement, but it's
+%D worth the memory: running for instance the 2000 page
+%D english examns publishing on demand document went down from
+%D 1350 seconds to less than 950 on a 650 Mhz pentium.
+
+\def\definefield
+ {\definemainfieldfalse\doquintupleempty\dodefinefield}
+
+\def\definemainfield
+ {\definemainfieldtrue \doquintupleempty\dodefinefield}
+
+\let\collectedfields\empty
+\newcounter\numberoffields
+\newcounter\totalnumberoffields
+
+\def\savenumberoffields
+ {\ifcase\numberoffields\relax\else
+ \savecurrentvalue\totalnumberoffields\numberoffields
+ \fi}
+
+\appendtoks \savenumberoffields \to \everybye % \everylastshipout
+
+% \def\presetfieldreferences
+% {\ifnum\totalnumberoffields>0
+% \definereference[AtOpenInitializeForm][\v!ResetForm]%
+% \fi}
+%
+% \definereference[AtOpenInitializeForm][\v!geen]
+%
+% \appendtoks \presetfieldreferences \to \everycheckreferences
+
+\def\dodefinefield[#1][#2][#3][#4][#5]%
+ {\ifsecondargument
+ \edef\currentfieldname{#1}% just in case we're inside a loop
+ \doifundefinedelse{define#2field}
+ {\writestatus\m!fields{unknown field type #2}}
+ {\doifundefined{fielddata\currentfieldname}
+ {\getmainfieldkids\currentfieldname
+ \ifdefinemainfield
+ \ifx\@@DriverFieldKids\empty
+ \let\@@DriverFieldMode\fieldlonermode
+ \else
+ \let\@@DriverFieldMode\fieldparentmode
+ \fi
+ \def\@@DriverFieldAuto{1}%
+ \else
+ \let\@@DriverFieldMode\fieldlonermode
+ \def\@@DriverFieldAuto{0}%
+ \fi
+ \def\@@DriverFieldFree{0}%
+ \getvalue{define#2field}{\currentfieldname}{#2}{#3}{#4}{#5}}}%
+ \else
+ \writestatus\m!fields{pass fieldname and fieldtype}%
+ \fi}
+
+\def\definelinefield#1#2#3#4#5%
+ {\setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{#4}}
+
+\let\definetextfield=\definelinefield
+
+\def\definechoicefield#1#2#3#4#5%
+ {\doifelsenothing{#4}
+ {\def\@@DriverFieldValues{yes,no}}
+ {\def\@@DriverFieldValues{#4}}%
+ \doifelsenothing{#5}
+ {\dogetcommacommandelement2\from\@@DriverFieldValues \to\@@DriverFieldDefault
+ \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault}
+ {\def\@@DriverFieldDefault{#5}}%
+ \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}}
+
+\let\definepopupfield=\definechoicefield
+\let\definecombofield=\definechoicefield
+
+%\def\definecheckfield#1#2#3#4#5%
+% {\doifelsenothing{#4}
+% {\definedefaultsymbols
+% \def\@@DriverFieldValues{defaultyes}}
+% {\def\@@DriverFieldValues{#4}}%
+% \doifelsenothing{#5}
+% {\dogetcommacommandelement2\from\@@DriverFieldValues\to\@@DriverFieldDefault
+% \dogetcommacommandelement1\from\@@DriverFieldDefault\to\@@DriverFieldDefault}
+% {\def\@@DriverFieldDefault{#5}}%
+% \setfield{#1}{#2}{}{}{\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{\@@DriverFieldValues}{\@@DriverFieldDefault}}
+
+%D Since these fields have an on/off state only, we pass 1/0
+%D to the driver as default values.
+
+\def\definecheckfield#1#2#3#4#5%
+ {\doifelsenothing{#4}
+ {\definedefaultsymbols
+ \def\@@DriverFieldValues{defaultyes}}
+ {\def\@@DriverFieldValues{#4}}%
+ \doifelsenothing{#5}
+ {\def\@@DriverFieldDefault{2}}
+ {\dogetcommacommandelement1\from\@@DriverFieldValues\to\@@DriverFieldDefault
+ \doifinstringelse{#5}{\@@DriverFieldDefault}
+ {\def\@@DriverFieldDefault{1}}
+ {\def\@@DriverFieldDefault{0}}}%
+ \setfield
+ {#1}{#2}{}{}{\@@DriverFieldKids}{#3}%
+ {\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}%
+ {\@@DriverFieldValues}{\@@DriverFieldDefault}}
+
+\let\definepushfield=\definecheckfield
+
+\def\defineradiofield#1#2#3#4#5%
+ {\iffourthargument
+ \doifelsenothing{#5}
+ {\dogetcommacommandelement1\from#4\to\SavedFieldDefault
+ \dogetcommacommandelement1\from\SavedFieldDefault\to\SavedFieldDefault}
+ {\def\SavedFieldDefault{#5}}%
+% when opt works
+% \@EA\beforesplitstring\SavedFieldDefault\at=>\to\SavedFieldDefault
+ \ifx\@@DriverFieldKids\empty
+ \setfield{#1}{#2}{}{}{#4}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}%
+ \else
+ \setfield{#1}{#2}{}{}{#4,\@@DriverFieldKids}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\SavedFieldDefault}%
+ \fi
+%
+ \def\docommand##1%
+ {\doifelse{##1}\SavedFieldDefault
+ {\def\@@DriverFieldDefault{##1}}%
+ {\let\@@DriverFieldDefault\empty}%
+ \setfield{##1}{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}%
+% when opt works
+% \def\docommand##1%
+% {\@EA\beforesplitstring##1\at=>\to\FieldValue
+% \doifelse\FieldValue\SavedFieldDefault
+% {\let\@@DriverFieldDefault\FieldValue}%
+% {\let\@@DriverFieldDefault\empty}%
+% \setfield\FieldValue{#2}{#1}{}{}{#3}{\@@DriverFieldMode\@@DriverFieldFree\@@DriverFieldAuto}{}{\@@DriverFieldDefault}}%
+ \processcommalist[#4]\docommand
+ \else
+ \writestatus\m!fields{pass values too}%
+ \fi}
+
+\def\definesubfield
+ {\dotripleempty\dodefinesubfield}
+
+\def\dodefinesubfield[#1][#2][#3]% for the moment only radio ones
+ {\ifsecondargument
+ \def\docommand##1%
+ {\getfield{##1}%
+ \ifx\@@DriverFieldType\empty
+ \writestatus\m!fields{unknown field ##1}% to do
+ \else
+ \doifsomething{#2}
+ {\edef\@@DriverFieldGroup{#2}}%
+ \doifelsenothing{#3}
+ {\definedefaultsymbols
+ \def\@@DriverFieldValues{defaultyes}}
+ {\def\@@DriverFieldValues{#3}}%
+ \changefield{##1}%
+ \fi}%
+ \processcommalist[#1]\docommand
+ \else
+ \writestatus\m!fields{pass fieldname, setupgroup, values and default}%
+ \fi}
+
+\def\doclonefield[#1][#2][#3][#4]% parent children setupgroup values
+ {\ifsecondargument
+ \getfield{#1}%
+\iftrialtypesetting\else
+ \ifx\@@DriverFieldType\empty
+ \writestatus\m!fields{unknown field #1}%
+ \else
+ \let\@@DriverFieldMode\fieldparentmode
+ %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}%
+ \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}%
+ \processcommalist[#2]\docommand
+ \changefield{#1}%
+ \let\@@DriverFieldAutoParent\@@DriverFieldAuto
+ \def\@@DriverFieldParent{#1}%
+ \let\@@DriverFieldKids\empty
+ \let\@@DriverFieldRoot\empty
+ \let\@@DriverFieldMode\fieldchildmode
+ \def\@@DriverFieldFree{0}%
+ \def\@@DriverFieldAuto{0}%
+ \doifsomething{#3}{\edef\@@DriverFieldGroup{#3}}%
+ \doifsomething{#4}{\edef\@@DriverFieldValues{#4}}%
+ \def\docommand##1%
+ {\ifcase\@@DriverFieldAutoParent\else
+ \setmainfieldkid{\@@DriverFieldParent}{##1}%
+ \fi
+ \changefield{##1}}%
+ \processcommalist[#2]\docommand
+ \fi
+\fi
+ \else
+ \writestatus\m!fields{pass parent field and clones}%
+ \fi}
+
+\def\clonefield
+ {\doquadrupleempty\doclonefield}
+
+\def\docopyfield[#1][#2]% parent children
+ {\ifsecondargument
+ \getfield{#1}%
+\iftrialtypesetting\else
+ \ifx\@@DriverFieldType\empty
+ \writestatus\m!fields{unknown field #1}%
+ \else
+ \let\@@DriverFieldMode\fieldparentmode
+ %\def\docommand##1{\addtocommalist{##1}\@@DriverFieldKids}%
+ \def\docommand##1{\appendtocommalist{##1}\@@DriverFieldKids}%
+ \processcommalist[#2]\docommand
+ \changefield{#1}%
+ \let\@@DriverFieldAutoParent\@@DriverFieldAuto
+ \def\@@DriverFieldParent{#1}%
+ \let\@@DriverFieldKids\empty
+ \let\@@DriverFieldRoot\empty
+ \let\@@DriverFieldMode\fieldcopymode
+ \def\@@DriverFieldFree{0}%
+ \def\@@DriverFieldAuto{0}%
+ \def\docommand##1%
+ {\ifcase\@@DriverFieldAutoParent\else
+ \setmainfieldkid{\@@DriverFieldParent}{##1}%
+ \fi
+ \changefield{##1}}%
+ \processcommalist[#2]\docommand
+ \fi
+\fi
+ \else
+ \writestatus\m!fields{pass parent field and copies}%
+ \fi}
+
+\def\copyfield{\dodoubleempty\docopyfield}
+
+\unexpanded\def\field {\dotripleempty\dofield[\dohandlefield]}
+\unexpanded\def\fitfield{\dotripleempty\dofield[\dohandlefitfield]}
+
+\def\dofield[#1][#2][#3]%
+ {\iffirstargument
+ \bgroup
+ \getfield{#2}%
+ \ifsecondargument
+ \def\@@DriverFieldLabel{#3}%
+ \else
+ \let\@@DriverFieldLabel\@@DriverFieldName
+ \fi
+ \ifx\@@DriverFieldType\empty
+ \writestatus\m!fields{unknown field #2}%
+ \else\ifcase\@@DriverFieldFree\relax
+ \doifdefinedelse{\strippedcsname\setupfield\@@DriverFieldGroup}
+ {\let\dosetupfield=#1\getvalue{\strippedcsname\setupfield\@@DriverFieldGroup}}
+ {#1[\@@DriverFieldName][\v!label,\v!frame,\v!horizontal][][][]}%
+\iftrialtypesetting\else
+ \def\@@DriverFieldFree{1}%
+ \changefield{#2}%
+\fi
+ \else\ifcase\@@DriverFieldAuto\relax
+ % \writestatus\m!fields{field #2 already typeset}%
+ \else
+ % \writestatus\m!fields{field #2 automatically copied}%
+ \nextsystemfield
+ \copyfield[\@@DriverFieldName][\currentsystemfield]%
+ \dotripleempty\dofield[#1][\currentsystemfield][#3]% get the if's right
+ \fi\fi\fi
+ \egroup
+ \fi}
+
+\def\typesetfield
+ {\useJSscripts[fld]%
+ \ifx\@@DriverFieldRoot\empty \else
+ \let\@@SavedFieldName\@@DriverFieldName
+ \getfield\@@DriverFieldRoot
+ \ifcase\@@DriverFieldFree\relax
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetrecord
+\iftrialtypesetting\else
+ \def\@@DriverFieldFree{1}%
+ \changefield\@@DriverFieldName
+\fi
+ \fi
+ \getfield\@@SavedFieldName
+ \fi
+ \ifx\@@DriverFieldKids\empty
+ \donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \let\@@DriverFieldParent\@@DriverFieldName
+ %\addtocommalist\@@DriverFieldParent\@@DriverFieldKids
+ \appendtocommalist\@@DriverFieldParent\@@DriverFieldKids
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetfield
+ \let\@@DriverFieldMode\fieldchildmode
+ \fi
+ \dosetfieldstatus\@@DriverFieldMode\@@DriverFieldParent\@@DriverFieldKids\@@DriverFieldRoot
+ \dopresetfield}
+
+\def\dopresetfield
+ {\iftrialtypesetting\else\iflocation\getvalue{preset\@@DriverFieldType field}\fi\fi}
+
+\def\dopresetrecord
+ {\iftrialtypesetting\else\iflocation\getvalue{preset\@@DriverFieldType record}\fi\fi}
+
+\def\dodefinethefieldset[#1][#2]%
+ {\dodefinefieldset{#1}{#2}}
+
+\def\definefieldset%
+ {\dodoubleargument\dodefinethefieldset}
+
+\def\normaldodosetupfield[#1][#2][#3][#4][#5]%
+ {\doifdefinedelse{\strippedcsname\setupfield#1}
+ {\pushmacro\dosetupfield
+ \def\dosetupfield[##1][##2][##3][##4][##5]%
+ {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][##2,#2][##3,#3][##4,#4][##5,#5]}}%
+ \getvalue{\strippedcsname\setupfield#1}%
+ \popmacro\dosetupfield}
+ {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][#2][#3][#4][#5]}}}
+
+\let\dodosetupfield\normaldodosetupfield
+
+\def\donosetupfield[#1][#2][#3][#4][#5]%
+ {\setvalue{\strippedcsname\setupfield#1}{\dosetupfield[#1][#2][#3][#4][#5]}}
+
+\def\dosetupfield[#1][#2][#3][#4][#5]%
+ {\iffifthargument
+ \def\docommand##1{\dodosetupfield[##1][#2][#3][#4][#5]}%
+ \processcommalist[#1]\docommand
+ \else\ifthirdargument
+ \def\docommand##1{\dodosetupfield[##1][#2][][][#3]}%
+ \processcommalist[#1]\docommand
+ \else\ifsecondargument
+ \doifelse{#2}\v!reset
+ {\def\docommand##1{\donosetupfield[#1][][][][]}}
+ {\def\docommand##1{\dodosetupfield[##1][][][][#2]}}%
+ \processcommalist[#1]\docommand
+ \else\iffirstargument
+ \def\docommand##1{\dodosetupfield[##1][][][][]}%
+ \processcommalist[#1]\docommand
+ \else
+ \writestatus\m!fields{provide either 1, 2, 3 or 5 arguments}%
+ \fi\fi\fi\fi}
+
+\def\setupfield
+ {\doquintupleempty\dosetupfield}
+
+\def\dosetupfields[#1][#2][#3][#4]%
+ {\ifsecondargument
+ \def\dodosetupfield[##1][##2][##3][##4][##5]%
+ {\doifdefinedelse{\strippedcsname\setupfield##1}
+ {\def\dosetupfield[####1][####2][####3][####4][####5]%
+ {\setvalue{\strippedcsname\setupfield##1}{\dosetupfield[##1][#1,####2,##2][#2,####3,##3][#3,####4,##4][#4,####5,##5]}}%
+ \getvalue{\strippedcsname\setupfield##1}}
+ {\setvalue{\strippedcsname\setupfield##1}{\dosetupfield[##1][#1,##2][#2,##3][#3,##4][#4,##5]}}}%
+ \else\iffirstargument
+ \doifelse{#1}\v!reset
+ {\resetfields}
+ {\setupfields[][][][#1]}% checken
+ \else
+ \writestatus\m!fields{provide either 1 or 4 arguments}%
+ \fi\fi}
+
+\def\setupfields
+ {\doquadrupleempty\dosetupfields}
+
+\def\resetfields
+ {\let\dodosetupfield\normaldodosetupfield}
+
+% \setupfields[\v!reset]
+
+% opties: veld, label, kader, vertikaal/horizontaal
+
+\newif\ifShowFieldLabel
+\newif\ifShowFieldFrame
+\newif\ifVerticalField
+\newif\ifHorizontalField
+
+% way to slow/complicated, we need some simple alternative
+% as well
+
+\def\dohandlefield[#1][#2][#3][#4][#5]%
+ {\presetlocalframed[\??fd]%
+ \processallactionsinset
+ [#2]
+ [ \v!reset=>\ShowFieldLabelfalse\ShowFieldFramefalse
+ \HorizontalFieldfalse\VerticalFieldfalse,
+ \v!label=>\ShowFieldLabeltrue,
+ \v!frame=>\ShowFieldFrametrue,
+ \v!horizontal=>\HorizontalFieldtrue,
+ \v!vertical=>\VerticalFieldtrue]%
+ \ifVerticalField
+ \getparameters[\??fd]
+ [\c!distance=\!!zeropoint,\c!inbetween=\vskip\@@localoffset,
+ \c!align=\v!right,\c!width=20em]%
+ \else\ifHorizontalField
+ \getparameters[\??fd]
+ [\c!distance=\@@localoffset,\c!inbetween=,\c!align=\c!left,
+ \c!height=10ex]%
+ \else
+ \getparameters[\??fd]
+ [\c!distance=\!!zeropoint,\c!inbetween=,\c!align=\c!left]%
+ \fi\fi
+ \getparameters[\??fd]
+ [\c!n=,\c!before=,\c!after=\vss,\c!style=,\c!color=,#3]%
+ \reshapeframeboxfalse % else ugly spacing
+ \ifShowFieldFrame
+ \localframed[\??fd][\c!strut=\v!no,\c!align=]\bgroup
+ \else
+ \vbox\bgroup
+ \fi
+ \dontcomplain
+ \ifShowFieldLabel
+ \setbox0\hbox
+ {\reshapeframeboxtrue % else wrong dimensions
+ \framed
+ [\c!style=,\c!color=,\c!align=\c!right,#4]
+ {\@@DriverFieldLabel}}%
+ \fi
+ \setbox2\hbox
+ {\reshapeframeboxtrue % else wrong dimensions
+ \ifVerticalField
+ \setupframed[\c!height=6ex,\c!width=\hsize]%
+ \else\ifHorizontalField
+ \setupframed[\c!height=\vsize,\c!width=20em]%
+ \else
+ \setupframed[\c!height=2cm,\c!width=2cm]%
+ \fi\fi
+ \framed
+ [\c!align=\v!right,\c!strut=\v!no,#5]
+ {\getparameters
+ [\??fd]
+ [\c!color=,\c!style=,\c!align=\v!right,\c!option=,
+ \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
+ \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
+ \c!focusin=,\c!focusout=,
+ \c!fieldoffset=\!!zeropoint,\c!fieldbackgroundcolor=,
+ \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5]%
+ \scratchdimen\framedwidth \edef\@@DriverFieldWidth {\the\scratchdimen}%
+ \scratchdimen\framedheight\edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \vfill
+ \hbox{\lower\@@fdfieldoffset\hbox{\typesetfield}}
+ \vss}}%
+ \ifShowFieldLabel
+ \ifVerticalField
+ \vbox
+ {\copy0
+ \@@fdinbetween
+ \copy2}%
+ \else
+ \hbox
+ {\vbox \ifdim\ht2>\ht0 to \ht2 \fi
+ {\@@fdbefore
+ \copy0
+ \@@fdafter}%
+ \hskip\@@fddistance
+ \vbox \ifdim\ht0>\ht2 to \ht0 \fi
+ {\@@fdbefore
+ \box2
+ \@@fdafter}}%
+ \fi
+ \else
+ \box2
+ \fi
+ \egroup}
+
+\chardef\fitfieldmode\plusone % 3 = best
+
+\def\dohandlefitfield[#1][#2][#3][#4][#5]% alleen check
+ {\presetlocalframed[\??fd]%
+ \localframed
+ [\??fd]
+ [\c!n=1024, % beware: weblink plug in truncates
+ \c!strut=\v!no,\c!color=,\c!style=,\c!option=,
+ \c!clickin=,\c!clickout=,\c!regionin=,\c!regionout=,
+ \c!focusin=,\c!focusout=,
+ \c!afterkey=,\c!format=,\c!validate=,\c!calculate=,
+ \c!fieldoffset=\!!zeropoint,\c!fieldbackgroundcolor=,
+ \c!fieldframecolor=,\c!fieldlayer=\@@iafieldlayer,#5,\c!align=]
+ {\dogetcommacommandelement1\from\@@DriverFieldValues\to\@@DriverFieldValue
+ \ifx\@@DriverFieldValue\empty
+ \let\@@DriverFieldValue\@@DriverFieldDefault
+ \fi
+ \dopresetfieldsymbol\@@DriverFieldValue
+ \setbox\scratchbox\hbox{\dogetfieldsymbol\@@DriverFieldValue}%
+ \scratchdimen\wd\scratchbox \edef\@@DriverFieldWidth {\the\scratchdimen}%
+ \scratchdimen\ht\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \ifcase\fitfieldmode
+ \typesetfield
+ \or % 1 = ignore depth (original, assumed no depth, actually a bug)
+ \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
+ \or % 2 = add depth to height, but no depth in result
+ \advance\scratchdimen\dp\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \vbox to \ht\scratchbox{\vfill\hbox to \wd\scratchbox{\typesetfield\hfill}\vss}%
+ \or % 3 = add depth to height, and apply depth to result
+ \advance\scratchdimen\dp\scratchbox \edef\@@DriverFieldHeight{\the\scratchdimen}%
+ \hbox to \wd\scratchbox{\lower\dp\scratchbox\hbox{\typesetfield}\hfill}%
+ \fi}}
+
+%D Common stuff
+
+\newcounter\nofsystemfields
+
+\def\nextsystemfield
+ {\doglobal\increment\nofsystemfields
+ \def\currentsystemfield{sys::\nofsystemfields}}
+
+%D An example:
+
+\def\fillinfield
+ {\dosingleempty\dofillinfield}
+
+\def\dofillinfield[#1]#2%
+ {\dontleavehmode
+ \hbox
+ {\forgetall
+ \setupfields[\v!reset]%
+ \nextsystemfield
+ \useJSscripts[ans]%
+ \doifelsenothing{#1}
+ {\def\therightanswer{#2}}
+ {\def\therightanswer{#1}}%
+ \setbox0\hbox{#2}%
+ \setbox2\hbox{\therightanswer}%
+ \dimen0=\ifdim\wd0>\wd2 \wd0 \else \wd2 \fi
+ \advance\dimen0 .2em
+ \definefield
+ [\currentsystemfield][line][systemfield]%
+ \setupfield
+ [systemfield]
+ [\c!n=1024, % beware: weblink plugin truncates
+ \c!location=\v!low,\c!strut=\v!yes,\c!fieldoffset=0pt,
+ \c!height=1.2\openlineheight,\c!width=\dimen0,\c!offset=\v!overlay,
+ \c!style=,\c!align=\v!middle,\c!frame=\v!off,
+ \c!color=red,\c!fieldbackgroundcolor=\s!white,\c!fieldframecolor=blue,
+ \c!validate=JS(Check_Answer{\currentsystemfield,\therightanswer})]%
+ \switchtobodyfont
+ [\c!small]%
+ \hbox to \wd0
+ {\copy0\hskip-\wd0\hss\field[\currentsystemfield]\hss}}}
+
+%D and another one:
+
+\def\tooltip
+ {\dosingleempty\dotooltip}
+
+\def\dotooltip[#1]#2#3%
+ {\bgroup
+ \setupfields[\v!reset]%
+ \useJSscripts[fld]%
+ \setbox0\hbox
+ {\dontcomplain
+ \nextsystemfield
+ \setbox0\hbox{#2}%
+ \definesymbol
+ [\currentsystemfield:txt]
+ [{\inframed[\c!frame=\v!off,\c!background=\v!screen]{#3}}]%
+ \setbox2\hbox{\symbol[\currentsystemfield:txt]}%
+ \definefield
+ [\currentsystemfield:txt][check]
+ [dummy][\currentsystemfield:txt][\currentsystemfield:txt]%
+ \setupfield
+ [dummy]
+ [\c!frame=\v!off,
+ \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
+ \c!option=\v!hidden]%
+ \hbox to \zeropoint
+ {\dimen0\wd2\advance\dimen0 -\wd0
+ \doifelse{#1}\v!left
+ {\hskip-\dimen0}
+ {\doif{#1}\v!middle
+ {\hskip-.5\dimen0}}%
+ \lower\openlineheight\hbox to \zeropoint
+ {\fitfield[\currentsystemfield:txt]}}%
+ \dimen0=\ifdim\wd0=\zeropoint 3em\else\wd0\fi
+ \definesymbol
+ [\currentsystemfield:but]
+ [{\framed[\c!height=2ex,\c!width=\dimen0,\c!frame=\v!off]{}}]%
+ \definefield
+ [\currentsystemfield:but][push]
+ [dummy][\currentsystemfield:but][\currentsystemfield:but]%
+ \setupfield
+ [dummy]
+ [\c!frame=\v!off,
+ \c!option=,
+ \c!regionin=JS(Vide_Field{\currentsystemfield:txt}),
+ \c!regionout=JS(Hide_Field{\currentsystemfield:txt}),
+ \c!fieldlayer=\@@iafieldlayer]%
+ \lower2ex\hbox to \zeropoint
+ {\fitfield[\currentsystemfield:but]}%
+ #2}%
+ \ht0\strutht\dp0\strutdp\box0
+ \egroup}
+
+%D And one more:
+
+\def\definefieldstack
+ {\dotripleargument\dodefinefieldstack}
+
+\def\dodefinefieldstack[#1][#2][#3]% name, symbols, settings
+ {\doifundefined{fieldstack:#1}
+ {\setgvalue{fieldstack:#1}{\dodofieldstack[#1][#2][#3]}}}
+
+\def\dodofieldstack[#1][#2][#3]% start=n, 0 == leeg
+ {\bgroup
+ \getparameters[\??fd][\c!start=1,#3]%
+ \setupfields[\v!reset]%
+ \definesymbol[\v!empty][]%
+ \useJSscripts[fld][FieldStack]%
+ \newcounter\stackedfieldnumber
+ \def\dododofieldstack##1%
+ {\increment\stackedfieldnumber
+ \ifnum\stackedfieldnumber=\@@fdstart\relax
+ \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!empty][##1]%
+ \else
+ \definefield[#1:\stackedfieldnumber][check][#1][##1,\v!empty][\v!empty]%
+ \fi}%
+ \processcommalist[#2]\dododofieldstack
+ \setupfield[#1][\v!reset]% added
+ \setupfield[#1][\c!option=\v!readonly,#3]% #3 swapped
+ \newcounter\stackedfieldnumber
+ \def\dododofieldstack##1%
+ {\doglobal\increment\stackedfieldnumber
+ \fitfield[#1:\stackedfieldnumber]\egroup\bgroup}%
+ \startoverlay
+ \bgroup
+ \globalprocesscommalist[#2]\dododofieldstack
+ \egroup
+ \stopoverlay
+ \egroup}
+
+\def\dofieldstack[#1][#2][#3]%
+ {\ifsecondargument
+ \dodefinefieldstack[#1][#2][#3]\fieldstack[#1]%
+ \else
+ \getvalue{fieldstack:#1}\setgvalue{fieldstack:#1}{[#1]}%
+ \fi}
+
+\def\fieldstack
+ {\dotripleempty\dofieldstack}
+
+%D When submitting a form, we need to tell the driver module
+%D that we want \FDF\ or \HTML.
+
+\def\setupforms
+ {\dodoubleargument\getparameters[\??fr]}
+
+\def\checksubmitform#1%
+ {\setsubmitoutputformat\@@frmethod}
+
+\setexecutecommandcheck {submitform} \checksubmitform
+
+\setupforms
+ [\c!method=HTML]
+
+\protect \endinput
diff --git a/tex/context/base/core-fnt.tex b/tex/context/base/core-fnt.mkii
index e6f7fada4..9bc2a66f5 100644
--- a/tex/context/base/core-fnt.tex
+++ b/tex/context/base/core-fnt.mkii
@@ -2,7 +2,7 @@
%D [ file=core-fnt,
%D version=1995.10.10,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Font Support,
+%D subtitle=Fonts,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Font Support}
+\writestatus{loading}{ConTeXt Core Macros / Fonts}
\unprotect
diff --git a/tex/context/base/core-fnt.mkiv b/tex/context/base/core-fnt.mkiv
new file mode 100644
index 000000000..323183712
--- /dev/null
+++ b/tex/context/base/core-fnt.mkiv
@@ -0,0 +1,498 @@
+%D \module
+%D [ file=core-fnt,
+%D version=1995.10.10,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Fonts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Fonts}
+
+\unprotect
+
+%D \macros
+%D {compound}
+%D
+%D We will overload the already active \type {|} so we have
+%D to save its meaning in order to be able to use this handy
+%D macro.
+%D
+%D \starttyping
+%D so test\compound{}test can be used instead of test||test
+%D \stoptyping
+
+\bgroup \catcode`\|=\@@active \gdef\compound#1{|#1|} \egroup
+
+%D Here we hook some code into the clean up mechanism needed
+%D for verbatim data.
+
+\appendtoks
+ \disablecompoundcharacters
+ \disablediscretionaries
+\to \everycleanupfeatures
+
+%D \macros
+%D {stretched}
+%D
+%D Stretching characters in a word is a sort of typographical
+%D murder. Nevertheless we support this manipulation for use in
+%D for instance titles.
+%D
+%D \starttyping
+%D \hbox to 5cm{\stretched{murder}}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D or
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D \showsetup{stretched}
+
+\def\stretched#1%
+ {\ifvmode\hbox to \hsize\else\ifinner\else\hbox\fi\fi
+ \bgroup\processtokens\relax\hss\relax{\hss\hss}{#1}\egroup}
+
+%D \startbuffer
+%D \stretched{Unknown Box}
+%D \hbox to .5\hsize{\stretched{A Horizontal Box}}
+%D \vbox to 2cm{\stretched{A Vertical Box}}
+%D \hbox to 3cm{\stretched{sp{\'e}c{\`\i}{\"a}l}}
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D The first line of this macros takes care of boxing. Normally
+%D one will use an \type{\hbox} specification. The last line
+%D shows how special characters should be passed.
+%D
+%D \typebuffer
+
+%D \macros
+%D {stretchednormalcase, stretcheduppercase, stretchedlowercase}
+%D
+%D A convenient alternative is:
+%D
+%D \starttyping
+%D \stretcheduppercase{Is this what you like?}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D this one uses fixed skips and kerns.
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D The default skip can be set with:
+
+% \def\stretchedspacefactor{4}
+% \def\stretchedspaceamount{.25em}
+%
+% \unexpanded\def\stretcheduppercase#1%
+% {\bgroup
+% \the\everyuppercase
+% \uppercase{\def\textstring{#1}}%
+% \ifdim\stretchedspaceamount>\zeropoint
+% \def\textkern%
+% {\kern\stretchedspaceamount}%
+% \def\textskip%
+% {\scratchdimen=\stretchedspaceamount
+% \hskip\stretchedspacefactor\scratchdimen}%
+% \@EA\processtokens\@EA\relax\@EA\textkern\@EA\relax\@EA
+% \textskip\@EA{\textstring}%
+% \else
+% \textstring
+% \fi
+% \egroup}
+
+%D Given the following settings, the space is 1em by default:
+
+\def\stretchedspacefactor{4}
+\def\stretchedspaceamount{.25em}
+\def\stretchedbreaktokens{.@/}
+
+\unexpanded\def\stretchednormalcase
+ {\stretchedsomecase\firstofoneargument}
+
+\unexpanded\def\stretcheduppercase
+ {\stretchedsomecase{\the\everyuppercase\uppercase}}
+
+\unexpanded\def\stretchedlowercase
+ {\stretchedsomecase{\the\everylowercase\lowercase}}
+
+\def\stretchedsomecase#1#2%
+ {\bgroup
+ #1{\def\textstring{#2}}%
+ \ifdim\stretchedspaceamount=\zeropoint
+ \textstring
+ \else
+ \def\textkern##1%
+ {% beware: ##1 may not be \box\somebox -)
+ \determinemidwordbreak{##1}{\stretchedbreaktokens}%
+ \kern\stretchedspaceamount##1\domidwordbreak}%
+ \def\textskip
+ {\scratchdimen\stretchedspaceamount
+ \hskip\stretchedspacefactor\scratchdimen}%
+ \@EA\processtokens\@EA\relax\@EA\textkern\@EA\relax\@EA
+ \textskip\@EA{\textstring}%
+ \fi
+ \egroup}
+
+%D An auxiliary macro, see for usage \type {\stretcheduppercase}.
+
+\let\domidwordbreak\relax
+
+\def\setmidwordbreaktoken#1%
+ {\sfcode`#1=5000\relax}
+
+\def\determinemidwordbreak#1#2%
+ {\edef\midwordbreaktokens{#2}%
+ \ifx\midwordbreaktokens\empty
+ \global\let\domidwordbreak\relax
+ \else
+ \setbox\scratchbox\hbox
+ {\expandafter\handletokens\midwordbreaktokens\with\setmidwordbreaktoken
+ a\space \!!dimena\lastskip
+ #1\space\!!dimenb\lastskip \relax % needed
+ \ifdim\!!dimena=\!!dimenb
+ \globallet\domidwordbreak\relax
+ \else
+ \globallet\domidwordbreak\allowbreak
+ \fi}%
+ \fi}
+
+%D \macros
+%D {underbar,underbars,
+%D overbar,overbars,
+%D overstrike,overstrikes,
+%D setupunderbar}
+%D
+%D In the rare case that we need undelined words, for instance
+%D because all font alternatives are already in use, one can
+%D use \type{\underbar} and \type{\overstrike} and their plural
+%D forms.
+%D
+%D \startbuffer
+%D \underbars{drawing \underbar{bars} under words is a typewriter leftover}
+%D \overstrikes{striking words makes them \overstrike{unreadable} but
+%D sometimes even \overbar{top lines} come into view.}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D The next macros are derived from the \PLAIN\ \TEX\ one, but
+%D also supports nesting. The \type{$} keeps us in horizontal
+%D mode and at the same time applies grouping.
+%D
+%D \showsetup{underbar}
+%D \showsetup{underbars}
+%D \showsetup{overbar}
+%D \showsetup{overbars}
+%D \showsetup{overstrike}
+%D \showsetup{overstrikes}
+%D
+%D Although underlining is ill advised, we permit some
+%D alternatives, that can be set up by:
+%D
+%D \showsetup{setupunderbar}
+%D
+%D The alternatives show up as
+%D {\setupunderbar [alternative=a]\underbar{alternative a}},
+%D {\setupunderbar [alternative=b]\underbar{alternative b}},
+%D {\setupunderbar [alternative=c]\underbar{alternative c}}
+%D and
+%D {\setupunderbar [rulethickness=1pt]\underbar{1pt width}},
+%D {\setupunderbar [rulethickness=2pt]\underbar{2pt width}},
+%D or whatever. Because \type{\overstrike} uses the same
+%D method, the settings also apply to that macro.
+
+\newcount\underbarlevel
+
+\def\underbarmethoda#1#2#3% RULE
+ {\hbox to #1{\vrule\!!width#1\!!height#2\!!depth#3}}
+
+\def\underbarmethodb#1#2#3% DASH
+ {\hbox to #1
+ {\hskip-.25em
+ \xleaders
+ \hbox{\hskip.25em\vrule\!!width.25em\!!height#2\!!depth#3}
+ \hfil}}
+
+\def\underbarmethodc#1#2#3% PERIOD
+ {\hbox to #1
+ {\dimen4=#3
+ \advance\dimen4 .2ex
+ \hskip-.25em
+ \xleaders
+ \hbox{\hskip.25em\lower\dimen4\hbox{.}}
+ \hfil}}
+
+\def\dododounderbar#1#2#3%
+ {\startmathmode
+ \setbox0\hbox{#3}%
+ \setbox2\hbox{\color[\@@onrulecolor]{\getvalue{underbarmethod\@@onalternative}{\wd0}{#1}{#2}}}%
+ \wd0\zeropoint
+ \ht2\ht0
+ \dp2\dp0
+ \box0\box2
+ \stopmathmode}
+
+\unexpanded\def\dodounderbar#1%
+ {\bgroup
+ \dimen0=\@@onbottomoffset
+ \dimen0=\underbarlevel\dimen0
+ \ifdone \else
+ \advance\dimen0 -\strutht
+ \fi
+ \dimen2\dimen0
+ \advance\dimen2 \@@onrulethickness
+ \dododounderbar{-\dimen0}{\dimen2}{#1}%
+ \egroup}
+
+\def\betweenunderbarwords
+ {\bgroup
+ \setbox0\hbox{\dodounderbar{\hskip\interwordspace}}%
+ \nobreak
+ \hskip\zeropoint\!!minus\interwordshrink
+ \discretionary{}{}{\box0}%
+ \egroup}
+
+\def\betweenunderbarspaces
+ {\hskip\currentspaceskip}
+
+% \unexpanded\def\dounderbar#1#2%
+% {\let\betweenisolatedwords#1%
+% \processisolatedwords{#2}\dodounderbar
+% \egroup}
+
+\unexpanded\def\underbar
+ {\bgroup
+ \advance\underbarlevel\plusone
+ \donetrue
+ \dounderbar\betweenunderbarwords}
+
+\unexpanded\def\dounderbar#1%
+ {\let\betweenisolatedwords#1%
+ \dosingleempty\redounderbar}
+
+\unexpanded\def\redounderbar[#1]#2%
+ {\iffirstargument\setupunderbar[#1]\fi
+ \processisolatedwords{#2}\dodounderbar
+ \egroup}
+
+\unexpanded\def\underbars
+ {\bgroup
+ \advance\underbarlevel\plusone
+ \donetrue
+ \dounderbar\betweenunderbarspaces}
+
+\unexpanded\def\overbar
+ {\bgroup
+ \advance\underbarlevel\minusone
+ \donefalse
+ \dounderbar\betweenunderbarwords}
+
+\unexpanded\def\overbars
+ {\bgroup
+ \advance\underbarlevel\minusone
+ \donefalse
+ \dounderbar\betweenunderbarspaces}
+
+\def\dooverstrike#1%
+ {\bgroup
+ \dimen0=\@@ontopoffset
+ \dimen2=\dimen0
+ \advance\dimen2 \@@onrulethickness
+ \dododounderbar{\dimen2}{-\dimen0}{#1}%
+ \egroup}
+
+\def\betweenoverstrikewords
+ {\bgroup
+ \setbox0\hbox{\dooverstrike{\hskip\interwordspace}}%
+ \nobreak
+ \hskip\zeropoint\!!minus\interwordshrink
+ \discretionary{}{}{\box0}%
+ \egroup}
+
+\unexpanded\def\overstrike#1%
+ {\bgroup
+ \let\betweenisolatedwords\betweenoverstrikewords
+ \processisolatedwords{#1}\dooverstrike
+ \egroup}
+
+\unexpanded\def\overstrikes#1%
+ {\bgroup
+ \processisolatedwords{#1}\dooverstrike
+ \egroup}
+
+\def\underbarparameter#1{\csname\??on#1\csname}
+
+\def\setupunderbar
+ {\dodoubleargument\getparameters[\??on]}
+
+%D \macros
+%D {shiftedword, shiftedwords}
+%D
+%D Used as \type {\shiftedwords {10pt} {some text}} this macro will
+%D move
+
+% \def\shiftedword#1% #2%
+% {\raise#1\hbox} % {#2}} % officially: {\ifdim#1>\zeropoint\raise\else\lower\fi#1\hbox{#2}}
+
+% \def\shiftedwords#1#2%
+% {\processisolatedwords{#2}{\shiftedword{#1}}}
+
+%D \macros
+%D {low, high, lohi, hilo}
+%D
+%D Although \TEX\ is pretty well aware of super- and
+%D subscripts, its mechanism is mainly tuned for math mode.
+%D The next few commands take care of script texts both modes.
+%D
+%D \startbuffer
+%D The higher\high{one goes} the lower\low{one drops}, or\lohi{yes}{no}?
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Note the different placement of \type {\lohi}, where we
+%D need a bit more space. The implementation looks a bit
+%D fuzzy, since some \type {\fontdimen}'s are involved to
+%D determine the optimal placement.
+
+\def\dodohighlow
+ {\ifx\fontsize\empty
+ \ifmmode
+ \ifnum\fam<0 \tx \else \holamathfont \fi
+ \else
+ \tx
+ \fi
+ \else
+ \tx
+ \fi}
+
+\def\dohighlow#1#2#3#4#5% todo, named fontdimens
+ {\dontleavehmode
+ \bgroup
+ \scratchdimen\ifdim\fontexheight\textfont2=1ex #2\textfont2\else #3ex\fi
+ \advance\scratchdimen #4ex
+ \kern.1ex
+ \setbox\scratchbox\hbox{#1\scratchdimen\hbox{\dodohighlow#5}}%
+ \ht\scratchbox\strutheight
+ \dp\scratchbox\strutdepth
+ \box\scratchbox
+ \egroup}
+
+\unexpanded\def\high{\dohighlow\raise\mathsupnormal{.86}{0}}
+\unexpanded\def\low {\dohighlow\lower\mathsubnormal{.48}{0}}
+
+\unexpanded\def\lohi
+ {\dosingleempty\dolohi}
+
+\unexpanded\def\hilo
+ {\dosingleempty\dohilo}
+
+\def\dolohi[#1]#2#3%
+ {\dontleavehmode
+ \hbox
+ {\setbox4\hbox{\dohighlow\lower\mathsubnormal{.48}{.1}{#2}}%
+ \setbox6\hbox{\dohighlow\raise\mathsupnormal{.86}{.1}{#3}}%
+ \doif{#1}{\v!left}
+ {\ifdim\wd4<\wd6
+ \setbox4\hbox to \wd6{\hss\box4}%
+ \else
+ \setbox6\hbox to \wd4{\hss\box6}%
+ \fi}%
+ \ifdim\wd4<\wd6
+ \wd4=\zeropoint\box4\box6
+ \else
+ \wd6=\zeropoint\box6\box4
+ \fi}}
+
+\def\dohilo[#1]#2#3%
+ {\dolohi[#1]{#3}{#2}}
+
+%D You can provide an optional keyword \type {left}, in which
+%D case the super and subscripts will be aligned in a way that
+%D permits placement at the left of a word (which means that
+%D it will be right aligned).
+%D
+%D \startbuffer
+%D \lohi{aha}{ah} test \lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah} test \lohi[left]{aha}{ah} test
+%D \lohi{aha}{ah} test\lohi{aha}{ah} test
+%D \lohi[left]{aha}{ah}test \lohi[left]{aha}{ah}test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+
+%D \macros
+%D {setupinitial,placeinitial,checkinitial}
+%D
+%D {\em To be documented.}
+%D
+%D \starttyping
+%D \setupinitial[state=start] \placeinitial \input tufte
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D \def\bpar{\ifvmode\checkinitial\fi}
+%D \def\epar{\ifhmode\par\fi\checkinitial}
+%D \stoptyping
+
+% to do: more fine tuning
+
+\def\setupinitial
+ {\dodoubleempty\getparameters[\??dc]}
+
+\definefontsynonym[Initial][Regular] % prefered initial identifier
+\definefontsynonym[initial][Initial] % internal but accepted too
+
+\setupinitial
+ [\c!state=\v!stop,
+ \c!location=\v!text,
+ \c!n=3,
+ \c!distance=.125em,
+ \c!command=,
+ \s!font=initial]
+
+\def\AutoDroppedCapsCommand{\NiceDroppedCaps\@@dccommand\@@dcfont\@@dcdistance\@@dcn}%
+
+\def\placeinitial
+ {\doifelse\@@dclocation\v!margin{\chardef\DropMode\plusone}{\chardef\DropMode\zerocount}%
+ \doif \@@dcstate\v!start{\ifcase\@@dcn\else\AutoDroppedCaps\fi}}
+
+\let\checkinitial\CheckDroppedCaps
+
+%D This module has only a few setups:
+
+\setupunderbar
+ [\c!alternative=a,
+ \c!rulethickness=\linewidth,
+ \c!bottomoffset=1.5pt,
+ \c!topoffset=2.5pt,
+ \c!rulecolor=]
+
+\protect \endinput
diff --git a/tex/context/base/core-gen.tex b/tex/context/base/core-gen.tex
index aaaba84d1..b6ab2a208 100644
--- a/tex/context/base/core-gen.tex
+++ b/tex/context/base/core-gen.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / General}
+\writestatus{loading}{ConTeXt Core Macros / General}
\unprotect
@@ -60,79 +60,38 @@
%D {waarde groot}
%D \stoptyping
-\def\assigndimension#1#2#3#4#5% can be a skip
- {\processaction
- [#1]
- [ \v!small=>#2=#3\relax,
- \v!medium=>#2=#4\relax,
- \v!big=>#2=#5\relax,
- \v!none=>#2=\zeropoint,
- -\v!small=>#2=-#3\relax,
- -\v!medium=>#2=-#4\relax,
- -\v!big=>#2=-#5\relax,
- \s!unknown=>#2=#1\relax]}
-
-\def\assignalfadimension#1#2#3#4#5%
- {\processaction
- [#1]
- [ \v!small=>\edef#2{#3},
- \v!medium=>\edef#2{#4},
- \v!big=>\edef#2{#5},
- \v!none=>\edef#2{0},
- \s!unknown=>\edef#2{#1}]}
-
-%D De onderstaande implementatie is veel sneller, maar
-%D tegelijkertijd ook veel lelijker. Omdat we deze macro
-%D relatief weinig aanroepen laten we deze optimalisatie maar
-%D achterwege. Bovendien kunnen oplossingen als deze de
-%D hash||table aardig uitputten (\type {\doifdefined}).
-%D
-%D \starttyping
-%D \edef\@@dimension{@@dim}
-%D \edef\@@negdimension{\@@dimension-}
-%D
-%D \def\assigndimension#1#2#3#4#5%
-%D {\setvalue{\@@dimension \v!small }{#3}%
-%D \setvalue{\@@dimension \v!medium}{#4}%
-%D \setvalue{\@@dimension \v!big }{#5}%
-%D \setvalue{\@@dimension \v!none }{\!!zeropoint}%
-%D \setvalue{\@@negdimension\v!small }{-#3}%
-%D \setvalue{\@@negdimension\v!medium}{-#4}%
-%D \setvalue{\@@negdimension\v!big }{-#5}%
-%D \setvalue{\@@negdimension\v!none }{\!!zeropoint}%
-%D \doifdefinedelse{\@@dimension#1}
-%D {#2=\getvalue{\@@dimension#1}}
-%D {#2=#1}}
-%D \stoptyping
-%D
-%D Let's give this a try:
-
-\let\nopv!none \v!none
-\let\posv!big \v!big
-\let\posv!middle \v!medium
-\let\posv!small \v!small
-\edef\negv!big {-\v!big}
-\edef\negv!middle{-\v!medium}
-\edef\negv!small {-\v!small}
-
-\def\assigndimension#1#2#3#4#5%
- {\edef\!!stringa{#1}%
- #2=\ifx\!!stringa\nopv!none \zeropoint\else
- \ifx\!!stringa\posv!big #5\else
- \ifx\!!stringa\posv!middle #4\else
- \ifx\!!stringa\posv!small #3\else
- \ifx\!!stringa\negv!big -#5\else
- \ifx\!!stringa\negv!middle-#4\else
- \ifx\!!stringa\negv!small -#3\else
- #1\fi\fi\fi\fi\fi\fi\fi}
-
-\def\assignalfadimension#1#2#3#4#5%
- {\edef\!!stringa{#1}%
- \edef#2{\ifx\!!stringa\posv!big #5\else
- \ifx\!!stringa\posv!middle#4\else
- \ifx\!!stringa\posv!small #3\else
- \ifx\!!stringa\nopv!none 0\else
- #1\fi\fi\fi\fi}}
+% The third (optimized) version:
+
+\def\@ad@{@ad@}
+
+\setvalue{\@ad@ \v!none }{\zeropoint\gobblethreearguments}
+\setvalue{\@ad@ \v!big }{\thirdofthreearguments}
+\setvalue{\@ad@ \v!medium}{\secondofthreearguments}
+\setvalue{\@ad@ \v!small }{\firstofthreearguments}
+\setvalue{\@ad@-\v!big }{-\thirdofthreearguments}
+\setvalue{\@ad@-\v!medium}{-\secondofthreearguments}
+\setvalue{\@ad@-\v!small }{-\firstofthreearguments}
+
+\def\assigndimension#1#2% #3 #4 #5
+ {#2=\ifcsname\@ad@#1\endcsname
+ \csname\@ad@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi}
+
+\def\@aa@{@aa@}
+
+\setvalue{\@aa@\v!none }{0\gobblethreearguments}
+\setvalue{\@aa@\v!big }{\thirdofthreearguments}
+\setvalue{\@aa@\v!medium}{\secondofthreearguments}
+\setvalue{\@aa@\v!small }{\firstofthreearguments}
+
+\def\assignalfadimension#1#2#3#4#5% #3#4#5 are single digits
+ {\edef#2{\ifcsname\@aa@#1\endcsname
+ \csname\@aa@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi#3#4#5}}
%D \macros
%D {assignvalue}
@@ -162,22 +121,18 @@
%D
%D Hier doet \type{geen} dus niet mee.
-\def\assignvalue#1#2#3#4#5%
- {\processaction
- [#1]
- [ \v!small=>\edef#2{#3},
- \v!medium=>\edef#2{#4},
- \v!big=>\edef#2{#5},
- \s!unknown=>\edef#2{#1}]}
+\def\@av@{@av@}
-%D Or faster:
+\letvalue{\@av@\v!big }\thirdofthreearguments
+\letvalue{\@av@\v!medium}\secondofthreearguments
+\letvalue{\@av@\v!small }\firstofthreearguments
\def\assignvalue#1#2#3#4#5%
- {\edef\!!stringa{#1}%
- \edef#2{\ifx\!!stringa\posv!big #5\else
- \ifx\!!stringa\posv!middle#4\else
- \ifx\!!stringa\posv!small #3\else
- #1\fi\fi\fi}}
+ {\edef#2{\ifcsname\@av@#1\endcsname
+ \csname\@av@#1\expandafter\endcsname
+ \else
+ #1\expandafter\gobblethreearguments
+ \fi{#3}{#4}{#5}}}
%D \macros
%D {assignwidth}
@@ -200,11 +155,11 @@
\def\assignwidth#1#2#3#4%
{\doifelsenothing{#2}
- {\setbox0\hbox{#3}%
- #1\wd0}
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox}
{\doifinsetelse{#2}{\v!fit,\v!broad}
- {\setbox0=\hbox{#3}%
- #1\wd0
+ {\setbox\scratchbox\hbox{#3}%
+ #1\wd\scratchbox
\doif{#2}\v!broad{\advance#1 #4}}%
{#1=#2}}}%
diff --git a/tex/context/base/core-grd.tex b/tex/context/base/core-grd.tex
index 5db966455..249e2e430 100644
--- a/tex/context/base/core-grd.tex
+++ b/tex/context/base/core-grd.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Grid Snapping}
+\writestatus{loading}{ConTeXt Core Macros / Grid Snapping}
\unprotect
diff --git a/tex/context/base/core-inc.lua b/tex/context/base/core-inc.lua
index 1707c1b25..35370058d 100644
--- a/tex/context/base/core-inc.lua
+++ b/tex/context/base/core-inc.lua
@@ -33,63 +33,23 @@ The TeX-Lua mix is suboptimal. This has to do with the fact that we cannot
run TeX code from within Lua. Some more functionality will move to Lua.
]]--
-local texsprint, format = tex.sprint, string.format
+local texsprint, format, lower = tex.sprint, string.format, string.lower
-backends = backends or { }
-backends.pdf = backends.pdf or { }
+local ctxcatcodes = tex.ctxcatcodes
---~ function backends.pdf.startscaling(sx,sy)
---~ return nodes.pdfliteral(format("q %s 0 0 %s 0 0 cm",(sx ~= 0 and sx) or .0001,(sy ~= 0 and sy) or .0001))
---~ end
---~ function backends.pdf.stopscaling()
---~ return nodes.pdfliteral("%Q")
---~ end
-
-function backends.pdf.insertmovie(data)
- data = data or figures.current()
- local dr, du, ds = data.request, data.used, data.status
- local width, height, factor = du.width or dr.width, du.height or dr.height, number.dimenfactors.bp
- local options, actions = "", ""
- if dr["repeat"] then
- actions = actions .. "/Mode /Repeat "
- end
- if dr.controls then
- actions = actions .. "/ShowControls true "
- else
- actions = actions .. "/ShowControls false "
- end
- if dr.preview then
- options = options .. "/Poster true "
- end
- if actions ~= "" then
- actions= "/A <<" .. actions .. ">>"
- end
- texsprint(tex.ctxcatcodes, format(
- "\\doPDFannotation{%ssp}{%ssp}{/Subtype /Movie /Border [0 0 0] /T (movie %s) /Movie << /F (%s) /Aspect [%s %s] %s>> %s}",
- width, height, dr.label, du.foundname, factor * width, factor * height, options, actions
- ))
- return data
-end
-
---~ if node then do
---~ local n = node.new(0,0)
---~ local m = getmetatable(n)
---~ m.__concat = function(a,b)
---~ local t = node.slide(a)
---~ t.next, b.prev = b, t
---~ return a
---~ end
---~ node.free(n)
---~ end end
+local trace_figures = false trackers.register("figures.locating",function(v) trace_figures = v end)
--- some extra img functions ---
-function img.totable(i)
- local t = { }
- for _, v in ipairs(img.keys()) do
- t[v] = i[v]
+local imgkeys = img.keys()
+
+function img.totable(imgtable)
+ local result = { }
+ for k=1,#imgkeys do
+ local key = imgkeys[k]
+ result[key] = imgtable[key]
end
- return t
+ return result
end
function img.serialize(i)
@@ -124,7 +84,6 @@ figures.found = figures.found or { }
figures.suffixes = figures.suffixes or { }
figures.patterns = figures.patterns or { }
figures.boxnumber = figures.boxid or 0
-figures.trace = false
figures.defaultsearch = true
figures.defaultwidth = 0
figures.defaultheight = 0
@@ -226,7 +185,7 @@ function figures.setpaths(locationset,pathlist)
end
end
figures.paths, last_pathlist = t, pathlist
- if figures.trace then
+ if trace_figures then
logs.report("figures","locations: %s",last_locationset)
logs.report("figures","path list: %s",table.concat(figures.paths))
end
@@ -299,11 +258,13 @@ do
end
function figures.push(request)
- input.starttiming(figures)
+ statistics.starttiming(figures)
local figuredata = figures.new()
if request then
- local iv = interfaces.variables
- local w, h = tonumber(request.width), tonumber(request.height)
+ local iv = interfaces.variables
+ -- request.width/height are strings and are only used when no natural dimensions
+ -- can be determined; at some point the handlers might set them to numbers instead
+--~ local w, h = tonumber(request.width), tonumber(request.height)
request.page = math.max(tonumber(request.page) or 1,1)
request.size = img.check_size(request.size)
request.object = iv[request.object] == "yes"
@@ -312,8 +273,8 @@ do
request.cache = request.cache ~= "" and request.cache
request.prefix = request.prefix ~= "" and request.prefix
request.format = request.format ~= "" and request.format
- request.width = (w and w > 0) or false
- request.height = (h and h > 0) or false
+--~ request.width = (w and w > 0) or false
+--~ request.height = (h and h > 0) or false
table.merge(figuredata.request,request)
end
callstack[#callstack+1] = figuredata
@@ -322,7 +283,7 @@ do
function figures.pop()
figuredata = callstack[#callstack]
callstack[#callstack] = nil
- input.stoptiming(figures)
+ statistics.stoptiming(figures)
end
-- maybe move texsprint to tex
function figures.get(category,tag,default)
@@ -334,7 +295,7 @@ do
end
end
function figures.tprint(category,tag,default)
- texsprint(tex.ctxcatcodes,figures.get(category,tag,default))
+ texsprint(ctxcatcodes,figures.get(category,tag,default))
end
function figures.current()
return callstack[#callstack]
@@ -342,187 +303,180 @@ do
end
-do
-
- local function register(askedname,specification)
- if specification then
- local format = specification.format
- if format then
- local converter = figures.converters[format]
- if converter then
- local oldname = specification.fullname
- local newformat = "pdf" -- todo, other target than pdf
- local newpath = file.dirname(oldname)
- local newbase = file.replacesuffix(file.basename(oldname),newformat)
- local fc = specification.cache or figures.cachepaths.path
- if fc and fc ~= "" and fc ~= "." then
- newpath = fc
- end
- local subpath = specification.subpath or figures.cachepaths.subpath
- if subpath and subpath ~= "" and subpath ~= "." then
- newpath = newpath .. "/" .. subpath
- end
- local prefix = specification.prefix or figures.cachepaths.prefix
- if prefix and prefix ~= "" then
- newbase = prefix .. newbase
- end
- local newname = file.join(newpath,newbase)
- dir.makedirs(newpath)
- local oldtime = lfs.attributes(oldname,'modification') or 0
- local newtime = lfs.attributes(newname,'modification') or 0
- if oldtime > newtime then
- converter(oldname,newname)
- end
- if io.exists(newname) then
- specification.foundname = oldname
- specification.fullname = newname
- specification.prefix = prefix
- specification.subpath = subpath
- specification.converted = true
- format = newformat
- elseif io.exists(oldname) then
- specification.fullname = newname
- specification.converted = false
- end
+local function register(askedname,specification)
+ if specification then
+ local format = specification.format
+ if format then
+ local converter = figures.converters[format]
+ if converter then
+ local oldname = specification.fullname
+ local newformat = "pdf" -- todo, other target than pdf
+ local newpath = file.dirname(oldname)
+ local newbase = file.replacesuffix(file.basename(oldname),newformat)
+ local fc = specification.cache or figures.cachepaths.path
+ if fc and fc ~= "" and fc ~= "." then
+ newpath = fc
+ end
+ local subpath = specification.subpath or figures.cachepaths.subpath
+ if subpath and subpath ~= "" and subpath ~= "." then
+ newpath = newpath .. "/" .. subpath
+ end
+ local prefix = specification.prefix or figures.cachepaths.prefix
+ if prefix and prefix ~= "" then
+ newbase = prefix .. newbase
+ end
+ local newname = file.join(newpath,newbase)
+ dir.makedirs(newpath)
+ local oldtime = lfs.attributes(oldname,'modification') or 0
+ local newtime = lfs.attributes(newname,'modification') or 0
+ if oldtime > newtime then
+ converter(oldname,newname)
+ end
+ if io.exists(newname) then
+ specification.foundname = oldname
+ specification.fullname = newname
+ specification.prefix = prefix
+ specification.subpath = subpath
+ specification.converted = true
+ format = newformat
+ elseif io.exists(oldname) then
+ specification.fullname = newname
+ specification.converted = false
end
end
- specification.found = validtypes[format]
- if figures.trace then
+ end
+ local found = figures.suffixes[format] -- validtypes[format]
+ if not found then
+ specification.found = false
+ if trace_figures then
logs.report("figures","format not supported: %s",format)
end
else
- specification = { }
+ specification.found = true
+ if trace_figures then
+ if validtypes[format] then
+ logs.report("figures","format natively supported by backend: %s",format)
+ else
+ logs.report("figures","format supported by output file format: %s",format)
+ end
+ end
end
- specification.foundname = specification.foundname or specification.fullname
- figures.found[askedname] = specification
- return specification
+ else
+ specification = { }
end
+ specification.foundname = specification.foundname or specification.fullname
+ figures.found[askedname] = specification
+ return specification
+end
- local function locate(request) -- name, format, cache
- local askedname = input.clean_path(request.name)
- if figures.found[askedname] then
- return figures.found[askedname]
- end
- local askedpath= file.dirname(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
- if askedformat ~= "" then
- askedformat = askedformat:lower()
- local format = figures.suffixes[askedformat]
- if not format then
- for _, pattern in ipairs(figures.patterns) do
- if askedformat:find(pattern[1]) then
- format = pattern[2]
- break
- end
+local function locate(request) -- name, format, cache
+ local askedname = resolvers.clean_path(request.name)
+ if figures.found[askedname] then
+ return figures.found[askedname]
+ end
+ local askedpath= file.dirname(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
+ if askedformat ~= "" then
+ askedformat = lower(askedformat)
+ local format = figures.suffixes[askedformat]
+ if not format then
+ for _, pattern in ipairs(figures.patterns) do
+ if askedformat:find(pattern[1]) then
+ format = pattern[2]
+ break
end
end
- if format then
- local foundname = figures.exists(askedname,askedformat)
- if foundname then
- return register(askedname, {
+ end
+ if format then
+ local foundname = figures.exists(askedname,askedformat)
+ if foundname then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = askedname,
+ format = format,
+ cache = askedcache,
+ foundname = foundname,
+ })
+ end
+ end
+ if askedpath ~= "" then
+ -- path and type given, todo: strip pieces of path
+ if figures.exists(askedname,askedformat) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = askedname,
+ format = askedformat,
+ cache = askedcache,
+ })
+ end
+ else
+ -- type given
+ for _, path in ipairs(figures.paths) do
+ local check = path .. "/" .. askedname
+ if figures.exists(check,askedformat) then
+ return register(check, {
askedname = askedname,
- fullname = askedname,
- format = format,
+ fullname = check,
+ format = askedformat,
cache = askedcache,
- foundname = foundname,
})
end
end
- if askedpath ~= "" then
- -- path and type given, todo: strip pieces of path
- if figures.exists(askedname,askedformat) then
+ if figures.defaultsearch then
+ local check = resolvers.find_file(askedname)
+ if check and check ~= "" then
return register(askedname, {
askedname = askedname,
- fullname = askedname,
+ fullname = check,
format = askedformat,
cache = askedcache,
})
end
- else
- -- type given
- for _, path in ipairs(figures.paths) do
- local check = path .. "/" .. askedname
- if figures.exists(check,askedformat) then
- return register(check, {
- askedname = askedname,
- fullname = check,
- format = askedformat,
- cache = askedcache,
- })
- end
- end
- if figures.defaultsearch then
- local check = input.find_file(askedname)
- if check and check ~= "" then
- return register(askedname, {
- askedname = askedname,
- fullname = check,
- format = askedformat,
- cache = askedcache,
- })
- end
+ end
+ end
+ elseif askedpath ~= "" then
+ for _, format in ipairs(figures.order) do
+ local list = figures.formats[format].list or { format }
+ for _, suffix in ipairs(list) do
+ local check = file.addsuffix(askedname,suffix)
+ if figures.exists(check,format) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ })
end
end
- elseif askedpath ~= "" then
+ end
+ else
+ if figures.prefer_quality then
for _, format in ipairs(figures.order) do
local list = figures.formats[format].list or { format }
for _, suffix in ipairs(list) do
- local check = file.addsuffix(askedname,suffix)
- if figures.exists(check,format) then
- return register(askedname, {
- askedname = askedname,
- fullname = check,
- format = format,
- cache = askedcache,
- })
- end
- end
- end
- else
- if figures.prefer_quality then
- for _, format in ipairs(figures.order) do
- local list = figures.formats[format].list or { format }
- for _, suffix in ipairs(list) do
- local name = file.replacesuffix(askedbase,suffix)
- for _, path in ipairs(figures.paths) do
- local check = path .. "/" .. name
- if figures.exists(check,format) then
- return register(askedname, {
- askedname = askedname,
- fullname = check,
- format = format,
- cache = askedcache,
- })
- end
- end
- end
- end
- else -- 'location'
- for _, path in ipairs(figures.paths) do
- for _, format in ipairs(figures.order) do
- local list = figures.formats[format].list or { format }
- for _, suffix in ipairs(list) do
- local check = path .. "/" .. file.replacesuffix(askedbase,suffix)
- if figures.exists(check,format) then
- return register(askedname, {
- askedname = askedname,
- fullname = check,
- format = format,
- cache = askedcache,
- })
- end
+ local name = file.replacesuffix(askedbase,suffix)
+ for _, path in ipairs(figures.paths) do
+ local check = path .. "/" .. name
+ if figures.exists(check,format) then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ })
end
end
end
end
- if figures.defaultsearch then
+ else -- 'location'
+ for _, path in ipairs(figures.paths) do
for _, format in ipairs(figures.order) do
local list = figures.formats[format].list or { format }
for _, suffix in ipairs(list) do
- local check = input.find_file(file.replacesuffix(askedname,suffix))
- if check and check ~= "" then
+ local check = path .. "/" .. file.replacesuffix(askedbase,suffix)
+ if figures.exists(check,format) then
return register(askedname, {
askedname = askedname,
fullname = check,
@@ -534,75 +488,92 @@ do
end
end
end
- return register(askedname)
+ if figures.defaultsearch then
+ for _, format in ipairs(figures.order) do
+ local list = figures.formats[format].list or { format }
+ for _, suffix in ipairs(list) do
+ local check = resolvers.find_file(file.replacesuffix(askedname,suffix))
+ if check and check ~= "" then
+ return register(askedname, {
+ askedname = askedname,
+ fullname = check,
+ format = format,
+ cache = askedcache,
+ })
+ end
+ end
+ end
+ end
end
+ return register(askedname)
+end
- -- -- -- plugins -- -- --
+-- -- -- plugins -- -- --
- figures.existers = figures.existers or { }
- figures.checkers = figures.checkers or { }
- figures.includers = figures.includers or { }
- figures.converters = figures.converters or { }
- figures.identifiers = figures.identifiers or { }
+figures.existers = figures.existers or { }
+figures.checkers = figures.checkers or { }
+figures.includers = figures.includers or { }
+figures.converters = figures.converters or { }
+figures.identifiers = figures.identifiers or { }
- figures.identifiers.list = {
- figures.identifiers.default
- }
+figures.identifiers.list = {
+ figures.identifiers.default
+}
- function figures.identifiers.default(data)
- local dr, du, ds = data.request, data.used, data.status
- local l = locate(dr)
- local foundname = l.foundname
- local fullname = l.fullname or foundname
- if fullname then
- du.format = l.format or false
- du.fullname = fullname -- can be cached
- ds.fullname = foundname -- original
- ds.format = l.format
- ds.status = (l.found and 10) or 0
- end
- return data
+function figures.identifiers.default(data)
+ local dr, du, ds = data.request, data.used, data.status
+ local l = locate(dr)
+ local foundname = l.foundname
+ local fullname = l.fullname or foundname
+ if fullname then
+ du.format = l.format or false
+ du.fullname = fullname -- can be cached
+ ds.fullname = foundname -- original
+ ds.format = l.format
+ ds.status = (l.found and 10) or 0
end
+ return data
+end
- function figures.identify(data)
- data = data or figures.current()
- for _, identifier in ipairs(figures.identifiers.list) do
- data = identifier(data)
- if data.status.status > 0 then
- break
- end
+function figures.identify(data)
+ data = data or figures.current()
+ for _, identifier in ipairs(figures.identifiers.list) do
+ data = identifier(data)
+ if data.status.status > 0 then
+ break
end
- return data
- end
- function figures.exists(askedname,format)
- return (figures.existers[format] or figures.existers.generic)(askedname)
- end
- function figures.check(data)
- data = data or figures.current()
- local dr, du, ds = data.request, data.used, data.status
- return (figures.checkers[ds.format] or figures.checkers.generic)(data)
- end
- function figures.include(data)
- data = data or figures.current()
- local dr, du, ds = data.request, data.used, data.status
- return (figures.includers[ds.format] or figures.includers.generic)(data)
- end
- function figures.scale(data) -- will become lua code
- texsprint(tex.ctxcatcodes,"\\doscalefigure")
- return data
- end
- function figures.done(data)
- figures.n = figures.n + 1
- data = data or figures.current()
- local dr, du, ds = data.request, data.used, data.status
- ds.width = tex.wd[figures.boxnumber]
- ds.height = tex.ht[figures.boxnumber]
- ds.xscale = ds.width/(du.width or 1)
- ds.yscale = ds.height/(du.height or 1)
- return data
end
+ return data
+end
+function figures.exists(askedname,format)
+ return (figures.existers[format] or figures.existers.generic)(askedname)
+end
+function figures.check(data)
+ data = data or figures.current()
+ local dr, du, ds = data.request, data.used, data.status
+ return (figures.checkers[ds.format] or figures.checkers.generic)(data)
+end
+function figures.include(data)
+ data = data or figures.current()
+ local dr, du, ds = data.request, data.used, data.status
+ return (figures.includers[ds.format] or figures.includers.generic)(data)
+end
+function figures.scale(data) -- will become lua code
+ texsprint(ctxcatcodes,"\\doscalefigure")
+ return data
+end
+function figures.done(data)
+ figures.n = figures.n + 1
+ data = data or figures.current()
+ local dr, du, ds = data.request, data.used, data.status
+ ds.width = tex.wd[figures.boxnumber]
+ ds.height = tex.ht[figures.boxnumber]
+ ds.xscale = ds.width/(du.width or 1)
+ ds.yscale = ds.height/(du.height or 1)
+ return data
+end
- function figures.dummy(data) -- fails
+function figures.dummy(data) -- fails
--~ data = data or figures.current()
--~ local dr, du, ds = data.request, data.used, data.status
--~ local r = node.new("rule")
@@ -610,9 +581,7 @@ do
--~ r.height = du.height or figures.defaultheight
--~ r.depth = du.depth or figures.defaultdepth
--~ tex.box[figures.boxnumber] = node.write(r)
- texsprint(tex.ctxcatcodes,"\\emptyfoundexternalfigure")
- end
-
+ texsprint(ctxcatcodes,"\\emptyfoundexternalfigure")
end
-- -- -- generic -- -- --
@@ -620,10 +589,10 @@ end
function figures.existers.generic(askedname)
--~ local result = io.exists(askedname)
--~ result = (result==true and askedname) or result
---~ local result = input.find_file(askedname) or ""
- local result = input.findbinfile(askedname) or ""
+--~ local result = resolvers.find_file(askedname) or ""
+ local result = resolvers.findbinfile(askedname) or ""
if result == "" then result = false end
- if figures.trace then
+ if trace_figures then
if result then
logs.report("figures","found: %s -> %s",askedname,result)
else
@@ -652,8 +621,9 @@ function figures.checkers.generic(data)
end
function figures.includers.generic(data)
local dr, du, ds = data.request, data.used, data.status
- dr.width = dr.width or du.width
- dr.height = dr.height or du.height
+ -- here we set the 'natural dimensions'
+ dr.width = du.width
+ dr.height = du.height
local hash = figures.hash(data)
local figure = figures.used[hash]
if figure == nil then
@@ -670,7 +640,7 @@ function figures.includers.generic(data)
tex.box[n] = img.node(figure) -- img.write(figure)
tex.wd[n], tex.ht[n], tex.dp[n] = figure.width, figure.height, 0 -- new, hm, tricky, we need to do that in tex (yet)
ds.objectnumber = figure.objnum
- texsprint(tex.ctxcatcodes,"\\relocateexternalfigure")
+ texsprint(ctxcatcodes,"\\relocateexternalfigure")
end
return data
end
@@ -682,13 +652,14 @@ function figures.checkers.nongeneric(data,command)
local name = du.fullname or "unknown nongeneric"
local hash = name
if dr.object then
- if not job.objects["FIG::"..hash] then
- texsprint(tex.ctxcatcodes,command)
- texsprint(tex.ctxcatcodes,format("\\setobject{FIG}{%s}\\vbox{\\box\\foundexternalfigure}",hash))
+ -- hm, bugged
+ if not jobobjects.get("FIG::"..hash) then
+ texsprint(ctxcatcodes,command)
+ texsprint(ctxcatcodes,format("\\setobject{FIG}{%s}\\vbox{\\box\\foundexternalfigure}",hash))
end
- texsprint(tex.ctxcatcodes,format("\\global\\setbox\\foundexternalfigure\\vbox{\\getobject{FIG}{%s}}",hash))
+ texsprint(ctxcatcodes,format("\\global\\setbox\\foundexternalfigure\\vbox{\\getobject{FIG}{%s}}",hash))
else
- texsprint(tex.ctxcatcodes,command)
+ texsprint(ctxcatcodes,command)
end
return data
end
@@ -700,14 +671,25 @@ end
function figures.checkers.mov(data)
local dr, du, ds = data.request, data.used, data.status
- du.width = dr.width or figures.defaultwidth
- du.height = dr.height or figures.defaultheight
+ dr.width = (dr.width or figures.defaultwidth):todimen()
+ dr.height = (dr.height or figures.defaultheight):todimen()
+ du.width = dr.width
+ du.height = dr.height
du.foundname = du.fullname
- texsprint(tex.ctxcatcodes,format("\\startfoundexternalfigure{%ssp}{%ssp}",du.width,du.height))
- data = backends.pdf.insertmovie(data)
- texsprint(tex.ctxcatcodes,"\\stopfoundexternalfigure")
+ local code = backends.codeinjections {
+ width = du.width or dr.width,
+ height = du.height or dr.height,
+ factor = number.dimenfactors.bp,
+ ["repeat"] = dr["repeat"],
+ controls = dr.controls,
+ preview = dr.preview,
+ label = dr.label,
+ foundname = du.foundname,
+ }
+ texsprint(ctxcatcodes,format("\\startfoundexternalfigure{%ssp}{%ssp}%s\\stopfoundexternalfigure",du.width,du.height,code))
return data
end
+
figures.includers.mov = figures.includers.nongeneric
-- -- -- mps -- -- --
@@ -731,7 +713,7 @@ figures.includers.buffers = figures.includers.nongeneric
-- -- -- tex -- -- --
function figures.existers.tex(askedname)
- askedname = input.find_file(askedname)
+ askedname = resolvers.find_file(askedname)
return (askedname ~= "" and askedname) or false
end
function figures.checkers.tex(data)
@@ -761,38 +743,39 @@ figures.converters.svg = figures.converters.eps
--~ os.spawn(command)
--~ end
-
figures.bases = { }
figures.bases.list = { } -- index => { basename, fullname, xmlroot }
figures.bases.used = { } -- [basename] => { basename, fullname, xmlroot } -- pointer to list
figures.bases.found = { }
figures.bases.enabled = false
-function figures.bases.use(basename)
+local bases = figures.bases
+
+function bases.use(basename)
if basename == "reset" then
- figures.bases.list = { }
- figures.bases.used = { }
- figures.bases.found = { }
- figures.bases.enabled = false
+ bases.list = { }
+ bases.used = { }
+ bases.found = { }
+ bases.enabled = false
else
basename = file.addsuffix(basename,"xml")
- if not figures.bases.used[basename] then
+ if not bases.used[basename] then
local t = { basename, nil, nil }
- figures.bases.used[basename] = t
- figures.bases.list[#figures.bases.list+1] = t
- if not figures.bases.enabled then
- figures.bases.enabled = true
+ bases.used[basename] = t
+ bases.list[#bases.list+1] = t
+ if not bases.enabled then
+ bases.enabled = true
xml.registerns("rlx","http://www.pragma-ade.com/schemas/rlx") -- we should be able to do this per xml file
end
end
end
end
-function figures.bases.find(basename,askedlabel)
+function bases.find(basename,askedlabel)
basename = file.addsuffix(basename,"xml")
- local t = figures.bases.found[askedlabel]
+ local t = bases.found[askedlabel]
if t == nil then
- local base = figures.bases.used[basename]
+ local base = bases.used[basename]
local page = 0
if base[2] == nil then
-- no yet located
@@ -816,7 +799,7 @@ function figures.bases.find(basename,askedlabel)
name = xml.filters.text(e,"*:file"),
page = page,
}
- figures.bases.found[askedlabel] = t
+ bases.found[askedlabel] = t
return t
end
end
@@ -827,9 +810,9 @@ end
-- we can access sequential or by name
-function figures.bases.locate(askedlabel)
- for _, entry in ipairs(figures.bases.list) do
- local t = figures.bases.find(entry[1],askedlabel)
+function bases.locate(askedlabel)
+ for _, entry in ipairs(bases.list) do
+ local t = bases.find(entry[1],askedlabel)
if t then
return t
end
@@ -838,9 +821,9 @@ function figures.bases.locate(askedlabel)
end
function figures.identifiers.base(data)
- if figures.bases.enabled then
+ if bases.enabled then
local dr, du, ds = data.request, data.used, data.status
- local fbl = figures.bases.locate(dr.name or dr.label)
+ local fbl = bases.locate(dr.name or dr.label)
if fbl then
du.page = fbl.page
du.format = fbl.format
@@ -858,3 +841,14 @@ figures.identifiers.list = {
figures.identifiers.base,
figures.identifiers.default
}
+
+-- tracing
+
+statistics.register("graphics processing time", function()
+ local n = figures.n
+ if n > 0 then
+ return format("%s seconds including tex, n=%s", statistics.elapsedtime(figures),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/core-inc.mkii b/tex/context/base/core-inc.mkii
index fe3894d57..ce97a0d1b 100644
--- a/tex/context/base/core-inc.mkii
+++ b/tex/context/base/core-inc.mkii
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Figure Inclusion}
+
% todo: directory : system -> \allinputpaths (so that we can \usesubpath)
%D This is a reimplementation of the original module, which
@@ -30,82 +32,19 @@
\unprotect
-\startmessages dutch library: figures
- title: figuren
- 1: figuur -- is niet te vinden
- 2: figuur -- wordt niet preset
- 3: maten van -- worden extern vastgesteld
- 4: maten van -- geladen uit figuurfile zelf
- 5: maten van -- zijn onbekend
- 6: maten van -- berekend door rlxtools
- 8: figuurobject -- wordt opnieuw gebruikt
-\stopmessages
-
-\startmessages english library: figures
- title: figures
- 1: figure -- can not be found
- 2: figure -- is not preset
- 3: dimensions of -- are determined externally
- 4: dimensions of -- loaded from figurefile itself
- 5: dimensions of -- are unknown
- 6: dimensions of -- calculated by rlxtools
- 8: figureobject -- is reused
-\stopmessages
-
-\startmessages german library: figures
- title: Abbildungen
- 1: Abbildung -- kann nicht gefunden werden
- 2: Abbildung -- wird nicht erstellt
- 3: dimensions of -- are determined externally
- 4: Dimensionen von -- geladen aus der Abbildungsdatei selbst
- 5: Dimensions of -- are unknown
- 6: Dimensionen von -- ausgerechnet durch rlxtools
- 8: Abbildungobjekt -- wurde wiederverwandt
-\stopmessages
-
-\startmessages czech library: figures
- title: obrazy
- 1: obraz -- nelze nalezt
- 2: obraz -- nepritomen
- 3: dimensions of -- are determined externally
- 4: dimenze obrazu -- nacteny primo z jeho souboru
- 5: dimensions of -- are unknown
- 6: dimenze obrazu -- spocteny programem rlxtools
- 8: obrazovy objekt -- je znovu pouzit
-\stopmessages
-
-\startmessages italian library: figures
- title: figure
- 1: figura -- non trovata
- 2: la figura -- non è preimpostata
- 3: dimensions of -- are determined externally
- 4: dimensioni di -- caricate dal file di immagini stesso
- 5: dimensions of -- are unknown
- 6: dimensioni di -- calcolate da rlxtools
- 8: oggetto-figura -- riutilizzato
-\stopmessages
-
-\startmessages romanian library: figures
- title: figuri
- 1: figura -- nu poate fi gasita
- 2: figura -- nu este presetata
- 3: dimensions of -- are determined externally
- 4: dimensiunea figurii -- se incarca din fisierul insusi
- 5: dimensions of -- are unknown
- 6: dimensiunea figurii -- este calculata de rlxtools
- 8: obiectul figura -- este refolosit
-\stopmessages
-
-\startmessages french library: figures
- title: figures
- 1: la figure -- ne peut être trouvée
- 2: la figure -- n'est pas pré-sélectionnée
- 3: dimensions of -- are determined externally
- 4: les dimensions de -- chargées implicitement à partir du fichier de figure
- 5: dimensions of -- are unknown
- 6: les dimensions de -- calculées par rlxtools
- 8: figureobject -- est réutilisé
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D Due to the mere fact that \DVI|/|\PDF\ drivers differ in their
%D needs for figure dimensions, we have to provide the width,
@@ -827,8 +766,8 @@
\def\insertscaledfiguredriverdata
{\insertfiguredriverdata\finalscaleboxwidth\finalscaleboxheight}
-\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethrearguments\fi
-\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethrearguments\fi
+\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethreearguments\fi
+\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethreearguments\fi
\def\registerexternalfigure % no placement, handy for preprocessing
{\dotripleempty\doregisterexternalfigure}
diff --git a/tex/context/base/core-inc.mkiv b/tex/context/base/core-inc.mkiv
index 24a78e657..06c8dc306 100644
--- a/tex/context/base/core-inc.mkiv
+++ b/tex/context/base/core-inc.mkiv
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Figure Inclusion}
+
%D todo:
%D
%D - color conversion
@@ -150,6 +152,8 @@
\let\@@efpreview \v!no
\let\@@efrepeat \v!no
%
+ \let\@@efforegroundcolor\empty
+ %
\let\@@efhfactor \empty
\let\@@efwfactor \empty
\let\@@effactor \empty
@@ -165,6 +169,8 @@
\let\@@eflines \empty
\let\@@efgrid \empty}
+\resetfigureusersettings
+
\appendtoks
\resetfigureusersettings
\to \everyexternalfigureresets
@@ -176,6 +182,8 @@
\doif\@@exoption\v!empty
{\skipexternalfigurestrue
\let\@@efframe\v!off}%
+ \doifsomething\@@efwidth {\doifdimensionelse\@@efwidth {\edef\@@efwidth {\the\dimexpr\@@efwidth }}\donothing}%
+ \doifsomething\@@efheight{\doifdimensionelse\@@efheight{\edef\@@efheight{\the\dimexpr\@@efheight}}\donothing}%
% seperation, seldom used
\doifseparatingcolorselse
{\let\@@efforegroundcolor\empty
@@ -346,8 +354,8 @@
\iftrialtypesetting \else \feedbackexternalfigure \fi
\fi}}
-\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethrearguments\fi
-\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethrearguments\fi
+\ifx\externalfigurereplacement\undefined\let\externalfigurereplacement\gobblethreearguments\fi
+\ifx\externalfigureplaceholder\undefined\let\externalfigureplaceholder\gobblethreearguments\fi
\let\feedbackexternalfigure\relax % \gobblefourarguments
\let\dowithfigure \relax
diff --git a/tex/context/base/core-inc.tex b/tex/context/base/core-inc.tex
deleted file mode 100644
index 88d52e746..000000000
--- a/tex/context/base/core-inc.tex
+++ /dev/null
@@ -1,18 +0,0 @@
-%D \module
-%D [ file=core-inc, % moved from core-fig
-%D version=2006.08.26, % overhaul of 1997.03.31
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Figure Inclusion,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Figure Inclusion}
-
-\loadmarkfile{core-inc}
-
-\endinput
diff --git a/tex/context/base/core-ini.tex b/tex/context/base/core-ini.tex
index 4f6e9fe1d..69edf9735 100644
--- a/tex/context/base/core-ini.tex
+++ b/tex/context/base/core-ini.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Initialization}
+\writestatus{loading}{ConTeXt Core Macros / Additional Initialization}
%D We will move more code to here, so that we become less dependent of the
%D orde in which modules are loaded.
diff --git a/tex/context/base/core-ins.tex b/tex/context/base/core-ins.tex
index c1185f7de..069153434 100644
--- a/tex/context/base/core-ins.tex
+++ b/tex/context/base/core-ins.tex
@@ -2,7 +2,7 @@
%D [ file=core-ins,
%D version=2002.04.16,
%D title=\CONTEXT\ Insertion Macros,
-%D subtitle=Insertions,
+%D subtitle=Insertions,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,14 +11,14 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Insertion Macros / General}
+\writestatus{loading}{ConTeXt Core Macros / Insertions}
%D Insertions are special data collections that are associated
%D to \TEX's internal page builder. When multiple footnote
%D classes were introduced, I decided to isolate some of the
-%D functionality in a module.
+%D functionality in a module.
-\unprotect
+\unprotect
\newtoks\@@insertionlist
@@ -29,7 +29,7 @@
%\def\installinsertion#1%
% {\ifx#1\undefined
% \newinsert#1%
-% \count#1\plusthousand
+% \count#1\plusthousand
% \skip #1\zeropoint
% \dimen#1\maxdimen
% \appendtoks\doprocessinsert#1\to\@@insertionlist
@@ -41,7 +41,7 @@
\fi
\ifx#1\relax % permits \csname...\endcsname
\newinsert#1%
- \count#1\plusthousand
+ \count#1\plusthousand
\skip #1\zeropoint
\dimen#1\maxdimen
\appendtoks\doprocessinsert#1\to\@@insertionlist
@@ -52,10 +52,10 @@
{\def\doprocessinsert##1{\ifvoid##1\else\insert##1{\unvbox##1}\fi}%
\processinsertions}
-%D For instance, when we postpone footnotes, we need to save
-%D some data related to the inserts. The next methods are
-%D far from ideal, but better than nothing. We save and
-%D restore box content and associated data independently.
+%D For instance, when we postpone footnotes, we need to save
+%D some data related to the inserts. The next methods are
+%D far from ideal, but better than nothing. We save and
+%D restore box content and associated data independently.
%D The box content is only restores when non||void.
\def\backupinsertion#1%
@@ -63,41 +63,41 @@
\def\installbackupinsertion#1%
{\expandafter\newinsert\csname\string#1\endcsname
- \count\backupinsertion#1\zerocount
+ \count\backupinsertion#1\zerocount
\skip \backupinsertion#1\zeropoint
\dimen\backupinsertion#1\maxdimen}
\def\saveinsertionbox#1%
- {\ifdim\ht#1>\zeropoint % hm, actually unknown
+ {\ifdim\ht#1>\zeropoint % hm, actually unknown
\global\setbox\backupinsertion#1\box#1%
\else
- \global\setbox\backupinsertion#1\box\voidb@x
+ \global\setbox\backupinsertion#1\emptybox
\fi}
\def\restoreinsertionbox#1%
- {\ifvoid\backupinsertion#1\else % if void, we keep the content
+ {\ifvoid\backupinsertion#1\else % if void, we keep the content
\global\setbox#1\box\backupinsertion#1%
\fi}
\def\eraseinsertionbackup#1%
- {\global\setbox\backupinsertion#1\box\voidb@x}
+ {\global\setbox\backupinsertion#1\emptybox}
-\def\saveinsertiondata#1%
+\def\saveinsertiondata#1%
{\global\skip \backupinsertion#1\skip #1%
\global\count\backupinsertion#1\count#1%
\global\dimen\backupinsertion#1\dimen#1}
-\def\restoreinsertiondata#1%
+\def\restoreinsertiondata#1%
{\global\skip #1\skip \backupinsertion#1%
\global\count#1\count\backupinsertion#1%
\global\dimen#1\dimen\backupinsertion#1}
-%D Auxiliary macros:
+%D Auxiliary macros:
\def\addinsertionheight#1\to#2%
{\ifvoid#1\else
- \advance#2 1\skip#1\relax
- \advance#2 \ht #1\relax
+ \advance#2 1\skip#1\relax
+ \advance#2 \ht #1\relax
\fi}
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/core-int.tex b/tex/context/base/core-int.mkii
index 79061958d..1ca9d23d1 100644
--- a/tex/context/base/core-int.tex
+++ b/tex/context/base/core-int.mkii
@@ -15,145 +15,7 @@
%D Still to be done properly.
-\writestatus{loading}{Context Core Macros / Interaction}
-
-% interactions 5 and 6 to be translated
-
-\startmessages dutch library: interactions
- title: interactie
- 1: aspect ratio -- x -- (b x h)
- 2: actief
- 3: niet actief
- 4: geen paginasynchronisatie (--) in hmode
- 5: onbekend attachment --
- 6: attachment file -- bestaat niet
-\stopmessages
-
-\startmessages english library: interactions
- title: interaction
- 1: aspect ratio -- x -- (b x h)
- 2: active
- 3: inactive
- 4: no pagesynchronisation (--) in hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages german library: interactions
- title: Interaktion
- 1: Seitenverhaeltnis -- x -- (B x H)
- 2: aktiv
- 3: inaktiv
- 4: keine Seitensynchronisation (--) im hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages czech library: interactions
- title: interakce
- 1: pomer -- x -- (s x v)
- 2: aktivni
- 3: neaktivni
- 4: zadna strankova synchronizace (--) v hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages italian library: interactions
- title: interazione
- 1: rapporto -- x -- (b x a)
- 2: attiva
- 3: inattiva
- 4: sincronizzazione di pagina (--) non disponibile in hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages norwegian library: interactions
- title: interaksjon
- 1: forholdstall -- x -- (b x h)
- 2: aktiv
- 3: inaktiv
- 4: ingen sidesynkronisering (--) i hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages romanian library: interactions
- title: interactiuni
- 1: aspectul -- x -- (b x h)
- 2: activ
- 3: inactiv
- 4: nu exista sincronizare pt. pagini (--) in hmode
- 5: unknown attachment --
- 6: attachment file -- does not exist
-\stopmessages
-
-\startmessages french library: interactions
- title: interaction
- 1: ratio d'aspect -- x -- (b x h)
- 2: actif
- 3: inactif
- 4: pas de synchronisation de page (--) dans le hmode
- 5: le fichier joint -- est inconnu
- 6: le fichier joint -- n'existe pas
-\stopmessages
-
-\startmessages dutch library: versions
- title: versie
- 1: er mankeert een @+
- 2: markeren pagina's
- 3: geselecteerde pagina's: --
-\stopmessages
-
-\startmessages english library: versions
- title: version
- 1: missing @+
- 2: marking pages
- 3: selected pages: --
-\stopmessages
-
-\startmessages german library: versions
- title: Version
- 1: fehlendes @+
- 2: Erstelle Seiten
- 3: Ausgewaehlte Seiten: --
-\stopmessages
-
-\startmessages czech library: versions
- title: verze
- 1: postradam @+
- 2: oznacuji se strany
- 3: oznacene strany: --
-\stopmessages
-
-\startmessages italian library: versions
- title: version
- 1: @+ mancante
- 2: marcatura pagine
- 3: pagine selezionate: --
-\stopmessages
-
-\startmessages norwegian library: versions
- title: versjon
- 1: manglende @+
- 2: markerer sider
- 3: valgte sider: --
-\stopmessages
-
-\startmessages romanian library: versions
- title: versiuni
- 1: lipseste @+
- 2: pagini marcate
- 3: pagini selectate: --
-\stopmessages
-
-\startmessages french library: versions
- title: version
- 1: @+ manquant
- 2: marquage des pages
- 3: pages sélectionnées : --
-\stopmessages
+\writestatus{loading}{ConTeXt Core Macros / Interaction}
\unprotect
@@ -1129,8 +991,8 @@
% Hier volgen de synchronisatiemacro's:
\def\syncprefix{sync}
-\def\syncmarker{syncmark}
+%def\syncmarker{syncmark}
%\definemarking[\syncmarker]
%\setupmarking[\syncmarker][\c!expansie=\v!ja]
@@ -1534,7 +1396,7 @@
\def\complexinteractionbar[#1]%
{\doifelse{#1}\v!reset
- {\global\setbox\interactionbarbox\box\voidb@x}%
+ {\global\setbox\interactionbarbox\emptybox}%
{\bgroup
\iflocation
\checksubpages % goes wrong / loads \numberofpages too
diff --git a/tex/context/base/core-int.mkiv b/tex/context/base/core-int.mkiv
new file mode 100644
index 000000000..d02881801
--- /dev/null
+++ b/tex/context/base/core-int.mkiv
@@ -0,0 +1,2036 @@
+%D \module
+%D [ file=core-int,
+%D version=1995.01.01,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Interaction,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% evt interactionbaren runtime laden (scheelt 8K)
+
+%D Still to be done properly.
+
+\writestatus{loading}{ConTeXt Core Macros / Interaction}
+
+\unprotect
+
+% \expand vs \expanded
+
+% linked registers implementeren als een koppeling == mooier
+
+\presetlocalframed[\??lk]
+
+\newcounter\numberoflinks
+
+\def\stelkoppelingenin%
+ {\dodoubleargument\getparameters[\??lk]}
+
+\def\definieerkoppeling[#1]% % local loading !
+ {\doifundefined{\s!link:#1:\s!list}
+ {\expanded{\definetwopasslist{\s!link:#1}}%
+ \expanded{\doloadtwopassdata{\s!link:#1}}%
+ \getfirsttwopassdata{\s!link:#1}%
+ \letgvalue{\s!link:#1:f}\twopassdata
+ \getlasttwopassdata{\s!link:#1}%
+ \letgvalue{\s!link:#1:l}\twopassdata
+ \letgvalue{\s!link:#1:s}\noftwopassitems
+ \gettwopassdata{\s!link:#1}%
+ \letgvalue{\s!link:#1:c}\twopassdata
+ \letgvalue{\s!link:#1:n}\twopassdata}}
+
+\def\koppeling[#1]#2%
+ {\bgroup
+ \definieerkoppeling[#1]%
+ \doglobal\increment\numberoflinks
+ \gettwopassdata{\s!link:#1}%
+ \edef\numberoflinks{0\getvalue{\s!link:#1:s}}%
+ \edef\firstlink {0\getvalue{\s!link:#1:f}}%
+ \edef\lastlink {0\getvalue{\s!link:#1:l}}%
+ \edef\currentlink {0\getvalue{\s!link:#1:n}}%
+ \edef\prevlink {0\getvalue{\s!link:#1:c}}%
+ \iftwopassdatafound
+ \edef\nextlink{0\twopassdata}%
+ \letgvalue{\s!link:#1:n}\nextlink
+ \letgvalue{\s!link:#1:c}\currentlink
+ \else
+ \edef\nextlink{0\getvalue{\s!link:#1:l}}%
+ \fi
+ \lazysavetwopassdata{\s!link:#1}{\numberoflinks}{\noexpand\realfolio}%
+ \ifnum\noflinks<\plustwo
+ \locationfalse
+ \fi
+ \iflocation
+ \hbox
+ {\setinteractionparameter\c!width\!!zeropoint
+ \dogotosomepage\??lk\gotobegincharacter\firstlink\hss
+ \ifnum\noflinks>\plustwo
+ \hskip\@@lkdistance
+ \dogotosomepage\??lk\gobackwardcharacter\prevlink\hss
+ \fi
+ \hskip\@@lkdistance
+ #2\relax
+ \hskip\@@lkdistance
+ \ifnum\noflinks>\plustwo
+ \dogotosomepage\??lk\goforwardcharacter\nextlink\hss
+ \hskip\@@lkdistance
+ \fi
+ \dogotosomepage\??lk\gotoendcharacter\lastlink}%
+ \else
+ \hbox{#2}%
+ \fi
+ \egroup}
+
+\def\definieerkoppeling[#1]% % local loading !
+ {\doifundefined{\s!link:#1:\s!list}
+ {\expanded{\definetwopasslist{\s!link:#1}}% \expanded{\doloadtwopassdata{\s!link:#1}}%
+ \getfirsttwopassdata{\s!link:#1}%
+ \let\firstlink\twopassdata
+ \getlasttwopassdata{\s!link:#1}%
+ \let\lastlink\twopassdata
+ \let\noflinks\noftwopassitems
+ \gettwopassdata{\s!link:#1}%
+ \let\currentlink\twopassdata
+ \let\nextlink\twopassdata
+ \setxvalue{\s!link:#1:}{\firstlink:\lastlink:\noflinks:\currentlink:\nextlink}}}
+
+\def\koppeling[#1]#2%
+ {\bgroup
+ \definieerkoppeling[#1]%
+ \doglobal\increment\numberoflinks
+ \gettwopassdata{\s!link:#1}%
+ \def\next[##1:##2:##3:##4:##5]%
+ {\edef\firstlink {0##1}%
+ \edef\lastlink {0##2}%
+ \edef\noflinks {0##3}%
+ \edef\prevlink {0##4}%
+ \edef\currentlink{0##5}}%
+ \expanded{\next[\getvalue{\s!link:#1:}]}%
+ \edef\nextlink{0\iftwopassdatafound\twopassdata\else\lastlink\fi}%
+ \setxvalue{\s!link:#1:}{\firstlink:\lastlink:\noflinks:\currentlink:\nextlink}%
+ \lazysavetwopassdata{\s!link:#1}{\numberoflinks}{\noexpand\realfolio}%
+ \ifnum\noflinks<\plustwo
+ \locationfalse
+ \fi
+ \iflocation
+ \hbox
+ {\setinteractionparameter\c!width\!!zeropoint
+ #2\relax
+ \hskip\@@lkdistance
+ \dogotosomepage\??lk\gotobegincharacter\firstlink\hss
+ \ifnum\noflinks>\plustwo
+ \dogotosomepage\??lk\gobackwardcharacter\prevlink\hss
+ \fi
+ \ifnum\noflinks>\plustwo
+ \dogotosomepage\??lk\goforwardcharacter\nextlink\hss
+ \hskip\@@lkdistance
+ \fi
+ \dogotosomepage\??lk\gotoendcharacter\lastlink}%
+ \else
+ \hbox{#2}%
+ \fi
+ \egroup}
+
+\let\setupinteractionscreens\empty
+
+\def\docalculateinteractionscreen
+ {\doifelse\@@scwidth\v!fit
+ {\!!widtha\leftcombitotal
+ \ifdim\backspace>\!!widtha\ifdim\backspace>\zeropoint\relax
+ \advance\backspace -\!!widtha
+ \fi\fi
+ \advance\!!widtha\rightcombitotal
+ \advance\!!widtha 2\dimexpr\@@scbackspace+\@@schoroffset\relax}
+ {\doifelse\@@scwidth\v!max
+ {\!!widtha\printpaperwidth}
+ {\!!widtha\@@scwidth}}%
+ \doifelse\@@scheight\v!fit
+ {\!!heighta\dimexpr\topheight+\topdistance\relax
+ \ifdim\topspace>\!!heighta\ifdim\topspace>\zeropoint\relax
+ \advance\topspace -\!!heighta
+ \fi\fi
+ \advance\!!heighta \dimexpr\makeupheight+\bottomdistance+\bottomheight\relax
+ \advance\!!heighta 2\dimexpr\@@sctopspace+\@@scveroffset\relax}
+ {\doifelse\@@scheight\v!max
+ {\!!heighta\printpaperheight}
+ {\!!heighta\@@scheight}}%
+ \doif\@@scdelay\v!none{\let\@@scdelay\zerocountervalue}}
+
+% The macro is not to be changed; only the \@@ia-variables
+% may be set! ConTeXt is the producer but we no longer
+% mention the pragma site, since we don't want to be bothered
+% with remarks about third party documents and/or associated
+% with documents produced outside our control.
+
+\def\doprepareidentity % beware, we need to construct
+ {\let\!!stringa\@@iakeyword % an unexpanded space separated
+ \let\@@iakeyword\empty % list of keywords from a comma
+ \def\doprepareidentity##1% % separated one
+ {\ifx\@@iakeyword\empty
+ \appended\def\@@iakeyword{##1}%
+ \else
+ \appended\def\@@iakeyword{ ##1}%
+ \fi}%
+ \@EA\processcommalist\@EA[\!!stringa]\doprepareidentity
+ \global\let\doprepareidentity\relax}
+
+%D The Creator field is changed per 12/04/2006 due to user presure. This
+%D means that I need to put my own status info someplace else.
+
+\def\initializeidentity
+ {\doprepareidentity
+ \dosetupidentity % no \expanded{..} will be done in special (else no pdfdoc)
+ {\@@iatitle}{\@@iasubtitle}{\@@iaauthor}%
+ {ConTeXt - \contextversion}%
+ {\@@iadate}{\@@iakeyword}%
+ \global\let\initializeidentity\relax}
+
+\appendtoks \initializeidentity \to \everyshipout
+
+\def\initializepaper
+ {\bgroup
+ \ifx\@@ppleft \empty
+ \ifx\@@ppright\empty
+ \ifx\@@pptop \empty
+ \ifx\@@ppbottom \empty
+ \ifx\@@pcstate\v!start
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi\else
+ \locationfalse\fi
+ \iflocation % without screen settings
+ \egroup
+ \dosetuppaper\papersize\paperwidth\paperheight
+ \else
+ \egroup
+ \dosetuppaper\printpapersize\printpaperwidth\printpaperheight
+ \fi}
+
+\appendtoks \initializepaper \to \everyshipout
+
+\def\doinitializepaper
+ {\bgroup
+ \docalculateinteractionscreen
+ \ifdim\!!widtha>\paperwidth\ifdim\!!widtha>\zeropoint
+ \paperwidth\!!widtha
+ \fi\fi
+ \ifdim\!!heighta>\paperheight\ifdim\!!heighta>\zeropoint
+ \paperheight\!!heighta
+ \fi\fi
+ \dosetuppaper
+ {\printpapersize}
+ {\the\paperwidth}
+ {\the\paperheight}%
+ \egroup}
+
+\let\@@pcscreendata\empty
+
+\def\dosetupinteractionscreens % met a, b en \number
+ {\doifnot\@@pcstate\v!start\dodosetupinteractionscreens}
+
+\setvalue{\??sc\c!option\v!max }{1} % tzt share with driver
+\setvalue{\??sc\c!option\v!bookmark }{2} % tzt share with driver
+\setvalue{\??sc\c!option\v!fit }{3} % tzt share with driver
+\setvalue{\??sc\c!option\v!doublesided}{4} % tzt share with driver
+
+\def\dodosetupinteractionscreens % met a, b en \number
+ {\bgroup
+ \docalculateinteractionscreen
+ \!!counte=0\getvalue{\??sc\c!option\@@scoption}\relax
+ % niet waterdicht
+ \doifnot{\the\!!widtha\the\!!heighta}\@@pcscreendata
+ {\xdef\@@pcscreendata{\the\!!widtha\the\!!heighta}%
+ \showmessage\m!interactions1{\withoutpt\the\!!widtha,\withoutpt\the\!!heighta}}%
+ % needs to be split: dimensions for each page
+ % and mode per document and only once !
+ \dosetupscreen \backoffset\topoffset\!!widtha\!!heighta{\the\!!counte}%
+ \dosetupcropbox\backoffset\topoffset\!!widtha\!!heighta
+ \egroup}
+
+\def\dosetupinteractionscreen[#1]%
+ {\getparameters[\??sc][#1]%
+ \ifproductionrun
+ \let\initializepaper\doinitializepaper
+ \let\setupinteractionscreens\dosetupinteractionscreens
+ \fi}
+
+\appendtoks \setupinteractionscreens \to \everyfirstshipout % needed to get option=max etc working
+\appendtoks \setupinteractionscreens \to \everyshipout % needed for page/screen dimensions
+
+\def\setupinteractionscreen
+ {\dosingleempty\dosetupinteractionscreen}
+
+% \startinteractionmenu[rechts]
+% \but [eerste] eerste \\
+% \txt hello world \\
+% \but [tweede] tweede \\
+% \nop \\
+% \but [tweede] tweede \\
+% \rul whow \\
+% \but [tweede] tweede \\
+% \raw hello world \\
+% \but [tweede] tweede \\
+% \com \vfill \\
+% \but [derde] derde \\
+% \stopinteractionmenu
+
+\newif\iflocationmenupermitted
+
+\def\testinteractionmenu#1%
+ {\iflocation
+ \doifelse\@@iamenu\v!on
+ {\doifelsevalue{\??am#1\c!state}\v!start
+ {\global\locationmenupermittedtrue}
+ {\global\locationmenupermittedfalse}}
+ {\global\locationmenupermittedfalse}%
+ \else
+ \global\locationmenupermittedfalse
+ \fi}
+
+\def\dodisableinteractionmenu[#1][#2][#3]%
+ {\def\dododisableinteractionmenu##1%
+ {\doifelse{#3}{}
+ {\letvalue{\??am##1\c!obstruction}\empty}
+ {\edef\interactieblokkade{\getvalue{\??am##1\c!obstruction}}
+ \def\docommand####1{#1{####1}{\interactieblokkade}}% #1 = \remove or \add
+ \processcommalist[#3]\docommand
+ \setevalue{\??am##1\c!obstruction}{\interactieblokkade}}}%
+ \processcommalist[#2]\dododisableinteractionmenu}
+
+\def\disableinteractionmenu
+ {\dotripleempty\dodisableinteractionmenu[\addtocommalist]}
+
+\def\enableinteractionmenu
+ {\dotripleempty\dodisableinteractionmenu[\removefromcommalist]}
+
+% ja : kader/achtergrond met tekst
+% leeg : kader/achtergrond maar geen tekst
+% nee : alleen ruimte reserveren
+% geen : helemaal weglaten
+
+\newif\iflocationdummy
+\newif\ifskippedmenuitem
+
+\newif\iflocationempty
+\newif\iflocationclick
+
+% ja : kader/achtergrond met tekst
+% leeg : kader/achtergrond maar geen tekst
+% nee : alleen ruimte reserveren
+% geen : helemaal weglaten
+%
+% \setupinteractionmenu[right][samepage=yes, unknownreference=yes]
+% \setupinteractionmenu[right][samepage=empty,unknownreference=empty]
+% \setupinteractionmenu[right][samepage=no, unknownreference=no]
+% \setupinteractionmenu[right][samepage=none, unknownreference=none]
+%
+% \startinteractionmenu[right]
+% \but [firstpage] first \\
+% \but [lastpage] last \\
+% \but [somepage] crap \\
+% \stopinteractionmenu
+
+\def\dosetlocationboxcontent#1[#2]#3[#4]%
+ {\global\skippedmenuitemfalse
+ \setbox\locationbox\hbox
+ {\resetgoto % anders cyclische aanroep !
+ \localframed[#1][#2]{\dolocationattributes{#1}\c!style\c!color{#3}}}%
+ \iflocationclick
+ \hbox{\gotolocation{#4}{\box\locationbox}}%
+ \else
+ \hbox{\box\locationbox}%
+ \fi}
+
+\let\dosetlocationboxyes\dosetlocationboxcontent
+
+\def\dosetlocationboxempty#1[%
+ {\dosetlocationboxcontent{#1}[\c!empty=\v!yes,}
+
+\def\dosetlocationboxno#1[%
+ {\dosetlocationboxcontent{#1}[\c!empty=\v!yes,\c!frame=,\c!background=,}
+
+\def\dosetlocationboxnone#1[#2]#3[#4]%
+ {\global\skippedmenuitemtrue}
+
+\def\setlocationboxyes#1[#2]#3[#4]%
+ {\locationclicktrue
+ \setbox\locationbox\hbox
+ {\resetgoto % anders cyclische aanroep !
+ \global\skippedmenuitemfalse
+ \gotolocation
+ {#4}% % needed
+ {\ifrealreferencepage
+ \ifcase\csname\??am\??am\csname#1\c!samepage\endcsname\endcsname\relax
+ \copycsname#1\c!color\endcsname\csname#1\c!contrastcolor\endcsname
+ \localframed[#1][#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \localframed[#1][\c!empty=\v!yes,#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \localframed[#1][\c!empty=\v!yes,\c!frame=,\c!background=,#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \global\skippedmenuitemtrue
+ \fi
+ \else
+ \localframed[#1][#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \fi}}%
+ \ifskippedmenuitem\else\box\locationbox\fi}
+
+\def\setlocationboxnop#1[#2]#3[#4]%
+ {\locationclickfalse
+ \setbox\locationbox\hbox
+ {\resetgoto % anders cyclische aanroep !
+ \global\skippedmenuitemfalse
+ \ifcase\csname\??am\??am\csname#1\c!unknownreference\endcsname\endcsname\relax
+ \localframed[#1][#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \localframed[#1][\c!empty=\v!yes,#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \localframed[#1][\c!empty=\v!yes,\c!frame=,\c!background=,#2]{\dolocationattributes{#1}\c!style\c!color{#3}}%
+ \or
+ \global\skippedmenuitemtrue
+ \fi}%
+ \ifskippedmenuitem\else\box\locationbox\fi}
+
+\def\setlocationboxraw#1[#2]#3[#4]%
+ {\localframed[#1][#2]{\dolocationattributes{#1}\c!style\c!color{#3}}}
+
+\def\setlocationbox#1[#2]#3[#4]%
+ {\bgroup % really needed !
+ \edef\permittedreferences{\csname#1\c!obstruction\endcsname}%
+ \doifreferencepermittedelse{#4}%
+ {\setlocationboxyes{#1}[#2]{#3}[#4]}%
+ {\setlocationboxnop{#1}[#2]{#3}[#4]}%
+ \egroup}
+
+\def\setlocationnop#1[#2]#3%
+ {\localframed[#1][#2]{#3}}
+
+\def\executeamboxcommands#1#2#3#4#5%
+ {%\processaction
+ % [\getvalue{\??am#1\c!dummy}]
+ % [ \v!yes=>\chardef\handleunknownmenuitem=0\relax,
+ % \v!empty=>\chardef\handleunknownmenuitem=1\relax,
+ % \v!no=>\chardef\handleunknownmenuitem=2\relax]%
+ \getvalue{\??am#1#3}\relax
+ \setamboxcommands{#1}{#4}%
+ \ignorespaces#2\unskip
+ \getvalue{\??am#1#5}}
+
+\newcounter\currentamposition
+
+\newtoks\everysetmenucommands
+
+\def\setamboxcommands#1#2%
+ {\def\currentmenu{#1}% % kan nog eerder
+ \def\currentsubmenu{#2}% % ? ?
+ \doglobal\newcounter\currentamposition
+ \the\everysetmenucommands}
+
+\def\menu@@amboxcommand#1\\%
+ {\dontleavehmode
+ \bgroup
+ \ignorespaces#1\unskip\relax
+ \ifskippedmenuitem \else
+ \getvalue{\??am\currentmenu\currentsubmenu}%
+ \fi
+ \egroup
+ \ignorespaces}
+
+\appendtoks
+ \let\@@amboxcommand\menu@@amboxcommand
+\to \everysetmenucommands
+
+\def\menu@raw[#1]#2\\%
+ {\@@amboxcommand\gotobox{\ignorespaces#2\unskip}[#1]\\}%
+
+\def\menu@but[#1]#2\\%
+ {\@@amboxcommand\do@@amposition\currentmenu{#1}{\setlocationbox{\??am\currentmenu}[]{\ignorespaces#2\unskip}[#1]}\\}%
+
+\def\menu@got[#1]#2\\% pas op! offset
+ {\@@amboxcommand\setlocationbox{\??am\currentmenu}[\c!frame=\v!off,\c!background=]{\ignorespaces#2\unskip}[#1]\\}%
+
+\def\menu@nop#1\\%
+ {\@@amboxcommand\setlocationboxraw{\??am\currentmenu}[\c!frame=\v!off,\c!background=,\c!empty=\v!yes]{\ignorespaces#1\unskip}[]\\}%
+
+\def\menu@txt#1\\%
+ {\@@amboxcommand\localframed[\??am\currentmenu][\c!frame=\v!off,\c!background=]{\ignorespaces#1\unskip}\\}%
+
+\def\menu@rul#1\\% ook \do@@amposition !
+ {\@@amboxcommand\localframed[\??am\currentmenu][]{\ignorespaces#1\unskip}\\}%
+
+\def\menu@com#1\\%
+ {\ignorespaces#1\unskip\ignorespaces}%
+
+\appendtoks
+ \let\raw\menu@raw
+ \let\but\menu@but
+ \let\got\menu@got
+ \let\nop\menu@nop
+ \let\txt\menu@txt
+ \let\rul\menu@rul
+ \let\com\menu@com
+\to \everysetmenucommands
+
+\ifx\do@@amposition\undefined
+ \let\do@@amposition\gobbletwoarguments % hook for positional thingies
+\fi
+
+\let\currentmenu\empty
+
+% beware : never change the concept of pbgoffset
+
+\def\menuparameter#1{\csname\??am\currentmenu#1\endcsname}
+
+\def\@@amhbox#1#2#3#4%
+ {\def\currentmenu{#3}%
+ \testinteractionmenu{#3}%
+ \iflocationmenupermitted
+ \bgroup
+ \showcomposition
+ \scratchdimen\dimexpr
+ \makeupwidth
+ +\pagebackgroundhoffset
+ +\pagebackgroundhoffset
+ -\menuparameter\c!leftoffset
+ -\menuparameter\c!rightoffset
+ \relax
+ \setbox\scratchbox\hbox to \scratchdimen
+ {\forgetall\executeamboxcommands{#3}{#4}\c!left\c!middle\c!right}%
+ \setbox\scratchbox\hbox{\do@@ammenuposition{#3}{\box\scratchbox}}%
+ \wd\scratchbox\makeupwidth % geen \ht=#2 setting (yet)
+ \hskip\dimexpr-\pagebackgroundhoffset+\menuparameter\c!leftoffset\relax
+ \box\scratchbox
+ \egroup
+ \else
+ #1\relax
+ \fi}
+
+\def\@@amvbox#1#2#3#4% don't change skipping, this one works!
+ {\def\currentmenu{#3}%
+ \testinteractionmenu{#3}%
+ \iflocationmenupermitted
+ \bgroup
+ \showcomposition
+ \scratchdimen\dimexpr
+ \textheight
+ +\pagebackgroundvoffset
+ +\pagebackgroundvoffset
+ +\pagebackgrounddepth
+ -\menuparameter\c!topoffset
+ -\menuparameter\c!bottomoffset
+ \relax
+ \setbox\scratchbox\vbox to \scratchdimen
+ {\forgetall % Voor't geval de afstand
+ %\setupblank[\v!standard]% % (tijdelijk) is aangepast.
+ \restorestandardblank
+ \hsize#2\relax
+ \executeamboxcommands{#3}{#4}\c!before\c!inbetween\c!after}%
+ \setbox\scratchbox\vbox{\hbox{\do@@ammenuposition{#3}{\box\scratchbox}}}%
+ \setbox\scratchbox\vbox
+ {\ht\scratchbox\zeropoint
+ \vskip\dimexpr-\pagebackgroundvoffset+\menuparameter\c!topoffset\relax
+ \box\scratchbox
+ \vskip\pagebackgroundvoffset}% overbodig
+ \ht\scratchbox\textheight
+ \wd\scratchbox#2\relax
+ \box\scratchbox
+ \egroup
+ \else
+ #1\relax
+ \fi}
+
+\ifx\do@@ammenuposition\undefined
+ \let\do@@ammenuposition\gobbleoneargument % hook for positional thingies
+\fi
+
+\setvalue{\??am\s!do\v!right }{\@@amvbox{\dodummypageskip\v!right }\rightedgewidth}
+\setvalue{\??am\s!do\v!left }{\@@amvbox{\dodummypageskip\v!left }\leftedgewidth }
+\setvalue{\??am\s!do\v!top }{\@@amhbox{\dodummypageskip\v!top }\topheight }
+\setvalue{\??am\s!do\v!bottom}{\@@amhbox{\dodummypageskip\v!bottom}\bottomheight }
+
+\def\dointeractionmenu#1#2%
+ {\getvalue{\??am\s!do\getvalue{\??am#1\c!location}}{#1}{#2}}
+
+\unexpanded\def\interactionmenu[#1]%
+ {\getvalue{\??am\c!menu#1}}
+
+\def\horizontalinteractionmenu#1#2#3#4%
+ {\ifdim#2>\zeropoint % new
+ \scratchdimen\zeropoint
+ \setbox\scratchbox\hbox
+ {\def\docommand##1%
+ {\doifnotvalue{\??am##1\c!state}\v!none
+ {\hskip\scratchdimen
+ \setbox2\hbox to #2
+ {\getvalue{\??am##1#3}\interactionmenu[##1]\getvalue{\??am##1#4}}%
+ \doifelsevalue{\??am##1\c!distance}\v!overlay
+ {\scratchdimen\zeropoint
+ \wd2\zeropoint}%
+ {\scratchdimen\getvalue{\??am##1\c!distance}}%
+ \box2}}%
+ \startinteraction
+ \processcommacommand[\getvalue{\??am#1}]\docommand
+ \stopinteraction}%
+ \wd\scratchbox#2\relax
+ \box\scratchbox
+ \fi}
+
+\def\verticalinteractionmenu#1#2#3#4%
+ {\ifdim#2>\zeropoint % new
+ \scratchdimen\zeropoint
+ \setbox\scratchbox\vbox
+ {\def\docommand##1%
+ {\doifnotvalue{\??am##1\c!state}\v!none
+ {\vskip\scratchdimen
+ \setbox2\vbox to #2
+ {\getvalue{\??am##1#3}\interactionmenu[##1]\getvalue{\??am##1#4}}%
+ \doifelsevalue{\??am##1\c!distance}\v!overlay
+ {\scratchdimen\zeropoint
+ \offinterlineskip
+ \dp2\zeropoint
+ \ht2\zeropoint}%
+ {\scratchdimen\getvalue{\??am##1\c!distance}}%
+ \box2}}%
+ \startinteraction
+ \processcommacommand[\getvalue{\??am#1}]\docommand
+ \stopinteraction}%
+ \ht\scratchbox#2\relax
+ \dp\scratchbox\zeropoint
+ \box\scratchbox
+ \fi}
+
+\letvalue{\??am\v!left }\empty
+\letvalue{\??am\v!right}\empty
+\letvalue{\??am\v!top }\empty
+\letvalue{\??am\v!bottom }\empty
+
+% todo : \defineinteractionmenuclass
+
+\def\interactionmenus[#1]%
+ {\iflocation
+ \getvalue{\??am\??am\c!menu#1}%
+ \else
+ \dodummypageskip{#1}%
+ \fi}
+
+\setvalue{\??am\??am\c!menu\v!left }{\horizontalinteractionmenu\v!left \leftedgewidth \c!left \c!right}
+\setvalue{\??am\??am\c!menu\v!right }{\horizontalinteractionmenu\v!right \rightedgewidth\c!left \c!right}
+\setvalue{\??am\??am\c!menu\v!top }{\verticalinteractionmenu \v!top \topheight \c!before\c!after}
+\setvalue{\??am\??am\c!menu\v!bottom}{\verticalinteractionmenu \v!bottom\bottomheight \c!before\c!after}
+
+% this can be implemented with the following command (which
+% is new, undocumented, experimental, untested, etc etc)
+
+\def\defineinteractionmenuclass
+ {\dodoubleargument\dodefineinteractionmenuclass}
+
+\def\dodefineinteractionmenuclass[#1][#2]% tag hori|veri
+ {\doifelse{#2}\v!vertical
+ {\setvalue{\??am\??am\c!menu#1}{\verticalinteractionmenu {#1}{\getvalue{\??am#1\c!width }}\c!before\c!after}}
+ {\setvalue{\??am\??am\c!menu#1}{\horizontalinteractionmenu{#1}{\getvalue{\??am#1\c!height}}\c!left\c!right }}}
+
+% \setupinteraction[menu=on,state=start]
+%
+% \defineinteractionmenuclass[test] [vertical]
+% \defineinteractionmenuclass[another][horizontal]
+%
+% \defineinteractionmenu[test] [left][state=start,width=4cm]
+% \defineinteractionmenu[another][top] [state=start,height=1cm]
+%
+% \startinteractionmenu[test]
+% \but [firstpage] test-a \\
+% \but [nextpage] test-b \\
+% \stopinteractionmenu
+%
+% \startinteractionmenu[another]
+% \but [firstpage] test-a \\
+% \but [nextpage] test-b \\
+% \stopinteractionmenu
+%
+% \setupheadertexts[{\interactionmenu[another]}]
+%
+% \starttext
+%
+% test \interactionmenu[test] \page
+% test \interactionmenu[test] \page
+%
+% \stoptext
+
+%D This can save complicated menu macros when one want to
+%D keep control over parts of a menu (i.e.\ turn them on and
+%D off). We could have achieved something similar with modes.
+
+\def\local@@ambox#1#2#3#4% don't change skipping, this one works!
+ {\bgroup
+ \testinteractionmenu{#3}%
+ \iflocationmenupermitted
+ \executeamboxcommands{#3}{#4}\c!before\c!inbetween\c!after
+ \else
+ #1\relax
+ \fi
+ \egroup}
+
+\def\includemenu[#1]%
+ {\doifvalue{\??am#1\c!state}\v!local
+ {\bgroup
+ \letvalue{\??am#1\c!state}\v!start
+ \let\@@amvbox\local@@ambox
+ \let\@@amhbox\local@@ambox
+ \getvalue{\??am\c!menu#1}%
+ \egroup}}
+
+%D We also need an explicit position control some day. I'll
+%D do that when I need it. [The stacking order.]
+
+\newif\ifextendedmenu
+
+% [name] [location]
+% [name] [location] [pars]
+
+\def\defineinteractionmenu
+ {\dotripleempty\dodefineinteractionmenu}
+
+\def\dodefineinteractionmenu[#1][#2][#3]%
+ {% main settings
+ \letvalue{\??am\c!menu#1}\empty
+ \setvalue{\@@dodolistelement#1}{\def\dosomelistelement{\dodomenulistelement{#1}}}%
+ \presetlocalframed[\??am#1]%
+ % register location
+ \expanded{\addtocommalist{#1}\@EA\noexpand\csname\??am#2\endcsname}%
+ % inherit settings
+ \doifnot{#1}{#2}
+ {\copyparameters[\??am#1][\??am#2]
+ [\c!left,\c!middle,\c!right,\c!before,\c!after,\c!inbetween,%
+ \c!width,\c!height,\c!distance,\c!offset,%
+ \c!frame,\c!framecolor,\c!rulethickness,%
+ \c!background,\c!backgroundcolor,\c!backgroundscreen,%
+ \c!style,\c!color,\c!contrastcolor,\c!samepage,\c!unknownreference,%
+ \c!leftoffset,\c!rightoffset,\c!topoffset,\c!bottomoffset]}%
+ % additional settings
+ \getparameters[\??am#1][\c!location=#2,\c!obstruction=,#3]}
+
+\def\setupinteractionmenu
+ {\dodoubleargument\dosetupinteractionmenu}
+
+\def\dosetupinteractionmenu[#1][#2]%
+ {\def\docommand##1{\getparameters[\??am##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\expandafter\chardef\csname\??am\??am\v!yes \endcsname\zerocount
+\expandafter\chardef\csname\??am\??am\v!empty\endcsname\plusone
+\expandafter\chardef\csname\??am\??am\v!no \endcsname\plustwo
+\expandafter\chardef\csname\??am\??am\v!none \endcsname\plusthree
+\expandafter\chardef\csname\??am\??am \endcsname\plusone % default
+
+\processbetween{\v!interactionmenu}\dostartinteractionmenu
+
+\def\dostartinteractionmenu#1%
+ {\dodostartinteractionmenu#1\dodostopinteractionmenu}
+
+\def\dodostartinteractionmenu[#1]#2\dodostopinteractionmenu
+ {\setvalue{\??am\c!menu#1}{\extendedmenutrue\dointeractionmenu{#1}{#2}}}
+
+\def\resetinteractionmenu[#1]%
+ {\letvalue{\??am\c!menu#1}\empty}
+
+\def\dodomenulistelement#1#2#3#4#5#6#7%
+ {\setbox0=\hbox
+ {\let\gotolocation\gobbleoneargument % hack to catch last []
+ %\locationclickfalse % ipv ^
+ \docheckrealreferencepage{#7}%
+ \setlocationboxyes
+ {\??am#1}% % needed !
+ []% no settings
+ {\limitatetext{#5}{\getvalue{\??li#2\c!maxwidth}}{\unknown}}% % needed !
+ []}% normally the destination, catch by gobble
+ \@@amboxcommand\do@@amposition{#1}{#7}% beware, we pass the pagenumber
+ {\ignorespaces\linklisttoelement{#3}{#6}{#7}{\box0}\unskip}\\}
+
+% \scherm moet worden als \page
+
+\def\screen
+ {\dosingleempty\doscreen}
+
+\def\doscreen[#1]%
+ {\iflocation\page[#1]\fi}
+
+\unexpanded\def\menubutton
+ {\dodoubleempty\domenubutton}
+
+\def\domenubutton[#1]%
+ {\iffirstargument
+ \ifsecondargument
+ \@EAEAEA\domenubuttonB
+ \else
+ \doifassignmentelse{#1}
+ {\@EAEAEA\domenubuttonC}
+ {\@EAEAEA\domenubuttonD}%
+ \fi
+ \else
+ \@EA\domenubuttonA
+ \fi[#1]}
+
+\def\domenubuttonA[#1][#2]#3[#4]% normal button, no parameters
+ {\bgroup
+ %\locationdummytrue
+ \setlocationbox\??bt[]{#3}[#4]%
+ \egroup}
+
+\def\domenubuttonB[#1][#2]#3[#4]% menu button, with parameters
+ {\bgroup
+ %\locationdummytrue
+ \setlocationbox{\??am#1}[#2]{#3}[#4]%
+ \egroup}
+
+\def\domenubuttonC[#1][#2]#3[#4]% normal button, with parameters
+ {\bgroup
+ %\locationdummytrue
+ \setlocationbox\??bt[#1]{#3}[#4]%
+ \egroup}
+
+\def\domenubuttonD[#1][#2]#3[#4]% menu button, no parameters
+ {\bgroup
+ %\locationdummytrue
+ \setlocationbox{\??am#1}[]{#3}[#4]%
+ \egroup}
+
+\def\menubox
+ {\dodoubleempty\domenubox}
+
+\def\domenubox[#1][#2]#3%
+ {\bgroup
+ \let\setlocationbox\setlocationboxraw
+ \domenubutton[#1][#2]#3[]%
+ \egroup}
+
+% Hier volgen de synchronisatiemacro's:
+
+\def\syncprefix{sync}
+
+%def\syncmarker{syncmark}
+%\definemarking[\syncmarker]
+%\setupmarking[\syncmarker][\c!expansie=\v!ja]
+
+\newmark\syncmarker
+
+\newcounter\synccounter
+
+\newif\ifsynchronisation
+
+\def\startsynchronization%
+ {\iflocation\ifsynchronisation
+ \doglobal\increment\synccounter
+ \fi\fi}
+
+\def\stopsynchronization%
+ {\iflocation\ifsynchronisation
+ %\thisisdestination{\syncprefix:\synccounter}%
+ \pagereference[\syncprefix:\synccounter]%
+ \ifvmode
+ \@EA\setmark\@EA\syncmarker\@EA{\synccounter} % \marking[\syncmarker]{\synccounter}%
+ \else
+ \showmessage\m!interactions4\synccounter
+ \fi
+ \fi\fi}
+
+\def\synchronize%
+ {\startsynchronization
+ \stopsynchronization}
+
+\def\dosetupsynchronization[#1]%
+ {\getparameters[\??sy][#1]%
+ \doifelse\@@systate\v!start
+ \synchronisationtrue
+ \synchronisationfalse}
+
+\def\setupsynchronization
+ {\dosingleargument\dosetupsynchronization}
+
+\def\definesynchronization
+ {\dosingleargument\dodefinesynchronization}
+
+\def\setupsynchronizationbar
+ {\dodoubleargument\getparameters[\??ba]}
+
+\presetlocalframed[\??ba]
+
+\setvalue{synchronisatie\v!page}[#1]%
+ {\bgroup
+ %\setupinteraction[\c!width=\!!zeropoint]%
+ \setinteractionparameter\c!width\!!zeropoint
+ \setbox0\hbox
+ {\localframed[\??ba][]{\dolocationattributes\??ba\c!style\c!color{\strut\@@batext}}}%
+ \dontcomplain
+ \def\atthebottom
+ {\leaders\hrule\!!depth1ex\!!height-.5ex\hfil}%
+ \def\atthetop##1##2##3%
+ {\dimen0=\wd0
+ \divide\dimen0 3
+ \multiply\dimen0 ##2\relax
+ \dimen2=.25em % brrr
+ \advance\dimen0 -##3\dimen2
+ %\gotodestination
+ % {}{#1}{\syncprefix:##1}{}
+ % {\hbox to \dimen0{\color[\locationcolor\@@bacolor]{\atthebottom}}}}%
+ \gotobox
+ {\hbox to \dimen0{\color[\locationcolor\@@bacolor]{\atthebottom}}}%
+ [#1::\syncprefix:##1]}%
+ \hbox
+ {\def\check##1##2%
+ {\edef##2{0##1\syncmarker}%
+ \ifnum0##2=0 \def##2{1}\fi}%
+ \check\gettopmark\top
+ \check\getfirstmark\first
+ \check\getbotmark\bot
+ \setbox2\hbox to \wd0
+ {\ifnum\top=\first\relax
+ \ifnum\first=\bot\relax
+ \atthetop\first30\relax
+ \else
+ \atthetop\first21\hss\atthetop\bot11\relax
+ \fi
+ \else
+ \ifnum\first=\bot\relax
+ \atthetop\top11\hss\atthetop\first21\relax
+ \else
+ \atthetop\top11\hss\atthetop\first11\hss\atthetop\bot11\relax
+ \fi
+ \fi}%
+ \wd2=\zeropoint\box2
+ \box0\relax}%
+ \egroup}
+
+\setvalue{synchronisatie\v!local}[#1]%
+ {\bgroup
+ %\setupinteraction[\c!width=\!!zeropoint]%
+ \setinteractionparameter\c!width\!!zeropoint
+ \def\blackrule{\hbox{\vrule\!!height.5em\!!width.5em}}%
+ %\gotodestination
+ % {}{##1}{\syncprefix:#1}{0}
+ % {\color[\locationcolor\@@bacolor]{\blackrule}}%
+ \gotobox %
+ {\color[\locationcolor\@@bacolor]{\blackrule}}%
+ [#1::\syncprefix:\synccounter]%
+ \egroup}
+
+\def\synchronizationbar[#1][#2]%
+ {\iflocation\ifsynchronisation
+ \bgroup
+ \setupsynchronizationbar
+ [\c!text=\getvalue{doc:des:#1},#2]%
+ \getvalue{synchronisatie\@@baalternative}[#1]%
+ \egroup
+ \fi\fi}
+
+% A nice application of glue. All this code will be rewritten and
+% generalized.
+
+\newbox\interactionbarbox
+
+\newif\ifbarsymbol
+
+\def\dogotosomepage#1#2#3% nog checken !
+ {\hbox
+ {\iflocation
+ \ifnum#3=\realpageno
+ #2%
+ \else
+ \gotorealpage\empty\empty{#3}{\doifsomething{#1}{\dolocationattributes{#1}\c!style\c!color}{#2}}%
+ \fi
+ \else
+ #2%
+ \fi}}
+
+\def\dogotosomecontrastpage#1#2#3% nog checken, may replace previous
+ {\checkreferences % nodig ??
+ \hbox
+ {\iflocation
+ \ifnum#3=\realpageno
+ \gotorealpage\empty\empty{#3}{\doifsomething{#1}{\dolocationattributes{#1}\c!style\c!contrastcolor}{#2}}%
+ \else
+ \gotorealpage\empty\empty{#3}{\doifsomething{#1}{\dolocationattributes{#1}\c!style\c!color}{#2}}%
+ \fi
+ \else
+ #2%
+ \fi}}
+
+\presetlocalframed[\??ib]
+
+\def\interactionbara % we need better control over contrastcolor
+ {\iflocation % maybe just use gotopage and set colors
+ \bgroup
+ \setinteractionparameter\c!width\zeropoint
+ \setupblackrules[\c!height=\v!max,\c!depth=\v!max]%
+ \!!widthb\dimexpr\@@ibwidth-2.75\emwidth\relax
+ \!!widtha\dimexpr\!!widthb/\lastpage\relax
+ \bgroup
+ \advance\realpageno\minusone
+ \ifvoid\interactionbarbox
+ \bgroup
+ \processaction
+ [\@@ibstep]
+ [ \v!small=>\scratchdimen.25\emwidth,
+ \v!medium=>\scratchdimen.5\emwidth,
+ \v!big=>\scratchdimen\emwidth,
+ \s!unknown=>\scratchdimen\!!widtha]%
+ \ifdim\!!widtha<\scratchdimen\relax
+ \!!counta\numexpr\scratchdimen/\!!widtha\relax
+ \else
+ \!!counta\@@ibstep\relax
+ \fi
+ \!!widtha\!!counta\!!widtha
+ \setbox\scratchbox\hbox{\blackrule[\c!width=\!!widtha,\c!color=middlegray]}% color here, else no mkiv
+ \global\setbox\interactionbarbox\hbox to \!!widthb
+ {\hss
+ \dostepwiserecurse\plusone\lastpage\!!counta
+ {\gotorealpage\empty\empty\recurselevel{\copy\scratchbox}}%
+ \hss}%
+ \global\wd\interactionbarbox\zeropoint
+ \egroup
+ \fi
+ \egroup
+ \noindent
+ \strut
+ \hbox to \@@ibwidth
+ {\dontcomplain
+ \setupblackrules[\c!width=\emwidth]%
+ \dogotosomecontrastpage\??ib\blackrule\firstpage
+ \hss
+ \copy\interactionbarbox
+ \hbox to \!!widthb
+ {\ifdim\!!widtha<\emwidth
+ \!!widtha\emwidth
+ \fi
+ \setupblackrules[\c!width=\!!widtha]%
+ \ifnum\realpageno>\plusone
+ \!!counta\numexpr\realpageno-\plustwo\relax
+ \hskip\zeropoint\!!plus\!!counta \s!sp\relax % cm gives overflow
+ \dogotosomepage\??ib\blackrule\prevpage
+ \fi
+ \dogotosomecontrastpage\??ib{\blackrule[\c!width=.5em]}\realpageno
+ \ifnum\realpageno<\lastpage\relax
+ \dogotosomepage\??ib\blackrule\nextpage
+ \!!counta\numexpr\lastpage-\realpageno-\plusone\relax
+ \hskip\zeropoint\!!plus\!!counta \s!sp\relax % cm gives overflow
+ \fi}%
+ \hss
+ \dogotosomecontrastpage\??ib\blackrule\lastpage}%
+ \egroup
+ \fi}
+
+\def\interactionbarb
+ {\ifnum\lastpage>\firstpage\relax
+ \interactionbuttons[\v!firstpage,\v!previouspage,\v!nextpage,\v!lastpage]%
+ \fi}
+
+\def\interactionbarc
+ {\iflocation
+ \ifnum\lastpage>\plusone
+ \hbox to \@@ibwidth
+ {\setupblackrules[\c!height=\@@ibheight,\c!depth=\@@ibdepth]%
+ \scratchdimen\dimexpr(\@@ibwidth-4\emwidth)/\numexpr\lastpage+\minusone\relax\relax
+ \!!widtha\numexpr\realpageno+\minusone\relax\scratchdimen
+ \!!widthb\numexpr\lastpage-\realpageno\relax\scratchdimen
+ \startcolor[\locationcolor\@@ibcolor]%
+ \dogotosomepage\empty{\blackrule[\c!width=\emwidth]}\firstpage
+ \hss
+ \dogotosomepage\empty{\blackrule[\c!width=\!!widtha]}\prevpage
+ \color[\@@ibcontrastcolor]{\blackrule[\c!width=\emwidth]}%
+ \dogotosomepage\empty{\blackrule[\c!width=\!!widthb]}\nextpage
+ \hss
+ \dogotosomepage\empty{\blackrule[\c!width=\emwidth]}\lastpage
+ \stopcolor}%
+ \fi
+ \fi}
+
+\def\interactionbard
+ {\iflocation\ifshowingsubpage
+ \ifnum\nofsubpages>\plusone
+ \hbox \bgroup
+ \setinteractionparameter\c!width\!!zeropoint
+ \ifbarsymbol
+ \setupsymbolset[\@@iasymbolset]%
+ \def\dogotox##1%
+ {\hbox{\symbol[\ifcase##1 \v!previous\or\v!somewhere\or\v!next\fi]}}%
+ \else
+ \def\dogotox##1%
+ {\hbox{\vrule\!!height\@@ibheight\!!depth \@@ibdepth\!!width \@@ibwidth}}%
+ \fi
+ \dostepwiserecurse\plusone\nofsubpages\plusone
+ {\bgroup
+ \scratchcounter\numexpr\recurselevel+\firstsubpage+\minusone\relax
+ \ifnum\scratchcounter<\realpageno\relax
+ \dogotosomecontrastpage\??ib{\dogotox0}\scratchcounter
+ \else\ifnum\scratchcounter=\realpageno\relax
+ \dogotosomecontrastpage\??ib{\dogotox1}\scratchcounter
+ \else
+ \dogotosomecontrastpage\??ib{\dogotox2}\scratchcounter
+ \fi\fi
+ \egroup
+ \hskip\@@ibdistance}%
+ \unskip % not needed
+ \egroup
+ \fi
+ \fi\fi}
+
+\def\interactionbare% KAN WORDEN GECOMBINEERD MET D
+ {\iflocation\ifshowingsubpage
+ \ifnum\nofsubpages>\plusone
+ \bgroup
+ \!!widthb\dimexpr\nofsubpages\dimexpr\@@ibdistance\relax-\@@ibdistance\relax % (n-1)
+ \!!widtha\dimexpr(\@@ibwidth-\!!widthb)/\nofsubpages\relax
+ \ifdim\!!widtha<\@@ibdistance\relax
+ \interactionbarf
+ \else
+ \setinteractionparameter\c!width\!!zeropoint
+ \noindent
+ \hbox to \@@ibwidth
+ \bgroup
+ \ifbarsymbol
+ \setupsymbolset[\@@iasymbolset]%
+ \def\dogotox##1%
+ {\hbox{\symbol[\ifcase##1 \v!previous\or\v!somewhere\or\v!next\fi}}%
+ \else
+ \def\dogotox##1%
+ {\hbox{\vrule\!!height\@@ibheight\!!depth\@@ibdepth\!!width\!!widtha}}%
+ \fi
+ \dostepwiserecurse\plusone\nofsubpages\plusone
+ {\bgroup
+ \scratchcounter\numexpr\recurselevel+\firstsubpage+\minusone\relax
+ \ifnum\scratchcounter<\realpageno\relax
+ \dogotosomecontrastpage\??ib{\dogotox0}\scratchcounter
+ \else\ifnum\scratchcounter=\realpageno\relax
+ \dogotosomecontrastpage\??ib{\dogotox1}\scratchcounter
+ \else
+ \dogotosomecontrastpage\??ib{\dogotox2}\scratchcounter
+ \fi\fi
+ \egroup
+ \hss}%
+ \unskip
+ \egroup
+ \fi
+ \egroup
+ \fi
+ \fi\fi}
+
+\def\interactionbarf % !! KAN WORDEN GECOMBINEERD MET D !!
+ {\iflocation\ifshowingsubpage
+ \ifnum\nofsubpages>\plusone
+ \setinteractionparameter\c!width\!!zeropoint
+ \noindent
+ \hbox to \@@ibwidth
+ \bgroup
+ \!!countb\zerocount
+ \loop % todo: \doloop
+ \advance\!!countb \plusone
+ %\!!countc\nofsubpages \divide\!!countc \!!countb \advance\!!countc \plusone
+ \!!countc\numexpr(\nofsubpages/\!!countb)+\plusone\relax % rounding
+ \!!widthb\@@ibdistance
+ \multiply\!!widthb \!!countc
+ \advance\!!widthb -\@@ibdistance
+ \!!widtha\@@ibwidth
+ \advance\!!widtha -\!!widthb
+ \divide\!!widtha \!!countc
+ \ifdim\!!widtha<\@@ibdistance\relax
+ \repeat
+ \ifnum\!!countc>\plusone
+ % this is not that well tested
+ \advance\!!countc \minustwo
+ \!!widtha-\@@ibdistance
+ \!!widtha\!!countc\!!widtha
+ \advance\!!widtha \@@ibwidth
+ \advance\!!countc \plusone
+ \divide\!!widtha \!!countc
+ \fi
+ \ifbarsymbol
+ \setupsymbolset[\@@iasymbolset]%
+ \def\dogotox##1%
+ {\hbox{\symbol[\ifcase##1 \v!previous\or\v!somewhere\or\v!somewhere\or\v!somewhere\or\v!next\fi}}%
+ \else
+ \def\dogotox##1%
+ {\hbox
+ {\!!heighta\@@ibheight
+ \!!deptha\@@ibdepth
+ \ifcase##1\relax
+ \vrule\!!height \!!heighta\!!depth \!!deptha\!!width\!!widtha
+ \or
+ \vrule\!!height.5\!!heighta\!!depth.5\!!deptha\!!width\!!widtha
+ \or
+ \vrule\!!height \!!heighta\!!depth \!!deptha\!!width\!!widtha
+ \or
+ \vrule\!!height.5\!!heighta\!!depth.5\!!deptha\!!width\!!widtha
+ \or
+ \vrule\!!height \!!heighta\!!depth \!!deptha\!!width\!!widtha
+ \fi}}%
+ \fi
+ \!!countc\numexpr\realpageno-\plustwo\relax
+ \!!countd\numexpr\realpageno+\plustwo\relax
+ \ifnum\!!countc<\plusone \!!countc\plusone \fi
+ \!!countf\zerocount
+ \dostepwiserecurse\firstsubpage\lastsubpage\plusone
+ {\!!doneafalse
+ \advance\!!countf \plusone
+ \ifnum\recurselevel=\firstsubpage\relax \!!doneatrue \fi
+ \ifnum\recurselevel=\lastsubpage\relax \!!doneatrue \fi
+ \if!!donea
+ \ifnum\recurselevel<\realpageno
+ \dogotosomecontrastpage\??ib{\dogotox0}\recurselevel
+ \else\ifnum\recurselevel>\realpageno
+ \dogotosomecontrastpage\??ib{\dogotox2}\recurselevel
+ \else
+ \dogotosomecontrastpage\??ib{\dogotox4}\recurselevel
+ \fi\fi
+ \hss
+ \!!countf\zerocount
+ \else\ifnum\!!countf=\!!countb
+ \ifnum\recurselevel<\realpageno
+ \dogotosomecontrastpage\??ib{\dogotox1}\recurselevel
+ \else\ifnum\recurselevel>\realpageno
+ \dogotosomecontrastpage\??ib{\dogotox3}\recurselevel
+ \else
+ \dogotosomecontrastpage\??ib{\dogotox2}\recurselevel
+ \fi\fi
+ \hss
+ \!!countf\zerocount
+ \fi\fi}%
+ \unskip
+ \egroup
+ \fi
+ \fi\fi}
+
+\def\interactionbarg
+ {\ifnum\lastsubpage>\firstsubpage\relax
+ \interactionbuttons[\v!firstsubpage,\v!previoussubpage,\v!nextsubpage,\v!lastsubpage]%
+ \fi}
+
+\def\checkinteractionbar#1#2#3%
+ {\ifdim\@@ibwidth=\zeropoint\def\@@ibwidth{#1}\fi
+ \doifnothing\@@ibheight{\def\@@ibheight{#2}}%
+ \doifnothing\@@ibdepth{\def\@@ibdepth{#3}}}
+
+\def\complexinteractionbar[#1]%
+ {\doifelse{#1}\v!reset
+ {\global\setbox\interactionbarbox\emptybox}%
+ {\bgroup
+ \iflocation
+ \checksubpages % goes wrong / loads \numberofpages too
+ \getparameters[\??ib][#1]%
+ \doif\@@ibstate\v!start
+ {\startinteraction
+ \processaction % breedte defaults !
+ [\@@ibalternative]
+ [ c=>\checkinteractionbar{10em}\v!max \v!max,
+ d=>\checkinteractionbar{.5em}{.5em} \!!zeropoint,
+ e=>\checkinteractionbar{10em}{.5em} \!!zeropoint,
+ f=>\checkinteractionbar{10em}{.5em} \!!zeropoint,
+ \s!default=>\checkinteractionbar{10em}\v!broad\!!zeropoint,
+ \s!unknown=>\checkinteractionbar{10em}\v!broad\!!zeropoint]%
+ \doifelse\@@ibsymbol\v!yes
+ \barsymboltrue\barsymbolfalse
+ \getvalue{interactionbar\@@ibalternative}%
+ \stopinteraction}%
+ \fi
+ \egroup}}
+
+\definecomplexorsimpleempty\interactionbar
+
+\def\setupinteractionbar
+ {\dodoubleargument\getparameters[\??ib]}
+
+% Er wordt vooralsnog uitgegaan van een symmetrische
+% start-stop situatie.
+
+\def\c!profiel!! {profiel:} % brrr
+\def\c!versie!! {versie:}
+
+\def\dodefineprofile[#1][#2]%
+ {\iflocation
+ \def\dododefineprofile##1%
+ {\def\dodododefineprofile####1%
+ {\doifdefinedelse{\c!profiel!!####1}%
+ {\edef\!!stringa{\getvalue{\c!profiel!!####1}}%
+ \setevalue{\c!profiel!!####1}{\!!stringa,##1}}%
+ {\setevalue{\c!profiel!!####1}{##1}}}%
+ \processcommalist[#2]\dodododefineprofile}%
+ \processcommalist[#1]\dododefineprofile
+ \fi}
+
+\def\defineprofile%
+ {\dodoubleargument\dodefineprofile}
+
+% Als met \getpar wordt gewerkt, dan moet \next worden toegepast.
+
+% TZT initialisatie!
+
+\def\profilepage{}
+
+\let\dosetprofilepage\relax
+\let\dogetprofilepage\relax
+
+\def\processprofile#1[#2]%
+ {\iflocation
+ \par % needed for pdftex
+ \bgroup
+ \dosetprofilepage
+ \dogetprofilepage
+ \def\processoneprofile##1##2%
+ {\ExpandBothAfter\doifinsetelse{##2}{\processedprofiles}%
+ {\doifsomething{##1}{(##1)}}%
+ {\addtocommalist{##2}\processedprofiles
+ ##1\relax
+ \ifcase#1\relax
+ \dobeginofprofile{##2}\paperwidth\paperheight\profilepage
+ \else
+ \doendofprofile
+ \fi}}%
+ \let\processedprofiles\empty
+ \def\doprocessprofile##1%
+ {\doifelse{\@@pfoption}{\v!test}%
+ {\goodbreak\blank\nobreak\tt[\space
+ \ifcase#1\v!start\else\v!stop\fi profiel\space ##1:\space
+ \doifdefinedelse{\c!profiel!!##1}%
+ {\def\dodoprocessprofile####1%
+ {\processoneprofile
+ {\goto{####1}[\c!profiel!!####1]}%
+ {####1}%
+ \space}%
+ \processcommacommand
+ [\getvalue{\c!profiel!!##1}]\dodoprocessprofile}%
+ {- }%
+ ]\nobreak\blank}%
+ {\doifdefined{\c!profiel!!##1}%
+ {\def\dodoprocessprofile####1%
+ {\processoneprofile{}{####1}}%
+ \processcommacommand
+ [\getvalue{\c!profiel!!##1}]\dodoprocessprofile}}}%
+ \processcommalist[#2]\doprocessprofile
+ \egroup
+ \par % needed for pdftex
+ \fi}
+
+\def\startprofile[#1]%
+ {\iflocation
+ \bgroup
+ \addtocommalist{#1}\actualprofile
+ \def\stopprofile%
+ {\processprofile1[#1]%
+ \egroup}%
+ \def\next{\processprofile0[#1]}% % \DoAfterFi \processprofile0[#1]%
+ \else % ^^^^^^^^^^ will be obsolete
+ \let\next\relax % since ugly and never used
+ \fi
+ \next}
+
+\let\stopprofile\relax
+
+\def\dofollowprofile#1[#2]%
+ {\iflocation
+ \hbox
+ {\dohandlegoto
+ {\dolocationattributes\??ia\c!style\c!color{#1\presetgoto}}%
+ {\dostartgotoprofile\buttonwidth\buttonheight{#2}}%
+ {\dostopgotoprofile}}%
+ \else
+ {#1}%
+ \fi}
+
+\def\followprofile#1[#2]%
+ {\iflocation
+ \doif\@@pfoption\v!test{\pagereference[\c!profiel!!#2]}%
+ \dofollowprofile{#1}[#2]%
+ \fi}
+
+\def\setupprofiles%
+ {\dodoubleargument\getparameters[\??pf]}
+
+% Als er nog geen tekst op de pagina staat, dan heeft het
+% profiel betrekking op het bovenstaande, dus soms een vorige
+% pagina! Vreemd, omdat PDF paginagewijs werkt. Gelukkig
+% biedt /page een oplossing. Echter: expansie van een
+% \special kan niet worden uitgesteld, zodat alleen een
+% two-pass een oplossing vormt. Het onderstaande kan komen
+% te vervallen als Acrobat dit ondervangt. Het scheelt een
+% pass en een lijst.
+%
+% Er kunnen eventueel twee lijsten worden gebruikt. Een voor
+% het begin (start) en een voor het eind (stop). Nu staat
+% alles in een lijst.
+
+\definetwopasslist\s!profile
+
+\newcounter\currentprofile
+
+\def\dosetprofilepage%
+ {\doglobal\increment\currentprofile
+ \lazysavetwopassdata{\s!profile}{\currentprofile}{\noexpand\realfolio}}
+
+\def\dogetprofilepage%
+ {\gettwopassdata{\s!profile}%
+ \let\profilepage=\twopassdata}
+
+% is this stuff used at all
+
+\newcounter\versionlevel
+\newcounter\versionorder
+
+\newif\ifrecentversion
+
+\let\oldatcharacter=@
+
+\def\minimumversion{0}
+\def\actualversion{0}
+
+\def\dosetupversions[#1]%
+ {\getparameters[\??ve][#1]
+ \stripcharacter.\from\@@venumber\to\minimumversion}
+
+\def\setupversions
+ {\dosingleargument\dosetupversions}
+
+\definetwopasslist\s!versionbegin
+\definetwopasslist\s!versionend
+
+\let\actualprofile\empty
+
+\def\doresetpageversion
+ {\lazysavetwopassdata{\s!versionend}{\versionorder}{\noexpand\realfolio}}
+
+\def\dosetpageversion#1%
+ {\recentversiontrue
+ \doglobal\increment\versionorder\relax
+ \lazysavetwopassdata{\s!versionbegin}{\versionorder}{\noexpand\realfolio}%
+ \let\resetpageversion\doresetpageversion}
+
+\def\recentcontributions{}
+
+\def\checkrecentcontributions%
+ {\gettwopassdata{\s!versionbegin}%
+ \iftwopassdatafound
+ \!!counta\twopassdata\relax
+ \gettwopassdata{\s!versionend}%
+ \iftwopassdatafound
+ \!!countb\twopassdata\relax
+ \doglobal\increment\versionorder\relax
+ \savetwopassdata{\s!versionbegin}{\versionorder}{\the\!!counta}%
+ \savetwopassdata{\s!versionend }{\versionorder}{\the\!!countb}%
+ \dostepwiserecurse\!!counta\!!countb\plusone
+ {\@EA\doglobal\@EA\addtocommalist\@EA{\recurselevel}{\recentcontributions}}%
+ \let\next\checkrecentcontributions
+ \else
+ \let\next\relax
+ \fi
+ \else
+ \let\next\relax
+ \fi
+ \next}
+
+\def\docheckpageversion
+ {\ExpandBothAfter\doifinsetelse{\realfolio}{\recentcontributions}
+ {\pageselectedtrue}%
+ {\pageselectedfalse}}
+
+\let\setpageversion \gobbleoneargument
+\let\resetpageversion \relax
+\let\checkpageversion \relax
+
+\def\complexstartversion[#1]%
+ {\bgroup
+ \doifelsenothing\actualprofile
+ {\startprofile[#1]}%
+ {\startprofile[#1,\actualprofile]}%
+ \def\docomplexstartversie##1%
+ {\stripcharacter.\from##1\to\actualversion
+ \ifnum\versionlevel>\zerocount\relax
+ \ifnum\actualversion=\zerocount
+ \setpageversion\actualversion % unknown version
+ \else
+ \ifnum\actualversion<\minimumversion\relax
+ \relax % old version
+ \else
+ \setpageversion\actualversion % new version
+ \fi
+ \fi
+ \fi}%
+ \doglobal\increment\versionlevel\relax
+ \doifelsenothing{#1}
+ {\docomplexstartversie{0}}%
+ {\processcommalist[#1]\docomplexstartversie}}
+
+\definecomplexorsimpleempty\startversion
+
+\def\stopversion
+ {\stopprofile
+ \doglobal\decrement\versionlevel
+ \ifnum\versionlevel<\zerocount
+ \showmessage\m!versions1\empty
+ \else
+ \resetpageversion
+ \egroup
+ \fi}
+
+\def\markversion
+ {\showmessage\m!versions2\empty
+ \let\setpageversion\dosetpageversion
+ \let\resetpageversion\relax
+ \let\checkpageversion\relax}
+
+\def\selectversion
+ {\checkrecentcontributions
+ \showmessage\m!versions3\recentcontributions
+ \let\setpageversio\gobbleoneargument
+ \let\resetpageversion\relax
+ \let\checkpageversion\docheckpageversion}
+
+\def\dodefineversion[#1][#2]%
+ {\setvalue{\c!versie!!#1}{#2}%
+ \defineprofile[#1][#2]}
+
+\def\defineversion
+ {\dodoubleargument\dodefineversion}
+
+\def\followversion
+ {\followprofile}
+
+\def\followprofileversion#1[#2][#3]%
+ {\def\docommand##1%
+ {\defineprofile[#2#3][##1]}%
+ \processcommacommand[\getvalue{\c!versie!!#3}]\docommand
+ \followprofile#1[#2#3]}
+
+\newcounter\currentpagetransition
+
+\newif\ifrandomtransitions
+
+\def\setuppagetransitions%
+ {\dosingleempty\dosetuppagetransitions}
+
+\def\dosetuppagetransitions[#1]%
+ {\doifelsenothing{#1}
+ {\doifnot\@@scdelay\v!none
+ {\let\setpagetransition\setsomepagedelay}}
+ {\doifelse{#1}\v!start
+ {\doifnot\@@scdelay\v!none
+ {\let\setpagetransition\setsomepagedelay}}
+ {\doglobal\newcounter\currentpagetransition
+ \doifinsetelse{#1}{\v!reset,\v!stop}
+ {\let\setpagetransition\relax}
+ {\let\setpagetransition\setsomepagetransition
+ \doifinsetelse\v!random{#1}
+ {\randomtransitionstrue}{\randomtransitionsfalse}%
+ \edef\userpagetransitions{#1}%
+ \@EA\removefromcommalist\@EA{\v!random}\userpagetransitions
+ \ifx\userpagetransitions\empty
+ \let\userpagetransitions\pagetransitions
+ \fi}}}}
+
+\def\setsomepagedelay
+ {\expanded{\dosetpagetransition{0}{\@@scdelay}}}
+
+\def\setsomepagetransition
+ {\iflocation
+ \ifrandomtransitions
+ \expanded{\getcommalistsize[\userpagetransitions]}%
+ \getrandomnumber\currentpagetransition1\commalistsize
+ \else
+ \doglobal\increment\currentpagetransition
+ \fi
+ \expanded{\getfromcommalist[\userpagetransitions][\currentpagetransition]}%
+ \doifnumberelse\commalistelement
+ {\expanded{\getfromcommalist[\pagetransitions][\commalistelement]}}
+ {}%
+ \ifx\commalistelement\empty
+ \doglobal\newcounter\currentpagetransition
+ \setsomepagetransition
+ \else
+ \doifelse\@@scdelay\v!none
+ {\expanded{\dosetpagetransition{\commalistelement}{0}}}
+ {\expanded{\dosetpagetransition{\commalistelement}{\@@scdelay}}}%
+ \fi
+ \fi}
+
+\prependtoks \setpagetransition \to \everyshipout
+
+% temporary here
+
+%D \startbuffer
+%D \dorecurse{10}
+%D {\horizontalpositionbar
+%D \pos\recurselevel \min1 \max10
+%D \token\framed{\recurselevel}%
+%D \\}
+%D
+%D \hbox to 15em
+%D {\hss
+%D \dorecurse{10}
+%D {\verticalpositionbar\pos\recurselevel\min1\max10\token\blackrule\\
+%D \hss}}
+%D \stopbuffer
+
+\def\horizontalpositionbar\pos#1\min#2\max#3\token#4\\%
+ {\hbox to \hsize
+ {\hskip\zeropoint\!!plus #1\!!fill
+ \hskip\zeropoint\!!plus-#2\!!fill
+ #4\relax
+ \hskip\zeropoint\!!plus #3\!!fill
+ \hskip\zeropoint\!!plus-#1\!!fill}}
+
+\def\verticalpositionbar\pos#1\min#2\max#3\token#4\\%
+ {\vbox to \vsize
+ {\vskip\zeropoint\!!plus #1\!!fill
+ \vskip\zeropoint\!!plus-#2\!!fill
+ \hbox{#4}\relax
+ \vskip\zeropoint\!!plus #3\!!fill
+ \vskip\zeropoint\!!plus-#1\!!fill}}
+
+\def\horizontalgrowingbar\pos#1\min#2\max#3\height#4\depth#5\\%
+ {\hbox to \hsize
+ {\scratchcounter#1%
+ \advance\scratchcounter -#2%
+ \advance\scratchcounter \plusone
+ \leaders\vrule\hskip\zeropoint\!!plus \scratchcounter\!!fill
+ \vrule\!!width\zeropoint\!!height#4\!!depth#5%
+ \hskip\zeropoint\!!plus #3\!!fill
+ \hskip\zeropoint\!!plus-#1\!!fill}}
+
+\def\verticalgrowingbar\pos#1\min#2\max#3\width#4\\%
+ {\vbox to \vsize
+ {\scratchcounter#1%
+ \advance\scratchcounter -#2%
+ \advance\scratchcounter \plusone
+ \leaders\hrule\vskip\zeropoint\!!plus\scratchcounter\!!fill
+ \hrule\!!width#4\!!height\zeropoint\!!depth\zeropoint
+ \vskip\zeropoint\!!plus #3\!!fill
+ \vskip\zeropoint\!!plus-#1\!!fill}}
+
+\newbox\commentbox
+
+\def\doflushcommentanchors
+ {\let\next\relax % new
+ \processaction
+ [\@@cclocation]
+ [% \v!text=>\let\next\relax, % new
+ \v!inmargin=>\let\next\inmargin, % brr not the same as inleft|rightmargin
+ \v!leftedge=>\let\next\inleftedge,
+ \v!rightedge=>\let\next\inrightedge,
+ \v!leftmargin=>\let\next\inleftmargin,
+ \v!rightmargin=>\let\next\inrightmargin]%
+ \next{\hbox{\raise\strutht\box\commentbox}}}
+
+\def\flushcommentanchors % in everypar so indirect
+ {\ifvoid\commentbox\else \doflushcommentanchors \fi}
+
+\def\setupcomment
+ {\dodoubleargument\getparameters[\??cc]}
+
+\setvalue{\e!start\v!comment}% the dummy triple gobbles trailing spaces
+ {\dotripleempty\dostartcommentaar}
+
+\def\comment
+ {\dodoubleempty\docomment}
+
+\def\dodocomment#1%
+ {\!!widtha\@@ccwidth
+ \!!heighta\@@ccheight
+ \doifelse\@@ccoption\v!max
+ {\let\@@ccopen \!!plusone}{\let\@@ccopen \!!zerocount}%
+ \doifelse\@@ccoption\v!buffer
+ {\let\@@cccollect\!!plusone}{\let\@@cccollect\!!zerocount}%
+ \preparecommentvariables
+ \doinsertcomment
+ \@@cctitle\!!widtha\!!heighta
+ \@@cccolor\@@ccopen\@@ccsymbol
+ \@@cccollect{#1}}
+
+\def\preparecommentvariables % more will move here as with fields
+ {\let\@@DriverCommentLayer\@@cctextlayer}
+
+\def\dopreparecommentaar#1#2%
+ {\doifassignmentelse{#1}
+ {\getparameters[\??cc][#1]}
+ {\getparameters[\??cc][\c!title=#1,#2]}%
+ \obeylines
+ \doif\@@ccspace\v!yes\obeyspaces}
+
+\def\dostartcommentaar[#1][#2][#3]%
+ {\bgroup
+ \doifelse\@@ccstate\v!start
+ {\dopreparecommentaar{#1}{#2}%
+ \long\def\docommand##1%
+ {\global\setbox\commentbox\frozenhbox
+ {\hbox to \zeropoint
+ {\struttedbox{\tbox{\dodocomment{##1}}}\hss}%
+ \hskip\ifvoid\commentbox\@@ccmargin\else\@@ccdistance\fi
+ \box\commentbox}%
+ \egroup}}%
+ {\long\def\docommand##1%
+ {\egroup}}%
+ \grabuntil{\e!stop\v!comment}\docommand}
+
+\letvalue{\e!stop\v!comment}\relax % handy for \expanded{...}
+
+\def\docomment[#1][#2]#3%
+ {\doif\@@ccstate\v!start
+ {\hbox to \zeropoint
+ {\dopreparecommentaar{#1}{#2}%
+ \hskip-\@@ccmargin
+ \struttedbox{\tbox{\dodocomment{#3}}\hss}}}%
+ \ignorespaces}
+
+% \startcomment
+% hello beautiful\\world
+% \stopcomment
+%
+% \startcomment[hello]
+% hello << \'e\'erste >>
+% beautiful
+% world
+% \stopcomment
+%
+% \startcomment[hello][color=green,width=4cm,height=3cm]
+% hello \leftguillemot\ \'e\'erste \rightguillemot\
+% beautiful
+% world
+% \stopcommentaar
+%
+% \startcomment[hello][color=green,width=4cm,height=3cm]
+% hello \leftguillemot\ \'e\'erste \rightguillemot\ test
+%
+% beautiful
+%
+% world
+% \stopcomment
+%
+% \startcomment[symbol=Balloon]
+% Do we want this kind of rubish? And, why isn't this and
+% some more features related to text annotations so poorly
+% (actually not) documented? Anyhow, by providing this
+% functionality we demonstrate that \pdfTeX\ can do it. By
+% the way, it's funny that when in Acrobat we scale up the
+% text, the symbols scale down.
+% \stopcomment
+
+% \definesymbol [comment-normal][{\externalfigure[cow.pdf]}]
+% \definesymbol [comment-down] [{\externalfigure[cow.pdf]}]
+%
+% \def\CowSymbol#1#2%
+% {\scale
+% [\c!height=#1]
+% {\startMPcode
+% loadfigure "koe.mp" number 1 ;
+% refill currentpicture withcolor #2 ;
+% \stopMPcode}}
+%
+% \definesymbol [comment-normal]
+% [\CowSymbol{4ex}{red}]
+%
+% \definesymbol [comment-down]
+% [\CowSymbol{4ex}{green}]
+%
+% \setupcomment
+% [\c!symbol={comment-normal,comment-down},
+% \c!option=\v!buffer]
+%
+% \setupfootertexts[\placecomments]
+
+\def\placecomments
+ {\doflushcomments}
+
+% \setupinteraction[state=start]
+%
+% \useattachment[test.tex]
+% \useattachment[whatever][test.tex]
+% \useattachment[whatever][newname][test.tex]
+% \useattachment[whatever][title][newname][test.tex]
+%
+% % \setupattachments[\c!symbol={symbol-normal,symbol-down}]
+%
+% \starttext \attachment[whatever] \stoptext
+
+\definesystemvariable{at}
+
+\def\useattachment
+ {\doquadrupleempty\douseattachment}
+
+\def\douseattachment[#1][#2][#3][#4]% tag title newname filename
+ {\iffourthargument
+ \setgvalue{\??at:#1}{{#2}{#3}{#4}}% tooltip kind of case
+ \else\ifthirdargument
+ \setgvalue{\??at:#1}{{#2}{#2}{#3}}% full path case
+ \else\ifsecondargument
+ \setgvalue{\??at:#1}{{#2}{#2}{#2}}% obvious case
+ \else
+ \setgvalue{\??at:#1}{{#1}{#1}{#1}}% worst case
+ \fi\fi\fi}
+
+\let\attachmenttitle\empty
+\let\attachmentname \empty
+\let\attachmentfile \empty
+
+\def\getattachmentdata[#1]%
+ {\edef\attachmenttitle{\filterfromvalue{\??at:#1}31}% description
+ \edef\attachmentname {\filterfromvalue{\??at:#1}32}% new name
+ \edef\attachmentfile {\filterfromvalue{\??at:#1}33}% original
+ \expandafter\splitstring\attachmentname\at.\to\!!stringa\and\!!stringb
+ \ifx\!!stringb\empty % no suffix, so we need to inherit it
+ \expandafter\splitstring\attachmentfile\at.\to\!!stringc\and\!!stringd
+ \edef\attachmentname{\attachmentname.\!!stringd}%
+ \fi}
+
+\def\attachment
+ {\dodoubleempty\doattachment}
+
+\def\doattachment[#1][#2]% currently title equals newname
+ {\iflocation
+ \ifsecondargument
+ \doifundefined{\??at:#2}
+ {\showmessage\m!interactions6{#2}%
+ \useattachment[#2]}%
+ \doif\@@atstate\v!start
+ {\bgroup
+ \getattachmentdata[#2]%
+ \doiffileelse\attachmentfile
+ {\setupattachments[#1]%
+ \presetattachmentvariables
+\struttedbox{\tbox{%
+ \doattachfile
+ \attachmenttitle
+ {1em}\strutheight\strutdepth\@@atcolor\@@atsymbol
+ \attachmentname
+ \attachmentfile}%
+}}%
+ {\showmessage\m!interactions5\attachmentfile}%
+ \egroup}%
+ \else\iffirstargument
+ \attachment[][#1]%
+ \fi\fi
+ \fi}
+
+\def\presetattachmentvariables
+ {\let\@@DriverAttachmentLayer\@@attextlayer}
+
+\def\setupattachments
+ {\dodoubleempty\getparameters[\??at]}
+
+\setupattachments
+ [\c!state=\v!start,
+ \c!color=\@@iacolor,
+ \c!textlayer=,
+ \c!symbol=]
+
+% jammer, tussen/midden had erin gemoeten; \c!commando toevoegen
+
+\def\registermenucommand#1%
+ {{\textonly\noindent#1\space}} % no math switching
+
+\def\doregistermenubuttons[#1][#2]% [menu id] [register]
+ {\bgroup
+ \ifsecondargument
+ \setupinteractionmenu
+ [#1][\c!unknownreference=\v!yes,\c!samepage=\v!yes]%
+ \def\docommand##1%
+ {\registermenucommand{\menubutton[#1]{##1}[#2:##1]}}%
+ \else
+ \def\docommand##1%
+ {\registermenucommand
+ {\button
+ [\c!unknownreference=\v!yes,\c!samepage=\v!yes]
+ {##1}[#1:##1]}}%
+ \fi
+ \handletokens abcdefghijklmnopqrstuvwxyz\with\docommand % moet anders
+ \egroup}
+
+\def\registermenubuttons
+ {\dodoubleempty\doregistermenubuttons}
+
+\stelkoppelingenin
+ [\c!distance=.25em,
+ \c!width=\v!fit,
+ \c!location=\v!low,
+ \c!color=\@@iacolor,
+ \c!frame=\v!off,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=]
+
+\defineinteractionmenu
+ [\v!right]
+ [\v!right]
+ [\c!before=,
+ \c!after=\vfil,
+ \c!inbetween=\blank,
+ \c!distance=\bodyfontsize, % 12pt
+ \c!left=\hss,
+ \c!right=\hss,
+ \c!width=\rightedgewidth,
+ \c!height=\v!broad]
+
+\defineinteractionmenu
+ [\v!left]
+ [\v!left]
+ [\c!before=,
+ \c!after=\vfil,
+ \c!inbetween=\blank,
+ \c!distance=\bodyfontsize, % 12pt
+ \c!left=\hss,
+ \c!right=\hss,
+ \c!width=\leftedgewidth,
+ \c!height=\v!broad]
+
+\defineinteractionmenu
+ [\v!bottom]
+ [\v!bottom]
+ [\c!before=\vss,
+ \c!after=\vss,
+ \c!middle=\hfil,
+ \c!distance=\bodyfontsize, % 12pt
+ \c!width=\v!fit,
+ \c!height=\v!broad]
+
+\defineinteractionmenu
+ [\v!top]
+ [\v!top]
+ [\c!before=\vss,
+ \c!after=\vss,
+ \c!middle=\hfil,
+ \c!distance=\bodyfontsize, % 12pt
+ \c!width=\v!fit,
+ \c!height=\v!broad]
+
+\setupinteractionmenu
+ [\v!left,\v!right,\v!top,\v!bottom]
+ [\c!offset=.25em,
+ \c!position=\v!no,
+ \c!frame=\v!on,
+ \c!background=,
+ \c!backgroundcolor=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!style=\@@iastyle,
+ \c!color=\@@iacolor,
+ \c!contrastcolor=\@@iacontrastcolor,
+ \c!state=\v!start,
+ \c!samepage=\v!yes,
+ \c!unknownreference=\v!empty,
+ \c!topoffset=\!!zeropoint,
+ \c!bottomoffset=\!!zeropoint,
+ \c!leftoffset=\!!zeropoint,
+ \c!rightoffset=\!!zeropoint]
+
+\def\placeleftedgetextblock % Is \hss/\hsize really needed here?
+ {\hbox to \leftedgewidth % (check outer level and settings)
+ {\hsize\leftedgewidth\hss\interactionmenus[\v!left]}}
+
+\def\placerightedgetextblock % Is \hss/\hsize really needed here?
+ {\hbox to \rightedgewidth % (check outer level and settings)
+ {\hsize\rightedgewidth\interactionmenus[\v!right]\hss}}
+
+\def\placetoptextblock
+ {\vbox to \topheight
+ {\vsize\topheight
+ \csname\??tk\v!top\c!before\endcsname
+ \interactionmenus[\v!top]%
+ \csname\??tk\v!top\c!after\endcsname
+ \kern\zeropoint}}
+
+\def\placebottomtextblock
+ {\vbox to \bottomheight
+ {\vsize\bottomheight
+ \csname\??tk\v!bottom\c!before\endcsname
+ \interactionmenus[\v!bottom]%
+ \csname\??tk\v!bottom\c!after\endcsname
+ \kern\zeropoint}}
+
+\ifx\leftedgetextcontent\undefined \else
+
+ \appendtoks \placeleftedgetextblock \hskip-\leftedgewidth \to \leftedgetextcontent
+ \appendtoks \placerightedgetextblock \hskip-\rightedgewidth \to \rightedgetextcontent
+ \appendtoks \placetoptextblock \vskip-\topheight \to \toptextcontent
+ \appendtoks \placebottomtextblock \vskip-\bottomheight \to \bottomtextcontent
+
+\fi
+
+\setupinteractionscreen
+ [\c!width=\printpaperwidth,
+ \c!height=\printpaperheight,
+ \c!horoffset=\!!zeropoint,
+ \c!veroffset=\!!zeropoint,
+ \c!backspace=\backspace,
+ \c!topspace=\topspace,
+ \c!option=\v!min,
+ \c!delay=\v!none]
+
+\setupbuttons
+ [\c!state=\v!start,
+ \c!width=\v!fit,
+ \c!height=\v!broad,
+ \c!offset=0.25em,
+ \c!frame=\v!on,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=,
+ \c!style=\@@iastyle,
+ \c!color=\@@iacolor,
+ \c!contrastcolor=\@@iacontrastcolor,
+ \c!samepage=\v!yes,
+ \c!unknownreference=\v!yes]
+
+\setupinteractionbar
+ [\c!state=\v!start,
+ \c!alternative=a,
+ \c!symbol=\v!no,
+ \c!width=\rightedgewidth,
+ \c!height=, % these are taken care
+ \c!depth=, % of at calling time
+ \c!distance=.5em, % beter relateren aan breedte
+ \c!step=1,
+ \c!color=\@@iacolor,
+ \c!contrastcolor=\@@iacontrastcolor,
+ \c!frame=\v!on,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=,
+ \c!samepage=\v!yes,
+ \c!unknownreference=\v!yes]
+
+\setupsynchronizationbar
+ [\c!alternative=\v!page,
+ \c!width=\rightedgewidth,
+ \c!style=\@@iastyle,
+ \c!color=\@@iacolor,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=]
+
+\setupsynchronization
+ [\c!state=\v!stop]
+
+\setupprofiles
+ [\c!option=]
+
+\setuppagetransitions
+ [\v!reset]
+
+\setupcomment
+ [\c!state=\v!start,
+ \c!margin=2.5em,
+ \c!distance=1em,
+ \c!width=.3\textwidth,
+ \c!height=.2\textheight,
+ \c!color=\@@iacolor,
+ \c!title=,
+ \c!space=\v!no,
+ \c!symbol=\v!normal,
+ \c!location=\v!inmargin,
+ \c!option=,
+ \c!textlayer=]
+
+\setupversions % beware, @ is made active here,
+ [\c!number=1, % therefore we set this one at the end
+ \c!style=\ss,
+ \c!color=]
+
+\protect \endinput
diff --git a/tex/context/base/core-itm.tex b/tex/context/base/core-itm.tex
index 1c8744d5b..406f9d1e4 100644
--- a/tex/context/base/core-itm.tex
+++ b/tex/context/base/core-itm.tex
@@ -14,39 +14,23 @@
% new: text + lefttext=(,righttext=)
% start=
-\writestatus{loading}{Context Core Macros / Itemgroups}
+\writestatus{loading}{ConTeXt Core Macros / Itemgroups}
-\startmessages dutch library: layouts
- 9: momenteel maximaal -- niveaus in opsommingen
-\stopmessages
+% messages moved
-\startmessages english library: layouts
- 9: currently no more than -- levels in itemizations
-\stopmessages
+% messages moved
-\startmessages german library: layouts
- 9: z.Z. nicht mehr als -- Ebenen in Aufzaehlungen
-\stopmessages
+% messages moved
-\startmessages czech library: layouts
- 9: aktualne ne vice nez -- urovne/urovni vyctu
-\stopmessages
+% messages moved
-\startmessages italian library: layouts
- 9: attualmente non più di -- livelli di elencazione
-\stopmessages
+% messages moved
-\startmessages norwegian library: layouts
- 9: for øyeblikket maksimalt -- nivåer i opplisting
-\stopmessages
+% messages moved
-\startmessages romanian library: layouts
- 9: acum nu se supota mai mult de -- nivele de adancime la iteratii
-\stopmessages
+% messages moved
-\startmessages french library: layouts
- 9: pas plus de -- niveaux pour l'instant dans les élémentarisations
-\stopmessages
+% messages moved
\unprotect
@@ -944,7 +928,7 @@
\ifdim\scratchdimen>\dimen0
\advance\scratchdimen -\dimen0
\else
- \scratchdimen\z@
+ \scratchdimen\zeropoint
\fi
\llap{\hbox to \dimen0{\ifconditional\sublistitem\llap{+}\fi\box8\hss}}% was: \hfill
\hskip\scratchdimen}
diff --git a/tex/context/base/core-job.lua b/tex/context/base/core-job.lua
index 8b45a5783..fb4f76de1 100644
--- a/tex/context/base/core-job.lua
+++ b/tex/context/base/core-job.lua
@@ -6,79 +6,14 @@ if not modules then modules = { } end modules ['core-job'] = {
license = "see context related readme files"
}
--- will move
+local texsprint, texprint, format, find, gmatch = tex.sprint, tex.print, string.format, string.find, string.gmatch
-local texsprint, texprint, format = tex.sprint, tex.print, string.format
-
-commands.writestatus = ctx.writestatus
-
-function commands.doifelse(b)
- if b then -- faster with if than with expression
- texsprint(tex.texcatcodes,"\\firstoftwoarguments")
- else
- texsprint(tex.texcatcodes,"\\secondoftwoarguments")
- end
-end
-function commands.doif(b)
- if b then
- texsprint(tex.texcatcodes,"\\firstofoneargument")
- else
- texsprint(tex.texcatcodes,"\\gobbleoneargument")
- end
-end
-function commands.doifnot(b)
- if b then
- texsprint(tex.texcatcodes,"\\gobbleoneargument")
- else
- texsprint(tex.texcatcodes,"\\firstofoneargument")
- end
-end
-cs.testcase = commands.doifelse
-
-function commands.doifelsespaces(str)
- return commands.doifelse(str:find("^ +$"))
-end
-
-local s = lpeg.splitat(",")
-
-local h = { }
-
-function commands.doifcommonelse(a,b)
- local ha = h[a]
- local hb = h[b]
- if not ha then ha = s:match(a) h[a] = ha end
- if not hb then hb = s:match(b) h[b] = hb end
- for i=1,#ha do
- for j=1,#hb do
- if ha[i] == hb[i] then
- return cs.testcase(true)
- end
- end
- end
- return cs.testcase(false)
-end
-
-function commands.doifinsetelse(a,b)
- local hb = h[b]
- if not hb then hb = s:match(b) h[b] = hb end
- for j=1,#hb do
- if a == hb[i] then
- return cs.testcase(true)
- end
- end
- return cs.testcase(false)
-end
-
-function commands. def(cs,value) texsprint(tex.ctxcatcodes,format( "\\def\\%s{%s}",cs,value)) end
-function commands.edef(cs,value) texsprint(tex.ctxcatcodes,format("\\edef\\%s{%s}",cs,value)) end
-function commands.gdef(cs,value) texsprint(tex.ctxcatcodes,format("\\gdef\\%s{%s}",cs,value)) end
-function commands.xdef(cs,value) texsprint(tex.ctxcatcodes,format("\\xdef\\%s{%s}",cs,value)) end
-
-function commands.cs(cs,args) texsprint(tex.ctxcatcodes,format("\\csname %s\\endcsname %s",cs,args or"")) end
+local ctxcatcodes = tex.ctxcatcodes
+local texcatcodes = tex.texcatcodes
-- main code
-function input.findctxfile(name,maxreadlevel)
+function resolvers.findctxfile(name,maxreadlevel)
local function exists(n)
if io.exists(n) then
return n
@@ -90,7 +25,7 @@ function input.findctxfile(name,maxreadlevel)
end
return nil
end
- if input.aux.qualified_path(name) then
+ if file.is_qualified_path(name) then
return name
else
-- not that efficient, too many ./ lookups
@@ -107,41 +42,40 @@ function input.findctxfile(name,maxreadlevel)
end
end
end
- return input.find_file(name) or ""
+ return resolvers.find_file(name) or ""
end
end
function commands.processfile(name,maxreadlevel)
- name = input.findctxfile(name,maxreadlevel)
+ name = resolvers.findctxfile(name,maxreadlevel)
if name ~= "" then
---~ texsprint(tex.ctxcatcodes,format('\\input {%s}',name)) -- future version
- texsprint(tex.ctxcatcodes,format("\\input %s\\relax",name)) -- we need \input {name}
+ texsprint(ctxcatcodes,format("\\input %s\\relax",name)) -- we need \input {name}
end
end
function commands.doifinputfileelse(name,maxreadlevel)
- commands.doifelse(input.findctxfile(name,maxreadlevel) ~= "")
+ commands.doifelse(resolvers.findctxfile(name,maxreadlevel) ~= "")
end
function commands.locatefilepath(name,maxreadlevel)
- texsprint(tex.texcatcodes,file.dirname(input.findctxfile(name,maxreadlevel)))
+ texsprint(texcatcodes,file.dirname(resolvers.findctxfile(name,maxreadlevel)))
end
function commands.usepath(paths,maxreadlevel)
- input.register_extra_path(paths)
- texsprint(tex.texcatcodes,table.concat(input.instance.extra_paths or {}, ""))
+ resolvers.register_extra_path(paths)
+ texsprint(texcatcodes,table.concat(resolvers.instance.extra_paths or {}, ""))
end
function commands.usesubpath(subpaths,maxreadlevel)
- input.register_extra_path(nil,subpaths)
- texsprint(tex.texcatcodes,table.concat(input.instance.extra_paths or {}, ""))
+ resolvers.register_extra_path(nil,subpaths)
+ texsprint(texcatcodes,table.concat(resolvers.instance.extra_paths or {}, ""))
end
function commands.usezipfile(name,tree)
if tree and tree ~= "" then
- input.usezipfile(format("zip:///%s?tree=%s",name,tree))
+ resolvers.usezipfile(format("zip:///%s?tree=%s",name,tree))
else
- input.usezipfile(format("zip:///%s",name))
+ resolvers.usezipfile(format("zip:///%s",name))
end
end
@@ -162,20 +96,20 @@ local function convertexamodes(str)
local data = xml.content(dk) or ""
local mode = label:match("^mode:(.+)$")
if mode then
- texsprint(tex.ctxcatcodes,format("\\enablemode[%s:%s]",mode,data))
+ texsprint(ctxcatcodes,format("\\enablemode[%s:%s]",mode,data))
end
- texsprint(tex.ctxcatcodes,format("\\setvariable{exa:variables}{%s}{%s}",label,data:gsub("([{}])","\\%1")))
+ texsprint(ctxcatcodes,format("\\setvariable{exa:variables}{%s}{%s}",label,data:gsub("([{}])","\\%1")))
end
end
end
--- we need a system file option: ,. .. etc + paths but no tex lookup so input.find_file is wrong here
+-- we need a system file option: ,. .. etc + paths but no tex lookup so resolvers.find_file is wrong here
function commands.loadexamodes(filename)
if not filename or filename == "" then
- filename = file.stripsuffix(tex.jobname)
+ filename = file.removesuffix(tex.jobname)
end
- filename = input.find_file(file.addsuffix(filename,'ctm')) or ""
+ filename = resolvers.find_file(file.addsuffix(filename,'ctm')) or ""
if filename ~= "" then
commands.writestatus("examodes","loading %s",filename) -- todo: message system
convertexamodes(io.loaddata(filename))
@@ -184,59 +118,72 @@ function commands.loadexamodes(filename)
end
end
+function commands.logoptionfile(name)
+ -- todo: xml if xml logmode
+ local f = io.open(name)
+ if f then
+ texio.write_nl("log","%\n%\tbegin of optionfile\n%\n")
+ for line in f:lines() do
+ texio.write("log",format("%%\t%s\n",line))
+ end
+ texio.write("log","%\n%\tend of optionfile\n%\n")
+ f:close()
+ end
+end
+
--~ set functions not ok and not faster on mk runs either
--~
--~ local function doifcommonelse(a,b)
---~ local ba = a:find(",")
---~ local bb = b:find(",")
+--~ local ba = find(a,",")
+--~ local bb = find(b,",")
--~ if ba and bb then
---~ for sa in a:gmatch("[^ ,]+") do
---~ for sb in b:gmatch("[^ ,]+") do
+--~ for sa in gmatch(a,"[^ ,]+") do
+--~ for sb in gmatch(b,"[^ ,]+") do
--~ if sa == sb then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..sa.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",sa,"}")
--~ return true
--~ end
--~ end
--~ end
--~ elseif ba then
---~ for sa in a:gmatch("[^ ,]+") do
+--~ for sa in gmatch(a,"[^ ,]+") do
--~ if sa == b then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..b.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",b,"}")
--~ return true
--~ end
--~ end
--~ elseif bb then
---~ for sb in b:gmatch("[^ ,]+") do
+--~ for sb in gmatch(b,"[^ ,]+") do
--~ if a == sb then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..a.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
--~ return true
--~ end
--~ end
--~ else
--~ if a == b then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..a.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
--~ return true
--~ end
--~ end
---~ texsprint(tex.ctxcatcodes,"\\let\\commalistelement\\empty")
+--~ texsprint(ctxcatcodes,"\\let\\commalistelement\\empty")
--~ return false
--~ end
--~ local function doifinsetelse(a,b)
---~ local bb = b:find(",")
+--~ local bb = find(b,",")
--~ if bb then
---~ for sb in b:gmatch("[^ ,]+") do
+--~ for sb in gmatch(b,"[^ ,]+") do
--~ if a == sb then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..a.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
--~ return true
--~ end
--~ end
--~ else
--~ if a == b then
---~ texsprint(tex.ctxcatcodes,"\\def\\commalistelement{"..a.."}")
+--~ texsprint(ctxcatcodes,"\\def\\commalistelement{",a,"}")
--~ return true
--~ end
--~ end
---~ texsprint(tex.ctxcatcodes,"\\let\\commalistelement\\empty")
+--~ texsprint(ctxcatcodes,"\\let\\commalistelement\\empty")
--~ return false
--~ end
--~ function commands.doifcommon (a,b) commands.doif (doifcommonelse(a,b)) end
@@ -245,4 +192,3 @@ end
--~ function commands.doifinset (a,b) commands.doif (doifinsetelse(a,b)) end
--~ function commands.doifnotinset (a,b) commands.doifnot (doifinsetelse(a,b)) end
--~ function commands.doifinsetelse (a,b) commands.doifelse(doifinsetelse(a,b)) end
-
diff --git a/tex/context/base/core-job.mkii b/tex/context/base/core-job.mkii
index 3a0f4e2f4..59d8552df 100644
--- a/tex/context/base/core-job.mkii
+++ b/tex/context/base/core-job.mkii
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-job, % copied from main-001,
-%D version=2008.01.25,
+%D version=1997.03.31,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Job Handling,
%D author=Hans Hagen,
@@ -11,8 +11,44 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D This module is still to be split and documented.
+
+\writestatus{loading}{ConTeXt Core Macros / Job Handling}
+
\unprotect
+\let \currentproject \empty
+\let \currentproduct \empty
+\let \currentenvironment \empty
+\let \currentcomponent \empty
+
+\let \loadedfiles \empty
+\let \processedfiles \empty
+
+\let \nomorefiles \relax
+
+\let \allinputpaths \empty
+\let \locatedfilepath \empty
+
+\newcount\textlevel
+\newcount\fileprocesslevel
+
+\setvalue{\c!file::0}{\jobname}
+
+\def\processedfile % is used in styles, don't change !
+ {\getvalue{\c!file::\number\fileprocesslevel}}
+
+\def\dostarttextfile#1%
+ {\global\advance\fileprocesslevel\plusone
+ \setxvalue{\c!file::\number\fileprocesslevel}{#1}%
+ \@EA\doglobal\@EA\addtocommalist\@EA{#1}\processedfiles}
+
+\def\dostoptextfile
+ {\global\advance\fileprocesslevel\minusone}
+
+\def\processlocalfile#1#2%
+ {#1{#2}\donothing{\readfile{#2}\donothing\donothing}}
+
\def\processfile#1%
{\ifx\allinputpaths\empty
\def\next{\processlocalfile\readlocfile}%
@@ -83,4 +119,282 @@
\processcommacommand[\allinputpaths]\docommand
\fi}
+\def\registerfileinfo[#1#2]#3% geen \showmessage ?
+ {\writestatus\m!systems{#1#2 file #3 at line \the\inputlineno}%
+ \immediatewriteutility{f #1 {#3}}}
+
+\ifx\preloadfonts \undefined \let\preloadfonts \relax \fi
+\ifx\preloadspecials\undefined \let\preloadspecials\relax \fi
+
+\def\loadallsystemfiles#1#2%
+ {\ifx\@@svdirectory\empty
+ \readsysfile{#1}{\showmessage\m!systems2{#1}}{#2}%
+ \else% yet undocumented
+ \def\doloadsystemfile##1%
+ {\readsetfile{##1}{#1}{\showmessage\m!systems2{#1}}{#2}}%
+ \processcommacommand[\@@svdirectory]\doloadsystemfile
+ \fi}
+
+\ifx\disableXML\undefined \let\disableXML\relax \fi
+
+\def\loadsystemfiles
+ {\reportprotectionstate
+ \readsysfile\f!newfilename{\showmessage\m!systems2\f!newfilename}\donothing
+ %\readsysfile\f!oldfilename{\showmessage\m!systems2\f!oldfilename}\donothing
+ \loadallsystemfiles\f!filfilename
+ \donothing
+ \loadallsystemfiles\f!sysfilename
+ {\loadallsystemfiles{\f!sysfilename.rme}\donothing % new, fall back
+ \doglobal\appendtoks % brrr better \setcatcodetable\ctxcatcodes % % test
+ \bgroup\disableXML\loadallsystemfiles\f!errfilename\donothing\egroup
+ \to\everygoodbye}}
+
+%D Loading of \type {cont-usr.tex} (edited by the user)
+%D and \type {cont-fmt.tex} (generated by texexec).
+
+\def\loaduserspecifications
+ {% this used to be the file where users can tune their system, especially patterns
+ \readsysfile\f!usrfilename{\showmessage\m!systems2\f!usrfilename}\donothing
+ % this one took care of user preferences (fonts, messages) but lm made this obsolete
+ \readjobfile\f!fmtfilename{\showmessage\m!systems2\f!fmtfilename}\donothing
+ % from now on we preload all patterns (only in mkii)
+ \preloadallpatterns}
+
+\let\loaduserspecifications\relax
+
+%D We don't want multiple jobfiles to interfere.
+
+\def\loadoptionfile
+ {\readjobfile{\jobname.\f!optionextension}
+ {\showmessage\m!systems2{\jobname.\f!optionextension}}%
+ {\writestatus\m!systems {no \jobname.\f!optionextension}}}
+
+% Most natural ...
+%
+% \def\doateverystarttext
+% {\the\everystarttext
+% \global\let\doateverystarttext\relax}
+%
+% ... most practical, since we can load env's in a
+% something.run file (nested \starttext's; see for
+% instance x-res-08, where we definitely want to
+% open the file!).
+
+\def\doateverystarttext
+ {\the\everystarttext
+ \global\everystarttext\emptytoks}
+
+\def\starttext
+ {\doateverystarttext
+ \ifcase\textlevel
+ \registerfileinfo[begin]\jobname
+ \expandafter\startcopyingblocks
+ \fi
+ \global\advance\textlevel\plusone}
+
+\def\stoptext
+ {\global\advance\textlevel\minusone
+ \ifnum\textlevel>\zerocount \else
+ \page[\v!last]\page % new, moved from everybye to here; flushes headers, colors etc etc etc
+ \the\everystoptext
+ %\the\everybye %
+ %\the\everygoodbye % == \end (new)
+ %\expandafter\normalend %
+ \expandafter\finalend
+ \fi}
+
+\def\finalend
+ {\ifnum\textlevel>\zerocount \else
+ \the\everybye
+ \the\everygoodbye
+ \doifsometokselse\everynotabene{\writeline\the\everynotabene\writeline}\donothing
+ \global\everybye \emptytoks % rather unneeded
+ \global\everygoodbye\emptytoks % but for sure
+ \expandafter\normalend
+ \fi}
+
+\let\end\finalend
+
+\def\emergencyend
+ {\writestatus\m!systems{invalid \@EA\string\csname\e!start\v!text\endcsname...\@EA\string\csname\e!stop\v!text\endcsname\space structure}%
+ \stoptext}
+
+\def\currentfile{\inputfilename}
+
+\def\doexecutefileonce#1%
+ {\beforesplitstring#1\at.\to\currentfile
+ \fullexpandtwoargsafter\doifnotinset\currentfile\loadedfiles
+ {\fullexpandoneargafter\addtocommalist\currentfile\loadedfiles
+ \doexecutefile{#1}}}
+
+\def\doexecutefile#1%
+ {\registerfileinfo[begin]{#1}%
+ \dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile
+ \registerfileinfo[end]{#1}}
+
+\def\donotexecutefile#1%
+ {}
+
+\def\verwerkfile#1 %
+ {\doexecutefile{#1}}
+
+\def\useenvironment[#1]% maybe commalist
+ {\environment #1 \relax}
+
+\def\environment #1 % at outermost level only (load only once)
+ {\pushmacro\startenvironment
+ \pushmacro\stopenvironment
+ \def\startenvironment ##1 {}%
+ \let\stopenvironment\relax
+ \startreadingfile
+ \doexecutefileonce{#1}
+ \stopreadingfile
+ \popmacro\stopenvironment
+ \popmacro\startenvironment}
+
+\def\component #1 % at outermost level only
+ {\dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile}
+
+\newcount\filelevel
+
+\let\currentcomponent \v!text
+\let\currentcomponentpath\f!currentpath
+
+\def\donextlevel#1#2#3#4#5#6#7\\%
+ {\pushmacro\currentcomponent
+ \pushmacro\currentcomponentpath
+ \let\currentcomponent#1%
+ \setsystemmode\currentcomponent
+ \splitfilename{#1}%
+ \ifx\splitoffpath\empty
+ \let\currentcomponentpath\f!currentpath
+ \else
+ \let\currentcomponentpath\splitoffpath
+ \fi
+ \beforesplitstring#7\at.\to#2\relax % can become path + base
+ \ifcase\filelevel\relax
+ \starttext
+ \def\project ##1 {#3{##1}}%
+ \def\environment ##1 {#4{##1}}%
+ \def\product ##1 {#5{##1}}%
+ \def\component ##1 {#6{##1}}%
+ \fi
+ \advance\filelevel\plusone
+ \fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
+
+\def\doprevlevel
+ {\popmacro\currentcomponentpath
+ \popmacro\currentcomponent
+ \setsystemmode\currentcomponent
+ \ifnum\filelevel=\plusone
+ \expandafter\stoptext
+ \else
+ \advance\filelevel\minusone
+ \expandafter\endinput
+ \fi}
+
+\def\startproject #1 %
+ {\donextlevel\v!project\currentproject
+ \donotexecutefile\doexecutefileonce
+ \doexecutefileonce\doexecutefile#1\\}
+
+\def\startproduct #1 %
+ {\doateverystarttext
+ \donextlevel\v!product\currentproduct
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startcomponent #1 %
+ {\doateverystarttext
+ \donextlevel\v!component\currentcomponent
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startenvironment #1 %
+ {\donextlevel\v!environment\currentenvironment
+ \donotexecutefile\doexecutefileonce
+ \donotexecutefile\donotexecutefile#1\\}
+
+% \startproject test
+% 1: \startmode[*project] project \stopmode \endgraf
+% 2: \startmode[*product] product \stopmode \endgraf
+% \stopproject
+
+\def\stopproject {\doprevlevel}
+\def\stopproduct {\doprevlevel}
+\def\stopcomponent {\doprevlevel}
+\def\stopenvironment{\doprevlevel}
+
+% more or less replaced by modes
+
+\setvalue{\e!start\v!localenvironment}[#1]%
+ {\let\loadedlocalenvironments\empty
+ \def\docommand##1%
+ {\beforesplitstring##1\at.\to\someevironment
+ \fullexpandoneargafter\addtocommalist\someevironment\loadedlocalenvironments}%
+ \processcommalist[#1]\docommand
+ \fullexpandtwoargsafter\doifcommonelse % no longer next needed
+ {\currentproject,\currentproduct,%
+ \currentcomponent,\currentenvironment}
+ {\loadedlocalenvironments}
+ {\letvalue{\e!stop\v!localenvironment}\relax}
+ {\grabuntil{\e!stop\v!localenvironment}\gobbleoneargument}} % TH: fixed, was \relax
+
+\setvalue{\v!localenvironment}#1 {\doexecutefileonce{#1}}
+
+% NOT TOEVOEGEN: \the\everytrace
+
+\neverypar=\emptytoks
+
+% \appendtoks \flushnotes \to \everypar
+% \appendtoks \synchronizesidefloats \to \everypar
+% \appendtoks \checkindentation \to \everypar
+% \appendtoks \showparagraphnumber \to \everypar
+% \appendtoks \flushmargincontents \to \everypar
+% \appendtoks \flushcommentanchors \to \everypar
+% \appendtoks \synchronizenotes \to \everypar
+
+% \appendtoks \flushnotes \to \everydisplay
+% \appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+% soon, when pdftex 1.22 is out in the field:
+
+\chardef\systemcommandmode\zerocount % 0=unknown 1=disabled 2=enabled
+
+\def\checksystemcommandmode
+ {\ifx\pdfshellescape\undefined \else
+ \chardef\systemcommandmode \ifcase\pdfshellescape \plusone \else \plustwo \fi
+ \fi
+ \global\let\checksystemcommandmode\relax}
+
+\def\reportsystemcommandmode
+ {\ifcase\systemcommandmode
+ \or
+ \writestatus\m!systems{system commands are disabled}%
+ \or
+ \writestatus\m!systems{system commands are enabled}%
+ \fi}
+
+% \ifx\etexversion\undefined \else \ifnum\etexversion<202
+% \prependtoks
+% \writestatus\m!systems{eTeX version \number\etexversion\space -> too old (bugs)}%
+% \writeline
+% \to \everyjob
+% \fi \fi
+
+% \ifx\pdftexversion\undefined \else \ifnum\number\pdftexversion<120
+% \prependtoks
+% \writestatus\m!systems{pdfTeX version \number\pdftexversion\space -> please update}%
+% \writeline
+% \to \everyjob
+% \fi \fi
+
+% Default-instellingen (verborgen)
+
+\resetutilities
+
\protect \endinput
diff --git a/tex/context/base/core-job.mkiv b/tex/context/base/core-job.mkiv
index 2c0f34412..cdb1564f4 100644
--- a/tex/context/base/core-job.mkiv
+++ b/tex/context/base/core-job.mkiv
@@ -1,6 +1,6 @@
%D \module
-%D [ file=core-job,
-%D version=2008.01.25,
+%D [ file=core-job, % copied from main-001,
+%D version=1997.03.31,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Job Handling,
%D author=Hans Hagen,
@@ -11,32 +11,333 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\registerctxluafile{core-job}{1.001}
+%D This module is still to be split and documented.
+
+\writestatus{loading}{ConTeXt Core Macros / Job Handling}
\unprotect
-\def\processfile #1{\ctxlua{commands.processfile("#1",\number\maxreadlevel)}}
-\def\doifinputfileelse#1{\ctxlua{commands.doifinputfileelse("#1",\number\maxreadlevel)}}
-\def\locatefilepath #1{\edef\locatedfilepath{\ctxlua{commands.locatefilepath("#1",\number\maxreadlevel)}}}
-\def\usepath [#1]{\edef\allinputpaths{\ctxlua{commands.usepath("#1")}}}
-\def\usesubpath [#1]{\edef\allinputpaths{\ctxlua{commands.usesubpath("#1")}}}
+\registerctxluafile{core-job}{1.001}
+
+\let \currentproject \empty
+\let \currentproduct \empty
+\let \currentenvironment \empty
+\let \currentcomponent \empty
+
+\let \loadedfiles \empty
+\let \processedfiles \empty
+
+\let \nomorefiles \relax
+
+\let \allinputpaths \empty
+\let \locatedfilepath \empty
+\newcount\textlevel
+\newcount\fileprocesslevel
+
+\setvalue{\c!file::0}{\jobname}
+
+\def\processedfile % is used in styles, don't change !
+ {\getvalue{\c!file::\number\fileprocesslevel}}
+
+\def\dostarttextfile#1%
+ {\global\advance\fileprocesslevel\plusone
+ \setxvalue{\c!file::\number\fileprocesslevel}{#1}%
+ \@EA\doglobal\@EA\addtocommalist\@EA{#1}\processedfiles}
+
+\def\dostoptextfile
+ {\global\advance\fileprocesslevel\minusone}
+
+\def\processlocalfile#1#2%
+ {#1{#2}\donothing{\readfile{#2}\donothing\donothing}}
+
+\def\processfile #1{\ctxlua{commands.processfile("#1",\number\maxreadlevel)}}
+\def\doifinputfileelse #1{\ctxlua{commands.doifinputfileelse("#1",\number\maxreadlevel)}}
+\def\locatefilepath #1{\edef\locatedfilepath{\ctxlua{commands.locatefilepath("#1",\number\maxreadlevel)}}}
+\def\usepath [#1]{\edef\allinputpaths{\ctxlua{commands.usepath("#1")}}}
+\def\usesubpath [#1]{\edef\allinputpaths{\ctxlua{commands.usesubpath("#1")}}}
\def\usezipfile {\dodoubleempty\dousezipfile}
\def\dousezipfile[#1][#2]{\ctxlua{commands.usezipfile("#1","#2")}} % [filename] [optional subtree]
\def\loadexamodes {\dosingleempty\doloadexamodes}
\def\doloadexamodes [#1]{\ctxlua{commands.loadexamodes("#1")}}
-% for the moment here:
+\def\registerfileinfo[#1#2]#3% geen \showmessage ?
+ {\writestatus\m!systems{#1#2 file #3 at line \the\inputlineno}%
+ \immediatewriteutility{f #1 {#3}}}
+
+\ifx\preloadfonts \undefined \let\preloadfonts \relax \fi
+\ifx\preloadspecials\undefined \let\preloadspecials\relax \fi
+
+\def\loadallsystemfiles#1#2%
+ {\ifx\@@svdirectory\empty
+ \readsysfile{#1}{\showmessage\m!systems2{#1}}{#2}%
+ \else% yet undocumented
+ \def\doloadsystemfile##1%
+ {\readsetfile{##1}{#1}{\showmessage\m!systems2{#1}}{#2}}%
+ \processcommacommand[\@@svdirectory]\doloadsystemfile
+ \fi}
+
+\ifx\disableXML\undefined \let\disableXML\relax \fi
+
+\def\loadsystemfiles
+ {\reportprotectionstate
+ \readsysfile\f!newfilename{\showmessage\m!systems2\f!newfilename}\donothing
+ %\readsysfile\f!oldfilename{\showmessage\m!systems2\f!oldfilename}\donothing
+ \loadallsystemfiles\f!filfilename
+ \donothing
+ \loadallsystemfiles\f!sysfilename
+ {\loadallsystemfiles{\f!sysfilename.rme}\donothing % new, fall back
+ \doglobal\appendtoks % brrr better \setcatcodetable\ctxcatcodes % % test
+ \bgroup\disableXML\loadallsystemfiles\f!errfilename\donothing\egroup
+ \to\everygoodbye}}
+
+%D Loading of \type {cont-usr.tex} (edited by the user)
+%D and \type {cont-fmt.tex} (generated by texexec).
+
+% \def\loaduserspecifications
+% {% this used to be the file where users can tune their system, especially patterns
+% \readsysfile\f!usrfilename{\showmessage\m!systems2\f!usrfilename}\donothing
+% % this one took care of user preferences (fonts, messages) but lm made this obsolete
+% \readjobfile\f!fmtfilename{\showmessage\m!systems2\f!fmtfilename}\donothing
+% % from now on we preload all patterns (only in mkii)
+% \preloadallpatterns}
+
+\let\loaduserspecifications\relax
+
+%D We don't want multiple jobfiles to interfere.
+
+\def\loadoptionfile
+ {\readjobfile{\jobname.\f!optionextension}
+ {\showmessage\m!systems2{\jobname.\f!optionextension}%
+ \ctxlua{commands.logoptionfile("\jobname.\f!optionextension")}}%
+ {\writestatus\m!systems {no \jobname.\f!optionextension}}}
+
+% Most natural ...
+%
+% \def\doateverystarttext
+% {\the\everystarttext
+% \global\let\doateverystarttext\relax}
+%
+% ... most practical, since we can load env's in a
+% something.run file (nested \starttext's; see for
+% instance x-res-08, where we definitely want to
+% open the file!).
+
+\def\doateverystarttext
+ {\the\everystarttext
+ \global\everystarttext\emptytoks}
+
+\def\starttext
+ {\doateverystarttext
+ \ifcase\textlevel
+ \registerfileinfo[begin]\jobname
+ \fi
+ \global\advance\textlevel\plusone}
+
+\def\stoptext
+ {\global\advance\textlevel\minusone
+ \ifnum\textlevel>\zerocount \else
+ \page[\v!last]\page % new, moved from everybye to here; flushes headers, colors etc etc etc
+ \the\everystoptext
+ %\the\everybye %
+ %\the\everygoodbye % == \end (new)
+ %\expandafter\normalend %
+ \expandafter\finalend
+ \fi}
+
+\def\finalend
+ {\ifnum\textlevel>\zerocount \else
+ \the\everybye
+ \the\everygoodbye
+ \doifsometokselse\everynotabene{\writeline\the\everynotabene\writeline}\donothing
+ \global\everybye \emptytoks % rather unneeded
+ \global\everygoodbye\emptytoks % but for sure
+ \expandafter\normalend
+ \fi}
+
+\let\end\finalend
+
+\def\emergencyend
+ {\writestatus\m!systems{invalid \@EA\string\csname\e!start\v!text\endcsname...\@EA\string\csname\e!stop\v!text\endcsname\space structure}%
+ \stoptext}
+
+\def\currentfile{\inputfilename}
+
+\def\doexecutefileonce#1%
+ {\beforesplitstring#1\at.\to\currentfile
+ \fullexpandtwoargsafter\doifnotinset\currentfile\loadedfiles
+ {\fullexpandoneargafter\addtocommalist\currentfile\loadedfiles
+ \doexecutefile{#1}}}
+
+\def\doexecutefile#1%
+ {\registerfileinfo[begin]{#1}%
+ \dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile
+ \registerfileinfo[end]{#1}}
+
+\def\donotexecutefile#1%
+ {}
+
+\def\verwerkfile#1 %
+ {\doexecutefile{#1}}
+
+\def\useenvironment[#1]% maybe commalist
+ {\environment #1 \relax}
+
+\def\environment #1 % at outermost level only (load only once)
+ {\pushmacro\startenvironment
+ \pushmacro\stopenvironment
+ \def\startenvironment ##1 {}%
+ \let\stopenvironment\relax
+ \startreadingfile
+ \doexecutefileonce{#1}
+ \stopreadingfile
+ \popmacro\stopenvironment
+ \popmacro\startenvironment}
+
+\def\component #1 % at outermost level only
+ {\dostarttextfile{#1}%
+ \processfile{#1}%
+ \dostoptextfile}
+
+\newcount\filelevel
+
+\let\currentcomponent \v!text
+\let\currentcomponentpath\f!currentpath
+
+\def\donextlevel#1#2#3#4#5#6#7\\%
+ {\pushmacro\currentcomponent
+ \pushmacro\currentcomponentpath
+ \let\currentcomponent#1%
+ \setsystemmode\currentcomponent
+ \splitfilename{#1}%
+ \ifx\splitoffpath\empty
+ \let\currentcomponentpath\f!currentpath
+ \else
+ \let\currentcomponentpath\splitoffpath
+ \fi
+ \beforesplitstring#7\at.\to#2\relax % can become path + base
+ \ifcase\filelevel\relax
+ \starttext
+ \def\project ##1 {#3{##1}}%
+ \def\environment ##1 {#4{##1}}%
+ \def\product ##1 {#5{##1}}%
+ \def\component ##1 {#6{##1}}%
+ \fi
+ \advance\filelevel\plusone
+ \fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
+
+\def\doprevlevel
+ {\popmacro\currentcomponentpath
+ \popmacro\currentcomponent
+ \setsystemmode\currentcomponent
+ \ifnum\filelevel=\plusone
+ \expandafter\stoptext
+ \else
+ \advance\filelevel\minusone
+ \expandafter\endinput
+ \fi}
+
+\def\startproject #1 %
+ {\donextlevel\v!project\currentproject
+ \donotexecutefile\doexecutefileonce
+ \doexecutefileonce\doexecutefile#1\\}
+
+\def\startproduct #1 %
+ {\doateverystarttext
+ \donextlevel\v!product\currentproduct
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startcomponent #1 %
+ {\doateverystarttext
+ \donextlevel\v!component\currentcomponent
+ \doexecutefileonce\doexecutefileonce
+ \donotexecutefile\doexecutefile#1\\}
+
+\def\startenvironment #1 %
+ {\donextlevel\v!environment\currentenvironment
+ \donotexecutefile\doexecutefileonce
+ \donotexecutefile\donotexecutefile#1\\}
+
+% \startproject test
+% 1: \startmode[*project] project \stopmode \endgraf
+% 2: \startmode[*product] product \stopmode \endgraf
+% \stopproject
+
+\def\stopproject {\doprevlevel}
+\def\stopproduct {\doprevlevel}
+\def\stopcomponent {\doprevlevel}
+\def\stopenvironment{\doprevlevel}
+
+% more or less replaced by modes
+
+\setvalue{\e!start\v!localenvironment}[#1]%
+ {\let\loadedlocalenvironments\empty
+ \def\docommand##1%
+ {\beforesplitstring##1\at.\to\someevironment
+ \fullexpandoneargafter\addtocommalist\someevironment\loadedlocalenvironments}%
+ \processcommalist[#1]\docommand
+ \fullexpandtwoargsafter\doifcommonelse % no longer next needed
+ {\currentproject,\currentproduct,%
+ \currentcomponent,\currentenvironment}
+ {\loadedlocalenvironments}
+ {\letvalue{\e!stop\v!localenvironment}\relax}
+ {\grabuntil{\e!stop\v!localenvironment}\gobbleoneargument}} % TH: fixed, was \relax
+
+\setvalue{\v!localenvironment}#1 {\doexecutefileonce{#1}}
+
+% NOT TOEVOEGEN: \the\everytrace
+
+\neverypar=\emptytoks
+
+% \appendtoks \flushnotes \to \everypar
+% \appendtoks \synchronizesidefloats \to \everypar
+% \appendtoks \checkindentation \to \everypar
+% \appendtoks \showparagraphnumber \to \everypar
+% \appendtoks \flushmargincontents \to \everypar
+% \appendtoks \flushcommentanchors \to \everypar
+% \appendtoks \synchronizenotes \to \everypar
+
+% \appendtoks \flushnotes \to \everydisplay
+% \appendtoks \adjustsidefloatdisplaylines \to \everydisplay
+
+% soon, when pdftex 1.22 is out in the field:
+
+\chardef\systemcommandmode\zerocount % 0=unknown 1=disabled 2=enabled
+
+\def\checksystemcommandmode
+ {\ifx\pdfshellescape\undefined \else
+ \chardef\systemcommandmode \ifcase\pdfshellescape \plusone \else \plustwo \fi
+ \fi
+ \global\let\checksystemcommandmode\relax}
+
+\def\reportsystemcommandmode
+ {\ifcase\systemcommandmode
+ \or
+ \writestatus\m!systems{system commands are disabled}%
+ \or
+ \writestatus\m!systems{system commands are enabled}%
+ \fi}
-\def\expdoifelse#1#2{\ctxlua{commands.doifelse(\!!bs#1\!!es==\!!bs#2\!!es)}}
-\def\expdoif #1#2{\ctxlua{commands.doif (\!!bs#1\!!es==\!!bs#2\!!es)}}
-\def\expdoifnot #1#2{\ctxlua{commands.doifnot (\!!bs#1\!!es==\!!bs#2\!!es)}}
+% \ifx\etexversion\undefined \else \ifnum\etexversion<202
+% \prependtoks
+% \writestatus\m!systems{eTeX version \number\etexversion\space -> too old (bugs)}%
+% \writeline
+% \to \everyjob
+% \fi \fi
-% \testfeatureonce{100000}{\doifelse{hello world}{here i am}{}} % 0.3
-% \testfeatureonce{100000}{\expandabledoifelse{hello world}{here i am}{}} % 1.5
+% \ifx\pdftexversion\undefined \else \ifnum\number\pdftexversion<120
+% \prependtoks
+% \writestatus\m!systems{pdfTeX version \number\pdftexversion\space -> please update}%
+% \writeline
+% \to \everyjob
+% \fi \fi
+
+% Default-instellingen (verborgen)
-\def\expdoifcommonelse#1#2{\ctxlua{commands.doifcommonelse("#1","#2")}}
-\def\expdoifinsetelse #1#2{\ctxlua{commands.doifinsetelse("#1","#2")}}
+\resetutilities
\protect \endinput
diff --git a/tex/context/base/core-job.tex b/tex/context/base/core-job.tex
deleted file mode 100644
index ca9ef67c3..000000000
--- a/tex/context/base/core-job.tex
+++ /dev/null
@@ -1,368 +0,0 @@
-%D \module
-%D [ file=core-job, % copied from main-001,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Job Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module is still to be split and documented.
-
-\writestatus{loading}{Context Core Macros / Job Handling}
-
-\loadmarkfile{core-job}
-
-\unprotect
-
-\let \currentproject \empty
-\let \currentproduct \empty
-\let \currentenvironment \empty
-\let \currentcomponent \empty
-
-\let \loadedfiles \empty
-\let \processedfiles \empty
-
-\let \nomorefiles \relax
-
-\let \allinputpaths \empty
-\let \locatedfilepath \empty
-
-\newcount\textlevel
-\newcount\fileprocesslevel
-
-\setvalue{\c!file::0}{\jobname}
-
-\def\processedfile % is used in styles, don't change !
- {\getvalue{\c!file::\number\fileprocesslevel}}
-
-\def\dostarttextfile#1%
- {\global\advance\fileprocesslevel\plusone
- \setxvalue{\c!file::\number\fileprocesslevel}{#1}%
- \@EA\doglobal\@EA\addtocommalist\@EA{#1}\processedfiles}
-
-\def\dostoptextfile
- {\global\advance\fileprocesslevel\minusone}
-
-\def\processlocalfile#1#2%
- {#1{#2}\donothing{\readfile{#2}\donothing\donothing}}
-
-\ifx\processfile \undefined \let\processfile \gobbleoneargument \fi
-\ifx\doifinputfileelse\undefined \let\doifinputfileelse \gobbleoneargument \fi
-\ifx\locatefilepath \undefined \let\locatefilepath \gobbleoneargument \fi
-\ifx\usepath \undefined \def\usepath [#1]{} \fi
-\ifx\usesubpath \undefined \def\usesubpath [#1]{} \fi
-
-\def\registerfileinfo[#1#2]#3% geen \showmessage ?
- {\writestatus\m!systems{#1#2 file #3 at line \the\inputlineno}%
- \immediatewriteutility{f #1 {#3}}}
-
-\ifx\preloadfonts \undefined \let\preloadfonts \relax \fi
-\ifx\preloadspecials\undefined \let\preloadspecials\relax \fi
-
-\def\loadallsystemfiles#1#2%
- {\ifx\@@svdirectory\empty
- \readsysfile{#1}{\showmessage\m!systems2{#1}}{#2}%
- \else% yet undocumented
- \def\doloadsystemfile##1%
- {\readsetfile{##1}{#1}{\showmessage\m!systems2{#1}}{#2}}%
- \processcommacommand[\@@svdirectory]\doloadsystemfile
- \fi}
-
-\ifx\disableXML\undefined \let\disableXML\relax \fi
-
-\def\loadsystemfiles
- {\reportprotectionstate
- \readsysfile\f!newfilename{\showmessage\m!systems2\f!newfilename}\donothing
- %\readsysfile\f!oldfilename{\showmessage\m!systems2\f!oldfilename}\donothing
- \loadallsystemfiles\f!filfilename
- \donothing
- \loadallsystemfiles\f!sysfilename
- {\loadallsystemfiles{\f!sysfilename.rme}\donothing % new, fall back
- \doglobal\appendtoks % brrr better \setcatcodetable\ctxcatcodes % % test
- \bgroup\disableXML\loadallsystemfiles\f!errfilename\donothing\egroup
- \to\everygoodbye}}
-
-%D Loading of \type {cont-usr.tex} (edited by the user)
-%D and \type {cont-fmt.tex} (generated by texexec).
-
-\def\loaduserspecifications
- {% this used to be the file where users can tune their system, especially patterns
- \readsysfile\f!usrfilename{\showmessage\m!systems2\f!usrfilename}\donothing
- % this one took care of user preferences (fonts, messages) but lm made this obsolete
- \readjobfile\f!fmtfilename{\showmessage\m!systems2\f!fmtfilename}\donothing
- % from now on we preload all patterns (only in mkii)
- \preloadallpatterns}
-
-%D We don't want multiple jobfiles to interfere.
-
-\def\loadoptionfile
- {\readjobfile{\jobname.\f!optionextension}
- {\showmessage\m!systems2{\jobname.\f!optionextension}}%
- {\writestatus\m!systems {no \jobname.\f!optionextension}}}
-
-% \newevery \everyjob \EveryJob
-% \appendtoks ... \to \everyjob
-
-\appendtoks \loadsystemfiles \to \everyjob
-\appendtoks \preloadfonts \to \everyjob
-\appendtoks \settopskip \to \everyjob
-\appendtoks \preloadlanguages \to \everyjob
-\appendtoks \preloadspecials \to \everyjob
-\appendtoks \openspecialfile \to \everyjob
-%appendtoks \checkutilityfile \to \everyjob % obsolete
-\appendtoks \openutilities \to \everyjob
-\appendtoks \loadoptionfile \to \everyjob
-%appendtoks \loadtwopassdata \to \everyjob
-\appendtoks \checknotes \to \everyjob % depends on bodyfont
-\appendtoks \initializeMPgraphics \to \everyjob % after loading system files
-
-\appendtoks \page[\v!last] \page \to \everybye
-\appendtoks \ifarrangingpages\poparrangedpages\fi \to \everybye
-\appendtoks \registerfileinfo[end]\jobname \to \everybye
-
-\appendtoks \savenofpages \to \everybye
-\appendtoks \savenofsubpages \to \everybye
-
-\appendtoks \closeutilities \to \everygoodbye
-\appendtoks \stopcopyingblocks \to \everygoodbye
-\appendtoks \closespecialfile \to \everygoodbye
-
-\prependtoks \resetutilities \to \everystarttext % moved 28-02-2002
-\prependtoks \loadtwopassdata \to \everystarttext % moved 28-02-2002
-\appendtoks \checkreferences \to \everystarttext % new 04-12-1999
-
-% Most natural ...
-%
-% \def\doateverystarttext
-% {\the\everystarttext
-% \global\let\doateverystarttext\relax}
-%
-% ... most practical, since we can load env's in a
-% something.run file (nested \starttext's; see for
-% instance x-res-08, where we definitely want to
-% open the file!).
-
-\def\doateverystarttext
- {\the\everystarttext
- \global\everystarttext\emptytoks}
-
-\def\starttext
- {\doateverystarttext
- \ifcase\textlevel
- \registerfileinfo[begin]\jobname
- \expandafter\startcopyingblocks
- \fi
- \global\advance\textlevel\plusone}
-
-\def\stoptext
- {\global\advance\textlevel\minusone
- \ifnum\textlevel>\zerocount \else
- \the\everystoptext
- %\the\everybye %
- %\the\everygoodbye % == \end (new)
- %\expandafter\normalend %
- \expandafter\finalend
- \fi}
-
-\def\finalend
- {\ifnum\textlevel>\zerocount \else
- \the\everybye
- \the\everygoodbye
- \global\everybye \emptytoks % rather unneeded
- \global\everygoodbye\emptytoks % but for sure
- \expandafter\normalend
- \fi}
-
-\let\end\finalend
-
-\def\emergencyend
- {\writestatus\m!systems{invalid \@EA\string\csname\e!start\v!text\endcsname...\@EA\string\csname\e!stop\v!text\endcsname\space structure}%
- \stoptext}
-
-\def\currentfile{\inputfilename}
-
-\def\doexecutefileonce#1%
- {\beforesplitstring#1\at.\to\currentfile
- \fullexpandtwoargsafter\doifnotinset\currentfile\loadedfiles
- {\fullexpandoneargafter\addtocommalist\currentfile\loadedfiles
- \doexecutefile{#1}}}
-
-\def\doexecutefile#1%
- {\registerfileinfo[begin]{#1}%
- \dostarttextfile{#1}%
- \processfile{#1}%
- \dostoptextfile
- \registerfileinfo[end]{#1}}
-
-\def\donotexecutefile#1%
- {}
-
-\def\verwerkfile#1 %
- {\doexecutefile{#1}}
-
-\def\useenvironment[#1]% maybe commalist
- {\environment #1 \relax}
-
-\def\environment #1 % at outermost level only (load only once)
- {\pushmacro\startenvironment
- \pushmacro\stopenvironment
- \def\startenvironment ##1 {}%
- \let\stopenvironment\relax
- \startreadingfile
- \doexecutefileonce{#1}
- \stopreadingfile
- \popmacro\stopenvironment
- \popmacro\startenvironment}
-
-\def\component #1 % at outermost level only
- {\dostarttextfile{#1}%
- \processfile{#1}%
- \dostoptextfile}
-
-\newcount\filelevel
-
-\let\currentcomponent \v!text
-\let\currentcomponentpath\f!currentpath
-
-\def\donextlevel#1#2#3#4#5#6#7\\%
- {\pushmacro\currentcomponent
- \pushmacro\currentcomponentpath
- \let\currentcomponent#1%
- \setsystemmode\currentcomponent
- \splitfilename{#1}%
- \ifx\splitoffpath\empty
- \let\currentcomponentpath\f!currentpath
- \else
- \let\currentcomponentpath\splitoffpath
- \fi
- \beforesplitstring#7\at.\to#2\relax % can become path + base
- \ifcase\filelevel\relax
- \starttext
- \def\project ##1 {#3{##1}}%
- \def\environment ##1 {#4{##1}}%
- \def\product ##1 {#5{##1}}%
- \def\component ##1 {#6{##1}}%
- \fi
- \advance\filelevel\plusone
- \fullexpandoneargafter\addtocommalist{#1}\loadedfiles}
-
-\def\doprevlevel
- {\popmacro\currentcomponentpath
- \popmacro\currentcomponent
- \setsystemmode\currentcomponent
- \ifnum\filelevel=\plusone
- \expandafter\stoptext
- \else
- \advance\filelevel\minusone
- \expandafter\endinput
- \fi}
-
-\def\startproject #1 %
- {\donextlevel\v!project\currentproject
- \donotexecutefile\doexecutefileonce
- \doexecutefileonce\doexecutefile#1\\}
-
-\def\startproduct #1 %
- {\doateverystarttext
- \donextlevel\v!product\currentproduct
- \doexecutefileonce\doexecutefileonce
- \donotexecutefile\doexecutefile#1\\}
-
-\def\startcomponent #1 %
- {\doateverystarttext
- \donextlevel\v!component\currentcomponent
- \doexecutefileonce\doexecutefileonce
- \donotexecutefile\doexecutefile#1\\}
-
-\def\startenvironment #1 %
- {\donextlevel\v!environment\currentenvironment
- \donotexecutefile\doexecutefileonce
- \donotexecutefile\donotexecutefile#1\\}
-
-% \startproject test
-% 1: \startmode[*project] project \stopmode \endgraf
-% 2: \startmode[*product] product \stopmode \endgraf
-% \stopproject
-
-\def\stopproject {\doprevlevel}
-\def\stopproduct {\doprevlevel}
-\def\stopcomponent {\doprevlevel}
-\def\stopenvironment{\doprevlevel}
-
-% more or less replaced by modes
-
-\setvalue{\e!start\v!localenvironment}[#1]%
- {\let\loadedlocalenvironments\empty
- \def\docommand##1%
- {\beforesplitstring##1\at.\to\someevironment
- \fullexpandoneargafter\addtocommalist\someevironment\loadedlocalenvironments}%
- \processcommalist[#1]\docommand
- \fullexpandtwoargsafter\doifcommonelse % no longer next needed
- {\currentproject,\currentproduct,%
- \currentcomponent,\currentenvironment}
- {\loadedlocalenvironments}
- {\letvalue{\e!stop\v!localenvironment}\relax}
- {\grabuntil{\e!stop\v!localenvironment}\gobbleoneargument}} % TH: fixed, was \relax
-
-\setvalue{\v!localenvironment}#1 {\doexecutefileonce{#1}}
-
-% NOT TOEVOEGEN: \the\everytrace
-
-\neverypar=\emptytoks
-
-% \appendtoks \flushnotes \to \everypar
-% \appendtoks \synchronizesidefloats \to \everypar
-% \appendtoks \checkindentation \to \everypar
-% \appendtoks \showparagraphnumber \to \everypar
-% \appendtoks \flushmargincontents \to \everypar
-% \appendtoks \flushcommentanchors \to \everypar
-% \appendtoks \synchronizenotes \to \everypar
-
-% \appendtoks \flushnotes \to \everydisplay
-% \appendtoks \adjustsidefloatdisplaylines \to \everydisplay
-
-% soon, when pdftex 1.22 is out in the field:
-
-\chardef\systemcommandmode\zerocount % 0=unknown 1=disabled 2=enabled
-
-\ifx\pdfshellescape\undefined \else
- \prependtoks
- \chardef\systemcommandmode \ifcase\pdfshellescape \plusone \else \plustwo \fi
- \to \everyjob
-\fi
-
-\appendtoks
- \ifcase\systemcommandmode
- \or
- \writestatus\m!systems{system commands are disabled}%
- \or
- \writestatus\m!systems{system commands are enabled}%
- \fi
-\to \everyjob
-
-\ifx\etexversion\undefined \else \ifnum\etexversion<202
- \prependtoks
- \writestatus\m!systems{eTeX version \number\etexversion\space -> too old (bugs)}%
- \writeline
- \to \everyjob
-\fi \fi
-
-\ifx\pdftexversion\undefined \else \ifnum\number\pdftexversion<120
- \prependtoks
- \writestatus\m!systems{pdfTeX version \number\pdftexversion\space -> please update}%
- \writeline
- \to \everyjob
-\fi \fi
-
-\prependtoks \showcontextbanner \to \everyjob
-
-% Default-instellingen (verborgen)
-
-\resetutilities
-
-\protect \endinput
diff --git a/tex/context/base/core-lme.tex b/tex/context/base/core-lme.tex
index d8c99d8c7..69dc3b7b2 100644
--- a/tex/context/base/core-lme.tex
+++ b/tex/context/base/core-lme.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Last Minute Extensions}
+\writestatus{loading}{ConTeXt Core Macros / Last Minute Extensions}
%D Things that depend on too much other things.
diff --git a/tex/context/base/core-lnt.tex b/tex/context/base/core-lnt.tex
index 0d960decd..ae3200e7a 100644
--- a/tex/context/base/core-lnt.tex
+++ b/tex/context/base/core-lnt.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Line Notes}
+\writestatus{loading}{ConTeXt Core Macros / Line Notes}
%D This module loads on top of the footnote and line numbering macros.
diff --git a/tex/context/base/core-lst.tex b/tex/context/base/core-lst.tex
index d246be3bc..84648f6c9 100644
--- a/tex/context/base/core-lst.tex
+++ b/tex/context/base/core-lst.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Lists}
+\writestatus{loading}{ConTeXt Core Macros / Lists}
\unprotect
@@ -241,6 +241,7 @@
\c!depth=\v!broad,
\c!offset=0.25em,
\c!maxwidth=,
+ \c!align=,
\c!state=\v!start,
\c!coupling=\v!off,
\c!criterium=\v!local,
diff --git a/tex/context/base/core-mak.tex b/tex/context/base/core-mak.tex
index 761f83156..574fb9756 100644
--- a/tex/context/base/core-mak.tex
+++ b/tex/context/base/core-mak.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / General Makeup Commands}
+\writestatus{loading}{ConTeXt Core Macros / General Makeup Commands}
\unprotect
diff --git a/tex/context/base/core-mar.tex b/tex/context/base/core-mar.tex
index 45d12d327..8096793ad 100644
--- a/tex/context/base/core-mar.tex
+++ b/tex/context/base/core-mar.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Markings}
+\writestatus{loading}{ConTeXt Core Macros / Markings}
\unprotect
@@ -108,9 +108,6 @@
\let\nomarking\empty
-\def\doifmarkingelse#1%
- {\doifdefinedelse{\??mk#1}}
-
\def\fetchmark[#1][#2]% % expandable / never use \unexpanded
{\ifcsname\??mk::#1\endcsname % saved mark
\csname\??mk::\??mk::#2\@EA\@EA\@EA\endcsname
diff --git a/tex/context/base/core-mat.tex b/tex/context/base/core-mat.tex
index f7517c445..21f4e60b8 100644
--- a/tex/context/base/core-mat.tex
+++ b/tex/context/base/core-mat.tex
@@ -13,7 +13,7 @@
% engels maken
-\writestatus{loading}{Context Core Macros / Math Fundamentals}
+\writestatus{loading}{ConTeXt Core Macros / Math Fundamentals}
\unprotect
@@ -31,16 +31,10 @@
% \definemessageconstant{math}
-% \startmessages all library: math
-% title: math
-% 1: don't use -- here (line \the\inputlineno)
-% \stopmessages
+% % messages moved
% \def\invalidmathcommand#1{\showmessage\m!math1{#1}}
-% \let\normaleqno \eqno
-% \let\normalleqno\leqno
-
% \appendtoks
% \def\eqno {\invalidmathcommand{\string\eqno }}%
% \def\leqno{\invalidmathcommand{\string\leqno}}%
@@ -55,7 +49,7 @@
% H(K|M,C) = H(K|C) - H(M|C)\eqno{\hbox{(\in{}[eq:keyapp])}}
% \stopformula
-\def\mathortext
+\unexpanded\def\mathortext
{\ifmmode
\expandafter\firstoftwoarguments
\else
@@ -342,11 +336,11 @@
\switchtoformulabodyfont[#2]%
\parskip\formulaparskip
\def\currentformula{#1}%
-% may look better in itemizations
-\doif{\formulaparameter\c!option}\v!middle
- {\def\leftdisplayskip{\zeropoint}%
- \def\rightdisplayskip{\zeropoint}}%
-% this was an experiment
+ % may look better in itemizations
+ \doif{\formulaparameter\c!option}\v!middle
+ {\def\leftdisplayskip{\zeropoint}%
+ \def\rightdisplayskip{\zeropoint}}%
+ % this was an experiment
\doifsomething{\formulaparameter\c!margin}% so we test first
{\dosetleftskipadaption{\formulaparameter\c!margin}%
\edef\leftdisplaymargin{\the\leftskipadaption}}% overloaded
@@ -415,9 +409,11 @@
\beforedisplayspace
\par
\ifvmode
- \verticalstrut
- \vskip-\struttotal
- \vskip-\baselineskip
+ \prevdepth-\maxdimen % texbook pagina 79-80
+ % otherwise problems at the top of a page, don't remove:
+ \verticalstrut
+ \vskip-\struttotal
+ \vskip-\baselineskip
\fi
\fi
$$\setdisplaydimensions
@@ -515,8 +511,6 @@
[\c!indentnext=\v!yes,
\c!alternative=multi]
-% in m-math
-%
% \defineformulaalternative[multi][\begindmath][\enddmath]
%
% \fakewords{20}{40}\epar
@@ -622,8 +616,8 @@
\setupsubformulas
[\c!conversion=\v!character,
-% \c!separator=\@@fmseparator,
- \c!separator=,%AM: for compatibility with \placesubformula
+ %\c!separator=\@@fmseparator,
+ \c!separator=,% AM: for compatibility with \placesubformula
\c!indentnext=\@@fmindentnext]
%D Experimental goodie:
@@ -718,9 +712,6 @@
\def\dispplaceformula[#1]#2$$#3$$%
{\dodoplaceformula[#1]{#2}\dostartformula{}#3\dostopformula}
-\let\normalreqno\eqno
-\let\normalleqno\leqno
-
\let\donestedformulanumber\gobbletwoarguments
\def\dodoplaceformula[#1]#2% messy, needs a clean up
@@ -768,6 +759,8 @@
%D The next code is derived from plain \TEX.
+\newcount\interdisplaylinepenalty \interdisplaylinepenalty=100
+
\newif\ifdt@p
\def\displ@y
@@ -777,7 +770,7 @@
{\noalign
{\ifdt@p
\global\dt@pfalse
- \ifdim\prevdepth>-1000\p@
+ \ifdim\prevdepth>-\thousandpoint
\vskip-\lineskiplimit
\vskip\normallineskiplimit
\fi
@@ -789,7 +782,7 @@
\def\displ@y{\resetdisplaymatheq\normaldispl@y}
-\def\m@th{\mathsurround\z@}
+\def\m@th{\mathsurround\zeropoint} % obsolete
%D Here we implement a basic math alignment mechanism. Numbers
%D are also handled. The macros \type {\startinnermath} and
@@ -1031,7 +1024,7 @@
%D some \PLAIN\ macros.
\def\@@dobig#1#2%
- {{\hbox{$\left#2\vbox\!!to#1\bodyfontsize{}\right.\n@space$}}}
+ {{\hbox{$\left#2\vbox\!!to#1\bodyfontsize{}\right.\nulldelimiterspace\zeropoint\relax\mathsurround\zeropoint$}}}
\def\big {\@@dobig{0.85}}
\def\Big {\@@dobig{1.15}}
@@ -2554,8 +2547,8 @@
\def\startsubstack
{\begingroup
\vcenter\bgroup
- \baselineskip\dimexpr\fontdimen10 \scriptfont\plustwo + \fontdimen12 \scriptfont\plustwo\relax
- \lineskip\plusthree\fontdimen8 \scriptfont\plusthree
+ \baselineskip\mathstacktotal
+ \lineskip\mathstackvgap
\lineskiplimit\lineskip
\let\stopmathmode\relax
\def\NC{\domatrixNC}%
@@ -2863,10 +2856,10 @@
\def\mathboldsymbol#1%
{\preparebinrel{#1}%
\currentbinrel{\mathchoice
- {\hbox{\switchtoformulabodyfont [boldmath]$\m@th#1$}}
- {\hbox{\switchtoformulabodyfont [boldmath]$\m@th#1$}}
- {\hbox{\switchtoformulabodyfont [boldmath,script]$\m@th#1$}}
- {\hbox{\switchtoformulabodyfont[boldmath,scriptscript]$\m@th#1$}}}}
+ {\hbox{\switchtoformulabodyfont [boldmath]$\mathsurround\zeropoint#1$}}
+ {\hbox{\switchtoformulabodyfont [boldmath]$\mathsurround\zeropoint#1$}}
+ {\hbox{\switchtoformulabodyfont [boldmath,script]$\mathsurround\zeropoint#1$}}
+ {\hbox{\switchtoformulabodyfont[boldmath,scriptscript]$\mathsurround\zeropoint#1$}}}}
\def\boldsymbol
{\mathortext\mathboldsymbol\bold}
@@ -2902,6 +2895,7 @@
\def\dealwithmathtextencoding
{\expanded{\everyhbox{\the\everyhbox\noexpand\fastenableencoding{\currentencoding}}}%
+ \expanded{\everyvbox{\the\everyvbox\noexpand\fastenableencoding{\currentencoding}}}%
\def\dealwithmathtextencoding{\let\characterencoding\nocharacterencoding}%
\dealwithmathtextencoding}
diff --git a/tex/context/base/core-mis.tex b/tex/context/base/core-mis.mkii
index de1da7597..e860a537a 100644
--- a/tex/context/base/core-mis.tex
+++ b/tex/context/base/core-mis.mkii
@@ -11,48 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Misc Commands}
+\writestatus{loading}{ConTeXt Core Macros / Misc Commands}
% todo: kleur in legenda + letter
-% Obsolete
-%
-% \startmessages dutch library: systems
-% title: systeem
-% 3: probeer LaTeX eens
-% \stopmessages
-%
-% \startmessages english library: systems
-% title: system
-% 3: try LaTeX
-% \stopmessages
-%
-% \startmessages german library: systems
-% title: system
-% 3: Versuche LaTeX
-% \stopmessages
-%
-% \startmessages czech library: systems
-% title: system
-% 3: zkuste LaTeX
-% \stopmessages
-%
-% \startmessages italian library: systems
-% title: sistema
-% 3: provare LaTeX
-% \stopmessages
-%
-% \startmessages norwegian library: systems
-% title: system
-% 3: forsker LaTeX
-% \stopmessages
-%
-% \startmessages romanian library: systems
-% title: sistem
-% 3: incercati LaTeX
-% \stopmessages
-%
-
% %D You would not expect the next macro in \CONTEXT,
% %D wouldn't you? It's there to warn \LATEX\ users that
% %D something is wrong.
@@ -82,16 +44,16 @@
%appendtoks \def\executesynonym#1#2#3#4{#3}\to\simplifiedcommands
%appendtoks \def\executesort#1#2#3{#3}\to\simplifiedcommands
-\appendtoks \def\ { }\to\simplifiedcommands
-\appendtoks \def\type#1{\string\\\strippedcsname#1}\to\simplifiedcommands
-\appendtoks \def\tex#1{\string\\#1}\to\simplifiedcommands
-\appendtoks \def\TeX{TeX}\to\simplifiedcommands
-\appendtoks \def\ConTeXt{ConTeXt}\to\simplifiedcommands
-\appendtoks \def\MetaPost{MetaPost}\to\simplifiedcommands
-\appendtoks \def\MetaFont{MetaFont}\to\simplifiedcommands
-\appendtoks \def\MetaFun{MetaFun}\to\simplifiedcommands
-%appendtoks \def||{-}\to\simplifiedcommands
-\appendtoks \def|#1|{\ifx#1\empty\empty-\else#1\fi}\to\simplifiedcommands
+\appendtoks \def\ { }\to\simplifiedcommands
+\appendtoks \def\type#1{\letterbackslash\strippedcsname#1}\to\simplifiedcommands
+\appendtoks \def\tex#1{\letterbackslash#1}\to\simplifiedcommands
+\appendtoks \def\TeX{TeX}\to\simplifiedcommands
+\appendtoks \def\ConTeXt{ConTeXt}\to\simplifiedcommands
+\appendtoks \def\MetaPost{MetaPost}\to\simplifiedcommands
+\appendtoks \def\MetaFont{MetaFont}\to\simplifiedcommands
+\appendtoks \def\MetaFun{MetaFun}\to\simplifiedcommands
+%appendtoks \def||{-}\to\simplifiedcommands
+\appendtoks \def|#1|{\ifx#1\empty\empty-\else#1\fi}\to\simplifiedcommands
\appendtoks\let\buildtextaccent\secondoftwoarguments\to\simplifiedcommands
@@ -650,7 +612,6 @@
\def\setuphyphenmark
{\dodoubleargument\getparameters[\??kp]}
-
\def\setuphyphenmark[#1]% sign=normal|wide
{\dodoubleargument\getparameters[\??kp][#1]%
\doifinsetelse\@@kpsign {\v!normal}
@@ -1316,74 +1277,74 @@
% old, will become obsolete or module, replace by bib module
-\defineenumeration
- [@publicatie]
- [\c!location=\v!left,
- \c!width=\@@pbwidth,\c!hang=,\c!sample=,
- \c!before=\@@pbbefore,\c!after=\@@pbafter,\c!inbetween=,
- \c!headstyle=\@@pbheadstyle,\c!style=,
- \c!headcolor=\@@pbheadcolor,\c!color=,
- \c!way=\@@pbway,\c!blockway=\@@pbblockway,
- \c!text=,\c!left=\@@pbleft,\c!right=\@@pbright]
-
-\def\dosetuppublications[#1]%
- {\getparameters[\??pb][#1]}
-
-\def\setuppublications%
- {\dosingleargument\dosetuppublications}
-
-\def\apa@publicatie
- {\doifsomething\@@pb@naam {\@@pb@naam,\space}%
- \doifsomething\@@pb@titel {{\sl\@@pb@titel}.\space}%
- \doifsomething\@@pb@jaar {(\@@pb@jaar).\space}%
- \doifsomething\@@pb@plaats {\@@pb@plaats\doifelsenothing\@@pb@uitgever{.}{:\space}}%
- \doifsomething\@@pb@uitgever{\@@pb@uitgever.}}
-
-\def\normaal@publicatie
- {\@@pb@naam, \@@pb@titel, \@@pb@jaar, \@@pb@pagina, \@@pb@plaats, \@@pb@uitgever.}
-
-\def\complexstartpublicatie[#1]#2\stoppublicatie
- {\bgroup
- \def\dosetpublicatie
- {\processcommalist
- [naam,titel,jaar,plaats,pagina,uitgever]
- \setpublicatie
- \ignorespaces}%
- \def\setpublicatie##1%
- {\letvalue{\??pb @##1}\empty
- \setvalue{##1}####1{\setvalue{\??pb @##1}{####1}\ignorespaces}}%
- \def\getpublicatie%
- {\doifsomething\@@pbalternative{\getvalue{\@@pbalternative @publicatie}}}%
- \doifelse\@@pbnumbering\v!yes
- {\@publicatie[#1]\dosetpublicatie#2\getpublicatie\par}%
- {\@@pbbefore
- \dosetpublicatie\ignorespaces#2\getpublicatie
- \@@pbafter}%
- \egroup}
-
-\definecomplexorsimpleempty\startpublicatie
-
-\def\publication#1[#2]%
- {\@@pbleft\in{#1}[#2]\@@pbright}
-
-\setuppublications
- [\c!numbering=\v!yes,
- \c!alternative=\c!apa,
- \c!width=2em,
- \c!hang=,
- \c!sample=,
- \c!before=,
- \c!after=,
- \c!inbetween=,
- \c!headstyle=,
- \c!headcolor=,
- \c!style=,
- \c!color=,
- \c!blockway=\v!by\v!text,
- \c!way=\v!by\v!text,
- \c!text=,
- \c!left={[},
- \c!right={]}]
+% \defineenumeration
+% [@publicatie]
+% [\c!location=\v!left,
+% \c!width=\@@pbwidth,\c!hang=,\c!sample=,
+% \c!before=\@@pbbefore,\c!after=\@@pbafter,\c!inbetween=,
+% \c!headstyle=\@@pbheadstyle,\c!style=,
+% \c!headcolor=\@@pbheadcolor,\c!color=,
+% \c!way=\@@pbway,\c!blockway=\@@pbblockway,
+% \c!text=,\c!left=\@@pbleft,\c!right=\@@pbright]
+
+% \def\dosetuppublications[#1]%
+% {\getparameters[\??pb][#1]}
+%
+% \def\setuppublications%
+% {\dosingleargument\dosetuppublications}
+%
+% \def\apa@publicatie
+% {\doifsomething\@@pb@naam {\@@pb@naam,\space}%
+% \doifsomething\@@pb@titel {{\sl\@@pb@titel}.\space}%
+% \doifsomething\@@pb@jaar {(\@@pb@jaar).\space}%
+% \doifsomething\@@pb@plaats {\@@pb@plaats\doifelsenothing\@@pb@uitgever{.}{:\space}}%
+% \doifsomething\@@pb@uitgever{\@@pb@uitgever.}}
+%
+% \def\normaal@publicatie
+% {\@@pb@naam, \@@pb@titel, \@@pb@jaar, \@@pb@pagina, \@@pb@plaats, \@@pb@uitgever.}
+%
+% \def\complexstartpublicatie[#1]#2\stoppublicatie
+% {\bgroup
+% \def\dosetpublicatie
+% {\processcommalist
+% [naam,titel,jaar,plaats,pagina,uitgever]
+% \setpublicatie
+% \ignorespaces}%
+% \def\setpublicatie##1%
+% {\letvalue{\??pb @##1}\empty
+% \setvalue{##1}####1{\setvalue{\??pb @##1}{####1}\ignorespaces}}%
+% \def\getpublicatie%
+% {\doifsomething\@@pbalternative{\getvalue{\@@pbalternative @publicatie}}}%
+% \doifelse\@@pbnumbering\v!yes
+% {\@publicatie[#1]\dosetpublicatie#2\getpublicatie\par}%
+% {\@@pbbefore
+% \dosetpublicatie\ignorespaces#2\getpublicatie
+% \@@pbafter}%
+% \egroup}
+%
+% \definecomplexorsimpleempty\startpublicatie
+%
+% \def\publication#1[#2]%
+% {\@@pbleft\in{#1}[#2]\@@pbright}
+%
+% \setuppublications
+% [\c!numbering=\v!yes,
+% \c!alternative=\c!apa,
+% \c!width=2em,
+% \c!hang=,
+% \c!sample=,
+% \c!before=,
+% \c!after=,
+% \c!inbetween=,
+% \c!headstyle=,
+% \c!headcolor=,
+% \c!style=,
+% \c!color=,
+% \c!blockway=\v!by\v!text,
+% \c!way=\v!by\v!text,
+% \c!text=,
+% \c!left={[},
+% \c!right={]}]
% only used at pragma, move from kernel to run time module
@@ -1460,37 +1421,21 @@
% THIS WAS MAIN-003.TEX
-\startmessages dutch library: systems
- 41: externe file -- in groep -- bestaat niet
-\stopmessages
+% messages moved
-\startmessages english library: systems
- 41: external file -- in group -- does not exist
-\stopmessages
+% messages moved
-\startmessages german library: systems
- 41: Externe Datei -- in Gruppe -- existiert nicht
-\stopmessages
+% messages moved
-\startmessages czech library: systems
- 41: externi soubor -- ve skupine -- neexistuje
-\stopmessages
+% messages moved
-\startmessages italian library: systems
- 41: il file esterno -- del gruppo -- non esiste
-\stopmessages
+% messages moved
-\startmessages norwegian library: systems
- 41: ekstern fil -- i gruppe -- eksisterer ikke
-\stopmessages
+% messages moved
-\startmessages romanian library: systems
- 41: fisierul extern -- din grupul -- nu exista
-\stopmessages
+% messages moved
-\startmessages french library: systems
- 41: le fichier externe -- du groupe -- n'existe pas
-\stopmessages
+% messages moved
\definetabulate
[\v!legend]
@@ -1852,8 +1797,6 @@
%D Goody:
-\newevery \everyinsidefloat \relax
-
\appendtoks
\global\resetsystemmode{combination}%
\global\resetsystemmode{pairedbox}%
@@ -2331,8 +2274,8 @@
\fi
\setbox\nextbox\vbox{\hbox{\raise\nextboxdp\flushnextbox}}%
\!!dimena \nextboxht
- \calculatecos\@@rorotation\edef\cos{\calculatedcos\@@rorotation}%
- \calculatesin\@@rorotation\edef\sin{\calculatedsin\@@rorotation}%
+ \setcalculatedcos\cos\@@rorotation
+ \setcalculatedsin\sin\@@rorotation
\@@layerxpos\zeropoint
\@@layerypos\zeropoint
\@@layerxoff\zeropoint
diff --git a/tex/context/base/core-mis.mkiv b/tex/context/base/core-mis.mkiv
new file mode 100644
index 000000000..96d3bd2cd
--- /dev/null
+++ b/tex/context/base/core-mis.mkiv
@@ -0,0 +1,2606 @@
+%D \module
+%D [ file=core-mis,
+%D version=1998.01.29,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Miscelaneous,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Misc Commands}
+
+% todo: kleur in legenda + letter
+
+% %D You would not expect the next macro in \CONTEXT,
+% %D wouldn't you? It's there to warn \LATEX\ users that
+% %D something is wrong.
+% %D
+% %D Obsolete now:
+% %
+% % \def\documentstyle{\showmessage\m!systems3\empty\stoptekst}
+% %
+% % \let\documentclass=\documentstyle
+% %D \macros
+% %D {simplifiedcommands, simplifycommands}
+% %D
+% %D I first needed this simplification in bookmarks. Users can
+% %D add their own if needed.
+
+\unprotect
+
+%D Sometimes (for instance in bookmarks) we need to simplify macro
+%D behaviour, so here is the hook.
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\def\simplifycommands{\the\simplifiedcommands}
+
+%D A possibly growing list:
+
+%appendtoks \def\executesynonym#1#2#3#4{#3}\to\simplifiedcommands
+%appendtoks \def\executesort#1#2#3{#3}\to\simplifiedcommands
+
+\appendtoks \def\ { }\to\simplifiedcommands
+\appendtoks \def\type#1{\letterbackslash\strippedcsname#1}\to\simplifiedcommands
+\appendtoks \def\tex#1{\letterbackslash#1}\to\simplifiedcommands
+\appendtoks \def\TeX{TeX}\to\simplifiedcommands
+\appendtoks \def\ConTeXt{ConTeXt}\to\simplifiedcommands
+\appendtoks \def\MetaPost{MetaPost}\to\simplifiedcommands
+\appendtoks \def\MetaFont{MetaFont}\to\simplifiedcommands
+\appendtoks \def\MetaFun{MetaFun}\to\simplifiedcommands
+%appendtoks \def||{-}\to\simplifiedcommands
+\appendtoks \def|#1|{\ifx#1\empty\empty-\else#1\fi}\to\simplifiedcommands
+
+\appendtoks\let\buildtextaccent\secondoftwoarguments\to\simplifiedcommands
+
+% THIS WAS MAIN-002.TEX
+
+%\def\checkinterlineskip
+% {\ifvmode
+% \ifdim\lastskip>\zeropoint
+% \nointerlineskip
+% \else\ifdim\lastkern>\zeropoint
+% \nointerlineskip
+% \fi\fi
+% \fi}
+
+\def\horitems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \divide\scratchdimen \nofitems
+ \!!counta\zerocount
+ \def\docommand##1%
+ {\advance\!!counta \plusone
+ \processaction
+ [\@@isalign]
+ [ \v!left=>\hbox to \scratchdimen{\strut##1\hss},
+ \v!right=>\hbox to \scratchdimen{\hss\strut##1},
+ \v!middle=>\hbox to \scratchdimen{\hss\strut##1\hss},
+ \v!margin=>\ifnum\!!counta=\plusone\hss\else\hfill\fi
+ \strut##1%
+ \ifnum\!!counta=\nofitems\hss\else\hfill\fi,
+ \s!default=>\hbox to \scratchdimen{\hss\strut##1\hss}, % midden
+ \s!unknown=>\hbox to \scratchdimen{\strut##1\hss}]}% % links
+ \hbox to #1{\hss#2\hss}}
+
+\def\veritems#1#2% #1=breedte #2=commandos
+ {\scratchdimen#1%
+ \def\docommand##1%
+ {\ifdim\scratchdimen<\zeropoint % the - was a signal
+ \hbox to -\scratchdimen{\hss\strut##1}%
+ \else\ifdim\scratchdimen>\zeropoint
+ \hbox to \scratchdimen{\strut##1\hss}%
+ \else
+ \hbox{\strut##1}%
+ \fi\fi}%
+ \vbox{#2}}
+
+\def\dosetupitems[#1]%
+ {\getparameters[\??is][#1]%
+ \doif\@@iswidth\v!unknown
+ {\def\@@iswidth{\hsize}}%
+ \doifconversiondefinedelse\@@issymbol
+ {\def\doitembullet##1{\convertnumber{\@@issymbol}{##1}}}
+ {\doifsymboldefinedelse\@@issymbol
+ {\def\doitembullet##1{\symbol[\@@issymbol]}}{}}}
+
+\def\makeitemsandbullets#1%
+ {\doifelse\@@isn\v!unknown
+ {\getcommalistsize[#1]%
+ \edef\nofitems{\commalistsize}}
+ {\edef\nofitems{\@@isn}}%
+ \setbox0\hbox
+ {\doitems \@@iswidth
+ {\processcommalist[#1]\docommand}}%
+ \setbox2\hbox
+ {\doitems \@@isbulletbreedte
+ {\dorecurse\nofitems
+ {\docommand{\strut\doitembullet\recurselevel}}}}}
+
+\def\dostartitems#1#2#3%
+ {\let\doitems#2%
+ \def\@@isbulletbreedte{#3}%
+ \makeitemsandbullets{#1}%
+ \@@isbefore}
+
+\def\dostopitems
+ {\@@isafter
+ \egroup}
+
+\setvalue{doitems\v!top}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \doifsomething\@@issymbol
+ {\doifnot\@@issymbol\v!none
+ {\box2
+ \@@isinbetween
+ \nointerlineskip}}%
+ \box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!bottom}#1%
+ {\dostartitems{#1}\horitems\@@iswidth
+ \noindent\vbox
+ {\forgetall
+ \box0
+ \doifsomething\@@issymbol
+ {\@@isinbetween
+ \nointerlineskip
+ \box2}}%
+ \dostopitems}
+
+\setvalue{doitems\v!inmargin}#1%
+ {\dostartitems{#1}\veritems{-1.5em}% - is a signal
+ \noindent\hbox{\llap{\box2\hskip\leftmargindistance}\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!left}#1%
+ {\advance\hsize -1.5em%
+ \dostartitems{#1}\veritems{1.5em}%
+ \noindent\hbox{\box2\box0}%
+ \dostopitems}
+
+\setvalue{doitems\v!right}#1%
+ {\dostartitems{#1}\veritems{0em}%
+ \noindent\hbox{\box0\hskip-\wd2\box2}%
+ \dostopitems}
+
+\def\setupitems
+ {\dosingleargument\dosetupitems}
+
+\def\complexitems[#1]%
+ {\bgroup
+ \setupitems[#1]%
+ \parindent\zeropoint
+ \setlocalhsize
+ \hsize\localhsize
+ \dontcomplain
+ %\doifundefined{doitems\@@islocation}%
+ % {\let\@@islocation\v!left}%
+ %\getvalue{doitems\@@islocation}}
+ \executeifdefined{doitems\@@islocation}{\let\@@islocation\v!left}}
+
+\definecomplexorsimpleempty\items
+
+\setupitems
+ [\c!location=\v!left,
+ \c!symbol=5,
+ \c!width=\hsize,
+ \c!align=\v!middle,
+ \c!n=\v!unknown,
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!after=\blank]
+
+% Te zijner tijd [plaats=boven,onder,midden] implementeren,
+% in dat geval moet eerst de maximale hoogte worden bepaald.
+%
+% Overigens kan een en ander mooier met \halign.
+
+% there is quite some historic balast in this mechanism, the next variant
+% is a first cleanup
+
+\let\currentparagraph\empty
+
+\newcount\alcounter \newcount\alnsize \newdimen\alhsize
+
+\def\paragraphparameter#1% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph#1}{\executeifdefined{\??al#1}\empty}}
+
+\def\paragraphcellmeter#1#2% \checkedparameter\??al\currentparagraph#1
+ {\executeifdefined{\??al\currentparagraph\number#1#2}{\paragraphparameter{#2}}}
+
+\def\dodefineparagraphs[#1][#2]%
+ {\edef\currentparagraph{#1}%
+ \setvalue{\s!do\s!next\currentparagraph}%
+ {\def\\{\getvalue\currentparagraph}}%
+ \setvalue\currentparagraph
+ {\getvalue{\s!do\s!next#1}%
+ \dostartparagraphs{#1}}%
+ \setvalue{\e!next\currentparagraph}%
+ {\getvalue{#1}}%
+ \setvalue{\e!start\currentparagraph}%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \letvalue{\s!do\s!next\currentparagraph}\empty
+ \setvalue{\e!stop\currentparagraph}{\getvalue\currentparagraph\egroup}%
+ \getvalue\currentparagraph}%
+ \getparameters[\??al\currentparagraph]%
+ [%\c!n=3,
+ %\c!before=\blank,
+ %\c!after=\blank,
+ %\c!distance=1em,
+ %\c!height=\v!fit,
+ %\c!rule=\v!off,
+ %\c!command=,
+ %\c!align=,
+ %\c!tolerance=\v!tolerant,
+ %\c!rulethickness=\linewidth,
+ %\c!rulecolor=,
+ %\c!style=,
+ %\c!color=,
+ %\c!top=,
+ %\c!top=\vss,
+ %\c!bottom=\vfill,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}%
+ {\setupparagraphs[#1]}%
+ \dorecurse
+ {\paragraphparameter\c!n}
+ {\setupparagraphs
+ [\currentparagraph]
+ [\recurselevel]
+ [\c!width=,
+ %\c!bottom=\paragraphparameter\c!bottom,
+ %\c!top=\paragraphparameter\c!top,
+ %\c!height=\paragraphparameter\c!height,
+ %\c!rule=\paragraphparameter\c!rule,
+ %\c!rulethickness=\paragraphparameter\c!rulethickness,
+ %\c!rulecolor=\paragraphparameter\c!rulecolor,
+ %\c!align=\paragraphparameter\c!align,
+ %\c!tolerance=\paragraphparameter\c!tolerance, % obsolete
+ %\c!distance=\paragraphparameter\c!distance,
+ \c!style=\paragraphparameter\c!style,
+ \c!color=\paragraphparameter\c!color]}%
+ \setupparagraphs[\currentparagraph][1][\c!distance=\zeropoint]}
+
+\def\defineparagraphs
+ {\dodoubleargument\dodefineparagraphs}
+
+\def\dosetupparagraphs[#1][#2][#3]%
+ {\edef\currentparagraph{#1}%
+ \ifsecondargument
+ \doifelse{#2}\v!each
+ {\dorecurse
+ {\paragraphparameter\c!n}
+ {\getparameters[\??al\currentparagraph\recurselevel][#3]}}
+ {\doifelsenothing{#3}
+ {\getparameters[\??al\currentparagraph][#2]}
+ {\def\docommand##1{\getparameters[\??al\currentparagraph##1][#3]}%
+ \processcommalist[#2]\docommand}}%
+ \else
+ \getparameters[\??al][#1]%
+ \fi}
+
+\def\setupparagraphs
+ {\dotripleempty\dosetupparagraphs}
+
+\setupparagraphs
+ [\c!n=3,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!distance=1em,
+ \c!height=\v!fit,
+ \c!rule=\v!off,
+ \c!command=,
+ \c!align=,
+ \c!tolerance=\v!tolerant, % obsolete
+ \c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!style=,
+ \c!color=,
+ \c!top=,
+ \c!top=\vss,
+ \c!bottom=\vfill]
+
+\def\doparagraphrule
+ {\doifelse{\paragraphcellmeter\alcounter\c!rule}\v!on
+ {\linewidth\paragraphcellmeter\alcounter\c!rulethickness
+ \scratchdimen\paragraphcellmeter\alcounter\c!distance
+ \advance\scratchdimen-\linewidth
+ \divide\scratchdimen \plustwo
+ \hskip\scratchdimen
+ \color[\paragraphcellmeter\alcounter\c!rulecolor]{\vrule\!!width\linewidth}%
+ \hskip\scratchdimen}
+ {\hskip\paragraphcellmeter\alcounter\c!distance}}
+
+\def\dostartparagraph
+ {\doifelsenothing{\paragraphcellmeter\alcounter\c!width}
+ {\!!widtha\alhsize
+ \divide\!!widtha \alnsize}
+ {\!!widtha\paragraphcellmeter\alcounter\c!width}%
+ \dostartattributes{\??al\currentparagraph\number\alcounter}\c!style\c!color\empty
+ \doifelse{\paragraphcellmeter\alcounter\c!height}\v!fit
+ {\setbox\scratchbox\vtop}
+ {\setbox\scratchbox\vtop to \paragraphcellmeter\alcounter\c!height}%
+ \bgroup
+ \blank[\v!disable]%
+ \forgetall
+ \paragraphcellmeter\alcounter\c!top
+ \paragraphparameter\c!inner
+ \hsize\!!widtha % setting \wd afterwards removed
+ \paragraphcellmeter\alcounter\c!inner % twice
+ \expanded{\setupalign [\paragraphcellmeter\alcounter\c!align ]}% {normal,verytolerant,stretch}
+ \expanded{\setuptolerance[\paragraphcellmeter\alcounter\c!tolerance]}% obsolete
+ \ignorespaces
+ \endgraf
+ \ignorespaces
+ %
+ % Nadeel van de onderstaande constructie is dat \everypar
+ % binnen een groep kan staan en zo steeds \begstruts
+ % worden geplaatst. Mooi is anders dus moet het anders!
+ %
+ % Hier is \Everypar niet nodig.
+ %
+ \everypar{\begstrut\everypar\emptytoks}%
+ %
+ \nospace % remove + ignore
+ \paragraphcellmeter\alcounter\c!command}
+
+\def\dostopparagraph
+ {\ifvmode
+ \removelastskip
+ \else
+ \unskip\endstrut\endgraf
+ \fi
+ \paragraphcellmeter\alcounter\c!bottom
+ \egroup
+ \ifdim\wd\scratchbox=\zeropoint % no data
+ \wd\scratchbox\!!widtha
+ \fi
+ \box\scratchbox
+ \dostopattributes
+ \ifnum\alcounter<\paragraphparameter\c!n\relax
+ \@EA\doparagraphcell
+ \else
+ \@EA\dostopparagraphs
+ \fi}
+
+\def\doparagraphcell
+ {\global\advance\alcounter \plusone
+ \doifelsenothing{\paragraphcellmeter\alcounter\c!distance}
+ {\ifnum\alcounter=\plusone\else
+ \hskip\paragraphparameter\c!distance
+ \fi}
+ {\ifnum\alcounter=\plusone
+ \hskip\paragraphcellmeter\alcounter\c!distance
+ \else
+ \doparagraphrule
+ \fi}%
+ \letvalue\currentparagraph\dostopparagraph
+ \dostartparagraph}
+
+\def\dostartparagraphs#1%
+ {\bgroup
+ \edef\currentparagraph{#1}%
+ \global\alcounter\zerocount
+ \parindent\zeropoint
+ \setlocalhsize
+ \alhsize\localhsize
+ \alnsize\paragraphparameter\c!n\relax
+ \dorecurse \alnsize
+ {\doifelsenothing{\paragraphcellmeter\recurselevel\c!distance}
+ {\ifnum\recurselevel=\plusone\else
+ \global\advance\alhsize -\paragraphparameter\c!distance
+ \fi}
+ {\global\advance\alhsize -\paragraphcellmeter\recurselevel\c!distance}%
+ \doifsomething{\paragraphcellmeter\recurselevel\c!width}
+ {\global\advance\alnsize \minusone
+ \global\advance\alhsize -\paragraphcellmeter\recurselevel\c!width}}%
+ %whitespace % gaat fout bij \framed
+ \paragraphparameter\c!before
+ \leavevmode % gaat wel goed bij \framed, brrr
+ \setbox\scratchbox\vbox\bgroup\hbox\bgroup\doparagraphcell}
+
+\def\dostopparagraphs
+ {\egroup
+ \egroup
+ \iftrue
+ \hbox{\raise\strutheight\box\scratchbox}% new
+ \else
+ \box\scratchbox % old
+ \fi
+ \par
+ \paragraphparameter\c!after
+ \egroup}
+
+\def\dosetuptab[#1]%
+ {\getparameters[\??ta]
+ [\c!headstyle=\v!normal,
+ \c!headcolor=,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!width=\v!broad,
+ \c!sample={\hskip4em},
+ \c!before=,
+ \c!after=,
+ #1]%
+ \definedescription
+ [tab]
+ [\c!headstyle=\@@taheadstyle,
+ \c!headcolor=\@@tacolor,
+ \c!sample=\@@tasample,
+ \c!width=\@@tawidth,
+ \c!before=\@@tabefore,
+ \c!after=\@@taafter]}
+
+\def\setuptab
+ {\dosingleargument\dosetuptab}
+
+\setuptab
+ [\c!location=\v!left]
+
+% The following macro's are derived from PPCHTEX and
+% therefore take some LaTeX font-switching into account.
+
+\newif\ifloweredsubscripts
+
+% Due to some upward incompatibality of LaTeX to LaTeX2.09
+% and/or LaTeX2e we had to force \@@chemieletter. Otherwise
+% some weird \nullfont error comes up.
+
+\doifundefined{@@chemieletter}{\def\@@chemieletter{\rm}}
+
+\def\beginlatexmathmodehack
+ {\ifmmode
+ \let\endlatexmathmodehack\relax
+ \else
+ \def\endlatexmathmodehack{$}$\@@chemieletter
+ \fi}
+
+\def\setsubscripts
+ {\beginlatexmathmodehack
+ \def\dosetsubscript##1##2##3%
+ {\dimen0=##3\fontexheight##2%
+ \setxvalue{@@\string##1\string##2}{\the##1##2\relax}%
+ ##1##2=\dimen0\relax}%
+ \def\dodosetsubscript##1##2%
+ {\dosetsubscript{##1}{\textfont2}{##2}%
+ \dosetsubscript{##1}{\scriptfont2}{##2}%
+ \dosetsubscript{##1}{\scriptscriptfont2}{##2}}%
+ %dodosetsubscript\mathsupnormal {?}%
+ \dodosetsubscript\mathsubnormal {.7}%
+ \dodosetsubscript\mathsubcombined{.7}%
+ \global\loweredsubscriptstrue
+ \endlatexmathmodehack}
+
+\def\resetsubscripts
+ {\ifloweredsubscripts
+ \beginlatexmathmodehack
+ \def\doresetsubscript##1##2%
+ {\dimen0=\getvalue{@@\string##1\string##2}\relax
+ ##1##2=\dimen0}%
+ \def\dodoresetsubscript##1%
+ {\doresetsubscript{##1}{\textfont2}%
+ \doresetsubscript{##1}{\scriptfont2}%
+ \doresetsubscript{##1}{\scriptscriptfont2}}%
+ %dodoresetsubscript\mathsupnormal
+ \dodoresetsubscript\mathsubnormal
+ \dodoresetsubscript\mathsubcombined
+ \global\loweredsubscriptsfalse
+ \endlatexmathmodehack
+ \fi}
+
+\let\beginlatexmathmodehack = \relax
+\let\endlatexmathmodehack = \relax
+
+\def\chem#1#2#3%
+ {\bgroup
+ \setsubscripts
+ \mathematics{\hbox{#1}_{#2}^{#3}}%
+ \resetsubscripts
+ \egroup}
+
+\unexpanded\def\celsius #1{#1\mathematics{^\circ}C}
+\unexpanded\def\inch {\mathematics{\prime\prime}} % was: \hbox{\rm\char125\relax}
+\unexpanded\def\fraction#1#2{\mathematics{#1\over#2}}
+
+% very dutch
+
+\unexpanded\def\graden {\mathematics{^\circ}}
+
+\def\bedragprefix {\euro\normalfixedspace}
+\def\bedragsuffix {}
+\def\bedragempty {\euro}
+
+\unexpanded\def\bedrag#1%
+ {\strut\hbox\bgroup
+ \let\normalfixedspace\nonbreakablespace
+ \doifelsenothing{#1}
+ {\bedragempty}
+ {\bedragprefix\digits{#1}\bedragsuffix}%
+ \egroup}
+
+% \definieeralineas[test][n=3]
+%
+% \stelalineasin[test][3][breedte=4cm,uitlijnen=links]
+%
+% \startopelkaar
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,--} \\
+% \test hans \\ ton \\ \bedrag{~.~~1,~~} \\
+% \test hans \\ ton \\ \bedrag{~.100,--} \\
+% \test hans \\ ton \\ \subtot{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{1.000,--} \\
+% \test hans \\ ton \\ \totaal{1.000,--} \\
+% \test hans \\ ton \\ \bedrag{nihil,--} \\
+% \test hans \\ ton \\ \totaal{nihil,--} \\
+% \test hans \\ ton \\ \subtot{nihil,--} \\
+% \stopopelkaar
+
+\def\periodswidth {.5em}
+\def\periodsdefault{3} % was 5, but now it's like \unknown
+
+\unexpanded\def\periods
+ {\dosingleempty\doperiods}
+
+\def\doperiods[#1]% todo: also n=,width= or maybe just #1,#2
+ {\dontleavehmode
+ \begingroup
+ \scratchdimen\periodswidth
+ \hbox to \iffirstargument#1\else\periodsdefault\fi \scratchdimen
+ {\leaders\hbox to \scratchdimen{\hss.\hss}\hss}%
+ \endgroup}
+
+\unexpanded\def\unknown
+ {\periods\relax} % relax prevents lookahead for []
+
+% Example by Wolfgang Schuster on the context list:
+%
+% \unexpanded\def\fourdots{{\def\periodswidth{.3em}\periods[4]}}
+%
+% Hello\fourdots\ World\fourdots \par Hello\fourdots\ World.
+
+% compatibility macros
+
+\def\doorsnede
+ {\hbox{\rlap/$\circ$} }
+
+\unexpanded\def\ongeveer
+ {\mathematics\pm}
+
+\chardef\boundarycharactermode\plusone
+
+\def\midboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\leftboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \languageparameter#1%
+ \nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+\def\rightboundarycharacter#1#2%
+ {\ifcase\boundarycharactermode
+ \or
+ \prewordbreak %\nobreak
+ \hskip\hspaceamount\currentlanguage{#2}%
+ \languageparameter#1%
+ \or
+ \languageparameter#1%
+ \fi
+ \chardef\boundarycharactermode\plusone}
+
+% actually this is pretty old, but temporary moved here
+%
+% obsolete:
+
+\def\setuphyphenmark
+ {\dodoubleargument\getparameters[\??kp]}
+
+\def\setuphyphenmark[#1]% sign=normal|wide
+ {\dodoubleargument\getparameters[\??kp][#1]%
+ \doifinsetelse\@@kpsign {\v!normal}
+ {\let\textmodehyphen\normalhyphen \let\textmodehyphendiscretionary\normalhyphendiscretionary}
+ {\let\textmodehyphen\composedhyphen\let\textmodehyphendiscretionary\composedhyphendiscretionary}}
+
+\setuphyphenmark[\c!sign=\v!wide]
+% % \setuphyphenmark[\c!sign=\v!normal]
+
+\definesymbol[\c!lefthyphen] [\languageparameter\c!lefthyphen]
+\definesymbol[\c!righthyphen] [\languageparameter\c!righthyphen]
+\definesymbol[\c!hyphen] [\languageparameter\c!hyphen]
+
+\def\normalhyphen
+ {\hbox{\directsymbol\empty\c!hyphen}}
+
+\def\composedhyphen
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}
+
+\def\normalhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!lefthyphen}}
+ {\hbox{\directsymbol\empty\c!righthyphen}}
+ {\hbox{\directsymbol\empty\c!hyphen}}}
+
+\def\composedhyphendiscretionary
+ {\discretionary
+ {\hbox{\directsymbol\empty\c!leftcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!rightcompoundhyphen}}
+ {\hbox{\directsymbol\empty\c!compoundhyphen}}}
+
+\let\textmodehyphen \composedhyphen
+\let\textmodehyphendiscretionary\composedhyphendiscretionary
+
+\definesymbol[\c!leftcompoundhyphen] [\languageparameter\c!leftcompoundhyphen]
+\definesymbol[\c!rightcompoundhyphen] [\languageparameter\c!rightcompoundhyphen]
+\definesymbol[\c!compoundhyphen] [\languageparameter\c!compoundhyphen]
+
+\definehspace [sentence] [\zeropoint]
+\definehspace [intersentence] [.250em]
+
+\definesymbol
+ [\c!midsentence]
+ [\midboundarycharacter\c!midsentence{sentence}]
+
+\definesymbol
+ [\c!leftsentence]
+ [\leftboundarycharacter\c!leftsentence{sentence}]
+
+\definesymbol
+ [\c!rightsentence]
+ [\rightboundarycharacter\c!rightsentence{sentence}]
+
+\definesymbol
+ [\c!leftsubsentence]
+ [\leftboundarycharacter\c!leftsubsentence{sentence}]
+
+\definesymbol
+ [\c!rightsubsentence]
+ [\rightboundarycharacter\c!rightsubsentence{sentence}]
+
+\newsignal \subsentencesignal
+\newcount \subsentencelevel
+
+\let\beforesubsentence\donothing
+\let\aftersubsentence \donothing
+
+% todo: make this language option
+%
+% \def\beforesubsentence{\removeunwantedspaces}
+% \def\aftersubsentence {\ignorespaces}
+
+\def\midsentence
+ {\symbol[\c!midsentence]}
+
+\def\beginofsubsentence
+ {\beforesubsentence
+ \ifdim\lastkern=\subsentencesignal
+ \unskip
+ \kern\hspaceamount\currentlanguage{intersentence}%
+ \fi
+ \global\advance\subsentencelevel\plusone
+ \ifnum\subsentencelevel=\plusone
+ \dontleavehmode % was \leaveoutervmode
+ \fi
+ \symbol[\ifodd\subsentencelevel\c!leftsentence\else\c!leftsubsentence\fi]%
+ }% \ignorespaces}
+
+\def\endofsubsentence % relax prevents space gobbling
+ {\symbol[\ifodd\subsentencelevel\c!rightsentence\else\c!rightsubsentence\fi]%
+ \global\advance\subsentencelevel\minusone
+ \unskip
+ \kern\subsentencesignal\relax
+ \aftersubsentence}
+
+\def\beginofsubsentencespacing % relax prevents space gobbling
+ {\kern\subsentencesignal\relax}% \ignorespaces}
+
+\def\endofsubsentencespacing
+ {\ifdim\lastkern=\subsentencesignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{intersentence}%
+ % no good, actually language dependent:
+% \ignorespaces
+ \else
+ \unskip
+ \fi}
+
+%D \startbuffer
+%D test |<|test |<|test|>| test|>| test \par
+%D test|<|test|<|test|>|test|>|test \par
+%D test |<||<|test|>||>| test \par
+%D test \directdiscretionary{<}test\directdiscretionary{>} test \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \getbuffer
+
+\def\startsubsentence{\beginofsubsentence \prewordbreak\beginofsubsentencespacing}
+\def\stopsubsentence {\endofsubsentencespacing\prewordbreak\endofsubsentence}
+
+%D \defineXMLenvironment [subsentence]
+%D {|<|}
+%D {|>|}
+%D \defineXMLenvironment [subsentence]
+%D {\directdiscretionary{<}}
+%D {\directdiscretionary{>}}
+%D \defineXMLenvironment [subsentence]
+%D {\startsubsentence}
+%D {\stopsubsentence}
+%D
+%D \startbuffer
+%D test <subsentence>test</subsentence> test
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \processXMLbuffer
+
+\enableactivediscretionaries
+
+\definehspace [quotation] [\zeropoint]
+\definehspace [interquotation] [.125em]
+
+%definehspace [quote] [\zeropoint]
+%definehspace [speech] [\zeropoint]
+
+\definehspace [quote] [\hspaceamount\currentlanguage{quotation}]
+\definehspace [speech] [\hspaceamount\currentlanguage{quotation}]
+
+\definesymbol
+ [\c!leftquotation]
+ [\leftboundarycharacter\c!leftquotation{quotation}]
+
+\definesymbol
+ [\c!rightquotation]
+ [\rightboundarycharacter\c!rightquotation{quotation}]
+
+\definesymbol
+ [\c!leftquote]
+ [\leftboundarycharacter\c!leftquote{quote}]
+
+\definesymbol
+ [\c!rightquote]
+ [\rightboundarycharacter\c!rightquote{quote}]
+
+\definesymbol
+ [\c!leftspeech]
+ [\leftboundarycharacter\c!leftspeech{speech}]
+
+\definesymbol
+ [\c!rightspeech]
+ [\rightboundarycharacter\c!rightspeech{speech}]
+
+\definesymbol
+ [\c!middlespeech]
+ [\leftboundarycharacter\c!middlespeech{speech}]
+
+\appendtoks\def\quotation#1{"#1"}\to\simplifiedcommands
+\appendtoks\def\quote #1{'#1'}\to\simplifiedcommands
+
+%D The next features was so desperately needed by Giuseppe
+%D Bilotta that he made a module for it. Since this is a
+%D typical example of core functionality, I decided to extend
+%D the low level quotation macros in such a way that a speech
+%D feature could be build on top of it. The speech opening and
+%D closing symbols are defined per language. Italian is an
+%D example of a language that has them set.
+
+% this will replace the quotation and speed definitions
+
+\newsignal\delimitedtextsignal
+
+\let\currentdelimitedtext\s!unknown
+
+\def\delimitedtextlevel{\csname\??ci:\currentdelimitedtext:\c!level\endcsname}
+
+\def\doinitializetextlevel#1%
+ {\ifcsname\??ci:#1:\c!level\endcsname
+ \newcount\csname\??ci:#1:\c!level\endcsname\zerocount
+ \else
+ \expandafter\newcount\csname\??ci:#1:\c!level\endcsname
+ \fi}
+
+\def\delimitedtextparameter#1% will be sped up
+ {\executeifdefined{\??ci\currentdelimitedtext:\number\delimitedtextlevel#1}%
+ {\executeifdefined{\??ci\currentdelimitedtext#1}%
+ {\executeifdefined{\??ci#1}\empty}}}
+
+\def\definedelimitedtext
+ {\dodoubleempty\dodefinedelimitedtext}
+
+\def\dodefinedelimitedtext[#1][#2]%
+ {\doinitializetextlevel{#1}%
+ \doifassignmentelse{#2}
+ {\getparameters
+ [\??ci#1]
+ [\c!location=\v!margin, % \v!text \v!paragraph
+ \c!spacebefore=,
+ \c!spaceafter=\delimitedtextparameter\c!spacebefore,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\delimitedtextparameter\c!leftmargin,
+ \c!indentnext=\v!yes,
+ \c!before=,
+ \c!after=,
+ \c!left=,
+ \c!right=,
+ %\c!level=0,
+ \c!repeat=\v!no,
+ \c!method=,
+ #2]}%
+ {\doifdefined{#2}
+ {\copyparameters[\??ci#1][\??ci#2]
+ [\c!location,\c!spacebefore,\c!spaceafter,\c!style,\c!color,
+ \c!leftmargin,\c!rightmargin,\c!indentnext,
+ \c!before,\c!after,\c!left,\c!right]}}%
+ \doifsomething{#1}
+ {\unexpanded\setvalue{#1}{\delimitedtext[#1]}%
+ \setvalue{\e!start#1}{\startdelimitedtext[#1]}%
+ \setvalue{\e!stop #1}{\stopdelimitedtext}}}
+
+\def\setupdelimitedtext
+ {\dotripleargument\dosetupdelimitedtext}
+
+\def\dosetupdelimitedtext[#1][#2][#3]% #2 = optional level
+ {\ifthirdargument
+ \getparameters[\??ci#1:#2][#3]%
+ \else\ifsecondargument
+ \getparameters[\??ci#1][#2]%
+ \else
+ \getparameters[\??ci][#1]%
+ \fi\fi}
+
+\def\dorepeatdelimitedtext
+ {\relax\ifcase\delimitedtextlevel\else
+ \dohandledelimitedtext\c!middle % maybe better \dohandleleftdelimitedtext
+ \fi}
+
+\let\dohandlerepeatdelimitedtext\relax
+
+\def\startdelimitedtext[#1]%
+ {\bgroup
+ \pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\def\dostopdelimitedtext
+ {\removeunwantedspaces\ignoredelimitedtext\c!right}%
+ \ignoredelimitedtext\c!left\ignorespaces}
+ {\doifelse{\delimitedtextparameter\c!repeat}\v!yes
+ {\let\dohandlerepeatdelimitedtext\dorepeatdelimitedtext}%
+ {\let\dohandlerepeatdelimitedtext\relax}%
+ \doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ {\dosingleempty\dostartdelimitedtextpar}\dostartdelimitedtexttxt}}
+
+\def\dostartdelimitedtextpar[#1]%
+ {\let\dostopdelimitedtext\dostopdelimitedtextpar
+ \doifsomething{\delimitedtextparameter\c!spacebefore}
+ {\blank[\delimitedtextparameter\c!spacebefore]}%
+ \delimitedtextparameter\c!before
+ % nicer:
+ % \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ % \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ % backward compatible:
+ \doifelsenothing{#1}
+ {\endgraf
+ \doadaptleftskip {\delimitedtextparameter\c!leftmargin}%
+ \doadaptrightskip{\delimitedtextparameter\c!rightmargin}%
+ \let\dodostopdelimitedtextpar\endgraf}
+ {\startnarrower[#1]\let\dodostopdelimitedtextpar\stopnarrower}%
+ % so far
+ % \dochecknextindentation{\??ci\currentdelimitedtext}% AM: not here
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \leftdelimitedtextmark
+ \ignorespaces}
+
+\def\dostopdelimitedtextpar
+ {\removeunwantedspaces
+ \removelastskip
+ \rightdelimitedtextmark
+ \dostopattributes
+ \dodostopdelimitedtextpar
+ \delimitedtextparameter\c!after
+ \doifsomething{\delimitedtextparameter\c!spaceafter}
+ {\blank[\delimitedtextparameter\c!spaceafter]}%
+ \dochecknextindentation{\??ci\currentdelimitedtext}% AM: here
+ \dorechecknextindentation}% AM: This was missing!
+
+\def\dostartdelimitedtexttxt
+ {\let\dostopdelimitedtext\dostopdelimitedtexttxt
+ \dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color\empty
+ \dohandleleftdelimitedtext\c!left
+ \ignorespaces}
+
+\def\dostopdelimitedtexttxt
+ {\removeunwantedspaces
+ \dohandlerightdelimitedtext\c!right
+ \dostopattributes}
+
+\def\stopdelimitedtext
+ {\dostopdelimitedtext
+ \popdelimitedtext
+ \egroup}
+
+\def\pushdelimitedtext#1%
+ {\globalpushmacro\currentdelimitedtext
+ \def\currentdelimitedtext{#1}%
+ \global\advance\delimitedtextlevel\plusone}
+
+\def\popdelimitedtext
+ {\global\advance\delimitedtextlevel\minusone
+ \globalpopmacro\currentdelimitedtext}
+
+\def\delimitedtext[#1]%
+ {\pushdelimitedtext{#1}%
+ \doifelse{\delimitedtextparameter\c!method}\s!font
+ {\dofontdrivendelimited}
+ {\doifinsetelse{\delimitedtextparameter\c!location}{\v!paragraph,\v!margin}%
+ \dodelimitedtextpar\dodelimitedtexttxt}}
+
+% shortcuts
+
+\def\startdelimited{\startdelimitedtext}
+\def\stopdelimited {\stopdelimitedtext} % no let, dynamically assigned
+\def\delimited {\delimitedtext}
+
+\def\leftdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!left}
+ {\setbox\scratchbox\hbox{\delimitedtextparameter\c!left}%
+ \dontleavehmode
+ \doif{\delimitedtextparameter\c!location}\v!margin{\hskip-\wd\scratchbox}%
+ \box\scratchbox}}
+
+\def\rightdelimitedtextmark
+ {\doifsomething{\delimitedtextparameter\c!right}
+ {\hsmash{\delimitedtextparameter\c!right}}}
+
+% \starttext
+% \hyphenatedword{groepsvrijstellingsverordeningen}\par
+% \hyphenatedword{\quote{groepsvrijstellingsverordeningen}}\par
+% \dorecurse{100}{\hskip300pt\hskip\recurselevel pt test \quote{xxx xxxx}.\par}
+% \page \setuppapersize[A5][A4]
+% \quotation {overly beautiful pusillanimous sesquipedalian
+% longwinded} test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test test test test test test test test test test test
+% test test test
+% \stoptext
+
+\def\dohandledelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+% \ifdim\lastskip=\delimitedtextsignal
+% \unskip
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+% \penalty\plustenthousand % else overfull boxes, but that's better than dangling periods
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandleleftdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \strut % new, needed below
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \hskip\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+\def\dohandlerightdelimitedtext#1#2%
+ {\begingroup
+ \setbox\scratchbox\hbox{\delimitedtextparameter#1}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \ifdim\lastkern=\delimitedtextsignal
+ \unkern
+ \penalty\plustenthousand
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else\ifdim\lastskip=\delimitedtextsignal
+ \unskip
+ \penalty\plustenthousand
+ \hskip\hspaceamount\currentlanguage{interquotation}%
+ \else
+ #2%
+ \fi\fi
+ \ifhmode % else funny pagebeaks
+ \penalty\plustenthousand
+ \hskip\zeropoint % == \prewordbreak
+ \fi
+ \strut % new, needed below
+ \delimitedtextparameter#1% unhbox\scratchbox
+ \kern\delimitedtextsignal % +- \prewordbreak
+ \fi
+ \endgroup}
+
+
+\def\ignoredelimitedtext#1%
+ {\delimitedtextparameter#1}
+
+\def\handledelimitedtext#1%
+ {\dohandledelimitedtext{#1}\relax}
+
+\def\handleleftdelimitedtext#1%
+ {\dohandleleftdelimitedtext{#1}\relax}
+
+\def\handlerightdelimitedtext#1%
+ {\dohandlerightdelimitedtext{#1}\relax}
+
+\unexpanded\def\dodelimitedtextpar
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right\removelastskip
+ \popdelimitedtext}}
+
+\unexpanded\def\dodelimitedtexttxt
+ {\doifelse{\delimitedtextparameter\c!style}\v!normal
+ \doquoteddelimited\doattributeddelimited}
+
+\def\doquoteddelimited
+ {\dohandleleftdelimitedtext\c!left\relax
+ \groupedcommand
+ \donothing
+ {\dohandlerightdelimitedtext\c!right
+ \removelastskip
+ \popdelimitedtext}}
+
+\def\doattributeddelimited
+ {\groupedcommand
+ {\dostartattributes{\??ci\currentdelimitedtext}\c!style\c!color}
+ {\dostopattributes
+ \popdelimitedtext}}
+
+\def\dofontdrivendelimited
+ {\simplegroupedcommand
+ {\languageparameter{\c!left\currentdelimitedtext}}
+ {\languageparameter{\c!right\currentdelimitedtext}%
+ \popdelimitedtext}}
+
+% testcase for nesting:
+%
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+% \setupdelimitedtext[quotation][1][left=(,right=)]
+% \setupdelimitedtext[quotation][2][left={[},right={]}]
+% \setupdelimitedtext[quotation][3][left=\{,right=\}]
+% \quotation{... \quotation{...} ...}
+% \startquotation ... \startquotation... \quotation{...} \stopquotation\space ...\stopquotation
+
+\definedelimitedtext
+ [\v!quotation]
+ [\c!left={\symbol[\c!leftquotation]},
+ \c!right={\symbol[\c!rightquotation]},
+ \c!leftmargin=\v!standard]
+
+\definedelimitedtext
+ [\v!quote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!quote]
+ [\c!location=\v!text,
+ \c!left={\symbol[\c!leftquote]},
+ \c!right={\symbol[\c!rightquote]}]
+
+\definedelimitedtext
+ [\v!blockquote][\v!quotation]
+
+\setupdelimitedtext
+ [\v!blockquote]
+ [\c!left=,
+ \c!right=]
+
+\definedelimitedtext
+ [\v!speech][\v!quotation]
+
+\setupdelimitedtext
+ [\v!speech]
+ [\c!repeat=\v!yes,
+ \c!left={\symbol[\c!leftspeech]},
+ \c!middle={\symbol[\c!middlespeech]},
+ \c!right={\symbol[\c!rightspeech]}]
+
+% how do we call an tight quote
+%
+% \definedelimitedtext
+% [\v!quotation][\v!quotation]
+%
+% \setupdelimitedtext
+% [\v!quotation]
+% [\c!indentnext=\v!no,
+% \c!spacebefore=\v!nowhite]
+
+\def\setupquotation{\setupdelimitedtext[\v!quotation]}
+\def\setupquote {\setupdelimitedtext[\v!quote]}
+
+% seldom used, move from kernel to run time module
+
+\ifx\tfx\undefined \let\tfx\relax \fi
+
+\def\basegrid
+ {\dosingleempty\dobasegrid}
+
+\def\dobasegrid[#1]%
+ {\begingroup
+ \getparameters[\??rt]
+ [\c!x=0,\c!y=0,
+ \c!nx=10,\c!ny=10,
+ \c!dx=.5,\c!dy=.5,
+ \c!xstep=0,\c!ystep=0,
+ \c!unit=\s!cm,
+ \c!scale=1,
+ \c!factor=1,
+ \c!offset=\v!yes,
+ \c!location=\v!left,
+ #1]%
+ \startpositioning
+ \dimen0=\@@rtdx\@@rtunit\relax
+ \dimen0=\@@rtscale\dimen0\relax
+ \dimen0=\@@rtfactor\dimen0\relax
+ \multiply\dimen0 \@@rtnx\relax
+ \dimen2=\@@rtdy\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \multiply\dimen2 \@@rtny\relax
+ \def\horline
+ {\vbox
+ {\hrule
+ \!!width \dimen0
+ \!!height \linewidth
+ \!!depth \!!zeropoint}}%
+ \def\verline%
+ {\vrule
+ \!!width \linewidth
+ \!!height \dimen2
+ \!!depth \!!zeropoint}%
+ \doglobal\newcounter\@@gridc
+ \doglobal\newcounter\@@gridd
+ \doglobal\newcounter\@@gride
+ \def\setlegend##1##2##3%
+ {\gdef\@@gridc{0}%
+ \dimen0=2em\relax
+ \dimen2=##2\@@rtunit\relax
+ \dimen2=\@@rtscale\dimen2\relax
+ \dimen2=\@@rtfactor\dimen2\relax
+ \divide\dimen0 \dimen2\relax
+ \xdef\@@gride{\number\dimen0}%
+ \ifnum\@@gride>50
+ \gdef\@@gride{100}%
+ \else\ifnum\@@gride>10
+ \gdef\@@gride{50}%
+ \else\ifnum\@@gride>5
+ \gdef\@@gride{10}%
+ \else\ifnum\@@gride>1
+ \gdef\@@gride{5}%
+ \else
+ \gdef\@@gride{1}%
+ \fi\fi\fi\fi
+ \gdef\@@gridd{0}%
+ \def\legend
+ {\ifnum\@@gridd=\zerocount
+ \vbox
+ {\increment(\@@gridc,##1)%
+ \hbox to 2em{\hss\@@gridc\hss}}%
+ \global\let\@@gridd=\@@gride
+ \fi
+ \doglobal\decrement\@@gridd
+ \doglobal\increment(\@@gridc,##1)}}%
+ \def\draw##1##2##3##4##5##6##7##8##9%
+ {\setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!absolute,
+ \c!ystep=\v!absolute,
+ \c!unit=\@@rtunit,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!xoffset=##6,
+ \c!yoffset=##7]%
+ \doifelse{##9}\v!middle
+ {\scratchdimen##3pt\scratchdimen.5\scratchdimen
+ \edef\@@psxx{\withoutpt\the\scratchdimen}%
+ \scratchdimen##4pt\scratchdimen.5\scratchdimen
+ \edef\@@psyy{\withoutpt\the\scratchdimen}%
+ \scratchcounter##2\advance\scratchcounter -1
+ \edef\@@pszz{\the\scratchcounter}}
+ {\edef\@@psxx{0}\edef\@@psyy{0}\edef\@@pszz{##2}}%
+ \position(\@@psxx,\@@psyy){##1}%
+ \setuppositioning
+ [\c!state=##8,
+ \c!xstep=\v!relative,
+ \c!ystep=\v!relative,
+ \c!scale=\@@rtscale,
+ \c!factor=\@@rtfactor,
+ \c!offset=\@@rtoffset,
+ \c!unit=\@@rtunit]%
+ \dorecurse\@@pszz{\position(##3,##4){##5}}}%
+ \draw
+ \verline\@@rtnx\@@rtdx0\verline\!!zeropoint\!!zeropoint\v!start\empty
+ \draw
+ \horline\@@rtny0\@@rtdy\horline\!!zeropoint\!!zeropoint\v!start\empty
+ \tfx
+ \doifnot\@@rtxstep{0}
+ {\setlegend\@@rtxstep\@@rtdx\@@rtx
+ \draw\legend\@@rtnx\@@rtdx0\legend{-1em}{-1.5em}\v!overlay\@@rtlocation}%
+ \doifnot\@@rtystep{0}
+ {\setlegend\@@rtystep\@@rtdy\@@rty
+ \draw\legend\@@rtny0\@@rtdy\legend{-2em}{-.75ex}\v!overlay\@@rtlocation}%
+ \stoppositioning
+ \endgroup}
+
+\let\grid\basegrid
+
+% only used at pragma, move from kernel to run time module
+
+\def\referraldate
+ {\currentdate[\v!referral]}
+
+\def\doreferral[#1]%
+ {\noheaderandfooterlines
+ \bgroup
+ \getparameters
+ [\??km]
+ [\c!bet=\unknown,\c!dat=\unknown,\c!ken=\unknown,
+ \c!from=,\c!to=,\c!ref=,#1]%
+ % moet anders, hoort niet in 01b
+ \assigntranslation[\s!nl=referentie,\s!en=reference,\s!de=Referenz,\s!sp=referencia]\to\@@@kmref
+ \assigntranslation[\s!nl=van,\s!en=from,\s!de=Von,\s!sp=de]\to\@@@kmvan
+ \assigntranslation[\s!nl=aan,\s!en=to,\s!de=An,\s!sp=a]\to\@@@kmaan
+ \assigntranslation[\s!nl=betreft,\s!en=concerns,\s!de=Betreff,\s!sp=]\to\@@@kmbet
+ \assigntranslation[\s!nl=datum,\s!en=date,\s!de=Datum,\s!sp=fecha]\to\@@@kmdat
+ \assigntranslation[\s!nl=kenmerk,\s!en=mark,\s!de=Kennzeichen,\s!sp=]\to\@@@kmken
+ %
+ \definetabulate[\s!dummy][|l|p|]
+ \startdummy
+ \NC\@@@kmbet\EQ\@@kmbet\NC\NR
+ \NC\@@@kmdat\EQ\@@kmdat\NC\NR
+ \NC\@@@kmken\EQ\expanded{\smallcapped{\@@kmken}}\NC\NR
+ \doifsomething{\@@kmfrom\@@kmto}{\NC\NC\NC\NR}%
+ \doifsomething \@@kmfrom {\NC\@@@kmvan\EQ\@@kmfrom\NC\NR}%
+ \doifsomething \@@kmto {\NC\@@@kmaan\EQ\@@kmto\NC\NR}%
+ \doifsomething \@@kmref {\NC\NC\NC\NR\NC\@@@kmref\EQ\@@kmref\NC\NR}%
+ \stopdummy
+ \egroup}
+
+\def\referral
+ {\dosingleargument\doreferral}
+
+% FUZZY OLD STUFF: will be removed when not used in some manual;
+% rows instead of columns, i'd forgotten that this code exist
+%
+% \definesystemvariable{ri}
+%
+% \def\setuprows
+% {\dodoubleargument\getparameters[\??ri]}
+%
+% \definecomplexorsimpleempty\startrows
+%
+% \def\complexstartrows[#1]%
+% {\bgroup
+% \setuprows[#1]%
+% \let\do@@ribottom\relax
+% \def\row
+% {\do@@ribottom
+% \egroup
+% \dimen0\vsize
+% \divide\dimen0 \@@rin
+% \advance\dimen0 -\lineskip
+% \vbox to \dimen0
+% \bgroup
+% \@@ritop
+% \let\do@@ribottom\@@ribottom
+% \ignorespaces}%
+% \bgroup
+% \row}
+%
+% \def\stoprows
+% {\do@@ribottom
+% \egroup
+% \egroup}
+%
+% \setuprows
+% [\c!n=2,
+% \c!top=,
+% \c!bottom=\vfill]
+
+% THIS WAS MAIN-003.TEX
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+\definetabulate
+ [\v!legend]
+ [|emj1|i1|mR|]
+
+\setuptabulate
+ [\v!legend]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\leg,EQ={=}]
+
+\definetabulate
+ [\v!legend][\v!two]
+ [|emj1|emk1|i1|mR|]
+
+\definetabulate
+ [\v!fact]
+ [|R|ecmj1|i1mR|]
+
+\setuptabulate
+ [\v!fact]
+ [\c!unit=.75em,\c!inner=\setquicktabulate\fact,EQ={=}]
+
+\unexpanded\def\xbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\tx\let\next=}
+
+\unexpanded\def\xxbox
+ {\bgroup\aftergroup\egroup\hbox\bgroup\txx\let\next=}
+
+% \def\mrm#1%
+% {$\rm#1$}
+
+%D \macros
+%D {definepairedbox, setuppairedbox, placepairedbox}
+%D
+%D Paired boxes, formally called legends, but from now on a
+%D legend is just an instance, are primarily meant for
+%D typesetting some text alongside an illustration. Although
+%D there is quite some variation possible, the functionality is
+%D kept simple, if only because in most cases such pairs are
+%D typeset sober.
+%D
+%D The location specification accepts a pair, where the first
+%D keyword specifies the arrangement, and the second one the
+%D alignment. The first key of the location pair is one of
+%D \type {left}, \type {right}, \type {top} or \type {bottom},
+%D while the second key can also be \type {middle}.
+%D
+%D The first box is just collected in an horizontal box, but
+%D the second one is a vertical box that gets passed the
+%D bodyfont and alignment settings.
+
+%D Today we would implement this using layers .... but for the
+%D moment we keep it this way.
+
+% \startbuffer[test]
+% \test left \test left,top \test left,bottom \test left,middle
+% \test right \test right,top \test right,bottom \test right,middle
+% \test top \test top,left \test top,right \test top,middle
+% \test bottom \test bottom,left \test bottom,right \test bottom,middle
+% \stopbuffer
+%
+% \def\showtest#1%
+% {\pagina
+% \typebuffer[demo]
+% \def\test##1
+% {\startlinecorrection[blank]
+% \getbuffer[demo]%
+% \ruledhbox\placelegend
+% [bodyfont=6pt,location={##1}]
+% {\framed[width=.25\textwidth]{\tttf##1}}
+% {#1}
+% \stoplinecorrection}
+% \getbuffer[test]}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\hsize,maxwidth=\makeupwidth,
+% height=\vsize,maxheight=\makeupheight]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate the default settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=\textwidth,
+% maxwidth=\textwidth]
+% \stopbuffer
+%
+% \showtest{\input tufte }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth]
+% \stopbuffer
+%
+% \showtest{\input knuth }
+%
+% \startbuffer[demo]
+% \setuplegend
+% [height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [width=.65\textwidth,
+% height=2cm]
+% \stopbuffer
+%
+% \showtest{These examples demonstrate some other settings.}
+%
+% \startbuffer[demo]
+% \setuplegend
+% [n=2,align=right,width=.5\textwidth]
+% \stopbuffer
+%
+% \showtest{\input zapf }
+
+%D \macros
+%D {setuplegend, placelegend}
+%D
+%D It makes sense to typeset a legend to a figure in \TEX\
+%D and not in a drawing package. The macro \type {\placelegend}
+%D combines a figure (or something else) and its legend. This
+%D command is just a paired box.
+%D
+%D The legend is placed according to \type {location}, being
+%D \type {bottom} or \type {right}. The macro macro is used as
+%D follows.
+%D
+%D \starttyping
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend
+%D {\externalfigure[cow]}
+%D {\starttabulation[|l|l|l|l|]
+%D \NC 1 \NC head \NC 3 \NC tail \NC \NR
+%D \NC 2 \NC legs \NC \NC \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\starttabulation
+%D \NC 1 \NC head \NC \NR
+%D \NC 2 \NC legs \NC \NR
+%D \NC 3 \NC tail \NC \NR
+%D \stoptabulation}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {head \par legs \par tail}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D
+%D \placefigure
+%D {whow}
+%D {\placelegend[n=2,width=.8\hsize]
+%D {\externalfigure[cow]}
+%D {\startitemize[packed]
+%D \item head \item legs \item tail \item belly \item horns
+%D \stopitemize}}
+%D \stoptyping
+
+\newbox\firstpairedbox
+\newbox\secondpairedbox
+
+\def\definepairedbox
+ {\dodoubleempty\dodefinepairedbox}
+
+\def\dodefinepairedbox[#1][#2]%
+ {\getparameters
+ [\??ld#1]
+ [\c!n=1,
+ \c!distance=\bodyfontsize,
+ \c!before=,
+ \c!after=,
+ \c!color=,
+ \c!style=,
+ \c!inbetween={\blank[\v!medium]},
+ \c!width=\hsize,
+ \c!height=\vsize,
+ \c!maxwidth=\textwidth, % \makeupwidth,
+ \c!maxheight=\textheight, % \makeupheight,
+ \c!bodyfont=,
+ \c!align=,
+ \c!location=\v!bottom,
+ #2]%
+ \setvalue{\e!setup#1\e!endsetup}{\setuppairedbox[#1]}%
+ \setvalue{\e!place#1}{\placepairedbox[#1]}}
+
+\def\setuppairedbox
+ {\dodoubleempty\dosetuppairedbox}
+
+\def\dosetuppairedbox[#1]%
+ {\getparameters[\??ld#1]}
+
+\def\placepairedbox
+ {\bgroup\dodoubleempty\doplacepairedbox}
+
+\def\doplacepairedbox[#1][#2]% watch the hsize/vsize tricks
+ {\setuppairedbox[#1][#2]% % and don't change them
+ \copyparameters % brrr
+ [\??ld][\??ld#1]
+ [\c!n,\c!distance,\c!inbetween,\c!before,\c!after,
+ \c!width,\c!height,\c!maxwidth,\c!maxheight,
+ \c!color,\c!style,\c!bodyfont,\c!align,\c!location]%
+ \@@ldbefore\bgroup
+ \global\setsystemmode{pairedbox}%
+ \beforefirstpairedbox
+ \dowithnextbox
+ {\betweenbothpairedboxes
+ \dowithnextbox
+ {\afterbothpairedboxes
+ \egroup\@@ldafter
+ \egroup}
+ \vbox\bgroup
+ \insidesecondpairedbox
+ \let\next=}
+ \hbox}
+
+\def\beforefirstpairedbox
+ {\chardef\pairedlocationa1 % left
+ \chardef\pairedlocationb4 % middle
+ \getfromcommacommand[\@@ldlocation][1]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationa0,
+ \v!right=>\chardef\pairedlocationa1,
+ \v!top=>\chardef\pairedlocationa2,
+ \v!bottom=>\chardef\pairedlocationa3]%
+ \getfromcommacommand[\@@ldlocation][2]%
+ \processaction
+ [\commalistelement]
+ [ \v!left=>\chardef\pairedlocationb0,
+ \v!right=>\chardef\pairedlocationb1,
+ \v!high=>\chardef\pairedlocationb2,
+ \v!top=>\chardef\pairedlocationb2,
+ \v!low=>\chardef\pairedlocationb3,
+ \v!bottom=>\chardef\pairedlocationb3,
+ \v!middle=>\chardef\pairedlocationb4]}
+
+\def\betweenbothpairedboxes
+ {\switchtobodyfont[\@@ldbodyfont]% split under same regime
+ \setbox\firstpairedbox\flushnextbox
+ \ifnum\pairedlocationa<2
+ \hsize\wd\firstpairedbox % trick
+ \hsize\@@ldwidth
+ \scratchdimen\wd\firstpairedbox
+ \advance\scratchdimen \@@lddistance
+ \bgroup\advance\scratchdimen \hsize
+ \ifdim\scratchdimen>\@@ldmaxwidth\relax
+ \egroup
+ \hsize\@@ldmaxwidth
+ \advance\hsize -\scratchdimen
+ \else
+ \egroup
+ \fi
+ \else
+ \hsize\wd\firstpairedbox
+ \hsize\@@ldwidth % can be \hsize
+ \ifdim\hsize>\@@ldmaxwidth\relax \hsize\@@ldmaxwidth \fi % can be \hsize
+ \fi
+ \ifnum\@@ldn>\plusone
+ \setrigidcolumnhsize\hsize\@@lddistance\@@ldn
+ \fi}
+
+\def\afterbothpairedboxes
+ {\setbox\secondpairedbox\vbox
+ {% \localstartcolor[\@@ldcolor]% does not work yet
+ \ifnum\@@ldn>1
+ \rigidcolumnbalance\nextbox
+ \else
+ \flushnextbox
+ \fi
+ }% \localstopcolor}%
+ \ifnum\pairedlocationa<2\hbox\else\vbox\fi\bgroup % hide vsize
+ \forgetall
+ \ifnum\pairedlocationa<2
+ \scratchdimen\maxoftwoboxdimens\ht\firstpairedbox\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\scratchdimen<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax
+ \scratchdimen\@@ldmaxheight
+ \fi
+ \valignpairedbox\firstpairedbox \scratchdimen
+ \valignpairedbox\secondpairedbox\scratchdimen
+ \else
+ \scratchdimen\maxoftwoboxdimens\wd\firstpairedbox\secondpairedbox
+ \halignpairedbox\firstpairedbox \scratchdimen
+ \halignpairedbox\secondpairedbox\scratchdimen
+ \scratchdimen\ht\secondpairedbox
+ \vsize\scratchdimen
+ \ifdim\ht\secondpairedbox<\@@ldheight\relax % can be \vsize
+ \scratchdimen\@@ldheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\@@ldmaxheight\relax % todo: totale hoogte
+ \scratchdimen\@@ldmaxheight\relax % \relax needed
+ \fi
+ \ifdim\scratchdimen>\ht\secondpairedbox
+ \setbox\secondpairedbox\vbox to \scratchdimen
+ {\ifnum\pairedlocationa=3 \vss\fi %
+ \box\secondpairedbox
+ \ifnum\pairedlocationa=2 \vss\fi}% \kern\zeropoint
+ \fi
+ \fi
+ \ifcase\pairedlocationa
+ \box\secondpairedbox\hskip\@@lddistance\box\firstpairedbox \or
+ \box\firstpairedbox \hskip\@@lddistance\box\secondpairedbox\or
+ \box\secondpairedbox\endgraf \nointerlineskip \@@ldinbetween \box\firstpairedbox \or
+ \box\firstpairedbox \endgraf \nointerlineskip \@@ldinbetween \box\secondpairedbox\else
+ \fi
+ \egroup}
+
+\def\insidesecondpairedbox
+ {\forgetall
+ \setupalign[\@@ldalign]%
+ \tolerantTABLEbreaktrue % hm.
+ \blank[\v!disable]%
+ \everypar{\begstrut}}
+
+\def\maxoftwoboxdimens#1#2#3%
+ {#1\ifdim#1#2>#1#3 #2\else#3\fi}
+
+\def\valignpairedbox#1#2%
+ {\setbox#1\vbox to #2
+ {\ifcase\pairedlocationb\or\or\or\vss\or\vss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\or\or\vss\or\or\vss\fi}}
+
+\def\halignpairedbox#1#2%
+ {\setbox#1\hbox to #2
+ {\ifcase\pairedlocationb\or\hss\or\or\or\hss\fi
+ \box#1\relax
+ \ifcase\pairedlocationb\hss\or\or\or\or\hss\fi}}
+
+\definepairedbox[\v!legend]
+
+%D Goody:
+
+\appendtoks
+ \global\resetsystemmode{combination}%
+ \global\resetsystemmode{pairedbox}%
+\to \everyinsidefloat
+
+% todo: \startcombination \startcomb \stopcomb ...
+
+\newcount\horcombination % counter
+\newcount\totcombination
+
+\def\definecombination
+ {\dodoubleempty\dodefinecombination}
+
+\def\dodefinecombination[#1][#2]%
+ {\copyparameters
+ [\??co#1][\??co]
+ [\c!width,\c!height,\c!distance,\c!location,%
+ \c!before,\c!inbetween,\c!after,\c!align,%
+ \c!style,\c!color]%
+ \getparameters
+ [\??co#1][#2]}
+
+\def\setupcombinations
+ {\dodoubleempty\dosetupcombinations}
+
+\def\dosetupcombinations[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??co#1][#2]%
+ \else
+ \getparameters[\??co][#1]%
+ \fi}
+
+\def\combinationparameter#1%
+ {\csname\??co\currentcombination#1\endcsname}%
+
+\def\startcombination
+ {\bgroup % so we can grab a group
+ \dodoubleempty\dostartcombination}
+
+% \startcombination {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2*1] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[1*2] {alpha} {a} {beta} {b} \stopcombination
+% \startcombination[2] {alpha} {a} {beta} {b} \stopcombination
+
+\def\dostartcombination[#1][#2]%
+ {\global\setsystemmode{combination}%
+ \doifnothing{#1}\firstargumentfalse % to be sure (when called in macros)
+ \doifnothing{#2}\secondargumentfalse % to be sure (when called in macros)
+ \ifsecondargument
+ \def\currentcombination{#1}%
+ \edef\currentcombinationspec{#2*1*}%
+ \else % better : \doifcombinationelse ... \??co#1\c!location
+ \doifinstringelse{*}{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\doifnumberelse{#1}
+ {\let\currentcombination\empty
+ \edef\currentcombinationspec{#1*1*}}
+ {\def\currentcombination{#1}%
+ \edef\currentcombinationspec{2*1*}}}%
+ \fi
+ \forgetall
+ \doifelse{\combinationparameter\c!height}\v!fit
+ \vbox {\vbox to \combinationparameter\c!height}%
+ \bgroup
+ \expanded{\dodostartcombination[\currentcombinationspec]}}
+
+\long\def\dodostartcombination[#1*#2*#3]%
+ {\setuphorizontaldivision
+ [\c!n=\v!fit,\c!distance=\combinationparameter\c!distance]%
+ \global\horcombination#1%
+ \global\totcombination#2%
+ \global\setbox\combinationstack\emptybox
+ \xdef\maxhorcombination{\the\horcombination}%
+ \multiply\totcombination\horcombination
+ \tabskip\zeropoint
+ \doifelse{\combinationparameter\c!width}\v!fit
+ {\halign}{\halign to \combinationparameter\c!width}%
+ \bgroup&%
+ %\hfil##\hfil% now : location={left,top}
+ \expanded{\doifnotinset{\v!left}{\combinationparameter\c!location}}\hfil
+ ##%
+ \expanded{\doifnotinset{\v!right}{\combinationparameter\c!location}}\hfil
+ &\tabskip\zeropoint \!!plus 1fill##\cr
+ \docombination}
+
+\def\docombination % we want to add struts but still ignore an empty box
+ {\dowithnextbox
+ {\setbox0\flushnextbox
+ \dowithnextbox
+ {\setbox2\flushnextbox
+ \dodocombination}%
+ \vtop\bgroup
+ \def\next
+ {\futurelet\nexttoken\nextnext}%
+ \def\nextnext
+ {\ifx\nexttoken\egroup \else % the next box is empty
+ \hsize\wd0
+ \setupalign[\combinationparameter\c!align]%
+ \dostartattributes{\??co\currentcombination}\c!style\c!color\empty
+ \bgroup
+ \aftergroup\endstrut
+ \aftergroup\dostopattributes
+ \aftergroup\egroup
+ \begstrut
+ \fi}%
+ \afterassignment\next\let\nexttoken=}
+ \hbox}
+
+% stupid version, does not align top stuff when captions,
+% keep as example
+%
+% \def\dodocombination
+% {\vbox
+% {\forgetall % \setupwhitespace[\v!none]%
+% \let\next\vbox
+% \ExpandFirstAfter\processallactionsinset
+% [\combinationparameter\c!location]
+% [ \v!top=>\let\next\tbox,
+% \v!middle=>\let\next\halfwaybox]%
+% \next{\copy0}%
+% \ifdim\ht2>\zeropoint % beter dan \wd2, nu \strut mogelijk
+% \combinationparameter\c!inbetween
+% %\vtop % wrong code
+% % {\nointerlineskip % recently added
+% % \hsize\wd0
+% % \setupalign[\combinationparameter\c!align]% % \raggedcenter
+% % \begstrut\unhbox2\endstrut}%
+% \box2
+% \fi}%
+% \ifnum\totcombination>\plusone
+% \global\advance\totcombination\minusone
+% \global\advance\horcombination\minusone
+% \ifnum\horcombination=\zerocount
+% \def\next
+% {\cr\noalign
+% {\forgetall % \setupwhitespace[\v!geen]% no
+% \nointerlineskip
+% \combinationparameter\c!before
+% \combinationparameter\c!after
+% \vss
+% \nointerlineskip}%
+% \global\horcombination\maxhorcombination\relax
+% \docombination}%
+% \else
+% \def\next
+% {&&&\hskip\combinationparameter\c!distance&\docombination}%
+% \fi
+% \else
+% \def\next
+% {\cr\egroup}%
+% \fi
+% \next}
+
+% \def\dodocombination
+% {\vbox
+% {\forgetall % \setupwhitespace[\v!none]%
+% \let\next\vbox
+% \ExpandFirstAfter\processallactionsinset
+% [\combinationparameter\c!plaats]
+% [ \v!top=>\let\next\tbox,
+% \v!middle=>\let\next\halfwaybox]%
+% \next{\copy0}%
+% % we need to save the caption for a next alignment line
+% \saveoncombinationstack2}%
+% \ifnum\totcombination>\plusone
+% \global\advance\totcombination\minusone
+% \global\advance\horcombination\minusone
+% \ifnum\horcombination=\zerocount
+% \def\next
+% {\cr
+% \flushcombinationstack
+% \noalign
+% {\forgetall % \setupwhitespace[\v!none]% no
+% \global\setbox\combinationstack\emptybox
+% \nointerlineskip
+% \combinationparameter\c!after
+% \combinationparameter\c!before
+% \vss
+% \nointerlineskip}%
+% \global\horcombination\maxhorcombination\relax
+% \docombination}%
+% \else
+% \def\next
+% {&&&\hskip\combinationparameter\c!distance&\docombination}%
+% \fi
+% \else
+% \def\next
+% {\cr
+% \flushcombinationstack
+% \egroup}%
+% \fi
+% \next}
+
+\def\depthonlybox
+ {\dowithnextbox{\vtop{\hsize\wd\nextbox\kern\zeropoint\box\nextbox}}\vbox}
+
+% \def\boxwithstrutheight
+% {\dowithnextbox
+% {\scratchdimen\strutheight
+% \advance\scratchdimen-\nextboxht
+% \hbox{\raise\scratchdimen\box\nextbox}}%
+% \vbox}
+
+\def\dodocombination
+ {\vbox
+ {\forgetall % \setupwhitespace[\v!none]%
+ \let\next\vbox
+ \expanded{\processallactionsinset[\combinationparameter\c!location]}
+ [ \v!top=>\let\next\depthonlybox, % \tbox,
+ \v!middle=>\let\next\halfwaybox]%
+ \next{\copy0}%
+ % we need to save the caption for a next alignment line
+ \saveoncombinationstack2}%
+ \ifnum\totcombination>\plusone
+ \global\advance\totcombination\minusone
+ \global\advance\horcombination\minusone
+ \ifnum\horcombination=\zerocount
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \noalign
+ {\forgetall % \setupwhitespace[\v!none]% no
+ \global\setbox\combinationstack\emptybox
+ \nointerlineskip
+ \combinationparameter\c!after
+ \combinationparameter\c!before
+ \vss
+ \nointerlineskip}%
+ \global\horcombination\maxhorcombination\relax
+ \docombination}%
+ \else
+ \def\next
+ {&&&\hskip\combinationparameter\c!distance&\docombination}%
+ \fi
+ \else
+ \def\next
+ {\cr
+ \flushcombinationstack
+ \egroup}%
+ \fi
+ \next}
+
+% formally ok:
+%
+% \def\stopcombination
+% {\egroup
+% \egroup}
+%
+% more robust:
+%
+% \def\stopcombination
+% {{}{}{}{}{}{}{}{}% catches (at most 4) missing entries
+% \egroup
+% \egroup}
+%
+% even better:
+
+\def\stopcombination
+ {{\scratchtoks{{}{}{}}\dorecurse\totcombination{\appendtoks{}{}{}{}\to\scratchtoks}\expandafter}\the\scratchtoks
+ \egroup
+ \egroup}
+
+\newbox\combinationstack
+
+\def\saveoncombinationstack#1%
+ {\global\setbox\combinationstack\hbox
+ {\hbox{\box#1}\unhbox\combinationstack}}
+
+\def\flushcombinationstack
+ {\noalign
+ {\ifdim\ht\combinationstack>\zeropoint
+\nointerlineskip % nieuw
+ \combinationparameter\c!inbetween
+ \global\horcombination\maxhorcombination
+ \globallet\doflushcombinationstack\dodoflushcombinationstack
+ \else
+ \global\setbox\combinationstack\emptybox
+ \globallet\doflushcombinationstack\donothing
+ \fi}%
+ \doflushcombinationstack\crcr}
+
+\gdef\dodoflushcombinationstack
+ {\global\setbox\combinationstack\hbox
+ {\unhbox\combinationstack
+ \global\setbox1\lastbox}%
+ \box1% \ruledhbox{\box1}%
+ \global\advance\horcombination\minusone\relax
+ \ifnum\horcombination>\zerocount
+ \def\next{&&&&\doflushcombinationstack}%
+ \else
+ \global\setbox\combinationstack\emptybox
+ %\let\next\relax
+ \@EA\gobbleoneargument
+ \fi
+ \next}
+
+\setupcombinations
+ [\c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!distance=1em,
+ \c!location=\v!bottom, % can be something {top,left}
+ \c!before=\blank,
+ \c!inbetween={\blank[\v!medium]},
+ \c!style=,
+ \c!color=,
+ \c!after=,
+ \c!align=\v!middle]
+
+%D \macros
+%D {startfloatcombination}
+%D
+%D \setupexternalfigures[directory={../sample}]
+%D \startbuffer
+%D \placefigure
+%D [left,none]
+%D {}
+%D {\startfloatcombination[2*2]
+%D \placefigure{alpha}{\externalfigure[cow.pdf][width=1cm]}
+%D \placefigure{beta} {\externalfigure[cow.pdf][width=2cm]}
+%D \placefigure{gamma}{\externalfigure[cow.pdf][width=3cm]}
+%D \placefigure{delta}{\externalfigure[cow.pdf][width=4cm]}
+%D \stopfloatcombination}
+%D
+%D \input tufte
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\startfloatcombination
+ {\dodoubleempty\dostartfloatcombination}
+
+\def\dostartfloatcombination[#1][#2]%
+ {\vbox\bgroup
+ %\insidecolumnstrue % trick, forces no centering, todo: proper switch/feature
+ \chardef\postcenterfloatmethod\zerocount
+ \forcelocalfloats
+ \def\stopfloatcombination
+ {\scratchtoks\emptytoks
+ \dorecurse\noflocalfloats
+ {\appendetoks{\noexpand\getlocalfloat{\recurselevel}}{}\to\scratchtoks}%
+ \expanded{\startcombination[#1]\the\scratchtoks}\stopcombination
+ \resetlocalfloats
+ \egroup}}
+
+\def\placerelativetoeachother#1#2%
+ {\bgroup
+ \dowithnextbox
+ {\bgroup
+ \setbox0\box\nextbox
+ \dowithnextbox
+ {\setbox2\box\nextbox
+ #1{#2#########2\cr\box0\cr\box2\cr}
+ \egroup
+ \egroup}
+ \hbox}
+ \hbox}
+
+\def\placeontopofeachother{\placerelativetoeachother\halign\hss}
+\def\placesidebyside {\placerelativetoeachother\valign\vss}
+
+% this will be replaced or go away, never used
+
+\def\douseexternalfiles[#1][#2]%
+ {\getparameters
+ [\??fi#1]
+ [\c!file=,
+ \c!bodyfont=,
+ \c!option=,
+ #2]}
+
+\def\useexternalfiles
+ {\dodoubleargument\douseexternalfiles}
+
+\def\dostelexternefilesin[#1][#2]%
+ {\doifundefinedelse{\??fi#1\c!file}
+ {\useexternalfiles[#1][#2]}
+ {\getparameters[\??fi#1][#2]}}
+
+\def\stelexternefilesin
+ {\dodoubleargument\dostelexternefilesin}
+
+\def\verwerkexternefile#1#2#3%
+ {\bgroup
+ \getparameters[\??fi#1][\c!file=,#3]%
+ \doinputonce{\getvalue{\??fi#1\c!file}}%
+ \ExpandFirstAfter\switchtobodyfont[\getvalue{\??fi#1\c!bodyfont}]%
+ \readsysfile{#2} % beter: loc of fix gebied
+ \donothing
+ {\showmessage\m!systems{41}{#2,#1}}%
+ \egroup}
+
+\def\douseexternalfile[#1][#2][#3][#4]%
+ {\stelexternefilesin[#1][]%
+ \doinputonce{\getvalue{\??fi#1\c!file}}%
+ \doifelsenothing{#2}
+ {\setvalue{#3}{\verwerkexternefile{#1}{#3}{#4}}}
+ {\setvalue{#2}{\verwerkexternefile{#1}{#3}{#4}}}}
+
+\def\useexternalfile
+ {\doquadrupleargument\douseexternalfile}
+
+\useexternalfiles
+ [pictex]
+ [\c!bodyfont=\v!small,
+ \c!file=pictex]
+
+\useexternalfiles
+ [table]
+ [\c!file=table]
+
+%D A couple of examples, demonstrating how the depth is
+%D taken care of:
+%D
+%D \startbuffer
+%D test\rotate[frame=on, rotation=0] {gans}%
+%D test\rotate[frame=on, rotation=90] {gans}%
+%D test\rotate[frame=on, rotation=180]{gans}%
+%D test\rotate[frame=on, rotation=270]{gans}%
+%D test
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% When we rotate over arbitrary angles, we need to relocate the
+% resulting box because rotation brings that box onto the negative
+% axis. The calculations (mostly sin and cosine) need to be tuned for
+% the way a box is packages (i.e. the refence point). A typical example
+% of drawing, scribbling, and going back to the days of school math.
+%
+% We do a bit more calculations than needed, simply because that way
+% it's easier to debug the code.
+
+\def\dododorotatenextbox
+ {\setbox\nextbox\vbox to \@@layerysiz
+ {\vfill
+ \hbox to \@@layerxsiz
+ {\dostartrotation\@@rorotation
+ \nextboxwd\zeropoint
+ \nextboxht\zeropoint
+ \flushnextbox
+ \dostoprotation
+ \hfill}%
+ \kern\@@layerypos}%
+ \setbox\nextbox\hbox
+ {\kern\@@layerxpos
+ \kern\@@layerxoff
+ \lower\@@layeryoff\flushnextbox}}
+
+\def\dodorotatenextbox#1#2% quite some trial and error -)
+ {\dontshowcomposition
+ \dontcomplain
+ \ifnum#2=\plusfour
+ % new, location=middle
+ \!!widthb \nextboxwd
+ \!!heightb\nextboxht
+ \!!depthb \nextboxdp
+ \setbox\nextbox\vbox{\vskip.5\nextboxht\hskip-.5\nextboxwd\flushnextbox}%
+ \smashbox\nextbox
+ \fi
+ \!!widtha \nextboxwd
+ \!!heighta\nextboxht
+ \!!deptha \nextboxdp
+ \!!doneafalse
+ \!!donebfalse
+ \ifcase#2\or
+ % 1: fit
+ \or
+ % 2: depth, not fit
+ \!!doneatrue
+ \!!donebtrue
+ \or
+ % 3: depth, fit
+ \!!donebtrue
+ \fi
+ \setbox\nextbox\vbox{\hbox{\raise\nextboxdp\flushnextbox}}%
+ \!!dimena \nextboxht
+ \setcalculatedcos\cos\@@rorotation
+ \setcalculatedsin\sin\@@rorotation
+ \@@layerxpos\zeropoint
+ \@@layerypos\zeropoint
+ \@@layerxoff\zeropoint
+ \@@layeryoff\zeropoint
+ \ifdim\sin\points>\zeropoint
+ \ifdim\cos\points>\zeropoint
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \@@layerypos \cos\!!dimena
+ \if!!donea
+ \@@layerxoff \negated\sin\!!dimena
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \else
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \sin\!!widtha
+ \advance\@@layerxsiz \sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \negated\cos\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \sin\!!deptha
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\cos\!!heighta
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\sin\!!deptha\else\@@layerxsiz\fi
+ \fi
+ \else
+ \ifdim\cos\points<\zeropoint
+ \@@layerxsiz \negated\cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \negated\cos\!!dimena
+ \@@layerxpos \@@layerxsiz
+ \@@layerypos \negated\sin\!!widtha
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \@@layerysiz
+ \advance\@@layeryoff \cos\!!deptha
+ \fi
+ \dododorotatenextbox
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \else
+ \@@layerxsiz \cos\!!widtha
+ \@@layerysiz \negated\sin\!!widtha
+ \advance\@@layerxsiz \negated\sin\!!dimena
+ \advance\@@layerysiz \cos\!!dimena
+ \ifdim\sin\points=\zeropoint
+ \@@layerxpos \zeropoint
+ \@@layerxoff \zeropoint
+ \@@layerypos \@@layerysiz
+ \if!!doneb
+ \@@layeryoff \!!deptha
+ \fi
+ \else
+ \@@layerypos \@@layerysiz
+ \@@layerxpos \negated\sin\!!dimena
+ \if!!donea
+ \@@layerxoff -\@@layerxsiz
+ \advance\@@layerxoff \negated\sin\!!heighta
+ \fi
+ \if!!doneb
+ \@@layeryoff \negated\sin\!!deptha
+ \fi
+ \fi
+ \dododorotatenextbox
+ \ifdim\sin\points=\zeropoint
+ \else
+ \wd\nextbox\if!!donea\negated\sin\!!heighta\else\@@layerxsiz\fi
+ \fi
+ \fi
+ \fi
+ % new, location=middle
+ \ifnum#2=\plusfour
+ \setbox\nextbox\vbox{\vskip-.5\!!heightb\hskip.5\!!heightb\flushnextbox}%
+ \nextboxwd\!!widthb
+ \nextboxht\!!heightb
+ \nextboxdp\!!depthb
+ \fi}
+
+\def\dorotatenextbox#1#2%
+ {\doifsomething{#1}
+ {\edef\@@rorotation{\realnumber{#1}}% get rid of leading zeros and spaces
+ \setbox\nextbox\vbox{\flushnextbox}% not really needed
+ \dodorotatenextbox\@@rorotation#2}%
+ \hbox{\boxcursor\flushnextbox}}
+
+\def\dodorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\bgroup\hbox\bgroup % compatibility hack
+ \dowithnextbox
+ {\dorotatenextbox{#1}\plusone
+ \egroup\egroup}}
+
+\def\dorotatebox#1% {angle} \hbox/\vbox/\vtop
+ {\ifcase#1\relax
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\dodorotatebox
+ \fi{#1}}
+
+\unexpanded\def\rotate % \bgroup: \rotate kan argument zijn
+ {\bgroup\complexorsimpleempty\rotate}
+
+% \def\complexrotate[#1]% framed met diepte !
+% {\getparameters[\??ro][#1]%
+% \processaction
+% [\@@rolocation]
+% [ \v!depth=>\!!counta\plusthree\donefalse,% depth fit - raw box
+% \v!fit=>\!!counta\plustwo \donefalse,% depth tight - raw box
+% \v!broad=>\!!counta\plusone \donefalse,% nodepth fit - raw box
+% \v!high=>\!!counta\plusone \donetrue ,% nodepth fit - framed
+% \v!middle=>\!!counta\plusfour \donefalse,% centered, keep dimensions
+% \s!default=>\!!counta\plusthree\donetrue ,% depth fit - framed
+% \s!unknown=>\!!counta\plusthree\donetrue ]% depth fit - framed
+% \ifdone
+% \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+% \else
+% \let\docommand\relax
+% \fi
+% \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\setvalue{\??ro::\c!location::\v!depth }{\!!counta\plusthree\donefalse} % depth fit - raw box
+\setvalue{\??ro::\c!location::\v!fit }{\!!counta\plustwo \donefalse} % depth tight - raw box
+\setvalue{\??ro::\c!location::\v!broad }{\!!counta\plusone \donefalse} % nodepth fit - raw box
+\setvalue{\??ro::\c!location::\v!high }{\!!counta\plusone \donetrue } % nodepth fit - framed
+\setvalue{\??ro::\c!location::\v!middle }{\!!counta\plusfour \donefalse} % centered, keep dimensions
+\setvalue{\??ro::\c!location::\v!default}{\!!counta\plusthree\donetrue } % depth fit - framed
+
+\def\complexrotate[#1]% framed met diepte !
+ {\getparameters[\??ro][#1]%
+ \executeifdefined{\??ro::\c!location::\@@rolocation}{\!!counta\plusthree\donetrue}%
+ \ifdone
+ \def\docommand{\localframed[\??ro][#1,\c!location=]}%
+ \else
+ \let\docommand\relax
+ \fi
+ \dowithnextbox{\dorotatenextbox\@@rorotation\!!counta\egroup}\vbox\docommand}
+
+\presetlocalframed[\??ro]
+
+\def\setuprotate
+ {\dodoubleargument\getparameters[\??ro]}
+
+\setuprotate
+ [\c!rotation=90,
+ \c!location=\v!normal,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!offset=\v!overlay,
+ \c!frame=\v!off]
+
+% \dostepwiserecurse{0}{360}{10}
+% {\startlinecorrection[blank]
+% \hbox
+% {\expanded{\setuprotate[rotation=\recurselevel]}%
+% \traceboxplacementtrue
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=depth] {\ruledhbox{\bfb (depth)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=fit] {\ruledhbox{\bfb (fit)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=broad] {\ruledhbox{\bfb (broad)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=normal]{\ruledhbox{\bfb (normal)}}}}%
+% \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}}
+% \stoplinecorrection}
+
+% to be used in some other places! todo!
+%
+% divides \hsize in fractions, will be made a bit more
+% clever and advanced when needed
+%
+% \horizontaldivision[n/m,elements,distance]
+%
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[2/5,3,1em]
+% \horizontaldivision[1/5,3,1em]
+%
+% \setuphorizontaldivision[afstand=,aantal=] (passend,passend)
+
+\def\??fr{@@fr}
+
+\def\setuphorizontaldivision
+ {\dodoubleargument\getparameters[\??fr]}
+
+\def\horizontaldivision
+ {\dosingleargument\dohorizontaldivision}
+
+\def\dohorizontaldivision[#1]%
+ {\dodohorizontaldivision[#1,,,,,,]}
+
+\def\dodohorizontaldivision[#1/#2,#3,#4,#5]%
+ {\doifelsenothing{#3}
+ {\doifelse\@@frn\v!fit
+ {\!!counta#2\relax}
+ {\!!counta\@@frn\relax}}
+ {\!!counta#3\relax}%
+ \doifelsenothing{#4}
+ {\doifelse\@@frdistance\v!fit
+ {\!!widtha\zeropoint}
+ {\!!widtha\@@frdistance}}
+ {\!!widtha#4}%
+ \advance\!!counta \minusone
+ \multiply\!!widtha \!!counta
+ \advance\hsize -\!!widtha
+ \divide\hsize #2\relax
+ \hsize#1\hsize}
+
+\setuphorizontaldivision
+ [\c!distance=\tfskipsize,
+ \c!n=\v!fit]
+
+%D This one is for Daniel Pittman, who wanted tight
+%D fractions. We show three versions. First the simple
+%D one using \type {\low} and \type {high}:
+%D
+%D \startbuffer
+%D \def\vfrac#1#2%
+%D {\hbox{\high{\tx#1\kern-.25em}/\low{\kern-.25em\tx#2}}}
+%D
+%D test \vfrac{1}{2} test \vfrac{123}{456} test
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D A better way to handle the kerning is the following, here
+%D we kind of assume that tye slash is symmetrical and has
+%D nearly zero width.
+%D
+%D \startbuffer
+%D \def\vfract#1#2%
+%D {\hbox{\high{\tx#1}\hbox to \zeropoint{\hss/\hss}\low{\tx#2}}}
+%D \stopbuffer
+%D
+%D \typebuffer {\showmakeup\getbuffer}
+%D
+%D The third and best alternative is the following:
+%D
+%D {\showmakeup\getbuffer}\crlf\getbuffer
+%D
+%D This time we measure the height of the \type {/} and
+%D shift over the maximum height and depths of this
+%D character and the fractional digits (we use 57 as
+%D sample). Here we combine all methods in one macros.
+
+\chardef\vulgarfractionmethod=3
+
+\definehspace[vulgarfraction][.25em] % [.15em]
+\definesymbol[vulgarfraction][/] % [\raise.2ex\hbox{/}]
+
+\unexpanded\def\vulgarfraction#1#2%
+ {\dontleavehmode
+ \hbox
+ {\def\vulgarfraction{vulgarfraction}%
+ \ifcase\vulgarfractionmethod
+ #1\symbol[\vulgarfraction]#2%
+ \or
+ \high{\tx#1\kern-\hspaceamount\empty\vulgarfraction}%
+ \symbol[\vulgarfraction]%
+ \low {\kern-\hspaceamount\empty\vulgarfraction\tx#2}%
+ \or
+ \high{\tx#1}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \low{\tx#2}%
+ \or
+ \setbox0\hbox{\symbol[\vulgarfraction]}%
+ \setbox2\hbox{\txx57}%
+ \raise\ht0\hbox{\lower\ht2\hbox{\txx#1}}%
+ \hbox to \zeropoint{\hss\symbol[\vulgarfraction]\hss}%
+ \lower\dp0\hbox{\raise\dp2\hbox{\txx#2}}%
+ \fi}}
+
+\ifx\vfrac\undefined \let\vfrac\vulgarfraction \fi
+
+%D \starttabulate
+%D \HL
+%D \NC \bf method \NC \bf visualization \NC\NR
+%D \HL
+%D \NC 0 \NC \chardef\vulgarfractionmethod0\vulgarfraction{1}{2} \NC\NR
+%D \NC 1 \NC \chardef\vulgarfractionmethod1\vulgarfraction{1}{2} \NC\NR
+%D \NC 2 \NC \chardef\vulgarfractionmethod2\vulgarfraction{1}{2} \NC\NR
+%D \NC 3 \NC \chardef\vulgarfractionmethod3\vulgarfraction{1}{2} \NC\NR
+%D \HL
+%D \stoptabulate
+
+%D Under construction:
+%D
+%D \starttyping
+%D \commalistsentence[aap,noot,mies]
+%D \commalistsentence[aap,noot]
+%D \commalistsentence[aap]
+%D \commalistsentence[a,b,c]
+%D \commalistsentence[a,b,c][{ \& },{ and }]
+%D \commalistsentence[a,b,c][+,-]
+%D \stoptyping
+
+\let\handlecommalistsentence\firstofoneargument
+
+\def\commalistsentenceone{and-1}
+\def\commalistsentencetwo{and-2}
+
+\def\commalistsentence
+ {\dodoubleempty\docommalistsentence}
+
+\def\docommalistsentence[#1][#2]%
+ {\bgroup
+ \getfromcommalist[#2][1]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentenceone{\labeltext\commalistsentenceone}%
+ \else
+ \let\@@commalistsentenceone\commalistelement
+ \fi
+ \getfromcommalist[#2][2]%
+ \ifx\commalistelement\empty
+ \def\@@commalistsentencetwo{\labeltext\commalistsentencetwo}%
+ \else
+ \let\@@commalistsentencetwo\commalistelement
+ \fi
+ \getcommalistsize[#1]%
+ \ifcase\commalistsize\relax
+ \def\serializedcommalist{#1}%
+ \else
+ \let\serializedcommalist\empty
+ \scratchcounter\zerocount
+ \def\docommand##1%
+ {\advance\scratchcounter \plusone
+ \ifnum\scratchcounter=\plusone
+ \scratchtoks{\handlecommalistsentence{##1}}%
+ \else
+ \ifnum\scratchcounter=\commalistsize
+ \appendtoks\@@commalistsentencetwo\handlecommalistsentence{##1}\to\scratchtoks
+ \else
+ \appendtoks\@@commalistsentenceone\handlecommalistsentence{##1}\to\scratchtoks
+ \fi
+ \fi}%
+ \processcommacommand[#1]\docommand
+ \edef\serializedcommalist{\the\scratchtoks}%
+ \fi
+ \serializedcommalist
+ \egroup}
+
+\def\commacommandsentence[#1]{\@EA\commalistsentence\@EA[#1]}
+
+\ifx\textcomma\undefined \def\textcomma{,} \fi
+
+\setuplabeltext [\s!nl] [and-1=\textcomma\ , and-2= en ]
+\setuplabeltext [\s!en] [and-1=\textcomma\ , and-2=\textcomma\ and ]
+\setuplabeltext [\s!de] [and-1=\textcomma\ , and-2= und ]
+
+%D \macros
+%D {somekindoftab}
+%D
+%D This macro can be used to create tabs:
+%D
+%D \starttyping
+%D \setupheadertexts[{\somekindoftab[alternative=horizontal]{\framed{\realfolio}}}]
+%D \setuptexttexts [{\somekindoftab[alternative=vertical] {\framed{\realfolio}}}]
+%D
+%D \starttext
+%D \showframe \dorecurse{10}{test\page}
+%D \stoptext
+%D \stoptyping
+
+\def\somekindoftab
+ {\dosingleempty\dosomekindoftab}
+
+\def\dosomekindoftab[#1]%
+ {\bgroup
+ \getparameters[xx]
+ [\c!alternative=\v!vertical,
+ \c!width=\textwidth,\c!height=\textheight,
+ \c!n=\lastpage,\c!m=\realpageno,
+ #1]%
+ \doifelse\xxalternative\v!vertical
+ {\dodosomekindoftab\vbox\vskip\xxheight}
+ {\dodosomekindoftab\hbox\hskip\xxwidth }}
+
+\def\dodosomekindoftab#1#2#3#4%
+ {#1 to #3 \bgroup
+ \forgetall
+ \ifnum\xxm>\plusone
+ #2\zeropoint \!!plus \the\numexpr\xxm -1\relax fill\relax
+ \fi
+ #4%
+ \ifnum\xxm<\xxn\relax
+ #2\zeropoint \!!plus \the\numexpr\xxn-\xxm\relax fill\relax
+ \fi
+ \egroup
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/core-nav.tex b/tex/context/base/core-nav.mkii
index 045a05123..f4594ab3b 100644
--- a/tex/context/base/core-nav.tex
+++ b/tex/context/base/core-nav.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Navigation}
+\writestatus{loading}{ConTeXt Core Macros / Navigation}
\unprotect
diff --git a/tex/context/base/core-nav.mkiv b/tex/context/base/core-nav.mkiv
new file mode 100644
index 000000000..e079f5f08
--- /dev/null
+++ b/tex/context/base/core-nav.mkiv
@@ -0,0 +1,425 @@
+%D \module
+%D [ file=core-nav,
+%D version=1998.01.15,
+%D title=\CONTEXT\ Core Macros,
+%D subtitle=Navigation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Core Macros / Navigation}
+
+\unprotect
+
+%D Support for interactive document is very present in
+%D \CONTEXT\ and interwoven in many modules. This means that in
+%D this module, where we deal with some common navigational
+%D features, there will be quite some forward references.
+%D
+%D When I started implementing hypertext support, the macros
+%D were mostly dealing with things related to locations, that
+%D is click in this location and goto that one. The
+%D functionality of many macro depends on the output medium:
+%D paper or screen. The next boolean holds the state:
+
+\newif\iflocation \def\ifinteractief{\iflocation} % upw comp
+
+%D We also allocate a scratchbox:
+
+\newbox\locationbox
+
+%D There is no interaction at all unless enabled by saying:
+%D
+%D \starttyping
+%D \setupinteraction[state=start]
+%D \stoptyping
+%D
+%D The other settings are:
+%D
+%D \showsetup{setupinteraction}
+%D
+%D In the special driver modules we introduced a switch that
+%D forces page destinations (instead of named ones). We set
+%D this switch here.
+
+\def\setinteractionparameter#1#2% use with case, no checking done
+ {\setvalue{\??ia#1}{#2}} % pass #2, can be \blabla
+
+\def\resetinteractionparameter#1% use with case, no checking done
+ {\letvalue{\??ia#1}\empty}
+
+% \def\interactionparameter#1%
+% {\csname\??ia#1\endcsname}
+
+\newtoks\everysetupinteraction
+
+\def\setupinteraction
+ {\dosingleargument\dodosetupinteraction}
+
+\def\dodosetupinteraction[#1]% % \dosetupinteraction == special
+ {\getparameters[\??ia][#1]%
+ \the\everysetupinteraction}
+
+% todo, move partial append to where the action happens
+
+\appendtoks
+ \doifelse\@@iastate\v!start
+ {\iflocation\else
+ \showmessage\m!interactions2{\ifusepagedestinations\space(PAGE)\fi}%
+ \global\locationtrue
+ \fi}
+ {\iflocation
+ \showmessage\m!interactions3{\ifusepagedestinations\space(PAGE)\fi}%
+ \global\locationfalse
+ \fi}%
+ \iflocation
+ \setsystemmode \v!interaction
+ \else
+ \resetsystemmode\v!interaction
+ \fi
+ \dosetuppageview\@@iafocus
+ \doifsomething\@@iacalculate
+ {\doregistercalculationset\@@iacalculate}%
+ \doifelse\@@iastrut\v!yes
+ \locationstruttrue
+ \locationstrutfalse
+ \doifelse\@@iaclick\v!yes
+ \highlighthyperlinkstrue
+ \highlighthyperlinksfalse
+ \doifelse\@@iasplit\v!yes
+ \locationsplittrue
+ \locationsplitfalse
+ \doifelse\@@iadisplay\v!new
+ \gotonewwindowtrue
+ \gotonewwindowfalse
+ \doifelse\@@iapage\v!yes
+ {\global\usepagedestinationstrue}
+ {\global\usepagedestinationsfalse}%
+\to \everysetupinteraction
+
+%D We have to make sure of some settings:
+
+\def\dolocationstartup
+ {\iflocation
+ \dosetupinteraction
+ \handlereferenceactions\@@iaopenaction \dosetupopenaction
+ \handlereferenceactions\@@iacloseaction\dosetupcloseaction
+ \setupinteractionscreens
+ \global\let\dolocationstartup\relax
+ \fi}
+
+\appendtoks \dolocationstartup \to \everyshipout
+
+\def\dolocationpagecheck % brr pdf dependent
+ {\iflocation
+ \handlereferenceactions\@@iaopenpageaction \dosetupopenpageaction
+ \handlereferenceactions\@@iaclosepageaction\dosetupclosepageaction
+ \fi}
+
+\appendtoks \dolocationpagecheck \to \everyshipout
+
+%D The next few macros are really horrible. For proper
+%D navigation a in||line hypertext fragment must have
+%D comfortable properties, so we must force some minimal
+%D dimensions. On the other hand button, and here I mean those
+%D pieces of text with fancy outlines and/or backgrounds, often
+%D have fixed, preset dimensions.
+%D
+%D To make things even worse, if we choose to let the optimal
+%D dimensions depend on the height and depth of a strut, a not
+%D too uncommon practice in \TEX, we have to deal with the fact
+%D that such a strut, set inside a box, is unknown too the
+%D outside world.
+%D
+%D The solution lays in passing the strut characteristics in
+%D a proper way, in our case by applying \type{\presetgoto}:
+%D
+%D \starttyping
+%D {some piece of text \presetgoto}
+%D \stoptyping
+%D
+%D This macro stores the current strut values.
+
+\newif\iflocationstrut
+\newif\iflocationsplit
+
+\def\resetgoto
+ {\globallet\@@ia@@hoogte\!!zeropoint
+ \globallet\@@ia@@diepte\!!zeropoint}
+
+\resetgoto
+
+\def\presetgoto
+ {\iflocationstrut
+ \setstrut
+ %\xdef\@@ia@@hoogte{\the\strutht}%
+ %\xdef\@@ia@@diepte{\the\strutdp}%
+ \globallet\@@ia@@hoogte\strutheight
+ \globallet\@@ia@@diepte\strutdepth
+ \else
+ \globallet\@@ia@@hoogte\@@iaheight
+ \globallet\@@ia@@diepte\@@iadepth
+ \fi}
+
+%D In the macros that deal with making areas into hyperlinks,
+%D we use:
+
+\newbox\driverresources
+
+\def\collectdriverresource#1%
+ {\global\setbox\driverresources\hbox{\box\driverresources#1}}
+
+\def\flushdriverresources
+ {\ifvoid\driverresources\else\box\driverresources\fi}
+
+% \def\dohandlegoto#1#2#3%
+% {\ifsecondaryreference
+% \bgroup\setbox0\hbox{#2#3}\egroup
+% \else
+% \hbox
+% {\setbox0\hbox{#1}%
+% \ifdim\wd0<\@@iawidth\relax
+% \buttonwidth\@@iawidth\relax
+% \else
+% \buttonwidth\wd0
+% \fi
+% \ifdim\ht0<\@@ia@@hoogte\relax
+% \buttonheight\@@ia@@hoogte\relax
+% \else
+% \buttonheight\ht0
+% \fi
+% \ifdim\dp0<\@@ia@@diepte\relax
+% \dimen0=\@@ia@@diepte\relax % = !
+% \else
+% \dimen0\dp0
+% \fi
+% \advance\buttonheight \dimen0
+% \setbox2\hbox
+% {\lower\dimen0\hbox
+% {\dontcomplain
+% \dimen0=.5\wd0 % direct skipping is faster of course
+% \advance\dimen0 -.5\buttonwidth % buts this is nicer
+% \hskip\dimen0#2#3}}% when visualizing things
+% \naturalhbox % needed for omega / moved from plus-omg
+% {\ifreversegoto
+% \dimen0\wd0\box0\kern-\dimen0\smashbox2\box2\kern\dimen0
+% \else
+% \smashbox2\box2\box0
+% \fi
+% \flushdriverresources}%
+% \resetgoto}%
+% \fi}
+
+\def\dohandlegoto#1#2#3%
+ {\ifcollectreferenceactions
+ % this happens here while in mkii elsewhere, better is to deal with
+ % in in the ref module but that's for later to deal with
+ \bgroup\setbox\scratchbox\hbox{#2#3}\egroup
+ \ifsecondaryreference \else
+ \resetgoto
+ \fi
+ \ifsecondaryreference\else#1\resetgoto\fi
+ \else\ifsecondaryreference
+ \bgroup\setbox\scratchbox\hbox{#2#3}\egroup
+ \else
+ \hbox
+ {\setbox0\hbox{#1}%
+ \ifdim\wd0<\@@iawidth\relax
+ \buttonwidth\@@iawidth\relax
+ \else
+ \buttonwidth\wd0
+ \fi
+ \ifdim\ht0<\@@ia@@hoogte\relax
+ \buttonheight\@@ia@@hoogte\relax
+ \else
+ \buttonheight\ht0
+ \fi
+ \ifdim\dp0<\@@ia@@diepte\relax
+ \dimen0=\@@ia@@diepte\relax % = !
+ \else
+ \dimen0\dp0
+ \fi
+ \advance\buttonheight \dimen0
+ \setbox2\hbox
+ {\lower\dimen0\hbox
+ {\dontcomplain
+ \dimen0=.5\wd0 % direct skipping is faster of course
+ \advance\dimen0 -.5\buttonwidth % buts this is nicer
+ \hskip\dimen0#2#3}}% when visualizing things
+ \naturalhbox % needed for omega / moved from plus-omg
+ {\ifreversegoto
+ \dimen0\wd0\box0\kern-\dimen0\smashbox2\box2\kern\dimen0
+ \else
+ \smashbox2\box2\box0
+ \fi
+ \flushdriverresources}%
+ \resetgoto}%
+ \fi\fi}
+
+%D The secondary references are processed but not typeset. The
+%D special driver must collect the data needed.
+
+%D The width of the active area depends on the dimensions
+%D preset, the actual dimens and/or the height and depth of the
+%D strut.
+%D
+%D Normally the hyper active area is laid on top of the text.
+%D This enables stacking hyperlinks on top of each other. When,
+%D for some reason the opposite is prefered, one can use the
+%D next boolean to signal this wish.
+
+\newif\ifreversegoto \reversegotofalse
+
+%D As long as there a natural feeling of what can be considered
+%D hyper active or not, we have to tell users where they can
+%D possibly click. We've already seen a few macros that deal
+%D with this visualization, something we definitely do not let
+%D up to the viewer. One way of telling is using a distinctive
+%D typeface, another way is using color.
+%D
+%D There are two colors involved: one for normal hyperlinks,
+%D and one for those that point to the currentpage, the
+%D contrast color.
+
+\definecolor [interactioncolor] [r=0, g=.6, b=0]
+\definecolor [interactioncontrastcolor] [r=.8, g=0, b=0]
+
+\definecolor [interactiekleur] [interactioncolor]
+\definecolor [interactiecontrastkleur] [interactioncontrastcolor]
+
+%D The next few macros are responsible for highlighting hyper
+%D links. The first one, \type{\showlocation}, is used in those
+%D situations where the typeface is handled by the calling
+%D macro.
+
+\def\interactioncolor % todo \??ia as argument
+ {\iflocation
+ \ifrealreferencepage
+ \@@iacontrastcolor
+ \else
+ \@@iacolor
+ \fi
+ \fi}
+
+%D CHECK WHERE USED / CONSISTENCY
+
+\def\showlocation#1%
+ {\iflocation\color[\@@iacolor]{#1\presetgoto}\else#1\fi}
+
+%D When local color settings are to be used, we can use the
+%D next macro, where \type{#1} is a tag like \type{\??tg} and
+%D \type{#2} some text.
+
+\def\showcoloredlocation#1#2%
+ {\iflocation
+ \color[\getvalue{#1\c!color}]{#2\presetgoto}%
+ \else
+ #2%
+ \fi}
+
+%D When we're dealing with pure page references, contrast
+%D colors are used when we are already at the page mentioned.
+
+\def\showcontrastlocation#1#2#3% the \@EA is needed
+ {\iflocation
+ \ifnum#2=\realpageno\relax
+ \doifelsevaluenothing{#1\c!color}
+ {#3\presetgoto}
+ {\color[\getvalue{#1\c!contrastcolor}]{#3\presetgoto}}%
+ \else
+ \color[\getvalue{#1\c!color}]{#3\presetgoto}%
+ \fi
+ \else
+ #3%
+ \fi}
+
+%D The next simple macro can be used in color specifications,
+%D like \type{\color[\locationcolor{green}]}.
+
+\def\locationcolor#1%
+ {\iflocation#1\fi}
+
+%D More tokens are spend when we want both typeface and color
+%D highlighting.
+
+\def\dolocationattributes#1#2#3#4%
+ {\bgroup
+ \let\fontattribute\empty
+ \let\colorattribute\empty
+ \doifdefined{#1#2}{\def\fontattribute{\getvalue{#1#2}}}%
+ \iflocation
+ \doifdefined{#1#3}{\def\colorattribute{\getvalue{#1#3}}}%
+ \fi
+ \startcolor[\colorattribute]%
+ \@EA\doconvertfont\@EA{\fontattribute}{#4}% no \edef, but \@EA here
+ \stopcolor
+ \egroup}
+
+\def\navigating
+ {\dolocationattributes\??ia\c!style\c!color}
+
+%D Although not decently supported in current viewers, a
+%D provisory hiding mechanims is implemented. Areas marked as
+%D such, are visible on screen, but invisible on paper. Don't
+%D trust this mechanism yet!
+
+\def\dostartinteraction
+ {\bgroup
+ \let\stopinteraction\egroup
+ \dowithnextbox{\dostarthide\flushnextbox\dostophide\egroup}\hbox}
+
+\let\startinteraction = \relax
+\let\stopinteraction = \relax
+
+% in the future:
+%
+% eerst boolean invoeren bij menu, achtergrond, balk, button
+% enz; verder startinteractie een argument meegeven {#1} ->
+% \getvalue{#1\c!print}=={\v!ja} enz. Consequent menubutton
+% gebruiken!
+
+\def\@@iatimestamp
+ {\the\normalyear
+ \ifnum\normalmonth<10 0\fi\the\normalmonth
+ \ifnum\normalday <10 0\fi\the\normalday}
+
+% happens in core-fld
+%
+% \definereference [AtOpenInitializeForm] [\v!geen]
+
+\setupinteraction % start fit page and reset form
+ [\c!state=\v!stop,
+ \c!page=\v!no,
+ \c!click=\v!yes,
+ \c!display=,
+ %\c!openaction={\v!firstpage,AtOpenInitializeForm},
+ %\c!openaction={\v!firstpage,\v!ResetForm},
+ %\c!openaction=\v!ResetForm, % too buggy in reader 4.05
+ \c!openaction=,
+ \c!closeaction=,
+ \c!openpageaction=,
+ \c!closepageaction=,
+ \c!display=\v!normal,
+ \c!focus=\v!fit,
+ \c!menu=\v!off,
+ \c!style=\v!bold,
+ \c!calculate=,
+ \c!strut=\v!yes,
+ \c!split=\v!yes,
+ \c!color=interactioncolor,
+ \c!contrastcolor=interactioncontrastcolor,
+ \c!symbolset=,
+ \c!width=1em,
+ \c!height=\!!zeropoint,
+ \c!depth=\!!zeropoint,
+ \c!title=\jobname, % needed for fdf/x
+ \c!subtitle=,
+ \c!author=,
+ \c!keyword=,
+ \c!date=\@@iatimestamp]
+
+\protect \endinput
diff --git a/tex/context/base/core-not.tex b/tex/context/base/core-not.tex
index aa6edd0e6..70d3f8627 100644
--- a/tex/context/base/core-not.tex
+++ b/tex/context/base/core-not.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Note Handling}
+\writestatus{loading}{ConTeXt Core Macros / Note Handling}
%D Unfortunately we cannot force an even number of lines in
%D a two column footnote placement.
@@ -36,8 +36,8 @@
%D \stopitemize
%D
%D Because footnotes are declared at the location of their
-%D reference. Footnotes can be seen as a special kind of
-%D floating bodies. There placement is postponed but has to be
+%D reference they can be seen as a special kind of
+%D floating bodies. Their placement is postponed but has to be
%D taken into account in the pagebreak calculations. This kind
%D of calculations are forced by using \type{\insert}.
@@ -383,7 +383,7 @@
\placenoterule
\noteparameter\c!after}%
\global\skip\currentnoteins\ht\scratchbox
- \setbox\scratchbox\box\voidb@x} % scratchbox can be in use
+ \setbox\scratchbox\emptybox} % scratchbox can be in use
\ifx\setnotehsize\undefined
diff --git a/tex/context/base/core-num.tex b/tex/context/base/core-num.tex
index 4dde1d4d3..a86ce8a1d 100644
--- a/tex/context/base/core-num.tex
+++ b/tex/context/base/core-num.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Numbering}
+\writestatus{loading}{ConTeXt Core Macros / Numbering}
\unprotect
diff --git a/tex/context/base/core-obj.lua b/tex/context/base/core-obj.lua
index 338ca9d1f..f879ddc8c 100644
--- a/tex/context/base/core-obj.lua
+++ b/tex/context/base/core-obj.lua
@@ -34,6 +34,10 @@ function jobobjects.set(tag,number,page)
collected[tag] = { number, page }
end
+function jobobjects.get(tag)
+ return collected[tag] or tobesaved[tag]
+end
+
function jobobjects.number(tag,default)
local o = collected[tag] or tobesaved[tag]
texsprint((o and o[1]) or default)
@@ -45,5 +49,6 @@ function jobobjects.page(tag,default)
end
function jobobjects.doifelse(tag)
- cs.testcase(collected[tag] or tobesaved[tag])
+ commands.testcase(collected[tag] or tobesaved[tag])
end
+
diff --git a/tex/context/base/core-obj.mkii b/tex/context/base/core-obj.mkii
index b0599dde9..6e210a0ab 100644
--- a/tex/context/base/core-obj.mkii
+++ b/tex/context/base/core-obj.mkii
@@ -11,9 +11,49 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% todo, move more to mkiv, get rid of blabelgroup
+
+\writestatus{loading}{ConTeXt Core Macros / Object Handling}
+
\unprotect
-\def\mkcheckobjectreferences
+%D \macros
+%D {setobject,getobject,ifinobject}
+%D
+%D Boxes can be considered reuable objects. Unfortunaltely once
+%D passed to the \DVI\ file, such objects cannot be reused. In
+%D \PDF\ however, reusing is possible and sometimes even a
+%D necessity. Therefore, \CONTEXT\ supports reusable objects.
+%D
+%D During the \TEX\ processing run, boxes can serve the purpose
+%D of objects, and the \DVI\ driver module implements objects
+%D using packed boxes.
+%D
+%D The \PDF\ and \PDFTEX\ driver modules implement objects
+%D using \PDF\ forms. There is no (real) restriction on the
+%D number of objects there.
+%D
+%D The first application of objects in \CONTEXT\ concerned
+%D \METAPOST\ graphics and fill||in form fields. The first
+%D application can save lots of bytes, while the latter use is
+%D more a necessity than byte saving.
+%D
+%D \starttyping
+%D \setobject{class}{name}\somebox{}
+%D \getobject{class}{name}
+%D \stoptyping
+%D
+%D Here \type{\somebox} can be whatever box specification suits
+%D \TEX. We save the dimensions of an object, although some
+%D drivers will do so themselves. This means that when for
+%D instance using \PDFTEX\ we could save a hash entry plus some
+%D 20+ memory locations per object by delegating this
+%D housekeeping to the driver. The current approach permits
+%D us to keep the box characteristic too.
+
+\newif\ifinobject
+
+\def\checkobjectreferences
{\startnointerference
\protectlabels
\ifx\usedoutputdriver\currentoutput
@@ -24,6 +64,198 @@
\global\let\checkobjectreferences\relax
\stopnointerference}
+\def\objectplaceholder{NOT YET FLUSHED}%
+
+\def\presetobject#1#2% \global added
+ {\blabelgroup
+ \ifcsname\r!object#1::#2\endcsname\else
+ \global\@EA\let\csname\r!object#1::#2\endcsname\objectplaceholder
+ \fi
+ \elabelgroup}
+
+\def\dosetobject#1#2#3% \initializepaper this will move to \everyshipout
+ {\initializepaper
+ \blabelgroup
+ \ifcsname\r!object#2::#3\endcsname
+ \elabelgroup \expandafter\gobblefivearguments
+ \else % tzt, overload internal referenced objects to save entries
+ \elabelgroup \expandafter\dodosetobject
+ \fi
+ {#1}{#2}{#3}}
+
+\def\resetobject#1#2%
+ {\checkobjectreferences
+ \letbeundefined{\r!object#1::#2}}
+
+%D \macros
+%D {finalizeobjectbox}
+%D
+%D This one provides a hook for last minute object box processing
+%D we need this in \MKIV.
+
+\ifx\finalizeobjectbox\undefined
+ \let\finalizeobjectbox\gobbleoneargument
+\fi
+
+%D Somehow there is a rounding error problem in either \PDFTEX\
+%D or in viewers, or maybe it is conforming the specs. The next
+%D variable compensate for it by removing the rather tight
+%D clip.
+
+\def\objectoffset{1cm}
+
+% \def\dodosetobject#1#2#3%
+% {\bgroup
+% \inobjecttrue
+% \dowithnextbox{\dododosetobject{#1}{#2}{#3}\egroup}}
+
+\def\dodosetobject#1#2#3%
+ {\bgroup
+ \globalpushmacro\crossreferenceobject \objectreferenced
+ \inobjecttrue
+ \dowithnextbox
+ {\globalpopmacro\crossreferenceobject
+ \dododosetobject{#1}{#2}{#3}\egroup}}
+
+\def\dododosetobject#1#2#3%
+ {\blabelgroup
+ \dontshowcomposition % rather fuzzy in \setxvalue ... \hbox
+ \scratchdimen\objectoffset
+ \@EA\xdef\csname\r!object#2::#3\endcsname
+ {\noexpand\dohandleobject{#2}{#3}%
+ {\ifhbox\nextbox\hbox\else\vbox\fi}%
+ %{\the\nextboxwd}{\the\nextboxht}{\the\nextboxdp}}%
+ {\number\nextboxwd}{\number\nextboxht}{\number\nextboxdp}%
+ {\number\scratchdimen}}%
+ \expanded % freeze the dimensions since \dostartobject may use \nextbox
+ {\dostartobject
+ {#2}{#3}{\the\nextboxwd}{\the\nextboxht}{\the\nextboxdp}}%
+ \ifcase#1\relax\else \ifdim\objectoffset>\zeropoint
+ \setbox\nextbox\vbox spread 2\scratchdimen
+ {\forgetall \offinterlineskip
+ \vss\hbox spread 2\scratchdimen{\hss\flushnextbox\hss}\vss}%
+ \fi \fi
+ \flushnextbox
+ \dostopobject
+ \elabelgroup}
+
+\def\getobject#1#2%
+ {\blabelgroup
+ \let\dohandleobject\dogetobject
+ \csname\r!object#1::#2\endcsname}
+
+% \def\dogetobject#1#2#3#4#5#6%
+% {\initializepaper
+% \forgetall
+% \dontshowcomposition
+% \setbox\scratchbox\vbox
+% {\doinsertobject{#1}{#2}}%
+% \setbox\scratchbox#3%
+% {\vbox to #5\scaledpoint
+% {\ifdim\ht\scratchbox>#5\scaledpoint
+% % or \ifdim\wd\scratchbox>#4\scaledpoint
+% \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+% \else
+% \vss\box\scratchbox
+% \fi}}%
+% \wd\scratchbox#4\scaledpoint
+% \ht\scratchbox#5\scaledpoint
+% \dp\scratchbox#6\scaledpoint
+% \box\scratchbox
+% \elabelgroup}
+
+% \def\dogetobject#1#2#3#4#5#6#7%
+% {\initializepaper
+% \forgetall
+% \dontshowcomposition
+% \setbox\scratchbox\vbox
+% {\doinsertobject{#1}{#2}}%
+% \setbox\scratchbox#3%
+% {\vbox to #5\scaledpoint
+% {\ifdim\ht\scratchbox>#5\scaledpoint
+% % or \ifdim\wd\scratchbox>#4\scaledpoint
+% \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+% \else
+% \vss\box\scratchbox
+% \fi}}%
+% \scratchdimen#7\scaledpoint
+% \setbox\nextbox\hbox
+% {\hskip-\scratchdimen\lower\scratchdimen\flushnextbox}%
+% \wd\scratchbox#4\scaledpoint
+% \ht\scratchbox#5\scaledpoint
+% \dp\scratchbox#6\scaledpoint
+% \box\scratchbox
+% \elabelgroup}
+
+\def\dogetobject#1#2#3#4#5#6#7% don't change this, should work for dvi & pdf
+ {\initializepaper
+ \forgetall
+ \dontshowcomposition
+ \setbox\scratchbox\vbox
+ {\doinsertobject{#1}{#2}}%
+ \setbox\scratchbox#3%
+ {\vbox to #5\scaledpoint
+ {\ifdim\ht\scratchbox>#5\scaledpoint
+ \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+ \else\ifdim\wd\scratchbox>#4\scaledpoint
+ \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+ \else
+ %\vss\box\scratchbox
+ \vss\hbox to #4\scaledpoint{\box\scratchbox\hss}% fix Chof
+ \fi\fi}}%
+ \box\scratchbox
+ \elabelgroup}
+
+%D If needed one can ask for the dimensions of an object with:
+%D
+%D \starttyping
+%D \getobjectdimensions{class}{name}
+%D \stoptyping
+%D
+%D The results are reported in \type {\objectwidth}, \type
+%D {\objectheight} and \type {\objectdepth}.
+
+% \def\dogetobjectdimensions#1#2#3#4#5#6%
+% {\def\objectwidth {#4\s!sp}%
+% \def\objectheight{#5\s!sp}%
+% \def\objectdepth {#6\s!sp}}
+
+\def\dogetobjectdimensions#1#2#3#4#5#6#7%
+ {\def\objectwidth {#4\s!sp}%
+ \def\objectheight{#5\s!sp}%
+ \def\objectdepth {#6\s!sp}%
+ \def\objectmargin{#7\s!sp}}
+
+\def\getobjectdimensions#1#2%
+ {\let\dohandleobject\dogetobjectdimensions
+ \let\objectwidth \!!zeropoint
+ \let\objectheight\!!zeropoint
+ \let\objectdepth \!!zeropoint
+ \labelcsname\r!object#1::#2\endcsname}
+
+%D Apart from this kind of objects, that have typeset content,
+%D we can have low level driver specific objects. Both types
+%D can have references to internal representations, hidden for
+%D the user. We keep track of such references by means of a
+%D dedicated cross reference mechanism. Normally, objects are
+%D defined before they are used, but forward referencing
+%D sometimes occurs.
+%D
+%D \starttyping
+%D \dosetobjectreference {class} {identifier} {reference value} {page}
+%D \dogetobjectreference {class} {identifier} \csname
+%D \stoptyping
+%D
+%D These commands are to be called by the \type{\startobject},
+%D \type{\stopobject} and \type{\insertobject} specials.
+
+\def\objectreferenced{\global\chardef\crossreferenceobject\plusone}
+\def\driverreferenced{\global\chardef\crossreferenceobject\zerocount}
+
+\objectreferenced
+
+% no undefined test ! ! ! ! (pdftex fails on undefined objects)
+
\def\setobjectreferences
{\def\objectreference##1##2##3##4%
{\ifundefined{\r!driver##1::##2}%
@@ -37,19 +269,36 @@
\resetobjectreferences
-\def\mkregisterobjectreference#1#2#3%
+\def\doregisterobjectreference#1#2#3%
{\checkobjectreferences
\blabelgroup
\expanded{\writeutilitycommand{\noexpand\objectreference{#1}{#2}{#3}{\noexpand\realfolio}}}%
\setxvalue{\r!driver#1::#2}{{#3}{\noexpand\realfolio}}%
\elabelgroup}
-\def\mkoverloadobjectreference#1#2#3%
+\def\dooverloadobjectreference#1#2#3%
{\checkobjectreferences
\blabelgroup
\setxvalue{\r!driver#1::#2}{{#3}{\noexpand\realfolio}}%
\elabelgroup}
+\def\dosetobjectreference
+ {\ifcase\crossreferenceobject
+ \objectreferenced
+ \expandafter\dooverloadobjectreference
+ \else
+ \expandafter\doregisterobjectreference
+ \fi}
+
+\def\dosetdriverreference
+ {\driverreferenced\dosetobjectreference}
+
+\def\defaultobjectreference#1#2{0} % driver dependent
+\def\defaultobjectpage #1#2{\realfolio}
+
+\def\dogetobjectreference {\dodogetobjectreference\firstoftwoarguments\defaultobjectreference}
+\def\dogetobjectreferencepage{\dodogetobjectreference\secondoftwoarguments\defaultobjectpage}
+
\def\dodogetobjectreference#1#2#3#4#5%
{\checkobjectreferences
\blabelgroup
@@ -61,13 +310,28 @@
\fi
\elabelgroup}
-\def\mkgetobjectreference
- {\dodogetobjectreference\firstoftwoarguments\defaultobjectreference}
+\def\setobject {\driverreferenced\dosetobject1}
+\def\settightobject{\driverreferenced\dosetobject0}
+
+%D \macros
+%D {doifobjectfoundelse,doifobjectreferencefoundelse}
+%D
+%D To prevent redundant definition of objects, one can use
+%D the next tests:
+%D
+%D \starttyping
+%D \doifobjectfoundelse{class}{object}{do then}{do else}
+%D \doifobjectreferencefoundelse{class}{object}{do then}{do else}
+%D \stoptyping
-\def\mkgetobjectreferencepage
- {\dodogetobjectreference\secondoftwoarguments\defaultobjectpage}
+\def\doifobjectfoundelse#1#2%
+ {\blabelgroup \ifcsname\r!object#1::#2\endcsname
+ \elabelgroup \expandafter\firstoftwoarguments
+ \else
+ \elabelgroup \expandafter\secondoftwoarguments
+ \fi}
-\def\mkdoifobjectreferencefoundelse#1#2%
+\def\doifobjectreferencefoundelse#1#2%
{\checkobjectreferences
\blabelgroup \ifcsname\r!driver#1::#2\endcsname
\elabelgroup \expandafter\firstoftwoarguments
@@ -75,4 +339,33 @@
\elabelgroup \expandafter\secondoftwoarguments
\fi}
+%D \macros
+%D {doifobjectssupportedelse}
+%D
+%D Starting with reuse of graphics, we will implement object
+%D reuse when possible. To enable mechanisms to determine
+%D what method to use, we provide:
+%D
+%D \starttyping
+%D \doifobjectssupportedelse{true action}{false action}
+%D \stoptyping
+%D
+%D As we can see, currently objects depend on the special
+%D driver.
+
+\newif\ifobjectssupported \objectssupportedtrue
+
+\def\doifobjectssupportedelse
+ {\ifobjectssupported
+ \@EA\doifspecialavailableelse\@EA\doinsertobject
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+%D There is a conceptual problem here. Objects are not possible
+%D in \DVI, unless faked like in \type {spec-dvi}. This means
+%D that we must be careful in loading special drivers that do
+%D support objects while we still want to be able to use the
+%D \DVI\ output.
+
\protect \endinput
diff --git a/tex/context/base/core-obj.mkiv b/tex/context/base/core-obj.mkiv
index 3a54e6507..560a7012d 100644
--- a/tex/context/base/core-obj.mkiv
+++ b/tex/context/base/core-obj.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-obj,
-%D version=2006.10.16,
+%D version=1998.01.15,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Object Handling,
%D author=Hans Hagen,
@@ -11,16 +11,224 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Object Handling}
+
\unprotect
\let\objectreference\gobblefourarguments % catch mkii tuo stuff
\registerctxluafile{core-obj}{1.001}
-\def\mkregisterobjectreference #1#2#3{\expanded{\ctxlatelua{jobobjects.save("#1::#2",#3,\noexpand\the\realpageno)}}}
-\def\mkoverloadobjectreference #1#2#3{\ctxlua{jobobjects.set("#1::#2",#3,\the\realpageno)}}
-\def\mkgetobjectreference #1#2#3{\xdef#3{\ctxlua{jobobjects.number("#1::#2","\defaultobjectreference{#1}{#2}")}}}
-\def\mkgetobjectreferencepage #1#2#3{\xdef#3{\ctxlua{jobobjects.page("#1::#2","\defaultobjectpage{#1}{#2}")}}}
-\def\mkdoifobjectreferencefoundelse#1#2{\ctxlua{jobobjects.doifelse("#1::#2")}}
+%D \macros
+%D {setobject,getobject,ifinobject}
+%D
+%D Boxes can be considered reuable objects. Unfortunaltely once
+%D passed to the \DVI\ file, such objects cannot be reused. In
+%D \PDF\ however, reusing is possible and sometimes even a
+%D necessity. Therefore, \CONTEXT\ supports reusable objects.
+%D
+%D During the \TEX\ processing run, boxes can serve the purpose
+%D of objects, and the \DVI\ driver module implements objects
+%D using packed boxes.
+%D
+%D The \PDF\ and \PDFTEX\ driver modules implement objects
+%D using \PDF\ forms. There is no (real) restriction on the
+%D number of objects there.
+%D
+%D The first application of objects in \CONTEXT\ concerned
+%D \METAPOST\ graphics and fill||in form fields. The first
+%D application can save lots of bytes, while the latter use is
+%D more a necessity than byte saving.
+%D
+%D \starttyping
+%D \setobject{class}{name}\somebox{}
+%D \getobject{class}{name}
+%D \stoptyping
+%D
+%D Here \type{\somebox} can be whatever box specification suits
+%D \TEX. We save the dimensions of an object, although some
+%D drivers will do so themselves. This means that when for
+%D instance using \PDFTEX\ we could save a hash entry plus some
+%D 20+ memory locations per object by delegating this
+%D housekeeping to the driver. The current approach permits
+%D us to keep the box characteristic too.
+
+\newif\ifinobject
+
+\def\objectplaceholder{NOT YET FLUSHED}%
+
+\def\presetobject#1#2% \global added
+ {\ifcsname\r!object#1::#2\endcsname\else
+ \global\@EA\let\csname\r!object#1::#2\endcsname\objectplaceholder
+ \fi}
+
+\def\dosetobject#1#2#3% \initializepaper this will move to \everyshipout
+ {\initializepaper
+ \ifcsname\r!object#2::#3\endcsname
+ \expandafter\gobblefivearguments
+ \else % tzt, overload internal referenced objects to save entries
+ \expandafter\dodosetobject
+ \fi
+ {#1}{#2}{#3}}
+
+\def\resetobject#1#2%
+ {\letbeundefined{\r!object#1::#2}}
+
+%D \macros
+%D {finalizeobjectbox}
+%D
+%D This one provides a hook for last minute object box processing
+%D we need this in \MKIV.
+
+\ifx\finalizeobjectbox\undefined
+ \let\finalizeobjectbox\gobbleoneargument
+\fi
+
+%D Somehow there is a rounding error problem in either \PDFTEX\
+%D or in viewers, or maybe it is conforming the specs. The next
+%D variable compensate for it by removing the rather tight
+%D clip.
+
+\def\objectoffset{1cm}
+
+\def\dodosetobject#1#2#3%
+ {\bgroup
+ \globalpushmacro\crossreferenceobject \objectreferenced
+ \inobjecttrue
+ \dowithnextbox
+ {\globalpopmacro\crossreferenceobject
+ \dododosetobject{#1}{#2}{#3}\egroup}}
+
+\def\dododosetobject#1#2#3%
+ {\begingroup
+ \dontshowcomposition % rather fuzzy in \setxvalue ... \hbox
+ \scratchdimen\objectoffset
+ \@EA\xdef\csname\r!object#2::#3\endcsname
+ {\noexpand\dohandleobject{#2}{#3}%
+ {\ifhbox\nextbox\hbox\else\vbox\fi}%
+ {\number\nextboxwd}{\number\nextboxht}{\number\nextboxdp}%
+ {\number\scratchdimen}}%
+ \expanded % freeze the dimensions since \dostartobject may use \nextbox
+ {\dostartobject{#2}{#3}{\the\nextboxwd}{\the\nextboxht}{\the\nextboxdp}}%
+ \ifcase#1\relax\else \ifdim\objectoffset>\zeropoint
+ \setbox\nextbox\vbox spread 2\scratchdimen
+ {\forgetall \offinterlineskip
+ \vss\hbox spread 2\scratchdimen{\hss\flushnextbox\hss}\vss}%
+ \fi \fi
+ \flushnextbox
+ \dostopobject
+ \endgroup}
+
+\def\getobject#1#2%
+ {\begingroup
+ \let\dohandleobject\dogetobject
+ \csname\r!object#1::#2\endcsname}
+
+\def\dogetobject#1#2#3#4#5#6#7% don't change this, should work for dvi & pdf
+ {\initializepaper
+ \forgetall
+ \dontshowcomposition
+ \setbox\scratchbox\vbox
+ {\doinsertobject{#1}{#2}}%
+ \setbox\scratchbox#3%
+ {\vbox to #5\scaledpoint
+ {\ifdim\ht\scratchbox>#5\scaledpoint
+ \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+ \else\ifdim\wd\scratchbox>#4\scaledpoint
+ \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
+ \else
+ %\vss\box\scratchbox
+ \vss\hbox to #4\scaledpoint{\box\scratchbox\hss}% fix Chof
+ \fi\fi}}%
+ \box\scratchbox
+ \endgroup}
+
+%D If needed one can ask for the dimensions of an object with:
+%D
+%D \starttyping
+%D \getobjectdimensions{class}{name}
+%D \stoptyping
+%D
+%D The results are reported in \type {\objectwidth}, \type
+%D {\objectheight} and \type {\objectdepth}.
+
+\def\dogetobjectdimensions#1#2#3#4#5#6#7%
+ {\def\objectwidth {#4\s!sp}%
+ \def\objectheight{#5\s!sp}%
+ \def\objectdepth {#6\s!sp}%
+ \def\objectmargin{#7\s!sp}}
+
+\def\getobjectdimensions#1#2%
+ {\let\dohandleobject\dogetobjectdimensions
+ \let\objectwidth \!!zeropoint
+ \let\objectheight\!!zeropoint
+ \let\objectdepth \!!zeropoint
+ \labelcsname\r!object#1::#2\endcsname}
+
+%D Apart from this kind of objects, that have typeset content,
+%D we can have low level driver specific objects. Both types
+%D can have references to internal representations, hidden for
+%D the user. We keep track of such references by means of a
+%D dedicated cross reference mechanism. Normally, objects are
+%D defined before they are used, but forward referencing
+%D sometimes occurs.
+%D
+%D \starttyping
+%D \dosetobjectreference {class} {identifier} {reference value} {page}
+%D \dogetobjectreference {class} {identifier} \csname
+%D \stoptyping
+%D
+%D These commands are to be called by the \type{\startobject},
+%D \type{\stopobject} and \type{\insertobject} specials.
+
+\def\objectreferenced{\global\chardef\crossreferenceobject\plusone}
+\def\driverreferenced{\global\chardef\crossreferenceobject\zerocount}
+
+\objectreferenced
+
+% no undefined test ! ! ! ! (pdftex fails on undefined objects)
+
+\def\doregisterobjectreference#1#2#3{\normalexpanded{\noexpand\ctxlatelua{jobobjects.save("#1::#2",#3,\noexpand\the\realpageno)}}}
+\def\dooverloadobjectreference#1#2#3{\ctxlua{jobobjects.set("#1::#2",#3,\the\realpageno)}}
+
+\def\dosetobjectreference
+ {\ifcase\crossreferenceobject
+ \objectreferenced
+ \expandafter\dooverloadobjectreference
+ \else
+ \expandafter\doregisterobjectreference
+ \fi}
+
+\def\dosetdriverreference
+ {\driverreferenced\dosetobjectreference}
+
+\def\defaultobjectreference#1#2{0} % driver dependent
+\def\defaultobjectpage #1#2{\realfolio}
+
+\def\dogetobjectreference #1#2#3{\xdef#3{\ctxlua{jobobjects.number("#1::#2","\defaultobjectreference{#1}{#2}")}}}
+\def\dogetobjectreferencepage#1#2#3{\xdef#3{\ctxlua{jobobjects.page("#1::#2","\defaultobjectpage{#1}{#2}")}}}
+
+\def\setobject {\driverreferenced\dosetobject1}
+\def\settightobject{\driverreferenced\dosetobject0}
+
+%D \macros
+%D {doifobjectfoundelse,doifobjectreferencefoundelse}
+%D
+%D To prevent redundant definition of objects, one can use
+%D the next tests:
+%D
+%D \starttyping
+%D \doifobjectfoundelse{class}{object}{do then}{do else}
+%D \doifobjectreferencefoundelse{class}{object}{do then}{do else}
+%D \stoptyping
+
+\def\doifobjectfoundelse#1#2%
+ {\ifcsname\r!object#1::#2\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifobjectreferencefoundelse#1#2{\ctxlua{jobobjects.doifelse("#1::#2")}}
\protect \endinput
diff --git a/tex/context/base/core-obj.tex b/tex/context/base/core-obj.tex
deleted file mode 100644
index 23873d2d6..000000000
--- a/tex/context/base/core-obj.tex
+++ /dev/null
@@ -1,365 +0,0 @@
-%D \module
-%D [ file=core-obj,
-%D version=1998.01.15,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Object Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% todo, move more to mkiv, get rid of blabelgroup
-
-\writestatus{loading}{Context Core Macros / Object Handling}
-
-\unprotect
-
-\startmessages dutch library: references
- 30: onbekend object --
- 31: dubbel object --
-\stopmessages
-
-\startmessages english library: references
- 30: unknown object --
- 31: duplicate object --
-\stopmessages
-
-\startmessages german library: references
- 30: unbekanntes Object --
- 31: doppeltes Object --
-\stopmessages
-
-\startmessages czech library: references
- 30: neznamy objekt --
- 31: duplicitni object --
-\stopmessages
-
-\startmessages italian library: references
- 30: oggetto sconosciuto --
- 31: oggetto duplicato --
-\stopmessages
-
-\startmessages norwegian library: references
- 30: ukjent objekt --
- 31: duplikat objekt --
-\stopmessages
-
-\startmessages romanian library: references
- 30: obiect necunoscut --
- 31: obiect duplicat --
-\stopmessages
-
-\startmessages french library: references
- 30: objet -- inconnu
- 31: objet -- dupliqué
-\stopmessages
-
-%D \macros
-%D {setobject,getobject,ifinobject}
-%D
-%D Boxes can be considered reuable objects. Unfortunaltely once
-%D passed to the \DVI\ file, such objects cannot be reused. In
-%D \PDF\ however, reusing is possible and sometimes even a
-%D necessity. Therefore, \CONTEXT\ supports reusable objects.
-%D
-%D During the \TEX\ processing run, boxes can serve the purpose
-%D of objects, and the \DVI\ driver module implements objects
-%D using packed boxes.
-%D
-%D The \PDF\ and \PDFTEX\ driver modules implement objects
-%D using \PDF\ forms. There is no (real) restriction on the
-%D number of objects there.
-%D
-%D The first application of objects in \CONTEXT\ concerned
-%D \METAPOST\ graphics and fill||in form fields. The first
-%D application can save lots of bytes, while the latter use is
-%D more a necessity than byte saving.
-%D
-%D \starttyping
-%D \setobject{class}{name}\somebox{}
-%D \getobject{class}{name}
-%D \stoptyping
-%D
-%D Here \type{\somebox} can be whatever box specification suits
-%D \TEX. We save the dimensions of an object, although some
-%D drivers will do so themselves. This means that when for
-%D instance using \PDFTEX\ we could save a hash entry plus some
-%D 20+ memory locations per object by delegating this
-%D housekeeping to the driver. The current approach permits
-%D us to keep the box characteristic too.
-
-\newif\ifinobject
-
-\ifx\mkcheckobjectreferences\undefined \let\mkcheckobjectreferences\relax \fi
-
-\def\checkobjectreferences{\mkcheckobjectreferences}
-
-\def\objectplaceholder{NOT YET FLUSHED}%
-
-\def\presetobject#1#2% \global added
- {\blabelgroup
- \ifcsname\r!object#1::#2\endcsname\else
- \global\@EA\let\csname\r!object#1::#2\endcsname\objectplaceholder
- \fi
- \elabelgroup}
-
-\def\dosetobject#1#2#3% \initializepaper this will move to \everyshipout
- {\initializepaper
- \blabelgroup
- \ifcsname\r!object#2::#3\endcsname
- \elabelgroup \expandafter\gobblefivearguments
- \else % tzt, overload internal referenced objects to save entries
- \elabelgroup \expandafter\dodosetobject
- \fi
- {#1}{#2}{#3}}
-
-\def\resetobject#1#2%
- {\checkobjectreferences
- \letbeundefined{\r!object#1::#2}}
-
-%D \macros
-%D {finalizeobjectbox}
-%D
-%D This one provides a hook for last minute object box processing
-%D we need this in \MKIV.
-
-\ifx\finalizeobjectbox\undefined
- \let\finalizeobjectbox\gobbleoneargument
-\fi
-
-%D Somehow there is a rounding error problem in either \PDFTEX\
-%D or in viewers, or maybe it is conforming the specs. The next
-%D variable compensate for it by removing the rather tight
-%D clip.
-
-\def\objectoffset{1cm}
-
-% \def\dodosetobject#1#2#3%
-% {\bgroup
-% \inobjecttrue
-% \dowithnextbox{\dododosetobject{#1}{#2}{#3}\egroup}}
-
-\def\dodosetobject#1#2#3%
- {\bgroup
- \globalpushmacro\crossreferenceobject \objectreferenced
- \inobjecttrue
- \dowithnextbox
- {\globalpopmacro\crossreferenceobject
- \dododosetobject{#1}{#2}{#3}\egroup}}
-
-\def\dododosetobject#1#2#3%
- {\blabelgroup
- \dontshowcomposition % rather fuzzy in \setxvalue ... \hbox
- \scratchdimen\objectoffset
- \@EA\xdef\csname\r!object#2::#3\endcsname
- {\noexpand\dohandleobject{#2}{#3}%
- {\ifhbox\nextbox\hbox\else\vbox\fi}%
- %{\the\nextboxwd}{\the\nextboxht}{\the\nextboxdp}}%
- {\number\nextboxwd}{\number\nextboxht}{\number\nextboxdp}%
- {\number\scratchdimen}}%
- \expanded % freeze the dimensions since \dostartobject may use \nextbox
- {\dostartobject
- {#2}{#3}{\the\nextboxwd}{\the\nextboxht}{\the\nextboxdp}}%
- \ifcase#1\relax\else \ifdim\objectoffset>\zeropoint
- \setbox\nextbox\vbox spread 2\scratchdimen
- {\forgetall \offinterlineskip
- \vss\hbox spread 2\scratchdimen{\hss\flushnextbox\hss}\vss}%
- \fi \fi
- \flushnextbox
- \dostopobject
- \elabelgroup}
-
-\def\getobject#1#2%
- {\blabelgroup
- \let\dohandleobject\dogetobject
- \csname\r!object#1::#2\endcsname}
-
-% \def\dogetobject#1#2#3#4#5#6%
-% {\initializepaper
-% \forgetall
-% \dontshowcomposition
-% \setbox\scratchbox\vbox
-% {\doinsertobject{#1}{#2}}%
-% \setbox\scratchbox#3%
-% {\vbox to #5\scaledpoint
-% {\ifdim\ht\scratchbox>#5\scaledpoint
-% % or \ifdim\wd\scratchbox>#4\scaledpoint
-% \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
-% \else
-% \vss\box\scratchbox
-% \fi}}%
-% \wd\scratchbox#4\scaledpoint
-% \ht\scratchbox#5\scaledpoint
-% \dp\scratchbox#6\scaledpoint
-% \box\scratchbox
-% \elabelgroup}
-
-% \def\dogetobject#1#2#3#4#5#6#7%
-% {\initializepaper
-% \forgetall
-% \dontshowcomposition
-% \setbox\scratchbox\vbox
-% {\doinsertobject{#1}{#2}}%
-% \setbox\scratchbox#3%
-% {\vbox to #5\scaledpoint
-% {\ifdim\ht\scratchbox>#5\scaledpoint
-% % or \ifdim\wd\scratchbox>#4\scaledpoint
-% \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
-% \else
-% \vss\box\scratchbox
-% \fi}}%
-% \scratchdimen#7\scaledpoint
-% \setbox\nextbox\hbox
-% {\hskip-\scratchdimen\lower\scratchdimen\flushnextbox}%
-% \wd\scratchbox#4\scaledpoint
-% \ht\scratchbox#5\scaledpoint
-% \dp\scratchbox#6\scaledpoint
-% \box\scratchbox
-% \elabelgroup}
-
-\def\dogetobject#1#2#3#4#5#6#7% don't change this, should work for dvi & pdf
- {\initializepaper
- \forgetall
- \dontshowcomposition
- \setbox\scratchbox\vbox
- {\doinsertobject{#1}{#2}}%
- \setbox\scratchbox#3%
- {\vbox to #5\scaledpoint
- {\ifdim\ht\scratchbox>#5\scaledpoint
- \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
- \else\ifdim\wd\scratchbox>#4\scaledpoint
- \vss\hbox to #4\scaledpoint{\hss\box\scratchbox\hss}\vss
- \else
- %\vss\box\scratchbox
- \vss\hbox to #4\scaledpoint{\box\scratchbox\hss}% fix Chof
- \fi\fi}}%
- \box\scratchbox
- \elabelgroup}
-
-%D If needed one can ask for the dimensions of an object with:
-%D
-%D \starttyping
-%D \getobjectdimensions{class}{name}
-%D \stoptyping
-%D
-%D The results are reported in \type {\objectwidth}, \type
-%D {\objectheight} and \type {\objectdepth}.
-
-% \def\dogetobjectdimensions#1#2#3#4#5#6%
-% {\def\objectwidth {#4\s!sp}%
-% \def\objectheight{#5\s!sp}%
-% \def\objectdepth {#6\s!sp}}
-
-\def\dogetobjectdimensions#1#2#3#4#5#6#7%
- {\def\objectwidth {#4\s!sp}%
- \def\objectheight{#5\s!sp}%
- \def\objectdepth {#6\s!sp}%
- \def\objectmargin{#7\s!sp}}
-
-\def\getobjectdimensions#1#2%
- {\let\dohandleobject\dogetobjectdimensions
- \let\objectwidth \!!zeropoint
- \let\objectheight\!!zeropoint
- \let\objectdepth \!!zeropoint
- \labelcsname\r!object#1::#2\endcsname}
-
-%D Apart from this kind of objects, that have typeset content,
-%D we can have low level driver specific objects. Both types
-%D can have references to internal representations, hidden for
-%D the user. We keep track of such references by means of a
-%D dedicated cross reference mechanism. Normally, objects are
-%D defined before they are used, but forward referencing
-%D sometimes occurs.
-%D
-%D \starttyping
-%D \dosetobjectreference {class} {identifier} {reference value} {page}
-%D \dogetobjectreference {class} {identifier} \csname
-%D \stoptyping
-%D
-%D These commands are to be called by the \type{\startobject},
-%D \type{\stopobject} and \type{\insertobject} specials.
-
-\def\objectreferenced{\global\chardef\crossreferenceobject\plusone}
-\def\driverreferenced{\global\chardef\crossreferenceobject\zerocount}
-
-\objectreferenced
-
-% no undefined test ! ! ! ! (pdftex fails on undefined objects)
-
-\def\dosetobjectreference
- {\ifcase\crossreferenceobject
- \objectreferenced
- \expandafter\mkoverloadobjectreference
- \else
- \expandafter\mkregisterobjectreference
- \fi}
-
-\def\dosetdriverreference
- {\driverreferenced\dosetobjectreference}
-
-\def\defaultobjectreference#1#2{0} % driver dependent
-\def\defaultobjectpage #1#2{\realfolio}
-
-\def\dogetobjectreference {\mkgetobjectreference}
-\def\dogetobjectreferencepage{\mkgetobjectreferencepage}
-
-\def\setobject {\driverreferenced\dosetobject1}
-\def\settightobject{\driverreferenced\dosetobject0}
-
-%D \macros
-%D {doifobjectfoundelse,doifobjectreferencefoundelse}
-%D
-%D To prevent redundant definition of objects, one can use
-%D the next tests:
-%D
-%D \starttyping
-%D \doifobjectfoundelse{class}{object}{do then}{do else}
-%D \doifobjectreferencefoundelse{class}{object}{do then}{do else}
-%D \stoptyping
-
-\def\doifobjectfoundelse#1#2%
- {\blabelgroup \ifcsname\r!object#1::#2\endcsname
- \elabelgroup \expandafter\firstoftwoarguments
- \else
- \elabelgroup \expandafter\secondoftwoarguments
- \fi}
-
-\def\doifobjectreferencefoundelse{\mkdoifobjectreferencefoundelse}
-
-%D \macros
-%D {doifobjectssupportedelse}
-%D
-%D Starting with reuse of graphics, we will implement object
-%D reuse when possible. To enable mechanisms to determine
-%D what method to use, we provide:
-%D
-%D \starttyping
-%D \doifobjectssupportedelse{true action}{false action}
-%D \stoptyping
-%D
-%D As we can see, currently objects depend on the special
-%D driver.
-
-\newif\ifobjectssupported \objectssupportedtrue
-
-\def\doifobjectssupportedelse
- {\ifobjectssupported
- \@EA\doifspecialavailableelse\@EA\doinsertobject
- \else
- \@EA\secondoftwoarguments
- \fi}
-
-%D There is a conceptual problem here. Objects are not possible
-%D in \DVI, unless faked like in \type {spec-dvi}. This means
-%D that we must be careful in loading special drivers that do
-%D support objects while we still want to be able to use the
-%D \DVI\ output.
-
-%D Plugin code:
-
-\loadmarkfile{core-obj}
-
-\protect \endinput
diff --git a/tex/context/base/core-par.tex b/tex/context/base/core-par.tex
index aa58ebb1e..0b283b294 100644
--- a/tex/context/base/core-par.tex
+++ b/tex/context/base/core-par.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{ConTeXt Pararaph Tricks}
+\writestatus{loading}{ConTeXt Core Macros / Pararaph Tricks}
\unprotect
diff --git a/tex/context/base/core-pgr.tex b/tex/context/base/core-pgr.tex
index e6f91cec8..ab2378441 100644
--- a/tex/context/base/core-pgr.tex
+++ b/tex/context/base/core-pgr.tex
@@ -2,7 +2,7 @@
%D [ file=core-pgr, % split off core-pos
%D version=1999.08.01,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Positioning Support,
+%D subtitle=Positioning Graphics,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Positioning Grapics}
+\writestatus{loading}{ConTeXt Core Macros / Positioning Grapics}
%D Before we come to graphics support, we have to make sure of
%D the reference point on the page. The next macro does so and
@@ -898,7 +898,7 @@
\def\calculatenexttextpardimensions
{\docalculatetextpardimensions\nextbtbanchor\nextetbanchor\relax}
-\def\docalculatetextpardimensions#1#2#3%
+\def\docalculatetextpardimensions#1#2#3% todo: dimexpr
{\scratchcounter\MPp#2%\etbanchor
\advance\scratchcounter-\MPp#1%\btanchor
\edef\textparpages{\the\scratchcounter}%
@@ -911,7 +911,7 @@
\scratchdimen \MPy#1%\btanchor
\advance\scratchdimen-\MPy#2%\etbanchor
\advance\scratchdimen-\MPy\textanchor
- \advance\scratchdimen \MPy\textanchor
+ \advance\scratchdimen \MPy\textanchor % - and then + ?
\advance\scratchdimen \MPh\textanchor\relax
\ifcase\scratchcounter>2 \ifnum\scratchcounter<5
% more pages
@@ -1185,7 +1185,7 @@
% \stopbuffer
% \getbuffer \typebuffer \flushstatus \page
-\newdimen\laststackvmove
+\newdimen\laststackvmove % use \scratchdimenone instead of skip
\def\stackeddown
{\bgroup
@@ -1214,7 +1214,7 @@
-\MPd\currentposition % untested
+\MPd\previousposition % untested
+\MPh\currentposition
- \relax
+ \relax\relax % second relax realy needed, forgotten while dimexpressing
% todo: also take depth into account
\ifdim\scratchskip<\scratchdimen
%\registerstatus{no \the\scratchskip}%
diff --git a/tex/context/base/core-pos.lua b/tex/context/base/core-pos.lua
index 212c65190..be2ac1915 100644
--- a/tex/context/base/core-pos.lua
+++ b/tex/context/base/core-pos.lua
@@ -18,6 +18,8 @@ jobpositions = jobpositions or { }
jobpositions.collected = jobpositions.collected or { }
jobpositions.tobesaved = jobpositions.tobesaved or { }
+-- these are global since they are used often at the tex end
+
ptbs, pcol = jobpositions.tobesaved, jobpositions.collected -- global
local function initializer()
@@ -35,7 +37,7 @@ function jobpositions.replace(name,...)
end
function jobpositions.doifelse(name)
- cs.testcase(jobpositions.collected[name] or ptbs[name])
+ commands.testcase(jobpositions.collected[name] or ptbs[name])
end
function jobpositions.MPp(id) local jpi = pcol[id] or ptbs[id] texprint((jpi and jpi[1]) or '0' ) end
diff --git a/tex/context/base/core-pos.mkii b/tex/context/base/core-pos.mkii
index 754673cfa..58784ed7b 100644
--- a/tex/context/base/core-pos.mkii
+++ b/tex/context/base/core-pos.mkii
@@ -11,35 +11,86 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
-
-%D A unique prefix used for storing data.
-
-\def\POSprefix{POS::}
-
-%D Reading form the utility file.
-
-\def\pxypos {\pospxy} % obsolete
-\def\pxyposwhd {\pospxywhd} % obsolete
-\def\pxyposplus{\pospxyplus} % obsolete
+% needs a cleanup, things may change; we also need to move the mp
+% related code to meta-pos
-\def\resetpositions
- {\let\pospxy \gobblefourarguments
- \let\pospxywhd \gobblesevenarguments
- \let\pospxyplus\gobbleeightarguments}
+% shorter tags, ..:achtergrond:.. etc in pos actions
-\def\setpositions
- {\let\pospxy \setpospxy
- \let\pospxywhd \setpospxywhd
- \let\pospxyplus\setpospxyplus}
+% dubbele text- * pos's eruit
-%D We need to initialize.
+% class pos -> als gelijk aan vorige, dan niet niet definieren
+% en erven, maw:
+%
+% 1 -> opslaan
+% 2 -> undef, dus == prev
+% 3 -> undef, dus == prev
+% 4 -> opslaan
+
+\writestatus{loading}{ConTeXt Core Macros / Positioning Support}
+
+% todo: topskip als optie voor eerste regel achtergrond
+% todo: build pos layers on top of layers
+% todo: positionlayer pos van text-1 etc delen
+
+%D Although \TEX\ has a rather powerful channel to the outside
+%D world, called \type {\special}, real communication with
+%D other programs is complicated by the fact that no positional
+%D information is available. Mid 1999, I discussed this with
+%D \THANH, the author of \PDFTEX, and after some experiments,
+%D \PDFTEX\ was extended with a simple but effective mechanism,
+%D that provided positional information. The interesting
+%D thought is that, although \TEX\ is frozen, similar
+%D functionality could have been achieved with \type
+%D {\specials} and an additional \DVI\ postprocessor.
+%D
+%D Since we want to be as compatible as can be, \CONTEXT\ will
+%D support both methods, although the development is primarily
+%D driven by the \PDFTEX\ way of doing things. Since the
+%D mechanism is basically not limited to one application, for
+%D the moment we stick to building the functionality around one
+%D \CONTEXT\ special command, but at the same time we keep our
+%D eyes open for extensions in other directions.
+%D
+%D A question that may arise when one reads this module, is to
+%D what extend these macros are generic, in the sense that they
+%D could be collected in a support module instead of a core
+%D module. Since the mechanism described here will closely
+%D cooperate with the \METAPOST\ support built in \CONTEXT,
+%D which in turn will be tightly integrated with the \CONTEXT\
+%D overlay mechanisms, I decided to write a core module instead
+%D of a support one. This makes even more sense, when one takes
+%D into account that this kind of support depends on special
+%D drivers.
-\resetpositions
+\unprotect
-\addutilityreset{positions}
+%D The first application of positional information was embedded
+%D graphics. Since we are interacting with text, it made sense
+%D to take the current line height and depth into account too.
+%D This is why we have two basic position macros: one for
+%D simple positions, and one for boxes.
+%D
+%D We could have sticked to one special, and actually did so in
+%D earlier experiments, but for convenience, as well for
+%D clearness, we now have two alternatives. This approach will
+%D save us quite some bytes when storing large quantities of
+%D positional information. We save as less information as
+%D needed, that is, we save no dimensions, in a \METAPOST\
+%D friendly way.
+%D
+%D The three specials involved are:
+%D
+%D \starttyping
+%D \dosetposition {identifier}
+%D \dosetpositionwhd {identifier} {width} {height} {depth}
+%D \dosetpositionplus {identifier} {width} {height} {depth} {list}
+%D \dosetpositionpapersize {width} {height}
+%D \stoptyping
+
+\newbox\positionbox
+\newif \ifpositioning
-%D Core set macros:
+\def\POSprefix{POS::}
\def\setpospxy#1#2#3#4%
{\@EA\xdef\csname\POSprefix#1\endcsname
@@ -66,6 +117,35 @@
\the\dimexpr#7\relax,%
#8}}
+%D This is real tricky! The page anchor is applied to the
+%D page box and therefore flushed first. So, when present, it
+%D is applied to all positions except itself.
+
+\chardef\positionanchormode=0 % don't relocate page origin
+\chardef\positionanchormode=1 % relocate page origin once
+
+%D The core set macros.
+
+\def\pxypos {\pospxy} % obsolete
+\def\pxyposwhd {\pospxywhd} % obsolete
+\def\pxyposplus{\pospxyplus} % obsolete
+
+\def\resetpositions
+ {\let\pospxy \gobblefourarguments
+ \let\pospxywhd \gobblesevenarguments
+ \let\pospxyplus\gobbleeightarguments}
+
+\def\setpositions
+ {\let\pospxy \setpospxy
+ \let\pospxywhd \setpospxywhd
+ \let\pospxyplus\setpospxyplus}
+
+%D We need to initialize.
+
+\resetpositions
+
+\addutilityreset{positions}
+
%D Sometimes we want to trick the position handler a bit:
\def\replacepospxywhd#1#2#3#4#5#6#7%
@@ -77,7 +157,55 @@
\the\dimexpr#6\relax,%
\the\dimexpr#7\relax}}
-%D Writing to the utility file.
+%D For postprocessing purposes, we save the number of
+%D positions.
+
+\newcount\currentpositions % current number of positions
+\newcounter\totalnofpositions % total from previous run
+
+\appendtoks
+ \expanded{\savecurrentvalue\noexpand\totalnofpositions{\the\currentpositions}}%
+\to \everybye
+
+%D The next switch can be used to communicate a special
+%D situation. Positioning and associated actions can be
+%D executed any time. However, in for instance backgrounds
+%D they can be collected in a layer, for instance the text
+%D layer (especially the hidden text layer). In the case of
+%D floats, we run into problems, since the page information is
+%D not applicable when the content floats indeed. In such
+%D situations one can treat positions and graphics local.
+
+\newif\iflocalpositioning
+
+%D Watch out: sometimes a pagebreak occurs inside a float
+%D placement, so there we need to disable local mode.
+
+\appendtoks
+ \localpositioningtrue
+\to \everyinsidefloat
+
+\appendtoks
+ \localpositioningfalse
+\to \everypagebody
+
+\def\checkpositions
+ {\startnointerference
+ \protectlabels
+ \doutilities{positions}\jobname\empty\relax\relax
+ \global\let\checkpositions\relax
+ \stopnointerference}
+
+%D Since the positional values are to be fully expandable, we
+%D need to preload them as soon as possible, which is why we
+%D load the data when we start a text.
+
+\appendtoks \checkpositions \to \everystarttext
+
+%D Positions are either generated at a delayed write time
+%D (in \PDFTEX), or derived from the dvi file. The actual
+%D method is implemented in a special driver. If needed, the
+%D driver can fall back on the following macros.
\def\dolazysaveposition#1#2#3#4% tag page x y
{\expanded{\writeutilitycommand{\noexpand\pospxy
@@ -103,6 +231,13 @@
{\expanded{\immediatewriteutilitycommand{\noexpand\pospxyplus
{#1}{#2}{#3}{#4}{#5}{#6}{#7}{#8}}}}
+%D \macros
+%D {MPp, MPx, MPy, MPw, MPh, MPd,
+%D MPxy, MPll, MPlr, MPur, MPul, MPpos}
+%D
+%D Access to the positional information is provided by macros
+%D with short names that are clearly meant for \METAPOST.
+
\def\MPp {\doMPxyhdwlr\doMPp }
\def\MPx {\doMPxyhdwlr\doMPx }
\def\MPy {\doMPxyhdwlr\doMPy }
@@ -136,12 +271,25 @@
#10,0pt,0pt,0pt,0pt,0pt,0pt\relax
\fi}
-% \def\doMPxyhdwlr#1#2% evt kan \s!unknown leeg zijn
-% {\@EA\@EA\@EA#1\csname\POSprefix
-% \ifcsname\POSprefix#2\endcsname#2\else\s!unknown\fi\endcsname
-% ,0pt,0pt,0pt,0pt\relax}
-%
-% \setvalue{\POSprefix\s!unknown}{0,0pt,0pt}
+%D \macros
+%D {MPplus, MPrest, MPv, MPvv}
+%D
+%D Since we will probably keep on extending, we provide a
+%D general extension macro. The plus alternative takes an
+%D extra argument, denoting what additional parameter to pick
+%D up. So, the third extra is fetched with,
+%D
+%D \starttyping
+%D \MPplus{identifier}{3}{default}
+%D \stoptyping
+%D
+%D All extras (comma separated) are fetched with:
+%D
+%D \starttyping
+%D \MPrest{identifier}
+%D \stoptyping
+%D
+%D The extra parameters are not treated.
\def\MPplus {\MPdoplus\doMPplus}
\def\MPrest#1{\MPdoplus\doMPrest{#1}{}}
@@ -165,7 +313,177 @@
\def\doMPrest#1,#2,#3,#4,#5,#6,#7,,#8\relax#9%
{#7}
-%D Testing:
+%D \macros
+%D {MPanchor}
+%D
+%D For readability we define a few synonyms:
+
+\def\MPanchor{\MPpos}
+
+%D \macros
+%D {POSp, POSx, POSy, POSh, POSd, POSw}
+%D
+%D and:
+
+\def\POSp{\MPp} \def\POSx{\MPx} \def\POSy{\MPy}
+\def\POSh{\MPh} \def\POSd{\MPd} \def\POSw{\MPw}
+
+%D There are two low level positioning macros. Both store the
+%D position as well as execute an action associated with that
+%D position.
+
+\def\initializenextposition
+ {\ifpositioning \else
+ \global\positioningtrue
+ \dosetpositionpapersize
+ {\printpaperwidth }%
+ {\printpaperheight}%
+ \fi
+ \global\advance\currentpositions\plusone}
+
+\def\setpositiononly#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \fi}
+
+\def\setposition#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \fi}
+
+\def\setpositiondata#1#2#3#4%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox
+ {\def\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionbox#1%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ \traceposstring\llap\green{\currentposition>}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\def\setpositiondataplus#1#2#3#4#5%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox % bug: to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ {#5}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionplus#1#2%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ {#2}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\let\currentposition\s!unknown
+
+%D A few more low level macros take care of defining and
+%D recalling actions. We could save this information in the
+%D position containers themselves, this would save hash
+%D entries, but at the cost of much more time consuming
+%D expansion. Actions are saved globally!
+
+\newtoks\everypositionaction
+
+\let\POSactionprefix\POSprefix
+
+\def\dosetpositionaction#1%
+ {\setgvalue{\POSactionprefix#1::}}
+
+%D The lists can become quite long (also because there can
+%D be lots of parameters passed on) so we provide a hook
+%D to clean up the list afterwards.
+
+\let\cleanuppositionaction\gobbleoneargument
+
+\def\doifpositionaction#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\def\doifpositionactionelse#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+%D We can copy a position with:
+%D
+%D \starttyping
+%D \copyposition {to} {from}
+%D \stoptyping
+%D
+%D Again, this is a global action.
+
+\def\copyposition#1#2%
+ {\ifcsname\POSprefix#2\endcsname
+ \global\@EA\let\csname\POSprefix#1\@EA\endcsname\csname\POSprefix#2\endcsname
+ \fi}
+
+%D The fact that handling positions is a two pass operation, is
+%D one of the reasons why we need to be able to test for
+%D existence, using:
+%D
+%D \starttyping
+%D \doifpositionelse {identifier} {found action} {not found action}
+%D \stoptyping
\def\doifpositionelse#1%
{\ifcsname\POSprefix#1\endcsname
@@ -174,11 +492,382 @@
\expandafter\secondoftwoarguments
\fi}
-%D Copying:
+%D We have now arrived at a few macros that would make sense as
+%D support macros, but ended up in the core.
+
+%D \macros
+%D {xypos}
+%D
+%D We have several macros available to save positions. Later
+%D we will see applications.
+%D
+%D \starttabulate[|l|l||]
+%D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR
+%D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR
+%D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR
+%D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR
+%D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR
+%D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR
+%D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR
+%D \stoptabulate
+%D
+%D Each macro takes an identifier as argument, and the \type
+%D {\hpos} and \type {\vpos} also expect box content.
+
+% \def\xypos{\initializenextposition\dosetposition}
+
+\let\xypos\setpositiononly
+
+\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox}
+\def\vpos#1{\setpositionbox{#1}\vbox}
+
+\def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces}
+\def\epos#1{\removelastspace\hpos{e:#1}{\strut}}
+
+\def\fpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut
+ \ignorespaces}
+
+\def\tpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\ffpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut\wpos{#1}%
+ \ignorespaces}
+
+\def\ttpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\wpos#1%
+ {\dontleavehmode\vadjust % may disappear if buried
+ {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}%
+ \rlap{\smashedbox0}}}
+
+\def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}}
+ {\rlap
+ {\setbox0\hbox{\rawwpos{#1}}%
+ \smashedbox0}}
+
+\def\rawwpos#1%
+ {\hpos{w:#1}
+ {\strut
+ \hskip-\leftskip
+ \hskip\hsize
+ \hskip-\rightskip}}
+
+% the next macro disables par positions (in inner boxes) and
+% only registers the width
+
+\def\setinnerparpositions
+ {\let\fpos\ffpos
+ \let\tpos\ttpos
+ \let\wpos\wwpos}
+
+% example of usage: (see for application "techniek")
+%
+% \appendtoks
+% \setinnerparpositions
+% \to \everytabulate
+
+%D When we want to calculate more complex backgrounds, we
+%D need to know what the current indentation scheme is. At
+%D the cost of many positions and memory, we can keep track
+%D of them. This mechanism is activated automatically
+%D based on information collected in the previous pass.
+
+\newcount\parposcounter
+
+\newif\ifpositioningpar
+
+% we can check for used entries, and if not, then not add one
+
+\def\registerparoptions
+ {\ifpositioningpar \ifpositioning \iftrialtypesetting \else
+ \ifinpagebody \else \ifmmode \else \ifinformula \else
+ \ifprocessingverbatim
+ \iflinepar \doregisterparoptions \fi
+ \else
+ \doregisterparoptions
+ \fi
+ \fi \fi \fi
+ \fi \fi \fi}
+
+\chardef\parposstrut=1 % 0 => no strut data, so fall backs used
+
+\newif\iftracepositions
+
+% \def\doregisterparoptions
+% {\global\advance\parposcounter\plusone
+% \begingroup
+% \leftskip 1\leftskip
+% \rightskip1\rightskip
+% \setpositiondataplus
+% {p:\number\parposcounter}% identifier
+% {\the\zeropoint}%
+% {\the\strutht}%
+% {\the\strutdp}%
+% {\the\hsize ,% 1
+% \the\leftskip ,% 2
+% \the\rightskip ,% 3
+% \the\hangindent,% 4
+% \the\hangafter ,% 5 (num)
+% \the\parindent }% 6
+% %\normalhbox{\registerparsymbol}%
+% \registerparsymbol
+% \endgroup}
+
+\def\doregisterparoptions
+ {\global\advance\parposcounter\plusone
+ \setpositiondataplus
+ {p:\number\parposcounter}% identifier
+ {\the\zeropoint}%
+ {\the\strutht}%
+ {\the\strutdp}%
+ {\the\hsize,\the\dimexpr\leftskip\relax,\the\dimexpr\rightskip\relax,\the\hangindent,\the\hangafter,\the\parindent}%
+ %\normalhbox{\registerparsymbol}%
+ \iftracepositions\registerparsymbol\fi}
+
+\def\traceposstring#1#2#3%
+ {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi}
+
+\def\registerparsymbol
+ {\iftracepositions
+ \smashedhbox to \zeropoint
+ {\hss
+ \startcolor[blue]%
+ \llap{\infofont\number\parposcounter}%
+ \scratchdimen\onepoint
+ \vrule
+ \!!width 4\scratchdimen
+ \!!height2\scratchdimen
+ \!!depth 2\scratchdimen
+ \stopcolor
+ \hss}%
+ \fi}
+
+% \appendtoks \registerparoptions \to \everypar
+
+%D Eperimental code, don't use this yet: (must be sped up anyway)
+
+\def\@@noden{node:n:}
+\def\@@nodeo{node:o:}
+\def\@@nodep{node:p:}
+
+\def\doifelsenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\nextnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\pluscounter{\@@noden#1}\fi}
-\def\copyposition#1#2%
- {\ifcsname\POSprefix#2\endcsname
- \global\@EA\let\csname\POSprefix#1\@EA\endcsname\csname\POSprefix#2\endcsname
+\def\newnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \setcounter{\@@noden#1}\zerocount
+ \letgvalue {\@@nodeo#1}\!!zerocount
\fi}
+\def\tagnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\xypos{\@@nodep#1:\countervalue{\@@noden#1}}\fi}
+
+\def\getnodelocationp#1{\MPp{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationx#1{\MPx{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationy#1{\MPy{\@@nodep#1:\countervalue{\@@noden#1}}}
+
+\def\numnodelocationp#1#2{\MPp{\@@nodep#1:\number#2}}
+\def\numnodelocationx#1#2{\MPx{\@@nodep#1:\number#2}}
+\def\numnodelocationy#1#2{\MPy{\@@nodep#1:\number#2}}
+
+\def\getnodelocationn#1{\countervalue{\@@noden#1}}
+\def\getnodelocationo#1{\getvalue {\@@nodeo#1}}
+
+\chardef\nodelocationmode\plusone
+
+\def\analyzenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \doanalyzenodelocation{#1}{\getnodelocationn{#1}}\zerocount
+ \fi}
+
+\def\doanalyzenodelocation#1#2#3% class n default
+ {\begingroup
+ \donefalse
+ \ifcase\nodelocationmode
+ % do nothing
+ \else
+ \edef\nodelocationselfn{#2}%
+ \edef\nodelocationselfp{\numnodelocationp{#1}\nodelocationselfn}%
+ \edef\nodelocationselfx{\numnodelocationx{#1}\nodelocationselfn}%
+ \edef\nodelocationselfy{\numnodelocationy{#1}\nodelocationselfn}%
+ \scratchcounter\plusone
+ \doloop
+ {\ifnum\recurselevel=\nodelocationselfn\relax
+ \donetrue
+ \else
+ \edef\nodelocationotherp{\numnodelocationp{#1}\recurselevel}%
+ \edef\nodelocationotherx{\numnodelocationx{#1}\recurselevel}%
+ \edef\nodelocationothery{\numnodelocationy{#1}\recurselevel}%
+ \ifcase\nodelocationmode
+ \or
+ % ok for single column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifdim\nodelocationothery>\nodelocationselfy\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifdim\nodelocationothery<\nodelocationselfy\relax
+ % skip
+ \else\ifdim\nodelocationotherx<\nodelocationselfx\relax
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi\fi\fi
+ \or
+ % acceptable for double column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifnum\recurselevel>\nodelocationselfn\relax
+ \donetrue \exitloop
+ \else
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi
+ \else
+ \exitloop
+ \fi
+ \fi}%
+ \fi
+ \ifdone \else
+ \scratchcounter#3\relax
+ \fi
+ \setxvalue{\@@nodeo#1}{\the\scratchcounter}%
+ \endgroup}
+
+\unexpanded\def\shownodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \analyzenodelocation{#1}%
+ (#1,%
+ n:\getnodelocationn{#1},%
+ p:\getnodelocationp{#1},%
+ x:\getnodelocationx{#1},%
+ y:\getnodelocationy{#1},%
+ o:\getnodelocationo{#1})%
+ \fi}
+
+%D \macros
+%D {doifoverlappingelse}
+%D
+%D A first application of positional information, is to
+%D determine if two boxes do overlap:
+%D
+%D \starttyping
+%D \doifoverlappingelse{point a}{point b}
+%D {action when overlapping}
+%D {action when not overlapping}
+%D \stoptyping
+
+\def\overlappingmargin{-2\scaledpoint}
+
+\def\doifoverlappingelse#1#2%
+ {\begingroup
+ \donefalse
+ \edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifnum\MPp\!!stringa=\MPp\!!stringb\relax
+ \!!dimena\MPx\!!stringa
+ \!!dimenb\dimexpr\MPx\!!stringa+\MPw\!!stringa\relax
+ \!!dimenc\dimexpr\MPy\!!stringa-\MPd\!!stringa\relax
+ \!!dimend\dimexpr\MPy\!!stringa+\MPh\!!stringa\relax
+ \!!dimene\MPx\!!stringb
+ \!!dimenf\dimexpr\MPx\!!stringb+\MPw\!!stringb\relax
+ \!!dimeng\dimexpr\MPy\!!stringb-\MPd\!!stringb\relax
+ \!!dimenh\dimexpr\MPy\!!stringb+\MPh\!!stringb\relax
+ \ifdim\overlappingmargin=\zeropoint\else
+ \advance\!!dimena-\overlappingmargin
+ \advance\!!dimenb+\overlappingmargin
+ \advance\!!dimenc-\overlappingmargin
+ \advance\!!dimend+\overlappingmargin
+ \advance\!!dimene-\overlappingmargin
+ \advance\!!dimenf+\overlappingmargin
+ \advance\!!dimeng-\overlappingmargin
+ \advance\!!dimenh+\overlappingmargin
+ \fi
+ % more often eh fb eg fg
+ \def\checkone##1##2%
+ {\ifdim##1<\!!dimena \else \ifdim##1>\!!dimenb \else
+ \ifdim##2<\!!dimenc \else \ifdim##2>\!!dimend \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \def\checktwo##1##2%
+ {\ifdim##1<\!!dimene \else \ifdim##1>\!!dimenf \else
+ \ifdim##2<\!!dimeng \else \ifdim##2>\!!dimenh \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \checkone\!!dimene\!!dimeng \ifdone \else
+ \checkone\!!dimene\!!dimenh \ifdone \else
+ \checkone\!!dimenf\!!dimeng \ifdone \else
+ \checkone\!!dimenf\!!dimenh \ifdone \else
+ \checktwo\!!dimena\!!dimenc \ifdone \else
+ \checktwo\!!dimena\!!dimend \ifdone \else
+ \checktwo\!!dimenb\!!dimene \ifdone \else
+ \checktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi
+ \fi
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifpositionsonsamepageelse,
+%D doifpositionsonthispageelse}
+%D
+%D Instead of letting the user handle fuzzy expansion, we
+%D provide a simple test on positione being on the same page.
+%D
+%D \starttyping
+%D \doifpositionsonsamepageelse{point a}{point b}
+%D {action when on same page}
+%D {action when not on same page}
+%D \doifpositionsonthispageelse{point a}{point b}
+%D {action when on this page}
+%D {action when not on this page}
+%D \stoptyping
+
+\def\dodoifpositionsonsamepageelse#1#2#3#4%
+ {\bgroup
+ \scratchcounter#1\donefalse
+ \def\docommand##1%
+ {\ifcase\scratchcounter
+ \scratchcounter\MPp{##1}\donetrue
+ \else
+ \ifnum\scratchcounter=\MPp{##1}\relax\else\donefalse\fi
+ \fi}%
+ \rawprocesscommalist[#2]\docommand
+ \ifdone\egroup#3\else\egroup#4\fi}
+
+\def\doifpositionsonsamepageelse
+ {\dodoifpositionsonsamepageelse{0}}
+
+\def\doifpositionsonthispageelse#1#2#3%
+ {\dodoifpositionsonsamepageelse\realfolio}
+
+%D Plugins:
+
+\let\MPv \MPplus
+\let\MPvv\MPrest
+
+\let\MPanchor\MPpos
+
+\let\POSp\MPp \let\POSx\MPx \let\POSy\MPy
+\let\POSh\MPh \let\POSd\MPd \let\POSw\MPw
+
\protect \endinput
diff --git a/tex/context/base/core-pos.mkiv b/tex/context/base/core-pos.mkiv
index 860a7a967..16d5b229f 100644
--- a/tex/context/base/core-pos.mkiv
+++ b/tex/context/base/core-pos.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-pos,
-%D version=2006.09.18,
+%D version=1999.08.01,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Positioning Support,
%D author=Hans Hagen,
@@ -11,7 +11,22 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+% needs a cleanup, things may change; we also need to move the mp
+% related code to meta-pos
+
+% shorter tags, ..:achtergrond:.. etc in pos actions
+
+% dubbele text- * pos's eruit
+
+% class pos -> als gelijk aan vorige, dan niet niet definieren
+% en erven, maw:
+%
+% 1 -> opslaan
+% 2 -> undef, dus == prev
+% 3 -> undef, dus == prev
+% 4 -> opslaan
+
+\writestatus{loading}{ConTeXt Core Macros / Positioning Support}
% saveposition : tag page x y
% savepositionwhd : tag page x y w h d
@@ -27,12 +42,71 @@
\registerctxluafile{core-pos}{1.001}
-% \def\dolazysaveposition #1#2#3#4{\expanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4"}}}}
-% \def\dolazysavepositionwhd #1#2#3#4#5#6#7{\expanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
-% \def\dolazysavepositionplus#1#2#3#4#5#6#7#8{\expanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4","#5","#6","#7","#8"}}}}
-% \def\dosaveposition #1#2#3#4{\expanded{\ctxlua {ptbs['#1']={#2,"#3","#4"}}}}
-% \def\dosavepositionwhd #1#2#3#4#5#6#7{\expanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
-% \def\dosavepositionplus #1#2#3#4#5#6#7#8{\expanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7","#8"}}}}
+% todo: topskip als optie voor eerste regel achtergrond
+% todo: build pos layers on top of layers
+% todo: positionlayer pos van text-1 etc delen
+
+%D Although \TEX\ has a rather powerful channel to the outside
+%D world, called \type {\special}, real communication with
+%D other programs is complicated by the fact that no positional
+%D information is available. Mid 1999, I discussed this with
+%D \THANH, the author of \PDFTEX, and after some experiments,
+%D \PDFTEX\ was extended with a simple but effective mechanism,
+%D that provided positional information. The interesting
+%D thought is that, although \TEX\ is frozen, similar
+%D functionality could have been achieved with \type
+%D {\specials} and an additional \DVI\ postprocessor.
+%D
+%D Since we want to be as compatible as can be, \CONTEXT\ will
+%D support both methods, although the development is primarily
+%D driven by the \PDFTEX\ way of doing things. Since the
+%D mechanism is basically not limited to one application, for
+%D the moment we stick to building the functionality around one
+%D \CONTEXT\ special command, but at the same time we keep our
+%D eyes open for extensions in other directions.
+%D
+%D A question that may arise when one reads this module, is to
+%D what extend these macros are generic, in the sense that they
+%D could be collected in a support module instead of a core
+%D module. Since the mechanism described here will closely
+%D cooperate with the \METAPOST\ support built in \CONTEXT,
+%D which in turn will be tightly integrated with the \CONTEXT\
+%D overlay mechanisms, I decided to write a core module instead
+%D of a support one. This makes even more sense, when one takes
+%D into account that this kind of support depends on special
+%D drivers.
+
+\unprotect
+
+%D The first application of positional information was embedded
+%D graphics. Since we are interacting with text, it made sense
+%D to take the current line height and depth into account too.
+%D This is why we have two basic position macros: one for
+%D simple positions, and one for boxes.
+%D
+%D We could have sticked to one special, and actually did so in
+%D earlier experiments, but for convenience, as well for
+%D clearness, we now have two alternatives. This approach will
+%D save us quite some bytes when storing large quantities of
+%D positional information. We save as less information as
+%D needed, that is, we save no dimensions, in a \METAPOST\
+%D friendly way.
+%D
+%D The three specials involved are:
+%D
+%D \starttyping
+%D \dosetposition {identifier}
+%D \dosetpositionwhd {identifier} {width} {height} {depth}
+%D \dosetpositionplus {identifier} {width} {height} {depth} {list}
+%D \dosetpositionpapersize {width} {height}
+%D \stoptyping
+%D
+%D Positions are either generated at a delayed write time
+%D (in \PDFTEX), or derived from the dvi file. The actual
+%D method is implemented in a special driver. If needed, the
+%D driver can fall back on the following macros.
+
+% TO BE MERGED
\def\dolazysaveposition #1#2#3#4{\normalexpanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4"}}}}
\def\dolazysavepositionwhd #1#2#3#4#5#6#7{\normalexpanded{\ctxlatelua{ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
@@ -41,10 +115,131 @@
\def\dosavepositionwhd #1#2#3#4#5#6#7{\normalexpanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7"}}}}
\def\dosavepositionplus #1#2#3#4#5#6#7#8{\normalexpanded{\ctxlua {ptbs['#1']={#2,"#3","#4","#5","#6","#7","#8"}}}}
-\def\doifpositionelse #1{\ctxlua{jobpositions.doifelse('#1')}}
-\def\copyposition #1#2{\ctxlua{jobpositions.copy('#1','#2')}}
+% \def\dosetposition#1%
+% {\pdfsavepos
+% \dolazysaveposition
+% {#1}%
+% {\noexpand\realfolio}%
+% {\noexpand\the\dimexpr\pdflastxpos\scaledpoint\relax}%
+% {\noexpand\the\dimexpr\pdflastypos\scaledpoint\relax}}%
+%
+% \def\dosetpositionwhd#1#2#3#4%
+% {\pdfsavepos
+% \dolazysavepositionwhd
+% {#1}%
+% {\noexpand\realfolio}%
+% {\noexpand\the\dimexpr\pdflastxpos\scaledpoint\relax}%
+% {\noexpand\the\dimexpr\pdflastypos\scaledpoint\relax}%
+% {#2}{#3}{#4}}
+%
+% \def\dosetpositionplus#1#2#3#4#5%
+% {\pdfsavepos
+% \dolazysavepositionplus
+% {#1}%
+% {\noexpand\realfolio}%
+% {\noexpand\the\dimexpr\pdflastxpos\scaledpoint\relax}%
+% {\noexpand\the\dimexpr\pdflastypos\scaledpoint\relax}%
+% {#2}{#3}{#4}{#5}}
+
+\def\lastsavedpositionx {\the\dimexpr\pdflastxpos\scaledpoint\relax}
+\def\lastsavedpositiony {\the\dimexpr\pdflastypos\scaledpoint\relax}
+\let\savecurrentposition\pdfsavepos
+
+\def\dosetposition#1%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony"}}}}
+
+\def\dosetpositionwhd#1#2#3#4%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony","#2","#3","#4"}}}}
+
+\def\dosetpositionplus#1#2#3#4#5%
+ {\savecurrentposition
+ \normalexpanded{\ctxlatelua{ptbs['#1']={%
+ \noexpand\realfolio,"\noexpand\lastsavedpositionx","\noexpand\lastsavedpositiony","#2","#3","#4","#5"}}}}
+
+\let\dosetpositionpapersize\gobbletwoarguments
+
+\newbox\positionbox
+\newif \ifpositioning
+
+\def\POSprefix{POS::}
+
+\let\setpospx \gobblefourarguments % suppress errors with mkii tuo file
+\let\setpospxywhd \gobblesevenarguments % suppress errors with mkii tuo file
+\let\setpospxyplus\gobbleeightarguments % suppress errors with mkii tuo file
+
+%D This is real tricky! The page anchor is applied to the
+%D page box and therefore flushed first. So, when present, it
+%D is applied to all positions except itself.
+
+\chardef\positionanchormode=0 % don't relocate page origin
+\chardef\positionanchormode=1 % relocate page origin once
+
+%D The core set macros.
+
+\let\pospxy \gobblefourarguments
+\let\pospxywhd \gobblesevenarguments
+\let\pospxyplus\gobbleeightarguments
+
+%D Sometimes we want to trick the position handler a bit:
+
\def\replacepospxywhd#1#2#3#4#5#6#7{\ctxlua{jobpositions.replace('#1',\number#2,"\the\dimexpr#3\relax","\the\dimexpr#4\relax","\the\dimexpr#5\relax","\the\dimexpr#6\relax","\the\dimexpr#7\relax")}}
+%D For postprocessing purposes, we save the number of
+%D positions.
+
+\newcount\currentpositions % current number of positions
+\newcounter\totalnofpositions % total from previous run
+
+\appendtoks
+ \expanded{\savecurrentvalue\noexpand\totalnofpositions{\the\currentpositions}}%
+\to \everybye
+
+%D The next switch can be used to communicate a special
+%D situation. Positioning and associated actions can be
+%D executed any time. However, in for instance backgrounds
+%D they can be collected in a layer, for instance the text
+%D layer (especially the hidden text layer). In the case of
+%D floats, we run into problems, since the page information is
+%D not applicable when the content floats indeed. In such
+%D situations one can treat positions and graphics local.
+
+\newif\iflocalpositioning
+
+%D Watch out: sometimes a pagebreak occurs inside a float
+%D placement, so there we need to disable local mode.
+
+\appendtoks
+ \localpositioningtrue
+\to \everyinsidefloat
+
+\appendtoks
+ \localpositioningfalse
+\to \everypagebody
+
+\def\checkpositions
+ {\startnointerference
+ \protectlabels
+ \doutilities{positions}\jobname\empty\relax\relax
+ \global\let\checkpositions\relax
+ \stopnointerference}
+
+%D Since the positional values are to be fully expandable, we
+%D need to preload them as soon as possible, which is why we
+%D load the data when we start a text.
+
+\appendtoks \checkpositions \to \everystarttext
+
+%D \macros
+%D {MPp, MPx, MPy, MPw, MPh, MPd,
+%D MPxy, MPll, MPlr, MPur, MPul, MPpos}
+%D
+%D Access to the positional information is provided by macros
+%D with short names that are clearly meant for \METAPOST.
+
\def\MPp #1{\ctxlua{jobpositions.MPp("#1")}}
\def\MPx #1{\ctxlua{jobpositions.MPx("#1")}}
\def\MPy #1{\ctxlua{jobpositions.MPy("#1")}}
@@ -57,7 +252,577 @@
\def\MPur #1{\ctxlua{jobpositions.MPur("#1")}}
\def\MPul #1{\ctxlua{jobpositions.MPul("#1")}}
\def\MPpos #1{\ctxlua{jobpositions.MPpos("#1")}}
-\def\MPplus#1#2#3{\ctxlua{jobpositions.MPplus("#1",#2,"#3")}}
-\def\MPrest #1#2{\ctxlua{jobpositions.MPrest("#1","#2")}}
+
+%D \macros
+%D {MPplus, MPrest, MPv, MPvv}
+%D
+%D Since we will probably keep on extending, we provide a
+%D general extension macro. The plus alternative takes an
+%D extra argument, denoting what additional parameter to pick
+%D up. So, the third extra is fetched with,
+%D
+%D \starttyping
+%D \MPplus{identifier}{3}{default}
+%D \stoptyping
+%D
+%D All extras (comma separated) are fetched with:
+%D
+%D \starttyping
+%D \MPrest{identifier}
+%D \stoptyping
+%D
+%D The extra parameters are not treated.
+
+\def\MPplus#1#2#3{\ctxlua{jobpositions.MPplus("#1",#2,"#3")}} \let\MPv \MPplus
+\def\MPrest #1#2{\ctxlua{jobpositions.MPrest("#1","#2")}} \let\MPvv\MPrest
+
+%D \macros
+%D {MPanchor}
+%D
+%D For readability we define a few synonyms:
+
+\def\MPanchor{\MPpos}
+
+%D \macros
+%D {POSp, POSx, POSy, POSh, POSd, POSw}
+%D
+%D and:
+
+\def\POSp{\MPp} \def\POSx{\MPx} \def\POSy{\MPy}
+\def\POSh{\MPh} \def\POSd{\MPd} \def\POSw{\MPw}
+
+%D There are two low level positioning macros. Both store the
+%D position as well as execute an action associated with that
+%D position.
+
+\def\initializenextposition
+ {\ifpositioning \else
+ \global\positioningtrue
+ \dosetpositionpapersize
+ {\printpaperwidth }%
+ {\printpaperheight}%
+ \fi
+ \global\advance\currentpositions\plusone}
+
+\def\setpositiononly#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \fi}
+
+\def\setposition#1%
+ {\iftrialtypesetting
+ % nothing
+ \else
+ \initializenextposition
+ \def\currentposition{#1}%
+ \dosetposition\currentposition
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \fi}
+
+\def\setpositiondata#1#2#3#4%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox
+ {\def\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ \traceposstring\llap\green{\currentposition>}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionbox#1%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionwhd\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ \traceposstring\llap\green{\currentposition>}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\def\setpositiondataplus#1#2#3#4#5%
+ {\iftrialtypesetting \else
+ \initializenextposition
+ \hbox % bug: to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\dimexpr#2\relax}%
+ {\the\dimexpr#3\relax}%
+ {\the\dimexpr#4\relax}%
+ {#5}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \dopositionaction\currentposition
+ \hss}%
+ \fi}
+
+\def\setpositionplus#1#2%
+ {\dowithnextbox
+ {\iftrialtypesetting
+ \flushnextbox
+ \else
+ \initializenextposition
+ \hbox to \nextboxwd
+ {\edef\currentposition{#1}%
+ \dosetpositionplus\currentposition
+ {\the\nextboxwd}%
+ {\the\nextboxht}%
+ {\the\nextboxdp}%
+ {#2}%
+ \traceposstring\rlap\magenta{<\currentposition}%
+ \setbox\positionbox\flushnextbox
+ \dopositionaction\currentposition
+ \box\positionbox
+ \hss}%
+ \fi}}
+
+\let\currentposition\s!unknown
+
+%D A few more low level macros take care of defining and
+%D recalling actions. We could save this information in the
+%D position containers themselves, this would save hash
+%D entries, but at the cost of much more time consuming
+%D expansion. Actions are saved globally!
+
+\newtoks\everypositionaction
+
+\let\POSactionprefix\POSprefix
+
+\def\dosetpositionaction#1%
+ {\setgvalue{\POSactionprefix#1::}}
+
+%D The lists can become quite long (also because there can
+%D be lots of parameters passed on) so we provide a hook
+%D to clean up the list afterwards.
+
+\let\cleanuppositionaction\gobbleoneargument
+
+\def\doifpositionaction#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\def\doifpositionactionelse#1%
+ {\ifcsname\POSactionprefix#1::\endcsname
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+%D We can copy a position with:
+%D
+%D \starttyping
+%D \copyposition {to} {from}
+%D \stoptyping
+%D
+%D Again, this is a global action.
+
+\def\copyposition#1#2{\ctxlua{jobpositions.copy('#1','#2')}}
+
+%D The fact that handling positions is a two pass operation, is
+%D one of the reasons why we need to be able to test for
+%D existence, using:
+%D
+%D \starttyping
+%D \doifpositionelse {identifier} {found action} {not found action}
+%D \stoptyping
+
+\def\doifpositionelse#1{\ctxlua{jobpositions.doifelse('#1')}}
+
+%D We have now arrived at a few macros that would make sense as
+%D support macros, but ended up in the core.
+
+%D \macros
+%D {xypos}
+%D
+%D We have several macros available to save positions. Later
+%D we will see applications.
+%D
+%D \starttabulate[|l|l||]
+%D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR
+%D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR
+%D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR
+%D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR
+%D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR
+%D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR
+%D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR
+%D \stoptabulate
+%D
+%D Each macro takes an identifier as argument, and the \type
+%D {\hpos} and \type {\vpos} also expect box content.
+
+% \def\xypos{\initializenextposition\dosetposition}
+
+\let\xypos\setpositiononly
+
+\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox}
+\def\vpos#1{\setpositionbox{#1}\vbox}
+
+\def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces}
+\def\epos#1{\removelastspace\hpos{e:#1}{\strut}}
+
+\def\fpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut
+ \ignorespaces}
+
+\def\tpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\ffpos#1%
+ {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut\wpos{#1}%
+ \ignorespaces}
+
+\def\ttpos#1%
+ {\removelastspace
+ \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
+
+\def\wpos#1%
+ {\dontleavehmode\vadjust % may disappear if buried
+ {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}%
+ \rlap{\smashedbox0}}}
+
+\def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}}
+ {\rlap
+ {\setbox0\hbox{\rawwpos{#1}}%
+ \smashedbox0}}
+
+\def\rawwpos#1%
+ {\hpos{w:#1}
+ {\strut
+ \hskip-\leftskip
+ \hskip\hsize
+ \hskip-\rightskip}}
+
+% the next macro disables par positions (in inner boxes) and
+% only registers the width
+
+\def\setinnerparpositions
+ {\let\fpos\ffpos
+ \let\tpos\ttpos
+ \let\wpos\wwpos}
+
+% example of usage: (see for application "techniek")
+%
+% \appendtoks
+% \setinnerparpositions
+% \to \everytabulate
+
+%D When we want to calculate more complex backgrounds, we
+%D need to know what the current indentation scheme is. At
+%D the cost of many positions and memory, we can keep track
+%D of them. This mechanism is activated automatically
+%D based on information collected in the previous pass.
+
+\newcount\parposcounter
+
+\newif\ifpositioningpar
+
+% we can check for used entries, and if not, then not add one
+
+\def\registerparoptions
+ {\ifpositioningpar \ifpositioning \iftrialtypesetting \else
+ \ifinpagebody \else \ifmmode \else \ifinformula \else
+ \ifprocessingverbatim
+ \iflinepar \doregisterparoptions \fi
+ \else
+ \doregisterparoptions
+ \fi
+ \fi \fi \fi
+ \fi \fi \fi}
+
+\chardef\parposstrut=1 % 0 => no strut data, so fall backs used
+
+\newif\iftracepositions
+
+% \def\doregisterparoptions
+% {\global\advance\parposcounter\plusone
+% \begingroup
+% \leftskip 1\leftskip
+% \rightskip1\rightskip
+% \setpositiondataplus
+% {p:\number\parposcounter}% identifier
+% {\the\zeropoint}%
+% {\the\strutht}%
+% {\the\strutdp}%
+% {\the\hsize ,% 1
+% \the\leftskip ,% 2
+% \the\rightskip ,% 3
+% \the\hangindent,% 4
+% \the\hangafter ,% 5 (num)
+% \the\parindent }% 6
+% %\normalhbox{\registerparsymbol}%
+% \registerparsymbol
+% \endgroup}
+
+\def\doregisterparoptions
+ {\global\advance\parposcounter\plusone
+ \setpositiondataplus
+ {p:\number\parposcounter}% identifier
+ {\the\zeropoint}%
+ {\the\strutht}%
+ {\the\strutdp}%
+ {\the\hsize,\the\dimexpr\leftskip\relax,\the\dimexpr\rightskip\relax,\the\hangindent,\the\hangafter,\the\parindent}%
+ %\normalhbox{\registerparsymbol}%
+ \iftracepositions\registerparsymbol\fi}
+
+\def\traceposstring#1#2#3%
+ {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi}
+
+\def\registerparsymbol
+ {\iftracepositions
+ \smashedhbox to \zeropoint
+ {\hss
+ \startcolor[blue]%
+ \llap{\infofont\number\parposcounter}%
+ \scratchdimen\onepoint
+ \vrule
+ \!!width 4\scratchdimen
+ \!!height2\scratchdimen
+ \!!depth 2\scratchdimen
+ \stopcolor
+ \hss}%
+ \fi}
+
+% \appendtoks \registerparoptions \to \everypar
+
+%D Eperimental code, don't use this yet: (must be sped up anyway)
+
+\def\@@noden{node:n:}
+\def\@@nodeo{node:o:}
+\def\@@nodep{node:p:}
+
+\def\doifelsenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\nextnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\pluscounter{\@@noden#1}\fi}
+
+\def\newnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \setcounter{\@@noden#1}\zerocount
+ \letgvalue {\@@nodeo#1}\!!zerocount
+ \fi}
+
+\def\tagnodelocation#1%
+ {\ifcsname\@@noden#1\endcsname\xypos{\@@nodep#1:\countervalue{\@@noden#1}}\fi}
+
+\def\getnodelocationp#1{\MPp{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationx#1{\MPx{\@@nodep#1:\countervalue{\@@noden#1}}}
+\def\getnodelocationy#1{\MPy{\@@nodep#1:\countervalue{\@@noden#1}}}
+
+\def\numnodelocationp#1#2{\MPp{\@@nodep#1:\number#2}}
+\def\numnodelocationx#1#2{\MPx{\@@nodep#1:\number#2}}
+\def\numnodelocationy#1#2{\MPy{\@@nodep#1:\number#2}}
+
+\def\getnodelocationn#1{\countervalue{\@@noden#1}}
+\def\getnodelocationo#1{\getvalue {\@@nodeo#1}}
+
+\chardef\nodelocationmode\plusone
+
+\def\analyzenodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \doanalyzenodelocation{#1}{\getnodelocationn{#1}}\zerocount
+ \fi}
+
+\def\doanalyzenodelocation#1#2#3% class n default
+ {\begingroup
+ \donefalse
+ \ifcase\nodelocationmode
+ % do nothing
+ \else
+ \edef\nodelocationselfn{#2}%
+ \edef\nodelocationselfp{\numnodelocationp{#1}\nodelocationselfn}%
+ \edef\nodelocationselfx{\numnodelocationx{#1}\nodelocationselfn}%
+ \edef\nodelocationselfy{\numnodelocationy{#1}\nodelocationselfn}%
+ \scratchcounter\plusone
+ \doloop
+ {\ifnum\recurselevel=\nodelocationselfn\relax
+ \donetrue
+ \else
+ \edef\nodelocationotherp{\numnodelocationp{#1}\recurselevel}%
+ \edef\nodelocationotherx{\numnodelocationx{#1}\recurselevel}%
+ \edef\nodelocationothery{\numnodelocationy{#1}\recurselevel}%
+ \ifcase\nodelocationmode
+ \or
+ % ok for single column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifdim\nodelocationothery>\nodelocationselfy\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifdim\nodelocationothery<\nodelocationselfy\relax
+ % skip
+ \else\ifdim\nodelocationotherx<\nodelocationselfx\relax
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi\fi\fi
+ \or
+ % acceptable for double column
+ \ifcase\nodelocationotherp\relax
+ \exitloop
+ \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
+ \donetrue \advance\scratchcounter\plusone
+ \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
+ % skip
+ \else\ifnum\recurselevel>\nodelocationselfn\relax
+ \donetrue \exitloop
+ \else
+ \donetrue \advance\scratchcounter\plusone
+ \fi\fi\fi\fi
+ \else
+ \exitloop
+ \fi
+ \fi}%
+ \fi
+ \ifdone \else
+ \scratchcounter#3\relax
+ \fi
+ \setxvalue{\@@nodeo#1}{\the\scratchcounter}%
+ \endgroup}
+
+\unexpanded\def\shownodelocation#1%
+ {\ifcsname\@@noden#1\endcsname
+ \analyzenodelocation{#1}%
+ (#1,%
+ n:\getnodelocationn{#1},%
+ p:\getnodelocationp{#1},%
+ x:\getnodelocationx{#1},%
+ y:\getnodelocationy{#1},%
+ o:\getnodelocationo{#1})%
+ \fi}
+
+%D \macros
+%D {doifoverlappingelse}
+%D
+%D A first application of positional information, is to
+%D determine if two boxes do overlap:
+%D
+%D \starttyping
+%D \doifoverlappingelse{point a}{point b}
+%D {action when overlapping}
+%D {action when not overlapping}
+%D \stoptyping
+
+\def\overlappingmargin{-2\scaledpoint}
+
+\def\doifoverlappingelse#1#2%
+ {\begingroup
+ \donefalse
+ \edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifnum\MPp\!!stringa=\MPp\!!stringb\relax
+ \!!dimena\MPx\!!stringa
+ \!!dimenb\dimexpr\MPx\!!stringa+\MPw\!!stringa\relax
+ \!!dimenc\dimexpr\MPy\!!stringa-\MPd\!!stringa\relax
+ \!!dimend\dimexpr\MPy\!!stringa+\MPh\!!stringa\relax
+ \!!dimene\MPx\!!stringb
+ \!!dimenf\dimexpr\MPx\!!stringb+\MPw\!!stringb\relax
+ \!!dimeng\dimexpr\MPy\!!stringb-\MPd\!!stringb\relax
+ \!!dimenh\dimexpr\MPy\!!stringb+\MPh\!!stringb\relax
+ \ifdim\overlappingmargin=\zeropoint\else
+ \advance\!!dimena-\overlappingmargin
+ \advance\!!dimenb+\overlappingmargin
+ \advance\!!dimenc-\overlappingmargin
+ \advance\!!dimend+\overlappingmargin
+ \advance\!!dimene-\overlappingmargin
+ \advance\!!dimenf+\overlappingmargin
+ \advance\!!dimeng-\overlappingmargin
+ \advance\!!dimenh+\overlappingmargin
+ \fi
+ % more often eh fb eg fg
+ \def\checkone##1##2%
+ {\ifdim##1<\!!dimena \else \ifdim##1>\!!dimenb \else
+ \ifdim##2<\!!dimenc \else \ifdim##2>\!!dimend \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \def\checktwo##1##2%
+ {\ifdim##1<\!!dimene \else \ifdim##1>\!!dimenf \else
+ \ifdim##2<\!!dimeng \else \ifdim##2>\!!dimenh \else
+ \donetrue
+ \fi\fi
+ \fi\fi}%
+ \checkone\!!dimene\!!dimeng \ifdone \else
+ \checkone\!!dimene\!!dimenh \ifdone \else
+ \checkone\!!dimenf\!!dimeng \ifdone \else
+ \checkone\!!dimenf\!!dimenh \ifdone \else
+ \checktwo\!!dimena\!!dimenc \ifdone \else
+ \checktwo\!!dimena\!!dimend \ifdone \else
+ \checktwo\!!dimenb\!!dimene \ifdone \else
+ \checktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi
+ \fi
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifpositionsonsamepageelse,
+%D doifpositionsonthispageelse}
+%D
+%D Instead of letting the user handle fuzzy expansion, we
+%D provide a simple test on positione being on the same page.
+%D
+%D \starttyping
+%D \doifpositionsonsamepageelse{point a}{point b}
+%D {action when on same page}
+%D {action when not on same page}
+%D \doifpositionsonthispageelse{point a}{point b}
+%D {action when on this page}
+%D {action when not on this page}
+%D \stoptyping
+
+\def\dodoifpositionsonsamepageelse#1#2#3#4%
+ {\bgroup
+ \scratchcounter#1\donefalse
+ \def\docommand##1%
+ {\ifcase\scratchcounter
+ \scratchcounter\MPp{##1}\donetrue
+ \else
+ \ifnum\scratchcounter=\MPp{##1}\relax\else\donefalse\fi
+ \fi}%
+ \rawprocesscommalist[#2]\docommand
+ \ifdone\egroup#3\else\egroup#4\fi}
+
+\def\doifpositionsonsamepageelse
+ {\dodoifpositionsonsamepageelse{0}}
+
+\def\doifpositionsonthispageelse#1#2#3%
+ {\dodoifpositionsonsamepageelse\realfolio}
+
+%D Plugins:
+
+\let\MPv \MPplus
+\let\MPvv\MPrest
+
+\let\MPanchor\MPpos
+
+\let\POSp\MPp \let\POSx\MPx \let\POSy\MPy
+\let\POSh\MPh \let\POSd\MPd \let\POSw\MPw
\protect \endinput
diff --git a/tex/context/base/core-pos.tex b/tex/context/base/core-pos.tex
deleted file mode 100644
index 06bf55cae..000000000
--- a/tex/context/base/core-pos.tex
+++ /dev/null
@@ -1,767 +0,0 @@
-%D \module
-%D [ file=core-pos,
-%D version=1999.08.01,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Positioning Support,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% needs a cleanup, things may change; we also need to move the mp
-% related code to meta-pos
-
-% shorter tags, ..:achtergrond:.. etc in pos actions
-
-% dubbele text- * pos's eruit
-
-% class pos -> als gelijk aan vorige, dan niet niet definieren
-% en erven, maw:
-%
-% 1 -> opslaan
-% 2 -> undef, dus == prev
-% 3 -> undef, dus == prev
-% 4 -> opslaan
-
-\writestatus{loading}{Context Positioning Support}
-
-% todo: topskip als optie voor eerste regel achtergrond
-% todo: build pos layers on top of layers
-% todo: positionlayer pos van text-1 etc delen
-
-%D Although \TEX\ has a rather powerful channel to the outside
-%D world, called \type {\special}, real communication with
-%D other programs is complicated by the fact that no positional
-%D information is available. Mid 1999, I discussed this with
-%D \THANH, the author of \PDFTEX, and after some experiments,
-%D \PDFTEX\ was extended with a simple but effective mechanism,
-%D that provided positional information. The interesting
-%D thought is that, although \TEX\ is frozen, similar
-%D functionality could have been achieved with \type
-%D {\specials} and an additional \DVI\ postprocessor.
-%D
-%D Since we want to be as compatible as can be, \CONTEXT\ will
-%D support both methods, although the development is primarily
-%D driven by the \PDFTEX\ way of doing things. Since the
-%D mechanism is basically not limited to one application, for
-%D the moment we stick to building the functionality around one
-%D \CONTEXT\ special command, but at the same time we keep our
-%D eyes open for extensions in other directions.
-%D
-%D A question that may arise when one reads this module, is to
-%D what extend these macros are generic, in the sense that they
-%D could be collected in a support module instead of a core
-%D module. Since the mechanism described here will closely
-%D cooperate with the \METAPOST\ support built in \CONTEXT,
-%D which in turn will be tightly integrated with the \CONTEXT\
-%D overlay mechanisms, I decided to write a core module instead
-%D of a support one. This makes even more sense, when one takes
-%D into account that this kind of support depends on special
-%D drivers.
-
-\unprotect
-
-%D The first application of positional information was embedded
-%D graphics. Since we are interacting with text, it made sense
-%D to take the current line height and depth into account too.
-%D This is why we have two basic position macros: one for
-%D simple positions, and one for boxes.
-%D
-%D We could have sticked to one special, and actually did so in
-%D earlier experiments, but for convenience, as well for
-%D clearness, we now have two alternatives. This approach will
-%D save us quite some bytes when storing large quantities of
-%D positional information. We save as less information as
-%D needed, that is, we save no dimensions, in a \METAPOST\
-%D friendly way.
-%D
-%D The three specials involved are:
-%D
-%D \starttyping
-%D \dosetposition {identifier}
-%D \dosetpositionwhd {identifier} {width} {height} {depth}
-%D \dosetpositionplus {identifier} {width} {height} {depth} {list}
-%D \dosetpositionpapersize {width} {height}
-%D \stoptyping
-
-\newbox\positionbox
-\newif \ifpositioning
-
-\def\POSprefix{POS::}
-
-\let\setpospx \gobblefourarguments % suppress errors with mkii tuo file
-\let\setpospxywhd \gobblesevenarguments % suppress errors with mkii tuo file
-\let\setpospxyplus\gobbleeightarguments % suppress errors with mkii tuo file
-
-%D This is real tricky! The page anchor is applied to the
-%D page box and therefore flushed first. So, when present, it
-%D is applied to all positions except itself.
-
-\chardef\positionanchormode=0 % don't relocate page origin
-\chardef\positionanchormode=1 % relocate page origin once
-
-%D The core set macros.
-
-\let\pospxy \gobblefourarguments
-\let\pospxywhd \gobblesevenarguments
-\let\pospxyplus\gobbleeightarguments
-
-%D Sometimes we want to trick the position handler a bit:
-
-\let\replacepospxywhd\gobbleeightarguments
-
-%D For postprocessing purposes, we save the number of
-%D positions.
-
-\newcount\currentpositions % current number of positions
-\newcounter\totalnofpositions % total from previous run
-
-\appendtoks
- \expanded{\savecurrentvalue\noexpand\totalnofpositions{\the\currentpositions}}%
-\to \everybye
-
-%D The next switch can be used to communicate a special
-%D situation. Positioning and associated actions can be
-%D executed any time. However, in for instance backgrounds
-%D they can be collected in a layer, for instance the text
-%D layer (especially the hidden text layer). In the case of
-%D floats, we run into problems, since the page information is
-%D not applicable when the content floats indeed. In such
-%D situations one can treat positions and graphics local.
-
-\newif\iflocalpositioning
-
-%D Watch out: sometimes a pagebreak occurs inside a float
-%D placement, so there we need to disable local mode.
-
-\appendtoks
- \localpositioningtrue
-\to \everyinsidefloat
-
-\appendtoks
- \localpositioningfalse
-\to \everypagebody
-
-\def\checkpositions
- {\startnointerference
- \protectlabels
- \doutilities{positions}\jobname\empty\relax\relax
- \global\let\checkpositions\relax
- \stopnointerference}
-
-%D Since the positional values are to be fully expandable, we
-%D need to preload them as soon as possible, which is why we
-%D load the data when we start a text.
-
-\appendtoks \checkpositions \to \everystarttext
-
-%D Positions are either generated at a delayed write time
-%D (in \PDFTEX), or derived from the dvi file. The actual
-%D method is implemented in a special driver. If needed, the
-%D driver can fall back on the following macros.
-
-\let\dolazysaveposition \gobblefourarguments % tag page x y
-\let\dolazysavepositionwhd \gobblesevenarguments % tag page x y w h d
-\let\dolazysavepositionplus\gobbleeightarguments % tag page x y w h d list
-\let\dosaveposition \gobblefourarguments % tag page x y
-\let\dosavepositionwhd \gobblesevenarguments % tag page x y w h d
-\let\dosavepositionplus \gobbleeightarguments % tag page x y w h d list
-
-%D \macros
-%D {MPp, MPx, MPy, MPw, MPh, MPd,
-%D MPxy, MPll, MPlr, MPur, MPul, MPpos}
-%D
-%D Access to the positional information is provided by macros
-%D with short names that are clearly meant for \METAPOST.
-
-\let\MPp \!!zerocount
-\def\MPx \!!zeropoint
-\def\MPy \!!zeropoint
-\def\MPw \!!zeropoint
-\def\MPh \!!zeropoint
-\def\MPd \!!zeropoint
-\def\MPxy \!!zeropoint
-\def\MPll \!!zeropoint
-\def\MPlr \!!zeropoint
-\def\MPur \!!zeropoint
-\def\MPul \!!zeropoint
-\def\MPpos{\!!zerocount,\!!zeropoint,\!!zeropoint,\!!zeropoint,\!!zeropoint,\!!zeropoint}
-
-%D \macros
-%D {MPplus, MPrest, MPv, MPvv}
-%D
-%D Since we will probably keep on extending, we provide a
-%D general extension macro. The plus alternative takes an
-%D extra argument, denoting what additional parameter to pick
-%D up. So, the third extra is fetched with,
-%D
-%D \starttyping
-%D \MPplus{identifier}{3}{default}
-%D \stoptyping
-%D
-%D All extras (comma separated) are fetched with:
-%D
-%D \starttyping
-%D \MPrest{identifier}
-%D \stoptyping
-%D
-%D The extra parameters are not treated.
-
-\def\MPplus#1#2{\!!zerocount} \def\MPv {\MPplus}
-\def\MPrest#1#2{#2} \def\MPvv{\MPrest}
-
-%D \macros
-%D {MPanchor}
-%D
-%D For readability we define a few synonyms:
-
-\def\MPanchor{\MPpos}
-
-%D \macros
-%D {POSp, POSx, POSy, POSh, POSd, POSw}
-%D
-%D and:
-
-\def\POSp{\MPp} \def\POSx{\MPx} \def\POSy{\MPy}
-\def\POSh{\MPh} \def\POSd{\MPd} \def\POSw{\MPw}
-
-%D There are two low level positioning macros. Both store the
-%D position as well as execute an action associated with that
-%D position.
-
-\def\initializenextposition
- {\ifpositioning \else
- \global\positioningtrue
- \dosetpositionpapersize
- {\printpaperwidth }%
- {\printpaperheight}%
- \fi
- \global\advance\currentpositions\plusone}
-
-\def\setpositiononly#1%
- {\iftrialtypesetting
- % nothing
- \else
- \initializenextposition
- \def\currentposition{#1}%
- \dosetposition\currentposition
- \fi}
-
-\def\setposition#1%
- {\iftrialtypesetting
- % nothing
- \else
- \initializenextposition
- \def\currentposition{#1}%
- \dosetposition\currentposition
- \traceposstring\llap\green{\currentposition>}%
- \dopositionaction\currentposition
- \fi}
-
-\def\setpositiondata#1#2#3#4%
- {\iftrialtypesetting \else
- \initializenextposition
- \hbox
- {\def\currentposition{#1}%
- \dosetpositionwhd\currentposition
- {\the\dimexpr#2\relax}%
- {\the\dimexpr#3\relax}%
- {\the\dimexpr#4\relax}%
- \traceposstring\llap\green{\currentposition>}%
- \dopositionaction\currentposition
- \hss}%
- \fi}
-
-\def\setpositionbox#1%
- {\dowithnextbox
- {\iftrialtypesetting
- \flushnextbox
- \else
- \initializenextposition
- \hbox to \nextboxwd
- {\edef\currentposition{#1}%
- \dosetpositionwhd\currentposition
- {\the\nextboxwd}%
- {\the\nextboxht}%
- {\the\nextboxdp}%
- \traceposstring\llap\green{\currentposition>}%
- \setbox\positionbox\flushnextbox
- \dopositionaction\currentposition
- \box\positionbox
- \hss}%
- \fi}}
-
-\def\setpositiondataplus#1#2#3#4#5%
- {\iftrialtypesetting \else
- \initializenextposition
- \hbox % bug: to \nextboxwd
- {\edef\currentposition{#1}%
- \dosetpositionplus\currentposition
- {\the\dimexpr#2\relax}%
- {\the\dimexpr#3\relax}%
- {\the\dimexpr#4\relax}%
- {#5}%
- \traceposstring\rlap\magenta{<\currentposition}%
- \dopositionaction\currentposition
- \hss}%
- \fi}
-
-\def\setpositionplus#1#2%
- {\dowithnextbox
- {\iftrialtypesetting
- \flushnextbox
- \else
- \initializenextposition
- \hbox to \nextboxwd
- {\edef\currentposition{#1}%
- \dosetpositionplus\currentposition
- {\the\nextboxwd}%
- {\the\nextboxht}%
- {\the\nextboxdp}%
- {#2}%
- \traceposstring\rlap\magenta{<\currentposition}%
- \setbox\positionbox\flushnextbox
- \dopositionaction\currentposition
- \box\positionbox
- \hss}%
- \fi}}
-
-\let\currentposition\s!unknown
-
-%D A few more low level macros take care of defining and
-%D recalling actions. We could save this information in the
-%D position containers themselves, this would save hash
-%D entries, but at the cost of much more time consuming
-%D expansion. Actions are saved globally!
-
-\newtoks\everypositionaction
-
-\let\POSactionprefix\POSprefix
-
-\def\dosetpositionaction#1%
- {\setgvalue{\POSactionprefix#1::}}
-
-%D The lists can become quite long (also because there can
-%D be lots of parameters passed on) so we provide a hook
-%D to clean up the list afterwards.
-
-\let\cleanuppositionaction\gobbleoneargument
-
-\def\doifpositionaction#1%
- {\ifcsname\POSactionprefix#1::\endcsname
- \@EA\firstofoneargument
- \else
- \@EA\gobbleoneargument
- \fi}
-
-\def\doifpositionactionelse#1%
- {\ifcsname\POSactionprefix#1::\endcsname
- \@EA\firstoftwoarguments
- \else
- \@EA\secondoftwoarguments
- \fi}
-
-%D We can copy a position with:
-%D
-%D \starttyping
-%D \copyposition {to} {from}
-%D \stoptyping
-%D
-%D Again, this is a global action.
-
-\let\copyposition\gobbletwoarguments
-
-%D The fact that handling positions is a two pass operation, is
-%D one of the reasons why we need to be able to test for
-%D existence, using:
-%D
-%D \starttyping
-%D \doifpositionelse {identifier} {found action} {not found action}
-%D \stoptyping
-
-\let\doifpositionelse\thirdofthreearguments
-
-%D We have now arrived at a few macros that would make sense as
-%D support macros, but ended up in the core.
-
-%D \macros
-%D {xypos}
-%D
-%D We have several macros available to save positions. Later
-%D we will see applications.
-%D
-%D \starttabulate[|l|l||]
-%D \NC \type {\xypos} \NC \NC simple position with no dimensions \NC \NR
-%D \NC \type {\hpos} \NC \NC position and characteristics of a \type {\hbox} \NC \NR
-%D \NC \type {\vpos} \NC \NC position and characteristics of a \type {\vbox} \NC \NR
-%D \NC \type {\bpos} \NC b: \NC begin point in a line \NC \NR
-%D \NC \type {\epos} \NC e: \NC end point in a line \NC \NR
-%D \NC \type {\fpos} \NC f: \NC begin point in a paragraph \NC \NR
-%D \NC \type {\tpos} \NC t: \NC end point in a paragraph \NC \NR
-%D \stoptabulate
-%D
-%D Each macro takes an identifier as argument, and the \type
-%D {\hpos} and \type {\vpos} also expect box content.
-
-% \def\xypos{\initializenextposition\dosetposition}
-
-\let\xypos\setpositiononly
-
-\def\hpos#1{\dontleavehmode\setpositionbox{#1}\hbox}
-\def\vpos#1{\setpositionbox{#1}\vbox}
-
-\def\bpos#1{\hpos{b:#1}{\strut}\ignorespaces}
-\def\epos#1{\removelastspace\hpos{e:#1}{\strut}}
-
-\def\fpos#1%
- {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut
- \ignorespaces}
-
-\def\tpos#1%
- {\removelastspace
- \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
-
-\def\ffpos#1%
- {\setpositionplus{b:#1}{\number\parposcounter}\horizontalstrut\wpos{#1}%
- \ignorespaces}
-
-\def\ttpos#1%
- {\removelastspace
- \setpositionplus{e:#1}{\number\parposcounter}\horizontalstrut}
-
-\def\wpos#1%
- {\dontleavehmode\vadjust % may disappear if buried
- {\setbox0\hbox{\raise\strutdp\hbox{\rawwpos{#1}}}%
- \rlap{\smashedbox0}}}
-
-\def\wwpos#1% \hsmashed{\llap{\rawwpos{#1}}}
- {\rlap
- {\setbox0\hbox{\rawwpos{#1}}%
- \smashedbox0}}
-
-\def\rawwpos#1%
- {\hpos{w:#1}
- {\strut
- \hskip-\leftskip
- \hskip\hsize
- \hskip-\rightskip}}
-
-% the next macro disables par positions (in inner boxes) and
-% only registers the width
-
-\def\setinnerparpositions
- {\let\fpos\ffpos
- \let\tpos\ttpos
- \let\wpos\wwpos}
-
-% example of usage: (see for application "techniek")
-%
-% \appendtoks
-% \setinnerparpositions
-% \to \everytabulate
-
-%D When we want to calculate more complex backgrounds, we
-%D need to know what the current indentation scheme is. At
-%D the cost of many positions and memory, we can keep track
-%D of them. This mechanism is activated automatically
-%D based on information collected in the previous pass.
-
-\newcount\parposcounter
-
-\newif\ifpositioningpar
-
-% we can check for used entries, and if not, then not add one
-
-\def\registerparoptions
- {\ifpositioningpar \ifpositioning \iftrialtypesetting \else
- \ifinpagebody \else \ifmmode \else \ifinformula \else
- \ifprocessingverbatim
- \iflinepar \doregisterparoptions \fi
- \else
- \doregisterparoptions
- \fi
- \fi \fi \fi
- \fi \fi \fi}
-
-\chardef\parposstrut=1 % 0 => no strut data, so fall backs used
-
-\newif\iftracepositions
-
-% \def\doregisterparoptions
-% {\global\advance\parposcounter\plusone
-% \begingroup
-% \leftskip 1\leftskip
-% \rightskip1\rightskip
-% \setpositiondataplus
-% {p:\number\parposcounter}% identifier
-% {\the\zeropoint}%
-% {\the\strutht}%
-% {\the\strutdp}%
-% {\the\hsize ,% 1
-% \the\leftskip ,% 2
-% \the\rightskip ,% 3
-% \the\hangindent,% 4
-% \the\hangafter ,% 5 (num)
-% \the\parindent }% 6
-% %\normalhbox{\registerparsymbol}%
-% \registerparsymbol
-% \endgroup}
-
-\def\doregisterparoptions
- {\global\advance\parposcounter\plusone
- \setpositiondataplus
- {p:\number\parposcounter}% identifier
- {\the\zeropoint}%
- {\the\strutht}%
- {\the\strutdp}%
- {\the\hsize,\the\dimexpr\leftskip\relax,\the\dimexpr\rightskip\relax,\the\hangindent,\the\hangafter,\the\parindent}%
- %\normalhbox{\registerparsymbol}%
- \iftracepositions\registerparsymbol\fi}
-
-\def\traceposstring#1#2#3%
- {\iftracepositions\smashedhbox{#1{\infofont#2#3}}\fi}
-
-\def\registerparsymbol
- {\iftracepositions
- \smashedhbox to \zeropoint
- {\hss
- \startcolor[blue]%
- \llap{\infofont\number\parposcounter}%
- \scratchdimen\onepoint
- \vrule
- \!!width 4\scratchdimen
- \!!height2\scratchdimen
- \!!depth 2\scratchdimen
- \stopcolor
- \hss}%
- \fi}
-
-% \appendtoks \registerparoptions \to \everypar
-
-%D Eperimental code, don't use this yet: (must be sped up anyway)
-
-\def\@@noden{node:n:}
-\def\@@nodeo{node:o:}
-\def\@@nodep{node:p:}
-
-\def\doifelsenodelocation#1%
- {\ifcsname\@@noden#1\endcsname
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-\def\nextnodelocation#1%
- {\ifcsname\@@noden#1\endcsname\pluscounter{\@@noden#1}\fi}
-
-\def\newnodelocation#1%
- {\ifcsname\@@noden#1\endcsname
- \setcounter{\@@noden#1}\zerocount
- \letgvalue {\@@nodeo#1}\!!zerocount
- \fi}
-
-\def\tagnodelocation#1%
- {\ifcsname\@@noden#1\endcsname\xypos{\@@nodep#1:\countervalue{\@@noden#1}}\fi}
-
-\def\getnodelocationp#1{\MPp{\@@nodep#1:\countervalue{\@@noden#1}}}
-\def\getnodelocationx#1{\MPx{\@@nodep#1:\countervalue{\@@noden#1}}}
-\def\getnodelocationy#1{\MPy{\@@nodep#1:\countervalue{\@@noden#1}}}
-
-\def\numnodelocationp#1#2{\MPp{\@@nodep#1:\number#2}}
-\def\numnodelocationx#1#2{\MPx{\@@nodep#1:\number#2}}
-\def\numnodelocationy#1#2{\MPy{\@@nodep#1:\number#2}}
-
-\def\getnodelocationn#1{\countervalue{\@@noden#1}}
-\def\getnodelocationo#1{\getvalue {\@@nodeo#1}}
-
-\chardef\nodelocationmode\plusone
-
-\def\analyzenodelocation#1%
- {\ifcsname\@@noden#1\endcsname
- \doanalyzenodelocation{#1}{\getnodelocationn{#1}}\zerocount
- \fi}
-
-\def\doanalyzenodelocation#1#2#3% class n default
- {\begingroup
- \donefalse
- \ifcase\nodelocationmode
- % do nothing
- \else
- \edef\nodelocationselfn{#2}%
- \edef\nodelocationselfp{\numnodelocationp{#1}\nodelocationselfn}%
- \edef\nodelocationselfx{\numnodelocationx{#1}\nodelocationselfn}%
- \edef\nodelocationselfy{\numnodelocationy{#1}\nodelocationselfn}%
- \scratchcounter\plusone
- \doloop
- {\ifnum\recurselevel=\nodelocationselfn\relax
- \donetrue
- \else
- \edef\nodelocationotherp{\numnodelocationp{#1}\recurselevel}%
- \edef\nodelocationotherx{\numnodelocationx{#1}\recurselevel}%
- \edef\nodelocationothery{\numnodelocationy{#1}\recurselevel}%
- \ifcase\nodelocationmode
- \or
- % ok for single column
- \ifcase\nodelocationotherp\relax
- \exitloop
- \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
- \donetrue \advance\scratchcounter\plusone
- \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
- % skip
- \else\ifdim\nodelocationothery>\nodelocationselfy\relax
- \donetrue \advance\scratchcounter\plusone
- \else\ifdim\nodelocationothery<\nodelocationselfy\relax
- % skip
- \else\ifdim\nodelocationotherx<\nodelocationselfx\relax
- \donetrue \advance\scratchcounter\plusone
- \fi\fi\fi\fi\fi\fi
- \or
- % acceptable for double column
- \ifcase\nodelocationotherp\relax
- \exitloop
- \else\ifnum\nodelocationotherp<\nodelocationselfp\relax
- \donetrue \advance\scratchcounter\plusone
- \else\ifnum\nodelocationotherp>\nodelocationselfp\relax
- % skip
- \else\ifnum\recurselevel>\nodelocationselfn\relax
- \donetrue \exitloop
- \else
- \donetrue \advance\scratchcounter\plusone
- \fi\fi\fi\fi
- \else
- \exitloop
- \fi
- \fi}%
- \fi
- \ifdone \else
- \scratchcounter#3\relax
- \fi
- \setxvalue{\@@nodeo#1}{\the\scratchcounter}%
- \endgroup}
-
-\unexpanded\def\shownodelocation#1%
- {\ifcsname\@@noden#1\endcsname
- \analyzenodelocation{#1}%
- (#1,%
- n:\getnodelocationn{#1},%
- p:\getnodelocationp{#1},%
- x:\getnodelocationx{#1},%
- y:\getnodelocationy{#1},%
- o:\getnodelocationo{#1})%
- \fi}
-
-%D \macros
-%D {doifoverlappingelse}
-%D
-%D A first application of positional information, is to
-%D determine if two boxes do overlap:
-%D
-%D \starttyping
-%D \doifoverlappingelse{point a}{point b}
-%D {action when overlapping}
-%D {action when not overlapping}
-%D \stoptyping
-
-\def\overlappingmargin{-2\scaledpoint}
-
-\def\doifoverlappingelse#1#2%
- {\begingroup
- \donefalse
- \edef\!!stringa{#1}\edef\!!stringb{#2}%
- \ifnum\MPp\!!stringa=\MPp\!!stringb\relax
- \!!dimena\MPx\!!stringa
- \!!dimenb\dimexpr\MPx\!!stringa+\MPw\!!stringa\relax
- \!!dimenc\dimexpr\MPy\!!stringa-\MPd\!!stringa\relax
- \!!dimend\dimexpr\MPy\!!stringa+\MPh\!!stringa\relax
- \!!dimene\MPx\!!stringb
- \!!dimenf\dimexpr\MPx\!!stringb+\MPw\!!stringb\relax
- \!!dimeng\dimexpr\MPy\!!stringb-\MPd\!!stringb\relax
- \!!dimenh\dimexpr\MPy\!!stringb+\MPh\!!stringb\relax
- \ifdim\overlappingmargin=\zeropoint\else
- \advance\!!dimena-\overlappingmargin
- \advance\!!dimenb+\overlappingmargin
- \advance\!!dimenc-\overlappingmargin
- \advance\!!dimend+\overlappingmargin
- \advance\!!dimene-\overlappingmargin
- \advance\!!dimenf+\overlappingmargin
- \advance\!!dimeng-\overlappingmargin
- \advance\!!dimenh+\overlappingmargin
- \fi
- % more often eh fb eg fg
- \def\checkone##1##2%
- {\ifdim##1<\!!dimena \else \ifdim##1>\!!dimenb \else
- \ifdim##2<\!!dimenc \else \ifdim##2>\!!dimend \else
- \donetrue
- \fi\fi
- \fi\fi}%
- \def\checktwo##1##2%
- {\ifdim##1<\!!dimene \else \ifdim##1>\!!dimenf \else
- \ifdim##2<\!!dimeng \else \ifdim##2>\!!dimenh \else
- \donetrue
- \fi\fi
- \fi\fi}%
- \checkone\!!dimene\!!dimeng \ifdone \else
- \checkone\!!dimene\!!dimenh \ifdone \else
- \checkone\!!dimenf\!!dimeng \ifdone \else
- \checkone\!!dimenf\!!dimenh \ifdone \else
- \checktwo\!!dimena\!!dimenc \ifdone \else
- \checktwo\!!dimena\!!dimend \ifdone \else
- \checktwo\!!dimenb\!!dimene \ifdone \else
- \checktwo\!!dimenb\!!dimenc \fi \fi \fi \fi \fi \fi \fi
- \fi
- \ifdone
- \endgroup\expandafter\firstoftwoarguments
- \else
- \endgroup\expandafter\secondoftwoarguments
- \fi}
-
-%D \macros
-%D {doifpositionsonsamepageelse,
-%D doifpositionsonthispageelse}
-%D
-%D Instead of letting the user handle fuzzy expansion, we
-%D provide a simple test on positione being on the same page.
-%D
-%D \starttyping
-%D \doifpositionsonsamepageelse{point a}{point b}
-%D {action when on same page}
-%D {action when not on same page}
-%D \doifpositionsonthispageelse{point a}{point b}
-%D {action when on this page}
-%D {action when not on this page}
-%D \stoptyping
-
-\def\dodoifpositionsonsamepageelse#1#2#3#4%
- {\bgroup
- \scratchcounter#1\donefalse
- \def\docommand##1%
- {\ifcase\scratchcounter
- \scratchcounter\MPp{##1}\donetrue
- \else
- \ifnum\scratchcounter=\MPp{##1}\relax\else\donefalse\fi
- \fi}%
- \rawprocesscommalist[#2]\docommand
- \ifdone\egroup#3\else\egroup#4\fi}
-
-\def\doifpositionsonsamepageelse
- {\dodoifpositionsonsamepageelse{0}}
-
-\def\doifpositionsonthispageelse#1#2#3%
- {\dodoifpositionsonsamepageelse\realfolio}
-
-%D Plugins:
-
-\loadmarkfile{core-pos}
-
-\let\MPv \MPplus
-\let\MPvv\MPrest
-
-\let\MPanchor\MPpos
-
-\let\POSp\MPp \let\POSx\MPx \let\POSy\MPy
-\let\POSh\MPh \let\POSd\MPd \let\POSw\MPw
-
-\protect \endinput
diff --git a/tex/context/base/core-ref.lua b/tex/context/base/core-ref.lua
deleted file mode 100644
index 6aaef5cc9..000000000
--- a/tex/context/base/core-ref.lua
+++ /dev/null
@@ -1,106 +0,0 @@
-if not modules then modules = { } end modules ['core-ref'] = {
- version = 1.001,
- comment = "companion to core-ref.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-local format, texsprint = string.format, tex.sprint
-
--- beware, this is a first step in the rewrite (just getting rid of
--- the tuo file); later all access and parsing will also move to lua
-
-jobreferences = jobreferences or { }
-jobreferences.tobesaved = jobreferences.tobesaved or { }
-jobreferences.collected = jobreferences.collected or { }
-
-local tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
-
-local function initializer()
- tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
- -- hack, just the old way
- texsprint(tex.ctxcatcodes,"\\bgroup\\the\\everyreference")
- for prefix, list in pairs(collected) do
- for tag, data in pairs(list) do
- texsprint(tex.ctxcatcodes,format("\\dosetjobreference{%s}{%s}{%s}{%s}{%s}",prefix,tag,data[1],data[2],data[3]))
- end
- end
- texsprint(tex.ctxcatcodes,"\\egroup")
-end
-
-if job then
- job.register('jobreferences.collected', jobreferences.tobesaved, initializer)
-end
-
-function jobreferences.set(prefix,tag,page,realpage,text)
- for ref in tag:gmatch("[^,]+") do
- local p, r = ref:match("^(%-):(.-)$")
- if p and r then
- prefix, ref = "", r
- end
- if ref ~= "" then
- local pd = tobesaved[prefix]
- if not pd then
- pd = { }
- tobesaved[prefix] = pd
- end
- pd[ref] = { page, realpage, text }
- end
- end
-end
-
-function jobreferences.with(tag)
- for ref in tag:gmatch("[^,]+") do
- texsprint(tex.ctxcatcodes,format("\\dowithjobreference{%s}",ref:gsub("^(%-):","")))
- end
-end
-
--- this reference parser is just an lpeg version of the tex based one
-
-local result = { }
-
-local lparent, rparent, lbrace, rbrace, dcolon = lpeg.P("("), lpeg.P(")"), lpeg.P("{"), lpeg.P("}"), lpeg.P("::")
-
-local reset = lpeg.P("") / function (s) result = { } end
-local outer = (1-dcolon-lparent-lbrace )^1 / function (s) result.outer = s end
-local operation = (1-rparent-rbrace-lparent-lbrace)^1 / function (s) result.operation = s end
-local arguments = (1-rbrace )^0 / function (s) result.arguments = s end
-local special = (1-lparent-lbrace-lparent-lbrace)^1 / function (s) result.special = s end
-local inner = (1-lparent-lbrace )^1 / function (s) result.inner = s end
-
-local outer_reference = (outer * dcolon)^0
-
-operation = outer_reference * operation -- special case: page(file::1) and file::page(1)
-
-local optional_arguments = (lbrace * arguments * rbrace)^0
-local inner_reference = inner * optional_arguments
-local special_reference = special * lparent * (operation * optional_arguments + operation^0) * rparent
-
-
-local scanner = (reset * outer_reference * (special_reference + inner_reference)^-1 * -1) / function() return result end
-
-function jobreferences.analyse(str)
- return scanner:match(str)
-end
-
-local template = "\\setreferencevariables{%s}{%s}{%s}{%s}{%s}"
-
-function jobreferences.split(str)
- local t = scanner:match(str)
- texsprint(tex.ctxcatcodes,format(template,t.special or "",t.operation or "",t.arguments or "",t.outer or "",t.inner or ""))
-end
-
---~ print(table.serialize(jobreferences.analyse("")))
---~ print(table.serialize(jobreferences.analyse("inner")))
---~ print(table.serialize(jobreferences.analyse("special(operation{argument,argument})")))
---~ print(table.serialize(jobreferences.analyse("special(operation)")))
---~ print(table.serialize(jobreferences.analyse("special()")))
---~ print(table.serialize(jobreferences.analyse("inner{argument}")))
---~ print(table.serialize(jobreferences.analyse("outer::")))
---~ print(table.serialize(jobreferences.analyse("outer::inner")))
---~ print(table.serialize(jobreferences.analyse("outer::special(operation{argument,argument})")))
---~ print(table.serialize(jobreferences.analyse("outer::special(operation)")))
---~ print(table.serialize(jobreferences.analyse("outer::special()")))
---~ print(table.serialize(jobreferences.analyse("outer::inner{argument}")))
---~ print(table.serialize(jobreferences.analyse("special(outer::operation)")))
diff --git a/tex/context/base/core-ref.mkii b/tex/context/base/core-ref.mkii
deleted file mode 100644
index a5937726a..000000000
--- a/tex/context/base/core-ref.mkii
+++ /dev/null
@@ -1,90 +0,0 @@
-%D \module
-%D [ file=core-ref,
-%D version=2008.10.14,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Cross Referencing,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\def\rawreference#1#2#3%
- {\bgroup
- \the\everyreference
- \makesectionformat
- \writereference{#2}
- {\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber}%
- {\noexpand\realfolio}%
- {#3}%
- \egroup}
-
-\def\rawpagereference#1#2%
- {\bgroup
- \the\everyreference
- \makesectionformat
- \writereference{#2}
- {\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber}%
- {\noexpand\realfolio}%
- {}%
- \egroup}
-
-\def\rawtextreference#1#2#3%
- {\bgroup
- \the\everyreference
- \writereference{#2}
- {}%
- {\noexpand\realfolio}%
- {#3}%
- \egroup}
-
-%D The last reference is saved in a macro named \type
-%D {\lastreference} (indeed). To keep track of the order of
-%D references, later we will see for what purpose, we maintain
-%D a counter.
-
-\newcount\crossreferencenumber \crossreferencenumber\plusone
-
-\let\lastreference\empty
-
-\def\writereference#1#2#3#4%
- {\ifreferencing
- \edef\!!stringa{#1}%
- \ifx\!!stringa\empty \else
- \def\dowritereference##1%
- {\xdef\lastreference{##1}%
- \@EA\dodowritereference\lastreference\empty\empty\end{#2}{#3}{#4}}%
- \rawprocesscommalist[\!!stringa]\dowritereference
- \fi
- \fi}
-
-%D Beware: \type {#2} gobbles space in references so that
-%D \typ {a nice ref} becomes \typ {anice ref}.
-
-\def\dodowritereference#1#2#3\end#4#5#6%
- {\bgroup
- \global\advance\crossreferencenumber \plusone\relax
- \if#1-\if#2:%
- \let\referenceprefix\empty
- \xdef\lastreference{#3}%
- \else
- % \xdef\lastreference{#1#2#3}% here we loose the space
- \fi\else
- % \xdef\lastreference{#1#2#3}% here we loose the space
- \fi
- \ifx\lastreference\empty \else
- \doiffirstreferenceoccurance\lastreference
- {\thisisdestination{\referenceprefix\lastreference}}%
- \referenceinfo>\lastreference
- \expanded{\writeutilitycommand{\noexpand\mainreference{\referenceprefix}{\lastreference}{#4}{#5}{#6}}}%
- \fi
- \egroup}
-
-%D We will implement \type {\doiffirstreferenceoccurance}
-%D later on.
-
-\protect
diff --git a/tex/context/base/core-ref.mkiv b/tex/context/base/core-ref.mkiv
deleted file mode 100644
index 56ef77b37..000000000
--- a/tex/context/base/core-ref.mkiv
+++ /dev/null
@@ -1,107 +0,0 @@
-%D \module
-%D [ file=core-ref,
-%D version=2008.10.14,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Cross Referencing,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\let\mainreference\gobblefivearguments % catch mkii tuo stuff
-
-\registerctxluafile{core-ref}{1.001}
-
-\unprotect
-
-% later we will use the lua tables directly (first a hack)
-%
-% \the\everyreference % we're grouped anyway
-
-\newcount\crossreferencenumber \crossreferencenumber\plusone
-
-\def\dowithjobreference#1%
- {\global\advance\crossreferencenumber\plusone
- \doiffirstreferenceoccurance{#1}{\thisisdestination{\referenceprefix#1}}%
- \referenceinfo>{#1}}
-
-% \def\dowithjobreference#1{}
-
-\def\dosetjobreference#1#2#3#4#5%
- {\ifcsname\r!cross\fileprefix#1#2\endcsname
- \ifcase0#4\else
- \showmessage\m!references2{[#1][#2],#4 (\currentutilityfilename)}%
- \fi
- \else
- \ifcase\autocrossfilereferences
- \setglobalcrossreference{#1#2}{#3}{#4}{#5}%
- \or
- \setglobalcrossreference{#1#2}{#3}{#4}{#5}%
- \ifcsname\r!cross#1#2\endcsname
- \showmessage\m!references2{[#1][#2],#4 (auto \currentutilityfilename)}%
- \else
- \expanded{\definereference[#1#2][\fileprefix#1#2]}%
- \fi
- \or
- \ifcsname\r!cross#1#2\endcsname
- \showmessage\m!references2{[#1][#2],#4 (auto \currentutilityfilename)}%
- \else
- \expanded{\definereference[#1#2][\noexpand\v!page(\fileprefix#4)]}%
- \fi
- \fi
- \fi}
-
-\def\rawreference#1#2#3%
- {\ifreferencing
- \doifsomething{#2}
- {\bgroup
- \the\everyreference
- \makesectionformat
- \expanded{\ctxlua{jobreferences.with("#2")}}%
- \expanded{\ctxlatelua{jobreferences.set(
- "\referenceprefix",
- "#2",
- "\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber",
- "\noexpand\the\realpageno",
- \!!bs#3\!!es
- )}}%
- \egroup}%
- \fi}
-
-\def\rawpagereference#1#2%
- {\ifreferencing
- \doifsomething{#2}
- {\bgroup
- \the\everyreference
- \makesectionformat
- \expanded{\ctxlua{jobreferences.with("#2")}}%
- \expanded{\ctxlatelua{jobreferences.set(
- "\referenceprefix",
- "#2",
- "\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber",
- "\noexpand\the\realpageno",
- ""
- )}}%
- \egroup}%
- \fi}
-
-\def\rawtextreference#1#2#3%
- {\ifreferencing
- \doifsomething{#2}
- {\bgroup
- \the\everyreference
- \expanded{\ctxlua{jobreferences.with("#2")}}%
- \expanded{\ctxlatelua{jobreferences.set(
- "\referenceprefix",
- "#2",
- "",
- "\noexpand\the\realpageno",
- \!!bs#3\!!es
- )}}%
- \egroup}%
- \fi}
-
-\protect
diff --git a/tex/context/base/core-ref.tex b/tex/context/base/core-ref.tex
index b67928e45..8ca0a92bf 100644
--- a/tex/context/base/core-ref.tex
+++ b/tex/context/base/core-ref.tex
@@ -11,7 +11,9 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Cross Referencing}
+% we will merge mkii code back in here
+
+\writestatus{loading}{ConTeXt Core Macros / Cross Referencing}
% todo : unknown/illegal reference no arg
% todo : +n pages check on 'samepage' (contrastcolor)
@@ -42,93 +44,21 @@
\unprotect
-\startmessages dutch library: references
- title: verwijzingen
- 1: onbekende verwijzing --
- 2: dubbele verwijzing -- op pagina --
- 3: type verwijzing -- onbekend
- 4: verboden verwijzing --
- 21: document -- geladen
- 22: document -- is niet interactief
- 23: onduidelijke verwijzing -- (prefix=--)
-\stopmessages
-
-\startmessages english library: references
- title: references
- 1: unknown reference --
- 2: duplicate reference -- on page --
- 3: unknown reference type --
- 4: illegal reference --
- 21: document -- loaded
- 22: document -- is not interactive
- 23: obscure reference -- (prefix=--)
-\stopmessages
-
-\startmessages german library: references
- title: referenzen
- 1: unbekannte Referenz --
- 2: doppelte Referenz -- auf Seite --
- 3: unbekannte Referenz Typ --
- 4: illegale Referenz --
- 21: Dokument -- geladen
- 22: Dokument -- ist nicht aktiv
- 23: Obskure Referenz -- (Prefix=--)
-\stopmessages
-
-\startmessages czech library: references
- title: reference
- 1: neznama reference --
- 2: duplicitni reference -- na strane --
- 3: neznamy typ reference --
- 4: nedovolena reference --
- 21: dokument -- nacten
- 22: dokument -- neni interaktivni
- 23: obskurni (nejasna) reference -- (prefix=--)
-\stopmessages
-
-\startmessages italian library: references
- title: riferimenti
- 1: riferimento sconosciuto --
- 2: riferimento duplicato -- a pagina --
- 3: riferimento di tipo sconosciuto --
- 4: riferimento illecito --
- 21: documento -- caricato
- 22: il documento -- non ø interattivo
- 23: riferimento ambiguo -- (prefisso=--)
-\stopmessages
-
-\startmessages norwegian library: references
- title: referanser
- 1: ukjent referanse --
- 2: duplikat referanse -- pø side --
- 3: ukjent referansetype --
- 4: ulovlig referanse --
- 21: dokument -- er lest inn
- 22: dokument -- er ikke interaktivt
- 23: obskur referanse -- (Prefix=--)
-\stopmessages
-
-\startmessages romanian library: references
- title: referinte
- 1: referinta necunoscuta --
- 2: referinta duplicat -- la pagina --
- 3: tip necunoscut de referinta --
- 4: referinta eronata --
- 21: documentul -- este incarcat
- 22: documentul -- nu este interactiv
- 23: referinta obscura -- (prefix=--)
-\stopmessages
-
-\startmessages french library: references
- title: réferences
- 1: réference -- inconnue
- 2: réference -- dupliquée à la page --
- 3: type -- de réference inconnu
- 4: réference -- inconnue
- 21: document -- chargé
- 22: le document -- n'est pas interactif
- 23: reference -- indéterminé (préfixe=--)
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D This module deals with referencing. In \CONTEXT\ referencing
%D is one of the core features, although at a first glance
@@ -193,9 +123,79 @@
%D full reference, but it's the concept that counts. The low
%D level implementation is:
-\let\rawreference \gobblethreearguments
-\let\rawpagereference\gobbletwoarguments
-\let\rawtextreference\gobbletwoarguments
+\def\rawreference#1#2#3%
+ {\bgroup
+ \the\everyreference
+ \makesectionformat
+ \writereference{#2}
+ {\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber}%
+ {\noexpand\realfolio}%
+ {#3}%
+ \egroup}
+
+\def\rawpagereference#1#2%
+ {\bgroup
+ \the\everyreference
+ \makesectionformat
+ \writereference{#2}
+ {\sectionformat\sectionseparator\sectionseparator\noexpand\pagenumber}%
+ {\noexpand\realfolio}%
+ {}%
+ \egroup}
+
+\def\rawtextreference#1#2#3%
+ {\bgroup
+ \the\everyreference
+ \writereference{#2}
+ {}%
+ {\noexpand\realfolio}%
+ {#3}%
+ \egroup}
+
+%D The last reference is saved in a macro named \type
+%D {\lastreference} (indeed). To keep track of the order of
+%D references, later we will see for what purpose, we maintain
+%D a counter.
+
+\newcount\crossreferencenumber \crossreferencenumber\plusone
+
+\let\lastreference\empty
+
+\def\writereference#1#2#3#4%
+ {\ifreferencing
+ \edef\!!stringa{#1}%
+ \ifx\!!stringa\empty \else
+ \def\dowritereference##1%
+ {\xdef\lastreference{##1}%
+ \@EA\dodowritereference\lastreference\empty\empty\end{#2}{#3}{#4}}%
+ \rawprocesscommalist[\!!stringa]\dowritereference
+ \fi
+ \fi}
+
+%D Beware: \type {#2} gobbles space in references so that
+%D \typ {a nice ref} becomes \typ {anice ref}.
+
+\def\dodowritereference#1#2#3\end#4#5#6%
+ {\bgroup
+ \global\advance\crossreferencenumber \plusone\relax
+ \if#1-\if#2:%
+ \let\referenceprefix\empty
+ \xdef\lastreference{#3}%
+ \else
+ % \xdef\lastreference{#1#2#3}% here we loose the space
+ \fi\else
+ % \xdef\lastreference{#1#2#3}% here we loose the space
+ \fi
+ \ifx\lastreference\empty \else
+ \doiffirstreferenceoccurance\lastreference
+ {\thisisdestination{\referenceprefix\lastreference}}%
+ \referenceinfo>\lastreference
+ \expanded{\writeutilitycommand{\noexpand\mainreference{\referenceprefix}{\lastreference}{#4}{#5}{#6}}}%
+ \fi
+ \egroup}
+
+%D We will implement \type {\doiffirstreferenceoccurance}
+%D later on.
%D These macros depend on three other ones,
%D \type {\makesectionformat}, that generated \type
@@ -215,8 +215,6 @@
%D different alphabet and needs accented entries in registers.
\appendtoks
- %\def\dohandleaccent #1#2{\string#1\string#2}%
- %\def\dohandlecommand #1{\string#1}%
\cleanupfeatures
\to \everyreference
@@ -671,20 +669,19 @@
\newif\ifreferencefound
-\let\currentfullreference =\empty
-\let\currentreferencespecial =\empty
-\let\currentreferenceoperation=\empty
-\let\currentreferencearguments=\empty
-\let\currentouterreference =\empty
-\let\currentinnerreference =\empty
-
-\def\setreferencevariables#1#2#3#4#5#6%
- {\def\currentfullreference {#1}%
- \def\currentreferencespecial {#2}%
- \def\currentreferenceoperation{#3}%
- \def\currentreferencearguments{#4}%
- \def\currentouterreference {#5}%
- \def\currentinnerreference {#6}}
+\let\currentfullreference \empty
+\let\currentreferencespecial \empty
+\let\currentreferenceoperation\empty
+\let\currentreferencearguments\empty
+\let\currentouterreference \empty
+\let\currentinnerreference \empty
+
+\def\setreferencevariables#1#2#3#4#5%
+ {\def\currentreferencespecial {#1}%
+ \def\currentreferenceoperation{#2}%
+ \def\currentreferencearguments{#3}%
+ \def\currentouterreference {#4}%
+ \def\currentinnerreference {#5}}
\def\splitofffullreference#1%
{\edef\currentfullreference{#1}%
@@ -1835,12 +1832,15 @@
% \let\normalover \over
-\definecommand in {\doinatreference\currenttextreference}
-\definecommand at {\doinatreference\currentpagereference}
+\definecommand in {\dospecialin}
+\definecommand at {\dospecialat}
\definecommand about {\dospecialabout}
\definecommand from {\dospecialfrom}
\definecommand over {\dospecialabout} % needed here, else math problems
+\unexpanded\def\dospecialin{\doinatreference\currenttextreference}
+\unexpanded\def\dospecialat{\doinatreference\currentpagereference}
+
\unexpanded\def\dospecialabout[#1]%
{\dontleavehmode
\bgroup
@@ -1896,9 +1896,7 @@
%D in a different color and typeface).
\def\doinatreference#1%
- {\doifnextcharelse[% {[}
- {\dodoinatreference{#1}{}}
- {\dodoinatreference{#1}}}
+ {\doifnextoptionalelse{\dodoinatreference{#1}{}}{\dodoinatreference{#1}}}
\def\dodoinatreference#1%
{\def\dododoinatreference{\dodododoinatreference{#1}}%
@@ -2068,7 +2066,7 @@
{\dontleavehmode % replaces \leaveoutervmode
\bgroup
\forgetall
- \postponefootnotes
+ \postponenotes
%\leaveoutervmode % replaced by \dontleavehmode
\doifreferencefoundelse{#3}
{\bgroup
@@ -2120,7 +2118,7 @@
\def\dogoto#1[#2]%
{\dontleavehmode
\bgroup
- \postponefootnotes
+ \postponenotes
\doifreferencefoundelse{#2}
{\doifelsenothing{#1}
{\dosymbolreference{}{}[#2]}
@@ -2284,13 +2282,6 @@
\let\useurl\useURL
-% \def\dodouseURL[#1][#2][#3][#4]%
-% {\iffirstargument
-% \iffourthargument\setgvalue{\v!file:::#1}{\doexternaldocument{#2}{#3}{#4}}\else
-% \ifthirdargument \setgvalue{\v!file:::#1}{\doexternaldocument{#2}{#3}{\url[#1]}}\else
-% \ifsecondargument\setgvalue{\v!file:::#1}{\doexternaldocument{#2}{}{\url[#1]}}\fi\fi\fi
-% \fi}
-
\def\dodouseURL[#1][#2][#3][#4]% to be redone: not too tricky redefs ad reuse
{\iffirstargument
\iffourthargument\setgvalue{\v!file:::#1}{\doexternaldocument{#2}{#3}{#4}}\else
@@ -2633,31 +2624,15 @@
\let\currentinnerreference\currentreferenceoperation
\fi
\ifx\currentouterreference\empty
-% numexpr
- \doifinstringelse+\currentinnerreference
- {\scratchcounter\realpageno
- \advance\scratchcounter \currentinnerreference
- \edef\currentinnerreference{\the\scratchcounter}}
- {\doifinstringelse-\currentinnerreference
- {\scratchcounter\realpageno
- \advance\scratchcounter \currentinnerreference
- \edef\currentinnerreference{\the\scratchcounter}}
- \donothing}%
- \doifnonzeropositiveelse\currentinnerreference
- \donothing
- {\edef\currentinnerreference{1}}%
+ \doifinstringelse+\currentinnerreference{\edef\currentinnerreference{\the\numexpr\realpageno\currentinnerreference}}
+ {\doifinstring -\currentinnerreference{\edef\currentinnerreference{\the\numexpr\realpageno\currentinnerreference}}}%
+ \doifnonzeropositiveelse\currentinnerreference\donothing{\edef\currentinnerreference{1}}%
\docheckrealreferencepage\currentinnerreference % new
\let\currentrealreference\currentinnerreference % handy to have this available
\gotorealpage\empty\empty\currentinnerreference{#2}%
\else
\setouterlocation\currentouterreference
- \doifnonzeropositiveelse\currentinnerreference
- \donothing
- {\ifcsname\v!page:::\currentinnerreference\endcsname
- \edef\currentinnerreference{\getvalue{\v!page:::\currentinnerreference}}%
- \else
- \edef\currentinnerreference{1}%
- \fi}%
+ \doifnonzeropositiveelse\currentinnerreference\donothing{\edef\currentinnerreference{\executeifdefined{\v!page:::\currentinnerreference}1}}%
\gotorealpage\otherURL\otherfile\currentinnerreference{#2}%
\fi
\else
@@ -2761,7 +2736,7 @@
\endgroup
\fi}
-\def\coupledocument%
+\def\coupledocument
{\doquadrupleempty\docoupledocument}
%D --- STRANGE HERE, BETTER IN CORE-NAV ---
@@ -2983,8 +2958,6 @@
%D Plugin code:
-\loadmarkfile{core-ref}
-
%D In the next settings we see some variables that were not
%D used here and that concern the way the pagenumbers refered
%D to are typeset.
diff --git a/tex/context/base/core-reg.lua b/tex/context/base/core-reg.lua
deleted file mode 100644
index 820d316a6..000000000
--- a/tex/context/base/core-reg.lua
+++ /dev/null
@@ -1,186 +0,0 @@
-if not modules then modules = { } end modules ['core-reg'] = {
- version = 1.001,
- comment = "companion to core-reg.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-sorters = sorters or { }
-sorters.register = sorters.register or { }
-
--- {'e','3','','test+test+test','2--0-0-0-0-0-0-0--1','1'}
-
-function sorters.register.compare(a,b)
- local result = 0
- for i=1,4 do
- if result == 0 then
- result = sorters.comparers.basic(a,b,i)
- else
- return result
- end
- end
- if a[1] ~= 's' then -- e/f/t
- local page_a, page_b = a[3], b[3]
- if page_a < page_b then
- return -1
- elseif page_a > page_b then
- return 1
- end
- end
- return 0
-end
-
-function sorters.register.prepare(data)
- sorters.prepare(data,sorters.splitters.utf,4)
-end
-
-function sorters.register.sort(data)
- sorters.sort(data,sorters.register.compare)
-end
-
-function sorters.register.unique(data)
- sorters.unique(data)
-end
-
-function sorters.register.cleanup(data)
- sorters.cleanup(data)
-end
-
-function sorters.register.finalize(data)
- local split = { }
- for k,v in ipairs(data) do
- local entry, tag = v[2][1][3][1], ""
- local se = sorters.entries[sorters.language]
- if se and se[entry] then
- if type(se[entry]) == "number" then
- entry = se[entry]
- end
- tag = se[entry]
- else
- entry = 0
- tag = "unknown"
- end
- split[entry] = split[entry] or { tag = tag, data = { } }
- split[entry].data[#split[entry].data+1] = v
- end
- return split
-end
-
--- \registerpage{index}{,}{6}{2--0-0-0-0-0-0-0--1}{1}
-
--- for the moment we use the old structure, some day mkiv code
--- will be different: more structure, less mess
-
-local template = {
- page = "\\registerpage{%s}{%s}{%s}{%s}{%s}",
- see = "\\registersee{%s}{%s}{%s}{%s}",
- letter = "\\registerentry{%s}{%s}",
- entry = {
- "\\registerentrya{%s}{%s}",
- "\\registerentryb{%s}{%s}",
- "\\registerentryc{%s}{%s}",
- "\\registerentryd{%s}{%s}",
- },
-}
-
-function sorters.register.flush(sorted,class)
- class = class or 'index'
- for k,v in ipairs(table.sortedkeys(sorted)) do
- local s = sorted[v]
- tex.sprint(tex.ctxcatcodes,template.letter:format(class,s.tag))
- local done = { false, false, false }
- for kk,vv in ipairs(s.data) do
- if vv[2][1] then
- local e = { false, false, false, false }
- for i=1,4,1 do
- if vv[2][i] then
- e[i] = vv[2][i][1]
- end
- if e[i] ~= done[i] then
- if e[i] and e[i] ~= "" then
- done[i] = e[i]
- tex.sprint(tex.ctxcatcodes,template.entry[i]:format(class,e[i]))
- else
- done[i] = false
- end
- end
- end
- if vv[1] == 'e' then
- -- format reference pagespec realpage
- tex.sprint(tex.ctxcatcodes,template.page:format(class,",",vv[4],vv[5],vv[3]))
- elseif vv[1] == 's' then
- tex.sprint(tex.ctxcatcodes,template.see:format(class,",",vv[5],vv[3]))
- end
- end
- end
- end
-end
-
-function sorters.register.process(data)
- return sorters.process('register',data)
-end
-
--- { { entry, key }, { entry, key }, { entry, key }, { entry, key } }, kind, realpage|see, reference, pagespec
-
-jobregisters = jobregisters or { }
-jobregisters.collected = jobregisters.collected or { }
-jobregisters.tobesaved = jobregisters.tobesaved or { }
-
-job.register('jobregisters.collected', jobregisters.tobesaved)
-
-local function allocate(class)
- local d = jobregisters.tobesaved[class]
- if not d then
- d = {
- language = 'en',
- entries = { },
- sorted = false,
- class = class
- }
- jobregisters.tobesaved[class] = d
- end
- return d
-end
-
-local function collect(class)
- return jobregisters.collected[class]
-end
-
-jobregisters.define = allocate
-
-function jobregisters.save_entry(class,kind,reference,key,entry,page,realpage) -- realpage|see
- local data = allocate(class).entries
- if type(entry) == 'string' then
- entry = entry:splitchr('+')
- end
- if type(key) == 'string' then
- key = key:splitchr('+')
- end
- data[#data+1] = {
- kind, -- kind (e, f, t, s)
- {
- { entry[1] or "", key[1] or "" },
- { entry[2] or "", key[2] or "" },
- { entry[3] or "", key[3] or "" },
- { entry[4] or "", key[4] or "" }
- },
- realpage, -- realpage or seeword (check see)
- reference, -- reference
- page, -- pagespec
- }
-end
-
-jobregisters.save_see = jobregisters.save_entry
-
-function jobregisters.save_variable(class,key,value)
- if key == "l" then key = "language" end
- allocate(class)[key] = value
-end
-
-function jobregisters.process(class)
- local data = collect(class)
- if data then
- return sorters.register.process(data)
- end
-end
diff --git a/tex/context/base/core-reg.mkii b/tex/context/base/core-reg.mkii
deleted file mode 100644
index bd925d568..000000000
--- a/tex/context/base/core-reg.mkii
+++ /dev/null
@@ -1,33 +0,0 @@
-%D \module
-%D [ file=core-reg,
-%D version=2007.05.07,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Register Management,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-% the spaces between } { are essential for texutil's split
-
-\def\mkdefineregister#1% class
- {\addutilityreset{#1}}
-
-\def\mksaveregisterentry#1#2#3#4#5#6#7% class type reference key entry pagespec realpage
- {\expanded{\writeutility{r #2 {#1} {#3} {#4} {#5} {#6} {#7}}}}
-
-\def\mksaveregistersee#1#2#3#4#5#6#7% class type reference key entry see pagespec
- {\expanded{\writeutility{r #2 {#1} {#3} {#4} {#5} {#6} {#7}}}}
-
-\def\mksaveregistervariable#1#2#3% class type value
- {\expanded{\immediatewriteutility{r #2 {#1} {#3}}}}
-
-\def\mkloadregister#1#2#3% class before after
- {\doutilities{#1}{\registerparameter\c!file}{#1}{#2}{#3}}
-
-\protect \endinput
diff --git a/tex/context/base/core-reg.mkiv b/tex/context/base/core-reg.mkiv
deleted file mode 100644
index 6b7ee4e30..000000000
--- a/tex/context/base/core-reg.mkiv
+++ /dev/null
@@ -1,40 +0,0 @@
-%D \module
-%D [ file=core-reg,
-%D version=2007.05.07,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Register Management,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\registerctxluafile{core-reg}{1.001}
-
-\def\mkdefineregister#1% class
- {\ctxlua{jobregisters.define('#1')}}
-
-\def\mksaveregisterentry#1#2#3#4#5#6#7% class type reference key entry pagespec realpage
- {\expanded{\ctxlatelua{jobregisters.save_entry('#1','#2','#3',\!!bs#4\!!es,\!!bs#5\!!es,'#6','#7')}}}
-
-\def\mksaveregistersee#1#2#3#4#5#6#7% class type reference key entry see pagespec
- {\expanded{\ctxlatelua{jobregisters.save_see('#1','#2','#3',\!!bs#4\!!es,\!!bs#5\!!es,'#6','#7')}}}
-
-\def\mksaveregistervariable#1#2#3% class type value
- {\expanded{\ctxlua{jobregisters.save_variable('#1','#2','#3')}}}
-
-% Beware, we have no filename support here. For that we need to save the resulting
-% tex code in a file. No big deal.
-
-\def\mkloadregister#1#2#3% class, todo: loader macro just like mkii
- {\bgroup
- \getvalue{\s!set#1}% smells like a hack
- #2\ctxlua{jobregisters.process('#1')}#3% par needed for hanging indentation
- \getvalue{\s!reset#1}%
- \egroup}
-
-\protect \endinput
diff --git a/tex/context/base/core-reg.tex b/tex/context/base/core-reg.tex
index af779c0b2..1d139a2dc 100644
--- a/tex/context/base/core-reg.tex
+++ b/tex/context/base/core-reg.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Register Management}
+\writestatus{loading}{ConTeXt Core Macros / Register Management}
\newif \ifautoregisterhack % for the moment a private hack
@@ -81,14 +81,6 @@
\newif\ifwritetoregister \writetoregistertrue
-\ifx\undefined\mkdefineregister
- \let\mkdefineregister \gobbleoneargument
- \let\mksaveregistervariable\gobblethreearguments
- \let\mksaveregisterentry \gobblesevenarguments
- \let\mksaveregistersee \gobblesevenarguments
- \let\mkloadregister \gobbleoneargument
-\fi
-
\chardef\registerpagestatus\zerocount
\def\doprocesspageregister[#1]#2#3% key altnum entry
@@ -105,15 +97,13 @@
\makesectionformat
\doifelse{\registerparameter\c!ownnumber}\v!yes
\donetrue\donefalse
- \mksaveregisterentry
- {\currentregister}
- {\ifcase\registerpagestatus\space\or e\or f\or t\fi}
- {\nextinternalreference}
- {\asciiregisterentryA}
- {\asciiregisterentryB}
- {\sectionformat\sectionseparator\sectionseparator
- \ifdone#2\else\noexpand\pagenumber\fi}
- {\noexpand\realfolio}%
+ \expanded{\writeutility{r % spaces are essential
+ {\ifcase\registerpagestatus\space\or e\or f\or t\fi} {\currentregister} %
+ {\nextinternalreference} %
+ {\asciiregisterentryA} %
+ {\asciiregisterentryB} %
+ {\sectionformat\sectionseparator\sectionseparator\ifdone#2\else\noexpand\pagenumber\fi} %
+ {\noexpand\realfolio}}}%
\getfirstcharacter\currentregister
\registerinfo{> \firstcharacter}{#3}%
\endgroup
@@ -197,14 +187,13 @@
\defconvertexpanded\asciiregisterentryA{\registerparameter\c!keyexpansion}{#2}%
\fi}%
\makesectionformat
- \mksaveregistersee
- {\currentregister}
- {s}
- {\nextinternalreference}
- {\asciiregisterentryA}
- {\asciiregisterentryB}
- {\asciiregisterentryC}
- {\sectionformat}%
+ \expanded{\writeutility{r s %
+ {\currentregister} %
+ {\nextinternalreference} %
+ {\asciiregisterentryA} %
+ {\asciiregisterentryB} %
+ {\asciiregisterentryC} %
+ {\sectionformat}}}%
\endgroup
\registerinfo{> see}{#2}%
\fi}
@@ -890,7 +879,7 @@
\let\dosetregister\doloadregisterlinks
\def\currentregister{#1}%
\setupregister[#1][#2]%
- \mkloadregister\currentregister\dobeforeplaceregister\doafterplaceregister
+ \doutilities\currentregister{\registerparameter\c!file}\currentregister\dobeforeplaceregister\doafterplaceregister
\endgroup
\ifautoregisterhack
\doinitializeautoregister{#1}%
@@ -1109,7 +1098,7 @@
tolerance=stretch]%
\dontcomplain
\startpacked[\v!blank]%
- \mkloadregister\currentregister\dobeforeplaceregister\doafterplaceregister
+ \doutilities\currentregister{\registerparameter\c!file}\currentregister\dobeforeplaceregister\doafterplaceregister
\stoppacked
\stopcolumns
\endgroup
@@ -1138,7 +1127,7 @@
\def\doregisterregisterlanguage#1%
{\savesortlanguage{\getvalue{\??id#1\s!language}}%
- \mksaveregistervariable{#1}{l}{\getvalue{\??id#1\s!language}}}
+ \expanded{\immediatewriteutility{r l {#1} {\getvalue{\??id#1\s!language}}}}}
\def\dodefineregister[#1][#2]%
{\setupregister[#1]%
@@ -1174,7 +1163,7 @@
\doregisterregisterlanguage{#1}%
\to \everysavesortkeys
\presetheadtext[#1=\Word{#1}]%
- \mkdefineregister{#1}%
+ \addutilityreset{#1}%
\setvalue{#1}{\doregister{#1}}%
\setvalue{\e!coupled#1}{\dolinkedregister{#1}}%
\setvalue{\s!set#1}{\dosetregister{#1}}%
@@ -1204,7 +1193,7 @@
\global\utilitydonetrue}
{}}%
\doglobal\newcounter\utilityregisterlength
- \setbox0\vbox{\mkloadregister\currentregister\dobeforeplaceregister\doafterplaceregister}%
+ \setbox0\vbox{\doutilities\currentregister{\registerparameter\c!file}\currentregister\dobeforeplaceregister\doafterplaceregister}%
\endgroup
\ifregistergeplaatst
\setsystemmode \v!register
@@ -1215,10 +1204,6 @@
\def\determineregistercharacteristics
{\dodoubleempty\dodetermineregistercharacteristics}
-%D Plugins.
-
-\loadmarkfile{core-reg}
-
%D Default index:
\defineregister
diff --git a/tex/context/base/core-rul.lua b/tex/context/base/core-rul.lua
index 1c93542db..6947c7f7b 100644
--- a/tex/context/base/core-rul.lua
+++ b/tex/context/base/core-rul.lua
@@ -18,7 +18,6 @@ function commands.doreshapeframedbox(n)
local list = tex.box[n].list
for h in node.traverse_id('hlist',list) do
done = true
- -- local p = hpack(h.list)
local p = hpack(copy(h.list))
lastlinelength = p.width
if lastlinelength > width then
diff --git a/tex/context/base/core-rul.mkii b/tex/context/base/core-rul.mkii
index 4381a8d5a..59bfd2f3c 100644
--- a/tex/context/base/core-rul.mkii
+++ b/tex/context/base/core-rul.mkii
@@ -11,12 +11,1864 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Ruled Content Handling}
+
\unprotect
+%D We have removed the rather old and out dated raster methods. They
+%D have not been used for ages.
+
+%D \macros
+%D {linewidth, setuplinewidth}
+%D
+%D This module deals with rules (lines) in several ways. First
+%D we introduce two macros that can be used to set some common
+%D characteristics.
+%D
+%D \showsetup{setuplinewidth}
+%D
+%D The linewidth is available in \type{\linewidth}. The
+%D preset value of .4pt equals the default hard coded \TEX\
+%D rule width.
+
+\newdimen\linewidth
+
+\def\dosetuplinewidth[#1]%
+ {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
+
+\def\setuplinewidth
+ {\dosingleargument\dosetuplinewidth}
+
+%D \macros
+%D {ruledlinewidth, inheritruledlinewidth}
+%D
+%D Inside framed boxed we will use a private dimensions. As
+%D an option one can let the linewidth inherit its value from
+%D this one.
+
+\newdimen\ruledlinewidth \newif\ifinheritruledlinewidth
+
+% %D \TEX\ lacks support for color and even gray scales. The next
+% %D macros can provide a sort of poor mans gray scales as well
+% %D as give access to more suitable methods of rendering. Such a
+% %D method looks like:
+% %D
+% %D \starttyping
+% %D \def\methodegraybox#1#2#3#4#5#6%
+% %D { ... }
+% %D \stoptyping
+% %D
+% %D The string \type{graybox} is a common element in the name,
+% %D so we can have for instance \type {\postscriptgraybox} or
+% %D \type {\texgraybox}. The first three arguments take a
+% %D dimension, the fourth one takes a number between~0 and~1,
+% %D and the last argument specifies a radius of the box when
+% %D rounded corners are used, so:
+% %D
+% %D \startbuffer
+% %D \dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}
+% %D \stopbuffer
+% %D
+% %D \typebuffer
+% %D
+% %D becomes:
+% %D
+% %D %\startlinecorrection
+% %D % \vbox to 1cm{\getbuffer}
+% %D %\stoplinecorrection
+% %D
+% %D \startlinecorrection
+% %D \unprotect
+% %D \vbox to 1cm{\dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}}
+% %D \protect
+% %D \stoplinecorrection
+% %D
+% %D There are two predefined methodes, one uses periods and the
+% %D other uses small rules. The second method is less
+% %D efficient, but sometimes give better results. The dimensions
+% %D of the resullting box are set to zero.
+%
+% \setvalue{\v!dot graybox}{\processraster\symbol\rasterdot}
+% \setvalue{\v!rule graybox}{\processraster\symbol\rasterbox}
+%
+% \def\rasterdot{\rasterfont.}
+% \def\rasterbox{\hss\vrule\!!width.4pt\!!height.4pt\!!depth\zeropoint}
+%
+% %D Now of course we need:
+%
+% \ifx\rasterfont\undefined \def\rasterfont{\fivepoint} \fi
+%
+% %D We implement two pure \TEX\ based generators, that use
+% %D \type{\leaders} to quickly gerenate the gray pattern. One
+% %D should beware of \DIMENSION\ conflicts, so we use some
+% %D registers above~8. These macros are memory hungry and byte
+% %D spoiling.
+%
+% \def\processraster#1#2#3#4#5#6#7%
+% {\bgroup
+% \forgetall
+% \dontcomplain
+% \dimen10=\onepoint
+% \dimen10=\@@rsfactor\dimen10
+% \dimen10=#5\dimen10
+% \setbox2\hbox to #2
+% {\cleaders\hbox to 2\dimen10{#1\hss}\hss}%
+% \dimen12=#3%
+% \advance\dimen12 #4%
+% % \setbox0\vbox to \dimen12
+% {\cleaders\vbox to 2\dimen10{\box2\vss}\vss}%
+% \setbox0\hbox
+% {\hskip-.5\dimen10\lower0.5\dimen10\copy0
+% \hskip-\wd0\hskip\dimen10\lower1.5\dimen10\box0}%
+% \box0
+% \egroup}
+
+%D \macros
+%D {setupscreens}
+%D
+%D The previous macro uses a predefined constant
+%D \type{\@@rsfactor}. This factor can be set by:
+%D
+%D \showsetup{setupscreens}
+
+\def\setupscreens
+ {\dodoubleargument\getparameters[\??rs]}
+
+% %D The most appropriate way to call for this feature is
+% %D using \type{\graybox}, which is defined as:
+%
+% \def\graybox{\getvalue{\@@rsmethod graybox}}
+%
+% %D We just introduced two pure \TEX\ methods for generating
+% %D rasters. However, it's far more efficient and comfortable in
+% %D terms of speed, memory usage and file size, to use a driver
+% %D supported method.
+%
+% \setvalue{\v!external graybox}{\setgraybox}
+%
+% %D For compatibility reasons we also define the original one:
+%
+% \setvalue{\v!postscript graybox}{\getvalue{\v!external graybox}}
+%
+% %D A quite valid way of letting drivers do the job, is giving
+% %D a solid rule a gray texture.
+
+%D We will communicate through module specific variables, current
+%D framed parameters and some reserved dimension registers.
+
+\newdimen \frameddimenwd
+\newdimen \frameddimenht
+\newdimen \frameddimendp
+
+%D We don't have to stick to a \TEX\ drawn rule, but
+%D also can use rounded or even fancier shapes, as we will
+%D see later on.
+
+\def\dofilledbox
+ {\bgroup
+ \doifelse{\framedparameter\c!backgroundcorner}\v!rectangular
+ {\dofilledlinedbox}
+ {\ifzeropt\dimexpr\framedparameter\c!backgroundradius\relax % just in case of .x\bodyfontsize
+ \dofilledlinedbox
+ \else
+ \dofilledroundbox
+ \fi}%
+ \egroup}
+
+\def\dophantombox
+ {\hphantom{\dofilledbox}}
+
+\def\dofilledlinedbox
+ {\vrule\!!width\frameddimenwd\!!height\frameddimenht\!!depth\frameddimendp\relax}%
+
+\def\dostrokedroundbox
+ {\doif{\framedparameter\c!frame}\v!on\dodostrokedroundbox}
+
+\def\dodostrokedroundbox
+ {\bgroup
+ \edef\ovalmod{\framedparameter\c!framecorner}%
+ \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
+ \edef\ovalwid{\the\frameddimenwd}%
+ \edef\ovalhei{\the\frameddimenht}%
+ \edef\ovaldep{\the\frameddimendp}%
+ \edef\ovallin{\the\dimexpr\ruledlinewidth}%
+ \edef\ovalrad{\the\dimexpr\framedparameter\c!frameradius}%
+ \let\ovalstr\!!plusone
+ \let\ovalfil\!!zerocount
+ \forcecolorhack
+ \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
+ \egroup}
+
+\def\dofilledroundbox
+ {\bgroup
+ \edef\ovalmod{\framedparameter\c!backgroundcorner}%
+ \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
+ \edef\ovalwid{\the\frameddimenwd}%
+ \edef\ovalhei{\the\frameddimenht}%
+ \edef\ovaldep{\the\frameddimendp}%
+ \edef\ovallin{\the\dimexpr\ruledlinewidth\relax}%
+ \edef\ovalrad{\the\dimexpr\framedparameter\c!backgroundradius\relax}%
+ \let\ovalstr\!!zerocount
+ \let\ovalfil\!!plusone
+ \forcecolorhack
+ \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
+ \egroup}
+
+% a lot of weird corners
+%
+% \startTEXpage
+% \dontleavehmode\framed
+% [corner=0,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \stopTEXpage
+
+%D The oval box is drawn using a special macro, depending on
+%D the driver in use.
+
+\def\dograybox % avoid black rules when no gray
+ {\doifelsenothing{\framedparameter\c!backgroundscreen}
+ {\dophantombox}
+ {\raster[\framedparameter\c!backgroundscreen]{\dofilledbox}}}
+
+%D It won't be a surprise that we not only provide gray boxes,
+%D but also colored ones. Here it is:
+
+\def\docolorbox
+ {\hbox{\ifincolor
+ \doifcolorelse{\framedparameter\c!backgroundcolor}
+ {\localcolortrue\color[\framedparameter\c!backgroundcolor]{\dofilledbox}}
+ {\dophantombox}%
+ \else
+ \dophantombox
+ \fi}}
+
+%D \macros
+%D {defineoverlay, doifoverlayelse, overlayoffset,
+%D overlaywidth, overlayheight, overlaydepth,
+%D overlaycolor, overlaylinecolor, overlaylinewidth}
+%D
+%D Before we define the macro that actually takes card of the
+%D backgrounds, we introduce overlays. An overlay is something
+%D that contrary to its name lays {\em under} the text. An
+%D example of an overlay definition is:
+%D
+%D \startbuffer[tmp-1]
+%D \defineoverlay
+%D [fancy]
+%D [{\externalfigure
+%D [mp-cont.502]
+%D [width=\overlaywidth,
+%D height=\overlayheight]}]
+%D \stopbuffer
+%D
+%D \typebuffer[tmp-1]
+%D
+%D That for instance can be uses in:
+%D
+%D \startbuffer[tmp-2]
+%D \framed[backgroundachtergrond=fancy]{How Fancy!}
+%D \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
+%D \stopbuffer
+%D
+%D and looks like:
+%D
+%D \startlinecorrection
+%D \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{defineoverlay}
+%D
+%D This macro's definition is a bit obscure, due the many
+%D non||used arguments and the two step call that enable the
+%D setting of the width, height and depth variables.
+%D Multiple backgrounds are possible and are specified as:
+%D
+%D \starttyping
+%D \framed[background={one,two,three}]{Three backgrounds!}
+%D \stoptyping
+%D
+%D Most drawing packages only know width and height. Therefore
+%D the dimensions have a slightly different meaning here:
+%D
+%D \startitemize[packed]
+%D \item \type{\overlaywidth }: width of the overlay
+%D \item \type{\overlayheight}: height plus depth of the overlay
+%D \item \type{\overlaydepth }: depth of the overlay
+%D \stopitemize
+%D
+%D The resulting box is lowered to the right depth.
+
+\def\overlaywidth {\the\hsize\space} % We preset the variables
+\def\overlayheight {\the\vsize\space} % to some reasonable default
+\let\overlaydepth \!!zeropoint % values. The attributes
+\let\overlayoffset \!!zeropoint % of the frame can be (are)
+\let\overlaycolor \empty % set somewhere else.
+\let\overlaylinewidth \!!zeropoint %
+\let\overlaylinecolor \empty %
+
+%D The next register is used to initialize overlays.
+
+\newtoks\everyoverlay
+
+%D An example of an initialization is the following (overlays
+%D can contain text and be executed under an regime where
+%D interlineskip is off).
+
+\appendtoks \oninterlineskip \to \everyoverlay
+
+\def\defineoverlay
+ {\dodoubleargument\dodefineoverlay}
+
+\def\dodefineoverlay[#1][#2]%
+ {\def\docommand##1{\setvalue{\??ov##1}{\executedefinedoverlay{##1}{#2}}}%
+ \processcommalist[#1]\docommand}
+
+\prependtoks
+ \hsize\overlaywidth
+ \vsize\overlayheight
+\to\everyoverlay
+
+\long\def\executedefinedoverlay#1#2%
+ {\bgroup
+ \edef\overlaywidth {\the\frameddimenwd\space}%
+ \edef\overlayheight{\the\dimexpr\frameddimenht+\frameddimendp\relax\space}%
+ \edef\overlaydepth {\the\frameddimendp\space}%
+ \edef\overlaycolor {\framedparameter\c!backgroundcolor}%
+ %\edef\overlaycorner{\framedparameter\c!backgroundcorner}%
+ %\edef\overlayradius{\framedparameter\c!backgroundradius}%
+ \let\overlayoffset\backgroundoffset % we steal this one
+ \setbox\scratchbox\hbox{\lower\overlaydepth\hbox{\the\everyoverlay#2}}%
+ \setbox\scratchbox\hbox
+ {\hskip-.5\dimexpr\wd\scratchbox-\overlaywidth \relax
+ \raise-.5\dimexpr\ht\scratchbox-\frameddimenht\relax % not overlayheight !
+ \box\scratchbox}%
+ \wd\scratchbox\overlaywidth
+ \ht\scratchbox\overlayheight
+ \dp\scratchbox\overlaydepth
+ \startlayoutcomponent{o:#1}{overlay #1}%
+ \box\scratchbox
+ \stoplayoutcomponent
+ \egroup}
+
+%D The empty case is:
+
+\let\executeoverlay\gobblesevenarguments
+
+%D For testing we provide:
+
+\def\doifoverlayelse#1%
+ {\doifdefinedelse{\??ov#1}}
+
+%D We predefine two already familiar backgrounds:
+
+\setvalue{\??ov\v!screen}{\dograybox }
+\setvalue{\??ov\v!color }{\docolorbox}
+
+% %D After all these preparations, the background macro does no
+% %D bring to many surprises. One has to keep in mind that this
+% %D macro starts up a call chain, depending on the background
+% %D one needs:
+% %D
+% %D \startitemize[packed]
+% %D \item a raster, color or user defined shape
+% %D \item square or round corners
+% %D \item a \TEX\ or driver based method
+% %D \stopitemize
+% %D
+% %D The macro can be extended by adding commands to the token
+% %D list register \type {\everybackgroundbox}. For this
+% %D purpose, the name of the current background is available in
+% %D \type {\currentbackgound}.
+
+%D The content of the box will be (temporary) saved in a box. We
+%D also have an extra box for backgrounds.
+
+\newbox\framebox
+\newbox\extraframebox
+
+\newtoks\everybackgroundbox
+
+\let\currentbackground\empty
+
+% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
+% {\bgroup
+% \def\currentbackground{#1}%
+% \the\everybackgroundbox
+% \setbox\extraframebox\hbox
+% {\vbox{\moveleft\backgroundoffset\hbox{\executeifdefined{\??ov\currentbackground}\donothing}}}%
+% \wd\extraframebox\zeropoint % \backgroundwidth
+% \ht\extraframebox\backgroundheight
+% \dp\extraframebox\backgrounddepth
+% \box\extraframebox % \hskip-\backgroundwidth
+% \egroup}
+
+% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
+% {\bgroup
+% \def\currentbackground{#1}%
+% \ifcsname\??ov\currentbackground\endcsname
+% \the\everybackgroundbox
+% \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
+% \wd\extraframebox\zeropoint % \backgroundwidth
+% \ht\extraframebox\backgroundheight
+% \dp\extraframebox\backgrounddepth
+% \box\extraframebox % \hskip-\backgroundwidth
+% \fi
+% \egroup}
+
+\def\dodobackgroundbox
+ {\bgroup
+ \ifcsname\??ov\currentbackground\endcsname
+ \the\everybackgroundbox
+ \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
+ \wd\extraframebox\zeropoint % \backgroundwidth
+ \ht\extraframebox\backgroundheight
+ \dp\extraframebox\backgrounddepth
+ \box\extraframebox % \hskip-\backgroundwidth
+ \fi
+ \egroup}
+
+\def\dododobackgroundbox#1,#2% #2 gobbles spaces
+ {\edef\currentbackground{#1}%
+ \ifx\currentbackground\s!unknown\else
+ \dodobackgroundbox\expandafter\dododobackgroundbox
+ \fi#2}
+
+\let\backgroundoffset\!!zeropoint
+\let\backgrounddepth \!!zeropoint
+\def\backgroundwidth {\the\hsize}
+\def\backgroundheight{\the\vsize}
+
+% todo: also \def\theforegroundbox{#1}
+
+% \def\dobackgroundbox#1%
+% {\setbox\framebox\vbox
+% {\forgetall
+% \boxmaxdepth\maxdimen
+% \scratchdimen \framedparameter{#1}\relax
+% \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
+% \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
+% \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
+% \edef\backgroundoffset{\the\scratchdimen}%
+% \edef\backgroundwidth {\the\wd\framebox}%
+% \edef\backgroundheight{\the\ht\framebox}%
+% \edef\backgrounddepth {\the\dp\framebox}%
+% %\edef\foregroundbox{\box#1}%
+% \def\foregroundbox% fuzzy but needed hack, this \vss, otherwise
+% {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
+% \edef\component{\framedparameter\c!component}%
+% \hbox to \backgroundwidth % in case 'foreground' is used as overlay
+% {\ifx\component\empty
+% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
+% \else
+% \startlayoutcomponent{b:\component}{\s!background\space\component}%
+% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
+% \stoplayoutcomponent
+% \fi
+% \box\framebox\hss}}}
+
+\def\normalforegroundbox% fuzzy but needed hack, this \vss, otherwise
+ {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
+
+\def\dobackgroundbox#1%
+ {\setbox\framebox\vbox
+ {\forgetall
+ \boxmaxdepth\maxdimen
+ \scratchdimen \framedparameter{#1}\relax
+ \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
+ \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
+ \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
+ \edef\backgroundoffset{\the\scratchdimen}%
+ \edef\backgroundwidth {\the\wd\framebox}%
+ \edef\backgroundheight{\the\ht\framebox}%
+ \edef\backgrounddepth {\the\dp\framebox}%
+ %\edef\foregroundbox{\box#1}%
+ \edef\component{\framedparameter\c!component}%
+ \let\foregroundbox\normalforegroundbox
+ \hbox to \backgroundwidth % in case 'foreground' is used as overlay
+ {\ifx\component\empty
+ \expanded{\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
+ \else
+ \startlayoutcomponent{b:\component}{background \component}%
+ \expanded{\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
+ \stoplayoutcomponent
+ \fi
+ \box\framebox\hss}}}
+
+%D One can explictly insert the foreground box. For that
+%D purpose we introduce the overlay \type {foreground}.
+
+\defineoverlay[\v!foreground][\foregroundbox]
+
+%D We can specify overlays as a comma separated list of
+%D overlays, a sometimes handy feature.
+
+%D Besides backgrounds (overlays) we also need some macros to
+%D draw outlines (ruled borders). Again we have to deal with
+%D square and round corners. The first category can be handled
+%D by \TEX\ itself, the latter one depends on the driver. This
+%D macro also support a negative offset.
+
+\ifx\scratchoffset\undefined \newdimen\scratchoffset \fi
+
+\def\dooutlinebox % we needed to move the color command in order to apply attributes properly
+ {\setbox\framebox\vbox % rules on top of box
+ {\scratchoffset \framedparameter\c!frameoffset\relax
+ \frameddimenwd\dimexpr\wd\framebox+2\scratchoffset\relax
+ \frameddimenht\dimexpr\ht\framebox+ \scratchoffset\relax
+ \frameddimendp\dimexpr\dp\framebox+ \scratchoffset+\framedparameter\c!framedepth\relax
+ \ifdim\frameddimendp<\zeropoint
+ \advance\frameddimenht \frameddimendp
+ \scratchdimen-\frameddimendp
+ \frameddimendp\zeropoint
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \setbox\extraframebox\hbox
+ {\doifsomething{\framedparameter\c!framecolor}{\color[\framedparameter\c!framecolor]}{\dostrokedbox}}%
+ \setbox\extraframebox\hbox
+ {\raise\scratchdimen\vbox
+ {\moveleft\scratchoffset
+ \box\extraframebox}}%
+ \wd\extraframebox\wd\framebox
+ \ht\extraframebox\ht\framebox
+ \dp\extraframebox\dp\framebox
+ \hbox{\box\framebox\hskip-\wd\extraframebox\box\extraframebox}}}
+
+\def\dostrokedbox
+ {\doifelse{\framedparameter\c!framecorner}\v!rectangular
+ {\dostrokedlinedbox}
+ {\ifzeropt\dimexpr\framedparameter\c!frameradius\relax % just in case of .x\bodyfontsize
+ \dostrokedlinedbox
+ \else
+ \dostrokedroundbox
+ \fi}}
+
+\def\dostrokedlinedbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\frameddimenwd
+ \ht\scratchbox\frameddimenht
+ \dp\scratchbox\frameddimendp
+ \setbox\scratchbox\vbox \bgroup
+ \csname t\@@frame@@\framedparameter\c!frame\framedparameter\c!topframe \endcsname
+ \hbox \bgroup
+ \csname l\@@frame@@\framedparameter\c!frame\framedparameter\c!leftframe \endcsname
+ \box\scratchbox
+ \csname r\@@frame@@\framedparameter\c!frame\framedparameter\c!rightframe \endcsname
+ \egroup
+ \csname b\@@frame@@\framedparameter\c!frame\framedparameter\c!bottomframe\endcsname
+ \egroup
+ \wd\scratchbox\frameddimenwd
+ \ht\scratchbox\frameddimenht
+ \dp\scratchbox\frameddimendp
+ \box\scratchbox}
+
+\def\@@frame@@{@@frame@@}
+
+% \setvalue{t\@@frame@@\v!on \v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{t\@@frame@@\v!off\v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{t\@@frame@@\v!on }{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!on }{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!on \v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!off\v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!on }{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!on }{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+
+\def\@@frame@@trule{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+\def\@@frame@@brule{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+\def\@@frame@@rrule{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+\def\@@frame@@lrule{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+
+\letvalue{t\@@frame@@\v!on \v!on}\@@frame@@trule
+\letvalue{t\@@frame@@\v!off\v!on}\@@frame@@trule
+\letvalue{t\@@frame@@\v!on }\@@frame@@trule
+
+\letvalue{b\@@frame@@\v!on \v!on}\@@frame@@brule
+\letvalue{b\@@frame@@\v!off\v!on}\@@frame@@brule
+\letvalue{b\@@frame@@\v!on }\@@frame@@brule
+
+\letvalue{l\@@frame@@\v!on \v!on}\@@frame@@lrule
+\letvalue{l\@@frame@@\v!off\v!on}\@@frame@@lrule
+\letvalue{l\@@frame@@\v!on }\@@frame@@lrule
+
+\letvalue{r\@@frame@@\v!on \v!on}\@@frame@@rrule
+\letvalue{r\@@frame@@\v!off\v!on}\@@frame@@rrule
+\letvalue{r\@@frame@@\v!on }\@@frame@@rrule
+
+% no overlapping rules
+
+\def\@@frame@@trules{\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}\nointerlineskip\kern-\ruledlinewidth}
+\def\@@frame@@brules{\kern-\ruledlinewidth\nointerlineskip\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}}
+\def\@@frame@@rrules{\kern-\ruledlinewidth\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth}
+\def\@@frame@@lrules{\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth\kern-\ruledlinewidth}
+
+% small is relatively new
+
+\letvalue{t\@@frame@@\v!small\v!small}\@@frame@@trules
+\letvalue{t\@@frame@@\v!off \v!small}\@@frame@@trules
+\letvalue{t\@@frame@@\v!small }\@@frame@@trules
+
+\letvalue{b\@@frame@@\v!small\v!small}\@@frame@@brules
+\letvalue{b\@@frame@@\v!off \v!small}\@@frame@@brules
+\letvalue{b\@@frame@@\v!small }\@@frame@@brules
+
+\letvalue{l\@@frame@@\v!small\v!small}\@@frame@@lrules
+\letvalue{l\@@frame@@\v!off \v!small}\@@frame@@lrules
+\letvalue{l\@@frame@@\v!small }\@@frame@@lrules
+
+\letvalue{r\@@frame@@\v!small\v!small}\@@frame@@rrules
+\letvalue{r\@@frame@@\v!off \v!small}\@@frame@@rrules
+\letvalue{r\@@frame@@\v!small }\@@frame@@rrules
+
+%D I condidered using the low level support command
+%D \type{\ruledhbox}, but this would slow down processing by a
+%D factor~3.
+
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
+% {}
+
+%D The next few macros are probably the most misused ones in
+%D \CONTEXT. They deal with putting rules around boxes, provide
+%D backgrounds, offer alignment features, and some more. We
+%D start with defining some booleans. These give an impression
+%D of what we are going to take into account.
+
+% todo: chardefs
+
+\newif\ifboxhasoffset
+\newif\ifboxhaswidth
+\newif\ifboxhasheight
+\newif\ifboxhasformat
+\newif\ifboxhasstrut
+\newif\ifboxisoverlaid
+\newif\ifboxhasframe
+\newif\ifdelayedstrut
+
+%D We also need a few \DIMENSIONS:
+
+\newdimen\@@localoffset
+\newdimen\@@globalwidth
+
+%D \macros
+%D {framed, setupframed}
+%D
+%D Ruled boxes are typeset using \type{\framed}. This command
+%D is quite versatile and, although some users will probably
+%D seldom use it, one cannot overlook its features.
+%D
+%D \showsetup{setupframed}
+%D \showsetup{framed}
+%D
+%D This general macro is a special version of an even more
+%D general case, that can easily be linked into other macros
+%D that need some kind of framing. The local version is called
+%D with an extra parameter: the variable identifier. The reason
+%D for passing this identifier between brackets lays in the
+%D mere fact that this way we can use the optional argument
+%D grabbers.
+
+\def\defaultframeoffset{.25ex}
+
+\unexpanded\def\framed
+ {\bgroup
+ \copylocalframed[\??ol][\??oi]% == \presetlocalframed[\??ol]%
+ \dodoubleempty\startlocalframed[\??ol]}
+
+\def\presetlocalframed[#1]%
+ {\copylocalframed[#1][\??oi]}
+
+% \def\copylocalframed[#1]#2[#3]%
+% {\copyparameters[#1][#3]%
+% [\c!width,\c!height,\c!radius,\c!corner,\c!depth,\c!offset,%
+% \c!autowidth,\c!empty,\c!component,\c!orientation,\c!lines,%
+% \c!align,\c!bottom,\c!top,\c!strut,\c!autostrut,\c!location,\c!setups,\c!extras,%
+% \c!foregroundstyle,\c!foregroundcolor,%
+% \c!background,\c!backgroundoffset,\c!backgroundcorner,\c!backgroundradius,\c!backgrounddepth,\c!backgroundcolor,\c!backgroundscreen,%
+% \c!frame,\c!frameoffset,\c!framecorner,\c!frameradius,\c!framedepth,\c!framecolor,\c!rulethickness,%
+% \c!topframe,\c!bottomframe,\c!leftframe,\c!rightframe]}
+
+% since framed is used all over the place, we have a (small) speedup)
+
+\def\copylocalframed[#1]#2[#3]%
+ {\edef\copiedfrom{#1}\edef\copiedto{#3}%
+ \docopyvalue\copiedfrom\copiedto\c!width
+ \docopyvalue\copiedfrom\copiedto\c!height
+ \docopyvalue\copiedfrom\copiedto\c!autowidth
+ \docopyvalue\copiedfrom\copiedto\c!offset
+ \docopyvalue\copiedfrom\copiedto\c!empty
+ \docopyvalue\copiedfrom\copiedto\c!rulethickness
+ \docopyvalue\copiedfrom\copiedto\c!radius
+ \docopyvalue\copiedfrom\copiedto\c!corner
+ \docopyvalue\copiedfrom\copiedto\c!depth
+ \docopyvalue\copiedfrom\copiedto\c!frame
+ \docopyvalue\copiedfrom\copiedto\c!framecolor
+ \docopyvalue\copiedfrom\copiedto\c!foregroundstyle
+ \docopyvalue\copiedfrom\copiedto\c!foregroundcolor
+ \docopyvalue\copiedfrom\copiedto\c!lines
+ \docopyvalue\copiedfrom\copiedto\c!orientation
+ \docopyvalue\copiedfrom\copiedto\c!topframe
+ \docopyvalue\copiedfrom\copiedto\c!bottomframe
+ \docopyvalue\copiedfrom\copiedto\c!leftframe
+ \docopyvalue\copiedfrom\copiedto\c!rightframe
+ \docopyvalue\copiedfrom\copiedto\c!rulethickness
+ \docopyvalue\copiedfrom\copiedto\c!frameoffset
+ \docopyvalue\copiedfrom\copiedto\c!background
+ \docopyvalue\copiedfrom\copiedto\c!component
+ \docopyvalue\copiedfrom\copiedto\c!backgroundoffset
+ \docopyvalue\copiedfrom\copiedto\c!backgroundscreen
+ \docopyvalue\copiedfrom\copiedto\c!backgroundcolor
+ \docopyvalue\copiedfrom\copiedto\c!align
+ \docopyvalue\copiedfrom\copiedto\c!bottom
+ \docopyvalue\copiedfrom\copiedto\c!top
+ \docopyvalue\copiedfrom\copiedto\c!strut
+ \docopyvalue\copiedfrom\copiedto\c!autostrut
+ \docopyvalue\copiedfrom\copiedto\c!location
+ \docopyvalue\copiedfrom\copiedto\c!component
+ \docopyvalue\copiedfrom\copiedto\c!extras
+ \docopyvalue\copiedfrom\copiedto\c!setups
+ \docopyvalue\copiedfrom\copiedto\c!backgroundradius
+ \docopyvalue\copiedfrom\copiedto\c!backgroundcorner
+ \docopyvalue\copiedfrom\copiedto\c!backgrounddepth
+ \docopyvalue\copiedfrom\copiedto\c!frameradius
+ \docopyvalue\copiedfrom\copiedto\c!framecorner
+ \docopyvalue\copiedfrom\copiedto\c!framedepth}
+
+\def\setupframed
+ {\dodoubleempty\dosetupframed}
+
+\def\dosetupframed
+ {\ifsecondargument
+ \@EA\dodoublesetupframed
+ \else
+ \@EA\dosinglesetupframed
+ \fi}
+
+\def\dosinglesetupframed[#1][#2]%
+ {\getparameters[\??oi][#1]}
+
+\def\dodoublesetupframed[#1][#2]%
+ {\bgroup
+ \let\dodoubleempty\empty
+ \def\doframed[##1]{\gdef\globalredefinedframed{\dodoubleempty\doframed[##1,#2]}}%
+ \getvalue{#1}%
+ \egroup
+ \letvalue{#1}\globalredefinedframed}
+
+%D \startbuffer
+%D \setupframed [framecolor=yellow] \framed{A}
+%D \defineframed[myframed] [framecolor=blue] \myframed{B}
+%D \setupframed [myframed] [framecolor=red] \myframed{C}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \presetlocalframed[myframed]
+%D \setuplocalframed[myframed][width=4cm,height=2cm]
+%D \localframed[myframed][framecolor=green]{oeps}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {ifinframed}
+%D
+%D The normal case first presets all parameters and next starts
+%D looking for the user supplied ones. The first step is
+%D omitted in the local case, because these are preset at
+%D declaration time and keep their values unless explictly
+%D changed. By presetting the variables everytime the normal
+%D command is called, we can use this command nested, without
+%D the unwanted side effect of inheritance. The boolean is
+%D used to speed up the color stack.
+
+\newif\ifinframed
+
+\def\localframed
+ {\bgroup
+ \dodoubleempty\startlocalframed}
+
+%D The next one is faster on multiple backgrounds per page. No
+%D dimensions can be set, only frames and backgrounds.
+
+\def\fastlocalframed[#1]#2[#3]#4% 3-4
+ {\bgroup
+ \inframedtrue
+ \edef\@@framed{#1}%
+ % more bytes
+ % \scratchdimen\framedparameter\c!frameoffset
+ % \setevalue{\@@framed\c!frameoffset}{\the\scratchdimen}%
+ % \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
+ % {\scratchdimen\framedparameter\c!backgroundoffset
+ % \setevalue{\@@framed\c!backgroundoffset}{\the\scratchdimen}}%
+ % less bytes
+ \@EA\freezedimenmacro\csname\@@framed\c!frameoffset\endcsname
+ \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
+ {\@EA\freezedimenmacro\csname\@@framed\c!backgroundoffset\endcsname}%
+ % so far
+ \setbox\framebox\hbox{#4}%
+ \getparameters[\@@framed][#3]% no \expanded !
+ % no, better in calling macro
+ %
+ % \edef\doframedsetups{\framedparameter\c!setups}%
+ % \ifx\doframedsetups\empty\else
+ % \edef\doframedsetups{\noexpand\setups[\doframedsetups]}%
+ % \fi
+ \removeframedboxdepth
+ \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
+ \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}%
+ \edef\overlaylinewidth{\the\ruledlinewidth}%
+ \edef\@@localframing {\framedparameter\c!frame}%
+ \ifx\@@localframing\v!overlay \else \ifx\@@localframing\v!none \else
+ \edef\framedrulethickness{\framedparameter\c!rulethickness}%
+ \ifx\framedrulethickness\empty\else
+ \ruledlinewidth\framedrulethickness\relax
+ \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
+ \fi
+ \dooutlinebox % real or invisible frame
+ \fi \fi
+ \edef\framedbackground{\framedparameter\c!background}%
+ \ifx\framedbackground\empty\else\dobackedbox\fi
+ \restoreframedboxdepth
+ \box\framebox
+ \egroup}
+
+%D Before we go into details, we present (and implement) the
+%D main framing routine. I saw no real reason for splitting the
+%D next two macros into smaller pieces. The content will be
+%D collected in a horizontal or vertical box with fixed or free
+%D dimensions and specific settings concerning aligment and
+%D offsets.
+%D
+%D In the first few lines, we pre||expand the frame and
+%D background offsets. We do so, because the can be defined in
+%D terms of the main offset. However, see for instance page
+%D backgrounds, when \type {#2} sets the offset to \type
+%D {overlay}, both offsets become invalid.
+%D
+%D Because it is used so often the he next macro is (and
+%D looks) rather optimized.
+
+\let\postprocessframebox\relax
+
+\let\@@framed\s!unknown
+
+\def\framedparameter#1%
+ {\csname\@@framed#1\endcsname}
+
+\newdimen\!!framedwidth
+\newdimen\!!framedheight
+
+\def\startlocalframed[#1][#2]%
+ {\bgroup
+ \inframedtrue
+ \edef\@@framed{#1}%
+ % this piece of pre expansion is needed (sometimes used in frameoffset)
+ % \doifvaluesomething{\@@framed\c!rulethickness} % obsolete
+ % {\ruledlinewidth\getvalue{\@@framed\c!rulethickness}}% obsolete
+ % this piece of pre expansion is needed (sometimes used circular)
+ \setevalue{\@@framed\c!frameoffset}{\the\dimexpr\framedparameter\c!frameoffset\relax}%
+ \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
+ {\setevalue{\@@framed\c!backgroundoffset}{\the\dimexpr\framedparameter\c!backgroundoffset\relax}}%
+ % to prevent deadlock in case of self refering
+ \ifsecondargument % faster
+ \getparameters[\@@framed][#2]% here !
+ \fi
+ % new, experimental dirty hook
+ \framedparameter\c!extras
+ % to get the right spacing
+ \doifvaluesomething{\@@framed\c!foregroundstyle}
+ {\@EA\doconvertfont\csname\@@framed\c!foregroundstyle\endcsname\empty}%
+ % beware, both the frame and background offset can be overruled
+ %
+ \edef\doframedsetups{\framedparameter\c!setups}%
+ \ifx\doframedsetups\empty\else
+ \edef\doframedsetups{\noexpand\setups[\doframedsetups]}%
+ \fi
+ % the next macros are visible
+ \edef\localoffset{\framedparameter\c!offset}%
+ \edef\localwidth {\framedparameter\c!width}%
+ \edef\localheight{\framedparameter\c!height}%
+ \edef\localformat{\framedparameter\c!align}%
+ \edef\localstrut {\framedparameter\c!strut}%
+ % these are not
+ \edef\@@localautostrut {\framedparameter\c!autostrut}%
+ \edef\@@localframing {\framedparameter\c!frame}%
+ \edef\@@locallocation {\framedparameter\c!location}%
+ \edef\@@localorientation{\framedparameter\c!orientation}%
+ %
+ \edef\@@localautowidth {\framedparameter\c!autowidth}%
+ %
+ \ifx\@@localframing\v!overlay % no frame, no offset, no framewidth
+ \boxhasframefalse
+ \let\localoffset\v!overlay
+ \else\ifx\@@localframing\v!none % no frame, no framewidth
+ \boxhasframefalse
+ \else
+ \boxhasframetrue
+ \fi\fi
+ \ifboxhasframe
+ \edef\framedrulethickness{\framedparameter\c!rulethickness}%
+ \ifx\framedrulethickness\empty\else
+ \ruledlinewidth\framedrulethickness\relax
+ \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
+ \fi
+ \else
+ \ruledlinewidth\zeropoint
+ \fi
+ \ifx\localformat\empty
+ \boxhasformatfalse
+ \else
+ \boxhasformattrue
+ \dosetraggedcommand\localformat
+ \edef\dobeforeframedbox{\raggedtopcommand\framedparameter\c!top}%
+ \edef\doafterframedbox {\framedparameter\c!bottom\raggedbottomcommand}%
+ \fi
+ \ifx\localoffset\v!none
+ \boxhasoffsetfalse
+ \boxhasstrutfalse
+ \boxisoverlaidfalse
+ \@@localoffset\ruledlinewidth
+ \else\ifx\localoffset\v!overlay
+ % \ifx\@@localframing\v!no \boxhasframefalse \fi % test first
+ \boxhasoffsetfalse
+ \boxhasstrutfalse
+ \boxisoverlaidtrue
+ \@@localoffset\zeropoint
+ \else
+ \boxhasoffsettrue
+ \boxhasstruttrue
+ \boxisoverlaidfalse
+ \ifx\localoffset\v!default % new per 2-6-2000
+ \let\localoffset\defaultframeoffset
+ \letvalue{\@@framed\c!offset}\defaultframeoffset
+ \else
+ \let\defaultframeoffset\localoffset
+ \fi
+ \@@localoffset\dimexpr\localoffset+\ruledlinewidth\relax
+ \fi\fi
+ \!!framedheight\zeropoint
+ \!!framedwidth \zeropoint
+ \ifx\localwidth\v!fit
+ \ifboxhasformat
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else
+ \boxhaswidthfalse
+ \fi
+ \else\ifx\localwidth\v!fixed % equals \v!fit but no shapebox
+ \ifboxhasformat
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else
+ \boxhaswidthfalse
+ \fi
+ \else\ifx\localwidth\v!broad
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else\ifx\localwidth\v!local
+ \boxhaswidthtrue
+ \setlocalhsize
+ \!!framedwidth\localhsize
+ \else
+ \boxhaswidthtrue
+ \!!framedwidth\localwidth
+ \fi\fi\fi\fi
+ \ifx\localheight\v!fit
+ \boxhasheightfalse % no longer: \boxhasstrutfalse
+ \else\ifx\localheight\v!broad
+ \boxhasheightfalse
+ \else
+ \boxhasheighttrue
+ \!!framedheight\localheight
+ \fi\fi
+ \ifboxhasheight
+ % obey user set height, also downward compatible
+ \else
+ \doifvaluesomething{\@@framed\c!lines}
+ {\ifcase\framedparameter\c!lines\else
+ \!!framedheight\framedparameter\c!lines\lineheight
+ \edef\localheight{\the\!!framedheight}%
+ \boxhasheighttrue
+ \fi}%
+ \fi
+ % this is now an option: width=local
+ %
+ % \ifdim\!!framedwidth=\hsize
+ % \parindent\zeropoint
+ % \setlocalhsize
+ % \!!framedwidth\localhsize
+ % \fi
+ % i.e. disable (colsetbackgroundproblemintechniek)
+ \advance\!!framedwidth -2\@@localoffset
+ \advance\!!framedheight -2\@@localoffset
+ \ifx\localstrut\v!no
+ \boxhasstrutfalse
+ \else\ifx\localstrut\v!global
+ \setstrut
+ \else\ifx\localstrut\v!local
+ \setfontstrut
+ \else
+ \setstrut
+ \fi\fi\fi
+ \ifboxhasstrut
+ \let\localbegstrut\begstrut
+ \let\localendstrut\endstrut
+ \let\localstrut \strut
+ \else
+ \let\localbegstrut\pseudobegstrut % was: \relax
+ \let\localendstrut\pseudoendstrut % was: \relax
+ \let\localstrut \pseudostrut % was: \relax
+ %\ifboxhasheight\ifdim\!!framedheight<\strutht % saveguard
+ % \let\localbegstrut\relax % but not that
+ % \let\localstrut \relax % save after all
+ %\fi\fi
+ \fi
+ \ifx\@@localautostrut\v!yes
+ \let\delayedbegstrut\relax
+ \let\delayedendstrut\relax
+ \let\delayedstrut \relax
+ \else
+ \let\delayedbegstrut\localbegstrut
+ \let\delayedendstrut\localendstrut
+ \let\delayedstrut \localstrut
+ \let\localbegstrut \relax
+ \let\localendstrut \relax
+ \let\localstrut \relax
+ \fi
+ \ifboxhasheight
+ \let\\\vboxednewline
+ \ifboxhaswidth
+ \let\hairline\vboxedhairline
+ \ifboxhasformat
+ \let\next\doformatboxSomeFormat
+ \else
+ \let\next\doformatboxNoFormat
+ \fi
+ \else
+ \let\hairline\hboxedhairline
+ \ifboxhasformat
+ \let\next\doformatboxHeight
+ \else
+ \let\next\doformatboxVSize
+ \fi
+ \fi
+ \else
+ \ifboxhaswidth
+ \ifboxhasformat
+ \let\hairline\vboxedhairline
+ \let\\\vboxednewline
+ \let\next\doformatboxWidth
+ \else
+ \let\hairline\hboxedhairline
+ \let\\\hboxednewline
+ \let\next\doformatboxHSize
+ \fi
+ \else
+ \let\hairline\hboxedhairline
+ \let\\\hboxednewline
+ \let\next\doformatboxNoSize
+ \fi
+ \fi
+ \edef\framedwidth % a new feature, visible for user
+ {\ifdim\!!framedwidth >\zeropoint\the\!!framedwidth \else\zeropoint\fi}%
+ \edef\framedheight% a new feature, visible for user
+ {\ifdim\!!framedheight>\zeropoint\the\!!framedheight\else\zeropoint\fi}%
+ % we need to register the (outer) color
+ \startregistercolor[\framedparameter\c!foregroundcolor]%
+ % first alternative
+ %\def\dowithframedbox%
+ % {\let\postprocessframebox\relax %new
+ % \aftergroup\stoplocalframed}%
+ % \afterassignment\dowithframedbox
+ % \setbox\framebox=\next}
+ % second alternative
+ %\dowithnextbox
+ % {\setbox\framebox\flushnextbox
+ % \let\postprocessframebox\relax %new
+ % \stoplocalframed}
+ % \next}
+ \@@startframedorientation
+ \afterassignment\dodowithframebox
+ \setbox\framebox\next}
+
+\def\dowithframebox
+ {% moved : \let\postprocessframebox\relax
+ \stoplocalframed}
+
+\def\dodowithframebox
+ {\aftergroup\dowithframebox}
+
+\let\doafterframedbox \relax
+\let\dobeforeframedbox\relax
+
+%D Carefull analysis of this macro will learn us that not all
+%D branches in the last conditionals can be encountered, that
+%D is, some assignments to \type{\next} will never occur.
+%D Nevertheless we implement the whole scheme, if not for
+%D future extensions.
+
+%D \macros
+%D {ifreshapeframebox}
+%D
+%D The last few lines tell what to do after the content of the
+%D box is collected and passed to the next macro. In the case
+%D of a fixed width and centered alignment, the content is
+%D evaluated and used to determine the most natural width. The
+%D rest of the code deals with backgrounds and frames.
+
+\newif\ifreshapeframebox \reshapeframeboxtrue
+
+%D Beware: setting \type {top} and \type {bottom} to nothing, may
+%D result in a frame that is larger that the given height! try:
+%D
+%D \starttyping
+%D \framed
+%D [height=3cm,top=,bottom=,offset=overlay]
+%D {\strut test \shapefill \strut test}
+%D \stoptyping
+%D
+%D This is intended behaviour and not a bug! One can always set
+%D
+%D \starttyping
+%D ...,bottom=\kern0pt,...
+%D \stoptyping
+
+\def\stoplocalframed
+ {\dontshowcomposition
+ \@@stopframedorientation % hm, wrong place ! should rotate the result (after reshape)
+ \stopregistercolor
+ \handleframedlocator\c!before\@@locallocation
+ \ifboxhasformat
+ \ifx\@@localautowidth\v!force
+ \ifreshapeframebox\doreshapeframedbox\fi
+ \boxhaswidthfalse
+ \else
+ \ifx\localwidth\v!fit
+ \ifx\@@localautowidth\v!yes
+ \ifreshapeframebox\doreshapeframedbox\fi
+ \fi
+ \boxhaswidthfalse
+ \else\ifx\localwidth\v!fixed
+ \boxhaswidthfalse
+ \else
+ \resetshapeframebox
+ \fi\fi
+ \fi
+ \else
+ \resetshapeframebox
+ \fi
+ \ifboxhaswidth
+ \wd\framebox\!!framedwidth
+ \fi
+ \ifboxhasheight
+ \ht\framebox\!!framedheight
+ \fi
+ \doifvalue{\@@framed\c!empty}\v!yes
+ {\setbox\scratchbox\null
+ \wd\scratchbox\wd\framebox
+ \ht\scratchbox\ht\framebox
+ \dp\scratchbox\dp\framebox
+ \setbox\framebox\box\scratchbox}%
+ \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
+ \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
+ \ifboxhasoffset
+ \dooffsetframebox
+ \fi
+ \ifboxisoverlaid \else
+ \dolocateframebox
+ \fi
+ \ifx\postprocessframebox\relax \else
+ \let\next\postprocessframebox
+ \let\postprocessframebox\relax % prevent nesting
+ \next\framebox
+ \fi
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}%
+ \edef\overlaylinewidth{\the\ruledlinewidth}% \@@...
+ \ifboxhasframe % real or invisible frame
+ \dooutlinebox
+ \fi
+ \edef\framedbackground{\framedparameter\c!background}%
+ \ifx\framedbackground\empty\else\dobackedbox\fi
+ \handleframedlocator\c!after\@@locallocation
+ \box\framebox
+ \egroup
+ \egroup}
+
+\def\installframedlocator#1#2#3%
+ {\setvalue{\??ol:\c!location:\c!before:#1}{#2}%
+ \setvalue{\??ol:\c!location:\c!after :#1}{#3}}
+
+\def\handleframedlocator#1#2%
+ {\getvalue{\??ol:\c!location:#1:#2}}
+
+\def\doprelocframedbox#1%
+ {\scratchdimen\dimexpr#1+\ruledlinewidth\relax
+ \ifboxhasoffset
+ \advance\scratchdimen \framedparameter\c!offset
+ \fi
+ \scratchskip\dimexpr\ht\framebox-\scratchdimen\relax}
+
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
+% \framed[width=2cm,align=middle,location=depth] {location\\equals\\depth}
+% \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=low] {location\\equals\\low}
+% \framed[width=2cm,align=middle,location=line] {location\\equals\\line}
+% \framed[width=2cm,align=middle,location=high] {location\\equals\\high}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=top] {location\\equals\\top}
+% \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
+% \framed[width=2cm,align=middle,location=lohi] {location\\equals\\lohi}
+% \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
+% B}
+
+\installframedlocator \v!hanging % best with strut=no
+ {}
+ {\dp\framebox\ht\framebox
+ \ht\framebox\zeropoint}
+
+\installframedlocator \v!depth
+ {}
+ {\ht\framebox\dimexpr\ht\framebox-\strutdp\relax
+ \dp\framebox\strutdp
+ \box\framebox}
+
+\installframedlocator \v!height
+ {}
+ {\dp\framebox\dimexpr\ht\framebox-\strutht\relax
+ \ht\framebox\strutht
+ \box\framebox}
+
+\installframedlocator \v!high
+ {}
+ {\doprelocframedbox\strutht
+ \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!line
+ {}
+ {\setbox\framebox\hbox{\lower.5\ht\framebox\box\framebox}%
+ \ht\framebox.5\lineheight
+ \dp\framebox.5\lineheight
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!low
+ {}
+ {\doprelocframedbox\strutdp
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \box\framebox}
+
+\installframedlocator \v!top
+ {}
+ {\doprelocframedbox\strutht
+ \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
+ \ht\framebox\scratchdimen
+ \dp\framebox\scratchskip
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!middle
+ {}
+ {\scratchdimen.5\ht\framebox
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\scratchdimen
+ \dp\framebox\scratchdimen
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!lohi
+ {\handleframedlocator\c!before\v!middle}
+ {\handleframedlocator\c!after \v!middle}
+
+\installframedlocator \v!bottom
+ {}
+ {\doprelocframedbox\strutdp
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\scratchskip
+ \dp\framebox\scratchdimen
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!keep % retains height/depth
+ {\removeframedboxdepth}
+ {\restoreframedboxdepth}
+
+% also used in fastlocalframed
+
+\newdimen\originalframedwd
+\newdimen\originalframedht
+\newdimen\originalframeddp
+
+\def\removeframedboxdepth
+ {\originalframedwd\wd\framebox
+ \originalframedht\ht\framebox
+ \originalframeddp\dp\framebox
+ \ifzeropt\originalframeddp\else\setbox\framebox\hbox{\raise\originalframeddp\box\framebox}\fi
+ \wd\framebox\originalframedwd
+ \ht\framebox\dimexpr\originalframedht+\originalframeddp\relax
+ \dp\framebox\zeropoint}
+
+\def\restoreframedboxdepth
+ {\ifzeropt\originalframeddp\else\setbox\framebox\hbox{\lower\originalframeddp\box\framebox}\fi
+ \wd\framebox\originalframedwd
+ \ht\framebox\originalframedht
+ \dp\framebox\originalframeddp}
+
+% \let\@@startframedorientation\relax
+% \let\@@stopframedorientation \relax
+
+% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
+
+\def\@@startframedorientation
+ {\let\@@stopframedorientation \relax
+ \ifx\@@localorientation\empty\else
+ \ifcase\@@localorientation\else
+ \scratchcounter\@@localorientation
+ \divide\scratchcounter\plustwo
+ \ifodd\scratchcounter
+ \swapmacros\framedwidth \framedheight
+ \swapmacros\localwidth \localheight
+ \swapdimens\!!framedheight\!!framedwidth
+ \def\@@stopframedorientation{\@@dostopframedorientation\plusone}%
+ \else
+ \def\@@stopframedorientation{\@@dostopframedorientation\zerocount}%
+ \fi
+ \fi
+ \fi}
+
+\def\@@dostopframedorientation#1%
+ {\ifcase#1\else
+ \swapmacros\framedwidth \framedheight
+ \swapmacros\localwidth \localheight
+ \swapdimens\!!framedheight\!!framedwidth
+ \fi
+ \setbox\framebox\hbox{\dorotatebox\@@localorientation\hbox{\box\framebox}}}
+
+%D The last conditional takes care of the special situation of
+%D in||line \inframed[height=3cm]{framed} boxes. Such boxes have
+%D to be \inframed{aligned} with the running text.
+
+\def\doinframed[#1]% we could omit #1] but readibility ...
+ {\framed[\c!location=\v!low,#1]}
+
+\unexpanded\def\inframed
+ {\dosingleempty\doinframed}
+
+%D When we set \type{empty} to \type{yes}, we get
+%D ourselves a frame and/or background, but no content, so
+%D actually we have a sort of phantom framed box.
+
+%D Because color marks and specials can interfere with
+%D spacing, we provide a way to specify a foregroundcolor.
+
+\def\docolorframebox
+ {\doifvaluesomething{\@@framed\c!foregroundcolor}
+ {\doifcolorelse{\framedparameter\c!foregroundcolor}
+ {\setbox\framebox\hbox
+ {\localcolortrue
+ \color[\framedparameter\c!foregroundcolor]{\box\framebox}}}
+ {}}}
+
+%D \macros
+%D {mframed, minframed}
+%D
+%D When Tobias asked how to frame mathematical elements in
+%D formulas, Taco's posted the next macro:
+%D
+%D \starttyping
+%D \def\mframed#1%
+%D {\relax
+%D \ifmmode
+%D \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}%
+%D \else
+%D \framed{$#1$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Because \type {\ifinner} does not (always) reports what
+%D one would expect, we move the test to the outer level. We
+%D also want to pass arguments,
+%D
+%D \starttyping
+%D \def\mframed%
+%D {\dosingleempty\domframed}
+%D
+%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ?
+%D {\relax
+%D \ifmmode
+%D \ifinner
+%D \inframed[#1]{$#2$}%
+%D \else
+%D \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}%
+%D \fi
+%D \else
+%D \inframed[#1]{$#2$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Still better is the next alternative, if only because it
+%D takes care of setting the super- and subscripts styles
+
+\ifx\restoremathstyle\undefined \let\restoremathstyle\relax \fi
+
+\def\domframed[#1][#2]#3%
+ {\begingroup
+ \ifmmode
+ \ifinner
+ \let\mframedstyle\restoremathstyle
+ \else
+ \let\mframedstyle\displaystyle
+ \fi
+ \else
+ \let\mframedstyle\restoremathstyle
+ \fi
+ #1\ifdone
+ \def\normalstrut{$\mframedstyle\vphantom($}%
+ \framed
+ [\c!frameoffset=\@@oioffset,\c!offset=\v!overlay,#2]
+ {$\mframedstyle#3$}%
+ \else
+ \inframed
+ [#2]
+ {$\mframedstyle#3$}%
+ \fi
+ \endgroup}
+
+\def\mframed
+ {\dodoubleempty\domframed[\donetrue]}
+
+\def\inmframed
+ {\dodoubleempty\domframed[\donefalse]}
+
+%D So instead of the rather versatile \type {\framed}, we ue
+%D the \type {\mframed}.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{z_z}
+%D x \times \inmframed{y} \times y^{z_z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D However, we got into troubles when we want to nest sub- and
+%D superscripts, like in
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Therefore, we can best use \type {\super} and \type {\suber}
+%D instead of \type {^} and \type {_}. Both commands take care
+%D of proper font switching.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y\super{\mframed{z}\suber{\mframed{z}}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D As usual, one can specify in what way the text should be
+%D framed. One should be aware of the fact that, inorder to
+%D preserve the proper spacing, the \type {offset} is set to
+%D \type {overlay} and \type {frameoffset} is used used
+%D instead.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times y\super{\mframed[framecolor=red]{z}\suber{z}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D For inline use, we also provide the \type {\inmframed}
+%D alternative: we want $x \times \inmframed{y}$ in inline
+%D math, right?
+
+%D This previous framing macros needs a lot of alternatives for
+%D putting rules around boxes, inserting offsets and aligning
+%D text. Each step is handled by separate macros.
+
+\def\dowidenframebox#1%
+ {\setbox\framebox\vbox
+ {\kern#1\hbox{\kern#1\box\framebox\kern#1}\kern#1}}
+
+\def\dooffsetframebox{\dowidenframebox\localoffset}
+\def\dolocateframebox{\dowidenframebox\ruledlinewidth}
+
+%D Let's hope that the next few examples show us enough of
+%D what needs to be done by the auxiliary macros.
+%D
+%D \startbuffer
+%D \framed[height=1cm,offset=.5cm] {rule based learning}
+%D \framed[height=1cm,offset=0cm] {rule based learning}
+%D \framed[height=1cm,offset=none] {rule based learning}
+%D \framed[height=1cm,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[offset=.5cm] {rule based learning}
+%D \framed[offset=0cm] {rule based learning}
+%D \framed[offset=none] {rule based learning}
+%D \framed[offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[strut=nee,offset=.5cm] {rule based learning}
+%D \framed[strut=nee,offset=0cm] {rule based learning}
+%D \framed[strut=nee,offset=none] {rule based learning}
+%D \framed[strut=nee,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[width=3cm,align=left] {rule\\based\\learning}
+%D \framed[width=3cm,align=middle] {rule\\based\\learning}
+%D \framed[width=3cm,align=right] {rule\\based\\learning}
+%D \framed[width=fit,align=middle] {rule\\based\\learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\dontcomplain\getbuffer}
+%D \stoplinecorrection
+%D
+%D So now we're ready for the complicated stuff. We distinguish
+%D between borders with straight lines and those with round
+%D corners. When using the first alternative it is possible to
+%D turn off one or more lines. More fancy shapes are also
+%D possible by specifying dedicated backgrounds. Turning lines
+%D on and off is implemented as efficient as possible and as a
+%D result is interface language dependant. This next
+%D implementation evolved from simpler ones. It puts for
+%D instance the rules on top of the content and provides
+%D additional offset capabilities. The lot of calls to other
+%D macros makes this mechanism not that easy to comprehend.
+
+%D Getting the backgrounds right takes less code. Again we
+%D have to take care of additional offsets.
+
+\def\dobackedbox
+ {\doifelsevalue{\@@framed\c!backgroundoffset}\v!frame % new
+ {\dobackgroundbox\c!frameoffset}
+ {\dobackgroundbox\c!backgroundoffset}}
+
+%D We handle left, right or middle alignment as well as fixed
+%D or free widths and heights. Each combination gets its own
+%D macro.
+
+%D The following code handles one-liners: \type{align={line,flushright}}.
+%D Beware, since we entered a group and either or not grab the next
+%D bgroup token, we need to finish the group in the oneliner mode.
+
+\ifx\raggedoneliner\undefined \chardef\raggedoneliner\zerocount \fi
+
+\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
+ {\ifcase\raggedoneliner
+ \expandafter\nodoformatonelinerbox
+ \else
+ \expandafter\dodoformatonelinerbox
+ \fi}
+
+\def\dodoformatonelinerbox
+ {\dowithnextboxcontent
+ {\ignorespaces}
+ {\hbox to \hsize
+ {\ifcase\raggedstatus\or\hss\or\hss\fi
+ \unhbox\nextbox \removeunwantedspaces
+ \ifcase\raggedstatus\or \or\hss\or\hss\fi}%
+ \egroup}
+ \hbox}
+
+\def\nodoformatonelinerbox % grabs {
+ {\let\next=}
+
+%D The handlers:
+
+\def\doformatboxSomeFormat
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \vsize\!!framedheight
+ \doframedsetups
+ \raggedcommand
+ \dobeforeframedbox
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\doafterframedbox
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxNoFormat
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \vsize\!!framedheight
+ \doframedsetups
+ \raggedcenter
+ \vss
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxHeight
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \doframedsetups
+ \raggedcommand
+ \vss
+ \bgroup
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \localbegstrut
+ \doformatonelinerbox}
+
+\def\doformatboxWidth
+ {\vbox
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \doframedsetups
+ \raggedcommand
+ \dobeforeframedbox
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\doafterframedbox
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxVSize
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \vsize\!!framedheight
+ \doframedsetups
+ \vss
+ \bgroup
+ \aftergroup\vss
+ \aftergroup\egroup
+ \hbox
+ \bgroup
+ \aftergroup\egroup
+ \localstrut
+ \doformatonelinerbox}
+
+\def\doformatboxHSize
+ {\hbox to \!!framedwidth
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \doframedsetups
+ \hss
+ \localstrut
+ \bgroup
+ \aftergroup\hss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxNoSize
+ {\hbox
+ \bgroup
+ \let\postprocessframebox\relax
+ \doframedsetups
+ \localstrut
+ \doformatonelinerbox}
+
+\let\doframedsetups\relax
+
+%D On the next page we show some examples of how these macros
+%D come into action. The examples show us how
+%D \type {fit}, \type {broad} dimensions influence the
+%D formatting. Watch the visualized struts. \footnote {Here we
+%D used \type {\showstruts}.}
+%D
+%D \startpostponing
+%D \bgroup
+%D \showstruts
+%D \dontcomplain
+%D \startlinecorrection
+%D \halign{#\enskip&#\enskip&#\enskip&#\enskip&#\enskip&#\cr
+%D \framed[width=.2\hsize, height=.2\hsize, align=] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=yes] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=yes] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=yes] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=right] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=right] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=right] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=left] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=left] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=left] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=middle] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=middle] {a\par b\par c}\cr}
+%D \stoplinecorrection
+%D \blank[2*big]
+%D \egroup
+%D \stoppostponing
+
+%D \macros
+%D {framednoflines, framedlastlength}
+%D
+%D It is possible to let the frame macro calculate the width
+%D of a centered box automatically (\type {fit}). When
+%D doing so, we need to reshape the box:
+
% The next implementation is frozen! It preserves the depth,
% otherwise we get problems with framed display math and auto
% width.
+\newcount\framednoflines
+\newdimen\framedlastlength
+
+\def\resetshapeframebox
+ {\framednoflines \zerocount
+ \framedlastlength\zeropoint}
+
+\chardef\reshapeframeboxmethod\plusone % 0=no flush, 1=old method 2=no depth messing
+
\def\shapeboxstrut % put this in front if needed !
{\vrule\!!width\zeropoint\!!height\ht\shapebox\!!depth\dp\shapebox}
@@ -72,4 +1924,1714 @@
\fi
\fi}
+%D The two variables \type {\framednoflines} and \type
+%D {\framedlastlength} can be used in a second pass to
+%D optimized framed material.
+
+% torture test / strange case (much depth) / method 2 needed
+%
+% \startTEXpage[frame=on]
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% \blank[big]
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% \stopTEXpage
+
+%D The examples on the next page show how one can give the
+%D frame as well as the background an additional offset and
+%D even a bit more depth. The blue outline is the frame, the
+%D red box is the background and the small black outline is the
+%D visualization of the resulting box, that is, we applied
+%D \type{\ruledhbox} to the result.
+
+%D \startpostponing
+%D \bgroup
+%D \unprotect
+%D \dontcomplain
+%D
+%D \startbuffer
+%D \vbox to \vsize
+%D \bgroup
+%D \startalignment[middle]
+%D \vss
+%D \dontleavehmode\vbox to .8\vsize
+%D \bgroup
+%D \hsize=300pt
+%D \setupframed
+%D [background=color,
+%D backgroundcolorachtergrondkleur=darkred,
+%D width=300pt,
+%D height=60pt,
+%D framecolorkaderkleur=DemoBlue,
+%D rulethickness=2pt]
+%D \def\status%
+%D {backgroundoffset=\framedparameter\c!backgroundoffset\\
+%D frameoffset=\framedparameter\c!frameoffset\\
+%D depth=\framedparameter\c!depth}
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
+%D \egroup
+%D \vss
+%D \stopalignment
+%D \egroup
+%D \stopbuffer
+%D
+%D \getbuffer \page
+%D
+%D {\setupframed[depth=4pt]\getbuffer} \page
+%D
+%D \protect
+%D \egroup
+%D \stoppostponing
+
+%D When typesetting the framed box inline, we have to keep the
+%D baseline intact outside as well as inside the framed box.
+
+\def\doinlineframedbox
+ {\scratchdimen\dimexpr\strutdp+\ruledlinewidth\relax
+ \ifboxhasoffset
+ \advance\scratchdimen \framedparameter\c!offset
+ \fi
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \box\framebox}
+
+%D We can also lower the box over the natural depth of the
+%D line.
+
+\def\doloweredframedbox
+ {\ht\framebox\dimexpr\ht\framebox+\dp\framebox-\strutdp\relax
+ \dp\framebox\strutdp
+ \box\framebox}
+
+%D Hanging the content is mainly meant for cases like the
+%D following:
+%D
+%D \starttyping
+%D \framed[strut=no]
+%D {\framed[height=2cm,location=hanging]{test}%
+%D \framed[height=1cm,location=hanging]{test}}
+%D \stoptyping
+
+\def\dohangingframedbox % best with strut=no
+ {\scratchdimen\dimexpr\ht\framebox+\dp\framebox\relax
+ \ht\framebox\zeropoint
+ \dp\framebox\scratchdimen}
+
+%D We can draw lines from left to right and top to bottom by
+%D using the normal \type{\hairline} command. Both directions
+%D need a different treatment.
+%D
+%D \startbuffer
+%D \framed[width=4cm] {alfa\hairline beta\hairline gamma}
+%D \framed[height=2cm] {alfa\hairline beta\hairline gamma}
+%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D These macros try to adapt their behaviour as good as
+%D possible to the circumstances and act as natural as
+%D possible.
+
+\def\vboxedhairline
+ {\bgroup
+ \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
+ \dimen4=\dimexpr\dimen2+\ruledlinewidth\relax
+ \setbox0\vbox
+ {\advance\hsize 2\dimen4
+ \vskip\dimen2
+ \hrule
+ \!!height\ruledlinewidth
+ \!!depth\zeropoint
+ \!!width\hsize
+ \vskip\dimen2}%
+ %\endgraf\nointerlineskip\endgraf
+ %\moveleft\dimen4\box0
+ %\endgraf\nointerlineskip\localbegstrut
+ \endgraf\obeydepth\nointerlineskip
+ \moveleft\dimen4\box0
+ \endgraf\nointerlineskip\localbegstrut % beware, we might kill it in a style using \vskip\lineheight
+ \egroup} % so this must not be changed
+
+\def\hboxedhairline % use framed dimen
+ {\bgroup
+ \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
+ \ifboxhasheight
+ \dimen4\dimexpr\localheight/2+\strutdp-2\ruledlinewidth\relax
+ \dimen6\dimexpr\localheight/2-\strutdp+2\ruledlinewidth\relax
+ \else
+ \dimen4\dimexpr\strutht+\dimen2\relax
+ \dimen6\dimexpr\strutdp+\dimen2\relax
+ \fi
+ \unskip
+ \setbox\scratchbox\hbox
+ {\hskip\dimen2
+ \vrule\!!height\dimen4\!!depth\dimen6\!!width\ruledlinewidth
+ \hskip\dimen2}%
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \box\scratchbox
+ \ignorespaces
+ \egroup}
+
+%D The argument of the frame command accepts \type{\\} as a
+%D sort of newline signal. In horizontal boxes it expands to a
+%D space.
+
+\def\vboxednewline
+ {\endgraf\ignorespaces}
+
+\def\hboxednewline
+ {\unskip\normalspace\ignorespaces}
+
+%D We can set each rule on or off. The default setting is
+%D inherited from \type{frame}. An earlier implementation
+%D use a bit different approach, but the new one seems more
+%D natural:
+%D
+%D \bgroup
+%D \setuptyping[margin=0pt]
+%D \startlinecorrection
+%D \startbuffer
+%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D \stoplinecorrection
+%D \egroup
+
+%D \macros
+%D {setupblackrules}
+%D
+%D The graphic capabilities of \TEX\ do not go beyond simple
+%D filled rules, except of course when using specials. Let's
+%D start with a warning: using this commands is far more slower
+%D than using the \TEX\ primitives \type{\hrule} and
+%D \type{\vrule}, but they save us some tokens. The
+%D characteristics of these rule drawing command can be set by:
+%D
+%D \showsetup{setupblackrules}
+
+\def\setupblackrules
+ {\dodoubleargument\getparameters[\??bj]}
+
+%D \macros
+%D {blackrule}
+%D
+%D The simple command draws only one rule. Its optional
+%D argument can be used to specify the dimensions. By setting
+%D the width, height or depth to \type {max}, one gets the
+%D natural dimensions.
+%D
+%D \showsetup{blackrule}
+
+\def\doblackrule[#1]%
+ {\hbox\bgroup
+ \getparameters[\??bj][#1]%
+ \setstrut
+ \doif\@@bjwidth \v!max{\def\@@bjwidth {1em}}%
+ \doif\@@bjheight\v!max{\def\@@bjheight{\strutht}}%
+ \doif\@@bjdepth \v!max{\def\@@bjdepth {\strutdp}}%
+ \localstartcolor[\@@bjcolor]%
+ \vrule
+ \!!width \@@bjwidth
+ \!!height\@@bjheight
+ \!!depth \@@bjdepth
+ \localstopcolor
+ \egroup}
+
+\unexpanded\def\blackrule
+ {\dosingleempty\doblackrule}
+
+%D \macros
+%D {blackrules}
+%D
+%D One can call for a sequence of black rules, if needed
+%D equally spaced over the given width.
+%D
+%D \showsetup{blackrules}
+%D
+%D The two alternative calls are therefore:
+%D
+%D \startbuffer
+%D Tell me, is this according to the \blackrules[n=6]?
+%D These \blackrules[alternativevariant=b,n=10,distance=.2em,width=4cm] are quite clear.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D We could of course have implemented this macro using
+%D \type{\leaders}, but this would probably have taken more
+%D tokens.
+
+\def\doblackrules[#1]%
+ {\hbox\bgroup
+ \getparameters[\??bj][#1]%
+ \!!widtha\@@bjwidth
+ \!!widthb\@@bjdistance
+ \doif\@@bjalternative\c!b
+ {\scratchcounter\@@bjn
+ \ifnum\scratchcounter=\plusone
+ \!!widthb\zeropoint
+ \else
+ \advance\scratchcounter \minusone
+ \advance\!!widtha -\scratchcounter\!!widthb
+ \divide \!!widtha \@@bjn
+ \fi}%
+ \localstartcolor[\@@bjcolor]%
+ \dorecurse\@@bjn
+ {\vrule
+ \!!width \!!widtha
+ \!!height\@@bjheight
+ \!!depth \@@bjdepth
+ \hskip\!!widthb}%
+ \unskip
+ \localstopcolor
+ \egroup}
+
+\unexpanded\def\blackrules
+ {\dosingleempty\doblackrules}
+
+%D The next commands can be used to draw margin rules. We
+%D support two methods: \marginrule{one for in||line use} and
+%D one that acts on a paragraph. Drawing a margin rule is
+%D rather straightforward because we can use the commands that
+%D put text in the margin.
+
+\def\dodrawmarginrule
+ {\setbox\scratchbox\hbox
+ {\vrule\!!depth\strutdepth\!!height\strutheight\!!width\@@karulethickness}%
+ \smashbox\scratchbox % no \vsmash !!!
+ \box\scratchbox}
+
+\def\drawmarginrule
+ {\strut\inleft{\dodrawmarginrule}}
+
+%D \macros
+%D {marginrule}
+%D
+%D The first method gobbles words and simply puts a bar in the
+%D margin. This method is not entirely robust.
+%D
+%D \showsetup{marginrule}
+
+\definecomplexorsimple\marginrule
+
+\def\simplemarginrule
+ {\let\processword\drawmarginrule
+ \processwords}
+
+\def\complexmarginrule[#1]%
+ {\ifnum#1<\@@kalevel\relax \else
+ \def\@@kadefaultwidth{#1}%
+ \expandafter\simplemarginrule
+ \fi}
+
+%D We need an auxiliary variable
+
+\def\@@kadefaultwidth{1}
+
+%D \macros
+%D {setupmarginrules}
+%D
+%D This macro definitions show us that we can pass an optional
+%D level, which is matched against the previous set one. The
+%D level can be set up with
+%D
+%D \showsetup{setupmarginrules}
+
+\def\setupmarginrules
+ {\dodoubleargument\getparameters[\??ka]}
+
+%D \macros
+%D {startmarginrule}
+%D
+%D The second method collects text and reformats it afterwards,
+%D using the shapebox macros. We prevent local margin rules.
+%D
+%D \showsetup{startmarginrule}
+
+\definecomplexorsimple\startmarginrule
+
+\def\simplestartmarginrule
+ {\bgroup
+ \let\drawmarginrule\relax
+ \let\stopmarginrule\dostopmarginrule
+ \beginofshapebox}
+
+\def\complexstartmarginrule[#1]%
+ {\bgroup
+ \let\drawmarginrule\relax
+ \ifnum#1<\@@kalevel\relax
+ \let\stopmarginrule\egroup
+ \else
+ \def\@@kadefaultwidth{#1}%
+ \let\stopmarginrule\dostopmarginrule
+ \expandafter\beginofshapebox
+ \fi}
+
+\def\dostopmarginrule
+ {\endofshapebox
+ \reshapebox
+ {\hbox{\inleftmargin{\dodrawmarginrule}\box\shapebox}}%
+ \flushshapebox
+ \egroup}
+
+%D \startbuffer
+%D \setupmarginrules[level=5]
+%D
+%D \startmarginrule[1]
+%D First we set the level at~5. Next we typeset this first
+%D paragraph as a level~1 one. As expected no rule show up.
+%D \stopmarginrule
+%D
+%D \startmarginrule[5]
+%D The second paragraph is a level~5 one. As we can see here,
+%D the marginal rule gets a width according to its level.
+%D \stopmarginrule
+%D
+%D \startmarginrule[8]
+%D It will of course be no surprise that this third paragraph
+%D has a even thicker margin rule. This behavior can be
+%D overruled by specifying the width explictly.
+%D \stopmarginrule
+%D \stopbuffer
+%D
+%D In next example we show most features. Watch the rule
+%D thickness adapting itself to the level.
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D We just said:
+%D
+%D \typebuffer
+
+%D \macros
+%D {vl, hl}
+%D
+%D The command \type{\vl} draws a vertical rule \vl\ with strut
+%D dimensions, multiplied with the factor specified in the
+%D optional argument. The height and depth are clipped \vl[3]
+%D to the baselinedistance. Its horizontal counterpart
+%D \type{\hl} draws a horizontal rule \hl\ with a width of 1em,
+%D multiplied with the optional factor. The horizontal rule is
+%D drawn on top of the baseline.
+%D
+%D \showsetup{vl}
+%D \showsetup{hl}
+
+\def\complexvl[#1]%
+ {\bgroup
+ \!!dimena#1\strutht
+ \!!dimenb#1\strutdp
+ \setbox\scratchbox\hbox
+ {\vrule
+ \!!width \linewidth
+ \!!height\!!dimena
+ \!!depth \!!dimenb}%
+ \dp\scratchbox\strutdp
+ \ht\scratchbox\strutht
+ \box\scratchbox
+ \egroup}
+
+\def\complexhl[#1]%
+ {\hbox
+ {\vrule
+ \!!width #1\s!em
+ \!!height\linewidth
+ \!!depth \zeropoint}}
+
+\definecomplexorsimple\vl \def\simplevl{\complexvl[1]}
+\definecomplexorsimple\hl \def\simplehl{\complexhl[1]}
+
+%D \macros
+%D {hairline, thinrule, thinrules, setupthinrules}
+%D
+%D Drawing thin lines can of course easily be accomplished by
+%D the \TEX\ primitives \type{\hrule} and \type{\vrule}. The
+%D next few macros however free us from some specifications.
+%D
+%D \startbuffer
+%D some text
+%D
+%D \hairline
+%D
+%D some more text
+%D
+%D \thinrule
+%D
+%D more and more text
+%D
+%D hi \thinrule\ there
+%D
+%D and then the final text
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D becomes
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D So we've got
+%D
+%D \showsetup{hairline}
+%D \showsetup{thinrule}
+%D
+%D Both can be set up with:
+%D
+%D \showsetup{setupthinrules}
+%D
+%D We also have
+%D
+%D \showsetup{thinrules}
+%D
+%D which looks like: \thinrules[n=2]
+
+\def\thinrule
+ {\strut
+ \bgroup
+ \chardef\ruletype\plusone
+ \processaction
+ [\@@dlalternative]
+ [ \v!a=>\chardef\ruletype0,% no line
+ %\v!b=>\chardef\ruletype1,% height/depth
+ \v!c=>\chardef\ruletype2,% topheight/botdepth
+ % 11=>\chardef\ruletype1,% fallback for backgrounds
+ 0=>\chardef\ruletype0,% compatible with backgrounds
+ % 1=>\chardef\ruletype1,% compatible with backgrounds
+ 2=>\chardef\ruletype2]% compatible with backgrounds
+ \doifsomething\@@dlrulethickness
+ {\linewidth\@@dlrulethickness}%
+ \ifdim\linewidth=\zeropoint
+ \chardef\ruletype\zerocount
+ \else
+ \doifnot\@@dlframe\v!on{\chardef\ruletype\zerocount}%
+ \fi
+ \ifnum\ruletype=\plusone
+ \doif\@@dlheight\v!max{\let\@@dlheight\!!plusone}%
+ \doif\@@dldepth \v!max{\let\@@dldepth \!!plusone}%
+ \else
+ \let\@@dlheight\!!plusone
+ \let\@@dldepth\!!plusone
+ \fi
+ \freezedimensionwithunit\@@dlheight\strutht
+ \freezedimensionwithunit\@@dldepth\strutdp
+ \divide\linewidth \plustwo
+ \doifelse\@@dlbackground\v!color
+ {\startcolor[\@@dlbackgroundcolor]%
+ \ifnum\ruletype=\plustwo % prevent overshoot due to rounding
+ \leaders
+ \hrule
+ \!!height\dimexpr\@@dlheight-.5\linewidth\relax
+ \!!depth \dimexpr\@@dldepth -.5\linewidth\relax
+ \hfill
+ \else
+ \leaders
+ \hrule
+ \!!height\@@dlheight
+ \!!depth \@@dldepth
+ \hfill
+ \fi
+ \stopcolor
+ \ifcase\ruletype
+ % no rule
+ \or
+ \startcolor[\@@dlcolor]%
+ \hfillneg
+ \leaders\hrule\!!height\linewidth\!!depth\linewidth\hfill
+ \stopcolor
+ \or
+ \startcolor[\@@dlcolor]%
+ \hfillneg\leaders\hrule\!!height\dimexpr-\@@dldepth+\linewidth\relax\!!depth\@@dldepth\hfill
+ \hfillneg\leaders\hrule\!!height\@@dlheight\!!depth\dimexpr-\@@dlheight+\linewidth\relax\hfill
+ \stopcolor
+ \fi}
+ {\ifcase\ruletype \else
+ \startcolor[\@@dlcolor]%
+ \leaders\hrule\!!height\@@dlheight\!!depth\@@dldepth\hfill
+ \stopcolor
+ \fi}%
+ \strut
+ \carryoverpar\egroup}
+
+\def\hairline
+ {\endgraf
+ \thinrule
+ \endgraf}
+
+\def\dosetupthinrules[#1]%
+ {\getparameters[\??dl][#1]}
+
+\def\setupthinrules
+ {\dosingleargument\dosetupthinrules}
+
+\def\dothinrules[#1]%
+ {\bgroup
+ \dosetupthinrules[#1]%
+ \@@dlbefore
+ \assignvalue\@@dlinterlinespace\@@dlinterlinespace{1.0}{1.5}{2.0}%
+ \spacing\@@dlinterlinespace
+ \dorecurse\@@dln
+ {\ifnum\recurselevel=\@@dln \dothinrulesnobreak \else
+ \ifnum\recurselevel=2 \dothinrulesnobreak \fi\fi
+ \thinrule
+ \ifnum\recurselevel<\@@dln\relax
+ % test needed, else messed up whitespace
+ \ifx\@@dlinbetween\empty
+ \softbreak
+ \else
+ \endgraf
+ \nowhitespace
+ \@@dlinbetween
+ \fi
+ \fi}%
+ \doifelsenothing\@@dlafter
+ {\carryoverpar\egroup}
+ {\@@dlafter\egroup}}
+
+\def\thinrules
+ {\dosingleempty\dothinrules}
+
+%D A couple of examples are given below.
+%D
+%D \startbuffer
+%D \setupthinrules[n=3,inbetween=,color=gray]
+%D
+%D test test \thinrules\ test test \par
+%D test test \thinrules [color=green] test test \par
+%D test test \thinrules [height=max, depth=max] test test \par
+%D
+%D \setupthinrules[height=.9,depth=.9]
+%D
+%D test test \thinrules\ test test \par
+%D test test \thinrules [alternativevariant=b] test test \par
+%D test test \thinrules [alternativevariant=c] test test \par
+%D test test \thinrules [alternativevariant=c,inbetween=\vskip2ex] test test \par
+%D \stopbuffer
+%D
+%D \typebuffer {\getbuffer}
+%D
+%D There are a couple of alternative ways to visualize rules
+%D using backgrounds. At first sight these may look strange,
+%D but they make sense in educational settings. The
+%D alternatives are more or less compatible with the more
+%D advanced \METAPOST\ based implementation.
+%D
+%D \startbuffer[a]
+%D \setupthinrules
+%D [n=2,
+%D backgroundcolor=gray ,
+%D rulethickness=1pt,
+%D colorkleur=donkerblauw,
+%D after=\blank,
+%D before=\blank]
+%D \stopbuffer
+%D
+%D \typebuffer[a]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a]
+%D \thinrules[alternativevariant=b]
+%D \thinrules[alternativevariant=c]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a,background=color]
+%D \thinrules[alternativevariant=b,background=color]
+%D \thinrules[alternativevariant=c,background=color]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a,height=.8,depth=.8,background=color]
+%D \thinrules[alternativevariant=b,height=.8,depth=.8,background=color]
+%D \thinrules[alternativevariant=c,height=.8,depth=.8,background=color]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+
+%D \macros
+%D {optimizethinrules}
+%D
+%D By saying \type {\thinrulestrue} or \type {-false}, we
+%D can influence the way dangling lines are handled.
+
+\newif\ifoptimizethinrules \optimizethinrulestrue
+
+\def\dothinrulesnobreak
+ {\ifoptimizethinrules\penalty500\fi}
+
+%D \macros
+%D {startframedtext, setupframedtexts, defineframedtext}
+%D
+%D The general framing command we discussed previously, is not
+%D entirely suited for what we call framed texts, as for
+%D instance used in intermezzo's. The next examples show what
+%D we have in mind.
+%D
+%D \startbuffer[framed-0]
+%D \setupframedtexts
+%D [frame=off,
+%D width=\hsize,
+%D background=screen]
+%D
+%D \startframedtext
+%D By default the framed text is centered \dots
+%D \stopframedtext
+%D
+%D \startframedtext[right]
+%D \dots\ but we can also align left, middle and right.
+%D \stopframedtext
+%D \stopbuffer
+%D
+%D \startbuffer[framed-1]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm,
+%D height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-1]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-2]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm]
+%D
+%D \startExample
+%D \typebuffer[framed-2]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-3]
+%D \defineframedtext
+%D [Example]
+%D [height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-3]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-4]
+%D \defineframedtext
+%D [Example]
+%D [width=fit,height=broad]
+%D
+%D \Example{a very exciting example}
+%D \stopbuffer
+%D
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
+%D
+%D Here we can see that we have a predefined framed text class
+%D as well as the tools for defining our own. So we have:
+%D
+%D \showsetup{setupframedtexts}
+%D
+%D as well as the definition command:
+%D
+%D \showsetup{defineframedtext}
+%D
+%D that generates two commands:
+%D
+%D \showsetup{start<<framedtext>>}
+%D \showsetup{<<framedtext>>}
+%D
+%D The next definition shows the defaults.
+
+\def\dodefineframedtext[#1][#2]%
+ {\presetlocalframed[\??kd#1]%
+ \getparameters[\??kd#1]
+ [\c!width=0.75\hsize,
+ \c!height=\v!fit,
+ \c!align=\v!yes,
+ \c!top=,
+ \c!bottom=\vfill,
+ \c!offset=1em,
+ \c!bodyfont=,
+ \c!style=,
+ \c!color=,
+ \c!left=,
+ \c!right=\hfill,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!inner=,
+ \c!frame=\v!on,
+ \c!topframe=,
+ \c!bottomframe=,
+ \c!leftframe=,
+ \c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!foregroundcolor=,
+ \c!foregroundstyle=,
+ \c!background=,
+ \c!backgroundcolor=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!linecorrection=\v!on,
+ \c!depthcorrection=\v!on,
+ \c!margin=\v!standard,
+ \c!orientation=,
+ \c!indenting=,
+ #2]%
+ \setvalue{\e!start#1}{\dostartframedtext[#1]}%
+ \setvalue{\e!stop #1}{\dostopframedtext }%
+ \setvalue {#1}{\doframedtext [#1]}}
+
+\def\defineframedtext
+ {\dodoubleempty\dodefineframedtext}
+
+%D We define the general (and original) case by just saying:
+
+\defineframedtext[\v!framedtext]
+
+%D We need several steps before the actual job is done,
+%D because we have to handle an optional identifier (and
+%D because these commands evolved out of a single case).
+
+\def\framedtextparameter#1#2%
+ {\csname\??kd#1#2\endcsname}
+
+\def\dosetupframedtexts[#1][#2]%
+ {\ifsecondargument
+ \def\docommand##1{\getparameters[\??kd##1][#2]}%
+ \processcommacommand[#1]\docommand % new, #1 may be macro
+ \else
+ \getparameters[\??kd\v!framedtext][#1]%
+ \fi}
+
+\def\setupframedtexts
+ {\dodoubleempty\dosetupframedtexts}
+
+\def\dostartframedtext
+ {\bgroup\dotripleempty\dodostartframedtext}
+
+\def\dodostartframedtext[#1][#2][#3]%
+ {\doifassignmentelse{#2}
+ {\dododostartframedtext[#1][][#2]}
+ {\dododostartframedtext[#1][#2][#3]}}
+
+\setfalse\framedtextlocationnone
+
+\def\dododostartframedtext[#1][#2][#3]% #3 only passed to framed, not to framedtext
+ {\doifsomething{#2}{\setvalue{\??kd#1\c!location}{#2}}% does not listen to #3
+ \setfalse\framedtextlocationnone
+ \processaction % \v!low en \v!depth are already taken !
+ [\framedtextparameter{#1}\c!location]
+ [ \v!left=>\letvalue{\??kd#1\c!left }\relax
+ \letvalue{\??kd#1\c!right}\hfill,
+ \v!right=>\letvalue{\??kd#1\c!left }\hfill
+ \letvalue{\??kd#1\c!right}\relax,
+ \v!middle=>\letvalue{\??kd#1\c!left }\hfill
+ \letvalue{\??kd#1\c!right}\hfill,
+ \v!none=>\letvalue{\??kd#1\c!left }\relax % new
+ \letvalue{\??kd#1\c!right}\relax % new
+ \settrue\framedtextlocationnone]%
+ \letvalue{\??kd#1\c!location}\empty
+ % removed 06/2001
+ % \forgetparindent
+ % added 06/2001 [see demo-bbv]
+ \localhsize\hsize \checkframedtext
+ % so far
+ \setbox\framebox\vbox
+ \startboxedcontent
+ \hsize\localhsize
+ % \insidefloattrue % ? better
+ \expanded{\switchtobodyfont[\framedtextparameter{#1}\c!bodyfont]}%
+ \startcolor[\framedtextparameter{#1}\c!color]%
+ \localframed[\??kd#1][\c!strut=\v!no,#3]% todo: use delayedstrut
+ \bgroup
+ \let\\=\endgraf
+ \framedtextparameter{#1}\c!inner % oud spul
+ \doifvalue{\??kd#1\c!depthcorrection}\v!on % new, inside box
+ {\bgroup
+ \verticalstrut
+ % we need \nowhitespace in case of setups setting whitespace
+ % nb, not safe, text vs \vbox as next
+ \vskip-\struttotal
+ \nowhitespace % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})
+ }%
+ \doinhibitblank % \blank[\v!disable]% plaatst signal
+\setupindenting[\framedtextparameter{#1}\c!indenting]%
+ \doconvertfont{\framedtextparameter{#1}\c!style}\empty
+ \def\dostopframedtext{\dodostopframedtext{#1}{#2}}}
+
+%D The \type {none} option is handy for nested usage, as
+%D in the presentation styles, where we don't want
+%D interference.
+
+\def\dodostopframedtext#1#2% % no \baselinecorrection, see faq docs
+ {\endgraf
+ \removelastskip
+ \doifvalue{\??kd#1\c!depthcorrection}\v!on % local and global
+ {\forgetall
+ \vskip-\struttotal
+ \verticalstrut
+ \egroup
+ \forgetall
+ \vskip-\lineheight
+ % will be an option, not default
+ % \setbaselinecorrections
+ % \donegbotbaselinecorrection
+ \verticalstrut}
+ \stopboxedcontent
+ \stopcolor
+ \ifconditional\framedtextlocationnone
+ \egroup
+ \box\framebox
+ \else\ifinsidefloat
+ \egroup
+ \box\framebox
+ \else
+ \egroup
+ \doplacement[\??kd#1][\c!depthcorrection=\v!off]{\box\framebox}%
+ \fi\fi
+ \egroup}
+
+%D Placement can be ignored:
+%D
+%D \starttyping
+%D \hbox to \hsize \bgroup
+%D \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
+%D \startframedtext[none][width=.5\textwidth] \input zapf \stopframedtext
+%D \egroup
+%D
+%D \hbox to \hsize \bgroup
+%D \setupframedtexts[location=none]%
+%D \startframedtext[width=.5\textwidth] \input zapf \stopframedtext
+%D \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
+%D \egroup
+%D \stoptyping
+
+%D The simple brace (or group) delimited case is typeset
+%D slightly different and is not aligned.
+
+\def\doframedtext
+ {\bgroup\dodoubleempty\dodoframedtext}
+
+\def\dodoframedtext[#1][#2]% beware!
+ {\expanded{\switchtobodyfont[\getvalue{\??kd#1\c!bodyfont}]}%
+ \localframed[\??kd#1][\c!strut=\v!no,#2]%
+ \bgroup
+ \blank[\v!disable]%
+ \let\\=\endgraf
+ \getvalue{\??kd#1\c!inner}% % kleur naar outer level
+ \dostartattributes{\??kd#1}\c!style\c!color\empty
+ \bgroup
+ \aftergroup\docloseframedtext
+ \let\next=}
+
+\def\docloseframedtext
+ {\removelastskip
+ \dostopattributes
+ \egroup
+ \egroup}
+
+%D \macros
+%D {defineframed}
+%D
+%D One can also define simple framed texts, using:
+%D
+%D \showsetup{defineframed}
+
+\def\defineframed
+ {\dodoubleempty\dodefineframed}
+
+\def\dodefineframed[#1][#2]%
+ {\iffirstargument
+ \setvalue{#1}{\dodoubleempty\doframed[#2]}%
+ \fi}
+
+\def\doframed[#1][#2]%
+ {\framed[#1,#2]}
+
+%D \macros
+%D {textrule, starttextrule, setuptextrules}
+%D
+%D Putting rules before and after a paragraph is very space
+%D sensitive, but the next command handles that quite well. It
+%D comes in two disguises:
+%D
+%D \startbuffer
+%D \textrule[top]{fragments}
+%D \input reich
+%D \textrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D \startbuffer
+%D \setuptextrules
+%D [width=90pt,distance=12pt,rulecolor=blue,
+%D bodyfont=small,style=\sc,color=red]
+%D
+%D \starttextrule{Ship Building Tools}
+%D \nl \setuptolerance[tolerant] \input materie
+%D \stoptextrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D \startbuffer
+%D \setuptextrules
+%D [location=inmargin,
+%D bodyfont=small,style=slantedbold]
+%D
+%D \starttextrule{wonderful}
+%D \input tufte
+%D \stoptextrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D The formal definition of these commands is:
+%D
+%D \showsetup{textrule}
+%D \showsetup{starttextrule}
+%D \showsetup{setuptextrules}
+%D
+%D The implementation looks a bit complicated due to the
+%D optional arguments.
+
+\def\setuptextrules
+ {\dodoubleargument\getparameters[\??tl]}
+
+\def\complextextrule[#1]% if needed we can make it installable
+ {\let\next\dobottomtextrule
+ \processaction
+ [#1]
+ [ \v!top=>\let\next\dotoptextrule,
+ \v!middle=>\let\next\domiddletextrule,
+ \v!bottom=>\let\next\dobottomtextrule]%
+ \dosinglegroupempty\next}
+
+\definecomplexorsimple\textrule
+
+\def\simpletextrule
+ {\dosinglegroupempty\dounknowntextrule}
+
+\def\docomplextextrule#1%
+ {\bgroup
+ \advance\hsize\dimexpr-\rightskip-\leftskip\relax
+ \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
+ \color[\@@tlrulecolor]
+ {\leaders\hrule\!!height\dimen4\!!depth\dimen6\hfill}}%
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \noindent\box\scratchbox
+%\nobreak\verticalstrut\kern-\struttotal
+% evt \witruimte
+ \egroup}
+
+\def\dotoptextrule#1%
+ {\page[\v!preference] % interferes
+ %\whitespace % no
+ \@@tlbefore
+ \docomplextextrule{#1}%
+% todo, option: \doifnothing{#1}{\ruledvskip-.5ex}
+ \nowhitespace
+ \@@tlinbetween
+ \endgraf}
+
+\def\dodobottomtextrule#1#2%
+ {\ifhmode
+ \endgraf
+ \fi
+ \dimen0\strutdp
+ \ifdim\prevdepth>\strutdp\else % was <\strutdp
+ \ifdim\prevdepth>\zeropoint
+ \advance\dimen0 -\prevdepth
+ \fi
+ \fi
+ \advance\dimen0 .5ex
+ \vskip\dimen0
+% ==
+% \vskip\dimexpr \strutdp + .5ex
+% \ifdim\prevdepth>\strutdp\else\ifdim\prevdepth>\zeropoint-\prevdepth\fi\fi\relax
+%
+ \@@tlinbetween
+ \doifelsenothing{#2}
+ {\bgroup
+ \advance\hsize\dimexpr-\rightskip-\leftskip\relax
+ \nointerlineskip
+ \moveleft-\leftskip\vbox
+ {\color[\@@tlrulecolor]
+ {\hrule\!!depth\linewidth\!!height\zeropoint\!!width\hsize}}%
+ \egroup}
+ {\docomplextextrule{#2}}%
+ \ifvmode\prevdepth\zeropoint\fi
+ #1%
+ \page[\v!preference]}
+
+\def\dobottomtextrule
+ {\dodobottomtextrule\@@tlafter}
+
+\def\domiddletextrule
+ {\dodobottomtextrule\@@tlinbetween}
+
+\def\dounknowntextrule
+ {\iffirstargument
+ \@EA\dotoptextrule
+ \else
+ \@EA\dobottomtextrule\@EA\empty
+ \fi}
+
+%D The grouped commands also supports bodyfont switching:
+
+\def\starttextrule#1%
+ {\bgroup
+ \def\dounknowntextrule{\domiddletextrule}
+ \dotoptextrule{#1}
+ \bgroup
+ \doifsomething\@@tlbodyfont{\switchtobodyfont[\@@tlbodyfont]}}
+
+\def\stoptextrule
+ {\par
+ \egroup
+ \dobottomtextrule\empty
+ \egroup}
+
+%D \macros
+%D {fillinrules, setupfillinrules}
+%D
+%D The next few commands do not really deserve a place in a
+%D core module, because they deal with specific typography.
+%D Nevertheless I decided to make them part of the core,
+%D because they permit us to make questionaires. Let's start
+%D with some examples.
+%D
+%D \fillinrules[n=2,width=fit]{first}
+%D \fillinrules[n=2,width=broad]{first}
+%D \fillinrules[n=2,width=3cm]{first}
+%D \fillinrules[n=2,width=3cm,distance=.5em,separator=:]{first}
+%D \fillinrules[n=2]{first}{last}
+%D \fillintext{first}{last} \input reich \par
+%D
+%D The main command is \type{\fillinrules}. This command takes
+%D one and an optional second argument and sets a paragraph with
+%D empty visualized lines.
+%D
+%D \showsetup{fillinrules}
+%D \showsetup{setupfillinrules}
+
+\def\setupfillinrules
+ {\dodoubleargument\getparameters[\??il]}
+
+\definecomplexorsimpleempty\fillinrules
+
+\def\complexfillinrules[#1]%
+ {\def\docomplexfillinrules##1##2%
+ {\dodocomplexfillinrules[#1]{##1}{##2}{\thinrules
+ [\c!n=\@@iln,\c!interlinespace=\@@ilinterlinespace,\c!before=,\c!after=]}}%
+ \dodoublegroupempty\docomplexfillinrules}
+
+\def\dodocomplexfillinrules[#1]#2#3#4%
+ {\endgraf
+ \@@ilbefore
+ \begingroup
+ \setupfillinrules[#1]%
+ \noindent
+ \doifsomething{#2}
+ {\doifelse\@@ilwidth\v!fit
+ {\let\@@ildistance\!!zeropoint
+ \hbox}
+ {\doifelse\@@ilwidth\v!broad
+ {\hbox}
+ {\hbox to \@@ilwidth}}%
+ \bgroup
+ \doattributes\??il\c!style\c!color{\strut#2\hfill\@@ilseparator}%
+ \hskip\@@ildistance
+ \egroup}%
+ %\hangindent=\wd0\relax % tzt hang=yes,n
+ %\parindent=\hangindent
+ %\box0\relax
+ \setupwhitespace[\v!big]%
+ \ignorespaces
+ #4%
+ \doifsomething{#3}
+ {\kern\@@ildistance
+ \doattributes\??il\c!style\c!color{#3\strut}}%
+ \endgroup
+ \endgraf
+ \@@ilafter}
+
+%D \macros
+%D {fillintext}
+%D
+%D To provide compatible layouts when texts and lines are
+%D mixed, one can typeset a paragraph by using the command
+%D \type{\fillintext}.
+%D
+%D \showsetup{fillintext}
+
+\definecomplexorsimpleempty\fillintext
+
+\def\complexfillintext[#1]% rather rough, using an \unhbox is suboptimal
+ {\def\docomplexfillintext##1##2%
+ {\dowithnextbox
+ {\dodocomplexfillinrules[#1]{##1}{\hfill##2}{\unhbox\nextbox\unskip}}%
+ \hbox\bgroup\let\par\egroup\ignorespaces}%
+ \dodoublegroupempty\docomplexfillintext}
+
+%D \macros
+%D {fillinline, setupfillinlines}
+%D
+%D Another member of the family takes care of putting a (often
+%D small) rule after a piece of text, like
+%D
+%D \startbuffer
+%D \fillinline \input reich \par
+%D \fillinline[margin=0cm] \input reich \par
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D which was typeset by saying:
+%D
+%D \typebuffer
+%D
+%D The two commands that take care of this are:
+%D
+%D \showsetup{fillinline}
+%D \showsetup{setupfillinlines}
+
+\def\setupfillinlines
+ {\dodoubleargument\getparameters[\??iv]}
+
+\definecomplexorsimpleempty\fillinline
+
+\def\complexfillinline[#1]%
+ {%\endgraf % interferes with \definedescription cum suis
+ \@@ivbefore
+ \begingroup
+ \setupfillinlines[#1]%
+ \advance\rightskip \@@ivmargin
+ \parfillskip\zeropoint
+ \def\par % very dangerous
+ {\let\par\endgraf % -)
+ \ifhmode\unskip\hfill\fi
+ \scratchdimen\dimexpr\@@ivwidth-\@@ivdistance\relax
+ \ifdim\scratchdimen>\@@ivmargin\else\expandafter\rlap\fi
+ {\kern\@@ivdistance
+ \vrule
+ \!!width \scratchdimen
+ \!!height.5\linewidth
+ \!!depth .5\linewidth}%
+ \endgraf % !
+ \endgroup
+ \endgraf % !
+ \@@ilafter}}
+
+%D \stopdocumentation
+%D \bgroup
+%D
+%D \setupframedtexts
+%D [setuptext]
+%D [background=color,backgroundcolor=white]
+%D
+%D \startbuffer
+%D \setupbackground
+%D [backgroundoffset=4pt,
+%D background=screen,
+%D frame=on,
+%D framecolor=red,
+%D leftoffset=2pt]
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D \startbackground
+%D
+%D \macros
+%D {setupbackground,startbackground,background}
+%D
+%D The section deals with backgrounds in the running text. This
+%D means that texts is to be collected and split over pages. To
+%D show what can be done, we provide this part of the
+%D documentation with some gray background and a red frame.
+%D Both the background and frame can have all characteristics
+%D of \type{\framed}. This time we used the setting:
+%D
+%D \typebuffer
+%D
+%D The implementation is not that sophisticated, but suffices.
+%D The main problem with this kind of functionality is to get
+%D the spacing all right.
+
+%D Specifying the background is more or less the same as
+%D specifying a framed box.
+%D
+%D \showsetup{setupbackground}
+
+\presetlocalframed[\??ag]
+
+\def\dosetupbackground[#1]%
+ {\getparameters[\??ag][#1]%
+ \doifelse\@@agstate\v!start
+ {\let\startbackground\dostartbackground
+ \let\stopbackground \dostopbackground
+ \let\background \dobackground}
+ {\let\startbackground\relax
+ \let\stopbackground \relax
+ \let\background \relax}}
+
+\def\setupbackground
+ {\dosingleargument\dosetupbackground}
+
+%D Actually typesetting the background is implemented rather
+%D straightforward. We need to handle some spacing as well as
+%D the (often) a bit smaller horizontal size.
+%D
+%D \showsetup{startbackground}
+%D
+%D Although we could have used a scratch one, we first
+%D declare a boolean.
+
+% 0=no-split, 1=no-split+indent, 2=split, 3=split+indent
+
+\chardef\backgroundsplitmode\plusthree
+
+%D The \type{\vbox to \lineheight{}\vskip\zeropoint}
+%D construction gives the first real line a decent height by
+%D adding a dummy line.
+
+\def\dostartbackground
+ {\endgraf
+ \bgroup
+ \setbox0\vbox\bgroup
+ \vbox to \lineheight{}\vskip\zeropoint
+ \blank[\v!disable]
+ % \advance\hsize -\@@agleftoffset
+ % \advance\hsize -\@@agrightoffset
+ \leftskip \@@agleftoffset % new **
+ \rightskip\@@agrightoffset} % new **
+
+%D This dummy line is removed by \type{\setbox2=\vsplit0 to
+%D \lineheight}. That way \type{\topskip} takes care of the
+%D lineheight. I'll probably forget to apply this trick
+%D elsewhere.
+
+\def\dostopbackground % improved version (i hope)
+ {\endgraf
+ \removelastskip
+ \egroup
+ \dimen2\leftskip % new **
+ \forgetall
+ \ifinsidefloat
+ \chardef\backgroundsplitmode\zerocount
+ \fi
+ \ifcase\backgroundsplitmode
+ \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
+ \or
+ \hskip\dimen2
+ \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
+ \else
+ \splitmaxdepth\boxmaxdepth
+ \splittopskip\topskip
+ \setbox2\vsplit0 to \lineheight % get rid of fake line
+ \loop
+ \ifdim\pagetotal=\zeropoint % empty page
+ \scratchdimen\textheight
+ \chardef\backgroundsplit\plusone % split to max height
+ \else
+ \setbox\scratchbox\vbox{\@@agbefore}%
+ \scratchdimen\dimexpr\pagegoal-\ht\scratchbox-\pagetotal\relax
+ \chardef\backgroundsplit\plustwo % split to partial height
+ \fi
+ \advance\scratchdimen\dimexpr-\@@agtopoffset-\@@agbottomoffset\relax
+ \ifdim\scratchdimen>2\lineheight\relax % reasonable, will be configurable
+ \ifdim\ht0>\scratchdimen % larger than page
+ \setbox2\vsplit0 to \scratchdimen
+ \else
+ \setbox2\box0
+ \chardef\backgroundsplit\zerocount % no split
+ \fi
+ \setbox2\vbox \ifcase\backgroundsplit\or to \textheight \fi % max split
+ {\vskip\@@agtopoffset
+ \popsplitproperties
+ \unvcopy2
+ \prevdepth\dp2
+ \obeydepth
+ \vskip\@@agbottomoffset
+ \vfill}
+ \@@agbefore
+ \ifcase\backgroundsplit\or\or % partial split
+ \ifdim\pagegoal<\maxdimen
+ \pagegoal=1.2\pagegoal % be a bit more tolerant
+ \fi
+ \fi
+ \startlinecorrection
+ %\localframed[\??ag][\c!offset=\v!overlay]{\hskip\@@agleftoffset\box2\hskip\@@agrightoffset}%
+ \ifnum\backgroundsplitmode=\plusthree \hskip\dimen2 \fi %
+ \localframed[\??ag][\c!offset=\v!overlay]{\box2}% new **
+ \stoplinecorrection
+ \ifcase\backgroundsplit % no split
+ \@@agafter
+ \else % some split
+ \vfill\eject % geen \page !
+ \fi
+ \else
+ \page
+ \fi
+ \ifdim\ht0>\zeropoint \repeat
+ \fi
+ \egroup
+ \endgraf}
+
+%D As a bonus we also have a short command, that is of not
+%D much use, but kept there for historic reasons.
+%D
+%D \showsetup{background}
+
+\def\dobackground
+ {\bgroup
+ \dowithnextbox
+ {\localframed[\??ag][\c!offset=\v!overlay]{\flushnextbox}\egroup}
+ \vbox}
+
+%D \stopdocumentation
+%D \stopbackground
+%D \egroup
+
+%D New, for the moment private; let's see when GB finds out
+%D about this one and its obscure usage. It's used in:
+%D
+%D \startbuffer
+%D \defineframedtext
+%D [tabulateframe]
+%D [offset=overlay,
+%D backgroundoffset=3pt,
+%D background=color,
+%D backgroundcolor=green]
+%D
+%D \setuptabulate
+%D [tabulate]
+%D [frame=tabulateframe]
+%D
+%D \setuptables
+%D [frame=tabulateframe]
+%D
+%D \input tufte
+%D
+%D \starttabulate[|l|l|]
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \stoptabulate
+%D
+%D \input tufte
+%D
+%D \starttable[|l|l|]
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \stoptable
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\def\defineframedcontent
+ {\dodoubleempty\dodefineframedcontent}
+
+\def\dodefineframedcontent[#1][#2]%
+ {\presetlocalframed[\??fc#1]%
+ \getparameters[\??fc#1]
+ [\c!leftoffset=\zeropoint,
+ \c!rightoffset=\getvalue{\??fc#1\c!leftoffset},
+ \c!topoffset=\zeropoint,
+ \c!bottomoffset=\getvalue{\??fc#1\c!topoffset},
+ \c!strut=\v!no,
+ \c!offset=\v!overlay,
+ \c!linecorrection=\v!no,
+ \c!left=,
+ \c!right=,
+ #2]}
+
+\let\setuplocalframed\getparameters
+
+\def\setupframedcontent
+ {\dodoubleempty\dosetupframedcontent}
+
+\def\dosetupframedcontent[#1][#2]%
+ {\def\docommand##1{\getparameters[\??fc##1][#2]}%
+ \processcommacommand[#1]\docommand}
+
+\def\startframedcontent[#1]%
+ {\bgroup
+ \let\stopframedcontent\egroup
+ \doifnot{#1}\v!off
+ {\doifdefined{\??fc#1\c!frame}
+ {\def\stopframedcontent{\dostopframedcontent{#1}}%
+ \dostartframedcontent{#1}}}}
+
+\def\dostartframedcontent#1%
+ {\setbox\framebox\hbox\bgroup
+ \setlocalhsize
+ \hsize\localhsize
+ \advance\hsize\dimexpr-\getvalue{\??fc#1\c!leftoffset}-\getvalue{\??fc#1\c!rightoffset} \relax
+ \advance\vsize\dimexpr-\getvalue{\??fc#1\c!topoffset} -\getvalue{\??fc#1\c!bottomoffset}\relax
+ \hskip\getvalue{\??fc#1\c!leftoffset}%
+ \vbox\bgroup
+ \vskip\getvalue{\??fc#1\c!topoffset}%
+ \vbox\bgroup
+ \forgetall
+ \blank[\v!disable]}
+
+\def\dostopframedcontent#1%
+ {\removelastskip
+ \egroup
+ \vskip\getvalue{\??fc#1\c!bottomoffset}%
+ \egroup
+ \hskip\getvalue{\??fc#1\c!rightoffset}%
+ \egroup
+ \doifvalue{\??fc#1\c!width}\v!fit
+ {\letvalue{\??fc#1\c!width}\v!fixed}% no shapebox
+ \ifinsidefloat
+ \donefalse
+ \else
+ \doifelsevalue{\??fc#1\c!linecorrection}\v!yes\donetrue\donefalse
+ \fi
+ % plaats ?
+ \ifdone\startlinecorrection\fi
+ \getvalue{\??fc#1\c!left}% new
+ \localframed[\??fc#1]{\box\framebox}%
+ \getvalue{\??fc#1\c!right}% new
+ \ifdone\stoplinecorrection\fi
+ \egroup}
+
+%D \macros
+%D {backgroundline}
+%D
+%D For the moment an undocumented feature, but a cancidate
+%D for going public.
+
+\def\backgroundline[#1]%
+ %{\doifsomething{#1}{\dobackgroundline{#1}}\hbox}
+ {\doifcolorelse{#1}{\dobackgroundline{#1}\hbox}\hbox}
+
+% \def\backgroundline[#1]%
+% {\doifcolor{#1}{\dobackgroundline{#1}}\hbox}
+
+\def\dobackgroundline#1%
+ {\dowithnextbox
+ {\hbox
+ {\localcolortrue
+ \startcolor[#1]%
+ \vrule
+ \!!width \nextboxwd
+ \!!height\nextboxht
+ \!!depth \nextboxdp
+ \stopcolor
+ \hskip-\nextboxwd
+ \flushnextbox}}}
+
+%D \macros
+%D {encircled}
+%D
+%D Some not so robust left||overs (borrowed from Knuth,
+%D \TEX Book\ page 356):
+
+\def\encircled#1%
+ {{\ooalign{\hfil\raise0.07ex\hbox{{\tx#1}}\hfil\crcr\mathhexbox20D}}}
+
+\let\omcirkeld\encircled
+
+\setuplinewidth
+ [\v!medium]
+
+\setupframed
+ [\c!width=\v!fit,
+ \c!height=\v!broad,
+ \c!lines=,
+ \c!offset=0.25ex, % \defaultframeoffset
+ \c!empty=\v!no,
+ \c!frame=\v!on,
+ \c!topframe=,
+ \c!bottomframe=,
+ \c!leftframe=,
+ \c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!depth=\!!zeropoint,
+ \c!foregroundcolor=,
+ \c!foregroundstyle=,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=,
+ \c!backgroundoffset=\!!zeropoint,
+ \c!framecolor=,
+ \c!frameoffset=\!!zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner,
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ \c!component=,
+ \c!align=,
+ \c!bottom=\vss,
+ \c!top=,
+ \c!strut=\v!yes,
+ \c!autostrut=\v!yes,
+ \c!location=\v!normal,
+ \c!orientation=,
+ \c!autowidth=\v!yes,
+ \c!setups=]
+
+\setupscreens
+ [%\c!factor=1.0, % obsolete
+ %\c!method=\v!external, % obsolete
+ \c!screen=0.95]
+
+\setupblackrules
+ [\c!n=3,
+ \c!width=1em,
+ \c!height=1ex,
+ \c!depth=\!!zeropoint,
+ \c!alternative=\c!a,
+ \c!distance=.25ex,
+ \c!color=]
+
+\setupmarginrules
+ [\c!level=0,
+ \c!rulethickness=\@@kadefaultwidth\linewidth]
+
+\setupthinrules
+ [\c!interlinespace=\v!small,
+ \c!n=3,
+ \c!before=,
+ \c!inbetween={\blank[\v!white]},
+ \c!after=,
+ \c!color=,
+ \c!height=.5\linewidth,
+ \c!depth=.5\linewidth,
+ \c!frame=\v!on, % compatible with textbackgrounds
+ \c!alternative=\v!b,
+ \c!backgroundcolor=,
+ \c!background=,
+ \c!rulethickness=]
+
+\setuptextrules
+ [\c!location=\v!left,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!inbetween=,
+ \c!width=2em,
+ \c!style=\v!bold,
+ \c!color=,
+ \c!rulecolor=,
+ \c!bodyfont=,
+ \c!distance=.5em]
+
+\setupfillinrules
+ [\c!width=\v!broad,
+ \c!distance=1em,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!n=1,
+ \c!interlinespace=\v!small,
+ \c!separator=,
+ \c!style=\v!normal,
+ \c!color=]
+
+\setupfillinlines
+ [\c!width=3cm,
+ \c!margin=\@@ivwidth,
+ \c!distance=1em,
+ \c!before=\blank,
+ \c!after=\blank]
+
+\setupbackground
+ [\c!leftoffset=.5\bodyfontsize,
+ \c!rightoffset=\@@agleftoffset,
+ \c!topoffset=\!!zeropoint,
+ \c!bottomoffset=\@@agtopoffset,
+ \c!state=\v!start,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!frame=\v!off,
+ \c!color=,
+ \c!depth=\!!zeropoint,
+ \c!background=\v!screen,
+ \c!backgroundcolor=\@@agcolor,
+ \c!screen=\@@rsscreen,
+ \c!before=,
+ \c!after=]
+
\protect \endinput
diff --git a/tex/context/base/core-rul.mkiv b/tex/context/base/core-rul.mkiv
index 24e05974d..78c7156b8 100644
--- a/tex/context/base/core-rul.mkiv
+++ b/tex/context/base/core-rul.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-rul,
-%D version=2008.06.05,
+%D version=1998.10.16,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Ruled Stuff Handling,
%D author=Hans Hagen,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+\writestatus{loading}{ConTeXt Core Macros / Ruled Content Handling}
%D After a few months testing this solution is now added
%D to the core. This introduces a possible incompatibility
@@ -23,16 +23,263 @@
% 4 lines oeps : 3.6 2.8 3.0
% tufte 7.5 4.1 4.3
-% \newbox\luashapebox
+\unprotect
+
+%D We have removed the rather old and out dated raster methods. They
+%D have not been used for ages.
+
+%D \macros
+%D {linewidth, setuplinewidth}
+%D
+%D This module deals with rules (lines) in several ways. First
+%D we introduce two macros that can be used to set some common
+%D characteristics.
+%D
+%D \showsetup{setuplinewidth}
+%D
+%D The linewidth is available in \type{\linewidth}. The
+%D preset value of .4pt equals the default hard coded \TEX\
+%D rule width.
+
+\newdimen\linewidth
+
+\def\dosetuplinewidth[#1]%
+ {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
+
+\def\setuplinewidth
+ {\dosingleargument\dosetuplinewidth}
+
+%D \macros
+%D {ruledlinewidth, inheritruledlinewidth}
+%D
+%D Inside framed boxed we will use a private dimensions. As
+%D an option one can let the linewidth inherit its value from
+%D this one.
+
+\newdimen\ruledlinewidth \newif\ifinheritruledlinewidth
+
+% %D \TEX\ lacks support for color and even gray scales. The next
+% %D macros can provide a sort of poor mans gray scales as well
+% %D as give access to more suitable methods of rendering. Such a
+% %D method looks like:
+% %D
+% %D \starttyping
+% %D \def\methodegraybox#1#2#3#4#5#6%
+% %D { ... }
+% %D \stoptyping
+% %D
+% %D The string \type{graybox} is a common element in the name,
+% %D so we can have for instance \type {\postscriptgraybox} or
+% %D \type {\texgraybox}. The first three arguments take a
+% %D dimension, the fourth one takes a number between~0 and~1,
+% %D and the last argument specifies a radius of the box when
+% %D rounded corners are used, so:
+% %D
+% %D \startbuffer
+% %D \dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}
+% %D \stopbuffer
+% %D
+% %D \typebuffer
+% %D
+% %D becomes:
+% %D
+% %D %\startlinecorrection
+% %D % \vbox to 1cm{\getbuffer}
+% %D %\stoplinecorrection
+% %D
+% %D \startlinecorrection
+% %D \unprotect
+% %D \vbox to 1cm{\dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}}
+% %D \protect
+% %D \stoplinecorrection
+% %D
+% %D There are two predefined methodes, one uses periods and the
+% %D other uses small rules. The second method is less
+% %D efficient, but sometimes give better results. The dimensions
+% %D of the resullting box are set to zero.
%
-% \def\doreshapeframedbox
-% {\setbox\luashapebox\box\framebox
-% \ctxlua{commands.doreshapeframedbox(\number\luashapebox)}%
-% \setbox\framebox\box\luashapebox}
+% \setvalue{\v!dot graybox}{\processraster\symbol\rasterdot}
+% \setvalue{\v!rule graybox}{\processraster\symbol\rasterbox}
+%
+% \def\rasterdot{\rasterfont.}
+% \def\rasterbox{\hss\vrule\!!width.4pt\!!height.4pt\!!depth\zeropoint}
+%
+% %D Now of course we need:
+%
+% \ifx\rasterfont\undefined \def\rasterfont{\fivepoint} \fi
+%
+% %D We implement two pure \TEX\ based generators, that use
+% %D \type{\leaders} to quickly gerenate the gray pattern. One
+% %D should beware of \DIMENSION\ conflicts, so we use some
+% %D registers above~8. These macros are memory hungry and byte
+% %D spoiling.
+%
+% \def\processraster#1#2#3#4#5#6#7%
+% {\bgroup
+% \forgetall
+% \dontcomplain
+% \dimen10=\onepoint
+% \dimen10=\@@rsfactor\dimen10
+% \dimen10=#5\dimen10
+% \setbox2\hbox to #2
+% {\cleaders\hbox to 2\dimen10{#1\hss}\hss}%
+% \dimen12=#3%
+% \advance\dimen12 #4%
+% % \setbox0\vbox to \dimen12
+% {\cleaders\vbox to 2\dimen10{\box2\vss}\vss}%
+% \setbox0\hbox
+% {\hskip-.5\dimen10\lower0.5\dimen10\copy0
+% \hskip-\wd0\hskip\dimen10\lower1.5\dimen10\box0}%
+% \box0
+% \egroup}
-\def\doreshapeframedbox{\ifvbox\framebox\ctxlua{commands.doreshapeframedbox(\number\framebox)}\fi}
+%D \macros
+%D {setupscreens}
+%D
+%D The previous macro uses a predefined constant
+%D \type{\@@rsfactor}. This factor can be set by:
+%D
+%D \showsetup{setupscreens}
+
+\def\setupscreens
+ {\dodoubleargument\getparameters[\??rs]}
+
+% %D The most appropriate way to call for this feature is
+% %D using \type{\graybox}, which is defined as:
+%
+% \def\graybox{\getvalue{\@@rsmethod graybox}}
+%
+% %D We just introduced two pure \TEX\ methods for generating
+% %D rasters. However, it's far more efficient and comfortable in
+% %D terms of speed, memory usage and file size, to use a driver
+% %D supported method.
+%
+% \setvalue{\v!external graybox}{\setgraybox}
+%
+% %D For compatibility reasons we also define the original one:
+%
+% \setvalue{\v!postscript graybox}{\getvalue{\v!external graybox}}
+%
+% %D A quite valid way of letting drivers do the job, is giving
+% %D a solid rule a gray texture.
+
+%D We will communicate through module specific variables, current
+%D framed parameters and some reserved dimension registers.
+
+\newdimen \frameddimenwd
+\newdimen \frameddimenht
+\newdimen \frameddimendp
+
+%D We don't have to stick to a \TEX\ drawn rule, but
+%D also can use rounded or even fancier shapes, as we will
+%D see later on.
+
+\def\dofilledbox
+ {\bgroup
+ \doifelse{\framedparameter\c!backgroundcorner}\v!rectangular
+ {\dofilledlinedbox}
+ {\ifzeropt\dimexpr\framedparameter\c!backgroundradius\relax % just in case of .x\bodyfontsize
+ \dofilledlinedbox
+ \else
+ \dofilledroundbox
+ \fi}%
+ \egroup}
+
+\def\dophantombox
+ {\hphantom{\dofilledbox}}
+
+\def\dofilledlinedbox
+ {\vrule\!!width\frameddimenwd\!!height\frameddimenht\!!depth\frameddimendp\relax}%
+
+\def\dostrokedroundbox
+ {\doif{\framedparameter\c!frame}\v!on\dodostrokedroundbox}
+
+\def\dodostrokedroundbox
+ {\bgroup
+ \edef\ovalmod{\framedparameter\c!framecorner}%
+ \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
+ \edef\ovalwid{\the\frameddimenwd}%
+ \edef\ovalhei{\the\frameddimenht}%
+ \edef\ovaldep{\the\frameddimendp}%
+ \edef\ovallin{\the\dimexpr\ruledlinewidth}%
+ \edef\ovalrad{\the\dimexpr\framedparameter\c!frameradius}%
+ \let\ovalstr\!!plusone
+ \let\ovalfil\!!zerocount
+% \forcecolorhack
+ \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
+ \egroup}
+
+\def\dofilledroundbox
+ {\bgroup
+ \edef\ovalmod{\framedparameter\c!backgroundcorner}%
+ \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
+ \edef\ovalwid{\the\frameddimenwd}%
+ \edef\ovalhei{\the\frameddimenht}%
+ \edef\ovaldep{\the\frameddimendp}%
+ \edef\ovallin{\the\dimexpr\ruledlinewidth\relax}%
+ \edef\ovalrad{\the\dimexpr\framedparameter\c!backgroundradius\relax}%
+ \let\ovalstr\!!zerocount
+ \let\ovalfil\!!plusone
+% \forcecolorhack
+ \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
+ \egroup}
+
+% a lot of weird corners
+%
+% \startTEXpage
+% \dontleavehmode\framed
+% [corner=0,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green,
+% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \vskip1em
+% \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
+% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
+% \quad}
+% \stopTEXpage
+
+%D The oval box is drawn using a special macro, depending on
+%D the driver in use.
-% speedup, prelude to dedicated mkiv module
+\def\dograybox % avoid black rules when no gray
+ {\doifelsenothing{\framedparameter\c!backgroundscreen}
+ {\dophantombox}
+ {\raster[\framedparameter\c!backgroundscreen]{\dofilledbox}}}
+
+%D It won't be a surprise that we not only provide gray boxes,
+%D but also colored ones. Here it is:
\def\dobackgroundcolorbox
{\hbox{\faststartcolor[\framedbackgroundcolor]\dofilledbox\faststopcolor}}
@@ -50,9 +297,3379 @@
\dophantombox
\fi}
+%D \macros
+%D {defineoverlay, doifoverlayelse, overlayoffset,
+%D overlaywidth, overlayheight, overlaydepth,
+%D overlaycolor, overlaylinecolor, overlaylinewidth}
+%D
+%D Before we define the macro that actually takes card of the
+%D backgrounds, we introduce overlays. An overlay is something
+%D that contrary to its name lays {\em under} the text. An
+%D example of an overlay definition is:
+%D
+%D \startbuffer[tmp-1]
+%D \defineoverlay
+%D [fancy]
+%D [{\externalfigure
+%D [mp-cont.502]
+%D [width=\overlaywidth,
+%D height=\overlayheight]}]
+%D \stopbuffer
+%D
+%D \typebuffer[tmp-1]
+%D
+%D That for instance can be uses in:
+%D
+%D \startbuffer[tmp-2]
+%D \framed[backgroundachtergrond=fancy]{How Fancy!}
+%D \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
+%D \stopbuffer
+%D
+%D and looks like:
+%D
+%D \startlinecorrection
+%D \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
+%D \stoplinecorrection
+%D
+%D The formal definition is:
+%D
+%D \showsetup{defineoverlay}
+%D
+%D This macro's definition is a bit obscure, due the many
+%D non||used arguments and the two step call that enable the
+%D setting of the width, height and depth variables.
+%D Multiple backgrounds are possible and are specified as:
+%D
+%D \starttyping
+%D \framed[background={one,two,three}]{Three backgrounds!}
+%D \stoptyping
+%D
+%D Most drawing packages only know width and height. Therefore
+%D the dimensions have a slightly different meaning here:
+%D
+%D \startitemize[packed]
+%D \item \type{\overlaywidth }: width of the overlay
+%D \item \type{\overlayheight}: height plus depth of the overlay
+%D \item \type{\overlaydepth }: depth of the overlay
+%D \stopitemize
+%D
+%D The resulting box is lowered to the right depth.
+
+\def\overlaywidth {\the\hsize\space} % We preset the variables
+\def\overlayheight {\the\vsize\space} % to some reasonable default
+\let\overlaydepth \!!zeropoint % values. The attributes
+\let\overlayoffset \!!zeropoint % of the frame can be (are)
+\let\overlaycolor \empty % set somewhere else.
+\let\overlaylinewidth \!!zeropoint %
+\let\overlaylinecolor \empty %
+
+%D The next register is used to initialize overlays.
+
+\newtoks\everyoverlay
+
+%D An example of an initialization is the following (overlays
+%D can contain text and be executed under an regime where
+%D interlineskip is off).
+
+\appendtoks \oninterlineskip \to \everyoverlay
+
+\def\defineoverlay
+ {\dodoubleargument\dodefineoverlay}
+
+\def\dodefineoverlay[#1][#2]%
+ {\def\docommand##1{\setvalue{\??ov##1}{\executedefinedoverlay{##1}{#2}}}%
+ \processcommalist[#1]\docommand}
+
+\prependtoks
+ \hsize\overlaywidth
+ \vsize\overlayheight
+\to\everyoverlay
+
+\long\def\executedefinedoverlay#1#2%
+ {\bgroup
+ \edef\overlaywidth {\the\frameddimenwd\space}%
+ \edef\overlayheight{\the\dimexpr\frameddimenht+\frameddimendp\relax\space}%
+ \edef\overlaydepth {\the\frameddimendp\space}%
+ \edef\overlaycolor {\framedparameter\c!backgroundcolor}%
+ %\edef\overlaycorner{\framedparameter\c!backgroundcorner}%
+ %\edef\overlayradius{\framedparameter\c!backgroundradius}%
+ \let\overlayoffset\backgroundoffset % we steal this one
+ \setbox\scratchbox\hbox{\lower\overlaydepth\hbox{\the\everyoverlay#2}}%
+ \setbox\scratchbox\hbox
+ {\hskip-.5\dimexpr\wd\scratchbox-\overlaywidth \relax
+ \raise-.5\dimexpr\ht\scratchbox-\frameddimenht\relax % not overlayheight !
+ \box\scratchbox}%
+ \wd\scratchbox\overlaywidth
+ \ht\scratchbox\overlayheight
+ \dp\scratchbox\overlaydepth
+ \startlayoutcomponent{o:#1}{overlay #1}%
+ \box\scratchbox
+ \stoplayoutcomponent
+ \egroup}
+
+%D The empty case is:
+
+\let\executeoverlay\gobblesevenarguments
+
+%D For testing we provide:
+
+\def\doifoverlayelse#1%
+ {\doifdefinedelse{\??ov#1}}
+
+%D We predefine two already familiar backgrounds:
+
+\setvalue{\??ov\v!screen}{\dograybox }
+\setvalue{\??ov\v!color }{\docolorbox}
+
+% %D After all these preparations, the background macro does no
+% %D bring to many surprises. One has to keep in mind that this
+% %D macro starts up a call chain, depending on the background
+% %D one needs:
+% %D
+% %D \startitemize[packed]
+% %D \item a raster, color or user defined shape
+% %D \item square or round corners
+% %D \item a \TEX\ or driver based method
+% %D \stopitemize
+% %D
+% %D The macro can be extended by adding commands to the token
+% %D list register \type {\everybackgroundbox}. For this
+% %D purpose, the name of the current background is available in
+% %D \type {\currentbackgound}.
+
+%D The content of the box will be (temporary) saved in a box. We
+%D also have an extra box for backgrounds.
+
+\newbox\framebox
+\newbox\extraframebox
+
+\newtoks\everybackgroundbox
+
+\let\currentbackground\empty
+
+% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
+% {\bgroup
+% \def\currentbackground{#1}%
+% \the\everybackgroundbox
+% \setbox\extraframebox\hbox
+% {\vbox{\moveleft\backgroundoffset\hbox{\executeifdefined{\??ov\currentbackground}\donothing}}}%
+% \wd\extraframebox\zeropoint % \backgroundwidth
+% \ht\extraframebox\backgroundheight
+% \dp\extraframebox\backgrounddepth
+% \box\extraframebox % \hskip-\backgroundwidth
+% \egroup}
+
+% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
+% {\bgroup
+% \def\currentbackground{#1}%
+% \ifcsname\??ov\currentbackground\endcsname
+% \the\everybackgroundbox
+% \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
+% \wd\extraframebox\zeropoint % \backgroundwidth
+% \ht\extraframebox\backgroundheight
+% \dp\extraframebox\backgrounddepth
+% \box\extraframebox % \hskip-\backgroundwidth
+% \fi
+% \egroup}
+
+\def\dodobackgroundbox
+ {\bgroup
+ \ifcsname\??ov\currentbackground\endcsname
+ \the\everybackgroundbox
+ \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
+ \wd\extraframebox\zeropoint % \backgroundwidth
+ \ht\extraframebox\backgroundheight
+ \dp\extraframebox\backgrounddepth
+ \box\extraframebox % \hskip-\backgroundwidth
+ \fi
+ \egroup}
+
+\def\dododobackgroundbox#1,#2% #2 gobbles spaces
+ {\edef\currentbackground{#1}%
+ \ifx\currentbackground\s!unknown\else
+ \dodobackgroundbox\expandafter\dododobackgroundbox
+ \fi#2}
+
+\let\backgroundoffset\!!zeropoint
+\let\backgrounddepth \!!zeropoint
+\def\backgroundwidth {\the\hsize}
+\def\backgroundheight{\the\vsize}
+
+% todo: also \def\theforegroundbox{#1}
+
+% \def\dobackgroundbox#1%
+% {\setbox\framebox\vbox
+% {\forgetall
+% \boxmaxdepth\maxdimen
+% \scratchdimen \framedparameter{#1}\relax
+% \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
+% \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
+% \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
+% \edef\backgroundoffset{\the\scratchdimen}%
+% \edef\backgroundwidth {\the\wd\framebox}%
+% \edef\backgroundheight{\the\ht\framebox}%
+% \edef\backgrounddepth {\the\dp\framebox}%
+% %\edef\foregroundbox{\box#1}%
+% \def\foregroundbox% fuzzy but needed hack, this \vss, otherwise
+% {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
+% \edef\component{\framedparameter\c!component}%
+% \hbox to \backgroundwidth % in case 'foreground' is used as overlay
+% {\ifx\component\empty
+% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
+% \else
+% \startlayoutcomponent{b:\component}{\s!background\space\component}%
+% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
+% \stoplayoutcomponent
+% \fi
+% \box\framebox\hss}}}
+
+\def\normalforegroundbox% fuzzy but needed hack, this \vss, otherwise
+ {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
+
+\def\dobackgroundbox#1%
+ {\setbox\framebox\vbox
+ {\forgetall
+ \boxmaxdepth\maxdimen
+ \scratchdimen \framedparameter{#1}\relax
+ \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
+ \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
+ \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
+ \edef\backgroundoffset{\the\scratchdimen}%
+ \edef\backgroundwidth {\the\wd\framebox}%
+ \edef\backgroundheight{\the\ht\framebox}%
+ \edef\backgrounddepth {\the\dp\framebox}%
+ %\edef\foregroundbox{\box#1}%
+ \edef\component{\framedparameter\c!component}%
+ \let\foregroundbox\normalforegroundbox
+ \hbox to \backgroundwidth % in case 'foreground' is used as overlay
+ {\ifx\component\empty
+ \normalexpanded{\noexpand\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
+ \else
+ \startlayoutcomponent{b:\component}{background \component}%
+ \normalexpanded{\noexpand\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
+ \stoplayoutcomponent
+ \fi
+ \box\framebox\hss}}}
+
+%D One can explictly insert the foreground box. For that
+%D purpose we introduce the overlay \type {foreground}.
+
+\defineoverlay[\v!foreground][\foregroundbox]
+
+%D We can specify overlays as a comma separated list of
+%D overlays, a sometimes handy feature.
+
+%D Besides backgrounds (overlays) we also need some macros to
+%D draw outlines (ruled borders). Again we have to deal with
+%D square and round corners. The first category can be handled
+%D by \TEX\ itself, the latter one depends on the driver. This
+%D macro also support a negative offset.
+
+\ifx\scratchoffset\undefined \newdimen\scratchoffset \fi
+
+\def\dooutlinebox % we needed to move the color command in order to apply attributes properly
+ {\setbox\framebox\vbox % rules on top of box
+ {\scratchoffset \framedparameter\c!frameoffset\relax
+ \frameddimenwd\dimexpr\wd\framebox+2\scratchoffset\relax
+ \frameddimenht\dimexpr\ht\framebox+ \scratchoffset\relax
+ \frameddimendp\dimexpr\dp\framebox+ \scratchoffset+\framedparameter\c!framedepth\relax
+ \ifdim\frameddimendp<\zeropoint
+ \advance\frameddimenht \frameddimendp
+ \scratchdimen-\frameddimendp
+ \frameddimendp\zeropoint
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \setbox\extraframebox\hbox
+ {\doifsomething{\framedparameter\c!framecolor}{\color[\framedparameter\c!framecolor]}{\dostrokedbox}}%
+ \setbox\extraframebox\hbox
+ {\raise\scratchdimen\vbox
+ {\moveleft\scratchoffset
+ \box\extraframebox}}%
+ \wd\extraframebox\wd\framebox
+ \ht\extraframebox\ht\framebox
+ \dp\extraframebox\dp\framebox
+ \hbox{\box\framebox\hskip-\wd\extraframebox\box\extraframebox}}}
+
+\def\dostrokedbox
+ {\doifelse{\framedparameter\c!framecorner}\v!rectangular
+ {\dostrokedlinedbox}
+ {\ifzeropt\dimexpr\framedparameter\c!frameradius\relax % just in case of .x\bodyfontsize
+ \dostrokedlinedbox
+ \else
+ \dostrokedroundbox
+ \fi}}
+
+\def\dostrokedlinedbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\frameddimenwd
+ \ht\scratchbox\frameddimenht
+ \dp\scratchbox\frameddimendp
+ \setbox\scratchbox\vbox \bgroup
+ \csname t\@@frame@@\framedparameter\c!frame\framedparameter\c!topframe \endcsname
+ \hbox \bgroup
+ \csname l\@@frame@@\framedparameter\c!frame\framedparameter\c!leftframe \endcsname
+ \box\scratchbox
+ \csname r\@@frame@@\framedparameter\c!frame\framedparameter\c!rightframe \endcsname
+ \egroup
+ \csname b\@@frame@@\framedparameter\c!frame\framedparameter\c!bottomframe\endcsname
+ \egroup
+ \wd\scratchbox\frameddimenwd
+ \ht\scratchbox\frameddimenht
+ \dp\scratchbox\frameddimendp
+ \box\scratchbox}
+
+\def\@@frame@@{@@frame@@}
+
+% \setvalue{t\@@frame@@\v!on \v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{t\@@frame@@\v!off\v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{t\@@frame@@\v!on }{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{b\@@frame@@\v!on }{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!on \v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!off\v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{l\@@frame@@\v!on }{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+% \setvalue{r\@@frame@@\v!on }{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+
+\def\@@frame@@trule{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
+\def\@@frame@@brule{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
+\def\@@frame@@rrule{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
+\def\@@frame@@lrule{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
+
+\letvalue{t\@@frame@@\v!on \v!on}\@@frame@@trule
+\letvalue{t\@@frame@@\v!off\v!on}\@@frame@@trule
+\letvalue{t\@@frame@@\v!on }\@@frame@@trule
+
+\letvalue{b\@@frame@@\v!on \v!on}\@@frame@@brule
+\letvalue{b\@@frame@@\v!off\v!on}\@@frame@@brule
+\letvalue{b\@@frame@@\v!on }\@@frame@@brule
+
+\letvalue{l\@@frame@@\v!on \v!on}\@@frame@@lrule
+\letvalue{l\@@frame@@\v!off\v!on}\@@frame@@lrule
+\letvalue{l\@@frame@@\v!on }\@@frame@@lrule
+
+\letvalue{r\@@frame@@\v!on \v!on}\@@frame@@rrule
+\letvalue{r\@@frame@@\v!off\v!on}\@@frame@@rrule
+\letvalue{r\@@frame@@\v!on }\@@frame@@rrule
+
+% no overlapping rules
+
+\def\@@frame@@trules{\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}\nointerlineskip\kern-\ruledlinewidth}
+\def\@@frame@@brules{\kern-\ruledlinewidth\nointerlineskip\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}}
+\def\@@frame@@rrules{\kern-\ruledlinewidth\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth}
+\def\@@frame@@lrules{\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth\kern-\ruledlinewidth}
+
+% small is relatively new
+
+\letvalue{t\@@frame@@\v!small\v!small}\@@frame@@trules
+\letvalue{t\@@frame@@\v!off \v!small}\@@frame@@trules
+\letvalue{t\@@frame@@\v!small }\@@frame@@trules
+
+\letvalue{b\@@frame@@\v!small\v!small}\@@frame@@brules
+\letvalue{b\@@frame@@\v!off \v!small}\@@frame@@brules
+\letvalue{b\@@frame@@\v!small }\@@frame@@brules
+
+\letvalue{l\@@frame@@\v!small\v!small}\@@frame@@lrules
+\letvalue{l\@@frame@@\v!off \v!small}\@@frame@@lrules
+\letvalue{l\@@frame@@\v!small }\@@frame@@lrules
+
+\letvalue{r\@@frame@@\v!small\v!small}\@@frame@@rrules
+\letvalue{r\@@frame@@\v!off \v!small}\@@frame@@rrules
+\letvalue{r\@@frame@@\v!small }\@@frame@@rrules
+
+%D I condidered using the low level support command
+%D \type{\ruledhbox}, but this would slow down processing by a
+%D factor~3.
+
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
+% {}
+% \framed
+% [width=4cm,height=3cm,rulethickness=3mm,
+% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
+% {}
+
+%D The next few macros are probably the most misused ones in
+%D \CONTEXT. They deal with putting rules around boxes, provide
+%D backgrounds, offer alignment features, and some more. We
+%D start with defining some booleans. These give an impression
+%D of what we are going to take into account.
+
+% todo: chardefs
+
+\newif\ifboxhasoffset
+\newif\ifboxhaswidth
+\newif\ifboxhasheight
+\newif\ifboxhasformat
+\newif\ifboxhasstrut
+\newif\ifboxisoverlaid
+\newif\ifboxhasframe
+\newif\ifdelayedstrut
+\newif\ifboxhasextraoffset
+
+%D We also need a few \DIMENSIONS:
+
+\newdimen\@@localoffset
+\newdimen\@@globalwidth
+
+%D \macros
+%D {framed, setupframed}
+%D
+%D Ruled boxes are typeset using \type{\framed}. This command
+%D is quite versatile and, although some users will probably
+%D seldom use it, one cannot overlook its features.
+%D
+%D \showsetup{setupframed}
+%D \showsetup{framed}
+%D
+%D This general macro is a special version of an even more
+%D general case, that can easily be linked into other macros
+%D that need some kind of framing. The local version is called
+%D with an extra parameter: the variable identifier. The reason
+%D for passing this identifier between brackets lays in the
+%D mere fact that this way we can use the optional argument
+%D grabbers.
+
+\def\defaultframeoffset{.25ex}
+
+\def\presetlocalframed [#1]{\letvalue{#1\s!parent}\??oi}
+\def\inheritlocalframed[#1]#2[#3]{\letvalue{#1\s!parent}#3}
+\def\copylocalframed [#1]#2[#3]{\setvalue{#1\s!parent}{#3}}
+
+\presetlocalframed[\??ol]
+
+% \unexpanded\def\framed
+% {\bgroup
+% \dodoubleempty\startlocalframed[\??ol]}
+
+\newcount\framednesting
+
+\unexpanded\def\framed
+ {\bgroup
+ \advance\framednesting\plusone
+ \letvalue{\??ol:\the\framednesting\s!parent}\??ol
+ \dodoubleempty\startlocalframed[\??ol:\the\framednesting]}
+
+\def\setupframed
+ {\dodoubleempty\dosetupframed}
+
+\def\dosetupframed
+ {\ifsecondargument
+ \@EA\dodoublesetupframed
+ \else
+ \@EA\dosinglesetupframed
+ \fi}
+
+\def\dosinglesetupframed[#1][#2]%
+ {\getparameters[\??ol][#1]}
+
+\def\dodoublesetupframed[#1][#2]%
+ {\bgroup
+ \let\dodoubleempty\empty
+ \def\doframed[##1]{\gdef\globalredefinedframed{\dodoubleempty\doframed[##1,#2]}}%
+ \getvalue{#1}%
+ \egroup
+ \letvalue{#1}\globalredefinedframed}
+
+%D \startbuffer
+%D \setupframed [framecolor=yellow] \framed{A}
+%D \defineframed[myframed] [framecolor=blue] \myframed{B}
+%D \setupframed [myframed] [framecolor=red] \myframed{C}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \presetlocalframed[myframed]
+%D \setuplocalframed[myframed][width=4cm,height=2cm]
+%D \localframed[myframed][framecolor=green]{oeps}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {ifinframed}
+%D
+%D The normal case first presets all parameters and next starts
+%D looking for the user supplied ones. The first step is
+%D omitted in the local case, because these are preset at
+%D declaration time and keep their values unless explictly
+%D changed. By presetting the variables everytime the normal
+%D command is called, we can use this command nested, without
+%D the unwanted side effect of inheritance. The boolean is
+%D used to speed up the color stack.
+
+\newif\ifinframed
+
+\def\localframed
+ {\bgroup
+ \dodoubleempty\startlocalframed}
+
+%D The next one is faster on multiple backgrounds per page. No
+%D dimensions can be set, only frames and backgrounds.
+
+\def\fastlocalframed[#1]#2[#3]#4% 3-4
+ {\bgroup
+ \inframedtrue
+ \edef\@@framed{#1}%
+ % some hackery (no \dimexpr)
+ \scratchdimen\framedparameter\c!frameoffset
+ \setevalue{\@@framed\c!frameoffset}{\the\scratchdimen}%
+ \doifnot{\framedparameter\c!backgroundoffset}\v!frame
+ {\scratchdimen\framedparameter\c!backgroundoffset
+ \setevalue{\@@framed\c!backgroundoffset}{\the\scratchdimen}}%
+ % so far
+ \setbox\framebox\hbox{#4}%
+ \getparameters[\@@framed][#3]% no \expanded !
+ % not here, in calling macro: setups
+ \removeframedboxdepth
+ \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
+ \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}%
+ \edef\overlaylinewidth{\the\ruledlinewidth}%
+ \edef\@@localframing {\framedparameter\c!frame}%
+ \ifx\@@localframing\v!overlay \else \ifx\@@localframing\v!none \else
+ \edef\framedrulethickness{\framedparameter\c!rulethickness}%
+ \ifx\framedrulethickness\empty\else
+ \ruledlinewidth\framedrulethickness\relax
+ \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
+ \fi
+ \dooutlinebox % real or invisible frame
+ \fi \fi
+ \edef\framedbackground{\framedparameter\c!background}%
+ \ifx\framedbackground\empty\else\dobackedbox\fi
+ \restoreframedboxdepth
+ \box\framebox
+ \egroup}
+
+%D Before we go into details, we present (and implement) the
+%D main framing routine. I saw no real reason for splitting the
+%D next two macros into smaller pieces. The content will be
+%D collected in a horizontal or vertical box with fixed or free
+%D dimensions and specific settings concerning aligment and
+%D offsets.
+%D
+%D In the first few lines, we pre||expand the frame and
+%D background offsets. We do so, because the can be defined in
+%D terms of the main offset. However, see for instance page
+%D backgrounds, when \type {#2} sets the offset to \type
+%D {overlay}, both offsets become invalid.
+%D
+%D Because it is used so often the he next macro is (and
+%D looks) rather optimized.
+
+\let\postprocessframebox\relax
+
+\let\@@framed\s!unknown
+
+\def\framedparameter #1{\csname\doframedparameter\@@framed#1\endcsname}
+\def\framedparameterhash#1{\doframedparameterhash \@@framed#1}
+
+\def\doframedparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\doframedparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\doframedparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\doframedparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\doframedparentparameter #1#2{\ifx#1\relax\s!empty\else\doframedparameter #1#2\fi}
+\def\doframedparentparameterhash#1#2{\ifx#1\relax \else\doframedparameterhash#1#2\fi}
+
+% \def\s!root{root} % maybe configurable
+
+\def\doframedparentparameter#1#2{\ifx#1\relax\doframedrootparameter#2\else\doframedparameter#1#2\fi}
+\def\doframedrootparameter #1{\ifcsname\??oi#1\endcsname\??oi#1\else\s!empty\fi}
+
+\def\dosetframedattributes#1#2% style color
+ {\edef\fontattributehash {\framedparameterhash#1}%
+ \edef\colorattributehash{\framedparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+% defaults, kind of isolated now
+
+\getparameters
+ [\??oi]
+ [\c!width=\v!fit,
+ \c!height=\v!broad,
+ %\c!lines=,
+ \c!offset=0.25ex, % \defaultframeoffset
+ \c!empty=\v!no,
+ \c!frame=\v!on,
+ %\c!topframe=,
+ %\c!bottomframe=,
+ %\c!leftframe=,
+ %\c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!depth=\!!zeropoint,
+ %\c!foregroundcolor=,
+ %\c!foregroundstyle=,
+ %\c!background=,
+ %\c!backgroundscreen=,
+ %\c!backgroundcolor=,
+ \c!backgroundoffset=\!!zeropoint,
+ %\c!framecolor=,
+ \c!frameoffset=\!!zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner,
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ %\c!component=,
+ %\c!align=,
+ \c!bottom=\vss,
+ %\c!top=,
+ \c!strut=\v!yes,
+ \c!autostrut=\v!yes,
+ \c!location=\v!normal,
+ %\c!orientation=,
+ \c!autowidth=\v!yes,
+ %\c!setups=
+]
+
+\getparameters
+ [\??od] % for fast version
+ [\c!frame=\v!off,
+ \c!depth=\zeropoint,
+ \c!offset=\v!overlay,
+ %\c!component=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!backgroundoffset=\!!zeropoint,
+ \c!frameoffset=\!!zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner,
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ \c!location=\v!normal]
+
+% so far
+
+\newdimen\!!framedwidth
+\newdimen\!!framedheight
+\newdimen\!!framedscratch % so that users can use \scratchdimen
+
+\let\setextraframedoffsets \relax
+\let\applyextraframedoffsets\relax
+
+\def\startlocalframed[#1][#2]%
+ {\bgroup
+ \inframedtrue
+ \edef\@@framed{#1}%
+ % this piece of pre expansion is needed (sometimes used circular)
+ \!!framedscratch\framedparameter\c!frameoffset
+ \setevalue{\@@framed\c!frameoffset}{\the\!!framedscratch}%
+ \doifnot{\framedparameter\c!backgroundoffset}\v!frame
+ {\!!framedscratch\framedparameter\c!backgroundoffset
+ \setevalue{\@@framed\c!backgroundoffset}{\the\!!framedscratch}}%
+ % to prevent deadlock in case of self refering
+ \ifsecondargument % faster
+ \getparameters[\@@framed][#2]% here !
+ \fi
+ % new, experimental dirty hook
+ \framedparameter\c!extras
+ % to get the right spacing
+ \doifsomething{\framedparameter\c!foregroundstyle}
+ {\@EA\doconvertfont\csname\@@framed\c!foregroundstyle\endcsname\empty}%
+ % beware, both the frame and background offset can be overruled
+ %
+ \edef\doframedsetups{\framedparameter\c!setups}%
+ \ifx\doframedsetups\empty\else
+ \edef\doframedsetups{\noexpand\setups[\doframedsetups]}%
+ \fi
+ % the next macros are visible
+ \edef\localoffset{\framedparameter\c!offset}%
+ \edef\localwidth {\framedparameter\c!width}%
+ \edef\localheight{\framedparameter\c!height}%
+ \edef\localformat{\framedparameter\c!align}%
+ \edef\localstrut {\framedparameter\c!strut}%
+ % these are not
+ \edef\@@localautostrut {\framedparameter\c!autostrut}%
+ \edef\@@localframing {\framedparameter\c!frame}%
+ \edef\@@locallocation {\framedparameter\c!location}%
+ \edef\@@localorientation{\framedparameter\c!orientation}%
+ %
+ \edef\@@localautowidth {\framedparameter\c!autowidth}%
+ %
+ \ifx\@@localframing\v!overlay % no frame, no offset, no framewidth
+ \boxhasframefalse
+ \let\localoffset\v!overlay
+ \else\ifx\@@localframing\v!none % no frame, no framewidth
+ \boxhasframefalse
+ \else
+ \boxhasframetrue
+ \fi\fi
+ \ifboxhasframe
+ \edef\framedrulethickness{\framedparameter\c!rulethickness}%
+ \ifx\framedrulethickness\empty\else
+ \ruledlinewidth\framedrulethickness\relax
+ \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
+ \fi
+ \else
+ \ruledlinewidth\zeropoint
+ \fi
+ \ifx\localformat\empty
+ \boxhasformatfalse
+ \else
+ \boxhasformattrue
+ \dosetraggedcommand\localformat
+ \edef\dobeforeframedbox{\raggedtopcommand\framedparameter\c!top}%
+ \edef\doafterframedbox {\framedparameter\c!bottom\raggedbottomcommand}%
+ \fi
+ \ifx\localoffset\v!none
+ \boxhasoffsetfalse
+ \boxhasstrutfalse
+ \boxisoverlaidfalse
+ \@@localoffset\ruledlinewidth
+ \else\ifx\localoffset\v!overlay
+ % \ifx\@@localframing\v!no \boxhasframefalse \fi % test first
+ \boxhasoffsetfalse
+ \boxhasstrutfalse
+ \boxisoverlaidtrue
+ \@@localoffset\zeropoint
+ \else
+ \boxhasoffsettrue
+ \boxhasstruttrue
+ \boxisoverlaidfalse
+ \ifx\localoffset\v!default % new per 2-6-2000
+ \let\localoffset\defaultframeoffset
+ \letvalue{\@@framed\c!offset}\defaultframeoffset
+ \else
+ \let\defaultframeoffset\localoffset
+ \fi
+ \@@localoffset\dimexpr\localoffset+\ruledlinewidth\relax
+ \fi\fi
+ \!!framedheight\zeropoint
+ \!!framedwidth \zeropoint
+ \ifx\localwidth\v!fit
+ \ifboxhasformat
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else
+ \boxhaswidthfalse
+ \fi
+ \else\ifx\localwidth\v!fixed % equals \v!fit but no shapebox
+ \ifboxhasformat
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else
+ \boxhaswidthfalse
+ \fi
+ \else\ifx\localwidth\v!broad
+ \boxhaswidthtrue
+ \!!framedwidth\hsize
+ \else\ifx\localwidth\v!local
+ \boxhaswidthtrue
+ \setlocalhsize
+ \!!framedwidth\localhsize
+ \else
+ \boxhaswidthtrue
+ \!!framedwidth\localwidth
+ \fi\fi\fi\fi
+ \ifx\localheight\v!fit
+ \boxhasheightfalse % no longer: \boxhasstrutfalse
+ \else\ifx\localheight\v!broad
+ \boxhasheightfalse
+ \else
+ \boxhasheighttrue
+ \!!framedheight\localheight
+ \fi\fi
+ \ifboxhasheight
+ % obey user set height, also downward compatible
+ \else
+ \doifsomething{\framedparameter\c!lines}
+ {\ifcase\framedparameter\c!lines\else
+ \!!framedheight\framedparameter\c!lines\lineheight
+ \edef\localheight{\the\!!framedheight}%
+ \boxhasheighttrue
+ \fi}%
+ \fi
+ % this is now an option: width=local
+ %
+ % \ifdim\!!framedwidth=\hsize
+ % \parindent\zeropoint
+ % \setlocalhsize
+ % \!!framedwidth\localhsize
+ % \fi
+ % i.e. disable (colsetbackgroundproblemintechniek)
+ \advance\!!framedwidth -2\@@localoffset
+ \advance\!!framedheight -2\@@localoffset
+ \ifx\localstrut\v!no
+ \boxhasstrutfalse
+ \else\ifx\localstrut\v!global
+ \setstrut
+ \else\ifx\localstrut\v!local
+ \setfontstrut
+ \else
+ \setstrut
+ \fi\fi\fi
+ \ifboxhasstrut
+ \let\localbegstrut\begstrut
+ \let\localendstrut\endstrut
+ \let\localstrut \strut
+ \else
+ \let\localbegstrut\pseudobegstrut % was: \relax
+ \let\localendstrut\pseudoendstrut % was: \relax
+ \let\localstrut \pseudostrut % was: \relax
+ %\ifboxhasheight\ifdim\!!framedheight<\strutht % saveguard
+ % \let\localbegstrut\relax % but not that
+ % \let\localstrut \relax % save after all
+ %\fi\fi
+ \fi
+ \ifx\@@localautostrut\v!yes
+ \let\delayedbegstrut\relax
+ \let\delayedendstrut\relax
+ \let\delayedstrut \relax
+ \else
+ \let\delayedbegstrut\localbegstrut
+ \let\delayedendstrut\localendstrut
+ \let\delayedstrut \localstrut
+ \let\localbegstrut \relax
+ \let\localendstrut \relax
+ \let\localstrut \relax
+ \fi
+ \ifboxhasheight
+ \let\\\vboxednewline
+ \ifboxhaswidth
+ \let\hairline\vboxedhairline
+ \ifboxhasformat
+ \let\next\doformatboxSomeFormat
+ \else
+ \let\next\doformatboxNoFormat
+ \fi
+ \else
+ \let\hairline\hboxedhairline
+ \ifboxhasformat
+ \let\next\doformatboxHeight
+ \else
+ \let\next\doformatboxVSize
+ \fi
+ \fi
+ \else
+ \ifboxhaswidth
+ \ifboxhasformat
+ \let\hairline\vboxedhairline
+ \let\\\vboxednewline
+ \let\next\doformatboxWidth
+ \else
+ \let\hairline\hboxedhairline
+ \let\\\hboxednewline
+ \let\next\doformatboxHSize
+ \fi
+ \else
+ \let\hairline\hboxedhairline
+ \let\\\hboxednewline
+ \let\next\doformatboxNoSize
+ \fi
+ \fi
+ \setextraframedoffsets
+ \edef\framedwidth % a new feature, visible for user
+ {\ifdim\!!framedwidth >\zeropoint\the\!!framedwidth \else\zeropoint\fi}%
+ \edef\framedheight% a new feature, visible for user
+ {\ifdim\!!framedheight>\zeropoint\the\!!framedheight\else\zeropoint\fi}%
+ % we need to register the (outer) color
+ \startregistercolor[\framedparameter\c!foregroundcolor]%
+ % first alternative
+ %\def\dowithframedbox%
+ % {\let\postprocessframebox\relax %new
+ % \aftergroup\stoplocalframed}%
+ % \afterassignment\dowithframedbox
+ % \setbox\framebox=\next}
+ % second alternative
+ %\dowithnextbox
+ % {\setbox\framebox\flushnextbox
+ % \let\postprocessframebox\relax %new
+ % \stoplocalframed}
+ % \next}
+ \@@startframedorientation
+ \afterassignment\dodowithframebox
+ \setbox\framebox\next}
+
+\def\dowithframebox
+ {% moved : \let\postprocessframebox\relax
+ \stoplocalframed}
+
+\def\dodowithframebox
+ {\aftergroup\dowithframebox}
+
+\let\doafterframedbox \relax
+\let\dobeforeframedbox\relax
+
+%D Carefull analysis of this macro will learn us that not all
+%D branches in the last conditionals can be encountered, that
+%D is, some assignments to \type{\next} will never occur.
+%D Nevertheless we implement the whole scheme, if not for
+%D future extensions.
+
+%D \macros
+%D {ifreshapeframebox}
+%D
+%D The last few lines tell what to do after the content of the
+%D box is collected and passed to the next macro. In the case
+%D of a fixed width and centered alignment, the content is
+%D evaluated and used to determine the most natural width. The
+%D rest of the code deals with backgrounds and frames.
+
+\newif\ifreshapeframebox \reshapeframeboxtrue
+
+%D Beware: setting \type {top} and \type {bottom} to nothing, may
+%D result in a frame that is larger that the given height! try:
+%D
+%D \starttyping
+%D \framed
+%D [height=3cm,top=,bottom=,offset=overlay]
+%D {\strut test \shapefill \strut test}
+%D \stoptyping
+%D
+%D This is intended behaviour and not a bug! One can always set
+%D
+%D \starttyping
+%D ...,bottom=\kern0pt,...
+%D \stoptyping
+
+\def\stoplocalframed
+ {\dontshowcomposition
+ \@@stopframedorientation % hm, wrong place ! should rotate the result (after reshape)
+ \stopregistercolor
+ \handleframedlocator\c!before\@@locallocation
+ \ifboxhasformat
+ \ifx\@@localautowidth\v!force
+ \ifreshapeframebox\doreshapeframedbox\fi
+ \boxhaswidthfalse
+ \else
+ \ifx\localwidth\v!fit
+ \ifx\@@localautowidth\v!yes
+ \ifreshapeframebox\doreshapeframedbox\fi
+ \fi
+ \boxhaswidthfalse
+ \else\ifx\localwidth\v!fixed
+ \boxhaswidthfalse
+ \else
+ \resetshapeframebox
+ \fi\fi
+ \fi
+\ifconditional\boxcontentneedsprocessing
+ \mkdoprocessboxcontents\framebox
+\fi
+ \else
+ \resetshapeframebox
+ \fi
+ \ifboxhaswidth
+ \wd\framebox\!!framedwidth
+ \fi
+ \ifboxhasheight
+ \ht\framebox\!!framedheight
+ \fi
+ \doif{\framedparameter\c!empty}\v!yes
+ {\setbox\scratchbox\null
+ \wd\scratchbox\wd\framebox
+ \ht\scratchbox\ht\framebox
+ \dp\scratchbox\dp\framebox
+ \setbox\framebox\box\scratchbox}%
+ \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
+ \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
+ \ifboxhasextraoffset
+ \applyextraframedoffsets
+ \fi
+ \ifboxhasoffset
+ \dooffsetframebox
+ \fi
+ \ifboxisoverlaid \else
+ \dolocateframebox
+ \fi
+ \ifx\postprocessframebox\relax \else
+ \let\next\postprocessframebox
+ \let\postprocessframebox\relax % prevent nesting
+ \next\framebox
+ \fi
+ \edef\overlaylinecolor{\framedparameter\c!framecolor}%
+ \edef\overlaylinewidth{\the\ruledlinewidth}% \@@...
+ \ifboxhasframe % real or invisible frame
+ \dooutlinebox
+ \fi
+ \edef\framedbackground{\framedparameter\c!background}%
+ \ifx\framedbackground\empty\else\dobackedbox\fi
+ \handleframedlocator\c!after\@@locallocation
+ \box\framebox
+ \egroup
+ \egroup}
+
+\def\installframedlocator#1#2#3%
+ {\setvalue{\??oi:\c!location:\c!before:#1}{#2}%
+ \setvalue{\??oi:\c!location:\c!after :#1}{#3}}
+
+\def\handleframedlocator#1#2%
+ {\getvalue{\??oi:\c!location:#1:#2}}
+
+\def\doprelocframedbox#1%
+ {\scratchdimen\dimexpr#1+\ruledlinewidth\relax
+ \ifboxhasoffset
+ \advance\scratchdimen \framedparameter\c!offset
+ \fi
+ \scratchskip\dimexpr\ht\framebox-\scratchdimen\relax}
+
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
+% \framed[width=2cm,align=middle,location=depth] {location\\equals\\depth}
+% \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=low] {location\\equals\\low}
+% \framed[width=2cm,align=middle,location=line] {location\\equals\\line}
+% \framed[width=2cm,align=middle,location=high] {location\\equals\\high}
+% B}
+% \vskip2cm
+% \ruledhbox
+% {A
+% \framed[width=2cm,align=middle,location=top] {location\\equals\\top}
+% \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
+% \framed[width=2cm,align=middle,location=lohi] {location\\equals\\lohi}
+% \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
+% B}
+
+\installframedlocator \v!hanging % best with strut=no
+ {}
+ {\dp\framebox\ht\framebox
+ \ht\framebox\zeropoint}
+
+\installframedlocator \v!depth
+ {}
+ {\ht\framebox\dimexpr\ht\framebox-\strutdp\relax
+ \dp\framebox\strutdp
+ \box\framebox}
+
+\installframedlocator \v!height
+ {}
+ {\dp\framebox\dimexpr\ht\framebox-\strutht\relax
+ \ht\framebox\strutht
+ \box\framebox}
+
+\installframedlocator \v!high
+ {}
+ {\doprelocframedbox\strutht
+ \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!line
+ {}
+ {\setbox\framebox\hbox{\lower.5\ht\framebox\box\framebox}%
+ \ht\framebox.5\lineheight
+ \dp\framebox.5\lineheight
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!low
+ {}
+ {\doprelocframedbox\strutdp
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \box\framebox}
+
+\installframedlocator \v!top
+ {}
+ {\doprelocframedbox\strutht
+ \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
+ \ht\framebox\scratchdimen
+ \dp\framebox\scratchskip
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!middle
+ {}
+ {\scratchdimen.5\ht\framebox
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\scratchdimen
+ \dp\framebox\scratchdimen
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!lohi
+ {\handleframedlocator\c!before\v!middle}
+ {\handleframedlocator\c!after \v!middle}
+
+\installframedlocator \v!bottom
+ {}
+ {\doprelocframedbox\strutdp
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\scratchskip
+ \dp\framebox\scratchdimen
+ \hbox{\box\framebox}}
+
+\installframedlocator \v!keep % retains height/depth
+ {\removeframedboxdepth}
+ {\restoreframedboxdepth}
+
+% also used in fastlocalframed
+
+\newdimen\originalframedwd
+\newdimen\originalframedht
+\newdimen\originalframeddp
+
+\def\removeframedboxdepth
+ {\originalframedwd\wd\framebox
+ \originalframedht\ht\framebox
+ \originalframeddp\dp\framebox
+ \ifzeropt\originalframeddp\else\setbox\framebox\hbox{\raise\originalframeddp\box\framebox}\fi
+ \wd\framebox\originalframedwd
+ \ht\framebox\dimexpr\originalframedht+\originalframeddp\relax
+ \dp\framebox\zeropoint}
+
+\def\restoreframedboxdepth
+ {\ifzeropt\originalframeddp\else\setbox\framebox\hbox{\lower\originalframeddp\box\framebox}\fi
+ \wd\framebox\originalframedwd
+ \ht\framebox\originalframedht
+ \dp\framebox\originalframeddp}
+
+% \let\@@startframedorientation\relax
+% \let\@@stopframedorientation \relax
+
+% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
+% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
+
+\def\@@startframedorientation
+ {\let\@@stopframedorientation \relax
+ \ifx\@@localorientation\empty\else
+ \ifcase\@@localorientation\else
+ \scratchcounter\@@localorientation
+ \divide\scratchcounter\plustwo
+ \ifodd\scratchcounter
+ \swapmacros\framedwidth \framedheight
+ \swapmacros\localwidth \localheight
+ \swapdimens\!!framedheight\!!framedwidth
+ \def\@@stopframedorientation{\@@dostopframedorientation\plusone}%
+ \else
+ \def\@@stopframedorientation{\@@dostopframedorientation\zerocount}%
+ \fi
+ \fi
+ \fi}
+
+\def\@@dostopframedorientation#1%
+ {\ifcase#1\else
+ \swapmacros\framedwidth \framedheight
+ \swapmacros\localwidth \localheight
+ \swapdimens\!!framedheight\!!framedwidth
+ \fi
+ \setbox\framebox\hbox{\dorotatebox\@@localorientation\hbox{\box\framebox}}}
+
+%D The last conditional takes care of the special situation of
+%D in||line \inframed[height=3cm]{framed} boxes. Such boxes have
+%D to be \inframed{aligned} with the running text.
+
+\def\doinframed[#1]% we could omit #1] but readibility ...
+ {\framed[\c!location=\v!low,#1]}
+
+\unexpanded\def\inframed
+ {\dosingleempty\doinframed}
+
+%D When we set \type{empty} to \type{yes}, we get
+%D ourselves a frame and/or background, but no content, so
+%D actually we have a sort of phantom framed box.
+
+%D Because color marks and specials can interfere with
+%D spacing, we provide a way to specify a foregroundcolor.
+
\def\docolorframebox
{\doifcolor\framedforegroundcolor
{\setbox\framebox\hbox{\faststartcolor[\framedforegroundcolor]\box\framebox\faststopcolor}}}
%{\setbox\framebox\hbox{\doactivatecolor\framedforegroundcolor\box\framebox}}}
+%D \macros
+%D {mframed, minframed}
+%D
+%D When Tobias asked how to frame mathematical elements in
+%D formulas, Taco's posted the next macro:
+%D
+%D \starttyping
+%D \def\mframed#1%
+%D {\relax
+%D \ifmmode
+%D \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}%
+%D \else
+%D \framed{$#1$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Because \type {\ifinner} does not (always) reports what
+%D one would expect, we move the test to the outer level. We
+%D also want to pass arguments,
+%D
+%D \starttyping
+%D \def\mframed%
+%D {\dosingleempty\domframed}
+%D
+%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ?
+%D {\relax
+%D \ifmmode
+%D \ifinner
+%D \inframed[#1]{$#2$}%
+%D \else
+%D \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}%
+%D \fi
+%D \else
+%D \inframed[#1]{$#2$}%
+%D \fi}
+%D \stoptyping
+%D
+%D Still better is the next alternative, if only because it
+%D takes care of setting the super- and subscripts styles
+
+\newcount\mframedstyle
+
+\def\doinlinemframed[#1]#2%
+ {\begingroup
+ \mframedstyle\mathstyle\relax
+ \inframed[#1]{$\triggermathstyle\mframedstyle#2$}%
+ \endgroup}
+
+\def\dodisplaymframed[#1]#2%
+ {\begingroup
+ \mframedstyle\mathstyle\relax
+ \def\normalstrut{$\triggermathstyle\mframedstyle\vphantom{(}$}%
+ \framed[#1]{$\triggermathstyle\mframedstyle#2$}%
+ \endgroup}
+
+\def\mframed {\dosingleempty\dodisplaymframed}
+\def\inmframed{\dosingleempty\doinlinemframed }
+
+%D So instead of the rather versatile \type {\framed}, we ue
+%D the \type {\mframed}.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{z_z}
+%D x \times \inmframed{y} \times y^{z_z}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D However, we got into troubles when we want to nest sub- and
+%D superscripts, like in
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D Therefore, we can best use \type {\super} and \type {\suber}
+%D instead of \type {^} and \type {_}. Both commands take care
+%D of proper font switching.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times \mframed{y} \times y\super{\mframed{z}\suber{\mframed{z}}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D As usual, one can specify in what way the text should be
+%D framed. One should be aware of the fact that, inorder to
+%D preserve the proper spacing, the \type {offset} is set to
+%D \type {overlay} and \type {frameoffset} is used used
+%D instead.
+%D
+%D \startbuffer
+%D \startformula
+%D x \times y\super{\mframed[framecolor=red]{z}\suber{z}}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D For inline use, we also provide the \type {\inmframed}
+%D alternative: we want $x \times \inmframed{y}$ in inline
+%D math, right?
+
+%D This previous framing macros needs a lot of alternatives for
+%D putting rules around boxes, inserting offsets and aligning
+%D text. Each step is handled by separate macros.
+
+\def\dowidenframebox#1%
+ {\setbox\framebox\vbox
+ {\kern#1\hbox{\kern#1\box\framebox\kern#1}\kern#1}}
+
+\def\dooffsetframebox{\dowidenframebox\localoffset}
+\def\dolocateframebox{\dowidenframebox\ruledlinewidth}
+
+%D Let's hope that the next few examples show us enough of
+%D what needs to be done by the auxiliary macros.
+%D
+%D \startbuffer
+%D \framed[height=1cm,offset=.5cm] {rule based learning}
+%D \framed[height=1cm,offset=0cm] {rule based learning}
+%D \framed[height=1cm,offset=none] {rule based learning}
+%D \framed[height=1cm,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[offset=.5cm] {rule based learning}
+%D \framed[offset=0cm] {rule based learning}
+%D \framed[offset=none] {rule based learning}
+%D \framed[offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[strut=nee,offset=.5cm] {rule based learning}
+%D \framed[strut=nee,offset=0cm] {rule based learning}
+%D \framed[strut=nee,offset=none] {rule based learning}
+%D \framed[strut=nee,offset=overlay]{rule based learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D \startbuffer
+%D \framed[width=3cm,align=left] {rule\\based\\learning}
+%D \framed[width=3cm,align=middle] {rule\\based\\learning}
+%D \framed[width=3cm,align=right] {rule\\based\\learning}
+%D \framed[width=fit,align=middle] {rule\\based\\learning}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\dontcomplain\getbuffer}
+%D \stoplinecorrection
+%D
+%D So now we're ready for the complicated stuff. We distinguish
+%D between borders with straight lines and those with round
+%D corners. When using the first alternative it is possible to
+%D turn off one or more lines. More fancy shapes are also
+%D possible by specifying dedicated backgrounds. Turning lines
+%D on and off is implemented as efficient as possible and as a
+%D result is interface language dependant. This next
+%D implementation evolved from simpler ones. It puts for
+%D instance the rules on top of the content and provides
+%D additional offset capabilities. The lot of calls to other
+%D macros makes this mechanism not that easy to comprehend.
+
+%D Getting the backgrounds right takes less code. Again we
+%D have to take care of additional offsets.
+
+\def\dobackedbox
+ {\doifelsevalue{\@@framed\c!backgroundoffset}\v!frame % new
+ {\dobackgroundbox\c!frameoffset}
+ {\dobackgroundbox\c!backgroundoffset}}
+
+%D We handle left, right or middle alignment as well as fixed
+%D or free widths and heights. Each combination gets its own
+%D macro.
+
+%D The following code handles one-liners: \type{align={line,flushright}}.
+%D Beware, since we entered a group and either or not grab the next
+%D bgroup token, we need to finish the group in the oneliner mode.
+
+\ifx\raggedoneliner\undefined \chardef\raggedoneliner\zerocount \fi
+
+\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
+ {\ifcase\raggedoneliner
+ \expandafter\nodoformatonelinerbox
+ \else
+ \expandafter\dodoformatonelinerbox
+ \fi}
+
+\def\dodoformatonelinerbox
+ {\dowithnextboxcontent
+ {\ignorespaces}
+ {\hbox to \hsize
+ {\ifcase\raggedstatus\or\hss\or\hss\fi
+ \unhbox\nextbox \removeunwantedspaces
+ \ifcase\raggedstatus\or \or\hss\or\hss\fi}%
+ \egroup}
+ \hbox}
+
+\def\nodoformatonelinerbox % grabs {
+ {\let\next=}
+
+%D The handlers:
+
+\def\doformatboxSomeFormat
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \vsize\!!framedheight
+ \doframedsetups
+ \raggedcommand
+ \dobeforeframedbox
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\doafterframedbox
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxNoFormat
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \vsize\!!framedheight
+ \doframedsetups
+ \raggedcenter
+ \vss
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxHeight
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \doframedsetups
+ \raggedcommand
+ \vss
+ \bgroup
+ \aftergroup\localendstrut
+ \aftergroup\vss
+ \aftergroup\egroup
+ \localbegstrut
+ \doformatonelinerbox}
+
+\def\doformatboxWidth
+ {\vbox
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \oninterlineskip
+ \hsize\!!framedwidth
+ \doframedsetups
+ \raggedcommand
+ \dobeforeframedbox
+ \bgroup
+ \localbegstrut
+ \aftergroup\localendstrut
+ \aftergroup\doafterframedbox
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxVSize
+ {\vbox to \!!framedheight
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \vsize\!!framedheight
+ \doframedsetups
+ \vss
+ \bgroup
+ \aftergroup\vss
+ \aftergroup\egroup
+ \hbox
+ \bgroup
+ \aftergroup\egroup
+ \localstrut
+ \doformatonelinerbox}
+
+\def\doformatboxHSize
+ {\hbox to \!!framedwidth
+ \bgroup
+ \let\postprocessframebox\relax
+ \forgetall
+ \doframedsetups
+ \hss
+ \localstrut
+ \bgroup
+ \aftergroup\hss
+ \aftergroup\egroup
+ \doformatonelinerbox}
+
+\def\doformatboxNoSize
+ {\hbox
+ \bgroup
+ \let\postprocessframebox\relax
+ \doframedsetups
+ \localstrut
+ \doformatonelinerbox}
+
+\let\doframedsetups\relax
+
+%D On the next page we show some examples of how these macros
+%D come into action. The examples show us how
+%D \type {fit}, \type {broad} dimensions influence the
+%D formatting. Watch the visualized struts. \footnote {Here we
+%D used \type {\showstruts}.}
+%D
+%D \startpostponing
+%D \bgroup
+%D \showstruts
+%D \dontcomplain
+%D \startlinecorrection
+%D \halign{#\enskip&#\enskip&#\enskip&#\enskip&#\enskip&#\cr
+%D \framed[width=.2\hsize, height=.2\hsize, align=] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=yes] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=yes] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=yes] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=yes] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=right] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=right] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=right] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=right] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=left] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=left] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=left] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=left] {a\par b\par c}\cr
+%D \noalign{\vskip1em}
+%D \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=broad, align=middle] {a\par b\par c}&
+%D \framed[width=.2\hsize, height=fit, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=.2\hsize, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=broad, align=middle] {a\par b\par c}&
+%D \framed[width=fit, height=fit, align=middle] {a\par b\par c}\cr}
+%D \stoplinecorrection
+%D \blank[2*big]
+%D \egroup
+%D \stoppostponing
+
+%D \macros
+%D {framednoflines, framedlastlength}
+%D
+%D It is possible to let the frame macro calculate the width
+%D of a centered box automatically (\type {fit}). When
+%D doing so, we need to reshape the box:
+
+% The next implementation is frozen! It preserves the depth,
+% otherwise we get problems with framed display math and auto
+% width.
+
+\newcount\framednoflines
+\newdimen\framedlastlength
+
+\def\resetshapeframebox
+ {\framednoflines \zerocount
+ \framedlastlength\zeropoint}
+
+\let\framedboxwidth \!!zeropoint
+\let\framedboxheight\!!zeropoint
+\let\framedboxdepth \!!zeropoint
+
+\chardef\reshapeframeboxmethod\plusone % 0=no flush, 1=old method 2=no depth messing
+
+% \newbox\luashapebox
+%
+% \def\doreshapeframedbox
+% {\setbox\luashapebox\box\framebox
+% \ctxlua{commands.doreshapeframedbox(\number\luashapebox)}%
+% \setbox\framebox\box\luashapebox}
+
+\def\doreshapeframedbox{\ifvbox\framebox\ctxlua{commands.doreshapeframedbox(\number\framebox)}\fi}
+
+%D The two variables \type {\framednoflines} and \type
+%D {\framedlastlength} can be used in a second pass to
+%D optimized framed material.
+
+% torture test / strange case (much depth) / method 2 needed
+%
+% \startTEXpage[frame=on]
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
+% \blank[big]
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% test outside formula
+% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
+% \stopTEXpage
+
+%D The examples on the next page show how one can give the
+%D frame as well as the background an additional offset and
+%D even a bit more depth. The blue outline is the frame, the
+%D red box is the background and the small black outline is the
+%D visualization of the resulting box, that is, we applied
+%D \type{\ruledhbox} to the result.
+
+%D \startpostponing
+%D \bgroup
+%D \unprotect
+%D \dontcomplain
+%D
+%D \startbuffer
+%D \vbox to \vsize
+%D \bgroup
+%D \startalignment[middle]
+%D \vss
+%D \dontleavehmode\vbox to .8\vsize
+%D \bgroup
+%D \hsize=300pt
+%D \setupframed
+%D [background=color,
+%D backgroundcolorachtergrondkleur=darkred,
+%D width=300pt,
+%D height=60pt,
+%D framecolorkaderkleur=DemoBlue,
+%D rulethickness=2pt]
+%D \def\status%
+%D {backgroundoffset=\framedparameter\c!backgroundoffset\\
+%D frameoffset=\framedparameter\c!frameoffset\\
+%D depth=\framedparameter\c!depth}
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
+%D \vss
+%D \dontleavehmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
+%D \egroup
+%D \vss
+%D \stopalignment
+%D \egroup
+%D \stopbuffer
+%D
+%D \getbuffer \page
+%D
+%D {\setupframed[depth=4pt]\getbuffer} \page
+%D
+%D \protect
+%D \egroup
+%D \stoppostponing
+
+%D When typesetting the framed box inline, we have to keep the
+%D baseline intact outside as well as inside the framed box.
+
+\def\doinlineframedbox
+ {\scratchdimen\dimexpr\strutdp+\ruledlinewidth\relax
+ \ifboxhasoffset
+ \advance\scratchdimen \framedparameter\c!offset
+ \fi
+ \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
+ \ht\framebox\strutht
+ \dp\framebox\strutdp
+ \box\framebox}
+
+%D We can also lower the box over the natural depth of the
+%D line.
+
+\def\doloweredframedbox
+ {\ht\framebox\dimexpr\ht\framebox+\dp\framebox-\strutdp\relax
+ \dp\framebox\strutdp
+ \box\framebox}
+
+%D Hanging the content is mainly meant for cases like the
+%D following:
+%D
+%D \starttyping
+%D \framed[strut=no]
+%D {\framed[height=2cm,location=hanging]{test}%
+%D \framed[height=1cm,location=hanging]{test}}
+%D \stoptyping
+
+\def\dohangingframedbox % best with strut=no
+ {\scratchdimen\dimexpr\ht\framebox+\dp\framebox\relax
+ \ht\framebox\zeropoint
+ \dp\framebox\scratchdimen}
+
+%D We can draw lines from left to right and top to bottom by
+%D using the normal \type{\hairline} command. Both directions
+%D need a different treatment.
+%D
+%D \startbuffer
+%D \framed[width=4cm] {alfa\hairline beta\hairline gamma}
+%D \framed[height=2cm] {alfa\hairline beta\hairline gamma}
+%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \hbox{\getbuffer}
+%D \stoplinecorrection
+%D
+%D These macros try to adapt their behaviour as good as
+%D possible to the circumstances and act as natural as
+%D possible.
+
+\def\vboxedhairline
+ {\bgroup
+ \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
+ \dimen4=\dimexpr\dimen2+\ruledlinewidth\relax
+ \setbox0\vbox
+ {\advance\hsize 2\dimen4
+ \vskip\dimen2
+ \hrule
+ \!!height\ruledlinewidth
+ \!!depth\zeropoint
+ \!!width\hsize
+ \vskip\dimen2}%
+ %\endgraf\nointerlineskip\endgraf
+ %\moveleft\dimen4\box0
+ %\endgraf\nointerlineskip\localbegstrut
+ \endgraf\obeydepth\nointerlineskip
+ \moveleft\dimen4\box0
+ \endgraf\nointerlineskip\localbegstrut % beware, we might kill it in a style using \vskip\lineheight
+ \egroup} % so this must not be changed
+
+\def\hboxedhairline % use framed dimen
+ {\bgroup
+ \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
+ \ifboxhasheight
+ \dimen4\dimexpr\localheight/2+\strutdp-2\ruledlinewidth\relax
+ \dimen6\dimexpr\localheight/2-\strutdp+2\ruledlinewidth\relax
+ \else
+ \dimen4\dimexpr\strutht+\dimen2\relax
+ \dimen6\dimexpr\strutdp+\dimen2\relax
+ \fi
+ \unskip
+ \setbox\scratchbox\hbox
+ {\hskip\dimen2
+ \vrule\!!height\dimen4\!!depth\dimen6\!!width\ruledlinewidth
+ \hskip\dimen2}%
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \box\scratchbox
+ \ignorespaces
+ \egroup}
+
+%D The argument of the frame command accepts \type{\\} as a
+%D sort of newline signal. In horizontal boxes it expands to a
+%D space.
+
+\def\vboxednewline
+ {\endgraf\ignorespaces}
+
+\def\hboxednewline
+ {\unskip\normalspace\ignorespaces}
+
+%D We can set each rule on or off. The default setting is
+%D inherited from \type{frame}. An earlier implementation
+%D use a bit different approach, but the new one seems more
+%D natural:
+%D
+%D \bgroup
+%D \setuptyping[margin=0pt]
+%D \startlinecorrection
+%D \startbuffer
+%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D
+%D \startbuffer
+%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
+%D \stopbuffer
+%D \hbox{\getbuffer\vbox{\typebuffer}}
+%D \stoplinecorrection
+%D \egroup
+
+%D \macros
+%D {setupblackrules}
+%D
+%D The graphic capabilities of \TEX\ do not go beyond simple
+%D filled rules, except of course when using specials. Let's
+%D start with a warning: using this commands is far more slower
+%D than using the \TEX\ primitives \type{\hrule} and
+%D \type{\vrule}, but they save us some tokens. The
+%D characteristics of these rule drawing command can be set by:
+%D
+%D \showsetup{setupblackrules}
+
+\def\setupblackrules
+ {\dodoubleargument\getparameters[\??bj]}
+
+%D \macros
+%D {blackrule}
+%D
+%D The simple command draws only one rule. Its optional
+%D argument can be used to specify the dimensions. By setting
+%D the width, height or depth to \type {max}, one gets the
+%D natural dimensions.
+%D
+%D \showsetup{blackrule}
+
+\def\doblackrule[#1]%
+ {\hbox\bgroup
+ \getparameters[\??bj][#1]%
+ \setstrut
+ \doif\@@bjwidth \v!max{\def\@@bjwidth {1em}}%
+ \doif\@@bjheight\v!max{\def\@@bjheight{\strutht}}%
+ \doif\@@bjdepth \v!max{\def\@@bjdepth {\strutdp}}%
+ \localstartcolor[\@@bjcolor]%
+ \vrule
+ \!!width \@@bjwidth
+ \!!height\@@bjheight
+ \!!depth \@@bjdepth
+ \localstopcolor
+ \egroup}
+
+\unexpanded\def\blackrule
+ {\dosingleempty\doblackrule}
+
+%D \macros
+%D {blackrules}
+%D
+%D One can call for a sequence of black rules, if needed
+%D equally spaced over the given width.
+%D
+%D \showsetup{blackrules}
+%D
+%D The two alternative calls are therefore:
+%D
+%D \startbuffer
+%D Tell me, is this according to the \blackrules[n=6]?
+%D These \blackrules[alternativevariant=b,n=10,distance=.2em,width=4cm] are quite clear.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D We could of course have implemented this macro using
+%D \type{\leaders}, but this would probably have taken more
+%D tokens.
+
+\def\doblackrules[#1]%
+ {\hbox\bgroup
+ \getparameters[\??bj][#1]%
+ \!!widtha\@@bjwidth
+ \!!widthb\@@bjdistance
+ \doif\@@bjalternative\c!b
+ {\scratchcounter\@@bjn
+ \ifnum\scratchcounter=\plusone
+ \!!widthb\zeropoint
+ \else
+ \advance\scratchcounter \minusone
+ \advance\!!widtha -\scratchcounter\!!widthb
+ \divide \!!widtha \@@bjn
+ \fi}%
+ \localstartcolor[\@@bjcolor]%
+ \dorecurse\@@bjn
+ {\vrule
+ \!!width \!!widtha
+ \!!height\@@bjheight
+ \!!depth \@@bjdepth
+ \hskip\!!widthb}%
+ \unskip
+ \localstopcolor
+ \egroup}
+
+\unexpanded\def\blackrules
+ {\dosingleempty\doblackrules}
+
+%D The next commands can be used to draw margin rules. We
+%D support two methods: \marginrule{one for in||line use} and
+%D one that acts on a paragraph. Drawing a margin rule is
+%D rather straightforward because we can use the commands that
+%D put text in the margin.
+
+\def\dodrawmarginrule
+ {\setbox\scratchbox\hbox
+ {\vrule\!!depth\strutdepth\!!height\strutheight\!!width\@@karulethickness}%
+ \smashbox\scratchbox % no \vsmash !!!
+ \box\scratchbox}
+
+\def\drawmarginrule
+ {\strut\inleft{\dodrawmarginrule}}
+
+%D \macros
+%D {marginrule}
+%D
+%D The first method gobbles words and simply puts a bar in the
+%D margin. This method is not entirely robust.
+%D
+%D \showsetup{marginrule}
+
+\definecomplexorsimple\marginrule
+
+\def\simplemarginrule
+ {\let\processword\drawmarginrule
+ \processwords}
+
+\def\complexmarginrule[#1]%
+ {\ifnum#1<\@@kalevel\relax \else
+ \def\@@kadefaultwidth{#1}%
+ \expandafter\simplemarginrule
+ \fi}
+
+%D We need an auxiliary variable
+
+\def\@@kadefaultwidth{1}
+
+%D \macros
+%D {setupmarginrules}
+%D
+%D This macro definitions show us that we can pass an optional
+%D level, which is matched against the previous set one. The
+%D level can be set up with
+%D
+%D \showsetup{setupmarginrules}
+
+\def\setupmarginrules
+ {\dodoubleargument\getparameters[\??ka]}
+
+%D \macros
+%D {startmarginrule}
+%D
+%D The second method collects text and reformats it afterwards,
+%D using the shapebox macros. We prevent local margin rules.
+%D
+%D \showsetup{startmarginrule}
+
+\definecomplexorsimple\startmarginrule
+
+\def\simplestartmarginrule
+ {\bgroup
+ \let\drawmarginrule\relax
+ \let\stopmarginrule\dostopmarginrule
+ \beginofshapebox}
+
+\def\complexstartmarginrule[#1]%
+ {\bgroup
+ \let\drawmarginrule\relax
+ \ifnum#1<\@@kalevel\relax
+ \let\stopmarginrule\egroup
+ \else
+ \def\@@kadefaultwidth{#1}%
+ \let\stopmarginrule\dostopmarginrule
+ \expandafter\beginofshapebox
+ \fi}
+
+\def\dostopmarginrule
+ {\endofshapebox
+ \reshapebox
+ {\hbox{\inleftmargin{\dodrawmarginrule}\box\shapebox}}%
+ \flushshapebox
+ \egroup}
+
+%D \startbuffer
+%D \setupmarginrules[level=5]
+%D
+%D \startmarginrule[1]
+%D First we set the level at~5. Next we typeset this first
+%D paragraph as a level~1 one. As expected no rule show up.
+%D \stopmarginrule
+%D
+%D \startmarginrule[5]
+%D The second paragraph is a level~5 one. As we can see here,
+%D the marginal rule gets a width according to its level.
+%D \stopmarginrule
+%D
+%D \startmarginrule[8]
+%D It will of course be no surprise that this third paragraph
+%D has a even thicker margin rule. This behavior can be
+%D overruled by specifying the width explictly.
+%D \stopmarginrule
+%D \stopbuffer
+%D
+%D In next example we show most features. Watch the rule
+%D thickness adapting itself to the level.
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D We just said:
+%D
+%D \typebuffer
+
+%D \macros
+%D {vl, hl}
+%D
+%D The command \type{\vl} draws a vertical rule \vl\ with strut
+%D dimensions, multiplied with the factor specified in the
+%D optional argument. The height and depth are clipped \vl[3]
+%D to the baselinedistance. Its horizontal counterpart
+%D \type{\hl} draws a horizontal rule \hl\ with a width of 1em,
+%D multiplied with the optional factor. The horizontal rule is
+%D drawn on top of the baseline.
+%D
+%D \showsetup{vl}
+%D \showsetup{hl}
+
+\def\complexvl[#1]%
+ {\bgroup
+ \!!dimena#1\strutht
+ \!!dimenb#1\strutdp
+ \setbox\scratchbox\hbox
+ {\vrule
+ \!!width \linewidth
+ \!!height\!!dimena
+ \!!depth \!!dimenb}%
+ \dp\scratchbox\strutdp
+ \ht\scratchbox\strutht
+ \box\scratchbox
+ \egroup}
+
+\def\complexhl[#1]%
+ {\hbox
+ {\vrule
+ \!!width #1\s!em
+ \!!height\linewidth
+ \!!depth \zeropoint}}
+
+\definecomplexorsimple\vl \def\simplevl{\complexvl[1]}
+\definecomplexorsimple\hl \def\simplehl{\complexhl[1]}
+
+%D \macros
+%D {hairline, thinrule, thinrules, setupthinrules}
+%D
+%D Drawing thin lines can of course easily be accomplished by
+%D the \TEX\ primitives \type{\hrule} and \type{\vrule}. The
+%D next few macros however free us from some specifications.
+%D
+%D \startbuffer
+%D some text
+%D
+%D \hairline
+%D
+%D some more text
+%D
+%D \thinrule
+%D
+%D more and more text
+%D
+%D hi \thinrule\ there
+%D
+%D and then the final text
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D becomes
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D So we've got
+%D
+%D \showsetup{hairline}
+%D \showsetup{thinrule}
+%D
+%D Both can be set up with:
+%D
+%D \showsetup{setupthinrules}
+%D
+%D We also have
+%D
+%D \showsetup{thinrules}
+%D
+%D which looks like: \thinrules[n=2]
+
+\def\thinrule
+ {\strut
+ \bgroup
+ \chardef\ruletype\plusone
+ \processaction
+ [\@@dlalternative]
+ [ \v!a=>\chardef\ruletype0,% no line
+ %\v!b=>\chardef\ruletype1,% height/depth
+ \v!c=>\chardef\ruletype2,% topheight/botdepth
+ % 11=>\chardef\ruletype1,% fallback for backgrounds
+ 0=>\chardef\ruletype0,% compatible with backgrounds
+ % 1=>\chardef\ruletype1,% compatible with backgrounds
+ 2=>\chardef\ruletype2]% compatible with backgrounds
+ \doifsomething\@@dlrulethickness
+ {\linewidth\@@dlrulethickness}%
+ \ifdim\linewidth=\zeropoint
+ \chardef\ruletype\zerocount
+ \else
+ \doifnot\@@dlframe\v!on{\chardef\ruletype\zerocount}%
+ \fi
+ \ifnum\ruletype=\plusone
+ \doif\@@dlheight\v!max{\let\@@dlheight\!!plusone}%
+ \doif\@@dldepth \v!max{\let\@@dldepth \!!plusone}%
+ \else
+ \let\@@dlheight\!!plusone
+ \let\@@dldepth\!!plusone
+ \fi
+ \freezedimensionwithunit\@@dlheight\strutht
+ \freezedimensionwithunit\@@dldepth\strutdp
+ \divide\linewidth \plustwo
+ \doifelse\@@dlbackground\v!color
+ {\startcolor[\@@dlbackgroundcolor]%
+ \ifnum\ruletype=\plustwo % prevent overshoot due to rounding
+ \leaders
+ \hrule
+ \!!height\dimexpr\@@dlheight-.5\linewidth\relax
+ \!!depth \dimexpr\@@dldepth -.5\linewidth\relax
+ \hfill
+ \else
+ \leaders
+ \hrule
+ \!!height\@@dlheight
+ \!!depth \@@dldepth
+ \hfill
+ \fi
+ \stopcolor
+ \ifcase\ruletype
+ % no rule
+ \or
+ \startcolor[\@@dlcolor]%
+ \hfillneg
+ \leaders\hrule\!!height\linewidth\!!depth\linewidth\hfill
+ \stopcolor
+ \or
+ \startcolor[\@@dlcolor]%
+ \hfillneg\leaders\hrule\!!height\dimexpr-\@@dldepth+\linewidth\relax\!!depth\@@dldepth\hfill
+ \hfillneg\leaders\hrule\!!height\@@dlheight\!!depth\dimexpr-\@@dlheight+\linewidth\relax\hfill
+ \stopcolor
+ \fi}
+ {\ifcase\ruletype \else
+ \startcolor[\@@dlcolor]%
+ \leaders\hrule\!!height\@@dlheight\!!depth\@@dldepth\hfill
+ \stopcolor
+ \fi}%
+ \strut
+ \carryoverpar\egroup}
+
+\def\hairline
+ {\endgraf
+ \thinrule
+ \endgraf}
+
+\def\dosetupthinrules[#1]%
+ {\getparameters[\??dl][#1]}
+
+\def\setupthinrules
+ {\dosingleargument\dosetupthinrules}
+
+\def\dothinrules[#1]%
+ {\bgroup
+ \dosetupthinrules[#1]%
+ \@@dlbefore
+ \assignvalue\@@dlinterlinespace\@@dlinterlinespace{1.0}{1.5}{2.0}%
+ \spacing\@@dlinterlinespace
+ \dorecurse\@@dln
+ {\ifnum\recurselevel=\@@dln \dothinrulesnobreak \else
+ \ifnum\recurselevel=2 \dothinrulesnobreak \fi\fi
+ \thinrule
+ \ifnum\recurselevel<\@@dln\relax
+ % test needed, else messed up whitespace
+ \ifx\@@dlinbetween\empty
+ \softbreak
+ \else
+ \endgraf
+ \nowhitespace
+ \@@dlinbetween
+ \fi
+ \fi}%
+ \doifelsenothing\@@dlafter
+ {\carryoverpar\egroup}
+ {\@@dlafter\egroup}}
+
+\def\thinrules
+ {\dosingleempty\dothinrules}
+
+%D A couple of examples are given below.
+%D
+%D \startbuffer
+%D \setupthinrules[n=3,inbetween=,color=gray]
+%D
+%D test test \thinrules\ test test \par
+%D test test \thinrules [color=green] test test \par
+%D test test \thinrules [height=max, depth=max] test test \par
+%D
+%D \setupthinrules[height=.9,depth=.9]
+%D
+%D test test \thinrules\ test test \par
+%D test test \thinrules [alternativevariant=b] test test \par
+%D test test \thinrules [alternativevariant=c] test test \par
+%D test test \thinrules [alternativevariant=c,inbetween=\vskip2ex] test test \par
+%D \stopbuffer
+%D
+%D \typebuffer {\getbuffer}
+%D
+%D There are a couple of alternative ways to visualize rules
+%D using backgrounds. At first sight these may look strange,
+%D but they make sense in educational settings. The
+%D alternatives are more or less compatible with the more
+%D advanced \METAPOST\ based implementation.
+%D
+%D \startbuffer[a]
+%D \setupthinrules
+%D [n=2,
+%D backgroundcolor=gray ,
+%D rulethickness=1pt,
+%D colorkleur=donkerblauw,
+%D after=\blank,
+%D before=\blank]
+%D \stopbuffer
+%D
+%D \typebuffer[a]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a]
+%D \thinrules[alternativevariant=b]
+%D \thinrules[alternativevariant=c]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a,background=color]
+%D \thinrules[alternativevariant=b,background=color]
+%D \thinrules[alternativevariant=c,background=color]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+%D
+%D \startbuffer[b]
+%D \thinrules[alternativevariant=a,height=.8,depth=.8,background=color]
+%D \thinrules[alternativevariant=b,height=.8,depth=.8,background=color]
+%D \thinrules[alternativevariant=c,height=.8,depth=.8,background=color]
+%D \stopbuffer
+%D
+%D \typebuffer[b] \getbuffer[a,b]
+
+%D \macros
+%D {optimizethinrules}
+%D
+%D By saying \type {\thinrulestrue} or \type {-false}, we
+%D can influence the way dangling lines are handled.
+
+\newif\ifoptimizethinrules \optimizethinrulestrue
+
+\def\dothinrulesnobreak
+ {\ifoptimizethinrules\penalty500\fi}
+
+%D \macros
+%D {startframedtext, setupframedtexts, defineframedtext}
+%D
+%D The general framing command we discussed previously, is not
+%D entirely suited for what we call framed texts, as for
+%D instance used in intermezzo's. The next examples show what
+%D we have in mind.
+%D
+%D \startbuffer[framed-0]
+%D \setupframedtexts
+%D [frame=off,
+%D width=\hsize,
+%D background=screen]
+%D
+%D \startframedtext
+%D By default the framed text is centered \dots
+%D \stopframedtext
+%D
+%D \startframedtext[right]
+%D \dots\ but we can also align left, middle and right.
+%D \stopframedtext
+%D \stopbuffer
+%D
+%D \startbuffer[framed-1]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm,
+%D height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-1]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-2]
+%D \defineframedtext
+%D [Example]
+%D [width=6cm]
+%D
+%D \startExample
+%D \typebuffer[framed-2]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-3]
+%D \defineframedtext
+%D [Example]
+%D [height=5cm]
+%D
+%D \startExample
+%D \typebuffer[framed-3]
+%D \stopExample
+%D \stopbuffer
+%D
+%D \startbuffer[framed-4]
+%D \defineframedtext
+%D [Example]
+%D [width=fit,height=broad]
+%D
+%D \Example{a very exciting example}
+%D \stopbuffer
+%D
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
+%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
+%D
+%D Here we can see that we have a predefined framed text class
+%D as well as the tools for defining our own. So we have:
+%D
+%D \showsetup{setupframedtexts}
+%D
+%D as well as the definition command:
+%D
+%D \showsetup{defineframedtext}
+%D
+%D that generates two commands:
+%D
+%D \showsetup{start<<framedtext>>}
+%D \showsetup{<<framedtext>>}
+%D
+%D The next definition shows the defaults.
+
+\def\dodefineframedtext[#1][#2]%
+ {\presetlocalframed[\??kd#1]%
+ \getparameters[\??kd#1]
+ [\c!width=0.75\hsize,
+ \c!height=\v!fit,
+ \c!align=\v!yes,
+ \c!top=,
+ \c!bottom=\vfill,
+ \c!offset=1em,
+ \c!bodyfont=,
+ \c!style=,
+ \c!color=,
+ \c!left=,
+ \c!right=\hfill,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!inner=,
+ \c!frame=\v!on,
+ \c!topframe=,
+ \c!bottomframe=,
+ \c!leftframe=,
+ \c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!foregroundcolor=,
+ \c!foregroundstyle=,
+ \c!background=,
+ \c!backgroundcolor=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!linecorrection=\v!on,
+ \c!depthcorrection=\v!on,
+ \c!margin=\v!standard,
+ \c!orientation=,
+ \c!indenting=,
+ #2]%
+ \setvalue{\e!start#1}{\dostartframedtext[#1]}%
+ \setvalue{\e!stop #1}{\dostopframedtext }%
+ \setvalue {#1}{\doframedtext [#1]}}
+
+\def\defineframedtext
+ {\dodoubleempty\dodefineframedtext}
+
+%D We define the general (and original) case by just saying:
+
+\defineframedtext[\v!framedtext]
+
+%D We need several steps before the actual job is done,
+%D because we have to handle an optional identifier (and
+%D because these commands evolved out of a single case).
+
+\def\framedtextparameter#1#2%
+ {\csname\??kd#1#2\endcsname}
+
+\def\dosetupframedtexts[#1][#2]%
+ {\ifsecondargument
+ \def\docommand##1{\getparameters[\??kd##1][#2]}%
+ \processcommacommand[#1]\docommand % new, #1 may be macro
+ \else
+ \getparameters[\??kd\v!framedtext][#1]%
+ \fi}
+
+\def\setupframedtexts
+ {\dodoubleempty\dosetupframedtexts}
+
+\def\dostartframedtext
+ {\bgroup\dotripleempty\dodostartframedtext}
+
+\def\dodostartframedtext[#1][#2][#3]%
+ {\doifassignmentelse{#2}
+ {\dododostartframedtext[#1][][#2]}
+ {\dododostartframedtext[#1][#2][#3]}}
+
+\setfalse\framedtextlocationnone
+
+\def\dododostartframedtext[#1][#2][#3]% #3 only passed to framed, not to framedtext
+ {\doifsomething{#2}{\setvalue{\??kd#1\c!location}{#2}}% does not listen to #3
+ \setfalse\framedtextlocationnone
+ \processaction % \v!low en \v!depth are already taken !
+ [\framedtextparameter{#1}\c!location]
+ [ \v!left=>\letvalue{\??kd#1\c!left }\relax
+ \letvalue{\??kd#1\c!right}\hfill,
+ \v!right=>\letvalue{\??kd#1\c!left }\hfill
+ \letvalue{\??kd#1\c!right}\relax,
+ \v!middle=>\letvalue{\??kd#1\c!left }\hfill
+ \letvalue{\??kd#1\c!right}\hfill,
+ \v!none=>\letvalue{\??kd#1\c!left }\relax % new
+ \letvalue{\??kd#1\c!right}\relax % new
+ \settrue\framedtextlocationnone]%
+ \letvalue{\??kd#1\c!location}\empty
+ % removed 06/2001
+ % \forgetparindent
+ % added 06/2001 [see demo-bbv]
+ \localhsize\hsize \checkframedtext
+ % so far
+ \setbox\framebox\vbox
+ \startboxedcontent
+ \hsize\localhsize
+ % \insidefloattrue % ? better
+ \normalexpanded{\noexpand\switchtobodyfont[\framedtextparameter{#1}\c!bodyfont]}%
+ \startcolor[\framedtextparameter{#1}\c!color]%
+ \localframed[\??kd#1][\c!strut=\v!no,#3]% todo: use delayedstrut
+ \bgroup
+ \let\\=\endgraf
+ \framedtextparameter{#1}\c!inner % oud spul
+ \doifvalue{\??kd#1\c!depthcorrection}\v!on % new, inside box
+ {\bgroup
+ \verticalstrut
+ % we need \nowhitespace in case of setups setting whitespace
+ % nb, not safe, text vs \vbox as next
+ \vskip-\struttotal
+ \nowhitespace % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})
+ }%
+ \doinhibitblank % \blank[\v!disable]% plaatst signal
+\setupindenting[\framedtextparameter{#1}\c!indenting]%
+ \doconvertfont{\framedtextparameter{#1}\c!style}\empty
+ \def\dostopframedtext{\dodostopframedtext{#1}{#2}}}
+
+%D The \type {none} option is handy for nested usage, as
+%D in the presentation styles, where we don't want
+%D interference.
+
+\def\dodostopframedtext#1#2% % no \baselinecorrection, see faq docs
+ {\endgraf
+ \removelastskip
+ \doifvalue{\??kd#1\c!depthcorrection}\v!on % local and global
+ {\forgetall
+ \vskip-\struttotal
+ \verticalstrut
+ \egroup
+ \forgetall
+ \vskip-\lineheight
+ % will be an option, not default
+ % \setbaselinecorrections
+ % \donegbotbaselinecorrection
+ \verticalstrut}
+ \stopboxedcontent
+ \stopcolor
+ \ifconditional\framedtextlocationnone
+ \egroup
+ \box\framebox
+ \else\ifinsidefloat
+ \egroup
+ \box\framebox
+ \else
+ \egroup
+ \doplacement[\??kd#1][\c!depthcorrection=\v!off]{\box\framebox}%
+ \fi\fi
+ \egroup}
+
+%D Placement can be ignored:
+%D
+%D \starttyping
+%D \hbox to \hsize \bgroup
+%D \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
+%D \startframedtext[none][width=.5\textwidth] \input zapf \stopframedtext
+%D \egroup
+%D
+%D \hbox to \hsize \bgroup
+%D \setupframedtexts[location=none]%
+%D \startframedtext[width=.5\textwidth] \input zapf \stopframedtext
+%D \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
+%D \egroup
+%D \stoptyping
+
+%D The simple brace (or group) delimited case is typeset
+%D slightly different and is not aligned.
+
+\def\doframedtext
+ {\bgroup\dodoubleempty\dodoframedtext}
+
+\def\dodoframedtext[#1][#2]% beware!
+ {\normalexpanded{\noexpand\switchtobodyfont[\getvalue{\??kd#1\c!bodyfont}]}%
+ \localframed[\??kd#1][\c!strut=\v!no,#2]%
+ \bgroup
+ \blank[\v!disable]%
+ \let\\=\endgraf
+ \getvalue{\??kd#1\c!inner}% % kleur naar outer level
+ \dostartattributes{\??kd#1}\c!style\c!color\empty
+ \bgroup
+ \aftergroup\docloseframedtext
+ \let\next=}
+
+\def\docloseframedtext
+ {\removelastskip
+ \dostopattributes
+ \egroup
+ \egroup}
+
+%D \macros
+%D {defineframed}
+%D
+%D One can also define simple framed texts, using:
+%D
+%D \showsetup{defineframed}
+
+\def\defineframed
+ {\dodoubleempty\dodefineframed}
+
+\def\dodefineframed[#1][#2]%
+ {\iffirstargument
+ \setvalue{#1}{\dodoubleempty\doframed[#2]}%
+ \fi}
+
+\def\doframed[#1][#2]%
+ {\framed[#1,#2]}
+
+%D \macros
+%D {textrule, starttextrule, setuptextrules}
+%D
+%D Putting rules before and after a paragraph is very space
+%D sensitive, but the next command handles that quite well. It
+%D comes in two disguises:
+%D
+%D \startbuffer
+%D \textrule[top]{fragments}
+%D \input reich
+%D \textrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D \startbuffer
+%D \setuptextrules
+%D [width=90pt,distance=12pt,rulecolor=blue,
+%D bodyfont=small,style=\sc,color=red]
+%D
+%D \starttextrule{Ship Building Tools}
+%D \nl \setuptolerance[tolerant] \input materie
+%D \stoptextrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D \startbuffer
+%D \setuptextrules
+%D [location=inmargin,
+%D bodyfont=small,style=slantedbold]
+%D
+%D \starttextrule{wonderful}
+%D \input tufte
+%D \stoptextrule
+%D \stopbuffer
+%D
+%D \bgroup \typebuffer \getbuffer \egroup
+%D
+%D The formal definition of these commands is:
+%D
+%D \showsetup{textrule}
+%D \showsetup{starttextrule}
+%D \showsetup{setuptextrules}
+%D
+%D The implementation looks a bit complicated due to the
+%D optional arguments.
+
+\def\setuptextrules
+ {\dodoubleargument\getparameters[\??tl]}
+
+\def\complextextrule[#1]% if needed we can make it installable
+ {\let\next\dobottomtextrule
+ \processaction
+ [#1]
+ [ \v!top=>\let\next\dotoptextrule,
+ \v!middle=>\let\next\domiddletextrule,
+ \v!bottom=>\let\next\dobottomtextrule]%
+ \dosinglegroupempty\next}
+
+\definecomplexorsimple\textrule
+
+\def\simpletextrule
+ {\dosinglegroupempty\dounknowntextrule}
+
+\def\docomplextextrule#1%
+ {\bgroup
+ \advance\hsize\dimexpr-\rightskip-\leftskip\relax
+ \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
+ \color[\@@tlrulecolor]
+ {\leaders\hrule\!!height\dimen4\!!depth\dimen6\hfill}}%
+ \ht\scratchbox\strutht
+ \dp\scratchbox\strutdp
+ \noindent\box\scratchbox
+%\nobreak\verticalstrut\kern-\struttotal
+% evt \witruimte
+ \egroup}
+
+\def\dotoptextrule#1%
+ {\page[\v!preference] % interferes
+ %\whitespace % no
+ \@@tlbefore
+ \docomplextextrule{#1}%
+% todo, option: \doifnothing{#1}{\ruledvskip-.5ex}
+ \nowhitespace
+ \@@tlinbetween
+ \endgraf}
+
+\def\dodobottomtextrule#1#2%
+ {\ifhmode
+ \endgraf
+ \fi
+ \dimen0\strutdp
+ \ifdim\prevdepth>\strutdp\else % was <\strutdp
+ \ifdim\prevdepth>\zeropoint
+ \advance\dimen0 -\prevdepth
+ \fi
+ \fi
+ \advance\dimen0 .5ex
+ \vskip\dimen0
+% ==
+% \vskip\dimexpr \strutdp + .5ex
+% \ifdim\prevdepth>\strutdp\else\ifdim\prevdepth>\zeropoint-\prevdepth\fi\fi\relax
+%
+ \@@tlinbetween
+ \doifelsenothing{#2}
+ {\bgroup
+ \advance\hsize\dimexpr-\rightskip-\leftskip\relax
+ \nointerlineskip
+ \moveleft-\leftskip\vbox
+ {\color[\@@tlrulecolor]
+ {\hrule\!!depth\linewidth\!!height\zeropoint\!!width\hsize}}%
+ \egroup}
+ {\docomplextextrule{#2}}%
+ \ifvmode\prevdepth\zeropoint\fi
+ #1%
+ \page[\v!preference]}
+
+\def\dobottomtextrule
+ {\dodobottomtextrule\@@tlafter}
+
+\def\domiddletextrule
+ {\dodobottomtextrule\@@tlinbetween}
+
+\def\dounknowntextrule
+ {\iffirstargument
+ \@EA\dotoptextrule
+ \else
+ \@EA\dobottomtextrule\@EA\empty
+ \fi}
+
+%D The grouped commands also supports bodyfont switching:
+
+\def\starttextrule#1%
+ {\bgroup
+ \def\dounknowntextrule{\domiddletextrule}
+ \dotoptextrule{#1}
+ \bgroup
+ \doifsomething\@@tlbodyfont{\switchtobodyfont[\@@tlbodyfont]}}
+
+\def\stoptextrule
+ {\par
+ \egroup
+ \dobottomtextrule\empty
+ \egroup}
+
+%D \macros
+%D {fillinrules, setupfillinrules}
+%D
+%D The next few commands do not really deserve a place in a
+%D core module, because they deal with specific typography.
+%D Nevertheless I decided to make them part of the core,
+%D because they permit us to make questionaires. Let's start
+%D with some examples.
+%D
+%D \fillinrules[n=2,width=fit]{first}
+%D \fillinrules[n=2,width=broad]{first}
+%D \fillinrules[n=2,width=3cm]{first}
+%D \fillinrules[n=2,width=3cm,distance=.5em,separator=:]{first}
+%D \fillinrules[n=2]{first}{last}
+%D \fillintext{first}{last} \input reich \par
+%D
+%D The main command is \type{\fillinrules}. This command takes
+%D one and an optional second argument and sets a paragraph with
+%D empty visualized lines.
+%D
+%D \showsetup{fillinrules}
+%D \showsetup{setupfillinrules}
+
+\def\setupfillinrules
+ {\dodoubleargument\getparameters[\??il]}
+
+\definecomplexorsimpleempty\fillinrules
+
+\def\complexfillinrules[#1]%
+ {\def\docomplexfillinrules##1##2%
+ {\dodocomplexfillinrules[#1]{##1}{##2}{\thinrules
+ [\c!n=\@@iln,\c!interlinespace=\@@ilinterlinespace,\c!before=,\c!after=]}}%
+ \dodoublegroupempty\docomplexfillinrules}
+
+\def\dodocomplexfillinrules[#1]#2#3#4%
+ {\endgraf
+ \@@ilbefore
+ \begingroup
+ \setupfillinrules[#1]%
+ \noindent
+ \doifsomething{#2}
+ {\doifelse\@@ilwidth\v!fit
+ {\let\@@ildistance\!!zeropoint
+ \hbox}
+ {\doifelse\@@ilwidth\v!broad
+ {\hbox}
+ {\hbox to \@@ilwidth}}%
+ \bgroup
+ \doattributes\??il\c!style\c!color{\strut#2\hfill\@@ilseparator}%
+ \hskip\@@ildistance
+ \egroup}%
+ %\hangindent=\wd0\relax % tzt hang=yes,n
+ %\parindent=\hangindent
+ %\box0\relax
+ \setupwhitespace[\v!big]%
+ \ignorespaces
+ #4%
+ \doifsomething{#3}
+ {\kern\@@ildistance
+ \doattributes\??il\c!style\c!color{#3\strut}}%
+ \endgroup
+ \endgraf
+ \@@ilafter}
+
+%D \macros
+%D {fillintext}
+%D
+%D To provide compatible layouts when texts and lines are
+%D mixed, one can typeset a paragraph by using the command
+%D \type{\fillintext}.
+%D
+%D \showsetup{fillintext}
+
+\definecomplexorsimpleempty\fillintext
+
+\def\complexfillintext[#1]% rather rough, using an \unhbox is suboptimal
+ {\def\docomplexfillintext##1##2%
+ {\dowithnextbox
+ {\dodocomplexfillinrules[#1]{##1}{\hfill##2}{\unhbox\nextbox\unskip}}%
+ \hbox\bgroup\let\par\egroup\ignorespaces}%
+ \dodoublegroupempty\docomplexfillintext}
+
+%D \macros
+%D {fillinline, setupfillinlines}
+%D
+%D Another member of the family takes care of putting a (often
+%D small) rule after a piece of text, like
+%D
+%D \startbuffer
+%D \fillinline \input reich \par
+%D \fillinline[margin=0cm] \input reich \par
+%D \stopbuffer
+%D
+%D \startvoorbeeld
+%D \getbuffer
+%D \stopvoorbeeld
+%D
+%D which was typeset by saying:
+%D
+%D \typebuffer
+%D
+%D The two commands that take care of this are:
+%D
+%D \showsetup{fillinline}
+%D \showsetup{setupfillinlines}
+
+\def\setupfillinlines
+ {\dodoubleargument\getparameters[\??iv]}
+
+\definecomplexorsimpleempty\fillinline
+
+\def\complexfillinline[#1]%
+ {%\endgraf % interferes with \definedescription cum suis
+ \@@ivbefore
+ \begingroup
+ \setupfillinlines[#1]%
+ \advance\rightskip \@@ivmargin
+ \parfillskip\zeropoint
+ \def\par % very dangerous
+ {\let\par\endgraf % -)
+ \ifhmode\unskip\hfill\fi
+ \scratchdimen\dimexpr\@@ivwidth-\@@ivdistance\relax
+ \ifdim\scratchdimen>\@@ivmargin\else\expandafter\rlap\fi
+ {\kern\@@ivdistance
+ \vrule
+ \!!width \scratchdimen
+ \!!height.5\linewidth
+ \!!depth .5\linewidth}%
+ \endgraf % !
+ \endgroup
+ \endgraf % !
+ \@@ilafter}}
+
+%D \stopdocumentation
+%D \bgroup
+%D
+%D \setupframedtexts
+%D [setuptext]
+%D [background=color,backgroundcolor=white]
+%D
+%D \startbuffer
+%D \setupbackground
+%D [backgroundoffset=4pt,
+%D background=screen,
+%D frame=on,
+%D framecolor=red,
+%D leftoffset=2pt]
+%D \stopbuffer
+%D
+%D \getbuffer
+%D
+%D \startbackground
+%D
+%D \macros
+%D {setupbackground,startbackground,background}
+%D
+%D The section deals with backgrounds in the running text. This
+%D means that texts is to be collected and split over pages. To
+%D show what can be done, we provide this part of the
+%D documentation with some gray background and a red frame.
+%D Both the background and frame can have all characteristics
+%D of \type{\framed}. This time we used the setting:
+%D
+%D \typebuffer
+%D
+%D The implementation is not that sophisticated, but suffices.
+%D The main problem with this kind of functionality is to get
+%D the spacing all right.
+
+%D Specifying the background is more or less the same as
+%D specifying a framed box.
+%D
+%D \showsetup{setupbackground}
+
+\presetlocalframed[\??ag]
+
+\def\dosetupbackground[#1]%
+ {\getparameters[\??ag][#1]%
+ \doifelse\@@agstate\v!start
+ {\let\startbackground\dostartbackground
+ \let\stopbackground \dostopbackground
+ \let\background \dobackground}
+ {\let\startbackground\relax
+ \let\stopbackground \relax
+ \let\background \relax}}
+
+\def\setupbackground
+ {\dosingleargument\dosetupbackground}
+
+%D Actually typesetting the background is implemented rather
+%D straightforward. We need to handle some spacing as well as
+%D the (often) a bit smaller horizontal size.
+%D
+%D \showsetup{startbackground}
+%D
+%D Although we could have used a scratch one, we first
+%D declare a boolean.
+
+% 0=no-split, 1=no-split+indent, 2=split, 3=split+indent
+
+\chardef\backgroundsplitmode\plusthree
+
+%D The \type{\vbox to \lineheight{}\vskip\zeropoint}
+%D construction gives the first real line a decent height by
+%D adding a dummy line.
+
+\def\dostartbackground
+ {\endgraf
+ \bgroup
+ \setbox0\vbox\bgroup
+ \vbox to \lineheight{}\vskip\zeropoint
+ \blank[\v!disable]
+ % \advance\hsize -\@@agleftoffset
+ % \advance\hsize -\@@agrightoffset
+ \leftskip \@@agleftoffset % new **
+ \rightskip\@@agrightoffset} % new **
+
+%D This dummy line is removed by \type{\setbox2=\vsplit0 to
+%D \lineheight}. That way \type{\topskip} takes care of the
+%D lineheight. I'll probably forget to apply this trick
+%D elsewhere.
+
+\def\dostopbackground % improved version (i hope)
+ {\endgraf
+ \removelastskip
+ \egroup
+ \dimen2\leftskip % new **
+ \forgetall
+ \ifinsidefloat
+ \chardef\backgroundsplitmode\zerocount
+ \fi
+ \ifcase\backgroundsplitmode
+ \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
+ \or
+ \hskip\dimen2
+ \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
+ \else
+ \splitmaxdepth\boxmaxdepth
+ \splittopskip\topskip
+ \setbox2\vsplit0 to \lineheight % get rid of fake line
+ \loop
+ \ifdim\pagetotal=\zeropoint % empty page
+ \scratchdimen\textheight
+ \chardef\backgroundsplit\plusone % split to max height
+ \else
+ \setbox\scratchbox\vbox{\@@agbefore}%
+ \scratchdimen\dimexpr\pagegoal-\ht\scratchbox-\pagetotal\relax
+ \chardef\backgroundsplit\plustwo % split to partial height
+ \fi
+ \advance\scratchdimen\dimexpr-\@@agtopoffset-\@@agbottomoffset\relax
+ \ifdim\scratchdimen>2\lineheight\relax % reasonable, will be configurable
+ \ifdim\ht0>\scratchdimen % larger than page
+ \setbox2\vsplit0 to \scratchdimen
+ \else
+ \setbox2\box0
+ \chardef\backgroundsplit\zerocount % no split
+ \fi
+ \setbox2\vbox \ifcase\backgroundsplit\or to \textheight \fi % max split
+ {\vskip\@@agtopoffset
+ \popsplitproperties
+ \unvcopy2
+ \prevdepth\dp2
+ \obeydepth
+ \vskip\@@agbottomoffset
+ \vfill}
+ \@@agbefore
+ \ifcase\backgroundsplit\or\or % partial split
+ \ifdim\pagegoal<\maxdimen
+ \pagegoal=1.2\pagegoal % be a bit more tolerant
+ \fi
+ \fi
+ \startlinecorrection
+ %\localframed[\??ag][\c!offset=\v!overlay]{\hskip\@@agleftoffset\box2\hskip\@@agrightoffset}%
+ \ifnum\backgroundsplitmode=\plusthree \hskip\dimen2 \fi %
+ \localframed[\??ag][\c!offset=\v!overlay]{\box2}% new **
+ \stoplinecorrection
+ \ifcase\backgroundsplit % no split
+ \@@agafter
+ \else % some split
+ \vfill\eject % geen \page !
+ \fi
+ \else
+ \page
+ \fi
+ \ifdim\ht0>\zeropoint \repeat
+ \fi
+ \egroup
+ \endgraf}
+
+%D As a bonus we also have a short command, that is of not
+%D much use, but kept there for historic reasons.
+%D
+%D \showsetup{background}
+
+\def\dobackground
+ {\bgroup
+ \dowithnextbox
+ {\localframed[\??ag][\c!offset=\v!overlay]{\flushnextbox}\egroup}
+ \vbox}
+
+%D \stopdocumentation
+%D \stopbackground
+%D \egroup
+
+%D New, for the moment private; let's see when GB finds out
+%D about this one and its obscure usage. It's used in:
+%D
+%D \startbuffer
+%D \defineframedtext
+%D [tabulateframe]
+%D [offset=overlay,
+%D backgroundoffset=3pt,
+%D background=color,
+%D backgroundcolor=green]
+%D
+%D \setuptabulate
+%D [tabulate]
+%D [frame=tabulateframe]
+%D
+%D \setuptables
+%D [frame=tabulateframe]
+%D
+%D \input tufte
+%D
+%D \starttabulate[|l|l|]
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
+%D \stoptabulate
+%D
+%D \input tufte
+%D
+%D \starttable[|l|l|]
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
+%D \stoptable
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\def\defineframedcontent
+ {\dodoubleempty\dodefineframedcontent}
+
+\def\dodefineframedcontent[#1][#2]%
+ {\presetlocalframed[\??fc#1]%
+ \getparameters[\??fc#1]
+ [\c!leftoffset=\zeropoint,
+ \c!rightoffset=\getvalue{\??fc#1\c!leftoffset},
+ \c!topoffset=\zeropoint,
+ \c!bottomoffset=\getvalue{\??fc#1\c!topoffset},
+ \c!strut=\v!no,
+ \c!offset=\v!overlay,
+ \c!linecorrection=\v!no,
+ \c!left=,
+ \c!right=,
+ #2]}
+
+\let\setuplocalframed\getparameters
+
+\def\setupframedcontent
+ {\dodoubleempty\dosetupframedcontent}
+
+\def\dosetupframedcontent[#1][#2]%
+ {\def\docommand##1{\getparameters[\??fc##1][#2]}%
+ \processcommacommand[#1]\docommand}
+
+\def\startframedcontent[#1]%
+ {\bgroup
+ \let\stopframedcontent\egroup
+ \doifnot{#1}\v!off
+ {\doifdefined{\??fc#1\c!frame}
+ {\def\stopframedcontent{\dostopframedcontent{#1}}%
+ \dostartframedcontent{#1}}}}
+
+\def\dostartframedcontent#1%
+ {\setbox\framebox\hbox\bgroup
+ \setlocalhsize
+ \hsize\localhsize
+ \advance\hsize\dimexpr-\getvalue{\??fc#1\c!leftoffset}-\getvalue{\??fc#1\c!rightoffset} \relax
+ \advance\vsize\dimexpr-\getvalue{\??fc#1\c!topoffset} -\getvalue{\??fc#1\c!bottomoffset}\relax
+ \hskip\getvalue{\??fc#1\c!leftoffset}%
+ \vbox\bgroup
+ \vskip\getvalue{\??fc#1\c!topoffset}%
+ \vbox\bgroup
+ \forgetall
+ \blank[\v!disable]}
+
+\def\dostopframedcontent#1%
+ {\removelastskip
+ \egroup
+ \vskip\getvalue{\??fc#1\c!bottomoffset}%
+ \egroup
+ \hskip\getvalue{\??fc#1\c!rightoffset}%
+ \egroup
+ \doifvalue{\??fc#1\c!width}\v!fit
+ {\letvalue{\??fc#1\c!width}\v!fixed}% no shapebox
+ \ifinsidefloat
+ \donefalse
+ \else
+ \doifelsevalue{\??fc#1\c!linecorrection}\v!yes\donetrue\donefalse
+ \fi
+ % plaats ?
+ \ifdone\startlinecorrection\fi
+ \getvalue{\??fc#1\c!left}% new
+ \localframed[\??fc#1]{\box\framebox}%
+ \getvalue{\??fc#1\c!right}% new
+ \ifdone\stoplinecorrection\fi
+ \egroup}
+
+%D \macros
+%D {backgroundline}
+%D
+%D For the moment an undocumented feature, but a cancidate
+%D for going public.
+
+\def\backgroundline[#1]%
+ %{\doifsomething{#1}{\dobackgroundline{#1}}\hbox}
+ {\doifcolorelse{#1}{\dobackgroundline{#1}\hbox}\hbox}
+
+% \def\backgroundline[#1]%
+% {\doifcolor{#1}{\dobackgroundline{#1}}\hbox}
+
+\def\dobackgroundline#1%
+ {\dowithnextbox
+ {\hbox
+ {\localcolortrue
+ \startcolor[#1]%
+ \vrule
+ \!!width \nextboxwd
+ \!!height\nextboxht
+ \!!depth \nextboxdp
+ \stopcolor
+ \hskip-\nextboxwd
+ \flushnextbox}}}
+
+%D \macros
+%D {encircled}
+%D
+%D Some not so robust left||overs (borrowed from Knuth,
+%D \TEX Book\ page 356):
+
+\def\encircled#1%
+ {{\ooalign{\hfil\raise0.07ex\hbox{{\tx#1}}\hfil\crcr\mathhexbox20D}}}
+
+\let\omcirkeld\encircled
+
+\setuplinewidth
+ [\v!medium]
+
+\setupframed
+ [\c!width=\v!fit,
+ \c!height=\v!broad,
+ \c!lines=,
+ \c!offset=0.25ex, % \defaultframeoffset
+ \c!empty=\v!no,
+ \c!frame=\v!on,
+ \c!topframe=,
+ \c!bottomframe=,
+ \c!leftframe=,
+ \c!rightframe=,
+ \c!radius=.5\bodyfontsize,
+ \c!rulethickness=\linewidth,
+ \c!corner=\v!rectangular,
+ \c!depth=\!!zeropoint,
+ \c!foregroundcolor=,
+ \c!foregroundstyle=,
+ \c!background=,
+ \c!backgroundscreen=\@@rsscreen,
+ \c!backgroundcolor=,
+ \c!backgroundoffset=\!!zeropoint,
+ \c!framecolor=,
+ \c!frameoffset=\!!zeropoint,
+ \c!backgroundcorner=\framedparameter\c!corner,
+ \c!backgroundradius=\framedparameter\c!radius,
+ \c!backgrounddepth=\framedparameter\c!depth,
+ \c!framecorner=\framedparameter\c!corner,
+ \c!frameradius=\framedparameter\c!radius,
+ \c!framedepth=\framedparameter\c!depth,
+ \c!component=,
+ \c!align=,
+ \c!bottom=\vss,
+ \c!top=,
+ \c!strut=\v!yes,
+ \c!autostrut=\v!yes,
+ \c!location=\v!normal,
+ \c!orientation=,
+ \c!autowidth=\v!yes,
+ \c!setups=]
+
+\setupscreens
+ [%\c!factor=1.0, % obsolete
+ %\c!method=\v!external, % obsolete
+ \c!screen=0.95]
+
+\setupblackrules
+ [\c!n=3,
+ \c!width=1em,
+ \c!height=1ex,
+ \c!depth=\!!zeropoint,
+ \c!alternative=\c!a,
+ \c!distance=.25ex,
+ \c!color=]
+
+\setupmarginrules
+ [\c!level=0,
+ \c!rulethickness=\@@kadefaultwidth\linewidth]
+
+\setupthinrules
+ [\c!interlinespace=\v!small,
+ \c!n=3,
+ \c!before=,
+ \c!inbetween={\blank[\v!white]},
+ \c!after=,
+ \c!color=,
+ \c!height=.5\linewidth,
+ \c!depth=.5\linewidth,
+ \c!frame=\v!on, % compatible with textbackgrounds
+ \c!alternative=\v!b,
+ \c!backgroundcolor=,
+ \c!background=,
+ \c!rulethickness=]
+
+\setuptextrules
+ [\c!location=\v!left,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!inbetween=,
+ \c!width=2em,
+ \c!style=\v!bold,
+ \c!color=,
+ \c!rulecolor=,
+ \c!bodyfont=,
+ \c!distance=.5em]
+
+\setupfillinrules
+ [\c!width=\v!broad,
+ \c!distance=1em,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!n=1,
+ \c!interlinespace=\v!small,
+ \c!separator=,
+ \c!style=\v!normal,
+ \c!color=]
+
+\setupfillinlines
+ [\c!width=3cm,
+ \c!margin=\@@ivwidth,
+ \c!distance=1em,
+ \c!before=\blank,
+ \c!after=\blank]
+
+\setupbackground
+ [\c!leftoffset=.5\bodyfontsize,
+ \c!rightoffset=\@@agleftoffset,
+ \c!topoffset=\!!zeropoint,
+ \c!bottomoffset=\@@agtopoffset,
+ \c!state=\v!start,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!frame=\v!off,
+ \c!color=,
+ \c!depth=\!!zeropoint,
+ \c!background=\v!screen,
+ \c!backgroundcolor=\@@agcolor,
+ \c!screen=\@@rsscreen,
+ \c!before=,
+ \c!after=]
+
+% Experimental extension:
+
+\def\c!loffset{loffset}
+\def\c!roffset{roffset}
+\def\c!toffset{toffset}
+\def\c!boffset{boffset}
+
+\getparameters
+ [\??oi]
+ [\c!loffset=\zeropoint,
+ \c!roffset=\zeropoint,
+ \c!toffset=\zeropoint,
+ \c!boffset=\zeropoint]
+
+\newdimen\!!framedloffset
+\newdimen\!!framedroffset
+\newdimen\!!framedtoffset
+\newdimen\!!framedboffset
+
+\def\setextraframedoffsets
+ {\boxhasextraoffsetfalse
+ \!!framedloffset\framedparameter\c!loffset
+ \!!framedroffset\framedparameter\c!roffset
+ \!!framedtoffset\framedparameter\c!toffset
+ \!!framedboffset\framedparameter\c!boffset
+ \ifzeropt\!!framedloffset\else \advance\!!framedwidth -\!!framedloffset \boxhasextraoffsettrue \fi
+ \ifzeropt\!!framedroffset\else \advance\!!framedwidth -\!!framedroffset \boxhasextraoffsettrue \fi
+ \ifzeropt\!!framedtoffset\else \advance\!!framedheight-\!!framedtoffset \boxhasextraoffsettrue \fi
+ \ifzeropt\!!framedboffset\else \advance\!!framedheight-\!!framedboffset \boxhasextraoffsettrue \fi}
+
+\def\applyextraframedoffsets
+ {\setbox\framebox\vbox\bgroup
+ \vskip\!!framedtoffset
+ \hbox\bgroup
+ \hskip\!!framedloffset
+ \box\framebox
+ \hskip\!!framedroffset
+ \egroup
+ \vskip\!!framedboffset
+ \egroup}
+
\protect \endinput
diff --git a/tex/context/base/core-rul.tex b/tex/context/base/core-rul.tex
deleted file mode 100644
index f9386d560..000000000
--- a/tex/context/base/core-rul.tex
+++ /dev/null
@@ -1,3590 +0,0 @@
-%D \module
-%D [ file=core-rul,
-%D version=1998.10.16,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Ruled Stuff Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Ruled Content Handling}
-
-\loadmarkfile{core-rul}
-
-\unprotect
-
-%D We have removed the rather old and out dated raster methods. They
-%D have not been used for ages.
-
-%D \macros
-%D {linewidth, setuplinewidth}
-%D
-%D This module deals with rules (lines) in several ways. First
-%D we introduce two macros that can be used to set some common
-%D characteristics.
-%D
-%D \showsetup{setuplinewidth}
-%D
-%D The linewidth is available in \type{\linewidth}. The
-%D preset value of .4pt equals the default hard coded \TEX\
-%D rule width.
-
-\newdimen\linewidth
-
-\def\dosetuplinewidth[#1]%
- {\assigndimension{#1}\linewidth{.2\points}{.4\points}{.6\points}}
-
-\def\setuplinewidth
- {\dosingleargument\dosetuplinewidth}
-
-%D \macros
-%D {ruledlinewidth, inheritruledlinewidth}
-%D
-%D Inside framed boxed we will use a private dimensions. As
-%D an option one can let the linewidth inherit its value from
-%D this one.
-
-\newdimen\ruledlinewidth \newif\ifinheritruledlinewidth
-
-% %D \TEX\ lacks support for color and even gray scales. The next
-% %D macros can provide a sort of poor mans gray scales as well
-% %D as give access to more suitable methods of rendering. Such a
-% %D method looks like:
-% %D
-% %D \starttyping
-% %D \def\methodegraybox#1#2#3#4#5#6%
-% %D { ... }
-% %D \stoptyping
-% %D
-% %D The string \type{graybox} is a common element in the name,
-% %D so we can have for instance \type {\postscriptgraybox} or
-% %D \type {\texgraybox}. The first three arguments take a
-% %D dimension, the fourth one takes a number between~0 and~1,
-% %D and the last argument specifies a radius of the box when
-% %D rounded corners are used, so:
-% %D
-% %D \startbuffer
-% %D \dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}
-% %D \stopbuffer
-% %D
-% %D \typebuffer
-% %D
-% %D becomes:
-% %D
-% %D %\startlinecorrection
-% %D % \vbox to 1cm{\getbuffer}
-% %D %\stoplinecorrection
-% %D
-% %D \startlinecorrection
-% %D \unprotect
-% %D \vbox to 1cm{\dotgraybox{.5\hsize}{1cm}{0cm}{.85}{\v!no}{0pt}}
-% %D \protect
-% %D \stoplinecorrection
-% %D
-% %D There are two predefined methodes, one uses periods and the
-% %D other uses small rules. The second method is less
-% %D efficient, but sometimes give better results. The dimensions
-% %D of the resullting box are set to zero.
-%
-% \setvalue{\v!dot graybox}{\processraster\symbol\rasterdot}
-% \setvalue{\v!rule graybox}{\processraster\symbol\rasterbox}
-%
-% \def\rasterdot{\rasterfont.}
-% \def\rasterbox{\hss\vrule\!!width.4pt\!!height.4pt\!!depth\zeropoint}
-%
-% %D Now of course we need:
-%
-% \ifx\rasterfont\undefined \def\rasterfont{\fivepoint} \fi
-%
-% %D We implement two pure \TEX\ based generators, that use
-% %D \type{\leaders} to quickly gerenate the gray pattern. One
-% %D should beware of \DIMENSION\ conflicts, so we use some
-% %D registers above~8. These macros are memory hungry and byte
-% %D spoiling.
-%
-% \def\processraster#1#2#3#4#5#6#7%
-% {\bgroup
-% \forgetall
-% \dontcomplain
-% \dimen10=\onepoint
-% \dimen10=\@@rsfactor\dimen10
-% \dimen10=#5\dimen10
-% \setbox2\hbox to #2
-% {\cleaders\hbox to 2\dimen10{#1\hss}\hss}%
-% \dimen12=#3%
-% \advance\dimen12 #4%
-% % \setbox0\vbox to \dimen12
-% {\cleaders\vbox to 2\dimen10{\box2\vss}\vss}%
-% \setbox0\hbox
-% {\hskip-.5\dimen10\lower0.5\dimen10\copy0
-% \hskip-\wd0\hskip\dimen10\lower1.5\dimen10\box0}%
-% \box0
-% \egroup}
-
-%D \macros
-%D {setupscreens}
-%D
-%D The previous macro uses a predefined constant
-%D \type{\@@rsfactor}. This factor can be set by:
-%D
-%D \showsetup{setupscreens}
-
-\def\setupscreens
- {\dodoubleargument\getparameters[\??rs]}
-
-% %D The most appropriate way to call for this feature is
-% %D using \type{\graybox}, which is defined as:
-%
-% \def\graybox{\getvalue{\@@rsmethod graybox}}
-%
-% %D We just introduced two pure \TEX\ methods for generating
-% %D rasters. However, it's far more efficient and comfortable in
-% %D terms of speed, memory usage and file size, to use a driver
-% %D supported method.
-%
-% \setvalue{\v!external graybox}{\setgraybox}
-%
-% %D For compatibility reasons we also define the original one:
-%
-% \setvalue{\v!postscript graybox}{\getvalue{\v!external graybox}}
-%
-% %D A quite valid way of letting drivers do the job, is giving
-% %D a solid rule a gray texture.
-
-%D We will communicate through module specific variables, current
-%D framed parameters and some reserved dimension registers.
-
-\newdimen \frameddimenwd
-\newdimen \frameddimenht
-\newdimen \frameddimendp
-
-%D We don't have to stick to a \TEX\ drawn rule, but
-%D also can use rounded or even fancier shapes, as we will
-%D see later on.
-
-\def\dofilledbox
- {\bgroup
- \doifelse{\framedparameter\c!backgroundcorner}\v!rectangular
- {\dofilledlinedbox}
- {\ifzeropt\dimexpr\framedparameter\c!backgroundradius\relax % just in case of .x\bodyfontsize
- \dofilledlinedbox
- \else
- \dofilledroundbox
- \fi}%
- \egroup}
-
-\def\dophantombox
- {\hphantom{\dofilledbox}}
-
-\def\dofilledlinedbox
- {\vrule\!!width\frameddimenwd\!!height\frameddimenht\!!depth\frameddimendp\relax}%
-
-\def\dostrokedroundbox
- {\doif{\framedparameter\c!frame}\v!on\dodostrokedroundbox}
-
-\def\dodostrokedroundbox
- {\bgroup
- \edef\ovalmod{\framedparameter\c!framecorner}%
- \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
- \edef\ovalwid{\the\frameddimenwd}%
- \edef\ovalhei{\the\frameddimenht}%
- \edef\ovaldep{\the\frameddimendp}%
- \edef\ovallin{\the\dimexpr\ruledlinewidth}%
- \edef\ovalrad{\the\dimexpr\framedparameter\c!frameradius}%
- \let\ovalstr\!!plusone
- \let\ovalfil\!!zerocount
- \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
- \egroup}
-
-\def\dofilledroundbox
- {\bgroup
- \edef\ovalmod{\framedparameter\c!backgroundcorner}%
- \doifelse\ovalmod\v!round{\let\ovalmod\!!zerocount}{\edef\ovalmod{\number\ovalmod}}%
- \edef\ovalwid{\the\frameddimenwd}%
- \edef\ovalhei{\the\frameddimenht}%
- \edef\ovaldep{\the\frameddimendp}%
- \edef\ovallin{\the\dimexpr\ruledlinewidth\relax}%
- \edef\ovalrad{\the\dimexpr\framedparameter\c!backgroundradius\relax}%
- \let\ovalstr\!!zerocount
- \let\ovalfil\!!plusone
- \doovalbox\ovalwid\ovalhei\ovaldep\ovallin\ovalrad\ovalstr\ovalfil\ovalmod
- \egroup}
-
-% a lot of weird corners
-%
-% \startTEXpage
-% \dontleavehmode\framed
-% [corner=0,frame=on,framecolor=green,
-% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green,
-% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green,
-% background=color,backgroundcolor=yellow]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse {1} {4}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse {5} {8}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse {9}{12}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse{13}{16}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse{17}{20}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse{21}{24}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \vskip1em
-% \dontleavehmode\dostepwiserecurse{25}{28}{1}{\framed
-% [corner=\recurselevel,frame=on,framecolor=green]{\tttf TEST \twodigits\recurselevel}%
-% \quad}
-% \stopTEXpage
-
-%D The oval box is drawn using a special macro, depending on
-%D the driver in use.
-
-\def\dograybox % avoid black rules when no gray
- {\doifelsenothing{\framedparameter\c!backgroundscreen}
- {\dophantombox}
- {\raster[\framedparameter\c!backgroundscreen]{\dofilledbox}}}
-
-%D It won't be a surprise that we not only provide gray boxes,
-%D but also colored ones. Here it is:
-
-\def\docolorbox
- {\hbox{\ifincolor
- \doifcolorelse{\framedparameter\c!backgroundcolor}
- {\localcolortrue\color[\framedparameter\c!backgroundcolor]{\dofilledbox}}
- {\dophantombox}%
- \else
- \dophantombox
- \fi}}
-
-%D \macros
-%D {defineoverlay, doifoverlayelse, overlayoffset,
-%D overlaywidth, overlayheight, overlaydepth,
-%D overlaycolor, overlaylinecolor, overlaylinewidth}
-%D
-%D Before we define the macro that actually takes card of the
-%D backgrounds, we introduce overlays. An overlay is something
-%D that contrary to its name lays {\em under} the text. An
-%D example of an overlay definition is:
-%D
-%D \startbuffer[tmp-1]
-%D \defineoverlay
-%D [fancy]
-%D [{\externalfigure
-%D [mp-cont.502]
-%D [width=\overlaywidth,
-%D height=\overlayheight]}]
-%D \stopbuffer
-%D
-%D \typebuffer[tmp-1]
-%D
-%D That for instance can be uses in:
-%D
-%D \startbuffer[tmp-2]
-%D \framed[backgroundachtergrond=fancy]{How Fancy!}
-%D \framed[backgroundachtergrond=fancy,frame=off]{Even More Fancy!}
-%D \stopbuffer
-%D
-%D and looks like:
-%D
-%D \startlinecorrection
-%D \vbox{\baselineskip24pt\getbuffer[tmp-1]\getbuffer[tmp-2]}
-%D \stoplinecorrection
-%D
-%D The formal definition is:
-%D
-%D \showsetup{defineoverlay}
-%D
-%D This macro's definition is a bit obscure, due the many
-%D non||used arguments and the two step call that enable the
-%D setting of the width, height and depth variables.
-%D Multiple backgrounds are possible and are specified as:
-%D
-%D \starttyping
-%D \framed[background={one,two,three}]{Three backgrounds!}
-%D \stoptyping
-%D
-%D Most drawing packages only know width and height. Therefore
-%D the dimensions have a slightly different meaning here:
-%D
-%D \startitemize[packed]
-%D \item \type{\overlaywidth }: width of the overlay
-%D \item \type{\overlayheight}: height plus depth of the overlay
-%D \item \type{\overlaydepth }: depth of the overlay
-%D \stopitemize
-%D
-%D The resulting box is lowered to the right depth.
-
-\def\overlaywidth {\the\hsize\space} % We preset the variables
-\def\overlayheight {\the\vsize\space} % to some reasonable default
-\let\overlaydepth \!!zeropoint % values. The attributes
-\let\overlayoffset \!!zeropoint % of the frame can be (are)
-\let\overlaycolor \empty % set somewhere else.
-\let\overlaylinewidth \!!zeropoint %
-\let\overlaylinecolor \empty %
-
-%D The next register is used to initialize overlays.
-
-\newtoks\everyoverlay
-
-%D An example of an initialization is the following (overlays
-%D can contain text and be executed under an regime where
-%D interlineskip is off).
-
-\appendtoks \oninterlineskip \to \everyoverlay
-
-\def\defineoverlay
- {\dodoubleargument\dodefineoverlay}
-
-\def\dodefineoverlay[#1][#2]%
- {\def\docommand##1{\setvalue{\??ov##1}{\executedefinedoverlay{##1}{#2}}}%
- \processcommalist[#1]\docommand}
-
-\prependtoks
- \hsize\overlaywidth
- \vsize\overlayheight
-\to\everyoverlay
-
-\long\def\executedefinedoverlay#1#2%
- {\bgroup
- \edef\overlaywidth {\the\frameddimenwd\space}%
- \edef\overlayheight{\the\dimexpr\frameddimenht+\frameddimendp\relax\space}%
- \edef\overlaydepth {\the\frameddimendp\space}%
- \edef\overlaycolor {\framedparameter\c!backgroundcolor}%
- %\edef\overlaycorner{\framedparameter\c!backgroundcorner}%
- %\edef\overlayradius{\framedparameter\c!backgroundradius}%
- \let\overlayoffset\backgroundoffset % we steal this one
- \setbox\scratchbox\hbox{\lower\overlaydepth\hbox{\the\everyoverlay#2}}%
- \setbox\scratchbox\hbox
- {\hskip-.5\dimexpr\wd\scratchbox-\overlaywidth \relax
- \raise-.5\dimexpr\ht\scratchbox-\frameddimenht\relax % not overlayheight !
- \box\scratchbox}%
- \wd\scratchbox\overlaywidth
- \ht\scratchbox\overlayheight
- \dp\scratchbox\overlaydepth
- \startlayoutcomponent{o:#1}{overlay #1}%
- \box\scratchbox
- \stoplayoutcomponent
- \egroup}
-
-%D The empty case is:
-
-\let\executeoverlay\gobblesevenarguments
-
-%D For testing we provide:
-
-\def\doifoverlayelse#1%
- {\doifdefinedelse{\??ov#1}}
-
-%D We predefine two already familiar backgrounds:
-
-\setvalue{\??ov\v!screen}{\dograybox }
-\setvalue{\??ov\v!color }{\docolorbox}
-
-% %D After all these preparations, the background macro does no
-% %D bring to many surprises. One has to keep in mind that this
-% %D macro starts up a call chain, depending on the background
-% %D one needs:
-% %D
-% %D \startitemize[packed]
-% %D \item a raster, color or user defined shape
-% %D \item square or round corners
-% %D \item a \TEX\ or driver based method
-% %D \stopitemize
-% %D
-% %D The macro can be extended by adding commands to the token
-% %D list register \type {\everybackgroundbox}. For this
-% %D purpose, the name of the current background is available in
-% %D \type {\currentbackgound}.
-
-\newbox\extraframebox
-
-\newtoks\everybackgroundbox
-
-\let\currentbackground\empty
-
-% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
-% {\bgroup
-% \def\currentbackground{#1}%
-% \the\everybackgroundbox
-% \setbox\extraframebox\hbox
-% {\vbox{\moveleft\backgroundoffset\hbox{\executeifdefined{\??ov\currentbackground}\donothing}}}%
-% \wd\extraframebox\zeropoint % \backgroundwidth
-% \ht\extraframebox\backgroundheight
-% \dp\extraframebox\backgrounddepth
-% \box\extraframebox % \hskip-\backgroundwidth
-% \egroup}
-
-% \def\dodobackgroundbox#1% also less passing, we can get rid of the old method
-% {\bgroup
-% \def\currentbackground{#1}%
-% \ifcsname\??ov\currentbackground\endcsname
-% \the\everybackgroundbox
-% \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
-% \wd\extraframebox\zeropoint % \backgroundwidth
-% \ht\extraframebox\backgroundheight
-% \dp\extraframebox\backgrounddepth
-% \box\extraframebox % \hskip-\backgroundwidth
-% \fi
-% \egroup}
-
-\def\dodobackgroundbox
- {\bgroup
- \ifcsname\??ov\currentbackground\endcsname
- \the\everybackgroundbox
- \setbox\extraframebox\hbox{\vbox{\moveleft\backgroundoffset\hbox{\csname\??ov\currentbackground\endcsname}}}%
- \wd\extraframebox\zeropoint % \backgroundwidth
- \ht\extraframebox\backgroundheight
- \dp\extraframebox\backgrounddepth
- \box\extraframebox % \hskip-\backgroundwidth
- \fi
- \egroup}
-
-\def\dododobackgroundbox#1,#2% #2 gobbles spaces
- {\edef\currentbackground{#1}%
- \ifx\currentbackground\s!unknown\else
- \dodobackgroundbox\expandafter\dododobackgroundbox
- \fi#2}
-
-\let\backgroundoffset\!!zeropoint
-\let\backgrounddepth \!!zeropoint
-\def\backgroundwidth {\the\hsize}
-\def\backgroundheight{\the\vsize}
-
-% todo: also \def\theforegroundbox{#1}
-
-% \def\dobackgroundbox#1%
-% {\setbox\framebox\vbox
-% {\forgetall
-% \boxmaxdepth\maxdimen
-% \scratchdimen \framedparameter{#1}\relax
-% \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
-% \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
-% \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
-% \edef\backgroundoffset{\the\scratchdimen}%
-% \edef\backgroundwidth {\the\wd\framebox}%
-% \edef\backgroundheight{\the\ht\framebox}%
-% \edef\backgrounddepth {\the\dp\framebox}%
-% %\edef\foregroundbox{\box#1}%
-% \def\foregroundbox% fuzzy but needed hack, this \vss, otherwise
-% {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
-% \edef\component{\framedparameter\c!component}%
-% \hbox to \backgroundwidth % in case 'foreground' is used as overlay
-% {\ifx\component\empty
-% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
-% \else
-% \startlayoutcomponent{b:\component}{\s!background\space\component}%
-% \rawprocesscommalist[\framedbackground]\dodobackgroundbox
-% \stoplayoutcomponent
-% \fi
-% \box\framebox\hss}}}
-
-\def\normalforegroundbox% fuzzy but needed hack, this \vss, otherwise
- {\vbox to \backgroundheight{\vss\box\framebox\vss}}% vertical shift
-
-\def\dobackgroundbox#1%
- {\setbox\framebox\vbox
- {\forgetall
- \boxmaxdepth\maxdimen
- \scratchdimen \framedparameter{#1}\relax
- \frameddimenwd\dimexpr\wd\framebox+2\scratchdimen\relax
- \frameddimenht\dimexpr\ht\framebox+ \scratchdimen\relax
- \frameddimendp\dimexpr\dp\framebox+ \scratchdimen+\framedparameter\c!backgrounddepth\relax
- \edef\backgroundoffset{\the\scratchdimen}%
- \edef\backgroundwidth {\the\wd\framebox}%
- \edef\backgroundheight{\the\ht\framebox}%
- \edef\backgrounddepth {\the\dp\framebox}%
- %\edef\foregroundbox{\box#1}%
- \edef\component{\framedparameter\c!component}%
- \let\foregroundbox\normalforegroundbox
- \hbox to \backgroundwidth % in case 'foreground' is used as overlay
- {\ifx\component\empty
- \expanded{\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
- \else
- \startlayoutcomponent{b:\component}{background \component}%
- \expanded{\dododobackgroundbox\framedparameter\c!background},\s!unknown,\relax
- \stoplayoutcomponent
- \fi
- \box\framebox\hss}}}
-
-%D One can explictly insert the foreground box. For that
-%D purpose we introduce the overlay \type {foreground}.
-
-\defineoverlay[\v!foreground][\foregroundbox]
-
-%D We can specify overlays as a comma separated list of
-%D overlays, a sometimes handy feature.
-
-%D Besides backgrounds (overlays) we also need some macros to
-%D draw outlines (ruled borders). Again we have to deal with
-%D square and round corners. The first category can be handled
-%D by \TEX\ itself, the latter one depends on the driver. This
-%D macro also support a negative offset.
-
-\ifx\scratchoffset\undefined \newdimen\scratchoffset \fi
-
-\def\dooutlinebox % we needed to move the color command in order to apply attributes properly
- {\setbox\framebox\vbox % rules on top of box
- {\scratchoffset \framedparameter\c!frameoffset\relax
- \frameddimenwd\dimexpr\wd\framebox+2\scratchoffset\relax
- \frameddimenht\dimexpr\ht\framebox+ \scratchoffset\relax
- \frameddimendp\dimexpr\dp\framebox+ \scratchoffset+\framedparameter\c!framedepth\relax
- \ifdim\frameddimendp<\zeropoint
- \advance\frameddimenht \frameddimendp
- \scratchdimen-\frameddimendp
- \frameddimendp\zeropoint
- \else
- \scratchdimen\zeropoint
- \fi
- \setbox\extraframebox\hbox
- {\doifsomething{\framedparameter\c!framecolor}{\color[\framedparameter\c!framecolor]}{\dostrokedbox}}%
- \setbox\extraframebox\hbox
- {\raise\scratchdimen\vbox
- {\moveleft\scratchoffset
- \box\extraframebox}}%
- \wd\extraframebox\wd\framebox
- \ht\extraframebox\ht\framebox
- \dp\extraframebox\dp\framebox
- \hbox{\box\framebox\hskip-\wd\extraframebox\box\extraframebox}}}
-
-\def\dostrokedbox
- {\doifelse{\framedparameter\c!framecorner}\v!rectangular
- {\dostrokedlinedbox}
- {\ifzeropt\dimexpr\framedparameter\c!frameradius\relax % just in case of .x\bodyfontsize
- \dostrokedlinedbox
- \else
- \dostrokedroundbox
- \fi}}
-
-\def\dostrokedlinedbox
- {\setbox\scratchbox\null
- \wd\scratchbox\frameddimenwd
- \ht\scratchbox\frameddimenht
- \dp\scratchbox\frameddimendp
- \setbox\scratchbox\vbox \bgroup
- \csname t\@@frame@@\framedparameter\c!frame\framedparameter\c!topframe \endcsname
- \hbox \bgroup
- \csname l\@@frame@@\framedparameter\c!frame\framedparameter\c!leftframe \endcsname
- \box\scratchbox
- \csname r\@@frame@@\framedparameter\c!frame\framedparameter\c!rightframe \endcsname
- \egroup
- \csname b\@@frame@@\framedparameter\c!frame\framedparameter\c!bottomframe\endcsname
- \egroup
- \wd\scratchbox\frameddimenwd
- \ht\scratchbox\frameddimenht
- \dp\scratchbox\frameddimendp
- \box\scratchbox}
-
-\def\@@frame@@{@@frame@@}
-
-% \setvalue{t\@@frame@@\v!on \v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{t\@@frame@@\v!off\v!on}{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{t\@@frame@@\v!on }{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{b\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
-% \setvalue{b\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
-% \setvalue{b\@@frame@@\v!on }{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
-% \setvalue{l\@@frame@@\v!on \v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{l\@@frame@@\v!off\v!on}{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{l\@@frame@@\v!on }{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
-% \setvalue{r\@@frame@@\v!on \v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
-% \setvalue{r\@@frame@@\v!off\v!on}{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
-% \setvalue{r\@@frame@@\v!on }{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
-
-\def\@@frame@@trule{\hrule\!!height\ruledlinewidth\kern-\ruledlinewidth}
-\def\@@frame@@brule{\kern-\ruledlinewidth\hrule\!!height\ruledlinewidth}
-\def\@@frame@@rrule{\kern-\ruledlinewidth\vrule\!!width\ruledlinewidth}
-\def\@@frame@@lrule{\vrule\!!width\ruledlinewidth\kern-\ruledlinewidth}
-
-\letvalue{t\@@frame@@\v!on \v!on}\@@frame@@trule
-\letvalue{t\@@frame@@\v!off\v!on}\@@frame@@trule
-\letvalue{t\@@frame@@\v!on }\@@frame@@trule
-
-\letvalue{b\@@frame@@\v!on \v!on}\@@frame@@brule
-\letvalue{b\@@frame@@\v!off\v!on}\@@frame@@brule
-\letvalue{b\@@frame@@\v!on }\@@frame@@brule
-
-\letvalue{l\@@frame@@\v!on \v!on}\@@frame@@lrule
-\letvalue{l\@@frame@@\v!off\v!on}\@@frame@@lrule
-\letvalue{l\@@frame@@\v!on }\@@frame@@lrule
-
-\letvalue{r\@@frame@@\v!on \v!on}\@@frame@@rrule
-\letvalue{r\@@frame@@\v!off\v!on}\@@frame@@rrule
-\letvalue{r\@@frame@@\v!on }\@@frame@@rrule
-
-% no overlapping rules
-
-\def\@@frame@@trules{\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}\nointerlineskip\kern-\ruledlinewidth}
-\def\@@frame@@brules{\kern-\ruledlinewidth\nointerlineskip\hbox{\kern\ruledlinewidth\vrule\!!width\dimexpr\frameddimenwd-2\ruledlinewidth\relax\!!height\ruledlinewidth}}
-\def\@@frame@@rrules{\kern-\ruledlinewidth\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth}
-\def\@@frame@@lrules{\vrule\!!height\dimexpr\frameddimenht-\ruledlinewidth\relax\!!depth-\ruledlinewidth\!!width\ruledlinewidth\kern-\ruledlinewidth}
-
-% small is relatively new
-
-\letvalue{t\@@frame@@\v!small\v!small}\@@frame@@trules
-\letvalue{t\@@frame@@\v!off \v!small}\@@frame@@trules
-\letvalue{t\@@frame@@\v!small }\@@frame@@trules
-
-\letvalue{b\@@frame@@\v!small\v!small}\@@frame@@brules
-\letvalue{b\@@frame@@\v!off \v!small}\@@frame@@brules
-\letvalue{b\@@frame@@\v!small }\@@frame@@brules
-
-\letvalue{l\@@frame@@\v!small\v!small}\@@frame@@lrules
-\letvalue{l\@@frame@@\v!off \v!small}\@@frame@@lrules
-\letvalue{l\@@frame@@\v!small }\@@frame@@lrules
-
-\letvalue{r\@@frame@@\v!small\v!small}\@@frame@@rrules
-\letvalue{r\@@frame@@\v!off \v!small}\@@frame@@rrules
-\letvalue{r\@@frame@@\v!small }\@@frame@@rrules
-
-%D I condidered using the low level support command
-%D \type{\ruledhbox}, but this would slow down processing by a
-%D factor~3.
-
-% \framed
-% [width=4cm,height=3cm,rulethickness=3mm,
-% frame=off,rightframe=on,leftframe=on,topframe=on,bottomframe=on]
-% {}
-% \framed
-% [width=4cm,height=3cm,rulethickness=3mm,
-% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=small]
-% {}
-% \framed
-% [width=4cm,height=3cm,rulethickness=3mm,
-% frame=off,rightframe=small,leftframe=small,topframe=small,bottomframe=on]
-% {}
-
-%D The next few macros are probably the most misused ones in
-%D \CONTEXT. They deal with putting rules around boxes, provide
-%D backgrounds, offer alignment features, and some more. We
-%D start with defining some booleans. These give an impression
-%D of what we are going to take into account.
-
-% todo: chardefs
-
-\newif\ifboxhasoffset
-\newif\ifboxhaswidth
-\newif\ifboxhasheight
-\newif\ifboxhasformat
-\newif\ifboxhasstrut
-\newif\ifboxisoverlaid
-\newif\ifboxhasframe
-\newif\ifdelayedstrut
-
-%D We also need a few \DIMENSIONS:
-
-\newdimen\@@localoffset
-\newdimen\@@globalwidth
-
-%D The content of the box will be (temporary) saved in a box:
-
-\newbox\framebox
-
-%D We also need a box for outlines and backgrounds:
-
-\newbox\extraframebox
-
-%D \macros
-%D {framed, setupframed}
-%D
-%D Ruled boxes are typeset using \type{\framed}. This command
-%D is quite versatile and, although some users will probably
-%D seldom use it, one cannot overlook its features.
-%D
-%D \showsetup{setupframed}
-%D \showsetup{framed}
-%D
-%D This general macro is a special version of an even more
-%D general case, that can easily be linked into other macros
-%D that need some kind of framing. The local version is called
-%D with an extra parameter: the variable identifier. The reason
-%D for passing this identifier between brackets lays in the
-%D mere fact that this way we can use the optional argument
-%D grabbers.
-
-\def\defaultframeoffset{.25ex}
-
-\unexpanded\def\framed
- {\bgroup
- \copylocalframed[\??ol][\??oi]% == \presetlocalframed[\??ol]%
- \dodoubleempty\startlocalframed[\??ol]}
-
-\def\presetlocalframed[#1]%
- {\copylocalframed[#1][\??oi]}
-
-% \def\copylocalframed[#1]#2[#3]%
-% {\copyparameters[#1][#3]%
-% [\c!width,\c!height,\c!radius,\c!corner,\c!depth,\c!offset,%
-% \c!autowidth,\c!empty,\c!component,\c!orientation,\c!lines,%
-% \c!align,\c!bottom,\c!top,\c!strut,\c!autostrut,\c!location,\c!setups,\c!extras,%
-% \c!foregroundstyle,\c!foregroundcolor,%
-% \c!background,\c!backgroundoffset,\c!backgroundcorner,\c!backgroundradius,\c!backgrounddepth,\c!backgroundcolor,\c!backgroundscreen,%
-% \c!frame,\c!frameoffset,\c!framecorner,\c!frameradius,\c!framedepth,\c!framecolor,\c!rulethickness,%
-% \c!topframe,\c!bottomframe,\c!leftframe,\c!rightframe]}
-
-% since framed is used all over the place, we have a (small) speedup)
-
-\def\copylocalframed[#1]#2[#3]%
- {\edef\copiedfrom{#1}\edef\copiedto{#3}%
- \docopyvalue\copiedfrom\copiedto\c!width
- \docopyvalue\copiedfrom\copiedto\c!height
- \docopyvalue\copiedfrom\copiedto\c!autowidth
- \docopyvalue\copiedfrom\copiedto\c!offset
- \docopyvalue\copiedfrom\copiedto\c!empty
- \docopyvalue\copiedfrom\copiedto\c!rulethickness
- \docopyvalue\copiedfrom\copiedto\c!radius
- \docopyvalue\copiedfrom\copiedto\c!corner
- \docopyvalue\copiedfrom\copiedto\c!depth
- \docopyvalue\copiedfrom\copiedto\c!frame
- \docopyvalue\copiedfrom\copiedto\c!framecolor
- \docopyvalue\copiedfrom\copiedto\c!foregroundstyle
- \docopyvalue\copiedfrom\copiedto\c!foregroundcolor
- \docopyvalue\copiedfrom\copiedto\c!lines
- \docopyvalue\copiedfrom\copiedto\c!orientation
- \docopyvalue\copiedfrom\copiedto\c!topframe
- \docopyvalue\copiedfrom\copiedto\c!bottomframe
- \docopyvalue\copiedfrom\copiedto\c!leftframe
- \docopyvalue\copiedfrom\copiedto\c!rightframe
- \docopyvalue\copiedfrom\copiedto\c!rulethickness
- \docopyvalue\copiedfrom\copiedto\c!frameoffset
- \docopyvalue\copiedfrom\copiedto\c!background
- \docopyvalue\copiedfrom\copiedto\c!component
- \docopyvalue\copiedfrom\copiedto\c!backgroundoffset
- \docopyvalue\copiedfrom\copiedto\c!backgroundscreen
- \docopyvalue\copiedfrom\copiedto\c!backgroundcolor
- \docopyvalue\copiedfrom\copiedto\c!align
- \docopyvalue\copiedfrom\copiedto\c!bottom
- \docopyvalue\copiedfrom\copiedto\c!top
- \docopyvalue\copiedfrom\copiedto\c!strut
- \docopyvalue\copiedfrom\copiedto\c!autostrut
- \docopyvalue\copiedfrom\copiedto\c!location
- \docopyvalue\copiedfrom\copiedto\c!component
- \docopyvalue\copiedfrom\copiedto\c!extras
- \docopyvalue\copiedfrom\copiedto\c!setups
- \docopyvalue\copiedfrom\copiedto\c!backgroundradius
- \docopyvalue\copiedfrom\copiedto\c!backgroundcorner
- \docopyvalue\copiedfrom\copiedto\c!backgrounddepth
- \docopyvalue\copiedfrom\copiedto\c!frameradius
- \docopyvalue\copiedfrom\copiedto\c!framecorner
- \docopyvalue\copiedfrom\copiedto\c!framedepth}
-
-\def\setupframed
- {\dodoubleempty\dosetupframed}
-
-\def\dosetupframed
- {\ifsecondargument
- \@EA\dodoublesetupframed
- \else
- \@EA\dosinglesetupframed
- \fi}
-
-\def\dosinglesetupframed[#1][#2]%
- {\getparameters[\??oi][#1]}
-
-\def\dodoublesetupframed[#1][#2]%
- {\bgroup
- \let\dodoubleempty\empty
- \def\doframed[##1]{\gdef\globalredefinedframed{\dodoubleempty\doframed[##1,#2]}}%
- \getvalue{#1}%
- \egroup
- \letvalue{#1}\globalredefinedframed}
-
-%D \startbuffer
-%D \setupframed [framecolor=yellow] \framed{A}
-%D \defineframed[myframed] [framecolor=blue] \myframed{B}
-%D \setupframed [myframed] [framecolor=red] \myframed{C}
-%D \stopbuffer
-%D
-%D \typebuffer \getbuffer
-%D
-%D \startbuffer
-%D \presetlocalframed[myframed]
-%D \setuplocalframed[myframed][width=4cm,height=2cm]
-%D \localframed[myframed][framecolor=green]{oeps}
-%D \stopbuffer
-%D
-%D \typebuffer \getbuffer
-
-%D \macros
-%D {ifinframed}
-%D
-%D The normal case first presets all parameters and next starts
-%D looking for the user supplied ones. The first step is
-%D omitted in the local case, because these are preset at
-%D declaration time and keep their values unless explictly
-%D changed. By presetting the variables everytime the normal
-%D command is called, we can use this command nested, without
-%D the unwanted side effect of inheritance. The boolean is
-%D used to speed up the color stack.
-
-\newif\ifinframed
-
-\def\localframed
- {\bgroup
- \dodoubleempty\startlocalframed}
-
-%D The next one is faster on multiple backgrounds per page. No
-%D dimensions can be set, only frames and backgrounds.
-
-\def\fastlocalframed[#1]#2[#3]#4% 3-4
- {\bgroup
- \inframedtrue
- \edef\@@framed{#1}%
- % more bytes
- % \scratchdimen\framedparameter\c!frameoffset
- % \setevalue{\@@framed\c!frameoffset}{\the\scratchdimen}%
- % \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
- % {\scratchdimen\framedparameter\c!backgroundoffset
- % \setevalue{\@@framed\c!backgroundoffset}{\the\scratchdimen}}%
- % less bytes
- \@EA\freezedimenmacro\csname\@@framed\c!frameoffset\endcsname
- \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
- {\@EA\freezedimenmacro\csname\@@framed\c!backgroundoffset\endcsname}%
- % so far
- \setbox\framebox\hbox{#4}%
- \getparameters[\@@framed][#3]% no \expanded !
- % no, better in calling macro
- %
- % \edef\doframedsetups{\framedparameter\c!setups}%
- % \ifx\doframedsetups\empty\else
- % \edef\doframedsetups{\noexpand\setups[\doframedsetups]}%
- % \fi
- \removeframedboxdepth
- \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
- \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
- \edef\overlaylinecolor{\framedparameter\c!framecolor}%
- \edef\overlaylinewidth{\the\ruledlinewidth}%
- \edef\@@localframing {\framedparameter\c!frame}%
- \ifx\@@localframing\v!overlay \else \ifx\@@localframing\v!none \else
- \edef\framedrulethickness{\framedparameter\c!rulethickness}%
- \ifx\framedrulethickness\empty\else
- \ruledlinewidth\framedrulethickness\relax
- \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
- \fi
- \dooutlinebox % real or invisible frame
- \fi \fi
- \edef\framedbackground{\framedparameter\c!background}%
- \ifx\framedbackground\empty\else\dobackedbox\fi
- \restoreframedboxdepth
- \box\framebox
- \egroup}
-
-%D Before we go into details, we present (and implement) the
-%D main framing routine. I saw no real reason for splitting the
-%D next two macros into smaller pieces. The content will be
-%D collected in a horizontal or vertical box with fixed or free
-%D dimensions and specific settings concerning aligment and
-%D offsets.
-%D
-%D In the first few lines, we pre||expand the frame and
-%D background offsets. We do so, because the can be defined in
-%D terms of the main offset. However, see for instance page
-%D backgrounds, when \type {#2} sets the offset to \type
-%D {overlay}, both offsets become invalid.
-%D
-%D Because it is used so often the he next macro is (and
-%D looks) rather optimized.
-
-\let\postprocessframebox\relax
-
-\let\@@framed\s!unknown
-
-\def\framedparameter#1%
- {\csname\@@framed#1\endcsname}
-
-\newdimen\!!framedwidth
-\newdimen\!!framedheight
-
-\def\startlocalframed[#1][#2]%
- {\bgroup
- \inframedtrue
- \edef\@@framed{#1}%
- % this piece of pre expansion is needed (sometimes used in frameoffset)
- % \doifvaluesomething{\@@framed\c!rulethickness} % obsolete
- % {\ruledlinewidth\getvalue{\@@framed\c!rulethickness}}% obsolete
- % this piece of pre expansion is needed (sometimes used circular)
- \setevalue{\@@framed\c!frameoffset}{\the\dimexpr\framedparameter\c!frameoffset\relax}%
- \doifnotvalue{\@@framed\c!backgroundoffset}\v!frame
- {\setevalue{\@@framed\c!backgroundoffset}{\the\dimexpr\framedparameter\c!backgroundoffset\relax}}%
- % to prevent deadlock in case of self refering
- \ifsecondargument % faster
- \getparameters[\@@framed][#2]% here !
- \fi
- % new, experimental dirty hook
- \framedparameter\c!extras
- % to get the right spacing
- \doifvaluesomething{\@@framed\c!foregroundstyle}
- {\@EA\doconvertfont\csname\@@framed\c!foregroundstyle\endcsname\empty}%
- % beware, both the frame and background offset can be overruled
- %
- \edef\doframedsetups{\framedparameter\c!setups}%
- \ifx\doframedsetups\empty\else
- \edef\doframedsetups{\noexpand\setups[\doframedsetups]}%
- \fi
- % the next macros are visible
- \edef\localoffset{\framedparameter\c!offset}%
- \edef\localwidth {\framedparameter\c!width}%
- \edef\localheight{\framedparameter\c!height}%
- \edef\localformat{\framedparameter\c!align}%
- \edef\localstrut {\framedparameter\c!strut}%
- % these are not
- \edef\@@localautostrut {\framedparameter\c!autostrut}%
- \edef\@@localframing {\framedparameter\c!frame}%
- \edef\@@locallocation {\framedparameter\c!location}%
- \edef\@@localorientation{\framedparameter\c!orientation}%
- %
- \edef\@@localautowidth {\framedparameter\c!autowidth}%
- %
- \ifx\@@localframing\v!overlay % no frame, no offset, no framewidth
- \boxhasframefalse
- \let\localoffset\v!overlay
- \else\ifx\@@localframing\v!none % no frame, no framewidth
- \boxhasframefalse
- \else
- \boxhasframetrue
- \fi\fi
- \ifboxhasframe
- \edef\framedrulethickness{\framedparameter\c!rulethickness}%
- \ifx\framedrulethickness\empty\else
- \ruledlinewidth\framedrulethickness\relax
- \ifinheritruledlinewidth\linewidth\ruledlinewidth\fi
- \fi
- \else
- \ruledlinewidth\zeropoint
- \fi
- \ifx\localformat\empty
- \boxhasformatfalse
- \else
- \boxhasformattrue
- \dosetraggedcommand\localformat
- \edef\dobeforeframedbox{\raggedtopcommand\framedparameter\c!top}%
- \edef\doafterframedbox {\framedparameter\c!bottom\raggedbottomcommand}%
- \fi
- \ifx\localoffset\v!none
- \boxhasoffsetfalse
- \boxhasstrutfalse
- \boxisoverlaidfalse
- \@@localoffset\ruledlinewidth
- \else\ifx\localoffset\v!overlay
- % \ifx\@@localframing\v!no \boxhasframefalse \fi % test first
- \boxhasoffsetfalse
- \boxhasstrutfalse
- \boxisoverlaidtrue
- \@@localoffset\zeropoint
- \else
- \boxhasoffsettrue
- \boxhasstruttrue
- \boxisoverlaidfalse
- \ifx\localoffset\v!default % new per 2-6-2000
- \let\localoffset\defaultframeoffset
- \letvalue{\@@framed\c!offset}\defaultframeoffset
- \else
- \let\defaultframeoffset\localoffset
- \fi
- \@@localoffset\dimexpr\localoffset+\ruledlinewidth\relax
- \fi\fi
- \!!framedheight\zeropoint
- \!!framedwidth \zeropoint
- \ifx\localwidth\v!fit
- \ifboxhasformat
- \boxhaswidthtrue
- \!!framedwidth\hsize
- \else
- \boxhaswidthfalse
- \fi
- \else\ifx\localwidth\v!fixed % equals \v!fit but no shapebox
- \ifboxhasformat
- \boxhaswidthtrue
- \!!framedwidth\hsize
- \else
- \boxhaswidthfalse
- \fi
- \else\ifx\localwidth\v!broad
- \boxhaswidthtrue
- \!!framedwidth\hsize
- \else\ifx\localwidth\v!local
- \boxhaswidthtrue
- \setlocalhsize
- \!!framedwidth\localhsize
- \else
- \boxhaswidthtrue
- \!!framedwidth\localwidth
- \fi\fi\fi\fi
- \ifx\localheight\v!fit
- \boxhasheightfalse % no longer: \boxhasstrutfalse
- \else\ifx\localheight\v!broad
- \boxhasheightfalse
- \else
- \boxhasheighttrue
- \!!framedheight\localheight
- \fi\fi
- \ifboxhasheight
- % obey user set height, also downward compatible
- \else
- \doifvaluesomething{\@@framed\c!lines}
- {\ifcase\framedparameter\c!lines\else
- \!!framedheight\framedparameter\c!lines\lineheight
- \edef\localheight{\the\!!framedheight}%
- \boxhasheighttrue
- \fi}%
- \fi
- % this is now an option: width=local
- %
- % \ifdim\!!framedwidth=\hsize
- % \parindent\zeropoint
- % \setlocalhsize
- % \!!framedwidth\localhsize
- % \fi
- % i.e. disable (colsetbackgroundproblemintechniek)
- \advance\!!framedwidth -2\@@localoffset
- \advance\!!framedheight -2\@@localoffset
- \ifx\localstrut\v!no
- \boxhasstrutfalse
- \else\ifx\localstrut\v!global
- \setstrut
- \else\ifx\localstrut\v!local
- \setfontstrut
- \else
- \setstrut
- \fi\fi\fi
- \ifboxhasstrut
- \let\localbegstrut\begstrut
- \let\localendstrut\endstrut
- \let\localstrut \strut
- \else
- \let\localbegstrut\pseudobegstrut % was: \relax
- \let\localendstrut\pseudoendstrut % was: \relax
- \let\localstrut \pseudostrut % was: \relax
- %\ifboxhasheight\ifdim\!!framedheight<\strutht % saveguard
- % \let\localbegstrut\relax % but not that
- % \let\localstrut \relax % save after all
- %\fi\fi
- \fi
- \ifx\@@localautostrut\v!yes
- \let\delayedbegstrut\relax
- \let\delayedendstrut\relax
- \let\delayedstrut \relax
- \else
- \let\delayedbegstrut\localbegstrut
- \let\delayedendstrut\localendstrut
- \let\delayedstrut \localstrut
- \let\localbegstrut \relax
- \let\localendstrut \relax
- \let\localstrut \relax
- \fi
- \ifboxhasheight
- \let\\\vboxednewline
- \ifboxhaswidth
- \let\hairline\vboxedhairline
- \ifboxhasformat
- \let\next\doformatboxSomeFormat
- \else
- \let\next\doformatboxNoFormat
- \fi
- \else
- \let\hairline\hboxedhairline
- \ifboxhasformat
- \let\next\doformatboxHeight
- \else
- \let\next\doformatboxVSize
- \fi
- \fi
- \else
- \ifboxhaswidth
- \ifboxhasformat
- \let\hairline\vboxedhairline
- \let\\\vboxednewline
- \let\next\doformatboxWidth
- \else
- \let\hairline\hboxedhairline
- \let\\\hboxednewline
- \let\next\doformatboxHSize
- \fi
- \else
- \let\hairline\hboxedhairline
- \let\\\hboxednewline
- \let\next\doformatboxNoSize
- \fi
- \fi
- \edef\framedwidth % a new feature, visible for user
- {\ifdim\!!framedwidth >\zeropoint\the\!!framedwidth \else\zeropoint\fi}%
- \edef\framedheight% a new feature, visible for user
- {\ifdim\!!framedheight>\zeropoint\the\!!framedheight\else\zeropoint\fi}%
- % we need to register the (outer) color
- \startregistercolor[\framedparameter\c!foregroundcolor]%
- % first alternative
- %\def\dowithframedbox%
- % {\let\postprocessframebox\relax %new
- % \aftergroup\stoplocalframed}%
- % \afterassignment\dowithframedbox
- % \setbox\framebox=\next}
- % second alternative
- %\dowithnextbox
- % {\setbox\framebox\flushnextbox
- % \let\postprocessframebox\relax %new
- % \stoplocalframed}
- % \next}
- \@@startframedorientation
- \afterassignment\dodowithframebox
- \setbox\framebox\next}
-
-\def\dowithframebox
- {% moved : \let\postprocessframebox\relax
- \stoplocalframed}
-
-\def\dodowithframebox
- {\aftergroup\dowithframebox}
-
-\let\doafterframedbox \relax
-\let\dobeforeframedbox\relax
-
-%D Carefull analysis of this macro will learn us that not all
-%D branches in the last conditionals can be encountered, that
-%D is, some assignments to \type{\next} will never occur.
-%D Nevertheless we implement the whole scheme, if not for
-%D future extensions.
-
-%D \macros
-%D {ifreshapeframebox}
-%D
-%D The last few lines tell what to do after the content of the
-%D box is collected and passed to the next macro. In the case
-%D of a fixed width and centered alignment, the content is
-%D evaluated and used to determine the most natural width. The
-%D rest of the code deals with backgrounds and frames.
-
-\newif\ifreshapeframebox \reshapeframeboxtrue
-
-%D Beware: setting \type {top} and \type {bottom} to nothing, may
-%D result in a frame that is larger that the given height! try:
-%D
-%D \starttyping
-%D \framed
-%D [height=3cm,top=,bottom=,offset=overlay]
-%D {\strut test \shapefill \strut test}
-%D \stoptyping
-%D
-%D This is intended behaviour and not a bug! One can always set
-%D
-%D \starttyping
-%D ...,bottom=\kern0pt,...
-%D \stoptyping
-
-\def\stoplocalframed
- {\dontshowcomposition
- \@@stopframedorientation % hm, wrong place ! should rotate the result (after reshape)
- \stopregistercolor
- \handleframedlocator\c!before\@@locallocation
- \ifboxhasformat
- \ifx\@@localautowidth\v!force
- \ifreshapeframebox\doreshapeframedbox\fi
- \boxhaswidthfalse
- \else
- \ifx\localwidth\v!fit
- \ifx\@@localautowidth\v!yes
- \ifreshapeframebox\doreshapeframedbox\fi
- \fi
- \boxhaswidthfalse
- \else\ifx\localwidth\v!fixed
- \boxhaswidthfalse
- \else
- \resetshapeframebox
- \fi\fi
- \fi
- \else
- \resetshapeframebox
- \fi
- \ifboxhaswidth
- \wd\framebox\!!framedwidth
- \fi
- \ifboxhasheight
- \ht\framebox\!!framedheight
- \fi
- \doifvalue{\@@framed\c!empty}\v!yes
- {\setbox\scratchbox\null
- \wd\scratchbox\wd\framebox
- \ht\scratchbox\ht\framebox
- \dp\scratchbox\dp\framebox
- \setbox\framebox\box\scratchbox}%
- \edef\framedforegroundcolor{\framedparameter\c!foregroundcolor}%
- \ifx\framedforegroundcolor\empty\else\docolorframebox\fi
- \ifboxhasoffset
- \dooffsetframebox
- \fi
- \ifboxisoverlaid \else
- \dolocateframebox
- \fi
- \ifx\postprocessframebox\relax \else
- \let\next\postprocessframebox
- \let\postprocessframebox\relax % prevent nesting
- \next\framebox
- \fi
- \edef\overlaylinecolor{\framedparameter\c!framecolor}%
- \edef\overlaylinewidth{\the\ruledlinewidth}% \@@...
- \ifboxhasframe % real or invisible frame
- \dooutlinebox
- \fi
- \edef\framedbackground{\framedparameter\c!background}%
- \ifx\framedbackground\empty\else\dobackedbox\fi
- \handleframedlocator\c!after\@@locallocation
- \box\framebox
- \egroup
- \egroup}
-
-\def\installframedlocator#1#2#3%
- {\setvalue{\??ol:\c!location:\c!before:#1}{#2}%
- \setvalue{\??ol:\c!location:\c!after :#1}{#3}}
-
-\def\handleframedlocator#1#2%
- {\getvalue{\??ol:\c!location:#1:#2}}
-
-\def\doprelocframedbox#1%
- {\scratchdimen\dimexpr#1+\ruledlinewidth\relax
- \ifboxhasoffset
- \advance\scratchdimen \framedparameter\c!offset
- \fi
- \scratchskip\dimexpr\ht\framebox-\scratchdimen\relax}
-
-% \ruledhbox
-% {A
-% \framed[width=2cm,align=middle,location=hanging]{location\\equals\\hanging}
-% \framed[width=2cm,align=middle,location=depth] {location\\equals\\depth}
-% \framed[width=2cm,align=middle,location=height] {location\\equals\\height}
-% B}
-% \vskip2cm
-% \ruledhbox
-% {A
-% \framed[width=2cm,align=middle,location=low] {location\\equals\\low}
-% \framed[width=2cm,align=middle,location=line] {location\\equals\\line}
-% \framed[width=2cm,align=middle,location=high] {location\\equals\\high}
-% B}
-% \vskip2cm
-% \ruledhbox
-% {A
-% \framed[width=2cm,align=middle,location=top] {location\\equals\\top}
-% \framed[width=2cm,align=middle,location=bottom] {location\\equals\\bottom}
-% \framed[width=2cm,align=middle,location=lohi] {location\\equals\\lohi}
-% \framed[width=2cm,align=middle,location=middle] {location\\equals\\middle}
-% B}
-
-\installframedlocator \v!hanging % best with strut=no
- {}
- {\dp\framebox\ht\framebox
- \ht\framebox\zeropoint}
-
-\installframedlocator \v!depth
- {}
- {\ht\framebox\dimexpr\ht\framebox-\strutdp\relax
- \dp\framebox\strutdp
- \box\framebox}
-
-\installframedlocator \v!height
- {}
- {\dp\framebox\dimexpr\ht\framebox-\strutht\relax
- \ht\framebox\strutht
- \box\framebox}
-
-\installframedlocator \v!high
- {}
- {\doprelocframedbox\strutht
- \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
- \ht\framebox\strutht
- \dp\framebox\strutdp
- \hbox{\box\framebox}}
-
-\installframedlocator \v!line
- {}
- {\setbox\framebox\hbox{\lower.5\ht\framebox\box\framebox}%
- \ht\framebox.5\lineheight
- \dp\framebox.5\lineheight
- \hbox{\box\framebox}}
-
-\installframedlocator \v!low
- {}
- {\doprelocframedbox\strutdp
- \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
- \ht\framebox\strutht
- \dp\framebox\strutdp
- \box\framebox}
-
-\installframedlocator \v!top
- {}
- {\doprelocframedbox\strutht
- \setbox\framebox\hbox{\lower\scratchskip\box\framebox}%
- \ht\framebox\scratchdimen
- \dp\framebox\scratchskip
- \hbox{\box\framebox}}
-
-\installframedlocator \v!middle
- {}
- {\scratchdimen.5\ht\framebox
- \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
- \ht\framebox\scratchdimen
- \dp\framebox\scratchdimen
- \hbox{\box\framebox}}
-
-\installframedlocator \v!lohi
- {\handleframedlocator\c!before\v!middle}
- {\handleframedlocator\c!after \v!middle}
-
-\installframedlocator \v!bottom
- {}
- {\doprelocframedbox\strutdp
- \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
- \ht\framebox\scratchskip
- \dp\framebox\scratchdimen
- \hbox{\box\framebox}}
-
-\installframedlocator \v!keep % retains height/depth
- {\removeframedboxdepth}
- {\restoreframedboxdepth}
-
-% also used in fastlocalframed
-
-\newdimen\originalframedwd
-\newdimen\originalframedht
-\newdimen\originalframeddp
-
-\def\removeframedboxdepth
- {\originalframedwd\wd\framebox
- \originalframedht\ht\framebox
- \originalframeddp\dp\framebox
- \ifzeropt\originalframeddp\else\setbox\framebox\hbox{\raise\originalframeddp\box\framebox}\fi
- \wd\framebox\originalframedwd
- \ht\framebox\dimexpr\originalframedht+\originalframeddp\relax
- \dp\framebox\zeropoint}
-
-\def\restoreframedboxdepth
- {\ifzeropt\originalframeddp\else\setbox\framebox\hbox{\lower\originalframeddp\box\framebox}\fi
- \wd\framebox\originalframedwd
- \ht\framebox\originalframedht
- \dp\framebox\originalframeddp}
-
-% \let\@@startframedorientation\relax
-% \let\@@stopframedorientation \relax
-
-% \framed[width=12cm,height=3cm,orientation=0]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=90]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=180]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=270]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=-90]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=-180]{\input ward\relax}
-% \framed[width=12cm,height=3cm,orientation=-270]{\input ward\relax}
-
-\def\@@startframedorientation
- {\let\@@stopframedorientation \relax
- \ifx\@@localorientation\empty\else
- \ifcase\@@localorientation\else
- \scratchcounter\@@localorientation
- \divide\scratchcounter\plustwo
- \ifodd\scratchcounter
- \swapmacros\framedwidth \framedheight
- \swapmacros\localwidth \localheight
- \swapdimens\!!framedheight\!!framedwidth
- \def\@@stopframedorientation{\@@dostopframedorientation\plusone}%
- \else
- \def\@@stopframedorientation{\@@dostopframedorientation\zerocount}%
- \fi
- \fi
- \fi}
-
-\def\@@dostopframedorientation#1%
- {\ifcase#1\else
- \swapmacros\framedwidth \framedheight
- \swapmacros\localwidth \localheight
- \swapdimens\!!framedheight\!!framedwidth
- \fi
- \setbox\framebox\hbox{\dorotatebox\@@localorientation\hbox{\box\framebox}}}
-
-%D The last conditional takes care of the special situation of
-%D in||line \inframed[height=3cm]{framed} boxes. Such boxes have
-%D to be \inframed{aligned} with the running text.
-
-\def\doinframed[#1]% we could omit #1] but readibility ...
- {\framed[\c!location=\v!low,#1]}
-
-\unexpanded\def\inframed
- {\dosingleempty\doinframed}
-
-%D When we set \type{empty} to \type{yes}, we get
-%D ourselves a frame and/or background, but no content, so
-%D actually we have a sort of phantom framed box.
-
-%D Because color marks and specials can interfere with
-%D spacing, we provide a way to specify a foregroundcolor.
-
-\def\docolorframebox
- {\doifvaluesomething{\@@framed\c!foregroundcolor}
- {\doifcolorelse{\framedparameter\c!foregroundcolor}
- {\setbox\framebox\hbox
- {\localcolortrue
- \color[\framedparameter\c!foregroundcolor]{\box\framebox}}}
- {}}}
-
-%D \macros
-%D {mframed, minframed}
-%D
-%D When Tobias asked how to frame mathematical elements in
-%D formulas, Taco's posted the next macro:
-%D
-%D \starttyping
-%D \def\mframed#1%
-%D {\relax
-%D \ifmmode
-%D \vcenter{\hbox{\framed{$\ifinner\else\displaystyle\fi#1$}}}%
-%D \else
-%D \framed{$#1$}%
-%D \fi}
-%D \stoptyping
-%D
-%D Because \type {\ifinner} does not (always) reports what
-%D one would expect, we move the test to the outer level. We
-%D also want to pass arguments,
-%D
-%D \starttyping
-%D \def\mframed%
-%D {\dosingleempty\domframed}
-%D
-%D \def\domframed[#1]#2% % tzt \dowithnextmathbox ?
-%D {\relax
-%D \ifmmode
-%D \ifinner
-%D \inframed[#1]{$#2$}%
-%D \else
-%D \vcenter{\hbox{\framed[#1]{$\displaystyle#2$}}}%
-%D \fi
-%D \else
-%D \inframed[#1]{$#2$}%
-%D \fi}
-%D \stoptyping
-%D
-%D Still better is the next alternative, if only because it
-%D takes care of setting the super- and subscripts styles
-
-\ifx\restoremathstyle\undefined \let\restoremathstyle\relax \fi
-
-\def\domframed[#1][#2]#3%
- {\begingroup
- \ifmmode
- \ifinner
- \let\mframedstyle\restoremathstyle
- \else
- \let\mframedstyle\displaystyle
- \fi
- \else
- \let\mframedstyle\restoremathstyle
- \fi
- #1\ifdone
- \def\normalstrut{$\mframedstyle\vphantom($}%
- \framed
- [\c!frameoffset=\@@oioffset,\c!offset=\v!overlay,#2]
- {$\mframedstyle#3$}%
- \else
- \inframed
- [#2]
- {$\mframedstyle#3$}%
- \fi
- \endgroup}
-
-\def\mframed
- {\dodoubleempty\domframed[\donetrue]}
-
-\def\inmframed
- {\dodoubleempty\domframed[\donefalse]}
-
-%D So instead of the rather versatile \type {\framed}, we ue
-%D the \type {\mframed}.
-%D
-%D \startbuffer
-%D \startformula
-%D x \times \mframed{y} \times y^{z_z}
-%D x \times \inmframed{y} \times y^{z_z}
-%D \stopformula
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D However, we got into troubles when we want to nest sub- and
-%D superscripts, like in
-%D
-%D \startbuffer
-%D \startformula
-%D x \times \mframed{y} \times y^{\mframed{z}_{\mframed{z}}}
-%D \stopformula
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D Therefore, we can best use \type {\super} and \type {\suber}
-%D instead of \type {^} and \type {_}. Both commands take care
-%D of proper font switching.
-%D
-%D \startbuffer
-%D \startformula
-%D x \times \mframed{y} \times y\super{\mframed{z}\suber{\mframed{z}}}
-%D \stopformula
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D As usual, one can specify in what way the text should be
-%D framed. One should be aware of the fact that, inorder to
-%D preserve the proper spacing, the \type {offset} is set to
-%D \type {overlay} and \type {frameoffset} is used used
-%D instead.
-%D
-%D \startbuffer
-%D \startformula
-%D x \times y\super{\mframed[framecolor=red]{z}\suber{z}}
-%D \stopformula
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D For inline use, we also provide the \type {\inmframed}
-%D alternative: we want $x \times \inmframed{y}$ in inline
-%D math, right?
-
-%D This previous framing macros needs a lot of alternatives for
-%D putting rules around boxes, inserting offsets and aligning
-%D text. Each step is handled by separate macros.
-
-\def\dowidenframebox#1%
- {\setbox\framebox\vbox
- {\kern#1\hbox{\kern#1\box\framebox\kern#1}\kern#1}}
-
-\def\dooffsetframebox{\dowidenframebox\localoffset}
-\def\dolocateframebox{\dowidenframebox\ruledlinewidth}
-
-%D Let's hope that the next few examples show us enough of
-%D what needs to be done by the auxiliary macros.
-%D
-%D \startbuffer
-%D \framed[height=1cm,offset=.5cm] {rule based learning}
-%D \framed[height=1cm,offset=0cm] {rule based learning}
-%D \framed[height=1cm,offset=none] {rule based learning}
-%D \framed[height=1cm,offset=overlay]{rule based learning}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \hbox{\getbuffer}
-%D \stoplinecorrection
-%D
-%D \startbuffer
-%D \framed[offset=.5cm] {rule based learning}
-%D \framed[offset=0cm] {rule based learning}
-%D \framed[offset=none] {rule based learning}
-%D \framed[offset=overlay]{rule based learning}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \hbox{\getbuffer}
-%D \stoplinecorrection
-%D
-%D \startbuffer
-%D \framed[strut=nee,offset=.5cm] {rule based learning}
-%D \framed[strut=nee,offset=0cm] {rule based learning}
-%D \framed[strut=nee,offset=none] {rule based learning}
-%D \framed[strut=nee,offset=overlay]{rule based learning}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \hbox{\getbuffer}
-%D \stoplinecorrection
-%D
-%D \startbuffer
-%D \framed[width=3cm,align=left] {rule\\based\\learning}
-%D \framed[width=3cm,align=middle] {rule\\based\\learning}
-%D \framed[width=3cm,align=right] {rule\\based\\learning}
-%D \framed[width=fit,align=middle] {rule\\based\\learning}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \hbox{\dontcomplain\getbuffer}
-%D \stoplinecorrection
-%D
-%D So now we're ready for the complicated stuff. We distinguish
-%D between borders with straight lines and those with round
-%D corners. When using the first alternative it is possible to
-%D turn off one or more lines. More fancy shapes are also
-%D possible by specifying dedicated backgrounds. Turning lines
-%D on and off is implemented as efficient as possible and as a
-%D result is interface language dependant. This next
-%D implementation evolved from simpler ones. It puts for
-%D instance the rules on top of the content and provides
-%D additional offset capabilities. The lot of calls to other
-%D macros makes this mechanism not that easy to comprehend.
-
-%D Getting the backgrounds right takes less code. Again we
-%D have to take care of additional offsets.
-
-\def\dobackedbox
- {\doifelsevalue{\@@framed\c!backgroundoffset}\v!frame % new
- {\dobackgroundbox\c!frameoffset}
- {\dobackgroundbox\c!backgroundoffset}}
-
-%D We handle left, right or middle alignment as well as fixed
-%D or free widths and heights. Each combination gets its own
-%D macro.
-
-%D The following code handles one-liners: \type{align={line,flushright}}.
-%D Beware, since we entered a group and either or not grab the next
-%D bgroup token, we need to finish the group in the oneliner mode.
-
-\ifx\raggedoneliner\undefined \chardef\raggedoneliner\zerocount \fi
-
-\def\doformatonelinerbox % beware: assumes explicit preceding bgroup
- {\ifcase\raggedoneliner
- \expandafter\nodoformatonelinerbox
- \else
- \expandafter\dodoformatonelinerbox
- \fi}
-
-\def\dodoformatonelinerbox
- {\dowithnextboxcontent
- {\ignorespaces}
- {\hbox to \hsize
- {\ifcase\raggedstatus\or\hss\or\hss\fi
- \unhbox\nextbox \removeunwantedspaces
- \ifcase\raggedstatus\or \or\hss\or\hss\fi}%
- \egroup}
- \hbox}
-
-\def\nodoformatonelinerbox % grabs {
- {\let\next=}
-
-%D The handlers:
-
-\def\doformatboxSomeFormat
- {\vbox to \!!framedheight
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \oninterlineskip
- \hsize\!!framedwidth
- \vsize\!!framedheight
- \doframedsetups
- \raggedcommand
- \dobeforeframedbox
- \bgroup
- \localbegstrut
- \aftergroup\localendstrut
- \aftergroup\doafterframedbox
- \aftergroup\egroup
- \doformatonelinerbox}
-
-\def\doformatboxNoFormat
- {\vbox to \!!framedheight
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \oninterlineskip
- \hsize\!!framedwidth
- \vsize\!!framedheight
- \doframedsetups
- \raggedcenter
- \vss
- \bgroup
- \localbegstrut
- \aftergroup\localendstrut
- \aftergroup\vss
- \aftergroup\egroup
- \doformatonelinerbox}
-
-\def\doformatboxHeight
- {\vbox to \!!framedheight
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \oninterlineskip
- \doframedsetups
- \raggedcommand
- \vss
- \bgroup
- \aftergroup\localendstrut
- \aftergroup\vss
- \aftergroup\egroup
- \localbegstrut
- \doformatonelinerbox}
-
-\def\doformatboxWidth
- {\vbox
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \oninterlineskip
- \hsize\!!framedwidth
- \doframedsetups
- \raggedcommand
- \dobeforeframedbox
- \bgroup
- \localbegstrut
- \aftergroup\localendstrut
- \aftergroup\doafterframedbox
- \aftergroup\egroup
- \doformatonelinerbox}
-
-\def\doformatboxVSize
- {\vbox to \!!framedheight
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \vsize\!!framedheight
- \doframedsetups
- \vss
- \bgroup
- \aftergroup\vss
- \aftergroup\egroup
- \hbox
- \bgroup
- \aftergroup\egroup
- \localstrut
- \doformatonelinerbox}
-
-\def\doformatboxHSize
- {\hbox to \!!framedwidth
- \bgroup
- \let\postprocessframebox\relax
- \forgetall
- \doframedsetups
- \hss
- \localstrut
- \bgroup
- \aftergroup\hss
- \aftergroup\egroup
- \doformatonelinerbox}
-
-\def\doformatboxNoSize
- {\hbox
- \bgroup
- \let\postprocessframebox\relax
- \doframedsetups
- \localstrut
- \doformatonelinerbox}
-
-\let\doframedsetups\relax
-
-%D On the next page we show some examples of how these macros
-%D come into action. The examples show us how
-%D \type {fit}, \type {broad} dimensions influence the
-%D formatting. Watch the visualized struts. \footnote {Here we
-%D used \type {\showstruts}.}
-%D
-%D \startpostponing
-%D \bgroup
-%D \showstruts
-%D \dontcomplain
-%D \startlinecorrection
-%D \halign{#\enskip&#\enskip&#\enskip&#\enskip&#\enskip&#\cr
-%D \framed[width=.2\hsize, height=.2\hsize, align=] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=broad, align=] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=fit, align=] {a\par b\par c}&
-%D \framed[width=fit, height=.2\hsize, align=] {a\par b\par c}&
-%D \framed[width=fit, height=broad, align=] {a\par b\par c}&
-%D \framed[width=fit, height=fit, align=] {a\par b\par c}\cr
-%D \noalign{\vskip1em}
-%D \framed[width=.2\hsize, height=.2\hsize, align=yes] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=broad, align=yes] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=fit, align=yes] {a\par b\par c}&
-%D \framed[width=fit, height=.2\hsize, align=yes] {a\par b\par c}&
-%D \framed[width=fit, height=broad, align=yes] {a\par b\par c}&
-%D \framed[width=fit, height=fit, align=yes] {a\par b\par c}\cr
-%D \noalign{\vskip1em}
-%D \framed[width=.2\hsize, height=.2\hsize, align=right] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=broad, align=right] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=fit, align=right] {a\par b\par c}&
-%D \framed[width=fit, height=.2\hsize, align=right] {a\par b\par c}&
-%D \framed[width=fit, height=broad, align=right] {a\par b\par c}&
-%D \framed[width=fit, height=fit, align=right] {a\par b\par c}\cr
-%D \noalign{\vskip1em}
-%D \framed[width=.2\hsize, height=.2\hsize, align=left] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=broad, align=left] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=fit, align=left] {a\par b\par c}&
-%D \framed[width=fit, height=.2\hsize, align=left] {a\par b\par c}&
-%D \framed[width=fit, height=broad, align=left] {a\par b\par c}&
-%D \framed[width=fit, height=fit, align=left] {a\par b\par c}\cr
-%D \noalign{\vskip1em}
-%D \framed[width=.2\hsize, height=.2\hsize, align=middle] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=broad, align=middle] {a\par b\par c}&
-%D \framed[width=.2\hsize, height=fit, align=middle] {a\par b\par c}&
-%D \framed[width=fit, height=.2\hsize, align=middle] {a\par b\par c}&
-%D \framed[width=fit, height=broad, align=middle] {a\par b\par c}&
-%D \framed[width=fit, height=fit, align=middle] {a\par b\par c}\cr}
-%D \stoplinecorrection
-%D \blank[2*big]
-%D \egroup
-%D \stoppostponing
-
-%D \macros
-%D {framednoflines, framedlastlength}
-%D
-%D It is possible to let the frame macro calculate the width
-%D of a centered box automatically (\type {fit}). When
-%D doing so, we need to reshape the box:
-
-% The next implementation is frozen! It preserves the depth,
-% otherwise we get problems with framed display math and auto
-% width.
-
-\newcount\framednoflines
-\newdimen\framedlastlength
-
-\def\resetshapeframebox
- {\framednoflines \zerocount
- \framedlastlength\zeropoint}
-
-\let\framedboxwidth \!!zeropoint
-\let\framedboxheight\!!zeropoint
-\let\framedboxdepth \!!zeropoint
-
-\chardef\reshapeframeboxmethod\plusone % 0=no flush, 1=old method 2=no depth messing
-
-%D The two variables \type {\framednoflines} and \type
-%D {\framedlastlength} can be used in a second pass to
-%D optimized framed material.
-
-% torture test / strange case (much depth) / method 2 needed
-%
-% \startTEXpage[frame=on]
-% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
-% test outside formula
-% \startformula \startalign \NC A \NC B \NR \intertext{test} \NC C \NC D \NR \stopalign \stopformula
-% \blank[big]
-% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
-% test outside formula
-% \startformula \startalign \NC \int_01 \NC B \NR \intertext{test} \NC \int_01 \NC D \NR \stopalign \stopformula
-% \stopTEXpage
-
-%D The examples on the next page show how one can give the
-%D frame as well as the background an additional offset and
-%D even a bit more depth. The blue outline is the frame, the
-%D red box is the background and the small black outline is the
-%D visualization of the resulting box, that is, we applied
-%D \type{\ruledhbox} to the result.
-
-%D \startpostponing
-%D \bgroup
-%D \unprotect
-%D \dontcomplain
-%D
-%D \startbuffer
-%D \vbox to \vsize
-%D \bgroup
-%D \startalignment[middle]
-%D \vss
-%D \leavevmode\vbox to .8\vsize
-%D \bgroup
-%D \hsize=300pt
-%D \setupframed
-%D [background=color,
-%D backgroundcolorachtergrondkleur=darkred,
-%D width=300pt,
-%D height=60pt,
-%D framecolorkaderkleur=DemoBlue,
-%D rulethickness=2pt]
-%D \def\status%
-%D {backgroundoffset=\framedparameter\c!backgroundoffset\\
-%D frameoffset=\framedparameter\c!frameoffset\\
-%D depth=\framedparameter\c!depth}
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=0pt]{\status}}
-%D \vss
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=0pt]{\status}}
-%D \vss
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=0pt,frameoffset=5pt]{\status}}
-%D \vss
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=2pt,frameoffset=5pt]{\status}}
-%D \vss
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=2pt]{\status}}
-%D \vss
-%D \leavevmode \ruledhbox{\framed[backgroundoffset=5pt,frameoffset=5pt]{\status}}
-%D \egroup
-%D \vss
-%D \stopalignment
-%D \egroup
-%D \stopbuffer
-%D
-%D \getbuffer \page
-%D
-%D {\setupframed[depth=4pt]\getbuffer} \page
-%D
-%D \protect
-%D \egroup
-%D \stoppostponing
-
-%D When typesetting the framed box inline, we have to keep the
-%D baseline intact outside as well as inside the framed box.
-
-\def\doinlineframedbox
- {\scratchdimen\dimexpr\strutdp+\ruledlinewidth\relax
- \ifboxhasoffset
- \advance\scratchdimen \framedparameter\c!offset
- \fi
- \setbox\framebox\hbox{\lower\scratchdimen\box\framebox}%
- \ht\framebox\strutht
- \dp\framebox\strutdp
- \box\framebox}
-
-%D We can also lower the box over the natural depth of the
-%D line.
-
-\def\doloweredframedbox
- {\ht\framebox\dimexpr\ht\framebox+\dp\framebox-\strutdp\relax
- \dp\framebox\strutdp
- \box\framebox}
-
-%D Hanging the content is mainly meant for cases like the
-%D following:
-%D
-%D \starttyping
-%D \framed[strut=no]
-%D {\framed[height=2cm,location=hanging]{test}%
-%D \framed[height=1cm,location=hanging]{test}}
-%D \stoptyping
-
-\def\dohangingframedbox % best with strut=no
- {\scratchdimen\dimexpr\ht\framebox+\dp\framebox\relax
- \ht\framebox\zeropoint
- \dp\framebox\scratchdimen}
-
-%D We can draw lines from left to right and top to bottom by
-%D using the normal \type{\hairline} command. Both directions
-%D need a different treatment.
-%D
-%D \startbuffer
-%D \framed[width=4cm] {alfa\hairline beta\hairline gamma}
-%D \framed[height=2cm] {alfa\hairline beta\hairline gamma}
-%D \framed[width=4cm,height=2cm]{alfa\hairline beta\hairline gamma}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \hbox{\getbuffer}
-%D \stoplinecorrection
-%D
-%D These macros try to adapt their behaviour as good as
-%D possible to the circumstances and act as natural as
-%D possible.
-
-\def\vboxedhairline
- {\bgroup
- \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
- \dimen4=\dimexpr\dimen2+\ruledlinewidth\relax
- \setbox0\vbox
- {\advance\hsize 2\dimen4
- \vskip\dimen2
- \hrule
- \!!height\ruledlinewidth
- \!!depth\zeropoint
- \!!width\hsize
- \vskip\dimen2}%
- %\endgraf\nointerlineskip\endgraf
- %\moveleft\dimen4\box0
- %\endgraf\nointerlineskip\localbegstrut
- \endgraf\obeydepth\nointerlineskip
- \moveleft\dimen4\box0
- \endgraf\nointerlineskip\localbegstrut % beware, we might kill it in a style using \vskip\lineheight
- \egroup} % so this must not be changed
-
-\def\hboxedhairline % use framed dimen
- {\bgroup
- \dimen2=\ifboxhasoffset \localoffset \else \zeropoint \fi
- \ifboxhasheight
- \dimen4\dimexpr\localheight/2+\strutdp-2\ruledlinewidth\relax
- \dimen6\dimexpr\localheight/2-\strutdp+2\ruledlinewidth\relax
- \else
- \dimen4\dimexpr\strutht+\dimen2\relax
- \dimen6\dimexpr\strutdp+\dimen2\relax
- \fi
- \unskip
- \setbox\scratchbox\hbox
- {\hskip\dimen2
- \vrule\!!height\dimen4\!!depth\dimen6\!!width\ruledlinewidth
- \hskip\dimen2}%
- \ht\scratchbox\strutht
- \dp\scratchbox\strutdp
- \box\scratchbox
- \ignorespaces
- \egroup}
-
-%D The argument of the frame command accepts \type{\\} as a
-%D sort of newline signal. In horizontal boxes it expands to a
-%D space.
-
-\def\vboxednewline
- {\endgraf\ignorespaces}
-
-\def\hboxednewline
- {\unskip\normalspace\ignorespaces}
-
-%D We can set each rule on or off. The default setting is
-%D inherited from \type{frame}. An earlier implementation
-%D use a bit different approach, but the new one seems more
-%D natural:
-%D
-%D \bgroup
-%D \setuptyping[margin=0pt]
-%D \startlinecorrection
-%D \startbuffer
-%D \framed[offset=overlay,frame=on]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D
-%D \startbuffer
-%D \framed[offset=overlay,frame=on,bottomframe=off]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D
-%D \startbuffer
-%D \framed[offset=overlay,frame=on,bottomframe=on]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D
-%D \startbuffer
-%D \framed[offset=overlay,frame=off]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D
-%D \startbuffer
-%D \framed[offset=overlay,frame=off,bottomframe=off]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D
-%D \startbuffer
-%D \framed[offset=overlay,frame=off,bottomframe=on]{\darkred\blackrule}
-%D \stopbuffer
-%D \hbox{\getbuffer\vbox{\typebuffer}}
-%D \stoplinecorrection
-%D \egroup
-
-%D \macros
-%D {setupblackrules}
-%D
-%D The graphic capabilities of \TEX\ do not go beyond simple
-%D filled rules, except of course when using specials. Let's
-%D start with a warning: using this commands is far more slower
-%D than using the \TEX\ primitives \type{\hrule} and
-%D \type{\vrule}, but they save us some tokens. The
-%D characteristics of these rule drawing command can be set by:
-%D
-%D \showsetup{setupblackrules}
-
-\def\setupblackrules
- {\dodoubleargument\getparameters[\??bj]}
-
-%D \macros
-%D {blackrule}
-%D
-%D The simple command draws only one rule. Its optional
-%D argument can be used to specify the dimensions. By setting
-%D the width, height or depth to \type {max}, one gets the
-%D natural dimensions.
-%D
-%D \showsetup{blackrule}
-
-\def\doblackrule[#1]%
- {\hbox\bgroup
- \getparameters[\??bj][#1]%
- \setstrut
- \doif\@@bjwidth \v!max{\def\@@bjwidth {1em}}%
- \doif\@@bjheight\v!max{\def\@@bjheight{\strutht}}%
- \doif\@@bjdepth \v!max{\def\@@bjdepth {\strutdp}}%
- \localstartcolor[\@@bjcolor]%
- \vrule
- \!!width \@@bjwidth
- \!!height\@@bjheight
- \!!depth \@@bjdepth
- \localstopcolor
- \egroup}
-
-\unexpanded\def\blackrule
- {\dosingleempty\doblackrule}
-
-%D \macros
-%D {blackrules}
-%D
-%D One can call for a sequence of black rules, if needed
-%D equally spaced over the given width.
-%D
-%D \showsetup{blackrules}
-%D
-%D The two alternative calls are therefore:
-%D
-%D \startbuffer
-%D Tell me, is this according to the \blackrules[n=6]?
-%D These \blackrules[alternativevariant=b,n=10,distance=.2em,width=4cm] are quite clear.
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D or:
-%D
-%D \startvoorbeeld
-%D \startlines
-%D \getbuffer
-%D \stoplines
-%D \stopvoorbeeld
-%D
-%D We could of course have implemented this macro using
-%D \type{\leaders}, but this would probably have taken more
-%D tokens.
-
-\def\doblackrules[#1]%
- {\hbox\bgroup
- \getparameters[\??bj][#1]%
- \!!widtha\@@bjwidth
- \!!widthb\@@bjdistance
- \doif\@@bjalternative\c!b
- {\scratchcounter\@@bjn
- \ifnum\scratchcounter=\plusone
- \!!widthb\zeropoint
- \else
- \advance\scratchcounter \minusone
- \advance\!!widtha -\scratchcounter\!!widthb
- \divide \!!widtha \@@bjn
- \fi}%
- \localstartcolor[\@@bjcolor]%
- \dorecurse\@@bjn
- {\vrule
- \!!width \!!widtha
- \!!height\@@bjheight
- \!!depth \@@bjdepth
- \hskip\!!widthb}%
- \unskip
- \localstopcolor
- \egroup}
-
-\unexpanded\def\blackrules
- {\dosingleempty\doblackrules}
-
-%D The next commands can be used to draw margin rules. We
-%D support two methods: \marginrule{one for in||line use} and
-%D one that acts on a paragraph. Drawing a margin rule is
-%D rather straightforward because we can use the commands that
-%D put text in the margin.
-
-\def\dodrawmarginrule
- {\setbox\scratchbox\hbox
- {\vrule\!!depth\strutdepth\!!height\strutheight\!!width\@@karulethickness}%
- \smashbox\scratchbox % no \vsmash !!!
- \box\scratchbox}
-
-\def\drawmarginrule
- {\strut\inleft{\dodrawmarginrule}}
-
-%D \macros
-%D {marginrule}
-%D
-%D The first method gobbles words and simply puts a bar in the
-%D margin. This method is not entirely robust.
-%D
-%D \showsetup{marginrule}
-
-\definecomplexorsimple\marginrule
-
-\def\simplemarginrule
- {\let\processword\drawmarginrule
- \processwords}
-
-\def\complexmarginrule[#1]%
- {\ifnum#1<\@@kalevel\relax \else
- \def\@@kadefaultwidth{#1}%
- \expandafter\simplemarginrule
- \fi}
-
-%D We need an auxiliary variable
-
-\def\@@kadefaultwidth{1}
-
-%D \macros
-%D {setupmarginrules}
-%D
-%D This macro definitions show us that we can pass an optional
-%D level, which is matched against the previous set one. The
-%D level can be set up with
-%D
-%D \showsetup{setupmarginrules}
-
-\def\setupmarginrules
- {\dodoubleargument\getparameters[\??ka]}
-
-%D \macros
-%D {startmarginrule}
-%D
-%D The second method collects text and reformats it afterwards,
-%D using the shapebox macros. We prevent local margin rules.
-%D
-%D \showsetup{startmarginrule}
-
-\definecomplexorsimple\startmarginrule
-
-\def\simplestartmarginrule
- {\bgroup
- \let\drawmarginrule\relax
- \let\stopmarginrule\dostopmarginrule
- \beginofshapebox}
-
-\def\complexstartmarginrule[#1]%
- {\bgroup
- \let\drawmarginrule\relax
- \ifnum#1<\@@kalevel\relax
- \let\stopmarginrule\egroup
- \else
- \def\@@kadefaultwidth{#1}%
- \let\stopmarginrule\dostopmarginrule
- \expandafter\beginofshapebox
- \fi}
-
-\def\dostopmarginrule
- {\endofshapebox
- \reshapebox
- {\hbox{\inleftmargin{\dodrawmarginrule}\box\shapebox}}%
- \flushshapebox
- \egroup}
-
-%D \startbuffer
-%D \setupmarginrules[level=5]
-%D
-%D \startmarginrule[1]
-%D First we set the level at~5. Next we typeset this first
-%D paragraph as a level~1 one. As expected no rule show up.
-%D \stopmarginrule
-%D
-%D \startmarginrule[5]
-%D The second paragraph is a level~5 one. As we can see here,
-%D the marginal rule gets a width according to its level.
-%D \stopmarginrule
-%D
-%D \startmarginrule[8]
-%D It will of course be no surprise that this third paragraph
-%D has a even thicker margin rule. This behavior can be
-%D overruled by specifying the width explictly.
-%D \stopmarginrule
-%D \stopbuffer
-%D
-%D In next example we show most features. Watch the rule
-%D thickness adapting itself to the level.
-%D
-%D \startvoorbeeld
-%D \getbuffer
-%D \stopvoorbeeld
-%D
-%D We just said:
-%D
-%D \typebuffer
-
-%D \macros
-%D {vl, hl}
-%D
-%D The command \type{\vl} draws a vertical rule \vl\ with strut
-%D dimensions, multiplied with the factor specified in the
-%D optional argument. The height and depth are clipped \vl[3]
-%D to the baselinedistance. Its horizontal counterpart
-%D \type{\hl} draws a horizontal rule \hl\ with a width of 1em,
-%D multiplied with the optional factor. The horizontal rule is
-%D drawn on top of the baseline.
-%D
-%D \showsetup{vl}
-%D \showsetup{hl}
-
-\def\complexvl[#1]%
- {\bgroup
- \!!dimena#1\strutht
- \!!dimenb#1\strutdp
- \setbox\scratchbox\hbox
- {\vrule
- \!!width \linewidth
- \!!height\!!dimena
- \!!depth \!!dimenb}%
- \dp\scratchbox\strutdp
- \ht\scratchbox\strutht
- \box\scratchbox
- \egroup}
-
-\def\complexhl[#1]%
- {\hbox
- {\vrule
- \!!width #1\s!em
- \!!height\linewidth
- \!!depth \zeropoint}}
-
-\definecomplexorsimple\vl \def\simplevl{\complexvl[1]}
-\definecomplexorsimple\hl \def\simplehl{\complexhl[1]}
-
-%D \macros
-%D {hairline, thinrule, thinrules, setupthinrules}
-%D
-%D Drawing thin lines can of course easily be accomplished by
-%D the \TEX\ primitives \type{\hrule} and \type{\vrule}. The
-%D next few macros however free us from some specifications.
-%D
-%D \startbuffer
-%D some text
-%D
-%D \hairline
-%D
-%D some more text
-%D
-%D \thinrule
-%D
-%D more and more text
-%D
-%D hi \thinrule\ there
-%D
-%D and then the final text
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D becomes
-%D
-%D \startvoorbeeld
-%D \getbuffer
-%D \stopvoorbeeld
-%D
-%D So we've got
-%D
-%D \showsetup{hairline}
-%D \showsetup{thinrule}
-%D
-%D Both can be set up with:
-%D
-%D \showsetup{setupthinrules}
-%D
-%D We also have
-%D
-%D \showsetup{thinrules}
-%D
-%D which looks like: \thinrules[n=2]
-
-\def\thinrule
- {\strut
- \bgroup
- \chardef\ruletype\plusone
- \processaction
- [\@@dlalternative]
- [ \v!a=>\chardef\ruletype0,% no line
- %\v!b=>\chardef\ruletype1,% height/depth
- \v!c=>\chardef\ruletype2,% topheight/botdepth
- % 11=>\chardef\ruletype1,% fallback for backgrounds
- 0=>\chardef\ruletype0,% compatible with backgrounds
- % 1=>\chardef\ruletype1,% compatible with backgrounds
- 2=>\chardef\ruletype2]% compatible with backgrounds
- \doifsomething\@@dlrulethickness
- {\linewidth\@@dlrulethickness}%
- \ifdim\linewidth=\zeropoint
- \chardef\ruletype\zerocount
- \else
- \doifnot\@@dlframe\v!on{\chardef\ruletype\zerocount}%
- \fi
- \ifnum\ruletype=\plusone
- \doif\@@dlheight\v!max{\let\@@dlheight\!!plusone}%
- \doif\@@dldepth \v!max{\let\@@dldepth \!!plusone}%
- \else
- \let\@@dlheight\!!plusone
- \let\@@dldepth\!!plusone
- \fi
- \freezedimensionwithunit\@@dlheight\strutht
- \freezedimensionwithunit\@@dldepth\strutdp
- \divide\linewidth \plustwo
- \doifelse\@@dlbackground\v!color
- {\startcolor[\@@dlbackgroundcolor]%
- \ifnum\ruletype=\plustwo % prevent overshoot due to rounding
- \leaders
- \hrule
- \!!height\dimexpr\@@dlheight-.5\linewidth\relax
- \!!depth \dimexpr\@@dldepth -.5\linewidth\relax
- \hfill
- \else
- \leaders
- \hrule
- \!!height\@@dlheight
- \!!depth \@@dldepth
- \hfill
- \fi
- \stopcolor
- \ifcase\ruletype
- % no rule
- \or
- \startcolor[\@@dlcolor]%
- \hfillneg
- \leaders\hrule\!!height\linewidth\!!depth\linewidth\hfill
- \stopcolor
- \or
- \startcolor[\@@dlcolor]%
- \hfillneg\leaders\hrule\!!height\dimexpr-\@@dldepth+\linewidth\relax\!!depth\@@dldepth\hfill
- \hfillneg\leaders\hrule\!!height\@@dlheight\!!depth\dimexpr-\@@dlheight+\linewidth\relax\hfill
- \stopcolor
- \fi}
- {\ifcase\ruletype \else
- \startcolor[\@@dlcolor]%
- \leaders\hrule\!!height\@@dlheight\!!depth\@@dldepth\hfill
- \stopcolor
- \fi}%
- \strut
- \carryoverpar\egroup}
-
-\def\hairline
- {\endgraf
- \thinrule
- \endgraf}
-
-\def\dosetupthinrules[#1]%
- {\getparameters[\??dl][#1]}
-
-\def\setupthinrules
- {\dosingleargument\dosetupthinrules}
-
-\def\dothinrules[#1]%
- {\bgroup
- \dosetupthinrules[#1]%
- \@@dlbefore
- \assignvalue\@@dlinterlinespace\@@dlinterlinespace{1.0}{1.5}{2.0}%
- \spacing\@@dlinterlinespace
- \dorecurse\@@dln
- {\ifnum\recurselevel=\@@dln \dothinrulesnobreak \else
- \ifnum\recurselevel=2 \dothinrulesnobreak \fi\fi
- \thinrule
- \ifnum\recurselevel<\@@dln\relax
- % test needed, else messed up whitespace
- \ifx\@@dlinbetween\empty
- \softbreak
- \else
- \endgraf
- \nowhitespace
- \@@dlinbetween
- \fi
- \fi}%
- \doifelsenothing\@@dlafter
- {\carryoverpar\egroup}
- {\@@dlafter\egroup}}
-
-\def\thinrules
- {\dosingleempty\dothinrules}
-
-%D A couple of examples are given below.
-%D
-%D \startbuffer
-%D \setupthinrules[n=3,inbetween=,color=gray]
-%D
-%D test test \thinrules\ test test \par
-%D test test \thinrules [color=green] test test \par
-%D test test \thinrules [height=max, depth=max] test test \par
-%D
-%D \setupthinrules[height=.9,depth=.9]
-%D
-%D test test \thinrules\ test test \par
-%D test test \thinrules [alternativevariant=b] test test \par
-%D test test \thinrules [alternativevariant=c] test test \par
-%D test test \thinrules [alternativevariant=c,inbetween=\vskip2ex] test test \par
-%D \stopbuffer
-%D
-%D \typebuffer {\getbuffer}
-%D
-%D There are a couple of alternative ways to visualize rules
-%D using backgrounds. At first sight these may look strange,
-%D but they make sense in educational settings. The
-%D alternatives are more or less compatible with the more
-%D advanced \METAPOST\ based implementation.
-%D
-%D \startbuffer[a]
-%D \setupthinrules
-%D [n=2,
-%D backgroundcolor=gray ,
-%D rulethickness=1pt,
-%D colorkleur=donkerblauw,
-%D after=\blank,
-%D before=\blank]
-%D \stopbuffer
-%D
-%D \typebuffer[a]
-%D
-%D \startbuffer[b]
-%D \thinrules[alternativevariant=a]
-%D \thinrules[alternativevariant=b]
-%D \thinrules[alternativevariant=c]
-%D \stopbuffer
-%D
-%D \typebuffer[b] \getbuffer[a,b]
-%D
-%D \startbuffer[b]
-%D \thinrules[alternativevariant=a,background=color]
-%D \thinrules[alternativevariant=b,background=color]
-%D \thinrules[alternativevariant=c,background=color]
-%D \stopbuffer
-%D
-%D \typebuffer[b] \getbuffer[a,b]
-%D
-%D \startbuffer[b]
-%D \thinrules[alternativevariant=a,height=.8,depth=.8,background=color]
-%D \thinrules[alternativevariant=b,height=.8,depth=.8,background=color]
-%D \thinrules[alternativevariant=c,height=.8,depth=.8,background=color]
-%D \stopbuffer
-%D
-%D \typebuffer[b] \getbuffer[a,b]
-
-%D \macros
-%D {optimizethinrules}
-%D
-%D By saying \type {\thinrulestrue} or \type {-false}, we
-%D can influence the way dangling lines are handled.
-
-\newif\ifoptimizethinrules \optimizethinrulestrue
-
-\def\dothinrulesnobreak
- {\ifoptimizethinrules\penalty500\fi}
-
-%D \macros
-%D {startframedtext, setupframedtexts, defineframedtext}
-%D
-%D The general framing command we discussed previously, is not
-%D entirely suited for what we call framed texts, as for
-%D instance used in intermezzo's. The next examples show what
-%D we have in mind.
-%D
-%D \startbuffer[framed-0]
-%D \setupframedtexts
-%D [frame=off,
-%D width=\hsize,
-%D background=screen]
-%D
-%D \startframedtext
-%D By default the framed text is centered \dots
-%D \stopframedtext
-%D
-%D \startframedtext[right]
-%D \dots\ but we can also align left, middle and right.
-%D \stopframedtext
-%D \stopbuffer
-%D
-%D \startbuffer[framed-1]
-%D \defineframedtext
-%D [Example]
-%D [width=6cm,
-%D height=5cm]
-%D
-%D \startExample
-%D \typebuffer[framed-1]
-%D \stopExample
-%D \stopbuffer
-%D
-%D \startbuffer[framed-2]
-%D \defineframedtext
-%D [Example]
-%D [width=6cm]
-%D
-%D \startExample
-%D \typebuffer[framed-2]
-%D \stopExample
-%D \stopbuffer
-%D
-%D \startbuffer[framed-3]
-%D \defineframedtext
-%D [Example]
-%D [height=5cm]
-%D
-%D \startExample
-%D \typebuffer[framed-3]
-%D \stopExample
-%D \stopbuffer
-%D
-%D \startbuffer[framed-4]
-%D \defineframedtext
-%D [Example]
-%D [width=fit,height=broad]
-%D
-%D \Example{a very exciting example}
-%D \stopbuffer
-%D
-%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-0] \egroup
-%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-1] \egroup
-%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-2] \egroup
-%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-3] \egroup
-%D \bgroup \setuptyping[margin=0pt] \getbuffer[framed-4] \egroup
-%D
-%D Here we can see that we have a predefined framed text class
-%D as well as the tools for defining our own. So we have:
-%D
-%D \showsetup{setupframedtexts}
-%D
-%D as well as the definition command:
-%D
-%D \showsetup{defineframedtext}
-%D
-%D that generates two commands:
-%D
-%D \showsetup{start<<framedtext>>}
-%D \showsetup{<<framedtext>>}
-%D
-%D The next definition shows the defaults.
-
-\def\dodefineframedtext[#1][#2]%
- {\presetlocalframed[\??kd#1]%
- \getparameters[\??kd#1]
- [\c!width=0.75\hsize,
- \c!height=\v!fit,
- \c!align=\v!yes,
- \c!top=,
- \c!bottom=\vfill,
- \c!offset=1em,
- \c!bodyfont=,
- \c!style=,
- \c!color=,
- \c!left=,
- \c!right=\hfill,
- \c!before=\blank,
- \c!after=\blank,
- \c!inner=,
- \c!frame=\v!on,
- \c!topframe=,
- \c!bottomframe=,
- \c!leftframe=,
- \c!rightframe=,
- \c!radius=.5\bodyfontsize,
- \c!corner=\v!rectangular,
- \c!foregroundcolor=,
- \c!foregroundstyle=,
- \c!background=,
- \c!backgroundcolor=,
- \c!backgroundscreen=\@@rsscreen,
- \c!linecorrection=\v!on,
- \c!depthcorrection=\v!on,
- \c!margin=\v!standard,
- \c!orientation=,
- \c!indenting=,
- #2]%
- \setvalue{\e!start#1}{\dostartframedtext[#1]}%
- \setvalue{\e!stop #1}{\dostopframedtext }%
- \setvalue {#1}{\doframedtext [#1]}}
-
-\def\defineframedtext
- {\dodoubleempty\dodefineframedtext}
-
-%D We define the general (and original) case by just saying:
-
-\defineframedtext[\v!framedtext]
-
-%D We need several steps before the actual job is done,
-%D because we have to handle an optional identifier (and
-%D because these commands evolved out of a single case).
-
-\def\framedtextparameter#1#2%
- {\csname\??kd#1#2\endcsname}
-
-\def\dosetupframedtexts[#1][#2]%
- {\ifsecondargument
- \def\docommand##1{\getparameters[\??kd##1][#2]}%
- \processcommacommand[#1]\docommand % new, #1 may be macro
- \else
- \getparameters[\??kd\v!framedtext][#1]%
- \fi}
-
-\def\setupframedtexts
- {\dodoubleempty\dosetupframedtexts}
-
-\def\dostartframedtext
- {\bgroup\dotripleempty\dodostartframedtext}
-
-\def\dodostartframedtext[#1][#2][#3]%
- {\doifassignmentelse{#2}
- {\dododostartframedtext[#1][][#2]}
- {\dododostartframedtext[#1][#2][#3]}}
-
-\setfalse\framedtextlocationnone
-
-\def\dododostartframedtext[#1][#2][#3]% #3 only passed to framed, not to framedtext
- {\doifsomething{#2}{\setvalue{\??kd#1\c!location}{#2}}% does not listen to #3
- \setfalse\framedtextlocationnone
- \processaction % \v!low en \v!depth are already taken !
- [\framedtextparameter{#1}\c!location]
- [ \v!left=>\letvalue{\??kd#1\c!left }\relax
- \letvalue{\??kd#1\c!right}\hfill,
- \v!right=>\letvalue{\??kd#1\c!left }\hfill
- \letvalue{\??kd#1\c!right}\relax,
- \v!middle=>\letvalue{\??kd#1\c!left }\hfill
- \letvalue{\??kd#1\c!right}\hfill,
- \v!none=>\letvalue{\??kd#1\c!left }\relax % new
- \letvalue{\??kd#1\c!right}\relax % new
- \settrue\framedtextlocationnone]%
- \letvalue{\??kd#1\c!location}\empty
- % removed 06/2001
- % \forgetparindent
- % added 06/2001 [see demo-bbv]
- \localhsize\hsize \checkframedtext
- % so far
- \setbox\framebox\vbox
- \startboxedcontent
- \hsize\localhsize
- % \insidefloattrue % ? better
- \expanded{\switchtobodyfont[\framedtextparameter{#1}\c!bodyfont]}%
- \startcolor[\framedtextparameter{#1}\c!color]%
- \localframed[\??kd#1][\c!strut=\v!no,#3]% todo: use delayedstrut
- \bgroup
- \let\\=\endgraf
- \framedtextparameter{#1}\c!inner % oud spul
- \doifvalue{\??kd#1\c!depthcorrection}\v!on % new, inside box
- {\bgroup
- \verticalstrut
- % we need \nowhitespace in case of setups setting whitespace
- % nb, not safe, text vs \vbox as next
- \vskip-\struttotal
- \nowhitespace % na vskip ! new 20/05/2004, fails with next content being box (\scale{..})
- }%
- \doinhibitblank % \blank[\v!disable]% plaatst signal
-\setupindenting[\framedtextparameter{#1}\c!indenting]%
- \doconvertfont{\framedtextparameter{#1}\c!style}\empty
- \def\dostopframedtext{\dodostopframedtext{#1}{#2}}}
-
-%D The \type {none} option is handy for nested usage, as
-%D in the presentation styles, where we don't want
-%D interference.
-
-\def\dodostopframedtext#1#2% % no \baselinecorrection, see faq docs
- {\endgraf
- \removelastskip
- \doifvalue{\??kd#1\c!depthcorrection}\v!on % local and global
- {\forgetall
- \vskip-\struttotal
- \verticalstrut
- \egroup
- \forgetall
- \vskip-\lineheight
- % will be an option, not default
- % \setbaselinecorrections
- % \donegbotbaselinecorrection
- \verticalstrut}
- \stopboxedcontent
- \stopcolor
- \ifconditional\framedtextlocationnone
- \egroup
- \box\framebox
- \else\ifinsidefloat
- \egroup
- \box\framebox
- \else
- \egroup
- \doplacement[\??kd#1][\c!depthcorrection=\v!off]{\box\framebox}%
- \fi\fi
- \egroup}
-
-%D Placement can be ignored:
-%D
-%D \starttyping
-%D \hbox to \hsize \bgroup
-%D \startframedtext[none][width=.5\textwidth] \input tufte \stopframedtext
-%D \startframedtext[none][width=.5\textwidth] \input zapf \stopframedtext
-%D \egroup
-%D
-%D \hbox to \hsize \bgroup
-%D \setupframedtexts[location=none]%
-%D \startframedtext[width=.5\textwidth] \input zapf \stopframedtext
-%D \startframedtext[width=.5\textwidth] \input tufte \stopframedtext
-%D \egroup
-%D \stoptyping
-
-%D The simple brace (or group) delimited case is typeset
-%D slightly different and is not aligned.
-
-\def\doframedtext
- {\bgroup\dodoubleempty\dodoframedtext}
-
-\def\dodoframedtext[#1][#2]% beware!
- {\expanded{\switchtobodyfont[\getvalue{\??kd#1\c!bodyfont}]}%
- \localframed[\??kd#1][\c!strut=\v!no,#2]%
- \bgroup
- \blank[\v!disable]%
- \let\\=\endgraf
- \getvalue{\??kd#1\c!inner}% % kleur naar outer level
- \dostartattributes{\??kd#1}\c!style\c!color\empty
- \bgroup
- \aftergroup\docloseframedtext
- \let\next=}
-
-\def\docloseframedtext
- {\removelastskip
- \dostopattributes
- \egroup
- \egroup}
-
-%D \macros
-%D {defineframed}
-%D
-%D One can also define simple framed texts, using:
-%D
-%D \showsetup{defineframed}
-
-\def\defineframed
- {\dodoubleempty\dodefineframed}
-
-\def\dodefineframed[#1][#2]%
- {\iffirstargument
- \setvalue{#1}{\dodoubleempty\doframed[#2]}%
- \fi}
-
-\def\doframed[#1][#2]%
- {\framed[#1,#2]}
-
-%D \macros
-%D {textrule, starttextrule, setuptextrules}
-%D
-%D Putting rules before and after a paragraph is very space
-%D sensitive, but the next command handles that quite well. It
-%D comes in two disguises:
-%D
-%D \startbuffer
-%D \textrule[top]{fragments}
-%D \input reich
-%D \textrule
-%D \stopbuffer
-%D
-%D \bgroup \typebuffer \getbuffer \egroup
-%D
-%D \startbuffer
-%D \setuptextrules
-%D [width=90pt,distance=12pt,rulecolor=blue,
-%D bodyfont=small,style=\sc,color=red]
-%D
-%D \starttextrule{Ship Building Tools}
-%D \nl \setuptolerance[tolerant] \input materie
-%D \stoptextrule
-%D \stopbuffer
-%D
-%D \bgroup \typebuffer \getbuffer \egroup
-%D
-%D \startbuffer
-%D \setuptextrules
-%D [location=inmargin,
-%D bodyfont=small,style=slantedbold]
-%D
-%D \starttextrule{wonderful}
-%D \input tufte
-%D \stoptextrule
-%D \stopbuffer
-%D
-%D \bgroup \typebuffer \getbuffer \egroup
-%D
-%D The formal definition of these commands is:
-%D
-%D \showsetup{textrule}
-%D \showsetup{starttextrule}
-%D \showsetup{setuptextrules}
-%D
-%D The implementation looks a bit complicated due to the
-%D optional arguments.
-
-\def\setuptextrules
- {\dodoubleargument\getparameters[\??tl]}
-
-\def\complextextrule[#1]% if needed we can make it installable
- {\let\next\dobottomtextrule
- \processaction
- [#1]
- [ \v!top=>\let\next\dotoptextrule,
- \v!middle=>\let\next\domiddletextrule,
- \v!bottom=>\let\next\dobottomtextrule]%
- \dosinglegroupempty\next}
-
-\definecomplexorsimple\textrule
-
-\def\simpletextrule
- {\dosinglegroupempty\dounknowntextrule}
-
-\def\docomplextextrule#1%
- {\bgroup
- \advance\hsize\dimexpr-\rightskip-\leftskip\relax
- \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
- \color[\@@tlrulecolor]
- {\leaders\hrule\!!height\dimen4\!!depth\dimen6\hfill}}%
- \ht\scratchbox\strutht
- \dp\scratchbox\strutdp
- \noindent\box\scratchbox
-%\nobreak\verticalstrut\kern-\struttotal
-% evt \witruimte
- \egroup}
-
-\def\dotoptextrule#1%
- {\page[\v!preference] % interferes
- %\whitespace % no
- \@@tlbefore
- \docomplextextrule{#1}%
-% todo, option: \doifnothing{#1}{\ruledvskip-.5ex}
- \nowhitespace
- \@@tlinbetween
- \endgraf}
-
-\def\dodobottomtextrule#1#2%
- {\ifhmode
- \endgraf
- \fi
- \dimen0\strutdp
- \ifdim\prevdepth>\strutdp\else % was <\strutdp
- \ifdim\prevdepth>\zeropoint
- \advance\dimen0 -\prevdepth
- \fi
- \fi
- \advance\dimen0 .5ex
- \vskip\dimen0
-% ==
-% \vskip\dimexpr \strutdp + .5ex
-% \ifdim\prevdepth>\strutdp\else\ifdim\prevdepth>\zeropoint-\prevdepth\fi\fi\relax
-%
- \@@tlinbetween
- \doifelsenothing{#2}
- {\bgroup
- \advance\hsize\dimexpr-\rightskip-\leftskip\relax
- \nointerlineskip
- \moveleft-\leftskip\vbox
- {\color[\@@tlrulecolor]
- {\hrule\!!depth\linewidth\!!height\zeropoint\!!width\hsize}}%
- \egroup}
- {\docomplextextrule{#2}}%
- \ifvmode\prevdepth\zeropoint\fi
- #1%
- \page[\v!preference]}
-
-\def\dobottomtextrule
- {\dodobottomtextrule\@@tlafter}
-
-\def\domiddletextrule
- {\dodobottomtextrule\@@tlinbetween}
-
-\def\dounknowntextrule
- {\iffirstargument
- \@EA\dotoptextrule
- \else
- \@EA\dobottomtextrule\@EA\empty
- \fi}
-
-%D The grouped commands also supports bodyfont switching:
-
-\def\starttextrule#1%
- {\bgroup
- \def\dounknowntextrule{\domiddletextrule}
- \dotoptextrule{#1}
- \bgroup
- \doifsomething\@@tlbodyfont{\switchtobodyfont[\@@tlbodyfont]}}
-
-\def\stoptextrule
- {\par
- \egroup
- \dobottomtextrule\empty
- \egroup}
-
-%D \macros
-%D {fillinrules, setupfillinrules}
-%D
-%D The next few commands do not really deserve a place in a
-%D core module, because they deal with specific typography.
-%D Nevertheless I decided to make them part of the core,
-%D because they permit us to make questionaires. Let's start
-%D with some examples.
-%D
-%D \fillinrules[n=2,width=fit]{first}
-%D \fillinrules[n=2,width=broad]{first}
-%D \fillinrules[n=2,width=3cm]{first}
-%D \fillinrules[n=2,width=3cm,distance=.5em,separator=:]{first}
-%D \fillinrules[n=2]{first}{last}
-%D \fillintext{first}{last} \input reich \par
-%D
-%D The main command is \type{\fillinrules}. This command takes
-%D one and an optional second argument and sets a paragraph with
-%D empty visualized lines.
-%D
-%D \showsetup{fillinrules}
-%D \showsetup{setupfillinrules}
-
-\def\setupfillinrules
- {\dodoubleargument\getparameters[\??il]}
-
-\definecomplexorsimpleempty\fillinrules
-
-\def\complexfillinrules[#1]%
- {\def\docomplexfillinrules##1##2%
- {\dodocomplexfillinrules[#1]{##1}{##2}{\thinrules
- [\c!n=\@@iln,\c!interlinespace=\@@ilinterlinespace,\c!before=,\c!after=]}}%
- \dodoublegroupempty\docomplexfillinrules}
-
-\def\dodocomplexfillinrules[#1]#2#3#4%
- {\endgraf
- \@@ilbefore
- \begingroup
- \setupfillinrules[#1]%
- \noindent
- \doifsomething{#2}
- {\doifelse\@@ilwidth\v!fit
- {\let\@@ildistance\!!zeropoint
- \hbox}
- {\doifelse\@@ilwidth\v!broad
- {\hbox}
- {\hbox to \@@ilwidth}}%
- \bgroup
- \doattributes\??il\c!style\c!color{\strut#2\hfill\@@ilseparator}%
- \hskip\@@ildistance
- \egroup}%
- %\hangindent=\wd0\relax % tzt hang=yes,n
- %\parindent=\hangindent
- %\box0\relax
- \setupwhitespace[\v!big]%
- \ignorespaces
- #4%
- \doifsomething{#3}
- {\kern\@@ildistance
- \doattributes\??il\c!style\c!color{#3\strut}}%
- \endgroup
- \endgraf
- \@@ilafter}
-
-%D \macros
-%D {fillintext}
-%D
-%D To provide compatible layouts when texts and lines are
-%D mixed, one can typeset a paragraph by using the command
-%D \type{\fillintext}.
-%D
-%D \showsetup{fillintext}
-
-\definecomplexorsimpleempty\fillintext
-
-\def\complexfillintext[#1]% rather rough, using an \unhbox is suboptimal
- {\def\docomplexfillintext##1##2%
- {\dowithnextbox
- {\dodocomplexfillinrules[#1]{##1}{\hfill##2}{\unhbox\nextbox\unskip}}%
- \hbox\bgroup\let\par\egroup\ignorespaces}%
- \dodoublegroupempty\docomplexfillintext}
-
-%D \macros
-%D {fillinline, setupfillinlines}
-%D
-%D Another member of the family takes care of putting a (often
-%D small) rule after a piece of text, like
-%D
-%D \startbuffer
-%D \fillinline \input reich \par
-%D \fillinline[margin=0cm] \input reich \par
-%D \stopbuffer
-%D
-%D \startvoorbeeld
-%D \getbuffer
-%D \stopvoorbeeld
-%D
-%D which was typeset by saying:
-%D
-%D \typebuffer
-%D
-%D The two commands that take care of this are:
-%D
-%D \showsetup{fillinline}
-%D \showsetup{setupfillinlines}
-
-\def\setupfillinlines
- {\dodoubleargument\getparameters[\??iv]}
-
-\definecomplexorsimpleempty\fillinline
-
-\def\complexfillinline[#1]%
- {%\endgraf % interferes with \definedescription cum suis
- \@@ivbefore
- \begingroup
- \setupfillinlines[#1]%
- \advance\rightskip \@@ivmargin
- \parfillskip\zeropoint
- \def\par % very dangerous
- {\let\par\endgraf % -)
- \ifhmode\unskip\hfill\fi
- \scratchdimen\dimexpr\@@ivwidth-\@@ivdistance\relax
- \ifdim\scratchdimen>\@@ivmargin\else\expandafter\rlap\fi
- {\kern\@@ivdistance
- \vrule
- \!!width \scratchdimen
- \!!height.5\linewidth
- \!!depth .5\linewidth}%
- \endgraf % !
- \endgroup
- \endgraf % !
- \@@ilafter}}
-
-%D \stopdocumentation
-%D \bgroup
-%D
-%D \setupframedtexts
-%D [setuptext]
-%D [background=color,backgroundcolor=white]
-%D
-%D \startbuffer
-%D \setupbackground
-%D [backgroundoffset=4pt,
-%D background=screen,
-%D frame=on,
-%D framecolor=red,
-%D leftoffset=2pt]
-%D \stopbuffer
-%D
-%D \getbuffer
-%D
-%D \startbackground
-%D
-%D \macros
-%D {setupbackground,startbackground,background}
-%D
-%D The section deals with backgrounds in the running text. This
-%D means that texts is to be collected and split over pages. To
-%D show what can be done, we provide this part of the
-%D documentation with some gray background and a red frame.
-%D Both the background and frame can have all characteristics
-%D of \type{\framed}. This time we used the setting:
-%D
-%D \typebuffer
-%D
-%D The implementation is not that sophisticated, but suffices.
-%D The main problem with this kind of functionality is to get
-%D the spacing all right.
-
-%D Specifying the background is more or less the same as
-%D specifying a framed box.
-%D
-%D \showsetup{setupbackground}
-
-\presetlocalframed[\??ag]
-
-\def\dosetupbackground[#1]%
- {\getparameters[\??ag][#1]%
- \doifelse\@@agstate\v!start
- {\let\startbackground\dostartbackground
- \let\stopbackground \dostopbackground
- \let\background \dobackground}
- {\let\startbackground\relax
- \let\stopbackground \relax
- \let\background \relax}}
-
-\def\setupbackground
- {\dosingleargument\dosetupbackground}
-
-%D Actually typesetting the background is implemented rather
-%D straightforward. We need to handle some spacing as well as
-%D the (often) a bit smaller horizontal size.
-%D
-%D \showsetup{startbackground}
-%D
-%D Although we could have used a scratch one, we first
-%D declare a boolean.
-
-% 0=no-split, 1=no-split+indent, 2=split, 3=split+indent
-
-\chardef\backgroundsplitmode\plusthree
-
-%D The \type{\vbox to \lineheight{}\vskip\zeropoint}
-%D construction gives the first real line a decent height by
-%D adding a dummy line.
-
-\def\dostartbackground
- {\endgraf
- \bgroup
- \setbox0\vbox\bgroup
- \vbox to \lineheight{}\vskip\zeropoint
- \blank[\v!disable]
- % \advance\hsize -\@@agleftoffset
- % \advance\hsize -\@@agrightoffset
- \leftskip \@@agleftoffset % new **
- \rightskip\@@agrightoffset} % new **
-
-%D This dummy line is removed by \type{\setbox2=\vsplit0 to
-%D \lineheight}. That way \type{\topskip} takes care of the
-%D lineheight. I'll probably forget to apply this trick
-%D elsewhere.
-
-\def\dostopbackground % improved version (i hope)
- {\endgraf
- \removelastskip
- \egroup
- \dimen2\leftskip % new **
- \forgetall
- \ifinsidefloat
- \chardef\backgroundsplitmode\zerocount
- \fi
- \ifcase\backgroundsplitmode
- \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
- \or
- \hskip\dimen2
- \localframed[\??ag][\c!offset=\v!overlay]{\box0}%
- \else
- \splitmaxdepth\boxmaxdepth
- \splittopskip\topskip
- \setbox2\vsplit0 to \lineheight % get rid of fake line
- \loop
- \ifdim\pagetotal=\zeropoint % empty page
- \scratchdimen\textheight
- \chardef\backgroundsplit\plusone % split to max height
- \else
- \setbox\scratchbox\vbox{\@@agbefore}%
- \scratchdimen\dimexpr\pagegoal-\ht\scratchbox-\pagetotal\relax
- \chardef\backgroundsplit\plustwo % split to partial height
- \fi
- \advance\scratchdimen\dimexpr-\@@agtopoffset-\@@agbottomoffset\relax
- \ifdim\scratchdimen>2\lineheight\relax % reasonable, will be configurable
- \ifdim\ht0>\scratchdimen % larger than page
- \setbox2\vsplit0 to \scratchdimen
- \else
- \setbox2\box0
- \chardef\backgroundsplit\zerocount % no split
- \fi
- \setbox2\vbox \ifcase\backgroundsplit\or to \textheight \fi % max split
- {\vskip\@@agtopoffset
- \popsplitproperties
- \unvcopy2
- \prevdepth\dp2
- \obeydepth
- \vskip\@@agbottomoffset
- \vfill}
- \@@agbefore
- \ifcase\backgroundsplit\or\or % partial split
- \ifdim\pagegoal<\maxdimen
- \pagegoal=1.2\pagegoal % be a bit more tolerant
- \fi
- \fi
- \startlinecorrection
- %\localframed[\??ag][\c!offset=\v!overlay]{\hskip\@@agleftoffset\box2\hskip\@@agrightoffset}%
- \ifnum\backgroundsplitmode=\plusthree \hskip\dimen2 \fi %
- \localframed[\??ag][\c!offset=\v!overlay]{\box2}% new **
- \stoplinecorrection
- \ifcase\backgroundsplit % no split
- \@@agafter
- \else % some split
- \vfill\eject % geen \page !
- \fi
- \else
- \page
- \fi
- \ifdim\ht0>\zeropoint \repeat
- \fi
- \egroup
- \endgraf}
-
-%D As a bonus we also have a short command, that is of not
-%D much use, but kept there for historic reasons.
-%D
-%D \showsetup{background}
-
-\def\dobackground
- {\bgroup
- \dowithnextbox
- {\localframed[\??ag][\c!offset=\v!overlay]{\flushnextbox}\egroup}
- \vbox}
-
-%D \stopdocumentation
-%D \stopbackground
-%D \egroup
-
-%D New, for the moment private; let's see when GB finds out
-%D about this one and its obscure usage. It's used in:
-%D
-%D \startbuffer
-%D \defineframedtext
-%D [tabulateframe]
-%D [offset=overlay,
-%D backgroundoffset=3pt,
-%D background=color,
-%D backgroundcolor=green]
-%D
-%D \setuptabulate
-%D [tabulate]
-%D [frame=tabulateframe]
-%D
-%D \setuptables
-%D [frame=tabulateframe]
-%D
-%D \input tufte
-%D
-%D \starttabulate[|l|l|]
-%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
-%D \NC test \NC test \NC \NR \NC test \NC test \NC \NR
-%D \stoptabulate
-%D
-%D \input tufte
-%D
-%D \starttable[|l|l|]
-%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
-%D \NC test \NC test \NC \AR \NC test \NC test \NC \AR
-%D \stoptable
-%D \stopbuffer
-%D
-%D \typebuffer
-
-\def\defineframedcontent
- {\dodoubleempty\dodefineframedcontent}
-
-\def\dodefineframedcontent[#1][#2]%
- {\presetlocalframed[\??fc#1]%
- \getparameters[\??fc#1]
- [\c!leftoffset=\zeropoint,
- \c!rightoffset=\getvalue{\??fc#1\c!leftoffset},
- \c!topoffset=\zeropoint,
- \c!bottomoffset=\getvalue{\??fc#1\c!topoffset},
- \c!strut=\v!no,
- \c!offset=\v!overlay,
- \c!linecorrection=\v!no,
- \c!left=,
- \c!right=,
- #2]}
-
-\let\setuplocalframed\getparameters
-
-\def\setupframedcontent
- {\dodoubleempty\dosetupframedcontent}
-
-\def\dosetupframedcontent[#1][#2]%
- {\def\docommand##1{\getparameters[\??fc##1][#2]}%
- \processcommacommand[#1]\docommand}
-
-\def\startframedcontent[#1]%
- {\bgroup
- \let\stopframedcontent\egroup
- \doifnot{#1}\v!off
- {\doifdefined{\??fc#1\c!frame}
- {\def\stopframedcontent{\dostopframedcontent{#1}}%
- \dostartframedcontent{#1}}}}
-
-\def\dostartframedcontent#1%
- {\setbox\framebox\hbox\bgroup
- \setlocalhsize
- \hsize\localhsize
- \advance\hsize\dimexpr-\getvalue{\??fc#1\c!leftoffset}-\getvalue{\??fc#1\c!rightoffset} \relax
- \advance\vsize\dimexpr-\getvalue{\??fc#1\c!topoffset} -\getvalue{\??fc#1\c!bottomoffset}\relax
- \hskip\getvalue{\??fc#1\c!leftoffset}%
- \vbox\bgroup
- \vskip\getvalue{\??fc#1\c!topoffset}%
- \vbox\bgroup
- \forgetall
- \blank[\v!disable]}
-
-\def\dostopframedcontent#1%
- {\removelastskip
- \egroup
- \vskip\getvalue{\??fc#1\c!bottomoffset}%
- \egroup
- \hskip\getvalue{\??fc#1\c!rightoffset}%
- \egroup
- \doifvalue{\??fc#1\c!width}\v!fit
- {\letvalue{\??fc#1\c!width}\v!fixed}% no shapebox
- \ifinsidefloat
- \donefalse
- \else
- \doifelsevalue{\??fc#1\c!linecorrection}\v!yes\donetrue\donefalse
- \fi
- % plaats ?
- \ifdone\startlinecorrection\fi
- \getvalue{\??fc#1\c!left}% new
- \localframed[\??fc#1]{\box\framebox}%
- \getvalue{\??fc#1\c!right}% new
- \ifdone\stoplinecorrection\fi
- \egroup}
-
-%D \macros
-%D {backgroundline}
-%D
-%D For the moment an undocumented feature, but a cancidate
-%D for going public.
-
-\def\backgroundline[#1]%
- %{\doifsomething{#1}{\dobackgroundline{#1}}\hbox}
- {\doifcolorelse{#1}{\dobackgroundline{#1}\hbox}\hbox}
-
-% \def\backgroundline[#1]%
-% {\doifcolor{#1}{\dobackgroundline{#1}}\hbox}
-
-\def\dobackgroundline#1%
- {\dowithnextbox
- {\hbox
- {\localcolortrue
- \startcolor[#1]%
- \vrule
- \!!width \nextboxwd
- \!!height\nextboxht
- \!!depth \nextboxdp
- \stopcolor
- \hskip-\nextboxwd
- \flushnextbox}}}
-
-%D \macros
-%D {encircled}
-%D
-%D Some not so robust left||overs (borrowed from Knuth,
-%D \TEX Book\ page 356):
-
-\def\encircled#1%
- {{\ooalign{\hfil\raise0.07ex\hbox{{\tx#1}}\hfil\crcr\mathhexbox20D}}}
-
-\let\omcirkeld\encircled
-
-\setuplinewidth
- [\v!medium]
-
-\setupframed
- [\c!width=\v!fit,
- \c!height=\v!broad,
- \c!lines=,
- \c!offset=0.25ex, % \defaultframeoffset
- \c!empty=\v!no,
- \c!frame=\v!on,
- \c!topframe=,
- \c!bottomframe=,
- \c!leftframe=,
- \c!rightframe=,
- \c!radius=.5\bodyfontsize,
- \c!rulethickness=\linewidth,
- \c!corner=\v!rectangular,
- \c!depth=\!!zeropoint,
- \c!foregroundcolor=,
- \c!foregroundstyle=,
- \c!background=,
- \c!backgroundscreen=\@@rsscreen,
- \c!backgroundcolor=,
- \c!backgroundoffset=\!!zeropoint,
- \c!framecolor=,
- \c!frameoffset=\!!zeropoint,
- \c!backgroundcorner=\framedparameter\c!corner,
- \c!backgroundradius=\framedparameter\c!radius,
- \c!backgrounddepth=\framedparameter\c!depth,
- \c!framecorner=\framedparameter\c!corner,
- \c!frameradius=\framedparameter\c!radius,
- \c!framedepth=\framedparameter\c!depth,
- \c!component=,
- \c!align=,
- \c!bottom=\vss,
- \c!top=,
- \c!strut=\v!yes,
- \c!autostrut=\v!yes,
- \c!location=\v!normal,
- \c!orientation=,
- \c!autowidth=\v!yes,
- \c!setups=]
-
-\setupscreens
- [%\c!factor=1.0, % obsolete
- %\c!method=\v!external, % obsolete
- \c!screen=0.95]
-
-\setupblackrules
- [\c!n=3,
- \c!width=1em,
- \c!height=1ex,
- \c!depth=\!!zeropoint,
- \c!alternative=\c!a,
- \c!distance=.25ex,
- \c!color=]
-
-\setupmarginrules
- [\c!level=0,
- \c!rulethickness=\@@kadefaultwidth\linewidth]
-
-\setupthinrules
- [\c!interlinespace=\v!small,
- \c!n=3,
- \c!before=,
- \c!inbetween={\blank[\v!white]},
- \c!after=,
- \c!color=,
- \c!height=.5\linewidth,
- \c!depth=.5\linewidth,
- \c!frame=\v!on, % compatible with textbackgrounds
- \c!alternative=\v!b,
- \c!backgroundcolor=,
- \c!background=,
- \c!rulethickness=]
-
-\setuptextrules
- [\c!location=\v!left,
- \c!before=\blank,
- \c!after=\blank,
- \c!inbetween=,
- \c!width=2em,
- \c!style=\v!bold,
- \c!color=,
- \c!rulecolor=,
- \c!bodyfont=,
- \c!distance=.5em]
-
-\setupfillinrules
- [\c!width=\v!broad,
- \c!distance=1em,
- \c!before=\blank,
- \c!after=\blank,
- \c!n=1,
- \c!interlinespace=\v!small,
- \c!separator=,
- \c!style=\v!normal,
- \c!color=]
-
-\setupfillinlines
- [\c!width=3cm,
- \c!margin=\@@ivwidth,
- \c!distance=1em,
- \c!before=\blank,
- \c!after=\blank]
-
-\setupbackground
- [\c!leftoffset=.5\bodyfontsize,
- \c!rightoffset=\@@agleftoffset,
- \c!topoffset=\!!zeropoint,
- \c!bottomoffset=\@@agtopoffset,
- \c!state=\v!start,
- \c!radius=.5\bodyfontsize,
- \c!corner=\v!rectangular,
- \c!frame=\v!off,
- \c!color=,
- \c!depth=\!!zeropoint,
- \c!background=\v!screen,
- \c!backgroundcolor=\@@agcolor,
- \c!screen=\@@rsscreen,
- \c!before=,
- \c!after=]
-
-\protect \endinput
diff --git a/tex/context/base/core-sec.mkiv b/tex/context/base/core-sec.mkiv
deleted file mode 100644
index fdab75bc8..000000000
--- a/tex/context/base/core-sec.mkiv
+++ /dev/null
@@ -1,2621 +0,0 @@
-%D \module
-%D [ file=core-sec,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Sectioning,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% start-stop per section en dan combineren met sectieblok; in dat geval
-% eenvoudiger per-* acties
-
-% nummeren per sectieblok implementeren
-
-% this module needs a clean up, currently some manipulations
-% take place multiple times; also, some clever recursive level
-% thing makes more sense
-
-% in manual (zie prikkels) : tussen=\blanko is enige hook om
-% met kop-in-hoofd een spatiering af te dwingen
-
-\writestatus{loading}{Context Core Macros / Sectioning}
-
-\startmessages dutch library: structures
- title: structuur
- 1: begin van sectieblok --
- 2: eind van sectieblok --
-\stopmessages
-
-\startmessages english library: structures
- title: structure
- 1: begin of sectionblock --
- 2: end of sectionblock --
-\stopmessages
-
-\startmessages german library: structures
- title: struktur
- 1: Begin des Abschnittsblocks --
- 2: Ende des Abschnittsblocks --
-\stopmessages
-
-\startmessages czech library: structures
- title: struktury
- 1: zacatek oddilu (sekce) --
- 2: konec oddilu (sekce) --
-\stopmessages
-
-\startmessages italian library: structures
- title: struttura
- 1: inizio del blocco (sezione) --
- 2: fine del blocco (sezione) --
-\stopmessages
-
-\startmessages norwegian library: structures
- title: struktur
- 1: starten av blokk -- (seksjon)
- 2: slutten av blokk -- (seksjon)
-\stopmessages
-
-\startmessages romanian library: structures
- title: structuri
- 1: inceput de bloc sectiune --
- 2: sfarsit de bloc sectiune --
-\stopmessages
-
-\startmessages french library: structures
- title: structure
- 1: début de blocsection --
- 2: fin de blocsection --
-\stopmessages
-
-\unprotect
-
-% new and to be tested
-
-\unexpanded\def\separatorlist#1%
- {\ifx\sepnumber\undefined\def\sepnumber{0}\fi
- \increment\sepnumber
- \getfromcommacommand[#1][\sepnumber]%
- \ifx\commalistelement\empty
- \getcommalistsize[#1]%
- \def\sepnumber{\number\commalistsize}%
- \getfromcommacommand[#1][\sepnumber]%
- \fi
- \commalistelement}
-
-% \setuphead[section] [separator=\separatorlist{?,!,*}]
-% \setuphead[subsection][separator=\separatorlist{??,!!,**}]
-%
-% \let\spr\separatorlist % this will enable this feature
-%
-% \setuphead[section] [separator={?,!,*}]
-% \setuphead[subsection][separator={??,!!,**}]
-%
-% \setupheads[separator={A,B,C,D,E,F}]
-% \chapter{test}
-% \section{test} \subsection{test} \subsection{test}
-% \section{test} \subsection{test} \subsection{test}
-
-% from now on, internaly numbers are separated by a period
-% and postprocessed on demand; this will change to {} {} {}
-
-\def\numberseparator {.} % reasonable default
-\def\sectionseparator{-} % was : but is now -
-
-\def\@@filterfirstpart [#1--#2]{#1}
-\def\@@filtersecondpart [#1--#2]{#2}
-
-\def\@@filterblockpart [#1--#2--#3]{#1}
-\def\@@filternumberpart [#1--#2--#3]{#2}
-\def\@@filterpagepart [#1--#2--#3]{#3}
-\def\@@filterblocknumberpart[#1--#2--#3]{#1--#2}
-
-\def\@@filterheadpart[#1]{\@EA\@@dofilterheadpart\@EA[#1-0]}
-\def\@@filtertailpart[#1]{\@EA\@@dofiltertailpart\@EA[#1-0]}
-
-\def\@@dofilterheadpart[#1-#2]{#1}
-\def\@@dofiltertailpart[#1-#2]{#2}
-
-\def\@@filterlevelpart[#1--#2--#3]{\@@dofilterlevelpart[#2-0-0-0-0]}
-
-\def\@@dofilterlevelpart[#1-0-0-0-#2]{#1}
-
-\def\gobbleuntilrelax#1\relax{}
-
-\def\separatednumber #1{\doseparatednumber #1.\empty\relax}
-\def\removefirstprefix#1{\doremovefirstprefix#1.\empty\relax}
-\def\removeallprefixes#1{\doremoveallprefixes#1.\empty\relax}
-
-\def\doseparatednumber#1.#2%
- {#1%
- \ifx#2\empty
- \@EA\gobbleuntilrelax
- \else \numberseparator
- \@EA\doseparatednumber
- \fi#2}
-
-\def\doremoveallprefixes#1.#2%
- {\ifx#2\empty
- #1\@EA\gobbleuntilrelax
- \else
- \@EA\doremoveallprefixes
- \fi#2}
-
-\def\doremovefirstprefix#1.#2%
- {\ifx#2\empty
- #1\@EA\gobbleuntilrelax
- \else
- \@EA\noremovefirstprefix
- \fi#2}
-
-\def\noremovefirstprefix#1.\empty\relax
- {#1}
-
-% we need to expand in order to get something separatable
-
-\def\dohandleheadnumber#1%
- {\expanded{\separatednumber{#1}}}
-
-\def\dodochecknumber#1#2#3% will become ugly after speed up
- {\bgroup
- \doifinstringelse{.0}{.#2}
- {\doifnot{#3}\v!by
- {%\debuggerinfo\m!systems{number #1 #3 becomes \getnumbervariable{#1\c!way}}%
- \setevalue{\@@thenumber{#1}\c!way}{#3}% geen \xdef, gaat mis met \subpage
- \dochecknumber{#1}}} % tricky and ugly
- {\doifnotvalue{\@@thenumber{#1}\s!check}{#2}
- {% new, calculate accumulated number
- \scratchcounter\getvalue{\@@thenumber{#1}\c!n}\relax
- \advance\scratchcounter\countervalue{\@@thenumber{#1}}\relax
- \setxvalue{\@@thenumber{#1}\c!n}{\the\scratchcounter}%
- %
- \setcounter{\@@thenumber{#1}}{0\getvalue{\@@thenumber{#1}\c!start}}%
- \setxvalue{\@@thenumber{#1}\c!way\c!local}{\getvalue{\@@thenumber{#1}\c!way}}%
- \setxvalue{\@@thenumber{#1}\s!check}{#2}}}%
- \egroup}
-
-\def\dochecknumber#1%
- {\edef\currentsection{\csname\??by\csname\@@thenumber{#1}\c!way\endcsname\endcsname}%
- \ifx\currentsection\empty\else
- \dodochecknumber
- {#1}%
- {\csname\currentsection\c!number\endcsname}%
- {\v!by\previoussection\currentsection}%
- \fi}
-
-\def\checknumber[#1]%
- {\bgroup
- %\ifcase\blocklevel\else
- \ifdoingblocks
- \doifnotvalue{\@@thenumber{#1}\c!blockway}\v!no\setblockcounters
- \fi
- \dochecknumber{#1}%
- \egroup}
-
-\def\rawsectionnumber#1%
- {\countervalue{\??se#1}}
-
-\def\precedingseparator{\@@koseparator} % brrr
-
-\def\domakeprecedingsectionnumber[#1]% will become ugly after speed up
- {\bgroup % added
- \globallet\precedingsectionnumber\empty
- \ifsectionnumber
- \doifvalue{\??sb\@@sectionblock\c!number}\v!yes % added
- {\doifelsevalue{\@@thenumber{#1}\c!sectionnumber}\v!yes
- \donetrue\donefalse
- \doifvalue{\@@thenumber{#1}\c!sectionnumber}\v!number
- {\donetrue\let\@@sectionconversion\gobbleoneargument}%
- \ifdone
- \edef\currentsection
- {\getvalue{\??by\getvalue{\@@thenumber{#1}\c!way\c!local}}}%
- \doifnot\currentsection\zerosection
- {\doifnot{\@@sectionvalue\currentsection}{0}
- {\xdef\precedingsectionnumber
- {\getvalue{\currentsection\c!number}%
- \spr{\precedingseparator}}}}%
- \fi}%
- \fi
- \egroup}
-
-\def\makeprecedingsectionnumber[#1]%
- {\bgroup
- %\ifnum\blocklevel>0
- %\ifcase\blocklevel\else
- \ifdoingblocks
- \doifnotvalue{\@@thenumber{#1}\c!blockway}\v!no\setblockcounters
- \fi
- \domakeprecedingsectionnumber[#1]%
- \egroup}
-
-% \def\makesectionnumber[#1]%
-% {\makeprecedingsectionnumber[#1]%
-% \xdef\composedsectionnumber%
-% {\precedingsectionnumber\convertednumber[#1]}}%
-%
-% hack needed for chinese and oldstyle in normal tex, will change
-
-\def\makesectionnumber[#1]%
- {\bgroup
- \forceunexpanded % i don't like this hack
- \makeprecedingsectionnumber[#1]%
- \xdef\composedsectionnumber% was \xdef maar dat gaat fout met font switches
- {\precedingsectionnumber\convertednumber[#1]}%
- \egroup}
-
-% \def\preparethenumber#1#2#3% {\??id#1} \number \result
-% {\doifelsevaluenothing{#1\c!separator}
-% {\let\numberseparator\empty
-% \let#3#2}
-% {% was \unexpanded \edef, but we need it unexpanded !
-% \edef\numberseparator{\spr{\getvalue{#1\c!separator}}}%
-% \doifelsenothing{\executeifdefined{#1\c!suffix}\empty}
-% {\edef#3%
-% {\@EA\separatednumber\@EA{#2}%
-% }}%\stp{\getvalue{#1\c!stopper}}}}
-% {\edef#3%
-% {\@EA\separatednumber\@EA{#2}%
-% \spr{\getvalue{#1\c!separator}}%
-% \getvalue{#1\c!suffix}%
-% \stp{\getvalue{#1\c!stopper}}}}}}
-%
-% some day we do a real cleanup
-
-\def\analyzenumber#1#2#3% {\??id#1} \(precedingsection)number \result
- {% was \unexpanded \edef, but we need it unexpanded !
- \doifelsenothing{\executeifdefined{#1\c!suffix}\empty}
- {\let \numbersuffix \empty}
- {\edef\numbersuffix{\spr{\getvalue{#1\c!suffix}}}}%
- \doifelsenothing{\executeifdefined{#1\c!stopper}\empty}
- {\let \numberstopper \empty}
- {\edef\numberstopper{\spr{\getvalue{#1\c!stopper}}}}%
- \doifelsenothing{\executeifdefined{#1\c!separator}\empty}
- {\let \numberseparator \empty}
- {\edef\numberseparator{\spr{\getvalue{#1\c!separator}}}}%
- \let\numberprefix\empty}
-
-\def\preparefullnumber#1#2#3% {\??id#1} \(precedingsection)number \result
- {\analyzenumber{#1}#2#3%
- \ifx\numberseparator\empty
- \edef\numberprefix{#2}%
- \else
- \edef\numberprefix{\@EA\separatednumber\@EA{#2}}%
- \fi
- \ifx\numbersuffix\empty
- \ifx\numberprefix\empty
- \let #3\empty
- \else
- \edef#3{\numberprefix\numberstopper}%
- \fi
- \else
- \ifx\numberprefix\empty
- \edef#3{\numbersuffix\numberstopper}%
- \else
- \edef#3{\numberprefix\numberseparator\numbersuffix\numberstopper}%
- \fi
- \fi}
-
-\def\prepareprefixnumber#1#2#3% {\??id#1} \number \result
- {\analyzenumber{#1}#2#3%
- \ifx\numberseparator\empty
- \edef\numberprefix{#2}%
- \else
- \edef\numberprefix{\@EA\separatednumber\@EA{#2}}%
- \fi
- \let#3\numberprefix}
-
-\def\sectionnumberonly[#1]%
- {\makesectionnumber[#1]%
- \composedsectionnumber}
-
-% sectioning
-
-\newcount\nofsections
-
-\let\zerosection \v!text
-\let\firstsection\empty
-\let\lastsection \empty
-\let\@@sectie \empty
-\let\@@koppeling \empty
-
-\makecounter{\??se\v!text}
-
-\letvalueempty{\??se\v!text\c!before}
-\letvalueempty{\??se\v!text\c!after }
-
-\setvalue {\v!text\c!number}{0}
-\letvalueempty{\v!text\s!format}
-
-\letvalueempty{\??sk\v!text}
-\letvalueempty{\??sk }
-
-\letvalue{\??by }\v!text
-\letvalue{\??by\v!text }\v!text
-\letvalue{\??by\v!all }\v!text
-\letvalue{\??by\v!by }\v!text
-\letvalue{\??by\v!by\v!text}\v!text
-\letvalue{\??by\v!by\v!all }\v!text
-\letvalue{\??by\v!by\v!page}\v!text % see footnotes
-
-\def\sectionofhead#1{\executeifdefined{\??ko#1\c!section}\s!unknown}
-
-\def\setupsection
- {\dotripleempty\dosetupsection}
-
-\def\dosetupsection[#1]%
- {\doifdefinedelse{\??se#1}
- {\dodosetupsection[#1]}%
- {\dodosetupsection[\sectionofhead{#1}]}}
-
-\def\dodosetupsection[#1][#2][#3]%
- {\doifdefined{\??se#1}
- {\ifthirdargument
- \getparameters[\??se#1#2][#3]%
- \else
- \getparameters[\??se#1][#2]%
- \fi
- \doifelsevalue{\??se#1\c!previousnumber}\v!yes
- {\setvalue{#1\c!number}{\@@longsectionnumber {#1}}}
- {\setvalue{#1\c!number}{\@@shortsectionnumber{#1}}}}}
-
-\def\docouplemarking[#1][#2]%
- {\doifdefinedelse{\??ko#2\c!section}
- {\docouplemarking[#1][\getvalue{\??ko#2\c!section}]}
- {\def\donexttrackcommando##1%
- {\edef\coupledmarkings{\getvalue{\??se##1\c!marking}}%
- \doifelse{##1}{#2}
- {\addtocommalist{#1}\coupledmarkings}
- {\removefromcommalist{#1}\coupledmarkings}%
- \setevalue{\??se##1\c!marking}{\coupledmarkings}%
- \donexttracklevel{##1}}%
- \donexttracklevel{\zerosection}}} % \firstsection
-
-\def\couplemarking
- {\dodoubleargument\docouplemarking}
-
-\def\decouplemarking[#1]%
- {\couplemarking[#1][]}
-
-\def\definesection[#1]%
- {\doifundefined{\??se#1}
- {\doifelsenothing\firstsection
- {\def\firstsection{#1}%
- \setevalue{\??se#1\c!before}{\v!text}%
- \setevalue{\??se\v!text\c!after}{#1}}
- {\setevalue{\??se\commalistelement\c!after}{#1}% commalistelement ?
- \setevalue{\??se#1\c!before}{\lastsection}%
- \setevalue{\??se\lastsection\c!after}{#1}}%
- \advance\nofsections \plusone
- \setevalue{\??se#1\c!level}{\the\nofsections}%
- \letvalue{\??se#1\c!after}\empty
- \setvalue{\e!next#1}{\@@nextsectionnumber{#1}}%
- \setvalue{#1\c!number}{\@@longsectionnumber{#1}}%
- \setvalue{#1\s!format}{\@@longformatnumber{#1}}%
- \setevalue{\??by#1}{#1}%
- \setevalue{\??by\v!by#1}{#1}%
- \makecounter{\??se#1}%
- \makecounter{\??se\v!last#1}% GB
- \edef\lastsection{#1}%
- \setvalue{\??sk#1}{#1}%
- \letvalue{\??se#1\c!marking}\empty
- \setupsection[#1][\c!previousnumber=\v!yes]}}%
-
-\def\previoussection#1{\csname\??se#1\c!before\endcsname}
-\def\nextsection #1{\csname\??se#1\c!after \endcsname}
-
-\let\preservedsection\v!unknown % \def\preservedsection{\firstsection}
-
-\def\checkpreservevalueafter#1% GB
- {\ifnum\getvalue{\??se#1\c!level}<\nofsections
- \edef\preservedsection{\getvalue{\??se#1\c!after}}%
- \ifconditional\@@resetsubheadnumbers
- \setcounter{\??se\v!last\preservedsection}\zerocount % {0}%
- \else
- \setcounter{\??se\v!last\preservedsection}{\countervalue{\??se\preservedsection}}%
- \fi
- \fi}
-
-\def\@@setsectionnumber#1#2%
- {\letgvalueempty{\??se#1\s!start}% signal i.p.v. boolean
- \setcounter{\??se#1}{#2}%
- \checkpreservevalueafter{#1}% GB
- \resetsectioncounters{#1}%
- \checkpagecounter}
-
-\def\@@nextsectionnumber#1% patched by GB
- {\letgvalueempty{\??se#1\s!start}% signal i.p.v. boolean
- \ifnum\countervalue{\??se\v!last#1}>\zerocount
- \setcounter{\??se#1}{\countervalue{\??se\v!last#1}}%
- \setcounter{\??se\v!last#1}\zerocount % {0}%
- \fi
- \pluscounter{\??se#1}%
- \checkpreservevalueafter{#1}%
- \resetsectioncounters{#1}%
- \checkpagecounter}
-
-\def\@@sectionvalue#1% % nog niet overal doorgevoerd
- {\countervalue{\??se#1}} % zoeken op \??se
-
-% suited for chinese too:
-
-\def\@@sectionconversion#1#2% a doublure with \@@shortsectionnumber
- {\ifnum#2=0 0\else % else troubles with \uchar
- \@EA\ifx\csname\??se#1\@@sectionblock\c!conversion\endcsname\relax
- \@EA\ifx\csname\??se#1\c!conversion\endcsname\relax
- #2%
- \else
- \convertnumber{\getvalue{\??se#1\c!conversion}}{#2}%
- \fi
- \else
- \convertnumber{\getvalue{\??se#1\@@sectionblock\c!conversion}}{#2}%
- \fi
- \fi}
-
-% \def\@@sectionlevel#1%
-% {\ifundefined{\??se#1\c!level}0\else\getvalue{\??se#1\c!level}\fi}
-
-\def\@@sectionlevel#1%
- {\executeifdefined{\??se#1\c!level}0}
-
-% Omdat een markering kan worden herdefinieerd moeten we
-% eerst testen of er wel een keten||afhankelijkheid is.
-
-\def\resetsectionmarks#1% can invoke a break
- {\ifundefined{\??se#1}%
- \fastresetmarker[\mainmarking{#1}]% % redundant \mainmarking
- \else
- \let\donexttrackcommando\doresetsectionmarks
- \donexttracklevel{#1}%
- \fi}
-
-\def\doresetsectionmarks#1%
- {\ifundefined{\??se#1\c!marking}\else % skip zero level
- \fastresetmarkerlist[\csname\??se#1\c!marking\endcsname]%
- \fi
- \donexttracklevel{#1}}
-
-% I'm not sure if the next one is better:
-%
-% \def\doresetsectionmarks#1%
-% {\ifundefined{\??se#1\c!markering}% skip zero level
-% \donexttracklevel{#1}%
-% \else
-% \fastresetmarkerlist[\csname\??se#1\c!markering\endcsname]%
-% \fi}
-%
-% and indeed, it isn't, actually, it does not work at all, so let's drop it.
-
-% packaged:
-%
-% \def\resetsectioncounters#1%
-% {\def\donexttrackcommando##1%
-% {\resetcounter{\??se##1}%
-% \donexttracklevel{##1}}%
-% \donexttracklevel{#1}}
-%
-% nicer
-%
-% \def\doresetsectioncounters#1%
-% {\resetcounter{\??se#1}%
-% \donexttracklevel{#1}}
-%
-% obey eigennummer
-
-\def\doresetsectioncounters#1%
- {\resetcounter{\??se#1}%
- \letgvalue{\??se#1\c!ownnumber}\relax
- \donexttracklevel{#1}}
-
-\def\resetsectioncounters % #1
- {\let\donexttrackcommando\doresetsectioncounters
- \donexttracklevel} % #1
-
-% bij checken kan geen prefix worden bekeken, anders vallen
-% er titels buiten de inhoudsopgave
-
-% evt ook level gaan opslaan tbv snelle selectie
-
-% \def\makesectionformat
-% {\edef\sectionformat
-% {\@@sectiontype\sectionseparator
-% \csname\lastsection\s!format\endcsname}}
-
-\unprotected \def\makesectionformat % we don't want eigennummers here
- {\pushmacro\@@shortsectionnumber
- \let\@@shortsectionnumber\@@sectionvalue
- \edef\sectionformat
- {\@@sectiontype\sectionseparator
- \csname\lastsection\s!format\endcsname}%
- \popmacro\@@shortsectionnumber}
-
-\def\dobacktracklevel#1%
- {\doifnot{\previoussection{#1}}\zerosection
- {\dobacktrackcommando{\previoussection{#1}}}}
-
-\def\donexttracklevel#1%
- {\doifnot{#1}\lastsection
- {\donexttrackcommando{\nextsection{#1}}}}
-
-\chardef\alltoclevels\zerocount
-
-\let\currentlevel\empty
-
-\def\dosetcurrentlevel#1%
- {\global\chardef\alltoclevels\zerocount
- \xdef\currentlevel{\getvalue{\lastsection\s!format}}}
-
-\def\dosetpreviouslevel#1%
- {\global\chardef\alltoclevels\plusone
- \globallet\currentlevel\empty
- \def\dobacktrackcommando##1%
- {\ifnum\countervalue{\??se##1}>\zerocount
- \global\chardef\alltoclevels\zerocount
- \xdef\currentlevel{\getvalue{\previoussection{##1}\s!format}}%
- \else
- \dobacktracklevel{##1}%
- \fi}%
- \dobacktrackcommando\lastsection}
-
-\def\dosettextlevel#1%
- {\global\chardef\alltoclevels\plusone
- \globallet\currentlevel\empty}
-
-\def\dosetotherlevel#1%
- {\doifdefinedelse{\??ko#1\c!section} % beter alteratief: ook
- {\edef\@@sectie{\getvalue{\??ko#1\c!section}}} % hoofdstuk\c!format
- {\edef\@@sectie{#1}}%
- \doifdefinedelse{\??se\@@sectie}
- {\global\chardef\alltoclevels\zerocount
- \xdef\currentlevel{\getvalue{\@@sectie\s!format}}}
- {\global\chardef\alltoclevels\plusone
- \globallet\currentlevel\empty
- \def\dobacktrackcommando##1%
- {\@EA\ifx\csname\??se##1\c!start\endcsname\relax
- \dobacktracklevel{##1}%
- \else
- \ifnum\countervalue{\??se##1}>\zerocount
- \global\chardef\alltoclevels\zerocount
- \xdef\currentlevel{\getvalue{##1\s!format}}%
- \else
- \dobacktracklevel{##1}%
- \fi
- \fi}%
- \dobacktrackcommando\lastsection}}
-
-% \def\ignoresectionconversion % brrr
-% {\let\@@sectionconversion\secondoftwoarguments}
-
-% todo: criterium=appendix|frontmatter|....
-
-\def\dosetfilterlevel#1#2% beware: this one is \let
- {\bgroup
- \let\@@shortsectionnumber\@@sectionvalue
-% \ignoresectionconversion
- \edef\askedlevel{#1}%
- \edef\askedfilter{#2}%
- \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}
-
-% \def\dontsetfilterlevel#1#2%
-% {\let\currentlevel\somesavedlevel
-% \chardef\alltoclevels\zerocount}
-
-\def\dontsetfilterlevel#1#2%
- {\let\currentlevel\somesavedlevel
- \let\@@sectiontype\@@tocsectiontype
- \chardef\alltoclevels\zerocount}
-
-\def\honorlocalfilterlevel % local lists will be real local
- {\let\dosetfilterlevel\dontsetfilterlevel}
-
-% cleaner
-%
-% \def\doifnextlevelelse[#1::#2]#3#4%
-% {\ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}
-% {\doifinstringelse{=\currentlevel:0}{=:#2:}{#4}{#3}}
-% {#4}}
-% {#4}%
-% \else
-% #3%
-% \fi}
-%
-% \def\doifprevlevelelse[#1::#2]#3#4%
-% {\ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}{#3}{#4}}
-% {#4}%
-% \else
-% #3%
-% \fi}
-%
-% faster
-%
-% \def\doifnextlevelelse[#1::#2]%
-% {\ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}
-% {\doifinstringelse{=\currentlevel:0}{=:#2:}\donefalse\donetrue}
-% \donefalse}
-% \donefalse
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% \def\doifprevlevelelse[#1::#2]%
-% {\ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}\donetrue\donefalse}
-% \donefalse
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% meaner
-%
-% \setuplist
-% [chapter]
-% [after={\startcolumns\placelist[section]\stopcolumns}]
-
-\def\somesavedlevel{0}
-
-% \def\dosavesomelevel[#1:0:0:0:#2]%
-% {\def\somesavedlevel{:#1}}
-
-% \def\doifnextlevelelse[#1::#2]%
-% {\dosavesomelevel[#2:0:0:0:0]%
-% \ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}
-% {\doifinstringelse{=\currentlevel:0}{=:#2:}\donefalse\donetrue}
-% \donefalse}
-% \donefalse
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% \def\doifprevlevelelse[#1::#2]%
-% {\dosavesomelevel[#2:0:0:0:0]%
-% \ifcase\alltoclevels
-% \doifelse{\@@sectiontype}{#1}
-% {\doifinstringelse{=\currentlevel:}{=:#2:}\donetrue\donefalse}
-% \donefalse
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% again faster:
-
-% \def\doifnextlevelelse[#1::#2]% beware: this one is \let
-% {\dosavesomelevel[#2:0:0:0:0]%
-% \ifcase\alltoclevels
-% \ifnum\@@sectiontype=#1
-% \def\levelstring{=:#2:}%
-% \doifincsnameelse{=\currentlevel:}\levelstring
-% {\doifincsnameelse{=\currentlevel:0}\levelstring\donefalse\donetrue}
-% \donefalse
-% \else
-% \donefalse
-% \fi
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-%\def\doifprevlevelelse[#1::#2]% beware: this one is \let
-% {\dosavesomelevel[#2:0:0:0:0]%
-% \ifcase\alltoclevels
-% \ifnum\@@sectiontype=#1
-% \doifinstringelse{=\currentlevel:}{=:#2:}\donetrue\donefalse
-% \else
-% \donefalse
-% \fi
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% \let\doiftoclevelelse\doifnextlevelelse
-% \let\doifreglevelelse\doifprevlevelelse
-% \let\doifblklevelelse\doifprevlevelelse
-%
-% we want to be able to overload them globally
-
-% This will be reimplemented some day soon
-%
-% {nn}{xx}{yy}
-%
-% -> \scan{..}{..}{0} met 0 als sentinel
-
-% still not perfect
-%
-% \def\doifnextlevelelse[#1]% !! this one is \let / uti seperator --
-% {\edef\somesavedlevel{\sectionseparator\@@filterlevelpart[#1]}%
-% \ifcase\alltoclevels
-% \ifnum\@@sectiontype=\@@filterblockpart[#1]\relax
-% \edef\levelstring{=\sectionseparator\@@filternumberpart[#1]\sectionseparator}%
-% \doifincsnameelse{=\currentlevel\sectionseparator}\levelstring
-% {\doifincsnameelse{=\currentlevel\sectionseparator0}\levelstring
-% \donefalse
-% \donetrue}
-% \donefalse
-% \else
-% \donefalse
-% \fi
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-%
-% \def\doifprevlevelelse[#1]% !! this one is \let / uti seperator --
-% {\edef\somesavedlevel{\sectionseparator\@@filterlevelpart[#1]}%
-% \ifcase\alltoclevels
-% \ifnum\@@sectiontype=\@@filterblockpart[#1]\relax
-% \doifinstringelse
-% {=\currentlevel\sectionseparator}
-% {=\sectionseparator\@@filternumberpart[#1]\sectionseparator}
-% \donetrue\donefalse
-% \else
-% \donefalse
-% \fi
-% \else
-% \donetrue
-% \fi
-% \ifdone
-% \expandafter\firstoftwoarguments
-% \else
-% \expandafter\secondoftwoarguments
-% \fi}
-
-\def\doifnextlevelelse[#1]% !! this one is \let / uti seperator --
- {\edef\somesavedlevel{\sectionseparator\@@filterlevelpart[#1]}%
- \edef\@@tocsectiontype{\@@filterblockpart[#1]}% needed for nested tocs
- \ifcase\alltoclevels
- \ifnum\@@sectiontype=\@@tocsectiontype\relax
- \edef\levelstring{=\sectionseparator\@@filternumberpart[#1]\sectionseparator}%
- \doifincsnameelse{=\currentlevel\sectionseparator}\levelstring
- {\doifincsnameelse{=\currentlevel\sectionseparator0}\levelstring
- \donefalse
- \donetrue}
- \donefalse
- \else
- \donefalse
- \fi
- \else
- \donetrue
- \fi
- \ifdone
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-\def\doifprevlevelelse[#1]% !! this one is \let / uti seperator --
- {\edef\somesavedlevel{\sectionseparator\@@filterlevelpart[#1]}%
- \edef\@@tocsectiontype{\@@filterblockpart[#1]}% needed for nested tocs
- \ifcase\alltoclevels
- \ifnum\@@sectiontype=\@@tocsectiontype\relax
- \doifinstringelse
- {=\currentlevel\sectionseparator}
- {=\sectionseparator\@@filternumberpart[#1]\sectionseparator}
- \donetrue\donefalse
- \else
- \donefalse
- \fi
- \else
- \donetrue
- \fi
- \ifdone
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-% we need to cover the special case of nested lists in section blocks
-%
-% \starttext
-%
-% \def\ChapterEntry#1#2#3%
-% {chapter : \hbox to \hsize{\strut\bf#2\hss#3}\endgraf\placelist[section]}
-%
-% \startfrontmatter % optional
-% \placelist[chapter][alternative=command,command=\ChapterEntry,criterium=text] \page
-% \stopfrontmatter % optional
-%
-% \startbodymatter % optional
-% \chapter{first} \section{one} test \section{two} test \page
-% \chapter{second} \section{alpha} test \section{beta} test \page
-% \stopbodymatter % optional
-%
-% \stoptext
-
-\def\doiftoclevelelse{\doifnextlevelelse}
-\def\doifreglevelelse{\doifprevlevelelse}
-\def\doifblklevelelse{\doifprevlevelelse}
-
-\def\@@longformatnumber#1%
- {\csname\previoussection{#1}\s!format\endcsname
- \sectionseparator
- \@@shortsectionnumber{#1}}
-
-% \def\@@longsectionnumber#1%
-% {\ifnum\countervalue{\??se\previoussection{#1}}>\zerocount
-% \csname\previoussection{#1}\c!nummer\endcsname.%
-% \fi
-% \@@shortsectionnumber{#1}}
-
-\def\@@longsectionnumber#1%
- {\ifreversesectionnumbers
- \@@shortsectionnumber{#1}%
- \ifnum\countervalue{\??se\previoussection{#1}}>\zerocount
- .\csname\previoussection{#1}\c!number\endcsname
- \fi
- \else
- \ifnum\countervalue{\??se\previoussection{#1}}>\zerocount
- \csname\previoussection{#1}\c!number\endcsname.%
- \fi
- \@@shortsectionnumber{#1}%
- \fi}
-
-% suited for chinese too:
-%
-% \def\@@shortsectionnumber#1%
-% {\@EA\ifx\csname\??se#1\@@sectionblock\c!conversie\endcsname\relax
-% \@@sectionvalue{#1}%
-% \else
-% \@@sectionconversion{#1}{\@@sectionvalue{#1}}%
-% \fi}
-%
-% obey eigennummer
-%
-% \def\@@shortsectionnumber#1%
-% {\@EA\ifx\csname\??se#1\c!eigennummer\endcsname\relax
-% \@EA\ifx\csname\??se#1\@@sectionblock\c!conversie\endcsname\relax
-% \@EA\ifx\csname\??se#1\c!conversie\endcsname\relax
-% \@@sectionvalue{#1}%
-% \else
-% \@@sectionconversion{#1}{\@@sectionvalue{#1}}%
-% \fi
-% \else
-% \@@sectionconversion{#1}{\@@sectionvalue{#1}}%
-% \fi
-% \else
-% \csname\??se#1\c!eigennummer\endcsname
-% \fi}
-
-\def\@@shortsectionnumber#1%
- {\@EA\ifx\csname\??se#1\c!ownnumber\endcsname\relax
- \@EA\ifx\csname\??se#1\@@sectionblock\c!conversion\endcsname\relax
- \@EA\ifx\csname\??se#1\c!conversion\endcsname\relax
- \@@sectionvalue{#1}%
- \else
- \@@sectionconversion{#1}{\@@sectionvalue{#1}}%
- \fi
- \else
- \@@sectionconversion{#1}{\@@sectionvalue{#1}}%
- \fi
- \else
- \csname\??se#1\c!ownnumber\endcsname
- \fi}
-
-\def\dosetlocalsectionblock#1#2#3% new \edef's
- {\edef\@@sectiontype {#1}%
- \edef\@@sectionblock {#2}%
- \edef\@@sectionblocks{#3}}
-
-% beware, the \resetsectionmarks generates some nodes that
-% will result in an additional last page, which needs to be
-% captured at the end
-
-% \def\doaroundsectionblock#1%
-% {\doifvaluesomething{\??sb#1\c!page}
-% {\ExpandFirstAfter\page[\getvalue{\??sb#1\c!page}]}%
-% \resetsectioncounters\zerosection % was firstsection
-% \resetsectionmarks\zerosection}
-
-% \def\dostartsectionblock#1#2%
-% {\begingroup
-% \doaroundsectionblock{#1}% % going to a new page or so
-% \getvalue{\??sb#1}% % set name of section block
-% \getsectionblockenvironment{#1}% % special settings, grouped
-% %\expandafter\csname#2true\endcsname % obsolete
-% \setsystemmode{#1}% % can be used in conditionals
-% \getvalue{\??sb\@@sectionblock\c!before}% this one is not to be moved!
-% \showmessage\m!structures1\@@sectionblocks}
-
-% \def\dostopsectionblock
-% {\showmessage\m!structures2\@@sectionblocks
-% \getvalue{\??sb\@@sectionblock\c!after}% don't move
-% \doaroundsectionblock\@@sectionblock
-% \endgroup}
-
-\def\doaroundsectionblock
- {\doifvaluesomething{\??sb\@@sectionblock\c!page}
- {\page[\getvalue{\??sb\@@sectionblock\c!page}]}%
- \resetsectioncounters\zerosection % was firstsection
- \resetsectionmarks\zerosection}
-
-\def\dostartsectionblock#1#2%
- {\begingroup
- \getvalue{\??sb#1}%
- \doaroundsectionblock
-% \doifvaluesomething{\??sb\@@sectionblock\c!page}{\page[\getvalue{\??sb\@@sectionblock\c!page}]}%
-% \resetsectioncounters\zerosection % was firstsection
-% \resetsectionmarks\zerosection
- \getsectionblockenvironment\@@sectionblock
- \setsystemmode\@@sectionblock
- \getvalue{\??sb\@@sectionblock\c!before}%
- \showmessage\m!structures1\@@sectionblocks}
-
-\def\dostopsectionblock
- {\showmessage\m!structures2\@@sectionblocks
- \getvalue{\??sb\@@sectionblock\c!after}% don't move
- \doaroundsectionblock
-% \doifvaluesomething{\??sb\@@sectionblock\c!page}{\page[\getvalue{\??sb\@@sectionblock\c!page}]}%
-% \resetsectioncounters\zerosection % was firstsection
-% \resetsectionmarks\zerosection
- \endgroup}
-
-\def\dosetupsectionblock[#1]% [#2]
- {\getparameters[\??sb#1]}
-
-\def\setupsectionblock
- {\dodoubleargument\dosetupsectionblock}
-
-\long\def\setsectionblockenvironment#1#2%
- {\long\setvalue{\??sb\s!do#1}{\do{#2}}}
-
-\def\getsectionblockenvironment#1%
- {\let\do\firstofoneargument\getvalue{\??sb\s!do#1}}
-
-\setvalue{\e!start\v!sectionblockenvironment}%
- {\dosingleargument\dostartsectionblockenvironment}
-
-\def\dostartsectionblockenvironment[#1]% evt \pushendofline \popendofline
- {\long\def\do##1##2{\setsectionblockenvironment{#1}{##1##2}}%
- \grabuntil{\e!stop\v!sectionblockenvironment}{\getvalue{\??sb\s!do#1}}}
-
-%D \starttyping
-%D \startsectionblockenvironment[frontpart]
-%D \setuppagenumbering[conversion=romannumerals]
-%D \stopsectionblockenvironment
-%D
-%D \startsectionblockenvironment[bodypart]
-%D \setuppagenumber[number=1]
-%D \stopsectionblockenvironment
-%D
-%D \startsectionblockenvironment[frontpart]
-%D \setuppagenumbering[conversion=character]
-%D \stopsectionblockenvironment
-%D
-%D \starttext
-%D \startfrontmatter \chapter{test} \stopfrontmatter
-%D \startbodymatter \chapter{test} \stopbodymatter
-%D \startappendices \chapter{test} \stopappendices
-%D \stoptext
-%D \stoptyping
-
-% We used to use the first char as id, but a counter is
-% better, because in english we get a name clash.
-
-\newcounter\currentsectionblock
-
-\def\currentsection{\@@sectionblock}
-
-\def\dodefinesectionblock[#1][#2][#3]%
- {\getparameters
- [\??sb#1]
- [\c!number=\v!yes,
- \c!page=\v!right, % anders worden marks te vroeg gereset !
- %\c!before=,
- %\c!after=,
- #3]%
- \expandafter\newif\csname if#2\endcsname % better a mode
- \doglobal\increment\currentsectionblock
- \setsectionblockenvironment{#1}{}%
- \setevalue{\??sb #1}{\noexpand\dosetlocalsectionblock{\currentsectionblock}{#1}{#2}}%
- \setvalue {\e!start#2}{\dostartsectionblock{#1}{#2}}%
- \setvalue {\e!stop #2}{\dostopsectionblock}}
-
-\def\definesectionblock
- {\dotripleargument\dodefinesectionblock}
-
-\def\sectionblocklabel#1#2%
- {\@EA\ifx\csname\??ko#1\@@sectionblock\c!label\endcsname\relax
- \labeltexts{#1}{#2}%
- \else
- \labeltexts{\getvalue{\??ko#1\@@sectionblock\c!label}}{#2}%
- \fi}
-
-\dosetlocalsectionblock{2}{\v!bodypart}{\v!bodymatter} % hm, dirty
-
-\def\setsectiontype[#1]%
- {\getvalue{\??sb#1}}
-
-\def\writesection#1#2#3% #3 -> \asciititle
- {\bgroup
- \edef\!!stringa{#1}%
- \@EA\writestatus\@EA
- {\!!stringa}
- {\ifsectionnumber#2\else(#2)\fi\normalspace\asciititle}%
- \egroup}
-
-\def\@@kolevel{1} \def\headlevel{\@@kolevel}
-
-\def\dohandlepagebreakAA#1%
- {\ifnum\lastpenalty>0
- \global\paginageblokkeerdtrue
- \fi}
-
-% \setuphead[section][aligntitle=float] % permits title next to sidefloat
-%
-% \placefigure[left]{}{} \section{\dorecurse{10}{bagger }} \input tufte
-
-% \def\dohandlepagebreakAB#1% will be replaced by a more clever (signaling) mechanism (in beta)
-% {\doifnotvalue{\??ko#1\c!aligntitle}\v!float\flushsidefloats
-% \getvalue{\??ko#1\c!before}%
-% % \whitespace vervangen door \noindent elders
-% \relax
-% \ifpaginageblokkeerd
-% \global\paginageblokkeerdfalse
-% \else
-% \!!countb\getvalue{\??se\@@sectie\c!level}\relax
-% \ifnum\!!countb>\@@kolevel\relax
-% \!!counta20000
-% \multiply\!!countb 500
-% \advance\!!counta \!!countb
-% \dosomebreak{\penalty\!!counta}%
-% \else
-% \dosomebreak\allowbreak
-% \fi
-% \fi
-% \doifvalue{\??ko#1\c!aligntitle}\v!float\indent
-% \xdef\@@kolevel{\getvalue{\??se\@@sectie\c!level}}}
-
-\chardef\somebreakmethod\plusone
-
-\def\dohandlepagebreakAB#1% will be replaced by a more clever (signaling) mechanism (in beta)
- {\doifnotvalue{\??ko#1\c!aligntitle}\v!float\flushsidefloats
- \getvalue{\??ko#1\c!before}%
- % \whitespace vervangen door \noindent elders
- \relax
- \ifpaginageblokkeerd
- \global\paginageblokkeerdfalse
- \else
- \ifcase\somebreakmethod
- % 0 = nothing
- \or
- % 1 = old weighted version
- \!!countb\getvalue{\??se\@@sectie\c!level}\relax
- \ifnum\!!countb>\@@kolevel\relax
- \!!counta20000
- \multiply\!!countb 500
- \advance\!!counta \!!countb
- \dosomebreak{\penalty\!!counta}%
- \else
- \dosomebreak\allowbreak % brr
- \fi
- \or
- % 2 = strict version
- \dosomebreak{\penalty\maxdimen}%
- \else
- % nothing
- \fi
- \fi
- \doifvalue{\??ko#1\c!aligntitle}\v!float\indent
- \xdef\@@kolevel{\getvalue{\??se\@@sectie\c!level}}}
-
-\def\dohandlepagebreakBB#1#2#3%
- {%\doifinsetelse{\getvalue{\??tk#2\c!state}}{\v!normal,\v!start}
- \doifelselayouttextline{#2}
- {\doifvaluesomething{\??ko#1#3}
- {\setuplayouttext[#2][\c!state=\getvalue{\??ko#1#3}]}}
- \donothing}
-
-\def\dohandlepagebreakB#1%
- {\doifvaluesomething{\??ko#1\c!page}
- {\def\resetcurrentsectionmarks% toegevoegd, zie \page
- {\resetsectionmarks{\previoussection\@@sectie}}%
- \page[\getvalue{\??ko#1\c!page}]%
- \dohandlepagebreakBB{#1}\v!header\c!header
- \dohandlepagebreakBB{#1}\v!text \c!text
- \dohandlepagebreakBB{#1}\v!footer\c!footer}}
-
-\def\dohandlepagebreakX#1% zie doordefinieren / boven
- {\bgroup
- \!!countb\@@kolevel
- \advance\!!countb #1
- \multiply\!!countb 500
- \!!counta20000
- \advance\!!counta \!!countb
- \dosomebreak{\penalty\!!counta}%
- \egroup}
-
-\newconditional\ignorehandlepagebreak
-
-\def\handlepagebreak#1%
- {\ifconditional\ignorehandlepagebreak
- \setfalse\ignorehandlepagebreak
- \else
- \dohandlepagebreakAA{#1}%
- \ifnum\countervalue{\??se\previoussection\@@sectie}>\zerocount\relax
- \ifnum\countervalue{\??se\@@sectie}>\zerocount
- \dohandlepagebreakB{#1}%
- \else
- \doifnotvalue{\??ko#1\c!continue}\v!yes{\dohandlepagebreakB{#1}}%
- \fi
- \else
- \dohandlepagebreakB{#1}%
- \fi
- \dohandlepagebreakAB{#1}%
- \fi}
-
-\def\handlenopagebreak#1%
- {\ifconditional\ignorehandlepagebreak
- \setfalse\ignorehandlepagebreak
- \else
- \xdef\@@kolevel{\getvalue{\??se\@@sectie\c!level}}%
- \nobreak
- \fi}
-
-\def\localheadheight {\strutht}
-\def\localheaddepth {\strutdp}
-\def\localheadlineheight{\lineheight}
-
-\def\dolocalheadsetup#1% koppeling met standaard kopcommando / engels
- {\forgetall % traag dus ...
- \doifvaluesomething{\??ko#1\c!align} % wordt al expanded in spa
- {\expanded{\setupalign[\getvalue{\??ko#1\c!align}]}}%
- \doifvaluesomething{\??ko#1\c!tolerance} % wordt al expanded in spa
- {\expanded{\setuptolerance[\getvalue{\??ko#1\c!tolerance}]}}%
- \doifvalue{\??ko#1\c!strut}\v!no % wordt al expanded in spa
- {\setnostrut}% new
- \def\\{\crlf\strut\ignorespaces}}
-
-\def\localkopsetup{\localheadsetup} % kan tzt weg
-
-% todo: make them conditionals:
-
-\newif\ifincrementnumber
-\newif\ifreversesectionnumbers % todo: key/val
-\newif\ifsectionnumber \sectionnumbertrue
-\newif\ifdisplaysectionhead \displaysectionheadtrue
-\newif\ifplacehead
-\newif\ifemptyhead
-\newif\ifwritetolist
-\newif\ifheadnumber
-\newif\ifheadnumbercontent % niet meer wijzigen / wordt mode
-\newif\ifheadprefix
-\newif\ifsomeheadconversion
-
-% new
-
-\newconditional\@@resetsubheadnumbers
-
-\def\setsectieenkoppeling#1%
- {\edef\@@koppeling{\getvalue{\??ko#1\c!coupling}}%
- \edef\@@sectie{\getvalue{\??ko#1\c!section}}%
- \doifnothing\@@koppeling
- {\edef\@@koppeling{#1}}%
- \doifnothing\@@sectie
- {\edef\@@sectie{\getvalue{\??ko\@@koppeling\c!section}}}}
-
-% \handlepagebreak komt het eerst omdat eventueel
-% subpaginanummers moeten worden afgehandeld. Vervolgens
-% worden de nummers opgehoogd en referenties geset, dan
-% volgt de kop en tot slot de worden de marks en de prefix
-% geset.
-
-% \hoofdstuk {tekst}
-% \hoofdstuk tekst
-% \hoofdstuk <niets>
-
-\let\finalsectionnumber\empty
-
-\def\dofinalsectionnumber
- {\ifundefined{\@@sectie\c!number}\else
- \ifsomeheadconversion
- \@@shortsectionnumber\@@sectie
- \else
- \getvalue{\@@sectie\c!number}%
- \fi
- \fi}
-
-\def\findsectionnumber#1#2#3% class file title / uti seperator --
- {\begingroup
- \setsectieenkoppeling{#1}%
- \xdef\foundsectionnumber{1}%
- \def\dolistelement##1##2##3##4##5##6%
- {\doif{##1}{#1}
- {\ConvertConstantAfter\doif{##4}{#3}
- {\global\utilitydonetrue
- \scratchcounter=0\getvalue{\??se\@@sectie\c!level}%
- %
- %\advance\scratchcounter 2
- %\@EA\def\@EA\do\@EA####\@EA1\sectionseparator####2]%
- % {\advance\scratchcounter -1
- % \ifcase\scratchcounter
- % \xdef\foundsectionnumber{####1}%
- % \else
- % \do####2]%
- % \fi}%
- %\do##5]}}}%
- %
- \def\do####1\relax % :/- clean
- {\advance\scratchcounter \minusone
- \ifcase\scratchcounter
- \xdef\foundsectionnumber{\@@filterheadpart[####1]}%
- \else
- \@EAEAEA\do\@@filtertailpart[####1]\relax
- \fi}%
- \@EA\do\@@filternumberpart[##5]\relax}}}%
- \setbox0\vbox
- {\doutilities{#1}{#2}{#1}\relax\relax}%
- \endgroup
- \doifnumberelse\foundsectionnumber
- {\doif\foundsectionnumber\!!zerocount
- {\globallet\foundsectionnumber\!!plusone}}
- {\globallet\foundsectionnumber\!!plusone}% an appendix or so
- \setupheadnumber[#1][\foundsectionnumber]%
- \setupheadnumber[#1][-1]}
-
-% deal with eigennummer
-
-\def\setsomeheadconversion#1#2%
- {\someheadconversionfalse
- \doifelsevalue{\??ko#1\c!ownnumber}\v!yes
- {\setgvalue{\??se\@@sectie\c!ownnumber}{#2}%
- \def\someheadconversion{#2}}
- {\letgvalue{\??se\@@sectie\c!ownnumber}\relax
- \determineheadnumber[#1]%
- \@EA\ifx\csname\??se\@@sectie\@@sectionblock\c!headconversion\endcsname\relax
- \@EA\ifx\csname\??se\@@sectie\c!headconversion\endcsname\relax
- \def\someheadconversion{#2}%
- \else
- \@EA\ifx\csname\??se\@@sectie\c!headconversion\endcsname\empty
- \def\someheadconversion{#2}%
- \else
- \someheadconversiontrue
- \def\someheadconversion%
- {\fullsectionnumber{#1}{\getvalue{\??se\@@sectie\c!headconversion}}{#2}}%
- \fi
- \fi
- \else
- \@EA\ifx\csname\??se\@@sectie\@@sectionblock\c!headconversion\endcsname\empty
- \def\someheadconversion{#2}%
- \else
- \someheadconversiontrue
- \def\someheadconversion%
- {\fullsectionnumber{#1}{\getvalue{\??se\@@sectie\@@sectionblock\c!headconversion}}{#2}}%
- \fi
- \fi}}
-
-\def\writtenfullsectionnumber
- {\string\fullsectionnumber}
-
-\def\ignoredfullsectionnumber#1#2#3%
- {#3}
-
-\let\storedfullsectionnumber\relax
-
-\def\expandablefullsectionnumber#1#2#3%
- {\convertnumber{#2}{#3}}
-
-\unexpanded\def\naturalfullsectionnumber#1#2#3%
- {\sectionblocklabel{#1}{\convertnumber{#2}{#3}}}
-
-\unexpanded\def\limitedfullsectionnumber#1#2#3%
- {\convertnumber{#2}{#3}}
-
-\def\setfullsectionnumber#1%
- {\doifelsevalue{#1\c!headconversion}\v!yes
- {\doifelsevalue{#1\c!headlabel}\v!yes
- {\let\fullsectionnumber\naturalfullsectionnumber}
- {\let\fullsectionnumber\limitedfullsectionnumber}}
- {\let\fullsectionnumber\ignoredfullsectionnumber}}
-
-\let\fullsectionnumber\limitedfullsectionnumber
-
-% \dodododoconstructhead IS NON GROUPED, SO WE NEED TO RESTORE !!!!
-%
-% dit kan dus beter \everyaroundhead zijn
-
-\let\currentheadnumber\empty
-\let\currentheadtext \empty
-
-\def\dodoconstructhead#1[#2]#3% [ref] {title}
- {\doifelsevalue{\??ko#1\c!ownnumber}\v!yes
- {\doquadruplegroupempty\dododoconstructhead{#1}{#2}{#3}}
- {\fourthargumentfalse \dododoconstructhead{#1}{#2}{#3}{}}}
-
-\def\dododoconstructhead#1#2#3#4% [ref] {own} {title}
- {\iffourthargument
- \def\next{\dodododoconstructhead{#1}[#2]{#3}{#4}}%
- \else
- \def\next{\dodododoconstructhead{#1}[#2]{\finalsectionnumber}{#3}}%
- \fi
- \next}
-
-% pas met \ExpandFirstAfter op bij twee||taligheid
-
-\ifx\dohandleheadnumber\undefined
- \let\dohandleheadnumber\firstofoneargument
-\fi
-
-\unexpanded\def\\{\space}
-
-\def\emptyheadcorrection % experimental, should work
- {\ifemptyhead % well with na=\blank
- \vskip-\lineheight
- \dosomebreak\nobreak
- \kern\zeropoint
- \prevdepth\strutdepth
- \fi}
-
-\let\localkopprefix\empty
-
-\def\headparameter#1% to do: everywhere in core-sec
- {\executeifdefined{\??ko\currenthead#1}\empty}
-
-% todo: write to list etc in both args or in enclosing h/vbox else it gets
-% lost when no #1 or #2 is typeset
-
-% we will use variables here
-
-\def\dodododoconstructhead#1[#2]#3#4% [ref] {number} {title}
- {\def\currenthead{#1}% dus #1 overal vervangen
- \let\finalsectionnumber\dofinalsectionnumber % overloaded ungrouped -)
- \unexpanded\def\\{\space}%
- \edef\numberseparator{\spr{\getvalue{\??ko\currenthead\c!separator}}}%
- \flushingcolumnfloatsfalse % {number} can be \finalsectionnumber
- \someheadconversionfalse
- \let\fullsectionnumber\limitedfullsectionnumber
- \setsectieenkoppeling{#1}%
- \doifelsevaluenothing{\??ko#1\c!prefix}
- \headprefixfalse\headprefixtrue
- \ifheadprefix
- \doifelsevalue{\??ko#1\c!prefix}{+}
- {\doifelsenothing{#2}
- {\def\localkopprefix{+}}
- {\def\localkopprefix{#2}}} % eigenlijk alleen eerste
- {\edef\localkoprefix{\getvalue{\??ko#1\c!prefix}}}%
- \else
- \let\localkoprefix\empty
- \fi
- \placeheadtrue
- \processaction
- [\getvalue{\??ko#1\c!placehead}]
- [ \v!yes=>\emptyheadfalse,
- \v!empty=>\emptyheadtrue,
- \v!no=>\emptyheadtrue\placeheadfalse]%
- \doifelsevalue{\??ko#1\c!resetnumber}\v!no
- {\setfalse\@@resetsubheadnumbers}%
- {\settrue \@@resetsubheadnumbers}%
- \writetolistfalse
- \processaction
- [\getvalue{\??ko#1\c!incrementnumber}]
- [ \v!yes=>\incrementnumbertrue,
- \v!no=>\incrementnumberfalse,
- \v!list=>\incrementnumberfalse
- % beware, since no numbers are used, no nested lists are
- % possible here
- \writetolisttrue,
- \s!unknown=>{\ifx\currentproduct\empty
- \findsectionnumber{#1}\commalistelement{#4}%
- \fi
- \incrementnumbertrue}]%
- \edef\numberheaddistance {\getvalue{\??ko#1\c!distance}}%
- \edef\numberheadalternative{\getvalue{\??ko#1\c!alternative}}%
- \doifelsevalue{\??ko:\numberheadalternative}\v!horizontal
- \displaysectionheadfalse
- \displaysectionheadtrue
- \ifsectionnumber
- \doifelsevalue{\??sb\@@sectionblock\c!number}\v!yes
- {\doifelsevalue{\??ko#1\c!number}\v!yes
- \headnumbertrue
- \headnumberfalse}
- {\headnumberfalse}%
- \else
- \headnumberfalse
- \fi
- \defconvertexpanded\asciititle{\getvalue{\??ko#1\c!expansion}}{#4}%
- %
- \gdef\currentheadtext{#4}% scheelt args
- \globallet\currentheadnumber\empty
- %
- \ifincrementnumber
- \ifplacehead
- \checknexthead\handlepagebreak{#1}%
- \setsectieenkoppeling{#1}% can be changed when [voor=\somehead{..}...]
- \ifheadprefix
- %\setupreferencing[\c!prefix=-]%
- \setupreferenceprefix[-]%
- \fi
- \getvalue{\e!next\@@sectie}%
- \ifheadnumber
- \setsomeheadconversion{#1}{#3}%
- \let\fullsectionnumber\expandablefullsectionnumber
- \xdef\currentheadnumber{\someheadconversion}%
- \getvalue{\??ko#1\c!inbetween}%
- \ifsomeheadconversion
- \let\fullsectionnumber\naturalfullsectionnumber
- \doplaceheadnumbertext
- {#1}
- {\setsectionlistreference{\@@sectie}{#1}%
- \pagetype[\@@koppeling]%
- \let\fullsectionnumber\writtenfullsectionnumber
- \rawreference\s!sec{#2}{{\someheadconversion}{\asciititle}}%
- \resetsectionmarks\@@sectie
- \setlistparameter\@@koppeling\c!expansion{\getvalue{\??ko#1\c!expansion}}%
- \let\fullsectionnumber\writtenfullsectionnumber
- \dowritetolist\@@koppeling\someheadconversion{#4}\v!head}%
- {\dohandleheadnumber\someheadconversion}% handle is new
- {#4}
- {\marking[#1]{#4}%
- \let\fullsectionnumber\storedfullsectionnumber
- \expanded{\marking[#1\v!number]{\someheadconversion}}}%
- \let\fullsectionnumber\ignoredfullsectionnumber
- \writesection{#1}{\someheadconversion}{#4}%
- \else
- \doplaceheadnumbertext
- {#1}
- {\setsectionlistreference{\@@sectie}{#1}%
- \pagetype[\@@koppeling]%
- \rawreference\s!sec{#2}{{#3}{\asciititle}}%
- \resetsectionmarks\@@sectie
- \setlistparameter\@@koppeling\c!expansion{\getvalue{\??ko#1\c!expansion}}%
- \dowritetolist\@@koppeling{#3}{#4}\v!head}
- {\sectionblocklabel{#1}{\dohandleheadnumber{#3}}}% handle is new
- {#4}
- {\marking[#1]{#4}%
- \doifelsevalue{\??ko#1\c!ownnumber}\v!yes % rommelig omdat
- {\edef\finalsectionnumber{#3}} % #3 al is toegekend
- {\determineheadnumber[#1]}% migreert naar 3e argument
- \expanded{\marking[#1\v!number]{\finalsectionnumber}}}%
- \writesection{#1}{#3}{#4}%
- \fi
- \else
- \getvalue{\??ko#1\c!inbetween}%
- \doplaceheadtext
- {#1}
- {\setsectionlistreference{\@@sectie}{#1}%
- \pagetype[\@@koppeling]%
- \rawreference\s!sec{#2}{{#3}{\asciititle}}%
- \resetsectionmarks\@@sectie
- \setlistparameter\@@koppeling\c!expansion{\getvalue{\??ko#1\c!expansion}}%
- \doifelsevalue{\??ko#1\c!ownnumber}\v!yes % brrr, new per 18/1/2005, sometimes we need
- {\dowritetolist\@@koppeling{#3}{#4}\v!head} % entries in the list (special purpose) but
- {\dowritetolist\@@koppeling {}{#4}\v!head}% not in the header, ok we could pop in a command
- }% \dowritetolist\@@koppeling{}{#4}\v!head}
- {#4}
- {\marking[#1]{#4}%
- \doifelsevalue{\??ko#1\c!ownnumber}\v!yes % brrr
- {\edef\finalsectionnumber{#3}}
- {\determineheadnumber[#1]}%
- % todo : geen markering (leeg maken)
- \expanded{\marking[#1\v!number]{\finalsectionnumber}}}%
- \writesection{#1}{-}{#4}%
- \fi
- \ifheadprefix
- \setupreferenceprefix[\localkopprefix]%
- \fi
- \ifdisplaysectionhead
- \dosomebreak\nobreak
- \emptyheadcorrection
- \getvalue{\??ko#1\c!after}%
- \fi
- \else
- % Whatever future tex's will do with nodes,
- % we assume a node here, because other \c!after=\blank
- % will fail! See 'prikkels'
- %
- % so, maybe we need an explicit \kern
- %
- % do nothing / should be vbox to 0pt
- %
- \checknexthead\dohandlepagebreakB{#1}% toegevoegd ivm subpaginanr / tug sheets
- \setsectieenkoppeling{#1}% can be changed when [voor=\somehead{..}...]
- \ifheadprefix
- \setupreferenceprefix[-]%
- \fi
- \getvalue{\e!next\@@sectie}%
- \ifheadnumber
- \setsomeheadconversion{#1}{#3}%
- \let\fullsectionnumber\expandablefullsectionnumber
- \xdef\currentheadnumber{\someheadconversion}%
- \fi
- \getvalue{\??ko#1\c!inbetween}% documenteren, is enige hook
- \bgroup
- \setsectionlistreference{\@@sectie}{#1}%
- \resetsectionmarks\@@sectie
- \marking[#1]{#4}%
- \doifelsevalue{\??ko#1\c!ownnumber}\v!yes
- {\edef\finalsectionnumber{#3}}
- {\determineheadnumber[#1]}%
- \expanded{\marking[#1\v!number]{\finalsectionnumber}}%
- \pagetype[\@@koppeling]%
-% \bgroup
- \setlistparameter\@@koppeling\c!expansion{\getvalue{\??ko#1\c!expansion}}%
- \ifheadnumber
- \rawreference\s!sec{#2}{{#3}{\asciititle}}%
- \dowritetolist\@@koppeling{#3}{#4}\v!head
- \writesection{#1}{#3}{#4}%
- \else % hm, also no own number
- \rawreference\s!sec{#2}{{#3}{\asciititle}}%
- \dowritetolist\@@koppeling{}{#4}\v!head
- \writesection{#1}{-}{#4}%
- \fi
- \egroup
- \ifheadprefix
- \setupreferenceprefix[\localkopprefix]%
- \fi
- \fi
- \else
- % todo : ref prefix
- \ifplacehead
- \checknexthead\handlepagebreak{#1}%
- \setsectieenkoppeling{#1}% can be changed when [voor=\somehead{..}...]
- \getvalue{\??ko#1\c!inbetween}%
- \doplaceheadtext
- {#1}
- {\forcesectiontolist{#1}{#4}%
- \rawreference\s!sec{#2}{{#3}{\asciititle}}} % #3 ?
- {#4}
- %{}% new:
- {\marking[#1]{#4}%
- \marking[#1\v!number]{}}%
- \writesection{#1}{-}{#4}%
- \ifdisplaysectionhead
- \dosomebreak\nobreak
- \emptyheadcorrection
- \getvalue{\??ko#1\c!after}%
- \fi
- \else
- % do nothing / should be vbox to 0pt
- \checknexthead\handlepagebreak{#1}%
- \setsectieenkoppeling{#1}% can be changed when [voor=\somehead{..}...]
- \getvalue{\??ko#1\c!inbetween}%
- \forcesectiontolist{#1}{#4}%
- \rawreference\s!sec{#2}{{#3}{\asciititle}}% #3 ?
- \marking[#1]{#4}%
- \marking[#1\v!number]{}%
- \writesection{#1}{-}{#4}%
- \fi
- \fi
- \flushingcolumnfloatstrue
- \someheadconversionfalse
- \setfalse\ignorehandlepagebreak
- \let\fullsectionnumber\limitedfullsectionnumber
- % ignorespaces prevents spaces creeping in when after=\dontleavehmode
- \ifdisplaysectionhead\ignorespaces\else\expandafter\GotoPar\fi}
-
-\def\forcesectiontolist#1#2%
- {\ifwritetolist
- % we need to make sure that there is a number set (non
- % zero) else the list mechanism cannot determine the
- % level
- \bgroup
- \setupheadnumber[#1][+1]% traag, wordt \getvalue{\c!next...}
- \setlistparameter\@@koppeling\c!expansion{\getvalue{\??ko#1\c!expansion}}%
- \dowritetolist\@@koppeling{}{#2}\v!head
- \setupheadnumber[#1][-1]% traag, wordt \getvalue{\c!previous...}
- \egroup
- \fi}
-
-\let\previoussectionformat\empty
-\let\currentsectionformat \empty
-
-\let\updatelistreferences \relax
-\let\updatedlistreferences\empty
-
-\def\setsectionlistreference#1#2%
- {\ifnum\countervalue{\??se\previoussection{#1}}>0\relax
- \xdef\previoussectionformat{\@@longformatnumber{\previoussection{#1}}}%
- \else
- \globallet\previoussectionformat\empty
- \fi
- \xdef\currentsectionformat{\@@longformatnumber{#1}}}
-
-\def\startlistreferences#1%
- {\thisissomeinternal{\s!lst}{#1\currentsectionformat}%
- \setxvalue{\s!lst:#1}{\realfolio}% to be sure
- \setxvalue{\s!lst:#1\currentsectionformat}{\realfolio}%
- \setxvalue{\e!previouslocal#1}{\s!lst:#1\previoussectionformat}%
- \setxvalue{\e!currentlocal#1}{\s!lst:#1\currentsectionformat}%
- \doifelse{\currentsectionformat}{}
- {\setglobalcrossreference
- {\e!previous#1}{}{\realfolio}{}}
- {\setglobalsystemreference\rt!list
- {\e!previous#1}{\getvalue{\e!previouslocal#1}}}%
- \def\stoplistreferences{\dostoplistreferences{#1}}}
-
-\def\dostoplistreferences#1%
- {\ifutilitydone
- \addtocommalist{#1}\updatedlistreferences % nog global (\doglobal)
- \globallet\updatedlistreferences\updatedlistreferences % een noodverbandje
- \gdef\updatelistreferences%
- {\def\docommand####1%
- {\setglobalsystemreference\rt!list
- {\e!previous####1}{\getvalue{\e!currentlocal####1}}}%
- \processcommacommand[\updatedlistreferences]\docommand
- \globallet\updatelistreferences\relax
- \globallet\updatedlistreferences\empty}%
- \fi}
-
-\let\stoplistreferences\relax
-
-\appendtoks
- \updatelistreferences
-\to\aftereverypage
-
-% \prevdepth\strutdp % is belangrijk, vergelijk naast elkaar:
-%
-% \subject{test} \input tufte
-% \subject{test} \strut \input tufte
-% \subject{test} \placelist[...]
-
-% todo: kap
-
-% to be documented: \placeheadtext \placeheadnumber
-
-\unexpanded\def\placeheadtext
- {\doquintupleempty\doplaceheadtextornumber
- [\c!textstyle][\c!textcolor][\empty]}
-
-\unexpanded\def\placeheadnumber
- {\doquintupleempty\doplaceheadtextornumber
- [\c!numberstyle][\c!numbercolor][\v!number]}
-
-\def\doplaceheadtextornumber[#1][#2][#3][#4][#5]%
- {\bgroup
- \edef\@@sectie{\??ko\iffifthargument#5\else#4\fi}%
- \dostartattributes\@@sectie\c!style\c!color\empty
- \dontconvertfont
- \dostartattributes\@@sectie{#1}{#2}\empty
- \setupinterlinespace
- \begstrut\getmarking[\mainmarking{#4#3}]\endstrut
- \endgraf
- \dostopattributes
- \dostopattributes
- \egroup}
-
-\chardef\headtimingmode=0
-
-% \chardef\headtimingmode=1 % 0 also works ok now too
-%
-% Martin Kolarik's problem:
-%
-% \setuphead[section][command=\doTitle]
-%
-% \def\doTitle#1#2%
-% {\ruledvbox{\forgetall \hsize=4cm
-% \ruledhbox{\ruledvtop{#1}\ruledvtop{#2}}}}
-%
-% \section{test test test test test test test test test test
-% test test test test test test test}
-
-\newevery \everyheadstart \relax
-
-\def\placeheadmargintexts#1%
- {\the\everyheadstart
- \doifvalue{\??ko#1\c!margintext}\v!yes\placemargincontent}
-
-\def\doplaceheadtext#1#2#3#4%
- {\beginheadplacement{#1}%
- \ifemptyhead % = needed
- \setbox0=\ifvertical\vbox\else\hbox\fi to \zeropoint
- {\headnumbercontentfalse
- \resetsystemmode\v!sectionnumber
- #2}%
- \makestrutofbox0
- \else % = needed
- \setbox0=\ifvertical\vbox\else\hbox\fi % \vhbox
- {\headnumbercontentfalse
- \resetsystemmode\v!sectionnumber
- % less interfering
- \ifcase\headtimingmode\or#2\fi
- % outerside font determines distance
- \dosetfontattribute{\??ko#1}\c!style
- \dosetcolorattribute{\??ko#1}\c!color
- % todo: get the if-else out of it
- \getvalue{\??ko#1\c!command}
- {} % no number
- {\dostartattributes{\??ko#1}\c!textstyle\c!textcolor\empty
- \dontconvertfont
- \ifdisplaysectionhead
- \setupinterlinespace
- \else
- \setupspacing
- \fi
- % \ifcase\headtimingmode#2\fi % can introduce cr
- \getvalue{\??ko#1\c!commandbefore}%
- \placeheadmargintexts{#1}% binnen #3?
- \ifdisplaysectionhead
- \getvalue{\??ko#1\c!textcommand}% struts can be nilled with \setnostrut
- {\setstrut
- \begstrut
- \ifcase\headtimingmode\hbox{#2}\fi
- \executeifdefined{\??ko#1\c!deeptextcommand}\firstofoneargument{#3}%
- \endstrut}% \hbox prevents break
- \xdef\localheadheight {\the\strutht}%
- \xdef\localheaddepth {\the\strutdp}%
- \xdef\localheadlineheight{\the\lineheight}%
- % == \globallet\localheaddepth\strutdepth
- \else
- \ifcase\headtimingmode#2\fi
- \getvalue{\??ko#1\c!textcommand}%
- {\executeifdefined{\??ko#1\c!deeptextcommand}\firstofoneargument{#3}}%
- \fi
- \getvalue{\??ko#1\c!commandafter}%
- \ifdisplaysectionhead\endgraf\fi
- \dostopattributes}}%
- \fi
- \endheadplacement{#1}{#4}}
-
-\def\doplaceheadnumbertext#1#2#3#4#5% maybe move modes outside box
- {\beginheadplacement{#1}%
- \ifemptyhead % = needed
- \setbox0=\ifvertical\vbox\else\hbox\fi to \zeropoint
- {\doiftextelse{#3}
- {\setsystemmode \v!sectionnumber\headnumbercontenttrue }
- {\resetsystemmode\v!sectionnumber\headnumbercontentfalse}%
- #2}%
- \makestrutofbox0
- \else % = needed
- \setbox0=\ifvertical\vbox\else\hbox\fi % \vhbox
- {\doiftextelse{#3}
- {\setsystemmode \v!sectionnumber\headnumbercontenttrue }
- {\resetsystemmode\v!sectionnumber\headnumbercontentfalse}%
- % less interfering
- \ifcase\headtimingmode\or#2\fi
- % outerside font determines distance
- \dosetfontattribute{\??ko#1}\c!style
- \dosetcolorattribute{\??ko#1}\c!color
- % but we don't want color to influence user commands
- \getvalue{\??ko#1\c!command}%
- {\dostartattributes{\??ko#1}\c!numberstyle\c!numbercolor\empty
- % \getvalue{\??ko#1\c!commandbefore}% strange, why here? moved 21/11/2005
- \placeheadmargintexts{#1}% binnen #3?
- \ifdisplaysectionhead
- % can be nilled with \setnostrut
- \getvalue{\??ko#1\c!numbercommand}%
- {\setstrut
- \begstrut
- \executeifdefined{\??ko#1\c!deepnumbercommand}\firstofoneargument{#3}%
- \endstrut}%
- \else
- \getvalue{\??ko#1\c!numbercommand}%
- {\executeifdefined{\??ko#1\c!deepnumbercommand}\firstofoneargument{#3}}%
- \fi
- \dostopattributes}
- {\dostartattributes{\??ko#1}\c!textstyle\c!textcolor\empty
- \dontconvertfont
- \ifdisplaysectionhead
- \setupinterlinespace
- \else
- \setupspacing
- \fi
- % \ifcase\headtimingmode#2\fi % can introduce cr
- \getvalue{\??ko#1\c!commandbefore}% makes more sense here
- \placeheadmargintexts{#1}% binnen #3?
- \ifdisplaysectionhead
- \getvalue{\??ko#1\c!textcommand}% struts can be nilled with \setnostrut
- {\setstrut
- \begstrut
- \ifcase\headtimingmode\hbox{#2}\fi
- \executeifdefined{\??ko#1\c!deeptextcommand}\firstofoneargument{#4}%
- \endstrut}% \hbox prevents break
- \xdef\localheadheight {\the\strutht}%
- \xdef\localheaddepth {\the\strutdp}%
- \xdef\localheadlineheight{\the\lineheight}%
- % == \globallet\localheaddepth\strutdepth
- \else
- \ifcase\headtimingmode#2\fi % inside textcommand ?
- \getvalue{\??ko#1\c!textcommand}%
- {\executeifdefined{\??ko#1\c!deeptextcommand}\firstofoneargument{#4}}%
- \fi
- \getvalue{\??ko#1\c!commandafter}%
- \ifdisplaysectionhead\endgraf\fi
- \dostopattributes}}%
- \fi
- \endheadplacement{#1}{#5}}
-
-
-
-%D \starttyping
-%D \def\StretchedBox#1%
-%D {\framed
-%D [frame=off,offset=.5em,align=middle,width=broad]
-%D {\sc\def\stretchedspaceamount{.3em}\stretchednormalcase{#1}}}
-%D
-%D \definehead[MySubject][subject]
-%D \setuphead [MySubject][deeptextcommand=\StretchedBox]
-%D
-%D \MySubject{feeling stretched feeling stretched feeling stretched feeling stretched}
-%D \stoptyping
-
-\newsignal\headsignal
-\let\headlastlinewidth\!!zeropoint
-
-\def\beginheadplacement#1%
- {\bgroup
- \setsystemmode{#1}% to be documented
- \ifgridsnapping\iftracegridsnapping\showstruts\fi\fi
- \xdef\localheadheight {\the\strutht}%
- \xdef\localheaddepth {\the\strutdp}%
- \xdef\localheadlineheight{\the\lineheight}%
- % == \globallet\localheaddepth\strutdp
- \everypar\emptytoks % needed indeed
- \noindent % ipv \whitespace elders, na \forgetall !
- \bgroup
- \doifinsetelse{\getvalue{\??ko#1\c!aligntitle}}{\v!yes,\v!float}% new
- {\skip0 1\leftskip
- \skip2 1\rightskip
- \xdef\localheadskip{\the\skip0}%
- \forgetall
- \leftskip\skip0
- \rightskip\skip2
- \setlocalhsize\hsize\localhsize
- \forgetbothskips}
- {\globallet\localheadskip\!!zeropoint
- \forgetall}%
- \dontcomplain
- \postponefootnotes
- \iflocation\ifdisplaysectionhead\else\noninterferingmarks\fi\fi
- \resetinteractionparameter\c!style
- \resetinteractionparameter\c!color
- \resetinteractionparameter\c!contrastcolor
- \strictouterreferencestrue % tzt instelling
- \def\localheadsetup{\dolocalheadsetup{#1}}%
- \startsynchronization}
-
-% \setuphead[chapter] [style=\bfd,after=,hang=line] % fit broad 2
-% \setuphead[section] [style=\bfc,after=,hang=line]
-% \setuphead[subsection] [style=\bfb,after=,hang=line]
-% \setuphead[subsubsection] [style=\bfa,after=,hang=line]
-% \setuphead[subsubsubsection][style=\bf ,after=,hang=line]
-%
-% \chapter {Test} \input tufte \page
-% \section {Test} \input tufte \page
-% \subsection {Test} \input tufte \page
-% \subsubsection {Test} \input tufte \page
-% \subsubsubsection{Test} \input tufte \page
-%
-% \chapter {Test\\Test} \input tufte \page
-% \section {Test\\Test} \input tufte \page
-% \subsection {Test\\Test} \input tufte \page
-% \subsubsection {Test\\Test} \input tufte \page
-% \subsubsubsection{Test\\Test} \input tufte \page
-
-\def\hangheadplacement
- {\scratchdimen\localheadlineheight
- \bgroup
- \openlineheight\scratchdimen
- \scratchdimen\ht0
- \advance\scratchdimen\dp0
- \getnoflines\scratchdimen
- \advance\noflines\minusone
- \expanded{\egroup\noflines\the\noflines}% brrr
- \setbox0\hbox{\lower\noflines\scratchdimen\box0}%
- \scratchdimen\ht0
- \advance\scratchdimen\dp0
- \advance\scratchdimen-\localheadheight
- \advance\scratchdimen+\strutdp
- \ht0 \strutht
- \dp0 \strutdp
- \edef\localheaddepth{\the\strutdp}}
-
-\newconditional\continuoussectionhead % oeps, \newif\ifcontinuoushead got lost
-
-\def\endheadplacement#1#2%
- {\doifelsevalue{\??rf#1\c!state}\v!start
- {\doifvaluenothing{\??ko#1\c!file}{\autocrossdocumentfalse}}
- {\autocrossdocumentfalse}%
- % no message needed here, should be a proper switch
- \noflines\zerocount
- \ifdisplaysectionhead
- % new (tod tight == one following line up)
- \processaction
- [\getvalue{\??ko#1\c!hang}]
- [ \v!line=>\hangheadplacement\noflines\zerocount,
- \v!broad=>\hangheadplacement\getnoflines\scratchdimen,
- \v!fit=>\hangheadplacement\getrawnoflines\scratchdimen,
- \v!none=>\noflines\zerocount,
- \v!default=>\noflines\zerocount,
- \v!unknown=>\hangheadplacement\noflines0\commalistelement\advance\noflines\minusone]%
- % so far
- \let\headlastlinewidth\!!zeropoint
- \snaptogrid[\getvalue{\??ko#1\c!grid}]\hbox
- {\hskip\localheadskip
- \hskip\getvalue{\??ko#1\c!margin}\relax
- \iflocation
- \ifautocrossdocument
- \doifreferencefoundelse{\getvalue{\??ko#1\c!file}::#1}
- {\edef\currentinnerreference{\s!aut:\currenttextreference}% stored in
- \gotoouterlocation{}{\box0}} % text slot
- {\hbox{\box0}}%
- \else
- \hbox{\box0}%
- \fi
- \else
- \hbox{\box0}%
- \fi}%
- \doflushnotes % new, not really needed
- \endgraf
- \ifvmode
- \ifnum\noflines>\zerocount
- \dorecurse\noflines{\nointerlineskip\dosomebreak\nobreak\strut\endgraf}%
- \fi
- \nointerlineskip
- \dosomebreak\nobreak
- \fi
- #2%
- \else
- \strut
- \doflushnotes % new, here since we're in par mode
- \iflocation
- \ifautocrossdocument
- \hhboxindent=\ifconditional\continuoussectionhead\headlastlinewidth\else\zeropoint\fi
- \unhhbox0\with{\gotobox{\box\hhbox}[\getvalue{\??ko#1\c!file}::#1]}%
- \advance\lasthhboxwidth by \numberheaddistance
- \xdef\headlastlinewidth{\the\lasthhboxwidth}%
- \else
- \unhbox0
- \globallet\headlastlinewidth\!!zeropoint
- \fi
- \else
- \unhbox0
- \globallet\headlastlinewidth\!!zeropoint
- \fi
- #2%
- \dimen0=\numberheaddistance
- \hskip\dimen0 \!!plus \dimen0 \!!minus .25\dimen0
- \hskip\headsignal\ignorespaces
- \fi
- \ifdisplaysectionhead \ifvmode
- \ifgridsnapping % important, font related depth, see comment
- \prevdepth\strutdp
- \else
- \prevdepth\localheaddepth
- \fi
- \fi \fi
- \stopsynchronization
- \egroup
- \egroup
- \ifdisplaysectionhead
- \dochecknextindentation{\??ko#1}%
- \else
- \nonoindentation % recently added, was a bug
- \fi}
-
-\def\checknexthead#1#2% nog optioneel
- {\ifhmode
- \scratchcounter=\lastpenalty\unpenalty % no beauty in this
- \ifdim\lastskip=\headsignal
- \handlenopagebreak{#1}%
- \global\settrue\continuoussectionhead
- \else
- \penalty\scratchcounter
- \global\setfalse\continuoussectionhead
- #1{#2}%
- \fi
- \else
- \global\setfalse\continuoussectionhead
- #1{#2}%
- \fi}
-
-\def\dosetupheadnumber[#1][#2#3]% todo: = (don't reset)
- {\bgroup
- \setsectieenkoppeling{#1}%
- \doifinstringelse{#2}{+-}
- {\doifelsenothing{#3}
- {\@@nextsectionnumber\@@sectie}
- {\!!counta=#2#3\relax
- \advance\!!counta \@@sectionvalue\@@sectie
- \@@setsectionnumber\@@sectie\!!counta}}
- {\@@setsectionnumber\@@sectie{#2#3}}%
- \egroup}
-
-\def\setupheadnumber
- {\dodoubleargument\dosetupheadnumber}
-
-\def\currentheadnumber{0}
-
-\def\determineheadnumber[#1]%
- {\bgroup
- \setsectieenkoppeling{#1}%
- \xdef\currentheadnumber{\@@sectionvalue{\@@sectie}}%
- \egroup}
-
-\def\complexheadnumber[#1]%
- {\bgroup
- \edef\currentheadnumber{#1}%
- \doifinsetelse{-}{#1} % br undocumented
- {\removefromcommalist{-}\currentheadnumber % br
- \setsectieenkoppeling\currentheadnumber
- \setupsection[\@@sectie][\c!previousnumber=\v!no]}%
- {\setsectieenkoppeling\currentheadnumber}%
- \xdef\currentheadnumber{\@@sectionvalue{\@@sectie}}%
- \doifnot{\currentheadnumber}{0}{\finalsectionnumber}%
- \egroup}
-
-\def\simpleheadnumber
- {\currentheadnumber}
-
-\definecomplexorsimple\headnumber
-
-\def\alinea
- {\par}
-
-% nice testcase
-%
-% \setupheads[aligntitle=yes]
-%
-% \startnarrower
-% \subject{\dorecurse{100}{x }}
-% \section{\dorecurse{100}{x }}
-% \input tufte \par
-% \setupheads[alternative=inmargin]
-% \subject{\dorecurse{100}{x }}
-% \section{\dorecurse{100}{x }}
-% \input tufte \par
-% \stopnarrower
-
-\let\numberheadalternative\v!normal
-
-\def\defineheadplacement
- {\dodoubleargument\dodefineheadplacement}
-
-\def\dodefineheadplacement[#1][#2]% #3#4
- {\setvalue{\??ko:#1}{#2}%
- \setvalue{\??ko::#1}}
-
-\def\normalplacehead
- {\executeifdefined
- {\??ko::\numberheadalternative}
- {\getvalue{\??ko::\v!normal}}}
-
-\defineheadplacement[\v!paragraph][\v!vertical]#1#2%
- {\vbox
- {\localheadsetup
- \begstrut\ifheadnumbercontent#1\hskip\numberheaddistance\fi#2}}
-
-% \defineheadplacement[\v!normal][\v!vertical]#1#2%
-% {\ifheadnumbercontent
-% \setbox0\hbox{{#1}\hskip\numberheaddistance}%
-% \vbox
-% {\localheadsetup
-% \hangindent 1\wd0
-% \hangafter 1
-% \noindent
-% \unhbox0 % don't use \strut's here!
-% #2}%
-% \else
-% \vbox
-% {\localheadsetup\noindent#2}%
-% \fi}
-%
-% enhanced version:
-
-% \setuphead
-% [chapter]
-% [numberwidth=2cm,hang=line,after={\blank[3*line]}]
-%
-% \chapter{Oeps oeps oeps} \input tufte \section{Oeps}
-% \chapter{Oeps oeps oeps} \section{Oeps} \input tufte
-
-\defineheadplacement[\v!normal][\v!vertical]#1#2%
- {\vbox
- {\localheadsetup
- \edef\headwidth {\headparameter\c!width }%
- \edef\headnumberwidth{\headparameter\c!numberwidth}%
- \edef\headtextwidth {\headparameter\c!textwidth }%
- \ifheadnumbercontent
- \ifx\headwidth\empty
- \else
- \ifx\headnumberwidth\empty
- \ifx\headtextwidth\empty\else
- \edef\headnumberwidth{\the\dimexpr\headwidth-\headtextwidth\relax}%
- \fi
- \else
- \ifx\headtextwidth\empty
- \edef\headtextwidth{\the\dimexpr\headwidth-\headnumberwidth\relax}%
- \fi
- \fi
- \hsize\headwidth
- \fi
- \ifx\headnumberwidth\empty\else
- \let\numberheaddistance\!!zeropoint
- \fi
- \setbox\scratchbox\hbox \ifx\headnumberwidth\empty\else to \headnumberwidth\fi{{#1}}%
- \scratchdimen\dimexpr\wd\scratchbox+\numberheaddistance\relax
- \ifx\headtextwidth\empty\else
- \hsize\dimexpr\scratchdimen+\headparameter\c!textwidth\relax
- \fi
- \hangindent\scratchdimen
- \hangafter \plusone
- \noindent
- \box\scratchbox\hskip\numberheaddistance
- \else
- \ifx\headtextwidth\empty
- \ifx\headwidth\empty
- \else
- \hsize\headwidth
- \fi
- \else
- \hsize\headtextwidth
- \fi
- \noindent
- \fi
- #2}}
-
-\def\placeheadmargin#1#2%
- {\vbox
- {\localheadsetup
- \begstrut % use one \strut here!
- \dontleavehmode % in case there is no strut, else side effects with llap
- \ifheadnumbercontent
- \llap{\hbox to 5em{\hfill{#1}\hskip\localheadskip\hskip\leftmargindistance}}% introduces whitespace
- % maybe better:
- % \inleftmargin{\hbox{\hss{#1}\hskip\localheadskip}}%
- \fi
- {#2}}}
-
-\defineheadplacement[\v!inmargin][\v!vertical]#1#2{\placeheadmargin{#1}{#2}}
-\defineheadplacement[\v!margin] [\v!vertical]#1#2{\placeheadmargin{#1}{#2}}
-
-\defineheadplacement[\v!middle][\v!vertical]#1#2%
- {\vbox
- {\localheadsetup
- \veryraggedcenter
- \let\\\endgraf
- \let\crlf\endgraf
- \ifheadnumbercontent\strut#1\par\fi\begstrut#2}}
-
-\defineheadplacement[\v!text][\v!horizontal]#1#2%
- {\bgroup
- \localheadsetup % no stretch in distance
- \ifheadnumbercontent{#1}\kern\numberheaddistance\fi{\begstrut#2}%
- \egroup}
-
-\def\placeheadlohi#1#2#3%
- {\ifheadnumbercontent
- \setbox0\hbox{#2}
- \setbox2=#1{\localheadsetup\advance\hsize-\wd0\relax#3}%
- \hbox{\box0\hskip\numberheaddistance\box2}%
- \else
- #1{\localheadsetup\noindent#3}%
- \fi}
-
-% onder/boven lijnt het nummer op de onderste/bovenste regel
-% uit van een meerregelige kop
-
-\defineheadplacement[\v!bottom][\v!vertical]#1#2{\placeheadlohi\vbox{#1}{#2}}
-\defineheadplacement[\v!top] [\v!vertical]#1#2{\placeheadlohi\vtop{#1}{#2}}
-
-% default == instellingen
-% koppeling == koppen, breaks, marks, enz.
-% sectie == nummering
-
-\let\@@kolist=\empty
-
-\def\dododefinehead#1#2% % don't preset prefix to much
- {\presetlabeltext[#1=]%
-% \getparameters
-% [\??ko#1]
-% [\c!numberstyle=\getvalue{\??ko#1\c!style},
-% \c!textstyle=\getvalue{\??ko#1\c!style},
-% \c!numbercolor=\getvalue{\??ko#1\c!color},
-% \c!textcolor=\getvalue{\??ko#1\c!color}]%
- % deeptextcommand and deepnumbercommand are left undefined !
- \doifassignmentelse{#2}
- {\getparameters
- [\??ko#1]
- [\c!section=\getvalue{\??ko\getvalue{\??ko#1\c!coupling}\c!section},
-\c!numberstyle=,
-\c!textstyle=,
-\c!numbercolor=,
-\c!textcolor=,
- \c!default=,
- \c!coupling=,
- \c!prefix=,
- \c!before=,
- \c!after=,
- \c!distance=\!!zeropoint,
- \c!page=,
- \c!header=,
- \c!text=,
- \c!footer=,
- \c!style=,
- \c!numbercommand=,
- \c!textcommand=,
- \c!ownnumber=\v!no,
- \c!number=\v!yes,
- \c!color=,
- \c!continue=\v!yes,
- \c!placehead=\v!yes,
- \c!resetnumber=\v!yes,
- \c!incrementnumber=\v!yes,
- \c!alternative=\@@koalternative,
- \c!command=\normalplacehead,
- \c!separator=\@@koseparator,
- \c!stopper=\@@kostopper,
- \c!align=\@@koalign,
- \c!aligntitle=\@@koaligntitle,
- \c!tolerance=\@@kotolerance,
- \c!indentnext=\@@koindentnext,
- \c!strut=\@@kostrut,
- \c!hang=\@@kohang,
- \c!file=,
- \c!expansion=,
- \c!grid=,
- \c!margintext=,
- \c!margin=\@@komargin,
- #2]%
- \ConvertToConstant\doifnot{#1}{\getvalue{\??ko#1\c!default}}
- {\doifsomething{\getvalue{\??ko#1\c!default}}
- {\copyparameters
- [\??ko#1][\??ko\getvalue{\??ko#1\c!default}]
- [\c!before,\c!after,\c!command,\c!file,\c!page,\c!continue,
- \c!header,\c!text,\c!footer,\c!separator,\c!stopper,\c!resetnumber,
- \c!number,\c!ownnumber,\c!placehead,\c!incrementnumber,
- \c!style,\c!color,\c!distance,\c!alternative,\c!indentnext,
- % new per 20/03/3002 (o-pbu-l) / was too confusing
- % \c!numberstyle,\c!textstyle,\c!expansion,
- % again too confusing
- \c!align,\c!aligntitle,\c!tolerance,\c!grid,\c!hang,\c!strut,
- \c!numbercommand,\c!textcommand,\c!margintext,\c!margin]}}%
- \getparameters[\??ko#1][#2]%
- \doifsomething{\getvalue{\??ko#1\c!section}}
- {\doifelsemarking{#1}% \doifundefined{\??mk#1}
- {}% marking #1 already defined
- {\definemarking[#1]%
- \couplemarking[#1][\getvalue{\??ko#1\c!section}]%
- \definemarking[#1\v!number]%
- \couplemarking[#1\v!number][\getvalue{\??ko#1\c!section}]}}%
- \doifundefined{\??li#1}{\definelist[#1]}}
- {\ConvertToConstant\doifelse{#1}{#2}
- {\doifundefined{\??li#1}{\definelist[#1]}}
- {\copyparameters
- [\??ko#1][\??ko#2]
- [\c!level,\c!section,\c!coupling,\c!prefix,
- \c!before,\c!after,\c!command,\c!file,\c!page,\c!continue,
- \c!separator,\c!stopper,
- \c!header,\c!text,\c!footer,\c!resetnumber,
- \c!number,\c!ownnumber,\c!placehead,\c!incrementnumber,
- \c!style,\c!color,\c!distance,\c!alternative,\c!indentnext,
- % new per 20/03/3002 (o-pbu-l) / was too confusing
- % \c!numberstyle,\c!textstyle,\c!expansion,
- % again too confusing
- \c!align,\c!aligntitle,\c!tolerance,\c!grid,\c!hang,\c!strut,
- \c!numbercommand,\c!textcommand,\c!margintext,\c!margin]%
- \getparameters[\??ko#1][\c!expansion=]% iig een value, rather fuzzy
- \definemarking[#1][#2]%
- \definemarking[#1\v!number][#2\v!number]%
- \doifundefined{\??li#1}{\definelist[#1][#2]}}}%
- \addtocommalist{#1}\@@kolist
- \setevalue{\??sk#1}{\getvalue{\??ko#1\c!coupling}}%
- \setevalue{\??by#1}{\getvalue{\??ko#1\c!section}}%
- \setevalue{\??by\v!by#1}{\getvalue{\??ko#1\c!section}}%
- \setvalue{#1}{\dodoubleempty\doconstructhead[#1]}}
-
-\def\dodefinehead[#1][#2]%
- {\doifelsenothing{#2}
- {% todo: message that it's an invalid definition
- \setvalue{#1}{\endgraf[#1]\kern.5em}}
- {\doifassignmentelse{#2}
- {\dododefinehead{#1}{#2}}
- {\doifdefined{\??ko#2\c!section}
- {\dododefinehead{#1}{#2}}}}}
-
-\def\definehead
- {\dodoubleemptywithset\dodefinehead}
-
-\def\doconstructhead[#1][#2]%
- {\dowithpargument{\dodoconstructhead{#1}[#2]}}
-
-\def\dosetuphead[#1][#2]%
- {\getparameters[\??ko#1][#2]%
- % The next check prevents hard to trace problems. I once
- % set \c!command to nothing and (quite natural) got the
- % wrong references etc. The whole bunch should be boxed!
- \expandafter\defconvertedcommand\expandafter\ascii\csname\??ko#1\c!command\endcsname
- \doifnothing\ascii{\setvalue{\??ko#1\c!command}{\normalplacehead}}}
-
-\def\setuphead
- {\dodoubleargumentwithset\dosetuphead}
-
-\def\dosetupheads[#1]%
- {\getparameters[\??ko][#1]%
- \doifelse{\@@kosectionnumber}\v!yes\sectionnumbertrue\sectionnumberfalse}
-
-\def\setupheads
- {\dosingleargument\dosetupheads}
-
-\def\systemsuppliedchapter {\getvalue{\v!chapter}}
-\def\systemsuppliedtitle {\getvalue{\v!title}}
-
-% a left over
-
-\def\complexbijlage[#1]#2%
- {\page[\v!right]
- \setuppagenumbering[\c!state=\v!stop]
- \systemsuppliedchapter[#1]{#2}
- \page[\v!right]
- \setuppagenumbering[\c!state=\v!start]
- \setuppagenumbering[\c!number=1]}
-
-\setvalue{\v!appendix}%
- {\complexorsimpleempty\bijlage}
-
-\setupheads
- [\c!alternative=\v!normal,
- \c!sectionnumber=\v!yes,
- \c!separator=.,
- \c!stopper=,
- \c!limittext=\v!yes,
- \c!align=,
- \c!aligntitle=,
- \c!tolerance=,
- \c!strut=,
- \c!indentnext=\v!no,
- \c!margin=\zeropoint,
- \c!hang=\v!none,
- \c!command=]
-
-\definesectionblock [\v!frontpart] [\v!frontmatter] [\c!number=\v!no]
-\definesectionblock [\v!bodypart] [\v!bodymatter] [\c!number=\v!yes]
-\definesectionblock [\v!appendix] [\v!appendices] [\c!number=\v!yes]
-\definesectionblock [\v!backpart] [\v!backmatter] [\c!number=\v!no]
-
-\definesection[\s!section-1] % part
-\definesection[\s!section-2] % chapter
-\definesection[\s!section-3] % section
-\definesection[\s!section-4] % subsection
-\definesection[\s!section-5] % subsubsection
-\definesection[\s!section-6] % subsubsubsection
-\definesection[\s!section-7] % subsubsubsubsection
-
-% \c!eigennummer ook hier?
-
-\definehead
- [\v!part]
- [\c!section=\s!section-1,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!chapter]
- [\c!section=\s!section-2,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!section]
- [\c!section=\s!section-3,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!subsection]
- [\c!section=\s!section-4,
- \c!default=\v!section,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!subsubsection]
- [\c!section=\s!section-5,
- \c!default=\v!subsection,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!subsubsubsection]
- [\c!section=\s!section-6,
- \c!default=\v!subsubsection,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!subsubsubsubsection]
- [\c!section=\s!section-7,
- \c!default=\v!subsubsubsection,
- \c!ownnumber=\v!no]
-
-\definehead
- [\v!title]
- [\c!coupling=\v!chapter,
- \c!default=\v!chapter,
- \c!incrementnumber=\v!no]
-
-\definehead
- [\v!subject]
- [\c!coupling=\v!section,
- \c!default=\v!section,
- \c!incrementnumber=\v!no]
-
-\definehead
- [\v!subsubject]
- [\c!coupling=\v!subsection,
- \c!default=\v!subsection,
- \c!incrementnumber=\v!no]
-
-\definehead
- [\v!subsubsubject]
- [\c!coupling=\v!subsubsection,
- \c!default=\v!subsubsection,
- \c!incrementnumber=\v!no]
-
-\definehead
- [\v!subsubsubsubject]
- [\c!coupling=\v!subsubsubsection,
- \c!default=\v!subsubsubsection,
- \c!incrementnumber=\v!no]
-
-\definehead
- [\v!subsubsubsubsubject]
- [\c!coupling=\v!subsubsubsubsection,
- \c!default=\v!subsubsubsubsection,
- \c!incrementnumber=\v!no]
-
-\setupsection
- [\s!section-2]
- [\v!appendix\c!conversion=\v!Character,
- \c!previousnumber=\v!no]
-
-\setuphead
- [\v!part]
- [\c!placehead=\v!no]
-
-\setuphead
- [\v!chapter]
- [\v!appendix\c!label=\v!appendix,
- \v!bodypart\c!label=\v!chapter] % bijlageconversie=\Character
-
-\setuphead
- [\v!section]
- [\v!appendix\c!label=\v!section,
- \v!bodypart\c!label=\v!section] % bijlageconversie=\Character
-
-\setuphead
- [\v!subsection]
- [\v!appendix\c!label=\v!subsection,
- \v!bodypart\c!label=\v!subsection] % bijlageconversie=\Character
-
-\setuphead
- [\v!subsubsection]
- [\v!appendix\c!label=\v!subsubsection,
- \v!bodypart\c!label=\v!subsubsection] % bijlageconversie=\Character
-
-\setuphead
- [\v!part,\v!chapter]
- [%\c!align=,
- %\c!indentnext=\v!no,
- \c!continue=\v!no,
- \c!page=\v!right,
- \c!header=,
- \c!style=\tfc,
- \c!distance=.75em,
- \c!before={\blank[2*\v!big]},
- \c!after={\blank[2*\v!big]}]
-
-\setuphead
- [\v!section]
- [%\c!align=,
- %\c!indentnext=\v!no,
- \c!style=\tfa,
- \c!distance=.75em,
- \c!before={\blank[2*\v!big]},
- \c!after=\blank]
-
-\setuphead % nieuw
- [\v!subsection]
- [\c!page=]
-
-\definecombinedlist
- [\v!content]
- [\v!part,
- \v!chapter,
- \v!section,
- \v!subsection,
- \v!subsubsection,
- \v!subsubsubsection,
- \v!subsubsubsubsection]
- [\c!level=\v!subsubsubsubsection,
- \c!criterium=\v!local]
-
-\setuplist
- [\v!part]
- [\c!before={\blank\page[\v!preference]},
- \c!after=\blank,
- \c!label=\v!yes,
- \c!separator=:,
- \c!distance=1em]
-
-\setuplist
- [\v!chapter]
- [\c!before={\blank\page[\v!preference]},
- \c!after=]
-
-\setuplist [\v!part] [\c!width=0em]
-\setuplist [\v!chapter] [\c!width=2em]
-\setuplist [\v!section] [\c!width=3em]
-\setuplist [\v!subsection] [\c!width=4em]
-\setuplist [\v!subsubsection] [\c!width=5em]
-\setuplist [\v!subsubsubsection] [\c!width=6em]
-\setuplist [\v!subsubsubsubsection] [\c!width=7em]
-
-% hm
-
-\setuppagenumbering % na instellen hoofdteksten !
- [\c!alternative=\v!singlesided,
- \c!location={\v!header,\v!middle},
- \c!conversion=\v!numbers,
- \c!width=, % in geval van \v!marginedge
- \c!left=,
- \c!right=,
- \c!way=\v!by\v!part,
- \c!text=,
- \v!chapter\v!number=\v!no, % v
- \v!part\v!number=\v!yes, % v
- \c!numberseparator=--,
- \c!textseparator=\tfskip,
- \c!state=\v!start,
- \c!command=,
- \c!strut=\v!yes, % nieuw
- \c!style=, % \v!normal, % empty, otherwise conflict
- \c!color=]
-
-\protect \endinput
diff --git a/tex/context/base/core-sec.mkii b/tex/context/base/core-sec.tex
index 960de366f..6cc0fbbf9 100644
--- a/tex/context/base/core-sec.mkii
+++ b/tex/context/base/core-sec.tex
@@ -23,55 +23,7 @@
% in manual (zie prikkels) : tussen=\blanko is enige hook om
% met kop-in-hoofd een spatiering af te dwingen
-\writestatus{loading}{Context Core Macros / Sectioning}
-
-\startmessages dutch library: structures
- title: structuur
- 1: begin van sectieblok --
- 2: eind van sectieblok --
-\stopmessages
-
-\startmessages english library: structures
- title: structure
- 1: begin of sectionblock --
- 2: end of sectionblock --
-\stopmessages
-
-\startmessages german library: structures
- title: struktur
- 1: Begin des Abschnittsblocks --
- 2: Ende des Abschnittsblocks --
-\stopmessages
-
-\startmessages czech library: structures
- title: struktury
- 1: zacatek oddilu (sekce) --
- 2: konec oddilu (sekce) --
-\stopmessages
-
-\startmessages italian library: structures
- title: struttura
- 1: inizio del blocco (sezione) --
- 2: fine del blocco (sezione) --
-\stopmessages
-
-\startmessages norwegian library: structures
- title: struktur
- 1: starten av blokk -- (seksjon)
- 2: slutten av blokk -- (seksjon)
-\stopmessages
-
-\startmessages romanian library: structures
- title: structuri
- 1: inceput de bloc sectiune --
- 2: sfarsit de bloc sectiune --
-\stopmessages
-
-\startmessages french library: structures
- title: structure
- 1: début de blocsection --
- 2: fin de blocsection --
-\stopmessages
+\writestatus{loading}{ConTeXt Core Macros / Sectioning}
\unprotect
@@ -1101,7 +1053,7 @@
\def\dohandlepagebreakAA#1%
{\ifnum\lastpenalty>0
- \global\paginageblokkeerdtrue
+ \global\pagebreakdisabledtrue
\fi}
% \setuphead[section][aligntitle=float] % permits title next to sidefloat
@@ -1113,8 +1065,8 @@
% \getvalue{\??ko#1\c!before}%
% % \whitespace vervangen door \noindent elders
% \relax
-% \ifpaginageblokkeerd
-% \global\paginageblokkeerdfalse
+% \ifpagebreakdisabled
+% \global\pagebreakdisabledfalse
% \else
% \!!countb\getvalue{\??se\@@sectie\c!level}\relax
% \ifnum\!!countb>\@@kolevel\relax
@@ -1136,8 +1088,8 @@
\getvalue{\??ko#1\c!before}%
% \whitespace vervangen door \noindent elders
\relax
- \ifpaginageblokkeerd
- \global\paginageblokkeerdfalse
+ \ifpagebreakdisabled
+ \global\pagebreakdisabledfalse
\else
\ifcase\somebreakmethod
% 0 = nothing
@@ -1920,7 +1872,7 @@
{\globallet\localheadskip\!!zeropoint
\forgetall}%
\dontcomplain
- \postponefootnotes
+ \postponenotes
\iflocation\ifdisplaysectionhead\else\noninterferingmarks\fi\fi
\resetinteractionparameter\c!style
\resetinteractionparameter\c!color
diff --git a/tex/context/base/core-snc.tex b/tex/context/base/core-snc.tex
index ac6960f4d..99c7d58f6 100644
--- a/tex/context/base/core-snc.tex
+++ b/tex/context/base/core-snc.tex
@@ -2,7 +2,7 @@
%D [ file=core-snc,
%D version=2003.12.01,
%D title=\CONTEXT\ Core Macros,
-%D subtitle=Synchronization Support,
+%D subtitle=Synchronization,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Synchronization}
+\writestatus{loading}{ConTeXt Core Macros / Synchronization}
\unprotect
diff --git a/tex/context/base/core-spa.lua b/tex/context/base/core-spa.lua
index 5f4df72a2..0f308b19c 100644
--- a/tex/context/base/core-spa.lua
+++ b/tex/context/base/core-spa.lua
@@ -6,13 +6,43 @@ if not modules then modules = { } end modules ['core-spa'] = {
license = "see context related readme files"
}
--- todo: test without unset
+-- this code dates from the beginning and is kind of experimental; it
+-- will be optimized and improved soon
-local format, insert = string.format, table.insert
-local utfchar = utf.char
+local next, type = next, type
+local format, gmatch, concat = string.format, string.gmatch, table.concat
+local texsprint, texlists = tex.sprint, tex.lists
+
+local ctxcatcodes = tex.ctxcatcodes
-- vertical space handler
+local trace_vbox_vspacing = false trackers.register("nodes.vbox_vspacing", function(v) trace_vbox_vspacing = v end)
+local trace_page_vspacing = false trackers.register("nodes.page_vspacing", function(v) trace_page_vspacing = v end)
+local trace_collect_vspacing = false trackers.register("nodes.collect_vspacing", function(v) trace_collect_vspacing = v end)
+local trace_vspacing = false trackers.register("nodes.vspacing", function(v) trace_vspacing = v end)
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local slide_node_list = node.slide
+local free_node = node.free
+local copy_node = node.copy
+local traverse_nodes = node.traverse
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local remove_node = nodes.remove
+local make_penalty_node = nodes.penalty
+local count_nodes = nodes.count
+local node_ids_to_string = nodes.ids_to_string
+
+local glyph = node.id("glyph")
+local penalty = node.id("penalty")
+local kern = node.id("kern")
+local glue = node.id('glue')
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+
vspacing = vspacing or { }
vspacing.categories = {
@@ -26,12 +56,14 @@ vspacing.categories = {
[7] = 'goback',
}
+local categories = vspacing.categories
+
function vspacing.tocategories(str)
local t = { }
- for s in str:gmatch("[^, ]") do
+ for s in gmatch(str,"[^, ]") do
local n = tonumber(s)
if n then
- t[vspacing.categories[n]] = true
+ t[categories[n]] = true
else
t[b] = true
end
@@ -43,7 +75,7 @@ function vspacing.tocategory(str)
if type(str) == "string" then
return set.tonumber(vspacing.tocategories(str))
else
- return set.tonumber({ [vspacing.categories[str]] = true })
+ return set.tonumber({ [categories[str]] = true })
end
end
@@ -51,90 +83,87 @@ vspacing.data = vspacing.data or { }
vspacing.data.map = vspacing.data.map or { }
vspacing.data.skip = vspacing.data.skip or { }
-input.storage.register(false, "vspacing/data/map", vspacing.data.map, "vspacing.data.map")
-input.storage.register(false, "vspacing/data/skip", vspacing.data.skip, "vspacing.data.skip")
+storage.register("vspacing/data/map", vspacing.data.map, "vspacing.data.map")
+storage.register("vspacing/data/skip", vspacing.data.skip, "vspacing.data.skip")
do
+ vspacing.fixed = false
+
local map = vspacing.data.map
local skip = vspacing.data.skip
- vspacing.fixed = false
- vspacing.trace = false
-
local multiplier = lpeg.C(lpeg.S("+-")^0 * lpeg.R("09")^1) * lpeg.P("*")
local category = lpeg.P(":") * lpeg.C(lpeg.P(1)^1)
local keyword = lpeg.C((1-category)^1)
-
local splitter = (multiplier + lpeg.Cc(1)) * keyword * (category + lpeg.Cc(false))
- function vspacing.analyse(str)
- local category, order, penalty, command, fixed = { }, 0, 0, { }, vspacing.fixed
- local function analyse(str)
- for s in str:gmatch("([^ ,]+)") do
- local amount, keyword, detail = splitter:match(s)
- if keyword then
- local mk = map[keyword]
- if mk then
- analyse(mk)
- elseif keyword == "fixed" then
- fixed = true
- elseif keyword == "flexible" then
- fixed = false
- elseif keyword == "category" then
- -- is a set
- local n = tonumber(detail)
- if n then
- category[vspacing.categories[n]] = true
- else
- category[detail] = true
- end
- elseif keyword == "order" then
- -- last one counts
- order = tonumber(detail) or 0
- elseif keyword == "penalty" then
- -- last one counts
- penalty = tonumber(detail) or 0
- elseif keyword == "skip" then
- -- last one counts
- command[#command+1] = { 1, tonumber(detail or 1) or 1}
+ local function analyse(str,category,order,penalty,command,fixed)
+ for s in gmatch(str,"([^ ,]+)") do
+ local amount, keyword, detail = splitter:match(s)
+ if keyword then
+ local mk = map[keyword]
+ if mk then
+ analyse(mk,category,order,penalty,command,fixed)
+ elseif keyword == "fixed" then
+ fixed = true
+ elseif keyword == "flexible" then
+ fixed = false
+ elseif keyword == "category" then
+ -- is a set
+ local n = tonumber(detail)
+ if n then
+ category[categories[n]] = true
else
- amount = tonumber(amount) or 1
- local sk = skip[keyword]
- if sk then
- command[#command+1] = { amount, sk[1], sk[2] or sk[1]}
- else -- no check
- command[#command+1] = { amount, keyword, keyword, keyword}
- end
+ category[detail] = true
end
+ elseif keyword == "order" then
+ -- last one counts
+ order = tonumber(detail) or 0
+ elseif keyword == "penalty" then
+ -- last one counts
+ penalty = tonumber(detail) or 0
+ elseif keyword == "skip" then
+ -- last one counts
+ command[#command+1] = { 1, tonumber(detail or 1) or 1}
else
- logs.report("vspacing","unknown directive: %s",str)
+ amount = tonumber(amount) or 1
+ local sk = skip[keyword]
+ if sk then
+ command[#command+1] = { amount, sk[1], sk[2] or sk[1]}
+ else -- no check
+ command[#command+1] = { amount, keyword, keyword, keyword}
+ end
end
+ else
+ logs.report("vspacing","unknown directive: %s",str)
end
end
- analyse(str)
+ end
+
+ local function logger(c,s)
+ logs.report("vspacing",s)
+ texsprint(c,s)
+ end
+
+ function vspacing.analyse(str)
+ local texsprint = (trace_vspacing and logger) or texsprint
+ local category, order, penalty, command, fixed = { }, 0, 0, { }, vspacing.fixed
+ analyse(str,category,order,penalty,command,fixed)
category = set.tonumber(category)
- local texsprint, ctxcatcodes = tex.sprint, tex.ctxcatcodes
- if vspacing.trace then
- -- quick and dirty
- texsprint = function(c,s)
- logs.report("vspacing",s)
- tex.sprint(c,s)
- end
- end
texsprint(ctxcatcodes,"\\startblankhandling")
if category > 0 then
- texsprint(ctxcatcodes,("\\setblankcategory{%s}"):format(category))
+ texsprint(ctxcatcodes,format("\\setblankcategory{%s}",category))
end
if order > 0 then
- texsprint(ctxcatcodes,("\\setblankorder{%s}"):format(order))
+ texsprint(ctxcatcodes,format("\\setblankorder{%s}",order))
end
if penalty > 0 then
- texsprint(ctxcatcodes,("\\setblankpenalty{%s}"):format(penalty))
+ texsprint(ctxcatcodes,format("\\setblankpenalty{%s}",penalty))
end
for i=1,#command do
local c = command[i]
- texsprint(ctxcatcodes,("\\addblankskip{%s}{%s}{%s}"):format(c[1],c[2],c[3] or c[2]))
+ texsprint(ctxcatcodes,format("\\addblankskip{%s}{%s}{%s}",c[1],c[2],c[3] or c[2]))
end
if fixed then
texsprint(ctxcatcodes,"\\fixedblankskip")
@@ -165,1488 +194,488 @@ function nodes.setsnapvalue(n,ht,dp)
nodes.snapvalues[n] = { ht, dp, ht+dp }
end
-do
-
- nodes.trace_vbox_spacing = false
- nodes.trace_page_spacing = false
+local trace_list, tracing_info, before, after = { }, false, "", ""
- local kern, glue, penalty, hlist = node.id('kern'), node.id('glue'), node.id('penalty'), node.id('hlist')
-
- local has_attribute = node.has_attribute
- local unset_attribute = node.unset_attribute
- local set_attribute = node.set_attribute
- local has_field = node.has_field
-
- local trace_list, tracing_info, before, after = { }, false, "", ""
-
- local function glue_to_string(glue)
- local spec = glue.spec
- if spec then
- local t = { }
- t[#t+1] = aux.strip_zeros(number.topoints(spec.width))
- if spec.stretch_order and spec.stretch_order ~= 0 then
- t[#t+1] = format("plus -%sfi%s",spec.stretch/65536,string.rep("l",math.abs(spec.stretch_order)-1))
- elseif spec.stretch and spec.stretch ~= 0 then
- t[#t+1] = format("plus %s",aux.strip_zeros(number.topoints(spec.stretch)))
- end
- if spec.shrink_order and spec.shrink_order ~= 0 then
- t[#t+1] = format("minus -%sfi%s",spec.shrink/65536,string.rep("l",math.abs(spec.shrink_order)-1))
- elseif spec.shrink and spec.shrink ~= 0 then
- t[#t+1] = format("minus %s",aux.strip_zeros(number.topoints(spec.shrink)))
- end
- return table.concat(t," ")
- else
- return "[0pt]"
- end
- end
- local function nodes_to_string(head)
- local current, t = head, { }
- while current do
- local id = current.id
- local ty = node.type(id)
- if id == penalty then
- t[#t+1] = format("%s:%s",ty,current.penalty)
- elseif id == glue then
- if current.spec then
- t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.spec.width)))
- else
- t[#t+1] = format("%s:[0pt]",ty)
- end
- elseif id == kern then
- t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.kern)))
- else
- t[#t+1] = ty
- end
- current = current.next
- end
- return table.concat(t," + ")
- end
- local function reset_tracing(head)
- trace_list, tracing_info, before, after = { }, false, nodes_to_string(head), ""
- end
- local function trace_skip(str,sc,so,sp,data)
- trace_list[#trace_list+1] = { "skip", ("%s | %s | category %s | order %s | penalty %s"):format(str, glue_to_string(data), sc or "-", so or "-", sp or "-") }
- tracing_info = true
- end
- local function trace_natural(str,data)
- trace_list[#trace_list+1] = { "skip", ("%s | %s"):format(str, glue_to_string(data)) }
- tracing_info = true
- end
- local function trace_info(message, where, what)
- trace_list[#trace_list+1] = { "info", format("%s: %s/%s",message,where,what) }
- end
- local function trace_node(what)
- local nt = node.type(what.id)
- local tl = trace_list[#trace_list]
- if tl[1] == "node" then
- trace_list[#trace_list] = { "node", tl[2] .. " + " .. nt }
- else
- trace_list[#trace_list+1] = { "node", nt }
+local function glue_to_string(glue)
+ local spec = glue.spec
+ if spec then
+ local t = { }
+ t[#t+1] = aux.strip_zeros(number.topoints(spec.width))
+ if spec.stretch_order and spec.stretch_order ~= 0 then
+ t[#t+1] = format("plus -%sfi%s",spec.stretch/65536,string.rep("l",math.abs(spec.stretch_order)-1))
+ elseif spec.stretch and spec.stretch ~= 0 then
+ t[#t+1] = format("plus %s",aux.strip_zeros(number.topoints(spec.stretch)))
end
- end
- local function trace_done(str,data)
- if data.id == penalty then
- trace_list[#trace_list+1] = { "penalty", ("%s | %s"):format(str, data.penalty) }
- else
- trace_list[#trace_list+1] = { "glue", ("%s | %s"):format(str, glue_to_string(data)) }
- end
- tracing_info = true
- end
- local function show_tracing(head)
- if tracing_info then
- after = nodes_to_string(head)
- for i=1,#trace_list do
- local tag, text = unpack(trace_list[i])
- if tag == "info" then
- logs.report("collapse",text)
- else
- logs.report("collapse"," %s: %s",tag,text)
- end
- end
- logs.report("collapse","before: %s",before)
- logs.report("collapse","after : %s",after)
+ if spec.shrink_order and spec.shrink_order ~= 0 then
+ t[#t+1] = format("minus -%sfi%s",spec.shrink/65536,string.rep("l",math.abs(spec.shrink_order)-1))
+ elseif spec.shrink and spec.shrink ~= 0 then
+ t[#t+1] = format("minus %s",aux.strip_zeros(number.topoints(spec.shrink)))
end
+ return concat(t," ")
+ else
+ return "[0pt]"
end
+end
- -- we assume that these are defined
-
- local skip_category = attributes.numbers['skip-category'] or 101
- local skip_penalty = attributes.numbers['skip-penalty'] or 102
- local skip_order = attributes.numbers['skip-order'] or 103
- local snap_category = attributes.numbers['snap-category'] or 111
- local display_math = attributes.numbers['display-math'] or 121
-
- -- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display
-
- local user_skip = 0
- local line_skip = 1
- local baseline_skip = 2
- local par_skip = 3
- local above_display_skip = 4
- local below_display_skip = 5
- local above_display_short_skip = 6
- local below_display_short_skip = 7
- local left_skip_code = 8
- local right_skip_code = 9
- local top_skip_code = 10
- local split_top_skip_code = 11
- local tab_skip_code = 12
- local space_skip_code = 13
- local xspace_skip_code = 14
- local par_fill_skip_code = 15
- local thin_mu_skip_code = 16
- local med_mu_skip_code = 17
- local thick_mu_skip_code = 18
-
- local skips = {
- [ 0] = "user_skip",
- [ 1] = "line_skip",
- [ 2] = "baseline_skip",
- [ 3] = "par_skip",
- [ 4] = "above_display_skip",
- [ 5] = "below_display_skip",
- [ 6] = "above_display_short_skip",
- [ 7] = "below_display_short_skip",
- [ 8] = "left_skip_code",
- [ 9] = "right_skip_code",
- [10] = "top_skip_code",
- [11] = "split_top_skip_code",
- [12] = "tab_skip_code",
- [13] = "space_skip_code",
- [14] = "xspace_skip_code",
- [15] = "par_fill_skip_code",
- [16] = "thin_mu_skip_code",
- [17] = "med_mu_skip_code",
- [18] = "thick_mu_skip_code",
- }
-
- function nodes.is_display_math(head)
- local n = head.prev
- while n do
- local id = n.id
- if id == penalty then
- elseif id == glue then
- if n.subtype == 6 then -- above_display_short_skip
- return true
- end
- else
- break
- end
- n = n.prev
- end
- n = head.next
- while n do
- local id = n.id
- if id == penalty then
- elseif id == glue then
- if n.subtype == 7 then -- below_display_short_skip
- return true
- end
+local function nodes_to_string(head)
+ local current, t = head, { }
+ while current do
+ local id = current.id
+ local ty = node.type(id)
+ if id == penalty then
+ t[#t+1] = format("%s:%s",ty,current.penalty)
+ elseif id == glue then
+ if current.spec then
+ t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.spec.width)))
else
- break
- end
- n = n.next
- end
- return false
- end
-
- local function collapser(head,where,what,trace,preceding)
- if head then
- input.starttiming(nodes)
- if trace then reset_tracing(head) end
- if trace then trace_info("start analyzing",where,what) end
- node.slide(head) -- hm, why
- local current, tail = head, nil
- local glue_order, glue_data = 0, nil
- local penalty_order, penalty_data, natural_penalty = 0, nil, nil
- local parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false
- while current do
- local id = current.id
- if id == glue and current.subtype == 0 then -- todo, other subtypes, like math
- local sc = has_attribute(current,skip_category)
- local so = has_attribute(current,skip_order)
- local sp = has_attribute(current,skip_penalty)
---~ if sc then unset_attribute(current,skip_category) end
---~ if so then unset_attribute(current,skip_order) end
---~ if sp then unset_attribute(current,skip_penalty) end
- so = so or 1
- if not sc then
- if glue_data then
- if trace then trace_done("flush",glue_data) end
- head, current = nodes.before(head,current,glue_data)
- if trace then trace_natural("natural",current) end
- else
- -- not look back across head
- local previous = current.prev
- if previous and previous.id == glue and previous.subtype == 0 then
- local ps = previous.spec
- if ps then
- local cs = current.spec
- if cs and ps.stretch_order == 0 and ps.shrink_order == 0 and cs.stretch_order == 0 and cs.shrink_order == 0 then
- local pw, pp, pm = ps.width, ps.stretch, ps.shrink
- local cw, cp, cm = cs.width, cs.stretch, cs.shrink
- ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm
- if trace then trace_natural("removed",current) end
- head, current = nodes.remove(head, current, true)
- current = previous
- if trace then trace_natural("collapsed",current) end
- else
- if trace then trace_natural("filler",current) end
- end
- else
- if trace then trace_natural("natural (no prev spec)",current) end
- end
- else
- if trace then trace_natural("natural (no prev)",current) end
- end
- end
- glue_order, glue_data = 0, nil
- if current then
- current = current.next
- end
- else
- local sct = vspacing.categories[sc] -- or 'unknown'
- if sct == 'disable' then
- ignore_following = true
- if trace then trace_skip(sct,sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- elseif sct == 'nowhite' then
- ignore_whitespace = true
- head, current = nodes.remove(head, current, true)
- elseif sct == 'discard' then
- if trace then trace_skip(sct,sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- else
- if sp then
- if not penalty_data then
- penalty_data = sp
- elseif penalty_order < so then
- penalty_order, penalty_data = so, sp
- elseif penalty_order == so and sp > penalty_data then
- penalty_data = sp
- end
- end
- if ignore_following then
- if trace then trace_skip("disabled",sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- elseif not glue_data then
- if trace then trace_skip("assign " .. sct,sc,so,sp,current) end
- glue_order = so
- head, current, glue_data = nodes.remove(head, current)
- elseif glue_order < so then
- if trace then trace_skip("force",sc,so,sp,current) end
- glue_order = so
- node.free(glue_data)
- head, current, glue_data = nodes.remove(head, current)
- elseif glue_order == so then
- if sct == 'largest' then
- local cs, gs = current.spec, glue_data.spec
- local cw = (cs and cs.width) or 0
- local gw = (gs and gs.width) or 0
- if cw > gw then
- if trace then trace_skip(sct,sc,so,sp,current) end
- node.free(glue_data) -- also free spec
- head, current, glue_data = nodes.remove(head, current)
- else
- if trace then trace_skip('remove smallest',sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- end
- elseif sct == 'goback' then
- if trace then trace_skip(sct,sc,so,sp,current) end
- node.free(glue_data) -- also free spec
- head, current, glue_data = nodes.remove(head, current)
- elseif sct == 'force' then
- -- todo: inject kern
- if trace then trace_skip(sct,sc,so,sp,current) end
- node.free(glue_data) -- also free spec
- head, current, glue_data = nodes.remove(head, current)
- elseif sct == 'penalty' then
- if trace then trace_skip(sct,sc,so,sp,current) end
- node.free(glue_data) -- also free spec
- head, current = nodes.remove(head, current, true)
- elseif sct == 'add' then
- if trace then trace_skip(sct,sc,so,sp,current) end
- local old, new = glue_data.spec, current.spec
- old.width = old.width + new.width
- old.stretch = old.stretch + new.stretch
- old.shrink = old.shrink + new.shrink
- -- toto: order
- head, current = nodes.remove(head, current, true)
- else
- if trace then trace_skip("unknown",sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- end
- else
- if trace then trace_skip("unknown",sc,so,sp,current) end
- head, current = nodes.remove(head, current, true)
- end
- end
- end
- elseif id == penalty then
---~ natural_penalty = current.penalty
---~ if trace then trace_done("removed penalty",current) end
---~ head, current = nodes.remove(head, current, true)
-current = current.next
- elseif id == glue and current.subtype == 2 then
- local sn = has_attribute(current,snap_category)
- if sn then
- -- local sv = nodes.snapvalues[sn]
- -- if sv then
- if trace then trace_natural("removed baselineskip",current) end
- head, current = nodes.remove(head, current, true)
- -- else
- -- current = current.next
- -- end
- else
- if trace then trace_natural("keep baselineskip",current) end
- current = current.next
- end
- elseif id == glue and current.subtype == 3 then
- -- parskip always comes later
- if ignore_whitespace then
- if trace then trace_natural("ignored parskip",current) end
- head, current = nodes.remove(head,current,true)
- elseif glue_data then
- local ps, gs = current.spec, glue_data.spec
- if ps and gs and ps.width > gs.width then
- node.free(glue_data.spec)
- glue_data.spec = ps
- if trace then trace_natural("taking parskip",current) end
- else
- if trace then trace_natural("removed parskip",current) end
- end
- head, current = nodes.remove(head, current,true)
- else
- if trace then trace_natural("honored parskip",current) end
- head, current, glue_data = nodes.remove(head, current)
- end
---~ if trace then trace_natural("removed parskip",current) end
---~ current.spec = nil
---~ current = current.next
- else
- if glue_data then
- if trace then trace_done("flushed",glue_data) end
- head, current = node.insert_before(head,current,glue_data)
- glue_order, glue_data = 0, nil
- end
- if penalty_data then
- local p = nodes.penalty(penalty_data)
- if trace then trace_done("flushed",p) end
- head, current = node.insert_before(head,current,p)
- penalty_data = nil
- end
- if trace then trace_node(current) end
- if id == hlist and where == 'hmode_par' then
- local list = current.list
- if list then
- local sn = has_attribute(list,snap_category)
- if sn then
- local sv = nodes.snapvalues[sn]
- if sv then
- local height, depth, lineheight = sv[1], sv[2], sv[3]
- current.height = math.ceil((current.height-height)/lineheight)*lineheight + height
- current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth
- end
- end
- end
- end
- current = current.next
- end
- end
- tail = node.slide(head)
- if trace then trace_info("stop analyzing",where,what) end
---~ if natural_penalty and (not penalty_data or natural_penalty > penalty_data) then
---~ penalty_data = natural_penalty
---~ end
- if trace and (glue_data or penalty_data) then trace_info("start flushing",where,what) end
- if penalty_data then
- local p = nodes.penalty(penalty_data)
- if trace then trace_done("result",p) end
- head, tail = node.insert_after(head,tail,p)
- end
- if glue_data then
- if trace then trace_done("result",glue_data) end
- head, tail = node.insert_after(head,tail,glue_data)
+ t[#t+1] = format("%s:[0pt]",ty)
end
- if trace and (glue_data or penalty_data) then trace_info("stop flushing",where,what) end
- input.stoptiming(nodes)
- if trace then show_tracing(head) end
+ elseif id == kern then
+ t[#t+1] = format("%s:%s",ty,aux.strip_zeros(number.topoints(current.kern)))
+ else
+ t[#t+1] = ty
end
- return head, true
- end
-
- -- alignment after_output end box new_graf vmode_par hmode_par insert penalty before_display after_display
-
- function nodes.handle_page_spacing(where) -- no arguments
- --~ status.best_page_break
- --~ tex.lists.best_page_break
- --~ tex.lists.best_size (natural size to best_page_break)
- --~ tex.lists.least_page_cost ( badness van best_page_break)
- --~ tex.lists.page_head
- --~ tex.lists.contrib_head
- local head, done= collapser(tex.lists.contrib_head,"page",where,nodes.trace_page_spacing,tex.lists.page_head)
- tex.lists.contrib_head = head
+ current = current.next
end
-
- -- split_keep, split_off, vbox
-
- local not_needed = table.tohash {
- "split_keep",
- "split_off",
- }
-
- function nodes.handle_vbox_spacing(t,where)
- return (t and not not_needed[where] and t.next and collapser(t,"vbox",where,nodes.trace_vbox_spacing)) or t
- end
-
+ return concat(t," + ")
end
--- experimental callback definitions will be moved elsewhere
---
--- this will become a chain
-
-function vspacing.enable()
---~ callback.register('vpack_filter', nodes.handle_vbox_spacing)
- callback.register('buildpage_filter', nodes.handle_page_spacing)
+local function reset_tracing(head)
+ trace_list, tracing_info, before, after = { }, false, nodes_to_string(head), ""
end
-function vspacing.disable()
- callback.register('vpack_filter', nil)
- callback.register('buildpage_filter', nil)
-end
-
--- horizontal stuff
--- probably a has_glyphs is rather fast too
-
-do -- maybe just share these locals
-
- local has_attribute = node.has_attribute
- local unset_attribute = node.unset_attribute
- local set_attribute = node.set_attribute
- local traverse_id = node.traverse_id
-
---~ local function unset_attribute(n,attribute)
---~ set_attribute(n,attribute,0)
---~ end
-
- local glyph = node.id("glyph")
- local whatsit = node.id("whatsit")
- local penalty = node.id("penalty")
- local kern = node.id("kern")
- local disc = node.id('disc')
- local glue = node.id('glue')
- local hlist = node.id('hlist')
- local vlist = node.id('vlist')
-
- spacings = spacings or { }
- spacings.mapping = spacings.mapping or { }
- spacings.enabled = false
-
- input.storage.register(false,"spacings/mapping", spacings.mapping, "spacings.mapping")
+local function trace_skip(str,sc,so,sp,data)
+ trace_list[#trace_list+1] = { "skip", format("%s | %s | category %s | order %s | penalty %s", str, glue_to_string(data), sc or "-", so or "-", sp or "-") }
+ tracing_info = true
+end
- function spacings.setspacing(id,char,left,right,alternative)
- local mapping = spacings.mapping[id]
- if not mapping then
- mapping = { }
- spacings.mapping[id] = mapping
- end
- local map = mapping[char]
- if not map then
- map = { }
- mapping[char] = map
- end
- map.left, map.right, map.alternative = left, right, alternative
- end
+local function trace_natural(str,data)
+ trace_list[#trace_list+1] = { "skip", format("%s | %s", str, glue_to_string(data)) }
+ tracing_info = true
+end
- -- todo: no ligatures
+local function trace_info(message, where, what)
+ trace_list[#trace_list+1] = { "info", format("%s: %s/%s",message,where,what) }
+end
- function nodes.somespace(n,all)
- if n then
- local id = n.id
- if id == glue then
- return (all or (n.spec.width ~= 0)) and glue
- elseif id == kern then
- return (all or (n.kern ~= 0)) and kern
- elseif id == glyph then
- local category = characters.data[n.char].category
- -- maybe more category checks are needed
- return (category == "zs") and glyph
- end
- end
- return false
+local function trace_node(what)
+ local nt = node.type(what.id)
+ local tl = trace_list[#trace_list]
+ if tl[1] == "node" then
+ trace_list[#trace_list] = { "node", tl[2] .. " + " .. nt }
+ else
+ trace_list[#trace_list+1] = { "node", nt }
end
+end
- function nodes.somepenalty(n,value)
- if n then
- local id = n.id
- if id == penalty then
- if value then
- return n.penalty == value
- else
- return true
- end
- end
- end
- return false
+local function trace_done(str,data)
+ if data.id == penalty then
+ trace_list[#trace_list+1] = { "penalty", format("%s | %s", str, data.penalty) }
+ else
+ trace_list[#trace_list+1] = { "glue", format("%s | %s", str, glue_to_string(data)) }
end
+ tracing_info = true
+end
- spacings.trace = false
-
- function spacings.process(namespace,attribute,head)
- local done, mapping, fontids = false, spacings.mapping, fonts.tfm.id
- local start = head
- -- head is always begin of par (whatsit), so we have at least two prev nodes
- -- penalty followed by glue
- while start do
- if start.id == glyph then
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- local map = mapping[attr]
- if map then
- map = map[start.char]
- unset_attribute(start,attribute)
- if map then
- local trace = spacings.trace
- local left, right, alternative = map.left, map.right, map.alternative
- local quad = fontids[start.font].parameters.quad
- local prev = start.prev
- if left and left ~= 0 and prev then
- local ok = false
- if alternative == 1 then
- local somespace = nodes.somespace(prev,true)
- if somespace then
- local prevprev = prev.prev
- local somepenalty = nodes.somepenalty(prevprev,10000)
- if somepenalty then
- if trace then
- logs.report("spacing","removing penalty and space before %s", utfchar(start.char))
- end
- head, _ = nodes.remove(head,prev,true)
- head, _ = nodes.remove(head,prevprev,true)
- else
- local somespace = nodes.somespace(prev,true)
- if somespace then
- if trace then
- logs.report("spacing","removing space before %s", utfchar(start.char))
- end
- head, _ = nodes.remove(head,prev,true)
- end
- end
- end
- ok = true
- else
- ok = not (nodes.somespace(prev,true) and nodes.somepenalty(prev.prev,true)) or nodes.somespace(prev,true)
- end
- if ok then
- if trace then
- logs.report("spacing","inserting penalty and space before %s", utfchar(start.char))
- end
- node.insert_before(head,start,nodes.penalty(10000))
- node.insert_before(head,start,nodes.glue(tex.scale(quad,left)))
- done = true
- end
- end
- local next = start.next
- if right and right ~= 0 and next then
- local ok = false
- if alternative == 1 then
- local somepenalty = nodes.somepenalty(next,10000)
- if somepenalty then
- local nextnext = next.next
- local somespace = nodes.somespace(nextnext,true)
- if somespace then
- if trace then
- logs.report("spacing","removing penalty and space after %s", utfchar(start.char))
- end
- head, _ = nodes.remove(head,next,true)
- head, _ = nodes.remove(head,nextnext,true)
- end
- else
- local somespace = nodes.somespace(next,true)
- if somespace then
- if trace then
- logs.report("spacing","removing space after %s", utfchar(start.char))
- end
- head, _ = nodes.remove(head,next,true)
- end
- end
- ok = true
- else
- ok = not (nodes.somepenalty(next,10000) and nodes.somespace(next.next,true)) or nodes.somespace(next,true)
- end
- if ok then
- if trace then
- logs.report("spacing","inserting penalty and space after %s", utfchar(start.char))
- end
- node.insert_after(head,start,nodes.glue(tex.scale(quad,right)))
- node.insert_after(head,start,nodes.penalty(10000))
- done = true
- end
- end
- end
- end
- end
+local function show_tracing(head)
+ if tracing_info then
+ after = nodes_to_string(head)
+ for i=1,#trace_list do
+ local tag, text = unpack(trace_list[i])
+ if tag == "info" then
+ logs.report("collapse",text)
+ else
+ logs.report("collapse"," %s: %s",tag,text)
end
- start = start.next
end
- return head, done
- end
-
- lists.handle_spacing = nodes.install_attribute_handler {
- name = "spacing",
- namespace = spacings,
- processor = spacings.process,
- }
-
- kerns = kerns or { }
- kerns.mapping = kerns.mapping or { }
- kerns.enabled = false
-
- input.storage.register(false, "kerns/mapping", kerns.mapping, "kerns.mapping")
-
- function kerns.setspacing(id,factor)
- kerns.mapping[id] = factor
+ logs.report("collapse","before: %s",before)
+ logs.report("collapse","after : %s",after)
end
+end
- -- local marks = fti[font].shared.otfdata.luatex.marks
- -- if not marks[tchar] then
-
- -- todo: use node.* functions
+-- we assume that these are defined
+
+local skip_category = attributes.private('skip-category')
+local skip_penalty = attributes.private('skip-penalty')
+local skip_order = attributes.private('skip-order')
+local snap_category = attributes.private('snap-category')
+local display_math = attributes.private('display-math')
+
+-- alignment box begin_of_par vmode_par hmode_par insert penalty before_display after_display
+
+local user_skip = 0
+local line_skip = 1
+local baseline_skip = 2
+local par_skip = 3
+local above_display_skip = 4
+local below_display_skip = 5
+local above_display_short_skip = 6
+local below_display_short_skip = 7
+local left_skip_code = 8
+local right_skip_code = 9
+local top_skip_code = 10
+local split_top_skip_code = 11
+local tab_skip_code = 12
+local space_skip_code = 13
+local xspace_skip_code = 14
+local par_fill_skip_code = 15
+local thin_mu_skip_code = 16
+local med_mu_skip_code = 17
+local thick_mu_skip_code = 18
+
+local skips = {
+ [ 0] = "user_skip",
+ [ 1] = "line_skip",
+ [ 2] = "baseline_skip",
+ [ 3] = "par_skip",
+ [ 4] = "above_display_skip",
+ [ 5] = "below_display_skip",
+ [ 6] = "above_display_short_skip",
+ [ 7] = "below_display_short_skip",
+ [ 8] = "left_skip_code",
+ [ 9] = "right_skip_code",
+ [10] = "top_skip_code",
+ [11] = "split_top_skip_code",
+ [12] = "tab_skip_code",
+ [13] = "space_skip_code",
+ [14] = "xspace_skip_code",
+ [15] = "par_fill_skip_code",
+ [16] = "thin_mu_skip_code",
+ [17] = "med_mu_skip_code",
+ [18] = "thick_mu_skip_code",
+}
- function kerns.process(namespace,attribute,head) -- todo interchar kerns / disc nodes / can be made faster
- local fti, scale = fonts.tfm.id, tex.scale
- local start, done, mapping, fontids, lastfont = head, false, kerns.mapping, fonts.tfm.id, nil
- while start do
- -- faster to test for attr first
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- unset_attribute(start,attribute)
- local krn = mapping[attr]
- if krn and krn ~= 0 then
- local id = start.id
- if id == glyph then
- lastfont = start.font
- local c = start.components
- if c then
- local s = start
- local tail = node.slide(c)
- if s.prev then
- s.prev.next = c
- c.prev = s.prev
+local free_glue_node = free_node
+local free_glue_spec = free_node
+--~ local free_glue_node = function(n) free_node(n) end
+--~ local free_glue_spec = function(n) end
+
+local function collapser(head,where,what,trace) -- maybe also pass tail
+ if trace then
+ reset_tracing(head)
+ trace_info("start analyzing",where,what)
+ end
+ local current = head
+ local glue_order, glue_data = 0, nil
+ local penalty_order, penalty_data, natural_penalty = 0, nil, nil
+ local parskip, ignore_parskip, ignore_following, ignore_whitespace = nil, false, false, false
+ while current do
+ local id = current.id
+ if id == glue and current.subtype == 0 then -- todo, other subtypes, like math
+ local sc = has_attribute(current,skip_category) -- has no default, no unset (yet)
+ local so = has_attribute(current,skip_order ) or 1 -- has 1 default, no unset (yet)
+ local sp = has_attribute(current,skip_penalty ) -- has no degault, no unset (yet)
+ if not sc then
+ if glue_data then
+ if trace then trace_done("flush",glue_data) end
+ head, current = nodes.before(head,current,glue_data)
+ if trace then trace_natural("natural",current) end
+ else
+ -- not look back across head
+ local previous = current.prev
+ if previous and previous.id == glue and previous.subtype == 0 then
+ local ps = previous.spec
+ if ps then
+ local cs = current.spec
+ if cs and ps.stretch_order == 0 and ps.shrink_order == 0 and cs.stretch_order == 0 and cs.shrink_order == 0 then
+ local pw, pp, pm = ps.width, ps.stretch, ps.shrink
+ local cw, cp, cm = cs.width, cs.stretch, cs.shrink
+ ps.width, ps.stretch, ps.shrink = pw + cw, pp + cp, pm + cm
+ if trace then trace_natural("removed",current) end
+ head, current = remove_node(head, current, true)
+ current = previous
+ if trace then trace_natural("collapsed",current) end
else
- head = c
- end
- if s.next then
- s.next.prev = tail
- end
- tail.next = s.next
- start = c
- start.attr = s.attr
- s.attr = nil
- s.components = nil
- node.free(s)
- done = true
- end
- local prev = start.prev
- if prev then
- local pid = prev.id
- if not pid then
- -- nothing
- elseif pid == kern and prev.subtype == 0 then
- prev.subtype = 1
- prev.kern = prev.kern + scale(fontids[lastfont].parameters.quad,krn)
- done = true
- elseif pid == glyph then
- -- fontdata access can be done more efficient
- if prev.font == lastfont then
- local prevchar, lastchar = prev.char, start.char
- local tfm = fti[lastfont].characters[prevchar]
- local ickern = tfm.kerns
- if ickern and ickern[lastchar] then
- krn = scale(ickern[lastchar]+fontids[lastfont].parameters.quad,krn)
- else
- krn = scale(fontids[lastfont].parameters.quad,krn)
- end
- else
- krn = scale(fontids[lastfont].parameters.quad,krn)
- end
- node.insert_before(head,start,nodes.kern(krn))
- done = true
- elseif pid == disc then
- local disc = start.prev -- disc
- local pre, post, replace = disc.pre, disc.post, disc.replace
- if pre then -- must pair with start.prev
- local before = node.copy(disc.prev)
- pre.prev = before
- before.next = pre
- before.prev = nil
- pre = kerns.process(namespace,attribute,before)
- pre = pre.next
- pre.prev = nil
- disc.pre = pre
- node.free(before)
- end
- if post then -- must pair with start
- local after = node.copy(disc.next)
- local tail = node.slide(post)
- tail.next = after
- after.prev = tail
- after.next = nil
- post = kerns.process(namespace,attribute,post)
- tail.next = nil
- disc.post = post
- node.free(after)
- end
- if replace then -- must pair with start and start.prev
- local before = node.copy(disc.prev)
- local after = node.copy(disc.next)
- local tail = node.slide(post)
- replace.prev = before
- before.next = replace
- before.prev = nil
- tail.next = after
- after.prev = tail
- after.next = nil
- replace = kerns.process(namespace,attribute,before)
- replace = replace.next
- replace.prev = nil
- tail.next = nil
- disc.replace = replace
- node.free(after)
- node.free(before)
- end
+ if trace then trace_natural("filler",current) end
end
+ else
+ if trace then trace_natural("natural (no prev spec)",current) end
end
- elseif id == glue and start.subtype == 0 then
- local s = start.spec
- local w = s.width
- if w > 0 then
- local width, stretch, shrink = w+2*scale(w,krn), s.stretch, s.shrink
- start.spec = nodes.glue_spec(width,scale(stretch,width/w),scale(shrink,width/w))
- -- local width, stretch, shrink = w+2*w*krn, s.stretch, s.shrink
- -- start.spec = nodes.glue_spec(width,stretch*width/w,shrink*width/w))
- done = true
- end
- elseif false and id == kern and start.subtype == 0 then -- handle with glyphs
- local sk = start.kern
- if sk > 0 then
- -- start.kern = scale(sk,krn)
- start.kern = sk*krn
- done = true
- end
- elseif lastfont and (id == hlist or id == vlist) then -- todo: lookahead
- if start.prev then
- node.insert_before(head,start,nodes.kern(scale(fontids[lastfont].parameters.quad,krn)))
- done = true
- end
- if start.next then
- node.insert_after(head,start,nodes.kern(scale(fontids[lastfont].parameters.quad,krn)))
- done = true
- end
- end
- end
- end
- if start then
- start = start.next
- end
- end
- return head, done
- end
-
- lists.handle_kerning = nodes.install_attribute_handler {
- name = "kern",
- namespace = kerns,
- processor = kerns.process,
- }
-
- -- spacing == attributename !! does not belong here but we will
- -- relocate node and attribute stuff once it's more complete !!
-
- -- experimental, we may extend or change this
-
- --~ Analysis by Idris:
- --~
- --~ 1. Assuming the reading- vs word-order distinction (bidi-char types) is governing;
- --~ 2. Assuming that 'ARAB' represents an actual arabic string in raw input order, not word-order;
- --~ 3. Assuming that 'BARA' represent the correct RL word order;
- --~
- --~ Then we have, with input: LATIN ARAB
- --~
- --~ \textdir TLT LATIN ARAB => LATIN BARA
- --~ \textdir TRT LATIN ARAB => LATIN BARA
- --~ \textdir TRT LRO LATIN ARAB => LATIN ARAB
- --~ \textdir TLT LRO LATIN ARAB => LATIN ARAB
- --~ \textdir TLT RLO LATIN ARAB => NITAL ARAB
- --~ \textdir TRT RLO LATIN ARAB => NITAL ARAB
-
- -- elseif d == "es" then -- European Number Separator
- -- elseif d == "et" then -- European Number Terminator
- -- elseif d == "cs" then -- Common Number Separator
- -- elseif d == "nsm" then -- Non-Spacing Mark
- -- elseif d == "bn" then -- Boundary Neutral
- -- elseif d == "b" then -- Paragraph Separator
- -- elseif d == "s" then -- Segment Separator
- -- elseif d == "ws" then -- Whitespace
- -- elseif d == "on" then -- Other Neutrals
-
- mirror = mirror or { }
- mirror.enabled = false
- mirror.trace = false
- mirror.strip = false
-
- local state = attributes.numbers['state'] or 100
-
- function mirror.process(namespace,attribute,head)
- local done, data, directions, trace = false, characters.data, characters.directions, mirror.trace
- local current, inserted, obsolete = head, nil, { }
- local override, embedded, autodir = 0, 0, 0
- local list, glyphs = trace and { }, false
- local stack, top, finished, finidir, finipos = { }, 0, nil, nil, 1
- local finish = nil
- local lro, rlo, prevattr = false, false, 0
- -- todo: delayed inserts here
- local function finish_auto_before()
- head, inserted = node.insert_before(head,current,nodes.textdir("-"..finish))
- finished, finidir = inserted, finish
- if trace then insert(list,#list,format("finish %s",finish)) ; finipos = #list-1 end
- finish, autodir, done = nil, 0, true
- end
- local function finish_auto_after()
- head, current = node.insert_after(head,current,nodes.textdir("-"..finish))
- finished, finidir = current, finish
- if trace then list[#list+1] = format("finish %s",finish) ; finipos = #list end
- finish, autodir, done = nil, 0, true
- end
- local function force_auto_left_before()
- if finish then
- finish_auto_before()
- end
- if embedded >= 0 then
- finish, autodir, done = "TLT", 1, true
- else
- finish, autodir, done = "TRT", -1, true
- end
- if finidir == finish then
- nodes.remove(head,finished,true)
- if trace then list[finipos] = list[finipos].." (deleted)" end
- if trace then insert(list,#list,format("start %s (deleted)",finish)) end
- else
- head, inserted = node.insert_before(head,current,nodes.textdir("+"..finish))
- if trace then insert(list,#list,format("start %s",finish)) end
- end
- end
- local function force_auto_right_before()
- if finish then
- finish_auto_before()
- end
- if embedded <= 0 then
- finish, autodir, done = "TRT", -1, true
- else
- finish, autodir, done = "TLT", 1, true
- end
- if finidir == finish then
- nodes.remove(head,finished,true)
- if trace then list[finipos] = list[finipos].." (deleted)" end
- if trace then insert(list,#list,format("start %s (deleted)",finish)) end
- else
- head, inserted = node.insert_before(head,current,nodes.textdir("+"..finish))
- if trace then insert(list,#list,format("start %s",finish)) end
- end
- end
- local function is_right(n)
- if n then
- local id = n.id
- if id == glyph then
- local attr = has_attribute(n,attribute)
- if attr and attr > 0 then
- local d = directions[n.char]
- if d == "r" or d == "al" then -- override
- return true
- end
- end
- end
- end
- return false
- end
- while current do
- local id = current.id
- local attr = has_attribute(current,attribute)
- if attr and attr > 0 then
- unset_attribute(current,attribute)
- if attr == 1 then
- -- bidi parsing mode
- elseif attr ~= prevattr then
- -- no pop, grouped driven (2=normal,3=lro,4=rlo)
- if attr == 3 then
- if trace then list[#list+1] = format("override right -> left (lro) (bidi=%s)",attr) end
- lro, rlo = true, false
- elseif attr == 4 then
- if trace then list[#list+1] = format("override left -> right (rlo) (bidi=%s)",attr) end
- lro, rlo = false, true
else
- if trace and current ~= head then list[#list+1] = format("override reset (bidi=%s)",attr) end
- lro, rlo = false, false
+ if trace then trace_natural("natural (no prev)",current) end
end
- prevattr = attr
end
- end
- if id == glyph then
- glyphs = true
- if attr and attr > 0 then
- local char = current.char
- local d = directions[char]
- if rlo or override > 0 then
- if d == "l" then
- if trace then list[#list+1] = format("char %s of class %s overidden to r (bidi=%s)",utf.char(char),d,attr) end
- d = "r"
- elseif trace then
- if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
- list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
- else -- todo: rle lre
- list[#list+1] = format("char %s of class %s (bidi=%s)",utf.char(char),d,attr)
- end
- end
- elseif lro or override < 0 then
- if d == "r" or d == "al" then
- set_attribute(current,state,4) -- maybe better have a special bidi attr value -> override (9) -> todo
- if trace then list[#list+1] = format("char %s of class %s overidden to l (bidi=%s) (state=isol)",utf.char(char),d,attr) end
- d = "l"
- elseif trace then
- if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
- list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
- else -- todo: rle lre
- list[#list+1] = format("char %s of class %s (bidi=%s)",utf.char(char),d,attr)
- end
- end
- elseif trace then
- if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
- list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
- else -- todo: rle lre
- list[#list+1] = format("char %s of class %s (bidi=%s)",utf.char(char),d,attr)
+ glue_order, glue_data = 0, nil
+ if current then
+ current = current.next
+ end
+ else
+ local sct = categories[sc] -- or 'unknown'
+ if sct == 'disable' then
+ ignore_following = true
+ if trace then trace_skip(sct,sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
+ elseif sct == 'nowhite' then
+ ignore_whitespace = true
+ head, current = remove_node(head, current, true)
+ elseif sct == 'discard' then
+ if trace then trace_skip(sct,sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
+ else
+ if sp then
+ if not penalty_data then
+ penalty_data = sp
+ elseif penalty_order < so then
+ penalty_order, penalty_data = so, sp
+ elseif penalty_order == so and sp > penalty_data then
+ penalty_data = sp
end
end
- if d == "on" then
- local mirror = data[char].mirror
- if mirror and fonts.tfm.id[current.font].characters[mirror] then
- -- todo: set attribute
- if autodir < 0 then
- current.char = mirror
- done = true
- --~ elseif left or autodir > 0 then
- --~ if not is_right(current.prev) then
- --~ current.char = mirror
- --~ done = true
- --~ end
+ if ignore_following then
+ if trace then trace_skip("disabled",sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
+ elseif not glue_data then
+ if trace then trace_skip("assign " .. sct,sc,so,sp,current) end
+ glue_order = so
+ head, current, glue_data = remove_node(head, current)
+ elseif glue_order < so then
+ if trace then trace_skip("force",sc,so,sp,current) end
+ glue_order = so
+ free_glue_node(glue_data)
+ head, current, glue_data = remove_node(head, current)
+ elseif glue_order == so then
+ if sct == 'largest' then
+ local cs, gs = current.spec, glue_data.spec
+ local cw = (cs and cs.width) or 0
+ local gw = (gs and gs.width) or 0
+ if cw > gw then
+ if trace then trace_skip('largest',sc,so,sp,current) end
+ free_glue_node(glue_data) -- also free spec
+ head, current, glue_data = remove_node(head, current)
+ else
+ if trace then trace_skip('remove smallest',sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
end
- end
- elseif d == "l" or d == "en" then -- european number
- if autodir <= 0 then
- force_auto_left_before()
- end
- elseif d == "r" or d == "al" or d == "an" then -- arabic left, arabic number
- if autodir >= 0 then
- force_auto_right_before()
- end
- elseif d == "lro" then -- Left-to-Right Override -> right becomes left
- if trace then list[#list+1] = "override right -> left" end
- top = top + 1
- stack[top] = { override, embedded }
- override = -1
- obsolete[#obsolete+1] = current
- elseif d == "rlo" then -- Right-to-Left Override -> left becomes right
- if trace then list[#list+1] = "override left -> right" end
- top = top + 1
- stack[top] = { override, embedded }
- override = 1
- obsolete[#obsolete+1] = current
- elseif d == "lre" then -- Left-to-Right Embedding -> TLT
- if trace then list[#list+1] = "embedding left -> right" end
- top = top + 1
- stack[top] = { override, embedded }
- embedded = 1
- obsolete[#obsolete+1] = current
- elseif d == "rle" then -- Right-to-Left Embedding -> TRT
- if trace then list[#list+1] = "embedding right -> left" end
- top = top + 1
- stack[top] = { override, embedded }
- embedded = 1
- obsolete[#obsolete+1] = current
- elseif d == "pdf" then -- Pop Directional Format
- -- override = 0
- if top > 0 then
- local s = stack[top]
- override, embedded = s[1], s[2]
- top = top - 1
- if trace then list[#list+1] = format("state: override: %s, embedded: %s, autodir: %s",override,embedded,autodir) end
- else
- if trace then list[#list+1] = "pop (error, too many pops)" end
- end
- obsolete[#obsolete+1] = current
- end
- else
- if trace then
- local char = current.char
- local d = directions[char]
- list[#list+1] = format("char %s of class %s (no bidi)",utf.char(char),d)
- end
- end
- elseif id == whatsit then
- if finish then
- finish_auto_before()
- end
- local subtype = current.subtype
- if subtype == 6 then
- local dir = current.dir
- local d = dir:sub(2,2)
- if dir:find(".R.") then
- autodir = -1
- else
- autodir = 1
- end
- embeddded = autodir
- if trace then list[#list+1] = format("pardir %s",dir) end
- elseif subtype == 7 then
- local dir = current.dir
- local sign = dir:sub(1,1)
- local dire = dir:sub(3,3)
- if dire == "R" then
- if sign == "+" then
- finish, autodir = "TRT", -1
+ elseif sct == 'goback' then
+ if trace then trace_skip('goback',sc,so,sp,current) end
+ free_glue_node(glue_data) -- also free spec
+ head, current, glue_data = remove_node(head, current)
+ elseif sct == 'force' then
+ -- todo: inject kern
+ if trace then trace_skip('force',sc,so,sp,current) end
+ free_glue_node(glue_data) -- also free spec
+ head, current, glue_data = remove_node(head, current)
+ elseif sct == 'penalty' then
+ if trace then trace_skip('penalty',sc,so,sp,current) end
+ free_glue_node(glue_data) -- also free spec
+ glue_data = nil
+ head, current = remove_node(head, current, true)
+ elseif sct == 'add' then
+ if trace then trace_skip('add',sc,so,sp,current) end
+ local old, new = glue_data.spec, current.spec
+ old.width = old.width + new.width
+ old.stretch = old.stretch + new.stretch
+ old.shrink = old.shrink + new.shrink
+ -- toto: order
+ head, current = remove_node(head, current, true)
else
- finish, autodir = nil, 0
+ if trace then trace_skip("unknown",sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
end
else
- if sign == "+" then
- finish, autodir = "TLT", 1
- else
- finish, autodir = nil, 0
- end
+ if trace then trace_skip("unknown",sc,so,sp,current) end
+ head, current = remove_node(head, current, true)
end
- if trace then list[#list+1] = format("textdir %s",dir) end
- end
- else
- if trace then list[#list+1] = format("node %s",node.type(id)) end
- if finish then
- finish_auto_before()
end
end
- local cn = current.next
- if not cn then
- if finish then
- finish_auto_after()
+ elseif id == penalty then
+ --~ natural_penalty = current.penalty
+ --~ if trace then trace_done("removed penalty",current) end
+ --~ head, current = remove_node(head, current, true)
+ current = current.next
+ elseif id == glue and current.subtype == 2 then
+ local sn = has_attribute(current,snap_category)
+ if sn then
+ -- local sv = nodes.snapvalues[sn]
+ -- if sv then
+ if trace then trace_natural("removed baselineskip",current) end
+ head, current = remove_node(head, current, true)
+ -- else
+ -- current = current.next
+ -- end
+ else
+ if trace then trace_natural("keep baselineskip",current) end
+ current = current.next
+ end
+ elseif id == glue and current.subtype == 3 then
+ -- parskip always comes later
+ if ignore_whitespace then
+ if trace then trace_natural("ignored parskip",current) end
+ head, current = remove_node(head,current,true)
+ elseif glue_data then
+ local ps, gs = current.spec, glue_data.spec
+ if ps and gs and ps.width > gs.width then
+ -- free_glue_spec(glue_data.spec) -- result in double free
+ glue_data.spec = copy_node(ps)
+ if trace then trace_natural("taking parskip",current) end
+ else
+ if trace then trace_natural("removed parskip",current) end
end
+ head, current = remove_node(head, current,true)
+ else
+ if trace then trace_natural("honored parskip",current) end
+ head, current, glue_data = remove_node(head, current)
end
- current = cn
- end
- if trace and glyphs then
- logs.report("bidi","start log")
- for i=1,#list do
- logs.report("bidi","%02i: %s",i,list[i])
- end
- logs.report("bidi","stop log")
- end
- if done and mirror.strip then
- local n = #obsolete
- if n > 0 then
- for i=1,n do
- nodes.remove(head,obsolete[i],true)
- end
- logs.report("bidi","%s character nodes removed",n)
+ --~ if trace then trace_natural("removed parskip",current) end
+ --~ current.spec = nil
+ --~ current = current.next
+ else
+ if glue_data then
+ if trace then trace_done("flushed",glue_data) end
+ head, current = insert_node_before(head,current,glue_data)
+ glue_order, glue_data = 0, nil
end
- end
- return head, done
- end
-
- chars.handle_mirroring = nodes.install_attribute_handler {
- name = "mirror",
- namespace = mirror,
- processor = mirror.process,
- }
-
- cases = cases or { }
- cases.enabled = false
- cases.actions = { }
-
- local function helper(start, code, codes)
- local data, char = characters.data, start.char
- local dc = data[char]
- if dc then
- local fnt = start.font
- local ifc = fonts.tfm.id[fnt].characters
- local ucs = dc[codes]
- if ucs then
- local ok = true
- for i=1,#ucs do
- ok = ok and ifc[ucs[i]]
- end
- if ok then
- local prev, original, copy = start, start, node.copy
- for i=1,#ucs do
- local chr = ucs[i]
- prev = start
- if i == 1 then
- start.char = chr
- else
- local g = copy(original)
- g.char = chr
- local next = start.next
- g.prev = start
- if next then
- g.next = next
- start.next = g
- next.prev = g
- end
- start = g
+ if penalty_data then
+ local p = make_penalty_node(penalty_data)
+ if trace then trace_done("flushed",p) end
+ head, current = insert_node_before(head,current,p)
+ penalty_data = nil
+ end
+ if trace then trace_node(current) end
+ if id == hlist and where == 'hmode_par' then
+ local list = current.list
+ if list then
+ local sn = has_attribute(list,snap_category)
+ if sn then
+ local sv = nodes.snapvalues[sn]
+ if sv then
+ local height, depth, lineheight = sv[1], sv[2], sv[3]
+ -- is math.ceil really needed?
+ current.height = math.ceil((current.height-height)/lineheight)*lineheight + height
+ current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth
end
end
- return prev, true
end
- return start, false
- end
- local uc = dc[code]
- if uc and ifc[uc] then
- start.char = uc
- return start, true
end
+ current = current.next
end
- return start, false
end
-
- local function upper(start)
- return helper(start,'uccode','uccodes')
+ local tail = slide_node_list(head) -- still needed, check previous code ?
+ if trace then trace_info("stop analyzing",where,what) end
+ --~ if natural_penalty and (not penalty_data or natural_penalty > penalty_data) then
+ --~ penalty_data = natural_penalty
+ --~ end
+ if trace and (glue_data or penalty_data) then
+ trace_info("start flushing",where,what)
end
- local function lower(start)
- return helper(start,'lccode','lccodes')
+ if penalty_data then
+ local p = make_penalty_node(penalty_data)
+ if trace then trace_done("result",p) end
+ head, tail = insert_node_after(head,tail,p)
end
-
- cases.actions[1], cases.actions[2] = upper, lower
-
- cases.actions[3] = function(start,attribute)
- local prev = start.prev
- if prev and prev.id == kern and prev.subtype == 0 then
- prev = prev.prev
- end
- if not prev or prev.id ~= glyph then
- --- only the first character is treated
- for n in traverse_id(glyph,start.next) do
- if has_attribute(n,attribute) then
- unset_attribute(n,attribute)
- end
- end
- return upper(start)
- else
- return start, false
- end
+ if glue_data then
+ if trace then trace_done("result",glue_data) end
+ head, tail = insert_node_after(head,tail,glue_data)
end
-
- cases.actions[4] = function(start,attribute)
- local prev = start.prev
- if prev and prev.id == kern and prev.subtype == 0 then
- prev = prev.prev
- end
- if not prev or prev.id ~= glyph then
- return upper(start)
- else
- return start, false
+ if trace then
+ if glue_data or penalty_data then
+ trace_info("stop flushing",where,what)
end
+ show_tracing(head)
end
+ return head, true
+end
+
+-- alignment after_output end box new_graf vmode_par hmode_par insert penalty before_display after_display
+-- \par -> vmode_par
+--
+-- status.best_page_break
+-- tex.lists.best_page_break
+-- tex.lists.best_size (natural size to best_page_break)
+-- tex.lists.least_page_cost (badness of best_page_break)
+-- tex.lists.page_head
+-- tex.lists.contrib_head
+
+local stackhead, stacktail, stackhack = nil, nil, false
- -- cases.actions[5] = function(start)
- -- local prev, next = start.prev, start.next
- -- if prev and prev.id == kern and prev.subtype == 0 then
- -- prev = prev.prev
- -- end
- -- if next and next.id == kern and next.subtype == 0 then
- -- next = next.next
- -- end
- -- if (not prev or prev.id ~= glyph) and next and next.id == glyph then
- -- return upper(start)
- -- else
- -- return start, false
- -- end
- -- end
+local function report(message,lst)
+ logs.report("vspacing",message,count_nodes(lst,true),node_ids_to_string(lst))
+end
- cases.actions[8] = function(start)
- local data = characters.data
- local ch = start.char
- local mr = math.random
- local tfm = fonts.tfm.id[start.font].characters
- if data[ch].lccode then
- while true do
- local d = data[mr(1,0xFFFF)]
- if d then
- local uc = d.uccode
- if uc and tfm[uc] then
- start.char = uc
- return start, true
+function nodes.handle_page_spacing(where)
+ local newhead = texlists.contrib_head
+ if newhead then
+ statistics.starttiming(vspacing)
+ local newtail = slide_node_list(newhead)
+ local flush = false
+ for n in traverse_nodes(newhead) do
+ local id = n.id
+ if id == glue then
+ if n.subtype == 0 then
+ if has_attribute(n,skip_category) then
+ stackhack = true
+ else
+ flush = true
end
+ else
+ -- tricky
end
+ else
+ flush = true
end
- elseif data[ch].uccode then
- while true do
- local d = data[mr(1,0xFFFF)]
- if d then
- local lc = d.lccode
- if lc and tfm[lc] then
- start.char = lc
- return start, true
- end
- end
+ end
+ if flush then
+ if stackhead then
+ if trace_collect_vspacing then report("appending %s nodes to stack (final): %s",newhead) end
+ stacktail.next = newhead
+ newhead.prev = stacktail
+ newhead = stackhead
+ stackhead, stacktail = nil, nil
+ end
+ if stackhack then
+ stackhack = false
+ if trace_collect_vspacing then report("processing %s nodes: %s",newhead) end
+ texlists.contrib_head = collapser(newhead,"page",where,trace_page_vspacing)
+ else
+ if trace_collect_vspacing then report("flushing %s nodes: %s",newhead) end
+ texlists.contrib_head = newhead
end
else
- return start, false
- end
- end
-
- -- node.traverse_id_attr
-
- function cases.process(namespace,attribute,head) -- not real fast but also not used on much data
- local done, actions = false, cases.actions
- for start in traverse_id(glyph,head) do
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- unset_attribute(start,attribute)
- local action = actions[attr]
- if action then
- local _, ok = action(start,attribute)
- done = done and ok
- end
+ if stackhead then
+ if trace_collect_vspacing then report("appending %s nodes to stack (intermediate): %s",newhead) end
+ stacktail.next = newhead
+ newhead.prev = stacktail
+ else
+ if trace_collect_vspacing then report("storing %s nodes in stack (initial): %s",newhead) end
+ stackhead = newhead
end
+ stacktail = newtail
+ texlists.contrib_head = nil
end
- return head, done
+ statistics.stoptiming(vspacing)
end
+end
- chars.handle_casing = nodes.install_attribute_handler {
- name = "case",
- namespace = cases,
- processor = cases.process,
- }
-
- breakpoints = breakpoints or { }
- breakpoints.mapping = breakpoints.mapping or { }
- breakpoints.methods = breakpoints.methods or { }
- breakpoints.enabled = false
-
- input.storage.register(false,"breakpoints/mapping", breakpoints.mapping, "breakpoints.mapping")
+local ignore = table.tohash {
+ "split_keep",
+ "split_off",
+ -- "vbox",
+}
- function breakpoints.setreplacement(id,char,kind,before,after)
- local mapping = breakpoints.mapping[id]
- if not mapping then
- mapping = { }
- breakpoints.mapping[id] = mapping
- end
- mapping[char] = { kind or 1, before or 1, after or 1 }
+function nodes.handle_vbox_spacing(head,where)
+ if head and not ignore[where] and head.next then
+ statistics.starttiming(vspacing)
+ head = collapser(slide_node_list(head),"vbox",where,trace_vbox_vspacing)
+ statistics.stoptiming(vspacing)
end
+ return head
+end
- breakpoints.methods[1] = function(head,start)
- if start.prev and start.next then
- node.insert_before(head,start,nodes.penalty(10000))
- node.insert_before(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.penalty(0))
- end
- return head, start
- end
- breakpoints.methods[2] = function(head,start) -- ( => (-
- if start.prev and start.next then
- local tmp = start
- start = nodes.disc()
- start.prev, start.next = tmp.prev, tmp.next
- tmp.prev.next, tmp.next.prev = start, start
- tmp.prev, tmp.next = nil, nil
- start.replace = tmp
- local tmp, hyphen = node.copy(tmp), node.copy(tmp)
- hyphen.char = languages.prehyphenchar(tmp.lang)
- tmp.next, hyphen.prev = hyphen, tmp
- start.post = tmp
- node.insert_before(head,start,nodes.penalty(10000))
- node.insert_before(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.penalty(10000))
- end
- return head, start
- end
- breakpoints.methods[3] = function(head,start) -- ) => -)
- if start.prev and start.next then
- local tmp = start
- start = nodes.disc()
- start.prev, start.next = tmp.prev, tmp.next
- tmp.prev.next, tmp.next.prev = start, start
- tmp.prev, tmp.next = nil, nil
- start.replace = tmp
- local tmp, hyphen = node.copy(tmp), node.copy(tmp)
- hyphen.char = languages.prehyphenchar(tmp.lang)
- tmp.prev, hyphen.next = hyphen, tmp
- start.pre = hyphen
- node.insert_before(head,start,nodes.penalty(10000))
- node.insert_before(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.glue(0))
- node.insert_after(head,start,nodes.penalty(10000))
- end
- return head, start
+statistics.register("v-node processing time", function()
+ if statistics.elapsedindeed(vspacing) then
+ return format("%s seconds", statistics.elapsedtime(vspacing))
end
+end)
- function breakpoints.process(namespace,attribute,head)
- local done, mapping, fontids = false, breakpoints.mapping, fonts.tfm.id
- local start, n = head, 0
- while start do
- local id = start.id
- if id == glyph then
- local attr = has_attribute(start,attribute)
- if attr and attr > 0 then
- unset_attribute(start,attribute) -- maybe test for subtype > 256 (faster)
- -- look ahead and back n chars
- local map = mapping[attr]
- if map then
- local smap = map[start.char]
- if smap then
- if n >= smap[2] then
- local m = smap[3]
- local next = start.next
- while next do -- gamble on same attribute
- local id = next.id
- if id == glyph then -- gamble on same attribute
- if map[next.char] then
- break
- elseif m == 1 then
- local method = breakpoints.methods[smap[1]]
- if method then
- head, start = method(head,start)
- done = true
- end
- break
- else
- m = m - 1
- next = next.next
- end
- elseif id == kern and next.subtype == 0 then
- next = next.next
- -- ignore intercharacter kerning, will go way
- else
- -- we can do clever and set n and jump ahead but ... not now
- break
- end
- end
- end
- n = 0
- else
- n = n + 1
- end
- else
- n = 0
- end
- end
- elseif id == kern and start.subtype == 0 then
- -- ignore intercharacter kerning, will go way
- else
- n = 0
- end
- start = start.next
- end
- return head, done
- end
-
- chars.handle_breakpoints = nodes.install_attribute_handler {
- name = "breakpoint",
- namespace = breakpoints,
- processor = breakpoints.process,
- }
+-- these are experimental callback definitions that definitely will
+-- be moved elsewhere as part of a chain of vnode handling
+function vspacing.enable()
+--~ callback.register('vpack_filter', nodes.handle_vbox_spacing)
+ callback.register('buildpage_filter', nodes.handle_page_spacing)
end
--- educational: snapper
-
---~ function demo_snapper(head,where) -- snap_category 105 / nodes.snapvalue = { [1] = { 8*65536, 4*65536, 12*65536 } }
---~ if head then
---~ local current, tail, dummy = head, nil, nil
---~ while current do
---~ local id = current.id
---~ if id == glue and current.subtype == 2 then
---~ local sn = has_attribute(current,snap_category)
---~ if sn then
---~ local sv = nodes.snapvalues[sn]
---~ if sv then
---~ head, current, dummy = node.delete(head, current)
---~ node.free(dummy)
---~ else
---~ current = current.next
---~ end
---~ else
---~ current = current.next
---~ end
---~ else
---~ if id == hlist and where == 'hmode_par' and current.list then
---~ local sn = has_attribute(current.list,snap_category)
---~ if sn then
---~ local sv = nodes.snapvalues[sn]
---~ if sv then
---~ local height, depth, lineheight = sv[1], sv[2], sv[3]
---~ current.height = math.ceil((current.height-height)/lineheight)*lineheight + height
---~ current.depth = math.ceil((current.depth -depth )/lineheight)*lineheight + depth
---~ end
---~ end
---~ end
---~ current = current.next
---~ end
---~ tail = current
---~ end
---~ end
---~ return head
---~ end
-
---~ callback.register('buildpage_filter', demo_snapper)
-
--- obsolete, callback changed
-
---~ local head, tail = nil, nil
-
---~ function nodes.flush_vertical_spacing()
---~ if head and head.next then
---~ local t = collapser(head,'flush')
---~ head = nil
---~ -- tail = nil
---~ return t
---~ else
---~ return head
---~ end
---~ end
-
---~ function nodes.handle_page_spacing(t, where)
---~ where = where or "page"
---~ -- we need to add the latest t too, else we miss skips and such
---~ if t then
---~ --~ node.slide(t) -- redunant
---~ if t.next then
---~ local tt = node.slide(t)
---~ local id = tt.id
---~ if id == glue then -- or id == penalty then -- or maybe: if not hlist or vlist
---~ if head then
---~ t.prev = tail
---~ tail.next = t
---~ else
---~ head = t
---~ end
---~ tail = tt
---~ t = nil
---~ elseif head then
---~ t.prev = tail
---~ tail.next = t
---~ t = collapser(head,"page",where)
---~ head = nil
---~ else
---~ t = collapser(t,"page",where)
---~ end
---~ elseif head then
---~ t.prev = tail
---~ tail.next = t
---~ t = collapser(head,"page",where)
---~ head = nil
---~ else
---~ t = collapser(t,"page",where)
---~ end
---~ elseif head then
---~ t = collapser(head,"page",where)
---~ head = nil
---~ end
---~ return t
---~ end
+function vspacing.disable()
+ callback.register('vpack_filter', nil)
+ callback.register('buildpage_filter', nil)
+end
diff --git a/tex/context/base/core-spa.mkii b/tex/context/base/core-spa.mkii
index b3d71699d..356b2cbe3 100644
--- a/tex/context/base/core-spa.mkii
+++ b/tex/context/base/core-spa.mkii
@@ -11,36 +11,4644 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Spacing}
+
+% to be sorted out: dependencies, order of initialization / also some dutch code here
+
\unprotect
-% Just after we implemented the \MKIV\ code, Thanh posted a patch for
-% \PDFTEX. The following code is untested! (\LUATEX\ does not contain
-% this code!)
+% some will move to core-var
+
+\newif \ifgridsnapping
+\newif \iffuzzyvskip
+\let \fuzzyvskip \gobbleoneargument
+\let \removelastfuzzyvskip \relax
+
+\let \startbaselinecorrection \relax
+\let \stopbaselinecorrection \relax
+\let \baselinecorrection \relax
+\let \offbaselinecorrection \relax
+
+\appendtoks \spacing 1\to \everybodyfont
+\appendtoks \presetnormallineheight \to \everybodyfont
+\appendtoks \setnormalbaselines \to \everybodyfont % check if redundant
+\appendtoks \setstrut \to \everybodyfont % check if redundant
+\appendtoks \settopskip \to \everybodyfont
+\appendtoks \setmaxdepth \to \everybodyfont
+%appendtoks \spacing 1\to \everybodyfont
+\appendtoks \simplesetupindenting \to \everybodyfont
+\appendtoks \simplesetupblank \to \everybodyfont
+\appendtoks \simplesetupwhitespace \to \everybodyfont
+%appendtoks \checknotes \to \everybodyfont % not
+\appendtoks \simplesetupspacing \to \everybodyfont % nieuw
+\appendtoks \setrelativeinterlinespace \to \everybodyfont
+
+\appendtoks \updateraggedskips \to \everyfontswitch % under test
+\prependtoks \let\par\endgraf \to \everypagebody % see \fillinline
+\appendtoks \simplesetupspacing \to \everydefinedfont
+
+% if you want to hyphenate the first word of a paragraph ... \appendtoks\hskip0pt\to\everypar
+
+\def\stelfactorenin
+ {\simplesetupwhitespace
+ \simplesetupblank
+ \settopskip
+ \setmaxdepth}
+
+\def\softbreak
+ {\relax\ifhmode\hskip\parfillskip\break\fi}
+
+\let\poplastnode\relax
+
+\def\pushlastnode
+ {\ifdim\lastskip=\zeropoint
+ \ifnum\lastpenalty=\zerocount
+ \ifnum\lastkern=\zerocount
+ \let\poplastnode\relax
+ \else
+ \edef\poplastnode{\kern\the\lastkern\relax}\kern-\lastkern % untested
+ \fi
+ \else
+ \edef\poplastnode{\penalty\the\lastpenalty\relax}\nobreak % untested
+ \fi
+ \else
+ \edef\poplastnode{\vskip\the\lastskip\relax}\vskip-\lastskip % \removelastskip
+ \fi}
+
+%D The dreadful sequence \type {\bgroup} \unknown\
+%D \type {\carryoverpar} \unknown\ \type {\egroup} is needed
+%D when for instance sidefloats are used in combination with
+%D something that starts with a group. This is because
+%D otherwise the indentation as set (by the output routine)
+%D inside the group are forgotten afterwards. (I must
+%D not forget its existence).
+
+\global\let\carriedoverpar\relax
+
+\def\carryoverpar#1%
+ {\expanded % \scratchtoks{#1}%
+ {\noexpand#1% \the\scratchtoks
+ \hangindent\the\hangindent
+ \hangafter \the\hangafter
+ \parskip \the\parskip
+ \leftskip \the\leftskip
+ \rightskip \the\rightskip}}
+
+%D A quick way to determine left|/|middle|/|right states
+%D (experimental).
+
+\setvalue{\??as\v!left }{0}
+\setvalue{\??as\v!middle}{1}
+\setvalue{\??as\v!right }{2}
+
+\def\setalignmentswitch#1%
+ {\chardef\alignmentswitch0\csname\??as#1\endcsname\relax}
+
+%D There are two ways to influence the interline spacing. The
+%D most general and often most consistent way is using
+%D
+%D \showsetup{setupinterlinespace}
+%D
+%D For instance
+%D
+%D \starttyping
+%D \setupinterlinespace[line=2.8ex]
+%D \stoptyping
+%D
+%D This setting adapts itself to the bodyfontsize, while for
+%D instance saying
+%D
+%D \starttyping
+%D \setupinterlinespace[line=12pt]
+%D \stoptyping
+%D
+%D sets things fixed for all sizes, which is definitely not
+%D what we want. Therefore one can also say:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[9pt][interlinespace=11pt]
+%D \stoptyping
+%D
+%D One can still use \type{\setupinterlinespace} (without
+%D arguments) to set the interline space according to the
+%D current font, e.g. a \type{\bfa}.
+
+\newif\iflocalinterlinespace
+
+% font-ini
+
+\ifx\bodyfontinterlinespecs\undefined
+
+ \let\bodyfontinterlinespecs\empty
+ \let\bodyfontinterlinespace\empty
+
+\fi
+
+\def\presetnormallineheight
+ {\edef\normallineheight{\@@itline}%
+% done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
+ \iflocalinterlinespace \else
+ \doifdefined\bodyfontinterlinespecs
+ {\doifsomething\bodyfontinterlinespace
+ {\edef\normallineheight{\bodyfontinterlinespace}}}%
+ \fi}
+
+\def\setupspecifiedinterlinespace[#1]%
+ {\getparameters[\??it][#1]%
+ \scratchdimen0\@@itheight\points
+ \advance\scratchdimen 0\@@itdepth\points
+ \ifdim\scratchdimen>\onepoint
+ \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
+ \let\@@itheight\strutheightfactor
+ \let\@@itdepth \strutdepthfactor
+ \else
+ \let\strutheightfactor\@@itheight
+ \let\strutdepthfactor \@@itdepth
+ \fi
+ \let\minimumstrutheight \@@itminheight
+ \let\minimumstrutdepth \@@itmindepth
+ \let\minimumlinedistance\@@itdistance
+ \let\normallineheight \@@itline % let ! ! ! ! ! ivm ex
+ \doifelse\@@ittop\v!height % new, topskip does more bad than good
+ {\let\topskipfactor \@@itheight}
+ {\let\topskipfactor \@@ittop }%
+ \let\maxdepthfactor \@@itbottom
+ \let\baselinegluefactor \@@itstretch
+ \setfontparameters % redundant, can be \setstrut, test first
+ \updateraggedskips} % yes indeed
+
+% \let\currentrelativeinterlinespace\empty
+%
+% \def\setuprelativeinterlinespace[#1]%
+% {\processallactionsinset
+% [#1]
+% [ \v!on=>\oninterlineskip,
+% \v!off=>\offinterlineskip,
+% \v!reset=>\let\currentrelativeinterlinespace\empty
+% \setfontparameters,% just \setstrut, test first
+% \s!unknown=>\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+% \spacing\currentrelativeinterlinespace]}
+
+% \setupinterlinespace[big] \switchtobodyfont[11pt] -> forgotten
+% \setupinterlinespace[auto,big] \switchtobodyfont[11pt] -> remembered
+
+\let\currentrelativeinterlinespace\empty
+
+\def\setuprelativeinterlinespace[#1]%
+ {\processallactionsinset
+ [#1]
+ [ \v!on=>\oninterlineskip,
+ \v!off=>\offinterlineskip,
+ \v!reset=>\let\currentrelativeinterlinespace\empty
+ \let\setrelativeinterlinespace\relax
+ \setfontparameters,
+ \v!auto=>\let\setrelativeinterlinespace\dosetrelativeinterlinespace,
+ \s!unknown=>\assignvalue\commalistelement\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+ \spacing\currentrelativeinterlinespace]}
+
+\def\dosetrelativeinterlinespace
+ {\ifx\currentrelativeinterlinespace\empty\else
+ \spacing\currentrelativeinterlinespace
+ \fi}
+
+\let\setrelativeinterlinespace\relax
+
+% \appendtoks \setrelativeinterlinespace \to \everybodyfont
+
+\def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
+ {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]}
+
+\def\setuplocalinterlinespace[#1]%
+ {\localinterlinespacetrue
+ \setupinterlinespace[#1]%
+ \localinterlinespacefalse}
+
+\def\simplesetupinterlinespace
+ {\localinterlinespacetrue
+ \setfontparameters
+ \updateraggedskips % funny one here
+ \localinterlinespacefalse}
+
+\definecomplexorsimple\setupinterlinespace
+
+% In earlier versions \type{\bigskipamount} was
+% \type{\ht\strutbox} and the stretch was plus or minus
+% \type{.4\dp\strutbox}. Don't ask me why. The most recent
+% implementation is based on a user supplied distance, which
+% is by default \type{.75\normalskipamount} where
+% \type{\normalskipamount} equals the current baseline
+% distance.
+
+% \lineskiplimit = -\maxdimen -> freezes baselineskip
+
+% can be conditionals
+
+\newif\ifblanknowhite \blanknowhitefalse
+\newif\ifblankindeed \blankindeedfalse
+\newif\ifblankreset \blankresetfalse
+\newif\ifblankdisable \blankdisablefalse
+\newif\ifblankflexible \blankflexibletrue
+\newif\ifblankouter
+\newif\ifblankforce
+\newif\ifblankgoback
+
+\newskip\blankskip \blankskip=\bigskipamount
+\newskip\blankskipamount
+
+\def\skipfactor {.75}
+\def\skipgluefactor{.25}
+
+\def\normalskipamount
+ {\openlineheight
+ \ifgridsnapping \else \ifblankflexible
+ \!!plus \skipgluefactor\openlineheight
+ \!!minus\skipgluefactor\openlineheight
+ \fi \fi
+ \relax}
+
+\def\linedistance {\normalskipamount}
+\def\appliedblankskip{\skipfactor\linedistance}
+\def\lastblankskip {\blankskip}
+\def\currentblank {\v!big}
+\def\oldprevdepth {\prevdepth}
+\def\newprevdepth {-1001pt}
+\def\mindimen {1sp} % was: 0.00002pt
+
+\newif\iflocalblankfixed
+\newif\iflocalblankflexible
+
+\def\geenblanko{\removelastskip} % will become obsolete
+
+%%%% pas op, wordt ook in core-pos gebruikt
+
+\def\doassignsomeskip#1\to#2% ook nog \v!halfline+fuzzysnap
+ {\doifelse{#1}\v!line
+ {#2\openlineheight}
+ {\ifgridsnapping
+ \assigndimension{#1}{#2}{.25\openlineheight}{.5\openlineheight}\openlineheight
+ \else
+ \assigndimension{#1}{#2}\smallskipamount\medskipamount\bigskipamount
+ \fi}%
+ \relax}
+
+% \relax is really needed, else we may loose stretch due to lookahead; somehow
+% this bug was introduced a while ago but somehow went unnoticed; fixed 2/7/2008
+
+\def\addblankskip#1#2#3{\global\advance\blankskip#1\ifgridsnapping#3\else#2\fi\relax}
+
+\def\defineblankmethod[#1]#2{\setvalue{\??bo\??bo#1}{#2}}
+
+\defineblankmethod [\v!big] {\addblankskip+\bigskipamount \openlineheight}
+\defineblankmethod [-\v!big] {\addblankskip-\bigskipamount \openlineheight}
+\defineblankmethod [\v!medium] {\addblankskip+\medskipamount {.5\openlineheight}}
+\defineblankmethod [-\v!medium] {\addblankskip-\medskipamount {.5\openlineheight}}
+\defineblankmethod [\v!small] {\addblankskip+\smallskipamount{.25\openlineheight}}
+\defineblankmethod [-\v!small] {\addblankskip-\smallskipamount{.25\openlineheight}}
+\defineblankmethod [\v!white] {\addblankskip+\parskip \openlineheight}
+\defineblankmethod [-\v!white] {\addblankskip-\parskip \openlineheight}
+\defineblankmethod [\v!line] {\addblankskip+\openlineheight \openlineheight}
+\defineblankmethod [-\v!line] {\addblankskip-\openlineheight \openlineheight}
+
+\defineblankmethod [\v!formula] {\global\advance\blankskip\medskipamount}
+\defineblankmethod [\v!nowhite] {\global\blanknowhitetrue}
+\defineblankmethod [\v!disable] {\global\blankdisabletrue}
+\defineblankmethod [\v!force] {\global\blankforcetrue}
+\defineblankmethod [\v!outer] {\ifvmode\ifinner\blankoutertrue\fi\fi}
+\defineblankmethod [\v!reset] {\global\blankresettrue}
+\defineblankmethod [\v!flexible] {\global\localblankflexibletrue}
+\defineblankmethod [\v!fixed] {\global\localblankfixedtrue}
+\defineblankmethod [\v!back] {\global\blankgobacktrue} % {\geenblanko}
+\defineblankmethod [\v!halfline] {\ifgridsnapping\global\fuzzyvskiptrue\fi
+ \global\advance\blankskip .5\lineheight}
+
+\defineblankmethod [\v!none] {\global\blankresettrue}
+\defineblankmethod [\v!joinedup] {\ifvmode\nointerlineskip\fi}
+
+\defineblankmethod [\v!always] {\redowhitespace} % experimental
+
+% happens often, so we speed this up:
+%
+% \defineblankmethod [2*\v!line] {\addblankskip+{2\openlineheight}{2\openlineheight}}
+% \defineblankmethod [2*\v!big] {\addblankskip+{2\bigskipamount }{2\openlineheight}}
+%
+% no, with 2\whatever we loose the stretch and shrink! Taco's alternative:
+
+\defineblankmethod
+ [2*\v!line]
+ {\addblankskip+\openlineheight\openlineheight
+ \addblankskip+\openlineheight\openlineheight}
+
+\defineblankmethod
+ [2*\v!big]
+ {\addblankskip+\bigskipamount\openlineheight
+ \addblankskip+\bigskipamount\openlineheight}
+
+\def\doblank#1%
+ {\edefconvertedargument\ascii{#1}%
+ \ifx\ascii\empty\else
+ \ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+ \else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+ \else
+ \dorepeatwithcommand[#1]\redoblank
+ \fi\fi
+ \fi
+ \relax}
+
+\def\redoblank#1%
+ {\edefconvertedargument\ascii{#1}%
+ \ifx\ascii\empty\else
+ \ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+ \else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+ \else
+ \global\advance\blankskip#1\relax
+ \fi\fi
+ \fi
+ \relax}
+
+\unexpanded\def\blank % the \relax is definitely needed due to the many \if's
+ {\relax\complexorsimple\doblank}
+
+\def\complexdoblank
+ {\flushnotes
+ \ifmmode
+ \@EA\nocomplexdoblank
+ \else
+ \ifopelkaar
+ \ifinpagebody
+ \@EA\@EAEAEA\@EA\docomplexdoblank
+ \else
+ \@EA\@EAEAEA\@EA\nocomplexdoblank
+ \fi
+ \else
+ \@EAEAEA\docomplexdoblank
+ \fi
+ \fi}
+
+\def\nocomplexdoblank[#1]%
+ {% evt blokkeerfalse
+ \ifmmode\else\par\fi}
+
+% Overloaded in cont-new!
+
+\newsignal\noblanksignal
+
+% \def\doinhibitblank
+% {\kern\noblanksignal}
+
+% \def\inhibitblank% the fast, local way
+% {\endgraf\ifvmode\prevdepth\newprevdepth\fi}
+
+% \def\docomplexdoblank[#1]% pas op \relax's zijn nodig ivm volgende \if
+% {\global\blankresetfalse
+% \global\blankdisablefalse
+% \global\blanknowhitefalse
+% \global\localblankflexiblefalse
+% \global\localblankfixedfalse
+% \global\blankskip\zeropoint
+% \global\blankforcefalse
+% \global\blankgobackfalse
+% \blankouterfalse
+% \expanded{\rawprocesscommalist[#1]}\doblank
+% \ifdim\blankskip=\zeropoint\relax
+% \iflocalblankflexible
+% \doglobal\advance\blankskip \currentblank
+% \else\iflocalblankfixed
+% \doglobal\advance\blankskip \currentblank
+% \fi\fi
+% \fi
+% \ifblankouter
+% \else
+% \par
+% \ifvmode
+% \ifblankgoback
+% \removelastskip
+% \fi
+% \ifblankforce
+% % dit gaat mis in pos fonts
+% % \ifdim\prevdepth>\zeropoint\else ...
+% % -1000pt signals top of page or column (\ejectcolumn)
+% \bgroup\forgeteverypar\verticalstrut\egroup\kern-\struttotal
+% \fi
+% \ifblankdisable
+% \global\blankindeedfalse
+% \ifgridsnapping
+% \ifdim\prevdepth<\zeropoint
+% % brrr
+% \else
+% % dirty trick: smaller blanks are ignored after
+% % a larger one, so 10 lines is probably safe; first make
+% % sure that we honor penalties
+% \scratchcounter\lastpenalty
+% % now comes the trick (cross our fingers that this works
+% % well in multi columns; maybe an ifinner test is needed
+% % \vskip-10\lineheight
+% % \ifnum\scratchcounter=\zerocount \else \penalty\lastpenalty \fi
+% % \vskip 10\lineheight
+% % allas, this leads to overfull pages, so we try this:
+% \kern-\noblanksignal
+% \ifnum\scratchcounter=\zerocount
+% \else
+% \penalty\lastpenalty
+% \fi
+% \kern\noblanksignal
+% % end-of-dirty-trick
+% \fi
+% \else
+% \ifdim\prevdepth<\zeropoint
+% % brrr
+% \else
+% % ensure at least a proper prevdepth, this should be
+% % an option
+% \vskip-\prevdepth
+% \vskip\strutdepth
+% \prevdepth\strutdepth
+% \fi
+% % the old crappy piece of code
+% \edef\oldprevdepth{\the\prevdepth}%
+% \prevdepth\newprevdepth
+% \fi
+% \else
+% \global\blankindeedtrue
+% \fi
+% \ifblankreset
+% \global\blankindeedtrue
+% \ifgridsnapping
+% % let's play safe and not fool around with the depth, if
+% % only because it took a lot of effort to sort out the grid
+% % stuff in the first place
+% \else
+% \ifdim\prevdepth=\newprevdepth
+% \prevdepth\oldprevdepth
+% \fi
+% \fi
+% \fi
+% \ifblankindeed
+% \ifdim1\lastskip<1\blankskip\relax
+% % else when \blanko[2*groot] + \blanko[3*groot] with parskip
+% % equaling 1*groot, gives a groot=\parskip so adding a small
+% % value makes it distinguishable; can also be done at parskip
+% % setting time (better)
+% \global\advance\blankskip \mindimen\relax % = skip
+% % test this on 2* + 3* and parskip groot
+% \ifblanknowhite
+% \global\advance\blankskip -\parskip
+% \else
+% \ifdim\lastskip=\parskip
+% \else % force this due to previous comment
+% \ifdim\parskip>\zeropoint\relax
+% \ifdim\blankskip<\parskip\relax
+% \global\blankskip\zeropoint
+% \else
+% \global\advance\blankskip -\parskip
+% \fi
+% \fi
+% \fi
+% \fi
+% \ifblankflexible \else
+% \blankskip1\blankskip
+% \fi
+% \iflocalblankfixed
+% \blankskip1\blankskip
+% \fi
+% \iflocalblankflexible
+% \blankskip1\blankskip
+% \!!plus\skipgluefactor\blankskip
+% \!!minus\skipgluefactor\blankskip
+% \fi
+% \ifdim\lastkern=\noblanksignal % controled and grid
+% \global\blankindeedfalse
+% \else\ifgridsnapping\else\ifdim\prevdepth=\newprevdepth
+% \global\blankindeedfalse
+% \fi\fi\fi
+% \ifblankindeed
+% \iffuzzyvskip
+% \removelastfuzzyvskip
+% \fuzzyvskip\blankskip\relax
+% \else
+% \removelastskip
+% \vskip\blankskip\relax
+% \fi
+% \fi
+% \else
+% \iffuzzyvskip
+% \removelastfuzzyvskip
+% \fuzzyvskip\blankskip\relax
+% \else
+% % new, test this on pascal
+% \ifdim\blankskip<\zeropoint
+% \advance\blankskip-\lastskip
+% \removelastskip
+% \ifdim\blankskip>\zeropoint
+% \vskip\blankskip
+% \else
+% \vskip\zeropoint
+% \fi
+% \else
+% % also new
+% \ifdim\blankskip=\zeropoint
+% \ifblanknowhite
+% \geenwitruimte
+% \fi
+% \fi
+% \fi
+% \fi
+% \fi
+% \fi
+% \fi
+% \fi
+% \global\fuzzyvskipfalse
+% \presetindentation}
+
+% goback was broken:
+
+% \def\doinhibitblank
+% {\kern\noblanksignal}
+
+% \def\inhibitblank% the fast, local way
+% {\endgraf\ifvmode\prevdepth\newprevdepth\fi}
+
+% problem: we cannot look back in the mvl so we need 3 kinds of signals
+
+\def\noblankpsignal{1010101}
+
+\def\inhibitgridblank % was doinhibitblank
+ {\ifvmode\else\endgraf\fi
+ \ifvmode
+ \ifnum\lastpenalty<10000
+ \kern-\noblanksignal % new
+ \kern \noblanksignal
+ \else
+ \penalty\noblankpsignal
+ \fi
+ \fi}
+
+\def\inhibittextblank % was inhibitblank
+ {\endgraf
+ \ifvmode
+ \prevdepth\newprevdepth
+ \fi}
+
+% new macro
+%
+% \def\inhibitblank % need some work
+% {\endgraf
+% \ifvmode
+% \ifgridsnapping
+% \inhibitgridblank
+% \else
+% % this one spoils the grid
+% \inhibittextblank
+% \fi
+% \fi}
+
+\def\doinhibitblank{\inhibitgridblank}
+\def\inhibitblank {\inhibittextblank}
+
+% will become obsolete
+
+\ifx\undefined\savedlastskip \newskip \savedlastskip \fi
+\ifx\undefined\savedlastpenalty \newcount\savedlastpenalty \fi
+
+% beware, prevdepth can have funny values (e.g. mvl value when in box)
+
+\def\docomplexdoblank[#1]% pas op \relax's zijn nodig ivm volgende \if
+ {\global\blankresetfalse
+ \global\blankdisablefalse
+ \global\blanknowhitefalse
+ \global\localblankflexiblefalse
+ \global\localblankfixedfalse
+ \global\blankforcefalse
+ \global\blankgobackfalse
+ \blankouterfalse
+ \global\blankskip\zeropoint
+%
+\edefconvertedargument\ascii{#1}% todo fast check for simple
+\ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+\else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+\else
+ \expanded{\rawprocesscommalist[#1]}\doblank
+\fi\fi
+%
+ \relax % to be sure
+ \ifdim\blankskip=\zeropoint\relax
+ \iflocalblankflexible
+ \doglobal\advance\blankskip \currentblank
+ \else\iflocalblankfixed
+ \doglobal\advance\blankskip \currentblank
+ \fi\fi
+ \fi
+ \relax % to be sure
+ \ifblankouter
+ % do nothing
+ \else
+ \par
+ \ifvmode
+ \ifblankgoback
+ \ifdim\lastskip>\zeropoint \vskip-\lastskip \fi
+ \savedlastskip\zeropoint
+ \else\ifdim\lastskip>\zeropoint
+ \savedlastskip\lastskip
+ \else % todo: lastnode, dan namelijk geen skip !
+ \savedlastskip\zeropoint
+ \fi\fi
+ \ifblankforce
+ % dit gaat mis in pos fonts
+ % \ifdim\prevdepth>\zeropoint\else ...
+ % -1000pt signals top of page or column (\ejectcolumn)
+ \bgroup\forgeteverypar\verticalstrut\egroup\kern-\struttotal
+ \savedlastskip\zeropoint
+ \fi
+ \savedlastpenalty\lastpenalty % hm, now it gets lost
+ \ifblankdisable
+ \global\blankindeedfalse % keep this, i.e. disable current too
+ \ifgridsnapping
+ \ifdim\prevdepth<\zeropoint
+ % brrr
+ \else
+ % dirty trick: smaller blanks are ignored after a
+ % larger one, so 10 lines is probably safe; we need
+ % to make sure that we honor penalties; here comes the
+ % trick (cross our fingers that this works well in
+ % multi columns; maybe an ifinner test is needed
+ % \scratchcounter\lastpenalty
+ % \vskip-10\lineheight
+ % \ifnum\scratchcounter=\zerocount \else \penalty\lastpenalty \fi
+ % \vskip 10\lineheight
+ % alas, this leads to overfull pages, so we try this:
+ \inhibitgridblank
+ \fi
+ \else
+ \ifdim\prevdepth<\zeropoint
+ % brrr
+ \else
+ % ensure at least a proper prevdepth, this should be
+ % an option
+ \vskip-\prevdepth
+ \vskip\strutdepth
+ \prevdepth\strutdepth
+ \fi
+ % the old crappy piece of code
+ \edef\oldprevdepth{\the\prevdepth}%
+ \prevdepth\newprevdepth % == \inhibittextblank
+ \fi
+ \else
+ \global\blankindeedtrue
+ \fi
+ \ifblankreset
+ \global\blankindeedtrue
+ \ifgridsnapping
+ % let's play safe and not fool around with the depth, if
+ % only because it took a lot of effort to sort out the grid
+ % stuff in the first place
+ \else
+ \ifdim\prevdepth=\newprevdepth
+ \prevdepth\oldprevdepth
+ \fi
+ \fi
+ \fi
+ \ifblankindeed
+ \ifdim1\savedlastskip<1\blankskip\relax
+ % else when \blank[2*groot] + \blank[3*groot] with parskip
+ % equaling 1*groot, gives a groot=\parskip so adding a small
+ % value makes it distinguishable; can also be done at parskip
+ % setting time (better)
+ \global\advance\blankskip \mindimen\relax % = skip
+ % test this on 2* + 3* and parskip groot
+ \ifblanknowhite
+ \global\advance\blankskip -\parskip
+ \else
+ \ifdim\savedlastskip=\parskip
+ \else % force this due to previous comment
+ \ifdim\parskip>\zeropoint\relax
+ \ifdim\blankskip<\parskip\relax
+ \global\blankskip\zeropoint
+ \else
+ \global\advance\blankskip -\parskip
+ \fi
+ \fi
+ \fi
+ \fi
+ \ifblankflexible \else
+ \blankskip1\blankskip
+ \fi
+ \iflocalblankfixed
+ \blankskip1\blankskip
+ \fi
+ \iflocalblankflexible
+ \blankskip1\blankskip
+ \!!plus \skipgluefactor\blankskip
+ \!!minus\skipgluefactor\blankskip
+ \fi
+ \ifdim\lastkern=\noblanksignal\relax % controlled and grid
+ \global\blankindeedfalse
+ \else\ifnum\savedlastpenalty=\noblankpsignal\relax % controlled and grid
+ \global\blankindeedfalse
+ \else\ifgridsnapping\else\ifdim\prevdepth=\newprevdepth
+ \global\blankindeedfalse
+ \fi\fi\fi\fi
+ \ifblankindeed
+ \iffuzzyvskip
+ \removelastfuzzyvskip
+ \fuzzyvskip\blankskip\relax
+ \else
+ \relax\ifdim\savedlastskip=\zeropoint\else
+ \vskip-\savedlastskip
+ \fi
+ \vskip\blankskip\relax
+ \fi
+ \fi
+ \else
+ \iffuzzyvskip
+ \removelastfuzzyvskip
+ \fuzzyvskip\blankskip\relax
+ \else
+ % new, test this on pascal
+ \ifdim\blankskip<\zeropoint
+ \relax\ifdim\savedlastskip=\zeropoint\else
+ \advance\blankskip-\savedlastskip
+ \vskip-\savedlastskip
+ \fi
+ \ifdim\blankskip>\zeropoint
+ \vskip\blankskip
+ \else
+ \vskip\zeropoint
+ \fi
+ \else
+ % also new
+ \ifdim\blankskip=\zeropoint
+ \ifblanknowhite
+ \nowhitespace
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \global\fuzzyvskipfalse
+ \presetindentation}
+
+%D For a long time we had:
+%D
+%D \starttyping
+%D \def\simpledoblank%
+%D {\doifelse{\currentwhitespace}{\v!geen}
+%D {\blank[\currentblank]}
+%D {\blank[\currentwhitespace]}}
+%D \stoptyping
+%D
+%D But Berend de Boer wanted more control, so now we have:
+
+\def\simpledoblank % ...
+ {\doifelse\currentwhitespace\v!none
+ {\blank[\currentblank]}
+ {\blank[\s!default]}}
+
+%D Another useful definition would be:
+%D
+%D \starttyping
+%D \defineblank
+%D [\s!default]
+%D [\v!groot]
+%D \stoptyping
+
+\def\dosetupblank#1% amount are an plain inheritance
+ {\bigskipamount#1\relax
+ \ifblankflexible \else
+ \bigskipamount1\bigskipamount
+ \fi
+ \medskipamount \bigskipamount \divide\medskipamount \plustwo
+ \smallskipamount\bigskipamount \divide\smallskipamount\plusfour}%
+
+\def\complexsetupblank[#1]% more \let's -> this also wil become installable
+ {\ifgridsnapping
+ \blankflexiblefalse
+ \else
+ \ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!flexible=>\blankflexibletrue,
+ \v!fixed=>\blankflexiblefalse]%
+ \fi
+ \ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!flexible=>\dosetupblank\appliedblankskip,
+ \v!fixed=>\dosetupblank\appliedblankskip,
+ \v!line=>\edef\appliedblankskip{\linedistance}%
+ \dosetupblank\appliedblankskip,
+ \v!halfline=>\scratchskip.5\linedistance
+ \edef\appliedblankskip{\the\scratchskip}%
+ \dosetupblank\appliedblankskip,
+ \v!big=>\ifgridsnapping
+ \edef\appliedblankskip{\linedistance}%
+ \dosetupblank\appliedblankskip
+ \fi
+ \let\currentblank\v!big,
+ \v!medium=>\let\currentblank\v!medium,
+ \v!small=>\let\currentblank\v!small,
+ \v!global=>\let\currentblank\v!global,
+ \v!normal=>\dosetupblank\appliedblankskip,
+ \v!standard=>\edef\appliedblankskip{\skipfactor\linedistance}%
+ \dosetupblank\appliedblankskip,
+ \s!default=>\dosetupblank\appliedblankskip,
+ \s!unknown=>\let\appliedblankskip\commalistelement
+ \dosetupblank\appliedblankskip]%
+ \simplesetupwhitespace}
+
+% \definecomplexorsimpleempty\setupblank
+%
+% speed gain: 60 sec -> 30 sec
+
+\definecomplexorsimple\setupblank
+
+\def\simplesetupblank % == snelle \setupblank[\s!default]
+ {\ifgridsnapping
+ \blankflexiblefalse
+ \fi
+ \dosetupblank\appliedblankskip
+ % \let\deblanko\v!big
+ \simplesetupwhitespace}
+
+\def\restorestandardblank% \v!standard
+ {\edef\appliedblankskip{\skipfactor\linedistance}%
+ \dosetupblank\appliedblankskip
+ }%\let\deblanko\v!big}
+
+\def\dodefineblank[#1][#2]%
+ {\def\docommand##1{\setvalue{\??bo##1}{#2}}%
+ \processcommalist[#1]\docommand}
+
+\def\defineblank
+ {\dodoubleargument\dodefineblank}
+
+\def\savecurrentblank
+ {\edef\restorecurrentblank
+ {\bigskipamount\the\bigskipamount
+ \medskipamount\the\medskipamount
+ \smallskipamount\the\smallskipamount
+ \noexpand\def\noexpand\currentblank{\currentblank}%
+ \ifblankflexible
+ \noexpand\blankflexibletrue
+ \else
+ \noexpand\blankflexiblefalse
+ \fi}}
+
+%D Now.
+
+\defineblank [\s!default] [\v!white]
+\defineblank [\v!height] [\strutheight]
+\defineblank [\v!depth] [\strutdepth]
+
+% old implementation
+%
+% \let\currentindentation=\empty
+%
+% \newdimen\ctxparindent
+%
+% \newif\ifindentfirstparagraph % \indentfirstparagraphtrue
+%
+% \def\presetindentation
+% {\doifoutervmode{\ifindentfirstparagraph\else\noindentation\fi}}
+%
+% \definecomplexorsimple\setupindenting
+%
+% \def\complexsetupindenting[#1]%
+% {\processallactionsinset
+% [#1]
+% [ \v!first=>\indentfirstparagraphtrue,
+% \v!next=>\indentfirstparagraphfalse,
+% \s!default=>\simplesetupindenting,
+% \s!unknown=>\edef\currentindentation{\commalistelement}%
+% \simplesetupindenting]}
+%
+% \def\simplesetupindenting
+% {\assigndimension\currentindentation\ctxparindent{1em}{1.5em}{2em}%
+% \parindent\ctxparindent\relax}
+%
+% \def\indenting % watch out: \dodo and no \do
+% {\dosingleargument\dodoindenting}
+%
+% \def\dodoindenting[#1]% oeps, we needed a commalist handler here!
+% {\edef\currentindenting{#1}%
+% \processcommacommand[#1]\dododoindenting}
+%
+% \def\dododoindenting#1%
+% {\executeifdefined{\??in:#1}\donothing}
+%
+% \let\currentindenting\empty
+%
+% \def\defineindentingmethod[#1]#2%
+% {\setvalue{\??in:#1}{#2}}
+%
+% \defineindentingmethod [\v!no] {\parindent\ctxparindent\noindent}
+% \defineindentingmethod [\v!not] {\parindent\ctxparindent\noindent}
+%
+% \defineindentingmethod [\v!first] {\indentfirstparagraphtrue}
+% \defineindentingmethod [\v!next] {\indentfirstparagraphfalse}
+%
+% \defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent !
+% \defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent !
+%
+% \defineindentingmethod [\v!never] {\parindent\zeropoint\relax} % no \indent !
+%
+% \def\noindenting{\indenting[\v!no,\v!next]} % was \nietinspringen
+% \def\doindenting{\indenting[\v!yes,\v!first]} % was \welinspringen
+%
+% \def\dochecknextindentation#1% internal one
+% {\checknextindentation[\getvalue{#1\c!indentnext}]}
+%
+% \def\checknextindentation[#1]%
+% {\processaction[#1][%\v!keep=>,
+% \v!yes=>\doindentation,
+% \v!no=>\noindentation,
+% \v!auto=>\autoindentation]}
+%
+% \def\doindentation% too simple
+% {\gdef\checkindentation{\global\indentationtrue}}
+%
+% \ifx\autoindentation\undefined
+% \let\autoindentation\relax
+% \fi
+%
+% \newif\ifindentation \indentationtrue % documenteren, naar buiten
+%
+% \let\checkindentation=\relax
+%
+% \def\donoindentation
+% {\ifdim\parindent=\zeropoint \else
+% \bgroup \setbox\scratchbox\lastbox \egroup
+% \fi}
+%
+% \def\noindentation % made global
+% {\ifinpagebody \else
+% \global\indentationfalse
+% \gdef\checkindentation
+% {\donoindentation
+% \gdef\checkindentation{\global\indentationtrue}}%
+% \fi}
+%
+% \def\nonoindentation % bv bij floats
+% {\ifinpagebody \else
+% \global\indentationtrue
+% \gdef\checkindentation{\global\indentationtrue}%
+% \fi}
+%
+% \def\indentation
+% {\ifvmode \ifdim\parindent=\zeropoint \else
+% % was : \hskip\parindent
+% % can be: \indent
+% % but we test:
+% \noindent\hskip\parindent
+% \fi \fi}
+
+\let\currentindentation\empty % amount/keyword
+% \let\normalindentation \empty % used for reinstating normal indentation
+\let\currentindenting \empty % method
+
+\newdimen\ctxparindent
+
+\newif\ifindentfirstparagraph % \indentfirstparagraphtrue
+
+\chardef\indentingtoggle\zerocount
+
+%D After a blank or comparable situation (left side floats) we
+%D need to check if the next paragraph has to be indented.
+
+\def\presetindentation
+ {\doifoutervmode{\ifindentfirstparagraph\else\noindentation\fi}}
+
+%D This sets up the (normally) global indentation behavior as well
+%D as the amounts.
+
+\definecomplexorsimple\setupindenting
+
+% \def\complexsetupindenting[#1]%
+% {\edef\currentindenting{#1}%
+% \indentfirstparagraphtrue
+% \parindent\ctxparindent
+% \chardef\indentingtoggle\zerocount
+% \processcommalist[#1]\docomplexsetupindenting
+% \ifindentfirstparagraph\else\noindentation\fi % added
+% \toggleindentation}
+
+\indentfirstparagraphtrue
+\parindent\ctxparindent
+\chardef\indentingtoggle\zerocount
+
+% \newtoks\savedeverypar \savedeverypar\everypar
+% \def\restoreeverypar{\everypar\savedeverypar}
+
+% we need a better everypar model: for each option a switch, which we
+% set to false with \forgetall and can enable when needed (context 4);
+% that way we can control the order of execution of options
+
+\def\checkeverypar % currently a hack
+ {\ifzeropt\parindent\else
+ \doifsometokselse\everypar\donothing{\appendtoks\checkindentation\to\everypar}%
+ \fi}
+
+\def\complexsetupindenting[#1]%
+ {\edef\currentindenting{#1}%
+ \doifsomething\currentindenting % handy when a parameter is passed
+ {% not here: \indentfirstparagraphtrue
+ % not here: \parindent\ctxparindent
+ % not here: \chardef\indentingtoggle\zerocount
+ % we use commacommand in order to catch #1 being a command (expanded parameter)
+ \processcommacommand[\currentindenting]\docomplexsetupindentingA % catch small, medium, etc
+ \processcommacommand[\currentindenting]\docomplexsetupindentingB % catch rest
+ \checkeverypar % only when non-empty #1
+ \ifindentfirstparagraph\else\noindentation\fi % added
+ \toggleindentation}}
+
+\def\docomplexsetupindentingA#1%
+ {\edefconvertedargument\!!stringa{#1}%
+ \doifundefined{\??in:\!!stringa}%
+ {\edef\currentindentation{#1}%
+ \let\normalindentation\currentindentation
+ \simplesetupindenting}}
+
+\def\docomplexsetupindentingB#1%
+ {\edefconvertedargument\!!stringa{#1}% catch #1=\somedimen
+ \executeifdefined{\??in:\!!stringa}\donothing}
+
+\def\simplesetupindenting % empty case, a it strange, needed this way?
+ {\assigndimension\currentindentation\ctxparindent{1em}{1.5em}{2em}}
+
+\def\indenting % kind of obsolete
+ {\dosingleargument\complexsetupindenting}
+
+% use \noindentation to suppress next indentation
+
+\def\defineindentingmethod[#1]#2%
+ {\setvalue{\??in:#1}{#2}}
+
+\defineindentingmethod [\v!no] {\parindent\zeropoint}% was: \ctxparindent\noindent}
+\defineindentingmethod [\v!not] {\parindent\zeropoint}% was: \ctxparindent\noindent}
+
+\defineindentingmethod [\v!first] {\indentfirstparagraphtrue}
+\defineindentingmethod [\v!next] {\indentfirstparagraphfalse}
+
+\defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent !
+\defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent !
+
+\defineindentingmethod [\v!never] {\parindent\zeropoint\relax % no \indent !
+ \chardef\indentingtoggle\zerocount}
+
+\defineindentingmethod [\v!odd] {\chardef\indentingtoggle\plusone}
+\defineindentingmethod [\v!even] {\chardef\indentingtoggle\plustwo}
+
+\defineindentingmethod [\v!normal] {\ifx\normalindentation\empty\else
+ \let\currentindentation\normalindentation
+ \simplesetupindenting
+ \fi}
+
+\defineindentingmethod [\v!reset] {\indentfirstparagraphtrue
+ \parindent\zeropoint
+ \chardef\indentingtoggle\zerocount}
+
+\def\noindenting{\indenting[\v!no, \v!next ]}
+\def\doindenting{\indenting[\v!yes,\v!first]}
+
+%D This one sets up the local indentation behaviour (i.e. either or not
+%D a next paragraph will be indented).
+
+\def\dochecknextindentation#1% internal one
+ {\checknextindentation[\getvalue{#1\c!indentnext}]}
+
+\def\checknextindentation[#1]%
+ {\processaction
+ [#1]
+ [%\v!keep=>,
+ \v!yes=>\doindentation,
+ \v!no=>\noindentation,
+ \v!auto=>\autoindentation]}
+
+%D Here come the handlers.
+
+\newif\ifindentation \indentationtrue % documenteren, naar buiten
+
+\let\checkindentation\relax
+
+\ifx\autoindentation\undefined \let\autoindentation\relax \fi % hook
+
+\def\doindentation
+ {\gdef\checkindentation{\global\indentationtrue}}
+
+\def\noindentation % made global
+ {\ifinpagebody \else
+ \global\indentationfalse
+ \gdef\checkindentation
+ {\donoindentation
+ \gdef\checkindentation{\global\indentationtrue}}%
+ \fi}
+
+\def\nonoindentation % bv bij floats
+ {\ifinpagebody \else
+ \global\indentationtrue
+ \gdef\checkindentation{\global\indentationtrue}%
+ \fi}
+
+\def\donoindentation
+ {\ifdim\parindent=\zeropoint \else
+ \bgroup \setbox\scratchbox\lastbox \egroup
+ \fi}
+
+\def\indentation
+ {\ifvmode \ifdim\parindent=\zeropoint \else
+ % was : \hskip\parindent
+ % can be: \indent
+ % but we test:
+ \noindent\hskip\parindent
+ \fi \fi}
+
+\def\toggleindentation
+ {\ifcase\indentingtoggle
+ % nothing
+ \or
+ \notoggleindentation
+ \or
+ \dotoggleindentation
+ \fi}
+
+\def\dokillindentation
+ {\gdef\checkindentation{\global\indentationfalse\donoindentation}}
+
+\def\dotoggleindentation
+ {\gdef\checkindentation{\global\indentationfalse\notoggleindentation\donoindentation}}
+
+\def\notoggleindentation
+ {\gdef\checkindentation{\global\indentationtrue\dotoggleindentation}}
+
+\appendtoks
+ \pushmacro\checkindentation
+ \pushmacro\ifindentation
+\to \everypushsomestate
+
+\appendtoks
+ \popmacro\ifindentation
+ \popmacro\checkindentation
+\to \everypopsomestate
+
+% we need to save the state if we want to adapt behaviour to empty lines
+%
+% \def\setlasthvmode
+% {\global\chardef\savedhvmode\ifhmode\plusone\else\ifvmode\plustwo\else\zerocount\fi\fi}
+%
+% \def\resetlasthvmode
+% {\global\chardef\savedhvmode\zerocount}
+%
+% \chardef\savedhvmode\zerocount
+
+% This is a user requested hack (using the auto-hook).
+
+\chardef\recheckindentationmode\zerocount
+
+\def\dontrechecknextindentation
+ {\global\chardef\recheckindentationmode\zerocount}
+
+\def\dorechecknextindentation
+ {\ifcase\recheckindentationmode
+ % nothing
+ \or
+ \dontrechecknextindentation
+ \expandafter\doautoindentation
+ \fi}
+
+\def\doautoindentation
+ {\doifnextcharelse\par\donothing\noindentation}
+
+\def\autoindentation
+ {\global\chardef\recheckindentationmode\plusone}
+
+%D An example of usage:
+%D
+%D \starttyping
+%D \setupindenting[small,yes]
+%D
+%D \setupitemize [indentnext=auto]
+%D \setuptyping [indentnext=auto]
+%D \setupformulas[indentnext=auto]
+%D
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D
+%D \page
+%D
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D
+%D \page
+%D
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+%D
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+
+
+%D \macros
+%D {frenchspacing,nonfrenchspacing}
+%D
+%D Smehow \type{\frenchspacing} can lead to hyphenation between
+%D dashes so we now have \type {\newfrenchspacing} (moved from
+%D \type {syst-chr}).
+
+%D Hm ... todo:
+
+\sfcode`\)=0
+\sfcode`\'=0
+\sfcode`\]=0
+
+\def\setfrenchspacing#1%
+ {\sfcode`\.#1 \sfcode`\,#1\relax
+ \sfcode`\?#1 \sfcode`\!#1\relax
+ \sfcode`\:#1 \sfcode`\;#1\relax}
+
+\def\frenchspacing
+ {\setfrenchspacing{1000}}
+
+\def\resetfrenchspacing
+ {\sfcode`\.3000 \sfcode`\,1250
+ \sfcode`\?3000 \sfcode`\!3000
+ \sfcode`\:2000 \sfcode`\;1500 }
+
+\def\frenchspacing {\setfrenchspacing{1000}}
+\def\newfrenchspacing{\setfrenchspacing{1050}}
+\def\nonfrenchspacing{\resetfrenchspacing}
+
+\def\definespacingmethod[#1]#2{\setvalue{\??sg\??sg#1}{#2}}
+
+\definespacingmethod[\v!packed]{\newfrenchspacing}
+\definespacingmethod[\v!broad ]{\nonfrenchspacing}
+
+\def\complexsetupspacing[#1]%
+ {\executeifdefined{\??sg\??sg#1}\relax
+ \updateraggedskips}
+
+\def\simplesetupspacing
+ {\updateraggedskips}
+
+\definecomplexorsimple\setupspacing
+
+% \dorecurse{100}{\recurselevel\spacefactor 800 \space} \par
+% \dorecurse{100}{\recurselevel\spacefactor1200 \space} \par
+% \dorecurse{100}{\recurselevel\spacefactor 800 \normalspaceprimitive} \par
+% \dorecurse{100}{\recurselevel\spacefactor1200 \normalspaceprimitive} \par
+
+% When we don't add the % here, we effectively get \<endlinechar> and
+% since we have by default \def\^^M{\ } we get into a loop.
+
+\let\normalspaceprimitive=\ % space-comment is really needed
+
+\unexpanded\def\ {\mathortext\normalspaceprimitive\space} % no \dontleavehmode\space (else no frenchspacing)
+
+\unexpanded\def\nonbreakablespace{\penalty\plustenthousand\space}
+
+\letcatcodecommand \ctxcatcodes `\~ \nonbreakablespace % overloaded later
+
+\def\space { }
+\def\removelastspace{\ifhmode\unskip\fi}
+\def\nospace {\removelastspace\ignorespaces}
+
+% in tables we need:
+%
+% \def\fixedspace {\hskip.5em\relax}
+%
+% but, since not all fonts have .5em digits:
+
+\unexpanded\def\fixedspace
+ {\setbox\scratchbox\normalhbox{\mathortext{0}{0}}%
+ \hskip\wd\scratchbox\relax}
+
+\def\fixedspaces
+ {\letcatcodecommand \ctxcatcodes `\~ \fixedspace}
+
+\def\removeunwantedspaces
+ {\ifhmode % we also need to unskip 0pt skips
+ \unskip\unskip\unskip\unskip\unskip
+ \unskip\unskip\unskip\unskip\unskip
+ \fi}
+
+\appendtoks\let~\space\to\simplifiedcommands
+
+% still not fixed in aleph / luatex
+%
+% \def\removeunwantedspaces
+% {\ifhmode \ifnum\lastnodetype=\@@gluenode
+% \unskip \@EAEAEA\removeunwantedspaces
+% \fi \fi}
+
+%D For old time sake, will disappear soon.
+
+\let\hardespatie\fixedspace
+\let\geenspatie \nospace
+
+% \startbuffer
+% \startlines \tt \fixedspaces
+% 0~1~~2~~~3~~~~4~~~~~5
+% 0~~~~~~~~~~~~~~~~~~~5
+% $0~1~~2~~~3~~~~4~~~~~5$
+% $0~~~~~~~~~~~~~~~~~~~5$
+% \stoplines
+%
+% \starttabulate[|~|]
+% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \NR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \NR
+% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \NR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \NR
+% \stoptabulate
+%
+% \starttable[||]
+% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \AR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \AR
+% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \AR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \AR
+% \stoptable
+% \stopbuffer
+%
+% \setupbodyfont[cmr] \getbuffer
+% \setupbodyfont[lbr] \getbuffer
+
+\def\packed
+ {\nointerlineskip}
+
+\def\godown[#1]%
+ {\relax
+ \ifhmode\endgraf\fi
+ \ifvmode\nointerlineskip\vskip#1\relax\fi}
+
+%D A couple of plain macros:
+
+\ifx\thinspace\undefined
-\ifx\pdfkeeplinedimen\undefined
+ \def\thinspace {\kern .16667em }
+ \def\negthinspace{\kern-.16667em }
+ \def\enspace {\kern .5em }
- \let\mksetupgridsnapping \relax
- \let\mkenablegridsnapping \relax
- \let\mkdisablegridsnapping\relax
+ \def\thinspace {\kern .16667\emwidth}
+ \def\negthinspace{\kern-.16667\emwidth}
+ \def\enspace {\kern .5\emwidth}
+\fi
+
+\ifx\quad\undefined
+
+ \def\enskip{\hskip.5em\relax}
+ \def\quad {\hskip 1em\relax}
+ \def\qquad {\hskip 2em\relax}
+
+ \def\enskip{\hskip.5\emwidth}
+ \def\quad {\hskip \emwidth}
+ \def\qquad {\hskip 2\emwidth}
+
+\fi
+
+\let\emspace\quad
+
+\ifx\smallskip\undefined
+
+ \def\smallskip{\vskip\smallskipamount}
+ \def\medskip {\vskip\medskipamount}
+ \def\bigskip {\vskip\bigskipamount}
+
+\fi
+
+\ifx\allowbreak\undefined
+
+ \def\break {\penalty\ifhmode-\plustenthousand\else\ejectpenalty\fi}
+ \def\nobreak {\penalty \plustenthousand}
+ \def\allowbreak{\penalty \zeropoint}
+ \def\filbreak {\par\vfil\penalty-200\vfilneg}
+ \def\goodbreak {\par\penalty-500 }
+
+\fi
+
+%D Made slightly more readable:
+
+\ifx\vglue\undefined
+
+ \def\vglue {\afterassignment\dovglue\scratchskip=}
+ \def\hglue {\afterassignment\dohglue\scratchskip=}
+ \def\topglue{\nointerlineskip\vglue-\topskip\vglue}
+
+ \def\dovglue
+ {\par
+ \scratchdimen\prevdepth
+ \hrule\!!height\zeropoint
+ \nobreak\vskip\scratchskip
+ \prevdepth\scratchdimen}
+
+ \def\dohglue
+ {\dontleavehmode % \leavevmode
+ \scratchcounter\spacefactor
+ \vrule\!!width\zeropoint
+ \nobreak\hskip\scratchskip
+ \spacefactor\scratchcounter}
+
+\fi
+
+\ifx\eject\undefined
+
+ \def\eject{\par\break}
+
+\fi
+
+\ifx\supereject\undefined
+
+ \def\supereject{\par\penalty\superpenalty}
+
+\fi
+
+\ifx\dosupereject\undefined
+
+ \def\dosupereject
+ {\ifnum\insertpenalties>\zerocount % something is being held over
+ \line{}
+ \kern-\topskip
+ \nobreak
+ \vfill\supereject
+ \fi}
+
+\fi
+
+%D We adapt plain's \type {\removelastskip} a bit:
+
+\ifx\removelastskip\undefined
+
+ \def\removelastskip
+ {\ifvmode \ifdim\lastskip=\zeropoint \else
+ \vskip-\lastskip
+ \fi \fi}
+
+\fi
+
+\ifx\smallbreak\undefined
+
+\def\smallbreak
+ {\par
+ \ifdim\lastskip<\smallskipamount
+ \removelastskip
+ \penalty-50
+ \smallskip
+ \fi}
+
+\def\medbreak
+ {\par
+ \ifdim\lastskip<\medskipamount
+ \removelastskip
+ \penalty-100
+ \medskip
+ \fi}
+
+\def\bigbreak
+ {\par
+ \ifdim\lastskip<\bigskipamount
+ \removelastskip
+ \penalty-200
+ \bigskip
+ \fi}
+
+\fi
+
+\newskip\ctxparskip \ctxparskip\zeropoint
+
+\newconditional \flexiblewhitespace \settrue\flexiblewhitespace
+
+\def\blankokleinmaat {\smallskipamount}
+\def\blankomiddelmaat {\medskipamount}
+\def\blankogrootmaat {\bigskipamount}
+\def\currentwhitespace {\zeropoint}
+
+\definecomplexorsimple\setupwhitespace
+
+% \def\simplesetupwhitespace
+% {\doifnot\currentwhitespace\v!none\dosetupwhitespace}
+%
+% \def\complexsetupwhitespace[#1]%
+% {\doifelsenothing{#1}
+% {\simplesetupwhitespace}
+% {\edef\currentwhitespace{#1}%
+% \dosetupwhitespace}}
+%
+% \def\dosetupwhitespace
+% {\processcommacommand[\currentwhitespace]\dowhitespacemethod
+% \dodosetupwhitespace}
+
+\def\simplesetupwhitespace
+ {\doifnot\currentwhitespace\v!none\dosetupwhitespace}
+
+\def\complexsetupwhitespace[#1]%
+ {\edef\nextcurrentwhitespace{#1}%
+ \ifx\nextcurrentwhitespace\empty
+ \simplesetupwhitespace
+ \else
+ \let\currentwhitespace\nextcurrentwhitespace
+ \dosetupwhitespace
+ \fi}
+
+\def\dosetupwhitespace % quick test for no list
+ {\ifcsname\??ws\??ws\currentwhitespace\endcsname
+ \csname\??ws\??ws\currentwhitespace\endcsname
+ \else
+ \expandafter\processcommalist\expandafter[\currentwhitespace]\dowhitespacemethod % can be raw
+ \fi\relax
+ \ifgridsnapping
+ \setfalse\flexiblewhitespace
+ \ifdim\ctxparskip>\zeropoint
+ \ctxparskip
+ \ifcase\baselinegridmode
+ \baselineskip % normal ! ! ! ! !!
+ \or
+ \ifdim\scratchdimen=\baselineskip % maybe range
+ \baselineskip % normal ! ! ! ! !!
+ \else
+ \numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
+ \fi
+ \else
+ \baselineskip % normal ! ! ! ! !!
+ \fi
+ \fi
+ \else
+ \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
+ \fi
+ \parskip\ctxparskip}
+
+\chardef\baselinegridmode=0 % option in layout / 1=permit_half_lines
+
+\def\dodosetupwhitespace
+ {\ifgridsnapping
+ \setfalse\flexiblewhitespace
+ \ctxparskip1\ctxparskip
+ \ifdim\ctxparskip>\zeropoint
+ \ifcase\baselinegridmode
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \or
+ \ifdim\scratchdimen=\baselineskip % maybe range
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \else
+ \ctxparskip\numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
+ \fi
+ \else
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \fi
+ \fi
+ \else
+ \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
+ \fi
+ \parskip\ctxparskip}
+
+\definesystemvariable {ws} % whitespace
+
+\def\definewhitespacemethod[#1]#2{\setvalue{\??ws\??ws#1}{#2}}
+
+\definewhitespacemethod [\v!fix] {}
+\definewhitespacemethod [\v!fixed] {\setfalse\flexiblewhitespace}
+\definewhitespacemethod [\v!flexible] {\settrue\flexiblewhitespace}
+\definewhitespacemethod [\v!line] {\ctxparskip \baselineskip}
+\definewhitespacemethod [\v!halfline] {\ctxparskip.5\baselineskip}
+\definewhitespacemethod [\v!none] {\ctxparskip \zeropoint}
+\definewhitespacemethod [\v!big] {\ctxparskip \bigskipamount}
+\definewhitespacemethod [\v!medium] {\ctxparskip \medskipamount}
+\definewhitespacemethod [\v!small] {\ctxparskip \smallskipamount}
+
+\definewhitespacemethod [\s!default] {\simplesetupwhitespace} % {\stelwitruimteopnieuwin}
+
+% \def\dowhitespacemethod#1%
+% {\executeifdefined{\??ws\??ws#1}{\ctxparskip#1}\relax}
+
+\def\dowhitespacemethod#1%
+ {\ifcsname\??ws\??ws#1\endcsname\csname\??ws\??ws#1\endcsname\else\ctxparskip#1\fi\relax}
+
+\def\nowhitespace
+ {\ifdim\parskip>\zeropoint\relax
+ \ifdim\lastskip=-\parskip
+ \else
+ \vskip-\parskip
+ \fi
+ \fi}
+
+\def\nowhitespaceunlessskip
+ {\ifdim\lastskip>\zeropoint \else
+ \nowhitespace
+ \fi}
+
+\def\redowhitespace
+ {\ifdim\lastskip>-\parskip \else
+ \vskip\parskip
+ \fi}
+
+\def\savecurrentwhitespace
+ {\edef\restorecurrentwhitespace
+ {\ctxparskip\the\ctxparskip
+ \parskip\the\parskip
+ \noexpand\def\noexpand\currentwhitespace{\currentwhitespace}%
+ \ifconditional\flexiblewhitespace
+ \noexpand\settrue\flexiblewhitespace
+ \else
+ \noexpand\setfalse\flexiblewhitespace
+ \fi}}
+
+% deze variant is nodig binnen \startopelkaar
+% steeds testen:
+%
+% \hoofdstuk{..}
+% \plaatslijst[..]
+% \hoofdstuk{..}
+% \input tufte
+%
+% met/zonder witruimte
+
+\def\whitespace
+ {\par
+ \ifdim\parskip>\zeropoint\relax
+ %\ifdim\lastskip>\parskip \else
+ % \removelastskip interferes with blanko blokkeer en klein
+ \vskip\parskip
+ %\fi
+ \fi}
+
+\def\nonoblanko[#1]%
+ {\par}
+
+\def\noblanko
+ {\dosingleempty\nonoblanko}
+
+% De onderstaande macro handelt ook de situatie dat er geen
+% tekst tussen \start ... \stop is geplaatst. Daartoe wordt de
+% laatste skip over de lege tekst heen gehaald. Dit komt goed
+% van pas bij het plaatsen van (mogelijk lege) lijsten.
+
+\newif\ifopelkaar
+
+\newsignal \noparskipsignal % \def\noparskipsignal {0.00001pt}
+\def\lastdoneparskip {0pt}
+
+\def\startpacked
+ {\dosingleempty\dostartpacked}
+
+\def\dostartpacked[#1]% nesting afvangen
+ {\par
+ \ifvmode
+ \edef\lastdoneparskip {\the\lastskip}%
+ \edef\lastdoneprevdepth{\the\prevdepth}% zeer recent toegevoegd
+ \ifdim\prevdepth=-\thousandpoint % toegevoegd omdat binnen
+ \else % een vbox een extra skip
+ \whitespace % ongewenst is; dit kan
+ \baselinecorrection %% zie in \placeregister[n=1]
+ \vskip\noparskipsignal % waarschijnlijk ook in
+ \fi % blanko blokkeer
+ \bgroup
+ \doifelse{#1}\v!blank
+ \opelkaarfalse
+ \opelkaartrue
+ \blank[\v!disable] % dit is nog niet ok, gaat fout
+ \setupwhitespace[\v!none] % bovenin vtop (dwz, baseline)
+ \fi}
+
+\def\stoppacked
+ {\par
+ \ifvmode
+ \egroup
+ \ifdim\lastskip=\noparskipsignal\relax
+ \removelastskip
+ \nowhitespace
+ \vskip-\lastdoneparskip
+ \vskip+\lastdoneparskip
+ \prevdepth-\lastdoneprevdepth % zeer recent toegevoegd
+ \fi
+ \fi}
+
+\def\startunpacked
+ {\blank
+ \leavevmode
+ \bgroup}
+
+\def\stopunpacked
+ {\egroup
+ \blank}
+
+% De onderstaande macro's moeten nog eens nader worden uitgewerkt.
+% Ze spelen een rol bij de spatiering rond omkaderde teksten
+% en/of boxen zonder diepte.
+
+\def\toonregelcorrectie{\showbaselinecorrection}
+\def\regelcorrectie {\baselinecorrection}
+
+% \prevdepth crosses pageboundaries!
+%
+% todo: a version that works ok inside a box
+
+\let\doaroundlinecorrection\relax
+
+\def\startlinecorrection
+ {\dodoubleempty\dostartlinecorrection}
+
+\def\dostartlinecorrection[#1][#2]% #2 gobbles spaces
+ {\bgroup
+ \processaction
+ [#1]
+ [ \v!blank=>\let\doaroundlinecorrection\blank,
+ \s!default=>\let\doaroundlinecorrection\relax,
+ \s!unknown=>{\def\doaroundlinecorrection{\blank[#1]}}]%
+ \doaroundlinecorrection
+ \startbaselinecorrection
+ \offbaselinecorrection
+ \ignorespaces}
+
+\def\stoplinecorrection
+ {\stopbaselinecorrection
+ \doaroundlinecorrection
+ \egroup}
+
+\def\correctwhitespace
+ {\dowithnextbox
+ {\startbaselinecorrection
+ \flushnextbox
+ \stopbaselinecorrection}%
+ \vbox}
+
+\def\verticalstrut {\normalvbox{\hsize\zeropoint\forgetall\strut}}
+\def\horizontalstrut{\normalhbox {\strut}}
+
+% Hieronder volgen enkele instellingen en macro's ten behoeve
+% van de interlinie en \strut. De waarden 2.8, 0.07, 0.72 en
+% 0.28 zijn ooit eens ontleend aan INRS-TEX en moeten wellicht
+% nog eens instelbaar worden.
+%
+% \lineheight : de hoogte van een regel
+% \spacing{getal} : instellen interlinie
+% \normalbaselines : instellen regelafstend
+%
+% \setstrut : instellen \strut
+% \setnostrut : resetten \strut, \endstrut, \begstrut
+%
+% \setteststrut : instellen zichtbare struts
+% \resetteststrut : instellen onzichtbare struts
+%
+% \setfontparameters : instellen na fontset
+%
+% De hoogte van een regel (\lineheight) is gelijk aan de
+% som van de hoogte (\ht) en diepte (\dp) van \strutbox.
+%
+% \strut : denkbeeldig blokje met hoogte en diepte
+%
+% Een \hbox kan als deze aan het begin van een regel staat
+% een breedte \hsize krijgen. Dit is soms te voorkomen met het
+% commando \leavevmode. Binnen een \vbox geeft dit echter
+% niet altijd het gewenste resultaat, vandaar het commando
+%
+% \leaveoutervmode
+
+% Pas op: niet zomaar \topskip en \baselineskip aanpassen
+% en zeker niet \widowpenalty. Dit kan ernstige gevolgen
+% hebben voor kolommen.
+%
+% Enige glue kan op zich geen kwaad, echter als blanko=vast,
+% dan moet ook de rek 0 zijn. Binnen kolommen is rek ook
+% niet bepaald mooi. Een hele kleine waarde (0.025) voldoet,
+% omdat een positieve glue eindeloos rekbaar is.
+
+\newdimen\strutdimen
+\newdimen\lineheight
+\newdimen\openlineheight
+\newdimen\openstrutheight
+\newdimen\openstrutdepth
+\newdimen\topskipgap
+\newdimen\struttotal
+
+\def\strutheightfactor {.72}
+\def\strutdepthfactor {.28}
+
+\def\baselinefactor {2.8}
+\def\baselinegluefactor {0}
+
+\def\minimumstrutheight {0pt}
+\def\minimumstrutdepth {0pt}
+
+\def\normallineheight {\baselinefactor ex}
+\def\minimumlinedistance {\lineskip}
+
+\def\strutheight {0pt}
+\def\strutdepth {0pt}
+\def\strutwidth {0pt}
+
+\def\spacingfactor {1}
+
+\def\topskipfactor {1.0}
+\def\maxdepthfactor {0.5}
+
+\def\systemtopskipfactor {\topskipfactor}
+\def\systemmaxdepthfactor {\maxdepthfactor}
+
+% De onderstaande definitie wordt in de font-module overruled
+
+\ifdefined\globalbodyfontsize\else
+ \newdimen\globalbodyfontsize
+ \globalbodyfontsize=12pt
+\fi
+
+\ifx\normalizedbodyfontsize\undefined
+ \def\normalizedbodyfontsize{12pt}
+\fi
+
+% door een \dimen. Dit is geen probleem omdat (1) de default
+% korpsgrootte 12pt is en (2) de fonts nog niet geladen zijn
+% en de instellingen bij het laden nogmaals plaatsvinden.
+
+% \def\topskipcorrection
+% {\ifdim\topskip>\openstrutheight
+% % == \vskip\topskipgap
+% \vskip\topskip
+% \vskip-\openstrutheight
+% \fi
+% \verticalstrut
+% \vskip-\struttotal}
+
+\def\topskipcorrection
+ {\simpletopskipcorrection
+ \vskip-\struttotal
+ \verticalstrut}
+
+\def\simpletopskipcorrection
+ {\ifdim\topskip>\openstrutheight
+ % == \vskip\topskipgap
+ \vskip\topskip
+ \vskip-\openstrutheight
+ \fi}
+
+% \def\settopskip % the extra test is needed for the lbr family
+% {\topskip\systemtopskipfactor\globalbodyfontsize
+% \ifgridsnapping \else
+% \ifr@ggedbottom\!!plus5\globalbodyfontsize\fi
+% \fi
+% \relax % the skip
+% \topskipgap\topskip
+% \advance\topskipgap -\openstrutheight\relax
+% \ifdim\topskip<\strutheightfactor\openlineheight
+% \topskip\strutheightfactor\openlineheight\relax
+% \fi}
+
+\def\settopskip % the extra test is needed for the lbr family
+ {\topskip\systemtopskipfactor\globalbodyfontsize
+ \ifgridsnapping \else
+ \ifr@ggedbottom\!!plus5\globalbodyfontsize\fi
+ \fi
+ \relax % the skip
+ \topskipgap\topskip
+ \advance\topskipgap -\openstrutheight\relax
+\ifdim\minimumstrutheight>\zeropoint
+ \ifdim\topskip<\minimumstrutheight
+ \topskip\minimumstrutheight\relax
+ \fi
\else
+ \ifdim\topskip<\strutheightfactor\openlineheight
+ \topskip\strutheightfactor\openlineheight\relax
+ \fi
+\fi}
+
+\def\setmaxdepth
+ {\maxdepth\systemmaxdepthfactor\globalbodyfontsize}
+
+\def\normalbaselines
+ {\baselineskip \normalbaselineskip
+ \lineskip \normallineskip
+ \lineskiplimit\normallineskiplimit}
+
+% \def\setnormalbaselines
+% {\ifdim\normallineheight>\zeropoint
+% \lineheight\normallineheight
+% \fi
+% \openlineheight\spacingfactor\lineheight
+% \openstrutheight\strutheightfactor\openlineheight
+% \openstrutdepth \strutdepthfactor \openlineheight
+% \normalbaselineskip\openlineheight
+% \!!plus\baselinegluefactor\openlineheight
+% \!!minus\baselinegluefactor\openlineheight
+% \normallineskip\minimumlinedistance\relax % \onepoint\relax
+% \normallineskiplimit\zeropoint\relax
+% \normalbaselines}
+
+\def\setnormalbaselines
+ {\ifdim\normallineheight>\zeropoint
+ \lineheight\normallineheight
+ \fi
+ \openlineheight\spacingfactor\lineheight
+ \openstrutheight \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight % new
+ \else
+ \strutheightfactor\openlineheight
+ \fi
+ \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth % new
+ \else
+ \strutdepthfactor \openlineheight
+ \fi
+ \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint
+ \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new
+ \fi
+ \normalbaselineskip\openlineheight
+ \ifgridsnapping\else
+ \!!plus \baselinegluefactor\openlineheight
+ \!!minus\baselinegluefactor\openlineheight
+ \fi
+ \normallineskip\minimumlinedistance\relax % \onepoint\relax
+ \normallineskiplimit\zeropoint\relax
+ \normalbaselines}
+
+% \def\setspacingfactor#1\to#2\by#3\\%
+% {\strutdimen#2\points
+% \strutdimen#3\strutdimen
+% \edef#1{\withoutpt\the\strutdimen}}
+%
+% \def\spacing#1%
+% {\ifgridsnapping
+% %\doifnot{#1}{1}{\showmessage\m!layouts{11}{#1}}%
+% \ifdim#1\points=\onepoint\else\showmessage\m!layouts{11}{#1}\fi
+% \edef\spacingfactor{1}%
+% \else
+% \edef\spacingfactor{#1}%
+% \fi
+% \setspacingfactor\systemtopskipfactor \to\topskipfactor \by#1\\% why no \spacingfactor ?
+% \setspacingfactor\systemmaxdepthfactor\to\maxdepthfactor\by#1\\% why no \spacingfactor ?
+% \setnormalbaselines
+% \setstrut}
+%
+% \def\setspacingfactor#1#2#3%
+% {\edef#1{\withoutpt\the\dimexpr#2\points*#3\relax}}
+
+\def\spacing#1%
+ {\ifgridsnapping
+ \ifdim#1\points=\onepoint\else\showmessage\m!layouts{11}{#1}\fi
+ \edef\spacingfactor{1}%
+ \else
+ \edef\spacingfactor{#1}%
+ \fi
+ %\setspacingfactor\systemtopskipfactor \topskipfactor {#1}% why no \spacingfactor ?
+ %\setspacingfactor\systemmaxdepthfactor\maxdepthfactor{#1}% why no \spacingfactor ?
+ \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}%
+ \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}%
+ \setnormalbaselines
+ \setstrut}
+
+%D Sometimes one needs to freeze the interlinespacing
+%D
+%D \starttyping
+%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf}
+%D \stoptyping
+
+\let\restoreinterlinespace\relax
+
+\def\saveinterlinespace
+ {\edef\restoreinterlinespace
+ {\lineheight \the\lineheight
+ \openstrutheight \the\openstrutheight
+ \openstrutdepth \the\openstrutdepth
+ \openlineheight \the\openlineheight
+ \normalbaselineskip \the\normalbaselineskip
+ \normallineskip \the\normallineskip
+ \normallineskiplimit\the\normallineskiplimit
+ \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
+ \noexpand\normalbaselines}}
+
+% plain definition:
+%
+% \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%
+% could be:
+%
+% \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+
+\ifx\strutbox\undefined
+
+ \newbox\strutbox
+
+ \setbox\strutbox=\normalhbox{\vrule height8.5pt depth3.5pt width\zeropoint}
+
+ %\def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+ \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+
+\fi
+
+\let\normalstrut\strut
+
+% The double \hbox construction enables us to \backtrack
+% boxes.
+
+% \def\setstrutdimen#1#2#3% % een strut is n.m maal ex
+% {\strutdimen\normallineheight % wat niet per se \lineheight
+% \strutdimen#2\strutdimen % is omdat een strut lokaal
+% \strutdimen#3\strutdimen % kan afwijken van de globale
+% \edef#1{\the\strutdimen}} % macro % strut
+
+% \def\setstrutdimen#1#2#3% % een strut is n.m maal ex
+% {\strutdimen\normallineheight % wat niet per se \lineheight
+% \strutdimen#2\strutdimen % is omdat een strut lokaal
+% \strutdimen#3\strutdimen % kan afwijken van de globale
+% \edef#1{\the\strutdimen}} % macro % strut
+
+% \def\setstrut
+% {\setstrutdimen\strutheight\strutheightfactor\spacingfactor
+% \setstrutdimen\strutdepth \strutdepthfactor \spacingfactor
+% \let\strut=\normalstrut
+% \setbox\strutbox=\normalhbox
+% {\normalhbox
+% {\vrule
+% \!!width \strutwidth
+% \!!height \strutheight
+% \!!depth \strutdepth
+% \normalkern-\strutwidth}}}
+
+% \def\setstrut
+% {\setstrutdimen\strutheight\strutheightfactor\spacingfactor
+% \setstrutdimen\strutdepth \strutdepthfactor \spacingfactor
+% \dosetstrut}
+
+% \def\setstrut
+% {\strutdimen\normallineheight
+% \strutdimen\strutheightfactor\strutdimen
+% \strutdimen\spacingfactor\strutdimen
+% \edef\strutheight{\the\strutdimen}%
+% \strutdimen\normallineheight
+% \ifgridsnapping
+% \advance\strutdimen-\strutheight
+% \else
+% \strutdimen\strutdepthfactor\strutdimen
+% \strutdimen\spacingfactor\strutdimen
+% \fi
+% \edef\strutdepth{\the\strutdimen}%
+% \dosetstrut}
+
+% interesting, strutdepth is 4.05064pt vs 4.05066pt depending on grid
+% nasty rounding problem
+
+% \def\setstrut
+% {% height
+% \strutdimen\normallineheight
+% \ifdim\minimumstrutheight>\zeropoint
+% \strutdimen\minimumstrutheight
+% \else
+% \strutdimen\strutheightfactor\strutdimen
+% \fi
+% \strutdimen\spacingfactor\strutdimen
+% \edef\strutheight{\the\strutdimen}%
+% % depth
+% \strutdimen\normallineheight
+% \ifgridsnapping
+% \ifdim\minimumstrutdepth>\zeropoint
+% \strutdimen\minimumstrutdepth
+% \else
+% \advance\strutdimen-\strutheight
+% \fi
+% \else
+% \ifdim\minimumstrutdepth>\zeropoint
+% \strutdimen\minimumstrutdepth
+% \else
+% \strutdimen\strutdepthfactor\strutdimen
+% \fi
+% \strutdimen\spacingfactor\strutdimen
+% \fi
+% \edef\strutdepth{\the\strutdimen}%
+% % finish
+% \dosetstrut}
+
+% \def\setstrut
+% {% height
+% \ifdim\minimumstrutheight>\zeropoint
+% \edef\strutheight{\the\dimexpr\spacingfactor\dimexpr\minimumstrutheight}%
+% \else
+% \edef\strutheight{\the\dimexpr\spacingfactor\dimexpr\strutheightfactor\dimexpr\normallineheight}%
+% \fi
+% % depth
+% \ifgridsnapping
+% \ifdim\minimumstrutdepth>\zeropoint
+% \edef\strutdepth{\the\dimexpr\minimumstrutdepth}%
+% \else
+% \edef\strutdepth{\the\dimexpr\normallineheight-\strutheight}%
+% \fi
+% \else
+% \ifdim\minimumstrutdepth>\zeropoint
+% \edef\strutdepth{\the\dimexpr\spacingfactor\dimexpr\minimumstrutdepth}%
+% \else
+% \edef\strutdepth{\the\dimexpr\spacingfactor\dimexpr\strutdepthfactor\dimexpr\normallineheight}%
+% \fi
+% \fi
+% % finish
+% \dosetstrut}
+
+\unexpanded\def\setstrut
+ {% height
+ \edef\strutheight
+ {\the\dimexpr\spacingfactor\dimexpr
+ \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight
+ \else
+ \strutheightfactor\dimexpr\normallineheight
+ \fi}%
+ % depth
+ \edef\strutdepth
+ {\the\dimexpr
+ \ifgridsnapping
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \normallineheight-\strutheight
+ \fi
+ \else
+ \spacingfactor\dimexpr
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \strutdepthfactor\dimexpr\normallineheight
+ \fi
+ \fi}%
+ % finish
+ \dosetstrut}
+
+\unexpanded\def\setcharstrut#1%
+ {\setbox\strutbox\normalhbox{#1}%
+ \edef\strutheight{\the\strutht}%
+ \edef\strutdepth {\the\strutdp}%
+ \dosetstrut}
+
+% \def\setfontstrut
+% {\setcharstrut{(}}
+%
+% better, since some fonts have small (but descending Q etc)
+
+\unexpanded\def\setfontstrut
+ {\setcharstrut{(gplQT}}
+
+\unexpanded\def\setcapstrut% could be M, but Q has descender
+ {\setcharstrut{Q}}
+
+%D Handy for math (used in mathml):
+
+\def\charhtstrut
+ {\begingroup
+ \setcharstrut{GJY}%
+ \vrule\!!width\zeropoint\!!depth\zeropoint\!!height\strutht
+ \endgroup}
+
+\def\chardpstrut
+ {\begingroup
+ \setcharstrut{gjy}%
+ \vrule\!!width\zeropoint\!!depth\strutdp\!!height\zeropoint
+ \endgroup}
+
+%D Centered looks nicer:
+
+% \def\dosetstrut
+% {\let\strut\normalstrut
+% \setbox\strutbox\normalhbox
+% {\normalhbox to \zeropoint
+% {% \hss % new, will be option
+% \vrule
+% \!!width \strutwidth
+% \!!height\strutheight
+% \!!depth \strutdepth
+% \hss}}%
+% \struttotal\dimexpr\strutht+\strutdp\relax}
+%
+% because of all the callbacks in mkiv, we avoid unnecessary boxes ...
+% maybe use an attribute so that we can tag boxes that don't need a
+% treatment; tests with using an attribute so far have shown that
+% it's slower because testing the attribute takes time too
+
+\def\dosetstrut
+ {\let\strut\normalstrut
+ \ifdim\strutwidth=\zeropoint
+ \setbox\strutbox\normalhbox
+ {\vrule
+ \!!width \zeropoint
+ \!!height\strutheight
+ \!!depth \strutdepth}%
+ \else
+ \setbox\strutbox\normalhbox
+ {\normalhbox to \zeropoint
+ {% \hss % new, will be option
+ \vrule
+ \!!width \strutwidth
+ \!!height\strutheight
+ \!!depth \strutdepth
+ \hss}}%
+ \fi
+ \struttotal\dimexpr\strutht+\strutdp\relax}
+
+%D The dimen \type {\struttotal} holds the exact size of the
+%D strut; occasionally a one scaled point difference can show
+%D up with the lineheight.
+
+%D Sometimes a capstrut comes in handy
+%D
+%D \starttabulate[|Tl|l|l|]
+%D \NC yes \NC normal strut \NC {\showstruts\setupstrut[yes]\strut} \NC \NR
+%D \NC no \NC no strut \NC {\showstruts\setupstrut[no]\strut} \NC \NR
+%D \NC kap \NC a capital strut (i.e. Q) \NC {\showstruts\setupstrut[cap]\strut} \NC \NR
+%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR
+%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR
+%D \stoptabulate
+
+\def\setupstrut
+ {\dosingleempty\dosetupstrut}
+
+\def\dosetupstrut[#1]% yet undocumented, todo: fontstrut
+ {\processaction
+ [#1]
+ [ \v!yes=>\setstrut,
+ \v!auto=>\setautostrut,
+ \v!no=>\setnostrut,
+ \v!cap=>\setcapstrut,
+ \v!fit=>\setfontstrut,
+ \v!line=>\setstrut,
+ \s!default=>\setstrut,
+ \s!unknown=>\setcharstrut\commalistelement]}
+
+\def\setteststrut
+ {\def\strutwidth{.8pt}%
+ \setstrut}
+
+\def\autostrutfactor{1.1}
+
+\def\setautostrut
+ {\begingroup
+ \setbox\scratchbox\copy\strutbox
+ \setstrut
+ \ifdim\ht\strutbox>\autostrutfactor\ht\scratchbox
+ \endgroup \setstrut
+ \else\ifdim\dp\strutbox>\autostrutfactor\dp\scratchbox
+ \endgroup \setstrut
+ \else
+ \endgroup
+ \fi\fi}
+
+% simple version
+%
+% \def\begstrut
+% {\relax\ifcase\strutht\else
+% \strut
+% \normalpenalty\plustenthousand
+% \normalhskip\zeropoint
+% \ignorespaces
+% \fi}
+%
+% \def\endstrut
+% {\relax\ifhmode\ifcase\strutht\else
+% \removeunwantedspaces
+% \normalpenalty\plustenthousand
+% \normalhskip\zeropoint
+% \strut
+% \fi\fi}
+
+% when enabled, sigstruts will remove themselves if nothing
+% goes inbetween
+
+\newsignal\strutsignal \setfalse\sigstruts
+
+\def\begstrut
+ {\relax\ifcase\strutht\else
+ \ifconditional\sigstruts
+ \noindent\horizontalstrut
+ \normalpenalty\plustenthousand
+ \normalhskip-\strutsignal
+ \normalhskip\strutsignal
+ \else
+ \strut
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \fi
+ \expandafter \ignorespaces
+ \fi}
+
+\def\endstrut
+ {\relax\ifhmode\ifcase\strutht\else
+ \ifconditional\sigstruts
+ \ifdim\lastskip=\strutsignal
+ \unskip\unskip\unpenalty\setbox\scratchbox\lastbox
+ \else
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \strut
+ \fi
+ \else
+ \removeunwantedspaces
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \strut
+ \fi
+ \fi\fi}
+
+\newbox\nostrutbox \setbox\nostrutbox\normalhbox{} % {\normalhbox{}}
+
+\def\setnostrut
+ {\setbox\strutbox\copy\nostrutbox
+ \let\strut\empty
+ \let\endstrut\empty
+ \let\begstrut\empty
+ \let\crlfplaceholder\empty}
+
+% unsave:
+%
+% \def\pseudostrut
+% {\bgroup
+% \setnostrut
+% \normalstrut
+% \egroup}
+%
+% try:
+%
+% \startchemie
+% \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C]
+% \stopchemie
+%
+% so:
+
+\def\pseudostrut
+ {\noindent} % better: \dontleavehmode
+
+\let\pseudobegstrut\pseudostrut
+
+\let\pseudoendstrut\removeunwantedspaces
+
+\def\resetteststrut
+ {\let\strutwidth\zeropoint
+ \setstrut}
+
+\ifx\setfontparameters\undefined
+ % problems ! ! ! !
+ \def\setfontparameters{\the\everybodyfont}
+\fi
+
+%D Handy:
+
+\def\baselinedistance{\the\lineheight}
+
+%D We need \type{\normaloffinterlineskip} because the new
+%D definition contains an assignment, and |<|don't ask me
+%D why|>| this assignment gives troubles in for instance the
+%D visual debugger.
+
+%D The plain ones:
+
+\def\offinterlineskip
+ {\baselineskip-\thousandpoint
+ \lineskip\zeropoint
+ \lineskiplimit\maxdimen}
+
+\def\nointerlineskip
+ {\prevdepth-\thousandpoint}
+
+\let\normaloffinterlineskip=\offinterlineskip % knuth's original
+
+%D My own one:
+
+\def\offinterlineskip
+ {\ifdim\baselineskip>\zeropoint
+ \edef\oninterlineskip
+ {\baselineskip\the\baselineskip
+ \lineskip\the\lineskip
+ \lineskiplimit\the\lineskiplimit
+ \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}%
+ \else
+ \let\oninterlineskip\setnormalbaselines
+ \fi
+ \normaloffinterlineskip}
+
+\let\oninterlineskip=\relax
+
+\def\leaveoutervmode
+ {\ifvmode\ifinner\else
+ \leavevmode
+ \fi\fi}
+
+% We stellen enkele penalties anders in dan Plain TEX:
+
+% oud
+%
+% \widowpenalty=\defaultwidowpenalty\relax
+% \clubpenalty =\defaultclubpenalty \relax
+
+\def\resetpenalties#1%
+ {\ifx#1\undefined\else
+ #1\minusone
+ \fi}
- \def\mksetupgridsnapping
- {\pdfeachlineheight \openstrutheight
- \pdfeachlinedepth \openstrutdepth
- \pdffirstlineheight \pdfeachlineheight
- \pdflastlinedepth \pdfeachlinedepth}
+\def\setpenalties#1#2#3%
+ {\ifx#1\undefined\else % space before #3 prevents lookahead problems, needed when #3=text
+ #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax
+ \fi}
- \def\mkenablegridsnapping
- {\pdfkeeplinedimen\maxdimen
- \topskip\strutht
- \offinterlineskip}
+\def\doexpandedrecurse#1#2%
+ {\ifnum#1>\zerocount#2\@EA\doexpandedrecurse\@EA{\the\numexpr#1-1\relax}{#2}\fi}
- \def\mkdisablegridsnapping
- {\pdfkeeplinedimen\zeropoint
- % reset topskip
- \oninterlineskip}
+%D \macros
+%D {keeplinestogether}
+%D
+%D Dirty hack, needed in margin content that can run of a page.
+
+\def\keeplinestogether#1%
+ {\xdef\restoreinterlinepenalty{\global\resetpenalties\interlinepenalties}%
+ \global\setpenalties\interlinepenalties{#1}\plustenthousand}
+
+\newif\ifgridsnapping % to be sure
+
+\def\defaultwidowpenalty {2000} % was: 1000
+\def\defaultclubpenalty {2000} % was: 800
+\def\defaultdisplaywidowpenalty {50}
+\def\defaultbrokenpenalty {100}
+
+\def\defaultgridwidowpenalty {0}
+\def\defaultgridclubpenalty {0}
+\def\defaultgriddisplaywidowpenalty {0}
+\def\defaultgridbrokenpenalty {0}
+
+% The original approach:
+%
+% \def\setdefaultpenalties
+% {\ifgridsnapping
+% \widowpenalty\defaultgridwidowpenalty
+% \clubpenalty \defaultgridclubpenalty
+% \else
+% \widowpenalty\defaultwidowpenalty
+% \clubpenalty \defaultclubpenalty
+% \fi}
+%
+% However, we will use setups:
+
+% to be documented
+
+\def\nopenalties
+ {\widowpenalty \zerocount
+ \clubpenalty \zerocount
+ \brokenpenalty \zerocount
+ \doublehyphendemerits\zerocount
+ \finalhyphendemerits \zerocount
+ \adjdemerits \zerocount}
+
+\def\setdefaultpenalties
+ {\directsetup{\systemsetupsprefix\s!default}}
+
+\startsetups [\systemsetupsprefix\s!reset]
+ \resetpenalties\widowpenalties
+ \resetpenalties\clubpenalties
+ \resetpenalties\interlinepenalties
+\stopsetups
+
+% we use \directsetup because it's faster and we know there is no csl
+
+\startsetups [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultwidowpenalty
+ \clubpenalty \defaultclubpenalty
+ \displaywidowpenalty\defaultdisplaywidowpenalty
+ \brokenpenalty \defaultbrokenpenalty
+
+\stopsetups
+
+\startsetups [\v!grid] [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultgridwidowpenalty
+ \clubpenalty \defaultgridclubpenalty
+ \displaywidowpenalty\defaultgriddisplaywidowpenalty
+ \brokenpenalty \defaultgridbrokenpenalty
+
+\stopsetups
+
+% as an illustration:
+
+\startsetups [\systemsetupsprefix\v!strict]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \setpenalties\widowpenalties2\maxdimen
+ \setpenalties\clubpenalties 2\maxdimen
+ \brokenpenalty \maxdimen
+
+\stopsetups
+
+\setdefaultpenalties % will happen later in \setuplayout
+
+% Suggested by GB (not the name -):
+
+\def\rapfillskip{.5\hsize plus .092\hsize minus .5\hsize} % D.A.'s value
+
+% Bovendien definieren we enkele extra \fill's:
+
+\def\hfilll{\hskip\zeropoint\!!plus1filll\relax}
+\def\vfilll{\vskip\zeropoint\!!plus1filll\relax}
+
+% De onderstaande hulpmacro's moeten nog eens instelbaar worden
+% gemaakt.
+
+\def\tfskipsize{1em\relax}
+\def\tfkernsize{1ex\relax}
+
+\def\tfskip{\dotfskip\tfskipsize}
+\def\tfkern{\dotfkern\tfkernsize}
+
+\def\dotfskip#1{{\tf\hskip#1}}
+\def\dotfkern#1{{\tf\kern #1}}
+
+% needs a proper \definenarrower or installnarrower
+
+\newskip\ctxleftskip
+\newskip\ctxrightskip
+\newskip\ctxmidskip
+
+\def\dosinglenarrower#1%
+ {\processaction
+ [#1]
+ [ \v!left=>\global\advance\ctxleftskip \@@slleft,
+ \v!middle=>\global\advance\ctxmidskip \@@slmiddle,
+ \v!right=>\global\advance\ctxrightskip \@@slright,
+ \v!reset=>\global\ctxleftskip \zeropoint
+ \global\ctxmidskip \zeropoint
+ \global\ctxrightskip\zeropoint,
+ \v!none=>,
+ \s!unknown=>\global\advance\ctxmidskip \commalistelement]}
+
+% \def\donarrower[#1]% hm, can be dorepeat directly
+% {\processaction
+% [#1]
+% [ \v!left=>\global\advance\ctxleftskip \@@slleft,
+% \v!middle=>\global\advance\ctxmidskip \@@slmiddle,
+% \v!right=>\global\advance\ctxrightskip \@@slright,
+% \v!none=>,% handy for delimitedtexts
+% \s!unknown=>{\dorepeatwithcommand[#1]\dosinglenarrower}]}
+
+\def\donarrower[#1]% hm, can be dorepeat directly
+ {\dorepeatwithcommand[#1]\dosinglenarrower}
+
+\def\complexstartnarrower[#1]%
+ {\@@slbefore % was hard coded \par
+ \bgroup
+ \global\ctxleftskip \zeropoint
+ \global\ctxrightskip\zeropoint
+ \global\ctxmidskip \zeropoint
+ \processcommalistwithparameters[#1]\donarrower
+ \advance\leftskip \ctxleftskip
+ \advance\rightskip \ctxrightskip
+ \advance\leftskip \ctxmidskip
+ \advance\rightskip \ctxmidskip
+ \seteffectivehsize}
+
+% todo: definenarrower
+
+\def\simplestartnarrower
+ {\startnarrower[\v!middle]}
+
+\definecomplexorsimple\startnarrower
+
+\def\stopnarrower
+ {\@@slafter % was hard coded \par / needed, else skips forgotten
+ \egroup}
+
+\def\setupnarrower
+ {\dodoubleargument\getparameters[\??sl]}
+
+\newdimen\@@effectivehsize \def\effectivehsize {\hsize}
+\newdimen\@@effectiveleftskip \def\effectiveleftskip {\leftskip}
+\newdimen\@@effectiverightskip \def\effectiverightskip{\rightskip}
+
+\def\seteffectivehsize
+ {\setlocalhsize
+ \@@effectivehsize \localhsize
+ \@@effectiveleftskip \leftskip
+ \@@effectiverightskip \rightskip
+ \let\effectivehsize \@@effectivehsize
+ \let\effectiveleftskip \@@effectiveleftskip
+ \let\effectiverightskip\@@effectiverightskip}
+
+\def\dodefinehbox[#1][#2]%
+ {\setvalue{hbox#1}##1%
+ {\hbox to #2{\begstrut##1\endstrut\hss}}}
+
+\def\definehbox
+ {\dodoubleargument\dodefinehbox}
+
+\def\iobox#1#2#3#% here #3# is not really needed
+ {\vbox\bgroup % we want to return a vbox like the others
+ \hbox\bgroup% we need to pack the signal with the box
+ \signalrightpage
+ \dowithnextboxcontent
+ {\let\\=\endgraf\forgetall\doifrightpageelse#1#2}
+ {\box\nextbox\egroup\egroup}
+ \vbox#3}
+
+\def\obox{\iobox\raggedleft \raggedright} % outerbox
+\def\ibox{\iobox\raggedright\raggedleft} % innerbox
+
+\def\dosetraggedvbox#1%
+ {\let\raggedbox\vbox
+ \processfirstactioninset
+ [#1]
+ [ \v!left=>\let\raggedbox\lbox,
+ \v!right=>\let\raggedbox\rbox,
+ \v!middle=>\let\raggedbox\cbox,
+ \v!inner=>\let\raggedbox\ibox,
+ \v!outer=>\let\raggedbox\obox,
+ \v!flushleft=>\let\raggedbox\rbox,
+ \v!flushright=>\let\raggedbox\lbox,
+ \v!center=>\let\raggedbox\cbox,
+ \v!no=>\def\raggedbox{\vbox\bgroup\raggedright\let\next=}]}
+
+\def\dosetraggedhbox#1%
+ {\let\raggedbox\hbox
+ \processaction % slow
+ [#1]
+ [ \v!left=>\def\raggedbox{\doalignedline\v!left },
+ \v!right=>\def\raggedbox{\doalignedline\v!right },
+ \v!middle=>\def\raggedbox{\doalignedline\v!middle},
+ \v!inner=>\def\raggedbox{\doalignedline\v!inner },
+ \v!outer=>\def\raggedbox{\doalignedline\v!outer },
+ \v!flushleft=>\def\raggedbox{\doalignedline\v!right },
+ \v!flushright=>\def\raggedbox{\doalignedline\v!left },
+ \v!center=>\def\raggedbox{\doalignedline\v!middle}]}
+
+\def\dosetraggedcommand#1%
+ {\expanded{\dodosetraggedcommand{#1}}}
+
+% \def\dodosetraggedcommand#1% beware: #1=empty is ignored, keep that!
+% {\let\raggedcommand \relax
+% \let\raggedtopcommand \empty
+% \let\raggedbottomcommand\empty
+% \chardef\raggedoneliner\zerocount
+% \doifsomething{#1}
+% {\doifinsetelse\v!broad{#1}\!!doneatrue\!!doneafalse
+% \doifinsetelse\v!wide {#1}\!!donebtrue\!!donebfalse
+% \!!donectrue
+% \rawprocesscommalist[#1]\dododosetraggedcommand}}
+
+\newtoks\everyraggedcommand
+
+\def\raggedcommand{\the\everyraggedcommand}
+
+\def\dodosetraggedcommand#1% beware: #1=empty is ignored, keep that!
+ {\everyraggedcommand \emptytoks
+ \let\raggedtopcommand \empty
+ \let\raggedbottomcommand\empty
+ \chardef\raggedoneliner\zerocount
+ \doifsomething{#1}
+ {\doifinsetelse\v!broad{#1}\!!doneatrue\!!doneafalse
+ \doifinsetelse\v!wide {#1}\!!donebtrue\!!donebfalse
+ \!!donectrue
+ \rawprocesscommalist[#1]\dododosetraggedcommand}}
+
+\def\dododosetraggedcommand#1%
+ {\executeifdefined{\@@ragged@@command\string#1}\relax}
+
+\def\@@ragged@@command{@@raggedcommand}
+
+\setvalue{\@@ragged@@command\v!hanging }{\appendtoks\enableprotruding \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nothanging }{\appendtoks\disableprotruding \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!hz }{\appendtoks\enableadjusting \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nohz }{\appendtoks\disableadjusting \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!spacing }{\appendtoks\enablespacehandling
+ \enablekernhandling \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nospacing }{\appendtoks\disablespacehandling
+ \disablekernhandling \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!hyphenated }{\appendtoks\dohyphens \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nothyphenated}{\appendtoks\nohyphens \to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!tolerant }{\appendtoks\tolerance3000\relax \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!verytolerant}{\appendtoks\tolerance4500\relax \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!stretch }{\appendtoks\emergencystretch\bodyfontsize\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!left}%
+ {\if!!donea \appendtoks\veryraggedleft\to\everyraggedcommand
+ \else \appendtoks\raggedleft \to\everyraggedcommand
+ \fi
+ \!!donecfalse}
+
+\setvalue{\@@ragged@@command\v!right}%
+ {\if!!donea \appendtoks\veryraggedright\to\everyraggedcommand
+ \else \appendtoks\raggedright \to\everyraggedcommand
+ \fi
+ \!!donecfalse}
+
+\setvalue{\@@ragged@@command\v!middle}%
+ {\if!!donec
+ \if!!doneb \appendtoks\raggedwidecenter\to\everyraggedcommand
+ \else\if!!donea \appendtoks\veryraggedcenter\to\everyraggedcommand
+ \else \appendtoks\raggedcenter \to\everyraggedcommand
+ \fi\fi
+ \!!donecfalse
+ \else
+ \let\raggedbottomcommand\vfilll % bonus, pretty strong
+ \let\raggedtopcommand \vfilll % used with \framed for
+ \fi} % instance in tables
+
+\setvalue{\@@ragged@@command\v!flushleft }{\getvalue{\@@ragged@@command\v!right }}
+\setvalue{\@@ragged@@command\v!flushright}{\getvalue{\@@ragged@@command\v!left }}
+\setvalue{\@@ragged@@command\v!center }{\getvalue{\@@ragged@@command\v!middle}}
+
+\setvalue{\@@ragged@@command\v!high}%
+ {\let\raggedbottomcommand\vfilll} % and since we lack a
+
+\setvalue{\@@ragged@@command\v!low}%
+ {\let\raggedtopcommand\vfilll} % proper keyword, but
+
+\setvalue{\@@ragged@@command\v!lohi}%
+ {\let\raggedbottomcommand\vfilll % we do support the
+ \let\raggedtopcommand\vfilll} % ugly laho (lohi)
+
+\setvalue{\@@ragged@@command\v!no}%
+ {\appendtoks\raggedright\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!yes}%
+ {\appendtoks\notragged\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!normal}%
+ {\appendtoks\notragged\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!inner}% not yet perfect
+ {\signalrightpage % may interfere
+ \doifrightpageelse
+ {\getvalue{\@@ragged@@command\v!right}}
+ {\getvalue{\@@ragged@@command\v!left}}}
+
+\setvalue{\@@ragged@@command\v!outer}% not yet perfect
+ {\signalrightpage % may interfere
+ \doifrightpageelse
+ {\getvalue{\@@ragged@@command\v!left}}
+ {\getvalue{\@@ragged@@command\v!right}}}
+
+\setvalue{\@@ragged@@command\v!lesshyphenation}%
+ {\appendtoks\lesshyphens\to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!morehyphenation}%
+ {\appendtoks\morehyphens\to\everyraggedcommand}
+
+% compare:
+%
+% \framed[width=4cm,align=no] {\hfil xxx}
+% \framed[width=4cm,align=disable]{\hfil xxx}
+
+\setvalue{\@@ragged@@command\v!disable}% for one liners
+ {\appendtoks\raggedright\parfillskip\zeropoint\to\everyraggedcommand}
+
+\chardef\raggedoneliner\zerocount
+
+\setvalue{\@@ragged@@command\v!line}%
+ {\chardef\raggedoneliner\plusone}
+
+%D Unofficial, may disappear. Now handled directly in the
+%D core-rul module.
+
+% \def\@@startraggedoneliner
+% {\ifcase\raggedoneliner\else
+% \dontleavehmode\hbox to \hsize \bgroup % hsize added, else useless
+% \ifcase\raggedstatus\or\hss\or\hss\fi
+% \ignorespaces
+% \bgroup
+% \aftergroup\removeunwantedspaces
+% \fi}
+
+% \def\@@stopraggedoneliner
+% {\ifcase\raggedoneliner\else
+% \egroup
+% \ifcase\raggedstatus\or\or\hss\or\hss\fi
+% \egroup
+% \ignorespaces % ? ? ?
+% \fi}
+
+% \def\@@handleoneliner
+% {\ifcase\raggedoneliner\else
+% \@@startraggedoneliner
+% \aftergroup\@@stopraggedoneliner
+% \fi}
+
+% Nog doen:
+%
+% \goodbreak -> \allowbreak en \dosomebreak{..} in koppen
+%
+% bij koppen zowieso: \blanko[reset]
+
+% Nog in commando verwerken:
+%
+% \voorkeur la \blanko
+%
+% Om ongewenste witruimte te voorkomen kan met \dosomebreak{\break}
+% een \penalty voor witruimte worden geplaatst.
+
+\def\removelastskip % a redefinition of plain
+ {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi}
+
+% first version:
+%
+% \def\dosomebreak#1%
+% {\scratchskip\lastskip
+% \removelastskip
+% %\type{#1}%
+% #1\relax
+% \ifdim\scratchskip=\zeropoint \else
+% \vskip\scratchskip
+% \fi}
+%
+% don't change the next improvement:
+
+% \def\dosomebreak#1%
+% {\endgraf % beware, this forces a newline
+% \ifvmode
+% \ifdim\lastskip=\zeropoint
+% #1\relax
+% \else
+% \scratchskip\lastskip
+% \removelastskip
+% #1\relax
+% \vskip\scratchskip
+% \fi
+% \fi}
+
+% beter, vooral in \vbox; nog in \pagina toepassen s!
+
+\def\doifoutervmode#1%
+ {\ifvmode\ifinner\else#1\fi\fi}
+
+\ifx\dosomebreak\undefined % defined in mkiv
+
+ \def\dosomebreak#1%
+ {\doifoutervmode
+ {\scratchskip\lastskip
+ \removelastskip
+ %\leavevmode\type{#1}%
+ #1\relax
+ \ifdim\scratchskip=\zeropoint % else interference with footnotes
+ \else
+ \vskip\scratchskip
+ \fi}}
\fi
+\def\forgeteverypar
+ {\everypar{\the\neverypar}}
+
+%\def\forgetparindent
+% {\forgeteverypar
+% \indentfirstparagraphtrue % recently added
+% \setupindenting[\v!geen]}
+
+%\def\forgetparskip
+% {\setupwhitespace[\v!geen]}
+
+\def\forgetparindent
+ {\forgeteverypar
+ \indentfirstparagraphtrue % recently added
+ \let\currentindentation\v!none
+ \ctxparindent\zeropoint
+ \parindent\zeropoint\relax}
+
+\def\forgetparskip
+ {\let\currentwhitespace\v!none
+ \ctxparskip\zeropoint
+ \parskip\zeropoint\relax}
+
+\def\forgetbothskips
+ {\tolerance1500
+ \leftskip\zeropoint
+ \rightskip\zeropoint\relax}
+
+\def\forgetspacing
+ {\emergencystretch\zeropoint}
+
+\newif\ifforgotten % rather good signal for inner
+
+\appendtoks \forgottentrue \to \everyforgetall
+\appendtoks \forgetragged \to \everyforgetall
+\appendtoks \forgetparskip \to \everyforgetall
+\appendtoks \forgetparindent \to \everyforgetall
+\appendtoks \forgetbothskips \to \everyforgetall
+\appendtoks \forgetspacing \to \everyforgetall % i.v.m. funny spacing in pagebody
+\appendtoks \spacing\!!plusone \to \everyforgetall % new per 10/08/2004, else problems in otr / !! needed
+\appendtoks \everypar\emptytoks \to \everyforgetall % indeed!
+
+\def\localvbox#1#%
+ {\vbox#1\bgroup
+ \forgetparskip
+ \setlocalhsize
+ \hsize\localhsize
+ \forgetparindent
+ \forgetbothskips
+ \forgeteverypar
+ \let\next=}
+
+% ach ja, hoort niet hier
+
+% \unexpanded\def\dostartattributes#1#2#3%
+% {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+% \doifdefinedelse{#1#2}
+% {\def\fontattribute{\getvalue{#1#2}}}
+% {\let\fontattribute=\empty}%
+% \doifdefinedelse{#1#3}
+% {\def\colorattribute{\getvalue{#1#3}}}
+% {\let\colorattribute=\empty}%
+% \startcolor[\colorattribute]%
+% \@EA\doconvertfont\@EA{\fontattribute}}
+%
+% \unexpanded\def\dostopattributes%
+% {\stopcolor
+% \endgroup}
+%
+% \unexpanded\def\doattributes#1#2#3#4%
+% {\dostartattributes{#1}{#2}{#3}{#4}\dostopattributes}
+
+%D A hardly faster implementation follows. We cannot use
+%D \type {csname} testing since the first argument can be
+%D anything, even a raw fontswitch. No a real improvement
+%D (some 5 seconds on 260 seconds for the maps bibliography).
+
+\let\dostopattributes\relax % in case these commands end up in an edef
+
+\unexpanded\def\dostartattributes#1#2#3%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \ifcsname#1#3\endcsname
+ \let\dostopattributes\@@dostopattributes
+ \startcolor[\csname#1#3\endcsname]%
+ \else
+ \let\dostopattributes\@@nostopattributes
+ \fi
+ \ifcsname#1#2\endcsname
+ \expandafter\doconvertfont
+ \else
+ \expandafter\gobbleoneargument
+ \fi{\csname#1#2\endcsname}}
+
+\newconditional \parbasedattributes
+
+\def\finishparbasedattributes
+ {\ifconditional\parbasedattributes
+ \setfalse\parbasedattributes
+ \par
+ \fi}
+
+\def\dostopparbasedattributes
+ {\settrue\parbasedattributes
+ \dostopattributes}
+
+\unexpanded\def\@@dostopattributes
+ {\stopcolor
+ \finishparbasedattributes
+ \endgroup}
+
+\unexpanded\def\@@nostopattributes
+ {\finishparbasedattributes
+ \endgroup}
+
+\unexpanded\def\doattributes#1#2#3#4%
+ {\dostartattributes{#1}{#2}{#3}{#4}\dostopattributes}
+
+% An even faster \ETEX\ version:
+
+\unexpanded\def\dostartattributes#1#2#3%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \ifincolor
+ \ifcsname#1#3\endcsname
+ \let\dostopattributes\@@dostopattributes
+ \faststartcolor[\csname#1#3\endcsname]%
+ \else
+ \let\dostopattributes\@@nostopattributes
+ \fi
+ \else
+ \let\dostopattributes\@@nostopattributes
+ \fi
+ \ifcsname#1#2\endcsname
+ % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi}
+
+\unexpanded\def\@@dostopattributes
+ {\faststopcolor
+ \finishparbasedattributes
+ \endgroup}
+
+\unexpanded\def\@@nostopattributes
+ {\finishparbasedattributes
+ \endgroup}
+
+%D Bonus macro, see core-sec.tex
+
+\unexpanded\def\dosetfontattribute#1#2%
+ {\ifcsname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi\empty}
+
+%D Since this happens a lot, and sometimes large arguments
+%D are passed in \type {#4}, we just copy some code:
+
+\unexpanded\def\doattributes#1#2#3#4%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \ifincolor
+ \ifcsname#1#3\endcsname
+ \let\dostopattributes\@@dostopattributes
+ \faststartcolor[\csname#1#3\endcsname]%
+ \else
+ \let\dostopattributes\endgroup
+ \fi
+ \else
+ \let\dostopattributes\endgroup
+ \fi
+ \ifcsname#1#2\endcsname
+ % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi
+ {#4}%
+ \dostopattributes}
+
+% Kan vaker worden toegepast en moet bovendien sneller!
+
+\newskip\leftskipadaption
+\newskip\rightskipadaption
+
+\def\doadaptleftskip#1%
+ {\dosetleftskipadaption{#1}%
+ \advance\leftskip \leftskipadaption}
+
+\def\doadaptrightskip#1%
+ {\dosetrightskipadaption{#1}%
+ \advance\rightskip \rightskipadaption}
+
+\setvalue{@lsa@\v!standard}{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
+\setvalue{@lsa@\v!yes }{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
+\letvalue{@lsa@\v!no }\zeropoint
+\letvalue{@lsa@\empty }\zeropoint
+\setvalue{@rsa@\v!standard}{\@@slright}
+\setvalue{@rsa@\v!yes }{\@@slright}
+\letvalue{@rsa@\v!no }\zeropoint
+\letvalue{@rsa@\empty }\zeropoint
+
+% not safe for 2\parindent
+%
+% \def\dosetleftskipadaption#1%
+% {\leftskipadaption
+% \ifcsname @lsa@#1\endcsname
+% \csname @lsa@#1\endcsname
+% \else
+% #1%
+% \fi
+% \relax}
+
+\def\dosetleftskipadaption#1%
+ {\edefconvertedargument\ascii{@lsa@#1}%
+ \leftskipadaption
+ \ifcsname\ascii\endcsname
+ \csname\ascii\endcsname
+ \else
+ #1%
+ \fi
+ \relax}
+
+\def\dosetrightskipadaption#1%
+ {\edefconvertedargument\ascii{@rsa@#1}%
+ \rightskipadaption
+ \ifcsname\ascii\endcsname
+ \csname\ascii\endcsname
+ \else
+ #1%
+ \fi
+ \relax}
+
+\newcount \noftrackedpagestates
+\newif \ifpagestatemismatch
+\newcount \realpagestateno
+\chardef \frozenpagestate \zerocount
+
+\def\dotrackpagestate#1#2%
+ {\ifdoublesided \ifinpagebody \else
+ \doforcedtrackpagestate{#1}{#2}%
+ \fi \fi}
+
+\def\doforcedtrackpagestate#1#2%
+ {\ifcase\frozenpagestate
+ \global\advance\noftrackedpagestates\plusone
+ \global\advance#2\plusone
+ \lazysavetaggedtwopassdata{#1}{\number\noftrackedpagestates}{\number#2}{\noexpand\realfolio}%
+ %\llap{\infofont\number\noftrackedpagestates/\number#2}% tracing
+ \fi}
+
+\def\doifrightpagestateelse#1#2%
+ {\ifcase\frozenpagestate
+ \pagestatemismatchfalse
+ \realpagestateno\realfolio
+ \ifinpagebody
+ \ifdoublesided
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \twopassdatafoundtrue
+ \fi
+ \else\ifdoublesided
+ \findtwopassdata{#1}{\number#2}%
+ \iftwopassdatafound
+ \realpagestateno\twopassdata\relax
+ \ifnum\twopassdata=\realpageno \else
+ \pagestatemismatchtrue
+ \fi
+ \ifodd\twopassdata\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \else
+ \twopassdatafoundtrue
+ \fi\fi
+ \else
+ \ifodd\realpagestateno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \iftwopassdatafound
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\doifforcedrightpagestateelse#1#2%
+ {\ifcase\frozenpagestate
+ \pagestatemismatchfalse
+ \realpagestateno\realfolio
+ \findtwopassdata{#1}{\number#2}%
+ \iftwopassdatafound
+ \realpagestateno\twopassdata\relax
+ \ifnum\twopassdata=\realpageno \else
+ \pagestatemismatchtrue
+ \fi
+ \ifodd\twopassdata\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \else
+ \ifodd\realpagestateno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \iftwopassdatafound
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\freezepagestate {\chardef\frozenpagestate\plusone }
+\def\defrostpagestate{\chardef\frozenpagestate\zerocount}
+
+% we can make more of these on top, but how to deal with mixed frozen states
+
+\definetwopasslist\s!paragraph \newcount \nofraggedparagraphs
+
+\def\signalrightpage {\dotrackpagestate \s!paragraph\nofraggedparagraphs}
+\def\doifrightpageelse{\doifrightpagestateelse\s!paragraph\nofraggedparagraphs}
+
+\newcount\pagesignallevel
+
+\def\startsignalrightpage % one may do a \postsignalrightplace
+ {\advance\pagesignallevel\plusone
+ \presignalrightpage
+ \let\signalrightpage\relax
+ \let\presignalrightpage\relax
+ \let\startsignalrightpage\relax
+ \doifrightpageelse\donothing\donothing
+ \freezepagestate}
+
+\def\stopsignalrightpage
+ {\ifcase\pagesignallevel\or\postsignalrightpage\fi
+ \advance\pagesignallevel\minusone}
+
+\def\setraggedparagraphmode
+ {\signalrightpage\doifrightpageelse} % move it there
+
+\ifx\swapmargins\undefined \let\swapmargins\undefined \fi % todo
+
+\def\doifswappedrightpageelse#1#2% alleen in box construction !
+ {\doifrightpageelse
+ {#1}
+ {\scratchcounter\realpageno
+ \realpageno\realpagestateno\relax
+ \swapmargins
+ \realpageno\scratchcounter
+ #2}}
+
+\newbox\signaledrightpage % this way we can avoid interference, i.e. postpone placement
+
+\def\presignalrightpage {\global\setbox\signaledrightpage\hbox{\signalrightpage}}
+\def\postsignalrightpage{\ifvoid\signaledrightpage\else\box\signaledrightpage\fi}
+
+% The next feature is is used in:
+%
+% \definenumber[test][way=bypage]
+%
+% \def\Test
+% {\incrementnumber[test]\rawnumber[test]/%
+% \incrementnumber[test]\rawnumber[test]/%
+% \incrementnumber[test]\rawnumber[test]\space
+% \checkpagechange{oeps}\changedpage{oeps}\space
+% \ifpagechanged TRUE\else FALSE\fi}
+%
+% \Test\page \Test\par \Test\page \Test\par \Test\page \Test\page
+%
+% (adapted from cont-new.tex:)
+
+\newif\ifpagechanged \let\lastchangedpage\empty
+
+\def\docheckpagestatechange#1#2#3%
+ {\pagechangedfalse
+ \doforcedtrackpagestate{#2}{#3}%
+ \findtwopassdata{#2}{\number#3}%
+ \iftwopassdatafound
+ \ifnum\twopassdata>0\getvalue{#2:p:#1}\relax
+ \pagechangedtrue
+ \fi
+ \fi
+ \ifpagechanged
+ \letgvalue{#2:p:#1}\twopassdata
+ \globallet\lastchangedpage\twopassdata
+ \else
+ \globallet\lastchangedpage\realfolio
+ \fi}
+
+\def\changedpagestate#1#2%
+ {\executeifdefined{#2:p:#1}{0}}
+
+\def\checkpagechange#1{\docheckpagestatechange{#1}\s!paragraph\nofraggedparagraphs}
+\def\changedpage #1{\changedpagestate{#1}\s!paragraph}
+
+% saved struts
+
+\ifx\savedstrutbox\undefined \newbox\savedstrutbox \fi
+
+\def\savestrut {\setbox\savedstrutbox\copy\strutbox}
+\def\savedstrut{\copy \savedstrutbox}
+
+% De onderstaande macro's zijn opgenomen in Plain TeX.
+%
+% \def\raggedright%
+% {\rightskip\zeropoint plus2em \spaceskip.3333em \xspaceskip.5em\relax}
+%
+% \def\ttraggedright%
+% {\tttf\rightskip\zeropoint plus2em\relax}
+%
+% \newif\ifr@ggedbottom
+%
+% \def\raggedbottom%
+% {\topskip 10\points plus60\points \r@ggedbottomtrue}
+%
+% \def\normalbottom%
+% {\topskip 10\points \r@ggedbottomfalse}
+%
+% en worden hieronder wat aangepast.
+
+% the three boolean will become obsolete some day in favour
+% of \bottomraggedness
+
+\chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
+
+\def\bottomalignlimit{3\lineheight}
+
+\newif\ifn@rmalbottom
+\newif\ifr@ggedbottom
+\newif\ifb@selinebottom
+
+\def\normalbottom
+ {% \topskip 10pt
+ \r@ggedbottomfalse}
+
+\def\raggedbottom
+ {\chardef\bottomraggedness\zerocount
+ \n@rmalbottomfalse
+ \r@ggedbottomtrue
+ \b@selinebottomfalse
+ \settopskip}
+
+\def\alignbottom
+ {\chardef\bottomraggedness\plusone
+ \n@rmalbottomtrue
+ \r@ggedbottomfalse
+ \b@selinebottomfalse
+ \settopskip}
+
+\def\baselinebottom
+ {\chardef\bottomraggedness\plustwo
+ \n@rmalbottomfalse
+ \r@ggedbottomfalse
+ \b@selinebottomtrue
+ \settopskip}
+
+\let\normalbottom=\alignbottom % downward compatible
+
+% so, the new one will be
+%
+% \chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
+%
+% \def\bottomalignlimit{3\lineheight} % will be settable
+%
+% \def\raggedbottom {\chardef\bottomraggedness=0 \settopskip}
+% \def\alignbottom {\chardef\bottomraggedness=1 \settopskip}
+% \def\baselinebottom{\chardef\bottomraggedness=2 \settopskip}
+%
+% \let\normalbottom =\alignbottom
+
+% \hyphenpenalty = ( 2.5 * \hsize ) / \raggedness
+% \tolerance >= 1500 % was 200
+% \raggedness = 2 .. 6\bodyfontsize
+
+\chardef\raggedstatus=0 % normal left center right
+
+\def\leftraggedness {2\bodyfontsize}
+\def\rightraggedness {2\bodyfontsize}
+\def\middleraggedness {6\bodyfontsize}
+
+\def\middleraggedness {.5\hsize} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
+
+% oeps, hsize can be 0pt in which case we get a strange division
+
+\def\middleraggedness {\ifdim\hsize=\zeropoint6\bodyfontsize\else.5\hsize\fi} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
+
+%D More hyphenation control, will be combined with align
+%D setup.
+
+\def\nohyphens
+ {\ifx\dohyphens\relax
+ \edef\dohyphens
+ {\hyphenpenalty\the\hyphenpenalty
+ \exhyphenpenalty\the\exhyphenpenalty\relax}%
+ \fi
+ \hyphenpenalty\plustenthousand
+ \exhyphenpenalty\plustenthousand}
+
+\let\dohyphens\relax
+
+%D To prevent unwanted side effects, we also have to check
+%D for hyphens here:
+
+% \def\setraggedness#1%
+% {\ifnum\tolerance<1500\relax % small values have
+% \tolerance1500\relax % unwanted side effects
+% \fi
+% \spaceskip2.5\hsize % we misuse these registers
+% \xspaceskip#1\relax % for temporary storage;
+% \divide\spaceskip \xspaceskip % they are changed anyway
+% \ifx\dohyphens\relax
+% \hyphenpenalty\spaceskip % \else no hyphens is active
+% \fi}
+
+\newskip\@@raggedskipa
+\newskip\@@raggedskipb
+
+\def\setraggedness#1%
+ {\ifnum\tolerance<1500\relax % small values have
+ \tolerance1500\relax % unwanted side effects
+ \fi
+ \ifx\dohyphens\relax
+ % this code will be reconsidered / kind of fuzzy (and old)
+ \@@raggedskipa 2.5\hsize
+ \@@raggedskipb #1\relax
+ \divide\@@raggedskipa \@@raggedskipb
+ \hyphenpenalty\@@raggedskipa
+ \fi}
+
+\let\updateraggedskips\relax
+
+\def\setraggedskips#1#2#3#4#5#6#7% never change this name
+ {\def\updateraggedskips{\dosetraggedskips{#1}{#2}{#3}{#4}{#5}{#6}{#7}}%
+ \updateraggedskips}
+
+\def\dosetraggedskips#1#2#3#4#5#6#7%
+ {\chardef \raggedstatus#1\relax
+ \leftskip 1\leftskip \!!plus#2\relax % zie: Tex By Topic 8.1.3
+ \rightskip 1\rightskip\!!plus#3\relax % zie: Tex By Topic 8.1.3
+ \spaceskip #4\relax
+ \xspaceskip #5\relax
+ \parfillskip\zeropoint\!!plus#6\relax
+ \parindent #7\relax}
+
+% \def\notragged%
+% {\setraggedskips{0}{0em}{0em}{0em}{0em}{1fil}{\parindent}}
+
+% older (context) names:
+
+\let\spaceamount \interwordspace
+\let\emspaceamount\emwidth
+
+% tracing:
+
+\def\doshowpardata#1%
+ {\ifx#1\relax\else
+ \hbox{\string#1: \the#1}\endgraf
+ \expandafter\doshowpardata
+ \fi}
+
+\def\showpardata
+ {\edef\thepardata
+ {\hbox{font: \fontname\font}\endgraf
+ \doshowpardata
+ \interwordspace \interwordstretch \interwordshrink \emwidth \exheight \extraspace
+ \hsize \vsize
+ \leftskip \rightskip
+ \spaceskip \xspaceskip
+ \parindent \parfillskip
+ \hyphenpenalty \exhyphenpenalty
+ \displaywidowpenalty \widowpenalty \clubpenalty \brokenpenalty
+ \doublehyphendemerits \finalhyphendemerits \adjdemerits
+ \relax}%
+ \begingroup
+ \dontshowcomposition
+ \inleftmargin{\vsmash
+ {\switchtobodyfont[7pt,tt]%
+ \framed[\c!align=\v!right]{\thepardata}}}%
+ \endgroup}
+
+\def\startshowpardata
+ {\begingroup
+ \showcomposition
+ \showstruts\tracepositionstrue \tracingparagraphs\maxdimen
+ \appendtoksonce\showpardata\let\showpardata\relax\to\everypar}
+
+\def\stopshowpardata
+ {\endgraf
+ \endgroup}
+
+% \defineXMLenvironment[showpardata] \startshowpardata \stopshowpardata
+% \defineXMLsingular [showpardata] \showpardata
+
+% defaults
+
+\def\raggedfillamount {1fil}
+\def\raggedhalffillamount{.5fil}
+\def\raggedspaceamount {\interwordspace} % {.3333em}
+\def\raggedxspaceamount {.5em}
+
+\def\notragged
+ {\chardef\raggedstatus\zerocount
+ \leftskip 1\leftskip
+ \rightskip 1\rightskip
+ \spaceskip \zeropoint
+ \xspaceskip \zeropoint
+ \parfillskip\zeropoint\!!plus\raggedfillamount\relax
+ \let\updateraggedskips\relax} % new
+
+\let\forgetragged\notragged
+
+\def\raggedleft
+ {\setraggedness\leftraggedness
+ \setraggedskips1\leftraggedness\zeropoint\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+\def\raggedcenter
+ {\setraggedness\middleraggedness
+ \setraggedskips2\middleraggedness\middleraggedness\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+%D We used to have:
+%D
+%D \starttyping
+%D \def\raggedright
+%D {\setraggedness\rightraggedness
+%D \setraggedskips{3}{0em}{\rightraggedness}{.3333em}{.5em}{0em}{\parindent}}
+%D \stoptyping
+%D
+%D However, the next alternative, suggested by Taco, is better.
+
+\def\raggedright
+ {\setraggedness\rightraggedness
+ \setraggedskips3\zeropoint\rightraggedness\raggedspaceamount
+ \raggedxspaceamount\raggedfillamount\parindent}
+
+\def\veryraggedleft
+ {\setraggedskips1\raggedfillamount\zeropoint\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+%D When we want the last line to have a natural width:
+%D
+%D \starttyping
+%D \def\veryraggedleft%
+%D {\setraggedskips{1}{1fil}{0em}{.3333em}{.5em}{0em}{-1fil}}
+%D \stoptyping
+%D
+%D but this one is not accepted by the macros.
+
+\def\veryraggedcenter
+ {\setraggedskips2\raggedfillamount\raggedfillamount\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+\def\veryraggedright
+ {\setraggedskips3\zeropoint\raggedfillamount\raggedspaceamount
+ \raggedxspaceamount\zeropoint\parindent}
+
+\def\ttraggedright
+ {\tttf
+ \setraggedskips3\zeropoint\rightraggedness
+ \zeropoint\zeropoint\zeropoint\parindent} % \ctxparindent
+
+%D A bonus one:
+
+\def\raggedwidecenter
+ {\setraggedness\middleraggedness
+ \setraggedskips2\raggedhalffillamount\raggedhalffillamount
+ \raggedspaceamount\raggedxspaceamount\zeropoint\zeropoint}
+
+\newif\if@@asragged \@@asraggedtrue % old method
+
+% todo
+%
+% \setuplayout[grid=yes,lines=44] \showgrid
+% \starttext
+% test \vfill test \endgraf \strut \endgraf \vskip-\lineheight \removedepth \pagina test
+% \stoptext
+
+% \setupalign[reset,new,right,old]
+
+\def\@@align@@rl{\if!!donea\veryraggedleft \else\raggedleft \fi}
+\def\@@align@@rr{\if!!donea\veryraggedright \else\raggedright \fi}
+\def\@@align@@rc{\if!!donea\veryraggedcenter\else\raggedcenter\fi}
+
+\setvalue{@@ngila@@\v!broad }{\!!doneatrue}
+\setvalue{@@ngila@@\v!wide }{\!!donebtrue}
+
+\def\installalign#1#2{\setvalue{@@align@@#1}{#2}} % can be used for overloads
+
+\installalign \v!new {\@@asraggedfalse}
+\installalign \v!old {\@@asraggedtrue}
+\installalign \empty {}
+
+\installalign \v!line {\baselinebottom}
+\installalign \v!bottom {\raggedbottom}
+\installalign \v!height {\normalbottom}
+\installalign \v!width {\notragged}
+\installalign \v!normal {\notragged}
+\installalign \v!yes {\notragged}
+\installalign \v!no {\raggedright}
+\installalign \v!inner {\if@@asragged \setraggedparagraphmode\@@align@@rl\@@align@@rr \else
+ \setraggedparagraphmode\@@align@@rr\@@align@@rl \fi}
+\installalign \v!outer {\if@@asragged \setraggedparagraphmode\@@align@@rr\@@align@@rl \else
+ \setraggedparagraphmode\@@align@@rl\@@align@@rr \fi}
+\installalign \v!left {\if@@asragged\@@align@@rl\else\@@align@@rr\fi}
+\installalign \v!right {\if@@asragged\@@align@@rr\else\@@align@@rl\fi}
+\installalign \v!middle {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
+\installalign \v!flushleft {\if!!donea\veryraggedright \else\raggedright\fi}
+\installalign \v!flushright {\if!!donea\veryraggedleft \else\raggedleft \fi}
+\installalign \v!flushouter {\setraggedparagraphmode\raggedleft\raggedright}
+\installalign \v!flushinner {\setraggedparagraphmode\raggedright\raggedleft}
+\installalign \v!center {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
+\installalign \v!hanging {\enableprotruding}
+\installalign \v!nothanging {\disableprotruding}
+\installalign \v!hz {\enableadjusting}
+\installalign \v!nohz {\disableadjusting}
+\installalign \v!spacing {\enablespacehandling \enablekernhandling}
+\installalign \v!nospacing {\disablespacehandling\disablekernhandling}
+\installalign \v!hyphenated {\dohyphens}
+\installalign \v!nothyphenated {\nohyphens}
+\installalign \v!new {\@@asraggedfalse} % so new will give you consistency
+\installalign \v!reset {\notragged\normalbottom}
+
+\installalign \v!tolerant {\tolerance3000 \relax}
+\installalign \v!verytolerant {\tolerance4500 \relax}
+\installalign \v!stretch {\emergencystretch\bodyfontsize}
+
+\newcount\hyphenminoffset
+
+\ifx\sethyphenationvariables\undefined \let\sethyphenationvariables\relax \fi
+
+\def\lesshyphens
+ {\advance\hyphenminoffset\plusone
+ \sethyphenationvariables}
+
+\def\morehyphens
+ {\ifcase\hyphenminoffset \else
+ \advance\hyphenminoffset\minusone
+ \fi
+ \sethyphenationvariables}
+
+\installalign \v!lesshyphenation {\lesshyphens}
+\installalign \v!morehyphenation {\morehyphens}
+
+\def\dodosetupalign#1{\csname @@align@@#1\endcsname}
+\def\dodosetupngila#1{\csname @@ngila@@#1\endcsname}
+
+\def\setupalign
+ {\dosingleargument\dosetupalign}
+
+\def\dosetupalign[#1]% can be made faster by checking for defined #1
+ {\!!doneafalse
+ \!!donebfalse
+ \processcommacommand[#1]\dodosetupngila
+ \processcommacommand[#1]\dodosetupalign}
+
+% \setupalign[flushleft] \input ward \par % lijnlinks
+% \setupalign[right] \input ward \par
+
+% \setupalign[flushright] \input ward \par % lijnrechts
+% \setupalign[left] \input ward \par
+
+% \setupalign[middle] \input ward \par % centreer
+% \setupalign[center] \input ward \par
+
+\def\startalignment
+ {\bgroup
+ \setupalign}
+
+\def\stopalignment
+ {\par
+ \egroup}
+
+\chardef\alignstrutmode=1
+
+% see later for the real definition, which in the simple case is:
+
+\newtoks \everyleftofalignedline
+\newtoks \everyrightofalignedline
+
+\def\shiftalignedline#1#2#3#4% left, right, inner, outer
+ {\rightorleftpageaction
+ {\everyleftofalignedline {\hskip\dimexpr#1+#3\relax}%
+ \everyrightofalignedline{\hskip\dimexpr#2+#4\relax}}
+ {\everyleftofalignedline {\hskip\dimexpr#1+#4\relax}%
+ \everyrightofalignedline{\hskip\dimexpr#2+#3\relax}}}
+
+% \def\doalignline#1#2% \\ == newline
+% {\begingroup
+% \setlocalhsize % new
+% \def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
+% \dowithnextbox
+% {\noindentation % was \noindent
+% \dontleavehmode % added in marrakesch at TUG 2006
+% \hbox to \localhsize
+% {\ifcase\alignstrutmode\or\strut\fi
+% \the\everyleftofalignedline
+% #1\unhbox\nextbox#2\relax
+% \the\everyrightofalignedline}%
+% \endgroup}
+% \hbox}
+
+\def\doalignline#1#2% \\ == newline
+ {\noindentation % was \noindent
+ \dontleavehmode % added in marrakesch at TUG 2006\begingroup
+ \begingroup
+ \setlocalhsize % new
+ \def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
+ \dowithnextbox
+ {\hbox to \localhsize
+ {\ifcase\alignstrutmode\or\strut\fi
+ \the\everyleftofalignedline
+ #1\unhbox\nextbox#2\relax
+ \the\everyrightofalignedline}%
+ \endgroup}
+ \hbox}
+
+% plain commands
+
+\ifx\undefined\line \def\line {\hbox to\hsize} \fi
+\ifx\undefined\leftline \def\leftline #1{\line{#1\hss}} \fi
+\ifx\undefined\rightline \def\rightline #1{\line{\hss#1}} \fi
+\ifx\undefined\centerline \def\centerline#1{\line{\hss#1\hss}} \fi
+
+% directe commando's
+
+\def\leftaligned {\doalignline \relax \hss }
+\def\midaligned {\doalignline \hss \hss }
+\def\rightaligned{\doalignline \hss \relax}
+
+\let\centeraligned\midaligned
+
+\def\regelbegrensd#1{\limitatetext{#1}{\hsize}{\unknown}} % to be translated
+
+% indirecte commando's
+
+\letvalue{\s!do\v!line\v!left }\leftaligned
+\letvalue{\s!do\v!line\v!right }\rightaligned
+\letvalue{\s!do\v!line\v!middle }\midaligned
+\letvalue{\s!do\v!line\v!flushleft }\rightaligned
+\letvalue{\s!do\v!line\v!flushright}\leftaligned
+\letvalue{\s!do\v!line\v!center }\midaligned
+
+\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
+
+%D Experimental:
+
+% simple version
+%
+% \def\doxalignline#1#2%
+% {\bgroup
+% \setlocalhsize
+% \def\\{\egroup\par\doxalignline{#1}{#2}\bgroup}% inefficient
+% \dowithnextbox
+% {\noindent\hbox to \localhsize
+% {\ifcase\alignstrutmode\or\strut\fi
+% \signalrightpage
+% \doifrightpageelse{#1\unhbox\nextbox#2}{#2\unhbox\nextbox#1}}%
+% \egroup}
+% \hbox}
+%
+% \setvalue{\s!do\v!regel\v!binnen}{\doxalignline\relax\hss}
+% \setvalue{\s!do\v!regel\v!buiten}{\doxalignline\hss\relax}
+%
+% more extensive:
+
+\def\doxalignline#1#2#3#4#5#6%
+ {\noindentation % was \noindent
+ \dontleavehmode % added in marrakesch at TUG 2006\begingroup
+ \begingroup
+ \setlocalhsize
+ \def\\{\egroup\par\doxalignline#1#2#3#4#5#6\bgroup}% inefficient
+ \dowithnextbox
+ {%\noindent moved up
+ \hbox to \localhsize
+ {#1\hskip\ifdone#2\else#3\fi#4%
+ \hbox to \localhsize
+ {\the\everyleftofalignedline
+ \ifcase\alignstrutmode\or\strut\fi
+ \ifdone#5\unhbox\nextbox#6\else#6\unhbox\nextbox#5\fi
+ \the\everyrightofalignedline}%
+ \hss}%
+ \endgroup}
+ \hbox}
+
+\def\doxcheckline
+ {\signalrightpage\doifrightpageelse\donetrue\donefalse}
+
+\setvalue{\s!do\v!line\v!inner }{\doxalignline\doxcheckline++\zeropoint \relax\hss }
+\setvalue{\s!do\v!line\v!outer }{\doxalignline\doxcheckline++\zeropoint \hss \relax}
+\setvalue{\s!do\v!line\v!innermargin}{\doxalignline\doxcheckline-+\innermargintotal\relax\hss }
+\setvalue{\s!do\v!line\v!outermargin}{\doxalignline\doxcheckline+-\outermargintotal\hss \relax}
+\setvalue{\s!do\v!line\v!inneredge }{\doxalignline\doxcheckline-+\inneredgetotal \relax\hss }
+\setvalue{\s!do\v!line\v!outeredge }{\doxalignline\doxcheckline+-\outeredgetotal \hss \relax}
+\setvalue{\s!do\v!line\v!backspace }{\doxalignline\doxcheckline-+\backspace \relax\hss }
+\setvalue{\s!do\v!line\v!cutspace }{\doxalignline\doxcheckline+-\cutspace \hss \relax}
+
+\setvalue{\s!do\v!line\v!leftmargin }{\doxalignline\donefalse --\leftmargintotal \hss \relax}
+\setvalue{\s!do\v!line\v!rightmargin}{\doxalignline\donefalse ++\rightmargintotal\relax\hss }
+\setvalue{\s!do\v!line\v!leftedge }{\doxalignline\donefalse --\leftedgetotal \hss \relax}
+\setvalue{\s!do\v!line\v!rightedge }{\doxalignline\donefalse ++\rightedgetotal \relax\hss }
+
+% ! ! ! beware, redefining \doalignline gives the wrong results ! ! !
+%
+% \def\doalignline{\doxalignline\donefalse++\zeropoint}
+
+%D Better:
+
+\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
+
+% \def\alignedline#1#2% setting default
+% {\csname
+% \s!do\v!line
+% \ifundefined{\s!do\v!line#1}#2\else#1\fi
+% \endcsname}
+
+\def\alignedline#1#2% setting default
+ {\csname\s!do\v!line\ifcsname\s!do\v!line#1\endcsname#1\else#2\fi\endcsname}
+
+%D ...
+
+\def\dosetuptolerance[#1]%
+ {\doifinsetelse\v!vertical{#1}%
+ {\ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!verystrict=>\def\bottomtolerance{},
+ \v!strict=>\def\bottomtolerance{.050},
+ \v!tolerant=>\def\bottomtolerance{.075},
+ \v!verytolerant=>\def\bottomtolerance{.100}]}%
+ {\ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!stretch=>\emergencystretch\bodyfontsize,
+ \v!space=>\spaceskip.5em\!!plus.25em\!!minus.25em\relax,
+ \v!verystrict=>\tolerance 200,
+ \v!strict=>\tolerance1500,
+ \v!tolerant=>\tolerance3000,
+ \v!verytolerant=>\tolerance4500]}}
+
+\def\setuptolerance
+ {\dosingleargument\dosetuptolerance}
+
+% \def\woordrechts
+% {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
+
+% beware: \wordright{whatever\kern-\rightskip} should work!
+% so, no funny boxing here
+
+\def\dowordright[#1]%
+ {% don't change
+ \groupedcommand
+ {\removeunwantedspaces
+ \hfill
+ \allowbreak % changed back from \hskip\zeropoint
+ \strut
+ \hfill
+ \quad % decent spacing
+ \hbox}
+ {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
+ \parfillskip\zeropoint
+ %\finalhyphendemerits\zerocount % yes or no
+ \par}}
+
+\def\wordright
+ {\dosingleempty\dowordright}
+
+% \dorecurse{5}{something } \wordright{--someone} \endgraf
+% \dorecurse{6}{something } \wordright{--someone} \endgraf
+% \dorecurse{7}{something } \wordright{--someone} \endgraf
+%
+% \dorecurse{5}{something } \wordright{--someone else entirely} \endgraf
+% \dorecurse{6}{something } \wordright{--someone else entirely} \endgraf
+% \dorecurse{7}{something } \wordright{--someone else entirely} \endgraf
+%
+% \wordright[\rightskip]{whatever}
+
+% \simplealignedbox{2cm}{right}{x}
+
+\setvalue{\s!simple\c!align\v!right }#1#2{\hbox to #1{#2\hss}}
+\setvalue{\s!simple\c!align\v!left }#1#2{\hbox to #1{\hss#2}}
+\setvalue{\s!simple\c!align\v!flushright }#1#2{\hbox to #1{\hss#2}}
+\setvalue{\s!simple\c!align\v!flushleft }#1#2{\hbox to #1{#2\hss}}
+\setvalue{\s!simple\c!align\v!middle }#1#2{\hbox to #1{\hss#2\hss}}
+
+\def\simplealignedbox#1{\executeifdefined{\s!simple\c!align#1}{\getvalue{\s!simple\c!align\v!right}}}
+
+%D \macros
+%D {pushindentation,popindentation}
+%D
+%D The pushing and popping is done by:
+
+\newbox\indentationboxA
+\newbox\indentationboxB
+
+\def\pushindentation
+ {\bgroup
+ \ifhmode
+ \unskip
+ \setbox\indentationboxA\lastbox % get \strut if present
+ \unskip
+ \setbox\indentationboxB\lastbox % get \indent generated box
+ \unskip
+ \else
+ \hskip\zeropoint % switch to horizontal mode
+ \unskip
+ \setbox\indentationboxA\lastbox % get \indent generated box
+ \setbox\indentationboxB\emptybox
+ \fi}
+
+\def\popindentation
+ {\box\indentationboxB\box\indentationboxA % put back the boxes
+ \egroup}
+
+%D The only complication lays in \type{\strut}. In \PLAIN\
+%D \TEX\ a \type{\strut} is defined as:
+%D
+%D \starttyping
+%D \def\strut%
+%D {\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%D \stoptyping
+%D
+%D But what is a \type{\strut}? Normally it's a rule of width
+%D zero, but when made visual, it's a rule and a negative skip.
+%D The mechanism for putting things in the margins described
+%D here cannot handle this situation very well. One
+%D characteristic of \type{\strut} is that the \type{\unhcopy}
+%D results in entering horizontal mode, which in return leads
+%D to some indentation.
+%D
+%D To serve our purpose a bit better, the macro \type{\strut}
+%D can be redefined as:
+%D
+%D \starttyping
+%D \def\strut
+%D {\relax\ifmmode\else\hskip0pt\fi\copy\strutbox}
+%D \stoptyping
+%D
+%D Or more compatible:
+%D
+%D \starttyping
+%D \def\strut
+%D {\relax\ifmmode
+%D \copy\strutbox
+%D \else
+%D \bgroup\setbox\strutbox=\normalhbox{\box\strutbox}\unhcopy\strutbox\egroup
+%D \fi}
+%D \stoptyping
+%D
+%D In \CONTEXT\ however we save some processing time by putting
+%D an extra \type{\hbox} around the \type{\strutbox}.
+
+% moved from page-lin.tex to here (due to visualization added
+% in august 2003)
+%
+% \unexpanded \def\crlf
+% {\ifhmode\unskip\else\strut\fi\ifcase\raggedstatus\hfil\fi\break}
+
+\unexpanded \def\crlf
+ {\ifhmode
+ \unskip
+ \prewordbreak\crlfplaceholder
+ \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
+ \break
+ \else
+ \crlfplaceholder
+ \endgraf
+ \fi}
+
+\def\crlfplaceholder
+ {\strut}
+
+\def\settestcrlf
+ {\def\crlfplaceholder
+ {\hbox to \zeropoint
+ {\strut{\infofont\kern.25em}\lohi{\infofont CR}{\infofont LF}\hss}}}
+
+%D \starttyping
+%D % \setuplayout[gridgrid=yes] \showgrid
+%D
+%D \startbuffer
+%D test 1\crlf
+%D test 2\crlf
+%D
+%D \crlf test 3
+%D
+%D test 4\crlf
+%D test 5
+%D
+%D \crlf
+%D \crlf
+%D \crlf
+%D test 6
+%D \stopbuffer
+%D
+%D \hbox
+%D {\hsize5em
+%D \ruledvtop{\getbuffer}\enspace
+%D \ruledvtop{\showstruts\getbuffer}\enspace
+%D \hsize15em \setuptyping[before=,after=]%
+%D \ruledvtop{\typebuffer}}
+%D \stoptyping
+
+\def\opeenregel % to be used grouped
+ {\def\crlf{\removelastspace\space}\let\\\crlf}
+
+\def\showstruts
+ {\setteststrut
+ \settestcrlf}
+
+\def\definehspace
+ {\dotripleempty\dodefinehspace}
+
+\def\dodefinehspace[#1][#2][#3]% #1 = optional namespace
+ {\ifthirdargument
+ \setvalue{\??hs#1:#2}{#3}%
+ \else
+ \setvalue{\??hs:#1}{#2}%
+ \fi}
+
+\unexpanded\def\hspace
+ {\dodoubleempty\dohspace}
+
+%\def\dohspace[#1][#2]%
+% {\ifhmode
+% \removeunwantedspaces
+% \hskip
+% \ifsecondargument
+% \hspaceamount{#1}{#2}%
+% \else
+% \hspaceamount\empty{\iffirstargument#1\else\s!default\fi}%
+% \fi
+% \expandafter\ignorespaces
+% \fi}
+
+\def\dohspace[#1][#2]%
+ {\ifsecondargument
+ \dodohspace[#1][#2]%
+ \else\iffirstargument
+ \hspace[][#1]%
+ \else
+ \hspace[][\s!default]%
+ \fi\fi}
+
+% \def\dodohspace[#1][#2#3]%
+% {\ifhmode
+% \removeunwantedspaces
+% \doifelse{#2}{-}
+% {{\scratchskip\hspaceamount{#1}{#3}\hskip-\scratchskip}}
+% {\hskip\hspaceamount{#1}{#2#3}}%
+% \expandafter\ignorespaces
+% \fi}
+%
+% not needed, tex handles -- as +
+
+\def\dodohspace[#1][#2]%
+ {\ifhmode
+ \removeunwantedspaces
+ \hskip\hspaceamount{#1}{#2}%
+ \expandafter\ignorespaces
+ \fi}
+
+\def\hspaceamount#1#2%
+ {\executeifdefined{\??hs#1:#2}{\executeifdefined{\??hs:#2}\zeropoint}}
+
+\definehspace [\v!small] [.25\emspaceamount]
+\definehspace [\v!medium] [.5\emspaceamount]
+\definehspace [\v!big] [1\emspaceamount]
+\definehspace [\v!normal] [1\spaceamount]
+\definehspace [\v!default] [\spaceamount]
+
+%D Taken from Taco's math module (cq. \AMS\ macros), but
+%D adapted to \type {\hspace}:
+
+\unexpanded\def\textormathspace#1#2#3%
+ {\ifmmode\mskip#1#2\else\kern#1\hspaceamount\empty{#3}\fi\relax}
+
+\newmuskip\hairmuskip \hairmuskip=.15mu
+
+\def\hairspace {\textormathspace+\hairmuskip{.5}}
+\def\thinspace {\textormathspace+\thinmuskip 1}
+\def\medspace {\textormathspace+\medmuskip 2}
+\def\thickspace {\textormathspace+\thickmuskip3}
+\def\neghairspace {\textormathspace-\thinmuskip{.5}}
+\def\negthinspace {\textormathspace-\thinmuskip 1}
+\def\negmedspace {\textormathspace-\medmuskip 2}
+\def\negthickspace{\textormathspace-\thickmuskip3}
+
+% needed for unicode:
+
+\def\twoperemspace {\hskip\dimexpr\emwidth/2\relax} % == \enspace
+\def\threeperemspace {\hskip\dimexpr\emwidth/3\relax}
+\def\fourperemspace {\hskip\dimexpr\emwidth/4\relax}
+\def\fiveperemspace {\hskip\dimexpr\emwidth/5\relax} % goodie
+\def\sixperemspace {\hskip\dimexpr\emwidth/6\relax}
+\def\figurespace {\begingroup\setbox\scratchbox\hbox{0}\hskip\wd\scratchbox\endgroup} % there is a command for this
+\def\punctuationspace {\begingroup\setbox\scratchbox\hbox{.}\hskip\wd\scratchbox\endgroup}
+\def\ideographicspace {\hskip\dimexpr\emwidth/1\relax}
+\def\ideographichalffillspace{\hskip\dimexpr\emwidth/2\relax}
+%def\nobreakspace {\penalty\plustenthousand\space}
+\def\nobreakspace {\penalty\plustenthousand\kern\interwordspace}
+\def\narrownobreakspace {\penalty\plustenthousand\thinspace}
+%def\zerowidthnobreakspace {\penalty\plustenthousand\hskip\zeropoint}
+\def\zerowidthnobreakspace {\penalty\plustenthousand\kern\zeropoint}
+\def\zerowidthspace {\hskip\zeropoint}
+
+\definehspace[.5][.1250\emspaceamount] % could also be [.1250\spaceamount]
+\definehspace[1] [.1667\emspaceamount]
+\definehspace[2] [.2222\emspaceamount]
+\definehspace[3] [.2777\emspaceamount]
+
+\let \, \thinspace
+\let \: \medspace
+\let \; \thickspace
+\let \! \negthinspace
+
+% this will become an alternative bunch of \blank settings
+%
+% \startlines
+% \scratchskip=.23pt plus 10pt minus 4pt \relax \number\scratchskip \space \the\scratchskip
+% \setsimplifiedskip\scratchskip1 \number\scratchskip \space \the\scratchskip
+% \setsimplifiedskip\scratchskip2 \number\scratchskip \space \the\scratchskip
+% \getsimplifiedskip\scratchskip\scratchcounter \number\scratchcounter
+% \stoplines
+%
+% \hrule width10cm \endgraf
+% \discardedskip{10pt}
+% \retainedskip {4pt}
+% \discardedskip {5pt}
+% \hrule width10cm \endgraf
+% \blockedskip{0pt}
+% \discardedskip{10pt}
+% \retainedskip {4pt}
+% \discardedskip {5pt}
+% \hrule width10cm \endgraf
+% \frozenskip {4cm}
+% \hrule width10cm \endgraf
+% \vskip10pt
+% \hrule width10cm \endgraf
+
+% ! ! ! etex only, evt splitskip macro gebruiken (syst-new)
+
+\newskip\simplifiedskip
+\newskip\simplifiedcounter
+
+\chardef\@@discardedskip1
+\chardef\@@retainedskip 2
+\chardef\@@forcedskip 3
+\chardef\@@blockedskip 4
+\chardef\@@frozenskip 5 % after heads, no break
+
+\def\setsimplifiedskip#1#2%
+ {#1\dimexpr(10\dimexpr(#1/10)) plus \gluestretch#1 minus \glueshrink#1\relax
+ \advance#1\numexpr(#2)sp\relax}
+
+\def\getsimplifiedskip#1#2%
+ {\simplifiedskip#1\relax
+ \ifzeropt\simplifiedskip % \ifdim\simplifiedskip=\zeropoint
+ #2\zerocount
+ \else
+ \simplifiedcounter\dimexpr10\dimexpr#1/10\relax\relax
+ \advance\simplifiedskip-\simplifiedcounter
+ #2\number\simplifiedskip\relax
+ \fi}
+
+\def\conditionalskip#1#2%
+ {\scratchskip#1\relax
+ \setsimplifiedskip\scratchskip#2\relax
+ \vskip\scratchskip\relax}
+
+\def\defrostskip
+ {\scratchskip\lastskip\penalty50000\normalvskip-\scratchskip\penalty50000\relax}
+
+\def\frozenskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \fi}
+
+\def\discardedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@discardedskip
+ \or % discard
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@discardedskip
+ \fi
+ \or % retain
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@discardedskip
+ \fi
+ \or % forced
+ \conditionalskip{#1}\@@discardedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+\def\retainedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@retainedskip
+ \or % discard
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@retainedskip
+ \or % retain
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@retainedskip
+ \fi
+ \or % forced
+ \conditionalskip{#1}\@@retainedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+\def\forcedskip#1%
+ {\endgraf
+ \ifvmode
+ \conditionalskip{#1}\@@forcedskip
+ \fi}
+
+\def\blockedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@blockedskip
+ \or % discard
+ \conditionalskip{#1}\@@blockedskip
+ \or % retain
+ \conditionalskip{#1}\@@blockedskip
+ \or % forced
+ \conditionalskip{#1}\@@blockedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+% beware, changing this will break some code (like pos/backgrounds)
+
+\newtoks\everyfirstparagraphintro
+\newtoks\everynextparagraphintro
+\newtoks\@@everyparagraphtoks
+
+\chardef\everyparagraphintro\zerocount
+
+\def\setupparagraphintro
+ {\dodoubleempty\dosetupparagraphintro}
+
+\def\dosetupparagraphintro[#1][#2]%
+ {\processallactionsinset
+ [#1]
+ [ \v!reset=>\global\chardef\everyparagraphintro\zerocount
+ \global\everyfirstparagraphintro\emptytoks
+ \global\everynextparagraphintro \emptytoks,
+ \v!first=>\global\chardef\everyparagraphintro\plusone
+ \doglobal\appendtoks#2\to\everyfirstparagraphintro,
+ \v!next=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plusone\fi
+ \doglobal\appendtoks#2\to\everynextparagraphintro,
+ \v!each=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plustwo\fi
+ \doglobal\appendtoks#2\to\everyfirstparagraphintro
+ \doglobal\appendtoks#2\to\everynextparagraphintro]}
+
+%D We can say:
+%D
+%D \starttyping
+%D \setupparagraphintro[first][\index{Knuth}]
+%D \stoptyping
+%D
+%D Maybe more convenient is:
+%D
+%D \starttyping
+%D \flushatparagraph{\index{Zapf}}
+%D \stoptyping
+
+\def\flushatparagraph#1%
+ {\global\chardef\everyparagraphintro\plusone
+ \global\appendtoks{#1}\to\everyfirstparagraphintro}
+
+% \def\doinsertparagraphintro
+% {\ifcase\everyparagraphintro\relax
+% % no data
+% \@@everyparagraphtoks\emptytoks
+% \or
+% % first data
+% \global\chardef\everyparagraphintro\plustwo
+% \@@everyparagraphtoks\everyfirstparagraphintro
+% \global\everyfirstparagraphintro\emptytoks
+% \or
+% % next data
+% \@@everyparagraphtoks\everynextparagraphintro
+% \fi
+% \the\@@everyparagraphtoks}
+
+\def\doinsertparagraphintro
+ {\begingroup
+ \everypar\emptytoks
+ \ifcase\everyparagraphintro\relax
+ % no data
+ \@@everyparagraphtoks\emptytoks
+ \or
+ % first data
+ \global\chardef\everyparagraphintro\plustwo
+ \@@everyparagraphtoks\everyfirstparagraphintro
+ \global\everyfirstparagraphintro\emptytoks
+ \or
+ % next data
+ \@@everyparagraphtoks\everynextparagraphintro
+ \fi
+ \the\@@everyparagraphtoks
+ \endgroup}
+
+\def\insertparagraphintro
+ {\ifcase\everyparagraphintro\else\@EA\doinsertparagraphintro\fi}
+
+% \appendtoksonce\insertparagraphintro\to\everypar % should come last
+
+%D \starttyping
+%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
+%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
+%D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT \hss}]
+%D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN \hss}]
+%D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH \hss}]
+%D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA \hss}]
+%D
+%D some paragraph \par
+%D some paragraph \par
+%D some paragraph \par
+%D
+%D \definelabel[parnumber]
+%D
+%D \setupparagraphintro[reset,each][\inleft{\slxx\parnumber}]
+%D
+%D some paragraph \par
+%D some paragraph \par
+%D some paragraph \par
+%D \stoptyping
+
+%D \macros
+%D {flushatnextpar}
+%D
+%D This macro collects data that will be flushed at the next paragraph.
+%D By using this macro you can avoid interfering nodes (writes, etc).
+
+\newbox \postponednodedata
+
+\def\flushatnextpar
+ {\bgroup
+ \dowithnextbox
+ {\global\setbox\postponednodedata\hbox{\box\postponednodedata\box\nextbox}\egroup}%
+ \hbox}
+
+\def\flushpostponednodedata
+ {\ifvoid\postponednodedata\else
+ \hbox{\smashedbox\postponednodedata}%
+ \fi}
+
+% Very nasty but needed for margin stuff inside colored
+% paragraphs.
+
+\let\normalvadjust\vadjust
+
+% \def\graphicvadjust % bad, those low level color calls here
+% {\dowithnextbox
+% {\normalvadjust
+% {\dostartgraphicgroup
+% \localstarttextcolor
+% \unvbox\nextbox
+% \localstoptextcolor
+% \dostopgraphicgroup}}%
+% \vbox}
+
+% test this prikkels/pascal margin text before heads (mode
+% 1) as well as uitwerkingen (mode 2)
+
+%chardef\graphicvadjustmode=0 % fake
+%chardef\graphicvadjustmode=1 % normal
+\chardef\graphicvadjustmode=2 % normal + compensate (== default)
+
+\def\graphicvadjust % bad, those low level color calls here
+ {\dowithnextboxcontent
+ {\forgetall}
+ {\ifcase\graphicvadjustmode \@EA \fakedvadjust \else \@EA\normalvadjust \fi
+ {\dostartgraphicgroup % don't ask
+ \localstarttextcolor
+ \unvbox\nextbox
+ \localstoptextcolor % don't ask
+ \dostopgraphicgroup
+ \ifcase\graphicvadjustmode \or \or
+ % corrects for one line paragraphs
+ \nointerlineskip
+ \kern-\struttotal
+ \nointerlineskip
+ \verticalstrut
+ \fi}}%
+ \vbox}
+
+%D This works only in a properly strutted line, and is meant
+%D for deeply burried operations, like in heads.
+
+\def\fakedvadjust
+ {\dowithnextbox
+ {\setbox\nextbox\hbox{\llap{\lower\strutdepth\box\nextbox}}%
+ \smashedbox\nextbox}%
+ \vtop}
+
+\def\flexiblespaceamount#1#2#3%
+ {#1\interwordspace
+ \!!plus#2\interwordstretch
+ \!!minus#3\interwordshrink}
+
+\def\fixedspaceamount#1%
+ {#1\interwordspace}
+
+%D This is a dangerous feature because it makes the \TEX\ source
+%D less portable, i.e. any parser now needs to apply exactly the
+%D same algorithm when it wants to interpret the source. We
+%D strongly recommend not to mention this feature in manuals! It's
+%D provided for users who are hooked to such a mechanism.
+%D
+%D \starttyping
+%D \setupsorting[logo][next=\autoinsertnextspace] \logo[TEX]{\TeX}
+%D
+%D bla bla \TEX bla bla \TEX (bla) bla (\TEX)
+%D \stoptyping
+
+\def\autoinsertnextspace{\futurelet\nexttoken\doautoinsertnextspace}
+
+\def\doautoinsertnextspace % slightly extended version of a user supplied macro
+ {\ifx\nexttoken \bgroup\else \ifx\nexttoken\begingroup\else
+ \ifx\nexttoken \egroup\else \ifx\nexttoken \endgroup\else
+ \ifx\nexttoken \/\else \ifx\nexttoken /\else \ifx\nexttoken ~\else
+ \ifx\nexttoken \ \else \ifx\nexttoken \blankspace\else \ifx\nexttoken \space\else
+ \ifx\nexttoken .\else \ifx\nexttoken ,\else
+ \ifx\nexttoken !\else \ifx\nexttoken ?\else
+ \ifx\nexttoken :\else \ifx\nexttoken ;\else
+ \ifx\nexttoken '\else \ifx\nexttoken "\else
+ \ifx\nexttoken )\else \ifx\nexttoken -\else \ifx\nexttoken |\else
+ \ifx\nexttoken \%\else \ifx\nexttoken \&\else
+ \space
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% moved from page-lin
+
+\def\installspacehandler#1#2% needs to set \obeyedspace
+ {\setvalue{\??sr#1}{#2}}
+
+\installspacehandler \v!on
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode{\tt\controlspace}}}%
+ \let\ =\obeyedspace}
+
+\installspacehandler \v!yes
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode \normalspace }}%
+ \let\ =\obeyedspace}
+
+\installspacehandler \v!off
+ {\normalspaces
+ \let\obeyedspace\normalspace
+ \let\ =\normalspace}
+
+\installspacehandler \v!fixed
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode\fixedspace}}%
+ \let\ =\obeyedspace}
+
+\def\activatespacehandler#1%
+ {\executeifdefined{\??sr#1}{\activatespacehandler\v!off}}
+
+% moved from page-lin
+
+%D When spacing is active we need to handle commands in
+%D a special way:
+%D
+%D \starttyping
+%D \setuplines[space=on]
+%D
+%D \startlines
+%D Let's talk about this{\ttsl\gobbleoneargument or}that.
+%D \stoplines
+%D
+%D \startlines
+%D Let's talk about this{\getvalue{ttsl}or}that.
+%D \stoplines
+%D \stoptyping
+%D
+%D One can indent in several ways:
+%D
+%D \starttyping
+%D \setupindenting[medium] \setuplines[indenting=odd] % no yes odd even
+%D
+%D \startlines
+%D first
+%D second
+%D third
+%D fourth
+%D \stoplines
+%D \stoptyping
+
+\def\setuplines
+ {\dodoubleargument\getparameters[\??rg]}
+
+\def\startlines
+ {\@@rgbefore
+ \pushmacro\checkindentation
+ \whitespace
+ %\page[\v!preference]} gaat mis na koppen, nieuw: later \nobreak
+ \begingroup
+ \setupindenting[\@@rgindenting]%
+ \typesettinglinestrue
+ \setupwhitespace[\v!none]%
+ \obeylines
+ \ignorespaces
+ \gdef\afterfirstobeyedline % tzt two pass, net als opsomming
+ {\gdef\afterfirstobeyedline
+ {\nobreak
+ \global\let\afterfirstobeyedline\relax}}%
+ \def\obeyedline
+ {\par
+ \afterfirstobeyedline
+ \futurelet\next\dobetweenthelines}%
+ \activatespacehandler\@@rgspace
+ \GotoPar}
+
+\def\stoplines
+ {\endgroup
+ \popmacro\checkindentation
+ \@@rgafter}
+
+\def\dobetweenthelines
+ {\doifmeaningelse\next\obeyedline\@@rginbetween\donothing}
+
+\setuplines
+ [\c!before=\blank,
+ \c!after=\blank,
+ \c!inbetween=\blank,
+ \c!indenting=\v!no,
+ \c!space=\v!default]
+
+\def\emptylines
+ {\dosingleempty\doemptylines}
+
+\def\doemptylines[#1]%
+ {\endgraf\dorecurse{\iffirstargument#1\else3\fi}\crlf}
+
+\setupwhitespace
+ [\v!none]
+
+% still old-fashioned
+
+\indenting
+ [\v!never]
+
+\setupindenting
+ [\v!none]
+
+\setupblank
+ [\v!standard,
+ \v!big]
+
+\defineblank[\v!default] [\currentblank]
+\defineblank[\v!before] [\v!default]
+\defineblank[\v!inbetween][\v!default]
+\defineblank[\v!after] [\v!before]
+
+\setupinterlinespace
+ [\c!minheight=0pt, % only special purpose
+ \c!mindepth=0pt, % only special purpose
+ \c!height=.72,
+ \c!depth=.28,
+ \c!top=1.0,
+ \c!bottom=0.4,
+ \c!distance=1pt,
+ \c!line=2.8ex,
+ \c!stretch=0]
+
+\setupnarrower
+ [\c!before=\endgraf,
+ \c!after=\endgraf,
+ \c!left=1.5em,
+ \c!right=1.5em,
+ \c!middle=1.5em]
+
+\setuptolerance
+ [\v!horizontal,\v!verystrict]
+
+\setuptolerance
+ [\v!vertical,\v!strict]
+
+\setupalign
+ [\v!bottom,
+ \v!width]
+
+\setupspacing
+ [\v!packed]
+
\protect \endinput
diff --git a/tex/context/base/core-spa.mkiv b/tex/context/base/core-spa.mkiv
index 8c1df68dc..dfb84da53 100644
--- a/tex/context/base/core-spa.mkiv
+++ b/tex/context/base/core-spa.mkiv
@@ -11,289 +11,2794 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Buffers}
+\writestatus{loading}{ConTeXt Core Macros / Spacing}
+
+% to be sorted out: dependencies, order of initialization / also some dutch code here
+% more documentation in the mkii file
\unprotect
-% category:
-%
-% 0 == discard
-% 1 == only if larger
-% 2 == force even if smaller
-% 3 == only take penalty component
-% 4 == add to existing skip
-% 5 == ignore following skips (== disable)
+% some will move to core-var
-% penalty:
+\newif \ifgridsnapping
+\newif \iffuzzyvskip
+\let \fuzzyvskip \gobbleoneargument
+\let \removelastfuzzyvskip \relax
+
+\let \startbaselinecorrection \relax
+\let \stopbaselinecorrection \relax
+\let \baselinecorrection \relax
+\let \offbaselinecorrection \relax
+
+\appendtoks \spacing 1\to \everybodyfont
+\appendtoks \presetnormallineheight \to \everybodyfont
+\appendtoks \setnormalbaselines \to \everybodyfont % check if redundant
+\appendtoks \setstrut \to \everybodyfont % check if redundant
+\appendtoks \settopskip \to \everybodyfont
+\appendtoks \setmaxdepth \to \everybodyfont
+%appendtoks \spacing 1\to \everybodyfont
+\appendtoks \simplesetupindenting \to \everybodyfont
+\appendtoks \simplesetupblank \to \everybodyfont
+\appendtoks \simplesetupwhitespace \to \everybodyfont
+%appendtoks \checknotes \to \everybodyfont % not
+\appendtoks \simplesetupspacing \to \everybodyfont % nieuw
+\appendtoks \setrelativeinterlinespace \to \everybodyfont
+
+\appendtoks \updateraggedskips \to \everyfontswitch % under test
+\prependtoks \let\par\endgraf \to \everypagebody % see \fillinline
+\appendtoks \simplesetupspacing \to \everydefinedfont
+
+% if you want to hyphenate the first word of a paragraph ... \appendtoks\hskip0pt\to\everypar
+
+\def\stelfactorenin
+ {\simplesetupwhitespace
+ \simplesetupblank
+ \settopskip
+ \setmaxdepth}
+
+\def\softbreak
+ {\relax\ifhmode\hskip\parfillskip\break\fi}
+
+\let\poplastnode\relax
+
+\def\pushlastnode
+ {\ifdim\lastskip=\zeropoint
+ \ifnum\lastpenalty=\zerocount
+ \ifnum\lastkern=\zerocount
+ \let\poplastnode\relax
+ \else
+ \edef\poplastnode{\kern\the\lastkern\relax}\kern-\lastkern % untested
+ \fi
+ \else
+ \edef\poplastnode{\penalty\the\lastpenalty\relax}\nobreak % untested
+ \fi
+ \else
+ \edef\poplastnode{\vskip\the\lastskip\relax}\vskip-\lastskip % \removelastskip
+ \fi}
+
+%D The dreadful sequence \type {\bgroup} \unknown\
+%D \type {\carryoverpar} \unknown\ \type {\egroup} is needed
+%D when for instance sidefloats are used in combination with
+%D something that starts with a group. This is because
+%D otherwise the indentation as set (by the output routine)
+%D inside the group are forgotten afterwards. (I must
+%D not forget its existence).
+
+\global\let\carriedoverpar\relax
+
+\def\carryoverpar#1%
+ {\expanded % \scratchtoks{#1}%
+ {\noexpand#1% \the\scratchtoks
+ \hangindent\the\hangindent
+ \hangafter \the\hangafter
+ \parskip \the\parskip
+ \leftskip \the\leftskip
+ \rightskip \the\rightskip}}
+
+%D A quick way to determine left|/|middle|/|right states
+%D (experimental).
+
+\setvalue{\??as\v!left }{0}
+\setvalue{\??as\v!middle}{1}
+\setvalue{\??as\v!right }{2}
+
+\def\setalignmentswitch#1%
+ {\chardef\alignmentswitch0\csname\??as#1\endcsname\relax}
+
+%D There are two ways to influence the interline spacing. The
+%D most general and often most consistent way is using
+%D
+%D \showsetup{setupinterlinespace}
+%D
+%D For instance
+%D
+%D \starttyping
+%D \setupinterlinespace[line=2.8ex]
+%D \stoptyping
+%D
+%D This setting adapts itself to the bodyfontsize, while for
+%D instance saying
+%D
+%D \starttyping
+%D \setupinterlinespace[line=12pt]
+%D \stoptyping
+%D
+%D sets things fixed for all sizes, which is definitely not
+%D what we want. Therefore one can also say:
+%D
+%D \starttyping
+%D \definebodyfontenvironment[9pt][interlinespace=11pt]
+%D \stoptyping
+%D
+%D One can still use \type{\setupinterlinespace} (without
+%D arguments) to set the interline space according to the
+%D current font, e.g. a \type{\bfa}.
+
+\newif\iflocalinterlinespace
+
+% font-ini
+
+\ifx\bodyfontinterlinespecs\undefined
+
+ \let\bodyfontinterlinespecs\empty
+ \let\bodyfontinterlinespace\empty
+
+\fi
+
+\def\presetnormallineheight
+ {\edef\normallineheight{\@@itline}%
+% done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
+ \iflocalinterlinespace \else
+ \doifdefined\bodyfontinterlinespecs
+ {\doifsomething\bodyfontinterlinespace
+ {\edef\normallineheight{\bodyfontinterlinespace}}}%
+ \fi}
+
+\def\setupspecifiedinterlinespace[#1]%
+ {\getparameters[\??it][#1]%
+ \scratchdimen0\@@itheight\points
+ \advance\scratchdimen 0\@@itdepth\points
+ \ifdim\scratchdimen>\onepoint
+ \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
+ \let\@@itheight\strutheightfactor
+ \let\@@itdepth \strutdepthfactor
+ \else
+ \let\strutheightfactor\@@itheight
+ \let\strutdepthfactor \@@itdepth
+ \fi
+ \let\minimumstrutheight \@@itminheight
+ \let\minimumstrutdepth \@@itmindepth
+ \let\minimumlinedistance\@@itdistance
+ \let\normallineheight \@@itline % let ! ! ! ! ! ivm ex
+ \doifelse\@@ittop\v!height % new, topskip does more bad than good
+ {\let\topskipfactor \@@itheight}
+ {\let\topskipfactor \@@ittop }%
+ \let\maxdepthfactor \@@itbottom
+ \let\baselinegluefactor \@@itstretch
+ \setfontparameters % redundant, can be \setstrut, test first
+ \updateraggedskips} % yes indeed
+
+\let\currentrelativeinterlinespace\empty
+
+\def\setuprelativeinterlinespace[#1]%
+ {\processallactionsinset
+ [#1]
+ [ \v!on=>\oninterlineskip,
+ \v!off=>\offinterlineskip,
+ \v!reset=>\let\currentrelativeinterlinespace\empty
+ \let\setrelativeinterlinespace\relax
+ \setfontparameters,
+ \v!auto=>\let\setrelativeinterlinespace\dosetrelativeinterlinespace,
+ \s!unknown=>\assignvalue\commalistelement\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
+ \spacing\currentrelativeinterlinespace]}
+
+\def\dosetrelativeinterlinespace
+ {\ifx\currentrelativeinterlinespace\empty\else
+ \spacing\currentrelativeinterlinespace
+ \fi}
+
+\let\setrelativeinterlinespace\relax
+
+% \appendtoks \setrelativeinterlinespace \to \everybodyfont
+
+\def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
+ {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]}
+
+\def\setuplocalinterlinespace[#1]%
+ {\localinterlinespacetrue
+ \setupinterlinespace[#1]%
+ \localinterlinespacefalse}
+
+\def\simplesetupinterlinespace
+ {\localinterlinespacetrue
+ \setfontparameters
+ \updateraggedskips % funny one here
+ \localinterlinespacefalse}
+
+\definecomplexorsimple\setupinterlinespace
+
+% In earlier versions \type{\bigskipamount} was
+% \type{\ht\strutbox} and the stretch was plus or minus
+% \type{.4\dp\strutbox}. Don't ask me why. The most recent
+% implementation is based on a user supplied distance, which
+% is by default \type{.75\normalskipamount} where
+% \type{\normalskipamount} equals the current baseline
+% distance.
+
+% \lineskiplimit = -\maxdimen -> freezes baselineskip
+
+% can be conditionals
+
+\newif\ifblanknowhite \blanknowhitefalse
+\newif\ifblankindeed \blankindeedfalse
+\newif\ifblankreset \blankresetfalse
+\newif\ifblankdisable \blankdisablefalse
+\newif\ifblankflexible \blankflexibletrue
+\newif\ifblankouter
+\newif\ifblankforce
+\newif\ifblankgoback
+
+\newskip\blankskip \blankskip=\bigskipamount
+\newskip\blankskipamount
+
+\def\skipfactor {.75}
+\def\skipgluefactor{.25}
+
+\def\normalskipamount
+ {\openlineheight
+ \ifgridsnapping \else \ifblankflexible
+ \!!plus \skipgluefactor\openlineheight
+ \!!minus\skipgluefactor\openlineheight
+ \fi \fi
+ \relax}
+
+\def\linedistance {\normalskipamount}
+\def\appliedblankskip{\skipfactor\linedistance}
+\def\lastblankskip {\blankskip}
+\def\currentblank {\v!big}
+\def\oldprevdepth {\prevdepth}
+\def\newprevdepth {-1001pt}
+\def\mindimen {1sp} % was: 0.00002pt
+
+\newif\iflocalblankfixed
+\newif\iflocalblankflexible
+
+\def\geenblanko{\removelastskip} % will become obsolete
+
+%%%% pas op, wordt ook in core-pos gebruikt
+
+\def\doassignsomeskip#1\to#2% ook nog \v!halfline+fuzzysnap
+ {\doifelse{#1}\v!line
+ {#2\openlineheight}
+ {\ifgridsnapping
+ \assigndimension{#1}{#2}{.25\openlineheight}{.5\openlineheight}\openlineheight
+ \else
+ \assigndimension{#1}{#2}\smallskipamount\medskipamount\bigskipamount
+ \fi}%
+ \relax}
+
+% \relax is really needed, else we may loose stretch due to lookahead; somehow
+% this bug was introduced a while ago but somehow went unnoticed; fixed 2/7/2008
+
+\def\addblankskip#1#2#3{\global\advance\blankskip#1\ifgridsnapping#3\else#2\fi\relax}
+
+\def\defineblankmethod[#1]#2{\setvalue{\??bo\??bo#1}{#2}}
+
+\defineblankmethod [\v!big] {\addblankskip+\bigskipamount \openlineheight}
+\defineblankmethod [-\v!big] {\addblankskip-\bigskipamount \openlineheight}
+\defineblankmethod [\v!medium] {\addblankskip+\medskipamount {.5\openlineheight}}
+\defineblankmethod [-\v!medium] {\addblankskip-\medskipamount {.5\openlineheight}}
+\defineblankmethod [\v!small] {\addblankskip+\smallskipamount{.25\openlineheight}}
+\defineblankmethod [-\v!small] {\addblankskip-\smallskipamount{.25\openlineheight}}
+\defineblankmethod [\v!white] {\addblankskip+\parskip \openlineheight}
+\defineblankmethod [-\v!white] {\addblankskip-\parskip \openlineheight}
+\defineblankmethod [\v!line] {\addblankskip+\openlineheight \openlineheight}
+\defineblankmethod [-\v!line] {\addblankskip-\openlineheight \openlineheight}
+
+\defineblankmethod [\v!formula] {\global\advance\blankskip\medskipamount}
+\defineblankmethod [\v!nowhite] {\global\blanknowhitetrue}
+\defineblankmethod [\v!disable] {\global\blankdisabletrue}
+\defineblankmethod [\v!force] {\global\blankforcetrue}
+\defineblankmethod [\v!outer] {\ifvmode\ifinner\blankoutertrue\fi\fi}
+\defineblankmethod [\v!reset] {\global\blankresettrue}
+\defineblankmethod [\v!flexible] {\global\localblankflexibletrue}
+\defineblankmethod [\v!fixed] {\global\localblankfixedtrue}
+\defineblankmethod [\v!back] {\global\blankgobacktrue} % {\geenblanko}
+\defineblankmethod [\v!halfline] {\ifgridsnapping\global\fuzzyvskiptrue\fi
+ \global\advance\blankskip .5\lineheight}
+
+\defineblankmethod [\v!none] {\global\blankresettrue}
+\defineblankmethod [\v!joinedup] {\ifvmode\nointerlineskip\fi}
+
+\defineblankmethod [\v!always] {\redowhitespace} % experimental
+
+% happens often, so we speed this up:
%
-% larger wins
+% \defineblankmethod [2*\v!line] {\addblankskip+{2\openlineheight}{2\openlineheight}}
+% \defineblankmethod [2*\v!big] {\addblankskip+{2\bigskipamount }{2\openlineheight}}
+%
+% no, with 2\whatever we loose the stretch and shrink! Taco's alternative:
-% order:
+\defineblankmethod
+ [2*\v!line]
+ {\addblankskip+\openlineheight\openlineheight
+ \addblankskip+\openlineheight\openlineheight}
+
+\defineblankmethod
+ [2*\v!big]
+ {\addblankskip+\bigskipamount\openlineheight
+ \addblankskip+\bigskipamount\openlineheight}
+
+\def\doblank#1%
+ {\edefconvertedargument\ascii{#1}%
+ \ifx\ascii\empty\else
+ \ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+ \else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+ \else
+ \dorepeatwithcommand[#1]\redoblank
+ \fi\fi
+ \fi
+ \relax}
+
+\def\redoblank#1%
+ {\edefconvertedargument\ascii{#1}%
+ \ifx\ascii\empty\else
+ \ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+ \else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+ \else
+ \global\advance\blankskip#1\relax
+ \fi\fi
+ \fi
+ \relax}
+
+\unexpanded\def\blank % the \relax is definitely needed due to the many \if's
+ {\relax\complexorsimple\doblank}
+
+\def\complexdoblank
+ {\flushnotes
+ \ifmmode
+ \@EA\nocomplexdoblank
+ \else
+ \ifopelkaar
+ \ifinpagebody
+ \@EA\@EAEAEA\@EA\docomplexdoblank
+ \else
+ \@EA\@EAEAEA\@EA\nocomplexdoblank
+ \fi
+ \else
+ \@EAEAEA\docomplexdoblank
+ \fi
+ \fi}
+
+\def\nocomplexdoblank[#1]%
+ {% evt blokkeerfalse
+ \ifmmode\else\par\fi}
+
+% Overloaded in cont-new!
+
+\newsignal\noblanksignal
+
+% problem: we cannot look back in the mvl so we need 3 kinds of signals
+
+\def\noblankpsignal{1010101}
+
+\def\inhibitgridblank % was doinhibitblank
+ {\ifvmode\else\endgraf\fi
+ \ifvmode
+ \ifnum\lastpenalty<10000
+ \kern-\noblanksignal % new
+ \kern \noblanksignal
+ \else
+ \penalty\noblankpsignal
+ \fi
+ \fi}
+
+\def\inhibittextblank % was inhibitblank
+ {\endgraf
+ \ifvmode
+ \prevdepth\newprevdepth
+ \fi}
+
+% new macro
%
-% larger wins
+% \def\inhibitblank % need some work
+% {\endgraf
+% \ifvmode
+% \ifgridsnapping
+% \inhibitgridblank
+% \else
+% % this one spoils the grid
+% \inhibittextblank
+% \fi
+% \fi}
-\defineattribute[kern-chars]
+\def\doinhibitblank{\inhibitgridblank}
+\def\inhibitblank {\inhibittextblank}
-\defineattribute[skip-category]
-\defineattribute[skip-penalty]
-\defineattribute[skip-order]
+% will become obsolete
-\defineattribute[snap-category]
+\ifx\undefined\savedlastskip \newskip \savedlastskip \fi
+\ifx\undefined\savedlastpenalty \newcount\savedlastpenalty \fi
-\defineattribute[display-math]
+% beware, prevdepth can have funny values (e.g. mvl value when in box)
-\registerctxluafile{core-spa}{1.001}
+\def\docomplexdoblank[#1]% pas op \relax's zijn nodig ivm volgende \if
+ {\global\blankresetfalse
+ \global\blankdisablefalse
+ \global\blanknowhitefalse
+ \global\localblankflexiblefalse
+ \global\localblankfixedfalse
+ \global\blankforcefalse
+ \global\blankgobackfalse
+ \blankouterfalse
+ \global\blankskip\zeropoint
+%
+\edefconvertedargument\ascii{#1}% todo fast check for simple
+\ifcsname\??bo\??bo\ascii\endcsname % internal def
+ \csname\??bo\??bo\ascii\endcsname
+\else\ifcsname\??bo\ascii\endcsname % user def / slow
+ \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
+\else
+ \expanded{\rawprocesscommalist[#1]}\doblank
+\fi\fi
+%
+ \relax % to be sure
+ \ifdim\blankskip=\zeropoint\relax
+ \iflocalblankflexible
+ \doglobal\advance\blankskip \currentblank
+ \else\iflocalblankfixed
+ \doglobal\advance\blankskip \currentblank
+ \fi\fi
+ \fi
+ \relax % to be sure
+ \ifblankouter
+ % do nothing
+ \else
+ \par
+ \ifvmode
+ \ifblankgoback
+ \ifdim\lastskip>\zeropoint \vskip-\lastskip \fi
+ \savedlastskip\zeropoint
+ \else\ifdim\lastskip>\zeropoint
+ \savedlastskip\lastskip
+ \else % todo: lastnode, dan namelijk geen skip !
+ \savedlastskip\zeropoint
+ \fi\fi
+ \ifblankforce
+ % dit gaat mis in pos fonts
+ % \ifdim\prevdepth>\zeropoint\else ...
+ % -1000pt signals top of page or column (\ejectcolumn)
+ \bgroup\forgeteverypar\verticalstrut\egroup\kern-\struttotal
+ \savedlastskip\zeropoint
+ \fi
+ \savedlastpenalty\lastpenalty % hm, now it gets lost
+ \ifblankdisable
+ \global\blankindeedfalse % keep this, i.e. disable current too
+ \ifgridsnapping
+ \ifdim\prevdepth<\zeropoint
+ % brrr
+ \else
+ % dirty trick: smaller blanks are ignored after a
+ % larger one, so 10 lines is probably safe; we need
+ % to make sure that we honor penalties; here comes the
+ % trick (cross our fingers that this works well in
+ % multi columns; maybe an ifinner test is needed
+ % \scratchcounter\lastpenalty
+ % \vskip-10\lineheight
+ % \ifnum\scratchcounter=\zerocount \else \penalty\lastpenalty \fi
+ % \vskip 10\lineheight
+ % alas, this leads to overfull pages, so we try this:
+ \inhibitgridblank
+ \fi
+ \else
+ \ifdim\prevdepth<\zeropoint
+ % brrr
+ \else
+ % ensure at least a proper prevdepth, this should be
+ % an option
+ \vskip-\prevdepth
+ \vskip\strutdepth
+ \prevdepth\strutdepth
+ \fi
+ % the old crappy piece of code
+ \edef\oldprevdepth{\the\prevdepth}%
+ \prevdepth\newprevdepth % == \inhibittextblank
+ \fi
+ \else
+ \global\blankindeedtrue
+ \fi
+ \ifblankreset
+ \global\blankindeedtrue
+ \ifgridsnapping
+ % let's play safe and not fool around with the depth, if
+ % only because it took a lot of effort to sort out the grid
+ % stuff in the first place
+ \else
+ \ifdim\prevdepth=\newprevdepth
+ \prevdepth\oldprevdepth
+ \fi
+ \fi
+ \fi
+ \ifblankindeed
+ \ifdim1\savedlastskip<1\blankskip\relax
+ % else when \blank[2*groot] + \blank[3*groot] with parskip
+ % equaling 1*groot, gives a groot=\parskip so adding a small
+ % value makes it distinguishable; can also be done at parskip
+ % setting time (better)
+ \global\advance\blankskip \mindimen\relax % = skip
+ % test this on 2* + 3* and parskip groot
+ \ifblanknowhite
+ \global\advance\blankskip -\parskip
+ \else
+ \ifdim\savedlastskip=\parskip
+ \else % force this due to previous comment
+ \ifdim\parskip>\zeropoint\relax
+ \ifdim\blankskip<\parskip\relax
+ \global\blankskip\zeropoint
+ \else
+ \global\advance\blankskip -\parskip
+ \fi
+ \fi
+ \fi
+ \fi
+ \ifblankflexible \else
+ \blankskip1\blankskip
+ \fi
+ \iflocalblankfixed
+ \blankskip1\blankskip
+ \fi
+ \iflocalblankflexible
+ \blankskip1\blankskip
+ \!!plus \skipgluefactor\blankskip
+ \!!minus\skipgluefactor\blankskip
+ \fi
+ \ifdim\lastkern=\noblanksignal\relax % controlled and grid
+ \global\blankindeedfalse
+ \else\ifnum\savedlastpenalty=\noblankpsignal\relax % controlled and grid
+ \global\blankindeedfalse
+ \else\ifgridsnapping\else\ifdim\prevdepth=\newprevdepth
+ \global\blankindeedfalse
+ \fi\fi\fi\fi
+ \ifblankindeed
+ \iffuzzyvskip
+ \removelastfuzzyvskip
+ \fuzzyvskip\blankskip\relax
+ \else
+ \relax\ifdim\savedlastskip=\zeropoint\else
+ \vskip-\savedlastskip
+ \fi
+ \vskip\blankskip\relax
+ \fi
+ \fi
+ \else
+ \iffuzzyvskip
+ \removelastfuzzyvskip
+ \fuzzyvskip\blankskip\relax
+ \else
+ % new, test this on pascal
+ \ifdim\blankskip<\zeropoint
+ \relax\ifdim\savedlastskip=\zeropoint\else
+ \advance\blankskip-\savedlastskip
+ \vskip-\savedlastskip
+ \fi
+ \ifdim\blankskip>\zeropoint
+ \vskip\blankskip
+ \else
+ \vskip\zeropoint
+ \fi
+ \else
+ % also new
+ \ifdim\blankskip=\zeropoint
+ \ifblanknowhite
+ \nowhitespace
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \global\fuzzyvskipfalse
+ \presetindentation}
-% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop
-% \start \dosetstretch{.5em} effe flink doorfietsen \stop
+%D For a long time we had:
+%D
+%D \starttyping
+%D \def\simpledoblank%
+%D {\doifelse{\currentwhitespace}{\v!geen}
+%D {\blank[\currentblank]}
+%D {\blank[\currentwhitespace]}}
+%D \stoptyping
+%D
+%D But Berend de Boer wanted more control, so now we have:
-\def\dosetstretch#1% to be interfaces
- {\relax\ifdim#1>\zeropoint
- \dosetattribute{kern-chars}{\number\dimexpr#1\relax}%
+\def\simpledoblank % ...
+ {\doifelse\currentwhitespace\v!none
+ {\blank[\currentblank]}
+ {\blank[\s!default]}}
+
+%D Another useful definition would be:
+%D
+%D \starttyping
+%D \defineblank
+%D [\s!default]
+%D [\v!groot]
+%D \stoptyping
+
+\def\dosetupblank#1% amount are an plain inheritance
+ {\bigskipamount#1\relax
+ \ifblankflexible \else
+ \bigskipamount1\bigskipamount
+ \fi
+ \medskipamount \bigskipamount \divide\medskipamount \plustwo
+ \smallskipamount\bigskipamount \divide\smallskipamount\plusfour}%
+
+\def\complexsetupblank[#1]% more \let's -> this also wil become installable
+ {\ifgridsnapping
+ \blankflexiblefalse
\else
- \doresetattribute{kern-chars}%
+ \ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!flexible=>\blankflexibletrue,
+ \v!fixed=>\blankflexiblefalse]%
+ \fi
+ \ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!flexible=>\dosetupblank\appliedblankskip,
+ \v!fixed=>\dosetupblank\appliedblankskip,
+ \v!line=>\edef\appliedblankskip{\linedistance}%
+ \dosetupblank\appliedblankskip,
+ \v!halfline=>\scratchskip.5\linedistance
+ \edef\appliedblankskip{\the\scratchskip}%
+ \dosetupblank\appliedblankskip,
+ \v!big=>\ifgridsnapping
+ \edef\appliedblankskip{\linedistance}%
+ \dosetupblank\appliedblankskip
+ \fi
+ \let\currentblank\v!big,
+ \v!medium=>\let\currentblank\v!medium,
+ \v!small=>\let\currentblank\v!small,
+ \v!global=>\let\currentblank\v!global,
+ \v!normal=>\dosetupblank\appliedblankskip,
+ \v!standard=>\edef\appliedblankskip{\skipfactor\linedistance}%
+ \dosetupblank\appliedblankskip,
+ \s!default=>\dosetupblank\appliedblankskip,
+ \s!unknown=>\let\appliedblankskip\commalistelement
+ \dosetupblank\appliedblankskip]%
+ \simplesetupwhitespace}
+
+% \definecomplexorsimpleempty\setupblank
+%
+% speed gain: 60 sec -> 30 sec
+
+\definecomplexorsimple\setupblank
+
+\def\simplesetupblank % == snelle \setupblank[\s!default]
+ {\ifgridsnapping
+ \blankflexiblefalse
+ \fi
+ \dosetupblank\appliedblankskip
+ % \let\deblanko\v!big
+ \simplesetupwhitespace}
+
+\def\restorestandardblank% \v!standard
+ {\edef\appliedblankskip{\skipfactor\linedistance}%
+ \dosetupblank\appliedblankskip
+ }%\let\deblanko\v!big}
+
+\def\dodefineblank[#1][#2]%
+ {\def\docommand##1{\setvalue{\??bo##1}{#2}}%
+ \processcommalist[#1]\docommand}
+
+\def\defineblank
+ {\dodoubleargument\dodefineblank}
+
+\def\savecurrentblank
+ {\edef\restorecurrentblank
+ {\bigskipamount\the\bigskipamount
+ \medskipamount\the\medskipamount
+ \smallskipamount\the\smallskipamount
+ \noexpand\def\noexpand\currentblank{\currentblank}%
+ \ifblankflexible
+ \noexpand\blankflexibletrue
+ \else
+ \noexpand\blankflexiblefalse
+ \fi}}
+
+%D Now.
+
+\defineblank [\s!default] [\v!white]
+\defineblank [\v!height] [\strutheight]
+\defineblank [\v!depth] [\strutdepth]
+
+\let\currentindentation\empty % amount/keyword
+% \let\normalindentation \empty % used for reinstating normal indentation
+\let\currentindenting \empty % method
+
+\newdimen\ctxparindent
+
+\newif\ifindentfirstparagraph % \indentfirstparagraphtrue
+
+\chardef\indentingtoggle\zerocount
+
+%D After a blank or comparable situation (left side floats) we
+%D need to check if the next paragraph has to be indented.
+
+\def\presetindentation
+ {\doifoutervmode{\ifindentfirstparagraph\else\noindentation\fi}}
+
+%D This sets up the (normally) global indentation behavior as well
+%D as the amounts.
+
+\definecomplexorsimple\setupindenting
+
+\indentfirstparagraphtrue
+\parindent\ctxparindent
+\chardef\indentingtoggle\zerocount
+
+% we need a better everypar model: for each option a switch, which we
+% set to false with \forgetall and can enable when needed (context 4);
+% that way we can control the order of execution of options
+
+\def\checkeverypar % currently a hack
+ {\ifzeropt\parindent\else
+ \doifsometokselse\everypar\donothing{\appendtoks\checkindentation\to\everypar}%
\fi}
-\appendtoks\doresetattribute{kern-chars}\to\everyforgetall
+\def\complexsetupindenting[#1]%
+ {\edef\currentindenting{#1}%
+ \doifsomething\currentindenting % handy when a parameter is passed
+ {% not here: \indentfirstparagraphtrue
+ % not here: \parindent\ctxparindent
+ % not here: \chardef\indentingtoggle\zerocount
+ % we use commacommand in order to catch #1 being a command (expanded parameter)
+ \processcommacommand[\currentindenting]\docomplexsetupindentingA % catch small, medium, etc
+ \processcommacommand[\currentindenting]\docomplexsetupindentingB % catch rest
+ \checkeverypar % only when non-empty #1
+ \ifindentfirstparagraph\else\noindentation\fi % added
+ \toggleindentation}}
-\def\mksetupgridsnapping
- {\ctxlua{nodes.setsnapvalue(1,\number\openstrutheight,\number\openstrutdepth)}}
+\def\docomplexsetupindentingA#1%
+ {\edefconvertedargument\!!stringa{#1}%
+ \doifundefined{\??in:\!!stringa}%
+ {\edef\currentindentation{#1}%
+ \let\normalindentation\currentindentation
+ \simplesetupindenting}}
-\def\mkenablegridsnapping
- {\dosetattribute{snap-category}{1}%
- \topskip\strutht
- \offinterlineskip}
+\def\docomplexsetupindentingB#1%
+ {\edefconvertedargument\!!stringa{#1}% catch #1=\somedimen
+ \executeifdefined{\??in:\!!stringa}\donothing}
-\def\mkdisablegridsnapping
- {\doresetattribute{snap-category}%
- % reset topskip
- \oninterlineskip}
+\def\simplesetupindenting % empty case, a it strange, needed this way?
+ {\assigndimension\currentindentation\ctxparindent{1em}{1.5em}{2em}}
+
+\def\indenting % kind of obsolete
+ {\dosingleargument\complexsetupindenting}
+
+% use \noindentation to suppress next indentation
+
+\def\defineindentingmethod[#1]#2%
+ {\setvalue{\??in:#1}{#2}}
+
+\defineindentingmethod [\v!no] {\parindent\zeropoint}% was: \ctxparindent\noindent}
+\defineindentingmethod [\v!not] {\parindent\zeropoint}% was: \ctxparindent\noindent}
+
+\defineindentingmethod [\v!first] {\indentfirstparagraphtrue}
+\defineindentingmethod [\v!next] {\indentfirstparagraphfalse}
+
+\defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent !
+\defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent !
+
+\defineindentingmethod [\v!never] {\parindent\zeropoint\relax % no \indent !
+ \chardef\indentingtoggle\zerocount}
+
+\defineindentingmethod [\v!odd] {\chardef\indentingtoggle\plusone}
+\defineindentingmethod [\v!even] {\chardef\indentingtoggle\plustwo}
+
+\defineindentingmethod [\v!normal] {\ifx\normalindentation\empty\else
+ \let\currentindentation\normalindentation
+ \simplesetupindenting
+ \fi}
+
+\defineindentingmethod [\v!reset] {\indentfirstparagraphtrue
+ \parindent\zeropoint
+ \chardef\indentingtoggle\zerocount}
+
+\def\noindenting{\indenting[\v!no, \v!next ]}
+\def\doindenting{\indenting[\v!yes,\v!first]}
+
+%D This one sets up the local indentation behaviour (i.e. either or not
+%D a next paragraph will be indented).
+
+\def\dochecknextindentation#1% internal one
+ {\checknextindentation[\csname#1\c!indentnext\endcsname]}
+
+\setvalue{\??in->\s!empty}{}
+\setvalue{\??in->\v!yes }{\doindentation}
+\setvalue{\??in->\v!no }{\noindentation}
+\setvalue{\??in->\v!auto }{\autoindentation}
+
+\def\checknextindentation[#1]%
+ {\csname\??in->\ifcsname\??in->#1\endcsname#1\else\s!empty\fi\endcsname}
+
+%D Here come the handlers.
+
+\newif\ifindentation \indentationtrue % documenteren, naar buiten
+
+\let\checkindentation\relax
+
+\ifx\autoindentation\undefined \let\autoindentation\relax \fi % hook
+
+\def\doindentation
+ {\gdef\checkindentation{\global\indentationtrue}}
+
+\def\noindentation % made global
+ {\ifinpagebody \else
+ \global\indentationfalse
+ \gdef\checkindentation
+ {\donoindentation
+ \gdef\checkindentation{\global\indentationtrue}}%
+ \fi}
-% experimental mirroring
+\def\nonoindentation % bv bij floats
+ {\ifinpagebody \else
+ \global\indentationtrue
+ \gdef\checkindentation{\global\indentationtrue}%
+ \fi}
-\defineattribute[mirror]
+\def\donoindentation
+ {\ifdim\parindent=\zeropoint \else
+ \bgroup \setbox\scratchbox\lastbox \egroup
+ \fi}
-\def\setcharactermirroring
- {\ctxlua{mirror.enabled=true}%
- \gdef\setcharactermirroring[##1]{\dosetattribute{mirror}{\number##1}}%
- \setcharactermirroring}
+\def\indentation
+ {\ifvmode \ifdim\parindent=\zeropoint \else
+ % was : \hskip\parindent
+ % can be: \indent
+ % but we test:
+ \noindent\hskip\parindent
+ \fi \fi}
-\def\resetcharactermirroring
- {\doresetattribute{mirror}}
+\def\toggleindentation
+ {\ifcase\indentingtoggle
+ % nothing
+ \or
+ \notoggleindentation
+ \or
+ \dotoggleindentation
+ \fi}
-\newtoks\everysetupdirections
+\def\dokillindentation
+ {\gdef\checkindentation{\global\indentationfalse\donoindentation}}
-\def\setupdirections[#1]% there will be more like setting up directions themselves
- {\getparameters[\??di][#1]%
- \the\everysetupdirections}
+\def\dotoggleindentation
+ {\gdef\checkindentation{\global\indentationfalse\notoggleindentation\donoindentation}}
-\chardef\directionsbidimode=0
+\def\notoggleindentation
+ {\gdef\checkindentation{\global\indentationtrue\dotoggleindentation}}
-\letvalue{\??di:bidi:\v!off }\zerocount
-\letvalue{\??di:bidi:\v!global}\plusone
-\letvalue{\??di:bidi:\v!local }\plustwo
-\letvalue{\??di:bidi:\v!on }\plustwo
+\appendtoks
+ \pushmacro\checkindentation
+ \pushmacro\ifindentation
+\to \everypushsomestate
\appendtoks
- \chardef\directionsbidimode\executeifdefined{\??di:bidi:\@@dibidi}\zerocount\relax
- \ifcase\directionsbidimode
- \resetcharactermirroring
- \or
- \setcharactermirroring[1]% global, chars
- \or
- \setcharactermirroring[2]% local, attributes
- \or
- \setcharactermirroring[1]% default
- \fi
-\to \everysetupdirections
+ \popmacro\ifindentation
+ \popmacro\checkindentation
+\to \everypopsomestate
+
+% we need to save the state if we want to adapt behaviour to empty lines
+%
+% \def\setlasthvmode
+% {\global\chardef\savedhvmode\ifhmode\plusone\else\ifvmode\plustwo\else\zerocount\fi\fi}
+%
+% \def\resetlasthvmode
+% {\global\chardef\savedhvmode\zerocount}
+%
+% \chardef\savedhvmode\zerocount
+
+% This is a user requested hack (using the auto-hook).
+
+\chardef\recheckindentationmode\zerocount
+
+\def\dontrechecknextindentation
+ {\global\chardef\recheckindentationmode\zerocount}
+
+\def\dorechecknextindentation
+ {\ifcase\recheckindentationmode
+ % nothing
+ \or
+ \dontrechecknextindentation
+ \expandafter\doautoindentation
+ \fi}
+
+\def\doautoindentation
+ {\doifnextcharelse\par\donothing\noindentation}
+
+\def\autoindentation
+ {\global\chardef\recheckindentationmode\plusone}
+
+%D An example of usage:
+%D
+%D \starttyping
+%D \setupindenting[small,yes]
+%D
+%D \setupitemize [indentnext=auto]
+%D \setuptyping [indentnext=auto]
+%D \setupformulas[indentnext=auto]
+%D
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D
+%D \input tufte
+%D
+%D \startitemize
+%D \item itemize
+%D \stopitemize
+%D
+%D \page
+%D
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D
+%D \input tufte
+%D
+%D \starttyping
+%D verbatim
+%D \stoptyping
+%D
+%D \page
+%D
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+%D
+%D \input tufte
+%D
+%D \startformula
+%D a = b
+%D \stopformula
+
+
+%D \macros
+%D {frenchspacing,nonfrenchspacing}
+%D
+%D Smehow \type{\frenchspacing} can lead to hyphenation between
+%D dashes so we now have \type {\newfrenchspacing} (moved from
+%D \type {syst-chr}).
+
+%D Hm ... todo:
+
+\sfcode`\)=0
+\sfcode`\'=0
+\sfcode`\]=0
+
+\def\setfrenchspacing#1%
+ {\sfcode`\.#1 \sfcode`\,#1\relax
+ \sfcode`\?#1 \sfcode`\!#1\relax
+ \sfcode`\:#1 \sfcode`\;#1\relax}
+
+\def\frenchspacing
+ {\setfrenchspacing{1000}}
+
+\def\resetfrenchspacing
+ {\sfcode`\.3000 \sfcode`\,1250
+ \sfcode`\?3000 \sfcode`\!3000
+ \sfcode`\:2000 \sfcode`\;1500 }
-% bidi: local=obey grouping, global=ignore grouping (unicode has no grouping)
+\def\frenchspacing {\setfrenchspacing{1000}}
+\def\newfrenchspacing{\setfrenchspacing{1050}}
+\def\nonfrenchspacing{\resetfrenchspacing}
-\setupdirections % maybe start/stop
- [bidi=\v!off]
+\def\definespacingmethod[#1]#2{\setvalue{\??sg\??sg#1}{#2}}
-\unexpanded\def\bidilre{\utfchar{"0x202A}}
-\unexpanded\def\bidirle{\utfchar{"0x202B}}
-\unexpanded\def\bidipop{\utfchar{"0x202C}}
-\unexpanded\def\bidilro{\utfchar{"0x202D}}
-\unexpanded\def\bidirlo{\utfchar{"0x202E}}
+\definespacingmethod[\v!packed]{\newfrenchspacing}
+\definespacingmethod[\v!broad ]{\nonfrenchspacing}
-\unexpanded\def\dirlre{\ifcase\directionsbidimode\or\bidilre\or\textdir TLT\fi}
-\unexpanded\def\dirrle{\ifcase\directionsbidimode\or\bidirle\or\textdir TRT\fi}
-\unexpanded\def\dirlro{\ifcase\directionsbidimode\or\bidilro\or\setcharactermirroring[3]\fi}
-\unexpanded\def\dirrlo{\ifcase\directionsbidimode\or\bidirlo\or\setcharactermirroring[4]\fi}
+\def\complexsetupspacing[#1]%
+ {\executeifdefined{\??sg\??sg#1}\relax
+ \updateraggedskips}
-% test at end of file
+\def\simplesetupspacing
+ {\updateraggedskips}
-% for the moment: \setcharactermirroring[\plusone]
+\definecomplexorsimple\setupspacing
+
+% \dorecurse{100}{\recurselevel\spacefactor 800 \space} \par
+% \dorecurse{100}{\recurselevel\spacefactor1200 \space} \par
+% \dorecurse{100}{\recurselevel\spacefactor 800 \normalspaceprimitive} \par
+% \dorecurse{100}{\recurselevel\spacefactor1200 \normalspaceprimitive} \par
-% experimental spacing
+% When we don't add the % here, we effectively get \<endlinechar> and
+% since we have by default \def\^^M{\ } we get into a loop.
+
+\let\normalspaceprimitive=\ % space-comment is really needed
+
+\unexpanded\def\ {\mathortext\normalspaceprimitive\space} % no \dontleavehmode\space (else no frenchspacing)
+
+\unexpanded\def\nonbreakablespace{\penalty\plustenthousand\space}
+
+\letcatcodecommand \ctxcatcodes `\~ \nonbreakablespace % overloaded later
+
+\def\space { }
+\def\removelastspace{\ifhmode\unskip\fi}
+\def\nospace {\removelastspace\ignorespaces}
+
+% in tables we need:
%
-% test: oeps {\setcharacterspacing[frenchpunctuation]x: xx \bfd x: xx} oeps: test
+% \def\fixedspace {\hskip.5em\relax}
+%
+% but, since not all fonts have .5em digits:
-\defineattribute[spacing]
+\unexpanded\def\fixedspace
+ {\setbox\scratchbox\normalhbox{\mathortext{0}{0}}%
+ \hskip\wd\scratchbox\relax}
-\newcount \maxcharacterspacingid
+\def\fixedspaces
+ {\letcatcodecommand \ctxcatcodes `\~ \fixedspace}
-\def\definecharacterspacing[#1]%
- {\ifcsname\??ch#1\endcsname \else
- \global\advance\maxcharacterspacingid\plusone
- \setxvalue{\??ch:#1}{\the\maxcharacterspacingid}%
+\def\removeunwantedspaces
+ {\ifhmode % we also need to unskip 0pt skips
+ \unskip\unskip\unskip\unskip\unskip
+ \unskip\unskip\unskip\unskip\unskip
\fi}
-\def\setupcharacterspacing
- {\dotripleargument\dosetupcharacterspacing}
+\appendtoks\let~\space\to\simplifiedcommands
-\def\dosetupcharacterspacing[#1][#2][#3]%
- {\ifcsname\??ch:#1\endcsname
- \begingroup % for the moment we use modes, in ordere to avoid interface translation
- \getparameters[\??ch][\c!left=0,\c!right=0,\c!alternative=0,#3]%
- \ctxlua{spacings.setspacing(\getvalue{\??ch:#1},\number#2,\@@chleft,\@@chright,\@@chalternative)}%
- \endgroup
+% still not fixed in aleph / luatex
+%
+% \def\removeunwantedspaces
+% {\ifhmode \ifnum\lastnodetype=\@@gluenode
+% \unskip \@EAEAEA\removeunwantedspaces
+% \fi \fi}
+
+%D For old time sake, will disappear soon.
+
+\let\hardespatie\fixedspace
+\let\geenspatie \nospace
+
+% \startbuffer
+% \startlines \tt \fixedspaces
+% 0~1~~2~~~3~~~~4~~~~~5
+% 0~~~~~~~~~~~~~~~~~~~5
+% $0~1~~2~~~3~~~~4~~~~~5$
+% $0~~~~~~~~~~~~~~~~~~~5$
+% \stoplines
+%
+% \starttabulate[|~|]
+% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \NR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \NR
+% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \NR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \NR
+% \stoptabulate
+%
+% \starttable[||]
+% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \AR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \AR
+% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \AR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \AR
+% \stoptable
+% \stopbuffer
+%
+% \setupbodyfont[cmr] \getbuffer
+% \setupbodyfont[lbr] \getbuffer
+
+\def\packed
+ {\nointerlineskip}
+
+\def\godown[#1]%
+ {\relax
+ \ifhmode\endgraf\fi
+ \ifvmode\nointerlineskip\vskip#1\relax\fi}
+
+%D A couple of plain macros:
+
+\ifx\thinspace\undefined
+
+ \def\thinspace {\kern .16667em }
+ \def\negthinspace{\kern-.16667em }
+ \def\enspace {\kern .5em }
+
+ \def\thinspace {\kern .16667\emwidth}
+ \def\negthinspace{\kern-.16667\emwidth}
+ \def\enspace {\kern .5\emwidth}
+
+\fi
+
+\ifx\quad\undefined
+
+ \def\enskip{\hskip.5em\relax}
+ \def\quad {\hskip 1em\relax}
+ \def\qquad {\hskip 2em\relax}
+
+ \def\enskip{\hskip.5\emwidth}
+ \def\quad {\hskip \emwidth}
+ \def\qquad {\hskip 2\emwidth}
+
+\fi
+
+\let\emspace\quad
+
+\ifx\smallskip\undefined
+
+ \def\smallskip{\vskip\smallskipamount}
+ \def\medskip {\vskip\medskipamount}
+ \def\bigskip {\vskip\bigskipamount}
+
+\fi
+
+\ifx\allowbreak\undefined
+
+ \def\break {\penalty\ifhmode-\plustenthousand\else\ejectpenalty\fi}
+ \def\nobreak {\penalty \plustenthousand}
+ \def\allowbreak{\penalty \zeropoint}
+ \def\filbreak {\par\vfil\penalty-200\vfilneg}
+ \def\goodbreak {\par\penalty-500 }
+
+\fi
+
+%D Made slightly more readable:
+
+\ifx\vglue\undefined
+
+ \def\vglue {\afterassignment\dovglue\scratchskip=}
+ \def\hglue {\afterassignment\dohglue\scratchskip=}
+ \def\topglue{\nointerlineskip\vglue-\topskip\vglue}
+
+ \def\dovglue
+ {\par
+ \scratchdimen\prevdepth
+ \hrule\!!height\zeropoint
+ \nobreak\vskip\scratchskip
+ \prevdepth\scratchdimen}
+
+ \def\dohglue
+ {\dontleavehmode % \leavevmode
+ \scratchcounter\spacefactor
+ \vrule\!!width\zeropoint
+ \nobreak\hskip\scratchskip
+ \spacefactor\scratchcounter}
+
+\fi
+
+\ifx\eject\undefined
+
+ \def\eject{\par\break}
+
+\fi
+
+\ifx\supereject\undefined
+
+ \def\supereject{\par\penalty\superpenalty}
+
+\fi
+
+\ifx\dosupereject\undefined
+
+ \def\dosupereject
+ {\ifnum\insertpenalties>\zerocount % something is being held over
+ \line{}
+ \kern-\topskip
+ \nobreak
+ \vfill\supereject
+ \fi}
+
+\fi
+
+%D We adapt plain's \type {\removelastskip} a bit:
+
+\ifx\removelastskip\undefined
+
+ \def\removelastskip
+ {\ifvmode \ifdim\lastskip=\zeropoint \else
+ \vskip-\lastskip
+ \fi \fi}
+
+\fi
+
+\ifx\smallbreak\undefined
+
+\def\smallbreak
+ {\par
+ \ifdim\lastskip<\smallskipamount
+ \removelastskip
+ \penalty-50
+ \smallskip
+ \fi}
+
+\def\medbreak
+ {\par
+ \ifdim\lastskip<\medskipamount
+ \removelastskip
+ \penalty-100
+ \medskip
+ \fi}
+
+\def\bigbreak
+ {\par
+ \ifdim\lastskip<\bigskipamount
+ \removelastskip
+ \penalty-200
+ \bigskip
+ \fi}
+
+\fi
+
+\newskip\ctxparskip \ctxparskip\zeropoint
+
+\newconditional \flexiblewhitespace \settrue\flexiblewhitespace
+
+\def\blankokleinmaat {\smallskipamount}
+\def\blankomiddelmaat {\medskipamount}
+\def\blankogrootmaat {\bigskipamount}
+\def\currentwhitespace {\zeropoint}
+
+\definecomplexorsimple\setupwhitespace
+
+\def\simplesetupwhitespace
+ {\doifnot\currentwhitespace\v!none\dosetupwhitespace}
+
+\def\complexsetupwhitespace[#1]%
+ {\edef\nextcurrentwhitespace{#1}%
+ \ifx\nextcurrentwhitespace\empty
+ \simplesetupwhitespace
+ \else
+ \let\currentwhitespace\nextcurrentwhitespace
+ \dosetupwhitespace
+ \fi}
+
+\def\dosetupwhitespace % quick test for no list
+ {\ifcsname\??ws\??ws\currentwhitespace\endcsname
+ \csname\??ws\??ws\currentwhitespace\endcsname
+ \else
+ \expandafter\processcommalist\expandafter[\currentwhitespace]\dowhitespacemethod % can be raw
+ \fi\relax
+ \ifgridsnapping
+ \setfalse\flexiblewhitespace
+ \ifdim\ctxparskip>\zeropoint
+ \ctxparskip
+ \ifcase\baselinegridmode
+ \baselineskip % normal ! ! ! ! !!
+ \or
+ \ifdim\scratchdimen=\baselineskip % maybe range
+ \baselineskip % normal ! ! ! ! !!
+ \else
+ \numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
+ \fi
+ \else
+ \baselineskip % normal ! ! ! ! !!
+ \fi
+ \fi
+ \else
+ \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
+ \fi
+ \parskip\ctxparskip}
+
+\chardef\baselinegridmode=0 % option in layout / 1=permit_half_lines
+
+\def\dodosetupwhitespace
+ {\ifgridsnapping
+ \setfalse\flexiblewhitespace
+ \ctxparskip1\ctxparskip
+ \ifdim\ctxparskip>\zeropoint
+ \ifcase\baselinegridmode
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \or
+ \ifdim\scratchdimen=\baselineskip % maybe range
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \else
+ \ctxparskip\numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
+ \fi
+ \else
+ \ctxparskip\baselineskip % normal ! ! ! ! !!
+ \fi
+ \fi
+ \else
+ \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
+ \fi
+ \parskip\ctxparskip}
+
+\definesystemvariable {ws} % whitespace
+
+\def\definewhitespacemethod[#1]#2{\setvalue{\??ws\??ws#1}{#2}}
+
+\definewhitespacemethod [\v!fix] {}
+\definewhitespacemethod [\v!fixed] {\setfalse\flexiblewhitespace}
+\definewhitespacemethod [\v!flexible] {\settrue\flexiblewhitespace}
+\definewhitespacemethod [\v!line] {\ctxparskip \baselineskip}
+\definewhitespacemethod [\v!halfline] {\ctxparskip.5\baselineskip}
+\definewhitespacemethod [\v!none] {\ctxparskip \zeropoint}
+\definewhitespacemethod [\v!big] {\ctxparskip \bigskipamount}
+\definewhitespacemethod [\v!medium] {\ctxparskip \medskipamount}
+\definewhitespacemethod [\v!small] {\ctxparskip \smallskipamount}
+
+\definewhitespacemethod [\s!default] {\simplesetupwhitespace} % {\stelwitruimteopnieuwin}
+
+% \def\dowhitespacemethod#1%
+% {\executeifdefined{\??ws\??ws#1}{\ctxparskip#1}\relax}
+
+\def\dowhitespacemethod#1%
+ {\ifcsname\??ws\??ws#1\endcsname\csname\??ws\??ws#1\endcsname\else\ctxparskip#1\fi\relax}
+
+\def\nowhitespace
+ {\ifdim\parskip>\zeropoint\relax
+ \ifdim\lastskip=-\parskip
+ \else
+ \vskip-\parskip
+ \fi
\fi}
-\def\setcharacterspacing
- {\ctxlua{spacings.enabled=true}%
- \gdef\setcharacterspacing[##1]{\dosetattribute{spacing}{\csname\??ch:##1\endcsname}}%
- \setcharacterspacing}
+\def\nowhitespaceunlessskip
+ {\ifdim\lastskip>\zeropoint \else
+ \nowhitespace
+ \fi}
+
+\def\redowhitespace
+ {\ifdim\lastskip>-\parskip \else
+ \vskip\parskip
+ \fi}
+
+\def\savecurrentwhitespace
+ {\edef\restorecurrentwhitespace
+ {\ctxparskip\the\ctxparskip
+ \parskip\the\parskip
+ \noexpand\def\noexpand\currentwhitespace{\currentwhitespace}%
+ \ifconditional\flexiblewhitespace
+ \noexpand\settrue\flexiblewhitespace
+ \else
+ \noexpand\setfalse\flexiblewhitespace
+ \fi}}
+
+% deze variant is nodig binnen \startopelkaar
+% steeds testen:
+%
+% \hoofdstuk{..}
+% \plaatslijst[..]
+% \hoofdstuk{..}
+% \input tufte
+%
+% met/zonder witruimte
+
+\def\whitespace
+ {\par
+ \ifdim\parskip>\zeropoint\relax
+ %\ifdim\lastskip>\parskip \else
+ % \removelastskip interferes with blanko blokkeer en klein
+ \vskip\parskip
+ %\fi
+ \fi}
+
+\def\nonoblanko[#1]%
+ {\par}
+
+\def\noblanko
+ {\dosingleempty\nonoblanko}
+
+% De onderstaande macro handelt ook de situatie dat er geen
+% tekst tussen \start ... \stop is geplaatst. Daartoe wordt de
+% laatste skip over de lege tekst heen gehaald. Dit komt goed
+% van pas bij het plaatsen van (mogelijk lege) lijsten.
+
+\newif\ifopelkaar
+
+\newsignal \noparskipsignal % \def\noparskipsignal {0.00001pt}
+\def\lastdoneparskip {0pt}
+
+\def\startpacked
+ {\dosingleempty\dostartpacked}
+
+\def\dostartpacked[#1]% nesting afvangen
+ {\par
+ \ifvmode
+ \edef\lastdoneparskip {\the\lastskip}%
+ \edef\lastdoneprevdepth{\the\prevdepth}% zeer recent toegevoegd
+ \ifdim\prevdepth=-\thousandpoint % toegevoegd omdat binnen
+ \else % een vbox een extra skip
+ \whitespace % ongewenst is; dit kan
+ \baselinecorrection %% zie in \placeregister[n=1]
+ \vskip\noparskipsignal % waarschijnlijk ook in
+ \fi % blanko blokkeer
+ \bgroup
+ \doifelse{#1}\v!blank
+ \opelkaarfalse
+ \opelkaartrue
+ \blank[\v!disable] % dit is nog niet ok, gaat fout
+ \setupwhitespace[\v!none] % bovenin vtop (dwz, baseline)
+ \fi}
+
+\def\stoppacked
+ {\par
+ \ifvmode
+ \egroup
+ \ifdim\lastskip=\noparskipsignal\relax
+ \removelastskip
+ \nowhitespace
+ \vskip-\lastdoneparskip
+ \vskip+\lastdoneparskip
+ \prevdepth-\lastdoneprevdepth % zeer recent toegevoegd
+ \fi
+ \fi}
+
+\def\startunpacked
+ {\blank
+ \leavevmode
+ \bgroup}
-\def\resetcharacterspacing
- {\doresetattribute{spacing}}
+\def\stopunpacked
+ {\egroup
+ \blank}
+
+% De onderstaande macro's moeten nog eens nader worden uitgewerkt.
+% Ze spelen een rol bij de spatiering rond omkaderde teksten
+% en/of boxen zonder diepte.
-\letvalue{\??ch:\s!reset}\minusone
+\def\toonregelcorrectie{\showbaselinecorrection}
+\def\regelcorrectie {\baselinecorrection}
-% \setcharacterspacing[frenchpunctuation]
-% «\type{bla}»\crlf « \type{bla}»\crlf
-% «bla »\crlf « bla»\crlf « bla »\crlf
-% bla: bla\crlf bla : bla
+% \prevdepth crosses pageboundaries!
+%
+% todo: a version that works ok inside a box
+
+\let\doaroundlinecorrection\relax
+
+\def\startlinecorrection
+ {\dodoubleempty\dostartlinecorrection}
-\definecharacterspacing [frenchpunctuation] % name may change / unit is em
+\def\dostartlinecorrection[#1][#2]% #2 gobbles spaces
+ {\bgroup
+ \processaction
+ [#1]
+ [ \v!blank=>\let\doaroundlinecorrection\blank,
+ \s!default=>\let\doaroundlinecorrection\relax,
+ \s!unknown=>{\def\doaroundlinecorrection{\blank[#1]}}]%
+ \doaroundlinecorrection
+ \startbaselinecorrection
+ \offbaselinecorrection
+ \ignorespaces}
-\setupcharacterspacing [frenchpunctuation] ["003A] [\c!left =.25,\c!alternative=1] % : % strip preceding space(char)
-\setupcharacterspacing [frenchpunctuation] ["003B] [\c!left =.25,\c!alternative=1] % ; % strip preceding space(char)
-\setupcharacterspacing [frenchpunctuation] ["003F] [\c!left =.25,\c!alternative=1] % ? % strip preceding space(char)
-\setupcharacterspacing [frenchpunctuation] ["0021] [\c!left =.25,\c!alternative=1] % ! % strip preceding space(char)
-\setupcharacterspacing [frenchpunctuation] ["00AB] [\c!right=.25,\c!alternative=1] % guillemotleft/leftguillemot % strip following space(char)
-\setupcharacterspacing [frenchpunctuation] ["00BB] [\c!left =.25,\c!alternative=1] % guillemotright/rightguillemot % strip preceding space(char)
+\def\stoplinecorrection
+ {\stopbaselinecorrection
+ \doaroundlinecorrection
+ \egroup}
+
+\def\correctwhitespace
+ {\dowithnextbox
+ {\startbaselinecorrection
+ \flushnextbox
+ \stopbaselinecorrection}%
+ \vbox}
+
+\def\verticalstrut {\normalvbox{\hsize\zeropoint\forgetall\strut}}
+\def\horizontalstrut{\normalhbox {\strut}}
+
+% Hieronder volgen enkele instellingen en macro's ten behoeve
+% van de interlinie en \strut. De waarden 2.8, 0.07, 0.72 en
+% 0.28 zijn ooit eens ontleend aan INRS-TEX en moeten wellicht
+% nog eens instelbaar worden.
+%
+% \lineheight : de hoogte van een regel
+% \spacing{getal} : instellen interlinie
+% \normalbaselines : instellen regelafstend
+%
+% \setstrut : instellen \strut
+% \setnostrut : resetten \strut, \endstrut, \begstrut
+%
+% \setteststrut : instellen zichtbare struts
+% \resetteststrut : instellen onzichtbare struts
+%
+% \setfontparameters : instellen na fontset
+%
+% De hoogte van een regel (\lineheight) is gelijk aan de
+% som van de hoogte (\ht) en diepte (\dp) van \strutbox.
+%
+% \strut : denkbeeldig blokje met hoogte en diepte
+%
+% Een \hbox kan als deze aan het begin van een regel staat
+% een breedte \hsize krijgen. Dit is soms te voorkomen met het
+% commando \leavevmode. Binnen een \vbox geeft dit echter
+% niet altijd het gewenste resultaat, vandaar het commando
+%
+% \leaveoutervmode
-% more
+% Pas op: niet zomaar \topskip en \baselineskip aanpassen
+% en zeker niet \widowpenalty. Dit kan ernstige gevolgen
+% hebben voor kolommen.
%
-% {\setcharacterkerning[extrakerning]\input davis\relax}
+% Enige glue kan op zich geen kwaad, echter als blanko=vast,
+% dan moet ook de rek 0 zijn. Binnen kolommen is rek ook
+% niet bepaald mooi. Een hele kleine waarde (0.025) voldoet,
+% omdat een positieve glue eindeloos rekbaar is.
+
+\newdimen\strutdimen
+\newdimen\lineheight
+\newdimen\openlineheight
+\newdimen\openstrutheight
+\newdimen\openstrutdepth
+\newdimen\topskipgap
+\newdimen\struttotal
+
+\def\strutheightfactor {.72}
+\def\strutdepthfactor {.28}
+
+\def\baselinefactor {2.8}
+\def\baselinegluefactor {0}
+
+\def\minimumstrutheight {0pt}
+\def\minimumstrutdepth {0pt}
+
+\def\normallineheight {\baselinefactor ex}
+\def\minimumlinedistance {\lineskip}
+
+\def\strutheight {0pt}
+\def\strutdepth {0pt}
+\def\strutwidth {0pt}
+
+\def\spacingfactor {1}
+
+\def\topskipfactor {1.0}
+\def\maxdepthfactor {0.5}
+
+\def\systemtopskipfactor {\topskipfactor}
+\def\systemmaxdepthfactor {\maxdepthfactor}
+
+% De onderstaande definitie wordt in de font-module overruled
+
+\ifdefined\globalbodyfontsize\else
+ \newdimen\globalbodyfontsize
+ \globalbodyfontsize=12pt
+\fi
-\defineattribute[kern]
+\ifx\normalizedbodyfontsize\undefined
+ \def\normalizedbodyfontsize{12pt}
+\fi
-\newcount \maxcharacterkerningid
+% door een \dimen. Dit is geen probleem omdat (1) de default
+% korpsgrootte 12pt is en (2) de fonts nog niet geladen zijn
+% en de instellingen bij het laden nogmaals plaatsvinden.
-\def\definecharacterkerning
- {\dosingleargument\dodefinecharacterkerning}
+\def\topskipcorrection
+ {\simpletopskipcorrection
+ \vskip-\struttotal
+ \verticalstrut}
-\def\dodefinecharacterkerning[#1]%
- {\ifcsname\??ck#1\endcsname \else
- \global\advance\maxcharacterkerningid\plusone
- \setxvalue{\??ck:#1}{\the\maxcharacterkerningid}%
+\def\simpletopskipcorrection
+ {\ifdim\topskip>\openstrutheight
+ % == \vskip\topskipgap
+ \vskip\topskip
+ \vskip-\openstrutheight
\fi}
-\def\setupcharacterkerning
- {\dodoubleargument\dosetupcharacterkerning}
+\def\settopskip % the extra test is needed for the lbr family
+ {\topskip\systemtopskipfactor\globalbodyfontsize
+ \ifgridsnapping \else
+ \ifr@ggedbottom\!!plus5\globalbodyfontsize\fi
+ \fi
+ \relax % the skip
+ \topskipgap\topskip
+ \advance\topskipgap -\openstrutheight\relax
+\ifdim\minimumstrutheight>\zeropoint
+ \ifdim\topskip<\minimumstrutheight
+ \topskip\minimumstrutheight\relax
+ \fi
+\else
+ \ifdim\topskip<\strutheightfactor\openlineheight
+ \topskip\strutheightfactor\openlineheight\relax
+ \fi
+\fi}
-\def\dosetupcharacterkerning[#1][#2]%
- {\ifcsname\??ck:#1\endcsname
- \begingroup
- \getparameters[\??ck][\c!factor=0,#2]%
- \ctxlua{kerns.setspacing(\getvalue{\??ck:#1},\@@ckfactor)}%
+\def\setmaxdepth
+ {\maxdepth\systemmaxdepthfactor\globalbodyfontsize}
+
+\def\normalbaselines
+ {\baselineskip \normalbaselineskip
+ \lineskip \normallineskip
+ \lineskiplimit\normallineskiplimit}
+
+\def\setnormalbaselines
+ {\ifdim\normallineheight>\zeropoint
+ \lineheight\normallineheight
+ \fi
+ \openlineheight\spacingfactor\lineheight
+ \openstrutheight \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight % new
+ \else
+ \strutheightfactor\openlineheight
+ \fi
+ \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth % new
+ \else
+ \strutdepthfactor \openlineheight
+ \fi
+ \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint
+ \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new
+ \fi
+ \normalbaselineskip\openlineheight
+ \ifgridsnapping\else
+ \!!plus \baselinegluefactor\openlineheight
+ \!!minus\baselinegluefactor\openlineheight
+ \fi
+ \normallineskip\minimumlinedistance\relax % \onepoint\relax
+ \normallineskiplimit\zeropoint\relax
+ \normalbaselines
+ \dosetupgridsnapping}
+
+\def\spacing#1%
+ {\ifgridsnapping
+ \ifdim#1\points=\onepoint\else\showmessage\m!layouts{11}{#1}\fi
+ \edef\spacingfactor{1}%
+ \else
+ \edef\spacingfactor{#1}%
+ \fi
+ %\setspacingfactor\systemtopskipfactor \topskipfactor {#1}% why no \spacingfactor ?
+ %\setspacingfactor\systemmaxdepthfactor\maxdepthfactor{#1}% why no \spacingfactor ?
+ \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}%
+ \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}%
+ \setnormalbaselines
+ \setstrut}
+
+%D Sometimes one needs to freeze the interlinespacing
+%D
+%D \starttyping
+%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf}
+%D \stoptyping
+
+\let\restoreinterlinespace\relax
+
+\def\saveinterlinespace
+ {\edef\restoreinterlinespace
+ {\lineheight \the\lineheight
+ \openstrutheight \the\openstrutheight
+ \openstrutdepth \the\openstrutdepth
+ \openlineheight \the\openlineheight
+ \normalbaselineskip \the\normalbaselineskip
+ \normallineskip \the\normallineskip
+ \normallineskiplimit\the\normallineskiplimit
+ \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
+ \noexpand\normalbaselines}}
+
+% plain definition:
+%
+% \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%
+% could be:
+%
+% \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+
+\ifx\strutbox\undefined
+
+ \newbox\strutbox
+
+ \setbox\strutbox=\normalhbox{\vrule height8.5pt depth3.5pt width\zeropoint}
+
+ %\def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+ \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
+
+\fi
+
+\let\normalstrut\strut
+
+% The double \hbox construction enables us to \backtrack
+% boxes.
+
+\unexpanded\def\setstrut
+ {% height
+ \edef\strutheight
+ {\the\dimexpr\spacingfactor\dimexpr
+ \ifdim\minimumstrutheight>\zeropoint
+ \minimumstrutheight
+ \else
+ \strutheightfactor\dimexpr\normallineheight
+ \fi}%
+ % depth
+ \edef\strutdepth
+ {\the\dimexpr
+ \ifgridsnapping
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \normallineheight-\strutheight
+ \fi
+ \else
+ \spacingfactor\dimexpr
+ \ifdim\minimumstrutdepth>\zeropoint
+ \minimumstrutdepth
+ \else
+ \strutdepthfactor\dimexpr\normallineheight
+ \fi
+ \fi}%
+ % finish
+ \dosetstrut}
+
+\unexpanded\def\setcharstrut#1%
+ {\setbox\strutbox\normalhbox{#1}%
+ \edef\strutheight{\the\strutht}%
+ \edef\strutdepth {\the\strutdp}%
+ \dosetstrut}
+
+\unexpanded\def\setfontstrut
+ {\setcharstrut{(gplQT}}
+
+\unexpanded\def\setcapstrut% could be M, but Q has descender
+ {\setcharstrut{Q}}
+
+%D Handy for math (used in mathml):
+
+\def\charhtstrut
+ {\begingroup
+ \setcharstrut{GJY}%
+ \vrule\!!width\zeropoint\!!depth\zeropoint\!!height\strutht
+ \endgroup}
+
+\def\chardpstrut
+ {\begingroup
+ \setcharstrut{gjy}%
+ \vrule\!!width\zeropoint\!!depth\strutdp\!!height\zeropoint
+ \endgroup}
+
+% because of all the callbacks in mkiv, we avoid unnecessary boxes ...
+% maybe use an attribute so that we can tag boxes that don't need a
+% treatment; tests with using an attribute so far have shown that
+% it's slower because testing the attribute takes time too
+
+\def\dosetstrut
+ {\let\strut\normalstrut
+ \ifdim\strutwidth=\zeropoint
+ \setbox\strutbox\normalhbox
+ {\vrule
+ \!!width \zeropoint
+ \!!height\strutheight
+ \!!depth \strutdepth}%
+ \else
+ \setbox\strutbox\normalhbox
+ {\normalhbox to \zeropoint
+ {% \hss % new, will be option
+ \vrule
+ \!!width \strutwidth
+ \!!height\strutheight
+ \!!depth \strutdepth
+ \hss}}%
+ \fi
+ \struttotal\dimexpr\strutht+\strutdp\relax}
+
+%D The dimen \type {\struttotal} holds the exact size of the
+%D strut; occasionally a one scaled point difference can show
+%D up with the lineheight.
+
+%D Sometimes a capstrut comes in handy
+%D
+%D \starttabulate[|Tl|l|l|]
+%D \NC yes \NC normal strut \NC {\showstruts\setupstrut[yes]\strut} \NC \NR
+%D \NC no \NC no strut \NC {\showstruts\setupstrut[no]\strut} \NC \NR
+%D \NC kap \NC a capital strut (i.e. Q) \NC {\showstruts\setupstrut[cap]\strut} \NC \NR
+%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR
+%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR
+%D \stoptabulate
+
+\def\setupstrut
+ {\dosingleempty\dosetupstrut}
+
+\def\dosetupstrut[#1]% yet undocumented, todo: fontstrut
+ {\processaction
+ [#1]
+ [ \v!yes=>\setstrut,
+ \v!auto=>\setautostrut,
+ \v!no=>\setnostrut,
+ \v!cap=>\setcapstrut,
+ \v!fit=>\setfontstrut,
+ \v!line=>\setstrut,
+ \s!default=>\setstrut,
+ \s!unknown=>\setcharstrut\commalistelement]}
+
+\def\setteststrut
+ {\def\strutwidth{.8pt}%
+ \setstrut}
+
+\def\autostrutfactor{1.1}
+
+\def\setautostrut
+ {\begingroup
+ \setbox\scratchbox\copy\strutbox
+ \setstrut
+ \ifdim\ht\strutbox>\autostrutfactor\ht\scratchbox
+ \endgroup \setstrut
+ \else\ifdim\dp\strutbox>\autostrutfactor\dp\scratchbox
+ \endgroup \setstrut
+ \else
\endgroup
+ \fi\fi}
+
+% when enabled, sigstruts will remove themselves if nothing
+% goes inbetween
+
+\newsignal\strutsignal \setfalse\sigstruts
+
+\def\begstrut
+ {\relax\ifcase\strutht\else
+ \ifconditional\sigstruts
+ \noindent\horizontalstrut
+ \normalpenalty\plustenthousand
+ \normalhskip-\strutsignal
+ \normalhskip\strutsignal
+ \else
+ \strut
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \fi
+ \expandafter \ignorespaces
+ \fi}
+
+\def\endstrut
+ {\relax\ifhmode\ifcase\strutht\else
+ \ifconditional\sigstruts
+ \ifdim\lastskip=\strutsignal
+ \unskip\unskip\unpenalty\setbox\scratchbox\lastbox
+ \else
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \strut
+ \fi
+ \else
+ \removeunwantedspaces
+ \normalpenalty\plustenthousand
+ \normalhskip\zeropoint
+ \strut
+ \fi
+ \fi\fi}
+
+\newbox\nostrutbox \setbox\nostrutbox\normalhbox{} % {\normalhbox{}}
+
+\def\setnostrut
+ {\setbox\strutbox\copy\nostrutbox
+ \let\strut\empty
+ \let\endstrut\empty
+ \let\begstrut\empty
+ \let\crlfplaceholder\empty}
+
+% unsave:
+%
+% \def\pseudostrut
+% {\bgroup
+% \setnostrut
+% \normalstrut
+% \egroup}
+%
+% try:
+%
+% \startchemie
+% \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C]
+% \stopchemie
+%
+% so:
+
+\def\pseudostrut
+ {\noindent} % better: \dontleavehmode
+
+\let\pseudobegstrut\pseudostrut
+
+\let\pseudoendstrut\removeunwantedspaces
+
+\def\resetteststrut
+ {\let\strutwidth\zeropoint
+ \setstrut}
+
+\ifx\setfontparameters\undefined
+ % problems ! ! ! !
+ \def\setfontparameters{\the\everybodyfont}
+\fi
+
+%D Handy:
+
+\def\baselinedistance{\the\lineheight}
+
+%D We need \type{\normaloffinterlineskip} because the new
+%D definition contains an assignment, and |<|don't ask me
+%D why|>| this assignment gives troubles in for instance the
+%D visual debugger.
+
+%D The plain ones:
+
+\def\offinterlineskip
+ {\baselineskip-\thousandpoint
+ \lineskip\zeropoint
+ \lineskiplimit\maxdimen}
+
+\def\nointerlineskip
+ {\prevdepth-\thousandpoint}
+
+\let\normaloffinterlineskip=\offinterlineskip % knuth's original
+
+%D My own one:
+
+\def\offinterlineskip
+ {\ifdim\baselineskip>\zeropoint
+ \edef\oninterlineskip
+ {\baselineskip\the\baselineskip
+ \lineskip\the\lineskip
+ \lineskiplimit\the\lineskiplimit
+ \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}%
+ \else
+ \let\oninterlineskip\setnormalbaselines
+ \fi
+ \normaloffinterlineskip}
+
+\let\oninterlineskip=\relax
+
+\def\leaveoutervmode
+ {\ifvmode\ifinner\else
+ \leavevmode
+ \fi\fi}
+
+% We stellen enkele penalties anders in dan Plain TEX:
+
+% oud
+%
+% \widowpenalty=\defaultwidowpenalty\relax
+% \clubpenalty =\defaultclubpenalty \relax
+
+\def\resetpenalties#1%
+ {\ifx#1\undefined\else
+ #1\minusone
\fi}
-\def\setcharacterkerning
- {\ctxlua{kerns.enabled=true}%
- \gdef\setcharacterkerning[##1]{\dosetattribute{kern}{\csname\??ck:##1\endcsname}}%
- \setcharacterkerning}
+\def\setpenalties#1#2#3%
+ {\ifx#1\undefined\else % space before #3 prevents lookahead problems, needed when #3=text
+ #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax
+ \fi}
+
+\def\doexpandedrecurse#1#2%
+ {\ifnum#1>\zerocount#2\@EA\doexpandedrecurse\@EA{\the\numexpr#1-1\relax}{#2}\fi}
+
+%D \macros
+%D {keeplinestogether}
+%D
+%D Dirty hack, needed in margin content that can run of a page.
+
+\def\keeplinestogether#1%
+ {\xdef\restoreinterlinepenalty{\global\resetpenalties\interlinepenalties}%
+ \global\setpenalties\interlinepenalties{#1}\plustenthousand}
+
+\newif\ifgridsnapping % to be sure
+
+\def\defaultwidowpenalty {2000} % was: 1000
+\def\defaultclubpenalty {2000} % was: 800
+\def\defaultdisplaywidowpenalty {50}
+\def\defaultbrokenpenalty {100}
+
+\def\defaultgridwidowpenalty {0}
+\def\defaultgridclubpenalty {0}
+\def\defaultgriddisplaywidowpenalty {0}
+\def\defaultgridbrokenpenalty {0}
+
+\def\nopenalties
+ {\widowpenalty \zerocount
+ \clubpenalty \zerocount
+ \brokenpenalty \zerocount
+ \doublehyphendemerits\zerocount
+ \finalhyphendemerits \zerocount
+ \adjdemerits \zerocount}
+
+\def\setdefaultpenalties
+ {\directsetup{\systemsetupsprefix\s!default}}
+
+\startsetups [\systemsetupsprefix\s!reset]
+ \resetpenalties\widowpenalties
+ \resetpenalties\clubpenalties
+ \resetpenalties\interlinepenalties
+\stopsetups
+
+% we use \directsetup because it's faster and we know there is no csl
+
+\startsetups [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultwidowpenalty
+ \clubpenalty \defaultclubpenalty
+ \displaywidowpenalty\defaultdisplaywidowpenalty
+ \brokenpenalty \defaultbrokenpenalty
+
+\stopsetups
+
+\startsetups [\v!grid] [\systemsetupsprefix\s!default]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \widowpenalty \defaultgridwidowpenalty
+ \clubpenalty \defaultgridclubpenalty
+ \displaywidowpenalty\defaultgriddisplaywidowpenalty
+ \brokenpenalty \defaultgridbrokenpenalty
+
+\stopsetups
+
+% as an illustration:
+
+\startsetups [\systemsetupsprefix\v!strict]
+
+ \directsetup{\systemsetupsprefix\s!reset}
+
+ \setpenalties\widowpenalties2\maxdimen
+ \setpenalties\clubpenalties 2\maxdimen
+ \brokenpenalty \maxdimen
-\letvalue{\??ck:\s!reset}\minusone
+\stopsetups
-\definecharacterkerning[extrakerning]
+\setdefaultpenalties % will happen later in \setuplayout
-\setupcharacterkerning[extrakerning][\c!factor=.125]
+% Suggested by GB (not the name -):
-% sorry, here:
+\def\rapfillskip{.5\hsize plus .092\hsize minus .5\hsize} % D.A.'s value
-% test \WORD{test TEST \TeX} test
-% test \word{test TEST \TeX} test
-% test \Word{test TEST \TeX} test
+% Bovendien definieren we enkele extra \fill's:
-\defineattribute[case]
+\def\hfilll{\hskip\zeropoint\!!plus1filll\relax}
+\def\vfilll{\vskip\zeropoint\!!plus1filll\relax}
-\def\setcharactercasing
- {\ctxlua{cases.enabled=true}%
- \gdef\setcharactercasing[##1]{\dosetattribute{case}{\number##1}}%
- \setcharactercasing}
+% De onderstaande hulpmacro's moeten nog eens instelbaar worden
+% gemaakt.
-\def\WORD {\groupedcommand{\setcharactercasing[\plusone ]}{}}
-\def\word {\groupedcommand{\setcharactercasing[\plustwo ]}{}}
-\def\Word {\groupedcommand{\setcharactercasing[\plusthree]}{}}
-\def\Words{\groupedcommand{\setcharactercasing[\plusfour]}{}}
+\def\tfskipsize{1em\relax}
+\def\tfkernsize{1ex\relax}
-\let\WORDS\WORD
-\let\words\word
+\def\tfskip{\dotfskip\tfskipsize}
+\def\tfkern{\dotfkern\tfkernsize}
-% \definestartstop is not yet in available at core-spa time
+\def\dotfskip#1{{\tf\hskip#1}}
+\def\dotfkern#1{{\tf\kern #1}}
+
+% needs a proper \definenarrower or installnarrower
+
+\newskip\ctxleftskip
+\newskip\ctxrightskip
+\newskip\ctxmidskip
+
+\def\dosinglenarrower#1%
+ {\processaction
+ [#1]
+ [ \v!left=>\global\advance\ctxleftskip \@@slleft,
+ \v!middle=>\global\advance\ctxmidskip \@@slmiddle,
+ \v!right=>\global\advance\ctxrightskip \@@slright,
+ \v!reset=>\global\ctxleftskip \zeropoint
+ \global\ctxmidskip \zeropoint
+ \global\ctxrightskip\zeropoint,
+ \v!none=>,
+ \s!unknown=>\global\advance\ctxmidskip \commalistelement]}
+
+\def\donarrower[#1]% hm, can be dorepeat directly
+ {\dorepeatwithcommand[#1]\dosinglenarrower}
+
+\def\complexstartnarrower[#1]%
+ {\@@slbefore % was hard coded \par
+ \bgroup
+ \global\ctxleftskip \zeropoint
+ \global\ctxrightskip\zeropoint
+ \global\ctxmidskip \zeropoint
+ \processcommalistwithparameters[#1]\donarrower
+ \advance\leftskip \ctxleftskip
+ \advance\rightskip \ctxrightskip
+ \advance\leftskip \ctxmidskip
+ \advance\rightskip \ctxmidskip
+ \seteffectivehsize}
+
+% todo: definenarrower
+
+\def\simplestartnarrower
+ {\startnarrower[\v!middle]}
+
+\definecomplexorsimple\startnarrower
+
+\def\stopnarrower
+ {\@@slafter % was hard coded \par / needed, else skips forgotten
+ \egroup}
+
+\def\setupnarrower
+ {\dodoubleargument\getparameters[\??sl]}
+
+\newdimen\@@effectivehsize \def\effectivehsize {\hsize}
+\newdimen\@@effectiveleftskip \def\effectiveleftskip {\leftskip}
+\newdimen\@@effectiverightskip \def\effectiverightskip{\rightskip}
+
+\def\seteffectivehsize
+ {\setlocalhsize
+ \@@effectivehsize \localhsize
+ \@@effectiveleftskip \leftskip
+ \@@effectiverightskip \rightskip
+ \let\effectivehsize \@@effectivehsize
+ \let\effectiveleftskip \@@effectiveleftskip
+ \let\effectiverightskip\@@effectiverightskip}
+
+\unexpanded\def\lefttoright{\textdir TLT\pardir TLT\relax}
+\unexpanded\def\righttoleft{\textdir TRT\pardir TRT\relax}
+
+\def\dodefinehbox[#1][#2]%
+ {\setvalue{hbox#1}##1%
+ {\hbox to #2{\begstrut##1\endstrut\hss}}}
+
+\def\definehbox
+ {\dodoubleargument\dodefinehbox}
+
+\def\iobox#1#2#3#% here #3# is not really needed
+ {\vbox\bgroup % we want to return a vbox like the others
+ \hbox\bgroup% we need to pack the signal with the box
+ \signalrightpage
+ \dowithnextboxcontent
+ {\let\\=\endgraf\forgetall\doifrightpageelse#1#2}
+ {\box\nextbox\egroup\egroup}
+ \vbox#3}
+
+\def\obox{\iobox\raggedleft \raggedright} % outerbox
+\def\ibox{\iobox\raggedright\raggedleft} % innerbox
+
+\def\dosetraggedvbox#1%
+ {\let\raggedbox\vbox
+ \processfirstactioninset
+ [#1]
+ [ \v!left=>\let\raggedbox\lbox,
+ \v!right=>\let\raggedbox\rbox,
+ \v!middle=>\let\raggedbox\cbox,
+ \v!inner=>\let\raggedbox\ibox,
+ \v!outer=>\let\raggedbox\obox,
+ \v!flushleft=>\let\raggedbox\rbox,
+ \v!flushright=>\let\raggedbox\lbox,
+ \v!center=>\let\raggedbox\cbox,
+ \v!no=>\def\raggedbox{\vbox\bgroup\raggedright\let\next=}]}
+
+\def\dosetraggedhbox#1%
+ {\let\raggedbox\hbox
+ \processaction % slow
+ [#1]
+ [ \v!left=>\def\raggedbox{\doalignedline\v!left },
+ \v!right=>\def\raggedbox{\doalignedline\v!right },
+ \v!middle=>\def\raggedbox{\doalignedline\v!middle},
+ \v!inner=>\def\raggedbox{\doalignedline\v!inner },
+ \v!outer=>\def\raggedbox{\doalignedline\v!outer },
+ \v!flushleft=>\def\raggedbox{\doalignedline\v!right },
+ \v!flushright=>\def\raggedbox{\doalignedline\v!left },
+ \v!center=>\def\raggedbox{\doalignedline\v!middle}]}
+
+\def\dosetraggedcommand#1%
+ {\expanded{\dodosetraggedcommand{#1}}}
+
+\newtoks\everyraggedcommand
+
+\def\raggedcommand{\the\everyraggedcommand}
+
+\def\dodosetraggedcommand#1% beware: #1=empty is ignored, keep that!
+ {\everyraggedcommand \emptytoks
+ \let\raggedtopcommand \empty
+ \let\raggedbottomcommand\empty
+ \chardef\raggedoneliner\zerocount
+ \doifsomething{#1}
+ {\doifinsetelse\v!broad{#1}\!!doneatrue\!!doneafalse
+ \doifinsetelse\v!wide {#1}\!!donebtrue\!!donebfalse
+ \!!donectrue
+ \rawprocesscommalist[#1]\dododosetraggedcommand}}
+
+\def\dododosetraggedcommand#1%
+ {\executeifdefined{\@@ragged@@command\string#1}\relax}
+
+\def\@@ragged@@command{@@raggedcommand}
+
+\setvalue{\@@ragged@@command\v!hanging }{\appendtoks\enableprotruding \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nothanging }{\appendtoks\disableprotruding \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!hz }{\appendtoks\enableadjusting \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nohz }{\appendtoks\disableadjusting \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!spacing }{\appendtoks\enablespacehandling
+ \enablekernhandling \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nospacing }{\appendtoks\disablespacehandling
+ \disablekernhandling \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!hyphenated }{\appendtoks\dohyphens \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!nothyphenated}{\appendtoks\nohyphens \to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!tolerant }{\appendtoks\tolerance3000\relax \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!verytolerant}{\appendtoks\tolerance4500\relax \to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!stretch }{\appendtoks\emergencystretch\bodyfontsize\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!left}%
+ {\if!!donea \appendtoks\veryraggedleft\to\everyraggedcommand
+ \else \appendtoks\raggedleft \to\everyraggedcommand
+ \fi
+ \!!donecfalse}
+
+\setvalue{\@@ragged@@command\v!right}%
+ {\if!!donea \appendtoks\veryraggedright\to\everyraggedcommand
+ \else \appendtoks\raggedright \to\everyraggedcommand
+ \fi
+ \!!donecfalse}
+
+\setvalue{\@@ragged@@command\v!middle}%
+ {\if!!donec
+ \if!!doneb \appendtoks\raggedwidecenter\to\everyraggedcommand
+ \else\if!!donea \appendtoks\veryraggedcenter\to\everyraggedcommand
+ \else \appendtoks\raggedcenter \to\everyraggedcommand
+ \fi\fi
+ \!!donecfalse
+ \else
+ \let\raggedbottomcommand\vfilll % bonus, pretty strong
+ \let\raggedtopcommand \vfilll % used with \framed for
+ \fi} % instance in tables
+
+\setvalue{\@@ragged@@command\v!flushleft }{\getvalue{\@@ragged@@command\v!right }}
+\setvalue{\@@ragged@@command\v!flushright}{\getvalue{\@@ragged@@command\v!left }}
+\setvalue{\@@ragged@@command\v!center }{\getvalue{\@@ragged@@command\v!middle}}
+
+\setvalue{\@@ragged@@command\v!high}%
+ {\let\raggedbottomcommand\vfilll} % and since we lack a
+
+\setvalue{\@@ragged@@command\v!low}%
+ {\let\raggedtopcommand\vfilll} % proper keyword, but
+
+\setvalue{\@@ragged@@command\v!lohi}%
+ {\let\raggedbottomcommand\vfilll % we do support the
+ \let\raggedtopcommand\vfilll} % ugly laho (lohi)
+
+\setvalue{\@@ragged@@command\v!no}%
+ {\appendtoks\raggedright\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!yes}%
+ {\appendtoks\notragged\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!normal}%
+ {\appendtoks\notragged\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!inner}% not yet perfect
+ {\signalrightpage % may interfere
+ \doifrightpageelse
+ {\getvalue{\@@ragged@@command\v!right}}
+ {\getvalue{\@@ragged@@command\v!left}}}
+
+\setvalue{\@@ragged@@command\v!outer}% not yet perfect
+ {\signalrightpage % may interfere
+ \doifrightpageelse
+ {\getvalue{\@@ragged@@command\v!left}}
+ {\getvalue{\@@ragged@@command\v!right}}}
+
+\setvalue{\@@ragged@@command\v!lesshyphenation}%
+ {\appendtoks\lesshyphens\to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!morehyphenation}%
+ {\appendtoks\morehyphens\to\everyraggedcommand}
+
+\setvalue{\@@ragged@@command\v!lefttoright}{\appendtoks\lefttoright\to\everyraggedcommand}
+\setvalue{\@@ragged@@command\v!righttoleft}{\appendtoks\righttoleft\to\everyraggedcommand}
+\setvalue{\@@ragged@@command l2r}{\appendtoks\lefttoright\to\everyraggedcommand}
+\setvalue{\@@ragged@@command r2l}{\appendtoks\righttoleft\to\everyraggedcommand}
+
+% compare:
+%
+% \framed[width=4cm,align=no] {\hfil xxx}
+% \framed[width=4cm,align=disable]{\hfil xxx}
+
+\setvalue{\@@ragged@@command\v!disable}% for one liners
+ {\appendtoks\raggedright\parfillskip\zeropoint\to\everyraggedcommand}
+
+\chardef\raggedoneliner\zerocount
+
+\setvalue{\@@ragged@@command\v!line}%
+ {\chardef\raggedoneliner\plusone}
+
+% Nog doen:
+%
+% \goodbreak -> \allowbreak en \dosomebreak{..} in koppen
+%
+% bij koppen zowieso: \blanko[reset]
+
+% Nog in commando verwerken:
%
-% \startrandomized \input tufte \stoprandomized
+% \voorkeur la \blanko
%
-% \definestartstop[randomized][\c!before=\dosetattribute{case}{8},\c!after=]
+% Om ongewenste witruimte te voorkomen kan met \dosomebreak{\break}
+% een \penalty voor witruimte worden geplaatst.
-\def\randomizetext{\groupedcommand{\dosetattribute{case}{8}}{}}
+\def\removelastskip % a redefinition of plain
+ {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi}
-% compound stuff (under construction)
+\def\doifoutervmode#1%
+ {\ifvmode\ifinner\else#1\fi\fi}
-\defineattribute[breakpoint]
+\ifx\dosomebreak\undefined % defined in mkiv
-\newbox\breakpointbox
+ \def\dosomebreak#1%
+ {\doifoutervmode
+ {\scratchskip\lastskip
+ \removelastskip
+ %\leavevmode\type{#1}%
+ #1\relax
+ \ifdim\scratchskip=\zeropoint % else interference with footnotes
+ \else
+ \vskip\scratchskip
+ \fi}}
-\definesystemvariable {bp} % BreakPoint
+\fi
-\exhyphenchar=\minusone % we use a different order then base tex, so we really need this
+\def\forgeteverypar
+ {\everypar{\the\neverypar}}
-\newcount \maxbreakpointsid
+\def\forgetparindent
+ {\forgeteverypar
+ \indentfirstparagraphtrue % recently added
+ \let\currentindentation\v!none
+ \ctxparindent\zeropoint
+ \parindent\zeropoint\relax}
-\def\definebreakpoints
- {\dosingleargument\dodefinebreakpoints}
+\def\forgetparskip
+ {\let\currentwhitespace\v!none
+ \ctxparskip\zeropoint
+ \parskip\zeropoint\relax}
-\def\dodefinebreakpoints[#1]%
- {\ifcsname\??bp:#1\endcsname \else
- \global\advance\maxbreakpointsid\plusone
- \setxvalue{\??bp:#1}{\the\maxbreakpointsid}%
+\def\forgetbothskips
+ {\tolerance1500
+ \leftskip\zeropoint
+ \rightskip\zeropoint\relax}
+
+\def\forgetspacing
+ {\emergencystretch\zeropoint}
+
+\newif\ifforgotten % rather good signal for inner
+
+\appendtoks \forgottentrue \to \everyforgetall
+\appendtoks \forgetragged \to \everyforgetall
+\appendtoks \forgetparskip \to \everyforgetall
+\appendtoks \forgetparindent \to \everyforgetall
+\appendtoks \forgetbothskips \to \everyforgetall
+\appendtoks \forgetspacing \to \everyforgetall % i.v.m. funny spacing in pagebody
+\appendtoks \spacing\!!plusone \to \everyforgetall % new per 10/08/2004, else problems in otr / !! needed
+\appendtoks \everypar\emptytoks \to \everyforgetall % indeed!
+
+\def\localvbox#1#%
+ {\vbox#1\bgroup
+ \forgetparskip
+ \setlocalhsize
+ \hsize\localhsize
+ \forgetparindent
+ \forgetbothskips
+ \forgeteverypar
+ \let\next=}
+
+\let\dostopattributes\relax % in case these commands end up in an edef
+
+% \unexpanded\def\dostartattributes#1#2#3%
+% {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+% \ifcsname#1#3\endcsname
+% \let\dostopattributes\@@dostopattributes
+% \startcolor[\csname#1#3\endcsname]%
+% \else
+% \let\dostopattributes\@@nostopattributes
+% \fi
+% \ifcsname#1#2\endcsname
+% \expandafter\doconvertfont
+% \else
+% \expandafter\gobbleoneargument
+% \fi{\csname#1#2\endcsname}}
+
+\newconditional \parbasedattributes
+
+\def\finishparbasedattributes
+ {\ifconditional\parbasedattributes
+ \setfalse\parbasedattributes
+ \par
\fi}
-\def\installbreakpoint
- {\dotripleempty\doinstallbreakpoint}
+\def\dostopparbasedattributes
+ {\settrue\parbasedattributes
+ \dostopattributes}
-% hm, we cannot prebuild lists, font dependent
+\unexpanded\def\@@dostopattributes
+ {\stopcolor
+ \finishparbasedattributes
+ \endgroup}
-\def\doinstallbreakpoint[#1][#2][#3]%
- {\ifcsname\??bp:#1\endcsname
- \begingroup
- \getparameters[\??bp][\c!type=1,\c!nleft=3,\c!nright=3,#3]%
- \ctxlua{breakpoints.setreplacement(\csname\??bp:#1\endcsname,#2,\@@bptype,\@@bpnleft,\@@bpnright)}%
- \endgroup
+\unexpanded\def\@@nostopattributes
+ {\finishparbasedattributes
+ \endgroup}
+
+\unexpanded\def\doattributes#1#2#3#4%
+ {\dostartattributes{#1}{#2}{#3}{#4}\dostopattributes}
+
+% An even faster \ETEX\ version:
+
+\unexpanded\def\dostartattributes#1#2#3%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \ifincolor
+ \ifcsname#1#3\endcsname
+ \let\dostopattributes\@@dostopattributes
+ \faststartcolor[\csname#1#3\endcsname]%
+ \else
+ \let\dostopattributes\@@nostopattributes
+ \fi
+ \else
+ \let\dostopattributes\@@nostopattributes
+ \fi
+ \ifcsname#1#2\endcsname
+ % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi}
+
+\unexpanded\def\@@dostopattributes
+ {\faststopcolor
+ \finishparbasedattributes
+ \endgroup}
+
+\unexpanded\def\@@nostopattributes
+ {\finishparbasedattributes
+ \endgroup}
+
+%D Bonus macro, see core-sec.tex
+
+\unexpanded\def\dosetfontattribute#1#2%
+ {\ifcsname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi\empty}
+
+%D Since this happens a lot, and sometimes large arguments
+%D are passed in \type {#4}, we just copy some code:
+
+\unexpanded\def\doattributes#1#2#3#4%
+ {\begingroup % geen \bgroup, anders in mathmode lege \hbox
+ \ifincolor
+ \ifcsname#1#3\endcsname
+ \let\dostopattributes\@@dostopattributes
+ \faststartcolor[\csname#1#3\endcsname]%
+ \else
+ \let\dostopattributes\endgroup
+ \fi
+ \else
+ \let\dostopattributes\endgroup
+ \fi
+ \ifcsname#1#2\endcsname
+ % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
+ \@EA\doconvertfont\csname#1#2\@EA\endcsname
+ \fi
+ {#4}%
+ \dostopattributes}
+
+% Kan vaker worden toegepast en moet bovendien sneller!
+
+\newskip\leftskipadaption
+\newskip\rightskipadaption
+
+\def\doadaptleftskip#1%
+ {\dosetleftskipadaption{#1}%
+ \advance\leftskip \leftskipadaption}
+
+\def\doadaptrightskip#1%
+ {\dosetrightskipadaption{#1}%
+ \advance\rightskip \rightskipadaption}
+
+\setvalue{@lsa@\v!standard}{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
+\setvalue{@lsa@\v!yes }{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
+\letvalue{@lsa@\v!no }\zeropoint
+\letvalue{@lsa@\empty }\zeropoint
+\setvalue{@rsa@\v!standard}{\@@slright}
+\setvalue{@rsa@\v!yes }{\@@slright}
+\letvalue{@rsa@\v!no }\zeropoint
+\letvalue{@rsa@\empty }\zeropoint
+
+\def\dosetleftskipadaption#1%
+ {\edefconvertedargument\ascii{@lsa@#1}%
+ \leftskipadaption
+ \ifcsname\ascii\endcsname
+ \csname\ascii\endcsname
+ \else
+ #1%
+ \fi
+ \relax}
+
+\def\dosetrightskipadaption#1%
+ {\edefconvertedargument\ascii{@rsa@#1}%
+ \rightskipadaption
+ \ifcsname\ascii\endcsname
+ \csname\ascii\endcsname
+ \else
+ #1%
+ \fi
+ \relax}
+
+\newcount \noftrackedpagestates
+\newif \ifpagestatemismatch
+\newcount \realpagestateno
+\chardef \frozenpagestate \zerocount
+
+\def\dotrackpagestate#1#2%
+ {\ifdoublesided \ifinpagebody \else
+ \doforcedtrackpagestate{#1}{#2}%
+ \fi \fi}
+
+\def\doforcedtrackpagestate#1#2%
+ {\ifcase\frozenpagestate
+ \global\advance\noftrackedpagestates\plusone
+ \global\advance#2\plusone
+ \lazysavetaggedtwopassdata{#1}{\number\noftrackedpagestates}{\number#2}{\noexpand\realfolio}%
+ %\llap{\infofont\number\noftrackedpagestates/\number#2}% tracing
+ \fi}
+
+\def\doifrightpagestateelse#1#2%
+ {\ifcase\frozenpagestate
+ \pagestatemismatchfalse
+ \realpagestateno\realfolio
+ \ifinpagebody
+ \ifdoublesided
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \twopassdatafoundtrue
+ \fi
+ \else\ifdoublesided
+ \findtwopassdata{#1}{\number#2}%
+ \iftwopassdatafound
+ \realpagestateno\twopassdata\relax
+ \ifnum\twopassdata=\realpageno \else
+ \pagestatemismatchtrue
+ \fi
+ \ifodd\twopassdata\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \else
+ \twopassdatafoundtrue
+ \fi\fi
+ \else
+ \ifodd\realpagestateno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \iftwopassdatafound
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\doifforcedrightpagestateelse#1#2%
+ {\ifcase\frozenpagestate
+ \pagestatemismatchfalse
+ \realpagestateno\realfolio
+ \findtwopassdata{#1}{\number#2}%
+ \iftwopassdatafound
+ \realpagestateno\twopassdata\relax
+ \ifnum\twopassdata=\realpageno \else
+ \pagestatemismatchtrue
+ \fi
+ \ifodd\twopassdata\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \else
+ \ifodd\realpageno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \else
+ \ifodd\realpagestateno\relax
+ \twopassdatafoundtrue \else \twopassdatafoundfalse
+ \fi
+ \fi
+ \iftwopassdatafound
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\freezepagestate {\chardef\frozenpagestate\plusone }
+\def\defrostpagestate{\chardef\frozenpagestate\zerocount}
+
+% we can make more of these on top, but how to deal with mixed frozen states
+
+\definetwopasslist\s!paragraph \newcount \nofraggedparagraphs
+
+\def\signalrightpage {\dotrackpagestate \s!paragraph\nofraggedparagraphs}
+\def\doifrightpageelse{\doifrightpagestateelse\s!paragraph\nofraggedparagraphs}
+
+\newcount\pagesignallevel
+
+\def\startsignalrightpage % one may do a \postsignalrightplace
+ {\advance\pagesignallevel\plusone
+ \presignalrightpage
+ \let\signalrightpage\relax
+ \let\presignalrightpage\relax
+ \let\startsignalrightpage\relax
+ \doifrightpageelse\donothing\donothing
+ \freezepagestate}
+
+\def\stopsignalrightpage
+ {\ifcase\pagesignallevel\or\postsignalrightpage\fi
+ \advance\pagesignallevel\minusone}
+
+\def\setraggedparagraphmode
+ {\signalrightpage\doifrightpageelse} % move it there
+
+\ifx\swapmargins\undefined \let\swapmargins\undefined \fi % todo
+
+\def\doifswappedrightpageelse#1#2% alleen in box construction !
+ {\doifrightpageelse
+ {#1}
+ {\scratchcounter\realpageno
+ \realpageno\realpagestateno\relax
+ \swapmargins
+ \realpageno\scratchcounter
+ #2}}
+
+\newbox\signaledrightpage % this way we can avoid interference, i.e. postpone placement
+
+\def\presignalrightpage {\global\setbox\signaledrightpage\hbox{\signalrightpage}}
+\def\postsignalrightpage{\ifvoid\signaledrightpage\else\box\signaledrightpage\fi}
+
+% The next feature is is used in:
+%
+% \definenumber[test][way=bypage]
+%
+% \def\Test
+% {\incrementnumber[test]\rawnumber[test]/%
+% \incrementnumber[test]\rawnumber[test]/%
+% \incrementnumber[test]\rawnumber[test]\space
+% \checkpagechange{oeps}\changedpage{oeps}\space
+% \ifpagechanged TRUE\else FALSE\fi}
+%
+% \Test\page \Test\par \Test\page \Test\par \Test\page \Test\page
+%
+% (adapted from cont-new.tex:)
+
+\newif\ifpagechanged \let\lastchangedpage\empty
+
+\def\docheckpagestatechange#1#2#3%
+ {\pagechangedfalse
+ \doforcedtrackpagestate{#2}{#3}%
+ \findtwopassdata{#2}{\number#3}%
+ \iftwopassdatafound
+ \ifnum\twopassdata>0\getvalue{#2:p:#1}\relax
+ \pagechangedtrue
+ \fi
+ \fi
+ \ifpagechanged
+ \letgvalue{#2:p:#1}\twopassdata
+ \globallet\lastchangedpage\twopassdata
+ \else
+ \globallet\lastchangedpage\realfolio
\fi}
-\def\setbreakpoints
- {\ctxlua{breakpoints.enabled=true}%
- \gdef\setbreakpoints[##1]{\dosetattribute{breakpoint}{\csname\??bp:##1\endcsname}}%
- \setbreakpoints}
+\def\changedpagestate#1#2%
+ {\executeifdefined{#2:p:#1}{0}}
+
+\def\checkpagechange#1{\docheckpagestatechange{#1}\s!paragraph\nofraggedparagraphs}
+\def\changedpage #1{\changedpagestate{#1}\s!paragraph}
+
+% saved struts
+
+\ifx\savedstrutbox\undefined \newbox\savedstrutbox \fi
+
+\def\savestrut {\setbox\savedstrutbox\copy\strutbox}
+\def\savedstrut{\copy \savedstrutbox}
+
+\chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
+
+\def\bottomalignlimit{3\lineheight}
+
+\newif\ifn@rmalbottom
+\newif\ifr@ggedbottom
+\newif\ifb@selinebottom
+
+\def\normalbottom
+ {% \topskip 10pt
+ \r@ggedbottomfalse}
+
+\def\raggedbottom
+ {\chardef\bottomraggedness\zerocount
+ \n@rmalbottomfalse
+ \r@ggedbottomtrue
+ \b@selinebottomfalse
+ \settopskip}
+
+\def\alignbottom
+ {\chardef\bottomraggedness\plusone
+ \n@rmalbottomtrue
+ \r@ggedbottomfalse
+ \b@selinebottomfalse
+ \settopskip}
+
+\def\baselinebottom
+ {\chardef\bottomraggedness\plustwo
+ \n@rmalbottomfalse
+ \r@ggedbottomfalse
+ \b@selinebottomtrue
+ \settopskip}
+
+\let\normalbottom=\alignbottom % downward compatible
+
+% new code, not in use yet
+
+% for future chinese typo-module:
+%
+% % \let\raggedleft\veryraggedleft
+% % \let\raggedleft\veryraggedright
+%
+% \startbuffer
+% 中中中中中中中中中中中中中中中中中中中中中中中中中%
+% 中中中中中中中中中中中中中中中中中中中中中中中中中%
+% 中中中中中中中中中中中中中中中中中中中中中中中中中%
+% 中中中中中中中中中中中中中中中中中中中中中中中中中%
+% \stopbuffer
+%
+% \framedtext
+% [align={broad,flushright},width=90mm]
+% {\getbuffer}
+%
+% \framedtext
+% [align={broad,flushleft},width=90mm]
+% {\getbuffer}
+%
+% \framedtext
+% [align=middle,width=90mm]
+% {\getbuffer}
+%
+% using just flushleft is not okay here due to the fact that
+% leftskip has less stretch than the inter character spacing
+
+% category:
+%
+% 0 == discard
+% 1 == only if larger
+% 2 == force even if smaller
+% 3 == only take penalty component
+% 4 == add to existing skip
+% 5 == ignore following skips (== disable)
+
+% penalty:
+%
+% larger wins
+
+% order:
+%
+% larger wins
-\letvalue{\??bp:\s!reset}\minusone
+\registerctxluafile{core-spa}{1.001}
+
+\definesystemattribute[kern-chars]
+\definesystemattribute[skip-category]
+\definesystemattribute[skip-penalty]
+\definesystemattribute[skip-order]
+\definesystemattribute[snap-category]
+\definesystemattribute[display-math]
-\definebreakpoints[compound]
+% \start \dosetstretch{.25em} \setuptolerance[tolerant,stretch] \input tufte \endgraf \stop
+% \start \dosetstretch{.5em} effe flink doorfietsen \stop
-\installbreakpoint [compound] [\number`+] [\c!left=3,\c!right=3,\c!type=1]
-\installbreakpoint [compound] [\number`-] [\c!left=3,\c!right=3,\c!type=1]
-\installbreakpoint [compound] [\number`/] [\c!left=3,\c!right=3,\c!type=1]
-\installbreakpoint [compound] [\number`(] [\c!left=3,\c!right=3,\c!type=2]
-\installbreakpoint [compound] [\number`)] [\c!left=3,\c!right=3,\c!type=3]
+\def\dosetupgridsnapping % calls too often, only needed in gridsnapping
+ {\ctxlua{nodes.setsnapvalue(1,\number\openstrutheight,\number\openstrutdepth)}}
-% \setbreakpoints[compound]
+\def\doenablegridsnapping
+ {\dosetattribute{snap-category}{1}%
+ \topskip\strutht
+ \offinterlineskip}
+
+\def\dodisablegridsnapping
+ {\doresetattribute{snap-category}%
+ % reset topskip
+ \oninterlineskip}
% experimental code, not yet interfaced:
@@ -355,7 +2860,7 @@
\def\dodefinevspacing[#1][#2]%
{\ctxlua{vspacing.setmap("#1","#2")}}
-\def\vspacing
+\unexpanded\def\vspacing
{\dosingleempty\dovspacing}
\def\dovspacing[#1]%
@@ -395,30 +2900,1209 @@
\setfalse\vspacingenabled
-% \def\dosomebreak#1%
-% {\doifoutervmode
-% {\scratchskip\lastskip
-% \removelastskip
-% #1\relax
-% \ifconditional\vspacingenabled
-% % we have collapsed so always 0pt
-% \vskip\scratchskip
-% \else\ifdim\scratchskip=\zeropoint
-% % else interference with footnotes
-% \else
-% \vskip\scratchskip
-% \fi\fi}}
-
% ! ! ! ! ! later, now each newline does a \par and call to the callback
-\def\enablevspacing {\settrue \vspacingenabled\ctxlua{vspacing.enable()}}
-\def\disablevspacing{\setfalse\vspacingenabled\ctxlua{vspacing.disable()}}
+\newtoks\everyenablevspacing
+\newtoks\everydisablevspacing
+
+\def\enablevspacing {\the\everyenablevspacing}
+\def\disablevspacing{\the\everydisablevspacing}
+
+\appendtoks
+ \writestatus\m!systems{! ! enabling vspacing ! !}%
+ \settrue\vspacingenabled
+ \ctxlua{vspacing.enable()}%
+\to \everyenablevspacing
+
+\appendtoks
+ \writestatus\m!systems{! ! disabling vspacing ! !}%
+ \setfalse\vspacingenabled
+ \ctxlua{vspacing.disable()}%
+\to \everydisablevspacing
+
+\let\originalblank \blank % we use \original for non-primitives
+\let\originalvspacing\vspacing
\let\setupvspacing\setupblank % for the moment
-\protect \endinput
+% so, the new one will be
+%
+% \chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
+%
+% \def\bottomalignlimit{3\lineheight} % will be settable
+%
+% \def\raggedbottom {\chardef\bottomraggedness=0 \settopskip}
+% \def\alignbottom {\chardef\bottomraggedness=1 \settopskip}
+% \def\baselinebottom{\chardef\bottomraggedness=2 \settopskip}
+%
+% \let\normalbottom =\alignbottom
+
+% \hyphenpenalty = ( 2.5 * \hsize ) / \raggedness
+% \tolerance >= 1500 % was 200
+% \raggedness = 2 .. 6\bodyfontsize
+
+\chardef\raggedstatus=0 % normal left center right
+
+\def\leftraggedness {2\bodyfontsize}
+\def\rightraggedness {2\bodyfontsize}
+\def\middleraggedness {6\bodyfontsize}
+
+\def\middleraggedness {.5\hsize} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
+
+% oeps, hsize can be 0pt in which case we get a strange division
+
+\def\middleraggedness {\ifdim\hsize=\zeropoint6\bodyfontsize\else.5\hsize\fi} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
+
+%D More hyphenation control, will be combined with align
+%D setup.
+
+\def\nohyphens
+ {\ifx\dohyphens\relax
+ \edef\dohyphens
+ {\hyphenpenalty\the\hyphenpenalty
+ \exhyphenpenalty\the\exhyphenpenalty\relax}%
+ \fi
+ \hyphenpenalty\plustenthousand
+ \exhyphenpenalty\plustenthousand}
+
+\let\dohyphens\relax
+
+%D To prevent unwanted side effects, we also have to check
+%D for hyphens here:
+
+\newskip\@@raggedskipa
+\newskip\@@raggedskipb
+
+\def\setraggedness#1%
+ {\ifnum\tolerance<1500\relax % small values have
+ \tolerance1500\relax % unwanted side effects
+ \fi
+ \ifx\dohyphens\relax
+ % this code will be reconsidered / kind of fuzzy (and old)
+ \@@raggedskipa 2.5\hsize
+ \@@raggedskipb #1\relax
+ \divide\@@raggedskipa \@@raggedskipb
+ \hyphenpenalty\@@raggedskipa
+ \fi}
+
+\let\updateraggedskips\relax
+
+\def\setraggedskips#1#2#3#4#5#6#7% never change this name
+ {\def\updateraggedskips{\dosetraggedskips{#1}{#2}{#3}{#4}{#5}{#6}{#7}}%
+ \updateraggedskips}
+
+\def\dosetraggedskips#1#2#3#4#5#6#7%
+ {\chardef \raggedstatus#1\relax
+ \leftskip 1\leftskip \!!plus#2\relax % zie: Tex By Topic 8.1.3
+ \rightskip 1\rightskip\!!plus#3\relax % zie: Tex By Topic 8.1.3
+ \spaceskip #4\relax
+ \xspaceskip #5\relax
+ \parfillskip\zeropoint\!!plus#6\relax
+ \parindent #7\relax}
+
+% \def\notragged%
+% {\setraggedskips{0}{0em}{0em}{0em}{0em}{1fil}{\parindent}}
+
+% older (context) names:
+
+\let\spaceamount \interwordspace
+\let\emspaceamount\emwidth
-\starttext
+% tracing:
+
+\def\doshowpardata#1%
+ {\ifx#1\relax\else
+ \hbox{\string#1: \the#1}\endgraf
+ \expandafter\doshowpardata
+ \fi}
+
+\def\showpardata
+ {\edef\thepardata
+ {\hbox{font: \fontname\font}\endgraf
+ \doshowpardata
+ \interwordspace \interwordstretch \interwordshrink \emwidth \exheight \extraspace
+ \hsize \vsize
+ \leftskip \rightskip
+ \spaceskip \xspaceskip
+ \parindent \parfillskip
+ \hyphenpenalty \exhyphenpenalty
+ \displaywidowpenalty \widowpenalty \clubpenalty \brokenpenalty
+ \doublehyphendemerits \finalhyphendemerits \adjdemerits
+ \relax}%
+ \begingroup
+ \dontshowcomposition
+ \inleftmargin{\vsmash
+ {\switchtobodyfont[7pt,tt]%
+ \framed[\c!align=\v!right]{\thepardata}}}%
+ \endgroup}
+
+\def\startshowpardata
+ {\begingroup
+ \showcomposition
+ \showstruts\tracepositionstrue \tracingparagraphs\maxdimen
+ \appendtoksonce\showpardata\let\showpardata\relax\to\everypar}
+
+\def\stopshowpardata
+ {\endgraf
+ \endgroup}
+
+% \defineXMLenvironment[showpardata] \startshowpardata \stopshowpardata
+% \defineXMLsingular [showpardata] \showpardata
+
+% defaults
+
+\def\raggedfillamount {1fil}
+\def\raggedhalffillamount{.5fil}
+\def\raggedspaceamount {\interwordspace} % {.3333em}
+\def\raggedxspaceamount {.5em}
+
+\def\notragged
+ {\chardef\raggedstatus\zerocount
+ \leftskip 1\leftskip
+ \rightskip 1\rightskip
+ \spaceskip \zeropoint
+ \xspaceskip \zeropoint
+ \parfillskip\zeropoint\!!plus\raggedfillamount\relax
+ \let\updateraggedskips\relax} % new
+
+\let\forgetragged\notragged
+
+\def\raggedleft
+ {\setraggedness\leftraggedness
+ \setraggedskips1\leftraggedness\zeropoint\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+\def\raggedcenter
+ {\setraggedness\middleraggedness
+ \setraggedskips2\middleraggedness\middleraggedness\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+%D We used to have:
+%D
+%D \starttyping
+%D \def\raggedright
+%D {\setraggedness\rightraggedness
+%D \setraggedskips{3}{0em}{\rightraggedness}{.3333em}{.5em}{0em}{\parindent}}
+%D \stoptyping
+%D
+%D However, the next alternative, suggested by Taco, is better.
+
+\def\raggedright
+ {\setraggedness\rightraggedness
+ \setraggedskips3\zeropoint\rightraggedness\raggedspaceamount
+ \raggedxspaceamount\raggedfillamount\parindent}
+
+\def\veryraggedleft
+ {\setraggedskips1\raggedfillamount\zeropoint\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+%D When we want the last line to have a natural width:
+%D
+%D \starttyping
+%D \def\veryraggedleft%
+%D {\setraggedskips{1}{1fil}{0em}{.3333em}{.5em}{0em}{-1fil}}
+%D \stoptyping
+%D
+%D but this one is not accepted by the macros.
+
+\def\veryraggedcenter
+ {\setraggedskips2\raggedfillamount\raggedfillamount\raggedspaceamount
+ \raggedxspaceamount\zeropoint\zeropoint}
+
+\def\veryraggedright
+ {\setraggedskips3\zeropoint\raggedfillamount\raggedspaceamount
+ \raggedxspaceamount\zeropoint\parindent}
+
+\def\ttraggedright
+ {\tttf
+ \setraggedskips3\zeropoint\rightraggedness
+ \zeropoint\zeropoint\zeropoint\parindent} % \ctxparindent
+
+%D A bonus one:
+
+\def\raggedwidecenter
+ {\setraggedness\middleraggedness
+ \setraggedskips2\raggedhalffillamount\raggedhalffillamount
+ \raggedspaceamount\raggedxspaceamount\zeropoint\zeropoint}
+
+\newif\if@@asragged \@@asraggedtrue % old method
+
+% todo
+%
+% \setuplayout[grid=yes,lines=44] \showgrid
+% \starttext
+% test \vfill test \endgraf \strut \endgraf \vskip-\lineheight \removedepth \pagina test
+% \stoptext
+
+% \setupalign[reset,new,right,old]
+
+\def\@@align@@rl{\if!!donea\veryraggedleft \else\raggedleft \fi}
+\def\@@align@@rr{\if!!donea\veryraggedright \else\raggedright \fi}
+\def\@@align@@rc{\if!!donea\veryraggedcenter\else\raggedcenter\fi}
+
+\setvalue{@@ngila@@\v!broad }{\!!doneatrue}
+\setvalue{@@ngila@@\v!wide }{\!!donebtrue}
+
+\def\installalign#1#2{\setvalue{@@align@@#1}{#2}} % can be used for overloads
+
+\installalign \v!new {\@@asraggedfalse}
+\installalign \v!old {\@@asraggedtrue}
+\installalign \empty {}
+
+\installalign \v!line {\baselinebottom}
+\installalign \v!bottom {\raggedbottom}
+\installalign \v!height {\normalbottom}
+\installalign \v!width {\notragged}
+\installalign \v!normal {\notragged}
+\installalign \v!yes {\notragged}
+\installalign \v!no {\raggedright}
+\installalign \v!inner {\if@@asragged \setraggedparagraphmode\@@align@@rl\@@align@@rr \else
+ \setraggedparagraphmode\@@align@@rr\@@align@@rl \fi}
+\installalign \v!outer {\if@@asragged \setraggedparagraphmode\@@align@@rr\@@align@@rl \else
+ \setraggedparagraphmode\@@align@@rl\@@align@@rr \fi}
+\installalign \v!left {\if@@asragged\@@align@@rl\else\@@align@@rr\fi}
+\installalign \v!right {\if@@asragged\@@align@@rr\else\@@align@@rl\fi}
+\installalign \v!middle {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
+\installalign \v!flushleft {\if!!donea\veryraggedright \else\raggedright\fi}
+\installalign \v!flushright {\if!!donea\veryraggedleft \else\raggedleft \fi}
+\installalign \v!flushouter {\setraggedparagraphmode\raggedleft\raggedright}
+\installalign \v!flushinner {\setraggedparagraphmode\raggedright\raggedleft}
+\installalign \v!center {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
+\installalign \v!hanging {\enableprotruding}
+\installalign \v!nothanging {\disableprotruding}
+\installalign \v!hz {\enableadjusting}
+\installalign \v!nohz {\disableadjusting}
+\installalign \v!spacing {\enablespacehandling \enablekernhandling}
+\installalign \v!nospacing {\disablespacehandling\disablekernhandling}
+\installalign \v!hyphenated {\dohyphens}
+\installalign \v!nothyphenated {\nohyphens}
+\installalign \v!new {\@@asraggedfalse} % so new will give you consistency
+\installalign \v!reset {\notragged\normalbottom}
+
+\installalign \v!tolerant {\tolerance3000 \relax}
+\installalign \v!verytolerant {\tolerance4500 \relax}
+\installalign \v!stretch {\emergencystretch\bodyfontsize}
+
+\installalign \v!grid {\doenablegridsnapping } % only mkiv
+\installalign \v!nogrid {\dodisablegridsnapping} % only mkiv
+
+\installalign \v!righttoleft {\lefttoright}
+\installalign \v!lefttoright {\righttoleft}
+\installalign {l2r} {\lefttoright}
+\installalign {r2l} {\righttoleft}
+
+\newcount\hyphenminoffset
+
+\ifx\sethyphenationvariables\undefined \let\sethyphenationvariables\relax \fi
+
+\def\lesshyphens
+ {\advance\hyphenminoffset\plusone
+ \sethyphenationvariables}
+
+\def\morehyphens
+ {\ifcase\hyphenminoffset \else
+ \advance\hyphenminoffset\minusone
+ \fi
+ \sethyphenationvariables}
+
+\installalign \v!lesshyphenation {\lesshyphens}
+\installalign \v!morehyphenation {\morehyphens}
+
+\def\dodosetupalign#1{\csname @@align@@#1\endcsname}
+\def\dodosetupngila#1{\csname @@ngila@@#1\endcsname}
+
+\def\setupalign
+ {\dosingleargument\dosetupalign}
+
+\def\dosetupalign[#1]% can be made faster by checking for defined #1
+ {\!!doneafalse
+ \!!donebfalse
+ \processcommacommand[#1]\dodosetupngila
+ \processcommacommand[#1]\dodosetupalign}
+
+% \setupalign[flushleft] \input ward \par % lijnlinks
+% \setupalign[right] \input ward \par
+
+% \setupalign[flushright] \input ward \par % lijnrechts
+% \setupalign[left] \input ward \par
+
+% \setupalign[middle] \input ward \par % centreer
+% \setupalign[center] \input ward \par
+
+\def\startalignment
+ {\bgroup
+ \setupalign}
+
+\def\stopalignment
+ {\par
+ \egroup}
+
+\chardef\alignstrutmode=1
+
+% see later for the real definition, which in the simple case is:
+
+\newtoks \everyleftofalignedline
+\newtoks \everyrightofalignedline
+
+\def\shiftalignedline#1#2#3#4% left, right, inner, outer
+ {\rightorleftpageaction
+ {\everyleftofalignedline {\hskip\dimexpr#1+#3\relax}%
+ \everyrightofalignedline{\hskip\dimexpr#2+#4\relax}}
+ {\everyleftofalignedline {\hskip\dimexpr#1+#4\relax}%
+ \everyrightofalignedline{\hskip\dimexpr#2+#3\relax}}}
+
+\def\doalignline#1#2% \\ == newline
+ {\noindentation % was \noindent
+ \dontleavehmode % added in marrakesch at TUG 2006\begingroup
+ \begingroup
+ \setlocalhsize % new
+ \def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
+ \dowithnextbox
+ {\hbox to \localhsize
+ {\ifcase\alignstrutmode\or\strut\fi
+ \the\everyleftofalignedline
+ #1\unhbox\nextbox#2\relax
+ \the\everyrightofalignedline}%
+ \endgroup}
+ \hbox}
+
+% plain commands
+
+\ifx\undefined\line \def\line {\hbox to\hsize} \fi
+\ifx\undefined\leftline \def\leftline #1{\line{#1\hss}} \fi
+\ifx\undefined\rightline \def\rightline #1{\line{\hss#1}} \fi
+\ifx\undefined\centerline \def\centerline#1{\line{\hss#1\hss}} \fi
+
+% directe commando's
+
+\def\leftaligned {\doalignline \relax \hss }
+\def\midaligned {\doalignline \hss \hss }
+\def\rightaligned{\doalignline \hss \relax}
+
+\let\centeraligned\midaligned
+
+\def\regelbegrensd#1{\limitatetext{#1}{\hsize}{\unknown}} % to be translated
+
+% indirecte commando's
+
+\letvalue{\s!do\v!line\v!left }\leftaligned
+\letvalue{\s!do\v!line\v!right }\rightaligned
+\letvalue{\s!do\v!line\v!middle }\midaligned
+\letvalue{\s!do\v!line\v!flushleft }\rightaligned
+\letvalue{\s!do\v!line\v!flushright}\leftaligned
+\letvalue{\s!do\v!line\v!center }\midaligned
+
+\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
+
+%D Experimental:
+
+\def\doxalignline#1#2#3#4#5#6%
+ {\noindentation % was \noindent
+ \dontleavehmode % added in marrakesch at TUG 2006\begingroup
+ \begingroup
+ \setlocalhsize
+ \def\\{\egroup\par\doxalignline#1#2#3#4#5#6\bgroup}% inefficient
+ \dowithnextbox
+ {%\noindent moved up
+ \hbox to \localhsize
+ {#1\hskip\ifdone#2\else#3\fi#4%
+ \hbox to \localhsize
+ {\the\everyleftofalignedline
+ \ifcase\alignstrutmode\or\strut\fi
+ \ifdone#5\unhbox\nextbox#6\else#6\unhbox\nextbox#5\fi
+ \the\everyrightofalignedline}%
+ \hss}%
+ \endgroup}
+ \hbox}
+
+\def\doxcheckline
+ {\signalrightpage\doifrightpageelse\donetrue\donefalse}
+
+\setvalue{\s!do\v!line\v!inner }{\doxalignline\doxcheckline++\zeropoint \relax\hss }
+\setvalue{\s!do\v!line\v!outer }{\doxalignline\doxcheckline++\zeropoint \hss \relax}
+\setvalue{\s!do\v!line\v!innermargin}{\doxalignline\doxcheckline-+\innermargintotal\relax\hss }
+\setvalue{\s!do\v!line\v!outermargin}{\doxalignline\doxcheckline+-\outermargintotal\hss \relax}
+\setvalue{\s!do\v!line\v!inneredge }{\doxalignline\doxcheckline-+\inneredgetotal \relax\hss }
+\setvalue{\s!do\v!line\v!outeredge }{\doxalignline\doxcheckline+-\outeredgetotal \hss \relax}
+\setvalue{\s!do\v!line\v!backspace }{\doxalignline\doxcheckline-+\backspace \relax\hss }
+\setvalue{\s!do\v!line\v!cutspace }{\doxalignline\doxcheckline+-\cutspace \hss \relax}
+
+\setvalue{\s!do\v!line\v!leftmargin }{\doxalignline\donefalse --\leftmargintotal \hss \relax}
+\setvalue{\s!do\v!line\v!rightmargin}{\doxalignline\donefalse ++\rightmargintotal\relax\hss }
+\setvalue{\s!do\v!line\v!leftedge }{\doxalignline\donefalse --\leftedgetotal \hss \relax}
+\setvalue{\s!do\v!line\v!rightedge }{\doxalignline\donefalse ++\rightedgetotal \relax\hss }
+
+% ! ! ! beware, redefining \doalignline gives the wrong results ! ! !
+%
+% \def\doalignline{\doxalignline\donefalse++\zeropoint}
+
+%D Better:
+
+\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
+
+\def\alignedline#1#2% setting default
+ {\csname\s!do\v!line\ifcsname\s!do\v!line#1\endcsname#1\else#2\fi\endcsname}
+
+%D ...
+
+\def\dosetuptolerance[#1]%
+ {\doifinsetelse\v!vertical{#1}%
+ {\ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!verystrict=>\def\bottomtolerance{},
+ \v!strict=>\def\bottomtolerance{.050},
+ \v!tolerant=>\def\bottomtolerance{.075},
+ \v!verytolerant=>\def\bottomtolerance{.100}]}%
+ {\ExpandFirstAfter\processallactionsinset
+ [#1]
+ [ \v!stretch=>\emergencystretch\bodyfontsize,
+ \v!space=>\spaceskip.5em\!!plus.25em\!!minus.25em\relax,
+ \v!verystrict=>\tolerance 200,
+ \v!strict=>\tolerance1500,
+ \v!tolerant=>\tolerance3000,
+ \v!verytolerant=>\tolerance4500]}}
+
+\def\setuptolerance
+ {\dosingleargument\dosetuptolerance}
+
+% \def\woordrechts
+% {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
+
+% beware: \wordright{whatever\kern-\rightskip} should work!
+% so, no funny boxing here
+
+\def\dowordright[#1]%
+ {% don't change
+ \groupedcommand
+ {\removeunwantedspaces
+ \hfill
+ \allowbreak % changed back from \hskip\zeropoint
+ \strut
+ \hfill
+ \quad % decent spacing
+ \hbox}
+ {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
+ \parfillskip\zeropoint
+ %\finalhyphendemerits\zerocount % yes or no
+ \par}}
+
+\def\wordright
+ {\dosingleempty\dowordright}
+
+% \dorecurse{5}{something } \wordright{--someone} \endgraf
+% \dorecurse{6}{something } \wordright{--someone} \endgraf
+% \dorecurse{7}{something } \wordright{--someone} \endgraf
+%
+% \dorecurse{5}{something } \wordright{--someone else entirely} \endgraf
+% \dorecurse{6}{something } \wordright{--someone else entirely} \endgraf
+% \dorecurse{7}{something } \wordright{--someone else entirely} \endgraf
+%
+% \wordright[\rightskip]{whatever}
+
+% \simplealignedbox{2cm}{right}{x}
+
+\setvalue{\s!simple\c!align\v!right }#1#2{\hbox to #1{#2\hss}}
+\setvalue{\s!simple\c!align\v!left }#1#2{\hbox to #1{\hss#2}}
+\setvalue{\s!simple\c!align\v!flushright }#1#2{\hbox to #1{\hss#2}}
+\setvalue{\s!simple\c!align\v!flushleft }#1#2{\hbox to #1{#2\hss}}
+\setvalue{\s!simple\c!align\v!middle }#1#2{\hbox to #1{\hss#2\hss}}
+
+\def\simplealignedbox#1{\executeifdefined{\s!simple\c!align#1}{\getvalue{\s!simple\c!align\v!right}}}
+
+%D \macros
+%D {pushindentation,popindentation}
+%D
+%D The pushing and popping is done by:
+
+\newbox\indentationboxA
+\newbox\indentationboxB
+
+\def\pushindentation
+ {\bgroup
+ \ifhmode
+ \unskip
+ \setbox\indentationboxA\lastbox % get \strut if present
+ \unskip
+ \setbox\indentationboxB\lastbox % get \indent generated box
+ \unskip
+ \else
+ \hskip\zeropoint % switch to horizontal mode
+ \unskip
+ \setbox\indentationboxA\lastbox % get \indent generated box
+ \setbox\indentationboxB\emptybox
+ \fi}
+
+\def\popindentation
+ {\box\indentationboxB\box\indentationboxA % put back the boxes
+ \egroup}
+
+%D The only complication lays in \type{\strut}. In \PLAIN\
+%D \TEX\ a \type{\strut} is defined as:
+%D
+%D \starttyping
+%D \def\strut%
+%D {\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
+%D \stoptyping
+%D
+%D But what is a \type{\strut}? Normally it's a rule of width
+%D zero, but when made visual, it's a rule and a negative skip.
+%D The mechanism for putting things in the margins described
+%D here cannot handle this situation very well. One
+%D characteristic of \type{\strut} is that the \type{\unhcopy}
+%D results in entering horizontal mode, which in return leads
+%D to some indentation.
+%D
+%D To serve our purpose a bit better, the macro \type{\strut}
+%D can be redefined as:
+%D
+%D \starttyping
+%D \def\strut
+%D {\relax\ifmmode\else\hskip0pt\fi\copy\strutbox}
+%D \stoptyping
+%D
+%D Or more compatible:
+%D
+%D \starttyping
+%D \def\strut
+%D {\relax\ifmmode
+%D \copy\strutbox
+%D \else
+%D \bgroup\setbox\strutbox=\normalhbox{\box\strutbox}\unhcopy\strutbox\egroup
+%D \fi}
+%D \stoptyping
+%D
+%D In \CONTEXT\ however we save some processing time by putting
+%D an extra \type{\hbox} around the \type{\strutbox}.
+
+% moved from page-lin.tex to here (due to visualization added
+% in august 2003)
+%
+% \unexpanded \def\crlf
+% {\ifhmode\unskip\else\strut\fi\ifcase\raggedstatus\hfil\fi\break}
+
+\unexpanded \def\crlf
+ {\ifhmode
+ \unskip
+ \prewordbreak\crlfplaceholder
+ \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
+ \break
+ \else
+ \crlfplaceholder
+ \endgraf
+ \fi}
+
+\def\crlfplaceholder
+ {\strut}
+
+\def\settestcrlf
+ {\def\crlfplaceholder
+ {\hbox to \zeropoint
+ {\strut{\infofont\kern.25em}\lohi{\infofont CR}{\infofont LF}\hss}}}
+
+%D \starttyping
+%D % \setuplayout[gridgrid=yes] \showgrid
+%D
+%D \startbuffer
+%D test 1\crlf
+%D test 2\crlf
+%D
+%D \crlf test 3
+%D
+%D test 4\crlf
+%D test 5
+%D
+%D \crlf
+%D \crlf
+%D \crlf
+%D test 6
+%D \stopbuffer
+%D
+%D \hbox
+%D {\hsize5em
+%D \ruledvtop{\getbuffer}\enspace
+%D \ruledvtop{\showstruts\getbuffer}\enspace
+%D \hsize15em \setuptyping[before=,after=]%
+%D \ruledvtop{\typebuffer}}
+%D \stoptyping
+
+\def\justonespace
+ {\removelastspace\space} % \removeunwantedspaces\space
+
+\def\ignorecrlf
+ {\let\crlf\justonespace\let\\\crlf}
+
+\def\showstruts
+ {\setteststrut
+ \settestcrlf}
+
+\def\definehspace
+ {\dotripleempty\dodefinehspace}
+
+\def\dodefinehspace[#1][#2][#3]% #1 = optional namespace
+ {\ifthirdargument
+ \setvalue{\??hs#1:#2}{#3}%
+ \else
+ \setvalue{\??hs:#1}{#2}%
+ \fi}
+
+\unexpanded\def\hspace
+ {\dodoubleempty\dohspace}
+
+\def\dohspace[#1][#2]%
+ {\ifsecondargument
+ \dodohspace[#1][#2]%
+ \else\iffirstargument
+ \hspace[][#1]%
+ \else
+ \hspace[][\s!default]%
+ \fi\fi}
+
+\def\dodohspace[#1][#2]%
+ {\ifhmode
+ \removeunwantedspaces
+ \hskip\hspaceamount{#1}{#2}%
+ \expandafter\ignorespaces
+ \fi}
+
+\def\hspaceamount#1#2%
+ {\executeifdefined{\??hs#1:#2}{\executeifdefined{\??hs:#2}\zeropoint}}
+
+\definehspace [\v!small] [.25\emspaceamount]
+\definehspace [\v!medium] [.5\emspaceamount]
+\definehspace [\v!big] [1\emspaceamount]
+\definehspace [\v!normal] [1\spaceamount]
+\definehspace [\v!default] [\spaceamount]
+
+%D Taken from Taco's math module (cq. \AMS\ macros), but
+%D adapted to \type {\hspace}:
+
+\unexpanded\def\textormathspace#1#2#3%
+ {\ifmmode\mskip#1#2\else\kern#1\hspaceamount\empty{#3}\fi\relax}
+
+\newmuskip\hairmuskip \hairmuskip=.15mu
+
+\unexpanded\def\hairspace {\textormathspace+\hairmuskip{.5}}
+\unexpanded\def\thinspace {\textormathspace+\thinmuskip 1}
+\unexpanded\def\medspace {\textormathspace+\medmuskip 2}
+\unexpanded\def\thickspace {\textormathspace+\thickmuskip3}
+\unexpanded\def\neghairspace {\textormathspace-\thinmuskip{.5}}
+\unexpanded\def\negthinspace {\textormathspace-\thinmuskip 1}
+\unexpanded\def\negmedspace {\textormathspace-\medmuskip 2}
+\unexpanded\def\negthickspace{\textormathspace-\thickmuskip3}
+
+% needed for unicode:
+
+\unexpanded\def\twoperemspace {\hskip\dimexpr\emwidth/2\relax} % == \enspace
+\unexpanded\def\threeperemspace {\hskip\dimexpr\emwidth/3\relax}
+\unexpanded\def\fourperemspace {\hskip\dimexpr\emwidth/4\relax}
+\unexpanded\def\fiveperemspace {\hskip\dimexpr\emwidth/5\relax} % goodie
+\unexpanded\def\sixperemspace {\hskip\dimexpr\emwidth/6\relax}
+\unexpanded\def\figurespace {\begingroup\setbox\scratchbox\hbox{0}\hskip\wd\scratchbox\endgroup} % there is a command for this
+\unexpanded\def\punctuationspace {\begingroup\setbox\scratchbox\hbox{.}\hskip\wd\scratchbox\endgroup}
+\unexpanded\def\ideographicspace {\hskip\dimexpr\emwidth/1\relax}
+\unexpanded\def\ideographichalffillspace{\hskip\dimexpr\emwidth/2\relax}
+%unexpanded\def\nobreakspace {\penalty\plustenthousand\space}
+\unexpanded\def\nobreakspace {\penalty\plustenthousand\kern\interwordspace}
+\unexpanded\def\narrownobreakspace {\penalty\plustenthousand\thinspace}
+%unexpanded\def\zerowidthnobreakspace {\penalty\plustenthousand\hskip\zeropoint}
+\unexpanded\def\zerowidthnobreakspace {\penalty\plustenthousand\kern\zeropoint}
+\unexpanded\def\zerowidthspace {\hskip\zeropoint}
+
+\definehspace[.5][.1250\emspaceamount] % could also be [.1250\spaceamount]
+\definehspace[1] [.1667\emspaceamount]
+\definehspace[2] [.2222\emspaceamount]
+\definehspace[3] [.2777\emspaceamount]
+
+\let \, \thinspace
+\let \: \medspace
+\let \; \thickspace
+\let \! \negthinspace
+
+% this will become an alternative bunch of \blank settings
+%
+% \startlines
+% \scratchskip=.23pt plus 10pt minus 4pt \relax \number\scratchskip \space \the\scratchskip
+% \setsimplifiedskip\scratchskip1 \number\scratchskip \space \the\scratchskip
+% \setsimplifiedskip\scratchskip2 \number\scratchskip \space \the\scratchskip
+% \getsimplifiedskip\scratchskip\scratchcounter \number\scratchcounter
+% \stoplines
+%
+% \hrule width10cm \endgraf
+% \discardedskip{10pt}
+% \retainedskip {4pt}
+% \discardedskip {5pt}
+% \hrule width10cm \endgraf
+% \blockedskip{0pt}
+% \discardedskip{10pt}
+% \retainedskip {4pt}
+% \discardedskip {5pt}
+% \hrule width10cm \endgraf
+% \frozenskip {4cm}
+% \hrule width10cm \endgraf
+% \vskip10pt
+% \hrule width10cm \endgraf
+
+\newskip\simplifiedskip
+\newskip\simplifiedcounter
+
+\chardef\@@discardedskip1
+\chardef\@@retainedskip 2
+\chardef\@@forcedskip 3
+\chardef\@@blockedskip 4
+\chardef\@@frozenskip 5 % after heads, no break
+
+\def\setsimplifiedskip#1#2%
+ {#1\dimexpr(10\dimexpr(#1/10)) plus \gluestretch#1 minus \glueshrink#1\relax
+ \advance#1\numexpr(#2)sp\relax}
+
+\def\getsimplifiedskip#1#2%
+ {\simplifiedskip#1\relax
+ \ifzeropt\simplifiedskip % \ifdim\simplifiedskip=\zeropoint
+ #2\zerocount
+ \else
+ \simplifiedcounter\dimexpr10\dimexpr#1/10\relax\relax
+ \advance\simplifiedskip-\simplifiedcounter
+ #2\number\simplifiedskip\relax
+ \fi}
+
+\def\conditionalskip#1#2%
+ {\scratchskip#1\relax
+ \setsimplifiedskip\scratchskip#2\relax
+ \vskip\scratchskip\relax}
+
+\def\defrostskip
+ {\scratchskip\lastskip\penalty50000\normalvskip-\scratchskip\penalty50000\relax}
+
+\def\frozenskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \fi}
+
+\def\discardedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@discardedskip
+ \or % discard
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@discardedskip
+ \fi
+ \or % retain
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@discardedskip
+ \fi
+ \or % forced
+ \conditionalskip{#1}\@@discardedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+\def\retainedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@retainedskip
+ \or % discard
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@retainedskip
+ \or % retain
+ \ifdim\lastskip>#1\else
+ \normalvskip-\lastskip
+ \conditionalskip{#1}\@@retainedskip
+ \fi
+ \or % forced
+ \conditionalskip{#1}\@@retainedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+\def\forcedskip#1%
+ {\endgraf
+ \ifvmode
+ \conditionalskip{#1}\@@forcedskip
+ \fi}
+
+\def\blockedskip#1%
+ {\endgraf
+ \ifvmode
+ \getsimplifiedskip\lastskip\scratchcounter
+ \ifcase\scratchcounter
+ \conditionalskip{#1}\@@blockedskip
+ \or % discard
+ \conditionalskip{#1}\@@blockedskip
+ \or % retain
+ \conditionalskip{#1}\@@blockedskip
+ \or % forced
+ \conditionalskip{#1}\@@blockedskip
+ \or % ignored
+ \or % frozen
+ \ifdim\lastskip>#1\else
+ \defrostskip
+ \conditionalskip{#1}\@@frozenskip
+ \fi
+ \else\ifdim#1=\zeropoint\else
+ \vskip#1\relax
+ \fi\fi
+ \fi}
+
+% beware, changing this will break some code (like pos/backgrounds)
+
+\newtoks\everyfirstparagraphintro
+\newtoks\everynextparagraphintro
+\newtoks\@@everyparagraphtoks
+
+\chardef\everyparagraphintro\zerocount
+
+\def\setupparagraphintro
+ {\dodoubleempty\dosetupparagraphintro}
+
+\def\dosetupparagraphintro[#1][#2]%
+ {\processallactionsinset
+ [#1]
+ [ \v!reset=>\global\chardef\everyparagraphintro\zerocount
+ \global\everyfirstparagraphintro\emptytoks
+ \global\everynextparagraphintro \emptytoks,
+ \v!first=>\global\chardef\everyparagraphintro\plusone
+ \doglobal\appendtoks#2\to\everyfirstparagraphintro,
+ \v!next=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plusone\fi
+ \doglobal\appendtoks#2\to\everynextparagraphintro,
+ \v!each=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plustwo\fi
+ \doglobal\appendtoks#2\to\everyfirstparagraphintro
+ \doglobal\appendtoks#2\to\everynextparagraphintro]}
+
+%D We can say:
+%D
+%D \starttyping
+%D \setupparagraphintro[first][\index{Knuth}]
+%D \stoptyping
+%D
+%D Maybe more convenient is:
+%D
+%D \starttyping
+%D \flushatparagraph{\index{Zapf}}
+%D \stoptyping
+
+\def\flushatparagraph#1%
+ {\global\chardef\everyparagraphintro\plusone
+ \global\appendtoks{#1}\to\everyfirstparagraphintro}
+
+\def\doinsertparagraphintro
+ {\begingroup
+ \everypar\emptytoks
+ \ifcase\everyparagraphintro\relax
+ % no data
+ \@@everyparagraphtoks\emptytoks
+ \or
+ % first data
+ \global\chardef\everyparagraphintro\plustwo
+ \@@everyparagraphtoks\everyfirstparagraphintro
+ \global\everyfirstparagraphintro\emptytoks
+ \or
+ % next data
+ \@@everyparagraphtoks\everynextparagraphintro
+ \fi
+ \the\@@everyparagraphtoks
+ \endgroup}
+
+\def\insertparagraphintro
+ {\ifcase\everyparagraphintro\else\@EA\doinsertparagraphintro\fi}
+
+% \appendtoksonce\insertparagraphintro\to\everypar % should come last
+
+%D \starttyping
+%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
+%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
+%D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT \hss}]
+%D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN \hss}]
+%D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH \hss}]
+%D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA \hss}]
+%D
+%D some paragraph \par
+%D some paragraph \par
+%D some paragraph \par
+%D
+%D \definelabel[parnumber]
+%D
+%D \setupparagraphintro[reset,each][\inleft{\slxx\parnumber}]
+%D
+%D some paragraph \par
+%D some paragraph \par
+%D some paragraph \par
+%D \stoptyping
+
+%D \macros
+%D {flushatnextpar}
+%D
+%D This macro collects data that will be flushed at the next paragraph.
+%D By using this macro you can avoid interfering nodes (writes, etc).
+
+\newbox \postponednodedata
+
+\def\flushatnextpar
+ {\bgroup
+ \dowithnextbox
+ {\global\setbox\postponednodedata\hbox{\box\postponednodedata\box\nextbox}\egroup}%
+ \hbox}
+
+\def\flushpostponednodedata
+ {\ifvoid\postponednodedata\else
+ \hbox{\smashedbox\postponednodedata}%
+ \fi}
+
+% Very nasty but needed for margin stuff inside colored
+% paragraphs.
+
+\let\normalvadjust\vadjust
+
+% test this prikkels/pascal margin text before heads (mode
+% 1) as well as uitwerkingen (mode 2)
+
+%chardef\graphicvadjustmode=0 % fake
+%chardef\graphicvadjustmode=1 % normal
+\chardef\graphicvadjustmode=2 % normal + compensate (== default)
+
+\def\graphicvadjust % bad, those low level color calls here
+ {\dowithnextboxcontent
+ {\forgetall}
+ {\ifcase\graphicvadjustmode \@EA \fakedvadjust \else \@EA\normalvadjust \fi
+ {\dostartgraphicgroup % don't ask
+ \localstarttextcolor
+ \unvbox\nextbox
+ \localstoptextcolor % don't ask
+ \dostopgraphicgroup
+ \ifcase\graphicvadjustmode \or \or
+ % corrects for one line paragraphs
+ \nointerlineskip
+ \kern-\struttotal
+ \nointerlineskip
+ \verticalstrut
+ \fi}}%
+ \vbox}
+
+%D This works only in a properly strutted line, and is meant
+%D for deeply burried operations, like in heads.
+
+\def\fakedvadjust
+ {\dowithnextbox
+ {\setbox\nextbox\hbox{\llap{\lower\strutdepth\box\nextbox}}%
+ \smashedbox\nextbox}%
+ \vtop}
+
+\def\flexiblespaceamount#1#2#3%
+ {#1\interwordspace
+ \!!plus#2\interwordstretch
+ \!!minus#3\interwordshrink}
+
+\def\fixedspaceamount#1%
+ {#1\interwordspace}
+
+%D This is a dangerous feature because it makes the \TEX\ source
+%D less portable, i.e. any parser now needs to apply exactly the
+%D same algorithm when it wants to interpret the source. We
+%D strongly recommend not to mention this feature in manuals! It's
+%D provided for users who are hooked to such a mechanism.
+%D
+%D \starttyping
+%D \setupsorting[logo][next=\autoinsertnextspace] \logo[TEX]{\TeX}
+%D
+%D bla bla \TEX bla bla \TEX (bla) bla (\TEX)
+%D \stoptyping
+
+\def\autoinsertnextspace{\futurelet\nexttoken\doautoinsertnextspace}
+
+\def\doautoinsertnextspace % slightly extended version of a user supplied macro
+ {\ifx\nexttoken \bgroup\else \ifx\nexttoken\begingroup\else
+ \ifx\nexttoken \egroup\else \ifx\nexttoken \endgroup\else
+ \ifx\nexttoken \/\else \ifx\nexttoken /\else \ifx\nexttoken ~\else
+ \ifx\nexttoken \ \else \ifx\nexttoken \blankspace\else \ifx\nexttoken \space\else
+ \ifx\nexttoken .\else \ifx\nexttoken ,\else
+ \ifx\nexttoken !\else \ifx\nexttoken ?\else
+ \ifx\nexttoken :\else \ifx\nexttoken ;\else
+ \ifx\nexttoken '\else \ifx\nexttoken "\else
+ \ifx\nexttoken )\else \ifx\nexttoken -\else \ifx\nexttoken |\else
+ \ifx\nexttoken \%\else \ifx\nexttoken \&\else
+ \space
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
+
+% moved from page-lin
+
+\def\installspacehandler#1#2% needs to set \obeyedspace
+ {\setvalue{\??sr#1}{#2}}
+
+\installspacehandler \v!on
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode{\tt\controlspace}}}%
+ \let\ =\obeyedspace}
+
+\installspacehandler \v!yes
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode \normalspace }}%
+ \let\ =\obeyedspace}
+
+\installspacehandler \v!off
+ {\normalspaces
+ \let\obeyedspace\normalspace
+ \let\ =\normalspace}
+
+\installspacehandler \v!fixed
+ {\obeyspaces
+ \def\obeyedspace{\mathortext\normalspace{\dontleavehmode\fixedspace}}%
+ \let\ =\obeyedspace}
+
+\def\activatespacehandler#1%
+ {\executeifdefined{\??sr#1}{\activatespacehandler\v!off}}
+
+% moved from page-lin
+
+%D When spacing is active we need to handle commands in
+%D a special way:
+%D
+%D \starttyping
+%D \setuplines[space=on]
+%D
+%D \startlines
+%D Let's talk about this{\ttsl\gobbleoneargument or}that.
+%D \stoplines
+%D
+%D \startlines
+%D Let's talk about this{\getvalue{ttsl}or}that.
+%D \stoplines
+%D \stoptyping
+%D
+%D One can indent in several ways:
+%D
+%D \starttyping
+%D \setupindenting[medium] \setuplines[indenting=odd] % no yes odd even
+%D
+%D \startlines
+%D first
+%D second
+%D third
+%D fourth
+%D \stoplines
+%D \stoptyping
+
+\def\setuplines
+ {\dodoubleargument\getparameters[\??rg]}
+
+\def\startlines
+ {\@@rgbefore
+ \pushmacro\checkindentation
+ \whitespace
+ %\page[\v!preference]} gaat mis na koppen, nieuw: later \nobreak
+ \begingroup
+ \setupindenting[\@@rgindenting]%
+ \typesettinglinestrue
+ \setupwhitespace[\v!none]%
+ \obeylines
+ \ignorespaces
+ \gdef\afterfirstobeyedline % tzt two pass, net als opsomming
+ {\gdef\afterfirstobeyedline
+ {\nobreak
+ \global\let\afterfirstobeyedline\relax}}%
+ \def\obeyedline
+ {\par
+ \afterfirstobeyedline
+ \futurelet\next\dobetweenthelines}%
+ \activatespacehandler\@@rgspace
+ \GotoPar}
+
+\def\stoplines
+ {\endgroup
+ \popmacro\checkindentation
+ \@@rgafter}
+
+\def\dobetweenthelines
+ {\doifmeaningelse\next\obeyedline\@@rginbetween\donothing}
+
+\setuplines
+ [\c!before=\blank,
+ \c!after=\blank,
+ \c!inbetween=\blank,
+ \c!indenting=\v!no,
+ \c!space=\v!default]
+
+\def\emptylines
+ {\dosingleempty\doemptylines}
+
+\def\doemptylines[#1]%
+ {\endgraf\dorecurse{\iffirstargument#1\else3\fi}\crlf}
+
+\setupwhitespace
+ [\v!none]
+
+% still old-fashioned
+
+\indenting
+ [\v!never]
+
+\setupindenting
+ [\v!none]
+
+\setupblank
+ [\v!standard,
+ \v!big]
+
+\defineblank[\v!default] [\currentblank]
+\defineblank[\v!before] [\v!default]
+\defineblank[\v!inbetween][\v!default]
+\defineblank[\v!after] [\v!before]
+
+\setupinterlinespace
+ [\c!minheight=0pt, % only special purpose
+ \c!mindepth=0pt, % only special purpose
+ \c!height=.72,
+ \c!depth=.28,
+ \c!top=1.0,
+ \c!bottom=0.4,
+ \c!distance=1pt,
+ \c!line=2.8ex,
+ \c!stretch=0]
+
+\setupnarrower
+ [\c!before=\endgraf,
+ \c!after=\endgraf,
+ \c!left=1.5em,
+ \c!right=1.5em,
+ \c!middle=1.5em]
+
+\setuptolerance
+ [\v!horizontal,\v!verystrict]
+
+\setuptolerance
+ [\v!vertical,\v!strict]
+
+\setupalign
+ [\v!bottom,
+ \v!width]
+
+\setupspacing
+ [\v!packed]
+
+\protect \endinput
\dorecurse{2}{
$2^{2^{2^{2}}}$ $2_{2_{2_{2}}}^{2^{2^{2^{2^{2^{2^{2^{2^{2}}}}}}}}}$
@@ -470,71 +4154,3 @@
\vskip10pt
fifth
}
-
-% bidi test
-
-\definefontfeature
- [arab]
- [mode=node,language=dflt,script=arab,
- init=yes,medi=yes,fina=yes,isol=yes,
- liga=yes,dlig=yes,rlig=yes,clig=yes,
- mark=yes,mkmk=yes,kern=yes,curs=yes]
-
-\font\Arabic=arabtype*arab at 20pt
-
-\def\LATIN{LATIN} {\setcharactermirroring[1]} % enable this
-\def\ARAB {محمد}
-
-\startluacode
- function document.split_tokens(str)
- for s in str:bytes() do
- tex.sprint(tex.ctxcatcodes,string.format("\\hbox{\\char %s}",s))
- end
- end
-\stopluacode
-
-\def\biditest#1#2#3% font text raw
- {\dontleavehmode\hbox
- {\framed[offset=overlay]{\tttf#2}\quad
- \ctxlua{mirror.trace = true}%
- \framed[offset=overlay]{#1#3}\quad
- \ctxlua{mirror.trace = false}
- \tttf\ctxlua{document.split_tokens([[\detokenize{#3}]])}}}
-
-\startbuffer[bidi-sample]
-\biditest\Arabic{LATIN BARA}{\textdir TLT\relax \LATIN\ \ARAB}\par
-\biditest\Arabic{BARA LATIN}{\textdir TRT\relax \LATIN\ \ARAB}\par
-\biditest\Arabic{LATIN ARAB}{\textdir TLT{\bidilro \LATIN\ \ARAB}}\par % right -> left
-\biditest\Arabic{LATIN ARAB}{\textdir TRT{\bidilro \LATIN\ \ARAB}}\par % right -> left
-\biditest\Arabic{BARA NITAL}{\textdir TLT{\bidirlo \LATIN\ \ARAB}}\par % left -> right
-\biditest\Arabic{BARA NITAL}{\textdir TRT{\bidirlo \LATIN\ \ARAB}}\par % left -> right
-\stopbuffer
-
-\startbuffer[bidi-sample]
-\biditest\Arabic{LATIN BARA}{\textdir TLT\relax \LATIN\ \ARAB}\par
-\biditest\Arabic{BARA LATIN}{\textdir TRT\relax \LATIN\ \ARAB}\par
-\biditest\Arabic{LATIN ARAB}{\textdir TLT\bidilro \LATIN\ \ARAB}\par % right -> left
-\biditest\Arabic{LATIN ARAB}{\textdir TRT\bidilro \LATIN\ \ARAB}\par % right -> left
-\biditest\Arabic{BARA NITAL}{\textdir TLT\bidirlo \LATIN\ \ARAB}\par % left -> right
-\biditest\Arabic{BARA NITAL}{\textdir TRT\bidirlo \LATIN\ \ARAB}\par % left -> right
-\stopbuffer
-
-\startbuffer[bidi-setup]
-\setupdirections[bidi=off]
-\stopbuffer
-
-{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
-
-\startbuffer[bidi-setup]
-\setupdirections[bidi=global]
-\stopbuffer
-
-{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
-
-\startbuffer[bidi-setup]
-\setupdirections[bidi=local]
-\stopbuffer
-
-{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
-
-\stoptext
diff --git a/tex/context/base/core-spa.tex b/tex/context/base/core-spa.tex
deleted file mode 100644
index 31a75876e..000000000
--- a/tex/context/base/core-spa.tex
+++ /dev/null
@@ -1,4637 +0,0 @@
-%D \module
-%D [ file=core-spa,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Spacing,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Spacing Macros}
-
-% to be sorted out: dependencies, order of initialization / also some dutch code here
-
-\unprotect
-
-% interfacing mkii/mkiv
-
-\ifx\mksetupgridsnapping \undefined \let\mksetupgridsnapping \relax \fi
-\ifx\mkenablegridsnapping \undefined \let\mkenablegridsnapping \relax \fi
-\ifx\mkdisablegridsnapping\undefined \let\mkdisablegridsnapping\relax \fi
-
-% some will move to core-var
-
-\newif \ifgridsnapping
-\newif \iffuzzyvskip
-\let \fuzzyvskip \gobbleoneargument
-\let \removelastfuzzyvskip \relax
-
-\let \startbaselinecorrection \relax
-\let \stopbaselinecorrection \relax
-\let \baselinecorrection \relax
-\let \offbaselinecorrection \relax
-
-\appendtoks \spacing 1\to \everybodyfont
-\appendtoks \presetnormallineheight \to \everybodyfont
-\appendtoks \setnormalbaselines \to \everybodyfont % check if redundant
-\appendtoks \setstrut \to \everybodyfont % check if redundant
-\appendtoks \settopskip \to \everybodyfont
-\appendtoks \setmaxdepth \to \everybodyfont
-%appendtoks \spacing 1\to \everybodyfont
-\appendtoks \simplesetupindenting \to \everybodyfont
-\appendtoks \simplesetupblank \to \everybodyfont
-\appendtoks \simplesetupwhitespace \to \everybodyfont
-%appendtoks \checknotes \to \everybodyfont % not
-\appendtoks \simplesetupspacing \to \everybodyfont % nieuw
-\appendtoks \setrelativeinterlinespace \to \everybodyfont
-
-\appendtoks \updateraggedskips \to \everyfontswitch % under test
-\prependtoks \let\par\endgraf \to \everypagebody % see \fillinline
-\appendtoks \simplesetupspacing \to \everydefinedfont
-
-% if you want to hyphenate the first word of a paragraph ... \appendtoks\hskip0pt\to\everypar
-
-\def\stelfactorenin
- {\simplesetupwhitespace
- \simplesetupblank
- \settopskip
- \setmaxdepth}
-
-\def\softbreak
- {\relax\ifhmode\hskip\parfillskip\break\fi}
-
-\let\poplastnode\relax
-
-\def\pushlastnode
- {\ifdim\lastskip=\zeropoint
- \ifnum\lastpenalty=\zerocount
- \ifnum\lastkern=\zerocount
- \let\poplastnode\relax
- \else
- \edef\poplastnode{\kern\the\lastkern\relax}\kern-\lastkern % untested
- \fi
- \else
- \edef\poplastnode{\penalty\the\lastpenalty\relax}\nobreak % untested
- \fi
- \else
- \edef\poplastnode{\vskip\the\lastskip\relax}\vskip-\lastskip % \removelastskip
- \fi}
-
-%D The dreadful sequence \type {\bgroup} \unknown\
-%D \type {\carryoverpar} \unknown\ \type {\egroup} is needed
-%D when for instance sidefloats are used in combination with
-%D something that starts with a group. This is because
-%D otherwise the indentation as set (by the output routine)
-%D inside the group are forgotten afterwards. (I must
-%D not forget its existence).
-
-\global\let\carriedoverpar\relax
-
-\def\carryoverpar#1%
- {\expanded % \scratchtoks{#1}%
- {\noexpand#1% \the\scratchtoks
- \hangindent\the\hangindent
- \hangafter \the\hangafter
- \parskip \the\parskip
- \leftskip \the\leftskip
- \rightskip \the\rightskip}}
-
-%D A quick way to determine left|/|middle|/|right states
-%D (experimental).
-
-\setvalue{\??as\v!left }{0}
-\setvalue{\??as\v!middle}{1}
-\setvalue{\??as\v!right }{2}
-
-\def\setalignmentswitch#1%
- {\chardef\alignmentswitch0\csname\??as#1\endcsname\relax}
-
-%D There are two ways to influence the interline spacing. The
-%D most general and often most consistent way is using
-%D
-%D \showsetup{setupinterlinespace}
-%D
-%D For instance
-%D
-%D \starttyping
-%D \setupinterlinespace[line=2.8ex]
-%D \stoptyping
-%D
-%D This setting adapts itself to the bodyfontsize, while for
-%D instance saying
-%D
-%D \starttyping
-%D \setupinterlinespace[line=12pt]
-%D \stoptyping
-%D
-%D sets things fixed for all sizes, which is definitely not
-%D what we want. Therefore one can also say:
-%D
-%D \starttyping
-%D \definebodyfontenvironment[9pt][interlinespace=11pt]
-%D \stoptyping
-%D
-%D One can still use \type{\setupinterlinespace} (without
-%D arguments) to set the interline space according to the
-%D current font, e.g. a \type{\bfa}.
-
-\newif\iflocalinterlinespace
-
-% font-ini
-
-\ifx\bodyfontinterlinespecs\undefined
-
- \let\bodyfontinterlinespecs\empty
- \let\bodyfontinterlinespace\empty
-
-\fi
-
-\def\presetnormallineheight
- {\edef\normallineheight{\@@itline}%
-% done elsewhere : \spacing\!!plusone % new per 10/08/2004, else problems in otr / !! needed
- \iflocalinterlinespace \else
- \doifdefined\bodyfontinterlinespecs
- {\doifsomething\bodyfontinterlinespace
- {\edef\normallineheight{\bodyfontinterlinespace}}}%
- \fi}
-
-\def\setupspecifiedinterlinespace[#1]%
- {\getparameters[\??it][#1]%
- \scratchdimen0\@@itheight\points
- \advance\scratchdimen 0\@@itdepth\points
- \ifdim\scratchdimen>\onepoint
- \showmessage\m!layouts{10}{\@@itheight,\@@itdepth}%
- \let\@@itheight\strutheightfactor
- \let\@@itdepth \strutdepthfactor
- \else
- \let\strutheightfactor\@@itheight
- \let\strutdepthfactor \@@itdepth
- \fi
- \let\minimumstrutheight \@@itminheight
- \let\minimumstrutdepth \@@itmindepth
- \let\minimumlinedistance\@@itdistance
- \let\normallineheight \@@itline % let ! ! ! ! ! ivm ex
- \doifelse\@@ittop\v!height % new, topskip does more bad than good
- {\let\topskipfactor \@@itheight}
- {\let\topskipfactor \@@ittop }%
- \let\maxdepthfactor \@@itbottom
- \let\baselinegluefactor \@@itstretch
- \setfontparameters % redundant, can be \setstrut, test first
- \updateraggedskips} % yes indeed
-
-% \let\currentrelativeinterlinespace\empty
-%
-% \def\setuprelativeinterlinespace[#1]%
-% {\processallactionsinset
-% [#1]
-% [ \v!on=>\oninterlineskip,
-% \v!off=>\offinterlineskip,
-% \v!reset=>\let\currentrelativeinterlinespace\empty
-% \setfontparameters,% just \setstrut, test first
-% \s!unknown=>\assignvalue{#1}\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
-% \spacing\currentrelativeinterlinespace]}
-
-% \setupinterlinespace[big] \switchtobodyfont[11pt] -> forgotten
-% \setupinterlinespace[auto,big] \switchtobodyfont[11pt] -> remembered
-
-\let\currentrelativeinterlinespace\empty
-
-\def\setuprelativeinterlinespace[#1]%
- {\processallactionsinset
- [#1]
- [ \v!on=>\oninterlineskip,
- \v!off=>\offinterlineskip,
- \v!reset=>\let\currentrelativeinterlinespace\empty
- \let\setrelativeinterlinespace\relax
- \setfontparameters,
- \v!auto=>\let\setrelativeinterlinespace\dosetrelativeinterlinespace,
- \s!unknown=>\assignvalue\commalistelement\currentrelativeinterlinespace{1.00}{1.25}{1.50}%
- \spacing\currentrelativeinterlinespace]}
-
-\def\dosetrelativeinterlinespace
- {\ifx\currentrelativeinterlinespace\empty\else
- \spacing\currentrelativeinterlinespace
- \fi}
-
-\let\setrelativeinterlinespace\relax
-
-% \appendtoks \setrelativeinterlinespace \to \everybodyfont
-
-\def\complexsetupinterlinespace[#1]% \commalistelement ipv #1
- {\doifassignmentelse{#1}\setupspecifiedinterlinespace\setuprelativeinterlinespace[#1]}
-
-\def\setuplocalinterlinespace[#1]%
- {\localinterlinespacetrue
- \setupinterlinespace[#1]%
- \localinterlinespacefalse}
-
-\def\simplesetupinterlinespace
- {\localinterlinespacetrue
- \setfontparameters
- \updateraggedskips % funny one here
- \localinterlinespacefalse}
-
-\definecomplexorsimple\setupinterlinespace
-
-% In earlier versions \type{\bigskipamount} was
-% \type{\ht\strutbox} and the stretch was plus or minus
-% \type{.4\dp\strutbox}. Don't ask me why. The most recent
-% implementation is based on a user supplied distance, which
-% is by default \type{.75\normalskipamount} where
-% \type{\normalskipamount} equals the current baseline
-% distance.
-
-% \lineskiplimit = -\maxdimen -> freezes baselineskip
-
-% can be conditionals
-
-\newif\ifblanknowhite \blanknowhitefalse
-\newif\ifblankindeed \blankindeedfalse
-\newif\ifblankreset \blankresetfalse
-\newif\ifblankdisable \blankdisablefalse
-\newif\ifblankflexible \blankflexibletrue
-\newif\ifblankouter
-\newif\ifblankforce
-\newif\ifblankgoback
-
-\newskip\blankskip \blankskip=\bigskipamount
-\newskip\blankskipamount
-
-\def\skipfactor {.75}
-\def\skipgluefactor{.25}
-
-\def\normalskipamount
- {\openlineheight
- \ifgridsnapping \else \ifblankflexible
- \!!plus \skipgluefactor\openlineheight
- \!!minus\skipgluefactor\openlineheight
- \fi \fi
- \relax}
-
-\def\linedistance {\normalskipamount}
-\def\appliedblankskip{\skipfactor\linedistance}
-\def\lastblankskip {\blankskip}
-\def\currentblank {\v!big}
-\def\oldprevdepth {\prevdepth}
-\def\newprevdepth {-1001pt}
-\def\mindimen {1sp} % was: 0.00002pt
-
-\newif\iflocalblankfixed
-\newif\iflocalblankflexible
-
-\def\geenblanko{\removelastskip} % will become obsolete
-
-%%%% pas op, wordt ook in core-pos gebruikt
-
-\def\doassignsomeskip#1\to#2% ook nog \v!halfline+fuzzysnap
- {\doifelse{#1}\v!line
- {#2\openlineheight}
- {\ifgridsnapping
- \assigndimension{#1}{#2}{.25\openlineheight}{.5\openlineheight}\openlineheight
- \else
- \assigndimension{#1}{#2}\smallskipamount\medskipamount\bigskipamount
- \fi}%
- \relax}
-
-% \relax is really needed, else we may loose stretch due to lookahead; somehow
-% this bug was introduced a while ago but somehow went unnoticed; fixed 2/7/2008
-
-\def\addblankskip#1#2#3{\global\advance\blankskip#1\ifgridsnapping#3\else#2\fi\relax}
-
-\def\defineblankmethod[#1]#2{\setvalue{\??bo\??bo#1}{#2}}
-
-\defineblankmethod [\v!big] {\addblankskip+\bigskipamount \openlineheight}
-\defineblankmethod [-\v!big] {\addblankskip-\bigskipamount \openlineheight}
-\defineblankmethod [\v!medium] {\addblankskip+\medskipamount {.5\openlineheight}}
-\defineblankmethod [-\v!medium] {\addblankskip-\medskipamount {.5\openlineheight}}
-\defineblankmethod [\v!small] {\addblankskip+\smallskipamount{.25\openlineheight}}
-\defineblankmethod [-\v!small] {\addblankskip-\smallskipamount{.25\openlineheight}}
-\defineblankmethod [\v!white] {\addblankskip+\parskip \openlineheight}
-\defineblankmethod [-\v!white] {\addblankskip-\parskip \openlineheight}
-\defineblankmethod [\v!line] {\addblankskip+\openlineheight \openlineheight}
-\defineblankmethod [-\v!line] {\addblankskip-\openlineheight \openlineheight}
-
-\defineblankmethod [\v!formula] {\global\advance\blankskip\medskipamount}
-\defineblankmethod [\v!nowhite] {\global\blanknowhitetrue}
-\defineblankmethod [\v!disable] {\global\blankdisabletrue}
-\defineblankmethod [\v!force] {\global\blankforcetrue}
-\defineblankmethod [\v!outer] {\ifvmode\ifinner\blankoutertrue\fi\fi}
-\defineblankmethod [\v!reset] {\global\blankresettrue}
-\defineblankmethod [\v!flexible] {\global\localblankflexibletrue}
-\defineblankmethod [\v!fixed] {\global\localblankfixedtrue}
-\defineblankmethod [\v!back] {\global\blankgobacktrue} % {\geenblanko}
-\defineblankmethod [\v!halfline] {\ifgridsnapping\global\fuzzyvskiptrue\fi
- \global\advance\blankskip .5\lineheight}
-
-\defineblankmethod [\v!none] {\global\blankresettrue}
-\defineblankmethod [\v!joinedup] {\ifvmode\nointerlineskip\fi}
-
-\defineblankmethod [\v!always] {\redowhitespace} % experimental
-
-% happens often, so we speed this up:
-%
-% \defineblankmethod [2*\v!line] {\addblankskip+{2\openlineheight}{2\openlineheight}}
-% \defineblankmethod [2*\v!big] {\addblankskip+{2\bigskipamount }{2\openlineheight}}
-%
-% no, with 2\whatever we loose the stretch and shrink! Taco's alternative:
-
-\defineblankmethod
- [2*\v!line]
- {\addblankskip+\openlineheight\openlineheight
- \addblankskip+\openlineheight\openlineheight}
-
-\defineblankmethod
- [2*\v!big]
- {\addblankskip+\bigskipamount\openlineheight
- \addblankskip+\bigskipamount\openlineheight}
-
-\def\doblank#1%
- {\edefconvertedargument\ascii{#1}%
- \ifx\ascii\empty\else
- \ifcsname\??bo\??bo\ascii\endcsname % internal def
- \csname\??bo\??bo\ascii\endcsname
- \else\ifcsname\??bo\ascii\endcsname % user def / slow
- \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
- \else
- \dorepeatwithcommand[#1]\redoblank
- \fi\fi
- \fi
- \relax}
-
-\def\redoblank#1%
- {\edefconvertedargument\ascii{#1}%
- \ifx\ascii\empty\else
- \ifcsname\??bo\??bo\ascii\endcsname % internal def
- \csname\??bo\??bo\ascii\endcsname
- \else\ifcsname\??bo\ascii\endcsname % user def / slow
- \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
- \else
- \global\advance\blankskip#1\relax
- \fi\fi
- \fi
- \relax}
-
-\unexpanded\def\blank % the \relax is definitely needed due to the many \if's
- {\relax\complexorsimple\doblank}
-
-\def\complexdoblank
- {\flushnotes
- \ifmmode
- \@EA\nocomplexdoblank
- \else
- \ifopelkaar
- \ifinpagebody
- \@EA\@EAEAEA\@EA\docomplexdoblank
- \else
- \@EA\@EAEAEA\@EA\nocomplexdoblank
- \fi
- \else
- \@EAEAEA\docomplexdoblank
- \fi
- \fi}
-
-\def\nocomplexdoblank[#1]%
- {% evt blokkeerfalse
- \ifmmode\else\par\fi}
-
-% Overloaded in cont-new!
-
-\newsignal\noblanksignal
-
-% \def\doinhibitblank
-% {\kern\noblanksignal}
-
-% \def\inhibitblank% the fast, local way
-% {\endgraf\ifvmode\prevdepth\newprevdepth\fi}
-
-% \def\docomplexdoblank[#1]% pas op \relax's zijn nodig ivm volgende \if
-% {\global\blankresetfalse
-% \global\blankdisablefalse
-% \global\blanknowhitefalse
-% \global\localblankflexiblefalse
-% \global\localblankfixedfalse
-% \global\blankskip\zeropoint
-% \global\blankforcefalse
-% \global\blankgobackfalse
-% \blankouterfalse
-% \expanded{\rawprocesscommalist[#1]}\doblank
-% \ifdim\blankskip=\zeropoint\relax
-% \iflocalblankflexible
-% \doglobal\advance\blankskip \currentblank
-% \else\iflocalblankfixed
-% \doglobal\advance\blankskip \currentblank
-% \fi\fi
-% \fi
-% \ifblankouter
-% \else
-% \par
-% \ifvmode
-% \ifblankgoback
-% \removelastskip
-% \fi
-% \ifblankforce
-% % dit gaat mis in pos fonts
-% % \ifdim\prevdepth>\zeropoint\else ...
-% % -1000pt signals top of page or column (\ejectcolumn)
-% \bgroup\forgeteverypar\verticalstrut\egroup\kern-\struttotal
-% \fi
-% \ifblankdisable
-% \global\blankindeedfalse
-% \ifgridsnapping
-% \ifdim\prevdepth<\zeropoint
-% % brrr
-% \else
-% % dirty trick: smaller blanks are ignored after
-% % a larger one, so 10 lines is probably safe; first make
-% % sure that we honor penalties
-% \scratchcounter\lastpenalty
-% % now comes the trick (cross our fingers that this works
-% % well in multi columns; maybe an ifinner test is needed
-% % \vskip-10\lineheight
-% % \ifnum\scratchcounter=\zerocount \else \penalty\lastpenalty \fi
-% % \vskip 10\lineheight
-% % allas, this leads to overfull pages, so we try this:
-% \kern-\noblanksignal
-% \ifnum\scratchcounter=\zerocount
-% \else
-% \penalty\lastpenalty
-% \fi
-% \kern\noblanksignal
-% % end-of-dirty-trick
-% \fi
-% \else
-% \ifdim\prevdepth<\zeropoint
-% % brrr
-% \else
-% % ensure at least a proper prevdepth, this should be
-% % an option
-% \vskip-\prevdepth
-% \vskip\strutdepth
-% \prevdepth\strutdepth
-% \fi
-% % the old crappy piece of code
-% \edef\oldprevdepth{\the\prevdepth}%
-% \prevdepth\newprevdepth
-% \fi
-% \else
-% \global\blankindeedtrue
-% \fi
-% \ifblankreset
-% \global\blankindeedtrue
-% \ifgridsnapping
-% % let's play safe and not fool around with the depth, if
-% % only because it took a lot of effort to sort out the grid
-% % stuff in the first place
-% \else
-% \ifdim\prevdepth=\newprevdepth
-% \prevdepth\oldprevdepth
-% \fi
-% \fi
-% \fi
-% \ifblankindeed
-% \ifdim1\lastskip<1\blankskip\relax
-% % else when \blanko[2*groot] + \blanko[3*groot] with parskip
-% % equaling 1*groot, gives a groot=\parskip so adding a small
-% % value makes it distinguishable; can also be done at parskip
-% % setting time (better)
-% \global\advance\blankskip \mindimen\relax % = skip
-% % test this on 2* + 3* and parskip groot
-% \ifblanknowhite
-% \global\advance\blankskip -\parskip
-% \else
-% \ifdim\lastskip=\parskip
-% \else % force this due to previous comment
-% \ifdim\parskip>\zeropoint\relax
-% \ifdim\blankskip<\parskip\relax
-% \global\blankskip\zeropoint
-% \else
-% \global\advance\blankskip -\parskip
-% \fi
-% \fi
-% \fi
-% \fi
-% \ifblankflexible \else
-% \blankskip1\blankskip
-% \fi
-% \iflocalblankfixed
-% \blankskip1\blankskip
-% \fi
-% \iflocalblankflexible
-% \blankskip1\blankskip
-% \!!plus\skipgluefactor\blankskip
-% \!!minus\skipgluefactor\blankskip
-% \fi
-% \ifdim\lastkern=\noblanksignal % controled and grid
-% \global\blankindeedfalse
-% \else\ifgridsnapping\else\ifdim\prevdepth=\newprevdepth
-% \global\blankindeedfalse
-% \fi\fi\fi
-% \ifblankindeed
-% \iffuzzyvskip
-% \removelastfuzzyvskip
-% \fuzzyvskip\blankskip\relax
-% \else
-% \removelastskip
-% \vskip\blankskip\relax
-% \fi
-% \fi
-% \else
-% \iffuzzyvskip
-% \removelastfuzzyvskip
-% \fuzzyvskip\blankskip\relax
-% \else
-% % new, test this on pascal
-% \ifdim\blankskip<\zeropoint
-% \advance\blankskip-\lastskip
-% \removelastskip
-% \ifdim\blankskip>\zeropoint
-% \vskip\blankskip
-% \else
-% \vskip\zeropoint
-% \fi
-% \else
-% % also new
-% \ifdim\blankskip=\zeropoint
-% \ifblanknowhite
-% \geenwitruimte
-% \fi
-% \fi
-% \fi
-% \fi
-% \fi
-% \fi
-% \fi
-% \fi
-% \global\fuzzyvskipfalse
-% \presetindentation}
-
-% goback was broken:
-
-% \def\doinhibitblank
-% {\kern\noblanksignal}
-
-% \def\inhibitblank% the fast, local way
-% {\endgraf\ifvmode\prevdepth\newprevdepth\fi}
-
-% problem: we cannot look back in the mvl so we need 3 kinds of signals
-
-\def\noblankpsignal{1010101}
-
-\def\inhibitgridblank % was doinhibitblank
- {\ifvmode\else\endgraf\fi
- \ifvmode
- \ifnum\lastpenalty<10000
- \kern-\noblanksignal % new
- \kern \noblanksignal
- \else
- \penalty\noblankpsignal
- \fi
- \fi}
-
-\def\inhibittextblank % was inhibitblank
- {\endgraf
- \ifvmode
- \prevdepth\newprevdepth
- \fi}
-
-% new macro
-%
-% \def\inhibitblank % need some work
-% {\endgraf
-% \ifvmode
-% \ifgridsnapping
-% \inhibitgridblank
-% \else
-% % this one spoils the grid
-% \inhibittextblank
-% \fi
-% \fi}
-
-\def\doinhibitblank{\inhibitgridblank}
-\def\inhibitblank {\inhibittextblank}
-
-% will become obsolete
-
-\ifx\undefined\savedlastskip \newskip \savedlastskip \fi
-\ifx\undefined\savedlastpenalty \newcount\savedlastpenalty \fi
-
-% beware, prevdepth can have funny values (e.g. mvl value when in box)
-
-\def\docomplexdoblank[#1]% pas op \relax's zijn nodig ivm volgende \if
- {\global\blankresetfalse
- \global\blankdisablefalse
- \global\blanknowhitefalse
- \global\localblankflexiblefalse
- \global\localblankfixedfalse
- \global\blankforcefalse
- \global\blankgobackfalse
- \blankouterfalse
- \global\blankskip\zeropoint
-%
-\edefconvertedargument\ascii{#1}% todo fast check for simple
-\ifcsname\??bo\??bo\ascii\endcsname % internal def
- \csname\??bo\??bo\ascii\endcsname
-\else\ifcsname\??bo\ascii\endcsname % user def / slow
- \@EA\rawprocesscommalist\@EA[\csname\??bo\ascii\endcsname]\doblank\relax
-\else
- \expanded{\rawprocesscommalist[#1]}\doblank
-\fi\fi
-%
- \relax % to be sure
- \ifdim\blankskip=\zeropoint\relax
- \iflocalblankflexible
- \doglobal\advance\blankskip \currentblank
- \else\iflocalblankfixed
- \doglobal\advance\blankskip \currentblank
- \fi\fi
- \fi
- \relax % to be sure
- \ifblankouter
- % do nothing
- \else
- \par
- \ifvmode
- \ifblankgoback
- \ifdim\lastskip>\zeropoint \vskip-\lastskip \fi
- \savedlastskip\zeropoint
- \else\ifdim\lastskip>\zeropoint
- \savedlastskip\lastskip
- \else % todo: lastnode, dan namelijk geen skip !
- \savedlastskip\zeropoint
- \fi\fi
- \ifblankforce
- % dit gaat mis in pos fonts
- % \ifdim\prevdepth>\zeropoint\else ...
- % -1000pt signals top of page or column (\ejectcolumn)
- \bgroup\forgeteverypar\verticalstrut\egroup\kern-\struttotal
- \savedlastskip\zeropoint
- \fi
- \savedlastpenalty\lastpenalty % hm, now it gets lost
- \ifblankdisable
- \global\blankindeedfalse % keep this, i.e. disable current too
- \ifgridsnapping
- \ifdim\prevdepth<\zeropoint
- % brrr
- \else
- % dirty trick: smaller blanks are ignored after a
- % larger one, so 10 lines is probably safe; we need
- % to make sure that we honor penalties; here comes the
- % trick (cross our fingers that this works well in
- % multi columns; maybe an ifinner test is needed
- % \scratchcounter\lastpenalty
- % \vskip-10\lineheight
- % \ifnum\scratchcounter=\zerocount \else \penalty\lastpenalty \fi
- % \vskip 10\lineheight
- % alas, this leads to overfull pages, so we try this:
- \inhibitgridblank
- \fi
- \else
- \ifdim\prevdepth<\zeropoint
- % brrr
- \else
- % ensure at least a proper prevdepth, this should be
- % an option
- \vskip-\prevdepth
- \vskip\strutdepth
- \prevdepth\strutdepth
- \fi
- % the old crappy piece of code
- \edef\oldprevdepth{\the\prevdepth}%
- \prevdepth\newprevdepth % == \inhibittextblank
- \fi
- \else
- \global\blankindeedtrue
- \fi
- \ifblankreset
- \global\blankindeedtrue
- \ifgridsnapping
- % let's play safe and not fool around with the depth, if
- % only because it took a lot of effort to sort out the grid
- % stuff in the first place
- \else
- \ifdim\prevdepth=\newprevdepth
- \prevdepth\oldprevdepth
- \fi
- \fi
- \fi
- \ifblankindeed
- \ifdim1\savedlastskip<1\blankskip\relax
- % else when \blank[2*groot] + \blank[3*groot] with parskip
- % equaling 1*groot, gives a groot=\parskip so adding a small
- % value makes it distinguishable; can also be done at parskip
- % setting time (better)
- \global\advance\blankskip \mindimen\relax % = skip
- % test this on 2* + 3* and parskip groot
- \ifblanknowhite
- \global\advance\blankskip -\parskip
- \else
- \ifdim\savedlastskip=\parskip
- \else % force this due to previous comment
- \ifdim\parskip>\zeropoint\relax
- \ifdim\blankskip<\parskip\relax
- \global\blankskip\zeropoint
- \else
- \global\advance\blankskip -\parskip
- \fi
- \fi
- \fi
- \fi
- \ifblankflexible \else
- \blankskip1\blankskip
- \fi
- \iflocalblankfixed
- \blankskip1\blankskip
- \fi
- \iflocalblankflexible
- \blankskip1\blankskip
- \!!plus \skipgluefactor\blankskip
- \!!minus\skipgluefactor\blankskip
- \fi
- \ifdim\lastkern=\noblanksignal\relax % controlled and grid
- \global\blankindeedfalse
- \else\ifnum\savedlastpenalty=\noblankpsignal\relax % controlled and grid
- \global\blankindeedfalse
- \else\ifgridsnapping\else\ifdim\prevdepth=\newprevdepth
- \global\blankindeedfalse
- \fi\fi\fi\fi
- \ifblankindeed
- \iffuzzyvskip
- \removelastfuzzyvskip
- \fuzzyvskip\blankskip\relax
- \else
- \relax\ifdim\savedlastskip=\zeropoint\else
- \vskip-\savedlastskip
- \fi
- \vskip\blankskip\relax
- \fi
- \fi
- \else
- \iffuzzyvskip
- \removelastfuzzyvskip
- \fuzzyvskip\blankskip\relax
- \else
- % new, test this on pascal
- \ifdim\blankskip<\zeropoint
- \relax\ifdim\savedlastskip=\zeropoint\else
- \advance\blankskip-\savedlastskip
- \vskip-\savedlastskip
- \fi
- \ifdim\blankskip>\zeropoint
- \vskip\blankskip
- \else
- \vskip\zeropoint
- \fi
- \else
- % also new
- \ifdim\blankskip=\zeropoint
- \ifblanknowhite
- \nowhitespace
- \fi
- \fi
- \fi
- \fi
- \fi
- \fi
- \fi
- \fi
- \global\fuzzyvskipfalse
- \presetindentation}
-
-%D For a long time we had:
-%D
-%D \starttyping
-%D \def\simpledoblank%
-%D {\doifelse{\currentwhitespace}{\v!geen}
-%D {\blank[\currentblank]}
-%D {\blank[\currentwhitespace]}}
-%D \stoptyping
-%D
-%D But Berend de Boer wanted more control, so now we have:
-
-\def\simpledoblank % ...
- {\doifelse\currentwhitespace\v!none
- {\blank[\currentblank]}
- {\blank[\s!default]}}
-
-%D Another useful definition would be:
-%D
-%D \starttyping
-%D \defineblank
-%D [\s!default]
-%D [\v!groot]
-%D \stoptyping
-
-\def\dosetupblank#1% amount are an plain inheritance
- {\bigskipamount#1\relax
- \ifblankflexible \else
- \bigskipamount1\bigskipamount
- \fi
- \medskipamount \bigskipamount \divide\medskipamount \plustwo
- \smallskipamount\bigskipamount \divide\smallskipamount\plusfour}%
-
-\def\complexsetupblank[#1]% more \let's -> this also wil become installable
- {\ifgridsnapping
- \blankflexiblefalse
- \else
- \ExpandFirstAfter\processallactionsinset
- [#1]
- [ \v!flexible=>\blankflexibletrue,
- \v!fixed=>\blankflexiblefalse]%
- \fi
- \ExpandFirstAfter\processallactionsinset
- [#1]
- [ \v!flexible=>\dosetupblank\appliedblankskip,
- \v!fixed=>\dosetupblank\appliedblankskip,
- \v!line=>\edef\appliedblankskip{\linedistance}%
- \dosetupblank\appliedblankskip,
- \v!halfline=>\scratchskip.5\linedistance
- \edef\appliedblankskip{\the\scratchskip}%
- \dosetupblank\appliedblankskip,
- \v!big=>\ifgridsnapping
- \edef\appliedblankskip{\linedistance}%
- \dosetupblank\appliedblankskip
- \fi
- \let\currentblank\v!big,
- \v!medium=>\let\currentblank\v!medium,
- \v!small=>\let\currentblank\v!small,
- \v!global=>\let\currentblank\v!global,
- \v!normal=>\dosetupblank\appliedblankskip,
- \v!standard=>\edef\appliedblankskip{\skipfactor\linedistance}%
- \dosetupblank\appliedblankskip,
- \s!default=>\dosetupblank\appliedblankskip,
- \s!unknown=>\let\appliedblankskip\commalistelement
- \dosetupblank\appliedblankskip]%
- \simplesetupwhitespace}
-
-% \definecomplexorsimpleempty\setupblank
-%
-% speed gain: 60 sec -> 30 sec
-
-\definecomplexorsimple\setupblank
-
-\def\simplesetupblank % == snelle \setupblank[\s!default]
- {\ifgridsnapping
- \blankflexiblefalse
- \fi
- \dosetupblank\appliedblankskip
- % \let\deblanko\v!big
- \simplesetupwhitespace}
-
-\def\restorestandardblank% \v!standard
- {\edef\appliedblankskip{\skipfactor\linedistance}%
- \dosetupblank\appliedblankskip
- }%\let\deblanko\v!big}
-
-\def\dodefineblank[#1][#2]%
- {\def\docommand##1{\setvalue{\??bo##1}{#2}}%
- \processcommalist[#1]\docommand}
-
-\def\defineblank
- {\dodoubleargument\dodefineblank}
-
-\def\savecurrentblank
- {\edef\restorecurrentblank
- {\bigskipamount\the\bigskipamount
- \medskipamount\the\medskipamount
- \smallskipamount\the\smallskipamount
- \noexpand\def\noexpand\currentblank{\currentblank}%
- \ifblankflexible
- \noexpand\blankflexibletrue
- \else
- \noexpand\blankflexiblefalse
- \fi}}
-
-%D Now.
-
-\defineblank [\s!default] [\v!white]
-\defineblank [\v!height] [\strutheight]
-\defineblank [\v!depth] [\strutdepth]
-
-% old implementation
-%
-% \let\currentindentation=\empty
-%
-% \newdimen\ctxparindent
-%
-% \newif\ifindentfirstparagraph % \indentfirstparagraphtrue
-%
-% \def\presetindentation
-% {\doifoutervmode{\ifindentfirstparagraph\else\noindentation\fi}}
-%
-% \definecomplexorsimple\setupindenting
-%
-% \def\complexsetupindenting[#1]%
-% {\processallactionsinset
-% [#1]
-% [ \v!first=>\indentfirstparagraphtrue,
-% \v!next=>\indentfirstparagraphfalse,
-% \s!default=>\simplesetupindenting,
-% \s!unknown=>\edef\currentindentation{\commalistelement}%
-% \simplesetupindenting]}
-%
-% \def\simplesetupindenting
-% {\assigndimension\currentindentation\ctxparindent{1em}{1.5em}{2em}%
-% \parindent\ctxparindent\relax}
-%
-% \def\indenting % watch out: \dodo and no \do
-% {\dosingleargument\dodoindenting}
-%
-% \def\dodoindenting[#1]% oeps, we needed a commalist handler here!
-% {\edef\currentindenting{#1}%
-% \processcommacommand[#1]\dododoindenting}
-%
-% \def\dododoindenting#1%
-% {\executeifdefined{\??in:#1}\donothing}
-%
-% \let\currentindenting\empty
-%
-% \def\defineindentingmethod[#1]#2%
-% {\setvalue{\??in:#1}{#2}}
-%
-% \defineindentingmethod [\v!no] {\parindent\ctxparindent\noindent}
-% \defineindentingmethod [\v!not] {\parindent\ctxparindent\noindent}
-%
-% \defineindentingmethod [\v!first] {\indentfirstparagraphtrue}
-% \defineindentingmethod [\v!next] {\indentfirstparagraphfalse}
-%
-% \defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent !
-% \defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent !
-%
-% \defineindentingmethod [\v!never] {\parindent\zeropoint\relax} % no \indent !
-%
-% \def\noindenting{\indenting[\v!no,\v!next]} % was \nietinspringen
-% \def\doindenting{\indenting[\v!yes,\v!first]} % was \welinspringen
-%
-% \def\dochecknextindentation#1% internal one
-% {\checknextindentation[\getvalue{#1\c!indentnext}]}
-%
-% \def\checknextindentation[#1]%
-% {\processaction[#1][%\v!keep=>,
-% \v!yes=>\doindentation,
-% \v!no=>\noindentation,
-% \v!auto=>\autoindentation]}
-%
-% \def\doindentation% too simple
-% {\gdef\checkindentation{\global\indentationtrue}}
-%
-% \ifx\autoindentation\undefined
-% \let\autoindentation\relax
-% \fi
-%
-% \newif\ifindentation \indentationtrue % documenteren, naar buiten
-%
-% \let\checkindentation=\relax
-%
-% \def\donoindentation
-% {\ifdim\parindent=\zeropoint \else
-% \bgroup \setbox\scratchbox\lastbox \egroup
-% \fi}
-%
-% \def\noindentation % made global
-% {\ifinpagebody \else
-% \global\indentationfalse
-% \gdef\checkindentation
-% {\donoindentation
-% \gdef\checkindentation{\global\indentationtrue}}%
-% \fi}
-%
-% \def\nonoindentation % bv bij floats
-% {\ifinpagebody \else
-% \global\indentationtrue
-% \gdef\checkindentation{\global\indentationtrue}%
-% \fi}
-%
-% \def\indentation
-% {\ifvmode \ifdim\parindent=\zeropoint \else
-% % was : \hskip\parindent
-% % can be: \indent
-% % but we test:
-% \noindent\hskip\parindent
-% \fi \fi}
-
-\let\currentindentation\empty % amount/keyword
-% \let\normalindentation \empty % used for reinstating normal indentation
-\let\currentindenting \empty % method
-
-\newdimen\ctxparindent
-
-\newif\ifindentfirstparagraph % \indentfirstparagraphtrue
-
-\chardef\indentingtoggle\zerocount
-
-%D After a blank or comparable situation (left side floats) we
-%D need to check if the next paragraph has to be indented.
-
-\def\presetindentation
- {\doifoutervmode{\ifindentfirstparagraph\else\noindentation\fi}}
-
-%D This sets up the (normally) global indentation behavior as well
-%D as the amounts.
-
-\definecomplexorsimple\setupindenting
-
-% \def\complexsetupindenting[#1]%
-% {\edef\currentindenting{#1}%
-% \indentfirstparagraphtrue
-% \parindent\ctxparindent
-% \chardef\indentingtoggle\zerocount
-% \processcommalist[#1]\docomplexsetupindenting
-% \ifindentfirstparagraph\else\noindentation\fi % added
-% \toggleindentation}
-
-\indentfirstparagraphtrue
-\parindent\ctxparindent
-\chardef\indentingtoggle\zerocount
-
-% \newtoks\savedeverypar \savedeverypar\everypar
-% \def\restoreeverypar{\everypar\savedeverypar}
-
-% we need a better everypar model: for each option a switch, which we
-% set to false with \forgetall and can enable when needed (context 4);
-% that way we can control the order of execution of options
-
-\def\checkeverypar % currently a hack
- {\ifzeropt\parindent\else
- \doifsometokselse\everypar\donothing{\appendtoks\checkindentation\to\everypar}%
- \fi}
-
-\def\complexsetupindenting[#1]%
- {\edef\currentindenting{#1}%
- \doifsomething\currentindenting % handy when a parameter is passed
- {% not here: \indentfirstparagraphtrue
- % not here: \parindent\ctxparindent
- % not here: \chardef\indentingtoggle\zerocount
- % we use commacommand in order to catch #1 being a command (expanded parameter)
- \processcommacommand[\currentindenting]\docomplexsetupindentingA % catch small, medium, etc
- \processcommacommand[\currentindenting]\docomplexsetupindentingB % catch rest
- \checkeverypar % only when non-empty #1
- \ifindentfirstparagraph\else\noindentation\fi % added
- \toggleindentation}}
-
-\def\docomplexsetupindentingA#1%
- {\edefconvertedargument\!!stringa{#1}%
- \doifundefined{\??in:\!!stringa}%
- {\edef\currentindentation{#1}%
- \let\normalindentation\currentindentation
- \simplesetupindenting}}
-
-\def\docomplexsetupindentingB#1%
- {\edefconvertedargument\!!stringa{#1}% catch #1=\somedimen
- \executeifdefined{\??in:\!!stringa}\donothing}
-
-\def\simplesetupindenting % empty case, a it strange, needed this way?
- {\assigndimension\currentindentation\ctxparindent{1em}{1.5em}{2em}}
-
-\def\indenting % kind of obsolete
- {\dosingleargument\complexsetupindenting}
-
-% use \noindentation to suppress next indentation
-
-\def\defineindentingmethod[#1]#2%
- {\setvalue{\??in:#1}{#2}}
-
-\defineindentingmethod [\v!no] {\parindent\zeropoint}% was: \ctxparindent\noindent}
-\defineindentingmethod [\v!not] {\parindent\zeropoint}% was: \ctxparindent\noindent}
-
-\defineindentingmethod [\v!first] {\indentfirstparagraphtrue}
-\defineindentingmethod [\v!next] {\indentfirstparagraphfalse}
-
-\defineindentingmethod [\v!yes] {\parindent\ctxparindent\relax} % no \indent !
-\defineindentingmethod [\v!always] {\parindent\ctxparindent\relax} % no \indent !
-
-\defineindentingmethod [\v!never] {\parindent\zeropoint\relax % no \indent !
- \chardef\indentingtoggle\zerocount}
-
-\defineindentingmethod [\v!odd] {\chardef\indentingtoggle\plusone}
-\defineindentingmethod [\v!even] {\chardef\indentingtoggle\plustwo}
-
-\defineindentingmethod [\v!normal] {\ifx\normalindentation\empty\else
- \let\currentindentation\normalindentation
- \simplesetupindenting
- \fi}
-
-\defineindentingmethod [\v!reset] {\indentfirstparagraphtrue
- \parindent\zeropoint
- \chardef\indentingtoggle\zerocount}
-
-\def\noindenting{\indenting[\v!no, \v!next ]}
-\def\doindenting{\indenting[\v!yes,\v!first]}
-
-%D This one sets up the local indentation behaviour (i.e. either or not
-%D a next paragraph will be indented).
-
-\def\dochecknextindentation#1% internal one
- {\checknextindentation[\getvalue{#1\c!indentnext}]}
-
-\def\checknextindentation[#1]%
- {\processaction
- [#1]
- [%\v!keep=>,
- \v!yes=>\doindentation,
- \v!no=>\noindentation,
- \v!auto=>\autoindentation]}
-
-%D Here come the handlers.
-
-\newif\ifindentation \indentationtrue % documenteren, naar buiten
-
-\let\checkindentation\relax
-
-\ifx\autoindentation\undefined \let\autoindentation\relax \fi % hook
-
-\def\doindentation
- {\gdef\checkindentation{\global\indentationtrue}}
-
-\def\noindentation % made global
- {\ifinpagebody \else
- \global\indentationfalse
- \gdef\checkindentation
- {\donoindentation
- \gdef\checkindentation{\global\indentationtrue}}%
- \fi}
-
-\def\nonoindentation % bv bij floats
- {\ifinpagebody \else
- \global\indentationtrue
- \gdef\checkindentation{\global\indentationtrue}%
- \fi}
-
-\def\donoindentation
- {\ifdim\parindent=\zeropoint \else
- \bgroup \setbox\scratchbox\lastbox \egroup
- \fi}
-
-\def\indentation
- {\ifvmode \ifdim\parindent=\zeropoint \else
- % was : \hskip\parindent
- % can be: \indent
- % but we test:
- \noindent\hskip\parindent
- \fi \fi}
-
-\def\toggleindentation
- {\ifcase\indentingtoggle
- % nothing
- \or
- \notoggleindentation
- \or
- \dotoggleindentation
- \fi}
-
-\def\dokillindentation
- {\gdef\checkindentation{\global\indentationfalse\donoindentation}}
-
-\def\dotoggleindentation
- {\gdef\checkindentation{\global\indentationfalse\notoggleindentation\donoindentation}}
-
-\def\notoggleindentation
- {\gdef\checkindentation{\global\indentationtrue\dotoggleindentation}}
-
-\appendtoks
- \pushmacro\checkindentation
- \pushmacro\ifindentation
-\to \everypushsomestate
-
-\appendtoks
- \popmacro\ifindentation
- \popmacro\checkindentation
-\to \everypopsomestate
-
-% we need to save the state if we want to adapt behaviour to empty lines
-%
-% \def\setlasthvmode
-% {\global\chardef\savedhvmode\ifhmode\plusone\else\ifvmode\plustwo\else\zerocount\fi\fi}
-%
-% \def\resetlasthvmode
-% {\global\chardef\savedhvmode\zerocount}
-%
-% \chardef\savedhvmode\zerocount
-
-% This is a user requested hack (using the auto-hook).
-
-\chardef\recheckindentationmode\zerocount
-
-\def\dontrechecknextindentation
- {\global\chardef\recheckindentationmode\zerocount}
-
-\def\dorechecknextindentation
- {\ifcase\recheckindentationmode
- % nothing
- \or
- \dontrechecknextindentation
- \expandafter\doautoindentation
- \fi}
-
-\def\doautoindentation
- {\doifnextcharelse\par\donothing\noindentation}
-
-\def\autoindentation
- {\global\chardef\recheckindentationmode\plusone}
-
-%D An example of usage:
-%D
-%D \starttyping
-%D \setupindenting[small,yes]
-%D
-%D \setupitemize [indentnext=auto]
-%D \setuptyping [indentnext=auto]
-%D \setupformulas[indentnext=auto]
-%D
-%D \input tufte
-%D
-%D \startitemize
-%D \item itemize
-%D \stopitemize
-%D \input tufte
-%D
-%D \startitemize
-%D \item itemize
-%D \stopitemize
-%D
-%D \input tufte
-%D
-%D \startitemize
-%D \item itemize
-%D \stopitemize
-%D
-%D \page
-%D
-%D \input tufte
-%D
-%D \starttyping
-%D verbatim
-%D \stoptyping
-%D \input tufte
-%D
-%D \starttyping
-%D verbatim
-%D \stoptyping
-%D
-%D \input tufte
-%D
-%D \starttyping
-%D verbatim
-%D \stoptyping
-%D
-%D \page
-%D
-%D \input tufte
-%D
-%D \startformula
-%D a = b
-%D \stopformula
-%D \input tufte
-%D
-%D \startformula
-%D a = b
-%D \stopformula
-%D
-%D \input tufte
-%D
-%D \startformula
-%D a = b
-%D \stopformula
-
-% \frenchspacing leidt soms tot afbreken tussen -, vandaar
-% de variant \newfrenchspacing.
-
-\def\frenchspacing {\setfrenchspacing{1000}}
-\def\newfrenchspacing{\setfrenchspacing{1050}}
-\def\nonfrenchspacing{\resetfrenchspacing}
-
-\def\definespacingmethod[#1]#2{\setvalue{\??sg\??sg#1}{#2}}
-
-\definespacingmethod[\v!packed]{\newfrenchspacing}
-\definespacingmethod[\v!broad ]{\nonfrenchspacing}
-
-\def\complexsetupspacing[#1]%
- {\executeifdefined{\??sg\??sg#1}\relax
- \updateraggedskips}
-
-\def\simplesetupspacing
- {\updateraggedskips}
-
-\definecomplexorsimple\setupspacing
-
-% \dorecurse{100}{\recurselevel\spacefactor 800 \space} \par
-% \dorecurse{100}{\recurselevel\spacefactor1200 \space} \par
-% \dorecurse{100}{\recurselevel\spacefactor 800 \normalspaceprimitive} \par
-% \dorecurse{100}{\recurselevel\spacefactor1200 \normalspaceprimitive} \par
-
-% When we don't add the % here, we effectively get \<endlinechar> and
-% since we have by default \def\^^M{\ } we get into a loop.
-
-\let\normalspaceprimitive=\ % space-comment is really needed
-
-\unexpanded\def\ {\mathortext\normalspaceprimitive\space} % no \dontleavehmode\space (else no frenchspacing)
-
-\unexpanded\def\nonbreakablespace{\penalty\plustenthousand\space}
-
-\letcatcodecommand \ctxcatcodes `\~ \nonbreakablespace % overloaded later
-
-\def\space { }
-\def\removelastspace{\ifhmode\unskip\fi}
-\def\nospace {\removelastspace\ignorespaces}
-
-% in tables we need:
-%
-% \def\fixedspace {\hskip.5em\relax}
-%
-% but, since not all fonts have .5em digits:
-
-\unexpanded\def\fixedspace
- {\setbox\scratchbox\normalhbox{\mathortext{0}{0}}%
- \hskip\wd\scratchbox\relax}
-
-\def\fixedspaces
- {\letcatcodecommand \ctxcatcodes `\~ \fixedspace}
-
-\def\removeunwantedspaces
- {\ifhmode % we also need to unskip 0pt skips
- \unskip\unskip\unskip\unskip\unskip
- \unskip\unskip\unskip\unskip\unskip
- \fi}
-
-\appendtoks\let~\space\to\simplifiedcommands
-
-% still not fixed in aleph / luatex
-%
-% \def\removeunwantedspaces
-% {\ifhmode \ifnum\lastnodetype=\@@gluenode
-% \unskip \@EAEAEA\removeunwantedspaces
-% \fi \fi}
-
-%D For old time sake, will disappear soon.
-
-\let\hardespatie\fixedspace
-\let\geenspatie \nospace
-
-% \startbuffer
-% \startlines \tt \fixedspaces
-% 0~1~~2~~~3~~~~4~~~~~5
-% 0~~~~~~~~~~~~~~~~~~~5
-% $0~1~~2~~~3~~~~4~~~~~5$
-% $0~~~~~~~~~~~~~~~~~~~5$
-% \stoplines
-%
-% \starttabulate[|~|]
-% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \NR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \NR
-% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \NR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \NR
-% \stoptabulate
-%
-% \starttable[||]
-% \NC 0~1~~2~~~3~~~~4~~~~~5 \NC \AR \NC 0~~~~~~~~~~~~~~~~~~~5 \NC \AR
-% \NC $0~1~~2~~~3~~~~4~~~~~5$ \NC \AR \NC $0~~~~~~~~~~~~~~~~~~~5$ \NC \AR
-% \stoptable
-% \stopbuffer
-%
-% \setupbodyfont[cmr] \getbuffer
-% \setupbodyfont[lbr] \getbuffer
-
-\def\packed
- {\nointerlineskip}
-
-\def\godown[#1]%
- {\relax
- \ifhmode\endgraf\fi
- \ifvmode\nointerlineskip\vskip#1\relax\fi}
-
-%D A couple of plain macros:
-
-\ifx\thinspace\undefined
-
- \def\thinspace {\kern .16667em }
- \def\negthinspace{\kern-.16667em }
- \def\enspace {\kern .5em }
-
- \def\thinspace {\kern .16667\fontdimen6\font}
- \def\negthinspace{\kern-.16667\fontdimen6\font}
- \def\enspace {\kern .5\fontdimen6\font}
-
-\fi
-
-\ifx\quad\undefined
-
- \def\enskip{\hskip.5em\relax}
- \def\quad {\hskip 1em\relax}
- \def\qquad {\hskip 2em\relax}
-
- \def\enskip{\hskip.5\fontdimen6\font}
- \def\quad {\hskip \fontdimen6\font} % faster
- \def\qquad {\hskip 2\fontdimen6\font}
-
-\fi
-
-\let\emspace\quad
-
-\ifx\smallskip\undefined
-
- \def\smallskip{\vskip\smallskipamount}
- \def\medskip {\vskip\medskipamount}
- \def\bigskip {\vskip\bigskipamount}
-
-\fi
-
-\ifx\allowbreak\undefined
-
- \def\break {\penalty\ifhmode-\plustenthousand\else\ejectpenalty\fi}
- \def\nobreak {\penalty \plustenthousand}
- \def\allowbreak{\penalty \zeropoint}
- \def\filbreak {\par\vfil\penalty-200\vfilneg}
- \def\goodbreak {\par\penalty-500 }
-
-\fi
-
-%D Made slightly more readable:
-
-\ifx\vglue\undefined
-
- \def\vglue {\afterassignment\dovglue\scratchskip=}
- \def\hglue {\afterassignment\dohglue\scratchskip=}
- \def\topglue{\nointerlineskip\vglue-\topskip\vglue}
-
- \def\dovglue
- {\par
- \scratchdimen\prevdepth
- \hrule\!!height\zeropoint
- \nobreak\vskip\scratchskip
- \prevdepth\scratchdimen}
-
- \def\dohglue
- {\dontleavehmode % \leavevmode
- \scratchcounter\spacefactor
- \vrule\!!width\zeropoint
- \nobreak\hskip\scratchskip
- \spacefactor\scratchcounter}
-
-\fi
-
-\ifx\eject\undefined
-
- \def\eject{\par\break}
-
-\fi
-
-\ifx\supereject\undefined
-
- \def\supereject{\par\penalty\superpenalty}
-
-\fi
-
-\ifx\dosupereject\undefined
-
- \def\dosupereject
- {\ifnum\insertpenalties>\z@ % something is being held over
- \line{}
- \kern-\topskip
- \nobreak
- \vfill\supereject
- \fi}
-
-\fi
-
-%D We adapt plain's \type {\removelastskip} a bit:
-
-\ifx\removelastskip\undefined
-
- \def\removelastskip
- {\ifvmode \ifdim\lastskip=\zeropoint \else
- \vskip-\lastskip
- \fi \fi}
-
-\fi
-
-\ifx\smallbreak\undefined
-
-\def\smallbreak
- {\par
- \ifdim\lastskip<\smallskipamount
- \removelastskip
- \penalty-50
- \smallskip
- \fi}
-
-\def\medbreak
- {\par
- \ifdim\lastskip<\medskipamount
- \removelastskip
- \penalty-100
- \medskip
- \fi}
-
-\def\bigbreak
- {\par
- \ifdim\lastskip<\bigskipamount
- \removelastskip
- \penalty-200
- \bigskip
- \fi}
-
-\fi
-
-\newskip\ctxparskip \ctxparskip\zeropoint
-
-\newconditional \flexiblewhitespace \settrue\flexiblewhitespace
-
-\def\blankokleinmaat {\smallskipamount}
-\def\blankomiddelmaat {\medskipamount}
-\def\blankogrootmaat {\bigskipamount}
-\def\currentwhitespace {\zeropoint}
-
-\definecomplexorsimple\setupwhitespace
-
-% \def\simplesetupwhitespace
-% {\doifnot\currentwhitespace\v!none\dosetupwhitespace}
-%
-% \def\complexsetupwhitespace[#1]%
-% {\doifelsenothing{#1}
-% {\simplesetupwhitespace}
-% {\edef\currentwhitespace{#1}%
-% \dosetupwhitespace}}
-%
-% \def\dosetupwhitespace
-% {\processcommacommand[\currentwhitespace]\dowhitespacemethod
-% \dodosetupwhitespace}
-
-\def\simplesetupwhitespace
- {\doifnot\currentwhitespace\v!none\dosetupwhitespace}
-
-\def\complexsetupwhitespace[#1]%
- {\edef\nextcurrentwhitespace{#1}%
- \ifx\nextcurrentwhitespace\empty
- \simplesetupwhitespace
- \else
- \let\currentwhitespace\nextcurrentwhitespace
- \dosetupwhitespace
- \fi}
-
-\def\dosetupwhitespace % quick test for no list
- {\ifcsname\??ws\??ws\currentwhitespace\endcsname
- \csname\??ws\??ws\currentwhitespace\endcsname
- \else
- \expandafter\processcommalist\expandafter[\currentwhitespace]\dowhitespacemethod % can be raw
- \fi\relax
- \ifgridsnapping
- \setfalse\flexiblewhitespace
- \ifdim\ctxparskip>\zeropoint
- \ctxparskip
- \ifcase\baselinegridmode
- \baselineskip % normal ! ! ! ! !!
- \or
- \ifdim\scratchdimen=\baselineskip % maybe range
- \baselineskip % normal ! ! ! ! !!
- \else
- \numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
- \fi
- \else
- \baselineskip % normal ! ! ! ! !!
- \fi
- \fi
- \else
- \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
- \fi
- \parskip\ctxparskip}
-
-\chardef\baselinegridmode=0 % option in layout / 1=permit_half_lines
-
-\def\dodosetupwhitespace
- {\ifgridsnapping
- \setfalse\flexiblewhitespace
- \ctxparskip1\ctxparskip
- \ifdim\ctxparskip>\zeropoint
- \ifcase\baselinegridmode
- \ctxparskip\baselineskip % normal ! ! ! ! !!
- \or
- \ifdim\scratchdimen=\baselineskip % maybe range
- \ctxparskip\baselineskip % normal ! ! ! ! !!
- \else
- \ctxparskip\numexpr\ctxparskip/\dimexpr.5\lineheight\relax\relax\dimexpr.5\lineheight\relax
- \fi
- \else
- \ctxparskip\baselineskip % normal ! ! ! ! !!
- \fi
- \fi
- \else
- \ifconditional\flexiblewhitespace \else \ctxparskip1\ctxparskip \fi
- \fi
- \parskip\ctxparskip}
-
-\definesystemvariable {ws} % whitespace
-
-\def\definewhitespacemethod[#1]#2{\setvalue{\??ws\??ws#1}{#2}}
-
-\definewhitespacemethod [\v!fix] {}
-\definewhitespacemethod [\v!fixed] {\setfalse\flexiblewhitespace}
-\definewhitespacemethod [\v!flexible] {\settrue\flexiblewhitespace}
-\definewhitespacemethod [\v!line] {\ctxparskip \baselineskip}
-\definewhitespacemethod [\v!halfline] {\ctxparskip.5\baselineskip}
-\definewhitespacemethod [\v!none] {\ctxparskip \zeropoint}
-\definewhitespacemethod [\v!big] {\ctxparskip \bigskipamount}
-\definewhitespacemethod [\v!medium] {\ctxparskip \medskipamount}
-\definewhitespacemethod [\v!small] {\ctxparskip \smallskipamount}
-
-\definewhitespacemethod [\s!default] {\simplesetupwhitespace} % {\stelwitruimteopnieuwin}
-
-% \def\dowhitespacemethod#1%
-% {\executeifdefined{\??ws\??ws#1}{\ctxparskip#1}\relax}
-
-\def\dowhitespacemethod#1%
- {\ifcsname\??ws\??ws#1\endcsname\csname\??ws\??ws#1\endcsname\else\ctxparskip#1\fi\relax}
-
-\def\nowhitespace
- {\ifdim\parskip>\zeropoint\relax
- \ifdim\lastskip=-\parskip
- \else
- \vskip-\parskip
- \fi
- \fi}
-
-\def\nowhitespaceunlessskip
- {\ifdim\lastskip>\zeropoint \else
- \nowhitespace
- \fi}
-
-\def\redowhitespace
- {\ifdim\lastskip>-\parskip \else
- \vskip\parskip
- \fi}
-
-\def\savecurrentwhitespace
- {\edef\restorecurrentwhitespace
- {\ctxparskip\the\ctxparskip
- \parskip\the\parskip
- \noexpand\def\noexpand\currentwhitespace{\currentwhitespace}%
- \ifconditional\flexiblewhitespace
- \noexpand\settrue\flexiblewhitespace
- \else
- \noexpand\setfalse\flexiblewhitespace
- \fi}}
-
-% deze variant is nodig binnen \startopelkaar
-% steeds testen:
-%
-% \hoofdstuk{..}
-% \plaatslijst[..]
-% \hoofdstuk{..}
-% \input tufte
-%
-% met/zonder witruimte
-
-\def\whitespace
- {\par
- \ifdim\parskip>\zeropoint\relax
- %\ifdim\lastskip>\parskip \else
- % \removelastskip interferes with blanko blokkeer en klein
- \vskip\parskip
- %\fi
- \fi}
-
-\def\nonoblanko[#1]%
- {\par}
-
-\def\noblanko
- {\dosingleempty\nonoblanko}
-
-% De onderstaande macro handelt ook de situatie dat er geen
-% tekst tussen \start ... \stop is geplaatst. Daartoe wordt de
-% laatste skip over de lege tekst heen gehaald. Dit komt goed
-% van pas bij het plaatsen van (mogelijk lege) lijsten.
-
-\newif\ifopelkaar
-
-\newsignal \noparskipsignal % \def\noparskipsignal {0.00001pt}
-\def\lastdoneparskip {0pt}
-
-\def\startpacked
- {\dosingleempty\dostartpacked}
-
-\def\dostartpacked[#1]% nesting afvangen
- {\par
- \ifvmode
- \edef\lastdoneparskip {\the\lastskip}%
- \edef\lastdoneprevdepth{\the\prevdepth}% zeer recent toegevoegd
- \ifdim\prevdepth=-\thousandpoint % toegevoegd omdat binnen
- \else % een vbox een extra skip
- \whitespace % ongewenst is; dit kan
- \baselinecorrection %% zie in \placeregister[n=1]
- \vskip\noparskipsignal % waarschijnlijk ook in
- \fi % blanko blokkeer
- \bgroup
- \doifelse{#1}\v!blank
- \opelkaarfalse
- \opelkaartrue
- \blank[\v!disable] % dit is nog niet ok, gaat fout
- \setupwhitespace[\v!none] % bovenin vtop (dwz, baseline)
- \fi}
-
-\def\stoppacked
- {\par
- \ifvmode
- \egroup
- \ifdim\lastskip=\noparskipsignal\relax
- \removelastskip
- \nowhitespace
- \vskip-\lastdoneparskip
- \vskip+\lastdoneparskip
- \prevdepth-\lastdoneprevdepth % zeer recent toegevoegd
- \fi
- \fi}
-
-\def\startunpacked
- {\blank
- \leavevmode
- \bgroup}
-
-\def\stopunpacked
- {\egroup
- \blank}
-
-% De onderstaande macro's moeten nog eens nader worden uitgewerkt.
-% Ze spelen een rol bij de spatiering rond omkaderde teksten
-% en/of boxen zonder diepte.
-
-\def\toonregelcorrectie{\showbaselinecorrection}
-\def\regelcorrectie {\baselinecorrection}
-
-% \prevdepth crosses pageboundaries!
-%
-% todo: a version that works ok inside a box
-
-\let\doaroundlinecorrection\relax
-
-\def\startlinecorrection
- {\dodoubleempty\dostartlinecorrection}
-
-\def\dostartlinecorrection[#1][#2]% #2 gobbles spaces
- {\bgroup
- \processaction
- [#1]
- [ \v!blank=>\let\doaroundlinecorrection\blank,
- \s!default=>\let\doaroundlinecorrection\relax,
- \s!unknown=>{\def\doaroundlinecorrection{\blank[#1]}}]%
- \doaroundlinecorrection
- \startbaselinecorrection
- \offbaselinecorrection
- \ignorespaces}
-
-\def\stoplinecorrection
- {\stopbaselinecorrection
- \doaroundlinecorrection
- \egroup}
-
-\def\correctwhitespace
- {\dowithnextbox
- {\startbaselinecorrection
- \flushnextbox
- \stopbaselinecorrection}%
- \vbox}
-
-\def\verticalstrut {\normalvbox{\hsize\zeropoint\forgetall\strut}}
-\def\horizontalstrut{\normalhbox {\strut}}
-
-% Hieronder volgen enkele instellingen en macro's ten behoeve
-% van de interlinie en \strut. De waarden 2.8, 0.07, 0.72 en
-% 0.28 zijn ooit eens ontleend aan INRS-TEX en moeten wellicht
-% nog eens instelbaar worden.
-%
-% \lineheight : de hoogte van een regel
-% \spacing{getal} : instellen interlinie
-% \normalbaselines : instellen regelafstend
-%
-% \setstrut : instellen \strut
-% \setnostrut : resetten \strut, \endstrut, \begstrut
-%
-% \setteststrut : instellen zichtbare struts
-% \resetteststrut : instellen onzichtbare struts
-%
-% \setfontparameters : instellen na fontset
-%
-% De hoogte van een regel (\lineheight) is gelijk aan de
-% som van de hoogte (\ht) en diepte (\dp) van \strutbox.
-%
-% \strut : denkbeeldig blokje met hoogte en diepte
-%
-% Een \hbox kan als deze aan het begin van een regel staat
-% een breedte \hsize krijgen. Dit is soms te voorkomen met het
-% commando \leavevmode. Binnen een \vbox geeft dit echter
-% niet altijd het gewenste resultaat, vandaar het commando
-%
-% \leaveoutervmode
-
-% Pas op: niet zomaar \topskip en \baselineskip aanpassen
-% en zeker niet \widowpenalty. Dit kan ernstige gevolgen
-% hebben voor kolommen.
-%
-% Enige glue kan op zich geen kwaad, echter als blanko=vast,
-% dan moet ook de rek 0 zijn. Binnen kolommen is rek ook
-% niet bepaald mooi. Een hele kleine waarde (0.025) voldoet,
-% omdat een positieve glue eindeloos rekbaar is.
-
-\newdimen\strutdimen
-\newdimen\lineheight
-\newdimen\openlineheight
-\newdimen\openstrutheight
-\newdimen\openstrutdepth
-\newdimen\topskipgap
-\newdimen\struttotal
-
-\def\strutheightfactor {.72}
-\def\strutdepthfactor {.28}
-
-\def\baselinefactor {2.8}
-\def\baselinegluefactor {0}
-
-\def\minimumstrutheight {0pt}
-\def\minimumstrutdepth {0pt}
-
-\def\normallineheight {\baselinefactor ex}
-\def\minimumlinedistance {\lineskip}
-
-\def\strutheight {0pt}
-\def\strutdepth {0pt}
-\def\strutwidth {0pt}
-
-\def\spacingfactor {1}
-
-\def\topskipfactor {1.0}
-\def\maxdepthfactor {0.5}
-
-\def\systemtopskipfactor {\topskipfactor}
-\def\systemmaxdepthfactor {\maxdepthfactor}
-
-% De onderstaande definitie wordt in de font-module overruled
-
-\ifx\globalbodyfontsize\undefined
- \newdimen\globalbodyfontsize
- \globalbodyfontsize=12pt
-\fi
-
-\ifx\normalizedbodyfontsize\undefined
- \def\normalizedbodyfontsize{12pt}
-\fi
-
-% door een \dimen. Dit is geen probleem omdat (1) de default
-% korpsgrootte 12pt is en (2) de fonts nog niet geladen zijn
-% en de instellingen bij het laden nogmaals plaatsvinden.
-
-% \def\topskipcorrection
-% {\ifdim\topskip>\openstrutheight
-% % == \vskip\topskipgap
-% \vskip\topskip
-% \vskip-\openstrutheight
-% \fi
-% \verticalstrut
-% \vskip-\struttotal}
-
-\def\topskipcorrection
- {\simpletopskipcorrection
- \vskip-\struttotal
- \verticalstrut}
-
-\def\simpletopskipcorrection
- {\ifdim\topskip>\openstrutheight
- % == \vskip\topskipgap
- \vskip\topskip
- \vskip-\openstrutheight
- \fi}
-
-% \def\settopskip % the extra test is needed for the lbr family
-% {\topskip\systemtopskipfactor\globalbodyfontsize
-% \ifgridsnapping \else
-% \ifr@ggedbottom\!!plus5\globalbodyfontsize\fi
-% \fi
-% \relax % the skip
-% \topskipgap\topskip
-% \advance\topskipgap -\openstrutheight\relax
-% \ifdim\topskip<\strutheightfactor\openlineheight
-% \topskip\strutheightfactor\openlineheight\relax
-% \fi}
-
-\def\settopskip % the extra test is needed for the lbr family
- {\topskip\systemtopskipfactor\globalbodyfontsize
- \ifgridsnapping \else
- \ifr@ggedbottom\!!plus5\globalbodyfontsize\fi
- \fi
- \relax % the skip
- \topskipgap\topskip
- \advance\topskipgap -\openstrutheight\relax
-\ifdim\minimumstrutheight>\zeropoint
- \ifdim\topskip<\minimumstrutheight
- \topskip\minimumstrutheight\relax
- \fi
-\else
- \ifdim\topskip<\strutheightfactor\openlineheight
- \topskip\strutheightfactor\openlineheight\relax
- \fi
-\fi}
-
-\def\setmaxdepth
- {\maxdepth\systemmaxdepthfactor\globalbodyfontsize}
-
-\def\normalbaselines
- {\baselineskip \normalbaselineskip
- \lineskip \normallineskip
- \lineskiplimit\normallineskiplimit}
-
-% \def\setnormalbaselines
-% {\ifdim\normallineheight>\zeropoint
-% \lineheight\normallineheight
-% \fi
-% \openlineheight\spacingfactor\lineheight
-% \openstrutheight\strutheightfactor\openlineheight
-% \openstrutdepth \strutdepthfactor \openlineheight
-% \normalbaselineskip\openlineheight
-% \!!plus\baselinegluefactor\openlineheight
-% \!!minus\baselinegluefactor\openlineheight
-% \normallineskip\minimumlinedistance\relax % \onepoint\relax
-% \normallineskiplimit\zeropoint\relax
-% \normalbaselines}
-
-\def\setnormalbaselines
- {\ifdim\normallineheight>\zeropoint
- \lineheight\normallineheight
- \fi
- \openlineheight\spacingfactor\lineheight
- \openstrutheight \ifdim\minimumstrutheight>\zeropoint
- \minimumstrutheight % new
- \else
- \strutheightfactor\openlineheight
- \fi
- \openstrutdepth \ifdim\minimumstrutdepth>\zeropoint
- \minimumstrutdepth % new
- \else
- \strutdepthfactor \openlineheight
- \fi
- \ifdim\dimexpr\minimumstrutdepth+\minimumstrutheight\relax>\zeropoint
- \openlineheight\dimexpr\openstrutheight+\openstrutdepth\relax % new
- \fi
- \normalbaselineskip\openlineheight
- \ifgridsnapping\else
- \!!plus \baselinegluefactor\openlineheight
- \!!minus\baselinegluefactor\openlineheight
- \fi
- \normallineskip\minimumlinedistance\relax % \onepoint\relax
- \normallineskiplimit\zeropoint\relax
- \normalbaselines
- \mksetupgridsnapping}
-
-% \def\setspacingfactor#1\to#2\by#3\\%
-% {\strutdimen#2\points
-% \strutdimen#3\strutdimen
-% \edef#1{\withoutpt\the\strutdimen}}
-%
-% \def\spacing#1%
-% {\ifgridsnapping
-% %\doifnot{#1}{1}{\showmessage\m!layouts{11}{#1}}%
-% \ifdim#1\points=\onepoint\else\showmessage\m!layouts{11}{#1}\fi
-% \edef\spacingfactor{1}%
-% \else
-% \edef\spacingfactor{#1}%
-% \fi
-% \setspacingfactor\systemtopskipfactor \to\topskipfactor \by#1\\% why no \spacingfactor ?
-% \setspacingfactor\systemmaxdepthfactor\to\maxdepthfactor\by#1\\% why no \spacingfactor ?
-% \setnormalbaselines
-% \setstrut}
-%
-% \def\setspacingfactor#1#2#3%
-% {\edef#1{\withoutpt\the\dimexpr#2\points*#3\relax}}
-
-\def\spacing#1%
- {\ifgridsnapping
- \ifdim#1\points=\onepoint\else\showmessage\m!layouts{11}{#1}\fi
- \edef\spacingfactor{1}%
- \else
- \edef\spacingfactor{#1}%
- \fi
- %\setspacingfactor\systemtopskipfactor \topskipfactor {#1}% why no \spacingfactor ?
- %\setspacingfactor\systemmaxdepthfactor\maxdepthfactor{#1}% why no \spacingfactor ?
- \edef\systemtopskipfactor {\withoutpt\the\dimexpr#1\dimexpr\topskipfactor \points}%
- \edef\systemmaxdepthfactor{\withoutpt\the\dimexpr#1\dimexpr\maxdepthfactor\points}%
- \setnormalbaselines
- \setstrut}
-
-%D Sometimes one needs to freeze the interlinespacing
-%D
-%D \starttyping
-%D \rm \saveinterlinespace .... {\ss \restoreinterlinespace .... \endgraf}
-%D \stoptyping
-
-\let\restoreinterlinespace\relax
-
-\def\saveinterlinespace
- {\edef\restoreinterlinespace
- {\lineheight \the\lineheight
- \openstrutheight \the\openstrutheight
- \openstrutdepth \the\openstrutdepth
- \openlineheight \the\openlineheight
- \normalbaselineskip \the\normalbaselineskip
- \normallineskip \the\normallineskip
- \normallineskiplimit\the\normallineskiplimit
- \noexpand\def\noexpand\normallineheight{\the\dimexpr\normallineheight}%
- \noexpand\normalbaselines}}
-
-% plain definition:
-%
-% \def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
-%
-% could be:
-%
-% \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
-
-\ifx\strutbox\undefined
-
- \newbox\strutbox
-
- \setbox\strutbox=\normalhbox{\vrule height8.5pt depth3.5pt width\z@}
-
- %\def\strut{\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
- \def\strut{\relax\ifmmode\copy\else\unhcopy\fi\strutbox}
-
-\fi
-
-\let\normalstrut=\strut
-
-% The double \hbox construction enables us to \backtrack
-% boxes.
-
-% \def\setstrutdimen#1#2#3% % een strut is n.m maal ex
-% {\strutdimen\normallineheight % wat niet per se \lineheight
-% \strutdimen#2\strutdimen % is omdat een strut lokaal
-% \strutdimen#3\strutdimen % kan afwijken van de globale
-% \edef#1{\the\strutdimen}} % macro % strut
-
-% \def\setstrutdimen#1#2#3% % een strut is n.m maal ex
-% {\strutdimen\normallineheight % wat niet per se \lineheight
-% \strutdimen#2\strutdimen % is omdat een strut lokaal
-% \strutdimen#3\strutdimen % kan afwijken van de globale
-% \edef#1{\the\strutdimen}} % macro % strut
-
-% \def\setstrut
-% {\setstrutdimen\strutheight\strutheightfactor\spacingfactor
-% \setstrutdimen\strutdepth \strutdepthfactor \spacingfactor
-% \let\strut=\normalstrut
-% \setbox\strutbox=\normalhbox
-% {\normalhbox
-% {\vrule
-% \!!width \strutwidth
-% \!!height \strutheight
-% \!!depth \strutdepth
-% \normalkern-\strutwidth}}}
-
-% \def\setstrut
-% {\setstrutdimen\strutheight\strutheightfactor\spacingfactor
-% \setstrutdimen\strutdepth \strutdepthfactor \spacingfactor
-% \dosetstrut}
-
-% \def\setstrut
-% {\strutdimen\normallineheight
-% \strutdimen\strutheightfactor\strutdimen
-% \strutdimen\spacingfactor\strutdimen
-% \edef\strutheight{\the\strutdimen}%
-% \strutdimen\normallineheight
-% \ifgridsnapping
-% \advance\strutdimen-\strutheight
-% \else
-% \strutdimen\strutdepthfactor\strutdimen
-% \strutdimen\spacingfactor\strutdimen
-% \fi
-% \edef\strutdepth{\the\strutdimen}%
-% \dosetstrut}
-
-% interesting, strutdepth is 4.05064pt vs 4.05066pt depending on grid
-% nasty rounding problem
-
-% \def\setstrut
-% {% height
-% \strutdimen\normallineheight
-% \ifdim\minimumstrutheight>\zeropoint
-% \strutdimen\minimumstrutheight
-% \else
-% \strutdimen\strutheightfactor\strutdimen
-% \fi
-% \strutdimen\spacingfactor\strutdimen
-% \edef\strutheight{\the\strutdimen}%
-% % depth
-% \strutdimen\normallineheight
-% \ifgridsnapping
-% \ifdim\minimumstrutdepth>\zeropoint
-% \strutdimen\minimumstrutdepth
-% \else
-% \advance\strutdimen-\strutheight
-% \fi
-% \else
-% \ifdim\minimumstrutdepth>\zeropoint
-% \strutdimen\minimumstrutdepth
-% \else
-% \strutdimen\strutdepthfactor\strutdimen
-% \fi
-% \strutdimen\spacingfactor\strutdimen
-% \fi
-% \edef\strutdepth{\the\strutdimen}%
-% % finish
-% \dosetstrut}
-
-% \def\setstrut
-% {% height
-% \ifdim\minimumstrutheight>\zeropoint
-% \edef\strutheight{\the\dimexpr\spacingfactor\dimexpr\minimumstrutheight}%
-% \else
-% \edef\strutheight{\the\dimexpr\spacingfactor\dimexpr\strutheightfactor\dimexpr\normallineheight}%
-% \fi
-% % depth
-% \ifgridsnapping
-% \ifdim\minimumstrutdepth>\zeropoint
-% \edef\strutdepth{\the\dimexpr\minimumstrutdepth}%
-% \else
-% \edef\strutdepth{\the\dimexpr\normallineheight-\strutheight}%
-% \fi
-% \else
-% \ifdim\minimumstrutdepth>\zeropoint
-% \edef\strutdepth{\the\dimexpr\spacingfactor\dimexpr\minimumstrutdepth}%
-% \else
-% \edef\strutdepth{\the\dimexpr\spacingfactor\dimexpr\strutdepthfactor\dimexpr\normallineheight}%
-% \fi
-% \fi
-% % finish
-% \dosetstrut}
-
-\unexpanded\def\setstrut
- {% height
- \edef\strutheight
- {\the\dimexpr\spacingfactor\dimexpr
- \ifdim\minimumstrutheight>\zeropoint
- \minimumstrutheight
- \else
- \strutheightfactor\dimexpr\normallineheight
- \fi}%
- % depth
- \edef\strutdepth%
- {\the\dimexpr
- \ifgridsnapping
- \ifdim\minimumstrutdepth>\zeropoint
- \minimumstrutdepth
- \else
- \normallineheight-\strutheight
- \fi
- \else
- \spacingfactor\dimexpr
- \ifdim\minimumstrutdepth>\zeropoint
- \minimumstrutdepth
- \else
- \strutdepthfactor\dimexpr\normallineheight
- \fi
- \fi}%
- % finish
- \dosetstrut}
-
-\unexpanded\def\setcharstrut#1%
- {\setbox\strutbox\normalhbox{#1}%
- \edef\strutheight{\the\strutht}%
- \edef\strutdepth {\the\strutdp}%
- \dosetstrut}
-
-% \def\setfontstrut
-% {\setcharstrut{(}}
-%
-% better, since some fonts have small (but descending Q etc)
-
-\unexpanded\def\setfontstrut
- {\setcharstrut{(gplQT}}
-
-\unexpanded\def\setcapstrut% could be M, but Q has descender
- {\setcharstrut{Q}}
-
-%D Handy for math (used in mathml):
-
-\def\charhtstrut
- {\begingroup
- \setcharstrut{GJY}%
- \vrule\!!width\zeropoint\!!depth\zeropoint\!!height\strutht
- \endgroup}
-
-\def\chardpstrut
- {\begingroup
- \setcharstrut{gjy}%
- \vrule\!!width\zeropoint\!!depth\strutdp\!!height\zeropoint
- \endgroup}
-
-%D Centered looks nicer:
-
-% \def\dosetstrut
-% {\let\strut\normalstrut
-% \setbox\strutbox\normalhbox
-% {\normalhbox to \zeropoint
-% {% \hss % new, will be option
-% \vrule
-% \!!width \strutwidth
-% \!!height\strutheight
-% \!!depth \strutdepth
-% \hss}}%
-% \struttotal\dimexpr\strutht+\strutdp\relax}
-%
-% because of all the callbacks in mkiv, we avoid unnecessary boxes ...
-% maybe use an attribute so that we can tag boxes that don't need a
-% treatment; tests with using an attribute so far have shown that
-% it's slower because testing the attribute takes time too
-
-\def\dosetstrut
- {\let\strut\normalstrut
- \ifdim\strutwidth=\zeropoint
- \setbox\strutbox\normalhbox
- {\vrule
- \!!width \zeropoint
- \!!height\strutheight
- \!!depth \strutdepth}%
- \else
- \setbox\strutbox\normalhbox
- {\normalhbox to \zeropoint
- {% \hss % new, will be option
- \vrule
- \!!width \strutwidth
- \!!height\strutheight
- \!!depth \strutdepth
- \hss}}%
- \fi
- \struttotal\dimexpr\strutht+\strutdp\relax}
-
-%D The dimen \type {\struttotal} holds the exact size of the
-%D strut; occasionally a one scaled point difference can show
-%D up with the lineheight.
-
-%D Sometimes a capstrut comes in handy
-%D
-%D \starttabulate[|Tl|l|l|]
-%D \NC yes \NC normal strut \NC {\showstruts\setupstrut[yes]\strut} \NC \NR
-%D \NC no \NC no strut \NC {\showstruts\setupstrut[no]\strut} \NC \NR
-%D \NC kap \NC a capital strut (i.e. Q) \NC {\showstruts\setupstrut[cap]\strut} \NC \NR
-%D \NC A B \unknown \NC a character strut (e.g. A) \NC {\showstruts\setupstrut[A]\strut} \NC \NR
-%D \NC \NC a normal strut \NC {\showstruts\setupstrut\strut} \NC \NR
-%D \stoptabulate
-
-\def\setupstrut
- {\dosingleempty\dosetupstrut}
-
-\def\dosetupstrut[#1]% yet undocumented, todo: fontstrut
- {\processaction
- [#1]
- [ \v!yes=>\setstrut,
- \v!auto=>\setautostrut,
- \v!no=>\setnostrut,
- \v!cap=>\setcapstrut,
- \v!fit=>\setfontstrut,
- \v!line=>\setstrut,
- \s!default=>\setstrut,
- \s!unknown=>\setcharstrut\commalistelement]}
-
-\def\setteststrut
- {\def\strutwidth{.8pt}%
- \setstrut}
-
-\def\autostrutfactor{1.1}
-
-\def\setautostrut
- {\begingroup
- \setbox\scratchbox\copy\strutbox
- \setstrut
- \ifdim\ht\strutbox>\autostrutfactor\ht\scratchbox
- \endgroup \setstrut
- \else\ifdim\dp\strutbox>\autostrutfactor\dp\scratchbox
- \endgroup \setstrut
- \else
- \endgroup
- \fi\fi}
-
-% simple version
-%
-% \def\begstrut
-% {\relax\ifcase\strutht\else
-% \strut
-% \normalpenalty\plustenthousand
-% \normalhskip\zeropoint
-% \ignorespaces
-% \fi}
-%
-% \def\endstrut
-% {\relax\ifhmode\ifcase\strutht\else
-% \removeunwantedspaces
-% \normalpenalty\plustenthousand
-% \normalhskip\zeropoint
-% \strut
-% \fi\fi}
-
-% when enabled, sigstruts will remove themselves if nothing
-% goes inbetween
-
-\newsignal\strutsignal \setfalse\sigstruts
-
-\def\begstrut
- {\relax\ifcase\strutht\else
- \ifconditional\sigstruts
- \noindent\horizontalstrut
- \normalpenalty\plustenthousand
- \normalhskip-\strutsignal
- \normalhskip\strutsignal
- \else
- \strut
- \normalpenalty\plustenthousand
- \normalhskip\zeropoint
- \fi
- \expandafter \ignorespaces
- \fi}
-
-\def\endstrut
- {\relax\ifhmode\ifcase\strutht\else
- \ifconditional\sigstruts
- \ifdim\lastskip=\strutsignal
- \unskip\unskip\unpenalty\setbox\scratchbox\lastbox
- \else
- \normalpenalty\plustenthousand
- \normalhskip\zeropoint
- \strut
- \fi
- \else
- \removeunwantedspaces
- \normalpenalty\plustenthousand
- \normalhskip\zeropoint
- \strut
- \fi
- \fi\fi}
-
-\newbox\nostrutbox \setbox\nostrutbox\normalhbox{} % {\normalhbox{}}
-
-\def\setnostrut
- {\setbox\strutbox\copy\nostrutbox
- \let\strut\empty
- \let\endstrut\empty
- \let\begstrut\empty
- \let\crlfplaceholder\empty}
-
-% unsave:
-%
-% \def\pseudostrut
-% {\bgroup
-% \setnostrut
-% \normalstrut
-% \egroup}
-%
-% try:
-%
-% \startchemie
-% \chemie[ONE,Z0,SB15,MOV1,SB15,Z0][C,C]
-% \stopchemie
-%
-% so:
-
-\def\pseudostrut
- {\noindent} % better: \dontleavehmode
-
-\let\pseudobegstrut\pseudostrut
-
-\let\pseudoendstrut\removeunwantedspaces
-
-\def\resetteststrut
- {\let\strutwidth\zeropoint
- \setstrut}
-
-\ifx\setfontparameters\undefined
- % problems ! ! ! !
- \def\setfontparameters{\the\everybodyfont}
-\fi
-
-%D Handy:
-
-\def\baselinedistance{\the\lineheight}
-
-%D We need \type{\normaloffinterlineskip} because the new
-%D definition contains an assignment, and |<|don't ask me
-%D why|>| this assignment gives troubles in for instance the
-%D visual debugger.
-
-%D The plain ones:
-
-\def\offinterlineskip
- {\baselineskip-\thousandpoint
- \lineskip\zeropoint
- \lineskiplimit\maxdimen}
-
-\def\nointerlineskip
- {\prevdepth-\thousandpoint}
-
-\let\normaloffinterlineskip=\offinterlineskip % knuth's original
-
-%D My own one:
-
-\def\offinterlineskip
- {\ifdim\baselineskip>\zeropoint
- \edef\oninterlineskip
- {\baselineskip\the\baselineskip
- \lineskip\the\lineskip
- \lineskiplimit\the\lineskiplimit
- \let\noexpand\offinterlineskip\noexpand\normaloffinterlineskip}%
- \else
- \let\oninterlineskip\setnormalbaselines
- \fi
- \normaloffinterlineskip}
-
-\let\oninterlineskip=\relax
-
-\def\leaveoutervmode
- {\ifvmode\ifinner\else
- \leavevmode
- \fi\fi}
-
-% We stellen enkele penalties anders in dan Plain TEX:
-
-% oud
-%
-% \widowpenalty=\defaultwidowpenalty\relax
-% \clubpenalty =\defaultclubpenalty \relax
-
-\def\resetpenalties#1%
- {\ifx#1\undefined\else
- #1\minusone
- \fi}
-
-\def\setpenalties#1#2#3%
- {\ifx#1\undefined\else % space before #3 prevents lookahead problems, needed when #3=text
- #1\numexpr#2+\plusone\relax\space\doexpandedrecurse{\the\numexpr#2\relax}{ #3}\zerocount\relax
- \fi}
-
-\def\doexpandedrecurse#1#2%
- {\ifnum#1>\zerocount#2\@EA\doexpandedrecurse\@EA{\the\numexpr#1-1\relax}{#2}\fi}
-
-%D \macros
-%D {keeplinestogether}
-%D
-%D Dirty hack, needed in margin content that can run of a page.
-
-\def\keeplinestogether#1%
- {\xdef\restoreinterlinepenalty{\global\resetpenalties\interlinepenalties}%
- \global\setpenalties\interlinepenalties{#1}\plustenthousand}
-
-\newif\ifgridsnapping % to be sure
-
-\def\defaultwidowpenalty {2000} % was: 1000
-\def\defaultclubpenalty {2000} % was: 800
-\def\defaultdisplaywidowpenalty {50}
-\def\defaultbrokenpenalty {100}
-
-\def\defaultgridwidowpenalty {0}
-\def\defaultgridclubpenalty {0}
-\def\defaultgriddisplaywidowpenalty {0}
-\def\defaultgridbrokenpenalty {0}
-
-% The original approach:
-%
-% \def\setdefaultpenalties
-% {\ifgridsnapping
-% \widowpenalty\defaultgridwidowpenalty
-% \clubpenalty \defaultgridclubpenalty
-% \else
-% \widowpenalty\defaultwidowpenalty
-% \clubpenalty \defaultclubpenalty
-% \fi}
-%
-% However, we will use setups:
-
-% to be documented
-
-\def\nopenalties
- {\widowpenalty \zerocount
- \clubpenalty \zerocount
- \brokenpenalty \zerocount
- \doublehyphendemerits\zerocount
- \finalhyphendemerits \zerocount
- \adjdemerits \zerocount}
-
-\def\setdefaultpenalties
- {\directsetup{\systemsetupsprefix\s!default}}
-
-\startsetups [\systemsetupsprefix\s!reset]
- \resetpenalties\widowpenalties
- \resetpenalties\clubpenalties
- \resetpenalties\interlinepenalties
-\stopsetups
-
-% we use \directsetup because it's faster and we know there is no csl
-
-\startsetups [\systemsetupsprefix\s!default]
-
- \directsetup{\systemsetupsprefix\s!reset}
-
- \widowpenalty \defaultwidowpenalty
- \clubpenalty \defaultclubpenalty
- \displaywidowpenalty\defaultdisplaywidowpenalty
- \brokenpenalty \defaultbrokenpenalty
-
-\stopsetups
-
-\startsetups [\v!grid] [\systemsetupsprefix\s!default]
-
- \directsetup{\systemsetupsprefix\s!reset}
-
- \widowpenalty \defaultgridwidowpenalty
- \clubpenalty \defaultgridclubpenalty
- \displaywidowpenalty\defaultgriddisplaywidowpenalty
- \brokenpenalty \defaultgridbrokenpenalty
-
-\stopsetups
-
-% as an illustration:
-
-\startsetups [\systemsetupsprefix\v!strict]
-
- \directsetup{\systemsetupsprefix\s!reset}
-
- \setpenalties\widowpenalties2\maxdimen
- \setpenalties\clubpenalties 2\maxdimen
- \brokenpenalty \maxdimen
-
-\stopsetups
-
-\setdefaultpenalties % will happen later in \setuplayout
-
-% Suggested by GB (not the name -):
-
-\def\rapfillskip{.5\hsize plus .092\hsize minus .5\hsize} % D.A.'s value
-
-% Bovendien definieren we enkele extra \fill's:
-
-\def\hfilll{\hskip\zeropoint\!!plus1filll\relax}
-\def\vfilll{\vskip\zeropoint\!!plus1filll\relax}
-
-% De onderstaande hulpmacro's moeten nog eens instelbaar worden
-% gemaakt.
-
-\def\tfskipsize{1em\relax}
-\def\tfkernsize{1ex\relax}
-
-\def\tfskip{\dotfskip\tfskipsize}
-\def\tfkern{\dotfkern\tfkernsize}
-
-\def\dotfskip#1{{\tf\hskip#1}}
-\def\dotfkern#1{{\tf\kern #1}}
-
-% needs a proper \definenarrower or installnarrower
-
-\newskip\ctxleftskip
-\newskip\ctxrightskip
-\newskip\ctxmidskip
-
-\def\dosinglenarrower#1%
- {\processaction
- [#1]
- [ \v!left=>\global\advance\ctxleftskip \@@slleft,
- \v!middle=>\global\advance\ctxmidskip \@@slmiddle,
- \v!right=>\global\advance\ctxrightskip \@@slright,
- \v!reset=>\global\ctxleftskip \zeropoint
- \global\ctxmidskip \zeropoint
- \global\ctxrightskip\zeropoint,
- \v!none=>,
- \s!unknown=>\global\advance\ctxmidskip \commalistelement]}
-
-% \def\donarrower[#1]% hm, can be dorepeat directly
-% {\processaction
-% [#1]
-% [ \v!left=>\global\advance\ctxleftskip \@@slleft,
-% \v!middle=>\global\advance\ctxmidskip \@@slmiddle,
-% \v!right=>\global\advance\ctxrightskip \@@slright,
-% \v!none=>,% handy for delimitedtexts
-% \s!unknown=>{\dorepeatwithcommand[#1]\dosinglenarrower}]}
-
-\def\donarrower[#1]% hm, can be dorepeat directly
- {\dorepeatwithcommand[#1]\dosinglenarrower}
-
-\def\complexstartnarrower[#1]%
- {\@@slbefore % was hard coded \par
- \bgroup
- \global\ctxleftskip \zeropoint
- \global\ctxrightskip\zeropoint
- \global\ctxmidskip \zeropoint
- \processcommalistwithparameters[#1]\donarrower
- \advance\leftskip \ctxleftskip
- \advance\rightskip \ctxrightskip
- \advance\leftskip \ctxmidskip
- \advance\rightskip \ctxmidskip
- \seteffectivehsize}
-
-% todo: definenarrower
-
-\def\simplestartnarrower
- {\startnarrower[\v!middle]}
-
-\definecomplexorsimple\startnarrower
-
-\def\stopnarrower
- {\@@slafter % was hard coded \par / needed, else skips forgotten
- \egroup}
-
-\def\setupnarrower
- {\dodoubleargument\getparameters[\??sl]}
-
-\newdimen\@@effectivehsize \def\effectivehsize {\hsize}
-\newdimen\@@effectiveleftskip \def\effectiveleftskip {\leftskip}
-\newdimen\@@effectiverightskip \def\effectiverightskip{\rightskip}
-
-\def\seteffectivehsize
- {\setlocalhsize
- \@@effectivehsize \localhsize
- \@@effectiveleftskip \leftskip
- \@@effectiverightskip \rightskip
- \let\effectivehsize \@@effectivehsize
- \let\effectiveleftskip \@@effectiveleftskip
- \let\effectiverightskip\@@effectiverightskip}
-
-\def\dodefinehbox[#1][#2]%
- {\setvalue{hbox#1}##1%
- {\hbox to #2{\begstrut##1\endstrut\hss}}}
-
-\def\definehbox
- {\dodoubleargument\dodefinehbox}
-
-\def\iobox#1#2#3#% here #3# is not really needed
- {\vbox\bgroup % we want to return a vbox like the others
- \hbox\bgroup% we need to pack the signal with the box
- \signalrightpage
- \dowithnextboxcontent
- {\let\\=\endgraf\forgetall\doifrightpageelse#1#2}
- {\box\nextbox\egroup\egroup}
- \vbox#3}
-
-\def\obox{\iobox\raggedleft \raggedright} % outerbox
-\def\ibox{\iobox\raggedright\raggedleft} % innerbox
-
-\def\dosetraggedvbox#1%
- {\let\raggedbox\vbox
- \processfirstactioninset
- [#1]
- [ \v!left=>\let\raggedbox\lbox,
- \v!right=>\let\raggedbox\rbox,
- \v!middle=>\let\raggedbox\cbox,
- \v!inner=>\let\raggedbox\ibox,
- \v!outer=>\let\raggedbox\obox,
- \v!flushleft=>\let\raggedbox\rbox,
- \v!flushright=>\let\raggedbox\lbox,
- \v!center=>\let\raggedbox\cbox,
- \v!no=>\def\raggedbox{\vbox\bgroup\raggedright\let\next=}]}
-
-\def\dosetraggedhbox#1%
- {\let\raggedbox\hbox
- \processaction % slow
- [#1]
- [ \v!left=>\def\raggedbox{\doalignedline\v!left },
- \v!right=>\def\raggedbox{\doalignedline\v!right },
- \v!middle=>\def\raggedbox{\doalignedline\v!middle},
- \v!inner=>\def\raggedbox{\doalignedline\v!inner },
- \v!outer=>\def\raggedbox{\doalignedline\v!outer },
- \v!flushleft=>\def\raggedbox{\doalignedline\v!right },
- \v!flushright=>\def\raggedbox{\doalignedline\v!left },
- \v!center=>\def\raggedbox{\doalignedline\v!middle}]}
-
-\def\dosetraggedcommand#1%
- {\expanded{\dodosetraggedcommand{#1}}}
-
-% \def\dodosetraggedcommand#1% beware: #1=empty is ignored, keep that!
-% {\let\raggedcommand \relax
-% \let\raggedtopcommand \empty
-% \let\raggedbottomcommand\empty
-% \chardef\raggedoneliner\zerocount
-% \doifsomething{#1}
-% {\doifinsetelse\v!broad{#1}\!!doneatrue\!!doneafalse
-% \doifinsetelse\v!wide {#1}\!!donebtrue\!!donebfalse
-% \!!donectrue
-% \rawprocesscommalist[#1]\dododosetraggedcommand}}
-
-\newtoks\everyraggedcommand
-
-\def\raggedcommand{\the\everyraggedcommand}
-
-\def\dodosetraggedcommand#1% beware: #1=empty is ignored, keep that!
- {\everyraggedcommand \emptytoks
- \let\raggedtopcommand \empty
- \let\raggedbottomcommand\empty
- \chardef\raggedoneliner\zerocount
- \doifsomething{#1}
- {\doifinsetelse\v!broad{#1}\!!doneatrue\!!doneafalse
- \doifinsetelse\v!wide {#1}\!!donebtrue\!!donebfalse
- \!!donectrue
- \rawprocesscommalist[#1]\dododosetraggedcommand}}
-
-\def\dododosetraggedcommand#1%
- {\executeifdefined{\@@ragged@@command\string#1}\relax}
-
-\def\@@ragged@@command{@@raggedcommand}
-
-\setvalue{\@@ragged@@command\v!hanging }{\appendtoks\enableprotruding \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!nothanging }{\appendtoks\disableprotruding \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!hz }{\appendtoks\enableadjusting \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!nohz }{\appendtoks\disableadjusting \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!spacing }{\appendtoks\enablespacehandling
- \enablekernhandling \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!nospacing }{\appendtoks\disablespacehandling
- \disablekernhandling \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!hyphenated }{\appendtoks\dohyphens \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!nothyphenated}{\appendtoks\nohyphens \to\everyraggedcommand}
-
-\setvalue{\@@ragged@@command\v!tolerant }{\appendtoks\tolerance3000\relax \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!verytolerant}{\appendtoks\tolerance4500\relax \to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!stretch }{\appendtoks\emergencystretch\bodyfontsize\to\everyraggedcommand}
-
-\setvalue{\@@ragged@@command\v!left}%
- {\if!!donea \appendtoks\veryraggedleft\to\everyraggedcommand
- \else \appendtoks\raggedleft \to\everyraggedcommand
- \fi
- \!!donecfalse}
-
-\setvalue{\@@ragged@@command\v!right}%
- {\if!!donea \appendtoks\veryraggedright\to\everyraggedcommand
- \else \appendtoks\raggedright \to\everyraggedcommand
- \fi
- \!!donecfalse}
-
-\setvalue{\@@ragged@@command\v!middle}%
- {\if!!donec
- \if!!doneb \appendtoks\raggedwidecenter\to\everyraggedcommand
- \else\if!!donea \appendtoks\veryraggedcenter\to\everyraggedcommand
- \else \appendtoks\raggedcenter \to\everyraggedcommand
- \fi\fi
- \!!donecfalse
- \else
- \let\raggedbottomcommand\vfilll % bonus, pretty strong
- \let\raggedtopcommand \vfilll % used with \framed for
- \fi} % instance in tables
-
-\setvalue{\@@ragged@@command\v!flushleft }{\getvalue{\@@ragged@@command\v!right }}
-\setvalue{\@@ragged@@command\v!flushright}{\getvalue{\@@ragged@@command\v!left }}
-\setvalue{\@@ragged@@command\v!center }{\getvalue{\@@ragged@@command\v!middle}}
-
-\setvalue{\@@ragged@@command\v!high}%
- {\let\raggedbottomcommand\vfilll} % and since we lack a
-
-\setvalue{\@@ragged@@command\v!low}%
- {\let\raggedtopcommand\vfilll} % proper keyword, but
-
-\setvalue{\@@ragged@@command\v!lohi}%
- {\let\raggedbottomcommand\vfilll % we do support the
- \let\raggedtopcommand\vfilll} % ugly laho (lohi)
-
-\setvalue{\@@ragged@@command\v!no}%
- {\appendtoks\raggedright\to\everyraggedcommand}
-
-\setvalue{\@@ragged@@command\v!yes}%
- {\appendtoks\notragged\to\everyraggedcommand}
-
-\setvalue{\@@ragged@@command\v!normal}%
- {\appendtoks\notragged\to\everyraggedcommand}
-
-\setvalue{\@@ragged@@command\v!inner}% not yet perfect
- {\signalrightpage % may interfere
- \doifrightpageelse
- {\getvalue{\@@ragged@@command\v!right}}
- {\getvalue{\@@ragged@@command\v!left}}}
-
-\setvalue{\@@ragged@@command\v!outer}% not yet perfect
- {\signalrightpage % may interfere
- \doifrightpageelse
- {\getvalue{\@@ragged@@command\v!left}}
- {\getvalue{\@@ragged@@command\v!right}}}
-
-\setvalue{\@@ragged@@command\v!lesshyphenation}%
- {\appendtoks\lesshyphens\to\everyraggedcommand}
-\setvalue{\@@ragged@@command\v!morehyphenation}%
- {\appendtoks\morehyphens\to\everyraggedcommand}
-
-% compare:
-%
-% \framed[width=4cm,align=no] {\hfil xxx}
-% \framed[width=4cm,align=disable]{\hfil xxx}
-
-\setvalue{\@@ragged@@command\v!disable}% for one liners
- {\appendtoks\raggedright\parfillskip\zeropoint\to\everyraggedcommand}
-
-\chardef\raggedoneliner\zerocount
-
-\setvalue{\@@ragged@@command\v!line}%
- {\chardef\raggedoneliner\plusone}
-
-%D Unofficial, may disappear. Now handled directly in the
-%D core-rul module.
-
-% \def\@@startraggedoneliner
-% {\ifcase\raggedoneliner\else
-% \dontleavehmode\hbox to \hsize \bgroup % hsize added, else useless
-% \ifcase\raggedstatus\or\hss\or\hss\fi
-% \ignorespaces
-% \bgroup
-% \aftergroup\removeunwantedspaces
-% \fi}
-
-% \def\@@stopraggedoneliner
-% {\ifcase\raggedoneliner\else
-% \egroup
-% \ifcase\raggedstatus\or\or\hss\or\hss\fi
-% \egroup
-% \ignorespaces % ? ? ?
-% \fi}
-
-% \def\@@handleoneliner
-% {\ifcase\raggedoneliner\else
-% \@@startraggedoneliner
-% \aftergroup\@@stopraggedoneliner
-% \fi}
-
-% Nodig i.v.m. inspringen eerste alineas
-
-\def\explicithmode{\unhbox\voidb@x} % can probably become \dontleavehmode
-
-% Nog doen:
-%
-% \goodbreak -> \allowbreak en \dosomebreak{..} in koppen
-%
-% bij koppen zowieso: \blanko[reset]
-
-% Nog in commando verwerken:
-%
-% \voorkeur la \blanko
-%
-% Om ongewenste witruimte te voorkomen kan met \dosomebreak{\break}
-% een \penalty voor witruimte worden geplaatst.
-
-\def\removelastskip % a redefinition of plain
- {\ifvmode\ifdim\lastskip=\zeropoint\else\vskip-\lastskip\fi\fi}
-
-% first version:
-%
-% \def\dosomebreak#1%
-% {\scratchskip\lastskip
-% \removelastskip
-% %\type{#1}%
-% #1\relax
-% \ifdim\scratchskip=\zeropoint \else
-% \vskip\scratchskip
-% \fi}
-%
-% don't change the next improvement:
-
-% \def\dosomebreak#1%
-% {\endgraf % beware, this forces a newline
-% \ifvmode
-% \ifdim\lastskip=\zeropoint
-% #1\relax
-% \else
-% \scratchskip\lastskip
-% \removelastskip
-% #1\relax
-% \vskip\scratchskip
-% \fi
-% \fi}
-
-% beter, vooral in \vbox; nog in \pagina toepassen s!
-
-\def\doifoutervmode#1%
- {\ifvmode\ifinner\else#1\fi\fi}
-
-\ifx\dosomebreak\undefined % defined in mkiv
-
- \def\dosomebreak#1%
- {\doifoutervmode
- {\scratchskip\lastskip
- \removelastskip
- %\leavevmode\type{#1}%
- #1\relax
- \ifdim\scratchskip=\zeropoint % else interference with footnotes
- \else
- \vskip\scratchskip
- \fi}}
-
-\fi
-
-\def\forgeteverypar
- {\everypar{\the\neverypar}}
-
-%\def\forgetparindent
-% {\forgeteverypar
-% \indentfirstparagraphtrue % recently added
-% \setupindenting[\v!geen]}
-
-%\def\forgetparskip
-% {\setupwhitespace[\v!geen]}
-
-\def\forgetparindent
- {\forgeteverypar
- \indentfirstparagraphtrue % recently added
- \let\currentindentation\v!none
- \ctxparindent\zeropoint
- \parindent\zeropoint\relax}
-
-\def\forgetparskip
- {\let\currentwhitespace\v!none
- \ctxparskip\zeropoint
- \parskip\zeropoint\relax}
-
-\def\forgetbothskips
- {\tolerance1500
- \leftskip\zeropoint
- \rightskip\zeropoint\relax}
-
-\def\forgetspacing
- {\emergencystretch\zeropoint}
-
-\newif\ifforgotten % rather good signal for inner
-
-\appendtoks \forgottentrue \to \everyforgetall
-\appendtoks \forgetragged \to \everyforgetall
-\appendtoks \forgetparskip \to \everyforgetall
-\appendtoks \forgetparindent \to \everyforgetall
-\appendtoks \forgetbothskips \to \everyforgetall
-\appendtoks \forgetspacing \to \everyforgetall % i.v.m. funny spacing in pagebody
-\appendtoks \spacing\!!plusone \to \everyforgetall % new per 10/08/2004, else problems in otr / !! needed
-\appendtoks \everypar\emptytoks \to \everyforgetall % indeed!
-
-\def\localvbox#1#%
- {\vbox#1\bgroup
- \forgetparskip
- \setlocalhsize
- \hsize\localhsize
- \forgetparindent
- \forgetbothskips
- \forgeteverypar
- \let\next=}
-
-% ach ja, hoort niet hier
-
-% \unexpanded\def\dostartattributes#1#2#3%
-% {\begingroup % geen \bgroup, anders in mathmode lege \hbox
-% \doifdefinedelse{#1#2}
-% {\def\fontattribute{\getvalue{#1#2}}}
-% {\let\fontattribute=\empty}%
-% \doifdefinedelse{#1#3}
-% {\def\colorattribute{\getvalue{#1#3}}}
-% {\let\colorattribute=\empty}%
-% \startcolor[\colorattribute]%
-% \@EA\doconvertfont\@EA{\fontattribute}}
-%
-% \unexpanded\def\dostopattributes%
-% {\stopcolor
-% \endgroup}
-%
-% \unexpanded\def\doattributes#1#2#3#4%
-% {\dostartattributes{#1}{#2}{#3}{#4}\dostopattributes}
-
-%D A hardly faster implementation follows. We cannot use
-%D \type {csname} testing since the first argument can be
-%D anything, even a raw fontswitch. No a real improvement
-%D (some 5 seconds on 260 seconds for the maps bibliography).
-
-\let\dostopattributes\relax % in case these commands end up in an edef
-
-\unexpanded\def\dostartattributes#1#2#3%
- {\begingroup % geen \bgroup, anders in mathmode lege \hbox
- \ifcsname#1#3\endcsname
- \let\dostopattributes\@@dostopattributes
- \startcolor[\csname#1#3\endcsname]%
- \else
- \let\dostopattributes\@@nostopattributes
- \fi
- \ifcsname#1#2\endcsname
- \expandafter\doconvertfont
- \else
- \expandafter\gobbleoneargument
- \fi{\csname#1#2\endcsname}}
-
-\newconditional \parbasedattributes
-
-\def\finishparbasedattributes
- {\ifconditional\parbasedattributes
- \setfalse\parbasedattributes
- \par
- \fi}
-
-\def\dostopparbasedattributes
- {\settrue\parbasedattributes
- \dostopattributes}
-
-\unexpanded\def\@@dostopattributes
- {\stopcolor
- \finishparbasedattributes
- \endgroup}
-
-\unexpanded\def\@@nostopattributes
- {\finishparbasedattributes
- \endgroup}
-
-\unexpanded\def\doattributes#1#2#3#4%
- {\dostartattributes{#1}{#2}{#3}{#4}\dostopattributes}
-
-% An even faster \ETEX\ version:
-
-\unexpanded\def\dostartattributes#1#2#3%
- {\begingroup % geen \bgroup, anders in mathmode lege \hbox
- \ifincolor
- \ifcsname#1#3\endcsname
- \let\dostopattributes\@@dostopattributes
- \faststartcolor[\csname#1#3\endcsname]%
- \else
- \let\dostopattributes\@@nostopattributes
- \fi
- \else
- \let\dostopattributes\@@nostopattributes
- \fi
- \ifcsname#1#2\endcsname
- % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
- \@EA\doconvertfont\csname#1#2\@EA\endcsname
- \fi}
-
-\unexpanded\def\@@dostopattributes
- {\faststopcolor
- \finishparbasedattributes
- \endgroup}
-
-\unexpanded\def\@@nostopattributes
- {\finishparbasedattributes
- \endgroup}
-
-%D Bonus macro, see core-sec.tex
-
-\unexpanded\def\dosetfontattribute#1#2%
- {\ifcsname#1#2\endcsname
- \@EA\doconvertfont\csname#1#2\@EA\endcsname
- \fi\empty}
-
-%D Since this happens a lot, and sometimes large arguments
-%D are passed in \type {#4}, we just copy some code:
-
-\unexpanded\def\doattributes#1#2#3#4%
- {\begingroup % geen \bgroup, anders in mathmode lege \hbox
- \ifincolor
- \ifcsname#1#3\endcsname
- \let\dostopattributes\@@dostopattributes
- \faststartcolor[\csname#1#3\endcsname]%
- \else
- \let\dostopattributes\endgroup
- \fi
- \else
- \let\dostopattributes\endgroup
- \fi
- \ifcsname#1#2\endcsname
- % \@EAEAEA\doconvertfont\@EA\@EA\csname#1#2\endcsname
- \@EA\doconvertfont\csname#1#2\@EA\endcsname
- \fi
- {#4}%
- \dostopattributes}
-
-% Kan vaker worden toegepast en moet bovendien sneller!
-
-\newskip\leftskipadaption
-\newskip\rightskipadaption
-
-\def\doadaptleftskip#1%
- {\dosetleftskipadaption{#1}%
- \advance\leftskip \leftskipadaption}
-
-\def\doadaptrightskip#1%
- {\dosetrightskipadaption{#1}%
- \advance\rightskip \rightskipadaption}
-
-\setvalue{@lsa@\v!standard}{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
-\setvalue{@lsa@\v!yes }{\ifdim\ctxparindent=\zeropoint\@@slleft\else\ctxparindent\fi}
-\letvalue{@lsa@\v!no }\zeropoint
-\letvalue{@lsa@\empty }\zeropoint
-\setvalue{@rsa@\v!standard}{\@@slright}
-\setvalue{@rsa@\v!yes }{\@@slright}
-\letvalue{@rsa@\v!no }\zeropoint
-\letvalue{@rsa@\empty }\zeropoint
-
-% not safe for 2\parindent
-%
-% \def\dosetleftskipadaption#1%
-% {\leftskipadaption
-% \ifcsname @lsa@#1\endcsname
-% \csname @lsa@#1\endcsname
-% \else
-% #1%
-% \fi
-% \relax}
-
-\def\dosetleftskipadaption#1%
- {\edefconvertedargument\ascii{@lsa@#1}%
- \leftskipadaption
- \ifcsname\ascii\endcsname
- \csname\ascii\endcsname
- \else
- #1%
- \fi
- \relax}
-
-\def\dosetrightskipadaption#1%
- {\edefconvertedargument\ascii{@rsa@#1}%
- \rightskipadaption
- \ifcsname\ascii\endcsname
- \csname\ascii\endcsname
- \else
- #1%
- \fi
- \relax}
-
-\newcount \noftrackedpagestates
-\newif \ifpagestatemismatch
-\newcount \realpagestateno
-\chardef \frozenpagestate \zerocount
-
-\def\dotrackpagestate#1#2%
- {\ifdoublesided \ifinpagebody \else
- \doforcedtrackpagestate{#1}{#2}%
- \fi \fi}
-
-\def\doforcedtrackpagestate#1#2%
- {\ifcase\frozenpagestate
- \global\advance\noftrackedpagestates\plusone
- \global\advance#2\plusone
- \lazysavetaggedtwopassdata{#1}{\number\noftrackedpagestates}{\number#2}{\noexpand\realfolio}%
- %\llap{\infofont\number\noftrackedpagestates/\number#2}% tracing
- \fi}
-
-\def\doifrightpagestateelse#1#2%
- {\ifcase\frozenpagestate
- \pagestatemismatchfalse
- \realpagestateno\realfolio
- \ifinpagebody
- \ifdoublesided
- \ifodd\realpageno\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \else
- \twopassdatafoundtrue
- \fi
- \else\ifdoublesided
- \findtwopassdata{#1}{\number#2}%
- \iftwopassdatafound
- \realpagestateno\twopassdata\relax
- \ifnum\twopassdata=\realpageno \else
- \pagestatemismatchtrue
- \fi
- \ifodd\twopassdata\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \else
- \ifodd\realpageno\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \fi
- \else
- \twopassdatafoundtrue
- \fi\fi
- \else
- \ifodd\realpagestateno\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \fi
- \iftwopassdatafound
- \@EA\firstoftwoarguments
- \else
- \@EA\secondoftwoarguments
- \fi}
-
-\def\doifforcedrightpagestateelse#1#2%
- {\ifcase\frozenpagestate
- \pagestatemismatchfalse
- \realpagestateno\realfolio
- \findtwopassdata{#1}{\number#2}%
- \iftwopassdatafound
- \realpagestateno\twopassdata\relax
- \ifnum\twopassdata=\realpageno \else
- \pagestatemismatchtrue
- \fi
- \ifodd\twopassdata\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \else
- \ifodd\realpageno\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \fi
- \else
- \ifodd\realpagestateno\relax
- \twopassdatafoundtrue \else \twopassdatafoundfalse
- \fi
- \fi
- \iftwopassdatafound
- \@EA\firstoftwoarguments
- \else
- \@EA\secondoftwoarguments
- \fi}
-
-\def\freezepagestate {\chardef\frozenpagestate\plusone }
-\def\defrostpagestate{\chardef\frozenpagestate\zerocount}
-
-% we can make more of these on top, but how to deal with mixed frozen states
-
-\definetwopasslist\s!paragraph \newcount \nofraggedparagraphs
-
-\def\signalrightpage {\dotrackpagestate \s!paragraph\nofraggedparagraphs}
-\def\doifrightpageelse{\doifrightpagestateelse\s!paragraph\nofraggedparagraphs}
-
-\newcount\pagesignallevel
-
-\def\startsignalrightpage % one may do a \postsignalrightplace
- {\advance\pagesignallevel\plusone
- \presignalrightpage
- \let\signalrightpage\relax
- \let\presignalrightpage\relax
- \let\startsignalrightpage\relax
- \doifrightpageelse\donothing\donothing
- \freezepagestate}
-
-\def\stopsignalrightpage
- {\ifcase\pagesignallevel\or\postsignalrightpage\fi
- \advance\pagesignallevel\minusone}
-
-\def\setraggedparagraphmode
- {\signalrightpage\doifrightpageelse} % move it there
-
-\ifx\swapmargins\undefined \let\swapmargins\undefined \fi % todo
-
-\def\doifswappedrightpageelse#1#2% alleen in box construction !
- {\doifrightpageelse
- {#1}
- {\scratchcounter\realpageno
- \realpageno\realpagestateno\relax
- \swapmargins
- \realpageno\scratchcounter
- #2}}
-
-\newbox\signaledrightpage % this way we can avoid interference, i.e. postpone placement
-
-\def\presignalrightpage {\global\setbox\signaledrightpage\hbox{\signalrightpage}}
-\def\postsignalrightpage{\ifvoid\signaledrightpage\else\box\signaledrightpage\fi}
-
-% The next feature is is used in:
-%
-% \definenumber[test][way=bypage]
-%
-% \def\Test
-% {\incrementnumber[test]\rawnumber[test]/%
-% \incrementnumber[test]\rawnumber[test]/%
-% \incrementnumber[test]\rawnumber[test]\space
-% \checkpagechange{oeps}\changedpage{oeps}\space
-% \ifpagechanged TRUE\else FALSE\fi}
-%
-% \Test\page \Test\par \Test\page \Test\par \Test\page \Test\page
-%
-% (adapted from cont-new.tex:)
-
-\newif\ifpagechanged \let\lastchangedpage\empty
-
-\def\docheckpagestatechange#1#2#3%
- {\pagechangedfalse
- \doforcedtrackpagestate{#2}{#3}%
- \findtwopassdata{#2}{\number#3}%
- \iftwopassdatafound
- \ifnum\twopassdata>0\getvalue{#2:p:#1}\relax
- \pagechangedtrue
- \fi
- \fi
- \ifpagechanged
- \letgvalue{#2:p:#1}\twopassdata
- \globallet\lastchangedpage\twopassdata
- \else
- \globallet\lastchangedpage\realfolio
- \fi}
-
-\def\changedpagestate#1#2%
- {\executeifdefined{#2:p:#1}{0}}
-
-\def\checkpagechange#1{\docheckpagestatechange{#1}\s!paragraph\nofraggedparagraphs}
-\def\changedpage #1{\changedpagestate{#1}\s!paragraph}
-
-% saved struts
-
-\ifx\savedstrutbox\undefined \newbox\savedstrutbox \fi
-
-\def\savestrut {\setbox\savedstrutbox\copy\strutbox}
-\def\savedstrut{\copy \savedstrutbox}
-
-% De onderstaande macro's zijn opgenomen in Plain TeX.
-%
-% \def\raggedright%
-% {\rightskip\z@ plus2em \spaceskip.3333em \xspaceskip.5em\relax}
-%
-% \def\ttraggedright%
-% {\tttf\rightskip\z@ plus2em\relax}
-%
-% \newif\ifr@ggedbottom
-%
-% \def\raggedbottom%
-% {\topskip 10\p@ plus60\p@ \r@ggedbottomtrue}
-%
-% \def\normalbottom%
-% {\topskip 10\p@ \r@ggedbottomfalse}
-%
-% en worden hieronder wat aangepast.
-
-% the three boolean will become obsolete some day in favour
-% of \bottomraggedness
-
-\chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
-
-\def\bottomalignlimit{3\lineheight}
-
-\newif\ifn@rmalbottom
-\newif\ifr@ggedbottom
-\newif\ifb@selinebottom
-
-\def\normalbottom
- {% \topskip 10pt
- \r@ggedbottomfalse}
-
-\def\raggedbottom
- {\chardef\bottomraggedness\zerocount
- \n@rmalbottomfalse
- \r@ggedbottomtrue
- \b@selinebottomfalse
- \settopskip}
-
-\def\alignbottom
- {\chardef\bottomraggedness\plusone
- \n@rmalbottomtrue
- \r@ggedbottomfalse
- \b@selinebottomfalse
- \settopskip}
-
-\def\baselinebottom
- {\chardef\bottomraggedness\plustwo
- \n@rmalbottomfalse
- \r@ggedbottomfalse
- \b@selinebottomtrue
- \settopskip}
-
-\let\normalbottom=\alignbottom % downward compatible
-
-% so, the new one will be
-%
-% \chardef\bottomraggedness=0 % 0=ragged 1=normal/align 2=baseline
-%
-% \def\bottomalignlimit{3\lineheight} % will be settable
-%
-% \def\raggedbottom {\chardef\bottomraggedness=0 \settopskip}
-% \def\alignbottom {\chardef\bottomraggedness=1 \settopskip}
-% \def\baselinebottom{\chardef\bottomraggedness=2 \settopskip}
-%
-% \let\normalbottom =\alignbottom
-
-% \hyphenpenalty = ( 2.5 * \hsize ) / \raggedness
-% \tolerance >= 1500 % was 200
-% \raggedness = 2 .. 6\bodyfontsize
-
-\chardef\raggedstatus=0 % normal left center right
-
-\def\leftraggedness {2\bodyfontsize}
-\def\rightraggedness {2\bodyfontsize}
-\def\middleraggedness {6\bodyfontsize}
-
-\def\middleraggedness {.5\hsize} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
-
-% oeps, hsize can be 0pt in which case we get a strange division
-
-\def\middleraggedness {\ifdim\hsize=\zeropoint6\bodyfontsize\else.5\hsize\fi} % was: 6\bodyfontsize, fails on: \placefigure{x $x=x$ x}{}
-
-%D More hyphenation control, will be combined with align
-%D setup.
-
-\def\nohyphens
- {\ifx\dohyphens\relax
- \edef\dohyphens
- {\hyphenpenalty\the\hyphenpenalty
- \exhyphenpenalty\the\exhyphenpenalty\relax}%
- \fi
- \hyphenpenalty\plustenthousand
- \exhyphenpenalty\plustenthousand}
-
-\let\dohyphens\relax
-
-%D To prevent unwanted side effects, we also have to check
-%D for hyphens here:
-
-% \def\setraggedness#1%
-% {\ifnum\tolerance<1500\relax % small values have
-% \tolerance1500\relax % unwanted side effects
-% \fi
-% \spaceskip2.5\hsize % we misuse these registers
-% \xspaceskip#1\relax % for temporary storage;
-% \divide\spaceskip \xspaceskip % they are changed anyway
-% \ifx\dohyphens\relax
-% \hyphenpenalty\spaceskip % \else no hyphens is active
-% \fi}
-
-\newskip\@@raggedskipa
-\newskip\@@raggedskipb
-
-\def\setraggedness#1%
- {\ifnum\tolerance<1500\relax % small values have
- \tolerance1500\relax % unwanted side effects
- \fi
- \ifx\dohyphens\relax
- % this code will be reconsidered / kind of fuzzy (and old)
- \@@raggedskipa 2.5\hsize
- \@@raggedskipb #1\relax
- \divide\@@raggedskipa \@@raggedskipb
- \hyphenpenalty\@@raggedskipa
- \fi}
-
-\let\updateraggedskips\relax
-
-\def\setraggedskips#1#2#3#4#5#6#7% never change this name
- {\def\updateraggedskips{\dosetraggedskips{#1}{#2}{#3}{#4}{#5}{#6}{#7}}%
- \updateraggedskips}
-
-\def\dosetraggedskips#1#2#3#4#5#6#7%
- {\chardef \raggedstatus#1\relax
- \leftskip 1\leftskip \!!plus#2\relax % zie: Tex By Topic 8.1.3
- \rightskip 1\rightskip\!!plus#3\relax % zie: Tex By Topic 8.1.3
- \spaceskip #4\relax
- \xspaceskip #5\relax
- \parfillskip\zeropoint\!!plus#6\relax
- \parindent #7\relax}
-
-% \def\notragged%
-% {\setraggedskips{0}{0em}{0em}{0em}{0em}{1fil}{\parindent}}
-
-% older (context) names:
-
-\let\spaceamount \interwordspace
-\let\emspaceamount\emwidth
-
-% tracing:
-
-\def\doshowpardata#1%
- {\ifx#1\relax\else
- \hbox{\string#1: \the#1}\endgraf
- \expandafter\doshowpardata
- \fi}
-
-\def\showpardata
- {\edef\thepardata
- {\hbox{font: \fontname\font}\endgraf
- \doshowpardata
- \interwordspace \interwordstretch \interwordshrink \emwidth \exheight \extraspace
- \hsize \vsize
- \leftskip \rightskip
- \spaceskip \xspaceskip
- \parindent \parfillskip
- \hyphenpenalty \exhyphenpenalty
- \displaywidowpenalty \widowpenalty \clubpenalty \brokenpenalty
- \doublehyphendemerits \finalhyphendemerits \adjdemerits
- \relax}%
- \begingroup
- \dontshowcomposition
- \inleftmargin{\vsmash
- {\switchtobodyfont[7pt,tt]%
- \framed[\c!align=\v!right]{\thepardata}}}%
- \endgroup}
-
-\def\startshowpardata
- {\begingroup
- \showcomposition
- \showstruts\tracepositionstrue \tracingparagraphs\maxdimen
- \appendtoksonce\showpardata\let\showpardata\relax\to\everypar}
-
-\def\stopshowpardata
- {\endgraf
- \endgroup}
-
-% \defineXMLenvironment[showpardata] \startshowpardata \stopshowpardata
-% \defineXMLsingular [showpardata] \showpardata
-
-% defaults
-
-\def\raggedfillamount {1fil}
-\def\raggedhalffillamount{.5fil}
-\def\raggedspaceamount {\interwordspace} % {.3333em}
-\def\raggedxspaceamount {.5em}
-
-\def\notragged
- {\chardef\raggedstatus\zerocount
- \leftskip 1\leftskip
- \rightskip 1\rightskip
- \spaceskip \zeropoint
- \xspaceskip \zeropoint
- \parfillskip\zeropoint\!!plus\raggedfillamount\relax
- \let\updateraggedskips\relax} % new
-
-\let\forgetragged\notragged
-
-\def\raggedleft
- {\setraggedness\leftraggedness
- \setraggedskips1\leftraggedness\zeropoint\raggedspaceamount
- \raggedxspaceamount\zeropoint\zeropoint}
-
-\def\raggedcenter
- {\setraggedness\middleraggedness
- \setraggedskips2\middleraggedness\middleraggedness\raggedspaceamount
- \raggedxspaceamount\zeropoint\zeropoint}
-
-%D We used to have:
-%D
-%D \starttyping
-%D \def\raggedright
-%D {\setraggedness\rightraggedness
-%D \setraggedskips{3}{0em}{\rightraggedness}{.3333em}{.5em}{0em}{\parindent}}
-%D \stoptyping
-%D
-%D However, the next alternative, suggested by Taco, is better.
-
-\def\raggedright
- {\setraggedness\rightraggedness
- \setraggedskips3\zeropoint\rightraggedness\raggedspaceamount
- \raggedxspaceamount\raggedfillamount\parindent}
-
-\def\veryraggedleft
- {\setraggedskips1\raggedfillamount\zeropoint\raggedspaceamount
- \raggedxspaceamount\zeropoint\zeropoint}
-
-%D When we want the last line to have a natural width:
-%D
-%D \starttyping
-%D \def\veryraggedleft%
-%D {\setraggedskips{1}{1fil}{0em}{.3333em}{.5em}{0em}{-1fil}}
-%D \stoptyping
-%D
-%D but this one is not accepted by the macros.
-
-\def\veryraggedcenter
- {\setraggedskips2\raggedfillamount\raggedfillamount\raggedspaceamount
- \raggedxspaceamount\zeropoint\zeropoint}
-
-\def\veryraggedright
- {\setraggedskips3\zeropoint\raggedfillamount\raggedspaceamount
- \raggedxspaceamount\zeropoint\parindent}
-
-\def\ttraggedright
- {\tttf
- \setraggedskips3\zeropoint\rightraggedness
- \zeropoint\zeropoint\zeropoint\parindent} % \ctxparindent
-
-%D A bonus one:
-
-\def\raggedwidecenter
- {\setraggedness\middleraggedness
- \setraggedskips2\raggedhalffillamount\raggedhalffillamount
- \raggedspaceamount\raggedxspaceamount\zeropoint\zeropoint}
-
-\newif\if@@asragged \@@asraggedtrue % old method
-
-% todo
-%
-% \setuplayout[grid=yes,lines=44] \showgrid
-% \starttext
-% test \vfill test \endgraf \strut \endgraf \vskip-\lineheight \removedepth \pagina test
-% \stoptext
-
-% \setupalign[reset,new,right,old]
-
-\def\@@align@@rl{\if!!donea\veryraggedleft \else\raggedleft \fi}
-\def\@@align@@rr{\if!!donea\veryraggedright \else\raggedright \fi}
-\def\@@align@@rc{\if!!donea\veryraggedcenter\else\raggedcenter\fi}
-
-\setvalue{@@ngila@@\v!broad }{\!!doneatrue}
-\setvalue{@@ngila@@\v!wide }{\!!donebtrue}
-
-\def\installalign#1#2{\setvalue{@@align@@#1}{#2}} % can be used for overloads
-
-\installalign \v!new {\@@asraggedfalse}
-\installalign \v!old {\@@asraggedtrue}
-\installalign \empty {}
-
-\installalign \v!line {\baselinebottom}
-\installalign \v!bottom {\raggedbottom}
-\installalign \v!height {\normalbottom}
-\installalign \v!width {\notragged}
-\installalign \v!normal {\notragged}
-\installalign \v!yes {\notragged}
-\installalign \v!no {\raggedright}
-\installalign \v!inner {\if@@asragged \setraggedparagraphmode\@@align@@rl\@@align@@rr \else
- \setraggedparagraphmode\@@align@@rr\@@align@@rl \fi}
-\installalign \v!outer {\if@@asragged \setraggedparagraphmode\@@align@@rr\@@align@@rl \else
- \setraggedparagraphmode\@@align@@rl\@@align@@rr \fi}
-\installalign \v!left {\if@@asragged\@@align@@rl\else\@@align@@rr\fi}
-\installalign \v!right {\if@@asragged\@@align@@rr\else\@@align@@rl\fi}
-\installalign \v!middle {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
-\installalign \v!flushleft {\if!!donea\veryraggedright \else\raggedright\fi}
-\installalign \v!flushright {\if!!donea\veryraggedleft \else\raggedleft \fi}
-\installalign \v!flushouter {\setraggedparagraphmode\raggedleft\raggedright}
-\installalign \v!flushinner {\setraggedparagraphmode\raggedright\raggedleft}
-\installalign \v!center {\if!!doneb\raggedwidecenter\else\@@align@@rc\fi}
-\installalign \v!hanging {\enableprotruding}
-\installalign \v!nothanging {\disableprotruding}
-\installalign \v!hz {\enableadjusting}
-\installalign \v!nohz {\disableadjusting}
-\installalign \v!spacing {\enablespacehandling \enablekernhandling}
-\installalign \v!nospacing {\disablespacehandling\disablekernhandling}
-\installalign \v!hyphenated {\dohyphens}
-\installalign \v!nothyphenated {\nohyphens}
-\installalign \v!new {\@@asraggedfalse} % so new will give you consistency
-\installalign \v!reset {\notragged\normalbottom}
-
-\installalign \v!tolerant {\tolerance3000 \relax}
-\installalign \v!verytolerant {\tolerance4500 \relax}
-\installalign \v!stretch {\emergencystretch\bodyfontsize}
-
-\installalign \v!grid {\mkenablegridsnapping } % only mkiv
-\installalign \v!nogrid {\mkdisablegridsnapping} % only mkiv
-
-\newcount\hyphenminoffset
-
-\ifx\sethyphenationvariables\undefined \let\sethyphenationvariables\relax \fi
-
-\def\lesshyphens
- {\advance\hyphenminoffset\plusone
- \sethyphenationvariables}
-
-\def\morehyphens
- {\ifcase\hyphenminoffset \else
- \advance\hyphenminoffset\minusone
- \fi
- \sethyphenationvariables}
-
-\installalign \v!lesshyphenation {\lesshyphens}
-\installalign \v!morehyphenation {\morehyphens}
-
-\def\dodosetupalign#1{\csname @@align@@#1\endcsname}
-\def\dodosetupngila#1{\csname @@ngila@@#1\endcsname}
-
-\def\setupalign
- {\dosingleargument\dosetupalign}
-
-\def\dosetupalign[#1]% can be made faster by checking for defined #1
- {\!!doneafalse
- \!!donebfalse
- \processcommacommand[#1]\dodosetupngila
- \processcommacommand[#1]\dodosetupalign}
-
-% \setupalign[flushleft] \input ward \par % lijnlinks
-% \setupalign[right] \input ward \par
-
-% \setupalign[flushright] \input ward \par % lijnrechts
-% \setupalign[left] \input ward \par
-
-% \setupalign[middle] \input ward \par % centreer
-% \setupalign[center] \input ward \par
-
-\def\startalignment
- {\bgroup
- \setupalign}
-
-\def\stopalignment
- {\par
- \egroup}
-
-\chardef\alignstrutmode=1
-
-% see later for the real definition, which in the simple case is:
-
-\newtoks \everyleftofalignedline
-\newtoks \everyrightofalignedline
-
-\def\shiftalignedline#1#2#3#4% left, right, inner, outer
- {\rightorleftpageaction
- {\everyleftofalignedline {\hskip\dimexpr#1+#3\relax}%
- \everyrightofalignedline{\hskip\dimexpr#2+#4\relax}}
- {\everyleftofalignedline {\hskip\dimexpr#1+#4\relax}%
- \everyrightofalignedline{\hskip\dimexpr#2+#3\relax}}}
-
-% \def\doalignline#1#2% \\ == newline
-% {\begingroup
-% \setlocalhsize % new
-% \def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
-% \dowithnextbox
-% {\noindentation % was \noindent
-% \dontleavehmode % added in marrakesch at TUG 2006
-% \hbox to \localhsize
-% {\ifcase\alignstrutmode\or\strut\fi
-% \the\everyleftofalignedline
-% #1\unhbox\nextbox#2\relax
-% \the\everyrightofalignedline}%
-% \endgroup}
-% \hbox}
-
-\def\doalignline#1#2% \\ == newline
- {\noindentation % was \noindent
- \dontleavehmode % added in marrakesch at TUG 2006\begingroup
- \begingroup
- \setlocalhsize % new
- \def\\{\egroup\par\doalignline{#1}{#2}\bgroup}%
- \dowithnextbox
- {\hbox to \localhsize
- {\ifcase\alignstrutmode\or\strut\fi
- \the\everyleftofalignedline
- #1\unhbox\nextbox#2\relax
- \the\everyrightofalignedline}%
- \endgroup}
- \hbox}
-
-% directe commando's
-
-\def\leftaligned {\doalignline \relax \hss }
-\def\midaligned {\doalignline \hss \hss }
-\def\rightaligned{\doalignline \hss \relax}
-
-\def\regelbegrensd#1{\limitatetext{#1}{\hsize}{\unknown}} % to be translated
-
-% indirecte commando's
-
-\letvalue{\s!do\v!line\v!left }\leftaligned
-\letvalue{\s!do\v!line\v!right }\rightaligned
-\letvalue{\s!do\v!line\v!middle }\midaligned
-\letvalue{\s!do\v!line\v!flushleft }\rightaligned
-\letvalue{\s!do\v!line\v!flushright}\leftaligned
-\letvalue{\s!do\v!line\v!center }\midaligned
-
-\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
-
-%D Experimental:
-
-% simple version
-%
-% \def\doxalignline#1#2%
-% {\bgroup
-% \setlocalhsize
-% \def\\{\egroup\par\doxalignline{#1}{#2}\bgroup}% inefficient
-% \dowithnextbox
-% {\noindent\hbox to \localhsize
-% {\ifcase\alignstrutmode\or\strut\fi
-% \signalrightpage
-% \doifrightpageelse{#1\unhbox\nextbox#2}{#2\unhbox\nextbox#1}}%
-% \egroup}
-% \hbox}
-%
-% \setvalue{\s!do\v!regel\v!binnen}{\doxalignline\relax\hss}
-% \setvalue{\s!do\v!regel\v!buiten}{\doxalignline\hss\relax}
-%
-% more extensive:
-
-\def\doxalignline#1#2#3#4#5#6%
- {\noindentation % was \noindent
- \dontleavehmode % added in marrakesch at TUG 2006\begingroup
- \begingroup
- \setlocalhsize
- \def\\{\egroup\par\doxalignline#1#2#3#4#5#6\bgroup}% inefficient
- \dowithnextbox
- {%\noindent moved up
- \hbox to \localhsize
- {#1\hskip\ifdone#2\else#3\fi#4%
- \hbox to \localhsize
- {\the\everyleftofalignedline
- \ifcase\alignstrutmode\or\strut\fi
- \ifdone#5\unhbox\nextbox#6\else#6\unhbox\nextbox#5\fi
- \the\everyrightofalignedline}%
- \hss}%
- \endgroup}
- \hbox}
-
-\def\doxcheckline
- {\signalrightpage\doifrightpageelse\donetrue\donefalse}
-
-\setvalue{\s!do\v!line\v!inner }{\doxalignline\doxcheckline++\zeropoint \relax\hss }
-\setvalue{\s!do\v!line\v!outer }{\doxalignline\doxcheckline++\zeropoint \hss \relax}
-\setvalue{\s!do\v!line\v!innermargin}{\doxalignline\doxcheckline-+\innermargintotal\relax\hss }
-\setvalue{\s!do\v!line\v!outermargin}{\doxalignline\doxcheckline+-\outermargintotal\hss \relax}
-\setvalue{\s!do\v!line\v!inneredge }{\doxalignline\doxcheckline-+\inneredgetotal \relax\hss }
-\setvalue{\s!do\v!line\v!outeredge }{\doxalignline\doxcheckline+-\outeredgetotal \hss \relax}
-\setvalue{\s!do\v!line\v!backspace }{\doxalignline\doxcheckline-+\backspace \relax\hss }
-\setvalue{\s!do\v!line\v!cutspace }{\doxalignline\doxcheckline+-\cutspace \hss \relax}
-
-\setvalue{\s!do\v!line\v!leftmargin }{\doxalignline\donefalse --\leftmargintotal \hss \relax}
-\setvalue{\s!do\v!line\v!rightmargin}{\doxalignline\donefalse ++\rightmargintotal\relax\hss }
-\setvalue{\s!do\v!line\v!leftedge }{\doxalignline\donefalse --\leftedgetotal \hss \relax}
-\setvalue{\s!do\v!line\v!rightedge }{\doxalignline\donefalse ++\rightedgetotal \relax\hss }
-
-% ! ! ! beware, redefining \doalignline gives the wrong results ! ! !
-%
-% \def\doalignline{\doxalignline\donefalse++\zeropoint}
-
-%D Better:
-
-\def\doalignedline#1{\csname\s!do\v!line#1\endcsname}
-
-% \def\alignedline#1#2% setting default
-% {\csname
-% \s!do\v!line
-% \ifundefined{\s!do\v!line#1}#2\else#1\fi
-% \endcsname}
-
-\def\alignedline#1#2% setting default
- {\csname\s!do\v!line\ifcsname\s!do\v!line#1\endcsname#1\else#2\fi\endcsname}
-
-%D ...
-
-\def\dosetuptolerance[#1]%
- {\doifinsetelse\v!vertical{#1}%
- {\ExpandFirstAfter\processallactionsinset
- [#1]
- [ \v!verystrict=>\def\bottomtolerance{},
- \v!strict=>\def\bottomtolerance{.050},
- \v!tolerant=>\def\bottomtolerance{.075},
- \v!verytolerant=>\def\bottomtolerance{.100}]}%
- {\ExpandFirstAfter\processallactionsinset
- [#1]
- [ \v!stretch=>\emergencystretch\bodyfontsize,
- \v!space=>\spaceskip.5em\!!plus.25em\!!minus.25em\relax,
- \v!verystrict=>\tolerance 200,
- \v!strict=>\tolerance1500,
- \v!tolerant=>\tolerance3000,
- \v!verytolerant=>\tolerance4500]}}
-
-\def\setuptolerance
- {\dosingleargument\dosetuptolerance}
-
-% \def\woordrechts
-% {\groupedcommand{\hfill\hbox}{\parfillskip\zeropoint}}
-
-% beware: \wordright{whatever\kern-\rightskip} should work!
-% so, no funny boxing here
-
-\def\dowordright[#1]%
- {% don't change
- \groupedcommand
- {\removeunwantedspaces
- \hfill
- \allowbreak % changed back from \hskip\zeropoint
- \strut
- \hfill
- \quad % decent spacing
- \hbox}
- {\doifelse{#1}\v!right{\kern-\rightskip}{\doifsomething{#1}{\kern-#1}}%
- \parfillskip\zeropoint
- %\finalhyphendemerits\zerocount % yes or no
- \par}}
-
-\def\wordright
- {\dosingleempty\dowordright}
-
-% \dorecurse{5}{something } \wordright{--someone} \endgraf
-% \dorecurse{6}{something } \wordright{--someone} \endgraf
-% \dorecurse{7}{something } \wordright{--someone} \endgraf
-%
-% \dorecurse{5}{something } \wordright{--someone else entirely} \endgraf
-% \dorecurse{6}{something } \wordright{--someone else entirely} \endgraf
-% \dorecurse{7}{something } \wordright{--someone else entirely} \endgraf
-%
-% \wordright[\rightskip]{whatever}
-
-% \simplealignedbox{2cm}{right}{x}
-
-\setvalue{\s!simple\c!align\v!right }#1#2{\hbox to #1{#2\hss}}
-\setvalue{\s!simple\c!align\v!left }#1#2{\hbox to #1{\hss#2}}
-\setvalue{\s!simple\c!align\v!flushright }#1#2{\hbox to #1{\hss#2}}
-\setvalue{\s!simple\c!align\v!flushleft }#1#2{\hbox to #1{#2\hss}}
-\setvalue{\s!simple\c!align\v!middle }#1#2{\hbox to #1{\hss#2\hss}}
-
-\def\simplealignedbox#1{\executeifdefined{\s!simple\c!align#1}{\getvalue{\s!simple\c!align\v!right}}}
-
-%D \macros
-%D {pushindentation,popindentation}
-%D
-%D The pushing and popping is done by:
-
-\newbox\indentationboxA
-\newbox\indentationboxB
-
-\def\pushindentation
- {\bgroup
- \ifhmode
- \unskip
- \setbox\indentationboxA\lastbox % get \strut if present
- \unskip
- \setbox\indentationboxB\lastbox % get \indent generated box
- \unskip
- \else
- \hskip\zeropoint % switch to horizontal mode
- \unskip
- \setbox\indentationboxA\lastbox % get \indent generated box
- \setbox\indentationboxB\box\voidb@x
- \fi}
-
-\def\popindentation
- {\box\indentationboxB\box\indentationboxA % put back the boxes
- \egroup}
-
-%D The only complication lays in \type{\strut}. In \PLAIN\
-%D \TEX\ a \type{\strut} is defined as:
-%D
-%D \starttyping
-%D \def\strut%
-%D {\relax\ifmmode\copy\strutbox\else\unhcopy\strutbox\fi}
-%D \stoptyping
-%D
-%D But what is a \type{\strut}? Normally it's a rule of width
-%D zero, but when made visual, it's a rule and a negative skip.
-%D The mechanism for putting things in the margins described
-%D here cannot handle this situation very well. One
-%D characteristic of \type{\strut} is that the \type{\unhcopy}
-%D results in entering horizontal mode, which in return leads
-%D to some indentation.
-%D
-%D To serve our purpose a bit better, the macro \type{\strut}
-%D can be redefined as:
-%D
-%D \starttyping
-%D \def\strut
-%D {\relax\ifmmode\else\hskip0pt\fi\copy\strutbox}
-%D \stoptyping
-%D
-%D Or more compatible:
-%D
-%D \starttyping
-%D \def\strut
-%D {\relax\ifmmode
-%D \copy\strutbox
-%D \else
-%D \bgroup\setbox\strutbox=\normalhbox{\box\strutbox}\unhcopy\strutbox\egroup
-%D \fi}
-%D \stoptyping
-%D
-%D In \CONTEXT\ however we save some processing time by putting
-%D an extra \type{\hbox} around the \type{\strutbox}.
-
-% moved from page-lin.tex to here (due to visualization added
-% in august 2003)
-%
-% \unexpanded \def\crlf
-% {\ifhmode\unskip\else\strut\fi\ifcase\raggedstatus\hfil\fi\break}
-
-\unexpanded \def\crlf
- {\ifhmode
- \unskip
- \prewordbreak\crlfplaceholder
- \ifcase\raggedstatus\hfil\or\or\or\hfil\fi
- \break
- \else
- \crlfplaceholder
- \endgraf
- \fi}
-
-\def\crlfplaceholder
- {\strut}
-
-\def\settestcrlf
- {\def\crlfplaceholder
- {\hbox to \zeropoint
- {\strut{\infofont\kern.25em}\lohi{\infofont CR}{\infofont LF}\hss}}}
-
-%D \starttyping
-%D % \setuplayout[gridgrid=yes] \showgrid
-%D
-%D \startbuffer
-%D test 1\crlf
-%D test 2\crlf
-%D
-%D \crlf test 3
-%D
-%D test 4\crlf
-%D test 5
-%D
-%D \crlf
-%D \crlf
-%D \crlf
-%D test 6
-%D \stopbuffer
-%D
-%D \hbox
-%D {\hsize5em
-%D \ruledvtop{\getbuffer}\enspace
-%D \ruledvtop{\showstruts\getbuffer}\enspace
-%D \hsize15em \setuptyping[before=,after=]%
-%D \ruledvtop{\typebuffer}}
-%D \stoptyping
-
-\def\opeenregel % to be used grouped
- {\def\crlf{\removelastspace\space}\let\\\crlf}
-
-\def\showstruts
- {\setteststrut
- \settestcrlf}
-
-\def\definehspace
- {\dotripleempty\dodefinehspace}
-
-\def\dodefinehspace[#1][#2][#3]% #1 = optional namespace
- {\ifthirdargument
- \setvalue{\??hs#1:#2}{#3}%
- \else
- \setvalue{\??hs:#1}{#2}%
- \fi}
-
-\unexpanded\def\hspace
- {\dodoubleempty\dohspace}
-
-%\def\dohspace[#1][#2]%
-% {\ifhmode
-% \removeunwantedspaces
-% \hskip
-% \ifsecondargument
-% \hspaceamount{#1}{#2}%
-% \else
-% \hspaceamount\empty{\iffirstargument#1\else\s!default\fi}%
-% \fi
-% \expandafter\ignorespaces
-% \fi}
-
-\def\dohspace[#1][#2]%
- {\ifsecondargument
- \dodohspace[#1][#2]%
- \else\iffirstargument
- \hspace[][#1]%
- \else
- \hspace[][\s!default]%
- \fi\fi}
-
-% \def\dodohspace[#1][#2#3]%
-% {\ifhmode
-% \removeunwantedspaces
-% \doifelse{#2}{-}
-% {{\scratchskip\hspaceamount{#1}{#3}\hskip-\scratchskip}}
-% {\hskip\hspaceamount{#1}{#2#3}}%
-% \expandafter\ignorespaces
-% \fi}
-%
-% not needed, tex handles -- as +
-
-\def\dodohspace[#1][#2]%
- {\ifhmode
- \removeunwantedspaces
- \hskip\hspaceamount{#1}{#2}%
- \expandafter\ignorespaces
- \fi}
-
-\def\hspaceamount#1#2%
- {\executeifdefined{\??hs#1:#2}{\executeifdefined{\??hs:#2}\zeropoint}}
-
-\definehspace [\v!small] [.25\emspaceamount]
-\definehspace [\v!medium] [.5\emspaceamount]
-\definehspace [\v!big] [1\emspaceamount]
-\definehspace [\v!normal] [1\spaceamount]
-\definehspace [\v!default] [\spaceamount]
-
-%D Taken from Taco's math module (cq. \AMS\ macros), but
-%D adapted to \type {\hspace}:
-
-\unexpanded\def\textormathspace#1#2#3%
- {\ifmmode\mskip#1#2\else\kern#1\hspaceamount\empty{#3}\fi\relax}
-
-\newmuskip\hairmuskip \hairmuskip=.15mu
-
-\def\hairspace {\textormathspace+\hairmuskip{.5}}
-\def\thinspace {\textormathspace+\thinmuskip 1}
-\def\medspace {\textormathspace+\medmuskip 2}
-\def\thickspace {\textormathspace+\thickmuskip3}
-\def\neghairspace {\textormathspace-\thinmuskip{.5}}
-\def\negthinspace {\textormathspace-\thinmuskip 1}
-\def\negmedspace {\textormathspace-\medmuskip 2}
-\def\negthickspace{\textormathspace-\thickmuskip3}
-
-% needed for unicode:
-
-\def\twoperemspace {\hskip\dimexpr\emwidth/2\relax} % == \enspace
-\def\threeperemspace {\hskip\dimexpr\emwidth/3\relax}
-\def\fourperemspace {\hskip\dimexpr\emwidth/4\relax}
-\def\fiveperemspace {\hskip\dimexpr\emwidth/5\relax} % goodie
-\def\sixperemspace {\hskip\dimexpr\emwidth/6\relax}
-\def\figurespace {\begingroup\setbox\scratchbox\hbox{0}\hskip\wd\scratchbox\endgroup} % there is a command for this
-\def\punctuationspace {\begingroup\setbox\scratchbox\hbox{.}\hskip\wd\scratchbox\endgroup}
-\def\ideographicspace {\hskip\dimexpr\emwidth/1\relax}
-\def\ideographichalffillspace{\hskip\dimexpr\emwidth/2\relax}
-\def\nobreakspace {\penalty\plustenthousand\space}
-\def\narrownobreakspace {\penalty\plustenthousand\thinspace}
-\def\zerowidthnobreakspace {\penalty\plustenthousand\hskip\zeropoint}
-\def\zerowidthspace {\hskip\zeropoint}
-
-\definehspace[.5][.1250\emspaceamount] % could also be [.1250\spaceamount]
-\definehspace[1] [.1667\emspaceamount]
-\definehspace[2] [.2222\emspaceamount]
-\definehspace[3] [.2777\emspaceamount]
-
-\let \, \thinspace
-\let \: \medspace
-\let \; \thickspace
-\let \! \negthinspace
-
-% this will become an alternative bunch of \blank settings
-%
-% \startlines
-% \scratchskip=.23pt plus 10pt minus 4pt \relax \number\scratchskip \space \the\scratchskip
-% \setsimplifiedskip\scratchskip1 \number\scratchskip \space \the\scratchskip
-% \setsimplifiedskip\scratchskip2 \number\scratchskip \space \the\scratchskip
-% \getsimplifiedskip\scratchskip\scratchcounter \number\scratchcounter
-% \stoplines
-%
-% \hrule width10cm \endgraf
-% \discardedskip{10pt}
-% \retainedskip {4pt}
-% \discardedskip {5pt}
-% \hrule width10cm \endgraf
-% \blockedskip{0pt}
-% \discardedskip{10pt}
-% \retainedskip {4pt}
-% \discardedskip {5pt}
-% \hrule width10cm \endgraf
-% \frozenskip {4cm}
-% \hrule width10cm \endgraf
-% \vskip10pt
-% \hrule width10cm \endgraf
-
-% ! ! ! etex only, evt splitskip macro gebruiken (syst-new)
-
-\newskip\simplifiedskip
-\newskip\simplifiedcounter
-
-\chardef\@@discardedskip1
-\chardef\@@retainedskip 2
-\chardef\@@forcedskip 3
-\chardef\@@blockedskip 4
-\chardef\@@frozenskip 5 % after heads, no break
-
-\def\setsimplifiedskip#1#2%
- {#1\dimexpr(10\dimexpr(#1/10)) plus \gluestretch#1 minus \glueshrink#1\relax
- \advance#1\numexpr(#2)sp\relax}
-
-\def\getsimplifiedskip#1#2%
- {\simplifiedskip#1\relax
- \ifzeropt\simplifiedskip % \ifdim\simplifiedskip=\zeropoint
- #2\zerocount
- \else
- \simplifiedcounter\dimexpr10\dimexpr#1/10\relax\relax
- \advance\simplifiedskip-\simplifiedcounter
- #2\number\simplifiedskip\relax
- \fi}
-
-\def\conditionalskip#1#2%
- {\scratchskip#1\relax
- \setsimplifiedskip\scratchskip#2\relax
- \vskip\scratchskip\relax}
-
-\def\defrostskip
- {\scratchskip\lastskip\penalty50000\normalvskip-\scratchskip\penalty50000\relax}
-
-\def\frozenskip#1%
- {\endgraf
- \ifvmode
- \getsimplifiedskip\lastskip\scratchcounter
- \ifdim\lastskip>#1\else
- \defrostskip
- \conditionalskip{#1}\@@frozenskip
- \fi
- \fi}
-
-\def\discardedskip#1%
- {\endgraf
- \ifvmode
- \getsimplifiedskip\lastskip\scratchcounter
- \ifcase\scratchcounter
- \conditionalskip{#1}\@@discardedskip
- \or % discard
- \ifdim\lastskip>#1\else
- \normalvskip-\lastskip
- \conditionalskip{#1}\@@discardedskip
- \fi
- \or % retain
- \ifdim\lastskip>#1\else
- \normalvskip-\lastskip
- \conditionalskip{#1}\@@discardedskip
- \fi
- \or % forced
- \conditionalskip{#1}\@@discardedskip
- \or % ignored
- \or % frozen
- \ifdim\lastskip>#1\else
- \defrostskip
- \conditionalskip{#1}\@@frozenskip
- \fi
- \else\ifdim#1=\zeropoint\else
- \vskip#1\relax
- \fi\fi
- \fi}
-
-\def\retainedskip#1%
- {\endgraf
- \ifvmode
- \getsimplifiedskip\lastskip\scratchcounter
- \ifcase\scratchcounter
- \conditionalskip{#1}\@@retainedskip
- \or % discard
- \normalvskip-\lastskip
- \conditionalskip{#1}\@@retainedskip
- \or % retain
- \ifdim\lastskip>#1\else
- \normalvskip-\lastskip
- \conditionalskip{#1}\@@retainedskip
- \fi
- \or % forced
- \conditionalskip{#1}\@@retainedskip
- \or % ignored
- \or % frozen
- \ifdim\lastskip>#1\else
- \defrostskip
- \conditionalskip{#1}\@@frozenskip
- \fi
- \else\ifdim#1=\zeropoint\else
- \vskip#1\relax
- \fi\fi
- \fi}
-
-\def\forcedskip#1%
- {\endgraf
- \ifvmode
- \conditionalskip{#1}\@@forcedskip
- \fi}
-
-\def\blockedskip#1%
- {\endgraf
- \ifvmode
- \getsimplifiedskip\lastskip\scratchcounter
- \ifcase\scratchcounter
- \conditionalskip{#1}\@@blockedskip
- \or % discard
- \conditionalskip{#1}\@@blockedskip
- \or % retain
- \conditionalskip{#1}\@@blockedskip
- \or % forced
- \conditionalskip{#1}\@@blockedskip
- \or % ignored
- \or % frozen
- \ifdim\lastskip>#1\else
- \defrostskip
- \conditionalskip{#1}\@@frozenskip
- \fi
- \else\ifdim#1=\zeropoint\else
- \vskip#1\relax
- \fi\fi
- \fi}
-
-% beware, changing this will break some code (like pos/backgrounds)
-
-\newtoks\everyfirstparagraphintro
-\newtoks\everynextparagraphintro
-\newtoks\@@everyparagraphtoks
-
-\chardef\everyparagraphintro\zerocount
-
-\def\setupparagraphintro
- {\dodoubleempty\dosetupparagraphintro}
-
-\def\dosetupparagraphintro[#1][#2]%
- {\processallactionsinset
- [#1]
- [ \v!reset=>\global\chardef\everyparagraphintro\zerocount
- \global\everyfirstparagraphintro\emptytoks
- \global\everynextparagraphintro \emptytoks,
- \v!first=>\global\chardef\everyparagraphintro\plusone
- \doglobal\appendtoks#2\to\everyfirstparagraphintro,
- \v!next=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plusone\fi
- \doglobal\appendtoks#2\to\everynextparagraphintro,
- \v!each=>\ifcase\everyparagraphintro\global\chardef\everyparagraphintro\plustwo\fi
- \doglobal\appendtoks#2\to\everyfirstparagraphintro
- \doglobal\appendtoks#2\to\everynextparagraphintro]}
-
-%D We can say:
-%D
-%D \starttyping
-%D \setupparagraphintro[first][\index{Knuth}]
-%D \stoptyping
-%D
-%D Maybe more convenient is:
-%D
-%D \starttyping
-%D \flushatparagraph{\index{Zapf}}
-%D \stoptyping
-
-\def\flushatparagraph#1%
- {\global\chardef\everyparagraphintro\plusone
- \global\appendtoks{#1}\to\everyfirstparagraphintro}
-
-% \def\doinsertparagraphintro
-% {\ifcase\everyparagraphintro\relax
-% % no data
-% \@@everyparagraphtoks\emptytoks
-% \or
-% % first data
-% \global\chardef\everyparagraphintro\plustwo
-% \@@everyparagraphtoks\everyfirstparagraphintro
-% \global\everyfirstparagraphintro\emptytoks
-% \or
-% % next data
-% \@@everyparagraphtoks\everynextparagraphintro
-% \fi
-% \the\@@everyparagraphtoks}
-
-\def\doinsertparagraphintro
- {\begingroup
- \everypar\emptytoks
- \ifcase\everyparagraphintro\relax
- % no data
- \@@everyparagraphtoks\emptytoks
- \or
- % first data
- \global\chardef\everyparagraphintro\plustwo
- \@@everyparagraphtoks\everyfirstparagraphintro
- \global\everyfirstparagraphintro\emptytoks
- \or
- % next data
- \@@everyparagraphtoks\everynextparagraphintro
- \fi
- \the\@@everyparagraphtoks
- \endgroup}
-
-\def\insertparagraphintro
- {\ifcase\everyparagraphintro\else\@EA\doinsertparagraphintro\fi}
-
-% \appendtoksonce\insertparagraphintro\to\everypar % should come last
-
-%D \starttyping
-%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
-%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
-%D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT \hss}]
-%D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN \hss}]
-%D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH \hss}]
-%D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA \hss}]
-%D
-%D some paragraph \par
-%D some paragraph \par
-%D some paragraph \par
-%D
-%D \definelabel[parnumber]
-%D
-%D \setupparagraphintro[reset,each][\inleft{\slxx\parnumber}]
-%D
-%D some paragraph \par
-%D some paragraph \par
-%D some paragraph \par
-%D \stoptyping
-
-%D \macros
-%D {flushatnextpar}
-%D
-%D This macro collects data that will be flushed at the next paragraph.
-%D By using this macro you can avoid interfering nodes (writes, etc).
-
-\newbox \postponednodedata
-
-\def\flushatnextpar
- {\bgroup
- \dowithnextbox
- {\global\setbox\postponednodedata\hbox{\box\postponednodedata\box\nextbox}\egroup}%
- \hbox}
-
-\def\flushpostponednodedata
- {\ifvoid\postponednodedata\else
- \hbox{\smashedbox\postponednodedata}%
- \fi}
-
-% Very nasty but needed for margin stuff inside colored
-% paragraphs.
-
-\let\normalvadjust\vadjust
-
-% \def\graphicvadjust % bad, those low level color calls here
-% {\dowithnextbox
-% {\normalvadjust
-% {\dostartgraphicgroup
-% \localstarttextcolor
-% \unvbox\nextbox
-% \localstoptextcolor
-% \dostopgraphicgroup}}%
-% \vbox}
-
-% test this prikkels/pascal margin text before heads (mode
-% 1) as well as uitwerkingen (mode 2)
-
-%chardef\graphicvadjustmode=0 % fake
-%chardef\graphicvadjustmode=1 % normal
-\chardef\graphicvadjustmode=2 % normal + compensate (== default)
-
-\def\graphicvadjust % bad, those low level color calls here
- {\dowithnextboxcontent
- {\forgetall}
- {\ifcase\graphicvadjustmode \@EA \fakedvadjust \else \@EA\normalvadjust \fi
- {\dostartgraphicgroup % don't ask
- \localstarttextcolor
- \unvbox\nextbox
- \localstoptextcolor % don't ask
- \dostopgraphicgroup
- \ifcase\graphicvadjustmode \or \or
- % corrects for one line paragraphs
- \nointerlineskip
- \kern-\struttotal
- \nointerlineskip
- \verticalstrut
- \fi}}%
- \vbox}
-
-%D This works only in a properly strutted line, and is meant
-%D for deeply burried operations, like in heads.
-
-\def\fakedvadjust
- {\dowithnextbox
- {\setbox\nextbox\hbox{\llap{\lower\strutdepth\box\nextbox}}%
- \smashedbox\nextbox}%
- \vtop}
-
-\def\flexiblespaceamount#1#2#3%
- {#1\interwordspace
- \!!plus#2\interwordstretch
- \!!minus#3\interwordshrink}
-
-\def\fixedspaceamount#1%
- {#1\interwordspace}
-
-%D This is a dangerous feature because it makes the \TEX\ source
-%D less portable, i.e. any parser now needs to apply exactly the
-%D same algorithm when it wants to interpret the source. We
-%D strongly recommend not to mention this feature in manuals! It's
-%D provided for users who are hooked to such a mechanism.
-%D
-%D \starttyping
-%D \setupsorting[logo][next=\autoinsertnextspace] \logo[TEX]{\TeX}
-%D
-%D bla bla \TEX bla bla \TEX (bla) bla (\TEX)
-%D \stoptyping
-
-\def\autoinsertnextspace{\futurelet\nexttoken\doautoinsertnextspace}
-
-\def\doautoinsertnextspace % slightly extended version of a user supplied macro
- {\ifx\nexttoken \bgroup\else \ifx\nexttoken\begingroup\else
- \ifx\nexttoken \egroup\else \ifx\nexttoken \endgroup\else
- \ifx\nexttoken \/\else \ifx\nexttoken /\else \ifx\nexttoken ~\else
- \ifx\nexttoken \ \else \ifx\nexttoken \blankspace\else \ifx\nexttoken \space\else
- \ifx\nexttoken .\else \ifx\nexttoken ,\else
- \ifx\nexttoken !\else \ifx\nexttoken ?\else
- \ifx\nexttoken :\else \ifx\nexttoken ;\else
- \ifx\nexttoken '\else \ifx\nexttoken "\else
- \ifx\nexttoken )\else \ifx\nexttoken -\else \ifx\nexttoken |\else
- \ifx\nexttoken \%\else \ifx\nexttoken \&\else
- \space
- \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi}
-
-% moved from page-lin
-
-\def\installspacehandler#1#2% needs to set \obeyedspace
- {\setvalue{\??sr#1}{#2}}
-
-\installspacehandler \v!on
- {\obeyspaces
- \def\obeyedspace{\mathortext\normalspace{\dontleavehmode{\tt\controlspace}}}%
- \let\ =\obeyedspace}
-
-\installspacehandler \v!yes
- {\obeyspaces
- \def\obeyedspace{\mathortext\normalspace{\dontleavehmode \normalspace }}%
- \let\ =\obeyedspace}
-
-\installspacehandler \v!off
- {\normalspaces
- \let\obeyedspace\normalspace
- \let\ =\normalspace}
-
-\installspacehandler \v!fixed
- {\obeyspaces
- \def\obeyedspace{\mathortext\normalspace{\dontleavehmode\fixedspace}}%
- \let\ =\obeyedspace}
-
-\def\activatespacehandler#1%
- {\executeifdefined{\??sr#1}{\activatespacehandler\v!off}}
-
-% moved from page-lin
-
-%D When spacing is active we need to handle commands in
-%D a special way:
-%D
-%D \starttyping
-%D \setuplines[space=on]
-%D
-%D \startlines
-%D Let's talk about this{\ttsl\gobbleoneargument or}that.
-%D \stoplines
-%D
-%D \startlines
-%D Let's talk about this{\getvalue{ttsl}or}that.
-%D \stoplines
-%D \stoptyping
-%D
-%D One can indent in several ways:
-%D
-%D \starttyping
-%D \setupindenting[medium] \setuplines[indenting=odd] % no yes odd even
-%D
-%D \startlines
-%D first
-%D second
-%D third
-%D fourth
-%D \stoplines
-%D \stoptyping
-
-\def\setuplines
- {\dodoubleargument\getparameters[\??rg]}
-
-\def\startlines
- {\@@rgbefore
- \pushmacro\checkindentation
- \whitespace
- %\page[\v!preference]} gaat mis na koppen, nieuw: later \nobreak
- \begingroup
- \setupindenting[\@@rgindenting]%
- \typesettinglinestrue
- \setupwhitespace[\v!none]%
- \obeylines
- \ignorespaces
- \gdef\afterfirstobeyedline % tzt two pass, net als opsomming
- {\gdef\afterfirstobeyedline
- {\nobreak
- \global\let\afterfirstobeyedline\relax}}%
- \def\obeyedline
- {\par
- \afterfirstobeyedline
- \futurelet\next\dobetweenthelines}%
- \activatespacehandler\@@rgspace
- \GotoPar}
-
-\def\stoplines
- {\endgroup
- \popmacro\checkindentation
- \@@rgafter}
-
-\def\dobetweenthelines
- {\doifmeaningelse\next\obeyedline\@@rginbetween\donothing}
-
-\setuplines
- [\c!before=\blank,
- \c!after=\blank,
- \c!inbetween=\blank,
- \c!indenting=\v!no,
- \c!space=\v!default]
-
-\def\emptylines
- {\dosingleempty\doemptylines}
-
-\def\doemptylines[#1]%
- {\endgraf\dorecurse{\iffirstargument#1\else3\fi}\crlf}
-
-% plugins
-
-\loadmarkfile{core-spa}
-
-\setupwhitespace
- [\v!none]
-
-% still old-fashioned
-
-\indenting
- [\v!never]
-
-\setupindenting
- [\v!none]
-
-\setupblank
- [\v!standard,
- \v!big]
-
-\defineblank[\v!default] [\currentblank]
-\defineblank[\v!before] [\v!default]
-\defineblank[\v!inbetween][\v!default]
-\defineblank[\v!after] [\v!before]
-
-\setupinterlinespace
- [\c!minheight=0pt, % only special purpose
- \c!mindepth=0pt, % only special purpose
- \c!height=.72,
- \c!depth=.28,
- \c!top=1.0,
- \c!bottom=0.4,
- \c!distance=1pt,
- \c!line=2.8ex,
- \c!stretch=0]
-
-\setupnarrower
- [\c!before=\endgraf,
- \c!after=\endgraf,
- \c!left=1.5em,
- \c!right=1.5em,
- \c!middle=1.5em]
-
-\setuptolerance
- [\v!horizontal,\v!verystrict]
-
-\setuptolerance
- [\v!vertical,\v!strict]
-
-\setupalign
- [\v!bottom,
- \v!width]
-
-\setupspacing
- [\v!packed]
-
-\protect \endinput
diff --git a/tex/context/base/core-stg.tex b/tex/context/base/core-stg.tex
index 94e5250e5..429e1e894 100644
--- a/tex/context/base/core-stg.tex
+++ b/tex/context/base/core-stg.tex
@@ -12,7 +12,7 @@
%C details.
%D This is a prelude to strategies. It is rather old code
-%D used in a project may years ago. Use with care since I
+%D used in a project many years ago. Use with care since I
%D will pick up this thread. (moved from cont-new)
\unprotect
@@ -28,7 +28,7 @@
\definetwopasslist{\s!strategy}
-\def\registerstrategypass%
+\def\registerstrategypass
{\ifnum\currentstrategypass>\maximumstrategypass \else
\ifconditional\strategypassforced
\doglobal\increment\currentstrategypass
diff --git a/tex/context/base/core-syn.lua b/tex/context/base/core-syn.lua
deleted file mode 100644
index 10bd9d6d9..000000000
--- a/tex/context/base/core-syn.lua
+++ /dev/null
@@ -1,127 +0,0 @@
-if not modules then modules = { } end modules ['core-syn'] = {
- version = 1.001,
- comment = "companion to core-syn.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
-sorters = sorters or { }
-sorters.list = sorters.list or { }
-
-function sorters.list.compare(a,b)
- return sorters.comparers.basic(a,b,1)
-end
-
-function sorters.list.prepare(data)
- sorters.prepare(data,sorters.splitters.utf,1)
-end
-
-function sorters.list.sort(data)
- sorters.sort(data,sorters.list.compare)
-end
-
-function sorters.list.unique(data)
- sorters.unique(data)
-end
-
-function sorters.list.cleanup(data)
- sorters.cleanup(data)
-end
-
-function sorters.list.finalize(data) -- hm, this really needs documentation
- -- we use the same splitter as with indices
- local split = { }
- for k,v in ipairs(data) do
- local entry, tag = v[2][1][3][1], ""
- local se = sorters.entries[sorters.language]
- if se and se[entry] then
- if type(se[entry]) == "number" then
- entry = se[entry]
- end
- tag = se[entry]
- else
- entry = 0
- tag = "unknown"
- end
- split[entry] = split[entry] or { tag = tag, data = { } }
- split[entry].data[#split[entry].data+1] = v
- end
- return split
-end
-
--- for the moment we use the old structure, some day mkiv code
--- will be different: more structure, less mess
-
-local template = {
- entry = "\\synonymentry{%s}{%s}{%s}{%s}"
-}
-
-function sorters.list.flush(sorted,class)
- -- for the moment we don't add split data (letters) yet
- class = class or 'abbreviation'
- for k,v in ipairs(table.sortedkeys(sorted)) do
- for _, vv in ipairs(sorted[v].data) do
- tex.sprint(tex.ctxcatcodes,template.entry:format(class,vv[2][1][1],vv[2][1][2],vv[3]))
- end
- end
-end
-
-function sorters.list.process(data)
- return sorters.process('list',data)
-end
-
--- interface to tex end
-
-joblists = joblists or { }
-joblists.collected = joblists.collected or { }
-joblists.tobesaved = joblists.tobesaved or { }
-
-local collected, tobesaved = joblists.collected, joblists.tobesaved
-
-local function initializer()
- collected, tobesaved = joblists.collected, joblists.tobesaved
-end
-
-job.register('joblists.collected', joblists.tobesaved, initializer, nil)
-
-local function allocate(class)
- local d = tobesaved[class]
- if not d then
- d = {
- language = 'en',
- entries = { },
- sorted = false,
- class = class
- }
- tobesaved[class] = d
- end
- return d
-end
-
-local function collect(class)
- return collected[class]
-end
-
-joblists.define = allocate
-
--- this should be more generic, i.e. userdata = { meaning = "" }
--- or at least we should get rid of the { { } } which is a quick
--- hack to share code with the indexer
-
-function joblists.save_entry(class,kind,entry,key,meaning)
- local data = allocate(class).entries
- data[#data+1] = { kind, { { entry, key } }, meaning } -- { kind, entry, key, meaning }
-end
-
-function joblists.save_variable(class,key,value)
- if key == "l" then key = "language" end
- allocate(class)[key] = value
-end
-
-function joblists.process(class)
- local data = collect(class)
- if data then
- sorters.list.process(data)
- end
-end
diff --git a/tex/context/base/core-syn.mkii b/tex/context/base/core-syn.mkii
deleted file mode 100644
index b3fdb1738..000000000
--- a/tex/context/base/core-syn.mkii
+++ /dev/null
@@ -1,28 +0,0 @@
-%D \module
-%D [ file=core-syn,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Synonyms and Sorts,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\def\mkdefinesortedlist#1% class
- {\addutilityreset{#1}}
-
-\def\mksavesortedlistentry#1#2#3#4%
- {\immediatewriteutility{s e {#1} {#2} {#3} {#4}}}
-
-\def\mksavesortedlistvariable#1#2#3% class type value
- {\immediatewriteutility{s #2 {#1} {#3}}}
-
-\def\mkloadsortedlist#1% class
- {\doutilities{#1}\jobname{#1}\relax\relax}
-
-\protect \endinput
diff --git a/tex/context/base/core-syn.mkiv b/tex/context/base/core-syn.mkiv
deleted file mode 100644
index 3b5398b56..000000000
--- a/tex/context/base/core-syn.mkiv
+++ /dev/null
@@ -1,34 +0,0 @@
-%D \module
-%D [ file=core-syn,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Synonyms and Sorts,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\registerctxluafile{core-syn}{1.001}
-
-\def\mkdefinesortedlist#1% class
- {\ctxlua{joblists.define('#1')}}
-
-\def\mksavesortedlistentry#1#2#3#4% class key entry meaning
- {\ctxlua{joblists.save_entry('#1','e','#2',\!!bs#3\!!es,\!!bs#4\!!es)}}
-
-\def\mksavesortedlistvariable#1#2#3% class type value
- {\ctxlua{joblists.save_variable('#1','#2','#3')}}
-
-\def\mkloadsortedlist#1% class
- {\bgroup
- \getvalue{\s!set#1}%
- \ctxlua{joblists.process('#1')}%
- \getvalue{\s!reset#1}%
- \egroup}
-
-\protect \endinput
diff --git a/tex/context/base/core-syn.tex b/tex/context/base/core-syn.tex
index 926e58233..b5c87c487 100644
--- a/tex/context/base/core-syn.tex
+++ b/tex/context/base/core-syn.tex
@@ -11,17 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Synonyms and Sorts}
+\writestatus{loading}{ConTeXt Core Macros / Synonyms and Sorts}
\unprotect
-\ifx\mkdefinesortedlist\undefined
- \let\mkdefinesortedlist \gobbleoneargument
- \let\mksavesortedlistentry \gobblefourarguments
- \let\mksavesortedlistvariable\gobblethreearguments
- \let\mkloadsortedlist \gobbleoneargument
-\fi
-
% \checkdefined kan hierheen
% Formaat tex-utility-input-file <jobname.tui>:
@@ -86,7 +79,7 @@
\c!color=]%
\setupwhitespace[\v!none]%
%doutilities{#1}\jobname{#2}\relax\par % no longer \par
- \mkloadsortedlist{#1}%
+ \doutilities{#1}\jobname{#1}\relax\relax
\endgroup
\ifutilitydone\else\nowhitespace\fi}
@@ -101,7 +94,7 @@
\synonymmeaningfalse
\doattributes{\??sm#1}\c!synonymstyle\c!synonymcolor{#3}%
\else
- \explicithmode
+ \dontleavehmode
\doattributes{\??sm#1}\c!textstyle\c!textcolor{#2}%
\fi
\endgroup}
@@ -119,7 +112,7 @@
{\begingroup % anders in mathmode lege \hbox
\defconvertexpanded\asciisynonym{\getvalue{\??sm#1\c!expansion}}{#3}%
\defconvertexpanded\asciimeaning{\getvalue{\??sm#1\c!expansion}}{#4}%
- \mksavesortedlistentry{#1}{#2}{\asciisynonym}{\asciimeaning}%
+ \immediatewriteutility{s e {#1} {#2} {\asciisynonym} {\asciimeaning}}%
\endgroup}
\def\reprocesssynonym#1#2#3%
@@ -155,7 +148,7 @@
{\bgroup
\let\dosetsynonym\doloadsynonym
\showmessage\m!systems{19}{#2}%
- \mkloadsortedlist{#1}%
+ \doutilities{#1}\jobname{#1}\relax\relax
\egroup
\setvalue{\s!check#1}##1{}}
@@ -180,7 +173,7 @@
\def\doregistersynonymlanguage#1%
{\savesortlanguage{\getvalue{\??sm#1\s!language}}%
- \mksavesortedlistvariable{#1}{l}{\getvalue{\??sm#1\s!language}}}
+ \immediatewriteutility{s l {#1} {\getvalue{\??sm#1\s!language}}}}
\def\dodefinesynonyms[#1][#2][#3][#4]%
{\iffourthargument
@@ -210,7 +203,7 @@
\doregistersynonymlanguage{#1}%
\to \everysavesortkeys
\presetheadtext[#2=\Word{#2}]% changes the \if...argument
- \mkdefinesortedlist{#1}%
+ \addutilityreset{#1}%
\setvalue{\e!setup #2\e!endsetup}{\dodoubleargument\getparameters[\??sm#1]}% to be obsolete
\setvalue{\s!set #1}{\dosetsynonym{#1}}%
\setvalue{\s!reset #1}{\doresetsynonym{#1}}%
@@ -256,8 +249,7 @@
{\whitespace % ZONDER WITRUIMTE ETC ETC
\begingroup
\setupwhitespace[\v!none]%
- %doutilities{#1}\jobname{#1}\relax\par % brr \par
- \mkloadsortedlist{#1}%
+ \doutilities{#1}\jobname{#1}\relax\relax
\endgroup
\ifutilitydone\else\nowhitespace\fi}
@@ -266,7 +258,7 @@
% \def\doplacelistofsorts#1% NOG EEN RUWE VERSIE MAKEN
% {\startpacked
% %doutilities{#1}\jobname{#1}\relax\par
-% \mkloadsortedlist{#1}%
+% \doutilities{#1}\jobname{#1}\relax\relax
% \stoppacked}
\def\docompletelistofsorts#1#2%
@@ -280,7 +272,7 @@
% {\doplacelistofsorts{#1}}
\def\processsort#1#2#3%
- {\explicithmode
+ {\dontleavehmode
\begingroup % was \bgroup
\doattributes{\??so#1}\c!style\c!color{#2}%
\endgroup} % was \egroup
@@ -288,7 +280,7 @@
\def\dowritesort#1#2#3%
{\bgroup
\defconvertexpanded\asciisynonym{\getvalue{\??so#1\c!expansion}}{#3}%
- \mksavesortedlistentry{#1}{#2}{\asciisynonym}{}%
+ \immediatewriteutility{s e {#1} {#2} {\asciisynonym} {}}%
\egroup}
\def\synonymentry#1%
@@ -321,7 +313,7 @@
{\bgroup
\let\dosetsort\doloadsort
\showmessage\m!systems{20}{#2}%
- \mkloadsortedlist{#1}%
+ \doutilities{#1}\jobname{#1}\relax\relax
\egroup
\setvalue{\s!check#1}##1{}}
@@ -346,7 +338,7 @@
\def\doregistersortinglanguage#1%
{\savesortlanguage{\getvalue{\??so#1\s!language}}%
- \mksavesortedlistvariable{#1}{l}{\getvalue{\??so#1\s!language}}}
+ \immediatewriteutility{s l {#1} {\getvalue{\??so#1\s!language}}}}
\def\dodefinesorting[#1][#2][#3]%
{\getparameters[\??so#1]
@@ -370,7 +362,7 @@
\else
\setvalue{#1}{\dotripleempty\docomplexsort[][#1]}%
\fi
- \mkdefinesortedlist{#1}%
+ \addutilityreset{#1}%
\presetheadtext[#2=\Word{#2}]% after \ifthirdargument -)
\setvalue{\e!setup#2\e!endsetup}[##1]{\getparameters[\??so#1][##1]}% to be obsolete
\setvalue{\s!set#1}{\dosetsort{#1}}%
@@ -388,7 +380,7 @@
%D written by Taco.
\def\processlistofsorts[#1]%
- {\mkloadsortedlist{#1}}
+ {\doutilities{#1}\jobname{#1}\relax\relax}
\newcounter\nofsortedalphalists
@@ -410,10 +402,6 @@
% \def\whatever{ax,bx,qx,dx,rx,fx} \sortalphacommacommand\whatever \whatever \endgraf
% \stoptext
-%D Plugins.
-
-\loadmarkfile{core-syn}
-
%D Presets.
\definesynonyms
diff --git a/tex/context/base/core-sys.mkii b/tex/context/base/core-sys.mkii
index 6816364de..24975ffb6 100644
--- a/tex/context/base/core-sys.mkii
+++ b/tex/context/base/core-sys.mkii
@@ -11,4 +11,386 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D For the moment this file is empty.
+\writestatus{loading}{ConTeXt Core Macros / System}
+
+\unprotect
+
+%D Version checking:
+
+\def\newcontextversion#1%
+ {\doifelse{#1}\contextversion
+ {\let\newcontextversion\gobbleoneargument}
+ {\writeline
+ \writestatus{Fatal Error}{Your format does not match the base files!}%
+ \writeline
+ \writestatus{Format Version}{\contextversion\space\contextmark}%
+ \writestatus{Files Version}{#1}%
+ \batchmode
+ \normalend}}
+
+%D End of lines to the output. \TEX\ will map this onto the platform specific
+%D line ending. I hate this mess.
+
+%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
+\newlinechar=10 \edef\outputnewlinechar{^^J}
+
+% in case formats are shared:
+
+\def\initializenewlinechar
+ {\bgroup\newlinechar=10\xdef\outputnewlinechar{^^J}\egroup}
+
+%D Job names.
+
+\def\outputfilename {\@@svfile}
+\def\inputfilename {\@@svinputfile}
+\def\operatingsystem{\@@svtype}
+
+\let\jobfilename \jobname
+\let\jobfilesuffix\c!tex
+
+\def\splitjobfilename % todo: mkiv
+ {\resetsystemmode{suffix-\jobfilesuffix}%
+ \edef\ascii{\inputfilename}\defconvertedcommand\ascii\ascii
+ \splitstring\ascii\at.\to\jobfilename\and\jobfilesuffix
+ \lowercasestring\jobfilesuffix\to\jobfilesuffix
+ \doifnothing\jobfilename {\let\jobfilename \jobname}%
+ % todo and totest: \defconvertedcommand\jobfilename\jobfilename
+ \doifnothing\jobfilesuffix{\let\jobfilesuffix\c!tex}%
+ \setsystemmode{suffix-\jobfilesuffix}}
+
+% Some mechanisms (see x-res-01) use either \jobfilename or
+% \jobfilename.somesuffix, in which case we need to use the
+% full name if given or a default (like \jobfilename.xml);
+% this comes down to replacing the default tex suffix.
+
+\def\jobfullname{\jobfilename.\jobfilesuffix}
+
+\def\setjobfullname#1% #1 = default if not given
+ {\doifelsenothing\jobfilename
+ {\let\jobfullname\empty}
+ {\doif\jobfilesuffix\c!tex{\edef\jobfullname{\jobfilename.#1}}}}
+
+% ...
+
+\def\dosetupsystem[#1]%
+ {\getparameters[\??sv][#1]%
+ \setuprandomize[\@@svrandom]%
+ \beforesplitstring\@@svresolution\at dpi\to\@@svresolution
+ \let\outputresolution\@@svresolution
+ \ifcase\@@svn
+ % % 0 : unknown
+ \or
+ \setsystemmode\v!first % 1 : first run
+ \or
+ % % 2 : successive run
+ \or
+ \setsystemmode\v!first % 3 : first and only run
+ \or
+ \setsystemmode\v!last % 4 : (extra) last run
+ \fi
+% \processaction
+% [\@@svtype]
+% %[ mswin=>\edef\@@svline{\rawcharacter{13}\rawcharacter{10}}, % crlf
+% [ mswin=>\edef\@@svline{\rawcharacter{13}}, % cr % crlf
+% darwin=>\edef\@@svline{\rawcharacter{13}}, % cr
+% \s!unknown=>\edef\@@svline{\rawcharacter{10}}]% % lf
+ \splitjobfilename}
+
+% \edef\@@svline{\rawcharacter{10}} % unix is the most critical/sensitive system
+
+\let\systemendofline\outputnewlinechar % will become obsolete
+
+\def\setupsystem
+ {\dosingleargument\dosetupsystem}
+
+\def\systemparameter#1{\executeifdefined{\??sv#1}\empty}
+
+%D The system modes set by the setup command can be used in
+%D situations like:
+%D
+%D \starttyping
+%D \startmode[*first]
+%D \executesystemcommand{cleanupxml text.xml clean-text.xml}
+%D \stopmode
+%D
+%D \starttext
+%D \typefile{clean-text.xml}
+%D \stoptext
+%D \stoptyping
+
+\def\setuprandomize[#1]%
+ {\doifsomething{#1}
+ {\bgroup
+ % tex's time is in minutes
+ \scratchcounter\normaltime
+ \processaction
+ [#1]
+ [ \v!small=>\divide\scratchcounter 15, % 900,
+ \v!medium=>\divide\scratchcounter 30, % 1800,
+ \v!big=>\divide\scratchcounter 60, % 3600,
+ \v!normal=>\getnewrandomseed\scratchcounter,
+ \s!default=>\getnewrandomseed\scratchcounter,
+ \s!unknown=>\scratchcounter#1]%
+ \expanded{\setrandomseed{\the\scratchcounter}}%
+% \writestatus\m!systems{randomseed: \the\scratchcounter}%
+ \egroup}}
+
+
+\setupsystem
+ [\c!directory=,
+ \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
+ \c!resolution=600dpi,
+ \c!random=,
+ \c!file=\jobname,
+ \c!inputfile=\outputfilename,
+ \c!type=unix, % windows is normally less sensitive to handle
+ \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders
+
+%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix
+%D is more picky, so we default to the \type {cr}. I never understood why
+%D \type {crlf} was not used in all systems, since it makes most sense.
+
+\def\dostartglobaldefs#1#2%
+ {\edef\!!stringa{\the\globaldefs}%
+ \ifnum\globaldefs#10
+ \globaldefs-\globaldefs
+ \fi
+ \advance\globaldefs #21
+ \setevalue{@gd@\the\globaldefs}{\!!stringa}}
+
+\def\dostopglobaldefs
+ {\doifdefinedelse{@gd@\the\globaldefs}
+ {\globaldefs\getvalue{@gd@\the\globaldefs}\relax}
+ {\globaldefs\zerocount}}
+
+\def\startlocal {\dostartglobaldefs>-}
+\def\stoplocal {\dostopglobaldefs}
+\def\startglobal {\dostartglobaldefs<+}
+\def\stopglobal {\dostopglobaldefs}
+
+\def\complexstart[#1]{\bgroup\getvalue{\e!start#1}}
+\def\complexstop [#1]{\getvalue{\e!stop #1}\egroup}
+
+\let\simplestart\bgroup
+\let\simplestop \egroup
+
+\definecomplexorsimple\start
+\definecomplexorsimple\stop
+
+\def\dododefinestartstop[#1][#2]% todo: use indirect commands
+ {\getparameters
+ [\??be#1]
+ [\c!before=,
+ \c!after=,
+ \c!inbetween=,
+ \c!commands=,
+ \c!style=,
+ #2]%
+ \unexpanded\setvalue{#1}%
+ {\groupedcommand
+ {\getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color}
+ {\dostopattributes
+ \getvalue{\??be#1\c!inbetween}}}%
+ \setvalue{\e!start#1}%
+ {\getvalue{\??be#1\c!before}%
+ \bgroup
+ \getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color\empty}%
+ \setvalue{\e!stop#1}%
+ {\dostopattributes
+ \egroup
+ \getvalue{\??be#1\c!after}}}
+
+\def\dodefinestartstop[#1][#2]%
+ {\def\docommand##1{\dododefinestartstop[##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\definestartstop
+ {\dodoubleargument\dodefinestartstop}
+
+\def\dosetupstartstop[#1][#2]%
+ {\def\docommand##1{\getparameters[\??be##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\setupstartstop
+ {\dodoubleargument\dosetupstartstop}
+
+% \docommand kan niet worden gebruikt omdat deze macro
+% soms lokaal wordt gebruikt
+
+% te zijner tijd:
+%
+% \definevariable {pc} % ProtectedCommand
+%
+% \def\executeprotected#1%
+% {\csname\??pc\string#1\endcsname}
+%
+% \def\defineprotected#1#2%
+% {\expandafter\def\csname\??pc\string#2\endcsname}
+%
+% \def\defineunprotected#1%
+% {\def#1}
+%
+% \def\doprotected%
+% {\ifx\next\define
+% \let\next=\defineprotected
+% \else
+% \let\next=\executeprotected
+% \fi
+% \next}
+%
+% \def\unexpanded%
+% {\futurelet\next\doprotected}
+%
+% \unexpanded\define\ziezo{ziezo}
+%
+% \unexpanded\ziezo
+
+\def\complexdefine[#1]#2#3%
+ {\ifx#2\undefined
+ \else
+ \showmessage\m!systems4{\string#2}%
+ \fi
+ \ifcase0#1\def#2{#3}%
+ \or\def#2##1{#3}%
+ \or\def#2##1##2{#3}%
+ \or\def#2##1##2##3{#3}%
+ \or\def#2##1##2##3##4{#3}%
+ \or\def#2##1##2##3##4##5{#3}%
+ \or\def#2##1##2##3##4##5##6{#3}%
+ \or\def#2##1##2##3##4##5##6##7{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8##9{#3}%
+ \else\def#2{#3}%
+ \fi}
+
+\definecomplexorsimpleempty\define
+
+\unexpanded\def\macroname#1% brrr
+ {\executeifdefined{#1}\empty}
+
+\def\usecommands#1%
+ {\bgroup
+ \def\docommand##1{\setbox0\hbox{\getvalue{\string##1}##1}}%
+ \processcommalist[#1]\docommand
+ \egroup}
+
+\newif\ifforcefileexpansion % handy for document level overload
+
+%D The next implementation is about 4 times as faster than a
+%D processaction alternative on an string of average length.
+%D Since this feature is used in XML processing, it made sense
+%D to support this faster alternative. It's installable as well.
+
+\def\installexpander#1#2#3% changed, no longer \convert..\to...
+ {\setvalue{\s!do\c!expansion#1l}{#2}%
+ \setvalue{\s!do\c!expansion#1g}{#3}}%
+
+% \convertexpanded is obsolete
+
+\long\def\doconvertexpanded#1#2#3% #4 % [l|g] \cs {kind} {data}
+ {\csname % that we assign all exp a value
+ \s!do\c!expansion
+ \ifforcefileexpansion
+ \v!yes
+ \else\ifcsname\s!do\c!expansion#3#1\endcsname
+ #3%
+ \else
+ \s!default
+ \fi\fi
+ #1%
+ \endcsname#2}% #3
+
+\long\def\defconvertexpanded {\doconvertexpanded l}
+\long\def\gdefconvertexpanded{\doconvertexpanded g}
+
+\installexpander\v!command \defconvertedcommand \gdefconvertedcommand
+\installexpander\s!default \defconvertedargument \gdefconvertedargument
+\installexpander\empty \defconvertedargument \gdefconvertedargument
+\installexpander\v!no \defconvertedargument \gdefconvertedargument
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!strict \defreducedargument \gdefreducedargument
+\installexpander {utf} \defreducedtoutf \gdefreducedtoutf
+
+%installexpander {xml} {see xtag-ext}
+
+\def\dodefconvertedmeaning#1#2#3% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#3}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ #1#2\@@globalexpanded}
+
+\def\defconvertedmeaning {\dodefconvertedmeaning\defconvertedcommand}
+\def\gdefconvertedmeaning{\dodefconvertedmeaning\gdefconvertedcommand}
+
+\def\dodefreducedargument#1#2#3%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedargument {\dodefreducedargument\edef}
+\def\gdefreducedargument{\dodefreducedargument\xdef}
+
+% \setupindex[expansion=utf]\index{\eacute}
+
+\def\dodefreducedtoutf#1#2#3%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedtoutf {\dodefreducedtoutf\edef}
+\def\gdefreducedtoutf{\dodefreducedtoutf\xdef}
+
+% old syntax:
+
+\def\convertmeaning#1\to#2% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#1}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ \defconvertedcommand#2\@@globalexpanded}
+
+\def\reduceargument#1\to#2%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
+\def\reducetoutf#1\to#2%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
+% \setvalue{statevalue\v!stop }{0}
+% \setvalue{statevalue\v!start }{1}
+% \setvalue{statevalue\v!normaal}{2}
+% \setvalue{statevalue\v!leeg }{3}
+% \setvalue{statevalue\v!geen }{4}
+%
+% \def\setcurrentstate#1%
+% {\chardef\currentstate=0\getvalue{statevalue\getvalue{#1\c!state}\relax}
+%
+% \ifcase\currentstate ...
+
+\def\redo{\dorepeat} % [n*10], kind of obsolete
+
+% obsolete, use \dorecurse instead
+%
+% \def\herhaler {\repeater}
+% \def\herhaalmetcommando {\dorepeatwithcommand}
+
+\protect \endinput
diff --git a/tex/context/base/core-sys.mkiv b/tex/context/base/core-sys.mkiv
index 0cef6c236..073c29b66 100644
--- a/tex/context/base/core-sys.mkiv
+++ b/tex/context/base/core-sys.mkiv
@@ -1,6 +1,6 @@
%D \module
-%D [ file=core-sys,
-%D version=2006.09.18,
+%D [ file=core-sys, % moved from main-001
+%D version=1997.03.31,
%D title=\CONTEXT\ Core Macros,
%D subtitle=System,
%D author=Hans Hagen,
@@ -11,6 +11,371 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% we need to mkiv-ize this file !
+
+\writestatus{loading}{ConTeXt Core Macros / System}
+
+\unprotect
+
+%D Version checking:
+
+\def\newcontextversion#1%
+ {\doifelse{#1}\contextversion
+ {\let\newcontextversion\gobbleoneargument}
+ {\writeline
+ \writestatus{Fatal Error}{Your format does not match the base files!}%
+ \writeline
+ \writestatus{Format Version}{\contextversion\space\contextmark}%
+ \writestatus{Files Version}{#1}%
+ \batchmode
+ \normalend}}
+
+%D End of lines to the output. \TEX\ will map this onto the platform specific
+%D line ending. I hate this mess.
+
+%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
+\newlinechar=10 \edef\outputnewlinechar{^^J}
+
+% in case formats are shared:
+
+\def\initializenewlinechar
+ {\bgroup\newlinechar=10\xdef\outputnewlinechar{^^J}\egroup}
+
+%D Job names.
+
+\def\outputfilename {\@@svfile}
+\def\inputfilename {\@@svinputfile}
+\def\operatingsystem{\@@svtype}
+
+\let\jobfilename \jobname
+\let\jobfilesuffix\c!tex
+
+\def\splitjobfilename % todo: mkiv
+ {\resetsystemmode{suffix-\jobfilesuffix}%
+ \edef\ascii{\inputfilename}\defconvertedcommand\ascii\ascii
+ \splitstring\ascii\at.\to\jobfilename\and\jobfilesuffix
+ \lowercasestring\jobfilesuffix\to\jobfilesuffix
+ \doifnothing\jobfilename {\let\jobfilename \jobname}%
+ % todo and totest: \defconvertedcommand\jobfilename\jobfilename
+ \doifnothing\jobfilesuffix{\let\jobfilesuffix\c!tex}%
+ \setsystemmode{suffix-\jobfilesuffix}}
+
+% Some mechanisms (see x-res-01) use either \jobfilename or
+% \jobfilename.somesuffix, in which case we need to use the
+% full name if given or a default (like \jobfilename.xml);
+% this comes down to replacing the default tex suffix.
+
+\def\jobfullname{\jobfilename.\jobfilesuffix}
+
+\def\setjobfullname#1% #1 = default if not given
+ {\doifelsenothing\jobfilename
+ {\let\jobfullname\empty}
+ {\doif\jobfilesuffix\c!tex{\edef\jobfullname{\jobfilename.#1}}}}
+
+% ...
+
+\def\dosetupsystem[#1]%
+ {\getparameters[\??sv][#1]%
+ \setuprandomize[\@@svrandom]%
+ \beforesplitstring\@@svresolution\at dpi\to\@@svresolution
+ \let\outputresolution\@@svresolution
+ \ifcase\@@svn
+ % % 0 : unknown
+ \or
+ \setsystemmode\v!first % 1 : first run
+ \or
+ % % 2 : successive run
+ \or
+ \setsystemmode\v!first % 3 : first and only run
+ \or
+ \setsystemmode\v!last % 4 : (extra) last run
+ \fi
+% \processaction
+% [\@@svtype]
+% %[ mswin=>\edef\@@svline{\rawcharacter{13}\rawcharacter{10}}, % crlf
+% [ mswin=>\edef\@@svline{\rawcharacter{13}}, % cr % crlf
+% darwin=>\edef\@@svline{\rawcharacter{13}}, % cr
+% \s!unknown=>\edef\@@svline{\rawcharacter{10}}]% % lf
+ \splitjobfilename}
+
+% \edef\@@svline{\rawcharacter{10}} % unix is the most critical/sensitive system
+
+\let\systemendofline\outputnewlinechar % will become obsolete
+
+\def\setupsystem
+ {\dosingleargument\dosetupsystem}
+
+\def\systemparameter#1{\executeifdefined{\??sv#1}\empty}
+
+%D The system modes set by the setup command can be used in
+%D situations like:
+%D
+%D \starttyping
+%D \startmode[*first]
+%D \executesystemcommand{cleanupxml text.xml clean-text.xml}
+%D \stopmode
+%D
+%D \starttext
+%D \typefile{clean-text.xml}
+%D \stoptext
+%D \stoptyping
+
+\def\setuprandomize[#1]%
+ {\doifsomething{#1}
+ {\bgroup
+ % tex's time is in minutes
+ \scratchcounter\normaltime
+ \processaction
+ [#1]
+ [ \v!small=>\divide\scratchcounter 15, % 900,
+ \v!medium=>\divide\scratchcounter 30, % 1800,
+ \v!big=>\divide\scratchcounter 60, % 3600,
+ \v!normal=>\getnewrandomseed\scratchcounter,
+ \s!default=>\getnewrandomseed\scratchcounter,
+ \s!unknown=>\scratchcounter#1]%
+ \expanded{\setrandomseed{\the\scratchcounter}}%
+% \writestatus\m!systems{randomseed: \the\scratchcounter}%
+ \egroup}}
+
+\setupsystem
+ [\c!directory=,
+ \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
+ \c!resolution=600dpi,
+ \c!random=,
+ \c!file=\jobname,
+ \c!inputfile=\outputfilename,
+ \c!type=unix, % windows is normally less sensitive to handle
+ \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders
+
+%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix
+%D is more picky, so we default to the \type {cr}. I never understood why
+%D \type {crlf} was not used in all systems, since it makes most sense.
+
+\def\dostartglobaldefs#1#2%
+ {\edef\!!stringa{\the\globaldefs}%
+ \ifnum\globaldefs#10
+ \globaldefs-\globaldefs
+ \fi
+ \advance\globaldefs #21
+ \setevalue{@gd@\the\globaldefs}{\!!stringa}}
+
+\def\dostopglobaldefs
+ {\doifdefinedelse{@gd@\the\globaldefs}
+ {\globaldefs\getvalue{@gd@\the\globaldefs}\relax}
+ {\globaldefs\zerocount}}
+
+\def\startlocal {\dostartglobaldefs>-}
+\def\stoplocal {\dostopglobaldefs}
+\def\startglobal {\dostartglobaldefs<+}
+\def\stopglobal {\dostopglobaldefs}
+
+\def\complexstart[#1]{\bgroup\getvalue{\e!start#1}}
+\def\complexstop [#1]{\getvalue{\e!stop #1}\egroup}
+
+\let\simplestart\bgroup
+\let\simplestop \egroup
+
+\definecomplexorsimple\start
+\definecomplexorsimple\stop
+
+\def\dododefinestartstop[#1][#2]% todo: use indirect commands
+ {\getparameters
+ [\??be#1]
+ [\c!before=,
+ \c!after=,
+ \c!inbetween=,
+ \c!commands=,
+ \c!style=,
+ #2]%
+ \unexpanded\setvalue{#1}%
+ {\groupedcommand
+ {\getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color}
+ {\dostopattributes
+ \getvalue{\??be#1\c!inbetween}}}%
+ \setvalue{\e!start#1}%
+ {\getvalue{\??be#1\c!before}%
+ \bgroup
+ \getvalue{\??be#1\c!commands}%
+ \dostartattributes{\??be#1}\c!style\c!color\empty}%
+ \setvalue{\e!stop#1}%
+ {\dostopattributes
+ \egroup
+ \getvalue{\??be#1\c!after}}}
+
+\def\dodefinestartstop[#1][#2]%
+ {\def\docommand##1{\dododefinestartstop[##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\definestartstop
+ {\dodoubleargument\dodefinestartstop}
+
+\def\dosetupstartstop[#1][#2]%
+ {\def\docommand##1{\getparameters[\??be##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\setupstartstop
+ {\dodoubleargument\dosetupstartstop}
+
+% \docommand kan niet worden gebruikt omdat deze macro
+% soms lokaal wordt gebruikt
+
+% te zijner tijd:
+%
+% \definevariable {pc} % ProtectedCommand
+%
+% \def\executeprotected#1%
+% {\csname\??pc\string#1\endcsname}
+%
+% \def\defineprotected#1#2%
+% {\expandafter\def\csname\??pc\string#2\endcsname}
+%
+% \def\defineunprotected#1%
+% {\def#1}
+%
+% \def\doprotected%
+% {\ifx\next\define
+% \let\next=\defineprotected
+% \else
+% \let\next=\executeprotected
+% \fi
+% \next}
+%
+% \def\unexpanded%
+% {\futurelet\next\doprotected}
+%
+% \unexpanded\define\ziezo{ziezo}
+%
+% \unexpanded\ziezo
+
+\def\complexdefine[#1]#2#3%
+ {\ifx#2\undefined
+ \else
+ \showmessage\m!systems4{\string#2}%
+ \fi
+ \ifcase0#1\def#2{#3}%
+ \or\def#2##1{#3}%
+ \or\def#2##1##2{#3}%
+ \or\def#2##1##2##3{#3}%
+ \or\def#2##1##2##3##4{#3}%
+ \or\def#2##1##2##3##4##5{#3}%
+ \or\def#2##1##2##3##4##5##6{#3}%
+ \or\def#2##1##2##3##4##5##6##7{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8{#3}%
+ \or\def#2##1##2##3##4##5##6##7##8##9{#3}%
+ \else\def#2{#3}%
+ \fi}
+
+\definecomplexorsimpleempty\define
+
+\unexpanded\def\macroname#1% brrr
+ {\executeifdefined{#1}\empty}
+
+\def\usecommands#1%
+ {\bgroup
+ \def\docommand##1{\setbox0\hbox{\getvalue{\string##1}##1}}%
+ \processcommalist[#1]\docommand
+ \egroup}
+
+\newif\ifforcefileexpansion % handy for document level overload
+
+%D The next implementation is about 4 times as faster than a
+%D processaction alternative on an string of average length.
+%D Since this feature is used in XML processing, it made sense
+%D to support this faster alternative. It's installable as well.
+
+\def\installexpander#1#2#3% changed, no longer \convert..\to...
+ {\setvalue{\s!do\c!expansion#1l}{#2}%
+ \setvalue{\s!do\c!expansion#1g}{#3}}%
+
+% \convertexpanded is obsolete
+
+\long\def\doconvertexpanded#1#2#3% #4 % [l|g] \cs {kind} {data}
+ {\csname % that we assign all exp a value
+ \s!do\c!expansion
+ \ifforcefileexpansion
+ \v!yes
+ \else\ifcsname\s!do\c!expansion#3#1\endcsname
+ #3%
+ \else
+ \s!default
+ \fi\fi
+ #1%
+ \endcsname#2}% #3
+
+\long\def\defconvertexpanded {\doconvertexpanded l}
+\long\def\gdefconvertexpanded{\doconvertexpanded g}
+
+\installexpander\v!command \defconvertedcommand \gdefconvertedcommand
+\installexpander\s!default \defconvertedargument \gdefconvertedargument
+\installexpander\empty \defconvertedargument \gdefconvertedargument
+\installexpander\v!no \defconvertedargument \gdefconvertedargument
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
+\installexpander\v!strict \defreducedargument \gdefreducedargument
+\installexpander {utf} \defreducedtoutf \gdefreducedtoutf
+
+%installexpander {xml} {see xtag-ext}
+
+\def\dodefconvertedmeaning#1#2#3% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#3}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ #1#2\@@globalexpanded}
+
+\def\defconvertedmeaning {\dodefconvertedmeaning\defconvertedcommand}
+\def\gdefconvertedmeaning{\dodefconvertedmeaning\gdefconvertedcommand}
+
+\def\dodefreducedargument#1#2#3%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedargument {\dodefreducedargument\edef}
+\def\gdefreducedargument{\dodefreducedargument\xdef}
+
+% \setupindex[expansion=utf]\index{\eacute}
+
+\def\dodefreducedtoutf#1#2#3%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#3}%
+ \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
+
+\def\defreducedtoutf {\dodefreducedtoutf\edef}
+\def\gdefreducedtoutf{\dodefreducedtoutf\xdef}
+
+% old syntax:
+
+\def\convertmeaning#1\to#2% watch the double expansion !
+ {\bgroup
+ \honorunexpanded
+ \convertencodedtokens % can be overloaded
+ \xdef\@@globalexpanded{#1}%
+ \xdef\@@globalexpanded{\@@globalexpanded}%
+ \egroup
+ \defconvertedcommand#2\@@globalexpanded}
+
+\def\reduceargument#1\to#2%
+ {\begingroup
+ \reducetocoding[raw]%
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
+\def\reducetoutf#1\to#2%
+ {\begingroup
+ \reducetocoding[uc]%
+ \let\uchar\uchartoutf
+ \let\unicodechar\numbertoutf
+ \edef\ascii{#1}%
+ \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
+
\startruntimeluacode
\ctxlua {
environment.inputfilename = "\inputfilename"
@@ -19,5 +384,5 @@
environment.jobfilesuffix = "\jobfilesuffix"
}
\stopruntimeluacode
-
-\endinput
+
+\protect \endinput
diff --git a/tex/context/base/core-sys.tex b/tex/context/base/core-sys.tex
deleted file mode 100644
index 7e3aa3c04..000000000
--- a/tex/context/base/core-sys.tex
+++ /dev/null
@@ -1,401 +0,0 @@
-%D \module
-%D [ file=core-sys, % moved from main-001
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=System,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros (System)}
-
-\unprotect
-
-%D Version checking:
-
-\def\newcontextversion#1%
- {\doifelse{#1}\contextversion
- {\let\newcontextversion\gobbleoneargument}
- {\writeline
- \writestatus{Fatal Error}{Your format does not match the base files!}%
- \writeline
- \writestatus{Format Version}{\contextversion\space\contextmark}%
- \writestatus{Files Version}{#1}%
- \batchmode
- \normalend}}
-
-%D End of lines to the output. \TEX\ will map this onto the platform specific
-%D line ending. I hate this mess.
-
-%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
-\newlinechar=10 \edef\outputnewlinechar{^^J}
-
-% in case formats are shared:
-
-\appendtoks
- \bgroup\newlinechar=10\xdef\outputnewlinechar{^^J}\egroup
-\to \everyjob
-
-%D Job names.
-
-\def\outputfilename {\@@svfile}
-\def\inputfilename {\@@svinputfile}
-\def\operatingsystem{\@@svtype}
-
-\let\jobfilename \jobname
-\let\jobfilesuffix\c!tex
-
-\def\splitjobfilename % todo: mkiv
- {\resetsystemmode{suffix-\jobfilesuffix}%
- \edef\ascii{\inputfilename}\defconvertedcommand\ascii\ascii
- \splitstring\ascii\at.\to\jobfilename\and\jobfilesuffix
- \lowercasestring\jobfilesuffix\to\jobfilesuffix
- \doifnothing\jobfilename {\let\jobfilename \jobname}%
- % todo and totest: \defconvertedcommand\jobfilename\jobfilename
- \doifnothing\jobfilesuffix{\let\jobfilesuffix\c!tex}%
- \setsystemmode{suffix-\jobfilesuffix}}
-
-\appendtoks \splitjobfilename \to \everyjob
-
-% Some mechanisms (see x-res-01) use either \jobfilename or
-% \jobfilename.somesuffix, in which case we need to use the
-% full name if given or a default (like \jobfilename.xml);
-% this comes down to replacing the default tex suffix.
-
-\def\jobfullname{\jobfilename.\jobfilesuffix}
-
-\def\setjobfullname#1% #1 = default if not given
- {\doifelsenothing\jobfilename
- {\let\jobfullname\empty}
- {\doif\jobfilesuffix\c!tex{\edef\jobfullname{\jobfilename.#1}}}}
-
-% ...
-
-\def\dosetupsystem[#1]%
- {\getparameters[\??sv][#1]%
- \setuprandomize[\@@svrandom]%
- \beforesplitstring\@@svresolution\at dpi\to\@@svresolution
- \let\outputresolution\@@svresolution
- \ifcase\@@svn
- % % 0 : unknown
- \or
- \setsystemmode\v!first % 1 : first run
- \or
- % % 2 : successive run
- \or
- \setsystemmode\v!first % 3 : first and only run
- \or
- \setsystemmode\v!last % 4 : (extra) last run
- \fi
-% \processaction
-% [\@@svtype]
-% %[ mswin=>\edef\@@svline{\rawcharacter{13}\rawcharacter{10}}, % crlf
-% [ mswin=>\edef\@@svline{\rawcharacter{13}}, % cr % crlf
-% darwin=>\edef\@@svline{\rawcharacter{13}}, % cr
-% \s!unknown=>\edef\@@svline{\rawcharacter{10}}]% % lf
- \splitjobfilename}
-
-% \edef\@@svline{\rawcharacter{10}} % unix is the most critical/sensitive system
-
-\let\systemendofline\outputnewlinechar % will become obsolete
-
-\def\setupsystem
- {\dosingleargument\dosetupsystem}
-
-\def\systemparameter#1{\executeifdefined{\??sv#1}\empty}
-
-%D The system modes set by the setup command can be used in
-%D situations like:
-%D
-%D \starttyping
-%D \startmode[*first]
-%D \executesystemcommand{cleanupxml text.xml clean-text.xml}
-%D \stopmode
-%D
-%D \starttext
-%D \typefile{clean-text.xml}
-%D \stoptext
-%D \stoptyping
-
-\def\setuprandomize[#1]%
- {\doifsomething{#1}
- {\bgroup
- % tex's time is in minutes
- \scratchcounter\normaltime
- \processaction
- [#1]
- [ \v!small=>\divide\scratchcounter 15, % 900,
- \v!medium=>\divide\scratchcounter 30, % 1800,
- \v!big=>\divide\scratchcounter 60, % 3600,
- \v!normal=>\getnewrandomseed\scratchcounter,
- \s!default=>\getnewrandomseed\scratchcounter,
- \s!unknown=>\scratchcounter#1]%
- \expanded{\setrandomseed{\the\scratchcounter}}%
- \egroup}}
-
-\setupsystem
- [\c!directory=,
- \c!n=0, % 0:unknown 1: one run 2: first 3: successive 4: final run
- \c!resolution=600dpi,
- \c!random=,
- \c!file=\jobname,
- \c!inputfile=\outputfilename,
- \c!type=unix, % windows is normally less sensitive to handle
- \c!bodyfont=\normalizedlocalbodyfontsize] % of iets anders
-
-%D Remark: windows programs normally handle \type {cr|lf|crlf} but unix
-%D is more picky, so we default to the \type {cr}. I never understood why
-%D \type {crlf} was not used in all systems, since it makes most sense.
-
-\def\dostartglobaldefs#1#2%
- {\edef\!!stringa{\the\globaldefs}%
- \ifnum\globaldefs#10
- \globaldefs-\globaldefs
- \fi
- \advance\globaldefs #21
- \setevalue{@gd@\the\globaldefs}{\!!stringa}}
-
-\def\dostopglobaldefs
- {\doifdefinedelse{@gd@\the\globaldefs}
- {\globaldefs\getvalue{@gd@\the\globaldefs}\relax}
- {\globaldefs\zerocount}}
-
-\def\startlocal {\dostartglobaldefs>-}
-\def\stoplocal {\dostopglobaldefs}
-\def\startglobal {\dostartglobaldefs<+}
-\def\stopglobal {\dostopglobaldefs}
-
-\def\complexstart[#1]{\bgroup\getvalue{\e!start#1}}
-\def\complexstop [#1]{\getvalue{\e!stop #1}\egroup}
-
-\let\simplestart\bgroup
-\let\simplestop \egroup
-
-\definecomplexorsimple\start
-\definecomplexorsimple\stop
-
-\def\dododefinestartstop[#1][#2]% todo: use indirect commands
- {\getparameters
- [\??be#1]
- [\c!before=,
- \c!after=,
- \c!inbetween=,
- \c!commands=,
- \c!style=,
- #2]%
- \unexpanded\setvalue{#1}%
- {\groupedcommand
- {\getvalue{\??be#1\c!commands}%
- \dostartattributes{\??be#1}\c!style\c!color}
- {\dostopattributes
- \getvalue{\??be#1\c!inbetween}}}%
- \setvalue{\e!start#1}%
- {\getvalue{\??be#1\c!before}%
- \bgroup
- \getvalue{\??be#1\c!commands}%
- \dostartattributes{\??be#1}\c!style\c!color\empty}%
- \setvalue{\e!stop#1}%
- {\dostopattributes
- \egroup
- \getvalue{\??be#1\c!after}}}
-
-\def\dodefinestartstop[#1][#2]%
- {\def\docommand##1{\dododefinestartstop[##1][#2]}%
- \processcommalist[#1]\docommand}
-
-\def\definestartstop
- {\dodoubleargument\dodefinestartstop}
-
-\def\dosetupstartstop[#1][#2]%
- {\def\docommand##1{\getparameters[\??be##1][#2]}%
- \processcommalist[#1]\docommand}
-
-\def\setupstartstop
- {\dodoubleargument\dosetupstartstop}
-
-% \docommand kan niet worden gebruikt omdat deze macro
-% soms lokaal wordt gebruikt
-
-% te zijner tijd:
-%
-% \definevariable {pc} % ProtectedCommand
-%
-% \def\executeprotected#1%
-% {\csname\??pc\string#1\endcsname}
-%
-% \def\defineprotected#1#2%
-% {\expandafter\def\csname\??pc\string#2\endcsname}
-%
-% \def\defineunprotected#1%
-% {\def#1}
-%
-% \def\doprotected%
-% {\ifx\next\define
-% \let\next=\defineprotected
-% \else
-% \let\next=\executeprotected
-% \fi
-% \next}
-%
-% \def\unexpanded%
-% {\futurelet\next\doprotected}
-%
-% \unexpanded\define\ziezo{ziezo}
-%
-% \unexpanded\ziezo
-
-\def\complexdefine[#1]#2#3%
- {\ifx#2\undefined
- \else
- \showmessage\m!systems4{\string#2}%
- \fi
- \ifcase0#1\def#2{#3}%
- \or\def#2##1{#3}%
- \or\def#2##1##2{#3}%
- \or\def#2##1##2##3{#3}%
- \or\def#2##1##2##3##4{#3}%
- \or\def#2##1##2##3##4##5{#3}%
- \or\def#2##1##2##3##4##5##6{#3}%
- \or\def#2##1##2##3##4##5##6##7{#3}%
- \or\def#2##1##2##3##4##5##6##7##8{#3}%
- \or\def#2##1##2##3##4##5##6##7##8##9{#3}%
- \else\def#2{#3}%
- \fi}
-
-\definecomplexorsimpleempty\define
-
-\unexpanded\def\macroname#1% brrr
- {\executeifdefined{#1}\empty}
-
-\def\usecommands#1%
- {\bgroup
- \def\docommand##1{\setbox0\hbox{\getvalue{\string##1}##1}}%
- \processcommalist[#1]\docommand
- \egroup}
-
-\newif\ifforcefileexpansion % handy for document level overload
-
-%D The next implementation is about 4 times as faster than a
-%D processaction alternative on an string of average length.
-%D Since this feature is used in XML processing, it made sense
-%D to support this faster alternative. It's installable as well.
-
-\def\installexpander#1#2#3% changed, no longer \convert..\to...
- {\setvalue{\s!do\c!expansion#1l}{#2}%
- \setvalue{\s!do\c!expansion#1g}{#3}}%
-
-% \convertexpanded is obsolete
-
-\long\def\doconvertexpanded#1#2#3% #4 % [l|g] \cs {kind} {data}
- {\csname % that we assign all exp a value
- \s!do\c!expansion
- \ifforcefileexpansion
- \v!yes
- \else\ifcsname\s!do\c!expansion#3#1\endcsname
- #3%
- \else
- \s!default
- \fi\fi
- #1%
- \endcsname#2}% #3
-
-\long\def\defconvertexpanded {\doconvertexpanded l}
-\long\def\gdefconvertexpanded{\doconvertexpanded g}
-
-\installexpander\v!command \defconvertedcommand \gdefconvertedcommand
-\installexpander\s!default \defconvertedargument \gdefconvertedargument
-\installexpander\empty \defconvertedargument \gdefconvertedargument
-\installexpander\v!no \defconvertedargument \gdefconvertedargument
-\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
-\installexpander\v!yes \defconvertedmeaning \gdefconvertedmeaning
-\installexpander\v!strict \defreducedargument \gdefreducedargument
-\installexpander {utf} \defreducedtoutf \gdefreducedtoutf
-
-%installexpander {xml} {see xtag-ext}
-
-\def\dodefconvertedmeaning#1#2#3% watch the double expansion !
- {\bgroup
- \honorunexpanded
- \convertencodedtokens % can be overloaded
- \xdef\@@globalexpanded{#3}%
- \xdef\@@globalexpanded{\@@globalexpanded}%
- \egroup
- #1#2\@@globalexpanded}
-
-\def\defconvertedmeaning {\dodefconvertedmeaning\defconvertedcommand}
-\def\gdefconvertedmeaning{\dodefconvertedmeaning\gdefconvertedcommand}
-
-\def\dodefreducedargument#1#2#3%
- {\begingroup
- \reducetocoding[raw]%
- \edef\ascii{#3}%
- \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
-
-\def\defreducedargument {\dodefreducedargument\edef}
-\def\gdefreducedargument{\dodefreducedargument\xdef}
-
-% \setupindex[expansion=utf]\index{\eacute}
-
-\def\dodefreducedtoutf#1#2#3%
- {\begingroup
- \reducetocoding[uc]%
- \let\uchar\uchartoutf
- \let\unicodechar\numbertoutf
- \edef\ascii{#3}%
- \expandafter\endgroup\expandafter#1\expandafter#2\expandafter{\ascii}}
-
-\def\defreducedtoutf {\dodefreducedtoutf\edef}
-\def\gdefreducedtoutf{\dodefreducedtoutf\xdef}
-
-% old syntax:
-
-\def\convertmeaning#1\to#2% watch the double expansion !
- {\bgroup
- \honorunexpanded
- \convertencodedtokens % can be overloaded
- \xdef\@@globalexpanded{#1}%
- \xdef\@@globalexpanded{\@@globalexpanded}%
- \egroup
- \defconvertedcommand#2\@@globalexpanded}
-
-\def\reduceargument#1\to#2%
- {\begingroup
- \reducetocoding[raw]%
- \edef\ascii{#1}%
- \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
-
-\def\reducetoutf#1\to#2%
- {\begingroup
- \reducetocoding[uc]%
- \let\uchar\uchartoutf
- \let\unicodechar\numbertoutf
- \edef\ascii{#1}%
- \expandafter\endgroup\expandafter\edef\expandafter#2\expandafter{\ascii}}
-
-% \setvalue{statevalue\v!stop }{0}
-% \setvalue{statevalue\v!start }{1}
-% \setvalue{statevalue\v!normaal}{2}
-% \setvalue{statevalue\v!leeg }{3}
-% \setvalue{statevalue\v!geen }{4}
-%
-% \def\setcurrentstate#1%
-% {\chardef\currentstate=0\getvalue{statevalue\getvalue{#1\c!state}\relax}
-%
-% \ifcase\currentstate ...
-
-\def\redo{\dorepeat} % [n*10], kind of obsolete
-
-% obsolete, use \dorecurse instead
-%
-% \def\herhaler {\repeater}
-% \def\herhaalmetcommando {\dorepeatwithcommand}
-
-%D Plugins
-
-\loadmarkfile{core-sys}
-
-\protect \endinput
diff --git a/tex/context/base/core-trf.tex b/tex/context/base/core-trf.tex
index 2049667d0..c7fa8d42b 100644
--- a/tex/context/base/core-trf.tex
+++ b/tex/context/base/core-trf.tex
@@ -14,7 +14,7 @@
%D It may be that some functionality got lost. If it concerns
%D defined features, let me know and it will be sorted out.
-\writestatus{loading}{Context Core Macros / Transformations}
+\writestatus{loading}{ConTeXt Core Macros / Transformations}
\unprotect
@@ -200,6 +200,14 @@
\xdef\finalscaleboxxscale {\withoutpt\the\dimexpr\scax\points/\plushundred\relax}%
\xdef\finalscaleboxyscale {\withoutpt\the\dimexpr\scay\points/\plushundred\relax}}
+
+\setvalue{\??xy:\c!grid:\v!yes }{\getnoflines \fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\setvalue{\??xy:\c!grid:\v!height }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!depth }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight-\strutdepth\relax}}
+\setvalue{\??xy:\c!grid:\v!halfline}{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+.5\lineheight\relax}}
+\setvalue{\??xy:\c!grid:\v!fit }{\getrawnoflines\fighei\setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}}
+\letvalue{\??xy:\c!grid:\empty }\donothing
+
\def\checkscaleboxsettings
{\doifsomething{\scaleparameter\c!maxwidth }% can be defined in itself
{\setevalue{\currentscaletag\c!maxwidth }{\the\dimexpr\scaleparameter\c!maxwidth \relax}}%
@@ -207,19 +215,7 @@
{\setevalue{\currentscaletag\c!maxheight}{\the\dimexpr\scaleparameter\c!maxheight\relax}}%
\doifsomething{\scaleparameter\c!lines}
{\setevalue{\currentscaletag\c!height}{\the\dimexpr\scaleparameter\c!lines\lineheight\relax}}%
- \doifsomething{\scaleparameter\c!grid}
- {\processaction
- [\scaleparameter\c!grid]
- [ \v!yes=>\getnoflines\fighei
- \setevalue{\currentscaletag\c!height}{\the\noflines\lineheight},
- \v!height=>\getrawnoflines\fighei
- \setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+\strutdepth\relax},
- \v!depth=>\getrawnoflines\fighei
- \setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight-\strutdepth\relax},
- \v!halfline=>\getrawnoflines\fighei
- \setevalue{\currentscaletag\c!height}{\the\dimexpr\noflines\lineheight+.5\lineheight\relax},
- \v!fit=>\getrawnoflines\fighei
- \setevalue{\currentscaletag\c!height}{\the\noflines\lineheight}]}}
+ \getvalue{\??xy:\c!grid:\scaleparameter\c!grid}}
\def\setscaleboxbynature % where ! ! ! ! !
{\doifsomething{\scaleparameter\c!width }{\global\scaleboxdimx\scaleparameter\c!width }%
@@ -260,7 +256,7 @@
\docalculatescaleboxnorm\scaleboxdimx\c!wfactor\c!width \hsize \hsize
\donefalse}}}%
\ifdone
-\settrue\scaleboxscalingdone
+ \settrue\scaleboxscalingdone
\ifdim\scaleboxdimx>\scaleboxhsize
\global\scaleboxdimy\zeropoint \global\scaleboxdimx\scaleboxhsize
\else\ifdim\scaleboxdimy>\scaleboxvsize
@@ -327,7 +323,7 @@
#3\relax
\fi}}
-\def\docalculatescaleboxnorm#1#2#3#4#5% 2 3 parameters
+\def\docalculatescaleboxnorm#1#2#3#4#5% 2 3 parameters (dodo:speedup)
{\processaction
[\scaleparameter#2]
[ \v!max=>\global#1\dimexpr#4\relax,
diff --git a/tex/context/base/core-two.lua b/tex/context/base/core-two.lua
index 748c4eb97..5749d406d 100644
--- a/tex/context/base/core-two.lua
+++ b/tex/context/base/core-two.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['core-two'] = {
license = "see context related readme files"
}
+local remove, concat = table.remove, table.concat
+
local texprint = tex.print
--[[ldx--
@@ -49,21 +51,21 @@ end
function jobpasses.get(id)
local jti = collected[id]
if jti and #jti > 0 then
- tex.print(table.remove(jti,1))
+ texprint(remove(jti,1))
end
end
function jobpasses.first(id)
local jti = collected[id]
if jti and #jti > 0 then
- tex.print(jti[1])
+ texprint(jti[1])
end
end
function jobpasses.last(id)
local jti = collected[id]
if jti and #jti > 0 then
- tex.print(jti[#jti])
+ texprint(jti[#jti])
end
end
@@ -84,7 +86,7 @@ end
function jobpasses.list(id)
local jti = collected[id]
if jti then
- texprint(table.concat(jti,','))
+ texprint(concat(jti,','))
end
end
@@ -92,15 +94,15 @@ function jobpasses.doifinlistelse(id,str)
local jti = collected[id]
if jti then
local found = false
- for _, v in pairs(jti) do
+ for _, v in next, jti do
if v == str then
found = true
break
end
end
- cs.testcase(found)
+ commands.testcase(found)
else
- cs.testcase(false)
+ commands.testcase(false)
end
end
@@ -119,7 +121,7 @@ end
function jobpasses.getfield(id,index,tag,default)
local jti = collected[id]
- jti = jit and jti[index]
- texprint((jit and jti[tag]) or default)
+ jti = jti and jti[index]
+ texprint((jti and jti[tag]) or default)
end
diff --git a/tex/context/base/core-two.mkii b/tex/context/base/core-two.mkii
index a14586dc4..0f2e0048c 100644
--- a/tex/context/base/core-two.mkii
+++ b/tex/context/base/core-two.mkii
@@ -11,9 +11,72 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Two Pass Data}
+
+%D This is a rather old mechanism which has not changed much over
+%D time, apart from adding a few more selectors. This code used
+%D to be part of \type {core-uti}. The following examples demonstrate
+%D the interface.
+%D
+%D \startbuffer
+%D \definetwopasslist{test-1}
+%D
+%D \gettwopassdatalist{test-1} [\twopassdatalist=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D
+%D \definetwopasslist{test-2}
+%D
+%D \lazysavetwopassdata{test-2}{1}{x}
+%D \lazysavetwopassdata{test-2}{2}{y}
+%D \lazysavetwopassdata{test-2}{3}{z}
+%D
+%D \gettwopassdatalist{test-2} [\twopassdatalist=x,y,z]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=y]
+%D \gettwopassdata {test-2} [\twopassdata=z]
+%D \gettwopassdata {test-2} [\twopassdata=]
+%D
+%D \definetwopasslist{test-3}
+%D
+%D \lazysavetaggedtwopassdata{test-3}{1}{x}{a}
+%D \lazysavetaggedtwopassdata{test-3}{2}{y}{b}
+%D \lazysavetaggedtwopassdata{test-3}{3}{z}{c}
+%D
+%D \findtwopassdata{test-3}{x} [\twopassdata=a]
+%D \findtwopassdata{test-3}{y} [\twopassdata=b]
+%D \findtwopassdata{test-3}{z} [\twopassdata=c]
+%D \findtwopassdata{test-3}{w} [\twopassdata=]
+%D
+%D \definetwopasslist{test-4}
+%D
+%D \lazysavetwopassdata{test-4}{1}{A}
+%D \lazysavetwopassdata{test-4}{2}{B}
+%D \lazysavetwopassdata{test-4}{3}{C}
+%D
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{1} [\twopassdata=A]
+%D \getfromtwopassdata {test-4}{3} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{2} [\twopassdata=B]
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
\unprotect
-%D We save two pass information in the utility file.
+\let\alltwopasslists\empty
+\let\twopassentry \gobblethreearguments % permits loading a MK II file
+\let\twopassdata \empty
+\let\twopassdatalist\empty
+
+\newif\iftwopassdatafound
\addutilityreset{twopassentries}
diff --git a/tex/context/base/core-two.mkiv b/tex/context/base/core-two.mkiv
index f4062725a..f7dbd4c91 100644
--- a/tex/context/base/core-two.mkiv
+++ b/tex/context/base/core-two.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-two, % moved from core-uti
-%D version=2006.09.24,
+%D version=1997.03.31,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Two Pass Data,
%D author=Hans Hagen,
@@ -11,17 +11,82 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Two Pass Data}
+
+%D This is a rather old mechanism which has not changed much over
+%D time, apart from adding a few more selectors. This code used
+%D to be part of \type {core-uti}. The following examples demonstrate
+%D the interface.
+%D
+%D \startbuffer
+%D \definetwopasslist{test-1}
+%D
+%D \gettwopassdatalist{test-1} [\twopassdatalist=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \checktwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D \gettwopassdata {test-1} [\twopassdata=]
+%D
+%D \definetwopasslist{test-2}
+%D
+%D \lazysavetwopassdata{test-2}{1}{x}
+%D \lazysavetwopassdata{test-2}{2}{y}
+%D \lazysavetwopassdata{test-2}{3}{z}
+%D
+%D \gettwopassdatalist{test-2} [\twopassdatalist=x,y,z]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \checktwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=x]
+%D \gettwopassdata {test-2} [\twopassdata=y]
+%D \gettwopassdata {test-2} [\twopassdata=z]
+%D \gettwopassdata {test-2} [\twopassdata=]
+%D
+%D \definetwopasslist{test-3}
+%D
+%D \lazysavetaggedtwopassdata{test-3}{1}{x}{a}
+%D \lazysavetaggedtwopassdata{test-3}{2}{y}{b}
+%D \lazysavetaggedtwopassdata{test-3}{3}{z}{c}
+%D
+%D \findtwopassdata{test-3}{x} [\twopassdata=a]
+%D \findtwopassdata{test-3}{y} [\twopassdata=b]
+%D \findtwopassdata{test-3}{z} [\twopassdata=c]
+%D \findtwopassdata{test-3}{w} [\twopassdata=]
+%D
+%D \definetwopasslist{test-4}
+%D
+%D \lazysavetwopassdata{test-4}{1}{A}
+%D \lazysavetwopassdata{test-4}{2}{B}
+%D \lazysavetwopassdata{test-4}{3}{C}
+%D
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfirsttwopassdata{test-4} [\twopassdata=A]
+%D \getlasttwopassdata {test-4} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{1} [\twopassdata=A]
+%D \getfromtwopassdata {test-4}{3} [\twopassdata=C]
+%D \getfromtwopassdata {test-4}{2} [\twopassdata=B]
+%D \stopbuffer
+%D
+%D \getbuffer \typebuffer
+
\unprotect
+\let\alltwopasslists\empty
+\let\twopassentry \empty
+\let\twopassentry \gobblethreearguments % permits loading a MK II file
+\let\twopassdatalist\empty
+
+\newif\iftwopassdatafound
+
\registerctxluafile{core-two}{1.001}
%D I'm not that sure if this behaves exactly like mkii. This needs a cleanup.
-\def\immediatesavetwopassdata #1#2#3{\expanded{\ctxlua {jobpasses.save('#1',"#3")}}}
-\def\savetwopassdata #1#2#3{\expanded{\ctxlatetua{jobpasses.save('#1',"#3")}}}
-\def\lazysavetwopassdata #1#2#3{\expanded{\ctxlatelua{jobpasses.save('#1',"#3")}}}
-\def\savetaggedtwopassdata #1#2#3#4{\expanded{\ctxlua {jobpasses.savetagged('#1','#3',"#4")}}}
-\def\lazysavetaggedtwopassdata#1#2#3#4{\expanded{\ctxlatelua{jobpasses.savetagged('#1','#3',"#4")}}}
+\def\immediatesavetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlua {jobpasses.save('#1',"#3")}}}
+\def\savetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlatelua{jobpasses.save('#1',"#3")}}}
+\def\lazysavetwopassdata #1#2#3{\normalexpanded{\noexpand\ctxlatelua{jobpasses.save('#1',"#3")}}}
+\def\savetaggedtwopassdata #1#2#3#4{\normalexpanded{\noexpand\ctxlua {jobpasses.savetagged('#1','#3',"#4")}}}
+\def\lazysavetaggedtwopassdata#1#2#3#4{\normalexpanded{\noexpand\ctxlatelua{jobpasses.savetagged('#1','#3',"#4")}}}
% temp hack: needs a proper \starteverytimeluacode
diff --git a/tex/context/base/core-two.tex b/tex/context/base/core-two.tex
deleted file mode 100644
index 5a845c614..000000000
--- a/tex/context/base/core-two.tex
+++ /dev/null
@@ -1,103 +0,0 @@
-%D \module
-%D [ file=core-two, % moved from core-uti
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Two Pass Data,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Two Pass Data}
-
-%D This is a rather old mechanism which has not changed much over
-%D time, apart from adding a few more selectors. This code used
-%D to be part of \type {core-uti}. The following examples demonstrate
-%D the interface.
-%D
-%D \startbuffer
-%D \definetwopasslist{test-1}
-%D
-%D \gettwopassdatalist{test-1} [\twopassdatalist=]
-%D \checktwopassdata {test-1} [\twopassdata=]
-%D \checktwopassdata {test-1} [\twopassdata=]
-%D \gettwopassdata {test-1} [\twopassdata=]
-%D \gettwopassdata {test-1} [\twopassdata=]
-%D
-%D \definetwopasslist{test-2}
-%D
-%D \lazysavetwopassdata{test-2}{1}{x}
-%D \lazysavetwopassdata{test-2}{2}{y}
-%D \lazysavetwopassdata{test-2}{3}{z}
-%D
-%D \gettwopassdatalist{test-2} [\twopassdatalist=x,y,z]
-%D \checktwopassdata {test-2} [\twopassdata=x]
-%D \checktwopassdata {test-2} [\twopassdata=x]
-%D \gettwopassdata {test-2} [\twopassdata=x]
-%D \gettwopassdata {test-2} [\twopassdata=y]
-%D \gettwopassdata {test-2} [\twopassdata=z]
-%D \gettwopassdata {test-2} [\twopassdata=]
-%D
-%D \definetwopasslist{test-3}
-%D
-%D \lazysavetaggedtwopassdata{test-3}{1}{x}{a}
-%D \lazysavetaggedtwopassdata{test-3}{2}{y}{b}
-%D \lazysavetaggedtwopassdata{test-3}{3}{z}{c}
-%D
-%D \findtwopassdata{test-3}{x} [\twopassdata=a]
-%D \findtwopassdata{test-3}{y} [\twopassdata=b]
-%D \findtwopassdata{test-3}{z} [\twopassdata=c]
-%D \findtwopassdata{test-3}{w} [\twopassdata=]
-%D
-%D \definetwopasslist{test-4}
-%D
-%D \lazysavetwopassdata{test-4}{1}{A}
-%D \lazysavetwopassdata{test-4}{2}{B}
-%D \lazysavetwopassdata{test-4}{3}{C}
-%D
-%D \getfirsttwopassdata{test-4} [\twopassdata=A]
-%D \getlasttwopassdata {test-4} [\twopassdata=C]
-%D \getfirsttwopassdata{test-4} [\twopassdata=A]
-%D \getlasttwopassdata {test-4} [\twopassdata=C]
-%D \getfromtwopassdata {test-4}{1} [\twopassdata=A]
-%D \getfromtwopassdata {test-4}{3} [\twopassdata=C]
-%D \getfromtwopassdata {test-4}{2} [\twopassdata=B]
-%D \stopbuffer
-%D
-%D \getbuffer \typebuffer
-
-\unprotect
-
-\let\alltwopasslists\empty
-\let\twopassentry \empty
-\let\twopassdata \empty
-\let\twopassdatalist\empty
-
-\newif\iftwopassdatafound
-
-\let\savetwopassdata \gobblethreearguments
-\let\immediatesavetwopassdata \gobblethreearguments
-\let\lazysavetwopassdata \gobblethreearguments
-\let\savetaggedtwopassdata \gobblefourarguments
-\let\lazysavetaggedtwopassdata\gobblefourarguments
-
-\let\twopassentry \gobblethreearguments % permits loading a MK II file
-\let\loadtwopassdata\relax % permits loading a MK II file
-
-\let\definetwopasslist\gobbleoneargument
-
-\def\gettwopassdata #1{\let\twopassdata \empty \twopassdatafoundfalse}
-\def\checktwopassdata #1{\let\twopassdata \empty \twopassdatafoundfalse}
-\def\findtwopassdata #1#2{\let\twopassdata \empty \twopassdatafoundfalse}
-\def\getlasttwopassdata #1{\let\twopassdata \empty \twopassdatafoundfalse}
-\def\getfromtwopassdata #1#2{\let\twopassdata \empty \twopassdatafoundfalse}
-\def\gettwopassdatalist #1{\let\twopassdatalist\empty \twopassdatafoundfalse}
-\def\getnamedtwopassdatalist#1#2{\let#1 \empty \twopassdatafoundfalse}
-\def\doifelseintwopassdata #1#2{\secondoftwoarguments}
-
-\loadmarkfile{core-two}
-
-\protect \endinput
diff --git a/tex/context/base/core-uti.lua b/tex/context/base/core-uti.lua
index fc99f67cb..20c63efd1 100644
--- a/tex/context/base/core-uti.lua
+++ b/tex/context/base/core-uti.lua
@@ -17,12 +17,13 @@ utility file under different setups, we now load a table once. This
saves much runtime but at the cost of more memory usage.</p>
--ldx]]--
-local format = string.format
+local sort, concat, format = table.sort, table.concat, string.format
+local next, type, tostring = next, type, tostring
if not jobs then jobs = { } end
if not job then jobs['main'] = { } end job = jobs['main']
-jobs.version = 1.01
+jobs.version = 1.10
--[[ldx--
<p>Variables are saved using in the previously defined table and passed
@@ -32,39 +33,206 @@ directly access the variable using a <l n='lua'/> call.</p>
local savelist, comment = { }, { }
-function job.comment(...)
- for _, str in ipairs({...}) do
- comment[#comment+1] = str
- end
+function job.comment(str)
+ comment[#comment+1] = str
end
job.comment(format("version: %1.2f",jobs.version))
job._save_, job._load_ = { }, { }
+function job.initialize(loadname,savename)
+ job.load(loadname)
+ main.register_stop_actions(function()
+ if not status.lasterrorstring or status.lasterrorstring == "" then
+ job.save(savename)
+ end
+ end)
+end
+
+function job.register(...) -- collected, tobesaved, initializer, finalizer
+ savelist[#savelist+1] = { ... }
+end
+
+-- as an example we implement variables
+
+jobvariables = jobvariables or { }
+jobvariables.collected = jobvariables.collected or { }
+jobvariables.tobesaved = jobvariables.tobesaved or { }
+
+jobvariables.checksums = jobvariables.checksums or { }
+
+if not jobvariables.checksums.old then jobvariables.checksums.old = md5.HEX("old") end
+if not jobvariables.checksums.new then jobvariables.checksums.new = md5.HEX("new") end
+
+job.register('jobvariables.checksums', jobvariables.checksums)
+
+local function initializer()
+ local r = jobvariables.collected.randomseed
+ if not r then
+ r = math.random()
+ end
+ math.randomseed(r)
+ jobvariables.tobesaved.randomseed = r
+ for cs, value in next, jobvariables.collected do
+ tex.sprint(format("\\xdef\\%s{%s}",cs,value))
+ end
+end
+
+job.register('jobvariables.collected', jobvariables.tobesaved, initializer)
+
+function jobvariables.save(cs,value)
+ jobvariables.tobesaved[cs] = value
+end
+
+-- experiment (bugged: some loop in running)
+
+-- for the moment here, very experimental stuff
+
+packer = packer or { }
+packer.version = 1.00
+
+local function hashed(t)
+ local s = { }
+ for k, v in next, t do
+ if type(v) == "table" then
+ s[#s+1] = k.."={"..hashed(v).."}"
+ else
+ s[#s+1] = k.."="..tostring(v)
+ end
+ end
+ sort(s)
+ return concat(s,",")
+end
+
+local function pack(t,keys,hash,index)
+ for k,v in next, t do
+ if type(v) == "table" then
+ pack(v,keys,hash,index)
+ end
+ if keys[k] and type(v) == "table" then
+ local h = hashed(v)
+ local i = hash[h]
+ if not i then
+ i = #index+1
+ index[i] = v
+ hash[h] = i
+ end
+ t[k] = i
+ end
+ end
+end
+
+local function unpack(t,keys,index)
+ for k,v in next, t do
+ if keys[k] and type(v) == "number" then
+ local iv = index[v]
+ if iv then
+ v = iv
+ t[k] = v
+ end
+ end
+ if type(v) == "table" then
+ unpack(v,keys,index)
+ end
+ end
+end
+
+function packer.new(keys,version)
+ return {
+ version = version or packer.version,
+ keys = table.tohash(keys),
+ hash = { },
+ index = { },
+ }
+end
+
+function packer.pack(t,p,shared)
+ if shared then
+ pack(t,p.keys,p.hash,p.index)
+ elseif not t.packer then
+ pack(t,p.keys,p.hash,p.index)
+ if #p.index > 0 then
+ t.packer = {
+ version = p.version or packer.version,
+ keys = p.keys,
+ index = p.index,
+ }
+ end
+ p.hash, p.index = { }, { }
+ end
+end
+
+function packer.unpack(t,p,shared)
+ if shared then
+ if p then
+ unpack(t,p.keys,p.index)
+ end
+ else
+ local tp = t.packer
+ if tp then
+ if tp.version == (p and p.version or packer.version) then
+ unpack(t,tp.keys,tp.index)
+ else
+ -- fatal error, wrong version
+ end
+ t.packer = nil
+ end
+ end
+end
+
+function packer.strip(p)
+ p.hash = nil
+end
+
+
+local packlist = {
+ "numbers",
+ "metadata",
+ "sectiondata",
+ "prefixdata",
+ "numberdata",
+ "pagedata",
+ "directives",
+ "specification",
+--~ "references",
+}
+
+local jobpacker = packer.new(packlist,1.01)
+
+job.pack = true
+
function job.save(filename)
- input.starttiming(job._save_)
+ statistics.starttiming(job._save_)
local f = io.open(filename,'w')
if f then
- for _, str in ipairs(comment) do
- f:write("-- ",str,"\n")
+ for c=1,#comment do
+ f:write("-- ",comment[c],"\n")
end
f:write("\n")
- for _, list in ipairs(savelist) do
+ for l=1,#savelist do
+ local list = savelist[l]
local target, data, finalizer = list[1], list[2], list[4]
if type(finalizer) == "function" then
finalizer()
end
+ if job.pack then
+ packer.pack(data,jobpacker,true)
+ end
f:write(aux.definetable(target),"\n")
f:write(table.serialize(data,target,true,true),"\n")
end
+ if job.pack then
+ packer.strip(jobpacker)
+ f:write(table.serialize(jobpacker,"job.packer",true,true),"\n")
+ end
f:close()
end
- input.stoptiming(job._save_)
+ statistics.stoptiming(job._save_)
end
function job.load(filename)
- input.starttiming(job._load_)
+ statistics.starttiming(job._load_)
local data = io.loaddata(filename)
if data and data ~= "" then
local version = tonumber(data:match("^-- version: ([%d%.]+)"))
@@ -72,46 +240,51 @@ function job.load(filename)
logs.report("job","version mismatch with jobfile: %s <> %s", version or "?", jobs.version)
else
loadstring(data)()
- for _, list in ipairs(savelist) do
+ for l=1,#savelist do
+ local list = savelist[l]
local target, initializer = list[1], list[3]
+ packer.unpack(aux.accesstable(target),job.packer,true)
if type(initializer) == "function" then
initializer(aux.accesstable(target))
end
end
+ job.packer = nil
end
end
- input.stoptiming(job._load_)
-end
-
-function job.initialize(loadname,savename)
- job.load(loadname)
- table.insert(input.stop_actions, function()
- if not status.lasterrorstring or status.lasterrorstring == "" then
- job.save(savename)
- end
- end)
+ statistics.stoptiming(job._load_)
end
-function job.register(...) -- collected, tobesaved, initializer, finalizer
- savelist[#savelist+1] = { ... }
-end
+-- eventually this will end up in strc-ini
--- as an example we implement variables
-
-jobvariables = jobvariables or { }
-jobvariables.collected = jobvariables.collected or { }
-jobvariables.tobesaved = jobvariables.tobesaved or { }
+statistics.register("startup time", function()
+ if statistics.elapsedindeed(ctx) then
+ return format("%s seconds (including runtime option file processing)", statistics.elapsedtime(ctx))
+ end
+end)
-local function initializer()
- for cs, value in pairs(jobvariables.collected) do
- tex.sprint(string.format("\\xdef\\%s{%s}",cs,value))
+statistics.register("jobdata time",function()
+ if statistics.elapsedindeed(job._save_) or statistics.elapsedindeed(job._load_) then
+ return format("%s seconds saving, %s seconds loading", statistics.elapsedtime(job._save_), statistics.elapsedtime(job._load_))
end
-end
+end)
-job.register('jobvariables.collected', jobvariables.tobesaved, initializer)
+statistics.register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ local pages = tex.count['realpageno'] - 1
+ if pages > 1 then
+ return format("direct: %s, indirect: %s, total: %s (%i per page)", total-indirect, indirect, total, total/pages)
+ else
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end
+end)
-function jobvariables.save(cs,value)
- jobvariables.tobesaved[cs] = value
+function statistics.formatruntime(runtime)
+ local shipped = tex.count['nofshipouts']
+ local pages = tex.count['realpageno'] - 1
+ if shipped > 0 or pages > 0 then
+ local persecond = shipped / runtime
+ return format("%s seconds, %i processed pages, %i shipped pages, %.3f pages/second",runtime,pages,shipped,persecond)
+ else
+ return format("%s seconds",runtime)
+ end
end
-
-
diff --git a/tex/context/base/core-uti.mkii b/tex/context/base/core-uti.mkii
index 8d8fc6dcb..b348ba358 100644
--- a/tex/context/base/core-uti.mkii
+++ b/tex/context/base/core-uti.mkii
@@ -11,6 +11,154 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Utility File Handling}
+
+\unprotect
+
+% todo : safe lan etc too
+% todo : load all commands at once (tok)
+% todo : merge status info patch into tui file (language, encoding, etc),
+
+% Utility-file
+%
+% De onderstaande macro's ondersteunen het gebruik van de
+% zogeheten utility-file. Alle extern onder te brengen
+% informatie wordt opgeslagen in de file \jobname.tui, tenzij
+% er selectief pagina's worden gezet. In dat geval wordt de
+% file \jobname.tmp gebruikt. Informatie wordt ingelezen uit
+% de file \jobname.tuo, welke door TeXUtil wordt aangemaakt.
+
+\edef\utilityversion{1998.07.07} % was: 1996.03.15 % status variables
+\edef\utilityversion{1998.12.20} % was: 1998.07.07 % index attributes
+\edef\utilityversion{2003.07.19} % was: 1998.12.20 % object pages
+\edef\utilityversion{2006.06.23} % was: 2003.07.19 % -- instead of :
+\edef\utilityversion{2006.09.21} % pt in pos
+\edef\utilityversion{2008.10.14} % moved more to lua in mkiv
+
+% Bepaalde commando's worden als string weggeschreven. Deze
+% zijn aan het eind van deze file gedefinieerd.
+
+% Om een opbouw van spaties te voorkomen (???) moet ^^M een
+% andere betekenis krijgen:
+%
+% \catcode`\^^M=14 (comment)
+%
+% read file
+%
+% \catcode`\^^M=5 (end of line)
+
+\newwrite\utility@tui
+\newif\ifutilitydone
+
+\ifx\sectionseparator\undefined \def\sectionseparator{-} \fi
+
+\def\@@utilityerrormessage
+ {\showmessage\m!systems8\empty
+ \globallet\@@utilityerrormessage\relax}
+
+\def\thisisutilityversion#1%
+ {\doifelse\utilityversion{#1}%
+ {\checksectionseparator}
+ {\@@utilityerrormessage\resetutilities\endinput}}
+
+\def\checksectionseparator % catches backward compatibility conflict
+ {}% \doifnot\sectionseparator:\endinput} % this dependency may go in a few years
+
+\def\dosplitofffoliopart[#1--#2--#3]{#3}
+
+\def\thisissectionseparator#1%
+ {\bgroup
+ \globallet\checksectionseparator\relax
+ \defconvertedcommand \asciia\sectionseparator
+ \defconvertedargument\asciib{#1}%
+ \expanded{\gdef\noexpand\dosplitofffoliopart[####1\sectionseparator
+ \sectionseparator####2\sectionseparator\sectionseparator####3]{####3}}%
+ \ifx\asciia\asciib
+ \egroup
+ \else
+ \egroup
+ % todo \@@utilityerrormessage
+ \resetutilities
+ \endinput
+ \fi}
+
+\def\writeutility {\write\utility@tui}
+\def\writeutilitycommand#1{\write\utility@tui{c \string#1}}
+
+% less tokens
+%
+% \def\immediatewriteutility {\immediate\writeutility}
+% \def\immediatewriteutilitycommand{\immediate\writeutilitycommand}
+%
+% more flexible (for overloading)
+
+\def\immediatewriteutility {\immediate\write\utility@tui}
+\def\immediatewriteutilitycommand#1{\immediate\write\utility@tui{c \string#1}}
+
+% as in:
+
+\def\cwriteutility#1%
+ {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{#1}}}
+
+\def\cwriteutilitycommand#1%
+ {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{c \string#1}}}
+
+\let\checkedutility\secondoftwoarguments
+
+\def\docheckedutility#1#2{\ifnum#1=\nofshipouts#2\else\letterpercent\fi}
+
+\prependtoks
+ \let\checkedutility\docheckedutility
+\to \everybeforeshipout
+
+% Better use marks.
+
+\newtoks \everyopenutilities
+\newtoks \everycloseutilities
+\newtoks \everycheckutilities
+
+\def\openutilities {\the\everyopenutilities } % \global\everyopenutilities\emptytoks
+\def\closeutilities{\the\everycloseutilities}
+\def\checkutilities{\the\everycheckutilities}
+
+\appendtoks
+ \let\writeutility \cwriteutility
+ \let\writeutilitycommand \cwriteutilitycommand
+ %\let\immediatewriteutility \cimmediatewriteutility
+ %\let\immediatewriteutilitycommand\cimmediatewriteutilitycommand
+ \let\checkutilities \relax
+\to \everycheckutilities
+
+\appendtoks
+ \immediate\openout\utility@tui\jobname.\f!inputextension
+ \immediatewriteutilitycommand{\thisissectionseparator{\sectionseparator}}% for the moment
+ \immediatewriteutilitycommand{\thisisutilityversion {\utilityversion }}% in this order
+\to \everyopenutilities
+
+\appendtoks
+% \immediate\closeout\utility@tui % niet echt nodig
+ \reportutilityproblems
+ % should be a message :
+ \let\writeutilitycommand \gobbleoneargument
+ \let\writeutility \gobbleoneargument
+ \let\immediatewriteutilitycommand\gobbleoneargument
+ \let\immediatewriteutility \gobbleoneargument
+\to \everycloseutilities
+
+% \def\reopenutilities
+% {\immediate\closeout\utility@tui
+% \openutilities}
+
+\def\abortutilitygeneration
+ {\immediatewriteutilitycommand\utilitygenerationaborted
+ \immediatewriteutility{q {quit}}}
+
+\def\utilitygenerationaborted
+ {\showmessage\m!systems{21}\empty
+ \globallet\utilitygenerationaborted\endinput
+ \gdef\reportutilityproblems{\showmessage\m!systems{22}\empty}%
+ \endinput}
+
\def\savecurrentvalue#1#2%
{\immediatewriteutilitycommand{\initializevariable\string#1{#2}}}
@@ -20,6 +168,46 @@
\globallet\initializevariable\gobbletwoarguments
\to \everyafterutilityread
+\let\reportutilityproblems\relax
+
+\newtoks\utilityresetlist
+
+\def\addutilityreset#1%
+ {\@EA\appendtoks\csname\s!reset#1\endcsname\to\utilityresetlist}
+
+\def\resetutilities
+ {\the\utilityresetlist}
+
+% #1=type #2=file #3=melding #4=voor #5=na
+%
+% Er wordt gegroepeerd. Als binnen een lijst (bijvoorbeeld) de
+% \leftskip is aangepast, maar nog geen \par is gegeven, dan
+% geldt buiten de groep de oude \leftskip. Aan #5 kan dan
+% ook \par worden meegegeven om de paragraaf af te sluiten.
+
+\newif\ifdoinpututilities
+\newif\ifunprotectutilities % voor't geval er \v!xxxxxx's zijn
+
+\def\currentutilityfilename{\jobname}
+
+% we need to pop and push, else problems with reading
+% utility files (toc) in xml mode and (e.g.) in a toc
+% entry doing a doifmode
+%
+% the following is not ok because we have no way to signal
+% xml content (yet), so for the moment we use this:
+
+\appendtoks
+ \ifprocessingXML
+ \processingXMLfalse
+ \enableXML
+ \catcode`\\=\@@escape
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup
+ \catcode`\%=\@@comment\relax
+ \fi
+\to \everybeforeutilityread
+
\edef\testbytesequence
{\rawcharacter{7}%
\rawcharacter{27}%
@@ -36,12 +224,123 @@
\fi
\global\let\thisisbytesequence\gobbleoneargument}
-\beginXETEX
+\ifnum\texengine=\xetexengine
\let\testbytesequence\empty
-\endXETEX
+\fi
\appendtoks
\immediatewriteutilitycommand{\thisisbytesequence{\testbytesequence}}%
\to \everyopenutilities
-\endinput
+\long\def\doutilities#1#2#3#4#5% % introduceren in utility file
+ {\resetutilities
+ % more than one utility thing can be handled in one pass,
+ % for instance lists, so we process ##1 as list
+ \def\douticommand##1{\csname\s!set##1\endcsname}%
+ \processcommacommand[#1]\douticommand
+ \begingroup
+ \def\currentutilityfilename{#2}%
+ \notesenabledfalse
+ \doinpututilitiestrue
+ \global\utilitydonefalse
+ \pushendofline % geeft problemen zodra andere file wordt ingelezen
+ \pushcatcodetable
+ \setcatcodetable\ctxcatcodes
+ \ifunprotectutilities % nog nodig ?
+ \unprotect
+ \fi
+ #4%
+ \the\everybeforeutilityread
+ \readjobfile{#2.\f!outputextension}\donothing\donothing
+ \the\everyafterutilityread
+ \popcatcodetable
+ #5%
+ \relax
+ \ifunprotectutilities
+ \protect
+ \fi
+ \popendofline
+ \ifutilitydone\else
+ \doifsomething{#3}
+ {\showmessage\m!systems9{{#3}}%
+ \doifconcepttracing
+ {\blank
+ \setmessagetext\m!systems9{{#3}}%
+ \type{[\currentmessagetext]}%
+ \blank}}%
+ \fi
+ \endgroup}
+
+% Default-instellingen (verborgen)
+
+\prependtoks \resetutilities \to \everyjob
+
+% Experiment
+%
+% \installprogram{Hello World}
+% \installprogram[hw]{Hello World}
+% \installedprogram[hw]
+
+\def\installprogram
+ {\dosingleempty\doinstallprogram}
+
+\def\doinstallprogram[#1]#2%
+ {\doifelsenothing{#1}
+ {\dodoinstallprogram{#2}}
+ {\setvalue{\??up#1}{\dodoinstallprogram{#2}}}}
+
+\def\dodoinstallprogram#1%
+ {\immediatewriteutility{e p {#1}}}
+
+\def\installedprogram[#1]%
+ {\getvalue{\??up#1}}
+
+% \writeplugindata{texutil}{{alpha}}
+% \writeplugindata{texutil}{{beta}}
+% \writeplugindata{texutil}{{gamma}}
+% \writeplugindata{texutil}{{delta}}
+%
+% \loadplugindata {plugintest}
+
+\def\immediatewriteplugindata#1#2%
+ {\immediatewriteutility{p u {#1} #2}}
+
+\def\writeplugindata#1#2%
+ {\writeutility{p u {#1} #2}}
+
+\def\loadplugindata#1%
+ {\doutilities{#1}\jobname\empty\relax\relax}
+
+% \plugincommand{\command{}{}{}}
+%
+% this way we can catch undefined commands
+
+\long\def\plugincommand#1%
+ {\doplugincommand#1\relax}
+
+\long\def\doplugincommand#1%
+ {\ifx#1\undefined
+ \expandafter\noplugincommand
+ \else
+ \expandafter#1%
+ \fi}
+
+\long\def\noplugincommand#1\relax
+ {}
+
+% \addutilityreset{plugintest}
+%
+% \def\resetplugintest{\let\plugintest\gobbletwoarguments}
+% \def\setplugintest {\let\plugintest\writestatus}
+%
+% \installplugin
+% {plugintest}
+% {\let\plugintest\gobbletwoarguments}
+% {\let\plugintest\writestatus}
+
+\long\def\installplugin#1#2#3%
+ {\addutilityreset {#1}%
+ \long\setvalue{\s!reset#1}{#2}%
+ \long\setvalue{\s!set #1}{#3}}
+
+\protect \endinput
diff --git a/tex/context/base/core-uti.mkiv b/tex/context/base/core-uti.mkiv
index ddbc47311..77cf91dd9 100644
--- a/tex/context/base/core-uti.mkiv
+++ b/tex/context/base/core-uti.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-uti,
-%D version=2006.09.19,
+%D version=1997.03.31, % 2006.09.19 mkiv
%D title=\CONTEXT\ Core Macros,
%D subtitle=Utility File Handling,
%D author=Hans Hagen,
@@ -11,67 +11,86 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
-
-\registerctxluafile{core-uti}{1.001}
+%D Most will disappear!
-%D We need a way to pass strings safely to \LUA\ without the
-%D need for tricky escaping. Compare:
-%D
-%D \starttyping
-%D \ctxlua {something("anything tricky can go here")}
-%D \ctxlua {something([\luastringsep[anything tricky can go here]\luastringsep])}
-%D \stoptyping
+\writestatus{loading}{ConTeXt Core Macros / Utility File Handling}
-\def\luastringsep{===} % this permits \typefile{self} otherwise nested b/e sep problems
-
-\edef\!!bs{[\luastringsep[}
-\edef\!!es{]\luastringsep]}
-
-%D We have a the following available as primitive so there is no need
-%D for it:
-%D
-%D \starttyping
-%D \long\edef\luaescapestring#1{\!!bs#1\!!es}
-%D \stoptyping
+\unprotect
-% variables
+\registerctxluafile{core-uti}{1.001}
\def\savecurrentvalue#1#2%
{\ctxlua{jobvariables.save("\strippedcsname#1","#2")}}
-% temp
-
+\let\initializevariable\gobbletwoarguments % mkii/mkiv
\let\thisisbytesequence\gobbleoneargument
-% wrong place but we need to have it someplace
+\appendtoks
+ \globallet\initializevariable\gobbletwoarguments
+\to \everyafterutilityread
\appendtoks
- \ctxlua{input.storage.dump()}%
+ \ctxlua{storage.dump()}%
\to \everydump
\appendtoks
- \ctxlua{input.storage.finalize()}%
+ \ctxlua{storage.finalize()}%
\to \everyfinalizeluacode
\appendtoks
\ctxlua{nodes.cleanup_reserved()}%
\to \everydump
-% new
-
-% this loads and also sets the saving
-
\appendtoks
\ctxlua {
- job.comment(
- "file: \jobname",
- "format: \contextformat",
- "stamp: \contextversion",
- "escape: \!!bs\space...\space\!!es"
- )
+ job.comment("file: \jobname")
+ job.comment("format: \contextformat")
+ job.comment("stamp: \contextversion")
+ job.comment("escape: \!!bs\space...\space\!!es")
job.initialize("\jobname.tuc","\jobname.tua")
}%
\to \everystarttext
+% cleaner, for the moment
+
+% \appendtoks
+% \ctxlua {
+% os.remove("\jobname.tui")
+% os.remove("\jobname.tuo")
+% }%
+% \to \everystarttext
+
+% keep this for a while
+
+\newif\ifutilitydone
+\newif\ifdoinpututilities
+\newif\ifunprotectutilities
+
+\let\writeutility \gobbleoneargument
+\let\writeutilitycommand \gobbleoneargument
+\let\immediatewriteutility \gobbleoneargument
+\let\immediatewriteutilitycommand\gobbleoneargument
+\let\cwriteutility \gobbleoneargument
+\let\cwriteutilitycommand \gobbleoneargument
+\let\checkedutility \secondoftwoarguments
+\let\doutilities \gobblefivearguments
+\let\abortutilitygeneration \relax
+
+\newtoks \everyopenutilities \let\openutilities \relax
+\newtoks \everycloseutilities \let\closeutilities\relax
+\newtoks \everycheckutilities \let\checkutilities\relax
+\newtoks \utilityresetlist
+
+\def\addutilityreset#1{\@EA\appendtoks\csname\s!reset#1\endcsname\to\utilityresetlist}
+\def\resetutilities {\the\utilityresetlist}
+
+\def\currentutilityfilename{\jobname}
+
+\prependtoks \resetutilities \to \everyjob
+
+\def\installprogram {\dosingleempty\doinstallprogram}
+\def\doinstallprogram[#1]{\gobbleoneargument}
+\def\installedprogram[#1]{}
+\let\installplugin \gobblethreearguments
+
\protect \endinput
diff --git a/tex/context/base/core-uti.tex b/tex/context/base/core-uti.tex
deleted file mode 100644
index e84a6db5c..000000000
--- a/tex/context/base/core-uti.tex
+++ /dev/null
@@ -1,382 +0,0 @@
-%D \module
-%D [ file=core-uti,
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Utility File Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Utility File Handling}
-
-\unprotect
-
-% todo : safe lan etc too
-% todo : load all commands at once (tok)
-% todo : merge status info patch into tui file (language, encoding, etc),
-
-% Utility-file
-%
-% De onderstaande macro's ondersteunen het gebruik van de
-% zogeheten utility-file. Alle extern onder te brengen
-% informatie wordt opgeslagen in de file \jobname.tui, tenzij
-% er selectief pagina's worden gezet. In dat geval wordt de
-% file \jobname.tmp gebruikt. Informatie wordt ingelezen uit
-% de file \jobname.tuo, welke door TeXUtil wordt aangemaakt.
-
-\edef\utilityversion{1998.07.07} % was: 1996.03.15 % status variables
-\edef\utilityversion{1998.12.20} % was: 1998.07.07 % index attributes
-\edef\utilityversion{2003.07.19} % was: 1998.12.20 % object pages
-\edef\utilityversion{2006.06.23} % was: 2003.07.19 % -- instead of :
-\edef\utilityversion{2006.09.21} % pt in pos
-\edef\utilityversion{2008.10.14} % moved more to lua in mkiv
-
-% Bepaalde commando's worden als string weggeschreven. Deze
-% zijn aan het eind van deze file gedefinieerd.
-
-% Om een opbouw van spaties te voorkomen (???) moet ^^M een
-% andere betekenis krijgen:
-%
-% \catcode`\^^M=14 (comment)
-%
-% read file
-%
-% \catcode`\^^M=5 (end of line)
-
-\newwrite\utility@tui
-\newif\ifutilitydone
-
-\def\@@utilityerrormessage
- {\showmessage\m!systems8\empty
- \globallet\@@utilityerrormessage\relax}
-
-\def\thisisutilityversion#1%
- {\doifelse\utilityversion{#1}%
- {\checksectionseparator}
- {\@@utilityerrormessage\resetutilities\endinput}}
-
-\def\checksectionseparator % catches backward compatibility conflict
- {}% \doifnot\sectionseparator:\endinput} % this dependency may go in a few years
-
-\def\dosplitofffoliopart[#1--#2--#3]{#3}
-
-\def\thisissectionseparator#1%
- {\bgroup
- \globallet\checksectionseparator\relax
- \defconvertedcommand \asciia\sectionseparator
- \defconvertedargument\asciib{#1}%
- \expanded{\gdef\noexpand\dosplitofffoliopart[####1\sectionseparator
- \sectionseparator####2\sectionseparator\sectionseparator####3]{####3}}%
- \ifx\asciia\asciib
- \egroup
- \else
- \egroup
- % todo \@@utilityerrormessage
- \resetutilities
- \endinput
- \fi}
-
-\def\writeutility {\write\utility@tui}
-\def\writeutilitycommand#1{\write\utility@tui{c \string#1}}
-
-% less tokens
-%
-% \def\immediatewriteutility {\immediate\writeutility}
-% \def\immediatewriteutilitycommand{\immediate\writeutilitycommand}
-%
-% more flexible (for overloading)
-
-\def\immediatewriteutility {\immediate\write\utility@tui}
-\def\immediatewriteutilitycommand#1{\immediate\write\utility@tui{c \string#1}}
-
-% as in:
-
-\def\cwriteutility#1%
- {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{#1}}}
-
-\def\cwriteutilitycommand#1%
- {\write\utility@tui{\noexpand\checkedutility{\number\nofshipouts}{c \string#1}}}
-
-\let\checkedutility\secondoftwoarguments
-
-\def\docheckedutility#1#2{\ifnum#1=\nofshipouts#2\else\letterpercent\fi}
-
-\prependtoks
- \let\checkedutility\docheckedutility
-\to \everybeforeshipout
-
-% Better use marks.
-
-\newtoks \everyopenutilities
-\newtoks \everycloseutilities
-\newtoks \everycheckutilities
-
-\def\openutilities {\the\everyopenutilities } % \global\everyopenutilities\emptytoks
-\def\closeutilities{\the\everycloseutilities}
-\def\checkutilities{\the\everycheckutilities}
-
-\appendtoks
- \let\writeutility \cwriteutility
- \let\writeutilitycommand \cwriteutilitycommand
- %\let\immediatewriteutility \cimmediatewriteutility
- %\let\immediatewriteutilitycommand\cimmediatewriteutilitycommand
- \let\checkutilities \relax
-\to \everycheckutilities
-
-\appendtoks
- \immediate\openout\utility@tui\jobname.\f!inputextension
- \immediatewriteutilitycommand{\thisissectionseparator{\sectionseparator}}% for the moment
- \immediatewriteutilitycommand{\thisisutilityversion {\utilityversion }}% in this order
-\to \everyopenutilities
-
-\appendtoks
-% \immediate\closeout\utility@tui % niet echt nodig
- \reportutilityproblems
- % should be a message :
- \let\writeutilitycommand \gobbleoneargument
- \let\writeutility \gobbleoneargument
- \let\immediatewriteutilitycommand\gobbleoneargument
- \let\immediatewriteutility \gobbleoneargument
-\to \everycloseutilities
-
-% \def\reopenutilities
-% {\immediate\closeout\utility@tui
-% \openutilities}
-
-\def\abortutilitygeneration
- {\immediatewriteutilitycommand\utilitygenerationaborted
- \immediatewriteutility{q {quit}}}
-
-\def\utilitygenerationaborted
- {\showmessage\m!systems{21}\empty
- \globallet\utilitygenerationaborted\endinput
- \gdef\reportutilityproblems{\showmessage\m!systems{22}\empty}%
- \endinput}
-
-\let\savecurrentvalue \gobbletwoarguments % mkii/mkiv
-\let\initializevariable\gobbletwoarguments % mkii/mkiv
-
-\appendtoks
- \globallet\initializevariable\gobbletwoarguments
-\to \everyafterutilityread
-
-\let\reportutilityproblems\relax
-\let\utilityresetlist \empty
-
-\newtoks\utilityresetlist
-
-\def\addutilityreset#1%
- {\@EA\appendtoks\csname\s!reset#1\endcsname\to\utilityresetlist}
-
-\def\resetutilities
- {\the\utilityresetlist}
-
-% #1=type
-% #2=file
-% #3=melding
-
-% #4=voor
-% #5=na
-
-% Er wordt gegroepeerd. Als binnen een lijst (bijvoorbeeld) de
-% \leftskip is aangepast, maar nog geen \par is gegeven, dan
-% geldt buiten de groep de oude \leftskip. Aan #5 kan dan
-% ook \par worden meegegeven om de paragraaf af te sluiten.
-
-\newif\ifdoinpututilities
-\newif\ifunprotectutilities % voor't geval er \v!xxxxxx's zijn
-
-\def\currentutilityfilename{\jobname}
-
-% \long\def\doutilities#1#2#3#4#5% % introduceren in utility file
-% {\restorecatcodes
-% \resetutilities
-% % more than one utility thing can be handled in one pass,
-% % for instance lists, so we process ##1 as list
-% \def\douticommand##1{\csname\s!set##1\endcsname}%
-% \processcommacommand[#1]\douticommand
-% \begingroup
-% \def\currentutilityfilename{#2}%
-% \notesenabledfalse
-% \doinpututilitiestrue
-% \global\utilitydonefalse
-% \catcode`\\=\@@escape
-% \catcode`\{=\@@begingroup
-% \catcode`\}=\@@endgroup
-% \catcode`\%=\@@comment\relax
-% \pushendofline % geeft problemen zodra andere file wordt ingelezen
-% \ifunprotectutilities % nog nodig ?
-% \unprotect
-% \fi
-% \ifnum\catcode`\@=\@@active \else
-% \catcode`\@=\@@letter % permits expanded commands with \@'s
-% \fi
-% \ifnum\catcode`\!=\@@active \else
-% \catcode`\!=\@@letter % permits multilingual constants
-% \fi
-% #4%
-% \the\everybeforeutilityread
-% \readjobfile{#2.\f!outputextension}\donothing\donothing
-% \the\everyafterutilityread
-% #5%
-% \relax
-% \ifunprotectutilities
-% \protect
-% \fi
-% \popendofline
-% \ifutilitydone\else
-% \doifsomething{#3}
-% {\showmessage\m!systems9{{#3}}%
-% \doifconcepttracing
-% {\blank
-% \type{[\currentmessagetext]}%
-% \blank}}%
-% \fi
-% \endgroup}
-
-% we need to pop and push, else problems with reading
-% utility files (toc) in xml mode and (e.g.) in a toc
-% entry doing a doifmode
-%
-% the following is not ok because we have no way to signal
-% xml content (yet), so for the moment we use this:
-
-\appendtoks
- \ifprocessingXML
- \processingXMLfalse
- \enableXML
- \catcode`\\=\@@escape
- \catcode`\{=\@@begingroup
- \catcode`\}=\@@endgroup
- \catcode`\%=\@@comment\relax
- \fi
-\to \everybeforeutilityread
-
-\long\def\doutilities#1#2#3#4#5% % introduceren in utility file
- {\resetutilities
- % more than one utility thing can be handled in one pass,
- % for instance lists, so we process ##1 as list
- \def\douticommand##1{\csname\s!set##1\endcsname}%
- \processcommacommand[#1]\douticommand
- \begingroup
- \def\currentutilityfilename{#2}%
- \notesenabledfalse
- \doinpututilitiestrue
- \global\utilitydonefalse
- \pushendofline % geeft problemen zodra andere file wordt ingelezen
- \pushcatcodetable
- \setcatcodetable\ctxcatcodes
- \ifunprotectutilities % nog nodig ?
- \unprotect
- \fi
- #4%
- \the\everybeforeutilityread
- \readjobfile{#2.\f!outputextension}\donothing\donothing
- \the\everyafterutilityread
- \popcatcodetable
- #5%
- \relax
- \ifunprotectutilities
- \protect
- \fi
- \popendofline
- \ifutilitydone\else
- \doifsomething{#3}
- {\showmessage\m!systems9{{#3}}%
- \doifconcepttracing
- {\blank
- \setmessagetext\m!systems9{{#3}}%
- \type{[\currentmessagetext]}%
- \blank}}%
- \fi
- \endgroup}
-
-% Default-instellingen (verborgen)
-
-\prependtoks \resetutilities \to \everyjob
-
-% Experiment
-%
-% \installprogram{Hello World}
-% \installprogram[hw]{Hello World}
-% \installedprogram[hw]
-
-\def\installprogram
- {\dosingleempty\doinstallprogram}
-
-\def\doinstallprogram[#1]#2%
- {\doifelsenothing{#1}
- {\dodoinstallprogram{#2}}
- {\setvalue{\??up#1}{\dodoinstallprogram{#2}}}}
-
-% \def\doinstallprogram[#1][#2]% less code
-% {\doifsomething{#1}{\setvalue{\??up#1}}{\dodoinstallprogram{#2}}}
-
-\def\dodoinstallprogram#1%
- {\immediatewriteutility{e p {#1}}}
-
-\def\installedprogram[#1]%
- {\getvalue{\??up#1}}
-
-% \writeplugindata{texutil}{{alpha}}
-% \writeplugindata{texutil}{{beta}}
-% \writeplugindata{texutil}{{gamma}}
-% \writeplugindata{texutil}{{delta}}
-%
-% \loadplugindata {plugintest}
-
-\def\immediatewriteplugindata#1#2%
- {\immediatewriteutility{p u {#1} #2}}
-
-\def\writeplugindata#1#2%
- {\writeutility{p u {#1} #2}}
-
-\def\loadplugindata#1%
- {\doutilities{#1}\jobname\empty\relax\relax}
-
-% \plugincommand{\command{}{}{}}
-%
-% this way we can catch undefined commands
-
-\long\def\plugincommand#1%
- {\doplugincommand#1\relax}
-
-\long\def\doplugincommand#1%
- {\ifx#1\undefined
- \expandafter\noplugincommand
- \else
- \expandafter#1%
- \fi}
-
-% shorter:
-%
-% \long\def\doplugincommand#1%
-% {\ifx#1\undefined\expandafter\noplugincommand\fi#1}
-
-\long\def\noplugincommand#1\relax
- {}
-
-% \addutilityreset{plugintest}
-%
-% \def\resetplugintest{\let\plugintest\gobbletwoarguments}
-% \def\setplugintest {\let\plugintest\writestatus}
-%
-% \installplugin
-% {plugintest}
-% {\let\plugintest\gobbletwoarguments}
-% {\let\plugintest\writestatus}
-
-\long\def\installplugin#1#2#3%
- {\addutilityreset {#1}%
- \long\setvalue{\s!reset#1}{#2}%
- \long\setvalue{\s!set #1}{#3}}
-
-% plugins
-
-\loadmarkfile{core-uti}
-
-\protect \endinput
diff --git a/tex/context/base/core-var.tex b/tex/context/base/core-var.tex
index 38c434e0b..4de1b8718 100644
--- a/tex/context/base/core-var.tex
+++ b/tex/context/base/core-var.tex
@@ -11,304 +11,121 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Variables}
+\writestatus{loading}{ConTeXt Core Macros / Variables}
\unprotect
-%D Modes:
-%D
-%D \starttyping
-%D \enablemode[screen,paper,bound]
-%D
-%D \doifmodeelse {paper} {this} {that}
-%D \doifmode {paper,screen} {this}
-%D \doifnotmode {paper,bound} {that}
-%D
-%D \startmode [list]
-%D \stopmode
-%D
-%D \startnotmode [list]
-%D \stopnotmode
-%D \stoptyping
-%D
-%D system modes have a * as prefix
+%D We introduce a couple of variables that are used all over
+%D \CONTEXT. Alternatively we could define them in each module
+%D but as they are part of the bigger picture we prefer to do
+%D it here.
+
+%D \macros
+%D {every...}
%D
-%D Sometimes, we want to prevent a mode for being set. Think
-%D of situations where a style enables a mode, but an outer
-%D level style does not want that. Preventing can be
-%D considered a permanent disabling on forehand.
-
-% \def\systemmodeprefix{*}
-%
-% \let\currentmode \empty
-% \let\preventedmodes\empty
-%
-% \def\preventmode[#1]%
-% {\expanded{\addtocommalist{#1}\noexpand\preventedmodes}}
-%
-% \def\enablemode[#1]%
-% {\expanded
-% {\doifnotinset{#1}{\preventedmodes}
-% {\noexpand\addtocommalist{#1}\noexpand\currentmode}}}
-%
-% \def\disablemode[#1]%
-% {\expanded{\removefromcommalist{#1}\noexpand\currentmode}}
-%
-% \def\doifmodeelse{\unprotect\dodoifmodeelse}
-% \def\doifmode {\unprotect\dodoifmode }
-% \def\doifnotmode {\unprotect\dodoifnotmode }
-% \def\startmode {\unprotect\dostartmode }
-% \def\startnotmode{\unprotect\dostartnotmode}
-%
-% \long\def\dodoifmodeelse#1%
-% {\protect\expanded{\doifcommonelse{#1}{\currentmode}}}
-%
-% \long\def\dodoifmode#1%
-% {\protect\expanded{\doifcommon {#1}{\currentmode}}}
-%
-% \long\def\dodoifnotmode#1%
-% {\protect\expanded{\doifnotcommon {#1}{\currentmode}}}
-%
-% \let\stopmode \relax
-% \let\stopnotmode\relax
-%
-% \long\def\dostartmode[#1]%
-% {\protect
-% \expanded{\doifnotcommon{#1}{\currentmode}}{\gobbleuntil\stopmode}}
-%
-% \long\def\dostartnotmode[#1]%
-% {\protect
-% \expanded{\doifcommon {#1}{\currentmode}}{\gobbleuntil\stopnotmode}}
-%
-% \def\doifallmodeselse{\unprotect\dodoifallmodeselse}
-% \def\doifallmodes {\unprotect\dodoifallmodes}
-% \def\doifnotallmodes {\unprotect\dodoifnotallmodes}
-% \def\startallmodes {\unprotect\dostartallmodes}
-% \def\startnotallmodes{\unprotect\dostartnotallmodes}
-%
-% \long\def\dodoifallmodeselse#1%
-% {\protect\expanded{\doifallcommonelse{#1}{\currentmode}}}
-%
-% \long\def\dodoifallmodes#1%
-% {\protect\expanded{\doifallcommon {#1}{\currentmode}}}
-%
-% \long\def\dodoifnotallmodes#1%
-% {\protect\expanded{\doifnotallcommon {#1}{\currentmode}}}
-%
-% \let\stopallmodes \relax
-% \let\stopnotallmodes\relax
-%
-% \long\def\dostartallmodes[#1]%
-% {\protect
-% \expanded{\doifnotallcommon{#1}{\currentmode}}{\gobbleuntil\stopallmodes}}
-%
-% \long\def\dostartnotallmodes[#1]%
-% {\protect
-% \expanded{\doifallcommon {#1}{\currentmode}}{\gobbleuntil\stopnotallmodes}}
-
-% faster
-
-\def\@mode@{@md@}
-
-\def\systemmodeprefix{*}
-
-\def\disabledmode {0}
-\def\enabledmode {1}
-\def\preventedmode {2}
-
-% fast internal ones
-
-\def\setmode #1{\@EA\let\csname\@mode@#1\endcsname\enabledmode }
-\def\resetmode#1{\@EA\let\csname\@mode@#1\endcsname\disabledmode}
-
-\def\setsystemmode #1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\enabledmode }
-\def\resetsystemmode#1{\@EA\let\csname\@mode@\systemmodeprefix#1\endcsname\disabledmode}
-
-% user ones
-
-\def\preventmode{\unprotect\dopreventmode}
-\def\enablemode {\unprotect\doenablemode }
-\def\disablemode{\unprotect\dodisablemode}
-
-% \def\dopreventmode[#1]{\protect\rawprocesscommalist[#1]\dodopreventmode}
-% \def\doenablemode [#1]{\protect\rawprocesscommalist[#1]\dodoenablemode }
-% \def\dodisablemode[#1]{\protect\rawprocesscommalist[#1]\dododisablemode}
-%
-% better:
-
-\def\dopreventmode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodopreventmode}
-\def\doenablemode [#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dodoenablemode }
-\def\dodisablemode[#1]{\protect\cleanuplabel{#1}\rawprocesscommalist[\cleanlabel]\dododisablemode}
-
-\def\dodopreventmode#1%
- {\@EA\let\csname\@mode@#1\endcsname\preventedmode}
-
-\def\dodoenablemode#1% mode can be relax
- {\ifcase0\csname\@mode@#1\endcsname\relax
- \@EA\let\csname\@mode@#1\endcsname\enabledmode
- \fi}
+%D A few every's. Some are only used in \MKII\ or \MKIV.
-\def\dododisablemode#1%
- {\ifcase0\csname\@mode@#1\endcsname\or
- \@EA\let\csname\@mode@#1\endcsname\disabledmode
- \fi}
+%D Output routine:
-% handy for mp
+\newtoks \everybeforeoutput
+\newtoks \everyafteroutput
-\def\booleanmodevalue#1% can be \relax
- {\expandafter\ifx\csname\@mode@#1\endcsname\relax
- fals%
- \else\ifnum0\csname\@mode@#1\endcsname=0
- fals%
- \else
- tru%
- \fi\fi e}
+%D Shipout:
-% check macros
+\newtoks \everyshipout
+\newtoks \everybeforeshipout
+\newtoks \everyaftershipout
+\newtoks \everyfirstshipout
+\newtoks \everylastshipout
-\newif\ifcheckedmode
+%D End of run:
-\def\dodocheckformode#1%
- {\ifcase0\csname\@mode@#1\endcsname\or\checkedmodetrue\fi}
+\newtoks \everybye
+\newtoks \everygoodbye
+\newtoks \everynotabene
-\def\docheckformode#1#2#3% will be sped up with a quit
- {\cleanuplabel{#3}%
- \protect\checkedmodefalse\rawprocesscommacommand[\cleanlabel]\dodocheckformode
- \ifcheckedmode\@EA#1\else\@EA#2\fi}
+%D Document
-\def\dodocheckforallmodes#1%
- {\ifcase0\csname\@mode@#1\endcsname\relax\checkedmodefalse\or\or\checkedmodefalse\fi}
+\newtoks \everysetupdocument
+\newtoks \everyendoftextbody
-\def\docheckforallmodes#1#2#3% will be sped up with a quit
- {\cleanuplabel{#3}%
- \protect\checkedmodetrue\rawprocesscommacommand[\cleanlabel]\dodocheckforallmodes
- \ifcheckedmode\@EA#1\else\@EA#2\fi}
+\newtoks \everystarttext
+\newtoks \everystoptext
-% simple ones
+%D Purity:
-\def\doifmodeelse{\unprotect\dodoifmodeelse}
-\def\doifmode {\unprotect\dodoifmode}
-\def\doifnotmode {\unprotect\dodoifnotmode}
-\def\startmode {\unprotect\dostartmode}
-\def\startnotmode{\unprotect\dostartnotmode}
+\newtoks \everyforgetall
+\newtoks \everycleanupfeatures
-\def\dodoifmodeelse
- {\docheckformode\firstoftwoarguments\secondoftwoarguments}
+\def\cleanupfeatures{\the\everycleanupfeatures}
+\def\forgetall {\the\everyforgetall}
-\def\dodoifmode
- {\docheckformode\firstofoneargument\gobbleoneargument}
+%D Page building:
-\def\dodoifnotmode
- {\docheckformode\gobbleoneargument\firstofoneargument}
+\newtoks \everybeforepagebody
+\newtoks \everyafterpagebody
-\long\def\dostartmode[#1]%
- {\docheckformode\donothing\dostopmode{#1}}
+\let \everypagebody \everybeforepagebody % backward compatible
-\long\def\dostartnotmode[#1]%
- {\docheckformode\dostopnotmode\donothing{#1}}
+%D Multipass:
-\let\stopmode \donothing
-\let\stopnotmode\donothing
+\newtoks \everybeforeutilityread
+\newtoks \everyafterutilityread
-\long\def\dostopmode #1\stopmode {}
-\long\def\dostopnotmode#1\stopnotmode{}
+%D Floats:
-\def\doifallmodeselse{\unprotect\dodoifallmodeselse}
-\def\doifallmodes {\unprotect\dodoifallmodes}
-\def\doifnotallmodes {\unprotect\dodoifnotallmodes}
-\def\startallmodes {\unprotect\dostartallmodes}
-\def\startnotallmodes{\unprotect\dostartnotallmodes}
+\newtoks \everyinsidefloat
-\def\dodoifallmodeselse
- {\docheckforallmodes\firstoftwoarguments\secondoftwoarguments}
+%D Sectioning:
-\def\dodoifallmodes
- {\docheckforallmodes\firstofoneargument\gobbleoneargument}
+\newtoks \everyheadstart
-\def\dodoifnotallmodes
- {\docheckforallmodes\gobbleoneargument\firstofoneargument}
+%D Par building (experimental, used in xml <p> .. </p>)
-\long\def\dostartallmodes[#1]%
- {\docheckforallmodes\donothing\dostopallmodes{#1}}
+\newtoks \everybeginofpar
+\newtoks \everyendofpar
+%newtoks \everyparflush
-\long\def\dostartnotallmodes[#1]%
- {\docheckforallmodes\dostopnotallmodes\donothing{#1}}
+\def\bpar{\the\everybeginofpar\ignorespaces} % may interfere with \everypar
+\def\epar{\ifhmode\removeunwantedspaces\the\everyendofpar\fi} % test prevents problems with \bpar\epar
-\let\stopallmodes \donothing
-\let\stopnotallmodes\donothing
+%D Lists:
-\long\def\dostopallmodes #1\stopallmodes {}
-\long\def\dostopnotallmodes#1\stopnotallmodes{}
+\newtoks \everylistentry
+\newtoks \everysavesortkeys
-%D \macros
-%D {every...}
-%D
-%D A few every's.
-
-\newevery \everyshipout \relax
-\newevery \everybeforeshipout \relax
-\newevery \everyaftershipout \relax
-\newevery \everyfirstshipout \relax
-\newevery \everylastshipout \relax
-\newevery \everybye \relax
-\newevery \everygoodbye \relax
-\newevery \everystarttext \relax
-\newevery \everystoptext \relax
-\newevery \everyforgetall \relax
-\newevery \everybeforepagebody \relax
-\newevery \everyafterpagebody \relax
-\newevery \everybeforeutilityread \relax
-\newevery \everyafterutilityread \relax
-
-\let \everypagebody \everybeforepagebody % backward compatible
-
-%newevery \everybeforeutilitywrite \relax
-
-\newevery \everycleanupfeatures \relax
-\newevery \everyinsidefloat \relax
-\newevery \everyheadstart \relax
-\newevery \everyendoftextbody \relax
-\newevery \everybeginofpar \relax
-\newevery \everyendofpar \relax
-\newevery \everylistentry \relax
-\newevery \everymarking \relax
-\newevery \everysavesortkeys \relax
-
-\newevery \everyfont \relax
-\newevery \everybodyfont \EveryBodyFont
-\newevery \everyglobalbodyfont \relax
-\newevery \everyfontswitch \EveryFontSwitch
-\newevery \everydefinedfont \relax
-
-\newevery \everybeforeoutput \relax
-\newevery \everyafteroutput \relax
-
-\newevery \everybeforedisplayformula \relax
+%D Marks:
-\def\cleanupfeatures{\the\everycleanupfeatures}
-\def\forgetall {\the\everyforgetall}
+\newtoks \everymarking
-%D State mess:
+%D Fonts:
-\newtoks \everypushsomestate
-\newtoks \everypopsomestate
+\newtoks \everyfont
+\newtoks \everyglobalbodyfont
+\newtoks \everydefinedfont
-\def\pushsomestates{\the\everypushsomestate}
-\def\popsomestates {\the\everypopsomestate }
+\newevery \everybodyfont \EveryBodyFont
+\newevery \everyfontswitch \EveryFontSwitch
-%D For shared \type {\everymath} and \type {\everydisplay}:
+%D Math:
-\newevery \everymathematics \relax
+\newtoks \everybeforedisplayformula
+\newtoks \everymathematics
\prependtoks \the\everymathematics \to \everymath
\prependtoks \the\everymathematics \to \everydisplay
-% \newevery \everyparflush \relax % collected nodes
+%D Tables
-%D Experimental (used in xml <p> .. </p>
+\newtoks \everytable
-\def\bpar{\the\everybeginofpar\ignorespaces} % may interfere with \everypar
-\def\epar{\ifhmode\removeunwantedspaces\the\everyendofpar\fi} % test prevents problems with \bpar\epar
+%D State mess:
+
+\newtoks \everypushsomestate
+\newtoks \everypopsomestate
+
+\def\pushsomestates{\the\everypushsomestate}
+\def\popsomestates {\the\everypopsomestate }
%D More generic (used to be pushcolor etc)
@@ -337,8 +154,9 @@
%D
%D New. Some work needs to be done.
+% not in mkiv
+
\def\defineinputmode[#1]{\@EA\newtoks\csname every#1inputmode\endcsname}
-%def\setinputmode [#1]{\the \csname every#1inputmode\endcsname}
\def\setinputmode [#1]{\the\executeifdefined{every#1inputmode}\emptytoks}
\defineinputmode [TEX]
@@ -352,7 +170,7 @@
%D We disable trial typesetting in the output routine,
%D just to be sure.
-% defined in syst-ext
+\newif\iftrialtypesetting
\prependtoks \trialtypesettingfalse \to \everybeforepagebody
@@ -372,7 +190,7 @@
%D
%D We need this one even if no \XML\ is supported.
-\newif\ifprocessingXML
+\newif\ifprocessingXML % old way
%D \macros
%D {ifproductionrun}
@@ -382,7 +200,9 @@
\ifx\protectionlevel\undefined \newcount\protectionlevel \fi
-\newif\ifproductionrun \appendtoks \productionruntrue \to \everydump
+\newif\ifproductionrun
+
+\appendtoks \productionruntrue \to \everydump
\appendtoks \ifcase\protectionlevel\else\reportunprotection\fi \to \everydump
@@ -393,8 +213,8 @@
%D This one is relatively new and will be used as a more
%D robust test for inner situations.
-\newif \ifboxedcontent
-\newevery \everyboxedcontent \relax
+\newif \ifboxedcontent
+\newtoks\everyboxedcontent
\appendtoks \boxedcontenttrue \to \everyboxedcontent
@@ -402,145 +222,12 @@
\let\stopboxedcontent \egroup
%D \macros
-%D {fastmode}
-%D
-%D The command \type {\fastmode} disables some time consuming
-%D typesetting.
-
-\newevery \everyfastmode \relax
-
-\newif\iffastmode
-
-\def\fastmode
- {\fastmodetrue
- \the\everyfastmode}
-
-\def\silentmode % ook hier \everysilentmode net als \fastmode
- {\showmessagesfalse
- \showwarningsfalse
- \let\writestatus\gobbletwoarguments}
-
-%D \macros
-%D {pdfoutput}
-%D
-%D There are some fundamental differences between producing
-%D \DVI\ and \PDF\ output, especially when we use \PDFTEX, like
-%D object reuse, one pass graphic inclusion and the lack of a
-%D postprocessing stage. Because we must make sure that
-%D \CONTEXT\ knows what it's up to, we always default to \DVI\
-%D mode, even when users explicitly ask for \PDF\ output in the
-%D \PDFTEX\ configuration file.
-
-% we assume no pdfcontext or whatever
-%
-% \ifx\pdfoutput\undefined \else
-% \prependtoks \pdfoutput=0 \to \everyjob
-% \fi
-
-%D \macros
-%D {setvariables,getvariable,getvariabledefault}
+%D {fastmode,silentmode}
%D
-%D \starttyping
-%D \setvariables[xx][title=]
-%D \setvariables[xx][title=test test]
-%D \setvariables[xx][title=test $x=1$ test] % fatal error reported
-%D \setvariables[xx][title=test {$x=1$} test]
-%D \setvariables[xx][title] % fatal error reported
-%D \setvariables[xx][titletitel=e]
-%D \stoptyping
-
-\def\??vars{@@vars}
-
-\def\setvariables {\dotripleargument\dosetvariables[\getrawparameters ]}
-\def\setevariables{\dotripleargument\dosetvariables[\getraweparameters]}
-\def\setgvariables{\dotripleargument\dosetvariables[\getrawgparameters]}
-\def\setxvariables{\dotripleargument\dosetvariables[\getrawxparameters]}
-
-\def\globalsetvariables % obsolete
- {\dotripleargument\dosetvariables[\globalgetrawparameters]}
-
-% \long\def\dosetvariables[#1][#2][#3]%
-% {\errorisfataltrue
-% \def\currentvariableclass{#2}%
-% \getvariable{#2}\s!reset
-% #1[\??vars:#2:][#3]%
-% \getvariable{#2}\s!set
-% \errorisfatalfalse}
-%
-% permit nested definitions while preventing nested set/reset
-%
-% wrong:
-%
-% \long\def\dosetvariables[#1][#2][#3]%
-% {\errorisfataltrue
-% \getrawparameters[\??vars:*:][\s!reset=*,\s!set=*,#3]%
-% \doifelse{\getvalue{\??vars:*:\s!reset}\getvalue{\??vars:*:\s!set}}{**}
-% {\doifelse{#2}\currentvariableclass
-% {#1[\??vars:#2:][#3]}
-% {\pushmacro\currentvariableclass
-% \def\currentvariableclass{#2}%
-% \getvariable{#2}\s!reset
-% #1[\??vars:#2:][#3]%
-% \getvariable{#2}\s!set
-% \popmacro\currentvariableclass}}%
-% {#1[\??vars:#2:][#3]}%
-% \errorisfatalfalse}
-
-\long\def\dosetvariables[#1][#2][#3]% tricky, test on s-pre-60
- {\errorisfataltrue
- \doifelse{#2}\currentvariableclass
- {#1[\??vars:#2:][#3]}%
- {\pushmacro\currentvariableclass
- \def\currentvariableclass{#2}%
- \getvariable{#2}\s!reset
- #1[\??vars:#2:][#3]%
- \getvariable{#2}\s!set
- \popmacro\currentvariableclass}%
- \errorisfatalfalse}
-
-\long\def\setvariable #1#2#3{\long\setvalue {\??vars:#1:#2}{#3}}
-\long\def\setevariable#1#2#3{\long\setevalue{\??vars:#1:#2}{#3}}
-\long\def\setgvariable#1#2#3{\long\setgvalue{\??vars:#1:#2}{#3}}
-\long\def\setxvariable#1#2#3{\long\setxvalue{\??vars:#1:#2}{#3}}
-
-\def\getvariable#1#2% to be sped up
- {\csname
- \ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi
- \endcsname}
-
-\def\showvariable#1#2%
- {\showvalue{\ifcsname\??vars:#1:#2\endcsname\??vars:#1:#2\else\s!empty\fi}}
-
-\let\currentvariableclass\empty
-
-%D \macros
-%D {doifelsevariable,doifvariable,doifnotvariable}
-%D
-%D A few trivial macros:
-
-\def\doifelsevariable#1#2%
- {\ifcsname\??vars:#1:#2\endcsname
- \expandafter\firstoftwoarguments
- \else
- \expandafter\secondoftwoarguments
- \fi}
-
-\def\doifvariable#1#2%
- {\ifcsname\??vars:#1:#2\endcsname
- \expandafter\firstofoneargument
- \else
- \expandafter\gobbleoneargument
- \fi}
-
-\def\doifnotvariable#1#2%
- {\ifcsname\??vars:#1:#2\endcsname
- \expandafter\gobbleoneargument
- \else
- \expandafter\firstofoneargument
- \fi}
+%D These commands are obsolete.
-\def\getvariabledefault#1#2% #3% can be command, so no ifcsname here
- {\executeifdefined{\??vars:#1:#2}}% {#3}
+\let\fastmode \relax
+\let\silentmode\relax
%D \macros
%D {defineselector,setupselector}
@@ -571,95 +258,20 @@
{\executeifdefined{\??sx#1\c!max}1}
{\executeifdefined{\??sx#1\c!n }1}}
-%D \macros
-%D {checkvariables}
-%D
-%D I'll probably forget that this on exists.
-
-\def\checkvariables
- {\dodoubleargument\docheckvariables}
-
-\def\docheckvariables
- {\dogetparameters\docheckrawvalue}
-
-\def\docheckrawvalue#1#2#3%
- {\doifundefined {\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}
- {\doifvaluenothing{\??vars:#1:#2}{\setvalue{\??vars:#1:#2}{#3}}}}
-
%D We store some original meanings, maybe in \type
%D {math-ini}.
-\let\normalat \at
-\let\normalin \in
-\let\normalfrom \from
-\let\normalover \over
-\let\normalabout \about
-
-\let\normalabove \above
-\let\normalatop \atop
-
-\let\normaloverwithdelims \overwithdelims
-\let\normalabovewithdelims\abovewithdelims
-\let\normalatopwithdelims \atopwithdelims
+\let\normalat \at
+\let\normalin \in
+\let\normalfrom \from
+%let\normalover \over
+\let\normalabout\about
%D Add-ons:
\let\startlayoutcomponent\gobbletwoarguments
\let\stoplayoutcomponent \relax
-
-%D Label cleanup:
-\bgroup % some day this will go away / we could use detokenize as well
-
-% actually we should handle all discretionaries here
-
-\catcode`:=\@@active
-
-\gdef\cleanuplabel#1%
- {\begingroup
- \let:\lettercolon
- \xdef\cleanlabel{#1}%
- \endgroup}
-
-\gdef\cleanupprefixedlabel#1#2%
- {\begingroup
- \let:\lettercolon
- \xdef\cleanprefix{#1}%
- \xdef\cleanlabel {#2}%
- \endgroup}
-
-\gdef\protectlabels
- {\let:\lettercolon}
-
-\global\def\blabelgroup {\begingroup \let:\lettercolon}
-\global\let\elabelgroup \endgroup
-
-\gdef\labelcsname
- {\begingroup\let:\lettercolon
- \expandafter\endgroup\csname}
-
-\gdef\labelvalue#1%
- {\labelcsname#1\endcsname}
-
-\egroup
-
-%D TO BE TESTED FIRST (needs changes in usage too)
-
-% \def\cleanuplabel#1%
-% {\edef\cleanlabel{\detokenize{#1}}}
-%
-% \def\cleanupprefixedlabel#1#2%
-% {\edef\cleanprefix{\detokenize{#1}}%
-% \edef\cleanlabel {\detokenize{#2}}}
-%
-% \def\labelvalue#1%
-% {\csname\detokenize{#1}\endcsname}
-%
-% \let\protectlabels\donothing
-%
-% \def\blabelgroup {\begingroup} % why no \let ?
-% \let\elabelgroup \endgroup
-
%D Concepts:
\chardef\conceptmode\zerocount
diff --git a/tex/context/base/core-ver.mkii b/tex/context/base/core-ver.mkii
index 4e51c934c..dd8f5f84f 100644
--- a/tex/context/base/core-ver.mkii
+++ b/tex/context/base/core-ver.mkii
@@ -11,12 +11,51 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Verbatim}
+
\unprotect
-% uses \prettyidentifier and sets \setupprettytype
+\ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+\ifx\stoplinenumbering \undefined \let\stoplinenumbering\relax \fi
+\ifx\setuplinenumbering\undefined \def\setuplinenumbering[#1]{} \fi
+
+% \type{ <crlf> char} geeft bagger
+
+%D We are going to embed the general verbatim support macros in
+%D a proper environment. First we show the common setup
+%D macro, so we know what features are supported. The options
+%D are hooked into the support macros via the \type{\obey}
+%D macros.
+
+\newif\ifslantedtypeactivated
+\newif\ifslantedtypepermitted
-\def\mksetupprettiesintype
- {\doifundefined{setuppretty\prettyidentifier type}%
+\def\switchslantedtype
+ {\ifslantedtypepermitted
+ \ifslantedtypeactivated
+ \slantedtypeactivatedfalse\tttf
+ \else
+ \slantedtypeactivatedtrue\ttsl
+ \fi
+ \fi}
+
+\newprettytrue % movet to here from cont-sys.tex
+
+\def\prettyidentifier {TEX}
+\def\prettypalet {}
+
+\def\installprettytype
+ {\dodoubleargument\doinstallprettytype}
+
+\def\doinstallprettytype[#1][#2]% map #1 onto #2
+ {\uppercasestring#1\to\asciia
+ \uppercasestring#2\to\asciib
+ \setevalue{\??ty\??ty\asciia}{\asciib}}
+
+\def\setupprettiesintype#1%
+ {\uppercasestring#1\to\ascii
+ \edef\prettyidentifier{\executeifdefined{\??ty\??ty\ascii}{TEX}}%
+ \doifundefined{setuppretty\prettyidentifier type}%
{\startnointerference
\restorecatcodes % also needed when loading during \newpretty
\startreadingfile % restore < and > if needed
@@ -26,8 +65,229 @@
\stopnointerference}%
\doifdefinedelse{setuppretty\prettyidentifier type}%
{\let\uncatcodecharacters\uncatcodeallcharacters % ugly, should be switch / todo
- \def\mksetupprettytype{\getvalue{setuppretty\prettyidentifier type}}}
- {\let\mksetupprettytype\relax}}
+ \def\dosetupprettytype{\getvalue{setuppretty\prettyidentifier type}}}
+ {\let\dosetupprettytype\relax}}
+
+\def\setupprettytype{\dosetupprettytype}
+
+% \def\setupcommonverbatim
+% {\recatcodeuppercharactersfalse % obey regime / encoding
+% %
+% \let\prettyidentifier\s!default
+% %
+% \doifelse{\typingparameter\c!text}\v!yes
+% \naturaltextexttrue
+% \naturaltextextfalse
+% \def\prettyidentifierfont{\typingparameter\c!icommand}%
+% \def\prettyvariablefont {\typingparameter\c!vcommand}%
+% \def\prettynaturalfont {\typingparameter\c!ccommand}%
+% %
+% \doif{\typingparameter\c!space}\v!on
+% {\def\obeyspaces{\setcontrolspaces}}%
+% \doif{\typingparameter\c!page }\v!no
+% {\def\obeypages {\ignorepages}}%
+% %
+% \doifelse{\typingparameter\c!tab}\v!yes
+% {\def\obeytabs{\settabskips}}%
+% {\doif{\typingparameter\c!tab}\s!ascii
+% {\chardef\tabskipmode\plustwo % quit on >127
+% \def\obeytabs{\settabskips}}}%
+% %
+% \ignorehyphens % default
+% \ExpandFirstAfter\processaction
+% [\typingparameter\c!lines]
+% [ \v!yes=>\obeybreakpoints,
+% \v!hyphenated=>\obeyhyphens]%
+% \processaction
+% [\typingparameter\c!empty]
+% [\v!yes=>\obeyemptylines,
+% \v!all=>\obeyallemptylines]%
+% %
+% \ExpandFirstAfter\processaction
+% [\typingparameter\c!option]
+% [ \v!none=>\let\obeycharacters\relax,
+% \v!color=>\setupprettiesintype{TEX}%
+% \let\obeycharacters\setupprettytype
+% \let\obeytabs\ignoretabs,
+% \v!normal=>\let\obeycharacters\setupgroupedtype,
+% \v!commands=>\def\obeycharacters{\setupcommandsintype}% \let
+% \let\obeytabs\ignoretabs,
+% \v!slanted=>\let\obeycharacters\setupslantedtype
+% \let\obeytabs\ignoretabs,
+% \s!unknown=>\setupprettiesintype{\typingparameter\c!option}%
+% \let\obeycharacters\setupprettytype
+% \let\obeytabs\ignoretabs]%
+% \doifnumberelse{\typingparameter\c!tab}
+% {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
+% \donothing
+% %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
+% % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
+% \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
+% \setupverbatimcolor}
+
+\setvalue{\??tp:\c!lines:\v!yes }{\obeybreakpoints}
+\setvalue{\??tp:\c!lines:\v!hyphenated}{\obeyhyphens}
+
+\setvalue{\??tp:\c!empty:\v!yes }{\obeyemptylines}
+\setvalue{\??tp:\c!empty:\v!all }{\obeyallemptylines}
+
+\setvalue{\??tp:\c!option:\v!none }{\let\obeycharacters\relax}
+\setvalue{\??tp:\c!option:\v!color }{\setupprettiesintype{TEX}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!normal }{\let\obeycharacters\setupgroupedtype}
+\setvalue{\??tp:\c!option:\v!commands }{\def\obeycharacters{\setupcommandsintype}%
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!slanted }{\let\obeycharacters\setupslantedtype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\s!unknown }{\setupprettiesintype{\typingparameter\c!option}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+
+
+\def\setupcommonverbatim
+ {\recatcodeuppercharactersfalse % obey regime / encoding
+ %
+ \let\prettyidentifier\s!default
+ %
+ \doifelse{\typingparameter\c!text}\v!yes
+ \naturaltextexttrue
+ \naturaltextextfalse
+ \def\prettyidentifierfont{\typingparameter\c!icommand}%
+ \def\prettyvariablefont {\typingparameter\c!vcommand}%
+ \def\prettynaturalfont {\typingparameter\c!ccommand}%
+ %
+ \doif{\typingparameter\c!space}\v!on
+ {\def\obeyspaces{\setcontrolspaces}}%
+ \doif{\typingparameter\c!page }\v!no
+ {\def\obeypages {\ignorepages}}%
+ %
+ \doifelse{\typingparameter\c!tab}\v!yes
+ {\def\obeytabs{\settabskips}}%
+ {\doif{\typingparameter\c!tab}\s!ascii % not needed in mkiv
+ {\chardef\tabskipmode\plustwo % quit on >127
+ \def\obeytabs{\settabskips}}}%
+ %
+ \ignorehyphens % default
+ \getvalue{\??tp:\c!lines:\typingparameter\c!lines}%
+ \getvalue{\??tp:\c!empty:\typingparameter\c!empty}%
+ \getvalue{\??tp:\c!option:\ifcsname\??tp:\c!option:\typingparameter\c!option\endcsname\typingparameter\c!option\else\s!unknown\fi}%
+ \doifnumberelse{\typingparameter\c!tab}
+ {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
+ \donothing
+ %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
+ % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
+ \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
+ \setupverbatimcolor}
+
+% BEWARE: the noligatures will globally change the verbatim font's behaviour
+
+% test case:
+%
+% \definetype[typeTEX][option=tex]
+%
+% \typeTEX|\example---oeps|. this---ligates---again.
+% \typeTEX{\example---oeps}. this---ligates---again.
+% \type {\example---oeps}. this---ligates---again.
+
+\def\setupcommandsintype % can also be \string\
+ {\setupgroupedtype
+ \edef\\{\typingparameter\c!escape}%
+ \letvalue{\\}=\\% for instance \/=/
+ \@EA\catcode\@EA`\\=\@@escape
+ \def\BTEX##1\ETEX##2% ##2 gobbles active space
+ {\naturaltextext##1\unskip\relax}}
+
+\def\setupslantedtype
+ {\slantedtypepermittedtrue\setupgroupedtype}
+
+\ifx\setupprettytype \undefined \let\setupprettytype \relax \fi
+\ifx\setupslantedtype \undefined \let\setupslantedtype \relax \fi
+\ifx\setupgroupedtype \undefined \let\setupgroupedtype \relax \fi
+\ifx\normalnoligatures\undefined \let\normalnoligatures\gobbleoneargument \fi
+
+%D The verbatim commands have a rather long and turbulent
+%D history. Most users of \CONTEXT\ probably will never use
+%D some of the features, but I've kept in mind that when one is
+%D writing a users manual, about everything can and undoubtly
+%D will be subject to a verbatim treatment.
+%D
+%D Verbatim command are very sensitive to argument processing,
+%D which is a direct result of the \CATCODES\ being fixed at
+%D reading time. With our growing understanding of \TEX,
+%D especially of the mechanism that can be used for looking
+%D ahead and manipulating \CATCODES, the verbatim support
+%D became more and more advanced and natural.
+%D
+%D Typesetting inline verbatim can be accomplished by
+%D \type{\type}, which in this sentence was typeset by saying
+%D just \type{\type{\type}}, which in turn was typeset by
+%D \unknown. Using the normal grouping characters \type{{}} is
+%D the most natural way of using this command.
+%D
+%D A second, more or less redundant, alternative is delimiting
+%D the argument with an own character. This method was
+%D implemented in the context of a publication in the \MAPS,
+%D where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using
+%D \type{<<} and \type{>>} as delimiters. This alternative can
+%D be used in situations where slanted typeseting is needed.
+
+% todo: we can use \letter... here:
+
+\def\lesscharacter {<}
+\def\morecharacter {>}
+
+\chardef\texescape = `\\
+\chardef\leftargument = `\{
+\chardef\rightargument = `\}
+
+%D \macros
+%D {type}
+%D
+%D We define \type{\type} as a protected command. This command
+%D has several invocations: grouped, wirt boundary characters,
+%D and with font switches.
+
+% \starttyping
+% normal: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+% normal: \par \type{xx<..xx..<xx <slanted> >..>xx} \par \type{<....>} \par \type{<..<xx>..>}
+% \setuptype[option=slanted]
+% slanted: \par \type{xx<<..sl..<<xx <<sl>> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<<sl>>..>> \par
+% slanted: \par \type{xx<<..sl..<xx <sl> xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<sl>..>> \par
+% \setuptype[option=none]
+% none: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+% \stoptyping
+
+%D When writing the manual to \CONTEXT\ and documenting this
+%D source we needed to typeset \type{<<} and \type{>>}. Because
+%D we wanted to do this in the natural way, we've adapted the
+%D original definition a bit. This implementation went through
+%D several live cycles. The final implementation looks a bit
+%D further and treats the lone \type{<<} and \type{>>} a bit
+%D different. The \type {\null} prevents ligatures, which
+%D unfortunately turn up in Lucida fonts.
+
+%D The following lines show what happens when we set
+%D \type {option=commands}.
+%D
+%D \startbuffer
+%D \starttyping
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test test test/BTEX \bf(nota bene)/ETEX test
+%D test test test /BTEX \bf(nota bene)/ETEX test
+%D \stoptyping
+%D \stopbuffer
+%D
+%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
+%D
+%D this was keyed in as:
+%D
+%D \typebuffer
+
+\unexpanded\def\type{\dotype\empty}
% not that fast but catches \type{\command} % nothing more after \command
%
@@ -51,7 +311,7 @@
% the rather messy \type command
-\def\mktype#1% was \dotype
+\def\dotype#1% was \dotype
{\bgroup
\resumecoloraftergroup % a problem is that we can still be in color mode, tricky hack
\begstrut % new, enables leading space in \type { abc } at par start / begstrut else no hyphenation
@@ -101,6 +361,32 @@
\@EAEAEA\dodotypeD
\fi\fi}
+% The next one is safe for: \def\xx#1{\type{#1}} \xx{\ifx}
+
+\let\protectedfirsttype\string % \relax for special cases
+
+\bgroup
+\catcode`\<=\active
+\catcode`\>=\active
+\gdef\doprotectfirsttype
+ {\normalifx\next<%
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\bgroup
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\egroup % takes care of \type{}
+ \endrobusttest \let\next\relax
+ \normalelse\normalifx\next\activeleftargument
+ \endrobusttest \let\next\relax
+ \normalelse
+ \endrobusttest \let\next\protectedfirsttype
+ \normalfi\normalfi\normalfi\normalfi
+ \next}
+\egroup
+
+\def\protectfirsttype
+ {\beginrobusttest
+ \futurelet\next\doprotectfirsttype}
+
% Verbatim does not work when passed as an argument, so here is a
% workaround. Beware, spaces are introduced after a \type {\csname}.
@@ -247,52 +533,802 @@
\def>{\futurelet\next\domore}}
\egroup
-\def\mksetupcommandsintype% can also be \string\
- {\setupgroupedtype
- \edef\\{\typingparameter\c!escape}%
- \letvalue{\\}=\\% for instance \/=/
- \@EA\catcode\@EA`\\=\@@escape
- \def\BTEX##1\ETEX##2% ##2 gobbles active space
- {\naturaltextext##1\unskip\relax}}
+%D The neccessary initializations are done by calling
+%D \type{\initializetype} which in return calls for the support
+%D macro \type{\setupinlineverbatim}.
-\def\mksetupslantedtype
- {\setupgroupedtype}
+\def\initializetype
+ {\let\obeylines\ignorelines
+ \setupcommonverbatim
+ \setupinlineverbatim}
-\let\protectedfirsttype\string % \relax for special cases
+%D \macros
+%D {setuptype}
+%D
+%D Some characteristics of \type{\type} can be set up by:
-% The next one is safe for: \def\xx#1{\type{#1}} \xx{\ifx}
+\def\setuptype
+ {\dodoubleempty\dosetuptype}
-\bgroup
-\catcode`\<=\active
-\catcode`\>=\active
-\gdef\doprotectfirsttype
- {\normalifx\next<%
- \endrobusttest \let\next\relax
- \normalelse\normalifx\next\bgroup
- \endrobusttest \let\next\relax
- \normalelse\normalifx\next\egroup % takes care of \type{}
- \endrobusttest \let\next\relax
- \normalelse\normalifx\next\activeleftargument
- \endrobusttest \let\next\relax
- \normalelse
- \endrobusttest \let\next\protectedfirsttype
- \normalfi\normalfi\normalfi\normalfi
- \next}
-\egroup
+\def\dosetuptype[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ty#1][#2]%
+ \else
+ \getparameters[\??ty][#1]%
+ \fi}
-\def\protectfirsttype
- {\beginrobusttest
- \futurelet\next\doprotectfirsttype}
+%D \macros
+%D {typ,obeyhyphens,obeybreakpoints}
+%D
+%D Although it's not clear from the macros, one character
+%D trait of this macros, which are build on top of the support
+%D module, is that they don't hyphenate. We therefore offer
+%D the alternative \type{\typ}. The current implementation
+%D works all right, but a decent hyphenation support of
+%D \type{\tt} text will be implemented soon.
+
+\def\obeyhyphens
+ {\def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.25em\relax} % hm a bit of stretch !
-% typing:
+\def\obeybreakpoints
+ {\ignorehyphens
+ \veryraggedright}
-\def\mktypeblockverbatim#1#2%
- {\processdisplayverbatim{#2}} % needs to be fixed
+\def\ignorehyphens
+ {% \language\minusone % extra bonus, the \null should do the job too
+ \def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.5em\relax}
-% typefile:
+\unexpanded\def\typ
+ {\bgroup
+ \let\@@tylines\v!hyphenated
+ \futurelet\next\dodotype}
-\def\mktypefileverbatim {\processfileverbatim \readfilename} % #1
-\def\mktypefilelinesverbatim{\processfilelinesverbatim\readfilename} % #1 / #2#3
+%D \macros
+%D {tex,arg,mat,dis}
+%D
+%D Sometimes, for instance when we pass verbatim text as an
+%D argument, the fixed \CATCODES\ interfere with our wishes. An
+%D experimental implementation of character by character
+%D processing of verbatim text did overcome this limitation,
+%D but we've decided not to use that slow and sometimes
+%D troublesome solution. Instead we stick to some 'old'
+%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
+%D
+%D The next implementation is more clear but less versatile,
+%D so we treated it for a beter one.
+%D
+%D \starttyping
+%D \def\dospecialtype#1#2%
+%D {\bgroup
+%D \initializetype
+%D \catcode`\{=\@@begingroup
+%D \catcode`\}=\@@endgroup
+%D \def\dospecialtype%
+%D {\def\dospecialtype{#2\egroup}%
+%D \bgroup
+%D \aftergroup\dospecialtype
+%D #1}%
+%D \afterassignment\dospecialtype
+%D \let\next=}
+%D
+%D \unexpanded\def\tex{\dospecialtype\texescape\relax}
+%D \unexpanded\def\arg{\dospecialtype\leftargument\rightargument}
+%D \unexpanded\def\mat{\dospecialtype\$\$}
+%D \unexpanded\def\dis{\dospecialtype{\$\$}{\$\$}}
+%D \stoptyping
-\protect \endinput
+\def\setgroupedtype
+ {\let\currenttypingclass\??ty
+ \initializetype
+ \verbatimcolor
+ %\setcatcodetable \typcatcodesa
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup}
+
+\unexpanded\def\tex{\groupedcommand{\setgroupedtype\texescape}{\relax}}
+\unexpanded\def\arg{\groupedcommand{\setgroupedtype\leftargument}{\rightargument}}
+\unexpanded\def\mat{\groupedcommand{\setgroupedtype\$}{\$}}
+\unexpanded\def\dis{\groupedcommand{\setgroupedtype\$\$}{\$\$}}
+
+%D \macros
+%D {starttyping}
+%D
+%D Display verbatim is realized far more easy, which is mostly
+%D due to the fact that we use \type{\stop...} as delimiter.
+%D The implementation inherits some features, for instance the
+%D support of linenumbering, which can best be studied in the
+%D documented support module.
+
+\let\currenttyping \empty
+\let\currenttypingclass\??ty % saveguard
+
+% \def\typingparameter#1%
+% {\executeifdefined
+% {\currenttypingclass\currenttyping#1}%
+% {\executeifdefined{\currenttypingclass#1}\empty}}
+
+\def\typingparameter#1%
+ {\ifcsname\currenttypingclass\currenttyping#1\endcsname
+ \csname\currenttypingclass\currenttyping#1\endcsname
+ \else\ifcsname\currenttypingclass#1\endcsname
+ \csname\currenttypingclass#1\endcsname
+ \fi\fi}
+
+\def\settypingparameter#1#2%
+ {\setvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+\def\setxtypingparameter#1#2%
+ {\setxvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+% \def\initializetyping
+% {%\donefalse
+% \switchtobodyfont[\typingparameter\c!bodyfont]%
+% \donefalse
+% \scratchskip\typingparameter\c!oddmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \scratchskip\typingparameter\c!evenmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \ifdone
+% \def\doopenupverbatimline
+% {\getpagestatus
+% \ifrightpage
+% \hskip\typingparameter\c!oddmargin\relax
+% \else
+% \hskip\typingparameter\c!evenmargin\relax
+% \fi}%
+% \else
+% \doadaptleftskip{\typingparameter\c!margin}%
+% \fi
+% \doifdefinedelse{\??bo\typingparameter\c!blank}
+% {\edef\!!stringa{\csname\??bo\typingparameter\c!blank\endcsname}}
+% {\edef\!!stringa{\typingparameter\c!blank}}%
+% \processaction
+% [\!!stringa]
+% [ \v!standard=>\scratchskip\ctxparskip,
+% \v!small=>\scratchskip\blankokleinmaat,
+% \v!medium=>\scratchskip\blankomiddelmaat,
+% \v!big=>\scratchskip\blankogrootmaat,
+% \v!halfline=>\scratchskip.5\baselineskip,
+% \v!line=>\scratchskip\baselineskip,
+% \v!none=>\scratchskip\zeropoint,
+% \s!unknown=>\scratchskip\commalistelement]%
+% \ifgridsnapping
+% \ifdim\scratchskip=.5\baselineskip\relax
+% \edef\verbatimbaselineskip{\the\scratchskip}% new
+% \else
+% \edef\verbatimbaselineskip{\the\baselineskip}%
+% \fi
+% \else
+% \edef\verbatimbaselineskip{\the\scratchskip}%
+% \fi
+% \setupcommonverbatim}
+
+\setvalue{\??tp:\c!blank:\v!standard}{\ctxparskip}
+\setvalue{\??tp:\c!blank:\v!small }{\blankokleinmaat}
+\setvalue{\??tp:\c!blank:\v!medium }{\blankomiddelmaat}
+\setvalue{\??tp:\c!blank:\v!big }{\blankogrootmaat}
+\setvalue{\??tp:\c!blank:\v!halfline}{.5\baselineskip}
+\setvalue{\??tp:\c!blank:\v!line }{\baselineskip}
+\setvalue{\??tp:\c!blank:\v!none }{\zeropoint}
+
+\def\initializetyping
+ {%\donefalse
+ \switchtobodyfont[\typingparameter\c!bodyfont]%
+ \donefalse
+ \scratchskip\typingparameter\c!oddmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \scratchskip\typingparameter\c!evenmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \ifdone
+ \def\doopenupverbatimline
+ {\getpagestatus
+ \ifrightpage
+ \hskip\typingparameter\c!oddmargin\relax
+ \else
+ \hskip\typingparameter\c!evenmargin\relax
+ \fi}%
+ \else
+ \doadaptleftskip{\typingparameter\c!margin}%
+ \fi
+ \edef\!!stringa{\executeifdefined{\??bo\typingparameter\c!blank}{\typingparameter\c!blank}}%
+ \scratchskip\executeifdefined{\??tp:\c!blank:\!!stringa}\!!stringa\relax
+ \ifgridsnapping
+ \ifdim\scratchskip=.5\baselineskip\relax
+ \edef\verbatimbaselineskip{\the\scratchskip}% new
+ \else
+ \edef\verbatimbaselineskip{\the\baselineskip}%
+ \fi
+ \else
+ \edef\verbatimbaselineskip{\the\scratchskip}%
+ \fi
+ \setupcommonverbatim}
+
+%D The basic display verbatim commands are defined in an
+%D indirect way. As we will see, they are a specific case of a
+%D more general mechanism.
+
+% we need this hack because otherwise verbatim skips
+% the first line (everything after the initial command)
+
+\def\dostarttyping#1% tricky non standard lookahead
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \obeylines
+ \futurelet\nexttoken\dodostarttyping}
+
+\def\dodostarttyping
+ {\ifx\nexttoken[%
+ \expandafter\dododostarttyping
+ \else
+ \expandafter\nododostarttyping
+ \fi}
+
+\def\nododostarttyping
+ {\dododostarttyping[]}
+
+\def\dododostarttyping[#1]%
+ {\typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#1}%
+ \initializetyping
+ \startverbatimcolor
+ \expanded{\processdisplayverbatim{\s!stop\currenttyping}}}
+
+\def\dostoptyping#1% hm, currenttyping
+ {\stopverbatimcolor
+ \stoppacked % includes \egroup
+ \typingparameter\c!after
+ \egroup
+ \dochecknextindentation{\??tp#1}%
+ \dorechecknextindentation}
+
+%D Line numbering for files is combined with filtering, while
+%D display verbatim has the ability to continue.
+%D
+%D \starttyping
+%D \typefile[numbering=file,start=10,stop=12]{test.tex}
+%D
+%D \definetyping[code][numbering=line]
+%D
+%D \starttext
+%D \startcode
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[continue]
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=10]
+%D ...
+%D \stopcode
+%D \stoptyping
+
+%D \macros
+%D {setuptyping}
+%D
+%D The setup of typing accepts two arguments. The optional
+%D first one identifies the user defined ones. If only one
+%D argument is given, the values apply to both the standard
+%D command \type{\starttyping} and \type{\typefile}.
+
+\def\dosetuptyping[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??tp#1][#2]%
+ \else
+ \getparameters[\??tp][#1]%
+ \fi}
+
+\def\setuptyping
+ {\dodoubleempty\dosetuptyping}
+
+%D \macros
+%D {definetype}
+%D
+%D Specific inline verbatim commands can be defined with the
+%D following command.
+
+\def\definetype
+ {\dodoubleempty\dodefinetype}
+
+\def\dodefinetype[#1][#2]%
+ {\unexpanded\setvalue{#1}{\dotype{#1}}%
+ \getparameters[\??ty#1][#2]}
+
+%D \macros
+%D {definetyping}
+%D
+%D For most users the standard \type{\start}||\type{\stop}||pair
+%D will suffice, but for documentation purposes the next
+%D definition command can be of use:
+%D
+%D \starttyping
+%D \definetyping[extratyping][margin=3em]
+%D
+%D \startextratyping
+%D these extra ones are indented by 1 em
+%D \stopextratyping
+%D \stoptyping
+%D
+%D The definitions default to the standard typing values.
+
+\def\presettyping[#1][#2]%
+ {\copyparameters[\??tp#1][\??tp][\c!color,\c!style]%
+ \getparameters [\??tp#1][#2]}
+
+\def\dodefinetyping[#1][#2]%
+ {\setvalue{\e!start#1}{\dostarttyping{#1}}%
+ \setvalue{\e!stop #1}{\dostoptyping {#1}}%
+ \presettyping[#1][#2]}
+
+\def\definetyping
+ {\dodoubleempty\dodefinetyping}
+
+%D We can use some core color commands. These are faster than
+%D the standard color switching ones and work ok on a line by
+%D line basis.
+%D
+%D \starttyping
+%D \def\setupverbatimcolor%
+%D {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}%
+%D \def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+%D \def\endofpretty {\stopcolormode}}
+%D \stoptyping
+%D
+%D Since we support a global color too, the folowing
+%D definition is better:
+
+% \def\setupverbatimcolor% fast and local versus slow and global
+% {\doifelsenothing{\typingparameter\c!color}
+% {\def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+% \let\endofpretty \restorecolormode % \stopcolormode
+% \let\startverbatimcolor \relax
+% \let\stopverbatimcolor \relax
+% \let\verbatimcolor \relax}
+% {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+% \let\endofpretty \stopcolor
+% \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+% \let\stopverbatimcolor \stopcolor
+% \def\verbatimcolor {\getvalue{\typingparameter\c!color}}}% command !
+% \doifelsenothing{\typingparameter\c!palet}
+% {\let\prettypalet\empty
+% \let\endofpretty\relax
+% \def\beginofpretty[##1]{}}
+% {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+%
+% let's forget about this optimization not that we have mkiv
+
+\def\setupverbatimcolor
+ {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+ \let\endofpretty \stopcolor
+ \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+ \let\stopverbatimcolor \stopcolor
+ \def\verbatimcolor {\getvalue{\typingparameter\c!color}}% command !
+ \doifelsenothing{\typingparameter\c!palet}
+ {\let\prettypalet\empty
+ \let\endofpretty\relax
+ \def\beginofpretty[##1]{}}
+ {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+
+\let\prettypalet \empty
+\let\startverbatimcolor\relax
+\let\stopverbatimcolor \relax
+\let\verbatimcolor \relax
+
+%D In the verbatim module, there are some examples given of
+%D the more obscure features of the verbatim environments.
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This gives, as can be expected:
+%D
+%D \getbuffer
+%D
+%D When we want to see some typeset \TEX\ too, we can say:
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% %%\ N usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} %%\ N becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or:
+%D
+%D \getbuffer
+%D
+%D In a similar way:
+%D
+%D \startbuffer
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives:
+%D
+%D \getbuffer
+%D
+%D The next examples sow how we can directly call for natural
+%D \TEX\ comments:
+%D
+%D \startbuffer
+%D \setuptyping
+%D [TEX]
+%D [text=yes]
+%D
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D
+%D \setuptyping
+%D [SQL]
+%D [text=yes,palet=,icommand=\bf,vcommand=,ccommand=\it]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D
+%D \setuptyping
+%D [SQL]
+%D [ccommand=\tf\underbar]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Now watch:
+%D
+%D \getbuffer
+%D
+%D The natural \TEX\ typesetting was introduced when Tobias
+%D and Berend started using verbatim \JAVASCRIPT\ and \SQL.
+
+%D \macros
+%D {EveryPar, EveryLine, iflinepar}
+%D
+%D One of the features of these commands is the support of
+%D \type{\EveryPar}, \type{\EveryLine} and \type{\iflinepar}.
+%D In the documentation of the verbatim support module we give
+%D some examples of line- and paragraph numbering using these
+%D macros.
+
+%D \macros
+%D {typefile}
+%D
+%D Typesetting files verbatim (for the moment) only supports
+%D colorization of \TEX\ sources as valid option. The other
+%D setup values are inherited from display verbatim.
+%D The implementation of \type{\typefile} is straightforward:
+% new feature (not yet 100\% ok)
+%
+% \setuptyping[file][numbering=file]
+%
+% \typefile[start=2,nlines=3]{zapf}
+% \typefile[start=continue,nlines=13]{zapf}
+% \typefile{zapf}
+%
+% \setuptyping[file][numbering=line]
+%
+% \typefile[start=4,step=3]{zapf}
+% \typefile{zapf}
+
+\def\typefile
+ {\dodoubleempty\dotypefile}
+
+\def\dotypefile[#1][#2]#3%
+ {\ifsecondargument
+ \dodotypefile[#1][#2]{#3}%
+ \else\iffirstargument
+ \doifassignmentelse{#1}
+ {\dodotypefile[\v!file][#1]{#3}}
+ {\dodotypefile[#1][]{#3}}%
+ \else
+ \dodotypefile[\v!file][]{#3}%
+ \fi\fi}
+
+\def\dosetuptypelinenumbering#1% fuzzy
+ {\doifundefined{\currenttypingclass\currenttyping\c!start}
+ {\setuptyping[\currenttyping][\c!start=1,\c!stop=,\c!step=1,\c!nlines=]}%
+ \setuptyping[\currenttyping][#1]%
+ \doifelse{\typingparameter\c!numbering}\v!file
+ {% kind of special: filters lines !
+ \setuplinenumbering[\c!method=\v!file]%
+ \donetrue}
+ {\doifelse{\typingparameter\c!numbering}\v!line
+ {% \setuplinenumbering defaults start/step to 1/1, so we need
+ \doifinsetelse\v!continue{#1,\typingparameter\c!start}
+ {\scratchcounter0\typingparameter\c!n
+ \setxtypingparameter\c!start{\ifnum\scratchcounter=0 1\else\number\scratchcounter\fi}}%
+ {\doifnothing{\typingparameter\c!start}{\settypingparameter\c!start{1}}}%
+ \doifnothing{\typingparameter\c!step}{\settypingparameter\c!step{1}}%
+ \setuplinenumbering
+ [\c!method=\v!type,
+ \c!start=\typingparameter\c!start,
+ \c!stop=\typingparameter\c!stop,
+ \c!step=\typingparameter\c!step]%
+ \donetrue}
+ {\donefalse}}%
+ \ifdone
+ \ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+ \ifx\stoplinenumbering \undefined \let\stoplinenumbering \relax \fi
+ \def\beginofverbatimlines{\startlinenumbering}%
+ \def\endofverbatimlines {\stoplinenumbering\setxtypingparameter\c!n{\number\linenumber}}%
+ \fi}
+
+\def\reporttypingerror#1% temp hack
+ {\blank
+ \dontleavehmode\hbox\bgroup
+ \expanded{\defconvertedargument\noexpand\ascii{#1}}%
+ \tttf[\makemessage\m!verbatims1\ascii]%
+ \showmessage\m!verbatims1\ascii
+ \egroup
+ \blank}
+
+\def\dosometyping#1#2#3#4#5%
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#2}%
+ \doifinset{\typingparameter\c!option}{\v!commands,\v!slanted,\v!normal}
+ {\setuptyping[#1][\c!option=\v!none]}%
+ \doif{\typingparameter\c!option}\v!color
+ {\expandafter\aftersplitstring#3\at.\to\prettyidentifier
+ \settypingparameter\c!option{\prettyidentifier}}%
+ \initializetyping
+ \startverbatimcolor
+ \doifundefinedelse{\currenttypingclass#3\v!global\c!start}
+ {\scratchcounter\zerocount}
+ {\scratchcounter\getvalue{\currenttypingclass#3\v!global\c!start}}%
+ \advance\scratchcounter\plusone
+ \setxvalue{\currenttypingclass#3\v!global\c!start}{\the\scratchcounter}%
+ \doifelsenothing{\typingparameter\c!start}
+ {#4}
+ {\doif{\typingparameter\c!start}\v!continue
+ {\setevalue{\currenttypingclass#1\c!start}%
+ {\getvalue{\currenttypingclass#3\v!global\c!start}}}%
+ \doifelsenothing{\typingparameter\c!stop}
+ {\doifelsenothing{\typingparameter\c!nlines}
+ {#4}
+ {\setxvalue{\currenttypingclass#3\v!global\c!start}%
+ {\the\numexpr\typingparameter\c!start+\typingparameter\c!nlines+\minusone\relax}%
+ #5{\typingparameter\c!start}{\getvalue{\currenttypingclass#3\v!global\c!start}}}}%
+ {#5{\typingparameter\c!start}{\typingparameter\c!stop}}}%
+ \stopverbatimcolor
+ \stoppacked
+ \typingparameter\c!after
+ \egroup}
+
+\def\doifelsetypingfile#1% sets \readfilename (we will make this proper mkiv i.e. less messy)
+ {\doiflocfileelse{#1}
+ {\firstoftwoarguments}
+ {\doifinputfileelse{#1}
+ {\def\readfilename{\pathplusfile\filepath{#1}}\firstoftwoarguments} % messy, looks wrong too
+ {\secondoftwoarguments}}}
+
+\def\dodotypefile[#1][#2]#3%
+ {\doifelsetypingfile{#3}
+ {\dosometyping{#1}{#2}{#3}{\processfileverbatim\readfilename}{\processfilelinesverbatim\readfilename}}
+ {\reporttypingerror{#3}}}
+
+%D \macros
+%D {filename}
+%D
+%D Typesetting filenames in monospaced fonts is possible with
+%D
+%D \starttyping
+%D \filename{here/there/filename.suffix}
+%D \stoptyping
+%D
+%D The definition is not that spectacular.
+
+\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
+
+%D This leaves some settings:
+
+\permitshiftedendofverbatim
+\optimizeverbatimtrue
+
+%D And a bonus macro:
+
+\def\verbatim#1{\defconvertedargument\ascii{#1}\ascii}
+
+%D The setups for display verbatim and file verbatim are
+%D shared. One can adapt the extra defined typing environments,
+%D but they also default to the values below. Watch the
+%D alternative escape character.
+
+\setuptyping
+ [ \c!before=\blank,
+ \c!after=\blank,
+ \c!bodyfont=,
+ \c!color=,
+ \c!space=\v!off,
+ \c!page=\v!no,
+ \c!tab=\s!ascii,
+ \c!option=\v!none,
+ \c!palet=colorpretty,
+ \c!text=\v!no,
+ \c!style=\tttf,
+ \c!icommand=\ttsl,
+ \c!vcommand=,
+ \c!ccommand=\tttf,
+ \c!indentnext=\v!yes,
+ \c!margin=\!!zeropoint,
+ \c!evenmargin=\!!zeropoint,
+ \c!oddmargin=\!!zeropoint,
+ \c!blank=\v!line,
+ \c!escape=/, % beware \string\ , should also be accepted
+ \c!numbering=\v!no,
+ \c!lines=,
+ \c!empty=,
+ \c!start=1,
+ \c!stop=,
+ \c!step=1,
+ \c!continue=,
+ \c!nlines=]
+
+\definetyping[\v!typing]
+
+\presettyping[\v!file][]
+
+% \setuptyping % not needed
+% [\v!file]
+% [\c!start=1,
+% \c!stop=,
+% \c!step=1,
+% \c!continue=,
+% \c!nlines=]
+
+%D The setups for inline verbatim default to:
+
+\setuptype
+ [ \c!space=\v!off,
+ \c!color=,
+ \c!style=\tt\tf, % \tttf gives problems with {\tx \type...}
+ \c!page=\v!no,
+ \c!tab=\v!yes,
+ \c!palet=colorpretty,
+ \c!option=\v!normal]
+
+\definetyping[RAW] [\c!option=RAW]
+\definetyping[MP] [\c!option=MP]
+\definetyping[PL] [\c!option=PL]
+\definetyping[PM] [\c!option=PL]
+\definetyping[JS] [\c!option=JS]
+\definetyping[JV] [\c!option=JV]
+\definetyping[SQL] [\c!option=SQL]
+\definetyping[TEX] [\c!option=TEX]
+\definetyping[PAS] [\c!option=PAS]
+\definetyping[PASCAL][\c!option=PAS]
+\definetyping[MOD] [\c!option=PAS]
+\definetyping[MODULA][\c!option=PAS]
+\definetyping[DELPHI][\c!option=PAS]
+\definetyping[EIFFEL][\c!option=EIF]
+\definetyping[XML] [\c!option=XML]
+\definetyping[LUA] [\c!option=LUA]
+
+\installprettytype [RAW] [RAW]
+
+\installprettytype [TEX] [TEX]
+
+\installprettytype [PERL] [PL]
+\installprettytype [PL] [PL]
+\installprettytype [PM] [PL]
+
+\installprettytype [METAPOST] [MP]
+\installprettytype [METAFONT] [MP]
+\installprettytype [MP] [MP]
+\installprettytype [MF] [MP]
+
+\installprettytype [JAVASCRIPT] [JS]
+\installprettytype [JAVA] [JV]
+\installprettytype [JS] [JS]
+\installprettytype [JV] [JV]
+
+\installprettytype [SQL] [SQL]
+
+\installprettytype [PASCAL] [PAS]
+\installprettytype [PAS] [PAS]
+\installprettytype [MODULA] [PAS]
+\installprettytype [MOD] [PAS]
+
+\installprettytype [EIFFEL] [EIF]
+\installprettytype [EIF] [EIF]
+\installprettytype [E] [EIF]
+
+\installprettytype [XML] [XML]
+
+\installprettytype [LUA] [LUA]
+
+\installnewpretty M {\setupprettiesintype {MP}\setupprettytype}
+\installnewpretty P {\setupprettiesintype {PL}\setupprettytype}
+\installnewpretty T {\setupprettiesintype{TEX}\setupprettytype}
+\installnewpretty J {\setupprettiesintype {JV}\setupprettytype}
+\installnewpretty S {\setupprettiesintype{SQL}\setupprettytype}
+\installnewpretty W {\setupprettiesintype{PAS}\setupprettytype} % Wirth
+\installnewpretty I {\setupprettiesintype{EIF}\setupprettytype} % E taken
+\installnewpretty X {\setupprettiesintype{XML}\setupprettytype}
+
+%D We use the \CONTEXT\ color system for switching to and from
+%D color mode. We can always redefine these colors afterwards.
+
+\definecolor [colorprettyone] [r=.9, g=.0, b=.0] % red
+\definecolor [colorprettytwo] [r=.0, g=.8, b=.0] % green
+\definecolor [colorprettythree] [r=.0, g=.0, b=.9] % blue
+\definecolor [colorprettyfour] [r=.8, g=.8, b=.6] % yellow
+
+\definecolor [grayprettyone] [s=.30]
+\definecolor [grayprettytwo] [s=.45]
+\definecolor [grayprettythree] [s=.60]
+\definecolor [grayprettyfour] [s=.75]
+
+\definepalet
+ [colorpretty]
+ [ prettyone=colorprettyone,
+ prettytwo=colorprettytwo,
+ prettythree=colorprettythree,
+ prettyfour=colorprettyfour]
+
+\definepalet
+ [graypretty]
+ [ prettyone=grayprettyone,
+ prettytwo=grayprettytwo,
+ prettythree=grayprettythree,
+ prettyfour=grayprettyfour]
+
+\definepalet [TEXcolorpretty] [colorpretty]
+\definepalet [TEXgraypretty] [graypretty]
+\definepalet [PLcolorpretty] [colorpretty]
+\definepalet [PLgraypretty] [graypretty]
+\definepalet [PMcolorpretty] [colorpretty]
+\definepalet [PMgraypretty] [graypretty]
+\definepalet [MPcolorpretty] [colorpretty]
+\definepalet [MPgraypretty] [graypretty]
+\definepalet [JVcolorpretty] [colorpretty]
+\definepalet [JVgraypretty] [graypretty]
+\definepalet [JScolorpretty] [colorpretty]
+\definepalet [JSgraypretty] [graypretty]
+\definepalet [SQLcolorpretty] [colorpretty]
+\definepalet [SQLgraypretty] [graypretty]
+\definepalet [PAScolorpretty] [colorpretty]
+\definepalet [PASgraypretty] [graypretty]
+\definepalet [EIFcolorpretty] [colorpretty]
+\definepalet [EIFgraypretty] [graypretty]
+\definepalet [XMLcolorpretty] [colorpretty]
+\definepalet [XMLgraypretty] [graypretty]
+\definepalet [LUAcolorpretty] [colorpretty]
+\definepalet [LUAgraypretty] [graypretty]
+
+\protect \endinput
diff --git a/tex/context/base/core-ver.mkiv b/tex/context/base/core-ver.mkiv
index dcc283d6f..e9c092f66 100644
--- a/tex/context/base/core-ver.mkiv
+++ b/tex/context/base/core-ver.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=core-ver,
-%D version=2000.10.13,
+%D version=2000.05.09,
%D title=\CONTEXT\ Core Macros,
%D subtitle=Verbatim,
%D author=Hans Hagen,
@@ -11,45 +11,122 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Core Macros / Verbatim}
+
\unprotect
-\def\mksetupprettiesintype
- {\begingroup
+\ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+\ifx\stoplinenumbering \undefined \let\stoplinenumbering\relax \fi
+\ifx\setuplinenumbering\undefined \def\setuplinenumbering[#1]{} \fi
+
+% \type{ <crlf> char} geeft bagger
+
+%D We are going to embed the general verbatim support macros in
+%D a proper environment. First we show the common setup
+%D macro, so we know what features are supported. The options
+%D are hooked into the support macros via the \type{\obey}
+%D macros.
+
+\newif\ifslantedtypeactivated
+\newif\ifslantedtypepermitted
+
+\def\switchslantedtype
+ {\ifslantedtypepermitted
+ \ifslantedtypeactivated
+ \slantedtypeactivatedfalse\tttf
+ \else
+ \slantedtypeactivatedtrue\ttsl
+ \fi
+ \fi}
+
+\newprettytrue % movet to here from cont-sys.tex
+
+\def\prettyidentifier {TEX}
+\def\prettypalet {}
+
+\def\installprettytype
+ {\dodoubleargument\doinstallprettytype}
+
+\def\doinstallprettytype[#1][#2]% map #1 onto #2
+ {\uppercasestring#1\to\asciia
+ \uppercasestring#2\to\asciib
+ \setevalue{\??ty\??ty\asciia}{\asciib}}
+
+% \ctxluafileload{verb-tex}{}
+% \ctxluafileload{verb-mp} {}
+% \registerctxluafile{core-buf-tex}{}
+% \registerctxluafile{core-buf-mp} {}
+
+\def\setupprettiesintype#1%
+ {\uppercasestring#1\to\ascii
+ \edef\prettyidentifier{\executeifdefined{\??ty\??ty\ascii}{TEX}}%
+ \begingroup
\lowercasestring verb-\prettyidentifier\to\filename
\doonlyonce\filename{\ctxloadluafile\filename\empty}%
\endgroup}
-% todo: obeytabs|spaces|lines|pages
-
-% \def\mksetupprettytype % todo check
-% {\processingverbatimtrue % will move
-% \ctxlua{buffers.doifelsevisualizer("\prettyidentifier")}
-% {\ctxlua{buffers.setvisualizer("\prettyidentifier")}%
-% % \def\obs{\obeyedspace}%
-% % \def\bop{\bgroup\beginofpretty}%
-% % \def\eop{\endofpretty\egroup}%
-% % \def\sop{\endofpretty\egroup\bgroup\beginofpretty}}
-% }
-% {\def\obs{\obeyedspace}}}
-% \def\mkinitializeverbatim
-% {\ctxlua{buffers.visualizers.reset()}%
-% \localcolortrue % tricky, maybe not here
-% \def\obs{\obeyedspace}%
-% \def\obs{\obeyedspace}%
-% \def\bop{\bgroup\beginofpretty}%
-% \def\eop{\endofpretty\egroup}%
-% \def\sop{\endofpretty\egroup\bgroup\beginofpretty}%
-% \verbatimfont
-% \resetfontfeature
-% \obeycharacters}
-
-\def\mksetupprettytype % todo check
+\def\setupprettytype
{\processingverbatimtrue % will move
\ctxlua{buffers.visualizers.reset()}}
+\setvalue{\??tp:\c!lines:\v!yes }{\obeybreakpoints}
+\setvalue{\??tp:\c!lines:\v!hyphenated}{\obeyhyphens}
+
+\setvalue{\??tp:\c!empty:\v!yes }{\obeyemptylines}
+\setvalue{\??tp:\c!empty:\v!all }{\obeyallemptylines}
+
+\setvalue{\??tp:\c!option:\v!none }{\let\obeycharacters\relax}
+\setvalue{\??tp:\c!option:\v!color }{\setupprettiesintype{TEX}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!normal }{\let\obeycharacters\setupgroupedtype}
+\setvalue{\??tp:\c!option:\v!commands }{\def\obeycharacters{\setupcommandsintype}%
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\v!slanted }{\let\obeycharacters\setupslantedtype
+ \let\obeytabs\ignoretabs}
+\setvalue{\??tp:\c!option:\s!unknown }{\setupprettiesintype{\typingparameter\c!option}%
+ \let\obeycharacters\setupprettytype
+ \let\obeytabs\ignoretabs}
+
+
+\def\setupcommonverbatim
+ {\recatcodeuppercharactersfalse % obey regime / encoding
+ %
+ \let\prettyidentifier\s!default
+ %
+ \doifelse{\typingparameter\c!text}\v!yes
+ \naturaltextexttrue
+ \naturaltextextfalse
+ \def\prettyidentifierfont{\typingparameter\c!icommand}%
+ \def\prettyvariablefont {\typingparameter\c!vcommand}%
+ \def\prettynaturalfont {\typingparameter\c!ccommand}%
+ %
+ \doif{\typingparameter\c!space}\v!on
+ {\def\obeyspaces{\setcontrolspaces}}%
+ \doif{\typingparameter\c!page }\v!no
+ {\def\obeypages {\ignorepages}}%
+ %
+ \doifelse{\typingparameter\c!tab}\v!yes
+ {\def\obeytabs{\settabskips}}%
+ {\doif{\typingparameter\c!tab}\s!ascii % not needed in mkiv
+ {\chardef\tabskipmode\plustwo % quit on >127
+ \def\obeytabs{\settabskips}}}%
+ %
+ \ignorehyphens % default
+ \getvalue{\??tp:\c!lines:\typingparameter\c!lines}%
+ \getvalue{\??tp:\c!empty:\typingparameter\c!empty}%
+ \getvalue{\??tp:\c!option:\ifcsname\??tp:\c!option:\typingparameter\c!option\endcsname\typingparameter\c!option\else\s!unknown\fi}%
+ \doifnumberelse{\typingparameter\c!tab}
+ {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
+ \donothing
+ %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
+ % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
+ \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
+ \setupverbatimcolor}
+
\newtoks \everyinitializeverbatim
-\def\mkinitializeverbatim
+\def\doinitializeverbatim
{\ctxlua{buffers.visualizers.reset()}%
\def\obs{\obeyedspace}%
\ctxlua{buffers.doifelsevisualizer("\prettyidentifier")}
@@ -69,37 +146,116 @@
\resetcharacterspacing
\to \everyinitializeverbatim
-% \ctxluafileload{verb-tex}{}
-% \ctxluafileload{verb-mp} {}
-
-% \registerctxluafile{core-buf-tex}{}
-% \registerctxluafile{core-buf-mp} {}
-
-% \def\mktype#1%
-% {\bgroup
-% \begstrut % new, enables leading space in \type { abc } at par start
-% \let\currenttypingclass\??ty
-% \edef\currenttyping{#1}%
-% \initializetype % probably too much
-% \verbatimcolor
-% \setcatcodetable \typcatcodesa
-% \dodotype}
-% \def\dodotype#1%
-% {\obeycharacters % everyinitializeverbatim
-% \ctxlua{buffers.hooks.flush_line(\!!bs\detokenize{#1}\!!es)}%
-% \egroup}
+% BEWARE: the noligatures will globally change the verbatim font's behaviour
-\let\mksetupslantedtype \relax
+% test case:
+%
+% \definetype[typeTEX][option=tex]
+%
+% \typeTEX|\example---oeps|. this---ligates---again.
+% \typeTEX{\example---oeps}. this---ligates---again.
+% \type {\example---oeps}. this---ligates---again.
-\def\mksetupcommandsintype% can also be \string\
+\def\setupcommandsintype % can also be \string\
{\ctxlua{
buffers.visualizers.enableescape = true
buffers.visualizers.escapetoken = \!!bs\typingparameter\c!escape\!!es
}%
\setevalue{\typingparameter\c!escape}{\typingparameter\c!escape}}
-\def\mktype#1% was \dotype
+\def\setupslantedtype
+ {\slantedtypepermittedtrue}
+
+\ifx\setupprettytype \undefined \let\setupprettytype \relax \fi
+\ifx\setupslantedtype \undefined \let\setupslantedtype \relax \fi
+\ifx\setupgroupedtype \undefined \let\setupgroupedtype \relax \fi
+\ifx\normalnoligatures\undefined \let\normalnoligatures\gobbleoneargument \fi
+
+%D The verbatim commands have a rather long and turbulent
+%D history. Most users of \CONTEXT\ probably will never use
+%D some of the features, but I've kept in mind that when one is
+%D writing a users manual, about everything can and undoubtly
+%D will be subject to a verbatim treatment.
+%D
+%D Verbatim command are very sensitive to argument processing,
+%D which is a direct result of the \CATCODES\ being fixed at
+%D reading time. With our growing understanding of \TEX,
+%D especially of the mechanism that can be used for looking
+%D ahead and manipulating \CATCODES, the verbatim support
+%D became more and more advanced and natural.
+%D
+%D Typesetting inline verbatim can be accomplished by
+%D \type{\type}, which in this sentence was typeset by saying
+%D just \type{\type{\type}}, which in turn was typeset by
+%D \unknown. Using the normal grouping characters \type{{}} is
+%D the most natural way of using this command.
+%D
+%D A second, more or less redundant, alternative is delimiting
+%D the argument with an own character. This method was
+%D implemented in the context of a publication in the \MAPS,
+%D where this way of delimiting is recognized by \LATEX\ users.
+%D
+%D The third, more original alternative, is the one using
+%D \type{<<} and \type{>>} as delimiters. This alternative can
+%D be used in situations where slanted typeseting is needed.
+
+% todo: we can use \letter... here:
+
+\def\lesscharacter {<}
+\def\morecharacter {>}
+
+\chardef\texescape = `\\
+\chardef\leftargument = `\{
+\chardef\rightargument = `\}
+
+%D \macros
+%D {type}
+%D
+%D We define \type{\type} as a protected command. This command
+%D has several invocations: grouped, wirt boundary characters,
+%D and with font switches.
+
+% \starttyping
+% normal: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+% normal: \par \type{xx<..xx..<xx <slanted> >..>xx} \par \type{<....>} \par \type{<..<xx>..>}
+% \setuptype[option=slanted]
+% slanted: \par \type{xx<<..sl..<<xx <<sl>> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<<sl>>..>> \par
+% slanted: \par \type{xx<<..sl..<xx <sl> xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<sl>..>> \par
+% \setuptype[option=none]
+% none: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
+% \stoptyping
+
+%D When writing the manual to \CONTEXT\ and documenting this
+%D source we needed to typeset \type{<<} and \type{>>}. Because
+%D we wanted to do this in the natural way, we've adapted the
+%D original definition a bit. This implementation went through
+%D several live cycles. The final implementation looks a bit
+%D further and treats the lone \type{<<} and \type{>>} a bit
+%D different. The \type {\null} prevents ligatures, which
+%D unfortunately turn up in Lucida fonts.
+
+%D The following lines show what happens when we set
+%D \type {option=commands}.
+%D
+%D \startbuffer
+%D \starttyping
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test//test test/BTEX \footnote{test test test}/ETEX test
+%D test test test/BTEX \bf(nota bene)/ETEX test
+%D test test test /BTEX \bf(nota bene)/ETEX test
+%D \stoptyping
+%D \stopbuffer
+%D
+%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
+%D
+%D this was keyed in as:
+%D
+%D \typebuffer
+
+\unexpanded\def\type{\dotype\empty}
+
+\def\dotype#1% was \dotype
{\bgroup
\begstrut % new, enables leading space in \type { abc } at par start / begstrut else no hyphenation
\let\currenttypingclass\??ty
@@ -124,7 +280,7 @@
\dodotypeAA}
\def\dodotypeAA#1%
- {\mkinitializeverbatim
+ {\doinitializeverbatim
\def\obs{\obeyedspace}%
\ctxlua{buffers.hooks.flush_line(\!!bs\detokenize{#1}\!!es)}%
\egroup}
@@ -136,7 +292,7 @@
\dodotypeBB}
\def\dodotypeBB#1%
- {\mkinitializeverbatim
+ {\doinitializeverbatim
\ctxlua{buffers.visualizers.flush_nested(\!!bs\detokenize{#1}\!!es,false)}%
\egroup
\gobbleoneargument} % grab last >
@@ -148,7 +304,7 @@
\dodotypeCC}
\def\dodotypeCC#1%
- {\mkinitializeverbatim
+ {\doinitializeverbatim
\ifx\obeycharacters\setupprettytype % temp hack, we need a proper signal
\ctxlua{buffers.hooks.flush_line([\!!bs\detokenize{#1}\!!es,true)}%
\else
@@ -166,33 +322,827 @@
\dodotypeDD}
\def\dodotypeDD#1%
- {\mkinitializeverbatim
+ {\doinitializeverbatim
\ctxlua{buffers.hooks.flush_line(\!!bs\detokenize{#1}\!!es,true)}%
\egroup
\gobbleoneargument} % grab last >
-% \typing:
+%D The neccessary initializations are done by calling
+%D \type{\initializetype} which in return calls for the support
+%D macro \type{\setupinlineverbatim}.
+
+\def\initializetype
+ {\let\obeylines\ignorelines
+ \setupcommonverbatim
+ \setupinlineverbatim}
+
+%D \macros
+%D {setuptype}
+%D
+%D Some characteristics of \type{\type} can be set up by:
+
+\def\setuptype
+ {\dodoubleempty\dosetuptype}
+
+\def\dosetuptype[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ty#1][#2]%
+ \else
+ \getparameters[\??ty][#1]%
+ \fi}
+
+%D \macros
+%D {typ,obeyhyphens,obeybreakpoints}
+%D
+%D Although it's not clear from the macros, one character
+%D trait of this macros, which are build on top of the support
+%D module, is that they don't hyphenate. We therefore offer
+%D the alternative \type{\typ}. The current implementation
+%D works all right, but a decent hyphenation support of
+%D \type{\tt} text will be implemented soon.
+
+\def\obeyhyphens
+ {\def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.25em\relax} % hm a bit of stretch !
+
+\def\obeybreakpoints
+ {\ignorehyphens
+ \veryraggedright}
+
+\def\ignorehyphens
+ {% \language\minusone % extra bonus, the \null should do the job too
+ \def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
+ \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\relax}%
+ \spaceskip.5em\relax}
+
+\unexpanded\def\typ
+ {\bgroup
+ \let\@@tylines\v!hyphenated
+ \futurelet\next\dodotype}
+
+%D \macros
+%D {tex,arg,mat,dis}
+%D
+%D Sometimes, for instance when we pass verbatim text as an
+%D argument, the fixed \CATCODES\ interfere with our wishes. An
+%D experimental implementation of character by character
+%D processing of verbatim text did overcome this limitation,
+%D but we've decided not to use that slow and sometimes
+%D troublesome solution. Instead we stick to some 'old'
+%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
+%D
+%D The next implementation is more clear but less versatile,
+%D so we treated it for a beter one.
+%D
+%D \starttyping
+%D \def\dospecialtype#1#2%
+%D {\bgroup
+%D \initializetype
+%D \catcode`\{=\@@begingroup
+%D \catcode`\}=\@@endgroup
+%D \def\dospecialtype%
+%D {\def\dospecialtype{#2\egroup}%
+%D \bgroup
+%D \aftergroup\dospecialtype
+%D #1}%
+%D \afterassignment\dospecialtype
+%D \let\next=}
+%D
+%D \unexpanded\def\tex{\dospecialtype\texescape\relax}
+%D \unexpanded\def\arg{\dospecialtype\leftargument\rightargument}
+%D \unexpanded\def\mat{\dospecialtype\$\$}
+%D \unexpanded\def\dis{\dospecialtype{\$\$}{\$\$}}
+%D \stoptyping
+
+\def\setgroupedtype
+ {\let\currenttypingclass\??ty
+ \initializetype
+ \verbatimcolor
+ %\setcatcodetable \typcatcodesa
+ \catcode`\{=\@@begingroup
+ \catcode`\}=\@@endgroup}
+
+\unexpanded\def\tex{\groupedcommand{\setgroupedtype\texescape}{\relax}}
+\unexpanded\def\arg{\groupedcommand{\setgroupedtype\leftargument}{\rightargument}}
+\unexpanded\def\mat{\groupedcommand{\setgroupedtype\$}{\$}}
+\unexpanded\def\dis{\groupedcommand{\setgroupedtype\$\$}{\$\$}}
+
+%D \macros
+%D {starttyping}
+%D
+%D Display verbatim is realized far more easy, which is mostly
+%D due to the fact that we use \type{\stop...} as delimiter.
+%D The implementation inherits some features, for instance the
+%D support of linenumbering, which can best be studied in the
+%D documented support module.
+
+\let\currenttyping \empty
+\let\currenttypingclass\??ty % saveguard
+
+% \def\typingparameter#1%
+% {\executeifdefined
+% {\currenttypingclass\currenttyping#1}%
+% {\executeifdefined{\currenttypingclass#1}\empty}}
+
+\def\typingparameter#1%
+ {\ifcsname\currenttypingclass\currenttyping#1\endcsname
+ \csname\currenttypingclass\currenttyping#1\endcsname
+ \else\ifcsname\currenttypingclass#1\endcsname
+ \csname\currenttypingclass#1\endcsname
+ \fi\fi}
+
+\def\settypingparameter#1#2%
+ {\setvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+\def\setxtypingparameter#1#2%
+ {\setxvalue{\currenttypingclass\currenttyping#1}{#2}}
+
+% \def\initializetyping
+% {%\donefalse
+% \switchtobodyfont[\typingparameter\c!bodyfont]%
+% \donefalse
+% \scratchskip\typingparameter\c!oddmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \scratchskip\typingparameter\c!evenmargin\relax
+% \ifzeropt\scratchskip\else\donetrue\fi
+% \ifdone
+% \def\doopenupverbatimline
+% {\getpagestatus
+% \ifrightpage
+% \hskip\typingparameter\c!oddmargin\relax
+% \else
+% \hskip\typingparameter\c!evenmargin\relax
+% \fi}%
+% \else
+% \doadaptleftskip{\typingparameter\c!margin}%
+% \fi
+% \doifdefinedelse{\??bo\typingparameter\c!blank}
+% {\edef\!!stringa{\csname\??bo\typingparameter\c!blank\endcsname}}
+% {\edef\!!stringa{\typingparameter\c!blank}}%
+% \processaction
+% [\!!stringa]
+% [ \v!standard=>\scratchskip\ctxparskip,
+% \v!small=>\scratchskip\blankokleinmaat,
+% \v!medium=>\scratchskip\blankomiddelmaat,
+% \v!big=>\scratchskip\blankogrootmaat,
+% \v!halfline=>\scratchskip.5\baselineskip,
+% \v!line=>\scratchskip\baselineskip,
+% \v!none=>\scratchskip\zeropoint,
+% \s!unknown=>\scratchskip\commalistelement]%
+% \ifgridsnapping
+% \ifdim\scratchskip=.5\baselineskip\relax
+% \edef\verbatimbaselineskip{\the\scratchskip}% new
+% \else
+% \edef\verbatimbaselineskip{\the\baselineskip}%
+% \fi
+% \else
+% \edef\verbatimbaselineskip{\the\scratchskip}%
+% \fi
+% \setupcommonverbatim}
+
+\setvalue{\??tp:\c!blank:\v!standard}{\ctxparskip}
+\setvalue{\??tp:\c!blank:\v!small }{\blankokleinmaat}
+\setvalue{\??tp:\c!blank:\v!medium }{\blankomiddelmaat}
+\setvalue{\??tp:\c!blank:\v!big }{\blankogrootmaat}
+\setvalue{\??tp:\c!blank:\v!halfline}{.5\baselineskip}
+\setvalue{\??tp:\c!blank:\v!line }{\baselineskip}
+\setvalue{\??tp:\c!blank:\v!none }{\zeropoint}
+
+\def\initializetyping
+ {%\donefalse
+ \switchtobodyfont[\typingparameter\c!bodyfont]%
+ \donefalse
+ \scratchskip\typingparameter\c!oddmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \scratchskip\typingparameter\c!evenmargin\relax
+ \ifzeropt\scratchskip\else\donetrue\fi
+ \ifdone
+ \def\doopenupverbatimline
+ {\getpagestatus
+ \ifrightpage
+ \hskip\typingparameter\c!oddmargin\relax
+ \else
+ \hskip\typingparameter\c!evenmargin\relax
+ \fi}%
+ \else
+ \doadaptleftskip{\typingparameter\c!margin}%
+ \fi
+ \edef\!!stringa{\executeifdefined{\??bo\typingparameter\c!blank}{\typingparameter\c!blank}}%
+ \scratchskip\executeifdefined{\??tp:\c!blank:\!!stringa}\!!stringa\relax
+ \ifgridsnapping
+ \ifdim\scratchskip=.5\baselineskip\relax
+ \edef\verbatimbaselineskip{\the\scratchskip}% new
+ \else
+ \edef\verbatimbaselineskip{\the\baselineskip}%
+ \fi
+ \else
+ \edef\verbatimbaselineskip{\the\scratchskip}%
+ \fi
+ \setupcommonverbatim}
+
+%D The basic display verbatim commands are defined in an
+%D indirect way. As we will see, they are a specific case of a
+%D more general mechanism.
+
+% we need this hack because otherwise verbatim skips
+% the first line (everything after the initial command)
+
+\def\dostarttyping#1% tricky non standard lookahead
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \obeylines
+ \futurelet\nexttoken\dodostarttyping}
+
+\def\dodostarttyping
+ {\ifx\nexttoken[%
+ \expandafter\dododostarttyping
+ \else
+ \expandafter\nododostarttyping
+ \fi}
+
+\def\nododostarttyping
+ {\dododostarttyping[]}
-\def\mktypeblockverbatim#1#2%
+\def\dotypefileverbatim
+ {\doinitializeverbatim
+ \ctxlua{buffers.typefile("\readfilename")}}
+
+\def\dotypefilelinesverbatim#1#2%
+ {#1%
+ \doinitializeverbatim
+ \ctxlua{buffers.typefile("\readfilename")}%
+ #2}
+
+\def\dotypeblockverbatim#1#2%
{\dowithbuffer{_typing_}{#1}{#2}
{}
- {\mkinitializeverbatim
+ {\doinitializeverbatim
\beginofverbatimlines
\ctxlua{buffers.type("_typing_")}%
\endofverbatimlines
\getvalue{\strippedcsname#2}}}
-% \typefile:
+\def\dododostarttyping[#1]%
+ {\typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#1}%
+ \initializetyping
+ \startverbatimcolor
+ \expanded{\dotypeblockverbatim{\s!start\currenttyping}{\s!stop\currenttyping}}}
-\def\mktypefileverbatim
- {\mkinitializeverbatim
- \ctxlua{buffers.typefile("\readfilename")}}
+\def\dostoptyping#1% hm, currenttyping
+ {\stopverbatimcolor
+ \stoppacked % includes \egroup
+ \typingparameter\c!after
+ \egroup
+ \dochecknextindentation{\??tp#1}%
+ \dorechecknextindentation}
-\def\mktypefilelinesverbatim#1#2%
- {#1%
- \mkinitializeverbatim
- \ctxlua{buffers.typefile("\readfilename")}%
- #2}
+%D Line numbering for files is combined with filtering, while
+%D display verbatim has the ability to continue.
+%D
+%D \starttyping
+%D \typefile[numbering=file,start=10,stop=12]{test.tex}
+%D
+%D \definetyping[code][numbering=line]
+%D
+%D \starttext
+%D \startcode
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[continue]
+%D ...
+%D ...
+%D \stopcode
+%D
+%D \startcode[start=10]
+%D ...
+%D \stopcode
+%D \stoptyping
+
+%D \macros
+%D {setuptyping}
+%D
+%D The setup of typing accepts two arguments. The optional
+%D first one identifies the user defined ones. If only one
+%D argument is given, the values apply to both the standard
+%D command \type{\starttyping} and \type{\typefile}.
+
+\def\dosetuptyping[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??tp#1][#2]%
+ \else
+ \getparameters[\??tp][#1]%
+ \fi}
+
+\def\setuptyping
+ {\dodoubleempty\dosetuptyping}
+
+%D \macros
+%D {definetype}
+%D
+%D Specific inline verbatim commands can be defined with the
+%D following command.
+
+\def\definetype
+ {\dodoubleempty\dodefinetype}
+
+\def\dodefinetype[#1][#2]%
+ {\unexpanded\setvalue{#1}{\dotype{#1}}%
+ \getparameters[\??ty#1][#2]}
+
+%D \macros
+%D {definetyping}
+%D
+%D For most users the standard \type{\start}||\type{\stop}||pair
+%D will suffice, but for documentation purposes the next
+%D definition command can be of use:
+%D
+%D \starttyping
+%D \definetyping[extratyping][margin=3em]
+%D
+%D \startextratyping
+%D these extra ones are indented by 1 em
+%D \stopextratyping
+%D \stoptyping
+%D
+%D The definitions default to the standard typing values.
+
+\def\presettyping[#1][#2]%
+ {\copyparameters[\??tp#1][\??tp][\c!color,\c!style]%
+ \getparameters [\??tp#1][#2]}
+
+\def\dodefinetyping[#1][#2]%
+ {\setvalue{\e!start#1}{\dostarttyping{#1}}%
+ \setvalue{\e!stop #1}{\dostoptyping {#1}}%
+ \presettyping[#1][#2]}
+
+\def\definetyping
+ {\dodoubleempty\dodefinetyping}
+
+%D We can use some core color commands. These are faster than
+%D the standard color switching ones and work ok on a line by
+%D line basis.
+%D
+%D \starttyping
+%D \def\setupverbatimcolor%
+%D {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}%
+%D \def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+%D \def\endofpretty {\stopcolormode}}
+%D \stoptyping
+%D
+%D Since we support a global color too, the folowing
+%D definition is better:
+
+% \def\setupverbatimcolor% fast and local versus slow and global
+% {\doifelsenothing{\typingparameter\c!color}
+% {\def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
+% \let\endofpretty \restorecolormode % \stopcolormode
+% \let\startverbatimcolor \relax
+% \let\stopverbatimcolor \relax
+% \let\verbatimcolor \relax}
+% {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+% \let\endofpretty \stopcolor
+% \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+% \let\stopverbatimcolor \stopcolor
+% \def\verbatimcolor {\getvalue{\typingparameter\c!color}}}% command !
+% \doifelsenothing{\typingparameter\c!palet}
+% {\let\prettypalet\empty
+% \let\endofpretty\relax
+% \def\beginofpretty[##1]{}}
+% {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+%
+% let's forget about this optimization not that we have mkiv
+
+\def\setupverbatimcolor
+ {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
+ \let\endofpretty \stopcolor
+ \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
+ \let\stopverbatimcolor \stopcolor
+ \def\verbatimcolor {\getvalue{\typingparameter\c!color}}% command !
+ \doifelsenothing{\typingparameter\c!palet}
+ {\let\prettypalet\empty
+ \let\endofpretty\relax
+ \def\beginofpretty[##1]{}}
+ {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
+
+\let\prettypalet \empty
+\let\startverbatimcolor\relax
+\let\stopverbatimcolor \relax
+\let\verbatimcolor \relax
+
+%D In the verbatim module, there are some examples given of
+%D the more obscure features of the verbatim environments.
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This gives, as can be expected:
+%D
+%D \getbuffer
+%D
+%D When we want to see some typeset \TEX\ too, we can say:
+%D
+%D \startbuffer
+%D \startTEX
+%D \def\mathematics#1% %%\ N usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} %%\ N becomes: \mathematics{x^2}
+%D \stopTEX
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D or:
+%D
+%D \getbuffer
+%D
+%D In a similar way:
+%D
+%D \startbuffer
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives:
+%D
+%D \getbuffer
+%D
+%D The next examples sow how we can directly call for natural
+%D \TEX\ comments:
+%D
+%D \startbuffer
+%D \setuptyping
+%D [TEX]
+%D [text=yes]
+%D
+%D \startTEX
+%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
+%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
+%D \stopTEX
+%D
+%D \setuptyping
+%D [SQL]
+%D [text=yes,palet=,icommand=\bf,vcommand=,ccommand=\it]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D
+%D \setuptyping
+%D [SQL]
+%D [ccommand=\tf\underbar]
+%D
+%D \startSQL
+%D select * -- indeed, here we {\em do} select
+%D from tableA
+%D where 1 = 2
+%D \stopSQL
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Now watch:
+%D
+%D \getbuffer
+%D
+%D The natural \TEX\ typesetting was introduced when Tobias
+%D and Berend started using verbatim \JAVASCRIPT\ and \SQL.
+
+%D \macros
+%D {EveryPar, EveryLine, iflinepar}
+%D
+%D One of the features of these commands is the support of
+%D \type{\EveryPar}, \type{\EveryLine} and \type{\iflinepar}.
+%D In the documentation of the verbatim support module we give
+%D some examples of line- and paragraph numbering using these
+%D macros.
+
+%D \macros
+%D {typefile}
+%D
+%D Typesetting files verbatim (for the moment) only supports
+%D colorization of \TEX\ sources as valid option. The other
+%D setup values are inherited from display verbatim.
+%D The implementation of \type{\typefile} is straightforward:
+
+% new feature (not yet 100\% ok)
+%
+% \setuptyping[file][numbering=file]
+%
+% \typefile[start=2,nlines=3]{zapf}
+% \typefile[start=continue,nlines=13]{zapf}
+% \typefile{zapf}
+%
+% \setuptyping[file][numbering=line]
+%
+% \typefile[start=4,step=3]{zapf}
+% \typefile{zapf}
+
+\def\typefile
+ {\dodoubleempty\dotypefile}
+
+\def\dotypefile[#1][#2]#3%
+ {\ifsecondargument
+ \dodotypefile[#1][#2]{#3}%
+ \else\iffirstargument
+ \doifassignmentelse{#1}
+ {\dodotypefile[\v!file][#1]{#3}}
+ {\dodotypefile[#1][]{#3}}%
+ \else
+ \dodotypefile[\v!file][]{#3}%
+ \fi\fi}
+
+\def\dosetuptypelinenumbering#1% fuzzy
+ {\doifundefined{\currenttypingclass\currenttyping\c!start}
+ {\setuptyping[\currenttyping][\c!start=1,\c!stop=,\c!step=1,\c!nlines=]}%
+ \setuptyping[\currenttyping][#1]%
+ \doifelse{\typingparameter\c!numbering}\v!file
+ {% kind of special: filters lines !
+ \setuplinenumbering[\c!method=\v!file]%
+ \donetrue}
+ {\doifelse{\typingparameter\c!numbering}\v!line
+ {% \setuplinenumbering defaults start/step to 1/1, so we need
+ \doifinsetelse\v!continue{#1,\typingparameter\c!start}
+ {\scratchcounter0\typingparameter\c!n
+ \setxtypingparameter\c!start{\ifnum\scratchcounter=0 1\else\number\scratchcounter\fi}}%
+ {\doifnothing{\typingparameter\c!start}{\settypingparameter\c!start{1}}}%
+ \doifnothing{\typingparameter\c!step}{\settypingparameter\c!step{1}}%
+ \setuplinenumbering
+ [\c!method=\v!type,
+ \c!start=\typingparameter\c!start,
+ \c!stop=\typingparameter\c!stop,
+ \c!step=\typingparameter\c!step]%
+ \donetrue}
+ {\donefalse}}%
+ \ifdone
+ \ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
+ \ifx\stoplinenumbering \undefined \let\stoplinenumbering \relax \fi
+ \def\beginofverbatimlines{\startlinenumbering}%
+ \def\endofverbatimlines {\stoplinenumbering\setxtypingparameter\c!n{\number\linenumber}}%
+ \fi}
+
+\def\reporttypingerror#1% temp hack
+ {\blank
+ \dontleavehmode\hbox\bgroup
+ \expanded{\defconvertedargument\noexpand\ascii{#1}}%
+ \tttf[\makemessage\m!verbatims1\ascii]%
+ \showmessage\m!verbatims1\ascii
+ \egroup
+ \blank}
+
+\def\dosometyping#1#2#3#4#5%
+ {\bgroup
+ \let\currenttypingclass\??tp
+ \edef\currenttyping{#1}%
+ \typingparameter\c!before
+ \startpacked % includes \bgroup
+ \dosetuptypelinenumbering{#2}%
+ \doifinset{\typingparameter\c!option}{\v!commands,\v!slanted,\v!normal}
+ {\setuptyping[#1][\c!option=\v!none]}%
+ \doif{\typingparameter\c!option}\v!color
+ {\expandafter\aftersplitstring#3\at.\to\prettyidentifier
+ \settypingparameter\c!option{\prettyidentifier}}%
+ \initializetyping
+ \startverbatimcolor
+ \doifundefinedelse{\currenttypingclass#3\v!global\c!start}
+ {\scratchcounter\zerocount}
+ {\scratchcounter\getvalue{\currenttypingclass#3\v!global\c!start}}%
+ \advance\scratchcounter\plusone
+ \setxvalue{\currenttypingclass#3\v!global\c!start}{\the\scratchcounter}%
+ \doifelsenothing{\typingparameter\c!start}
+ {#4}
+ {\doif{\typingparameter\c!start}\v!continue
+ {\setevalue{\currenttypingclass#1\c!start}%
+ {\getvalue{\currenttypingclass#3\v!global\c!start}}}%
+ \doifelsenothing{\typingparameter\c!stop}
+ {\doifelsenothing{\typingparameter\c!nlines}
+ {#4}
+ {\setxvalue{\currenttypingclass#3\v!global\c!start}%
+ {\the\numexpr\typingparameter\c!start+\typingparameter\c!nlines+\minusone\relax}%
+ #5{\typingparameter\c!start}{\getvalue{\currenttypingclass#3\v!global\c!start}}}}%
+ {#5{\typingparameter\c!start}{\typingparameter\c!stop}}}%
+ \stopverbatimcolor
+ \stoppacked
+ \typingparameter\c!after
+ \egroup}
+
+\def\doifelsetypingfile#1% sets \readfilename (we will make this proper mkiv i.e. less messy)
+ {\doiflocfileelse{#1}
+ {\firstoftwoarguments}
+ {\doifinputfileelse{#1}
+ {\def\readfilename{\pathplusfile\filepath{#1}}\firstoftwoarguments} % messy, looks wrong too
+ {\secondoftwoarguments}}}
+
+\def\dodotypefile[#1][#2]#3%
+ {\doifelsetypingfile{#3}
+ {\dosometyping{#1}{#2}{#3}\dotypefileverbatim\dotypefilelinesverbatim}
+ {\reporttypingerror{#3}}}
+
+%D \macros
+%D {filename}
+%D
+%D Typesetting filenames in monospaced fonts is possible with
+%D
+%D \starttyping
+%D \filename{here/there/filename.suffix}
+%D \stoptyping
+%D
+%D The definition is not that spectacular.
+
+\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
+
+%D This leaves some settings:
+
+\permitshiftedendofverbatim
+\optimizeverbatimtrue
+
+%D And a bonus macro:
+
+\def\verbatim#1{\defconvertedargument\ascii{#1}\ascii}
+
+%D The setups for display verbatim and file verbatim are
+%D shared. One can adapt the extra defined typing environments,
+%D but they also default to the values below. Watch the
+%D alternative escape character.
+
+\setuptyping
+ [ \c!before=\blank,
+ \c!after=\blank,
+ \c!bodyfont=,
+ \c!color=,
+ \c!space=\v!off,
+ \c!page=\v!no,
+ \c!tab=\s!ascii,
+ \c!option=\v!none,
+ \c!palet=colorpretty,
+ \c!text=\v!no,
+ \c!style=\tttf,
+ \c!icommand=\ttsl,
+ \c!vcommand=,
+ \c!ccommand=\tttf,
+ \c!indentnext=\v!yes,
+ \c!margin=\!!zeropoint,
+ \c!evenmargin=\!!zeropoint,
+ \c!oddmargin=\!!zeropoint,
+ \c!blank=\v!line,
+ \c!escape=/, % beware \string\ , should also be accepted
+ \c!numbering=\v!no,
+ \c!lines=,
+ \c!empty=,
+ \c!start=1,
+ \c!stop=,
+ \c!step=1,
+ \c!continue=,
+ \c!nlines=]
+
+\definetyping[\v!typing]
+
+\presettyping[\v!file][]
+
+% \setuptyping % not needed
+% [\v!file]
+% [\c!start=1,
+% \c!stop=,
+% \c!step=1,
+% \c!continue=,
+% \c!nlines=]
+
+%D The setups for inline verbatim default to:
+
+\setuptype
+ [ \c!space=\v!off,
+ \c!color=,
+ \c!style=\tt\tf, % \tttf gives problems with {\tx \type...}
+ \c!page=\v!no,
+ \c!tab=\v!yes,
+ \c!palet=colorpretty,
+ \c!option=\v!normal]
+
+\definetyping[RAW] [\c!option=RAW]
+\definetyping[MP] [\c!option=MP]
+\definetyping[PL] [\c!option=PL]
+\definetyping[PM] [\c!option=PL]
+\definetyping[JS] [\c!option=JS]
+\definetyping[JV] [\c!option=JV]
+\definetyping[SQL] [\c!option=SQL]
+\definetyping[TEX] [\c!option=TEX]
+\definetyping[PAS] [\c!option=PAS]
+\definetyping[PASCAL][\c!option=PAS]
+\definetyping[MOD] [\c!option=PAS]
+\definetyping[MODULA][\c!option=PAS]
+\definetyping[DELPHI][\c!option=PAS]
+\definetyping[EIFFEL][\c!option=EIF]
+\definetyping[XML] [\c!option=XML]
+\definetyping[LUA] [\c!option=LUA]
+
+\installprettytype [RAW] [RAW]
+
+\installprettytype [TEX] [TEX]
+
+\installprettytype [PERL] [PL]
+\installprettytype [PL] [PL]
+\installprettytype [PM] [PL]
+
+\installprettytype [METAPOST] [MP]
+\installprettytype [METAFONT] [MP]
+\installprettytype [MP] [MP]
+\installprettytype [MF] [MP]
+
+\installprettytype [JAVASCRIPT] [JS]
+\installprettytype [JAVA] [JV]
+\installprettytype [JS] [JS]
+\installprettytype [JV] [JV]
+
+\installprettytype [SQL] [SQL]
+
+\installprettytype [PASCAL] [PAS]
+\installprettytype [PAS] [PAS]
+\installprettytype [MODULA] [PAS]
+\installprettytype [MOD] [PAS]
+
+\installprettytype [EIFFEL] [EIF]
+\installprettytype [EIF] [EIF]
+\installprettytype [E] [EIF]
+
+\installprettytype [XML] [XML]
+
+\installprettytype [LUA] [LUA]
+
+\installnewpretty M {\setupprettiesintype {MP}\setupprettytype}
+\installnewpretty P {\setupprettiesintype {PL}\setupprettytype}
+\installnewpretty T {\setupprettiesintype{TEX}\setupprettytype}
+\installnewpretty J {\setupprettiesintype {JV}\setupprettytype}
+\installnewpretty S {\setupprettiesintype{SQL}\setupprettytype}
+\installnewpretty W {\setupprettiesintype{PAS}\setupprettytype} % Wirth
+\installnewpretty I {\setupprettiesintype{EIF}\setupprettytype} % E taken
+\installnewpretty X {\setupprettiesintype{XML}\setupprettytype}
+
+%D We use the \CONTEXT\ color system for switching to and from
+%D color mode. We can always redefine these colors afterwards.
+
+\definecolor [colorprettyone] [r=.9, g=.0, b=.0] % red
+\definecolor [colorprettytwo] [r=.0, g=.8, b=.0] % green
+\definecolor [colorprettythree] [r=.0, g=.0, b=.9] % blue
+\definecolor [colorprettyfour] [r=.8, g=.8, b=.6] % yellow
+
+\definecolor [grayprettyone] [s=.30]
+\definecolor [grayprettytwo] [s=.45]
+\definecolor [grayprettythree] [s=.60]
+\definecolor [grayprettyfour] [s=.75]
+
+\definepalet
+ [colorpretty]
+ [ prettyone=colorprettyone,
+ prettytwo=colorprettytwo,
+ prettythree=colorprettythree,
+ prettyfour=colorprettyfour]
+
+\definepalet
+ [graypretty]
+ [ prettyone=grayprettyone,
+ prettytwo=grayprettytwo,
+ prettythree=grayprettythree,
+ prettyfour=grayprettyfour]
+
+\definepalet [TEXcolorpretty] [colorpretty]
+\definepalet [TEXgraypretty] [graypretty]
+\definepalet [PLcolorpretty] [colorpretty]
+\definepalet [PLgraypretty] [graypretty]
+\definepalet [PMcolorpretty] [colorpretty]
+\definepalet [PMgraypretty] [graypretty]
+\definepalet [MPcolorpretty] [colorpretty]
+\definepalet [MPgraypretty] [graypretty]
+\definepalet [JVcolorpretty] [colorpretty]
+\definepalet [JVgraypretty] [graypretty]
+\definepalet [JScolorpretty] [colorpretty]
+\definepalet [JSgraypretty] [graypretty]
+\definepalet [SQLcolorpretty] [colorpretty]
+\definepalet [SQLgraypretty] [graypretty]
+\definepalet [PAScolorpretty] [colorpretty]
+\definepalet [PASgraypretty] [graypretty]
+\definepalet [EIFcolorpretty] [colorpretty]
+\definepalet [EIFgraypretty] [graypretty]
+\definepalet [XMLcolorpretty] [colorpretty]
+\definepalet [XMLgraypretty] [graypretty]
+\definepalet [LUAcolorpretty] [colorpretty]
+\definepalet [LUAgraypretty] [graypretty]
% patched from verb-ini (todo)
diff --git a/tex/context/base/core-ver.tex b/tex/context/base/core-ver.tex
deleted file mode 100644
index 57dba0af1..000000000
--- a/tex/context/base/core-ver.tex
+++ /dev/null
@@ -1,1120 +0,0 @@
-%D \module
-%D [ file=core-ver,
-%D version=2000.05.09,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Verbatim,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Verbatim}
-
-\startmessages dutch library: verbatims
- title: typen
- 1: file -- bestaat niet
-\stopmessages
-
-\startmessages english library: verbatims
- title: verbatim
- 1: file -- does not exist
-\stopmessages
-
-\startmessages german library: verbatims
- title: verbatim
- 1: Datei -- existiert nicht
-\stopmessages
-
-\startmessages czech library: verbatims
- title: verbatim
- 1: soubor -- neexistuje
-\stopmessages
-
-\startmessages italian library: verbatims
- title: verbatim
- 1: il file -- non esiste
-\stopmessages
-
-\startmessages norwegian library: verbatims
- title: verbatim
- 1: fil -- eksisterer ikke
-\stopmessages
-
-\startmessages romanian library: verbatims
- title: verbatim
- 1: fisierul -- nu exista
-\stopmessages
-
-\startmessages french library: verbatims
- title: verbatim
- 1: le fichier -- n'existe pas
-\stopmessages
-
-\unprotect
-
-\ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
-\ifx\stoplinenumbering \undefined \let\stoplinenumbering\relax \fi
-\ifx\setuplinenumbering\undefined \def\setuplinenumbering[#1]{} \fi
-
-% \type{ <crlf> char} geeft bagger
-
-%D We are going to embed the general verbatim support macros in
-%D a proper environment. First we show the common setup
-%D macro, so we know what features are supported. The options
-%D are hooked into the support macros via the \type{\obey}
-%D macros.
-
-\newif\ifslantedtypeactivated
-\newif\ifslantedtypepermitted
-
-\def\switchslantedtype
- {\ifslantedtypepermitted
- \ifslantedtypeactivated
- \slantedtypeactivatedfalse\tttf
- \else
- \slantedtypeactivatedtrue\ttsl
- \fi
- \fi}
-
-\newprettytrue % movet to here from cont-sys.tex
-
-\def\prettyidentifier {TEX}
-\def\prettypalet {}
-
-\def\installprettytype
- {\dodoubleargument\doinstallprettytype}
-
-\def\doinstallprettytype[#1][#2]% map #1 onto #2
- {\uppercasestring#1\to\asciia
- \uppercasestring#2\to\asciib
- \setevalue{\??ty\??ty\asciia}{\asciib}}
-
-\def\setupprettiesintype#1%
- {\uppercasestring#1\to\ascii
- \edef\prettyidentifier{\executeifdefined{\??ty\??ty\ascii}{TEX}}%
- \mksetupprettiesintype}
-
-\def\setupprettytype{\mksetupprettytype}
-
-% \def\setupcommonverbatim
-% {\recatcodeuppercharactersfalse % obey regime / encoding
-% %
-% \let\prettyidentifier\s!default
-% %
-% \doifelse{\typingparameter\c!text}\v!yes
-% \naturaltextexttrue
-% \naturaltextextfalse
-% \def\prettyidentifierfont{\typingparameter\c!icommand}%
-% \def\prettyvariablefont {\typingparameter\c!vcommand}%
-% \def\prettynaturalfont {\typingparameter\c!ccommand}%
-% %
-% \doif{\typingparameter\c!space}\v!on
-% {\def\obeyspaces{\setcontrolspaces}}%
-% \doif{\typingparameter\c!page }\v!no
-% {\def\obeypages {\ignorepages}}%
-% %
-% \doifelse{\typingparameter\c!tab}\v!yes
-% {\def\obeytabs{\settabskips}}%
-% {\doif{\typingparameter\c!tab}\s!ascii
-% {\chardef\tabskipmode\plustwo % quit on >127
-% \def\obeytabs{\settabskips}}}%
-% %
-% \ignorehyphens % default
-% \ExpandFirstAfter\processaction
-% [\typingparameter\c!lines]
-% [ \v!yes=>\obeybreakpoints,
-% \v!hyphenated=>\obeyhyphens]%
-% \processaction
-% [\typingparameter\c!empty]
-% [\v!yes=>\obeyemptylines,
-% \v!all=>\obeyallemptylines]%
-% %
-% \ExpandFirstAfter\processaction
-% [\typingparameter\c!option]
-% [ \v!none=>\let\obeycharacters\relax,
-% \v!color=>\setupprettiesintype{TEX}%
-% \let\obeycharacters\setupprettytype
-% \let\obeytabs\ignoretabs,
-% \v!normal=>\let\obeycharacters\setupgroupedtype,
-% \v!commands=>\def\obeycharacters{\setupcommandsintype}% \let
-% \let\obeytabs\ignoretabs,
-% \v!slanted=>\let\obeycharacters\setupslantedtype
-% \let\obeytabs\ignoretabs,
-% \s!unknown=>\setupprettiesintype{\typingparameter\c!option}%
-% \let\obeycharacters\setupprettytype
-% \let\obeytabs\ignoretabs]%
-% \doifnumberelse{\typingparameter\c!tab}
-% {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
-% \donothing
-% %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
-% % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
-% \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
-% \setupverbatimcolor}
-
-\setvalue{\??tp:\c!lines:\v!yes }{\obeybreakpoints}
-\setvalue{\??tp:\c!lines:\v!hyphenated}{\obeyhyphens}
-
-\setvalue{\??tp:\c!empty:\v!yes }{\obeyemptylines}
-\setvalue{\??tp:\c!empty:\v!all }{\obeyallemptylines}
-
-\setvalue{\??tp:\c!option:\v!none }{\let\obeycharacters\relax}
-\setvalue{\??tp:\c!option:\v!color }{\setupprettiesintype{TEX}%
- \let\obeycharacters\setupprettytype
- \let\obeytabs\ignoretabs}
-\setvalue{\??tp:\c!option:\v!normal }{\let\obeycharacters\setupgroupedtype}
-\setvalue{\??tp:\c!option:\v!commands }{\def\obeycharacters{\setupcommandsintype}%
- \let\obeytabs\ignoretabs}
-\setvalue{\??tp:\c!option:\v!slanted }{\let\obeycharacters\setupslantedtype
- \let\obeytabs\ignoretabs}
-\setvalue{\??tp:\c!option:\s!unknown }{\setupprettiesintype{\typingparameter\c!option}%
- \let\obeycharacters\setupprettytype
- \let\obeytabs\ignoretabs}
-
-
-\def\setupcommonverbatim
- {\recatcodeuppercharactersfalse % obey regime / encoding
- %
- \let\prettyidentifier\s!default
- %
- \doifelse{\typingparameter\c!text}\v!yes
- \naturaltextexttrue
- \naturaltextextfalse
- \def\prettyidentifierfont{\typingparameter\c!icommand}%
- \def\prettyvariablefont {\typingparameter\c!vcommand}%
- \def\prettynaturalfont {\typingparameter\c!ccommand}%
- %
- \doif{\typingparameter\c!space}\v!on
- {\def\obeyspaces{\setcontrolspaces}}%
- \doif{\typingparameter\c!page }\v!no
- {\def\obeypages {\ignorepages}}%
- %
- \doifelse{\typingparameter\c!tab}\v!yes
- {\def\obeytabs{\settabskips}}%
- {\doif{\typingparameter\c!tab}\s!ascii % not needed in mkiv
- {\chardef\tabskipmode\plustwo % quit on >127
- \def\obeytabs{\settabskips}}}%
- %
- \ignorehyphens % default
- \getvalue{\??tp:\c!lines:\typingparameter\c!lines}%
- \getvalue{\??tp:\c!empty:\typingparameter\c!empty}%
- \getvalue{\??tp:\c!option:\ifcsname\??tp:\c!option:\typingparameter\c!option\endcsname\typingparameter\c!option\else\s!unknown\fi}%
- \doifnumberelse{\typingparameter\c!tab}
- {\def\obeytabs{\setfixedtabskips{\typingparameter\c!tab}}}%
- \donothing
- %\def\verbatimfont{\typingparameter\c!style\normalnoligatures\font}%
- % more generic, but beware of the \redoconvertfont (else no typing in titles and such)
- \def\verbatimfont{\redoconvertfont\dosetfontattribute{\currenttypingclass\currenttyping}\c!style\normalnoligatures\font}%
- \setupverbatimcolor}
-
-% BEWARE: the noligatures will globally change the verbatim font's behaviour
-
-% test case:
-%
-% \definetype[typeTEX][option=tex]
-%
-% \typeTEX|\example---oeps|. this---ligates---again.
-% \typeTEX{\example---oeps}. this---ligates---again.
-% \type {\example---oeps}. this---ligates---again.
-
-\def\setupcommandsintype{\mksetupcommandsintype}
-\def\setupslantedtype {\slantedtypepermittedtrue\mksetupslantedtype}
-
-\ifx\setupprettytype \undefined \let\setupprettytype \relax \fi
-\ifx\setupslantedtype \undefined \let\setupslantedtype \relax \fi
-\ifx\setupgroupedtype \undefined \let\setupgroupedtype \relax \fi
-\ifx\normalnoligatures\undefined \let\normalnoligatures\gobbleoneargument \fi
-
-%D The verbatim commands have a rather long and turbulent
-%D history. Most users of \CONTEXT\ probably will never use
-%D some of the features, but I've kept in mind that when one is
-%D writing a users manual, about everything can and undoubtly
-%D will be subject to a verbatim treatment.
-%D
-%D Verbatim command are very sensitive to argument processing,
-%D which is a direct result of the \CATCODES\ being fixed at
-%D reading time. With our growing understanding of \TEX,
-%D especially of the mechanism that can be used for looking
-%D ahead and manipulating \CATCODES, the verbatim support
-%D became more and more advanced and natural.
-%D
-%D Typesetting inline verbatim can be accomplished by
-%D \type{\type}, which in this sentence was typeset by saying
-%D just \type{\type{\type}}, which in turn was typeset by
-%D \unknown. Using the normal grouping characters \type{{}} is
-%D the most natural way of using this command.
-%D
-%D A second, more or less redundant, alternative is delimiting
-%D the argument with an own character. This method was
-%D implemented in the context of a publication in the \MAPS,
-%D where this way of delimiting is recognized by \LATEX\ users.
-%D
-%D The third, more original alternative, is the one using
-%D \type{<<} and \type{>>} as delimiters. This alternative can
-%D be used in situations where slanted typeseting is needed.
-
-% todo: we can use \letter... here:
-
-\def\lesscharacter {<}
-\def\morecharacter {>}
-
-\chardef\texescape = `\\
-\chardef\leftargument = `\{
-\chardef\rightargument = `\}
-
-%D \macros
-%D {type}
-%D
-%D We define \type{\type} as a protected command. This command
-%D has several invocations: grouped, wirt boundary characters,
-%D and with font switches.
-
-% \starttyping
-% normal: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
-% normal: \par \type{xx<..xx..<xx <slanted> >..>xx} \par \type{<....>} \par \type{<..<xx>..>}
-% \setuptype[option=slanted]
-% slanted: \par \type{xx<<..sl..<<xx <<sl>> xx>>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<<sl>>..>> \par
-% slanted: \par \type{xx<<..sl..<xx <sl> xx>..sl..>>xx} \par \type<<..xx..>> \par \type<<..<sl>..>> \par
-% \setuptype[option=none]
-% none: \par \type{xx<<..xx..<<xx <<xx>> >>..>>xx} \par \type<<....>> \par \type<<..<<xx>>..>> \par
-% \stoptyping
-
-%D When writing the manual to \CONTEXT\ and documenting this
-%D source we needed to typeset \type{<<} and \type{>>}. Because
-%D we wanted to do this in the natural way, we've adapted the
-%D original definition a bit. This implementation went through
-%D several live cycles. The final implementation looks a bit
-%D further and treats the lone \type{<<} and \type{>>} a bit
-%D different. The \type {\null} prevents ligatures, which
-%D unfortunately turn up in Lucida fonts.
-
-%D The following lines show what happens when we set
-%D \type {option=commands}.
-%D
-%D \startbuffer
-%D \starttyping
-%D test//test test/BTEX \footnote{test test test}/ETEX test
-%D test//test test/BTEX \footnote{test test test}/ETEX test
-%D test test test/BTEX \bf(nota bene)/ETEX test
-%D test test test /BTEX \bf(nota bene)/ETEX test
-%D \stoptyping
-%D \stopbuffer
-%D
-%D % \bgroup\setuptyping[option=commands]\getbuffer\egroup
-%D
-%D this was keyed in as:
-%D
-%D \typebuffer
-
-\unexpanded\def\type{\mktype\empty}
-
-\let\mktype\gobbleoneargument
-
-%D The neccessary initializations are done by calling
-%D \type{\initializetype} which in return calls for the support
-%D macro \type{\setupinlineverbatim}.
-
-\def\initializetype
- {\let\obeylines\ignorelines
- \setupcommonverbatim
- \setupinlineverbatim}
-
-%D \macros
-%D {setuptype}
-%D
-%D Some characteristics of \type{\type} can be set up by:
-
-\def\setuptype
- {\dodoubleempty\dosetuptype}
-
-\def\dosetuptype[#1][#2]%
- {\ifsecondargument
- \getparameters[\??ty#1][#2]%
- \else
- \getparameters[\??ty][#1]%
- \fi}
-
-%D \macros
-%D {typ,obeyhyphens,obeybreakpoints}
-%D
-%D Although it's not clear from the macros, one character
-%D trait of this macros, which are build on top of the support
-%D module, is that they don't hyphenate. We therefore offer
-%D the alternative \type{\typ}. The current implementation
-%D works all right, but a decent hyphenation support of
-%D \type{\tt} text will be implemented soon.
-
-\def\obeyhyphens
- {\def\obeyedspace {\hskip\interwordspace\relax}% better than spaceskip
- \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint}%
- \spaceskip.25em\relax} % hm a bit of stretch !
-
-\def\obeybreakpoints
- {\ignorehyphens
- \veryraggedright}
-
-% \def\ignorehyphens
-% {\def\obeyedspace {\null\hskip\interwordspace\null}% better than spaceskip
-% \def\controlspace{\null\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint\null}%
-% \spaceskip.5em\relax}
-
-\def\ignorehyphens
- {% \language\minusone % extra bonus, the \null should do the job too
- \def\obeyedspace {\hskip\interwordspace}% better than spaceskip
- \def\controlspace{\hskip\zeropoint\hbox{\normalcontrolspace}\hskip\zeropoint}%
- \spaceskip.5em\relax}
-
-\unexpanded\def\typ
- {\bgroup
- \let\@@tylines\v!hyphenated
- \futurelet\next\dodotype}
-
-%D \macros
-%D {tex,arg,mat,dis}
-%D
-%D Sometimes, for instance when we pass verbatim text as an
-%D argument, the fixed \CATCODES\ interfere with our wishes. An
-%D experimental implementation of character by character
-%D processing of verbatim text did overcome this limitation,
-%D but we've decided not to use that slow and sometimes
-%D troublesome solution. Instead we stick to some 'old'
-%D \CONTEXT\ macros for typesetting typical \TEX\ characters.
-%D
-%D The next implementation is more clear but less versatile,
-%D so we treated it for a beter one.
-%D
-%D \starttyping
-%D \def\dospecialtype#1#2%
-%D {\bgroup
-%D \initializetype
-%D \catcode`\{=\@@begingroup
-%D \catcode`\}=\@@endgroup
-%D \def\dospecialtype%
-%D {\def\dospecialtype{#2\egroup}%
-%D \bgroup
-%D \aftergroup\dospecialtype
-%D #1}%
-%D \afterassignment\dospecialtype
-%D \let\next=}
-%D
-%D \unexpanded\def\tex{\dospecialtype\texescape\relax}
-%D \unexpanded\def\arg{\dospecialtype\leftargument\rightargument}
-%D \unexpanded\def\mat{\dospecialtype\$\$}
-%D \unexpanded\def\dis{\dospecialtype{\$\$}{\$\$}}
-%D \stoptyping
-
-\def\setgroupedtype
- {\let\currenttypingclass\??ty
- \initializetype
- \catcode`\{=\@@begingroup
- \catcode`\}=\@@endgroup}
-
-\unexpanded\def\tex{\groupedcommand{\setgroupedtype\texescape}{\relax}}
-\unexpanded\def\arg{\groupedcommand{\setgroupedtype\leftargument}{\rightargument}}
-\unexpanded\def\mat{\groupedcommand{\setgroupedtype\$}{\$}}
-\unexpanded\def\dis{\groupedcommand{\setgroupedtype\$\$}{\$\$}}
-
-%D \macros
-%D {starttyping}
-%D
-%D Display verbatim is realized far more easy, which is mostly
-%D due to the fact that we use \type{\stop...} as delimiter.
-%D The implementation inherits some features, for instance the
-%D support of linenumbering, which can best be studied in the
-%D documented support module.
-
-\let\currenttyping \empty
-\let\currenttypingclass\??ty % saveguard
-
-% \def\typingparameter#1%
-% {\executeifdefined
-% {\currenttypingclass\currenttyping#1}%
-% {\executeifdefined{\currenttypingclass#1}\empty}}
-
-\def\typingparameter#1%
- {\ifcsname\currenttypingclass\currenttyping#1\endcsname
- \csname\currenttypingclass\currenttyping#1\endcsname
- \else\ifcsname\currenttypingclass#1\endcsname
- \csname\currenttypingclass#1\endcsname
- \fi\fi}
-
-\def\settypingparameter#1#2%
- {\setvalue{\currenttypingclass\currenttyping#1}{#2}}
-
-\def\setxtypingparameter#1#2%
- {\setxvalue{\currenttypingclass\currenttyping#1}{#2}}
-
-% \def\initializetyping
-% {%\donefalse
-% \switchtobodyfont[\typingparameter\c!bodyfont]%
-% \donefalse
-% \scratchskip\typingparameter\c!oddmargin\relax
-% \ifzeropt\scratchskip\else\donetrue\fi
-% \scratchskip\typingparameter\c!evenmargin\relax
-% \ifzeropt\scratchskip\else\donetrue\fi
-% \ifdone
-% \def\doopenupverbatimline
-% {\getpagestatus
-% \ifrightpage
-% \hskip\typingparameter\c!oddmargin\relax
-% \else
-% \hskip\typingparameter\c!evenmargin\relax
-% \fi}%
-% \else
-% \doadaptleftskip{\typingparameter\c!margin}%
-% \fi
-% \doifdefinedelse{\??bo\typingparameter\c!blank}
-% {\edef\!!stringa{\csname\??bo\typingparameter\c!blank\endcsname}}
-% {\edef\!!stringa{\typingparameter\c!blank}}%
-% \processaction
-% [\!!stringa]
-% [ \v!standard=>\scratchskip\ctxparskip,
-% \v!small=>\scratchskip\blankokleinmaat,
-% \v!medium=>\scratchskip\blankomiddelmaat,
-% \v!big=>\scratchskip\blankogrootmaat,
-% \v!halfline=>\scratchskip.5\baselineskip,
-% \v!line=>\scratchskip\baselineskip,
-% \v!none=>\scratchskip\zeropoint,
-% \s!unknown=>\scratchskip\commalistelement]%
-% \ifgridsnapping
-% \ifdim\scratchskip=.5\baselineskip\relax
-% \edef\verbatimbaselineskip{\the\scratchskip}% new
-% \else
-% \edef\verbatimbaselineskip{\the\baselineskip}%
-% \fi
-% \else
-% \edef\verbatimbaselineskip{\the\scratchskip}%
-% \fi
-% \setupcommonverbatim}
-
-\setvalue{\??tp:\c!blank:\v!standard}{\ctxparskip}
-\setvalue{\??tp:\c!blank:\v!small }{\blankokleinmaat}
-\setvalue{\??tp:\c!blank:\v!medium }{\blankomiddelmaat}
-\setvalue{\??tp:\c!blank:\v!big }{\blankogrootmaat}
-\setvalue{\??tp:\c!blank:\v!halfline}{.5\baselineskip}
-\setvalue{\??tp:\c!blank:\v!line }{\baselineskip}
-\setvalue{\??tp:\c!blank:\v!none }{\zeropoint}
-
-\def\initializetyping
- {%\donefalse
- \switchtobodyfont[\typingparameter\c!bodyfont]%
- \donefalse
- \scratchskip\typingparameter\c!oddmargin\relax
- \ifzeropt\scratchskip\else\donetrue\fi
- \scratchskip\typingparameter\c!evenmargin\relax
- \ifzeropt\scratchskip\else\donetrue\fi
- \ifdone
- \def\doopenupverbatimline
- {\getpagestatus
- \ifrightpage
- \hskip\typingparameter\c!oddmargin\relax
- \else
- \hskip\typingparameter\c!evenmargin\relax
- \fi}%
- \else
- \doadaptleftskip{\typingparameter\c!margin}%
- \fi
- \edef\!!stringa{\executeifdefined{\??bo\typingparameter\c!blank}{\typingparameter\c!blank}}%
- \scratchskip\executeifdefined{\??tp:\c!blank:\!!stringa}\!!stringa\relax
- \ifgridsnapping
- \ifdim\scratchskip=.5\baselineskip\relax
- \edef\verbatimbaselineskip{\the\scratchskip}% new
- \else
- \edef\verbatimbaselineskip{\the\baselineskip}%
- \fi
- \else
- \edef\verbatimbaselineskip{\the\scratchskip}%
- \fi
- \setupcommonverbatim}
-
-%D The basic display verbatim commands are defined in an
-%D indirect way. As we will see, they are a specific case of a
-%D more general mechanism.
-
-% we need this hack because otherwise verbatim skips
-% the first line (everything after the initial command)
-
-\def\dostarttyping#1% tricky non standard lookahead
- {\bgroup
- \let\currenttypingclass\??tp
- \edef\currenttyping{#1}%
- \obeylines
- \futurelet\nexttoken\dodostarttyping}
-
-\def\dodostarttyping
- {\ifx\nexttoken[%
- \expandafter\dododostarttyping
- \else
- \expandafter\nododostarttyping
- \fi}
-
-\def\nododostarttyping
- {\dododostarttyping[]}
-
-\def\dododostarttyping[#1]%
- {\typingparameter\c!before
- \startpacked % includes \bgroup
- \dosetuptypelinenumbering{#1}%
- \initializetyping
- \startverbatimcolor
- \expanded{\mktypeblockverbatim{\s!start\currenttyping}{\s!stop\currenttyping}}}
-
-\def\dostoptyping#1% hm, currenttyping
- {\stopverbatimcolor
- \stoppacked % includes \egroup
- \typingparameter\c!after
- \egroup
- \dochecknextindentation{\??tp#1}%
- \dorechecknextindentation}
-
-%D Line numbering for files is combined with filtering, while
-%D display verbatim has the ability to continue.
-%D
-%D \starttyping
-%D \typefile[numbering=file,start=10,stop=12]{test.tex}
-%D
-%D \definetyping[code][numbering=line]
-%D
-%D \starttext
-%D \startcode
-%D ...
-%D ...
-%D \stopcode
-%D
-%D \startcode[continue]
-%D ...
-%D ...
-%D \stopcode
-%D
-%D \startcode[start=10]
-%D ...
-%D \stopcode
-%D \stoptyping
-
-%D \macros
-%D {setuptyping}
-%D
-%D The setup of typing accepts two arguments. The optional
-%D first one identifies the user defined ones. If only one
-%D argument is given, the values apply to both the standard
-%D command \type{\starttyping} and \type{\typefile}.
-
-\def\dosetuptyping[#1][#2]%
- {\ifsecondargument
- \getparameters[\??tp#1][#2]%
- \else
- \getparameters[\??tp][#1]%
- \fi}
-
-\def\setuptyping
- {\dodoubleempty\dosetuptyping}
-
-%D \macros
-%D {definetype}
-%D
-%D Specific inline verbatim commands can be defined with the
-%D following command.
-
-\def\definetype
- {\dodoubleempty\dodefinetype}
-
-\def\dodefinetype[#1][#2]%
- {\unexpanded\setvalue{#1}{\mktype{#1}}%
- \getparameters[\??ty#1][#2]}
-
-%D \macros
-%D {definetyping}
-%D
-%D For most users the standard \type{\start}||\type{\stop}||pair
-%D will suffice, but for documentation purposes the next
-%D definition command can be of use:
-%D
-%D \starttyping
-%D \definetyping[extratyping][margin=3em]
-%D
-%D \startextratyping
-%D these extra ones are indented by 1 em
-%D \stopextratyping
-%D \stoptyping
-%D
-%D The definitions default to the standard typing values.
-
-\def\presettyping[#1][#2]%
- {\copyparameters[\??tp#1][\??tp][\c!color,\c!style]%
- \getparameters [\??tp#1][#2]}
-
-\def\dodefinetyping[#1][#2]%
- {\setvalue{\e!start#1}{\dostarttyping{#1}}%
- \setvalue{\e!stop #1}{\dostoptyping {#1}}%
- \presettyping[#1][#2]}
-
-\def\definetyping
- {\dodoubleempty\dodefinetyping}
-
-%D We can use some core color commands. These are faster than
-%D the standard color switching ones and work ok on a line by
-%D line basis.
-%D
-%D \starttyping
-%D \def\setupverbatimcolor%
-%D {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}%
-%D \def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
-%D \def\endofpretty {\stopcolormode}}
-%D \stoptyping
-%D
-%D Since we support a global color too, the folowing
-%D definition is better:
-
-% \def\setupverbatimcolor% fast and local versus slow and global
-% {\doifelsenothing{\typingparameter\c!color}
-% {\def\beginofpretty[##1]{\startcolormode{\prettypalet:##1}}%
-% \let\endofpretty \restorecolormode % \stopcolormode
-% \let\startverbatimcolor \relax
-% \let\stopverbatimcolor \relax
-% \let\verbatimcolor \relax}
-% {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
-% \let\endofpretty \stopcolor
-% \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
-% \let\stopverbatimcolor \stopcolor
-% \def\verbatimcolor {\getvalue{\typingparameter\c!color}}}% command !
-% \doifelsenothing{\typingparameter\c!palet}
-% {\let\prettypalet\empty
-% \let\endofpretty\relax
-% \def\beginofpretty[##1]{}}
-% {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
-%
-% let's forget about this optimization not that we have mkiv
-
-\def\setupverbatimcolor
- {\def\beginofpretty[##1]{\startcolor[\prettypalet:##1]}%
- \let\endofpretty \stopcolor
- \def\startverbatimcolor{\startcolor[\typingparameter\c!color]}%
- \let\stopverbatimcolor \stopcolor
- \def\verbatimcolor {\getvalue{\typingparameter\c!color}}% command !
- \doifelsenothing{\typingparameter\c!palet}
- {\let\prettypalet\empty
- \let\endofpretty\relax
- \def\beginofpretty[##1]{}}
- {\edef\prettypalet{\prettyidentifier\typingparameter\c!palet}}}
-
-\let\prettypalet \empty
-\let\startverbatimcolor\relax
-\let\stopverbatimcolor \relax
-\let\verbatimcolor \relax
-
-%D In the verbatim module, there are some examples given of
-%D the more obscure features of the verbatim environments.
-%D
-%D \startbuffer
-%D \startTEX
-%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
-%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
-%D \stopTEX
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D This gives, as can be expected:
-%D
-%D \getbuffer
-%D
-%D When we want to see some typeset \TEX\ too, we can say:
-%D
-%D \startbuffer
-%D \startTEX
-%D \def\mathematics#1% %%\ N usage: \type {\mathematics{x^2}}
-%D {\ifmmode#1\else$#1$\fi} %%\ N becomes: \mathematics{x^2}
-%D \stopTEX
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D or:
-%D
-%D \getbuffer
-%D
-%D In a similar way:
-%D
-%D \startbuffer
-%D \startSQL
-%D select * -- indeed, here we {\em do} select
-%D from tableA
-%D where 1 = 2
-%D \stopSQL
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D gives:
-%D
-%D \getbuffer
-%D
-%D The next examples sow how we can directly call for natural
-%D \TEX\ comments:
-%D
-%D \startbuffer
-%D \setuptyping
-%D [TEX]
-%D [text=yes]
-%D
-%D \startTEX
-%D \def\mathematics#1% % usage: \type {\mathematics{x^2}}
-%D {\ifmmode#1\else$#1$\fi} % becomes: \mathematics{x^2}
-%D \stopTEX
-%D
-%D \setuptyping
-%D [SQL]
-%D [text=yes,palet=,icommand=\bf,vcommand=,ccommand=\it]
-%D
-%D \startSQL
-%D select * -- indeed, here we {\em do} select
-%D from tableA
-%D where 1 = 2
-%D \stopSQL
-%D
-%D \setuptyping
-%D [SQL]
-%D [ccommand=\tf\underbar]
-%D
-%D \startSQL
-%D select * -- indeed, here we {\em do} select
-%D from tableA
-%D where 1 = 2
-%D \stopSQL
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D Now watch:
-%D
-%D \getbuffer
-%D
-%D The natural \TEX\ typesetting was introduced when Tobias
-%D and Berend started using verbatim \JAVASCRIPT\ and \SQL.
-
-%D \macros
-%D {EveryPar, EveryLine, iflinepar}
-%D
-%D One of the features of these commands is the support of
-%D \type{\EveryPar}, \type{\EveryLine} and \type{\iflinepar}.
-%D In the documentation of the verbatim support module we give
-%D some examples of line- and paragraph numbering using these
-%D macros.
-
-%D \macros
-%D {typefile}
-%D
-%D Typesetting files verbatim (for the moment) only supports
-%D colorization of \TEX\ sources as valid option. The other
-%D setup values are inherited from display verbatim.
-%D The implementation of \type{\typefile} is straightforward:
-
-% new feature (not yet 100\% ok)
-%
-% \setuptyping[file][numbering=file]
-%
-% \typefile[start=2,nlines=3]{zapf}
-% \typefile[start=continue,nlines=13]{zapf}
-% \typefile{zapf}
-%
-% \setuptyping[file][numbering=line]
-%
-% \typefile[start=4,step=3]{zapf}
-% \typefile{zapf}
-
-\def\typefile
- {\dodoubleempty\dotypefile}
-
-\def\dotypefile[#1][#2]#3%
- {\ifsecondargument
- \dodotypefile[#1][#2]{#3}%
- \else\iffirstargument
- \doifassignmentelse{#1}
- {\dodotypefile[\v!file][#1]{#3}}
- {\dodotypefile[#1][]{#3}}%
- \else
- \dodotypefile[\v!file][]{#3}%
- \fi\fi}
-
-\def\dosetuptypelinenumbering#1% fuzzy
- {\doifundefined{\currenttypingclass\currenttyping\c!start}
- {\setuptyping[\currenttyping][\c!start=1,\c!stop=,\c!step=1,\c!nlines=]}%
- \setuptyping[\currenttyping][#1]%
- \doifelse{\typingparameter\c!numbering}\v!file
- {% kind of special: filters lines !
- \setuplinenumbering[\c!method=\v!file]%
- \donetrue}
- {\doifelse{\typingparameter\c!numbering}\v!line
- {% \setuplinenumbering defaults start/step to 1/1, so we need
- \doifinsetelse\v!continue{#1,\typingparameter\c!start}
- {\scratchcounter0\typingparameter\c!n
- \setxtypingparameter\c!start{\ifnum\scratchcounter=0 1\else\number\scratchcounter\fi}}%
- {\doifnothing{\typingparameter\c!start}{\settypingparameter\c!start{1}}}%
- \doifnothing{\typingparameter\c!step}{\settypingparameter\c!step{1}}%
- \setuplinenumbering
- [\c!method=\v!type,
- \c!start=\typingparameter\c!start,
- \c!stop=\typingparameter\c!stop,
- \c!step=\typingparameter\c!step]%
- \donetrue}
- {\donefalse}}%
- \ifdone
- \ifx\startlinenumbering\undefined \let\startlinenumbering\relax \fi
- \ifx\stoplinenumbering \undefined \let\stoplinenumbering \relax \fi
- \def\beginofverbatimlines{\startlinenumbering}%
- \def\endofverbatimlines {\stoplinenumbering\setxtypingparameter\c!n{\number\linenumber}}%
- \fi}
-
-\def\reporttypingerror#1% temp hack
- {\blank
- \dontleavehmode\hbox\bgroup
- \expanded{\defconvertedargument\noexpand\ascii{#1}}%
- \tttf[\makemessage\m!verbatims1\ascii]%
- \showmessage\m!verbatims1\ascii
- \egroup
- \blank}
-
-\def\dosometyping#1#2#3#4#5%
- {\bgroup
- \let\currenttypingclass\??tp
- \edef\currenttyping{#1}%
- \typingparameter\c!before
- \startpacked % includes \bgroup
- \dosetuptypelinenumbering{#2}%
- \doifinset{\typingparameter\c!option}{\v!commands,\v!slanted,\v!normal}
- {\setuptyping[#1][\c!option=\v!none]}%
- \doif{\typingparameter\c!option}\v!color
- {\expandafter\aftersplitstring#3\at.\to\prettyidentifier
- \settypingparameter\c!option{\prettyidentifier}}%
- \initializetyping
- \startverbatimcolor
- \doifundefinedelse{\currenttypingclass#3\v!global\c!start}
- {\scratchcounter\zerocount}
- {\scratchcounter\getvalue{\currenttypingclass#3\v!global\c!start}}%
- \advance\scratchcounter\plusone
- \setxvalue{\currenttypingclass#3\v!global\c!start}{\the\scratchcounter}%
- \doifelsenothing{\typingparameter\c!start}
- {#4}
- {\doif{\typingparameter\c!start}\v!continue
- {\setevalue{\currenttypingclass#1\c!start}%
- {\getvalue{\currenttypingclass#3\v!global\c!start}}}%
- \doifelsenothing{\typingparameter\c!stop}
- {\doifelsenothing{\typingparameter\c!nlines}
- {#4}
- {\setxvalue{\currenttypingclass#3\v!global\c!start}%
- {\the\numexpr\typingparameter\c!start+\typingparameter\c!nlines+\minusone\relax}%
- #5{\typingparameter\c!start}{\getvalue{\currenttypingclass#3\v!global\c!start}}}}%
- {#5{\typingparameter\c!start}{\typingparameter\c!stop}}}%
- \stopverbatimcolor
- \stoppacked
- \typingparameter\c!after
- \egroup}
-
-\def\doifelsetypingfile#1% sets \readfilename
- {\doiflocfileelse{#1}
- {\firstoftwoarguments}
- {\doifinputfileelse{#1}
- {\def\readfilename{\pathplusfile\filepath{#1}}\firstoftwoarguments}
- {\secondoftwoarguments}}}
-
-\def\dodotypefile[#1][#2]#3%
- {\doifelsetypingfile{#3}
- {\dosometyping{#1}{#2}{#3}\mktypefileverbatim\mktypefilelinesverbatim}
- {\reporttypingerror{#3}}}
-
-%D \macros
-%D {filename}
-%D
-%D Typesetting filenames in monospaced fonts is possible with
-%D
-%D \starttyping
-%D \filename{here/there/filename.suffix}
-%D \stoptyping
-%D
-%D The definition is not that spectacular.
-
-\unexpanded\def\filename#1{{\tttf\hyphenatedfilename{#1}}}
-
-%D This leaves some settings:
-
-\permitshiftedendofverbatim
-\optimizeverbatimtrue
-
-%D And a bonus macro:
-
-\def\verbatim#1{\defconvertedargument\ascii{#1}\ascii}
-
-%D Plugins
-
-\loadmarkfile{core-ver}
-
-%D The setups for display verbatim and file verbatim are
-%D shared. One can adapt the extra defined typing environments,
-%D but they also default to the values below. Watch the
-%D alternative escape character.
-
-\setuptyping
- [ \c!before=\blank,
- \c!after=\blank,
- \c!bodyfont=,
- \c!color=,
- \c!space=\v!off,
- \c!page=\v!no,
- \c!tab=\s!ascii,
- \c!option=\v!none,
- \c!palet=colorpretty,
- \c!text=\v!no,
- \c!style=\tttf,
- \c!icommand=\ttsl,
- \c!vcommand=,
- \c!ccommand=\tttf,
- \c!indentnext=\v!yes,
- \c!margin=\!!zeropoint,
- \c!evenmargin=\!!zeropoint,
- \c!oddmargin=\!!zeropoint,
- \c!blank=\v!line,
- \c!escape=/, % beware \string\ , should also be accepted
- \c!numbering=\v!no,
- \c!lines=,
- \c!empty=,
- \c!start=1,
- \c!stop=,
- \c!step=1,
- \c!continue=,
- \c!nlines=]
-
-\definetyping[\v!typing]
-
-\presettyping[\v!file][]
-
-% \setuptyping % not needed
-% [\v!file]
-% [\c!start=1,
-% \c!stop=,
-% \c!step=1,
-% \c!continue=,
-% \c!nlines=]
-
-%D The setups for inline verbatim default to:
-
-\setuptype
- [ \c!space=\v!off,
- \c!color=,
- \c!style=\tt\tf, % \tttf gives problems with {\tx \type...}
- \c!page=\v!no,
- \c!tab=\v!yes,
- \c!palet=colorpretty,
- \c!option=\v!normal]
-
-\definetyping[RAW] [\c!option=RAW]
-\definetyping[MP] [\c!option=MP]
-\definetyping[PL] [\c!option=PL]
-\definetyping[PM] [\c!option=PL]
-\definetyping[JS] [\c!option=JS]
-\definetyping[JV] [\c!option=JV]
-\definetyping[SQL] [\c!option=SQL]
-\definetyping[TEX] [\c!option=TEX]
-\definetyping[PAS] [\c!option=PAS]
-\definetyping[PASCAL][\c!option=PAS]
-\definetyping[MOD] [\c!option=PAS]
-\definetyping[MODULA][\c!option=PAS]
-\definetyping[DELPHI][\c!option=PAS]
-\definetyping[EIFFEL][\c!option=EIF]
-\definetyping[XML] [\c!option=XML]
-\definetyping[LUA] [\c!option=LUA]
-
-\installprettytype [RAW] [RAW]
-
-\installprettytype [TEX] [TEX]
-
-\installprettytype [PERL] [PL]
-\installprettytype [PL] [PL]
-\installprettytype [PM] [PL]
-
-\installprettytype [METAPOST] [MP]
-\installprettytype [METAFONT] [MP]
-\installprettytype [MP] [MP]
-\installprettytype [MF] [MP]
-
-\installprettytype [JAVASCRIPT] [JS]
-\installprettytype [JAVA] [JV]
-\installprettytype [JS] [JS]
-\installprettytype [JV] [JV]
-
-\installprettytype [SQL] [SQL]
-
-\installprettytype [PASCAL] [PAS]
-\installprettytype [PAS] [PAS]
-\installprettytype [MODULA] [PAS]
-\installprettytype [MOD] [PAS]
-
-\installprettytype [EIFFEL] [EIF]
-\installprettytype [EIF] [EIF]
-\installprettytype [E] [EIF]
-
-\installprettytype [XML] [XML]
-
-\installprettytype [LUA] [LUA]
-
-\installnewpretty M {\setupprettiesintype {MP}\setupprettytype}
-\installnewpretty P {\setupprettiesintype {PL}\setupprettytype}
-\installnewpretty T {\setupprettiesintype{TEX}\setupprettytype}
-\installnewpretty J {\setupprettiesintype {JV}\setupprettytype}
-\installnewpretty S {\setupprettiesintype{SQL}\setupprettytype}
-\installnewpretty W {\setupprettiesintype{PAS}\setupprettytype} % Wirth
-\installnewpretty I {\setupprettiesintype{EIF}\setupprettytype} % E taken
-\installnewpretty X {\setupprettiesintype{XML}\setupprettytype}
-
-%D We use the \CONTEXT\ color system for switching to and from
-%D color mode. We can always redefine these colors afterwards.
-
-\definecolor [colorprettyone] [r=.9, g=.0, b=.0] % red
-\definecolor [colorprettytwo] [r=.0, g=.8, b=.0] % green
-\definecolor [colorprettythree] [r=.0, g=.0, b=.9] % blue
-\definecolor [colorprettyfour] [r=.8, g=.8, b=.6] % yellow
-
-\definecolor [grayprettyone] [s=.30]
-\definecolor [grayprettytwo] [s=.45]
-\definecolor [grayprettythree] [s=.60]
-\definecolor [grayprettyfour] [s=.75]
-
-\definepalet
- [colorpretty]
- [ prettyone=colorprettyone,
- prettytwo=colorprettytwo,
- prettythree=colorprettythree,
- prettyfour=colorprettyfour]
-
-\definepalet
- [graypretty]
- [ prettyone=grayprettyone,
- prettytwo=grayprettytwo,
- prettythree=grayprettythree,
- prettyfour=grayprettyfour]
-
-\definepalet [TEXcolorpretty] [colorpretty]
-\definepalet [TEXgraypretty] [graypretty]
-\definepalet [PLcolorpretty] [colorpretty]
-\definepalet [PLgraypretty] [graypretty]
-\definepalet [PMcolorpretty] [colorpretty]
-\definepalet [PMgraypretty] [graypretty]
-\definepalet [MPcolorpretty] [colorpretty]
-\definepalet [MPgraypretty] [graypretty]
-\definepalet [JVcolorpretty] [colorpretty]
-\definepalet [JVgraypretty] [graypretty]
-\definepalet [JScolorpretty] [colorpretty]
-\definepalet [JSgraypretty] [graypretty]
-\definepalet [SQLcolorpretty] [colorpretty]
-\definepalet [SQLgraypretty] [graypretty]
-\definepalet [PAScolorpretty] [colorpretty]
-\definepalet [PASgraypretty] [graypretty]
-\definepalet [EIFcolorpretty] [colorpretty]
-\definepalet [EIFgraypretty] [graypretty]
-\definepalet [XMLcolorpretty] [colorpretty]
-\definepalet [XMLgraypretty] [graypretty]
-\definepalet [LUAcolorpretty] [colorpretty]
-\definepalet [LUAgraypretty] [graypretty]
-
-\protect \endinput
diff --git a/tex/context/base/core-vis.tex b/tex/context/base/core-vis.tex
index b20c9b9ce..949cd176f 100644
--- a/tex/context/base/core-vis.tex
+++ b/tex/context/base/core-vis.tex
@@ -25,14 +25,12 @@
%D %\leftskip only if explicit one
%D %\rightskip only if explicit one
-\writestatus{loading}{Context Support Macros / Visualization}
+\writestatus{loading}{ConTeXt Support Macros / Visualization}
\unprotect
%D \macros
-%D {indent, noindent,
-%D leavevmode,
-%D par}
+%D {indent, noindent, par}
%D
%D \TeX\ acts upon paragraphs. In mosts documents paragraphs
%D are separated by empty lines, which internally are handled as
@@ -43,17 +41,11 @@
%D Because the actual typesetting is based on both explicit
%D user and implicit system actions, visualization is only
%D possible for the user supplied \type{\indent},
-%D \type{\noindent}, \type{\leavevmode} and \type{\par}. Other
+%D \type{\noindent}, and \type{\par}. Other
%D 'clever' tricks will quite certainly lead to more failures
%D than successes, so we only support these three explicit
%D primitives and one macro:
-\let\normalnoindent = \noindent
-\let\normalindent = \indent
-\let\normalpar = \par
-
-\let\normalleavevmode = \leavevmode
-
\def\showparagraphcue#1#2#3#4#5%
{\bgroup
\scratchdimen#1\relax
@@ -128,30 +120,15 @@
\fi
\normalhskip\parindent}
-\def\ruledleavevmode
- {\relax
- \normalleavevmode
- \ifdim\parindent>\zeropoint
- \normalhskip-\parindent
- \ruledparagraphcues
- \showparagraphcue\parindent\relax\leftrulefalse\rightrulefalse\!!height
- \normalhskip\parindent
- \else
- \ruledparagraphcues
- \showparagraphcue{40\testrulewidth}\llap\leftrulefalse\rightrulefalse\!!height
- \fi}
-
\def\dontshowimplicits
{\let\noindent \normalnoindent
\let\indent \normalindent
- \let\leavevmode \normalleavevmode
\let\par \normalpar}
\def\showimplicits
{\testrulewidth \defaulttestrulewidth
\let\noindent \rulednoindent
\let\indent \ruledindent
- \let\leavevmode \ruledleavevmode
\let\par \ruledpar}
%D The next few||line examples show the four cues. Keep in
@@ -170,18 +147,15 @@
%D
%D \voorbeeld \indent
%D \voorbeeld \noindent
-%D \voorbeeld \leavevmode
%D
%D \parindent=60pt
%D
%D \voorbeeld \indent
%D \voorbeeld \noindent
-%D \voorbeeld \leavevmode
%D
%D \startnarrower
%D \voorbeeld \indent
%D \voorbeeld \noindent
-%D \voorbeeld \leavevmode
%D \stopnarrower
%D \egroup
%D
diff --git a/tex/context/base/data-aux.lua b/tex/context/base/data-aux.lua
new file mode 100644
index 000000000..492cce6fd
--- /dev/null
+++ b/tex/context/base/data-aux.lua
@@ -0,0 +1,57 @@
+if not modules then modules = { } end modules ['data-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local find = string.find
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+
+function resolvers.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
+ local scriptpath = "scripts/context/lua"
+ newname = file.addsuffix(newname,"lua")
+ local oldscript = resolvers.clean_path(oldname)
+ if trace_verbose then
+ logs.report("fileio","to be replaced old script %s", oldscript)
+ end
+ local newscripts = resolvers.find_files(newname) or { }
+ if #newscripts == 0 then
+ if trace_verbose then
+ logs.report("fileio","unable to locate new script")
+ end
+ else
+ for i=1,#newscripts do
+ local newscript = resolvers.clean_path(newscripts[i])
+ if trace_verbose then
+ logs.report("fileio","checking new script %s", newscript)
+ end
+ if oldscript == newscript then
+ if trace_verbose then
+ logs.report("fileio","old and new script are the same")
+ end
+ elseif not find(newscript,scriptpath) then
+ if trace_verbose then
+ logs.report("fileio","new script should come from %s",scriptpath)
+ end
+ elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then
+ if trace_verbose then
+ logs.report("fileio","invalid new script name")
+ end
+ else
+ local newdata = io.loaddata(newscript)
+ if newdata then
+ if trace_verbose then
+ logs.report("fileio","old script content replaced by new content")
+ end
+ io.savedata(oldscript,newdata)
+ break
+ elseif trace_verbose then
+ logs.report("fileio","unable to load new script")
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/data-bin.lua b/tex/context/base/data-bin.lua
new file mode 100644
index 000000000..5f342c339
--- /dev/null
+++ b/tex/context/base/data-bin.lua
@@ -0,0 +1,26 @@
+if not modules then modules = { } end modules ['data-bin'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function resolvers.findbinfile(filename, filetype)
+ return resolvers.methodhandler('finders',file.collapse_path(filename), filetype)
+end
+
+function resolvers.openbinfile(filename)
+ return resolvers.methodhandler('loaders',file.collapse_path(filename))
+end
+
+function resolvers.loadbinfile(filename, filetype)
+ local fname = resolvers.findbinfile(file.collapse_path(filename), filetype)
+ if fname and fname ~= "" then
+ return resolvers.openbinfile(fname)
+ else
+ return unpack(loaders.notfound)
+ end
+end
diff --git a/tex/context/base/data-con.lua b/tex/context/base/data-con.lua
new file mode 100644
index 000000000..02ee9eedd
--- /dev/null
+++ b/tex/context/base/data-con.lua
@@ -0,0 +1,122 @@
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
diff --git a/tex/context/base/data-crl.lua b/tex/context/base/data-crl.lua
new file mode 100644
index 000000000..5cad241a6
--- /dev/null
+++ b/tex/context/base/data-crl.lua
@@ -0,0 +1,58 @@
+if not modules then modules = { } end modules ['data-crl'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+curl = curl or { }
+
+curl.cached = { }
+curl.cachepath = caches.definepath("curl")
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function curl.fetch(protocol, name)
+ local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-")
+-- cachename = cachename:gsub("[\\/]", io.fileseparator)
+ cachename = cachename:gsub("[\\]", "/") -- cleanup
+ if not curl.cached[name] then
+ if not io.exists(cachename) then
+ curl.cached[name] = cachename
+ local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
+ os.spawn(command)
+ end
+ if io.exists(cachename) then
+ curl.cached[name] = cachename
+ else
+ curl.cached[name] = ""
+ end
+ end
+ return curl.cached[name]
+end
+
+function finders.curl(protocol,filename)
+ local foundname = curl.fetch(protocol, filename)
+ return finders.generic(protocol,foundname,filetype)
+end
+
+function openers.curl(protocol,filename)
+ return openers.generic(protocol,filename)
+end
+
+function loaders.curl(protocol,filename)
+ return loaders.generic(protocol,filename)
+end
+
+-- todo: metamethod
+
+function curl.install(protocol)
+ finders[protocol] = function (filename,filetype) return finders.curl(protocol,filename) end
+ openers[protocol] = function (filename) return openers.curl(protocol,filename) end
+ loaders[protocol] = function (filename) return loaders.curl(protocol,filename) end
+end
+
+curl.install('http')
+curl.install('https')
+curl.install('ftp')
diff --git a/tex/context/base/data-ctx.lua b/tex/context/base/data-ctx.lua
new file mode 100644
index 000000000..00d307b6d
--- /dev/null
+++ b/tex/context/base/data-ctx.lua
@@ -0,0 +1,29 @@
+if not modules then modules = { } end modules ['data-ctx'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+function resolvers.save_used_files_in_trees(filename,jobname)
+ if not filename then filename = 'luatex.jlg' end
+ local found = instance.foundintrees
+ local f = io.open(filename,'w')
+ if f then
+ f:write("<?xml version='1.0' standalone='yes'?>\n")
+ f:write("<rl:job>\n")
+ if jobname then
+ f:write(format("\t<rl:name>%s</rl:name>\n",jobname))
+ end
+ f:write("\t<rl:files>\n")
+ for _,v in ipairs(table.sortedkeys(found)) do
+ f:write(format("\t\t<rl:file n='%s'>%s</rl:file>\n",found[v],v))
+ end
+ f:write("\t</rl:files>\n")
+ f:write("</rl:usedfiles>\n")
+ f:close()
+ end
+end
diff --git a/tex/context/base/data-gen.lua b/tex/context/base/data-gen.lua
new file mode 100644
index 000000000..8537b0526
--- /dev/null
+++ b/tex/context/base/data-gen.lua
@@ -0,0 +1,9 @@
+if not modules then modules = { } end modules ['data-gen'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- move generators here
diff --git a/tex/context/base/data-inp.lua b/tex/context/base/data-inp.lua
new file mode 100644
index 000000000..700e982c2
--- /dev/null
+++ b/tex/context/base/data-inp.lua
@@ -0,0 +1,15 @@
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+resolvers.finders = resolvers.finders or { }
+resolvers.openers = resolvers.openers or { }
+resolvers.loaders = resolvers.loaders or { }
+
+resolvers.finders.notfound = { nil }
+resolvers.openers.notfound = { nil }
+resolvers.loaders.notfound = { false, nil, 0 }
diff --git a/tex/context/base/data-kps.lua b/tex/context/base/data-kps.lua
new file mode 100644
index 000000000..09d502409
--- /dev/null
+++ b/tex/context/base/data-kps.lua
@@ -0,0 +1,101 @@
+if not modules then modules = { } end modules ['luat-kps'] = {
+ version = 1.001,
+ comment = "companion to luatools.lua",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This file is used when we want the input handlers to behave like
+<type>kpsewhich</type>. What to do with the following:</p>
+
+<typing>
+{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
+$SELFAUTOLOC : /usr/tex/bin/platform
+$SELFAUTODIR : /usr/tex/bin
+$SELFAUTOPARENT : /usr/tex
+</typing>
+
+<p>How about just forgetting about them?</p>
+--ldx]]--
+
+local suffixes = resolvers.suffixes
+local formats = resolvers.formats
+
+suffixes['gf'] = { '<resolution>gf' }
+suffixes['pk'] = { '<resolution>pk' }
+suffixes['base'] = { 'base' }
+suffixes['bib'] = { 'bib' }
+suffixes['bst'] = { 'bst' }
+suffixes['cnf'] = { 'cnf' }
+suffixes['mem'] = { 'mem' }
+suffixes['mf'] = { 'mf' }
+suffixes['mfpool'] = { 'pool' }
+suffixes['mft'] = { 'mft' }
+suffixes['mppool'] = { 'pool' }
+suffixes['graphic/figure'] = { 'eps', 'epsi' }
+suffixes['texpool'] = { 'pool' }
+suffixes['PostScript header'] = { 'pro' }
+suffixes['ist'] = { 'ist' }
+suffixes['web'] = { 'web', 'ch' }
+suffixes['cweb'] = { 'w', 'web', 'ch' }
+suffixes['cmap files'] = { 'cmap' }
+suffixes['lig files'] = { 'lig' }
+suffixes['bitmap font'] = { }
+suffixes['MetaPost support'] = { }
+suffixes['TeX system documentation'] = { }
+suffixes['TeX system sources'] = { }
+suffixes['dvips config'] = { }
+suffixes['type42 fonts'] = { }
+suffixes['web2c files'] = { }
+suffixes['other text files'] = { }
+suffixes['other binary files'] = { }
+suffixes['opentype fonts'] = { 'otf' }
+
+suffixes['fmt'] = { 'fmt' }
+suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
+
+suffixes['pdftex config'] = { }
+suffixes['Troff fonts'] = { }
+
+suffixes['ls-R'] = { }
+
+--[[ldx--
+<p>If you wondered abou tsome of the previous mappings, how about
+the next bunch:</p>
+--ldx]]--
+
+formats['bib'] = ''
+formats['bst'] = ''
+formats['mft'] = ''
+formats['ist'] = ''
+formats['web'] = ''
+formats['cweb'] = ''
+formats['MetaPost support'] = ''
+formats['TeX system documentation'] = ''
+formats['TeX system sources'] = ''
+formats['Troff fonts'] = ''
+formats['dvips config'] = ''
+formats['graphic/figure'] = ''
+formats['ls-R'] = ''
+formats['other text files'] = ''
+formats['other binary files'] = ''
+
+formats['gf'] = ''
+formats['pk'] = ''
+formats['base'] = 'MFBASES'
+formats['cnf'] = ''
+formats['mem'] = 'MPMEMS'
+formats['mf'] = 'MFINPUTS'
+formats['mfpool'] = 'MFPOOL'
+formats['mppool'] = 'MPPOOL'
+formats['texpool'] = 'TEXPOOL'
+formats['PostScript header'] = 'TEXPSHEADERS'
+formats['cmap files'] = 'CMAPFONTS'
+formats['type42 fonts'] = 'T42FONTS'
+formats['web2c files'] = 'WEB2C'
+formats['pdftex config'] = 'PDFTEXCONFIG'
+formats['texmfscripts'] = 'TEXMFSCRIPTS'
+formats['bitmap font'] = ''
+formats['lig files'] = 'LIGFONTS'
diff --git a/tex/context/base/data-lst.lua b/tex/context/base/data-lst.lua
new file mode 100644
index 000000000..10d3ea479
--- /dev/null
+++ b/tex/context/base/data-lst.lua
@@ -0,0 +1,58 @@
+if not modules then modules = { } end modules ['data-lst'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- used in mtxrun
+
+local find, concat, upper, format = string.find, table.concat, string.upper, string.format
+
+resolvers.listers = resolvers.listers or { }
+
+local function tabstr(str)
+ if type(str) == 'table' then
+ return concat(str," | ")
+ else
+ return str
+ end
+end
+
+local function list(list,report)
+ local instance = resolvers.instance
+ local pat = upper(pattern or "","")
+ local report = report or texio.write_nl
+ for _,key in pairs(table.sortedkeys(list)) do
+ if instance.pattern == "" or find(upper(key),pat) then
+ if instance.kpseonly then
+ if instance.kpsevars[key] then
+ report(format("%s=%s",key,tabstr(list[key])))
+ end
+ else
+ report(format('%s %s=%s',(instance.kpsevars[key] and 'K') or 'E',key,tabstr(list[key])))
+ end
+ end
+ end
+end
+
+function resolvers.listers.variables () list(resolvers.instance.variables ) end
+function resolvers.listers.expansions() list(resolvers.instance.expansions) end
+
+function resolvers.listers.configurations(report)
+ local report = report or texio.write_nl
+ local instance = resolvers.instance
+ for _,key in ipairs(table.sortedkeys(instance.kpsevars)) do
+ if not instance.pattern or (instance.pattern=="") or find(key,instance.pattern) then
+ report(format("%s\n",key))
+ for i,c in ipairs(instance.order) do
+ local str = c[key]
+ if str then
+ report(format("\t%s\t%s",i,str))
+ end
+ end
+ report("")
+ end
+ end
+end
diff --git a/tex/context/base/data-lua.lua b/tex/context/base/data-lua.lua
new file mode 100644
index 000000000..86231b3a3
--- /dev/null
+++ b/tex/context/base/data-lua.lua
@@ -0,0 +1,55 @@
+if not modules then modules = { } end modules ['data-lua'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- some loading stuff ... we might move this one to slot 1 depending
+-- on the developments (the loaders must not trigger kpse); we could
+-- of course use a more extensive lib path spec
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+local gsub = string.gsub
+
+local libformats = { 'luatexlibs', 'tex', 'texmfscripts', 'othertextfiles' }
+local libpaths = file.split_path(package.path)
+
+package.loaders[#package.loaders+1] = function(name)
+ for i=1,#libformats do
+ local format = libformats[i]
+ local resolved = resolvers.find_file(name,format) or ""
+ if resolved ~= "" then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via environment: '%s'",name,resolved)
+ end
+ return function() return dofile(resolved) end
+ end
+ end
+ local simple = file.removesuffix(name)
+ for i=1,#libpaths do
+ local resolved = gsub(libpaths[i],"?",simple)
+ if resolvers.isreadable.file(resolved) then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located via 'package.path': '%s'",name,resolved)
+ end
+ return function() return dofile(resolved) end
+ end
+ end
+ -- just in case the distribution is messed up
+ local resolved = resolvers.find_file(file.basename(name),'luatexlibs') or ""
+ if resolved ~= "" then
+ if trace_locating then
+ logs.report("fileio","! lib '%s' located by basename via environment: '%s'",name,resolved)
+ end
+ return function() return dofile(resolved) end
+ end
+ if trace_locating then
+ logs.report("fileio",'? unable to locate lib: %s',name)
+ end
+ return "unable to locate " .. name
+end
+
+resolvers.loadlualib = require
diff --git a/tex/context/base/data-out.lua b/tex/context/base/data-out.lua
new file mode 100644
index 000000000..b774e25fc
--- /dev/null
+++ b/tex/context/base/data-out.lua
@@ -0,0 +1,10 @@
+if not modules then modules = { } end modules ['data-out'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+outputs = outputs or { }
+
diff --git a/tex/context/base/data-pre.lua b/tex/context/base/data-pre.lua
new file mode 100644
index 000000000..deee9ebf4
--- /dev/null
+++ b/tex/context/base/data-pre.lua
@@ -0,0 +1,90 @@
+if not modules then modules = { } end modules ['data-res'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--~ print(resolvers.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
+
+local upper, lower, gsub = string.upper, string.lower, string.gsub
+
+local prefixes = { }
+
+prefixes.environment = function(str)
+ return resolvers.clean_path(os.getenv(str) or os.getenv(upper(str)) or os.getenv(lower(str)) or "")
+end
+
+prefixes.relative = function(str,n)
+ if io.exists(str) then
+ -- nothing
+ elseif io.exists("./" .. str) then
+ str = "./" .. str
+ else
+ local p = "../"
+ for i=1,n or 2 do
+ if io.exists(p .. str) then
+ str = p .. str
+ break
+ else
+ p = p .. "../"
+ end
+ end
+ end
+ return resolvers.clean_path(str)
+end
+
+prefixes.locate = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path((fullname ~= "" and fullname) or str)
+end
+
+prefixes.filename = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.basename((fullname ~= "" and fullname) or str))
+end
+
+prefixes.pathname = function(str)
+ local fullname = resolvers.find_given_file(str) or ""
+ return resolvers.clean_path(file.dirname((fullname ~= "" and fullname) or str))
+end
+
+prefixes.env = prefixes.environment
+prefixes.rel = prefixes.relative
+prefixes.loc = prefixes.locate
+prefixes.kpse = prefixes.locate
+prefixes.full = prefixes.locate
+prefixes.file = prefixes.filename
+prefixes.path = prefixes.pathname
+
+local function _resolve_(method,target)
+ if prefixes[method] then
+ return prefixes[method](target)
+ else
+ return method .. ":" .. target
+ end
+end
+
+local function resolve(str)
+ if type(str) == "table" then
+ for k, v in pairs(str) do -- ipairs
+ str[k] = resolve(v) or v
+ end
+ elseif str and str ~= "" then
+ str = gsub(str,"([a-z]+):([^ \"\']*)",_resolve_)
+ end
+ return str
+end
+
+resolvers.resolve = resolve
+
+if os.uname then
+
+ for k, v in pairs(os.uname()) do
+ if not prefixes[k] then
+ prefixes[k] = function() return v end
+ end
+ end
+
+end
diff --git a/tex/context/base/data-res.lua b/tex/context/base/data-res.lua
new file mode 100644
index 000000000..0981881a2
--- /dev/null
+++ b/tex/context/base/data-res.lua
@@ -0,0 +1,2029 @@
+if not modules then modules = { } end modules ['data-inp'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+ comment = "companion to luat-lib.tex",
+}
+
+-- After a few years using the code the large luat-inp.lua file
+-- has been split up a bit. In the process some functionality was
+-- dropped:
+--
+-- * support for reading lsr files
+-- * selective scanning (subtrees)
+-- * some public auxiliary functions were made private
+--
+-- TODO: os.getenv -> os.env[]
+-- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
+-- TODO: check escaping in find etc, too much, too slow
+
+-- This lib is multi-purpose and can be loaded again later on so that
+-- additional functionality becomes available. We will split thislogs.report("fileio",
+-- module in components once we're done with prototyping. This is the
+-- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
+-- something in this module one can best check with Taco or Hans first; there
+-- is some nasty trickery going on that relates to traditional kpse support.
+
+-- To be considered: hash key lowercase, first entry in table filename
+-- (any case), rest paths (so no need for optimization). Or maybe a
+-- separate table that matches lowercase names to mixed case when
+-- present. In that case the lower() cases can go away. I will do that
+-- only when we run into problems with names ... well ... Iwona-Regular.
+
+-- Beware, loading and saving is overloaded in luat-tmp!
+
+local format, gsub, find, lower, upper, match, gmatch = string.format, string.gsub, string.find, string.lower, string.upper, string.match, string.gmatch
+local concat, insert, sortedkeys = table.concat, table.insert, table.sortedkeys
+local next, type = next, type
+
+local trace_locating, trace_detail, trace_verbose = false, false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+trackers.register("resolvers.detail", function(v) trace_detail = v trackers.enable("resolvers.verbose,resolvers.detail") end)
+
+if not resolvers then
+ resolvers = {
+ suffixes = { },
+ formats = { },
+ dangerous = { },
+ suffixmap = { },
+ alternatives = { },
+ locators = { }, -- locate databases
+ hashers = { }, -- load databases
+ generators = { }, -- generate databases
+ }
+end
+
+local resolvers = resolvers
+
+resolvers.locators .notfound = { nil }
+resolvers.hashers .notfound = { nil }
+resolvers.generators.notfound = { nil }
+
+resolvers.cacheversion = '1.0.1'
+resolvers.cnfname = 'texmf.cnf'
+resolvers.luaname = 'texmfcnf.lua'
+resolvers.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
+resolvers.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
+
+local dummy_path_expr = "^!*unset/*$"
+
+local formats = resolvers.formats
+local suffixes = resolvers.suffixes
+local dangerous = resolvers.dangerous
+local suffixmap = resolvers.suffixmap
+local alternatives = resolvers.alternatives
+
+formats['afm'] = 'AFMFONTS' suffixes['afm'] = { 'afm' }
+formats['enc'] = 'ENCFONTS' suffixes['enc'] = { 'enc' }
+formats['fmt'] = 'TEXFORMATS' suffixes['fmt'] = { 'fmt' }
+formats['map'] = 'TEXFONTMAPS' suffixes['map'] = { 'map' }
+formats['mp'] = 'MPINPUTS' suffixes['mp'] = { 'mp' }
+formats['ocp'] = 'OCPINPUTS' suffixes['ocp'] = { 'ocp' }
+formats['ofm'] = 'OFMFONTS' suffixes['ofm'] = { 'ofm', 'tfm' }
+formats['otf'] = 'OPENTYPEFONTS' suffixes['otf'] = { 'otf' } -- 'ttf'
+formats['opl'] = 'OPLFONTS' suffixes['opl'] = { 'opl' }
+formats['otp'] = 'OTPINPUTS' suffixes['otp'] = { 'otp' }
+formats['ovf'] = 'OVFFONTS' suffixes['ovf'] = { 'ovf', 'vf' }
+formats['ovp'] = 'OVPFONTS' suffixes['ovp'] = { 'ovp' }
+formats['tex'] = 'TEXINPUTS' suffixes['tex'] = { 'tex' }
+formats['tfm'] = 'TFMFONTS' suffixes['tfm'] = { 'tfm' }
+formats['ttf'] = 'TTFONTS' suffixes['ttf'] = { 'ttf', 'ttc' }
+formats['pfb'] = 'T1FONTS' suffixes['pfb'] = { 'pfb', 'pfa' }
+formats['vf'] = 'VFFONTS' suffixes['vf'] = { 'vf' }
+
+formats['fea'] = 'FONTFEATURES' suffixes['fea'] = { 'fea' }
+formats['cid'] = 'FONTCIDMAPS' suffixes['cid'] = { 'cid', 'cidmap' }
+
+formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
+suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
+
+formats ['lua'] = 'LUAINPUTS' -- new
+suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
+
+-- backward compatible ones
+
+alternatives['map files'] = 'map'
+alternatives['enc files'] = 'enc'
+alternatives['cid files'] = 'cid'
+alternatives['fea files'] = 'fea'
+alternatives['opentype fonts'] = 'otf'
+alternatives['truetype fonts'] = 'ttf'
+alternatives['truetype collections'] = 'ttc'
+alternatives['type1 fonts'] = 'pfb'
+
+-- obscure ones
+
+formats ['misc fonts'] = ''
+suffixes['misc fonts'] = { }
+
+formats ['sfd'] = 'SFDFONTS'
+suffixes ['sfd'] = { 'sfd' }
+alternatives['subfont definition files'] = 'sfd'
+
+-- In practice we will work within one tds tree, but i want to keep
+-- the option open to build tools that look at multiple trees, which is
+-- why we keep the tree specific data in a table. We used to pass the
+-- instance but for practical pusposes we now avoid this and use a
+-- instance variable.
+
+-- here we catch a few new thingies (todo: add these paths to context.tmf)
+--
+-- FONTFEATURES = .;$TEXMF/fonts/fea//
+-- FONTCIDMAPS = .;$TEXMF/fonts/cid//
+
+-- we always have one instance active
+
+resolvers.instance = resolvers.instance or nil -- the current one (slow access)
+local instance = resolvers.instance or nil -- the current one (fast access)
+
+function resolvers.newinstance()
+
+ -- store once, freeze and faster (once reset we can best use
+ -- instance.environment) maybe better have a register suffix
+ -- function
+
+ for k, v in next, suffixes do
+ for i=1,#v do
+ local vi = v[i]
+ if vi then
+ suffixmap[vi] = k
+ end
+ end
+ end
+
+ -- because vf searching is somewhat dangerous, we want to prevent
+ -- too liberal searching esp because we do a lookup on the current
+ -- path anyway; only tex (or any) is safe
+
+ for k, v in next, formats do
+ dangerous[k] = true
+ end
+ dangerous.tex = nil
+
+ -- the instance
+
+ local newinstance = {
+ rootpath = '',
+ treepath = '',
+ progname = 'context',
+ engine = 'luatex',
+ format = '',
+ environment = { },
+ variables = { },
+ expansions = { },
+ files = { },
+ remap = { },
+ configuration = { },
+ setup = { },
+ order = { },
+ found = { },
+ foundintrees = { },
+ kpsevars = { },
+ hashes = { },
+ cnffiles = { },
+ luafiles = { },
+ lists = { },
+ remember = true,
+ diskcache = true,
+ renewcache = false,
+ scandisk = true,
+ cachepath = nil,
+ loaderror = false,
+ sortdata = false,
+ savelists = true,
+ cleanuppaths = true,
+ allresults = false,
+ pattern = nil, -- lists
+ data = { }, -- only for loading
+ force_suffixes = true,
+ fakepaths = { },
+ }
+
+ local ne = newinstance.environment
+
+ for k,v in next, os.env do
+ ne[k] = resolvers.bare_variable(v)
+ end
+
+ return newinstance
+
+end
+
+function resolvers.setinstance(someinstance)
+ instance = someinstance
+ resolvers.instance = someinstance
+ return someinstance
+end
+
+function resolvers.reset()
+ return resolvers.setinstance(resolvers.newinstance())
+end
+
+local function reset_hashes()
+ instance.lists = { }
+ instance.found = { }
+end
+
+local function check_configuration() -- not yet ok, no time for debugging now
+ local ie = instance.environment
+ local function fix(varname,default)
+ local proname = varname .. "." .. instance.progname or "crap"
+ local p, v = ie[proname], ie[varname]
+ if not ((p and p ~= "") or (v and v ~= "")) then
+ instance.variables[varname] = default -- or environment?
+ end
+ end
+ local name = os.name
+ if name == "windows" then
+ fix("OSFONTDIR", "c:/windows/fonts//")
+ elseif name == "macosx" then
+ fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
+ else
+ -- bad luck
+ end
+ fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
+ fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
+ fix("LUATEXLIBS" , ".;$TEXMF/luatex/lua//")
+end
+
+function resolvers.bare_variable(str) -- assumes str is a string
+ return (gsub(str,"\s*([\"\']?)(.+)%1\s*", "%2"))
+end
+
+function resolvers.settrace(n) -- no longer number but: 'locating' or 'detail'
+ if n then
+ trackers.disable("resolvers.*")
+ trackers.enable("resolvers."..n)
+ end
+end
+
+resolvers.settrace(os.getenv("MTX.resolvers.TRACE") or os.getenv("MTX_INPUT_TRACE"))
+
+function resolvers.osenv(key)
+ local ie = instance.environment
+ local value = ie[key]
+ if value == nil then
+ -- local e = os.getenv(key)
+ local e = os.env[key]
+ if e == nil then
+ -- value = "" -- false
+ else
+ value = resolvers.bare_variable(e)
+ end
+ ie[key] = value
+ end
+ return value or ""
+end
+
+function resolvers.env(key)
+ return instance.environment[key] or resolvers.osenv(key)
+end
+
+--
+
+local function expand_vars(lst) -- simple vars
+ local variables, env = instance.variables, resolvers.env
+ local function resolve(a)
+ return variables[a] or env(a)
+ end
+ for k=1,#lst do
+ lst[k] = gsub(lst[k],"%$([%a%d%_%-]+)",resolve)
+ end
+end
+
+local function expanded_var(var) -- simple vars
+ local function resolve(a)
+ return instance.variables[a] or resolvers.env(a)
+ end
+ return (gsub(var,"%$([%a%d%_%-]+)",resolve))
+end
+
+local function entry(entries,name)
+ if name and (name ~= "") then
+ name = gsub(name,'%$','')
+ local result = entries[name..'.'..instance.progname] or entries[name]
+ if result then
+ return result
+ else
+ result = resolvers.env(name)
+ if result then
+ instance.variables[name] = result
+ resolvers.expand_variables()
+ return instance.expansions[name] or ""
+ end
+ end
+ end
+ return ""
+end
+
+local function is_entry(entries,name)
+ if name and name ~= "" then
+ name = gsub(name,'%$','')
+ return (entries[name..'.'..instance.progname] or entries[name]) ~= nil
+ else
+ return false
+ end
+end
+
+-- {a,b,c,d}
+-- a,b,c/{p,q,r},d
+-- a,b,c/{p,q,r}/d/{x,y,z}//
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
+-- a{b,c}{d,e}f
+-- {a,b,c,d}
+-- {a,b,c/{p,q,r},d}
+-- {a,b,c/{p,q,r}/d/{x,y,z}//}
+-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
+-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
+-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
+
+-- this one is better and faster, but it took me a while to realize
+-- that this kind of replacement is cleaner than messy parsing and
+-- fuzzy concatenating we can probably gain a bit with selectively
+-- applying lpeg, but experiments with lpeg parsing this proved not to
+-- work that well; the parsing is ok, but dealing with the resulting
+-- table is a pain because we need to work inside-out recursively
+
+local function splitpathexpr(str, t, validate)
+ -- no need for further optimization as it is only called a
+ -- few times, we can use lpeg for the sub; we could move
+ -- the local functions outside the body
+ t = t or { }
+ str = gsub(str,",}",",@}")
+ str = gsub(str,"{,","{@,")
+ -- str = "@" .. str .. "@"
+ local ok, done
+ local function do_first(a,b)
+ local t = { }
+ for s in gmatch(b,"[^,]+") do t[#t+1] = a .. s end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_second(a,b)
+ local t = { }
+ for s in gmatch(a,"[^,]+") do t[#t+1] = s .. b end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_both(a,b)
+ local t = { }
+ for sa in gmatch(a,"[^,]+") do
+ for sb in gmatch(b,"[^,]+") do
+ t[#t+1] = sa .. sb
+ end
+ end
+ return "{" .. concat(t,",") .. "}"
+ end
+ local function do_three(a,b,c)
+ return a .. b.. c
+ end
+ while true do
+ done = false
+ while true do
+ str, ok = gsub(str,"([^{},]+){([^{}]+)}",do_first)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}([^{},]+)",do_second)
+ if ok > 0 then done = true else break end
+ end
+ while true do
+ str, ok = gsub(str,"{([^{}]+)}{([^{}]+)}",do_both)
+ if ok > 0 then done = true else break end
+ end
+ str, ok = gsub(str,"({[^{}]*){([^{}]+)}([^{}]*})",do_three)
+ if ok > 0 then done = true end
+ if not done then break end
+ end
+ str = gsub(str,"[{}]", "")
+ str = gsub(str,"@","")
+ if validate then
+ for s in gmatch(str,"[^,]+") do
+ s = validate(s)
+ if s then t[#t+1] = s end
+ end
+ else
+ for s in gmatch(str,"[^,]+") do
+ t[#t+1] = s
+ end
+ end
+ return t
+end
+
+local function expanded_path_from_list(pathlist) -- maybe not a list, just a path
+ -- a previous version fed back into pathlist
+ local newlist, ok = { }, false
+ for k=1,#pathlist do
+ if find(pathlist[k],"[{}]") then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local function validate(s)
+ s = file.collapse_path(s)
+ return s ~= "" and not find(s,dummy_path_expr) and s
+ end
+ for k=1,#pathlist do
+ splitpathexpr(pathlist[k],newlist,validate)
+ end
+ else
+ for k=1,#pathlist do
+ for p in gmatch(pathlist[k],"([^,]+)") do
+ p = file.collapse_path(p)
+ if p ~= "" then newlist[#newlist+1] = p end
+ end
+ end
+ end
+ return newlist
+end
+
+-- we follow a rather traditional approach:
+--
+-- (1) texmf.cnf given in TEXMFCNF
+-- (2) texmf.cnf searched in default variable
+--
+-- also we now follow the stupid route: if not set then just assume *one*
+-- cnf file under texmf (i.e. distribution)
+
+resolvers.ownpath = resolvers.ownpath or nil
+resolvers.ownbin = resolvers.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
+resolvers.autoselfdir = true -- false may be handy for debugging
+
+function resolvers.getownpath()
+ if not resolvers.ownpath then
+ if resolvers.autoselfdir and os.selfdir then
+ resolvers.ownpath = os.selfdir
+ else
+ local binary = resolvers.ownbin
+ if os.platform == "windows" then
+ binary = file.replacesuffix(binary,"exe")
+ end
+ for p in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
+ local b = file.join(p,binary)
+ if lfs.isfile(b) then
+ -- we assume that after changing to the path the currentdir function
+ -- resolves to the real location and use this side effect here; this
+ -- trick is needed because on the mac installations use symlinks in the
+ -- path instead of real locations
+ local olddir = lfs.currentdir()
+ if lfs.chdir(p) then
+ local pp = lfs.currentdir()
+ if trace_verbose and p ~= pp then
+ logs.report("fileio","following symlink %s to %s",p,pp)
+ end
+ resolvers.ownpath = pp
+ lfs.chdir(olddir)
+ else
+ if trace_verbose then
+ logs.report("fileio","unable to check path %s",p)
+ end
+ resolvers.ownpath = p
+ end
+ break
+ end
+ end
+ end
+ if not resolvers.ownpath then resolvers.ownpath = '.' end
+ end
+ return resolvers.ownpath
+end
+
+local own_places = { "SELFAUTOLOC", "SELFAUTODIR", "SELFAUTOPARENT", "TEXMFCNF" }
+
+local function identify_own()
+ local ownpath = resolvers.getownpath() or lfs.currentdir()
+ local ie = instance.environment
+ if ownpath then
+ if resolvers.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
+ if resolvers.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
+ if resolvers.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
+ else
+ logs.report("fileio","error: unable to locate ownpath")
+ os.exit()
+ end
+ if resolvers.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = resolvers.cnfdefault end
+ if resolvers.env('TEXOS') == "" then os.env['TEXOS'] = resolvers.env('SELFAUTODIR') end
+ if resolvers.env('TEXROOT') == "" then os.env['TEXROOT'] = resolvers.env('SELFAUTOPARENT') end
+ if trace_verbose then
+ for i=1,#own_places do
+ local v = own_places[i]
+ logs.report("fileio","variable %s set to %s",v,resolvers.env(v) or "unknown")
+ end
+ end
+ identify_own = function() end
+end
+
+function resolvers.identify_cnf()
+ if #instance.cnffiles == 0 then
+ -- fallback
+ identify_own()
+ -- the real search
+ resolvers.expand_variables()
+ local t = resolvers.split_path(resolvers.env('TEXMFCNF'))
+ t = expanded_path_from_list(t)
+ expand_vars(t) -- redundant
+ local function locate(filename,list)
+ for i=1,#t do
+ local ti = t[i]
+ local texmfcnf = file.collapse_path(file.join(ti,filename))
+ if lfs.isfile(texmfcnf) then
+ list[#list+1] = texmfcnf
+ end
+ end
+ end
+ locate(resolvers.luaname,instance.luafiles)
+ locate(resolvers.cnfname,instance.cnffiles)
+ end
+end
+
+local function load_cnf_file(fname)
+ fname = resolvers.clean_path(fname)
+ local lname = file.replacesuffix(fname,'lua')
+ local f = io.open(lname)
+ if f then -- this will go
+ f:close()
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ resolvers.load_data(dname,'configuration',lname and file.basename(lname))
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ else
+ f = io.open(fname)
+ if f then
+ if trace_verbose then
+ logs.report("fileio","loading %s", fname)
+ end
+ local line, data, n, k, v
+ local dname = file.dirname(fname)
+ if not instance.configuration[dname] then
+ instance.configuration[dname] = { }
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ end
+ local data = instance.configuration[dname]
+ while true do
+ local line, n = f:read(), 0
+ if line then
+ while true do -- join lines
+ line, n = gsub(line,"\\%s*$", "")
+ if n > 0 then
+ line = line .. f:read()
+ else
+ break
+ end
+ end
+ if not find(line,"^[%%#]") then
+ local l = gsub(line,"%s*%%.*$","")
+ local k, v = match(l,"%s*(.-)%s*=%s*(.-)%s*$")
+ if k and v and not data[k] then
+ v = gsub(v,"[%%#].*",'')
+ data[k] = gsub(v,"~","$HOME")
+ instance.kpsevars[k] = true
+ end
+ end
+ else
+ break
+ end
+ end
+ f:close()
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s", fname)
+ end
+ end
+end
+
+local function collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
+ for _,c in ipairs(instance.order) do
+ for k,v in next, c do
+ if not instance.variables[k] then
+ if instance.environment[k] then
+ instance.variables[k] = instance.environment[k]
+ else
+ instance.kpsevars[k] = true
+ instance.variables[k] = resolvers.bare_variable(v)
+ end
+ end
+ end
+ end
+end
+
+function resolvers.load_cnf()
+ local function loadoldconfigdata()
+ for _, fname in ipairs(instance.cnffiles) do
+ load_cnf_file(fname)
+ end
+ end
+ -- instance.cnffiles contain complete names now !
+ if #instance.cnffiles == 0 then
+ if trace_verbose then
+ logs.report("fileio","no cnf files found (TEXMFCNF may not be set/known)")
+ end
+ else
+ instance.rootpath = instance.cnffiles[1]
+ for k,fname in ipairs(instance.cnffiles) do
+ instance.cnffiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadoldconfig(instance.cnffiles)
+ if instance.loaderror then
+ loadoldconfigdata()
+ resolvers.saveoldconfig()
+ end
+ else
+ loadoldconfigdata()
+ if instance.renewcache then
+ resolvers.saveoldconfig()
+ end
+ end
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+function resolvers.load_lua()
+ if #instance.luafiles == 0 then
+ -- yet harmless
+ else
+ instance.rootpath = instance.luafiles[1]
+ for k,fname in ipairs(instance.luafiles) do
+ instance.luafiles[k] = file.collapse_path(gsub(fname,"\\",'/'))
+ end
+ for i=1,3 do
+ instance.rootpath = file.dirname(instance.rootpath)
+ end
+ instance.rootpath = file.collapse_path(instance.rootpath)
+ resolvers.loadnewconfig()
+ collapse_cnf_data()
+ end
+ check_configuration()
+end
+
+-- database loading
+
+function resolvers.load_hash()
+ resolvers.locatelists()
+ if instance.diskcache and not instance.renewcache then
+ resolvers.loadfiles()
+ if instance.loaderror then
+ resolvers.loadlists()
+ resolvers.savefiles()
+ end
+ else
+ resolvers.loadlists()
+ if instance.renewcache then
+ resolvers.savefiles()
+ end
+ end
+end
+
+function resolvers.append_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash append: %s",tag)
+ end
+ insert(instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.prepend_hash(type,tag,name)
+ if trace_locating then
+ logs.report("fileio","= hash prepend: %s",tag)
+ end
+ insert(instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
+end
+
+function resolvers.extend_texmf_var(specification) -- crap, we could better prepend the hash
+-- local t = resolvers.expanded_path_list('TEXMF') -- full expansion
+ local t = resolvers.split_path(resolvers.env('TEXMF'))
+ insert(t,1,specification)
+ local newspec = concat(t,";")
+ if instance.environment["TEXMF"] then
+ instance.environment["TEXMF"] = newspec
+ elseif instance.variables["TEXMF"] then
+ instance.variables["TEXMF"] = newspec
+ else
+ -- weird
+ end
+ resolvers.expand_variables()
+ reset_hashes()
+end
+
+-- locators
+
+function resolvers.locatelists()
+ for _, path in ipairs(resolvers.clean_path_list('TEXMF')) do
+ if trace_verbose then
+ logs.report("fileio","locating list of %s",path)
+ end
+ resolvers.locatedatabase(file.collapse_path(path))
+ end
+end
+
+function resolvers.locatedatabase(specification)
+ return resolvers.methodhandler('locators', specification)
+end
+
+function resolvers.locators.tex(specification)
+ if specification and specification ~= '' and lfs.isdir(specification) then
+ if trace_locating then
+ logs.report("fileio",'! tex locator found: %s',specification)
+ end
+ resolvers.append_hash('file',specification,filename)
+ elseif trace_locating then
+ logs.report("fileio",'? tex locator not found: %s',specification)
+ end
+end
+
+-- hashers
+
+function resolvers.hashdatabase(tag,name)
+ return resolvers.methodhandler('hashers',tag,name)
+end
+
+function resolvers.loadfiles()
+ instance.loaderror = false
+ instance.files = { }
+ if not instance.renewcache then
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.hashdatabase(hash.tag,hash.name)
+ if instance.loaderror then break end
+ end
+ end
+end
+
+function resolvers.hashers.tex(tag,name)
+ resolvers.load_data(tag,'files')
+end
+
+-- generators:
+
+function resolvers.loadlists()
+ for _, hash in ipairs(instance.hashes) do
+ resolvers.generatedatabase(hash.tag)
+ end
+end
+
+function resolvers.generatedatabase(specification)
+ return resolvers.methodhandler('generators', specification)
+end
+
+-- starting with . or .. etc or funny char
+
+local weird = lpeg.P(".")^1 + lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
+
+function resolvers.generators.tex(specification)
+ local tag = specification
+ if trace_verbose then
+ logs.report("fileio","scanning path %s",specification)
+ end
+ instance.files[tag] = { }
+ local files = instance.files[tag]
+ local n, m, r = 0, 0, 0
+ local spec = specification .. '/'
+ local attributes = lfs.attributes
+ local directory = lfs.dir
+ local function action(path)
+ local full
+ if path then
+ full = spec .. path .. '/'
+ else
+ full = spec
+ end
+ for name in directory(full) do
+ if not weird:match(name) then
+ local mode = attributes(full..name,'mode')
+ if mode == 'file' then
+ if path then
+ n = n + 1
+ local f = files[name]
+ if f then
+ if type(f) == 'string' then
+ files[name] = { f, path }
+ else
+ f[#f+1] = path
+ end
+ else -- probably unique anyway
+ files[name] = path
+ local lower = lower(name)
+ if name ~= lower then
+ files["remap:"..lower] = name
+ r = r + 1
+ end
+ end
+ end
+ elseif mode == 'directory' then
+ m = m + 1
+ if path then
+ action(path..'/'..name)
+ else
+ action(name)
+ end
+ end
+ end
+ end
+ end
+ action()
+ if trace_verbose then
+ logs.report("fileio","%s files found on %s directories with %s uppercase remappings",n,m,r)
+ end
+end
+
+-- savers, todo
+
+function resolvers.savefiles()
+ resolvers.save_data('files')
+end
+
+-- A config (optionally) has the paths split in tables. Internally
+-- we join them and split them after the expansion has taken place. This
+-- is more convenient.
+
+function resolvers.splitconfig()
+ for i,c in ipairs(instance) do
+ for k,v in pairs(c) do
+ if type(v) == 'string' then
+ local t = file.split_path(v)
+ if #t > 1 then
+ c[k] = t
+ end
+ end
+ end
+ end
+end
+
+function resolvers.joinconfig()
+ for i,c in ipairs(instance.order) do
+ for k,v in pairs(c) do -- ipairs?
+ if type(v) == 'table' then
+ c[k] = file.join_path(v)
+ end
+ end
+ end
+end
+function resolvers.split_path(str)
+ if type(str) == 'table' then
+ return str
+ else
+ return file.split_path(str)
+ end
+end
+function resolvers.join_path(str)
+ if type(str) == 'table' then
+ return file.join_path(str)
+ else
+ return str
+ end
+end
+
+function resolvers.splitexpansions()
+ local ie = instance.expansions
+ for k,v in next, ie do
+ local t, h = { }, { }
+ for _,vv in ipairs(file.split_path(v)) do
+ if vv ~= "" and not h[vv] then
+ t[#t+1] = vv
+ h[vv] = true
+ end
+ end
+ if #t > 1 then
+ ie[k] = t
+ else
+ ie[k] = t[1]
+ end
+ end
+end
+
+-- end of split/join code
+
+function resolvers.saveoldconfig()
+ resolvers.splitconfig()
+ resolvers.save_data('configuration')
+ resolvers.joinconfig()
+end
+
+resolvers.configbanner = [[
+-- This is a Luatex configuration file created by 'luatools.lua' or
+-- 'luatex.exe' directly. For comment, suggestions and questions you can
+-- contact the ConTeXt Development Team. This configuration file is
+-- not copyrighted. [HH & TH]
+]]
+
+function resolvers.serialize(files)
+ -- This version is somewhat optimized for the kind of
+ -- tables that we deal with, so it's much faster than
+ -- the generic serializer. This makes sense because
+ -- luatools and mtxtools are called frequently. Okay,
+ -- we pay a small price for properly tabbed tables.
+ local t = { }
+ local function dump(k,v,m) -- could be moved inline
+ if type(v) == 'string' then
+ return m .. "['" .. k .. "']='" .. v .. "',"
+ elseif #v == 1 then
+ return m .. "['" .. k .. "']='" .. v[1] .. "',"
+ else
+ return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
+ end
+ end
+ t[#t+1] = "return {"
+ if instance.sortdata then
+ for _, k in pairs(sortedkeys(files)) do -- ipairs
+ local fk = files[k]
+ if type(fk) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for _, kk in pairs(sortedkeys(fk)) do -- ipairs
+ t[#t+1] = dump(kk,fk[kk],"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,fk,"\t")
+ end
+ end
+ else
+ for k, v in next, files do
+ if type(v) == 'table' then
+ t[#t+1] = "\t['" .. k .. "']={"
+ for kk,vv in next, v do
+ t[#t+1] = dump(kk,vv,"\t\t")
+ end
+ t[#t+1] = "\t},"
+ else
+ t[#t+1] = dump(k,v,"\t")
+ end
+ end
+ end
+ t[#t+1] = "}"
+ return concat(t,"\n")
+end
+
+function resolvers.save_data(dataname, makename) -- untested without cache overload
+ for cachename, files in next, instance[dataname] do
+ local name = (makename or file.join)(cachename,dataname)
+ local luaname, lucname = name .. ".lua", name .. ".luc"
+ if trace_verbose then
+ logs.report("fileio","preparing %s for %s",dataname,cachename)
+ end
+ for k, v in next, files do
+ if type(v) == "table" and #v == 1 then
+ files[k] = v[1]
+ end
+ end
+ local data = {
+ type = dataname,
+ root = cachename,
+ version = resolvers.cacheversion,
+ date = os.date("%Y-%m-%d"),
+ time = os.date("%H:%M:%S"),
+ content = files,
+ }
+ local ok = io.savedata(luaname,resolvers.serialize(data))
+ if ok then
+ if trace_verbose then
+ logs.report("fileio","%s saved in %s",dataname,luaname)
+ end
+ if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
+ if trace_verbose then
+ logs.report("fileio","%s compiled to %s",dataname,lucname)
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","compiling failed for %s, deleting file %s",dataname,lucname)
+ end
+ os.remove(lucname)
+ end
+ elseif trace_verbose then
+ logs.report("fileio","unable to save %s in %s (access error)",dataname,luaname)
+ end
+ end
+end
+
+function resolvers.load_data(pathname,dataname,filename,makename) -- untested without cache overload
+ filename = ((not filename or (filename == "")) and dataname) or filename
+ filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
+ local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
+ if blob then
+ local data = blob()
+ if data and data.content and data.type == dataname and data.version == resolvers.cacheversion then
+ if trace_verbose then
+ logs.report("fileio","loading %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = data.content
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+ instance[dataname][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping %s for %s from %s",dataname,pathname,filename)
+ end
+end
+
+-- some day i'll use the nested approach, but not yet (actually we even drop
+-- engine/progname support since we have only luatex now)
+--
+-- first texmfcnf.lua files are located, next the cached texmf.cnf files
+--
+-- return {
+-- TEXMFBOGUS = 'effe checken of dit werkt',
+-- }
+
+function resolvers.resetconfig()
+ identify_own()
+ instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
+end
+
+function resolvers.loadnewconfig()
+ for _, cnf in ipairs(instance.luafiles) do
+ local pathname = file.dirname(cnf)
+ local filename = file.join(pathname,resolvers.luaname)
+ local blob = loadfile(filename)
+ if blob then
+ local data = blob()
+ if data then
+ if trace_verbose then
+ logs.report("fileio","loading configuration file %s",filename)
+ end
+ if true then
+ -- flatten to variable.progname
+ local t = { }
+ for k, v in next, data do -- v = progname
+ if type(v) == "string" then
+ t[k] = v
+ else
+ for kk, vv in next, v do -- vv = variable
+ if type(vv) == "string" then
+ t[vv.."."..v] = kk
+ end
+ end
+ end
+ end
+ instance['setup'][pathname] = t
+ else
+ instance['setup'][pathname] = data
+ end
+ else
+ if trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance['setup'][pathname] = { }
+ instance.loaderror = true
+ end
+ elseif trace_verbose then
+ logs.report("fileio","skipping configuration file %s",filename)
+ end
+ instance.order[#instance.order+1] = instance.setup[pathname]
+ if instance.loaderror then break end
+ end
+end
+
+function resolvers.loadoldconfig()
+ if not instance.renewcache then
+ for _, cnf in ipairs(instance.cnffiles) do
+ local dname = file.dirname(cnf)
+ resolvers.load_data(dname,'configuration')
+ instance.order[#instance.order+1] = instance.configuration[dname]
+ if instance.loaderror then break end
+ end
+ end
+ resolvers.joinconfig()
+end
+
+function resolvers.expand_variables()
+ local expansions, environment, variables = { }, instance.environment, instance.variables
+ local env = resolvers.env
+ instance.expansions = expansions
+ if instance.engine ~= "" then environment['engine'] = instance.engine end
+ if instance.progname ~= "" then environment['progname'] = instance.progname end
+ for k,v in next, environment do
+ local a, b = match(k,"^(%a+)%_(.*)%s*$")
+ if a and b then
+ expansions[a..'.'..b] = v
+ else
+ expansions[k] = v
+ end
+ end
+ for k,v in next, environment do -- move environment to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ for k,v in next, variables do -- move variables to expansions
+ if not expansions[k] then expansions[k] = v end
+ end
+ local busy = false
+ local function resolve(a)
+ busy = true
+ return expansions[a] or env(a)
+ end
+ while true do
+ busy = false
+ for k,v in next, expansions do
+ local s, n = gsub(v,"%$([%a%d%_%-]+)",resolve)
+ local s, m = gsub(s,"%$%{([%a%d%_%-]+)%}",resolve)
+ if n > 0 or m > 0 then
+ expansions[k]= s
+ end
+ end
+ if not busy then break end
+ end
+ for k,v in next, expansions do
+ expansions[k] = gsub(v,"\\", '/')
+ end
+end
+
+function resolvers.variable(name)
+ return entry(instance.variables,name)
+end
+
+function resolvers.expansion(name)
+ return entry(instance.expansions,name)
+end
+
+function resolvers.is_variable(name)
+ return is_entry(instance.variables,name)
+end
+
+function resolvers.is_expansion(name)
+ return is_entry(instance.expansions,name)
+end
+
+function resolvers.unexpanded_path_list(str)
+ local pth = resolvers.variable(str)
+ local lst = resolvers.split_path(pth)
+ return expanded_path_from_list(lst)
+end
+
+function resolvers.unexpanded_path(str)
+ return file.join_path(resolvers.unexpanded_path_list(str))
+end
+
+do -- no longer needed
+
+ local done = { }
+
+ function resolvers.reset_extra_path()
+ local ep = instance.extra_paths
+ if not ep then
+ ep, done = { }, { }
+ instance.extra_paths = ep
+ elseif #ep > 0 then
+ instance.lists, done = { }, { }
+ end
+ end
+
+ function resolvers.register_extra_path(paths,subpaths)
+ local ep = instance.extra_paths or { }
+ local n = #ep
+ if paths and paths ~= "" then
+ if subpaths and subpaths ~= "" then
+ for p in gmatch(paths,"[^,]+") do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = p .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ else
+ for p in gmatch(paths,"[^,]+") do
+ if not done[p] then
+ ep[#ep+1] = resolvers.clean_path(p)
+ done[p] = true
+ end
+ end
+ end
+ elseif subpaths and subpaths ~= "" then
+ for i=1,n do
+ -- we gmatch each step again, not that fast, but used seldom
+ for s in gmatch(subpaths,"[^,]+") do
+ local ps = ep[i] .. "/" .. s
+ if not done[ps] then
+ ep[#ep+1] = resolvers.clean_path(ps)
+ done[ps] = true
+ end
+ end
+ end
+ end
+ if #ep > 0 then
+ instance.extra_paths = ep -- register paths
+ end
+ if #ep > n then
+ instance.lists = { } -- erase the cache
+ end
+ end
+
+end
+
+local function made_list(instance,list)
+ local ep = instance.extra_paths
+ if not ep or #ep == 0 then
+ return list
+ else
+ local done, new = { }, { }
+ -- honour . .. ../.. but only when at the start
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ if find(v,"^[%.%/]$") then
+ done[v] = true
+ new[#new+1] = v
+ else
+ break
+ end
+ end
+ end
+ -- first the extra paths
+ for k=1,#ep do
+ local v = ep[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ -- next the formal paths
+ for k=1,#list do
+ local v = list[k]
+ if not done[v] then
+ done[v] = true
+ new[#new+1] = v
+ end
+ end
+ return new
+ end
+end
+
+function resolvers.clean_path_list(str)
+ local t = resolvers.expanded_path_list(str)
+ if t then
+ for i=1,#t do
+ t[i] = file.collapse_path(resolvers.clean_path(t[i]))
+ end
+ end
+ return t
+end
+
+function resolvers.expand_path(str)
+ return file.join_path(resolvers.expanded_path_list(str))
+end
+
+function resolvers.expanded_path_list(str)
+ if not str then
+ return ep or { }
+ elseif instance.savelists then
+ -- engine+progname hash
+ str = gsub(str,"%$","")
+ if not instance.lists[str] then -- cached
+ local lst = made_list(instance,resolvers.split_path(resolvers.expansion(str)))
+ instance.lists[str] = expanded_path_from_list(lst)
+ end
+ return instance.lists[str]
+ else
+ local lst = resolvers.split_path(resolvers.expansion(str))
+ return made_list(instance,expanded_path_from_list(lst))
+ end
+end
+
+function resolvers.expanded_path_list_from_var(str) -- brrr
+ local tmp = resolvers.var_of_format_or_suffix(gsub(str,"%$",""))
+ if tmp ~= "" then
+ return resolvers.expanded_path_list(str)
+ else
+ return resolvers.expanded_path_list(tmp)
+ end
+end
+
+function resolvers.expand_path_from_var(str)
+ return file.join_path(resolvers.expanded_path_list_from_var(str))
+end
+
+function resolvers.format_of_var(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+function resolvers.format_of_suffix(str)
+ return suffixmap[file.extname(str)] or 'tex'
+end
+
+function resolvers.variable_of_format(str)
+ return formats[str] or formats[alternatives[str]] or ''
+end
+
+function resolvers.var_of_format_or_suffix(str)
+ local v = formats[str]
+ if v then
+ return v
+ end
+ v = formats[alternatives[str]]
+ if v then
+ return v
+ end
+ v = suffixmap[file.extname(str)]
+ if v then
+ return formats[isf]
+ end
+ return ''
+end
+
+function resolvers.expand_braces(str) -- output variable and brace expansion of STRING
+ local ori = resolvers.variable(str)
+ local pth = expanded_path_from_list(resolvers.split_path(ori))
+ return file.join_path(pth)
+end
+
+resolvers.isreadable = { }
+
+function resolvers.isreadable.file(name)
+ local readable = lfs.isfile(name) -- brrr
+ if trace_detail then
+ if readable then
+ logs.report("fileio","+ readable: %s",name)
+ else
+ logs.report("fileio","- readable: %s", name)
+ end
+ end
+ return readable
+end
+
+resolvers.isreadable.tex = resolvers.isreadable.file
+
+-- name
+-- name/name
+
+local function collect_files(names)
+ local filelist = { }
+ for k=1,#names do
+ local fname = names[k]
+ if trace_detail then
+ logs.report("fileio","? blobpath asked: %s",fname)
+ end
+ local bname = file.basename(fname)
+ local dname = file.dirname(fname)
+ if dname == "" or find(dname,"^%.") then
+ dname = false
+ else
+ dname = "/" .. dname .. "$"
+ end
+ local hashes = instance.hashes
+ for h=1,#hashes do
+ local hash = hashes[h]
+ local blobpath = hash.tag
+ local files = blobpath and instance.files[blobpath]
+ if files then
+ if trace_detail then
+ logs.report("fileio",'? blobpath do: %s (%s)',blobpath,bname)
+ end
+ local blobfile = files[bname]
+ if not blobfile then
+ local rname = "remap:"..bname
+ blobfile = files[rname]
+ if blobfile then
+ bname = files[rname]
+ blobfile = files[bname]
+ end
+ end
+ if blobfile then
+ if type(blobfile) == 'string' then
+ if not dname or find(blobfile,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,blobfile,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,blobfile,bname) -- result
+ }
+ end
+ else
+ for kk=1,#blobfile do
+ local vv = blobfile[kk]
+ if not dname or find(vv,dname) then
+ filelist[#filelist+1] = {
+ hash.type,
+ file.join(blobpath,vv,bname), -- search
+ resolvers.concatinators[hash.type](blobpath,vv,bname) -- result
+ }
+ end
+ end
+ end
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! blobpath no: %s (%s)',blobpath,bname)
+ end
+ end
+ end
+ if #filelist > 0 then
+ return filelist
+ else
+ return nil
+ end
+end
+
+function resolvers.suffix_of_format(str)
+ if suffixes[str] then
+ return suffixes[str][1]
+ else
+ return ""
+ end
+end
+
+function resolvers.suffixes_of_format(str)
+ if suffixes[str] then
+ return suffixes[str]
+ else
+ return {}
+ end
+end
+
+function resolvers.register_in_trees(name)
+ if not find(name,"^%.") then
+ instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
+ end
+end
+
+-- split the next one up for readability (bu this module needs a cleanup anyway)
+
+local function can_be_dir(name) -- can become local
+ local fakepaths = instance.fakepaths
+ if not fakepaths[name] then
+ if lfs.isdir(name) then
+ fakepaths[name] = 1 -- directory
+ else
+ fakepaths[name] = 2 -- no directory
+ end
+ end
+ return (fakepaths[name] == 1)
+end
+
+local function collect_instance_files(filename,collected) -- todo : plugin (scanners, checkers etc)
+ local result = collected or { }
+ local stamp = nil
+ filename = file.collapse_path(filename) -- elsewhere
+ filename = file.collapse_path(gsub(filename,"\\","/")) -- elsewhere
+ -- speed up / beware: format problem
+ if instance.remember then
+ stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
+ if instance.found[stamp] then
+ if trace_locating then
+ logs.report("fileio",'! remembered: %s',filename)
+ end
+ return instance.found[stamp]
+ end
+ end
+ if not dangerous[instance.format or "?"] then
+ if resolvers.isreadable.file(filename) then
+ if trace_detail then
+ logs.report("fileio",'= found directly: %s',filename)
+ end
+ instance.found[stamp] = { filename }
+ return { filename }
+ end
+ end
+ if find(filename,'%*') then
+ if trace_locating then
+ logs.report("fileio",'! wildcard: %s', filename)
+ end
+ result = resolvers.find_wildcard_files(filename)
+ elseif file.is_qualified_path(filename) then
+ if resolvers.isreadable.file(filename) then
+ if trace_locating then
+ logs.report("fileio",'! qualified: %s', filename)
+ end
+ result = { filename }
+ else
+ local forcedname, ok, suffix = "", false, file.extname(filename)
+ if suffix == "" then -- why
+ if instance.format == "" then
+ forcedname = filename .. ".tex"
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing standard filetype: tex')
+ end
+ result, ok = { forcedname }, true
+ end
+ else
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ forcedname = filename .. "." .. s
+ if resolvers.isreadable.file(forcedname) then
+ if trace_locating then
+ logs.report("fileio",'! no suffix, forcing format filetype: %s', s)
+ end
+ result, ok = { forcedname }, true
+ break
+ end
+ end
+ end
+ end
+ if not ok and suffix ~= "" then
+ -- try to find in tree (no suffix manipulation), here we search for the
+ -- matching last part of the name
+ local basename = file.basename(filename)
+ local pattern = (filename .. "$"):gsub("([%.%-])","%%%1")
+ local savedformat = instance.format
+ local format = savedformat or ""
+ if format == "" then
+ instance.format = resolvers.format_of_suffix(suffix)
+ end
+ if not format then
+ instance.format = "othertextfiles" -- kind of everything, maybe texinput is better
+ end
+ --
+ local resolved = collect_instance_files(basename)
+ if #result == 0 then
+ local lowered = lower(basename)
+ if filename ~= lowered then
+ resolved = collect_instance_files(lowered)
+ end
+ end
+ resolvers.format = savedformat
+ --
+ for r=1,#resolved do
+ local rr = resolved[r]
+ if rr:find(pattern) then
+ result[#result+1], ok = rr, true
+ end
+ end
+ -- a real wildcard:
+ --
+ -- if not ok then
+ -- local filelist = collect_files({basename})
+ -- for f=1,#filelist do
+ -- local ff = filelist[f][3] or ""
+ -- if ff:find(pattern) then
+ -- result[#result+1], ok = ff, true
+ -- end
+ -- end
+ -- end
+ end
+ if not ok and trace_locating then
+ logs.report("fileio",'? qualified: %s', filename)
+ end
+ end
+ else
+ -- search spec
+ local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
+ if ext == "" then
+ if not instance.force_suffixes then
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ else
+ wantedfiles[#wantedfiles+1] = filename
+ end
+ if instance.format == "" then
+ if ext == "" then
+ local forcedname = filename .. '.tex'
+ wantedfiles[#wantedfiles+1] = forcedname
+ filetype = resolvers.format_of_suffix(forcedname)
+ if trace_locating then
+ logs.report("fileio",'! forcing filetype: %s',filetype)
+ end
+ else
+ filetype = resolvers.format_of_suffix(filename)
+ if trace_locating then
+ logs.report("fileio",'! using suffix based filetype: %s',filetype)
+ end
+ end
+ else
+ if ext == "" then
+ local suffixes = resolvers.suffixes_of_format(instance.format)
+ for _, s in next, suffixes do
+ wantedfiles[#wantedfiles+1] = filename .. "." .. s
+ end
+ end
+ filetype = instance.format
+ if trace_locating then
+ logs.report("fileio",'! using given filetype: %s',filetype)
+ end
+ end
+ local typespec = resolvers.variable_of_format(filetype)
+ local pathlist = resolvers.expanded_path_list(typespec)
+ if not pathlist or #pathlist == 0 then
+ -- no pathlist, access check only / todo == wildcard
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ logs.report("fileio",'? filetype: %s',filetype or '?')
+ logs.report("fileio",'? wanted files: %s',concat(wantedfiles," | "))
+ end
+ for k=1,#wantedfiles do
+ local fname = wantedfiles[k]
+ if fname and resolvers.isreadable.file(fname) then
+ filename, done = fname, true
+ result[#result+1] = file.join('.',fname)
+ break
+ end
+ end
+ -- this is actually 'other text files' or 'any' or 'whatever'
+ local filelist = collect_files(wantedfiles)
+ local fl = filelist and filelist[1]
+ if fl then
+ filename = fl[3]
+ result[#result+1] = filename
+ done = true
+ end
+ else
+ -- list search
+ local filelist = collect_files(wantedfiles)
+ local doscan, recurse
+ if trace_detail then
+ logs.report("fileio",'? filename: %s',filename)
+ end
+ -- a bit messy ... esp the doscan setting here
+ for k=1,#pathlist do
+ local path = pathlist[k]
+ if find(path,"^!!") then doscan = false else doscan = true end
+ if find(path,"//$") then recurse = true else recurse = false end
+ local pathname = gsub(path,"^!+", '')
+ done = false
+ -- using file list
+ if filelist and not (done and not instance.allresults) and recurse then
+ -- compare list entries with permitted pattern
+ pathname = gsub(pathname,"([%-%.])","%%%1") -- this also influences
+ pathname = gsub(pathname,"/+$", '/.*') -- later usage of pathname
+ pathname = gsub(pathname,"//", '/.-/') -- not ok for /// but harmless
+ local expr = "^" .. pathname
+ for k=1,#filelist do
+ local fl = filelist[k]
+ local f = fl[2]
+ if find(f,expr) then
+ if trace_detail then
+ logs.report("fileio",'= found in hash: %s',f)
+ end
+ --- todo, test for readable
+ result[#result+1] = fl[3]
+ resolvers.register_in_trees(f) -- for tracing used files
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ end
+ if not done and doscan then
+ -- check if on disk / unchecked / does not work at all / also zips
+ if resolvers.splitmethod(pathname).scheme == 'file' then -- ?
+ local pname = gsub(pathname,"%.%*$",'')
+ if not find(pname,"%*") then
+ local ppname = gsub(pname,"/+$","")
+ if can_be_dir(ppname) then
+ for k=1,#wantedfiles do
+ local w = wantedfiles[k]
+ local fname = file.join(ppname,w)
+ if resolvers.isreadable.file(fname) then
+ if trace_detail then
+ logs.report("fileio",'= found by scanning: %s',fname)
+ end
+ result[#result+1] = fname
+ done = true
+ if not instance.allresults then break end
+ end
+ end
+ else
+ -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
+ end
+ end
+ end
+ end
+ if not done and doscan then
+ -- todo: slow path scanning
+ end
+ if done and not instance.allresults then break end
+ end
+ end
+ end
+ for k=1,#result do
+ result[k] = file.collapse_path(result[k])
+ end
+ if instance.remember then
+ instance.found[stamp] = result
+ end
+ return result
+end
+
+if not resolvers.concatinators then resolvers.concatinators = { } end
+
+resolvers.concatinators.tex = file.join
+resolvers.concatinators.file = resolvers.concatinators.tex
+
+function resolvers.find_files(filename,filetype,mustexist)
+ if type(mustexist) == boolean then
+ -- all set
+ elseif type(filetype) == 'boolean' then
+ filetype, mustexist = nil, false
+ elseif type(filetype) ~= 'string' then
+ filetype, mustexist = nil, false
+ end
+ instance.format = filetype or ''
+ local result = collect_instance_files(filename)
+ if #result == 0 then
+ local lowered = lower(filename)
+ if filename ~= lowered then
+ return collect_instance_files(lowered)
+ end
+ end
+ instance.format = ''
+ return result
+end
+
+function resolvers.find_file(filename,filetype,mustexist)
+ return (resolvers.find_files(filename,filetype,mustexist)[1] or "")
+end
+
+function resolvers.find_given_files(filename)
+ local bname, result = file.basename(filename), { }
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local files = instance.files[hash.tag]
+ local blist = files[bname]
+ if not blist then
+ local rname = "remap:"..bname
+ blist = files[rname]
+ if blist then
+ bname = files[rname]
+ blist = files[bname]
+ end
+ end
+ if blist then
+ if type(blist) == 'string' then
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,blist,bname) or ""
+ if not instance.allresults then break end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ result[#result+1] = resolvers.concatinators[hash.type](hash.tag,vv,bname) or ""
+ if not instance.allresults then break end
+ end
+ end
+ end
+ end
+ return result
+end
+
+function resolvers.find_given_file(filename)
+ return (resolvers.find_given_files(filename)[1] or "")
+end
+
+local function doit(path,blist,bname,tag,kind,result,allresults)
+ local done = false
+ if blist and kind then
+ if type(blist) == 'string' then
+ -- make function and share code
+ if find(lower(blist),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,blist,bname) or ""
+ done = true
+ end
+ else
+ for kk=1,#blist do
+ local vv = blist[kk]
+ if find(lower(vv),path) then
+ result[#result+1] = resolvers.concatinators[kind](tag,vv,bname) or ""
+ done = true
+ if not allresults then break end
+ end
+ end
+ end
+ end
+ return done
+end
+
+function resolvers.find_wildcard_files(filename) -- todo: remap:
+ local result = { }
+ local bname, dname = file.basename(filename), file.dirname(filename)
+ local path = gsub(dname,"^*/","")
+ path = gsub(path,"*",".*")
+ path = gsub(path,"-","%%-")
+ if dname == "" then
+ path = ".*"
+ end
+ local name = bname
+ name = gsub(name,"*",".*")
+ name = gsub(name,"-","%%-")
+ path = lower(path)
+ name = lower(name)
+ local files, allresults, done = instance.files, instance.allresults, false
+ if find(name,"%*") then
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ for kk, hh in next, files[hash.tag] do
+ if not find(kk,"^remap:") then
+ if find(lower(kk),name) then
+ if doit(path,hh,kk,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ end
+ end
+ else
+ local hashes = instance.hashes
+ for k=1,#hashes do
+ local hash = hashes[k]
+ local tag, kind = hash.tag, hash.type
+ if doit(path,files[tag][bname],bname,tag,kind,result,allresults) then done = true end
+ if done and not allresults then break end
+ end
+ end
+ -- we can consider also searching the paths not in the database, but then
+ -- we end up with a messy search (all // in all path specs)
+ return result
+end
+
+function resolvers.find_wildcard_file(filename)
+ return (resolvers.find_wildcard_files(filename)[1] or "")
+end
+
+-- main user functions
+
+function resolvers.automount()
+ -- implemented later
+end
+
+function resolvers.load(option)
+ statistics.starttiming(instance)
+ resolvers.resetconfig()
+ resolvers.identify_cnf()
+ resolvers.load_lua()
+ resolvers.expand_variables()
+ resolvers.load_cnf()
+ resolvers.expand_variables()
+ if option ~= "nofiles" then
+ resolvers.load_hash()
+ resolvers.automount()
+ end
+ statistics.stoptiming(instance)
+end
+
+function resolvers.for_files(command, files, filetype, mustexist)
+ if files and #files > 0 then
+ local function report(str)
+ if trace_verbose then
+ logs.report("fileio",str) -- has already verbose
+ else
+ print(str)
+ end
+ end
+ if trace_verbose then
+ report('')
+ end
+ for _, file in ipairs(files) do
+ local result = command(file,filetype,mustexist)
+ if type(result) == 'string' then
+ report(result)
+ else
+ for _,v in ipairs(result) do
+ report(v)
+ end
+ end
+ end
+ end
+end
+
+-- strtab
+
+resolvers.var_value = resolvers.variable -- output the value of variable $STRING.
+resolvers.expand_var = resolvers.expansion -- output variable expansion of STRING.
+
+function resolvers.show_path(str) -- output search path for file type NAME
+ return file.join_path(resolvers.expanded_path_list(resolvers.format_of_var(str)))
+end
+
+-- resolvers.find_file(filename)
+-- resolvers.find_file(filename, filetype, mustexist)
+-- resolvers.find_file(filename, mustexist)
+-- resolvers.find_file(filename, filetype)
+
+function resolvers.register_file(files, name, path)
+ if files[name] then
+ if type(files[name]) == 'string' then
+ files[name] = { files[name], path }
+ else
+ files[name] = path
+ end
+ else
+ files[name] = path
+ end
+end
+
+function resolvers.splitmethod(filename)
+ if not filename then
+ return { } -- safeguard
+ elseif type(filename) == "table" then
+ return filename -- already split
+ elseif not find(filename,"://") then
+ return { scheme="file", path = filename, original=filename } -- quick hack
+ else
+ return url.hashed(filename)
+ end
+end
+
+function table.sequenced(t,sep) -- temp here
+ local s = { }
+ for k, v in pairs(t) do -- pairs?
+ s[#s+1] = k .. "=" .. v
+ end
+ return concat(s, sep or " | ")
+end
+
+function resolvers.methodhandler(what, filename, filetype) -- ...
+ local specification = (type(filename) == "string" and resolvers.splitmethod(filename)) or filename -- no or { }, let it bomb
+ local scheme = specification.scheme
+ if resolvers[what][scheme] then
+ if trace_locating then
+ logs.report("fileio",'= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
+ end
+ return resolvers[what][scheme](filename,filetype) -- todo: specification
+ else
+ return resolvers[what].tex(filename,filetype) -- todo: specification
+ end
+end
+
+function resolvers.clean_path(str)
+ if str then
+ str = gsub(str,"\\","/")
+ str = gsub(str,"^!+","")
+ str = gsub(str,"^~",resolvers.homedir)
+ return str
+ else
+ return nil
+ end
+end
+
+function resolvers.do_with_path(name,func)
+ for _, v in pairs(resolvers.expanded_path_list(name)) do -- pairs?
+ func("^"..resolvers.clean_path(v))
+ end
+end
+
+function resolvers.do_with_var(name,func)
+ func(expanded_var(name))
+end
+
+function resolvers.with_files(pattern,handle)
+ for _, hash in ipairs(instance.hashes) do
+ local blobpath = hash.tag
+ local blobtype = hash.type
+ if blobpath then
+ local files = instance.files[blobpath]
+ if files then
+ for k,v in next, files do
+ if find(k,"^remap:") then
+ k = files[k]
+ v = files[k] -- chained
+ end
+ if find(k,pattern) then
+ if type(v) == "string" then
+ handle(blobtype,blobpath,v,k)
+ else
+ for _,vv in pairs(v) do -- ipairs?
+ handle(blobtype,blobpath,vv,k)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function resolvers.locate_format(name)
+ local barename, fmtname = name:gsub("%.%a+$",""), ""
+ if resolvers.usecache then
+ local path = file.join(caches.setpath("formats")) -- maybe platform
+ fmtname = file.join(path,barename..".fmt") or ""
+ end
+ if fmtname == "" then
+ fmtname = resolvers.find_files(barename..".fmt")[1] or ""
+ end
+ fmtname = resolvers.clean_path(fmtname)
+ if fmtname ~= "" then
+ local barename = file.removesuffix(fmtname)
+ local luaname, lucname, luiname = barename .. ".lua", barename .. ".luc", barename .. ".lui"
+ if lfs.isfile(luiname) then
+ return barename, luiname
+ elseif lfs.isfile(lucname) then
+ return barename, lucname
+ elseif lfs.isfile(luaname) then
+ return barename, luaname
+ end
+ end
+ return nil, nil
+end
+
+function resolvers.boolean_variable(str,default)
+ local b = resolvers.expansion(str)
+ if b == "" then
+ return default
+ else
+ b = toboolean(b)
+ return (b == nil and default) or b
+ end
+end
+
+texconfig.kpse_init = false
+
+kpse = { original = kpse } setmetatable(kpse, { __index = function(k,v) return resolvers[v] end } )
+
+-- for a while
+
+input = resolvers
diff --git a/tex/context/base/data-tex.lua b/tex/context/base/data-tex.lua
new file mode 100644
index 000000000..792c48fec
--- /dev/null
+++ b/tex/context/base/data-tex.lua
@@ -0,0 +1,220 @@
+if not modules then modules = { } end modules ['data-tex'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- special functions that deal with io
+
+local format, lower = string.format, string.lower
+
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v end)
+
+local texiowrite_nl = (texio and texio.write_nl) or print
+local texiowrite = (texio and texio.write) or print
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+function finders.generic(tag,filename,filetype)
+ local foundname = resolvers.find_file(filename,filetype)
+ if foundname and foundname ~= "" then
+ if trace_locating then
+ logs.report("fileio",'+ finder: %s, file: %s', tag,filename)
+ end
+ return foundname
+ else
+ if trace_locating then
+ logs.report("fileio",'- finder: %s, file: %s', tag,filename)
+ end
+ return unpack(finders.notfound)
+ end
+end
+
+--~ local getlines = lpeg.Ct(lpeg.linebyline)
+
+local input_translator, utf_translator, user_translator = nil, nil, nil
+
+function resolvers.install_text_filter(name,func)
+ if name == "input" then input_translator = func
+ elseif name == "utf" then utf_translator = func
+ elseif name == "user" then user_translator = func end
+end
+
+function openers.text_opener(filename,file_handle,tag)
+ local u = unicode.utftype(file_handle)
+ local t = { }
+ if u > 0 then
+ if trace_locating then
+ logs.report("fileio",'+ opener: %s (%s), file: %s',tag,unicode.utfname[u],filename)
+ end
+ local l
+ if u > 2 then
+ l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
+ else
+ l = unicode.utf16_to_utf8(file_handle:read("*a"),u==2)
+ end
+ file_handle:close()
+ t = {
+ utftype = u, -- may go away
+ lines = l,
+ current = 0, -- line number, not really needed
+ handle = nil,
+ noflines = #l,
+ close = function()
+ if trace_locating then
+ logs.report("fileio",'= closer: %s (%s), file: %s',tag,unicode.utfname[u],filename)
+ end
+ logs.show_close(filename)
+ t = nil
+ end,
+ reader = function(self)
+ self = self or t
+ local current, lines = self.current, self.lines
+ if current >= #lines then
+ return nil
+ else
+ current = current + 1
+ self.current = current
+ local line = lines[current]
+ if not line then
+ return nil
+ elseif line == "" then
+ return ""
+ else
+ if input_translator then
+ line = input_translator(line)
+ end
+ if utf_translator then
+ line = utf_translator(line)
+ end
+ if user_translator then
+ line = user_translator(line)
+ end
+ return line
+ end
+ end
+ end
+ }
+ else
+ if trace_locating then
+ logs.report("fileio",'+ opener: %s, file: %s',tag,filename)
+ end
+ -- todo: file;name -> freeze / eerste regel scannen -> freeze
+ --~ local data = getlines:match(file_handle:read("*a"))
+ --~ local n = 0
+ t = {
+ reader = function() -- self
+ local line = file_handle:read()
+ --~ n = n + 1
+ --~ local line = data[n]
+ --~ print(line)
+ if not line then
+ return nil
+ elseif line == "" then
+ return ""
+ else
+ if input_translator then
+ line = input_translator(line)
+ end
+ if utf_translator then
+ line = utf_translator(line)
+ end
+ if user_translator then
+ line = user_translator(line)
+ end
+ return line
+ end
+ end,
+ close = function()
+ if trace_locating then
+ logs.report("fileio",'= closer: %s, file: %s',tag,filename)
+ end
+ logs.show_close(filename)
+ file_handle:close()
+ t = nil
+ end,
+ handle = function()
+ return file_handle
+ end,
+ noflines = function()
+ t.noflines = io.noflines(file_handle)
+ return t.noflines
+ end
+ }
+ end
+ return t
+end
+
+function openers.generic(tag,filename)
+ if filename and filename ~= "" then
+ local f = io.open(filename,"r")
+ if f then
+ logs.show_open(filename)
+ return openers.text_opener(filename,f,tag)
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- opener: %s, file: %s',tag,filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.generic(tag,filename)
+ if filename and filename ~= "" then
+ local f = io.open(filename,"rb")
+ if f then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio",'+ loader: %s, file: %s',tag,filename)
+ end
+ local s = f:read("*a")
+ if garbagecollector and garbagecollector.check then garbagecollector.check(#s) end
+ f:close()
+ if s then
+ return true, s, #s
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- loader: %s, file: %s',tag,filename)
+ end
+ return unpack(loaders.notfound)
+end
+
+function finders.tex(filename,filetype)
+ return finders.generic('tex',filename,filetype)
+end
+
+function openers.tex(filename)
+ return openers.generic('tex',filename)
+end
+
+function loaders.tex(filename)
+ return loaders.generic('tex',filename)
+end
+
+function resolvers.findtexfile(filename, filetype)
+ return resolvers.methodhandler('finders',file.collapse_path(filename), filetype)
+end
+
+function resolvers.opentexfile(filename)
+ return resolvers.methodhandler('openers',file.collapse_path(filename))
+end
+
+function resolvers.openfile(filename)
+ local fullname = resolvers.findtexfile(filename)
+ if fullname and (fullname ~= "") then
+ return resolvers.opentexfile(fullname)
+ else
+ return nil
+ end
+end
+
+function resolvers.texdatablob(filename, filetype)
+ local ok, data, size = resolvers.loadbinfile(filename, filetype)
+ return data or ""
+end
+
+resolvers.loadtexfile = resolvers.texdatablob
diff --git a/tex/context/base/data-tmf.lua b/tex/context/base/data-tmf.lua
new file mode 100644
index 000000000..302841a65
--- /dev/null
+++ b/tex/context/base/data-tmf.lua
@@ -0,0 +1,72 @@
+if not modules then modules = { } end modules ['data-tmf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- loads *.tmf files in minimal tree roots (to be optimized and documented)
+
+function resolvers.check_environment(tree)
+ logs.simpleline()
+ os.setenv('TMP', os.getenv('TMP') or os.getenv('TEMP') or os.getenv('TMPDIR') or os.getenv('HOME'))
+ os.setenv('TEXOS', os.getenv('TEXOS') or ("texmf-" .. os.currentplatform()))
+ os.setenv('TEXPATH', (tree or "tex"):gsub("\/+$",''))
+ os.setenv('TEXMFOS', os.getenv('TEXPATH') .. "/" .. os.getenv('TEXOS'))
+ logs.simpleline()
+ logs.simple("preset : TEXPATH => %s", os.getenv('TEXPATH'))
+ logs.simple("preset : TEXOS => %s", os.getenv('TEXOS'))
+ logs.simple("preset : TEXMFOS => %s", os.getenv('TEXMFOS'))
+ logs.simple("preset : TMP => %s", os.getenv('TMP'))
+ logs.simple('')
+end
+
+function resolvers.load_environment(name) -- todo: key=value as well as lua
+ local f = io.open(name)
+ if f then
+ for line in f:lines() do
+ if line:find("^[%%%#]") then
+ -- skip comment
+ else
+ local key, how, value = line:match("^(.-)%s*([<=>%?]+)%s*(.*)%s*$")
+ if how then
+ value = value:gsub("%%(.-)%%", function(v) return os.getenv(v) or "" end)
+ if how == "=" or how == "<<" then
+ os.setenv(key,value)
+ elseif how == "?" or how == "??" then
+ os.setenv(key,os.getenv(key) or value)
+ elseif how == "<" or how == "+=" then
+ if os.getenv(key) then
+ os.setenv(key,os.getenv(key) .. io.fileseparator .. value)
+ else
+ os.setenv(key,value)
+ end
+ elseif how == ">" or how == "=+" then
+ if os.getenv(key) then
+ os.setenv(key,value .. io.pathseparator .. os.getenv(key))
+ else
+ os.setenv(key,value)
+ end
+ end
+ end
+ end
+ end
+ f:close()
+ end
+end
+
+function resolvers.load_tree(tree)
+ if tree and tree ~= "" then
+ local setuptex = 'setuptex.tmf'
+ if lfs.attributes(tree, "mode") == "directory" then -- check if not nil
+ setuptex = tree .. "/" .. setuptex
+ else
+ setuptex = tree
+ end
+ if io.exists(setuptex) then
+ resolvers.check_environment(tree)
+ resolvers.load_environment(setuptex)
+ end
+ end
+end
diff --git a/tex/context/base/data-tmp.lua b/tex/context/base/data-tmp.lua
new file mode 100644
index 000000000..31d0147ea
--- /dev/null
+++ b/tex/context/base/data-tmp.lua
@@ -0,0 +1,174 @@
+if not modules then modules = { } end modules ['data-tmp'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This module deals with caching data. It sets up the paths and
+implements loaders and savers for tables. Best is to set the
+following variable. When not set, the usual paths will be
+checked. Personally I prefer the (users) temporary path.</p>
+
+</code>
+TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
+</code>
+
+<p>Currently we do no locking when we write files. This is no real
+problem because most caching involves fonts and the chance of them
+being written at the same time is small. We also need to extend
+luatools with a recache feature.</p>
+--ldx]]--
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+
+caches = caches or { }
+
+caches.path = caches.path or nil
+caches.base = caches.base or "luatex-cache"
+caches.more = caches.more or "context"
+caches.direct = false -- true is faster but may need huge amounts of memory
+caches.tree = false
+caches.paths = caches.paths or nil
+caches.force = false
+caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
+
+function caches.temp()
+ local cachepath = nil
+ local function check(list,isenv)
+ if not cachepath then
+ for k=1,#list do
+ local v = list[k]
+ cachepath = (isenv and (os.env[v] or "")) or v or ""
+ if cachepath == "" then
+ -- next
+ else
+ cachepath = resolvers.clean_path(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
+ break
+ elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
+ dir.mkdirs(cachepath)
+ if lfs.isdir(cachepath) and file.iswritable(cachepath) then
+ break
+ end
+ end
+ end
+ cachepath = nil
+ end
+ end
+ end
+ check(resolvers.clean_path_list("TEXMFCACHE") or { })
+ check(caches.defaults,true)
+ if not cachepath then
+ print("\nfatal error: there is no valid (writable) cache path defined\n")
+ os.exit()
+ elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
+ print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
+ os.exit()
+ end
+ cachepath = file.collapse_path(cachepath)
+ function caches.temp()
+ return cachepath
+ end
+ return cachepath
+end
+
+function caches.configpath()
+ return table.concat(resolvers.instance.cnffiles,";")
+end
+
+function caches.hashed(tree)
+ return md5.hex(gsub(lower(tree),"[\\\/]+","/"))
+end
+
+function caches.treehash()
+ local tree = caches.configpath()
+ if not tree or tree == "" then
+ return false
+ else
+ return caches.hashed(tree)
+ end
+end
+
+function caches.setpath(...)
+ if not caches.path then
+ if not caches.path then
+ caches.path = caches.temp()
+ end
+ caches.path = resolvers.clean_path(caches.path) -- to be sure
+ caches.tree = caches.tree or caches.treehash()
+ if caches.tree then
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
+ else
+ caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
+ end
+ end
+ if not caches.path then
+ caches.path = '.'
+ end
+ caches.path = resolvers.clean_path(caches.path)
+ if not table.is_empty({...}) then
+ local pth = dir.mkdirs(caches.path,...)
+ return pth
+ end
+ caches.path = dir.expand_name(caches.path)
+ return caches.path
+end
+
+function caches.definepath(category,subcategory)
+ return function()
+ return caches.setpath(category,subcategory)
+ end
+end
+
+function caches.setluanames(path,name)
+ return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
+end
+
+function caches.loaddata(path,name)
+ local tmaname, tmcname = caches.setluanames(path,name)
+ local loader = loadfile(tmcname) or loadfile(tmaname)
+ if loader then
+ return loader()
+ else
+ return false
+ end
+end
+
+--~ function caches.loaddata(path,name)
+--~ local tmaname, tmcname = caches.setluanames(path,name)
+--~ return dofile(tmcname) or dofile(tmaname)
+--~ end
+
+function caches.iswritable(filepath,filename)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ return file.iswritable(tmaname)
+end
+
+function caches.savedata(filepath,filename,data,raw)
+ local tmaname, tmcname = caches.setluanames(filepath,filename)
+ local reduce, simplify = true, true
+ if raw then
+ reduce, simplify = false, false
+ end
+ if caches.direct then
+ file.savedata(tmaname, table.serialize(data,'return',false,true,false)) -- no hex
+ else
+ table.tofile(tmaname, data,'return',false,true,false) -- maybe not the last true
+ end
+ local cleanup = resolvers.boolean_variable("PURGECACHE", false)
+ local strip = resolvers.boolean_variable("LUACSTRIP", true)
+ utils.lua.compile(tmaname, tmcname, cleanup, strip)
+end
+
+-- here we use the cache for format loading (texconfig.[formatname|jobname])
+
+--~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
+if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and resolvers.instance then
+ if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
+ texconfig.formatname = caches.setpath("formats") .. "/" .. gsub(texconfig.luaname,"%.lu.$",".fmt")
+end
diff --git a/tex/context/base/data-tre.lua b/tex/context/base/data-tre.lua
new file mode 100644
index 000000000..9cac73b8e
--- /dev/null
+++ b/tex/context/base/data-tre.lua
@@ -0,0 +1,43 @@
+if not modules then modules = { } end modules ['data-tre'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- \input tree://oeps1/**/oeps.tex
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+
+local done, found = { }, { }
+
+function finders.tree(specification,filetype)
+ local fnd = found[specification]
+ if not fnd then
+ local spec = resolvers.splitmethod(specification).path or ""
+ if spec ~= "" then
+ local path, name = file.dirname(spec), file.basename(spec)
+ if path == "" then path = "." end
+ local hash = done[path]
+ if not hash then
+ local pattern = path .. "/*" -- we will use the proper splitter
+ hash = dir.glob(pattern)
+ done[path] = hash
+ end
+ local pattern = "/" .. name:gsub("([%.%-%+])", "%%%1") .. "$"
+ for k, v in pairs(hash) do
+ if v:find(pattern) then
+ found[specification] = v
+ return v
+ end
+ end
+ end
+ fnd = unpack(finders.notfound)
+ found[specification] = fnd
+ end
+ return fnd
+end
+
+openers.tree = openers.generic
+loaders.tree = loaders.generic
diff --git a/tex/context/base/data-use.lua b/tex/context/base/data-use.lua
new file mode 100644
index 000000000..609ffd88f
--- /dev/null
+++ b/tex/context/base/data-use.lua
@@ -0,0 +1,127 @@
+if not modules then modules = { } end modules ['data-use'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+-- since we want to use the cache instead of the tree, we will now
+-- reimplement the saver.
+
+local save_data = resolvers.save_data
+local load_data = resolvers.load_data
+
+resolvers.cachepath = nil -- public, for tracing
+resolvers.usecache = true -- public, for tracing
+
+function resolvers.save_data(dataname)
+ save_data(dataname, function(cachename,dataname)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(cachename))
+ else
+ return file.join(cachename,dataname)
+ end
+ end)
+end
+
+function resolvers.load_data(pathname,dataname,filename)
+ load_data(pathname,dataname,filename,function(dataname,filename)
+ resolvers.usecache = not toboolean(resolvers.expansion("CACHEINTDS") or "false",true)
+ if resolvers.usecache then
+ resolvers.cachepath = resolvers.cachepath or caches.definepath("trees")
+ return file.join(resolvers.cachepath(),caches.hashed(pathname))
+ else
+ if not filename or (filename == "") then
+ filename = dataname
+ end
+ return file.join(pathname,filename)
+ end
+ end)
+end
+
+-- we will make a better format, maybe something xml or just text or lua
+
+resolvers.automounted = resolvers.automounted or { }
+
+function resolvers.automount(usecache)
+ local mountpaths = resolvers.clean_path_list(resolvers.expansion('TEXMFMOUNT'))
+ if table.is_empty(mountpaths) and usecache then
+ mountpaths = { caches.setpath("mount") }
+ end
+ if not table.is_empty(mountpaths) then
+ statistics.starttiming(resolvers.instance)
+ for k, root in pairs(mountpaths) do
+ local f = io.open(root.."/url.tmi")
+ if f then
+ for line in f:lines() do
+ if line then
+ if line:find("^[%%#%-]") then -- or %W
+ -- skip
+ elseif line:find("^zip://") then
+ if trace_locating then
+ logs.report("fileio","mounting %s",line)
+ end
+ table.insert(resolvers.automounted,line)
+ resolvers.usezipfile(line)
+ end
+ end
+ end
+ f:close()
+ end
+ end
+ statistics.stoptiming(resolvers.instance)
+ end
+end
+
+-- status info
+
+statistics.register("used config path", function() return caches.configpath() end)
+statistics.register("used cache path", function() return caches.temp() or "?" end)
+
+-- experiment (code will move)
+
+function statistics.save_fmt_status(texname,formatbanner,sourcefile) -- texname == formatname
+ local enginebanner = status.list().banner
+ if formatbanner and enginebanner and sourcefile then
+ local luvname = file.replacesuffix(texname,"luv")
+ local luvdata = {
+ enginebanner = enginebanner,
+ formatbanner = formatbanner,
+ sourcehash = md5.hex(io.loaddata(resolvers.find_file(sourcefile)) or "unknown"),
+ sourcefile = sourcefile,
+ }
+ io.savedata(luvname,table.serialize(luvdata,true))
+ end
+end
+
+function statistics.check_fmt_status(texname)
+ local enginebanner = status.list().banner
+ if enginebanner and texname then
+ local luvname = file.replacesuffix(texname,"luv")
+ if lfs.isfile(luvname) then
+ local luv = dofile(luvname)
+ if luv and luv.sourcefile then
+ local sourcehash = md5.hex(io.loaddata(resolvers.find_file(luv.sourcefile)) or "unknown")
+ if luv.enginebanner and luv.enginebanner ~= enginebanner then
+ return "engine mismatch"
+ end
+ if luv.sourcehash and luv.sourcehash ~= sourcehash then
+ return "source mismatch"
+ end
+ else
+ return "invalid status file"
+ end
+ else
+ return "missing status file"
+ end
+ end
+ return true
+end
diff --git a/tex/context/base/data-zip.lua b/tex/context/base/data-zip.lua
new file mode 100644
index 000000000..dcb6b170a
--- /dev/null
+++ b/tex/context/base/data-zip.lua
@@ -0,0 +1,241 @@
+if not modules then modules = { } end modules ['data-zip'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, find = string.format, string.find
+
+local trace_locating, trace_verbose = false, false
+
+trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+trackers.register("resolvers.locating", function(v) trace_locating = v trace_verbose = v end)
+
+zip = zip or { }
+zip.archives = zip.archives or { }
+zip.registeredfiles = zip.registeredfiles or { }
+
+local finders, openers, loaders = resolvers.finders, resolvers.openers, resolvers.loaders
+local locators, hashers, concatinators = resolvers.locators, resolvers.hashers, resolvers.concatinators
+
+local archives = zip.archives
+
+-- zip:///oeps.zip?name=bla/bla.tex
+-- zip:///oeps.zip?tree=tex/texmf-local
+
+local function validzip(str) -- todo: use url splitter
+ if not find(str,"^zip://") then
+ return "zip:///" .. str
+ else
+ return str
+ end
+end
+
+function zip.openarchive(name)
+ if not name or name == "" then
+ return nil
+ else
+ local arch = archives[name]
+ if not arch then
+ local full = resolvers.find_file(name) or ""
+ arch = (full ~= "" and zip.open(full)) or false
+ archives[name] = arch
+ end
+ return arch
+ end
+end
+
+function zip.closearchive(name)
+ if not name or (name == "" and archives[name]) then
+ zip.close(archives[name])
+ archives[name] = nil
+ end
+end
+
+-- zip:///texmf.zip?tree=/tex/texmf
+-- zip:///texmf.zip?tree=/tex/texmf-local
+-- zip:///texmf-mine.zip?tree=/tex/texmf-projects
+
+function locators.zip(specification) -- where is this used? startup zips (untested)
+ specification = resolvers.splitmethod(specification)
+ local zipfile = specification.path
+ local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
+ if trace_locating then
+ if zfile then
+ logs.report("fileio",'! zip locator, found: %s',specification.original)
+ else
+ logs.report("fileio",'? zip locator, not found: %s',specification.original)
+ end
+ end
+end
+
+function hashers.zip(tag,name)
+ if trace_verbose then
+ logs.report("fileio","loading zip file %s as %s",name,tag)
+ end
+ resolvers.usezipfile(format("%s?tree=%s",tag,name))
+end
+
+function concatinators.zip(tag,path,name)
+ if not path or path == "" then
+ return format('%s?name=%s',tag,name)
+ else
+ return format('%s?name=%s/%s',tag,path,name)
+ end
+end
+
+function resolvers.isreadable.zip(name)
+ return true
+end
+
+function finders.zip(specification,filetype)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'! zip finder, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ dfile = zfile:close()
+ if trace_locating then
+ logs.report("fileio",'+ zip finder, name: %s',q.name)
+ end
+ return specification.original
+ end
+ elseif trace_locating then
+ logs.report("fileio",'? zip finder, path %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip finder, name: %s',filename)
+ end
+ return unpack(finders.notfound)
+end
+
+function openers.zip(specification)
+ local zipspecification = resolvers.splitmethod(specification)
+ if zipspecification.path then
+ local q = url.query(zipspecification.query)
+ if q.name then
+ local zfile = zip.openarchive(zipspecification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',zipspecification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_open(specification)
+ return openers.text_opener(specification,dfile,'zip')
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path %s',zipspecification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip opener, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+function loaders.zip(specification)
+ specification = resolvers.splitmethod(specification)
+ if specification.path then
+ local q = url.query(specification.query)
+ if q.name then
+ local zfile = zip.openarchive(specification.path)
+ if zfile then
+ if trace_locating then
+ logs.report("fileio",'+ zip starter, path: %s',specification.path)
+ end
+ local dfile = zfile:open(q.name)
+ if dfile then
+ logs.show_load(filename)
+ if trace_locating then
+ logs.report("fileio",'+ zip loader, name: %s',filename)
+ end
+ local s = dfile:read("*all")
+ dfile:close()
+ return true, s, #s
+ end
+ elseif trace_locating then
+ logs.report("fileio",'- zip starter, path: %s',specification.path)
+ end
+ end
+ end
+ if trace_locating then
+ logs.report("fileio",'- zip loader, name: %s',filename)
+ end
+ return unpack(openers.notfound)
+end
+
+-- zip:///somefile.zip
+-- zip:///somefile.zip?tree=texmf-local -> mount
+
+function resolvers.usezipfile(zipname)
+ zipname = validzip(zipname)
+ if trace_locating then
+ logs.report("fileio",'! zip use, file: %s',zipname)
+ end
+ local specification = resolvers.splitmethod(zipname)
+ local zipfile = specification.path
+ if zipfile and not zip.registeredfiles[zipname] then
+ local tree = url.query(specification.query).tree or ""
+ if trace_locating then
+ logs.report("fileio",'! zip register, file: %s',zipname)
+ end
+ local z = zip.openarchive(zipfile)
+ if z then
+ local instance = resolvers.instance
+ if trace_locating then
+ logs.report("fileio","= zipfile, registering: %s",zipname)
+ end
+ statistics.starttiming(instance)
+ resolvers.prepend_hash('zip',zipname,zipfile)
+ resolvers.extend_texmf_var(zipname) -- resets hashes too
+ zip.registeredfiles[zipname] = z
+ instance.files[zipname] = resolvers.register_zip_file(z,tree or "")
+ statistics.stoptiming(instance)
+ elseif trace_locating then
+ logs.report("fileio","? zipfile, unknown: %s",zipname)
+ end
+ elseif trace_locating then
+ logs.report("fileio",'! zip register, no file: %s',zipname)
+ end
+end
+
+function resolvers.register_zip_file(z,tree)
+ local files, filter = { }, ""
+ if tree == "" then
+ filter = "^(.+)/(.-)$"
+ else
+ filter = format("^%s/(.+)/(.-)$",tree)
+ end
+ if trace_locating then
+ logs.report("fileio",'= zip filter: %s',filter)
+ end
+ local register, n = resolvers.register_file, 0
+ for i in z:files() do
+ local path, name = i.filename:match(filter)
+ if path then
+ if name and name ~= '' then
+ register(files, name, path)
+ n = n + 1
+ else
+ -- directory
+ end
+ else
+ register(files, i.filename, '')
+ n = n + 1
+ end
+ end
+ logs.report("fileio",'= zip entries: %s',n)
+ return files
+end
diff --git a/tex/context/base/enco-cyr.tex b/tex/context/base/enco-cyr.tex
index 0ac82207f..36bca82b5 100644
--- a/tex/context/base/enco-cyr.tex
+++ b/tex/context/base/enco-cyr.tex
@@ -256,6 +256,8 @@
% \definecharacter textperthousand {\%\char 24 }
% \definecharacter textpertenthousand {\%\char 24\char 24 }
+\definecharacter cyrillicgheupturn 160 % to satisfy the patterns
+
\stopencoding
\startmapping[t2b]
diff --git a/tex/context/base/enco-def.tex b/tex/context/base/enco-def.tex
index c319c0065..a0631ac25 100644
--- a/tex/context/base/enco-def.tex
+++ b/tex/context/base/enco-def.tex
@@ -509,6 +509,7 @@
\definecharacter greekzeta {\zeta}
\definecharacter greeketa {\eta}
\definecharacter greektheta {\theta}
+\definecharacter greekthetaalt {\vartheta}
\definecharacter greekiota {\iota}
\definecharacter greekkappa {\kappa}
\definecharacter greeklambda {\lambda}
@@ -522,7 +523,8 @@
\definecharacter greeksigma {\sigma}
\definecharacter greektau {\tau}
\definecharacter greekupsilon {\upsilon}
-\definecharacter greekphi {\phi}
+\definecharacter greekphi {\varphi}
+\definecharacter greekphialt {\phi}
\definecharacter greekchi {\chi}
\definecharacter greekpsi {\psi}
\definecharacter greekomega {\omega}
@@ -893,7 +895,7 @@
\startencoding[\s!default]
-\definecharacter texthorizontalbar {{--\kern\zeropoint--}}
+\definecharacter texthorizontalbar {{\endash\kern\zeropoint\endash}}
\definecharacter textdong {\underbar{\dstroke}}
\stopencoding
diff --git a/tex/context/base/enco-fpl.tex b/tex/context/base/enco-fpl.tex
index ee9d98dc8..14d102ff1 100644
--- a/tex/context/base/enco-fpl.tex
+++ b/tex/context/base/enco-fpl.tex
@@ -21,7 +21,7 @@
\startlanguagespecifics[\s!pl]
- \appendtoks \makecharacteractive / \to \everynormalcatcodes
+% \appendtoks \makecharacteractive / \to \everynormalcatcodes % obsolete
\installcompoundcharacter /a {\aogonek}
\installcompoundcharacter /c {\cacute}
diff --git a/tex/context/base/enco-ini.mkii b/tex/context/base/enco-ini.mkii
index d39a64fca..9379c3a7f 100644
--- a/tex/context/base/enco-ini.mkii
+++ b/tex/context/base/enco-ini.mkii
@@ -1,34 +1,1137 @@
%D \module
%D [ file=enco-ini,
-%D version=2007.02.19,
+%D version=2007.02.19, % 2000.12.27, % 1998.12.03,
%D title=\CONTEXT\ Encoding Macros,
%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright=\PRAGMA]
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D In the end we will cleanup enco-ini.tex!
+%D Quite some code will be moved to the mk files once we're ready
+%D for it.
+
+%D This module is a reimplementation of the module that handled
+%D composed characters and non \ASCII\ characters. The changed
+%D are not that fundamental, and mainly concerns moving
+%D definitions of specific glyphs and accents to other files as
+%D well as moving plain handling of accents to this module
+%D instead of overloading plain \TEX\ commands.
+
+%D Patterns are kind of mixed with font encodings and
+%D mappings. Alas.
+
+\ifx\synchronizepatterns\undefined \let\synchronizepatterns\relax \fi
+
+%D While dealing with input (the text source) and output (the
+%D glyphs), encoding comes into view. To summarize a few:
+%D
+%D \startitemize
+%D \item Bytes in the input file are mapped to an internal
+%D representation. An~\type {a} often stays an~\type {a},
+%D but~\type {\"e} can become either one code or become
+%D two codes (ending in overlapping glyphs).
+%D \item Characters can be made active and mapped onto another
+%D character.
+%D \item When changing case, characters are mapped onto
+%D themselves, their case||counterpart or a reasonable
+%D alternative, like~\"e onto~e.
+%D \item Single character representations in a \DVI\ file can
+%D be mapped onto one or more characters, either of not
+%D in more than one font file (virtual fonts).
+%D \item In the final format, fonts collections can be
+%D partially embedded, thereby losing the one||to||one
+%D relation between several instances of one font.
+%D \item For special purposes, individual characters should be
+%D mapped onto a dedicated encoding vector, for instance
+%D \PDF\ document encoding.
+%D \stopitemize
+%D
+%D These and other kind of mappings are to be dealt with, and
+%D the exact way of dealing often depends on the language to be
+%D typeset.
+
+\writestatus{loading}{ConTeXt Encoding Macros / Initialization}
\unprotect
-\beginOLDTEX
+%D First we define a few local or not yet initialized constants.
- \useencoding[ans,il2,ec,tbo,pdf,pol,qx,t5,cyr,agr] % pol and il2 will go away, not needed in mkiv, uc removed
+\def\@map@{@m@ap@} % mapping prefix
+\def\@fha@{@f@ha@} % font prefix
+\def\@cas@{@c@as@} % casecom prefix
- \useencoding[032,033,037] % fallbacks for some unicode chars
+\ifx\currentlanguage\undefined \let\currentlanguage\s!en \fi
- \setupencoding[\s!default=ec] % was: [\s!default=\s!default]
+%D \macros
+%D {setupencoding}
+%D
+%D The following setup command is used to tune encoding
+%D handling.
-\endOLDTEX
+\def\setupencoding
+ {\dosingleargument\dosetupencoding}
-\beginXETEX
+\def\dosetupencoding[#1]%
+ {\getparameters[\??ec][#1]%
+ \edef\defaultencoding
+ {\ifx\@@ecdefault\empty\s!default\else\@@ecdefault\fi}}
- \setupencoding[\s!default=\s!default]
+%D \macros
+%D {useencoding}
+%D
+%D Encodings things are defined in separate files and are
+%D loaded only once, using:
+%D
+%D \showsetup{useencoding}
+
+\def\douseencoding#1%
+ {\doifundefined{\c!file\f!encodingprefix#1}%
+ {\letvalue{\c!file\f!encodingprefix#1}\empty
+ \makeshortfilename[\truefilename{\f!encodingprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!encodings2{#1}}
+ {\showmessage\m!encodings3{#1}}%
+ \stopreadingfile}}
+
+\def\useencoding[#1]%
+ {\processcommalist[#1]\douseencoding}
+
+%D \macros
+%D {startmapping,enablemapping}
+%D
+%D In order to process patterns, convert from lower to
+%D uppercase and vise versa and some more, we provide a
+%D mechanism to define mappings. The first real application
+%D of this command was:
+%D
+%D \starttyping
+%D \startmapping [something]
+%D \definecasemap 165 181 165
+%D \definecasemap 171 187 171
+%D ...
+%D \defineuppercasecom \i {I}
+%D \defineuppercasecom \l \L
+%D \definelowercasecom \AE \ae
+%D ...
+%D \stopmapping
+%D \stoptyping
+%D
+%D So, character 165 becomes 181 in uppercase and 165 in
+%D lowercase. A mapping is activated with \type {\enablemapping}.
+
+\def\startsavingmappingtoks#1%
+ {\bgroup
+ \edef\charactermapping{@#1@}%
+ \checkmappingtoks
+ \setmappingtoks
+ \the\mappingtoks}
+
+\def\stopsavingmappingtoks
+ {\global\mappingtoks\emptytoks
+ \dostepwiserecurse{0}{255}\plusone
+ {\edef\@@expanded
+ {\the\mappingtoks
+ \ifnum\recurselevel>127
+ \noexpand\settoletterunlessactive{\recurselevel}%
+ \fi
+ \lccode\recurselevel\ifnum\lccode\recurselevel=\zerocount\zerocount\else\space\the\lccode\recurselevel\space\fi
+ \uccode\recurselevel\ifnum\uccode\recurselevel=\zerocount\zerocount\else\space\the\uccode\recurselevel\space\fi
+ \ifnum\sfcode\recurselevel=\plusthousand\else\sfcode\recurselevel=\the\sfcode\recurselevel\space\fi
+ }%
+ \global\mappingtoks\expandafter{\@@expanded}}%
+ \egroup
+ \let\enabledmapping\empty
+ \enablemapping[\currentmapping]}
+
+\def\startmapping[#1]%
+ {\startsavingmappingtoks{#1}}
+
+\def\stopmapping
+ {\stopsavingmappingtoks}
+
+\def\optimizemapping[#1]%
+ {\startsavingmappingtoks{#1}%
+ % nothing, just an automatic cleanup
+ \stopsavingmappingtoks
+ % we need to resync
+ %\let\enabledmapping\relax
+ }%\enablemapping[\currentmapping]}
+
+\def\setmappingtoks
+ {\@EA\let\@EA\mappingtoks\csname\@map@\charactermapping\endcsname
+ \@EA\let\@EA\casecomtoks\csname\@cas@\charactermapping\endcsname}
+
+\def\checkmappingtoks
+ {\ifundefined{\@map@\charactermapping}%
+ \expandafter\newtoks\csname\@map@\charactermapping\endcsname
+ \fi
+ \ifundefined{\@cas@\charactermapping}%
+ \expandafter\newtoks\csname\@cas@\charactermapping\endcsname
+ \fi}
+
+\def\definecasemap #1 #2 #3 % code lower upper
+ {\doifelse{#2}{to}
+ {\presetcaserange{#1}{#3}}
+ {\lccode#1=#2\relax
+ \uccode#1=#3\relax}%
+ \ignorespaces}
+
+%D Saves a few tokens
+
+\def\definecaseswap #1 #2 % lower upper
+ {\lccode#1=#1\relax
+ \uccode#2=#2\relax
+ \lccode#2=#1\relax
+ \uccode#1=#2\relax
+ \ignorespaces}
+
+\def\definecaseself #1 % lower=upper=self
+ {\lccode#1=#1\relax
+ \uccode#1=#1\relax
+ \ignorespaces}
+
+%D Watch the \type {\definecasemap 127 to 255} option!
+%D Dedicated to Taco there is also:
+
+\def\definecasemaps #1 to #2 lc #3 uc #4 % from to lc+ uc+
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\scratchcounter\recurselevel\advance\scratchcounter#3\lccode\recurselevel=\scratchcounter
+ \scratchcounter\recurselevel\advance\scratchcounter#4\uccode\recurselevel=\scratchcounter}%
+ \ignorespaces}
+
+%D This can be used like:
+%D
+%D \starttyping
+%D \definecasemaps 128 to 156 lc 32 uc 0
+%D \definecasemaps 160 to 188 lc -32 uc 0
+%D \definecasemaps 160 to 188 lc -32 uc 0
+%D \definecasemaps 192 to 255 lc 32 uc 0
+%D \stoptyping
+%D
+%D and saves a lot of typing (copying).
+
+\def\resetcaserange #1 to #2
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\lccode\recurselevel\zerocount
+ \uccode\recurselevel\zerocount}%
+ \ignorespaces}
+
+\def\presetcaserange#1#2% could be pre-expanded
+ {\dostepwiserecurse{#1}{#2}\plusone
+ {\lccode\recurselevel=\recurselevel
+ \uccode\recurselevel=\recurselevel}%
+ \ignorespaces}
+
+\def\setcasemap #1 #2 #3 %
+ {\settoletterunlessactive{#1}%
+ \lccode #1=#2
+ \uccode #1=#3 }
+
+\def\setcaseswap #1 #2 %
+ {\settoletterunlessactive{#1}%
+ \settoletterunlessactive{#2}%
+ \lccode #1=#1
+ \uccode #2=#2
+ \lccode #2=#1
+ \uccode #1=#2 }
+
+\def\setcaseself #1 %
+ {\settoletterunlessactive{#1}%
+ \lccode #1=#1
+ \uccode #1=#1 }
+
+\def\definespacemap #1 #2 % code sfcode
+ {\sfcode#1=#2%
+ \ignorespaces}
+
+\def\setspacemap #1 #2 %
+ {\settootherunlessactive{#1}%
+ %\lccode #1=\zerocount
+ %\uccode #1=\zerocount
+ \sfcode #1=#2 }
+
+\def\defineuppercasecom#1#2%
+ {\global\casecomtoks\expandafter{\the\casecomtoks\setuppercasecom#1{#2}}%
+ \ignorespaces}
+
+\def\definelowercasecom#1#2%
+ {\global\casecomtoks\expandafter{\the\casecomtoks\setlowercasecom#1{#2}}%
+ \ignorespaces}
+
+\let\setuppercasecom\gobbletwoarguments
+\let\setlowercasecom\gobbletwoarguments
+
+\def\setcasecom#1#2{\def#1{#2}}
+
+\let\enabledmapping\empty % indirect, needed to handle default too
+
+\def\enablemapping[#1]%
+ {\edef\charactermapping{@#1@}%
+ \ifx\enabledmapping\charactermapping \else
+ \doifdefined{\@map@\charactermapping}
+ {%\expandafter\showthe\csname\@map@\charactermapping\endcsname\endcsname
+ \the\csname\@map@\charactermapping\endcsname}%
+ % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
+ \edef\enabledmapping{\charactermapping}%
+ \enablelanguagespecifics[\currentlanguage]% new
+ % \edef\enabledmapping{\charactermapping\currentlanguage}% can be comma list
+ \fi
+ \synchronizepatterns}
+
+% on behalf of font switching:
+
+\def\fastenablemapping#1%
+ {\edef\charactermapping{@#1@}%
+ \ifx\enabledmapping\charactermapping \else
+ \@EA\ifx\csname\@map@\charactermapping\endcsname\relax\else
+ \the\csname\@map@\charactermapping\endcsname
+ \fi
+ % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
+ \let\enabledmapping\charactermapping
+ \enablelanguagespecifics[\currentlanguage]% to faster
+ \fi}
+
+%D This macro wil be implemented in \type {lang-ini.tex}.
+
+\ifx\enablelanguagespecifics\undefined
+ \def\enablelanguagespecifics[#1]{}
+\fi
+
+%D Further on we have to take some precautions when dealing
+%D with special characters like~\type{~}, \type{_}
+%D and~\type{^}, so let us define ourselve some handy macros
+%D first.
+
+\def\protectfontcharacters
+ {\edef\unprotectfontcharacters
+ {\catcode`\noexpand ~=\the\catcode`~\relax
+ \catcode`\noexpand _=\the\catcode`_\relax
+ \catcode`\noexpand ^=\the\catcode`^\relax}%
+ \catcode`~=\@@letter
+ \catcode`_=\@@letter
+ \catcode`^=\@@letter\relax}
+
+%D The completeness of the Computer Modern Roman typefaces
+%D makes clear how incomplete other faces are. To honour 7~bit
+%D \ASCII, these fonts were designed using only the first 127
+%D values of the 256 ones that can be presented by one byte.
+%D Nowadays 8~bit character codings are more common, mainly
+%D because they permit us to predefine some composed
+%D characters, which are needed in most european languages.
+%D
+%D Supporting more than the standard \TEX\ encoding vector
+%D |<|which in itself is far from standard and differs per
+%D font|>| puts a burden on the fonts mechanism. The \CONTEXT\
+%D mechanism is far from complete, but can handle several
+%D schemes at once. The main problem lays in the accented
+%D characters and ligatures like~ff, although handling
+%D ligatures is not the responsibility of this module.
+%D
+%D By default, we use \PLAIN\ \TEX's approach of placing
+%D accents. All other schemes sooner or later give problems
+%D when we distribute \DVI||files are distributed across
+%D machines and platforms. Nevertheless, we have to take care
+%D of different encoding vectors, which tell us where to find
+%D the characters we need. This means that all kind of
+%D character placement macro's like \type{\"} and \type{\ae}
+%D have to be implemented and adapted in a way that suits
+%D these vectors.
+%D
+%D The main difference between different vector is the way
+%D accents are ordered and/or the availability of prebuilt
+%D accented characters. Accented characters can for instance be
+%D called for by sequences like \type{\"e}. Here the \type{\"}
+%D is defined as:
+%D
+%D \starttyping
+%D \def\"#1{{\accent"7F #1}}
+%D \stoptyping
+%D
+%D This macro places the accent \accent"7F {} on top of an~e
+%D gives \"e. Some fonts however can have prebuild accents and
+%D use a more direct approach like
+%D
+%D \starttyping
+%D \def\"#1{\if#1e\char 235\else ... \fi}
+%D \stoptyping
+%D
+%D The latter approach is not used in \CONTEXT, because we
+%D store relevant combinations of accents and characters in
+%D individual macros.
+
+%D We define character substitutes and commands with definition
+%D commands like:
+%D
+%D \starttyping
+%D \startcoding[texnansi]
+%D
+%D \defineaccent " a 228
+%D \defineaccent ^ e 234
+%D \defineaccent ' {\dotlessi} 237
+%D
+%D \definecharacter ae 230
+%D \definecharacter oe 156
+%D
+%D \definecommand b \texnansiencodedb
+%D \definecommand c \texnansiencodedc
+%D
+%D \stopcoding
+%D \stoptyping
+%D
+%D The last argument of \type{\defineaccent} and
+%D \type{\definecharacter} tells \TEX\ the position of the
+%D accented character in the encoding vector. In order to
+%D complish this, we tag each implementation with the character
+%D coding identifier. We therefore need two auxiliary variables
+%D \type{\characterencoding} and \type{\nocharacterencoding}. These
+%D contain the current and default encoding vectors and both
+%D default to the \PLAIN\ one.
+
+\edef\characterencoding {@\s!default @}
+\edef\nocharacterencoding {@\s!default @}
+\edef\charactermapping {@\s!default @}
+
+% todo, else \d j == \dj, print file and check
+
+\def\accentprefix {}%{*}
+\def\commandprefix {}%{=}
+\def\characterprefix{}%{-}
+
+%D \macros
+%D {startcoding, reducetocoding}
+%D
+%D Before we can redefine accents and special characters, we
+%D have to tell \CONTEXT\ what encoding is in force. The next
+%D command is responsible for doing this and also takes care of
+%D the definition of the recoding commands. We use the \type
+%D {\start}||\type {\stop}||commands for definitions and the
+%D \type {\reduceto}||command for local switching to
+%D simplified commands.
+
+% etex : \ifcsname
+
+\def\justhandleaccent#1#2% \empty makes #2={} save % no \unexpanded
+ {\ifundefined{\accentprefix\characterencoding#1\string#2\empty}%
+ #2%
+ \else
+ \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \fi}
+
+\def\justhandlecommand#1% % no \unexpanded, otherwise pdfdoc will fail
+ {\ifundefined{\commandprefix\characterencoding#1}% as well as hyph patterns
+ #1%
+ \else
+ \csname\commandprefix\characterencoding#1\endcsname
+ \fi}
+
+\def\enableencoding
+ {\dodoubleempty\doenableencoding}
+
+\def\doenableencoding[#1][#2]% main fallback
+ {\iffirstargument\edef\characterencoding{@#1@}\fi
+ \edef\nocharacterencoding{@\ifsecondargument#2\else\s!default\fi @}%
+ \synchronizepatterns}
+
+\edef\xnocharacterencoding{@\s!default @}
+
+\def\fastenableencoding#1%
+ {\edef\characterencoding{@#1@}%
+ \let\nocharacterencoding\xnocharacterencoding}
+
+\def\startencoding
+ {\dodoubleempty\dostartencoding}
+
+\def\dostartencoding[#1][#2]% encoding regime
+ {%\showmessage\m!encodings1{#1}%
+ \pushmacro\characterencoding
+ \pushmacro\currentregime
+ \pushmacro\dohandleaccent % still needed?
+ \pushmacro\dohandlecommand % still needed?
+ \pushmacro\doautosetregime
+ \let\dohandleaccent\donthandleaccent % still needed?
+ \let\dohandlecommand\donthandlecommand % still needed?
+ %let\definesortkey\savesortkey
+ \edef\characterencoding{@#1@}%
+ \doifelsenothing{#2}%
+ {\let\doautosetregime\gobbletwoarguments}
+ {\def\currentregime{#2}}}
+
+\def\stopencoding
+ {\popmacro\doautosetregime
+ \popmacro\dohandlecommand % still needed?
+ \popmacro\dohandleaccent % still needed?
+ \popmacro\currentregime
+ \popmacro\characterencoding}
+
+% probably obsolete (hm, not yet)
+
+\def\reducetocoding[#1]% use grouped!
+ {\doifsomething{#1}
+ {\let\dohandleaccent \justhandleaccent
+ \let\dohandlecommand\justhandlecommand
+ \enableencoding[#1]%
+ \enablelanguagespecifics[\currentlanguage]}}
+
+\let\startcoding \startencoding
+\def\stopcoding {\stopencoding}
+\let\enablecoding \enableencoding
+
+%D The use of these macros are not limited to font
+%D definition files, but may also be used when loading
+%D patterns.
+
+%D \macros
+%D {definesortkey,flushsortkeys,flushsortkey}
+%D
+%D Yet another definition concerns sorting of indexes and
+%D lists.
+%D
+%D \starttyping
+%D \definesortkey {\'e} {e} {a} {\'e}
+%D \stoptyping
+%D
+%D The first argument denotes the string to be treated. The
+%D second argument is the raw replacement, while the third
+%D argument determines the sort order given the replacement.
+%D The last argument is used as entry in the index (a, b, etc).
+%D
+%D The keys can be flushed using \type {\flushsortkeys}
+%D which in turn results in a sequence of calls to \type
+%D {\flushsortkey}, a macro taking 4~arguments.
+%D
+%D This mechanism is currently being tested and subjected to
+%D changes! Obsolete:
+
+\let\definesortkey\gobblefourarguments
+\let\savesortkey \gobblefourarguments
+\let\flushsortkeys\relax
+\let\flushsortkey \relax
+
+%D \macros
+%D {defineaccent, definecharacter, definecommand}
+%D
+%D The actual definition of accents, special characters and
+%D commands is done with the next three commands.
+
+\def\defineaccent
+ {\protectfontcharacters
+ \dodefineaccent}
+
+\def\dodefineaccent#1 #2 %
+ {\unprotectfontcharacters
+ \dododefineaccent#1 #2 }
+
+\def\dododefineaccent#1 #2 #3 %
+ {\setvalue{#1}{\dohandleaccent{#1}}%
+ \doifnumberelse{\string#3}
+ {\setvalue{\accentprefix\characterencoding#1\string#2}{\char#3 }} % space added
+ {\setvalue{\accentprefix\characterencoding#1\string#2}{#3}}}
+
+\def\dohandleaccent#1#2%
+ {\ifcsname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
+ \else\ifcsname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
+ \csname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
+ \else\ifcsname\accentprefix\characterencoding#1\endcsname
+ \csname\accentprefix\characterencoding#1\endcsname{#2}%
+ \else%\ifcsname\accentprefix\nocharacterencoding#1\endcsname
+ \csname\accentprefix\nocharacterencoding#1\endcsname{#2}%
+% \else
+% \donormaltextaccent{#1}{#2}%
+ \fi\fi\fi}%\fi}
+
+\def\patternchar#1 {\rawcharacter{#1}} % space is part of character definition !
+
+% \ifx \enablepatterntokens\undefined
+% \def\handlepatterntoken#1]{\csname#1\endcsname}
+% \fi
+
+% we need to postpone catcode changes, e.g. hr patterns
+% have \catcode" -> which fails when " is letter
+
+\def\pathypsettings
+ {\ifx \enablepatterntokens\undefined
+ \defineactivecharacter [ {\handlepatterntoken}%
+ \else
+ \enablepatterntokens
+ \fi
+ \let\dochar\thechr
+ \lccode16=16 % brrr, extra quote in ec (turkish)
+ \lccode17=17 % brrr, extra quote in ec (turkish)
+ \lccode`\-=`\-
+ \lccode`\'=`\'
+ \lccode`\"=`\"
+ \relax}
+
+\def\patterns {\pathypsettings\normalpatterns }
+\def\hyphenation{\pathypsettings\normalhyphenation}
+
+%D Because we don't want to use the second command grouped, we
+%D (re)define it as follows:
+
+\def\hyphenation
+ {\begingroup\def\hyphenation{\normalhyphenation{\the\scratchtoks}\endgroup}%
+ \pathypsettings\afterassignment\hyphenation\scratchtoks=}
+
+%D This is not needed for patterns because they are loaded grouped
+%D anyway and it saves us an assignment. Can go ... no longer
+%D shared patterns.
+
+\def\startpatternloading#1#2#3% % we should use \everypatternloading
+ {\startreadingfile
+ \bgroup
+ % let's get rid of interfering stuff
+ \let\everyjob\scratchtoks
+ \let\message \gobbleoneargument
+ % we want direct characters
+ \let\char\patternchar
+ \doifelsenothing{#2}{\enableencoding[ec]}{\enableencoding[#2]}%
+ \doifelsenothing{#3}{\enablemapping [ec]}{\enablemapping [#3]}%
+ \expanded{\doifinstring{\f!languageprefix}{#1}}
+ {\ifx \enablepatternxml\undefined \else
+ \enablepatternxml
+ \fi}%
+ \let\dohandleaccent\normaldohandleaccent}
+
+\def\stoppatternloading
+ {\egroup
+ \stopreadingfile}
+
+ \def\thechr#1{\char#1 } % just in case \relax interferes
+\unexpanded\def\numchr#1{\char#1\relax}
+\unexpanded\def\strchr#1{\csname#1\endcsname}
+
+\let\dochar\numchr
+
+\def\startdirectcharacters {\pushmacro\dochar \let\dochar\thechr}
+\def\stopdirectcharacters {\popmacro \dochar}
+
+\def\definecharacter#1 #2 %
+ {\ifundefined{#1}\setvalue{#1}{\dohandlecharacter{#1}}\fi
+ \doifnumberelse{\string#2}
+ {\setvalue{\characterprefix\characterencoding\string#1}{\dochar{#2}}%
+ \doautosetregime{#1}{#2}}
+ {\setvalue{\characterprefix\characterencoding\string#1}{#2}}}
+
+\def\dohandlecharacter#1%
+ {\csname\characterprefix\ifcsname\characterprefix\characterencoding#1\endcsname
+ \characterencoding\else\nocharacterencoding\fi#1\endcsname}
+
+% \def\fallbackpatternchar{x} % makes no sense, duplicate patterns
+
+\def\defaultcharacter#1%
+ {\csname\characterprefix\nocharacterencoding\strippedcsname#1\endcsname}
+
+%D Instead of numbers, a command may be entered.
+
+\def\definecommand#1 #2 %
+ {\setvalue{\string#1}{\dohandlecommand{#1}}%
+ %\redefinecommand #1 % just to be sure
+ \setvalue{\commandprefix\characterencoding\string#1}{#2}}
+
+%D Here we see that redefining accents is characters is more
+%D or less the same as redefining commands. We also could have
+%D said:
+%D
+%D \starttyping
+%D \def\defineaccent#1 #2 {\definecommand#1\string#2 \char}
+%D \def\definecharacter#1 {\definecommand#1 \char}
+%D \stoptyping
+
+%D \macros
+%D {defineaccentcommand}
+%D
+%D When needed, one can overload the default positions of the
+%D accents. The \PLAIN\ \TEX\ defaults are:
+%D
+%D \starttyping
+%D \defineaccentcommand ` 18
+%D \defineaccentcommand ' 19
+%D \defineaccentcommand v 20
+%D \defineaccentcommand u 21
+%D \defineaccentcommand = 22
+%D \defineaccentcommand ^ 94
+%D \defineaccentcommand . 95
+%D \defineaccentcommand H 125 % "7D
+%D \defineaccentcommand ~ 126 % "7E
+%D \defineaccentcommand " 127 % "7F
+%D \stoptyping
-\endXETEX
+\def\defineaccentcommand
+ {\protectfontcharacters
+ \dodefineaccentcommand}
+
+\def\dodefineaccentcommand#1 #2 % \string toegevoegd
+ {\doifnumberelse{\string#2}
+ {\setvalue{\accentprefix\characterencoding\string#1}##1{{\accent#2 ##1}}}
+ {\setvalue{\accentprefix\characterencoding\string#1}##1{{#2##1}}}%
+ \unprotectfontcharacters}
+
+%D We don't have to define them for the default \PLAIN\ case.
+%D Commands may be used instead of character codes.
+
+%D \macros
+%D {redefinecommand}
+%D
+%D Redefinition of encoding dependant commands like \type{\b}
+%D and \type{\c} can be triggered by:
+%D
+%D \starttyping
+%D \redefinecommand b % something math
+%D \redefinecommand c % something math
+%D \stoptyping
+%D
+%D Handling of characters is easier than handling accents
+%D because here we don't have to take care of arguments. We
+%D just call for the right glyph in the right place.
+%D
+%D The \type{\next} construction permits handling of commands
+%D that take arguments. This means that we can use this
+%D command to redefine accent handling commands too
+%D (although today the next is not needed any longer in test
+%D macros).
+
+\def\redefinecommand#1 %
+ {% no \unexpanded, else pdfdoc fails
+ \setvalue{\string#1}{\dohandlecommand{#1}}}%
+
+\def\dohandlecommand#1%
+ {\csname\commandprefix
+ \ifcsname\commandprefix\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi
+ #1\endcsname}
+
+%D \macros
+%D {currentencoding, currentmapping}
+%D
+%D When we show 'm, we don't want to see the protection
+%D measures.
+
+\def\currentencoding{\@EA\dopureencodingname\characterencoding}
+\def\currentmapping {\@EA\dopureencodingname\charactermapping }
+
+\def\dopureencodingname @#1@{#1}
+
+\def\pureencodingname#1{\@EA\dopureencodingname#1}
+
+%D \macros
+%D {showaccents, showcharacters,
+%D showcharacterbounds, showhyphenations}
+%D
+%D Encoding is a tricky business. Therefore we provide a
+%D a few macros that show most of the characters involved. The
+%D next two tables show the result of \type {\showaccents}.
+%D
+%D \placetable
+%D {The special glyphs in default encoding.}
+%D {\showaccents}
+%D
+%D \placetable
+%D {The special glyphs in texnansi encoding.}
+%D {\switchtobodyfont[lbr]\showaccents}
+%D
+%D The command
+%D
+%D \starttyping
+%D \showhyphenations{doordefini\"eren}
+%D \stoptyping
+%D
+%D can be used to check the correct loading of hyphenation
+%D patterns.
+
+\fetchruntimecommand \showaccents {\f!encodingprefix\s!run}
+\fetchruntimecommand \showcharacters {\f!encodingprefix\s!run}
+\fetchruntimecommand \showcharacterbounds {\f!encodingprefix\s!run}
+\fetchruntimecommand \showhyphenations {\f!encodingprefix\s!run}
+\fetchruntimecommand \showmapping {\f!encodingprefix\s!run}
+
+%D \macros
+%D {everyuppercase, EveryUppercase,
+%D everyuppercase, EveryUppercase}
+%D
+%D When we want to uppercase strings of characters, we have to
+%D take care of those characters that have a special meaning or
+%D are only accessible by means of macros. The next hack was
+%D introduced when Tobias Burnus started translating head and
+%D label texts into spanish and italian. The first application
+%D of this token register therefore can be found in the module
+%D that deals with these texts.
+
+\newevery \everyuppercase \EveryUppercase
+\newevery \everylowercase \EveryLowercase
+
+%D This magic trick maps takes care of mapping from lower to
+%D upper case and reverse.
+
+\def\reloadmapping{\the\executeifdefined{\@cas@\charactermapping}\emptytoks}
+
+\appendtoks\let\setuppercasecom\setcasecom\to\everyuppercase
+\appendtoks\let\setlowercasecom\setcasecom\to\everylowercase
+
+\appendtoks\reloadmapping\to\everyuppercase % slow, will be sped up
+\appendtoks\reloadmapping\to\everylowercase % slow, will be sped up
+
+\newtoks\everyULmap
+
+\appendtoks\let\remapcase\remapuppercase\the\everyULmap\to\everyuppercase
+\appendtoks\let\remapcase\remaplowercase\the\everyULmap\to\everylowercase
+
+\let\remapcase\gobbletwoarguments
+
+\def\remapuppercase#1#2{\let#2#1} % more efficient:
+\def\remaplowercase#1#2{\let#1#2} \let\remaplowercase\let
+
+\def\defineLCcharacter #1 #2 %
+ {\appendtoks\let\to\everylowercase
+ \@EA\appendtoks\csname#1\endcsname\to\everylowercase
+ \@EA\appendtoks\csname#2\endcsname\to\everylowercase}
+
+\def\defineUCcharacter #1 #2 %
+ {\appendtoks\let\to\everyuppercase
+ \@EA\appendtoks\csname#1\endcsname\to\everyuppercase
+ \@EA\appendtoks\csname#2\endcsname\to\everyuppercase}
+
+\def\defineULcharacter #1 #2 %
+ {\appendtoks\remapcase\to\everyULmap
+ \@EA\appendtoks\csname#1\endcsname\to\everyULmap
+ \@EA\appendtoks\csname#2\endcsname\to\everyULmap}
+
+% slightly faster with \smallcapped's but far more hash and stringspace
+%
+% \newif\ifuppercase \appendtoks\uppercasetrue\to\everyuppercase
+% \newif\iflowercase \appendtoks\lowercasetrue\to\everylowercase
+%
+% \def\defineULcharacter #1 #2 %
+% {\def\!!stringa{@#1}\@EA\letvalue\@EA\!!stringa\csname#1\endcsname
+% \def\!!stringa{@#2}\@EA\letvalue\@EA\!!stringa\csname#2\endcsname
+% \setvalue{#1}{\getvalue{@\ifuppercase#2\else#1\fi}}%
+% \setvalue{#2}{\getvalue{@\iflowercase#1\else#2\fi}}}
+
+% 2 = tricky, since expanding \definedfont[lowcasename] ... goes wrong
+
+\chardef\uppercasemode\plusthree % 0=ignore 1=normal 2=expand 3=auto
+\chardef\casecommode \plusone % 0=noexpand 1=expand
+
+\def\setcasecom #1#2{\def#1{\ifcase\casecommode\noexpand#1\else#2\fi}}
+
+% \def\OEPS{whatever}
+%
+% \startmapping[ec]
+% \defineuppercasecom \oeps {\getvalue{OEPS}}
+% \stopmapping
+%
+% \WORD{xx \oeps}
+
+\def\douppercase#1%
+ {\bgroup
+ \let\douppercase\firstofoneargument
+ \the\everyuppercase % currently also checks uppercasemode
+ \let\dochar\rawcharacter
+ \ifcase\uppercasemode
+ #1%
+ \or % No expansion here, otherwise \getvalue problems! Default!!!
+ %\edef\next{#1}% keep this to prevent roll back
+ %\uppercase\expandafter{\next}% keep this to prevent roll back
+ \uppercase{#1}%
+ \or
+ \chardef\casecommode\zerocount
+ \let\docasecom\firstoftwoarguments
+ \edef\ascii{#1}%
+ \edef\ascii{\expandafter\uppercase\expandafter{\ascii}}% needed when in regime
+ \chardef\casecommode\plusone
+ \ascii
+ \else
+ % mode three may trigger setting 2 elsewhere (e.g. regime test)
+ \uppercase{#1}%
+ \fi
+ \egroup}
+
+\prependtoksonce
+ \doifnot\currentregime\s!default
+ {\ifnum\uppercasemode=\plusthree \chardef\uppercasemode\plustwo \fi}%
+\to \everyuppercase
+
+%D \macros
+%D {everysanitize, EverySanitize}
+%D
+%D Whenever we are sanitizing strings, like we sometimes do
+%D when we deal with specials, the next token register can be
+%D called.
+
+\newevery \everysanitize \EverySanitize
+
+%D \macros
+%D {defineuclass,defineudigit,udigit}
+%D
+%D The next few macros are experimental and needed for unicoded
+%D chinese characters.
+
+\def\defineuclass #1 #2 #3 %
+ {\setvalue{uc\the\numexpr#2*256+#3\relax}{#1}}
+
+\def\defineudigit #1 #2 #3 {\setvalue{\characterencoding uc#1}{\uchar{#2}{#3}}}
+
+%D It may look strange, but for the moment, we want the encoding
+%D to be part of the digit specification. This may change!
+
+\unexpanded\def\udigit#1#2{\getvalue{@#1@uc\number#2}}
+
+%D \macros
+%D {uchar, octuchar, hexuchar}
+
+\ifx\uchar\undefined \def\uchar#1#2{(\number#1,\number#2)} \fi
+
+\def\octuchar#1#2{\uchar{`#1}{`#2}}
+\def\hexuchar#1#2{\uchar{"#1}{"#2}}
+
+%D Basics and fallbacks.
+
+\newif\ifignoreaccent
+
+\let\textaccent \accent
+\let\normaltextaccent\textaccent
+
+% ** we will explicitly embrace the two arguments, since in definitions
+% this may not be the case, and we don't want faulty expansions like
+% "\dobuildtextaccent \char 18 a" but "\dobuildtextaccent {\char 18}{a}"
+% instead
+
+\def\buildmathaccent#1%
+ {\mathaccent#1 }
+
+\def\buildtextaccent#1#2% **
+ {\ifignoreaccent
+ \expandafter\nobuildtextaccent
+ \else
+ \expandafter\dobuildtextaccent
+ \fi{#1}{#2}}
+
+\unexpanded\def\nobuildtextaccent#1#2%
+ {#2}
+
+\unexpanded\def\dobuildtextaccent#1#2%
+ {{\let\char\normalaccent#1\let\char\normalchar#2}}
+
+% some fake ones, name will change into build
+
+\unexpanded\def\bottomaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode % why this align mess
+ \vtop
+ {\forgetall
+ \baselineskip\zeropoint
+ \lineskip#1%
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \lineskiplimit\zeropoint
+ \setbox0\hbox{#4}%
+ \halign
+ {##\crcr\hbox{#5}\crcr
+ \hidewidth
+ \hskip#2\wd0
+ \hskip-#3\slantperpoint % in plain 1ex * dimenless value
+ \vbox to .2ex{\box0\vss}\hidewidth
+ \crcr}}}
+
+\def\buildtextmacron {\bottomaccent{.25ex}{0}{15}{\textmacron}}
+\def\buildtextbottomdot{\bottomaccent{.25ex}{0}{5}{\textbottomdot}}
+\def\buildtextcedilla {\bottomaccent{0ex}{0}{5}{\textcedilla}}
+\def\buildtextogonek {\bottomaccent{-.1ex}{.5}{0}{\textogonek}}
+
+%D A collectors item:
+
+\def\buildtextbottomcomma{\bottomaccent{.15ex}{0}{5}{\tx,}}
+
+%D Rarely needed but there:
+
+\unexpanded\def\topaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode
+ \bgroup
+ \setbox0\hbox{#4}%
+ \setbox2\hbox{#5}%
+ \hbox to \wd2 \bgroup
+ \hss\copy2\hss
+ \hskip-\wd2
+ \hss\hskip#2\wd0\hskip-#3\slantperpoint\raise#1\hbox{#4}\hss
+ \egroup
+ \egroup}
+
+\def\buildtextgrave{\topaccent{0pt}{0}{15}{\textgrave}} % e.g.
+
+% \definecharacter schwa {\hbox{\rotate[rotation=180,location=high]{\hbox{e}}}}
+% \definecharacter schwagrave {\buildtextgrave\schwa}
+
+% math stuff, will change
+
+\def\definemathaccent#1 #2%
+ {\setvalue{\string#1}{#2}%
+ \setvalue{normalmathaccent\string#1}{#2}}
+
+\def\donormalmathaccent#1%
+ {\getvalue{normalmathaccent\string#1}}
+
+%D Some precautions:
+
+\ifx\usepdffontresource\undefined
+ \def\usepdffontresource #1 {} % this will be defined elsewhere
+\fi
+
+\def\donthandleaccent #1{\expandafter\string\csname#1\endcsname\space}
+\def\donthandlecommand #1{\expandafter\string\csname#1\endcsname\space}
+\def\donthandlecharacter #1{\expandafter\string\csname#1\endcsname\space}
+
+\def\stringifyhandleaccent #1{\strchr{#1}}
+\def\stringifyhandlecommand #1{\strchr{#1}}
+\def\stringifyhandlecharacter#1{\strchr{#1}}
+
+\def\keephandleaccent #1{\expandafter\noexpand\csname#1\endcsname}
+\def\keephandlecommand #1{\expandafter\noexpand\csname#1\endcsname}
+\def\keephandlecharacter #1{\expandafter\noexpand\csname#1\endcsname}
+
+\def\handleaccent #1{\csname#1\endcsname}
+\def\handlecommand #1{\csname#1\endcsname}
+\def\handlecharacter #1{\csname#1\endcsname}
+
+\def\dontexpandencoding
+ {\let\dohandleaccent \donthandleaccent
+ \let\dohandlecommand \donthandlecommand
+ \let\dohandlecharacter\donthandlecharacter}
+
+\def\keepencodedtokens
+ {\let\dohandleaccent \keephandleaccent
+ \let\dohandlecommand \keephandlecommand
+ \let\dohandlecharacter\keephandlecharacter}
+
+\def\literateencodedtokens
+ {% \let\dohandleaccent \keephandleaccent
+ % \let\dohandlecommand \keephandlecommand
+ \let\dohandlecharacter\keephandlecharacter}
+
+\def\stringifyencodedtokens
+ {% \let\dohandleaccent \stringifyhandleaccent
+ % \let\dohandlecommand \stringifyhandlecommand
+ \let\dohandlecharacter\stringifyhandlecharacter}
+
+\unexpanded\def\uhandleaccent #1{\csname#1\endcsname}
+\unexpanded\def\uhandlecommand #1{\csname#1\endcsname}
+\unexpanded\def\uhandlecharacter#1{\csname#1\endcsname}
+
+\def\dontexpandencodedtokens
+ {\def\dohandleaccent {\uhandleaccent}%
+ \def\dohandlecommand {\uhandlecommand}%
+ \def\dohandlecharacter{\uhandlecharacter}}
+
+% no longer: \def\convertencodedtokens{\dontexpandencoding} but:
+
+\def\convertencodedtokens{\stringifyencodedtokens}
+
+% test case:
+%
+% \enableregime[cp1250]
+% \mainlanguage[cz]
+%
+% \starttext
+%
+% \title{Ϭuޯu餭 kon졺p
+% \placelist[chapter][criterium=all]
+%
+% \startbuffer
+% <chapter>
+% <title>Ϭuޯu餭 kon졺p󛱴itle>
+% </chapter>
+% \stopbuffer
+%
+% \defineXMLenvironment
+% [chapter]
+% {\defineXMLsave[title]}
+% {\expanded{\chapter{\XMLflush{title}}}}
+% \processXMLbuffer
+%
+% \setuphead[chapter][expansion=yes]
+% \defineXMLenvironment
+% [chapter]
+% {\defineXMLsave[title]}
+% {\chapter{\XMLflush{title}}}
+% \processXMLbuffer
+%
+% \stoptext
+
+%D Still valid? To be checked:
+
+\def\doignoreaccent #1#2{\string#1\string#2}%
+\def\doignorecommand #1{\string#1}
+\def\doignorecharacter#1{\string#1}
+
+\def\ignoreencoding
+ {\let\dohandleaccent \doignoreaccent
+ \let\dohandlecommand \doignorecommand
+ \let\dohandlecharacter\doignorecharacter}
+
+\appendtoks
+ \ignoreencoding
+\to \everycleanupfeatures
+
+\appendtoks
+ \keepencodedtokens
+\to \everysafeexpanded
+
+%D Now we will not redefine any more, so:
+
+\let\normaldohandleaccent \dohandleaccent
+\let\normaldohandlecharacter\dohandlecharacter
+
+\definecommand ` {\buildtextaccent\textgrave}
+\definecommand ' {\buildtextaccent\textacute}
+\definecommand r {\buildtextaccent\textring}
+\definecommand v {\buildtextaccent\textcaron}
+\definecommand u {\buildtextaccent\textbreve}
+\definecommand = {\buildtextaccent\textmacron}
+\definecommand ^ {\buildtextaccent\textcircumflex}
+\definecommand . {\buildtextaccent\textdotaccent}
+\definecommand H {\buildtextaccent\texthungarumlaut}
+\definecommand ~ {\buildtextaccent\texttilde}
+\definecommand " {\buildtextaccent\textdiaeresis}
+
+\definecommand c {\buildtextcedilla}
+\definecommand b {\buildtextmacron}
+\definecommand d {\buildtextbottomdot}
+\definecommand k {\buildtextogonek}
+
+\definemathaccent acute {\buildmathaccent\mathacute}
+\definemathaccent grave {\buildmathaccent\mathgrave}
+\definemathaccent ddot {\buildmathaccent\mathddot}
+\definemathaccent tilde {\buildmathaccent\mathtilde}
+\definemathaccent bar {\buildmathaccent\mathbar}
+\definemathaccent breve {\buildmathaccent\mathbreve}
+\definemathaccent check {\buildmathaccent\mathcheck}
+\definemathaccent hat {\buildmathaccent\mathhat}
+\definemathaccent vec {\buildmathaccent\mathvec}
+\definemathaccent dot {\buildmathaccent\mathdot}
+\definemathaccent widetilde {\buildmathaccent\mathwidetilde}
+\definemathaccent widehat {\buildmathaccent\mathwidehat}
+
+\useencoding[def] % defaults (partly simplified)
+\useencoding[acc] % accent commands
+\useencoding[raw] % simplified (incomplete)
+\useencoding[com] % a few commands
+\useencoding[cas] % case mapping, not needed in mkiv
+\useencoding[mis] % a few commands
+
+%D We preload several encodings:
+
+\ifnum\texengine=\xetexengine
+ \setupencoding[\s!default=\s!default]
+\else
+ \useencoding[ans,il2,ec,tbo,pdf,pol,qx,t5,cyr,agr] % pol and il2 will go away, not needed in mkiv, uc removed
+ \useencoding[032,033,037] % fallbacks for some unicode chars
+ \setupencoding[\s!default=ec] % was: [\s!default=\s!default]
+\fi
\protect \endinput
diff --git a/tex/context/base/enco-ini.mkiv b/tex/context/base/enco-ini.mkiv
index cbebaad9e..5fd3d9cef 100644
--- a/tex/context/base/enco-ini.mkiv
+++ b/tex/context/base/enco-ini.mkiv
@@ -1,61 +1,122 @@
%D \module
%D [ file=enco-ini,
-%D version=2007.02.19,
+%D version=2007.02.19, % 2000.12.27, % 1998.12.03,
%D title=\CONTEXT\ Encoding Macros,
%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright=\PRAGMA]
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D In the end we will cleanup enco-ini.tex!
-
-% \setinterfacecommand{setuphead}{stelleüberschriftein}
-% \section{Oeps}
-% \stelleüberschriftein[section][style=\bf]
-% \section{Oeps}
-
-% could also be a new kind of table \definecharacter {name} {char} {fallback}
-
-% \startruntimectxluacode
-% characters.context.rehash()
-% \stopruntimectxluacode
-
-% % % % \ctxlua{characters.context.rehash()}
-
-% \ctxlua {
-% characters.context.define(
-% { % letter catcodes
-% \number\texcatcodes,
-% \number\ctxcatcodes,
-% \number\notcatcodes,
-% \number\mthcatcodes,
-% \number\vrbcatcodes,
-% \number\prtcatcodes,
-% \number\xmlcatcodesn,
-% \number\xmlcatcodese,
-% \number\xmlcatcodesr,
-% \number\typcatcodesa,
-% \number\typcatcodesb,
-% },
-% { % activate catcodes
-% \number\ctxcatcodes,
-% \number\notcatcodes,
-% \number\xmlcatcodesn,
-% \number\xmlcatcodese,
-% \number\xmlcatcodesr,
-% }
-% )
-% }
+%D This is s stripped down version of th eoriginal enco-ini.tex
+%D file. For more details you might want to study the \MKII\ file
+%D but since \LUATEX\ is unicode inside we need less code.
+
+% When dealing with characters we have four cases to take into account when moving
+% from mkii to mkiv:
+
+% 1. <byte 200> => ref to slot 200 in current font
+% 2. \char 200 => ref to slot 200 in current font
+% 3. <active 200> => can (e.g.) map to another slot in current font
+% 4. \namedglyph => can map to some slot in some font
+
+% Using case 2 for special characters is doomed to fail because we are not going
+% to intercept these on the fly as happens automatically with traditional font
+% encoding handling. We could do that in a node pass but it's not worth the effort
+% because we seldom use this case in a document source.
+
+% We can consider using utf as internal format for mkii. The main reason for not
+% doing this before was that it was slow. On the other hand, it would make dealing
+% with utility files easier. However, we've now kind of frozen mkii.
+
+\writestatus{loading}{ConTeXt Encoding Macros / Initialization}
\unprotect
+%D Quite some commands are now obsolete. These nillers will disappear soon.
+
+\def\currentencoding {utf}
+\def\currentmapping {utf}
+
+\let\defaultencoding \s!default
+\let\characterencoding \s!default
+\let\nocharacterencoding\s!default
+
+\def\setupencoding [#1]{}
+\def\startmapping [#1]{\gobbleuntil\stopmapping}
+\def\startencoding [#1]{}
+\let\stopencoding \relax
+\let\startcoding \startencoding
+\let\stopcoding \relax
+\def\optimizemapping [#1]{}
+\def\enablemapping [#1]{}
+\def\enableencoding [#1]{}
+\def\enablecoding [#1]{}
+\def\fastenableencoding #1{}
+\def\enablelanguagespecifics[#1]{}
+\def\useencoding [#1]{}
+
+\let\dontexpandencoding \relax
+\let\keepencodedtokens \relax
+\let\literateencodedtokens \relax
+\let\stringifyencodedtokens \relax
+\let\dontexpandencodedtokens\relax
+\let\convertencodedtokens \relax
+\let\ignoreencoding \relax
+
+% todo:
+
+% \def\showaccents {\f!encodingprefix\s!run}
+% \def\showcharacters {\f!encodingprefix\s!run}
+% \def\showcharacterbounds {\f!encodingprefix\s!run}
+% \def\showhyphenations {\f!encodingprefix\s!run}
+% \def\showmapping {\f!encodingprefix\s!run}
+
+%D \macros
+%D {defineaccent, definecharacter, definecommand}
+
+\def\accentprefix{@acc@}
+
+\def\defineaccent#1 #2 #3 %
+ {\setevalue{\string#1}{\noexpand\dohandleaccent{\string#1}}%
+ \setvalue{\accentprefix\string#1\string#2}{#3}}
+
+\def\dohandleaccent#1#2%
+ {\csname\accentprefix\string#1\string#2\endcsname}
+
+\def\definecharacter#1 #2 %
+ {\doifnumberelse{\string#2}
+ {\setevalue{\string#1}{\utfchar{#2}}} % or {\expandafter\chardef\csname#1\endcsname#2\relax}
+ {\unexpanded\setvalue {\string#1}{#2}}}
+
+\def\definecommand#1 #2 %
+ {\unexpanded\setvalue{\string#1}{#2}}
+
+%D \macros
+%D {everyuppercase, EveryUppercase,
+%D everyuppercase, EveryUppercase,
+%D everysanitize, EverySanitize}
+
+\newevery \everyuppercase \EveryUppercase
+\newevery \everylowercase \EveryLowercase
+\newevery \everysanitize \EverySanitize
+
+%D Some saved meanings (not really needed):
+
+\let\textaccent \accent
+\let\normaltextaccent\accent
+
+%D Accent handling (try to avoid this):
+
\newbox\accenttestbox
-\unexpanded\def\dobuildtextaccent#1#2%
+\def\buildmathaccent#1%
+ {\mathaccent#1 }
+
+\unexpanded\def\buildtextaccent#1#2%
{\begingroup
\global\setbox\accenttestbox\hbox{#1}%
\scratchcounter\ctxlua{characters.charcode(\number\accenttestbox)}%
@@ -63,47 +124,405 @@
\relax#2%
\endgroup}
-\useencoding[032,033,037] % fallbacks for some unicode chars, todo
+\unexpanded\def\bottomaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode % why this align mess
+ \vtop
+ {\forgetall
+ \baselineskip\zeropoint
+ \lineskip#1%
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \lineskiplimit\zeropoint
+ \setbox0\hbox{#4}%
+ \halign
+ {##\crcr\hbox{#5}\crcr
+ \hidewidth
+ \hskip#2\wd0
+ \hskip-#3\slantperpoint % in plain 1ex * dimenless value
+ \vbox to .2ex{\box0\vss}\hidewidth
+ \crcr}}}
-\setupencoding[\s!default=ec] % for the moment keep it this way, till fonts are there
+\def\buildtextmacron {\bottomaccent{.25ex}{0}{15}{\textmacron}}
+\def\buildtextbottomdot {\bottomaccent{.25ex}{0}{5}{\textbottomdot}}
+\def\buildtextcedilla {\bottomaccent{0ex}{0}{5}{\textcedilla}}
+\def\buildtextogonek {\bottomaccent{-.1ex}{.5}{0}{\textogonek}}
+\def\buildtextbottomcomma{\bottomaccent{.15ex}{0}{5}{\tx,}}
-\protect \endinput
+\unexpanded\def\topaccent#1#2#3#4#5% down right slantcorrection accent char
+ {\dontleavehmode
+ \bgroup
+ \setbox0\hbox{#4}%
+ \setbox2\hbox{#5}%
+ \hbox to \wd2 \bgroup
+ \hss\copy2\hss
+ \hskip-\wd2
+ \hss\hskip#2\wd0\hskip-#3\slantperpoint\raise#1\hbox{#4}\hss
+ \egroup
+ \egroup}
+
+\def\buildtextgrave{\topaccent{0pt}{0}{15}{\textgrave}} % e.g.
+
+\def\definemathaccent#1 #2%
+ {\setvalue{#1}{\mathaccent#2 }}
+
+%D Math (will move):
+
+\definemathaccent acute \mathacute
+\definemathaccent grave \mathgrave
+\definemathaccent ddot \mathddot
+\definemathaccent tilde \mathtilde
+\definemathaccent bar \mathbar
+\definemathaccent breve \mathbreve
+\definemathaccent check \mathcheck
+\definemathaccent hat \mathhat
+\definemathaccent vec \mathvec
+\definemathaccent dot \mathdot
+\definemathaccent widetilde \mathwidetilde
+\definemathaccent widehat \mathwidehat
+
+% from enco-com:
+
+\def\AA{\Aring}
+\def\aa{\aring}
+\def\AE{\AEligature}
+\def\ae{\aeligature}
+\def\CC{\Ccedilla}
+\def\cc{\ccedilla}
+\def \L{\Lstroke}
+\def \l{\lstroke}
+\def \O{\Ostroke}
+\def \o{\ostroke}
+\def\OE{\OEligature}
+\def\oe{\oeligature}
+\def\SZ{\Ssharp}
+\def\sz{\ssharp}
+\def\SS{\ssharp}
+\def\IJ{\IJligature}
+\def\ij{\ijligature}
+\def \i{\dotlessi}
+\def \j{\dotlessj}
+
+% from enco-def:
+
+\def\dotlessI {I}
+\def\dotlessJ {J}
+
+\def\Ssharp {SS}
+
+\def\eszett {\ssharp}
+\def\Eszett {\Ssharp}
+
+\def\lslash {\lstroke}
+\def\Lslash {\Lstroke}
+\def\dslash {\dstroke}
+\def\Dslash {\Dstroke}
+\def\oslash {\ostroke}
+\def\Oslash {\Ostroke}
+\def\dcroat {\dstroke}
+\def\Dcroat {\Dstroke}
+
+\def\Kcedilla {\Kcommaaccent}
+\def\kcedilla {\kcommaaccent}
+\def\Lcedilla {\Lcommaaccent}
+\def\lcedilla {\lcommaaccent}
+\def\Ncedilla {\Ncommaaccent}
+\def\ncedilla {\ncommaaccent}
+\def\Rcedilla {\Rcommaaccent}
+\def\rcedilla {\rcommaaccent}
+
+\def\S {\sectionmark}
+\def\P {\paragraphmark}
+
+\def\aumlaut {\adiaeresis}
+\def\eumlaut {\ediaeresis}
+\def\iumlaut {\idiaeresis}
+\def\oumlaut {\odiaeresis}
+\def\uumlaut {\udiaeresis}
+\def\Aumlaut {\Adiaeresis}
+\def\Eumlaut {\Ediaeresis}
+\def\Iumlaut {\Idiaeresis}
+\def\Oumlaut {\Odiaeresis}
+\def\Uumlaut {\Udiaeresis}
+
+% for latex users
+
+\def\textS {\sectionmark}
+\def\textP {\paragraphmark}
+
+% for old times sake
+
+\def\textflorin{\fhook}
+\def\florin {\textflorin}
+\def\dollar {\textdollar}
+\def\pound {\textsterling}
+\def\sterling {\textsterling}
+\def\promille {\perthousand}
+\def\permille {\perthousand}
+\def\procent {\percent}
+\def\permine {\fakepermine}
+
+% some more
+
+\def\hyphen {\softhyphen}
+\def\compoundwordmark {\hyphen}
+\def\cwm {\hyphen}
+\def\nonbreakinghyphen{\hyphen}
+\def\breakinghyphen {\hyphen\prewordbreak}
-When dealing with characters we have four cases to take into account when moving
-from mkii to mkiv:
-
-1. <byte 200> => ref to slot 200 in current font
-2. \char 200 => ref to slot 200 in current font
-3. <active 200> => can (e.g.) map to another slot in current font
-4. \namedglyph => can map to some slot in some font
-
-Using case 2 for special characters is doomed to fail because we are not going
-to intercept these on the fly as happens automatically with traditional font
-encoding handling. We could do that in a node pass but it's not worth the effort
-because we seldom use this case in a document source.
-
-We can consider using utf as internal format for mkii. The main reason for not
-doing this before was that it was slow. On the other hand, it would make dealing
-with utility files easier.
-
-These are the only cases where char references are used:
-
-enco-def.tex : 46 : \definecharacter dotlessi {\char"10 }
-enco-def.tex : 47 : \definecharacter dotlessj {\char"11 }
-enco-def.tex : 54 : \definecharacter aeligature {\char26 } % "1A
-enco-def.tex : 55 : \definecharacter AEligature {\char29 } % "1D
-enco-def.tex : 58 : \definecharacter oeligature {\char27 } % "1B
-enco-def.tex : 59 : \definecharacter OEligature {\char30 } % "1E
-enco-def.tex : 61 : \definecharacter ssharp {\char25 } % "19
-enco-def.tex : 336 : \definecharacter Lstroke {\hsmash{\char32}L}
-enco-def.tex : 337 : \definecharacter lstroke {\hsmash{\char32}l}
-enco-def.tex : 338 : \definecharacter Ostroke {\char31 } % "1F
-enco-def.tex : 339 : \definecharacter ostroke {\char28 } % "1C
-enco-il2.tex : 147 : {\dontleavehmode{\char32l}}
-enco-il2.tex : 152 : \hbox to\wd0{\hss\char32L}%
-symb-eur.tex : 37 : \definesymbol [euro] [\getglyph{Euro}{\char160}]
-symb-glm.tex : 61 : \definesymbol [xleftguillemot] [\getglyph{Guil}{\char19}]
-symb-glm.tex : 62 : \definesymbol [xrightguillemot] [\getglyph{Guil}{\char20}]
-symb-glm.tex : 64 : \definesymbol [xguilsingleleft] [\getglyph{Guil}{\char14}]
-symb-glm.tex : 65 : \definesymbol [xguilsingleright] [\getglyph{Guil}{\char15}]
+% quotes
+\def\lowerleftsingleninequote {\quotesinglebase}
+\def\lowerleftdoubleninequote {\quotedblbase}
+\def\lowerrightsingleninequote {\quotesinglebase}
+\def\lowerrightdoubleninequote {\quotedblbase}
+
+\def\upperleftsingleninequote {\quoteright}
+\def\upperleftdoubleninequote {\quotedblright}
+\def\upperrightsingleninequote {\quoteright}
+\def\upperrightdoubleninequote {\quotedblright}
+
+\def\upperleftsinglesixquote {\quoteleft}
+\def\upperleftdoublesixquote {\quotedblleft}
+\def\upperrightsinglesixquote {\quoteleft}
+\def\upperrightdoublesixquote {\quotedblleft}
+
+\def\leftsubguillemot {\guilsingleleft}
+\def\rightsubguillemot {\guilsingleright}
+
+% obsolete:
+
+% \greekleftquot {[obsolete]}
+% \greekrightquot {[obsolete]}
+% \greekapostrophos {[obsolete]}
+% \greekupsilondialytika{[obsolete]}
+% \Ycaron {[obsolete]}
+% \ycaron {[obsolete]}
+
+% to be done in char-def:
+
+% \definecharacter cyrillicGUP {GUP}
+% \definecharacter cyrillicGHCRS {GHCRS}
+% \definecharacter cyrillicZHDSC {ZHDSC}
+% \definecharacter cyrillicKDSC {KDSC}
+% \definecharacter cyrillicKBEAK {KBEAK}
+% \definecharacter cyrillicKVCRS {KVCRS}
+% \definecharacter cyrillicNG {NG}
+% \definecharacter cyrillicOTLD {OTLD}
+% \definecharacter cyrillicY {Y}
+% \definecharacter cyrillicYHCRS {YHCRS}
+% \definecharacter cyrillicHDSC {HDSC}
+% \definecharacter cyrillicCHVCRS {CHVCRS}
+% \definecharacter cyrillicCHRDSC {CHRDSC}
+% \definecharacter cyrillicQ {Q}
+% \definecharacter cyrillicW {W}
+%
+% \definecharacter cyrillicgup {gup}
+% \definecharacter cyrillicghcrs {ghcrs}
+% \definecharacter cyrilliczhdsc {zhdsc}
+% \definecharacter cyrillickdsc {kdsc}
+% \definecharacter cyrillickbeak {kbeak}
+% \definecharacter cyrillickvcrs {kvcrs}
+% \definecharacter cyrillicng {ng}
+% \definecharacter cyrillicotld {otld}
+% \definecharacter cyrillicy {y}
+% \definecharacter cyrillicyhcrs {yhcrs}
+% \definecharacter cyrillichdsc {hdsc}
+% \definecharacter cyrillicchvcrs {chvcrs}
+% \definecharacter cyrillicchrdsc {chrdsc}
+% \definecharacter cyrillicq {q}
+% \definecharacter cyrillicw {w}
+
+% \definecharacter softhyphen 45
+% \definecharacter compoundwordmark 23
+
+% left-overs (some day in private unicode space, so that we can roundtrip)
+
+\unexpanded\def\textblacksquare {\dontleavehmode\hbox{\vrule\!!width.3\s!em\!!height.4\s!em\!!depth-.1\s!em}}
+\unexpanded\def\schwa {\hbox{\rotate[\c!rotation=180,\c!location=\v!high]{\hbox{e}}}}
+\unexpanded\def\schwagrave {\buildtextgrave\schwa}
+
+\unexpanded\def\normalcontrolspace{\getglyph{ComputerModernMono}{\char32}}
+\unexpanded\def\textvisiblespace {\fakecontrolspace}
+\unexpanded\def\fakecontrolspace {\let\normalcontrolspace\fakedcontrolspace}
+
+% helpers
+
+\def\fakepercent
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle0}}}
+
+\def\fakeperthousand
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle00}}}
+
+\def\fakepermine
+ {\dontleavehmode
+ \bgroup
+ \setbox\scratchbox\hbox
+ {\mathematics{+}}%
+ \hbox to \wd\scratchbox
+ {\hss\mathematics{^{\scriptscriptstyle-}\kern-.4em/\kern-.3em_{\scriptscriptstyle-}}\hss}%
+ \egroup}
+
+\def\fakedcontrolspace % can be virtual in luatex
+ {\dontleavehmode\hbox
+ {\scratchdimen.1ex%
+ \kern\scratchdimen
+ \vrule \!!width\scratchdimen \!!height5.5\scratchdimen\!!depth3\scratchdimen
+ \vrule \!!width\dimexpr.5em-4\scratchdimen\!!height -2\scratchdimen\!!depth3\scratchdimen
+ \vrule \!!width\scratchdimen \!!height5.5\scratchdimen\!!depth3\scratchdimen
+ \kern\scratchdimen}}
+
+% what to do with these:
+%
+% \definecharacter mathacute "7013
+% \definecharacter mathgrave "7012
+% \definecharacter mathddot "707F
+% \definecharacter mathtilde "707E
+% \definecharacter mathbar "7016
+% \definecharacter mathbreve "7015
+% \definecharacter mathcheck "7014
+% \definecharacter mathhat "705E
+% \definecharacter mathvec "017E
+% \definecharacter mathdot "705F
+% \definecharacter mathwidetilde "0365
+% \definecharacter mathwidehat "0362
+
+% from enco-acc:
+
+\defineaccent ^ A {\Acircumflex} \defineaccent ^ a {\acircumflex}
+\defineaccent ^ C {\Ccircumflex} \defineaccent ^ c {\ccircumflex}
+\defineaccent ^ E {\Ecircumflex} \defineaccent ^ e {\ecircumflex}
+\defineaccent ^ G {\Gcircumflex} \defineaccent ^ g {\gcircumflex}
+\defineaccent ^ H {\Hcircumflex} \defineaccent ^ h {\hcircumflex}
+\defineaccent ^ I {\Icircumflex} \defineaccent ^ i {\icircumflex} \defineaccent ^ {\i} {\icircumflex}
+\defineaccent ^ J {\Jcircumflex} \defineaccent ^ j {\jcircumflex} \defineaccent ^ {\j} {\jcircumflex}
+\defineaccent ^ O {\Ocircumflex} \defineaccent ^ o {\ocircumflex}
+\defineaccent ^ S {\Scircumflex} \defineaccent ^ s {\scircumflex}
+\defineaccent ^ U {\Ucircumflex} \defineaccent ^ u {\ucircumflex}
+\defineaccent ^ W {\Wcircumflex} \defineaccent ^ w {\wcircumflex}
+\defineaccent ^ Y {\Ycircumflex} \defineaccent ^ y {\ycircumflex}
+
+\defineaccent ` A {\Agrave} \defineaccent ` a {\agrave}
+\defineaccent ` E {\Egrave} \defineaccent ` e {\egrave}
+\defineaccent ` I {\Igrave} \defineaccent ` i {\igrave} \defineaccent ` {\i} {\igrave}
+\defineaccent ` O {\Ograve} \defineaccent ` o {\ograve}
+\defineaccent ` U {\Ugrave} \defineaccent ` u {\ugrave}
+\defineaccent ` Y {\Ygrave} \defineaccent ` y {\ygrave}
+
+\defineaccent ~ A {\Atilde} \defineaccent ~ a {\atilde}
+\defineaccent ~ I {\Itilde} \defineaccent ~ i {\itilde} \defineaccent ~ {\i} {\itilde}
+\defineaccent ~ O {\Otilde} \defineaccent ~ o {\otilde}
+\defineaccent ~ U {\Utilde} \defineaccent ~ u {\utilde}
+
+\defineaccent " A {\Adiaeresis} \defineaccent " a {\adiaeresis}
+\defineaccent " E {\Ediaeresis} \defineaccent " e {\ediaeresis}
+\defineaccent " I {\Idiaeresis} \defineaccent " i {\idiaeresis} \defineaccent " {\i} {\idiaeresis}
+\defineaccent " O {\Odiaeresis} \defineaccent " o {\odiaeresis}
+\defineaccent " U {\Udiaeresis} \defineaccent " u {\udiaeresis}
+\defineaccent " Y {\Ydiaeresis} \defineaccent " y {\ydiaeresis}
+
+\defineaccent ' A {\Aacute} \defineaccent ' a {\aacute}
+\defineaccent ' C {\Cacute} \defineaccent ' c {\cacute}
+\defineaccent ' E {\Eacute} \defineaccent ' e {\eacute}
+\defineaccent ' I {\Iacute} \defineaccent ' i {\iacute} \defineaccent ' {\i} {\iacute}
+\defineaccent ' L {\Lacute} \defineaccent ' l {\lacute}
+\defineaccent ' N {\Nacute} \defineaccent ' n {\nacute}
+\defineaccent ' O {\Oacute} \defineaccent ' o {\oacute}
+\defineaccent ' R {\Racute} \defineaccent ' r {\racute}
+\defineaccent ' S {\Sacute} \defineaccent ' s {\sacute}
+\defineaccent ' U {\Uacute} \defineaccent ' u {\uacute}
+\defineaccent ' Y {\Yacute} \defineaccent ' y {\yacute}
+\defineaccent ' Z {\Zacute} \defineaccent ' z {\zacute}
+
+\defineaccent . C {\Cdotaccent} \defineaccent . c {\cdotaccent}
+\defineaccent . E {\Edotaccent} \defineaccent . e {\edotaccent}
+\defineaccent . G {\Gdotaccent} \defineaccent . g {\gdotaccent}
+\defineaccent . I {\Idotaccent} \defineaccent . i {\idotaccent} \defineaccent . {\i} {\idotaccent}
+\defineaccent . Z {\Zdotaccent} \defineaccent . z {\zdotaccent}
+
+\defineaccent = A {\Amacron} \defineaccent = a {\amacron}
+\defineaccent = E {\Emacron} \defineaccent = e {\emacron}
+\defineaccent = I {\Imacron} \defineaccent = i {\imacron} \defineaccent = {\i} {\imacron}
+\defineaccent = O {\Omacron} \defineaccent = o {\omacron}
+\defineaccent = U {\Umacron} \defineaccent = u {\umacron}
+
+\defineaccent c C {\Ccedilla} \defineaccent c c {\ccedilla}
+\defineaccent c K {\Kcedilla} \defineaccent c k {\kcedilla}
+\defineaccent c L {\Lcedilla} \defineaccent c l {\lcedilla}
+\defineaccent c N {\Ncedilla} \defineaccent c n {\ncedilla}
+\defineaccent c R {\Rcedilla} \defineaccent c r {\rcedilla}
+\defineaccent c S {\Scedilla} \defineaccent c s {\scedilla}
+\defineaccent c T {\Tcedilla} \defineaccent c t {\tcedilla}
+
+\defineaccent H O {\Ohungarumlaut} \defineaccent H o {\ohungarumlaut}
+\defineaccent H u {\uhungarumlaut} \defineaccent H U {\Uhungarumlaut}
+
+\defineaccent k A {\Aogonek} \defineaccent k a {\aogonek}
+\defineaccent k E {\Eogonek} \defineaccent k e {\eogonek}
+\defineaccent k I {\Iogonek} \defineaccent k i {\iogonek}
+\defineaccent k U {\Uogonek} \defineaccent k u {\uogonek}
+
+\defineaccent r A {\Aring} \defineaccent r a {\aring}
+\defineaccent r U {\Uring} \defineaccent r u {\uring}
+
+\defineaccent u A {\Abreve} \defineaccent u a {\abreve}
+\defineaccent u E {\Ebreve} \defineaccent u e {\ebreve}
+\defineaccent u G {\Gbreve} \defineaccent u g {\gbreve}
+\defineaccent u I {\Ibreve} \defineaccent u i {\ibreve} \defineaccent u {\i} {\ibreve}
+\defineaccent u O {\Obreve} \defineaccent u o {\obreve}
+\defineaccent u U {\Ubreve} \defineaccent u u {\ubreve}
+
+\defineaccent v C {\Ccaron} \defineaccent v c {\ccaron}
+\defineaccent v D {\Dcaron} \defineaccent v d {\dcaron}
+\defineaccent v E {\Ecaron} \defineaccent v e {\ecaron}
+\defineaccent v L {\Lcaron} \defineaccent v l {\lcaron}
+\defineaccent v N {\Ncaron} \defineaccent v n {\ncaron}
+\defineaccent v R {\Rcaron} \defineaccent v r {\rcaron}
+\defineaccent v S {\Scaron} \defineaccent v s {\scaron}
+\defineaccent v T {\Tcaron} \defineaccent v t {\tcaron}
+\defineaccent v Z {\Zcaron} \defineaccent v z {\zcaron}
+
+% from enco-mis:
+
+\def\fakepercent
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle0}}}
+
+\def\fakeperthousand
+ {\mathematics{^{\scriptscriptstyle0}\kern-.25em/\kern-.2em_{\scriptscriptstyle00}}}
+
+\def\fakepermine
+ {\dontleavehmode
+ \bgroup
+ \setbox\scratchbox\hbox
+ {\mathematics{+}}%
+ \hbox to \wd\scratchbox
+ {\hss
+ \mathematics{^{\scriptscriptstyle-}\kern-.4em/\kern-.3em_{\scriptscriptstyle-}}%
+ \hss}%
+ \egroup}
+
+%D A smaller and bolder variant, more like the math and monospaced ones.
+
+\def\fakeunderscore
+ {\leavevmode\hbox
+ {\setbox\scratchbox\hbox{(}%
+ \scratchdimen.2\dp\scratchbox
+ \setbox\scratchbox\hbox{\space}%
+ \vrule
+ \!!depth \scratchdimen
+ \!!width \wd\scratchbox
+ \!!height\zeropoint}}
+
+
+\def\fakeunderscores{\let\_\fakeunderscore}
+\def\textunderscores{\let\_\textunderscore}
+
+\textunderscores
+
+\ifx\mathunderscore\undefined \let\mathunderscore\fakeunderscore \fi
+\ifx\textunderscore\undefined \let\textunderscore\fakeunderscore \fi
+
+\unexpanded\def\normalunderscore{\ifmmode\mathunderscore\else\textunderscore\fi}
+
+\let\_\normalunderscore
+
+\protect \endinput
diff --git a/tex/context/base/enco-ini.tex b/tex/context/base/enco-ini.tex
deleted file mode 100644
index 4c85bac5b..000000000
--- a/tex/context/base/enco-ini.tex
+++ /dev/null
@@ -1,1228 +0,0 @@
-%D \module
-%D [ file=enco-ini,
-%D version=2000.12.27, % 1998.12.03,
-%D title=\CONTEXT\ Encoding Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D Quite some code will be moved to the mk files once we're ready
-%D for it.
-
-%D This module is a reimplementation of the module that handled
-%D composed characters and non \ASCII\ characters. The changed
-%D are not that fundamental, and mainly concerns moving
-%D definitions of specific glyphs and accents to other files as
-%D well as moving plain handling of accents to this module
-%D instead of overloading plain \TEX\ commands.
-
-%D Patterns are kind of mixed with font encodings and
-%D mappings. Alas.
-
-\ifx\synchronizepatterns\undefined \let\synchronizepatterns\relax \fi
-
-%D While dealing with input (the text source) and output (the
-%D glyphs), encoding comes into view. To summarize a few:
-%D
-%D \startitemize
-%D \item Bytes in the input file are mapped to an internal
-%D representation. An~\type {a} often stays an~\type {a},
-%D but~\type {\"e} can become either one code or become
-%D two codes (ending in overlapping glyphs).
-%D \item Characters can be made active and mapped onto another
-%D character.
-%D \item When changing case, characters are mapped onto
-%D themselves, their case||counterpart or a reasonable
-%D alternative, like~\"e onto~e.
-%D \item Single character representations in a \DVI\ file can
-%D be mapped onto one or more characters, either of not
-%D in more than one font file (virtual fonts).
-%D \item In the final format, fonts collections can be
-%D partially embedded, thereby losing the one||to||one
-%D relation between several instances of one font.
-%D \item For special purposes, individual characters should be
-%D mapped onto a dedicated encoding vector, for instance
-%D \PDF\ document encoding.
-%D \stopitemize
-%D
-%D These and other kind of mappings are to be dealt with, and
-%D the exact way of dealing often depends on the language to be
-%D typeset.
-
-\writestatus{loading}{Context Encoding Macros (ini)}
-
-\unprotect
-
-\startmessages dutch library: encodings
- title: encoding
- 1: codering --
- 2: codering -- wordt geladen
- 3: onbekende codering --
-\stopmessages
-
-\startmessages english library: encodings
- title: encoding
- 1: coding --
- 2: coding -- is loaded
- 3: unknown coding --
-\stopmessages
-
-\startmessages german library: encodings
- title: Kodierung
- 1: Kodierung --
- 2: Kodierung -- ist geladen
- 3: Unbekannte Kodierung --
-\stopmessages
-
-\startmessages czech library: encodings
- title: kodovani
- 1: kodovani --
- 2: je nacteno kodovani --
- 3: nezname kodovani --
-\stopmessages
-
-\startmessages italian library: encodings
- title: codifica
- 1: codifica --
- 2: codifica -- caricata
- 3: codifica sconosciuta --
-\stopmessages
-
-\startmessages norwegian library: encodings
- title: koding
- 1: koding --
- 2: koding -- er lest inn
- 3: ukjent koding --
-\stopmessages
-
-\startmessages romanian library: encodings
- title: codificari
- 1: codificarea --
- 2: codificarea -- este Encarcata
- 3: codificarea -- este necunoscuta
-\stopmessages
-
-\startmessages french library: encodings
- title: encodage
- 1: encodage --
- 2: l'encodage -- est chargé
- 3: encodage -- inconnu
-\stopmessages
-
-%D First we define a few local or not yet initialized constants.
-
-\def\@map@{@m@ap@} % mapping prefix
-\def\@fha@{@f@ha@} % font prefix
-\def\@cas@{@c@as@} % casecom prefix
-
-\ifx\currentlanguage\undefined \let\currentlanguage\s!en \fi
-
-%D \macros
-%D {setupencoding}
-%D
-%D The following setup command is used to tune encoding
-%D handling.
-
-\def\setupencoding
- {\dosingleargument\dosetupencoding}
-
-\def\dosetupencoding[#1]%
- {\getparameters[\??ec][#1]%
- \edef\defaultencoding
- {\ifx\@@ecdefault\empty\s!default\else\@@ecdefault\fi}}
-
-%D \macros
-%D {useencoding}
-%D
-%D Encodings things are defined in separate files and are
-%D loaded only once, using:
-%D
-%D \showsetup{useencoding}
-
-\def\douseencoding#1%
- {\doifundefined{\c!file\f!encodingprefix#1}%
- {\letvalue{\c!file\f!encodingprefix#1}\empty
- \makeshortfilename[\truefilename{\f!encodingprefix#1}]%
- \startreadingfile
- \readsysfile\shortfilename
- {\showmessage\m!encodings2{#1}}
- {\showmessage\m!encodings3{#1}}%
- \stopreadingfile}}
-
-\def\useencoding[#1]%
- {\processcommalist[#1]\douseencoding}
-
-%D \macros
-%D {startmapping,enablemapping}
-%D
-%D In order to process patterns, convert from lower to
-%D uppercase and vise versa and some more, we provide a
-%D mechanism to define mappings. The first real application
-%D of this command was:
-%D
-%D \starttyping
-%D \startmapping [something]
-%D \definecasemap 165 181 165
-%D \definecasemap 171 187 171
-%D ...
-%D \defineuppercasecom \i {I}
-%D \defineuppercasecom \l \L
-%D \definelowercasecom \AE \ae
-%D ...
-%D \stopmapping
-%D \stoptyping
-%D
-%D So, character 165 becomes 181 in uppercase and 165 in
-%D lowercase. A mapping is activated with \type {\enablemapping}.
-
-\def\startsavingmappingtoks#1%
- {\bgroup
- \edef\charactermapping{@#1@}%
- \checkmappingtoks
- \setmappingtoks
- \the\mappingtoks}
-
-\def\stopsavingmappingtoks
- {\global\mappingtoks\emptytoks
- \dostepwiserecurse{0}{255}\plusone
- {\edef\@@expanded
- {\the\mappingtoks
- \ifnum\recurselevel>127
- \noexpand\settoletterunlessactive{\recurselevel}%
- \fi
- \lccode\recurselevel\ifnum\lccode\recurselevel=\zerocount\zerocount\else\space\the\lccode\recurselevel\space\fi
- \uccode\recurselevel\ifnum\uccode\recurselevel=\zerocount\zerocount\else\space\the\uccode\recurselevel\space\fi
- \ifnum\sfcode\recurselevel=\plusthousand\else\sfcode\recurselevel=\the\sfcode\recurselevel\space\fi
- }%
- \global\mappingtoks\expandafter{\@@expanded}}%
- \egroup
- \let\enabledmapping\empty
- \enablemapping[\currentmapping]}
-
-\def\startmapping[#1]%
- {\startsavingmappingtoks{#1}}
-
-\def\stopmapping
- {\stopsavingmappingtoks}
-
-\def\optimizemapping[#1]%
- {\startsavingmappingtoks{#1}%
- % nothing, just an automatic cleanup
- \stopsavingmappingtoks
- % we need to resync
- %\let\enabledmapping\relax
- }%\enablemapping[\currentmapping]}
-
-\def\setmappingtoks
- {\@EA\let\@EA\mappingtoks\csname\@map@\charactermapping\endcsname
- \@EA\let\@EA\casecomtoks\csname\@cas@\charactermapping\endcsname}
-
-\def\checkmappingtoks
- {\ifundefined{\@map@\charactermapping}%
- \expandafter\newtoks\csname\@map@\charactermapping\endcsname
- \fi
- \ifundefined{\@cas@\charactermapping}%
- \expandafter\newtoks\csname\@cas@\charactermapping\endcsname
- \fi}
-
-\def\definecasemap #1 #2 #3 % code lower upper
- {\doifelse{#2}{to}
- {\presetcaserange{#1}{#3}}
- {\lccode#1=#2\relax
- \uccode#1=#3\relax}%
- \ignorespaces}
-
-%D Saves a few tokens
-
-\def\definecaseswap #1 #2 % lower upper
- {\lccode#1=#1\relax
- \uccode#2=#2\relax
- \lccode#2=#1\relax
- \uccode#1=#2\relax
- \ignorespaces}
-
-\def\definecaseself #1 % lower=upper=self
- {\lccode#1=#1\relax
- \uccode#1=#1\relax
- \ignorespaces}
-
-%D Watch the \type {\definecasemap 127 to 255} option!
-%D Dedicated to Taco there is also:
-
-\def\definecasemaps #1 to #2 lc #3 uc #4 % from to lc+ uc+
- {\dostepwiserecurse{#1}{#2}\plusone
- {\scratchcounter\recurselevel\advance\scratchcounter#3\lccode\recurselevel=\scratchcounter
- \scratchcounter\recurselevel\advance\scratchcounter#4\uccode\recurselevel=\scratchcounter}%
- \ignorespaces}
-
-%D This can be used like:
-%D
-%D \starttyping
-%D \definecasemaps 128 to 156 lc 32 uc 0
-%D \definecasemaps 160 to 188 lc -32 uc 0
-%D \definecasemaps 160 to 188 lc -32 uc 0
-%D \definecasemaps 192 to 255 lc 32 uc 0
-%D \stoptyping
-%D
-%D and saves a lot of typing (copying).
-
-\def\resetcaserange #1 to #2
- {\dostepwiserecurse{#1}{#2}\plusone
- {\lccode\recurselevel\zerocount
- \uccode\recurselevel\zerocount}%
- \ignorespaces}
-
-\def\presetcaserange#1#2% could be pre-expanded
- {\dostepwiserecurse{#1}{#2}\plusone
- {\lccode\recurselevel=\recurselevel
- \uccode\recurselevel=\recurselevel}%
- \ignorespaces}
-
-\def\setcasemap #1 #2 #3 %
- {\settoletterunlessactive{#1}%
- \lccode #1=#2
- \uccode #1=#3 }
-
-\def\setcaseswap #1 #2 %
- {\settoletterunlessactive{#1}%
- \settoletterunlessactive{#2}%
- \lccode #1=#1
- \uccode #2=#2
- \lccode #2=#1
- \uccode #1=#2 }
-
-\def\setcaseself #1 %
- {\settoletterunlessactive{#1}%
- \lccode #1=#1
- \uccode #1=#1 }
-
-\def\definespacemap #1 #2 % code sfcode
- {\sfcode#1=#2%
- \ignorespaces}
-
-\def\setspacemap #1 #2 %
- {\settootherunlessactive{#1}%
- %\lccode #1=\zerocount
- %\uccode #1=\zerocount
- \sfcode #1=#2 }
-
-\def\defineuppercasecom#1#2%
- {\global\casecomtoks\expandafter{\the\casecomtoks\setuppercasecom#1{#2}}%
- \ignorespaces}
-
-\def\definelowercasecom#1#2%
- {\global\casecomtoks\expandafter{\the\casecomtoks\setlowercasecom#1{#2}}%
- \ignorespaces}
-
-\let\setuppercasecom\gobbletwoarguments
-\let\setlowercasecom\gobbletwoarguments
-
-\def\setcasecom#1#2{\def#1{#2}}
-
-\let\enabledmapping\empty % indirect, needed to handle default too
-
-\def\enablemapping[#1]%
- {\edef\charactermapping{@#1@}%
- \ifx\enabledmapping\charactermapping \else
- \doifdefined{\@map@\charactermapping}
- {%\expandafter\showthe\csname\@map@\charactermapping\endcsname\endcsname
- \the\csname\@map@\charactermapping\endcsname}%
- % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
- \edef\enabledmapping{\charactermapping}%
- \enablelanguagespecifics[\currentlanguage]% new
- % \edef\enabledmapping{\charactermapping\currentlanguage}% can be comma list
- \fi
- \synchronizepatterns}
-
-% on behalf of font switching:
-
-\def\fastenablemapping#1%
- {\edef\charactermapping{@#1@}%
- \ifx\enabledmapping\charactermapping \else
- \@EA\ifx\csname\@map@\charactermapping\endcsname\relax\else
- \the\csname\@map@\charactermapping\endcsname
- \fi
- % == \the\executeifdefined{\@map@\charactermapping}\emptytoks
- \let\enabledmapping\charactermapping
- \enablelanguagespecifics[\currentlanguage]% to faster
- \fi}
-
-%D This macro wil be implemented in \type {lang-ini.tex}.
-
-\ifx\enablelanguagespecifics\undefined
- \def\enablelanguagespecifics[#1]{}
-\fi
-
-%D Further on we have to take some precautions when dealing
-%D with special characters like~\type{~}, \type{_}
-%D and~\type{^}, so let us define ourselve some handy macros
-%D first.
-
-\def\protectfontcharacters
- {\edef\unprotectfontcharacters
- {\catcode`\noexpand ~=\the\catcode`~\relax
- \catcode`\noexpand _=\the\catcode`_\relax
- \catcode`\noexpand ^=\the\catcode`^\relax}%
- \catcode`~=\@@letter
- \catcode`_=\@@letter
- \catcode`^=\@@letter\relax}
-
-%D The completeness of the Computer Modern Roman typefaces
-%D makes clear how incomplete other faces are. To honour 7~bit
-%D \ASCII, these fonts were designed using only the first 127
-%D values of the 256 ones that can be presented by one byte.
-%D Nowadays 8~bit character codings are more common, mainly
-%D because they permit us to predefine some composed
-%D characters, which are needed in most european languages.
-%D
-%D Supporting more than the standard \TEX\ encoding vector
-%D |<|which in itself is far from standard and differs per
-%D font|>| puts a burden on the fonts mechanism. The \CONTEXT\
-%D mechanism is far from complete, but can handle several
-%D schemes at once. The main problem lays in the accented
-%D characters and ligatures like~ff, although handling
-%D ligatures is not the responsibility of this module.
-%D
-%D By default, we use \PLAIN\ \TEX's approach of placing
-%D accents. All other schemes sooner or later give problems
-%D when we distribute \DVI||files are distributed across
-%D machines and platforms. Nevertheless, we have to take care
-%D of different encoding vectors, which tell us where to find
-%D the characters we need. This means that all kind of
-%D character placement macro's like \type{\"} and \type{\ae}
-%D have to be implemented and adapted in a way that suits
-%D these vectors.
-%D
-%D The main difference between different vector is the way
-%D accents are ordered and/or the availability of prebuilt
-%D accented characters. Accented characters can for instance be
-%D called for by sequences like \type{\"e}. Here the \type{\"}
-%D is defined as:
-%D
-%D \starttyping
-%D \def\"#1{{\accent"7F #1}}
-%D \stoptyping
-%D
-%D This macro places the accent \accent"7F {} on top of an~e
-%D gives \"e. Some fonts however can have prebuild accents and
-%D use a more direct approach like
-%D
-%D \starttyping
-%D \def\"#1{\if#1e\char 235\else ... \fi}
-%D \stoptyping
-%D
-%D The latter approach is not used in \CONTEXT, because we
-%D store relevant combinations of accents and characters in
-%D individual macros.
-
-%D We define character substitutes and commands with definition
-%D commands like:
-%D
-%D \starttyping
-%D \startcoding[texnansi]
-%D
-%D \defineaccent " a 228
-%D \defineaccent ^ e 234
-%D \defineaccent ' {\dotlessi} 237
-%D
-%D \definecharacter ae 230
-%D \definecharacter oe 156
-%D
-%D \definecommand b \texnansiencodedb
-%D \definecommand c \texnansiencodedc
-%D
-%D \stopcoding
-%D \stoptyping
-%D
-%D The last argument of \type{\defineaccent} and
-%D \type{\definecharacter} tells \TEX\ the position of the
-%D accented character in the encoding vector. In order to
-%D complish this, we tag each implementation with the character
-%D coding identifier. We therefore need two auxiliary variables
-%D \type{\characterencoding} and \type{\nocharacterencoding}. These
-%D contain the current and default encoding vectors and both
-%D default to the \PLAIN\ one.
-
-\edef\characterencoding {@\s!default @}
-\edef\nocharacterencoding {@\s!default @}
-\edef\charactermapping {@\s!default @}
-
-% todo, else \d j == \dj, print file and check
-
-\def\accentprefix {}%{*}
-\def\commandprefix {}%{=}
-\def\characterprefix{}%{-}
-
-%D \macros
-%D {startcoding, reducetocoding}
-%D
-%D Before we can redefine accents and special characters, we
-%D have to tell \CONTEXT\ what encoding is in force. The next
-%D command is responsible for doing this and also takes care of
-%D the definition of the recoding commands. We use the \type
-%D {\start}||\type {\stop}||commands for definitions and the
-%D \type {\reduceto}||command for local switching to
-%D simplified commands.
-
-% etex : \ifcsname
-
-\def\justhandleaccent#1#2% \empty makes #2={} save % no \unexpanded
- {\ifundefined{\accentprefix\characterencoding#1\string#2\empty}%
- #2%
- \else
- \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
- \fi}
-
-\def\justhandlecommand#1% % no \unexpanded, otherwise pdfdoc will fail
- {\ifundefined{\commandprefix\characterencoding#1}% as well as hyph patterns
- #1%
- \else
- \csname\commandprefix\characterencoding#1\endcsname
- \fi}
-
-\def\enableencoding
- {\dodoubleempty\doenableencoding}
-
-\def\doenableencoding[#1][#2]% main fallback
- {\iffirstargument\edef\characterencoding{@#1@}\fi
- \edef\nocharacterencoding{@\ifsecondargument#2\else\s!default\fi @}%
- \synchronizepatterns}
-
-\edef\xnocharacterencoding{@\s!default @}
-
-\def\fastenableencoding#1%
- {\edef\characterencoding{@#1@}%
- \let\nocharacterencoding\xnocharacterencoding}
-
-\def\startencoding
- {\dodoubleempty\dostartencoding}
-
-\def\dostartencoding[#1][#2]% encoding regime
- {%\showmessage\m!encodings1{#1}%
- \pushmacro\characterencoding
- \pushmacro\currentregime
- \pushmacro\dohandleaccent % still needed?
- \pushmacro\dohandlecommand % still needed?
- \pushmacro\doautosetregime
- \let\dohandleaccent\donthandleaccent % still needed?
- \let\dohandlecommand\donthandlecommand % still needed?
- %let\definesortkey\savesortkey
- \edef\characterencoding{@#1@}%
- \doifelsenothing{#2}%
- {\let\doautosetregime\gobbletwoarguments}
- {\def\currentregime{#2}}}
-
-\def\stopencoding
- {\popmacro\doautosetregime
- \popmacro\dohandlecommand % still needed?
- \popmacro\dohandleaccent % still needed?
- \popmacro\currentregime
- \popmacro\characterencoding}
-
-% probably obsolete (hm, not yet)
-
-\def\reducetocoding[#1]% use grouped!
- {\doifsomething{#1}
- {\let\dohandleaccent \justhandleaccent
- \let\dohandlecommand\justhandlecommand
- \enableencoding[#1]%
- \enablelanguagespecifics[\currentlanguage]}}
-
-\let\startcoding \startencoding
-\def\stopcoding {\stopencoding}
-\let\enablecoding \enableencoding
-
-%D The use of these macros are not limited to font
-%D definition files, but may also be used when loading
-%D patterns.
-
-%D \macros
-%D {definesortkey,flushsortkeys,flushsortkey}
-%D
-%D Yet another definition concerns sorting of indexes and
-%D lists.
-%D
-%D \starttyping
-%D \definesortkey {\'e} {e} {a} {\'e}
-%D \stoptyping
-%D
-%D The first argument denotes the string to be treated. The
-%D second argument is the raw replacement, while the third
-%D argument determines the sort order given the replacement.
-%D The last argument is used as entry in the index (a, b, etc).
-%D
-%D The keys can be flushed using \type {\flushsortkeys}
-%D which in turn results in a sequence of calls to \type
-%D {\flushsortkey}, a macro taking 4~arguments.
-%D
-%D This mechanism is currently being tested and subjected to
-%D changes! Obsolete:
-
-\let\definesortkey\gobblefourarguments
-\let\savesortkey \gobblefourarguments
-\let\flushsortkeys\relax
-\let\flushsortkey \relax
-
-%D \macros
-%D {defineaccent, definecharacter, definecommand}
-%D
-%D The actual definition of accents, special characters and
-%D commands is done with the next three commands.
-
-\def\defineaccent
- {\protectfontcharacters
- \dodefineaccent}
-
-\def\dodefineaccent#1 #2 %
- {\unprotectfontcharacters
- \dododefineaccent#1 #2 }
-
-\def\dododefineaccent#1 #2 #3 %
- {\setvalue{#1}{\dohandleaccent{#1}}%
- \doifnumberelse{\string#3}
- {\setvalue{\accentprefix\characterencoding#1\string#2}{\char#3 }} % space added
- {\setvalue{\accentprefix\characterencoding#1\string#2}{#3}}}
-
-\def\dohandleaccent#1#2%
- {\ifcsname\accentprefix\characterencoding#1\string#2\empty\endcsname
- \csname\accentprefix\characterencoding#1\string#2\empty\endcsname
- \else\ifcsname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
- \csname\accentprefix\nocharacterencoding#1\string#2\empty\endcsname
- \else\ifcsname\accentprefix\characterencoding#1\endcsname
- \csname\accentprefix\characterencoding#1\endcsname{#2}%
- \else%\ifcsname\accentprefix\nocharacterencoding#1\endcsname
- \csname\accentprefix\nocharacterencoding#1\endcsname{#2}%
-% \else
-% \donormaltextaccent{#1}{#2}%
- \fi\fi\fi}%\fi}
-
-%D In patterns, characters have to be bytes. These will be
-%D mapped onto the compact pattern arrays.
-
-\let\normalpatterns \patterns
-\let\normalhyphenation\hyphenation
-
-\def\patternchar#1 {\rawcharacter{#1}} % space is part of character definition !
-
-% \ifx \enablepatterntokens\undefined
-% \def\handlepatterntoken#1]{\csname#1\endcsname}
-% \fi
-
-% we need to postpone catcode changes, e.g. hr patterns
-% have \catcode" -> which fails when " is letter
-
-\def\pathypsettings
- {\ifx \enablepatterntokens\undefined
- \defineactivecharacter [ {\handlepatterntoken}%
- \else
- \enablepatterntokens
- \fi
- \let\dochar\thechr
- \lccode16=16 % brrr, extra quote in ec (turkish)
- \lccode17=17 % brrr, extra quote in ec (turkish)
- \lccode`\-=`\-
- \lccode`\'=`\'
- \lccode`\"=`\"
- \relax}
-
-\def\patterns {\pathypsettings\normalpatterns }
-\def\hyphenation{\pathypsettings\normalhyphenation}
-
-%D Because we don't want to use the second command grouped, we
-%D (re)define it as follows:
-
-\def\hyphenation
- {\begingroup\def\hyphenation{\normalhyphenation{\the\scratchtoks}\endgroup}%
- \pathypsettings\afterassignment\hyphenation\scratchtoks=}
-
-%D This is not needed for patterns because they are loaded grouped
-%D anyway and it saves us an assignment. Can go ... no longer
-%D shared patterns.
-
-\def\startpatternloading#1#2#3% % we should use \everypatternloading
- {\startreadingfile
- \bgroup
- % let's get rid of interfering stuff
- \let\everyjob\scratchtoks
- \let\message \gobbleoneargument
- % we want direct characters
- \let\char\patternchar
- \doifelsenothing{#2}{\enableencoding[ec]}{\enableencoding[#2]}%
- \doifelsenothing{#3}{\enablemapping [ec]}{\enablemapping [#3]}%
- \expanded{\doifinstring{\f!languageprefix}{#1}}
- {\ifx \enablepatternxml\undefined \else
- \enablepatternxml
- \fi}%
- \let\dohandleaccent\normaldohandleaccent}
-
-\def\stoppatternloading
- {\egroup
- \stopreadingfile}
-
- \def\thechr#1{\char#1 } % just in case \relax interferes
-\unexpanded\def\numchr#1{\char#1\relax}
-\unexpanded\def\strchr#1{\csname#1\endcsname}
-
-\let\dochar\numchr
-
-\def\startdirectcharacters {\pushmacro\dochar \let\dochar\thechr}
-\def\stopdirectcharacters {\popmacro \dochar}
-
-\def\definecharacter#1 #2 %
- {\ifundefined{#1}\setvalue{#1}{\dohandlecharacter{#1}}\fi
- \doifnumberelse{\string#2}
- {\setvalue{\characterprefix\characterencoding\string#1}{\dochar{#2}}%
- \doautosetregime{#1}{#2}}
- {\setvalue{\characterprefix\characterencoding\string#1}{#2}}}
-
-\def\dohandlecharacter#1%
- {\csname\characterprefix\ifcsname\characterprefix\characterencoding#1\endcsname
- \characterencoding\else\nocharacterencoding\fi#1\endcsname}
-
-% \def\fallbackpatternchar{x} % makes no sense, duplicate patterns
-
-\def\defaultcharacter#1%
- {\csname\characterprefix\nocharacterencoding\strippedcsname#1\endcsname}
-
-%D Instead of numbers, a command may be entered.
-
-\def\definecommand#1 #2 %
- {\setvalue{\string#1}{\dohandlecommand{#1}}%
- %\redefinecommand #1 % just to be sure
- \setvalue{\commandprefix\characterencoding\string#1}{#2}}
-
-%D Here we see that redefining accents is characters is more
-%D or less the same as redefining commands. We also could have
-%D said:
-%D
-%D \starttyping
-%D \def\defineaccent#1 #2 {\definecommand#1\string#2 \char}
-%D \def\definecharacter#1 {\definecommand#1 \char}
-%D \stoptyping
-
-%D \macros
-%D {defineaccentcommand}
-%D
-%D When needed, one can overload the default positions of the
-%D accents. The \PLAIN\ \TEX\ defaults are:
-%D
-%D \starttyping
-%D \defineaccentcommand ` 18
-%D \defineaccentcommand ' 19
-%D \defineaccentcommand v 20
-%D \defineaccentcommand u 21
-%D \defineaccentcommand = 22
-%D \defineaccentcommand ^ 94
-%D \defineaccentcommand . 95
-%D \defineaccentcommand H 125 % "7D
-%D \defineaccentcommand ~ 126 % "7E
-%D \defineaccentcommand " 127 % "7F
-%D \stoptyping
-
-\def\defineaccentcommand
- {\protectfontcharacters
- \dodefineaccentcommand}
-
-\def\dodefineaccentcommand#1 #2 % \string toegevoegd
- {\doifnumberelse{\string#2}
- {\setvalue{\accentprefix\characterencoding\string#1}##1{{\accent#2 ##1}}}
- {\setvalue{\accentprefix\characterencoding\string#1}##1{{#2##1}}}%
- \unprotectfontcharacters}
-
-%D We don't have to define them for the default \PLAIN\ case.
-%D Commands may be used instead of character codes.
-
-%D \macros
-%D {normalaccent,normalchar}
-%D
-%D Accents are either placed by \TEX's \type {\accent}
-%D primitive, or part of the glyph. By default the former
-%D method is used, unless overruled in the encoding
-%D definitions.
-
-\let\normalchar =\char
-\let\normalaccent=\accent
-
-%D \macros
-%D {redefinecommand}
-%D
-%D Redefinition of encoding dependant commands like \type{\b}
-%D and \type{\c} can be triggered by:
-%D
-%D \starttyping
-%D \redefinecommand b % something math
-%D \redefinecommand c % something math
-%D \stoptyping
-%D
-%D Handling of characters is easier than handling accents
-%D because here we don't have to take care of arguments. We
-%D just call for the right glyph in the right place.
-%D
-%D The \type{\next} construction permits handling of commands
-%D that take arguments. This means that we can use this
-%D command to redefine accent handling commands too
-%D (although today the next is not needed any longer in test
-%D macros).
-
-\def\redefinecommand#1 %
- {% no \unexpanded, else pdfdoc fails
- \setvalue{\string#1}{\dohandlecommand{#1}}}%
-
-\def\dohandlecommand#1%
- {\csname\commandprefix
- \ifcsname\commandprefix\characterencoding#1\endcsname
- \characterencoding
- \else
- \nocharacterencoding
- \fi
- #1\endcsname}
-
-%D \macros
-%D {currentencoding, currentmapping}
-%D
-%D When we show 'm, we don't want to see the protection
-%D measures.
-
-\def\currentencoding{\@EA\dopureencodingname\characterencoding}
-\def\currentmapping {\@EA\dopureencodingname\charactermapping }
-
-\def\dopureencodingname @#1@{#1}
-
-\def\pureencodingname#1{\@EA\dopureencodingname#1}
-
-%D \macros
-%D {showaccents, showcharacters,
-%D showcharacterbounds, showhyphenations}
-%D
-%D Encoding is a tricky business. Therefore we provide a
-%D a few macros that show most of the characters involved. The
-%D next two tables show the result of \type {\showaccents}.
-%D
-%D \placetable
-%D {The special glyphs in default encoding.}
-%D {\showaccents}
-%D
-%D \placetable
-%D {The special glyphs in texnansi encoding.}
-%D {\switchtobodyfont[lbr]\showaccents}
-%D
-%D The command
-%D
-%D \starttyping
-%D \showhyphenations{doordefini\"eren}
-%D \stoptyping
-%D
-%D can be used to check the correct loading of hyphenation
-%D patterns.
-
-\fetchruntimecommand \showaccents {\f!encodingprefix\s!run}
-\fetchruntimecommand \showcharacters {\f!encodingprefix\s!run}
-\fetchruntimecommand \showcharacterbounds {\f!encodingprefix\s!run}
-\fetchruntimecommand \showhyphenations {\f!encodingprefix\s!run}
-\fetchruntimecommand \showmapping {\f!encodingprefix\s!run}
-
-%D \macros
-%D {everyuppercase, EveryUppercase,
-%D everyuppercase, EveryUppercase}
-%D
-%D When we want to uppercase strings of characters, we have to
-%D take care of those characters that have a special meaning or
-%D are only accessible by means of macros. The next hack was
-%D introduced when Tobias Burnus started translating head and
-%D label texts into spanish and italian. The first application
-%D of this token register therefore can be found in the module
-%D that deals with these texts.
-
-\newevery \everyuppercase \EveryUppercase
-\newevery \everylowercase \EveryLowercase
-
-%D This magic trick maps takes care of mapping from lower to
-%D upper case and reverse.
-
-\def\reloadmapping{\the\executeifdefined{\@cas@\charactermapping}\emptytoks}
-
-\appendtoks\let\setuppercasecom\setcasecom\to\everyuppercase
-\appendtoks\let\setlowercasecom\setcasecom\to\everylowercase
-
-\appendtoks\reloadmapping\to\everyuppercase % slow, will be sped up
-\appendtoks\reloadmapping\to\everylowercase % slow, will be sped up
-
-\newtoks\everyULmap
-
-\appendtoks\let\remapcase\remapuppercase\the\everyULmap\to\everyuppercase
-\appendtoks\let\remapcase\remaplowercase\the\everyULmap\to\everylowercase
-
-\let\remapcase\gobbletwoarguments
-
-\def\remapuppercase#1#2{\let#2#1} % more efficient:
-\def\remaplowercase#1#2{\let#1#2} \let\remaplowercase\let
-
-\def\defineLCcharacter #1 #2 %
- {\appendtoks\let\to\everylowercase
- \@EA\appendtoks\csname#1\endcsname\to\everylowercase
- \@EA\appendtoks\csname#2\endcsname\to\everylowercase}
-
-\def\defineUCcharacter #1 #2 %
- {\appendtoks\let\to\everyuppercase
- \@EA\appendtoks\csname#1\endcsname\to\everyuppercase
- \@EA\appendtoks\csname#2\endcsname\to\everyuppercase}
-
-\def\defineULcharacter #1 #2 %
- {\appendtoks\remapcase\to\everyULmap
- \@EA\appendtoks\csname#1\endcsname\to\everyULmap
- \@EA\appendtoks\csname#2\endcsname\to\everyULmap}
-
-% slightly faster with \smallcapped's but far more hash and stringspace
-%
-% \newif\ifuppercase \appendtoks\uppercasetrue\to\everyuppercase
-% \newif\iflowercase \appendtoks\lowercasetrue\to\everylowercase
-%
-% \def\defineULcharacter #1 #2 %
-% {\def\!!stringa{@#1}\@EA\letvalue\@EA\!!stringa\csname#1\endcsname
-% \def\!!stringa{@#2}\@EA\letvalue\@EA\!!stringa\csname#2\endcsname
-% \setvalue{#1}{\getvalue{@\ifuppercase#2\else#1\fi}}%
-% \setvalue{#2}{\getvalue{@\iflowercase#1\else#2\fi}}}
-
-% 2 = tricky, since expanding \definedfont[lowcasename] ... goes wrong
-
-\chardef\uppercasemode\plusthree % 0=ignore 1=normal 2=expand 3=auto
-\chardef\casecommode \plusone % 0=noexpand 1=expand
-
-\def\setcasecom #1#2{\def#1{\ifcase\casecommode\noexpand#1\else#2\fi}}
-
-% \def\OEPS{whatever}
-%
-% \startmapping[ec]
-% \defineuppercasecom \oeps {\getvalue{OEPS}}
-% \stopmapping
-%
-% \WORD{xx \oeps}
-
-\def\douppercase#1%
- {\bgroup
- \let\douppercase\firstofoneargument
- \the\everyuppercase % currently also checks uppercasemode
- \let\dochar\rawcharacter
- \ifcase\uppercasemode
- #1%
- \or % No expansion here, otherwise \getvalue problems! Default!!!
- %\edef\next{#1}% keep this to prevent roll back
- %\uppercase\expandafter{\next}% keep this to prevent roll back
- \uppercase{#1}%
- \or
- \chardef\casecommode\zerocount
- \let\docasecom\firstoftwoarguments
- \edef\ascii{#1}%
- \edef\ascii{\expandafter\uppercase\expandafter{\ascii}}% needed when in regime
- \chardef\casecommode\plusone
- \ascii
- \else
- % mode three may trigger setting 2 elsewhere (e.g. regime test)
- \uppercase{#1}%
- \fi
- \egroup}
-
-\prependtoksonce
- \doifnot\currentregime\s!default
- {\ifnum\uppercasemode=\plusthree \chardef\uppercasemode\plustwo \fi}%
-\to \everyuppercase
-
-%D \macros
-%D {everysanitize, EverySanitize}
-%D
-%D Whenever we are sanitizing strings, like we sometimes do
-%D when we deal with specials, the next token register can be
-%D called.
-
-\newevery \everysanitize \EverySanitize
-
-%D \macros
-%D {defineuclass,defineudigit,udigit}
-%D
-%D The next few macros are experimental and needed for unicoded
-%D chinese characters.
-
-\def\defineuclass #1 #2 #3 %
- {\setvalue{uc\the\numexpr#2*256+#3\relax}{#1}}
-
-\def\defineudigit #1 #2 #3 {\setvalue{\characterencoding uc#1}{\uchar{#2}{#3}}}
-
-%D It may look strange, but for the moment, we want the encoding
-%D to be part of the digit specification. This may change!
-
-\unexpanded\def\udigit#1#2{\getvalue{@#1@uc\number#2}}
-
-%D \macros
-%D {uchar, octuchar, hexuchar}
-
-\ifx\uchar\undefined \def\uchar#1#2{(\number#1,\number#2)} \fi
-
-\def\octuchar#1#2{\uchar{`#1}{`#2}}
-\def\hexuchar#1#2{\uchar{"#1}{"#2}}
-
-%D Basics and fallbacks.
-
-\newif\ifignoreaccent
-
-\let\textaccent \accent
-
-\let\normalaccent \accent
-\let\normaltextaccent\textaccent
-\let\normalmathaccent\mathaccent
-\let\normalchar \char
-
-% ** we will explicitly embrace the two arguments, since in definitions
-% this may not be the case, and we don't want faulty expansions like
-% "\dobuildtextaccent \char 18 a" but "\dobuildtextaccent {\char 18}{a}"
-% instead
-
-\def\buildmathaccent#1%
- {\mathaccent#1 }
-
-\def\buildtextaccent#1#2% **
- {\ifignoreaccent
- \expandafter\nobuildtextaccent
- \else
- \expandafter\dobuildtextaccent
- \fi{#1}{#2}}
-
-\unexpanded\def\nobuildtextaccent#1#2%
- {#2}
-
-\unexpanded\def\dobuildtextaccent#1#2%
- {{\let\char\normalaccent#1\let\char\normalchar#2}}
-
-% EVENTUALLY THIS CODE WILL MOVE TO AN mkiv module
-
-\beginLUATEX
-
-\newbox\accenttestbox
-
-\unexpanded\def\dobuildtextaccent#1#2%
- {\begingroup
- \global\setbox\accenttestbox\hbox{#1}%
- \scratchcounter\ctxlua{characters.charcode(\number\accenttestbox)}%
- \ifcase\scratchcounter\else\accent\scratchcounter\fi
- \relax#2%
- \endgroup}
-
-\endLUATEX
-
-% some fake ones, name will change into build
-
-\unexpanded\def\bottomaccent#1#2#3#4#5% down right slantcorrection accent char
- {\dontleavehmode % why this align mess
- \vtop
- {\forgetall
- \baselineskip\zeropoint
- \lineskip#1%
- \everycr\emptytoks
- \tabskip\zeropoint
- \lineskiplimit\zeropoint
- \setbox0\hbox{#4}%
- \halign
- {##\crcr\hbox{#5}\crcr
- \hidewidth
- \hskip#2\wd0
- \hskip-#3\slantperpoint % in plain 1ex * dimenless value
- \vbox to .2ex{\box0\vss}\hidewidth
- \crcr}}}
-
-\def\buildtextmacron {\bottomaccent{.25ex}{0}{15}{\textmacron}}
-\def\buildtextbottomdot{\bottomaccent{.25ex}{0}{5}{\textbottomdot}}
-\def\buildtextcedilla {\bottomaccent{0ex}{0}{5}{\textcedilla}}
-\def\buildtextogonek {\bottomaccent{-.1ex}{.5}{0}{\textogonek}}
-
-%D A collectors item:
-
-\def\buildtextbottomcomma{\bottomaccent{.15ex}{0}{5}{\tx,}}
-
-%D Rarely needed but there:
-
-\unexpanded\def\topaccent#1#2#3#4#5% down right slantcorrection accent char
- {\dontleavehmode
- \bgroup
- \setbox0\hbox{#4}%
- \setbox2\hbox{#5}%
- \hbox to \wd2 \bgroup
- \hss\copy2\hss
- \hskip-\wd2
- \hss\hskip#2\wd0\hskip-#3\slantperpoint\raise#1\hbox{#4}\hss
- \egroup
- \egroup}
-
-\def\buildtextgrave{\topaccent{0pt}{0}{15}{\textgrave}} % e.g.
-
-% \definecharacter schwa {\hbox{\rotate[rotation=180,location=high]{\hbox{e}}}}
-% \definecharacter schwagrave {\buildtextgrave\schwa}
-
-% math stuff, will change
-
-\def\definemathaccent#1 #2%
- {\setvalue{\string#1}{#2}%
- \setvalue{normalmathaccent\string#1}{#2}}
-
-\def\donormalmathaccent#1%
- {\getvalue{normalmathaccent\string#1}}
-
-%D Some precautions:
-
-\ifx\usepdffontresource\undefined
- \def\usepdffontresource #1 {} % this will be defined elsewhere
-\fi
-
-\def\donthandleaccent #1{\expandafter\string\csname#1\endcsname\space}
-\def\donthandlecommand #1{\expandafter\string\csname#1\endcsname\space}
-\def\donthandlecharacter #1{\expandafter\string\csname#1\endcsname\space}
-
-\def\stringifyhandleaccent #1{\strchr{#1}}
-\def\stringifyhandlecommand #1{\strchr{#1}}
-\def\stringifyhandlecharacter#1{\strchr{#1}}
-
-\def\keephandleaccent #1{\expandafter\noexpand\csname#1\endcsname}
-\def\keephandlecommand #1{\expandafter\noexpand\csname#1\endcsname}
-\def\keephandlecharacter #1{\expandafter\noexpand\csname#1\endcsname}
-
-\def\handleaccent #1{\csname#1\endcsname}
-\def\handlecommand #1{\csname#1\endcsname}
-\def\handlecharacter #1{\csname#1\endcsname}
-
-\def\dontexpandencoding
- {\let\dohandleaccent \donthandleaccent
- \let\dohandlecommand \donthandlecommand
- \let\dohandlecharacter\donthandlecharacter}
-
-\def\keepencodedtokens
- {\let\dohandleaccent \keephandleaccent
- \let\dohandlecommand \keephandlecommand
- \let\dohandlecharacter\keephandlecharacter}
-
-\def\literateencodedtokens
- {% \let\dohandleaccent \keephandleaccent
- % \let\dohandlecommand \keephandlecommand
- \let\dohandlecharacter\keephandlecharacter}
-
-\def\stringifyencodedtokens
- {% \let\dohandleaccent \stringifyhandleaccent
- % \let\dohandlecommand \stringifyhandlecommand
- \let\dohandlecharacter\stringifyhandlecharacter}
-
-\unexpanded\def\uhandleaccent #1{\csname#1\endcsname}
-\unexpanded\def\uhandlecommand #1{\csname#1\endcsname}
-\unexpanded\def\uhandlecharacter#1{\csname#1\endcsname}
-
-\def\dontexpandencodedtokens
- {\def\dohandleaccent {\uhandleaccent}%
- \def\dohandlecommand {\uhandlecommand}%
- \def\dohandlecharacter{\uhandlecharacter}}
-
-% no longer: \def\convertencodedtokens{\dontexpandencoding} but:
-
-\def\convertencodedtokens{\stringifyencodedtokens}
-
-% test case:
-%
-% \enableregime[cp1250]
-% \mainlanguage[cz]
-%
-% \starttext
-%
-% \title{luouc kon p}
-% \placelist[chapter][criterium=all]
-%
-% \startbuffer
-% <chapter>
-% <title>luouc kon p</title>
-% </chapter>
-% \stopbuffer
-%
-% \defineXMLenvironment
-% [chapter]
-% {\defineXMLsave[title]}
-% {\expanded{\chapter{\XMLflush{title}}}}
-% \processXMLbuffer
-%
-% \setuphead[chapter][expansion=yes]
-% \defineXMLenvironment
-% [chapter]
-% {\defineXMLsave[title]}
-% {\chapter{\XMLflush{title}}}
-% \processXMLbuffer
-%
-% \stoptext
-
-%D Still valid? To be checked:
-
-\def\doignoreaccent #1#2{\string#1\string#2}%
-\def\doignorecommand #1{\string#1}
-\def\doignorecharacter#1{\string#1}
-
-\def\ignoreencoding
- {\let\dohandleaccent \doignoreaccent
- \let\dohandlecommand \doignorecommand
- \let\dohandlecharacter\doignorecharacter}
-
-\appendtoks
- \ignoreencoding
-\to \everycleanupfeatures
-
-\appendtoks
- \keepencodedtokens
-\to \everysafeexpanded
-
-%D Now we will not redefine any more, so:
-
-\let\normaldohandleaccent \dohandleaccent
-\let\normaldohandlecharacter\dohandlecharacter
-
-%D We preload several encodings:
-
-\loadmarkfile{enco-ini}
-
-\definecommand ` {\buildtextaccent\textgrave}
-\definecommand ' {\buildtextaccent\textacute}
-\definecommand r {\buildtextaccent\textring}
-\definecommand v {\buildtextaccent\textcaron}
-\definecommand u {\buildtextaccent\textbreve}
-\definecommand = {\buildtextaccent\textmacron}
-\definecommand ^ {\buildtextaccent\textcircumflex}
-\definecommand . {\buildtextaccent\textdotaccent}
-\definecommand H {\buildtextaccent\texthungarumlaut}
-\definecommand ~ {\buildtextaccent\texttilde}
-\definecommand " {\buildtextaccent\textdiaeresis}
-
-\definecommand c {\buildtextcedilla}
-\definecommand b {\buildtextmacron}
-\definecommand d {\buildtextbottomdot}
-\definecommand k {\buildtextogonek}
-
-\definemathaccent acute {\buildmathaccent\mathacute}
-\definemathaccent grave {\buildmathaccent\mathgrave}
-\definemathaccent ddot {\buildmathaccent\mathddot}
-\definemathaccent tilde {\buildmathaccent\mathtilde}
-\definemathaccent bar {\buildmathaccent\mathbar}
-\definemathaccent breve {\buildmathaccent\mathbreve}
-\definemathaccent check {\buildmathaccent\mathcheck}
-\definemathaccent hat {\buildmathaccent\mathhat}
-\definemathaccent vec {\buildmathaccent\mathvec}
-\definemathaccent dot {\buildmathaccent\mathdot}
-\definemathaccent widetilde {\buildmathaccent\mathwidetilde}
-\definemathaccent widehat {\buildmathaccent\mathwidehat}
-
-\useencoding[def] % defaults (partly simplified)
-\useencoding[acc] % accent commands
-\useencoding[raw] % simplified (incomplete)
-\useencoding[com] % a few commands
-\useencoding[cas] % case mapping, not needed in mkiv
-\useencoding[mis] % a few commands
-
-% \useencoding[ans,il2,ec,tbo,pdf,uc,pol,qx,t5,cyr,agr] % pol and il2 will go away, not needed in mkiv
-% \useencoding[032,033,037] % fallbacks for some unicode chars
-% \setupencoding[\s!default=ec] % was: [\s!default=\s!default]
-
-\protect \endinput
diff --git a/tex/context/base/enco-mis.tex b/tex/context/base/enco-mis.tex
index b04d4ab7d..92dc61b3f 100644
--- a/tex/context/base/enco-mis.tex
+++ b/tex/context/base/enco-mis.tex
@@ -36,30 +36,6 @@
\unprotect
-% \def\pseudoencodeddj % like in babel
-% {\leavevmode\hbox\bgroup
-% \setbox0\hbox{d}%
-% \dimen0=\ht0
-% \advance\dimen0 1ex
-% \dimen0=.45\dimen0
-% \dimen2=\withoutpt\the\slantperpoint\dimen0
-% \advance\dimen2 .5ex
-% \rlap{\raise\dimen0\hbox{\kern\dimen2\vbox{\hrule\!!height0.1ex\!!width0.3em}}}%
-% \box0
-% \egroup}
-%
-% \def\pseudoencodedDJ % like in babel
-% {\leavevmode
-% \hbox\bgroup
-% \setbox0\hbox{D}%
-% \dimen0=.55\ht0
-% \dimen2=\withoutpt\the\slantperpoint\dimen0
-% \advance\dimen2 .15ex
-% \advance\dimen2 -.15\extraspace
-% \rlap{\raise\dimen0\hbox{\kern\dimen2\vbox{\hrule\!!height0.1ex\!!width0.33em}}}%
-% \box0
-% \egroup}
-
\def\pseudoencodeddj % like in babel, but safer
{\dontleavehmode\hbox\bgroup
\setbox\scratchbox\hbox{d}%
@@ -73,19 +49,6 @@
\raise\scratchdimen\hbox{\kern\dimen2\vbox{\hrule\!!height0.1ex\!!width0.3em}}}%
\egroup}
-% \def\pseudoencodedDJ % like in babel, but safer
-% {\leavevmode
-% \hbox\bgroup
-% \setbox\scratchbox\hbox{D}%
-% \scratchdimen.55\ht\scratchbox
-% \dimen2=\withoutpt\the\slantperpoint\scratchdimen
-% \advance\dimen2 .15ex
-% \advance\dimen2 -.15\extraspace
-% \hbox to \wd\scratchbox
-% {\box\scratchbox\hss
-% \raise\scratchdimen\hbox{\kern\dimen2\vbox{\hrule\!!height0.1ex\!!width0.3em}}}%
-% \egroup}
-
\def\pseudoencodedDJ % design: taco; quality assurance: mojca; cleanup: hans
{\dontleavehmode
\hbox\bgroup
diff --git a/tex/context/base/enco-pfr.mkii b/tex/context/base/enco-pfr.mkii
deleted file mode 100644
index aec926e22..000000000
--- a/tex/context/base/enco-pfr.mkii
+++ /dev/null
@@ -1,20 +0,0 @@
-%D \module
-%D [ file=enco-pfr,
-%D version=2000.12.10, % adapted 2005.08.14 to more delayed loading
-%D title=\CONTEXT\ Encoding Macros,
-%D subtitle=PDF Font Resource Inclusion,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\ifx\pdfglyphtounicode\undefined \else
- \appendtoks
- \doif\jobsuffix{pdf}{\readfile{pdfr-def.tex}\donothing\donothing}%
- \to \everystarttext
-\fi
-
-\endinput
diff --git a/tex/context/base/enco-pfr.mkiv b/tex/context/base/enco-pfr.mkiv
deleted file mode 100644
index 52ef0cc3b..000000000
--- a/tex/context/base/enco-pfr.mkiv
+++ /dev/null
@@ -1,22 +0,0 @@
-%D \module
-%D [ file=enco-pfr,
-%D version=2000.12.10, % adapted 2005.08.14 to more delayed loading
-%D title=\CONTEXT\ Encoding Macros,
-%D subtitle=PDF Font Resource Inclusion,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% obsolete, at least for wide fonts, we may need to support it otherwise
-%
-% \ifx\pdfglyphtounicode\undefined \else
-% \appendtoks
-% \doif\jobsuffix{pdf}{\ctxlua{characters.setpdfunicodes()}}% pdftounicode mappings can only be done runtime
-% \to \everystarttext
-% \fi
-
-\endinput
diff --git a/tex/context/base/enco-pfr.tex b/tex/context/base/enco-pfr.tex
index 902eb7bcd..a90c62352 100644
--- a/tex/context/base/enco-pfr.tex
+++ b/tex/context/base/enco-pfr.tex
@@ -2,7 +2,7 @@
%D [ file=enco-pfr,
%D version=2000.12.10, % adapted 2005.08.14 to more delayed loading
%D title=\CONTEXT\ Encoding Macros,
-%D subtitle=PDF Font Resource Inclusion,
+%D subtitle=PDF Resources,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,17 +11,13 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\beginXETEX
+\ifnum\texengine>\pdftexengine
\endinput
-\endXETEX
-
-\beginLUATEX
- \endinput
-\endLUATEX
+\fi
\ifx\pdffontresource\undefined\else\endinput\fi
-\writestatus{loading}{Context Encoding Macros (pdf)}
+\writestatus{loading}{ConTeXt Encoding Macros / PDF Resources}
%D This is an experimental module in which we implement
%D font resource inclusion in \PDF. One reason to include
@@ -60,7 +56,11 @@
\newif\ifincludepdffontresources \includepdffontresourcestrue
-\ifx\pdfglyphtounicode\undefined \else \loadmarkfile{enco-pfr} \fi
+\ifx\pdfglyphtounicode\undefined \else
+ \appendtoks
+ \doif\jobsuffix{pdf}{\readfile{pdfr-def.tex}\donothing\donothing}%
+ \to \everystarttext
+\fi
% somehow we cannot preload this beast; also, it's mk dependent
%
diff --git a/tex/context/base/enco-run.tex b/tex/context/base/enco-run.tex
index 8e50e9398..50fb52e15 100644
--- a/tex/context/base/enco-run.tex
+++ b/tex/context/base/enco-run.tex
@@ -98,16 +98,7 @@
% {\font\test=uplr8t \test \ruledhbox{t}
% \font\test=uplr8r \test \ruledhbox{t}}
-\gdef\showcharacterbounds
- {\bgroup
- \localcolortrue
- \dorecurse{255}
- {\ifdim\fontcharwd\font\recurselevel>\zeropoint
- \noindent\ruledhbox{\darkgray\char\recurselevel}\space
- \fi}\unskip
- \egroup}
-
-\beginOLDTEX
+\ifnum\texengine=\pdftexengine
\gdef\showhyphenations#1%
{\starttabulate[|le|l|]
@@ -119,9 +110,28 @@
\NC sample \NC \hyphenatedword{#1} \NC \NR
\stoptabulate}
-\endOLDTEX
+ \gdef\showmapping
+ {\dostepwiserecurse{128}{255}{1}
+ {\hbox\bgroup
+ \hbox to 2em{\hss\recurselevel}%
+ \hbox to 2em{\hss\char\recurselevel\hss}%
+ \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \lccode\recurselevel\fi}%
+ \hbox to 2em{\hss\ifcase\lccode\recurselevel\else\char\lccode\recurselevel\fi\hss}%
+ \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \uccode\recurselevel\fi}%
+ \hbox to 2em{\hss\ifcase\uccode\recurselevel\else\char\uccode\recurselevel\fi\hss}%
+ \egroup
+ \endgraf}}
-\beginNEWTEX
+ \gdef\showcharacterbounds
+ {\bgroup
+ \localcolortrue
+ \dorecurse{255}
+ {\ifdim\fontcharwd\font\recurselevel>\zeropoint
+ \noindent\ruledhbox{\darkgray\char\recurselevel}\space
+ \fi}\unskip
+ \egroup}
+
+\else
\gdef\showhyphenations#1%
{\starttabulate[|le|l|]
@@ -130,18 +140,10 @@
\NC sample \NC \hyphenatedword{#1} \NC \NR
\stoptabulate}
-\endNEWTEX
-
-\gdef\showmapping
- {\dostepwiserecurse{128}{255}{1}
- {\hbox\bgroup
- \hbox to 2em{\hss\recurselevel}%
- \hbox to 2em{\hss\char\recurselevel\hss}%
- \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \lccode\recurselevel\fi}%
- \hbox to 2em{\hss\ifcase\lccode\recurselevel\else\char\lccode\recurselevel\fi\hss}%
- \hbox to 3em{\hss\ifcase\lccode\recurselevel\else\the \uccode\recurselevel\fi}%
- \hbox to 2em{\hss\ifcase\uccode\recurselevel\else\char\uccode\recurselevel\fi\hss}%
- \egroup
- \endgraf}}
+ \globallet\showmapping\relax
+
+ \globallet\showcharacterbounds\relax
+
+\fi
\protect \endinput
diff --git a/tex/context/base/enco-t5.tex b/tex/context/base/enco-t5.tex
index ee9fa4856..251c68765 100644
--- a/tex/context/base/enco-t5.tex
+++ b/tex/context/base/enco-t5.tex
@@ -210,8 +210,8 @@
%
% \def\xfiveencodedAA%
% {\leavevmode
-% \setbox\z@\hbox{h}%
-% \dimen@\ht\z@
+% \setbox\zerocount\hbox{h}%
+% \dimen@\ht\zerocount
% \advance\dimen@ -1ex
% \rlap{\raise.67\dimen@\hbox{\char23}}A}
diff --git a/tex/context/base/enco-utf.tex b/tex/context/base/enco-utf.tex
deleted file mode 100644
index bfb427381..000000000
--- a/tex/context/base/enco-utf.tex
+++ /dev/null
@@ -1,3126 +0,0 @@
-% filename : enco-utf.tex
-% comment : generated by mtxrun --script chars --utf
-% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
-% copyright: PRAGMA ADE / ConTeXt Development Team
-% license : see context related readme files
-
-\ifx\setcclcucx\undefined
-
- \def\setcclcucx #1 #2 #3 %
- {\global\catcode"#1=11
- \global\lccode "#1="#2
- \global\uccode "#1="#3 }
-
-\fi
-
-% lc/uc/catcode mappings
-
-\setcclcucx 0041 0061 0041 % LATIN CAPITAL LETTER A
-\setcclcucx 0042 0062 0042 % LATIN CAPITAL LETTER B
-\setcclcucx 0043 0063 0043 % LATIN CAPITAL LETTER C
-\setcclcucx 0044 0064 0044 % LATIN CAPITAL LETTER D
-\setcclcucx 0045 0065 0045 % LATIN CAPITAL LETTER E
-\setcclcucx 0046 0066 0046 % LATIN CAPITAL LETTER F
-\setcclcucx 0047 0067 0047 % LATIN CAPITAL LETTER G
-\setcclcucx 0048 0068 0048 % LATIN CAPITAL LETTER H
-\setcclcucx 0049 0069 0049 % LATIN CAPITAL LETTER I
-\setcclcucx 004A 006A 004A % LATIN CAPITAL LETTER J
-\setcclcucx 004B 006B 004B % LATIN CAPITAL LETTER K
-\setcclcucx 004C 006C 004C % LATIN CAPITAL LETTER L
-\setcclcucx 004D 006D 004D % LATIN CAPITAL LETTER M
-\setcclcucx 004E 006E 004E % LATIN CAPITAL LETTER N
-\setcclcucx 004F 006F 004F % LATIN CAPITAL LETTER O
-\setcclcucx 0050 0070 0050 % LATIN CAPITAL LETTER P
-\setcclcucx 0051 0071 0051 % LATIN CAPITAL LETTER Q
-\setcclcucx 0052 0072 0052 % LATIN CAPITAL LETTER R
-\setcclcucx 0053 0073 0053 % LATIN CAPITAL LETTER S
-\setcclcucx 0054 0074 0054 % LATIN CAPITAL LETTER T
-\setcclcucx 0055 0075 0055 % LATIN CAPITAL LETTER U
-\setcclcucx 0056 0076 0056 % LATIN CAPITAL LETTER V
-\setcclcucx 0057 0077 0057 % LATIN CAPITAL LETTER W
-\setcclcucx 0058 0078 0058 % LATIN CAPITAL LETTER X
-\setcclcucx 0059 0079 0059 % LATIN CAPITAL LETTER Y
-\setcclcucx 005A 007A 005A % LATIN CAPITAL LETTER Z
-\setcclcucx 0061 0061 0041 % LATIN SMALL LETTER A
-\setcclcucx 0062 0062 0042 % LATIN SMALL LETTER B
-\setcclcucx 0063 0063 0043 % LATIN SMALL LETTER C
-\setcclcucx 0064 0064 0044 % LATIN SMALL LETTER D
-\setcclcucx 0065 0065 0045 % LATIN SMALL LETTER E
-\setcclcucx 0066 0066 0046 % LATIN SMALL LETTER F
-\setcclcucx 0067 0067 0047 % LATIN SMALL LETTER G
-\setcclcucx 0068 0068 0048 % LATIN SMALL LETTER H
-\setcclcucx 0069 0069 0049 % LATIN SMALL LETTER I
-\setcclcucx 006A 006A 004A % LATIN SMALL LETTER J
-\setcclcucx 006B 006B 004B % LATIN SMALL LETTER K
-\setcclcucx 006C 006C 004C % LATIN SMALL LETTER L
-\setcclcucx 006D 006D 004D % LATIN SMALL LETTER M
-\setcclcucx 006E 006E 004E % LATIN SMALL LETTER N
-\setcclcucx 006F 006F 004F % LATIN SMALL LETTER O
-\setcclcucx 0070 0070 0050 % LATIN SMALL LETTER P
-\setcclcucx 0071 0071 0051 % LATIN SMALL LETTER Q
-\setcclcucx 0072 0072 0052 % LATIN SMALL LETTER R
-\setcclcucx 0073 0073 0053 % LATIN SMALL LETTER S
-\setcclcucx 0074 0074 0054 % LATIN SMALL LETTER T
-\setcclcucx 0075 0075 0055 % LATIN SMALL LETTER U
-\setcclcucx 0076 0076 0056 % LATIN SMALL LETTER V
-\setcclcucx 0077 0077 0057 % LATIN SMALL LETTER W
-\setcclcucx 0078 0078 0058 % LATIN SMALL LETTER X
-\setcclcucx 0079 0079 0059 % LATIN SMALL LETTER Y
-\setcclcucx 007A 007A 005A % LATIN SMALL LETTER Z
-\setcclcucx 00AA 00AA 00AA % FEMININE ORDINAL INDICATOR
-\setcclcucx 00B5 00B5 039C % MICRO SIGN
-\setcclcucx 00BA 00BA 00BA % MASCULINE ORDINAL INDICATOR
-\setcclcucx 00C0 00E0 00C0 % LATIN CAPITAL LETTER A WITH GRAVE
-\setcclcucx 00C1 00E1 00C1 % LATIN CAPITAL LETTER A WITH ACUTE
-\setcclcucx 00C2 00E2 00C2 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX
-\setcclcucx 00C3 00E3 00C3 % LATIN CAPITAL LETTER A WITH TILDE
-\setcclcucx 00C4 00E4 00C4 % LATIN CAPITAL LETTER A WITH DIAERESIS
-\setcclcucx 00C5 00E5 00C5 % LATIN CAPITAL LETTER A WITH RING ABOVE
-\setcclcucx 00C6 00E6 00C6 % LATIN CAPITAL LETTER AE
-\setcclcucx 00C7 00E7 00C7 % LATIN CAPITAL LETTER C WITH CEDILLA
-\setcclcucx 00C8 00E8 00C8 % LATIN CAPITAL LETTER E WITH GRAVE
-\setcclcucx 00C9 00E9 00C9 % LATIN CAPITAL LETTER E WITH ACUTE
-\setcclcucx 00CA 00EA 00CA % LATIN CAPITAL LETTER E WITH CIRCUMFLEX
-\setcclcucx 00CB 00EB 00CB % LATIN CAPITAL LETTER E WITH DIAERESIS
-\setcclcucx 00CC 00EC 00CC % LATIN CAPITAL LETTER I WITH GRAVE
-\setcclcucx 00CD 00ED 00CD % LATIN CAPITAL LETTER I WITH ACUTE
-\setcclcucx 00CE 00EE 00CE % LATIN CAPITAL LETTER I WITH CIRCUMFLEX
-\setcclcucx 00CF 00EF 00CF % LATIN CAPITAL LETTER I WITH DIAERESIS
-\setcclcucx 00D0 00F0 00D0 % LATIN CAPITAL LETTER ETH
-\setcclcucx 00D1 00F1 00D1 % LATIN CAPITAL LETTER N WITH TILDE
-\setcclcucx 00D2 00F2 00D2 % LATIN CAPITAL LETTER O WITH GRAVE
-\setcclcucx 00D3 00F3 00D3 % LATIN CAPITAL LETTER O WITH ACUTE
-\setcclcucx 00D4 00F4 00D4 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX
-\setcclcucx 00D5 00F5 00D5 % LATIN CAPITAL LETTER O WITH TILDE
-\setcclcucx 00D6 00F6 00D6 % LATIN CAPITAL LETTER O WITH DIAERESIS
-\setcclcucx 00D8 00F8 00D8 % LATIN CAPITAL LETTER O WITH STROKE
-\setcclcucx 00D9 00F9 00D9 % LATIN CAPITAL LETTER U WITH GRAVE
-\setcclcucx 00DA 00FA 00DA % LATIN CAPITAL LETTER U WITH ACUTE
-\setcclcucx 00DB 00FB 00DB % LATIN CAPITAL LETTER U WITH CIRCUMFLEX
-\setcclcucx 00DC 00FC 00DC % LATIN CAPITAL LETTER U WITH DIAERESIS
-\setcclcucx 00DD 00FD 00DD % LATIN CAPITAL LETTER Y WITH ACUTE
-\setcclcucx 00DE 00FE 00DE % LATIN CAPITAL LETTER THORN
-\setcclcucx 00DF 00DF 00DF % LATIN SMALL LETTER SHARP S
-\setcclcucx 00E0 00E0 00C0 % LATIN SMALL LETTER A WITH GRAVE
-\setcclcucx 00E1 00E1 00C1 % LATIN SMALL LETTER A WITH ACUTE
-\setcclcucx 00E2 00E2 00C2 % LATIN SMALL LETTER A WITH CIRCUMFLEX
-\setcclcucx 00E3 00E3 00C3 % LATIN SMALL LETTER A WITH TILDE
-\setcclcucx 00E4 00E4 00C4 % LATIN SMALL LETTER A WITH DIAERESIS
-\setcclcucx 00E5 00E5 00C5 % LATIN SMALL LETTER A WITH RING ABOVE
-\setcclcucx 00E6 00E6 00C6 % LATIN SMALL LETTER AE
-\setcclcucx 00E7 00E7 00C7 % LATIN SMALL LETTER C WITH CEDILLA
-\setcclcucx 00E8 00E8 00C8 % LATIN SMALL LETTER E WITH GRAVE
-\setcclcucx 00E9 00E9 00C9 % LATIN SMALL LETTER E WITH ACUTE
-\setcclcucx 00EA 00EA 00CA % LATIN SMALL LETTER E WITH CIRCUMFLEX
-\setcclcucx 00EB 00EB 00CB % LATIN SMALL LETTER E WITH DIAERESIS
-\setcclcucx 00EC 00EC 00CC % LATIN SMALL LETTER I WITH GRAVE
-\setcclcucx 00ED 00ED 00CD % LATIN SMALL LETTER I WITH ACUTE
-\setcclcucx 00EE 00EE 00CE % LATIN SMALL LETTER I WITH CIRCUMFLEX
-\setcclcucx 00EF 00EF 00CF % LATIN SMALL LETTER I WITH DIAERESIS
-\setcclcucx 00F0 00F0 00D0 % LATIN SMALL LETTER ETH
-\setcclcucx 00F1 00F1 00D1 % LATIN SMALL LETTER N WITH TILDE
-\setcclcucx 00F2 00F2 00D2 % LATIN SMALL LETTER O WITH GRAVE
-\setcclcucx 00F3 00F3 00D3 % LATIN SMALL LETTER O WITH ACUTE
-\setcclcucx 00F4 00F4 00D4 % LATIN SMALL LETTER O WITH CIRCUMFLEX
-\setcclcucx 00F5 00F5 00D5 % LATIN SMALL LETTER O WITH TILDE
-\setcclcucx 00F6 00F6 00D6 % LATIN SMALL LETTER O WITH DIAERESIS
-\setcclcucx 00F8 00F8 00D8 % LATIN SMALL LETTER O WITH STROKE
-\setcclcucx 00F9 00F9 00D9 % LATIN SMALL LETTER U WITH GRAVE
-\setcclcucx 00FA 00FA 00DA % LATIN SMALL LETTER U WITH ACUTE
-\setcclcucx 00FB 00FB 00DB % LATIN SMALL LETTER U WITH CIRCUMFLEX
-\setcclcucx 00FC 00FC 00DC % LATIN SMALL LETTER U WITH DIAERESIS
-\setcclcucx 00FD 00FD 00DD % LATIN SMALL LETTER Y WITH ACUTE
-\setcclcucx 00FE 00FE 00DE % LATIN SMALL LETTER THORN
-\setcclcucx 00FF 00FF 0178 % LATIN SMALL LETTER Y WITH DIAERESIS
-\setcclcucx 0100 0101 0100 % LATIN CAPITAL LETTER A WITH MACRON
-\setcclcucx 0101 0101 0100 % LATIN SMALL LETTER A WITH MACRON
-\setcclcucx 0102 0103 0102 % LATIN CAPITAL LETTER A WITH BREVE
-\setcclcucx 0103 0103 0102 % LATIN SMALL LETTER A WITH BREVE
-\setcclcucx 0104 0105 0104 % LATIN CAPITAL LETTER A WITH OGONEK
-\setcclcucx 0105 0105 0104 % LATIN SMALL LETTER A WITH OGONEK
-\setcclcucx 0106 0107 0106 % LATIN CAPITAL LETTER C WITH ACUTE
-\setcclcucx 0107 0107 0106 % LATIN SMALL LETTER C WITH ACUTE
-\setcclcucx 0108 0109 0108 % LATIN CAPITAL LETTER C WITH CIRCUMFLEX
-\setcclcucx 0109 0109 0108 % LATIN SMALL LETTER C WITH CIRCUMFLEX
-\setcclcucx 010A 010B 010A % LATIN CAPITAL LETTER C WITH DOT ABOVE
-\setcclcucx 010B 010B 010A % LATIN SMALL LETTER C WITH DOT ABOVE
-\setcclcucx 010C 010D 010C % LATIN CAPITAL LETTER C WITH CARON
-\setcclcucx 010D 010D 010C % LATIN SMALL LETTER C WITH CARON
-\setcclcucx 010E 010F 010E % LATIN CAPITAL LETTER D WITH CARON
-\setcclcucx 010F 010F 010E % LATIN SMALL LETTER D WITH CARON
-\setcclcucx 0110 0111 0110 % LATIN CAPITAL LETTER D WITH STROKE
-\setcclcucx 0111 0111 0110 % LATIN SMALL LETTER D WITH STROKE
-\setcclcucx 0112 0113 0112 % LATIN CAPITAL LETTER E WITH MACRON
-\setcclcucx 0113 0113 0112 % LATIN SMALL LETTER E WITH MACRON
-\setcclcucx 0114 0115 0114 % LATIN CAPITAL LETTER E WITH BREVE
-\setcclcucx 0115 0115 0114 % LATIN SMALL LETTER E WITH BREVE
-\setcclcucx 0116 0117 0116 % LATIN CAPITAL LETTER E WITH DOT ABOVE
-\setcclcucx 0117 0117 0116 % LATIN SMALL LETTER E WITH DOT ABOVE
-\setcclcucx 0118 0119 0118 % LATIN CAPITAL LETTER E WITH OGONEK
-\setcclcucx 0119 0119 0118 % LATIN SMALL LETTER E WITH OGONEK
-\setcclcucx 011A 011B 011A % LATIN CAPITAL LETTER E WITH CARON
-\setcclcucx 011B 011B 011A % LATIN SMALL LETTER E WITH CARON
-\setcclcucx 011C 011D 011C % LATIN CAPITAL LETTER G WITH CIRCUMFLEX
-\setcclcucx 011D 011D 011C % LATIN SMALL LETTER G WITH CIRCUMFLEX
-\setcclcucx 011E 011F 011E % LATIN CAPITAL LETTER G WITH BREVE
-\setcclcucx 011F 011F 011E % LATIN SMALL LETTER G WITH BREVE
-\setcclcucx 0120 0121 0120 % LATIN CAPITAL LETTER G WITH DOT ABOVE
-\setcclcucx 0121 0121 0120 % LATIN SMALL LETTER G WITH DOT ABOVE
-\setcclcucx 0122 0123 0122 % LATIN CAPITAL LETTER G WITH CEDILLA
-\setcclcucx 0123 0123 0122 % LATIN SMALL LETTER G WITH CEDILLA
-\setcclcucx 0124 0125 0124 % LATIN CAPITAL LETTER H WITH CIRCUMFLEX
-\setcclcucx 0125 0125 0124 % LATIN SMALL LETTER H WITH CIRCUMFLEX
-\setcclcucx 0126 0127 0126 % LATIN CAPITAL LETTER H WITH STROKE
-\setcclcucx 0127 0127 0126 % LATIN SMALL LETTER H WITH STROKE
-\setcclcucx 0128 0129 0128 % LATIN CAPITAL LETTER I WITH TILDE
-\setcclcucx 0129 0129 0128 % LATIN SMALL LETTER I WITH TILDE
-\setcclcucx 012A 012B 012A % LATIN CAPITAL LETTER I WITH MACRON
-\setcclcucx 012B 012B 012A % LATIN SMALL LETTER I WITH MACRON
-\setcclcucx 012C 012D 012C % LATIN CAPITAL LETTER I WITH BREVE
-\setcclcucx 012D 012D 012C % LATIN SMALL LETTER I WITH BREVE
-\setcclcucx 012E 012F 012E % LATIN CAPITAL LETTER I WITH OGONEK
-\setcclcucx 012F 012F 012E % LATIN SMALL LETTER I WITH OGONEK
-\setcclcucx 0130 0069 0130 % LATIN CAPITAL LETTER I WITH DOT ABOVE
-\setcclcucx 0131 0131 0049 % LATIN SMALL LETTER DOTLESS I
-\setcclcucx 0132 0133 0132 % LATIN CAPITAL LIGATURE IJ
-\setcclcucx 0133 0133 0132 % LATIN SMALL LIGATURE IJ
-\setcclcucx 0134 0135 0134 % LATIN CAPITAL LETTER J WITH CIRCUMFLEX
-\setcclcucx 0135 0135 0134 % LATIN SMALL LETTER J WITH CIRCUMFLEX
-\setcclcucx 0136 0137 0136 % LATIN CAPITAL LETTER K WITH CEDILLA
-\setcclcucx 0137 0137 0136 % LATIN SMALL LETTER K WITH CEDILLA
-\setcclcucx 0138 0138 0138 % LATIN SMALL LETTER KRA
-\setcclcucx 0139 013A 0139 % LATIN CAPITAL LETTER L WITH ACUTE
-\setcclcucx 013A 013A 0139 % LATIN SMALL LETTER L WITH ACUTE
-\setcclcucx 013B 013C 013B % LATIN CAPITAL LETTER L WITH CEDILLA
-\setcclcucx 013C 013C 013B % LATIN SMALL LETTER L WITH CEDILLA
-\setcclcucx 013D 013E 013D % LATIN CAPITAL LETTER L WITH CARON
-\setcclcucx 013E 013E 013D % LATIN SMALL LETTER L WITH CARON
-\setcclcucx 013F 0140 013F % LATIN CAPITAL LETTER L WITH MIDDLE DOT
-\setcclcucx 0140 0140 013F % LATIN SMALL LETTER L WITH MIDDLE DOT
-\setcclcucx 0141 0142 0141 % LATIN CAPITAL LETTER L WITH STROKE
-\setcclcucx 0142 0142 0141 % LATIN SMALL LETTER L WITH STROKE
-\setcclcucx 0143 0144 0143 % LATIN CAPITAL LETTER N WITH ACUTE
-\setcclcucx 0144 0144 0143 % LATIN SMALL LETTER N WITH ACUTE
-\setcclcucx 0145 0146 0145 % LATIN CAPITAL LETTER N WITH CEDILLA
-\setcclcucx 0146 0146 0145 % LATIN SMALL LETTER N WITH CEDILLA
-\setcclcucx 0147 0148 0147 % LATIN CAPITAL LETTER N WITH CARON
-\setcclcucx 0148 0148 0147 % LATIN SMALL LETTER N WITH CARON
-\setcclcucx 0149 0149 0149 % LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
-\setcclcucx 014A 014B 014A % LATIN CAPITAL LETTER ENG
-\setcclcucx 014B 014B 014A % LATIN SMALL LETTER ENG
-\setcclcucx 014C 014D 014C % LATIN CAPITAL LETTER O WITH MACRON
-\setcclcucx 014D 014D 014C % LATIN SMALL LETTER O WITH MACRON
-\setcclcucx 014E 014F 014E % LATIN CAPITAL LETTER O WITH BREVE
-\setcclcucx 014F 014F 014E % LATIN SMALL LETTER O WITH BREVE
-\setcclcucx 0150 0151 0150 % LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
-\setcclcucx 0151 0151 0150 % LATIN SMALL LETTER O WITH DOUBLE ACUTE
-\setcclcucx 0152 0153 0152 % LATIN CAPITAL LIGATURE OE
-\setcclcucx 0153 0153 0152 % LATIN SMALL LIGATURE OE
-\setcclcucx 0154 0155 0154 % LATIN CAPITAL LETTER R WITH ACUTE
-\setcclcucx 0155 0155 0154 % LATIN SMALL LETTER R WITH ACUTE
-\setcclcucx 0156 0157 0156 % LATIN CAPITAL LETTER R WITH CEDILLA
-\setcclcucx 0157 0157 0156 % LATIN SMALL LETTER R WITH CEDILLA
-\setcclcucx 0158 0159 0158 % LATIN CAPITAL LETTER R WITH CARON
-\setcclcucx 0159 0159 0158 % LATIN SMALL LETTER R WITH CARON
-\setcclcucx 015A 015B 015A % LATIN CAPITAL LETTER S WITH ACUTE
-\setcclcucx 015B 015B 015A % LATIN SMALL LETTER S WITH ACUTE
-\setcclcucx 015C 015D 015C % LATIN CAPITAL LETTER S WITH CIRCUMFLEX
-\setcclcucx 015D 015D 015C % LATIN SMALL LETTER S WITH CIRCUMFLEX
-\setcclcucx 015E 015F 015E % LATIN CAPITAL LETTER S WITH CEDILLA
-\setcclcucx 015F 015F 015E % LATIN SMALL LETTER S WITH CEDILLA
-\setcclcucx 0160 0161 0160 % LATIN CAPITAL LETTER S WITH CARON
-\setcclcucx 0161 0161 0160 % LATIN SMALL LETTER S WITH CARON
-\setcclcucx 0162 0163 0162 % LATIN CAPITAL LETTER T WITH CEDILLA
-\setcclcucx 0163 0163 0162 % LATIN SMALL LETTER T WITH CEDILLA
-\setcclcucx 0164 0165 0164 % LATIN CAPITAL LETTER T WITH CARON
-\setcclcucx 0165 0165 0164 % LATIN SMALL LETTER T WITH CARON
-\setcclcucx 0166 0167 0166 % LATIN CAPITAL LETTER T WITH STROKE
-\setcclcucx 0167 0167 0166 % LATIN SMALL LETTER T WITH STROKE
-\setcclcucx 0168 0169 0168 % LATIN CAPITAL LETTER U WITH TILDE
-\setcclcucx 0169 0169 0168 % LATIN SMALL LETTER U WITH TILDE
-\setcclcucx 016A 016B 016A % LATIN CAPITAL LETTER U WITH MACRON
-\setcclcucx 016B 016B 016A % LATIN SMALL LETTER U WITH MACRON
-\setcclcucx 016C 016D 016C % LATIN CAPITAL LETTER U WITH BREVE
-\setcclcucx 016D 016D 016C % LATIN SMALL LETTER U WITH BREVE
-\setcclcucx 016E 016F 016E % LATIN CAPITAL LETTER U WITH RING ABOVE
-\setcclcucx 016F 016F 016E % LATIN SMALL LETTER U WITH RING ABOVE
-\setcclcucx 0170 0171 0170 % LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
-\setcclcucx 0171 0171 0170 % LATIN SMALL LETTER U WITH DOUBLE ACUTE
-\setcclcucx 0172 0173 0172 % LATIN CAPITAL LETTER U WITH OGONEK
-\setcclcucx 0173 0173 0172 % LATIN SMALL LETTER U WITH OGONEK
-\setcclcucx 0174 0175 0174 % LATIN CAPITAL LETTER W WITH CIRCUMFLEX
-\setcclcucx 0175 0175 0174 % LATIN SMALL LETTER W WITH CIRCUMFLEX
-\setcclcucx 0176 0177 0176 % LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
-\setcclcucx 0177 0177 0176 % LATIN SMALL LETTER Y WITH CIRCUMFLEX
-\setcclcucx 0178 00FF 0178 % LATIN CAPITAL LETTER Y WITH DIAERESIS
-\setcclcucx 0179 017A 0179 % LATIN CAPITAL LETTER Z WITH ACUTE
-\setcclcucx 017A 017A 0179 % LATIN SMALL LETTER Z WITH ACUTE
-\setcclcucx 017B 017C 017B % LATIN CAPITAL LETTER Z WITH DOT ABOVE
-\setcclcucx 017C 017C 017B % LATIN SMALL LETTER Z WITH DOT ABOVE
-\setcclcucx 017D 017E 017D % LATIN CAPITAL LETTER Z WITH CARON
-\setcclcucx 017E 017E 017D % LATIN SMALL LETTER Z WITH CARON
-\setcclcucx 017F 017F 0053 % LATIN SMALL LETTER LONG S
-\setcclcucx 0180 0180 0243 % LATIN SMALL LETTER B WITH STROKE
-\setcclcucx 0181 0253 0181 % LATIN CAPITAL LETTER B WITH HOOK
-\setcclcucx 0182 0183 0182 % LATIN CAPITAL LETTER B WITH TOPBAR
-\setcclcucx 0183 0183 0182 % LATIN SMALL LETTER B WITH TOPBAR
-\setcclcucx 0184 0185 0184 % LATIN CAPITAL LETTER TONE SIX
-\setcclcucx 0185 0185 0184 % LATIN SMALL LETTER TONE SIX
-\setcclcucx 0186 0254 0186 % LATIN CAPITAL LETTER OPEN O
-\setcclcucx 0187 0188 0187 % LATIN CAPITAL LETTER C WITH HOOK
-\setcclcucx 0188 0188 0187 % LATIN SMALL LETTER C WITH HOOK
-\setcclcucx 0189 0256 0189 % LATIN CAPITAL LETTER AFRICAN D
-\setcclcucx 018A 0257 018A % LATIN CAPITAL LETTER D WITH HOOK
-\setcclcucx 018B 018C 018B % LATIN CAPITAL LETTER D WITH TOPBAR
-\setcclcucx 018C 018C 018B % LATIN SMALL LETTER D WITH TOPBAR
-\setcclcucx 018D 018D 018D % LATIN SMALL LETTER TURNED DELTA
-\setcclcucx 018E 01DD 018E % LATIN CAPITAL LETTER REVERSED E
-\setcclcucx 018F 0259 018F % LATIN CAPITAL LETTER SCHWA
-\setcclcucx 0190 025B 0190 % LATIN CAPITAL LETTER OPEN E
-\setcclcucx 0191 0192 0191 % LATIN CAPITAL LETTER F WITH HOOK
-\setcclcucx 0192 0192 0191 % LATIN SMALL LETTER F WITH HOOK
-\setcclcucx 0193 0260 0193 % LATIN CAPITAL LETTER G WITH HOOK
-\setcclcucx 0194 0263 0194 % LATIN CAPITAL LETTER GAMMA
-\setcclcucx 0195 0195 01F6 % LATIN SMALL LETTER HV
-\setcclcucx 0196 0269 0196 % LATIN CAPITAL LETTER IOTA
-\setcclcucx 0197 0268 0197 % LATIN CAPITAL LETTER I WITH STROKE
-\setcclcucx 0198 0199 0198 % LATIN CAPITAL LETTER K WITH HOOK
-\setcclcucx 0199 0199 0198 % LATIN SMALL LETTER K WITH HOOK
-\setcclcucx 019A 019A 023D % LATIN SMALL LETTER L WITH BAR
-\setcclcucx 019B 019B 019B % LATIN SMALL LETTER LAMBDA WITH STROKE
-\setcclcucx 019C 026F 019C % LATIN CAPITAL LETTER TURNED M
-\setcclcucx 019D 0272 019D % LATIN CAPITAL LETTER N WITH LEFT HOOK
-\setcclcucx 019E 019E 0220 % LATIN SMALL LETTER N WITH LONG RIGHT LEG
-\setcclcucx 019F 0275 019F % LATIN CAPITAL LETTER O WITH MIDDLE TILDE
-\setcclcucx 01A0 01A1 01A0 % LATIN CAPITAL LETTER O WITH HORN
-\setcclcucx 01A1 01A1 01A0 % LATIN SMALL LETTER O WITH HORN
-\setcclcucx 01A2 01A3 01A2 % LATIN CAPITAL LETTER OI
-\setcclcucx 01A3 01A3 01A2 % LATIN SMALL LETTER OI
-\setcclcucx 01A4 01A5 01A4 % LATIN CAPITAL LETTER P WITH HOOK
-\setcclcucx 01A5 01A5 01A4 % LATIN SMALL LETTER P WITH HOOK
-\setcclcucx 01A6 0280 01A6 % LATIN LETTER YR
-\setcclcucx 01A7 01A8 01A7 % LATIN CAPITAL LETTER TONE TWO
-\setcclcucx 01A8 01A8 01A7 % LATIN SMALL LETTER TONE TWO
-\setcclcucx 01A9 0283 01A9 % LATIN CAPITAL LETTER ESH
-\setcclcucx 01AA 01AA 01AA % LATIN LETTER REVERSED ESH LOOP
-\setcclcucx 01AB 01AB 01AB % LATIN SMALL LETTER T WITH PALATAL HOOK
-\setcclcucx 01AC 01AD 01AC % LATIN CAPITAL LETTER T WITH HOOK
-\setcclcucx 01AD 01AD 01AC % LATIN SMALL LETTER T WITH HOOK
-\setcclcucx 01AE 0288 01AE % LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
-\setcclcucx 01AF 01B0 01AF % LATIN CAPITAL LETTER U WITH HORN
-\setcclcucx 01B0 01B0 01AF % LATIN SMALL LETTER U WITH HORN
-\setcclcucx 01B1 028A 01B1 % LATIN CAPITAL LETTER UPSILON
-\setcclcucx 01B2 028B 01B2 % LATIN CAPITAL LETTER V WITH HOOK
-\setcclcucx 01B3 01B4 01B3 % LATIN CAPITAL LETTER Y WITH HOOK
-\setcclcucx 01B4 01B4 01B3 % LATIN SMALL LETTER Y WITH HOOK
-\setcclcucx 01B5 01B6 01B5 % LATIN CAPITAL LETTER Z WITH STROKE
-\setcclcucx 01B6 01B6 01B5 % LATIN SMALL LETTER Z WITH STROKE
-\setcclcucx 01B7 0292 01B7 % LATIN CAPITAL LETTER EZH
-\setcclcucx 01B8 01B9 01B8 % LATIN CAPITAL LETTER EZH REVERSED
-\setcclcucx 01B9 01B9 01B8 % LATIN SMALL LETTER EZH REVERSED
-\setcclcucx 01BA 01BA 01BA % LATIN SMALL LETTER EZH WITH TAIL
-\setcclcucx 01BC 01BD 01BC % LATIN CAPITAL LETTER TONE FIVE
-\setcclcucx 01BD 01BD 01BC % LATIN SMALL LETTER TONE FIVE
-\setcclcucx 01BE 01BE 01BE % LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE
-\setcclcucx 01BF 01BF 01F7 % LATIN LETTER WYNN
-\setcclcucx 01C4 01C6 01C5 % LATIN CAPITAL LETTER DZ WITH CARON
-\setcclcucx 01C5 01C6 01C4 % LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
-\setcclcucx 01C6 01C6 01C4 % LATIN SMALL LETTER DZ WITH CARON
-\setcclcucx 01C7 01C9 01C8 % LATIN CAPITAL LETTER LJ
-\setcclcucx 01C8 01C9 01C7 % LATIN CAPITAL LETTER L WITH SMALL LETTER J
-\setcclcucx 01C9 01C9 01C7 % LATIN SMALL LETTER LJ
-\setcclcucx 01CA 01CC 01CB % LATIN CAPITAL LETTER NJ
-\setcclcucx 01CB 01CC 01CA % LATIN CAPITAL LETTER N WITH SMALL LETTER J
-\setcclcucx 01CC 01CC 01CA % LATIN SMALL LETTER NJ
-\setcclcucx 01CD 01CE 01CD % LATIN CAPITAL LETTER A WITH CARON
-\setcclcucx 01CE 01CE 01CD % LATIN SMALL LETTER A WITH CARON
-\setcclcucx 01CF 01D0 01CF % LATIN CAPITAL LETTER I WITH CARON
-\setcclcucx 01D0 01D0 01CF % LATIN SMALL LETTER I WITH CARON
-\setcclcucx 01D1 01D2 01D1 % LATIN CAPITAL LETTER O WITH CARON
-\setcclcucx 01D2 01D2 01D1 % LATIN SMALL LETTER O WITH CARON
-\setcclcucx 01D3 01D4 01D3 % LATIN CAPITAL LETTER U WITH CARON
-\setcclcucx 01D4 01D4 01D3 % LATIN SMALL LETTER U WITH CARON
-\setcclcucx 01D5 01D6 01D5 % LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
-\setcclcucx 01D6 01D6 01D5 % LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
-\setcclcucx 01D7 01D8 01D7 % LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
-\setcclcucx 01D8 01D8 01D7 % LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
-\setcclcucx 01D9 01DA 01D9 % LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
-\setcclcucx 01DA 01DA 01D9 % LATIN SMALL LETTER U WITH DIAERESIS AND CARON
-\setcclcucx 01DB 01DC 01DB % LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
-\setcclcucx 01DC 01DC 01DB % LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
-\setcclcucx 01DD 01DD 018E % LATIN SMALL LETTER TURNED E
-\setcclcucx 01DE 01DF 01DE % LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
-\setcclcucx 01DF 01DF 01DE % LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
-\setcclcucx 01E0 01E1 01E0 % LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
-\setcclcucx 01E1 01E1 01E0 % LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
-\setcclcucx 01E2 01E3 01E2 % LATIN CAPITAL LETTER AE WITH MACRON
-\setcclcucx 01E3 01E3 01E2 % LATIN SMALL LETTER AE WITH MACRON
-\setcclcucx 01E4 01E5 01E4 % LATIN CAPITAL LETTER G WITH STROKE
-\setcclcucx 01E5 01E5 01E4 % LATIN SMALL LETTER G WITH STROKE
-\setcclcucx 01E6 01E7 01E6 % LATIN CAPITAL LETTER G WITH CARON
-\setcclcucx 01E7 01E7 01E6 % LATIN SMALL LETTER G WITH CARON
-\setcclcucx 01E8 01E9 01E8 % LATIN CAPITAL LETTER K WITH CARON
-\setcclcucx 01E9 01E9 01E8 % LATIN SMALL LETTER K WITH CARON
-\setcclcucx 01EA 01EB 01EA % LATIN CAPITAL LETTER O WITH OGONEK
-\setcclcucx 01EB 01EB 01EA % LATIN SMALL LETTER O WITH OGONEK
-\setcclcucx 01EC 01ED 01EC % LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
-\setcclcucx 01ED 01ED 01EC % LATIN SMALL LETTER O WITH OGONEK AND MACRON
-\setcclcucx 01EE 01EF 01EE % LATIN CAPITAL LETTER EZH WITH CARON
-\setcclcucx 01EF 01EF 01EE % LATIN SMALL LETTER EZH WITH CARON
-\setcclcucx 01F0 01F0 01F0 % LATIN SMALL LETTER J WITH CARON
-\setcclcucx 01F1 01F3 01F2 % LATIN CAPITAL LETTER DZ
-\setcclcucx 01F2 01F3 01F1 % LATIN CAPITAL LETTER D WITH SMALL LETTER Z
-\setcclcucx 01F3 01F3 01F1 % LATIN SMALL LETTER DZ
-\setcclcucx 01F4 01F5 01F4 % LATIN CAPITAL LETTER G WITH ACUTE
-\setcclcucx 01F5 01F5 01F4 % LATIN SMALL LETTER G WITH ACUTE
-\setcclcucx 01F6 0195 01F6 % LATIN CAPITAL LETTER HWAIR
-\setcclcucx 01F7 01BF 01F7 % LATIN CAPITAL LETTER WYNN
-\setcclcucx 01F8 01F9 01F8 % LATIN CAPITAL LETTER N WITH GRAVE
-\setcclcucx 01F9 01F9 01F8 % LATIN SMALL LETTER N WITH GRAVE
-\setcclcucx 01FA 01FB 01FA % LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
-\setcclcucx 01FB 01FB 01FA % LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
-\setcclcucx 01FC 01FD 01FC % LATIN CAPITAL LETTER AE WITH ACUTE
-\setcclcucx 01FD 01FD 01FC % LATIN SMALL LETTER AE WITH ACUTE
-\setcclcucx 01FE 01FF 01FE % LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
-\setcclcucx 01FF 01FF 01FE % LATIN SMALL LETTER O WITH STROKE AND ACUTE
-\setcclcucx 0200 0201 0200 % LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
-\setcclcucx 0201 0201 0200 % LATIN SMALL LETTER A WITH DOUBLE GRAVE
-\setcclcucx 0202 0203 0202 % LATIN CAPITAL LETTER A WITH INVERTED BREVE
-\setcclcucx 0203 0203 0202 % LATIN SMALL LETTER A WITH INVERTED BREVE
-\setcclcucx 0204 0205 0204 % LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
-\setcclcucx 0205 0205 0204 % LATIN SMALL LETTER E WITH DOUBLE GRAVE
-\setcclcucx 0206 0207 0206 % LATIN CAPITAL LETTER E WITH INVERTED BREVE
-\setcclcucx 0207 0207 0206 % LATIN SMALL LETTER E WITH INVERTED BREVE
-\setcclcucx 0208 0209 0208 % LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
-\setcclcucx 0209 0209 0208 % LATIN SMALL LETTER I WITH DOUBLE GRAVE
-\setcclcucx 020A 020B 020A % LATIN CAPITAL LETTER I WITH INVERTED BREVE
-\setcclcucx 020B 020B 020A % LATIN SMALL LETTER I WITH INVERTED BREVE
-\setcclcucx 020C 020D 020C % LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
-\setcclcucx 020D 020D 020C % LATIN SMALL LETTER O WITH DOUBLE GRAVE
-\setcclcucx 020E 020F 020E % LATIN CAPITAL LETTER O WITH INVERTED BREVE
-\setcclcucx 020F 020F 020E % LATIN SMALL LETTER O WITH INVERTED BREVE
-\setcclcucx 0210 0211 0210 % LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
-\setcclcucx 0211 0211 0210 % LATIN SMALL LETTER R WITH DOUBLE GRAVE
-\setcclcucx 0212 0213 0212 % LATIN CAPITAL LETTER R WITH INVERTED BREVE
-\setcclcucx 0213 0213 0212 % LATIN SMALL LETTER R WITH INVERTED BREVE
-\setcclcucx 0214 0215 0214 % LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
-\setcclcucx 0215 0215 0214 % LATIN SMALL LETTER U WITH DOUBLE GRAVE
-\setcclcucx 0216 0217 0216 % LATIN CAPITAL LETTER U WITH INVERTED BREVE
-\setcclcucx 0217 0217 0216 % LATIN SMALL LETTER U WITH INVERTED BREVE
-\setcclcucx 0218 0219 0218 % LATIN CAPITAL LETTER S WITH COMMA BELOW
-\setcclcucx 0219 0219 0218 % LATIN SMALL LETTER S WITH COMMA BELOW
-\setcclcucx 021A 021B 021A % LATIN CAPITAL LETTER T WITH COMMA BELOW
-\setcclcucx 021B 021B 021A % LATIN SMALL LETTER T WITH COMMA BELOW
-\setcclcucx 021C 021D 021C % LATIN CAPITAL LETTER YOGH
-\setcclcucx 021D 021D 021C % LATIN SMALL LETTER YOGH
-\setcclcucx 021E 021F 021E % LATIN CAPITAL LETTER H WITH CARON
-\setcclcucx 021F 021F 021E % LATIN SMALL LETTER H WITH CARON
-\setcclcucx 0220 019E 0220 % LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
-\setcclcucx 0221 0221 0221 % LATIN SMALL LETTER D WITH CURL
-\setcclcucx 0222 0223 0222 % LATIN CAPITAL LETTER OU
-\setcclcucx 0223 0223 0222 % LATIN SMALL LETTER OU
-\setcclcucx 0224 0225 0224 % LATIN CAPITAL LETTER Z WITH HOOK
-\setcclcucx 0225 0225 0224 % LATIN SMALL LETTER Z WITH HOOK
-\setcclcucx 0226 0227 0226 % LATIN CAPITAL LETTER A WITH DOT ABOVE
-\setcclcucx 0227 0227 0226 % LATIN SMALL LETTER A WITH DOT ABOVE
-\setcclcucx 0228 0229 0228 % LATIN CAPITAL LETTER E WITH CEDILLA
-\setcclcucx 0229 0229 0228 % LATIN SMALL LETTER E WITH CEDILLA
-\setcclcucx 022A 022B 022A % LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
-\setcclcucx 022B 022B 022A % LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
-\setcclcucx 022C 022D 022C % LATIN CAPITAL LETTER O WITH TILDE AND MACRON
-\setcclcucx 022D 022D 022C % LATIN SMALL LETTER O WITH TILDE AND MACRON
-\setcclcucx 022E 022F 022E % LATIN CAPITAL LETTER O WITH DOT ABOVE
-\setcclcucx 022F 022F 022E % LATIN SMALL LETTER O WITH DOT ABOVE
-\setcclcucx 0230 0231 0230 % LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
-\setcclcucx 0231 0231 0230 % LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
-\setcclcucx 0232 0233 0232 % LATIN CAPITAL LETTER Y WITH MACRON
-\setcclcucx 0233 0233 0232 % LATIN SMALL LETTER Y WITH MACRON
-\setcclcucx 0234 0234 0234 % LATIN SMALL LETTER L WITH CURL
-\setcclcucx 0235 0235 0235 % LATIN SMALL LETTER N WITH CURL
-\setcclcucx 0236 0236 0236 % LATIN SMALL LETTER T WITH CURL
-\setcclcucx 0237 0237 0237 % LATIN SMALL LETTER DOTLESS J
-\setcclcucx 0238 0238 0238 % LATIN SMALL LETTER DB DIGRAPH
-\setcclcucx 0239 0239 0239 % LATIN SMALL LETTER QP DIGRAPH
-\setcclcucx 023A 2C65 023A % LATIN CAPITAL LETTER A WITH STROKE
-\setcclcucx 023B 023C 023B % LATIN CAPITAL LETTER C WITH STROKE
-\setcclcucx 023C 023C 023B % LATIN SMALL LETTER C WITH STROKE
-\setcclcucx 023D 019A 023D % LATIN CAPITAL LETTER L WITH BAR
-\setcclcucx 023E 2C66 023E % LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
-\setcclcucx 023F 023F 023F % LATIN SMALL LETTER S WITH SWASH TAIL
-\setcclcucx 0240 0240 0240 % LATIN SMALL LETTER Z WITH SWASH TAIL
-\setcclcucx 0241 0242 0241 % LATIN CAPITAL LETTER GLOTTAL STOP
-\setcclcucx 0242 0242 0241 % LATIN SMALL LETTER GLOTTAL STOP
-\setcclcucx 0243 0180 0243 % LATIN CAPITAL LETTER B WITH STROKE
-\setcclcucx 0244 0289 0244 % LATIN CAPITAL LETTER U BAR
-\setcclcucx 0245 028C 0245 % LATIN CAPITAL LETTER TURNED V
-\setcclcucx 0246 0247 0246 % LATIN CAPITAL LETTER E WITH STROKE
-\setcclcucx 0247 0247 0246 % LATIN SMALL LETTER E WITH STROKE
-\setcclcucx 0248 0249 0248 % LATIN CAPITAL LETTER J WITH STROKE
-\setcclcucx 0249 0249 0248 % LATIN SMALL LETTER J WITH STROKE
-\setcclcucx 024A 024B 024A % LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
-\setcclcucx 024B 024B 024A % LATIN SMALL LETTER Q WITH HOOK TAIL
-\setcclcucx 024C 024D 024C % LATIN CAPITAL LETTER R WITH STROKE
-\setcclcucx 024D 024D 024C % LATIN SMALL LETTER R WITH STROKE
-\setcclcucx 024E 024F 024E % LATIN CAPITAL LETTER Y WITH STROKE
-\setcclcucx 024F 024F 024E % LATIN SMALL LETTER Y WITH STROKE
-\setcclcucx 0250 0250 0250 % LATIN SMALL LETTER TURNED A
-\setcclcucx 0251 0251 0251 % LATIN SMALL LETTER ALPHA
-\setcclcucx 0252 0252 0252 % LATIN SMALL LETTER TURNED ALPHA
-\setcclcucx 0253 0253 0181 % LATIN SMALL LETTER B WITH HOOK
-\setcclcucx 0254 0254 0186 % LATIN SMALL LETTER OPEN O
-\setcclcucx 0255 0255 0255 % LATIN SMALL LETTER C WITH CURL
-\setcclcucx 0256 0256 0189 % LATIN SMALL LETTER D WITH TAIL
-\setcclcucx 0257 0257 018A % LATIN SMALL LETTER D WITH HOOK
-\setcclcucx 0258 0258 0258 % LATIN SMALL LETTER REVERSED E
-\setcclcucx 0259 0259 018F % LATIN SMALL LETTER SCHWA
-\setcclcucx 025A 025A 025A % LATIN SMALL LETTER SCHWA WITH HOOK
-\setcclcucx 025B 025B 0190 % LATIN SMALL LETTER OPEN E
-\setcclcucx 025C 025C 025C % LATIN SMALL LETTER REVERSED OPEN E
-\setcclcucx 025D 025D 025D % LATIN SMALL LETTER REVERSED OPEN E WITH HOOK
-\setcclcucx 025E 025E 025E % LATIN SMALL LETTER CLOSED REVERSED OPEN E
-\setcclcucx 025F 025F 025F % LATIN SMALL LETTER DOTLESS J WITH STROKE
-\setcclcucx 0260 0260 0193 % LATIN SMALL LETTER G WITH HOOK
-\setcclcucx 0261 0261 0261 % LATIN SMALL LETTER SCRIPT G
-\setcclcucx 0262 0262 0262 % LATIN LETTER SMALL CAPITAL G
-\setcclcucx 0263 0263 0194 % LATIN SMALL LETTER GAMMA
-\setcclcucx 0264 0264 0264 % LATIN SMALL LETTER RAMS HORN
-\setcclcucx 0265 0265 0265 % LATIN SMALL LETTER TURNED H
-\setcclcucx 0266 0266 0266 % LATIN SMALL LETTER H WITH HOOK
-\setcclcucx 0267 0267 0267 % LATIN SMALL LETTER HENG WITH HOOK
-\setcclcucx 0268 0268 0197 % LATIN SMALL LETTER I WITH STROKE
-\setcclcucx 0269 0269 0196 % LATIN SMALL LETTER IOTA
-\setcclcucx 026A 026A 026A % LATIN LETTER SMALL CAPITAL I
-\setcclcucx 026B 026B 2C62 % LATIN SMALL LETTER L WITH MIDDLE TILDE
-\setcclcucx 026C 026C 026C % LATIN SMALL LETTER L WITH BELT
-\setcclcucx 026D 026D 026D % LATIN SMALL LETTER L WITH RETROFLEX HOOK
-\setcclcucx 026E 026E 026E % LATIN SMALL LETTER LEZH
-\setcclcucx 026F 026F 019C % LATIN SMALL LETTER TURNED M
-\setcclcucx 0270 0270 0270 % LATIN SMALL LETTER TURNED M WITH LONG LEG
-\setcclcucx 0271 0271 0271 % LATIN SMALL LETTER M WITH HOOK
-\setcclcucx 0272 0272 019D % LATIN SMALL LETTER N WITH LEFT HOOK
-\setcclcucx 0273 0273 0273 % LATIN SMALL LETTER N WITH RETROFLEX HOOK
-\setcclcucx 0274 0274 0274 % LATIN LETTER SMALL CAPITAL N
-\setcclcucx 0275 0275 019F % LATIN SMALL LETTER BARRED O
-\setcclcucx 0276 0276 0276 % LATIN LETTER SMALL CAPITAL OE
-\setcclcucx 0277 0277 0277 % LATIN SMALL LETTER CLOSED OMEGA
-\setcclcucx 0278 0278 0278 % LATIN SMALL LETTER PHI
-\setcclcucx 0279 0279 0279 % LATIN SMALL LETTER TURNED R
-\setcclcucx 027A 027A 027A % LATIN SMALL LETTER TURNED R WITH LONG LEG
-\setcclcucx 027B 027B 027B % LATIN SMALL LETTER TURNED R WITH HOOK
-\setcclcucx 027C 027C 027C % LATIN SMALL LETTER R WITH LONG LEG
-\setcclcucx 027D 027D 2C64 % LATIN SMALL LETTER R WITH TAIL
-\setcclcucx 027E 027E 027E % LATIN SMALL LETTER R WITH FISHHOOK
-\setcclcucx 027F 027F 027F % LATIN SMALL LETTER REVERSED R WITH FISHHOOK
-\setcclcucx 0280 0280 01A6 % LATIN LETTER SMALL CAPITAL R
-\setcclcucx 0281 0281 0281 % LATIN LETTER SMALL CAPITAL INVERTED R
-\setcclcucx 0282 0282 0282 % LATIN SMALL LETTER S WITH HOOK
-\setcclcucx 0283 0283 01A9 % LATIN SMALL LETTER ESH
-\setcclcucx 0284 0284 0284 % LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK
-\setcclcucx 0285 0285 0285 % LATIN SMALL LETTER SQUAT REVERSED ESH
-\setcclcucx 0286 0286 0286 % LATIN SMALL LETTER ESH WITH CURL
-\setcclcucx 0287 0287 0287 % LATIN SMALL LETTER TURNED T
-\setcclcucx 0288 0288 01AE % LATIN SMALL LETTER T WITH RETROFLEX HOOK
-\setcclcucx 0289 0289 0244 % LATIN SMALL LETTER U BAR
-\setcclcucx 028A 028A 01B1 % LATIN SMALL LETTER UPSILON
-\setcclcucx 028B 028B 01B2 % LATIN SMALL LETTER V WITH HOOK
-\setcclcucx 028C 028C 0245 % LATIN SMALL LETTER TURNED V
-\setcclcucx 028D 028D 028D % LATIN SMALL LETTER TURNED W
-\setcclcucx 028E 028E 028E % LATIN SMALL LETTER TURNED Y
-\setcclcucx 028F 028F 028F % LATIN LETTER SMALL CAPITAL Y
-\setcclcucx 0290 0290 0290 % LATIN SMALL LETTER Z WITH RETROFLEX HOOK
-\setcclcucx 0291 0291 0291 % LATIN SMALL LETTER Z WITH CURL
-\setcclcucx 0292 0292 01B7 % LATIN SMALL LETTER EZH
-\setcclcucx 0293 0293 0293 % LATIN SMALL LETTER EZH WITH CURL
-\setcclcucx 0295 0295 0295 % LATIN LETTER PHARYNGEAL VOICED FRICATIVE
-\setcclcucx 0296 0296 0296 % LATIN LETTER INVERTED GLOTTAL STOP
-\setcclcucx 0297 0297 0297 % LATIN LETTER STRETCHED C
-\setcclcucx 0298 0298 0298 % LATIN LETTER BILABIAL CLICK
-\setcclcucx 0299 0299 0299 % LATIN LETTER SMALL CAPITAL B
-\setcclcucx 029A 029A 029A % LATIN SMALL LETTER CLOSED OPEN E
-\setcclcucx 029B 029B 029B % LATIN LETTER SMALL CAPITAL G WITH HOOK
-\setcclcucx 029C 029C 029C % LATIN LETTER SMALL CAPITAL H
-\setcclcucx 029D 029D 029D % LATIN SMALL LETTER J WITH CROSSED-TAIL
-\setcclcucx 029E 029E 029E % LATIN SMALL LETTER TURNED K
-\setcclcucx 029F 029F 029F % LATIN LETTER SMALL CAPITAL L
-\setcclcucx 02A0 02A0 02A0 % LATIN SMALL LETTER Q WITH HOOK
-\setcclcucx 02A1 02A1 02A1 % LATIN LETTER GLOTTAL STOP WITH STROKE
-\setcclcucx 02A2 02A2 02A2 % LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE
-\setcclcucx 02A3 02A3 02A3 % LATIN SMALL LETTER DZ DIGRAPH
-\setcclcucx 02A4 02A4 02A4 % LATIN SMALL LETTER DEZH DIGRAPH
-\setcclcucx 02A5 02A5 02A5 % LATIN SMALL LETTER DZ DIGRAPH WITH CURL
-\setcclcucx 02A6 02A6 02A6 % LATIN SMALL LETTER TS DIGRAPH
-\setcclcucx 02A7 02A7 02A7 % LATIN SMALL LETTER TESH DIGRAPH
-\setcclcucx 02A8 02A8 02A8 % LATIN SMALL LETTER TC DIGRAPH WITH CURL
-\setcclcucx 02A9 02A9 02A9 % LATIN SMALL LETTER FENG DIGRAPH
-\setcclcucx 02AA 02AA 02AA % LATIN SMALL LETTER LS DIGRAPH
-\setcclcucx 02AB 02AB 02AB % LATIN SMALL LETTER LZ DIGRAPH
-\setcclcucx 02AC 02AC 02AC % LATIN LETTER BILABIAL PERCUSSIVE
-\setcclcucx 02AD 02AD 02AD % LATIN LETTER BIDENTAL PERCUSSIVE
-\setcclcucx 02AE 02AE 02AE % LATIN SMALL LETTER TURNED H WITH FISHHOOK
-\setcclcucx 02AF 02AF 02AF % LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
-\setcclcucx 037B 037B 03FD % GREEK SMALL REVERSED LUNATE SIGMA SYMBOL
-\setcclcucx 037C 037C 03FE % GREEK SMALL DOTTED LUNATE SIGMA SYMBOL
-\setcclcucx 037D 037D 03FF % GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
-\setcclcucx 0386 03AC 0386 % GREEK CAPITAL LETTER ALPHA WITH TONOS
-\setcclcucx 0388 03AD 0388 % GREEK CAPITAL LETTER EPSILON WITH TONOS
-\setcclcucx 0389 03AE 0389 % GREEK CAPITAL LETTER ETA WITH TONOS
-\setcclcucx 038A 03AF 038A % GREEK CAPITAL LETTER IOTA WITH TONOS
-\setcclcucx 038C 03CC 038C % GREEK CAPITAL LETTER OMICRON WITH TONOS
-\setcclcucx 038E 03CD 038E % GREEK CAPITAL LETTER UPSILON WITH TONOS
-\setcclcucx 038F 03CE 038F % GREEK CAPITAL LETTER OMEGA WITH TONOS
-\setcclcucx 0390 0390 0390 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
-\setcclcucx 0391 03B1 0391 % GREEK CAPITAL LETTER ALPHA
-\setcclcucx 0392 03B2 0392 % GREEK CAPITAL LETTER BETA
-\setcclcucx 0393 03B3 0393 % GREEK CAPITAL LETTER GAMMA
-\setcclcucx 0394 03B4 0394 % GREEK CAPITAL LETTER DELTA
-\setcclcucx 0395 03B5 0395 % GREEK CAPITAL LETTER EPSILON
-\setcclcucx 0396 03B6 0396 % GREEK CAPITAL LETTER ZETA
-\setcclcucx 0397 03B7 0397 % GREEK CAPITAL LETTER ETA
-\setcclcucx 0398 03B8 0398 % GREEK CAPITAL LETTER THETA
-\setcclcucx 0399 03B9 0399 % GREEK CAPITAL LETTER IOTA
-\setcclcucx 039A 03BA 039A % GREEK CAPITAL LETTER KAPPA
-\setcclcucx 039B 03BB 039B % GREEK CAPITAL LETTER LAMDA
-\setcclcucx 039C 03BC 039C % GREEK CAPITAL LETTER MU
-\setcclcucx 039D 03BD 039D % GREEK CAPITAL LETTER NU
-\setcclcucx 039E 03BE 039E % GREEK CAPITAL LETTER XI
-\setcclcucx 039F 03BF 039F % GREEK CAPITAL LETTER OMICRON
-\setcclcucx 03A0 03C0 03A0 % GREEK CAPITAL LETTER PI
-\setcclcucx 03A1 03C1 03A1 % GREEK CAPITAL LETTER RHO
-\setcclcucx 03A3 03C3 03A3 % GREEK CAPITAL LETTER SIGMA
-\setcclcucx 03A4 03C4 03A4 % GREEK CAPITAL LETTER TAU
-\setcclcucx 03A5 03C5 03A5 % GREEK CAPITAL LETTER UPSILON
-\setcclcucx 03A6 03C6 03A6 % GREEK CAPITAL LETTER PHI
-\setcclcucx 03A7 03C7 03A7 % GREEK CAPITAL LETTER CHI
-\setcclcucx 03A8 03C8 03A8 % GREEK CAPITAL LETTER PSI
-\setcclcucx 03A9 03C9 03A9 % GREEK CAPITAL LETTER OMEGA
-\setcclcucx 03AA 03CA 03AA % GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
-\setcclcucx 03AB 03CB 03AB % GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
-\setcclcucx 03AC 03AC 0386 % GREEK SMALL LETTER ALPHA WITH TONOS
-\setcclcucx 03AD 03AD 0388 % GREEK SMALL LETTER EPSILON WITH TONOS
-\setcclcucx 03AE 03AE 0389 % GREEK SMALL LETTER ETA WITH TONOS
-\setcclcucx 03AF 03AF 038A % GREEK SMALL LETTER IOTA WITH TONOS
-\setcclcucx 03B0 03B0 03B0 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
-\setcclcucx 03B1 03B1 0391 % GREEK SMALL LETTER ALPHA
-\setcclcucx 03B2 03B2 0392 % GREEK SMALL LETTER BETA
-\setcclcucx 03B3 03B3 0393 % GREEK SMALL LETTER GAMMA
-\setcclcucx 03B4 03B4 0394 % GREEK SMALL LETTER DELTA
-\setcclcucx 03B5 03B5 0395 % GREEK SMALL LETTER EPSILON
-\setcclcucx 03B6 03B6 0396 % GREEK SMALL LETTER ZETA
-\setcclcucx 03B7 03B7 0397 % GREEK SMALL LETTER ETA
-\setcclcucx 03B8 03B8 0398 % GREEK SMALL LETTER THETA
-\setcclcucx 03B9 03B9 0399 % GREEK SMALL LETTER IOTA
-\setcclcucx 03BA 03BA 039A % GREEK SMALL LETTER KAPPA
-\setcclcucx 03BB 03BB 039B % GREEK SMALL LETTER LAMDA
-\setcclcucx 03BC 03BC 039C % GREEK SMALL LETTER MU
-\setcclcucx 03BD 03BD 039D % GREEK SMALL LETTER NU
-\setcclcucx 03BE 03BE 039E % GREEK SMALL LETTER XI
-\setcclcucx 03BF 03BF 039F % GREEK SMALL LETTER OMICRON
-\setcclcucx 03C0 03C0 03A0 % GREEK SMALL LETTER PI
-\setcclcucx 03C1 03C1 03A1 % GREEK SMALL LETTER RHO
-\setcclcucx 03C2 03C2 03A3 % GREEK SMALL LETTER FINAL SIGMA
-\setcclcucx 03C3 03C3 03A3 % GREEK SMALL LETTER SIGMA
-\setcclcucx 03C4 03C4 03A4 % GREEK SMALL LETTER TAU
-\setcclcucx 03C5 03C5 03A5 % GREEK SMALL LETTER UPSILON
-\setcclcucx 03C6 03C6 03A6 % GREEK SMALL LETTER PHI
-\setcclcucx 03C7 03C7 03A7 % GREEK SMALL LETTER CHI
-\setcclcucx 03C8 03C8 03A8 % GREEK SMALL LETTER PSI
-\setcclcucx 03C9 03C9 03A9 % GREEK SMALL LETTER OMEGA
-\setcclcucx 03CA 03CA 03AA % GREEK SMALL LETTER IOTA WITH DIALYTIKA
-\setcclcucx 03CB 03CB 03AB % GREEK SMALL LETTER UPSILON WITH DIALYTIKA
-\setcclcucx 03CC 03CC 038C % GREEK SMALL LETTER OMICRON WITH TONOS
-\setcclcucx 03CD 03CD 038E % GREEK SMALL LETTER UPSILON WITH TONOS
-\setcclcucx 03CE 03CE 038F % GREEK SMALL LETTER OMEGA WITH TONOS
-\setcclcucx 03D0 03D0 0392 % GREEK BETA SYMBOL
-\setcclcucx 03D1 03D1 0398 % GREEK THETA SYMBOL
-\setcclcucx 03D2 03D2 03D2 % GREEK UPSILON WITH HOOK SYMBOL
-\setcclcucx 03D3 03D3 03D3 % GREEK UPSILON WITH ACUTE AND HOOK SYMBOL
-\setcclcucx 03D4 03D4 03D4 % GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL
-\setcclcucx 03D5 03D5 03A6 % GREEK PHI SYMBOL
-\setcclcucx 03D6 03D6 03A0 % GREEK PI SYMBOL
-\setcclcucx 03D7 03D7 03D7 % GREEK KAI SYMBOL
-\setcclcucx 03D8 03D9 03D8 % GREEK LETTER ARCHAIC KOPPA
-\setcclcucx 03D9 03D9 03D8 % GREEK SMALL LETTER ARCHAIC KOPPA
-\setcclcucx 03DA 03DB 03DA % GREEK LETTER STIGMA
-\setcclcucx 03DB 03DB 03DA % GREEK SMALL LETTER STIGMA
-\setcclcucx 03DC 03DD 03DC % GREEK LETTER DIGAMMA
-\setcclcucx 03DD 03DD 03DC % GREEK SMALL LETTER DIGAMMA
-\setcclcucx 03DE 03DF 03DE % GREEK LETTER KOPPA
-\setcclcucx 03DF 03DF 03DE % GREEK SMALL LETTER KOPPA
-\setcclcucx 03E0 03E1 03E0 % GREEK LETTER SAMPI
-\setcclcucx 03E1 03E1 03E0 % GREEK SMALL LETTER SAMPI
-\setcclcucx 03E2 03E3 03E2 % COPTIC CAPITAL LETTER SHEI
-\setcclcucx 03E3 03E3 03E2 % COPTIC SMALL LETTER SHEI
-\setcclcucx 03E4 03E5 03E4 % COPTIC CAPITAL LETTER FEI
-\setcclcucx 03E5 03E5 03E4 % COPTIC SMALL LETTER FEI
-\setcclcucx 03E6 03E7 03E6 % COPTIC CAPITAL LETTER KHEI
-\setcclcucx 03E7 03E7 03E6 % COPTIC SMALL LETTER KHEI
-\setcclcucx 03E8 03E9 03E8 % COPTIC CAPITAL LETTER HORI
-\setcclcucx 03E9 03E9 03E8 % COPTIC SMALL LETTER HORI
-\setcclcucx 03EA 03EB 03EA % COPTIC CAPITAL LETTER GANGIA
-\setcclcucx 03EB 03EB 03EA % COPTIC SMALL LETTER GANGIA
-\setcclcucx 03EC 03ED 03EC % COPTIC CAPITAL LETTER SHIMA
-\setcclcucx 03ED 03ED 03EC % COPTIC SMALL LETTER SHIMA
-\setcclcucx 03EE 03EF 03EE % COPTIC CAPITAL LETTER DEI
-\setcclcucx 03EF 03EF 03EE % COPTIC SMALL LETTER DEI
-\setcclcucx 03F0 03F0 039A % GREEK KAPPA SYMBOL
-\setcclcucx 03F1 03F1 03A1 % GREEK RHO SYMBOL
-\setcclcucx 03F2 03F2 03F9 % GREEK LUNATE SIGMA SYMBOL
-\setcclcucx 03F3 03F3 03F3 % GREEK LETTER YOT
-\setcclcucx 03F4 03B8 03F4 % GREEK CAPITAL THETA SYMBOL
-\setcclcucx 03F5 03F5 0395 % GREEK LUNATE EPSILON SYMBOL
-\setcclcucx 03F7 03F8 03F7 % GREEK CAPITAL LETTER SHO
-\setcclcucx 03F8 03F8 03F7 % GREEK SMALL LETTER SHO
-\setcclcucx 03F9 03F2 03F9 % GREEK CAPITAL LUNATE SIGMA SYMBOL
-\setcclcucx 03FA 03FB 03FA % GREEK CAPITAL LETTER SAN
-\setcclcucx 03FB 03FB 03FA % GREEK SMALL LETTER SAN
-\setcclcucx 03FC 03FC 03FC % GREEK RHO WITH STROKE SYMBOL
-\setcclcucx 03FD 037B 03FD % GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL
-\setcclcucx 03FE 037C 03FE % GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL
-\setcclcucx 03FF 037D 03FF % GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
-\setcclcucx 0400 0450 0400 % CYRILLIC CAPITAL LETTER IE WITH GRAVE
-\setcclcucx 0401 0451 0401 % CYRILLIC CAPITAL LETTER IO
-\setcclcucx 0402 0452 0402 % CYRILLIC CAPITAL LETTER DJE
-\setcclcucx 0403 0453 0403 % CYRILLIC CAPITAL LETTER GJE
-\setcclcucx 0404 0454 0404 % CYRILLIC CAPITAL LETTER UKRAINIAN IE
-\setcclcucx 0405 0455 0405 % CYRILLIC CAPITAL LETTER DZE
-\setcclcucx 0406 0456 0406 % CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
-\setcclcucx 0407 0457 0407 % CYRILLIC CAPITAL LETTER YI
-\setcclcucx 0408 0458 0408 % CYRILLIC CAPITAL LETTER JE
-\setcclcucx 0409 0459 0409 % CYRILLIC CAPITAL LETTER LJE
-\setcclcucx 040A 045A 040A % CYRILLIC CAPITAL LETTER NJE
-\setcclcucx 040B 045B 040B % CYRILLIC CAPITAL LETTER TSHE
-\setcclcucx 040C 045C 040C % CYRILLIC CAPITAL LETTER KJE
-\setcclcucx 040D 045D 040D % CYRILLIC CAPITAL LETTER I WITH GRAVE
-\setcclcucx 040E 045E 040E % CYRILLIC CAPITAL LETTER SHORT U
-\setcclcucx 040F 045F 040F % CYRILLIC CAPITAL LETTER DZHE
-\setcclcucx 0410 0430 0410 % CYRILLIC CAPITAL LETTER A
-\setcclcucx 0411 0431 0411 % CYRILLIC CAPITAL LETTER BE
-\setcclcucx 0412 0432 0412 % CYRILLIC CAPITAL LETTER VE
-\setcclcucx 0413 0433 0413 % CYRILLIC CAPITAL LETTER GHE
-\setcclcucx 0414 0434 0414 % CYRILLIC CAPITAL LETTER DE
-\setcclcucx 0415 0435 0415 % CYRILLIC CAPITAL LETTER IE
-\setcclcucx 0416 0436 0416 % CYRILLIC CAPITAL LETTER ZHE
-\setcclcucx 0417 0437 0417 % CYRILLIC CAPITAL LETTER ZE
-\setcclcucx 0418 0438 0418 % CYRILLIC CAPITAL LETTER I
-\setcclcucx 0419 0439 0419 % CYRILLIC CAPITAL LETTER SHORT I
-\setcclcucx 041A 043A 041A % CYRILLIC CAPITAL LETTER KA
-\setcclcucx 041B 043B 041B % CYRILLIC CAPITAL LETTER EL
-\setcclcucx 041C 043C 041C % CYRILLIC CAPITAL LETTER EM
-\setcclcucx 041D 043D 041D % CYRILLIC CAPITAL LETTER EN
-\setcclcucx 041E 043E 041E % CYRILLIC CAPITAL LETTER O
-\setcclcucx 041F 043F 041F % CYRILLIC CAPITAL LETTER PE
-\setcclcucx 0420 0440 0420 % CYRILLIC CAPITAL LETTER ER
-\setcclcucx 0421 0441 0421 % CYRILLIC CAPITAL LETTER ES
-\setcclcucx 0422 0442 0422 % CYRILLIC CAPITAL LETTER TE
-\setcclcucx 0423 0443 0423 % CYRILLIC CAPITAL LETTER U
-\setcclcucx 0424 0444 0424 % CYRILLIC CAPITAL LETTER EF
-\setcclcucx 0425 0445 0425 % CYRILLIC CAPITAL LETTER HA
-\setcclcucx 0426 0446 0426 % CYRILLIC CAPITAL LETTER TSE
-\setcclcucx 0427 0447 0427 % CYRILLIC CAPITAL LETTER CHE
-\setcclcucx 0428 0448 0428 % CYRILLIC CAPITAL LETTER SHA
-\setcclcucx 0429 0449 0429 % CYRILLIC CAPITAL LETTER SHCHA
-\setcclcucx 042A 044A 042A % CYRILLIC CAPITAL LETTER HARD SIGN
-\setcclcucx 042B 044B 042B % CYRILLIC CAPITAL LETTER YERU
-\setcclcucx 042C 044C 042C % CYRILLIC CAPITAL LETTER SOFT SIGN
-\setcclcucx 042D 044D 042D % CYRILLIC CAPITAL LETTER E
-\setcclcucx 042E 044E 042E % CYRILLIC CAPITAL LETTER YU
-\setcclcucx 042F 044F 042F % CYRILLIC CAPITAL LETTER YA
-\setcclcucx 0430 0430 0410 % CYRILLIC SMALL LETTER A
-\setcclcucx 0431 0431 0411 % CYRILLIC SMALL LETTER BE
-\setcclcucx 0432 0432 0412 % CYRILLIC SMALL LETTER VE
-\setcclcucx 0433 0433 0413 % CYRILLIC SMALL LETTER GHE
-\setcclcucx 0434 0434 0414 % CYRILLIC SMALL LETTER DE
-\setcclcucx 0435 0435 0415 % CYRILLIC SMALL LETTER IE
-\setcclcucx 0436 0436 0416 % CYRILLIC SMALL LETTER ZHE
-\setcclcucx 0437 0437 0417 % CYRILLIC SMALL LETTER ZE
-\setcclcucx 0438 0438 0418 % CYRILLIC SMALL LETTER I
-\setcclcucx 0439 0439 0419 % CYRILLIC SMALL LETTER SHORT I
-\setcclcucx 043A 043A 041A % CYRILLIC SMALL LETTER KA
-\setcclcucx 043B 043B 041B % CYRILLIC SMALL LETTER EL
-\setcclcucx 043C 043C 041C % CYRILLIC SMALL LETTER EM
-\setcclcucx 043D 043D 041D % CYRILLIC SMALL LETTER EN
-\setcclcucx 043E 043E 041E % CYRILLIC SMALL LETTER O
-\setcclcucx 043F 043F 041F % CYRILLIC SMALL LETTER PE
-\setcclcucx 0440 0440 0420 % CYRILLIC SMALL LETTER ER
-\setcclcucx 0441 0441 0421 % CYRILLIC SMALL LETTER ES
-\setcclcucx 0442 0442 0422 % CYRILLIC SMALL LETTER TE
-\setcclcucx 0443 0443 0423 % CYRILLIC SMALL LETTER U
-\setcclcucx 0444 0444 0424 % CYRILLIC SMALL LETTER EF
-\setcclcucx 0445 0445 0425 % CYRILLIC SMALL LETTER HA
-\setcclcucx 0446 0446 0426 % CYRILLIC SMALL LETTER TSE
-\setcclcucx 0447 0447 0427 % CYRILLIC SMALL LETTER CHE
-\setcclcucx 0448 0448 0428 % CYRILLIC SMALL LETTER SHA
-\setcclcucx 0449 0449 0429 % CYRILLIC SMALL LETTER SHCHA
-\setcclcucx 044A 044A 042A % CYRILLIC SMALL LETTER HARD SIGN
-\setcclcucx 044B 044B 042B % CYRILLIC SMALL LETTER YERU
-\setcclcucx 044C 044C 042C % CYRILLIC SMALL LETTER SOFT SIGN
-\setcclcucx 044D 044D 042D % CYRILLIC SMALL LETTER E
-\setcclcucx 044E 044E 042E % CYRILLIC SMALL LETTER YU
-\setcclcucx 044F 044F 042F % CYRILLIC SMALL LETTER YA
-\setcclcucx 0450 0450 0400 % CYRILLIC SMALL LETTER IE WITH GRAVE
-\setcclcucx 0451 0451 0401 % CYRILLIC SMALL LETTER IO
-\setcclcucx 0452 0452 0402 % CYRILLIC SMALL LETTER DJE
-\setcclcucx 0453 0453 0403 % CYRILLIC SMALL LETTER GJE
-\setcclcucx 0454 0454 0404 % CYRILLIC SMALL LETTER UKRAINIAN IE
-\setcclcucx 0455 0455 0405 % CYRILLIC SMALL LETTER DZE
-\setcclcucx 0456 0456 0406 % CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
-\setcclcucx 0457 0457 0407 % CYRILLIC SMALL LETTER YI
-\setcclcucx 0458 0458 0408 % CYRILLIC SMALL LETTER JE
-\setcclcucx 0459 0459 0409 % CYRILLIC SMALL LETTER LJE
-\setcclcucx 045A 045A 040A % CYRILLIC SMALL LETTER NJE
-\setcclcucx 045B 045B 040B % CYRILLIC SMALL LETTER TSHE
-\setcclcucx 045C 045C 040C % CYRILLIC SMALL LETTER KJE
-\setcclcucx 045D 045D 040D % CYRILLIC SMALL LETTER I WITH GRAVE
-\setcclcucx 045E 045E 040E % CYRILLIC SMALL LETTER SHORT U
-\setcclcucx 045F 045F 040F % CYRILLIC SMALL LETTER DZHE
-\setcclcucx 0460 0461 0460 % CYRILLIC CAPITAL LETTER OMEGA
-\setcclcucx 0461 0461 0460 % CYRILLIC SMALL LETTER OMEGA
-\setcclcucx 0462 0463 0462 % CYRILLIC CAPITAL LETTER YAT
-\setcclcucx 0463 0463 0462 % CYRILLIC SMALL LETTER YAT
-\setcclcucx 0464 0465 0464 % CYRILLIC CAPITAL LETTER IOTIFIED E
-\setcclcucx 0465 0465 0464 % CYRILLIC SMALL LETTER IOTIFIED E
-\setcclcucx 0466 0467 0466 % CYRILLIC CAPITAL LETTER LITTLE YUS
-\setcclcucx 0467 0467 0466 % CYRILLIC SMALL LETTER LITTLE YUS
-\setcclcucx 0468 0469 0468 % CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
-\setcclcucx 0469 0469 0468 % CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
-\setcclcucx 046A 046B 046A % CYRILLIC CAPITAL LETTER BIG YUS
-\setcclcucx 046B 046B 046A % CYRILLIC SMALL LETTER BIG YUS
-\setcclcucx 046C 046D 046C % CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
-\setcclcucx 046D 046D 046C % CYRILLIC SMALL LETTER IOTIFIED BIG YUS
-\setcclcucx 046E 046F 046E % CYRILLIC CAPITAL LETTER KSI
-\setcclcucx 046F 046F 046E % CYRILLIC SMALL LETTER KSI
-\setcclcucx 0470 0471 0470 % CYRILLIC CAPITAL LETTER PSI
-\setcclcucx 0471 0471 0470 % CYRILLIC SMALL LETTER PSI
-\setcclcucx 0472 0473 0472 % CYRILLIC CAPITAL LETTER FITA
-\setcclcucx 0473 0473 0472 % CYRILLIC SMALL LETTER FITA
-\setcclcucx 0474 0475 0474 % CYRILLIC CAPITAL LETTER IZHITSA
-\setcclcucx 0475 0475 0474 % CYRILLIC SMALL LETTER IZHITSA
-\setcclcucx 0476 0477 0476 % CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
-\setcclcucx 0477 0477 0476 % CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
-\setcclcucx 0478 0479 0478 % CYRILLIC CAPITAL LETTER UK
-\setcclcucx 0479 0479 0478 % CYRILLIC SMALL LETTER UK
-\setcclcucx 047A 047B 047A % CYRILLIC CAPITAL LETTER ROUND OMEGA
-\setcclcucx 047B 047B 047A % CYRILLIC SMALL LETTER ROUND OMEGA
-\setcclcucx 047C 047D 047C % CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
-\setcclcucx 047D 047D 047C % CYRILLIC SMALL LETTER OMEGA WITH TITLO
-\setcclcucx 047E 047F 047E % CYRILLIC CAPITAL LETTER OT
-\setcclcucx 047F 047F 047E % CYRILLIC SMALL LETTER OT
-\setcclcucx 0480 0481 0480 % CYRILLIC CAPITAL LETTER KOPPA
-\setcclcucx 0481 0481 0480 % CYRILLIC SMALL LETTER KOPPA
-\setcclcucx 048A 048B 048A % CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
-\setcclcucx 048B 048B 048A % CYRILLIC SMALL LETTER SHORT I WITH TAIL
-\setcclcucx 048C 048D 048C % CYRILLIC CAPITAL LETTER SEMISOFT SIGN
-\setcclcucx 048D 048D 048C % CYRILLIC SMALL LETTER SEMISOFT SIGN
-\setcclcucx 048E 048F 048E % CYRILLIC CAPITAL LETTER ER WITH TICK
-\setcclcucx 048F 048F 048E % CYRILLIC SMALL LETTER ER WITH TICK
-\setcclcucx 0490 0491 0490 % CYRILLIC CAPITAL LETTER GHE WITH UPTURN
-\setcclcucx 0491 0491 0490 % CYRILLIC SMALL LETTER GHE WITH UPTURN
-\setcclcucx 0492 0493 0492 % CYRILLIC CAPITAL LETTER GHE WITH STROKE
-\setcclcucx 0493 0493 0492 % CYRILLIC SMALL LETTER GHE WITH STROKE
-\setcclcucx 0494 0495 0494 % CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
-\setcclcucx 0495 0495 0494 % CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
-\setcclcucx 0496 0497 0496 % CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
-\setcclcucx 0497 0497 0496 % CYRILLIC SMALL LETTER ZHE WITH DESCENDER
-\setcclcucx 0498 0499 0498 % CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
-\setcclcucx 0499 0499 0498 % CYRILLIC SMALL LETTER ZE WITH DESCENDER
-\setcclcucx 049A 049B 049A % CYRILLIC CAPITAL LETTER KA WITH DESCENDER
-\setcclcucx 049B 049B 049A % CYRILLIC SMALL LETTER KA WITH DESCENDER
-\setcclcucx 049C 049D 049C % CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
-\setcclcucx 049D 049D 049C % CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
-\setcclcucx 049E 049F 049E % CYRILLIC CAPITAL LETTER KA WITH STROKE
-\setcclcucx 049F 049F 049E % CYRILLIC SMALL LETTER KA WITH STROKE
-\setcclcucx 04A0 04A1 04A0 % CYRILLIC CAPITAL LETTER BASHKIR KA
-\setcclcucx 04A1 04A1 04A0 % CYRILLIC SMALL LETTER BASHKIR KA
-\setcclcucx 04A2 04A3 04A2 % CYRILLIC CAPITAL LETTER EN WITH DESCENDER
-\setcclcucx 04A3 04A3 04A2 % CYRILLIC SMALL LETTER EN WITH DESCENDER
-\setcclcucx 04A4 04A5 04A4 % CYRILLIC CAPITAL LIGATURE EN GHE
-\setcclcucx 04A5 04A5 04A4 % CYRILLIC SMALL LIGATURE EN GHE
-\setcclcucx 04A6 04A7 04A6 % CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
-\setcclcucx 04A7 04A7 04A6 % CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
-\setcclcucx 04A8 04A9 04A8 % CYRILLIC CAPITAL LETTER ABKHASIAN HA
-\setcclcucx 04A9 04A9 04A8 % CYRILLIC SMALL LETTER ABKHASIAN HA
-\setcclcucx 04AA 04AB 04AA % CYRILLIC CAPITAL LETTER ES WITH DESCENDER
-\setcclcucx 04AB 04AB 04AA % CYRILLIC SMALL LETTER ES WITH DESCENDER
-\setcclcucx 04AC 04AD 04AC % CYRILLIC CAPITAL LETTER TE WITH DESCENDER
-\setcclcucx 04AD 04AD 04AC % CYRILLIC SMALL LETTER TE WITH DESCENDER
-\setcclcucx 04AE 04AF 04AE % CYRILLIC CAPITAL LETTER STRAIGHT U
-\setcclcucx 04AF 04AF 04AE % CYRILLIC SMALL LETTER STRAIGHT U
-\setcclcucx 04B0 04B1 04B0 % CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
-\setcclcucx 04B1 04B1 04B0 % CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
-\setcclcucx 04B2 04B3 04B2 % CYRILLIC CAPITAL LETTER HA WITH DESCENDER
-\setcclcucx 04B3 04B3 04B2 % CYRILLIC SMALL LETTER HA WITH DESCENDER
-\setcclcucx 04B4 04B5 04B4 % CYRILLIC CAPITAL LIGATURE TE TSE
-\setcclcucx 04B5 04B5 04B4 % CYRILLIC SMALL LIGATURE TE TSE
-\setcclcucx 04B6 04B7 04B6 % CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
-\setcclcucx 04B7 04B7 04B6 % CYRILLIC SMALL LETTER CHE WITH DESCENDER
-\setcclcucx 04B8 04B9 04B8 % CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
-\setcclcucx 04B9 04B9 04B8 % CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
-\setcclcucx 04BA 04BB 04BA % CYRILLIC CAPITAL LETTER SHHA
-\setcclcucx 04BB 04BB 04BA % CYRILLIC SMALL LETTER SHHA
-\setcclcucx 04BC 04BD 04BC % CYRILLIC CAPITAL LETTER ABKHASIAN CHE
-\setcclcucx 04BD 04BD 04BC % CYRILLIC SMALL LETTER ABKHASIAN CHE
-\setcclcucx 04BE 04BF 04BE % CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
-\setcclcucx 04BF 04BF 04BE % CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
-\setcclcucx 04C0 04CF 04C0 % CYRILLIC LETTER PALOCHKA
-\setcclcucx 04C1 04C2 04C1 % CYRILLIC CAPITAL LETTER ZHE WITH BREVE
-\setcclcucx 04C2 04C2 04C1 % CYRILLIC SMALL LETTER ZHE WITH BREVE
-\setcclcucx 04C3 04C4 04C3 % CYRILLIC CAPITAL LETTER KA WITH HOOK
-\setcclcucx 04C4 04C4 04C3 % CYRILLIC SMALL LETTER KA WITH HOOK
-\setcclcucx 04C5 04C6 04C5 % CYRILLIC CAPITAL LETTER EL WITH TAIL
-\setcclcucx 04C6 04C6 04C5 % CYRILLIC SMALL LETTER EL WITH TAIL
-\setcclcucx 04C7 04C8 04C7 % CYRILLIC CAPITAL LETTER EN WITH HOOK
-\setcclcucx 04C8 04C8 04C7 % CYRILLIC SMALL LETTER EN WITH HOOK
-\setcclcucx 04C9 04CA 04C9 % CYRILLIC CAPITAL LETTER EN WITH TAIL
-\setcclcucx 04CA 04CA 04C9 % CYRILLIC SMALL LETTER EN WITH TAIL
-\setcclcucx 04CB 04CC 04CB % CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
-\setcclcucx 04CC 04CC 04CB % CYRILLIC SMALL LETTER KHAKASSIAN CHE
-\setcclcucx 04CD 04CE 04CD % CYRILLIC CAPITAL LETTER EM WITH TAIL
-\setcclcucx 04CE 04CE 04CD % CYRILLIC SMALL LETTER EM WITH TAIL
-\setcclcucx 04CF 04CF 04C0 % CYRILLIC SMALL LETTER PALOCHKA
-\setcclcucx 04D0 04D1 04D0 % CYRILLIC CAPITAL LETTER A WITH BREVE
-\setcclcucx 04D1 04D1 04D0 % CYRILLIC SMALL LETTER A WITH BREVE
-\setcclcucx 04D2 04D3 04D2 % CYRILLIC CAPITAL LETTER A WITH DIAERESIS
-\setcclcucx 04D3 04D3 04D2 % CYRILLIC SMALL LETTER A WITH DIAERESIS
-\setcclcucx 04D4 04D5 04D4 % CYRILLIC CAPITAL LIGATURE A IE
-\setcclcucx 04D5 04D5 04D4 % CYRILLIC SMALL LIGATURE A IE
-\setcclcucx 04D6 04D7 04D6 % CYRILLIC CAPITAL LETTER IE WITH BREVE
-\setcclcucx 04D7 04D7 04D6 % CYRILLIC SMALL LETTER IE WITH BREVE
-\setcclcucx 04D8 04D9 04D8 % CYRILLIC CAPITAL LETTER SCHWA
-\setcclcucx 04D9 04D9 04D8 % CYRILLIC SMALL LETTER SCHWA
-\setcclcucx 04DA 04DB 04DA % CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
-\setcclcucx 04DB 04DB 04DA % CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
-\setcclcucx 04DC 04DD 04DC % CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
-\setcclcucx 04DD 04DD 04DC % CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
-\setcclcucx 04DE 04DF 04DE % CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
-\setcclcucx 04DF 04DF 04DE % CYRILLIC SMALL LETTER ZE WITH DIAERESIS
-\setcclcucx 04E0 04E1 04E0 % CYRILLIC CAPITAL LETTER ABKHASIAN DZE
-\setcclcucx 04E1 04E1 04E0 % CYRILLIC SMALL LETTER ABKHASIAN DZE
-\setcclcucx 04E2 04E3 04E2 % CYRILLIC CAPITAL LETTER I WITH MACRON
-\setcclcucx 04E3 04E3 04E2 % CYRILLIC SMALL LETTER I WITH MACRON
-\setcclcucx 04E4 04E5 04E4 % CYRILLIC CAPITAL LETTER I WITH DIAERESIS
-\setcclcucx 04E5 04E5 04E4 % CYRILLIC SMALL LETTER I WITH DIAERESIS
-\setcclcucx 04E6 04E7 04E6 % CYRILLIC CAPITAL LETTER O WITH DIAERESIS
-\setcclcucx 04E7 04E7 04E6 % CYRILLIC SMALL LETTER O WITH DIAERESIS
-\setcclcucx 04E8 04E9 04E8 % CYRILLIC CAPITAL LETTER BARRED O
-\setcclcucx 04E9 04E9 04E8 % CYRILLIC SMALL LETTER BARRED O
-\setcclcucx 04EA 04EB 04EA % CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
-\setcclcucx 04EB 04EB 04EA % CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
-\setcclcucx 04EC 04ED 04EC % CYRILLIC CAPITAL LETTER E WITH DIAERESIS
-\setcclcucx 04ED 04ED 04EC % CYRILLIC SMALL LETTER E WITH DIAERESIS
-\setcclcucx 04EE 04EF 04EE % CYRILLIC CAPITAL LETTER U WITH MACRON
-\setcclcucx 04EF 04EF 04EE % CYRILLIC SMALL LETTER U WITH MACRON
-\setcclcucx 04F0 04F1 04F0 % CYRILLIC CAPITAL LETTER U WITH DIAERESIS
-\setcclcucx 04F1 04F1 04F0 % CYRILLIC SMALL LETTER U WITH DIAERESIS
-\setcclcucx 04F2 04F3 04F2 % CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
-\setcclcucx 04F3 04F3 04F2 % CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
-\setcclcucx 04F4 04F5 04F4 % CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
-\setcclcucx 04F5 04F5 04F4 % CYRILLIC SMALL LETTER CHE WITH DIAERESIS
-\setcclcucx 04F6 04F7 04F6 % CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
-\setcclcucx 04F7 04F7 04F6 % CYRILLIC SMALL LETTER GHE WITH DESCENDER
-\setcclcucx 04F8 04F9 04F8 % CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
-\setcclcucx 04F9 04F9 04F8 % CYRILLIC SMALL LETTER YERU WITH DIAERESIS
-\setcclcucx 04FA 04FB 04FA % CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
-\setcclcucx 04FB 04FB 04FA % CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
-\setcclcucx 04FC 04FD 04FC % CYRILLIC CAPITAL LETTER HA WITH HOOK
-\setcclcucx 04FD 04FD 04FC % CYRILLIC SMALL LETTER HA WITH HOOK
-\setcclcucx 04FE 04FF 04FE % CYRILLIC CAPITAL LETTER HA WITH STROKE
-\setcclcucx 04FF 04FF 04FE % CYRILLIC SMALL LETTER HA WITH STROKE
-\setcclcucx 0500 0501 0500 % CYRILLIC CAPITAL LETTER KOMI DE
-\setcclcucx 0501 0501 0500 % CYRILLIC SMALL LETTER KOMI DE
-\setcclcucx 0502 0503 0502 % CYRILLIC CAPITAL LETTER KOMI DJE
-\setcclcucx 0503 0503 0502 % CYRILLIC SMALL LETTER KOMI DJE
-\setcclcucx 0504 0505 0504 % CYRILLIC CAPITAL LETTER KOMI ZJE
-\setcclcucx 0505 0505 0504 % CYRILLIC SMALL LETTER KOMI ZJE
-\setcclcucx 0506 0507 0506 % CYRILLIC CAPITAL LETTER KOMI DZJE
-\setcclcucx 0507 0507 0506 % CYRILLIC SMALL LETTER KOMI DZJE
-\setcclcucx 0508 0509 0508 % CYRILLIC CAPITAL LETTER KOMI LJE
-\setcclcucx 0509 0509 0508 % CYRILLIC SMALL LETTER KOMI LJE
-\setcclcucx 050A 050B 050A % CYRILLIC CAPITAL LETTER KOMI NJE
-\setcclcucx 050B 050B 050A % CYRILLIC SMALL LETTER KOMI NJE
-\setcclcucx 050C 050D 050C % CYRILLIC CAPITAL LETTER KOMI SJE
-\setcclcucx 050D 050D 050C % CYRILLIC SMALL LETTER KOMI SJE
-\setcclcucx 050E 050F 050E % CYRILLIC CAPITAL LETTER KOMI TJE
-\setcclcucx 050F 050F 050E % CYRILLIC SMALL LETTER KOMI TJE
-\setcclcucx 0510 0511 0510 % CYRILLIC CAPITAL LETTER REVERSED ZE
-\setcclcucx 0511 0511 0510 % CYRILLIC SMALL LETTER REVERSED ZE
-\setcclcucx 0512 0513 0512 % CYRILLIC CAPITAL LETTER EL WITH HOOK
-\setcclcucx 0513 0513 0512 % CYRILLIC SMALL LETTER EL WITH HOOK
-\setcclcucx 0531 0561 0531 % ARMENIAN CAPITAL LETTER AYB
-\setcclcucx 0532 0562 0532 % ARMENIAN CAPITAL LETTER BEN
-\setcclcucx 0533 0563 0533 % ARMENIAN CAPITAL LETTER GIM
-\setcclcucx 0534 0564 0534 % ARMENIAN CAPITAL LETTER DA
-\setcclcucx 0535 0565 0535 % ARMENIAN CAPITAL LETTER ECH
-\setcclcucx 0536 0566 0536 % ARMENIAN CAPITAL LETTER ZA
-\setcclcucx 0537 0567 0537 % ARMENIAN CAPITAL LETTER EH
-\setcclcucx 0538 0568 0538 % ARMENIAN CAPITAL LETTER ET
-\setcclcucx 0539 0569 0539 % ARMENIAN CAPITAL LETTER TO
-\setcclcucx 053A 056A 053A % ARMENIAN CAPITAL LETTER ZHE
-\setcclcucx 053B 056B 053B % ARMENIAN CAPITAL LETTER INI
-\setcclcucx 053C 056C 053C % ARMENIAN CAPITAL LETTER LIWN
-\setcclcucx 053D 056D 053D % ARMENIAN CAPITAL LETTER XEH
-\setcclcucx 053E 056E 053E % ARMENIAN CAPITAL LETTER CA
-\setcclcucx 053F 056F 053F % ARMENIAN CAPITAL LETTER KEN
-\setcclcucx 0540 0570 0540 % ARMENIAN CAPITAL LETTER HO
-\setcclcucx 0541 0571 0541 % ARMENIAN CAPITAL LETTER JA
-\setcclcucx 0542 0572 0542 % ARMENIAN CAPITAL LETTER GHAD
-\setcclcucx 0543 0573 0543 % ARMENIAN CAPITAL LETTER CHEH
-\setcclcucx 0544 0574 0544 % ARMENIAN CAPITAL LETTER MEN
-\setcclcucx 0545 0575 0545 % ARMENIAN CAPITAL LETTER YI
-\setcclcucx 0546 0576 0546 % ARMENIAN CAPITAL LETTER NOW
-\setcclcucx 0547 0577 0547 % ARMENIAN CAPITAL LETTER SHA
-\setcclcucx 0548 0578 0548 % ARMENIAN CAPITAL LETTER VO
-\setcclcucx 0549 0579 0549 % ARMENIAN CAPITAL LETTER CHA
-\setcclcucx 054A 057A 054A % ARMENIAN CAPITAL LETTER PEH
-\setcclcucx 054B 057B 054B % ARMENIAN CAPITAL LETTER JHEH
-\setcclcucx 054C 057C 054C % ARMENIAN CAPITAL LETTER RA
-\setcclcucx 054D 057D 054D % ARMENIAN CAPITAL LETTER SEH
-\setcclcucx 054E 057E 054E % ARMENIAN CAPITAL LETTER VEW
-\setcclcucx 054F 057F 054F % ARMENIAN CAPITAL LETTER TIWN
-\setcclcucx 0550 0580 0550 % ARMENIAN CAPITAL LETTER REH
-\setcclcucx 0551 0581 0551 % ARMENIAN CAPITAL LETTER CO
-\setcclcucx 0552 0582 0552 % ARMENIAN CAPITAL LETTER YIWN
-\setcclcucx 0553 0583 0553 % ARMENIAN CAPITAL LETTER PIWR
-\setcclcucx 0554 0584 0554 % ARMENIAN CAPITAL LETTER KEH
-\setcclcucx 0555 0585 0555 % ARMENIAN CAPITAL LETTER OH
-\setcclcucx 0556 0586 0556 % ARMENIAN CAPITAL LETTER FEH
-\setcclcucx 0561 0561 0531 % ARMENIAN SMALL LETTER AYB
-\setcclcucx 0562 0562 0532 % ARMENIAN SMALL LETTER BEN
-\setcclcucx 0563 0563 0533 % ARMENIAN SMALL LETTER GIM
-\setcclcucx 0564 0564 0534 % ARMENIAN SMALL LETTER DA
-\setcclcucx 0565 0565 0535 % ARMENIAN SMALL LETTER ECH
-\setcclcucx 0566 0566 0536 % ARMENIAN SMALL LETTER ZA
-\setcclcucx 0567 0567 0537 % ARMENIAN SMALL LETTER EH
-\setcclcucx 0568 0568 0538 % ARMENIAN SMALL LETTER ET
-\setcclcucx 0569 0569 0539 % ARMENIAN SMALL LETTER TO
-\setcclcucx 056A 056A 053A % ARMENIAN SMALL LETTER ZHE
-\setcclcucx 056B 056B 053B % ARMENIAN SMALL LETTER INI
-\setcclcucx 056C 056C 053C % ARMENIAN SMALL LETTER LIWN
-\setcclcucx 056D 056D 053D % ARMENIAN SMALL LETTER XEH
-\setcclcucx 056E 056E 053E % ARMENIAN SMALL LETTER CA
-\setcclcucx 056F 056F 053F % ARMENIAN SMALL LETTER KEN
-\setcclcucx 0570 0570 0540 % ARMENIAN SMALL LETTER HO
-\setcclcucx 0571 0571 0541 % ARMENIAN SMALL LETTER JA
-\setcclcucx 0572 0572 0542 % ARMENIAN SMALL LETTER GHAD
-\setcclcucx 0573 0573 0543 % ARMENIAN SMALL LETTER CHEH
-\setcclcucx 0574 0574 0544 % ARMENIAN SMALL LETTER MEN
-\setcclcucx 0575 0575 0545 % ARMENIAN SMALL LETTER YI
-\setcclcucx 0576 0576 0546 % ARMENIAN SMALL LETTER NOW
-\setcclcucx 0577 0577 0547 % ARMENIAN SMALL LETTER SHA
-\setcclcucx 0578 0578 0548 % ARMENIAN SMALL LETTER VO
-\setcclcucx 0579 0579 0549 % ARMENIAN SMALL LETTER CHA
-\setcclcucx 057A 057A 054A % ARMENIAN SMALL LETTER PEH
-\setcclcucx 057B 057B 054B % ARMENIAN SMALL LETTER JHEH
-\setcclcucx 057C 057C 054C % ARMENIAN SMALL LETTER RA
-\setcclcucx 057D 057D 054D % ARMENIAN SMALL LETTER SEH
-\setcclcucx 057E 057E 054E % ARMENIAN SMALL LETTER VEW
-\setcclcucx 057F 057F 054F % ARMENIAN SMALL LETTER TIWN
-\setcclcucx 0580 0580 0550 % ARMENIAN SMALL LETTER REH
-\setcclcucx 0581 0581 0551 % ARMENIAN SMALL LETTER CO
-\setcclcucx 0582 0582 0552 % ARMENIAN SMALL LETTER YIWN
-\setcclcucx 0583 0583 0553 % ARMENIAN SMALL LETTER PIWR
-\setcclcucx 0584 0584 0554 % ARMENIAN SMALL LETTER KEH
-\setcclcucx 0585 0585 0555 % ARMENIAN SMALL LETTER OH
-\setcclcucx 0586 0586 0556 % ARMENIAN SMALL LETTER FEH
-\setcclcucx 0587 0587 0587 % ARMENIAN SMALL LIGATURE ECH YIWN
-\setcclcucx 10A0 2D00 10A0 % GEORGIAN CAPITAL LETTER AN
-\setcclcucx 10A1 2D01 10A1 % GEORGIAN CAPITAL LETTER BAN
-\setcclcucx 10A2 2D02 10A2 % GEORGIAN CAPITAL LETTER GAN
-\setcclcucx 10A3 2D03 10A3 % GEORGIAN CAPITAL LETTER DON
-\setcclcucx 10A4 2D04 10A4 % GEORGIAN CAPITAL LETTER EN
-\setcclcucx 10A5 2D05 10A5 % GEORGIAN CAPITAL LETTER VIN
-\setcclcucx 10A6 2D06 10A6 % GEORGIAN CAPITAL LETTER ZEN
-\setcclcucx 10A7 2D07 10A7 % GEORGIAN CAPITAL LETTER TAN
-\setcclcucx 10A8 2D08 10A8 % GEORGIAN CAPITAL LETTER IN
-\setcclcucx 10A9 2D09 10A9 % GEORGIAN CAPITAL LETTER KAN
-\setcclcucx 10AA 2D0A 10AA % GEORGIAN CAPITAL LETTER LAS
-\setcclcucx 10AB 2D0B 10AB % GEORGIAN CAPITAL LETTER MAN
-\setcclcucx 10AC 2D0C 10AC % GEORGIAN CAPITAL LETTER NAR
-\setcclcucx 10AD 2D0D 10AD % GEORGIAN CAPITAL LETTER ON
-\setcclcucx 10AE 2D0E 10AE % GEORGIAN CAPITAL LETTER PAR
-\setcclcucx 10AF 2D0F 10AF % GEORGIAN CAPITAL LETTER ZHAR
-\setcclcucx 10B0 2D10 10B0 % GEORGIAN CAPITAL LETTER RAE
-\setcclcucx 10B1 2D11 10B1 % GEORGIAN CAPITAL LETTER SAN
-\setcclcucx 10B2 2D12 10B2 % GEORGIAN CAPITAL LETTER TAR
-\setcclcucx 10B3 2D13 10B3 % GEORGIAN CAPITAL LETTER UN
-\setcclcucx 10B4 2D14 10B4 % GEORGIAN CAPITAL LETTER PHAR
-\setcclcucx 10B5 2D15 10B5 % GEORGIAN CAPITAL LETTER KHAR
-\setcclcucx 10B6 2D16 10B6 % GEORGIAN CAPITAL LETTER GHAN
-\setcclcucx 10B7 2D17 10B7 % GEORGIAN CAPITAL LETTER QAR
-\setcclcucx 10B8 2D18 10B8 % GEORGIAN CAPITAL LETTER SHIN
-\setcclcucx 10B9 2D19 10B9 % GEORGIAN CAPITAL LETTER CHIN
-\setcclcucx 10BA 2D1A 10BA % GEORGIAN CAPITAL LETTER CAN
-\setcclcucx 10BB 2D1B 10BB % GEORGIAN CAPITAL LETTER JIL
-\setcclcucx 10BC 2D1C 10BC % GEORGIAN CAPITAL LETTER CIL
-\setcclcucx 10BD 2D1D 10BD % GEORGIAN CAPITAL LETTER CHAR
-\setcclcucx 10BE 2D1E 10BE % GEORGIAN CAPITAL LETTER XAN
-\setcclcucx 10BF 2D1F 10BF % GEORGIAN CAPITAL LETTER JHAN
-\setcclcucx 10C0 2D20 10C0 % GEORGIAN CAPITAL LETTER HAE
-\setcclcucx 10C1 2D21 10C1 % GEORGIAN CAPITAL LETTER HE
-\setcclcucx 10C2 2D22 10C2 % GEORGIAN CAPITAL LETTER HIE
-\setcclcucx 10C3 2D23 10C3 % GEORGIAN CAPITAL LETTER WE
-\setcclcucx 10C4 2D24 10C4 % GEORGIAN CAPITAL LETTER HAR
-\setcclcucx 10C5 2D25 10C5 % GEORGIAN CAPITAL LETTER HOE
-\setcclcucx 1D00 1D00 1D00 % LATIN LETTER SMALL CAPITAL A
-\setcclcucx 1D01 1D01 1D01 % LATIN LETTER SMALL CAPITAL AE
-\setcclcucx 1D02 1D02 1D02 % LATIN SMALL LETTER TURNED AE
-\setcclcucx 1D03 1D03 1D03 % LATIN LETTER SMALL CAPITAL BARRED B
-\setcclcucx 1D04 1D04 1D04 % LATIN LETTER SMALL CAPITAL C
-\setcclcucx 1D05 1D05 1D05 % LATIN LETTER SMALL CAPITAL D
-\setcclcucx 1D06 1D06 1D06 % LATIN LETTER SMALL CAPITAL ETH
-\setcclcucx 1D07 1D07 1D07 % LATIN LETTER SMALL CAPITAL E
-\setcclcucx 1D08 1D08 1D08 % LATIN SMALL LETTER TURNED OPEN E
-\setcclcucx 1D09 1D09 1D09 % LATIN SMALL LETTER TURNED I
-\setcclcucx 1D0A 1D0A 1D0A % LATIN LETTER SMALL CAPITAL J
-\setcclcucx 1D0B 1D0B 1D0B % LATIN LETTER SMALL CAPITAL K
-\setcclcucx 1D0C 1D0C 1D0C % LATIN LETTER SMALL CAPITAL L WITH STROKE
-\setcclcucx 1D0D 1D0D 1D0D % LATIN LETTER SMALL CAPITAL M
-\setcclcucx 1D0E 1D0E 1D0E % LATIN LETTER SMALL CAPITAL REVERSED N
-\setcclcucx 1D0F 1D0F 1D0F % LATIN LETTER SMALL CAPITAL O
-\setcclcucx 1D10 1D10 1D10 % LATIN LETTER SMALL CAPITAL OPEN O
-\setcclcucx 1D11 1D11 1D11 % LATIN SMALL LETTER SIDEWAYS O
-\setcclcucx 1D12 1D12 1D12 % LATIN SMALL LETTER SIDEWAYS OPEN O
-\setcclcucx 1D13 1D13 1D13 % LATIN SMALL LETTER SIDEWAYS O WITH STROKE
-\setcclcucx 1D14 1D14 1D14 % LATIN SMALL LETTER TURNED OE
-\setcclcucx 1D15 1D15 1D15 % LATIN LETTER SMALL CAPITAL OU
-\setcclcucx 1D16 1D16 1D16 % LATIN SMALL LETTER TOP HALF O
-\setcclcucx 1D17 1D17 1D17 % LATIN SMALL LETTER BOTTOM HALF O
-\setcclcucx 1D18 1D18 1D18 % LATIN LETTER SMALL CAPITAL P
-\setcclcucx 1D19 1D19 1D19 % LATIN LETTER SMALL CAPITAL REVERSED R
-\setcclcucx 1D1A 1D1A 1D1A % LATIN LETTER SMALL CAPITAL TURNED R
-\setcclcucx 1D1B 1D1B 1D1B % LATIN LETTER SMALL CAPITAL T
-\setcclcucx 1D1C 1D1C 1D1C % LATIN LETTER SMALL CAPITAL U
-\setcclcucx 1D1D 1D1D 1D1D % LATIN SMALL LETTER SIDEWAYS U
-\setcclcucx 1D1E 1D1E 1D1E % LATIN SMALL LETTER SIDEWAYS DIAERESIZED U
-\setcclcucx 1D1F 1D1F 1D1F % LATIN SMALL LETTER SIDEWAYS TURNED M
-\setcclcucx 1D20 1D20 1D20 % LATIN LETTER SMALL CAPITAL V
-\setcclcucx 1D21 1D21 1D21 % LATIN LETTER SMALL CAPITAL W
-\setcclcucx 1D22 1D22 1D22 % LATIN LETTER SMALL CAPITAL Z
-\setcclcucx 1D23 1D23 1D23 % LATIN LETTER SMALL CAPITAL EZH
-\setcclcucx 1D24 1D24 1D24 % LATIN LETTER VOICED LARYNGEAL SPIRANT
-\setcclcucx 1D25 1D25 1D25 % LATIN LETTER AIN
-\setcclcucx 1D26 1D26 1D26 % GREEK LETTER SMALL CAPITAL GAMMA
-\setcclcucx 1D27 1D27 1D27 % GREEK LETTER SMALL CAPITAL LAMDA
-\setcclcucx 1D28 1D28 1D28 % GREEK LETTER SMALL CAPITAL PI
-\setcclcucx 1D29 1D29 1D29 % GREEK LETTER SMALL CAPITAL RHO
-\setcclcucx 1D2A 1D2A 1D2A % GREEK LETTER SMALL CAPITAL PSI
-\setcclcucx 1D2B 1D2B 1D2B % CYRILLIC LETTER SMALL CAPITAL EL
-\setcclcucx 1D62 1D62 1D62 % LATIN SUBSCRIPT SMALL LETTER I
-\setcclcucx 1D63 1D63 1D63 % LATIN SUBSCRIPT SMALL LETTER R
-\setcclcucx 1D64 1D64 1D64 % LATIN SUBSCRIPT SMALL LETTER U
-\setcclcucx 1D65 1D65 1D65 % LATIN SUBSCRIPT SMALL LETTER V
-\setcclcucx 1D66 1D66 1D66 % GREEK SUBSCRIPT SMALL LETTER BETA
-\setcclcucx 1D67 1D67 1D67 % GREEK SUBSCRIPT SMALL LETTER GAMMA
-\setcclcucx 1D68 1D68 1D68 % GREEK SUBSCRIPT SMALL LETTER RHO
-\setcclcucx 1D69 1D69 1D69 % GREEK SUBSCRIPT SMALL LETTER PHI
-\setcclcucx 1D6A 1D6A 1D6A % GREEK SUBSCRIPT SMALL LETTER CHI
-\setcclcucx 1D6B 1D6B 1D6B % LATIN SMALL LETTER UE
-\setcclcucx 1D6C 1D6C 1D6C % LATIN SMALL LETTER B WITH MIDDLE TILDE
-\setcclcucx 1D6D 1D6D 1D6D % LATIN SMALL LETTER D WITH MIDDLE TILDE
-\setcclcucx 1D6E 1D6E 1D6E % LATIN SMALL LETTER F WITH MIDDLE TILDE
-\setcclcucx 1D6F 1D6F 1D6F % LATIN SMALL LETTER M WITH MIDDLE TILDE
-\setcclcucx 1D70 1D70 1D70 % LATIN SMALL LETTER N WITH MIDDLE TILDE
-\setcclcucx 1D71 1D71 1D71 % LATIN SMALL LETTER P WITH MIDDLE TILDE
-\setcclcucx 1D72 1D72 1D72 % LATIN SMALL LETTER R WITH MIDDLE TILDE
-\setcclcucx 1D73 1D73 1D73 % LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE
-\setcclcucx 1D74 1D74 1D74 % LATIN SMALL LETTER S WITH MIDDLE TILDE
-\setcclcucx 1D75 1D75 1D75 % LATIN SMALL LETTER T WITH MIDDLE TILDE
-\setcclcucx 1D76 1D76 1D76 % LATIN SMALL LETTER Z WITH MIDDLE TILDE
-\setcclcucx 1D77 1D77 1D77 % LATIN SMALL LETTER TURNED G
-\setcclcucx 1D79 1D79 1D79 % LATIN SMALL LETTER INSULAR G
-\setcclcucx 1D7A 1D7A 1D7A % LATIN SMALL LETTER TH WITH STRIKETHROUGH
-\setcclcucx 1D7B 1D7B 1D7B % LATIN SMALL CAPITAL LETTER I WITH STROKE
-\setcclcucx 1D7C 1D7C 1D7C % LATIN SMALL LETTER IOTA WITH STROKE
-\setcclcucx 1D7D 1D7D 2C63 % LATIN SMALL LETTER P WITH STROKE
-\setcclcucx 1D7E 1D7E 1D7E % LATIN SMALL CAPITAL LETTER U WITH STROKE
-\setcclcucx 1D7F 1D7F 1D7F % LATIN SMALL LETTER UPSILON WITH STROKE
-\setcclcucx 1D80 1D80 1D80 % LATIN SMALL LETTER B WITH PALATAL HOOK
-\setcclcucx 1D81 1D81 1D81 % LATIN SMALL LETTER D WITH PALATAL HOOK
-\setcclcucx 1D82 1D82 1D82 % LATIN SMALL LETTER F WITH PALATAL HOOK
-\setcclcucx 1D83 1D83 1D83 % LATIN SMALL LETTER G WITH PALATAL HOOK
-\setcclcucx 1D84 1D84 1D84 % LATIN SMALL LETTER K WITH PALATAL HOOK
-\setcclcucx 1D85 1D85 1D85 % LATIN SMALL LETTER L WITH PALATAL HOOK
-\setcclcucx 1D86 1D86 1D86 % LATIN SMALL LETTER M WITH PALATAL HOOK
-\setcclcucx 1D87 1D87 1D87 % LATIN SMALL LETTER N WITH PALATAL HOOK
-\setcclcucx 1D88 1D88 1D88 % LATIN SMALL LETTER P WITH PALATAL HOOK
-\setcclcucx 1D89 1D89 1D89 % LATIN SMALL LETTER R WITH PALATAL HOOK
-\setcclcucx 1D8A 1D8A 1D8A % LATIN SMALL LETTER S WITH PALATAL HOOK
-\setcclcucx 1D8B 1D8B 1D8B % LATIN SMALL LETTER ESH WITH PALATAL HOOK
-\setcclcucx 1D8C 1D8C 1D8C % LATIN SMALL LETTER V WITH PALATAL HOOK
-\setcclcucx 1D8D 1D8D 1D8D % LATIN SMALL LETTER X WITH PALATAL HOOK
-\setcclcucx 1D8E 1D8E 1D8E % LATIN SMALL LETTER Z WITH PALATAL HOOK
-\setcclcucx 1D8F 1D8F 1D8F % LATIN SMALL LETTER A WITH RETROFLEX HOOK
-\setcclcucx 1D90 1D90 1D90 % LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK
-\setcclcucx 1D91 1D91 1D91 % LATIN SMALL LETTER D WITH HOOK AND TAIL
-\setcclcucx 1D92 1D92 1D92 % LATIN SMALL LETTER E WITH RETROFLEX HOOK
-\setcclcucx 1D93 1D93 1D93 % LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK
-\setcclcucx 1D94 1D94 1D94 % LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK
-\setcclcucx 1D95 1D95 1D95 % LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK
-\setcclcucx 1D96 1D96 1D96 % LATIN SMALL LETTER I WITH RETROFLEX HOOK
-\setcclcucx 1D97 1D97 1D97 % LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK
-\setcclcucx 1D98 1D98 1D98 % LATIN SMALL LETTER ESH WITH RETROFLEX HOOK
-\setcclcucx 1D99 1D99 1D99 % LATIN SMALL LETTER U WITH RETROFLEX HOOK
-\setcclcucx 1D9A 1D9A 1D9A % LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
-\setcclcucx 1E00 1E01 1E00 % LATIN CAPITAL LETTER A WITH RING BELOW
-\setcclcucx 1E01 1E01 1E00 % LATIN SMALL LETTER A WITH RING BELOW
-\setcclcucx 1E02 1E03 1E02 % LATIN CAPITAL LETTER B WITH DOT ABOVE
-\setcclcucx 1E03 1E03 1E02 % LATIN SMALL LETTER B WITH DOT ABOVE
-\setcclcucx 1E04 1E05 1E04 % LATIN CAPITAL LETTER B WITH DOT BELOW
-\setcclcucx 1E05 1E05 1E04 % LATIN SMALL LETTER B WITH DOT BELOW
-\setcclcucx 1E06 1E07 1E06 % LATIN CAPITAL LETTER B WITH LINE BELOW
-\setcclcucx 1E07 1E07 1E06 % LATIN SMALL LETTER B WITH LINE BELOW
-\setcclcucx 1E08 1E09 1E08 % LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
-\setcclcucx 1E09 1E09 1E08 % LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
-\setcclcucx 1E0A 1E0B 1E0A % LATIN CAPITAL LETTER D WITH DOT ABOVE
-\setcclcucx 1E0B 1E0B 1E0A % LATIN SMALL LETTER D WITH DOT ABOVE
-\setcclcucx 1E0C 1E0D 1E0C % LATIN CAPITAL LETTER D WITH DOT BELOW
-\setcclcucx 1E0D 1E0D 1E0C % LATIN SMALL LETTER D WITH DOT BELOW
-\setcclcucx 1E0E 1E0F 1E0E % LATIN CAPITAL LETTER D WITH LINE BELOW
-\setcclcucx 1E0F 1E0F 1E0E % LATIN SMALL LETTER D WITH LINE BELOW
-\setcclcucx 1E10 1E11 1E10 % LATIN CAPITAL LETTER D WITH CEDILLA
-\setcclcucx 1E11 1E11 1E10 % LATIN SMALL LETTER D WITH CEDILLA
-\setcclcucx 1E12 1E13 1E12 % LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
-\setcclcucx 1E13 1E13 1E12 % LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
-\setcclcucx 1E14 1E15 1E14 % LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
-\setcclcucx 1E15 1E15 1E14 % LATIN SMALL LETTER E WITH MACRON AND GRAVE
-\setcclcucx 1E16 1E17 1E16 % LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
-\setcclcucx 1E17 1E17 1E16 % LATIN SMALL LETTER E WITH MACRON AND ACUTE
-\setcclcucx 1E18 1E19 1E18 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
-\setcclcucx 1E19 1E19 1E18 % LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
-\setcclcucx 1E1A 1E1B 1E1A % LATIN CAPITAL LETTER E WITH TILDE BELOW
-\setcclcucx 1E1B 1E1B 1E1A % LATIN SMALL LETTER E WITH TILDE BELOW
-\setcclcucx 1E1C 1E1D 1E1C % LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
-\setcclcucx 1E1D 1E1D 1E1C % LATIN SMALL LETTER E WITH CEDILLA AND BREVE
-\setcclcucx 1E1E 1E1F 1E1E % LATIN CAPITAL LETTER F WITH DOT ABOVE
-\setcclcucx 1E1F 1E1F 1E1E % LATIN SMALL LETTER F WITH DOT ABOVE
-\setcclcucx 1E20 1E21 1E20 % LATIN CAPITAL LETTER G WITH MACRON
-\setcclcucx 1E21 1E21 1E20 % LATIN SMALL LETTER G WITH MACRON
-\setcclcucx 1E22 1E23 1E22 % LATIN CAPITAL LETTER H WITH DOT ABOVE
-\setcclcucx 1E23 1E23 1E22 % LATIN SMALL LETTER H WITH DOT ABOVE
-\setcclcucx 1E24 1E25 1E24 % LATIN CAPITAL LETTER H WITH DOT BELOW
-\setcclcucx 1E25 1E25 1E24 % LATIN SMALL LETTER H WITH DOT BELOW
-\setcclcucx 1E26 1E27 1E26 % LATIN CAPITAL LETTER H WITH DIAERESIS
-\setcclcucx 1E27 1E27 1E26 % LATIN SMALL LETTER H WITH DIAERESIS
-\setcclcucx 1E28 1E29 1E28 % LATIN CAPITAL LETTER H WITH CEDILLA
-\setcclcucx 1E29 1E29 1E28 % LATIN SMALL LETTER H WITH CEDILLA
-\setcclcucx 1E2A 1E2B 1E2A % LATIN CAPITAL LETTER H WITH BREVE BELOW
-\setcclcucx 1E2B 1E2B 1E2A % LATIN SMALL LETTER H WITH BREVE BELOW
-\setcclcucx 1E2C 1E2D 1E2C % LATIN CAPITAL LETTER I WITH TILDE BELOW
-\setcclcucx 1E2D 1E2D 1E2C % LATIN SMALL LETTER I WITH TILDE BELOW
-\setcclcucx 1E2E 1E2F 1E2E % LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
-\setcclcucx 1E2F 1E2F 1E2E % LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
-\setcclcucx 1E30 1E31 1E30 % LATIN CAPITAL LETTER K WITH ACUTE
-\setcclcucx 1E31 1E31 1E30 % LATIN SMALL LETTER K WITH ACUTE
-\setcclcucx 1E32 1E33 1E32 % LATIN CAPITAL LETTER K WITH DOT BELOW
-\setcclcucx 1E33 1E33 1E32 % LATIN SMALL LETTER K WITH DOT BELOW
-\setcclcucx 1E34 1E35 1E34 % LATIN CAPITAL LETTER K WITH LINE BELOW
-\setcclcucx 1E35 1E35 1E34 % LATIN SMALL LETTER K WITH LINE BELOW
-\setcclcucx 1E36 1E37 1E36 % LATIN CAPITAL LETTER L WITH DOT BELOW
-\setcclcucx 1E37 1E37 1E36 % LATIN SMALL LETTER L WITH DOT BELOW
-\setcclcucx 1E38 1E39 1E38 % LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
-\setcclcucx 1E39 1E39 1E38 % LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
-\setcclcucx 1E3A 1E3B 1E3A % LATIN CAPITAL LETTER L WITH LINE BELOW
-\setcclcucx 1E3B 1E3B 1E3A % LATIN SMALL LETTER L WITH LINE BELOW
-\setcclcucx 1E3C 1E3D 1E3C % LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
-\setcclcucx 1E3D 1E3D 1E3C % LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
-\setcclcucx 1E3E 1E3F 1E3E % LATIN CAPITAL LETTER M WITH ACUTE
-\setcclcucx 1E3F 1E3F 1E3E % LATIN SMALL LETTER M WITH ACUTE
-\setcclcucx 1E40 1E41 1E40 % LATIN CAPITAL LETTER M WITH DOT ABOVE
-\setcclcucx 1E41 1E41 1E40 % LATIN SMALL LETTER M WITH DOT ABOVE
-\setcclcucx 1E42 1E43 1E42 % LATIN CAPITAL LETTER M WITH DOT BELOW
-\setcclcucx 1E43 1E43 1E42 % LATIN SMALL LETTER M WITH DOT BELOW
-\setcclcucx 1E44 1E45 1E44 % LATIN CAPITAL LETTER N WITH DOT ABOVE
-\setcclcucx 1E45 1E45 1E44 % LATIN SMALL LETTER N WITH DOT ABOVE
-\setcclcucx 1E46 1E47 1E46 % LATIN CAPITAL LETTER N WITH DOT BELOW
-\setcclcucx 1E47 1E47 1E46 % LATIN SMALL LETTER N WITH DOT BELOW
-\setcclcucx 1E48 1E49 1E48 % LATIN CAPITAL LETTER N WITH LINE BELOW
-\setcclcucx 1E49 1E49 1E48 % LATIN SMALL LETTER N WITH LINE BELOW
-\setcclcucx 1E4A 1E4B 1E4A % LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
-\setcclcucx 1E4B 1E4B 1E4A % LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
-\setcclcucx 1E4C 1E4D 1E4C % LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
-\setcclcucx 1E4D 1E4D 1E4C % LATIN SMALL LETTER O WITH TILDE AND ACUTE
-\setcclcucx 1E4E 1E4F 1E4E % LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
-\setcclcucx 1E4F 1E4F 1E4E % LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
-\setcclcucx 1E50 1E51 1E50 % LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
-\setcclcucx 1E51 1E51 1E50 % LATIN SMALL LETTER O WITH MACRON AND GRAVE
-\setcclcucx 1E52 1E53 1E52 % LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
-\setcclcucx 1E53 1E53 1E52 % LATIN SMALL LETTER O WITH MACRON AND ACUTE
-\setcclcucx 1E54 1E55 1E54 % LATIN CAPITAL LETTER P WITH ACUTE
-\setcclcucx 1E55 1E55 1E54 % LATIN SMALL LETTER P WITH ACUTE
-\setcclcucx 1E56 1E57 1E56 % LATIN CAPITAL LETTER P WITH DOT ABOVE
-\setcclcucx 1E57 1E57 1E56 % LATIN SMALL LETTER P WITH DOT ABOVE
-\setcclcucx 1E58 1E59 1E58 % LATIN CAPITAL LETTER R WITH DOT ABOVE
-\setcclcucx 1E59 1E59 1E58 % LATIN SMALL LETTER R WITH DOT ABOVE
-\setcclcucx 1E5A 1E5B 1E5A % LATIN CAPITAL LETTER R WITH DOT BELOW
-\setcclcucx 1E5B 1E5B 1E5A % LATIN SMALL LETTER R WITH DOT BELOW
-\setcclcucx 1E5C 1E5D 1E5C % LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
-\setcclcucx 1E5D 1E5D 1E5C % LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
-\setcclcucx 1E5E 1E5F 1E5E % LATIN CAPITAL LETTER R WITH LINE BELOW
-\setcclcucx 1E5F 1E5F 1E5E % LATIN SMALL LETTER R WITH LINE BELOW
-\setcclcucx 1E60 1E61 1E60 % LATIN CAPITAL LETTER S WITH DOT ABOVE
-\setcclcucx 1E61 1E61 1E60 % LATIN SMALL LETTER S WITH DOT ABOVE
-\setcclcucx 1E62 1E63 1E62 % LATIN CAPITAL LETTER S WITH DOT BELOW
-\setcclcucx 1E63 1E63 1E62 % LATIN SMALL LETTER S WITH DOT BELOW
-\setcclcucx 1E64 1E65 1E64 % LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
-\setcclcucx 1E65 1E65 1E64 % LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
-\setcclcucx 1E66 1E67 1E66 % LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
-\setcclcucx 1E67 1E67 1E66 % LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
-\setcclcucx 1E68 1E69 1E68 % LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
-\setcclcucx 1E69 1E69 1E68 % LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
-\setcclcucx 1E6A 1E6B 1E6A % LATIN CAPITAL LETTER T WITH DOT ABOVE
-\setcclcucx 1E6B 1E6B 1E6A % LATIN SMALL LETTER T WITH DOT ABOVE
-\setcclcucx 1E6C 1E6D 1E6C % LATIN CAPITAL LETTER T WITH DOT BELOW
-\setcclcucx 1E6D 1E6D 1E6C % LATIN SMALL LETTER T WITH DOT BELOW
-\setcclcucx 1E6E 1E6F 1E6E % LATIN CAPITAL LETTER T WITH LINE BELOW
-\setcclcucx 1E6F 1E6F 1E6E % LATIN SMALL LETTER T WITH LINE BELOW
-\setcclcucx 1E70 1E71 1E70 % LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
-\setcclcucx 1E71 1E71 1E70 % LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
-\setcclcucx 1E72 1E73 1E72 % LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
-\setcclcucx 1E73 1E73 1E72 % LATIN SMALL LETTER U WITH DIAERESIS BELOW
-\setcclcucx 1E74 1E75 1E74 % LATIN CAPITAL LETTER U WITH TILDE BELOW
-\setcclcucx 1E75 1E75 1E74 % LATIN SMALL LETTER U WITH TILDE BELOW
-\setcclcucx 1E76 1E77 1E76 % LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
-\setcclcucx 1E77 1E77 1E76 % LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
-\setcclcucx 1E78 1E79 1E78 % LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
-\setcclcucx 1E79 1E79 1E78 % LATIN SMALL LETTER U WITH TILDE AND ACUTE
-\setcclcucx 1E7A 1E7B 1E7A % LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
-\setcclcucx 1E7B 1E7B 1E7A % LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
-\setcclcucx 1E7C 1E7D 1E7C % LATIN CAPITAL LETTER V WITH TILDE
-\setcclcucx 1E7D 1E7D 1E7C % LATIN SMALL LETTER V WITH TILDE
-\setcclcucx 1E7E 1E7F 1E7E % LATIN CAPITAL LETTER V WITH DOT BELOW
-\setcclcucx 1E7F 1E7F 1E7E % LATIN SMALL LETTER V WITH DOT BELOW
-\setcclcucx 1E80 1E81 1E80 % LATIN CAPITAL LETTER W WITH GRAVE
-\setcclcucx 1E81 1E81 1E80 % LATIN SMALL LETTER W WITH GRAVE
-\setcclcucx 1E82 1E83 1E82 % LATIN CAPITAL LETTER W WITH ACUTE
-\setcclcucx 1E83 1E83 1E82 % LATIN SMALL LETTER W WITH ACUTE
-\setcclcucx 1E84 1E85 1E84 % LATIN CAPITAL LETTER W WITH DIAERESIS
-\setcclcucx 1E85 1E85 1E84 % LATIN SMALL LETTER W WITH DIAERESIS
-\setcclcucx 1E86 1E87 1E86 % LATIN CAPITAL LETTER W WITH DOT ABOVE
-\setcclcucx 1E87 1E87 1E86 % LATIN SMALL LETTER W WITH DOT ABOVE
-\setcclcucx 1E88 1E89 1E88 % LATIN CAPITAL LETTER W WITH DOT BELOW
-\setcclcucx 1E89 1E89 1E88 % LATIN SMALL LETTER W WITH DOT BELOW
-\setcclcucx 1E8A 1E8B 1E8A % LATIN CAPITAL LETTER X WITH DOT ABOVE
-\setcclcucx 1E8B 1E8B 1E8A % LATIN SMALL LETTER X WITH DOT ABOVE
-\setcclcucx 1E8C 1E8D 1E8C % LATIN CAPITAL LETTER X WITH DIAERESIS
-\setcclcucx 1E8D 1E8D 1E8C % LATIN SMALL LETTER X WITH DIAERESIS
-\setcclcucx 1E8E 1E8F 1E8E % LATIN CAPITAL LETTER Y WITH DOT ABOVE
-\setcclcucx 1E8F 1E8F 1E8E % LATIN SMALL LETTER Y WITH DOT ABOVE
-\setcclcucx 1E90 1E91 1E90 % LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
-\setcclcucx 1E91 1E91 1E90 % LATIN SMALL LETTER Z WITH CIRCUMFLEX
-\setcclcucx 1E92 1E93 1E92 % LATIN CAPITAL LETTER Z WITH DOT BELOW
-\setcclcucx 1E93 1E93 1E92 % LATIN SMALL LETTER Z WITH DOT BELOW
-\setcclcucx 1E94 1E95 1E94 % LATIN CAPITAL LETTER Z WITH LINE BELOW
-\setcclcucx 1E95 1E95 1E94 % LATIN SMALL LETTER Z WITH LINE BELOW
-\setcclcucx 1E96 1E96 1E96 % LATIN SMALL LETTER H WITH LINE BELOW
-\setcclcucx 1E97 1E97 1E97 % LATIN SMALL LETTER T WITH DIAERESIS
-\setcclcucx 1E98 1E98 1E98 % LATIN SMALL LETTER W WITH RING ABOVE
-\setcclcucx 1E99 1E99 1E99 % LATIN SMALL LETTER Y WITH RING ABOVE
-\setcclcucx 1E9A 1E9A 1E9A % LATIN SMALL LETTER A WITH RIGHT HALF RING
-\setcclcucx 1E9B 1E9B 1E60 % LATIN SMALL LETTER LONG S WITH DOT ABOVE
-\setcclcucx 1EA0 1EA1 1EA0 % LATIN CAPITAL LETTER A WITH DOT BELOW
-\setcclcucx 1EA1 1EA1 1EA0 % LATIN SMALL LETTER A WITH DOT BELOW
-\setcclcucx 1EA2 1EA3 1EA2 % LATIN CAPITAL LETTER A WITH HOOK ABOVE
-\setcclcucx 1EA3 1EA3 1EA2 % LATIN SMALL LETTER A WITH HOOK ABOVE
-\setcclcucx 1EA4 1EA5 1EA4 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1EA5 1EA5 1EA4 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1EA6 1EA7 1EA6 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1EA7 1EA7 1EA6 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1EA8 1EA9 1EA8 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1EA9 1EA9 1EA8 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1EAA 1EAB 1EAA % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1EAB 1EAB 1EAA % LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1EAC 1EAD 1EAC % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1EAD 1EAD 1EAC % LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1EAE 1EAF 1EAE % LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
-\setcclcucx 1EAF 1EAF 1EAE % LATIN SMALL LETTER A WITH BREVE AND ACUTE
-\setcclcucx 1EB0 1EB1 1EB0 % LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
-\setcclcucx 1EB1 1EB1 1EB0 % LATIN SMALL LETTER A WITH BREVE AND GRAVE
-\setcclcucx 1EB2 1EB3 1EB2 % LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
-\setcclcucx 1EB3 1EB3 1EB2 % LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
-\setcclcucx 1EB4 1EB5 1EB4 % LATIN CAPITAL LETTER A WITH BREVE AND TILDE
-\setcclcucx 1EB5 1EB5 1EB4 % LATIN SMALL LETTER A WITH BREVE AND TILDE
-\setcclcucx 1EB6 1EB7 1EB6 % LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
-\setcclcucx 1EB7 1EB7 1EB6 % LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
-\setcclcucx 1EB8 1EB9 1EB8 % LATIN CAPITAL LETTER E WITH DOT BELOW
-\setcclcucx 1EB9 1EB9 1EB8 % LATIN SMALL LETTER E WITH DOT BELOW
-\setcclcucx 1EBA 1EBB 1EBA % LATIN CAPITAL LETTER E WITH HOOK ABOVE
-\setcclcucx 1EBB 1EBB 1EBA % LATIN SMALL LETTER E WITH HOOK ABOVE
-\setcclcucx 1EBC 1EBD 1EBC % LATIN CAPITAL LETTER E WITH TILDE
-\setcclcucx 1EBD 1EBD 1EBC % LATIN SMALL LETTER E WITH TILDE
-\setcclcucx 1EBE 1EBF 1EBE % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1EBF 1EBF 1EBE % LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1EC0 1EC1 1EC0 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1EC1 1EC1 1EC0 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1EC2 1EC3 1EC2 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1EC3 1EC3 1EC2 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1EC4 1EC5 1EC4 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1EC5 1EC5 1EC4 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1EC6 1EC7 1EC6 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1EC7 1EC7 1EC6 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1EC8 1EC9 1EC8 % LATIN CAPITAL LETTER I WITH HOOK ABOVE
-\setcclcucx 1EC9 1EC9 1EC8 % LATIN SMALL LETTER I WITH HOOK ABOVE
-\setcclcucx 1ECA 1ECB 1ECA % LATIN CAPITAL LETTER I WITH DOT BELOW
-\setcclcucx 1ECB 1ECB 1ECA % LATIN SMALL LETTER I WITH DOT BELOW
-\setcclcucx 1ECC 1ECD 1ECC % LATIN CAPITAL LETTER O WITH DOT BELOW
-\setcclcucx 1ECD 1ECD 1ECC % LATIN SMALL LETTER O WITH DOT BELOW
-\setcclcucx 1ECE 1ECF 1ECE % LATIN CAPITAL LETTER O WITH HOOK ABOVE
-\setcclcucx 1ECF 1ECF 1ECE % LATIN SMALL LETTER O WITH HOOK ABOVE
-\setcclcucx 1ED0 1ED1 1ED0 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1ED1 1ED1 1ED0 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
-\setcclcucx 1ED2 1ED3 1ED2 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1ED3 1ED3 1ED2 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
-\setcclcucx 1ED4 1ED5 1ED4 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1ED5 1ED5 1ED4 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
-\setcclcucx 1ED6 1ED7 1ED6 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1ED7 1ED7 1ED6 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
-\setcclcucx 1ED8 1ED9 1ED8 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1ED9 1ED9 1ED8 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
-\setcclcucx 1EDA 1EDB 1EDA % LATIN CAPITAL LETTER O WITH HORN AND ACUTE
-\setcclcucx 1EDB 1EDB 1EDA % LATIN SMALL LETTER O WITH HORN AND ACUTE
-\setcclcucx 1EDC 1EDD 1EDC % LATIN CAPITAL LETTER O WITH HORN AND GRAVE
-\setcclcucx 1EDD 1EDD 1EDC % LATIN SMALL LETTER O WITH HORN AND GRAVE
-\setcclcucx 1EDE 1EDF 1EDE % LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
-\setcclcucx 1EDF 1EDF 1EDE % LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
-\setcclcucx 1EE0 1EE1 1EE0 % LATIN CAPITAL LETTER O WITH HORN AND TILDE
-\setcclcucx 1EE1 1EE1 1EE0 % LATIN SMALL LETTER O WITH HORN AND TILDE
-\setcclcucx 1EE2 1EE3 1EE2 % LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
-\setcclcucx 1EE3 1EE3 1EE2 % LATIN SMALL LETTER O WITH HORN AND DOT BELOW
-\setcclcucx 1EE4 1EE5 1EE4 % LATIN CAPITAL LETTER U WITH DOT BELOW
-\setcclcucx 1EE5 1EE5 1EE4 % LATIN SMALL LETTER U WITH DOT BELOW
-\setcclcucx 1EE6 1EE7 1EE6 % LATIN CAPITAL LETTER U WITH HOOK ABOVE
-\setcclcucx 1EE7 1EE7 1EE6 % LATIN SMALL LETTER U WITH HOOK ABOVE
-\setcclcucx 1EE8 1EE9 1EE8 % LATIN CAPITAL LETTER U WITH HORN AND ACUTE
-\setcclcucx 1EE9 1EE9 1EE8 % LATIN SMALL LETTER U WITH HORN AND ACUTE
-\setcclcucx 1EEA 1EEB 1EEA % LATIN CAPITAL LETTER U WITH HORN AND GRAVE
-\setcclcucx 1EEB 1EEB 1EEA % LATIN SMALL LETTER U WITH HORN AND GRAVE
-\setcclcucx 1EEC 1EED 1EEC % LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
-\setcclcucx 1EED 1EED 1EEC % LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
-\setcclcucx 1EEE 1EEF 1EEE % LATIN CAPITAL LETTER U WITH HORN AND TILDE
-\setcclcucx 1EEF 1EEF 1EEE % LATIN SMALL LETTER U WITH HORN AND TILDE
-\setcclcucx 1EF0 1EF1 1EF0 % LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
-\setcclcucx 1EF1 1EF1 1EF0 % LATIN SMALL LETTER U WITH HORN AND DOT BELOW
-\setcclcucx 1EF2 1EF3 1EF2 % LATIN CAPITAL LETTER Y WITH GRAVE
-\setcclcucx 1EF3 1EF3 1EF2 % LATIN SMALL LETTER Y WITH GRAVE
-\setcclcucx 1EF4 1EF5 1EF4 % LATIN CAPITAL LETTER Y WITH DOT BELOW
-\setcclcucx 1EF5 1EF5 1EF4 % LATIN SMALL LETTER Y WITH DOT BELOW
-\setcclcucx 1EF6 1EF7 1EF6 % LATIN CAPITAL LETTER Y WITH HOOK ABOVE
-\setcclcucx 1EF7 1EF7 1EF6 % LATIN SMALL LETTER Y WITH HOOK ABOVE
-\setcclcucx 1EF8 1EF9 1EF8 % LATIN CAPITAL LETTER Y WITH TILDE
-\setcclcucx 1EF9 1EF9 1EF8 % LATIN SMALL LETTER Y WITH TILDE
-\setcclcucx 1F00 1F00 1F08 % GREEK SMALL LETTER ALPHA WITH PSILI
-\setcclcucx 1F01 1F01 1F09 % GREEK SMALL LETTER ALPHA WITH DASIA
-\setcclcucx 1F02 1F02 1F0A % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA
-\setcclcucx 1F03 1F03 1F0B % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA
-\setcclcucx 1F04 1F04 1F0C % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA
-\setcclcucx 1F05 1F05 1F0D % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA
-\setcclcucx 1F06 1F06 1F0E % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F07 1F07 1F0F % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F08 1F00 1F08 % GREEK CAPITAL LETTER ALPHA WITH PSILI
-\setcclcucx 1F09 1F01 1F09 % GREEK CAPITAL LETTER ALPHA WITH DASIA
-\setcclcucx 1F0A 1F02 1F0A % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
-\setcclcucx 1F0B 1F03 1F0B % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
-\setcclcucx 1F0C 1F04 1F0C % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
-\setcclcucx 1F0D 1F05 1F0D % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
-\setcclcucx 1F0E 1F06 1F0E % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F0F 1F07 1F0F % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F10 1F10 1F18 % GREEK SMALL LETTER EPSILON WITH PSILI
-\setcclcucx 1F11 1F11 1F19 % GREEK SMALL LETTER EPSILON WITH DASIA
-\setcclcucx 1F12 1F12 1F1A % GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA
-\setcclcucx 1F13 1F13 1F1B % GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA
-\setcclcucx 1F14 1F14 1F1C % GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA
-\setcclcucx 1F15 1F15 1F1D % GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
-\setcclcucx 1F18 1F10 1F18 % GREEK CAPITAL LETTER EPSILON WITH PSILI
-\setcclcucx 1F19 1F11 1F19 % GREEK CAPITAL LETTER EPSILON WITH DASIA
-\setcclcucx 1F1A 1F12 1F1A % GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
-\setcclcucx 1F1B 1F13 1F1B % GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
-\setcclcucx 1F1C 1F14 1F1C % GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
-\setcclcucx 1F1D 1F15 1F1D % GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
-\setcclcucx 1F20 1F20 1F28 % GREEK SMALL LETTER ETA WITH PSILI
-\setcclcucx 1F21 1F21 1F29 % GREEK SMALL LETTER ETA WITH DASIA
-\setcclcucx 1F22 1F22 1F2A % GREEK SMALL LETTER ETA WITH PSILI AND VARIA
-\setcclcucx 1F23 1F23 1F2B % GREEK SMALL LETTER ETA WITH DASIA AND VARIA
-\setcclcucx 1F24 1F24 1F2C % GREEK SMALL LETTER ETA WITH PSILI AND OXIA
-\setcclcucx 1F25 1F25 1F2D % GREEK SMALL LETTER ETA WITH DASIA AND OXIA
-\setcclcucx 1F26 1F26 1F2E % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F27 1F27 1F2F % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F28 1F20 1F28 % GREEK CAPITAL LETTER ETA WITH PSILI
-\setcclcucx 1F29 1F21 1F29 % GREEK CAPITAL LETTER ETA WITH DASIA
-\setcclcucx 1F2A 1F22 1F2A % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
-\setcclcucx 1F2B 1F23 1F2B % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
-\setcclcucx 1F2C 1F24 1F2C % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
-\setcclcucx 1F2D 1F25 1F2D % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
-\setcclcucx 1F2E 1F26 1F2E % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F2F 1F27 1F2F % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F30 1F30 1F38 % GREEK SMALL LETTER IOTA WITH PSILI
-\setcclcucx 1F31 1F31 1F39 % GREEK SMALL LETTER IOTA WITH DASIA
-\setcclcucx 1F32 1F32 1F3A % GREEK SMALL LETTER IOTA WITH PSILI AND VARIA
-\setcclcucx 1F33 1F33 1F3B % GREEK SMALL LETTER IOTA WITH DASIA AND VARIA
-\setcclcucx 1F34 1F34 1F3C % GREEK SMALL LETTER IOTA WITH PSILI AND OXIA
-\setcclcucx 1F35 1F35 1F3D % GREEK SMALL LETTER IOTA WITH DASIA AND OXIA
-\setcclcucx 1F36 1F36 1F3E % GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F37 1F37 1F3F % GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F38 1F30 1F38 % GREEK CAPITAL LETTER IOTA WITH PSILI
-\setcclcucx 1F39 1F31 1F39 % GREEK CAPITAL LETTER IOTA WITH DASIA
-\setcclcucx 1F3A 1F32 1F3A % GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
-\setcclcucx 1F3B 1F33 1F3B % GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
-\setcclcucx 1F3C 1F34 1F3C % GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
-\setcclcucx 1F3D 1F35 1F3D % GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
-\setcclcucx 1F3E 1F36 1F3E % GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F3F 1F37 1F3F % GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F40 1F40 1F48 % GREEK SMALL LETTER OMICRON WITH PSILI
-\setcclcucx 1F41 1F41 1F49 % GREEK SMALL LETTER OMICRON WITH DASIA
-\setcclcucx 1F42 1F42 1F4A % GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA
-\setcclcucx 1F43 1F43 1F4B % GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA
-\setcclcucx 1F44 1F44 1F4C % GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA
-\setcclcucx 1F45 1F45 1F4D % GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
-\setcclcucx 1F48 1F40 1F48 % GREEK CAPITAL LETTER OMICRON WITH PSILI
-\setcclcucx 1F49 1F41 1F49 % GREEK CAPITAL LETTER OMICRON WITH DASIA
-\setcclcucx 1F4A 1F42 1F4A % GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
-\setcclcucx 1F4B 1F43 1F4B % GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
-\setcclcucx 1F4C 1F44 1F4C % GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
-\setcclcucx 1F4D 1F45 1F4D % GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
-\setcclcucx 1F50 1F50 1F50 % GREEK SMALL LETTER UPSILON WITH PSILI
-\setcclcucx 1F51 1F51 1F59 % GREEK SMALL LETTER UPSILON WITH DASIA
-\setcclcucx 1F52 1F52 1F52 % GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
-\setcclcucx 1F53 1F53 1F5B % GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA
-\setcclcucx 1F54 1F54 1F54 % GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
-\setcclcucx 1F55 1F55 1F5D % GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA
-\setcclcucx 1F56 1F56 1F56 % GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
-\setcclcucx 1F57 1F57 1F5F % GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
-\setcclcucx 1F59 1F51 1F59 % GREEK CAPITAL LETTER UPSILON WITH DASIA
-\setcclcucx 1F5B 1F53 1F5B % GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
-\setcclcucx 1F5D 1F55 1F5D % GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
-\setcclcucx 1F5F 1F57 1F5F % GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
-\setcclcucx 1F60 1F60 1F68 % GREEK SMALL LETTER OMEGA WITH PSILI
-\setcclcucx 1F61 1F61 1F69 % GREEK SMALL LETTER OMEGA WITH DASIA
-\setcclcucx 1F62 1F62 1F6A % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA
-\setcclcucx 1F63 1F63 1F6B % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA
-\setcclcucx 1F64 1F64 1F6C % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA
-\setcclcucx 1F65 1F65 1F6D % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA
-\setcclcucx 1F66 1F66 1F6E % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F67 1F67 1F6F % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F68 1F60 1F68 % GREEK CAPITAL LETTER OMEGA WITH PSILI
-\setcclcucx 1F69 1F61 1F69 % GREEK CAPITAL LETTER OMEGA WITH DASIA
-\setcclcucx 1F6A 1F62 1F6A % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
-\setcclcucx 1F6B 1F63 1F6B % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
-\setcclcucx 1F6C 1F64 1F6C % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
-\setcclcucx 1F6D 1F65 1F6D % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
-\setcclcucx 1F6E 1F66 1F6E % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
-\setcclcucx 1F6F 1F67 1F6F % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
-\setcclcucx 1F70 1F70 1FBA % GREEK SMALL LETTER ALPHA WITH VARIA
-\setcclcucx 1F71 1F71 1FBB % GREEK SMALL LETTER ALPHA WITH OXIA
-\setcclcucx 1F72 1F72 1FC8 % GREEK SMALL LETTER EPSILON WITH VARIA
-\setcclcucx 1F73 1F73 1FC9 % GREEK SMALL LETTER EPSILON WITH OXIA
-\setcclcucx 1F74 1F74 1FCA % GREEK SMALL LETTER ETA WITH VARIA
-\setcclcucx 1F75 1F75 1FCB % GREEK SMALL LETTER ETA WITH OXIA
-\setcclcucx 1F76 1F76 1FDA % GREEK SMALL LETTER IOTA WITH VARIA
-\setcclcucx 1F77 1F77 1FDB % GREEK SMALL LETTER IOTA WITH OXIA
-\setcclcucx 1F78 1F78 1FF8 % GREEK SMALL LETTER OMICRON WITH VARIA
-\setcclcucx 1F79 1F79 1FF9 % GREEK SMALL LETTER OMICRON WITH OXIA
-\setcclcucx 1F7A 1F7A 1FEA % GREEK SMALL LETTER UPSILON WITH VARIA
-\setcclcucx 1F7B 1F7B 1FEB % GREEK SMALL LETTER UPSILON WITH OXIA
-\setcclcucx 1F7C 1F7C 1FFA % GREEK SMALL LETTER OMEGA WITH VARIA
-\setcclcucx 1F7D 1F7D 1FFB % GREEK SMALL LETTER OMEGA WITH OXIA
-\setcclcucx 1F80 1F80 1F88 % GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
-\setcclcucx 1F81 1F81 1F89 % GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
-\setcclcucx 1F82 1F82 1F8A % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1F83 1F83 1F8B % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1F84 1F84 1F8C % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1F85 1F85 1F8D % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1F86 1F86 1F8E % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1F87 1F87 1F8F % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1F88 1F80 1F88 % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
-\setcclcucx 1F89 1F81 1F89 % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
-\setcclcucx 1F8A 1F82 1F8A % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1F8B 1F83 1F8B % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1F8C 1F84 1F8C % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1F8D 1F85 1F8D % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1F8E 1F86 1F8E % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1F8F 1F87 1F8F % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1F90 1F90 1F98 % GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
-\setcclcucx 1F91 1F91 1F99 % GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
-\setcclcucx 1F92 1F92 1F9A % GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1F93 1F93 1F9B % GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1F94 1F94 1F9C % GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1F95 1F95 1F9D % GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1F96 1F96 1F9E % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1F97 1F97 1F9F % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1F98 1F90 1F98 % GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
-\setcclcucx 1F99 1F91 1F99 % GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
-\setcclcucx 1F9A 1F92 1F9A % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1F9B 1F93 1F9B % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1F9C 1F94 1F9C % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1F9D 1F95 1F9D % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1F9E 1F96 1F9E % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1F9F 1F97 1F9F % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1FA0 1FA0 1FA8 % GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
-\setcclcucx 1FA1 1FA1 1FA9 % GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
-\setcclcucx 1FA2 1FA2 1FAA % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1FA3 1FA3 1FAB % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
-\setcclcucx 1FA4 1FA4 1FAC % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1FA5 1FA5 1FAD % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
-\setcclcucx 1FA6 1FA6 1FAE % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1FA7 1FA7 1FAF % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1FA8 1FA0 1FA8 % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
-\setcclcucx 1FA9 1FA1 1FA9 % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
-\setcclcucx 1FAA 1FA2 1FAA % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1FAB 1FA3 1FAB % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
-\setcclcucx 1FAC 1FA4 1FAC % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1FAD 1FA5 1FAD % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
-\setcclcucx 1FAE 1FA6 1FAE % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1FAF 1FA7 1FAF % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
-\setcclcucx 1FB0 1FB0 1FB8 % GREEK SMALL LETTER ALPHA WITH VRACHY
-\setcclcucx 1FB1 1FB1 1FB9 % GREEK SMALL LETTER ALPHA WITH MACRON
-\setcclcucx 1FB2 1FB2 1FB2 % GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
-\setcclcucx 1FB3 1FB3 1FBC % GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
-\setcclcucx 1FB4 1FB4 1FB4 % GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
-\setcclcucx 1FB6 1FB6 1FB6 % GREEK SMALL LETTER ALPHA WITH PERISPOMENI
-\setcclcucx 1FB7 1FB7 1FB7 % GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1FB8 1FB0 1FB8 % GREEK CAPITAL LETTER ALPHA WITH VRACHY
-\setcclcucx 1FB9 1FB1 1FB9 % GREEK CAPITAL LETTER ALPHA WITH MACRON
-\setcclcucx 1FBA 1F70 1FBA % GREEK CAPITAL LETTER ALPHA WITH VARIA
-\setcclcucx 1FBB 1F71 1FBB % GREEK CAPITAL LETTER ALPHA WITH OXIA
-\setcclcucx 1FBC 1FB3 1FBC % GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
-\setcclcucx 1FBE 1FBE 0399 % GREEK PROSGEGRAMMENI
-\setcclcucx 1FC2 1FC2 1FC2 % GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
-\setcclcucx 1FC3 1FC3 1FCC % GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
-\setcclcucx 1FC4 1FC4 1FC4 % GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
-\setcclcucx 1FC6 1FC6 1FC6 % GREEK SMALL LETTER ETA WITH PERISPOMENI
-\setcclcucx 1FC7 1FC7 1FC7 % GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1FC8 1F72 1FC8 % GREEK CAPITAL LETTER EPSILON WITH VARIA
-\setcclcucx 1FC9 1F73 1FC9 % GREEK CAPITAL LETTER EPSILON WITH OXIA
-\setcclcucx 1FCA 1F74 1FCA % GREEK CAPITAL LETTER ETA WITH VARIA
-\setcclcucx 1FCB 1F75 1FCB % GREEK CAPITAL LETTER ETA WITH OXIA
-\setcclcucx 1FCC 1FC3 1FCC % GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
-\setcclcucx 1FD0 1FD0 1FD8 % GREEK SMALL LETTER IOTA WITH VRACHY
-\setcclcucx 1FD1 1FD1 1FD9 % GREEK SMALL LETTER IOTA WITH MACRON
-\setcclcucx 1FD2 1FD2 1FD2 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
-\setcclcucx 1FD3 1FD3 1FD3 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
-\setcclcucx 1FD6 1FD6 1FD6 % GREEK SMALL LETTER IOTA WITH PERISPOMENI
-\setcclcucx 1FD7 1FD7 1FD7 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
-\setcclcucx 1FD8 1FD0 1FD8 % GREEK CAPITAL LETTER IOTA WITH VRACHY
-\setcclcucx 1FD9 1FD1 1FD9 % GREEK CAPITAL LETTER IOTA WITH MACRON
-\setcclcucx 1FDA 1F76 1FDA % GREEK CAPITAL LETTER IOTA WITH VARIA
-\setcclcucx 1FDB 1F77 1FDB % GREEK CAPITAL LETTER IOTA WITH OXIA
-\setcclcucx 1FE0 1FE0 1FE8 % GREEK SMALL LETTER UPSILON WITH VRACHY
-\setcclcucx 1FE1 1FE1 1FE9 % GREEK SMALL LETTER UPSILON WITH MACRON
-\setcclcucx 1FE2 1FE2 1FE2 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
-\setcclcucx 1FE3 1FE3 1FE3 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
-\setcclcucx 1FE4 1FE4 1FE4 % GREEK SMALL LETTER RHO WITH PSILI
-\setcclcucx 1FE5 1FE5 1FEC % GREEK SMALL LETTER RHO WITH DASIA
-\setcclcucx 1FE6 1FE6 1FE6 % GREEK SMALL LETTER UPSILON WITH PERISPOMENI
-\setcclcucx 1FE7 1FE7 1FE7 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
-\setcclcucx 1FE8 1FE0 1FE8 % GREEK CAPITAL LETTER UPSILON WITH VRACHY
-\setcclcucx 1FE9 1FE1 1FE9 % GREEK CAPITAL LETTER UPSILON WITH MACRON
-\setcclcucx 1FEA 1F7A 1FEA % GREEK CAPITAL LETTER UPSILON WITH VARIA
-\setcclcucx 1FEB 1F7B 1FEB % GREEK CAPITAL LETTER UPSILON WITH OXIA
-\setcclcucx 1FEC 1FE5 1FEC % GREEK CAPITAL LETTER RHO WITH DASIA
-\setcclcucx 1FF2 1FF2 1FF2 % GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
-\setcclcucx 1FF3 1FF3 1FFC % GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
-\setcclcucx 1FF4 1FF4 1FF4 % GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
-\setcclcucx 1FF6 1FF6 1FF6 % GREEK SMALL LETTER OMEGA WITH PERISPOMENI
-\setcclcucx 1FF7 1FF7 1FF7 % GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
-\setcclcucx 1FF8 1F78 1FF8 % GREEK CAPITAL LETTER OMICRON WITH VARIA
-\setcclcucx 1FF9 1F79 1FF9 % GREEK CAPITAL LETTER OMICRON WITH OXIA
-\setcclcucx 1FFA 1F7C 1FFA % GREEK CAPITAL LETTER OMEGA WITH VARIA
-\setcclcucx 1FFB 1F7D 1FFB % GREEK CAPITAL LETTER OMEGA WITH OXIA
-\setcclcucx 1FFC 1FF3 1FFC % GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
-\setcclcucx 2071 2071 2071 % SUPERSCRIPT LATIN SMALL LETTER I
-\setcclcucx 207F 207F 207F % SUPERSCRIPT LATIN SMALL LETTER N
-\setcclcucx 2102 2102 2102 % DOUBLE-STRUCK CAPITAL C
-\setcclcucx 2107 2107 2107 % EULER CONSTANT
-\setcclcucx 210A 210A 210A % SCRIPT SMALL G
-\setcclcucx 210B 210B 210B % SCRIPT CAPITAL H
-\setcclcucx 210C 210C 210C % BLACK-LETTER CAPITAL H
-\setcclcucx 210D 210D 210D % DOUBLE-STRUCK CAPITAL H
-\setcclcucx 210E 210E 210E % PLANCK CONSTANT
-\setcclcucx 210F 210F 210F % PLANCK CONSTANT OVER TWO PI
-\setcclcucx 2110 2110 2110 % SCRIPT CAPITAL I
-\setcclcucx 2111 2111 2111 % BLACK-LETTER CAPITAL I
-\setcclcucx 2112 2112 2112 % SCRIPT CAPITAL L
-\setcclcucx 2113 2113 2113 % SCRIPT SMALL L
-\setcclcucx 2115 2115 2115 % DOUBLE-STRUCK CAPITAL N
-\setcclcucx 2119 2119 2119 % DOUBLE-STRUCK CAPITAL P
-\setcclcucx 211A 211A 211A % DOUBLE-STRUCK CAPITAL Q
-\setcclcucx 211B 211B 211B % SCRIPT CAPITAL R
-\setcclcucx 211C 211C 211C % BLACK-LETTER CAPITAL R
-\setcclcucx 211D 211D 211D % DOUBLE-STRUCK CAPITAL R
-\setcclcucx 2124 2124 2124 % DOUBLE-STRUCK CAPITAL Z
-\setcclcucx 2126 03C9 2126 % OHM SIGN
-\setcclcucx 2128 2128 2128 % BLACK-LETTER CAPITAL Z
-\setcclcucx 212A 006B 212A % KELVIN SIGN
-\setcclcucx 212B 00E5 212B % ANGSTROM SIGN
-\setcclcucx 212C 212C 212C % SCRIPT CAPITAL B
-\setcclcucx 212D 212D 212D % BLACK-LETTER CAPITAL C
-\setcclcucx 212F 212F 212F % SCRIPT SMALL E
-\setcclcucx 2130 2130 2130 % SCRIPT CAPITAL E
-\setcclcucx 2131 2131 2131 % SCRIPT CAPITAL F
-\setcclcucx 2132 214E 2132 % TURNED CAPITAL F
-\setcclcucx 2133 2133 2133 % SCRIPT CAPITAL M
-\setcclcucx 2134 2134 2134 % SCRIPT SMALL O
-\setcclcucx 2139 2139 2139 % INFORMATION SOURCE
-\setcclcucx 213C 213C 213C % DOUBLE-STRUCK SMALL PI
-\setcclcucx 213D 213D 213D % DOUBLE-STRUCK SMALL GAMMA
-\setcclcucx 213E 213E 213E % DOUBLE-STRUCK CAPITAL GAMMA
-\setcclcucx 213F 213F 213F % DOUBLE-STRUCK CAPITAL PI
-\setcclcucx 2145 2145 2145 % DOUBLE-STRUCK ITALIC CAPITAL D
-\setcclcucx 2146 2146 2146 % DOUBLE-STRUCK ITALIC SMALL D
-\setcclcucx 2147 2147 2147 % DOUBLE-STRUCK ITALIC SMALL E
-\setcclcucx 2148 2148 2148 % DOUBLE-STRUCK ITALIC SMALL I
-\setcclcucx 2149 2149 2149 % DOUBLE-STRUCK ITALIC SMALL J
-\setcclcucx 214E 214E 2132 % TURNED SMALL F
-\setcclcucx 2183 2184 2183 % ROMAN NUMERAL REVERSED ONE HUNDRED
-\setcclcucx 2184 2184 2183 % LATIN SMALL LETTER REVERSED C
-\setcclcucx 2C00 2C30 2C00 % GLAGOLITIC CAPITAL LETTER AZU
-\setcclcucx 2C01 2C31 2C01 % GLAGOLITIC CAPITAL LETTER BUKY
-\setcclcucx 2C02 2C32 2C02 % GLAGOLITIC CAPITAL LETTER VEDE
-\setcclcucx 2C03 2C33 2C03 % GLAGOLITIC CAPITAL LETTER GLAGOLI
-\setcclcucx 2C04 2C34 2C04 % GLAGOLITIC CAPITAL LETTER DOBRO
-\setcclcucx 2C05 2C35 2C05 % GLAGOLITIC CAPITAL LETTER YESTU
-\setcclcucx 2C06 2C36 2C06 % GLAGOLITIC CAPITAL LETTER ZHIVETE
-\setcclcucx 2C07 2C37 2C07 % GLAGOLITIC CAPITAL LETTER DZELO
-\setcclcucx 2C08 2C38 2C08 % GLAGOLITIC CAPITAL LETTER ZEMLJA
-\setcclcucx 2C09 2C39 2C09 % GLAGOLITIC CAPITAL LETTER IZHE
-\setcclcucx 2C0A 2C3A 2C0A % GLAGOLITIC CAPITAL LETTER INITIAL IZHE
-\setcclcucx 2C0B 2C3B 2C0B % GLAGOLITIC CAPITAL LETTER I
-\setcclcucx 2C0C 2C3C 2C0C % GLAGOLITIC CAPITAL LETTER DJERVI
-\setcclcucx 2C0D 2C3D 2C0D % GLAGOLITIC CAPITAL LETTER KAKO
-\setcclcucx 2C0E 2C3E 2C0E % GLAGOLITIC CAPITAL LETTER LJUDIJE
-\setcclcucx 2C0F 2C3F 2C0F % GLAGOLITIC CAPITAL LETTER MYSLITE
-\setcclcucx 2C10 2C40 2C10 % GLAGOLITIC CAPITAL LETTER NASHI
-\setcclcucx 2C11 2C41 2C11 % GLAGOLITIC CAPITAL LETTER ONU
-\setcclcucx 2C12 2C42 2C12 % GLAGOLITIC CAPITAL LETTER POKOJI
-\setcclcucx 2C13 2C43 2C13 % GLAGOLITIC CAPITAL LETTER RITSI
-\setcclcucx 2C14 2C44 2C14 % GLAGOLITIC CAPITAL LETTER SLOVO
-\setcclcucx 2C15 2C45 2C15 % GLAGOLITIC CAPITAL LETTER TVRIDO
-\setcclcucx 2C16 2C46 2C16 % GLAGOLITIC CAPITAL LETTER UKU
-\setcclcucx 2C17 2C47 2C17 % GLAGOLITIC CAPITAL LETTER FRITU
-\setcclcucx 2C18 2C48 2C18 % GLAGOLITIC CAPITAL LETTER HERU
-\setcclcucx 2C19 2C49 2C19 % GLAGOLITIC CAPITAL LETTER OTU
-\setcclcucx 2C1A 2C4A 2C1A % GLAGOLITIC CAPITAL LETTER PE
-\setcclcucx 2C1B 2C4B 2C1B % GLAGOLITIC CAPITAL LETTER SHTA
-\setcclcucx 2C1C 2C4C 2C1C % GLAGOLITIC CAPITAL LETTER TSI
-\setcclcucx 2C1D 2C4D 2C1D % GLAGOLITIC CAPITAL LETTER CHRIVI
-\setcclcucx 2C1E 2C4E 2C1E % GLAGOLITIC CAPITAL LETTER SHA
-\setcclcucx 2C1F 2C4F 2C1F % GLAGOLITIC CAPITAL LETTER YERU
-\setcclcucx 2C20 2C50 2C20 % GLAGOLITIC CAPITAL LETTER YERI
-\setcclcucx 2C21 2C51 2C21 % GLAGOLITIC CAPITAL LETTER YATI
-\setcclcucx 2C22 2C52 2C22 % GLAGOLITIC CAPITAL LETTER SPIDERY HA
-\setcclcucx 2C23 2C53 2C23 % GLAGOLITIC CAPITAL LETTER YU
-\setcclcucx 2C24 2C54 2C24 % GLAGOLITIC CAPITAL LETTER SMALL YUS
-\setcclcucx 2C25 2C55 2C25 % GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
-\setcclcucx 2C26 2C56 2C26 % GLAGOLITIC CAPITAL LETTER YO
-\setcclcucx 2C27 2C57 2C27 % GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
-\setcclcucx 2C28 2C58 2C28 % GLAGOLITIC CAPITAL LETTER BIG YUS
-\setcclcucx 2C29 2C59 2C29 % GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
-\setcclcucx 2C2A 2C5A 2C2A % GLAGOLITIC CAPITAL LETTER FITA
-\setcclcucx 2C2B 2C5B 2C2B % GLAGOLITIC CAPITAL LETTER IZHITSA
-\setcclcucx 2C2C 2C5C 2C2C % GLAGOLITIC CAPITAL LETTER SHTAPIC
-\setcclcucx 2C2D 2C5D 2C2D % GLAGOLITIC CAPITAL LETTER TROKUTASTI A
-\setcclcucx 2C2E 2C5E 2C2E % GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
-\setcclcucx 2C30 2C30 2C00 % GLAGOLITIC SMALL LETTER AZU
-\setcclcucx 2C31 2C31 2C01 % GLAGOLITIC SMALL LETTER BUKY
-\setcclcucx 2C32 2C32 2C02 % GLAGOLITIC SMALL LETTER VEDE
-\setcclcucx 2C33 2C33 2C03 % GLAGOLITIC SMALL LETTER GLAGOLI
-\setcclcucx 2C34 2C34 2C04 % GLAGOLITIC SMALL LETTER DOBRO
-\setcclcucx 2C35 2C35 2C05 % GLAGOLITIC SMALL LETTER YESTU
-\setcclcucx 2C36 2C36 2C06 % GLAGOLITIC SMALL LETTER ZHIVETE
-\setcclcucx 2C37 2C37 2C07 % GLAGOLITIC SMALL LETTER DZELO
-\setcclcucx 2C38 2C38 2C08 % GLAGOLITIC SMALL LETTER ZEMLJA
-\setcclcucx 2C39 2C39 2C09 % GLAGOLITIC SMALL LETTER IZHE
-\setcclcucx 2C3A 2C3A 2C0A % GLAGOLITIC SMALL LETTER INITIAL IZHE
-\setcclcucx 2C3B 2C3B 2C0B % GLAGOLITIC SMALL LETTER I
-\setcclcucx 2C3C 2C3C 2C0C % GLAGOLITIC SMALL LETTER DJERVI
-\setcclcucx 2C3D 2C3D 2C0D % GLAGOLITIC SMALL LETTER KAKO
-\setcclcucx 2C3E 2C3E 2C0E % GLAGOLITIC SMALL LETTER LJUDIJE
-\setcclcucx 2C3F 2C3F 2C0F % GLAGOLITIC SMALL LETTER MYSLITE
-\setcclcucx 2C40 2C40 2C10 % GLAGOLITIC SMALL LETTER NASHI
-\setcclcucx 2C41 2C41 2C11 % GLAGOLITIC SMALL LETTER ONU
-\setcclcucx 2C42 2C42 2C12 % GLAGOLITIC SMALL LETTER POKOJI
-\setcclcucx 2C43 2C43 2C13 % GLAGOLITIC SMALL LETTER RITSI
-\setcclcucx 2C44 2C44 2C14 % GLAGOLITIC SMALL LETTER SLOVO
-\setcclcucx 2C45 2C45 2C15 % GLAGOLITIC SMALL LETTER TVRIDO
-\setcclcucx 2C46 2C46 2C16 % GLAGOLITIC SMALL LETTER UKU
-\setcclcucx 2C47 2C47 2C17 % GLAGOLITIC SMALL LETTER FRITU
-\setcclcucx 2C48 2C48 2C18 % GLAGOLITIC SMALL LETTER HERU
-\setcclcucx 2C49 2C49 2C19 % GLAGOLITIC SMALL LETTER OTU
-\setcclcucx 2C4A 2C4A 2C1A % GLAGOLITIC SMALL LETTER PE
-\setcclcucx 2C4B 2C4B 2C1B % GLAGOLITIC SMALL LETTER SHTA
-\setcclcucx 2C4C 2C4C 2C1C % GLAGOLITIC SMALL LETTER TSI
-\setcclcucx 2C4D 2C4D 2C1D % GLAGOLITIC SMALL LETTER CHRIVI
-\setcclcucx 2C4E 2C4E 2C1E % GLAGOLITIC SMALL LETTER SHA
-\setcclcucx 2C4F 2C4F 2C1F % GLAGOLITIC SMALL LETTER YERU
-\setcclcucx 2C50 2C50 2C20 % GLAGOLITIC SMALL LETTER YERI
-\setcclcucx 2C51 2C51 2C21 % GLAGOLITIC SMALL LETTER YATI
-\setcclcucx 2C52 2C52 2C22 % GLAGOLITIC SMALL LETTER SPIDERY HA
-\setcclcucx 2C53 2C53 2C23 % GLAGOLITIC SMALL LETTER YU
-\setcclcucx 2C54 2C54 2C24 % GLAGOLITIC SMALL LETTER SMALL YUS
-\setcclcucx 2C55 2C55 2C25 % GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL
-\setcclcucx 2C56 2C56 2C26 % GLAGOLITIC SMALL LETTER YO
-\setcclcucx 2C57 2C57 2C27 % GLAGOLITIC SMALL LETTER IOTATED SMALL YUS
-\setcclcucx 2C58 2C58 2C28 % GLAGOLITIC SMALL LETTER BIG YUS
-\setcclcucx 2C59 2C59 2C29 % GLAGOLITIC SMALL LETTER IOTATED BIG YUS
-\setcclcucx 2C5A 2C5A 2C2A % GLAGOLITIC SMALL LETTER FITA
-\setcclcucx 2C5B 2C5B 2C2B % GLAGOLITIC SMALL LETTER IZHITSA
-\setcclcucx 2C5C 2C5C 2C2C % GLAGOLITIC SMALL LETTER SHTAPIC
-\setcclcucx 2C5D 2C5D 2C2D % GLAGOLITIC SMALL LETTER TROKUTASTI A
-\setcclcucx 2C5E 2C5E 2C2E % GLAGOLITIC SMALL LETTER LATINATE MYSLITE
-\setcclcucx 2C60 2C61 2C60 % LATIN CAPITAL LETTER L WITH DOUBLE BAR
-\setcclcucx 2C61 2C61 2C60 % LATIN SMALL LETTER L WITH DOUBLE BAR
-\setcclcucx 2C62 026B 2C62 % LATIN CAPITAL LETTER L WITH MIDDLE TILDE
-\setcclcucx 2C63 1D7D 2C63 % LATIN CAPITAL LETTER P WITH STROKE
-\setcclcucx 2C64 027D 2C64 % LATIN CAPITAL LETTER R WITH TAIL
-\setcclcucx 2C65 2C65 023A % LATIN SMALL LETTER A WITH STROKE
-\setcclcucx 2C66 2C66 023E % LATIN SMALL LETTER T WITH DIAGONAL STROKE
-\setcclcucx 2C67 2C68 2C67 % LATIN CAPITAL LETTER H WITH DESCENDER
-\setcclcucx 2C68 2C68 2C67 % LATIN SMALL LETTER H WITH DESCENDER
-\setcclcucx 2C69 2C6A 2C69 % LATIN CAPITAL LETTER K WITH DESCENDER
-\setcclcucx 2C6A 2C6A 2C69 % LATIN SMALL LETTER K WITH DESCENDER
-\setcclcucx 2C6B 2C6C 2C6B % LATIN CAPITAL LETTER Z WITH DESCENDER
-\setcclcucx 2C6C 2C6C 2C6B % LATIN SMALL LETTER Z WITH DESCENDER
-\setcclcucx 2C74 2C74 2C74 % LATIN SMALL LETTER V WITH CURL
-\setcclcucx 2C75 2C76 2C75 % LATIN CAPITAL LETTER HALF H
-\setcclcucx 2C76 2C76 2C75 % LATIN SMALL LETTER HALF H
-\setcclcucx 2C77 2C77 2C77 % LATIN SMALL LETTER TAILLESS PHI
-\setcclcucx 2C80 2C81 2C80 % COPTIC CAPITAL LETTER ALFA
-\setcclcucx 2C81 2C81 2C80 % COPTIC SMALL LETTER ALFA
-\setcclcucx 2C82 2C83 2C82 % COPTIC CAPITAL LETTER VIDA
-\setcclcucx 2C83 2C83 2C82 % COPTIC SMALL LETTER VIDA
-\setcclcucx 2C84 2C85 2C84 % COPTIC CAPITAL LETTER GAMMA
-\setcclcucx 2C85 2C85 2C84 % COPTIC SMALL LETTER GAMMA
-\setcclcucx 2C86 2C87 2C86 % COPTIC CAPITAL LETTER DALDA
-\setcclcucx 2C87 2C87 2C86 % COPTIC SMALL LETTER DALDA
-\setcclcucx 2C88 2C89 2C88 % COPTIC CAPITAL LETTER EIE
-\setcclcucx 2C89 2C89 2C88 % COPTIC SMALL LETTER EIE
-\setcclcucx 2C8A 2C8B 2C8A % COPTIC CAPITAL LETTER SOU
-\setcclcucx 2C8B 2C8B 2C8A % COPTIC SMALL LETTER SOU
-\setcclcucx 2C8C 2C8D 2C8C % COPTIC CAPITAL LETTER ZATA
-\setcclcucx 2C8D 2C8D 2C8C % COPTIC SMALL LETTER ZATA
-\setcclcucx 2C8E 2C8F 2C8E % COPTIC CAPITAL LETTER HATE
-\setcclcucx 2C8F 2C8F 2C8E % COPTIC SMALL LETTER HATE
-\setcclcucx 2C90 2C91 2C90 % COPTIC CAPITAL LETTER THETHE
-\setcclcucx 2C91 2C91 2C90 % COPTIC SMALL LETTER THETHE
-\setcclcucx 2C92 2C93 2C92 % COPTIC CAPITAL LETTER IAUDA
-\setcclcucx 2C93 2C93 2C92 % COPTIC SMALL LETTER IAUDA
-\setcclcucx 2C94 2C95 2C94 % COPTIC CAPITAL LETTER KAPA
-\setcclcucx 2C95 2C95 2C94 % COPTIC SMALL LETTER KAPA
-\setcclcucx 2C96 2C97 2C96 % COPTIC CAPITAL LETTER LAULA
-\setcclcucx 2C97 2C97 2C96 % COPTIC SMALL LETTER LAULA
-\setcclcucx 2C98 2C99 2C98 % COPTIC CAPITAL LETTER MI
-\setcclcucx 2C99 2C99 2C98 % COPTIC SMALL LETTER MI
-\setcclcucx 2C9A 2C9B 2C9A % COPTIC CAPITAL LETTER NI
-\setcclcucx 2C9B 2C9B 2C9A % COPTIC SMALL LETTER NI
-\setcclcucx 2C9C 2C9D 2C9C % COPTIC CAPITAL LETTER KSI
-\setcclcucx 2C9D 2C9D 2C9C % COPTIC SMALL LETTER KSI
-\setcclcucx 2C9E 2C9F 2C9E % COPTIC CAPITAL LETTER O
-\setcclcucx 2C9F 2C9F 2C9E % COPTIC SMALL LETTER O
-\setcclcucx 2CA0 2CA1 2CA0 % COPTIC CAPITAL LETTER PI
-\setcclcucx 2CA1 2CA1 2CA0 % COPTIC SMALL LETTER PI
-\setcclcucx 2CA2 2CA3 2CA2 % COPTIC CAPITAL LETTER RO
-\setcclcucx 2CA3 2CA3 2CA2 % COPTIC SMALL LETTER RO
-\setcclcucx 2CA4 2CA5 2CA4 % COPTIC CAPITAL LETTER SIMA
-\setcclcucx 2CA5 2CA5 2CA4 % COPTIC SMALL LETTER SIMA
-\setcclcucx 2CA6 2CA7 2CA6 % COPTIC CAPITAL LETTER TAU
-\setcclcucx 2CA7 2CA7 2CA6 % COPTIC SMALL LETTER TAU
-\setcclcucx 2CA8 2CA9 2CA8 % COPTIC CAPITAL LETTER UA
-\setcclcucx 2CA9 2CA9 2CA8 % COPTIC SMALL LETTER UA
-\setcclcucx 2CAA 2CAB 2CAA % COPTIC CAPITAL LETTER FI
-\setcclcucx 2CAB 2CAB 2CAA % COPTIC SMALL LETTER FI
-\setcclcucx 2CAC 2CAD 2CAC % COPTIC CAPITAL LETTER KHI
-\setcclcucx 2CAD 2CAD 2CAC % COPTIC SMALL LETTER KHI
-\setcclcucx 2CAE 2CAF 2CAE % COPTIC CAPITAL LETTER PSI
-\setcclcucx 2CAF 2CAF 2CAE % COPTIC SMALL LETTER PSI
-\setcclcucx 2CB0 2CB1 2CB0 % COPTIC CAPITAL LETTER OOU
-\setcclcucx 2CB1 2CB1 2CB0 % COPTIC SMALL LETTER OOU
-\setcclcucx 2CB2 2CB3 2CB2 % COPTIC CAPITAL LETTER DIALECT-P ALEF
-\setcclcucx 2CB3 2CB3 2CB2 % COPTIC SMALL LETTER DIALECT-P ALEF
-\setcclcucx 2CB4 2CB5 2CB4 % COPTIC CAPITAL LETTER OLD COPTIC AIN
-\setcclcucx 2CB5 2CB5 2CB4 % COPTIC SMALL LETTER OLD COPTIC AIN
-\setcclcucx 2CB6 2CB7 2CB6 % COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
-\setcclcucx 2CB7 2CB7 2CB6 % COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
-\setcclcucx 2CB8 2CB9 2CB8 % COPTIC CAPITAL LETTER DIALECT-P KAPA
-\setcclcucx 2CB9 2CB9 2CB8 % COPTIC SMALL LETTER DIALECT-P KAPA
-\setcclcucx 2CBA 2CBB 2CBA % COPTIC CAPITAL LETTER DIALECT-P NI
-\setcclcucx 2CBB 2CBB 2CBA % COPTIC SMALL LETTER DIALECT-P NI
-\setcclcucx 2CBC 2CBD 2CBC % COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
-\setcclcucx 2CBD 2CBD 2CBC % COPTIC SMALL LETTER CRYPTOGRAMMIC NI
-\setcclcucx 2CBE 2CBF 2CBE % COPTIC CAPITAL LETTER OLD COPTIC OOU
-\setcclcucx 2CBF 2CBF 2CBE % COPTIC SMALL LETTER OLD COPTIC OOU
-\setcclcucx 2CC0 2CC1 2CC0 % COPTIC CAPITAL LETTER SAMPI
-\setcclcucx 2CC1 2CC1 2CC0 % COPTIC SMALL LETTER SAMPI
-\setcclcucx 2CC2 2CC3 2CC2 % COPTIC CAPITAL LETTER CROSSED SHEI
-\setcclcucx 2CC3 2CC3 2CC2 % COPTIC SMALL LETTER CROSSED SHEI
-\setcclcucx 2CC4 2CC5 2CC4 % COPTIC CAPITAL LETTER OLD COPTIC SHEI
-\setcclcucx 2CC5 2CC5 2CC4 % COPTIC SMALL LETTER OLD COPTIC SHEI
-\setcclcucx 2CC6 2CC7 2CC6 % COPTIC CAPITAL LETTER OLD COPTIC ESH
-\setcclcucx 2CC7 2CC7 2CC6 % COPTIC SMALL LETTER OLD COPTIC ESH
-\setcclcucx 2CC8 2CC9 2CC8 % COPTIC CAPITAL LETTER AKHMIMIC KHEI
-\setcclcucx 2CC9 2CC9 2CC8 % COPTIC SMALL LETTER AKHMIMIC KHEI
-\setcclcucx 2CCA 2CCB 2CCA % COPTIC CAPITAL LETTER DIALECT-P HORI
-\setcclcucx 2CCB 2CCB 2CCA % COPTIC SMALL LETTER DIALECT-P HORI
-\setcclcucx 2CCC 2CCD 2CCC % COPTIC CAPITAL LETTER OLD COPTIC HORI
-\setcclcucx 2CCD 2CCD 2CCC % COPTIC SMALL LETTER OLD COPTIC HORI
-\setcclcucx 2CCE 2CCF 2CCE % COPTIC CAPITAL LETTER OLD COPTIC HA
-\setcclcucx 2CCF 2CCF 2CCE % COPTIC SMALL LETTER OLD COPTIC HA
-\setcclcucx 2CD0 2CD1 2CD0 % COPTIC CAPITAL LETTER L-SHAPED HA
-\setcclcucx 2CD1 2CD1 2CD0 % COPTIC SMALL LETTER L-SHAPED HA
-\setcclcucx 2CD2 2CD3 2CD2 % COPTIC CAPITAL LETTER OLD COPTIC HEI
-\setcclcucx 2CD3 2CD3 2CD2 % COPTIC SMALL LETTER OLD COPTIC HEI
-\setcclcucx 2CD4 2CD5 2CD4 % COPTIC CAPITAL LETTER OLD COPTIC HAT
-\setcclcucx 2CD5 2CD5 2CD4 % COPTIC SMALL LETTER OLD COPTIC HAT
-\setcclcucx 2CD6 2CD7 2CD6 % COPTIC CAPITAL LETTER OLD COPTIC GANGIA
-\setcclcucx 2CD7 2CD7 2CD6 % COPTIC SMALL LETTER OLD COPTIC GANGIA
-\setcclcucx 2CD8 2CD9 2CD8 % COPTIC CAPITAL LETTER OLD COPTIC DJA
-\setcclcucx 2CD9 2CD9 2CD8 % COPTIC SMALL LETTER OLD COPTIC DJA
-\setcclcucx 2CDA 2CDB 2CDA % COPTIC CAPITAL LETTER OLD COPTIC SHIMA
-\setcclcucx 2CDB 2CDB 2CDA % COPTIC SMALL LETTER OLD COPTIC SHIMA
-\setcclcucx 2CDC 2CDD 2CDC % COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
-\setcclcucx 2CDD 2CDD 2CDC % COPTIC SMALL LETTER OLD NUBIAN SHIMA
-\setcclcucx 2CDE 2CDF 2CDE % COPTIC CAPITAL LETTER OLD NUBIAN NGI
-\setcclcucx 2CDF 2CDF 2CDE % COPTIC SMALL LETTER OLD NUBIAN NGI
-\setcclcucx 2CE0 2CE1 2CE0 % COPTIC CAPITAL LETTER OLD NUBIAN NYI
-\setcclcucx 2CE1 2CE1 2CE0 % COPTIC SMALL LETTER OLD NUBIAN NYI
-\setcclcucx 2CE2 2CE3 2CE2 % COPTIC CAPITAL LETTER OLD NUBIAN WAU
-\setcclcucx 2CE3 2CE3 2CE2 % COPTIC SMALL LETTER OLD NUBIAN WAU
-\setcclcucx 2CE4 2CE4 2CE4 % COPTIC SYMBOL KAI
-\setcclcucx 2D00 2D00 10A0 % GEORGIAN SMALL LETTER AN
-\setcclcucx 2D01 2D01 10A1 % GEORGIAN SMALL LETTER BAN
-\setcclcucx 2D02 2D02 10A2 % GEORGIAN SMALL LETTER GAN
-\setcclcucx 2D03 2D03 10A3 % GEORGIAN SMALL LETTER DON
-\setcclcucx 2D04 2D04 10A4 % GEORGIAN SMALL LETTER EN
-\setcclcucx 2D05 2D05 10A5 % GEORGIAN SMALL LETTER VIN
-\setcclcucx 2D06 2D06 10A6 % GEORGIAN SMALL LETTER ZEN
-\setcclcucx 2D07 2D07 10A7 % GEORGIAN SMALL LETTER TAN
-\setcclcucx 2D08 2D08 10A8 % GEORGIAN SMALL LETTER IN
-\setcclcucx 2D09 2D09 10A9 % GEORGIAN SMALL LETTER KAN
-\setcclcucx 2D0A 2D0A 10AA % GEORGIAN SMALL LETTER LAS
-\setcclcucx 2D0B 2D0B 10AB % GEORGIAN SMALL LETTER MAN
-\setcclcucx 2D0C 2D0C 10AC % GEORGIAN SMALL LETTER NAR
-\setcclcucx 2D0D 2D0D 10AD % GEORGIAN SMALL LETTER ON
-\setcclcucx 2D0E 2D0E 10AE % GEORGIAN SMALL LETTER PAR
-\setcclcucx 2D0F 2D0F 10AF % GEORGIAN SMALL LETTER ZHAR
-\setcclcucx 2D10 2D10 10B0 % GEORGIAN SMALL LETTER RAE
-\setcclcucx 2D11 2D11 10B1 % GEORGIAN SMALL LETTER SAN
-\setcclcucx 2D12 2D12 10B2 % GEORGIAN SMALL LETTER TAR
-\setcclcucx 2D13 2D13 10B3 % GEORGIAN SMALL LETTER UN
-\setcclcucx 2D14 2D14 10B4 % GEORGIAN SMALL LETTER PHAR
-\setcclcucx 2D15 2D15 10B5 % GEORGIAN SMALL LETTER KHAR
-\setcclcucx 2D16 2D16 10B6 % GEORGIAN SMALL LETTER GHAN
-\setcclcucx 2D17 2D17 10B7 % GEORGIAN SMALL LETTER QAR
-\setcclcucx 2D18 2D18 10B8 % GEORGIAN SMALL LETTER SHIN
-\setcclcucx 2D19 2D19 10B9 % GEORGIAN SMALL LETTER CHIN
-\setcclcucx 2D1A 2D1A 10BA % GEORGIAN SMALL LETTER CAN
-\setcclcucx 2D1B 2D1B 10BB % GEORGIAN SMALL LETTER JIL
-\setcclcucx 2D1C 2D1C 10BC % GEORGIAN SMALL LETTER CIL
-\setcclcucx 2D1D 2D1D 10BD % GEORGIAN SMALL LETTER CHAR
-\setcclcucx 2D1E 2D1E 10BE % GEORGIAN SMALL LETTER XAN
-\setcclcucx 2D1F 2D1F 10BF % GEORGIAN SMALL LETTER JHAN
-\setcclcucx 2D20 2D20 10C0 % GEORGIAN SMALL LETTER HAE
-\setcclcucx 2D21 2D21 10C1 % GEORGIAN SMALL LETTER HE
-\setcclcucx 2D22 2D22 10C2 % GEORGIAN SMALL LETTER HIE
-\setcclcucx 2D23 2D23 10C3 % GEORGIAN SMALL LETTER WE
-\setcclcucx 2D24 2D24 10C4 % GEORGIAN SMALL LETTER HAR
-\setcclcucx 2D25 2D25 10C5 % GEORGIAN SMALL LETTER HOE
-\setcclcucx FB00 FB00 FB00 % LATIN SMALL LIGATURE FF
-\setcclcucx FB01 FB01 FB01 % LATIN SMALL LIGATURE FI
-\setcclcucx FB02 FB02 FB02 % LATIN SMALL LIGATURE FL
-\setcclcucx FB03 FB03 FB03 % LATIN SMALL LIGATURE FFI
-\setcclcucx FB04 FB04 FB04 % LATIN SMALL LIGATURE FFL
-\setcclcucx FB05 FB05 FB05 % LATIN SMALL LIGATURE LONG S T
-\setcclcucx FB06 FB06 FB06 % LATIN SMALL LIGATURE ST
-\setcclcucx FB13 FB13 FB13 % ARMENIAN SMALL LIGATURE MEN NOW
-\setcclcucx FB14 FB14 FB14 % ARMENIAN SMALL LIGATURE MEN ECH
-\setcclcucx FB15 FB15 FB15 % ARMENIAN SMALL LIGATURE MEN INI
-\setcclcucx FB16 FB16 FB16 % ARMENIAN SMALL LIGATURE VEW NOW
-\setcclcucx FB17 FB17 FB17 % ARMENIAN SMALL LIGATURE MEN XEH
-\setcclcucx FF21 FF41 FF21 % FULLWIDTH LATIN CAPITAL LETTER A
-\setcclcucx FF22 FF42 FF22 % FULLWIDTH LATIN CAPITAL LETTER B
-\setcclcucx FF23 FF43 FF23 % FULLWIDTH LATIN CAPITAL LETTER C
-\setcclcucx FF24 FF44 FF24 % FULLWIDTH LATIN CAPITAL LETTER D
-\setcclcucx FF25 FF45 FF25 % FULLWIDTH LATIN CAPITAL LETTER E
-\setcclcucx FF26 FF46 FF26 % FULLWIDTH LATIN CAPITAL LETTER F
-\setcclcucx FF27 FF47 FF27 % FULLWIDTH LATIN CAPITAL LETTER G
-\setcclcucx FF28 FF48 FF28 % FULLWIDTH LATIN CAPITAL LETTER H
-\setcclcucx FF29 FF49 FF29 % FULLWIDTH LATIN CAPITAL LETTER I
-\setcclcucx FF2A FF4A FF2A % FULLWIDTH LATIN CAPITAL LETTER J
-\setcclcucx FF2B FF4B FF2B % FULLWIDTH LATIN CAPITAL LETTER K
-\setcclcucx FF2C FF4C FF2C % FULLWIDTH LATIN CAPITAL LETTER L
-\setcclcucx FF2D FF4D FF2D % FULLWIDTH LATIN CAPITAL LETTER M
-\setcclcucx FF2E FF4E FF2E % FULLWIDTH LATIN CAPITAL LETTER N
-\setcclcucx FF2F FF4F FF2F % FULLWIDTH LATIN CAPITAL LETTER O
-\setcclcucx FF30 FF50 FF30 % FULLWIDTH LATIN CAPITAL LETTER P
-\setcclcucx FF31 FF51 FF31 % FULLWIDTH LATIN CAPITAL LETTER Q
-\setcclcucx FF32 FF52 FF32 % FULLWIDTH LATIN CAPITAL LETTER R
-\setcclcucx FF33 FF53 FF33 % FULLWIDTH LATIN CAPITAL LETTER S
-\setcclcucx FF34 FF54 FF34 % FULLWIDTH LATIN CAPITAL LETTER T
-\setcclcucx FF35 FF55 FF35 % FULLWIDTH LATIN CAPITAL LETTER U
-\setcclcucx FF36 FF56 FF36 % FULLWIDTH LATIN CAPITAL LETTER V
-\setcclcucx FF37 FF57 FF37 % FULLWIDTH LATIN CAPITAL LETTER W
-\setcclcucx FF38 FF58 FF38 % FULLWIDTH LATIN CAPITAL LETTER X
-\setcclcucx FF39 FF59 FF39 % FULLWIDTH LATIN CAPITAL LETTER Y
-\setcclcucx FF3A FF5A FF3A % FULLWIDTH LATIN CAPITAL LETTER Z
-\setcclcucx FF41 FF41 FF21 % FULLWIDTH LATIN SMALL LETTER A
-\setcclcucx FF42 FF42 FF22 % FULLWIDTH LATIN SMALL LETTER B
-\setcclcucx FF43 FF43 FF23 % FULLWIDTH LATIN SMALL LETTER C
-\setcclcucx FF44 FF44 FF24 % FULLWIDTH LATIN SMALL LETTER D
-\setcclcucx FF45 FF45 FF25 % FULLWIDTH LATIN SMALL LETTER E
-\setcclcucx FF46 FF46 FF26 % FULLWIDTH LATIN SMALL LETTER F
-\setcclcucx FF47 FF47 FF27 % FULLWIDTH LATIN SMALL LETTER G
-\setcclcucx FF48 FF48 FF28 % FULLWIDTH LATIN SMALL LETTER H
-\setcclcucx FF49 FF49 FF29 % FULLWIDTH LATIN SMALL LETTER I
-\setcclcucx FF4A FF4A FF2A % FULLWIDTH LATIN SMALL LETTER J
-\setcclcucx FF4B FF4B FF2B % FULLWIDTH LATIN SMALL LETTER K
-\setcclcucx FF4C FF4C FF2C % FULLWIDTH LATIN SMALL LETTER L
-\setcclcucx FF4D FF4D FF2D % FULLWIDTH LATIN SMALL LETTER M
-\setcclcucx FF4E FF4E FF2E % FULLWIDTH LATIN SMALL LETTER N
-\setcclcucx FF4F FF4F FF2F % FULLWIDTH LATIN SMALL LETTER O
-\setcclcucx FF50 FF50 FF30 % FULLWIDTH LATIN SMALL LETTER P
-\setcclcucx FF51 FF51 FF31 % FULLWIDTH LATIN SMALL LETTER Q
-\setcclcucx FF52 FF52 FF32 % FULLWIDTH LATIN SMALL LETTER R
-\setcclcucx FF53 FF53 FF33 % FULLWIDTH LATIN SMALL LETTER S
-\setcclcucx FF54 FF54 FF34 % FULLWIDTH LATIN SMALL LETTER T
-\setcclcucx FF55 FF55 FF35 % FULLWIDTH LATIN SMALL LETTER U
-\setcclcucx FF56 FF56 FF36 % FULLWIDTH LATIN SMALL LETTER V
-\setcclcucx FF57 FF57 FF37 % FULLWIDTH LATIN SMALL LETTER W
-\setcclcucx FF58 FF58 FF38 % FULLWIDTH LATIN SMALL LETTER X
-\setcclcucx FF59 FF59 FF39 % FULLWIDTH LATIN SMALL LETTER Y
-\setcclcucx FF5A FF5A FF3A % FULLWIDTH LATIN SMALL LETTER Z
-
-% named characters mapped onto utf (\\char is needed for accents)
-
-\def\textbackslash {\char"005C } % REVERSE SOLIDUS: \
-\def\textasciicircum {\char"005E } % CIRCUMFLEX ACCENT: ^
-\def\textunderscore {\char"005F } % LOW LINE: _
-\def\textgrave {\char"0060 } % GRAVE ACCENT: `
-\def\textbraceleft {\char"007B } % LEFT CURLY BRACKET: {
-\def\textbar {\char"007C } % VERTICAL LINE: |
-\def\textbraceright {\char"007D } % RIGHT CURLY BRACKET: }
-\def\textasciitilde {\char"007E } % TILDE: ~
-\def\nonbreakablespace {\char"00A0 } % NO-BREAK SPACE:  
-\def\exclamdown {\char"00A1 } % INVERTED EXCLAMATION MARK: ¡
-\def\textcent {\char"00A2 } % CENT SIGN: ¢
-\def\textsterling {\char"00A3 } % POUND SIGN: £
-\def\textcurrency {\char"00A4 } % CURRENCY SIGN: ¤
-\def\textyen {\char"00A5 } % YEN SIGN: ¥
-\def\textbrokenbar {\char"00A6 } % BROKEN BAR: ¦
-\def\sectionmark {\char"00A7 } % SECTION SIGN: §
-\def\textdiaeresis {\char"00A8 } % DIAERESIS: ¨
-\def\copyright {\char"00A9 } % COPYRIGHT SIGN: ©
-\def\ordfeminine {\char"00AA } % FEMININE ORDINAL INDICATOR: ª
-\def\leftguillemot {\char"00AB } % LEFT-POINTING DOUBLE ANGLE QUOTATION MARK: «
-\def\textlognot {\char"00AC } % NOT SIGN: ¬
-\def\softhyphen {\char"00AD } % SOFT HYPHEN: ­
-\def\registered {\char"00AE } % REGISTERED SIGN: ®
-\def\textmacron {\char"00AF } % MACRON: ¯
-\def\textdegree {\char"00B0 } % DEGREE SIGN: °
-\def\textpm {\char"00B1 } % PLUS-MINUS SIGN: ±
-\def\twosuperior {\char"00B2 } % SUPERSCRIPT TWO: ²
-\def\threesuperior {\char"00B3 } % SUPERSCRIPT THREE: ³
-\def\textacute {\char"00B4 } % ACUTE ACCENT: ´
-\def\textmu {\char"00B5 } % MICRO SIGN: µ
-\def\paragraphmark {\char"00B6 } % PILCROW SIGN: ¶
-\def\periodcentered {\char"00B7 } % MIDDLE DOT: ·
-\def\textcedilla {\char"00B8 } % CEDILLA: ¸
-\def\onesuperior {\char"00B9 } % SUPERSCRIPT ONE: ¹
-\def\ordmasculine {\char"00BA } % MASCULINE ORDINAL INDICATOR: º
-\def\rightguillemot {\char"00BB } % RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK: »
-\def\onequarter {\char"00BC } % VULGAR FRACTION ONE QUARTER: ¼
-\def\onehalf {\char"00BD } % VULGAR FRACTION ONE HALF: ½
-\def\threequarter {\char"00BE } % VULGAR FRACTION THREE QUARTERS: ¾
-\def\questiondown {\char"00BF } % INVERTED QUESTION MARK: ¿
-\def\Agrave {\char"00C0 } % LATIN CAPITAL LETTER A WITH GRAVE: À
-\def\Aacute {\char"00C1 } % LATIN CAPITAL LETTER A WITH ACUTE: Á
-\def\Acircumflex {\char"00C2 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX: Â
-\def\Atilde {\char"00C3 } % LATIN CAPITAL LETTER A WITH TILDE: Ã
-\def\Adiaeresis {\char"00C4 } % LATIN CAPITAL LETTER A WITH DIAERESIS: Ä
-\def\Aring {\char"00C5 } % LATIN CAPITAL LETTER A WITH RING ABOVE: Å
-\def\AEligature {\char"00C6 } % LATIN CAPITAL LETTER AE: Æ
-\def\Ccedilla {\char"00C7 } % LATIN CAPITAL LETTER C WITH CEDILLA: Ç
-\def\Egrave {\char"00C8 } % LATIN CAPITAL LETTER E WITH GRAVE: È
-\def\Eacute {\char"00C9 } % LATIN CAPITAL LETTER E WITH ACUTE: É
-\def\Ecircumflex {\char"00CA } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX: Ê
-\def\Ediaeresis {\char"00CB } % LATIN CAPITAL LETTER E WITH DIAERESIS: Ë
-\def\Igrave {\char"00CC } % LATIN CAPITAL LETTER I WITH GRAVE: Ì
-\def\Iacute {\char"00CD } % LATIN CAPITAL LETTER I WITH ACUTE: Í
-\def\Icircumflex {\char"00CE } % LATIN CAPITAL LETTER I WITH CIRCUMFLEX: Î
-\def\Idiaeresis {\char"00CF } % LATIN CAPITAL LETTER I WITH DIAERESIS: Ï
-\def\Eth {\char"00D0 } % LATIN CAPITAL LETTER ETH: Ð
-\def\Ntilde {\char"00D1 } % LATIN CAPITAL LETTER N WITH TILDE: Ñ
-\def\Ograve {\char"00D2 } % LATIN CAPITAL LETTER O WITH GRAVE: Ò
-\def\Oacute {\char"00D3 } % LATIN CAPITAL LETTER O WITH ACUTE: Ó
-\def\Ocircumflex {\char"00D4 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX: Ô
-\def\Otilde {\char"00D5 } % LATIN CAPITAL LETTER O WITH TILDE: Õ
-\def\Odiaeresis {\char"00D6 } % LATIN CAPITAL LETTER O WITH DIAERESIS: Ö
-\def\textmultiply {\char"00D7 } % MULTIPLICATION SIGN: ×
-\def\Ostroke {\char"00D8 } % LATIN CAPITAL LETTER O WITH STROKE: Ø
-\def\Ugrave {\char"00D9 } % LATIN CAPITAL LETTER U WITH GRAVE: Ù
-\def\Uacute {\char"00DA } % LATIN CAPITAL LETTER U WITH ACUTE: Ú
-\def\Ucircumflex {\char"00DB } % LATIN CAPITAL LETTER U WITH CIRCUMFLEX: Û
-\def\Udiaeresis {\char"00DC } % LATIN CAPITAL LETTER U WITH DIAERESIS: Ü
-\def\Yacute {\char"00DD } % LATIN CAPITAL LETTER Y WITH ACUTE: Ý
-\def\Thorn {\char"00DE } % LATIN CAPITAL LETTER THORN: Þ
-\def\ssharp {\char"00DF } % LATIN SMALL LETTER SHARP S: ß
-\def\agrave {\char"00E0 } % LATIN SMALL LETTER A WITH GRAVE: à
-\def\aacute {\char"00E1 } % LATIN SMALL LETTER A WITH ACUTE: á
-\def\acircumflex {\char"00E2 } % LATIN SMALL LETTER A WITH CIRCUMFLEX: â
-\def\atilde {\char"00E3 } % LATIN SMALL LETTER A WITH TILDE: ã
-\def\adiaeresis {\char"00E4 } % LATIN SMALL LETTER A WITH DIAERESIS: ä
-\def\aring {\char"00E5 } % LATIN SMALL LETTER A WITH RING ABOVE: å
-\def\aeligature {\char"00E6 } % LATIN SMALL LETTER AE: æ
-\def\ccedilla {\char"00E7 } % LATIN SMALL LETTER C WITH CEDILLA: ç
-\def\egrave {\char"00E8 } % LATIN SMALL LETTER E WITH GRAVE: è
-\def\eacute {\char"00E9 } % LATIN SMALL LETTER E WITH ACUTE: é
-\def\ecircumflex {\char"00EA } % LATIN SMALL LETTER E WITH CIRCUMFLEX: ê
-\def\ediaeresis {\char"00EB } % LATIN SMALL LETTER E WITH DIAERESIS: ë
-\def\igrave {\char"00EC } % LATIN SMALL LETTER I WITH GRAVE: ì
-\def\iacute {\char"00ED } % LATIN SMALL LETTER I WITH ACUTE: í
-\def\icircumflex {\char"00EE } % LATIN SMALL LETTER I WITH CIRCUMFLEX: î
-\def\idiaeresis {\char"00EF } % LATIN SMALL LETTER I WITH DIAERESIS: ï
-\def\eth {\char"00F0 } % LATIN SMALL LETTER ETH: ð
-\def\ntilde {\char"00F1 } % LATIN SMALL LETTER N WITH TILDE: ñ
-\def\ograve {\char"00F2 } % LATIN SMALL LETTER O WITH GRAVE: ò
-\def\oacute {\char"00F3 } % LATIN SMALL LETTER O WITH ACUTE: ó
-\def\ocircumflex {\char"00F4 } % LATIN SMALL LETTER O WITH CIRCUMFLEX: ô
-\def\otilde {\char"00F5 } % LATIN SMALL LETTER O WITH TILDE: õ
-\def\odiaeresis {\char"00F6 } % LATIN SMALL LETTER O WITH DIAERESIS: ö
-\def\textdiv {\char"00F7 } % DIVISION SIGN: ÷
-\def\ostroke {\char"00F8 } % LATIN SMALL LETTER O WITH STROKE: ø
-\def\ugrave {\char"00F9 } % LATIN SMALL LETTER U WITH GRAVE: ù
-\def\uacute {\char"00FA } % LATIN SMALL LETTER U WITH ACUTE: ú
-\def\ucircumflex {\char"00FB } % LATIN SMALL LETTER U WITH CIRCUMFLEX: û
-\def\udiaeresis {\char"00FC } % LATIN SMALL LETTER U WITH DIAERESIS: ü
-\def\yacute {\char"00FD } % LATIN SMALL LETTER Y WITH ACUTE: ý
-\def\thorn {\char"00FE } % LATIN SMALL LETTER THORN: þ
-\def\ydiaeresis {\char"00FF } % LATIN SMALL LETTER Y WITH DIAERESIS: ÿ
-\def\Amacron {\char"0100 } % LATIN CAPITAL LETTER A WITH MACRON: Ā
-\def\amacron {\char"0101 } % LATIN SMALL LETTER A WITH MACRON: ā
-\def\Abreve {\char"0102 } % LATIN CAPITAL LETTER A WITH BREVE: Ă
-\def\abreve {\char"0103 } % LATIN SMALL LETTER A WITH BREVE: ă
-\def\Aogonek {\char"0104 } % LATIN CAPITAL LETTER A WITH OGONEK: Ą
-\def\aogonek {\char"0105 } % LATIN SMALL LETTER A WITH OGONEK: ą
-\def\Cacute {\char"0106 } % LATIN CAPITAL LETTER C WITH ACUTE: Ć
-\def\cacute {\char"0107 } % LATIN SMALL LETTER C WITH ACUTE: ć
-\def\Ccircumflex {\char"0108 } % LATIN CAPITAL LETTER C WITH CIRCUMFLEX: Ĉ
-\def\ccircumflex {\char"0109 } % LATIN SMALL LETTER C WITH CIRCUMFLEX: ĉ
-\def\Cdotaccent {\char"010A } % LATIN CAPITAL LETTER C WITH DOT ABOVE: Ċ
-\def\cdotaccent {\char"010B } % LATIN SMALL LETTER C WITH DOT ABOVE: ċ
-\def\Ccaron {\char"010C } % LATIN CAPITAL LETTER C WITH CARON: Č
-\def\ccaron {\char"010D } % LATIN SMALL LETTER C WITH CARON: č
-\def\Dcaron {\char"010E } % LATIN CAPITAL LETTER D WITH CARON: Ď
-\def\dcaron {\char"010F } % LATIN SMALL LETTER D WITH CARON: ď
-\def\Dstroke {\char"0110 } % LATIN CAPITAL LETTER D WITH STROKE: Đ
-\def\dstroke {\char"0111 } % LATIN SMALL LETTER D WITH STROKE: đ
-\def\Emacron {\char"0112 } % LATIN CAPITAL LETTER E WITH MACRON: Ē
-\def\emacron {\char"0113 } % LATIN SMALL LETTER E WITH MACRON: ē
-\def\Ebreve {\char"0114 } % LATIN CAPITAL LETTER E WITH BREVE: Ĕ
-\def\ebreve {\char"0115 } % LATIN SMALL LETTER E WITH BREVE: ĕ
-\def\Edotaccent {\char"0116 } % LATIN CAPITAL LETTER E WITH DOT ABOVE: Ė
-\def\edotaccent {\char"0117 } % LATIN SMALL LETTER E WITH DOT ABOVE: ė
-\def\Eogonek {\char"0118 } % LATIN CAPITAL LETTER E WITH OGONEK: Ę
-\def\eogonek {\char"0119 } % LATIN SMALL LETTER E WITH OGONEK: ę
-\def\Ecaron {\char"011A } % LATIN CAPITAL LETTER E WITH CARON: Ě
-\def\ecaron {\char"011B } % LATIN SMALL LETTER E WITH CARON: ě
-\def\Gcircumflex {\char"011C } % LATIN CAPITAL LETTER G WITH CIRCUMFLEX: Ĝ
-\def\gcircumflex {\char"011D } % LATIN SMALL LETTER G WITH CIRCUMFLEX: ĝ
-\def\Gbreve {\char"011E } % LATIN CAPITAL LETTER G WITH BREVE: Ğ
-\def\gbreve {\char"011F } % LATIN SMALL LETTER G WITH BREVE: ğ
-\def\Gdotaccent {\char"0120 } % LATIN CAPITAL LETTER G WITH DOT ABOVE: Ġ
-\def\gdotaccent {\char"0121 } % LATIN SMALL LETTER G WITH DOT ABOVE: ġ
-\def\Gcommaaccent {\char"0122 } % LATIN CAPITAL LETTER G WITH CEDILLA: Ģ
-\def\gcommaaccent {\char"0123 } % LATIN SMALL LETTER G WITH CEDILLA: ģ
-\def\Hcircumflex {\char"0124 } % LATIN CAPITAL LETTER H WITH CIRCUMFLEX: Ĥ
-\def\hcircumflex {\char"0125 } % LATIN SMALL LETTER H WITH CIRCUMFLEX: ĥ
-\def\Hstroke {\char"0126 } % LATIN CAPITAL LETTER H WITH STROKE: Ħ
-\def\hstroke {\char"0127 } % LATIN SMALL LETTER H WITH STROKE: ħ
-\def\Itilde {\char"0128 } % LATIN CAPITAL LETTER I WITH TILDE: Ĩ
-\def\itilde {\char"0129 } % LATIN SMALL LETTER I WITH TILDE: ĩ
-\def\Imacron {\char"012A } % LATIN CAPITAL LETTER I WITH MACRON: Ī
-\def\imacron {\char"012B } % LATIN SMALL LETTER I WITH MACRON: ī
-\def\Ibreve {\char"012C } % LATIN CAPITAL LETTER I WITH BREVE: Ĭ
-\def\ibreve {\char"012D } % LATIN SMALL LETTER I WITH BREVE: ĭ
-\def\Iogonek {\char"012E } % LATIN CAPITAL LETTER I WITH OGONEK: Į
-\def\iogonek {\char"012F } % LATIN SMALL LETTER I WITH OGONEK: į
-\def\Idotaccent {\char"0130 } % LATIN CAPITAL LETTER I WITH DOT ABOVE: İ
-\def\dotlessi {\char"0131 } % LATIN SMALL LETTER DOTLESS I: ı
-\def\IJligature {\char"0132 } % LATIN CAPITAL LIGATURE IJ: IJ
-\def\ijligature {\char"0133 } % LATIN SMALL LIGATURE IJ: ij
-\def\Jcircumflex {\char"0134 } % LATIN CAPITAL LETTER J WITH CIRCUMFLEX: Ĵ
-\def\jcircumflex {\char"0135 } % LATIN SMALL LETTER J WITH CIRCUMFLEX: ĵ
-\def\Kcommaaccent {\char"0136 } % LATIN CAPITAL LETTER K WITH CEDILLA: Ķ
-\def\kcommaaccent {\char"0137 } % LATIN SMALL LETTER K WITH CEDILLA: ķ
-\def\kkra {\char"0138 } % LATIN SMALL LETTER KRA: ĸ
-\def\Lacute {\char"0139 } % LATIN CAPITAL LETTER L WITH ACUTE: Ĺ
-\def\lacute {\char"013A } % LATIN SMALL LETTER L WITH ACUTE: ĺ
-\def\Lcommaaccent {\char"013B } % LATIN CAPITAL LETTER L WITH CEDILLA: Ļ
-\def\lcommaaccent {\char"013C } % LATIN SMALL LETTER L WITH CEDILLA: ļ
-\def\Lcaron {\char"013D } % LATIN CAPITAL LETTER L WITH CARON: Ľ
-\def\lcaron {\char"013E } % LATIN SMALL LETTER L WITH CARON: ľ
-\def\Ldotmiddle {\char"013F } % LATIN CAPITAL LETTER L WITH MIDDLE DOT: Ŀ
-\def\ldotmiddle {\char"0140 } % LATIN SMALL LETTER L WITH MIDDLE DOT: ŀ
-\def\Lstroke {\char"0141 } % LATIN CAPITAL LETTER L WITH STROKE: Ł
-\def\lstroke {\char"0142 } % LATIN SMALL LETTER L WITH STROKE: ł
-\def\Nacute {\char"0143 } % LATIN CAPITAL LETTER N WITH ACUTE: Ń
-\def\nacute {\char"0144 } % LATIN SMALL LETTER N WITH ACUTE: ń
-\def\Ncommaaccent {\char"0145 } % LATIN CAPITAL LETTER N WITH CEDILLA: Ņ
-\def\ncommaaccent {\char"0146 } % LATIN SMALL LETTER N WITH CEDILLA: ņ
-\def\Ncaron {\char"0147 } % LATIN CAPITAL LETTER N WITH CARON: Ň
-\def\ncaron {\char"0148 } % LATIN SMALL LETTER N WITH CARON: ň
-\def\napostrophe {\char"0149 } % LATIN SMALL LETTER N PRECEDED BY APOSTROPHE: ʼn
-\def\Neng {\char"014A } % LATIN CAPITAL LETTER ENG: Ŋ
-\def\neng {\char"014B } % LATIN SMALL LETTER ENG: ŋ
-\def\Omacron {\char"014C } % LATIN CAPITAL LETTER O WITH MACRON: Ō
-\def\omacron {\char"014D } % LATIN SMALL LETTER O WITH MACRON: ō
-\def\Obreve {\char"014E } % LATIN CAPITAL LETTER O WITH BREVE: Ŏ
-\def\obreve {\char"014F } % LATIN SMALL LETTER O WITH BREVE: ŏ
-\def\Ohungarumlaut {\char"0150 } % LATIN CAPITAL LETTER O WITH DOUBLE ACUTE: Ő
-\def\ohungarumlaut {\char"0151 } % LATIN SMALL LETTER O WITH DOUBLE ACUTE: ő
-\def\OEligature {\char"0152 } % LATIN CAPITAL LIGATURE OE: Œ
-\def\oeligature {\char"0153 } % LATIN SMALL LIGATURE OE: œ
-\def\Racute {\char"0154 } % LATIN CAPITAL LETTER R WITH ACUTE: Ŕ
-\def\racute {\char"0155 } % LATIN SMALL LETTER R WITH ACUTE: ŕ
-\def\Rcommaaccent {\char"0156 } % LATIN CAPITAL LETTER R WITH CEDILLA: Ŗ
-\def\rcommaaccent {\char"0157 } % LATIN SMALL LETTER R WITH CEDILLA: ŗ
-\def\Rcaron {\char"0158 } % LATIN CAPITAL LETTER R WITH CARON: Ř
-\def\rcaron {\char"0159 } % LATIN SMALL LETTER R WITH CARON: ř
-\def\Sacute {\char"015A } % LATIN CAPITAL LETTER S WITH ACUTE: Ś
-\def\sacute {\char"015B } % LATIN SMALL LETTER S WITH ACUTE: ś
-\def\Scircumflex {\char"015C } % LATIN CAPITAL LETTER S WITH CIRCUMFLEX: Ŝ
-\def\scircumflex {\char"015D } % LATIN SMALL LETTER S WITH CIRCUMFLEX: ŝ
-\def\Scedilla {\char"015E } % LATIN CAPITAL LETTER S WITH CEDILLA: Ş
-\def\scedilla {\char"015F } % LATIN SMALL LETTER S WITH CEDILLA: ş
-\def\Scaron {\char"0160 } % LATIN CAPITAL LETTER S WITH CARON: Š
-\def\scaron {\char"0161 } % LATIN SMALL LETTER S WITH CARON: š
-\def\Tcedilla {\char"0162 } % LATIN CAPITAL LETTER T WITH CEDILLA: Ţ
-\def\tcedilla {\char"0163 } % LATIN SMALL LETTER T WITH CEDILLA: ţ
-\def\Tcaron {\char"0164 } % LATIN CAPITAL LETTER T WITH CARON: Ť
-\def\tcaron {\char"0165 } % LATIN SMALL LETTER T WITH CARON: ť
-\def\Tstroke {\char"0166 } % LATIN CAPITAL LETTER T WITH STROKE: Ŧ
-\def\tstroke {\char"0167 } % LATIN SMALL LETTER T WITH STROKE: ŧ
-\def\Utilde {\char"0168 } % LATIN CAPITAL LETTER U WITH TILDE: Ũ
-\def\utilde {\char"0169 } % LATIN SMALL LETTER U WITH TILDE: ũ
-\def\Umacron {\char"016A } % LATIN CAPITAL LETTER U WITH MACRON: Ū
-\def\umacron {\char"016B } % LATIN SMALL LETTER U WITH MACRON: ū
-\def\Ubreve {\char"016C } % LATIN CAPITAL LETTER U WITH BREVE: Ŭ
-\def\ubreve {\char"016D } % LATIN SMALL LETTER U WITH BREVE: ŭ
-\def\Uring {\char"016E } % LATIN CAPITAL LETTER U WITH RING ABOVE: Ů
-\def\uring {\char"016F } % LATIN SMALL LETTER U WITH RING ABOVE: ů
-\def\Uhungarumlaut {\char"0170 } % LATIN CAPITAL LETTER U WITH DOUBLE ACUTE: Ű
-\def\uhungarumlaut {\char"0171 } % LATIN SMALL LETTER U WITH DOUBLE ACUTE: ű
-\def\Uogonek {\char"0172 } % LATIN CAPITAL LETTER U WITH OGONEK: Ų
-\def\uogonek {\char"0173 } % LATIN SMALL LETTER U WITH OGONEK: ų
-\def\Wcircumflex {\char"0174 } % LATIN CAPITAL LETTER W WITH CIRCUMFLEX: Ŵ
-\def\wcircumflex {\char"0175 } % LATIN SMALL LETTER W WITH CIRCUMFLEX: ŵ
-\def\Ycircumflex {\char"0176 } % LATIN CAPITAL LETTER Y WITH CIRCUMFLEX: Ŷ
-\def\ycircumflex {\char"0177 } % LATIN SMALL LETTER Y WITH CIRCUMFLEX: ŷ
-\def\Ydiaeresis {\char"0178 } % LATIN CAPITAL LETTER Y WITH DIAERESIS: Ÿ
-\def\Zacute {\char"0179 } % LATIN CAPITAL LETTER Z WITH ACUTE: Ź
-\def\zacute {\char"017A } % LATIN SMALL LETTER Z WITH ACUTE: ź
-\def\Zdotaccent {\char"017B } % LATIN CAPITAL LETTER Z WITH DOT ABOVE: Ż
-\def\zdotaccent {\char"017C } % LATIN SMALL LETTER Z WITH DOT ABOVE: ż
-\def\Zcaron {\char"017D } % LATIN CAPITAL LETTER Z WITH CARON: Ž
-\def\zcaron {\char"017E } % LATIN SMALL LETTER Z WITH CARON: ž
-\def\slong {\char"017F } % LATIN SMALL LETTER LONG S: ſ
-\def\bstroke {\char"0180 } % LATIN SMALL LETTER B WITH STROKE: ƀ
-\def\Bhook {\char"0181 } % LATIN CAPITAL LETTER B WITH HOOK: Ɓ
-\def\Chook {\char"0187 } % LATIN CAPITAL LETTER C WITH HOOK: Ƈ
-\def\chook {\char"0188 } % LATIN SMALL LETTER C WITH HOOK: ƈ
-\def\Dafrican {\char"0189 } % LATIN CAPITAL LETTER AFRICAN D: Ɖ
-\def\Dhook {\char"018A } % LATIN CAPITAL LETTER D WITH HOOK: Ɗ
-\def\Schwa {\char"018F } % LATIN CAPITAL LETTER SCHWA: Ə
-\def\Fhook {\char"0191 } % LATIN CAPITAL LETTER F WITH HOOK: Ƒ
-\def\fhook {\char"0192 } % LATIN SMALL LETTER F WITH HOOK: ƒ
-\def\Ghook {\char"0193 } % LATIN CAPITAL LETTER G WITH HOOK: Ɠ
-\def\Istroke {\char"0197 } % LATIN CAPITAL LETTER I WITH STROKE: Ɨ
-\def\Khook {\char"0198 } % LATIN CAPITAL LETTER K WITH HOOK: Ƙ
-\def\khook {\char"0199 } % LATIN SMALL LETTER K WITH HOOK: ƙ
-\def\lbar {\char"019A } % LATIN SMALL LETTER L WITH BAR: ƚ
-\def\Ohorn {\char"01A0 } % LATIN CAPITAL LETTER O WITH HORN: Ơ
-\def\ohorn {\char"01A1 } % LATIN SMALL LETTER O WITH HORN: ơ
-\def\Phook {\char"01A4 } % LATIN CAPITAL LETTER P WITH HOOK: Ƥ
-\def\phook {\char"01A5 } % LATIN SMALL LETTER P WITH HOOK: ƥ
-\def\Thook {\char"01AC } % LATIN CAPITAL LETTER T WITH HOOK: Ƭ
-\def\thook {\char"01AD } % LATIN SMALL LETTER T WITH HOOK: ƭ
-\def\Uhorn {\char"01AF } % LATIN CAPITAL LETTER U WITH HORN: Ư
-\def\uhorn {\char"01B0 } % LATIN SMALL LETTER U WITH HORN: ư
-\def\Uhook {\char"01B2 } % LATIN CAPITAL LETTER V WITH HOOK: Ʋ
-\def\Yhook {\char"01B3 } % LATIN CAPITAL LETTER Y WITH HOOK: Ƴ
-\def\yhook {\char"01B4 } % LATIN SMALL LETTER Y WITH HOOK: ƴ
-\def\Zstroke {\char"01B5 } % LATIN CAPITAL LETTER Z WITH STROKE: Ƶ
-\def\zstroke {\char"01B6 } % LATIN SMALL LETTER Z WITH STROKE: ƶ
-\def\DZcaronligature {\char"01C4 } % LATIN CAPITAL LETTER DZ WITH CARON: DŽ
-\def\Dzcaronligature {\char"01C5 } % LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON: Dž
-\def\dzcaronligature {\char"01C6 } % LATIN SMALL LETTER DZ WITH CARON: dž
-\def\LJligature {\char"01C7 } % LATIN CAPITAL LETTER LJ: LJ
-\def\Ljligature {\char"01C8 } % LATIN CAPITAL LETTER L WITH SMALL LETTER J: Lj
-\def\ljligature {\char"01C9 } % LATIN SMALL LETTER LJ: lj
-\def\NJligature {\char"01CA } % LATIN CAPITAL LETTER NJ: NJ
-\def\Njligature {\char"01CB } % LATIN CAPITAL LETTER N WITH SMALL LETTER J: Nj
-\def\njligature {\char"01CC } % LATIN SMALL LETTER NJ: nj
-\def\Acaron {\char"01CD } % LATIN CAPITAL LETTER A WITH CARON: Ǎ
-\def\acaron {\char"01CE } % LATIN SMALL LETTER A WITH CARON: ǎ
-\def\Icaron {\char"01CF } % LATIN CAPITAL LETTER I WITH CARON: Ǐ
-\def\icaron {\char"01D0 } % LATIN SMALL LETTER I WITH CARON: ǐ
-\def\Ocaron {\char"01D1 } % LATIN CAPITAL LETTER O WITH CARON: Ǒ
-\def\ocaron {\char"01D2 } % LATIN SMALL LETTER O WITH CARON: ǒ
-\def\Ucaron {\char"01D3 } % LATIN CAPITAL LETTER U WITH CARON: Ǔ
-\def\ucaron {\char"01D4 } % LATIN SMALL LETTER U WITH CARON: ǔ
-\def\Udiaeresismacron {\char"01D5 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON: Ǖ
-\def\udiaeresismacron {\char"01D6 } % LATIN SMALL LETTER U WITH DIAERESIS AND MACRON: ǖ
-\def\Udiaeresisacute {\char"01D7 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE: Ǘ
-\def\udiaeresisacute {\char"01D8 } % LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE: ǘ
-\def\Udiaeresiscaron {\char"01D9 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON: Ǚ
-\def\udiaeresiscaron {\char"01DA } % LATIN SMALL LETTER U WITH DIAERESIS AND CARON: ǚ
-\def\Udiaeresisgrave {\char"01DB } % LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE: Ǜ
-\def\udiaeresisgrave {\char"01DC } % LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE: ǜ
-\def\Adiaeresismacron {\char"01DE } % LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON: Ǟ
-\def\adiaeresismacron {\char"01DF } % LATIN SMALL LETTER A WITH DIAERESIS AND MACRON: ǟ
-\def\Adotaccentmacron {\char"01E0 } % LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON: Ǡ
-\def\adotaccentmacron {\char"01E1 } % LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON: ǡ
-\def\AEmacron {\char"01E2 } % LATIN CAPITAL LETTER AE WITH MACRON: Ǣ
-\def\aemacron {\char"01E3 } % LATIN SMALL LETTER AE WITH MACRON: ǣ
-\def\Gstroke {\char"01E4 } % LATIN CAPITAL LETTER G WITH STROKE: Ǥ
-\def\gstroke {\char"01E5 } % LATIN SMALL LETTER G WITH STROKE: ǥ
-\def\Gcaron {\char"01E6 } % LATIN CAPITAL LETTER G WITH CARON: Ǧ
-\def\gcaron {\char"01E7 } % LATIN SMALL LETTER G WITH CARON: ǧ
-\def\Kcaron {\char"01E8 } % LATIN CAPITAL LETTER K WITH CARON: Ǩ
-\def\kcaron {\char"01E9 } % LATIN SMALL LETTER K WITH CARON: ǩ
-\def\Oogonek {\char"01EA } % LATIN CAPITAL LETTER O WITH OGONEK: Ǫ
-\def\oogonek {\char"01EB } % LATIN SMALL LETTER O WITH OGONEK: ǫ
-\def\Oogonekmacron {\char"01EC } % LATIN CAPITAL LETTER O WITH OGONEK AND MACRON: Ǭ
-\def\oogonekmacron {\char"01ED } % LATIN SMALL LETTER O WITH OGONEK AND MACRON: ǭ
-\def\jcaron {\char"01F0 } % LATIN SMALL LETTER J WITH CARON: ǰ
-\def\DZligature {\char"01F1 } % LATIN CAPITAL LETTER DZ: DZ
-\def\Dzligature {\char"01F2 } % LATIN CAPITAL LETTER D WITH SMALL LETTER Z: Dz
-\def\dzligature {\char"01F3 } % LATIN SMALL LETTER DZ: dz
-\def\Gacute {\char"01F4 } % LATIN CAPITAL LETTER G WITH ACUTE: Ǵ
-\def\gacute {\char"01F5 } % LATIN SMALL LETTER G WITH ACUTE: ǵ
-\def\Ngrave {\char"01F8 } % LATIN CAPITAL LETTER N WITH GRAVE: Ǹ
-\def\ngrave {\char"01F9 } % LATIN SMALL LETTER N WITH GRAVE: ǹ
-\def\Aringacute {\char"01FA } % LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE: Ǻ
-\def\aringacute {\char"01FB } % LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE: ǻ
-\def\AEacute {\char"01FC } % LATIN CAPITAL LETTER AE WITH ACUTE: Ǽ
-\def\aeacute {\char"01FD } % LATIN SMALL LETTER AE WITH ACUTE: ǽ
-\def\Ostrokeacute {\char"01FE } % LATIN CAPITAL LETTER O WITH STROKE AND ACUTE: Ǿ
-\def\ostrokeacute {\char"01FF } % LATIN SMALL LETTER O WITH STROKE AND ACUTE: ǿ
-\def\Adoublegrave {\char"0200 } % LATIN CAPITAL LETTER A WITH DOUBLE GRAVE: Ȁ
-\def\adoublegrave {\char"0201 } % LATIN SMALL LETTER A WITH DOUBLE GRAVE: ȁ
-\def\Ainvertedbreve {\char"0202 } % LATIN CAPITAL LETTER A WITH INVERTED BREVE: Ȃ
-\def\ainvertedbreve {\char"0203 } % LATIN SMALL LETTER A WITH INVERTED BREVE: ȃ
-\def\Edoublegrave {\char"0204 } % LATIN CAPITAL LETTER E WITH DOUBLE GRAVE: Ȅ
-\def\edoublegrave {\char"0205 } % LATIN SMALL LETTER E WITH DOUBLE GRAVE: ȅ
-\def\Einvertedbreve {\char"0206 } % LATIN CAPITAL LETTER E WITH INVERTED BREVE: Ȇ
-\def\einvertedbreve {\char"0207 } % LATIN SMALL LETTER E WITH INVERTED BREVE: ȇ
-\def\Idoublegrave {\char"0208 } % LATIN CAPITAL LETTER I WITH DOUBLE GRAVE: Ȉ
-\def\idoublegrave {\char"0209 } % LATIN SMALL LETTER I WITH DOUBLE GRAVE: ȉ
-\def\Iinvertedbreve {\char"020A } % LATIN CAPITAL LETTER I WITH INVERTED BREVE: Ȋ
-\def\iinvertedbreve {\char"020B } % LATIN SMALL LETTER I WITH INVERTED BREVE: ȋ
-\def\Odoublegrave {\char"020C } % LATIN CAPITAL LETTER O WITH DOUBLE GRAVE: Ȍ
-\def\odoublegrave {\char"020D } % LATIN SMALL LETTER O WITH DOUBLE GRAVE: ȍ
-\def\Oinvertedbreve {\char"020E } % LATIN CAPITAL LETTER O WITH INVERTED BREVE: Ȏ
-\def\oinvertedbreve {\char"020F } % LATIN SMALL LETTER O WITH INVERTED BREVE: ȏ
-\def\Rdoublegrave {\char"0210 } % LATIN CAPITAL LETTER R WITH DOUBLE GRAVE: Ȑ
-\def\rdoublegrave {\char"0211 } % LATIN SMALL LETTER R WITH DOUBLE GRAVE: ȑ
-\def\Rinvertedbreve {\char"0212 } % LATIN CAPITAL LETTER R WITH INVERTED BREVE: Ȓ
-\def\rinvertedbreve {\char"0213 } % LATIN SMALL LETTER R WITH INVERTED BREVE: ȓ
-\def\Udoublegrave {\char"0214 } % LATIN CAPITAL LETTER U WITH DOUBLE GRAVE: Ȕ
-\def\udoublegrave {\char"0215 } % LATIN SMALL LETTER U WITH DOUBLE GRAVE: ȕ
-\def\Uinvertedbreve {\char"0216 } % LATIN CAPITAL LETTER U WITH INVERTED BREVE: Ȗ
-\def\uinvertedbreve {\char"0217 } % LATIN SMALL LETTER U WITH INVERTED BREVE: ȗ
-\def\Scommaaccent {\char"0218 } % LATIN CAPITAL LETTER S WITH COMMA BELOW: Ș
-\def\scommaaccent {\char"0219 } % LATIN SMALL LETTER S WITH COMMA BELOW: ș
-\def\Tcommaaccent {\char"021A } % LATIN CAPITAL LETTER T WITH COMMA BELOW: Ț
-\def\tcommaaccent {\char"021B } % LATIN SMALL LETTER T WITH COMMA BELOW: ț
-\def\Hcaron {\char"021E } % LATIN CAPITAL LETTER H WITH CARON: Ȟ
-\def\hcaron {\char"021F } % LATIN SMALL LETTER H WITH CARON: ȟ
-\def\dcurl {\char"0221 } % LATIN SMALL LETTER D WITH CURL: ȡ
-\def\Zhook {\char"0224 } % LATIN CAPITAL LETTER Z WITH HOOK: Ȥ
-\def\zhook {\char"0225 } % LATIN SMALL LETTER Z WITH HOOK: ȥ
-\def\Adotaccent {\char"0226 } % LATIN CAPITAL LETTER A WITH DOT ABOVE: Ȧ
-\def\adotaccent {\char"0227 } % LATIN SMALL LETTER A WITH DOT ABOVE: ȧ
-\def\Ecedilla {\char"0228 } % LATIN CAPITAL LETTER E WITH CEDILLA: Ȩ
-\def\ecedilla {\char"0229 } % LATIN SMALL LETTER E WITH CEDILLA: ȩ
-\def\Odiaeresismacron {\char"022A } % LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON: Ȫ
-\def\odiaeresismacron {\char"022B } % LATIN SMALL LETTER O WITH DIAERESIS AND MACRON: ȫ
-\def\Otildemacron {\char"022C } % LATIN CAPITAL LETTER O WITH TILDE AND MACRON: Ȭ
-\def\otildemacron {\char"022D } % LATIN SMALL LETTER O WITH TILDE AND MACRON: ȭ
-\def\Odotaccent {\char"022E } % LATIN CAPITAL LETTER O WITH DOT ABOVE: Ȯ
-\def\odotaccent {\char"022F } % LATIN SMALL LETTER O WITH DOT ABOVE: ȯ
-\def\Odotaccentmacron {\char"0230 } % LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON: Ȱ
-\def\odotaccentmacron {\char"0231 } % LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON: ȱ
-\def\Ymacron {\char"0232 } % LATIN CAPITAL LETTER Y WITH MACRON: Ȳ
-\def\ymacron {\char"0233 } % LATIN SMALL LETTER Y WITH MACRON: ȳ
-\def\lcurl {\char"0234 } % LATIN SMALL LETTER L WITH CURL: ȴ
-\def\ncurl {\char"0235 } % LATIN SMALL LETTER N WITH CURL: ȵ
-\def\tcurl {\char"0236 } % LATIN SMALL LETTER T WITH CURL: ȶ
-\def\dotlessj {\char"0237 } % LATIN SMALL LETTER DOTLESS J: ȷ
-\def\Astroke {\char"023A } % LATIN CAPITAL LETTER A WITH STROKE: Ⱥ
-\def\Cstroke {\char"023B } % LATIN CAPITAL LETTER C WITH STROKE: Ȼ
-\def\cstroke {\char"023C } % LATIN SMALL LETTER C WITH STROKE: ȼ
-\def\Lbar {\char"023D } % LATIN CAPITAL LETTER L WITH BAR: Ƚ
-\def\bhook {\char"0253 } % LATIN SMALL LETTER B WITH HOOK: ɓ
-\def\ccurl {\char"0255 } % LATIN SMALL LETTER C WITH CURL: ɕ
-\def\dtail {\char"0256 } % LATIN SMALL LETTER D WITH TAIL: ɖ
-\def\dhook {\char"0257 } % LATIN SMALL LETTER D WITH HOOK: ɗ
-\def\schwa {\char"0259 } % LATIN SMALL LETTER SCHWA: ə
-\def\schwahook {\char"025A } % LATIN SMALL LETTER SCHWA WITH HOOK: ɚ
-\def\dotlessjstroke {\char"025F } % LATIN SMALL LETTER DOTLESS J WITH STROKE: ɟ
-\def\textcircumflex {\char"02C6 } % MODIFIER LETTER CIRCUMFLEX ACCENT: ˆ
-\def\textcaron {\char"02C7 } % CARON: ˇ
-\def\textbreve {\char"02D8 } % BREVE: ˘
-\def\textdotaccent {\char"02D9 } % DOT ABOVE: ˙
-\def\textring {\char"02DA } % RING ABOVE: ˚
-\def\textogonek {\char"02DB } % OGONEK: ˛
-\def\texttilde {\char"02DC } % SMALL TILDE: ˜
-\def\texthungarumlaut {\char"02DD } % DOUBLE ACUTE ACCENT: ˝
-\def\greektonos {\char"0384 } % GREEK TONOS: ΄
-\def\greekdialytikatonos {\char"0385 } % GREEK DIALYTIKA TONOS: ΅
-\def\greekAlphatonos {\char"0386 } % GREEK CAPITAL LETTER ALPHA WITH TONOS: Ά
-\def\greekEpsilontonos {\char"0388 } % GREEK CAPITAL LETTER EPSILON WITH TONOS: Έ
-\def\greekEtatonos {\char"0389 } % GREEK CAPITAL LETTER ETA WITH TONOS: Ή
-\def\greekIotatonos {\char"038A } % GREEK CAPITAL LETTER IOTA WITH TONOS: Ί
-\def\greekOmicrontonos {\char"038C } % GREEK CAPITAL LETTER OMICRON WITH TONOS: Ό
-\def\greekUpsilontonos {\char"038E } % GREEK CAPITAL LETTER UPSILON WITH TONOS: Ύ
-\def\greekOmegatonos {\char"038F } % GREEK CAPITAL LETTER OMEGA WITH TONOS: Ώ
-\def\greekiotadialytikatonos {\char"0390 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS: ΐ
-\def\greekAlpha {\char"0391 } % GREEK CAPITAL LETTER ALPHA: Α
-\def\greekBeta {\char"0392 } % GREEK CAPITAL LETTER BETA: Β
-\def\greekGamma {\char"0393 } % GREEK CAPITAL LETTER GAMMA: Γ
-\def\greekDelta {\char"0394 } % GREEK CAPITAL LETTER DELTA: Δ
-\def\greekEpsilon {\char"0395 } % GREEK CAPITAL LETTER EPSILON: Ε
-\def\greekZeta {\char"0396 } % GREEK CAPITAL LETTER ZETA: Ζ
-\def\greekEta {\char"0397 } % GREEK CAPITAL LETTER ETA: Η
-\def\greekTheta {\char"0398 } % GREEK CAPITAL LETTER THETA: Θ
-\def\greekIota {\char"0399 } % GREEK CAPITAL LETTER IOTA: Ι
-\def\greekKappa {\char"039A } % GREEK CAPITAL LETTER KAPPA: Κ
-\def\greekLambda {\char"039B } % GREEK CAPITAL LETTER LAMDA: Λ
-\def\greekMu {\char"039C } % GREEK CAPITAL LETTER MU: Μ
-\def\greekNu {\char"039D } % GREEK CAPITAL LETTER NU: Ν
-\def\greekXi {\char"039E } % GREEK CAPITAL LETTER XI: Ξ
-\def\greekOmicron {\char"039F } % GREEK CAPITAL LETTER OMICRON: Ο
-\def\greekPi {\char"03A0 } % GREEK CAPITAL LETTER PI: Π
-\def\greekRho {\char"03A1 } % GREEK CAPITAL LETTER RHO: Ρ
-\def\greekSigma {\char"03A3 } % GREEK CAPITAL LETTER SIGMA: Σ
-\def\greekTau {\char"03A4 } % GREEK CAPITAL LETTER TAU: Τ
-\def\greekUpsilon {\char"03A5 } % GREEK CAPITAL LETTER UPSILON: Υ
-\def\greekPhi {\char"03A6 } % GREEK CAPITAL LETTER PHI: Φ
-\def\greekChi {\char"03A7 } % GREEK CAPITAL LETTER CHI: Χ
-\def\greekPsi {\char"03A8 } % GREEK CAPITAL LETTER PSI: Ψ
-\def\greekOmega {\char"03A9 } % GREEK CAPITAL LETTER OMEGA: Ω
-\def\greekIotadialytika {\char"03AA } % GREEK CAPITAL LETTER IOTA WITH DIALYTIKA: Ϊ
-\def\greekUpsilondialytika {\char"03AB } % GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA: Ϋ
-\def\greekalphatonos {\char"03AC } % GREEK SMALL LETTER ALPHA WITH TONOS: ά
-\def\greekepsilontonos {\char"03AD } % GREEK SMALL LETTER EPSILON WITH TONOS: έ
-\def\greeketatonos {\char"03AE } % GREEK SMALL LETTER ETA WITH TONOS: ή
-\def\greekiotatonos {\char"03AF } % GREEK SMALL LETTER IOTA WITH TONOS: ί
-\def\greekupsilondialytikatonos {\char"03B0 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS: ΰ
-\def\greekalpha {\char"03B1 } % GREEK SMALL LETTER ALPHA: α
-\def\greekbeta {\char"03B2 } % GREEK SMALL LETTER BETA: β
-\def\greekgamma {\char"03B3 } % GREEK SMALL LETTER GAMMA: γ
-\def\greekdelta {\char"03B4 } % GREEK SMALL LETTER DELTA: δ
-\def\greekepsilon {\char"03B5 } % GREEK SMALL LETTER EPSILON: ε
-\def\greekzeta {\char"03B6 } % GREEK SMALL LETTER ZETA: ζ
-\def\greeketa {\char"03B7 } % GREEK SMALL LETTER ETA: η
-\def\greektheta {\char"03B8 } % GREEK SMALL LETTER THETA: θ
-\def\greekiota {\char"03B9 } % GREEK SMALL LETTER IOTA: ι
-\def\greekkappa {\char"03BA } % GREEK SMALL LETTER KAPPA: κ
-\def\greeklambda {\char"03BB } % GREEK SMALL LETTER LAMDA: λ
-\def\greekmu {\char"03BC } % GREEK SMALL LETTER MU: μ
-\def\greeknu {\char"03BD } % GREEK SMALL LETTER NU: ν
-\def\greekxi {\char"03BE } % GREEK SMALL LETTER XI: ξ
-\def\greekomicron {\char"03BF } % GREEK SMALL LETTER OMICRON: ο
-\def\greekpi {\char"03C0 } % GREEK SMALL LETTER PI: π
-\def\greekrho {\char"03C1 } % GREEK SMALL LETTER RHO: ρ
-\def\greekfinalsigma {\char"03C2 } % GREEK SMALL LETTER FINAL SIGMA: ς
-\def\greeksigma {\char"03C3 } % GREEK SMALL LETTER SIGMA: σ
-\def\greektau {\char"03C4 } % GREEK SMALL LETTER TAU: τ
-\def\greekupsilon {\char"03C5 } % GREEK SMALL LETTER UPSILON: υ
-\def\greekphi {\char"03C6 } % GREEK SMALL LETTER PHI: φ
-\def\greekchi {\char"03C7 } % GREEK SMALL LETTER CHI: χ
-\def\greekpsi {\char"03C8 } % GREEK SMALL LETTER PSI: ψ
-\def\greekomega {\char"03C9 } % GREEK SMALL LETTER OMEGA: ω
-\def\greekiotadialytika {\char"03CA } % GREEK SMALL LETTER IOTA WITH DIALYTIKA: ϊ
-\def\greekupsilondiaeresis {\char"03CB } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA: ϋ
-\def\greekomicrontonos {\char"03CC } % GREEK SMALL LETTER OMICRON WITH TONOS: ό
-\def\greekupsilontonos {\char"03CD } % GREEK SMALL LETTER UPSILON WITH TONOS: ύ
-\def\greekomegatonos {\char"03CE } % GREEK SMALL LETTER OMEGA WITH TONOS: ώ
-\def\greekthetaalt {\char"03D1 } % GREEK THETA SYMBOL: ϑ
-\def\greekphialt {\char"03D5 } % GREEK PHI SYMBOL: ϕ
-\def\greekpialt {\char"03D6 } % GREEK PI SYMBOL: ϖ
-\def\greekkoppa {\char"03D9 } % GREEK SMALL LETTER ARCHAIC KOPPA: ϙ
-\def\greekstigma {\char"03DB } % GREEK SMALL LETTER STIGMA: ϛ
-\def\greekdigamma {\char"03DD } % GREEK SMALL LETTER DIGAMMA: ϝ
-\def\greeknumkoppa {\char"03DF } % GREEK SMALL LETTER KOPPA: ϟ
-\def\greeksampi {\char"03E1 } % GREEK SMALL LETTER SAMPI: ϡ
-\def\greekrhoalt {\char"03F1 } % GREEK RHO SYMBOL: ϱ
-\def\greeksigmalunate {\char"03F2 } % GREEK LUNATE SIGMA SYMBOL: ϲ
-\def\greekepsilonalt {\char"03F5 } % GREEK LUNATE EPSILON SYMBOL: ϵ
-\def\greekSigmalunate {\char"03F9 } % GREEK CAPITAL LUNATE SIGMA SYMBOL: Ϲ
-\def\cyrillicEgrave {\char"0400 } % CYRILLIC CAPITAL LETTER IE WITH GRAVE: Ѐ
-\def\cyrillicYO {\char"0401 } % CYRILLIC CAPITAL LETTER IO: Ё
-\def\cyrillicDJE {\char"0402 } % CYRILLIC CAPITAL LETTER DJE: Ђ
-\def\cyrillicGJE {\char"0403 } % CYRILLIC CAPITAL LETTER GJE: Ѓ
-\def\cyrillicIE {\char"0404 } % CYRILLIC CAPITAL LETTER UKRAINIAN IE: Є
-\def\cyrillicDZE {\char"0405 } % CYRILLIC CAPITAL LETTER DZE: Ѕ
-\def\cyrillicII {\char"0406 } % CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I: І
-\def\cyrillicYI {\char"0407 } % CYRILLIC CAPITAL LETTER YI: Ї
-\def\cyrillicJE {\char"0408 } % CYRILLIC CAPITAL LETTER JE: Ј
-\def\cyrillicLJE {\char"0409 } % CYRILLIC CAPITAL LETTER LJE: Љ
-\def\cyrillicNJE {\char"040A } % CYRILLIC CAPITAL LETTER NJE: Њ
-\def\cyrillicTSHE {\char"040B } % CYRILLIC CAPITAL LETTER TSHE: Ћ
-\def\cyrillicKJE {\char"040C } % CYRILLIC CAPITAL LETTER KJE: Ќ
-\def\cyrillicIgrave {\char"040D } % CYRILLIC CAPITAL LETTER I WITH GRAVE: Ѝ
-\def\cyrillicUSHRT {\char"040E } % CYRILLIC CAPITAL LETTER SHORT U: Ў
-\def\cyrillicDZHE {\char"040F } % CYRILLIC CAPITAL LETTER DZHE: Џ
-\def\cyrillicA {\char"0410 } % CYRILLIC CAPITAL LETTER A: А
-\def\cyrillicB {\char"0411 } % CYRILLIC CAPITAL LETTER BE: Б
-\def\cyrillicV {\char"0412 } % CYRILLIC CAPITAL LETTER VE: В
-\def\cyrillicG {\char"0413 } % CYRILLIC CAPITAL LETTER GHE: Г
-\def\cyrillicD {\char"0414 } % CYRILLIC CAPITAL LETTER DE: Д
-\def\cyrillicE {\char"0415 } % CYRILLIC CAPITAL LETTER IE: Е
-\def\cyrillicZH {\char"0416 } % CYRILLIC CAPITAL LETTER ZHE: Ж
-\def\cyrillicZ {\char"0417 } % CYRILLIC CAPITAL LETTER ZE: З
-\def\cyrillicI {\char"0418 } % CYRILLIC CAPITAL LETTER I: И
-\def\cyrillicISHRT {\char"0419 } % CYRILLIC CAPITAL LETTER SHORT I: Й
-\def\cyrillicK {\char"041A } % CYRILLIC CAPITAL LETTER KA: К
-\def\cyrillicL {\char"041B } % CYRILLIC CAPITAL LETTER EL: Л
-\def\cyrillicM {\char"041C } % CYRILLIC CAPITAL LETTER EM: М
-\def\cyrillicN {\char"041D } % CYRILLIC CAPITAL LETTER EN: Н
-\def\cyrillicO {\char"041E } % CYRILLIC CAPITAL LETTER O: О
-\def\cyrillicP {\char"041F } % CYRILLIC CAPITAL LETTER PE: П
-\def\cyrillicR {\char"0420 } % CYRILLIC CAPITAL LETTER ER: Р
-\def\cyrillicS {\char"0421 } % CYRILLIC CAPITAL LETTER ES: С
-\def\cyrillicT {\char"0422 } % CYRILLIC CAPITAL LETTER TE: Т
-\def\cyrillicU {\char"0423 } % CYRILLIC CAPITAL LETTER U: У
-\def\cyrillicF {\char"0424 } % CYRILLIC CAPITAL LETTER EF: Ф
-\def\cyrillicH {\char"0425 } % CYRILLIC CAPITAL LETTER HA: Х
-\def\cyrillicC {\char"0426 } % CYRILLIC CAPITAL LETTER TSE: Ц
-\def\cyrillicCH {\char"0427 } % CYRILLIC CAPITAL LETTER CHE: Ч
-\def\cyrillicSH {\char"0428 } % CYRILLIC CAPITAL LETTER SHA: Ш
-\def\cyrillicSHCH {\char"0429 } % CYRILLIC CAPITAL LETTER SHCHA: Щ
-\def\cyrillicHRDSN {\char"042A } % CYRILLIC CAPITAL LETTER HARD SIGN: Ъ
-\def\cyrillicERY {\char"042B } % CYRILLIC CAPITAL LETTER YERU: Ы
-\def\cyrillicSFTSN {\char"042C } % CYRILLIC CAPITAL LETTER SOFT SIGN: Ь
-\def\cyrillicEREV {\char"042D } % CYRILLIC CAPITAL LETTER E: Э
-\def\cyrillicYU {\char"042E } % CYRILLIC CAPITAL LETTER YU: Ю
-\def\cyrillicYA {\char"042F } % CYRILLIC CAPITAL LETTER YA: Я
-\def\cyrillica {\char"0430 } % CYRILLIC SMALL LETTER A: а
-\def\cyrillicb {\char"0431 } % CYRILLIC SMALL LETTER BE: б
-\def\cyrillicv {\char"0432 } % CYRILLIC SMALL LETTER VE: в
-\def\cyrillicg {\char"0433 } % CYRILLIC SMALL LETTER GHE: г
-\def\cyrillicd {\char"0434 } % CYRILLIC SMALL LETTER DE: д
-\def\cyrillice {\char"0435 } % CYRILLIC SMALL LETTER IE: е
-\def\cyrilliczh {\char"0436 } % CYRILLIC SMALL LETTER ZHE: ж
-\def\cyrillicz {\char"0437 } % CYRILLIC SMALL LETTER ZE: з
-\def\cyrillici {\char"0438 } % CYRILLIC SMALL LETTER I: и
-\def\cyrillicishrt {\char"0439 } % CYRILLIC SMALL LETTER SHORT I: й
-\def\cyrillick {\char"043A } % CYRILLIC SMALL LETTER KA: к
-\def\cyrillicl {\char"043B } % CYRILLIC SMALL LETTER EL: л
-\def\cyrillicm {\char"043C } % CYRILLIC SMALL LETTER EM: м
-\def\cyrillicn {\char"043D } % CYRILLIC SMALL LETTER EN: н
-\def\cyrillico {\char"043E } % CYRILLIC SMALL LETTER O: о
-\def\cyrillicp {\char"043F } % CYRILLIC SMALL LETTER PE: п
-\def\cyrillicr {\char"0440 } % CYRILLIC SMALL LETTER ER: р
-\def\cyrillics {\char"0441 } % CYRILLIC SMALL LETTER ES: с
-\def\cyrillict {\char"0442 } % CYRILLIC SMALL LETTER TE: т
-\def\cyrillicu {\char"0443 } % CYRILLIC SMALL LETTER U: у
-\def\cyrillicf {\char"0444 } % CYRILLIC SMALL LETTER EF: ф
-\def\cyrillich {\char"0445 } % CYRILLIC SMALL LETTER HA: х
-\def\cyrillicc {\char"0446 } % CYRILLIC SMALL LETTER TSE: ц
-\def\cyrillicch {\char"0447 } % CYRILLIC SMALL LETTER CHE: ч
-\def\cyrillicsh {\char"0448 } % CYRILLIC SMALL LETTER SHA: ш
-\def\cyrillicshch {\char"0449 } % CYRILLIC SMALL LETTER SHCHA: щ
-\def\cyrillichrdsn {\char"044A } % CYRILLIC SMALL LETTER HARD SIGN: ъ
-\def\cyrillicery {\char"044B } % CYRILLIC SMALL LETTER YERU: ы
-\def\cyrillicsftsn {\char"044C } % CYRILLIC SMALL LETTER SOFT SIGN: ь
-\def\cyrillicerev {\char"044D } % CYRILLIC SMALL LETTER E: э
-\def\cyrillicyu {\char"044E } % CYRILLIC SMALL LETTER YU: ю
-\def\cyrillicya {\char"044F } % CYRILLIC SMALL LETTER YA: я
-\def\cyrillicegrave {\char"0450 } % CYRILLIC SMALL LETTER IE WITH GRAVE: ѐ
-\def\cyrillicyo {\char"0451 } % CYRILLIC SMALL LETTER IO: ё
-\def\cyrillicdje {\char"0452 } % CYRILLIC SMALL LETTER DJE: ђ
-\def\cyrillicgje {\char"0453 } % CYRILLIC SMALL LETTER GJE: ѓ
-\def\cyrillicie {\char"0454 } % CYRILLIC SMALL LETTER UKRAINIAN IE: є
-\def\cyrillicdze {\char"0455 } % CYRILLIC SMALL LETTER DZE: ѕ
-\def\cyrillicii {\char"0456 } % CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I: і
-\def\cyrillicyi {\char"0457 } % CYRILLIC SMALL LETTER YI: ї
-\def\cyrillicje {\char"0458 } % CYRILLIC SMALL LETTER JE: ј
-\def\cyrilliclje {\char"0459 } % CYRILLIC SMALL LETTER LJE: љ
-\def\cyrillicnje {\char"045A } % CYRILLIC SMALL LETTER NJE: њ
-\def\cyrillictshe {\char"045B } % CYRILLIC SMALL LETTER TSHE: ћ
-\def\cyrillickje {\char"045C } % CYRILLIC SMALL LETTER KJE: ќ
-\def\cyrillicigrave {\char"045D } % CYRILLIC SMALL LETTER I WITH GRAVE: ѝ
-\def\cyrillicushrt {\char"045E } % CYRILLIC SMALL LETTER SHORT U: ў
-\def\cyrillicdzhe {\char"045F } % CYRILLIC SMALL LETTER DZHE: џ
-\def\cyrillicOMEGA {\char"0460 } % CYRILLIC CAPITAL LETTER OMEGA: Ѡ
-\def\cyrillicomega {\char"0461 } % CYRILLIC SMALL LETTER OMEGA: ѡ
-\def\cyrillicYAT {\char"0462 } % CYRILLIC CAPITAL LETTER YAT: Ѣ
-\def\cyrillicyat {\char"0463 } % CYRILLIC SMALL LETTER YAT: ѣ
-\def\cyrillicEiotified {\char"0464 } % CYRILLIC CAPITAL LETTER IOTIFIED E: Ѥ
-\def\cyrilliceiotified {\char"0465 } % CYRILLIC SMALL LETTER IOTIFIED E: ѥ
-\def\cyrillicLITTLEYUS {\char"0466 } % CYRILLIC CAPITAL LETTER LITTLE YUS: Ѧ
-\def\cyrilliclittleyus {\char"0467 } % CYRILLIC SMALL LETTER LITTLE YUS: ѧ
-\def\cyrillicLITTLEYUSiotified {\char"0468 } % CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS: Ѩ
-\def\cyrilliclittleyusiotified {\char"0469 } % CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS: ѩ
-\def\cyrillicBIGYUS {\char"046A } % CYRILLIC CAPITAL LETTER BIG YUS: Ѫ
-\def\cyrillicbigyus {\char"046B } % CYRILLIC SMALL LETTER BIG YUS: ѫ
-\def\cyrillicBIGYUSiotified {\char"046C } % CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS: Ѭ
-\def\cyrillicbigyusiotified {\char"046D } % CYRILLIC SMALL LETTER IOTIFIED BIG YUS: ѭ
-\def\cyrillicKSI {\char"046E } % CYRILLIC CAPITAL LETTER KSI: Ѯ
-\def\cyrillicksi {\char"046F } % CYRILLIC SMALL LETTER KSI: ѯ
-\def\cyrillicPSI {\char"0470 } % CYRILLIC CAPITAL LETTER PSI: Ѱ
-\def\cyrillicpsi {\char"0471 } % CYRILLIC SMALL LETTER PSI: ѱ
-\def\cyrillicFITA {\char"0472 } % CYRILLIC CAPITAL LETTER FITA: Ѳ
-\def\cyrillicfita {\char"0473 } % CYRILLIC SMALL LETTER FITA: ѳ
-\def\cyrillicIZHITSA {\char"0474 } % CYRILLIC CAPITAL LETTER IZHITSA: Ѵ
-\def\cyrillicizhitsa {\char"0475 } % CYRILLIC SMALL LETTER IZHITSA: ѵ
-\def\cyrillicIZHITSAdoublegrave {\char"0476 } % CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT: Ѷ
-\def\cyrillicizhitsadoublegrave {\char"0477 } % CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT: ѷ
-\def\cyrillicUK {\char"0478 } % CYRILLIC CAPITAL LETTER UK: Ѹ
-\def\cyrillicuk {\char"0479 } % CYRILLIC SMALL LETTER UK: ѹ
-\def\cyrillicOMEGAround {\char"047A } % CYRILLIC CAPITAL LETTER ROUND OMEGA: Ѻ
-\def\cyrillicomegaround {\char"047B } % CYRILLIC SMALL LETTER ROUND OMEGA: ѻ
-\def\cyrillicOMEGAtitlo {\char"047C } % CYRILLIC CAPITAL LETTER OMEGA WITH TITLO: Ѽ
-\def\cyrillicomegatitlo {\char"047D } % CYRILLIC SMALL LETTER OMEGA WITH TITLO: ѽ
-\def\cyrillicOT {\char"047E } % CYRILLIC CAPITAL LETTER OT: Ѿ
-\def\cyrillicot {\char"047F } % CYRILLIC SMALL LETTER OT: ѿ
-\def\cyrillicKOPPA {\char"0480 } % CYRILLIC CAPITAL LETTER KOPPA: Ҁ
-\def\cyrillickoppa {\char"0481 } % CYRILLIC SMALL LETTER KOPPA: ҁ
-\def\cyrillicTITLO {\char"0483 } % COMBINING CYRILLIC TITLO: ҃
-\def\cyrillicPALATALIZATION {\char"0484 } % COMBINING CYRILLIC PALATALIZATION: ҄
-\def\cyrillicDASIAPNEUMATA {\char"0485 } % COMBINING CYRILLIC DASIA PNEUMATA: ҅
-\def\cyrillicPSILIPNEUMATA {\char"0486 } % COMBINING CYRILLIC PSILI PNEUMATA: ҆
-\def\cyrillicISHRTtail {\char"048A } % CYRILLIC CAPITAL LETTER SHORT I WITH TAIL: Ҋ
-\def\cyrillicishrttail {\char"048B } % CYRILLIC SMALL LETTER SHORT I WITH TAIL: ҋ
-\def\cyrillicSEMISOFT {\char"048C } % CYRILLIC CAPITAL LETTER SEMISOFT SIGN: Ҍ
-\def\cyrillicsemisoft {\char"048D } % CYRILLIC SMALL LETTER SEMISOFT SIGN: ҍ
-\def\cyrillicERtick {\char"048E } % CYRILLIC CAPITAL LETTER ER WITH TICK: Ҏ
-\def\cyrillicertick {\char"048F } % CYRILLIC SMALL LETTER ER WITH TICK: ҏ
-\def\cyrillicGHEupturn {\char"0490 } % CYRILLIC CAPITAL LETTER GHE WITH UPTURN: Ґ
-\def\cyrillicgheupturn {\char"0491 } % CYRILLIC SMALL LETTER GHE WITH UPTURN: ґ
-\def\cyrillicGHEstroke {\char"0492 } % CYRILLIC CAPITAL LETTER GHE WITH STROKE: Ғ
-\def\cyrillicghestroke {\char"0493 } % CYRILLIC SMALL LETTER GHE WITH STROKE: ғ
-\def\cyrillicGHEmidhook {\char"0494 } % CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK: Ҕ
-\def\cyrillicghemidhook {\char"0495 } % CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK: ҕ
-\def\cyrillicZHEdescender {\char"0496 } % CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER: Җ
-\def\cyrilliczhedescender {\char"0497 } % CYRILLIC SMALL LETTER ZHE WITH DESCENDER: җ
-\def\cyrillicZDSC {\char"0498 } % CYRILLIC CAPITAL LETTER ZE WITH DESCENDER: Ҙ
-\def\cyrilliczdsc {\char"0499 } % CYRILLIC SMALL LETTER ZE WITH DESCENDER: ҙ
-\def\cyrillicKADC {\char"049A } % CYRILLIC CAPITAL LETTER KA WITH DESCENDER: Қ
-\def\cyrillickadc {\char"049B } % CYRILLIC SMALL LETTER KA WITH DESCENDER: қ
-\def\cyrillicKAvertstroke {\char"049C } % CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE: Ҝ
-\def\cyrillickavertstroke {\char"049D } % CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE: ҝ
-\def\cyrillicKAstroke {\char"049E } % CYRILLIC CAPITAL LETTER KA WITH STROKE: Ҟ
-\def\cyrillickastroke {\char"049F } % CYRILLIC SMALL LETTER KA WITH STROKE: ҟ
-\def\cyrillicKAbashkir {\char"04A0 } % CYRILLIC CAPITAL LETTER BASHKIR KA: Ҡ
-\def\cyrillickabashkir {\char"04A1 } % CYRILLIC SMALL LETTER BASHKIR KA: ҡ
-\def\cyrillicENDC {\char"04A2 } % CYRILLIC CAPITAL LETTER EN WITH DESCENDER: Ң
-\def\cyrillicendc {\char"04A3 } % CYRILLIC SMALL LETTER EN WITH DESCENDER: ң
-\def\cyrillicENGHE {\char"04A4 } % CYRILLIC CAPITAL LIGATURE EN GHE: Ҥ
-\def\cyrillicenghe {\char"04A5 } % CYRILLIC SMALL LIGATURE EN GHE: ҥ
-\def\cyrillicPEmidhook {\char"04A6 } % CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK: Ҧ
-\def\cyrillicpemidhook {\char"04A7 } % CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK: ҧ
-\def\cyrillicHA {\char"04A8 } % CYRILLIC CAPITAL LETTER ABKHASIAN HA: Ҩ
-\def\cyrillicha {\char"04A9 } % CYRILLIC SMALL LETTER ABKHASIAN HA: ҩ
-\def\cyrillicSDSC {\char"04AA } % CYRILLIC CAPITAL LETTER ES WITH DESCENDER: Ҫ
-\def\cyrillicsdsc {\char"04AB } % CYRILLIC SMALL LETTER ES WITH DESCENDER: ҫ
-\def\cyrillicTEDC {\char"04AC } % CYRILLIC CAPITAL LETTER TE WITH DESCENDER: Ҭ
-\def\cyrillictedc {\char"04AD } % CYRILLIC SMALL LETTER TE WITH DESCENDER: ҭ
-\def\cyrillicYstr {\char"04AE } % CYRILLIC CAPITAL LETTER STRAIGHT U: Ү
-\def\cyrillicystr {\char"04AF } % CYRILLIC SMALL LETTER STRAIGHT U: ү
-\def\cyrillicYstrstroke {\char"04B0 } % CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE: Ұ
-\def\cyrillicystrstroke {\char"04B1 } % CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE: ұ
-\def\cyrillicHADC {\char"04B2 } % CYRILLIC CAPITAL LETTER HA WITH DESCENDER: Ҳ
-\def\cyrillichadc {\char"04B3 } % CYRILLIC SMALL LETTER HA WITH DESCENDER: ҳ
-\def\cyrillicTETSE {\char"04B4 } % CYRILLIC CAPITAL LIGATURE TE TSE: Ҵ
-\def\cyrillictetse {\char"04B5 } % CYRILLIC SMALL LIGATURE TE TSE: ҵ
-\def\cyrillicCHEDC {\char"04B6 } % CYRILLIC CAPITAL LETTER CHE WITH DESCENDER: Ҷ
-\def\cyrillicchedc {\char"04B7 } % CYRILLIC SMALL LETTER CHE WITH DESCENDER: ҷ
-\def\cyrillicCHEvertstroke {\char"04B8 } % CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE: Ҹ
-\def\cyrillicchevertstroke {\char"04B9 } % CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE: ҹ
-\def\cyrillicSHHA {\char"04BA } % CYRILLIC CAPITAL LETTER SHHA: Һ
-\def\cyrillicshha {\char"04BB } % CYRILLIC SMALL LETTER SHHA: һ
-\def\cyrillicCHEabkhasian {\char"04BC } % CYRILLIC CAPITAL LETTER ABKHASIAN CHE: Ҽ
-\def\cyrilliccheabkhasian {\char"04BD } % CYRILLIC SMALL LETTER ABKHASIAN CHE: ҽ
-\def\cyrillicCHEDCabkhasian {\char"04BE } % CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER: Ҿ
-\def\cyrillicchedcabkhasian {\char"04BF } % CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER: ҿ
-\def\cyrillicPALOCHKA {\char"04C0 } % CYRILLIC LETTER PALOCHKA: Ӏ
-\def\cyrillicZHEbreve {\char"04C1 } % CYRILLIC CAPITAL LETTER ZHE WITH BREVE: Ӂ
-\def\cyrilliczhebreve {\char"04C2 } % CYRILLIC SMALL LETTER ZHE WITH BREVE: ӂ
-\def\cyrillicKAhook {\char"04C3 } % CYRILLIC CAPITAL LETTER KA WITH HOOK: Ӄ
-\def\cyrillickahook {\char"04C4 } % CYRILLIC SMALL LETTER KA WITH HOOK: ӄ
-\def\cyrillicELtail {\char"04C5 } % CYRILLIC CAPITAL LETTER EL WITH TAIL: Ӆ
-\def\cyrilliceltail {\char"04C6 } % CYRILLIC SMALL LETTER EL WITH TAIL: ӆ
-\def\cyrillicENhook {\char"04C7 } % CYRILLIC CAPITAL LETTER EN WITH HOOK: Ӈ
-\def\cyrillicenhook {\char"04C8 } % CYRILLIC SMALL LETTER EN WITH HOOK: ӈ
-\def\cyrillicENtail {\char"04C9 } % CYRILLIC CAPITAL LETTER EN WITH TAIL: Ӊ
-\def\cyrillicentail {\char"04CA } % CYRILLIC SMALL LETTER EN WITH TAIL: ӊ
-\def\cyrillicCHEkhakassian {\char"04CB } % CYRILLIC CAPITAL LETTER KHAKASSIAN CHE: Ӌ
-\def\cyrillicchekhakassian {\char"04CC } % CYRILLIC SMALL LETTER KHAKASSIAN CHE: ӌ
-\def\cyrillicEMtail {\char"04CD } % CYRILLIC CAPITAL LETTER EM WITH TAIL: Ӎ
-\def\cyrillicemtail {\char"04CE } % CYRILLIC SMALL LETTER EM WITH TAIL: ӎ
-\def\cyrillicAbreve {\char"04D0 } % CYRILLIC CAPITAL LETTER A WITH BREVE: Ӑ
-\def\cyrillicabreve {\char"04D1 } % CYRILLIC SMALL LETTER A WITH BREVE: ӑ
-\def\cyrillicAdiaeresis {\char"04D2 } % CYRILLIC CAPITAL LETTER A WITH DIAERESIS: Ӓ
-\def\cyrillicadiaeresis {\char"04D3 } % CYRILLIC SMALL LETTER A WITH DIAERESIS: ӓ
-\def\cyrillicAE {\char"04D4 } % CYRILLIC CAPITAL LIGATURE A IE: Ӕ
-\def\cyrillicae {\char"04D5 } % CYRILLIC SMALL LIGATURE A IE: ӕ
-\def\cyrillicEbreve {\char"04D6 } % CYRILLIC CAPITAL LETTER IE WITH BREVE: Ӗ
-\def\cyrillicebreve {\char"04D7 } % CYRILLIC SMALL LETTER IE WITH BREVE: ӗ
-\def\cyrillicSCHWA {\char"04D8 } % CYRILLIC CAPITAL LETTER SCHWA: Ә
-\def\cyrillicschwa {\char"04D9 } % CYRILLIC SMALL LETTER SCHWA: ә
-\def\cyrillicSCHWAdiaeresis {\char"04DA } % CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS: Ӛ
-\def\cyrillicschwadiaeresis {\char"04DB } % CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS: ӛ
-\def\cyrillicZHEdiaeresis {\char"04DC } % CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS: Ӝ
-\def\cyrilliczhediaeresis {\char"04DD } % CYRILLIC SMALL LETTER ZHE WITH DIAERESIS: ӝ
-\def\cyrillicZEdiaeresis {\char"04DE } % CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS: Ӟ
-\def\cyrilliczediaeresis {\char"04DF } % CYRILLIC SMALL LETTER ZE WITH DIAERESIS: ӟ
-\def\cyrillicDZEabkhasian {\char"04E0 } % CYRILLIC CAPITAL LETTER ABKHASIAN DZE: Ӡ
-\def\cyrillicdzeabkhasian {\char"04E1 } % CYRILLIC SMALL LETTER ABKHASIAN DZE: ӡ
-\def\cyrillicImacron {\char"04E2 } % CYRILLIC CAPITAL LETTER I WITH MACRON: Ӣ
-\def\cyrillicimacron {\char"04E3 } % CYRILLIC SMALL LETTER I WITH MACRON: ӣ
-\def\cyrillicIdiaeresis {\char"04E4 } % CYRILLIC CAPITAL LETTER I WITH DIAERESIS: Ӥ
-\def\cyrillicidiaeresis {\char"04E5 } % CYRILLIC SMALL LETTER I WITH DIAERESIS: ӥ
-\def\cyrillicOdiaeresis {\char"04E6 } % CYRILLIC CAPITAL LETTER O WITH DIAERESIS: Ӧ
-\def\cyrillicodiaeresis {\char"04E7 } % CYRILLIC SMALL LETTER O WITH DIAERESIS: ӧ
-\def\cyrillicObarred {\char"04E8 } % CYRILLIC CAPITAL LETTER BARRED O: Ө
-\def\cyrillicobarred {\char"04E9 } % CYRILLIC SMALL LETTER BARRED O: ө
-\def\cyrillicObarreddiaeresis {\char"04EA } % CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS: Ӫ
-\def\cyrillicobarreddiaeresis {\char"04EB } % CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS: ӫ
-\def\cyrillicEdiaeresis {\char"04EC } % CYRILLIC CAPITAL LETTER E WITH DIAERESIS: Ӭ
-\def\cyrillicediaeresis {\char"04ED } % CYRILLIC SMALL LETTER E WITH DIAERESIS: ӭ
-\def\cyrillicUmacron {\char"04EE } % CYRILLIC CAPITAL LETTER U WITH MACRON: Ӯ
-\def\cyrillicumacron {\char"04EF } % CYRILLIC SMALL LETTER U WITH MACRON: ӯ
-\def\cyrillicUdiaeresis {\char"04F0 } % CYRILLIC CAPITAL LETTER U WITH DIAERESIS: Ӱ
-\def\cyrillicudiaeresis {\char"04F1 } % CYRILLIC SMALL LETTER U WITH DIAERESIS: ӱ
-\def\cyrillicUdoubleacute {\char"04F2 } % CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE: Ӳ
-\def\cyrillicudoubleacute {\char"04F3 } % CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE: ӳ
-\def\cyrillicCHEdiaeresis {\char"04F4 } % CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS: Ӵ
-\def\cyrillicchediaeresis {\char"04F5 } % CYRILLIC SMALL LETTER CHE WITH DIAERESIS: ӵ
-\def\cyrillicYERUdiaeresis {\char"04F8 } % CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS: Ӹ
-\def\cyrillicyerudiaeresis {\char"04F9 } % CYRILLIC SMALL LETTER YERU WITH DIAERESIS: ӹ
-\def\hebrewAlef {\char"05D0 } % HEBREW LETTER ALEF: א
-\def\hebrewBet {\char"05D1 } % HEBREW LETTER BET: ב
-\def\hebrewGimel {\char"05D2 } % HEBREW LETTER GIMEL: ג
-\def\hebrewDalet {\char"05D3 } % HEBREW LETTER DALET: ד
-\def\hebrewHe {\char"05D4 } % HEBREW LETTER HE: ה
-\def\hebrewVav {\char"05D5 } % HEBREW LETTER VAV: ו
-\def\hebrewZayin {\char"05D6 } % HEBREW LETTER ZAYIN: ז
-\def\hebrewHet {\char"05D7 } % HEBREW LETTER HET: ח
-\def\hebrewTet {\char"05D8 } % HEBREW LETTER TET: ט
-\def\hebrewYod {\char"05D9 } % HEBREW LETTER YOD: י
-\def\hebrewKaffinal {\char"05DA } % HEBREW LETTER FINAL KAF: ך
-\def\hebrewKaf {\char"05DB } % HEBREW LETTER KAF: כ
-\def\hebrewLamed {\char"05DC } % HEBREW LETTER LAMED: ל
-\def\hebrewMemfinal {\char"05DD } % HEBREW LETTER FINAL MEM: ם
-\def\hebrewMem {\char"05DE } % HEBREW LETTER MEM: מ
-\def\hebrewNunfinal {\char"05DF } % HEBREW LETTER FINAL NUN: ן
-\def\hebrewNun {\char"05E0 } % HEBREW LETTER NUN: נ
-\def\hebrewSamekh {\char"05E1 } % HEBREW LETTER SAMEKH: ס
-\def\hebrewAyin {\char"05E2 } % HEBREW LETTER AYIN: ע
-\def\hebrewPefinal {\char"05E3 } % HEBREW LETTER FINAL PE: ף
-\def\hebrewPe {\char"05E4 } % HEBREW LETTER PE: פ
-\def\hebrewTsadifinal {\char"05E5 } % HEBREW LETTER FINAL TSADI: ץ
-\def\hebrewTsadi {\char"05E6 } % HEBREW LETTER TSADI: צ
-\def\hebrewQof {\char"05E7 } % HEBREW LETTER QOF: ק
-\def\hebrewResh {\char"05E8 } % HEBREW LETTER RESH: ר
-\def\hebrewShin {\char"05E9 } % HEBREW LETTER SHIN: ש
-\def\hebrewTav {\char"05EA } % HEBREW LETTER TAV: ת
-\def\Adotbelow {\char"1EA0 } % LATIN CAPITAL LETTER A WITH DOT BELOW: Ạ
-\def\adotbelow {\char"1EA1 } % LATIN SMALL LETTER A WITH DOT BELOW: ạ
-\def\Ahook {\char"1EA2 } % LATIN CAPITAL LETTER A WITH HOOK ABOVE: Ả
-\def\ahook {\char"1EA3 } % LATIN SMALL LETTER A WITH HOOK ABOVE: ả
-\def\Acircumflexacute {\char"1EA4 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE: Ấ
-\def\acircumflexacute {\char"1EA5 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE: ấ
-\def\Acircumflexgrave {\char"1EA6 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE: Ầ
-\def\acircumflexgrave {\char"1EA7 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE: ầ
-\def\Acircumflexhook {\char"1EA8 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE: Ẩ
-\def\acircumflexhook {\char"1EA9 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE: ẩ
-\def\Acircumflextilde {\char"1EAA } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE: Ẫ
-\def\acircumflextilde {\char"1EAB } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE: ẫ
-\def\Acircumflexdotbelow {\char"1EAC } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW: Ậ
-\def\acircumflexdotbelow {\char"1EAD } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW: ậ
-\def\Abreveacute {\char"1EAE } % LATIN CAPITAL LETTER A WITH BREVE AND ACUTE: Ắ
-\def\abreveacute {\char"1EAF } % LATIN SMALL LETTER A WITH BREVE AND ACUTE: ắ
-\def\Abrevegrave {\char"1EB0 } % LATIN CAPITAL LETTER A WITH BREVE AND GRAVE: Ằ
-\def\abrevegrave {\char"1EB1 } % LATIN SMALL LETTER A WITH BREVE AND GRAVE: ằ
-\def\Abrevehook {\char"1EB2 } % LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE: Ẳ
-\def\abrevehook {\char"1EB3 } % LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE: ẳ
-\def\Abrevetilde {\char"1EB4 } % LATIN CAPITAL LETTER A WITH BREVE AND TILDE: Ẵ
-\def\abrevetilde {\char"1EB5 } % LATIN SMALL LETTER A WITH BREVE AND TILDE: ẵ
-\def\Abrevedotbelow {\char"1EB6 } % LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW: Ặ
-\def\abrevedotbelow {\char"1EB7 } % LATIN SMALL LETTER A WITH BREVE AND DOT BELOW: ặ
-\def\Edotbelow {\char"1EB8 } % LATIN CAPITAL LETTER E WITH DOT BELOW: Ẹ
-\def\edotbelow {\char"1EB9 } % LATIN SMALL LETTER E WITH DOT BELOW: ẹ
-\def\Ehook {\char"1EBA } % LATIN CAPITAL LETTER E WITH HOOK ABOVE: Ẻ
-\def\ehook {\char"1EBB } % LATIN SMALL LETTER E WITH HOOK ABOVE: ẻ
-\def\Etilde {\char"1EBC } % LATIN CAPITAL LETTER E WITH TILDE: Ẽ
-\def\etilde {\char"1EBD } % LATIN SMALL LETTER E WITH TILDE: ẽ
-\def\Ecircumflexacute {\char"1EBE } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE: Ế
-\def\ecircumflexacute {\char"1EBF } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE: ế
-\def\Ecircumflexgrave {\char"1EC0 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE: Ề
-\def\ecircumflexgrave {\char"1EC1 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE: ề
-\def\Ecircumflexhook {\char"1EC2 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE: Ể
-\def\ecircumflexhook {\char"1EC3 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE: ể
-\def\Ecircumflextilde {\char"1EC4 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE: Ễ
-\def\ecircumflextilde {\char"1EC5 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE: ễ
-\def\Ecircumflexdotbelow {\char"1EC6 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW: Ệ
-\def\ecircumflexdotbelow {\char"1EC7 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW: ệ
-\def\Ihook {\char"1EC8 } % LATIN CAPITAL LETTER I WITH HOOK ABOVE: Ỉ
-\def\ihook {\char"1EC9 } % LATIN SMALL LETTER I WITH HOOK ABOVE: ỉ
-\def\Idotbelow {\char"1ECA } % LATIN CAPITAL LETTER I WITH DOT BELOW: Ị
-\def\idotbelow {\char"1ECB } % LATIN SMALL LETTER I WITH DOT BELOW: ị
-\def\Odotbelow {\char"1ECC } % LATIN CAPITAL LETTER O WITH DOT BELOW: Ọ
-\def\odotbelow {\char"1ECD } % LATIN SMALL LETTER O WITH DOT BELOW: ọ
-\def\Ohook {\char"1ECE } % LATIN CAPITAL LETTER O WITH HOOK ABOVE: Ỏ
-\def\ohook {\char"1ECF } % LATIN SMALL LETTER O WITH HOOK ABOVE: ỏ
-\def\Ocircumflexacute {\char"1ED0 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE: Ố
-\def\ocircumflexacute {\char"1ED1 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE: ố
-\def\Ocircumflexgrave {\char"1ED2 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE: Ồ
-\def\ocircumflexgrave {\char"1ED3 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE: ồ
-\def\Ocircumflexhook {\char"1ED4 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE: Ổ
-\def\ocircumflexhook {\char"1ED5 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE: ổ
-\def\Ocircumflextilde {\char"1ED6 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE: Ỗ
-\def\ocircumflextilde {\char"1ED7 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE: ỗ
-\def\Ocircumflexdotbelow {\char"1ED8 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW: Ộ
-\def\ocircumflexdotbelow {\char"1ED9 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW: ộ
-\def\Ohornacute {\char"1EDA } % LATIN CAPITAL LETTER O WITH HORN AND ACUTE: Ớ
-\def\ohornacute {\char"1EDB } % LATIN SMALL LETTER O WITH HORN AND ACUTE: ớ
-\def\Ohorngrave {\char"1EDC } % LATIN CAPITAL LETTER O WITH HORN AND GRAVE: Ờ
-\def\ohorngrave {\char"1EDD } % LATIN SMALL LETTER O WITH HORN AND GRAVE: ờ
-\def\Ohornhook {\char"1EDE } % LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE: Ở
-\def\ohornhook {\char"1EDF } % LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE: ở
-\def\Ohorntilde {\char"1EE0 } % LATIN CAPITAL LETTER O WITH HORN AND TILDE: Ỡ
-\def\ohorntilde {\char"1EE1 } % LATIN SMALL LETTER O WITH HORN AND TILDE: ỡ
-\def\Ohorndotbelow {\char"1EE2 } % LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW: Ợ
-\def\ohorndotbelow {\char"1EE3 } % LATIN SMALL LETTER O WITH HORN AND DOT BELOW: ợ
-\def\Udotbelow {\char"1EE4 } % LATIN CAPITAL LETTER U WITH DOT BELOW: Ụ
-\def\udotbelow {\char"1EE5 } % LATIN SMALL LETTER U WITH DOT BELOW: ụ
-\def\Uhook {\char"1EE6 } % LATIN CAPITAL LETTER U WITH HOOK ABOVE: Ủ
-\def\uhook {\char"1EE7 } % LATIN SMALL LETTER U WITH HOOK ABOVE: ủ
-\def\Uhornacute {\char"1EE8 } % LATIN CAPITAL LETTER U WITH HORN AND ACUTE: Ứ
-\def\uhornacute {\char"1EE9 } % LATIN SMALL LETTER U WITH HORN AND ACUTE: ứ
-\def\Uhorngrave {\char"1EEA } % LATIN CAPITAL LETTER U WITH HORN AND GRAVE: Ừ
-\def\uhorngrave {\char"1EEB } % LATIN SMALL LETTER U WITH HORN AND GRAVE: ừ
-\def\Uhornhook {\char"1EEC } % LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE: Ử
-\def\uhornhook {\char"1EED } % LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE: ử
-\def\Uhorntilde {\char"1EEE } % LATIN CAPITAL LETTER U WITH HORN AND TILDE: Ữ
-\def\uhorntilde {\char"1EEF } % LATIN SMALL LETTER U WITH HORN AND TILDE: ữ
-\def\Uhorndotbelow {\char"1EF0 } % LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW: Ự
-\def\uhorndotbelow {\char"1EF1 } % LATIN SMALL LETTER U WITH HORN AND DOT BELOW: ự
-\def\Ygrave {\char"1EF2 } % LATIN CAPITAL LETTER Y WITH GRAVE: Ỳ
-\def\ygrave {\char"1EF3 } % LATIN SMALL LETTER Y WITH GRAVE: ỳ
-\def\Ydotbelow {\char"1EF4 } % LATIN CAPITAL LETTER Y WITH DOT BELOW: Ỵ
-\def\ydotbelow {\char"1EF5 } % LATIN SMALL LETTER Y WITH DOT BELOW: ỵ
-\def\Yhook {\char"1EF6 } % LATIN CAPITAL LETTER Y WITH HOOK ABOVE: Ỷ
-\def\yhook {\char"1EF7 } % LATIN SMALL LETTER Y WITH HOOK ABOVE: ỷ
-\def\Ytilde {\char"1EF8 } % LATIN CAPITAL LETTER Y WITH TILDE: Ỹ
-\def\ytilde {\char"1EF9 } % LATIN SMALL LETTER Y WITH TILDE: ỹ
-\def\greekalphapsili {\char"1F00 } % GREEK SMALL LETTER ALPHA WITH PSILI: ἀ
-\def\greekalphadasia {\char"1F01 } % GREEK SMALL LETTER ALPHA WITH DASIA: ἁ
-\def\greekalphapsilivaria {\char"1F02 } % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA: ἂ
-\def\greekalphadasiavaria {\char"1F03 } % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA: ἃ
-\def\greekalphapsilitonos {\char"1F04 } % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA: ἄ
-\def\greekalphadasiatonos {\char"1F05 } % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA: ἅ
-\def\greekalphapsiliperispomeni {\char"1F06 } % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI: ἆ
-\def\greekalphadasiaperispomeni {\char"1F07 } % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI: ἇ
-\def\greekAlphapsili {\char"1F08 } % GREEK CAPITAL LETTER ALPHA WITH PSILI: Ἀ
-\def\greekAlphadasia {\char"1F09 } % GREEK CAPITAL LETTER ALPHA WITH DASIA: Ἁ
-\def\greekAlphapsilivaria {\char"1F0A } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA: Ἂ
-\def\greekAlphadasiavaria {\char"1F0B } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA: Ἃ
-\def\greekAlphapsilitonos {\char"1F0C } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA: Ἄ
-\def\greekAlphadasiatonos {\char"1F0D } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA: Ἅ
-\def\greekAlphapsiliperispomeni {\char"1F0E } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI: Ἆ
-\def\greekAlphadasiaperispomeni {\char"1F0F } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI: Ἇ
-\def\greekepsilonpsili {\char"1F10 } % GREEK SMALL LETTER EPSILON WITH PSILI: ἐ
-\def\greekepsilondasia {\char"1F11 } % GREEK SMALL LETTER EPSILON WITH DASIA: ἑ
-\def\greekepsilonpsilivaria {\char"1F12 } % GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA: ἒ
-\def\greekepsilondasiavaria {\char"1F13 } % GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA: ἓ
-\def\greekepsilonpsilitonos {\char"1F14 } % GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA: ἔ
-\def\greekepsilondasiatonos {\char"1F15 } % GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA: ἕ
-\def\greekEpsilonpsili {\char"1F18 } % GREEK CAPITAL LETTER EPSILON WITH PSILI: Ἐ
-\def\greekEpsilondasia {\char"1F19 } % GREEK CAPITAL LETTER EPSILON WITH DASIA: Ἑ
-\def\greekEpsilonpsilivaria {\char"1F1A } % GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA: Ἒ
-\def\greekEpsilondasiavaria {\char"1F1B } % GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA: Ἓ
-\def\greekEpsilonpsilitonos {\char"1F1C } % GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA: Ἔ
-\def\greekEpsilondasiatonos {\char"1F1D } % GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA: Ἕ
-\def\greeketapsili {\char"1F20 } % GREEK SMALL LETTER ETA WITH PSILI: ἠ
-\def\greeketadasia {\char"1F21 } % GREEK SMALL LETTER ETA WITH DASIA: ἡ
-\def\greeketapsilivaria {\char"1F22 } % GREEK SMALL LETTER ETA WITH PSILI AND VARIA: ἢ
-\def\greeketadasiavaria {\char"1F23 } % GREEK SMALL LETTER ETA WITH DASIA AND VARIA: ἣ
-\def\greeketapsilitonos {\char"1F24 } % GREEK SMALL LETTER ETA WITH PSILI AND OXIA: ἤ
-\def\greeketadasiatonos {\char"1F25 } % GREEK SMALL LETTER ETA WITH DASIA AND OXIA: ἥ
-\def\greeketapsiliperispomeni {\char"1F26 } % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI: ἦ
-\def\greeketadasiaperispomeni {\char"1F27 } % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI: ἧ
-\def\greekEtapsili {\char"1F28 } % GREEK CAPITAL LETTER ETA WITH PSILI: Ἠ
-\def\greekEtadasia {\char"1F29 } % GREEK CAPITAL LETTER ETA WITH DASIA: Ἡ
-\def\greekEtapsilivaria {\char"1F2A } % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA: Ἢ
-\def\greekEtadasiavaria {\char"1F2B } % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA: Ἣ
-\def\greekEtapsilitonos {\char"1F2C } % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA: Ἤ
-\def\greekEtadasiatonos {\char"1F2D } % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA: Ἥ
-\def\greekEtapsiliperispomeni {\char"1F2E } % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI: Ἦ
-\def\greekEtadasiaperispomeni {\char"1F2F } % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI: Ἧ
-\def\greekiotapsili {\char"1F30 } % GREEK SMALL LETTER IOTA WITH PSILI: ἰ
-\def\greekiotadasia {\char"1F31 } % GREEK SMALL LETTER IOTA WITH DASIA: ἱ
-\def\greekiotapsilivaria {\char"1F32 } % GREEK SMALL LETTER IOTA WITH PSILI AND VARIA: ἲ
-\def\greekiotadasiavaria {\char"1F33 } % GREEK SMALL LETTER IOTA WITH DASIA AND VARIA: ἳ
-\def\greekiotapsilitonos {\char"1F34 } % GREEK SMALL LETTER IOTA WITH PSILI AND OXIA: ἴ
-\def\greekiotadasiatonos {\char"1F35 } % GREEK SMALL LETTER IOTA WITH DASIA AND OXIA: ἵ
-\def\greekiotapsiliperispomeni {\char"1F36 } % GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI: ἶ
-\def\greekiotadasiaperispomeni {\char"1F37 } % GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI: ἷ
-\def\greekIotapsili {\char"1F38 } % GREEK CAPITAL LETTER IOTA WITH PSILI: Ἰ
-\def\greekIotadasia {\char"1F39 } % GREEK CAPITAL LETTER IOTA WITH DASIA: Ἱ
-\def\greekIotapsilivaria {\char"1F3A } % GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA: Ἲ
-\def\greekIotadasiavaria {\char"1F3B } % GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA: Ἳ
-\def\greekIotapsilitonos {\char"1F3C } % GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA: Ἴ
-\def\greekIotadasiatonos {\char"1F3D } % GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA: Ἵ
-\def\greekIotapsiliperispomeni {\char"1F3E } % GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI: Ἶ
-\def\greekIotadasiaperispomeni {\char"1F3F } % GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI: Ἷ
-\def\greekomicronpsili {\char"1F40 } % GREEK SMALL LETTER OMICRON WITH PSILI: ὀ
-\def\greekomicrondasia {\char"1F41 } % GREEK SMALL LETTER OMICRON WITH DASIA: ὁ
-\def\greekomicronpsilivaria {\char"1F42 } % GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA: ὂ
-\def\greekomicrondasiavaria {\char"1F43 } % GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA: ὃ
-\def\greekomicronpsilitonos {\char"1F44 } % GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA: ὄ
-\def\greekomicrondasiatonos {\char"1F45 } % GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA: ὅ
-\def\greekOmicronpsili {\char"1F48 } % GREEK CAPITAL LETTER OMICRON WITH PSILI: Ὀ
-\def\greekOmicrondasia {\char"1F49 } % GREEK CAPITAL LETTER OMICRON WITH DASIA: Ὁ
-\def\greekOmicronpsilivaria {\char"1F4A } % GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA: Ὂ
-\def\greekOmicrondasiavaria {\char"1F4B } % GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA: Ὃ
-\def\greekOmicronpsilitonos {\char"1F4C } % GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA: Ὄ
-\def\greekOmicrondasiatonos {\char"1F4D } % GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA: Ὅ
-\def\greekupsilonpsili {\char"1F50 } % GREEK SMALL LETTER UPSILON WITH PSILI: ὐ
-\def\greekupsilondasia {\char"1F51 } % GREEK SMALL LETTER UPSILON WITH DASIA: ὑ
-\def\greekupsilonpsilivaria {\char"1F52 } % GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA: ὒ
-\def\greekupsilondasiavaria {\char"1F53 } % GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA: ὓ
-\def\greekupsilonpsilitonos {\char"1F54 } % GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA: ὔ
-\def\greekupsilondasiatonos {\char"1F55 } % GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA: ὕ
-\def\greekupsilonpsiliperispomeni {\char"1F56 } % GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI: ὖ
-\def\greekupsilondasiaperispomeni {\char"1F57 } % GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI: ὗ
-\def\greekUpsilondasia {\char"1F59 } % GREEK CAPITAL LETTER UPSILON WITH DASIA: Ὑ
-\def\greekUpsilondasiavaria {\char"1F5B } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA: Ὓ
-\def\greekUpsilondasiatonos {\char"1F5D } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA: Ὕ
-\def\greekUpsilondasiaperispomeni {\char"1F5F } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI: Ὗ
-\def\greekomegapsili {\char"1F60 } % GREEK SMALL LETTER OMEGA WITH PSILI: ὠ
-\def\greekomegadasia {\char"1F61 } % GREEK SMALL LETTER OMEGA WITH DASIA: ὡ
-\def\greekomegapsilivaria {\char"1F62 } % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA: ὢ
-\def\greekomegadasiavaria {\char"1F63 } % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA: ὣ
-\def\greekomegapsilitonos {\char"1F64 } % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA: ὤ
-\def\greekomegadasiatonos {\char"1F65 } % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA: ὥ
-\def\greekomegapsiliperispomeni {\char"1F66 } % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI: ὦ
-\def\greekomegadasiaperispomeni {\char"1F67 } % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI: ὧ
-\def\greekOmegapsili {\char"1F68 } % GREEK CAPITAL LETTER OMEGA WITH PSILI: Ὠ
-\def\greekOmegadasia {\char"1F69 } % GREEK CAPITAL LETTER OMEGA WITH DASIA: Ὡ
-\def\greekOmegapsilivaria {\char"1F6A } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA: Ὢ
-\def\greekOmegadasiavaria {\char"1F6B } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA: Ὣ
-\def\greekOmegapsilitonos {\char"1F6C } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA: Ὤ
-\def\greekOmegadasiatonos {\char"1F6D } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA: Ὥ
-\def\greekOmegapsiliperispomeni {\char"1F6E } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI: Ὦ
-\def\greekOmegadasiaperispomeni {\char"1F6F } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI: Ὧ
-\def\greekalphavaria {\char"1F70 } % GREEK SMALL LETTER ALPHA WITH VARIA: ὰ
-\def\greekalphaoxia {\char"1F71 } % GREEK SMALL LETTER ALPHA WITH OXIA: ά
-\def\greekepsilonvaria {\char"1F72 } % GREEK SMALL LETTER EPSILON WITH VARIA: ὲ
-\def\greekepsilonoxia {\char"1F73 } % GREEK SMALL LETTER EPSILON WITH OXIA: έ
-\def\greeketavaria {\char"1F74 } % GREEK SMALL LETTER ETA WITH VARIA: ὴ
-\def\greeketaoxia {\char"1F75 } % GREEK SMALL LETTER ETA WITH OXIA: ή
-\def\greekiotavaria {\char"1F76 } % GREEK SMALL LETTER IOTA WITH VARIA: ὶ
-\def\greekiotaoxia {\char"1F77 } % GREEK SMALL LETTER IOTA WITH OXIA: ί
-\def\greekomicronvaria {\char"1F78 } % GREEK SMALL LETTER OMICRON WITH VARIA: ὸ
-\def\greekomicronoxia {\char"1F79 } % GREEK SMALL LETTER OMICRON WITH OXIA: ό
-\def\greekupsilonvaria {\char"1F7A } % GREEK SMALL LETTER UPSILON WITH VARIA: ὺ
-\def\greekupsilonoxia {\char"1F7B } % GREEK SMALL LETTER UPSILON WITH OXIA: ύ
-\def\greekomegavaria {\char"1F7C } % GREEK SMALL LETTER OMEGA WITH VARIA: ὼ
-\def\greekomegaoxia {\char"1F7D } % GREEK SMALL LETTER OMEGA WITH OXIA: ώ
-\def\greekalphaiotasubpsili {\char"1F80 } % GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI: ᾀ
-\def\greekalphaiotasubdasia {\char"1F81 } % GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI: ᾁ
-\def\greekalphaiotasubpsilivaria {\char"1F82 } % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾂ
-\def\greekalphaiotasubdasiavaria {\char"1F83 } % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾃ
-\def\greekalphaiotasubpsilitonos {\char"1F84 } % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾄ
-\def\greekalphaiotasubdasiatonos {\char"1F85 } % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾅ
-\def\greekalphaiotasubpsiliperispomeni{\char"1F86 } % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾆ
-\def\greekalphaiotasubdasiaperispomeni{\char"1F87 } % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾇ
-\def\greekAlphaiotasubpsili {\char"1F88 } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI: ᾈ
-\def\greekAlphaiotasubdasia {\char"1F89 } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI: ᾉ
-\def\greekAlphaiotasubpsilivaria {\char"1F8A } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾊ
-\def\greekAlphaiotasubdasiavaria {\char"1F8B } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾋ
-\def\greekAlphaiotasubpsilitonos {\char"1F8C } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾌ
-\def\greekAlphaiotasubdasiatonos {\char"1F8D } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾍ
-\def\greekAlphaiotasubpsiliperispomeni{\char"1F8E } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾎ
-\def\greekAlphaiotasubdasiaperispomeni{\char"1F8F } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾏ
-\def\greeketaiotasubpsili {\char"1F90 } % GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI: ᾐ
-\def\greeketaiotasubdasia {\char"1F91 } % GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI: ᾑ
-\def\greeketaiotasubpsilivaria {\char"1F92 } % GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾒ
-\def\greeketaiotasubdasiavaria {\char"1F93 } % GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾓ
-\def\greeketaiotasubpsilitonos {\char"1F94 } % GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾔ
-\def\greeketaiotasubdasiatonos {\char"1F95 } % GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾕ
-\def\greeketaiotasubpsiliperispomeni {\char"1F96 } % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾖ
-\def\greeketaiotasubdasiaperispomeni {\char"1F97 } % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾗ
-\def\greekEtaiotasubpsili {\char"1F98 } % GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI: ᾘ
-\def\greekEtaiotasubdasia {\char"1F99 } % GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI: ᾙ
-\def\greekEtaiotasubpsilivaria {\char"1F9A } % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾚ
-\def\greekEtaiotasubdasiavaria {\char"1F9B } % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾛ
-\def\greekEtaiotasubpsilitonos {\char"1F9C } % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾜ
-\def\greekEtaiotasubdasiatonos {\char"1F9D } % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾝ
-\def\greekEtaiotasubpsiliperispomeni {\char"1F9E } % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾞ
-\def\greekEtaiotasubdasiaperispomeni {\char"1F9F } % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾟ
-\def\greekomegaiotasubpsili {\char"1FA0 } % GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI: ᾠ
-\def\greekomegaiotasubdasia {\char"1FA1 } % GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI: ᾡ
-\def\greekomegaiotasubpsilivaria {\char"1FA2 } % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾢ
-\def\greekomegaiotasubdasiavaria {\char"1FA3 } % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾣ
-\def\greekomegaiotasubpsilitonos {\char"1FA4 } % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾤ
-\def\greekomegaiotasubdasiatonos {\char"1FA5 } % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾥ
-\def\greekomegaiotasubpsiliperispomeni{\char"1FA6 } % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾦ
-\def\greekomegaiotasubdasiaperispomeni{\char"1FA7 } % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾧ
-\def\greekOmegaiotasubpsili {\char"1FA8 } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI: ᾨ
-\def\greekOmegaiotasubdasia {\char"1FA9 } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI: ᾩ
-\def\greekOmegaiotasubpsilivaria {\char"1FAA } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾪ
-\def\greekOmegaiotasubdasiavaria {\char"1FAB } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾫ
-\def\greekOmegaiotasubpsilitonos {\char"1FAC } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾬ
-\def\greekOmegaiotasubdasiatonos {\char"1FAD } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾭ
-\def\greekOmegaiotasubpsiliperispomeni{\char"1FAE } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾮ
-\def\greekOmegaiotasubdasiaperispomeni{\char"1FAF } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾯ
-\def\greekalphavrachy {\char"1FB0 } % GREEK SMALL LETTER ALPHA WITH VRACHY: ᾰ
-\def\greekalphamacron {\char"1FB1 } % GREEK SMALL LETTER ALPHA WITH MACRON: ᾱ
-\def\greekalphaiotasubvaria {\char"1FB2 } % GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI: ᾲ
-\def\greekalphaiotasub {\char"1FB3 } % GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI: ᾳ
-\def\greekalphaiotasubtonos {\char"1FB4 } % GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI: ᾴ
-\def\greekalphaperispomeni {\char"1FB6 } % GREEK SMALL LETTER ALPHA WITH PERISPOMENI: ᾶ
-\def\greekalphaiotasubperispomeni {\char"1FB7 } % GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI: ᾷ
-\def\greekAlphavrachy {\char"1FB8 } % GREEK CAPITAL LETTER ALPHA WITH VRACHY: Ᾰ
-\def\greekAlphamacron {\char"1FB9 } % GREEK CAPITAL LETTER ALPHA WITH MACRON: Ᾱ
-\def\greekAlphavaria {\char"1FBA } % GREEK CAPITAL LETTER ALPHA WITH VARIA: Ὰ
-\def\greekAlphatonos {\char"1FBB } % GREEK CAPITAL LETTER ALPHA WITH OXIA: Ά
-\def\greekAlphaiotasub {\char"1FBC } % GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI: ᾼ
-\def\greekCoronis {\char"1FBD } % GREEK KORONIS: ᾽
-\def\greekprosgegrammeni {\char"1FBE } % GREEK PROSGEGRAMMENI: ι
-\def\greekpsili {\char"1FBF } % GREEK PSILI: ᾿
-\def\greekperispomeni {\char"1FC0 } % GREEK PERISPOMENI: ῀
-\def\greekdialytikaperispomeni {\char"1FC1 } % GREEK DIALYTIKA AND PERISPOMENI: ῁
-\def\greeketaiotasubvaria {\char"1FC2 } % GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI: ῂ
-\def\greeketaiotasub {\char"1FC3 } % GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI: ῃ
-\def\greeketaiotasubtonos {\char"1FC4 } % GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI: ῄ
-\def\greeketaperispomeni {\char"1FC6 } % GREEK SMALL LETTER ETA WITH PERISPOMENI: ῆ
-\def\greeketaiotasubperispomeni {\char"1FC7 } % GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI: ῇ
-\def\greekEpsilonvaria {\char"1FC8 } % GREEK CAPITAL LETTER EPSILON WITH VARIA: Ὲ
-\def\greekEpsilontonos {\char"1FC9 } % GREEK CAPITAL LETTER EPSILON WITH OXIA: Έ
-\def\greekEtavaria {\char"1FCA } % GREEK CAPITAL LETTER ETA WITH VARIA: Ὴ
-\def\greekEtatonos {\char"1FCB } % GREEK CAPITAL LETTER ETA WITH OXIA: Ή
-\def\greekEtaiotasub {\char"1FCC } % GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI: ῌ
-\def\greekpsilivaria {\char"1FCD } % GREEK PSILI AND VARIA: ῍
-\def\greekpsilitonos {\char"1FCE } % GREEK PSILI AND OXIA: ῎
-\def\greekpsiliperispomeni {\char"1FCF } % GREEK PSILI AND PERISPOMENI: ῏
-\def\greekiotavrachy {\char"1FD0 } % GREEK SMALL LETTER IOTA WITH VRACHY: ῐ
-\def\greekiotamacron {\char"1FD1 } % GREEK SMALL LETTER IOTA WITH MACRON: ῑ
-\def\greekiotadialytikavaria {\char"1FD2 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA: ῒ
-\def\greekiotadialytikatonos {\char"1FD3 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA: ΐ
-\def\greekiotaperispomeni {\char"1FD6 } % GREEK SMALL LETTER IOTA WITH PERISPOMENI: ῖ
-\def\greekiotadialytikaperispomeni {\char"1FD7 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI: ῗ
-\def\greekIotavrachy {\char"1FD8 } % GREEK CAPITAL LETTER IOTA WITH VRACHY: Ῐ
-\def\greekIotamacron {\char"1FD9 } % GREEK CAPITAL LETTER IOTA WITH MACRON: Ῑ
-\def\greekIotavaria {\char"1FDA } % GREEK CAPITAL LETTER IOTA WITH VARIA: Ὶ
-\def\greekIotatonos {\char"1FDB } % GREEK CAPITAL LETTER IOTA WITH OXIA: Ί
-\def\greekdasiavaria {\char"1FDD } % GREEK DASIA AND VARIA: ῝
-\def\greekdasiatonos {\char"1FDE } % GREEK DASIA AND OXIA: ῞
-\def\greekdasiaperispomeni {\char"1FDF } % GREEK DASIA AND PERISPOMENI: ῟
-\def\greekupsilonvrachy {\char"1FE0 } % GREEK SMALL LETTER UPSILON WITH VRACHY: ῠ
-\def\greekupsilonmacron {\char"1FE1 } % GREEK SMALL LETTER UPSILON WITH MACRON: ῡ
-\def\greekupsilondialytikavaria {\char"1FE2 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA: ῢ
-\def\greekupsilondialytikatonos {\char"1FE3 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA: ΰ
-\def\greekrhopsili {\char"1FE4 } % GREEK SMALL LETTER RHO WITH PSILI: ῤ
-\def\greekrhodasia {\char"1FE5 } % GREEK SMALL LETTER RHO WITH DASIA: ῥ
-\def\greekupsilonperispomeni {\char"1FE6 } % GREEK SMALL LETTER UPSILON WITH PERISPOMENI: ῦ
-\def\greekupsilondialytikaperispomeni {\char"1FE7 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI: ῧ
-\def\greekUpsilonvrachy {\char"1FE8 } % GREEK CAPITAL LETTER UPSILON WITH VRACHY: Ῠ
-\def\greekUpsilonmacron {\char"1FE9 } % GREEK CAPITAL LETTER UPSILON WITH MACRON: Ῡ
-\def\greekUpsilonvaria {\char"1FEA } % GREEK CAPITAL LETTER UPSILON WITH VARIA: Ὺ
-\def\greekUpsilontonos {\char"1FEB } % GREEK CAPITAL LETTER UPSILON WITH OXIA: Ύ
-\def\greekRhodasia {\char"1FEC } % GREEK CAPITAL LETTER RHO WITH DASIA: Ῥ
-\def\greekdialytikavaria {\char"1FED } % GREEK DIALYTIKA AND VARIA: ῭
-\def\greekdialytikatonos {\char"1FEE } % GREEK DIALYTIKA AND OXIA: ΅
-\def\greekvaria {\char"1FEF } % GREEK VARIA: `
-\def\greekomegaiotasubvaria {\char"1FF2 } % GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI: ῲ
-\def\greekomegaiotasub {\char"1FF3 } % GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI: ῳ
-\def\greekomegaiotasubtonos {\char"1FF4 } % GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI: ῴ
-\def\greekomegaperispomeni {\char"1FF6 } % GREEK SMALL LETTER OMEGA WITH PERISPOMENI: ῶ
-\def\greekomegaiotasubperispomeni {\char"1FF7 } % GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI: ῷ
-\def\greekOmicronvaria {\char"1FF8 } % GREEK CAPITAL LETTER OMICRON WITH VARIA: Ὸ
-\def\greekOmicrontonos {\char"1FF9 } % GREEK CAPITAL LETTER OMICRON WITH OXIA: Ό
-\def\greekOmegavaria {\char"1FFA } % GREEK CAPITAL LETTER OMEGA WITH VARIA: Ὼ
-\def\greekOmegatonos {\char"1FFB } % GREEK CAPITAL LETTER OMEGA WITH OXIA: Ώ
-\def\greekOmegaiotasub {\char"1FFC } % GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI: ῼ
-\def\greekoxia {\char"1FFD } % GREEK OXIA: ´
-\def\greekdasia {\char"1FFE } % GREEK DASIA: ῾
-\def\enspace {\char"2002 } % EN SPACE:  
-\def\emspace {\char"2003 } % EM SPACE:  
-\def\thinspace {\char"2009 } % THIN SPACE:  
-\def\hairspace {\char"200A } % HAIR SPACE:  
-\def\textminus {\char"2012 } % FIGURE DASH: ‒
-\def\endash {\char"2013 } % EN DASH: –
-\def\emdash {\char"2014 } % EM DASH: —
-\def\texthorizontalbar {\char"2015 } % HORIZONTAL BAR: ―
-\def\quoteleft {\char"2018 } % LEFT SINGLE QUOTATION MARK: ‘
-\def\quoteright {\char"2019 } % RIGHT SINGLE QUOTATION MARK: ’
-\def\quotesinglebase {\char"201A } % SINGLE LOW-0x0009 QUOTATION MARK: ‚
-\def\quotedblleft {\char"201C } % LEFT DOUBLE QUOTATION MARK: “
-\def\quotedblright {\char"201D } % RIGHT DOUBLE QUOTATION MARK: ”
-\def\quotedblbase {\char"201E } % DOUBLE LOW-0x0009 QUOTATION MARK: „
-\def\textdag {\char"2020 } % DAGGER: †
-\def\textddag {\char"2021 } % DOUBLE DAGGER: ‡
-\def\textbullet {\char"2022 } % BULLET: •
-\def\textellipsis {\char"2026 } % HORIZONTAL ELLIPSIS: …
-\def\perthousand {\char"2030 } % PER MILLE SIGN: ‰
-\def\guilsingleleft {\char"2039 } % SINGLE LEFT-POINTING ANGLE QUOTATION MARK: ‹
-\def\guilsingleright {\char"203A } % SINGLE RIGHT-POINTING ANGLE QUOTATION MARK: ›
-\def\textdong {\char"20AB } % DONG SIGN: ₫
-\def\texteuro {\char"20AC } % EURO SIGN: €
-\def\textnumero {\char"2116 } % NUMERO SIGN: №
-\def\trademark {\char"2122 } % TRADE MARK SIGN: ™
-\def\onethird {\char"2153 } % VULGAR FRACTION ONE THIRD: ⅓
-\def\twothirds {\char"2154 } % VULGAR FRACTION TWO THIRDS: ⅔
-\def\onefifth {\char"2155 } % VULGAR FRACTION ONE FIFTH: ⅕
-\def\twofifths {\char"2156 } % VULGAR FRACTION TWO FIFTHS: ⅖
-\def\threefifths {\char"2157 } % VULGAR FRACTION THREE FIFTHS: ⅗
-\def\fourfifths {\char"2158 } % VULGAR FRACTION FOUR FIFTHS: ⅘
-\def\onesixth {\char"2159 } % VULGAR FRACTION ONE SIXTH: ⅙
-\def\fivesixths {\char"215A } % VULGAR FRACTION FIVE SIXTHS: ⅚
-\def\oneeighth {\char"215B } % VULGAR FRACTION ONE EIGHTH: ⅛
-\def\threeeighths {\char"215C } % VULGAR FRACTION THREE EIGHTHS: ⅜
-\def\fiveeighths {\char"215D } % VULGAR FRACTION FIVE EIGHTHS: ⅝
-\def\seveneighths {\char"215E } % VULGAR FRACTION SEVEN EIGHTHS: ⅞
-\def\romanI {\char"2160 } % ROMAN NUMERAL ONE: Ⅰ
-\def\romanII {\char"2161 } % ROMAN NUMERAL TWO: Ⅱ
-\def\romanIII {\char"2162 } % ROMAN NUMERAL THREE: Ⅲ
-\def\romanIV {\char"2163 } % ROMAN NUMERAL FOUR: Ⅳ
-\def\romanV {\char"2164 } % ROMAN NUMERAL FIVE: Ⅴ
-\def\romanVI {\char"2165 } % ROMAN NUMERAL SIX: Ⅵ
-\def\romanVII {\char"2166 } % ROMAN NUMERAL SEVEN: Ⅶ
-\def\romanVIII {\char"2167 } % ROMAN NUMERAL EIGHT: Ⅷ
-\def\romanIX {\char"2168 } % ROMAN NUMERAL NINE: Ⅸ
-\def\romanX {\char"2169 } % ROMAN NUMERAL TEN: Ⅹ
-\def\romanXI {\char"216A } % ROMAN NUMERAL ELEVEN: Ⅺ
-\def\romanXII {\char"216B } % ROMAN NUMERAL TWELVE: Ⅻ
-\def\romanL {\char"216C } % ROMAN NUMERAL FIFTY: Ⅼ
-\def\romanC {\char"216D } % ROMAN NUMERAL ONE HUNDRED: Ⅽ
-\def\romanD {\char"216E } % ROMAN NUMERAL FIVE HUNDRED: Ⅾ
-\def\romanM {\char"216F } % ROMAN NUMERAL ONE THOUSAND: Ⅿ
-\def\romani {\char"2170 } % SMALL ROMAN NUMERAL ONE: ⅰ
-\def\romanii {\char"2171 } % SMALL ROMAN NUMERAL TWO: ⅱ
-\def\romaniii {\char"2172 } % SMALL ROMAN NUMERAL THREE: ⅲ
-\def\romaniv {\char"2173 } % SMALL ROMAN NUMERAL FOUR: ⅳ
-\def\romanv {\char"2174 } % SMALL ROMAN NUMERAL FIVE: ⅴ
-\def\romanvi {\char"2175 } % SMALL ROMAN NUMERAL SIX: ⅵ
-\def\romanvii {\char"2176 } % SMALL ROMAN NUMERAL SEVEN: ⅶ
-\def\romanviii {\char"2177 } % SMALL ROMAN NUMERAL EIGHT: ⅷ
-\def\romanix {\char"2178 } % SMALL ROMAN NUMERAL NINE: ⅸ
-\def\romanx {\char"2179 } % SMALL ROMAN NUMERAL TEN: ⅹ
-\def\romanxi {\char"217A } % SMALL ROMAN NUMERAL ELEVEN: ⅺ
-\def\romanxii {\char"217B } % SMALL ROMAN NUMERAL TWELVE: ⅻ
-\def\romanl {\char"217C } % SMALL ROMAN NUMERAL FIFTY: ⅼ
-\def\romanc {\char"217D } % SMALL ROMAN NUMERAL ONE HUNDRED: ⅽ
-\def\romand {\char"217E } % SMALL ROMAN NUMERAL FIVE HUNDRED: ⅾ
-\def\romanm {\char"217F } % SMALL ROMAN NUMERAL ONE THOUSAND: ⅿ
-\def\ffligature {\char"FB00 } % LATIN SMALL LIGATURE FF: ff
-\def\filigature {\char"FB01 } % LATIN SMALL LIGATURE FI: fi
-\def\flligature {\char"FB02 } % LATIN SMALL LIGATURE FL: fl
-\def\ffiligature {\char"FB03 } % LATIN SMALL LIGATURE FFI: ffi
-\def\fflligature {\char"FB04 } % LATIN SMALL LIGATURE FFL: ffl
-\def\stligature {\char"FB06 } % LATIN SMALL LIGATURE ST: st
-
-\endinput
diff --git a/tex/context/base/enco-x5.tex b/tex/context/base/enco-x5.tex
index 32a7399ca..f82ec6c5c 100644
--- a/tex/context/base/enco-x5.tex
+++ b/tex/context/base/enco-x5.tex
@@ -8,12 +8,12 @@
%D copyright=Hans Hagen]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-%D This module is derived from the some files Han The Thanh
-%D prepared for \LATEX. The dual accent support is still
-%D preliminary, but works ok.
+%D This module is derived from the some files Han The Thanh
+%D prepared for \LATEX. The dual accent support is still
+%D preliminary, but works ok.
\startencoding[x5]
@@ -28,8 +28,8 @@
\definecharacter textbreve 8
\definecharacter textmacron 9
\definecharacter textdotaccent 10
-\definecharacter textcedilla 11
-\definecharacter textogonek 12
+\definecharacter textcedilla 11
+\definecharacter textogonek 12
\definecharacter dotlessi 25
\definecharacter DJ 30
@@ -168,24 +168,24 @@
\defineaccent h y 27
\defineaccent d y 29
-\stopencoding
+\stopencoding
-\endinput
+\endinput
% \startencoding [x5]
-%
+%
% \definecharacter aa {\xfiveencodedaa}
% \definecharacter AA {\xfiveencodedAA}
-%
-% \stopencoding
-%
+%
+% \stopencoding
+%
% \def\xfiveencodedaa%
% {\accent23a}
%
% \def\xfiveencodedAA%
% {\leavevmode
-% \setbox\z@\hbox{h}%
-% \dimen@\ht\z@
+% \setbox\zerocount\hbox{h}%
+% \dimen@\ht\zerocount
% \advance\dimen@ -1ex
% \rlap{\raise.67\dimen@\hbox{\char23}}A}
@@ -200,8 +200,8 @@
% \textendash 21
% \textemdash 22
% \textcompwordmark 23
-% \textperthousand \% \char 24
-% \textpertenthousand \%\char 24\char 24
+% \textperthousand \% \char 24
+% \textpertenthousand \%\char 24\char 24
% \textvisiblespace 32
% \textquotedbl `\"
% \textdollar `\$
diff --git a/tex/context/base/filt-ini.tex b/tex/context/base/filt-ini.tex
index 98c885467..49b32bdd8 100644
--- a/tex/context/base/filt-ini.tex
+++ b/tex/context/base/filt-ini.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Filter Macros (ini)}
+\writestatus{loading}{ConTeXt Filter Macros / Initialization}
% \ifx\OmegaVersion\undefined
@@ -28,41 +28,17 @@
%D The real work starts here.
-\startmessages dutch library: filters
- title: filter
- 1: filter -- wordt geladen
- 2: onbekend filter --
-\stopmessages
-
-\startmessages english library: filters
- title: filter
- 1: filter -- is loaded
- 2: unknown filter --
-\stopmessages
-
-\startmessages german library: filters
- title: filter
- 1: filter -- ist geladen
- 2: unknown filter --
-\stopmessages
-
-\startmessages czech library: filters
- title: filter
- 1: filter -- is loaded
- 2: unknown filter --
-\stopmessages
-
-\startmessages italian library: filters
- title: filtri
- 1: filtro -- caricato
- 2: filtro sconosciuto --
-\stopmessages
-
-\startmessages french library: filters
- title: filtre
- 1: le filtre -- est chargé
- 2: filtre -- inconnu
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
% We need the {\??ot::#1} check because otherwise aleph will crash. Taco's
% torture test:
@@ -108,12 +84,6 @@
\def\magicocpnumber{1}
-% \def\dodousefiltersequence#1%
-% {\expandafter\ocp\csname\??or:#1\endcsname=\truefiltername{#1}\relax
-% \@EA \appendtoks
-% \@EA \addbeforeocplist \@EA \magicocpnumber \csname\??or:#1\endcsname
-% \to \scratchtoks}
-
% one can do:
%
% \definefiltersequence
@@ -135,14 +105,6 @@
\expandafter\noexpand\csname\??or:\!!stringa\endcsname
\to \scratchtoks}
-% \unexpanded\def\usefiltersequence[#1]%
-% {\edef\currentfiltersequence{\getvalue{\??ot#1}}%
-% \scratchtoks\emptytoks
-% \processcommacommand[\currentfiltersequence]\dodousefiltersequence
-% % \showthe\scratchtoks
-% \expanded{\ocplist\csname\??ot:#1\endcsname=\the\scratchtoks}\nullocplist
-% \expanded{\pushocplist\csname\??ot:#1\endcsname}\relax}
-
\unexpanded\def\usefiltersequence[#1]%
{\doifdefined{\??ot::#1}%
{\doifvalue{\??ot::#1}\v!stop
diff --git a/tex/context/base/font-afm.lua b/tex/context/base/font-afm.lua
index eef80c597..6cc227588 100644
--- a/tex/context/base/font-afm.lua
+++ b/tex/context/base/font-afm.lua
@@ -17,7 +17,11 @@ where we handles font encodings. Eventually font encoding goes
away.</p>
--ldx]]--
-local format = string.format
+local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
+local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
+local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end)
+
+local format, match, gmatch, lower = string.format, string.match, string.gmatch, string.lower
fonts = fonts or { }
fonts.afm = fonts.afm or { }
@@ -25,10 +29,9 @@ fonts.afm = fonts.afm or { }
local afm = fonts.afm
local tfm = fonts.tfm
-afm.version = 1.30 -- incrementing this number one up will force a re-cache
-afm.syncspace = true -- when true, nicer stretch values
-afm.enhance_data = true -- best leave this set to true
-afm.trace_features = false
+afm.version = 1.400 -- incrementing this number one up will force a re-cache
+afm.syncspace = true -- when true, nicer stretch values
+afm.enhance_data = true -- best leave this set to true
afm.features = { }
afm.features.aux = { }
afm.features.data = { }
@@ -93,25 +96,25 @@ end
local keys = { }
-function keys.FontName (data,line) data.fullname = line:strip() end
-function keys.ItalicAngle (data,line) data.italicangle = tonumber (line) end
-function keys.IsFixedPitch(data,line) data.isfixedpitch = toboolean(line,true) end
-function keys.CharWidth (data,line) data.charwidth = tonumber (line) end
-function keys.XHeight (data,line) data.xheight = tonumber (line) end
-function keys.Descender (data,line) data.descender = tonumber (line) end
-function keys.Ascender (data,line) data.ascender = tonumber (line) end
+function keys.FontName (data,line) data.metadata.fullname = line:strip() end
+function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end
+function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end
+function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end
+function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end
+function keys.Descender (data,line) data.metadata.descender = tonumber (line) end
+function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end
function keys.Comment (data,line)
-- Comment DesignSize 12 (pts)
-- Comment TFM designsize: 12 (in points)
- line = line:lower()
- local designsize = line:match("designsize[^%d]*(%d+)")
- if designsize then data.designsize = tonumber(designsize) end
+ line = lower(line)
+ local designsize = match(line,"designsize[^%d]*(%d+)")
+ if designsize then data.metadata.designsize = tonumber(designsize) end
end
local function get_charmetrics(data,charmetrics,vector)
local characters = data.characters
local chr, str, ind = { }, "", 0
- for k,v in charmetrics:gmatch("([%a]+) +(.-) *;") do
+ for k,v in gmatch(charmetrics,"([%a]+) +(.-) *;") do
if k == 'C' then
if str ~= "" then characters[str] = chr end
chr = { }
@@ -128,10 +131,10 @@ local function get_charmetrics(data,charmetrics,vector)
elseif k == 'N' then
str = v
elseif k == 'B' then
- local llx, lly, urx, ury = v:match("^ *(.-) +(.-) +(.-) +(.-)$")
+ local llx, lly, urx, ury = match(v,"^ *(.-) +(.-) +(.-) +(.-)$")
chr.boundingbox = { tonumber(llx), tonumber(lly), tonumber(urx), tonumber(ury) }
elseif k == 'L' then
- local plus, becomes = v:match("^(.-) +(.-)$")
+ local plus, becomes = match(v,"^(.-) +(.-)$")
if not chr.ligatures then chr.ligatures = { } end
chr.ligatures[plus] = becomes
end
@@ -143,7 +146,7 @@ end
local function get_kernpairs(data,kernpairs)
local characters = data.characters
- for one, two, value in kernpairs:gmatch("KPX +(.-) +(.-) +(.-)\n") do
+ for one, two, value in gmatch(kernpairs,"KPX +(.-) +(.-) +(.-)\n") do
local chr = characters[one]
if chr then
if not chr.kerns then chr.kerns = { } end
@@ -153,83 +156,85 @@ local function get_kernpairs(data,kernpairs)
end
local function get_variables(data,fontmetrics)
- for key, rest in fontmetrics:gmatch("(%a+) *(.-)[\n\r]") do
+ for key, rest in gmatch(fontmetrics,"(%a+) *(.-)[\n\r]") do
if keys[key] then keys[key](data,rest) end
end
end
local function get_indexes(data,filename)
- local trace = fonts.trace
- local pfbname = input.find_file(file.removesuffix(filename)..".pfb","pfb") or ""
+ local pfbfile = file.replacesuffix(filename,"pfb")
+ local pfbname = resolvers.find_file(pfbfile,"pfb") or ""
if pfbname == "" then
- pfbname = input.find_file(file.removesuffix(file.basename(filename))..".pfb","pfb") or ""
+ pfbname = resolvers.find_file(file.basename(pfbfile),"pfb") or ""
end
if pfbname ~= "" then
- data.luatex = data.luatex or { }
data.luatex.filename = pfbname
- local pfbblob = fontforge.open(pfbname)
+ local pfbblob = fontloader.open(pfbname)
if pfbblob then
local characters = data.characters
- local pfbdata = fontforge.to_table(pfbblob)
+ local pfbdata = fontloader.to_table(pfbblob)
--~ print(table.serialize(pfbdata))
if pfbdata then
local glyphs = pfbdata.glyphs
if glyphs then
- if trace then
+ if trace_loading then
logs.report("load afm","getting index data from %s",pfbname)
end
-- local offset = (glyphs[0] and glyphs[0] != .notdef) or 0
- for index, glyph in pairs(glyphs) do
+ for index, glyph in next, glyphs do
local name = glyph.name
if name then
local char = characters[name]
if char then
- if trace then
+ if trace_indexing then
logs.report("load afm","glyph %s has index %s",name,index)
end
char.index = index
end
end
end
- elseif trace then
+ elseif trace_loading then
logs.report("load afm","no glyph data in pfb file %s",pfbname)
end
- elseif trace then
+ elseif trace_loading then
logs.report("load afm","no data in pfb file %s",pfbname)
end
- elseif trace then
+ fontloader.close(pfbblob)
+ elseif trace_loading then
logs.report("load afm","invalid pfb file %s",pfbname)
end
- elseif trace then
+ elseif trace_loading then
logs.report("load afm","no pfb file for %s",filename)
end
end
function afm.read_afm(filename)
- local ok, afmblob, size = input.loadbinfile(filename) -- has logging
+ local ok, afmblob, size = resolvers.loadbinfile(filename) -- has logging
-- local ok, afmblob = true, file.readdata(filename)
if ok and afmblob then
local data = {
- version = version or '0',
characters = { },
- filename = file.removesuffix(file.basename(filename))
+ metadata = {
+ version = version or '0', -- hm
+ filename = file.removesuffix(file.basename(filename))
+ }
}
afmblob = afmblob:gsub("StartCharMetrics(.-)EndCharMetrics", function(charmetrics)
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","loading char metrics")
end
get_charmetrics(data,charmetrics,vector)
return ""
end)
afmblob = afmblob:gsub("StartKernPairs(.-)EndKernPairs", function(kernpairs)
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","loading kern pairs")
end
get_kernpairs(data,kernpairs)
return ""
end)
afmblob = afmblob:gsub("StartFontMetrics%s+([%d%.]+)(.-)EndFontMetrics", function(version,fontmetrics)
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","loading variables")
end
data.afmversion = version
@@ -237,10 +242,11 @@ function afm.read_afm(filename)
data.fontdimens = scan_comment(fontmetrics) -- todo: all lpeg, no time now
return ""
end)
+ data.luatex = { }
get_indexes(data,filename)
return data
else
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","no valid afm file %s",filename)
end
return nil
@@ -254,50 +260,53 @@ way we can set them faster when defining a font.</p>
--ldx]]--
function afm.load(filename)
- local name = file.removesuffix(filename)
- local data = containers.read(afm.cache(),name)
- if data and data.verbose ~= fonts.verbose then
- data = nil
- end
- local size = lfs.attributes(name,"size") or 0
- if data and data.size ~= size then
- data = nil
- end
- if not data then
- local foundname = input.find_file(filename,'afm')
- if foundname and foundname ~= "" then
- data = afm.read_afm(foundname)
+ -- hm, for some reasons not resolved yet
+ filename = resolvers.find_file(filename,'afm') or ""
+ if filename ~= "" then
+ local name = file.removesuffix(file.basename(filename))
+ local data = containers.read(afm.cache(),name)
+ local size = lfs.attributes(filename,"size") or 0
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
+ logs.report("load afm", "reading %s",filename)
+ data = afm.read_afm(filename)
if data then
+ -- data.luatex = data.luatex or { }
+ logs.report("load afm", "unifying %s",filename)
afm.unify(data,filename)
if afm.enhance_data then
+ logs.report("load afm", "add ligatures")
afm.add_ligatures(data,'ligatures') -- easier this way
+ logs.report("load afm", "add tex-ligatures")
afm.add_ligatures(data,'texligatures') -- easier this way
+ logs.report("load afm", "add extra kerns")
afm.add_kerns(data) -- faster this way
end
- logs.report("load afm","file size: %s",size)
data.size = size
data.verbose = fonts.verbose
- logs.report("load afm","saving: in cache")
+ logs.report("load afm","saving: %s in cache",name)
data = containers.write(afm.cache(), name, data)
+ data = containers.read(afm.cache(),name)
end
end
+ return data
+ else
+ return nil
end
- return data
end
function afm.unify(data, filename)
local unicodevector = fonts.enc.load('unicode').hash
local glyphs, indices, unicodes, names = { }, { }, { }, { }
local verbose, private = fonts.verbose, fonts.private
- for name, blob in pairs(data.characters) do
+ for name, blob in next, data.characters do
local code = unicodevector[name] -- or characters.name_to_unicode[name]
if not code then
- local u = name:match("^uni(%x+)$")
+ local u = match(name,"^uni(%x+)$")
code = u and tonumber(u,16)
if not code then
code = private
private = private + 1
- logs.report("afm glyph", "assigning private slot 0x%04X for unknown glyph name %s", code, name)
+ logs.report("afm glyph", "assigning private slot U+%04X for unknown glyph name %s", code, name)
end
end
local index = blob.index
@@ -319,14 +328,15 @@ function afm.unify(data, filename)
blob.index = nil
end
end
- data.luatex = {
- filename = file.basename(filename),
- unicodes = unicodes, -- name to unicode
- indices = indices, -- unicode to index
- names = names, -- name to index
- }
data.glyphs = glyphs
data.characters = nil
+ local luatex = data.luatex
+ luatex.filename = luatex.filename or file.removesuffix(file.basename(filename))
+ luatex.unicodes = unicodes -- name to unicode
+ luatex.indices = indices -- unicode to index
+ luatex.marks = { } -- todo
+ luatex.names = names -- name to index
+ luatex.private = private
end
--[[ldx--
@@ -335,15 +345,12 @@ and extra kerns. This saves quite some lookups later.</p>
--ldx]]--
function afm.add_ligatures(afmdata,ligatures)
- local glyphs = afmdata.glyphs
- local luatex = afmdata.luatex
- local indices = luatex.indices
- local unicodes = luatex.unicodes
- local names = luatex.names
- for k,v in pairs(characters[ligatures]) do -- main characters table
+ local glyphs, luatex = afmdata.glyphs, afmdata.luatex
+ local indices, unicodes, names = luatex.indices, luatex.unicodes, luatex.names
+ for k,v in next, characters[ligatures] do -- main characters table
local one = glyphs[names[k]]
if one then
- for _, b in pairs(v) do
+ for _, b in next, v do
two, three = b[1], b[2]
if two and three and names[two] and names[three] then
local ol = one[ligatures]
@@ -370,28 +377,42 @@ function afm.add_kerns(afmdata)
local names = afmdata.luatex.names
local uncomposed = characters.uncomposed
local function do_it_left(what)
- for index, glyph in pairs(glyphs) do
- if glyph.kerns then
- local k = { }
- for complex, simple in pairs(uncomposed[what]) do
- local ks = k[simple]
- if ks and not k[complex] then
- k[complex] = ks
+ for index, glyph in next, glyphs do
+ local kerns = glyph.kerns
+ if kerns then
+ local extrakerns = glyph.extrakerns or { }
+ for complex, simple in next, uncomposed[what] do
+ if names[compex] then
+ local ks = kerns[simple]
+ if ks and not kerns[complex] then
+ extrakerns[complex] = ks
+ end
end
end
- if next(k) then
- glyph.extrakerns = k
+ if next(extrakerns) then
+ glyph.extrakerns = extrakerns
end
end
end
end
local function do_it_copy(what)
- for complex, simple in pairs(uncomposed[what]) do
+ for complex, simple in next, uncomposed[what] do
local c = glyphs[names[complex]]
if c then -- optional
local s = glyphs[names[simple]]
- if s and s.kerns then
- c.extrakerns = s.kerns -- ok ? no merge ?
+ if s then
+ if not c.kerns then
+ c.extrakerns = s.kerns or { }
+ end
+ if s.extrakerns then
+ local extrakerns = c.extrakerns or { }
+ for k, v in next, s.extrakerns do
+ extrakerns[k] = v
+ end
+ if next(extrakerns) then
+ s.extrakerns = extrakerns
+ end
+ end
end
end
end
@@ -413,12 +434,20 @@ end
function afm.add_dimensions(data) -- we need to normalize afm to otf i.e. indexed table instead of name
if data then
- for index, glyph in pairs(data.glyphs) do
+ for index, glyph in next, data.glyphs do
local bb = glyph.boundingbox
if bb then
local ht, dp = bb[4], -bb[2]
- if ht ~= 0 then glyph.height = ht end
- if dp ~= 0 then glyph.depth = dp end
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ glyph.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
+ else
+ glyph.depth = dp
+ end
end
end
end
@@ -428,42 +457,48 @@ function afm.copy_to_tfm(data)
if data then
local glyphs = data.glyphs
if glyphs then
+ local metadata, luatex = data.metadata, data.luatex
+ local unicodes, indices = luatex.unicodes, luatex.indices
local characters, parameters, descriptions = { }, { }, { }
- local unicodes = data.luatex.unicodes
- local indices = data.luatex.indices
- local tfm = { characters = characters, parameters = parameters, descriptions = descriptions }
- for u, i in pairs(indices) do
+ local tfm = {
+ characters = characters,
+ parameters = parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ luatex = luatex,
+ }
+ for u, i in next, indices do
local d = glyphs[i]
- characters[u] = { } -- not needed
+ characters[u] = { }
descriptions[u] = d
- d.index = i
end
- tfm.encodingbytes = data.encodingbytes or 2
- tfm.fullname = data.fullname
- tfm.filename = data.filename
- tfm.name = tfm.fullname -- data.name or tfm.fullname
+ tfm.encodingbytes = metadata.encodingbytes or 2
+ tfm.fullname = metadata.fullname
+ tfm.filename = metadata.filename
+ tfm.name = tfm.fullname
tfm.type = "real"
tfm.units = 1000
- tfm.stretch = stretch
- tfm.slant = slant
+ tfm.stretch = stretch -- nil
+ tfm.slant = slant -- nil
tfm.direction = 0
tfm.boundarychar_label = 0
tfm.boundarychar = 65536
--~ tfm.false_boundarychar = 65536 -- produces invalid tfm in luatex
- tfm.designsize = (data.designsize or 10)*65536
+ tfm.designsize = (metadata.designsize or 10)*65536
local spaceunits = 500
tfm.spacer = "500 units"
-- same as otf
local endash, emdash = unicodes['space'], unicodes['emdash']
- if data.isfixedpitch then
+ if metadata.isfixedpitch then
if descriptions[endash] then
spaceunits, tfm.spacer = descriptions[endash].width, "space"
end
if not spaceunits and descriptions[emdash] then
spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
end
- if not spaceunits and data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth"
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
end
else
if descriptions[endash] then
@@ -472,8 +507,8 @@ function afm.copy_to_tfm(data)
-- if not spaceunits and descriptions[emdash] then
-- spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
-- end
- if not spaceunits and data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth"
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
end
end
--
@@ -484,25 +519,26 @@ function afm.copy_to_tfm(data)
parameters.space_shrink = 333
parameters.x_height = 400
parameters.quad = 1000
- parameters.extra_space = 0
if spaceunits < 200 then
-- todo: warning
end
- tfm.italicangle = data.italicangle
- tfm.ascender = math.abs(data.ascender or 0)
- tfm.descender = math.abs(data.descender or 0)
- if data.italicangle then
- parameters.slant = parameters.slant - math.round(math.tan(data.italicangle*math.pi/180))
+ tfm.ascender = math.abs(metadata.ascender or 0)
+ tfm.descender = math.abs(metadata.descender or 0)
+ local italicangle = data.metadata.italicangle
+ if italicangle then
+ tfm.italicangle = italicangle
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
end
- if data.isfixedpitch then
+ if metadata.isfixedpitch then
parameters.space_stretch = 0
parameters.space_shrink = 0
elseif afm.syncspace then
parameters.space_stretch = spaceunits/2
parameters.space_shrink = spaceunits/3
end
- if data.xheight and data.xheight > 0 then
- parameters.x_height = data.xheight
+ parameters.extra_space = parameters.space_shrink
+ if metadata.xheight and metadata.xheight > 0 then
+ parameters.x_height = metadata.xheight
else
-- same as otf
local x = unicodes['x']
@@ -516,7 +552,7 @@ function afm.copy_to_tfm(data)
end
local fd = data.fontdimens
if fd and fd[8] and fd[9] and fd[10] then -- math
- for k,v in pairs(fd) do
+ for k,v in next, fd do
parameters[k] = v
end
end
@@ -543,47 +579,59 @@ end
function afm.set_features(tfmdata)
local shared = tfmdata.shared
local afmdata = shared.afmdata
- -- elsewhere: shared.features = fonts.define.check(shared.features,afm.features.default)
local features = shared.features
if not table.is_empty(features) then
local mode = tfmdata.mode or fonts.mode
- local fi = fonts.initializers[mode]
- if fi and fi.afm then
- local function initialize(list) -- using tex lig and kerning
+ local initializers = fonts.initializers
+ local fi = initializers[mode]
+ local fiafm = fi and fi.afm
+ if fiafm then
+ local lists = {
+ fonts.triggers,
+ afm.features.list,
+ fonts.manipulators,
+ }
+ for l=1,3 do
+ local list = lists[l]
if list then
- for _, f in ipairs(list) do
+ for i=1,#list do
+ local f = list[i]
local value = features[f]
- if value and fi.afm[f] then -- brr
- if afm.trace_features then
+ if value and fiafm[f] then -- brr
+ if trace_features then
logs.report("define afm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
end
- fi.afm[f](tfmdata,value)
+ fiafm[f](tfmdata,value)
mode = tfmdata.mode or fonts.mode
- fi = fonts.initializers[mode]
+ fiafm = initializers[mode].afm
end
end
end
end
- initialize(fonts.triggers)
- initialize(afm.features.list)
- initialize(fonts.manipulators)
end
local fm = fonts.methods[mode]
- if fm and fm.afm then
- local function register(list) -- node manipulations
+ local fmafm = fm and fm.afm
+ if fmfm then
+ local lists = {
+ afm.features.list,
+ }
+ local sp = shared.processors
+ for l=1,1 do
+ local list = lists[l]
if list then
- for _, f in ipairs(list) do
- if features[f] and fm.afm[f] then -- brr
- if not shared.processors then -- maybe also predefine
- shared.processors = { fm.afm[f] }
+ for i=1,#list do
+ local f = list[i]
+ if features[f] and fmafm[f] then -- brr
+ if not sp then
+ sp = { fmafm[f] }
+ shared.processors = sp
else
- shared.processors[#shared.processors+1] = fm.afm[f]
+ sp[#sp+1] = fmafm[f]
end
end
end
end
end
- register(afm.features.list)
end
end
end
@@ -598,21 +646,21 @@ end
function afm.afm_to_tfm(specification)
local afmname = specification.filename or specification.name
- local encoding, filename = afmname:match("^(.-)%-(.*)$") -- context: encoding-name.*
+ local encoding, filename = match(afmname,"^(.-)%-(.*)$") -- context: encoding-name.*
if encoding and filename and fonts.enc.known[encoding] then
tfm.set_normal_feature(specification,'encoding',encoding) -- will go away
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","stripping encoding prefix from filename %s",afmname)
end
afmname = filename
- elseif specification.forced == "afm" then
- if fonts.trace then
+ elseif specification.forced == "afm" or specification.format == "afm" then -- move this one up
+ if trace_loading then
logs.report("load afm","forcing afm format for %s",afmname)
end
else
- local tfmname = input.findbinfile(afmname,"ofm") or ""
+ local tfmname = resolvers.findbinfile(afmname,"ofm") or ""
if tfmname ~= "" then
- if fonts.trace then
+ if trace_loading then
logs.report("load afm","fallback from afm to tfm for %s",afmname)
end
afmname = ""
@@ -638,7 +686,7 @@ function afm.afm_to_tfm(specification)
tfmdata.shared.features = features
afm.set_features(tfmdata)
end
- elseif fonts.trace then
+ elseif trace_loading then
logs.report("load afm","no (valid) afm file found with name %s",afmname)
end
tfmdata = containers.write(tfm.cache(),cache_id,tfmdata)
@@ -677,8 +725,8 @@ function tfm.read_from_afm(specification)
end
if filename then
tfmtable.encodingbytes = 2
- tfmtable.filename = input.findbinfile(filename,"") or filename
- tfmtable.fullname = afmdata.fontname or afmdata.fullname
+ tfmtable.filename = resolvers.findbinfile(filename,"") or filename
+ tfmtable.fullname = afmdata.metadata.fontname or afmdata.metadata.fullname
tfmtable.format = 'type1'
tfmtable.name = afmdata.luatex.filename or tfmtable.fullname
end
@@ -701,7 +749,7 @@ function afm.features.prepare_ligatures(tfmdata,ligatures,value)
local luatex = afmdata.luatex
local unicodes = luatex.unicodes
local descriptions = tfmdata.descriptions
- for u, chr in pairs(tfmdata.characters) do
+ for u, chr in next, tfmdata.characters do
local d = descriptions[u]
local l = d[ligatures]
if l then
@@ -710,7 +758,7 @@ function afm.features.prepare_ligatures(tfmdata,ligatures,value)
ligatures = { }
chr.ligatures = ligatures
end
- for k, v in pairs(l) do
+ for k, v in next, l do
local uk, uv = unicodes[k], unicodes[v]
if uk and uv then
ligatures[uk] = {
@@ -730,7 +778,7 @@ function afm.features.prepare_kerns(tfmdata,kerns,value)
local luatex = afmdata.luatex
local unicodes = luatex.unicodes
local descriptions = tfmdata.descriptions
- for u, chr in pairs(tfmdata.characters) do
+ for u, chr in next, tfmdata.characters do
local d = descriptions[u]
local newkerns = d[kerns]
if newkerns then
@@ -739,7 +787,7 @@ function afm.features.prepare_kerns(tfmdata,kerns,value)
kerns = { }
chr.kerns = kerns
end
- for k,v in pairs(newkerns) do
+ for k,v in next, newkerns do
local uk = unicodes[k]
if uk then
kerns[uk] = v
diff --git a/tex/context/base/font-bfm.tex b/tex/context/base/font-bfm.tex
index a7bf398ef..23e3176c4 100644
--- a/tex/context/base/font-bfm.tex
+++ b/tex/context/base/font-bfm.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Font Macros / Mixed Bold Math Support}
+\writestatus{loading}{ConTeXt Font Macros / Mixed Bold Math Support}
%D The following example demonstrates how to use normal, bold, and mixed
%D normal|/|bold math. Since not everyone has the Lucida on his|/|her
diff --git a/tex/context/base/font-chi.tex b/tex/context/base/font-chi.tex
index cf30470d7..0acf710d5 100644
--- a/tex/context/base/font-chi.tex
+++ b/tex/context/base/font-chi.tex
@@ -22,7 +22,7 @@
%D unicode codepoints (yet); if it were possible we could use
%D just one table per input encoding.
-\writestatus{loading}{Context Font Macros / Chinese}
+\writestatus{loading}{ConTeXt Font Macros / Chinese}
% much will to typo-chi.tex
diff --git a/tex/context/base/font-chk.lua b/tex/context/base/font-chk.lua
new file mode 100644
index 000000000..61f3f8ab5
--- /dev/null
+++ b/tex/context/base/font-chk.lua
@@ -0,0 +1,80 @@
+if not modules then modules = { } end modules ['font-chk'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- possible optimization: delayed initialization of vectors
+
+fonts = fonts or { }
+fonts.checkers = fonts.checkers or { }
+
+local checkers = fonts.checkers
+local fontdata = fonts.ids
+local is_character = characters.is_character
+local chardata = characters.data
+
+local glyph = node.id('glyph')
+local traverse_id = node.traverse_id
+
+-- maybe in fonts namespace
+-- deletion can be option
+
+checkers.enabled = false
+checkers.delete = false
+
+function fonts.register_message(font,char,message)
+ local tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ local messages = shared.messages
+ if not messages then
+ messages = { }
+ shared.messages = messages
+ end
+ local category = messages[message]
+ if not category then
+ category = { }
+ messages[message] = category
+ end
+ if not category[char] then
+ logs.report("fonts","char U+%04X in font '%s' with id %s: %s",char,tfmdata.fullname,font,message)
+ category[char] = true
+ end
+end
+
+function checkers.missing(head,tail)
+ if checkers.enabled then
+ local lastfont, characters, found = nil, nil, nil
+ for n in traverse_id(glyph,head) do
+ local font, char = n.font, n.char
+ if font ~= lastfont then
+ characters = fontdata[font].characters
+ end
+ if not characters[char] and is_character[chardata[char].category] then
+ if checkers.delete then
+ fonts.register_message(font,char,"missing (will be deleted)")
+ else
+ fonts.register_message(font,char,"missing")
+ end
+ if not found then
+ found = { n }
+ else
+ found[#found+1] = n
+ end
+ end
+ end
+ if found and checkers.delete then
+ for i=1,#found do
+ local n = found[i]
+ if n == tail then
+ head, tail = nodes.remove(head,n,true)
+ else
+ head, _ = nodes.remove(head,n,true)
+ end
+ end
+ end
+ end
+ return head, tail, false
+end
diff --git a/tex/context/base/font-cid.lua b/tex/context/base/font-cid.lua
new file mode 100644
index 000000000..b8dfc4294
--- /dev/null
+++ b/tex/context/base/font-cid.lua
@@ -0,0 +1,143 @@
+if not modules then modules = { } end modules ['font-cid'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (cidmaps)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, match = string.format, string.match
+local tonumber = tonumber
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+fonts = fonts or { }
+fonts.cid = fonts.cid or { }
+fonts.cid.map = fonts.cid.map or { }
+fonts.cid.max = fonts.cid.max or 10
+
+
+-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
+--
+-- 18964 18964 (leader)
+-- 0 /.notdef
+-- 1..95 0020
+-- 99 3000
+
+local number = lpeg.C(lpeg.R("09","af","AF")^1)
+local space = lpeg.S(" \n\r\t")
+local spaces = space^0
+local period = lpeg.P(".")
+local periods = period * period
+local name = lpeg.P("/") * lpeg.C((1-space)^1)
+
+local unicodes, names = { }, { }
+
+local function do_one(a,b)
+ unicodes[tonumber(a)] = tonumber(b,16)
+end
+
+local function do_range(a,b,c)
+ c = tonumber(c,16)
+ for i=tonumber(a),tonumber(b) do
+ unicodes[i] = c
+ c = c + 1
+ end
+end
+
+local function do_name(a,b)
+ names[tonumber(a)] = b
+end
+
+local grammar = lpeg.P { "start",
+ start = number * spaces * number * lpeg.V("series"),
+ series = (spaces * (lpeg.V("one") + lpeg.V("range") + lpeg.V("named")) )^1,
+ one = (number * spaces * number) / do_one,
+ range = (number * periods * number * spaces * number) / do_range,
+ named = (number * spaces * name) / do_name
+}
+
+function fonts.cid.load(filename)
+ local data = io.loaddata(filename)
+ if data then
+ unicodes, names = { }, { }
+ grammar:match(data)
+ local supplement, registry, ordering = match(filename,"^(.-)%-(.-)%-()%.(.-)$")
+ return {
+ supplement = supplement,
+ registry = registry,
+ ordering = ordering,
+ filename = filename,
+ unicodes = unicodes,
+ names = names
+ }
+ else
+ return nil
+ end
+end
+
+local template = "%s-%s-%s.cidmap"
+
+local function locate(registry,ordering,supplement)
+ local filename = string.lower(format(template,registry,ordering,supplement))
+ local cidmap = fonts.cid.map[filename]
+ if not cidmap then
+ if trace_loading then
+ logs.report("load otf","checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
+ end
+ local fullname = resolvers.find_file(filename,'cid') or ""
+ if fullname ~= "" then
+ cidmap = fonts.cid.load(fullname)
+ if cidmap then
+ if trace_loading then
+ logs.report("load otf","using cidmap file %s",filename)
+ end
+ fonts.cid.map[filename] = cidmap
+ return cidmap
+ end
+ end
+ end
+ return cidmap
+end
+
+function fonts.cid.getmap(registry,ordering,supplement)
+ -- cf Arthur R. we can safely scan upwards since cids are downward compatible
+ local supplement = tonumber(supplement)
+ if trace_loading then
+ logs.report("load otf","needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
+ end
+ local cidmap = locate(registry,ordering,supplement)
+ if not cidmap then
+ local cidnum = nil
+ -- next highest (alternatively we could start high)
+ if supplement < fonts.cid.max then
+ for supplement=supplement+1,fonts.cid.max do
+ local c = locate(registry,ordering,supplement)
+ if c then
+ cidmap, cidnum = c, supplement
+ break
+ end
+ end
+ end
+ -- next lowest (least worse fit)
+ if not cidmap and supplement > 0 then
+ for supplement=supplement-1,0,-1 do
+ local c = locate(registry,ordering,supplement)
+ if c then
+ cidmap, cidnum = c, supplement
+ break
+ end
+ end
+ end
+ -- prevent further lookups
+ if cidmap and cidnum > 0 then
+ for s=0,cidnum-1 do
+ filename = format(template,registry,ordering,s)
+ if not fonts.cid.map[filename] then
+ fonts.cid.map[filename] = cidmap -- copy of ref
+ end
+ end
+ end
+ end
+ return cidmap
+end
diff --git a/tex/context/base/font-col.lua b/tex/context/base/font-col.lua
index 0bafea708..5d089fef2 100644
--- a/tex/context/base/font-col.lua
+++ b/tex/context/base/font-col.lua
@@ -8,17 +8,24 @@ if not modules then modules = { } end modules ['font-col'] = {
-- possible optimization: delayed initialization of vectors
-fonts = fonts or { }
-nodes = nodes or { }
+local format, gmatch, texsprint, type = string.format, string.gmatch, tex.sprint, type
+local traverse_id, first_character = node.traverse_id, node.first_character
-local format, texsprint = string.format, tex.sprint
-local traverse_id, glyph = node.traverse_id, node.id('glyph')
+local ctxcatcodes = tex.ctxcatcodes
+
+local trace_collecting = false trackers.register("fonts.collecting", function(v) trace_collecting = v end)
+
+local fontdata = fonts.ids
+
+local glyph = node.id('glyph')
+
+fonts.normalizers = fonts.normalizers or { }
fonts.collections = fonts.collections or { }
fonts.collections.definitions = fonts.collections.definitions or { }
fonts.collections.vectors = fonts.collections.vectors or { }
-fonts.collections.trace = false
+local collections = fonts.collections
local definitions = fonts.collections.definitions
local vectors = fonts.collections.vectors
@@ -26,7 +33,7 @@ local list, current, active = { }, 0, false
-- maybe also a copy
-function fonts.collections.reset(name,font)
+function collections.reset(name,font)
if font and font ~= "" then
local d = definitions[name]
if d then
@@ -40,17 +47,16 @@ function fonts.collections.reset(name,font)
end
end
-function fonts.collections.define(name,font,ranges,details)
+function collections.define(name,font,ranges,details)
-- todo: details -> method=force|conditional rscale=
-- todo: remap=name
- local trace = fonts.collections.trace
local d = definitions[name]
if d then
- if name and trace then
+ if name and trace_collecting then
logs.report("fonts","def: extending set %s using %s",name, font)
end
else
- if name and trace then
+ if name and trace_collecting then
logs.report("fonts","def: defining set %s using %s",name, font)
end
d = { }
@@ -58,17 +64,17 @@ function fonts.collections.define(name,font,ranges,details)
end
details = aux.settings_to_hash(details)
-- todo, combine per font start/stop as arrays
- for s in ranges:gmatch("([^, ]+)") do
+ for s in gmatch(ranges,"([^, ]+)") do
local start, stop, description = characters.getrange(s)
if start and stop then
- if trace then
+ if trace_collecting then
if description then
- logs.report("fonts","def: using range %s (0x%04x-0x%04X, %s)",s,start,stop,description)
+ logs.report("fonts","def: using range %s (U+%04x-U+%04X, %s)",s,start,stop,description)
end
for i=1,#d do
local di = d[i]
if (start >= di.start and start <= di.stop) or (stop >= di.start and stop <= di.stop) then
- logs.report("fonts","def: overlapping ranges 0x%04x-0x%04X and 0x%04x-0x%04X",start,stop,di.start,di.stop)
+ logs.report("fonts","def: overlapping ranges U+%04x-U+%04X and U+%04x-U+%04X",start,stop,di.start,di.stop)
end
end
end
@@ -78,37 +84,35 @@ function fonts.collections.define(name,font,ranges,details)
end
end
-function fonts.collections.stage_1(name)
- input.starttiming(fonts)
+function collections.stage_1(name)
local last = font.current()
- if fonts.collections.trace then
+ if trace_collecting then
logs.report("fonts","def: registering font %s with name %s",last,name)
end
list[#list+1] = last
end
-function fonts.collections.stage_2(name)
+function collections.stage_2(name)
+ statistics.starttiming(fonts)
local d = definitions[name]
local t = { }
- local ids = fonts.tfm.id
- local trace = fonts.collections.trace
- if trace then
+ if trace_collecting then
logs.report("fonts","def: process collection %s",name)
end
for i=1,#d do
local f = d[i]
local id = list[i]
local start, stop = f.start, f.stop
- if trace then
- logs.report("fonts","def: remapping font %s to %s for range 0x%04X - 0x%04X",current,id,start,stop)
+ if trace_collecting then
+ logs.report("fonts","def: remapping font %s to %s for range U+%04X - U+%04X",current,id,start,stop)
end
- local check = toboolean(f.check or "false")
- local force = toboolean(f.force or "true")
+ local check = toboolean(f.check or "false",true)
+ local force = toboolean(f.force or "true",true)
local remap = f.remap or nil
-- check: when true, only set when present in font
-- force: when false, then not set when already set
- local oldchars = ids[current].characters
- local newchars = ids[id].characters
+ local oldchars = fontdata[current].characters
+ local newchars = fontdata[id].characters
if check then
for i=start,stop do
if newchars[i] and (force or (not t[i] and not oldchars[i])) then
@@ -132,11 +136,11 @@ function fonts.collections.stage_2(name)
end
end
vectors[current] = t
- if trace then
+ if trace_collecting then
logs.report("fonts","def: activating collection %s for font %s",name,current)
end
active = true
- input.stoptiming(fonts)
+ statistics.stoptiming(fonts)
end
local P, Cc = lpeg.P, lpeg.Cc
@@ -145,47 +149,47 @@ local okay = ((1-spec)^1 * spec * Cc(true)) + Cc(false)
-- todo: check for already done
-function fonts.collections.prepare(name)
+function collections.prepare(name)
current = font.current()
if vectors[current] then
return
end
- local ids = fonts.tfm.id
- local trace = fonts.collections.trace
local d = definitions[name]
if d then
- if trace then
- local filename = file.basename(ids[current].filename or "?")
+ if trace_collecting then
+ local filename = file.basename(fontdata[current].filename or "?")
logs.report("fonts","def: applying collection %s to %s (file: %s)",name,current,filename)
end
list = { }
- texsprint(tex.ctxcatcodes,"\\dostartcloningfonts") -- move this to tex \dostart...
+ texsprint(ctxcatcodes,"\\dostartcloningfonts") -- move this to tex \dostart...
for i=1,#d do
local f = d[i]
local name = f.font
local scale = f.rscale or 1
if okay:match(name) then
- texsprint(tex.ctxcatcodes,format("\\doclonefonta{%s}{%s}",name,scale)) -- define with unique specs
+ texsprint(ctxcatcodes,format("\\doclonefonta{%s}{%s}",name,scale)) -- define with unique specs
else
- texsprint(tex.ctxcatcodes,format("\\doclonefontb{%s}{%s}",name,scale)) -- define with inherited specs
+ texsprint(ctxcatcodes,format("\\doclonefontb{%s}{%s}",name,scale)) -- define with inherited specs
end
- texsprint(tex.ctxcatcodes,format("\\ctxlua{fonts.collections.stage_1('%s')}",name)) -- registering main font
+ texsprint(ctxcatcodes,format("\\ctxlua{fonts.collections.stage_1('%s')}",name)) -- registering main font
end
- texsprint(tex.ctxcatcodes,format("\\ctxlua{fonts.collections.stage_2('%s')}",name)) -- preparing clone vectors
- texsprint(tex.ctxcatcodes,"\\dostopcloningfonts")
+ texsprint(ctxcatcodes,format("\\ctxlua{fonts.collections.stage_2('%s')}",name)) -- preparing clone vectors
+ texsprint(ctxcatcodes,"\\dostopcloningfonts")
+ elseif trace_collecting then
+ local filename = file.basename(fontdata[current].filename or "?")
+ logs.report("fonts","def: error in applying collection %s to %s (file: %s)",name,current,filename)
end
end
-function fonts.collections.message(message)
- if fonts.collections.trace then
+function collections.message(message)
+ if trace_collecting then
logs.report("fonts","tex: %s",message)
end
end
-function fonts.collections.normalize(head,tail)
+function collections.process(head,tail)
if active then
local done = false
- local trace = fonts.collections.trace
for n in traverse_id(glyph,head) do
local v = vectors[n.font]
if v then
@@ -193,12 +197,12 @@ function fonts.collections.normalize(head,tail)
if id then
if type(id) == "table" then
local newid, newchar = id[1], id[2]
- if trace then
+ if trace_collecting then
logs.report("fonts","lst: remapping character %s in font %s to character %s in font %s",n.char,n.font,newchar,newid)
end
n.font, n.char = newid, newchar
else
- if trace then
+ if trace_collecting then
logs.report("fonts","lst: remapping font %s to %s for character %s",n.font,id,n.char)
end
n.font = id
@@ -209,5 +213,3 @@ function fonts.collections.normalize(head,tail)
end
return head, tail, done
end
-
-nodes.normalize_fonts = fonts.collections.normalize
diff --git a/tex/context/base/font-col.tex b/tex/context/base/font-col.mkiv
index 3383b6515..22a67ac8e 100644
--- a/tex/context/base/font-col.tex
+++ b/tex/context/base/font-col.mkiv
@@ -21,7 +21,7 @@
% \definefontfallback [whatever] [Bold] [0x0080-0x00FF,0x00A0-0x00AF] [rscale=1.2]
% \definefontfallback [whatever] [BoldSlanted] [0x00C0-0x00C7] [check=yes,force=yes]
-\writestatus{loading}{Context Font Fallbacks (col)}
+\writestatus{loading}{ConTeXt Font Macros / Collections}
\registerctxluafile{font-col}{1.001}
@@ -113,8 +113,6 @@
% }
% \stopcolumns
-% \ctxlua{fonts.trace = true ; fonts.collections.trace = true}
-%
% \definefontfeature[zh][mode=node,script=hang,lang=zhs]
% \definefontfallback[serifwhatever] [lmroman10-regular] [0x0000-0x0400][force=yes]
% \definefontfallback[serifboldwhatever] [lmroman10-bold] [0x0000-0x0400][force=yes]
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
new file mode 100644
index 000000000..e87b21165
--- /dev/null
+++ b/tex/context/base/font-ctx.lua
@@ -0,0 +1,387 @@
+if not modules then modules = { } end modules ['font-ctx'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, count = tex.sprint, tex.count
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+local tfm = fonts.tfm
+local define = fonts.define
+local fontdata = fonts.ids
+local specify = define.specify
+
+specify.context_setups = specify.context_setups or { }
+specify.context_numbers = specify.context_numbers or { }
+specify.context_merged = specify.context_merged or { }
+specify.synonyms = specify.synonyms or { }
+
+local setups = specify.context_setups
+local numbers = specify.context_numbers
+local merged = specify.context_merged
+local synonyms = specify.synonyms
+local triggers = fonts.triggers
+
+--[[ldx--
+<p>So far we haven't really dealt with features (or whatever we want
+to pass along with the font definition. We distinguish the following
+situations:</p>
+situations:</p>
+
+<code>
+name:xetex like specs
+name@virtual font spec
+name*context specification
+</code>
+--ldx]]--
+
+function specify.predefined(specification)
+ local detail = specification.detail
+ if detail ~= "" then
+ -- detail = detail:gsub("["..define.splitsymbols.."].*$","") -- get rid of *whatever specs and such
+ if define.methods[detail] then -- since these may be appended at the
+ specification.features.vtf = { preset = detail } -- tex end by default
+ end
+ end
+ return specification
+end
+
+define.register_split("@", specify.predefined)
+
+storage.register("fonts/setups" , define.specify.context_setups , "fonts.define.specify.context_setups" )
+storage.register("fonts/numbers", define.specify.context_numbers, "fonts.define.specify.context_numbers")
+storage.register("fonts/merged", define.specify.context_merged, "fonts.define.specify.context_merged")
+storage.register("fonts/synonyms", define.specify.synonyms, "fonts.define.specify.synonyms")
+
+local normalize_meanings = fonts.otf.meanings.normalize
+local settings_to_hash = aux.settings_to_hash
+local default_features = fonts.otf.features.default
+
+local function preset_context(name,parent,features) -- currently otf only
+ if features == "" then
+ if find(parent,"=") then
+ features = parent
+ parent = ""
+ end
+ end
+ local number = (setups[name] and setups[name].number) or 0
+ local t = (features == "" and { }) or normalize_meanings(settings_to_hash(features))
+ -- todo: synonyms, and not otf bound
+ if parent ~= "" then
+ for p in gmatch(parent,"[^, ]+") do
+ local s = setups[p]
+ if s then
+ for k,v in next, s do
+ if t[k] == nil then
+ t[k] = v
+ end
+ end
+ end
+ end
+ end
+ -- these are auto set so in order to prevent redundant definitions
+ -- we need to preset them (we hash the features and adding a default
+ -- setting during initialization may result in a different hash)
+ for k,v in next, triggers do
+ if type(t[v]) == "nil" then
+ local vv = default_features[v]
+ if vv then t[v] = vv end
+ end
+ end
+ -- sparse 'm so that we get a better hash and less test (experimental
+ -- optimization)
+ local tt = { } -- maybe avoid tt
+ for k,v in next, t do
+ if v then tt[k] = v end
+ end
+ -- needed for dynamic features
+ if number == 0 then
+ number = #numbers + 1
+ numbers[number] = name
+ end
+ tt.number = number
+ setups[name] = tt
+ return number
+end
+
+local function context_number(name) -- will be replaced
+ local t = setups[name]
+ if not t then
+ return 0
+ elseif t.auto then
+ local lng = tonumber(tex.language)
+ local tag = name .. ":" .. lng
+ local s = setups[tag]
+ if s then
+ return s.number or 0
+ else
+ local script, language = languages.association(lng)
+ if t.script ~= script or t.language ~= language then
+ local s = table.fastcopy(t)
+ local n = #numbers + 1
+ setups[tag] = s
+ numbers[n] = tag
+ s.number = n
+ s.script = script
+ s.language = language
+ return n
+ else
+ setups[tag] = t
+ return t.number or 0
+ end
+ end
+ else
+ return t.number or 0
+ end
+end
+
+local function merge_context(currentnumber,extraname,option)
+ local current = setups[numbers[currentnumber]]
+ local extra = setups[extraname]
+ if extra then
+ local mergedfeatures, mergedname = { }, nil
+ if option < 0 then
+ if current then
+ for k, v in next, current do
+ if not extra[k] then
+ mergedfeatures[k] = v
+ end
+ end
+ end
+ mergedname = currentnumber .. "-" .. extraname
+ else
+ if current then
+ for k, v in next, current do
+ mergedfeatures[k] = v
+ end
+ end
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ mergedname = currentnumber .. "+" .. extraname
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = option
+ setups[mergedname] = mergedfeatures
+ return number -- context_number(mergedname)
+ else
+ return currentnumber
+ end
+end
+
+local function register_context(fontnumber,extraname,option)
+ local extra = setups[extraname]
+ if extra then
+ local mergedfeatures, mergedname = { }, nil
+ if option < 0 then
+ mergedname = fontnumber .. "-" .. extraname
+ else
+ mergedname = fontnumber .. "+" .. extraname
+ end
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = option
+ setups[mergedname] = mergedfeatures
+ return number -- context_number(mergedname)
+ else
+ return 0
+ end
+end
+
+specify.preset_context = preset_context
+specify.context_number = context_number
+specify.merge_context = merge_context
+specify.register_context = register_context
+
+local current_font = font.current
+local tex_attribute = tex.attribute
+
+local cache = { } -- concat might be less efficient than nested tables
+
+function fonts.withset(name,what)
+ local zero = tex_attribute[0]
+ local hash = zero .. "+" .. name .. "*" .. what
+ local done = cache[hash]
+ if not done then
+ done = merge_context(zero,name,what)
+ cache[hash] = done
+ end
+ tex_attribute[0] = done
+end
+function fonts.withfnt(name,what)
+ local font = current_font()
+ local hash = font .. "*" .. name .. "*" .. what
+ local done = cache[hash]
+ if not done then
+ done = register_context(font,name,what)
+ cache[hash] = done
+ end
+ tex_attribute[0] = done
+end
+
+function specify.show_context(name)
+ return setups[name] or setups[numbers[name]] or setups[numbers[tonumber(name)]] or { }
+end
+
+local function split_context(features)
+ return setups[features] or (preset_context(features,"","") and setups[features])
+end
+
+specify.split_context = split_context
+
+function specify.context_tostring(name,kind,separator,yes,no,strict,omit) -- not used
+ return aux.hash_to_string(table.merged(fonts[kind].features.default or {},setups[name] or {}),separator,yes,no,strict,omit)
+end
+
+local splitter = lpeg.splitat(",")
+
+function specify.starred(features) -- no longer fallbacks here
+ local detail = features.detail
+ if detail and detail ~= "" then
+ features.features.normal = split_context(detail)
+ else
+ features.features.normal = { }
+ end
+ return features
+end
+
+define.register_split('*',specify.starred)
+
+-- define (two steps)
+
+local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc
+
+local space = P(" ")
+local spaces = space^0
+local value = C((1-space)^1)
+local rest = C(P(1)^0)
+local scale_none = Cc(0)
+local scale_at = P("at") * Cc(1) * spaces * value
+local scale_sa = P("sa") * Cc(2) * spaces * value
+local scale_mo = P("mo") * Cc(3) * spaces * value
+local scale_scaled = P("scaled") * Cc(4) * spaces * value
+
+local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
+local splitpattern = spaces * value * spaces * rest
+
+local specification --
+
+local get_specification = define.get_specification
+
+function define.command_1(str)
+ statistics.starttiming(fonts)
+ local fullname, size = splitpattern:match(str)
+ local lookup, name, sub, method, detail = get_specification(fullname)
+ if not name then
+ logs.report("define font","strange definition '%s'",str)
+ texsprint(ctxcatcodes,"\\glet\\somefontname\\defaultfontfile")
+ elseif name == "unknown" then
+ texsprint(ctxcatcodes,"\\glet\\somefontname\\defaultfontfile")
+ else
+ texsprint(ctxcatcodes,format("\\xdef\\somefontname{%s}",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))
+ else
+ count.scaledfontmode = 0
+ texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size))
+ 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))
+ else
+ count.scaledfontmode = 0
+ texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size))
+ end
+ specification = define.makespecification(str,lookup,name,sub,method,detail,size)
+end
+
+function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,mathsize,textsize)
+ -- name is now resolved and size is scaled cf sa/mo
+ local lookup, name, sub, method, detail = get_specification(str or "")
+ -- asome settings can be overloaded
+ if lookup and lookup ~= "" then specification.lookup = lookup end
+ specification.name = name
+ specification.size = size
+ specification.sub = sub
+ specification.mathsize = mathsize
+ specification.textsize = textsize
+ if detail and detail ~= "" then
+ specification.method, specification.detail = method or "*", detail
+ elseif specification.detail and specification.detail ~= "" then
+ -- already set
+ elseif fontfeatures and fontfeatures ~= "" then
+ specification.method, specification.detail = "*", fontfeatures
+ elseif classfeatures and classfeatures ~= "" then
+ specification.method, specification.detail = "*", classfeatures
+ end
+ if trace_defining then
+ logs.report("define font","memory usage before: %s",statistics.memused())
+ end
+ if fontfallbacks and fontfallbacks ~= "" then
+ specification.fallbacks = fontfallbacks
+ elseif classfallbacks and classfallbacks ~= "" then
+ specification.fallbacks = classfallbacks
+ end
+ local tfmdata = define.read(specification,size) -- id not yet known
+ if not tfmdata then
+ logs.report("define font","unable to define %s as \\%s",name,cs)
+ elseif type(tfmdata) == "number" then
+ if trace_defining then
+ logs.report("define font","reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
+ end
+ tex.definefont(global,cs,tfmdata)
+ -- resolved (when designsize is used):
+ texsprint(ctxcatcodes,format("\\def\\somefontsize{%isp}",fontdata[tfmdata].size))
+ else
+ -- local t = os.clock(t)
+ local id = font.define(tfmdata)
+ -- print(name,os.clock()-t)
+ tfmdata.id = id
+ define.register(tfmdata,id)
+ tex.definefont(global,cs,id)
+ tfm.cleanup_table(tfmdata)
+ if trace_defining then
+ logs.report("define font","defining %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,id,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
+ end
+ -- resolved (when designsize is used):
+ texsprint(ctxcatcodes,format("\\def\\somefontsize{%isp}",tfmdata.size))
+ --~ if specification.fallbacks then
+ --~ fonts.collections.prepare(specification.fallbacks)
+ --~ end
+ end
+ if trace_defining then
+ logs.report("define font","memory usage after: %s",statistics.memused())
+ end
+ statistics.stoptiming(fonts)
+end
+
+--~ table.insert(readers.sequence,1,'vtf')
+
+--~ function readers.vtf(specification)
+--~ if specification.features.vtf and specification.features.vtf.preset then
+--~ return tfm.make(specification)
+--~ else
+--~ return nil
+--~ end
+--~ end
diff --git a/tex/context/base/font-def.lua b/tex/context/base/font-def.lua
index 474cde41d..8c367e148 100644
--- a/tex/context/base/font-def.lua
+++ b/tex/context/base/font-def.lua
@@ -6,9 +6,13 @@ if not modules then modules = { } end modules ['font-def'] = {
license = "see context related readme files"
}
--- check reuse of lmroman1o-regular vs lmr10
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
-local texsprint, count, dimen, format, concat = tex.sprint, tex.count, tex.dimen, string.format, table.concat
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading")
+trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*")
--[[ldx--
<p>Here we deal with defining fonts. We do so by intercepting the
@@ -18,43 +22,30 @@ default loader that only handles <l n='tfm'/>.</p>
fonts = fonts or { }
fonts.define = fonts.define or { }
fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
fonts.vf = fonts.vf or { }
fonts.used = fonts.used or { }
-local tfm = fonts.tfm
-local vf = fonts.vf
+local tfm = fonts.tfm
+local vf = fonts.vf
+local define = fonts.define
tfm.version = 1.01
tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
---[[ldx--
-<p>Choosing a font by name and specififying its size is only part of the
-game. In order to prevent complex commands, <l n='xetex'/> introduced
-a method to pass feature information as part of the font name. At the
-risk of introducing nasty parsing and compatinility problems, this
-syntax was expanded over time.</p>
-
-<p>For the sake of users who have defined fonts using that syntax, we
-will support it, but we will provide additional methods as well.
-Normally users will not use this direct way, but use a more abstract
-interface.</p>
- --ldx]]--
-
---~ name, kind, features = fonts.features.split_xetex("blabla / B : + lnum ; foo = bar ; - whatever ; whow ; + hans ; test = yes")
-
-fonts.define.method = 3 -- 1: tfm 2: tfm and if not then afm 3: afm and if not then tfm
-fonts.define.auto_afm = true
-fonts.define.auto_otf = true
-fonts.define.specify = fonts.define.specify or { }
-fonts.define.methods = fonts.define.methods or { }
+define.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
+define.specify = fonts.define.specify or { }
+define.methods = fonts.define.methods or { }
tfm.fonts = tfm.fonts or { }
tfm.readers = tfm.readers or { }
tfm.internalized = tfm.internalized or { } -- internal tex numbers
-tfm.id = tfm.id or { } -- font data, maybe use just fonts.ids (faster lookup)
tfm.readers.sequence = { 'otf', 'ttf', 'afm', 'tfm' }
+local readers = tfm.readers
+local sequence = readers.sequence
+
--[[ldx--
<p>We hardly gain anything when we cache the final (pre scaled)
<l n='tfm'/> table. But it can be handy for debugging.</p>
@@ -84,7 +75,7 @@ and prepares a table that will move along as we proceed.</p>
local splitter, specifiers = nil, ""
-function fonts.define.add_specifier(symbol)
+function define.add_specifier(symbol)
specifiers = specifiers .. symbol
local left = lpeg.P("(")
local right = lpeg.P(")")
@@ -92,27 +83,32 @@ function fonts.define.add_specifier(symbol)
local method = lpeg.S(specifiers)
local lookup = lpeg.C(lpeg.P("file")+lpeg.P("name")) * colon -- hard test, else problems with : method
local sub = left * lpeg.C(lpeg.P(1-left-right-method)^1) * right
- local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1)
+--~ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1)
+ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1)^1)
local name = lpeg.C((1-sub-specification)^1)
splitter = lpeg.P((lookup + lpeg.Cc("")) * name * (sub + lpeg.Cc("")) * (specification + lpeg.Cc("")))
end
-function fonts.define.get_specification(str)
+function define.get_specification(str)
return splitter:match(str)
end
-function fonts.define.register_split(symbol,action)
- fonts.define.add_specifier(symbol)
- fonts.define.specify[symbol] = action
+function define.register_split(symbol,action)
+ define.add_specifier(symbol)
+ define.specify[symbol] = action
end
-function fonts.define.makespecification(specification, lookup, name, sub, method, detail, size)
+function define.makespecification(specification, lookup, name, sub, method, detail, size)
size = size or 655360
- if fonts.trace then
+ if trace_defining then
logs.report("define font","%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s",
specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-",
(sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-")
end
+--~ if specification.lookup then
+--~ lookup = specification.lookup -- can come from xetex [] syntax
+--~ specification.lookup = nil
+--~ end
if lookup ~= 'name' then -- for the moment only two lookups, maybe some day also system:
lookup = 'file'
end
@@ -131,37 +127,43 @@ function fonts.define.makespecification(specification, lookup, name, sub, method
return t
end
-function fonts.define.analyze(specification, size)
- local lookup, name, sub, method, detail = fonts.define.get_specification(specification or "")
- return fonts.define.makespecification(specification,lookup, name, sub, method, detail, size)
+function define.analyze(specification, size)
+ -- can be optimized with locals
+ local lookup, name, sub, method, detail = define.get_specification(specification or "")
+ return define.makespecification(specification,lookup, name, sub, method, detail, size)
end
--[[ldx--
<p>A unique hash value is generated by:</p>
--ldx]]--
+local sortedhashkeys = table.sortedhashkeys
+
function tfm.hash_features(specification)
local features = specification.features
if features then
local t = { }
local normal = features.normal
if normal and next(normal) then
- local f = table.sortedhashkeys(normal)
+ local f = sortedhashkeys(normal)
for i=1,#f do
local v = f[i]
- if v ~= "number" then
+ if v ~= "number" and v ~= "features" then -- i need to figure this out, features
t[#t+1] = v .. '=' .. tostring(normal[v])
end
end
end
local vtf = features.vtf
if vtf and next(vtf) then
- local f = table.sortedhashkeys(vtf)
+ local f = sortedhashkeys(vtf)
for i=1,#f do
local v = f[i]
t[#t+1] = v .. '=' .. tostring(vtf[v])
end
end
+--~ if specification.mathsize then
+--~ t[#t] = "mathsize=" .. specification.mathsize
+--~ end
if #t > 0 then
return concat(t,"+")
end
@@ -189,18 +191,28 @@ function tfm.hash_instance(specification,force)
size = math.round(tfm.scaled(size, fonts.designsizes[hash]))
specification.size = size
end
- if fallbacks then
- return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
- else
- return hash .. ' @ ' .. tostring(size)
- end
+--~ local mathsize = specification.mathsize or 0
+--~ if mathsize > 0 then
+--~ local textsize = specification.textsize
+--~ if fallbacks then
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
+--~ else
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
+--~ end
+--~ else
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+--~ end
end
--[[ldx--
<p>We can resolve the filename using the next function:</p>
--ldx]]--
-function fonts.define.resolve(specification)
+function define.resolve(specification)
if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash
if specification.lookup == 'name' then
specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
@@ -218,7 +230,8 @@ function fonts.define.resolve(specification)
else
specification.forced = specification.forced
end
- specification.hash = specification.name .. ' @ ' .. tfm.hash_features(specification)
+--~ specification.hash = specification.name .. ' @ ' .. tfm.hash_features(specification)
+ specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
end
@@ -242,22 +255,23 @@ specification yet.</p>
--ldx]]--
function tfm.read(specification)
---~ input.starttiming(fonts)
local hash = tfm.hash_instance(specification)
local tfmtable = tfm.fonts[hash] -- hashes by size !
if not tfmtable then
- if specification.forced and specification.forced ~= "" then
- tfmtable = tfm.readers[specification.forced:lower()](specification)
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = readers[lower(forced)](specification)
if not tfmtable then
- logs.report("define font","forced type %s of %s not found",specification.forced,specification.name)
+ logs.report("define font","forced type %s of %s not found",forced,specification.name)
end
else
- for _, reader in ipairs(tfm.readers.sequence) do
- if tfm.readers[reader] then -- not really needed
- if fonts.trace then
+ for s=1,#sequence do -- reader sequence
+ local reader = sequence[s]
+ if readers[reader] then -- not really needed
+ if trace_defining then
logs.report("define font","trying type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
end
- tfmtable = tfm.readers[reader](specification)
+ tfmtable = readers[reader](specification)
if tfmtable then break end
end
end
@@ -273,7 +287,6 @@ function tfm.read(specification)
--~ tfmtable.mode = specification.features.normal.mode or "base"
end
end
---~ input.stoptiming(fonts)
if not tfmtable then
logs.report("define font","font with name %s is not found",specification.name)
end
@@ -285,26 +298,26 @@ end
--ldx]]--
function tfm.read_and_define(name,size) -- no id
- local specification = fonts.define.analyze(name,size)
+ local specification = define.analyze(name,size)
local method = specification.method
- if method and fonts.define.specify[method] then
- specification = fonts.define.specify[method](specification)
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
end
- specification = fonts.define.resolve(specification)
+ specification = define.resolve(specification)
local hash = tfm.hash_instance(specification)
- local id = fonts.define.registered(hash)
+ local id = define.registered(hash)
if not id then
local fontdata = tfm.read(specification)
if fontdata then
fontdata.hash = hash
id = font.define(fontdata)
- fonts.define.register(fontdata,id)
-tfm.cleanup_table(fontdata)
+ define.register(fontdata,id)
+ tfm.cleanup_table(fontdata)
else
id = 0 -- signal
end
end
- return tfm.id[id], id
+ return fonts.ids[id], id
end
--[[ldx--
@@ -312,275 +325,113 @@ end
evolved. Each one has its own way of dealing with its format.</p>
--ldx]]--
-function tfm.readers.opentype(specification,suffix,what)
- if fonts.define.auto_otf then
- local fullname, tfmtable = nil, nil
- fullname = input.findbinfile(specification.name,suffix) or ""
- if fullname == "" then
- local fb = fonts.names.old_to_new[specification.name]
- if fb then
- fullname = input.findbinfile(fb,suffix) or ""
- end
- end
- if fullname == "" then
- local fb = fonts.names.new_to_old[specification.name]
- if fb then
- fullname = input.findbinfile(fb,suffix) or ""
- end
- end
- if fullname ~= "" then
- specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
- tfmtable = tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
- end
- return tfmtable
- else
- return nil
+local function check_tfm(specification,fullname)
+ -- ofm directive blocks local path search unless set
+ fullname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, "ofm"
+ return tfm.read_from_tfm(specification)
end
end
-function tfm.readers.otf(specification) return tfm.readers.opentype(specification,"otf","opentype") end
-function tfm.readers.ttf(specification) return tfm.readers.opentype(specification,"ttf","truetype") end
-function tfm.readers.ttc(specification) return tfm.readers.opentype(specification,"ttf","truetype") end -- !!
-
-function tfm.readers.afm(specification,method)
- local fullname, tfmtable = nil, nil
- method = method or fonts.define.method
- if method == 2 then
- fullname = input.findbinfile(specification.name,"ofm") or ""
- if fullname == "" then
- tfmtable = tfm.read_from_afm(specification)
- else -- redundant
- specification.filename = fullname
- tfmtable = tfm.read_from_tfm(specification)
- end
- elseif method == 3 then -- maybe also findbinfile here
- if fonts.define.auto_afm then
- tfmtable = tfm.read_from_afm(specification)
- end
- elseif method == 4 then -- maybe also findbinfile here
- tfmtable = tfm.read_from_afm(specification)
+local function check_afm(specification,fullname)
+ fullname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, "afm"
+ return tfm.read_from_afm(specification)
end
- return tfmtable
end
-function tfm.readers.tfm(specification)
- local fullname, tfmtable = nil, nil
- tfmtable = tfm.read_from_tfm(specification)
- return tfmtable
-end
-
---[[ldx--
-<p>So far we haven't really dealt with features (or whatever we want
-to pass along with the font definition. We distinguish the following
-situations:</p>
-situations:</p>
-
-<code>
-name:xetex like specs
-name@virtual font spec
-name*context specification
-</code>
-
-<p>Of course one can always define more.</p>
---ldx]]--
-
-function fonts.define.specify.predefined(specification)
- local detail = specification.detail
- if detail ~= "" then
- -- detail = detail:gsub("["..fonts.define.splitsymbols.."].*$","") -- get rid of *whatever specs and such
- if fonts.define.methods[detail] then -- since these may be appended at the
- specification.features.vtf = { preset = detail } -- tex end by default
+function readers.tfm(specification)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_tfm(specification,specification.name .. "." .. forced)
end
- end
- return specification
-end
-
-fonts.define.register_split("@", fonts.define.specify.predefined)
-
-function fonts.define.specify.colonized(specification) -- xetex mode
- local list = { }
- if specification.detail and specification.detail ~= "" then
- local expanded_features = { }
- local function expand(features)
- for _,v in pairs(features:split(";")) do --just gmatch
- expanded_features[#expanded_features+1] = v
- end
- end
- expand(specification.detail)
- for _,v in pairs(expanded_features) do
- local a, b = v:match("^%s*(%S+)%s*=%s*(%S+)%s*$")
- if a and b then
- list[a] = b:is_boolean()
- if type(list[a]) == "nil" then
- list[a] = b
- end
- else
- local a, b = v:match("^%s*([%+%-]?)%s*(%S+)%s*$")
- if a and b then
- list[b] = a ~= "-"
- end
- end
+ if not tfmtable then
+ tfmtable = check_tfm(specification,specification.name)
end
- end
- specification.features.normal = list
- return specification
-end
-
-function tfm.make(specification)
- -- currently fonts are scaled while constructing the font, so we
- -- have to do scaling of commands in the vf at that point using
- -- e.g. "local scale = g.factor or 1" after all, we need to work
- -- with copies anyway and scaling needs to be done at some point;
- -- however, when virtual tricks are used as feature (makes more
- -- sense) we scale the commands in fonts.tfm.scale (and set the
- -- factor there)
- local fvm = fonts.define.methods[specification.features.vtf.preset]
- if fvm then
- return fvm(specification)
else
- return nil
+ tfmtable = check_tfm(specification,fullname)
end
+ return tfmtable
end
-fonts.define.register_split(":", fonts.define.specify.colonized)
-
-fonts.define.specify.context_setups = fonts.define.specify.context_setups or { }
-fonts.define.specify.context_numbers = fonts.define.specify.context_numbers or { }
-fonts.define.specify.synonyms = fonts.define.specify.synonyms or { }
-
-input.storage.register(false,"fonts/setups" , fonts.define.specify.context_setups , "fonts.define.specify.context_setups" )
-input.storage.register(false,"fonts/numbers", fonts.define.specify.context_numbers, "fonts.define.specify.context_numbers")
-
-fonts.triggers = fonts.triggers or { }
-
-function fonts.define.specify.preset_context(name,parent,features)
- if features == "" then
- if parent:find("=") then
- features = parent
- parent = ""
+function readers.afm(specification,method)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_afm(specification,specification.name .. "." .. forced)
end
- end
- local fds = fonts.define.specify
- local setups, numbers, synonyms = fds.context_setups, fds.context_numbers, fds.synonyms
- local number = (setups[name] and setups[name].number) or 0
- local t = (features == "" and { }) or fonts.otf.meanings.normalize(aux.settings_to_hash(features))
- -- todo: synonyms, and not otf bound
- if parent ~= "" then
- for p in parent:gmatch("[^, ]+") do
- local s = setups[p]
- if s then
- for k,v in pairs(s) do
- if t[k] == nil then
- t[k] = v
- end
- end
+ if not tfmtable then
+ method = method or define.method or "afm or tfm"
+ if method == "tfm" then
+ tfmtable = check_tfm(specification,specification.name)
+ elseif method == "afm" then
+ tfmtable = check_afm(specification,specification.name)
+ elseif method == "tfm or afm" then
+ tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
+ else -- method == "afm or tfm" or method == "" then
+ tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
end
end
- end
- -- these are auto set so in order to prevent redundant definitions
- -- we need to preset them (we hash the features and adding a default
- -- setting during initialization may result in a different hash)
- local default = fonts.otf.features.default
- for k,v in pairs(fonts.triggers) do
- if type(t[v]) == "nil" then
- local vv = default[v]
- if vv then t[v] = vv end
- end
- end
- -- sparse 'm so that we get a better hash and less test (experimental
- -- optimization)
- local tt = { }
- for k,v in pairs(t) do
- if v then tt[k] = v end
- end
- -- needed for dynamic features
- if number == 0 then
- numbers[#numbers+1] = name
- tt.number = #numbers
else
- tt.number = number
+ tfmtable = check_afm(specification,fullname)
end
- setups[name] = tt
+ return tfmtable
end
-do
-
- -- here we clone features according to languages
-
- local default = 0
- local setups = fonts.define.specify.context_setups
- local numbers = fonts.define.specify.context_numbers
-
- function fonts.define.specify.context_number(name)
- local t = setups[name]
- if not t then
- return default
- elseif t.auto then
- local lng = tonumber(tex.language)
- local tag = name .. ":" .. lng
- local s = setups[tag]
- if s then
- return s.number or default
- else
- local script, language = languages.association(lng)
- if t.script ~= script or t.language ~= language then
- local s = table.fastcopy(t)
- local n = #numbers + 1
- setups[tag] = s
- numbers[n] = tag
- s.number = n
- s.script = script
- s.language = language
- return n
- else
- setups[tag] = t
- return t.number or default
- end
- end
- else
- return t.number or default
+local function check_otf(specification,suffix,what)
+ local fullname, tfmtable = resolvers.findbinfile(specification.name,suffix) or "", nil
+ if fullname == "" then
+ local fb = fonts.names.old_to_new[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
end
end
-
-end
-
-function fonts.define.specify.context_tostring(name,kind,separator,yes,no,strict,omit) -- not used
- return aux.hash_to_string(table.merged(fonts[kind].features.default or {},fonts.define.specify.context_setups[name] or {}),separator,yes,no,strict,omit)
-end
-
-function fonts.define.specify.split_context(features)
- if fonts.define.specify.context_setups[features] then
- return fonts.define.specify.context_setups[features]
- else -- ? ? ?
- return fonts.define.specify.preset_context("***",features)
+ if fullname == "" then
+ local fb = fonts.names.new_to_old[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
+ end
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
+ tfmtable = tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
end
+ return tfmtable
end
-local splitter = lpeg.splitat(",")
-
-function fonts.define.specify.starred(features) -- no longer fallbacks here
- local detail = features.detail
- if detail and detail ~= "" then
- features.features.normal = fonts.define.specify.split_context(detail)
+function readers.opentype(specification,suffix,what)
+ local forced = specification.forced or ""
+ if forced == "otf" then
+ return check_otf(specification,forced,"opentype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
else
- features.features.normal = { }
+ return check_otf(specification,suffix,what)
end
- return features
end
-fonts.define.register_split('*',fonts.define.specify.starred)
+function readers.otf(specification) return readers.opentype(specification,"otf","opentype") end
+function readers.ttf(specification) return readers.opentype(specification,"ttf","truetype") end
+function readers.ttc(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
--[[ldx--
<p>We need to check for default features. For this we provide
a helper function.</p>
--ldx]]--
-function fonts.define.check(features,defaults) -- nb adapts features !
+function define.check(features,defaults) -- nb adapts features !
local done = false
if table.is_empty(features) then
features, done = table.fastcopy(defaults), true
else
- for k,v in pairs(defaults) do
+ for k,v in next, defaults do
if features[k] == nil then
features[k], done = v, true
end
@@ -601,43 +452,59 @@ not gain much. By the way, passing id's back to in the callback was
introduced later in the development.</p>
--ldx]]--
-fonts.define.last = nil
+define.last = nil
-function fonts.define.register(fontdata,id)
+function define.register(fontdata,id)
if fontdata and id then
local hash = fontdata.hash
if not tfm.internalized[hash] then
- if fonts.trace then
+ if trace_defining then
logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?")
end
- tfm.id[id] = fontdata
+ fonts.ids[id] = fontdata
tfm.internalized[hash] = id
end
end
end
-function fonts.define.registered(hash)
+function define.registered(hash)
local id = tfm.internalized[hash]
- return id, id and tfm.id[id]
+ return id, id and fonts.ids[id]
end
local cache_them = false
-function fonts.define.read(specification,size,id) -- id can be optional, name can already be table
- input.starttiming(fonts)
+function tfm.make(specification)
+ -- currently fonts are scaled while constructing the font, so we
+ -- have to do scaling of commands in the vf at that point using
+ -- e.g. "local scale = g.factor or 1" after all, we need to work
+ -- with copies anyway and scaling needs to be done at some point;
+ -- however, when virtual tricks are used as feature (makes more
+ -- sense) we scale the commands in fonts.tfm.scale (and set the
+ -- factor there)
+ local fvm = define.methods[specification.features.vtf.preset]
+ if fvm then
+ return fvm(specification)
+ else
+ return nil
+ end
+end
+
+function define.read(specification,size,id) -- id can be optional, name can already be table
+ statistics.starttiming(fonts)
if type(specification) == "string" then
- specification = fonts.define.analyze(specification,size)
+ specification = define.analyze(specification,size)
end
local method = specification.method
- if method and fonts.define.specify[method] then
- specification = fonts.define.specify[method](specification)
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
end
- specification = fonts.define.resolve(specification)
+ specification = define.resolve(specification)
local hash = tfm.hash_instance(specification)
if cache_them then
local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
end
- local fontdata = fonts.define.registered(hash) -- id
+ local fontdata = define.registered(hash) -- id
if not fontdata then
if specification.features.vtf and specification.features.vtf.preset then
fontdata = tfm.make(specification)
@@ -652,15 +519,16 @@ function fonts.define.read(specification,size,id) -- id can be optional, name ca
end
if fontdata then
fontdata.hash = hash
+ fontdata.cache = "no"
if id then
- fonts.define.register(fontdata,id)
+ define.register(fontdata,id)
end
end
end
- fonts.define.last = fontdata or id -- todo ! ! ! ! !
+ define.last = fontdata or id -- todo ! ! ! ! !
if not fontdata then
logs.report("define font", "unknown font %s, loading aborted",specification.name)
- elseif fonts.trace and type(fontdata) == "table" then
+ elseif trace_defining and type(fontdata) == "table" then
logs.report("define font","using %s font with id %s, n:%s s:%s b:%s e:%s p:%s f:%s",
fontdata.type or "unknown",
id or "?",
@@ -671,148 +539,30 @@ function fonts.define.read(specification,size,id) -- id can be optional, name ca
fontdata.fullname or "?",
file.basename(fontdata.filename or "?"))
end
- input.stoptiming(fonts)
+ statistics.stoptiming(fonts)
return fontdata
end
--- define (two steps)
-
-local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc
-
-local space = P(" ")
-local spaces = space^0
-local value = C((1-space)^1)
-local rest = C(P(1)^0)
-local scale_none = Cc(0)
-local scale_at = P("at") * Cc(1) * spaces * value
-local scale_sa = P("sa") * Cc(2) * spaces * value
-local scale_mo = P("mo") * Cc(3) * spaces * value
-local scale_scaled = P("scaled") * Cc(4) * spaces * value
-
-local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
-local splitpattern = spaces * value * spaces * rest
-
-local specification --
-
-function fonts.define.command_1(str)
- input.starttiming(fonts)
- local fullname, size = splitpattern:match(str)
- local lookup, name, sub, method, detail = fonts.define.get_specification(fullname)
- if not name then
- logs.report("define font","strange definition '%s'",str)
- texsprint(tex.ctxcatcodes,"\\glet\\somefontname\\defaultfontfile")
- elseif name == "unknown" then
- texsprint(tex.ctxcatcodes,"\\glet\\somefontname\\defaultfontfile")
- else
- texsprint(tex.ctxcatcodes,format("\\xdef\\somefontname{%s}",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(tex.ctxcatcodes,format("\\def\\somefontsize{%s}",size))
- else
- count.scaledfontmode = 0
- texsprint(tex.ctxcatcodes,format("\\let\\somefontsize\\empty",size))
- end
- else
- count.scaledfontmode = 0
- texsprint(tex.ctxcatcodes,format("\\let\\somefontsize\\empty",size))
- end
- specification = fonts.define.makespecification(str,lookup,name,sub,method,detail,size)
-end
-
-function fonts.define.command_2(global,cs,name,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
- local trace = fonts.trace
- -- name is now resolved and size is scaled cf sa/mo
- local lookup, name, sub, method, detail = fonts.define.get_specification(name or "")
- -- asome settings can be overloaded
- if lookup and lookup ~= "" then specification.lookup = lookup end
- specification.name = name
- specification.size = size
- specification.sub = sub
- if detail and detail ~= "" then
- specification.method, specification.detail = method or "*", detail
- elseif specification.detail and specification.detail ~= "" then
- -- already set
- elseif fontfeatures and fontfeatures ~= "" then
- specification.method, specification.detail = "*", fontfeatures
- elseif classfeatures and classfeatures ~= "" then
- specification.method, specification.detail = "*", classfeatures
- end
- if trace then
- logs.report("define font","memory usage before: %s",ctx.memused())
- end
-if fontfallbacks and fontfallbacks ~= "" then
- specification.fallbacks = fontfallbacks
-elseif classfallbacks and classfallbacks ~= "" then
- specification.fallbacks = classfallbacks
-end
- local tfmdata = fonts.define.read(specification,size) -- id not yet known
- if not tfmdata then
- logs.report("define font","unable to define %s as \\%s",name,cs)
- elseif type(tfmdata) == "number" then
- if trace then
- logs.report("define font","reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
- end
- tex.definefont(global,cs,tfmdata)
- -- resolved (when designsize is used):
- texsprint(tex.ctxcatcodes,format("\\def\\somefontsize{%isp}",tfm.id[tfmdata].size))
- else
- -- local t = os.clock(t)
- local id = font.define(tfmdata)
- -- print(name,os.clock()-t)
- tfmdata.id = id
- fonts.define.register(tfmdata,id)
- tex.definefont(global,cs,id)
- tfm.cleanup_table(tfmdata)
- if fonts.trace then
- logs.report("define font","defining %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,id,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks)
- end
- -- resolved (when designsize is used):
- texsprint(tex.ctxcatcodes,format("\\def\\somefontsize{%isp}",tfmdata.size))
- --~ if specification.fallbacks then
- --~ fonts.collections.prepare(specification.fallbacks)
- --~ end
- end
- if trace then
- logs.report("define font","memory usage after: %s",ctx.memused())
- end
- input.stoptiming(fonts)
-end
-
-
---~ table.insert(tfm.readers.sequence,1,'vtf')
-
---~ function tfm.readers.vtf(specification)
---~ if specification.features.vtf and specification.features.vtf.preset then
---~ return tfm.make(specification)
---~ else
---~ return nil
---~ end
---~ end
-
-function fonts.vf.find(name)
+function vf.find(name)
name = file.removesuffix(file.basename(name))
if tfm.resolve_vf then
local format = fonts.logger.format(name)
if format == 'tfm' or format == 'ofm' then
- if fonts.trace then
+ if trace_defining then
logs.report("define font","locating vf for %s",name)
end
- return input.findbinfile(name,"ovf")
+ return resolvers.findbinfile(name,"ovf")
else
- if fonts.trace then
+ if trace_defining then
logs.report("define font","vf for %s is already taken care of",name)
end
return nil -- ""
end
else
- if fonts.trace then
+ if trace_defining then
logs.report("define font","locating vf for %s",name)
end
- return input.findbinfile(name,"ovf")
+ return resolvers.findbinfile(name,"ovf")
end
end
@@ -820,5 +570,5 @@ end
<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
--ldx]]--
-callback.register('define_font' , fonts.define.read)
-callback.register('find_vf_file', fonts.vf.find ) -- not that relevant any more
+callback.register('define_font' , define.read)
+callback.register('find_vf_file', vf.find ) -- not that relevant any more
diff --git a/tex/context/base/font-dum.lua b/tex/context/base/font-dum.lua
new file mode 100644
index 000000000..0d28128d8
--- /dev/null
+++ b/tex/context/base/font-dum.lua
@@ -0,0 +1,113 @@
+if not modules then modules = { } end modules ['font-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+fonts = fonts or { }
+
+-- general
+
+fonts.otf.pack = false
+fonts.tfm.resolve_vf = false -- no sure about this
+
+-- readers
+
+fonts.tfm.readers = fonts.tfm.readers or { }
+fonts.tfm.readers.sequence = { 'otf', 'ttf', 'tfm' }
+fonts.tfm.readers.afm = nil
+
+-- define
+
+fonts.define = fonts.define or { }
+
+--~ fonts.define.method = "tfm"
+
+fonts.define.specify.colonized_default_lookup = "name"
+
+function fonts.define.get_specification(str)
+ return "", str, "", ":", str
+end
+
+-- logger
+
+fonts.logger = fonts.logger or { }
+
+function fonts.logger.save()
+end
+
+-- names
+
+fonts.names = fonts.names or { }
+
+fonts.names.basename = "luatex-fonts-names.lua"
+fonts.names.new_to_old = { }
+fonts.names.old_to_new = { }
+
+local data, loaded = nil, false
+
+function fonts.names.resolve(name,sub)
+ if not loaded then
+ local basename = fonts.names.basename
+ if basename and basename ~= "" then
+ for _, format in ipairs { "lua", "tex", "other text files" } do
+ local foundname = resolvers.find_file(basename,format) or ""
+ if foundname ~= "" then
+ data = dofile(foundname)
+ if data then
+ local d = { }
+ for k, v in pairs(data.mapping) do
+ local t = v[1]
+ if t == "ttf" or t == "otf" or t == "ttc" then
+ d[k] = v
+ end
+ end
+ data.mapping = d
+ end
+ break
+ end
+ end
+ end
+ loaded = true
+ end
+ if type(data) == "table" and data.version == 1.08 then
+ local condensed = string.gsub(name,"[^%a%d]","")
+ local found = data.mapping and data.mapping[condensed]
+ if found then
+ local filename, is_sub = found[3], found[4]
+ if is_sub then is_sub = found[2] end
+ return filename, is_sub
+ else
+ return name, false -- fallback to filename
+ end
+ end
+end
+
+-- For the moment we put this (adapted) pseudo feature here.
+
+table.insert(fonts.triggers,"itlc")
+
+local function itlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local metadata = tfmdata.shared.otfdata.metadata
+ if metadata then
+ local italicangle = metadata.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (metadata.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.has_italic = true
+ end
+ end
+ end
+end
+
+fonts.initializers.base.otf.itlc = itlc
+fonts.initializers.node.otf.itlc = itlc
diff --git a/tex/context/base/font-enc.lua b/tex/context/base/font-enc.lua
index 86ace93c6..faeae3a10 100644
--- a/tex/context/base/font-enc.lua
+++ b/tex/context/base/font-enc.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['font-enc'] = {
license = "see context related readme files"
}
+local match, gmatch, gsub = string.match, string.gmatch, string.gsub
+
--[[ldx--
<p>Because encodings are going to disappear, we don't bother defining
them in tables. But we may do so some day, for consistency.</p>
@@ -62,15 +64,15 @@ function fonts.enc.load(filename)
return data
end
local vector, tag, hash, unicodes = { }, "", { }, { }
- local foundname = input.find_file(filename,'enc')
+ local foundname = resolvers.find_file(filename,'enc')
if foundname and foundname ~= "" then
- local ok, encoding, size = input.loadbinfile(foundname)
+ local ok, encoding, size = resolvers.loadbinfile(foundname)
if ok and encoding then
local enccodes = characters.enccodes
- encoding = encoding:gsub("%%(.-)\n","")
- local tag, vec = encoding:match("/(%w+)%s*%[(.*)%]%s*def")
+ encoding = gsub(encoding,"%%(.-)\n","")
+ local tag, vec = match(encoding,"/(%w+)%s*%[(.*)%]%s*def")
local i = 0
- for ch in vec:gmatch("/([%a%d%.]+)") do
+ for ch in gmatch(vec,"/([%a%d%.]+)") do
if ch ~= ".notdef" then
vector[i] = ch
if not hash[ch] then
@@ -105,7 +107,7 @@ one.</p>
function fonts.enc.make_unicode_vector()
local vector, hash = { }, { }
- for code, v in pairs(characters.data) do
+ for code, v in next, characters.data do
local name = v.adobename
if name then
vector[code], hash[name] = name, code
@@ -113,7 +115,7 @@ function fonts.enc.make_unicode_vector()
vector[code] = '.notdef'
end
end
- for name, code in pairs(characters.synonyms) do
+ for name, code in next, characters.synonyms do
vector[code], hash[name] = name, code
end
return containers.write(fonts.enc.cache(), 'unicode', { name='unicode', tag='unicode', vector=vector, hash=hash })
diff --git a/tex/context/base/font-ext.lua b/tex/context/base/font-ext.lua
index c3979fad6..17c302c53 100644
--- a/tex/context/base/font-ext.lua
+++ b/tex/context/base/font-ext.lua
@@ -6,7 +6,191 @@ if not modules then modules = { } end modules ['font-ext'] = {
license = "see context related readme files"
}
-local byte = string.byte
+local next, type, byte = next, type, string.byte
+
+--[[ldx--
+<p>When we implement functions that deal with features, most of them
+will depend of the font format. Here we define the few that are kind
+of neutral.</p>
+--ldx]]--
+
+fonts.triggers = fonts.triggers or { }
+fonts.initializers = fonts.initializers or { }
+fonts.initializers.common = fonts.initializers.common or { }
+
+local initializers = fonts.initializers
+
+--[[ldx--
+<p>This feature will remove inter-digit kerns.</p>
+--ldx]]--
+
+table.insert(fonts.triggers,"equaldigits")
+
+function initializers.common.equaldigits(tfmdata,value)
+ if value then
+ local chr = tfmdata.characters
+ for i = utfbyte('0'), utfbyte('9') do
+ local c = chr[i]
+ if c then
+ c.kerns = nil
+ end
+ end
+ end
+end
+
+--[[ldx--
+<p>This feature will give all glyphs an equal height and/or depth. Valid
+values are <type>none</type>, <type>height</type>, <type>depth</type> and
+<type>both</type>.</p>
+--ldx]]--
+
+table.insert(fonts.triggers,"lineheight")
+
+function initializers.common.lineheight(tfmdata,value)
+ if value and type(value) == "string" then
+ if value == "none" then
+ for _,v in next, tfmdata.characters do
+ v.height, v.depth = 0, 0
+ end
+ else
+ local ascender, descender = tfmdata.ascender, tfmdata.descender
+ if ascender and descender then
+ local ht, dp = ascender or 0, descender or 0
+ if value == "height" then
+ dp = 0
+ elseif value == "depth" then
+ ht = 0
+ end
+ if ht > 0 then
+ if dp > 0 then
+ for _,v in next, tfmdata.characters do
+ v.height, v.depth = ht, dp
+ end
+ else
+ for _,v in next, tfmdata.characters do
+ v.height = ht
+ end
+ end
+ elseif dp > 0 then
+ for _,v in next, tfmdata.characters do
+ v.depth = dp
+ end
+ end
+ end
+ end
+ end
+end
+
+--[[ldx--
+<p>It does not make sense any more to support messed up encoding vectors
+so we stick to those that implement oldstyle and small caps. After all,
+we move on. We can extend the next function on demand. This features is
+only used with <l n='afm'/> files.</p>
+--ldx]]--
+
+--~ do
+--~
+--~ local smallcaps = lpeg.P(".sc") + lpeg.P(".smallcaps") + lpeg.P(".caps") + lpeg.P("small")
+--~ local oldstyle = lpeg.P(".os") + lpeg.P(".oldstyle") + lpeg.P(".onum")
+--~
+--~ smallcaps = lpeg.Cs((1-smallcaps)^1) * smallcaps^1
+--~ oldstyle = lpeg.Cs((1-oldstyle )^1) * oldstyle ^1
+--~
+--~ function initializers.common.encoding(tfmdata,value)
+--~ if value then
+--~ local afmdata = tfmdata.shared.afmdata
+--~ if afmdata then
+--~ local encodingfile = value .. '.enc'
+--~ local encoding = fonts.enc.load(encodingfile)
+--~ if encoding then
+--~ local vector = encoding.vector
+--~ local characters = tfmdata.characters
+--~ local unicodes = afmdata.luatex.unicodes
+--~ local function remap(pattern,name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ local oldchr, newchr = unicodes[p], unicodes[name]
+--~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
+--~ -- logs.report("encoding","%s (%s) -> %s (%s)",p,oldchr or -1,name,newchr or -1)
+--~ characters[oldchr] = characters[newchr]
+--~ end
+--~ end
+--~ return p
+--~ end
+--~ for _, name in next, vector do
+--~ local ok = remap(smallcaps,name) or remap(oldstyle,name)
+--~ end
+--~ if fonts.map.data[tfmdata.name] then
+--~ fonts.map.data[tfmdata.name].encoding = encodingfile
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~
+--~ -- when needed we can provide this as features in e.g. afm files
+--~
+--~ function initializers.common.remap(tfmdata,value,pattern) -- will go away
+--~ if value then
+--~ local afmdata = tfmdata.shared.afmdata
+--~ if afmdata then
+--~ local characters = tfmdata.characters
+--~ local descriptions = tfmdata.descriptions
+--~ local unicodes = afmdata.luatex.unicodes
+--~ local done = false
+--~ for u, _ in next, characters do
+--~ local name = descriptions[u].name
+--~ if name then
+--~ local p = pattern:match(name)
+--~ if p then
+--~ local oldchr, newchr = unicodes[p], unicodes[name]
+--~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
+--~ characters[oldchr] = characters[newchr]
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~
+--~ function initializers.common.oldstyle(tfmdata,value)
+--~ initializers.common.remap(tfmdata,value,oldstyle)
+--~ end
+--~ function initializers.common.smallcaps(tfmdata,value)
+--~ initializers.common.remap(tfmdata,value,smallcaps)
+--~ end
+--~
+--~ function initializers.common.fakecaps(tfmdata,value)
+--~ if value then
+--~ -- todo: scale down
+--~ local afmdata = tfmdata.shared.afmdata
+--~ if afmdata then
+--~ local characters = tfmdata.characters
+--~ local descriptions = tfmdata.descriptions
+--~ local unicodes = afmdata.luatex.unicodes
+--~ for u, _ in next, characters do
+--~ local name = descriptions[u].name
+--~ if name then
+--~ local p = lower(name)
+--~ if p then
+--~ local oldchr, newchr = unicodes[p], unicodes[name]
+--~ if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
+--~ characters[oldchr] = characters[newchr]
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
+--~
+--~ end
+--~
+--~ function initializers.common.install(format,feature) -- 'afm','lineheight'
+--~ initializers.base[format][feature] = initializers.common[feature]
+--~ initializers.node[format][feature] = initializers.common[feature]
+--~ end
-- -- -- -- -- --
-- expansion (hz)
@@ -16,19 +200,23 @@ fonts.expansions = fonts.expansions or { }
fonts.expansions.classes = fonts.expansions.classes or { }
fonts.expansions.vectors = fonts.expansions.vectors or { }
+local expansions = fonts.expansions
+local classes = fonts.expansions.classes
+local vectors = fonts.expansions.vectors
+
-- beware, pdftex itself uses percentages * 10
-fonts.expansions.classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 }
+classes.preset = { stretch = 2, shrink = 2, step = .5, factor = 1 }
function commands.setupfontexpansion(class,settings)
- aux.getparameters(fonts.expansions.classes,class,'preset',settings)
+ aux.getparameters(classes,class,'preset',settings)
end
-fonts.expansions.classes['quality'] = {
+classes['quality'] = {
stretch = 2, shrink = 2, step = .5, vector = 'default', factor = 1
}
-fonts.expansions.vectors['default'] = {
+vectors['default'] = {
[byte('A')] = 0.5, [byte('B')] = 0.7, [byte('C')] = 0.7, [byte('D')] = 0.5, [byte('E')] = 0.7,
[byte('F')] = 0.7, [byte('G')] = 0.5, [byte('H')] = 0.7, [byte('K')] = 0.7, [byte('M')] = 0.7,
[byte('N')] = 0.7, [byte('O')] = 0.5, [byte('P')] = 0.7, [byte('Q')] = 0.5, [byte('R')] = 0.7,
@@ -40,11 +228,11 @@ fonts.expansions.vectors['default'] = {
[byte('2')] = 0.7, [byte('3')] = 0.7, [byte('6')] = 0.7, [byte('8')] = 0.7, [byte('9')] = 0.7,
}
-function fonts.initializers.common.expansion(tfmdata,value)
+function initializers.common.expansion(tfmdata,value)
if value then
- local class = fonts.expansions.classes[value]
+ local class = classes[value]
if class then
- local vector = fonts.expansions.vectors[class.vector]
+ local vector = vectors[class.vector]
if vector then
tfmdata.stretch = (class.stretch or 0) * 10
tfmdata.shrink = (class.shrink or 0) * 10
@@ -52,7 +240,7 @@ function fonts.initializers.common.expansion(tfmdata,value)
tfmdata.auto_expand = true
local factor = class.factor or 1
local data = characters.data
- for i, chr in pairs(tfmdata.characters) do
+ for i, chr in next, tfmdata.characters do
local v = vector[i]
if not v then
local d = data[i]
@@ -80,11 +268,11 @@ end
table.insert(fonts.manipulators,"expansion")
-fonts.initializers.base.otf.expansion = fonts.initializers.common.expansion
-fonts.initializers.node.otf.expansion = fonts.initializers.common.expansion
+initializers.base.otf.expansion = initializers.common.expansion
+initializers.node.otf.expansion = initializers.common.expansion
-fonts.initializers.base.afm.expansion = fonts.initializers.common.expansion
-fonts.initializers.node.afm.expansion = fonts.initializers.common.expansion
+initializers.base.afm.expansion = initializers.common.expansion
+initializers.node.afm.expansion = initializers.common.expansion
-- -- -- -- -- --
-- protrusion
@@ -94,28 +282,32 @@ fonts.protrusions = fonts.protrusions or { }
fonts.protrusions.classes = fonts.protrusions.classes or { }
fonts.protrusions.vectors = fonts.protrusions.vectors or { }
+local protrusions = fonts.protrusions
+local classes = fonts.protrusions.classes
+local vectors = fonts.protrusions.vectors
+
-- the values need to be revisioned
-fonts.protrusions.classes.preset = { factor = 1 }
+classes.preset = { factor = 1 }
function commands.setupfontprotrusion(class,settings)
- aux.getparameters(fonts.protrusions.classes,class,'preset',settings)
+ aux.getparameters(classes,class,'preset',settings)
end
-fonts.protrusions.classes['pure'] = {
+classes['pure'] = {
vector = 'pure', factor = 1
}
-fonts.protrusions.classes['punctuation'] = {
+classes['punctuation'] = {
vector = 'punctuation', factor = 1
}
-fonts.protrusions.classes['alpha'] = {
+classes['alpha'] = {
vector = 'alpha', factor = 1
}
-fonts.protrusions.classes['quality'] = {
+classes['quality'] = {
vector = 'quality', factor = 1
}
-fonts.protrusions.vectors['pure'] = {
+vectors['pure'] = {
[0x002C] = { 0, 1 }, -- comma
[0x002E] = { 0, 1 }, -- period
@@ -126,10 +318,13 @@ fonts.protrusions.vectors['pure'] = {
[0x2014] = { 0, 0.33 }, -- emdash
[0x3001] = { 0, 1 }, -- ideographic comma 、
[0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
}
-fonts.protrusions.vectors['punctuation'] = {
+vectors['punctuation'] = {
[0x003F] = { 0, 0.20 }, -- ?
[0x00BF] = { 0, 0.20 }, -- ¿
@@ -146,6 +341,10 @@ fonts.protrusions.vectors['punctuation'] = {
[0x002D] = { 0, 0.70 }, -- hyphen
[0x2013] = { 0, 0.30 }, -- endash
[0x2014] = { 0, 0.20 }, -- emdash
+ [0x060C] = { 0, 0.70 }, -- arabic comma
+ [0x061B] = { 0, 0.50 }, -- arabic semicolon
+ [0x06D4] = { 0, 0.70 }, -- arabic full stop
+ [0x061F] = { 0, 0.20 }, -- ؟
-- todo: left and right quotes: .5 double, .7 single
@@ -165,7 +364,7 @@ fonts.protrusions.vectors['punctuation'] = {
}
-fonts.protrusions.vectors['alpha'] = {
+vectors['alpha'] = {
[byte("A")] = { .05, .05 },
[byte("F")] = { 0, .05 },
@@ -188,21 +387,22 @@ fonts.protrusions.vectors['alpha'] = {
}
-fonts.protrusions.vectors['quality'] = table.merge( {},
- fonts.protrusions.vectors['punctuation'],
- fonts.protrusions.vectors['alpha']
+vectors['quality'] = table.merge( {},
+ vectors['punctuation'],
+ vectors['alpha']
)
-function fonts.initializers.common.protrusion(tfmdata,value)
+function initializers.common.protrusion(tfmdata,value)
if value then
- local class = fonts.protrusions.classes[value]
+ local class = classes[value]
if class then
- local vector = fonts.protrusions.vectors[class.vector]
+ local vector = vectors[class.vector]
if vector then
local factor = class.factor or 1
local data = characters.data
local emwidth = tfmdata.parameters.quad
- for i, chr in pairs(tfmdata.characters) do
+ tfmdata.auto_protrude = true
+ for i, chr in next, tfmdata.characters do
local v, pl, pr = vector[i], nil, nil
if v then
pl, pr = v[1], v[2]
@@ -234,8 +434,46 @@ end
table.insert(fonts.manipulators,"protrusion")
-fonts.initializers.base.otf.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.node.otf.protrusion = fonts.initializers.common.protrusion
+initializers.base.otf.protrusion = initializers.common.protrusion
+initializers.node.otf.protrusion = initializers.common.protrusion
+
+initializers.base.afm.protrusion = initializers.common.protrusion
+initializers.node.afm.protrusion = initializers.common.protrusion
+
+function initializers.common.nostackmath(tfmdata,value)
+ tfmdata.ignore_stack_math = value
+end
+
+table.insert(fonts.manipulators,"nostackmath")
+
+initializers.base.otf.nostackmath = initializers.common.nostackmath
+initializers.node.otf.nostackmath = initializers.common.nostackmath
+
+table.insert(fonts.triggers,"itlc")
+
+function initializers.common.itlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local fontdata = tfmdata.shared.otfdata or tfmdata.shared.afmdata
+ local metadata = fontdata and fontdata.metadata
+ if metadata then
+ local italicangle = metadata.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (metadata.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.has_italic = true
+ end
+ end
+ end
+end
+
+initializers.base.otf.itlc = initializers.common.itlc
+initializers.node.otf.itlc = initializers.common.itlc
-fonts.initializers.base.afm.protrusion = fonts.initializers.common.protrusion
-fonts.initializers.node.afm.protrusion = fonts.initializers.common.protrusion
+initializers.base.afm.itlc = initializers.common.itlc
+initializers.node.afm.itlc = initializers.common.itlc
diff --git a/tex/context/base/font-fbk.lua b/tex/context/base/font-fbk.lua
index d3287c393..6c4f78a3c 100644
--- a/tex/context/base/font-fbk.lua
+++ b/tex/context/base/font-fbk.lua
@@ -6,34 +6,37 @@ if not modules then modules = { } end modules ['font-fbk'] = {
license = "see context related readme files"
}
+local cos, tan, rad, format = math.cos, math.tan, math.rad, string.format
+
+local trace_combining = false trackers.register("fonts.combining", function(v) trace_combining = v end)
+
--[[ldx--
<p>This is very experimental code!</p>
--ldx]]--
-fonts.fallbacks = fonts.fallbacks or { }
-fonts.vf.aux.combine.trace = false
+fonts.fallbacks = fonts.fallbacks or { }
local vf = fonts.vf
local tfm = fonts.tfm
vf.aux.combine.commands["enable-tracing"] = function(g,v)
- vf.aux.combine.trace = true
+ trace_combining = true
end
vf.aux.combine.commands["disable-tracing"] = function(g,v)
- vf.aux.combine.trace = false
+ trace_combining = false
end
vf.aux.combine.commands["set-tracing"] = function(g,v)
if v[2] == nil then
- vf.aux.combine.trace = true
+ trace_combining = true
else
- vf.aux.combine.trace = v[2]
+ trace_combining = v[2]
end
end
function vf.aux.combine.initialize_trace()
- if vf.aux.combine.trace then
+ if trace_combining then
return "special", "pdf: .8 0 0 rg .8 0 0 RG", "pdf: 0 .8 0 rg 0 .8 0 RG", "pdf: 0 0 .8 rg 0 0 .8 RG", "pdf: 0 g 0 G"
else
return "comment", "", "", "", ""
@@ -54,7 +57,7 @@ end
fonts.fallbacks['textcent'] = function (g)
local c = ("c"):byte()
local t = table.fastcopy(g.characters[c])
- local a = - math.tan(math.rad(g.italicangle or 0))
+ local a = - tan(rad(g.italicangle or 0))
local special, red, green, blue, black = vf.aux.combine.initialize_trace()
local quad = g.parameters.quad
if a == 0 then
@@ -71,7 +74,7 @@ fonts.fallbacks['textcent'] = function (g)
{"push"},
{"right", .5*t.width-.025*quad},
{"down", .2*t.height},
- {"special",("pdf: q 1 0 %s 1 0 0 cm"):format(a)},
+ {"special",format("pdf: q 1 0 %s 1 0 0 cm",a)},
{special, green},
{"rule", 1.4*t.height, .025*quad},
{special, black},
@@ -84,6 +87,7 @@ fonts.fallbacks['textcent'] = function (g)
-- todo: set height
t.height = 1.2*t.height
t.depth = 0.2*t.height
+ g.virtualized = true
local d = g.descriptions
return t, d and d[c]
end
@@ -91,7 +95,7 @@ end
fonts.fallbacks['texteuro'] = function (g)
local c = ("C"):byte()
local t = table.fastcopy(g.characters[c])
- local d = math.cos(math.rad(90+(g.italicangle)))
+ local d = cos(rad(90+(g.italicangle)))
local special, red, green, blue, black = vf.aux.combine.initialize_trace()
local quad = g.parameters.quad
t.width = 1.05*t.width
@@ -104,6 +108,7 @@ fonts.fallbacks['texteuro'] = function (g)
{"rule", .05*quad, .4*quad},
{special, black},
}
+ g.virtualized = true
return t, g.descriptions[c]
end
@@ -111,6 +116,10 @@ end
vf.aux.combine.force_composed = false
+local push, pop = { "push" }, { "pop" }
+
+local cache = { } -- we could make these weak
+
function vf.aux.compose_characters(g) -- todo: scaling depends on call location
-- this assumes that slot 1 is self, there will be a proper self some day
local chars, descs = g.characters, g.descriptions
@@ -120,14 +129,16 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
if xchar and xdesc then
local scale = g.factor or 1
local cap_lly = scale*xdesc.boundingbox[4]
- local ita_cor = math.cos(math.rad(90+(g.italicangle or 0)))
+ local ita_cor = cos(rad(90+(g.italicangle or 0)))
local force = vf.aux.combine.force_composed
local fallbacks = characters.fallbacks
- local special, red, green, blue, black = vf.aux.combine.initialize_trace()
- red, green, blue, black = { special, red }, { special, green }, { special, blue }, { special, black }
- local push, pop = { "push" }, { "pop" }
- local trace = vf.aux.combine.trace -- saves mem
- for i,c in pairs(characters.data) do
+ local special, red, green, blue, black
+ if trace_combining then
+ special, red, green, blue, black = vf.aux.combine.initialize_trace()
+ red, green, blue, black = { special, red }, { special, green }, { special, blue }, { special, black }
+ end
+ local done = false
+ for i,c in next, characters.data do
if force or not chars[i] then
local s = c.specials
if s and s[1] == 'char' then
@@ -138,17 +149,35 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
if cc == 'll' or cc == 'lu' or cc == 'lt' then
local acc = s[3]
local t = { }
- for k, v in pairs(charschr) do
+ for k, v in next, charschr do
if k ~= "commands" then
t[k] = v
end
end
local charsacc = chars[acc]
+--~ local ca = charsacc.category
+--~ if ca == "mn" then
+--~ -- mark nonspacing
+--~ elseif ca == "ms" then
+--~ -- mark spacing combining
+--~ elseif ca == "me" then
+--~ -- mark enclosing
+--~ else
if not charsacc then
acc = fallbacks[acc]
charsacc = acc and chars[acc]
end
if charsacc then
+ local chr_t = cache[chr]
+ if not cht_t then
+ chr_t = {"slot", 1, chr}
+ cache[chr] = chr_t
+ end
+ local acc_t = cache[acc]
+ if not acc_t then
+ acc_t = {"slot", 1, acc}
+ cache[acc] = acc_t
+ end
local cb = descs[chr].boundingbox
local ab = descs[acc].boundingbox
if cb and ab then
@@ -158,77 +187,75 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
local dx = (c_urx - a_urx - a_llx + c_llx)/2
local dd = (c_urx - c_llx)*ita_cor
if a_ury < 0 then
- -- local dy = cap_lly-a_lly
- if trace then
+ if trace_combining then
t.commands = {
push,
{"right", dx-dd},
- -- {"down", -dy}, -- added
red,
- {"slot", 1, acc},
+ acc_t,
black,
pop,
- {"slot", 1, chr},
+ chr_t,
}
else
t.commands = {
push,
{"right", dx-dd},
- -- {"down", -dy}, -- added
- {"slot", 1, acc},
+ acc_t,
pop,
- {"slot", 1, chr},
+ chr_t,
}
end
elseif c_ury > a_lly then
local dy = cap_lly-a_lly
- if trace then
+ if trace_combining then
t.commands = {
push,
{"right", dx+dd},
{"down", -dy},
green,
- {"slot", 1, acc},
+ acc_t,
black,
pop,
- {"slot", 1, chr},
+ chr_t,
}
else
t.commands = {
push,
{"right", dx+dd},
{"down", -dy},
- {"slot", 1, acc},
+ acc_t,
pop,
- {"slot", 1, chr},
+ chr_t,
}
end
else
- if trace then
+ if trace_combining then
t.commands = {
{"push"},
{"right", dx+dd},
blue,
- {"slot", 1, acc},
+ acc_t,
black,
{"pop"},
- {"slot", 1, chr},
+ chr_t,
}
else
t.commands = {
{"push"},
{"right", dx+dd},
- {"slot", 1, acc},
+ acc_t,
{"pop"},
- {"slot", 1, chr},
+ chr_t,
}
end
end
+ done = true
end
end
chars[i] = t
local d = { }
- for k, v in pairs(descs[chr]) do
+ for k, v in next, descs[chr] do
d[k] = v
end
d.name = c.adobename or "unknown"
@@ -239,6 +266,9 @@ function vf.aux.compose_characters(g) -- todo: scaling depends on call location
end
end
end
+ if done then
+ g.virtualized = true
+ end
end
end
diff --git a/tex/context/base/font-ini.lua b/tex/context/base/font-ini.lua
index 5db2973a1..248a2baca 100644
--- a/tex/context/base/font-ini.lua
+++ b/tex/context/base/font-ini.lua
@@ -10,34 +10,44 @@ if not modules then modules = { } end modules ['font-ini'] = {
<p>Not much is happening here.</p>
--ldx]]--
+local utf = unicode.utf8
+
+if not fontloader then fontloader = fontforge end
+
+fontloader.totable = fontloader.to_table
+
-- vtf comes first
-- fix comes last
-fonts = fonts or { }
+fonts = fonts or { }
+fonts.ids = fonts.ids or { } -- aka fontdata
+fonts.tfm = fonts.tfm or { }
-fonts.trace = false -- true
fonts.mode = 'base'
-fonts.private = 0xE000
+fonts.private = 0xF0000 -- 0x10FFFF
fonts.verbose = false -- more verbose cache tables
-fonts.methods = {
+fonts.methods = fonts.methods or {
base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
}
-fonts.initializers = {
+fonts.initializers = fonts.initializers or {
base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }
}
-fonts.triggers = {
+fonts.triggers = fonts.triggers or {
'mode',
'language',
'script',
'strategy',
}
-fonts.manipulators = {
+fonts.processors = fonts.processors or {
+}
+
+fonts.manipulators = fonts.manipulators or {
}
fonts.define = fonts.define or { }
@@ -48,18 +58,35 @@ fonts.define.specify.synonyms = fonts.define.specify.synonyms or { }
fonts.color = fonts.color or { }
-fonts.color.trace = false
-
-local attribute = attributes.numbers['color'] or 7 -- we happen to know this -)
-local mapping = attributes.list[attribute]
+local attribute = attributes.private('color')
+local mapping = (attributes and attributes.list[attribute]) or { }
local set_attribute = node.set_attribute
local unset_attribute = node.unset_attribute
function fonts.color.set(n,c)
--- local mc = mapping[c] if mc then unset_attribute((n,attribute) else set_attribute(n,attribute,mc) end
- set_attribute(n,attribute,mapping[c] or -1) -- also handles -1 now
+ local mc = mapping[c]
+ if not mc then
+ unset_attribute(n,attribute)
+ else
+ set_attribute(n,attribute,mc)
+ end
end
function fonts.color.reset(n)
unset_attribute(n,attribute)
end
+
+-- this will change ...
+
+function fonts.show_char_data(n)
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ if type(n) == "string" then
+ n = utf.byte(n)
+ end
+ local chr = tfmdata.characters[n]
+ if chr then
+ texio.write_nl(table.serialize(chr,string.format("U_%04X",n)))
+ end
+ end
+end
diff --git a/tex/context/base/font-ini.mkii b/tex/context/base/font-ini.mkii
index 9b9f5ac83..658d06f70 100644
--- a/tex/context/base/font-ini.mkii
+++ b/tex/context/base/font-ini.mkii
@@ -12,7 +12,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Font Macros (ini)}
+\writestatus{loading}{ConTeXt Font Macros / Initialization}
\unprotect
@@ -121,125 +121,21 @@
%%% message 14 added
-\startmessages dutch library: fonts
- title: korps
- 1: codering --
- 2: variant -- wordt geladen
- 3: onbekende variant --
- 4: korps -- is niet gedefinieerd
- 5: stijl -- is niet gedefinieerd
- 6: -- wordt geladen
- 7: onbekend formaat --
- 8: stijl -- gedefinieerd
-% 9: mapping -- is geladen
- 10: onbekende font file --
- 14: korps -- is gedefinieerd (kan beter globaal plaatsvinden)
-\stopmessages
-
-\startmessages english library: fonts
- title: bodyfont
- 1: coding --
- 2: variant -- is loaded
- 3: unknown variant --
- 4: bodyfont -- is not defined
- 5: style -- is not defined
- 6: -- is loaded
- 7: unknown format --
- 8: style -- defined
-% 9: mapping -- is loaded
- 10: unknown font file --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages german library: fonts
- title: Fliesstext
- 1: Kodierung --
- 2: Variante -- ist geladen
- 3: Unbekannte Variante --
- 4: Fliesstext -- ist nicht definiert
- 5: Stil -- ist nicht definiert
- 6: -- ist geladen
- 7: unbekanntes Format --
- 8: Stil -- definiert
-% 9: Map -- ist geladen
- 10: unbekanntes Font --
- 14: Fliesstext -- wurde definiert (besser waere globale Definition)
-\stopmessages
-
-\startmessages czech library: fonts
- title: zakladnifont
- 1: kodovani --
- 2: varianta -- je nactena
- 3: neznama varianta --
- 4: zakladni font -- neni definovan
- 5: styl -- neni definovan
- 6: -- je nacten
- 7: neznamy format --
- 8: styl -- definovan
-% 9: mapovani -- je nacteno
- 10: neznamy font --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages italian library: fonts
- title: font del corpo
- 1: codifica --
- 2: variante -- caricata
- 3: variante sconosciuta --
- 4: corpo del testo -- non definito
- 5: stile -- non definito
- 6: -- caricato
- 7: formato sconosciuto --
- 8: stile -- definito
-% 9: mappatura -- caricata
- 10: file di font sconosciuto --
- 14: corpo del testo -- definito (sarebbe meglio globale)
-\stopmessages
-
-\startmessages norwegian library: fonts
- title: hovedfont
- 1: koding --
- 2: variant -- er lest inn
- 3: ukjent variant --
- 4: hovedfont -- er ikke definert
- 5: stil -- er ikke definert
- 6: -- er lest inn
- 7: ukjent format --
- 8: stil -- definert
-% 9: avbildning -- er lest inn
- 10: ukjent fontfil --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages romanian library: fonts
- title: corp de litere
- 1: codificarea --
- 2: varianta -- este incarcata
- 3: varianta necunoscuta --
- 4: corpul de litere -- nu este definit
- 5: stilul -- nu este definit
- 6: -- este incarcat
- 7: format necunoscut --
- 8: stilul -- definit
-% 9: maparea -- este incarcat
- 10: fisier font necunoscut --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages french library: fonts
- title: corps de texte
- 1: encodage --
- 2: la variante -- est chargée
- 3: variante -- inconnue
- 4: policecorps -- n'est pas définie
- 5: le style -- n'est pas défini
- 6: -- est chargé
- 7: format -- inconnu
- 8: style -- défini
-% 9: mapping -- is loaded
- 10: fichier de police -- inconnu
- 14: policecorps -- est défini (une définition globale pourrait être plus adéquat)
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D This module is one of the oldest modules of \CONTEXT. The
%D macros below evolved out of the \PLAIN\ \TEX\ macros and
@@ -682,8 +578,6 @@
%D
%D We can fix this by defining
-\let\normalmathop\mathop
-
\unexpanded\def\mathop
{\normalmathop
\bgroup
@@ -694,8 +588,6 @@
%D \TEX\ primitive \type{\hbox}:
%D
%D \starttyping
-%D \let\normalhbox=\hbox
-%D
%D \def\hbox{\ifmmode\mbox\else\normalhbox\fi}
%D \stoptyping
%D
@@ -875,6 +767,7 @@
\def\@shortstyle@ {@f@sh@} % short style prefix (rm etc)
\def\@letter@ {@f@le@} % first alternative typeface
\def\@noletter@ {@f@no@} % second alternative typeface
+\def\@fontclass@ {@f@cl@} % fontclass
%D The families can be grouped into math specific ones and
%D more text related families, although text ones can be
@@ -1060,9 +953,7 @@
%D separated list. Appart from practical limitations one can
%D define as many styles as needed.
-\let\stylelist=\empty
-
-\def\fontsizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
+\def\fontrelativesizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
%D \macros
%D {magfactor,magfactorhalf}
@@ -1099,7 +990,7 @@
%D \stoptable
\def\magstep#1% \relax removed, otherwise space after it sticks, else added
- {\ifcase#1 \@m\or1200\or1440\or1728\or2074\or2488\or\@m\fi}
+ {\ifcase#1 1000\or1200\or1440\or1728\or2074\or2488\or1000\fi}
\def\magstephalf
{1095}
@@ -1287,25 +1178,21 @@
% [encoding=ec]
% \definedfont[blabla] test \currentencoding/\fontfile \par
-\beginOLDTEX
-
- \def\checkfontfilename
- {\expandafter\docheckfontfilename\fontfile:\empty:\empty\relax}
-
- \def\docheckfontfilename#1:#2:#3#4\relax
- {\edef\!!stringa{#1}%
- \edef\!!stringb{#2}%
- \ifx\!!stringb\empty
- \edef\checkedfontfile{\!!stringa}%
- \else\ifx\!!stringa\v!file
- \edef\checkedfontfile{"\!!stringb"}%
- \else\ifx\!!stringa\v!name
- \edef\checkedfontfile{"\!!stringb"}%
- \else
- \edef\checkedfontfile{\!!stringb}%
- \fi\fi\fi}
-
-\endOLDTEX
+\def\checkfontfilename
+ {\expandafter\docheckfontfilename\fontfile:\empty:\empty\relax}
+
+\def\docheckfontfilename#1:#2:#3#4\relax
+ {\edef\!!stringa{#1}%
+ \edef\!!stringb{#2}%
+ \ifx\!!stringb\empty
+ \edef\checkedfontfile{\!!stringa}%
+ \else\ifx\!!stringa\v!file
+ \edef\checkedfontfile{"\!!stringb"}%
+ \else\ifx\!!stringa\v!name
+ \edef\checkedfontfile{"\!!stringb"}%
+ \else
+ \edef\checkedfontfile{\!!stringb}%
+ \fi\fi\fi}
% \definefontfeature[default] [liga=yes,texligatures=yes,texquotes=yes]
% \definefontfeature[default-caps][liga=yes,texligatures=yes,texquotes=yes,smcp=yes,script=latn]
@@ -1389,156 +1276,6 @@
%
% \stoptext
-% xetex / todo: disable default features ! file:, name:, [], "" etc etc
-
-\beginXETEX
-
- % for some reason xetex does not support [filename] for tfm files and
- % quotes also behave kind of strange " vs ' vs [ vs ...
-
- % we need to use the specs,
- %
- % \font\myfont = msam7 % ok
- % \font\myfont = "msam7" % also ok
- % \font\myfont = "msam7" at 8pt % error
-
- \ifx\suppressfontnotfounderror\undefined
-
- \newcount\xetexsavedinteractionmode
- \newbox \xetexcrappyhackbox
-
- \def\doiffoundxetexfontelse#1#2%
- {\xetexsavedinteractionmode\interactionmode
- \batchmode
- \setbox\xetexcrappyhackbox\vbox{\par}% resets error count
- \font\xetextempfont=#2\somefontspec\relax
- \edef\xetextempfont{\fontname\xetextempfont}%
- \ifx\xetextempfont\nullfontname
- \interactionmode\xetexsavedinteractionmode
- %\writestatus\m!fonts{fails #1: #2 (\xetextempfont)}%
- \expandafter\secondoftwoarguments
- \else
- \interactionmode\xetexsavedinteractionmode
- %\writestatus\m!fonts{succeeds #1: #2 (\xetextempfont)}%
- \expandafter\firstoftwoarguments
- \fi}
-
- \else
-
- \def\doiffoundxetexfontelse#1#2%
- {\suppressfontnotfounderror\plusone
- \font\xetextempfont=#2\somefontspec\relax
- \suppressfontnotfounderror\zerocount
- \edef\xetextempfont{\fontname\xetextempfont}%
- \ifx\xetextempfont\nullfontname
- %\writestatus\m!fonts{fails #1: #2 (\xetextempfont)}%
- \expandafter\secondoftwoarguments
- \else
- %\writestatus\m!fonts{succeeds #1: #2 (\xetextempfont)}%
- \expandafter\firstoftwoarguments
- \fi}
-
- \fi
-
- \def\docheckfontfilenameprefix#1:#2:#3#4\relax
- {\edef\!!stringa{#1}%
- \edef\!!stringb{#2}%
- \ifx\!!stringb\empty
- % no prefix
- \let\checkedfontfile\!!stringa
- \doiffoundxetexfontelse{1a}{\checkedfontfile\checkedfontfeatures}
- {\edef\checkedfontfile{\checkedfontfile\checkedfontfeatures}}
- {\doiffoundxetexfontelse{1b}{"\checkedfontfile\checkedfontfeatures"}
- {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
- {\doiffoundxetexfontelse{1c}{"[\checkedfontfile]\checkedfontfeatures"}
- {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
- {}}}%
- \else\ifx\!!stringa\v!file
- % force file, only file check when no spaces
- \let\checkedfontfile\!!stringb
- \doiffoundxetexfontelse{2b}{"[\checkedfontfile]\checkedfontfeatures"}
- {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
- {\doiffoundxetexfontelse{2c}{"\checkedfontfile\checkedfontfeatures"}
- {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
- {}}%
- \else\ifx\!!stringa\v!name
- % force name, always lookup by xetex itself, "" forces otf/ttf/type1
- \edef\checkedfontfile{"\!!stringb\checkedfontfeatures"}%
- \else
- % whatever, maybe even xetex spec, forget about features
- \edef\checkedfontfile{"\!!stringa\!!stringb"}%
- \fi\fi\fi}
-
- \def\checkfontfilename% -- todo: integrate so that we call do.. directly
- {\expandafter\docheckfontfilename\fontfile*\empty*\relax}
-
- \def\docheckfontfilename#1*#2#3*#4\relax % class overrules file
- {\edef\checkedfontfeatures
- {\expandafter\ifx\csname\fontclass\s!features\endcsname\empty
- \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
- \else\expandafter\ifx\csname\fontclass\s!features\endcsname\relax % redundant, will go away
- \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
- \else
- \csname\fontclass\s!features\endcsname
- \fi\fi}%
- \ifx\checkedfontfeatures\empty
- % done
- \else
- \edef\checkedfontfeatures{\executeifdefined{\??fa\checkedfontfeatures}\empty}%
- \ifx\checkedfontfeatures\empty
- % done
- \else
- \let\convertedfontfeatures\empty
- \processcommacommand[\checkedfontfeatures]\doconvertfontfeatures % raw
- \ifx\convertedfontfeatures\empty
- \let\checkedfontfeatures\empty
- \else
- \edef\checkedfontfeatures{:\convertedfontfeatures}%
- \fi
- \fi
- \fi
- \docheckfontfilenameprefix#1:\empty:\empty\relax
- \doshowcheckedfontfeatures}
-
- \def\dodoconvertfontfeatures#1=#2#3=#4\relax
- {\ifx#2\empty
- % invalid feature
- \else\ifcsname @xtx@#1@#2#3\endcsname
- \expandafter\ifx\csname @xtx@#1@#2#3\endcsname\empty\else
- \edef\convertedfontfeatures{\convertedfontfeatures\csname @xtx@#1@#2#3\endcsname;}%
- \fi
- \else
- \edef\!!stringa{#1}%
- \edef\!!stringb{#2#3}%
- \edef\convertedfontfeatures
- {\convertedfontfeatures
- \ifx\!!stringb\v!yes
- +\!!stringa
- \else\ifx\!!stringb\v!no
- -\!!stringa
- \else
- \!!stringa=\!!stringb
- \fi\fi;}%
- \fi\fi}
-
- \def\doconvertfontfeatures#1%
- {\dodoconvertfontfeatures#1=\empty=\relax}
-
- \def\remapfontfeature #1 #2 #3 {\setevalue{@xtx@#1@#2}{#3}}
-
- % this may move to another file, maybe font-xtx
-
- \remapfontfeature tlig yes mapping=tlig
- %remapfontfeature tlig no mapping=
- \remapfontfeature trep yes {}
- \remapfontfeature trep no {}
- \remapfontfeature texligatures yes mapping=tlig
- %remapfontfeature texligatures no mapping=
- %remapfontfeature texquotes yes mapping=tex-text
- %remapfontfeature texquotes no mapping=
-
-\endXETEX
-
\let\doshowcheckedfontfeatures\relax
\def\showcheckedfontfeatures
@@ -1550,7 +1287,7 @@
\def\donoparsefontspec % #1 == \cs
{\edef\fontfile{\truefontname\somefontname}%
- \ifx\fontfile\s!unknown \let\fontfile\defaultfontfile \fi
+ \ifx\fontfile\s!unknown \let\fontfile\defaultfontfile \fi % can for instance happen with MathGamma
\updatefontparameters
\checkfontfilename
\edef\lastfontname{\checkedfontfile\somefontspec}%
@@ -1606,10 +1343,6 @@
\edef\nullfontname {\fontname\nullfont}
\edef\dummyfontname {font\strippedcsname\\}
-\beginXETEX
- \def\defaultfontfile{lmtypewriter10-regular}
-\endXETEX
-
%D \macros
%D {everyfont,everyfontswitch}
%D
@@ -1688,12 +1421,10 @@
\def\classfont#1#2{#1#2} % \definefont[whatever][\classfont{xx}{yy} at 10pt]
-\beginOLDTEX
-
\def\definefontsynonym[#1]#2[#3]%
{\edef\@@fontfile{#3}%
\@EA\let\csname\??ff\fontclass#1\endcsname\@@fontfile
- \doifnextcharelse[\dodefinefontsynonym\donothing}
+ \doifnextoptionalelse\dodefinefontsynonym\donothing}
\def\dodefinefontsynonym[#1]%
{\edef\@@fontdata{#1}%
@@ -1703,48 +1434,6 @@
\getglobalfontparameters
\fi \fi}
-\endOLDTEX
-
-% We need to move the feature into the filename else it may be
-% overloaded by another reference. For instance the definition of
-% a regular and caps variant can use the same font.
-
-% We could use an indirect method ... store in 'array' and refer to
-% slot.
-
-\beginNEWTEX
-
-\def\definefontsynonym[#1]#2[#3]%
- {\edef\@@fontname{#1}%
- \edef\@@fontfile{#3}%
- \doifnextcharelse[\dodefinefontsynonym\nodefinefontsynonym}
-
-\def\nodefinefontsynonym
- {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile}
-
-\def\dodefinefontsynonym[#1]%
- {\edef\@@fontdata{#1}%
- \ifx\@@fontdata\empty
- \nodefinefontsynonym
- \else
- \ifx\fontclass\empty
- \getfontparameters
- \else
- \getglobalfontparameters
- \fi
- \ifcsname\??ff\@@fontfile\s!features\endcsname
- \@EA\edef\csname\??ff\fontclass\@@fontname\endcsname{\@@fontfile*\csname\??ff\@@fontfile\s!features\endcsname}%
- \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
- \else
- \nodefinefontsynonym
- \fi
- \fi}
-
-\endNEWTEX
-
-% \def\resetfontsynonym[#1]% fails
-% {\letbeundefined{\??ff\fontclass#1}\letbeundefined{\??ff#1}}
-
\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
\def\setupfontsynonym
@@ -1776,8 +1465,6 @@
\csname\??ff#2\endcsname
\fi\fi\fi\fi}
-\beginOLDTEX
-
\def\truefontname#1%
{\ifcsname\??ff\fontclass#1\endcsname
\@EA\truefontname\csname\??ff\fontclass#1\endcsname
@@ -1787,86 +1474,6 @@
#1%
\fi\fi}
-\endOLDTEX
-
-\beginNEWTEX
-
-% simple version
-%
-% \def\truefontname#1%
-% {\@EA\dotruefontname#1*\relax}
-%
-% \def\dotruefontname#1*#2\relax
-% {\ifcsname\??ff\fontclass#1\endcsname
-% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
-% \else\ifcsname\??ff#1\endcsname
-% \@EA\truefontname\csname\??ff#1\endcsname
-% \else
-% #1%
-% \fi\fi}
-%
-% last counts
-%
-% \def\truefontname#1%
-% {\@EA\dotruefontname#1*\empty*\relax}
-%
-% \def\dotruefontname#1*#2#3*#4\relax
-% {\ifcsname\??ff\fontclass#1\endcsname
-% \ifx#2\empty
-% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
-% \else
-% \@EA\truefontname\csname\??ff\fontclass#1\endcsname*#2#3%
-% \fi
-% \else\ifcsname\??ff#1\endcsname
-% \ifx#2\empty
-% \@EA\truefontname\csname\??ff#1\endcsname
-% \else
-% \@EA\truefontname\csname\??ff#1\endcsname*#2#3%
-% \fi
-% \else
-% \ifx#2\empty
-% #1%
-% \else
-% #1*#2#3%
-% \fi
-% \fi\fi}
-%
-% first counts
-
-\def\truefontname#1%
- {\@EA\dotruefontname#1*\empty*\relax}
-
-\def\dotruefontname#1*#2#3*#4\relax
- {\ifcsname\??ff\fontclass#1\endcsname
- \ifx#2\empty
- \@EA\truefontname\csname\??ff\fontclass#1\endcsname
- \else
- \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
- \fi
- \else\ifcsname\??ff#1\endcsname
- \ifx#2\empty
- \@EA\truefontname\csname\??ff#1\endcsname
- \else
- \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
- \fi
- \else
- #1\ifx#2\empty\else*#2#3\fi
- \fi\fi}
-
-\def\redotruefontname#1%
- {\@EA\dodotruefontname#1*\relax}
-
-\def\dodotruefontname#1*#2\relax
- {\ifcsname\??ff\fontclass#1\endcsname
- \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
- \else\ifcsname\??ff#1\endcsname
- \@EA\redotruefontname\csname\??ff#1\endcsname
- \else
- #1%
- \fi\fi}
-
-\endNEWTEX
-
\def\expandfontsynonym#1#2% #2 := onelevelexpansion(#1)
{\ifcsname\??ff\fontclass#2\endcsname
\expandafter\def\expandafter#1\expandafter{\csname\??ff\fontclass#2\endcsname}%
@@ -2109,26 +1716,24 @@
%D To be documented.
-\let\sizelist\empty
+\let\fontsizelist\empty
+\let\fontstylelist\empty
\def\definefontsize[#1]% sneller met toks
- {\addtocommalist{#1}\sizelist
+ {\addtocommalist{#1}\fontsizelist
\def\docommand##1%
{\def\dodocommand####1%
{\def\dododocommand########1%
%{\checkbodyfont{}{########1}{####1}{##1}}%
{\checkbodyfont{########1}{####1}{##1}}%
- \processcommacommand[\stylelist]\dododocommand}%
- \processcommacommand[\alternativelist]\dodocommand}%
- \processcommacommand[\sizelist]\docommand}
-
-\def\alternativetextlist{\c!tf,\c!bf,\c!it,\c!sl,\c!bs,\c!bi,\c!sc}
-\def\alternativemathlist{\c!mr,\c!mi,\c!sy,\c!ex,\c!ma,\c!mb}
+ \processcommacommand[\fontstylelist]\dododocommand}%
+ \processcommacommand[\fontalternativelist]\dodocommand}%
+ \processcommacommand[\fontsizelist]\docommand}
-\let\alternativelist\alternativetextlist % upward compatible
+\def\fontalternativetextlist{\c!tf,\c!bf,\c!it,\c!sl,\c!bs,\c!bi,\c!sc}
+\def\fontalternativemathlist{\c!mr,\c!mi,\c!sy,\c!ex,\c!ma,\c!mb}
-%\definefontsize[\c!a] \definefontsize[\c!b]
-%\definefontsize[\c!c] \definefontsize[\c!d]
+\let\fontalternativelist\fontalternativetextlist % upward compatible
%D \macros
%D {currentfontscale,currentfontbodyscale}
@@ -2268,7 +1873,7 @@
\scratchdimen\csname\??ft\s!default##1\endcsname\scratchdimen
\normalizebodyfontsize\scratchdimen\to\tempbodyfontsize
\setevalue{\??ft#2#1##1}{\tempbodyfontsize}}%
- \processcommacommand[\fontsizelist]\docommand
+ \processcommacommand[\fontrelativesizelist]\docommand
\copyparameters
[\??ft#2#1][\??ft\s!default]
[\c!interlinespace,\c!em]}%
@@ -2595,7 +2200,7 @@
% \scratchdimen\csname\??ft\s!default##1\endcsname\scratchdimen
% \normalizebodyfontsize\scratchdimen\to\!!stringa
% \letvalue{\??ft#1##1}\!!stringa}}%
-% \processcommacommand[\fontsizelist]\docommand
+% \processcommacommand[\fontrelativesizelist]\docommand
% \let\c!text\c!savedtext
% \ifdone
% \donefalse
@@ -2605,7 +2210,7 @@
% {\doifdefined{\s!default\s!default##1}
% {\donetrue\getvalue{\s!default\s!default##1}{#1}{##1}}}%
% \processcommacommand
-% [\stylelist]
+% [\fontstylelist]
% \defineunknownbodyfont
% \ifdone
% \setvalue{\@size@#1}{\docompletefontswitch[#1]}%
@@ -2614,7 +2219,7 @@
% \def\defineunknownsubfont##1%
% {\doifundefined{\@size@\getvalue{\??ft#1##1}}
% {\defineunknownfont{\getvalue{\??ft#1##1}}}}%
-% \processcommacommand[\fontsizelist]\defineunknownsubfont
+% \processcommacommand[\fontrelativesizelist]\defineunknownsubfont
% \definingunknownfontfalse
% \fi
% \fi
@@ -2659,19 +2264,19 @@
{\let\c!savedtext\c!text
\let\c!text\s!text
\donefalse
- \processcommacommand[\fontsizelist]{\dodefineunknownfont{#1}}%
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownfont{#1}}%
\let\c!text\c!savedtext
\ifdone
\donefalse
\processcommacommand
- [\stylelist]
+ [\fontstylelist]
{\dodefineunknownbodyfont{#1}}%
\ifdone
\donefalse
\setvalue{\@size@#1}{\docompletefontswitch[#1]}%
\ifdefiningunknownfont \else
\definingunknownfonttrue
- \processcommacommand[\fontsizelist]{\dodefineunknownsubfont{#1}}%
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownsubfont{#1}}%
\definingunknownfontfalse
\fi
\fi
@@ -2683,7 +2288,7 @@
% \def\defineunknownfontstyles#1%
% {\def\defineunknownbodyfont##1% see ***
% {\executeifdefined{\s!default\s!default##1}\gobbletwoarguments{#1}{##1}}%
-% \rawprocesscommacommand[\stylelist]\defineunknownbodyfont}
+% \rawprocesscommacommand[\fontstylelist]\defineunknownbodyfont}
%D These macros show that quite some definitions take place.
%D Fonts are not loaded yet! This means that at format
@@ -2741,8 +2346,8 @@
%D size and the local (sometimes in the textflow) size. We
%D store these dimensions in two \DIMENSION\ registers.
-\newdimen\globalbodyfontsize \globalbodyfontsize=12pt
-\newdimen\localbodyfontsize \localbodyfontsize =\globalbodyfontsize
+\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
+\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
%D \macros
%D {bodyfontsize}
@@ -2776,27 +2381,37 @@
%D often not the way users specify the bodyfont size. Therefore
%D we also store the normalized value.
-\chardef\fontdigits=1
+\chardef\fontdigits=2 % was 1
+
+% \def\normalizebodyfontsize#1\to#2%
+% {\scratchdimen#1\relax
+% \ifcase\fontdigits\advance\scratchdimen.5\points\fi
+% \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen00\to#2}
+%
+% \def\donormalizedbodyfontsize#1.#2#3#4\to#5% \points ?
+% {\edef#5%
+% {#1%
+% \ifcase\fontdigits\or
+% \ifcase#2 \else.#2\fi % and not: \ifcase#2\else ...
+% \else
+% \ifcase#2#3 \else.#2\ifcase#3 \else#3\fi\fi % not: \ifcase#2#3\else ...
+% \fi
+% \s!pt}}
\def\normalizebodyfontsize#1\to#2%
- {\scratchdimen#1\relax
- \ifcase\fontdigits\advance\scratchdimen.5\points\fi
- \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen00\to#2}
+ {\scratchdimen\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax
+ \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen000\to#2}
-\def\donormalizedbodyfontsize#1.#2#3#4\to#5% \points ?
- {\edef#5%
+\def\donormalizedbodyfontsize#1.#2#3#4#5\to#6% \points ?
+ {\edef#6% not \ifcase#2\else due to \relax adding
{#1%
- \ifcase\fontdigits\or
- \ifcase#2 \else.#2\fi % and not: \ifcase#2\else ...
- \else
- \ifcase#2#3 \else.#2\ifcase#3 \else#3\fi\fi % not: \ifcase#2#3\else ...
+ \ifcase\fontdigits
+ \or \ifcase#2 \else .#2\fi % 1
+ \or \ifcase#2#3 \else .#2\ifcase#3 \else #3\fi\fi % 2
+ \else \ifcase#2#3#4 \else .#2\ifcase#4 \ifcase#3 \else#3\fi \else#3#4\fi\fi % 3
\fi
\s!pt}}
-\normalizebodyfontsize\bodyfontsize\to\normalizedglobalbodyfontsize
-\normalizebodyfontsize\bodyfontsize\to\normalizedlocalbodyfontsize
-\normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
-
%D To be internationalized:
\def\korpsgrootte {\bodyfontsize}
@@ -3018,8 +2633,16 @@
\let\fontclass\empty \let\globalfontclass\fontclass
+% \def\setcurrentfontclass#1%
+% {\edef\fontclass{#1}}
+
+\def\registerfontclass#1%
+ {\letgvalue{\@fontclass@#1}\v!yes} % global ?
+
\def\setcurrentfontclass#1%
- {\edef\fontclass{#1}}
+ {\ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \fi}
\let\defaultfontstyle \c!rm
\let\defaultfontalternative \c!tf
@@ -3317,9 +2940,9 @@
%D \stoptyping
\def\dodefinefontstyle[#1][#2]%
- {\rawdoifinsetelse{#2}{\stylelist}
+ {\rawdoifinsetelse{#2}{\fontstylelist}
{}%\debuggerinfo\m!fonts{unknown style #2}}
- {\addtocommalist{#2}\stylelist
+ {\addtocommalist{#2}\fontstylelist
\showmessage\m!fonts8{#2\space (#1)}}%
% check kan hier
\def\docommand##1%
@@ -4389,7 +4012,7 @@
%D {bordermatrix}
%D
%D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
-%D the \DIMENSION\ \type{\p@renwd}. This value is derived from
+%D the \DIMENSION\ \type{\mathparentwd}. This value is derived from
%D the width of \type{\tenrm B}, so let's take care of it now:
\let\normalbordermatrix=\bordermatrix
@@ -4397,7 +4020,7 @@
\def\bordermatrix%
{\bgroup
\setbox0\hbox{\getvalue{\textface\c!mm\c!ex}B}%
- \global\p@renwd\wd0\relax
+ \global\mathparentwd\wd0\relax
\egroup
\normalbordermatrix}
@@ -4678,6 +4301,7 @@
%D So far.
+\definefontstyle [\c!mm] [\c!mm]
\definefontstyle [\c!rm,\v!roman,\v!serif,\v!regular] [\c!rm]
\definefontstyle [\c!ss,\v!sansserif,\v!sans,\v!support] [\c!ss]
\definefontstyle [\c!tt,\v!teletype,\v!type,\v!mono] [\c!tt]
@@ -4800,24 +4424,6 @@
\def\fontvariant#1#2{\executeifdefined{\??fv#1#2}\empty}
-% original:
-%
-% \def\variant[#1]%
-% {\expanded{\definedfont
-% [\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}}
-% at \currentfontscale\bodyfontsize]}}
-%
-% \beginXETEX \font
-%
-% \def\variant[#1]%
-% {\font\variantfont\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}}
-% at \currentfontscale\bodyfontsize
-% \variantfont}
-%
-% \endXETEX
-%
-% better
-
\def\dosetscaledfont
{\checkrelativefontsize\fontstyle
\scaledfont\currentfontscale\bodyfontsize
@@ -4830,16 +4436,6 @@
at \scaledfont]}%
\ignoreimplicitspaces}
-\beginXETEX \font
-
- \unexpanded\def\variant[#1]%
- {\dosetscaledfont
- \font\variantfont\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}}
- at \scaledfont
- \variantfont}
-
-\endXETEX
-
\ifx\Var\undefined \let\Var\variant \fi
%D By default we load the Computer Modern Roman fonts (but
@@ -4847,7 +4443,7 @@
%D bodyfont. Sans serif and teletype are also available and
%D can be called for by \type{\ss} and \type{\tt}.
-\setupbodyfont [unk, rm]
+% \setupbodyfont [unk, rm]
%D Also needed is:
@@ -4889,4 +4485,83 @@
\egroup\expandafter\firstoftwoarguments
\fi}
+%D New commands (not yet interfaced):
+
+\def\style[#1]% for inline usage, like \color
+ {\groupedcommand{\ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}{}}
+
+\def\startstyle[#1]%
+ {\begingroup
+ \ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}
+
+\def\stopstyle
+ {\endgroup}
+
+%D Still experimental (might even go away).
+
+% \definestylecollection[mine]
+
+% \definestyleinstance[mine][default][sorry]
+% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
+% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
+% \definestyleinstance[mine][bf][\sl]
+% \definestyleinstance[mine][sl][\tt]
+
+% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
+
+\definesystemvariable{sx}
+
+\def\definestylecollection
+ {\dosingleargument\dodefinestylecollection}
+
+\def\dodefinestylecollection[#1]%
+ {\iffirstargument
+ \unexpanded\setvalue{#1}{\styleinstance[#1]}%
+ \def\docommand##1%
+ {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
+ \processcommacommand[\fontalternativelist,\s!default]\dodocommand}%
+ \processcommacommand[\fontstylelist,\s!default]\docommand
+ \fi}
+
+\def\definestyleinstance
+ {\doquadrupleargument\dodefinestyleinstance}
+
+\def\dodefinestyleinstance[#1][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
+ {\iffirstargument
+ \doifundefined{#1}{\definestylecollection[#1]}%
+ \fi
+ \iffourthargument
+ \setvalue{\??sx#1:#2:#3}{#4}%
+ \else\ifthirdargument
+ \setvalue{\??sx#1::#2}{#3}%
+ \else\ifsecondargument
+ \letvalue{\??sx#1::#2}\empty
+ \fi\fi\fi}
+
+\unexpanded\def\styleinstance[#1]% will be faster
+ {%\begingroup\expanded{\infofont[#1:\fontstyle:\fontalternative]}\endgroup
+ \executeifdefined{\??sx#1:\fontstyle:\fontalternative}%
+ {\executeifdefined{\??sx#1:\fontstyle:\s!default}%
+ {\executeifdefined{\??sx#1::\fontalternative}
+ {\getvalue {\??sx#1::\s!default}}}}}
+
+% \unexpanded\def\styleinstance[#1]%
+% {\csname\??sx#1%
+% \ifcsname:\fontstyle:\fontalternative\endcsname
+% :\fontstyle:\fontalternative
+% \else\ifcsname:\fontstyle:\s!default\endcsname
+% :\fontstyle:\s!default
+% \else\ifcsname::\fontalternative\endcsname
+% ::\fontalternative
+% \else\ifcsname::\s!default\endcsname
+% ::\s!default
+% \else
+% % nothing, \relax
+% \fi\fi\fi\fi
+% \endcsname}
+
+%D \Compatibility with \MKIV:
+
+\def\somefontsize{\scaledfont}
+
\protect \endinput
diff --git a/tex/context/base/font-ini.mkiv b/tex/context/base/font-ini.mkiv
index 3e2e57145..4d0d92fc5 100644
--- a/tex/context/base/font-ini.mkiv
+++ b/tex/context/base/font-ini.mkiv
@@ -12,26 +12,64 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% simplification ... we no longer deal with specific mmtfa specifications
-% \rm\bf --> \song
-% \rm\it --> \kai
-% \ss\it --> \kai
-% \tt\bf --> \hei
+% todo: always fontclass, then less testing
-\writestatus{loading}{Context Font Macros (ini)}
+% \starttext
+% \definefontfeature[basekerned][default][mode=base]
+% \definefontfeature[nodekerned][default][mode=node]
+% \definefontfeature[nonekerned][default][mode=base,kern=no]
+% \setupcolors[state=start]
+% \startoverlay
+% {\vbox{\red \definedfont[Serif*nonekerned at 12pt]\input tufte }}
+% {\vbox{\blue \definedfont[Serif*basekerned at 12pt]\input tufte }}
+% {\vbox{\green\definedfont[Serif*nodekerned at 12pt]\input tufte }}
+% \stopoverlay
+% \stoptext
+
+% \enabletrackers[otf.kerns]
+%
+% \definefontfeature[withkern][default][mode=node]
+% \definefontfeature[nokern] [default][mode=node,kern=no]
+% \definefontfeature[single] [default][mode=node,cpsp=yes]
+% \definefontfeature[simple] [default][mode=node,cpsp=yes,kern=no]
+%
+% {\definedfont[Serif*default] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*nokern] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*single] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+% {\definedfont[Serif*simple] [FGFGFGFGFGFGFGFGFGFGFGFGFG ABCDEFGHIJKLMNOPQRSTUVWXYZ] \par}
+
+% figure out why \fontbody is not expanded
+
+\writestatus{loading}{ConTeXt Font Macros / Initialization}
\registerctxluafile{font-ini}{1.001}
+\registerctxluafile{node-fnt}{1.001} % here
\registerctxluafile{font-enc}{1.001}
\registerctxluafile{font-map}{1.001}
\registerctxluafile{font-syn}{1.001}
+\registerctxluafile{font-log}{1.001}
\registerctxluafile{font-tfm}{1.001}
\registerctxluafile{font-afm}{1.001}
-\registerctxluafile{font-otf}{1.001}
+\registerctxluafile{font-cid}{1.001} % cid maps
+\registerctxluafile{font-ott}{1.001} % otf tables
+\registerctxluafile{font-otf}{1.001} % otf main
+\registerctxluafile{font-otd}{1.001} % otf dynamics
+\registerctxluafile{font-oti}{1.001} % otf initialization
+\registerctxluafile{font-otb}{1.001} % otf main base
+\registerctxluafile{font-otn}{1.001} % otf main node
+\registerctxluafile{font-ota}{1.001} % otf analyzers
+\registerctxluafile{font-otp}{1.001} % otf pack
+\registerctxluafile{font-otc}{1.001} % otf context
\registerctxluafile{font-vf} {1.001}
\registerctxluafile{font-def}{1.001}
+\registerctxluafile{font-ctx}{1.001}
+\registerctxluafile{font-xtx}{1.001}
\registerctxluafile{font-fbk}{1.001}
\registerctxluafile{font-ext}{1.001}
\registerctxluafile{font-pat}{1.001}
+\registerctxluafile{font-chk}{1.001}
\unprotect
@@ -107,10 +145,10 @@
%D
%D A couple of relatively new macros:
-\newevery \everydefinedfont \relax % not ot be confused with \everydefinefont
+% \newtoks \everydefinedfont % not ot be confused with \everydefinefont
\def\dodefinedfont[#1]%
- {\iffirstargument\definefont[thedefinedfont][#1]\fi
+ {\iffirstargument\definefont[thedefinedfont][#1]\fi % we can speed this one up
\csname thedefinedfont\endcsname
\the\everydefinedfont}
@@ -132,158 +170,10 @@
\egroup\expandafter\secondoftwoarguments
\fi}
-%%% message 14 added
-
-\startmessages dutch library: fonts
- title: korps
- 1: codering --
- 2: variant -- wordt geladen
- 3: onbekende variant --
- 4: korps -- is niet gedefinieerd
- 5: stijl -- is niet gedefinieerd
- 6: -- wordt geladen
- 7: onbekend formaat --
- 8: stijl -- gedefinieerd
-% 9: mapping -- is geladen
- 10: onbekende font file --
- 14: korps -- is gedefinieerd (kan beter globaal plaatsvinden)
-\stopmessages
-
-\startmessages english library: fonts
- title: bodyfont
- 1: coding --
- 2: variant -- is loaded
- 3: unknown variant --
- 4: bodyfont -- is not defined
- 5: style -- is not defined
- 6: -- is loaded
- 7: unknown format --
- 8: style -- defined
-% 9: mapping -- is loaded
- 10: unknown font file --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages german library: fonts
- title: Fliesstext
- 1: Kodierung --
- 2: Variante -- ist geladen
- 3: Unbekannte Variante --
- 4: Fliesstext -- ist nicht definiert
- 5: Stil -- ist nicht definiert
- 6: -- ist geladen
- 7: unbekanntes Format --
- 8: Stil -- definiert
-% 9: Map -- ist geladen
- 10: unbekanntes Font --
- 14: Fliesstext -- wurde definiert (besser waere globale Definition)
-\stopmessages
-
-\startmessages czech library: fonts
- title: zakladnifont
- 1: kodovani --
- 2: varianta -- je nactena
- 3: neznama varianta --
- 4: zakladni font -- neni definovan
- 5: styl -- neni definovan
- 6: -- je nacten
- 7: neznamy format --
- 8: styl -- definovan
-% 9: mapovani -- je nacteno
- 10: neznamy font --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages italian library: fonts
- title: font del corpo
- 1: codifica --
- 2: variante -- caricata
- 3: variante sconosciuta --
- 4: corpo del testo -- non definito
- 5: stile -- non definito
- 6: -- caricato
- 7: formato sconosciuto --
- 8: stile -- definito
-% 9: mappatura -- caricata
- 10: file di font sconosciuto --
- 14: corpo del testo -- definito (sarebbe meglio globale)
-\stopmessages
-
-\startmessages norwegian library: fonts
- title: hovedfont
- 1: koding --
- 2: variant -- er lest inn
- 3: ukjent variant --
- 4: hovedfont -- er ikke definert
- 5: stil -- er ikke definert
- 6: -- er lest inn
- 7: ukjent format --
- 8: stil -- definert
-% 9: avbildning -- er lest inn
- 10: ukjent fontfil --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages romanian library: fonts
- title: corp de litere
- 1: codificarea --
- 2: varianta -- este incarcata
- 3: varianta necunoscuta --
- 4: corpul de litere -- nu este definit
- 5: stilul -- nu este definit
- 6: -- este incarcat
- 7: format necunoscut --
- 8: stilul -- definit
-% 9: maparea -- este incarcat
- 10: fisier font necunoscut --
- 14: bodyfont -- is defined (can better be done global)
-\stopmessages
-
-\startmessages french library: fonts
- title: corps de texte
- 1: encodage --
- 2: la variante -- est chargée
- 3: variante -- inconnue
- 4: policecorps -- n'est pas définie
- 5: le style -- n'est pas défini
- 6: -- est chargé
- 7: format -- inconnu
- 8: style -- défini
-% 9: mapping -- is loaded
- 10: fichier de police -- inconnu
- 14: policecorps -- est défini (une définition globale pourrait être plus adéquat)
-\stopmessages
-
-%D This module is one of the oldest modules of \CONTEXT. The
-%D macros below evolved out of the \PLAIN\ \TEX\ macros and
-%D therefore use a similar naming scheme (\type{\rm},
-%D \type{\bf}, etc). This module grew out of our needs. We
-%D started with the \PLAIN\ \TEX\ definitions, generalized the
-%D underlaying macros, and extended those to a level at which
-%D probably no one will ever recognize them.
-%D
-%D In 2001 we ran into a couple of projects where more than
-%D one combined set of fonts was involved in a document. To
-%D make definitions more readable, as well as to overcome the
-%D problem of ever growing file name lists, and also because
-%D we needed to scale fonts relative to each other, the low
-%D level implementation was partly rewritten. Global
-%D font assignments, relative scaling, font classes and alike
-%D were added then. At the same time some macros were made a
-%D bit more readable, and math support was extended to the
-%D larger sizes.
-%D
-%D One important characteristic of the font mechanism presented
-%D here is the postponing of font loading. This makes it
-%D possible to distribute \type{fmt} files without bothering
-%D about the specific breed of \type{tfm} files.
-%D
-%D Another feature implemented here is the massive switching
-%D from roman to {\ss sans serif}, {\tt teletype} or else. This
-%D means one doesn't have to take care of all kind of relations
-%D between fonts.
-%D
-%D \page[bigpreference]
+%D For more detailed (and historic information) we refer to the file
+%D \type {font-ini.mkii}. Here we have a much simplified lower level
+%D implementation due to a different approach to math. Also the chapter
+%D on fonts in the reference manual explains a lot.
%D \macros
%D {rm,ss,tt,hw,cg}
@@ -314,56 +204,6 @@
%D \stoptable
%D \stoplinecorrection
%D
-%D Anyone who feels the need, can define additional ones, like
-%D
-%D \startlinecorrection
-%D \starttable[|l||]
-%D \HL
-%D \NC faxfont \NC \type{\ff} \NC\FR
-%D \NC blackboard \NC \type{\bb} \NC\LR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D Or even
-%D
-%D \startlinecorrection
-%D \starttable[|l||]
-%D \HL
-%D \NC hebrew \NC \type{\hb} \NC\SR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D Styles are grouped in font sets. At the moment there are
-%D three main sets defined:
-%D
-%D \startlinecorrection
-%D \starttable[|l|l||]
-%D \HL
-%D \NC Computer Modern Roman \NC Knuth \NC \type{cmr} \NC\FR
-%D \NC Lucida Bright \NC Bigelow \& Holmes \NC \type{lbr} \NC\MR
-%D \NC Standard Postscript Fonts \NC Adobe \NC \type{pos} \NC\LR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D There are also some Computer Modern Roman alternatives:
-%D
-%D \startlinecorrection
-%D \starttable[|l|l||]
-%D \HL
-%D \NC Computer Modern Roman \NC Knuth \& Sauter \NC \type{sau} \NC\FR
-%D \NC Euler fonts \NC Zapf \NC \type{eul} \NC\MR
-%D \NC Computer Modern Concrete \NC Knuth \& Zapf \NC \type{con} \NC\LR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D All these definitions are ordered in files with names like
-%D \type{font-cmr} and \type{font-pos}, where the last three
-%D characters specify the name as known to \CONTEXT.
-%D
%D Within such a font set (\type{cmr}) and style (\type{\rm})
%D we can define a number of text font alternatives:
%D
@@ -380,43 +220,6 @@
%D \HL
%D \stoptable
%D \stoplinecorrection
-
-%D For old stylish Frans Goddijn we have:
-%D
-%D \startlinecorrection
-%D \starttable[|l||]
-%D \HL
-%D \NC oldstyle \NC \type{\os} \NC\SR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D The availability of these alternatives depends on the
-%D completeness of a font family and of course the definitions
-%D in the font files.
-%D
-%D But let's not forget math. In addition to the previous \TEX\
-%D families (the mysterious \type{\fam}'s) we've got some more:
-%D
-%D \startlinecorrection
-%D \starttable[|l||]
-%D \HL
-%D \NC Math Roman \NC \type{\mr} \NC\FR
-%D \NC Math Italic \NC \type{\mi} \NC\MR
-%D \NC Math Symbol \NC \type{\sy} \NC\MR
-%D \NC Math Extra \NC \type{\ex} \NC\MR
-%D \NC Math A \NC \type{\ma} \NC\MR
-%D \NC Math B \NC \type{\mb} \NC\MR
-%D \NC Math C \NC \type{\mc} \NC\LR
-%D \HL
-%D \stoptable
-%D \stoplinecorrection
-%D
-%D Users can call for specific fonts in many ways. Switches to
-%D other typefaces, like the switch from normal to bold, are as
-%D intuitive as possible, which means that all dependant fonts
-%D also switch. One can imagine that this takes quite some
-%D processing time.
%D
%D Internally fonts are stored as combination of size, style
%D and alternative, e.g. \type{12pt}+\type{\ss}+\type{\bf}.
@@ -514,7 +317,7 @@
%D And compare $\rm \scriptstyle THIS$ with the slightly larger
%D \cap{THIS}: \ruledhbox{$\rm \scriptstyle scriptstyle: THIS$}
%D or \ruledhbox{\cap{x style: THIS}} makes a big difference.
-
+%D
%D The \type{x..d} sizes should be used grouped. If you
%D don't group them, i.e. call them in a row, \CONTEXT\ will
%D not be able to sort out your intention (\type {x} inside
@@ -592,282 +395,8 @@
%D \NC \NR
%D \HL
%D \stoptabulate
-
-%D \macros
-%D {mf}
-%D
-%D Math fonts are a species in their own. They are tightly
-%D hooked into smaller and even smaller ones of similar breed
-%D to form a tight family. Let's first see how these are
-%D related:
-%D
-%D \startbuffer
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\rm 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\rm 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\tf 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\tf 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\bf 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\bf 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+ \bi x^2 =\sl 6x^2$
-%D $\tf x^2+\bf x^2+\sl x^2+\it x^2+\bs x^2+{\bi x^2}=\sl 6x^2$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D Gives both an expected and unexpected result:
-%D
-%D \startvoorbeeld
-%D \startlines
-%D \getbuffer
-%D \stoplines
-%D \stopvoorbeeld
-%D
-%D We see here that the character shapes change accordingly to
-%D the current family, but that the symbols are always typeset
-%D in the font assigned to \type{\fam0}.
-%D
-%D \startbuffer
-%D $\tf\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D $\bf\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D $\sl\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D $\bs\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D $\it\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D $\bi\mf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = 6x^2$
-%D \stopbuffer
-%D
-%D \startvoorbeeld
-%D \startlines
-%D \getbuffer
-%D \stoplines
-%D \stopvoorbeeld
%D
-%D In this example we see a new command \type{\mf} surface
-%D which means as much as {\em math font}. This commands
-%D reactivates the last font alternative and therefore equals
-%D \type{\bf}, \type{\sl} etc. but by default it equals
-%D \type{\tf}:
-
-\unexpanded\def\mf
- {\dodosetmathfont\fontalternative
- \csname\fontalternative\endcsname}
-
-%D The previous example was typeset saying:
-%D
-%D \typebuffer
-%D
-%D Beware: the exact location of \type{\mf} is not that
-%D important, we could as well has said
-%D
-%D \startbuffer
-%D $\bf x^2 + x^2 + x^2 + x^2 + x^2 + x^2 = \mf 6x^2$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D This is due to the way \TEX\ handles fonts in math mode.
-%D
-%D Of course we'll have to redefine \type{\mf} every time we
-%D change the current \type{\fam}.
-
-%D \macros
-%D {mbox,enablembox,mathop}
-%D
-%D Now how can we put this to use? Will the next sequence
-%D give the desired result?
-%D
-%D \startbuffer
-%D $\bf x^2 + \hbox{\mf whatever} + \sin(2x)$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D It won't!
-%D
-%D \startvoorbeeld
-%D \let\mathop=\normalmathop \getbuffer
-%D \stopvoorbeeld
-%D
-%D The reason for this is that \type{\sin} is defined as:
-%D
-%D \starttyping
-%D \def\sin{\mathop{\rm sin}\nolimits}
-%D \stoptyping
-%D
-%D We can fix this by defining
-
-\let\normalmathop\mathop
-
-\unexpanded\def\mathop
- {\normalmathop
- \bgroup
- \let\rm\mf
- \let\next=}
-
-%D We can fix arbitrary horizontal boxes by redefining the
-%D \TEX\ primitive \type{\hbox}:
-%D
-%D \starttyping
-%D \let\normalhbox=\hbox
-%D
-%D \def\hbox{\ifmmode\mbox\else\normalhbox\fi}
-%D \stoptyping
-%D
-%D with
-%D
-%D \starttyping
-%D \def\mbox#1#%
-%D {\normalhbox#1\bgroup\mf\let\next=}
-%D \stoptyping
-%D
-%D or more robust, that is, also accepting \type{\hbox\bgroup}:
-%D
-%D \starttyping
-%D \def\mbox%
-%D {\normalhbox\bgroup\mf
-%D \dowithnextbox{\flushnextbox\egroup}%
-%D \normalhbox}
-%D \stoptyping
-%D
-%D And now:
-%D
-%D \startbuffer
-%D $\bf x^2 + \hbox{whatever} + \sin(2x)$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D Indeed gives:
-%D
-%D \startvoorbeeld
-%D \enablembox\getbuffer
-%D \stopvoorbeeld
-%D
-%D But, do we want this kind of trickery to be activated? No,
-%D simply because we cannot be sure of incompatibilities,
-%D although for instance unboxing goes ok. Therefore we
-%D introduce:
-
-% best can go to math-ini and make \mf a hook then
-
-% better use \dowithnextboxcontent
-
-\def\normalmbox
- {\normalhbox\bgroup\mf
- \dowithnextbox{\flushnextbox\egroup}\normalhbox}
-
-% to test:
-%
-% \def\normalmbox
-% {\dowithnextboxcontent\mf\flushnextbox\normalhbox}
-
-\def\mbox
- {\ifmmode\normalmbox\else\normalhbox\fi}
-
-\def\enablembox
- {\appendtoks
- \ifx\normalhbox\undefined\let\normalhbox\hbox\fi
- \let\hbox\mbox
- \to\everymathematics}
-
-%D So in fact one can enable this feature if needed. I would say:
-%D go along, but use grouping if needed!
-
-%D \macros
-%D {mrfam,mifam,syfam,exfam,
-%D bsfam,bifam,scfam,tffam,
-%D mafam,mbfam,msfam}
-%D
-%D After this short mathematical excursion, we enter the world
-%D of fonts and fontswitching. We start with something very
-%D \TEX: \type{\fam} specified font families. \TEX\ uses
-%D families for managing fonts in math mode. Such a family has
-%D three members: text, script and scriptscript: $x^{y^z}$. In
-%D \CONTEXT\ we take a bit different approach than \PLAIN\
-%D \TEX\ does. \PLAIN\ \TEX\ needs at least four families for
-%D typesetting math. We use those but give them symbolic names.
-
-\chardef\mrfam = 0 % (Plain TeX) Math Roman
-\chardef\mifam = 1 % (Plain TeX) Math Italic
-\chardef\syfam = 2 % (Plain TeX) Math Symbol
-\chardef\exfam = 3 % (Plain TeX) Math Extra
-
-%D \PLAIN\ \TEX\ also defines families for {\it italic}, {\sl
-%D slanted} and {\bf bold} typefaces, so we don't have to
-%D define them here.
-
-\ifx\itfam\undefined
-
-\chardef\itfam = 4 % (Plain TeX) Italic
-\chardef\slfam = 5 % (Plain TeX) Slanted
-\chardef\bffam = 6 % (Plain TeX) Boldface
-
-\fi
-
-%D Family~7 in \PLAIN\ \TEX\ is not used in \CONTEXT, because
-%D we do massive switches from roman to sans serif, teletype or
-%D other faces.
-
-\ifx\ttfam\undefined
- \chardef\ttfam = 7 % (Plain TeX) can be reused!
-\fi
-
-%D We define ourselves some more families for {\bs bold
-%D slanted}, {\bi bold italic} and {\sc Small Caps}, so
-%D we can use them in math mode too. Instead of separate
-%D families for {\ss sans serif} and \type{teletype} we use the
-%D more general \type{\tffam}, which stands for typeface.
-
-\chardef\bsfam = 8 % (ConTeXt) BoldSlanted
-\chardef\bifam = 9 % (ConTeXt) BoldItalic
-\chardef\scfam = 10 % (ConTeXt) SmallCaps
-\chardef\tffam = 11 % (ConTeXt) TypeFace
-
-%D Because Taco needs a few more math families, we reuse
-%D family~7 for all those typefaces that have no related
-%D family, and therefore are grouped into one.
-
-\chardef\nnfam = 7 % (ReUsed) NoName
-
-%D Normally \type{\mrfam} equals \type{\tffam}, but a more
-%D distinctive alternatives are possible, for instance the
-%D Euler and Concrete Typefaces.
-%D
-%D After having defined all those in nature non||mathematical
-%D families, we define ourselves some real math ones. These are
-%D needed for the \AMS\ Symbol Fonts and Extended Lucida
-%D Bright.
-
-\chardef\mafam = 12 % (ConTeXt) Math A Fam (AmsTeX A)
-\chardef\mbfam = 13 % (ConTeXt) Math B Fam (AmsTeX B)
-\chardef\mcfam = 14 % (ConTeXt) Math C Fam (MathTime)
-\chardef\mdfam = 15 % (ConTeXt) Math D Fam (MathTime)
-
-%D Because there are 16~families and because \type{\ttfam}
-%D is reused, at the moment we have no so many families
-%D left. By default, we map any newly defined family on the
-%D last one (F).
-
-\def\newfam#1{\chardef#1=15 }
-
-%D This hack is also needed because in \ETEX\ we are going
-%D to reuse the \type {\newfam} allocation counter.
-
-%D To ease the support of font packages, we als define
-%D shortcuts to these familynames. This is necessary because
-%D the family names are in fact \type{\chardef}'s, which means
-%D that we're dealing with numbers (one can check this by
-%D applying \type{\showthe} and \type{\show}). In the
-%D specification of math symbols however we need hexadecimal
-%D numbers, so we have to convert the \type{\fam}'s value.
-
-\edef\hexmrfam {\hexnumber\mrfam} \edef\hexbsfam {\hexnumber\bsfam}
-\edef\hexmifam {\hexnumber\mifam} \edef\hexbifam {\hexnumber\bifam}
-\edef\hexsyfam {\hexnumber\syfam} \edef\hexscfam {\hexnumber\scfam}
-\edef\hexexfam {\hexnumber\exfam} \edef\hextffam {\hexnumber\tffam}
-\edef\hexitfam {\hexnumber\itfam} \edef\hexmafam {\hexnumber\mafam}
-\edef\hexslfam {\hexnumber\slfam} \edef\hexmbfam {\hexnumber\mbfam}
-\edef\hexbffam {\hexnumber\bffam} \edef\hexmcfam {\hexnumber\mcfam}
-\edef\hexnnfam {\hexnumber\nnfam} \edef\hexmdfam {\hexnumber\mdfam}
+%D Remark: math support has changed a bit.
%D \macros
%D {uchar}
@@ -886,244 +415,122 @@
\def\@shortstyle@ {@f@sh@} % short style prefix (rm etc)
\def\@letter@ {@f@le@} % first alternative typeface
\def\@noletter@ {@f@no@} % second alternative typeface
+\def\@fontclass@ {@f@cl@} % fontclass
+
+%D \macros
+%D {fontclass, defaultfontclass}
+%D
+%D The fontclass model was introduced a while after we implement
+%D the basic font model and at that time we still defaulted to
+%D no model at all. Nowadays we default to the \type {modern}
+%D fontclass.
+
+\let\fontclass \empty
+\let\defaultfontclass\empty
-%D The families can be grouped into math specific ones and
-%D more text related families, although text ones can be
-%D mapped onto the math ones to get for instance bold math.
+%D \macros
+%D {textonly}
%D
-%D Both groups of families are handles by a couple of token
-%D list tagged as strategies. This implementation makes
-%D implementing extensions more comfortable.
+%D Traditionally math has a big impact on font definitions, mainly
+%D because we need to define alphabet variants using families and
+%D fonts. This means that one can easily get 10 fonts loaded per
+%D math size. In \MKIV\ we use a different approach: one family
+%D which has either a virtual font made of traditional fonts, or
+%D an \OPENTYPE\ font that has it all.
+%D
+%D We currently use only one math family but in the future we
+%D might consider using a second one for bold math. For the
+%D moment we keep the \MKII\ method of using a token register
+%D for definitions but we already dropped the text and symbols
+%D ones since they now live in the same family.
-\newtoks \textstrategies
\newtoks \mathstrategies
-\newtoks \symbstrategies
\newif\ifsynchronizemathfonts \synchronizemathfontstrue
-\def\synchronizetext % stylish text in mmode
- {\ifsynchronizemathfonts\the\textstrategies\fi} % \if...\fam\minusone\fi}
-
\def\synchronizemath % math stuff in mmode
- {\ifsynchronizemathfonts\the\mathstrategies\fi} % \if...\fam\minusone\fi}
+ {\ifsynchronizemathfonts\the\mathstrategies\fi}
-\def\synchronizesymb % stylish math stuff in mmode
- {\ifsynchronizemathfonts\the\symbstrategies\fi} % \if...\fam\minusone\fi}
+\def\textonly{\synchronizemathfontsfalse} % document this
-%D By not setting the family we can append a font switch to \type
-%D {\everymath}. On the other hand, one never knows in what family
-%D state the strategies brought us.
-%D
-%D \starttyping
-%D {\bfa $\the\fam$} {\bfa \everymath{} $\the\fam$}
-%D \stoptyping
+%D The main math font definer. We have removed some optimized
+%D code simply because we now always have a fontclass. We could
+%D check for fontclass being default or empty and save a few
+%D tests but it does not help us when no math is defined.
-%D \macros
-%D {textonly}
-%D
-%D We can inhibit this slow||downer with:
+\chardef\mrfam\zerocount % math regular
+\chardef\mbfam\zerocount % math bold
-\def\textonly{\synchronizemathfontsfalse} % document this
+\def\mathtextsuffix {-text}
+\def\mathscriptsuffix {-script}
+\def\mathscriptscriptsuffix{-scriptscript}
-\appendtoks
- \dosettextfamily\c!tf
- \dosettextfamily\c!bf
- \dosettextfamily\c!sl
- \dosettextfamily\c!it
- \dosettextfamily\c!bs
- \dosettextfamily\c!bi
- \dosettextfamily\c!sc
-\to \textstrategies
-
-\def\dosettextfamily#1% better pass fontbody to dodoset
- {\let\savedfontbody\fontbody
- \let\fontfamily#1%
- \let\fontbody\scriptscriptface\dodosettextfamily\scriptscriptfont
- \let\fontbody\scriptface \dodosettextfamily \scriptfont
- \let\fontbody\textface \dodosettextfamily \textfont
- \let\fontbody\savedfontbody}
-
-% \def\s!nullfont{nullfont}
-
-\def\dodosettextfamily
- {\ifx\fontclass\empty
- \@EA\dodosettextfamilyA
- \else
- \@EA\dodosettextfamilyB
- \fi}
+% \let\mathsizesuffix\empty
-\def\dodosettextfamilyA#1%
- {\ifcsname \fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname \fontbody\c!mm\fontfamily\fontsize\endcsname \else
- \ifcsname \fontbody\c!mm\fontfamily\endcsname \autofontsizetrue
- \csname \fontbody\c!mm\fontfamily\endcsname \else
- \ifcsname \fontbody\c!rm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname \fontbody\c!rm\fontfamily\fontsize\endcsname \else
- \ifcsname \fontbody\c!rm\fontfamily\endcsname \autofontsizetrue
- \csname \fontbody\c!rm\fontfamily\endcsname \else
- \nullfont \autofontsizetrue
- \fi\fi\fi\fi
- #1\csname\fontfamily\s!fam\endcsname\font}
-
-\def\dodosettextfamilyB#1%
- {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \else
- \ifcsname\fontclass\fontbody\c!mm\fontfamily\endcsname \autofontsizetrue
- \csname\fontclass\fontbody\c!mm\fontfamily\endcsname \else
- \ifcsname\fontclass\fontbody\c!rm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname\fontclass\fontbody\c!rm\fontfamily\fontsize\endcsname \else
- \ifcsname\fontclass\fontbody\c!rm\fontfamily\endcsname \autofontsizetrue
- \csname\fontclass\fontbody\c!rm\fontfamily\endcsname \else
- \dodosettextfamilyA#1%
- \fi\fi\fi\fi
- #1\csname\fontfamily\s!fam\endcsname\font}
-
-\def\mrfallback{\c!rm\c!tf}
+\chardef\currentmathsize\zerocount
-\appendtoks
- \dosetmathfamily\mrfam\textface\scriptface\scriptscriptface\c!mr\mrfallback
- \dosetmathfamily\mifam\textface\scriptface\scriptscriptface\c!mi\empty
- \dosetmathfamily\syfam\textface\scriptface\scriptscriptface\c!sy\empty
- \dosetmathfamily\exfam\textface\textface \textface \c!ex\empty
- \dosetmathfamily\mafam\textface\scriptface\scriptscriptface\c!ma\empty
- \dosetmathfamily\mbfam\textface\scriptface\scriptscriptface\c!mb\empty
- \dosetmathfamily\mcfam\textface\scriptface\scriptscriptface\c!mc\empty
-% \dosetmathfamily\mdfam\textface\scriptface\scriptscriptface\c!md\empty
- \dosetmathfamily\nnfam\textface\scriptface\scriptscriptface\c!nn\empty
-\to \mathstrategies
+\def\mathsizesuffix{\ifcase\currentmathsize\or\mathtextsuffix\or\mathscriptscriptsuffix\or\mathscriptsuffix\fi}
-\appendtoks
- \dosetskewchar\mifam\defaultskewcharmi % implemented later on
- \dosetskewchar\syfam\defaultskewcharsy % implemented later on
-\to \mathstrategies
+\def\dodosetmathfamily#1#2%
+ {\ifcsname\fontclass \fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \autofontsizefalse
+ \csname\fontclass \fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \else
+ \ifcsname\fontclass \fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \autofontsizetrue
+ \csname\fontclass \fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \else
+ \dodosetmathfamilyx#1#2%
+ \fi\fi
+ #1#2\font}
-\def\dosetmathfamily#1#2#3#4#5#6%
- {\let\savedfontbody\fontbody % op hoger plan
- \let\fontfamily#5%
- \let\backfamily#6%
- \let\fontbody #4\dodosetmathfamily\scriptscriptfont#1%
- \let\fontbody #3\dodosetmathfamily \scriptfont#1%
- \let\fontbody #2\dodosetmathfamily \textfont#1%
- \let\fontbody\savedfontbody}
-
-\def\dodosetmathfamily
- {\ifx\fontclass\empty
- \@EA\dodosetmathfamilyA
- \else
- \@EA\dodosetmathfamilyB
- \fi}
+\def\dodosetmathfamilyx#1#2%
+ {\ifcsname\defaultfontclass\fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \autofontsizefalse
+ \csname\defaultfontclass\fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \else
+ \ifcsname\defaultfontclass\fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \autofontsizetrue
+ \csname\defaultfontclass\fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \else
+ \dodosetmathfamilyxx#1#2%
+ \fi\fi}
-\def\dodosetmathfamilyA#1#2%
- {\ifcsname \fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname \fontbody\c!mm\fontfamily\fontsize\endcsname \else
- \ifcsname \fontbody\c!mm\fontfamily \endcsname \autofontsizetrue
- \csname \fontbody\c!mm\fontfamily \endcsname \else
- \ifcsname \fontbody \backfamily\fontsize\endcsname \autofontsizefalse
- \csname \fontbody \backfamily\fontsize\endcsname \else
- \ifcsname \fontbody \backfamily \endcsname \autofontsizetrue
- \csname \fontbody \backfamily \endcsname \else
- \nullfont \autofontsizetrue
- \fi\fi\fi\fi
- #1#2\font}
+\def\dodosetmathfamilyxx#1#2%
+ {\ifcsname \fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \autofontsizefalse
+ \csname \fontbody\c!mm\fontfamily\fontsize\the\currentmathsize\endcsname \else
+ \ifcsname \fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \autofontsizetrue
+ \csname \fontbody\c!mm\fontfamily \the\currentmathsize\endcsname \else
+ \nullfont \autofontsizetrue
+ \fi\fi}
-\def\dodosetmathfamilyB#1#2%
- {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \autofontsizefalse
- \csname\fontclass\fontbody\c!mm\fontfamily\fontsize\endcsname \else
- \ifcsname\fontclass\fontbody\c!mm\fontfamily \endcsname \autofontsizetrue
- \csname\fontclass\fontbody\c!mm\fontfamily \endcsname \else
- \ifcsname\fontclass\fontbody \backfamily\fontsize\endcsname \autofontsizefalse
- \csname\fontclass\fontbody \backfamily\fontsize\endcsname \else
- \ifcsname\fontclass\fontbody \backfamily \endcsname \autofontsizetrue
- \csname\fontclass\fontbody \backfamily \endcsname \else
- \dodosetmathfamilyA#1#2%
- \fi\fi\fi\fi
- #1#2\font}
+\def\dosetmathfamily#1#2%
+ {\let\savedfontbody\fontbody % op hoger plan
+ \let\fontfamily#2%
+ \let\currentmathsize\plusthree\let\fontbody\scriptscriptface\dodosetmathfamily\scriptscriptfont#1%
+ \let\currentmathsize\plustwo \let\fontbody\scriptface \dodosetmathfamily\scriptfont #1%
+ \let\currentmathsize\plusone \let\fontbody\textface \dodosetmathfamily\textfont #1%
+ \let\currentmathsize\zerocount
+ \let\fontbody\savedfontbody
+ \autofontsizefalse}
\appendtoks
- \dosetsymbfamily\mrfam\textface\scriptface\scriptscriptface\c!mr
- \dosetsymbfamily\mifam\textface\scriptface\scriptscriptface\c!mi
- \dosetsymbfamily\syfam\textface\scriptface\scriptscriptface\c!sy
- \dosetsymbfamily\exfam\textface\textface \textface \c!ex
- \dosetsymbfamily\mafam\textface\scriptface\scriptscriptface\c!ma
- \dosetsymbfamily\mbfam\textface\scriptface\scriptscriptface\c!mb
- \dosetsymbfamily\mcfam\textface\scriptface\scriptscriptface\c!mc
-% \dosetsymbfamily\mdfam\textface\scriptface\scriptscriptface\c!md % also ?
-\to \symbstrategies
-
-\def\dosetsymbfamily#1#2#3#4#5%
- {\let\savedfontbody\fontbody
- \let\fontfamily#5%
- \let\fontbody #4\dodosetsymbfamily\scriptscriptfont#1%
- \let\fontbody #3\dodosetsymbfamily \scriptfont#1%
- \let\fontbody #2\dodosetsymbfamily \textfont#1%
- \let\fontbody\savedfontbody}
-
-\def\dodosetsymbfamily#1#2%
- {\ifcsname\fontclass\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
- \csname\fontclass\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
- #1#2\font
- \else\ifcsname\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
- \csname\fontbody\c!mm\fontfamily\fontalternative\fontsize\endcsname
- #1#2\font
- \fi\fi}
+ \dosetmathfamily\mrfam\c!mr
+ %\dosetmathfamily\mbfam\c!mb % some day, only when defined, else equivalent to 0
+\to \mathstrategies
%D All used styles, like rm, ss and tt, are saved in a comma
%D separated list. Appart from practical limitations one can
%D define as many styles as needed.
-\let\stylelist=\empty
+\def\fontrelativesizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
-\def\fontsizelist{\s!text,\s!script,\s!scriptscript,\c!x,\c!xx,\c!big,\c!small}
-
-%D \macros
-%D {magfactor,magfactorhalf}
-%D
%D There are several ways to specify a font. Three of them are
%D pure \TeX\ ones, the fourth one is new:
%D
%D \starttyping
%D \font\name=cmr12
%D \font\name=cmr12 at 10pt
-%D \font\name=cmr12 scaled \magstep2
+%D \font\name=cmr12 scaled 2
%D \font\name=cmr12 sa 1.440
%D \stoptyping
%D
%D The non||\TEX\ alternative \type{sa} stands for {\em scaled
%D at}. This means as much as: scale the bodyfontsize with this
-%D factor. The value 1.440 in this example is derived
-%D from the \type{\magstep}'s as mentioned in
-%D \in{table}[tab:magstep]. We therefore introduce
-%D \type{\magfactor} as an alternative for \type{\magstep}.
-%D
-%D \placetable[here][tab:magstep]
-%D {Factors to be used with \type{sa.}}
-%D \starttable[|c|c|c|]
-%D \HL
-%D \NC \bf magstep \NC \bf equivalent \NC \bf factor \NC\SR
-%D \HL
-%D \NC 1 \NC \type{\magfactor1} \NC 1.200 \NC\FR
-%D \NC 2 \NC \type{\magfactor2} \NC 1.440 \NC\MR
-%D \NC 3 \NC \type{\magfactor3} \NC 1.728 \NC\MR
-%D \NC 4 \NC \type{\magfactor4} \NC 2.074 \NC\MR
-%D \NC 5 \NC \type{\magfactor5} \NC 2.488 \NC\LR
-%D \HL
-%D \stoptable
-
-\def\magstep#1% \relax removed, otherwise space after it sticks, else added
- {\ifcase#1 \@m\or1200\or1440\or1728\or2074\or2488\or\@m\fi}
-
-\def\magstephalf
- {1095}
-
-\def\magfactor#1%
- {\ifcase#1 1.000\or1.200\or1.440\or1.728\or2.074\or2.488\or1\fi}
-
-\def\magfactorhalf
- {1.095}
-
-%D These macros enable the use of definitions like \type{sa
-%D \magfactor3} which saves us both (mis|)|calculations and
-%D potential mistypings.
+%D factor. The scaled option is not that useful as one needs to
+%D know the design size.
%D
%D Because \type {sa} (scaled at) and \type {mo} (mapped on)
%D are not low level \TEX\ supported alternatives, we have to
@@ -1146,9 +553,25 @@
{\edef\relativefontsize
{\ifcsname\fontclass#1\s!rscale\endcsname
\csname\fontclass#1\s!rscale\endcsname
+ \else\ifcsname\defaultfontclass#1\s!rscale\endcsname
+ \csname\defaultfontclass#1\s!rscale\endcsname
\else
\defaultrelativefontsize
- \fi}}
+ \fi\fi}}
+
+% \letvalue{\s!default\s!rscale}\defaultrelativefontsize
+%
+% \def\checkrelativefontsize#1%
+% {\edef\relativefontsize
+% {\csname
+% \ifcsname\fontclass#1\s!rscale\endcsname
+% \fontclass#1%
+% \else\ifcsname\defaultfontclass#1\s!rscale\endcsname
+% \defaultfontclass#1%
+% \else
+% \s!default
+% \fi\fi
+% \s!rscale\endcsname}}
%D We also save:
@@ -1159,6 +582,38 @@
{\executeifdefined{\fontclass\c!mm\s!text}\empty}
%D Scaling macros:
+%D
+%D This system is somewhat complicated by two (possible conflicting)
+%D demands:
+%D
+%D \startitemize
+%D \item We support wildcards like \type {sa *} which will adapt
+%D to the current size. This is also the default specification.
+%D \item We support named scales like \type {sa d}; beware: \type
+%D {x} and \type {xx} are valid scales but they are not alway
+%D the same as the ones used in for instance \type {\bfx} because
+%D there the sized come from the bodyfont environment. In the
+%D future there maybe a switch that also honors the environment
+%D in named scales.
+%D \stopitemize
+
+%D Keep in mind that the smaller sizes are just for text super and
+%D subscripts while larger sizes can be used in titles where for
+%D instance math follows the size.
+
+% b:x{\definedfont[SerifBold sa b]x}{\bfb x $x^x$}\par
+% 1:x{\definedfont[SerifBold sa 1]x}{\bf x $x^x$}\par
+% x:x{\definedfont[SerifBold sa x]x}{\bfx x $x^x$}\par
+% xx:x{\definedfont[SerifBold sa xx]x}{\bfxx x $x^x$}\par
+%
+% *:x{\definedfont[Serif sa *]x}\par
+% 1:x{\definedfont[Serif sa 1]x}\par
+% 2:x{\definedfont[Serif sa 2]x}\par
+% 3:x{\definedfont[Serif sa 3]x}\par
+% 4:x{\definedfont[Serif sa 4]x}\par
+% 5:x{\definedfont[Serif sa 5]x}\par
+%
+% {\definedfont[cmbx10 at 10pt]x\definedfont[cmbx8 at 10pt]x}
\def\safontscale{\number\dimexpr\localabsolutefontsize\relax}
\def\mofontscale{\number\dimexpr\setmappedfontsize\localabsolutefontsize\relax}
@@ -1171,29 +626,39 @@
\newdimen\scaledfontsize
\newtoks\everydefinefont
+\def\currentfontbodysize
+ {\ifcsname\??ft\s!default\somefontsize\endcsname
+ \csname\??ft\s!default\somefontsize\endcsname
+ \else
+ \somefontsize
+ \fi}
+
\def\lowleveldefinefont#1#2% #2 = cs
- {\ctxlua{fonts.define.command_1("\luaescapestring{#1}")}% the escapestring catches at \somedimen
+ {%
+ \ctxlua{fonts.define.command_1("\luaescapestring{#1}")}% the escapestring catches at \somedimen
% sets \scaledfontmode and \somefontname and \somefontsize
\ifcase\scaledfontmode\relax
- % none
+ % none, avoid the designsize if possible
\scaledfontsize-1000\scaledpoint
\or
% at
\scaledfontsize\somefontsize
\or
% sa
- \scaledfontsize\localabsolutefontsize
- \scaledfontsize\ifcsname\??ft\s!default\somefontsize\endcsname\csname\??ft\s!default\somefontsize\endcsname\else\somefontsize\fi\scaledfontsize
+ \scaledfontsize\localabsolutefontsize\relax
+ \scaledfontsize\currentfontbodysize\scaledfontsize
\or
% mo
\scaledfontsize\setmappedfontsize\localabsolutefontsize
- \scaledfontsize\ifcsname\??ft\s!default\somefontsize\endcsname\csname\??ft\s!default\somefontsize\endcsname\else\somefontsize\fi\scaledfontsize
+ \scaledfontsize\currentfontbodysize\scaledfontsize
\or
- % scaled
+ % scaled, don't use this one as it's unpredictable
\scaledfontsize-\somefontsize\scaledpoint
\fi
\scaledfontsize\localrelativefontsize\scaledfontsize
- \ifautofontsize\scaledfontsize\currentfontbodyscale\scaledfontsize\fi
+ \ifautofontsize
+ \scaledfontsize\currentfontbodyscale\scaledfontsize
+ \fi
\edef\somefontspec{at \number\scaledfontsize sp}%
\edef\somefontfile{\truefontname\somefontname}%
\ifx\somefontfile\s!unknown
@@ -1209,7 +674,9 @@
"\@@fontclassfeatures",
"\@@fontfeatures",
"\@@fontclassfallbacks",
- "\@@fontfallbacks"
+ "\@@fontfallbacks",
+ \number\currentmathsize,
+ \number\dimexpr\textface\relax
)}%
\edef\somefontspec{at \somefontsize}% we need the resolved designsize (for fallbacks)
\expandafter\let\expandafter\lastrawfontcall\csname#2\endcsname
@@ -1219,12 +686,48 @@
{\edef\@@fontclassfeatures {\ifcsname\fontclass\s!features \endcsname\csname\fontclass\s!features \endcsname\fi}%
\edef\@@fontclassfallbacks{\ifcsname\fontclass\s!fallbacks\endcsname\csname\fontclass\s!fallbacks\endcsname\fi}}
+% resolve
+
+\def\@@thefeaturesyes#1%
+ {\ifcsname\??ff\fontclass#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff\fontclass#1\s!features \endcsname\else
+ \ifcsname\??ff #1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff #1\s!features \endcsname\else
+ \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefeaturesyes \csname\??ff\fontclass #1\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesyes \csname\??ff #1\endcsname\else
+ \let \@@fontfeatures \empty \fi\fi\fi\fi}
+
+\def\@@thefallbacksyes#1%
+ {\ifcsname\??ff\fontclass#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff\fontclass#1\s!fallbacks\endcsname\else
+ \ifcsname\??ff #1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff #1\s!fallbacks\endcsname\else
+ \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefallbacksyes\csname\??ff\fontclass #1\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksyes\csname\??ff #1\endcsname\else
+ \let \@@fontfallbacks \empty \fi\fi\fi\fi}
+
+\def\@@thefeaturesnop#1%
+ {\ifcsname\??ff#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff#1\s!features \endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesnop \csname\??ff #1\endcsname\else
+ \let \@@fontfeatures \empty \fi\fi}
+
+\def\@@thefallbacksnop#1%
+ {\ifcsname\??ff#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff#1\s!fallbacks\endcsname\else
+ \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksnop\csname\??ff #1\endcsname\else
+ \let \@@fontfallbacks \empty \fi\fi}
+
+\def\updatefontparametersyes
+ {\@@thefeaturesyes \somefontname
+ \@@thefallbacksyes\somefontname}
+
+\def\updatefontparametersnop
+ {\@@thefeaturesnop \somefontname
+ \@@thefallbacksnop\somefontname}
+
+\def\updatefontparameters
+ {\ifx\fontclass\empty\updatefontparametersnop\else\updatefontparametersyes\fi}
+
\let\@@fontclassfeatures \empty
\let\@@fontclassfallbacks\empty
\let\@@fontfallbacks\empty
\let\@@fontfeatures \empty
-\let\@@skewchar \empty
\let\@@hyphenchar \empty % todo, will go to encoding
%D This brings down maps processing from 466 to 309 seconds
@@ -1334,14 +837,6 @@
%D We also accept \type{sa a}||\type{sa d} as specification.
-%D The duplicate font definition, using the ever the same dummy
-%D font name, results in less fuzzy error messages. In the log
-%D file, for instance when overfull boxes are reported, the
-%D simple keyword `font' replaces the \TEX\ ordinated name. The
-%D latter can be too misleading, due to the fact that \TEX\ has
-%D a rather optimized font memory management. Thanks to Taco
-%D for helping me sort this out.
-
%D \macros
%D {definefontsynonym, doifelsefontsynonym,
%D expandfontsynonym, truefontname, truefontdata}
@@ -1366,47 +861,64 @@
\def\definefontsynonym[#1]#2[#3]%
{\edef\@@fontname{#1}%
\edef\@@fontfile{#3}%
- \doifnextcharelse[\dodefinefontsynonym\nodefinefontsynonym}
-
-\def\nodefinefontsynonym
- {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile}
-
-\def\dodefinefontsynonym[#1]%
- {\edef\@@fontdata{#1}%
- \ifx\@@fontdata\empty
- \nodefinefontsynonym
+ \ifx\fontclass\empty
+ \expandafter\dodefinefontsynonymnop
\else
- \ifx\fontclass\empty
- \getfontparameters
- \else
- \getglobalfontparameters
- \fi
- \ifcsname\??ff\@@fontfile\s!features\endcsname
- \@EA\edef\csname\??ff\fontclass\@@fontname\endcsname{\@@fontfile*\csname\??ff\@@fontfile\s!features\endcsname}%
- \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
- \else
- \nodefinefontsynonym
- \fi
+ \expandafter\dodefinefontsynonymyes
\fi}
-\def\getfontparameters
- {\expandafter\dogetfontparameter\@@fontdata,]=,}
+\def\dodefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
+ \doifnextoptionalelse\dododefinefontsynonymnop\nonodefinefontsynonymnop}
+
+\def\dodefinefontsynonymyes
+ {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
+ \doifnextoptionalelse\dododefinefontsynonymyes\nonodefinefontsynonymyes}
+
+\def\dododefinefontsynonymnop[#1]%
+ {\let\@@ff@@features \undefined
+ \let\@@ff@@fallbacks\undefined
+ \expandafter\dogetfontparameternop#1,]=,}
-\def\getglobalfontparameters
- {\expandafter\dogetglobalfontparameter\@@fontdata,]=,}
+\def\dododefinefontsynonymyes[#1]%
+ {\let\@@ff@@features \undefined
+ \let\@@ff@@fallbacks\undefined
+ \expandafter\dogetfontparameteryes#1,]=,}
-\def\dogetfontparameter#1=#2,%
- {\if]#1\else
- \expandafter\def\csname\??ff\@@fontfile#1\endcsname{#2}%
- \expandafter\dogetfontparameter
+\def\dogetfontparameternop#1=#2,%
+ {\if]#1%
+ \dodododefinefontsynonymnop
+ \else
+ \expandafter\def\csname @@ff@@#1\endcsname{#2}%
+ \expandafter\dogetfontparameternop
\fi}
-\def\dogetglobalfontparameter#1=#2,%
- {\if]#1\else
- \expandafter\gdef\csname\??ff\@@fontfile#1\endcsname{#2}%
- \expandafter\dogetglobalfontparameter
+\def\dogetfontparameteryes#1=#2,%
+ {\if]#1%
+ \dodododefinefontsynonymyes
+ \else
+ \expandafter\def\csname @@ff@@#1\endcsname{#2}%
+ \expandafter\dogetfontparameteryes
\fi}
+% hm, was wrong, class/global reversed
+
+\def\nonodefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\s!features \endcsname\undefined
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined}
+
+\def\nonodefinefontsynonymyes
+ {\global\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\undefined
+ \global\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined}
+
+\def\dodododefinefontsynonymnop
+ {\@EA\let\csname\??ff\@@fontname\s!features \endcsname\@@ff@@features
+ \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+
+\def\dodododefinefontsynonymyes
+ {\global\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\@@ff@@features
+ \global\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks}
+
\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
\def\setupfontsynonym
@@ -1423,20 +935,51 @@
\fi
\fi}
-\def\truefontdata#1#2%
- {\ifcsname\??ff#1#2\endcsname
- % raw(Regular) raw(key)
- \csname\??ff#1#2\endcsname
- \else\ifcsname\??ff\fontclass#1\endcsname
- % exp(palatino Regular) raw(key)
- \expandafter\truefontdata\csname\??ff\fontclass#1\endcsname#2%
- \else\ifcsname\??ff#1\endcsname
- % exp(Regular) raw(key)
- \expandafter\truefontdata\csname\??ff#1\endcsname#2%
- \else\ifcsname\??ff#2\endcsname
- % raw(key)
- \csname\??ff#2\endcsname
- \fi\fi\fi\fi}
+% \def\truefontname#1%
+% {\@EA\dotruefontname#1*\empty*\relax}
+%
+% \def\dotruefontname#1*#2#3*#4\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+% \else
+% \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+% \fi
+% \else\ifcsname\??ff#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff#1\endcsname
+% \else
+% \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
+% \fi
+% \else
+% #1\ifx#2\empty\else*#2#3\fi
+% \fi\fi}
+%
+% \def\redotruefontname#1%
+% {\@EA\dodotruefontname#1*\relax}
+%
+% \def\dodotruefontname#1*#2\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
+% \else\ifcsname\??ff#1\endcsname
+% \@EA\redotruefontname\csname\??ff#1\endcsname
+% \else
+% #1%
+% \fi\fi}
+%
+% \def\expandfontsynonym#1#2% #2 := onelevelexpansion(#1)
+% {\ifcsname\??ff\fontclass#2\endcsname
+% \expandafter\def\expandafter#1\expandafter{\csname\??ff\fontclass#2\endcsname}%
+% \fi}
+%
+% \def\doifelsefontsynonym#1%
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \expandafter\firstoftwoarguments
+% \else
+% \expandafter\secondoftwoarguments
+% \fi}
+
+% maybe we need to stick in one branch
\def\truefontname#1%
{\@EA\dotruefontname#1*\empty*\relax}
@@ -1448,6 +991,12 @@
\else
\@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
\fi
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff\defaultfontclass#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff\defaultfontclass#1\endcsname*#2#3%
+ \fi
\else\ifcsname\??ff#1\endcsname
\ifx#2\empty
\@EA\truefontname\csname\??ff#1\endcsname
@@ -1456,7 +1005,7 @@
\fi
\else
#1\ifx#2\empty\else*#2#3\fi
- \fi\fi}
+ \fi\fi\fi}
\def\redotruefontname#1%
{\@EA\dodotruefontname#1*\relax}
@@ -1464,23 +1013,29 @@
\def\dodotruefontname#1*#2\relax
{\ifcsname\??ff\fontclass#1\endcsname
\@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \@EA\redotruefontname\csname\??ff\defaultfontclass#1\endcsname
\else\ifcsname\??ff#1\endcsname
\@EA\redotruefontname\csname\??ff#1\endcsname
\else
#1%
- \fi\fi}
+ \fi\fi\fi}
\def\expandfontsynonym#1#2% #2 := onelevelexpansion(#1)
{\ifcsname\??ff\fontclass#2\endcsname
\expandafter\def\expandafter#1\expandafter{\csname\??ff\fontclass#2\endcsname}%
- \fi}
+ \else\ifcsname\??ff\defaultfontclass#2\endcsname
+ \expandafter\def\expandafter#1\expandafter{\csname\??ff\defaultfontclass#2\endcsname}%
+ \fi\fi}
\def\doifelsefontsynonym#1%
{\ifcsname\??ff\fontclass#1\endcsname
- \expandafter\firstoftwoarguments
+ \@EA\firstoftwoarguments
+ \else\ifcsname\??ff\defaultfontclass#1\endcsname
+ \@EAEAEA\firstoftwoarguments
\else
- \expandafter\secondoftwoarguments
- \fi}
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
% \definetypeface[palatino][rm][serif][palatino,allbold][default]
%
@@ -1498,7 +1053,7 @@
\def\dostartfontclass[#1]%
{\pushmacro\fontclass
- \doifelse{#1}{\v!each}
+ \doifelse{#1}\v!each
{\let\fontclass\empty}
{\doifsomething{#1}{\def\fontclass{#1}}}}
@@ -1510,47 +1065,14 @@
%D
%D A goody:
-\def\tracedfontencoding#1%
- {\ifcsname\??ff#1\s!encoding\endcsname
- \space[\csname\??ff#1\s!encoding\endcsname]%
- \fi}
-
\def\tracedfontname#1%
- {\ifcsname\??ff\fontclass#1\endcsname
- #1\tracedfontencoding{\fontclass#1}\space->\space
- \@EA\tracedfontname\csname\??ff\fontclass#1\endcsname
+ {#1\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\tracedfontname\csname\??ff\fontclass#1\endcsname
\else\ifcsname\??ff#1\endcsname
- #1\tracedfontencoding{#1}\space->\space
- \@EA\tracedfontname\csname\??ff#1\endcsname
- \else
- #1%
+ \@EA\tracedfontname\csname\??ff#1\endcsname
\fi\fi}
%D \macros
-%D {getfontfileparameters}
-%D
-%D For special purposes, one can use the next macro to
-%D access font file characteristics, for instance:
-%D
-%D \starttyping
-%D \getfontfileparameters{Regular}
-%D \stoptyping
-%D
-%D can result in:
-%D
-%D \starttyping
-%D \def\currentfontfileencoding{texnansi}
-%D \stoptyping
-
-% \let\currentfontfileencoding\s!unknown
-% \let\currentfontfilemapping \s!unknown
-% \let\currentfontfilehandling\s!unknown
-
-% \def\getfontfileparameters#1%
-% {\edef\@@truefontname{\truefontname{#1}}%
-% \edef\currentfontfilefeatures{\truefontdata\@@truefontname\s!features}}
-
-%D \macros
%D {definefont}
%D
%D Before we implement the main definition macro, we first show
@@ -1568,14 +1090,23 @@
\def\definefont
{\dotripleempty\dodefinefont}
+% \def\dodefinefont[#1][#2][#3]% [name][spec][1.6 | line=10pt | setup_id]
+% {\doifinstringelse{ }{#2}
+% {\ifthirdargument
+% \unexpanded\setvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
+% \else
+% \unexpanded\setvalue{#1}{\dododefinefont{#1}{#2}}%
+% \fi}
+% {\definefont[#1][#2 sa *][#3]}}
+
+% we moved the unspecified size check to lua
+
\def\dodefinefont[#1][#2][#3]% [name][spec][1.6 | line=10pt | setup_id]
- {\doifinstringelse{ }{#2}
- {\ifthirdargument
- \unexpanded\setvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
- \else
- \unexpanded\setvalue{#1}{\dododefinefont{#1}{#2}}%
- \fi}
- {\definefont[#1][#2 sa *][#3]}}
+ {\ifthirdargument
+ \unexpanded\setvalue{#1}{\redodefinefont{#1}{#2}{#3}}%
+ \else
+ \unexpanded\setvalue{#1}{\dododefinefont{#1}{#2}}%
+ \fi}
\def\redodefinefont#1#2#3%
{\dododefinefont{#1}{#2}%
@@ -1636,11 +1167,6 @@
\the\everyfontswitch
\fi}
-%D I considered checking for mistakenly use of \PLAIN's
-%D \type{\magstep}'s but although it would take only a few
-%D lines of code, this would not add to consistent use. I
-%D therefore removed this check.
-
%D \macros
%D {mapfontsize}
%D
@@ -1673,8 +1199,7 @@
{\dodoubleargument\domapfontsize}
\def\domapfontsize[#1][#2]%
- {\scratchdimen#1\relax % \relax is really needed here
- \setvalue{\??ft*\the\scratchdimen}{#2}}
+ {\setvalue{\??ft*\the\dimexpr#1\relax}{#2}}
\def\setmappedfontsize#1%
{\ifcsname\??ft*#1\endcsname
@@ -1695,26 +1220,25 @@
%D To be documented.
-\let\sizelist\empty
+\let\fontsizelist \empty
+\let\fontalternativelist\empty
+\let\fontstylelist \empty
-\def\definefontsize[#1]% sneller met toks
- {\addtocommalist{#1}\sizelist
- \def\docommand##1%
+\def\checkfontnamecombinations
+ {\def\docommand##1%
{\def\dodocommand####1%
- {\def\dododocommand########1%
- %{\checkbodyfont{}{########1}{####1}{##1}}%
- {\checkbodyfont{########1}{####1}{##1}}%
- \processcommacommand[\stylelist]\dododocommand}%
- \processcommacommand[\alternativelist]\dodocommand}%
- \processcommacommand[\sizelist]\docommand}
-
-\def\alternativetextlist{\c!tf,\c!bf,\c!it,\c!sl,\c!bs,\c!bi,\c!sc}
-\def\alternativemathlist{\c!mr,\c!mi,\c!sy,\c!ex,\c!ma,\c!mb}
+ {\def\dododocommand########1{\checkbodyfont{########1}{####1}{##1}}%
+ \processcommacommand[\fontstylelist]\dododocommand}%
+ \processcommacommand[\fontalternativelist]\dodocommand}%
+ \processcommacommand[\fontsizelist]\docommand}
-\let\alternativelist\alternativetextlist % upward compatible
+\def\definefontsize[#1]% sneller met toks
+ {\addtocommalist{#1}\fontsizelist
+ \checkfontnamecombinations}
-%\definefontsize[\c!a] \definefontsize[\c!b]
-%\definefontsize[\c!c] \definefontsize[\c!d]
+\def\definefontalternative[#1]%
+ {\addtocommalist{#1}\fontalternativelist
+ \checkfontnamecombinations}
%D \macros
%D {currentfontscale,currentfontbodyscale}
@@ -1810,7 +1334,7 @@
\let\bodyfontenvironmentlist\empty
-\newcount\@@fontdefhack
+\newcount\@@fontdefhack % check if this is still needed
\def\@@beginfontdef
{\ifcase\@@fontdefhack
@@ -1843,29 +1367,44 @@
\@EA\dododefinebodyfontenvironment\@EA[\tempbodyfontsize][#1][#3]}%
\@@endfontdef
\else
+ \ifx\fontclass\empty\else
+ \writestatus\m!fonts{beware: fontclass ignored (if needed use: [fontclass][size][settings])}%
+ \fi
+ \pushmacro\fontclass
+ \let\fontclass\empty
\definebodyfontenvironment[\fontclass][#1][#2]% change */*
+ \popmacro\fontclass
\fi}
\def\dododefinebodyfontenvironment[#1][#2][#3]% size class settings
- {\@@beginfontdef
- \doifundefined{\??ft#2#1\c!em} % \s!text goes wrong in testing because
- {\def\docommand##1% % the 12pt alternative will called when
- {\scratchdimen#1\relax % typesetting the test (or so)
- \scratchdimen\csname\??ft\s!default##1\endcsname\scratchdimen
+ {\@@beginfontdef % \s!text goes wrong in testing because the 12pt alternative will called when typesetting the test (or so)
+ \ifcsname\??ft#2#1\c!em\endcsname
+ % we test for em as we assume it to be set
+ \else
+ \def\docommand##1%
+% fails: \def\checkbodyfontenvironment[#1]{! #1 ! \definebodyfontenvironment[\fontclass][#1][]} \setupbodyfont[8.5pt]
+% {\normalizebodyfontsize\csname\??ft\s!default##1\endcsname\dimexpr#1\relax\to\tempbodyfontsize
+% \letvalue{\??ft#2#1##1}\tempbodyfontsize}%
+ {\scratchdimen\csname\??ft\s!default##1\endcsname\dimexpr#1\relax
\normalizebodyfontsize\scratchdimen\to\tempbodyfontsize
- \setevalue{\??ft#2#1##1}{\tempbodyfontsize}}%
- \processcommacommand[\fontsizelist]\docommand
+ \letvalue{\??ft#2#1##1}\tempbodyfontsize}%
+ \processcommacommand[\fontrelativesizelist]\docommand
\copyparameters
[\??ft#2#1][\??ft\s!default]
- [\c!interlinespace,\c!em]}%
+ [\c!interlinespace,\c!em]%
+ \fi
\getparameters[\??ft#2#1][#3]%
\@@endfontdef
% new code, see remark
- \ifloadingfonts \else % only runtime
- \doifundefined{\@size@#1} % only once
- {\letvalue{\@size@#1}\empty % prevent loop
- \defineunknownfont{#1}}% % safeguard
- \fi
+ \ifloadingfonts
+ % only runtime
+ \else\ifcsname\@size@#1\endcsname
+ % only once
+ \else
+ % prevent loop (hence \empty)
+ \letvalue{\@size@#1}\empty
+ \defineunknownfont{#1}%
+ \fi\fi
% so far
\setvalue{\@size@#1}{\docompletefontswitch[#1]}}
@@ -1891,28 +1430,18 @@
\def\checkbodyfontenvironment[#1]%
{\definebodyfontenvironment[\fontclass][#1][]}
+
+\def\checkbodyfontenvironment[#1]%
+ {\ifcsname\??ft\fontclass#1\c!em\endcsname
+ % we test for em as we assume it to be set
+ \else
+ \definebodyfontenvironment[\fontclass][#1][]%
+ \fi}
% this one already catches both define/setup
\def\setupbodyfontenvironment{\definebodyfontenvironment}
-% officially, but not needed (yet):
-%
-% \def\dosetupbodyfontenvironment[#1][#2][#3]% class size settings
-% {\ifthirdargument
-% \localbodyfontsize#2\relax
-% \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
-% \doifundefinedelse{\??ft#1\normalizedbodyfontsize\c!em}
-% {\definebodyfontenvironment[#1][#2][#3]}%
-% {\getparameters[\??ft#1\normalizedbodyfontsize][#3]}%
-% \else
-% \localbodyfontsize#1\relax
-% \normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
-% \doifundefinedelse{\??ft\normalizedbodyfontsize\c!em}
-% {\definebodyfontenvironment[#1][#2]}%
-% {\getparameters[\??ft\normalizedbodyfontsize][#2]}%
-% \fi}
-
%D Just a couple of interface macros:
\def\bodyfontvariable#1%
@@ -1952,7 +1481,8 @@
%D We show two examples, that show all the alternative
%D scaling options. The \type{\tfa} alternatives can be
%D extended with \type{\bfa}, \type{\slb}, etc. or even
-%D \type{e} and higher alternatives.
+%D \type{e} and higher alternatives. The magic scaled
+%D values are derived from plain \TEX's \type {\magstep}:
%D
%D \starttyping
%D \definebodyfont [12pt] [rm]
@@ -1962,10 +1492,10 @@
%D sl=cmsl12,
%D bi=cmbxti10 at 12pt,
%D bs=cmbxsl10 at 12pt,
-%D tfa=cmr12 scaled \magstep1,
-%D tfb=cmr12 scaled \magstep2,
-%D tfc=cmr12 scaled \magstep3,
-%D tfd=cmr12 scaled \magstep4,
+%D tfa=cmr12 scaled 1.200,
+%D tfb=cmr12 scaled 1.440,
+%D tfc=cmr12 scaled 1.728,
+%D tfd=cmr12 scaled 2.074,
%D sc=cmcsc10 at 12pt]
%D
%D \definebodyfont [12pt,11pt,10pt,9pt,8pt] [rm]
@@ -2026,12 +1556,12 @@
\doifnumberelse{#1}
{\doifassignmentelse{#3}
{% [12pt] [style] [settings]
- \doifundefined{#2}{\expanded{\definefontstyle[#2][#2]}}% new
+ \doifundefined{#2}{\normalexpanded{\noexpand\definefontstyle[#2][#2]}}% new
\processcommalist[#1]{\dododefinebodyfont{#2}{#3}}}
{% [12pt] [style] [identifier]
\dodefinedefaultbodyfont[#1][#2][#3]}} % body style identifier
{% [identifier] [style] [settings] % see ***
- \setvalue{\s!default#1#2}##1##2{\expanded{\xdodefinebodyfont[##1][##2][#3]}}}%
+ \setvalue{\s!default#1#2}##1##2{\normalexpanded{\noexpand\xdodefinebodyfont[##1][##2][#3]}}}%
\else\ifsecondargument
\definebodyfont[#1][\c!rm][#2]%
\else
@@ -2042,9 +1572,8 @@
\fi\fi}
\def\xdodefinebodyfont[#1][#2][#3]% body|identifier style defs|identifier
- {%\writestatus{[#1]}{[#2][#3]}%
- \checkrelativefontsize{#2}% rather new, inherit from other defs
- \ifundefined{#2}\expanded{\definefontstyle[#2][#2]}\fi % new
+ {\checkrelativefontsize{#2}% rather new, inherit from other defs
+ \ifcsname#2\endcsname\else\normalexpanded{\noexpand\definefontstyle[#2][#2]}\fi % new
\processcommalist[#1]{\dododefinebodyfont{#2}{#3}}%
\let\relativefontsize\defaultrelativefontsize}
@@ -2055,47 +1584,56 @@
\def\dodododefinebodyfont#1#2#3% style body def
{\dododododefinebodyfont{#1}{#2}[#3]}
-\def\iflocalclassfonts{\ifx\fontclass\empty}
-
-\def\dododododefinebodyfont#1#2[#3#4#5=#6]% style body def
- {\ifundefined{#1#3#4#5}%
- %\checkbodyfont{#2}{#1}{#3#4}{#5}% not \definefontsize[#5]
- \checkbodyfont{#1}{#3#4}{#5}% not \definefontsize[#5]
- \fi
- \iflocalclassfonts
- \letbeundefined{*\fontclass#2#1#3#4#5*}%
- \scratchtoks{#6}%
- \expanded{\unexpanded\noexpand\setvalue{#2#1#3#4#5}%
- {\noexpand\xxdododefinefont{\relativefontsize}{#2}%
- {#2#1#3#4#5}{\the\scratchtoks}}}%
+\def\dododododefinebodyfont
+ {\ifx\fontclass\empty
+ \expandafter\dododododefinebodyfontnop
\else
- %\expanded{\writestatus{defining}{[\fontclass][#2#1#3#4#5] \resolvefontname#6 }}%
- \global\letbeundefined{*\fontclass#2#1#3#4#5*}%
- \scratchtoks{#6}%
- \expanded{\unexpanded\noexpand\setgvalue{\fontclass#2#1#3#4#5}%
- {\noexpand\xxdododefinefont{\relativefontsize}{#2}%
- {#2#1#3#4#5}{\the\scratchtoks}}}%
+ \expandafter\dododododefinebodyfontyes
\fi}
-% \def\checkbodyfont#1#2#3#4% body style alt size / gdef % #4 can be empty
-% {\def\c!!mm{#2}%
-% \ifx\c!!mm\c!mm % prevents \max and alike (re)defs
-% \unexpanded\setgvalue {#2}{\setcurrentfontstyle {#2}}% \rm
-% \unexpanded\setgvalue {#3}{\setcurrentfontalternative {#3}}% \sl
-% \else
-% \unexpanded\setgvalue {#2#4}{\setcurrentfontstylesize {#2}{#4}}% \rma
-% \unexpanded\setgvalue {#3#4}{\setcurrentfontalternativesize {#3}{#4}}% \sla
-% \unexpanded\setgvalue {#2#3#4}{\setcurrentfontstylealternativesize{#2}{#3}{#4}}% \rmsla
-% \unexpanded\setgvalue {#2}{\setcurrentfontstyle {#2}}% \rm
-% \unexpanded\setgvalue {#3}{\setcurrentfontalternative {#3}}% \sl
-% \unexpanded\setgvalue {#2\c!x}{\setcurrentfontxstylealternative {#2}}% \rmx
-% \unexpanded\setgvalue{#2\c!xx}{\setcurrentfontxxstylealternative {#2}}% \rmxx
-% \unexpanded\setgvalue {#3\c!x}{\setcurrentfontxalternative {#3}}% \slx
-% \unexpanded\setgvalue{#3\c!xx}{\setcurrentfontxxalternative {#3}}% \slxx
-% \unexpanded\setgvalue {#2#3}{\setcurrentfontstylealternative {#2}{#3}}% \rmsl
-% \fi}
-%
-% leaner
+\def\dododododefinebodyfontyes#1% style body def
+ {\edef\askedbodyfontstyle{#1}%
+ \ifx\askedbodyfontstyle\c!mm
+ \expandafter\dodefinebodyfontyesmm
+ \else
+ \expandafter\dodefinebodyfontyesxx
+ \fi\askedbodyfontstyle} % we can get rid of #1
+
+\def\dododododefinebodyfontnop#1% style body def
+ {\edef\askedbodyfontstyle{#1}%
+ \ifx\askedbodyfontstyle\c!mm
+ \expandafter\dodefinebodyfontnopmm
+ \else
+ \expandafter\dodefinebodyfontnopxx
+ \fi\askedbodyfontstyle} % we can get rid of #1
+
+\def\dodefinebodyfontnopxx#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \@EA\let\csname*#2#1#3#4#5*\endcsname\undefined
+ \normalprotected\@EA\edef\csname#2#1#3#4#5\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#5}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontyesxx#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \global\@EA\let\csname*\fontclass#2#1#3#4#5*\endcsname\undefined
+ \normalprotected\@EA\xdef\csname\fontclass#2#1#3#4#5\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#5}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontnopmm#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \@EA\let\csname*#2#1#3#4#51*\endcsname\undefined
+ \@EA\let\csname*#2#1#3#4#52*\endcsname\undefined
+ \@EA\let\csname*#2#1#3#4#53*\endcsname\undefined
+ \normalprotected\@EA\edef\csname#2#1#3#4#51\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#51}{\normalunexpanded{#6}}}%
+ \normalprotected\@EA\edef\csname#2#1#3#4#52\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#52}{\normalunexpanded{#6}}}%
+ \normalprotected\@EA\edef\csname#2#1#3#4#53\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#53}{\normalunexpanded{#6}}}}
+
+\def\dodefinebodyfontyesmm#1#2[#3#4#5=#6]% style body def
+ {\ifcsname#1#3#4#5\endcsname\else\checkbodyfont{#1}{#3#4}{#5}\fi% not \definefontsize[#5]
+ \global\@EA\let\csname*\fontclass#2#1#3#4#51*\endcsname\undefined
+ \global\@EA\let\csname*\fontclass#2#1#3#4#52*\endcsname\undefined
+ \global\@EA\let\csname*\fontclass#2#1#3#4#53*\endcsname\undefined
+ \normalprotected\@EA\xdef\csname\fontclass#2#1#3#4#51\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#51}{\normalunexpanded{#6}}}%
+ \normalprotected\@EA\xdef\csname\fontclass#2#1#3#4#52\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#52}{\normalunexpanded{#6}}}%
+ \normalprotected\@EA\xdef\csname\fontclass#2#1#3#4#53\endcsname{\noexpand\xxdododefinefont{\number\relativefontsize}{#2}{#2#1#3#4#53}{\normalunexpanded{#6}}}}
\def\checkbodyfont#1% tests for ttsl mmbf
{\def\c!!mm{#1}%
@@ -2108,9 +1646,9 @@
\def\checkmathbodyfont#1#2#3% style alt size / gdef % #3 can be empty
{%\message{!m #1 #2 #3!}%
% #1 #2 #3 = signal
- \unexpanded\setgvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \mmsla
- \unexpanded\setgvalue {#1}{\setcurrentfontstyle {#1}}% \mm
- \unexpanded\setgvalue {#2}{\setcurrentfontalternative {#2}}}% \sl
+ %unexpanded\setgvalue {#1#2#3}{\setcurrentfontstylealternativesize{#1}{#2}{#3}}% \mmsla
+ \unexpanded\setgvalue {#2}{\setcurrentfontalternative {#2}}% \sl
+ \unexpanded\setgvalue {#1}{\setcurrentfontstyle {#1}}}% \mm
\def\checktextbodyfont#1#2#3% style alt size / gdef % #3 can be empty
{%\message{!t #1 #2 #3!}%
@@ -2144,40 +1682,42 @@
\newif\ifdefiningunknownfont
\def\dodefineunknownfont#1#2%
- {\doifdefined{\??ft\s!default#2}
- {\donetrue
- \scratchdimen#1\relax
- \scratchdimen\csname\??ft\s!default#2\endcsname\scratchdimen
- \normalizebodyfontsize\scratchdimen\to\!!stringa
- \letvalue{\??ft#1#2}\!!stringa}}
+ {\ifcsname\??ft\s!default#2\endcsname
+ \donetrue
+ \normalizebodyfontsize\csname\??ft\s!default#2\endcsname\dimexpr#1\relax\to\tempbodyfontsize
+ \letvalue{\??ft#1#2}\tempbodyfontsize
+ \fi}
\def\dodefineunknownbodyfont#1#2% see ***
- {\doifdefined{\s!default\s!default#2}% somehow related to */*
- {\donetrue
- \getvalue{\s!default\s!default#2}{#1}{#2}}}
+ {\ifcsname\s!default\s!default#2\endcsname % somehow related to */*
+ \donetrue
+ \getvalue{\s!default\s!default#2}{#1}{#2}%
+ \fi}
\def\dodefineunknownsubfont#1#2%
- {\doifundefined{\@size@\getvalue{\??ft#1#2}}
- {\donetrue
- \defineunknownfont{\getvalue{\??ft#1#2}}}}
+ {\ifcsname\@size@\getvalue{\??ft#1#2}\endcsname
+ \else
+ \donetrue
+ \defineunknownfont{\getvalue{\??ft#1#2}}%
+ \fi}
\def\defineunknownfont#1%
{\let\c!savedtext\c!text
\let\c!text\s!text
\donefalse
- \processcommacommand[\fontsizelist]{\dodefineunknownfont{#1}}%
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownfont{#1}}%
\let\c!text\c!savedtext
\ifdone
\donefalse
\processcommacommand
- [\stylelist]
+ [\fontstylelist]
{\dodefineunknownbodyfont{#1}}%
\ifdone
\donefalse
\setvalue{\@size@#1}{\docompletefontswitch[#1]}%
\ifdefiningunknownfont \else
\definingunknownfonttrue
- \processcommacommand[\fontsizelist]{\dodefineunknownsubfont{#1}}%
+ \processcommacommand[\fontrelativesizelist]{\dodefineunknownsubfont{#1}}%
\definingunknownfontfalse
\fi
\fi
@@ -2238,8 +1778,8 @@
%D size and the local (sometimes in the textflow) size. We
%D store these dimensions in two \DIMENSION\ registers.
-\newdimen\globalbodyfontsize \globalbodyfontsize=12pt
-\newdimen\localbodyfontsize \localbodyfontsize =\globalbodyfontsize
+\ifdefined\globalbodyfontsize\else \newdimen\globalbodyfontsize \fi \globalbodyfontsize=12pt
+\ifdefined\localbodyfontsize \else \newdimen\localbodyfontsize \fi \localbodyfontsize =\globalbodyfontsize
%D \macros
%D {bodyfontsize}
@@ -2273,34 +1813,41 @@
%D often not the way users specify the bodyfont size. Therefore
%D we also store the normalized value.
-\chardef\fontdigits=1
+\chardef\fontdigits=2 % was 1
\def\normalizebodyfontsize#1\to#2%
- {\scratchdimen#1\relax
- \ifcase\fontdigits\advance\scratchdimen.5\points\fi
- \@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\scratchdimen00\to#2}
+ {\@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax000\to#2}
-\def\donormalizedbodyfontsize#1.#2#3#4\to#5% \points ?
- {\edef#5%
+\def\donormalizedbodyfontsize#1.#2#3#4#5\to#6% \points ?
+ {\edef#6% not \ifcase#2\else due to \relax adding
{#1%
- \ifcase\fontdigits\or
- \ifcase#2 \else.#2\fi % and not: \ifcase#2\else ...
- \else
- \ifcase#2#3 \else.#2\ifcase#3 \else#3\fi\fi % not: \ifcase#2#3\else ...
+ \ifcase\fontdigits
+ \or \ifcase#2 \else .#2\fi % 1
+ \or \ifcase#2#3 \else .#2\ifcase#3 \else #3\fi\fi % 2
+ \else \ifcase#2#3#4 \else .#2\ifcase#4 \ifcase#3 \else#3\fi \else#3#4\fi\fi % 3
\fi
\s!pt}}
+% not faster, just less tracing
+%
+% \def\setfontdigits#1%
+% {\chardef\fontdigits\ifnum#1>\plusthree\plusthree\else#1\fi\relax
+% \@EA\let\@EA\normalizedbfs\csname normalizedbfs\number\fontdigits\endcsname}
+%
+% \def\normalizebodyfontsize#1\to#2%
+% {\@EA\@EA\@EA\normalizedbfs\@EA\WITHOUTPT\the\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax000\to#2}
+%
+% \setvalue{normalizedbfs0}#1.#2\to #3{\edef#3{#1\s!pt}}
+% \setvalue{normalizedbfs1}#1.#2#3\to #4{\edef#4{#1\ifcase#2 \else.#2\fi\s!pt}}
+% \setvalue{normalizedbfs2}#1.#2#3#4\to #5{\edef#5{#1\ifcase#2#3 \else.#2\ifcase#3 \else#3\fi\fi\s!pt}}
+% \setvalue{normalizedbfs3}#1.#2#3#4#5\to#6{\edef#6{#1\ifcase#2#3#4 \else.#2\ifcase#4 \ifcase#3 \else#3\fi\else#3#4\fi\fi\s!pt}}
+%
+% \setfontdigits2
+
\normalizebodyfontsize\bodyfontsize\to\normalizedglobalbodyfontsize
\normalizebodyfontsize\bodyfontsize\to\normalizedlocalbodyfontsize
\normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
-%D To be internationalized:
-
-\def\korpsgrootte {\bodyfontsize}
-\def\korpspunten {\bodyfontpoints}
-
-%D some day.
-
%D \macros
%D {fontstyle,fontalternative,fontsize}
%D
@@ -2322,28 +1869,6 @@
\let\fontstyle = \defaultfontstyle
\let\fontsize = \defaultfontsize
-%D {\em The following approach is obsolete.}
-%D
-%D All things related to fonts are grouped into files with
-%D names like \type{font-cmr}. These files are loaded by:
-
-\def\resetfontdefinitionfile[#1]%
- {\letbeundefined{\c!file\f!fontprefix#1}}
-
-\newif\ifloadfontfileonce
-
-\def\doreadfontdefinitionfile#1#2% #1 = set/switch state
- {\doifundefined{\c!file\f!fontprefix#2}%
- {\ifloadfontfileonce
- \letvalue{\c!file\f!fontprefix#2}\empty
- \fi
- \makeshortfilename[\truefilename{\f!fontprefix#2}]%
- \startreadingfile
- \readsysfile\shortfilename
- {\showmessage\m!fonts2{#2}}
- {\showmessage\m!fonts3{#2}}%
- \stopreadingfile}}
-
%D When \type {\loadfontfileoncetrue}, such files are
%D only loaded once! This permits redundant loading, but at
%D the same time forced grouping when we want continuously mix
@@ -2352,8 +1877,10 @@
%D needed to prevent problems with loading files that use this
%D character in numbers.
+% can be made faster (only used internally now)
+
\def\doswitchpoints[#1]%
- {\expanded{\dodoswitchpoints{#1}}}
+ {\normalexpanded{\noexpand\dodoswitchpoints{#1}}}
\def\dodoswitchpoints#1%
{\doifundefined{\@size@#1}
@@ -2363,6 +1890,7 @@
{\getvalue{\@size@#1}%
\localbodyfontsize#1\relax
\normalizebodyfontsize\localbodyfontsize\to\normalizedbodyfontsize
+% \edef\fontbody{\fontbody}% to be tested but we can clean up mkiv further
\checkbodyfontenvironment[\normalizedbodyfontsize]}
{\showmessage\m!fonts4{#1}}}
@@ -2425,17 +1953,29 @@
%D sequence of a session. After the loading job is done, the
%D macro relaxes itself and reset the signal.
+% \appendtoks
+% \to \everysetupdocument
+
+\newconditional\fontsareloaded
+
\def\preloadfonts % never called, needs a clean up
- {\showmessage\m!fonts6{\normalizedbodyfontsize\normalspace\fontstyle}%
- \global\loadingfontsfalse
- \doswitchpoints[\normalizedbodyfontsize]%
- \doswitchstyle[\fontstyle]%
- \the\everybodyfont
- \the\everyglobalbodyfont
- \saveinterlinespace
+ {\global\loadingfontsfalse
+ \ifconditional\fontsareloaded \else
+ \doifmodeelse {*nofonts}
+ {\writestatus\m!fonts{latin modern fonts are not preloaded}}
+ {\writestatus\m!fonts{preloading latin modern fonts}%
+ \usetypescript[modern]%
+ \setuptypeface[modern]%
+ \showmessage\m!fonts6{\normalizedbodyfontsize\normalspace\fontstyle}}%
+ \fi
\global\let\preloadfonts\relax}
-% \prependtoks \preloadfonts \to \everydump % saves .1 s on a DELL P60 - 2GHZ
+% maybe add this to \everystarttext
+%
+% \ifconditional\fontsareloaded\else
+% \usetypescript[modern]%
+% \setuptypeface[modern]%
+% \fi
%D Here comes the main font switching macros. These macros
%D handle changes in size as well as returning to the global
@@ -2446,36 +1986,68 @@
{\restoreglobalbodyfont}
{\processcommacommand[#2]{\dodosetfont{#1}}% ##1 get also passed
\ifloadingfonts\else
+ \global\settrue\fontsareloaded
\doswitchpoints[\normalizedbodyfontsize]%
\doswitchstyle[\fontstyle]%
+ \ifx\defaultfontclass\empty
+ \let\defaultfontclass\fontclass
+ \fi
\fi}%
\chardef\currentxfontsize\zerocount}
\def\dodosetfont#1#2% #1 = set/switch state | check fo rempty, else space
{\doifsomething{#2}{\dododosetfont{#1}{#2}{\showmessage\m!fonts4{#2}}}}
-\def\dododosetfont#1#2#3% #1 = set/switch state
- {\doifnumberelse{#2}
- {\dodododosetfont{#1}{#2}{#3}}
- {\doifdefinedelse{\??ft\normalizedbodyfontsize\interfaced{#2}}
- {\edef\fontstep{\csname\bodyfontvariable\normalizedbodyfontsize\interfaced{#2}\endcsname}%
- \expanded{\dodododosetfont{#1}{\fontstep}}{#3}}
- {\doifelse{#2}\v!reset
- {\let\fontstyle\empty % new 31/7/2006
- \let\fontsize \empty}
- {\doifdefinedelse{\@style@#2}
- {\edef\fontstyle{#2}}
- {\doreadfontdefinitionfile{#1}{#2}}}}}}
+% % % this can be retrofitted in mkii code % % %
+
+% \def\normalizebodyfontsize#1\to#2%
+% {\@EA\@EA\@EA\donormalizedbodyfontsize\@EA\WITHOUTPT\the\dimexpr#1+\ifcase\fontdigits.5\or.05\or.005\fi\points\relax000\to#2}
+
+\def\dododosetfont#1#2#3% #1 = set/switch state ! ! ! !could also be used for mkii
+ {\doifnumberelse{#2}\dodododosetfont\redododosetfont{#1}{#2}{#3}}
+
+\def\redododosetfont#1#2#3% #1 = set/switch state ! ! ! !could also be used for mkii
+ {\edef\expandedfontthing{#2}%
+ \def\interfacedfontsize{\normalizedbodyfontsize\interfaced\expandedfontthing}%
+ \ifcsname\??ft\interfacedfontsize\endcsname
+ \edef\fontstep{\csname\bodyfontvariable\interfacedfontsize\endcsname}%
+ \normalexpanded{\noexpand\dodododosetfont{#1}{\fontstep}}{#3}%
+ \else\ifx\expandedfontthing\v!reset
+ \let\fontstyle\empty % new 31/7/2006
+ \let\fontsize \empty
+ \else
+ \ifcsname\@style@\expandedfontthing\endcsname
+ \let\fontstyle\expandedfontthing
+ \else
+ \setcurrentfontclass\expandedfontthing
+ \ifcase#1\relax
+ \let\globalfontclass\globalfontclass
+ \else
+ \let\globalfontclass\fontclass
+ \fi
+ \ifx\fontclass\empty
+ \let\fontstyle\c!rm
+ \else\ifcsname\??tf\fontclass\s!default\endcsname
+ \edef\fontstyle{\csname\??tf\fontclass\s!default\endcsname}%
+ \else
+ \let\fontstyle\c!rm
+ \fi\fi
+ \fi
+ \fi\fi}
\def\dodododosetfont#1#2#3% #1 = set/switch state
- {\scratchdimen#2\relax
- \normalizebodyfontsize\scratchdimen\to\normalizedsetfont
- \doifundefined{\@size@\normalizedsetfont}
- {\defineunknownfont{#2}}%
- \doifdefinedelse{\@size@\normalizedsetfont}
- {\localbodyfontsize\normalizedsetfont
- \let\normalizedbodyfontsize\normalizedsetfont}
- {#3\dosetsubstitutefont{#1}{#2}}}
+ {\normalizebodyfontsize#2\to\normalizedsetfont
+ \ifcsname\@size@\normalizedsetfont\endcsname \else
+ \defineunknownfont{#2}%
+ \fi
+ \ifcsname\@size@\normalizedsetfont\endcsname
+ \localbodyfontsize\normalizedsetfont
+ \let\normalizedbodyfontsize\normalizedsetfont
+ \else
+ #3\dosetsubstitutefont{#1}{#2}%
+ \fi}
+
+% % %
%D In the previous macros we use \type{\currentxfontsize} to
%D hold the current x||size of the font. This enables us to
@@ -2515,8 +2087,15 @@
\let\fontclass\empty \let\globalfontclass\fontclass
+% we need to check the fontclass
+
+\def\registerfontclass#1%
+ {\letgvalue{\@fontclass@#1}\v!yes} % global ?
+
\def\setcurrentfontclass#1%
- {\edef\fontclass{#1}}
+ {\ifcsname\@fontclass@#1\endcsname
+ \edef\fontclass{#1}%
+ \fi}
\let\defaultfontstyle \c!rm
\let\defaultfontalternative \c!tf
@@ -2553,7 +2132,7 @@
% already in sync
\else
\let\bigmathfontsize\fontsize
- \synchronizemath \synchronizetext
+ \synchronizemath
\fi}
\def\checkbigmathsynchronization
@@ -2572,10 +2151,7 @@
\checkbigmathsynchronization}
\def\dosetcurrentfontalternative#1%
- {\edef\fontalternative{#1}%
- \ifmmode % maybe no test, or actually, an option
- \fam\csname\fontalternative\s!fam\endcsname
- \fi}
+ {\edef\fontalternative{#1}}
\def\setcurrentfont#1#2#3#4%
{%\message{[1 #1 #2 #3 #4]}%
@@ -2660,6 +2236,7 @@
\global\let\fontstrategy\dofontstrategy
\the\fontstrategies \relax % \relax still needed ?
\fi
+ \autofontsizefalse
\ifskipfontcharacteristics
\setfontcharacteristics
\the\everyfontswitch
@@ -2675,6 +2252,8 @@
#1\csname\fontclass#2#3#4#5\endcsname \tryingfontfalse
\fi}
+% old sequence
+
\appendtoks \iftryingfont \fontstrategy \autofontsizefalse % --- --- --- --- % pt tt bf a
\fontbody \fontstyle \fontalternative \fontsize
\fi \to \fontstrategies
@@ -2706,7 +2285,6 @@
\prependtoks
\ifsynchronizefonts
\synchronizemath
- \synchronizetext
\synchronizefont % problem: syncs last font
\fi
\to \everybodyfont
@@ -2757,9 +2335,6 @@
% This alterative is not really needed, but for old time's sake
% we keep it there. We can speed it up when needed.
-% \def\setcurrentfontxstylealternative #1{\csname#1\endcsname\tfx}
-% \def\setcurrentfontxxstylealternative#1{\csname#1\endcsname\tfxx}
-
\def\setcurrentfontxstylealternative #1{\csname#1\endcsname\tx}
\def\setcurrentfontxxstylealternative#1{\csname#1\endcsname\txx}
@@ -2808,10 +2383,11 @@
%D \stoptyping
\def\dodefinefontstyle[#1][#2]%
- {\rawdoifinsetelse{#2}{\stylelist}
- {}%\debuggerinfo\m!fonts{unknown style #2}}
- {\addtocommalist{#2}\stylelist
- \showmessage\m!fonts8{#2\space (#1)}}%
+ {\rawdoifinsetelse{#2}{\fontstylelist}
+ {%\debuggerinfo\m!fonts{unknown style #2}%
+ }
+ {%\debuggerinfo\m!fonts8{#2\space (#1)}%
+ \addtocommalist{#2}\fontstylelist}%
% check kan hier
\def\docommand##1%
{\setvalue{\@shortstyle@##1}{#2}%
@@ -2823,25 +2399,9 @@
\def\setfontstyle#1#2% #1:name (roman, romaan) #2:style (rm)
{\edef\fontstyle{#1}%
+ \checkfontnamecombinations
\setcurrentfontstyle\normalizedbodyfontsize}
-\chardef\defaultskewcharmi=127 % '177
-\chardef\defaultskewcharsy= 48 % '60
-
-% \def\dosetskewchar#1%
-% {\skewchar\font\ifx\@@fontskewchar\empty#1\else\@@fontskewchar\fi}
-
-\def\dosetskewchar#1#2%
- {\ifx\@@fontskewchar\empty
- \skewchar\textfont #1#2%
- \skewchar\scriptfont #1#2%
- \skewchar\scriptscriptfont#1#2%
- \else
- \skewchar\textfont #1\@@fontskewchar
- \skewchar\scriptfont #1\@@fontskewchar
- \skewchar\scriptscriptfont#1\@@fontskewchar
- \fi}
-
%D The previous macros show that it's is not always
%D neccessary to define the whole bunch of fonts, take for
%D instance the sequence:
@@ -2878,7 +2438,7 @@
\def\docompletefontswitch[#1]%
{\bodyfontsize#1\relax
- \dimensiontocount\bodyfontsize\bodyfontpoints
+ \dimensiontocount\bodyfontsize\bodyfontpoints % rounded, still used in m-chart
\edef\bodyfontfactor{\withoutpt\the\bodyfontsize}%
\normalizebodyfontsize\bodyfontsize\to\normalizedbodyfontsize
\dosetbodyfontface \textface \s!text
@@ -2948,8 +2508,7 @@
\def\fastswitchtobodyfont#1%
{\ifcsname\??ft\normalizedbodyfontsize#1\endcsname
- \edef\futurebodyfontsize
- {\csname\??ft\normalizedbodyfontsize#1\endcsname}%
+ \edef\futurebodyfontsize{\csname\??ft\normalizedbodyfontsize#1\endcsname}%
\ifcsname\@size@\futurebodyfontsize\endcsname
\csname\@size@\futurebodyfontsize\endcsname
\localbodyfontsize\futurebodyfontsize\relax
@@ -2958,46 +2517,10 @@
\csname\@style@\fontstyle\endcsname
\the\everybodyfont}
-%D Because the last macro can appear in arguments or be assigned
-%D to parameters, we protect this one for unwanted expansion.
-
-\def\dodosetmathfont#1%
- {\setcurrentfontalternative{#1}%
- % \doifdefinedelse{#1\s!fam} % adapted
- % {\edef\mffam{\getvalue{#1\s!fam}}}
- % {\edef\mffam{\getvalue{\c!nn\s!fam}}}%
- \textfont \mrfam\textfont \mffam
- \scriptfont \mrfam\scriptfont \mffam
- \scriptscriptfont\mrfam\scriptscriptfont\mffam}
-
-\def\domffam#1%
- {\csname\ifcsname#1\s!fam\endcsname#1\else\c!nn\fi\s!fam\endcsname}
-
-\def\mffam
- {\domffam\fontalternative}
-
-\def\dosetmathfont
- {\def\rm{\fam\mrfam}\dodosetmathfont}
-
-\def\enableencodinginmath
- {\appendtoks
- \everyhbox{\mr\everyhbox\emptytoks}%
- \everyvbox{\mr\everyvbox\emptytoks}%
- \to \everymathematics} % was \everymath
-
-% \enableencodinginmath % too untested to enable by default
-
%D \starttyping
%D $\cases{& \ccaron}$ $x=\hbox{\ccaron $x=\hbox{\ccaron}$}$
%D \stoptyping
-%D The font specific features are bound to the filename.
-
-\def\updatefontparameters
- {\edef\@@fontfeatures {\truefontdata\somefontfile\s!features}%
- \edef\@@fontfallbacks{\truefontdata\somefontname\s!fallbacks}%
- \edef\@@fontskewchar {\truefontdata\somefontfile\s!skewchar}} % will be replaced
-
\def\setfontcharacteristics
{\the\everyfont}
@@ -3020,27 +2543,53 @@
{\dotripleargument\dodefinefontfeature}
\def\dodefinefontfeature[#1][#2][#3]%
- {\ctxlua{fonts.define.specify.preset_context("#1","#2","#3")}}
+ {\global\expandafter\chardef\csname\??fq=#1\endcsname
+ \ctxlua{tex.write(fonts.define.specify.preset_context("#1","#2","#3"))}\relax}
\definefontfeature
[default]
- [liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
+ [%mode=node,%
+ liga=yes,kern=yes,tlig=yes,trep=yes] % texligatures=yes,texquotes=yes
\definefontfeature
[smallcaps]
- [liga=yes,kern=yes,tlig=yes,trep=yes,smcp=yes] % texligatures=yes,texquotes=yes
+ [%mode=node,%
+ liga=yes,kern=yes,tlig=yes,trep=yes,smcp=yes] % texligatures=yes,texquotes=yes
\definefontfeature
[oldstyle]
- [liga=yes,kern=yes,tlig=yes,trep=yes,onum=yes] % texligatures=yes,texquotes=yes
+ [%mode=node,%
+ liga=yes,kern=yes,tlig=yes,trep=yes,onum=yes] % texligatures=yes,texquotes=yes
-\definefontfeature % no calt
+\definefontfeature
[arabic]
- [mode=node,language=dflt,script=arab,
+ [mode=node,language=dflt,script=arab,ccmp=yes,
init=yes,medi=yes,fina=yes,isol=yes,
- liga=yes,dlig=yes,rlig=yes,clig=yes,
+ liga=yes,dlig=yes,rlig=yes,clig=yes,calt=yes,
mark=yes,mkmk=yes,kern=yes,curs=yes]
+\definefontfeature
+ [none]
+ [mode=none,features=off]
+
+\definefontfeature
+ [virtualmath]
+ [mode=base,liga=yes,kern=yes,tlig=yes,trep=yes]
+
+% for the moment here, this will change but we need it for mk.tex
+
+\definefontfeature[math-text] [virtualmath][ssty=no]
+\definefontfeature[math-script] [virtualmath][ssty=1,mathsize=yes]
+\definefontfeature[math-scriptscript][virtualmath][ssty=2,mathsize=yes]
+
+\definefontfeature [math-nostack-text] [math-text] [nostackmath=yes]
+\definefontfeature [math-nostack-script] [math-script] [nostackmath=yes]
+\definefontfeature [math-nostack-scriptscript][math-scriptscript][nostackmath=yes]
+
+% \definefontfeature[mathtext] [math-text]
+% \definefontfeature[mathscript] [math-script]
+% \definefontfeature[mathscriptscript] [math-scriptscript]
+
%D Also new:
% handy for manuals
@@ -3052,32 +2601,9 @@
\definecolor[font:init][r=.75]
\definecolor[font:medi][g=.75]
\definecolor[font:fina][b=.75]
-\definecolor[font:isol][y=.75]
-\definecolor[font:mark][m=.75]
-\definecolor[font:rest][c=.75]
-
-%D goodies:
-%D
-%D \starttyping
-%D \showinstalledfonts[officinasans.*][all]
-%D \showinstalledfonts[officinaserif.*][all]
-%D \showinstalledfonts[officina.*itc.*][all]
-%D
-%D \showinstalledfonts[officina.*itc.*][all,new]
-%D \stoptyping
-
-\def\showinstalledfonts
- {\dodoubleempty\doshowinstalledfonts}
-
-\def\doshowinstalledfonts[#1][#2]%
- {\bgroup
- \def\pattern{#1}%
- \def\all{false}%
- \def\reload{false}%
- \doifnothing\pattern{\def\pattern{.*}}%
- \processallactionsinset[#2][\v!new=>\def\reload{true},\v!all=>\def\all{true}]%
- \ctxlua{fonts.names.table("#1",\reload,\all)}%
- \egroup}
+\definecolor[font:isol][r=.75,g=.75] % [y=.75]
+\definecolor[font:mark][r=.75,b=.75] % [m=.75]
+\definecolor[font:rest][g=.75,b=.75] % [c=.75]
%D Experimental!
@@ -3085,7 +2611,7 @@
{\dodoubleargument\doinstallfontfeature}
\def\doinstallfontfeature[#1][#2]%
- {\ctxlua{fonts.install_feature("#1","#2")}}
+ {\writestatus\m!fonts{installing font features was experimental}} % \ctxlua{fonts.install_feature("#1","#2")}}
%D Not yet in \MKII.
@@ -3099,13 +2625,35 @@
\let\currentfeature\empty
+% ! ! ! very experimental, some test code for idris advanced features ! ! !
+%
+% \startbuffer
+% \definefontfeature[smallcaps][smallcaps][script=latn]
+% \definefontfeature[oldstyle] [oldstyle] [script=latn]
+%
+% \definedfont[name:cambria at 15pt]
+%
+% Hello there {\setff{smallcaps}capped 123 \setff{oldstyle}123!} \blank
+% Hello there {\addff{smallcaps}capped 123 \addff{oldstyle}123!} \blank
+% Hello there {\addff{smallcaps}capped \subff{smallcaps}normal} \blank
+% \stopbuffer
+%
+% \typebuffer \getbuffer
+
\def\featureattribute#1{\ctxlua{tex.sprint(fonts.define.specify.context_number("#1"))}}
\def\setfontfeature #1{\edef\currentfeature{#1}\attribute\zerocount\featureattribute{#1}\relax}
-\def\resetfontfeature#1{\let\currentfeature\empty\attribute\zerocount\zerocount}
+\def\resetfontfeature#1{\let\currentfeature\empty\attribute\zerocount\zerocount} % initial value
-\appendtoks
- \setfontfeature\currentfeature
-\to \everylanguage
+\def\addfontfeaturetoset #1{\ctxlua{fonts.withset("#1", 1)}}
+\def\subtractfontfeaturefromset #1{\ctxlua{fonts.withset("#1",-1)}}
+\def\addfontfeaturetofont #1{\ctxlua{fonts.withfnt("#1", 2)}}
+\def\subtractfontfeaturefromfont#1{\ctxlua{fonts.withfnt("#1",-2)}}
+
+\let\setff\setfontfeature
+\let\addfs\addfontfeaturetoset
+\let\subfs\subtractfontfeaturefromset
+\let\addff\addfontfeaturetofont
+\let\subff\subtractfontfeaturefromfont
%D The next auxilliary macro is an alternative to \type
%D {\fontname}.
@@ -3140,75 +2688,23 @@
\the\everybodyfont} % needed ?
%D \macros
-%D {os,frak, goth, cal}
-%D
-%D Old style numerals can be typeset with \type{\os} and look
-%D like {\os 1234567890} instead of the more common looking
-%D 1234567890.
+%D {os}
%D
-%D On behalf of {\frac Tobias Burnus}, we define some more of
-%D these. Later we will link these names to real file names.
-
-% older
-%
-% \definefont [os] [OldStyle sa *]
-% \definefont [frak] [Fraktur sa *]
-% \definefont [goth] [Gothic sa *]
-% \definefont [cal] [Calligraphic sa *]
-% \definefont [bbd] [Blackboard sa *]
-%
-% newer
+%D In good old \TEX, the old style numerals were often taken
+%D from the math fonts. No longer.
-\def\os {\mathortext{\fam\purefamily {oldstyle}}{\symbolicfont {OldStyle}}}
-\def\frak{\mathortext{\fam\purefamily {fraktur}}{\symbolicfont {Fraktur}}}
-\def\goth{\mathortext{\fam\purefamily {gothic}}{\symbolicfont {Gothic}}}
-\def\cal {\mathortext{\fam\purefamily{calligraphic}}{\symbolicfont{Calligraphic}}}
-\def\bbd {\mathortext{\fam\purefamily {blackboard}}{\symbolicfont {Blackboard}}}
+\definefontfeature
+ [just-os]
+ [mode=node,onum=yes]
-\definefontsynonym [OldStyle] [Serif]
-\definefontsynonym [Fraktur] [Serif]
-\definefontsynonym [Gothic] [Serif]
-\definefontsynonym [Calligraphic] [Serif]
-\definefontsynonym [Blackboard] [Serif]
+% \def\sc{\setfontfeature{smallcaps}}
+\def\os{\setfontfeature{just-os}}
-%D \macros
-%D {fraktur, gothic, calligraphic, blackboard}
-%D
-%D These macros assume that we use text fonts, and not math
-%D families.
+%D Code for swithcing to fraktur and script has also been
+%D changed. We now have an alphabet switcher.
\ifx\mathtext\undefined \let\mathtext\hbox \fi
-\def\fraktur #1{\mathortext\domathtext\donothing{\frak#1}}
-\def\gothic #1{\mathortext\domathtext\donothing{\goth#1}}
-\def\calligraphic#1{\mathortext\domathtext\donothing{\cal #1}}
-\def\blackboard #1{\mathortext\domathtext\donothing{\bbd#1}}
-
-%D Torture test:
-%D
-%D \starttyping
-%D \usetypescript[modern] [texnansi]
-%D \usetypescript[lucida] [texnansi]
-%D \usetypescript[palatino][texnansi]
-%D \usetypescript[times] [texnansi]
-%D \usetypescript[fourier] [ec]
-%D
-%D \startbuffer
-%D \section{\blackboard{T\high{\blackboard{T}}} \blackboard{E}\high{\blackboard{E}} \blackboard{X}\high{\blackboard{X}}}
-%D
-%D {\fontclass: 123 \os123 \cal TEX $\os 123$}
-%D
-%D $\blackboard{T}^{\blackboard{T}} \blackboard{E}^{\blackboard{E}} \blackboard{X}^{\blackboard{X}}$
-%D \blackboard{T}\high{\blackboard{T}} \blackboard{E}\high{\blackboard{E}} \blackboard{X}\high{\blackboard{X}}
-%D \stopbuffer
-%D
-%D {\setupbodyfont[lucida] \getbuffer}
-%D {\setupbodyfont[modern] \getbuffer}
-%D {\setupbodyfont[palatino] \getbuffer}
-%D {\setupbodyfont[times] \getbuffer}
-%D {\setupbodyfont[fourier] \getbuffer}
-%D \stoptyping
-
%D \macros
%D {definebodyfontswitch}
%D
@@ -3264,7 +2760,7 @@
%D in the main bodyfont and style of the document. Returning to
%D the global state can be done with the next macro:
-\let\mainfontclass\empty
+\let\globalfontstyle\c!rm
\def\fullrestoreglobalbodyfont
{\let\fontsize\defaultfontsize
@@ -3420,7 +2916,7 @@
%D \stoptyping
%D
%D We deliberately pass an argument. This enables us to
-%D assign converters that handle one agrument, like
+%D assign converters that handle one argument, like
%D \type{\cap}.
%D
%D By default the first specification is used to set the style,
@@ -3429,43 +2925,11 @@
%D \type{\noconvertfont}. In nested calls, we can restore the
%D conversion by saying \type{\redoconvertfont}.
-% \def\@@dodoconvertfont#1{\csname\@letter@ #1\endcsname}
-% \def\@@donoconvertfont#1{\csname\@noletter@#1\endcsname}
-%
-% \unexpanded\def\dodoconvertfont#1% #2% we need the protection
-% {\doifdefinedelse{\@letter@#1} % in testing
-% {\doifelsenothing{#1}\gobbleoneargument\@@dodoconvertfont}
-% {\doifdefinedelse{#1}\getvalue \firstofoneargument}%
-% {#1}} % {#2}}
-%
-% \let\doconvertfont\dodoconvertfont
-%
-% \def\noconvertfont#1% #2%
-% {\doifdefinedelse{\@noletter@#1}
-% {\doifelsenothing{#1}\gobbleoneargument\@@donoconvertfont}\gobbleoneargument
-% {#1}} % {#2}}
-
-% \def\@@dodoconvertfont{\csname\@letter@ \p!defined\endcsname}
-% \def\@@donoconvertfont{\csname\@noletter@\p!defined\endcsname}
-% \def\@@redoconvertfont{\csname \p!defined\endcsname}
-%
-% \unexpanded\def\dodoconvertfont#1% #2% we need the protection
-% {\edef\p!defined{#1}%
-% \ifcsname\@letter@\detokenize\@EA{\p!defined}\endcsname
-% \ifx\p!defined\empty\else\@EAEAEA\@@dodoconvertfont\fi
-% \else
-% \ifcsname\detokenize\@EA{\p!defined}\endcsname\@EAEAEA\@@redoconvertfont\else\@EAEAEA\p!defined\fi
-% \fi} % {#2}}
-%
-% \unexpanded\def\noconvertfont#1% #2%
-% {\edef\p!defined{#1}%
-% \ifcsname\@noletter@\detokenize\@EA{\p!defined}\endcsname
-% \ifx\p!defined\empty\else\@EAEAEA\@@donoconvertfont\fi
-% \fi} % {#2}}
+% subtle ... \expandafter is needed else problems with lookahead caps
-\def\@@dodoconvertfont{\csname\@letter@ \p!defined\endcsname\gobbleoneargument}
+\def\@@dodoconvertfont{\csname\@letter@ \p!defined\expandafter\endcsname\gobbleoneargument}
\def\@@donoconvertfont{\csname\@noletter@\p!defined\endcsname}
-\def\@@redoconvertfont{\csname \p!defined\endcsname\gobbleoneargument}
+\def\@@redoconvertfont{\csname \p!defined\expandafter\endcsname\gobbleoneargument}
% beware: p!defined can contain crap like \edef crap {...} and such
% so we need to pass #1 as well
@@ -3501,11 +2965,8 @@
%D Extras:
-\unexpanded\def\dontconvertfont
- {\let\doconvertfont\noconvertfont}
-
-\unexpanded\def\redoconvertfont
- {\let\doconvertfont\dodoconvertfont}
+\unexpanded\def\dontconvertfont{\let\doconvertfont\noconvertfont}
+\unexpanded\def\redoconvertfont{\let\doconvertfont\dodoconvertfont}
%D These commands are not grouped! Grouping is most probably
%D done by the calling macro's and would lead to unnecessary
@@ -3534,13 +2995,7 @@
%D or even better:
-% \def\doemphasistypeface#1#2%
-% {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!slanted#1%
-% {\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!italic #2%
-% {\doifelsevalue{\??ft \normalizedbodyfontsize\c!em}\v!slanted#1%
-% {\doifvalue {\??ft \normalizedbodyfontsize\c!em}\v!italic #2}}}}
-
-\def\doemphasistypeface#1#2%
+\def\doemphasistypeface#1#2% slow
{\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!slanted
{#1}%
{\doifelsevalue{\??ft\fontclass\normalizedbodyfontsize\c!em}\v!italic
@@ -3553,6 +3008,25 @@
{\getvalue{\??ft\normalizedbodyfontsize\c!em}}}}
{\getvalue{\??ft\fontclass\normalizedbodyfontsize\c!em}}}}}
+% \def\doemphasistypeface#1#2%
+% {\edef\emphasizedtypeface{\csname\??ft\fontclass\normalizedbodyfontsize\c!em\endcsname}%
+% \ifx\emphasizedtypeface\v!slanted
+% #1%
+% \else\ifx\emphasizedtypeface\v!italic
+% #2%
+% \else\ifx\emphasizedtypeface\v!empty
+% \edef\emphasizedtypeface{\csname\??ft\normalizedbodyfontsize\c!em\endcsname}%
+% \ifx\emphasizedtypeface\v!slanted
+% #1%
+% \else\ifx\emphasizedtypeface\v!italic
+% #2%
+% \else
+% \getvalue\emphasizedtypeface
+% \fi\fi
+% \else
+% \getvalue\emphasizedtypeface
+% \fi\fi\fi}
+
\def\emphasistypeface{\doemphasistypeface\sl\it}
\def\emphasisboldface{\doemphasistypeface\bs\bi}
@@ -3571,15 +3045,15 @@
\setfalse\emneeded
\fi
\setemphasisboldface % new
- \ifx\fontalternative\c!it % \ifnum\fam=\itfam
+ \ifx\fontalternative\c!it
\def\emphasistypeface{\it}\tf
- \else\ifx\fontalternative\c!sl % \ifnum\fam=\slfam
+ \else\ifx\fontalternative\c!sl
\def\emphasistypeface{\sl}\tf
- \else\ifx\fontalternative\c!bf % \ifnum\fam=\bffam
+ \else\ifx\fontalternative\c!bf
\emphasisboldface
- \else\ifx\fontalternative\c!bs % \ifnum\fam=\bsfam
+ \else\ifx\fontalternative\c!bs
\def\emphasisboldface{\bs}\bf
- \else\ifx\fontalternative\c!bi % \ifnum\fam=\bifam
+ \else\ifx\fontalternative\c!bi
\def\emphasisboldface{\bi}\bf
\else
\emphasistypeface
@@ -3605,9 +3079,9 @@
\unexpanded\def\bf
{%\relax
\let\bf\relax % new
- \ifx\fontalternative\c!it % \ifnum\fam=\itfam
+ \ifx\fontalternative\c!it
\bi
- \else\ifx\fontalternative\c!sl % \ifnum\fam=\slfam
+ \else\ifx\fontalternative\c!sl
\bs
\else
\normalbf
@@ -3619,24 +3093,35 @@
%D look for something that looks like a dash, in which case we
%D don't correct.
-\let\italiccorrection=\/
+\let\italiccorrection=\/ % tex primitive
\def\emphasiscorrection
{\ifhmode
\expandafter\emphasislook
\fi}
+% \def\emphasislook
+% {\begingroup
+% \beginrobusttest
+% \futurelet\next\emphasistest}
+
+% \def\emphasistest
+% {\normalifcat\noexpand\next,%
+% \endrobusttest\expandafter\doemphasiscorrection
+% \normalelse
+% \endrobusttest\expandafter\dododoemphasiscorrection
+% \normalfi}
+
\def\emphasislook
{\begingroup
- \beginrobusttest
\futurelet\next\emphasistest}
\def\emphasistest
- {\normalifcat\noexpand\next,%
- \endrobusttest\expandafter\doemphasiscorrection
- \normalelse
- \endrobusttest\expandafter\dododoemphasiscorrection
- \normalfi}
+ {\ifcat\noexpand\next,% still ok?
+ \expandafter\doemphasiscorrection
+ \else
+ \expandafter\dododoemphasiscorrection
+ \fi}
\def\doemphasiscorrection
{\futurelet\next\dodoemphasiscorrection}
@@ -3792,11 +3277,6 @@
%D \stopbuffer
%D
%D \typebuffer
-%D
-%D Below the table the name, encoding, mapping and handling are
-%D shown. Special characters like the \type {\skewchar} and
-%D \type {\hyphenchar} als marked.
-%D
%D \getbuffer
% to be internationalized
@@ -3954,49 +3434,6 @@
%D The shape as well as the size is adapted to the current
%D environment.
-%D Fonts can only be used when loaded. In \CONTEXT\ we
-%D postpone the loading of fonts, even when we load \PLAIN.
-%D This means that we have to redefine one of the \PLAIN\
-%D macros. Let's tell that to the user first:
-
-\writestatus{loading}{Postponed Plain TeX Font Definitions}
-
-%D \macros
-%D {bordermatrix}
-%D
-%D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
-%D the \DIMENSION\ \type{\p@renwd}. This value is derived from
-%D the width of \type{\tenrm B}, so let's take care of it now:
-
-\let\normalbordermatrix=\bordermatrix
-
-\def\bordermatrix%
- {\bgroup
- \setbox0\hbox{\getvalue{\textface\c!mm\c!ex}B}%
- \global\p@renwd\wd0\relax
- \egroup
- \normalbordermatrix}
-
-%D Because we want to be as \PLAIN\ compatible as possible, we
-%D make most of \PLAIN's font mechanisme available to the
-%D \CONTEXT\ user.
-
-\def\setplainfonts#1#2%
- {\setvalue {ten#1}{\getvalue{\!!tenpoint #2}}%
- \setvalue{seven#1}{\getvalue{\!!sevenpoint#2}}%
- \setvalue {five#1}{\getvalue{\!!fivepoint #2}}}
-
-\setplainfonts {\c!rm} {\c!rm\c!tf}
-\setplainfonts {\c!bf} {\c!rm\c!bf}
-\setplainfonts {\c!sl} {\c!rm\c!sl}
-\setplainfonts {\c!it} {\c!rm\c!it}
-\setplainfonts {\c!tt} {\c!rm\c!tt}
-\setplainfonts {\c!sy} {\c!mm\c!sy}
-\setplainfonts {\c!ex} {\c!mm\c!ex}
-\setplainfonts {\c!i} {\c!mm\c!mi}
-
-\let\setplainfonts=\undefined
-
%D \macros
%D {ss, SS, sz}
%D
@@ -4008,81 +3445,11 @@
\ifx\undefined\SS \let\SS=\ss \fi
\ifx\undefined\sz \let\sz=\ss \fi
-%D \macros
-%D {xi}
-%D
-%D We are going to redefine \type{\xi}, but fortunately this
-%D is a math mode character, so we can just say:
-
-\let\normalxi=\xi
-
-%D \macros
-%D {smashaccent}
-%D
-%D When we let \TEX\ put an accent on top of a character, such
-%D composed characters can get more height that height of a
-%D standard \type{\strut}. The next macro takes care of such
-%D unwanted compositions.
-%D
-%D We need to reach over the number that specifies the accent,
-%D and in doing so we use \type{\scratchcounter} as a placeholder
-%D because it accepts 8 bit numbers in octal, decimal or
-%D hexadecimal format. Next we set the height of the accented
-%D character to the natural height of the character.
-
-\unexpanded\def\smashaccent#1%
- {\dontleavehmode
- \bgroup
- \setbox\scratchbox\hbox{#1}%
- \ifdim\ht\scratchbox>\strutheight\relax\ht\scratchbox\strutheight\fi
- \ifdim\dp\scratchbox>\strutdepth \relax\dp\scratchbox\strutdepth \fi
- \box\scratchbox
- \egroup}
-
-%D For instance we can say:
-%D
-%D \starttyping
-%D \smashaccent{\"Uberhaupt}
-%D \stoptyping
-%D
-%D But normally one will use it as a prefix in definitions.
-%D The difference is in the height:
-%D
-%D \leavevmode\ruledhbox
-%D {\ruledhbox{\smashaccent{\"U}berhaupt}\quad
-%D oder\quad
-%D \ruledhbox{\"Uberhaupt}}
-
-%D \macros
-%D {moveaccent}
-%D
-%D Exact positioning of accents can be realized by saying:
-%D
-%D \starttyping
-%D \moveaccent{-.1ex}{\"u}berhaupt
-%D \stoptyping
-%D
-%D Again, this one will mostly used as a prefix in definitions.
-%D Here the difference is in the position:
-%D
-%D \leavevmode\ruledhbox
-%D {\ruledhbox{\moveaccent{-.1ex}{\"}Uberhaupt}\quad
-%D oder\quad
-%D \ruledhbox{\"Uberhaupt}}
-
-\unexpanded\def\moveaccent#1#2%
- {\smashaccent
- {\dimen0\exheight
- \dimen2\dimen0
- \advance\dimen2 -#1%
- \exheight\dimen2
- #2\relax
- \exheight\dimen0}}
-
-%D Personally I think that using \TEX\ is complicated by the
-%D way fonts are handled. Apart from the many encodings, we
-%D also deal with different naming schemes. Confronted with
-%D this problem, I decided to change the definitions into:
+%D Personally I think that using \TEX\ macro packages is
+%D complicated by the way fonts are handled. Apart from the
+%D many encodings, we also deal with different naming schemes.
+%D Confronted with this problem, I decided to change the
+%D definitions into:
%D
%D \starttyping
%D \definebodyfont [12pt] [rm] [tf=Times-Roman at 12pt]
@@ -4244,22 +3611,31 @@
\definebodyfontswitch [fivepoint] [\!!fivepoint]
\definebodyfontswitch [fourpoint] [\!!fourpoint]
-\definebodyfontswitch [xii] [\!!twelvepoint]
-\definebodyfontswitch [xi] [\!!elevenpoint]
-\definebodyfontswitch [x] [\!!tenpoint]
-\definebodyfontswitch [ix] [\!!ninepoint]
-\definebodyfontswitch [viii] [\!!eightpoint]
-\definebodyfontswitch [vii] [\!!sevenpoint]
-\definebodyfontswitch [vi] [\!!sixpoint]
+% \definebodyfontswitch [xii] [\!!twelvepoint]
+% \definebodyfontswitch [xi] [\!!elevenpoint]
+% \definebodyfontswitch [x] [\!!tenpoint]
+% \definebodyfontswitch [ix] [\!!ninepoint]
+% \definebodyfontswitch [viii] [\!!eightpoint]
+% \definebodyfontswitch [vii] [\!!sevenpoint]
+% \definebodyfontswitch [vi] [\!!sixpoint]
%D So far.
+\definefontstyle [\c!mm] [\c!mm]
\definefontstyle [\c!rm,\v!roman,\v!serif,\v!regular] [\c!rm]
\definefontstyle [\c!ss,\v!sansserif,\v!sans,\v!support] [\c!ss]
\definefontstyle [\c!tt,\v!teletype,\v!type,\v!mono] [\c!tt]
\definefontstyle [\c!hw,\v!handwritten] [\c!hw]
\definefontstyle [\c!cg,\v!calligraphic] [\c!cg]
+\definefontalternative[\c!tf]
+\definefontalternative[\c!bf]
+\definefontalternative[\c!it]
+\definefontalternative[\c!sl]
+\definefontalternative[\c!bs]
+\definefontalternative[\c!bi]
+\definefontalternative[\c!sc]
+
\definefontsize[\c!a] \definefontsize[\c!b]
\definefontsize[\c!c] \definefontsize[\c!d]
@@ -4295,41 +3671,11 @@
\definealternativestyle [\v!WORD] [\WORD] [\WORD]
%D \macros
-%D {...math}
-%D
-%D New or old?
-
-% tzt proper \define...
-%
-% watch out: \synchronizesymb resets the family so we need a second
-% \mf (or maybe \mr): messy and to be sorted out
-
-\def\tfmath{\tf\mf\synchronizesymb\mf}
-\def\bfmath{\bf\mf\synchronizesymb\mf}
-\def\slmath{\sl\mf\synchronizesymb\mf}
-\def\itmath{\it\mf\synchronizesymb\mf}
-\def\bsmath{\bs\mf\synchronizesymb\mf}
-\def\bimath{\bi\mf\synchronizesymb\mf}
-\def\scmath{\sc\mf\synchronizesymb\mf}
-\def\nnmath{\nn\mf\synchronizesymb\mf}
-
-\def\textmath {\synchronizesymb}
-
-%D \macros
%D {fontstylesuffix}
%D
%D The next macro is used to map non latin fontnames on
%D fonts. See \type {font-uni} for an example of its use.
-%\def\fontstylesuffix%
-% {\ifnum\fam=\tffam \s!Regular \else
-% \ifnum\fam=\bffam \s!Bold \else
-% \ifnum\fam=\slfam \s!Slanted \else
-% \ifnum\fam=\itfam \s!Italic \else
-% \ifnum\fam=\bsfam \s!BoldSlanted \else
-% \ifnum\fam=\bifam \s!BoldItalic \else
-% \s!Regular \fi\fi\fi\fi\fi\fi}%
-
\def\fontstylesuffix% why the \s!Regular ? see \getglyph
{\ifx\fontalternative\c!tf \s!Regular \else
\ifx\fontalternative\c!bf \s!Bold \else
@@ -4340,10 +3686,6 @@
\ifx\fontalternative\c!sc \s!Caps \else
\s!Regular \fi\fi\fi\fi\fi\fi\fi}%
-%D We still have to take care of \type{\xi}, so:
-
-\def\xi{\ifmmode\normalxi\else\elevenpoint\fi}
-
%D \macros
%D {definefontvariant,fontvariant,variant}
%D
@@ -4383,7 +3725,7 @@
\unexpanded\def\variant[#1]% slow
{\dosetscaledfont
- \expanded{\definedfont[\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1} at \the\dimexpr\scaledfontsize\relax]}%
+ \normalexpanded{\noexpand\definedfont[\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1} at \the\dimexpr\scaledfontsize\relax]}%
\ignoreimplicitspaces}
\ifx\Var\undefined \let\Var\variant \fi
@@ -4393,262 +3735,113 @@
%D bodyfont. Sans serif and teletype are also available and
%D can be called for by \type{\ss} and \type{\tt}.
-\setupbodyfont [unk, rm]
+% \setupbodyfont [unk, rm]
+% \setupbodyfont [rm]
%D Also needed is:
\definefont[tinyfont][Mono at 1ex]
-%D \macros
-%D {doiffontpresentelse}
-%D
-%D \starttyping
-%D \doiffontpresentelse{texnansi-lmr10}{YES}{NO}
-%D \doiffontpresentelse{adam-lindsay-modern-serif}{YES}{NO}
-%D \stoptyping
+% \tracinglostchars=1
-\def\doiffontpresentelse#1{\ctxlua{commands.doifelse(fonts.names.exists("#1"))}}
+% this needs some interfacing
+%
+% \setupfonts[check=...]
-%D OPTIMIZATIONS
+\def\checkcharactersinfont {\ctxlua{fonts.checkers.enabled=true}}
+\def\removemissingcharacters{\ctxlua{fonts.checkers.enabled=true fonts.checkers.delete=true}}
-\def\definefontsynonym[#1]#2[#3]%
- {\edef\@@fontname{#1}%
- \edef\@@fontfile{#3}%
- \@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
- \doifnextcharelse[\dodefinefontsynonym\nodefinefontsynonym}
+%D New commands (not yet interfaced):
-\def\dodefinefontsynonym[#1]%
- {\let\@@ff@@features \undefined
- \let\@@ff@@fallbacks\undefined
- \let\@@ff@@skewchar \undefined
- \expandafter\dogetfontparameter#1,]=,}
+\def\style[#1]% for inline usage, like \color
+ {\groupedcommand{\ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}{}}
-\def\dogetfontparameter#1=#2,%
- {\if]#1%
- \dododefinefontsynonym
- \else
- \expandafter\def\csname @@ff@@#1\endcsname{#2}%
- \expandafter\dogetfontparameter
- \fi}
+\def\startstyle[#1]%
+ {\begingroup
+ \ifcsname#1\endcsname\csname#1\endcsname\else\definedfont[#1]\fi}
-\def\nodefinefontsynonym
- {\ifx\fontclass\empty
- \@EA\let\csname\??ff\@@fontname\s!features \endcsname\undefined
- \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined
- \@EA\let\csname\??ff\@@fontfile\s!skewchar \endcsname\undefined
- \else
- \global\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\undefined
- \global\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined
- \global\@EA\let\csname\??ff\fontclass\@@fontfile\s!skewchar \endcsname\undefined
- \fi}
+\def\stopstyle
+ {\endgroup}
-\def\dododefinefontsynonym
- {\ifx\fontclass\empty
- \@EA\let\csname\??ff\@@fontname\s!features \endcsname\@@ff@@features
- \@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
- \@EA\let\csname\??ff\@@fontfile\s!skewchar \endcsname\@@ff@@skewchar
- \else
- \global\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\@@ff@@features
- \global\@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
- \global\@EA\let\csname\??ff\fontclass\@@fontfile\s!skewchar \endcsname\@@ff@@skewchar
- \fi}
+%D Still experimental (might even go away).
-\def\truefontname#1%
- {\ifcsname\??ff\fontclass#1\endcsname
- \@EA\truefontname\csname\??ff\fontclass#1\endcsname
- \else\ifcsname\??ff#1\endcsname
- \@EA\truefontname\csname\??ff#1\endcsname
- \else
- #1%
- \fi\fi}
+% \definestylecollection[mine]
-\def\updatefontparameters
- {\edef\@@fontfeatures {\@@thefeatures \somefontname}%
- \edef\@@fontfallbacks{\@@thefallbacks\somefontname}%
- \edef\@@fontskewchar {\@@theskewchar \somefontname}}
-
-\def\@@thefeatures#1%
- {\ifcsname\??ff\fontclass#1\s!features\endcsname \csname\??ff\fontclass#1\s!features\endcsname\else % class + symbolic_name
- \ifcsname\??ff #1\s!features\endcsname \csname\??ff #1\s!features\endcsname\else % symbolic_name
- \ifcsname\??ff\fontclass#1\endcsname \@EA\@@thefeatures\csname\??ff\fontclass#1\endcsname \else % fontclass + parent_name
- \ifcsname\??ff #1\endcsname \@EA\@@thefeatures\csname\??ff #1\endcsname \fi\fi\fi\fi} % parent_name
-
-\def\@@thefallbacks#1%
- {\ifcsname\??ff\fontclass#1\s!fallbacks\endcsname \csname\??ff\fontclass#1\s!fallbacks\endcsname\else % class + symbolic_name
- \ifcsname\??ff #1\s!fallbacks\endcsname \csname\??ff #1\s!fallbacks\endcsname\else % symbolic_name
- \ifcsname\??ff\fontclass#1\endcsname \@EA\@@thefallbacks\csname\??ff\fontclass#1\endcsname \else % fontclass + parent_name
- \ifcsname\??ff #1\endcsname \@EA\@@thefallbacks\csname\??ff #1\endcsname \fi\fi\fi\fi} % parent_name
-
-\def\@@theskewchar#1% skew chars will be done differently (just a hash with registered skewchars)
- {\ifcsname\??ff\fontclass#1\s!skewchar\endcsname \csname\??ff\fontclass#1\s!skewchar\endcsname\else % class + symbolic_name
- \ifcsname\??ff #1\s!skewchar\endcsname \csname\??ff #1\s!skewchar\endcsname\else % symbolic_name
- \ifcsname\??ff\fontclass#1\endcsname \@EA\@@theskewchar\csname\??ff\fontclass#1\endcsname \else % fontclass + parent_name
- \ifcsname\??ff #1\endcsname \@EA\@@theskewchar\csname\??ff #1\endcsname \fi\fi\fi\fi} % parent_name
-
-% more efficient ?
+% \definestyleinstance[mine][default][sorry]
+% \definestyleinstance[mine][tt][bs][ttbs:\rm\sl]
+% \definestyleinstance[mine][tt][bf][ttbf:\rm\sl]
+% \definestyleinstance[mine][bf][\sl]
+% \definestyleinstance[mine][sl][\tt]
-\def\definefontsynonym[#1]#2[#3]%
- {\edef\@@fontname{#1}%
- \edef\@@fontfile{#3}%
- \ifx\fontclass\empty
- \expandafter\dodefinefontsynonymnop
- \else
- \expandafter\dodefinefontsynonymyes
- \fi}
+% {\bf test \mine test \sl test \mine test \bs oeps \mine oeps {\tt test \mine \bf test}}
-\def\dodefinefontsynonymyes
- {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
- \doifnextcharelse[\dododefinefontsynonymyes\nonodefinefontsynonymyes}
-\def\dodefinefontsynonymnop
- {\@EA\let\csname\??ff\@@fontname\endcsname\@@fontfile % maybe just #1 #3, saves expansion
- \doifnextcharelse[\dododefinefontsynonymnop\nonodefinefontsynonymnop}
+\definesystemvariable{sx}
-\def\dododefinefontsynonymyes[#1]%
- {\let\@@ff@@features \undefined
- \let\@@ff@@fallbacks\undefined
- \let\@@ff@@skewchar \undefined
- \expandafter\dogetfontparameteryes#1,]=,}
-\def\dododefinefontsynonymnop[#1]%
- {\let\@@ff@@features \undefined
- \let\@@ff@@fallbacks\undefined
- \let\@@ff@@skewchar \undefined
- \expandafter\dogetfontparameternop#1,]=,}
+\def\definestylecollection
+ {\dosingleargument\dodefinestylecollection}
-\def\dogetfontparameteryes#1=#2,%
- {\if]#1%
- \dodododefinefontsynonymyes
- \else
- \expandafter\def\csname @@ff@@#1\endcsname{#2}%
- \expandafter\dogetfontparameteryes
+\def\dodefinestylecollection[#1]%
+ {\iffirstargument
+ \unexpanded\setvalue{#1}{\styleinstance[#1]}%
+ \def\docommand##1%
+ {\def\dodocommand####1{\letbeundefined{\??sx##1:####1:\commalistelement}}%
+ \processcommacommand[\fontalternativelist,\s!default]\dodocommand}%
+ \processcommacommand[\fontstylelist,\s!default]\docommand
\fi}
-\def\dogetfontparameternop#1=#2,%
- {\if]#1%
- \dodododefinefontsynonymnop
- \else
- \expandafter\def\csname @@ff@@#1\endcsname{#2}%
- \expandafter\dogetfontparameternop
- \fi}
-
-\def\nonodefinefontsynonymyes
- {\global\@EA\let\csname\??ff\@@fontname\s!features \endcsname\undefined
- \global\@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\undefined
- \global\@EA\let\csname\??ff\@@fontfile\s!skewchar \endcsname\undefined}
-\def\nonodefinefontsynonymnop
- {\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\undefined
- \@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\undefined
- \@EA\let\csname\??ff\fontclass\@@fontfile\s!skewchar \endcsname\undefined}
-
-\def\dodododefinefontsynonymyes
- {\global\@EA\let\csname\??ff\@@fontname\s!features \endcsname\@@ff@@features
- \global\@EA\let\csname\??ff\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
- \global\@EA\let\csname\??ff\@@fontfile\s!skewchar \endcsname\@@ff@@skewchar}
-\def\dodododefinefontsynonymnop
- {\@EA\let\csname\??ff\fontclass\@@fontname\s!features \endcsname\@@ff@@features
- \@EA\let\csname\??ff\fontclass\@@fontname\s!fallbacks\endcsname\@@ff@@fallbacks
- \@EA\let\csname\??ff\fontclass\@@fontfile\s!skewchar \endcsname\@@ff@@skewchar}
-
-% resolve
-
-\def\@@thefeaturesyes#1%
- {\ifcsname\??ff\fontclass#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff\fontclass#1\s!features \endcsname\else
- \ifcsname\??ff #1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff #1\s!features \endcsname\else
- \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefeaturesyes \csname\??ff\fontclass #1\endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesyes \csname\??ff #1\endcsname\else
- \let \@@fontfeatures \empty \fi\fi\fi\fi}
-\def\@@thefallbacksyes#1%
- {\ifcsname\??ff\fontclass#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff\fontclass#1\s!fallbacks\endcsname\else
- \ifcsname\??ff #1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff #1\s!fallbacks\endcsname\else
- \ifcsname\??ff\fontclass #1\endcsname\@EA \@@thefallbacksyes\csname\??ff\fontclass #1\endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksyes\csname\??ff #1\endcsname\else
- \let \@@fontfallbacks \empty \fi\fi\fi\fi}
-\def\@@theskewcharyes#1%
- {\ifcsname\??ff\fontclass#1\s!skewchar \endcsname\@EA\let\@EA\@@fontskewchar \csname\??ff\fontclass#1\s!skewchar \endcsname\else
- \ifcsname\??ff #1\s!skewchar \endcsname\@EA\let\@EA\@@fontskewchar \csname\??ff #1\s!skewchar \endcsname\else
- \ifcsname\??ff\fontclass #1\endcsname\@EA \@@theskewcharyes \csname\??ff\fontclass #1\endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@theskewcharyes \csname\??ff #1\endcsname\else
- \let \@@fontskewchar \empty \fi\fi\fi\fi}
-
-\def\@@thefeaturesnop#1%
- {\ifcsname\??ff#1\s!features \endcsname\@EA\let\@EA\@@fontfeatures \csname\??ff#1\s!features \endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@thefeaturesnop \csname\??ff #1\endcsname\else
- \let \@@fontfeatures \empty \fi\fi}
-\def\@@thefallbacksnop#1%
- {\ifcsname\??ff#1\s!fallbacks\endcsname\@EA\let\@EA\@@fontfallbacks \csname\??ff#1\s!fallbacks\endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@thefallbacksnop\csname\??ff #1\endcsname\else
- \let \@@fontfallbacks \empty \fi\fi}
-\def\@@theskewcharnop#1%
- {\ifcsname\??ff#1\s!skewchar \endcsname\@EA\let\@EA\@@fontskewchar \csname\??ff#1\s!skewchar \endcsname\else
- \ifcsname\??ff #1\endcsname\@EA \@@theskewcharnop \csname\??ff #1\endcsname\else
- \let \@@fontskewchar \empty \fi\fi}
-\def\updatefontparametersyes
- {\@@thefeaturesyes \somefontname
- \@@thefallbacksyes\somefontname
- \@@theskewcharyes \somefontname}
-\def\updatefontparametersnop
- {\@@thefeaturesnop \somefontname
- \@@thefallbacksnop\somefontname
- \@@theskewcharnop \somefontname}
+\def\definestyleinstance
+ {\doquadrupleargument\dodefinestyleinstance}
-\def\updatefontparameters
- {\ifx\fontclass\empty\updatefontparametersnop\else\updatefontparametersyes\fi}
+\def\dodefinestyleinstance[#1][#2][#3][#4]% [name] [rm|ss|tt|..] [sl|bf|...] [whatever]
+ {\iffirstargument
+ \doifundefined{#1}{\definestylecollection[#1]}%
+ \fi
+ \iffourthargument
+ \setvalue{\??sx#1:#2:#3}{#4}%
+ \else\ifthirdargument
+ \setvalue{\??sx#1::#2}{#3}%
+ \else\ifsecondargument
+ \letvalue{\??sx#1::#2}\empty
+ \fi\fi\fi}
+
+\unexpanded\def\styleinstance[#1]% will be faster
+ {%\begingroup\normalexpanded{\noexpand\infofont[#1:\fontstyle:\fontalternative]}\endgroup
+ \executeifdefined{\??sx#1:\fontstyle:\fontalternative}%
+ {\executeifdefined{\??sx#1:\fontstyle:\s!default}%
+ {\executeifdefined{\??sx#1::\fontalternative}
+ {\getvalue {\??sx#1::\s!default}}}}}
+
+% \unexpanded\def\styleinstance[#1]%
+% {\csname\??sx#1%
+% \ifcsname:\fontstyle:\fontalternative\endcsname
+% :\fontstyle:\fontalternative
+% \else\ifcsname:\fontstyle:\s!default\endcsname
+% :\fontstyle:\s!default
+% \else\ifcsname::\fontalternative\endcsname
+% ::\fontalternative
+% \else\ifcsname::\s!default\endcsname
+% ::\s!default
+% \else
+% % nothing, \relax
+% \fi\fi\fi\fi
+% \endcsname}
\protect \endinput
-% bewaren
-%
-% \def\truefontdata#1#2%
-% {\ifcsname\??ff\fontclass#1#2\endcsname
-% % raw(Regular) raw(key)
-% \csname\??ff\fontclass#1#2\endcsname
-% \else\ifcsname\??ff\fontclass#1\endcsname
-% % exp(palatino Regular) raw(key)
-% \expandafter\truefontdata\csname\??ff\fontclass#1\endcsname#2%
-% \else\ifcsname\??ff#1\endcsname
-% % exp(Regular) raw(key)
-% \expandafter\truefontdata\csname\??ff#1\endcsname#2%
-% \else\ifcsname\??ff#2\endcsname
-% % raw(key)
-% \csname\??ff#2\endcsname
-% \fi\fi\fi\fi}
-
-% test file
-%
-% \starttypescript[serif][mine-1]
-% \definefontsynonym[Serif] [TeXGyrePagella-Regular]
-% \definefontsynonym[TeXGyrePagella-Regular][file:texgyrepagella-regular]
-% \stoptypescript
-%
-% \starttypescript[serif][mine-2]
-% \definefontsynonym[Serif] [TeXGyrePagella-Regular] [features=default]
-% \definefontsynonym[TeXGyrePagella-Regular][file:texgyrepagella-regular] [features=oldstyle]
-% \stoptypescript
-%
-% \starttypescript[serif][mine-3]
-% \definefontsynonym[Serif] [TeXGyrePagella-Regular] [features=oldstyle]
-% \definefontsynonym[TeXGyrePagella-Regular][file:texgyrepagella-regular] [features=default]
-% \stoptypescript
-%
-% \starttypescript[serif][mine-4]
-% \definefontsynonym[Serif] [TeXGyrePagella-Regular] [features=default]
-% \definefontsynonym[TeXGyrePagella-Regular][file:texgyrepagella-regular] [features=default]
-% \stoptypescript
-%
-% \starttypescript[serif][mine-5]
-% \definefontsynonym[Serif] [TeXGyrePagella-Regular] [features=oldstyle]
-% \definefontsynonym[TeXGyrePagella-Regular][file:texgyrepagella-regular] [features=oldstyle]
-% \stoptypescript
-%
-% \starttext
-% \dorecurse {5} {
-% \expanded{\definetypeface[mine-\recurselevel][rm][serif][mine-\recurselevel][default]}
-% \expanded{\setupbodyfont [mine-\recurselevel] mine-\recurselevel: text 1234567890 done}
-% \par
-% }
-% \blank
-% \dorecurse {5} {
-% \expanded{\definetypeface[more-\recurselevel][rm][serif][mine-\recurselevel][default][features=oldstyle]}
-% \expanded{\setupbodyfont [more-\recurselevel] mine-\recurselevel: text 1234567890 done}
-% \par
-% }
-% \stoptext
+% \startluacode
+% function commands.doifelsecurrentfonthasfeature(name)
+% local f = fonts.ids[font.current()]
+% f = f and f.shared
+% f = f and f.otfdata
+% f = f and f.luatex
+% f = f and f.features
+% commands.doifelse(f and (f.gpos[name] or f.gsub[name]))
+% end
+% \stopluacode
+
+% \def\doifelsecurrentfonthasfeature#1%
+% {\ctxlua{commands.doifelsecurrentfonthasfeature("#1")}}
+
+% \doifelsecurrentfonthasfeature{smcp}{YES}{NO}
+% \doifelsecurrentfonthasfeature{crap}{YES}{NO}
+% \doifelsecurrentfonthasfeature{kern}{YES}{NO}
diff --git a/tex/context/base/font-jap.tex b/tex/context/base/font-jap.tex
index 6bb813ccc..42480df43 100644
--- a/tex/context/base/font-jap.tex
+++ b/tex/context/base/font-jap.tex
@@ -15,7 +15,7 @@
\ifx\handlejapaneseunicodeglyph\undefined \else \endinput \fi
\ifx\handlechineseunicodeglyph \undefined \input font-chi.tex \fi
-\writestatus{loading}{Context Font Macros / Japanese}
+\writestatus{loading}{ConTeXt Font Macros / Japanese}
\unprotect
diff --git a/tex/context/base/font-log.lua b/tex/context/base/font-log.lua
new file mode 100644
index 000000000..499bd4304
--- /dev/null
+++ b/tex/context/base/font-log.lua
@@ -0,0 +1,53 @@
+if not modules then modules = { } end modules ['font-log'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, format, lower, concat = next, string.format, string.lower, table.concat
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+fonts.logger = fonts.logger or { }
+
+--[[ldx--
+<p>The following functions are used for reporting about the fonts
+used. The message itself is not that useful in regular runs but since
+we now have several readers it may be handy to know what reader is
+used for which font.</p>
+--ldx]]--
+
+function fonts.logger.save(tfmtable,source,specification) -- save file name in spec here ! ! ! ! ! !
+ if tfmtable and specification and specification.specification then
+ local name = lower(specification.name)
+ if trace_defining and not fonts.used[name] then
+ logs.report("define font","registering %s as %s",file.basename(specification.name),source)
+ end
+ specification.source = source
+ fonts.loaded[lower(specification.specification)] = specification
+ fonts.used[name] = source
+ end
+end
+
+function fonts.logger.report()
+ local t = { }
+ for name, used in table.sortedpairs(fonts.used) do
+ t[#t+1] = file.basename(name) .. ":" .. used
+ end
+ return t
+end
+
+function fonts.logger.format(name)
+ return fonts.used[name] or "unknown"
+end
+
+statistics.register("loaded fonts", function()
+ if next(fonts.used) then
+ local t = fonts.logger.report(separator)
+ return (#t > 0 and format("%s files: %s",#t,concat(t,separator or " "))) or "none"
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/font-map.lua b/tex/context/base/font-map.lua
index 64ff268fb..35cfaf32f 100644
--- a/tex/context/base/font-map.lua
+++ b/tex/context/base/font-map.lua
@@ -6,6 +6,10 @@ if not modules then modules = { } end modules ['font-map'] = {
license = "see context related readme files"
}
+local match, format, find = string.match, string.format, string.find
+
+local ctxcatcodes = tex.ctxcatcodes
+
--[[ldx--
<p>Eventually this code will disappear because map files are kind
of obsolete. Some code may move to runtime or auxiliary modules.</p>
@@ -29,21 +33,21 @@ function fonts.map.line.pdftex(e) -- so far no combination of slant and stretch
local fullname = e.fullname or ""
if e.slant and e.slant ~= 0 then
if e.encoding then
- return fonts.map.line.pdfmapline("=",string.format('%s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile))
else
- return fonts.map.line.pdfmapline("=",string.format('%s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile))
end
elseif e.stretch and e.stretch ~= 1 and e.stretch ~= 0 then
if e.encoding then
- return fonts.map.line.pdfmapline("=",string.format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.stretch,e.encoding,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.stretch,e.encoding,e.fontfile))
else
- return fonts.map.line.pdfmapline("=",string.format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.stretch,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.stretch,e.fontfile))
end
else
if e.encoding then
- return fonts.map.line.pdfmapline("=",string.format('%s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile))
else
- return fonts.map.line.pdfmapline("=",string.format('%s %s <%s',e.name,fullname,e.fontfile))
+ return fonts.map.line.pdfmapline("=",format('%s %s <%s',e.name,fullname,e.fontfile))
end
end
else
@@ -54,7 +58,7 @@ end
function fonts.map.flush(backend) -- will also erase the accumulated data
local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex
for _, e in pairs(fonts.map.data) do
- tex.sprint(tex.ctxcatcodes,flushline(e))
+ tex.sprint(ctxcatcodes,flushline(e))
end
fonts.map.data = { }
end
@@ -76,27 +80,27 @@ function fonts.map.load_file(filename, entries, encodings)
if f then
local data = f:read("*a")
if data then
- for line in data:gmatch("(.-)[\n\t]") do
- if line:find("^[%#%%%s]") then
+ for line in gmatch(data,"(.-)[\n\t]") do
+ if find(line,"^[%#%%%s]") then
-- print(line)
else
local stretch, slant, name, fullname, fontfile, encoding
line = line:gsub('"(.+)"', function(s)
- stretch = s:find('"([^"]+) ExtendFont"')
- slant = s:find('"([^"]+) SlantFont"')
+ stretch = find(s,'"([^"]+) ExtendFont"')
+ slant = find(s,'"([^"]+) SlantFont"')
return ""
end)
if not name then
-- name fullname encoding fontfile
- name, fullname, encoding, fontfile = line:match("^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$")
+ name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$")
end
if not name then
-- name fullname (flag) fontfile encoding
- name, fullname, fontfile, encoding = line:match("^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$")
+ name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$")
end
if not name then
-- name fontfile
- name, fontfile = line:match("^(%S+)%s+[%d%s<]+(%S*)%s*$")
+ name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$")
end
if name then
if encoding == "" then encoding = nil end
diff --git a/tex/context/base/font-mis.lua b/tex/context/base/font-mis.lua
new file mode 100644
index 000000000..520f9e7a6
--- /dev/null
+++ b/tex/context/base/font-mis.lua
@@ -0,0 +1,91 @@
+if not modules then modules = { } end modules ['font-mis'] = {
+ version = 1.001,
+ comment = "companion to luatex-fonts.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, pairs, ipairs = next, pairs, ipairs
+local lower, strip = string.lower, string.strip
+
+fonts.otf = fonts.otf or { }
+
+fonts.otf.version = fonts.otf.version or 2.626
+fonts.otf.pack = true
+fonts.otf.cache = containers.define("fonts", "otf", fonts.otf.version, true)
+
+function fonts.otf.loadcached(filename,format,sub)
+ -- no recache when version mismatch
+ local name = file.basename(file.removesuffix(filename))
+ if sub == "" then sub = false end
+ local hash = name
+ if sub then
+ hash = hash .. "-" .. sub
+ end
+ hash = containers.cleanname(hash)
+ local data = containers.read(fonts.otf.cache(), hash)
+ if data and not data.verbose then
+ fonts.otf.enhancers.unpack(data)
+ return data
+ else
+ return nil
+ end
+end
+
+function fonts.get_features(name,t,script,language)
+ local t = lower(t or (name and file.extname(name)) or "")
+ if t == "otf" or t == "ttf" or t == "ttc" then
+ local filename = resolvers.find_file(name,t) or ""
+ if filename ~= "" then
+ local data = fonts.otf.loadcached(filename)
+ if data and data.luatex and data.luatex.features then
+ return data.luatex.features
+ else
+ local ff = fontloader.open(filename)
+ if ff then
+ local data = fontloader.to_table(ff)
+ fontloader.close(ff)
+ local features = { }
+ for k, what in pairs { "gsub", "gpos" } do
+ local dw = data[what]
+ if dw then
+ local f = { }
+ features[what] = f
+ for _, d in ipairs(dw) do
+ if d.features then
+ for _, df in ipairs(d.features) do
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ for _, ds in ipairs(df.scripts) do
+ local scri = strip(lower(ds.script))
+ local fts = ft[scri] if not fts then fts = {} ft[scri] = fts end
+ for _, lang in ipairs(ds.langs) do
+ lang = strip(lower(lang))
+ if scri == script then
+ if lang == language then
+ fts[lang] = 'sl'
+ else
+ fts[lang] = 's'
+ end
+ else
+ if lang == language then
+ fts[lang] = 'l'
+ else
+ fts[lang] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ return features
+ end
+ end
+ end
+ end
+ return nil, nil
+end
diff --git a/tex/context/base/font-ota.lua b/tex/context/base/font-ota.lua
new file mode 100644
index 000000000..72e7414c8
--- /dev/null
+++ b/tex/context/base/font-ota.lua
@@ -0,0 +1,320 @@
+if not modules then modules = { } end modules ['font-ota'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (analysing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this might become scrp-*.lua
+
+local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
+
+if not trackers then trackers = { register = function() end } end
+
+local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+local trace_cjk = false trackers.register("cjk.injections", function(v) trace_cjk = v end)
+
+trackers.register("cjk.analyzing","otf.analyzing")
+
+fonts = fonts or { }
+fonts.analyzers = fonts.analyzers or { }
+fonts.analyzers.initializers = fonts.analyzers.initializers or { node = { otf = { } } }
+fonts.analyzers.methods = fonts.analyzers.methods or { node = { otf = { } } }
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local initializers = fonts.analyzers.initializers
+local methods = fonts.analyzers.methods
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local delete_node = nodes.delete
+local replace_node = nodes.replace
+local insert_node_after = node.insert_after
+local insert_node_before = node.insert_before
+local traverse_node_list = node.traverse
+
+local fontdata = fonts.ids
+local state = attributes.private('state')
+
+local fcs = (fonts.color and fonts.color.set) or function() end
+local fcr = (fonts.color and fonts.color.reset) or function() end
+
+local a_to_script = otf.a_to_script
+local a_to_language = otf.a_to_language
+
+-- in the future we will use language/script attributes instead of the
+-- font related value, but then we also need dynamic features which is
+-- somewhat slower; and .. we need a chain of them
+
+
+function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = initializers[script]
+ if action then
+ if type(action) == "function" then
+ return action(tfmdata,value)
+ else
+ local action = action[language]
+ if action then
+ return action(tfmdata,value)
+ end
+ end
+ end
+ return nil
+end
+
+function fonts.methods.node.otf.analyze(head,font,attr)
+ local tfmdata = fontdata[font]
+ local script, language
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = methods[script]
+ if action then
+ if type(action) == "function" then
+ return action(head,font,attr)
+ else
+ action = action[language]
+ if action then
+ return action(head,font,attr)
+ end
+ end
+ end
+ return head, false
+end
+
+otf.features.register("analyze",true) -- we always analyze
+table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
+
+-- latin
+
+fonts.analyzers.methods.latn = fonts.analyzers.aux.setstate
+
+-- this info eventually will go into char-def
+
+local zwnj = 0x200C
+local zwj = 0x200D
+
+local isol = {
+ [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
+ [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
+ [0x06DD] = true, [zwnj] = true,
+}
+
+local isol_fina = {
+ [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
+ [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
+ [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
+ [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true,
+ [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true,
+ [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true,
+ [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true,
+ [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true,
+ [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true,
+ [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true,
+ [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true,
+ [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true,
+ [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
+ [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
+ [0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true,
+ [0x0778] = true, [0x0779] = true,
+}
+
+local isol_fina_medi_init = {
+ [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
+ [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
+ [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
+ [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
+ [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
+ [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
+ [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
+ [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
+ [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
+ [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true,
+ [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true,
+ [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true,
+ [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true,
+ [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true,
+ [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true,
+ [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true,
+ [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true,
+ [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true,
+ [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true,
+ [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true,
+ [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true,
+ [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true,
+ [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true,
+ [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true,
+ [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true,
+ [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true,
+ [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true,
+ [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true,
+ [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true,
+ [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true,
+ [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true,
+ [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
+ [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
+ [0x077E] = true, [0x077F] = true, [zwj] = true,
+}
+
+local arab_warned = { }
+
+-- todo: gref
+
+local function warning(current,what)
+ local char = current.char
+ if not arab_warned[char] then
+ log.report("analyze","arab: character %s (U+%04X) has no %s class", char, char, what)
+ arab_warned[char] = true
+ end
+end
+
+function fonts.analyzers.methods.nocolor(head,font,attr)
+ for n in traverse_node_list(head,glyph) do
+ if not font or n.font == font then
+ fcr(n)
+ end
+ end
+ return head, true
+end
+
+otf.remove_joiners = false -- true -- for idris who want it as option
+
+local function finish(first,last)
+ if last then
+ if first == last then
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ else
+ local lc = last.char
+ if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
+ -- if laststate == 1 or laststate == 2 or laststate == 4 then
+ set_attribute(last,state,3) -- fina
+ if trace_analyzing then fcs(last,"font:fina") end
+ else
+ warning(last,"fina")
+ set_attribute(last,state,0) -- error
+ if trace_analyzing then fcr(last) end
+ end
+ end
+ first, last = nil, nil
+ elseif first then
+ -- first and last are either both set so we never com here
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ first = nil
+ end
+ return first, last
+end
+
+function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
+ local tfmdata = fontdata[font]
+ local marks = tfmdata.marks
+ local first, last, current, done = nil, nil, head, false
+ local joiners, nonjoiners
+ local removejoiners = tfmdata.remove_joiners -- or otf.remove_joiners
+ if removejoiners then
+ joiners, nonjoiners = { }, { }
+ end
+ while current do
+ if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then
+ done = true
+ local char = current.char
+ if removejoiners then
+ if char == zwj then
+ joiners[#joiners+1] = current
+ elseif char == zwnj then
+ nonjoiners[#nonjoiners+1] = current
+ end
+ end
+ if marks[char] then
+ set_attribute(current,state,5) -- mark
+ if trace_analyzing then fcs(current,"font:mark") end
+ elseif isol[char] then -- can be zwj or zwnj too
+ first, last = finish(first,last)
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ elseif not first then
+ if isol_fina_medi_init[char] then
+ set_attribute(current,state,1) -- init
+ if trace_analyzing then fcs(current,"font:init") end
+ first, last = first or current, current
+ elseif isol_fina[char] then
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ else -- no arab
+ first, last = finish(first,last)
+ end
+ elseif isol_fina_medi_init[char] then
+ first, last = first or current, current
+ set_attribute(current,state,2) -- medi
+ if trace_analyzing then fcs(current,"font:medi") end
+ elseif isol_fina[char] then
+ if not has_attribute(last,state,1) then
+ -- tricky, we need to check what last may be !
+ set_attribute(last,state,2) -- medi
+ if trace_analyzing then fcs(last,"font:medi") end
+ end
+ set_attribute(current,state,3) -- fina
+ if trace_analyzing then fcs(current,"font:fina") end
+ first, last = nil, nil
+ elseif char >= 0x0600 and char <= 0x06FF then
+ if trace_analyzing then fcs(current,"font:rest") end
+ first, last = finish(first,last)
+ else --no
+ first, last = finish(first,last)
+ end
+ else
+ first, last = finish(first,last)
+ end
+ current = current.next
+ end
+ first, last = finish(first,last)
+ if removejoiners then
+ for i=1,#joiners do
+ head = delete_node(head,joiners[i])
+ end
+ for i=1,#nonjoiners do
+ head = replace_node(head,nonjoiners[i],nodes.glue(0)) -- or maybe a kern
+ end
+ end
+ return head, done
+end
+
+table.insert(fonts.manipulators,"joiners")
+
+function fonts.initializers.node.otf.joiners(tfmdata,value)
+ if value == "strip" then
+ tfmdata.remove_joiners = true
+ end
+end
diff --git a/tex/context/base/font-otb.lua b/tex/context/base/font-otb.lua
new file mode 100644
index 000000000..2a14085d6
--- /dev/null
+++ b/tex/context/base/font-otb.lua
@@ -0,0 +1,364 @@
+if not modules then modules = { } end modules ['font-otb'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local pcache, fcache = { }, { } -- could be weak
+
+local function gref(descriptions,n)
+ if type(n) == "number" then
+ local name = descriptions[n].name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X")
+ end
+ elseif n then
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[i] = format("U+%04X",ni)
+ nam[i] = descriptions[ni].name or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ else
+ return "?"
+ end
+end
+
+local function cref(kind,lookupname)
+ if lookupname then
+ return format("feature %s, lookup %s",kind,lookupname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function resolve_ligatures(tfmdata,ligatures,kind)
+ kind = kind or "unknown"
+ local unicodes = tfmdata.unicodes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ local done = { }
+ while true do
+ local ok = false
+ for k,v in next, ligatures do
+ local lig = v[1]
+ if not done[lig] then
+ local ligs = split_at_space:match(lig)
+ if #ligs == 2 then
+ local uc = v[2]
+ local c, f, s = characters[uc], ligs[1], ligs[2]
+ local uft, ust = unicodes[f] or 0, unicodes[s] or 0
+ if not uft or not ust then
+ logs.report("define otf","%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust))
+ -- some kind of error
+ else
+ if type(uft) == "number" then uft = { uft } end
+ if type(ust) == "number" then ust = { ust } end
+ for ufi=1,#uft do
+ local uf = uft[ufi]
+ for usi=1,#ust do
+ local us = ust[usi]
+ if changed[uf] or changed[us] then
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us))
+ end
+ else
+ local first, second = characters[uf], us
+ if first and second then
+ local t = first.ligatures
+ if not t then
+ t = { }
+ first.ligatures = t
+ end
+ if type(uc) == "number" then
+ t[second] = { type = 0, char = uc }
+ else
+ t[second] = { type = 0, char = uc[1] } -- can this still happen?
+ end
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc))
+ end
+ end
+ end
+ end
+ end
+ end
+ ok, done[lig] = true, descriptions[uc].name
+ end
+ end
+ end
+ if ok then
+ -- done has "a b c" = "a_b_c" and ligatures the already set ligatures: "a b" = 123
+ -- and here we add extras (f i i = fi + i and alike)
+ --
+ -- we could use a hash for fnc and pattern
+ --
+ -- this might be interfering !
+ for d,n in next, done do
+ local pattern = pcache[d] if not pattern then pattern = "^(" .. d .. ") " pcache[d] = pattern end
+ local fnc = fcache[n] if not fnc then fnc = function() return n .. " " end fcache[n] = fnc end
+ for k,v in next, ligatures do
+ v[1] = gsub(v[1],pattern,fnc)
+ end
+ end
+ else
+ break
+ end
+ end
+end
+
+local function collect_lookups(otfdata,kind,script,language)
+ -- maybe store this in the font
+ local sequences = otfdata.luatex.sequences
+ if sequences then
+ local featuremap, featurelist = { }, { }
+ for s=1,#sequences do
+ local sequence = sequences[s]
+ local features = sequence.features
+ features = features and features[kind]
+ features = features and (features[script] or features[default] or features[wildcard])
+ features = features and (features[language] or features[default] or features[wildcard])
+ if features then
+ local subtables = sequence.subtables
+ if subtables then
+ for s=1,#subtables do
+ local ss = subtables[s]
+ if not featuremap[s] then
+ featuremap[ss] = true
+ featurelist[#featurelist+1] = ss
+ end
+ end
+ end
+ end
+ end
+ if #featurelist > 0 then
+ return featuremap, featurelist
+ end
+ end
+ return nil, nil
+end
+
+local splitter = lpeg.splitat(" ")
+
+function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local ligatures = { }
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ for k,c in next, characters do
+ local glyph = descriptions[k]
+ local lookups = glyph.lookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local ps = lookups[lookup]
+ if ps then
+ for i=1,#ps do
+ local p = ps[i]
+ local t = p[1]
+ if t == 'substitution' then
+ local pv = p[2] -- p.variant
+ if pv then
+ local upv = unicodes[pv]
+ if upv then
+ if type(upv) == "table" then
+ upv = upv[1]
+ end
+ if characters[upv] then
+ if trace_baseinit and trace_singles then
+ logs.report("define otf","%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv))
+ end
+ changed[k] = upv
+ end
+ end
+ end
+ elseif t == 'alternate' then
+ local pc = p[2] -- p.components
+ if pc then
+ -- a bit optimized ugliness
+ if value == 1 then
+ pc = splitter:match(pc)
+ elseif value == 2 then
+ local a, b = splitter:match(pc)
+ pc = b or a
+ else
+ pc = { splitter:match(pc) }
+ pc = pc[value] or pc[#pc]
+ end
+ if pc then
+ local upc = unicodes[pc]
+ if upc then
+ if type(upc) == "table" then
+ upc = upc[1]
+ end
+ if characters[upc] then
+ if trace_baseinit and trace_alternatives then
+ logs.report("define otf","%s: base alternate %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upc))
+ end
+ changed[k] = upc
+ end
+ end
+ end
+ end
+ elseif t == 'ligature' and not changed[k] then
+ local pc = p[2]
+ if pc then
+ if trace_baseinit and trace_ligatures then
+ local upc = { splitter:match(pc) }
+ for i=1,#upc do upc[i] = unicodes[upc[i]] end
+ -- we assume that it's no table
+ logs.report("define otf","%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k))
+ end
+ ligatures[#ligatures+1] = { pc, k }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ resolve_ligatures(tfmdata,ligatures,kind)
+ end
+ else
+ tfmdata.ligatures = tfmdata.ligatures or { } -- left over from what ?
+ end
+end
+
+local function prepare_base_kerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ for u, chr in next, characters do
+ local d = descriptions[u]
+ if d then
+ local dk = d.mykerns
+ if dk then
+ local t, done = chr.kerns or { }, false
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local kerns = dk[lookup]
+ if kerns then
+ for k, v in next, kerns do
+ if v ~= 0 and not t[k] then -- maybe no 0 test here
+ t[k], done = v, true
+ if trace_baseinit and trace_kerns then
+ logs.report("define otf","%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v)
+ end
+ end
+ end
+ end
+ end
+ if done then
+ chr.kerns = t -- no empty assignments
+ end
+ -- elseif d.kerns then
+ -- logs.report("define otf","%s: invalid mykerns for %s",cref(kind),gref(descriptions,u))
+ end
+ end
+ end
+ end
+ end
+end
+
+-- In principle we could register each feature individually which was
+-- what we did in earlier versions. However, after the rewrite it
+-- made more sense to collect them in an overall features initializer
+-- just as with the node variant. There it was needed because we need
+-- to do complete mixed runs and not run featurewise (as we did before).
+
+local supported_gsub = {
+ 'liga','dlig','rlig','hlig',
+ 'pnum','onum','tnum','lnum',
+ 'zero',
+ 'smcp','cpsp','c2sc','ornm','aalt',
+ 'hwid','fwid',
+ 'ssty', -- math
+}
+
+local supported_gpos = {
+ 'kern'
+}
+
+function otf.features.register_base_substitution(tag)
+ supported_gsub[#supported_gsub+1] = tag
+end
+function otf.features.register_base_kern(tag)
+ supported_gsub[#supported_gpos+1] = tag
+end
+
+local basehash, basehashes = { }, 1
+
+function fonts.initializers.base.otf.features(tfmdata,value)
+ if true then -- value then
+ -- not shared
+ local t = trace_preparing and os.clock()
+ local features = tfmdata.shared.features
+ if features then
+ local h = { }
+ for f=1,#supported_gsub do
+ local feature = supported_gsub[f]
+ prepare_base_substitutions(tfmdata,feature,features[feature])
+ h[#h+1] = feature
+ end
+ for f=1,#supported_gpos do
+ local feature = supported_gpos[f]
+ prepare_base_kerns(tfmdata,feature,features[feature])
+ h[#h+1] = feature
+ end
+ local hash = concat(h," ")
+ local base = basehash[hash]
+ if not base then
+ basehashes = basehashes + 1
+ base = basehashes
+ basehash[hash] = base
+ end
+ -- We need to make sure that luatex sees the difference between
+ -- base fonts that have different glyphs in the same slots in fonts
+ -- that have the same fullname (or filename). LuaTeX will merge fonts
+ -- eventually (and subset later on). If needed we can use a more
+ -- verbose name as long as we don't use <()<>[]{}/%> and the length
+ -- is < 128.
+ tfmdata.fullname = tfmdata.fullname .. base
+ end
+ if trace_preparing then
+ logs.report("otf define","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+end
diff --git a/tex/context/base/font-otc.lua b/tex/context/base/font-otc.lua
new file mode 100644
index 000000000..f75da39cd
--- /dev/null
+++ b/tex/context/base/font-otc.lua
@@ -0,0 +1,238 @@
+if not modules then modules = { } end modules ['font-otc'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (context)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, insert = string.format, table.insert
+local type, next = type, next
+
+local ctxcatcodes = tex.ctxcatcodes
+
+-- we assume that the other otf stuff is loaded already
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+-- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
+-- have always); some day we can write a "force always when true" trick for other
+-- features as well
+
+local extra_lists = {
+ tlig = {
+ {
+ endash = "hyphen hyphen",
+ emdash = "hyphen hyphen hyphen",
+ -- quotedblleft = "quoteleft quoteleft",
+ -- quotedblright = "quoteright quoteright",
+ -- quotedblleft = "grave grave",
+ -- quotedblright = "quotesingle quotesingle",
+ -- quotedblbase = "comma comma",
+ },
+ },
+ trep = {
+ {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+ },
+ },
+ anum = {
+ { -- arabic
+ [0x0030] = 0x0660,
+ [0x0031] = 0x0661,
+ [0x0032] = 0x0662,
+ [0x0033] = 0x0663,
+ [0x0034] = 0x0664,
+ [0x0035] = 0x0665,
+ [0x0036] = 0x0666,
+ [0x0037] = 0x0667,
+ [0x0038] = 0x0668,
+ [0x0039] = 0x0669,
+ },
+ { -- persian
+ [0x0030] = 0x06F0,
+ [0x0031] = 0x06F1,
+ [0x0032] = 0x06F2,
+ [0x0033] = 0x06F3,
+ [0x0034] = 0x06F4,
+ [0x0035] = 0x06F5,
+ [0x0036] = 0x06F6,
+ [0x0037] = 0x06F7,
+ [0x0038] = 0x06F8,
+ [0x0039] = 0x06F9,
+ },
+ },
+}
+
+local extra_features = { -- maybe just 1..n so that we prescribe order
+ tlig = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, },
+ name = "ctx_tlig_1",
+ subtables = { { name = "ctx_tlig_1_s" } },
+ type = "gsub_ligature",
+ flags = { },
+ },
+ },
+ trep = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, },
+ name = "ctx_trep_1",
+ subtables = { { name = "ctx_trep_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+ anum = {
+ {
+ features = { { scripts = { { script = "arab", langs = { "dflt", "FAR" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_1",
+ subtables = { { name = "ctx_anum_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ {
+ features = { { scripts = { { script = "arab", langs = { "URD" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_2",
+ subtables = { { name = "ctx_anum_2_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+}
+
+fonts.otf.enhancers["add some missing characters"] = function(data,filename)
+ -- todo
+end
+
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- could be done elsewhere (true can be #)
+ local used = { }
+ for i=1,#otf.glists do
+ local g = data[otf.glists[i]]
+ if g then
+ for i=1,#g do
+ local f = g[i].features
+ if f then
+ for i=1,#f do
+ local t = f[i].tag
+ if t then used[t] = true end
+ end
+ end
+ end
+ end
+ end
+ --
+ local glyphs = data.glyphs
+ local indices = data.map.map
+ data.gsub = data.gsub or { }
+ for kind, specifications in next, extra_features do
+ if not used[kind] then
+ local done = 0
+ for s=1,#specifications do
+ local added = false
+ local specification = specifications[s]
+ local list = extra_lists[kind][s]
+ local name = specification.name .. "_s"
+ if specification.type == "gsub_ligature" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local ligature = list[glyph.name]
+ if ligature then
+ local o = glyph.lookups or { }
+ -- o[name] = { "ligature", ligature, glyph.name }
+ o[name] = {
+ {
+ ["type"] = "ligature",
+ ["specification"] = {
+ char = glyph.name,
+ components = ligature,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ elseif specification.type == "gsub_single" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local r = list[unicode]
+ if r then
+ local replacement = indices[r]
+ if replacement and glyphs[replacement] then
+ local o = glyph.lookups or { }
+ -- o[name] = { { "substitution", glyphs[replacement].name } }
+ o[name] = {
+ {
+ ["type"] = "substitution",
+ ["specification"] = {
+ variant = glyphs[replacement].name,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ end
+ end
+ if added then
+ insert(data.gsub,s,table.fastcopy(specification)) -- right order
+ end
+ end
+ if done > 0 then
+ if trace_loading then
+ logs.report("load otf","enhance: registering %s feature (%s glyphs affected)",kind,done)
+ end
+ end
+ end
+ end
+end
+
+otf.tables.features['tlig'] = 'TeX Ligatures'
+otf.tables.features['trep'] = 'TeX Replacements'
+otf.tables.features['anum'] = 'Arabic Digits'
+
+otf.features.register_base_substitution('tlig')
+otf.features.register_base_substitution('trep')
+otf.features.register_base_substitution('anum')
+
+-- the functionality is defined elsewhere
+
+fonts.initializers.base.otf.equaldigits = fonts.initializers.common.equaldigits
+fonts.initializers.node.otf.equaldigits = fonts.initializers.common.equaldigits
+
+fonts.initializers.base.otf.lineheight = fonts.initializers.common.lineheight
+fonts.initializers.node.otf.lineheight = fonts.initializers.common.lineheight
+
+fonts.initializers.base.otf.compose = fonts.initializers.common.compose
+fonts.initializers.node.otf.compose = fonts.initializers.common.compose
+
+-- bonus function
+
+function otf.name_to_slot(name) -- todo: afm en tfm
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata and tfmdata.shared then
+ local otfdata = tfmdata.shared.otfdata
+ local unicode = otfdata.luatex.unicodes[name]
+ if type(unicode) == "number" then
+ return unicode
+ else
+ return unicode[1]
+ end
+ end
+ return nil
+end
+
+function otf.char(n) -- todo: afm en tfm
+ if type(n) == "string" then
+ n = otf.name_to_slot(n)
+ end
+ if n then
+ tex.sprint(ctxcatcodes,format("\\char%s ",n))
+ end
+end
diff --git a/tex/context/base/font-otd.lua b/tex/context/base/font-otd.lua
new file mode 100644
index 000000000..78a828146
--- /dev/null
+++ b/tex/context/base/font-otd.lua
@@ -0,0 +1,78 @@
+if not modules then modules = { } end modules ['font-otd'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+local fontdata = fonts.ids
+
+otf.features = otf.features or { }
+otf.features.default = otf.features.default or { }
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+
+local a_to_script = { } otf.a_to_script = a_to_script
+local a_to_language = { } otf.a_to_language = a_to_language
+
+function otf.set_dynamics(font,dynamics,attribute)
+ features = context_setups[context_numbers[attribute]] -- can be moved to caller
+ if features then
+ local script = features.script or 'dflt'
+ local language = features.language or 'dflt'
+ local ds = dynamics[script]
+ if not ds then
+ ds = { }
+ dynamics[script] = ds
+ end
+ local dsl = ds[language]
+ if not dsl then
+ dsl = { }
+ ds[language] = dsl
+ end
+ local dsla = dsl[attribute]
+ if dsla then
+ -- if trace_dynamics then
+ -- logs.report("otf define","using dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ -- end
+ return dsla
+ else
+ local tfmdata = fontdata[font]
+ a_to_script [attribute] = script
+ a_to_language[attribute] = language
+ -- we need to save some values
+ local saved = {
+ script = tfmdata.script,
+ language = tfmdata.language,
+ mode = tfmdata.mode,
+ features = tfmdata.shared.features
+ }
+ tfmdata.mode = "node"
+ tfmdata.language = language
+ tfmdata.script = script
+ tfmdata.shared.features = { }
+ -- end of save
+ dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+ if trace_dynamics then
+ logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ end
+ -- we need to restore some values
+ tfmdata.script = saved.script
+ tfmdata.language = saved.language
+ tfmdata.mode = saved.mode
+ tfmdata.shared.features = saved.features
+ -- end of restore
+ dynamics[script][language][attribute] = dsla -- cache
+ return dsla
+ end
+ end
+ return nil -- { }
+end
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
index fffd4eeda..20273f8f5 100644
--- a/tex/context/base/font-otf.lua
+++ b/tex/context/base/font-otf.lua
@@ -6,829 +6,210 @@ if not modules then modules = { } end modules ['font-otf'] = {
license = "see context related readme files"
}
-local format, concat, getn = string.format, table.concat, table.getn
-local type, pairs, ipairs, next, tonumber, tostring = type, pairs, ipairs, next, tonumber, tostring
+local utf = unicode.utf8
-local space = lpeg.P(" ")
-local nospaces = (1-space)^1
-local optionalspace = space^0
+local concat, getn, utfbyte = table.concat, table.getn, utf.byte
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
-local split_at_space = lpeg.Ct((lpeg.C(nospaces) * optionalspace)^0) -- table !
+local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
+local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
--- we can use more lpegs when lpeg is extended with function args and so
+--~ trackers.enable("otf.loading")
--- the flattening code is a prelude to a more compact table format (so, we're now
--- at the fourth version); maybe we will go unicode, although that will mean that we
--- miss some glyphs (unicode -1)
-
--- todo: featuredata is now indexed by kind,lookup but probably lookup is okay too
-
--- todo: now that we pack ... resolve strings to unicode points
--- todo: unpack already in tmc file, i.e. save tables and return ref''d version
--- todo: dependents etc resolve too, maybe even reorder glyphs to unicode
--- todo: pack ignoreflags
-
--- abvf abvs blwf blws dist falt half halt jalt lfbd ljmo
--- mset opbd palt pwid qwid rand rtbd ruby size tjmo twid valt vatu vert
--- vhal vjmo vkna vkrn vpal vrt2
-
--- The specification of OpenType is vague, very vague. Apart from a lack of proper
--- specifications (a free one) there's also the problem that Microsoft and Adobe
--- may have their own rules. Anyhow, the following is from Adobe's feature file
--- specification:
---
--- http://www.adobe.com/devnet/opentype/afdko/topic_feature_file_syntax.html#6.h
---
--- The following is a reference summary of the algorithm used by an OpenType layout
--- (OTL) engine to perform substitutions and positionings. The important aspect of
--- this for a feature file editor is that each lookup corresponds to one "pass" over
--- the glyph run (see step 4 below). Thus, each lookup has as input the accumulated
--- result of all previous lookups in the LookupList (whether in the same feature or
--- in other features).
--- 1. All glyphs in the client's glyph run must belong to the same language
--- system. Glyph sequence matching may not occur across language
--- systems. Do the following first for the GSUB and then for the GPOS:
--- 2. Assemble all features (including any required feature) for the glyph
--- run's language system.
--- 3. Assemble all lookups in these features, in LookupList order, removing
--- any duplicates. All features and thus all lookups needn't be applied to
--- every glyph in the run.
--- 4. For each lookup:
--- 5. For each glyph in the glyph run:
--- 6. If the lookup is applied to that glyph and the lookupflag doesn't
--- indicate that that glyph is to be ignored:
--- 7. For each subtable in the lookup:
--- 8. If the subtable's target context is matched:
--- 9. Do the glyph substitution or positioning,
--- --- OR: ---
--- If this is a (chain) contextual lookup do the following
--- [(10)-(11)] in the subtable's Subst/PosLookupRecord order:
--- 10. For each (sequenceIndex, lookupListIndex) pair:
--- 11. Apply lookup[lookupListIndex] at input sequence[sequenceIndex]
--- [steps (7)-(11)]
--- 12. Goto the glyph after the input sequence matched in (8)
--- (i.e. skip any remaining subtables in the lookup).
--- The "target context" in step 8 above comprises the input sequence and any
--- backtrack and lookahead sequences.
--- The input sequence must be matched entirely within the lookup's "application
--- range" at that glyph (that contiguous subrun of glyphs including and around
--- the current glyph on which the lookup is applied). There is no such restriction
--- on the backtrack and lookahead sequences.
--- "Matching" includes matching any glyphs designated to be skipped in the
--- lookup's LookupFlag.
+local zwnj = 0x200C
+local zwj = 0x200D
--[[ldx--
-<p>This module is sparsely documented because it is a moving target.
-The table format of the reader changes and we experiment a lot with
-different methods for supporting features.</p>
+<p>The fontforge table has organized lookups in a certain way. A first implementation
+of this code was organized featurewise: information related to features was
+collected and processing boiled down to a run over the features. The current
+implementation honors the order in the main feature table. Since we can reorder this
+table as we want, we can eventually support several models of processing. We kept
+the static as well as dynamic feature processing, because it had proved to be
+rather useful. The formerly three loop variants have beem discarded but will
+reapear at some time.</p>
+
+<itemize>
+<item>we loop over all lookups</item>
+<item>for each lookup we do a run over the list of glyphs</item>
+<item>but we only process them for features that are enabled</item>
+<item>if we're dealing with a contextual lookup, we loop over all contexts</item>
+<item>in that loop we quit at a match and then process the list of sublookups</item>
+<item>we always continue after the match</item>
+</itemize>
+
+<p>In <l n='context'/> we do this for each font that is used in a list, so in
+practice we have quite some nested loops.</p>
+
+<p>We process the whole list and then consult the glyph nodes. An alternative approach
+is to collect strings of characters using the same font including spaces (because some
+lookups involve spaces). However, we then need to reconstruct the list which is no fun.
+Also, we need to carry quite some information, like attributes, so eventually we don't
+gain much (if we gain something at all).</p>
+
+<p>Another consideration has been to operate on sublists (subhead, subtail) but again
+this would complicate matters as we then neext to keep track of a changing subhead
+and subtail. On the other hand, this might save some runtime. The number of changes
+involved is not that large. This only makes sense when we have many fonts in a list
+and don't change to frequently.</p>
+--ldx]]--
-<p>As with the <l n='afm'/> code, we may decide to store more information
-in the <l n='otf'/> table.</p>
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+fonts.tfm = fonts.tfm or { }
-<p>Incrementing the version number will force a re-cache. We jump the
-number by one when there's a fix in the <l n='fontforge'/> library or
-<l n='lua'/> code that results in different tables.</p>
---ldx]]--
+local otf = fonts.otf
+local tfm = fonts.tfm
---~ The node based processing functions look quite complex which is mainly due to
---~ the fact that we need to share data and cache resolved issues (saves much memory and
---~ is also faster). A further complication is that we support static as well as dynamic
---~ features.
+local fontdata = fonts.ids
-fonts = fonts or { }
-fonts.otf = fonts.otf or { }
+otf.tables = otf.tables or { } -- defined in font-ott.lua
+otf.meanings = otf.meanings or { } -- defined in font-ott.lua
+otf.tables.features = otf.tables.features or { } -- defined in font-ott.lua
+otf.tables.languages = otf.tables.languages or { } -- defined in font-ott.lua
+otf.tables.scripts = otf.tables.scripts or { } -- defined in font-ott.lua
-local otf = fonts.otf
-local tfm = fonts.tfm
+otf.features = otf.features or { }
+otf.features.list = otf.features.list or { }
+otf.features.default = otf.features.default or { }
-otf.version = 2.24
-otf.pack = true
-otf.tables = otf.tables or { }
-otf.meanings = otf.meanings or { }
-otf.enhance_data = false
-otf.syncspace = true
-otf.features = { }
-otf.features.aux = { }
-otf.features.data = { }
-otf.features.list = { } -- not (yet) used, oft fonts have gpos/gsub lists
-otf.features.default = { }
-otf.trace_features = false
-otf.trace_set_features = false
-otf.trace_replacements = false
-otf.trace_contexts = false
-otf.trace_anchors = false
-otf.trace_ligatures = false
-otf.trace_kerns = false
-otf.trace_cursive = false
-otf.notdef = false
-otf.cache = containers.define("fonts", "otf", otf.version, true)
+otf.enhancers = otf.enhancers or { }
+otf.glists = { "gsub", "gpos" }
-function otf.trace_process()
- otf.trace_replacements = true
- otf.trace_contexts = true
- otf.trace_anchors = true
- otf.trace_ligatures = true
- otf.trace_kerns = true
- otf.trace_cursive = true
-end
+otf.version = 2.626 -- beware: also sync font-mis.lua
+otf.pack = true -- beware: also sync font-mis.lua
+otf.syncspace = true
+otf.notdef = false
+otf.cache = containers.define("fonts", "otf", otf.version, true)
+otf.cleanup_aat = false -- only context
--[[ldx--
<p>We start with a lot of tables and related functions.</p>
--ldx]]--
-otf.tables.scripts = {
- ['dflt'] = 'Default',
-
- ['arab'] = 'Arabic',
- ['armn'] = 'Armenian',
- ['bali'] = 'Balinese',
- ['beng'] = 'Bengali',
- ['bopo'] = 'Bopomofo',
- ['brai'] = 'Braille',
- ['bugi'] = 'Buginese',
- ['buhd'] = 'Buhid',
- ['byzm'] = 'Byzantine Music',
- ['cans'] = 'Canadian Syllabics',
- ['cher'] = 'Cherokee',
- ['copt'] = 'Coptic',
- ['cprt'] = 'Cypriot Syllabary',
- ['cyrl'] = 'Cyrillic',
- ['deva'] = 'Devanagari',
- ['dsrt'] = 'Deseret',
- ['ethi'] = 'Ethiopic',
- ['geor'] = 'Georgian',
- ['glag'] = 'Glagolitic',
- ['goth'] = 'Gothic',
- ['grek'] = 'Greek',
- ['gujr'] = 'Gujarati',
- ['guru'] = 'Gurmukhi',
- ['hang'] = 'Hangul',
- ['hani'] = 'CJK Ideographic',
- ['hano'] = 'Hanunoo',
- ['hebr'] = 'Hebrew',
- ['ital'] = 'Old Italic',
- ['jamo'] = 'Hangul Jamo',
- ['java'] = 'Javanese',
- ['kana'] = 'Hiragana and Katakana',
- ['khar'] = 'Kharosthi',
- ['khmr'] = 'Khmer',
- ['knda'] = 'Kannada',
- ['lao' ] = 'Lao',
- ['latn'] = 'Latin',
- ['limb'] = 'Limbu',
- ['linb'] = 'Linear B',
- ['math'] = 'Mathematical Alphanumeric Symbols',
- ['mlym'] = 'Malayalam',
- ['mong'] = 'Mongolian',
- ['musc'] = 'Musical Symbols',
- ['mymr'] = 'Myanmar',
- ['nko' ] = "N'ko",
- ['ogam'] = 'Ogham',
- ['orya'] = 'Oriya',
- ['osma'] = 'Osmanya',
- ['phag'] = 'Phags-pa',
- ['phnx'] = 'Phoenician',
- ['runr'] = 'Runic',
- ['shaw'] = 'Shavian',
- ['sinh'] = 'Sinhala',
- ['sylo'] = 'Syloti Nagri',
- ['syrc'] = 'Syriac',
- ['tagb'] = 'Tagbanwa',
- ['tale'] = 'Tai Le',
- ['talu'] = 'Tai Lu',
- ['taml'] = 'Tamil',
- ['telu'] = 'Telugu',
- ['tfng'] = 'Tifinagh',
- ['tglg'] = 'Tagalog',
- ['thaa'] = 'Thaana',
- ['thai'] = 'Thai',
- ['tibt'] = 'Tibetan',
- ['ugar'] = 'Ugaritic Cuneiform',
- ['xpeo'] = 'Old Persian Cuneiform',
- ['xsux'] = 'Sumero-Akkadian Cuneiform',
- ['yi' ] = 'Yi'
-}
-
-otf.tables.languages = {
- ['dflt'] = 'Default',
-
- ['aba'] = 'Abaza',
- ['abk'] = 'Abkhazian',
- ['ady'] = 'Adyghe',
- ['afk'] = 'Afrikaans',
- ['afr'] = 'Afar',
- ['agw'] = 'Agaw',
- ['als'] = 'Alsatian',
- ['alt'] = 'Altai',
- ['amh'] = 'Amharic',
- ['ara'] = 'Arabic',
- ['ari'] = 'Aari',
- ['ark'] = 'Arakanese',
- ['asm'] = 'Assamese',
- ['ath'] = 'Athapaskan',
- ['avr'] = 'Avar',
- ['awa'] = 'Awadhi',
- ['aym'] = 'Aymara',
- ['aze'] = 'Azeri',
- ['bad'] = 'Badaga',
- ['bag'] = 'Baghelkhandi',
- ['bal'] = 'Balkar',
- ['bau'] = 'Baule',
- ['bbr'] = 'Berber',
- ['bch'] = 'Bench',
- ['bcr'] = 'Bible Cree',
- ['bel'] = 'Belarussian',
- ['bem'] = 'Bemba',
- ['ben'] = 'Bengali',
- ['bgr'] = 'Bulgarian',
- ['bhi'] = 'Bhili',
- ['bho'] = 'Bhojpuri',
- ['bik'] = 'Bikol',
- ['bil'] = 'Bilen',
- ['bkf'] = 'Blackfoot',
- ['bli'] = 'Balochi',
- ['bln'] = 'Balante',
- ['blt'] = 'Balti',
- ['bmb'] = 'Bambara',
- ['bml'] = 'Bamileke',
- ['bos'] = 'Bosnian',
- ['bre'] = 'Breton',
- ['brh'] = 'Brahui',
- ['bri'] = 'Braj Bhasha',
- ['brm'] = 'Burmese',
- ['bsh'] = 'Bashkir',
- ['bti'] = 'Beti',
- ['cat'] = 'Catalan',
- ['ceb'] = 'Cebuano',
- ['che'] = 'Chechen',
- ['chg'] = 'Chaha Gurage',
- ['chh'] = 'Chattisgarhi',
- ['chi'] = 'Chichewa',
- ['chk'] = 'Chukchi',
- ['chp'] = 'Chipewyan',
- ['chr'] = 'Cherokee',
- ['chu'] = 'Chuvash',
- ['cmr'] = 'Comorian',
- ['cop'] = 'Coptic',
- ['cos'] = 'Corsican',
- ['cre'] = 'Cree',
- ['crr'] = 'Carrier',
- ['crt'] = 'Crimean Tatar',
- ['csl'] = 'Church Slavonic',
- ['csy'] = 'Czech',
- ['dan'] = 'Danish',
- ['dar'] = 'Dargwa',
- ['dcr'] = 'Woods Cree',
- ['deu'] = 'German',
- ['dgr'] = 'Dogri',
- ['div'] = 'Divehi',
- ['djr'] = 'Djerma',
- ['dng'] = 'Dangme',
- ['dnk'] = 'Dinka',
- ['dri'] = 'Dari',
- ['dun'] = 'Dungan',
- ['dzn'] = 'Dzongkha',
- ['ebi'] = 'Ebira',
- ['ecr'] = 'Eastern Cree',
- ['edo'] = 'Edo',
- ['efi'] = 'Efik',
- ['ell'] = 'Greek',
- ['eng'] = 'English',
- ['erz'] = 'Erzya',
- ['esp'] = 'Spanish',
- ['eti'] = 'Estonian',
- ['euq'] = 'Basque',
- ['evk'] = 'Evenki',
- ['evn'] = 'Even',
- ['ewe'] = 'Ewe',
- ['fan'] = 'French Antillean',
- ['far'] = 'Farsi',
- ['fin'] = 'Finnish',
- ['fji'] = 'Fijian',
- ['fle'] = 'Flemish',
- ['fne'] = 'Forest Nenets',
- ['fon'] = 'Fon',
- ['fos'] = 'Faroese',
- ['fra'] = 'French',
- ['fri'] = 'Frisian',
- ['frl'] = 'Friulian',
- ['fta'] = 'Futa',
- ['ful'] = 'Fulani',
- ['gad'] = 'Ga',
- ['gae'] = 'Gaelic',
- ['gag'] = 'Gagauz',
- ['gal'] = 'Galician',
- ['gar'] = 'Garshuni',
- ['gaw'] = 'Garhwali',
- ['gez'] = "Ge'ez",
- ['gil'] = 'Gilyak',
- ['gmz'] = 'Gumuz',
- ['gon'] = 'Gondi',
- ['grn'] = 'Greenlandic',
- ['gro'] = 'Garo',
- ['gua'] = 'Guarani',
- ['guj'] = 'Gujarati',
- ['hai'] = 'Haitian',
- ['hal'] = 'Halam',
- ['har'] = 'Harauti',
- ['hau'] = 'Hausa',
- ['haw'] = 'Hawaiin',
- ['hbn'] = 'Hammer-Banna',
- ['hil'] = 'Hiligaynon',
- ['hin'] = 'Hindi',
- ['hma'] = 'High Mari',
- ['hnd'] = 'Hindko',
- ['ho'] = 'Ho',
- ['hri'] = 'Harari',
- ['hrv'] = 'Croatian',
- ['hun'] = 'Hungarian',
- ['hye'] = 'Armenian',
- ['ibo'] = 'Igbo',
- ['ijo'] = 'Ijo',
- ['ilo'] = 'Ilokano',
- ['ind'] = 'Indonesian',
- ['ing'] = 'Ingush',
- ['inu'] = 'Inuktitut',
- ['iri'] = 'Irish',
- ['irt'] = 'Irish Traditional',
- ['isl'] = 'Icelandic',
- ['ism'] = 'Inari Sami',
- ['ita'] = 'Italian',
- ['iwr'] = 'Hebrew',
- ['jan'] = 'Japanese',
- ['jav'] = 'Javanese',
- ['jii'] = 'Yiddish',
- ['jud'] = 'Judezmo',
- ['jul'] = 'Jula',
- ['kab'] = 'Kabardian',
- ['kac'] = 'Kachchi',
- ['kal'] = 'Kalenjin',
- ['kan'] = 'Kannada',
- ['kar'] = 'Karachay',
- ['kat'] = 'Georgian',
- ['kaz'] = 'Kazakh',
- ['keb'] = 'Kebena',
- ['kge'] = 'Khutsuri Georgian',
- ['kha'] = 'Khakass',
- ['khk'] = 'Khanty-Kazim',
- ['khm'] = 'Khmer',
- ['khs'] = 'Khanty-Shurishkar',
- ['khv'] = 'Khanty-Vakhi',
- ['khw'] = 'Khowar',
- ['kik'] = 'Kikuyu',
- ['kir'] = 'Kirghiz',
- ['kis'] = 'Kisii',
- ['kkn'] = 'Kokni',
- ['klm'] = 'Kalmyk',
- ['kmb'] = 'Kamba',
- ['kmn'] = 'Kumaoni',
- ['kmo'] = 'Komo',
- ['kms'] = 'Komso',
- ['knr'] = 'Kanuri',
- ['kod'] = 'Kodagu',
- ['koh'] = 'Korean Old Hangul',
- ['kok'] = 'Konkani',
- ['kon'] = 'Kikongo',
- ['kop'] = 'Komi-Permyak',
- ['kor'] = 'Korean',
- ['koz'] = 'Komi-Zyrian',
- ['kpl'] = 'Kpelle',
- ['kri'] = 'Krio',
- ['krk'] = 'Karakalpak',
- ['krl'] = 'Karelian',
- ['krm'] = 'Karaim',
- ['krn'] = 'Karen',
- ['krt'] = 'Koorete',
- ['ksh'] = 'Kashmiri',
- ['ksi'] = 'Khasi',
- ['ksm'] = 'Kildin Sami',
- ['kui'] = 'Kui',
- ['kul'] = 'Kulvi',
- ['kum'] = 'Kumyk',
- ['kur'] = 'Kurdish',
- ['kuu'] = 'Kurukh',
- ['kuy'] = 'Kuy',
- ['kyk'] = 'Koryak',
- ['lad'] = 'Ladin',
- ['lah'] = 'Lahuli',
- ['lak'] = 'Lak',
- ['lam'] = 'Lambani',
- ['lao'] = 'Lao',
- ['lat'] = 'Latin',
- ['laz'] = 'Laz',
- ['lcr'] = 'L-Cree',
- ['ldk'] = 'Ladakhi',
- ['lez'] = 'Lezgi',
- ['lin'] = 'Lingala',
- ['lma'] = 'Low Mari',
- ['lmb'] = 'Limbu',
- ['lmw'] = 'Lomwe',
- ['lsb'] = 'Lower Sorbian',
- ['lsm'] = 'Lule Sami',
- ['lth'] = 'Lithuanian',
- ['ltz'] = 'Luxembourgish',
- ['lub'] = 'Luba',
- ['lug'] = 'Luganda',
- ['luh'] = 'Luhya',
- ['luo'] = 'Luo',
- ['lvi'] = 'Latvian',
- ['maj'] = 'Majang',
- ['mak'] = 'Makua',
- ['mal'] = 'Malayalam Traditional',
- ['man'] = 'Mansi',
- ['map'] = 'Mapudungun',
- ['mar'] = 'Marathi',
- ['maw'] = 'Marwari',
- ['mbn'] = 'Mbundu',
- ['mch'] = 'Manchu',
- ['mcr'] = 'Moose Cree',
- ['mde'] = 'Mende',
- ['men'] = "Me'en",
- ['miz'] = 'Mizo',
- ['mkd'] = 'Macedonian',
- ['mle'] = 'Male',
- ['mlg'] = 'Malagasy',
- ['mln'] = 'Malinke',
- ['mlr'] = 'Malayalam Reformed',
- ['mly'] = 'Malay',
- ['mnd'] = 'Mandinka',
- ['mng'] = 'Mongolian',
- ['mni'] = 'Manipuri',
- ['mnk'] = 'Maninka',
- ['mnx'] = 'Manx Gaelic',
- ['moh'] = 'Mohawk',
- ['mok'] = 'Moksha',
- ['mol'] = 'Moldavian',
- ['mon'] = 'Mon',
- ['mor'] = 'Moroccan',
- ['mri'] = 'Maori',
- ['mth'] = 'Maithili',
- ['mts'] = 'Maltese',
- ['mun'] = 'Mundari',
- ['nag'] = 'Naga-Assamese',
- ['nan'] = 'Nanai',
- ['nas'] = 'Naskapi',
- ['ncr'] = 'N-Cree',
- ['ndb'] = 'Ndebele',
- ['ndg'] = 'Ndonga',
- ['nep'] = 'Nepali',
- ['new'] = 'Newari',
- ['ngr'] = 'Nagari',
- ['nhc'] = 'Norway House Cree',
- ['nis'] = 'Nisi',
- ['niu'] = 'Niuean',
- ['nkl'] = 'Nkole',
- ['nko'] = "N'ko",
- ['nld'] = 'Dutch',
- ['nog'] = 'Nogai',
- ['nor'] = 'Norwegian',
- ['nsm'] = 'Northern Sami',
- ['nta'] = 'Northern Tai',
- ['nto'] = 'Esperanto',
- ['nyn'] = 'Nynorsk',
- ['oci'] = 'Occitan',
- ['ocr'] = 'Oji-Cree',
- ['ojb'] = 'Ojibway',
- ['ori'] = 'Oriya',
- ['oro'] = 'Oromo',
- ['oss'] = 'Ossetian',
- ['paa'] = 'Palestinian Aramaic',
- ['pal'] = 'Pali',
- ['pan'] = 'Punjabi',
- ['pap'] = 'Palpa',
- ['pas'] = 'Pashto',
- ['pgr'] = 'Polytonic Greek',
- ['pil'] = 'Pilipino',
- ['plg'] = 'Palaung',
- ['plk'] = 'Polish',
- ['pro'] = 'Provencal',
- ['ptg'] = 'Portuguese',
- ['qin'] = 'Chin',
- ['raj'] = 'Rajasthani',
- ['rbu'] = 'Russian Buriat',
- ['rcr'] = 'R-Cree',
- ['ria'] = 'Riang',
- ['rms'] = 'Rhaeto-Romanic',
- ['rom'] = 'Romanian',
- ['roy'] = 'Romany',
- ['rsy'] = 'Rusyn',
- ['rua'] = 'Ruanda',
- ['rus'] = 'Russian',
- ['sad'] = 'Sadri',
- ['san'] = 'Sanskrit',
- ['sat'] = 'Santali',
- ['say'] = 'Sayisi',
- ['sek'] = 'Sekota',
- ['sel'] = 'Selkup',
- ['sgo'] = 'Sango',
- ['shn'] = 'Shan',
- ['sib'] = 'Sibe',
- ['sid'] = 'Sidamo',
- ['sig'] = 'Silte Gurage',
- ['sks'] = 'Skolt Sami',
- ['sky'] = 'Slovak',
- ['sla'] = 'Slavey',
- ['slv'] = 'Slovenian',
- ['sml'] = 'Somali',
- ['smo'] = 'Samoan',
- ['sna'] = 'Sena',
- ['snd'] = 'Sindhi',
- ['snh'] = 'Sinhalese',
- ['snk'] = 'Soninke',
- ['sog'] = 'Sodo Gurage',
- ['sot'] = 'Sotho',
- ['sqi'] = 'Albanian',
- ['srb'] = 'Serbian',
- ['srk'] = 'Saraiki',
- ['srr'] = 'Serer',
- ['ssl'] = 'South Slavey',
- ['ssm'] = 'Southern Sami',
- ['sur'] = 'Suri',
- ['sva'] = 'Svan',
- ['sve'] = 'Swedish',
- ['swa'] = 'Swadaya Aramaic',
- ['swk'] = 'Swahili',
- ['swz'] = 'Swazi',
- ['sxt'] = 'Sutu',
- ['syr'] = 'Syriac',
- ['tab'] = 'Tabasaran',
- ['taj'] = 'Tajiki',
- ['tam'] = 'Tamil',
- ['tat'] = 'Tatar',
- ['tcr'] = 'TH-Cree',
- ['tel'] = 'Telugu',
- ['tgn'] = 'Tongan',
- ['tgr'] = 'Tigre',
- ['tgy'] = 'Tigrinya',
- ['tha'] = 'Thai',
- ['tht'] = 'Tahitian',
- ['tib'] = 'Tibetan',
- ['tkm'] = 'Turkmen',
- ['tmn'] = 'Temne',
- ['tna'] = 'Tswana',
- ['tne'] = 'Tundra Nenets',
- ['tng'] = 'Tonga',
- ['tod'] = 'Todo',
- ['trk'] = 'Turkish',
- ['tsg'] = 'Tsonga',
- ['tua'] = 'Turoyo Aramaic',
- ['tul'] = 'Tulu',
- ['tuv'] = 'Tuvin',
- ['twi'] = 'Twi',
- ['udm'] = 'Udmurt',
- ['ukr'] = 'Ukrainian',
- ['urd'] = 'Urdu',
- ['usb'] = 'Upper Sorbian',
- ['uyg'] = 'Uyghur',
- ['uzb'] = 'Uzbek',
- ['ven'] = 'Venda',
- ['vit'] = 'Vietnamese',
- ['wa' ] = 'Wa',
- ['wag'] = 'Wagdi',
- ['wcr'] = 'West-Cree',
- ['wel'] = 'Welsh',
- ['wlf'] = 'Wolof',
- ['xbd'] = 'Tai Lue',
- ['xhs'] = 'Xhosa',
- ['yak'] = 'Yakut',
- ['yba'] = 'Yoruba',
- ['ycr'] = 'Y-Cree',
- ['yic'] = 'Yi Classic',
- ['yim'] = 'Yi Modern',
- ['zhh'] = 'Chinese Hong Kong',
- ['zhp'] = 'Chinese Phonetic',
- ['zhs'] = 'Chinese Simplified',
- ['zht'] = 'Chinese Traditional',
- ['znd'] = 'Zande',
- ['zul'] = 'Zulu'
-}
-
-otf.tables.features = {
- ['aalt'] = 'Access All Alternates',
- ['abvf'] = 'Above-Base Forms',
- ['abvm'] = 'Above-Base Mark Positioning',
- ['abvs'] = 'Above-Base Substitutions',
- ['afrc'] = 'Alternative Fractions',
- ['akhn'] = 'Akhands',
- ['blwf'] = 'Below-Base Forms',
- ['blwm'] = 'Below-Base Mark Positioning',
- ['blws'] = 'Below-Base Substitutions',
- ['c2pc'] = 'Petite Capitals From Capitals',
- ['c2sc'] = 'Small Capitals From Capitals',
- ['calt'] = 'Contextual Alternates',
- ['case'] = 'Case-Sensitive Forms',
- ['ccmp'] = 'Glyph Composition/Decomposition',
- ['cjct'] = 'Conjunct Forms',
- ['clig'] = 'Contextual Ligatures',
- ['cpsp'] = 'Capital Spacing',
- ['cswh'] = 'Contextual Swash',
- ['curs'] = 'Cursive Positioning',
- ['dflt'] = 'Default Processing',
- ['dist'] = 'Distances',
- ['dlig'] = 'Discretionary Ligatures',
- ['dnom'] = 'Denominators',
- ['expt'] = 'Expert Forms',
- ['falt'] = 'Final glyph Alternates',
- ['fin2'] = 'Terminal Forms #2',
- ['fin3'] = 'Terminal Forms #3',
- ['fina'] = 'Terminal Forms',
- ['frac'] = 'Fractions',
- ['fwid'] = 'Full Width',
- ['half'] = 'Half Forms',
- ['haln'] = 'Halant Forms',
- ['halt'] = 'Alternate Half Width',
- ['hist'] = 'Historical Forms',
- ['hkna'] = 'Horizontal Kana Alternates',
- ['hlig'] = 'Historical Ligatures',
- ['hngl'] = 'Hangul',
- ['hojo'] = 'Hojo Kanji Forms',
- ['hwid'] = 'Half Width',
- ['init'] = 'Initial Forms',
- ['isol'] = 'Isolated Forms',
- ['ital'] = 'Italics',
- ['jalt'] = 'Justification Alternatives',
- ['jp04'] = 'JIS2004 Forms',
- ['jp78'] = 'JIS78 Forms',
- ['jp83'] = 'JIS83 Forms',
- ['jp90'] = 'JIS90 Forms',
- ['kern'] = 'Kerning',
- ['lfbd'] = 'Left Bounds',
- ['liga'] = 'Standard Ligatures',
- ['ljmo'] = 'Leading Jamo Forms',
- ['lnum'] = 'Lining Figures',
- ['locl'] = 'Localized Forms',
- ['mark'] = 'Mark Positioning',
- ['med2'] = 'Medial Forms #2',
- ['medi'] = 'Medial Forms',
- ['mgrk'] = 'Mathematical Greek',
- ['mkmk'] = 'Mark to Mark Positioning',
- ['mset'] = 'Mark Positioning via Substitution',
- ['nalt'] = 'Alternate Annotation Forms',
- ['nlck'] = 'NLC Kanji Forms',
- ['nukt'] = 'Nukta Forms',
- ['numr'] = 'Numerators',
- ['onum'] = 'Old Style Figures',
- ['opbd'] = 'Optical Bounds',
- ['ordn'] = 'Ordinals',
- ['ornm'] = 'Ornaments',
- ['palt'] = 'Proportional Alternate Width',
- ['pcap'] = 'Petite Capitals',
- ['pnum'] = 'Proportional Figures',
- ['pref'] = 'Pre-base Forms',
- ['pres'] = 'Pre-base Substitutions',
- ['pstf'] = 'Post-base Forms',
- ['psts'] = 'Post-base Substitutions',
- ['pwid'] = 'Proportional Widths',
- ['qwid'] = 'Quarter Widths',
- ['rand'] = 'Randomize',
- ['rkrf'] = 'Rakar Forms',
- ['rlig'] = 'Required Ligatures',
- ['rphf'] = 'Reph Form',
- ['rtbd'] = 'Right Bounds',
- ['rtla'] = 'Right-To-Left Alternates',
- ['ruby'] = 'Ruby Notation Forms',
- ['salt'] = 'Stylistic Alternates',
- ['sinf'] = 'Scientific Inferiors',
- ['size'] = 'Optical Size',
- ['smcp'] = 'Small Capitals',
- ['smpl'] = 'Simplified Forms',
- ['ss01'] = 'Stylistic Set 1',
- ['ss02'] = 'Stylistic Set 2',
- ['ss03'] = 'Stylistic Set 3',
- ['ss04'] = 'Stylistic Set 4',
- ['ss05'] = 'Stylistic Set 5',
- ['ss06'] = 'Stylistic Set 6',
- ['ss07'] = 'Stylistic Set 7',
- ['ss08'] = 'Stylistic Set 8',
- ['ss09'] = 'Stylistic Set 9',
- ['ss10'] = 'Stylistic Set 10',
- ['ss11'] = 'Stylistic Set 11',
- ['ss12'] = 'Stylistic Set 12',
- ['ss13'] = 'Stylistic Set 13',
- ['ss14'] = 'Stylistic Set 14',
- ['ss15'] = 'Stylistic Set 15',
- ['ss16'] = 'Stylistic Set 16',
- ['ss17'] = 'Stylistic Set 17',
- ['ss18'] = 'Stylistic Set 18',
- ['ss19'] = 'Stylistic Set 19',
- ['ss20'] = 'Stylistic Set 20',
- ['subs'] = 'Subscript',
- ['sups'] = 'Superscript',
- ['swsh'] = 'Swash',
- ['titl'] = 'Titling',
- ['tjmo'] = 'Trailing Jamo Forms',
- ['tnam'] = 'Traditional Name Forms',
- ['tnum'] = 'Tabular Figures',
- ['trad'] = 'Traditional Forms',
- ['twid'] = 'Third Widths',
- ['unic'] = 'Unicase',
- ['valt'] = 'Alternate Vertical Metrics',
- ['vatu'] = 'Vattu Variants',
- ['vert'] = 'Vertical Writing',
- ['vhal'] = 'Alternate Vertical Half Metrics',
- ['vjmo'] = 'Vowel Jamo Forms',
- ['vkna'] = 'Vertical Kana Alternates',
- ['vkrn'] = 'Vertical Kerning',
- ['vpal'] = 'Proportional Alternate Vertical Metrics',
- ['vrt2'] = 'Vertical Rotation',
- ['zero'] = 'Slashed Zero'
+otf.tables.global_fields = table.tohash {
+ "lookups",
+ "glyphs",
+ "subfonts",
+ "luatex",
+ "pfminfo",
+ "cidinfo",
+ "tables",
+ "names",
+ "unicodes",
+ "names",
+ "anchor_classes",
+ "kern_classes",
+ "gpos",
+ "gsub"
}
-otf.tables.baselines = {
- ['hang'] = 'Hanging baseline',
- ['icfb'] = 'Ideographic character face bottom edge baseline',
- ['icft'] = 'Ideographic character face tope edige baseline',
- ['ideo'] = 'Ideographic em-box bottom edge baseline',
- ['idtp'] = 'Ideographic em-box top edge baseline',
- ['math'] = 'Mathmatical centered baseline',
- ['romn'] = 'Roman baseline'
+otf.tables.valid_fields = {
+ "anchor_classes",
+ "ascent",
+ "cache_version",
+ "cidinfo",
+ "copyright",
+ "creationtime",
+ "descent",
+ "design_range_bottom",
+ "design_range_top",
+ "design_size",
+ "encodingchanged",
+ "extrema_bound",
+ "familyname",
+ "fontname",
+ "fontstyle_id",
+ "fontstyle_name",
+ "fullname",
+ "glyphs",
+ "hasvmetrics",
+ "head_optimized_for_cleartype",
+ "horiz_base",
+ "issans",
+ "isserif",
+ "italicangle",
+ "kerns",
+ "lookups",
+ -- "luatex",
+ "macstyle",
+ "modificationtime",
+ "onlybitmaps",
+ "origname",
+ "os2_version",
+ "pfminfo",
+ "private",
+ "serifcheck",
+ "sfd_version",
+ -- "size",
+ "strokedfont",
+ "strokewidth",
+ "subfonts",
+ "table_version",
+ -- "tables",
+ -- "ttf_tab_saved",
+ "ttf_tables",
+ "uni_interp",
+ "uniqueid",
+ "units_per_em",
+ "upos",
+ "use_typo_metrics",
+ "uwidth",
+ "validation_state",
+ "verbose",
+ "version",
+ "vert_base",
+ "weight",
+ "weight_width_slope_only",
+ "xuid",
}
-function otf.tables.to_tag(id)
- return stringformat("%4s",id:lower())
-end
+--[[ldx--
+<p>Here we go.</p>
+--ldx]]--
-function otf.meanings.resolve(tab,id)
- if tab and id then
- id = id:lower()
- return tab[id] or tab[id:gsub(" ","")] or tab['dflt'] or ''
- else
- return "unknown"
+local function load_featurefile(ff,featurefile)
+ if featurefile then
+ featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES"
+ if featurefile and featurefile ~= "" then
+ if trace_loading then
+ logs.report("load otf", "featurefile: %s", featurefile)
+ end
+ fontloader.apply_featurefile(ff, featurefile)
+ end
end
end
-function otf.meanings.script(id)
- return otf.meanings.resolve(otf.tables.scripts,id)
-end
-function otf.meanings.language(id)
- return otf.meanings.resolve(otf.tables.languages,id)
-end
-function otf.meanings.feature(id)
- return otf.meanings.resolve(otf.tables.features,id)
-end
-function otf.meanings.baseline(id)
- return otf.meanings.resolve(otf.tables.baselines,id)
-end
-
-otf.tables.to_scripts = table.reverse_hash(otf.tables.scripts )
-otf.tables.to_languages = table.reverse_hash(otf.tables.languages)
-otf.tables.to_features = table.reverse_hash(otf.tables.features )
-
-do
-
- local scripts = otf.tables.scripts
- local languages = otf.tables.languages
- local features = otf.tables.features
-
- local to_scripts = otf.tables.to_scripts
- local to_languages = otf.tables.to_languages
- local to_features = otf.tables.to_features
-
- function otf.meanings.normalize(features)
- local h = { }
- for k,v in pairs(features) do
- k = k:lower() -- :gsub("[^a-z0-9%-%.]" -- not needed
- if k == "language" or k == "lang" then
- v = (v:lower()):gsub("[^a-z0-9%-]","")
- k = language
- if not languages[v] then
- h.language = to_languages[v] or "dflt"
- else
- h.language = v
- end
- elseif k == "script" then
- v = (v:lower()):gsub("[^a-z0-9%-]","")
- if not scripts[v] then
- h.script = to_scripts[v] or "dflt"
- else
- h.script = v
- end
- else
- if type(v) == "string" then
- local b = v:is_boolean()
- if type(b) == "nil" then
- v = tonumber(v) or v:lower() -- gsub("[^a-z0-9%-]") -- too dangerous, e.g. featurefiles
- else
- v = b
- end
- end
- h[to_features[k] or k] = v
- end
+function otf.enhance(name,data,filename,verbose)
+ local enhancer = otf.enhancers[name]
+ if enhancer then
+ if (verbose ~= nil and verbose) or trace_loading then
+ logs.report("load otf","enhance: %s",name)
end
- return h
+ enhancer(data,filename)
end
-
end
---[[ldx--
-<p>Here we go.</p>
---ldx]]--
-
-otf.enhance = otf.enhance or { }
-otf.enhance.add_kerns = true
-
-otf.featurefiles = {
---~ "texhistoric.fea"
+local enhancers = {
+ -- pack and unpack are handled separately; they might even be moved
+ -- away from the enhancers namespace
+ "patch bugs",
+ "merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage",
+ "cleanup aat", "enrich with features", "add some missing characters",
+ "reorganize kerns", -- moved here
+ "flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
+ "prepare luatex tables",
+ "analyse features", "rehash features",
+ "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",
+ "check italic correction","check math",
+ "share widths",
+ "strip not needed data",
+ "migrate metadata",
}
function otf.load(filename,format,sub,featurefile)
@@ -838,72 +219,45 @@ function otf.load(filename,format,sub,featurefile)
end
if sub == "" then sub = false end
local hash = name
- if sub then -- name cleanup will move to cache code
+ if sub then
hash = hash .. "-" .. sub
- hash = hash:lower()
- hash = hash:gsub("[^%w%d]+","-")
end
+ hash = containers.cleanname(hash)
local data = containers.read(otf.cache(), hash)
- if data and data.verbose ~= fonts.verbose then
- data = nil
- end
local size = lfs.attributes(filename,"size") or 0
- if data and data.size ~= size then
- data = nil
- end
- if not data then
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
logs.report("load otf","loading: %s",filename)
local ff, messages
if sub then
- ff, messages = fontforge.open(filename,sub)
+ ff, messages = fontloader.open(filename,sub)
else
- ff, messages = fontforge.open(filename)
+ ff, messages = fontloader.open(filename)
end
- if messages and #messages > 0 then
- for _, m in ipairs(messages) do
- logs.report("load otf","warning: %s",m)
+ if trace_loading and messages and #messages > 0 then
+ for m=1,#messages do
+ logs.report("load otf","warning: %s",messages[m])
end
end
if ff then
- local function load_featurefile(featurefile)
- if featurefile then
- featurefile = input.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES"
- if featurefile and featurefile ~= "" then
- logs.report("load otf", "featurefile: %s", featurefile)
- fontforge.apply_featurefile(ff, featurefile)
- end
- end
- end
- -- for _, featurefile in pairs(otf.featurefiles) do
- -- load_featurefile(featurefile)
- -- end
- load_featurefile(featurefile)
- data = fontforge.to_table(ff)
- fontforge.close(ff)
+ load_featurefile(ff,featurefile)
+ data = fontloader.to_table(ff)
+ fontloader.close(ff)
if data then
- logs.report("load otf","enhance: patch")
- otf.enhance.patch(data,filename)
- logs.report("load otf","enhance: before")
- otf.enhance.before(data,filename)
- logs.report("load otf","enhance: enrich")
- otf.enhance.enrich(data,filename)
- logs.report("load otf","enhance: flatten")
- otf.enhance.flatten(data,filename)
- logs.report("load otf","enhance: analyze")
- otf.enhance.analyze(data,filename)
- logs.report("load otf","enhance: after")
- otf.enhance.after(data,filename)
- logs.report("load otf","enhance: strip")
- otf.enhance.strip(data,filename)
+ logs.report("load otf","file size: %s", size)
+ logs.report("load otf","enhancing ...")
+ for e=1,#enhancers do
+ otf.enhance(enhancers[e],data,filename)
+ end
if otf.pack and not fonts.verbose then
- logs.report("load otf","enhance: pack")
- otf.enhance.pack(data)
+ otf.enhance("pack",data,filename)
end
- logs.report("load otf","file size: %s", size)
data.size = size
data.verbose = fonts.verbose
- logs.report("load otf","saving: in cache")
+ logs.report("load otf","saving in cache: %s",filename)
data = containers.write(otf.cache(), hash, data)
+ collectgarbage("collect")
+ data = containers.read(otf.cache(), hash) -- this frees the old table and load the sparse one
+ collectgarbage("collect")
else
logs.report("load otf","loading failed (table conversion error)")
end
@@ -911,375 +265,357 @@ function otf.load(filename,format,sub,featurefile)
logs.report("load otf","loading failed (file read error)")
end
end
- otf.enhance.unpack(data)
+ if data then
+ otf.enhance("unpack",data,filename,false) -- no message here
+ otf.add_dimensions(data)
+ if trace_sequences then
+ otf.show_feature_order(data,filename)
+ end
+ end
return data
end
--- memory saver ..
-
-local criterium, threshold = 1, 0
-
-function otf.enhance.pack(data)
+function otf.add_dimensions(data)
+ -- todo: forget about the width if it's the defaultwidth (saves mem)
+ -- we could also build the marks hash here (instead of storing it)
if data then
- local h, t, c = { }, { }, { }
- local hh, tt, cc = { }, { }, { }
- local function tabstr(t)
- for i=1,#t do
- -- tricky, was if type(t[i]) == "boolean" then, but if no [1] then error
- local ti = type(t[i])
- if ti ~= "string" or ti ~= "number" then
- local s = tostring(t[1])
- for i=2,#t do
- s = s .. ",".. tostring(t[i])
- end
- return s
- end
- end
- return concat(t,",")
- end
- for pass=1,2 do
- local pack
- if pass == 1 then
- pack = function(v)
- -- v == table
- local tag = tabstr(v,",")
- local ht = h[tag]
- if not ht then
- ht = #t+1
- t[ht] = v
- h[tag] = ht
- c[ht] = 1
- else
- c[ht] = c[ht] + 1
- end
- return ht
- end
- else
- pack = function(v)
- -- v == number
- if c[v] <= criterium then
- return t[v]
- else
- -- compact hash
- local hv = hh[v]
- if not hv then
- hv = #tt+1
- tt[hv] = t[v]
- hh[v] = hv
- cc[hv] = c[v]
- end
- return hv
- end
- end
- end
- for k, v in pairs(data.glyphs) do
- v.boundingbox = pack(v.boundingbox)
- if v.lookups then
- for k,v in pairs(v.lookups) do
- for kk=1,#v do
- v[kk] = pack(v[kk])
- end
- end
- end
- local a = v.anchors
- if a then
- for k,v in pairs(a) do
- if k == "baselig" then
- for kk, vv in pairs(v) do
- for kkk=1,#vv do
- vv[kkk] = pack(vv[kkk])
- end
- end
- else
- for kk, vv in pairs(v) do
- v[kk] = pack(vv)
- end
- end
- end
- end
+ local force = otf.notdef
+ local luatex = data.luatex
+ local defaultwidth = luatex.defaultwidth or 0
+ local defaultheight = luatex.defaultheight or 0
+ local defaultdepth = luatex.defaultdepth or 0
+ for _, d in next, data.glyphs do
+ local bb, wd = d.boundingbox, d.width
+ if not wd then
+ d.width = defaultwidth
+ elseif wd ~= 0 and d.class == "mark" then
+ d.width = -wd
end
- if data.lookups then
- for k, v in pairs(data.lookups) do
- if v.rules then
- for kk, vv in pairs(v.rules) do
- local l = vv.lookups
- if l then
- vv.lookups = pack(l)
- end
- local c = vv.coverage
- if c then
- c.before = c.before and pack(c.before )
- c.after = c.after and pack(c.after )
- c.current = c.current and pack(c.current)
- end
- end
- end
- end
+ if force and not d.name then
+ d.name = ".notdef"
end
- if data.luatex then
- local li = data.luatex.ignore_flags
- if li then
- for k, v in pairs(li) do
- li[k] = pack(v)
- end
+ if bb then
+ local ht, dp = bb[4], -bb[2]
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ d.height = ht
end
- end
- if #t == 0 then
- logs.report("load otf","pack quality: nothing to pack")
- break
- elseif #t >= threshold then
- local one, two, rest = 0, 0, 0
- if pass == 1 then
- for k,v in pairs(c) do
- if v == 1 then
- one = one + 1
- elseif v == 2 then
- two = two + 1
- else
- rest = rest + 1
- end
- end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
else
- for k,v in pairs(cc) do
- if v >20 then
- rest = rest + 1
- elseif v >10 then
- two = two + 1
- else
- one = one + 1
- end
- end
- data.tables = tt
+ d.depth = dp
end
- logs.report("load otf","pack quality: pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", pass, one+two+rest, one, two, rest, criterium)
- else
- logs.report("load otf","pack quality: pass 1, %s packed, aborting pack (threshold: %s)", #t, threshold)
- break
end
end
end
end
-function otf.enhance.unpack(data)
- if data then
- local t = data.tables
- if t then
- for k, v in pairs(data.glyphs) do
- local tv = t[v.boundingbox] if tv then v.boundingbox = tv end
- local l = v.lookups
- if l then
- for k,v in pairs(l) do
- for i=1,#v do
- local tv = t[v[i]] if tv then v[i] = tv end
- end
- end
- end
- local a = v.anchors
- if a then
- for k,v in pairs(a) do
- if k == "baselig" then
- for kk, vv in pairs(v) do
- for kkk=1,#vv do
- local tv = t[vv[kkk]] if tv then vv[kkk] = tv end
- end
- end
- else
- for kk, vv in pairs(v) do
- local tv = t[vv] if tv then v[kk] = tv end
- end
- end
- end
- end
+function otf.show_feature_order(otfdata,filename)
+ local sequences = otfdata.luatex.sequences
+ if sequences and #sequences > 0 then
+ if trace_loading then
+ logs.report("otf check","font %s has %s sequences",filename,#sequences)
+ logs.report("otf check"," ")
+ end
+ for nos=1,#sequences do
+ local sequence = sequences[nos]
+ local typ = sequence.type or "no-type"
+ local name = sequence.name or "no-name"
+ local subtables = sequence.subtables or { "no-subtables" }
+ local features = sequence.features
+ if trace_loading then
+ logs.report("otf check","%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,","))
end
- if data.lookups then
- for k, v in pairs(data.lookups) do
- local r = v.rules
- if r then
- for kk, vv in pairs(r) do
- local l = vv.lookups
- if l then
- local tv = t[l] if tv then vv.lookups = tv end
- end
- local c = vv.coverage
- if c then
- local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
- cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
- cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
- end
+ if features then
+ for feature, scripts in next, features do
+ local tt = { }
+ for script, languages in next, scripts do
+ local ttt = { }
+ for language, _ in next, languages do
+ ttt[#ttt+1] = language
end
+ tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
end
- end
- end
- if data.luatex then
- local li = data.luatex.ignore_flags
- if li then
- for k, v in pairs(li) do
- local tv = t[v] if tv then li[k] = tv end
+ if trace_loading then
+ logs.report("otf check"," %s: %s",feature,concat(tt," "))
end
end
end
- data.tables = nil
end
+ if trace_loading then
+ logs.report("otf check","\n")
+ end
+ elseif trace_loading then
+ logs.report("otf check","font %s has no sequences",filename)
end
end
-- todo: normalize, design_size => designsize
-function otf.enhance.analyze(data,filename)
- local t = {
---~ filename = file.basename(filename),
- filename = filename,
- version = otf.version,
- creator = "context mkiv",
- unicodes = otf.analyze_unicodes(data),
- gposfeatures = otf.analyze_features(data.gpos),
- gsubfeatures = otf.analyze_features(data.gsub),
- marks = otf.analyze_class(data,'mark'),
- }
- t.subtables, t.name_to_type, t.internals, t.always_valid, t.ignore_flags, t.ctx_always = otf.analyze_subtables(data)
- data.luatex = t
+otf.enhancers["prepare luatex tables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ luatex.filename = filename
+ luatex.version = otf.version
+ luatex.creator = "context mkiv"
end
-do
- -- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
- --
- -- 18964 18964 (leader)
- -- 0 /.notdef
- -- 1..95 0020
- -- 99 3000
-
- local number = lpeg.C(lpeg.R("09","af","AF")^1)
- local space = lpeg.S(" \n\r\t")
- local spaces = space^0
- local period = lpeg.P(".")
- local periods = period * period
- local name = lpeg.P("/") * lpeg.C((1-space)^1)
-
- local unicodes, names = { }, {}
-
- local function do_one(a,b)
- unicodes[tonumber(a)] = tonumber(b,16)
- end
- local function do_range(a,b,c)
- c = tonumber(c,16)
- for i=tonumber(a),tonumber(b) do
- unicodes[i] = c
- c = c + 1
- end
+otf.enhancers["cleanup aat"] = function(data,filename)
+ if otf.cleanup_aat then
end
- local function do_name(a,b)
- names[tonumber(a)] = b
- end
-
- local grammar = lpeg.P { "start",
- start = number * spaces * number * lpeg.V("series"),
- series = (spaces * (lpeg.V("one") + lpeg.V("range") + lpeg.V("named")) )^1,
- one = (number * spaces * number) / do_one,
- range = (number * periods * number * spaces * number) / do_range,
- named = (number * spaces * name) / do_name
- }
+end
- function otf.load_cidmap(filename) -- lpeg
- local data = io.loaddata(filename)
- if data then
- unicodes, names = { }, { }
- grammar:match(data)
- local supplement, registry, ordering = filename:match("^(.-)%-(.-)%-()%.(.-)$")
- return {
- supplement = supplement,
- registry = registry,
- ordering = ordering,
- filename = filename,
- unicodes = unicodes,
- names = names
- }
- else
- return nil
+local function analyze_features(g, features)
+ if g then
+ local t, done = { }, { }
+ for k=1,#g do
+ local f = features or g[k].features
+ if f then
+ for k=1,#f do
+ -- scripts and tag
+ local tag = f[k].tag
+ if not done[tag] then
+ t[#t+1] = tag
+ done[tag] = true
+ end
+ end
+ end
+ end
+ if #t > 0 then
+ return t
end
end
-
+ return nil
end
-otf.cidmaps = { }
-otf.cidmax = 10
+otf.enhancers["analyse features"] = function(data,filename)
+ -- local luatex = data.luatex
+ -- luatex.gposfeatures = analyze_features(data.gpos)
+ -- luatex.gsubfeatures = analyze_features(data.gsub)
+end
-function otf.cidmap(registry,ordering,supplement)
- -- cf Arthur R. we can safely scan upwards since cids are downward compatible
- local template = "%s-%s-%s.cidmap"
- local supplement = tonumber(supplement)
- logs.report("load otf","needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
- local function locate(registry,ordering,supplement)
- local filename = format(template,registry,ordering,supplement)
- local cidmap = otf.cidmaps[filename]
- if not cidmap then
- logs.report("load otf","checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
- local fullname = input.find_file(filename,'cid') or ""
- if fullname ~= "" then
- cidmap = otf.load_cidmap(fullname)
- if cidmap then
- logs.report("load otf","using cidmap file %s",filename)
- otf.cidmaps[filename] = cidmap
- return cidmap
+otf.enhancers["rehash features"] = function(data,filename)
+ local features = { }
+ data.luatex.features = features
+ for k, what in next, otf.glists do
+ local dw = data[what]
+ if dw then
+ local f = { }
+ features[what] = f
+ for i=1,#dw do
+ local d= dw[i]
+ local dfeatures = d.features
+ if dfeatures then
+ for i=1,#dfeatures do
+ local df = dfeatures[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dscripts = df.scripts
+ for script, languages in next, dscripts do
+ script = strip(lower(script))
+ local fts = ft[script] if not fts then fts = {} ft[script] = fts end
+ for i=1,#languages do
+ fts[strip(lower(languages[i]))] = true
+ end
+ end
+ end
end
end
end
- return cidmap
end
- local cidmap = locate(registry,ordering,supplement)
- if not cidmap then
- local cidnum = nil
- -- next highest (alternatively we could start high)
- if supplement < otf.cidmax then
- for supplement=supplement+1,otf.cidmax do
- local c = locate(registry,ordering,supplement)
- if c then
- cidmap, cidnum = c, supplement
- break
- end
+end
+
+otf.enhancers["analyse anchors"] = function(data,filename)
+ local classes = data.anchor_classes
+ local luatex = data.luatex
+ local anchor_to_lookup, lookup_to_anchor = { }, { }
+ luatex.anchor_to_lookup, luatex.lookup_to_anchor = anchor_to_lookup, lookup_to_anchor
+ if classes then
+ for c=1,#classes do
+ local class = classes[c]
+ local anchor = class.name
+ local lookups = class.lookup
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ local a = anchor_to_lookup[anchor]
+ if not a then a = { } anchor_to_lookup[anchor] = a end
+ for l=1,#lookups do
+ local lookup = lookups[l]
+ local l = lookup_to_anchor[lookup]
+ if not l then l = { } lookup_to_anchor[lookup] = l end
+ l[anchor] = true
+ a[lookup] = true
end
end
- -- next lowest (least worse fit)
- if not cidmap and supplement > 0 then
- for supplement=supplement-1,0,-1 do
- local c = locate(registry,ordering,supplement)
- if c then
- cidmap, cidnum = c, supplement
- break
- end
- end
+ end
+end
+
+otf.enhancers["analyse marks"] = function(data,filename)
+ local glyphs = data.glyphs
+ local marks = { }
+ data.luatex.marks = marks
+ for unicode, index in next, data.luatex.indices do
+ local glyph = glyphs[index]
+ if glyph.class == "mark" then
+ marks[unicode] = true
end
- -- prevent further lookups
- if cidmap and cidnum > 0 then
- for s=0,cidnum-1 do
- filename = format(template,registry,ordering,s)
- if not otf.cidmaps[filename] then
- otf.cidmaps[filename] = cidmap -- copy of ref
+ end
+end
+
+local other = lpeg.C((1 - lpeg.S("_."))^0)
+local ligsplitter = lpeg.Ct(other * (lpeg.P("_") * other)^0)
+
+--~ print(splitter:match("this"))
+--~ print(splitter:match("this.that"))
+--~ print(splitter:match("such_so_more"))
+--~ print(splitter:match("such_so_more.that"))
+
+otf.enhancers["analyse unicodes"] = function(data,filename)
+ local unicodes = data.luatex.unicodes
+ -- we need to move this code
+ unicodes['space'] = unicodes['space'] or 32 -- handly later on
+ unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on
+ unicodes['zwj'] = unicodes['zwj'] or zwj -- handly later on
+ unicodes['zwnj'] = unicodes['zwnj'] or zwnj -- handly later on
+ -- the tounicode mapping is sparse and only needed for alternatives
+ local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
+ data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ for index, glyph in next, data.glyphs do
+ local name, unic = glyph.name, glyph.unicode or -1 -- play safe
+ if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
+ -- a.whatever or a_b_c.whatever or a_b_c
+ local split = ligsplitter:match(name)
+ if #split == 0 then
+ -- skip
+ elseif #split == 1 then
+ local u = unicodes[split[1]]
+ if u then
+ if type(u) == "table" then
+ u = u[1]
+ end
+ if u < 0x10000 then
+ originals[index], tounicode[index] = u, format("%04X",u)
+ else
+ originals[index], tounicode[index] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00)
+ end
+ ns = ns + 1
+ else
+ originals[index], tounicode[index] = 0xFFFD, "FFFD"
+ end
+ else
+ local as = { }
+ for l=1,#split do
+ local u = unicodes[split[l]]
+ if not u then
+ as[l], split[l] = 0xFFFD, "FFFD"
+ else
+ if type(u) == "table" then
+ u = u[1]
+ end
+ if u < 0x10000 then
+ as[l], split[l] = u, format("%04X",u)
+ else
+ as[l], split[l] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00)
+ end
+ end
+ end
+ split = concat(split)
+ if split ~= "" then
+ originals[index], tounicode[index] = as, split
+ nl = nl + 1
+ else
+ originals[index], tounicode[index] = 0xFFFD, "FFFD"
end
end
end
end
- return cidmap
+ if trace_loading and (ns > 0 or nl > 0) then
+ logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ end
end
---~ ["cidinfo"]={
---~ ["ordering"]="Japan1",
---~ ["registry"]="Adobe",
---~ ["supplement"]=6,
---~ ["version"]=6,
---~ },
+otf.enhancers["analyse subtables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ local sequences = { }
+ local lookups = { }
+ luatex.sequences = sequences
+ luatex.lookups = lookups
+ for _, g in next, { data.gsub, data.gpos } do
+ for k=1,#g do
+ local gk = g[k]
-function otf.enhance.before(data,filename)
- local private = fonts.private
+local typ = gk.type
+if typ == "gsub_contextchain" or typ == "gpos_contextchain" then
+ gk.chain = 1
+elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then
+ gk.chain = -1
+else
+ gk.chain = 0
+end
+
+ local features = gk.features
+ if features then
+ sequences[#sequences+1] = gk
+ -- scripts, tag, ismac
+ local t = { }
+ for f=1,#features do
+ local feature = features[f]
+ local hash = { }
+ -- only script and langs matter
+ for s, languages in next, feature.scripts do
+ s = lower(s)
+ local h = hash[s]
+ if not h then h = { } hash[s] = h end
+ for l=1,#languages do
+ h[strip(lower(languages[l]))] = true
+ end
+ end
+ t[feature.tag] = hash
+ end
+ gk.features = t
+ else
+ lookups[gk.name] = gk
+ gk.name = nil
+ end
+ local subtables = gk.subtables
+ if subtables then
+ local t = { }
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local name = subtable.name
+ t[#t+1] = name
+ end
+ gk.subtables = t
+ 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
+ }
+ end
+ end
+ end
+end
+
+otf.enhancers["merge cid fonts"] = function(data,filename)
+ -- we can also move the names to data.luatex.names which might
+ -- save us some more memory (at the cost of harder tracing)
if data.subfonts and table.is_empty(data.glyphs) then
local cidinfo = data.cidinfo
local verbose = fonts.verbose
if cidinfo.registry then
- local cidmap = otf.cidmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ local cidmap = fonts.cid.getmap and fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
if cidmap then
local glyphs, uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, { }, 0, 0
local unicodes, names = cidmap.unicodes, cidmap.names
- for n, subfont in pairs(data.subfonts) do
- for index, g in pairs(subfont.glyphs) do
+ for n, subfont in next, data.subfonts do
+ for index, g in next, subfont.glyphs do
if not next(g) then
-- dummy entry
else
@@ -1288,90 +624,143 @@ function otf.enhance.before(data,filename)
g.boundingbox = g.boundingbox -- or zerobox
g.name = g.name or name or "unknown"
if unicode then
--- g.unicode = unicode
uni_to_int[unicode] = index
int_to_uni[index] = unicode
nofunicodes = nofunicodes + 1
+ g.unicode = unicode
elseif name then
--- g.unicode = -1
nofnames = nofnames + 1
+ g.unicode = -1
end
glyphs[index] = g
end
end
subfont.glyphs = nil
end
- logs.report("load otf","cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ if trace_loading then
+ logs.report("load otf","cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ end
data.glyphs = glyphs
data.map = data.map or { }
data.map.map = uni_to_int
data.map.backmap = int_to_uni
- else
+ elseif trace_loading then
logs.report("load otf","unable to remap cid font, missing cid file for %s",filename)
end
- else
+ elseif trace_loading then
logs.report("load otf","font %s has no glyphs",filename)
end
end
- if data.map then
- local uni_to_int = data.map.map -- [unic] = slot
- local int_to_uni = data.map.backmap -- { [0|1] = unic, ... }
- for index, glyph in pairs(data.glyphs) do
- if glyph.name then
--- local unic = glyph.unicode or glyph.unicodeenc or -1
-local unic = int_to_uni[index] or -1
- if index > 0 and (unic == -1 or unic >= 0x110000) then
- while uni_to_int[private] do
- private = private + 1
- end
- uni_to_int[private] = index
- int_to_uni[index] = private
--- glyph.unicode = private
- if fonts.trace then
- logs.report("load otf","enhance: glyph %s at index %s is moved to private unicode slot %s",glyph.name,index,private)
- end
+end
+
+otf.enhancers["prepare unicode"] = function(data,filename)
+ local luatex = data.luatex
+ if not luatex then luatex = { } data.luatex = luatex end
+ local indices, unicodes, multiples, internals = { }, { }, { }, { }
+ local glyphs = data.glyphs
+ local mapmap = data.map
+ if not mapmap then
+ logs.report("load otf","no map in %s",filename)
+ mapmap = { }
+ data.map = { map = mapmap }
+ elseif not mapmap.map then
+ logs.report("load otf","no unicode map in %s",filename)
+ mapmap = { }
+ data.map.map = mapmap
+ else
+ mapmap = mapmap.map
+ end
+ local criterium = fonts.private
+ local private = fonts.private
+ for index, glyph in next, glyphs do
+ if index > 0 then
+ local name = glyph.name
+ if name then
+ local unicode = glyph.unicode
+ if unicode == -1 or unicode >= criterium then
+ glyph.unicode = private
+ indices[private] = index
+ unicodes[name] = private
+ internals[index] = true
+ if trace_private then
+ logs.report("load otf","enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
else
- glyph.unicode = unic -- safeguard for older version
+ indices[unicode] = index
+ unicodes[name] = unicode
end
end
end
- local n = 0
- for k,v in pairs(int_to_uni) do
- if v == -1 or v >= 0x110000 then
- int_to_uni[k], n = nil, n+1
- end
- end
- if fonts.trace then
- logs.report("load otf","enhance: %s entries removed from map.backmap",n)
- end
- local n = 0
- for k,v in pairs(uni_to_int) do
- if k == -1 or k >= 0x110000 then
- uni_to_int[k], n = nil, n+1
+ end
+ -- beware: the indeces table is used to initialize the tfm table
+ for unicode, index in next, mapmap do
+ if not internals[index] then
+ local name = glyphs[index].name
+ if name then
+ local un = unicodes[name]
+ if not un then
+ unicodes[name] = unicode -- or 0
+ elseif type(un) == "number" then
+ if un ~= unicode then
+ multiples[#multiples+1] = name
+ unicodes[name] = { un, unicode }
+ indices[unicode] = index
+ end
+ else
+ local ok = false
+ for u=1,#un do
+ if un[u] == unicode then
+ ok = true
+ break
+ end
+ end
+ if not ok then
+ multiples[#multiples+1] = name
+ un[#un+1] = unicode
+ indices[unicode] = index
+ end
+ end
end
end
- if fonts.trace then
- logs.report("load otf","enhance: %s entries removed from map.mapmap",n)
+ end
+ if trace_loading then
+ if #multiples > 0 then
+ logs.report("load otf","%s glyph are reused: %s",#multiples, concat(multiples," "))
+ else
+ logs.report("load otf","no glyph are reused")
end
- else
- data.map = { map = {}, backmap = {} }
end
- if data.ttf_tables then
- for _, v in ipairs(data.ttf_tables) do
- if v.data then v.data = "deleted" end
+ luatex.indices = indices
+ luatex.unicodes = unicodes
+ luatex.private = private
+end
+
+otf.enhancers["cleanup ttf tables"] = function(data,filename)
+ local ttf_tables = data.ttf_tables
+ if ttf_tables then
+ for k=1,#ttf_tables do
+ if ttf_tables[k].data then ttf_tables[k].data = "deleted" end
end
end
- table.compact(data.glyphs)
+ data.ttf_tab_saved = nil
+end
+
+otf.enhancers["compact glyphs"] = function(data,filename)
+ table.compact(data.glyphs) -- needed?
if data.subfonts then
- for _, subfont in pairs(data.subfonts) do
- table.compact(subfont.glyphs)
+ for _, subfont in next, data.subfonts do
+ table.compact(subfont.glyphs) -- needed?
end
end
+end
+
+otf.enhancers["reverse coverage"] = function(data,filename)
-- we prefer the before lookups in a normal order
if data.lookups then
- for _, v in pairs(data.lookups) do
+ for _, v in next, data.lookups do
if v.rules then
- for _, vv in pairs(v.rules) do
+ for _, vv in next, v.rules do
local c = vv.coverage
if c and c.before then
c.before = table.reverse(c.before)
@@ -1382,24 +771,148 @@ local unic = int_to_uni[index] or -1
end
end
-function otf.enhance.after(data,filename) -- to be split
- if otf.enhance.add_kerns then
- local glyphs, mapmap, unicodes = data.glyphs, data.map.map, data.luatex.unicodes
- local mkdone = false
- for index, glyph in pairs(data.glyphs) do
- if glyph.kerns then
- local mykerns = { } -- unicode indexed !
- for k,v in pairs(glyph.kerns) do
- local vc, vo, vl = v.char, v.off, v.lookup
- if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
- local uvc = unicodes[vc]
- if not uvc then
+otf.enhancers["check italic correction"] = function(data,filename)
+ local glyphs = data.glyphs
+ local ok = false
+ for index, glyph in next, glyphs do
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ glyph.italic = ic
+ end
+ glyph.italic_correction = nil
+ ok = true
+ end
+ end
+ -- we can use this to avoid calculations
+ otf.tables.valid_fields[#otf.tables.valid_fields+1] = "has_italic"
+ data.has_italic = true
+end
+
+otf.enhancers["check math"] = function(data,filename)
+ if data.math then
+ -- we move the math stuff into a math subtable because we then can
+ -- test faster in the tfm copy
+ local glyphs = data.glyphs
+ local unicodes = data.luatex.unicodes
+ for index, glyph in next, glyphs do
+ local mk = glyph.mathkern
+ local hv = glyph.horiz_variants
+ local vv = glyph.vert_variants
+ if mk or hv or vv then
+ local math = { }
+ glyph.math = math
+ if mk then
+ for k, v in next, mk do
+ if not next(v) then
+ mk[k] = nil
+ end
+ end
+ math.kerns = mk
+ glyph.mathkern = nil
+ end
+ if hv then
+ math.horiz_variants = hv.variants
+ local p = hv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.horiz_parts = p
+ end
+ end
+ local ic = hv.italic_correction
+ if ic and ic ~= 0 then
+ math.horiz_italic_correction = ic
+ end
+ glyph.horiz_variants = nil
+ end
+ if vv then
+ local uc = unicodes[index]
+ math.vert_variants = vv.variants
+ local p = vv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.vert_parts = p
+ end
+ end
+ local ic = vv.italic_correction
+ if ic and ic ~= 0 then
+ math.vert_italic_correction = ic
+ end
+ glyph.vert_variants = nil
+ end
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ math.italic_correction = ic
+ end
+ glyph.italic_correction = nil
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["share widths"] = function(data,filename)
+ local glyphs = data.glyphs
+ local widths = { }
+ for index, glyph in next, glyphs do
+ local width = glyph.width
+ widths[width] = (widths[width] or 0) + 1
+ end
+ -- share width for cjk fonts
+ local wd, most = 0, 1
+ for k,v in next, widths do
+ if v > most then
+ wd, most = k, v
+ end
+ end
+ if most > 1000 then
+ if trace_loading then
+ logs.report("load otf", "most common width: %s (%s times), sharing (cjk font)",wd,most)
+ end
+ for k, v in next, glyphs do
+ if v.width == wd then
+ v.width = nil
+ end
+ end
+ data.luatex.defaultwidth = wd
+ end
+end
+
+-- kern: ttf has a table with kerns
+
+otf.enhancers["reorganize kerns"] = function(data,filename)
+ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+ local mkdone = false
+ for index, glyph in next, data.glyphs do
+ if glyph.kerns then
+ local mykerns = { }
+ for k,v in next, glyph.kerns do
+ local vc, vo, vl = v.char, v.off, v.lookup
+ if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
+ local uvc = unicodes[vc]
+ if not uvc then
+ if trace_loading then
logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index)
- else
- local mkl = mykerns[vl]
+ end
+ else
+ if type(vl) ~= "table" then
+ vl = { vl }
+ end
+ for l=1,#vl do
+ local vll = vl[l]
+ local mkl = mykerns[vll]
if not mkl then
mkl = { }
- mykerns[v.lookup] = mkl
+ mykerns[vll] = mkl
end
if type(uvc) == "table" then
for u=1,#uvc do
@@ -1411,62 +924,86 @@ function otf.enhance.after(data,filename) -- to be split
end
end
end
- glyph.mykerns = mykerns
- glyph.kerns = nil -- saves space and time
- mkdone = true
end
+ glyph.mykerns = mykerns
+ glyph.kerns = nil -- saves space and time
+ mkdone = true
end
- if mkdone then
- logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables")
+ end
+ if trace_loading and mkdone then
+ logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables")
+ end
+ if data.kerns then
+ if trace_loading then
+ logs.report("load otf", "removing global 'kern' table")
end
- if data.gpos then
- for _, gpos in ipairs(data.gpos) do
- if gpos.subtables then
- for _, subtable in ipairs(gpos.subtables) do
- local kernclass = subtable.kernclass
- if kernclass then
- for _, kcl in ipairs(kernclass) do
- local firsts, seconds, offsets, lookup = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup
+ data.kerns = nil
+ end
+ local dgpos = data.gpos
+ if dgpos then
+ for gp=1,#dgpos do
+ local gpos = dgpos[gp]
+ local subtables = gpos.subtables
+ if subtables then
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
+ if kernclass then
+ for k=1,#kernclass do
+ local kcl = kernclass[k]
+ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ for l=1,#lookups do
+ local lookup = lookups[l]
local maxfirsts, maxseconds = getn(firsts), getn(seconds)
- logs.report("load otf", "adding kernclass %s with %s times %s pairs)",lookup, maxfirsts, maxseconds)
- for fk, fv in pairs(firsts) do
- for first in fv:gmatch("[^ ]+") do
+ if trace_loading then
+ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
+ end
+ for fk, fv in next, firsts do
+ for first in gmatch(fv,"[^ ]+") do
local first_unicode = unicodes[first]
if type(first_unicode) == "number" then
first_unicode = { first_unicode }
end
for f=1,#first_unicode do
local glyph = glyphs[mapmap[first_unicode[f]]]
- local mykerns = glyph.mykerns
- if not mykerns then
- mykerns = { } -- unicode indexed !
- glyph.mykerns = mykerns
- end
- local lookupkerns = mykerns[lookup]
- if not lookupkerns then
- lookupkerns = { }
- mykerns[lookup] = lookupkerns
- end
- for sk, sv in pairs(seconds) do
- local offset = offsets[(fk-1) * maxseconds + sk]
- for second in sv:gmatch("[^ ]+") do
- local second_unicode = unicodes[second]
- if type(second_unicode) == "number" then
- lookupkerns[second_unicode] = offset
- else
- for s=1,#second_unicode do
- lookupkerns[second_unicode[s]] = offset
+ if glyph then
+ local mykerns = glyph.mykerns
+ if not mykerns then
+ mykerns = { } -- unicode indexed !
+ glyph.mykerns = mykerns
+ end
+ local lookupkerns = mykerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ mykerns[lookup] = lookupkerns
+ end
+ for sk, sv in next, seconds do
+ local offset = offsets[(fk-1) * maxseconds + sk]
+ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+ for second in gmatch(sv,"[^ ]+") do
+ local second_unicode = unicodes[second]
+ if type(second_unicode) == "number" then
+ lookupkerns[second_unicode] = offset
+ else
+ for s=1,#second_unicode do
+ lookupkerns[second_unicode[s]] = offset
+ end
end
end
end
+ elseif trace_loading then
+ logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
end
end
end
end
end
- subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
- subtable.kernclass = { }
end
+ subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
+ subtable.kernclass = { }
end
end
end
@@ -1474,21 +1011,28 @@ function otf.enhance.after(data,filename) -- to be split
end
end
-function otf.enhance.strip(data)
+otf.enhancers["strip not needed data"] = function(data,filename)
local verbose = fonts.verbose
- local int_to_uni = data.map.backmap
- for k, v in pairs(data.glyphs) do
+ local int_to_uni = data.luatex.unicodes
+ for k, v in next, data.glyphs do
local d = v.dependents
if d then v.dependents = nil end
+ local a = v.altuni
+ if a then v.altuni = nil end
if verbose then
local code = int_to_uni[k]
+ -- looks like this is done twice ... bug?
if code then
local vu = v.unicode
if not vu then
v.unicode = code
elseif type(vu) == "table" then
- vu[#bu+1] = code
- else
+ if vu[#vu] == code then
+ -- weird
+ else
+ vu[#vu+1] = code
+ end
+ elseif vu ~= code then
v.unicode = { vu, code }
end
end
@@ -1498,19 +1042,39 @@ function otf.enhance.strip(data)
end
end
data.luatex.comment = "Glyph tables have their original index. When present, mykern tables are indexed by unicode."
- data.luatex.indices = data.map.map -- needed for shared glyphs
data.map = nil
- data.names = nil
+ data.names = nil -- funny names for editors
data.glyphcnt = nil
data.glyphmax = nil
+ if true then
+ data.gpos = nil
+ data.gsub = nil
+ data.anchor_classes = nil
+ end
end
-function otf.enhance.flatten(data,filename) -- to be split
- logs.report("load otf", "flattening 'specifications' tables")
- for k, v in pairs(data.glyphs) do
+otf.enhancers["migrate metadata"] = function(data,filename)
+ local global_fields = otf.tables.global_fields
+ local metadata = { }
+ for k,v in next, data do
+ if not global_fields[k] then
+ metadata[k] = v
+ data[k] = nil
+ end
+ end
+ data.metadata = metadata
+ -- goodies
+ local pfminfo = data.pfminfo
+ metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose["proportion"] == "Monospaced")
+ metadata.charwidth = pfminfo and pfminfo.avgwidth
+end
+
+otf.enhancers["flatten glyph lookups"] = function(data,filename)
+ for k, v in next, data.glyphs do
if v.lookups then
- for kk, vv in pairs(v.lookups) do
- for kkk, vvv in ipairs(vv) do
+ for kk, vv in next, v.lookups do
+ for kkk=1,#vv do
+ local vvv = vv[kkk]
local s = vvv.specification
if s then
local t = vvv.type
@@ -1523,27 +1087,29 @@ function otf.enhance.flatten(data,filename) -- to be split
elseif t == "multiple" then
vv[kkk] = { "multiple", s.components }
elseif t == "position" then
- vv[kkk] = { "position", s.x or 0, s.y or 0, s.h or 0, s.v or 0 }
+ vv[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
elseif t == "pair" then
local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
if one then
if two then
- vv[kkk] = { "pair", paired, one.x or 0, one.y or 0, one.h or 0, one.v or 0, two.x or 0, two.y or 0, two.h or 0, two.v or 0 }
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
else
- vv[kkk] = { "pair", paired, one.x or 0, one.y or 0, one.h or 0 }
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
end
else
if two then
- vv[kkk] = { "pair", paired, 0, 0, 0, 0, two.x or 0, two.y or 0, two.h or 0, two.v or 0 }
+ vv[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
else
vv[kkk] = { "pair", paired }
end
end
else
- logs.report("load otf", "flattening needed, warn Hans and/or Taco")
- for a, b in pairs(s) do
- if vvv[a] then
- logs.report("load otf", "flattening conflict, warn Hans and/or Taco")
+ if trace_loading then
+ logs.report("load otf", "flattening needed, report to context list")
+ end
+ for a, b in next, s do
+ if trace_loading and vvv[a] then
+ logs.report("load otf", "flattening conflict, report to context list")
end
vvv[a] = b
end
@@ -1554,15 +1120,18 @@ function otf.enhance.flatten(data,filename) -- to be split
end
end
end
- logs.report("load otf", "flattening 'anchor' tables")
- for k, v in pairs(data.glyphs) do
+end
+
+otf.enhancers["flatten anchor tables"] = function(data,filename)
+ for k, v in next, data.glyphs do
if v.anchors then
- for kk, vv in pairs(v.anchors) do
- for kkk, vvv in pairs(vv) do
- if vvv.x or vvv.y then -- kkk == "centry"
+ for kk, vv in next, v.anchors do
+ for kkk, vvv in next, vv do
+ if vvv.x or vvv.y then
vv[kkk] = { vvv.x or 0, vvv.y or 0 }
else
- for kkkk, vvvv in ipairs(vvv) do
+ for kkkk=1,#vvv do
+ local vvvv = vvv[kkkk]
vvv[kkkk] = { vvvv.x or 0, vvvv.y or 0 }
end
end
@@ -1570,14 +1139,24 @@ function otf.enhance.flatten(data,filename) -- to be split
end
end
end
- for _, tag in pairs({"gpos","gsub"}) do
+end
+
+otf.enhancers["flatten feature tables"] = function(data,filename)
+ -- is this needed? do we still use them at all?
+ for _, tag in next, otf.glists do
if data[tag] then
- logs.report("load otf", "flattening '%s' tables", tag)
- for k, v in pairs(data[tag]) do
- if v.features then
- for kk, vv in ipairs(v.features) do
+ if trace_loading then
+ logs.report("load otf", "flattening %s table", tag)
+ end
+ for k, v in next, data[tag] do
+ local features = v.features
+ if features then
+ for kk=1,#features do
+ local vv = features[kk]
local t = { }
- for kkk, vvv in ipairs(vv.scripts) do
+ local scripts = vv.scripts
+ for kkk=1,#scripts do
+ local vvv = scripts[kkk]
t[vvv.script] = vvv.langs
end
vv.scripts = t
@@ -1588,12 +1167,12 @@ function otf.enhance.flatten(data,filename) -- to be split
end
end
-otf.enhance.patches = { }
+otf.enhancers.patches = otf.enhancers.patches or { }
-function otf.enhance.patch(data,filename)
- local basename = file.basename(filename:lower())
- for pattern, action in pairs(otf.enhance.patches) do
- if basename:find(pattern) then
+otf.enhancers["patch bugs"] = function(data,filename)
+ local basename = file.basename(lower(filename))
+ for pattern, action in next, otf.enhancers.patches do
+ if find(basename,pattern) then
action(data,filename)
end
end
@@ -1601,160 +1180,8 @@ end
-- tex features
-function otf.enhance.enrich(data,filename)
- -- later
-end
-
-function otf.analyze_class(data,class)
- local classes = { }
- local glyphs = data.glyphs
- for unicode, index in pairs(data.map.map) do
- local glyph = glyphs[index]
- if glyph.class == class then
- classes[unicode] = true
- end
- end
- return classes
-end
-
-function otf.analyze_subtables(data)
- local subtables, name_to_type, internals, always_valid, ignore_flags, ctx_always = { }, { }, { }, { }, { }, { }
- local function collect(g)
- if g then
- for k,v in ipairs(g) do
- if v.features then
- local ignored = { false, false, false }
- local flags = v.flags
- if flags.ignorecombiningmarks then ignored[1] = 'mark' end
- if flags.ignorebasechars then ignored[2] = 'base' end
- if flags.ignoreligatures then ignored[3] = 'ligature' end
- if v.subtables then
- local type = v.type
- for _, feature in ipairs(v.features) do
- local ft = feature.tag:lower()
- subtables[ft] = subtables[ft] or { }
- ctx_always[ft] = v.always
- for script, languages in pairs(feature.scripts) do
- script = script:lower()
- script = script:strip()
- sft = subtables[ft]
- local sfts = sft[script]
- if not sfts then
- sfts = { }
- sft[script] = sfts
- end
- for _, language in ipairs(languages) do
- language = language:lower()
- language = language:strip()
- local sftsl = sfts[language]
- if not sftsl then
- sftsl = sfts[language] or { }
- sfts[language] = sftsl
- end
- local lookups, valid = sftsl.lookups or { }, sftsl.valid or { }
- for n, subtable in ipairs(v.subtables) do
- local stl = subtable.name
- if stl then
- lookups[#lookups+1] = stl
- valid[stl] = true
- name_to_type[stl] = type
- ignore_flags[stl] = ignored
- end
- end
- sftsl.lookups, sftsl.valid = lookups, valid
- end
- end
- end
- end
- else
- -- we have an internal feature, say ss_l_83 that resolves to
- -- subfeatures like ss_l_83_s which we find in the glyphs
- name_to_type[v.name] = v.type
- local lookups, valid = { }, { }
- for n, subtable in ipairs(v.subtables) do
- local stl = subtable.name
- if stl then
- lookups[#lookups+1] = stl
- valid[stl] = true
- always_valid[stl] = true
- end
- end
- internals[v.name] = {
- lookups = lookups,
- valid = valid
- }
- always_valid[v.name] = true -- bonus
- end
- end
- end
- end
- collect(data.gsub)
- collect(data.gpos)
- return subtables, name_to_type, internals, always_valid, ignore_flags, ctx_always
-end
-
-function otf.analyze_unicodes(data)
- local unicodes = { }
- local indices = data.map.map
- local glyphs = data.glyphs
- local multiples = { }
- for unicode, index in pairs(indices) do
- local name = glyphs[index].name
- if name then
- local un = unicodes[name]
- if not un then
- unicodes[name] = unicode -- or 0
- elseif type(un) == "number" then
- multiples[#multiples+1] = name
- unicodes[name] = { un, unicode }
- else
- un[#un+1] = unicode
- end
- end
- end
- if #multiples > 0 then
- logs.report("load otf","%s glyph are reused: %s",#multiples, concat(multiples," "))
- end
- unicodes['space'] = unicodes['space'] or 32 -- handly later on
- unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on
- return unicodes
-end
-
-function otf.analyze_features(g, features)
- if g then
- local t, done = { }, { }
- for k=1,#g do
- local f = features or g[k].features
- if f then
- for k=1,#f do
- -- scripts and tag
- local tag = f[k].tag
- if not done[tag] then
- t[#t+1] = tag
- done[tag] = true
- end
- end
- end
- end
- if #t > 0 then
- return t
- end
- end
- return nil
-end
-
-function otf.valid_subtable(otfdata,kind,script,language)
- local tk = otfdata.luatex.subtables[kind]
- if tk then
- local tks = tk[script] or tk.dflt
- if tks then
- local tksl = tks[language] or tks.dflt
- if tksl then
- return tksl.lookups
- end
- end
- end
- return false
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- later, ctx only
end
function otf.features.register(name,default)
@@ -1762,75 +1189,70 @@ function otf.features.register(name,default)
otf.features.default[name] = default
end
-function otf.set_features(tfmdata) -- node and base, simple mapping
- local shared = tfmdata.shared
- local otfdata = shared.otfdata
- shared.features = fonts.define.check(shared.features,otf.features.default)
- local features = shared.features
- local trace = otf.trace_features or otf.trace_set_features
- if not tfmdata.language then tfmdata.language = 'dflt' end
- if not tfmdata.script then tfmdata.script = 'dflt' end
+function otf.set_features(tfmdata,features)
+ local processes = { }
if not table.is_empty(features) then
- local gposlist = otfdata.luatex.gposfeatures
- local gsublist = otfdata.luatex.gsubfeatures
- local mode = tfmdata.mode or fonts.mode
+ local lists = {
+ fonts.triggers,
+ fonts.processors,
+ fonts.manipulators,
+ }
+ local mode = tfmdata.mode or fonts.mode -- or features.mode
local initializers = fonts.initializers
local fi = initializers[mode]
- if fi then -- todo: delay initilization for mode 'node'
+ if fi then
local fiotf = fi.otf
if fiotf then
local done = { }
- local function initialize(list) -- using tex lig and kerning
+ for l=1,4 do
+ local list = lists[l]
if list then
for i=1,#list do
local f = list[i]
local value = features[f]
if value and fiotf[f] then -- brr
if not done[f] then -- so, we can move some to triggers
- if trace then
+ if trace_features then
logs.report("define otf","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown', tfmdata.fullname or 'unknown')
end
fiotf[f](tfmdata,value) -- can set mode (no need to pass otf)
mode = tfmdata.mode or fonts.mode -- keep this, mode can be set local !
- local fi = initializers[mode]
- fiotf = fi.otf
+ local im = initializers[mode]
+ if im then
+ fiotf = initializers[mode].otf
+ end
done[f] = true
end
end
end
end
end
- initialize(fonts.triggers)
- initialize(gsublist)
- initialize(gposlist)
- initialize(fonts.manipulators)
end
end
local fm = fonts.methods[mode]
if fm then
local fmotf = fm.otf
- local sp = shared.processors
if fmotf then
- local function register(list) -- node manipulations
+ for l=1,4 do
+ local list = lists[l]
if list then
for i=1,#list do
local f = list[i]
- if features[f] and fmotf[f] then -- brr
- if trace then
+ if fmotf[f] then -- brr
+ if trace_features then
logs.report("define otf","installing feature handler %s for mode %s for font %s",f,mode or 'unknown', tfmdata.fullname or 'unknown')
end
- sp[#sp+1] = fmotf[f]
+ processes[#processes+1] = fmotf[f]
end
end
end
end
- register(fonts.triggers)
- register(gsublist)
- register(gposlist)
- register(fonts.manipulators)
end
+ else
+ -- message
end
end
+ return processes, features
end
function otf.otf_to_tfm(specification)
@@ -1841,38 +1263,37 @@ function otf.otf_to_tfm(specification)
local features = specification.features.normal
local cache_id = specification.hash
local tfmdata = containers.read(tfm.cache(),cache_id)
+--~ print(cache_id)
if not tfmdata then
local otfdata = otf.load(filename,format,sub,features and features.featurefile)
if not table.is_empty(otfdata) then
- otf.add_dimensions(otfdata)
- if true then
- otfdata._shared_ = otfdata._shared_ or { -- aggressive sharing
- processes = { },
- lookuptable = { },
- featuredata = { },
- featurecache = { },
- }
- end
- tfmdata = otf.copy_to_tfm(otfdata)
+ otfdata.shared = otfdata.shared or {
+ featuredata = { },
+ anchorhash = { },
+ initialized = false,
+ }
+ tfmdata = otf.copy_to_tfm(otfdata,cache_id)
if not table.is_empty(tfmdata) then
tfmdata.unique = tfmdata.unique or { }
tfmdata.shared = tfmdata.shared or { } -- combine
local shared = tfmdata.shared
shared.otfdata = otfdata
- shared.features = features
- shared.processors = { }
+ shared.features = features -- default
shared.dynamics = { }
shared.processes = { }
- shared.lookuptable = { }
- shared.featuredata = { }
- shared.featurecache = { }
- if otfdata._shared_ then
- shared.processes = otfdata._shared_.processes
- shared.lookuptable = otfdata._shared_.lookuptable
- shared.featuredata = otfdata._shared_.featuredata
- shared.featurecache = otfdata._shared_.featurecache
- end
- otf.set_features(tfmdata)
+ shared.set_dynamics = otf.set_dynamics -- fast access and makes other modules independent
+ -- this will be done later anyway, but it's convenient to have
+ -- them already for fast access
+ tfmdata.luatex = otfdata.luatex
+ tfmdata.indices = otfdata.luatex.indices
+ tfmdata.unicodes = otfdata.luatex.unicodes
+ tfmdata.marks = otfdata.luatex.marks
+ tfmdata.originals = otfdata.luatex.originals
+ tfmdata.changed = { }
+ tfmdata.has_italic = otfdata.metadata.has_italic
+ if not tfmdata.language then tfmdata.language = 'dflt' end
+ if not tfmdata.script then tfmdata.script = 'dflt' end
+ shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
end
end
containers.write(tfm.cache(),cache_id,tfmdata)
@@ -1880,108 +1301,106 @@ function otf.otf_to_tfm(specification)
return tfmdata
end
-function otf.features.prepare_base_kerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
- if value then
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local unicodes = otfdata.luatex.unicodes -- names to unicodes
- local somevalid = otf.some_valid_feature(otfdata,kind,tfmdata.script,tfmdata.language)
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- for u, chr in pairs(characters) do
- -- hm, maybe just use descriptions, and why still index? font is already in
- -- unicode with private slots, so: d = glyphs[u] should work ok
- local d = glyphs[descriptions[u].index]
- if d then
- local dk = d.mykerns
- if dk then
- local t, done = chr.kerns or { }, false
- for lookup,kerns in pairs(dk) do
- if somevalid[lookup] then
- for k, v in pairs(kerns) do
- if v ~= 0 then
- t[k], done = v, true
+--~ {
+--~ ['boundingbox']={ 95, -458, 733, 1449 },
+--~ ['class']="base",
+--~ ['name']="braceleft",
+--~ ['unicode']=123,
+--~ ['vert_variants']={
+--~ ['italic_correction']=0,
+--~ ['parts']={
+--~ { ['component']="uni23A9", ['endConnectorLength']=1000, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=0, }, -- bot
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A8", ['endConnectorLength']=1000, ['fullAdvance']=4688, ['is_extender']=0, ['startConnectorLength']=1000, }, -- mid
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A7", ['endConnectorLength']=0, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=1000, }, -- top
+--~ },
+--~ ['variants']="braceleft braceleft.vsize1 braceleft.vsize2 braceleft.vsize3 braceleft.vsize4 braceleft.vsize5 braceleft.vsize6 braceleft.vsize7",
+--~ },
+--~ ['width']=793,
+--~ },
+
+-- the first version made a top/mid/not extensible table, now we just pass on the variants data
+-- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
+
+-- we cannot share descriptions as virtual fonts might extend them (ok, we could
+-- use a cache with a hash
+
+function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
+ if data then
+ local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
+ local luatex = data.luatex
+ local unicodes = luatex.unicodes -- names to unicodes
+ local indices = luatex.indices
+ local characters, parameters, math_parameters, descriptions = { }, { }, { }, { }
+ local tfm = {
+ characters = characters,
+ parameters = parameters,
+ math_parameters = math_parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ }
+ -- indices maps from unicodes to indices
+ for u, i in next, indices do
+ characters[u] = { } -- we need this because for instance we add protruding info
+ descriptions[u] = glyphs[i]
+ end
+ -- math
+ if metadata.math then
+ -- parameters
+ for name, value in next, metadata.math do
+ math_parameters[name] = value
+ end
+ -- we could use a subset
+ for u, char in next, characters do
+ local d = descriptions[u]
+ local m = d.math
+ -- we have them shared because that packs nicer
+ -- we could prepare the variants and keep 'm in descriptions
+ if m then
+ local variants = m.horiz_variants
+ if variants then
+ local c = char
+ for n in variants:gmatch("[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
+ end
+ end
+ c.horiz_variants = m.horiz_parts
+ else
+ local variants = m.vert_variants
+ if variants then
+ local c = char
+ for n in variants:gmatch("[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
end
end
+ c.vert_variants = m.vert_parts
end
end
- if done then
- chr.kerns = t -- no empty assignments
- end
- else
- dk = d.kerns
- if dk then
- local t, done = chr.kerns or { }, false
- for _, v in pairs(dk) do
- if somevalid[v.lookup] then
- local k = unicodes[v.char]
- local o = v.off
- if type(k) == "number" then
- if k > 0 then
- t[k], done = o, true
- end
- else
- for i=1,#k do
- local ki = k[i]
- if ki > 0 then
- t[ki], done = o, true
- end
- end
- end
- end
- end
- if done then
- chr.kerns = t -- no empty assignments
- end
+ local kerns = m.kerns
+ if kerns then
+ char.mathkerns = kerns
end
end
end
end
- end
-end
-
-function otf.add_dimensions(data)
- if data then
- local force = otf.notdef
- for k, d in pairs(data.glyphs) do
- local bb, wd = d.boundingbox, d.width or 0
- if force and not d.name then
- d.name = ".notdef"
- end
- if wd ~= 0 and d.class == "mark" then
- d.width = -wd
- end
- if bb then
- local ht, dp = bb[4], -bb[2]
- if ht ~= 0 then d.height = ht end
- if dp ~= 0 then d.depth = dp end
- end
- d.index = k
- end
- end
-end
-
-function otf.copy_to_tfm(data) -- we can save a copy when we reorder the tma to unicode
- if data then
- local characters, parameters, descriptions = { }, { }, { }
- local tfm = { characters = characters, parameters = parameters, descriptions = descriptions }
- local luatex = data.luatex
- local indices = luatex.indices -- unicodes to indices
- local glyphs = data.glyphs
- for u, i in pairs(indices) do
- local d = glyphs[i]
- characters[u] = { } -- not needed
- descriptions[u] = d
- end
- local designsize = data.designsize or data.design_size or 100
+ -- end math
+ local designsize = metadata.designsize or metadata.design_size or 100
if designsize == 0 then
designsize = 100
end
local spaceunits = 500
- tfm.units = data.units_per_em or 1000
+ tfm.units = metadata.units_per_em or 1000
-- we need a runtime lookup because of running from cdrom or zip, brrr
- tfm.filename = input.findbinfile(data.luatex.filename,"") or data.luatex.filename
- tfm.fullname = data.fontname or data.fullname
+ tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename
+ tfm.fullname = metadata.fontname or metadata.fullname
tfm.encodingbytes = 2
tfm.cidinfo = data.cidinfo
tfm.cidinfo.registry = tfm.cidinfo.registry or ""
@@ -1993,21 +1412,16 @@ function otf.copy_to_tfm(data) -- we can save a copy when we reorder the tma to
tfm.boundarychar = 65536
tfm.designsize = (designsize/10)*65536
tfm.spacer = "500 units"
- data.isfixedpitch = data.pfminfo and data.pfminfo.panose and data.pfminfo.panose["proportion"] == "Monospaced"
- data.charwidth = nil
- if data.pfminfo then
- data.charwidth = data.pfminfo.avgwidth
- end
local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
- if data.isfixedpitch then
+ if metadata.isfixedpitch then
if descriptions[endash] then
spaceunits, tfm.spacer = descriptions[endash].width, "space"
end
if not spaceunits and descriptions[emdash] then
spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
end
- if not spaceunits and data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth"
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
end
else
if descriptions[endash] then
@@ -2016,36 +1430,37 @@ function otf.copy_to_tfm(data) -- we can save a copy when we reorder the tma to
if not spaceunits and descriptions[emdash] then
spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
end
- if not spaceunits and data.charwidth then
- spaceunits, tfm.spacer = data.charwidth, "charwidth"
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
end
end
spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr
parameters.slant = 0
- parameters.space = spaceunits
- parameters.space_stretch = tfm.units/2 -- 500
- parameters.space_shrink = 2*tfm.units/3 -- 333
- parameters.x_height = 4*tfm.units/5 -- 400
+ parameters.space = spaceunits -- 3.333 (cmr10)
+ parameters.space_stretch = tfm.units/2 -- 500 -- 1.666 (cmr10)
+ parameters.space_shrink = 1*tfm.units/3 -- 333 -- 1.111 (cmr10)
+ parameters.x_height = 2*tfm.units/5 -- 400
parameters.quad = tfm.units -- 1000
- parameters.extra_space = 0
if spaceunits < 2*tfm.units/5 then
-- todo: warning
end
- tfm.italicangle = data.italicangle
- tfm.ascender = math.abs(data.ascent or 0)
- tfm.descender = math.abs(data.descent or 0)
- if data.italicangle then -- maybe also in afm _
- parameters.slant = parameters.slant - math.round(math.tan(data.italicangle*math.pi/180))
+ local italicangle = metadata.italicangle
+ tfm.ascender = math.abs(metadata.ascent or 0)
+ tfm.descender = math.abs(metadata.descent or 0)
+ if italicangle then -- maybe also in afm _
+ tfm.italicangle = italicangle
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
end
- if data.isfixedpitch then
+ if metadata.isfixedpitch then
parameters.space_stretch = 0
parameters.space_shrink = 0
elseif otf.syncspace then --
parameters.space_stretch = spaceunits/2
parameters.space_shrink = spaceunits/3
end
- if data.pfminfo and data.pfminfo.os2_xheight and data.pfminfo.os2_xheight > 0 then
- parameters.x_height = data.pfminfo.os2_xheight
+ parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)
+ if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
+ parameters.x_height = pfminfo.os2_xheight
else
local x = 0x78 -- unicodes['x']
if x then
@@ -2062,23 +1477,55 @@ function otf.copy_to_tfm(data) -- we can save a copy when we reorder the tma to
end
end
+otf.features.register('mathsize')
+
function tfm.read_from_open_type(specification)
local tfmtable = otf.otf_to_tfm(specification)
if tfmtable then
+ local otfdata = tfmtable.shared.otfdata
tfmtable.name = specification.name
tfmtable.sub = specification.sub
- tfmtable = tfm.scale(tfmtable, specification.size)
+ local s = specification.size
+ local m = otfdata.metadata.math
+ if m then
+ local f = specification.features
+ if f then
+ local f = f.normal
+ if f and f.mathsize then
+ local mathsize = specification.mathsize or 0
+ if mathsize == 2 then
+ local p = m.ScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ elseif mathsize == 3 then
+ local p = m.ScriptScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ end
+ end
+ end
+ end
+ tfmtable = tfm.scale(tfmtable,s)
-- here we resolve the name; file can be relocated, so this info is not in the cache
- local otfdata = tfmtable.shared.otfdata
local filename = (otfdata and otfdata.luatex and otfdata.luatex.filename) or specification.filename
if not filename then
-- try to locate anyway and set otfdata.luatex.filename
end
if filename then
tfmtable.encodingbytes = 2
- tfmtable.filename = input.findbinfile(filename,"") or filename
- tfmtable.fullname = otfdata.fontname or otfdata.fullname
- local order = otfdata and otfdata.order2
+ tfmtable.filename = resolvers.findbinfile(filename,"") or filename
+ tfmtable.fullname = otfdata.metadata.fontname or otfdata.metadata.fullname
+ local order = otfdata and otfdata.metadata.order2
if order == 0 then
tfmtable.format = 'opentype'
elseif order == 1 then
@@ -2092,3295 +1539,3 @@ function tfm.read_from_open_type(specification)
end
return tfmtable
end
-
-function otf.analyze_only(otfdata)
- local analyze = otf.analyze_features
- return analyze(otfdata.gpos), analyze(otfdata.gsub)
-end
-
-local a_to_script = { }
-local a_to_language = { }
-
-do
-
- local context_setups = fonts.define.specify.context_setups
- local context_numbers = fonts.define.specify.context_numbers
-
- function otf.set_dynamics(tfmdata,attribute,features) --currently experimental and slow / hackery
- local shared = tfmdata.shared
- if shared then
- local dynamics = shared.dynamics
- if dynamics then
- features = features or context_setups[context_numbers[attribute]]
- if features then
- local script = features.script or 'dflt'
- local language = features.language or 'dflt'
- local ds = dynamics[script]
- if not ds then
- ds = { }
- dynamics[script] = ds
- end
- local dsl = ds[language]
- if not dsl then
- dsl = { }
- ds[language] = dsl
- end
- local dsla = dsl[attribute]
- if dsla then
- return dsla
- else
- a_to_script [attribute] = script
- a_to_language[attribute] = language
- dsla = { }
- local otfdata = shared.otfdata
- local methods = fonts.methods.node.otf
- local initializers = fonts.initializers.node.otf
- local gposfeatures, gsubfeatures = otf.analyze_only(otfdata,features)
- local default = otf.features.default
- local function register(list)
- if list then
- for i=1,#list do
- local f = list[i]
- local value = features[f] or default[f]
- if value then
- local i, m = initializers[f], methods[f]
- if i then
- i(tfmdata,value)
- end
- if m then
- dsla[#dsla+1] = m
- end
- end
- end
- end
- end
- register(fonts.triggers)
- register(gsubfeatures)
- register(gposfeatures)
- dynamics[script][language][attribute] = dsla
- return dsla
- end
- end
- end
- end
- return { } -- todo: false
- end
-
-end
-
--- scripts
-
-otf.default_language = 'latn'
-otf.default_script = 'dflt'
-
-function otf.valid_feature(otfdata,kind,script,language) -- return hash is faster
- local luatex = otfdata.luatex
- if luatex.ctx_always[kind] then
- script, language = 'dflt', 'dflt'
- else
- script = script or otf.default_script
- language = language or otf.default_language
- end
- script, language = script:lower(), language:lower() -- will go away, we will lowercase values
- local ft = luatex.subtables[kind]
- local st = ft[script] or ft.dflt
- local lt = st and (st[language] or st.dflt)
- return false, luatex.always_valid, lt.valid
-end
-
-function otf.some_valid_feature(otfdata,kind,script,language)
- local luatex = otfdata.luatex
- if luatex.ctx_always[kind] then
- script, language = 'dflt', 'dflt'
- else
- script = script or otf.default_script
- language = language or otf.default_language
- script, language = script:lower(), language:lower() -- will go away, we will lowercase values
- end
- local t = luatex.subtables[kind]
- if t then
- local ts = t[script] or t.dflt
- if ts then
- local tsl = ts[language] or ts.dflt
- return (tsl and tsl.valid) or { }
- end
- end
- return { }
-end
-
-function otf.features.aux.resolve_ligatures(tfmdata,ligatures,kind)
- local otfdata = tfmdata.shared.otfdata
- local unicodes = otfdata.luatex.unicodes
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local changed = tfmdata.changed or { }
- local done = { }
- kind = kind or "unknown"
- local trace = otf.trace_features
- while true do
- local ok = false
- for k,v in pairs(ligatures) do
- local lig = v[1]
- if not done[lig] then
- local ligs = split_at_space:match(lig)
- if #ligs == 2 then
- local uc = v[2]
- local c, f, s = characters[uc], ligs[1], ligs[2]
---~ local uf, us = unicodes[f], unicodes[s]
-
-local uft, ust = unicodes[f], unicodes[s]
-if not uft or not ust then
- logs.report("define otf","%s: unicode problem with ligature (%s->%s=%s->%s+%s->%s)",kind,descriptions[uc].name or "?",uc,f,uft or "?",s,ust or "?")
- -- some kind of error
-else
- if type(uft) == "number" then uft = { uft } end
- if type(ust) == "number" then ust = { ust } end
- for ufi=1,#uft do
- local uf = uft[ufi]
- for usi=1,#ust do
- local us = ust[usi]
-
- if changed[uf] or changed[us] then
- if trace then
- logs.report("define otf","%s: %s (%s) + %s (%s) ignored",kind,f,uf,s,us)
- end
- else
- local first, second = characters[uf], us
- if first and second then
- local t = first.ligatures
- if not t then
- t = { }
- first.ligatures = t
- end
- local uuc = unicodes[descriptions[uc].name]
- if type(uuc) == "number" then
- t[second] = { type = 0, char = uuc }
- else
- t[second] = { type = 0, char = uuc[1] }
- end
- if trace then
- logs.report("define otf","%s: %s (%s) + %s (%s) = %s (%s)",kind,f,uf,s,us,descriptions[uc].name,unicodes[descriptions[uc].name])
- end
- end
- end
-
- end
- end
-end
-
- ok, done[lig] = true, descriptions[uc].name
- end
- end
- end
- if ok then
- for d,n in pairs(done) do
- local pattern = "^(" .. d .. ") "
- for k,v in pairs(ligatures) do
- v[1] = v[1]:gsub(pattern, function(str)
- return n .. " "
- end)
- end
- end
- else
- break
- end
- end
-end
-
-function otf.features.prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
- if value then
- local ligatures = { }
- local otfdata = tfmdata.shared.otfdata
- local unicodes = otfdata.luatex.unicodes
- local trace = otf.trace_features
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local somevalid = otf.some_valid_feature(otfdata,kind,tfmdata.script,tfmdata.language)
- if not table.is_empty(somevalid) then
- tfmdata.changed = tfmdata.changed or { }
- local changed = tfmdata.changed
- local glyphs = otfdata.glyphs
- for k,c in pairs(characters) do
- local o = glyphs[descriptions[k].index]
- if o and o.lookups then
- for lookup,ps in pairs(o.lookups) do
- if somevalid[lookup] then
- for i=1,#ps do
- local p = ps[i]
- local t = p[1]
- if t == 'substitution' then
- local pv = p[2] -- p.variant
- if pv then
- local upv = unicodes[pv]
- if upv then
- if type(upv) == "number" then
- if characters[upv] then
- if trace then
- logs.report("define otf","%s: %s (%s) => %s (%s)",kind,descriptions[k].name,k,descriptions[upv].name,upv)
- end
- characters[k] = characters[upv]
- descriptions[k] = descriptions[upv]
- changed[k] = true
- end
- else
- for i=1,#upv do
- local upv = upv[i]
- if characters[upv] then
- if trace then
- logs.report("define otf","%s: %s (%s) => %s (%s)",kind,descriptions[k].name,k,descriptions[upv].name,upv)
- end
- characters[k] = characters[upv]
- descriptions[k] = descriptions[upv]
- changed[k] = true
- end
- end
- end
- end
- end
- elseif t == 'alternate' then
- local pc = p[2] -- p.components
- if pc then
- pc = pa.components:match("([^ ]+)") -- todo: selector
- if pc then
- local upc = unicodes[pc]
- if upc then
- if type(upc) == "number" then
- if chars[upc] then
- if trace then
- logs.report("define otf","%s: %s (%s) => %s (%s)",kind,descriptions[k].name,k,descriptions[upc].name,upc)
- end
- characters[k] = characters[upc]
- descriptions[k] = descriptions[upc]
- changed[k] = true
- end
- else
- for i=1,#upc do
- local upc = upc[i]
- if chars[upc] then
- if trace then
- logs.report("define otf","%s: %s (%s) => %s (%s)",kind,descriptions[k].name,k,descriptions[upc].name,upc)
- end
- characters[k] = characters[upc]
- descriptions[k] = descriptions[upc]
- changed[k] = true
- end
- end
- end
- end
- end
- end
- elseif t == 'ligature' and not changed[k] then
- local pc = p[2]
- if pc then
- if trace then
- logs.report("define otf","%s: %s => %s (%s)",kind,pc,descriptions[k].name,k)
- end
- ligatures[#ligatures+1] = { pc, k }
- end
- end
- end
- end
- end
- end
- end
- otf.features.aux.resolve_ligatures(tfmdata,ligatures,kind)
- end
- else
- tfmdata.ligatures = tfmdata.ligatures or { }
- end
-end
-
-function fonts.initializers.base.otf.liga(tfm,value) otf.features.prepare_base_substitutions(tfm,'liga',value) end
-function fonts.initializers.base.otf.dlig(tfm,value) otf.features.prepare_base_substitutions(tfm,'dlig',value) end
-function fonts.initializers.base.otf.rlig(tfm,value) otf.features.prepare_base_substitutions(tfm,'rlig',value) end
-function fonts.initializers.base.otf.hlig(tfm,value) otf.features.prepare_base_substitutions(tfm,'hlig',value) end
-function fonts.initializers.base.otf.pnum(tfm,value) otf.features.prepare_base_substitutions(tfm,'pnum',value) end
-function fonts.initializers.base.otf.onum(tfm,value) otf.features.prepare_base_substitutions(tfm,'onum',value) end
-function fonts.initializers.base.otf.tnum(tfm,value) otf.features.prepare_base_substitutions(tfm,'tnum',value) end
-function fonts.initializers.base.otf.lnum(tfm,value) otf.features.prepare_base_substitutions(tfm,'lnum',value) end
-function fonts.initializers.base.otf.zero(tfm,value) otf.features.prepare_base_substitutions(tfm,'zero',value) end
-function fonts.initializers.base.otf.smcp(tfm,value) otf.features.prepare_base_substitutions(tfm,'smcp',value) end
-function fonts.initializers.base.otf.cpsp(tfm,value) otf.features.prepare_base_substitutions(tfm,'cpsp',value) end
-function fonts.initializers.base.otf.c2sc(tfm,value) otf.features.prepare_base_substitutions(tfm,'c2sc',value) end
-function fonts.initializers.base.otf.ornm(tfm,value) otf.features.prepare_base_substitutions(tfm,'ornm',value) end
-function fonts.initializers.base.otf.aalt(tfm,value) otf.features.prepare_base_substitutions(tfm,'aalt',value) end
-
-function fonts.initializers.base.otf.hwid(tfm,value) otf.features.prepare_base_substitutions(tfm,'hwid',value) end
-function fonts.initializers.base.otf.fwid(tfm,value) otf.features.prepare_base_substitutions(tfm,'fwid',value) end
-
--- Here comes the real thing ... node processing! The next session prepares
--- things. The main features (unchained by rules) have their own caches,
--- while the private ones cache locally.
-
-do
-
- otf.features.prepare = { }
-
- local falsetable = { false, false, false }
-
- function otf.features.prepare.feature(tfmdata,kind,value)
- if value then
- local language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
- local shared = tfmdata.shared
- local otfdata = shared.otfdata
- local lookuptable = otf.valid_subtable(otfdata,kind,script,language)
- if lookuptable then
- local fullkind = kind .. script .. language
- if not shared.lookuptable [fullkind] then
- --~ print(tfmdata,file.basename(tfmdata.fullname or ""),kind,script,language,lookuptable,fullkind)
- local processes = { }
- -- featuredata and featurecache are indexed by lookup so we can share them
- shared.featuredata [kind] = shared.featuredata [kind] or { }
- shared.featurecache[kind] = shared.featurecache[kind] or false -- signal
- shared.lookuptable [fullkind] = lookuptable
- shared.processes [fullkind] = processes
- local luatex = otfdata.luatex
- local types = luatex.name_to_type
- local flags = luatex.ignore_flags
- local preparers = otf.features.prepare
- local process = otf.features.process
- for i=1,#lookuptable do
- local lookupname = lookuptable[i]
- local lookuptype = types[lookupname]
- local prepare = preparers[lookuptype]
- if prepare then
- local processdata = prepare(tfmdata,kind,lookupname)
- if processdata then
- local processflags = flags[lookupname] or falsetable --- share false table
- -- local chain = (lookuptype == "gsub_contextchain") or (lookuptype == "gpos_contextchain")
- local chain = lookuptype:find("context") ~= nil
- processes[#processes+1] = { process[lookuptype], lookupname, processdata, processflags, chain }
- end
- end
- end
- end
- end
- end
- end
-
- -- helper: todo, we don't need to store non local ones for chains so we can pass the
- -- validator as parameter
-
- function otf.features.collect_ligatures(tfmdata,kind) -- ligs are spread all over the place
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes -- names to unicode
- local indices = luatex.indices -- unicode to index
- local trace = otf.trace_features
- local ligatures = { }
- local function collect(lookup,unicode,glyph,ps)
- for i=1,#ps do
- local p = ps[i]
- if p[1] == 'ligature' then
- if trace then
- logs.report("define otf","feature %s lookup %s ligature %s => %s",kind,lookup,p[2],glyph.name)
- end
- local t = ligatures[lookup]
- if not t then
- t = { }
- ligatures[lookup] = t
- end
- -- this table is kind of special:
- -- unicode -> tree of names/indices -> unicode
- -- this way we can handle multiple unicode to one glyph cases
- local first = true
- for s in p[2]:gmatch("[^ ]+") do
- if first then
- local u = unicodes[s]
- if not u then
- logs.report("define otf","feature %s lookup %s ligature %s => %s ignored due to invalid unicode",kind,lookup,p[2],glyph.name)
- elseif type(u) == "number" then
- if not t[u] then
- t[u] = { { } }
- end
- t = t[u]
- else
- local tt = t
- local tu
- for i=1,#u do
- local u = u[i]
- if i==1 then
- if not t[u] then
- t[u] = { { } }
- end
- tu = t[u]
- t = tu
- else
- if not t[u] then
- tt[u] = tu
- end
- end
- end
- end
- first = false
- else
- -- beware, we mix unicodes and indices, we can comment these
- -- lines when testing, see (*lig*)
- s = unicodes[s]
- if type(s) == "number" then
- s = indices[s]
- else
- s = indices[s[1]]
- end
- -- maybe we will introduce a names table some day
- local t1 = t[1]
- if not t1[s] then
- t1[s] = { { } }
- end
- t = t1[s]
- end
- end
- t[2] = unicode
- end
- end
- end
- local forced, always, okay = otf.valid_feature(otfdata,kind,tfmdata.script,tfmdata.language)
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local lookups = glyph.lookups
- if lookups then
- if forced then
- for lookup, ps in pairs(lookups) do collect(lookup,unicode,glyph,ps) end
- elseif okay then
- for lookup, ps in pairs(lookups) do if always[lookup] or okay[lookup] then collect(lookup,unicode,glyph,ps) end end
- else
- for lookup, ps in pairs(lookups) do if always[lookup] then collect(lookup,unicode,glyph,ps) end end
- end
- end
- end
- return ligatures
- end
-
- -- gsub_single -> done
- -- gsub_multiple -> done
- -- gsub_alternate -> done
- -- gsub_ligature -> done
- -- gsub_context -> todo
- -- gsub_contextchain -> done
- -- gsub_reversecontextchain -> todo
-
- -- we used to share code in the following functions but that was relatively
- -- due to extensive calls to functions (easily hundreds of thousands per
- -- document)
-
- function otf.features.prepare.gsub_single(tfmdata,kind,lookupname)
- local featuredata = tfmdata.shared.featuredata[kind]
- local substitutions = featuredata[lookupname]
- if not substitutions then
- substitutions = { }
- featuredata[lookupname] = substitutions
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes -- names to unicode
- local indices = luatex.indices -- unicode to index
- local trace = otf.trace_features
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local lookups = glyph.lookups
- if lookups then
- for lookup,ps in pairs(lookups) do
- if lookup == lookupname then
- for i=1,#ps do
- local p = ps[i]
- if p[1] == 'substitution' then
- local old, new = unicode, unicodes[p[2]]
- if type(new) == "table" then
- new = new[1]
- end
- substitutions[old] = new
- if trace then
- logs.report("define otf","%s:%s substitution %s => %s",kind,lookupname,old,new)
- end
- end
- end
- end
- end
- end
- end
- end
- return substitutions
- end
-
- function otf.features.prepare.gsub_multiple(tfmdata,kind,lookupname)
- local featuredata = tfmdata.shared.featuredata[kind]
- local substitutions = featuredata[lookupname]
- if not substitutions then
- substitutions = { }
- featuredata[lookupname] = substitutions
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes -- names to unicode
- local indices = luatex.indices -- unicode to index
- local trace = otf.trace_features
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local lookups = glyph.lookups
- if lookups then
- for lookup,ps in pairs(lookups) do
- if lookup == lookupname then
- for i=1,#ps do
- local p = ps[i]
- if p[1] == 'multiple' then
- local old, new = unicode, { }
- substitutions[old] = new
- for pc in p[2]:gmatch("[^ ]+") do
- local upc = unicodes[pc]
- if type(upc) == "number" then
- new[#new+1] = upc
- else
- new[#new+1] = upc[1]
- end
- end
- if trace then
- logs.report("define otf","%s:%s multiple %s => %s",kind,lookupname,old,concat(new," "))
- end
- end
- end
- end
- end
- end
- end
- end
- return substitutions
- end
-
- function otf.features.prepare.gsub_alternate(tfmdata,kind,lookupname)
- -- todo: configurable preference list
- local featuredata = tfmdata.shared.featuredata[kind]
- local substitutions = featuredata[lookupname]
- if not substitutions then
- featuredata[lookupname] = { }
- substitutions = featuredata[lookupname]
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes -- names to unicode
- local indices = luatex.indices -- unicode to index
- local trace = otf.trace_features
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local lookups = glyph.lookups
- if lookups then
- for lookup,ps in pairs(lookups) do
- if lookup == lookupname then
- for i=1,#ps do
- local p = ps[i]
- if p[1] == 'alternate' then
- local old = unicode
- local t = { }
- for pc in p[2]:gmatch("[^ ]+") do
- local upc = unicodes[pc]
- if type(upc) == "number" then
- t[#t+1] = upc
- else
- t[#t+1] = upc[1]
- end
- end
- substitutions[old] = t
- if trace then
- logs.report("define otf","%s:%s alternate %s => %s",kind,lookupname,old,concat(substitutions,"|"))
- end
- end
- end
- end
- end
- end
- end
- end
- return substitutions
- end
-
- function otf.features.prepare.gsub_ligature(tfmdata,kind,lookupname)
- -- we collect them for all lookups, this saves loops, we only use the
- -- lookupname for testing, we need to check if this leads to redundant
- -- collections
- local ligatures = tfmdata.shared.featuredata[kind]
- if not ligatures[lookupname] then
- ligatures = otf.features.collect_ligatures(tfmdata,kind)
- tfmdata.shared.featuredata[kind] = ligatures
- end
- return ligatures[lookupname]
- end
-
- function otf.features.prepare.contextchain(tfmdata,kind,lookupname)
- local featuredata = tfmdata.shared.featuredata[kind]
- local contexts = featuredata[lookupname]
- if not contexts then
- contexts = { }
- featuredata[lookupname] = contexts
- local characters = tfmdata.characters
- local otfdata = tfmdata.shared.otfdata
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes
- local internals = luatex.internals
- local flags = luatex.ignore_flags
- local types = luatex.name_to_type
- local cache = luatex.covers
- if not cache then
- cache = { }
- luatex.covers = cache
- end
- local function uncover(covers,result)
- -- lpeg hardly faster (.005 sec on mk)
- for n=1,#covers do
- local c = covers[n]
- local cc = cache[c]
- if not cc then
- local t = { }
- for s in c:gmatch("[^ ]+") do
- local us = unicodes[s]
- if type(us) == "number" then
- t[us] = true
- else
- for i=1,#us do
- t[us[i]] = true
- end
- end
- end
- cache[c] = t
- result[#result+1] = t
- else
- result[#result+1] = cc
- end
- end
- end
- local lookupdata = otfdata.lookups[lookupname]
- if not lookupdata then
- logs.report("otf process","missing lookupdata table %s",lookupname)
- elseif lookupdata.rules then
- local rules = lookupdata.rules
- local center_match = otf.center_match
- for nofrules=1,#rules do
- local rule = rules[nofrules]
- local coverage = rule.coverage
- if coverage and coverage.current then
- local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
- if before then
- uncover(before,sequence)
- end
- local start = #sequence + 1
- uncover(current,sequence)
- local stop = #sequence
- if after then
- uncover(after,sequence)
- end
- if sequence[1] then
- local lookups, lookuptype = rule.lookups, 'self'
- -- for the moment only lookup index 1
- if lookups then
- if #lookups > 1 then
- logs.report("otf process","WARNING: more than one lookup in rule")
- end
- lookuptype = types[lookups[1]]
- end
- -- this may be wrong; we cannot copy inside the for loop (out of memory with hz);
- -- so we may end up with a different usage of sequence in the chainproc handlers
- sequence = table.copy(sequence)
- -- we trigger on the first character in current
- for unic, _ in pairs(sequence[start]) do
- local t = contexts[unic]
- if not t then
- contexts[unic] = { lookups={}, flags=flags[lookupname] }
- t = contexts[unic].lookups
- end
- t[#t+1] = { nofrules, lookuptype, sequence, start, stop, lookups }
- end
- end
- end
- end
- end
- end
- return contexts
- end
-
- otf.features.prepare.gsub_context = otf.features.prepare.contextchain
- otf.features.prepare.gsub_contextchain = otf.features.prepare.contextchain
- otf.features.prepare.gsub_reversecontextchain = otf.features.prepare.contextchain
-
- -- ruled->lookup=ks_latn_l_27_c_4 => internal[ls_l_84] => valid[ls_l_84_s]
-
- -- gpos_mark2base -> done
- -- gpos_mark2ligature -> done
- -- gpos_mark2mark -> done
- -- gpos_single -> not done
- -- gpos_pair -> not done
- -- gpos_cursive -> not done
- -- gpos_context -> not done
- -- gpos_reversecontextchain -> not done
-
- function otf.features.prepare.anchors(tfmdata,kind,lookupname) -- tracing
- local featuredata = tfmdata.shared.featuredata[kind]
- local anchors = featuredata[lookupname]
- if not anchors then
- anchors = { }
- featuredata[lookupname] = anchors
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes
- local indices = luatex.indices
- local validanchors = { }
- local trace = otf.trace_features
- local classes = otfdata.anchor_classes
- if classes then
- for k=1,#classes do
- local class = classes[k]
- if class.lookup == lookupname then
- if trace then
- logs.report("define otf","%s:%s anchor -> %s",kind,lookupname,class.name)
- end
- validanchors[class.name] = true
- end
- end
- end
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local oanchor = glyph.anchors
- if oanchor then
- local t, ok = { }, false
- for type, anchors in pairs(oanchor) do -- types
- local tt = false
- for name, anchor in pairs(anchors) do
- if validanchors[name] then
- if not tt then
- tt = { [name] = anchor }
- t[type] = tt
- ok = true
- else
- tt[name] = anchor
- end
- end
- end
- end
- if ok then
- anchors[unicode] = t
- end
- end
- end
- end
---~ if kind == "mkmk" then print(lookupname,table.serialize(anchors)) end
- return anchors
- end
-
- otf.features.prepare.gpos_mark2base = otf.features.prepare.anchors
- otf.features.prepare.gpos_mark2ligature = otf.features.prepare.anchors
- otf.features.prepare.gpos_mark2mark = otf.features.prepare.anchors
- otf.features.prepare.gpos_cursive = otf.features.prepare.anchors
- otf.features.prepare.gpos_context = otf.features.prepare.contextchain
- otf.features.prepare.gpos_contextchain = otf.features.prepare.contextchain
-
- function otf.features.prepare.gpos_single(tfmdata,kind,lookupname)
- logs.report("otf define","gpos_single not yet supported")
- end
-
- -- ["kerns"]={ { ["char"]="ytilde", ["lookup"]="pp_l_1_s", ["off"]=-83, ...
- -- ["mykerns"] = { ["pp_l_1_s"] = { [67] = -28, ...
-
- function otf.features.prepare.gpos_pair(tfmdata,kind,lookupname)
- local featuredata = tfmdata.shared.featuredata[kind]
- local kerns = featuredata[lookupname]
- if not kerns then
- local trace = otf.trace_features
- featuredata[lookupname] = { }
- kerns = featuredata[lookupname]
- local otfdata = tfmdata.shared.otfdata
- local glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- local unicodes = luatex.unicodes
- local indices = luatex.indices
- -- ff has isolated kerns in a separate table
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local list = glyph.mykerns
- if list then
- local omk = list[lookupname]
- if omk then
- local krn = kerns[unicode]
- for other, off in pairs(omk) do
- if not krn then
- krn = { }
- kerns[unicode] = krn
- end
- krn[other] = off
- if trace then
- logs.report("define otf","feature %s kern pair %s - %s",kind,unicode,other)
- end
- end
- end
- else
- list = glyph.kerns
- if list then
- local krn
- for ok=1,#list do
- local k = list[ok]
- if k.lookup == lookupname then
- local char = k.char
- if char then
- if not krn then
- krn = kerns[unicode]
- if not krn then
- krn = { }
- kerns[unicode] = krn
- end
- end
- local second = unicodes[char]
- local off = k.off
- if type(second) == "number" then
- krn[second] = off
- if trace then
- logs.report("define otf","feature %s kern pair %s - %s",kind,unicode,second)
- end
- else
- for i=1,#second do
- local second = second[i]
- krn[second] = off
- if trace then
- logs.report("define otf","feature %s kern pair %s - %s",kind,unicode,second)
- end
- end
- end
- end
- end
- end
- end
- end
- list = glyphs.lookups
- if list then
- for lookup,ps in pairs(list) do
- if lookup == lookupname then
- local krn
- for i=1,#ps do
- local p = ps[i]
- if p[1] == 'pair' then
- if not krn then
- krn = kerns[unicode]
- if not krn then
- krn = { }
- kerns[unicode] = krn
- end
- end
- local second = unicodes[p[2]]
- if type(second) == "number" then
- krn[second] = p
- if trace then
- logs.report("define otf","feature %s kern pair %s - %s",kind,unicode,second)
- end
- else
- for i=1,#second do
- local second = second[i]
- krn[second] = p
- if trace then
- logs.report("define otf","feature %s kern pair %s - %s",kind,unicode,second)
- end
- end
- end
- end
- end
- end
- end
- end
- end
- end
- return kerns
- end
-
- otf.features.prepare.gpos_contextchain = otf.features.prepare.contextchain
-
-end
-
--- can be generalized: one loop in main
-
-do
-
- local prepare = otf.features.prepare.feature
-
- function fonts.initializers.node.otf.aalt(tfm,value) return prepare(tfm,'aalt',value) end
- function fonts.initializers.node.otf.abvm(tfm,value) return prepare(tfm,'abvm',value) end
- function fonts.initializers.node.otf.afrc(tfm,value) return prepare(tfm,'afrc',value) end
- function fonts.initializers.node.otf.akhn(tfm,value) return prepare(tfm,'akhn',value) end
- function fonts.initializers.node.otf.blwm(tfm,value) return prepare(tfm,'blwm',value) end
- function fonts.initializers.node.otf.c2pc(tfm,value) return prepare(tfm,'c2pc',value) end
- function fonts.initializers.node.otf.c2sc(tfm,value) return prepare(tfm,'c2sc',value) end
- function fonts.initializers.node.otf.calt(tfm,value) return prepare(tfm,'calt',value) end
- function fonts.initializers.node.otf.case(tfm,value) return prepare(tfm,'case',value) end
- function fonts.initializers.node.otf.ccmp(tfm,value) return prepare(tfm,'ccmp',value) end
- function fonts.initializers.node.otf.clig(tfm,value) return prepare(tfm,'clig',value) end
- function fonts.initializers.node.otf.cpsp(tfm,value) return prepare(tfm,'cpsp',value) end
- function fonts.initializers.node.otf.cswh(tfm,value) return prepare(tfm,'cswh',value) end
- function fonts.initializers.node.otf.curs(tfm,value) return prepare(tfm,'curs',value) end
- function fonts.initializers.node.otf.dlig(tfm,value) return prepare(tfm,'dlig',value) end
- function fonts.initializers.node.otf.dnom(tfm,value) return prepare(tfm,'dnom',value) end
- function fonts.initializers.node.otf.expt(tfm,value) return prepare(tfm,'expt',value) end
- function fonts.initializers.node.otf.fin2(tfm,value) return prepare(tfm,'fin2',value) end
- function fonts.initializers.node.otf.fin3(tfm,value) return prepare(tfm,'fin3',value) end
- function fonts.initializers.node.otf.fina(tfm,value) return prepare(tfm,'fina',value) end
- function fonts.initializers.node.otf.frac(tfm,value) return prepare(tfm,'frac',value) end
- function fonts.initializers.node.otf.fwid(tfm,value) return prepare(tfm,'fwid',value) end
- function fonts.initializers.node.otf.haln(tfm,value) return prepare(tfm,'haln',value) end
- function fonts.initializers.node.otf.hist(tfm,value) return prepare(tfm,'hist',value) end
- function fonts.initializers.node.otf.hkna(tfm,value) return prepare(tfm,'hkna',value) end
- function fonts.initializers.node.otf.hlig(tfm,value) return prepare(tfm,'hlig',value) end
- function fonts.initializers.node.otf.hngl(tfm,value) return prepare(tfm,'hngl',value) end
- function fonts.initializers.node.otf.hwid(tfm,value) return prepare(tfm,'hwid',value) end
- function fonts.initializers.node.otf.init(tfm,value) return prepare(tfm,'init',value) end
- function fonts.initializers.node.otf.isol(tfm,value) return prepare(tfm,'isol',value) end
- function fonts.initializers.node.otf.ital(tfm,value) return prepare(tfm,'ital',value) end
- function fonts.initializers.node.otf.jp78(tfm,value) return prepare(tfm,'jp78',value) end
- function fonts.initializers.node.otf.jp83(tfm,value) return prepare(tfm,'jp83',value) end
- function fonts.initializers.node.otf.jp90(tfm,value) return prepare(tfm,'jp90',value) end
- function fonts.initializers.node.otf.kern(tfm,value) return prepare(tfm,'kern',value) end
- function fonts.initializers.node.otf.liga(tfm,value) return prepare(tfm,'liga',value) end
- function fonts.initializers.node.otf.lnum(tfm,value) return prepare(tfm,'lnum',value) end
- function fonts.initializers.node.otf.locl(tfm,value) return prepare(tfm,'locl',value) end
- function fonts.initializers.node.otf.mark(tfm,value) return prepare(tfm,'mark',value) end
- function fonts.initializers.node.otf.med2(tfm,value) return prepare(tfm,'med2',value) end
- function fonts.initializers.node.otf.medi(tfm,value) return prepare(tfm,'medi',value) end
- function fonts.initializers.node.otf.mgrk(tfm,value) return prepare(tfm,'mgrk',value) end
- function fonts.initializers.node.otf.mkmk(tfm,value) return prepare(tfm,'mkmk',value) end
- function fonts.initializers.node.otf.nalt(tfm,value) return prepare(tfm,'nalt',value) end
- function fonts.initializers.node.otf.nlck(tfm,value) return prepare(tfm,'nlck',value) end
- function fonts.initializers.node.otf.nukt(tfm,value) return prepare(tfm,'nukt',value) end
- function fonts.initializers.node.otf.numr(tfm,value) return prepare(tfm,'numr',value) end
- function fonts.initializers.node.otf.onum(tfm,value) return prepare(tfm,'onum',value) end
- function fonts.initializers.node.otf.ordn(tfm,value) return prepare(tfm,'ordn',value) end
- function fonts.initializers.node.otf.ornm(tfm,value) return prepare(tfm,'ornm',value) end
- function fonts.initializers.node.otf.pnum(tfm,value) return prepare(tfm,'pnum',value) end
- function fonts.initializers.node.otf.pref(tfm,value) return prepare(tfm,'pref',value) end
- function fonts.initializers.node.otf.pres(tfm,value) return prepare(tfm,'pres',value) end
- function fonts.initializers.node.otf.pstf(tfm,value) return prepare(tfm,'pstf',value) end
- function fonts.initializers.node.otf.rlig(tfm,value) return prepare(tfm,'rlig',value) end
- function fonts.initializers.node.otf.rphf(tfm,value) return prepare(tfm,'rphf',value) end
- function fonts.initializers.node.otf.rtla(tfm,value) return prepare(tfm,'rtla',value) end
- function fonts.initializers.node.otf.salt(tfm,value) return prepare(tfm,'salt',value) end
- function fonts.initializers.node.otf.sinf(tfm,value) return prepare(tfm,'sinf',value) end
- function fonts.initializers.node.otf.smcp(tfm,value) return prepare(tfm,'smcp',value) end
- function fonts.initializers.node.otf.smpl(tfm,value) return prepare(tfm,'smpl',value) end
- function fonts.initializers.node.otf.ss01(tfm,value) return prepare(tfm,'ss01',value) end
- function fonts.initializers.node.otf.ss02(tfm,value) return prepare(tfm,'ss02',value) end
- function fonts.initializers.node.otf.ss03(tfm,value) return prepare(tfm,'ss03',value) end
- function fonts.initializers.node.otf.ss04(tfm,value) return prepare(tfm,'ss04',value) end
- function fonts.initializers.node.otf.ss05(tfm,value) return prepare(tfm,'ss05',value) end
- function fonts.initializers.node.otf.ss06(tfm,value) return prepare(tfm,'ss06',value) end
- function fonts.initializers.node.otf.ss07(tfm,value) return prepare(tfm,'ss07',value) end
- function fonts.initializers.node.otf.ss08(tfm,value) return prepare(tfm,'ss08',value) end
- function fonts.initializers.node.otf.ss09(tfm,value) return prepare(tfm,'ss09',value) end
- function fonts.initializers.node.otf.subs(tfm,value) return prepare(tfm,'subs',value) end
- function fonts.initializers.node.otf.sups(tfm,value) return prepare(tfm,'sups',value) end
- function fonts.initializers.node.otf.swsh(tfm,value) return prepare(tfm,'swsh',value) end
- function fonts.initializers.node.otf.titl(tfm,value) return prepare(tfm,'titl',value) end
- function fonts.initializers.node.otf.tnam(tfm,value) return prepare(tfm,'tnam',value) end
- function fonts.initializers.node.otf.tnum(tfm,value) return prepare(tfm,'tnum',value) end
- function fonts.initializers.node.otf.trad(tfm,value) return prepare(tfm,'trad',value) end
- function fonts.initializers.node.otf.unic(tfm,value) return prepare(tfm,'unic',value) end
- function fonts.initializers.node.otf.zero(tfm,value) return prepare(tfm,'zero',value) end
-
-end
-
-do
-
- -- todo: use nodes helpers
-
- local glyph = node.id('glyph')
- local glue = node.id('glue')
- local kern = node.id('kern')
- local disc = node.id('disc')
- local whatsit = node.id('whatsit')
-
- local fontdata = tfm.id
- local has_attribute = node.has_attribute
- local set_attribute = node.set_attribute
- local state = attributes.numbers['state'] or 100
- local marknumber = attributes.numbers['mark'] or 200
- local report = logs.report
- local scale = tex.scale
-
- otf.features.process = { }
-
- -- we share some vars here, after all, we have no nested lookups and
- -- less code
-
- local tfmdata = false
- local otfdata = false
- local characters = false
- local descriptions = false
- local marks = false
- local indices = false
- local glyphs = false
- local currentfont = false
- local rlmode = 0
-
- -- we cheat a bit and assume that a font,attr combination are kind of ranged
-
- local context_setups = fonts.define.specify.context_setups
- local context_numbers = fonts.define.specify.context_numbers
-
- -- 1 loop over glyphs loop over lookups, quit at match
- -- 2 loop over glyphs loop over lookups, continue at match
- -- 3 loop over lookups loop over glyphs
-
- otf.strategy = 2
-
- function otf.features.process.feature(head,font,attr,kind,attribute)
- tfmdata = fontdata[font]
- local shared = tfmdata.shared
- otfdata = shared.otfdata
- characters = tfmdata.characters
- descriptions = tfmdata.descriptions
- glyphs = otfdata.glyphs
- local luatex = otfdata.luatex
- marks = luatex.marks
- indices = luatex.indices
- currentfont = font
- rlmode = 0
- local script, language, strategy
- if attr and attr > 0 then
- local features = context_setups[context_numbers[attr]]
- language, script, strategy = features.language or "dflt", features.script or "dflt", features.strategy or otf.strategy
- else
- language, script, strategy = tfmdata.language or "dflt", tfmdata.script or "dflt", tfmdata.strategy or otf.strategy
- end
- local fullkind = kind .. script .. language
- local lookuptable = shared.lookuptable[fullkind]
- if lookuptable then
- -- local strategy = otf.strategy
- local types = otfdata.luatex.name_to_type
- local start, done, ok = head, false, false
- local processes = shared.processes[fullkind]
- if #processes == 1 then
- local p = processes[1]
- while start do -- evt splitsen
- local id = start.id
- if id == glyph then
- if start.subtype<256 and start.font == font and
- (not attr or has_attribute(start,0,attr)) and -- dynamic feature
- (not attribute or has_attribute(start,state,attribute)) then
- -- we can make the p vars also global to this closure
- local pp = p[3] -- all lookups
- local pc = pp[start.char]
- if pc then
- start, ok = p[1](start,kind,p[2],pc,pp,p[4])
- done = done or ok
- if start then start = start.next end
- else
- start = start.next
- end
- else
- start = start.next
- end
- elseif id == glue and p[5] then
- local pp = p[3] -- all lookups
- local pc = pp[32] -- space, todo: more generic spacing
- if pc then
- start, ok = p[1](start,kind,p[2],pc,pp,p[4])
- done = done or ok
- if start then start = start.next end
- else
- start = start.next
- end
- elseif id == whatsit then
- local subtype = start.subtype
- if subtype == 7 then
- local dir = start.dir
- if dir == "+TRT" then
- rlmode = -1
- elseif dir == "+TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- elseif subtype == 6 then
- local dir = start.dir
- if dir == "TRT" then
- rlmode = -1
- elseif dir == "TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- end
- start = start.next
- else
- start = start.next
- end
- end
- elseif strategy == 3 then
- for i=1,#processes do local p = processes[i]
- local pp = p[3]
- start = head
- while start do
- local id = start.id
- if id == glyph then
- if start.subtype<256 and start.font == font and
- (not attr or has_attribute(start,0,attr)) and -- dynamic feature
- (not attribute or has_attribute(start,state,attribute)) then
- local pc = pp[start.char]
- if pc then
- start, ok = p[1](start,kind,p[2],pc,pp,p[4])
- if ok then
- done = true
- end -- else
- if start then start = start.next end
- else
- start = start.next
- end
- else
- start = start.next
- end
- elseif id == glue then
- if p[5] then -- chain
- local pc = pp[32]
- if pc then
- start, ok = p[1](start,kind,p[2],pc,p[3],p[4])
- if ok then
- done = true
- end
- if start then start = start.next end
- else
- start = start.next
- end
- else
- start = start.next
- end
- elseif id == whatsit then
- local subtype = start.subtype
- if subtype == 7 then
- local dir = start.dir
- if dir == "+TRT" then
- rlmode = -1
- elseif dir == "+TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- elseif subtype == 6 then
- local dir = start.dir
- if dir == "TRT" then
- rlmode = -1
- elseif dir == "TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- end
- start = start.next
- else
- start = start.next
- end
- end
- end
- else
- while start do
- local id = start.id
- if id == glyph then
- if start.subtype<256 and start.font == font and
- (not attr or has_attribute(start,0,attr)) and -- dynamic feature
- (not attribute or has_attribute(start,state,attribute)) then
- local chr = start.char -- used ?
- for i=1,#processes do local p = processes[i]
- local pp = p[3]
---~ local pc = pp[chr]
- local pc = pp[start.char]
- if pc then
- start, ok = p[1](start,kind,p[2],pc,pp,p[4])
- if ok then
- done = true
- if strategy == 1 then
- break
- end
- end -- else
- if not start then
- break
- end
- end
- end
- if start then start = start.next end
- else
- start = start.next
- end
- elseif id == glue then
- for i=1,#processes do local p = processes[i]
- if p[5] then -- chain
- local pp = p[3]
- local pc = pp[32]
- if pc then
- start, ok = p[1](start,kind,p[2],pc,pp,p[4])
- if ok then
- done = true
- if strategy == 1 then
- break
- end
- end
- if not start then
- break
- end
- end
- end
- end
- if start then start = start.next end
- elseif id == whatsit then
- local subtype = start.subtype
- if subtype == 7 then
- local dir = start.dir
- if dir == "+TRT" then
- rlmode = -1
- elseif dir == "+TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- elseif subtype == 6 then
- local dir = start.dir
- if dir == "TRT" then
- rlmode = -1
- elseif dir == "TLT" then
- rlmode = 1
- else
- rlmode = 0
- end
- end
- start = start.next
- else
- start = start.next
- end
- end
- end
- return head, done
- else
- return head, false
- end
- end
-
- -- we can assume that languages that use marks are not hyphenated
- -- we can also assume that at most one discretionary is present
-
- local copy_list, slide, free = node.copy_list, node.slide, node.free
-
- local function toligature(start,stop,char,markflag,discfound) -- brr head
- if start ~= stop then
- if discfound then
- local lignode = node.copy(start)
- lignode.font = start.font
- lignode.char = char
- lignode.subtype = 2
- start = node.do_ligature_n(start, stop, lignode)
- if start.id == disc then
- local prev = start.prev
- start = start.next
- end
- else -- start is the ligature
- -- to be checked: this marknum mess (sensitive for looping)
- local deletemarks = markflag ~= "mark"
---~ deletemarks = false
- start.components = copy_list(start,stop)
- local last = slide(start.components)
- start.components.prev, last.next = nil, nil
- start.char, start.subtype = char, 2
- local next, done, marknum = start.next, false, 1
- local after = stop.next
- while not done do
- done = next == stop
- if not deletemarks and marks[next.char] then
- set_attribute(next,marknumber,marknum)
- next = next.next
- --~ marknum = marknum + 1
- else
- marknum = marknum + 1
- start, next = nodes.remove(start,next,true)
- end
- end
- while after and after.id == glyph and after.font == currentfont and marks[after.char] do
- if deletemarks then
- start, after = nodes.remove(start,after,true)
- else
- set_attribute(after,marknumber,marknum)
- after = after.next
- --~ marknum = marknum + 1
- end
- end
-
- end
- end
- return start
- end
-
- function otf.features.process.gsub_single(start,kind,lookupname,replacements)
- if replacements then
- if otf.trace_replacements then
- report("otf process","%s:%s replacing 0x%04X by 0x%04X",kind,lookupname,start.char,replacements)
- end
- start.char = replacements
- return start, true
- else
- return start, false
- end
- end
-
- function otf.features.process.gsub_alternate(start,kind,lookupname,alternatives)
- if alternatives then
- if otf.trace_replacements then
- report("otf process","%s:%s alternative 0x%04X => %s",kind,lookupname,start.char,table.hexed(alternatives))
- end
- start.char = alternatives[1] -- will be preference
- return start, true
- else
- return start, false
- end
- end
-
- function otf.features.process.gsub_multiple(start,kind,lookupname,multiples)
- if multiples then
- if otf.trace_replacements then
- report("otf process","%s:%s multiple 0x%04X => %s",kind,lookupname,start.char,table.hexed(multiples))
- end
- start.char = multiples[1]
- if #multiples > 1 then
- for k=2,#multiples do
- local n = node.copy(start)
- local sn = start.next
- n.char = multiples[k]
- n.next = sn
- n.prev = start
- if sn then
- sn.prev = n
- end
- start.next = n
- start = n
- end
- end
- return start, true
- else
- return start, false
- end
- end
-
- function otf.features.process.gsub_ligature(start,kind,lookupname,ligatures,alldata,flags)
- local s, stop, discfound = start.next, nil, false
- while s do
- local id = s.id
- if id == glyph and s.subtype<256 then
- if s.font == currentfont then
- local char = s.char
- if marks[char] then
- s = s.next
- else
- -- we use indices, which saves a lookup, but we can use
- -- names when we comment the line after (*lig*)
- -- local lg = ligatures[1][glyphs[indices[char]].name]
- local lg = ligatures[1][indices[char]]
- -- mayb esome day we introduce a more efficient method
- if not lg then
- break
- else
- stop = s
- ligatures = lg
- s = s.next
- end
- end
- else
- break
- end
- elseif id == disc then
- discfound = true
- s = s.next
- else
- break
- end
- end
- if stop and ligatures[2] then
- start = toligature(start,stop,ligatures[2],flags[1],discfound)
- if otf.trace_ligatures then
- report("otf process","%s: inserting ligature 0x%04X (%s)",kind,start.char,utf.char(start.char))
- end
- return start, true
- end
- return start, false
- end
-
- function otf.features.process.gpos_mark2base(start,kind,lookupname,m_anchors,b_anchors)
- local markchar = start.char
- if marks[markchar] then
- local markanchors = m_anchors['mark']
- if markanchors then
- local component = start.prev
- while component and component.id == glyph and component.subtype<256 and component.font == currentfont do
- local basechar = component.char
- if marks[basechar] then
- component = component.prev
- else
- local baseanchors = b_anchors[basechar]
- if baseanchors then
- baseanchors = baseanchors['basechar']
- if baseanchors then
- for anchor, ma in pairs(markanchors) do
- local ba = baseanchors[anchor]
- if ba then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- start.xoffset, start.yoffset = component.xoffset - dx, component.yoffset + dy
- if otf.trace_anchors then
- report("otf process","%s: anchoring mark 0x%04X to basechar 0x%04X => (%s,%s) => (%s,%s)",
- kind,markchar,basechar,dx,dy,start.xoffset,start.yoffset)
- end
- return start, true
- end
- end
- end
- end
- break
- end
- end
- end
- end
- return start, false
- end
-
- function otf.features.process.gpos_mark2ligature(start,kind,lookupname,m_anchors,b_anchors) -- maybe use copies
- local markchar = start.char
- if marks[markchar] then
- local markanchors = m_anchors['mark']
- if markanchors then
- local component = start.prev
- while component and component.id == glyph and component.subtype<256 and component.font == currentfont do
- local basechar = component.char
- if marks[basechar] then
- component = component.prev
- else
- local baseanchors = b_anchors[basechar]
- if baseanchors then
- baseanchors = baseanchors['baselig']
- if baseanchors then
- for anchor, ma in pairs(markanchors) do
- local ba = baseanchors[anchor]
- if ba then
- local n = has_attribute(start,marknumber)
- ba = ba[n]
- if ba then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- start.xoffset, start.yoffset = component.xoffset - dx, component.yoffset + dy
- if otf.trace_anchors then
- report("otf process","%s: anchoring mark 0x%04X to baseligature 0x%04X => (%s,%s) => (%s,%s)",
- kind,markchar,basechar,dx,dy,component.xoffset,component.yoffset)
- end
- return start, true
- end
- end
- end
- end
- end
- break
- end
- end
- return start, done
- end
- end
- return start, false
- end
-
- -- hm which one is the correct one? chainprocs.gpos_mark2mark ot the next; the next one
- -- had more tracing so might be the best
-
- function otf.features.process.gpos_mark2mark(start,kind,lookupname,b_anchors,m_anchors)
- local basemarkchar = start.char
- if marks[basemarkchar] then
- local baseanchors = b_anchors['basemark']
- if baseanchors then
- local component = start.next
- while component and component.id == glyph and component.subtype<256 and component.font == currentfont do
- local markchar = component.char
- if not marks[markchar] then
- break
- else
- local basemarkattr = has_attribute(start,marknumber) or 1
- local markattr = has_attribute(component,marknumber) or 1
- if basemarkattr == markattr then -- still needed?
- local markanchors = m_anchors[markchar]
- if markanchors then
- local markanchor = markanchors['mark']
- if markanchor then
- for anchor,ma in pairs(markanchor) do
- local ba = baseanchors[anchor]
- if ba then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- component.xoffset, component.yoffset = start.xoffset - dx, start.yoffset + dy
- if otf.trace_anchors then
- report("otf process","%s:%s:%s anchoring mark 0x%04X to basemark 0x%04X => (%s,%s) => (%s,%s)",
- kind,anchor,markattr,markchar,basemarkchar,dx,dy,component.xoffset,component.yoffset)
- end
- return start, true
- end
- end
- end
- end
- -- weird, was here
- end
- component = component.next
- end
- end
- end
- end
- return start, false
- end
-
- function otf.features.process.gpos_cursive(start,kind,lookupname,exitanchors,anchors)
- local trace = otf.trace_cursive
- if rlmode >= 0 then
- local prev, done = start.prev, false
- while prev do
- if prev.id == glyph and prev.subtype<256 and prev.font == currentfont then
- local prevchar = prev.char
- if marks[prevchar] then
- -- what do do with marks, give them the offset of the previous glyph?
- prev = prev.prev
- else
- local startchar = start.char
- local entryanchors, exitanchors = anchors[startchar], anchors[prevchar]
- if entryanchors and exitanchors then
- local centry, cexit = entryanchors['centry'], exitanchors['cexit']
- if centry and cexit then
- for anchor, entry in pairs(centry) do
- local exit = cexit[anchor]
- if exit then
- local factor = tfmdata.factor
- local dx = -(descriptions[prevchar].width-exit[1]) - entry[1]
- local dy = -(entry[2]-exit[2])
- start.yoffset = prev.yoffset + scale(dy, factor)
- -- start.xoffset = scale(tx[i], factor)
- node.insert_before(prev,start,nodes.kern(scale(dx,factor)))
- if trace then
- report("otf process","%s:%s move 0x%04X cursive (%s,%s)",kind,lookupname,startchar,dx,dy)
- end
- done = true
- end
- end
- end
- end
- break
- end
- else
- break
- end
- end
- else
- local trace, factor = fonts.otf.trace_anchors, tfmdata.factor
- local next, done, total_x, total_y, tx, ty, stack = start.next, false, 0, 0, { }, { }, { }
- local function finish()
- done = true
- for i=1,#stack do
- local s = stack[i]
- s.yoffset = scale(total_y, factor)
- node.insert_before(s.prev,s,nodes.kern(scale(tx[i],factor)))
- if fonts.otf.trace_cursive then
- report("otf process",format("%s:%s move 0x%04X cursive (%s,%s)",kind,lookupname,s.char,tx[i],total_y))
- end
- total_y = total_y - (ty[i] or 0)
- end
- total_x, total_y, tx, ty, stack = 0, 0, { }, { }, { }
- end
- while next do
- if next.id == glyph and next.subtype<256 and next.font == currentfont then
- local nextchar = next.char
- if marks[nextchar] then
- next = next.next
- else
- local entryanchors, exitanchors = anchors[nextchar], anchors[start.char]
- if entryanchors and exitanchors then
- local centry, cexit = entryanchors['centry'], exitanchors['cexit']
- if centry and cexit then
- for anchor, entry in pairs(centry) do
- local exit = cexit[anchor]
- if exit then
- local dy = -exit[2] + entry[2]
- local dx = -(descriptions[nextchar].width-entry[1]) - exit[1] -- often width == entry 1
- tx[#tx+1], ty[#ty+1] = dx, dy
- total_x, total_y = total_x + dx, total_y + dy
- stack[#stack+1] = start
- break
- end
- end
- else
- finish()
- end
- else
- finish()
- end
- start = next
- next = start.next
- end
- else
- finish()
- break
- end
- end
- return start, done
- end
- return start, done
- end
-
- function otf.features.process.gpos_single(start,kind,lookupname,basekerns,kerns)
- report("otf process","gpos_single not yet supported")
- return start, false
- end
-
- function otf.features.process.gpos_pair(start,kind,lookupname,basekerns,kerns)
- -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
- -- todo: kerns in components of ligatures
- local next = start.next
- if not next then
- return start, false
- else
- local prev, done = start, false
- local trace = otf.trace_kerns
- local factor = tfmdata.factor
- while next and next.id == glyph and next.subtype<256 and next.font == currentfont do
- local cn = descriptions[next.char]
- if not cn or cn.class == 'mark' then
- prev = next
- next = next.next
- else
- local krn = basekerns[next.char]
- if not krn then
- -- skip
- elseif type(krn) == "table" then
- local a, b = krn[3], krn[7]
- if a and a ~= 0 then
- local k = nodes.kern(scale(a,factor))
- k.next = next
- k.prev = prev
- prev.next = k
- next.prev = k
- if trace then
- -- todo
- end
- end
- if b and b ~= 0 then
- report("otf process","we need to do something with the second kern xoff %s",b)
- end
- else
- -- todo, just start, next = node.insert_before(head,next,nodes.kern(scale(kern,factor)))
- if otf.trace_kerns then
- report("otf process","%s: inserting kern %s between 0x%04X and 0x%04X",kind,krn,prev.char,next.char)
- end
- local k = nodes.kern(scale(krn,factor))
- k.next = next
- k.prev = prev
- prev.next = k
- next.prev = k
- end
- break
- end
- end
- return start, done
- end
- end
-
--- -- -- temp here, needs to be tested first -- -- --
-
---~ function do_gpos_pair(start,kind,lookupname,basekerns,kerns)
---~ local trace = otf.trace_kerns
---~ local factor = tfmdata.factor
---~ local next, prev, middle = start.next, start, nil
---~ -- to be optimized, we can consider using basemode for fonts without lookups
---~ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
---~ -- todo: kerns in components of ligatures
---~ --
---~ -- find valid next
---~ while next do
---~ local id = next.id
---~ if id == glyph and next.subtype<256 and next.font == currentfont then
---~ local cn = characters[next.char]
---~ if not cn or cn.description.class == 'mark' then
---~ prev = next
---~ next = next.next
---~ else
---~ break
---~ end
---~ elseif id == disc then -- assume same font
---~ middle = next
---~ else
---~ return start, false
---~ end
---~ end
---~ local function inject(head, prevkern, nextkern)
---~ if head then
---~ -- kern between prevchar and head
---~ local tail = node.slide(head) -- tail
---~ if head.id == glyph then
---~ local c = head.char
---~ local pc = prevkern[c]
---~ if pc then
---~ local k = nodes.kern(scale(pc,factor))
---~ k.next = head
---~ head = k
---~ end
---~ end
---~ -- kern between prevchar and tail
---~ if tail.id == glyph then
---~ local c = tail.char
---~ local nc = nextkern[c]
---~ if nc then
---~ tail.next = nodes.kern(scale(nc,factor))
---~ end
---~ end
---~ -- kern between head .. tail
---~ local c = head
---~ while c do do_gpos_pair(c,kind,lookupname,basekerns,kerns) ; c = c.next end
---~ end
---~ return head
---~ end
---~ if middle then
---~ -- prev middle next - assumes same lookup
---~ local prevkern, nextkern = kerns[prev.char], kerns[next.char]
---~ local m = middle.pre ; if m then middle.pre = inject(m, prevkern, nextkern) end
---~ local m = middle.post ; if m then middle.post = inject(m, prevkern, nextkern) end
---~ local m = middle.replace ; if m then middle.replace = inject(m, prevkern, nextkern) end
---~ elseif next then
---~ local prevchar, nextchar = prev.char, next.char
---~ if prev.components then
---~ local prevkern, nextkern = kerns[prev.char], kerns[next.char]
---~ local p = prev.components ; if p then prev.components = inject(p, prevkern, nextkern) end
---~ end
---~ local krn = basekerns[nextchar]
---~ if not krn then
---~ return start, false
---~ elseif type(krn) == "table" then
---~ local a, b = krn[3], krn[7]
---~ if a and a ~= 0 then
---~ start, next = node.insert_before(start,next,nodes.kern(scale(a,factor)))
---~ if trace then
---~ report("otf process","%s: inserting kern %s between 0x%04X and 0x%04X",kind,a,prevchar,nextchar)
---~ end
---~ end
---~ if b and b ~= 0 then
---~ report("otf process","we need to do something with the second kern xoff %s",b)
---~ end
---~ return start, true -- could be next
---~ else
---~ if otf.trace_kerns then
---~ report("otf process","%s: inserting kern %s between 0x%04X and 0x%04X",kind,krn,prevchar,nextchar)
---~ end
---~ start, next = node.insert_before(start,next,nodes.kern(scale(krn,factor)))
---~ return start, true -- could be next
---~ end
---~ end
---~ return start, false
---~ end
-
---~ otf.features.process.gpos_pair = do_gpos_pair
-
--- -- -- temp here, needs to be tested -- -- --
-
-
- local chainprocs = { } -- we can probably optimize this because they're all internal lookups
-
- -- For the moment we save each looked up glyph in the sequence, which is ok because
- -- each lookup in the chain has its own sequence. This saves memory. Only ligatures
- -- are stored in the featurecache, because we don't want to loop over all characters
- -- in order to locate them.
-
- function chainprocs.gsub_single(start,stop,kind,lookupname,sequence,f,l,lookups)
- local trace = otf.trace_replacements
- local c, r = trace and { }, trace and { }
- local lookup, index, current = 1, f, start
- while current ~= nil do
- if current.id == glyph then -- test for more ?
- local char = current.char
- local cacheslot = sequence[index]
- local replacement = cacheslot[char]
- if replacement == true then
- if lookups then
- -- didn't we have the arrays available?
- local looks = glyphs[descriptions[char].index].lookups -- SLOW, USE OTFDATA
- if looks then
- local luatex = otfdata.luatex
- local glyphlookups = luatex.internals[lookups[lookup]].lookups
- local unicodes = luatex.unicodes
- for gl=1,#glyphlookups do
- local lv = looks[glyphlookups[gl]]
- if lv then
- local ulv = unicodes[lv[1][2]]
- if not ulv then
- replacement = char
- elseif type(ulv) == "number" then
- replacement = ulv
- else
- replacement = ulv[1]
- end
- cacheslot[char] = replacement
- break
- end
- end
- else
- replacement, cacheslot[char] = char, char
- end
- else
- replacement, cacheslot[char] = char, char
- end
- end
- if trace then
- c[#c+1], r[#r+1] = char, replacement
- end
- current.char = replacement
- if current == stop then
- break
- else
- current, lookup, index = current.next, lookup + 1, index + 1
- end
- elseif current == stop then
- break
- else
- current = current.next
- end
- end
- if trace then
- report("otf chain","%s: single replacement %s by %s",kind,table.hexed(c),table.hexed(r))
- end
- return start
- end
-
- function chainprocs.gsub_multiple(start,stop,kind,lookupname,sequence,f,l,lookups)
- local char = start.char
- local cacheslot = sequence[f] -- [1]
- local replacement = cacheslot[char]
- if replacement == true then
- if lookups then
- local looks = glyphs[descriptions[char].index].lookups
- if looks then
- local luatex = otfdata.luatex
- local lookups = luatex.internals[lookups[1]].lookups
- local unicodes = luatex.unicodes
- for l=1,#lookups do
- local lv = looks[lookups[l]]
- if lv then
- replacement = { }
- for c in lv[1][2]:gmatch("[^ ]+") do
- local uc = unicodes[c]
- if type(uc) == "number" then
- replacement[#replacement+1] = uc
- else
- replacement[#replacement+1] = uc[1]
- end
- end
- cacheslot[char] = replacement
- break
- end
- end
- else
- replacement = { char }
- cacheslot[char] = replacement
- end
- else
- replacement = { char }
- cacheslot[char] = replacement
- end
- end
- if otf.trace_replacements then
- report("otf chain","%s: replacing character 0x%04X by multiple 0x%04X",kind,char,table.hexed(replacement))
- end
- start.char = replacement[1]
- if #replacement > 1 then
- for k=2,#replacement do
- local n = node.copy(start)
- local sn = start.next
- n.char = replacement[k]
- n.next = sn
- n.prev = start
- if sn then
- sn.prev = n
- end
- start.next = n
- start = n
- end
- end
- return start
- end
-
- function chainprocs.gsub_alternate(start,stop,kind,lookupname,sequence,f,l,lookups)
- local char = start.char
- local cacheslot = sequence[f] -- [1]
- local replacement = cacheslot[char]
- if replacement == true then
- if lookups then
- local looks = glyphs[descriptions[char].index].lookups
- if looks then
- local luatex = otfdata.luatex
- local lookups = luatex.internals[lookups[1]].lookups
- local unicodes = luatex.unicodes
- for l=1,#lookups do
- local lv = looks[lookups[l]]
- if lv then
- replacement = { }
- for c in lv[1][2]:gmatch("[^ ]+") do
- local uc = unicodes[c]
- if type(uc) == "number" then
- replacement[#replacement+1] = uc
- else
- replacement[#replacement+1] = uc[1]
- end
- end
- cacheslot[char] = replacement
- break
- end
- end
- else
- replacement = { char }
- cacheslot[char] = replacement
- end
- else
- replacement = { char }
- cacheslot[char] = replacement
- end
- end
- if otf.trace_replacements then
- report("otf chain","%s: replacing character 0x%04X by alternate",kind,char)
- end
- start.char = replacement[1]
- return start
- end
-
- function chainprocs.gsub_ligature(start,stop,kind,lookupname,sequence,f,l,lookups,flags)
- if lookups then
- if start == stop then
- -- print("todo: optimize")
- end
- local featurecache = fontdata[currentfont].shared.featurecache
- local ligaturecache = featurecache[kind]
- if not ligaturecache then
- ligaturecache = otf.features.collect_ligatures(tfmdata,kind) -- double cached ?
- featurecache[kind] = ligaturecache
- end
- local lookups = otfdata.luatex.internals[lookups[1]].lookups
- local trace = otf.trace_ligatures
- for i=1,#lookups do
- local ligatures = ligaturecache[lookups[i]]
- if ligatures and ligatures[start.char] then
- ligatures = ligatures[start.char]
- local s, discfound = start.next, false
- while s do
- local id = s.id
- if id == disc then
- s = s.next
- discfound = true
- elseif descriptions[s.char].class == 'mark' then -- marks
- s = s.next
- else
- local lg = ligatures[1][s.char]
- if not lg then
- break
- else
- ligatures = lg
- if s == stop then
- break
- else
- s = s.next
- end
- end
- end
- end
- if ligatures[2] then
- if trace then
- if start == stop then
- report("otf chain","%s: replacing character 0x%04X by ligature 0x%04X",kind,start.char,ligatures[2])
- else
- report("otf chain","%s: replacing character 0x%04X upto 0x%04X by ligature 0x%04X",kind,start.char,stop.char,ligatures[2])
- end
- end
- return toligature(start,stop,ligatures[2],flags[1],discfound)
- end
- break
- end
- end
- end
- return stop
- end
-
- -- weird, mkmk can have a mark2base, in idris font
-
- function chainprocs.gpos_mark2base(start,stop,kind,lookupname,sequence,f,l,lookups,flags)
- -- dynamic resolver
- local markchar = start.char
- if marks[markchar] then
- local anchortag = sequence[f][markchar]
- if anchortag == true then
- local ok = false
- local classes = otfdata.anchor_classes
- local lookups = otfdata.luatex.internals[lookups[1]].lookups
- for k=1,#classes do
- local v = classes[k]
- if v.lookup == lookups[1] then -- let's gamble for uniqueness: and v.type == kind then
- anchortag = v.name
- sequence[f][markchar] = anchortag
- ok = true
- break
- end
- end
- if not ok and otf.trace_anchors then
- report("otf chain","%s: no matching mark2base anchor class for 0x%04X, lookup %s",kind,markchar,lookups[1])
- end
- end
- if anchortag ~= true then
- local component = start.prev
- while component and component.id == glyph and component.subtype<256 and component.font == currentfont do
- local basechar = component.char
- if marks[basechar] then
- component = component.prev
- else
- local bglyph = glyphs[descriptions[basechar].index] -- startchar
- local baseanchors = bglyph.anchors['basechar']
- if baseanchors then
- local ba = baseanchors[anchortag]
- if ba then
- local mglyph = glyphs[descriptions[markchar].index]
- local markanchors = mglyph.anchors['mark']
- if markanchors then
- local ma = markanchors[anchortag]
- if ma then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- start.xoffset, start.yoffset = component.xoffset - dx, component.yoffset + dy
- if otf.trace_anchors then
- report("otf chain","%s: anchoring mark 0x%04X to basechar 0x%04X => (%s,%s) => (%s,%s)",
- kind,markchar,basechar,dx,dy,start.xoffset,start.yoffset)
- end
- return start, true
- end
- end
- end
- end
- break
- end
- end
- end
- end
- return start, false
- end
-
- function chainprocs.gpos_mark2ligature(start,stop,kind,lookupname,sequence,f,l,lookups,flags)
- -- dynamic resolver
- local markchar = start.char
- if marks[markchar] then
- local anchortag = sequence[f][markchar]
- if anchortag == true then
- local classes = otfdata.anchor_classes
- local lookups = otfdata.luatex.internals[lookups[1]].lookups
- local ok = false
- for k=1,#classes do
- local v = classes[k]
- if v.lookup == lookups[1] then -- and v.type == kind then
- anchortag = v.name
- sequence[f][markchar] = anchortag
- ok = true
- break
- end
- end
- if not ok and otf.trace_anchors then
- report("otf chain","%s: no matching mark2ligature anchor class for 0x%04X, lookup %s",kind,markchar,lookups[1])
- end
- end
- if anchortag ~= true then
- local component = start.prev
- while component and component.id == glyph and component.subtype<256 and component.font == currentfont do
- local basechar = component.char
- if marks[basechar] then
- component = component.prev
- else
- local bglyph = glyphs[descriptions[basechar].index] -- startchar
- local baseanchors = bglyph.anchors['baselig']
- if baseanchors then
- local ba = baseanchors[anchortag]
- if ba then
- local n = has_attribute(start,marknumber)
- ba = ba[n] -- ok ?
- if ba then
- local mglyph = glyphs[descriptions[markchar].index]
- local markanchors = mglyph.anchors['mark']
- if markanchors then
- local ma = markanchors[anchortag]
- if ma then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- start.xoffset, start.yoffset = component.xoffset - dx, component.yoffset + dy
- if otf.trace_anchors then
- report("otf chain","%s: anchoring mark 0x%04X to baseligature 0x%04X => (%s,%s) => (%s,%s)",
- kind,basechar,markchar,dx,dy,start.xoffset,start.yoffset)
- end
- return start, true
- end
- end
- end
- end
- end
- break
- end
- end
- end
- end
- return start, false
- end
-
- -- to be checked (see previous generic mark2mark)
-
- function chainprocs.gpos_mark2mark(start,stop,kind,lookupname,sequence,f,l,lookups)
- local component = start.next
- if component and component.id == glyph and component.subtype<256 and component.font == currentfont and marks[component.char] then
- local markchar = start.char
- local anchortag = sequence[f][markchar] -- [1][char]
- if anchortag == true then
- local classes = otfdata.anchor_classes
- local ok = false
- for k=1,#classes do
- local v = classes[k]
- if v.lookup == lookupname then -- and v.type == kind then
- anchortag = v.name
- sequence[f][markchar] = anchortag
- ok = true
- break
- end
- end
- if not ok and otf.trace_anchors then
- report("otf chain","%s: no matching mark2mark anchor class for 0x%04X, lookup %s",kind,markchar,lookups[1])
- end
- end
- if anchortag ~= true then
- -- the following may have been be spoiled while idrising the other ones
- local markattr = has_attribute(start, marknumber) or 1 -- i need to check this ! 1 is new !
- local baseattr = has_attribute(component,marknumber) or 1 -- i need to check this ! 1 is new !
- if baseattr == markattr then
- local glyph = glyphs[descriptions[markchar].index]
- if glyph.anchors and glyph.anchors[anchortag] then
- local trace = otf.trace_anchors
- local done = false
- local baseanchors = glyph.anchors['basemark'][anchortag]
- while component do
- local basechar = component.char
- local markanchors = glyphs[descriptions[basechar].index].anchors['mark'][anchortag]
- if markanchors then
- for anchor,data in pairs(markanchors) do
- local ba = baseanchors[anchor]
- if ba then
- local factor = tfmdata.factor
- local dx, dy = scale(ba[1]-ma[1],factor), scale(ba[2]-ma[2],factor)
- start.xoffset, start.yoffset = component.xoffset - dx, component.yoffset + dy
- if otf.trace_anchors then
- report("otf chain","%s: anchoring mark 0x%04X to basemark 0x%04X => (%s,%s) => (%s,%s)",
- kind,markchar,basechar,dx,dy,component.xoffset,component.yoffset)
- end
- done = true
- break
- end
- end
- end
- component = component.next
- if component and component.id == glyph and component.subtype<256 and component.font == currentfont and marks[component.char] then
- markattr = has_attribute(component,marknumber)
- if baseattr ~= markattr then
- break
- end
- else
- break
- end
- end
- return start, done
- end
- end
- end
- end
- return start, false
- end
-
- function chainprocs.gpos_cursive(start,stop,kind,lookupname,sequence,f,l,lookups)
- report("otf chain","chainproc gpos_cursive not yet supported")
- return start
- end
- function chainprocs.gpos_single(start,stop,kind,lookupname,sequence,f,l,lookups)
- report("otf process","chainproc gpos_single not yet supported")
- return start
- end
- function chainprocs.gpos_pair(start,stop,kind,lookupname,sequence,f,l,lookups)
- report("otf process","chainproc gpos_pair not yet supported")
- return start
- end
-
- function chainprocs.self(start,stop,kind,lookupname,sequence,f,l,lookups)
- report("otf process","self refering lookup cannot happen")
- return stop
- end
-
- local zwnj = 0x200C
- local zwj = 0x200D
-
- -- what pointer to return, spec says stop
-
- -- to be discussed ... is bidi changer a space?
-
- function otf.features.process.contextchain(start,kind,lookupname,contextdata)
- local contexts, flags, done = contextdata.lookups, contextdata.flags, false
- local skipmark, skipligature, skipbase = unpack(flags) -- unpack slower than assignment
- for k=1,#contexts do
- local match, next, last = true, start, start
- local rule, lookuptype, sequence, f, l, lookups = unpack(contexts[k]) -- unpack is slow
- local s = #sequence
- if s == 1 then
- match = next.id == glyph and next.subtype<256 and next.font == currentfont and sequence[1][next.char]
- else
- -- todo: better space check (maybe check for glue)
- local n = f
- while n <= l do
- if last then
- local id = last.id
- if id == glyph and last.subtype<256 and last.font == currentfont then
- local char = last.char
- local cc = characters[char]
- if cc then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase then
- -- skip 'm
- last = last.next
- elseif sequence[n][char] then
- if n < l then
- last = last.next
- end
- n = n + 1
- else
- match = false break
- end
- else
- match = false break
- end
- else -- play safe
- match = false break
- end
- elseif id == disc then -- what to do with kerns?
- last = last.next
- else
- match = false break
- end
- else
- match = false break
- end
- end
- if match and f > 1 then
- local prev = start.prev
- if prev then
- -- removed optimiziation for f == 2, we have to deal with marks anyway
- local n = f-1
- while n >= 1 do
- if prev then
- local id = prev.id
- if id == glyph and prev.subtype<256 and prev.font == currentfont then -- normal char
- local char = prev.char
- local cc = characters[char]
- if cc then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase then
- -- skip 'm
- elseif sequence[n][char] then
- n = n -1
- else
- match = false break
- end
- else
- match = false break
- end
- else
- match = false break
- end
- elseif id == disc then
- -- skip 'm
- elseif sequence[n][32] then
- n = n -1
- else
- match = false break
- end
- prev = prev.prev
- elseif sequence[n][32] then
- n = n -1
- else
- match = false break
- end
- end
- elseif f == 2 then
- match = sequence[1][32]
- else
- for n=f-1,1 do
- if not sequence[n][32] then
- match = false break
- end
- end
- end
- end
- if match and s > l then
- local next = last.next
- if next then
- -- removed optimiziation for s-l == 1, we have to deal with marks anyway
- local n = l+ 1
- while n <= s do
- if next then
- local id = next.id
- if id == glyph and next.subtype<256 and next.font == currentfont then -- normal char
- local char = next.char
- local cc = characters[char]
- if cc then
- local ccd = descriptions[char]
- if ccd then
- local class = ccd.class
- if class == skipmark or class == skipligature or class == skipbase then
- -- skip 'm
- elseif sequence[n][char] then
- n = n + 1
- else
- match = false break
- end
- else
- match = false break
- end
- else
- match = false break
- end
- elseif id == disc then
- -- skip 'm
- elseif sequence[n][32] then -- brrr
- n = n + 1
- else
- match = false break
- end
- next = next.next
- elseif sequence[n][32] then
- n = n + 1
- else
- match = false break
- end
- end
- elseif s-l == 1 then
- match = sequence[s][32]
- else
- for n=l+1,s do
- if not sequence[n][32] then
- match = false break
- end
- end
- end
- end
- end
- if match then
- local trace = otf.trace_contexts
- if trace then
- local char = start.char
- report("otf chain","%s: rule %s of %s matches at char 0x%04X (%s) for (%s,%s,%s) chars, lookuptype %s",kind,rule,lookupname,char,utf.char(char),f-1,l-f+1,s-l,lookuptype)
- end
- if lookups then
- local cp = chainprocs[lookuptype]
- if cp then
- start = cp(start,last,kind,lookupname,sequence,f,l,lookups,flags)
- else
- report("otf chain","%s: lookuptype %s not supported yet for %s",kind,lookuptype,lookupname)
- end
- elseif trace then
- report("otf chain","%s: skipping match for %s",kind,lookupname)
- end
- done = true
- break
- end
- end
- return start, done
- end
-
---~ if true then
---~ if n < f then
---~ texio.write_nl(format("%s before %s %04x %s %s %s",lookupname,n,char,class,skipmark or "?",tostring(sequence[n][char])))
---~ elseif n > l then
---~ texio.write_nl(format("%s after %s %04x %s %s %s",lookupname,n,char,class,skipmark or "?",tostring(sequence[n][char])))
---~ else
---~ texio.write_nl(format("%s current %s %04x %s %s %s",lookupname,n,char,class,skipmark or "?",tostring(sequence[n][char])))
---~ end
---~ end
-
---~ elseif char == zwnj and sequence[n][32] then -- brrr
-
- -- this needs to be fixed ! ! ! ! ! ! ! !
-
- function otf.features.process.reversecontextchain(start,kind,lookupname,contextdata)
- -- PROBABLY WRONG, WE NEED TO WALK BACK OVER THE LIST
- local done = false
- local contexts = contextdata.lookups
- local flags = contextdata.flags
- local skipmark, skipligature, skipbase = unpack(flags)
- for k=1,#contexts do
- local match, next, first, last = true, start, start, start
- local rule, lookuptype, sequence, f, l, lookups = unpack(contexts[k]) -- unpack is slow
- if #sequence == 1 then
- match = next.id == glyph and next.subtype<256 and next.font == currentfont and sequence[1][next.char]
- else
- local n, s = #sequence, 1
- while n > 0 do
- if next then
- local id = next.id
- if id == glyph and next.subtype<256 and next.font == currentfont then -- normal char
- local char = next.char
- local class = descriptions[char].class
- if class == skipmark or class == skipligature or class == skipbase then
- -- skip
- elseif sequence[n][char] then
- if n == f then
- first = next -- ok ?
- end
- if n == l then
- last = next -- ok ?
- end
- n = n - 1
- else
- match = false break
- end
- elseif id == disc then
- -- skip
- elseif not sequence[n][32] then -- brrr
- match = false break
- end
- next = next.next
- elseif sequence[n][32] then
- n = n - 1
- else
- match = false break
- end
- end
- end
- if match then
- local trace = otf.trace_contexts
- if trace then
- local char = first.char
- report("otf reverse chain","%s: rule %s of %s matches, replacing starts at char 0x%04X (%s) lookuptype %s",kind,rule,lookupname,char,utf.char(char),lookuptype)
- end
- if lookups then
- local cp = chainprocs[lookuptype]
- if cp then
- if start == first then
- start = cp(first,last,kind,lookupname,sequence,f,l,lookups,flags)
- else
- first = cp(first,last,kind,lookupname,sequence,f,l,lookups,flags)
- end
- else
- report("otf reverse chain","%s: lookuptype %s not supported yet for %s",kind,lookuptype,lookupname)
- end
- elseif trace then
- report("otf reverse chain","%s: skipping match for %s",kind,lookupname)
- end
- done = true
- break
- end
- end
- return start, done
- end
-
- otf.features.process.gsub_context = otf.features.process.contextchain
- otf.features.process.gsub_contextchain = otf.features.process.contextchain
- otf.features.process.gsub_reversecontextchain = otf.features.process.reversecontextchain
-
- otf.features.process.gpos_contextchain = otf.features.process.contextchain
- otf.features.process.gpos_context = otf.features.process.contextchain
-
-end
-
-do
-
- local process = otf.features.process.feature
-
- function fonts.methods.node.otf.aalt(head,font,attr) return process(head,font,attr,'aalt') end
- function fonts.methods.node.otf.abvm(head,font,attr) return process(head,font,attr,'abvm') end
- function fonts.methods.node.otf.afrc(head,font,attr) return process(head,font,attr,'afrc') end
- function fonts.methods.node.otf.akhn(head,font,attr) return process(head,font,attr,'akhn') end
- function fonts.methods.node.otf.blwm(head,font,attr) return process(head,font,attr,'blwm') end
- function fonts.methods.node.otf.c2pc(head,font,attr) return process(head,font,attr,'c2pc') end
- function fonts.methods.node.otf.c2sc(head,font,attr) return process(head,font,attr,'c2sc') end
- function fonts.methods.node.otf.calt(head,font,attr) return process(head,font,attr,'calt') end
- function fonts.methods.node.otf.case(head,font,attr) return process(head,font,attr,'case') end
- function fonts.methods.node.otf.ccmp(head,font,attr) return process(head,font,attr,'ccmp') end
- function fonts.methods.node.otf.clig(head,font,attr) return process(head,font,attr,'clig') end
- function fonts.methods.node.otf.cpsp(head,font,attr) return process(head,font,attr,'cpsp') end
- function fonts.methods.node.otf.cswh(head,font,attr) return process(head,font,attr,'cswh') end
- function fonts.methods.node.otf.curs(head,font,attr) return process(head,font,attr,'curs') end
- function fonts.methods.node.otf.dlig(head,font,attr) return process(head,font,attr,'dlig') end
- function fonts.methods.node.otf.dnom(head,font,attr) return process(head,font,attr,'dnom') end
- function fonts.methods.node.otf.expt(head,font,attr) return process(head,font,attr,'expt') end
- function fonts.methods.node.otf.fin2(head,font,attr) return process(head,font,attr,'fin2') end
- function fonts.methods.node.otf.fin3(head,font,attr) return process(head,font,attr,'fin3') end
- function fonts.methods.node.otf.fina(head,font,attr) return process(head,font,attr,'fina',3) end
- function fonts.methods.node.otf.frac(head,font,attr) return process(head,font,attr,'frac') end
- function fonts.methods.node.otf.fwid(head,font,attr) return process(head,font,attr,'fwid') end
- function fonts.methods.node.otf.haln(head,font,attr) return process(head,font,attr,'haln') end
- function fonts.methods.node.otf.hist(head,font,attr) return process(head,font,attr,'hist') end
- function fonts.methods.node.otf.hkna(head,font,attr) return process(head,font,attr,'hkna') end
- function fonts.methods.node.otf.hlig(head,font,attr) return process(head,font,attr,'hlig') end
- function fonts.methods.node.otf.hngl(head,font,attr) return process(head,font,attr,'hngl') end
- function fonts.methods.node.otf.hwid(head,font,attr) return process(head,font,attr,'hwid') end
- function fonts.methods.node.otf.init(head,font,attr) return process(head,font,attr,'init',1) end
- function fonts.methods.node.otf.isol(head,font,attr) return process(head,font,attr,'isol',4) end
- function fonts.methods.node.otf.ital(head,font,attr) return process(head,font,attr,'ital') end
- function fonts.methods.node.otf.jp78(head,font,attr) return process(head,font,attr,'jp78') end
- function fonts.methods.node.otf.jp83(head,font,attr) return process(head,font,attr,'jp83') end
- function fonts.methods.node.otf.jp90(head,font,attr) return process(head,font,attr,'jp90') end
- function fonts.methods.node.otf.kern(head,font,attr) return process(head,font,attr,'kern') end
- function fonts.methods.node.otf.liga(head,font,attr) return process(head,font,attr,'liga') end
- function fonts.methods.node.otf.lnum(head,font,attr) return process(head,font,attr,'lnum') end
- function fonts.methods.node.otf.locl(head,font,attr) return process(head,font,attr,'locl') end
- function fonts.methods.node.otf.mark(head,font,attr) return process(head,font,attr,'mark') end
- function fonts.methods.node.otf.med2(head,font,attr) return process(head,font,attr,'med2') end
- function fonts.methods.node.otf.medi(head,font,attr) return process(head,font,attr,'medi',2) end
- function fonts.methods.node.otf.mgrk(head,font,attr) return process(head,font,attr,'mgrk') end
- function fonts.methods.node.otf.mkmk(head,font,attr) return process(head,font,attr,'mkmk') end
- function fonts.methods.node.otf.nalt(head,font,attr) return process(head,font,attr,'nalt') end
- function fonts.methods.node.otf.nlck(head,font,attr) return process(head,font,attr,'nlck') end
- function fonts.methods.node.otf.nukt(head,font,attr) return process(head,font,attr,'nukt') end
- function fonts.methods.node.otf.numr(head,font,attr) return process(head,font,attr,'numr') end
- function fonts.methods.node.otf.onum(head,font,attr) return process(head,font,attr,'onum') end
- function fonts.methods.node.otf.ordn(head,font,attr) return process(head,font,attr,'ordn') end
- function fonts.methods.node.otf.ornm(head,font,attr) return process(head,font,attr,'ornm') end
- function fonts.methods.node.otf.pnum(head,font,attr) return process(head,font,attr,'pnum') end
- function fonts.methods.node.otf.pref(head,font,attr) return process(head,font,attr,'pref') end
- function fonts.methods.node.otf.pres(head,font,attr) return process(head,font,attr,'pres') end
- function fonts.methods.node.otf.pstf(head,font,attr) return process(head,font,attr,'pstf') end
- function fonts.methods.node.otf.rlig(head,font,attr) return process(head,font,attr,'rlig') end
- function fonts.methods.node.otf.rphf(head,font,attr) return process(head,font,attr,'rphf') end
- function fonts.methods.node.otf.rtla(head,font,attr) return process(head,font,attr,'rtla') end
- function fonts.methods.node.otf.salt(head,font,attr) return process(head,font,attr,'calt') end
- function fonts.methods.node.otf.sinf(head,font,attr) return process(head,font,attr,'sinf') end
- function fonts.methods.node.otf.smcp(head,font,attr) return process(head,font,attr,'smcp') end
- function fonts.methods.node.otf.smpl(head,font,attr) return process(head,font,attr,'smpl') end
- function fonts.methods.node.otf.ss01(head,font,attr) return process(head,font,attr,'ss01') end
- function fonts.methods.node.otf.ss02(head,font,attr) return process(head,font,attr,'ss02') end
- function fonts.methods.node.otf.ss03(head,font,attr) return process(head,font,attr,'ss03') end
- function fonts.methods.node.otf.ss04(head,font,attr) return process(head,font,attr,'ss04') end
- function fonts.methods.node.otf.ss05(head,font,attr) return process(head,font,attr,'ss05') end
- function fonts.methods.node.otf.ss06(head,font,attr) return process(head,font,attr,'ss06') end
- function fonts.methods.node.otf.ss07(head,font,attr) return process(head,font,attr,'ss07') end
- function fonts.methods.node.otf.ss08(head,font,attr) return process(head,font,attr,'ss08') end
- function fonts.methods.node.otf.ss09(head,font,attr) return process(head,font,attr,'ss09') end
- function fonts.methods.node.otf.subs(head,font,attr) return process(head,font,attr,'subs') end
- function fonts.methods.node.otf.sups(head,font,attr) return process(head,font,attr,'sups') end
- function fonts.methods.node.otf.swsh(head,font,attr) return process(head,font,attr,'swsh') end
- function fonts.methods.node.otf.titl(head,font,attr) return process(head,font,attr,'titl') end
- function fonts.methods.node.otf.tnam(head,font,attr) return process(head,font,attr,'tnam') end
- function fonts.methods.node.otf.tnum(head,font,attr) return process(head,font,attr,'tnum') end
- function fonts.methods.node.otf.trad(head,font,attr) return process(head,font,attr,'trad') end
- function fonts.methods.node.otf.unic(head,font,attr) return process(head,font,attr,'unic') end
- function fonts.methods.node.otf.zero(head,font,attr) return process(head,font,attr,'zero') end
-
-end
-
--- common stuff
-
-function otf.features.language(tfmdata,value)
- if value then
- value = value:lower()
- if otf.tables.languages[value] then
- tfmdata.language = value
- end
- end
-end
-
-function otf.features.script(tfmdata,value)
- if value then
- value = value:lower()
- if otf.tables.scripts[value] then
- tfmdata.script = value
- end
- end
-end
-
-function otf.features.mode(tfmdata,value)
- if value then
- tfmdata.mode = value:lower()
- end
-end
-
-function otf.features.strategy(tfmdata,value)
- if value then
- tfmdata.strategy = tonumber(value) or otf.strategy
- end
-end
-
-fonts.initializers.base.otf.language = otf.features.language
-fonts.initializers.base.otf.script = otf.features.script
-fonts.initializers.base.otf.mode = otf.features.mode
-fonts.initializers.base.otf.method = otf.features.mode
-fonts.initializers.base.otf.strategy = otf.features.strategy -- not needed
-
-fonts.initializers.node.otf.language = otf.features.language
-fonts.initializers.node.otf.script = otf.features.script
-fonts.initializers.node.otf.mode = otf.features.mode
-fonts.initializers.node.otf.method = otf.features.mode
-fonts.initializers.node.otf.strategy = otf.features.strategy
-
-do
-
- local tlig_list = {
- endash = "hyphen hyphen",
- emdash = "hyphen hyphen hyphen",
- --~ quotedblleft = "quoteleft quoteleft",
- --~ quotedblright = "quoteright quoteright",
- --~ quotedblleft = "grave grave",
- --~ quotedblright = "quotesingle quotesingle",
- --~ quotedblbase = "comma comma",
- }
- local trep_list = {
- --~ [0x0022] = 0x201D,
- [0x0027] = 0x2019,
- --~ [0x0060] = 0x2018,
- }
-
- local tlig_feature = {
- features = { { scripts = { { script = "DFLT", langs = { "dflt" }, } }, tag = "tlig", comment = "added bij mkiv" }, },
- name = "ctx_tlig",
- subtables = { { name = "ctx_tlig_1" } },
- type = "gsub_ligature",
- flags = { },
- always = true
- }
- local trep_feature = {
- features = { { scripts = { { script = "DFLT", langs = { "dflt" }, } }, tag = "trep", comment = "added bij mkiv" }, },
- name = "ctx_trep",
- subtables = { { name = "ctx_trep_1" } },
- type = "gsub_single",
- flags = { },
- always = true
- }
-
- function otf.enhance.enrich(data,filename)
- local glyphs = data.glyphs
- local indices = data.map.map
- for unicode, index in pairs(indices) do
- local glyph = glyphs[index]
- local l = tlig_list[glyph.name]
- if l then
- local o = glyph.lookups or { }
- o["ctx_tlig_1"] = { { "ligature", l, glyph.name } }
- glyph.lookups = o
- end
- local r = trep_list[unicode]
- if r then
- local replacement = indices[r]
- if replacement then
- local o = glyph.lookups or { }
- o["ctx_trep_1"] = { { "substitution", glyphs[replacement].name } } ---
- glyph.lookups = o
- end
- end
- end
- data.gsub = data.gsub or { }
- logs.report("load otf","enhance: registering tlig feature")
- table.insert(data.gsub,1,table.fastcopy(tlig_feature))
- logs.report("load otf","enhance: registering trep feature")
- table.insert(data.gsub,1,table.fastcopy(trep_feature))
- end
-
- local prepare = otf.features.prepare.feature
- local process = otf.features.process.feature
-
- otf.tables.features['tlig'] = 'TeX Ligatures'
- otf.tables.features['trep'] = 'TeX Replacements'
-
- function fonts.initializers.node.otf.tlig(tfm,value) return prepare(tfm,'tlig',value) end
- function fonts.initializers.node.otf.trep(tfm,value) return prepare(tfm,'trep',value) end
-
- function fonts.methods.node.otf.tlig(head,font,attr) return process(head,font,attr,'tlig') end
- function fonts.methods.node.otf.trep(head,font,attr) return process(head,font,attr,'trep') end
-
- function fonts.initializers.base.otf.tlig(tfm,value) otf.features.prepare_base_substitutions(tfm,'tlig',value) end
- function fonts.initializers.base.otf.trep(tfm,value) otf.features.prepare_base_substitutions(tfm,'trep',value) end
-
-end
-
--- we need this because fonts can be bugged
-
--- \definefontfeature[calt][language=nld,script=latn,mode=node,calt=yes,clig=yes,rlig=yes]
--- \definefontfeature[dflt][language=nld,script=latn,mode=node,calt=no, clig=yes,rlig=yes]
--- \definefontfeature[fixd][language=nld,script=latn,mode=node,calt=no, clig=yes,rlig=yes,ignoredrules={44,45,47}]
-
--- \starttext
-
--- {\type{dflt:}\font\test=ZapfinoExtraLTPro*dflt at 24pt \test \char57777\char57812 c/o} \endgraf
--- {\type{calt:}\font\test=ZapfinoExtraLTPro*calt at 24pt \test \char57777\char57812 c/o} \endgraf
--- {\type{fixd:}\font\test=ZapfinoExtraLTPro*fixd at 24pt \test \char57777\char57812 c/o} \endgraf
-
--- \stoptext
-
---~ table.insert(fonts.triggers,"ignoredrules")
-
---~ function fonts.initializers.node.otf.ignoredrules(tfmdata,value)
---~ if value then
---~ -- these tests must move !
---~ tfmdata.unique = tfmdata.unique or { }
---~ tfmdata.unique.ignoredrules = tfmdata.unique.ignoredrules or { }
---~ local ignored = tfmdata.unique.ignoredrules
---~ -- value is already ok now
---~ for s in string.gmatch(value:gsub("[{}]","")..",", "%s*(.-),") do
---~ ignored[tonumber(s)] = true
---~ end
---~ end
---~ end
-
-fonts.initializers.base.otf.equaldigits = fonts.initializers.common.equaldigits
-fonts.initializers.node.otf.equaldigits = fonts.initializers.common.equaldigits
-
-fonts.initializers.base.otf.lineheight = fonts.initializers.common.lineheight
-fonts.initializers.node.otf.lineheight = fonts.initializers.common.lineheight
-
-fonts.initializers.base.otf.compose = fonts.initializers.common.compose
-fonts.initializers.node.otf.compose = fonts.initializers.common.compose
-
--- temp hack, may change
-
-function fonts.initializers.base.otf.kern(tfmdata,value)
- otf.features.prepare_base_kerns(tfmdata,'kern',value)
-end
-
--- bonus function
-
-function otf.name_to_slot(name) -- todo: afm en tfm
- local tfmdata = tfm.id[font.current()]
- if tfmdata and tfmdata.shared then
- local otfdata = tfmdata.shared.otfdata
- if otfdata and otfdata.luatex then
- local unicode = otfdata.luatex.unicodes[name]
- if type(unicode) == "number" then
- return unicode
- else
- return unicode[1]
- end
- end
- end
- return nil
-end
-
-function otf.char(n) -- todo: afm en tfm
- if type(n) == "string" then
- n = otf.name_to_slot(n)
- end
- if n then
- tex.sprint(tex.ctxcatcodes,format("\\char%s ",n))
- end
-end
-
--- Here we plug in some analyzing code (will move to font-tfm).
-
-do
-
- local glyph = node.id('glyph')
- local glue = node.id('glue')
- local penalty = node.id('penalty')
-
- local fontdata = tfm.id
- local set_attribute = node.set_attribute
- local has_attribute = node.has_attribute
- local state = attributes.numbers['state'] or 100
-
- local fcs = fonts.color.set
- local fcr = fonts.color.reset
- local remove = node.remove
-
- -- in the future we will use language/script attributes instead of the
- -- font related value, but then we also need dynamic features which is
- -- somewhat slower; and .. we need a chain of them
-
- local type = type
-
- local initializers, methods = fonts.analyzers.initializers, fonts.analyzers.methods
-
- function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
- if attr and attr > 0 then
- script, language = a_to_script[attr], a_to_language[attr]
- else
- script, language = tfmdata.script, tfmdata.language
- end
- local action = initializers[script]
- if action then
- if type(action) == "function" then
- return action(tfmdata,value)
- else
- local action = action[language]
- if action then
- return action(tfmdata,value)
- end
- end
- end
- return nil
- end
-
- function fonts.methods.node.otf.analyze(head,font,attr)
- local tfmdata = fontdata[font]
- local script, language
- if attr and attr > 0 then
- script, language = a_to_script[attr], a_to_language[attr]
- else
- script, language = tfmdata.script, tfmdata.language
- end
- local action = methods[script]
- if action then
- if type(action) == "function" then
- return action(head,font,attr)
- else
- action = action[language]
- if action then
- return action(head,font,attr)
- end
- end
- end
- return head, false
- end
-
- otf.features.register("analyze",true) -- we always analyze
- table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
-
- -- latin
-
- fonts.analyzers.methods.latn = fonts.analyzers.aux.setstate
-
- -- this info eventually will go into char-def
-
- local zwnj = 0x200C
- local zwj = 0x200D
-
- local isol = {
- [0x0621] = true, [zwnj] = true,
- }
-
- local isol_fina = {
- [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true, [0x0627] = true, [0x062F] = true,
- [0x0630] = true, [0x0631] = true, [0x0632] = true,
- [0x0648] = true, [0x0698] = true,
- [0xFEF5] = true, [0xFEF7] = true, [0xFEF9] = true, [0xFEFB] = true,
- }
-
- local isol_fina_medi_init = {
- [0x0626] = true, [0x0628] = true, [0x0629] = true, [0x062A] = true, [0x062B] = true, [0x062C] = true, [0x062D] = true, [0x062E] = true,
- [0x0633] = true, [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true, [0x0638] = true, [0x0639] = true, [0x063A] = true,
- [0x0640] = true, -- tadwil
- [0x0641] = true, [0x0642] = true, [0x0643] = true, [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true, [0x0649] = true, [0x064A] = true,
- [0x067E] = true, [0x0686] = true, [0x06AF] = true, [0x06A9] = true, [0x06CC] = true,
- [zwj] = true,
- }
-
- local arab_warned = { }
-
- local function warning(current,what)
- local char = current.char
- if not arab_warned[char] then
- log.report("analyze","arab: character %s (0x%04X) has no %s class", char, char, what)
- arab_warned[char] = true
- end
- end
-
- function fonts.analyzers.methods.nocolor(head,font,attr)
- for n in node.traverse(head,glyph) do
- if not font or n.font == font then
- fcr(n)
- end
- end
- return head, true
- end
-
- otf.remove_joiners = true -- for idris who want it as option
-
- function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local first, last, current, done = nil, nil, head, false
- local trace, removejoiners = fonts.color.trace, otf.remove_joiners
- --~ local laststate = 0
- local joiners = { }
- local function finish()
- if last then
- if first == last then
- local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- if trace then fcs(first,"font:isol") end
- else
- warning(first,"isol")
- set_attribute(first,state,0) -- error
- if trace then fcr(first) end
- end
- else
- local lc = last.char
- if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
- -- if laststate == 1 or laststate == 2 or laststate == 4 then
- set_attribute(last,state,3) -- fina
- if trace then fcs(last,"font:fina") end
- else
- warning(last,"fina")
- set_attribute(last,state,0) -- error
- if trace then fcr(last) end
- end
- end
- first, last = nil, nil
- elseif first then
- -- first and last are either both set so we never com here
- local fc = first.char
- if isol_fina_medi_init[fc] or isol_fina[fc] then
- set_attribute(first,state,4) -- isol
- if trace then fcs(first,"font:isol") end
- else
- warning(first,"isol")
- set_attribute(first,state,0) -- error
- if trace then fcr(first) end
- end
- first = nil
- end
- --~ laststate = 0
- end
- while current do
- if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then
- done = true
- -- some day we will make a characters.marks hash
- -- this is also more efficient since it's shared
- local char = current.char
- local descriptions = descriptions[char]
- if removejoiners and char == zwj or char == zwnj then
- joiners[#joiners+1] = current
- end
- if descriptions and descriptions.class == "mark" then
- set_attribute(current,state,5) -- mark
- if trace then fcs(current,"font:mark") end
- elseif isol[char] then -- can be zwj or zwnj too
- finish()
- set_attribute(current,state,4) -- isol
- if trace then fcs(current,"font:isol") end
- first, last = nil, nil
- --~ laststate = 0
- elseif not first then
- if isol_fina_medi_init[char] then
- set_attribute(current,state,1) -- init
- if trace then fcs(current,"font:init") end
- first, last = first or current, current
- --~ laststate = 1
- elseif isol_fina[char] then
- set_attribute(current,state,4) -- isol
- if trace then fcs(current,"font:isol") end
- first, last = nil, nil
- --~ laststate = 0
- else -- no arab
- finish()
- end
- elseif isol_fina_medi_init[char] then
- first, last = first or current, current
- set_attribute(current,state,2) -- medi
- if trace then fcs(current,"font:medi") end
- --~ laststate = 2
- elseif isol_fina[char] then
- -- if not laststate == 1 then
- if not has_attribute(last,state,1) then
- -- tricky, we need to check what last may be !
- set_attribute(last,state,2) -- medi
- if trace then fcs(last,"font:medi") end
- end
- set_attribute(current,state,3) -- fina
- if trace then fcs(current,"font:fina") end
- first, last = nil, nil
- --~ laststate = 0
- elseif char >= 0x0600 and char <= 0x06FF then
- if trace then fcs(current,"font:rest") end
- finish()
- else --no
- finish()
- end
- else
- finish()
- end
- current = current.next
- end
- finish()
- if removejoiners then
- for i=1,#joiners do
- head = remove(head,joiners[i])
- end
- end
- return head, done
- end
-
- -- han (chinese) (unfinished)
-
- -- this info eventually will go into char-def
-
- -- in the future we will use language/script attributes instead of the
- -- font related value, but then we also need dynamic features which is
- -- somewhat slower; and .. we need a chain of them
-
- local type = type
-
- local opening_parenthesis_hw = table.tohash { -- half width
- 0x0028,
- 0x005B,
- 0x007B,
- 0x2018, -- ‘
- 0x201C, -- “
- }
-
- local opening_parenthesis_fw = table.tohash { -- full width
- 0x3008, -- 〈 Left book quote
- 0x300A, -- 《 Left double book quote
- 0x300C, -- 「 left quote
- 0x300E, -- 『 left double quote
- 0x3010, -- 【 left double book quote
- 0x3014, -- 〔 left book quote
- 0x3016, --〖 left double book quote
- 0x3018, -- left tortoise bracket
- 0x301A, -- left square bracket
- 0x301D, -- reverse double prime qm
- 0xFF08, -- ( left parenthesis
- 0xFF3B, -- [ left square brackets
- 0xFF5B, -- { left curve bracket
- 0xFF62, -- left corner bracket
- }
-
- local closing_parenthesis_hw = table.tohash { -- half width
- 0x0029,
- 0x005D,
- 0x007D,
- 0x2019, -- ’ right quote, right
- 0x201D, -- ” right double quote
- }
-
- local closing_parenthesis_fw = table.tohash { -- full width
- 0x3009, -- 〉 book quote
- 0x300B, -- 》 double book quote
- 0x300D, -- 」 right quote, right
- 0x300F, -- 』 right double quote
- 0x3011, -- 】 right double book quote
- 0x3015, -- 〕 right book quote
- 0x3017, -- 〗 right double book quote
- 0x3019, -- right tortoise bracket
- 0x301B, -- right square bracket
- 0x301E, -- double prime qm
- 0x301F, -- low double prime qm
- 0xFF09, -- ) right parenthesis
- 0xFF3D, -- ] right square brackets
- 0xFF5D, -- } right curve brackets
- 0xFF63, -- right corner bracket
- }
-
- local opening_vertical = table.tohash {
- 0xFE35, 0xFE37, 0xFE39, 0xFE3B, 0xFE3D, 0xFE3F, 0xFE41, 0xFE43, 0xFE47,
- }
-
- local closing_vertical = table.tohash {
- 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42, 0xFE44, 0xFE48,
- }
-
- local opening_punctuation_hw = table.tohash { -- half width
- }
-
- local opening_punctuation_fw = table.tohash {
- -- 0x2236, -- ∶
- -- 0xFF0C, -- ,
- }
-
- local closing_punctuation_hw = table.tohash { -- half width
- 0x0021, -- !
- 0x002C, -- ,
- 0x002E, -- .
- 0x003A, -- :
- 0x003B, -- ;
- 0x003F, -- ?
- 0xFF61, -- hw full stop
- }
-
- local closing_punctuation_fw = table.tohash { -- full width
- 0x3001, -- 、
- 0x3002, -- 。
- 0xFF01, -- !
- 0xFF0C, -- ,
- 0xFF0E, -- .
- 0xFF1A, -- :
- 0xFF1B, -- ;
- 0xFF1F, -- ?
- }
-
- local non_starter = table.tohash { -- japanese
- 0x3005, 0x3041, 0x3043, 0x3045, 0x3047,
- 0x3049, 0x3063, 0x3083, 0x3085, 0x3087,
- 0x308E, 0x3095, 0x3096, 0x309B, 0x309C,
- 0x309D, 0x309E, 0x30A0, 0x30A1, 0x30A3,
- 0x30A5, 0x30A7, 0x30A9, 0x30C3, 0x30E3,
- 0x30E5, 0x30E7, 0x30EE, 0x30F5, 0x30F6,
- 0x30FC, 0x30FD, 0x30FE, 0x31F0, 0x31F1,
- 0x30F2, 0x30F3, 0x30F4, 0x31F5, 0x31F6,
- 0x30F7, 0x30F8, 0x30F9, 0x31FA, 0x31FB,
- 0x30FC, 0x30FD, 0x30FE, 0x31FF,
- }
-
- -- the characters below are always appear in a double form, so there
- -- will be two Chinese ellipsis characters together that denote
- -- ellipsis marks and it is not allowed to break between them
-
- local hyphenation = table.tohash {
- 0x2026, -- … ellipsis
- 0x2014, -- — hyphen
- }
-
- local function is_han_character(char)
- -- we might add such info to char-def
- return
- (char>=0x03040 and char<=0x0309F) or
- (char>=0x030A0 and char<=0x030FF) or
- (char>=0x031F0 and char<=0x031FF) or
- (char>=0x03400 and char<=0x04DFF) or
- (char>=0x04E00 and char<=0x09FFF) or
- (char>=0x0F900 and char<=0x0FAFF) or
- (char>=0x0FF00 and char<=0x0FFEF) or
- (char>=0x20000 and char<=0x2A6DF) or
- (char>=0x2F800 and char<=0x2FA1F)
- end
- -- maybe an entry in the character table: hanclass
-
- --~ opening_parenthesis_hw / closing_parenthesis_hw
- --~ opening_parenthesis_fw / closing_parenthesis_fw
- --~ opening_punctuation_hw / closing_punctuation_hw
- --~ opening_punctuation_fw / closing_punctuation_fw
-
- --~ non_starter
- --~ hyphenation
-
- --~ opening_vertical / closing_vertical
-
- fonts.analyzers.methods.stretch_hang = true
-
- fonts.analyzers.methods.hang_data = {
- inter_char_stretch_factor = 2.00, -- we started with 0.5, then 1.0
- inter_char_half_factor = 0.50, -- normally there is no reason to change this
- inter_char_half_shrink_factor = 0.25, -- normally there is no reason to change this
- }
-
- local hang_data = fonts.analyzers.methods.hang_data
-
- local insert_after, insert_before, delete = node.insert_after, node.insert_before, nodes.delete
-
- local function nobreak_before(head,current)
- local p = current.prev
- if p then
- p = p.prev
- if p and p.id == penalty then
- p.penalty = 10000
- return head, current
- end
- end
- return insert_before(head,current,nodes.penalty(10000))
- end
-
- function fonts.analyzers.methods.hani(head,font,attr)
- -- maybe make a special version with no trace
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local current, done, stretch, prevclass = head, false, 0, 0
- if fonts.analyzers.methods.stretch_hang then
- stretch = fontdata[font].parameters.quad
- end
- -- penalty before break
- local interspecialskip = - stretch * hang_data.inter_char_half_factor
- local interspecialshrink = stretch * hang_data.inter_char_half_shrink_factor
- local internormalstretch = stretch * hang_data.inter_char_stretch_factor
- local trace = fonts.color.trace
- -- todo: check for first and last
- -- maybe it's better to look back
--- we need to backtrack a glyph (also other font)
- while current do
- if current.id == glyph and current.subtype<256 then
- if current.font == font then
- local char = current.char
- if false then
- -- don't ask -)
- elseif opening_punctuation_fw[char] or opening_parenthesis_fw[char] then
- if trace then fcs(current,"font:init") end
- if head ~= current then
- head, _ = insert_before(head,current,nodes.glue(interspecialskip,0,interspecialshrink))
- end
- head, current = insert_after(head,current,nodes.penalty(10000))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- prevclass, done = 1, true
- elseif closing_punctuation_fw[char] or closing_parenthesis_fw[char] then
- if trace then fcs(current,"font:fina") end
- if prevclass > 0 then
- head, current = nobreak_before(head,current)
- head, current = insert_after(head,current,nodes.penalty(10000))
- head, current = insert_after(head,current,nodes.glue(interspecialskip,0,interspecialshrink))
- head, current = insert_after(head,current,nodes.penalty(0))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- end
- prevclass, done = 2, true
- elseif opening_punctuation_hw[char] or opening_parenthesis_hw[char] then
- if trace then fcs(current,"font:init") end
- head, current = insert_after(head,current,nodes.penalty(10000))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- prevclass, done = 3, true
- elseif closing_punctuation_hw[char] or closing_parenthesis_hw[char] then
- if trace then fcs(current,"font:fina") end
- if prevclass > 0 then
- head, current = nobreak_before(head,current)
- head, current = insert_after(head,current,nodes.penalty(0))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- end
- prevclass, done = 4, true
- elseif hyphenation[char] then
- if trace then fcs(current,"font:medi") end
- if prevclass > 0 then
- head, current = nobreak_before(head,current)
- head, current = insert_after(head,current,nodes.penalty(0))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- end
- prevclass, done = 5, true
- elseif non_starter[char] then
- if trace then fcs(current,"font:isol") end
- head, current = insert_after(head,current,nodes.penalty(10000))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- prevclass, done = 6, true
- elseif is_han_character(char) then
- -- if trace then fcs(current,"font:isol") end
- prevclass, done = 7, true
- head, current = insert_after(head,current,nodes.penalty(0))
- head, current = insert_after(head,current,nodes.glue(0,internormalstretch,0))
- end
- else
--- here we might have a mixed font
- prevclass = 0
- end
- elseif prevclass > 0 and current.id == glue and current.spec and current.spec.width > 0 then
- -- hack, it might be better to look back and flush (we need to delete end-of-line spaces)
- local next = current.next
- if next.id == glyph and next.font == font then
- head, current = delete(head,current)
- end
- end
- if current then
- current = current.next
- end
- end
- return head, done
- end
-
- fonts.analyzers.methods.hang = fonts.analyzers.methods.hani
-
-end
-
--- experimental and will probably change
-
-do
- local process = otf.features.process.feature
- local prepare = otf.features.prepare.feature
- function fonts.install_feature(type,...)
- if fonts[type] and fonts[type].install_feature then
- fonts[type].install_feature(...)
- end
- end
- function otf.install_feature(tag)
- fonts.methods.node.otf [tag] = function(head,font,attr) return process(head,font,attr,tag) end
- fonts.initializers.node.otf[tag] = function(tfm,value) return prepare(tfm,tag,value) end
- end
-end
diff --git a/tex/context/base/font-oti.lua b/tex/context/base/font-oti.lua
new file mode 100644
index 000000000..cbac6d36a
--- /dev/null
+++ b/tex/context/base/font-oti.lua
@@ -0,0 +1,57 @@
+if not modules then modules = { } end modules ['font-oti'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- i need to check features=yes|no also in relation to hashing
+
+local lower = string.lower
+
+local otf = fonts.otf
+
+otf.default_language = 'latn'
+otf.default_script = 'dflt'
+
+local languages = otf.tables.languages
+local scripts = otf.tables.scripts
+
+function otf.features.language(tfmdata,value)
+ if value then
+ value = lower(value)
+ if languages[value] then
+ tfmdata.language = value
+ end
+ end
+end
+
+function otf.features.script(tfmdata,value)
+ if value then
+ value = lower(value)
+ if scripts[value] then
+ tfmdata.script = value
+ end
+ end
+end
+
+function otf.features.mode(tfmdata,value)
+ if value then
+ tfmdata.mode = lower(value)
+ end
+end
+
+fonts.initializers.base.otf.language = otf.features.language
+fonts.initializers.base.otf.script = otf.features.script
+fonts.initializers.base.otf.mode = otf.features.mode
+fonts.initializers.base.otf.method = otf.features.mode
+
+fonts.initializers.node.otf.language = otf.features.language
+fonts.initializers.node.otf.script = otf.features.script
+fonts.initializers.node.otf.mode = otf.features.mode
+fonts.initializers.node.otf.method = otf.features.mode
+
+otf.features.register("features",true) -- we always do features
+table.insert(fonts.processors,"features") -- we need a proper function for doing this
+
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
new file mode 100644
index 000000000..113f90470
--- /dev/null
+++ b/tex/context/base/font-otn.lua
@@ -0,0 +1,2496 @@
+if not modules then modules = { } end modules ['font-otn'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is still somewhat preliminary and it will get better in due time;
+-- much functionality could only be implemented thanks to the husayni font
+-- of Idris Samawi Hamid to who we dedicate this module.
+
+-- we can use more lpegs when lpeg is extended with function args and so
+-- resolving to unicode does not gain much
+
+-- in retrospect it always looks easy but believe it or not, it took a lot
+-- of work to get proper open type support done: buggy fonts, fuzzy specs,
+-- special made testfonts, many skype sessions between taco, idris and me,
+-- torture tests etc etc ... unfortunately the code does not show how much
+-- time it took ...
+
+-- todo:
+--
+-- kerning is probably not yet ok for latin around dics nodes
+-- extension infrastructure (for usage out of context)
+-- sorting features according to vendors/renderers
+-- alternative loop quitters
+-- check cursive and r2l
+-- find out where ignore-mark-classes went
+-- remove unused tables
+-- slide tail (always glue at the end so only needed once
+-- default features (per language, script)
+-- cleanup kern(class) code, remove double info
+-- handle positions (we need example fonts)
+-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
+
+--[[ldx--
+<p>This module is a bit more split up that I'd like but since we also want to test
+with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/>
+and discussion about improvements and functionality mostly happens on the
+<l n='context'/> mailing list.</p>
+
+<p>The specification of OpenType is kind of vague. Apart from a lack of a proper
+free specifications there's also the problem that Microsoft and Adobe
+may have their own interpretation of how and in what order to apply features.
+In general the Microsoft website has more detailed specifications and is a
+better reference. There is also some information in the FontForge help files.</p>
+
+<p>Because there is so much possible, fonts might contain bugs and/or be made to
+work with certain rederers. These may evolve over time which may have the side
+effect that suddenly fonts behave differently.</p>
+
+<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
+implementation. Of course all errors are mine and of course the code can be
+improved. There are quite some optimizations going on here and processing speed
+is currently acceptable. Not all functions are implemented yet, often because I
+lack the fonts for testing. Many scripts are not yet supported either, but I will
+look into them as soon as <l n='context'/> users ask for it.</p>
+
+<p>Because there are different interpretations possible, I will extend the code
+with more (configureable) variants. I can also add hooks for users so that they can
+write their own extensions.</p>
+
+<p>Glyphs are indexed not by unicode but in their own way. This is because there is no
+relationship with unicode at all, apart from the fact that a font might cover certain
+ranges of characters. One character can have multiple shapes. However, at the
+<l n='tex'/> end we use unicode so and all extra glyphs are mapped into a private
+space. This is needed because we need to access them and <l n='tex'/> has to include
+then in the output eventually.</p>
+
+<p>The raw table as it coms from <l n='fontforge'/> gets reorganized in to fit out needs.
+In <l n='context'/> that table is packed (similar tables are shared) and cached on disk
+so that successive runs can use the optimized table (after loading the table is
+unpacked). The flattening code used later is a prelude to an even more compact table
+format (and as such it keeps evolving).</p>
+
+<p>This module is sparsely documented because it is a moving target. The table format
+of the reader changes and we experiment a lot with different methods for supporting
+features.</p>
+
+<p>As with the <l n='afm'/> code, we may decide to store more information in the
+<l n='otf'/> table.</p>
+
+<p>Incrementing the version number will force a re-cache. We jump the number by one
+when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that
+results in different tables.</p>
+--ldx]]--
+
+-- action handler chainproc chainmore comment
+--
+-- gsub_single ok ok ok
+-- gsub_multiple ok ok not implemented yet
+-- gsub_alternate ok ok not implemented yet
+-- gsub_ligature ok ok ok
+-- gsub_context ok --
+-- gsub_contextchain ok --
+-- gsub_reversecontextchain ok --
+-- chainsub -- ok
+-- reversesub -- ok
+-- gpos_mark2base ok ok
+-- gpos_mark2ligature ok ok
+-- gpos_mark2mark ok ok
+-- gpos_cursive ok untested
+-- gpos_single ok ok
+-- gpos_pair ok ok
+-- gpos_context ok --
+-- gpos_contextchain ok --
+--
+-- actions:
+--
+-- handler : actions triggered by lookup
+-- chainproc : actions triggered by contextual lookup
+-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij)
+--
+-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
+-- remark: we need to check what to do with discretionaries
+
+local concat = table.concat
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false trackers.register("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false trackers.register("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false trackers.register("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false trackers.register("otf.bugs", function(v) trace_bugs = v end)
+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)
+
+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)
+
+trackers.register("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
+trackers.register("otf.positions","otf.marks,otf.kerns,otf.cursive")
+trackers.register("otf.actions","otf.replacements,otf.positions")
+trackers.register("otf.injections","nodes.injections")
+
+trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local slide_node_list = node.slide
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local kern = node.id('kern')
+local disc = node.id('disc')
+local whatsit = node.id('whatsit')
+
+local state = attributes.private('state')
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local set_mark = nodes.set_mark
+local set_cursive = nodes.set_cursive
+local set_kern = nodes.set_kern
+local set_pair = nodes.set_pair
+
+local markonce = true
+local cursonce = true
+local kernonce = true
+
+local fontdata = fonts.ids
+
+otf.features.process = { }
+
+-- we share some vars here, after all, we have no nested lookups and
+-- less code
+
+local tfmdata = false
+local otfdata = false
+local characters = false
+local descriptions = false
+local marks = false
+local indices = false
+local unicodes = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
+
+-- we cheat a bit and assume that a font,attr combination are kind of ranged
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+local context_merged = fonts.define.specify.context_merged
+
+-- we cannot optimize with "start = first_character(head)" because then we don't
+-- know which rlmode we're in which messes up cursive handling later on
+--
+-- head is always a whatsit so we can safely assume that head is not changed
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+-- we use this for special testing and documentation
+
+local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
+local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
+local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf direct",...)
+end
+local function logwarning(...)
+ logs.report("otf direct",...)
+end
+
+local function gref(n)
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X",n)
+ end
+ elseif not n then
+ return "<error in tracing>"
+ else
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[#num+1] = format("U+%04X",ni)
+ local dni = descriptions[ni]
+ nam[#num] = (dni and dni.name) or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ end
+end
+
+local function cref(kind,chainname,chainlookupname,lookupname,index)
+ if index then
+ return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index)
+ elseif lookupname then
+ return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname)
+ elseif chainlookupname then
+ return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname)
+ elseif chainname then
+ return format("feature %s, chain %s",kind,chainname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function pref(kind,lookupname)
+ return format("feature %s, lookup %s",kind,lookupname)
+end
+
+-- we can assume that languages that use marks are not hyphenated
+-- we can also assume that at most one discretionary is present
+
+local function markstoligature(kind,lookupname,start,stop,char)
+ local n = copy_node(start)
+ local keep = start
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ return keep
+end
+
+local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
+ if start ~= stop then
+ if discfound then
+ local lignode = copy_node(start)
+ lignode.font = start.font
+ lignode.char = char
+ lignode.subtype = 2
+ start = node.do_ligature_n(start, stop, lignode)
+ if start.id == disc then
+ local prev = start.prev
+ start = start.next
+ end
+ else -- start is the ligature
+ local deletemarks = markflag ~= "mark"
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ local head = current
+ if deletemarks then
+ if trace_marks then
+ while start do
+ if marks[start.char] then
+ logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
+ end
+ start = start.next
+ end
+ end
+ else
+ local i = 0
+ while start do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ head, current = insert_node_after(head,current,copy_node(start))
+ else
+ i = i + 1
+ end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ else
+ break
+ end
+ start = start.next
+ end
+ end
+ return head
+ end
+ else
+ start.char = char
+ end
+ return start
+end
+
+function handlers.gsub_single(start,kind,lookupname,replacement)
+ if trace_singles then
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+end
+
+local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional
+ local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr
+ if value == "random" then
+ local r = math.random(1,n)
+ value, choice = format("random, choice %s",r), alternatives[r]
+ elseif value == "first" then
+ value, choice = format("first, choice %s",1), alternatives[1]
+ elseif value == "last" then
+ value, choice = format("last, choice %s",n), alternatives[n]
+ elseif type(value) ~= "number" then
+ value, choice = "default, choice 1", alternatives[1]
+ elseif value > n then
+ value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ elseif value == 0 then
+ value, choice = format("choice %s (no change)",value), start.char
+ elseif value < 1 then
+ value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ else
+ value, choice = format("choice %s",value), alternatives[value]
+ end
+ if not choice then
+ logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(start.char))
+ choice, value = start.char, format("no replacement instead of %s",value)
+ end
+ return choice, value
+end
+
+function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
+ local choice, index = alternative_glyph(start,alternative,kind,lookupname)
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),index)
+ end
+ start.char = choice
+ return start, true
+end
+
+function handlers.gsub_multiple(start,kind,lookupname,multiple)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
+ end
+ start.char = multiple[1]
+ if #multiple > 1 then
+ for k=2,#multiple do
+ local n = copy_node(start)
+ n.char = multiple[k]
+ local sn = start.next
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return start, true
+end
+
+function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
+ local s, stop, discfound = start.next, nil, false
+ if marks[start.char] then
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local startchar, stopchar = start.char, stop.char
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ end
+ return start, true
+ end
+ else
+ local skipmark = sequence.flags[1]
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ if skipmark and marks[char] then
+ s = s.next
+ else
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ end
+ else
+ break
+ end
+ elseif id == disc then
+ discfound = true
+ s = s.next
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local startchar, stopchar = start.char, stop.char
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>We get hits on a mark, but we're not sure if the it has to be applied so
+we need to explicitly test for basechar, baselig and basemark entries.</p>
+--ldx]]--
+
+function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ end
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
+ -- check chainpos variant
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start,true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start,false
+end
+
+function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to be checked
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local done = false
+ local startchar = start.char
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+end
+
+function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
+ local startchar = start.char
+ local dx, dy = set_pair(start,tfmdata.factor,rlmode,kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy)
+ end
+ return start, false
+end
+
+function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
+ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
+ -- todo: kerns in components of ligatures
+ local snext = start.next
+ if not snext then
+ return start, false
+ else
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ local krn = kerns[nextchar]
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",pref(kind,lookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+end
+
+--[[ldx--
+<p>I will implement multiple chain replacements once I run into a font that uses
+it. It's not that complex to handle.</p>
+--ldx]]--
+
+local chainmores = { }
+local chainprocs = { }
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf subchain",...)
+end
+local function logwarning(...)
+ logs.report("otf subchain",...)
+end
+
+-- ['coverage']={
+-- ['after']={ "r" },
+-- ['before']={ "q" },
+-- ['current']={ "a", "b", "c" },
+-- },
+-- ['lookups']={ "ls_l_1", "ls_l_1", "ls_l_1" },
+
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n)
+ logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf chain",...)
+end
+local function logwarning(...)
+ logs.report("otf chain",...)
+end
+
+-- We could share functions but that would lead to extra function calls with many
+-- arguments, redundant tests and confusing messages.
+
+function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname)
+ logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- The reversesub is a special case, which is why we need to store the replacements
+-- in a bit weird way. There is no lookup and the replacement comes from the lookup
+-- itself. It is meant mostly for dealing with Urdu.
+
+function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements)
+ local char = start.char
+ local replacement = replacements[char]
+ if replacement then
+ if trace_singles then
+ logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+ else
+ return start, false
+ end
+end
+
+--[[ldx--
+<p>This chain stuff is somewhat tricky since we can have a sequence of actions to be
+applied: single, alternate, multiple or ligature where ligature can be an invalid
+one in the sense that it will replace multiple by one but not neccessary one that
+looks like the combination (i.e. it is the counterpart of multiple then). For
+example, the following is valid:</p>
+
+<typing>
+<line>xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx</line>
+</typing>
+
+<p>Therefore we we don't really do the replacement here already unless we have the
+single lookup case. The efficiency of the replacements can be improved by deleting
+as less as needed but that would also mke the code even more messy.</p>
+--ldx]]--
+
+local function delete_till_stop(start,stop,ignoremarks)
+ if start ~= stop then
+ -- todo keep marks
+ local done = false
+ while not done do
+ done = start == stop
+ delete_node(start,start.next)
+ end
+ end
+end
+
+--[[ldx--
+<p>Here we replace start by a single variant, First we delete the rest of the
+match.</p>
+--ldx]]--
+
+function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ -- todo: marks ?
+ if not chainindex then
+ delete_till_stop(start,stop) -- ,currentlookup.flags[1])
+ end
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local replacement = cache.gsub_single[lookupname]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ replacement = replacement[currentchar]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
+ end
+ current.char = replacement
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+chainmores.gsub_single = chainprocs.gsub_single
+
+--[[ldx--
+<p>Here we replace start by a sequence of new glyphs. First we delete the rest of
+the match.</p>
+--ldx]]--
+
+function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ delete_till_stop(start,stop)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local replacements = cache.gsub_multiple[lookupname]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ replacements = replacements[startchar]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
+ end
+ else
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
+ end
+ local sn = start.next
+ for k=1,#replacements do
+ if k == 1 then
+ start.char = replacements[k]
+ else
+ local n = copy_node(start) -- maybe delete the components and such
+ n.char = replacements[k]
+ n.next, n.prev = sn, start
+ if sn then
+ sn.prev = n
+ end
+ start.next, start = n, n
+ end
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
+--ldx]]--
+
+function chainprocs.gsub_alternate(start,stop,kind,lookupname,currentcontext,cache,currentlookup)
+ -- todo: marks ?
+ delete_till_stop(start,stop)
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local alternatives = cache.gsub_alternate[lookupname]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ alternatives = alternatives[currentchar]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
+ end
+ else
+ local choice, index = alternative_glyph(current,alternatives,kind,chainname,chainlookupname,lookupname)
+ current.char = choice
+ if trace_alternatives then
+ logprocess("%s: replacing single %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),index,gref(currentchar),gref(choice),index)
+ end
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>When we replace ligatures we use a helper that handles the marks. I might change
+this function (move code inline and handle the marks by a separate function). We
+assume rather stupid ligatures (no complex disc nodes).</p>
+--ldx]]--
+
+function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local ligatures = cache.gsub_ligature[lookupname]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ ligatures = ligatures[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ end
+ else
+ local s, discfound, last, nofreplacements = start.next, false, stop, 0
+ while s do
+ local id = s.id
+ if id == disc then
+ s = s.next
+ discfound = true
+ else
+ local schar = s.char
+ if marks[schar] then -- marks
+ s = s.next
+ else
+ local lg = ligatures[1][schar]
+ if not lg then
+ break
+ else
+ ligatures, last, nofreplacements = lg, s, nofreplacements + 1
+ if s == stop then
+ break
+ else
+ s = s.next
+ end
+ end
+ end
+ end
+ end
+ local l2 = ligatures[2]
+ if l2 then
+ if chainindex then
+ stop = last
+ end
+ if trace_ligatures then
+ if start == stop then
+ logprocess("%s: replacing character %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ end
+ end
+ start = toligature(kind,lookup,start,stop,l2,currentlookup.flags[1],discfound)
+ return start, true, nofreplacements
+ elseif trace_bugs then
+ if start == stop then
+ logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ else
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
+ end
+ end
+ end
+ end
+ return start, false, 0
+end
+
+chainmores.gsub_ligature = chainprocs.gsub_ligature
+
+function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2base[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2ligature[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
+ end
+ return start, false
+ end
+ end
+ end
+ -- todo: like marks a ligatures hash
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname)
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2mark[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+-- ! ! ! untested ! ! !
+
+function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local exitanchors = cache.gpos_cursive[lookupname]
+ if exitanchors then
+ exitanchors = exitanchors[startchar]
+ end
+ if exitanchors then
+ local done = false
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+ end
+ return start, false
+end
+
+function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ -- untested
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_single[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local dx, dy = set_pair(start,tfmdata.factor,rlmode,kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy)
+ end
+ end
+ end
+ return start, false
+end
+
+-- when machines become faster i will make a shared function
+
+function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
+ local snext = start.next
+ if snext then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_pair[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+--~ local krn = kerns[nextchar]
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+ end
+ end
+ return start, false
+end
+
+-- what pointer to return, spec says stop
+-- to be discussed ... is bidi changer a space?
+-- elseif char == zwnj and sequence[n][32] then -- brrr
+
+-- somehow l or f is global
+-- 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 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 !)
+ for k=1,#contexts do
+ local match, current, last = true, start, start
+ local ck = contexts[k]
+ local sequence = ck[3]
+ local s = #sequence
+ if s == 1 then
+ -- never happens
+ match = current.id == glyph and current.subtype<256 and current.font == currentfont and sequence[1][current.char]
+ else
+ -- todo: better space check (maybe check for glue)
+ local f, l = ck[4], ck[5]
+ if f == l then
+ -- already a hit
+ match = true
+ else
+ -- no need to test first hit (to be optimized)
+ local n = f + 1
+ last = last.next
+ -- we cannot optimize for n=2 because there can be disc nodes
+ -- if not someskip and n == l then
+ -- -- n=2 and no skips then faster loop
+ -- match = last and last.id == glyph and last.subtype<256 and last.font == currentfont and sequence[n][last.char]
+ -- else
+ while n <= l do
+ if last then
+ local id = last.id
+ if id == glyph then
+ if last.subtype<256 and last.font == currentfont then
+ local char = last.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ last = last.next
+ elseif sequence[n][char] then
+ if n < l then
+ last = last.next
+ end
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then -- what to do with kerns?
+ last = last.next
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ end
+ -- end
+ end
+ if match and f > 1 then
+ local prev = start.prev
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = prev.id
+ if id == glyph then
+ if prev.subtype<256 and prev.font == currentfont then -- normal char
+ local char = prev.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ elseif sequence[n][char] then
+ n = n -1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif sequence[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ prev = prev.prev
+ elseif sequence[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ end
+ elseif f == 2 then
+ match = sequence[1][32]
+ else
+ for n=f-1,1 do
+ if not sequence[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ if match and s > l then
+ local current = last.next
+ if current then
+ -- removed optimiziation for s-l == 1, we have to deal with marks anyway
+ local n = l + 1
+ while n <= s do
+ if current then
+ local id = current.id
+ if id == glyph then
+ if current.subtype<256 and current.font == currentfont then -- normal char
+ local char = current.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ elseif sequence[n][char] then
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif sequence[n][32] then -- brrr
+ n = n + 1
+ else
+ match = false break
+ end
+ current = current.next
+ elseif sequence[n][32] then
+ n = n + 1
+ else
+ match = false break
+ end
+ end
+ elseif s-l == 1 then
+ match = sequence[s][32]
+ else
+ for n=l+1,s do
+ if not sequence[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ end
+ if match then
+ -- ck == currentcontext
+ if trace_contexts then
+ local rule, lookuptype, sequence, f, l = ck[1], ck[2] ,ck[3], ck[4], ck[5]
+ local char = start.char
+ if ck[9] then
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s (%s=>%s)",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
+ else
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
+ end
+ end
+ local chainlookups = ck[6]
+ if chainlookups then
+ local nofchainlookups = #chainlookups
+ -- we can speed this up if needed
+ if nofchainlookups == 1 then
+ local chainlookupname = chainlookups[1]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainprocs[chainlookup.type]
+ if cp then
+ start, done = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname)
+ else
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ else
+ -- actually this needs a more complex treatment for which we will use chainmores
+ local i = 1
+ repeat
+ local chainlookupname = chainlookups[i]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainmores[chainlookup.type]
+ if cp then
+ local ok, n
+ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i)
+ -- messy since last can be changed !
+ if ok then
+ done = true
+ start = start.next
+ if n then
+ -- skip next one(s) if ligature
+ i = i + n - 1
+ end
+ end
+ else
+ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ i = i + 1
+ until i > nofchainlookups
+ end
+ else
+ local replacements = ck[7]
+ if replacements then
+ start, done = chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements)
+ else
+ done = true -- can be meant to be skipped
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(kind,chainname))
+ end
+ end
+ end
+ end
+ end
+ return start, done
+end
+
+-- Because we want to keep this elsewhere (an because speed is less an issue) we
+-- pass the font id so that the verbose variant can access the relevant helper tables.
+
+local verbose_handle_contextchain = function(font,...)
+ logwarning("no verbose handler installed, reverting to 'normal'")
+ otf.setcontextchain()
+ return normal_handle_contextchain(...)
+end
+
+otf.chainhandlers = {
+ normal = normal_handle_contextchain,
+ verbose = verbose_handle_contextchain,
+}
+
+function otf.setcontextchain(method)
+ if not method or method == "normal" or not otf.chainhandlers[method] then
+ if handlers.contextchain then -- no need for a message while making the format
+ logwarning("installing normal contextchain handler")
+ end
+ handlers.contextchain = normal_handle_contextchain
+ else
+ logwarning("installing contextchain handler '%s'",method)
+ local handler = otf.chainhandlers[method]
+ handlers.contextchain = function(...)
+ return handler(currentfont,...)
+ end
+ end
+ handlers.gsub_context = handlers.contextchain
+ handlers.gsub_contextchain = handlers.contextchain
+ handlers.gsub_reversecontextchain = handlers.contextchain
+ handlers.gpos_contextchain = handlers.contextchain
+ handlers.gpos_context = handlers.contextchain
+end
+
+otf.setcontextchain()
+
+local missing = { } -- we only report once
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf process",...)
+end
+local function logwarning(...)
+ logs.report("otf process",...)
+end
+
+local function report_missing_cache(typ,lookup)
+ local f = missing[currentfont] if not f then f = { } missing[currentfont] = f end
+ local t = f[typ] if not t then t = { } f[typ] = t end
+ if not t[lookup] then
+ t[lookup] = true
+ logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname)
+ end
+end
+
+local resolved = { } -- we only resolve a font,script,language pair once
+
+function fonts.methods.node.otf.features(head,font,attr)
+ if trace_steps then
+ checkstep(head)
+ end
+ tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ otfdata = shared.otfdata
+ local luatex = otfdata.luatex
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ indices = tfmdata.indices
+ unicodes = tfmdata.unicodes
+ marks = tfmdata.marks
+ anchorlookups = luatex.lookup_to_anchor
+ currentfont = font
+ rlmode = 0
+ local featuredata = otfdata.shared.featuredata -- can be made local to closure
+ local sequences = luatex.sequences
+ lookuptable = luatex.lookups
+ local done = false
+ local script, language, s_enabled, a_enabled, dyn
+ local attribute_driven = attr and attr ~= 0
+ if attribute_driven then
+ local features = context_setups[context_numbers[attr]] -- could be a direct list
+ dyn = context_merged[attr] or 0
+ language, script = features.language or "dflt", features.script or "dflt"
+ a_enabled = features -- shared.features -- can be made local to the resolver
+ if dyn == 2 or dyn == -2 then
+ -- font based
+ s_enabled = shared.features
+ end
+ else
+ language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
+ s_enabled = shared.features -- can be made local to the resolver
+ dyn = 0
+ end
+ -- we can save some runtime by caching feature tests
+ local res = resolved[font] if not res then res = { } resolved[font] = res end
+ local rs = res [script] if not rs then rs = { } res [script] = rs end
+ local rl = rs [language] if not rl then rl = { } rs [language] = rl end
+ local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
+ -- sequences always > 1 so no need for optimization
+ for s=1,#sequences do
+ local success = false
+ local sequence = sequences[s]
+ local r = ra[s] -- cache
+ if r == nil then
+ --
+ -- this bit will move to font-ctx and become a function
+ ---
+ local chain = sequence.chain or 0
+ local features = sequence.features
+ if not features then
+ -- indirect lookup, part of chain (todo: make this a separate table)
+ r = false -- { false, false, chain }
+ else
+ local valid, attribute, kind, what = false, false
+ for k,v in next, features do
+ -- we can quit earlier but for the moment we want the tracing
+ local s_e = s_enabled and s_enabled[k]
+ local a_e = a_enabled and a_enabled[k]
+ if s_e or a_e then
+ local l = v[script] or v[wildcard]
+ if l then
+ -- not l[language] or l[default] or l[wildcard] because we want tracing
+ -- only first attribute match check, so we assume simple fina's
+ -- default can become a font feature itself
+ if l[language] then
+--~ valid, what = true, language
+ valid, what = s_e or a_e, language
+ -- elseif l[default] then
+ -- valid, what = true, default
+ elseif l[wildcard] then
+--~ valid, what = true, wildcard
+ valid, what = s_e or a_e, wildcard
+ end
+ if valid then
+ kind, attribute = k, special_attributes[k] or false
+ if a_e and dyn < 0 then
+ valid = false
+ end
+ if trace_applied then
+ local typ, action = match(sequence.type,"(.*)_(.*)")
+ logs.report("otf node mode",
+ "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
+ (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
+ end
+ break
+ end
+ end
+ end
+ end
+ if valid then
+ r = { valid, attribute, chain, kind }
+ else
+ r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
+ end
+ end
+ ra[s] = r
+ end
+featurevalue = r and r[1] -- toto: pass to function instead
+ if featurevalue then
+ local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables
+ if chain < 0 then
+ -- this is a limited case, no special treatments like 'init' etc
+ local handler = handlers[typ]
+ local thecache = featuredata[typ] or { }
+ -- we need to get rid of this slide !
+ start = slide_node_list(head) -- slow (we can store tail because there's always a skip at the end): todo
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
+ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
+ for i=1,#subtables do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if success then
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.prev end
+ else
+ start = start.prev
+ end
+ else
+ start = start.prev
+ end
+ end
+ else
+ local handler = handlers[typ]
+ local ns = #subtables
+ local thecache = featuredata[typ] or { }
+ start = head -- local ?
+ rlmode = 0
+ if ns == 1 then
+ local lookupname = subtables[1]
+ local lookupcache = thecache[lookupname]
+ if not lookupcache then
+ report_missing_cache(typ,lookupname)
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+ if ok then
+ success = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" then
+ rlmode = -1
+ elseif dir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlmode = -1
+ elseif dir == "TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+
+ end
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if ok then
+ success = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" then
+ rlmode = -1
+ elseif dir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlmode = -1
+ elseif dir == "TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+ end
+ end
+ if success then
+ done = true
+ end
+ if trace_steps then -- ?
+ registerstep(head)
+ end
+ end
+ end
+ return head, done
+end
+
+otf.features.prepare = { }
+
+-- we used to share code in the following functions but that costs a lot of
+-- memory due to extensive calls to functions (easily hundreds of thousands per
+-- document)
+
+local function split(replacement,original,cache,unicodes)
+ -- we can cache this too, but not the same
+ local o, t, n = { }, { }, 0
+ for s in gmatch(original,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then
+ o[#o+1] = us
+ else
+ o[#o+1] = us[1]
+ end
+ end
+ for s in gmatch(replacement,"[^ ]+") do
+ n = n + 1
+ local us = unicodes[s]
+ if type(us) == "number" then
+ t[o[n]] = us
+ else
+ t[o[n]] = us[1]
+ end
+ end
+ return t
+end
+
+local function uncover(covers,result,cache,unicodes)
+ -- lpeg hardly faster (.005 sec on mk)
+ for n=1,#covers do
+ local c = covers[n]
+ local cc = cache[c]
+ if not cc then
+ local t = { }
+ for s in gmatch(c,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then
+ t[us] = true
+ else
+ for i=1,#us do
+ t[us[i]] = true
+ end
+ end
+ end
+ cache[c] = t
+ result[#result+1] = t
+ else
+ result[#result+1] = cc
+ end
+ end
+end
+
+local function prepare_lookups(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ local anchor_to_lookup = otfdata.luatex.anchor_to_lookup
+ local lookup_to_anchor = otfdata.luatex.lookup_to_anchor
+ --
+ local multiple = featuredata.gsub_multiple
+ local alternate = featuredata.gsub_alternate
+ local single = featuredata.gsub_single
+ local ligature = featuredata.gsub_ligature
+ local pair = featuredata.gpos_pair
+ local position = featuredata.gpos_single
+ local kerns = featuredata.gpos_pair
+ local mark = featuredata.gpos_mark2mark
+ local cursive = featuredata.gpos_cursive
+ --
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local descriptions = tfmdata.descriptions
+ --
+ -- we can change the otf table after loading but then we need to adapt base mode
+ -- as well (no big deal)
+ --
+ for unicode, glyph in next, descriptions do
+ local lookups = glyph.lookups
+ if lookups then
+ for lookup, whatever in next, lookups do
+ for i=1,#whatever do -- normaly one
+ local p = whatever[i]
+ local what = p[1]
+ if what == 'substitution' then
+ local old, new = unicode, unicodes[p[2]]
+ if type(new) == "table" then
+ new = new[1]
+ end
+ local s = single[lookup]
+ if not s then s = { } single[lookup] = s end
+ s[old] = new
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: substitution %s => %s",lookup,old,new)
+--~ end
+ break
+ elseif what == 'multiple' then
+ local old, new = unicode, { }
+ local m = multiple[lookup]
+ if not m then m = { } multiple[lookup] = m end
+ m[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: multiple %s => %s",lookup,old,concat(new," "))
+--~ end
+ break
+ elseif what == 'alternate' then
+ local old, new = unicode, { }
+ local a = alternate[lookup]
+ if not a then a = { } alternate[lookup] = a end
+ a[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
+--~ end
+ break
+ elseif what == "ligature" then
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
+--~ end
+ local first = true
+ local t = ligature[lookup]
+ if not t then t = { } ligature[lookup] = t end
+ for s in gmatch(p[2],"[^ ]+") do
+ if first then
+ local u = unicodes[s]
+ if not u then
+ logs.report("define otf","lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name)
+ break
+ elseif type(u) == "number" then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ t = t[u]
+ else
+ local tt = t
+ local tu
+ for i=1,#u do
+ local u = u[i]
+ if i==1 then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ tu = t[u]
+ t = tu
+ else
+ if not t[u] then
+ tt[u] = tu
+ end
+ end
+ end
+ end
+ first = false
+ else
+ s = unicodes[s]
+ local t1 = t[1]
+ if not t1[s] then
+ t1[s] = { { } }
+ end
+ t = t1[s]
+ end
+ end
+ t[2] = unicode
+ elseif what == 'position' then
+ -- not used
+ local s = position[lookup]
+ if not s then s = { } position[lookup] = s end
+ s[unicode] = p[2] -- direct pointer to kern spec
+ elseif what == 'pair' then
+ local s = pair[lookup]
+ if not s then s = { } pair[lookup] = s end
+ local others = s[unicode]
+ if not others then others = { } s[unicode] = others end
+ -- todo: fast check for space
+ local two = p[2]
+ local upc = unicodes[two]
+ if not upc then
+ for pc in gmatch(two,"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+ end
+ elseif type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: pair for U+%04X",lookup,unicode)
+--~ end
+ end
+ end
+ end
+ end
+ local list = glyph.mykerns
+ if list then
+ for lookup, krn in next, list do
+ local k = kerns[lookup]
+ if not k then k = { } kerns[lookup] = k end
+ k[unicode] = krn -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: kern for U+%04X",lookup,unicode)
+--~ end
+ end
+ end
+ local oanchor = glyph.anchors
+ if oanchor then
+ for typ, anchors in next, oanchor do -- types
+ if typ == "mark" then
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = mark[lookup]
+ if not f then f = { } mark[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
+--~ end
+ end
+ end
+ end
+ elseif typ == "cexit" then -- or entry?
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = cursive[lookup]
+ if not f then f = { } cursive[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
+--~ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- local cache = { }
+luatex = luatex or {} -- this has to change ... we need a better one
+
+function prepare_contextchains(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local lookups = otfdata.lookups
+ if lookups then
+ local featuredata = otfdata.shared.featuredata
+ local contextchain = featuredata.gsub_contextchain -- shared with gpos
+ local reversecontextchain = featuredata.gsub_reversecontextchain -- shared with gpos
+ local characters = tfmdata.characters
+ local unicodes = tfmdata.unicodes
+ local indices = tfmdata.indices
+ local cache = luatex.covers
+ if not cache then
+ cache = { }
+ luatex.covers = cache
+ end
+ --
+ for lookupname, lookupdata in next, otfdata.lookups do
+ local lookuptype = lookupdata.type
+ if not lookuptype then
+ logs.report("otf process","missing lookuptype for %s",lookupname)
+ else
+ local rules = lookupdata.rules
+ if rules then
+ local fmt = lookupdata.format
+ -- contextchain[lookupname][unicode]
+ if fmt == "coverage" then
+ if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = contextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ contextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do -- does #rules>1 happen often?
+ local rule = rules[nofrules]
+ local coverage = rule.coverage
+ if coverage and coverage.current then
+ local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if sequence[1] then
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif fmt == "reversecoverage" then
+ if lookuptype ~= "reversesub" then
+ logs.report("otf process","unsupported reverse coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = reversecontextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ reversecontextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do
+ local rule = rules[nofrules]
+ local reversecoverage = rule.reversecoverage
+ if reversecoverage and reversecoverage.current then
+ local current, before, after, replacements, sequence = reversecoverage.current, reversecoverage.before, reversecoverage.after, reversecoverage.replacements, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if replacements then
+ replacements = split(replacements,current[1],cache,unicodes)
+ end
+ if sequence[1] then
+ -- this is different from normal coverage, we assume only replacements
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function fonts.initializers.node.otf.features(tfmdata,value)
+ if true then -- value then
+ if not tfmdata.shared.otfdata.shared.initialized then
+ local t = trace_preparing and os.clock()
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ -- caches
+ featuredata.gsub_multiple = { }
+ featuredata.gsub_alternate = { }
+ featuredata.gsub_single = { }
+ featuredata.gsub_ligature = { }
+ featuredata.gsub_contextchain = { }
+ featuredata.gsub_reversecontextchain = { }
+ featuredata.gpos_pair = { }
+ featuredata.gpos_single = { }
+ featuredata.gpos_mark2base = { }
+ featuredata.gpos_mark2ligature = featuredata.gpos_mark2base
+ featuredata.gpos_mark2mark = featuredata.gpos_mark2base
+ featuredata.gpos_cursive = { }
+ featuredata.gpos_contextchain = featuredata.gsub_contextchain
+ featuredata.gpos_reversecontextchain = featuredata.gsub_reversecontextchain
+ --
+ prepare_contextchains(tfmdata)
+ prepare_lookups(tfmdata)
+ otfdata.shared.initialized = true
+ if trace_preparing then
+ logs.report("otf process","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+ end
+end
diff --git a/tex/context/base/font-otp.lua b/tex/context/base/font-otp.lua
new file mode 100644
index 000000000..3cdc80737
--- /dev/null
+++ b/tex/context/base/font-otp.lua
@@ -0,0 +1,420 @@
+if not modules then modules = { } end modules ['font-otp'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (packing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: pack math (but not that much to share)
+
+local next = next
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+fonts.otf.enhancers = fonts.otf.enhancers or { }
+fonts.otf.glists = fonts.otf.glists or { "gsub", "gpos" }
+
+local criterium, threshold, tabstr = 1, 0, table.serialize
+
+function fonts.otf.enhancers.pack(data)
+ if data then
+ local h, t, c = { }, { }, { }
+ local hh, tt, cc = { }, { }, { }
+ local function pack_1(v)
+ -- v == table
+ local tag = tabstr(v)
+ local ht = h[tag]
+ if not ht then
+ ht = #t+1
+ t[ht] = v
+ h[tag] = ht
+ c[ht] = 1
+ else
+ c[ht] = c[ht] + 1
+ end
+ return ht
+ end
+ local function pack_2(v)
+ -- v == number
+ if c[v] <= criterium then
+ return t[v]
+ else
+ -- compact hash
+ local hv = hh[v]
+ if not hv then
+ hv = #tt+1
+ tt[hv] = t[v]
+ hh[v] = hv
+ cc[hv] = c[v]
+ end
+ return hv
+ end
+ end
+ local function success(stage,pass)
+ if #t == 0 then
+ if trace_loading then
+ logs.report("load otf","pack quality: nothing to pack")
+ end
+ return false
+ elseif #t >= threshold then
+ local one, two, rest = 0, 0, 0
+ if pass == 1 then
+ for k,v in next, c do
+ if v == 1 then
+ one = one + 1
+ elseif v == 2 then
+ two = two + 1
+ else
+ rest = rest + 1
+ end
+ end
+ else
+ for k,v in next, cc do
+ if v >20 then
+ rest = rest + 1
+ elseif v >10 then
+ two = two + 1
+ else
+ one = one + 1
+ end
+ end
+ data.tables = tt
+ end
+ if trace_loading then
+ logs.report("load otf","pack quality: stage %s, pass %s, %s packed, 1-10:%s, 11-20:%s, rest:%s (criterium: %s)", stage, pass, one+two+rest, one, two, rest, criterium)
+ end
+ return true
+ else
+ if trace_loading then
+ logs.report("load otf","pack quality: stage %s, pass %s, %s packed, aborting pack (threshold: %s)", stage, pass, #t, threshold)
+ end
+ return false
+ end
+ end
+ for pass=1,2 do
+ local pack = (pass == 1 and pack_1) or pack_2
+ for k, v in next, data.glyphs do
+ v.boundingbox = pack(v.boundingbox)
+ local l = v.lookups
+ if l then
+ for k,v in next, l do
+ for kk=1,#v do
+ local vkk = v[kk]
+ local what = vkk[1]
+ if what == "pair" then
+ local t = vkk[3] if t then vkk[3] = pack(t) end
+ local t = vkk[4] if t then vkk[4] = pack(t) end
+ elseif what == "position" then
+ local t = vkk[2] if t then vkk[2] = pack(t) end
+ end
+ -- v[kk] = pack(vkk)
+ end
+ end
+ end
+ local m = v.mykerns
+ if m then
+ for k,v in next, m do
+ m[k] = pack(v)
+ end
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ for k,v in next, mk do
+ mk[k] = pack(v)
+ end
+ end
+ end
+ local a = v.anchors
+ if a then
+ for k,v in next, a do
+ if k == "baselig" then
+ for kk, vv in next, v do
+ for kkk=1,#vv do
+ vv[kkk] = pack(vv[kkk])
+ end
+ end
+ else
+ for kk, vv in next, v do
+ v[kk] = pack(vv)
+ end
+ end
+ end
+ end
+ end
+ if data.lookups then
+ for k, v in next, data.lookups do
+ if v.rules then
+ for kk, vv in next, v.rules do
+ local l = vv.lookups
+ if l then
+ vv.lookups = pack(l)
+ end
+ local c = vv.coverage
+ if c then
+ c.before = c.before and pack(c.before )
+ c.after = c.after and pack(c.after )
+ c.current = c.current and pack(c.current)
+ end
+ local c = vv.reversecoverage
+ if c then
+ c.before = c.before and pack(c.before )
+ c.after = c.after and pack(c.after )
+ c.current = c.current and pack(c.current)
+ end
+ end
+ end
+ end
+ end
+ if data.luatex then
+ local la = data.luatex.anchor_to_lookup
+ if la then
+ for lookup, ldata in next, la do
+ la[lookup] = pack(ldata)
+ end
+ end
+ local la = data.luatex.lookup_to_anchor
+ if la then
+ for lookup, ldata in next, la do
+ la[lookup] = pack(ldata)
+ end
+ end
+ local ls = data.luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ fdata.flags = pack(flags)
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ fdata.subtables = pack(subtables)
+ end
+ local features = fdata.features
+ if features then
+ for script, sdata in next, features do
+ features[script] = pack(sdata)
+ end
+ end
+ end
+ end
+ local ls = data.luatex.lookups
+ if ls then
+ for lookup, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ fdata.flags = pack(flags)
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ fdata.subtables = pack(subtables)
+ end
+ end
+ end
+ local lf = data.luatex.features
+ if lf then
+ for _, g in next, fonts.otf.glists do
+ local gl = lf[g]
+ if gl then
+ for feature, spec in next, gl do
+ gl[feature] = pack(spec)
+ end
+ end
+ end
+ end
+ end
+ if not success(1,pass) then
+ return
+ end
+ end
+ if #t > 0 then
+ for pass=1,2 do
+ local pack = (pass == 1 and pack_1) or pack_2
+ for k, v in next, data.glyphs do
+ local m = v.mykerns
+ if m then
+ v.mykerns = pack(m)
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ m.kerns = pack(mk)
+ end
+ end
+ local a = v.anchors
+ if a then
+ v.anchors = pack(a)
+ end
+ local l = v.lookups
+ if l then
+ for k,v in next, l do
+ for kk=1,#v do
+ v[kk] = pack(v[kk])
+ end
+ end
+ end
+ end
+ local ls = data.luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ fdata.features = pack(fdata.features)
+ end
+ end
+ if not success(2,pass) then
+--~ return
+ end
+ end
+ end
+ end
+end
+
+function fonts.otf.enhancers.unpack(data)
+ if data then
+ local t = data.tables
+ if t then
+ for k, v in next, data.glyphs do
+ local tv = t[v.boundingbox] if tv then v.boundingbox = tv end
+ local l = v.lookups
+ if l then
+ for k,v in next, l do
+ for i=1,#v do
+ local tv = t[v[i]] if tv then v[i] = tv end
+ local vi = v[i]
+ local what = vi[1]
+ if what == "pair" then
+ local tv = t[vi[3]] if tv then vi[3] = tv end
+ local tv = t[vi[4]] if tv then vi[4] = tv end
+ elseif what == "position" then
+ local tv = t[vi[2]] if tv then vi[2] = tv end
+ end
+ end
+ end
+ end
+ local m = v.mykerns
+ if m then
+ local tv = t[m] if tv then m = tv v.mykerns = m end -- secondary optimization
+ for k,v in next, m do
+ local tv = t[v] if tv then m[k] = tv end
+ end
+ end
+ local m = v.math
+ if m then
+ local mk = m.kerns
+ if mk then
+ local tv = t[mk] if tv then mk = tv m.kerns = mk end -- secondary optimization
+ for k,v in next, mk do
+ local tv = t[v] if tv then mk[k] = tv end
+ end
+ end
+ end
+ local a = v.anchors
+ if a then
+ local tv = t[a] if tv then a = tv v.anchors = a end -- secondary optimization
+ for k,v in next, a do
+ if k == "baselig" then
+ for kk, vv in next, v do
+ for kkk=1,#vv do
+ local tv = t[vv[kkk]] if tv then vv[kkk] = tv end
+ end
+ end
+ else
+ for kk, vv in next, v do
+ local tv = t[vv] if tv then v[kk] = tv end
+ end
+ end
+ end
+ end
+ end
+ if data.lookups then
+ for k, v in next, data.lookups do
+ local r = v.rules
+ if r then
+ for kk, vv in next, r do
+ local l = vv.lookups
+ if l then
+ local tv = t[l] if tv then vv.lookups = tv end
+ end
+ local c = vv.coverage
+ if c then
+ local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
+ cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
+ cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ end
+ local c = vv.reversecoverage
+ if c then
+ local cc = c.before if cc then local tv = t[cc] if tv then c.before = tv end end
+ cc = c.after if cc then local tv = t[cc] if tv then c.after = tv end end
+ cc = c.current if cc then local tv = t[cc] if tv then c.current = tv end end
+ end
+ end
+ end
+ end
+ end
+ local luatex = data.luatex
+ if luatex then
+ local la = luatex.anchor_to_lookup
+ if la then
+ for lookup, ldata in next, la do
+ local tv = t[ldata] if tv then la[lookup] = tv end
+ end
+ end
+ local la = luatex.lookup_to_anchor
+ if la then
+ for lookup, ldata in next, la do
+ local tv = t[ldata] if tv then la[lookup] = tv end
+ end
+ end
+ local ls = luatex.sequences
+ if ls then
+ for feature, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ local tv = t[flags] if tv then fdata.flags = tv end
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ local features = fdata.features
+ if features then
+ local tv = t[features] if tv then fdata.features = tv features = tv end -- secondary pack
+ for script, sdata in next, features do
+ local tv = t[sdata] if tv then features[script] = tv end
+ end
+ end
+ end
+ end
+ local ls = luatex.lookups
+ if ls then
+ for lookups, fdata in next, ls do
+ local flags = fdata.flags
+ if flags then
+ local tv = t[flags] if tv then fdata.flags = tv end
+ end
+ local subtables = fdata.subtables
+ if subtables then
+ local tv = t[subtables] if tv then fdata.subtables = tv end
+ end
+ end
+ end
+ local lf = luatex.features
+ if lf then
+ for _, g in next, fonts.otf.glists do
+ local gl = lf[g]
+ if gl then
+ for feature, spec in next, gl do
+ local tv = t[spec] if tv then gl[feature] = tv end
+ end
+ end
+ end
+ end
+ end
+ data.tables = nil
+ end
+ end
+end
diff --git a/tex/context/base/font-ott.lua b/tex/context/base/font-ott.lua
new file mode 100644
index 000000000..6676ff64b
--- /dev/null
+++ b/tex/context/base/font-ott.lua
@@ -0,0 +1,935 @@
+if not modules then modules = { } end modules ['font-otf'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (tables)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local gsub, lower = string.gsub, string.lower
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+
+otf.tables = otf.tables or { }
+otf.meanings = otf.meanings or { }
+
+otf.tables.scripts = {
+ ['dflt'] = 'Default',
+
+ ['arab'] = 'Arabic',
+ ['armn'] = 'Armenian',
+ ['bali'] = 'Balinese',
+ ['beng'] = 'Bengali',
+ ['bopo'] = 'Bopomofo',
+ ['brai'] = 'Braille',
+ ['bugi'] = 'Buginese',
+ ['buhd'] = 'Buhid',
+ ['byzm'] = 'Byzantine Music',
+ ['cans'] = 'Canadian Syllabics',
+ ['cher'] = 'Cherokee',
+ ['copt'] = 'Coptic',
+ ['cprt'] = 'Cypriot Syllabary',
+ ['cyrl'] = 'Cyrillic',
+ ['deva'] = 'Devanagari',
+ ['dsrt'] = 'Deseret',
+ ['ethi'] = 'Ethiopic',
+ ['geor'] = 'Georgian',
+ ['glag'] = 'Glagolitic',
+ ['goth'] = 'Gothic',
+ ['grek'] = 'Greek',
+ ['gujr'] = 'Gujarati',
+ ['guru'] = 'Gurmukhi',
+ ['hang'] = 'Hangul',
+ ['hani'] = 'CJK Ideographic',
+ ['hano'] = 'Hanunoo',
+ ['hebr'] = 'Hebrew',
+ ['ital'] = 'Old Italic',
+ ['jamo'] = 'Hangul Jamo',
+ ['java'] = 'Javanese',
+ ['kana'] = 'Hiragana and Katakana',
+ ['khar'] = 'Kharosthi',
+ ['khmr'] = 'Khmer',
+ ['knda'] = 'Kannada',
+ ['lao' ] = 'Lao',
+ ['latn'] = 'Latin',
+ ['limb'] = 'Limbu',
+ ['linb'] = 'Linear B',
+ ['math'] = 'Mathematical Alphanumeric Symbols',
+ ['mlym'] = 'Malayalam',
+ ['mong'] = 'Mongolian',
+ ['musc'] = 'Musical Symbols',
+ ['mymr'] = 'Myanmar',
+ ['nko' ] = "N'ko",
+ ['ogam'] = 'Ogham',
+ ['orya'] = 'Oriya',
+ ['osma'] = 'Osmanya',
+ ['phag'] = 'Phags-pa',
+ ['phnx'] = 'Phoenician',
+ ['runr'] = 'Runic',
+ ['shaw'] = 'Shavian',
+ ['sinh'] = 'Sinhala',
+ ['sylo'] = 'Syloti Nagri',
+ ['syrc'] = 'Syriac',
+ ['tagb'] = 'Tagbanwa',
+ ['tale'] = 'Tai Le',
+ ['talu'] = 'Tai Lu',
+ ['taml'] = 'Tamil',
+ ['telu'] = 'Telugu',
+ ['tfng'] = 'Tifinagh',
+ ['tglg'] = 'Tagalog',
+ ['thaa'] = 'Thaana',
+ ['thai'] = 'Thai',
+ ['tibt'] = 'Tibetan',
+ ['ugar'] = 'Ugaritic Cuneiform',
+ ['xpeo'] = 'Old Persian Cuneiform',
+ ['xsux'] = 'Sumero-Akkadian Cuneiform',
+ ['yi' ] = 'Yi'
+}
+
+otf.tables.languages = {
+ ['dflt'] = 'Default',
+
+ ['aba'] = 'Abaza',
+ ['abk'] = 'Abkhazian',
+ ['ady'] = 'Adyghe',
+ ['afk'] = 'Afrikaans',
+ ['afr'] = 'Afar',
+ ['agw'] = 'Agaw',
+ ['als'] = 'Alsatian',
+ ['alt'] = 'Altai',
+ ['amh'] = 'Amharic',
+ ['ara'] = 'Arabic',
+ ['ari'] = 'Aari',
+ ['ark'] = 'Arakanese',
+ ['asm'] = 'Assamese',
+ ['ath'] = 'Athapaskan',
+ ['avr'] = 'Avar',
+ ['awa'] = 'Awadhi',
+ ['aym'] = 'Aymara',
+ ['aze'] = 'Azeri',
+ ['bad'] = 'Badaga',
+ ['bag'] = 'Baghelkhandi',
+ ['bal'] = 'Balkar',
+ ['bau'] = 'Baule',
+ ['bbr'] = 'Berber',
+ ['bch'] = 'Bench',
+ ['bcr'] = 'Bible Cree',
+ ['bel'] = 'Belarussian',
+ ['bem'] = 'Bemba',
+ ['ben'] = 'Bengali',
+ ['bgr'] = 'Bulgarian',
+ ['bhi'] = 'Bhili',
+ ['bho'] = 'Bhojpuri',
+ ['bik'] = 'Bikol',
+ ['bil'] = 'Bilen',
+ ['bkf'] = 'Blackfoot',
+ ['bli'] = 'Balochi',
+ ['bln'] = 'Balante',
+ ['blt'] = 'Balti',
+ ['bmb'] = 'Bambara',
+ ['bml'] = 'Bamileke',
+ ['bos'] = 'Bosnian',
+ ['bre'] = 'Breton',
+ ['brh'] = 'Brahui',
+ ['bri'] = 'Braj Bhasha',
+ ['brm'] = 'Burmese',
+ ['bsh'] = 'Bashkir',
+ ['bti'] = 'Beti',
+ ['cat'] = 'Catalan',
+ ['ceb'] = 'Cebuano',
+ ['che'] = 'Chechen',
+ ['chg'] = 'Chaha Gurage',
+ ['chh'] = 'Chattisgarhi',
+ ['chi'] = 'Chichewa',
+ ['chk'] = 'Chukchi',
+ ['chp'] = 'Chipewyan',
+ ['chr'] = 'Cherokee',
+ ['chu'] = 'Chuvash',
+ ['cmr'] = 'Comorian',
+ ['cop'] = 'Coptic',
+ ['cos'] = 'Corsican',
+ ['cre'] = 'Cree',
+ ['crr'] = 'Carrier',
+ ['crt'] = 'Crimean Tatar',
+ ['csl'] = 'Church Slavonic',
+ ['csy'] = 'Czech',
+ ['dan'] = 'Danish',
+ ['dar'] = 'Dargwa',
+ ['dcr'] = 'Woods Cree',
+ ['deu'] = 'German',
+ ['dgr'] = 'Dogri',
+ ['div'] = 'Divehi',
+ ['djr'] = 'Djerma',
+ ['dng'] = 'Dangme',
+ ['dnk'] = 'Dinka',
+ ['dri'] = 'Dari',
+ ['dun'] = 'Dungan',
+ ['dzn'] = 'Dzongkha',
+ ['ebi'] = 'Ebira',
+ ['ecr'] = 'Eastern Cree',
+ ['edo'] = 'Edo',
+ ['efi'] = 'Efik',
+ ['ell'] = 'Greek',
+ ['eng'] = 'English',
+ ['erz'] = 'Erzya',
+ ['esp'] = 'Spanish',
+ ['eti'] = 'Estonian',
+ ['euq'] = 'Basque',
+ ['evk'] = 'Evenki',
+ ['evn'] = 'Even',
+ ['ewe'] = 'Ewe',
+ ['fan'] = 'French Antillean',
+ ['far'] = 'Farsi',
+ ['fin'] = 'Finnish',
+ ['fji'] = 'Fijian',
+ ['fle'] = 'Flemish',
+ ['fne'] = 'Forest Nenets',
+ ['fon'] = 'Fon',
+ ['fos'] = 'Faroese',
+ ['fra'] = 'French',
+ ['fri'] = 'Frisian',
+ ['frl'] = 'Friulian',
+ ['fta'] = 'Futa',
+ ['ful'] = 'Fulani',
+ ['gad'] = 'Ga',
+ ['gae'] = 'Gaelic',
+ ['gag'] = 'Gagauz',
+ ['gal'] = 'Galician',
+ ['gar'] = 'Garshuni',
+ ['gaw'] = 'Garhwali',
+ ['gez'] = "Ge'ez",
+ ['gil'] = 'Gilyak',
+ ['gmz'] = 'Gumuz',
+ ['gon'] = 'Gondi',
+ ['grn'] = 'Greenlandic',
+ ['gro'] = 'Garo',
+ ['gua'] = 'Guarani',
+ ['guj'] = 'Gujarati',
+ ['hai'] = 'Haitian',
+ ['hal'] = 'Halam',
+ ['har'] = 'Harauti',
+ ['hau'] = 'Hausa',
+ ['haw'] = 'Hawaiin',
+ ['hbn'] = 'Hammer-Banna',
+ ['hil'] = 'Hiligaynon',
+ ['hin'] = 'Hindi',
+ ['hma'] = 'High Mari',
+ ['hnd'] = 'Hindko',
+ ['ho'] = 'Ho',
+ ['hri'] = 'Harari',
+ ['hrv'] = 'Croatian',
+ ['hun'] = 'Hungarian',
+ ['hye'] = 'Armenian',
+ ['ibo'] = 'Igbo',
+ ['ijo'] = 'Ijo',
+ ['ilo'] = 'Ilokano',
+ ['ind'] = 'Indonesian',
+ ['ing'] = 'Ingush',
+ ['inu'] = 'Inuktitut',
+ ['iri'] = 'Irish',
+ ['irt'] = 'Irish Traditional',
+ ['isl'] = 'Icelandic',
+ ['ism'] = 'Inari Sami',
+ ['ita'] = 'Italian',
+ ['iwr'] = 'Hebrew',
+ ['jan'] = 'Japanese',
+ ['jav'] = 'Javanese',
+ ['jii'] = 'Yiddish',
+ ['jud'] = 'Judezmo',
+ ['jul'] = 'Jula',
+ ['kab'] = 'Kabardian',
+ ['kac'] = 'Kachchi',
+ ['kal'] = 'Kalenjin',
+ ['kan'] = 'Kannada',
+ ['kar'] = 'Karachay',
+ ['kat'] = 'Georgian',
+ ['kaz'] = 'Kazakh',
+ ['keb'] = 'Kebena',
+ ['kge'] = 'Khutsuri Georgian',
+ ['kha'] = 'Khakass',
+ ['khk'] = 'Khanty-Kazim',
+ ['khm'] = 'Khmer',
+ ['khs'] = 'Khanty-Shurishkar',
+ ['khv'] = 'Khanty-Vakhi',
+ ['khw'] = 'Khowar',
+ ['kik'] = 'Kikuyu',
+ ['kir'] = 'Kirghiz',
+ ['kis'] = 'Kisii',
+ ['kkn'] = 'Kokni',
+ ['klm'] = 'Kalmyk',
+ ['kmb'] = 'Kamba',
+ ['kmn'] = 'Kumaoni',
+ ['kmo'] = 'Komo',
+ ['kms'] = 'Komso',
+ ['knr'] = 'Kanuri',
+ ['kod'] = 'Kodagu',
+ ['koh'] = 'Korean Old Hangul',
+ ['kok'] = 'Konkani',
+ ['kon'] = 'Kikongo',
+ ['kop'] = 'Komi-Permyak',
+ ['kor'] = 'Korean',
+ ['koz'] = 'Komi-Zyrian',
+ ['kpl'] = 'Kpelle',
+ ['kri'] = 'Krio',
+ ['krk'] = 'Karakalpak',
+ ['krl'] = 'Karelian',
+ ['krm'] = 'Karaim',
+ ['krn'] = 'Karen',
+ ['krt'] = 'Koorete',
+ ['ksh'] = 'Kashmiri',
+ ['ksi'] = 'Khasi',
+ ['ksm'] = 'Kildin Sami',
+ ['kui'] = 'Kui',
+ ['kul'] = 'Kulvi',
+ ['kum'] = 'Kumyk',
+ ['kur'] = 'Kurdish',
+ ['kuu'] = 'Kurukh',
+ ['kuy'] = 'Kuy',
+ ['kyk'] = 'Koryak',
+ ['lad'] = 'Ladin',
+ ['lah'] = 'Lahuli',
+ ['lak'] = 'Lak',
+ ['lam'] = 'Lambani',
+ ['lao'] = 'Lao',
+ ['lat'] = 'Latin',
+ ['laz'] = 'Laz',
+ ['lcr'] = 'L-Cree',
+ ['ldk'] = 'Ladakhi',
+ ['lez'] = 'Lezgi',
+ ['lin'] = 'Lingala',
+ ['lma'] = 'Low Mari',
+ ['lmb'] = 'Limbu',
+ ['lmw'] = 'Lomwe',
+ ['lsb'] = 'Lower Sorbian',
+ ['lsm'] = 'Lule Sami',
+ ['lth'] = 'Lithuanian',
+ ['ltz'] = 'Luxembourgish',
+ ['lub'] = 'Luba',
+ ['lug'] = 'Luganda',
+ ['luh'] = 'Luhya',
+ ['luo'] = 'Luo',
+ ['lvi'] = 'Latvian',
+ ['maj'] = 'Majang',
+ ['mak'] = 'Makua',
+ ['mal'] = 'Malayalam Traditional',
+ ['man'] = 'Mansi',
+ ['map'] = 'Mapudungun',
+ ['mar'] = 'Marathi',
+ ['maw'] = 'Marwari',
+ ['mbn'] = 'Mbundu',
+ ['mch'] = 'Manchu',
+ ['mcr'] = 'Moose Cree',
+ ['mde'] = 'Mende',
+ ['men'] = "Me'en",
+ ['miz'] = 'Mizo',
+ ['mkd'] = 'Macedonian',
+ ['mle'] = 'Male',
+ ['mlg'] = 'Malagasy',
+ ['mln'] = 'Malinke',
+ ['mlr'] = 'Malayalam Reformed',
+ ['mly'] = 'Malay',
+ ['mnd'] = 'Mandinka',
+ ['mng'] = 'Mongolian',
+ ['mni'] = 'Manipuri',
+ ['mnk'] = 'Maninka',
+ ['mnx'] = 'Manx Gaelic',
+ ['moh'] = 'Mohawk',
+ ['mok'] = 'Moksha',
+ ['mol'] = 'Moldavian',
+ ['mon'] = 'Mon',
+ ['mor'] = 'Moroccan',
+ ['mri'] = 'Maori',
+ ['mth'] = 'Maithili',
+ ['mts'] = 'Maltese',
+ ['mun'] = 'Mundari',
+ ['nag'] = 'Naga-Assamese',
+ ['nan'] = 'Nanai',
+ ['nas'] = 'Naskapi',
+ ['ncr'] = 'N-Cree',
+ ['ndb'] = 'Ndebele',
+ ['ndg'] = 'Ndonga',
+ ['nep'] = 'Nepali',
+ ['new'] = 'Newari',
+ ['ngr'] = 'Nagari',
+ ['nhc'] = 'Norway House Cree',
+ ['nis'] = 'Nisi',
+ ['niu'] = 'Niuean',
+ ['nkl'] = 'Nkole',
+ ['nko'] = "N'ko",
+ ['nld'] = 'Dutch',
+ ['nog'] = 'Nogai',
+ ['nor'] = 'Norwegian',
+ ['nsm'] = 'Northern Sami',
+ ['nta'] = 'Northern Tai',
+ ['nto'] = 'Esperanto',
+ ['nyn'] = 'Nynorsk',
+ ['oci'] = 'Occitan',
+ ['ocr'] = 'Oji-Cree',
+ ['ojb'] = 'Ojibway',
+ ['ori'] = 'Oriya',
+ ['oro'] = 'Oromo',
+ ['oss'] = 'Ossetian',
+ ['paa'] = 'Palestinian Aramaic',
+ ['pal'] = 'Pali',
+ ['pan'] = 'Punjabi',
+ ['pap'] = 'Palpa',
+ ['pas'] = 'Pashto',
+ ['pgr'] = 'Polytonic Greek',
+ ['pil'] = 'Pilipino',
+ ['plg'] = 'Palaung',
+ ['plk'] = 'Polish',
+ ['pro'] = 'Provencal',
+ ['ptg'] = 'Portuguese',
+ ['qin'] = 'Chin',
+ ['raj'] = 'Rajasthani',
+ ['rbu'] = 'Russian Buriat',
+ ['rcr'] = 'R-Cree',
+ ['ria'] = 'Riang',
+ ['rms'] = 'Rhaeto-Romanic',
+ ['rom'] = 'Romanian',
+ ['roy'] = 'Romany',
+ ['rsy'] = 'Rusyn',
+ ['rua'] = 'Ruanda',
+ ['rus'] = 'Russian',
+ ['sad'] = 'Sadri',
+ ['san'] = 'Sanskrit',
+ ['sat'] = 'Santali',
+ ['say'] = 'Sayisi',
+ ['sek'] = 'Sekota',
+ ['sel'] = 'Selkup',
+ ['sgo'] = 'Sango',
+ ['shn'] = 'Shan',
+ ['sib'] = 'Sibe',
+ ['sid'] = 'Sidamo',
+ ['sig'] = 'Silte Gurage',
+ ['sks'] = 'Skolt Sami',
+ ['sky'] = 'Slovak',
+ ['sla'] = 'Slavey',
+ ['slv'] = 'Slovenian',
+ ['sml'] = 'Somali',
+ ['smo'] = 'Samoan',
+ ['sna'] = 'Sena',
+ ['snd'] = 'Sindhi',
+ ['snh'] = 'Sinhalese',
+ ['snk'] = 'Soninke',
+ ['sog'] = 'Sodo Gurage',
+ ['sot'] = 'Sotho',
+ ['sqi'] = 'Albanian',
+ ['srb'] = 'Serbian',
+ ['srk'] = 'Saraiki',
+ ['srr'] = 'Serer',
+ ['ssl'] = 'South Slavey',
+ ['ssm'] = 'Southern Sami',
+ ['sur'] = 'Suri',
+ ['sva'] = 'Svan',
+ ['sve'] = 'Swedish',
+ ['swa'] = 'Swadaya Aramaic',
+ ['swk'] = 'Swahili',
+ ['swz'] = 'Swazi',
+ ['sxt'] = 'Sutu',
+ ['syr'] = 'Syriac',
+ ['tab'] = 'Tabasaran',
+ ['taj'] = 'Tajiki',
+ ['tam'] = 'Tamil',
+ ['tat'] = 'Tatar',
+ ['tcr'] = 'TH-Cree',
+ ['tel'] = 'Telugu',
+ ['tgn'] = 'Tongan',
+ ['tgr'] = 'Tigre',
+ ['tgy'] = 'Tigrinya',
+ ['tha'] = 'Thai',
+ ['tht'] = 'Tahitian',
+ ['tib'] = 'Tibetan',
+ ['tkm'] = 'Turkmen',
+ ['tmn'] = 'Temne',
+ ['tna'] = 'Tswana',
+ ['tne'] = 'Tundra Nenets',
+ ['tng'] = 'Tonga',
+ ['tod'] = 'Todo',
+ ['trk'] = 'Turkish',
+ ['tsg'] = 'Tsonga',
+ ['tua'] = 'Turoyo Aramaic',
+ ['tul'] = 'Tulu',
+ ['tuv'] = 'Tuvin',
+ ['twi'] = 'Twi',
+ ['udm'] = 'Udmurt',
+ ['ukr'] = 'Ukrainian',
+ ['urd'] = 'Urdu',
+ ['usb'] = 'Upper Sorbian',
+ ['uyg'] = 'Uyghur',
+ ['uzb'] = 'Uzbek',
+ ['ven'] = 'Venda',
+ ['vit'] = 'Vietnamese',
+ ['wa' ] = 'Wa',
+ ['wag'] = 'Wagdi',
+ ['wcr'] = 'West-Cree',
+ ['wel'] = 'Welsh',
+ ['wlf'] = 'Wolof',
+ ['xbd'] = 'Tai Lue',
+ ['xhs'] = 'Xhosa',
+ ['yak'] = 'Yakut',
+ ['yba'] = 'Yoruba',
+ ['ycr'] = 'Y-Cree',
+ ['yic'] = 'Yi Classic',
+ ['yim'] = 'Yi Modern',
+ ['zhh'] = 'Chinese Hong Kong',
+ ['zhp'] = 'Chinese Phonetic',
+ ['zhs'] = 'Chinese Simplified',
+ ['zht'] = 'Chinese Traditional',
+ ['znd'] = 'Zande',
+ ['zul'] = 'Zulu'
+}
+
+otf.tables.features = {
+ ['aalt'] = 'Access All Alternates',
+ ['abvf'] = 'Above-Base Forms',
+ ['abvm'] = 'Above-Base Mark Positioning',
+ ['abvs'] = 'Above-Base Substitutions',
+ ['afrc'] = 'Alternative Fractions',
+ ['akhn'] = 'Akhands',
+ ['blwf'] = 'Below-Base Forms',
+ ['blwm'] = 'Below-Base Mark Positioning',
+ ['blws'] = 'Below-Base Substitutions',
+ ['c2pc'] = 'Petite Capitals From Capitals',
+ ['c2sc'] = 'Small Capitals From Capitals',
+ ['calt'] = 'Contextual Alternates',
+ ['case'] = 'Case-Sensitive Forms',
+ ['ccmp'] = 'Glyph Composition/Decomposition',
+ ['cjct'] = 'Conjunct Forms',
+ ['clig'] = 'Contextual Ligatures',
+ ['cpsp'] = 'Capital Spacing',
+ ['cswh'] = 'Contextual Swash',
+ ['curs'] = 'Cursive Positioning',
+ ['dflt'] = 'Default Processing',
+ ['dist'] = 'Distances',
+ ['dlig'] = 'Discretionary Ligatures',
+ ['dnom'] = 'Denominators',
+ ['dtls'] = 'Dotless Forms', -- math
+ ['expt'] = 'Expert Forms',
+ ['falt'] = 'Final glyph Alternates',
+ ['fin2'] = 'Terminal Forms #2',
+ ['fin3'] = 'Terminal Forms #3',
+ ['fina'] = 'Terminal Forms',
+ ['flac'] = 'Flattened Accents Over Capitals', -- math
+ ['frac'] = 'Fractions',
+ ['fwid'] = 'Full Width',
+ ['half'] = 'Half Forms',
+ ['haln'] = 'Halant Forms',
+ ['halt'] = 'Alternate Half Width',
+ ['hist'] = 'Historical Forms',
+ ['hkna'] = 'Horizontal Kana Alternates',
+ ['hlig'] = 'Historical Ligatures',
+ ['hngl'] = 'Hangul',
+ ['hojo'] = 'Hojo Kanji Forms',
+ ['hwid'] = 'Half Width',
+ ['init'] = 'Initial Forms',
+ ['isol'] = 'Isolated Forms',
+ ['ital'] = 'Italics',
+ ['jalt'] = 'Justification Alternatives',
+ ['jp04'] = 'JIS2004 Forms',
+ ['jp78'] = 'JIS78 Forms',
+ ['jp83'] = 'JIS83 Forms',
+ ['jp90'] = 'JIS90 Forms',
+ ['kern'] = 'Kerning',
+ ['lfbd'] = 'Left Bounds',
+ ['liga'] = 'Standard Ligatures',
+ ['ljmo'] = 'Leading Jamo Forms',
+ ['lnum'] = 'Lining Figures',
+ ['locl'] = 'Localized Forms',
+ ['mark'] = 'Mark Positioning',
+ ['med2'] = 'Medial Forms #2',
+ ['medi'] = 'Medial Forms',
+ ['mgrk'] = 'Mathematical Greek',
+ ['mkmk'] = 'Mark to Mark Positioning',
+ ['mset'] = 'Mark Positioning via Substitution',
+ ['nalt'] = 'Alternate Annotation Forms',
+ ['nlck'] = 'NLC Kanji Forms',
+ ['nukt'] = 'Nukta Forms',
+ ['numr'] = 'Numerators',
+ ['onum'] = 'Old Style Figures',
+ ['opbd'] = 'Optical Bounds',
+ ['ordn'] = 'Ordinals',
+ ['ornm'] = 'Ornaments',
+ ['palt'] = 'Proportional Alternate Width',
+ ['pcap'] = 'Petite Capitals',
+ ['pnum'] = 'Proportional Figures',
+ ['pref'] = 'Pre-base Forms',
+ ['pres'] = 'Pre-base Substitutions',
+ ['pstf'] = 'Post-base Forms',
+ ['psts'] = 'Post-base Substitutions',
+ ['pwid'] = 'Proportional Widths',
+ ['qwid'] = 'Quarter Widths',
+ ['rand'] = 'Randomize',
+ ['rkrf'] = 'Rakar Forms',
+ ['rlig'] = 'Required Ligatures',
+ ['rphf'] = 'Reph Form',
+ ['rtbd'] = 'Right Bounds',
+ ['rtla'] = 'Right-To-Left Alternates',
+ ['ruby'] = 'Ruby Notation Forms',
+ ['salt'] = 'Stylistic Alternates',
+ ['sinf'] = 'Scientific Inferiors',
+ ['size'] = 'Optical Size',
+ ['smcp'] = 'Small Capitals',
+ ['smpl'] = 'Simplified Forms',
+ ['ss01'] = 'Stylistic Set 1',
+ ['ss02'] = 'Stylistic Set 2',
+ ['ss03'] = 'Stylistic Set 3',
+ ['ss04'] = 'Stylistic Set 4',
+ ['ss05'] = 'Stylistic Set 5',
+ ['ss06'] = 'Stylistic Set 6',
+ ['ss07'] = 'Stylistic Set 7',
+ ['ss08'] = 'Stylistic Set 8',
+ ['ss09'] = 'Stylistic Set 9',
+ ['ss10'] = 'Stylistic Set 10',
+ ['ss11'] = 'Stylistic Set 11',
+ ['ss12'] = 'Stylistic Set 12',
+ ['ss13'] = 'Stylistic Set 13',
+ ['ss14'] = 'Stylistic Set 14',
+ ['ss15'] = 'Stylistic Set 15',
+ ['ss16'] = 'Stylistic Set 16',
+ ['ss17'] = 'Stylistic Set 17',
+ ['ss18'] = 'Stylistic Set 18',
+ ['ss19'] = 'Stylistic Set 19',
+ ['ss20'] = 'Stylistic Set 20',
+ ['ssty'] = 'Script Style', -- math
+ ['subs'] = 'Subscript',
+ ['sups'] = 'Superscript',
+ ['swsh'] = 'Swash',
+ ['titl'] = 'Titling',
+ ['tjmo'] = 'Trailing Jamo Forms',
+ ['tnam'] = 'Traditional Name Forms',
+ ['tnum'] = 'Tabular Figures',
+ ['trad'] = 'Traditional Forms',
+ ['twid'] = 'Third Widths',
+ ['unic'] = 'Unicase',
+ ['valt'] = 'Alternate Vertical Metrics',
+ ['vatu'] = 'Vattu Variants',
+ ['vert'] = 'Vertical Writing',
+ ['vhal'] = 'Alternate Vertical Half Metrics',
+ ['vjmo'] = 'Vowel Jamo Forms',
+ ['vkna'] = 'Vertical Kana Alternates',
+ ['vkrn'] = 'Vertical Kerning',
+ ['vpal'] = 'Proportional Alternate Vertical Metrics',
+ ['vrt2'] = 'Vertical Rotation',
+ ['zero'] = 'Slashed Zero',
+
+ ['trep'] = 'Traditional TeX Replacements',
+ ['tlig'] = 'Traditional TeX Ligatures',
+}
+
+otf.tables.baselines = {
+ ['hang'] = 'Hanging baseline',
+ ['icfb'] = 'Ideographic character face bottom edge baseline',
+ ['icft'] = 'Ideographic character face tope edige baseline',
+ ['ideo'] = 'Ideographic em-box bottom edge baseline',
+ ['idtp'] = 'Ideographic em-box top edge baseline',
+ ['math'] = 'Mathmatical centered baseline',
+ ['romn'] = 'Roman baseline'
+}
+
+-- can be sped up by local tables
+
+function otf.tables.to_tag(id)
+ return stringformat("%4s",lower(id))
+end
+
+local function resolve(tab,id)
+ if tab and id then
+ id = lower(id)
+ return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or ''
+ else
+ return "unknown"
+ end
+end
+
+function otf.meanings.script(id)
+ return resolve(otf.tables.scripts,id)
+end
+function otf.meanings.language(id)
+ return resolve(otf.tables.languages,id)
+end
+function otf.meanings.feature(id)
+ return resolve(otf.tables.features,id)
+end
+function otf.meanings.baseline(id)
+ return resolve(otf.tables.baselines,id)
+end
+
+otf.tables.to_scripts = table.reverse_hash(otf.tables.scripts )
+otf.tables.to_languages = table.reverse_hash(otf.tables.languages)
+otf.tables.to_features = table.reverse_hash(otf.tables.features )
+
+local scripts = otf.tables.scripts
+local languages = otf.tables.languages
+local features = otf.tables.features
+
+local to_scripts = otf.tables.to_scripts
+local to_languages = otf.tables.to_languages
+local to_features = otf.tables.to_features
+
+function otf.meanings.normalize(features)
+ local h = { }
+ for k,v in next, features do
+ k = lower(k)
+ if k == "language" or k == "lang" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ k = language
+ if not languages[v] then
+ h.language = to_languages[v] or "dflt"
+ else
+ h.language = v
+ end
+ elseif k == "script" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ if not scripts[v] then
+ h.script = to_scripts[v] or "dflt"
+ else
+ h.script = v
+ end
+ else
+ if type(v) == "string" then
+ local b = v:is_boolean()
+ if type(b) == "nil" then
+ v = tonumber(v) or lower(v)
+ else
+ v = b
+ end
+ end
+ h[to_features[k] or k] = v
+ end
+ end
+ return h
+end
+
+-- When I feel the need ...
+
+--~ otf.tables.aat = {
+--~ [ 0] = {
+--~ name = "allTypographicFeaturesType",
+--~ [ 0] = "allTypeFeaturesOnSelector",
+--~ [ 1] = "allTypeFeaturesOffSelector",
+--~ },
+--~ [ 1] = {
+--~ name = "ligaturesType",
+--~ [0 ] = "requiredLigaturesOnSelector",
+--~ [1 ] = "requiredLigaturesOffSelector",
+--~ [2 ] = "commonLigaturesOnSelector",
+--~ [3 ] = "commonLigaturesOffSelector",
+--~ [4 ] = "rareLigaturesOnSelector",
+--~ [5 ] = "rareLigaturesOffSelector",
+--~ [6 ] = "logosOnSelector ",
+--~ [7 ] = "logosOffSelector ",
+--~ [8 ] = "rebusPicturesOnSelector",
+--~ [9 ] = "rebusPicturesOffSelector",
+--~ [10] = "diphthongLigaturesOnSelector",
+--~ [11] = "diphthongLigaturesOffSelector",
+--~ [12] = "squaredLigaturesOnSelector",
+--~ [13] = "squaredLigaturesOffSelector",
+--~ [14] = "abbrevSquaredLigaturesOnSelector",
+--~ [15] = "abbrevSquaredLigaturesOffSelector",
+--~ },
+--~ [ 2] = {
+--~ name = "cursiveConnectionType",
+--~ [ 0] = "unconnectedSelector",
+--~ [ 1] = "partiallyConnectedSelector",
+--~ [ 2] = "cursiveSelector ",
+--~ },
+--~ [ 3] = {
+--~ name = "letterCaseType",
+--~ [ 0] = "upperAndLowerCaseSelector",
+--~ [ 1] = "allCapsSelector ",
+--~ [ 2] = "allLowerCaseSelector",
+--~ [ 3] = "smallCapsSelector ",
+--~ [ 4] = "initialCapsSelector",
+--~ [ 5] = "initialCapsAndSmallCapsSelector",
+--~ },
+--~ [ 4] = {
+--~ name = "verticalSubstitutionType",
+--~ [ 0] = "substituteVerticalFormsOnSelector",
+--~ [ 1] = "substituteVerticalFormsOffSelector",
+--~ },
+--~ [ 5] = {
+--~ name = "linguisticRearrangementType",
+--~ [ 0] = "linguisticRearrangementOnSelector",
+--~ [ 1] = "linguisticRearrangementOffSelector",
+--~ },
+--~ [ 6] = {
+--~ name = "numberSpacingType",
+--~ [ 0] = "monospacedNumbersSelector",
+--~ [ 1] = "proportionalNumbersSelector",
+--~ },
+--~ [ 7] = {
+--~ name = "appleReserved1Type",
+--~ },
+--~ [ 8] = {
+--~ name = "smartSwashType",
+--~ [ 0] = "wordInitialSwashesOnSelector",
+--~ [ 1] = "wordInitialSwashesOffSelector",
+--~ [ 2] = "wordFinalSwashesOnSelector",
+--~ [ 3] = "wordFinalSwashesOffSelector",
+--~ [ 4] = "lineInitialSwashesOnSelector",
+--~ [ 5] = "lineInitialSwashesOffSelector",
+--~ [ 6] = "lineFinalSwashesOnSelector",
+--~ [ 7] = "lineFinalSwashesOffSelector",
+--~ [ 8] = "nonFinalSwashesOnSelector",
+--~ [ 9] = "nonFinalSwashesOffSelector",
+--~ },
+--~ [ 9] = {
+--~ name = "diacriticsType",
+--~ [ 0] = "showDiacriticsSelector",
+--~ [ 1] = "hideDiacriticsSelector",
+--~ [ 2] = "decomposeDiacriticsSelector",
+--~ },
+--~ [10] = {
+--~ name = "verticalPositionType",
+--~ [ 0] = "normalPositionSelector",
+--~ [ 1] = "superiorsSelector ",
+--~ [ 2] = "inferiorsSelector ",
+--~ [ 3] = "ordinalsSelector ",
+--~ },
+--~ [11] = {
+--~ name = "fractionsType",
+--~ [ 0] = "noFractionsSelector",
+--~ [ 1] = "verticalFractionsSelector",
+--~ [ 2] = "diagonalFractionsSelector",
+--~ },
+--~ [12] = {
+--~ name = "appleReserved2Type",
+--~ },
+--~ [13] = {
+--~ name = "overlappingCharactersType",
+--~ [ 0] = "preventOverlapOnSelector",
+--~ [ 1] = "preventOverlapOffSelector",
+--~ },
+--~ [14] = {
+--~ name = "typographicExtrasType",
+--~ [0 ] = "hyphensToEmDashOnSelector",
+--~ [1 ] = "hyphensToEmDashOffSelector",
+--~ [2 ] = "hyphenToEnDashOnSelector",
+--~ [3 ] = "hyphenToEnDashOffSelector",
+--~ [4 ] = "unslashedZeroOnSelector",
+--~ [5 ] = "unslashedZeroOffSelector",
+--~ [6 ] = "formInterrobangOnSelector",
+--~ [7 ] = "formInterrobangOffSelector",
+--~ [8 ] = "smartQuotesOnSelector",
+--~ [9 ] = "smartQuotesOffSelector",
+--~ [10] = "periodsToEllipsisOnSelector",
+--~ [11] = "periodsToEllipsisOffSelector",
+--~ },
+--~ [15] = {
+--~ name = "mathematicalExtrasType",
+--~ [ 0] = "hyphenToMinusOnSelector",
+--~ [ 1] = "hyphenToMinusOffSelector",
+--~ [ 2] = "asteriskToMultiplyOnSelector",
+--~ [ 3] = "asteriskToMultiplyOffSelector",
+--~ [ 4] = "slashToDivideOnSelector",
+--~ [ 5] = "slashToDivideOffSelector",
+--~ [ 6] = "inequalityLigaturesOnSelector",
+--~ [ 7] = "inequalityLigaturesOffSelector",
+--~ [ 8] = "exponentsOnSelector",
+--~ [ 9] = "exponentsOffSelector",
+--~ },
+--~ [16] = {
+--~ name = "ornamentSetsType",
+--~ [ 0] = "noOrnamentsSelector",
+--~ [ 1] = "dingbatsSelector ",
+--~ [ 2] = "piCharactersSelector",
+--~ [ 3] = "fleuronsSelector ",
+--~ [ 4] = "decorativeBordersSelector",
+--~ [ 5] = "internationalSymbolsSelector",
+--~ [ 6] = "mathSymbolsSelector",
+--~ },
+--~ [17] = {
+--~ name = "characterAlternativesType",
+--~ [ 0] = "noAlternatesSelector",
+--~ },
+--~ [18] = {
+--~ name = "designComplexityType",
+--~ [ 0] = "designLevel1Selector",
+--~ [ 1] = "designLevel2Selector",
+--~ [ 2] = "designLevel3Selector",
+--~ [ 3] = "designLevel4Selector",
+--~ [ 4] = "designLevel5Selector",
+--~ },
+--~ [19] = {
+--~ name = "styleOptionsType",
+--~ [ 0] = "noStyleOptionsSelector",
+--~ [ 1] = "displayTextSelector",
+--~ [ 2] = "engravedTextSelector",
+--~ [ 3] = "illuminatedCapsSelector",
+--~ [ 4] = "titlingCapsSelector",
+--~ [ 5] = "tallCapsSelector ",
+--~ },
+--~ [20] = {
+--~ name = "characterShapeType",
+--~ [0 ] = "traditionalCharactersSelector",
+--~ [1 ] = "simplifiedCharactersSelector",
+--~ [2 ] = "jis1978CharactersSelector",
+--~ [3 ] = "jis1983CharactersSelector",
+--~ [4 ] = "jis1990CharactersSelector",
+--~ [5 ] = "traditionalAltOneSelector",
+--~ [6 ] = "traditionalAltTwoSelector",
+--~ [7 ] = "traditionalAltThreeSelector",
+--~ [8 ] = "traditionalAltFourSelector",
+--~ [9 ] = "traditionalAltFiveSelector",
+--~ [10] = "expertCharactersSelector",
+--~ },
+--~ [21] = {
+--~ name = "numberCaseType",
+--~ [ 0] = "lowerCaseNumbersSelector",
+--~ [ 1] = "upperCaseNumbersSelector",
+--~ },
+--~ [22] = {
+--~ name = "textSpacingType",
+--~ [ 0] = "proportionalTextSelector",
+--~ [ 1] = "monospacedTextSelector",
+--~ [ 2] = "halfWidthTextSelector",
+--~ [ 3] = "normallySpacedTextSelector",
+--~ },
+--~ [23] = {
+--~ name = "transliterationType",
+--~ [ 0] = "noTransliterationSelector",
+--~ [ 1] = "hanjaToHangulSelector",
+--~ [ 2] = "hiraganaToKatakanaSelector",
+--~ [ 3] = "katakanaToHiraganaSelector",
+--~ [ 4] = "kanaToRomanizationSelector",
+--~ [ 5] = "romanizationToHiraganaSelector",
+--~ [ 6] = "romanizationToKatakanaSelector",
+--~ [ 7] = "hanjaToHangulAltOneSelector",
+--~ [ 8] = "hanjaToHangulAltTwoSelector",
+--~ [ 9] = "hanjaToHangulAltThreeSelector",
+--~ },
+--~ [24] = {
+--~ name = "annotationType",
+--~ [ 0] = "noAnnotationSelector",
+--~ [ 1] = "boxAnnotationSelector",
+--~ [ 2] = "roundedBoxAnnotationSelector",
+--~ [ 3] = "circleAnnotationSelector",
+--~ [ 4] = "invertedCircleAnnotationSelector",
+--~ [ 5] = "parenthesisAnnotationSelector",
+--~ [ 6] = "periodAnnotationSelector",
+--~ [ 7] = "romanNumeralAnnotationSelector",
+--~ [ 8] = "diamondAnnotationSelector",
+--~ },
+--~ [25] = {
+--~ name = "kanaSpacingType",
+--~ [ 0] = "fullWidthKanaSelector",
+--~ [ 1] = "proportionalKanaSelector",
+--~ },
+--~ [26] = {
+--~ name = "ideographicSpacingType",
+--~ [ 0] = "fullWidthIdeographsSelector",
+--~ [ 1] = "proportionalIdeographsSelector",
+--~ },
+--~ [103] = {
+--~ name = "cjkRomanSpacingType",
+--~ [ 0] = "halfWidthCJKRomanSelector",
+--~ [ 1] = "proportionalCJKRomanSelector",
+--~ [ 2] = "defaultCJKRomanSelector",
+--~ [ 3] = "fullWidthCJKRomanSelector",
+--~ },
+--~ }
diff --git a/tex/context/base/font-pat.lua b/tex/context/base/font-pat.lua
index 8f1817ec2..ae91700a9 100644
--- a/tex/context/base/font-pat.lua
+++ b/tex/context/base/font-pat.lua
@@ -6,19 +6,56 @@ if not modules then modules = { } end modules ['font-pat'] = {
license = "see context related readme files"
}
+local match, lower = string.match, string.lower
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
-- older versions of latin modern didn't have the designsize set
-- so for them we get it from the name
-local patches = fonts.otf.enhance.patches
+local patches = fonts.otf.enhancers.patches
local function patch(data,filename)
if data.design_size == 0 then
- local ds = (file.basename(filename:lower())):match("(%d+)")
+ local ds = match(file.basename(lower(filename)),"(%d+)")
if ds then
- logs.report("load otf","patching design size (%s)",ds)
+ if trace_loading then
+ logs.report("load otf","patching design size (%s)",ds)
+ end
data.design_size = tonumber(ds) * 10
end
end
+ local uni_to_ind = data.map.map
+ if not uni_to_ind[0x391] then
+ -- beware, this is a hack, features for latin often don't apply to greek
+ -- but lm has not much features anyway (and only greek for math)
+ if trace_loading then
+ logs.report("load otf","adding 13 greek capitals")
+ end
+ uni_to_ind[0x391] = uni_to_ind[0x41]
+ uni_to_ind[0x392] = uni_to_ind[0x42]
+ uni_to_ind[0x395] = uni_to_ind[0x45]
+ uni_to_ind[0x397] = uni_to_ind[0x48]
+ uni_to_ind[0x399] = uni_to_ind[0x49]
+ uni_to_ind[0x39A] = uni_to_ind[0x4B]
+ uni_to_ind[0x39C] = uni_to_ind[0x4D]
+ uni_to_ind[0x39D] = uni_to_ind[0x4E]
+ uni_to_ind[0x39F] = uni_to_ind[0x4F]
+ uni_to_ind[0x3A1] = uni_to_ind[0x52]
+ uni_to_ind[0x3A4] = uni_to_ind[0x54]
+ uni_to_ind[0x3A7] = uni_to_ind[0x58]
+ uni_to_ind[0x396] = uni_to_ind[0x5A]
+ end
+ -- better make this into a feature
+ --
+ -- local glyphs = data.glyphs
+ -- for i=0x300,0x36F do
+ -- local c = glyphs[uni_to_ind[i]]
+ -- if c and c.width == 0 then
+ -- local boundingbox = c.boundingbox
+ -- c.width = boundingbox[3] - boundingbox[1]
+ -- end
+ -- end
end
patches["^lmroman"] = patch
@@ -30,10 +67,14 @@ patches["^lmtypewriter"] = patch
-- have the mkmk features properly set up
local function patch(data,filename)
- if data.gpos then
- for _, v in ipairs(data.gpos) do
+ local gpos = data.gpos
+ if gpos then
+ for k=1,#gpos do
+ local v = gpos[k]
if not v.features and v.type == "gpos_mark2mark" then
- logs.report("load otf","patching mkmk feature (name: %s)", v.name or "?")
+ if trace_loading then
+ logs.report("load otf","patching mkmk feature (name: %s)", v.name or "?")
+ end
v.features = {
{
scripts = {
diff --git a/tex/context/base/font-run.tex b/tex/context/base/font-run.tex
index 83da04b62..0a0ddd057 100644
--- a/tex/context/base/font-run.tex
+++ b/tex/context/base/font-run.tex
@@ -213,8 +213,7 @@
\processcommalist[#2]\docommand
\egroup
\else\ifsecondargument
- \showfontstyle[#1][#2][\alternativetextlist]%
- \doif{#2}{\c!mm}{\showfontstyle[#1][#2][\alternativemathlist]}%
+ \showfontstyle[#1][#2][\fontalternativelist]% math is gone
\else
\showfontstyle[#1][\c!rm]\showfontstyle[#1][\c!ss]
\showfontstyle[#1][\c!tt]\showfontstyle[#1][\c!mm]
diff --git a/tex/context/base/font-syn.lua b/tex/context/base/font-syn.lua
index 70f859cde..2f4bebbaf 100644
--- a/tex/context/base/font-syn.lua
+++ b/tex/context/base/font-syn.lua
@@ -6,53 +6,62 @@ if not modules then modules = { } end modules ['font-syn'] = {
license = "see context related readme files"
}
+local next = next
+local gsub, lower, match, find, lower, upper = string.gsub, string.lower, string.match, string.find, string.lower, string.upper
+
+local trace_names = false trackers.register("fonts.names", function(v) trace_names = v end)
+
--[[ldx--
<p>This module implements a name to filename resolver. Names are resolved
using a table that has keys filtered from the font related files.</p>
--ldx]]--
-local texsprint = tex.sprint
+local texsprint = (tex and tex.sprint) or print
fonts = fonts or { }
input = input or { }
texmf = texmf or { }
-fonts.names = { }
-fonts.names.filters = { }
-fonts.names.data = { }
-fonts.names.version = 1.07
-fonts.names.saved = false
-fonts.names.loaded = false
-fonts.names.be_clever = true
-fonts.names.enabled = true
-fonts.names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_AUTOLOAD'] or "no")
-fonts.names.cache = containers.define("fonts","data",fonts.names.version,true)
-fonts.names.trace = false
+fonts.names = fonts.names or { }
+fonts.names.filters = fonts.names.filters or { }
+fonts.names.data = fonts.names.data or { }
+
+local names = fonts.names
+local filters = fonts.names.filters
+
+names.version = 1.08 -- when adapting this, also changed font-dum.lua
+names.basename = "names"
+names.saved = false
+names.loaded = false
+names.be_clever = true
+names.enabled = true
+names.autoreload = toboolean(os.env['MTX.FONTS.AUTOLOAD'] or os.env['MTX_FONTS_AUTOLOAD'] or "no")
+names.cache = containers.define("fonts","data",names.version,true)
--[[ldx--
<p>It would make sense to implement the filters in the related modules,
but to keep the overview, we define them here.</p>
--ldx]]--
-fonts.names.filters.otf = fontforge.info
-fonts.names.filters.ttf = fontforge.info
-fonts.names.filters.ttc = fontforge.info
+filters.otf = fontloader.info
+filters.ttf = fontloader.info
+filters.ttc = fontloader.info
-function fonts.names.filters.afm(name)
- local pfbname = input.find_file(file.removesuffix(name)..".pfb","pfb") or ""
+function filters.afm(name)
+ local pfbname = resolvers.find_file(file.removesuffix(name)..".pfb","pfb") or ""
if pfbname == "" then
- pfbname = input.find_file(file.removesuffix(file.basename(name))..".pfb","pfb") or ""
+ pfbname = resolvers.find_file(file.removesuffix(file.basename(name))..".pfb","pfb") or ""
end
if pfbname ~= "" then
local f = io.open(name)
if f then
local hash = { }
for line in f:lines() do
- local key, value = line:match("^(.+)%s+(.+)%s*$")
+ local key, value = match(line,"^(.+)%s+(.+)%s*$")
if key and #key > 0 then
- hash[key:lower()] = value
+ hash[lower(key)] = value
end
- if line:find("StartCharMetrics") then
+ if find(line,"StartCharMetrics") then
break
end
end
@@ -63,8 +72,8 @@ function fonts.names.filters.afm(name)
return nil
end
-function fonts.names.filters.pfb(name)
- return fontforge.info(name)
+function filters.pfb(name)
+ return fontloader.info(name)
end
--[[ldx--
@@ -73,101 +82,103 @@ the file databases. Watch how we check not only for the names, but also
for combination with the weight of a font.</p>
--ldx]]--
-fonts.names.filters.list = {
+filters.list = {
"otf", "ttf", "ttc", "afm",
}
-fonts.names.filters.fixes = {
+filters.fixes = {
{ "reg$", "regular", },
{ "ita$", "italic", },
{ "ital$", "italic", },
{ "cond$", "condensed", },
+ { "book$", "", },
}
-fonts.names.xml_configuration_file = "fonts.conf" -- a bit weird format, bonus feature
-fonts.names.environment_path_variable = "OSFONTDIR" -- the official way, in minimals etc
+names.xml_configuration_file = "fonts.conf" -- a bit weird format, bonus feature
+names.environment_path_variable = "OSFONTDIR" -- the official way, in minimals etc
-fonts.names.filters.paths = { }
-fonts.names.filters.names = { }
+filters.paths = { }
+filters.names = { }
-function fonts.names.getpaths()
+function names.getpaths()
local hash, result = { }, { }
local function collect(t)
for i=1, #t do
- local v = input.clean_path(t[i])
- v = v:gsub("/+$","")
- local key = v:lower()
+ local v = resolvers.clean_path(t[i])
+ v = gsub(v,"/+$","")
+ local key = lower(v)
if not hash[key] then
hash[key], result[#result+1] = true, v
end
end
end
- local path = fonts.names.environment_path_variable or ""
+ local path = names.environment_path_variable or ""
if path ~= "" then
- collect(input.expanded_path_list(path))
+ collect(resolvers.expanded_path_list(path))
end
- local name = fonts.names.xml_configuration_file or ""
- if name ~= "" then
- local name = input.find_file(name,"other")
+ if xml then
+ local name = names.xml_configuration_file or ""
if name ~= "" then
- collect(xml.collect_texts(xml.load(name),"dir",true))
+ local name = resolvers.find_file(name,"other")
+ if name ~= "" then
+ collect(xml.collect_texts(xml.load(name),"dir",true))
+ end
end
end
- function fonts.names.getpaths()
+ function names.getpaths()
return result
end
return result
end
-function fonts.names.cleanname(name)
- return ((name:lower()):gsub("[^%a%d]",""))
+function names.cleanname(name)
+ return (gsub(lower(name),"[^%a%d]",""))
end
-function fonts.names.identify(verbose)
- fonts.names.data = {
- version = fonts.names.version,
+function names.identify(verbose) -- lsr is for kpse
+ names.data = {
+ version = names.version,
mapping = { },
-- sorted = { },
fallback_mapping = { },
-- fallback_sorted = { },
}
- local done, mapping, fallback_mapping, nofread, nofok = { }, fonts.names.data.mapping, fonts.names.data.fallback_mapping, 0, 0
- local cleanname = fonts.names.cleanname
+ local done, mapping, fallback_mapping, nofread, nofok = { }, names.data.mapping, names.data.fallback_mapping, 0, 0
+ local cleanname = names.cleanname
local function check(result, filename, suffix, is_sub)
local fontname = result.fullname
if fontname then
local n = cleanname(result.fullname)
if not mapping[n] then
- mapping[n], nofok = { suffix, fontname, filename, is_sub }, nofok + 1
+ mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1
end
end
if result.fontname then
fontname = fontname or result.fontname
local n = cleanname(result.fontname)
if not mapping[n] then
- mapping[n], nofok = { suffix, fontname, filename, is_sub }, nofok + 1
+ mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1
end
end
if result.familyname and result.weight and result.italicangle == 0 then
local madename = result.familyname .. " " .. result.weight
fontname = fontname or madename
- local n = cleanname(madename)
+ local n = cleanname(fontname)
if not mapping[n] and not fallback_mapping[n] then
- fallback_mapping[n], nofok = { suffix, fontname, filename, is_sub }, nofok + 1
+ fallback_mapping[n], nofok = { lower(suffix), fontname, filename, is_sub }, nofok + 1
end
end
end
- local trace = verbose or fonts.names.trace
- local filters = fonts.names.filters
- local skip_paths = fonts.names.filters.paths
- local skip_names = fonts.names.filters.names
+ local trace = verbose or trace_names
+ local skip_paths = filters.paths
+ local skip_names = filters.names
local function identify(completename,name,suffix,storedname)
if not done[name] and io.exists(completename) then
nofread = nofread + 1
if #skip_paths > 0 then
local path = file.dirname(completename)
for i=1,#skip_paths do
- if path:find(skip_paths[i]) then
+ if find(path,skip_paths[i]) then
if trace then
logs.report("fontnames","rejecting path of %s font %s",suffix,completename)
logs.push()
@@ -179,7 +190,7 @@ function fonts.names.identify(verbose)
if #skip_names > 0 then
local base = file.basename(completename)
for i=1,#skip_paths do
- if base:find(skip_names[i]) then
+ if find(base,skip_names[i]) then
done[name] = true
if trace then
logs.report("fontnames","rejecting name of %s font %s",suffix,completename)
@@ -189,51 +200,46 @@ function fonts.names.identify(verbose)
end
end
end
- if trace then
+ if trace_names then
logs.report("fontnames","identifying %s font %s",suffix,completename)
logs.push()
end
- local result = filters[suffix:lower()](completename)
+ local result = filters[lower(suffix)](completename)
if trace then
logs.pop()
end
if result then
if not result[1] then
check(result,storedname,suffix,false) -- was name
- else for _, r in ipairs(result) do
- check(r,storedname,suffix,true) -- was name
- end end
+ else
+ for r=1,#result do
+ check(result[r],storedname,suffix,true) -- was name
+ end
+ end
end
done[name] = true
end
end
+ local totalread, totalok = 0, 0
local function traverse(what, method)
- for n, suffix in ipairs(fonts.names.filters.list) do
+ for n, suffix in ipairs(filters.list) do
nofread, nofok = 0, 0
local t = os.gettimeofday() -- use elapser
- suffix = suffix:lower()
+ suffix = lower(suffix)
logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
method(suffix)
- suffix = suffix:upper()
+ suffix = upper(suffix)
logs.report("fontnames", "identifying %s font files with suffix %s",what,suffix)
method(suffix)
logs.report("fontnames", "%s %s files identified, %s hash entries added, runtime %0.3f seconds",nofread,what,nofok,os.gettimeofday()-t)
+ totalread, totalok = totalread + nofread, totalok + nofok
end
end
- traverse("tree", function(suffix) -- TEXTREE only
- input.with_files(".*%." .. suffix .. "$", function(method,root,path,name)
- if method == "file" then
- local completename = root .."/" .. path .. "/" .. name
- identify(completename,name,suffix,name,name)
- end
- end)
- end)
- traverse("system", function(suffix) -- OSFONTDIR cum suis
- local pathlist = fonts.names.getpaths()
+ local function walk_tree(pathlist,suffix)
if pathlist then
for _, path in ipairs(pathlist) do
- path = input.clean_path(path .. "/")
- path = path:gsub("/+","/")
+ path = resolvers.clean_path(path .. "/")
+ path = gsub(path,"/+","/")
local pattern = path .. "**." .. suffix -- ** forces recurse
logs.report("fontnames", "globbing path %s",pattern)
local t = dir.glob(pattern)
@@ -242,67 +248,115 @@ function fonts.names.identify(verbose)
end
end
end
+ end
+ traverse("tree", function(suffix) -- TEXTREE only
+ resolvers.with_files(".*%." .. suffix .. "$", function(method,root,path,name)
+ if method == "file" then
+ local completename = root .."/" .. path .. "/" .. name
+ identify(completename,name,suffix,name,name)
+ end
+ end)
end)
+ if texconfig.kpse_init then
+ -- we do this only for a stupid names run, not used for context itself,
+ -- using the vars is to clumsy so we just stick to a full scan instead
+ traverse("lsr", function(suffix) -- all trees
+ local pathlist = resolvers.split_path(resolvers.show_path("ls-R") or "")
+ walk_tree(pathlist,suffix)
+ end)
+ else
+ traverse("system", function(suffix) -- OSFONTDIR cum suis
+ walk_tree(names.getpaths(),suffix)
+ end)
+ end
local t = { }
- for _, f in ipairs(fonts.names.filters.fixes) do
+ for _, f in ipairs(filters.fixes) do
local expression, replacement = f[1], f[2]
- for k,v in pairs(mapping) do
- local fix, pos = k:gsub(expression,replacement)
+ for k,v in next, mapping do
+ local fix, pos = gsub(k,expression,replacement)
if pos > 0 and not mapping[fix] then
t[fix] = v
end
end
end
- for k,v in pairs(t) do
+ local n = 0
+ for k,v in next, t do
mapping[k] = v
+ n = n + 1
end
+ local rejected = 0
+ for k, v in next, mapping do
+ local kind, filename = v[1], v[3]
+ if not file.is_qualified_path(filename) and resolvers.find_file(filename,kind) == "" then
+ mapping[k] = nil
+ rejected = rejected + 1
+ end
+ end
+ if n > 0 then
+ logs.report("fontnames", "%s files read, %s normal and %s extra entries added, %s rejected, %s valid",totalread,totalok,n,rejected,totalok+n-rejected)
+ end
+end
+
+function names.is_permitted(name)
+ return containers.is_usable(names.cache(), name)
+end
+function names.write_data(name,data)
+ containers.write(names.cache(),name,data)
+end
+function names.read_data(name)
+ return containers.read(names.cache(),name)
end
-function fonts.names.load(reload,verbose)
- if not fonts.names.loaded then
+function names.load(reload,verbose)
+ if not names.loaded then
if reload then
- if containers.is_usable(fonts.names.cache(), "names") then
- fonts.names.identify(verbose)
- containers.write(fonts.names.cache(), "names", fonts.names.data)
+ if names.is_permitted(names.basename) then
+ names.identify(verbose)
+ names.write_data(names.basename,names.data)
+ else
+ logs.report("font table", "unable to access database cache")
end
- fonts.names.saved = true
+ names.saved = true
else
- fonts.names.data = containers.read(fonts.names.cache(), "names")
- if not fonts.names.saved then
- if table.is_empty(fonts.names.data) or table.is_empty(fonts.names.data.mapping) then
- fonts.names.load(true)
+ names.data = names.read_data(names.basename)
+ if not names.saved then
+ if table.is_empty(names.data) or table.is_empty(names.data.mapping) then
+ names.load(true)
end
- fonts.names.saved = true
+ names.saved = true
end
end
- local data = fonts.names.data
+ local data = names.data
if data then
data.sorted = table.sortedkeys(data.mapping or { }) or { }
data.fallback_sorted = table.sortedkeys(data.fallback_mapping or { }) or { }
else
logs.report("font table", "accessing the data table failed")
end
- fonts.names.loaded = true
+ names.loaded = true
end
end
-function fonts.names.list(pattern,reload)
- fonts.names.load(reload)
- if fonts.names.loaded then
+function names.list(pattern,reload)
+ names.load(reload)
+ if names.loaded then
local t = { }
local function list_them(mapping,sorted)
if mapping[pattern] then
t[pattern] = mapping[pattern]
else
for k,v in ipairs(sorted) do
- if v:find(pattern) then
+ if find(v,pattern) then
t[v] = mapping[v]
end
end
end
end
- list_them(fonts.names.data.mapping,fonts.names.data.sorted)
- list_them(fonts.names.data.fallback_mapping,fonts.names.data.fallback_sorted)
+ local data = names.data
+ if data then
+ list_them(data.mapping,data.sorted)
+ list_them(data.fallback_mapping,data.fallback_sorted)
+ end
return t
else
return nil
@@ -315,110 +369,81 @@ here is for testing purposes only (it deals with names prefixed by an
encoding name).</p>
--ldx]]--
-do
-
- local function found(name)
- if fonts.names.data then
- name = fonts.names.cleanname(name)
- local function found_indeed(mapping,sorted)
- local mn = mapping[name]
- if mn then
- return mn[2], mn[3], mn[4]
- end
- if fonts.names.be_clever then -- this will become obsolete
- local encoding, tag = name:match("^(.-)[%-%:](.+)$")
- local mt = mapping[tag]
- if tag and fonts.enc.is_known(encoding) and mt then
- return mt[1], encoding .. "-" .. mt[3], mt[4]
- end
- end
- -- name, type, file
- for k,v in pairs(mapping) do
- if k:find(name) then
- return v[2], v[3], v[4]
- end
- end
- local condensed = name:gsub("[^%a%d]","")
- local mc = mapping[condensed]
- if mc then
- return mc[2], mc[3], mc[4]
- end
- for k,v in ipairs(sorted) do
- if v:find(condensed) then
- v = mapping[v]
- return v[2], v[3], v[4]
- end
- end
- return nil, nil, nil
- end
- local data = fonts.names.data
- local fontname, filename, is_sub = found_indeed(data.mapping, data.sorted)
- if not fontname or not filename then
- fontname, filename, is_sub = found_indeed(data.fallback_mapping, data.fallback_sorted)
- end
- return fontname, filename, is_sub
- else
- return nil, nil, nil
+local function found_indeed(mapping,sorted,name)
+ local mn = mapping[name]
+ if mn then
+ return mn[2], mn[3], mn[4]
+ end
+ if names.be_clever then -- this will become obsolete
+ local encoding, tag = match(name,"^(.-)[%-%:](.+)$")
+ local mt = mapping[tag]
+ if tag and fonts.enc.is_known(encoding) and mt then
+ return mt[1], encoding .. "-" .. mt[3], mt[4]
end
end
-
- local reloaded = false
-
- function fonts.names.resolve(askedname, sub)
- if not askedname then
- return nil, nil
- elseif fonts.names.enabled then
- askedname = askedname:lower()
- fonts.names.load()
- local name, filename, is_sub = found(askedname)
- if not filename and not reloaded and fonts.names.autoreload then
- fonts.names.loaded = false
- reloaded = true
- io.flush()
- fonts.names.load(true)
- name, filename, is_sub = found(askedname)
- end
- if is_sub then
- return filename, name
- else
- return filename, sub
- end
- else
- return filename, sub
+ -- name, type, file
+ for k,v in next, mapping do
+ if find(k,name) then
+ return v[2], v[3], v[4]
end
end
+ local condensed = gsub(name,"[^%a%d]","")
+ local mc = mapping[condensed]
+ if mc then
+ return mc[2], mc[3], mc[4]
+ end
+ for k=1,#sorted do
+ local v = sorted[k]
+ if find(v,condensed) then
+ v = mapping[v]
+ return v[2], v[3], v[4]
+ end
+ end
+ return nil, nil, nil
+end
+local function found(name)
+ if name and name ~= "" and names.data then
+ name = names.cleanname(name)
+ local data = names.data
+ local fontname, filename, is_sub = found_indeed(data.mapping, data.sorted, name)
+ if not fontname or not filename then
+ fontname, filename, is_sub = found_indeed(data.fallback_mapping, data.fallback_sorted, name)
+ end
+ return fontname, filename, is_sub
+ else
+ return nil, nil, nil
+ end
end
---[[ldx--
-<p>A handy helper.</p>
---ldx]]--
+local reloaded = false
-function fonts.names.table(pattern,reload,all)
- local t = fonts.names.list(pattern,reload)
- if t then
- texsprint(tex.ctxcatcodes,"\\start\\nonknuthmode\\starttabulate[|T|T|T|T|T|]")
- texsprint(tex.ctxcatcodes,"\\NC hashname\\NC type\\NC fontname\\NC filename\\NC\\NR\\HL")
- for k,v in pairs(table.sortedkeys(t)) do
- if all or v == t[v][2]:lower() then
- local type, name, file = unpack(t[v])
- if type and name and file then
- texsprint(tex.ctxcatcodes,string.format("\\NC %s\\NC %s\\NC %s\\NC %s\\NC\\NR",v,type, name, file))
- else
- logs.report("font table", "skipping %s", v)
- end
- end
+function names.specification(askedname, sub)
+ if askedname and askedname ~= "" and names.enabled then
+ askedname = lower(askedname)
+ names.load()
+ local name, filename, is_sub = found(askedname)
+ if not filename and not reloaded and names.autoreload then
+ names.loaded = false
+ reloaded = true
+ io.flush()
+ names.load(true)
+ name, filename, is_sub = found(askedname)
end
- texsprint(tex.ctxcatcodes,"\\stoptabulate\\stop")
+ return name, filename, is_sub
end
end
+function names.resolve(askedname, sub)
+ local name, filename, is_sub = names.specification(askedname, sub)
+ return filename, (is_sub and name) or sub
+end
--[[ldx--
<p>Fallbacks, not permanent but a transition thing.</p>
--ldx]]--
-fonts.names.new_to_old = {
+names.new_to_old = {
["lmroman10-capsregular"] = "lmromancaps10-oblique",
["lmroman10-capsoblique"] = "lmromancaps10-regular",
["lmroman10-demi"] = "lmromandemi10-oblique",
@@ -460,19 +485,19 @@ fonts.names.new_to_old = {
["lmtypewritervarwd10-darkoblique"] = "lmmonoproplt10-boldoblique",
}
-fonts.names.old_to_new = table.swapped(fonts.names.new_to_old)
+names.old_to_new = table.swapped(names.new_to_old)
-function fonts.names.exists(name)
- local fna, found = fonts.names.autoreload, false
- fonts.names.autoreload = false
- for k,v in ipairs(fonts.names.filters.list) do
- found = (input.find_file(name,v) or "") ~= ""
+function names.exists(name)
+ local fna, found = names.autoreload, false
+ names.autoreload = false
+ for k,v in ipairs(filters.list) do
+ found = (resolvers.find_file(name,v) or "") ~= ""
if found then
break
end
end
- found = found or (input.find_file(name,"tfm") or "") ~= ""
- found = found or (fonts.names.resolve(name) or "") ~= ""
- fonts.names.autoreload = fna
+ found = found or (resolvers.find_file(name,"tfm") or "") ~= ""
+ found = found or (names.resolve(name) or "") ~= ""
+ names.autoreload = fna
return found
end
diff --git a/tex/context/base/font-tfm.lua b/tex/context/base/font-tfm.lua
index 1955b58bc..2ee633b77 100644
--- a/tex/context/base/font-tfm.lua
+++ b/tex/context/base/font-tfm.lua
@@ -6,31 +6,51 @@ if not modules then modules = { } end modules ['font-tfm'] = {
license = "see context related readme files"
}
+local utf = unicode.utf8
+
+local next, format, match, lower = next, string.format, string.match, string.lower
+local concat, sortedkeys, utfbyte, serialize = table.concat, table.sortedkeys, utf.byte, table.serialize
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+
+-- tfmdata has also fast access to indices and unicodes
+-- to be checked: otf -> tfm -> tfmscaled
+--
+-- watch out: no negative depths and negative eights permitted in regular fonts
+
--[[ldx--
<p>Here we only implement a few helper functions.</p>
--ldx]]--
fonts = fonts or { }
fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
local tfm = fonts.tfm
-fonts.loaded = fonts.loaded or { }
-fonts.dontembed = fonts.dontembed or { }
-fonts.logger = fonts.logger or { }
-fonts.loadtime = 0
-fonts.triggers = fonts.triggers or { } -- brrr
+fonts.loaded = fonts.loaded or { }
+fonts.dontembed = fonts.dontembed or { }
+fonts.triggers = fonts.triggers or { } -- brrr
+fonts.initializers = fonts.initializers or { }
+fonts.initializers.common = fonts.initializers.common or { }
+
+local fontdata = fonts.ids
+local glyph = node.id('glyph')
+local set_attribute = node.set_attribute
--[[ldx--
<p>The next function encapsulates the standard <l n='tfm'/> loader as
supplied by <l n='luatex'/>.</p>
--ldx]]--
-tfm.resolve_vf = true -- false
+tfm.resolve_vf = true -- false
+tfm.share_base_kerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
+tfm.mathactions = { }
function tfm.enhance(tfmdata,specification)
local name, size = specification.name, specification.size
- local encoding, filename = name:match("^(.-)%-(.*)$") -- context: encoding-name.*
+ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
if filename and encoding and fonts.enc.known[encoding] then
local data = fonts.enc.load(encoding)
if data then
@@ -38,14 +58,14 @@ function tfm.enhance(tfmdata,specification)
tfmdata.encoding = encoding
local vector = data.vector
local original = { }
- for k, v in pairs(characters) do
+ for k, v in next, characters do
v.name = vector[k]
v.index = k
original[k] = v
end
- for k,v in pairs(data.unicodes) do
+ for k,v in next, data.unicodes do
if k ~= v then
- if fonts.trace then
+ if trace_defining then
logs.report("define font","mapping %s onto %s",k,v)
end
characters[k] = original[v]
@@ -56,21 +76,9 @@ function tfm.enhance(tfmdata,specification)
end
function tfm.read_from_tfm(specification)
- local fname, tfmdata = specification.filename, nil
- if fname then
- -- safeguard, we use tfm as fallback
- local suffix = file.extname(fname)
- if suffix ~= "" and suffix ~= "tfm" then
- fname = ""
- end
- end
- if not fname or fname == "" then
- fname = input.findbinfile(specification.name, 'ofm')
- else
- fname = input.findbinfile(fname, 'ofm')
- end
- if fname and fname ~= "" then
- if fonts.trace then
+ local fname, tfmdata = specification.filename or "", nil
+ if fname ~= "" then
+ if trace_defining then
logs.report("define font","loading tfm file %s at size %s",fname,specification.size)
end
tfmdata = font.read_tfm(fname,specification.size) -- not cached, fast enough
@@ -78,12 +86,12 @@ function tfm.read_from_tfm(specification)
tfmdata.descriptions = tfmdata.descriptions or { }
if tfm.resolve_vf then
fonts.logger.save(tfmdata,file.extname(fname),specification) -- strange, why here
- fname = input.findbinfile(specification.name, 'ovf')
+ fname = resolvers.findbinfile(specification.name, 'ovf')
if fname and fname ~= "" then
local vfdata = font.read_vf(fname,specification.size) -- not cached, fast enough
if vfdata then
local chars = tfmdata.characters
- for k,v in pairs(vfdata.characters) do -- no ipairs, can have holes
+ for k,v in next, vfdata.characters do
chars[k].commands = v.commands
end
tfmdata.type = 'virtual'
@@ -93,10 +101,8 @@ function tfm.read_from_tfm(specification)
end
tfm.enhance(tfmdata,specification)
end
- else
- if fonts.trace then
- logs.report("define font","loading tfm with name %s fails",specification.name)
- end
+ elseif trace_defining then
+ logs.report("define font","loading tfm with name %s fails",specification.name)
end
return tfmdata
end
@@ -107,21 +113,17 @@ do with the fact that <l n='tex'/> uses a negative multiple of 1000 as
a signal for a font scaled based on the design size.</p>
--ldx]]--
-do
-
- local factors = {
- pt = 65536.0,
- bp = 65781.8,
- }
-
- function tfm.setfactor(f)
- tfm.factor = factors[f or 'pt'] or factors.pt
- end
-
- tfm.setfactor()
+local factors = {
+ pt = 65536.0,
+ bp = 65781.8,
+}
+function tfm.setfactor(f)
+ tfm.factor = factors[f or 'pt'] or factors.pt
end
+tfm.setfactor()
+
function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as well
if scaledpoints < 0 then
if designsize then
@@ -160,9 +162,11 @@ function tfm.check_virtual_id(tfmdata, id)
if not tfmdata.fonts or #tfmdata.fonts == 0 then
tfmdata.type, tfmdata.fonts = "real", nil
else
- for k,v in ipairs(tfmdata.fonts) do
- if v.id and v.id == 0 then
- v.id = id
+ local vfonts = tfmdata.fonts
+ for f=1,#vfonts do
+ local fnt = vfonts[f]
+ if fnt.id and fnt.id == 0 then
+ fnt.id = id
end
end
end
@@ -177,25 +181,91 @@ excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
fonts.trace_scaling = false
+-- the following hack costs a bit of runtime but safes memory
+--
+-- basekerns are scaled and will be hashed by table id
+-- sharedkerns are unscaled and are be hashed by concatenated indexes
+
+function tfm.check_base_kerns(tfmdata)
+ if tfm.share_base_kerns then
+ local sharedkerns = tfmdata.sharedkerns
+ if sharedkerns then
+ local basekerns = { }
+ tfmdata.basekerns = basekerns
+ return sharedkerns, basekerns
+ end
+ end
+ return nil, nil
+end
+
+function tfm.prepare_base_kerns(tfmdata)
+ if tfm.share_base_kerns and not tfmdata.sharedkerns then
+ local sharedkerns = { }
+ tfmdata.sharedkerns = sharedkerns
+ for u, chr in next, tfmdata.characters do
+ local kerns = chr.kerns
+ if kerns then
+ local hash = concat(sortedkeys(kerns), " ")
+ local base = sharedkerns[hash]
+ if not base then
+ sharedkerns[hash] = kerns
+ else
+ chr.kerns = base
+ end
+ end
+ end
+ end
+end
+
+-- we can have cache scaled characters when we are in node mode and don't have
+-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
+-- but in practice (except from mk) the otf hash will be enough already so it
+-- makes no sense to mess up the code now
+
+local charactercache = { }
+
+-- The scaler is only used for otf and afm and virtual fonts. If
+-- a virtual font has italic correction make sur eto set the
+-- has_italic flag. Some more flags will be added in the future.
+
function tfm.do_scale(tfmtable, scaledpoints)
- local trace = fonts.trace_scaling
+ tfm.prepare_base_kerns(tfmtable) -- optimalization
if scaledpoints < 0 then
scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
end
---~ print(">>>",tfmtable.units)
local delta = scaledpoints/(tfmtable.units or 1000) -- brr, some open type fonts have 2048
local t = { }
- t.factor = delta
- for k,v in pairs(tfmtable) do
- t[k] = (type(v) == "table" and { }) or v
- end
- -- new
+ -- unicoded unique descriptions shared cidinfo characters changed parameters indices
+ for k,v in next, tfmtable do
+ if type(v) == "table" then
+ -- print(k)
+ else
+ t[k] = v
+ end
+ end
+ -- status
+ local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized
+ local hasmath = tfmtable.math_parameters ~= nil or tfmtable.MathConstants ~= nil
+ local nodemode = tfmtable.mode == "node"
+ local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude
+ local hasitalic = tfmtable.has_italic
+ --
+ t.parameters = { }
+ t.characters = { }
+ t.MathConstants = { }
+ -- fast access
+ local descriptions = tfmtable.descriptions or { }
+ t.unicodes = tfmtable.unicodes
+ t.indices = tfmtable.indices
+ t.marks = tfmtable.marks
+ t.descriptions = descriptions
if tfmtable.fonts then
- t.fonts = table.fastcopy(tfmtable.fonts)
+ t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
end
- -- local zerobox = { 0, 0, 0, 0 }
local tp = t.parameters
+ local mp = t.math_parameters
local tfmp = tfmtable.parameters -- let's check for indexes
+ --
tp.slant = (tfmp.slant or tfmp[1] or 0)
tp.space = (tfmp.space or tfmp[2] or 0)*delta
tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*delta
@@ -205,107 +275,271 @@ function tfm.do_scale(tfmtable, scaledpoints)
tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*delta
local protrusionfactor = (tp.quad ~= 0 and 1000/tp.quad) or 0
local tc = t.characters
- -- we can loop over (descriptions or characters), in which case
- -- we don't need to init characters in afm/otf (saves some mem)
- -- but then .. beware of protruding etc
- local descriptions = tfmtable.descriptions or { }
- t.descriptions = descriptions
+ local characters = tfmtable.characters
local nameneeded = not tfmtable.shared.otfdata --hack
--- loop over descriptions
- -- afm and otf have descriptions, tfm not
- for k,v in pairs(tfmtable.characters) do
- local description = descriptions[k] or v
- local chr
- -- there is no need (yet) to assign a value to chr.tonunicode
- if nameneeded then
- chr = {
- name = description.name, -- is this used at all?
- index = description.index or k,
- width = delta*(description.width or 0),
- height = delta*(description.height or 0),
- depth = delta*(description.depth or 0),
- }
+ local changed = tfmtable.changed or { } -- for base mode
+ local ischanged = not table.is_empty(changed)
+ local indices = tfmtable.indices
+ local luatex = tfmtable.luatex
+ local tounicode = luatex and luatex.tounicode
+ local defaultwidth = luatex and luatex.defaultwidth or 0
+ local defaultheight = luatex and luatex.defaultheight or 0
+ local defaultdepth = luatex and luatex.defaultdepth or 0
+ -- experimental, sharing kerns (unscaled and scaled) saves memory
+ local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
+ -- loop over descriptions (afm and otf have descriptions, tfm not)
+ -- there is no need (yet) to assign a value to chr.tonunicode
+ local scaledwidth = defaultwidth * delta
+ local scaledheight = defaultheight * delta
+ local scaleddepth = defaultdepth * delta
+ local stackmath = tfmtable.ignore_stack_math ~= true
+ for k,v in next, characters do
+ local chr, description, index
+ if ischanged then
+ -- basemode hack
+ local c = changed[k]
+ if c then
+ description = descriptions[c] or v
+ v = characters[c] or v
+ index = (indices and indices[c]) or c
+ else
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
else
- chr = {
- index = description.index or k,
- width = delta*(description.width or 0),
- height = delta*(description.height or 0),
- depth = delta*(description.depth or 0),
- }
- end
- if trace then
- logs.report("define font","t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or k,description.index,description.name or '-',description.class or '-')
- end
- local ve = v.expansion_factor
- if ve then
- chr.expansion_factor = ve*1000 -- expansionfactor
- end
- local vl = v.left_protruding
- if vl then
- chr.left_protruding = protrusionfactor*chr.width*vl
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
+ local width = description.width
+ local height = description.height
+ local depth = description.depth
+ if width then width = delta*width else width = scaledwidth end
+ if height then height = delta*height else height = scaledheight end
+ -- if depth then depth = delta*depth else depth = scaleddepth end
+ if depth and depth ~= 0 then
+ depth = delta*depth
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ end
+ else
+ -- this saves a little bit of memory time and memory, esp for big cjk fonts
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ width = width,
+ }
+ end
end
- local vr = v.right_protruding
- if vr then
- chr.right_protruding = protrusionfactor*chr.width*vr
+ -- if trace_scaling then
+ -- logs.report("define font","t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or k,description.index,description.name or '-',description.class or '-')
+ -- end
+ if tounicode then
+ local tu = tounicode[index]
+ if tu then
+ chr.tounicode = tu
+ end
end
- local vi = description.italic
- if vi then
- chr.italic = vi*delta
+ if hasquality then
+ local ve = v.expansion_factor
+ if ve then
+ chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
+ end
+ local vl = v.left_protruding
+ if vl then
+ chr.left_protruding = protrusionfactor*width*vl
+ end
+ local vr = v.right_protruding
+ if vr then
+ chr.right_protruding = protrusionfactor*width*vr
+ end
end
- local vk = v.kerns
- if vk then
- local tt = {}
- for k,v in pairs(vk) do tt[k] = v*delta end
- chr.kerns = tt
+ -- todo: hasitalic
+ if hasitalic then
+ local vi = description.italic or v.italic
+ if vi and vi ~= 0 then
+ chr.italic = vi*delta
+ end
end
- local vl = v.ligatures
- if vl then
- if true then
- chr.ligatures = vl -- shared
+ -- to be tested
+ if hasmath then
+ -- todo, just operate on descriptions.math
+ local vn = v.next
+ if vn then
+ chr.next = vn
else
- local tt = { }
- for i,l in pairs(vl) do
- tt[i] = l
+ local vv = v.vert_variants
+ if vv then
+ local t = { }
+ for i=1,#vv do
+ local vvi = vv[i]
+ t[i] = {
+ ["start"] = (vvi["start"] or 0)*delta,
+ ["end"] = (vvi["end"] or 0)*delta,
+ ["advance"] = (vvi["advance"] or 0)*delta,
+ ["extender"] = vvi["extender"],
+ ["glyph"] = vvi["glyph"],
+ }
+ end
+ chr.vert_variants = t
+ else
+ local hv = v.horiz_variants
+ if hv then
+ local t = { }
+ for i=1,#hv do
+ local hvi = hv[i]
+ t[i] = {
+ ["start"] = (hvi["start"] or 0)*delta,
+ ["end"] = (hvi["end"] or 0)*delta,
+ ["advance"] = (hvi["advance"] or 0)*delta,
+ ["extender"] = hvi["extender"],
+ ["glyph"] = hvi["glyph"],
+ }
+ end
+ chr.horiz_variants = t
+ end
+ end
+ end
+ local vt = description.top_accent
+ if vt then
+ chr.top_accent = delta*vt
+ end
+ if stackmath then
+ local mk = v.mathkerns
+ if mk then
+ local kerns = { }
+ -- for k, v in next, mk do
+ -- local kk = { }
+ -- for i=1,#v do
+ -- local vi = v[i]
+ -- kk[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ -- end
+ -- kerns[k] = kk
+ -- end
+ local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.top_right = k end
+ local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.top_left = k end
+ local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.bottom_left = k end
+ local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.bottom_right = k end
+ chr.mathkern = kerns -- singular
end
- chr.ligatures = tt
end
end
- local vc = v.commands
- if vc then
- -- we assume non scaled commands here
- local ok = false
- for i=1,#vc do
- local key = vc[i][1]
- -- if key == "right" or key == "left" or key == "down" or key == "up" then
- if key == "right" or key == "down" then
- ok = true
- break
+ if not nodemode then
+ local vk = v.kerns
+ if vk then
+ if sharedkerns then
+ local base = basekerns[vk] -- hashed by table id, not content
+ if not base then
+ base = {}
+ for k,v in next, vk do base[k] = v*delta end
+ basekerns[vk] = base
+ end
+ chr.kerns = base
+ else
+ local tt = {}
+ for k,v in next, vk do tt[k] = v*delta end
+ chr.kerns = tt
+ end
+ end
+ local vl = v.ligatures
+ if vl then
+ if true then
+ chr.ligatures = vl -- shared
+ else
+ local tt = { }
+ for i,l in next, vl do
+ tt[i] = l
+ end
+ chr.ligatures = tt
end
end
- if ok then
- local tt = { }
+ end
+ if isvirtual then
+ local vc = v.commands
+ if vc then
+ -- we assume non scaled commands here
+ local ok = false
for i=1,#vc do
- local ivc = vc[i]
- local key = ivc[1]
- -- if key == "right" or key == "left" or key == "down" or key == "up" then
+ local key = vc[i][1]
if key == "right" or key == "down" then
- tt[#tt+1] = { key, ivc[2]*delta }
- else -- not comment
- tt[#tt+1] = ivc -- shared since in cache and untouched
+ ok = true
+ break
end
end
- chr.commands = tt
- else
- chr.commands = vc
+ if ok then
+ local tt = { }
+ for i=1,#vc do
+ local ivc = vc[i]
+ local key = ivc[1]
+ if key == "right" or key == "down" then
+ tt[#tt+1] = { key, ivc[2]*delta }
+ else -- not comment
+ tt[#tt+1] = ivc -- shared since in cache and untouched
+ end
+ end
+ chr.commands = tt
+ else
+ chr.commands = vc
+ end
end
end
tc[k] = chr
end
-- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
t.size = scaledpoints
+ t.factor = delta
if t.fonts then
t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
end
+ if hasmath then
+ -- mathematics.extras.copy(t) -- can be done elsewhere if needed
+ local ma = tfm.mathactions
+ for i=1,#ma do
+ ma[i](t,tfmtable,delta)
+ end
+ end
+ -- needed for \high cum suis
+ local tpx = tp.x_height
+ if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay
+ if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal
+ if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped
+ if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal
+ if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined
+ if not tp[22] then tp[22] = 0 end -- mathaxisheight
+ if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard
+ t.tounicode = 1
+ -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename
+ -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files
+ -- can have multiple subfonts
+--~ collectgarbage("collect")
return t, delta
end
@@ -320,14 +554,25 @@ tfm.auto_cleanup = true
local lastfont = nil
--- we can get rid of the tfm instance when we hav efast access to the
+-- we can get rid of the tfm instance when we have fast access to the
-- scaled character dimensions at the tex end, e.g. a fontobject.width
+--
+-- flushing the kern and ligature tables from memory saves a lot (only
+-- base mode) but it complicates vf building where the new characters
+-- demand this data
+
+--~ for id, f in pairs(fonts.ids) do -- or font.fonts
+--~ local ffi = font.fonts[id]
+--~ f.characters = ffi.characters
+--~ f.kerns = ffi.kerns
+--~ f.ligatures = ffi.ligatures
+--~ end
function tfm.cleanup_table(tfmdata) -- we need a cleanup callback, now we miss the last one
if tfm.auto_cleanup then -- ok, we can hook this into everyshipout or so ... todo
- if tfmdata.type == 'virtual' then
- for k, v in pairs(tfmdata.characters) do
- if v.commands then v.commands = nil end
+ if tfmdata.type == 'virtual' or tfmdata.virtualized then
+ for k, v in next, tfmdata.characters do
+ if v.commands then v.commands = nil end
end
end
end
@@ -349,235 +594,6 @@ function tfm.scale(tfmtable, scaledpoints)
end
--[[ldx--
-<p>The following functions are used for reporting about the fonts
-used. The message itself is not that useful in regular runs but since
-we now have several readers it may be handy to know what reader is
-used for which font.</p>
---ldx]]--
-
-function fonts.logger.save(tfmtable,source,specification) -- save file name in spec here ! ! ! ! ! !
- if tfmtable and specification and specification.specification then
- if fonts.trace then
- logs.report("define font","registering %s as %s",specification.name,source)
- end
- specification.source = source
- fonts.loaded[specification.specification] = specification
- fonts.used[specification.name] = source
- end
-end
-
---~ function fonts.logger.report(separator)
---~ local s = table.sortedkeys(fonts.loaded)
---~ if #s > 0 then
---~ local t = { }
---~ for _,v in ipairs(s) do
---~ t[#t+1] = v .. ":" .. fonts.loaded[v].source
---~ end
---~ return table.concat(t,separator or " ")
---~ else
---~ return "none"
---~ end
---~ end
-
-function fonts.logger.report(separator)
- local s = table.sortedkeys(fonts.used)
- if #s > 0 then
- local t = { }
- for _,v in ipairs(s) do
- t[#t+1] = v .. ":" .. fonts.used[v]
- end
- return table.concat(t,separator or " ")
- else
- return "none"
- end
-end
-
-function fonts.logger.format(name)
- return fonts.used[name] or "unknown"
-end
-
---[[ldx--
-<p>When we implement functions that deal with features, most of them
-will depend of the font format. Here we define the few that are kind
-of neutral.</p>
---ldx]]--
-
-fonts.initializers = fonts.initializers or { }
-fonts.initializers.common = fonts.initializers.common or { }
-
---[[ldx--
-<p>This feature will remove inter-digit kerns.</p>
---ldx]]--
-
-table.insert(fonts.triggers,"equaldigits")
-
-function fonts.initializers.common.equaldigits(tfmdata,value)
- if value then
- local chr = tfmdata.characters
- for i = utf.byte('0'), utf.byte('9') do
- local c = chr[i]
- if c then
- c.kerns = nil
- end
- end
- end
-end
-
---[[ldx--
-<p>This feature will give all glyphs an equal height and/or depth. Valid
-values are <type>none</type>, <type>height</type>, <type>depth</type> and
-<type>both</type>.</p>
---ldx]]--
-
-table.insert(fonts.triggers,"lineheight")
-
-function fonts.initializers.common.lineheight(tfmdata,value)
- if value and type(value) == "string" then
- if value == "none" then
- for _,v in pairs(tfmdata.characters) do
- v.height, v.depth = 0, 0
- end
- else
- local ascender, descender = tfmdata.ascender, tfmdata.descender
- if ascender and descender then
- local ht, dp = ascender or 0, descender or 0
- if value == "height" then
- dp = 0
- elseif value == "depth" then
- ht = 0
- end
- if ht > 0 then
- if dp > 0 then
- for _,v in pairs(tfmdata.characters) do
- v.height, v.depth = ht, dp
- end
- else
- for _,v in pairs(tfmdata.characters) do
- v.height = ht
- end
- end
- elseif dp > 0 then
- for _,v in pairs(tfmdata.characters) do
- v.depth = dp
- end
- end
- end
- end
- end
-end
-
---[[ldx--
-<p>It does not make sense any more to support messed up encoding vectors
-so we stick to those that implement oldstyle and small caps. After all,
-we move on. We can extend the next function on demand. This features is
-only used with <l n='afm'/> files.</p>
---ldx]]--
-
-do
-
- local smallcaps = lpeg.P(".sc") + lpeg.P(".smallcaps") + lpeg.P(".caps") + lpeg.P("small")
- local oldstyle = lpeg.P(".os") + lpeg.P(".oldstyle") + lpeg.P(".onum")
-
- smallcaps = lpeg.Cs((1-smallcaps)^1) * smallcaps^1
- oldstyle = lpeg.Cs((1-oldstyle )^1) * oldstyle ^1
-
- function fonts.initializers.common.encoding(tfmdata,value)
- if value then
- local afmdata = tfmdata.shared.afmdata
- if afmdata then
- local encodingfile = value .. '.enc'
- local encoding = fonts.enc.load(encodingfile)
- if encoding then
- local vector = encoding.vector
- local characters = tfmdata.characters
- local unicodes = afmdata.luatex.unicodes
- local function remap(pattern,name)
- local p = pattern:match(name)
- if p then
- local oldchr, newchr = unicodes[p], unicodes[name]
- if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
- -- logs.report("encoding","%s (%s) -> %s (%s)",p,oldchr or -1,name,newchr or -1)
- characters[oldchr] = characters[newchr]
- end
- end
- return p
- end
- for _, name in pairs(vector) do
- local ok = remap(smallcaps,name) or remap(oldstyle,name)
- end
- if fonts.map.data[tfmdata.name] then
- fonts.map.data[tfmdata.name].encoding = encodingfile
- end
- end
- end
- end
- end
-
- -- when needed we can provide this as features in e.g. afm files
-
- function fonts.initializers.common.remap(tfmdata,value,pattern) -- will go away
- if value then
- local afmdata = tfmdata.shared.afmdata
- if afmdata then
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local unicodes = afmdata.luatex.unicodes
- local done = false
- for u, _ in pairs(characters) do
- local name = descriptions[u].name
- if name then
- local p = pattern:match(name)
- if p then
- local oldchr, newchr = unicodes[p], unicodes[name]
- if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
- characters[oldchr] = characters[newchr]
- end
- end
- end
- end
- end
- end
- end
-
- function fonts.initializers.common.oldstyle(tfmdata,value)
- fonts.initializers.common.remap(tfmdata,value,oldstyle)
- end
- function fonts.initializers.common.smallcaps(tfmdata,value)
- fonts.initializers.common.remap(tfmdata,value,smallcaps)
- end
-
- function fonts.initializers.common.fakecaps(tfmdata,value)
- if value then
- -- todo: scale down
- local afmdata = tfmdata.shared.afmdata
- if afmdata then
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local unicodes = afmdata.luatex.unicodes
- for u, _ in pairs(characters) do
- local name = descriptions[u].name
- if name then
- local p = name:lower()
- if p then
- local oldchr, newchr = unicodes[p], unicodes[name]
- if oldchr and newchr and type(oldchr) == "number" and type(newchr) == "number" then
- characters[oldchr] = characters[newchr]
- end
- end
- end
- end
- end
- end
- end
-
-end
-
---~ function fonts.initializers.common.install(format,feature) -- 'afm','lineheight'
---~ fonts.initializers.base[format][feature] = fonts.initializers.common[feature]
---~ fonts.initializers.node[format][feature] = fonts.initializers.common[feature]
---~ end
-
---[[ldx--
<p>Analyzers run per script and/or language and are needed in order to
process features right.</p>
--ldx]]--
@@ -587,47 +603,31 @@ fonts.analyzers.aux = fonts.analyzers.aux or { }
fonts.analyzers.methods = fonts.analyzers.methods or { }
fonts.analyzers.initializers = fonts.analyzers.initializers or { }
-do
-
- local glyph = node.id('glyph')
- local fontdata = tfm.id
- local set_attribute = node.set_attribute
--- local unset_attribute = node.unset_attribute
--- local has_attribute = node.has_attribute
-
- local state = attributes.numbers['state'] or 100
-
- -- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
- -- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
-
- -- an example analyzer
-
- function fonts.analyzers.aux.setstate(head,font)
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
- while current do
- if current.id == glyph and current.font == font then
- local d = descriptions[current.char]
- if d then
- if d.class == "mark" then
- done = true
- set_attribute(current,state,5) -- mark
- elseif n == 0 then
- first, last, n = current, current, 1
- set_attribute(current,state,1) -- init
- else
- last, n = current, n+1
- set_attribute(current,state,2) -- medi
- end
- else -- finish
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- first, last, n = nil, nil, 0
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
+
+-- an example analyzer (should move to font-ota.lua)
+
+local state = attributes.private('state')
+
+function fonts.analyzers.aux.setstate(head,font)
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ if current.id == glyph and current.font == font then
+ local d = descriptions[current.char]
+ if d then
+ if d.class == "mark" then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
end
else -- finish
if first and first == last then
@@ -637,132 +637,22 @@ do
end
first, last, n = nil, nil, 0
end
- current = current.next
- end
- if first and first == last then
- set_attribute(last,state,4) -- isol
- elseif last then
- set_attribute(last,state,3) -- fina
- end
- return head, done
- end
-
-end
-
---[[ldx--
-<p>We move marks into the components list. This saves much nasty testing later on.</p>
---ldx]]--
-
-do
-
- local glyph = node.id('glyph')
- local fontdata = tfm.id
- local marknumber = attributes.numbers['mark'] or 200
- local set_attribute = node.set_attribute
-
- function fonts.pushmarks(head,font)
- local tfmdata = fontdata[font]
- local characters = tfmdata.characters
- local descriptions = tfmdata.descriptions
- local current, last, done, n = head, nil, false, 0
- while current do
- if current.id == glyph and current.font == font then
- local d = descriptions[current.char]
- if d and d.class == "mark" then
- -- check if head
- if last and not last.components then
- last.components = current
- current.prev = nil -- last.components.prev = nil
- done = true
- n = 1
- else
- n = n + 1
- end
- set_attribute(current,marknumber,n)
- current = current.next
- elseif last and last.components then
- -- finish 'm
- current.prev.next = nil
- current.prev = last
- last.next = current
- last = current
- last = nil
- else
- last = current
- current = current.next
- end
- elseif last and last.components then
- current.prev.next = nil
- current.prev = last
- last.next = current
- last = nil
- else
- last = nil
- current = current.next
- end
- end
- if last and last.components then
- last.next = nil
- end
- tfmdata.shared.markspushed = done
- return head, done
- end
-
- function fonts.removemarks(head,font)
- local current, done, characters, descriptions = head, false, tfmdata.characters, tfmdata.descriptions
- while current do
- if current.id == glyph and current.font == font and descriptions[current.char].class == "mark" then
- local next, prev = current.next, current.prev
- if next then
- next.prev = prev
- end
- if prev then
- prev.next = next
- else
- head = next
- end
- node.free(current)
- current = next
- done = true
- else
- current = current.next
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
end
+ first, last, n = nil, nil, 0
end
- return head, done
+ current = current.next
end
-
- function fonts.popmarks(head,font)
- local tfmdata = fontdata[font]
- if tfmdata.shared.markspushed then
- local current, done, characters = head, false, tfmdata.characters
- while current do
- if current.id == glyph and current.font == font then
- local components = current.components
- if components then
- local last, next = components, current.next
- while last.next do last = last.next end
- if next then
- next.prev = last
- end
- last.next= next
- current.next = components
- components.prev = current
- current.components = nil
- current = last.next
- done = true
- else
- current = current.next
- end
- else
- current = current.next
- end
- end
- return head, done
- else
- return head, false
- end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
end
-
+ return head, done
end
function tfm.replacements(tfm,value)
@@ -800,7 +690,7 @@ function tfm.enhance(tfmdata,specification)
tfmdata.filename = specification.name
if not features.encoding then
local name, size = specification.name, specification.size
- local encoding, filename = name:match("^(.-)%-(.*)$") -- context: encoding-name.*
+ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
if filename and encoding and fonts.enc.known[encoding] then
features.encoding = encoding
end
@@ -809,6 +699,7 @@ tfmdata.filename = specification.name
end
function tfm.set_features(tfmdata)
+ -- todo: no local functions
local shared = tfmdata.shared
-- local tfmdata = shared.tfmdata
local features = shared.features
@@ -818,7 +709,8 @@ function tfm.set_features(tfmdata)
if fi and fi.tfm then
local function initialize(list) -- using tex lig and kerning
if list then
- for _, f in ipairs(list) do
+ for i=1,#list do
+ local f = list[i]
local value = features[f]
if value and fi.tfm[f] then -- brr
if tfm.trace_features then
@@ -839,7 +731,8 @@ function tfm.set_features(tfmdata)
if fm and fm.tfm then
local function register(list) -- node manipulations
if list then
- for _, f in ipairs(list) do
+ for i=1,#list do
+ local f = list[i]
if features[f] and fm.tfm[f] then -- brr
if not shared.processors then -- maybe also predefine
shared.processors = { fm.tfm[f] }
@@ -866,13 +759,13 @@ function tfm.reencode(tfmdata,encoding)
if data then
local characters, original, vector = tfmdata.characters, { }, data.vector
tfmdata.encoding = encoding -- not needed
- for k, v in pairs(characters) do
+ for k, v in next, characters do
v.name, v.index, original[k] = vector[k], k, v
end
- for k,v in pairs(data.unicodes) do
+ for k,v in next, data.unicodes do
if k ~= v then
- if fonts.trace then
- logs.report("define font","reencoding %04X to %04X",k,v)
+ if trace_defining then
+ logs.report("define font","reencoding U+%04X to U+%04X",k,v)
end
characters[k] = original[v]
end
@@ -893,13 +786,13 @@ function tfm.remap(tfmdata,remapping)
local vector = remapping and fonts.enc.remappings[remapping]
if vector then
local characters, original = tfmdata.characters, { }
- for k, v in pairs(characters) do
+ for k, v in next, characters do
original[k], characters[k] = v, nil
end
- for k,v in pairs(vector) do
+ for k,v in next, vector do
if k ~= v then
- if fonts.trace then
- logs.report("define font","remapping %04X to %04X",k,v)
+ if trace_defining then
+ logs.report("define font","remapping U+%04X to U+%04X",k,v)
end
local c = original[k]
characters[v] = c
@@ -915,3 +808,11 @@ tfm.features.register('remap')
fonts.initializers.base.tfm.remap = tfm.remap
fonts.initializers.node.tfm.remap = tfm.remap
+
+-- status info
+
+statistics.register("fonts load time", function()
+ if statistics.elapsedindeed(fonts) then
+ return format("%s seconds",statistics.elapsedtime(fonts))
+ end
+end)
diff --git a/tex/context/base/font-tra.mkiv b/tex/context/base/font-tra.mkiv
new file mode 100644
index 000000000..c45e1394d
--- /dev/null
+++ b/tex/context/base/font-tra.mkiv
@@ -0,0 +1,113 @@
+%D \module
+%D [ file=font-tra,
+%D version=2009.01.02, % or so
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Tracing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+%D \macros
+%D {doiffontpresentelse}
+%D
+%D \starttyping
+%D \doiffontpresentelse{texnansi-lmr10}{YES}{NO}
+%D \doiffontpresentelse{adam-lindsay-modern-serif}{YES}{NO}
+%D \stoptyping
+
+\def\doiffontpresentelse#1{\ctxlua{commands.doifelse(fonts.names.exists("#1"))}}
+
+% experimental, maybe this becomes a module
+
+\newbox\otfcollector
+
+\def\startotfcollecting{\ctxlua{nodes.tracers.steppers.start()}}
+\def\stopotfcollecting {\ctxlua{nodes.tracers.steppers.stop()}}
+\def\resetotfcollecting{\ctxlua{nodes.tracers.steppers.reset()}}
+
+% Rather experimental:
+%
+% \page \showotfcomposition{arabtype*arab-default at 48pt}{-1}{الضَّرَّ} \page
+% \page \showotfcomposition{arabtype*arab-default at 48pt}{-1}{لِلّٰهِ} \page
+
+\def\showotfstepglyphs#1%
+ {\ctxlua{nodes.tracers.steppers.glyphs(\number\otfcollector,#1)}%
+ \unhbox\otfcollector}
+
+\def\otfstepcharcommand#1#2% font char
+ {\removeunwantedspaces
+ \hskip.5em plus .125em\relax
+ U+\hexnumber{#2}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}%
+ \hskip.5em plus .125em\relax}
+
+\def\otfstepmessagecommand#1#2%
+ {\begingroup
+ \tttf\language\minusone
+ \veryraggedright
+ \hangindent1em
+ \hangafter\plusone
+ \dontleavehmode\hbox{\detokenize{#1}}\removeunwantedspaces
+ \doifsomething{#2}{\break\detokenize{#2}}\endgraf
+ \endgroup
+ \blank}
+
+\def\showotfstepchars#1%
+ {\ctxlua{nodes.tracers.steppers.codes(#1,\!!bs\detokenize{\otfstepcharcommand}\!!es)}}
+
+\def\showotfstepmessages#1%
+ {\ctxlua{nodes.tracers.steppers.messages(#1,\!!bs\detokenize{\otfstepmessagecommand}\!!es,true)}}
+
+\def\showotfstepfeatures
+ {\ctxlua{nodes.tracers.steppers.features()}}
+
+\def\showotfsteps
+ {\dontleavehmode\bgroup\tttf \language\minusone features: \showotfstepfeatures\egroup
+ \blank
+ \dontleavehmode\bgroup\tttf result:\egroup
+ \blank
+ \startlinecorrection
+ \ruledhbox\bgroup\box\otfcompositionbox\egroup
+ \stoplinecorrection
+ \dorecurse{\ctxlua{nodes.tracers.steppers.nofsteps()}}
+ {\blank
+ \showotfstepmessages\recurselevel
+ \blank
+ \startlinecorrection
+ \dontleavehmode\bgroup\resetallattributes\pardir TLT\textdir TLT\relax\tttf\recurselevel: \showotfstepchars\recurselevel\egroup
+ \stoplinecorrection
+ \blank
+ \startlinecorrection
+ \ruledhbox % can be mode
+ \bgroup\resetallattributes\showotfstepglyphs\recurselevel\egroup % reset is new, we don't want additional processing
+ \stoplinecorrection
+ \blank}}
+
+\def\startotfsample
+ {\enabletrackers[*otf.sample]% beware, kind of global
+ \startotfcollecting
+ \begingroup}
+
+\def\stopotfsample
+ {\endgroup
+ \stopotfcollecting
+ \disabletrackers[*otf.sample]% beware, kind of global: otf.sample
+ \showotfsteps
+ \resetotfcollecting}
+
+\newbox\otfcompositionbox
+
+\def\showotfcomposition#1#2#3% {font*features at size}, rl=-1, text
+ {\begingroup
+ \setupcolors[\c!state=\v!start]% can be option
+ \startotfsample
+ \global\setbox\otfcompositionbox\hbox{\definedfont[#1]\ifnum#2<0 \textdir TRT\else\ifnum#2>0 \textdir TLT\fi\fi\relax#3}%
+ \stopotfsample
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/font-uni.tex b/tex/context/base/font-uni.mkii
index 7d4f3e442..1b8ce8e43 100644
--- a/tex/context/base/font-uni.tex
+++ b/tex/context/base/font-uni.mkii
@@ -2,7 +2,7 @@
%D [ file=font-uni,
%D version=1999.10.10,
%D title=\CONTEXT\ Font Macros,
-%D subtitle=\UNICODE\ Initialization,
+%D subtitle=\UNICODE,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,18 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Font Macros / UNICODE Support}
+\writestatus{loading}{ConTeXt Font Macros / Unicode}
+
+%D In \XETEX, unicode support is straightforward, so we
+%D simply output a \type {\char} with a 16||bit number.
+
+\ifnum\texengine=\xetexengine
+ \unexpanded\def\uchar#1#2{\char\numexpr#2+#1*\pluscclvi\relax}
+ \let\uc\uchar
+ \endinput
+\fi
+
+%D Now comes the more traditional 8 bit \TEX\ hackery.
%D I wrote this module when Wang Lei asked me how to use
%D Chinese in \CONTEXT. From the samples he sent me, I deduced
@@ -25,25 +36,6 @@
%D is involved, which is why the macros handling those
%D characters look ahead.
-% \startmessages dutch library: fonts
-% 21: het is veiliger om (pdf)eTeX te gebruiken
-% \stopmessages
-% \startmessages english library: fonts
-% 21: using (pdf)eTeX is more save
-% \stopmessages
-% \startmessages german library: fonts
-% 21: Verwenden von (pdf)eTeX ist sicherer
-% \stopmessages
-% \startmessages italian library: fonts
-% 21: l'uso di (pdf)eTeX è più sicuro
-% \stopmessages
-% \startmessages norwegian library: fonts
-% 21: å bruke (pdf)eTeX er tryggere
-% \stopmessages
-% \startmessages french library: fonts
-% 21: l'utilisation de (pdf)eTeX est plus économe
-% \stopmessages
-
\unprotect
%D \macros
@@ -136,19 +128,6 @@
{\def\dolookaheaduchar{\uchar{#1}{#2}\let\nextutoken\relax}%
\futurelet\nextutoken\dolookaheaduchar}
-%D In \XETEX, unicode support is straightforward, so we
-%D simply output a \type {\char} with a 16||bit number.
-%D
-%D \starttyping
-%D \def\uchar#1#2{\char\numexpr(#2+(#1*256))\relax}
-%D \stoptyping
-
-\beginXETEX \uchar
-
- \unexpanded\def\uchar#1#2{\char\numexpr#2+#1*\@cclvi\relax}
-
-\endXETEX
-
\def\dohandleucflowglyph
{\unicodeposition\numexpr\unicodeone*256+\unicodetwo\relax
\handleunicodeglyph
diff --git a/tex/context/base/font-uni.mkiv b/tex/context/base/font-uni.mkiv
new file mode 100644
index 000000000..40ab75ed6
--- /dev/null
+++ b/tex/context/base/font-uni.mkiv
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=font-uni,
+%D version=2008.11.03, % 1999.10.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=\UNICODE,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Font Macros / Unicode}
+
+%D In \MKIV\ we only provide the \type {\uchar} macro and
+%D implement it as just an \UTF\ converter. We expand it so
+%D best not use not use it for active characters.
+
+\unprotect
+
+\def\uchar#1#2{\ctxlua{commands.uchar(\number#1,\number#2)}}
+
+\let\uc\uchar
+
+\protect \endinput
diff --git a/tex/context/base/font-unk.tex b/tex/context/base/font-unk.mkii
index 4e450ae74..30f824781 100644
--- a/tex/context/base/font-unk.tex
+++ b/tex/context/base/font-unk.mkii
@@ -16,6 +16,8 @@
%D completely independant of real font names. First we map
%D some meaningful names onto unknown filenames.
+\unprotect
+
\definefontsynonym [Serif] [unknown]
\definefontsynonym [SerifBold] [unknown]
\definefontsynonym [SerifItalic] [unknown]
@@ -182,4 +184,4 @@
%D mapped onto real file names (or names that themselves are
%D mapped).
-\endinput
+\protect \endinput
diff --git a/tex/context/base/font-unk.mkiv b/tex/context/base/font-unk.mkiv
new file mode 100644
index 000000000..bd699ef71
--- /dev/null
+++ b/tex/context/base/font-unk.mkiv
@@ -0,0 +1,162 @@
+%D \module
+%D [ file=font-unk,
+%D version=1998.09.10,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=Unknown Defaults,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is rather important, because it enables us to
+%D define and call for not yet defined fonts in a way
+%D completely independant of real font names. First we map
+%D some meaningful names onto unknown filenames.
+
+\unprotect
+
+\definefontsynonym [Serif] [unknown]
+\definefontsynonym [SerifBold] [unknown]
+\definefontsynonym [SerifItalic] [unknown]
+\definefontsynonym [SerifSlanted] [unknown]
+\definefontsynonym [SerifBoldItalic] [unknown]
+\definefontsynonym [SerifBoldSlanted] [unknown]
+\definefontsynonym [SerifCaps] [unknown]
+
+\definefontsynonym [Sans] [unknown]
+\definefontsynonym [SansBold] [unknown]
+\definefontsynonym [SansItalic] [unknown]
+\definefontsynonym [SansSlanted] [unknown]
+\definefontsynonym [SansBoldItalic] [unknown]
+\definefontsynonym [SansBoldSlanted] [unknown]
+\definefontsynonym [SansCaps] [unknown]
+
+\definefontsynonym [Mono] [unknown]
+\definefontsynonym [MonoBold] [unknown]
+\definefontsynonym [MonoItalic] [unknown]
+\definefontsynonym [MonoSlanted] [unknown]
+\definefontsynonym [MonoBoldItalic] [unknown]
+\definefontsynonym [MonoBoldSlanted] [unknown]
+\definefontsynonym [MonoCaps] [unknown]
+
+\definefontsynonym [MathRoman] [unknown]
+\definefontsynonym [MathExtension] [unknown]
+\definefontsynonym [MathItalic] [unknown]
+\definefontsynonym [MathSymbol] [unknown]
+
+\definefontsynonym [MathNoName] [unknown]
+
+\definefontsynonym [MathAlpha] [unknown]
+\definefontsynonym [MathBeta] [unknown]
+\definefontsynonym [MathGamma] [unknown]
+\definefontsynonym [MathDelta] [unknown]
+
+\definefontsynonym [MathRomanBold] [MathRoman] % todo:
+\definefontsynonym [MathExtensionBold] [MathExtension] % [MathRoman]
+\definefontsynonym [MathItalicBold] [MathItalic] % [MathRoman]
+\definefontsynonym [MathSymbolBold] [MathSymbol] % [MathRoman]
+\definefontsynonym [MathAlphaBold] [MathAlpha] % [MathRoman]
+\definefontsynonym [MathBetaBold] [MathBeta] % [MathRoman]
+\definefontsynonym [MathGammaBold] [MathGamma] % [MathRoman]
+\definefontsynonym [MathDeltaBold] [MathDelta] % [MathRoman]
+
+\definefontsynonym [Handwriting] [unknown]
+\definefontsynonym [Calligraphic] [unknown]
+
+%D This permit us to define (use) fonts that refer to the default
+%D style (so, Bold may expand to SansBold or SerifBold, depending
+%D on the default style in the typeface).
+
+\definefontsynonym[\s!Normal] [\noexpand\fontstringD]
+\definefontsynonym[\s!Bold] [\noexpand\fontstringD\noexpand\s!Bold]
+\definefontsynonym[\s!Italic] [\noexpand\fontstringD\noexpand\s!Italic]
+\definefontsynonym[\s!Slanted] [\noexpand\fontstringD\noexpand\s!Slanted]
+\definefontsynonym[\s!BoldItalic] [\noexpand\fontstringD\noexpand\s!BoldItalic]
+\definefontsynonym[\s!BoldSlanted][\noexpand\fontstringD\noexpand\s!BoldSlanted]
+\definefontsynonym[\s!Caps] [\noexpand\fontstringD\noexpand\s!Caps]
+
+%D Also handy:
+
+\definefontsynonym [Regular] [Serif]
+\definefontsynonym [RegularBold] [SerifBold]
+\definefontsynonym [RegularItalic] [SerifItalic]
+\definefontsynonym [RegularSlanted] [SerifSlanted]
+\definefontsynonym [RegularBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RegularBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RegularCaps] [SerifCaps]
+
+\definefontsynonym [Support] [Sans]
+\definefontsynonym [SupportBold] [SansBold]
+\definefontsynonym [SupportItalic] [SansItalic]
+\definefontsynonym [SupportSlanted] [SansSlanted]
+\definefontsynonym [SupportBoldItalic] [SansBoldItalic]
+\definefontsynonym [SupportBoldSlanted] [SansBoldSlanted]
+\definefontsynonym [SupportCaps] [SansCaps]
+
+%D Well, not that good an idea:
+
+\definefontsynonym [Roman] [Serif]
+\definefontsynonym [RomanBold] [SerifBold]
+\definefontsynonym [RomanItalic] [SerifItalic]
+\definefontsynonym [RomanSlanted] [SerifSlanted]
+\definefontsynonym [RomanBoldItalic] [SerifBoldItalic]
+\definefontsynonym [RomanBoldSlanted] [SerifBoldSlanted]
+\definefontsynonym [RomanCaps] [SerifCaps]
+
+\definefontsynonym [Type] [Mono]
+\definefontsynonym [TypeBold] [MonoBold]
+\definefontsynonym [TypeItalic] [MonoItalic]
+\definefontsynonym [TypeSlanted] [MonoSlanted]
+\definefontsynonym [TypeBoldItalic] [MonoBoldItalic]
+\definefontsynonym [TypeBoldSlanted] [MonoBoldSlanted]
+\definefontsynonym [TypeCaps] [MonoCaps]
+
+%D Next we define roman, sans and monospaced font sets.
+
+\definebodyfont [default] [rm]
+ [tf=Serif sa 1,
+ bf=SerifBold sa 1,
+ it=SerifItalic sa 1,
+ sl=SerifSlanted sa 1,
+ bi=SerifBoldItalic sa 1,
+ bs=SerifBoldSlanted sa 1,
+ sc=SerifCaps sa 1]
+
+\definebodyfont [default] [ss]
+ [tf=Sans sa 1,
+ bf=SansBold sa 1,
+ it=SansItalic sa 1,
+ sl=SansSlanted sa 1,
+ bi=SansBoldItalic sa 1,
+ bs=SansBoldSlanted sa 1,
+ sc=SansCaps sa 1]
+
+\definebodyfont [default] [tt]
+ [tf=Mono sa 1,
+ bf=MonoBold sa 1,
+ it=MonoItalic sa 1,
+ sl=MonoSlanted sa 1,
+ bi=MonoBoldItalic sa 1,
+ bs=MonoBoldSlanted sa 1,
+ sc=MonoCaps sa 1]
+
+\definebodyfont [default] [mm]
+ [mr=MathRoman mo 1]
+
+\definebodyfont [bfmath] [mm]
+ [mr=MathRomanBold mo 1]
+
+\definebodyfont [default] [hw]
+ [tf=Handwriting sa 1]
+
+\definebodyfont [default] [cg]
+ [tf=Calligraphy sa 1]
+
+%D These definitions come into action as soon as names are
+%D mapped onto real file names (or names that themselves are
+%D mapped).
+
+\protect \endinput
diff --git a/tex/context/base/font-vf.lua b/tex/context/base/font-vf.lua
index 37e4eeb6e..c103555a3 100644
--- a/tex/context/base/font-vf.lua
+++ b/tex/context/base/font-vf.lua
@@ -64,7 +64,7 @@ end
function vf.aux.combine.process(g,list)
if list then
- for _,v in pairs(list) do
+ for _,v in next, list do
(vf.aux.combine.commands[v[1]] or nop)(g,v)
end
end
@@ -81,7 +81,7 @@ function vf.aux.combine.names(g,name,force)
local fd, gd = f.descriptions, g.descriptions
g.fonts[#g.fonts+1] = { id = id } -- no need to be sparse
local hn = #g.fonts
- for k, v in pairs(fc) do
+ for k, v in next, fc do
if force or not gc[k] then
gc[k] = table.fastcopy(v)
gc[k].commands = { { 'slot', hn, k } }
@@ -113,7 +113,8 @@ vf.aux.combine.commands = {
function vf.combine(specification,tag)
local g = {
name = specification.name,
- type = 'virtual',
+ -- type = 'virtual',
+ virtualized = true,
fonts = { },
characters = { },
descriptions = { },
@@ -180,12 +181,11 @@ fonts.define.methods.install(
fonts.define.methods["demo-1"] = function(specification)
local name = specification.name -- symbolic name
local size = specification.size -- given size
---~ specification.name = 'lmroman10-regular' -- forced base name
---~ specification.features.vtf = { }
local f, id = tfm.read_and_define('lmroman10-regular',size)
if f and id then
local capscale, digscale = 0.85, 0.75
- f.name, f.type = name, 'virtual'
+ -- f.name, f.type = name, 'virtual'
+ f.name, f.virtualized = name, true
f.fonts = {
{ id = id },
{ name = 'lmsans10-regular' , size = size*capscale }, -- forced extra name
@@ -193,65 +193,21 @@ fonts.define.methods["demo-1"] = function(specification)
}
local i_is_of_category = characters.i_is_of_category
local characters, descriptions = f.characters, f.descriptions
- for u,v in pairs(characters) do
+ local red = {'special','pdf: 1 0 0 rg'}
+ local green = {'special','pdf: 0 1 0 rg'}
+ local blue = {'special','pdf: 0 0 1 rg'}
+ local black = {'special','pdf: 0 g'}
+ for u,v in next, characters do
if u and i_is_of_category(u,'lu') then
v.width = capscale*v.width
- v.commands = {
- {'special','pdf: 1 0 0 rg'},
- {'slot',2, u},
- {'special','pdf: 0 g'},
- }
+ v.commands = { red, {'slot',2,u}, black }
elseif u and i_is_of_category(u,'nd') then
v.width = digscale*v.width
- v.commands = {
- {'special','pdf: 0 0 1 rg'},
- {'slot',3,u},
- {'special','pdf: 0 g'},
- }
+ v.commands = { blue, {'slot',3,u}, black }
else
- v.commands = {
- {'special','pdf: 0 1 0 rg'},
- {'slot',1,u},
- {'special','pdf: 0 g'},
- }
+ v.commands = { green, {'slot',1,u}, black }
end
end
end
return f
end
-
--- keep as example, now tfm feature
-
---~ vf.aux.combine.commands["lineheight"] = function(g,v)
---~ if g.ascender and g.descender then
---~ local ht, dp = g.ascender or 0, g.descender or 0
---~ if v[2] == "none" then
---~ for _,v in pairs(g.characters) do
---~ v.height = 0
---~ v.depth = 0
---~ end
---~ else
---~ if v[2] == "height" then
---~ dp = 0
---~ elseif v[2] == "depth" then
---~ ht = 0
---~ end
---~ if ht > 0 then
---~ if dp > 0 then
---~ for _,v in pairs(g.characters) do
---~ v.height = ht
---~ v.depth = dp
---~ end
---~ else
---~ for _,v in pairs(g.characters) do
---~ v.height = ht
---~ end
---~ end
---~ elseif dp > 0 then
---~ for _,v in pairs(g.characters) do
---~ v.depth = dp
---~ end
---~ end
---~ end
---~ end
---~ end
diff --git a/tex/context/base/font-xtx.lua b/tex/context/base/font-xtx.lua
new file mode 100644
index 000000000..63e421fa4
--- /dev/null
+++ b/tex/context/base/font-xtx.lua
@@ -0,0 +1,115 @@
+if not modules then modules = { } end modules ['font-xtx'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, count = tex.sprint, tex.count
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+--[[ldx--
+<p>Choosing a font by name and specififying its size is only part of the
+game. In order to prevent complex commands, <l n='xetex'/> introduced
+a method to pass feature information as part of the font name. At the
+risk of introducing nasty parsing and compatinility problems, this
+syntax was expanded over time.</p>
+
+<p>For the sake of users who have defined fonts using that syntax, we
+will support it, but we will provide additional methods as well.
+Normally users will not use this direct way, but use a more abstract
+interface.</p>
+
+<p>The next one is the official one. However, in the plain
+variant we need to support the crappy [] specification as
+well and that does not work too well with the general design
+of the specifier.</p>
+--ldx]]--
+
+--~ function fonts.define.specify.colonized(specification) -- xetex mode
+--~ local list = { }
+--~ if specification.detail and specification.detail ~= "" then
+--~ for v in gmatch(specification.detail,"%s*([^;]+)%s*") do
+--~ local a, b = match(v,"^(%S*)%s*=%s*(%S*)$")
+--~ if a and b then
+--~ list[a] = b:is_boolean()
+--~ if type(list[a]) == "nil" then
+--~ list[a] = b
+--~ end
+--~ else
+--~ local a, b = match(v,"^([%+%-]?)%s*(%S+)$")
+--~ if a and b then
+--~ list[b] = a ~= "-"
+--~ end
+--~ end
+--~ end
+--~ end
+--~ specification.features.normal = list
+--~ return specification
+--~ end
+
+--~ check("oeps/BI:+a;-b;c=d")
+--~ check("[oeps]/BI:+a;-b;c=d")
+--~ check("file:oeps/BI:+a;-b;c=d")
+--~ check("name:oeps/BI:+a;-b;c=d")
+
+local list = { }
+
+fonts.define.specify.colonized_default_lookup = "file"
+
+local function issome () list.lookup = fonts.define.specify.colonized_default_lookup end
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function istrue (s) list[s] = 'yes' end
+local function isfalse(s) list[s] = 'no' end
+local function iskey (k,v) list[k] = v end
+
+local spaces = lpeg.P(" ")^0
+local namespec = (1-lpeg.S("/: ("))^0
+local crapspec = spaces * lpeg.P("/") * (((1-lpeg.P(":"))^0)/iscrap) * spaces
+local filename = (lpeg.P("file:")/isfile * (namespec/thename)) + (lpeg.P("[") * lpeg.P(true)/isname * (((1-lpeg.P("]"))^0)/thename) * lpeg.P("]"))
+local fontname = (lpeg.P("name:")/isname * (namespec/thename)) + lpeg.P(true)/issome * (namespec/thename)
+local sometext = (lpeg.R("az") + lpeg.R("AZ") + lpeg.R("09"))^1
+local truevalue = lpeg.P("+") * spaces * (sometext/istrue)
+local falsevalue = lpeg.P("-") * spaces * (sometext/isfalse)
+local keyvalue = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(sometext))/iskey
+local somevalue = sometext/istrue
+local subvalue = lpeg.P("(") * (lpeg.C(lpeg.P(1-lpeg.S("()"))^1)/issub) * lpeg.P(")") -- for Kim
+local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
+local options = lpeg.P(":") * spaces * (lpeg.P(";")^0 * option)^0
+local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
+
+function fonts.define.specify.colonized(specification) -- xetex mode
+ list = { }
+ pattern:match(specification.specification)
+ for k, v in next, list do
+ list[k] = v:is_boolean()
+ if type(list[a]) == "nil" then
+ list[k] = v
+ end
+ end
+ list.crap = nil -- style not supported, maybe some day
+ if list.name then
+ specification.name = list.name
+ list.name = nil
+ end
+ if list.lookup then
+ specification.lookup = list.lookup
+ list.lookup = nil
+ end
+ if list.sub then
+ specification.sub = list.sub
+ list.sub = nil
+ end
+ specification.features.normal = list
+ return specification
+end
+
+fonts.define.register_split(":", fonts.define.specify.colonized)
diff --git a/tex/context/base/font-xtx.tex b/tex/context/base/font-xtx.tex
new file mode 100644
index 000000000..5f4b85879
--- /dev/null
+++ b/tex/context/base/font-xtx.tex
@@ -0,0 +1,357 @@
+%D \module
+%D [ file=font-xtx,
+%D version=2004.09.11,
+%D title=\CONTEXT\ Font Macros,
+%D subtitle=\XETEX\ Hacks,
+%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.
+
+\ifnum\texengine=\xetexengine
+ \writestatus{loading}{ConTeXt Font Macros / XeTeX Hacks}
+\else
+ \endinput
+\fi
+
+\unprotect
+
+%D Loading:
+
+%D for some reason xetex does not support [filename] for tfm files and
+%D quotes also behave kind of strange " vs ' vs [ vs ...
+%D
+%D \starttyping
+%D \font\myfont = msam7 % ok
+%D \font\myfont = "msam7" % also ok
+%D \font\myfont = "msam7" at 8pt % error
+%D \stoptyping
+
+\newconditional\tracexetexfonts
+
+%D Because \XETEX\ is not that fast on locating fonts we cache lookups so
+%D that we minimize the test. It saves a little bit of runtime, depending
+%D on the number of fonts loaded (which is normally not that much).
+
+\def\doiffoundXTXfontelse#1#2%
+ {\ifcsname xtx@fnt@#2\somefontspec\endcsname
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{already checked #1: #2\somefontspec\space (state: \number\csname xtx@fnt@#2\somefontspec\endcsname)}%
+ \fi
+ \else
+ \suppressfontnotfounderror\plusone
+ \font\xetextempfont=#2\somefontspec\relax
+ \suppressfontnotfounderror\zerocount
+ \edef\xetextempfont{\fontname\xetextempfont}%
+ \global\expandafter\chardef\csname xtx@fnt@#2\somefontspec\endcsname
+ \ifx\xetextempfont\nullfontname
+ \zerocount \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{not found #1: #2\somefontspec}%
+ \fi
+ \else
+ \plusone \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{found #1: #2\somefontspec}%
+ \fi
+ \fi
+ \fi
+ \ifcase\csname xtx@fnt@#2\somefontspec\endcsname
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\def\docheckfontfilenameprefix#1:#2:#3#4\relax
+ {\edef\!!stringa{#1}%
+ \edef\!!stringb{#2}%
+ \ifx\!!stringb\empty
+ % no prefix
+ \let\checkedfontfile\!!stringa
+ \doiffoundXTXfontelse{1a}{\checkedfontfile\checkedfontfeatures}
+ {\edef\checkedfontfile{\checkedfontfile\checkedfontfeatures}}
+ {\doiffoundXTXfontelse{1b}{"\checkedfontfile\checkedfontfeatures"}
+ {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
+ {\doiffoundXTXfontelse{1c}{"[\checkedfontfile]\checkedfontfeatures"}
+ {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
+ {}}}%
+ \else\ifx\!!stringa\v!file
+ % force file, only file check when no spaces
+ \let\checkedfontfile\!!stringb
+ \doiffoundXTXfontelse{2a}{"[\checkedfontfile]\checkedfontfeatures"}
+ {\edef\checkedfontfile{"[\checkedfontfile]\checkedfontfeatures"}}
+ {\doiffoundXTXfontelse{2b}{"\checkedfontfile\checkedfontfeatures"}
+ {\edef\checkedfontfile{"\checkedfontfile\checkedfontfeatures"}}
+ {}}%
+ \else\ifx\!!stringa\v!name
+ % force name, always lookup by xetex itself, "" forces otf/ttf/type1
+ \edef\checkedfontfile{"\!!stringb\checkedfontfeatures"}%
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{no checking 3a: \checkedfontfile}%
+ \fi
+ \else
+ % whatever, maybe even xetex spec, forget about features
+ \edef\checkedfontfile{"\!!stringa\!!stringb"}%
+ \ifconditional\tracexetexfonts
+ \writestatus\m!fonts{no checking 3b: \checkedfontfile}%
+ \fi
+ \fi\fi\fi}
+
+\def\checkfontfilename% -- todo: integrate so that we call do.. directly
+ {\expandafter\docheckfontfilename\fontfile*\empty*\relax}
+
+\def\docheckfontfilename#1*#2#3*#4\relax % class overrules file
+ {\edef\checkedfontfeatures
+ {\expandafter\ifx\csname\fontclass\s!features\endcsname\empty
+ \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
+ \else\expandafter\ifx\csname\fontclass\s!features\endcsname\relax % redundant, will go away
+ \ifx\@@fontfeatures\empty\ifx#2\empty\else#2#3\fi\else\@@fontfeatures\fi
+ \else
+ \csname\fontclass\s!features\endcsname
+ \fi\fi}%
+ \ifx\checkedfontfeatures\empty
+ % done
+ \else
+ \edef\checkedfontfeatures{\executeifdefined{\??fa\checkedfontfeatures}\empty}%
+ \ifx\checkedfontfeatures\empty
+ % done
+ \else
+ \let\convertedfontfeatures\empty
+ \processcommacommand[\checkedfontfeatures]\doconvertfontfeatures % raw
+ \ifx\convertedfontfeatures\empty
+ \let\checkedfontfeatures\empty
+ \else
+ \edef\checkedfontfeatures{:\convertedfontfeatures}%
+ \fi
+ \fi
+ \fi
+ \docheckfontfilenameprefix#1:\empty:\empty\relax
+ \doshowcheckedfontfeatures}
+
+\def\dodoconvertfontfeatures#1=#2#3=#4\relax
+ {\ifx#2\empty
+ % invalid feature
+ \else\ifcsname @xtx@#1@#2#3\endcsname
+ \expandafter\ifx\csname @xtx@#1@#2#3\endcsname\empty\else
+ \edef\convertedfontfeatures{\convertedfontfeatures\csname @xtx@#1@#2#3\endcsname;}%
+ \fi
+ \else
+ \edef\!!stringa{#1}%
+ \edef\!!stringb{#2#3}%
+ \edef\convertedfontfeatures
+ {\convertedfontfeatures
+ \ifx\!!stringb\v!yes
+ +\!!stringa
+ \else\ifx\!!stringb\v!no
+ -\!!stringa
+ \else
+ \!!stringa=\!!stringb
+ \fi\fi;}%
+ \fi\fi}
+
+\def\doconvertfontfeatures#1%
+ {\dodoconvertfontfeatures#1=\empty=\relax}
+
+\def\remapfontfeature #1 #2 #3 {\setevalue{@xtx@#1@#2}{#3}}
+
+% this may move to another file, maybe font-xtx
+
+\remapfontfeature tlig yes mapping=tlig
+%remapfontfeature tlig no mapping=
+\remapfontfeature trep yes {}
+\remapfontfeature trep no {}
+\remapfontfeature texligatures yes mapping=tlig
+%remapfontfeature texligatures no mapping=
+%remapfontfeature texquotes yes mapping=tex-text
+%remapfontfeature texquotes no mapping=
+
+%D Variants:
+
+\unexpanded\def\variant[#1]%
+ {\dosetscaledfont
+ \font\variantfont\truefontname{\fontstringA\fontstylesuffix\fontvariant\fontstringA{#1}} at \scaledfont
+ \variantfont}
+
+%D Possible optimizations:
+
+% \def\updatefontparameters
+% {\edef\@@fontfeatures{\truefontdata\fontfile\s!features}%
+% \edef\@@fontskewchar{\truefontdata\fontfile\s!skewchar}}
+
+% \def\setfontcharacteristics
+% {\updatefontparameters % redundant, will go away, faster too
+% \the\everyfont}
+
+% \let\synchronizepatternswithfont\relax
+
+%D Names:
+
+% We need to move the feature into the filename else it may be
+% overloaded by another reference. For instance the definition of
+% a regular and caps variant can use the same font.
+
+% We could use an indirect method ... store in 'array' and refer to
+% slot.
+
+\def\definefontsynonym[#1]#2[#3]%
+ {\edef\@@fontname{#1}%
+ \edef\@@fontfile{#3}%
+ \doifnextoptionalelse\dodefinefontsynonym\nodefinefontsynonym}
+
+\def\nodefinefontsynonym
+ {\@EA\let\csname\??ff\fontclass\@@fontname\endcsname\@@fontfile}
+
+\def\dodefinefontsynonym[#1]%
+ {\edef\@@fontdata{#1}%
+ \ifx\@@fontdata\empty
+ \nodefinefontsynonym
+ \else
+ \ifx\fontclass\empty
+ \getfontparameters
+ \else
+ \getglobalfontparameters
+ \fi
+ \ifcsname\??ff\@@fontfile\s!features\endcsname
+ \@EA\edef\csname\??ff\fontclass\@@fontname\endcsname{\@@fontfile*\csname\??ff\@@fontfile\s!features\endcsname}%
+ \@EA\let\csname\??ff\@@fontfile\s!features\endcsname\undefined
+ \else
+ \nodefinefontsynonym
+ \fi
+ \fi}
+
+\let\definefontfile\definefontsynonym % dedicated to Taco Hoekwater
+
+% simple version
+%
+% \def\truefontname#1%
+% {\@EA\dotruefontname#1*\relax}
+%
+% \def\dotruefontname#1*#2\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+% \else\ifcsname\??ff#1\endcsname
+% \@EA\truefontname\csname\??ff#1\endcsname
+% \else
+% #1%
+% \fi\fi}
+%
+% last counts
+%
+% \def\truefontname#1%
+% {\@EA\dotruefontname#1*\empty*\relax}
+%
+% \def\dotruefontname#1*#2#3*#4\relax
+% {\ifcsname\??ff\fontclass#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+% \else
+% \@EA\truefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+% \fi
+% \else\ifcsname\??ff#1\endcsname
+% \ifx#2\empty
+% \@EA\truefontname\csname\??ff#1\endcsname
+% \else
+% \@EA\truefontname\csname\??ff#1\endcsname*#2#3%
+% \fi
+% \else
+% \ifx#2\empty
+% #1%
+% \else
+% #1*#2#3%
+% \fi
+% \fi\fi}
+%
+% first counts
+
+\def\truefontname#1%
+ {\@EA\dotruefontname#1*\empty*\relax}
+
+\def\dotruefontname#1*#2#3*#4\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff\fontclass#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname*#2#3%
+ \fi
+ \else\ifcsname\??ff#1\endcsname
+ \ifx#2\empty
+ \@EA\truefontname\csname\??ff#1\endcsname
+ \else
+ \@EA\redotruefontname\csname\??ff#1\endcsname*#2#3%
+ \fi
+ \else
+ #1\ifx#2\empty\else*#2#3\fi
+ \fi\fi}
+
+\def\redotruefontname#1%
+ {\@EA\dodotruefontname#1*\relax}
+
+\def\dodotruefontname#1*#2\relax
+ {\ifcsname\??ff\fontclass#1\endcsname
+ \@EA\redotruefontname\csname\??ff\fontclass#1\endcsname
+ \else\ifcsname\??ff#1\endcsname
+ \@EA\redotruefontname\csname\??ff#1\endcsname
+ \else
+ #1%
+ \fi\fi}
+
+%D Default:
+
+\def\defaultfontfile{file:lmmono10-regular}
+
+%D Maybe:
+
+% \def\updatefontparameters
+% {\edef\@@fontfeatures{\truefontdata\fontfile \s!features}%
+% \edef\@@fontskewchar{\truefontdata\fontfile \s!skewchar}}
+
+% \def\setfontcharacteristics
+% {%\updatefontparameters % redundant, will go away, faster too
+% \the\everyfont
+% \synchronizepatternswithfont}
+
+\protect \endinput
+
+% \starttypescript[serif] [myzhfont]
+% \definefontsynonym [Serif] [file:SimSun]
+% \definefontsynonym [SerifBold] [file:SimSun]
+% \definefontsynonym [SerifItalic] [file:SimSun]
+% \definefontsynonym [SerifBoldItalic] [file:SimSun]
+% \stoptypescript
+% \starttypescript[sans] [myzhfont]
+% \definefontsynonym [Sans] [file:SimSun]
+% \definefontsynonym [SansBold] [file:SimSun]
+% \definefontsynonym [SansItalic] [file:SimSun]
+% \definefontsynonym [SansBoldItalic] [file:SimSun]
+% \stoptypescript
+% \starttypescript[mono] [myzhfont]
+% \definefontsynonym [Mono] [file:SimSun]
+% \definefontsynonym [MonoBold] [file:SimSun]
+% \definefontsynonym [MonoItalic] [file:SimSun]
+% \definefontsynonym [MonoBoldItalic] [file:SimSun]
+% \stoptypescript
+% \definetypeface [myzhfont] [rm] [serif][myzhfont] [default]
+% \definetypeface [myzhfont] [ss] [sans] [myzhfont] [default]
+% \definetypeface [myzhfont] [tt] [mono] [myzhfont] [default]
+
+% \starttext
+% % on windows: make sure fonts.conf has no cache mentioned
+% %
+% % 64 sec xetex, 11 sec luatex (56 sec xetex when \nobigmath)
+% %
+% \setupbodyfont[myzhfont] \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
+% %
+% % 67 sec xetex, 11.5 sec luatex
+% %
+% % \dorecurse{10000}{{hello {\switchtobodyfont[myzhfont] 你好}}\par}
+% %
+% % 5 sec xetex, 7 sec luatex
+% %
+% % \setupbodyfont[myzhfont] \dorecurse{10000}{{hello {你好}}\par}
+% %
+% % 5 sec xetex, 7 sec luatex
+% %
+% % \setupbodyfont[myzhfont] \dorecurse{10000}{{\bf hello {你好}}\par}
+% \stoptext
+
diff --git a/tex/context/base/hand-ini.mkii b/tex/context/base/hand-ini.mkii
index 59c98fa06..42d248df6 100644
--- a/tex/context/base/hand-ini.mkii
+++ b/tex/context/base/hand-ini.mkii
@@ -16,61 +16,21 @@
\unprotect
-\startmessages dutch library: handlings
- title: handling
- 1: font afhandeling --
- 2: font afhandeling -- wordt geladen
- 3: onbekende font afhandeling --
-\stopmessages
-
-\startmessages english library: handlings
- title: handling
- 1: font handling --
- 2: font handling -- is loaded
- 3: unknown font handling --
-\stopmessages
-
-\startmessages german library: handlings % to do
- title: handling
- 1: Font Verarbeitung --
- 2: Font Verarbeitung -- ist geladen
- 3: unknown font handling --
-\stopmessages
-
-\startmessages czech library: handlings % to do
- title: handling
- 1: font handling --
- 2: font handling -- is loaded
- 3: unknown font handling --
-\stopmessages
-
-\startmessages italian library: handlings % to do
- title: handling
- 1: font handling --
- 2: font handling -- is loaded
- 3: unknown font handling --
-\stopmessages
-
-\startmessages norwegian library: handlings % to do
- title: handling
- 1: font handling --
- 2: font handling -- is loaded
- 3: unknown font handling --
-\stopmessages
-
-\startmessages romanian library: handlings % to do
- title: handling
- 1: font handling --
- 2: font handling -- is loaded
- 3: unknown font handling --
-\stopmessages
-
-\startmessages french library: handlings
- title: manipulation
- 1: manipulation -- de police
- 2: la manipulation -- de police est chargée
- 3: manipulation -- inconnue de police
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
\newif\iftracefonthandling % \tracefonthandlingtrue
@@ -81,8 +41,6 @@
% much in common with hz/protruding defs
% todo: fix others
-\let\normalchar\char % also done in enco-ini
-
\def\dosetsomehandling#1#2#3 #4 % no define since directly set
{\ifskiphandlingdef \else
\doifnumberelse{\string#2}
@@ -105,17 +63,6 @@
\let\char\normalchar}}%
\fi}
-% \def\dosettriplethandling#1#2#3 #4 #5 #6 % no define since directly set
-% {\ifskiphandlingdef \else
-% \doifnumberelse{\string#2}
-% {#1{#2#3}{#4}{#5}{#6}}
-% {\doifelsenothing{#3}
-% {#1{`#2}{#4}{#5}{#6}}
-% {\let\char\empty
-% \doifnumberelse{\csname#2#3\endcsname}{#1{\csname#2#3\endcsname}{#4}{#5}{#6}}\donothing
-% \let\char\normalchar}}%
-% \fi}
-
\def\dosetquartethandling#1#2#3 #4 #5 #6 #7 % no define since directly set
{\ifskiphandlingdef \else
\doifnumberelse{\string#2}
@@ -127,14 +74,6 @@
\let\char\normalchar}}%
\fi}
-
-% \def\doinhsomehandling#1#2 #3 %
-% {\ifskiphandlingdef \else
-% \let\char\empty
-% \doifnumberelse{\csname#2\endcsname}{#1{\csname#2\endcsname}{`#3}}\donothing
-% \let\char\normalchar
-% \fi}
-
\def\doinhsomehandling#1#2#3 #4 % to be checked
{\ifskiphandlingdef \else
\if#3\relax\relax
diff --git a/tex/context/base/hand-ini.mkiv b/tex/context/base/hand-ini.mkiv
index 527c32da7..41e9db415 100644
--- a/tex/context/base/hand-ini.mkiv
+++ b/tex/context/base/hand-ini.mkiv
@@ -36,7 +36,7 @@
\appendtoks \disableadjusting \to \everyforgetall % Here or not here?
\appendtoks \disableprotruding \to \everyforgetall % Here or not here?
-\def\startfonthandling #1{\fonthandlingerror\gobbleuntil\stopfonthandling} % can't happen
+\def\startfonthandling #1{\fonthandlingerror\fonthandlingerror\gobbleuntil\stopfonthandling} % can't happen
\def\definefonthandling {\dotripleempty\dodefinefonthandling}
\def\setupfonthandling {\dodoubleempty\dosetupfonthandling }
\def\dodefinefonthandling[#1][#2][#3]{\fonthandlingerror}
diff --git a/tex/context/base/hand-ini.tex b/tex/context/base/hand-ini.tex
deleted file mode 100644
index 4d19b5284..000000000
--- a/tex/context/base/hand-ini.tex
+++ /dev/null
@@ -1,18 +0,0 @@
-%D \module
-%D [ file=hand-ini, % moved from enco-ini / pro
-%D version=2000.12.27, % 1998.12.03,
-%D title=\CONTEXT\ Handling Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Handling Macros (ini)}
-
-\loadmarkfile{hand-ini}
-
-\endinput
diff --git a/tex/context/base/java-ini.tex b/tex/context/base/java-ini.mkii
index 7dc2cfe04..e929da108 100644
--- a/tex/context/base/java-ini.tex
+++ b/tex/context/base/java-ini.mkii
@@ -11,10 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context JavaScript Macros / Initialization}
+\writestatus{loading}{ConTeXt JavaScript Macros / Initialization}
% BUG: preamble zonder used/used en split
+% todo: lua sanitizer
+
% JavaScript support is under development. In the near future
% a slightly different model will be used. The JScode stuff
% will probably become just auto function inclusion and the
@@ -33,53 +35,21 @@
%D variables to a \JAVASCRIPT\ is closely related to other core
%D macros. First some messages:
-\startmessages dutch library: javascript
- title: javascript
- 1: script set -- wordt geladen
- 2: onbekende preamble --
-\stopmessages
-
-\startmessages english library: javascript
- title: javascript
- 1: loading script set --
- 2: unknown preamble --
-\stopmessages
-
-\startmessages german library: javascript
- title: javascript
- 1: Lade Scriptdatei --
- 2: unbekannte Preamble --
-\stopmessages
-
-\startmessages czech library: javascript
- title: javascript
- 1: nacita se soubor skriptu --
- 2: neznama preambule --
-\stopmessages
-
-\startmessages italian library: javascript
- title: javascript
- 1: caricamento dello script set --
- 2: preambolo sconosciuto --
-\stopmessages
-
-\startmessages norwegian library: javascript
- title: javascript
- 1: leser inn scriptsett --
- 2: ukjent 'preamble' --
-\stopmessages
-
-\startmessages romanian library: javascript
- title: javascript
- 1: se incarca scriptul --
- 2: preambul necunoscut --
-\stopmessages
-
-\startmessages french library: javascript
- title: javascript
- 1: chargement du jeu de script --
- 2: préambule -- inconnu
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D \TEX\ is not the right tool to check the \JAVA\ code; the
@@ -428,6 +398,7 @@
{\ifx\allJSpreambles\empty\else
\bgroup
\setverbosecscharacters
+ \obeyspaces \let\obeyedspace\normalspace
\def\par{\delcharacter}% was: { }
\globallet\JSpreamble\empty
\def\@@collectedJSpreamble{\r!java\r!java collected}%
diff --git a/tex/context/base/java-ini.mkiv b/tex/context/base/java-ini.mkiv
new file mode 100644
index 000000000..53c36d65f
--- /dev/null
+++ b/tex/context/base/java-ini.mkiv
@@ -0,0 +1,688 @@
+%D \module
+%D [ file=java-ini,
+%D version=1998.01.30,
+%D title=\CONTEXT\ JavaScript Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt JavaScript Macros / Initialization}
+
+% BUG: preamble zonder used/used en split
+
+% todo: lua sanitizer
+
+% JavaScript support is under development. In the near future
+% a slightly different model will be used. The JScode stuff
+% will probably become just auto function inclusion and the
+% JS_* things will disappear. First I have to find a way to
+% deal with global variables so the 'uses' thing will remain.
+
+% ook p{ref}
+% documentation should be corrected to JS(
+
+% Also, obeylines will be supported.
+
+\unprotect
+
+%D \JAVA\ support is not implemented as a generic support
+%D module. The main reason for this is that passing system
+%D variables to a \JAVASCRIPT\ is closely related to other core
+%D macros. First some messages:
+
+%D \TEX\ is not the right tool to check the \JAVA\ code; the
+%D most we can do is reporting some passed variables:
+
+\newif\iftraceJScode \traceJScodefalse
+
+\let\traceJScode\traceJScodetrue
+
+%D A bit out of place, but not dangerous:
+
+\bgroup
+\catcode127=\@@letter
+\gdef\delcharacter{^^7f}
+\egroup
+
+%D The number of passed variables is minimalized by setting the
+%D next switch.
+
+\newif\ifminimalizeJScode \minimalizeJScodetrue
+
+%D \macros
+%D {JS*}
+%D
+%D Because \JAVASCRIPT's are activated by the user, for
+%D instance by activating on a button, their support is closely
+%D related to the referencing mechanism. Integration takes
+%D place by
+%D
+%D \starttyping
+%D \goto{calculate total}[Sum()]
+%D \stoptyping
+%D
+%D The \type{()} classify this as a script. If they are absent,
+%D the keyword is treated as a normal reference.
+%D
+%D One can pass arguments to such a script by saying:
+%D
+%D \starttyping
+%D \goto{calculate total}[Sum(1.5,2.3)]
+%D \stoptyping
+%D
+%D References are passed by using the \type{R{}} classifier.
+%D
+%D \starttyping
+%D \goto{calculate total}[Sum(1.5,2.3,R{overflow})]
+%D \stoptyping
+%D
+%D The last call calls the script \type{Sum} and passes the
+%D next set of variables:
+%D
+%D \starttyping
+%D JS_S_1="1.5";
+%D JS_S_2="2.3";
+%D JS_R_3="overflow";
+%D JS_P_3=3;
+%D \stoptyping
+%D
+%D The first two parameters are just strings, the third one
+%D however is treated as a reference and results in passing the
+%D reference (if needed this references is prefixed) and the
+%D (real) page number. The alternative:
+%D
+%D \starttyping
+%D \goto{calculate total}[JS(Sum{V{1.5},V{2.3},R{overflow}})]
+%D \stoptyping
+%D
+%D does a verbose passing:
+%D
+%D \starttyping
+%D JS_V_1=1.5;
+%D JS_V_2=2.3;
+%D JS_R_3="overflow";
+%D JS_P_3=3;
+%D \stoptyping
+% %D
+% %D Finally we have a counter that tells\JAVA\ how many
+% %D arguments were passed,
+% %D
+% %D \starttyping
+% %D JS_N
+% %D \stoptyping
+
+%D We will also support direct function calls. In that case
+%D no intermediate variables are used.
+
+%D \macros
+%D {startJScode}
+%D
+%D A piece of \JAVASCRIPT\ code is defined by saying:
+%D
+%D \starttyping
+%D \startJScode{SomeScript}
+%D var Item=this.getField("item");
+%D N=Item.getArray();
+%D Total=this.getField("total");
+%D Total.value=0;
+%D for (j=0; j<N.length; j++)
+%D { if (N[j].value!="")
+%D { Total.value += N[j].value } } ;
+%D if ((JS_N>0) && (JS_R_1!=""))
+%D { gotoNamedDest(JS_R_1) };
+%D \stopJScode
+%D \stoptyping
+%D
+%D Such a piece of code is closely related to the interpreter
+%D used. Watch the last two lines, here the script adapts
+%D itself to the presence of a reference.
+%D
+%D While
+%D
+%D \starttyping
+%D \startJScode{name}
+%D name = 4 ;
+%D \stopJScode
+%D \stoptyping
+%D
+%D assumes uses no preamble or presumes that the preamble is
+%D always loaded, the next definition also tells \CONTEXT\ to
+%D actually include the preamble needed.
+%D
+%D \starttyping
+%D \startJScode{uses} uses {later}
+%D uses = 6 ;
+%D \stopJScode
+%D \stoptyping
+
+\long\def\startJScode#1 #2
+ {\doifelse{#2}{uses}
+ {\dostartJScodeA{#1}}
+ {\dostartJScodeB{#1} #2 }}
+
+\long\def\dostartJScodeA#1#2 #3\stopJScode
+ {\long\setgvalue{\r!java#1}{\do{#2}{#3}}}
+
+\long\def\dostartJScodeB#1#2\stopJScode
+ {\long\setgvalue{\r!java#1}{\do{}{#2}}}
+
+\let\stopJScode\relax
+
+%D \macros
+%D {presetJScode}
+%D
+%D The code can be retrieved by saying
+%D
+%D \starttyping
+%D \presetJScode{SomeScript}{template}
+%D \stoptyping
+%D
+%D Such a template is a comma separated list, where
+%D individual entries can optionally be transformed by
+%D \type{R{}} and \type{V{}}.
+%D
+%D After this call, the code is available in \type{\JScode}.
+
+\newif\ifdirectJScode
+
+\def\presetJScode#1#2% #1=operation #2=arguments
+ {\setverbosecscharacters
+ \def\par{\delcharacter}% was: { }
+ \scratchcounter\zerocount
+ \globallet\JScode\empty
+ \def\do##1##2%
+ {\doifelse{##2}{!}\directJScodetrue\directJScodefalse}%
+ \getvalue{\r!java#1}%
+ \edef\!!stringa{#2}%
+ \ifx\!!stringa\empty \else
+ \processcommacommand[\!!stringa]\dopresetJSvariables
+ \fi
+ \def\docommand##1%
+ {\doifundefinedelse{\r!java\r!java##1}
+ {\showmessage\m!javascript2{##1}}
+ {\useJSpreamblenow{##1}}}%
+% {\doglobal\increment\currentJSpreamble
+% \doglobal\addtocommalist{##1}\allJSpreambles}}%
+ \def\do##1##2%
+ {\xdef\JScode{\ifdirectJScode#1(\JScode)\else\JScode##2\fi}%
+ %\xdef\JScode{JS\string_N=\the\scratchcounter;\JScode}%
+ \processcommalist[##1]\docommand}%
+ \getvalue{\r!java#1}}
+
+\def\dopresetJSvariables#1%
+ {\advance\scratchcounter \plusone
+ \donefalse
+ \dodopresetJSvariables#1\end}%
+
+\def\dodopresetJSvariables
+ {\doifnextcharelse R\dodopresetJSrefvariables
+ {\doifnextcharelse V\dodopresetJSvervariables
+ {\doifnextcharelse S\dodopresetJSstrvariables
+ \dodopresetJSrawvariables}}}
+
+\def\dodopresetJSrefvariables R#1\end
+ {\doifreferencefoundelse{#1}
+ {\donetrue \dododopresetJSvariables R{\referenceprefix#1}%
+ \donefalse\dododopresetJSvariables P{\currentrealreference}}
+ {\unknownreference{#1}}%
+ \ifminimalizeJScode \else
+ \donetrue\dododopresetJSvariables S{#1}%
+ \fi}
+
+\def\dodopresetJSvervariables V#1\end
+ {\donefalse\dododopresetJSvariables V{#1}%
+ \ifminimalizeJScode \else
+ \donetrue\dododopresetJSvariables S{#1}%
+ \fi}
+
+\def\dodopresetJSstrvariables S#1\end
+ {\donetrue\dododopresetJSvariables S{#1}}
+
+\def\dodopresetJSrawvariables #1\end
+ {\donetrue\dododopresetJSvariables S{#1}}
+
+\def\JSprefix#1%
+ {JS\string_#1\string_\the\scratchcounter}
+
+\def\dododopresetJSvariables#1#2%
+ {\iftraceJScode
+ \writestatus{JavaScript}{\JSprefix#1=#2}
+ \xdef\JScode{\JScode console.println("\JSprefix#1=#2"); }%
+ \fi
+ \ifdirectJScode
+ \xdef\JScode{\ifx\JScode\empty\else\JScode,\fi\ifdone"#2"\else#2\fi}%
+ \else
+ \xdef\JScode{\JScode\JSprefix#1=\ifdone"#2"\else#2\fi; }%
+ \fi}
+
+%D \macros
+%D {startJSpreamble, flushJSpreamble}
+%D
+%D One can define insert \JAVASCRIPT\ code at the document level
+%D by using:
+%D
+%D \starttyping
+%D \startJSpreamble{oeps}
+%D oeps = 1 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D which is the same as:
+%D
+%D \starttyping
+%D \startJSpreamble{now} used now
+%D now = 2 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D while the next definition is only included when actually
+%D used.
+%D
+%D \starttyping
+%D \startJSpreamble{later} used later
+%D later = 3 ;
+%D \stopJSpreamble
+%D \stoptyping
+%D
+%D This command may be used more that once, but always before
+%D the first page is shipped out.
+
+\newif\ifoneJSpreamble \oneJSpreamblefalse
+
+\let\allJSpreambles\empty
+\newcounter\nofJSpreambles
+\newcounter\currentJSpreamble
+
+\long\def\startJSpreamble#1 #2 %
+ {\bgroup % we need to restore the catcodes
+ \restoreendofline % just in case it happens while reading lists
+ \doifelse{#2}{used}
+ {\dostartJSpreamble#1 }
+ {\dostartJSpreamble#1 now #2 }}
+
+\long\def\dostartJSpreamble#1 #2 %
+ {\processaction
+ [#2]
+ [ later=>\chardef\JSstatus\zerocount,%
+ now=>\chardef\JSstatus\plusone ,%
+ \s!default=>\chardef\JSstatus\plustwo ,%
+ \s!unknown=>\chardef\JSstatus\plustwo ]%
+ \ifaddJSlinebreaks
+ \obeylines \let\obeyedline \normalpar
+ \obeyspaces \let\obeyedspace\normalspace
+ \fi
+ \dodostartJSpreamble{#1}}
+
+\long\def\dodostartJSpreamble#1#2\stopJSpreamble
+ {\presetJSfunctions #2function ()\end
+ \long\setgvalue{\r!java\r!java#1}{#2}%
+ \ifcase\JSstatus \else
+ \useJSpreamblenow{#1}%
+ \fi
+ \egroup}
+
+%D \macros
+%D {setJSpreamble, addtoJSpreamble}
+%D
+%D In addition to the previous preamble definitions, we can
+%D set a preamble \quote {in||line} and add tokens to a
+%D preamble.
+
+\def\setJSpreamble#1#2%
+ {\doifundefined{\r!java\r!java#1}
+ {\setgvalue{\r!java\r!java#1}{#2;}%
+ \doglobal\increment\currentJSpreamble
+ \doglobal\addtocommalist{#1}\allJSpreambles}}
+
+\def\addtoJSpreamble#1#2%
+ {\doifdefinedelse{\r!java\r!java#1}
+ {\edef\!!stringa{\r!java\r!java#1}%
+ \edef\!!stringb{\csname\!!stringa\endcsname}%
+ \@EA\setgvalue\@EA\!!stringa\@EA{\!!stringb #2;}}
+ {\setJSpreamble{#1}{#2}}}
+
+%D \macros
+%D {useJSpreamblenow}
+%D
+%D The next macro can be used to force inclusion of postponed
+%D \JAVASCRIPT\ preambles.
+
+\def\useJSpreamblenow#1%
+ {\doglobal\increment\currentJSpreamble
+ \doglobal\addtocommalist{#1}\allJSpreambles}
+
+%D Because we want to check for valid calls, we preload the
+%D functions. This means that we can call them directly as
+%D well as indirectly when defined by \type {\startJScode} etc.
+
+% \long\def\presetJSfunctions#1function #2(#3)%
+% {\doifelsenothing{#2}
+% {\long\def\presetJSfunctions##1\end{}}
+% {\stripspaces\from#2\to\ascii
+% \doifundefined{\r!java\ascii}{\setgvalue{\r!java\ascii}{\do{}{!}}}}%
+% \presetJSfunctions}
+
+\long\def\presetJSfunctions#1function#2(#3)%
+ {\doifelse{#2}\space
+ {\long\def\presetJSfunctions##1\end{}}
+ {\stripspaces\from#2\to\ascii
+ \doifundefined{\r!java\ascii}{\setgvalue{\r!java\ascii}{\do{}{!}}}}%
+ \presetJSfunctions}
+
+\def\getJSpreamble#1%
+ {\getvalue{\r!java\r!java#1}}
+
+\def\presetJSpreamble
+ {\ifx\allJSpreambles\empty\else
+ \bgroup
+ \setverbosecscharacters
+ \obeyspaces \let\obeyedspace\normalspace
+ \def\par{\delcharacter}% was: { }
+ \globallet\JSpreamble\empty
+ \def\@@collectedJSpreamble{\r!java\r!java collected}%
+ \letvalue{\@@collectedJSpreamble}=\empty
+ \def\docommand##1%
+ {\xdef\JScode{\getvalue{\r!java\r!java##1}}%
+ \ifoneJSpreamble % \global\letcdcsname
+ \@EA\setxvalue\@EA\@@collectedJSpreamble\@EA
+ {\csname\@@collectedJSpreamble\endcsname\JScode}%
+ \else
+ \setxvalue{\r!java\r!java##1}{\JScode}%
+ \fi}%
+ \processcommacommand[\allJSpreambles]\docommand
+ \ifoneJSpreamble
+ \gdef\allJSpreambles{collected}%
+ \fi
+ \globallet\presetJSpreamble\relax
+ \egroup
+ \fi}
+
+\def\flushJSpreamble
+ {\iflocation\ifx\allJSpreambles\empty\else
+ \ifcase\nofJSpreambles\else\ifnum\nofJSpreambles=\currentJSpreamble
+ \bgroup
+ \presetJSpreamble
+ \expanded{\doflushJSpreamble{\allJSpreambles}}%
+ \globallet\flushJSpreamble\relax
+ \globallet\allJSpreambles\empty
+ \egroup
+ \fi\fi
+ \fi\fi}
+
+\def\finalflushJSpreamble
+ {\iflocation
+ \flushJSpreamble
+ \ifcase\currentJSpreamble\relax\else
+ \savecurrentvalue\nofJSpreambles\currentJSpreamble
+ \globallet\currentJSpreamble\nofJSpreambles
+ \fi
+ \fi}
+
+%D \macros
+%D {doPSsanitizeJScode}
+%D
+%D Before the code can be passed to the (\POSTSCRIPT\ or \PDF)
+%D output file, some precautions must be made concerning the
+%D use of \type{(} and~\type{)}. Here we use a beautiful
+%D \type{\aftergroup} trick I discovered in the \TABLE\ format.
+
+\def\doPSsanitizeJScode#1\to#2%
+ {\begingroup
+ \scratchcounter\zerocount % \aftergroup counter
+ \aftergroup\xdef
+ \aftergroup#2%
+ \aftergroup{%
+ \expanded{\defconvertedargument\noexpand\JScode{#1}}%
+ \expandafter\handletokens\JScode\with\dodoPSsanitizeJScode
+ \aftergroup}%
+ \endgroup
+ \iftraceJScode
+ \writestatus{JS trace}{#2}%
+ \fi}
+
+%D I started with:
+%D
+%D \starttyping
+%D \def\dodoPSsanitizeJScode#1%
+%D {\aftergroup\string
+%D \if#1(%
+%D \expandafter\aftergroup\csname#1\endcsname
+%D \else\if#1)%
+%D \expandafter\aftergroup\csname#1\endcsname
+%D \else\if#1;%
+%D \aftergroup;\aftergroup\string\expandafter\aftergroup\
+%D \else
+%D \expandafter\aftergroup#1%
+%D \fi\fi\fi
+%D \advance\scratchcounter by 1
+%D \ifnum\scratchcounter=500
+%D \expandafter\dododoPSsanitizeJScode
+%D \fi}
+%D \stoptyping
+%D
+%D For pretty printing purposes, we need some way to signal
+%D \TEX\ macros. Therefore we introduce a special keyword
+%D \type{TEX}. When followed by a space, this keyword is
+%D ignored, that is, filtered from the stream. Now we have:
+
+\chardef\JSisTEX \zerocount
+\chardef\JScomment\zerocount
+
+\newif\ifaddJSlinebreaks \addJSlinebreakstrue
+
+\def\flushJSisTEX
+ {\ifcase\JSisTEX
+ \or \aftergroup T%
+ \or \aftergroup T\aftergroup E%
+ \or \aftergroup T\aftergroup E\aftergroup X%
+ \fi
+ \chardef\JSisTEX\zerocount}
+
+% \def\doJSlinebreak
+% {\ifaddJSlinebreaks
+% \aftergroup\string\aftergroup\n%
+% \fi}
+%
+% \def\dodoPSsanitizeJScode#1% % input stack>500 & TEX check
+% {\if#1/%
+% \ifnum\JScomment=0
+% \chardef\JScomment\plusone
+% \else\ifnum\JScomment=1
+% \chardef\JScomment\plustwo
+% \fi\fi
+% \else
+% \ifnum\JScomment=1
+% \aftergroup/%
+% \chardef\JScomment\zerocount
+% \fi
+% \ifnum\JScomment=2
+% \if#1\delcharacter
+% \chardef\JScomment\zerocount
+% \fi
+% \else
+% \if#1\delcharacter
+% \flushJSisTEX\doJSlinebreak
+% \else\if#1(%
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+% \else\if#1)%
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+% \else\if#1;%
+% \flushJSisTEX\aftergroup;\doJSlinebreak
+% \else\if#1T%
+% \ifnum\JSisTEX=0 \chardef\JSisTEX\plusone \else\flushJSisTEX\aftergroup T\fi
+% \else\if#1E%
+% \ifnum\JSisTEX=1 \chardef\JSisTEX\plustwo \else\flushJSisTEX\aftergroup E\fi
+% \else\if#1X%
+% \ifnum\JSisTEX=2 \chardef\JSisTEX\plusthree \else\flushJSisTEX\aftergroup X\fi
+% \else\if#1\normalspace
+% \ifnum\JSisTEX=3 \chardef\JSisTEX\zerocount \else\flushJSisTEX\aftergroup#1\fi
+% \else
+% \flushJSisTEX\aftergroup\string\expandafter\aftergroup#1%
+% \fi\fi\fi\fi\fi\fi\fi\fi
+% \fi
+% \fi
+% \dododoPSsanitizeJScode}
+
+% todo: "http:\\" -> simple. maar wel \" afvangen
+%
+% use new pdftex escape mechanism or make fully expandable version, not used that often btw
+
+\chardef\JSstring\zerocount
+
+\def\doJSlinebreak
+ {\chardef\JScomment\zerocount
+ \chardef\JSstring\zerocount
+ \ifaddJSlinebreaks
+ \aftergroup\string\aftergroup\n%
+ \fi}
+
+\def\dodoPSsanitizeJScode#1% % input stack>500 & TEX check
+ {\if#1/%
+ \ifnum\JSstring=0
+ \ifnum\JScomment=0
+ \chardef\JScomment\plusone
+ \else\ifnum\JScomment=1
+ \chardef\JScomment\plustwo
+ \fi\fi
+ \else
+ \aftergroup/%
+ \fi
+ \else
+ \ifnum\JScomment=1
+ \aftergroup/%
+ \chardef\JScomment\zerocount
+ \fi
+ % is the delchar trick still needed?
+ \ifnum\JScomment=2
+ \ifnum`#1=13 % brrr
+ \doJSlinebreak
+ \else\if#1\par
+ \doJSlinebreak
+ \else\if#1\delcharacter
+ \doJSlinebreak
+ \fi\fi\fi
+ \else
+ \ifnum`#1=13 % brrr
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1\par
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1\delcharacter
+ \flushJSisTEX\doJSlinebreak
+ \else\if#1(%
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+ \else\if#1)%
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup\csname#1\endcsname
+ %\else\if#1;%
+ % \flushJSisTEX\aftergroup;\doJSlinebreak
+ \else\if#1T%
+ \ifnum\JSisTEX=0 \chardef\JSisTEX\plusone \else\flushJSisTEX\aftergroup T\fi
+ \else\if#1E%
+ \ifnum\JSisTEX=1 \chardef\JSisTEX\plustwo \else\flushJSisTEX\aftergroup E\fi
+ \else\if#1X%
+ \ifnum\JSisTEX=2 \chardef\JSisTEX\plusthree \else\flushJSisTEX\aftergroup X\fi
+ \else\if#1\normalspace
+ \ifnum\JSisTEX=3 \chardef\JSisTEX\zerocount \else\flushJSisTEX\aftergroup#1\fi
+ \else
+ % todo: "test\"test"
+ \if#1"%
+ \ifcase\JSstring
+ \chardef\JSstring\plusone
+ \else
+ \chardef\JSstring\zerocount
+ \fi
+ \fi
+ \flushJSisTEX\aftergroup\string\expandafter\aftergroup#1%
+ \fi\fi\fi\fi\fi\fi\fi\fi\fi % \fi
+ \fi
+ \fi
+ \dododoPSsanitizeJScode}
+
+%D Close reading learns that one line comments (\type{// ...})
+%D are removed from the stream. This permits switching in
+%D pretty printing \JAVASCRIPT\ sources as well as saves
+%D some bytes.
+
+%D The magic 500 in the next hack prevents the input stack from
+%D overflowing when large scripts are sanitized.
+
+\def\dododoPSsanitizeJScode
+ {\ifcase\JSisTEX\ifcase\JScomment
+ \advance\scratchcounter \plusone
+ \fi\fi
+ \ifnum\scratchcounter=500
+ \expandafter\dodododoPSsanitizeJScode
+ \fi}
+
+\def\dodododoPSsanitizeJScode
+ {\let\next={%
+ \aftergroup}%
+ \endgroup
+ \begingroup
+ \aftergroup\xdef
+ \aftergroup\sanitizedJScode
+ \aftergroup{%
+ \aftergroup\sanitizedJScode
+ \let\next=}}
+
+%D The macro \type{\doPSsanitizeJScode} converts its argument
+%D into the macro \type{\sanitizedJScode}, thereby prefixing
+%D each \type{(} and \type{)} by a slash.
+
+%D Hooking this mechanism into the general \CONTEXT\ reference
+%D mechanism does not take much effort:
+
+\definespecialtest{JS}%
+ {\doifdefinedelse{\r!java\currentreferenceoperation}}
+
+\def\gotojavascriptspecial#1#2#3#4% special operation arguments data
+ {\begingroup
+ \iflocation
+ \bgroup
+ \presetJScode{#2}{#3}%
+ \egroup
+ \dohandlegoto{#4}{\dostartgotoJS\buttonwidth\buttonheight\JScode}{\dostopgotoJS}%
+ \else
+ #4%
+ \fi
+ \endgroup}
+
+%D \macros
+%D {useJSscripts}
+%D
+%D In due time, users will build their collections of scripts,
+%D which can be used (loaded) when applicable. Although not all
+%D public, we will provide some general purpose scripts,
+%D collected in files with names like \type{java-...}. One can
+%D load these scripts with \type{\useJSscripts}, like:
+%D
+%D \starttyping
+%D \useJSscripts[fld]
+%D \stoptyping
+%D
+%D The not so complicated implementation of this macro is:
+
+\def\dodouseJSscripts#1%
+ {\doifelse{#1}\v!reset
+ {\let\allJSpreambles\empty}
+ {\doifundefined{\c!file\f!javascriptprefix#1}
+ {\startnointerference
+ \letgvalueempty{\c!file\f!javascriptprefix#1}%
+ \makeshortfilename[\f!javascriptprefix#1]%
+ \startreadingfile
+ \readsysfile\shortfilename{\showmessage\m!javascript1{#1}}\donothing
+ \stopreadingfile
+ \stopnointerference}}}
+
+\def\douseJSscripts[#1][#2]%
+ {\processcommalist[#1]\dodouseJSscripts
+ \processcommalist[#2]\useJSpreamblenow}
+
+\def\useJSscripts
+ {\dodoubleempty\douseJSscripts}
+
+\protect \endinput
diff --git a/tex/context/base/l-aux.lua b/tex/context/base/l-aux.lua
index 9705fb711..6b1fd67ff 100644
--- a/tex/context/base/l-aux.lua
+++ b/tex/context/base/l-aux.lua
@@ -1,68 +1,94 @@
--- filename : l-aux.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-aux'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-aux'] = 1.001
-if not aux then aux = { } end
+aux = aux or { }
-local concat, format = table.concat, string.format
+local concat, format, gmatch = table.concat, string.format, string.gmatch
local tostring, type = tostring, type
-do
+local space = lpeg.P(' ')
+local equal = lpeg.P("=")
+local comma = lpeg.P(",")
+local lbrace = lpeg.P("{")
+local rbrace = lpeg.P("}")
+local nobrace = 1 - (lbrace+rbrace)
+local nested = lpeg.P{ lbrace * (nobrace + lpeg.V(1))^0 * rbrace }
+local spaces = space^0
- local hash = { }
+local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
- local function set(key,value) -- using Carg is slower here
- hash[key] = value
+local key = lpeg.C((1-equal-comma)^1)
+local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C(""))
+
+local key = lpeg.C((1-space-equal-comma)^1)
+local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + lpeg.C("")))
+
+-- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored
+
+local hash = { }
+
+local function set(key,value) -- using Carg is slower here
+ hash[key] = value
+end
+
+local pattern_a_s = (pattern_a/set)^1
+local pattern_b_s = (pattern_b/set)^1
+
+aux.settings_to_hash_pattern_a = pattern_a_s
+aux.settings_to_hash_pattern_b = pattern_b_s
+
+function aux.make_settings_to_hash_pattern(set,moretolerant)
+ if moretolerant then
+ return (pattern_b/set)^1
+ else
+ return (pattern_a/set)^1
end
+end
- local space = lpeg.P(' ')
- local equal = lpeg.P("=")
- local comma = lpeg.P(",")
- local lbrace = lpeg.P("{")
- local rbrace = lpeg.P("}")
- local nobrace = 1 - (lbrace+rbrace)
- local nested = lpeg.P{ lbrace * (nobrace + lpeg.V(1))^0 * rbrace }
-
- local key = lpeg.C((1-equal-comma)^1)
- local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
--- local pattern = (((space+comma)^0 * (key * equal * value + key) * comma^0) / set)^1
- local pattern = (((space+comma)^0 * (key * equal * value + key * lpeg.C(""))) / set)^1
-
- -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored
-
- function aux.settings_to_hash(str)
- if str and str ~= "" then
- hash = { }
- pattern:match(str)
- return hash
+function aux.settings_to_hash(str,moretolerant)
+ if str and str ~= "" then
+ hash = { }
+ if moretolerant then
+ pattern_b_s:match(str)
else
- return { }
+ pattern_a_s:match(str)
end
+ return hash
+ else
+ return { }
end
+end
- local seperator = comma * space^0
- local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
- local pattern = lpeg.Ct(value*(seperator*value)^0)
+local seperator = comma * space^0
+local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0)
+local pattern = lpeg.Ct(value*(seperator*value)^0)
- -- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
+-- "aap, {noot}, mies" : outer {} removes, leading spaces ignored
- function aux.settings_to_array(str)
- return pattern:match(str)
- end
+aux.settings_to_array_pattern = pattern
- local function set(t,v)
- t[#t+1] = v
+function aux.settings_to_array(str)
+ if not str or str == "" then
+ return { }
+ else
+ return pattern:match(str)
end
+end
- local value = lpeg.P(lpeg.Carg(1)*value) / set
- local pattern = value*(seperator*value)^0 * lpeg.Carg(1)
+local function set(t,v)
+ t[#t+1] = v
+end
- function aux.add_settings_to_array(t,str)
- return pattern:match(str, nil, t)
- end
+local value = lpeg.P(lpeg.Carg(1)*value) / set
+local pattern = value*(seperator*value)^0 * lpeg.Carg(1)
+function aux.add_settings_to_array(t,str)
+ return pattern:match(str, nil, t)
end
function aux.hash_to_string(h,separator,yes,no,strict,omit)
@@ -102,9 +128,9 @@ function aux.array_to_string(a,separator)
end
end
-function aux.settings_to_set(str)
- local t = { }
- for s in str:gmatch("%s*([^,]+)") do
+function aux.settings_to_set(str,t)
+ t = t or { }
+ for s in gmatch(str,"%s*([^,]+)") do
t[s] = true
end
return t
@@ -152,7 +178,7 @@ end
function aux.definetable(target) -- defines undefined tables
local composed, t = nil, { }
- for name in target:gmatch("([^%.]+)") do
+ for name in gmatch(target,"([^%.]+)") do
if composed then
composed = composed .. "." .. name
else
@@ -165,7 +191,7 @@ end
function aux.accesstable(target)
local t = _G
- for name in target:gmatch("([^%.]+)") do
+ for name in gmatch(target,"([^%.]+)") do
t = t[name]
end
return t
diff --git a/tex/context/base/l-boolean.lua b/tex/context/base/l-boolean.lua
index 1542238c4..c8c919eda 100644
--- a/tex/context/base/l-boolean.lua
+++ b/tex/context/base/l-boolean.lua
@@ -1,11 +1,14 @@
--- filename : l-boolean.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-boolean'] = 1.001
-if not boolean then boolean = { } end
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
function boolean.tonumber(b)
if b then return 1 else return 0 end
diff --git a/tex/context/base/l-dimen.lua b/tex/context/base/l-dimen.lua
index 103cb2d88..32becb276 100644
--- a/tex/context/base/l-dimen.lua
+++ b/tex/context/base/l-dimen.lua
@@ -15,6 +15,8 @@ done by using the conversion factors collected in the following
table.</p>
--ldx]]--
+local format, type = string.format, type
+
local dimenfactors = {
["pt"] = 1/65536,
["in"] = ( 100/ 7227)/65536,
@@ -39,7 +41,7 @@ local function todimen(n,unit,fmt)
return n
else
unit = unit or 'pt'
- return (fmt or "%.5f%s"):format(n*dimenfactors[unit],unit)
+ return format(fmt or "%.5f%s",n*dimenfactors[unit],unit)
end
end
@@ -73,10 +75,10 @@ a number and optionally a unit. When no unit is given a constant
capture takes place.</p>
--ldx]]--
-local amount = lpeg.S("+-")^0 * lpeg.R("09")^0 * (lpeg.P(".") * lpeg.R("09")^1)^0
-local unit = lpeg.R("az")^1 / dimenfactors -- produces a capture
+local amount = (lpeg.S("+-")^0 * lpeg.R("09")^0 * lpeg.P(".")^0 * lpeg.R("09")^0) + lpeg.Cc("0")
+local unit = lpeg.R("az")^1
-local pattern = lpeg.C(amount) * (unit^1 + lpeg.Cc(1))
+local pattern = amount/tonumber * (unit^1/dimenfactors + lpeg.Cc(1)) -- tonumber is new
--[[ldx--
<p>We use a metatable to intercept errors. When no key is found in
@@ -96,6 +98,7 @@ function string:todimen()
return self
else
local value, unit = pattern:match(self)
+ print(value,unit)
return value/unit
end
end
@@ -260,7 +263,7 @@ yet be available.</p>
--ldx]]--
function dimensions.texify()
- local fti, fc = fonts and fonts.tfm and fonts.tfm.id, font and font.current
+ local fti, fc = fonts and fonts.ids and fonts.ids, font and font.current
if fti and fc then
dimenfactors["ex"] = function() return fti[fc()].ex_height end
dimenfactors["em"] = function() return fti[fc()].quad end
diff --git a/tex/context/base/l-dir.lua b/tex/context/base/l-dir.lua
index 0a174e18a..5a726303f 100644
--- a/tex/context/base/l-dir.lua
+++ b/tex/context/base/l-dir.lua
@@ -1,202 +1,203 @@
--- filename : l-dir.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-dir'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-dir'] = 1.001
+local type = type
+local find, gmatch = string.find, string.gmatch
-dir = { }
+dir = dir or { }
-- optimizing for no string.find (*) does not save time
-if lfs then do
+local attributes = lfs.attributes
+local walkdir = lfs.dir
- local attributes = lfs.attributes
- local walkdir = lfs.dir
-
- local function glob_pattern(path,patt,recurse,action)
- local ok, scanner
- if path == "/" then
- ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
- else
- ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
- end
- if ok and type(scanner) == "function" then
- if not path:find("/$") then path = path .. '/' end
- for name in scanner do
- local full = path .. name
- local mode = attributes(full,'mode')
- if mode == 'file' then
- if full:find(patt) then
- action(full)
- end
- elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
- glob_pattern(full,patt,recurse,action)
+local function glob_pattern(path,patt,recurse,action)
+ local ok, scanner
+ if path == "/" then
+ ok, scanner = xpcall(function() return walkdir(path..".") end, function() end) -- kepler safe
+ else
+ ok, scanner = xpcall(function() return walkdir(path) end, function() end) -- kepler safe
+ end
+ if ok and type(scanner) == "function" then
+ if not find(path,"/$") then path = path .. '/' end
+ for name in scanner do
+ local full = path .. name
+ local mode = attributes(full,'mode')
+ if mode == 'file' then
+ if find(full,patt) then
+ action(full)
end
+ elseif recurse and (mode == "directory") and (name ~= '.') and (name ~= "..") then
+ glob_pattern(full,patt,recurse,action)
end
end
end
+end
- dir.glob_pattern = glob_pattern
+dir.glob_pattern = glob_pattern
- local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
+local P, S, R, C, Cc, Cs, Ct, Cv, V = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cv, lpeg.V
- local pattern = Ct {
- [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
- [2] = C(((1-S("*?/"))^0 * P("/"))^0),
- [3] = C(P(1)^0)
- }
+local pattern = Ct {
+ [1] = (C(P(".") + P("/")^1) + C(R("az","AZ") * P(":") * P("/")^0) + Cc("./")) * V(2) * V(3),
+ [2] = C(((1-S("*?/"))^0 * P("/"))^0),
+ [3] = C(P(1)^0)
+}
- local filter = Cs ( (
- P("**") / ".*" +
- P("*") / "[^/]*" +
- P("?") / "[^/]" +
- P(".") / "%%." +
- P("+") / "%%+" +
- P("-") / "%%-" +
- P(1)
- )^0 )
+local filter = Cs ( (
+ P("**") / ".*" +
+ P("*") / "[^/]*" +
+ P("?") / "[^/]" +
+ P(".") / "%%." +
+ P("+") / "%%+" +
+ P("-") / "%%-" +
+ P(1)
+)^0 )
- local function glob(str,t)
- if type(str) == "table" then
- local t = t or { }
- for _, s in ipairs(str) do
- glob(s,t)
- end
- return t
- elseif lfs.isfile(str) then
+local function glob(str,t)
+ if type(str) == "table" then
+ local t = t or { }
+ for s=1,#str do
+ glob(str[s],t)
+ end
+ return t
+ elseif lfs.isfile(str) then
+ local t = t or { }
+ t[#t+1] = str
+ return t
+ else
+ local split = pattern:match(str)
+ if split then
local t = t or { }
- t[#t+1] = str
+ local action = action or function(name) t[#t+1] = name end
+ local root, path, base = split[1], split[2], split[3]
+ local recurse = find(base,"%*%*")
+ local start = root .. path
+ local result = filter:match(start .. base)
+ glob_pattern(start,result,recurse,action)
return t
else
- local split = pattern:match(str)
- if split then
- local t = t or { }
- local action = action or function(name) t[#t+1] = name end
- local root, path, base = split[1], split[2], split[3]
- local recurse = base:find("%*%*")
- local start = root .. path
- local result = filter:match(start .. base)
- glob_pattern(start,result,recurse,action)
- return t
- else
- return { }
- end
+ return { }
end
end
+end
- dir.glob = glob
+dir.glob = glob
- --~ list = dir.glob("**/*.tif")
- --~ list = dir.glob("/**/*.tif")
- --~ list = dir.glob("./**/*.tif")
- --~ list = dir.glob("oeps/**/*.tif")
- --~ list = dir.glob("/oeps/**/*.tif")
+--~ list = dir.glob("**/*.tif")
+--~ list = dir.glob("/**/*.tif")
+--~ list = dir.glob("./**/*.tif")
+--~ list = dir.glob("oeps/**/*.tif")
+--~ list = dir.glob("/oeps/**/*.tif")
- local function globfiles(path,recurse,func,files) -- func == pattern or function
- if type(func) == "string" then
- local s = func -- alas, we need this indirect way
- func = function(name) return name:find(s) end
- end
- files = files or { }
- for name in walkdir(path) do
- if name:find("^%.") then
- --- skip
- else
- local mode = attributes(name,'mode')
- if mode == "directory" then
- if recurse then
- globfiles(path .. "/" .. name,recurse,func,files)
- end
- elseif mode == "file" then
- if func then
- if func(name) then
- files[#files+1] = path .. "/" .. name
- end
- else
+local function globfiles(path,recurse,func,files) -- func == pattern or function
+ if type(func) == "string" then
+ local s = func -- alas, we need this indirect way
+ func = function(name) return find(name,s) end
+ end
+ files = files or { }
+ for name in walkdir(path) do
+ if find(name,"^%.") then
+ --- skip
+ else
+ local mode = attributes(name,'mode')
+ if mode == "directory" then
+ if recurse then
+ globfiles(path .. "/" .. name,recurse,func,files)
+ end
+ elseif mode == "file" then
+ if func then
+ if func(name) then
files[#files+1] = path .. "/" .. name
end
+ else
+ files[#files+1] = path .. "/" .. name
end
end
end
- return files
end
+ return files
+end
- dir.globfiles = globfiles
+dir.globfiles = globfiles
- -- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
- -- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
- -- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
- -- t = dir.glob("f:/minimal/tex/**/*")
- -- print(dir.ls("f:/minimal/tex/**/*"))
- -- print(dir.ls("*.tex"))
+-- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex")
+-- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex")
+-- t = dir.glob("c:/data/develop/context/texmf/**/*.tex")
+-- t = dir.glob("f:/minimal/tex/**/*")
+-- print(dir.ls("f:/minimal/tex/**/*"))
+-- print(dir.ls("*.tex"))
- function dir.ls(pattern)
- return table.concat(glob(pattern),"\n")
- end
+function dir.ls(pattern)
+ return table.concat(glob(pattern),"\n")
+end
- --~ mkdirs("temp")
- --~ mkdirs("a/b/c")
- --~ mkdirs(".","/a/b/c")
- --~ mkdirs("a","b","c")
+--~ mkdirs("temp")
+--~ mkdirs("a/b/c")
+--~ mkdirs(".","/a/b/c")
+--~ mkdirs("a","b","c")
- local make_indeed = true -- false
+local make_indeed = true -- false
- if string.find(os.getenv("PATH"),";") then
+if string.find(os.getenv("PATH"),";") then
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- local first, middle, last
- local drive = false
- first, middle, last = str:match("^(//)(//*)(.*)$")
+ end
+ local first, middle, last
+ local drive = false
+ first, middle, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ -- empty network path == local path
+ else
+ first, last = str:match("^(//)/*(.-)$")
if first then
- -- empty network path == local path
+ middle, last = str:match("([^/]+)/+(.-)$")
+ if middle then
+ pth = "//" .. middle
+ else
+ pth = "//" .. last
+ last = ""
+ end
else
- first, last = str:match("^(//)/*(.-)$")
+ first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
if first then
- middle, last = str:match("([^/]+)/+(.-)$")
- if middle then
- pth = "//" .. middle
- else
- pth = "//" .. last
- last = ""
- end
+ pth, drive = first .. middle, true
else
- first, middle, last = str:match("^([a-zA-Z]:)(/*)(.-)$")
- if first then
- pth, drive = first .. middle, true
- else
- middle, last = str:match("^(/*)(.-)$")
- if not middle then
- last = str
- end
+ middle, last = str:match("^(/*)(.-)$")
+ if not middle then
+ last = str
end
end
end
- for s in last:gmatch("[^/]+") do
- if pth == "" then
- pth = s
- elseif drive then
- pth, drive = pth .. s, false
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ for s in gmatch(last,"[^/]+") do
+ if pth == "" then
+ pth = s
+ elseif drive then
+ pth, drive = pth .. s, false
+ else
+ pth = pth .. "/" .. s
+ end
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -210,79 +211,79 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- local first, nothing, last = str:match("^(//)(//*)(.*)$")
- if first then
- first = lfs.currentdir() .. "/"
- first = first:gsub("\\","/")
- end
- if not first then
- first, last = str:match("^(//)/*(.*)$")
- end
- if not first then
- first, last = str:match("^([a-zA-Z]:)(.*)$")
- if first and not last:find("^/") then
- local d = lfs.currentdir()
- if lfs.chdir(first) then
- first = lfs.currentdir()
- first = first:gsub("\\","/")
- end
- lfs.chdir(d)
+ function dir.expand_name(str)
+ local first, nothing, last = str:match("^(//)(//*)(.*)$")
+ if first then
+ first = lfs.currentdir() .. "/"
+ first = first:gsub("\\","/")
+ end
+ if not first then
+ first, last = str:match("^(//)/*(.*)$")
+ end
+ if not first then
+ first, last = str:match("^([a-zA-Z]:)(.*)$")
+ if first and not find(last,"^/") then
+ local d = lfs.currentdir()
+ if lfs.chdir(first) then
+ first = lfs.currentdir()
+ first = first:gsub("\\","/")
end
+ lfs.chdir(d)
end
- if not first then
- first, last = lfs.currentdir(), str
- first = first:gsub("\\","/")
- end
- last = last:gsub("//","/")
- last = last:gsub("/%./","/")
- last = last:gsub("^/*","")
- first = first:gsub("/*$","")
- if last == "" then
- return first
- else
- return first .. "/" .. last
- end
end
+ if not first then
+ first, last = lfs.currentdir(), str
+ first = first:gsub("\\","/")
+ end
+ last = last:gsub("//","/")
+ last = last:gsub("/%./","/")
+ last = last:gsub("^/*","")
+ first = first:gsub("/*$","")
+ if last == "" then
+ return first
+ else
+ return first .. "/" .. last
+ end
+ end
- else
+else
- function dir.mkdirs(...)
- local str, pth = "", ""
- for _, s in ipairs({...}) do
- if s ~= "" then
- if str ~= "" then
- str = str .. "/" .. s
- else
- str = s
- end
+ function dir.mkdirs(...)
+ local str, pth = "", ""
+ for _, s in ipairs({...}) do
+ if s ~= "" then
+ if str ~= "" then
+ str = str .. "/" .. s
+ else
+ str = s
end
end
- str = str:gsub("/+","/")
- if str:find("^/") then
- pth = "/"
- for s in str:gmatch("[^/]+") do
- local first = (pth == "/")
- if first then
- pth = pth .. s
- else
- pth = pth .. "/" .. s
- end
- if make_indeed and not first and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
- end
- else
- pth = "."
- for s in str:gmatch("[^/]+") do
+ end
+ str = str:gsub("/+","/")
+ if find(str,"^/") then
+ pth = "/"
+ for s in gmatch(str,"[^/]+") do
+ local first = (pth == "/")
+ if first then
+ pth = pth .. s
+ else
pth = pth .. "/" .. s
- if make_indeed and not lfs.isdir(pth) then
- lfs.mkdir(pth)
- end
+ end
+ if make_indeed and not first and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
+ end
+ end
+ else
+ pth = "."
+ for s in gmatch(str,"[^/]+") do
+ pth = pth .. "/" .. s
+ if make_indeed and not lfs.isdir(pth) then
+ lfs.mkdir(pth)
end
end
- return pth, (lfs.isdir(pth) == true)
end
+ return pth, (lfs.isdir(pth) == true)
+ end
--~ print(dir.mkdirs("","","a","c"))
--~ print(dir.mkdirs("a"))
@@ -292,17 +293,15 @@ if lfs then do
--~ print(dir.mkdirs("///a/b/c"))
--~ print(dir.mkdirs("a/bbb//ccc/"))
- function dir.expand_name(str)
- if not str:find("^/") then
- str = lfs.currentdir() .. "/" .. str
- end
- str = str:gsub("//","/")
- str = str:gsub("/%./","/")
- return str
+ function dir.expand_name(str)
+ if not find(str,"^/") then
+ str = lfs.currentdir() .. "/" .. str
end
-
+ str = str:gsub("//","/")
+ str = str:gsub("/%./","/")
+ return str
end
- dir.makedirs = dir.mkdirs
+end
-end end
+dir.makedirs = dir.mkdirs
diff --git a/tex/context/base/l-file.lua b/tex/context/base/l-file.lua
index ae4cd426a..0782ac676 100644
--- a/tex/context/base/l-file.lua
+++ b/tex/context/base/l-file.lua
@@ -1,23 +1,24 @@
--- filename : l-file.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-file'] = 1.001
+-- needs a cleanup
-if not file then file = { } end
+file = file or { }
local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
function file.removesuffix(filename)
- return (filename:gsub("%.[%a%d]+$",""))
+ return (gsub(filename,"%.[%a%d]+$",""))
end
-file.stripsuffix = file.removesuffix
-
function file.addsuffix(filename, suffix)
- if not filename:find("%.[%a%d]+$") then
+ if not find(filename,"%.[%a%d]+$") then
return filename .. "." .. suffix
else
return filename
@@ -25,23 +26,23 @@ function file.addsuffix(filename, suffix)
end
function file.replacesuffix(filename, suffix)
- return (filename:gsub("%.[%a%d]+$","")) .. "." .. suffix
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
end
-function file.dirname(name)
- return name:match("^(.+)[/\\].-$") or ""
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
end
function file.basename(name)
- return name:match("^.+[/\\](.-)$") or name
+ return match(name,"^.+[/\\](.-)$") or name
end
function file.nameonly(name)
- return ((name:match("^.+[/\\](.-)$") or name):gsub("%..*$",""))
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
end
function file.extname(name)
- return name:match("^.+%.([^/\\]-)$") or ""
+ return match(name,"^.+%.([^/\\]-)$") or ""
end
file.suffix = file.extname
@@ -54,40 +55,20 @@ file.suffix = file.extname
function file.join(...)
local pth = concat({...},"/")
- pth = pth:gsub("\\","/")
- local a, b = pth:match("^(.*://)(.*)$")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
+ return a .. gsub(b,"//+","/")
end
- a, b = pth:match("^(//)(.*)$")
+ a, b = match(pth,"^(//)(.*)$")
if a and b then
- return a .. b:gsub("//+","/")
- end
- return (pth:gsub("//+","/"))
-end
-
-function file.is_writable(name)
- local f = io.open(name, 'w')
- if f then
- f:close()
- return true
- else
- return false
- end
-end
-
-function file.is_readable(name)
- local f = io.open(name,'r')
- if f then
- f:close()
- return true
- else
- return false
+ return a .. gsub(b,"//+","/")
end
+ return (gsub(pth,"//+","/"))
end
function file.iswritable(name)
- local a = lfs.attributes(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
return a and a.permissions:sub(2,2) == "w"
end
@@ -96,24 +77,18 @@ function file.isreadable(name)
return a and a.permissions:sub(1,1) == "r"
end
---~ function file.split_path(str)
---~ if str:find(';') then
---~ return str:splitchr(";")
---~ else
---~ return str:splitchr(io.pathseparator)
---~ end
---~ end
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
-- todo: lpeg
function file.split_path(str)
local t = { }
- str = str:gsub("\\", "/")
- str = str:gsub("(%a):([;/])", "%1\001%2")
- for name in str:gmatch("([^;:]+)") do
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
if name ~= "" then
- name = name:gsub("\001",":")
- t[#t+1] = name
+ t[#t+1] = gsub(name,"\001",":")
end
end
return t
@@ -124,15 +99,15 @@ function file.join_path(tab)
end
function file.collapse_path(str)
- str = str:gsub("/%./","/")
+ str = gsub(str,"/%./","/")
local n, m = 1, 1
while n > 0 or m > 0 do
- str, n = str:gsub("[^/%.]+/%.%.$","")
- str, m = str:gsub("[^/%.]+/%.%./","")
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
end
- str = str:gsub("([^/])/$","%1")
- str = str:gsub("^%./","")
- str = str:gsub("/%.$","")
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
if str == "" then str = "." end
return str
end
@@ -145,7 +120,7 @@ end
--~ print(file.collapse_path("a/b/c/../.."))
function file.robustname(str)
- return (str:gsub("[^%a%d%/%-%.\\]+","-"))
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
end
file.readdata = io.loaddata
@@ -175,8 +150,6 @@ end
--~ return pattern:match(name)
--~ end
---~ file.stripsuffix = file.removesuffix
-
--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
--~ function file.basename(name)
@@ -230,7 +203,6 @@ end
--~ end
--~ local test = file.extname
---~ local test = file.stripsuffix
--~ local test = file.basename
--~ local test = file.dirname
--~ local test = file.addsuffix
@@ -246,3 +218,41 @@ end
--~ print(7,test("def.xxx","!!!"))
--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+local slash = lpeg.S("\\/")
+local period = lpeg.P(".")
+local drive = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":")
+local path = lpeg.C(((1-slash)^0 * slash)^0)
+local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1))
+local base = lpeg.C((1-suffix)^0)
+
+local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc(""))
+
+function file.splitname(str) -- returns drive, path, base, suffix
+ return pattern:match(str)
+end
+
+-- function test(t) for k, v in pairs(t) do print(v, "=>", file.splitname(v)) end end
+--
+-- test { "c:", "c:/aa", "c:/aa/bb", "c:/aa/bb/cc", "c:/aa/bb/cc.dd", "c:/aa/bb/cc.dd.ee" }
+-- test { "c:", "c:aa", "c:aa/bb", "c:aa/bb/cc", "c:aa/bb/cc.dd", "c:aa/bb/cc.dd.ee" }
+-- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
+-- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
diff --git a/tex/context/base/l-io.lua b/tex/context/base/l-io.lua
index 6d773c582..4b937a322 100644
--- a/tex/context/base/l-io.lua
+++ b/tex/context/base/l-io.lua
@@ -1,10 +1,12 @@
--- filename : l-io.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-io'] = 1.001
+local byte = string.byte
if string.find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator = "\\", ";"
@@ -12,8 +14,8 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-function io.loaddata(filename)
- local f = io.open(filename,'rb')
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
if f then
local data = f:read('*all')
-- garbagecollector.check(data)
@@ -71,146 +73,83 @@ function io.noflines(f)
return n
end
-do
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
- local sb = string.byte
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
- local nextchar = {
- [ 4] = function(f)
- return f:read(1,1,1,1)
- end,
- [ 2] = function(f)
- return f:read(1,1)
- end,
- [ 1] = function(f)
- return f:read(1)
- end,
- [-2] = function(f)
- local a, b = f:read(1,1)
- return b, a
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- return d, c, b, a
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
end
- }
-
- function io.characters(f,n)
- if f then
- return nextchar[n or 1], f
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
else
return nil, nil
end
- end
-
-end
-
-do
-
- local sb = string.byte
-
---~ local nextbyte = {
---~ [4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(a), sb(b), sb(c), sb(d)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end,
---~ [2] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(a), sb(b)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [1] = function (f)
---~ local a = f:read(1)
---~ if a then
---~ return sb(a)
---~ else
---~ return nil
---~ end
---~ end,
---~ [-2] = function (f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ if b then
---~ return sb(b), sb(a)
---~ else
---~ return nil, nil
---~ end
---~ end,
---~ [-4] = function(f)
---~ local a = f:read(1)
---~ local b = f:read(1)
---~ local c = f:read(1)
---~ local d = f:read(1)
---~ if d then
---~ return sb(d), sb(c), sb(b), sb(a)
---~ else
---~ return nil, nil, nil, nil
---~ end
---~ end
---~ }
-
- local nextbyte = {
- [4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(a), sb(b), sb(c), sb(d)
- else
- return nil, nil, nil, nil
- end
- end,
- [2] = function(f)
- local a, b = f:read(1,1)
- if b then
- return sb(a), sb(b)
- else
- return nil, nil
- end
- end,
- [1] = function (f)
- local a = f:read(1)
- if a then
- return sb(a)
- else
- return nil
- end
- end,
- [-2] = function (f)
- local a, b = f:read(1,1)
- if b then
- return sb(b), sb(a)
- else
- return nil, nil
- end
- end,
- [-4] = function(f)
- local a, b, c, d = f:read(1,1,1,1)
- if d then
- return sb(d), sb(c), sb(b), sb(a)
- else
- return nil, nil, nil, nil
- end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
end
- }
-
- function io.bytes(f,n)
- if f then
- return nextbyte[n or 1], f
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
else
return nil, nil
end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
end
+}
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
end
function io.ask(question,default,options)
diff --git a/tex/context/base/l-lpeg.lua b/tex/context/base/l-lpeg.lua
index cd61dc926..88b445717 100644
--- a/tex/context/base/l-lpeg.lua
+++ b/tex/context/base/l-lpeg.lua
@@ -1,9 +1,12 @@
--- filename : l-lpeg.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-lpeg'] = 1.001
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
--~ l-lpeg.lua :
@@ -27,35 +30,33 @@ if not versions then versions = { } end versions['l-lpeg'] = 1.001
local hash = { }
function lpeg.anywhere(pattern) --slightly adapted from website
- return lpeg.P { lpeg.P(pattern) + 1 * lpeg.V(1) }
+ return P { P(pattern) + 1 * lpeg.V(1) }
end
function lpeg.startswith(pattern) --slightly adapted
- return lpeg.P(pattern)
+ return P(pattern)
end
---~ g = lpeg.splitter(" ",function(s) ... end) -- gmatch:lpeg = 3:2
-
function lpeg.splitter(pattern, action)
- return (((1-lpeg.P(pattern))^1)/action+1)^0
+ return (((1-P(pattern))^1)/action+1)^0
end
-- variant:
--~ local parser = lpeg.Ct(lpeg.splitat(newline))
-local crlf = lpeg.P("\r\n")
-local cr = lpeg.P("\r")
-local lf = lpeg.P("\n")
-local space = lpeg.S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
local newline = crlf + cr + lf
local spacing = space^0 * newline
-local empty = spacing * lpeg.Cc("")
-local nonempty = lpeg.Cs((1-spacing)^1) * spacing^-1
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
local content = (empty + nonempty)^1
-local capture = lpeg.Ct(content^0)
+local capture = Ct(content^0)
function string:splitlines()
return capture:match(self)
@@ -70,19 +71,32 @@ lpeg.linebyline = content -- better make a sublibrary
local splitters_s, splitters_m = { }, { }
-function lpeg.splitat(separator,single)
+local function splitat(separator,single)
local splitter = (single and splitters_s[separator]) or splitters_m[separator]
if not splitter then
- separator = lpeg.P(separator)
+ separator = P(separator)
if single then
- local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
- splitter = other * (separator * lpeg.C(any^0) + "")
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
splitters_s[separator] = splitter
else
- local other = lpeg.C((1 - separator)^0)
+ local other = C((1 - separator)^0)
splitter = other * (separator * other)^0
splitters_m[separator] = splitter
end
end
return splitter
end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
diff --git a/tex/context/base/l-math.lua b/tex/context/base/l-math.lua
index 00b72dba5..bfb3d506b 100644
--- a/tex/context/base/l-math.lua
+++ b/tex/context/base/l-math.lua
@@ -1,12 +1,12 @@
--- filename : l-math.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-math'] = 1.001
-
-local floor = math.floor
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
if not math.round then
function math.round(x)
@@ -25,3 +25,17 @@ if not math.mod then
return n % m
end
end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
diff --git a/tex/context/base/l-md5.lua b/tex/context/base/l-md5.lua
index 4deb9bd74..8640ad54e 100644
--- a/tex/context/base/l-md5.lua
+++ b/tex/context/base/l-md5.lua
@@ -1,18 +1,72 @@
--- filename : l-md5.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-md5'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-md5'] = 1.001
+-- This also provides file checksums and checkers.
-if md5 then do
+local gsub, format, byte = string.gsub, string.format, string.byte
- local function convert(str,fmt)
- return (string.gsub(md5.sum(str),".",function(chr) return string.format(fmt,string.byte(chr)) end))
+local function convert(str,fmt)
+ return (gsub(md5.sum(str),".",function(chr) return format(fmt,byte(chr)) end))
+end
+
+if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
+if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
+if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+
+--~ if not md5.HEX then
+--~ local function remap(chr) return format("%02X",byte(chr)) end
+--~ function md5.HEX(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.hex then
+--~ local function remap(chr) return format("%02x",byte(chr)) end
+--~ function md5.hex(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+--~ if not md5.dec then
+--~ local function remap(chr) return format("%03i",byte(chr)) end
+--~ function md5.dec(str) return (gsub(md5.sum(str),".",remap)) end
+--~ end
+
+file.needs_updating_threshold = 1
+
+function file.needs_updating(oldname,newname) -- size modification access change
+ local oldtime = lfs.attributes(oldname, modification)
+ local newtime = lfs.attributes(newname, modification)
+ if newtime >= oldtime then
+ return false
+ elseif oldtime - newtime < file.needs_updating_threshold then
+ return false
+ else
+ return true
end
+end
- if not md5.HEX then function md5.HEX(str) return convert(str,"%02X") end end
- if not md5.hex then function md5.hex(str) return convert(str,"%02x") end end
- if not md5.dec then function md5.dec(str) return convert(str,"%03i") end end
+function file.checksum(name)
+ if md5 then
+ local data = io.loaddata(name)
+ if data then
+ return md5.HEX(data)
+ end
+ end
+ return nil
+end
+
+function file.loadchecksum(name)
+ if md5 then
+ local data = io.loaddata(name .. ".md5")
+ return data and data:gsub("%s","")
+ end
+ return nil
+end
-end end
+function file.savechecksum(name, checksum)
+ if not checksum then checksum = file.checksum(name) end
+ if checksum then
+ io.savedata(name .. ".md5",checksum)
+ return checksum
+ end
+ return nil
+end
diff --git a/tex/context/base/l-number.lua b/tex/context/base/l-number.lua
index 180b4c544..18d488a1a 100644
--- a/tex/context/base/l-number.lua
+++ b/tex/context/base/l-number.lua
@@ -1,12 +1,14 @@
--- filename : l-number.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-number'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-number'] = 1.001
+local format = string.format
-if not number then number = { } end
+number = number or { }
-- a,b,c,d,e,f = number.toset(100101)
@@ -14,8 +16,6 @@ function number.toset(n)
return (tostring(n)):match("(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
end
-local format = string.format
-
function number.toevenhex(n)
local s = format("%X",n)
if #s % 2 == 0 then
@@ -36,11 +36,10 @@ end
--
-- of course dedicated "(.)(.)(.)(.)" matches are even faster
-do
- local one = lpeg.C(1-lpeg.S(''))^1
+local one = lpeg.C(1-lpeg.S(''))^1
- function number.toset(n)
- return one:match(tostring(n))
- end
+function number.toset(n)
+ return one:match(tostring(n))
end
+
diff --git a/tex/context/base/l-os.lua b/tex/context/base/l-os.lua
index 1dba5262f..47b47fa4f 100644
--- a/tex/context/base/l-os.lua
+++ b/tex/context/base/l-os.lua
@@ -1,13 +1,12 @@
--- filename : l-os.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-os'] = {
+ version = 1.001,
+ comment = "companion to luat-lub.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-
---~ print(table.serialize(os.uname()))
-
-if not versions then versions = { } end versions['l-os'] = 1.001
+local find = string.find
function os.resultof(command)
return io.popen(command,"r"):read("*all")
@@ -20,7 +19,7 @@ if not os.spawn then os.spawn = os.execute end
--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new)
if not io.fileseparator then
- if string.find(os.getenv("PATH"),";") then
+ if find(os.getenv("PATH"),";") then
io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows"
else
io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix"
@@ -58,11 +57,10 @@ end
os.gettimeofday = os.gettimeofday or os.clock
-do
- local startuptime = os.gettimeofday()
- function os.runtime()
- return os.gettimeofday() - startuptime
- end
+local startuptime = os.gettimeofday()
+
+function os.runtime()
+ return os.gettimeofday() - startuptime
end
--~ print(os.gettimeofday()-os.time())
@@ -70,3 +68,63 @@ end
--~ print (">>",os.runtime())
--~ print(os.date("%H:%M:%S",os.gettimeofday()))
--~ print(os.date("%H:%M:%S",os.time()))
+
+os.arch = os.arch or function()
+ local a = os.resultof("uname -m") or "linux"
+ os.arch = function()
+ return a
+ end
+ return a
+end
+
+local platform
+
+function os.currentplatform(name,default)
+ if not platform then
+ local name = os.name or os.platform or name -- os.name is built in, os.platform is mine
+ if not name then
+ platform = default or "linux"
+ elseif name == "windows" or name == "mswin" or name == "win32" or name == "msdos" then
+ if os.getenv("PROCESSOR_ARCHITECTURE") == "AMD64" then
+ platform = "mswin-64"
+ else
+ platform = "mswin"
+ end
+ else
+ local architecture = os.arch()
+ if name == "linux" then
+ if find(architecture,"x86_64") then
+ platform = "linux-64"
+ elseif find(architecture,"ppc") then
+ platform = "linux-ppc"
+ else
+ platform = "linux"
+ end
+ elseif name == "macosx" then
+ if find(architecture,"i386") then
+ platform = "osx-intel"
+ else
+ platform = "osx-ppc"
+ end
+ elseif name == "sunos" then
+ if find(architecture,"sparc") then
+ platform = "solaris-sparc"
+ else -- if architecture == 'i86pc'
+ platform = "solaris-intel"
+ end
+ elseif name == "freebsd" then
+ if find(architecture,"amd64") then
+ platform = "freebsd-amd64"
+ else
+ platform = "freebsd"
+ end
+ else
+ platform = default or name
+ end
+ end
+ function os.currentplatform()
+ return platform
+ end
+ end
+ return platform
+end
diff --git a/tex/context/base/l-set.lua b/tex/context/base/l-set.lua
index 2bcf664f8..199253ee2 100644
--- a/tex/context/base/l-set.lua
+++ b/tex/context/base/l-set.lua
@@ -1,59 +1,56 @@
--- filename : l-set.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-set'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-set'] = 1.001
+set = set or { }
-if not set then set = { } end
+local nums = { }
+local tabs = { }
+local concat = table.concat
-do
+set.create = table.tohash
- local nums = { }
- local tabs = { }
- local concat = table.concat
-
- set.create = table.tohash
-
- function set.tonumber(t)
- if next(t) then
- local s = ""
- -- we could save mem by sorting, but it slows down
- for k, v in pairs(t) do
- if v then
- -- why bother about the leading space
- s = s .. " " .. k
- end
- end
- if not nums[s] then
- tabs[#tabs+1] = t
- nums[s] = #tabs
+function set.tonumber(t)
+ if next(t) then
+ local s = ""
+ -- we could save mem by sorting, but it slows down
+ for k, v in pairs(t) do
+ if v then
+ -- why bother about the leading space
+ s = s .. " " .. k
end
- return nums[s]
- else
- return 0
end
- end
-
- function set.totable(n)
- if n == 0 then
- return { }
- else
- return tabs[n] or { }
+ if not nums[s] then
+ tabs[#tabs+1] = t
+ nums[s] = #tabs
end
+ return nums[s]
+ else
+ return 0
end
+end
- function set.contains(n,s)
- if type(n) == "table" then
- return n[s]
- elseif n == 0 then
- return false
- else
- local t = tabs[n]
- return t and t[s]
- end
+function set.totable(n)
+ if n == 0 then
+ return { }
+ else
+ return tabs[n] or { }
end
+end
+function set.contains(n,s)
+ if type(n) == "table" then
+ return n[s]
+ elseif n == 0 then
+ return false
+ else
+ local t = tabs[n]
+ return t and t[s]
+ end
end
--~ local c = set.create{'aap','noot','mies'}
diff --git a/tex/context/base/l-string.lua b/tex/context/base/l-string.lua
index 90af72c87..ab7d314e4 100644
--- a/tex/context/base/l-string.lua
+++ b/tex/context/base/l-string.lua
@@ -1,137 +1,31 @@
--- filename : l-string.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['l-string'] = 1.001
-
---~ function string.split(str, pat) -- taken from the lua wiki
---~ local t = {n = 0} -- so this table has a length field, traverse with ipairs then!
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = string.find(str, fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ table.insert(t,cap)
---~ end
---~ last_end = e+1
---~ s, e, cap = string.find(str, fpat, last_end)
---~ end
---~ if last_end<=string.len(str) then
---~ table.insert(t,(string.sub(str,last_end)))
---~ end
---~ return t
---~ end
-
---~ function string:split(pat) -- taken from the lua wiki but adapted
---~ local t = { } -- self and colon usage (faster)
---~ local fpat = "(.-)"..pat
---~ local last_end = 1
---~ local s, e, cap = self:find(fpat, 1)
---~ while s ~= nil do
---~ if s~=1 or cap~="" then
---~ t[#t+1] = cap
---~ end
---~ last_end = e+1
---~ s, e, cap = self:find(fpat, last_end)
---~ end
---~ if last_end <= #self then
---~ t[#t+1] = self:sub(last_end)
---~ end
---~ return t
---~ end
-
---~ a piece of brilliant code by Rici Lake (posted on lua list) -- only names changed
---~
---~ function string:splitter(pat)
---~ local st, g = 1, self:gmatch("()"..pat.."()")
---~ local function splitter(self)
---~ if st then
---~ local s, f = g()
---~ local rv = self:sub(st, (s or 0)-1)
---~ st = f
---~ return rv
---~ end
---~ end
---~ return splitter, self
---~ end
-
-function string:splitter(pat)
- -- by Rici Lake (posted on lua list) -- only names changed
- -- p 79 ref man: () returns position of match
- local st, g = 1, self:gmatch("()("..pat..")")
- local function strgetter(self, segs, seps, sep, cap1, ...)
- st = sep and seps + #sep
- return self:sub(segs, (seps or 0) - 1), cap1 or sep, ...
- end
- local function strsplitter(self)
- if st then return strgetter(self, st, g()) end
- end
- return strsplitter, self
-end
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-function string:split(separator)
- local t = {}
- for k in self:splitter(separator) do t[#t+1] = k end
- return t
-end
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
--- faster than a string:split:
+if not string.split then
-function string:splitchr(chr)
- if #self > 0 then
- local t = { }
- for s in (self..chr):gmatch("(.-)"..chr) do
- t[#t+1] = s
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
end
- return t
- else
- return { }
end
-end
-function string.piecewise(str, pat, fnc) -- variant of split
- for k in string.splitter(str,pat) do fnc(k) end
end
---~ function string.piecewise(str, pat, fnc) -- variant of split
---~ for k in str:splitter(pat) do fnc(k) end
---~ end
-
---~ do if lpeg then
-
---~ -- this alternative is 30% faster esp when we cache them
---~ -- problem: no expressions
-
---~ splitters = { }
-
---~ function string:split(separator)
---~ if #self > 0 then
---~ local split = splitters[separator]
---~ if not split then
---~ -- based on code by Roberto
---~ local p = lpeg.P(separator)
---~ local c = lpeg.C((1-p)^0)
---~ split = lpeg.Ct(c*(p*c)^0)
---~ splitters[separator] = split
---~ end
---~ return split:match(self)
---~ else
---~ return { }
---~ end
---~ end
-
---~ string.splitchr = string.split
-
---~ function string:piecewise(separator,fnc)
---~ for _,v in pairs(self:split(separator)) do
---~ fnc(v)
---~ end
---~ end
-
---~ end end
-
local chr_to_esc = {
["%"] = "%%",
["."] = "%.",
@@ -145,20 +39,20 @@ local chr_to_esc = {
string.chr_to_esc = chr_to_esc
function string:esc() -- variant 2
- return (self:gsub("(.)",chr_to_esc))
+ return (gsub(self,"(.)",chr_to_esc))
end
function string:unquote()
- return (self:gsub("^([\"\'])(.*)%1$","%2"))
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
end
-function string:quote()
+function string:quote() -- we could use format("%q")
return '"' .. self:unquote() .. '"'
end
function string:count(pattern) -- variant 3
local n = 0
- for _ in self:gmatch(pattern) do
+ for _ in gmatch(self,pattern) do
n = n + 1
end
return n
@@ -167,29 +61,25 @@ end
function string:limit(n,sentinel)
if #self > n then
sentinel = sentinel or " ..."
- return self:sub(1,(n-#sentinel)) .. sentinel
+ return sub(self,1,(n-#sentinel)) .. sentinel
else
return self
end
end
function string:strip()
- return (self:gsub("^%s*(.-)%s*$", "%1"))
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
end
---~ function string.strip(str) -- slightly different
---~ return (string.gsub(string.gsub(str,"^%s*(.-)%s*$","%1"),"%s+"," "))
---~ end
-
function string:is_empty()
- return not self:find("%S")
+ return not find(find,"%S")
end
function string:enhance(pattern,action)
local ok, n = true, 0
while ok do
ok = false
- self = self:gsub(pattern, function(...)
+ self = gsub(self,pattern, function(...)
ok, n = true, n + 1
return action(...)
end)
@@ -197,59 +87,19 @@ function string:enhance(pattern,action)
return self, n
end
---~ function string:enhance(pattern,action)
---~ local ok, n = 0, 0
---~ repeat
---~ self, ok = self:gsub(pattern, function(...)
---~ n = n + 1
---~ return action(...)
---~ end)
---~ until ok == 0
---~ return self, n
---~ end
-
---~ function string:to_hex()
---~ if self then
---~ return (self:gsub("(.)",function(c)
---~ return string.format("%02X",c:byte())
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
---~ function string:from_hex()
---~ if self then
---~ return (self:gsub("(..)",function(c)
---~ return string.char(tonumber(c,16))
---~ end))
---~ else
---~ return ""
---~ end
---~ end
-
-string.chr_to_hex = { }
-string.hex_to_chr = { }
+local chr_to_hex, hex_to_chr = { }, { }
for i=0,255 do
- local c, h = string.char(i), string.format("%02X",i)
- string.chr_to_hex[c], string.hex_to_chr[h] = h, c
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
end
---~ function string:to_hex()
---~ if self then return (self:gsub("(.)",string.chr_to_hex)) else return "" end
---~ end
-
---~ function string:from_hex()
---~ if self then return (self:gsub("(..)",string.hex_to_chr)) else return "" end
---~ end
-
function string:to_hex()
- return ((self or ""):gsub("(.)",string.chr_to_hex))
+ return (gsub(self or "","(.)",chr_to_hex))
end
function string:from_hex()
- return ((self or ""):gsub("(..)",string.hex_to_chr))
+ return (gsub(self or "","(..)",hex_to_chr))
end
if not string.characters then
@@ -263,7 +113,7 @@ if not string.characters then
end
local function nextbyte(str, index)
index = index + 1
- return (index <= #str) and index or nil, string.byte(str:sub(index,index))
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
end
function string:bytes()
return nextbyte, self, 0
@@ -271,9 +121,7 @@ if not string.characters then
end
---~ function string:padd(n,chr)
---~ return self .. self.rep(chr or " ",n-#self)
---~ end
+-- we can use format for this (neg n)
function string:rpadd(n,chr)
local m = n-#self
@@ -295,8 +143,8 @@ end
string.padd = string.rpadd
-function is_number(str)
- return str:find("^[%-%+]?[%d]-%.?[%d+]$") == 1
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
end
--~ print(is_number("1"))
@@ -308,9 +156,9 @@ end
--~ print(is_number("+.1"))
function string:split_settings() -- no {} handling, see l-aux for lpeg variant
- if self:find("=") then
+ if find(self,"=") then
local t = { }
- for k,v in self:gmatch("(%a+)=([^%,]*)") do
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
t[k] = v
end
return t
@@ -332,13 +180,49 @@ local patterns_escapes = {
}
function string:pattesc()
- return (self:gsub(".",patterns_escapes))
+ return (gsub(self,".",patterns_escapes))
end
function string:tohash()
local t = { }
- for s in self:gmatch("([^, ]+)") do -- lpeg
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
t[s] = true
end
return t
end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
diff --git a/tex/context/base/l-table.lua b/tex/context/base/l-table.lua
index 23d4bed63..bfe33ff85 100644
--- a/tex/context/base/l-table.lua
+++ b/tex/context/base/l-table.lua
@@ -1,22 +1,22 @@
--- filename : l-table.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['l-table'] = 1.001
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
table.join = table.concat
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
-local format = string.format
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
local getmetatable, setmetatable = getmetatable, setmetatable
-local pairs, ipairs, type, next, tostring = pairs, ipairs, type, next, tostring
+local type, next, tostring, ipairs = type, next, tostring, ipairs
function table.strip(tab)
local lst = { }
for i=1,#tab do
- local s = tab[i]:gsub("^%s*(.-)%s*$","%1")
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
if s == "" then
-- skip this one
else
@@ -28,7 +28,7 @@ end
local function sortedkeys(tab)
local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
if kind == 3 then
-- no further check
@@ -55,7 +55,7 @@ end
local function sortedhashkeys(tab) -- fast one
local srt = { }
- for key,_ in pairs(tab) do
+ for key,_ in next, tab do
srt[#srt+1] = key
end
sort(srt)
@@ -65,14 +65,25 @@ end
table.sortedkeys = sortedkeys
table.sortedhashkeys = sortedhashkeys
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
function table.append(t, list)
- for _,v in pairs(list) do
+ for _,v in next, list do
insert(t,v)
end
end
function table.prepend(t, list)
- for k,v in pairs(list) do
+ for k,v in next, list do
insert(t,k,v)
end
end
@@ -81,7 +92,7 @@ function table.merge(t, ...) -- first one is target
t = t or {}
local lst = {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
t[k] = v
end
end
@@ -91,7 +102,7 @@ end
function table.merged(...)
local tmp, lst = { }, {...}
for i=1,#lst do
- for k, v in pairs(lst[i]) do
+ for k, v in next, lst[i] do
tmp[k] = v
end
end
@@ -123,13 +134,14 @@ end
local function fastcopy(old) -- fast one
if old then
local new = { }
- for k,v in pairs(old) do
+ for k,v in next, old do
if type(v) == "table" then
new[k] = fastcopy(v) -- was just table.copy
else
new[k] = v
end
end
+ -- optional second arg
local mt = getmetatable(old)
if mt then
setmetatable(new,mt)
@@ -146,7 +158,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
if not tables[t] then
tables[t] = tcopy
end
- for i,v in pairs(t) do -- brrr, what happens with sparse indexed
+ for i,v in next, t do -- brrr, what happens with sparse indexed
if type(i) == "table" then
if tables[i] then
i = tables[i]
@@ -179,7 +191,7 @@ function table.sub(t,i,j)
end
function table.replace(a,b)
- for k,v in pairs(b) do
+ for k,v in next, b do
a[k] = v
end
end
@@ -201,16 +213,18 @@ end
function table.tohash(t,value)
local h = { }
- if value == nil then value = true end
- for _, v in pairs(t) do -- no ipairs here
- h[v] = value
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
end
return h
end
function table.fromhash(t)
local h = { }
- for k, v in pairs(t) do -- no ipairs here
+ for k, v in next, t do -- no ipairs here
if v then h[#h+1] = k end
end
return h
@@ -234,24 +248,10 @@ local reserved = table.tohash { -- intercept a language flaw, no reserved words
'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
}
-local function key(k)
- if type(k) == "number" then -- or k:find("^%d+$") then
- if hexify then
- return ("[0x%04X]"):format(k)
- else
- return "["..k.."]"
- end
- elseif noquotes and not reserved[k] and k:find("^%a[%a%d%_]*$") then
- return k
- else
- return '["'..k..'"]'
- end
-end
-
local function simple_table(t)
if #t > 0 then
local n = 0
- for _,v in pairs(t) do
+ for _,v in next, t do
n = n + 1
end
if n == #t then
@@ -261,14 +261,14 @@ local function simple_table(t)
local tv = type(v)
if tv == "number" then
if hexify then
- tt[#tt+1] = ("0x%04X"):format(v)
+ tt[#tt+1] = format("0x%04X",v)
else
- tt[#tt+1] = tostring(v)
+ tt[#tt+1] = tostring(v) -- tostring not needed
end
elseif tv == "boolean" then
tt[#tt+1] = tostring(v)
elseif tv == "string" then
- tt[#tt+1] = ("%q"):format(v)
+ tt[#tt+1] = format("%q",v)
else
tt = nil
break
@@ -280,21 +280,40 @@ local function simple_table(t)
return nil
end
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
local function do_serialize(root,name,depth,level,indexed)
if level > 0 then
depth = depth .. " "
if indexed then
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
elseif name then
- handle(("%s%s={"):format(depth,key(name)))
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
else
- handle(("%s{"):format(depth))
+ handle(format("%s{",depth))
end
end
if root and next(root) then
local first, last = nil, 0 -- #root cannot be trusted here
if compact then
- for k,v in ipairs(root) do -- NOT: for k=1,#root do (we need to quit at nil)
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
if not first then first = k end
last = last + 1
end
@@ -303,30 +322,30 @@ local function do_serialize(root,name,depth,level,indexed)
for i=1,#sk do
local k = sk[i]
local v = root[k]
---~ if v == root then
- -- circular
---~ else
+ --~ if v == root then
+ -- circular
+ --~ else
local t = type(v)
if compact and first and type(k) == "number" and k >= first and k <= last then
if t == "number" then
if hexify then
- handle(("%s 0x%04X,"):format(depth,v))
+ handle(format("%s 0x%04X,",depth,v))
else
- handle(("%s %s,"):format(depth,v))
+ handle(format("%s %s,",depth,v))
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s,"):format(depth,v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
else
- handle(("%s %q,"):format(depth,v))
+ handle(format("%s %q,",depth,v))
end
elseif t == "table" then
if not next(v) then
- handle(("%s {},"):format(depth))
- elseif inline then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
local st = simple_table(v)
if st then
- handle(("%s { %s },"):format(depth,concat(st,", ")))
+ handle(format("%s { %s },",depth,concat(st,", ")))
else
do_serialize(v,k,depth,level+1,true)
end
@@ -334,39 +353,102 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1,true)
end
elseif t == "boolean" then
- handle(("%s %s,"):format(depth,tostring(v)))
+ handle(format("%s %s,",depth,tostring(v)))
elseif t == "function" then
if functions then
- handle(('%s loadstring(%q),'):format(depth,v:dump()))
+ handle(format('%s loadstring(%q),',depth,dump(v)))
else
- handle(('%s "function",'):format(depth))
+ handle(format('%s "function",',depth))
end
else
- handle(("%s %q,"):format(depth,tostring(v)))
+ handle(format("%s %q,",depth,tostring(v)))
end
elseif k == "__p__" then -- parent
if false then
- handle(("%s __p__=nil,"):format(depth))
+ handle(format("%s __p__=nil,",depth))
end
elseif t == "number" then
- if hexify then
- handle(("%s %s=0x%04X,"):format(depth,key(k),v))
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
end
elseif t == "string" then
- if reduce and (v:find("^[%-%+]?[%d]-%.?[%d+]$") == 1) then
- handle(("%s %s=%s,"):format(depth,key(k),v))
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
else
- handle(("%s %s=%q,"):format(depth,key(k),v))
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
end
elseif t == "table" then
if not next(v) then
- handle(("%s %s={},"):format(depth,key(k)))
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
elseif inline then
local st = simple_table(v)
if st then
- handle(("%s %s={ %s },"):format(depth,key(k),concat(st,", ")))
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
else
do_serialize(v,k,depth,level+1)
end
@@ -374,25 +456,58 @@ local function do_serialize(root,name,depth,level,indexed)
do_serialize(v,k,depth,level+1)
end
elseif t == "boolean" then
- handle(("%s %s=%s,"):format(depth,key(k),tostring(v)))
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
elseif t == "function" then
if functions then
- handle(('%s %s=loadstring(%q),'):format(depth,key(k),v:dump()))
- else
- handle(('%s %s="function",'):format(depth,key(k)))
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
end
else
- handle(("%s %s=%q,"):format(depth,key(k),tostring(v)))
- -- handle(('%s %s=loadstring(%q),'):format(depth,key(k),string.dump(function() return v end)))
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
end
---~ end
+ --~ end
end
end
if level > 0 then
- handle(("%s},"):format(depth))
+ handle(format("%s},",depth))
end
end
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
noquotes = _noquotes
hexify = _hexify
@@ -410,7 +525,7 @@ local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
end
elseif tname == "number" then
if hexify then
- handle(("[0x%04X]={"):format(name))
+ handle(format("[0x%04X]={",name))
else
handle("[" .. name .. "]={")
end
@@ -561,14 +676,18 @@ function table.insert_after_value(t,value,str)
end
end
-function table.are_equal(a,b,n,m)
+local function are_equal(a,b,n,m) -- indexed
if #a == #b then
n = n or 1
m = m or #a
for i=n,m do
local ai, bi = a[i], b[i]
- if (ai==bi) or (type(ai)=="table" and type(bi)=="table" and table.are_equal(ai,bi)) then
- -- continue
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
else
return false
end
@@ -579,9 +698,30 @@ function table.are_equal(a,b,n,m)
end
end
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
function table.compact(t)
if t then
- for k,v in pairs(t) do
+ for k,v in next, t do
if not next(v) then
t[k] = nil
end
@@ -610,7 +750,7 @@ end
function table.swapped(t)
local s = { }
- for k, v in pairs(t) do
+ for k, v in next, t do
s[v] = k
end
return s
@@ -632,14 +772,14 @@ end
function table.hexed(t,seperator)
local tt = { }
- for i=1,#t do tt[i] = ("0x%04X"):format(t[i]) end
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
return concat(tt,seperator or " ")
end
function table.reverse_hash(h)
local r = { }
- for k,v in pairs(h) do
- r[v] = (k:gsub(" ","")):lower()
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
end
return r
end
@@ -653,3 +793,19 @@ function table.reverse(t)
end
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
diff --git a/tex/context/base/l-unicode.lua b/tex/context/base/l-unicode.lua
index ebd67db1c..124a1e240 100644
--- a/tex/context/base/l-unicode.lua
+++ b/tex/context/base/l-unicode.lua
@@ -1,14 +1,17 @@
--- filename : l-unicode.lua
--- comment : split off from luat-inp
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-unicode'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+utf = utf or unicode.utf8
-if not versions then versions = { } end versions['l-unicode'] = 1.001
-if not unicode then unicode = { } end
+local concat, utfchar, utfgsub = table.concat, utf.char, utf.gsub
+local char, byte, find, bytepairs = string.char, string.byte, string.find, string.bytepairs
-local concat, utfchar, utfgsub = table.concat, unicode.utf8.char, unicode.utf8.gsub
-local char, byte = string.char, string.byte
+unicode = unicode or { }
-- 0 EF BB BF UTF-8
-- 1 FF FE UTF-16-little-endian
@@ -29,17 +32,17 @@ function unicode.utftype(f) -- \000 fails !
if not str then
f:seek('set')
return 0
- elseif str:find("^%z%z\254\255") then
+ elseif find(str,"^%z%z\254\255") then
return 4
- elseif str:find("^\255\254%z%z") then
+ elseif find(str,"^\255\254%z%z") then
return 3
- elseif str:find("^\254\255") then
+ elseif find(str,"^\254\255") then
f:seek('set',2)
return 2
- elseif str:find("^\255\254") then
+ elseif find(str,"^\255\254") then
f:seek('set',2)
return 1
- elseif str:find("^\239\187\191") then
+ elseif find(str,"^\239\187\191") then
f:seek('set',3)
return 0
else
@@ -67,7 +70,7 @@ function unicode.utf16_to_utf8(str, endian) -- maybe a gsub is faster or an lpeg
p = 0
end
end
- for l,r in str:bytepairs() do
+ for l,r in bytepairs(str) do
if r then
if endian then
n = l*256 + r
@@ -111,7 +114,7 @@ function unicode.utf32_to_utf8(str, endian)
p = 0
end
end
- for a,b in str:bytepairs() do
+ for a,b in bytepairs(str) do
if a and b then
if m < 0 then
if endian then
@@ -138,28 +141,32 @@ function unicode.utf32_to_utf8(str, endian)
return result
end
+local function little(c)
+ local b = byte(c) -- b = c:byte()
+ if b < 0x10000 then
+ return char(b%256,b/256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1%256,b1/256,b2%256,b2/256)
+ end
+end
+
+local function big(c)
+ local b = byte(c)
+ if b < 0x10000 then
+ return char(b/256,b%256)
+ else
+ b = b - 0x10000
+ local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
+ return char(b1/256,b1%256,b2/256,b2%256)
+ end
+end
+
function unicode.utf8_to_utf16(str,littleendian)
if littleendian then
- return char(255,254) .. utfgsub(str,".",function(c)
- local b = byte(c) -- b = c:byte()
- if b < 0x10000 then
- return char(b%256,b/256)
- else
- b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1%256,b1/256,b2%256,b2/256)
- end
- end)
+ return char(255,254) .. utfgsub(str,".",little)
else
- return char(254,255) .. utfgsub(str,".",function(c)
- local b = byte(c)
- if b < 0x10000 then
- return char(b/256,b%256)
- else
- b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1/256,b1%256,b2/256,b2%256)
- end
- end)
+ return char(254,255) .. utfgsub(str,".",big)
end
end
diff --git a/tex/context/base/l-url.lua b/tex/context/base/l-url.lua
index 3bb2b1f11..097c94467 100644
--- a/tex/context/base/l-url.lua
+++ b/tex/context/base/l-url.lua
@@ -1,10 +1,13 @@
--- filename : l-url.lua
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-url'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-url'] = 1.001
-if not url then url = { } end
+local char, gmatch = string.char, string.gmatch
+local tonumber, type = tonumber, type
-- from the spec (on the web):
--
@@ -16,29 +19,28 @@ if not url then url = { } end
-- / \ / \
-- urn:example:animal:ferret:nose
-do
+url = url or { }
- local function tochar(s)
- return string.char(tonumber(s,16))
- end
+local function tochar(s)
+ return char(tonumber(s,16))
+end
- local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
+local colon, qmark, hash, slash, percent, endofstring = lpeg.P(":"), lpeg.P("?"), lpeg.P("#"), lpeg.P("/"), lpeg.P("%"), lpeg.P(-1)
- local hexdigit = lpeg.R("09","AF","af")
- local escaped = percent * lpeg.C(hexdigit * hexdigit) / tochar
+local hexdigit = lpeg.R("09","AF","af")
+local plus = lpeg.P("+")
+local escaped = (plus / " ") + (percent * lpeg.C(hexdigit * hexdigit) / tochar)
- local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
- local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
- local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
- local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
- local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
+local scheme = lpeg.Cs((escaped+(1-colon-slash-qmark-hash))^0) * colon + lpeg.Cc("")
+local authority = slash * slash * lpeg.Cs((escaped+(1- slash-qmark-hash))^0) + lpeg.Cc("")
+local path = slash * lpeg.Cs((escaped+(1- qmark-hash))^0) + lpeg.Cc("")
+local query = qmark * lpeg.Cs((escaped+(1- hash))^0) + lpeg.Cc("")
+local fragment = hash * lpeg.Cs((escaped+(1- endofstring))^0) + lpeg.Cc("")
- local parser = lpeg.Ct(scheme * authority * path * query * fragment)
-
- function url.split(str)
- return (type(str) == "string" and parser:match(str)) or str
- end
+local parser = lpeg.Ct(scheme * authority * path * query * fragment)
+function url.split(str)
+ return (type(str) == "string" and parser:match(str)) or str
end
function url.hashed(str)
@@ -61,7 +63,7 @@ end
function url.query(str)
if type(str) == "string" then
local t = { }
- for k, v in str:gmatch("([^&=]*)=([^&=]*)") do
+ for k, v in gmatch(str,"([^&=]*)=([^&=]*)") do
t[k] = v
end
return t
@@ -76,12 +78,12 @@ end
--~ print(url.filename("file:///etc/test.txt"))
--~ print(url.filename("/oeps.txt"))
--- from the spec on the web (sort of):
+--~ from the spec on the web (sort of):
--~
--~ function test(str)
--~ print(table.serialize(url.hashed(str)))
--~ end
----~
+--~
--~ test("%56pass%20words")
--~ test("file:///c:/oeps.txt")
--~ test("file:///c|/oeps.txt")
diff --git a/tex/context/base/l-utils.lua b/tex/context/base/l-utils.lua
index fa8e31ba8..8d531711f 100644
--- a/tex/context/base/l-utils.lua
+++ b/tex/context/base/l-utils.lua
@@ -1,10 +1,12 @@
--- filename : l-utils.lua
--- comment : split off from luat-lib
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['l-utils'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['l-utils'] = 1.001
+-- hm, quite unreadable
if not utils then utils = { } end
if not utils.merger then utils.merger = { } end
@@ -69,24 +71,52 @@ function utils.merger._self_swap_(data,code)
end
end
+--~ stripper:
+--~
+--~ data = string.gsub(data,"%-%-~[^\n]*\n","")
+--~ data = string.gsub(data,"\n\n+","\n")
+
function utils.merger._self_libs_(libs,list)
- local result, f = { }, nil
+ local result, f, frozen = { }, nil, false
+ result[#result+1] = "\n"
if type(libs) == 'string' then libs = { libs } end
if type(list) == 'string' then list = { list } end
+ local foundpath = nil
for _, lib in ipairs(libs) do
for _, pth in ipairs(list) do
- local name = string.gsub(pth .. "/" .. lib,"\\","/")
- f = io.open(name)
- if f then
- utils.report("merging library %s",name)
- result[#result+1] = f:read("*all")
- f:close()
- list = { pth } -- speed up the search
- break
+ pth = string.gsub(pth,"\\","/") -- file.clean_path
+ utils.report("checking library path %s",pth)
+ local name = pth .. "/" .. lib
+ if lfs.isfile(name) then
+ foundpath = pth
+ end
+ end
+ if foundpath then break end
+ end
+ if foundpath then
+ utils.report("using library path %s",foundpath)
+ local right, wrong = { }, { }
+ for _, lib in ipairs(libs) do
+ local fullname = foundpath .. "/" .. lib
+ if lfs.isfile(fullname) then
+ -- right[#right+1] = lib
+ utils.report("merging library %s",fullname)
+ result[#result+1] = "do -- create closure to overcome 200 locals limit"
+ result[#result+1] = io.loaddata(fullname,true)
+ result[#result+1] = "end -- of closure"
else
- utils.report("no library %s",name)
+ -- wrong[#wrong+1] = lib
+ utils.report("no library %s",fullname)
end
end
+ if #right > 0 then
+ utils.report("merged libraries: %s",table.concat(right," "))
+ end
+ if #wrong > 0 then
+ utils.report("skipped libraries: %s",table.concat(wrong," "))
+ end
+ else
+ utils.report("no valid library path found")
end
return table.concat(result, "\n\n")
end
diff --git a/tex/context/base/l-xml.lua b/tex/context/base/l-xml.lua
index cdb9dacc5..d6c48fe7b 100644
--- a/tex/context/base/l-xml.lua
+++ b/tex/context/base/l-xml.lua
@@ -10,6 +10,7 @@ if not modules then modules = { } end modules ['l-xml'] = {
-- 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
--[[ldx--
<p>The parser used here is inspired by the variant discussed in the lua book, but
@@ -38,15 +39,30 @@ optimize the code.</p>
xml = xml or { }
tex = tex or { }
-xml.trace_lpath = false
-xml.trace_print = false
-xml.trace_remap = false
+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 = string.format, string.lower, string.gmatch, string.gsub, string.find
-local format, concat, remove, insert, type, next = string.format, table.concat, table.remove, table.insert, type, next
+--[[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 pairs, next, type = pairs, next, type
+local trace_lpath, trace_remap = false, false
--- todo: some things per xml file, like namespace remapping
+if trackers then
+ trackers.register("xml.lpath", function(v) trace_lpath = v end)
+ trackers.register("xml.remap", function(v) trace_remap = v end)
+end
+
+function xml.settrace(str,value)
+ if str == "lpath" then
+ trace_lpath = value or false
+ elseif str == "remap" then
+ trace_remap = value or false
+ end
+end
--[[ldx--
<p>First a hack to enable namespace resolving. A namespace is characterized by
@@ -73,7 +89,7 @@ do
--ldx]]--
function xml.registerns(namespace, pattern) -- pattern can be an lpeg
- check = check + lpeg.C(lpeg.P(pattern:lower())) / namespace
+ check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
end
@@ -88,7 +104,7 @@ do
--ldx]]--
function xml.checkns(namespace,url)
- local ns = parse:match(url:lower())
+ local ns = parse:match(lower(url))
if ns and namespace ~= ns then
xml.xmlns[namespace] = ns
end
@@ -106,7 +122,7 @@ do
--ldx]]--
function xml.resolvens(url)
- return parse:match(url:lower()) or ""
+ return parse:match(lower(url)) or ""
end
--[[ldx--
@@ -173,6 +189,9 @@ do
end
local function add_attribute(namespace,tag,value)
+ if cleanup and #value > 0 then
+ value = cleanup(value) -- new
+ end
if tag == "xmlns" then
xmlns[#xmlns+1] = resolvens(value)
at[tag] = value
@@ -245,7 +264,7 @@ dt[0] = top
end
end
local function set_message(txt)
- errorstr = "garbage at the end of the file: " .. txt:gsub("([ \n\r\t]*)","")
+ 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
@@ -293,7 +312,7 @@ dt[0] = top
local somecomment = C((1 - endcomment )^0)
local somecdata = C((1 - endcdata )^0)
- function entity(k,v) entities[k] = v end
+ local function entity(k,v) entities[k] = v end
local begindoctype = open * P("!DOCTYPE")
local enddoctype = close
@@ -389,7 +408,7 @@ dt[0] = top
return root and not root.error
end
- xml.error_handler = (logs and logs.report) or (input and input.report) or print
+ xml.error_handler = (logs and logs.report) or (input and logs.report) or print
end
@@ -535,16 +554,16 @@ do
local ats = eat and next(eat) and { } -- type test maybe faster
if ats then
if attributeconverter then
- for k,v in pairs(eat) do
+ for k,v in next, eat do
ats[#ats+1] = format('%s=%q',k,attributeconverter(v))
end
else
- for k,v in pairs(eat) do
+ for k,v in next, eat do
ats[#ats+1] = format('%s=%q',k,v)
end
end
end
- if ern and xml.trace_remap and ern ~= ens then
+ if ern and trace_remap and ern ~= ens then
ens = ern
end
if ens ~= "" then
@@ -640,7 +659,8 @@ do
function xml.checkbom(root) -- can be made faster
if root.ri then
local dt, found = root.dt, false
- for k,v in ipairs(dt) do
+ for k=1,#dt do
+ local v = dt[k]
if type(v) == "table" and v.special and v.tg == "@pi" and v.dt:find("xml.*version=") then
found = true
break
@@ -913,8 +933,6 @@ do
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 = C(P(true)) * C(valid^1)
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
@@ -1051,7 +1069,7 @@ do
if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
insert(map, 1, { 16 })
end
- -- print((table.serialize(map)):gsub("[ \n]+"," "))
+ -- print(gsub(table.serialize(map),"[ \n]+"," "))
return map
end
end
@@ -1068,7 +1086,7 @@ do
cache[pattern] = result
lpathcached = lpathcached + 1
end
- if trace or xml.trace_lpath then
+ if trace or trace_lpath then
xml.lshow(result)
end
return result
@@ -1077,14 +1095,17 @@ do
end
end
- function lpath_cached_patterns()
+ function xml.cached_patterns()
return cache
end
- local fallbackreport = (texio and texio.write) or io.write
+-- 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 fallbackreport
+ report = report or (texio and texio.write) or io.write
local lp = xml.lpath(pattern)
if lp == false then
report(" -: root\n")
@@ -1116,7 +1137,8 @@ do
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 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
@@ -1636,7 +1658,7 @@ do
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 ekat[arguments:gsub("^([\"\'])(.*)%1$","%2")])) or ""
+ return (ekat and (ekat[arguments] or ekat[gsub(arguments,"^([\"\'])(.*)%1$","%2")])) or ""
end
function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
local dtk, rt, dt, dk = xml.filters.index(root,pattern,arguments)
@@ -1698,9 +1720,6 @@ do
function xml.filter(root,pattern)
local kind, a, b, c = parser:match(pattern)
---~ if xml.trace_lpath then
---~ print(pattern,kind,a,b,c)
---~ end
if kind == 1 or kind == 3 then
return (filters[b] or default_filter)(root,a,c)
elseif kind == 2 then
@@ -2013,7 +2032,7 @@ do
end
if not name then
if ek.at then
- for a in (attribute or "href"):gmatch("([^|]+)") do
+ for a in gmatch(attribute or "href","([^|]+)") do
name = ek.at[a]
if name then break end
end
@@ -2052,7 +2071,7 @@ do
-- stripped
else
if nolines then
- str = str:gsub("[ \n\r\t]+"," ")
+ str = gsub(str,"[ \n\r\t]+"," ")
end
if str == "" then
-- stripped
@@ -2069,9 +2088,8 @@ do
end)
end
- function xml.rename_space(root, oldspace, newspace) -- fast variant
+ local function rename_space(root, oldspace, newspace) -- fast variant
local ndt = #root.dt
- local rename = xml.rename_space
for i=1,ndt or 0 do
local e = root[i]
if type(e) == "table" then
@@ -2083,12 +2101,14 @@ do
end
local edt = e.dt
if edt then
- rename(edt, oldspace, newspace)
+ 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
@@ -2167,10 +2187,12 @@ put them here instead of loading mode modules there then needed.</p>
--ldx]]--
function xml.gsub(t,old,new)
- if t.dt then
- for k,v in ipairs(t.dt) do
+ local dt = t.dt
+ if dt then
+ for k=1,#dt do
+ local v = dt[k]
if type(v) == "string" then
- t.dt[k] = v:gsub(old,new)
+ dt[k] = gsub(v,old,new)
else
xml.gsub(v,old,new)
end
@@ -2195,9 +2217,9 @@ end
--~ xml.escapes = { ['&'] = '&amp;', ['<'] = '&lt;', ['>'] = '&gt;', ['"'] = '&quot;' }
--~ xml.unescapes = { } for k,v in pairs(xml.escapes) do xml.unescapes[v] = k end
---~ function xml.escaped (str) return str:gsub("(.)" , xml.escapes ) end
---~ function xml.unescaped(str) return str:gsub("(&.-;)", xml.unescapes) end
---~ function xml.cleansed (str) return str:gsub("<.->" , '' ) end -- "%b<>"
+--~ function xml.escaped (str) return (gsub(str,"(.)" , xml.escapes )) end
+--~ function xml.unescaped(str) return (gsub(str,"(&.-;)", xml.unescapes)) end
+--~ function xml.cleansed (str) return (gsub(str,"<.->" , '' )) end -- "%b<>"
do
@@ -2229,6 +2251,10 @@ do
local cleansed = Cs(((P("<") * (1-P(">"))^0 * P(">"))/"" + 1)^0)
+ xml.escaped_pattern = escaped
+ xml.unescaped_pattern = unescaped
+ 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
@@ -2273,14 +2299,14 @@ do if unicode and unicode.utf8 then
return char(tonumber(s,16))
end
- function utfize(root)
+ 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 dk:find("&#x.-;") then
- d[k] = dk:gsub("&#x(.-);",toutf)
+ if find(dk,"&#x.-;") then
+ d[k] = gsub(dk,"&#x(.-);",toutf)
end
else
utfize(dk)
@@ -2291,8 +2317,10 @@ do if unicode and unicode.utf8 then
xml.utfize = utfize
local function resolve(e) -- hex encoded always first, just to avoid mkii fallbacks
- if e:find("#x") then
+ if find(e,"^#x") then
return char(tonumber(e:sub(3),16))
+ elseif find(e,"^#") then
+ return char(tonumber(e:sub(2)))
else
local ee = xml.entities[e] -- we cannot shortcut this one (is reloaded)
if ee then
@@ -2310,8 +2338,8 @@ do if unicode and unicode.utf8 then
for k=1,#d do
local dk = d[k]
if type(dk) == "string" then
- if dk:find("&.-;") then
- d[k] = dk:gsub("&(.-);",resolve)
+ if find(dk,"&.-;") then
+ d[k] = gsub(dk,"&(.-);",resolve)
end
else
resolve_entities(dk)
@@ -2323,24 +2351,24 @@ do if unicode and unicode.utf8 then
xml.resolve_entities = resolve_entities
function xml.utfize_text(str)
- if str:find("&#") then
- return (str:gsub("&#x(.-);",toutf))
+ 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 str:find("&") then
- return (str:gsub("&(.-);",resolve))
+ if find(str,"&") then
+ return (gsub(str,"&(.-);",resolve))
else
return str
end
end
function xml.show_text_entities(str)
- if str:find("&") then
- return (str:gsub("&(.-);","[%1]"))
+ if find(str,"&") then
+ return (gsub(str,"&(.-);","[%1]"))
else
return str
end
@@ -2352,7 +2380,7 @@ do if unicode and unicode.utf8 then
local documententities = root.entities
local allentities = xml.entities
if documententities then
- for k, v in pairs(documententities) do
+ for k, v in next, documententities do
allentities[k] = v
end
end
@@ -2386,7 +2414,7 @@ end
--~ </a>
--~ ]])
---~ xml.trace_lpath = true
+--~ 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')]"))
diff --git a/tex/context/base/lang-alt.tex b/tex/context/base/lang-alt.tex
index d59df78bd..e45748ead 100644
--- a/tex/context/base/lang-alt.tex
+++ b/tex/context/base/lang-alt.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Altaic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Altaic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -37,8 +37,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!year,\ ,\v!month,\ ,\v!day},
- \c!state=\v!stop]
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day}]
\installlanguage [turkish] [\s!tr]
diff --git a/tex/context/base/lang-ana.tex b/tex/context/base/lang-ana.tex
index 336be50f2..c108655c4 100644
--- a/tex/context/base/lang-ana.tex
+++ b/tex/context/base/lang-ana.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Anatolian Languages}
+\writestatus{loading}{ConTeXt Language Macros / Anatolian Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -21,6 +21,4 @@
\unprotect
-\protect
-
-\endinput
+\protect \endinput
diff --git a/tex/context/base/lang-ara.tex b/tex/context/base/lang-ara.tex
index 91bd6ae38..3c4d3c522 100644
--- a/tex/context/base/lang-ara.tex
+++ b/tex/context/base/lang-ara.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Arabic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Arabic Languages}
\unprotect
@@ -29,8 +29,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,{،\ },\v!year},
- \c!state=\v!stop] % elders always preloaded!
+ \c!date={\v!day,\ ,\v!month,{،\ },\v!year}]
\installlanguage [\s!arabic] [\s!ar]
diff --git a/tex/context/base/lang-art.tex b/tex/context/base/lang-art.tex
index 3f857e11e..e8be91630 100644
--- a/tex/context/base/lang-art.tex
+++ b/tex/context/base/lang-art.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Artificial Languages}
+\writestatus{loading}{ConTeXt Language Macros / Artificial Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -23,6 +23,4 @@
\unprotect
-\protect
-
-\endinput
+\protect \endinput
diff --git a/tex/context/base/lang-bal.tex b/tex/context/base/lang-bal.tex
index c4e0f31f7..9b0528a27 100644
--- a/tex/context/base/lang-bal.tex
+++ b/tex/context/base/lang-bal.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Baltic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Baltic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -23,6 +23,4 @@
\unprotect
-\protect
-
-\endinput
+\protect \endinput
diff --git a/tex/context/base/lang-cel.tex b/tex/context/base/lang-cel.tex
index abbeb10c6..4d93957f1 100644
--- a/tex/context/base/lang-cel.tex
+++ b/tex/context/base/lang-cel.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Celtic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Celtic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -23,6 +23,4 @@
\unprotect
-\protect
-
-\endinput
+\protect \endinput
diff --git a/tex/context/base/lang-chi.tex b/tex/context/base/lang-chi.tex
index 7458268f7..278e10745 100644
--- a/tex/context/base/lang-chi.tex
+++ b/tex/context/base/lang-chi.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Language Macros / Chinese}
+\writestatus{loading}{ConTeXt Language Macros / Chinese}
%D This module is coded using the \UNICODE\ support built in
%D \CONTEXT. Therefore, \type {\uchar} is used instead of latin
@@ -31,9 +31,7 @@
\c!rightquote=\cnencoding\cnupperrightsinglequote,
\c!leftquotation=\cnencoding\cnupperleftdoublequote,
\c!rightquotation=\cnencoding\cnupperrightdoublequote,
- \c!date={\v!year,\cnyear,\ ,\v!month,\v!day,\cnday},
- \c!state=\v!stop]
-
+ \c!date={\v!year,\cnyear,\ ,\v!month,\v!day,\cnday}]
\setupheadtext [\s!cn] [\v!content={\cnencoding\cnencodedcontents}]
\setupheadtext [\s!cn] [\v!tables={\cnencoding\cnencodedtables}]
diff --git a/tex/context/base/lang-cjk.tex b/tex/context/base/lang-cjk.tex
new file mode 100644
index 000000000..138f6d263
--- /dev/null
+++ b/tex/context/base/lang-cjk.tex
@@ -0,0 +1,328 @@
+%D \module
+%D [ file=lang-chi,
+%D version=2009.03.02,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Chinese,
+%D author={Hans Hagen \& Wang Lei},
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Derived from \MKII\ files.
+
+\writestatus{loading}{ConTeXt Language Macros / CJK}
+
+\definesystemconstant {chinese} \definesystemconstant {cn}
+\definesystemconstant {japanese} \definesystemconstant {ja}
+\definesystemconstant {korean} \definesystemconstant {kr}
+
+\unprotect
+
+% Chinese
+
+\installlanguage
+ [\s!cn]
+ [\c!leftsentence=——,
+ \c!rightsentence=——,
+ \c!leftsubsentence=——,
+ \c!rightsubsentence=——,
+ \c!leftquote=‘,
+ \c!rightquote=’,
+ \c!leftquotation=“,
+ \c!rightquotation=”,
+ \c!date={\v!year,年,\ ,\v!month,\v!day,日}]
+
+\setupheadtext [\s!cn] [\v!content=目录]
+\setupheadtext [\s!cn] [\v!tables=表格]
+\setupheadtext [\s!cn] [\v!figures=图形]
+\setupheadtext [\s!cn] [\v!graphics=图]
+\setupheadtext [\s!cn] [\v!intermezzi=퉣]
+\setupheadtext [\s!cn] [\v!index=索引]
+\setupheadtext [\s!cn] [\v!abbreviations=缩略语]
+\setupheadtext [\s!cn] [\v!logos=徽贬]
+\setupheadtext [\s!cn] [\v!units=计量单位]
+
+\setuplabeltext [\s!cn] [\v!table=表]
+\setuplabeltext [\s!cn] [\v!figure=图]
+\setuplabeltext [\s!cn] [\v!intermezzo=퉣]
+\setuplabeltext [\s!cn] [\v!graphic=插图]
+\setuplabeltext [\s!cn] [\v!appendix=附录]
+\setuplabeltext [\s!cn] [\v!part={第,部分}]
+\setuplabeltext [\s!cn] [\v!chapter={第,章}]
+\setuplabeltext [\s!cn] [\v!section={第,节}]
+\setuplabeltext [\s!cn] [\v!line=行]
+\setuplabeltext [\s!cn] [\v!lines=行]
+
+\setuplabeltext [\s!cn] [\v!subsection=]
+\setuplabeltext [\s!cn] [\v!subsubsection=]
+\setuplabeltext [\s!cn] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!cn] [\v!january=一月]
+\setuplabeltext [\s!cn] [\v!february=二月]
+\setuplabeltext [\s!cn] [\v!march=三月]
+\setuplabeltext [\s!cn] [\v!april=四月]
+\setuplabeltext [\s!cn] [\v!may=五月]
+\setuplabeltext [\s!cn] [\v!june=六月]
+\setuplabeltext [\s!cn] [\v!july=七月]
+\setuplabeltext [\s!cn] [\v!august=八月]
+\setuplabeltext [\s!cn] [\v!september=九月]
+\setuplabeltext [\s!cn] [\v!october=十月]
+\setuplabeltext [\s!cn] [\v!november=十一月]
+\setuplabeltext [\s!cn] [\v!december=十二月]
+
+\setuplabeltext [\s!cn] [\v!sunday=星期日]
+\setuplabeltext [\s!cn] [\v!monday=星期一]
+\setuplabeltext [\s!cn] [\v!tuesday=星期二]
+\setuplabeltext [\s!cn] [\v!wednesday=星期三]
+\setuplabeltext [\s!cn] [\v!thursday=星期四]
+\setuplabeltext [\s!cn] [\v!friday=星期五]
+\setuplabeltext [\s!cn] [\v!saturday=星期六]
+
+%D Japanese
+
+\installlanguage
+ [\s!ja]
+ [\c!leftsentence=——,
+ \c!rightsentence=——,
+ \c!leftsubsentence=——,
+ \c!rightsubsentence=——,
+ \c!leftquote=‘,
+ \c!rightquote=’,
+ \c!leftquotation=「,
+ \c!rightquotation=」,
+ \c!date={西暦,\v!year,年,\v!month,月,\v!day,日}]
+
+\setupheadtext [\s!ja] [\v!content=目次]
+\setupheadtext [\s!ja] [\v!tables=机]
+\setupheadtext [\s!ja] [\v!figures=図]
+\setupheadtext [\s!ja] [\v!graphics=グラフ]
+\setupheadtext [\s!ja] [\v!intermezzi=間奏曲]
+\setupheadtext [\s!ja] [\v!index=目次]
+\setupheadtext [\s!ja] [\v!abbreviations=略語]
+\setupheadtext [\s!ja] [\v!logos=理性]
+\setupheadtext [\s!ja] [\v!units=ユニッツ]
+
+\setuplabeltext [\s!ja] [\v!table=表]
+\setuplabeltext [\s!ja] [\v!figure=図]
+\setuplabeltext [\s!ja] [\v!intermezzo=間奏曲]
+\setuplabeltext [\s!ja] [\v!graphic=イラスト]
+\setuplabeltext [\s!ja] [\v!appendix=付録]
+\setuplabeltext [\s!ja] [\v!part={第,パート}]
+\setuplabeltext [\s!ja] [\v!chapter={第,章}]
+\setuplabeltext [\s!ja] [\v!section={第,項}]
+\setuplabeltext [\s!ja] [\v!line=線]
+\setuplabeltext [\s!ja] [\v!lines=線]
+
+\setuplabeltext [\s!ja] [\v!subsection=]
+\setuplabeltext [\s!ja] [\v!subsubsection=]
+\setuplabeltext [\s!ja] [\v!subsubsubsection=]
+
+\setuplabeltext [\s!ja] [\v!january=1]
+\setuplabeltext [\s!ja] [\v!february=2]
+\setuplabeltext [\s!ja] [\v!march=3]
+\setuplabeltext [\s!ja] [\v!april=4]
+\setuplabeltext [\s!ja] [\v!may=5]
+\setuplabeltext [\s!ja] [\v!june=6]
+\setuplabeltext [\s!ja] [\v!july=7]
+\setuplabeltext [\s!ja] [\v!august=8]
+\setuplabeltext [\s!ja] [\v!september=9]
+\setuplabeltext [\s!ja] [\v!october=10]
+\setuplabeltext [\s!ja] [\v!november=11]
+\setuplabeltext [\s!ja] [\v!december=12]
+
+\setuplabeltext [\s!ja] [\v!sunday=月曜日]
+\setuplabeltext [\s!ja] [\v!monday=火曜日]
+\setuplabeltext [\s!ja] [\v!tuesday=水曜日]
+\setuplabeltext [\s!ja] [\v!wednesday=木曜日]
+\setuplabeltext [\s!ja] [\v!thursday=金曜日]
+\setuplabeltext [\s!ja] [\v!friday=土曜日]
+\setuplabeltext [\s!ja] [\v!saturday=日曜日]
+
+%D Korean
+
+% todo
+
+\protect \endinput
+
+cn={
+ ["abbreviations"]="缩略语",
+ ["appendix"]="附录",
+ ["april"]="四月",
+ ["august"]="八月",
+ ["chapter"]="章",
+ ["contents"]="目录",
+ ["day"]="日",
+ ["december"]="十二月",
+ ["febrary"]="二月",
+ ["figure"]="图",
+ ["figures"]="图形",
+ ["friday"]="星期五",
+ ["graphics"]="图",
+ ["illustration"]="插图",
+ ["index"]="索引",
+ ["intermezzo"]="퉣",
+ ["intro"]="第",
+ ["january"]="一月",
+ ["july"]="七月",
+ ["june"]="六月",
+ ["leftsentence"]="——",
+ ["leftsubsentence"]="——",
+ ["line"]="行",
+ ["logos"]="徽贬",
+ ["march"]="三月",
+ ["may"]="五月",
+ ["monday"]="星期一",
+ ["month"]="月",
+ ["november"]="十一月",
+ ["october"]="十月",
+ ["part"]="部分",
+ ["rightsentence"]="——",
+ ["rightsubsentence"]="——",
+ ["saturday"]="星期六",
+ ["section"]="节",
+ ["september"]="九月",
+ ["sunday"]="星期日",
+ ["table"]="表",
+ ["tables"]="表格",
+ ["thursday"]="星期四",
+ ["tuesday"]="星期二",
+ ["units"]="计量单位",
+ ["upperleftdoublequote"]="“",
+ ["upperleftdoublequote-v"]="『",
+ ["upperleftsinglequote"]="‘",
+ ["upperleftsinglequote-v"]="「",
+ ["upperrightdoublequote"]="”",
+ ["upperrightdoublequote-v"]="』",
+ ["upperrightsinglequote"]="’",
+ ["upperrightsinglequote-v"]="」",
+ ["wednesday"]="星期三",
+ ["year"]="年",
+}
+
+ja={
+ ["abbreviations"]="略語",
+ ["abstract"]="概要",
+ ["and"]="、",
+ ["answer"]="答:",
+ ["appendix"]="付録",
+ ["april"]="四月",
+ ["article"]="項目",
+ ["august"]="八月",
+ ["bibliography"]="参考文献",
+ ["book"]="ブック",
+ ["bridgehead"]="項",
+ ["bullet"]="●",
+ ["by"]=":",
+ ["caution"]="注意",
+ ["chapter"]="章",
+ ["christiandate"]="西暦",
+ ["colophon"]="奥付",
+ ["copyright"]="製作著作",
+ ["day"]="日",
+ ["december"]="十二月",
+ ["dedication"]="謝辞",
+ ["edited"]="編者",
+ ["editedby"]="編者:",
+ ["edition"]="編集",
+ ["endquote"]="」",
+ ["equation"]="式",
+ ["example"]="例",
+ ["february"]="二月",
+ ["figure"]="図",
+ ["figures"]="図",
+ ["friday"]="土曜日",
+ ["glossary"]="用語集",
+ ["glosssee"]="参照",
+ ["glossseealso"]="参照",
+ ["graphics"]="グラフ",
+ ["illustration"]="イラスト",
+ ["important"]="重要項目",
+ ["index"]="目次",
+ ["indexsymbols"]="シンボル",
+ ["intermezzo"]="間奏曲",
+ ["intermezzos"]="間奏曲",
+ ["intro"]="第",
+ ["january"]="一月",
+ ["july"]="七月",
+ ["june"]="六月",
+ ["leftsentence"]="——",
+ ["leftsubsentence"]="——",
+ ["line"]="線",
+ ["lines"]="線",
+ ["listofequations"]="式目次",
+ ["listofexamples"]="例目次",
+ ["listoffigures"]="図目次",
+ ["listoftables"]="表目次",
+ ["listofunknown"]="不明目次",
+ ["logos"]="理性",
+ ["march"]="三月",
+ ["may"]="五月",
+ ["monday"]="火曜日",
+ ["month"]="月",
+ ["msgaud"]="対象者",
+ ["msglevel"]="レベル",
+ ["msgorig"]="発信元",
+ ["navhome"]="ホーム",
+ ["navnext"]="次のページ",
+ ["navnextsibling"]="早送り",
+ ["navprev"]="前のページ",
+ ["navprevsibling"]="巻戻し",
+ ["navup"]="上に戻る",
+ ["nestedendquote"]="』",
+ ["nestedstartquote"]="『",
+ ["nonexistantelement"]="要素が存在しません",
+ ["note"]="注意",
+ ["notes"]="注意",
+ ["november"]="十一月",
+ ["october"]="十月",
+ ["pages"]="偧献",
+ ["part"]="パート",
+ ["preface"]="序文",
+ ["procedure"]="手順",
+ ["procedureformal"]="手順",
+ ["productionset"]="プロダクション",
+ ["productionsetformal"]="プロダクション",
+ ["published"]="発行",
+ ["qandadiv"]="問:、答:",
+ ["qandaentry"]="問:",
+ ["question"]="問:",
+ ["reference"]="参照",
+ ["refname"]="名前",
+ ["refsection"]="項",
+ ["refsynopsisdiv"]="概要",
+ ["revhistory"]="改訂履歴",
+ ["revision"]="改訂",
+ ["rightsentence"]="——",
+ ["rightsubsentence"]="——",
+ ["saturday"]="日曜日",
+ ["section"]="項",
+ ["see"]="参照",
+ ["seealso"]="参照",
+ ["separator"]="、",
+ ["september"]="九月",
+ ["set"]="設定",
+ ["setindex"]="目次設定",
+ ["sidebar"]="サイドバー",
+ ["simplesect"]="項",
+ ["singleendquote"]="’",
+ ["singlestartquote"]="‘",
+ ["startquote"]="「",
+ ["step"]="ステップ",
+ ["sunday"]="月曜日",
+ ["table"]="表",
+ ["tablenotes"]="注意",
+ ["tableofcontents"]="目次",
+ ["tables"]="机",
+ ["thursday"]="金曜日",
+ ["tip"]="ティップ",
+ ["tuesday"]="水曜日",
+ ["unexpectedelementname"]="不明な要素名",
+ ["units"]="ユニッツ",
+ ["unsupported"]="サポートしません",
+ ["warning"]="警告",
+ ["wednesday"]="木曜日",
+ ["year"]="年",
+}
diff --git a/tex/context/base/lang-ctx.tex b/tex/context/base/lang-ctx.tex
index 5364c1af6..09f28dda1 100644
--- a/tex/context/base/lang-ctx.tex
+++ b/tex/context/base/lang-ctx.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Language Macros / Generic Patterns}
+\writestatus{loading}{ConTeXt Language Macros / Generic Patterns}
\unprotect
@@ -28,31 +28,26 @@
%D than one font encoding is in use. I can add more defaults here
%D if users let me know what encoding they use.
-\installlanguage [\s!nl] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
-\installlanguage [\s!fr] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
-\installlanguage [\s!de] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
-\installlanguage [\s!it] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
-
-\installlanguage [\s!pt] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
-
-\installlanguage [\s!hr] [\s!mapping=ec,\s!encoding=ec] % no il2, misses cacute characters
-
-\installlanguage [\s!pl] [\s!mapping={pl0,ec,qx},\s!encoding={pl0,ec,qx}] % pl0 may go
-\installlanguage [\s!cs] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
-\installlanguage [\s!sk] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
-\installlanguage [\s!sl] [\s!mapping=ec,\s!encoding=ec] % il2 has gone
-
-\installlanguage [\s!vn] [\s!mapping=t5,\s!encoding=t5]
-
-\installlanguage [\s!ru] [\s!mapping=t2a,\s!encoding=t2a]
+% \installlanguage [\s!nl] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!fr] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!de] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!it] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!pt] [\s!mapping={texnansi,ec},\s!encoding={texnansi,ec}]
+% \installlanguage [\s!hr] [\s!mapping=ec,\s!encoding=ec] % no il2, misses cacute characters
+% \installlanguage [\s!pl] [\s!mapping={pl0,ec,qx},\s!encoding={pl0,ec,qx}] % pl0 may go
+% \installlanguage [\s!cs] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
+% \installlanguage [\s!sk] [\s!mapping={il2,ec},\s!encoding={il2,ec}] % il2 may go
+% \installlanguage [\s!sl] [\s!mapping=ec,\s!encoding=ec] % il2 has gone
+% \installlanguage [\s!vi] [\s!mapping=t5,\s!encoding=t5]
+% \installlanguage [\s!ru] [\s!mapping=t2a,\s!encoding=t2a]
% beware, don't use \setuplanguage here
-\installlanguage[\s!gb][\s!lefthyphenmin=3,\s!righthyphenmin=3] % patterns can only handle this
-\installlanguage[\s!us][\s!lefthyphenmin=2,\s!righthyphenmin=3] % patterns can only handle this
+% \installlanguage[\s!gb][\s!lefthyphenmin=3,\s!righthyphenmin=3] % patterns can only handle this
+% \installlanguage[\s!us][\s!lefthyphenmin=2,\s!righthyphenmin=3] % patterns can only handle this
% greek
-\installlanguage[\s!agr][\s!mapping=\s!agr,\s!encoding=\s!agr]
+% \installlanguage[\s!agr][\s!mapping=\s!agr,\s!encoding=\s!agr]
\protect \endinput
diff --git a/tex/context/base/lang-cyr.tex b/tex/context/base/lang-cyr.tex
index 34b5e78c3..470402bb1 100644
--- a/tex/context/base/lang-cyr.tex
+++ b/tex/context/base/lang-cyr.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Cyrillic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Cyrillic Languages}
%D The cyrillic languages always use a dedicated input regime.
%D Therefore we define the labels using symbolic names.
@@ -37,7 +37,8 @@
\c!leftquotation=\leftguillemot,
\c!rightquotation=\rightguillemot,
\c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping=t2a,
+ \s!encoding=t2a]
\installlanguage
[\s!ua]
@@ -53,11 +54,12 @@
\c!leftquotation=\leftguillemot,
\c!rightquotation=\rightguillemot,
\c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
-
-\installlanguage [russian] [\s!ru]
-\installlanguage [ukrainian] [\s!ua]
+ \s!patterns=\s!uk,
+ \s!mapping=t2a,
+ \s!encoding=t2a]
+\installlanguage [russian] [\s!ru]
+\installlanguage [ukrainian] [\s!ua]
%D Labels and header texts.
diff --git a/tex/context/base/lang-dis.tex b/tex/context/base/lang-dis.tex
index db932d68a..f081bf4a9 100644
--- a/tex/context/base/lang-dis.tex
+++ b/tex/context/base/lang-dis.tex
@@ -15,7 +15,7 @@
%D use more generic pattern files, we decided to isolate these
%D mappings.
-\writestatus{loading}{Context Language Macros / Distribution Patterns}
+\writestatus{loading}{ConTeXt Language Macros / Distribution Patterns}
%D Hyphenation patterns are normally sought in filed named
%D \type {lang-xx.pat}. When present on the system, those
@@ -52,8 +52,8 @@
% \definefilefallback [lang-sk.pat] [skhyphen.tex,skhyph.pat]
% \definefilefallback [lang-deo.pat] [dehypht.tex]
-\definefilesynonym [lang-af.pat] [lang-nl.pat]
-\definefilesynonym [lang-en.pat] [lang-us.pat]
-\definefilesynonym [lang-en.hyp] [lang-us.hyp]
+% \definefilesynonym [lang-af.pat] [lang-nl.pat]
+% \definefilesynonym [lang-en.pat] [lang-us.pat]
+% \definefilesynonym [lang-en.hyp] [lang-us.hyp]
\protect \endinput
diff --git a/tex/context/base/lang-frq.tex b/tex/context/base/lang-frq.tex
index 372813f70..773230e6c 100644
--- a/tex/context/base/lang-frq.tex
+++ b/tex/context/base/lang-frq.tex
@@ -2,7 +2,7 @@
%D [ file=lang-frq,
%D version=2004.01.15,
%D title=\CONTEXT\ Language Macros,
-%D subtitle=Language Frequency Table Support,
+%D subtitle=Frequency Tables,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Language Frequency Table Support}
+\writestatus{loading}{ConTeXt Language Macros / Frequency Tables}
\unprotect
diff --git a/tex/context/base/lang-ger.tex b/tex/context/base/lang-ger.tex
index bdcaa9cb3..b9717ce9a 100644
--- a/tex/context/base/lang-ger.tex
+++ b/tex/context/base/lang-ger.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Germanic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Germanic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -42,7 +42,8 @@
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
\installlanguage
[\s!en]
@@ -57,11 +58,14 @@
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!month,\ ,\v!day,{,\ },\v!year},
\s!patterns=\s!us,
- \c!state=\v!stop] % elders always preloaded!
+ \s!lefthyphenmin=2,
+ \s!righthyphenmin=3]
\installlanguage
[\s!de]
[\c!spacing=\v!packed,
+ \s!lefthyphenmin=3,
+ \s!righthyphenmin=3,
\c!leftsentence={\hbox{--~}},
\c!rightsentence={\hbox{~--}},
\c!leftsubsentence={--},
@@ -71,7 +75,8 @@
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoublesixquote,
\c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
\installlanguage
[\s!da]
@@ -84,8 +89,7 @@
\c!rightquote=\upperrightsinglesixquote,
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoublesixquote,
- \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,{.},\ ,\v!month,\ ,\v!year}]
\installlanguage
[\s!sv]
@@ -98,8 +102,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperrightdoubleninequote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
\installlanguage
[\s!af]
@@ -113,7 +116,7 @@
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!year,\ ,\v!month,\ ,\v!day},
- \c!state=\v!stop]
+ \s!patterns=\s!nl]
\installlanguage
[\s!nb]
@@ -180,14 +183,12 @@
\installlanguage % old german
[deo]
[\c!spacing=\v!packed,
- \c!default=\s!de,
- \c!state=\v!stop]
+ \c!default=\s!de]
\installlanguage
[de-de]
[\c!spacing=\v!packed,
- \c!default=\s!de,
- \c!state=\v!stop]
+ \c!default=\s!de]
\installlanguage
[de-at]
@@ -196,14 +197,12 @@
\c!leftquote=\leftguillemot,
\c!rightquote=\rightguillemot,
\c!leftquotation=\leftguillemot,
- \c!rightquotation=\rightguillemot,
- \c!state=\v!stop]
+ \c!rightquotation=\rightguillemot]
\installlanguage
[de-ch]
[\c!spacing=\v!packed,
- \c!default=\s!de,
- \c!state=\v!stop]
+ \c!default=\s!de]
%D And some alternative (but very real) english patterns:
@@ -211,24 +210,23 @@
[en-gb]
[\c!default=\s!en,
\s!patterns=\s!gb,
- \c!state=\v!stop]
+ \s!lefthyphenmin=3,
+ \s!righthyphenmin=3]
\installlanguage
[en-us]
- [\c!default=\s!en,
- %\s!patterns=\s!us,
- \c!state=\v!stop]
+ [\c!default=\s!en]
\installlanguage [\s!uk] [en-gb]
\installlanguage [\s!us] [en-us]
%D For compatibility reasons we also define:
-\installlanguage [du] [\s!de] % old times context
+%installlanguage [du] [\s!de] % old times context
%installlanguage [sp] [\s!es] % old times context /lang-ita
\installlanguage [usenglish] [en-us]
-\installlanguage [ukenglish] [en-uk]
+\installlanguage [ukenglish] [en-gb]
\installlanguage [english] [en-us]
\installlanguage [dutch] [\s!nl]
\installlanguage [german] [\s!de]
diff --git a/tex/context/base/lang-grk.tex b/tex/context/base/lang-grk.tex
index 13cebb207..e4ba781eb 100644
--- a/tex/context/base/lang-grk.tex
+++ b/tex/context/base/lang-grk.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Greek Language}
+\writestatus{loading}{ConTeXt Language Macros / Greek}
%D The framework of this module is set up by Hans Hagen while
%D all the translations have been done by Apostolos Syropoulos
@@ -29,8 +29,7 @@
\c!rightquote=\greekrightquot,
\c!leftquotation=\greekleftquot,
\c!rightquotation=\greekrightquot,
- \c!date={\v!day\ \v!month\ \v!year},
- \c!state=\v!stop]
+ \c!date={\v!day\ \v!month\ \v!year}]
\installlanguage [greek] [\s!gr]
@@ -86,7 +85,9 @@
\installlanguage
[\s!agr]
[\s!default=\s!gr,
- \c!state=\v!stop]
+ \s!patterns=\s!agr,
+ \s!mapping=\s!agr,
+ \s!encoding=\s!agr]
\installlanguage [ancientgreek] [\s!agr]
diff --git a/tex/context/base/lang-ind.tex b/tex/context/base/lang-ind.tex
index f9bbad0d7..9b6e5ff1d 100644
--- a/tex/context/base/lang-ind.tex
+++ b/tex/context/base/lang-ind.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Indo-Iranian Languages}
+\writestatus{loading}{ConTeXt Language Macros / Indo-Iranian Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
diff --git a/tex/context/base/lang-ini.lua b/tex/context/base/lang-ini.lua
index e9e9af1b6..e188ad36c 100644
--- a/tex/context/base/lang-ini.lua
+++ b/tex/context/base/lang-ini.lua
@@ -6,6 +6,13 @@ if not modules then modules = { } end modules ['lang-ini'] = {
license = "see context related readme files"
}
+-- needs a cleanup (share locals)
+
+local utf = unicode.utf8
+
+local find, lower, format, utfchar = string.find, string.lower, string.format, utf.char
+local concat = table.concat
+
if lang.use_new then lang.use_new(true) end
languages = languages or {}
@@ -13,6 +20,8 @@ languages.version = 1.009
languages.hyphenation = languages.hyphenation or { }
languages.hyphenation.data = languages.hyphenation.data or { }
+local langdata = languages.hyphenation.data
+
-- 002D : hyphen-minus (ascii)
-- 2010 : hyphen
-- 2011 : nonbreakable hyphen
@@ -26,7 +35,7 @@ languages.hyphenation.data = languages.hyphenation.data or { }
-- we can consider hiding data (faster access too)
--~ local function filter(filename,what)
---~ local data = io.loaddata(input.find_file(filename))
+--~ local data = io.loaddata(resolvers.find_file(filename))
--~ local data = data:match(string.format("\\%s%%s*(%%b{})",what or "patterns"))
--~ return data:match("{%s*(.-)%s*}") or ""
--~ end
@@ -47,29 +56,29 @@ local command = lpeg.P("\\patterns")
local parser = (1-command)^0 * command * content
local function filterpatterns(filename)
- if filename:find("%.rpl") then
- return io.loaddata(input.find_file(filename)) or ""
+ if find(filename,"%.rpl") then
+ return io.loaddata(resolvers.find_file(filename)) or ""
else
- return parser:match(io.loaddata(input.find_file(filename)) or "")
+ return parser:match(io.loaddata(resolvers.find_file(filename)) or "")
end
end
-local command = lpeg.P("\\hyphenation")
-local parser = (1-command)^0 * command * content
+local command = lpeg.P("\\hyphenation")
+local parser = (1-command)^0 * command * content
local function filterexceptions(filename)
- if filename:find("%.rhl") then
- return io.loaddata(input.find_file(filename)) or ""
+ if find(filename,"%.rhl") then
+ return io.loaddata(resolvers.find_file(filename)) or ""
else
- return parser:match(io.loaddata(input.find_file(filename)) or {}) -- "" ?
+ return parser:match(io.loaddata(resolvers.find_file(filename)) or {}) -- "" ?
end
end
local function record(tag)
- local data = languages.hyphenation.data[tag]
+ local data = langdata[tag]
if not data then
data = lang.new()
- languages.hyphenation.data[tag] = data or 0
+ langdata[tag] = data or 0
end
return data
end
@@ -82,31 +91,31 @@ function languages.hyphenation.define(tag)
end
function languages.hyphenation.number(tag)
- local d = languages.hyphenation.data[tag]
+ local d = langdata[tag]
return (d and d:id()) or 0
end
-function languages.hyphenation.load(tag, filename, filter, target)
- input.starttiming(languages)
+local function loadthem(tag, filename, filter, target)
+ statistics.starttiming(languages)
local data = record(tag)
- filename = (filename and filename ~= "" and input.find_file(filename)) or ""
+ filename = (filename and filename ~= "" and resolvers.find_file(filename)) or ""
local ok = filename ~= ""
if ok then
lang[target](data,filterpatterns(filename))
else
lang[target](data,"")
end
- languages.hyphenation.data[tag] = data
- input.stoptiming(languages)
+ langdata[tag] = data
+ statistics.stoptiming(languages)
return ok
end
function languages.hyphenation.loadpatterns(tag, patterns)
- return languages.hyphenation.load(tag, patterns, filterpatterns, "patterns")
+ return loadthem(tag, patterns, filterpatterns, "patterns")
end
function languages.hyphenation.loadexceptions(tag, exceptions)
- return languages.hyphenation.load(tag, patterns, filterexceptions, "hyphenation")
+ return loadthem(tag, patterns, filterexceptions, "hyphenation")
end
function languages.hyphenation.exceptions(tag, ...)
@@ -130,16 +139,17 @@ function languages.hyphenation.righthyphenmin(tag, value)
end
function languages.hyphenation.n()
- return table.count(languages.hyphenation.data)
+ return table.count(langdata)
end
-- we can speed this one up with locals if needed
local function tolang(what)
- if type(what) == "number" then
- return languages.hyphenation.data[languages.numbers[what]]
- elseif type(what) == "string" then
- return languages.hyphenation.data[what]
+ local kind = type(what)
+ if kind == "number" then
+ return langdata[languages.numbers[what]]
+ elseif kind == "string" then
+ return langdata[what]
else
return what
end
@@ -158,15 +168,15 @@ languages.registered = languages.registered or { }
languages.associated = languages.associated or { }
languages.numbers = languages.numbers or { }
-input.storage.register(false,"languages/registered",languages.registered,"languages.registered")
-input.storage.register(false,"languages/associated",languages.associated,"languages.associated")
+storage.register("languages/registered",languages.registered,"languages.registered")
+storage.register("languages/associated",languages.associated,"languages.associated")
function languages.register(tag,parent,patterns,exceptions)
parent = parent or tag
languages.registered[tag] = {
parent = parent,
- patterns = patterns or string.format("lang-%s.pat",parent),
- exceptions = exceptions or string.format("lang-%s.hyp",parent),
+ patterns = patterns or format("lang-%s.pat",parent),
+ exceptions = exceptions or format("lang-%s.hyp",parent),
loaded = false,
number = 0,
}
@@ -190,7 +200,7 @@ end
function languages.loadable(tag)
local l = languages.registered[tag]
- if l and l.patterns and input.find_file(patterns) then
+ if l and l.patterns and resolvers.find_file(patterns) then
return true
else
return false
@@ -237,10 +247,10 @@ function languages.hyphenation.loadwords(tag, filename)
local id = languages.hyphenation.number(tag)
if id > 0 then
local l = lang.new(id) or 0
- input.starttiming(languages)
+ statistics.starttiming(languages)
local data = io.loaddata(filename) or ""
l:hyphenation(data)
- input.stoptiming(languages)
+ statistics.stoptiming(languages)
end
end
@@ -257,10 +267,10 @@ function languages.logger.report()
if l.loaded then
local p = (l.patterns and "pat") or '-'
local e = (l.exceptions and "exc") or '-'
- result[#result+1] = string.format("%s:%s:%s:%s:%s", tag, l.parent, p, e, l.number)
+ result[#result+1] = format("%s:%s:%s:%s:%s", tag, l.parent, p, e, l.number)
end
end
- return (#result > 0 and table.concat(result," ")) or "none"
+ return (#result > 0 and concat(result," ")) or "none"
end
languages.words = languages.words or {}
@@ -283,15 +293,15 @@ do
local word = lpeg.Cs((markup/"" + disc/"" + (1-spacing))^1)
function languages.words.load(tag, filename)
- local filename = input.find_file(filename,'other text file') or ""
+ local filename = resolvers.find_file(filename,'other text file') or ""
if filename ~= "" then
- input.starttiming(languages)
+ statistics.starttiming(languages)
local data = io.loaddata(filename) or ""
local words = languages.words.data[tag] or {}
parser = (spacing + word/function(s) words[s] = true end)^0
parser:match(data)
languages.words.data[tag] = words
- input.stoptiming(languages)
+ statistics.stoptiming(languages)
end
end
@@ -301,7 +311,7 @@ function languages.words.found(id, str)
local tag = languages.numbers[id]
if tag then
local data = languages.words.data[tag]
- return data and (data[str] or data[str:lower()])
+ return data and (data[str] or data[lower(str)])
else
return false
end
@@ -314,11 +324,10 @@ do
local glyph, disc, kern = node.id('glyph'), node.id('disc'), node.id('kern')
- local bynode = node.traverse
+ local bynode = node.traverse
+ local chardata = characters.data
local function mark_words(head,found) -- can be optimized
- local cd = characters.data
- local uc = utf.char
local current, start, str, language, n = head, nil, "", nil, 0
local function action()
if #str > 0 then
@@ -347,25 +356,25 @@ do
action()
language = a
end
- if current.subtype > 0 then
+ local components = current.components
+ if components then
start = start or current
n = n + 1
- for g in bynode(current.components) do
- str = str .. uc(g.char)
+ for g in bynode(components) do
+ str = str .. utfchar(g.char)
end
else
local code = current.char
- if cd[code].uccode or cd[code].lccode then
+ if chardata[code].uccode or chardata[code].lccode then
start = start or current
n = n + 1
- str = str .. uc(code)
- else
- if start then
- action()
- end
+ str = str .. utfchar(code)
+ elseif start then
+ action()
end
end
elseif id == disc then
+ if n > 0 then n = n + 1 end
-- ok
elseif id == kern and current.subtype == 0 and start then
-- ok
@@ -383,18 +392,20 @@ do
languages.words.methods = { }
languages.words.method = 1
+ local lw = languages.words
+
languages.words.methods[1] = function(head, attribute, yes, nop)
local set = node.set_attribute
local unset = node.unset_attribute
- local wrong, right = false, false
- if nop then wrong = function(n) set(n,attribute,nop) end end
+ local right, wrong = false, false
if yes then right = function(n) set(n,attribute,yes) end end
+ if nop then wrong = function(n) set(n,attribute,nop) end end
for n in node.traverse(head) do
unset(n,attribute) -- hm
end
local found, done = languages.words.found, false
mark_words(head, function(language,str)
- if #str < languages.words.threshold then
+ if #str < lw.threshold then
return false
elseif found(language,str) then
done = true
@@ -407,11 +418,10 @@ do
return head, done
end
- local lw = languages.words
+ local color = attributes.private('color')
function languages.words.check(head)
if lw.enable and head.next then
- local color = attributes.numbers['color']
local colors = lw.colors
local alc = attributes.list[color]
return lw.methods[lw.method](head, color, alc[colors.known], alc[colors.unknown])
@@ -443,3 +453,16 @@ languages.associate('uk','latn','eng')
languages.associate('nl','latn','nld')
languages.associate('de','latn','deu')
languages.associate('fr','latn','fra')
+
+statistics.register("loaded patterns", function()
+ local result = languages.logger.report()
+ if result ~= "none" then
+ return result
+ end
+end)
+
+statistics.register("language load time", function()
+ if statistics.elapsedindeed(languages) then
+ return format("%s seconds, n=%s", statistics.elapsedtime(languages), languages.hyphenation.n())
+ end
+end)
diff --git a/tex/context/base/lang-ini.mkii b/tex/context/base/lang-ini.mkii
index 46b9f51ce..e5759bc84 100644
--- a/tex/context/base/lang-ini.mkii
+++ b/tex/context/base/lang-ini.mkii
@@ -11,13 +11,159 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D This module needs a further cleanup (real split between ii/iv).
+
+%D This module implements the (for the moment still simple)
+%D multi||language support of \CONTEXT, which should not be
+%D confused with the multi||lingual interface. This support
+%D will be extended when needed.
+
+\writestatus{loading}{ConTeXt Language Macros / Initialization}
+
\unprotect
+\ifx\nonfrenchspacing\undefined \let\nonfrenchspacing\relax \fi
+\ifx\frenchspacing \undefined \let\frenchspacing \relax \fi
+
+%D When loading hyphenation patterns, \TEX\ assign a number to
+%D each loaded table, starting with~0. Switching to a specific
+%D table is done by assigning the relevant number to the
+%D predefined \COUNTER\ \type{\language}.
+
+%D We keep track of the last loaded patterns by means of a
+%D pseudo \COUNTER. This just one of those situations in which
+%D we don't want to spent a real one. Language zero has no
+%D patterns, first of all because I like to start numbering
+%D at one. It may come in handy for special purposes as well.
+
+\normallanguage\zerocount \def\loadedlanguage{1}
+
+%D \macros
+%D {currentlanguage, setupcurrentlanguage}
+%D
+%D Instead of numbers,we are going to use symbolic names for
+%D the languages. The current langage is saved in the macro
+%D \type {\currentlanguage}. The setup macro is mainly used
+%D for cosmetic purposes.
+%D
+%D \starttyping
+%D \dorecurse{3}
+%D {\language[nl]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode
+%D \language[en]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode}
+%D \stoptyping
+
+\let\currentlanguage \empty
+\let\currentmainlanguage\empty
+
+\def\setupcurrentlanguage[#1]{\setcurrentlanguage\currentmainlanguage{#1}}
+
+\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
+ {\doifsomething{#1}
+ {\ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
+ \edef\currentmainlanguage{#1}%
+ \setsystemmode{\systemmodeprefix\currentmainlanguage}}%
+ \doifsomething{#2}
+ {\ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
+ \edef\currentlanguage{#2}%
+ \setsystemmode\currentlanguage}}
+
+%D The internal macros will be defined later.
+
+%D \macros
+%D {installlanguage}
+%D
+%D Hyphenation patterns can only be loaded when the format file
+%D is prepared. The next macro takes care of this loading. A
+%D language is specified with
+%D
+%D \showsetup{installlanguage}
+%D
+%D When \type {state} equals \type {start}, both patterns
+%D and additional hyphenation specifications are loaded. These
+%D files are seached for on the system path and are to be
+%D named:
+%D
+%D \starttyping
+%D \f!languageprefix-identifier.\f!patternsextension
+%D \f!languageprefix-identifier.\f!hyhensextension
+%D \stoptyping
+%D
+%D The \type{spacing} variable specifies how the spaces after
+%D punctuation has to be handled. English is by tradition more
+%D tolerant to inter||sentence spacing than other languages.
+%D
+%D This macro also defines \type {\identifier} as a shortcut
+%D switch to the language. Furthermore the command defined as
+%D being language specific, are executed. With
+%D \type {default} we can default to another language
+%D (patterns) at format generation time. This default language
+%D is overruled when the appropriate patterns are loaded (some
+%D implementations support run time addition of patterns to a
+%D preloaded format).
+
+\def\dodoinstalllanguage#1#2% #2 added
+ {\doifundefined{#1}{\setvalue{#1}{\complexlanguage[#2]}}%
+ \expanded{\noexpand\uppercase{\noexpand\edef\noexpand\ascii{#1}}}%
+ \doifundefined\ascii{\setvalue\ascii{\complexlanguage[#2]}}}
+
+%D \macros
+%D {preloadlanguages}
+%D
+%D We first try to load the files defined as file synonym
+%D for \type {lang-*.pat} and \type {lang-*.hyp}. After that we
+%D fall back on those files. The macro \type {\preloadpatterns}
+%D reports which patterns are loaded and what hyphenmin
+%D values are set.
+
+\let\installedlanguages\empty
+
+\def\doiflanguageelse#1{\doifdefinedelse{\??la#1\c!state}}
+
+\def\doloadlanguagefiles#1%
+ {\doifelsevalue{\??la#1\c!state}\v!start
+ {\edef\languagesuffix{\specificlanguageparameter{#1}\s!patterns}%
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \else\ifx\languagesuffix\relax
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \fi\fi
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{#1}%
+ \fi
+ \doifundefinedelse{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}
+ {\doloadpatterns{#1}\languagesuffix}
+ {\bgroup
+ \edef\loadedlanguage{\getvalue{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}}%
+ %\showmessage\m!linguals1{\languagesuffix,#1,\loadedlanguage,*,*}%
+ %\showmessage\m!linguals3{\languagesuffix,#1,\loadedlanguage,*,*}%
+ \egroup}}
+ {\showmessage\m!linguals5{#1}}}
+
+\def\doinstalllanguage[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\doiflanguageelse{#1}
+ {\getparameters[\??la#1][#2]}
+ {\setvalue{\l!prefix!#1}{#1}%
+ \addtocommalist{#1}\installedlanguages
+ \dodoinstalllanguage{#1}{#1}%
+ \getparameters[\??la#1][\c!state=\v!start,#2]}%
+ \doloadlanguagefiles{#1}}
+ {\setvalue{\l!prefix!#1}{#2}%
+ \getparameters[\??la#1][\s!default=#2]%
+ \dodoinstalllanguage{#1}{#2}}}
+
+\def\reallanguagetag#1%
+ {\ifcsname\l!prefix!#1\endcsname\csname\l!prefix!#1\endcsname\else#1\fi}
+
\let\preloadedpatterns\empty
\let\preloadedpmessage\empty
\def\doshowpatterns#1#2#3#4% language number encoding mapping
- {#1->#3:#4->#2->\xxlanguageparameter{#1}\s!lefthyphenmin:\xxlanguageparameter{#1}\s!righthyphenmin\space}
+ {#1->#3:#4->#2->\specificlanguageparameter{#1}\s!lefthyphenmin:\specificlanguageparameter{#1}\s!righthyphenmin\space}
\def\preloadlanguages
{\doifsomething\preloadedpmessage{\showmessage\m!linguals{10}\preloadedpmessage}}
@@ -27,16 +173,33 @@
\processcommacommand[\installedlanguages]\preloadallpatterns
\global\let\preloadallpatterns\relax}
-\fetchruntimecommand \showpatterns {\f!languageprefix\s!run}
+% ^^ \language[#1] gave unwanted side effect of loading language specifics
+
+\def\installlanguage
+ {\dodoubleargument\doinstalllanguage}
+
+%D When the second argument is a language identifier, a
+%D synonym is created. This feature is present because we
+%D used dutch mnemonics in the dutch version, but nowadays
+%D conform a standard.
+
+\let \patternencoding \s!default
+\let \patternmapping \s!default
-\def\mkdoloadpatterns#1#2%
- {\expanded{\getcommacommandsize[\getvalue{\??la#2\s!encoding}]}%
+\def\doifpatternselse#1%
+ {\expanded{\doifinsetelse{#1}{\preloadedpatterns}}}
+
+\def\doloadpatterns#1#2%
+ {\edef\askedlanguageencoding{\specificlanguageparameter{#1}\s!encoding}%
+ \edef\askedlanguagemapping {\specificlanguageparameter{#1}\s!mapping}%
+ \expanded{\getcommacommandsize[\askedlanguageencoding]}%
+ % slightly faster: \let\unicodechar\utfunihashglyph
\ifnum\commalistsize>0
- %\message{[nofpatterns #2: \commalistsize/\getvalue{\??la#2\s!encoding}]}%
+ %\message{[nofpatterns #2: \commalistsize/\askedlanguageencoding]}%
\dorecurse\commalistsize
- {\expanded{\getfromcommacommand[\getvalue{\??la#2\s!encoding}][\recurselevel]}%
+ {\expanded{\getfromcommacommand[\askedlanguageencoding][\recurselevel]}%
\let\patternencoding\commalistelement
- \expanded{\getfromcommacommand[\getvalue{\??la#2\s!mapping }][\recurselevel]}%
+ \expanded{\getfromcommacommand[\askedlanguagemapping][\recurselevel]}%
\let\patternmapping \commalistelement
%\message{[patterns: #1/#2/\patternencoding/\patternmapping]}%
\dodoloadpatterns{#1}{#2}\patternencoding\patternmapping}%
@@ -45,14 +208,14 @@
\dodoloadpatterns{#1}{#2}{}{}%
\fi}
-\beginXETEX
+\ifnum\texengine=\xetexengine
-\def\mkdoloadpatterns#1#2%
- {\letvalue{\??la#2\s!encoding}\empty
- \letvalue{\??la#2\s!mapping }\empty
- \dodoloadpatterns{#1}{#2}{}{}}
+ \def\doloadpatterns#1#2%
+ {%\letvalue{\??la#2\s!encoding}\empty
+ %\letvalue{\??la#2\s!mapping }\empty
+ \dodoloadpatterns{#1}{#2}{}{}}
-\endXETEX
+\fi
\def\setuphyppatencoding
{\pathypsettings
@@ -102,6 +265,8 @@
\fi
\egroup}
+\fetchruntimecommand \showpatterns {\f!languageprefix\s!run}
+
%D Since we can only load patterns in ini\TeX, we nil the
%D loading before dumping (which saves a bit of memory, but
%D strangely enough not in the format).
@@ -111,30 +276,130 @@
\globallet\dodoloadpatterns\gobblefourarguments
\to \everydump
-\def\mkdoifpatternselse#1%
- {\expanded{\doifinsetelse{#1}{\preloadedpatterns}}}
+%D \macros
+%D {setuplanguage}
+%D
+%D Quick and dirty, but useful:
+%D
+%D \showsetup{setuplanguage}
+%D
+%D Beware, this command can only be used when a language is installed.
-\def\mkloadlanguagefiles#1%
- {\doifelsevalue{\??la#1\c!state}\v!start
- {\doifelsevaluenothing{\??la#1\s!patterns}
- {\edef\languagesuffix{#1}}
- {\edef\languagesuffix{\getvalue{\??la#1\s!patterns}}}%
- \doifundefinedelse{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}
- {\mkdoloadpatterns{#1}\languagesuffix}
- {\bgroup
- \edef\loadedlanguage{\getvalue{\??la\??la:\currentencoding:\currentmapping:\languagesuffix}}%
- \showmessage\m!linguals1{\languagesuffix,#1,\loadedlanguage,*,*}%
- \showmessage\m!linguals3{\languagesuffix,#1,\loadedlanguage,*,*}%
- \egroup}}
- {\showmessage\m!linguals5{#1}}}
+\unprotected \def\setuplanguage
+ {\dodoubleempty\dosetuplanguage}
+
+\def\dosetuplanguage[#1][#2]% handy patch for testing
+ {\ifsecondargument
+ \getparameters[\??la#1][#2]%
+ \doif{#1}\currentlanguage\docomplexlanguage
+ \else
+ \getparameters[\??la\currentlanguage][#1]%
+ \docomplexlanguage
+ \fi}
+
+\setuplanguage
+ [\s!default]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \s!patterns=,
+ \c!spacing=\v!packed,
+ \s!encoding=,
+ \s!mapping=,
+ \c!lefthyphen=,
+ \c!righthyphen=-,
+ \c!hyphen=-,
+ \c!midsentence=---,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\languageparameter\c!leftquotation,
+ \c!middlespeech=,
+ \c!rightspeech=\languageparameter\c!rightquotation,
+ \c!limittext=\unknown,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \c!text=Ag]
+
+% rather new, split and per language
+
+\setuplanguage
+ [\s!default]
+ [\c!compoundhyphen=\compoundhyphen,
+ \c!leftcompoundhyphen=\compoundhyphen,
+ \c!rightcompoundhyphen=]
-\def\mksetnormallanguage#1#2% current default
+%D The values \type {leftsentence} and \type
+%D {rightsentence} can be (and are) used to implement
+%D automatic subsentence boundary glyphs, like in {\fr
+%D |<|french guillemots|>|} or {\de |<|german guillemots|>|} or
+%D {\nl |<|dutch dashes|>|} like situations. Furthermore \type
+%D {leftquotation} and \type {leftquote} come into view
+%D \quotation {when we quote} or \quote {quote} something.
+
+%D \macros
+%D {currentdatespecification}
+%D
+%D Just to make things easy we can ask for the current date
+%D specification by saying:
+
+\def\currentdatespecification{\languageparameter\c!date}
+
+%D This command is not meant for users.
+
+%D Carefull reading of these macros shows that it's legal to
+%D say
+%D
+%D \starttyping
+%D \installlanguage [du] [de]
+%D \stoptyping
+
+%D \macros
+%D {language,mainlanguage}
+%D
+%D Switching to another language (actually another hyphenation
+%D pattern) is done with:
+%D
+%D \starttyping
+%D \language[identifier]
+%D \stoptyping
+%D
+%D or with \type{\identifier}. Just to be compatible with
+%D \PLAIN\ \TEX, we still support the original meaning, so
+%D
+%D \starttyping
+%D \language=1
+%D \stoptyping
+%D
+%D is a valid operation, where the relation between number
+%D and language depends on the order in installing languages.
+%D
+%D \showsetup{language}
+%D \showsetup{mainlanguage}
+%D
+%D Both commands take a predefined language identifier as
+%D argument. We can use \type{\mainlanguage[identifier]} for
+%D setting the (indeed) main language. This is the language
+%D used for translating labels like {\em figure} and {\em
+%D table}. The main language defaults to the current language.
+%D
+%D We take care of local as well as standardized language
+%D switching (fr and fa, de and du, but nl and nl).
+
+\ifx\synchronizepatterns \undefined \let\synchronizepatterns\relax \fi
+\ifx\synchronizepatternswithfont\undefined \def\synchronizepatternswithfont{\synchronizepatterns} \fi
+
+\def\setnormallanguage#1#2% current default
{% called quite often, so we use \csname
% \def\synchronizepatterns{\setnormallanguage
% {\csname\??la\currentlanguage\s!patterns\endcsname}}% called often
% of even better pre-expand in an ugly way:
- \@EA\def\@EA\synchronizepatterns\@EA{\@EA\dosetnormallanguage
- \csname\??la\currentlanguage\s!patterns\endcsname}%
+% \@EA\def\@EA\synchronizepatterns\@EA{\@EA\dosetnormallanguage
+% \csname\??la\currentlanguage\s!patterns\endcsname}%
+\edef\synchronizepatterns{\noexpand\dosetnormallanguage{\languageparameter\s!patterns}}%
\donefalse
\synchronizepatterns
\ifdone\else
@@ -142,8 +407,9 @@
\synchronizepatterns
\ifdone\else
\ifx\currentdefaultlanguage\empty\else
- \@EA\def\@EA\synchronizepatterns\@EA{\@EA\dosetnormallanguage
- \csname\??la\currentdefaultlanguage\s!patterns\endcsname}%
+% \@EA\def\@EA\synchronizepatterns\@EA{\@EA\dosetnormallanguage
+% \csname\??la\currentdefaultlanguage\s!patterns\endcsname}%
+\edef\synchronizepatterns{\noexpand\dosetnormallanguage{\specificlanguageparameter\currentdefaultlanguage\s!patterns}}%
\synchronizepatterns
\ifdone\else
\dosetnormallanguage\currentdefaultlanguage
@@ -153,11 +419,11 @@
\fi
\fi}
-\def\dosetnormallanguage#1% #1 == \cs
- {\dodosetnormallanguage{:\currentencoding:\currentmapping:}#1{%
- \dodosetnormallanguage{:\currentencoding:\s!default :}#1{%
- \dodosetnormallanguage{:\s!default :\currentmapping:}#1{%
- \dodosetnormallanguage{:\s!default :\s!default :}#1\empty}}}}
+\def\dosetnormallanguage#1% #1 == \cs (no longer)
+ {\dodosetnormallanguage{:\currentencoding:\currentmapping:}{#1}{%
+ \dodosetnormallanguage{:\currentencoding:\s!default :}{#1}{%
+ \dodosetnormallanguage{:\s!default :\currentmapping:}{#1}{%
+ \dodosetnormallanguage{:\s!default :\s!default :}{#1}\empty}}}}
\def\dodosetnormallanguage#1#2%
{\ifcsname\??la\??la#1#2\endcsname
@@ -174,11 +440,251 @@
\@EA\firstofoneargument
\fi}
-\beginXETEX
+\newevery \everylanguage \relax
+
+\def\disablelanguagespecifics
+ {\ignorecompoundcharacter}
+
+\def\sethyphenationvariables
+ {\lefthyphenmin 0\languageparameter\s!lefthyphenmin \relax
+ \righthyphenmin0\languageparameter\s!righthyphenmin\relax
+ \lefthyphenmin \numexpr\lefthyphenmin +\hyphenminoffset\relax
+ \righthyphenmin\numexpr\righthyphenmin+\hyphenminoffset\relax}
+
+\def\docomplexlanguage% assumes that \currentlanguage is set
+ {\edef\currentdefaultlanguage{\defaultlanguage\currentlanguage}%
+ \setnormallanguage\currentlanguage\currentdefaultlanguage
+ \the\everylanguage
+ \enablelanguagespecifics[\currentlanguage]%
+ \sethyphenationvariables
+ \relax
+ % will be definable and move to core-spa !
+ \doifelse{\languageparameter\c!spacing}\v!broad\nonfrenchspacing\frenchspacing}
+
+\ifx\enablelanguagespecifics\undefined \def\enablelanguagespecifics[#1]{} \fi
+
+% The following may be a solution for the fact that one cannot
+% change catcodes of characters like : and ; inside an environment.
+
+\appendtoks
+ \enablelanguagespecifics[\currentlanguage]%
+\to \everystarttext
+
+\def\complexlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage \else
+ \setcurrentlanguage\currentmainlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \showmessage\m!linguals6{#1}%
+ \fi
+ \fi}
+
+\let\simplelanguage\normallanguage
+
+\definecomplexorsimple\language
+
+\def\mainlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage
+ \ifx\currentmainlanguage\askedlanguage
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \fi
+ \fi}
+
+%D \macros
+%D {defaultlanguage,languageparameter,specificlanguageparameter}
+
+\def\defaultlanguage#1%
+ {\ifcsname\??la#1\s!default\endcsname
+ \expandafter\defaultlanguage\csname\??la#1\s!default\endcsname
+ \else
+ #1%
+ \fi}
+
+\def\languageparameter#1%
+ {\ifcsname\??la\currentlanguage#1\endcsname
+ \csname\??la\currentlanguage#1\endcsname
+ \else\ifcsname\??la\currentlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la\currentlanguage\s!default\endcsname{#1}%
+ \else\ifcsname\??la\s!default#1\endcsname
+ \csname\??la\s!default#1\endcsname
+ \fi\fi\fi}
+
+\def\specificlanguageparameter#1#2%
+ {\ifcsname\??la#1#2\endcsname
+ \csname\??la#1#2\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la#1\s!default\endcsname{#2}%
+ \else\ifcsname\??la\s!default#2\endcsname
+ \csname\??la\s!default#2\endcsname
+ \fi\fi\fi}
+
+%D New (see nomarking and nolist):
+
+\def\splitsequence#1#2%
+ {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
+
+\def\splitsymbol#1%
+ {\splitsequence{#1}{\languageparameter\c!limittext}}
+
+%D Just like with subsentence boundary symbols, quotes
+%D placement depends on the current language, therefore we show
+%D the defaults here.
+%D
+%D \def\ShowLanguageValues [#1] [#2] #3 #4
+%D {\blank
+%D \startlinecorrection
+%D \vbox\bgroup
+%D \language[#1]%
+%D \setbox0=\hbox to \hsize{\hss\bf#2 subsentence symbol and quotes\hss}
+%D \dp0=0pt
+%D \box0
+%D \vskip.5em
+%D \hrule
+%D \vskip.5em
+%D \let\normalbar=|
+%D \hbox to \hsize
+%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
+%D \let|=\normalbar\strut|<||<|#3|>|#4|>|\hfil}
+%D \vskip.5em
+%D \hrule
+%D \egroup
+%D \stoplinecorrection
+%D \blank}
+%D
+%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
+%D \ShowLanguageValues [ca] [catalan] catalan ...
+%D \ShowLanguageValues [cs] [czech] tjechisch tex
+%D \ShowLanguageValues [cs] [slovak] slowaakse ...
+%D \ShowLanguageValues [da] [danish] deense ...
+%D \ShowLanguageValues [de] [german] duitse degelijkheid
+%D \ShowLanguageValues [en] [english] engelse humor
+%D \ShowLanguageValues [fi] [finnish] finse ...
+%D \ShowLanguageValues [fr] [french] franse slag
+%D \ShowLanguageValues [it] [italian] italiaanse ...
+%D \ShowLanguageValues [la] [latin] latijnse missen
+%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
+%D \ShowLanguageValues [nb] [bokmal] noorse zalm
+%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
+%D \ShowLanguageValues [pl] [polish] poolse vlag
+%D \ShowLanguageValues [pt] [portuguese] portugese ...
+%D \ShowLanguageValues [es] [spanish] spaans benauwd
+%D \ShowLanguageValues [sv] [swedish] zweedse ...
+%D \ShowLanguageValues [tr] [turkish] turks fruit
+
+%D We support a lot of languages. These are specified and
+%D loaded in separate files, according to their roots. Here
+%D we only take care of (postponed) setting of the current
+%D language.
+%D
+%D \unprotect
+%D \placetable{The germanic languages (\type{lang-ger})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!nl \NC dutch \NC germanic \NC\FR
+%D \NC \s!en \NC english \NC germanic \NC\MR
+%D \NC \s!de \NC german \NC germanic \NC\MR
+%D \NC \s!da \NC danish \NC germanic \NC\MR
+%D \NC \s!sv \NC swedish \NC germanic \NC\MR
+%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
+%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
+%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The italic languages (\type{lang-ita})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fr \NC french \NC italic \NC\FR
+%D \NC \s!ca \NC catalan \NC italic \NC\MR
+%D \NC \s!es \NC spanish \NC italic \NC\MR
+%D \NC \s!it \NC italian \NC italic \NC\MR
+%D \NC \s!la \NC latin \NC italic \NC\MR
+%D \NC \s!pt \NC portuguese \NC italic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The slavic languages (\type{lang-sla})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!pl \NC polish \NC slavic \NC\FR
+%D \NC \s!cs \NC czech \NC slavic \NC\MR
+%D \NC \s!sk \NC slavik \NC slavic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D \unprotect
+%D
+%D \placetable{The altaic languages (\type{lang-alt})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!tr \NC turkish \NC altaic \NC\SR
+%D \HL
+%D \stoptable
+%D
+%D \placetable{The uralic languages (\type{lang-ura})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fi \NC finnish \NC uralic \NC\SR
+%D \HL
+%D \stoptable
+%D \protect
+
+% \bgroup \normallanguage255 \patterns{} \egroup
+% \def\nopatterns{\normallanguage255 }
+
+\def\nopatterns{\normallanguage\minusone}
+
+%D \XETEX\ is \UNICODE:
+
+\ifnum\texengine=\xetexengine
+
\def\synchronizepatternswithfont{}
\def\doloadpatterns #1#2{\dodoloadpatterns{#1}{#2}\s!default\s!default}
- \def\setnormallanguage #1{\dosetnormallanguage{:\s!default:\s!default:}#1\empty}
+ \def\dosetnormallanguage #1{\dodosetnormallanguage{:\s!default:\s!default:}{#1}\empty}
\def\setuphyppatencoding {\pathypsettings}
-\endXETEX
+
+\fi
+
+%D We default to the language belonging to the interface. This
+%D is one of the few places outside the interface modules where
+%D \type{\startinterface} is used.
+
+%D We default to english:
+
+\setupcurrentlanguage[\s!en]
+
+\def\initializemainlanguage
+ {\mainlanguage[\currentlanguage]%
+ \showmessage\m!linguals9\currentlanguage}
\protect \endinput
diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv
index ce82b5a47..7cb945ef9 100644
--- a/tex/context/base/lang-ini.mkiv
+++ b/tex/context/base/lang-ini.mkiv
@@ -11,16 +11,133 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+%D This module needs a further cleanup (real split between ii/iv).
+
+%D This module implements the (for the moment still simple)
+%D multi||language support of \CONTEXT, which should not be
+%D confused with the multi||lingual interface. This support
+%D will be extended when needed.
+
+\writestatus{loading}{ConTeXt Language Macros / Initialization}
\registerctxluafile{lang-ini}{1.001}
-\let\synchronizepatterns \relax % todo: cleanup
-\let\synchronizepatternswithfont\relax % todo: cleanup
-\let\preloadallpatterns \relax % just for old times sake
-\let\preloadlanguages \relax % just for old times sake
+\unprotect
+
+% \def\testlanguage[#1]%
+% {\start
+% \language[#1]
+% \number\normallanguage/\the\lefthyphenmin/\the\righthyphenmin:
+% \input tufte
+% \hyphenatedword{effetestenofditwerkt}
+% \par
+% \stop}
+%
+% \testlanguage[de] \testlanguage[de-de] \testlanguage[de-at] \testlanguage[de-ch] \page
+% \testlanguage[en] \testlanguage[us] \testlanguage[en-us] \testlanguage[uk] \testlanguage[en-gb] \page
+
+\ifx\nonfrenchspacing\undefined \let\nonfrenchspacing\relax \fi
+\ifx\frenchspacing \undefined \let\frenchspacing \relax \fi
+
+%D When loading hyphenation patterns, \TEX\ assign a number to
+%D each loaded table, starting with~0. Switching to a specific
+%D table is done by assigning the relevant number to the
+%D predefined \COUNTER\ \type{\language}.
+
+%D We keep track of the last loaded patterns by means of a
+%D pseudo \COUNTER. This just one of those situations in which
+%D we don't want to spent a real one. Language zero has no
+%D patterns, first of all because I like to start numbering
+%D at one. It may come in handy for special purposes as well.
+
+\normallanguage\zerocount \def\loadedlanguage{1}
+
+%D \macros
+%D {currentlanguage, setupcurrentlanguage}
+%D
+%D Instead of numbers,we are going to use symbolic names for
+%D the languages. The current langage is saved in the macro
+%D \type {\currentlanguage}. The setup macro is mainly used
+%D for cosmetic purposes.
+%D
+%D \starttyping
+%D \dorecurse{3}
+%D {\language[nl]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode
+%D \language[en]
+%D \startmode[*en] english \stopmode
+%D \startmode[*nl] dutch \stopmode}
+%D \stoptyping
+
+\let\currentlanguage \empty
+\let\currentmainlanguage\empty
+
+\def\setupcurrentlanguage[#1]{\setcurrentlanguage\currentmainlanguage{#1}}
+
+\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
+ {\doifsomething{#1}
+ {\ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
+ \edef\currentmainlanguage{#1}%
+ \setsystemmode{\systemmodeprefix\currentmainlanguage}}%
+ \doifsomething{#2}
+ {\ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
+ \edef\currentlanguage{#2}%
+ \setsystemmode\currentlanguage}}
+
+%D The internal macros will be defined later.
+
+%D \macros
+%D {installlanguage}
+%D
+%D Hyphenation patterns can only be loaded when the format file
+%D is prepared. The next macro takes care of this loading. A
+%D language is specified with
+%D
+%D \showsetup{installlanguage}
+%D
+%D When \type {state} equals \type {start}, both patterns
+%D and additional hyphenation specifications are loaded. These
+%D files are seached for on the system path and are to be
+%D named:
+%D
+%D \starttyping
+%D \f!languageprefix-identifier.\f!patternsextension
+%D \f!languageprefix-identifier.\f!hyhensextension
+%D \stoptyping
+%D
+%D The \type{spacing} variable specifies how the spaces after
+%D punctuation has to be handled. English is by tradition more
+%D tolerant to inter||sentence spacing than other languages.
+%D
+%D This macro also defines \type {\identifier} as a shortcut
+%D switch to the language. Furthermore the command defined as
+%D being language specific, are executed. With
+%D \type {default} we can default to another language
+%D (patterns) at format generation time. This default language
+%D is overruled when the appropriate patterns are loaded (some
+%D implementations support run time addition of patterns to a
+%D preloaded format).
+
+\def\dodoinstalllanguage#1#2% #2 added
+ {\doifundefined{#1}{\setvalue{#1}{\complexlanguage[#2]}}%
+ \expanded{\noexpand\uppercase{\noexpand\edef\noexpand\ascii{#1}}}%
+ \doifundefined\ascii{\setvalue\ascii{\complexlanguage[#2]}}}
+
+%D \macros
+%D {preloadlanguages}
+%D
+%D We first try to load the files defined as file synonym
+%D for \type {lang-*.pat} and \type {lang-*.hyp}. After that we
+%D fall back on those files. The macro \type {\preloadpatterns}
+%D reports which patterns are loaded and what hyphenmin
+%D values are set.
-\def\mkdoloadpatterns#1#2%
+\let\installedlanguages\empty
+
+\def\doiflanguageelse#1{\doifdefinedelse{\??la#1\c!state}}
+
+\def\doloadpatterns#1#2%
{\ctxlua{languages.register(
"#1",
"#2",
@@ -28,43 +145,431 @@
"\truefilename{\f!languageprefix#2.\f!hyphensextension }")
}}
-\def\mkdoifpatternselse#1%
+% \def\doloadlanguagefiles#1%
+% {\doifelsevaluenothing{\??la#1\s!patterns}
+% {\doloadpatterns{#1}{#1}}
+% {\doloadpatterns{#1}{\getvalue{\??la#1\s!patterns}}}}
+
+\def\doloadlanguagefiles#1%
+ {\edef\languagesuffix{\specificlanguageparameter{#1}\s!patterns}%
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \else\ifx\languagesuffix\relax
+ \edef\languagesuffix{\defaultlanguage{#1}}%
+ \fi\fi
+ \ifx\languagesuffix\empty
+ \edef\languagesuffix{#1}%
+ \fi
+ \doloadpatterns{#1}\languagesuffix}
+
+\def\doinstalllanguage[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\doiflanguageelse{#1}
+ {\getparameters[\??la#1][#2]}
+ {\setvalue{\l!prefix!#1}{#1}%
+ \addtocommalist{#1}\installedlanguages
+ \dodoinstalllanguage{#1}{#1}%
+ \getparameters[\??la#1][\c!state=\v!start,#2]}%
+ \doloadlanguagefiles{#1}}
+ {\setvalue{\l!prefix!#1}{#2}%
+ \getparameters[\??la#1][\s!default=#2]%
+ \dodoinstalllanguage{#1}{#2}}}
+
+\def\reallanguagetag#1%
+ {\ifcsname\l!prefix!#1\endcsname\csname\l!prefix!#1\endcsname\else#1\fi}
+
+% ^^ \language[#1] gave unwanted side effect of loading language specifics
+
+\def\installlanguage
+ {\dodoubleargument\doinstalllanguage}
+
+%D When the second argument is a language identifier, a
+%D synonym is created. This feature is present because we
+%D used dutch mnemonics in the dutch version, but nowadays
+%D conform a standard.
+
+\def\doifpatternselse#1%
{\ctxlua{cs.testcase(languages.loadable("#1"))}}
-\def\mkloadlanguagefiles#1%
- {\doifelsevaluenothing{\??la#1\s!patterns}
- {\mkdoloadpatterns{#1}{#1}}
- {\mkdoloadpatterns{#1}{\getvalue{\??la#1\s!patterns}}}}
+%D \macros
+%D {setuplanguage}
+%D
+%D Quick and dirty, but useful:
+%D
+%D \showsetup{setuplanguage}
+%D
+%D Beware, this command can only be used when a language is installed.
-\def\mksetnormallanguage#1#2% current default / we can freeze the number here
- {\normallanguage=\ctxlua{tex.sprint(languages.enable({
- "\csname\??la#1\s!patterns\endcsname","#1",
- "\csname\??la#2\s!patterns\endcsname","#2",
- }))}\relax}
+\unprotected \def\setuplanguage
+ {\dodoubleempty\dosetuplanguage}
-% to be tested
-%
-% \def\mkdosetnormallanguage#1#2% current default
-% {\normallanguage=\ctxlua{tex.sprint(languages.enable({
-% "\csname\??la#1\s!patterns\endcsname","#1",
-% "\csname\??la#2\s!patterns\endcsname","#2",
-% }))}}%
-% \setxvalue{\??la\??la#1#2}{\number\normallanguage}}
-%
-% \def\mksetnormallanguage#1#2% current default / we can freeze the number here
-% {\normallanguage\executeifdefined{\??la\??la#1#2}{\mkdosetnormallanguage{#1}{#2}}}
+\def\dosetuplanguage[#1][#2]% handy patch for testing
+ {\ifsecondargument
+ \getparameters[\??la#1][#2]%
+ \doif{#1}\currentlanguage\docomplexlanguage
+ \else
+ \getparameters[\??la\currentlanguage][#1]%
+ \docomplexlanguage
+ \fi}
+\setuplanguage
+ [\s!default]
+ [\s!lefthyphenmin=2,
+ \s!righthyphenmin=2,
+ \s!patterns=,
+ \c!spacing=\v!packed,
+ \c!lefthyphen=,
+ \c!righthyphen=-,
+ \c!hyphen=-,
+ \c!midsentence=---,
+ \c!leftsentence=---,
+ \c!rightsentence=---,
+ \c!leftsubsentence=---,
+ \c!rightsubsentence=---,
+ \c!leftquote=\upperleftsinglesixquote,
+ \c!rightquote=\upperrightsingleninequote,
+ \c!leftquotation=\upperleftdoublesixquote,
+ \c!rightquotation=\upperrightdoubleninequote,
+ \c!leftspeech=\languageparameter\c!leftquotation,
+ \c!middlespeech=,
+ \c!rightspeech=\languageparameter\c!rightquotation,
+ \c!limittext=\unknown,
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day},
+ \c!text=Ag]
-\def\loadspellchecklist
- {\dodoubleempty\doloadspellchecklist}
+% rather new, split and per language
+
+\setuplanguage
+ [\s!default]
+ [\c!compoundhyphen=\compoundhyphen,
+ \c!leftcompoundhyphen=\compoundhyphen,
+ \c!rightcompoundhyphen=]
+
+%D The values \type {leftsentence} and \type
+%D {rightsentence} can be (and are) used to implement
+%D automatic subsentence boundary glyphs, like in {\fr
+%D |<|french guillemots|>|} or {\de |<|german guillemots|>|} or
+%D {\nl |<|dutch dashes|>|} like situations. Furthermore \type
+%D {leftquotation} and \type {leftquote} come into view
+%D \quotation {when we quote} or \quote {quote} something.
+
+%D \macros
+%D {currentdatespecification}
+%D
+%D Just to make things easy we can ask for the current date
+%D specification by saying:
+
+\def\currentdatespecification{\languageparameter\c!date}
+
+%D This command is not meant for users.
+
+%D Carefull reading of these macros shows that it's legal to
+%D say
+%D
+%D \starttyping
+%D \installlanguage [du] [de]
+%D \stoptyping
+
+%D \macros
+%D {language,mainlanguage}
+%D
+%D Switching to another language (actually another hyphenation
+%D pattern) is done with:
+%D
+%D \starttyping
+%D \language[identifier]
+%D \stoptyping
+%D
+%D or with \type{\identifier}. Just to be compatible with
+%D \PLAIN\ \TEX, we still support the original meaning, so
+%D
+%D \starttyping
+%D \language=1
+%D \stoptyping
+%D
+%D is a valid operation, where the relation between number
+%D and language depends on the order in installing languages.
+%D
+%D \showsetup{language}
+%D \showsetup{mainlanguage}
+%D
+%D Both commands take a predefined language identifier as
+%D argument. We can use \type{\mainlanguage[identifier]} for
+%D setting the (indeed) main language. This is the language
+%D used for translating labels like {\em figure} and {\em
+%D table}. The main language defaults to the current language.
+%D
+%D We take care of local as well as standardized language
+%D switching (fr and fa, de and du, but nl and nl).
+
+\def\dosetnormallanguage#1#2% current default
+ {\edef\askedlanguagepatterns{\specificlanguageparameter{#1}\s!patterns}%
+ \normallanguage=\ctxlua{tex.sprint(languages.enable({"\askedlanguagepatterns","#1","\askedlanguagepatterns","#2"}))}%
+ \ifproductionrun
+ \setxvalue{\??la\??la#1#2}{\number\normallanguage}%
+ \fi}
+
+\def\setnormallanguage#1#2% current default / we can freeze the number here
+ {\ifcsname\??la\??la#1#2\endcsname
+ \normallanguage\csname\??la\??la#1#2\endcsname % todo: we can set language at the lua end now
+ \else
+ \dosetnormallanguage{#1}{#2}%
+ \fi}
+
+\newtoks \everylanguage
+
+\def\disablelanguagespecifics
+ {\ignorecompoundcharacter}
+
+\def\sethyphenationvariables
+ {\lefthyphenmin 0\languageparameter\s!lefthyphenmin \relax
+ \righthyphenmin0\languageparameter\s!righthyphenmin\relax
+ \lefthyphenmin \numexpr\lefthyphenmin +\hyphenminoffset\relax
+ \righthyphenmin\numexpr\righthyphenmin+\hyphenminoffset\relax}
+
+\def\docomplexlanguage% assumes that \currentlanguage is set
+ {\edef\currentdefaultlanguage{\defaultlanguage\currentlanguage}%
+ \setnormallanguage\currentlanguage\currentdefaultlanguage
+ \the\everylanguage
+ \enablelanguagespecifics[\currentlanguage]%
+ \sethyphenationvariables
+ \relax
+ % will be definable and move to core-spa !
+ \doifelse{\languageparameter\c!spacing}\v!broad\nonfrenchspacing\frenchspacing}
+
+\ifx\enablelanguagespecifics\undefined \def\enablelanguagespecifics[#1]{} \fi
+
+% The following may be a solution for the fact that one cannot
+% change catcodes of characters like : and ; inside an environment.
+
+\appendtoks
+ \enablelanguagespecifics[\currentlanguage]%
+\to \everystarttext
+
+\def\complexlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage \else
+ \setcurrentlanguage\currentmainlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \showmessage\m!linguals6{#1}%
+ \fi
+ \fi}
+
+\let\simplelanguage\normallanguage
+
+\definecomplexorsimple\language
+
+\def\mainlanguage[#1]%
+ {\edef\askedlanguage{#1}%
+ \ifx\askedlanguage\empty \else
+ \ifcsname\l!prefix!\askedlanguage\endcsname
+ \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
+ \ifx\currentlanguage\askedlanguage
+ \ifx\currentmainlanguage\askedlanguage
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \else
+ \setcurrentlanguage\askedlanguage\askedlanguage
+ \docomplexlanguage
+ \fi
+ \fi
+ \fi}
+
+%D \macros
+%D {defaultlanguage,languageparameter,specificlanguageparameter}
+
+\def\defaultlanguage#1%
+ {\ifcsname\??la#1\s!default\endcsname
+ \expandafter\defaultlanguage\csname\??la#1\s!default\endcsname
+ \else
+ #1%
+ \fi}
+
+\def\languageparameter#1%
+ {\ifcsname\??la\currentlanguage#1\endcsname
+ \csname\??la\currentlanguage#1\endcsname
+ \else\ifcsname\??la\currentlanguage\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la\currentlanguage\s!default\endcsname{#1}%
+ \else\ifcsname\??la\s!default#1\endcsname
+ \csname\??la\s!default#1\endcsname
+ \fi\fi\fi}
+
+\def\specificlanguageparameter#1#2%
+ {\ifcsname\??la#1#2\endcsname
+ \csname\??la#1#2\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\specificlanguageparameter\csname\??la#1\s!default\endcsname{#2}%
+ \else\ifcsname\??la\s!default#2\endcsname
+ \csname\??la\s!default#2\endcsname
+ \fi\fi\fi}
+
+%D New (see nomarking and nolist):
+
+\def\splitsequence#1#2%
+ {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
+
+\def\splitsymbol#1%
+ {\splitsequence{#1}{\languageparameter\c!limittext}}
+
+%D Just like with subsentence boundary symbols, quotes
+%D placement depends on the current language, therefore we show
+%D the defaults here.
+%D
+%D \def\ShowLanguageValues [#1] [#2] #3 #4
+%D {\blank
+%D \startlinecorrection
+%D \vbox\bgroup
+%D \language[#1]%
+%D \setbox0=\hbox to \hsize{\hss\bf#2 subsentence symbol and quotes\hss}
+%D \dp0=0pt
+%D \box0
+%D \vskip.5em
+%D \hrule
+%D \vskip.5em
+%D \let\normalbar=|
+%D \hbox to \hsize
+%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
+%D \let|=\normalbar\strut|<||<|#3|>|#4|>|\hfil}
+%D \vskip.5em
+%D \hrule
+%D \egroup
+%D \stoplinecorrection
+%D \blank}
+%D
+%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
+%D \ShowLanguageValues [ca] [catalan] catalan ...
+%D \ShowLanguageValues [cs] [czech] tjechisch tex
+%D \ShowLanguageValues [cs] [slovak] slowaakse ...
+%D \ShowLanguageValues [da] [danish] deense ...
+%D \ShowLanguageValues [de] [german] duitse degelijkheid
+%D \ShowLanguageValues [en] [english] engelse humor
+%D \ShowLanguageValues [fi] [finnish] finse ...
+%D \ShowLanguageValues [fr] [french] franse slag
+%D \ShowLanguageValues [it] [italian] italiaanse ...
+%D \ShowLanguageValues [la] [latin] latijnse missen
+%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
+%D \ShowLanguageValues [nb] [bokmal] noorse zalm
+%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
+%D \ShowLanguageValues [pl] [polish] poolse vlag
+%D \ShowLanguageValues [pt] [portuguese] portugese ...
+%D \ShowLanguageValues [es] [spanish] spaans benauwd
+%D \ShowLanguageValues [sv] [swedish] zweedse ...
+%D \ShowLanguageValues [tr] [turkish] turks fruit
+
+%D We support a lot of languages. These are specified and
+%D loaded in separate files, according to their roots. Here
+%D we only take care of (postponed) setting of the current
+%D language.
+%D
+%D \unprotect
+%D \placetable{The germanic languages (\type{lang-ger})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!nl \NC dutch \NC germanic \NC\FR
+%D \NC \s!en \NC english \NC germanic \NC\MR
+%D \NC \s!de \NC german \NC germanic \NC\MR
+%D \NC \s!da \NC danish \NC germanic \NC\MR
+%D \NC \s!sv \NC swedish \NC germanic \NC\MR
+%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
+%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
+%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The italic languages (\type{lang-ita})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fr \NC french \NC italic \NC\FR
+%D \NC \s!ca \NC catalan \NC italic \NC\MR
+%D \NC \s!es \NC spanish \NC italic \NC\MR
+%D \NC \s!it \NC italian \NC italic \NC\MR
+%D \NC \s!la \NC latin \NC italic \NC\MR
+%D \NC \s!pt \NC portuguese \NC italic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D
+%D \unprotect
+%D \placetable{The slavic languages (\type{lang-sla})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!pl \NC polish \NC slavic \NC\FR
+%D \NC \s!cs \NC czech \NC slavic \NC\MR
+%D \NC \s!sk \NC slavik \NC slavic \NC\LR
+%D \HL
+%D \stoptable
+%D \protect
+%D \unprotect
+%D
+%D \placetable{The altaic languages (\type{lang-alt})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!tr \NC turkish \NC altaic \NC\SR
+%D \HL
+%D \stoptable
+%D
+%D \placetable{The uralic languages (\type{lang-ura})}
+%D \starttable[||||]
+%D \HL
+%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
+%D \HL
+%D \NC \s!fi \NC finnish \NC uralic \NC\SR
+%D \HL
+%D \stoptable
+%D \protect
+
+% \bgroup \normallanguage255 \patterns{} \egroup
+% \def\nopatterns{\normallanguage255 }
+
+\def\nopatterns{\normallanguage\minusone}
+
+%D We default to the language belonging to the interface. This
+%D is one of the few places outside the interface modules where
+%D \type{\startinterface} is used.
+
+%D We default to english:
+
+\setupcurrentlanguage[\s!en]
+
+\def\initializemainlanguage
+ {\mainlanguage[\currentlanguage]%
+ \showmessage\m!linguals9\currentlanguage}
+
+%D Might be in use:
+
+\let\preloadallpatterns\relax % just for old times sake
+\let\preloadlanguages \relax % just for old times sake
+
+%D This might bexcome a seperate file:
% mkiv only -- todo: internationalize command names
% \loadspellchecklist[en][words-en.txt]
+% \loadspellchecklist[us][words-en.txt]
% \loadspellchecklist[nl][words-nl.txt]
% \setupspellchecking[state=start]
-\def\loadspellchecklist[#1][#2]%
+\def\loadspellchecklist
+ {\dodoubleempty\doloadspellchecklist}
+
+\def\doloadspellchecklist[#1][#2]%
{\ctxlua{languages.words.load("#1","#2")}}
\def\setupspellchecking
diff --git a/tex/context/base/lang-ini.tex b/tex/context/base/lang-ini.tex
deleted file mode 100644
index 17393da33..000000000
--- a/tex/context/base/lang-ini.tex
+++ /dev/null
@@ -1,692 +0,0 @@
-%D \module
-%D [ file=lang-ini,
-%D version=1996.01.25,
-%D title=\CONTEXT\ Language Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module needs a further cleanup (real split between ii/iv).
-
-%D This module implements the (for the moment still simple)
-%D multi||language support of \CONTEXT, which should not be
-%D confused with the multi||lingual interface. This support
-%D will be extended when needed.
-
-\writestatus{loading}{Context Language Macros / Initialization}
-
-\startmessages dutch library: linguals
- title: taal
- 1: afbreekpatronen -- voor -- geladen (n=--,e=--,m=--)
- 2: geen afbreekpatronen -- voor -- (n=--,e=--,m=--) (--,--)
- 3: afbreekdefinities -- voor -- geladen (n=--,e=--,m=--)
- 4: geen afbreekdefinities -- voor -- (n=--,e=--,m=--)
- 5: afbreekpatronen voor -- niet geladen
- 6: taal -- is niet gedefinieerd
- 7: taal specifieke opties [--] introduceren een skip van --
- 8: taal specifieke opties [--] naadloos toegevoegd
- 9: taal -- is actief
- 10: patronen --geladen
-\stopmessages
-
-\startmessages english library: linguals
- title: language
- 1: patterns -- for -- loaded (n=--,e=--,m=--)
- 2: no patterns -- for -- (n=--,e=--,m=--) (--,--)
- 3: hyphenations -- for -- loaded (n=--,e=--,m=--)
- 4: no hyphenations -- for -- (n=--,e=--,m=--)
- 5: patterns for -- not loaded
- 6: language -- is undefined
- 7: language specific options [--] introduce a -- skip
- 8: language specific options [--] seamless appended
- 9: language -- is active
- 10: patterns --loaded
-\stopmessages
-
-\startmessages german library: linguals
- title: Sprache
- 1: Trennmuster -- fuer -- geladen (n=--,e=--,m=--)
- 2: Keine Trennmuster -- fuer -- (n=--,e=--,m=--) (--,--)
- 3: Trenndefinitionen -- fuer -- geladen (n=--,e=--,m=--)
- 4: Keine Trenndefinitionen -- fuer -- (n=--,e=--,m=--)
- 5: Trennmuster fuer -- nicht geladen
- 6: Sprache -- ist undefiniert
- 7: Sprachenspezifische Option [--] fuegt eine Luecke von -- ein
- 8: Sprachenspezifische Option [--] nahtlos hinzugefuegt
- 9: Sprache -- ist aktiv
- 10: Trennmuster --geladen
-\stopmessages
-
-% TOM: 9 and 10
-
-\startmessages czech library: linguals
- title: jazyky
- 1: vzory -- pro -- nacteny (n=--,e=--,m=--)
- 2: zadne vzory -- pro -- (n=--,e=--,m=--) (--,--)
- 3: deleni slov -- pro -- nacteno (n=--,e=--,m=--)
- 4: zadne deleni slov -- pro -- (n=--,e=--,m=--)
- 5: vzory pro -- nenacteny
- 6: jazyk -- neni definovan
- 7: specificke volby jazyka [--] zavadeji -- (zavlecenou) mezeru
- 8: specificke volby jazyka [--] bez mezer pripojeny
- 9: language -- is active
- 10: vzory --nacteny
-\stopmessages
-
-\startmessages italian library: linguals
- title: lingua
- 1: schemi -- per -- caricati (n=--,e=--,m=--)
- 2: niente schemi -- per -- (n=--,e=--,m=--) (--,--)
- 3: sillabazione -- per -- caricata (n=--,e=--,m=--)
- 4: niente sillabazione -- per -- (n=--,e=--,m=--)
- 5: schemi per -- non caricati
- 6: lingua -- non definita
- 7: opzioni specifiche per la lingua [--] introducono un salto --
- 8: opzioni specifiche per la lingua [--] aggiunte trasparentemente
- 9: lingua -- attiva
- 10: schemi -- caricati
-\stopmessages
-
-\startmessages norwegian library: linguals
- title: sprøk
- 1: orddelingsmønster -- for -- er lest inn (n=--,e=--,m=--)
- 2: ingen orddelingsmønster -- for -- (n=--,e=--,m=--) (--,--)
- 3: orddelingsdefinisjon -- for -- er lest inn (n=--,e=--,m=--)
- 4: ingen orddelingsdefinisjon -- for -- (n=--,e=--,m=--)
- 5: orddelingsmønster for -- er ikke lest inn
- 6: spràk -- er udefinert
- 7: spràk spesifikk opsjon [--] introduserer et -- hopp
- 8: spràk spesifikk opsjon [--] problemfritt tilføyd
- 9: spràk -- er aktivt
- 10: orddelingsmønster -- er lest inn
-\stopmessages
-
-\startmessages romanian library: linguals
- title: limbi
- 1: sablonul -- pentru -- s-a incarcat (n=--,e=--,m=--)
- 2: nu exista sabloane -- pentru -- (n=--,e=--,m=--) (--,--)
- 3: despartirea in silabe -- pentru -- s-a incarcat (n=--,e=--,m=--)
- 4: nu exista despartire in silabe -- pentru -- (n=--,e=--,m=--)
- 5: sabloanele pentru -- nu sunt incarcate
- 6: limba -- nu este definita
- 7: optiunile specifice ale limbii [--] introduc un spatiu --
- 8: optiunile specifice ale limbii [--] adaugate
- 9: limba -- este activa
- 10: sabloanele -- incarcate
-\stopmessages
-
-\startmessages french library: linguals
- title: langue
- 1: les motifs -- pour -- sont chargés (n=--,e=--,m=--)
- 2: pas de motifs -- pour -- (n=--,e=--,m=--) (--,--)
- 3: hyphenations -- pour -- chargés (n=--,e=--,m=--)
- 4: pas d'hyphenations -- pour -- (n=--,e=--,m=--)
- 5: les motifs pour -- ne sont pas chargés
- 6: langue -- non définie
- 7: les options spécifiques de langue [--] introduisent un -- saut
- 8: les options spécifiques de langue [--] sont ajoutés en douceur
- 9: la langue -- est active
- 10: motifs -- chargés
-\stopmessages
-
-\unprotect
-
-\ifx\nonfrenchspacing\undefined \let\nonfrenchspacing\relax \fi
-\ifx\frenchspacing \undefined \let\frenchspacing \relax \fi
-
-%D When loading hyphenation patterns, \TEX\ assign a number to
-%D each loaded table, starting with~0. Switching to a specific
-%D table is done by assigning the relevant number to the
-%D predefined \COUNTER\ \type{\language}. Unfortunately the
-%D name of this command suits very well the name of the
-%D language switching command we are to define, so let's save
-%D this primitive under another name:
-
-\let\normallanguage\language
-
-%D We keep track of the last loaded patterns by means of a
-%D pseudo \COUNTER. This just one of those situations in which
-%D we don't want to spent a real one. Language zero has no
-%D patterns, first of all because I like to start numbering
-%D at one. It may come in handy for special purposes as well.
-
-\normallanguage\zerocount \def\loadedlanguage{1}
-
-%D \macros
-%D {currentlanguage, setupcurrentlanguage}
-%D
-%D Instead of numbers,we are going to use symbolic names for
-%D the languages. The current langage is saved in the macro
-%D \type {\currentlanguage}. The setup macro is mainly used
-%D for cosmetic purposes.
-%D
-%D \starttyping
-%D \dorecurse{3}
-%D {\language[nl]
-%D \startmode[*en] english \stopmode
-%D \startmode[*nl] dutch \stopmode
-%D \language[en]
-%D \startmode[*en] english \stopmode
-%D \startmode[*nl] dutch \stopmode}
-%D \stoptyping
-
-\let\currentlanguage \empty
-\let\currentmainlanguage\empty
-
-\def\setupcurrentlanguage[#1]{\setcurrentlanguage\currentmainlanguage{#1}}
-
-\def\setcurrentlanguage#1#2% sets modes: **id (currentmain) *id (current)
- {\doifsomething{#1}
- {\ifx\currentmainlanguage\empty\else\resetsystemmode{\systemmodeprefix\currentmainlanguage}\fi
- \edef\currentmainlanguage{#1}%
- \setsystemmode{\systemmodeprefix\currentmainlanguage}}%
- \doifsomething{#2}
- {\ifx\currentlanguage\empty\else\resetsystemmode\currentlanguage\fi
- \edef\currentlanguage{#2}%
- \setsystemmode\currentlanguage}}
-
-%D The internal macros will be defined later.
-
-%D \macros
-%D {installlanguage}
-%D
-%D Hyphenation patterns can only be loaded when the format file
-%D is prepared. The next macro takes care of this loading. A
-%D language is specified with
-%D
-%D \showsetup{installlanguage}
-%D
-%D When \type {state} equals \type {start}, both patterns
-%D and additional hyphenation specifications are loaded. These
-%D files are seached for on the system path and are to be
-%D named:
-%D
-%D \starttyping
-%D \f!languageprefix-identifier.\f!patternsextension
-%D \f!languageprefix-identifier.\f!hyhensextension
-%D \stoptyping
-%D
-%D The \type{spacing} variable specifies how the spaces after
-%D punctuation has to be handled. English is by tradition more
-%D tolerant to inter||sentence spacing than other languages.
-%D
-%D This macro also defines \type {\identifier} as a shortcut
-%D switch to the language. Furthermore the command defined as
-%D being language specific, are executed. With
-%D \type {default} we can default to another language
-%D (patterns) at format generation time. This default language
-%D is overruled when the appropriate patterns are loaded (some
-%D implementations support run time addition of patterns to a
-%D preloaded format).
-
-\def\dodoinstalllanguage#1#2% #2 added
- {\doifundefined{#1}{\setvalue{#1}{\complexlanguage[#2]}}%
- \expanded{\noexpand\uppercase{\noexpand\edef\noexpand\ascii{#1}}}%
- \doifundefined\ascii{\setvalue\ascii{\complexlanguage[#2]}}}
-
-%D \macros
-%D {preloadlanguages}
-%D
-%D We first try to load the files defined as file synonym
-%D for \type {lang-*.pat} and \type {lang-*.hyp}. After that we
-%D fall back on those files. The macro \type {\preloadpatterns}
-%D reports which patterns are loaded and what hyphenmin
-%D values are set.
-
-\let\installedlanguages\empty
-
-\def\doiflanguageelse#1{\doifdefinedelse{\??la#1\c!state}}
-
-\ifx\mkloadlanguagefiles\undefined \let\mkloadlanguagefiles\gobbleoneargument \fi
-
-\def\doinstalllanguage[#1][#2]% some day we will make one for mkii and mkiv
- {\doifassignmentelse{#2}
- {\doiflanguageelse{#1}
- {\getparameters[\??la#1][#2]}
- {\setvalue{\l!prefix!#1}{#1}%
- \addtocommalist{#1}\installedlanguages
- \dodoinstalllanguage{#1}{#1}%
- \getparameters
- [\??la#1]
- [\c!state=\v!stop,
- \c!default=,
- \s!patterns=,
- \s!mapping=,
- \s!encoding=,
- \s!lefthyphenmin=\defaultlanguageparameter\s!lefthyphenmin,
- \s!righthyphenmin=\defaultlanguageparameter\s!righthyphenmin,
- #2]}%
- \doifvalue{\??la#1\c!default}{#1}{\letvalue{\??la#1\c!default}\empty}%
- % loop in deo: \doifvalue{\??la#1\s!patterns}{#1}{\letvalue{\??la#1\c!default}\empty}%
- \mkloadlanguagefiles{#1}}
- {\setvalue{\l!prefix!#1}{#2}%
- \dodoinstalllanguage{#1}{#2}}}
-
-\def\reallanguagetag#1%
- {\ifcsname\l!prefix!#1\endcsname
- %\expandafter\reallanguagetag\csname\l!prefix!#1\endcsname % evt undefined en dan wel
- \csname\l!prefix!#1\endcsname
- \else
- #1%
- \fi}
-
-% ^^ \language[#1] gave unwanted side effect of loading language specifics
-
-\def\installlanguage
- {\dodoubleargument\doinstalllanguage}
-
-%D When the second argument is a language identifier, a
-%D synonym is created. This feature is present because we
-%D used dutch mnemonics in the dutch version, but nowadays
-%D conform a standard.
-
-\let \patternencoding \s!default
-\let \patternmapping \s!default
-
-\ifx\mkloadpatterns \undefined \let\mkloadpatterns \gobbletwoarguments \fi
-\ifx\mkdoifpatternselse\undefined \let\mkdoifpatternselse\gobbletwoarguments \fi
-
-\def\doloadpatterns {\mkdoloadpatterns}
-\def\doifpatternselse{\mkdoifpatternselse}
-
-%D \macros
-%D {setuplanguage}
-%D
-%D Quick and dirty, but useful:
-%D
-%D \showsetup{setuplanguage}
-%D
-%D Beware, this command can only be used when a language is installed.
-
-\unprotected \def\setuplanguage
- {\dodoubleempty\dosetuplanguage}
-
-\def\dosetuplanguage[#1][#2]% handy patch for testing
- {\ifsecondargument
- \getparameters[\??la#1][#2]%
- \doif{#1}\currentlanguage\docomplexlanguage
- \else
- \getparameters[\??la\currentlanguage][#1]%
- \docomplexlanguage
- \fi}
-
-\setuplanguage
- [\s!default]
- [\s!lefthyphenmin=2,
- \s!righthyphenmin=2,
- \c!spacing=\v!packed,
- \c!lefthyphen=,
- \c!righthyphen=-,
- \c!hyphen=-,
- \c!midsentence=---,
- \c!leftsentence=---,
- \c!rightsentence=---,
- \c!leftsubsentence=---,
- \c!rightsubsentence=---,
- \c!leftquote=\upperleftsinglesixquote,
- \c!rightquote=\upperrightsingleninequote,
- \c!leftquotation=\upperleftdoublesixquote,
- \c!rightquotation=\upperrightdoubleninequote,
- \c!leftspeech=\languageparameter\c!leftquotation,
- \c!middlespeech=,
- \c!rightspeech=\languageparameter\c!rightquotation,
- \c!limittext=\unknown,
- \c!date={\v!year,\ ,\v!month,\ ,\v!day},
- \c!text=Ag]
-
-% rather new, split and per language
-
-\setuplanguage
- [\s!default]
- [\c!compoundhyphen=\compoundhyphen,
- \c!leftcompoundhyphen=\compoundhyphen,
- \c!rightcompoundhyphen=]
-
-%D The values \type {leftsentence} and \type
-%D {rightsentence} can be (and are) used to implement
-%D automatic subsentence boundary glyphs, like in {\fr
-%D |<|french guillemots|>|} or {\de |<|german guillemots|>|} or
-%D {\nl |<|dutch dashes|>|} like situations. Furthermore \type
-%D {leftquotation} and \type {leftquote} come into view
-%D \quotation {when we quote} or \quote {quote} something.
-
-%D \macros
-%D {currentdatespecification}
-%D
-%D Just to make things easy we can ask for the current date
-%D specification by saying:
-
-\def\currentdatespecification{\languageparameter\c!date}
-
-%D This command is not meant for users.
-
-%D Carefull reading of these macros shows that it's legal to
-%D say
-%D
-%D \starttyping
-%D \installlanguage [du] [de]
-%D \stoptyping
-
-%D \macros
-%D {language,mainlanguage}
-%D
-%D Switching to another language (actually another hyphenation
-%D pattern) is done with:
-%D
-%D \starttyping
-%D \language[identifier]
-%D \stoptyping
-%D
-%D or with \type{\identifier}. Just to be compatible with
-%D \PLAIN\ \TEX, we still support the original meaning, so
-%D
-%D \starttyping
-%D \language=1
-%D \stoptyping
-%D
-%D is a valid operation, where the relation between number
-%D and language depends on the order in installing languages.
-%D
-%D \showsetup{language}
-%D \showsetup{mainlanguage}
-%D
-%D Both commands take a predefined language identifier as
-%D argument. We can use \type{\mainlanguage[identifier]} for
-%D setting the (indeed) main language. This is the language
-%D used for translating labels like {\em figure} and {\em
-%D table}. The main language defaults to the current language.
-%D
-%D We take care of local as well as standardized language
-%D switching (fr and fa, de and du, but nl and nl).
-
-\ifx\synchronizepatterns \undefined \let\synchronizepatterns\relax \fi
-\ifx\synchronizepatternswithfont\undefined \def\synchronizepatternswithfont{\synchronizepatterns} \fi
-
-\ifx\mksetnormallanguage\undefined \let\mksetnormallanguage\gobbletwoarguments \fi
-
-\def\setnormallanguage{\mksetnormallanguage}
-
-\newevery \everylanguage \relax
-\newevery \everyresetlanguagespecifics \relax
-
-\def\disablelanguagespecifics
- {\ignorecompoundcharacter}
-
-\def\sethyphenationvariables
- {\lefthyphenmin 0\languageparameter\s!lefthyphenmin \relax
- \righthyphenmin0\languageparameter\s!righthyphenmin\relax
- \lefthyphenmin \numexpr\lefthyphenmin +\hyphenminoffset\relax
- \righthyphenmin\numexpr\righthyphenmin+\hyphenminoffset\relax}
-
-\def\docomplexlanguage% assumes that \currentlanguage is set
- {\edef\currentdefaultlanguage{\defaultlanguage\currentlanguage}%
- \mksetnormallanguage\currentlanguage\currentdefaultlanguage
- \the\everylanguage
- \enablelanguagespecifics[\currentlanguage]%
- \sethyphenationvariables
- \relax
- % will be definable and move to core-spa !
- \doifelse{\languageparameter\c!spacing}\v!broad
- \nonfrenchspacing\frenchspacing}
-
-\ifx\enablelanguagespecifics\undefined \def\enablelanguagespecifics[#1]{} \fi
-
-% The following may be a solution for the fact that one cannot
-% change catcodes of characters like : and ; inside an environment.
-
-\appendtoks
- \enablelanguagespecifics[\currentlanguage]%
-\to \everystarttext
-
-\def\complexlanguage[#1]%
- {\edef\askedlanguage{#1}%
- \ifx\askedlanguage\empty \else
- \ifcsname\l!prefix!\askedlanguage\endcsname
- \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
- \ifx\currentlanguage\askedlanguage \else
- \setcurrentlanguage\currentmainlanguage\askedlanguage
- \docomplexlanguage
- \fi
- \else
- \showmessage\m!linguals6{#1}%
- \fi
- \fi}
-
-\let\simplelanguage\normallanguage
-
-\definecomplexorsimple\language
-
-% \def\mainlanguage[#1]%
-% {\edef\askedlanguage{#1}%
-% \ifx\askedlanguage\empty \else
-% \ifcsname\l!prefix!\askedlanguage\endcsname
-% \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
-% \ifx\currentmainlanguage\askedlanguage \else
-% \setcurrentlanguage\askedlanguage\askedlanguage
-% \docomplexlanguage
-% \fi
-% \fi
-% \fi}
-
-\def\mainlanguage[#1]%
- {\edef\askedlanguage{#1}%
- \ifx\askedlanguage\empty \else
- \ifcsname\l!prefix!\askedlanguage\endcsname
- \edef\askedlanguage{\csname\l!prefix!\askedlanguage\endcsname}%
- \ifx\currentlanguage\askedlanguage
- \ifx\currentmainlanguage\askedlanguage
- \else
- \setcurrentlanguage\askedlanguage\askedlanguage
- \docomplexlanguage
- \fi
- \else
- \setcurrentlanguage\askedlanguage\askedlanguage
- \docomplexlanguage
- \fi
- \fi
- \fi}
-
-%D \macros
-%D {defaultlanguage,languagedefault}
-%D
-%D The macro \type {\defaultlanguage{id}} expands into the
-%D default language, when defined, while \type
-%D {\languagedefault{id}\c!parameter} returns the default's
-%D parameter.
-
-\def\defaultlanguage#1%
- {\@EA\ifx\csname\??la#1\c!default\endcsname\empty
- #1%
- \else
- \@EA\defaultlanguage\csname\??la#1\c!default\endcsname
- \fi}
-
-\def\languagedefault#1#2%
- {\csname\??la\defaultlanguage{#1}#2\endcsname}
-
-\def\languageparameter % @EA = speedup
- {\@EA\dolanguageparameter\@EA{\defaultlanguage\currentlanguage}}
-
-\def\specificlanguageparameter#1% @EA = speedup
- {\@EA\dospecificlanguageparameter\@EA{\defaultlanguage{#1}}{#1}}
-
-\def\xxlanguageparameter#1% @EA = speedup
- {\@EA\dolanguageparameter\@EA{\defaultlanguage{#1}}}
-
-\def\defaultlanguageparameter#1%
- {\csname\??la\s!default#1\endcsname}
-
-\def\dolanguageparameter#1#2%
- {\csname\??la
- \ifcsname\??la\currentlanguage#2\endcsname
- \currentlanguage
- \else\ifcsname\??la#1#2\endcsname
- \@EA\ifx\csname\??la#1#2\endcsname\empty\s!default\else#1\fi
- \else
- \s!default
- \fi\fi
- #2\endcsname}
-
-\def\dospecificlanguageparameter#1#2#3%
- {\csname\??la
- \ifcsname\??la#2#3\endcsname
- \@EA\ifx\csname\??la#2#3\endcsname\empty\s!default\else#2\fi
- \else\ifcsname\??la#1#3\endcsname
- \@EA\ifx\csname\??la#1#3\endcsname\empty\s!default\else#1\fi
- \else
- \s!default
- \fi\fi
- #3\endcsname}
-
-%D New (see nomarking and nolist):
-
-\def\splitsequence#1#2%
- {\doifelse{#1}\v!no{#2}{\doifelse{#1}\v!yes{\languageparameter\c!limittext}{#1}}}
-
-\def\splitsymbol#1%
- {\splitsequence{#1}{\languageparameter\c!limittext}}
-
-%D Just like with subsentence boundary symbols, quotes
-%D placement depends on the current language, therefore we show
-%D the defaults here.
-%D
-%D \def\ShowLanguageValues [#1] [#2] #3 #4
-%D {\blank
-%D \startlinecorrection
-%D \vbox\bgroup
-%D \language[#1]%
-%D \setbox0=\hbox to \hsize{\hss\bf#2 subsentence symbol and quotes\hss}
-%D \dp0=0pt
-%D \box0
-%D \vskip.5em
-%D \hrule
-%D \vskip.5em
-%D \let\normalbar=|
-%D \hbox to \hsize
-%D {\hfil\quotation{#3 #4}\hfil\quote{#2}\hfil
-%D \let|=\normalbar\strut|<||<|#3|>|#4|>|\hfil}
-%D \vskip.5em
-%D \hrule
-%D \egroup
-%D \stoplinecorrection
-%D \blank}
-%D
-%D \ShowLanguageValues [af] [afrikaans] afrikaanse ...
-%D \ShowLanguageValues [ca] [catalan] catalan ...
-%D \ShowLanguageValues [cs] [czech] tjechisch tex
-%D \ShowLanguageValues [cs] [slovak] slowaakse ...
-%D \ShowLanguageValues [da] [danish] deense ...
-%D \ShowLanguageValues [de] [german] duitse degelijkheid
-%D \ShowLanguageValues [en] [english] engelse humor
-%D \ShowLanguageValues [fi] [finnish] finse ...
-%D \ShowLanguageValues [fr] [french] franse slag
-%D \ShowLanguageValues [it] [italian] italiaanse ...
-%D \ShowLanguageValues [la] [latin] latijnse missen
-%D \ShowLanguageValues [nl] [dutch] nederlandse zuinigheid
-%D \ShowLanguageValues [nb] [bokmal] noorse zalm
-%D \ShowLanguageValues [nn] [nnynorsk] noorse zalm
-%D \ShowLanguageValues [pl] [polish] poolse vlag
-%D \ShowLanguageValues [pt] [portuguese] portugese ...
-%D \ShowLanguageValues [es] [spanish] spaans benauwd
-%D \ShowLanguageValues [sv] [swedish] zweedse ...
-%D \ShowLanguageValues [tr] [turkish] turks fruit
-
-%D We support a lot of languages. These are specified and
-%D loaded in separate files, according to their roots. Here
-%D we only take care of (postponed) setting of the current
-%D language.
-%D
-%D \unprotect
-%D \placetable{The germanic languages (\type{lang-ger})}
-%D \starttable[||||]
-%D \HL
-%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
-%D \HL
-%D \NC \s!nl \NC dutch \NC germanic \NC\FR
-%D \NC \s!en \NC english \NC germanic \NC\MR
-%D \NC \s!de \NC german \NC germanic \NC\MR
-%D \NC \s!da \NC danish \NC germanic \NC\MR
-%D \NC \s!sv \NC swedish \NC germanic \NC\MR
-%D \NC \s!af \NC afrikaans \NC germanic \NC\MR
-%D \NC \s!nb \NC bokmal \NC germanic \NC\LR
-%D \NC \s!nn \NC nynorsk \NC germanic \NC\LR
-%D \HL
-%D \stoptable
-%D \protect
-%D
-%D \unprotect
-%D \placetable{The italic languages (\type{lang-ita})}
-%D \starttable[||||]
-%D \HL
-%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
-%D \HL
-%D \NC \s!fr \NC french \NC italic \NC\FR
-%D \NC \s!ca \NC catalan \NC italic \NC\MR
-%D \NC \s!es \NC spanish \NC italic \NC\MR
-%D \NC \s!it \NC italian \NC italic \NC\MR
-%D \NC \s!la \NC latin \NC italic \NC\MR
-%D \NC \s!pt \NC portuguese \NC italic \NC\LR
-%D \HL
-%D \stoptable
-%D \protect
-%D
-%D \unprotect
-%D \placetable{The slavic languages (\type{lang-sla})}
-%D \starttable[||||]
-%D \HL
-%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
-%D \HL
-%D \NC \s!pl \NC polish \NC slavic \NC\FR
-%D \NC \s!cs \NC czech \NC slavic \NC\MR
-%D \NC \s!sk \NC slavik \NC slavic \NC\LR
-%D \HL
-%D \stoptable
-%D \protect
-%D \unprotect
-%D
-%D \placetable{The altaic languages (\type{lang-alt})}
-%D \starttable[||||]
-%D \HL
-%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
-%D \HL
-%D \NC \s!tr \NC turkish \NC altaic \NC\SR
-%D \HL
-%D \stoptable
-%D
-%D \placetable{The uralic languages (\type{lang-ura})}
-%D \starttable[||||]
-%D \HL
-%D \NC \bf mnemonic \NC \bf language \NC \bf group \NC\SR
-%D \HL
-%D \NC \s!fi \NC finnish \NC uralic \NC\SR
-%D \HL
-%D \stoptable
-%D \protect
-
-% \bgroup \normallanguage255 \patterns{} \egroup
-% \def\nopatterns{\normallanguage255 }
-
-\def\nopatterns{\normallanguage\minusone}
-
-%D Mark plugin:
-
-\loadmarkfile{lang-ini} % not yet
-
-%D We default to the language belonging to the interface. This
-%D is one of the few places outside the interface modules where
-%D \type{\startinterface} is used.
-
-%D We default to english:
-
-\setupcurrentlanguage[\s!en]
-
-\appendtoks\mainlanguage[\currentlanguage]\to\everyjob
-
-\appendtoks\showmessage\m!linguals9\currentlanguage\to\everyjob
-
-\protect \endinput
diff --git a/tex/context/base/lang-ita.tex b/tex/context/base/lang-ita.tex
index 93a169112..ae3b7a514 100644
--- a/tex/context/base/lang-ita.tex
+++ b/tex/context/base/lang-ita.tex
@@ -13,7 +13,7 @@
% Todo: replace \'.. by \namedglyph
-\writestatus{loading}{Italic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Italic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -47,7 +47,8 @@
\c!leftquotation=\leftguillemot,
\c!rightquotation=\rightguillemot,
\c!date={\v!day+,\v!space,\v!month,\v!space,\v!year},
- \c!state=\v!stop]
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
\installlanguage
[\s!es]
@@ -60,8 +61,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
\installlanguage [sp] [\s!es] % old times context
@@ -76,8 +76,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
% Note GB left|/|right (sub)sentences are for \quote {incisi}.
@@ -96,7 +95,8 @@
\c!middlespeech=\leftguillemot,
\c!rightspeech=\rightguillemot,
\c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
\installlanguage % the same as italian
[\s!la]
@@ -109,8 +109,7 @@
\c!rightquote=\lowerrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\lowerrightdoubleninequote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
\installlanguage
[\s!pt]
@@ -124,7 +123,8 @@
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!year,\ ,\v!month,\ ,\v!day},
- \c!state=\v!stop]
+ \s!mapping={texnansi,ec},
+ \s!encoding={texnansi,ec}]
\installlanguage
[\s!ro]
@@ -137,8 +137,7 @@
\c!rightquote=\rightguillemot,
\c!leftquotation=\lowerrightdoubleninequote,
\c!rightquotation=\upperleftdoublesixquote,
- \c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
%D For compatibility reasons we also define:
@@ -227,8 +226,8 @@
\setupheadtext [\s!ro] [\v!units=Unit\u{a}\c{t}i]
\setuplabeltext [\s!fr] [\v!table=Tableau ]
-\setuplabeltext [\s!es] [\v!table=Tablas ]
-\setuplabeltext [\s!ca] [\v!table=Taules ]
+\setuplabeltext [\s!es] [\v!table=Tabla ]
+\setuplabeltext [\s!ca] [\v!table=Taula ]
\setuplabeltext [\s!it] [\v!table=Tabella ]
\setuplabeltext [\s!la] [\v!table=Tabula ]
\setuplabeltext [\s!pt] [\v!table=Tabela ]
@@ -259,48 +258,48 @@
\setuplabeltext [\s!ro] [\v!graphic=Graficul ]
\setuplabeltext [\s!fr] [\v!chapter=]
-\setuplabeltext [\s!es] [\v!chapter=]
-\setuplabeltext [\s!ca] [\v!chapter=]
+\setuplabeltext [\s!es] [\v!chapter=Cap\'\itulo]
+\setuplabeltext [\s!ca] [\v!chapter=Cap\'\itol]
\setuplabeltext [\s!it] [\v!chapter=]
\setuplabeltext [\s!la] [\v!chapter=]
\setuplabeltext [\s!pt] [\v!chapter=]
\setuplabeltext [\s!ro] [\v!chapter=]
\setuplabeltext [\s!fr] [\v!section=]
-\setuplabeltext [\s!es] [\v!section=]
-\setuplabeltext [\s!ca] [\v!section=]
+\setuplabeltext [\s!es] [\v!section=Secci\'on]
+\setuplabeltext [\s!ca] [\v!section=Secci\'o]
\setuplabeltext [\s!it] [\v!section=]
\setuplabeltext [\s!la] [\v!section=]
\setuplabeltext [\s!pt] [\v!section=]
\setuplabeltext [\s!ro] [\v!section=]
\setuplabeltext [\s!fr] [\v!subsection=]
-\setuplabeltext [\s!es] [\v!subsection=]
-\setuplabeltext [\s!ca] [\v!subsection=]
+\setuplabeltext [\s!es] [\v!subsection=Subsecci\'on]
+\setuplabeltext [\s!ca] [\v!subsection=Subsecci\'o]
\setuplabeltext [\s!it] [\v!subsection=]
\setuplabeltext [\s!la] [\v!subsection=]
\setuplabeltext [\s!pt] [\v!subsection=]
\setuplabeltext [\s!ro] [\v!subsection=]
\setuplabeltext [\s!fr] [\v!subsubsection=]
-\setuplabeltext [\s!es] [\v!subsubsection=]
-\setuplabeltext [\s!ca] [\v!subsubsection=]
+\setuplabeltext [\s!es] [\v!subsubsection=Subsubsecci\'on]
+\setuplabeltext [\s!ca] [\v!subsubsection=Subsubsecci\'o]
\setuplabeltext [\s!it] [\v!subsubsection=]
\setuplabeltext [\s!la] [\v!subsubsection=]
\setuplabeltext [\s!pt] [\v!subsubsection=]
\setuplabeltext [\s!ro] [\v!subsubsection=]
\setuplabeltext [\s!fr] [\v!subsubsubsection=]
-\setuplabeltext [\s!es] [\v!subsubsubsection=]
-\setuplabeltext [\s!ca] [\v!subsubsubsection=]
+\setuplabeltext [\s!es] [\v!subsubsubsection=Subsubsubsecci\'on]
+\setuplabeltext [\s!ca] [\v!subsubsubsection=Subsubsubsecci\'o]
\setuplabeltext [\s!it] [\v!subsubsubsection=]
\setuplabeltext [\s!la] [\v!subsubsubsection=]
\setuplabeltext [\s!pt] [\v!subsubsubsection=]
\setuplabeltext [\s!ro] [\v!subsubsubsection=]
\setuplabeltext [\s!fr] [\v!appendix=]
-\setuplabeltext [\s!es] [\v!appendix=]
-\setuplabeltext [\s!ca] [\v!appendix=]
+\setuplabeltext [\s!es] [\v!appendix=Ap\'endice]
+\setuplabeltext [\s!ca] [\v!appendix=Ap\`endix]
\setuplabeltext [\s!it] [\v!appendix=]
\setuplabeltext [\s!la] [\v!appendix=]
\setuplabeltext [\s!pt] [\v!appendix=]
@@ -479,14 +478,12 @@
%D Rather new \unknown
-\setuplabeltext [\s!it] [\v!page=pagina ]
-\setuplabeltext [\s!it] [\v!atpage=a pagina ]
+\setuplabeltext [\s!it] [\v!page=pagina ]
+\setuplabeltext [\s!it] [\v!atpage=a pagina ]
\setuplabeltext [\s!it] [\v!hencefore=come mostrato sopra]
\setuplabeltext [\s!it] [\v!hereafter=come mostrato sotto]
\setuplabeltext [\s!it] [\v!see=cf. ]
-\setuplabeltext[\s!fr] [\v!see=voir ]
-
%D Ordinal converters:
\def\frordinaldaynumber#1% date is masculine
diff --git a/tex/context/base/lang-jap.tex b/tex/context/base/lang-jap.tex
index ffb53ea70..05c9b1d41 100644
--- a/tex/context/base/lang-jap.tex
+++ b/tex/context/base/lang-jap.tex
@@ -13,7 +13,7 @@
% rgabriel@kerio.com
-\writestatus{loading}{Context Language Macros / Japanese}
+\writestatus{loading}{ConTeXt Language Macros / Japanese}
\unprotect
@@ -29,8 +29,7 @@
\c!rightquote=\jaencoding\jaencodedsingleendquote,
\c!leftquotation=\jaencoding\jaencodedstartquote,
\c!rightquotation=\jaencoding\jaencodedendquote,
- \c!date={\jaencodedchristiandate,\v!year,\jaencodedyear,\v!month,\jaencodedmonth,\v!day,\jaencodedday},
- \c!state=\v!stop]
+ \c!date={\jaencodedchristiandate,\v!year,\jaencodedyear,\v!month,\jaencodedmonth,\v!day,\jaencodedday}]
\setupheadtext [\s!ja] [\v!content={\jaencoding\jaencodedtableofcontents}]
\setupheadtext [\s!ja] [\v!tables={\jaencoding\jaencodedtables}]
diff --git a/tex/context/base/lang-lab.tex b/tex/context/base/lang-lab.mkii
index 664460129..269ac249b 100644
--- a/tex/context/base/lang-lab.tex
+++ b/tex/context/base/lang-lab.mkii
@@ -2,7 +2,7 @@
%D [ file=lang-lab,
%D version=1997.08.27,
%D title=\CONTEXT\ Language Macros,
-%D subtitle=Language Head and Label Texts,
+%D subtitle=Labels,
%D author=Hans Hagen / Tobias Burnus,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,8 +11,6 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Language Head and Label Texts}
-
\unprotect
%D In this module we deal with language dependant labels and
@@ -183,21 +181,34 @@
% \csname#2\s!nl#3\endcsname \else
% \reporttextprefixerror{#1}{#2}{#3}%
% \fi\fi\fi\fi\fi}
+%
+% \def\dogetupsometextprefix#1#2#3% must be expandable !
+% {\ifcsname#2#1#3\endcsname
+% \csname#2#1#3\endcsname
+% \else\@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
+% \else
+% \reporttextprefixerror{#1}{#2}{#3}%
+% \fi\fi
+% \else
+% \dogetupsometextprefix{\csname\??la#1\c!default\endcsname}{#2}{#3}%
+% \fi\fi}
-\def\dogetupsometextprefix#1#2#3% must be expandable !
+\def\dogetupsometextprefix#1#2#3% must be expandable ! #1 == language
{\ifcsname#2#1#3\endcsname
\csname#2#1#3\endcsname
- \else\@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
- \else
- \reporttextprefixerror{#1}{#2}{#3}%
- \fi\fi
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\dogetupsometextprefix\csname\??la#1\s!default\endcsname{#2}{#3}%
+ \else\ifcsname#2#3\endcsname
+ \csname#2#3\endcsname
+ \else\ifcsname#1\s!en#3\endcsname
+ \csname#2\s!en#3\endcsname
\else
- \dogetupsometextprefix{\csname\??la#1\c!default\endcsname}{#2}{#3}%
- \fi\fi}
+ \reporttextprefixerror{#1}{#2}{#3}%
+ \fi\fi\fi\fi}
\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
@@ -247,15 +258,15 @@
%D which expands to {\em something} or {\em iets}, depending on
%D de current language.
-\def\dotranslate[#1]% don't group! SLOW if really used: speed up
+\def\dotranslate[#1]%
{\getparameters[\??lg][#1]%
- \doifdefinedelse{\??lg\currentlanguage}%
- {\getvalue{\??lg\currentlanguage}}
- {\doifdefinedelse{\??lg\s!en}
- {\getvalue{\??lg\s!en}}
- {\doifdefinedelse{\??lg\s!nl}
- {\getvalue{\??lg\s!nl}}
- {[translation #1]}}}}
+ \ifcsname\??lg\currentlanguage\endcsname
+ \csname\??lg\currentlanguage\endcsname
+ \else\ifcsname\??lg\s!en\endcsname
+ \csname\??lg\s!en\endcsname
+ \else
+ [translation #1]%
+ \fi\fi}
\unexpanded\def\translate
{\dosingleempty\dotranslate}
diff --git a/tex/context/base/lang-lab.mkiv b/tex/context/base/lang-lab.mkiv
new file mode 100644
index 000000000..60408f787
--- /dev/null
+++ b/tex/context/base/lang-lab.mkiv
@@ -0,0 +1,266 @@
+%D \module
+%D [ file=lang-lab,
+%D version=1997.08.27,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Labels,
+%D author=Hans Hagen / Tobias Burnus,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+%D In this module we deal with language dependant labels and
+%D prefixes, like in {\em Figure~12} and {\em Chapter 1}. In
+%D this file we set the default values. Users can easily
+%D overrule these.
+%D
+%D This module is dedicated to the grandfather of Tobias
+%D Burnus, who's extensive languages oriented library helped us
+%D a lot in finding the right translations. All those labels
+%D are collected in files that reflect their common ancestor.
+%D
+%D Not all languages can be satisfied with the labeling
+%D mechanism as provided here. Chinese for instance put a label
+%D in front as well as after a part number. This is why the
+%D current implementation of labels supports two labels too.
+
+%D \macros
+%D {setupheadtext, setuplabeltext}
+%D
+%D First we present some macros that deal with what we will
+%D call head and label texts. Such texts are defines by:
+%D
+%D \showsetup{setupheadtext}
+%D \showsetup{setuplabeltext}
+%D
+%D In a few paragraphs we'll show quite a lot of examples
+%D of its use.
+
+\let\handletextprefix\relax
+
+\def\setupheadtext {\dosetupsometextprefix[\c!title]}
+\def\setuplabeltext{\dosetupsometextprefix[\c!label]}
+
+\def\dosetupsometextprefix
+ {\let\dodocommand\xdosetupsometextprefix
+ \dotripleempty\dodosetupsometextprefix}
+
+% \def\dodosetupsometextprefix[#1][#2][#3]%
+% {\ifthirdargument
+% \def\docommand##1{\dodocommand[#1#2][##1]}%
+% \processcommalist[#3]\docommand
+% \else
+% \def\docommand##1{\dodocommand[#1\currentmainlanguage][##1]}%
+% \processcommalist[#2]\docommand
+% \fi}
+
+\def\dodosetupsometextprefix[#1][#2][#3]%
+ {\ifthirdargument
+ \def\docommand##1{\expanded{\dodocommand[#1\reallanguagetag{#2}]}[##1]}%
+ \processcommalist[#3]\docommand
+ \else
+ \def\docommand##1{\expanded{\dodocommand[#1\reallanguagetag\currentmainlanguage]}[##1]}%
+ \processcommalist[#2]\docommand
+ \fi}
+
+\def\doassignsometextprefix[#1][#2,#3,#4]%
+ {\setvalue{#1}{\handletextprefix{#2}{#3}}}
+
+\def\xdosetupsometextprefix[#1][#2=#3]%
+ {\doassignsometextprefix[#1#2][#3,,]}
+
+%D By changing the meaning of \type {\handletextprefix} we
+%D can filter the left and right labeltext as well as convert
+%D labels to uppercase.
+%D
+%D These commands accept all kind of inputs:
+%D
+%D \starttyping
+%D \setuplabeltext [language] [labellabel=text]
+%D \setuplabeltext [language] [labellabel=text,labellabel=text,...]
+%D \setuplabeltext [labellabel=text]
+%D \setuplabeltext [labellabel=text,labellabel=text,...]
+%D \stoptyping
+%D
+%D The last two cases concern the current language.
+
+%D \macros
+%D {headtext,
+%D labeltext, leftlabeltext, rightlabeltext, labeltexts,
+%D LABELTEXT, LEFTLABELTEXT, RIGHTLABELTEXT, LABELTEXTS}
+%D
+%D Once defined, head and label texts can be called upon using:
+%D
+%D \showsetup{headtext}
+%D \showsetup{labeltext}
+%D
+%D The latter one has an upcased alternative \type{\LABELTEXT}.
+
+% \def\labellanguage{\currentmainlanguage}
+% \def\headlanguage {\currentmainlanguage}
+
+% \def\labellanguage{\defaultlanguage\currentmainlanguage}
+% \def\headlanguage {\defaultlanguage\currentmainlanguage}
+
+\def\labellanguage{\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+\def\headlanguage {\reallanguagetag{\defaultlanguage\currentmainlanguage}}
+
+\appendtoks \let\labellanguage\currentlanguage \to \everycurrentdate
+
+\unexpanded\def\headtext
+ {\let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\headlanguage\c!title}
+
+\unexpanded\def\leftlabeltext
+ {\let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label}
+
+\unexpanded\def\rightlabeltext
+ {\let\handletextprefix\secondoftwoarguments
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label}
+
+\unexpanded\def\LEFTLABELTEXT
+ {\def\handletextprefix##1##2{\uppercase{##1}}\DOLABELTEXT}
+
+\unexpanded\def\RIGHTLABELTEXT
+ {\def\handletextprefix##1##2{\uppercase{##2}}\DOLABELTEXT}
+
+\def\DOLABELTEXT#1%
+ {\bgroup
+ \the\everyuppercase
+ \let\reporttextprefixerror\doreporttextprefixerror
+ \global\labeltextdonetrue
+ \dogetupsometextprefix\labellanguage\c!label{#1}% not \labeltext (see \MONTH)
+ \egroup}
+
+\let\labeltext \leftlabeltext
+\let\LABELTEXT \LEFTLABELTEXT
+
+\unexpanded\def\labeltexts#1#2{\leftlabeltext{#1}#2\rightlabeltext{#1}}
+\unexpanded\def\LABELTEXTS#1#2{\LEFTLABELTEXT{#1}#2\RIGHTLABELTEXT{#1}}
+
+\newif\iflabeltextdone % needs to be reset elsewhere
+\newif\iftracelabels % shows missing labels
+
+\def\doreporttextprefixerror#1#2#3%
+ {\iftracelabels{\tttf[#2:~#3/#1]~}\fi}
+
+\def\dosetexpandedheadlabeltext#1#2#3%
+ {\bgroup
+ \let\handletextprefix\firstoftwoarguments
+ \let\reporttextprefixerror\gobblethreearguments
+ \keepencodedtokens % test on multilingual pascal, ok in stretched
+ %\dontexpandencodedtokens % not usable in token handler
+ \expanded
+ {\egroup\noexpand\def\noexpand#2% watch out, no \edef
+ {\dogetupsometextprefix{\headlanguage}{#1}{#3}}}}
+
+\def\setexpandedheadtext {\dosetexpandedheadlabeltext\c!title}
+\def\setexpandedlabeltext{\dosetexpandedheadlabeltext\c!label}
+
+\def\dogetupsometextprefix#1#2#3% must be expandable ! #1 == language
+ {\ifcsname#2#1#3\endcsname
+ \csname#2#1#3\endcsname
+ \else\ifcsname\??la#1\s!default\endcsname
+ \expandafter\dogetupsometextprefix\csname\??la#1\s!default\endcsname{#2}{#3}%
+ \else\ifcsname#2#3\endcsname
+ \csname#2#3\endcsname
+ \else\ifcsname#1\s!en#3\endcsname
+ \csname#2\s!en#3\endcsname
+ \else
+ % \doreporttextprefixerror{#1}{#2}{#3}%
+ \fi\fi\fi\fi}
+
+\ifx\simplifiedcommands\undefined \newtoks\simplifiedcommands \fi
+
+\appendtoks
+ \let \headtext \firstofoneargument
+ \let \labeltext \firstofoneargument
+ \let \leftlabeltext \firstofoneargument
+ \let \rightlabeltext \firstofoneargument
+ \let \HEADTEXT \firstofoneargument
+ \let \LABELTEXT \firstofoneargument
+ \let \LEFTLABELTEXT \firstofoneargument
+ \let \RIGHTLABELTEXT \firstofoneargument
+\to \simplifiedcommands
+
+%D \macros
+%D {presetheadtext,presetlabeltext}
+%D
+%D The next two macros enable us to automatically define
+%D head and label texts without replacing predefined ones.
+%D These are internal macros.
+
+\def\xdopresetsometextprefix[#1][#2=#3]%
+ {\ifundefined{#1#2}\doassignsometextprefix[#1\reallanguagetag{#2}][#3,,]\fi}
+
+\def\dopresetsometextprefix
+ {\let\dodocommand\xdopresetsometextprefix
+ \dotripleempty\dodosetupsometextprefix}
+
+\def\presetheadtext {\dopresetsometextprefix[\c!title]}
+\def\presetlabeltext{\dopresetsometextprefix[\c!label]}
+
+%D \macros
+%D {translate}
+%D
+%D Sometismes macros contain language specific words that are to
+%D be typeset. Such macros can be made (more) language
+%D independant by using:
+%D
+%D \showsetup{translate}
+%D
+%D like for instance:
+%D
+%D \starttyping
+%D \translate[en=something,nl=iets]
+%D \stoptyping
+%D
+%D which expands to {\em something} or {\em iets}, depending on
+%D de current language.
+
+\def\dotranslate[#1]%
+ {\getparameters[\??lg][#1]%
+ \ifcsname\??lg\currentlanguage\endcsname
+ \csname\??lg\currentlanguage\endcsname
+ \else\ifcsname\??lg\s!en\endcsname
+ \csname\??lg\s!en\endcsname
+ \else
+ [translation #1]%
+ \fi\fi}
+
+\unexpanded\def\translate
+ {\dosingleempty\dotranslate}
+
+%D When used without argument, the last defined values are
+%D used. This enables repetitive use like
+%D
+%D \starttyping
+%D \en \translate\ means \nl \translate
+%D \stoptyping
+
+%D \macros
+%D {assigntranslation}
+%D
+%D This macro is a system macro, and can be used to assign a
+%D translation to a macro. Its form is:
+%D
+%D \starttyping
+%D \assigntranslation[en=something,nl=iets]\to\command
+%D \stoptyping
+
+\def\assigntranslation[#1]\to#2%
+ {\getparameters[\??lg][#1]%
+ \edef#2{\csname\??lg\currentlanguage\endcsname}}
+
+\protect \endinput
diff --git a/tex/context/base/lang-mis.tex b/tex/context/base/lang-mis.tex
index 41f370974..eb7bb1a04 100644
--- a/tex/context/base/lang-mis.tex
+++ b/tex/context/base/lang-mis.tex
@@ -2,7 +2,7 @@
%D [ file=lang-mis,
%D version=1997.03.20, % used to be supp-lan.tex
%D title=\CONTEXT\ Language Macros,
-%D subtitle=Language Options,
+%D subtitle=Compounds,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Language Macros / Compounds}
+\writestatus{loading}{ConTeXt Language Macros / Compounds}
%D \gdef\starttest
%D {\blank
@@ -181,7 +181,7 @@
%ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \prewordbreak } \fi
\ifx\postwordbreak \undefined \def\postwordbreak{\penalty\zerocount \hskip\zeropoint\relax} \fi
-\ifx\hspaceamount \undefined \def\hspaceamount#1#2{\kern.16667em} \fi % language specific
+\ifx\hspaceamount \undefined \def\hspaceamount#1#2{.16667em} \fi % language specific
%D \macros
%D {beginofsubsentencespacing,endofsubsentencespacing}
diff --git a/tex/context/base/lang-sla.tex b/tex/context/base/lang-sla.tex
index 50ebed127..0832e3f46 100644
--- a/tex/context/base/lang-sla.tex
+++ b/tex/context/base/lang-sla.tex
@@ -32,7 +32,7 @@
% Lusatian/Sorbian/Wendish, Polish, Slovak, Albanian,
% Illyrian, Armenian
-\writestatus{loading}{Slavic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Slavic Languages}
\unprotect
@@ -77,7 +77,8 @@
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={pl0,ec,qx},
+ \s!encoding={pl0,ec,qx}]
\installlanguage
[\s!cs]
@@ -91,7 +92,8 @@
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoublesixquote,
\c!date={\v!day,{.\,},\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={il2,ec},
+ \s!encoding={il2,ec}]
\installlanguage
[\s!sk]
@@ -105,7 +107,8 @@
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!day,{.\,},\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping={il2,ec},
+ \s!encoding={il2,ec}]
\installlanguage
[\s!hr]
@@ -119,7 +122,8 @@
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!day,\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping=ec,
+ \s!encoding=ec]
%D The default quotation marks for Slovenian were chosen as
%D \lowerleftdoubleninequote these ones\upperrightdoublesixquote\
@@ -168,7 +172,8 @@
\c!leftquotation=\rightguillemot,
\c!rightquotation=\leftguillemot,
\c!date={\v!day,{.},\ ,\v!month,\ ,\v!year},
- \c!state=\v!stop]
+ \s!mapping=ec,
+ \s!encoding=ec]
\installlanguage [polish] [\s!pl]
\installlanguage [czech] [\s!cs]
@@ -177,6 +182,8 @@
\installlanguage [slovenian] [\s!sl]
\installlanguage [slovene] [\s!sl] % both possible (mojca: still needed?)
+\installlanguage [cz] [\s!cs]
+
% If this is really needed we should make an enco-fhr.
%
% \startlanguagespecifics[\s!hr]
@@ -443,9 +450,7 @@
% \c!rightquote=\upperrightsinglesixquote,
% \c!leftquotation=\lowerleftdoubleninequote,
% \c!rightquotation=\upperrightdoublesixquote,
-% \c!date={\v!day,\ ,\v!month,\ ,\v!year},
-% \c!state=\v!stop]
-
+% \c!date={\v!day,\ ,\v!month,\ ,\v!year}]
\setuplabeltext [\s!sl] [\v!page=stran ]
\setuplabeltext [\s!sl] [\v!atpage=na strani ]
diff --git a/tex/context/base/lang-spa.tex b/tex/context/base/lang-spa.tex
index 1ec45cd69..f6e22aa51 100644
--- a/tex/context/base/lang-spa.tex
+++ b/tex/context/base/lang-spa.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Language Macros / Spacing}
+\writestatus{loading}{ConTeXt Language Macros / Spacing}
%D This module was created in the process of enhancing
%D support for French (with the help of Daniel Flipo).
diff --git a/tex/context/base/lang-spe.tex b/tex/context/base/lang-spe.mkii
index 00b514be2..7911b0c95 100644
--- a/tex/context/base/lang-spe.tex
+++ b/tex/context/base/lang-spe.mkii
@@ -30,7 +30,7 @@
%D this is a good learning experience (catcodes, lccodes, token
%D lists, expansion, \unknown).
-\writestatus{loading}{Context Language Macros / Specifics}
+\writestatus{loading}{ConTeXt Language Macros / Specifics}
\unprotect
@@ -122,10 +122,11 @@
\def\languagespectag#1{\??la\languageencoding#1\??la}
\long\def\dosetlanguagespecifics#1#2%
- {\ifcsname\languagespectag{#2}\endcsname \else
- \expandafter\newtoks\csname\languagespectag{#2}\endcsname
+ {\edef\askedlanguagespecificstag{\languagespectag{#2}}%
+ \ifcsname\askedlanguagespecificstag\endcsname \else
+ \expandafter\newtoks\csname\askedlanguagespecificstag\endcsname
\fi
- \csname\languagespectag{#2}\endcsname\@EA{\the\csname\languagespectag{#2}\endcsname#1}%
+ \csname\askedlanguagespecificstag\endcsname\@EA{\the\csname\askedlanguagespecificstag\endcsname#1}%
\bgroup
\setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
\ifdim\wd\scratchbox>\zeropoint
@@ -136,9 +137,6 @@
\egroup
\doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}
-% \def\forgetlanguagespecifics[#1]%
-% {\letvalue{\??la\languageencoding#1\??la}\empty}
-
\def\forgetlanguagespecifics[#1]%
{\csname\languagespectag{#1}\endcsname\emptytoks}
@@ -146,24 +144,28 @@
%D define \type{\do} in such a way that \type{{ }} is removed
%D and the language key is gobbled.
-\def\enablelanguagespecifics[#1]%
- {\the\executeifdefined{\??la
- \@EA\ifx\csname\??la#1\c!default\endcsname\relax
- \languageencoding
- \else
- \csname\??la#1\c!default\endcsname
- \fi
- \??la}\emptytoks
- \the\executeifdefined{\??la#1\??la}\emptytoks
- \the\executeifdefined{\??la\languageencoding#1\??la}\emptytoks} % dup ?
-
-% check:
-
% \def\enablelanguagespecifics[#1]%
-% {\the\executeifdefined{\??la\executeifdefined{\??la#1\c!default}\languageencoding\??la}\emptytoks
+% {\the\executeifdefined{\??la
+% \@EA\ifx\csname\??la#1\c!default\endcsname\relax
+% \languageencoding
+% \else
+% \csname\??la#1\c!default\endcsname
+% \fi
+% \??la}\emptytoks
% \the\executeifdefined{\??la#1\??la}\emptytoks
% \the\executeifdefined{\??la\languageencoding#1\??la}\emptytoks} % dup ?
+\def\enablelanguagespecifics[#1]%
+ {\edef\askedlanguagespecificslanguage{\defaultlanguage{#1}}%
+ \ifcsname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \the\csname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \fi
+ \ifx\languageencoding\empty\else
+ \ifcsname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
+ \the\csname\??la\languageencoding\askedlanguagespecificslanguage\??la\endcsname
+ \fi
+ \fi}
+
%D \macros
%D {deactivatelanguagespecific}
%D
diff --git a/tex/context/base/lang-spe.mkiv b/tex/context/base/lang-spe.mkiv
new file mode 100644
index 000000000..6f32888e6
--- /dev/null
+++ b/tex/context/base/lang-spe.mkiv
@@ -0,0 +1,111 @@
+%D \module
+%D [ file=lang-spe,
+%D version=2002.05.07, % 1996.01.25,
+%D title=\CONTEXT\ Language Macros,
+%D subtitle=Specifics,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Language Macros / Specifics}
+
+%D In \MKIV\ we will get away from this feature. See \MKII\ file
+%D for comments. So, consider this a temporary feature.
+
+\unprotect
+
+%D \macros
+%D {everyresetlanguagespecifics,resetlanguagespecifics}
+%D
+%D Cleanup macros.
+
+\newevery \everyresetlanguagespecifics \relax
+
+\def\resetlanguagespecifics
+ {\ifcase\protectionlevel
+ \the\everyresetlanguagespecifics
+ \fi}
+
+\appendtoks
+ \resetlanguagespecifics
+\to \everycleanupfeatures
+
+%D \macros
+%D {startlanguagespecifics,enablelanguagespecifics}
+
+\def\startlanguagespecifics
+ {\bgroup
+ \catcode`\^^I=\@@ignore
+ \catcode`\^^M=\@@ignore
+ \catcode`\^^L=\@@ignore
+ \dodoubleempty\dostartlanguagespecifics} % get rid of spaces
+
+\long\def\dostartlanguagespecifics[#1][#2]#3\stoplanguagespecifics
+ {\egroup
+ \processcommalist[#1]{\dosetlanguagespecifics{#3}}}
+
+\long\def\dosetlanguagespecifics#1#2% specifics language
+ {\ifcsname\??la#2\??la\endcsname \else
+ \expandafter\newtoks\csname\??la#2\??la\endcsname
+ \fi
+ \csname\??la#2\??la\endcsname\@EA{\the\csname\??la#2\??la\endcsname#1}%
+ \bgroup
+ \setbox\scratchbox\hbox{\enablelanguagespecifics[#2]}%
+ \ifdim\wd\scratchbox>\zeropoint
+ \showmessage\m!linguals7{#2,\the\wd\scratchbox\space}\wait
+ \else
+ \showmessage\m!linguals8{#2}%
+ \fi
+ \egroup
+ \doif{#2}\currentmainlanguage{\enablelanguagespecifics[#2]}}
+
+\def\forgetlanguagespecifics[#1]%
+ {\ifcsname\??la#1\??la\endcsname
+ \csname\??la#1\??la\endcsname\emptytoks
+ \fi}
+
+% \def\enablelanguagespecifics[#1]% no default language fallback (yet)
+% {\ifcsname\??la#1\??la\endcsname
+% \the\csname\??la#1\??la\endcsname\relax
+% \fi}
+
+\def\enablelanguagespecifics[#1]%
+ {\edef\askedlanguagespecificslanguage{\defaultlanguage{#1}}%
+ \ifcsname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \the\csname\??la\askedlanguagespecificslanguage\??la\endcsname
+ \fi}
+
+%D \macros
+%D {ordinaldaynumber, highordinalstr, ordinalstr}
+%D
+%D Efficient general ordinal number converters are sometimes
+%D difficult to implement. Fortunately dates never exceed the
+%D number~31.
+
+\ifx\high \undefined \let\high \firstofoneargument \fi % todo
+\ifx\notsmallcapped\undefined \let\notsmallcapped\firstofoneargument \fi % todo
+
+\def\highordinalstr#1{\high{\notsmallcapped{#1}}}
+\def\ordinalstr #1{\notsmallcapped{#1}}
+
+\def\ordinaldaynumber#1% \strippedcsname\ordinaldaynumber
+ {\expanded{\executeifdefined{\currentlanguage ordinaldaynumber}%
+ \noexpand\firstofoneargument{\number#1}}}
+
+%D Language specific converters have definitions like:
+%D
+%D \starttyping
+%D \def\enordinaldaynumber#1{...}
+%D \stoptyping
+%D
+%D Examples can be found in the other \type {lang} modules.
+
+\appendtoks
+ \ifprocessingXML \else \resetlanguagespecifics \fi
+\to \everylanguage
+
+\protect \endinput
diff --git a/tex/context/base/lang-ura.tex b/tex/context/base/lang-ura.tex
index 2ecb31e6b..a2bcd3d2b 100644
--- a/tex/context/base/lang-ura.tex
+++ b/tex/context/base/lang-ura.tex
@@ -13,7 +13,7 @@
% Todo: replace \'.. by \namedglyph
-\writestatus{loading}{Uralic Languages}
+\writestatus{loading}{ConTeXt Language Macros / Uralic Languages}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -42,8 +42,7 @@
\c!rightquote=\upperrightsingleninequote,
\c!leftquotation=\upperleftdoublesixquote,
\c!rightquotation=\upperrightdoubleninequote,
- \c!date={\v!year,\ ,\v!month,\ ,\v!day},
- \c!state=\v!stop]
+ \c!date={\v!year,\ ,\v!month,\ ,\v!day}]
\installlanguage
[\s!hu]
@@ -57,7 +56,6 @@
\c!leftquotation=\lowerleftdoubleninequote,
\c!rightquotation=\upperrightdoubleninequote,
\c!date={\v!year,.,\ ,\v!month,\ ,\v!day,.},
- \c!state=\v!stop,
\s!mapping=ec,
\s!encoding=ec]
diff --git a/tex/context/base/lang-url.lua b/tex/context/base/lang-url.lua
index b732dcef0..1524878cf 100644
--- a/tex/context/base/lang-url.lua
+++ b/tex/context/base/lang-url.lua
@@ -6,6 +6,12 @@ if not modules then modules = { } end modules ['lang-url'] = {
license = "see context related readme files"
}
+local utf = unicode.utf8
+
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
+local ctxcatcodes = tex.ctxcatcodes
+
commands = commands or { }
--[[
@@ -76,13 +82,13 @@ do
return "\\a{" .. u(s) .. "}"
end
end )
- tex.sprint(tex.ctxcatcodes,str)
+ tex.sprint(ctxcatcodes,str)
end
-- todo, no interface in mkiv yet
function commands.hyphenatedurl.setcharacters(str,value) -- 1, 2 == before, after
- for s in str:utfcharacters() do
+ for s in utfcharacters(str) do
chars[s] = value or 1
end
end
diff --git a/tex/context/base/lang-url.mkii b/tex/context/base/lang-url.mkii
index f3310cceb..fdf530b45 100644
--- a/tex/context/base/lang-url.mkii
+++ b/tex/context/base/lang-url.mkii
@@ -18,6 +18,29 @@
\ifx\\\undefined \let\\\crlf \fi
+%D \macros
+%D {hyphenatedurl}
+%D
+%D For those who want to put full \URL's in a text, we offer
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://optimist.optimist/optimist/optimist.optimist#optimist}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D which breaks at the appropriate places. Watch the \type{#}
+%D hack.
+%D
+%D When passed as argument, like in \type {\goto}, one needs
+%D to substitute a \type {\\} for each \type{#}.
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://this.is.a.rather/strange/reference#indeed}
+%D \stopbuffer
+%D
+%D \typebuffer
+
\ifx\urlsplitmode\undefined \chardef\urlsplitmode\plusone \fi
% 0 => don't split
@@ -229,4 +252,55 @@
%
% {\hsize1cm\hyphenatedstring{ABXXXXXXXXXXC-12345-12345}}
+%D \macros
+%D {hyphenatedfilename}
+%D
+%D For the moment we treat filenames in a similar way,
+%D
+%D \starttyping
+%D \hyphenatedfilename{here/there/filename.suffix}
+%D \stoptyping
+
+\ifx\hyphenatedfilename\undefined \let\hyphenatedfilename\hyphenatedurl \fi
+
+% \def\test#1%
+% {\dontleavehmode
+% \begingroup
+% \tttf
+% \hyphenatedurl {%
+% \letterampersand #1\letterampersand #1\letterampersand #1\letterampersand #1\letterampersand
+% \letterhash #1\letterhash #1\letterpercent #1\letterslash #1\letterampersand
+% }%
+% \endgroup}
+
+% \dorecurse{100}{\test{a} \test{ab} \test{abc} \test{abcd} \test{abcde} \test{abcdef}}
+
\protect \endinput
+
+% \bgroup
+
+% \gdef\lettercolon{:}
+
+% \catcode`\:=\active
+% \catcode`\^=\active
+% \catcode`\/=\active
+% \catcode`\~=\active
+
+% \gdef\theurlcolon {\nobreak\hbox{\lettercolon}\allowbreak}
+% \gdef\theurlslash#1{\nobreak\hbox{\letterslash}\ifx#1\relax\else\ifnum`/=\expandafter`\string#1\else\allowbreak\fi#1\fi}
+% \gdef\theurlhat {\allowbreak\hbox{\letterhat}\nobreak}
+% \gdef\theurltilde {\allowbreak\hbox{\lettertilde}\nobreak}
+
+% \gdef\ForMojcaWhoLikesHacks#1%
+% {\dontleavehmode
+% \begingroup
+% \mathcode`\:="8000 \let:\theurlcolon
+% \mathcode`\^="8000 \let^\theurlhat
+% \mathcode`\/="8000 \let/\theurlslash
+% \mathcode`\~="8000 \let~\theurltilde
+% \everymath\emptytoks
+% \mathsurround\zeropoint$\tf#1\relax$%
+% \endgroup}
+% \egroup
+
+% \hsize 1mm \ForMojcaWhoLikesHacks{http://www.sil.org//silesr/}
diff --git a/tex/context/base/lang-url.mkiv b/tex/context/base/lang-url.mkiv
index 7479fed68..c22f9f420 100644
--- a/tex/context/base/lang-url.mkiv
+++ b/tex/context/base/lang-url.mkiv
@@ -15,7 +15,30 @@
\unprotect
-% \urlsplitmode is not (yet) supported (not that much needed)
+%D \macros
+%D {hyphenatedurl}
+%D
+%D For those who want to put full \URL's in a text, we offer
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://optimist.optimist/optimist/optimist.optimist#optimist}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D which breaks at the appropriate places. Watch the \type{#}
+%D hack.
+%D
+%D When passed as argument, like in \type {\goto}, one needs
+%D to substitute a \type {\\} for each \type{#}.
+%D
+%D \startbuffer
+%D \hyphenatedurl{http://this.is.a.rather/strange/reference#indeed}
+%D \stopbuffer
+%D
+%D \typebuffer
+
+\ifx\urlsplitmode\undefined \chardef\urlsplitmode\zerocount \fi % not supported in mkiv
\newtoks\everyhyphenatedurl
@@ -54,11 +77,34 @@
\let\n\dohyphenatedurlnormal
\let\b\dohyphenatedurlbefore
\let\a\dohyphenatedurlafter
- \expanded{\ctxlua{commands.hyphenatedurl.action(
+ \normalexpanded{\noexpand\ctxlua{commands.hyphenatedurl.action(
\!!bs\noexpand\detokenize{#1}\!!es,
\number\hyphenatedurllefthyphenmin,
\number\hyphenatedurlrighthyphenmin
)}}%
\endgroup}
+%D \macros
+%D {hyphenatedfilename}
+%D
+%D For the moment we treat filenames in a similar way,
+%D
+%D \starttyping
+%D \hyphenatedfilename{here/there/filename.suffix}
+%D \stoptyping
+
+\ifx\hyphenatedfilename\undefined \let\hyphenatedfilename\hyphenatedurl \fi
+
+% \def\test#1%
+% {\dontleavehmode
+% \begingroup
+% \tttf
+% \hyphenatedurl {%
+% \letterampersand #1\letterampersand #1\letterampersand #1\letterampersand #1\letterampersand
+% \letterhash #1\letterhash #1\letterpercent #1\letterslash #1\letterampersand
+% }%
+% \endgroup}
+
+% \dorecurse{100}{\test{a} \test{ab} \test{abc} \test{abcd} \test{abcde} \test{abcdef}}
+
\protect \endinput
diff --git a/tex/context/base/lang-url.tex b/tex/context/base/lang-url.tex
deleted file mode 100644
index 3eb891914..000000000
--- a/tex/context/base/lang-url.tex
+++ /dev/null
@@ -1,70 +0,0 @@
-%D \module
-%D [ file=lang-url,
-%D version=2008.01.22, % used to be lang-mis
-%D title=\CONTEXT\ Language Macros,
-%D subtitle=Language Options,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Language Macros / URL}
-
-\loadmarkfile{lang-url}
-
-\unprotect
-
-\ifx\urlsplitmode\undefined \chardef\urlsplitmode\zerocount \fi % not supported in mkiv
-
-%D \macros
-%D {hyphenatedurl}
-%D
-%D For those who want to put full \URL's in a text, we offer
-%D
-%D \startbuffer
-%D \hyphenatedurl{http://optimist.optimist/optimist/optimist.optimist#optimist}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D which breaks at the appropriate places. Watch the \type{#}
-%D hack.
-%D
-%D When passed as argument, like in \type {\goto}, one needs
-%D to substitute a \type {\\} for each \type{#}.
-%D
-%D \startbuffer
-%D \hyphenatedurl{http://this.is.a.rather/strange/reference#indeed}
-%D \stopbuffer
-%D
-%D \typebuffer
-
-\ifx\hyphenatedurl\undefined \let\hyphenatedurl\firstofoneargument \fi
-
-%D \macros
-%D {hyphenatedfilename}
-%D
-%D For the moment we treat filenames in a similar way,
-%D
-%D \starttyping
-%D \hyphenatedfilename{here/there/filename.suffix}
-%D \stoptyping
-
-\ifx\hyphenatedfilename\undefined \let\hyphenatedfilename\hyphenatedurl \fi
-
-% \def\test#1%
-% {\dontleavehmode
-% \begingroup
-% \tttf
-% \hyphenatedurl {%
-% \letterampersand #1\letterampersand #1\letterampersand #1\letterampersand #1\letterampersand
-% \letterhash #1\letterhash #1\letterpercent #1\letterslash #1\letterampersand
-% }%
-% \endgroup}
-
-% \dorecurse{100}{\test{a} \test{ab} \test{abc} \test{abcd} \test{abcde} \test{abcdef}}
-
-\protect \endinput
diff --git a/tex/context/base/lang-vn.tex b/tex/context/base/lang-vn.tex
index 22bbe9ff6..27d2a48a1 100644
--- a/tex/context/base/lang-vn.tex
+++ b/tex/context/base/lang-vn.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Vietnamese Language}
+\writestatus{loading}{ConTeXt Language Macros / Vietnamese Language}
%D The framework of this module is set up by Hans Hagen while
%D many of the first translations were done by Tobias. Later
@@ -37,7 +37,8 @@
\c!leftquotation=\quotedblleft,
\c!rightquotation=\quotedblright,
\c!date={{ },dd,{/},mm,{/},yy},
- \c!state=\v!stop]
+ \s!mapping=t5,
+ \s!encoding=t5]
\installlanguage [vietnamese] [\s!vi]
diff --git a/tex/context/base/luat-bas.tex b/tex/context/base/luat-bas.tex
new file mode 100644
index 000000000..a78455173
--- /dev/null
+++ b/tex/context/base/luat-bas.tex
@@ -0,0 +1,64 @@
+%D \module
+%D [ file=luat-bas, % moved from luat-lib,
+%D version=2006.09.11,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Basic \LUA\ Libraries,
+%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.
+
+% \writestatus{loading}{ConTeXt Lua Macros / Basic Lua Libraries}
+
+%D This will move cq. become configurable. The XML like output is just
+%D an example.
+
+% todo \let\normaleverytoks\everytoks \newtoks\everytoke \normaleverytoks{\the\everytoks}
+
+\chardef\statuswidth=15
+\chardef\statuswrite=16
+
+\newtoks\everywritestring
+
+\def\writedirect {\immediate\write\statuswrite}
+\def\writeline {\writedirect{}}
+\def\writestring#1{\begingroup\the\everywritestring\writedirect{#1}\endgroup}
+
+\ifx\normalwritestatus\undefined \def\normalwritestatus#1#2{\writedirect{#1 : #2}} \fi
+
+% Because all libs are also on bytecodes we can start without stub. However,
+% some initializations need to take place before the \TEX\ engine itself
+% kicks in, especially memory settings and so. In due time we might make the
+% stub smaller and just create a configuration startup file.
+
+\registerctxluafile{l-string} {1.001}
+\registerctxluafile{l-lpeg} {1.001}
+\registerctxluafile{l-boolean}{1.001}
+\registerctxluafile{l-number} {1.001}
+\registerctxluafile{l-math} {1.001}
+\registerctxluafile{l-table} {1.001}
+\registerctxluafile{l-aux} {1.001}
+\registerctxluafile{l-io} {1.001}
+\registerctxluafile{l-os} {1.001}
+\registerctxluafile{l-file} {1.001}
+\registerctxluafile{l-md5} {1.001}
+\registerctxluafile{l-dir} {1.001}
+\registerctxluafile{l-unicode}{1.001}
+\registerctxluafile{l-utils} {1.001}
+\registerctxluafile{l-dimen} {1.001}
+\registerctxluafile{l-url} {1.001}
+\registerctxluafile{l-set} {1.001}
+
+% \registerctxluafile{socket.lua}{}
+% \registerctxluafile{ltn12.lua} {}
+% \registerctxluafile{mime.lua} {}
+% \registerctxluafile{http.lua} {}
+% \registerctxluafile{url.lua} {}
+% \registerctxluafile{tp.lua} {}
+% \registerctxluafile{ftp.lua} {}
+% %registerctxluafile{smtp.lua} {}
+
+\endinput
diff --git a/tex/context/base/luat-cbk.lua b/tex/context/base/luat-cbk.lua
index 4069fe61f..d8b508c13 100644
--- a/tex/context/base/luat-cbk.lua
+++ b/tex/context/base/luat-cbk.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['luat-cbk'] = {
license = "see context related readme files"
}
+local trace_checking = false trackers.register("memory.checking", function(v) trace_checking = v end)
+
--[[ldx--
<p>Callbacks are the real asset of <l n='luatex'/>. They permit you to hook
your own code into the <l n='tex'/> engine. Here we implement a few handy
@@ -67,7 +69,6 @@ end)
<p>This does a one-shot.</p>
--ldx]]--
-
--[[ldx--
<p>Callbacks may result in <l n='lua'/> doing some hard work
which takes time and above all resourses. Sometimes it makes
@@ -97,8 +98,8 @@ because messing aroudn with the gc is too unpredictable.</p>
garbagecollector = garbagecollector or { }
-garbagecollector.trace = false
-garbagecollector.enabled = false
+garbagecollector.enabled = false
+garbagecollector.criterium = 4*1024*1024
-- Lua allocates up to 12 times the amount of memory needed for
-- handling a string, and for large binary chunks (like chinese otf
@@ -122,13 +123,11 @@ garbagecollector.enabled = false
-- As a result of this, LuaTeX now uses an optimized version of f:read("*a"),
-- one that does not use the 4K allocations but allocates in one step.
-garbagecollector.criterium = 4*1024*1024
-
function garbagecollector.check(size,criterium)
if garbagecollector.enabled then
criterium = criterium or garbagecollector.criterium
if not size or (criterium and criterium > 0 and size > criterium) then
- if garbagecollector.trace then
+ if trace_checking then
local round = math.round or math.floor
local b = collectgarbage("count")
collectgarbage("collect")
@@ -140,5 +139,3 @@ function garbagecollector.check(size,criterium)
end
end
end
-
-
diff --git a/tex/context/base/luat-cnf.lua b/tex/context/base/luat-cnf.lua
new file mode 100644
index 000000000..9f237b981
--- /dev/null
+++ b/tex/context/base/luat-cnf.lua
@@ -0,0 +1,114 @@
+if not modules then modules = { } end modules ['luat-cnf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat = string.format, table.concat
+
+luatex = luatex or { }
+
+luatex.variablenames = {
+ 'main_memory', 'extra_mem_bot', 'extra_mem_top',
+ 'buf_size','expand_depth',
+ 'font_max', 'font_mem_size',
+ 'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
+ 'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
+ 'nest_size', 'param_size', 'save_size', 'stack_size','expand_depth',
+ 'trie_size', 'hyph_size', 'max_in_open',
+ 'ocp_stack_size', 'ocp_list_size', 'ocp_buf_size',
+ 'max_print_line',
+}
+
+function luatex.variables()
+ local t, x = { }, nil
+ for _,v in next, luatex.variablenames do
+ x = resolvers.var_value(v)
+ if x and x:find("^%d+$") then
+ t[v] = tonumber(x)
+ end
+ end
+ return t
+end
+
+if not luatex.variables_set then
+ for k, v in next, luatex.variables() do
+ texconfig[k] = v
+ end
+ luatex.variables_set = true
+end
+
+local stub = [[
+-- checking
+
+storage = storage or {}
+luatex = luatex or {}
+
+-- as soon as possible
+
+luatex.starttime = os.gettimeofday()
+
+-- we provide our own file handling
+
+texconfig.kpse_init = false
+texconfig.shell_escape = 't'
+
+-- this will happen after the format is loaded
+
+function texconfig.init()
+
+ -- shortcut and helper
+
+ local b = lua.bytecode
+
+ local function init(start)
+ local i = start
+ while b[i] do
+ b[i]() ; b[i] = nil ; i = i + 1
+ end
+ return i - start
+ end
+
+ -- the stored tables and modules
+
+ storage.noftables = init(0)
+ storage.nofmodules = init(%s)
+
+end
+
+-- we provide a qualified path
+
+callback.register('find_format_file',function(name)
+ texconfig.formatname = name
+ return name
+end)
+
+-- done, from now on input and callbacks are internal
+]]
+
+function luatex.dumpstate(name,firsttable)
+ if tex and tex.luatexversion < 38 then
+ os.remove(name)
+ elseif true then
+ local t = {
+ "-- this file is generated, don't change it\n",
+ "-- configuration (can be overloaded later)\n"
+ }
+ for _,v in next, luatex.variablenames do
+ local tv = texconfig[v]
+ if tv then
+ t[#t+1] = format("texconfig.%s=%s",v,tv)
+ end
+ end
+ io.savedata(name,format("%s\n\n%s",concat(t,"\n"),format(stub,firsttable or 501)))
+ else
+ io.savedata(name,format(stub,firsttable or 501))
+ end
+end
+
+texconfig.kpse_init = false
+texconfig.max_print_line = 100000
+texconfig.max_in_open = 127
+texconfig.shell_escape = 't'
diff --git a/tex/context/base/luat-cod.tex b/tex/context/base/luat-cod.tex
new file mode 100644
index 000000000..07db36483
--- /dev/null
+++ b/tex/context/base/luat-cod.tex
@@ -0,0 +1,161 @@
+%D \module
+%D [ file=luat-cod,
+%D version=2005.05.26,
+%D title=\CONTEXT\ Lua Macros,
+%D subtitle=Code,
+%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.
+
+% \writestatus{loading}{ConTeXt Lua Macros / Code}
+
+%D Originally we compiled the lua files externally and loaded
+%D then at runtime, but when the amount grew, we realized that
+%D we needed away to store them in the format, which is what
+%D bytecode arrays do. And so the following is obsolete:
+%D
+%D \starttyping
+%D \chardef\ctxluaembeddingmode \plusone
+%D
+%D 0 = external compilation and loading
+%D 1 = runtime compilation and embedding
+%D \stoptyping
+%D
+%D Allocation of \LUA\ engines has changed too. The original idea
+%D was to have multiple \LUA\ instances and it worked that way for
+%D several years. Hoewver in practice we used only one engine because
+%D scripts need to share data anyway. So eventually \LUATEX\ got only
+%D one instance. Because each call is reentrant there is not much
+%D danger for crashes.
+
+\def\ctxdirectlua{\directlua\zerocount}
+\def\ctxlatelua {\latelua \zerocount}
+
+%D Take your choice \unknown
+
+\let\ctxlua \ctxdirectlua
+\let\luacode \ctxdirectlua
+\let\lateluacode \ctxlatelua
+\let\directluacode\ctxdirectlua
+
+%D Reporting the version of \LUA\ that we use is done as follows:
+
+\edef\luaversion{\ctxlua{tex.print(_VERSION)}}
+
+%D We want to define \LUA\ related things in the format but
+%D need to reload code because \LUA\ instances themselves are
+%D not dumped into the format.
+
+\newtoks\everyloadluacode
+\newtoks\everyfinalizeluacode
+
+\normaleveryjob{\the\everyloadluacode\the\everyfinalizeluacode\the\everyjob}
+
+\newif\ifproductionrun
+
+%D Here we operate in the \TEX\ catcode regime as we haven't yet defined
+%D catcode regimes. A chicken or egg problem.
+
+\long\def\startruntimeluacode#1\stopruntimeluacode % only simple code (load +init)
+ {\ifproductionrun
+ \global\let\startruntimeluacode\relax
+ \global\let\stopruntimeluacode \relax
+ \else
+ \global\everyloadluacode\expandafter{\the\everyloadluacode#1}%
+ \fi
+ #1} % maybe no interference
+
+\long\def\startruntimectxluacode#1\stopruntimectxluacode
+ {\startruntimeluacode\ctxlua{#1}\stopruntimeluacode}
+
+%D Next we load the initialization code.
+
+\startruntimectxluacode
+ environment = environment or { }
+ environment.jobname = "\jobname" % tex.jobname
+ environment.initex = \ifproductionrun false \else true \fi % tex.formatname == ""
+ environment.version = "\fmtversion"
+\stopruntimectxluacode
+
+% we start at 500, below this, we store predefined data (dumps)
+
+\newcount\luabytecodecounter \luabytecodecounter=500
+
+\startruntimectxluacode
+ lua.bytedata = lua.bytedata or { }
+\stopruntimectxluacode
+
+%D Handy when we expand:
+
+\let\stopruntimeluacode \relax
+\let\stopruntimectxluacode\relax
+
+\long\def\lastexpanded{} % todo: elsewhere we use \@@expanded
+
+\long\def\expanded#1{\long\xdef\lastexpanded{\noexpand#1}\lastexpanded}
+
+%D More code:
+
+% \def\ctxluabytecode#1% executes an already loaded chunk
+% {\ctxlua {
+% local str = ''
+% if lua.bytedata[#1] then
+% str = " from file " .. lua.bytedata[#1][1] .. " version " .. lua.bytedata[#1][2]
+% end
+% if lua.bytecode[#1] then
+% if environment.initex then
+% texio.write_nl("bytecode: executing blob " .. "#1" .. str)
+% assert(lua.bytecode[#1])()
+% else
+% texio.write_nl("bytecode: initializing blob " .. "#1" .. str)
+% assert(lua.bytecode[#1])()
+% lua.bytecode[#1] = nil
+% end
+% else
+% texio.write_nl("bytecode: invalid blob " .. "#1" .. str)
+% end
+% }}
+
+\def\ctxluabytecode#1% executes an already loaded chunk
+ {\ctxlua {
+ local lbc = lua.bytecode
+ if lbc[#1] then
+ assert(lbc[#1])()
+ if not environment.initex then
+ lbc[#1] = nil
+ end
+ end
+ }}
+
+\def\ctxluabyteload#1#2% registers and compiles chunk
+ {\global\advance\luabytecodecounter \plusone
+ \expanded{\startruntimectxluacode
+ lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
+ \stopruntimectxluacode}%
+ \ctxlua {
+ lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
+ lua.bytecode[\the\luabytecodecounter] = environment.luafilechunk("#1")
+ }}
+
+\def\ctxloadluafile#1#2% load a (either not compiled) chunk at runtime
+ {\doifelsenothing{#2}
+ {\ctxlua{environment.loadluafile("#1")}}
+ {\ctxlua{environment.loadluafile("#1",#2)}}}
+
+\def\registerctxluafile#1#2% name version
+ {\ifproductionrun
+ \ctxloadluafile{#1}{#2}%
+ \else
+ \ctxluabyteload{#1}{#2}% can go away
+ \fi
+ \global\everyloadluacode\expandafter\expandafter\expandafter{\expandafter\the\expandafter\everyloadluacode
+ \expandafter\ctxluabytecode\expandafter{\the\luabytecodecounter}}%
+ \ctxluabytecode{\the\luabytecodecounter}}
+
+\everydump\expandafter{\the\everydump\ctxlua{luatex.dumpstate(environment.jobname..".lui",501)}}
+
+\endinput
diff --git a/tex/context/base/luat-crl.lua b/tex/context/base/luat-crl.lua
deleted file mode 100644
index 5ebd62d22..000000000
--- a/tex/context/base/luat-crl.lua
+++ /dev/null
@@ -1,53 +0,0 @@
--- filename : luat-crl.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-crl'] = 1.001
-if not curl then curl = { } end
-
-curl.cached = { }
-curl.cachepath = caches.definepath("curl")
-
-function curl.fetch(protocol, name)
- local cachename = curl.cachepath() .. "/" .. name:gsub("[^%a%d%.]+","-")
--- cachename = cachename:gsub("[\\/]", io.fileseparator)
- cachename = cachename:gsub("[\\]", "/")
- if not curl.cached[name] then
- if not io.exists(cachename) then
- curl.cached[name] = cachename
- local command = "curl --silent --create-dirs --output " .. cachename .. " " .. name -- no protocol .. "://"
- os.spawn(command)
- end
- if io.exists(cachename) then
- curl.cached[name] = cachename
- else
- curl.cached[name] = ""
- end
- end
- return curl.cached[name]
-end
-
-function input.finders.curl(protocol,filename)
- local foundname = curl.fetch(protocol, filename)
- return input.finders.generic(protocol,foundname,filetype)
-end
-function input.openers.curl(protocol,filename)
- return input.openers.generic(protocol,filename)
-end
-function input.loaders.curl(protocol,filename)
- return input.loaders.generic(protocol,filename)
-end
-
--- todo: metamethod
-
-function curl.install(protocol)
- input.finders[protocol] = function (filename,filetype) return input.finders.curl(protocol,filename) end
- input.openers[protocol] = function (filename) return input.openers.curl(protocol,filename) end
- input.loaders[protocol] = function (filename) return input.loaders.curl(protocol,filename) end
-end
-
-curl.install('http')
-curl.install('https')
-curl.install('ftp')
diff --git a/tex/context/base/luat-dum.lua b/tex/context/base/luat-dum.lua
new file mode 100644
index 000000000..f2ff50577
--- /dev/null
+++ b/tex/context/base/luat-dum.lua
@@ -0,0 +1,60 @@
+if not modules then modules = { } end modules ['luat-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local dummyfunction = function() end
+
+statistics = {
+ register = dummyfunction,
+ starttiming = dummyfunction,
+ stoptiming = dummyfunction,
+}
+trackers = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
+storage = {
+ register = dummyfunction,
+ shared = { },
+}
+logs = {
+ report = dummyfunction,
+ simple = dummyfunction,
+}
+tasks = {
+ new = dummyfunction,
+ actions = dummyfunction,
+ appendaction = dummyfunction,
+ prependaction = dummyfunction,
+}
+
+-- we need to cheat a bit here
+
+texconfig.kpse_init = true
+
+resolvers = resolvers or { } -- no fancy file helpers used
+
+local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ cid = "other text files", -- will become "cid files"
+}
+
+function resolvers.find_file(name,kind)
+ name = string.gsub(name,"\\","\/")
+ kind = string.lower(kind)
+ return kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or "tex")
+end
+
+function resolvers.findbinfile(name,kind)
+ if not kind or kind == "" then
+ kind = file.extname(name) -- string.match(name,"%.([^%.]-)$")
+ end
+ return resolvers.find_file(name,(kind and remapper[kind]) or kind)
+end
diff --git a/tex/context/base/luat-env.lua b/tex/context/base/luat-env.lua
index 67e2f7050..9c05b249c 100644
--- a/tex/context/base/luat-env.lua
+++ b/tex/context/base/luat-env.lua
@@ -1,50 +1,217 @@
--- filename : luat-env.lua
--- comment : companion to luat-env.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['luat-env'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
--- here we don't assume any extra libraries
-
--- A former version provides functionality for non embeded core
+-- A former version provided functionality for non embeded core
-- scripts i.e. runtime library loading. Given the amount of
-- Lua code we use now, this no longer makes sense. Much of this
--- evolved before bytecode arrays were available. Much code has
--- disappeared already.
+-- evolved before bytecode arrays were available and so a lot of
+-- code has disappeared already.
-if not versions then versions = { } end versions['luat-env'] = 1.001
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
--- environment
+local format = string.format
+
+-- precautions
+
+os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
+
+function os.setlocale()
+ -- no way you can mess with it
+end
-if not environment then environment = { } end
+-- dirty tricks
-environment.trace = false
+if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
+ arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
+end
+
+if profiler and os.env["MTX_PROFILE_RUN"] == "YES" then
+ profiler.start("luatex-profile.log")
+end
+
+-- environment
--- kpse is overloaded by this time
+environment = environment or { }
+environment.arguments = { }
+environment.files = { }
+environment.sortedflags = nil
if not environment.jobname or environment.jobname == "" then if tex then environment.jobname = tex.jobname end end
if not environment.version or environment.version == "" then environment.version = "unknown" end
+if not environment.jobname then environment.jobname = "unknown" end
+
+function environment.initialize_arguments(arg)
+ local arguments, files = { }, { }
+ environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
+ for index, argument in pairs(arg) do
+ if index > 0 then
+ local flag, value = argument:match("^%-+(.+)=(.-)$")
+ if flag then
+ arguments[flag] = string.unquote(value or "")
+ else
+ flag = argument:match("^%-+(.+)")
+ if flag then
+ arguments[flag] = true
+ else
+ files[#files+1] = argument
+ end
+ end
+ end
+ end
+ environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
+end
+
+function environment.setargument(name,value)
+ environment.arguments[name] = value
+end
+
+-- todo: defaults, better checks e.g on type (boolean versus string)
+--
+-- tricky: too many hits when we support partials unless we add
+-- a registration of arguments so from now on we have 'partial'
+
+function environment.argument(name,partial)
+ local arguments, sortedflags = environment.arguments, environment.sortedflags
+ if arguments[name] then
+ return arguments[name]
+ elseif partial then
+ if not sortedflags then
+ sortedflags = { }
+ for _,v in pairs(table.sortedkeys(arguments)) do
+ sortedflags[#sortedflags+1] = "^" .. v
+ end
+ environment.sortedflags = sortedflags
+ end
+ -- example of potential clash: ^mode ^modefile
+ for _,v in ipairs(sortedflags) do
+ if name:find(v) then
+ return arguments[v:sub(2,#v)]
+ end
+ end
+ end
+ return nil
+end
+
+function environment.split_arguments(separator) -- rather special, cut-off before separator
+ local done, before, after = false, { }, { }
+ for _,v in ipairs(environment.original_arguments) do
+ if not done and v == separator then
+ done = true
+ elseif done then
+ after[#after+1] = v
+ else
+ before[#before+1] = v
+ end
+ end
+ return before, after
+end
+
+function environment.reconstruct_commandline(arg,noquote)
+ arg = arg or environment.original_arguments
+ if noquote and #arg == 1 then
+ local a = arg[1]
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ return a
+ elseif next(arg) then
+ local result = { }
+ for _,a in ipairs(arg) do -- ipairs 1 .. #n
+ a = resolvers.resolve(a)
+ a = a:unquote()
+ a = a:gsub('"','\\"') -- tricky
+ if a:find(" ") then
+ result[#result+1] = a:quote()
+ else
+ result[#result+1] = a
+ end
+ end
+ return table.join(result," ")
+ else
+ return ""
+ end
+end
+
+if arg then
+
+ -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
+ local newarg, instring = { }, false
+
+ for index, argument in ipairs(arg) do
+ if argument:find("^\"") then
+ newarg[#newarg+1] = argument:gsub("^\"","")
+ if not argument:find("\"$") then
+ instring = true
+ end
+ elseif argument:find("\"$") then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
+ instring = false
+ elseif instring then
+ newarg[#newarg] = newarg[#newarg] .. " " .. argument
+ else
+ newarg[#newarg+1] = argument
+ end
+ end
+ for i=1,-5,-1 do
+ newarg[i] = arg[i]
+ end
+
+ environment.initialize_arguments(newarg)
+ environment.original_arguments = newarg
+ environment.raw_arguments = arg
+
+ arg = { } -- prevent duplicate handling
+
+end
+
+-- weird place ... depends on a not yet loaded module
function environment.texfile(filename)
- return input.find_file(filename,'tex')
+ return resolvers.find_file(filename,'tex')
end
function environment.luafile(filename)
- return input.find_file(filename,'tex') or input.find_file(filename,'texmfscripts')
+ local resolved = resolvers.find_file(filename,'tex') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ resolved = resolvers.find_file(filename,'texmfscripts') or ""
+ if resolved ~= "" then
+ return resolved
+ end
+ return resolvers.find_file(filename,'luatexlibs') or ""
end
-if not environment.jobname then environment.jobname = "unknown" end
-
environment.loadedluacode = loadfile -- can be overloaded
+--~ function environment.loadedluacode(name)
+--~ if os.spawn("texluac -s -o texluac.luc " .. name) == 0 then
+--~ local chunk = loadstring(io.loaddata("texluac.luc"))
+--~ os.remove("texluac.luc")
+--~ return chunk
+--~ else
+--~ environment.loadedluacode = loadfile -- can be overloaded
+--~ return loadfile(name)
+--~ end
+--~ end
+
function environment.luafilechunk(filename) -- used for loading lua bytecode in the format
filename = file.replacesuffix(filename, "lua")
local fullname = environment.luafile(filename)
if fullname and fullname ~= "" then
- input.report("loading file %s", fullname)
+ if trace_verbose then
+ logs.report("fileio","loading file %s", fullname)
+ end
return environment.loadedluacode(fullname)
else
- input.report("unknown file %s", filename)
+ if trace_verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
return nil
end
end
@@ -62,7 +229,9 @@ function environment.loadluafile(filename, version)
-- when not overloaded by explicit suffix we look for a luc file first
local fullname = (lucname and environment.luafile(lucname)) or ""
if fullname ~= "" then
- input.report("loading %s", fullname)
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
chunk = loadfile(fullname) -- this way we don't need a file exists check
end
if chunk then
@@ -78,7 +247,9 @@ function environment.loadluafile(filename, version)
if v == version then
return true
else
- input.report("version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ if trace_verbose then
+ logs.report("fileio","version mismatch for %s: lua=%s, luc=%s", filename, v, version)
+ end
environment.loadluafile(filename)
end
else
@@ -87,10 +258,14 @@ function environment.loadluafile(filename, version)
end
fullname = (luaname and environment.luafile(luaname)) or ""
if fullname ~= "" then
- input.report("loading %s", fullname)
+ if trace_verbose then
+ logs.report("fileio","loading %s", fullname)
+ end
chunk = loadfile(fullname) -- this way we don't need a file exists check
if not chunk then
- input.report("unknown file %s", filename)
+ if verbose then
+ logs.report("fileio","unknown file %s", filename)
+ end
else
assert(chunk)()
return true
@@ -98,82 +273,3 @@ function environment.loadluafile(filename, version)
end
return false
end
-
--- -- -- the next function was posted by Peter Cawley on the lua list -- -- --
--- -- -- -- -- --
--- -- -- stripping makes the compressed format file about 1MB smaller -- -- --
--- -- -- -- -- --
--- -- -- using this trick is at your own risk -- -- --
--- -- -- -- -- --
--- -- -- this is just an experiment, this feature may disappear -- -- --
-
-local function strip_code(dump)
- local version, format, endian, int, size, ins, num = dump:byte(5, 11)
- local subint
- if endian == 1 then
- subint = function(dump, i, l)
- local val = 0
- for n = l, 1, -1 do
- val = val * 256 + dump:byte(i + n - 1)
- end
- return val, i + l
- end
- else
- subint = function(dump, i, l)
- local val = 0
- for n = 1, l, 1 do
- val = val * 256 + dump:byte(i + n - 1)
- end
- return val, i + l
- end
- end
- local strip_function
- strip_function = function(dump)
- local count, offset = subint(dump, 1, size)
- local stripped, dirty = string.rep("\0", size), offset + count
- offset = offset + count + int * 2 + 4
- offset = offset + int + subint(dump, offset, int) * ins
- count, offset = subint(dump, offset, int)
- for n = 1, count do
- local t
- t, offset = subint(dump, offset, 1)
- if t == 1 then
- offset = offset + 1
- elseif t == 4 then
- offset = offset + size + subint(dump, offset, size)
- elseif t == 3 then
- offset = offset + num
- end
- end
- count, offset = subint(dump, offset, int)
- stripped = stripped .. dump:sub(dirty, offset - 1)
- for n = 1, count do
- local proto, off = strip_function(dump:sub(offset, -1))
- stripped, offset = stripped .. proto, offset + off - 1
- end
- offset = offset + subint(dump, offset, int) * int + int
- count, offset = subint(dump, offset, int)
- for n = 1, count do
- offset = offset + subint(dump, offset, size) + size + int * 2
- end
- count, offset = subint(dump, offset, int)
- for n = 1, count do
- offset = offset + subint(dump, offset, size) + size
- end
- stripped = stripped .. string.rep("\0", int * 3)
- return stripped, offset
- end
- return dump:sub(1,12) .. strip_function(dump:sub(13,-1))
-end
-
-environment.stripcode = false -- true
-
-function environment.loadedluacode(fullname)
- if environment.stripcode then
- return loadstring(strip_code(string.dump(loadstring(io.loaddata(fullname)))))
- else
- return loadfile(fullname)
- end
-end
-
--- -- end of stripping code -- --
diff --git a/tex/context/base/luat-env.tex b/tex/context/base/luat-env.tex
deleted file mode 100644
index 164be174c..000000000
--- a/tex/context/base/luat-env.tex
+++ /dev/null
@@ -1,172 +0,0 @@
-%D \module
-%D [ file=luat-env,
-%D version=2005.05.26,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=ConTeXt features,
-%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 Originally we compiled the lua files externally and loaded
-%D then at runtime, but when the amount grew, we realized that
-%D we needed away to store them in the format, which is what
-%D bytecode arrays do. And so the following is obsolete:
-%D
-%D \starttyping
-%D \chardef\ctxluaembeddingmode \plusone
-%D
-%D 0 = external compilation and loading
-%D 1 = runtime compilation and embedding
-%D \stoptyping
-
-% \writestatus{loading}{Lua Support Macros (environment)}
-
-% print (lua.id)
-% print (lua.version)
-% print (lua.startupfile)
-
-%D Allocation of \LUA\ engines.
-
-\newcount\luadefcounter
-
-\ifx\zerocount\undefined \chardef\zerocount=0 \fi
-\ifx\plusone \undefined \chardef\plusone =1 \fi
-
-\def\newlua#1%
- {\global\advance\luadefcounter\plusone
- \mathchardef#1\luadefcounter}
-
-%D We use a dedicated instance for \CONTEXT\ core functionality. In
-%D \CONTEXT we also use this as callback instance. Instance 0 is
-%D the scratch instance.
-
-\ifx\luastartup\undefined \newcount\luastartup \fi
-
-\chardef\CTXlua\zerocount \luadefcounter\CTXlua \luastartup\CTXlua
-
-\def\ctxdirectlua{\directlua\CTXlua} \let\ctxlua\ctxdirectlua
-\def\ctxlatelua {\latelua \CTXlua}
-
-%D The simple \type {\lua} command is just a shortcut to the
-%D zero instance. Beware, we don't use the 0--9 range for
-%D scratch purposes as we do with other registers. First of all
-%D we want to avoid the overhead, but mostly, users can just define
-%D their own.
-
-\newlua \luadefault
-
-\def \lua {\directlua\luadefault} % zero is the main one, and reserved for ctx
-\edef\luaversion{\ctxlua{tex.print(_VERSION)}}
-
-%D We want to define \LUA\ related things in the format but
-%D need to reluad code because \LUA\ instances are not dumped
-%D into the format.
-
-\ifx\undefined\normaleveryjob \let\normaleveryjob\everyjob \newtoks\everyjob \fi
-
-\newtoks\everyloadluacode
-\newtoks\everyfinalizeluacode
-
-\normaleveryjob{\the\everyloadluacode\the\everyfinalizeluacode\the\everyjob}
-
-\newif\ifproductionrun
-
-\long\def\startruntimeluacode#1\stopruntimeluacode % only simple code (load +init)
- {\ifproductionrun
- \global\let\startruntimeluacode\relax
- \global\let\stopruntimeluacode \relax
- \else
- \global\everyloadluacode\expandafter{\the\everyloadluacode#1}%
- \fi
- #1} % maybe no interference
-
-\long\def\startruntimectxluacode#1\stopruntimectxluacode
- {\startruntimeluacode\ctxlua{#1}\stopruntimeluacode}
-
-%D Next we load the initialization code.
-
-\startruntimectxluacode
- environment = environment or { }
- environment.jobname = "\jobname" % tex.jobname
- environment.initex = \ifproductionrun false \else true \fi % tex.formatname == ""
- environment.version = "\contextversion"
-\stopruntimectxluacode
-
-\chardef\ctxluaexecutionmode \zerocount % private
-
-% we start at 500, below this, we store predefined data (dumps)
-
-\newcount\luabytecodecounter \luabytecodecounter=500
-
-\startruntimectxluacode
- if not lua.bytedata then lua.bytedata = { } end
-\stopruntimectxluacode
-
-%D Handy when we expand:
-
-\let\stopruntimeluacode \relax
-\let\stopruntimectxluacode\relax
-
-\ifx\normalprotected \undefined \let\normalprotected \protected \fi
-\ifx\normalunexpanded\undefined \let\normalunexpanded\unexpanded \fi
-\ifx\normalexpanded \undefined \let\normalexpanded \expanded \fi
-
-\long\def\lastexpanded{} % todo: elsewhere we use \@@expanded
-
-\long\def\expanded#1{\long\xdef\lastexpanded{\noexpand#1}\lastexpanded}
-
-%D More code:
-
-\def\ctxluabytecode#1% executes an already loaded chunk
- {\ctxlua {
- do
- local str = ''
- if lua.bytedata[#1] then
- str = " from file " .. lua.bytedata[#1][1] .. " version " .. lua.bytedata[#1][2]
- end
- if lua.bytecode[#1] then
- if environment.initex then
- % logs.report("bytecode","executing blob " .. "#1" .. str)
- assert(lua.bytecode[#1])()
- else
- assert(lua.bytecode[#1])()
- lua.bytecode[#1] = nil
- end
- else
- % logs.report("bytecode", "invalid blob " .. "#1" .. str)
- end
- end
- }}
-
-\def\ctxluabyteload#1#2% registers and compiles chunk
- {\global\advance\luabytecodecounter \plusone
- \expanded{\startruntimectxluacode
- lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
- \stopruntimectxluacode}%
- \ctxlua {
- lua.bytedata[\the\luabytecodecounter] = { "#1", "#2" }
- lua.bytecode[\the\luabytecodecounter] = environment.luafilechunk("#1")
- }}
-
-\def\ctxloadluafile#1#2% load a (either not compiled) chunk at runtime
- {\doifelsenothing{#2}
- {\ctxlua{environment.loadluafile("#1")}}
- {\ctxlua{environment.loadluafile("#1",#2)}}}
-
-\def\registerctxluafile#1#2% name version
- {\ifproductionrun \else
- \ctxluabyteload{#1}{#2}%
- \fi
- \global\everyloadluacode\expandafter\expandafter\expandafter{\expandafter\the\expandafter\everyloadluacode
- \expandafter\ctxluabytecode\expandafter{\the\luabytecodecounter}}%
- \ifcase\ctxluaexecutionmode\or\ctxluabytecode{\the\luabytecodecounter}\fi}
-
-\registerctxluafile{luat-env}{1.001}
-
-\chardef\ctxluaexecutionmode \plusone
-
-\endinput
diff --git a/tex/context/base/luat-exe.lua b/tex/context/base/luat-exe.lua
index c2245d568..fd93ad382 100644
--- a/tex/context/base/luat-exe.lua
+++ b/tex/context/base/luat-exe.lua
@@ -1,10 +1,11 @@
--- filename : luat-exe.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['luat-exe'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['luat-exe'] = 1.001
if not executer then executer = { } end
executer.permitted = { }
diff --git a/tex/context/base/luat-fio.lua b/tex/context/base/luat-fio.lua
new file mode 100644
index 000000000..3f42b4497
--- /dev/null
+++ b/tex/context/base/luat-fio.lua
@@ -0,0 +1,81 @@
+if not modules then modules = { } end modules ['luat-fio'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texiowrite_nl = (texio and texio.write_nl) or print
+local texiowrite = (texio and texio.write) or print
+
+local format = string.format
+
+texconfig.kpse_init = false
+texconfig.trace_file_names = true -- also influences pdf fonts reporting .. todo
+texconfig.max_print_line = 100000
+
+kpse = { } setmetatable(kpse, { __index = function(k,v) return input[v] end } )
+
+-- if still present, we overload kpse (put it off-line so to say)
+
+if not resolvers.instance then
+
+ resolvers.reset()
+
+ resolvers.instance.progname = 'context'
+ resolvers.instance.engine = 'luatex'
+ resolvers.instance.validfile = resolvers.validctxfile
+
+ resolvers.load()
+
+ if callback then
+
+ callback.register('find_read_file' , function(id,name) return resolvers.findtexfile(name) end)
+ callback.register('open_read_file' , function( name) return resolvers.opentexfile(name) end)
+
+ callback.register('find_data_file' , function(name) return resolvers.findbinfile(name,"tex") end)
+ callback.register('find_enc_file' , function(name) return resolvers.findbinfile(name,"enc") end)
+ callback.register('find_font_file' , function(name) return resolvers.findbinfile(name,"tfm") end)
+ callback.register('find_format_file' , function(name) return resolvers.findbinfile(name,"fmt") end)
+ callback.register('find_image_file' , function(name) return resolvers.findbinfile(name,"tex") end)
+ callback.register('find_map_file' , function(name) return resolvers.findbinfile(name,"map") end)
+ callback.register('find_ocp_file' , function(name) return resolvers.findbinfile(name,"ocp") end)
+ callback.register('find_opentype_file' , function(name) return resolvers.findbinfile(name,"otf") end)
+ callback.register('find_output_file' , function(name) return name end)
+ callback.register('find_pk_file' , function(name) return resolvers.findbinfile(name,"pk") end)
+ callback.register('find_sfd_file' , function(name) return resolvers.findbinfile(name,"sfd") end)
+ callback.register('find_truetype_file' , function(name) return resolvers.findbinfile(name,"ttf") end)
+ callback.register('find_type1_file' , function(name) return resolvers.findbinfile(name,"pfb") end)
+ callback.register('find_vf_file' , function(name) return resolvers.findbinfile(name,"vf") end)
+
+ callback.register('read_data_file' , function(file) return resolvers.loadbinfile(file,"tex") end)
+ callback.register('read_enc_file' , function(file) return resolvers.loadbinfile(file,"enc") end)
+ callback.register('read_font_file' , function(file) return resolvers.loadbinfile(file,"tfm") end)
+ -- format
+ -- image
+ callback.register('read_map_file' , function(file) return resolvers.loadbinfile(file,"map") end)
+ callback.register('read_ocp_file' , function(file) return resolvers.loadbinfile(file,"ocp") end)
+ -- callback.register('read_opentype_file' , function(file) return resolvers.loadbinfile(file,"otf") end)
+ -- output
+ callback.register('read_pk_file' , function(file) return resolvers.loadbinfile(file,"pk") end)
+ callback.register('read_sfd_file' , function(file) return resolvers.loadbinfile(file,"sfd") end)
+ -- callback.register('read_truetype_file' , function(file) return resolvers.loadbinfile(file,"ttf") end)
+ -- callback.register('read_type1_file' , function(file) return resolvers.loadbinfile(file,"pfb") end)
+ callback.register('read_vf_file' , function(file) return resolvers.loadbinfile(file,"vf" ) end)
+
+ callback.register('find_font_file' , function(name) return resolvers.findbinfile(name,"ofm") end)
+ callback.register('read_font_file' , function(file) return resolvers.loadbinfile(file,"ofm") end)
+ callback.register('find_vf_file' , function(name) return resolvers.findbinfile(name,"ovf") end)
+ callback.register('read_vf_file' , function(file) return resolvers.loadbinfile(file,"ovf") end)
+
+ callback.register('find_write_file' , function(id,name) return name end)
+ callback.register('find_format_file' , function(name) return name end)
+
+ end
+
+end
+
+statistics.register("input load time", function()
+ return format("%s seconds", statistics.elapsedtime(resolvers.instance))
+end)
diff --git a/tex/context/base/luat-ini.lua b/tex/context/base/luat-ini.lua
index 092593541..d9f39e61b 100644
--- a/tex/context/base/luat-ini.lua
+++ b/tex/context/base/luat-ini.lua
@@ -6,15 +6,25 @@ if not modules then modules = { } end modules ['luat-ini'] = {
license = "see context related readme files"
}
+--~ local ctxcatcodes = tex.ctxcatcodes
+
--[[ldx--
<p>We cannot load anything yet. However what we will do us reserve a fewtables.
These can be used for runtime user data or third party modules and will not be
cluttered by macro package code.</p>
--ldx]]--
-userdata = userdata or { }
-thirddata = thirddata or { }
-document = document or { }
+userdata = userdata or { } -- might be used
+thirddata = thirddata or { } -- might be used
+moduledata = moduledata or { } -- might be used
+document = document or { }
+
+--[[ldx--
+<p>These can be used/set by the caller program; <t>mtx-context.lua</t> does it.</p>
+--ldx]]--
+
+document.arguments = document.arguments or { }
+document.files = document.files or { }
--[[ldx--
<p>Please create a namespace within these tables before using them!</p>
@@ -24,3 +34,116 @@ userdata ['my.name'] = { }
thirddata['tricks' ] = { }
</typing>
--ldx]]--
+
+--[[ldx--
+<p>We could cook up a readonly model for global tables but it
+makes more sense to invite users to use one of the predefined
+namespaces. One can redefine the protector. After all, it's
+just a lightweight suggestive system, not a watertight
+one.</p>
+--ldx]]--
+
+local string, table, lpeg, math, io, system = string, table, lpeg, math, io, system
+local next, setfenv = next, setfenv
+local format = string.format
+
+local global = _G
+
+global.global = global
+
+local dummy = function() end
+
+local protected = {
+ -- global table
+ global = global,
+ -- user tables
+ userdata = userdata,
+ moduledata = moduledata,
+ thirddata = thirddata,
+ document = document,
+ -- reserved
+ protect = dummy,
+ unprotect = dummy,
+ -- luatex
+ tex = tex,
+ -- lua
+ string = string,
+ table = table,
+ lpeg = lpeg,
+ math = math,
+ io = io,
+ system = system,
+}
+
+userdata, thirddata, moduledata = nil, nil, nil
+
+function protect(name)
+ if name == "isolateddata" then
+ local t = { }
+ for k, v in next, protected do
+ t[k] = v
+ end
+ setfenv(2,t)
+ else
+ if not name then
+ name = "shareddata"
+ end
+ local t = global[name]
+ if not t then
+ t = { }
+ for k, v in next, protected do
+ t[k] = v
+ end
+ global[name] = t
+ end
+ setfenv(2,t)
+ end
+end
+
+lua.numbers = { }
+lua.messages = { }
+
+function lua.registername(name,message)
+ local lnn = lua.numbers[name]
+ if not lnn then
+ lnn = #lua.messages + 1
+ lua.messages[lnn] = message
+ lua.numbers[name] = lnn
+ end
+ lua.name[lnn] = message
+ tex.write(lnn)
+end
+
+--~ function lua.checknames()
+--~ lua.name[0] = "ctx"
+--~ for k, v in next, lua.messages do
+--~ lua.name[k] = v
+--~ end
+--~ end
+
+storage.register("lua/numbers", lua.numbers, "lua.numbers")
+storage.register("lua/messages", lua.messages, "lua.messages")
+
+function document.setargument(key,value)
+ document.arguments[key] = value
+end
+
+function document.setdefaultargument(key,default)
+ local v = document.arguments[key]
+ if v == nil or v == "" then
+ document.arguments[key] = default
+ end
+end
+
+function document.getargument(key,default)
+ local v = document.arguments[key]
+ if type(v) == "boolean" then
+ v = (v and "yes") or "no"
+ document.arguments[key] = v
+ end
+ tex.sprint(tex.ctxcatcodes,v or default or "")
+end
+
+function document.getfilename(i)
+ tex.sprint(tex.ctxcatcodes,document.files[i] or "")
+end
diff --git a/tex/context/base/luat-ini.tex b/tex/context/base/luat-ini.tex
index 1e1e20ebe..265f1b643 100644
--- a/tex/context/base/luat-ini.tex
+++ b/tex/context/base/luat-ini.tex
@@ -11,15 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Lua Support Macros (initialization)}
+\writestatus{loading}{ConTeXt Lua Macros / Initialization}
\unprotect
-%D We have to load this module in a very early stage. Therefore we
-%D cannot rely on support macros being available.
-
-% \long\def\rescan#1{\expanded{\scantextokens{#1}}}
-
%D Loading lua code can be done using \type {startup.lua}. The following
%D method uses the \TEX\ input file locator of kpse. At least we need to
%D use that way of loading when we haven't yet define our own code, which
@@ -30,36 +25,27 @@
\ifx\obeylualines \undefined \let\obeylualines \relax \fi
\ifx\obeyluatokens \undefined \let\obeyluatokens \relax \fi
-% \def\loadluacode#1#2% instance filename
-% {\bgroup
-% \everyeof{\noexpand}% hack to make \input nicely expandable
-% \setnaturalcatcodes
-% \obeylualines
-% %message{[Lua Load: #2]}%
-% \directlua#1\expandafter{\normalinput#2\space}\relax
-% \egroup}
-
%D A few more goodies:
-\long\def\dostartlua#1%
+\long\def\dostartlua
{\begingroup
\obeylualines
- \dodostartlua{#1}}
+ \dodostartlua}
-\long\def\dodostartlua#1#2\stoplua
- {\expanded{\endgroup\noexpand\directlua#1{#2}}}
+\long\def\dodostartlua#1\stoplua
+ {\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
-\long\def\dostartluacode#1%
+\long\def\dostartluacode
{\begingroup
\obeylualines
\obeyluatokens
- \dodostartluacode{#1}}
+ \dodostartluacode}
-\long\def\dodostartluacode#1#2\stopluacode
- {\expanded{\endgroup\noexpand\directlua#1{#2}}}
+\long\def\dodostartluacode#1\stopluacode
+ {\normalexpanded{\endgroup\noexpand\directlua\zerocount{#1}}}
-\def\startlua {\dostartlua \zerocount}
-\def\startluacode{\dostartluacode\zerocount}
+\def\startlua {\dostartlua } % tex catcodes
+\def\startluacode{\dostartluacode} % lua catcodes
%D Some delayed definitions:
@@ -69,40 +55,164 @@
\ifx\obeyedspace \undefined \let\obeyedspace \relax \fi
\ifx\outputnewlinechar\undefined \let\outputnewlinechar\relax \fi
-\def\obeylualines
- {\obeylines \let\obeyedline \outputnewlinechar
- \obeyspaces \let\obeyedspace\space}
-
-\def\obeyluatokens % todo: make this a proper catcode table, use let's
- {\catcode`\%=12 \catcode`\#=12
- \catcode`\_=12 \catcode`\^=12
- \catcode`\&=12 \catcode`\|=12
- \catcode`\{=12 \catcode`\}=12
- \catcode`\~=12 \catcode`\$=12
- \def\\{\string\\}\def\|{\string\|}\def\-{\string\-}%
- \def\({\string\(}\def\){\string\)}\def\{{\string\{}\def\}{\string\}}%
- \def\'{\string\'}\def\"{\string\"}%
- \def\n{\string\n}\def\r{\string\r}\def\f{\string\f}\def\t{\string\t}%
- \def\a{\string\a}\def\b{\string\b}\def\v{\string\v}\def\s{\string\s}%
- \def\1{\string1}\def\2{\string2}\def\3{\string3}\def\4{\string\4}\def\5{\string\5}%
- \def\6{\string6}\def\7{\string7}\def\8{\string8}\def\9{\string\9}\def\0{\string\0}}
-
+%D A previous version used a bit less code and no catcode table,
+%D simply becaus ethey were not around at the time of writing.
+%
+% we keep it around for archival purposes
+%
+% \def\obeylualines
+% {\obeylines \let\obeyedline \outputnewlinechar
+% \obeyspaces \let\obeyedspace\space}
+%
+% \def\obeyluatokens % todo: make this a proper catcode table, use let's
+% {\catcode`\%=12 \catcode`\#=12
+% \catcode`\_=12 \catcode`\^=12
+% \catcode`\&=12 \catcode`\|=12
+% \catcode`\{=12 \catcode`\}=12
+% \catcode`\~=12 \catcode`\$=12
+% \def\\{\string\\}\def\|{\string\|}\def\-{\string\-}%
+% \def\({\string\(}\def\){\string\)}\def\{{\string\{}\def\}{\string\}}%
+% \def\'{\string\'}\def\"{\string\"}%
+% \def\n{\string\n}\def\r{\string\r}\def\f{\string\f}\def\t{\string\t}%
+% \def\a{\string\a}\def\b{\string\b}\def\v{\string\v}\def\s{\string\s}%
+% \def\1{\string\1}\def\2{\string\2}\def\3{\string\3}\def\4{\string\4}\def\5{\string\5}%
+% \def\6{\string\6}\def\7{\string\7}\def\8{\string\8}\def\9{\string\9}\def\0{\string\0}}
+
+\let\obeylualines\relax
+
+\newtoks\everyluacode
+
+\edef\lualetterbackslash{\string\\}
+\edef\lualetterbar {\string\|} \edef\lualetterdash {\string\-}
+\edef\lualetterlparent {\string\(} \edef\lualetterrparent {\string\)}
+\edef\lualetterlbrace {\string\{} \edef\lualetterrbrace {\string\}}
+\edef\lualettersquote {\string\'} \edef\lualetterdquote {\string\"}
+\edef\lualettern {\string\n} \edef\lualetterr {\string\r}
+\edef\lualetterf {\string\f} \edef\lualettert {\string\t}
+\edef\lualettera {\string\a} \edef\lualetterb {\string\b}
+\edef\lualetterv {\string\v} \edef\lualetters {\string\s}
+\edef\lualetterone {\string\1} \edef\lualettertwo {\string\2}
+\edef\lualetterthree {\string\3} \edef\lualetterfour {\string\4}
+\edef\lualetterfive {\string\5} \edef\lualettersix {\string\6}
+\edef\lualetterseven {\string\7} \edef\lualettereight {\string\8}
+\edef\lualetternine {\string\9} \edef\lualetterzero {\string\0}
+
+\appendtoks
+ \let\\\lualetterbackslash
+ \let\|\lualetterbar \let\-\lualetterdash
+ \let\(\lualetterlparent \let\)\lualetterrparent
+ \let\{\lualetterlbrace \let\}\lualetterrbrace
+ \let\'\lualettersquote \let\"\lualetterdquote
+ \let\n\lualettern \let\r\lualetterr
+ \let\f\lualetterf \let\t\lualettert
+ \let\a\lualettera \let\b\lualetterb
+ \let\v\lualetterv \let\s\lualetters
+ \let\1\lualetterone \let\2\lualettertwo
+ \let\3\lualetterthree \let\4\lualetterfour
+ \let\5\lualetterfive \let\6\lualettersix
+ \let\7\lualetterseven \let\8\lualettereight
+ \let\9\lualetternine \let\0\lualetterzero
+\to \everyluacode
+
+\def\obeyluatokens
+ {\setcatcodetable \luacatcodes
+ \the\everyluacode}
+
+%D \macros
+%D {definenamedlua}
+%D
%D We provide an interface for defining instances:
-\def\s!lua{lua} \def\v!code{code} \let\@EA\expandafter
+\def\s!lua{lua} \def\v!code{code} \def\!!name{name} \def\s!data{data}
-\def\setluainstancename#1#2%
- {\ifproductionrun\else\appendtoks\setluainstancename{#1}{#2}\to\everyjob\fi
- \directlua0{if lua.instancename then lua.instancename[\number#1]="#2" end}}
+%D Beware: because \type {\expanded} is een convert command, the error
+%D message will show \type{<inserted text>} as part of the message.
-\def\definelua[#1]% no ptional arg handling here yet
- {\ifcsname#1\s!lua\endcsname\else\expandafter\newlua\csname#1\s!lua\endcsname\fi
- \setluainstancename{\csname#1\s!lua\endcsname}{#1}%
- \setevalue{\e!start#1\s!lua }{\noexpand\dostartlua \csname#1\s!lua\endcsname}%
- \setevalue{\e!start#1\s!lua\v!code}{\noexpand\dostartluacode\csname#1\s!lua\endcsname}%
- \setvalue {\e!stop #1\s!lua }{\dostoplua }%
- \setvalue {\e!stop #1\s!lua\v!code}{\dostopluacode}}
-
-\definelua[CTX] \setluainstancename\CTXlua{main ctx instance}
+\long\def\dostartnamedluacode#1%
+ {\begingroup
+ \obeylualines
+ \obeyluatokens
+ \csname dodostartnamed#1\v!code\endcsname}
+
+\ifdefined\closelua
+
+ \def\definenamedlua[#1]#2[#3]% no optional arg handling here yet
+ {\expanded{\long\def\csname dodostartnamed#1\v!code\endcsname####1\csname\e!stop#1\v!code\endcsname}%
+ {\normalexpanded{\endgroup\noexpand\directlua\!!name{#3}\zerocount{protect("#1\s!data")##1}}}%
+ \long\expandafter\def\csname\e!start#1\v!code\endcsname {\dostartnamedluacode{#1}}%
+ \long\expandafter\def\csname #1\v!code\endcsname##1{\directlua\!!name{#3}\zerocount{protect("#1\s!data")##1}}}
+
+\else
+
+ \def\definenamedlua[#1]#2[#3]% no optional arg handling here yet
+ {\scratchcounter\ctxlua{lua.registername("#1","#3")}%
+ \expanded{\long\edef\csname dodostartnamed#1\v!code\endcsname####1\csname\e!stop#1\v!code\endcsname}%
+ {\endgroup\noexpand\directlua\the\scratchcounter{protect("#1\s!data")##1}}%
+ \long\expandafter\def \csname\e!start#1\v!code\endcsname {\dostartnamedluacode{#1}}%
+ \long\expandafter\edef\csname #1\v!code\endcsname##1{\noexpand\directlua\the\scratchcounter{protect("#1\s!data")##1}}}
+
+\fi
+
+%D We predefine a few.
+
+\definenamedlua[user] [private user instance]
+\definenamedlua[third] [third party module instance]
+\definenamedlua[module] [module instance]
+\definenamedlua[isolated][isolated instance]
+
+%D In practice this works out as follows:
+%D
+%D \startbuffer
+%D \startluacode
+%D tex.print("LUA")
+%D \stopluacode
+%D
+%D \startusercode
+%D global.tex.print("USER 1")
+%D tex.print("USER 2")
+%D if characters then
+%D tex.print("ACCESS")
+%D else
+%D tex.print("NO ACCESS")
+%D end
+%D \stopusercode
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D We need a way to pass strings safely to \LUA\ without the
+%D need for tricky escaping. Compare:
+%D
+%D \starttyping
+%D \ctxlua {something("anything tricky can go here")}
+%D \ctxlua {something([\luastringsep[anything tricky can go here]\luastringsep])}
+%D \stoptyping
+
+\def\luastringsep{===} % this permits \typefile{self} otherwise nested b/e sep problems
+
+\edef\!!bs{[\luastringsep[}
+\edef\!!es{]\luastringsep]}
+
+%D We have a the following available as primitive so there is no need
+%D for it:
+%D
+%D \starttyping
+%D \long\edef\luaescapestring#1{\!!bs#1\!!es}
+%D \stoptyping
+
+\def\setdocumentfilename #1#2{\ctxlua{document.setfilename(#1,"#2")}}
+\def\setdocumentargument #1#2{\ctxlua{document.setargument("#1","#2")}}
+\def\setdefaultdocumentargument#1#2{\ctxlua{document.getargument("#1","#2")}}
+\def\getdocumentfilename #1{\ctxlua{document.getfilename(#1)}}
+\def\getdocumentargument #1{\ctxlua{document.getargument(#1)}}
+\def\doifdocumentargumentelse #1{\doifsomethingelse{\getdocumentargument{#1}}}
+\def\doifdocumentargument #1{\doifsomething {\getdocumentargument{#1}}}
+\def\doifnotdocumentargument #1{\doifnothing {\getdocumentargument{#1}}}
+
+\let\doifelsedocumentargument\doifdocumentargumentelse
+
+%D A handy helper:
+
+\def\luaexpanded#1{\luaescapestring\expandafter{\normalexpanded{#1}}}
\protect \endinput
diff --git a/tex/context/base/luat-inp.lua b/tex/context/base/luat-inp.lua
deleted file mode 100644
index d71ab3b73..000000000
--- a/tex/context/base/luat-inp.lua
+++ /dev/null
@@ -1,2300 +0,0 @@
-if not modules then modules = { } end modules ['luat-inp'] = {
- version = 1.001,
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
- comment = "companion to luat-lib.tex",
-}
-
--- TODO: os.getenv -> os.env[]
--- TODO: instances.[hashes,cnffiles,configurations,522] -> ipairs (alles check, sneller)
--- TODO: check escaping in find etc, too much, too slow
-
--- This lib is multi-purpose and can be loaded again later on so that
--- additional functionality becomes available. We will split this
--- module in components once we're done with prototyping. This is the
--- first code I wrote for LuaTeX, so it needs some cleanup. Before changing
--- something in this module one can best check with Taco or Hans first; there
--- is some nasty trickery going on that relates to traditional kpse support.
-
--- To be considered: hash key lowercase, first entry in table filename
--- (any case), rest paths (so no need for optimization). Or maybe a
--- separate table that matches lowercase names to mixed case when
--- present. In that case the lower() cases can go away. I will do that
--- only when we run into problems with names ... well ... Iwona-Regular.
-
--- Beware, loading and saving is overloaded in luat-tmp!
-
-if not input then input = { } end
-if not input.suffixes then input.suffixes = { } end
-if not input.formats then input.formats = { } end
-if not input.aux then input.aux = { } end
-
-if not input.suffixmap then input.suffixmap = { } end
-
-if not input.locators then input.locators = { } end -- locate databases
-if not input.hashers then input.hashers = { } end -- load databases
-if not input.generators then input.generators = { } end -- generate databases
-if not input.filters then input.filters = { } end -- conversion filters
-
-local format, concat, sortedkeys = string.format, table.concat, table.sortedkeys
-
-input.locators.notfound = { nil }
-input.hashers.notfound = { nil }
-input.generators.notfound = { nil }
-
-input.cacheversion = '1.0.1'
-input.banner = nil
-input.verbose = false
-input.debug = false
-input.cnfname = 'texmf.cnf'
-input.luaname = 'texmfcnf.lua'
-input.lsrname = 'ls-R'
-input.homedir = os.env[os.platform == "windows" and 'USERPROFILE'] or os.env['HOME'] or '~'
-
---~ input.luasuffix = 'tma'
---~ input.lucsuffix = 'tmc'
-
--- for the moment we have .local but this will disappear
-input.cnfdefault = '{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- chances are low that the cnf file is in the bin path
-input.cnfdefault = '{$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}'
-
--- we use a cleaned up list / format=any is a wildcard, as is *name
-
-input.formats['afm'] = 'AFMFONTS' input.suffixes['afm'] = { 'afm' }
-input.formats['enc'] = 'ENCFONTS' input.suffixes['enc'] = { 'enc' }
-input.formats['fmt'] = 'TEXFORMATS' input.suffixes['fmt'] = { 'fmt' }
-input.formats['map'] = 'TEXFONTMAPS' input.suffixes['map'] = { 'map' }
-input.formats['mp'] = 'MPINPUTS' input.suffixes['mp'] = { 'mp' }
-input.formats['ocp'] = 'OCPINPUTS' input.suffixes['ocp'] = { 'ocp' }
-input.formats['ofm'] = 'OFMFONTS' input.suffixes['ofm'] = { 'ofm', 'tfm' }
-input.formats['otf'] = 'OPENTYPEFONTS' input.suffixes['otf'] = { 'otf' } -- 'ttf'
-input.formats['opl'] = 'OPLFONTS' input.suffixes['opl'] = { 'opl' }
-input.formats['otp'] = 'OTPINPUTS' input.suffixes['otp'] = { 'otp' }
-input.formats['ovf'] = 'OVFFONTS' input.suffixes['ovf'] = { 'ovf', 'vf' }
-input.formats['ovp'] = 'OVPFONTS' input.suffixes['ovp'] = { 'ovp' }
-input.formats['tex'] = 'TEXINPUTS' input.suffixes['tex'] = { 'tex' }
-input.formats['tfm'] = 'TFMFONTS' input.suffixes['tfm'] = { 'tfm' }
-input.formats['ttf'] = 'TTFONTS' input.suffixes['ttf'] = { 'ttf', 'ttc' }
-input.formats['pfb'] = 'T1FONTS' input.suffixes['pfb'] = { 'pfb', 'pfa' }
-input.formats['vf'] = 'VFFONTS' input.suffixes['vf'] = { 'vf' }
-
-input.formats['fea'] = 'FONTFEATURES' input.suffixes['fea'] = { 'fea' }
-input.formats['cid'] = 'FONTCIDMAPS' input.suffixes['cid'] = { 'cid', 'cidmap' }
-
-input.formats ['texmfscripts'] = 'TEXMFSCRIPTS' -- new
-input.suffixes['texmfscripts'] = { 'rb', 'pl', 'py' } -- 'lua'
-
-input.formats ['lua'] = 'LUAINPUTS' -- new
-input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' }
-
--- here we catch a few new thingies (todo: add these paths to context.tmf)
---
--- FONTFEATURES = .;$TEXMF/fonts/fea//
--- FONTCIDMAPS = .;$TEXMF/fonts/cid//
-
-function input.checkconfigdata() -- not yet ok, no time for debugging now
- local instance = input.instance
- local function fix(varname,default)
- local proname = varname .. "." .. instance.progname or "crap"
- local p = instance.environment[proname]
- local v = instance.environment[varname]
- if not ((p and p ~= "") or (v and v ~= "")) then
- instance.variables[varname] = default -- or environment?
- end
- end
- local name = os.name
- if name == "windows" then
- fix("OSFONTDIR", "c:/windows/fonts//")
- elseif name == "macosx" then
- fix("OSFONTDIR", "$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//")
- else
- -- bad luck
- end
- fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") -- no progname, hm
- fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
- fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS")
-end
-
--- backward compatible ones
-
-input.alternatives = { }
-
-input.alternatives['map files'] = 'map'
-input.alternatives['enc files'] = 'enc'
-input.alternatives['cid files'] = 'cid'
-input.alternatives['fea files'] = 'fea'
-input.alternatives['opentype fonts'] = 'otf'
-input.alternatives['truetype fonts'] = 'ttf'
-input.alternatives['truetype collections'] = 'ttc'
-input.alternatives['type1 fonts'] = 'pfb'
-
--- obscure ones
-
-input.formats ['misc fonts'] = ''
-input.suffixes['misc fonts'] = { }
-
-input.formats ['sfd'] = 'SFDFONTS'
-input.suffixes ['sfd'] = { 'sfd' }
-input.alternatives['subfont definition files'] = 'sfd'
-
--- In practice we will work within one tds tree, but i want to keep
--- the option open to build tools that look at multiple trees, which is
--- why we keep the tree specific data in a table. We used to pass the
--- instance but for practical pusposes we now avoid this and use a
--- instance variable.
-
-function input.newinstance()
-
- local instance = { }
-
- instance.rootpath = ''
- instance.treepath = ''
- instance.progname = 'context'
- instance.engine = 'luatex'
- instance.format = ''
- instance.environment = { }
- instance.variables = { }
- instance.expansions = { }
- instance.files = { }
- instance.remap = { }
- instance.configuration = { }
- instance.setup = { }
- instance.order = { }
- instance.found = { }
- instance.foundintrees = { }
- instance.kpsevars = { }
- instance.hashes = { }
- instance.cnffiles = { }
- instance.luafiles = { }
- instance.lists = { }
- instance.remember = true
- instance.diskcache = true
- instance.renewcache = false
- instance.scandisk = true
- instance.cachepath = nil
- instance.loaderror = false
- instance.smallcache = false
- instance.sortdata = false
- instance.savelists = true
- instance.cleanuppaths = true
- instance.allresults = false
- instance.pattern = nil -- lists
- instance.kpseonly = false -- lists
- instance.loadtime = 0
- instance.starttime = 0
- instance.stoptime = 0
- instance.validfile = function(path,name) return true end
- instance.data = { } -- only for loading
- instance.force_suffixes = true
- instance.dummy_path_expr = "^!*unset/*$"
- instance.fakepaths = { }
- instance.lsrmode = false
-
- -- store once, freeze and faster (once reset we can best use instance.environment)
-
- for k,v in pairs(os.env) do
- instance.environment[k] = input.bare_variable(v)
- end
-
- -- cross referencing, delayed because we can add suffixes
-
- for k, v in pairs(input.suffixes) do
- for _, vv in pairs(v) do
- if vv then
- input.suffixmap[vv] = k
- end
- end
- end
-
- return instance
-
-end
-
-input.instance = input.instance or nil
-
-function input.reset()
- input.instance = input.newinstance()
- return input.instance
-end
-
-function input.reset_hashes()
- input.instance.lists = { }
- input.instance.found = { }
-end
-
-function input.bare_variable(str) -- assumes str is a string
- -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1")
- return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2"))
-end
-
-function input.settrace(n)
- input.trace = tonumber(n or 0)
- if input.trace > 0 then
- input.verbose = true
- end
-end
-
-input.log = (texio and texio.write_nl) or print
-
-function input.report(...)
- if input.verbose then
- input.log("<<"..format(...)..">>")
- end
-end
-
-function input.report(...)
- if input.trace > 0 then -- extra test
- input.log("<<"..format(...)..">>")
- end
-end
-
-input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRACE") or input.trace or 0))
-
--- These functions can be used to test the performance, especially
--- loading the database files.
-
-do
- local clock = os.gettimeofday or os.clock
-
- function input.hastimer(instance)
- return instance and instance.starttime
- end
-
- function input.starttiming(instance)
- if instance then
- local it = instance.timing
- if not it then
- it = 0
- end
- if it == 0 then
- instance.starttime = clock()
- if not instance.loadtime then
- instance.loadtime = 0
- end
- end
- instance.timing = it + 1
- end
- end
-
- function input.stoptiming(instance, report)
- if instance then
- local it = instance.timing
- if it > 1 then
- instance.timing = it - 1
- else
- local starttime = instance.starttime
- if starttime then
- local stoptime = clock()
- local loadtime = stoptime - starttime
- instance.stoptime = stoptime
- instance.loadtime = instance.loadtime + loadtime
- if report then
- input.report("load time %0.3f",loadtime)
- end
- instance.timing = 0
- return loadtime
- end
- end
- end
- return 0
- end
-
-end
-
-function input.elapsedtime(instance)
- return format("%0.3f",(instance and instance.loadtime) or 0)
-end
-
-function input.report_loadtime(instance)
- if instance then
- input.report('total load time %s', input.elapsedtime(instance))
- end
-end
-
-input.loadtime = input.elapsedtime
-
-function input.env(key)
- return input.instance.environment[key] or input.osenv(key)
-end
-
-function input.osenv(key)
- local ie = input.instance.environment
- local value = ie[key]
- if value == nil then
- -- local e = os.getenv(key)
- local e = os.env[key]
- if e == nil then
- -- value = "" -- false
- else
- value = input.bare_variable(e)
- end
- ie[key] = value
- end
- return value or ""
-end
-
--- we follow a rather traditional approach:
---
--- (1) texmf.cnf given in TEXMFCNF
--- (2) texmf.cnf searched in default variable
---
--- also we now follow the stupid route: if not set then just assume *one*
--- cnf file under texmf (i.e. distribution)
-
-input.ownpath = input.ownpath or nil
-input.ownbin = input.ownbin or arg[-2] or arg[-1] or arg[0] or "luatex"
-input.autoselfdir = true -- false may be handy for debugging
-
-function input.getownpath()
- if not input.ownpath then
- if input.autoselfdir and os.selfdir then
- input.ownpath = os.selfdir
- else
- local binary = input.ownbin
- if os.platform == "windows" then
- binary = file.replacesuffix(binary,"exe")
- end
- for p in string.gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
- local b = file.join(p,binary)
- if lfs.isfile(b) then
- -- we assume that after changing to the path the currentdir function
- -- resolves to the real location and use this side effect here; this
- -- trick is needed because on the mac installations use symlinks in the
- -- path instead of real locations
- local olddir = lfs.currentdir()
- if lfs.chdir(p) then
- local pp = lfs.currentdir()
- if input.verbose and p ~= pp then
- input.report("following symlink %s to %s",p,pp)
- end
- input.ownpath = pp
- lfs.chdir(olddir)
- else
- if input.verbose then
- input.report("unable to check path %s",p)
- end
- input.ownpath = p
- end
- break
- end
- end
- end
- if not input.ownpath then input.ownpath = '.' end
- end
- return input.ownpath
-end
-
-function input.identify_own()
- local instance = input.instance
- local ownpath = input.getownpath() or lfs.currentdir()
- local ie = instance.environment
- if ownpath then
- if input.env('SELFAUTOLOC') == "" then os.env['SELFAUTOLOC'] = file.collapse_path(ownpath) end
- if input.env('SELFAUTODIR') == "" then os.env['SELFAUTODIR'] = file.collapse_path(ownpath .. "/..") end
- if input.env('SELFAUTOPARENT') == "" then os.env['SELFAUTOPARENT'] = file.collapse_path(ownpath .. "/../..") end
- else
- input.verbose = true
- input.report("error: unable to locate ownpath")
- os.exit()
- end
- if input.env('TEXMFCNF') == "" then os.env['TEXMFCNF'] = input.cnfdefault end
- if input.env('TEXOS') == "" then os.env['TEXOS'] = input.env('SELFAUTODIR') end
- if input.env('TEXROOT') == "" then os.env['TEXROOT'] = input.env('SELFAUTOPARENT') end
- if input.verbose then
- for _,v in ipairs({"SELFAUTOLOC","SELFAUTODIR","SELFAUTOPARENT","TEXMFCNF"}) do
- input.report("variable %s set to %s",v,input.env(v) or "unknown")
- end
- end
- function input.identify_own() end
-end
-
-function input.identify_cnf()
- local instance = input.instance
- if #instance.cnffiles == 0 then
- -- fallback
- input.identify_own()
- -- the real search
- input.expand_variables()
- local t = input.split_path(input.env('TEXMFCNF'))
- t = input.aux.expanded_path(t)
- input.aux.expand_vars(t) -- redundant
- local function locate(filename,list)
- for _,v in ipairs(t) do
- local texmfcnf = input.normalize_name(file.join(v,filename))
- if lfs.isfile(texmfcnf) then
- table.insert(list,texmfcnf)
- end
- end
- end
- locate(input.luaname,instance.luafiles)
- locate(input.cnfname,instance.cnffiles)
- end
-end
-
-function input.load_cnf()
- local instance = input.instance
- local function loadoldconfigdata()
- for _, fname in ipairs(instance.cnffiles) do
- input.aux.load_cnf(fname)
- end
- end
- -- instance.cnffiles contain complete names now !
- if #instance.cnffiles == 0 then
- input.report("no cnf files found (TEXMFCNF may not be set/known)")
- else
- instance.rootpath = instance.cnffiles[1]
- for k,fname in ipairs(instance.cnffiles) do
- instance.cnffiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- if instance.lsrmode then
- loadoldconfigdata()
- elseif instance.diskcache and not instance.renewcache then
- input.loadoldconfig(instance.cnffiles)
- if instance.loaderror then
- loadoldconfigdata()
- input.saveoldconfig()
- end
- else
- loadoldconfigdata()
- if instance.renewcache then
- input.saveoldconfig()
- end
- end
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.load_lua()
- local instance = input.instance
- if #instance.luafiles == 0 then
- -- yet harmless
- else
- instance.rootpath = instance.luafiles[1]
- for k,fname in ipairs(instance.luafiles) do
- instance.luafiles[k] = input.normalize_name(fname:gsub("\\",'/'))
- end
- for i=1,3 do
- instance.rootpath = file.dirname(instance.rootpath)
- end
- instance.rootpath = input.normalize_name(instance.rootpath)
- input.loadnewconfig()
- input.aux.collapse_cnf_data()
- end
- input.checkconfigdata()
-end
-
-function input.aux.collapse_cnf_data() -- potential optimization: pass start index (setup and configuration are shared)
- local instance = input.instance
- for _,c in ipairs(instance.order) do
- for k,v in pairs(c) do
- if not instance.variables[k] then
- if instance.environment[k] then
- instance.variables[k] = instance.environment[k]
- else
- instance.kpsevars[k] = true
- instance.variables[k] = input.bare_variable(v)
- end
- end
- end
- end
-end
-
-function input.aux.load_cnf(fname)
- local instance = input.instance
- fname = input.clean_path(fname)
- local lname = file.replacesuffix(fname,'lua')
- local f = io.open(lname)
- if f then -- this will go
- f:close()
- local dname = file.dirname(fname)
- if not instance.configuration[dname] then
- input.aux.load_configuration(dname,lname)
- instance.order[#instance.order+1] = instance.configuration[dname]
- end
- else
- f = io.open(fname)
- if f then
- input.report("loading %s", fname)
- local line, data, n, k, v
- local dname = file.dirname(fname)
- if not instance.configuration[dname] then
- instance.configuration[dname] = { }
- instance.order[#instance.order+1] = instance.configuration[dname]
- end
- local data = instance.configuration[dname]
- while true do
- local line, n = f:read(), 0
- if line then
- while true do -- join lines
- line, n = line:gsub("\\%s*$", "")
- if n > 0 then
- line = line .. f:read()
- else
- break
- end
- end
- if not line:find("^[%%#]") then
- local k, v = (line:gsub("%s*%%.*$","")):match("%s*(.-)%s*=%s*(.-)%s*$")
- if k and v and not data[k] then
- data[k] = (v:gsub("[%%#].*",'')):gsub("~", "$HOME")
- instance.kpsevars[k] = true
- end
- end
- else
- break
- end
- end
- f:close()
- else
- input.report("skipping %s", fname)
- end
- end
-end
-
--- database loading
-
-function input.load_hash()
- local instance = input.instance
- input.locatelists()
- if instance.lsrmode then
- input.loadlists()
- elseif instance.diskcache and not instance.renewcache then
- input.loadfiles()
- if instance.loaderror then
- input.loadlists()
- input.savefiles()
- end
- else
- input.loadlists()
- if instance.renewcache then
- input.savefiles()
- end
- end
-end
-
-function input.aux.append_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash append: %s",tag)
- end
- table.insert(input.instance.hashes, { ['type']=type, ['tag']=tag, ['name']=name } )
-end
-
-function input.aux.prepend_hash(type,tag,name)
- if input.trace > 0 then
- input.logger("= hash prepend: %s",tag)
- end
- table.insert(input.instance.hashes, 1, { ['type']=type, ['tag']=tag, ['name']=name } )
-end
-
-function input.aux.extend_texmf_var(specification) -- crap, we could better prepend the hash
- local instance = input.instance
--- local t = input.expanded_path_list('TEXMF') -- full expansion
- local t = input.split_path(input.env('TEXMF'))
- table.insert(t,1,specification)
- local newspec = table.join(t,";")
- if instance.environment["TEXMF"] then
- instance.environment["TEXMF"] = newspec
- elseif instance.variables["TEXMF"] then
- instance.variables["TEXMF"] = newspec
- else
- -- weird
- end
- input.expand_variables()
- input.reset_hashes()
-end
-
--- locators
-
-function input.locatelists()
- local instance = input.instance
- for _, path in pairs(input.clean_path_list('TEXMF')) do
- input.report("locating list of %s",path)
- input.locatedatabase(input.normalize_name(path))
- end
-end
-
-function input.locatedatabase(specification)
- return input.methodhandler('locators', specification)
-end
-
-function input.locators.tex(specification)
- if specification and specification ~= '' and lfs.isdir(specification) then
- if input.trace > 0 then
- input.logger('! tex locator found: %s',specification)
- end
- input.aux.append_hash('file',specification,filename)
- elseif input.trace > 0 then
- input.logger('? tex locator not found: %s',specification)
- end
-end
-
--- hashers
-
-function input.hashdatabase(tag,name)
- return input.methodhandler('hashers',tag,name)
-end
-
-function input.loadfiles()
- local instance = input.instance
- instance.loaderror = false
- instance.files = { }
- if not instance.renewcache then
- for _, hash in ipairs(instance.hashes) do
- input.hashdatabase(hash.tag,hash.name)
- if instance.loaderror then break end
- end
- end
-end
-
-function input.hashers.tex(tag,name)
- input.aux.load_files(tag)
-end
-
--- generators:
-
-function input.loadlists()
- for _, hash in ipairs(input.instance.hashes) do
- input.generatedatabase(hash.tag)
- end
-end
-
-function input.generatedatabase(specification)
- return input.methodhandler('generators', specification)
-end
-
-local weird = lpeg.anywhere(lpeg.S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t"))
-
-function input.generators.tex(specification)
- local instance = input.instance
- local tag = specification
- if not instance.lsrmode and lfs.dir then
- input.report("scanning path %s",specification)
- instance.files[tag] = { }
- local files = instance.files[tag]
- local n, m, r = 0, 0, 0
- local spec = specification .. '/'
- local attributes = lfs.attributes
- local directory = lfs.dir
- local small = instance.smallcache
- local function action(path)
- local mode, full
- if path then
- full = spec .. path .. '/'
- else
- full = spec
- end
- for name in directory(full) do
- if name:find("^%.") then
- -- skip
- -- elseif name:find("[%~%`%!%#%$%%%^%&%*%(%)%=%{%}%[%]%:%;\"\'%|%<%>%,%?\n\r\t]") then -- too much escaped
- elseif weird:match(name) then
- -- texio.write_nl("skipping " .. name)
- -- skip
- else
- mode = attributes(full..name,'mode')
- if mode == 'directory' then
- m = m + 1
- if path then
- action(path..'/'..name)
- else
- action(name)
- end
- elseif path and mode == 'file' then
- n = n + 1
- local f = files[name]
- if f then
- if not small then
- if type(f) == 'string' then
- files[name] = { f, path }
- else
- f[#f+1] = path
- end
- end
- else
- files[name] = path
- local lower = name:lower()
- if name ~= lower then
- files["remap:"..lower] = name
- r = r + 1
- end
- end
- end
- end
- end
- end
- action()
- input.report("%s files found on %s directories with %s uppercase remappings",n,m,r)
- else
- local fullname = file.join(specification,input.lsrname)
- local path = '.'
- local f = io.open(fullname)
- if f then
- instance.files[tag] = { }
- local files = instance.files[tag]
- local small = instance.smallcache
- input.report("loading lsr file %s",fullname)
- -- for line in f:lines() do -- much slower then the next one
- for line in (f:read("*a")):gmatch("(.-)\n") do
- if line:find("^[%a%d]") then
- local fl = files[line]
- if fl then
- if not small then
- if type(fl) == 'string' then
- files[line] = { fl, path } -- table
- else
- fl[#fl+1] = path
- end
- end
- else
- files[line] = path -- string
- local lower = line:lower()
- if line ~= lower then
- files["remap:"..lower] = line
- end
- end
- else
- path = line:match("%.%/(.-)%:$") or path -- match could be nil due to empty line
- end
- end
- f:close()
- end
- end
-end
-
--- savers, todo
-
-function input.savefiles()
- input.aux.save_data('files', function(k,v)
- return input.instance.validfile(k,v) -- path, name
- end)
-end
-
--- A config (optionally) has the paths split in tables. Internally
--- we join them and split them after the expansion has taken place. This
--- is more convenient.
-
-function input.splitconfig()
- for i,c in ipairs(input.instance) do
- for k,v in pairs(c) do
- if type(v) == 'string' then
- local t = file.split_path(v)
- if #t > 1 then
- c[k] = t
- end
- end
- end
- end
-end
-
-function input.joinconfig()
- for i,c in ipairs(input.instance.order) do
- for k,v in pairs(c) do
- if type(v) == 'table' then
- c[k] = file.join_path(v)
- end
- end
- end
-end
-function input.split_path(str)
- if type(str) == 'table' then
- return str
- else
- return file.split_path(str)
- end
-end
-function input.join_path(str)
- if type(str) == 'table' then
- return file.join_path(str)
- else
- return str
- end
-end
-
-function input.splitexpansions()
- local ie = input.instance.expansions
- for k,v in pairs(ie) do
- local t, h = { }, { }
- for _,vv in pairs(file.split_path(v)) do
- if vv ~= "" and not h[vv] then
- t[#t+1] = vv
- h[vv] = true
- end
- end
- if #t > 1 then
- ie[k] = t
- else
- ie[k] = t[1]
- end
- end
-end
-
--- end of split/join code
-
-function input.saveoldconfig()
- input.splitconfig()
- input.aux.save_data('configuration', nil)
- input.joinconfig()
-end
-
-input.configbanner = [[
--- This is a Luatex configuration file created by 'luatools.lua' or
--- 'luatex.exe' directly. For comment, suggestions and questions you can
--- contact the ConTeXt Development Team. This configuration file is
--- not copyrighted. [HH & TH]
-]]
-
-function input.serialize(files)
- -- This version is somewhat optimized for the kind of
- -- tables that we deal with, so it's much faster than
- -- the generic serializer. This makes sense because
- -- luatools and mtxtools are called frequently. Okay,
- -- we pay a small price for properly tabbed tables.
- local t = { }
- local function dump(k,v,m)
- if type(v) == 'string' then
- return m .. "['" .. k .. "']='" .. v .. "',"
- elseif #v == 1 then
- return m .. "['" .. k .. "']='" .. v[1] .. "',"
- else
- return m .. "['" .. k .. "']={'" .. concat(v,"','").. "'},"
- end
- end
- t[#t+1] = "return {"
- if input.instance.sortdata then
- for _, k in pairs(sortedkeys(files)) do
- local fk = files[k]
- if type(fk) == 'table' then
- t[#t+1] = "\t['" .. k .. "']={"
- for _, kk in pairs(sortedkeys(fk)) do
- t[#t+1] = dump(kk,fk[kk],"\t\t")
- end
- t[#t+1] = "\t},"
- else
- t[#t+1] = dump(k,fk,"\t")
- end
- end
- else
- for k, v in pairs(files) do
- if type(v) == 'table' then
- t[#t+1] = "\t['" .. k .. "']={"
- for kk,vv in pairs(v) do
- t[#t+1] = dump(kk,vv,"\t\t")
- end
- t[#t+1] = "\t},"
- else
- t[#t+1] = dump(k,v,"\t")
- end
- end
- end
- t[#t+1] = "}"
- return concat(t,"\n")
-end
-
-if not texmf then texmf = {} end -- no longer needed, at least not here
-
-function input.aux.save_data(dataname, check, makename) -- untested without cache overload
- for cachename, files in pairs(input.instance[dataname]) do
- local name = (makename or file.join)(cachename,dataname)
- local luaname, lucname = name .. ".lua", name .. ".luc"
- input.report("preparing %s for %s",dataname,cachename)
- for k, v in pairs(files) do
- if not check or check(v,k) then -- path, name
- if type(v) == "table" and #v == 1 then
- files[k] = v[1]
- end
- else
- files[k] = nil -- false
- end
- end
- local data = {
- type = dataname,
- root = cachename,
- version = input.cacheversion,
- date = os.date("%Y-%m-%d"),
- time = os.date("%H:%M:%S"),
- content = files,
- }
- local ok = io.savedata(luaname,input.serialize(data))
- if ok then
- input.report("%s saved in %s",dataname,luaname)
- if utils.lua.compile(luaname,lucname,false,true) then -- no cleanup but strip
- input.report("%s compiled to %s",dataname,lucname)
- else
- input.report("compiling failed for %s, deleting file %s",dataname,lucname)
- os.remove(lucname)
- end
- else
- input.report("unable to save %s in %s (access error)",dataname,luaname)
- end
- end
-end
-
-function input.aux.load_data(pathname,dataname,filename,makename) -- untested without cache overload
- local instance = input.instance
- filename = ((not filename or (filename == "")) and dataname) or filename
- filename = (makename and makename(dataname,filename)) or file.join(pathname,filename)
- local blob = loadfile(filename .. ".luc") or loadfile(filename .. ".lua")
- if blob then
- local data = blob()
- if data and data.content and data.type == dataname and data.version == input.cacheversion then
- input.report("loading %s for %s from %s",dataname,pathname,filename)
- instance[dataname][pathname] = data.content
- else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
- instance[dataname][pathname] = { }
- instance.loaderror = true
- end
- else
- input.report("skipping %s for %s from %s",dataname,pathname,filename)
- end
-end
-
--- some day i'll use the nested approach, but not yet (actually we even drop
--- engine/progname support since we have only luatex now)
---
--- first texmfcnf.lua files are located, next the cached texmf.cnf files
---
--- return {
--- TEXMFBOGUS = 'effe checken of dit werkt',
--- }
-
-function input.aux.load_texmfcnf(dataname,pathname)
- local instance = input.instance
- local filename = file.join(pathname,input.luaname)
- local blob = loadfile(filename)
- if blob then
- local data = blob()
- if data then
- input.report("loading configuration file %s",filename)
- if true then
- -- flatten to variable.progname
- local t = { }
- for k, v in pairs(data) do -- v = progname
- if type(v) == "string" then
- t[k] = v
- else
- for kk, vv in pairs(v) do -- vv = variable
- if type(vv) == "string" then
- t[vv.."."..v] = kk
- end
- end
- end
- end
- instance[dataname][pathname] = t
- else
- instance[dataname][pathname] = data
- end
- else
- input.report("skipping configuration file %s",filename)
- instance[dataname][pathname] = { }
- instance.loaderror = true
- end
- else
- input.report("skipping configuration file %s",filename)
- end
-end
-
-function input.aux.load_configuration(dname,lname)
- input.aux.load_data(dname,'configuration',lname and file.basename(lname))
-end
-function input.aux.load_files(tag)
- input.aux.load_data(tag,'files')
-end
-
-function input.resetconfig()
- input.identify_own()
- local instance = input.instance
- instance.configuration, instance.setup, instance.order, instance.loaderror = { }, { }, { }, false
-end
-
-function input.loadnewconfig()
- local instance = input.instance
- for _, cnf in ipairs(instance.luafiles) do
- local dname = file.dirname(cnf)
- input.aux.load_texmfcnf('setup',dname)
- instance.order[#instance.order+1] = instance.setup[dname]
- if instance.loaderror then break end
- end
-end
-
-function input.loadoldconfig()
- local instance = input.instance
- if not instance.renewcache then
- for _, cnf in ipairs(instance.cnffiles) do
- local dname = file.dirname(cnf)
- input.aux.load_configuration(dname)
- instance.order[#instance.order+1] = instance.configuration[dname]
- if instance.loaderror then break end
- end
- end
- input.joinconfig()
-end
-
-function input.expand_variables()
- local instance = input.instance
- local expansions, environment, variables = { }, instance.environment, instance.variables
- local env = input.env
- instance.expansions = expansions
- if instance.engine ~= "" then environment['engine'] = instance.engine end
- if instance.progname ~= "" then environment['progname'] = instance.progname end
- for k,v in pairs(environment) do
- local a, b = k:match("^(%a+)%_(.*)%s*$")
- if a and b then
- expansions[a..'.'..b] = v
- else
- expansions[k] = v
- end
- end
- for k,v in pairs(environment) do -- move environment to expansions
- if not expansions[k] then expansions[k] = v end
- end
- for k,v in pairs(variables) do -- move variables to expansions
- if not expansions[k] then expansions[k] = v end
- end
- while true do
- local busy = false
- for k,v in pairs(expansions) do
- local s, n = v:gsub("%$([%a%d%_%-]+)", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
- local s, m = s:gsub("%$%{([%a%d%_%-]+)%}", function(a)
- busy = true
- return expansions[a] or env(a)
- end)
- if n > 0 or m > 0 then
- expansions[k]= s
- end
- end
- if not busy then break end
- end
- for k,v in pairs(expansions) do
- expansions[k] = v:gsub("\\", '/')
- end
-end
-
-function input.aux.expand_vars(lst) -- simple vars
- local instance = input.instance
- local variables, env = instance.variables, input.env
- for k,v in pairs(lst) do
- lst[k] = v:gsub("%$([%a%d%_%-]+)", function(a)
- return variables[a] or env(a)
- end)
- end
-end
-
-function input.aux.expanded_var(var) -- simple vars
- local instance = input.instance
- return var:gsub("%$([%a%d%_%-]+)", function(a)
- return instance.variables[a] or input.env(a)
- end)
-end
-
-function input.aux.entry(entries,name)
- if name and (name ~= "") then
- local instance = input.instance
- name = name:gsub('%$','')
- local result = entries[name..'.'..instance.progname] or entries[name]
- if result then
- return result
- else
- result = input.env(name)
- if result then
- instance.variables[name] = result
- input.expand_variables()
- return instance.expansions[name] or ""
- end
- end
- end
- return ""
-end
-function input.variable(name)
- return input.aux.entry(input.instance.variables,name)
-end
-function input.expansion(name)
- return input.aux.entry(input.instance.expansions,name)
-end
-
-function input.aux.is_entry(entries,name)
- if name and name ~= "" then
- name = name:gsub('%$','')
- return (entries[name..'.'..input.instance.progname] or entries[name]) ~= nil
- else
- return false
- end
-end
-
-function input.is_variable(name)
- return input.aux.is_entry(input.instance.variables,name)
-end
-
-function input.is_expansion(name)
- return input.aux.is_entry(input.instance.expansions,name)
-end
-
-function input.unexpanded_path_list(str)
- local pth = input.variable(str)
- local lst = input.split_path(pth)
- return input.aux.expanded_path(lst)
-end
-
-function input.unexpanded_path(str)
- return file.join_path(input.unexpanded_path_list(str))
-end
-
-do
- local done = { }
-
- function input.reset_extra_path()
- local instance = input.instance
- local ep = instance.extra_paths
- if not ep then
- ep, done = { }, { }
- instance.extra_paths = ep
- elseif #ep > 0 then
- instance.lists, done = { }, { }
- end
- end
-
- function input.register_extra_path(paths,subpaths)
- local instance = input.instance
- local ep = instance.extra_paths or { }
- local n = #ep
- if paths and paths ~= "" then
- if subpaths and subpaths ~= "" then
- for p in paths:gmatch("[^,]+") do
- -- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
- local ps = p .. "/" .. s
- if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
- done[ps] = true
- end
- end
- end
- else
- for p in paths:gmatch("[^,]+") do
- if not done[p] then
- ep[#ep+1] = input.clean_path(p)
- done[p] = true
- end
- end
- end
- elseif subpaths and subpaths ~= "" then
- for i=1,n do
- -- we gmatch each step again, not that fast, but used seldom
- for s in subpaths:gmatch("[^,]+") do
- local ps = ep[i] .. "/" .. s
- if not done[ps] then
- ep[#ep+1] = input.clean_path(ps)
- done[ps] = true
- end
- end
- end
- end
- if #ep > 0 then
- instance.extra_paths = ep -- register paths
- end
- if #ep > n then
- instance.lists = { } -- erase the cache
- end
- end
-
-end
-
-function input.expanded_path_list(str)
- local instance = input.instance
- local function made_list(list)
- local ep = instance.extra_paths
- if not ep or #ep == 0 then
- return list
- else
- local done, new = { }, { }
- -- honour . .. ../.. but only when at the start
- for k, v in ipairs(list) do
- if not done[v] then
- if v:find("^[%.%/]$") then
- done[v] = true
- new[#new+1] = v
- else
- break
- end
- end
- end
- -- first the extra paths
- for k, v in ipairs(ep) do
- if not done[v] then
- done[v] = true
- new[#new+1] = v
- end
- end
- -- next the formal paths
- for k, v in ipairs(list) do
- if not done[v] then
- done[v] = true
- new[#new+1] = v
- end
- end
- return new
- end
- end
- if not str then
- return ep or { }
- elseif instance.savelists then
- -- engine+progname hash
- str = str:gsub("%$","")
- if not instance.lists[str] then -- cached
- local lst = made_list(input.split_path(input.expansion(str)))
- instance.lists[str] = input.aux.expanded_path(lst)
- end
- return instance.lists[str]
- else
- local lst = input.split_path(input.expansion(str))
- return made_list(input.aux.expanded_path(lst))
- end
-end
-
-
-function input.clean_path_list(str)
- local t = input.expanded_path_list(str)
- if t then
- for i=1,#t do
- t[i] = file.collapse_path(input.clean_path(t[i]))
- end
- end
- return t
-end
-
-function input.expand_path(str)
- return file.join_path(input.expanded_path_list(str))
-end
-
-function input.expanded_path_list_from_var(str) -- brrr
- local tmp = input.var_of_format_or_suffix(str:gsub("%$",""))
- if tmp ~= "" then
- return input.expanded_path_list(str)
- else
- return input.expanded_path_list(tmp)
- end
-end
-function input.expand_path_from_var(str)
- return file.join_path(input.expanded_path_list_from_var(str))
-end
-
-function input.format_of_var(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
-end
-function input.format_of_suffix(str)
- return input.suffixmap[file.extname(str)] or 'tex'
-end
-
-function input.variable_of_format(str)
- return input.formats[str] or input.formats[input.alternatives[str]] or ''
-end
-
-function input.var_of_format_or_suffix(str)
- local v = input.formats[str]
- if v then
- return v
- end
- v = input.formats[input.alternatives[str]]
- if v then
- return v
- end
- v = input.suffixmap[file.extname(str)]
- if v then
- return input.formats[isf]
- end
- return ''
-end
-
-function input.expand_braces(str) -- output variable and brace expansion of STRING
- local ori = input.variable(str)
- local pth = input.aux.expanded_path(input.split_path(ori))
- return file.join_path(pth)
-end
-
--- {a,b,c,d}
--- a,b,c/{p,q,r},d
--- a,b,c/{p,q,r}/d/{x,y,z}//
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a,b,c/{p,q/{x,y,z},r},d/{p,q,r}
--- a{b,c}{d,e}f
--- {a,b,c,d}
--- {a,b,c/{p,q,r},d}
--- {a,b,c/{p,q,r}/d/{x,y,z}//}
--- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}}
--- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}}
--- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c}
-
--- this one is better and faster, but it took me a while to realize
--- that this kind of replacement is cleaner than messy parsing and
--- fuzzy concatenating we can probably gain a bit with selectively
--- applying lpeg, but experiments with lpeg parsing this proved not to
--- work that well; the parsing is ok, but dealing with the resulting
--- table is a pain because we need to work inside-out recursively
-
-function input.aux.splitpathexpr(str, t, validate)
- -- no need for optimization, only called a few times, we can use lpeg for the sub
- t = t or { }
- str = str:gsub(",}",",@}")
- str = str:gsub("{,","{@,")
- -- str = "@" .. str .. "@"
- while true do
- local done = false
- while true do
- local ok = false
- str = str:gsub("([^{},]+){([^{}]+)}", function(a,b)
- local t = { }
- for s in b:gmatch("[^,]+") do t[#t+1] = a .. s end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}([^{},]+)", function(a,b)
- local t = { }
- for s in a:gmatch("[^,]+") do t[#t+1] = s .. b end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- while true do
- local ok = false
- str = str:gsub("{([^{}]+)}{([^{}]+)}", function(a,b)
- local t = { }
- for sa in a:gmatch("[^,]+") do
- for sb in b:gmatch("[^,]+") do
- t[#t+1] = sa .. sb
- end
- end
- ok, done = true, true
- return "{" .. concat(t,",") .. "}"
- end)
- if not ok then break end
- end
- str = str:gsub("({[^{}]*){([^{}]+)}([^{}]*})", function(a,b,c)
- done = true
- return a .. b.. c
- end)
- if not done then break end
- end
- str = str:gsub("[{}]", "")
- str = str:gsub("@","")
- if validate then
- for s in str:gmatch("[^,]+") do
- s = validate(s)
- if s then t[#t+1] = s end
- end
- else
- for s in str:gmatch("[^,]+") do
- t[#t+1] = s
- end
- end
- return t
-end
-
-function input.aux.expanded_path(pathlist) -- maybe not a list, just a path
- local instance = input.instance
- -- a previous version fed back into pathlist
- local newlist, ok = { }, false
- for _,v in ipairs(pathlist) do
- if v:find("[{}]") then
- ok = true
- break
- end
- end
- if ok then
- for _, v in ipairs(pathlist) do
- input.aux.splitpathexpr(v, newlist, function(s)
- s = file.collapse_path(s)
- return s ~= "" and not s:find(instance.dummy_path_expr) and s
- end)
- end
- else
- for _,v in ipairs(pathlist) do
- for vv in string.gmatch(v..',',"(.-),") do
- vv = file.collapse_path(v)
- if vv ~= "" then newlist[#newlist+1] = vv end
- end
- end
- end
- return newlist
-end
-
-input.is_readable = { }
-
-function input.aux.is_readable(readable, name)
- if input.trace > 2 then
- if readable then
- input.logger("+ readable: %s",name)
- else
- input.logger("- readable: %s", name)
- end
- end
- return readable
-end
-
-function input.is_readable.file(name)
- return input.aux.is_readable(lfs.isfile(name), name)
-end
-
-input.is_readable.tex = input.is_readable.file
-
--- name
--- name/name
-
-function input.aux.collect_files(names)
- local instance = input.instance
- local filelist = { }
- for _, fname in pairs(names) do
- if fname then
- if input.trace > 2 then
- input.logger("? blobpath asked: %s",fname)
- end
- local bname = file.basename(fname)
- local dname = file.dirname(fname)
- if dname == "" or dname:find("^%.") then
- dname = false
- else
- dname = "/" .. dname .. "$"
- end
- for _, hash in ipairs(instance.hashes) do
- local blobpath = hash.tag
- local files = blobpath and instance.files[blobpath]
- if files then
- if input.trace > 2 then
- input.logger('? blobpath do: %s (%s)',blobpath,bname)
- end
- local blobfile = files[bname]
- if not blobfile then
- local rname = "remap:"..bname
- blobfile = files[rname]
- if blobfile then
- bname = files[rname]
- blobfile = files[bname]
- end
- end
- if blobfile then
- if type(blobfile) == 'string' then
- if not dname or blobfile:find(dname) then
- filelist[#filelist+1] = {
- hash.type,
- file.join(blobpath,blobfile,bname), -- search
- input.concatinators[hash.type](blobpath,blobfile,bname) -- result
- }
- end
- else
- for _, vv in pairs(blobfile) do
- if not dname or vv:find(dname) then
- filelist[#filelist+1] = {
- hash.type,
- file.join(blobpath,vv,bname), -- search
- input.concatinators[hash.type](blobpath,vv,bname) -- result
- }
- end
- end
- end
- end
- elseif input.trace > 1 then
- input.logger('! blobpath no: %s (%s)',blobpath,bname)
- end
- end
- end
- end
- if #filelist > 0 then
- return filelist
- else
- return nil
- end
-end
-
-function input.suffix_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str][1]
- else
- return ""
- end
-end
-
-function input.suffixes_of_format(str)
- if input.suffixes[str] then
- return input.suffixes[str]
- else
- return {}
- end
-end
-
-do
-
- -- called about 700 times for an empty doc (font initializations etc)
- -- i need to weed the font files for redundant calls
-
- local letter = lpeg.R("az","AZ")
- local separator = lpeg.P("://")
-
- local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator
- local rootbased = lpeg.P("/") + letter*lpeg.P(":")
-
- -- ./name ../name /name c: ://
- function input.aux.qualified_path(filename)
- return qualified:match(filename)
- end
- function input.aux.rootbased_path(filename)
- return rootbased:match(filename)
- end
-
- function input.normalize_name(original)
- return original
- end
-
- input.normalize_name = file.collapse_path
-
-end
-
-function input.aux.register_in_trees(name)
- if not name:find("^%.") then
- local instance = input.instance
- instance.foundintrees[name] = (instance.foundintrees[name] or 0) + 1 -- maybe only one
- end
-end
-
--- split the next one up, better for jit
-
-function input.aux.find_file(filename) -- todo : plugin (scanners, checkers etc)
- local instance = input.instance
- local result = { }
- local stamp = nil
- filename = input.normalize_name(filename) -- elsewhere
- filename = file.collapse_path(filename:gsub("\\","/")) -- elsewhere
- -- speed up / beware: format problem
- if instance.remember then
- stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format
- if instance.found[stamp] then
- if input.trace > 0 then
- input.logger('! remembered: %s',filename)
- end
- return instance.found[stamp]
- end
- end
- if filename:find('%*') then
- if input.trace > 0 then
- input.logger('! wildcard: %s', filename)
- end
- result = input.find_wildcard_files(filename)
- elseif input.aux.qualified_path(filename) then
- if input.is_readable.file(filename) then
- if input.trace > 0 then
- input.logger('! qualified: %s', filename)
- end
- result = { filename }
- else
- local forcedname, ok = "", false
- if file.extname(filename) == "" then
- if instance.format == "" then
- forcedname = filename .. ".tex"
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing standard filetype: tex')
- end
- result, ok = { forcedname }, true
- end
- else
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
- forcedname = filename .. "." .. s
- if input.is_readable.file(forcedname) then
- if input.trace > 0 then
- input.logger('! no suffix, forcing format filetype: %s', s)
- end
- result, ok = { forcedname }, true
- break
- end
- end
- end
- end
- if not ok and input.trace > 0 then
- input.logger('? qualified: %s', filename)
- end
- end
- else
- -- search spec
- local filetype, extra, done, wantedfiles, ext = '', nil, false, { }, file.extname(filename)
- if ext == "" then
- if not instance.force_suffixes then
- wantedfiles[#wantedfiles+1] = filename
- end
- else
- wantedfiles[#wantedfiles+1] = filename
- end
- if instance.format == "" then
- if ext == "" then
- local forcedname = filename .. '.tex'
- wantedfiles[#wantedfiles+1] = forcedname
- filetype = input.format_of_suffix(forcedname)
- if input.trace > 0 then
- input.logger('! forcing filetype: %s',filetype)
- end
- else
- filetype = input.format_of_suffix(filename)
- if input.trace > 0 then
- input.logger('! using suffix based filetype: %s',filetype)
- end
- end
- else
- if ext == "" then
- for _, s in pairs(input.suffixes_of_format(instance.format)) do
- wantedfiles[#wantedfiles+1] = filename .. "." .. s
- end
- end
- filetype = instance.format
- if input.trace > 0 then
- input.logger('! using given filetype: %s',filetype)
- end
- end
- local typespec = input.variable_of_format(filetype)
- local pathlist = input.expanded_path_list(typespec)
- if not pathlist or #pathlist == 0 then
- -- no pathlist, access check only / todo == wildcard
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- input.logger('? filetype: %s',filetype or '?')
- input.logger('? wanted files: %s',concat(wantedfiles," | "))
- end
- for _, fname in pairs(wantedfiles) do
- if fname and input.is_readable.file(fname) then
- filename, done = fname, true
- result[#result+1] = file.join('.',fname)
- break
- end
- end
- -- this is actually 'other text files' or 'any' or 'whatever'
- local filelist = input.aux.collect_files(wantedfiles)
- local fl = filelist and filelist[1]
- if fl then
- filename = fl[3]
- result[#result+1] = filename
- done = true
- end
- else
- -- list search
- local filelist = input.aux.collect_files(wantedfiles)
- local doscan, recurse
- if input.trace > 2 then
- input.logger('? filename: %s',filename)
- -- if pathlist then input.logger('? path list: %s',concat(pathlist," | ")) end
- -- if filelist then input.logger('? file list: %s',concat(filelist," | ")) end
- end
- -- a bit messy ... esp the doscan setting here
- for _, path in pairs(pathlist) do
- if path:find("^!!") then doscan = false else doscan = true end
- if path:find("//$") then recurse = true else recurse = false end
- local pathname = path:gsub("^!+", '')
- done = false
- -- using file list
- if filelist and not (done and not instance.allresults) and recurse then
- -- compare list entries with permitted pattern
- pathname = pathname:gsub("([%-%.])","%%%1") -- this also influences
- pathname = pathname:gsub("/+$", '/.*') -- later usage of pathname
- pathname = pathname:gsub("//", '/.-/') -- not ok for /// but harmless
- local expr = "^" .. pathname
- -- input.debug('?',expr)
- for _, fl in ipairs(filelist) do
- local f = fl[2]
- if f:find(expr) then
- -- input.debug('T',' '..f)
- if input.trace > 2 then
- input.logger('= found in hash: %s',f)
- end
- --- todo, test for readable
- result[#result+1] = fl[3]
- input.aux.register_in_trees(f) -- for tracing used files
- done = true
- if not instance.allresults then break end
- else
- -- input.debug('F',' '..f)
- end
- end
- end
- if not done and doscan then
- -- check if on disk / unchecked / does not work at all / also zips
- if input.method_is_file(pathname) then -- ?
- local pname = pathname:gsub("%.%*$",'')
- if not pname:find("%*") then
- local ppname = pname:gsub("/+$","")
- if input.aux.can_be_dir(ppname) then
- for _, w in pairs(wantedfiles) do
- local fname = file.join(ppname,w)
- if input.is_readable.file(fname) then
- if input.trace > 2 then
- input.logger('= found by scanning: %s',fname)
- end
- result[#result+1] = fname
- done = true
- if not instance.allresults then break end
- end
- end
- else
- -- no access needed for non existing path, speedup (esp in large tree with lots of fake)
- end
- end
- end
- end
- if not done and doscan then
- -- todo: slow path scanning
- end
- if done and not instance.allresults then break end
- end
- end
- end
- for k,v in pairs(result) do
- result[k] = file.collapse_path(v)
- end
- if instance.remember then
- instance.found[stamp] = result
- end
- return result
-end
-
-input.aux._find_file_ = input.aux.find_file -- frozen variant
-
-function input.aux.find_file(filename) -- maybe make a lowres cache too
- local result = input.aux._find_file_(filename)
- if #result == 0 then
- local lowered = filename:lower()
- if filename ~= lowered then
- return input.aux._find_file_(lowered)
- end
- end
- return result
-end
-
-function input.aux.can_be_dir(name)
- local instance = input.instance
- if not instance.fakepaths[name] then
- if lfs.isdir(name) then
- instance.fakepaths[name] = 1 -- directory
- else
- instance.fakepaths[name] = 2 -- no directory
- end
- end
- return (instance.fakepaths[name] == 1)
-end
-
-if not input.concatinators then input.concatinators = { } end
-
-input.concatinators.tex = file.join
-input.concatinators.file = input.concatinators.tex
-
-function input.find_files(filename,filetype,mustexist)
- local instance = input.instance
- if type(mustexist) == boolean then
- -- all set
- elseif type(filetype) == 'boolean' then
- filetype, mustexist = nil, false
- elseif type(filetype) ~= 'string' then
- filetype, mustexist = nil, false
- end
- instance.format = filetype or ''
- local t = input.aux.find_file(filename,true)
- instance.format = ''
- return t
-end
-
-function input.find_file(filename,filetype,mustexist)
- return (input.find_files(filename,filetype,mustexist)[1] or "")
-end
-
-function input.find_given_files(filename)
- local instance = input.instance
- local bname, result = file.basename(filename), { }
- for k, hash in ipairs(instance.hashes) do
- local files = instance.files[hash.tag]
- local blist = files[bname]
- if not blist then
- local rname = "remap:"..bname
- blist = files[rname]
- if blist then
- bname = files[rname]
- blist = files[bname]
- end
- end
- if blist then
- if type(blist) == 'string' then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
- if not instance.allresults then break end
- else
- for kk,vv in pairs(blist) do
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
- if not instance.allresults then break end
- end
- end
- end
- end
- return result
-end
-
-function input.find_given_file(filename)
- return (input.find_given_files(filename)[1] or "")
-end
-
-function input.find_wildcard_files(filename) -- todo: remap:
- local instance = input.instance
- local result = { }
- local bname, dname = file.basename(filename), file.dirname(filename)
- local path = dname:gsub("^*/","")
- path = path:gsub("*",".*")
- path = path:gsub("-","%%-")
- if dname == "" then
- path = ".*"
- end
- local name = bname
- name = name:gsub("*",".*")
- name = name:gsub("-","%%-")
- path = path:lower()
- name = name:lower()
- local function doit(blist,bname,hash,allresults)
- local done = false
- if blist then
- if type(blist) == 'string' then
- -- make function and share code
- if (blist:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,blist,bname) or ""
- done = true
- end
- else
- for kk,vv in pairs(blist) do
- if (vv:lower()):find(path) then
- result[#result+1] = input.concatinators[hash.type](hash.tag,vv,bname) or ""
- done = true
- if not allresults then break end
- end
- end
- end
- end
- return done
- end
- local files, allresults, done = instance.files, instance.allresults, false
- if name:find("%*") then
- for k, hash in ipairs(instance.hashes) do
- for kk, hh in pairs(files[hash.tag]) do
- if not kk:find("^remap:") then
- if (kk:lower()):find(name) then
- if doit(hh,kk,hash,allresults) then done = true end
- if done and not allresults then break end
- end
- end
- end
- end
- else
- for k, hash in ipairs(instance.hashes) do
- if doit(files[hash.tag][bname],bname,hash,allresults) then done = true end
- if done and not allresults then break end
- end
- end
- -- we can consider also searching the paths not in the database, but then
- -- we end up with a messy search (all // in all path specs)
- return result
-end
-
-function input.find_wildcard_file(filename)
- return (input.find_wildcard_files(filename)[1] or "")
-end
-
--- main user functions
-
-function input.save_used_files_in_trees(filename,jobname)
- local instance = input.instance
- if not filename then filename = 'luatex.jlg' end
- local f = io.open(filename,'w')
- if f then
- f:write("<?xml version='1.0' standalone='yes'?>\n")
- f:write("<rl:job>\n")
- if jobname then
- f:write("\t<rl:name>" .. jobname .. "</rl:name>\n")
- end
- f:write("\t<rl:files>\n")
- for _,v in pairs(sorted(instance.foundintrees)) do -- ipairs
- f:write("\t\t<rl:file n='" .. instance.foundintrees[v] .. "'>" .. v .. "</rl:file>\n")
- end
- f:write("\t</rl:files>\n")
- f:write("</rl:usedfiles>\n")
- f:close()
- end
-end
-
-function input.automount()
- -- implemented later
-end
-
-function input.load()
- input.starttiming(input.instance)
- input.resetconfig()
- input.identify_cnf()
- input.load_lua()
- input.expand_variables()
- input.load_cnf()
- input.expand_variables()
- input.load_hash()
- input.automount()
- input.stoptiming(input.instance)
-end
-
-function input.for_files(command, files, filetype, mustexist)
- if files and #files > 0 then
- local function report(str)
- if input.verbose then
- input.report(str) -- has already verbose
- else
- print(str)
- end
- end
- if input.verbose then
- report('')
- end
- for _, file in pairs(files) do
- local result = command(file,filetype,mustexist)
- if type(result) == 'string' then
- report(result)
- else
- for _,v in pairs(result) do
- report(v)
- end
- end
- end
- end
-end
-
--- strtab
-
-input.var_value = input.variable -- output the value of variable $STRING.
-input.expand_var = input.expansion -- output variable expansion of STRING.
-
-function input.show_path(str) -- output search path for file type NAME
- return file.join_path(input.expanded_path_list(input.format_of_var(str)))
-end
-
--- input.find_file(filename)
--- input.find_file(filename, filetype, mustexist)
--- input.find_file(filename, mustexist)
--- input.find_file(filename, filetype)
-
-function input.aux.register_file(files, name, path)
- if files[name] then
- if type(files[name]) == 'string' then
- files[name] = { files[name], path }
- else
- files[name] = path
- end
- else
- files[name] = path
- end
-end
-
-if not input.finders then input.finders = { } end
-if not input.openers then input.openers = { } end
-if not input.loaders then input.loaders = { } end
-
-input.finders.notfound = { nil }
-input.openers.notfound = { nil }
-input.loaders.notfound = { false, nil, 0 }
-
-function input.splitmethod(filename)
- if not filename then
- return { } -- safeguard
- elseif type(filename) == "table" then
- return filename -- already split
- elseif not filename:find("://") then
- return { scheme="file", path = filename, original=filename } -- quick hack
- else
- return url.hashed(filename)
- end
-end
-
-function input.method_is_file(filename)
- return input.splitmethod(filename).scheme == 'file'
-end
-
-function table.sequenced(t,sep) -- temp here
- local s = { }
- for k, v in pairs(t) do
- s[#s+1] = k .. "=" .. v
- end
- return concat(s, sep or " | ")
-end
-
-function input.methodhandler(what, filename, filetype) -- ...
- local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb
- local scheme = specification.scheme
- if input[what][scheme] then
- if input.trace > 0 then
- input.logger('= handler: %s -> %s -> %s',specification.original,what,table.sequenced(specification))
- end
- return input[what][scheme](filename,filetype) -- todo: specification
- else
- return input[what].tex(filename,filetype) -- todo: specification
- end
-end
-
--- also inside next test?
-
-function input.findtexfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.opentexfile(filename)
- return input.methodhandler('openers',input.normalize_name(filename))
-end
-
-function input.findbinfile(filename, filetype)
- return input.methodhandler('finders',input.normalize_name(filename), filetype)
-end
-function input.openbinfile(filename)
- return input.methodhandler('loaders',input.normalize_name(filename))
-end
-
-function input.loadbinfile(filename, filetype)
- local fname = input.findbinfile(input.normalize_name(filename), filetype)
- if fname and fname ~= "" then
- return input.openbinfile(fname)
- else
- return unpack(input.loaders.notfound)
- end
-end
-
-function input.texdatablob(filename, filetype)
- local ok, data, size = input.loadbinfile(filename, filetype)
- return data or ""
-end
-
-input.loadtexfile = input.texdatablob
-
-function input.openfile(filename)
- local fullname = input.findtexfile(filename)
- if fullname and (fullname ~= "") then
- return input.opentexfile(fullname)
- else
- return nil
- end
-end
-
-function input.logmode()
- return (os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"):lower()
-end
-
--- this is a prelude to engine/progname specific configuration files
--- in which case we can omit files meant for other programs and
--- packages
-
---- ctx
-
--- maybe texinputs + font paths
--- maybe positive selection tex/context fonts/tfm|afm|vf|opentype|type1|map|enc
-
-input.validators = { }
-input.validators.visibility = { }
-
-function input.validators.visibility.default(path, name)
- return true
-end
-
-function input.validators.visibility.context(path, name)
- path = path[1] or path -- some day a loop
- return not (
- path:find("latex") or
--- path:find("doc") or
- path:find("tex4ht") or
- path:find("source") or
--- path:find("config") or
--- path:find("metafont") or
- path:find("lists$") or
- name:find("%.tpm$") or
- name:find("%.bak$")
- )
-end
-
--- todo: describe which functions are public (maybe input.private. ... )
-
--- beware: i need to check where we still need a / on windows:
-
-function input.clean_path(str)
- if str then
- str = str:gsub("\\","/")
- str = str:gsub("^!+","")
- str = str:gsub("^~",input.homedir)
- return str
- else
- return nil
- end
-end
-
-function input.do_with_path(name,func)
- for _, v in pairs(input.expanded_path_list(name)) do
- func("^"..input.clean_path(v))
- end
-end
-
-function input.do_with_var(name,func)
- func(input.aux.expanded_var(name))
-end
-
-function input.with_files(pattern,handle)
- local instance = input.instance
- for _, hash in ipairs(instance.hashes) do
- local blobpath = hash.tag
- local blobtype = hash.type
- if blobpath then
- local files = instance.files[blobpath]
- if files then
- for k,v in pairs(files) do
- if k:find("^remap:") then
- k = files[k]
- v = files[k] -- chained
- end
- if k:find(pattern) then
- if type(v) == "string" then
- handle(blobtype,blobpath,v,k)
- else
- for _,vv in pairs(v) do
- handle(blobtype,blobpath,vv,k)
- end
- end
- end
- end
- end
- end
- end
-end
-
-function input.update_script(oldname,newname) -- oldname -> own.name, not per se a suffix
- local scriptpath = "scripts/context/lua"
- newname = file.addsuffix(newname,"lua")
- local oldscript = input.clean_path(oldname)
- input.report("to be replaced old script %s", oldscript)
- local newscripts = input.find_files(newname) or { }
- if #newscripts == 0 then
- input.report("unable to locate new script")
- else
- for _, newscript in ipairs(newscripts) do
- newscript = input.clean_path(newscript)
- input.report("checking new script %s", newscript)
- if oldscript == newscript then
- input.report("old and new script are the same")
- elseif not newscript:find(scriptpath) then
- input.report("new script should come from %s",scriptpath)
- elseif not (oldscript:find(file.removesuffix(newname).."$") or oldscript:find(newname.."$")) then
- input.report("invalid new script name")
- else
- local newdata = io.loaddata(newscript)
- if newdata then
- input.report("old script content replaced by new content")
- io.savedata(oldscript,newdata)
- break
- else
- input.report("unable to load new script")
- end
- end
- end
- end
-end
-
-
---~ print(table.serialize(input.aux.splitpathexpr("/usr/share/texmf-{texlive,tetex}", {})))
-
--- command line resolver:
-
---~ print(input.resolve("abc env:tmp file:cont-en.tex path:cont-en.tex full:cont-en.tex rel:zapf/one/p-chars.tex"))
-
-do
-
- local resolvers = { }
-
- resolvers.environment = function(str)
- return input.clean_path(os.getenv(str) or os.getenv(str:upper()) or os.getenv(str:lower()) or "")
- end
- resolvers.relative = function(str,n)
- if io.exists(str) then
- -- nothing
- elseif io.exists("./" .. str) then
- str = "./" .. str
- else
- local p = "../"
- for i=1,n or 2 do
- if io.exists(p .. str) then
- str = p .. str
- break
- else
- p = p .. "../"
- end
- end
- end
- return input.clean_path(str)
- end
- resolvers.locate = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path((fullname ~= "" and fullname) or str)
- end
- resolvers.filename = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.basename((fullname ~= "" and fullname) or str))
- end
- resolvers.pathname = function(str)
- local fullname = input.find_given_file(str) or ""
- return input.clean_path(file.dirname((fullname ~= "" and fullname) or str))
- end
-
- resolvers.env = resolvers.environment
- resolvers.rel = resolvers.relative
- resolvers.loc = resolvers.locate
- resolvers.kpse = resolvers.locate
- resolvers.full = resolvers.locate
- resolvers.file = resolvers.filename
- resolvers.path = resolvers.pathname
-
- local function resolve(str)
- if type(str) == "table" then
- for k, v in pairs(str) do
- str[k] = resolve(v) or v
- end
- elseif str and str ~= "" then
- str = str:gsub("([a-z]+):([^ \"\']*)", function(method,target)
- if resolvers[method] then
- return resolvers[method](target)
- else
- return method .. ":" .. target
- end
- end)
- end
- return str
- end
-
- if os.uname then
- for k, v in pairs(os.uname()) do
- if not resolvers[k] then
- resolvers[k] = function() return v end
- end
- end
- end
-
- input.resolve = resolve
-
-end
-
-function input.boolean_variable(str,default)
- local b = input.expansion(str)
- if b == "" then
- return default
- else
- b = toboolean(b)
- return (b == nil and default) or b
- end
-end
diff --git a/tex/context/base/luat-iop.lua b/tex/context/base/luat-iop.lua
index 469b7c034..883ec43ce 100644
--- a/tex/context/base/luat-iop.lua
+++ b/tex/context/base/luat-iop.lua
@@ -1,16 +1,16 @@
--- filename : luat-iop.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['luat-iop'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-- this paranoid stuff in web2c ... we cannot hook checks into the
-- input functions because one can always change the callback but
-- we can feed back specific patterns and paths into the next
-- mechanism
-if not versions then versions = { } end versions['luat-exe'] = 1.001
-
if not io.inp then io.inp = { } end
if not io.out then io.out = { } end
@@ -127,11 +127,11 @@ function io.inp.modes.paranoid()
io.inp.inhibit('%.%.')
io.inp.permit('^%./')
io.inp.permit('[^/]')
- input.do_with_path('TEXMF',io.inp.permit)
+ resolvers.do_with_path('TEXMF',io.inp.permit)
end
function io.out.modes.paranoid()
io.out.inhibit('.*')
- input.do_with_path('TEXMFOUTPUT',io.out.permit)
+ resolvers.do_with_path('TEXMFOUTPUT',io.out.permit)
end
-- handy
diff --git a/tex/context/base/luat-kps.lua b/tex/context/base/luat-kps.lua
deleted file mode 100644
index 15dadbb84..000000000
--- a/tex/context/base/luat-kps.lua
+++ /dev/null
@@ -1,102 +0,0 @@
-if not modules then modules = { } end modules ['luat-kps'] = {
- version = 1.001,
- comment = "companion to luatools.lua",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This file is used when we want the input handlers to behave like
-<type>kpsewhich</type>. What to do with the following:</p>
-
-<typing>
-{$SELFAUTOLOC,$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,}/web2c}
-$SELFAUTOLOC : /usr/tex/bin/platform
-$SELFAUTODIR : /usr/tex/bin
-$SELFAUTOPARENT : /usr/tex
-</typing>
-
-<p>How about just forgetting abou them?</p>
---ldx]]--
-
-input = input or { }
-input.suffixes = input.suffixes or { }
-input.formats = input.formats or { }
-
-input.suffixes['gf'] = { '<resolution>gf' }
-input.suffixes['pk'] = { '<resolution>pk' }
-input.suffixes['base'] = { 'base' }
-input.suffixes['bib'] = { 'bib' }
-input.suffixes['bst'] = { 'bst' }
-input.suffixes['cnf'] = { 'cnf' }
-input.suffixes['mem'] = { 'mem' }
-input.suffixes['mf'] = { 'mf' }
-input.suffixes['mfpool'] = { 'pool' }
-input.suffixes['mft'] = { 'mft' }
-input.suffixes['mppool'] = { 'pool' }
-input.suffixes['graphic/figure'] = { 'eps', 'epsi' }
-input.suffixes['texpool'] = { 'pool' }
-input.suffixes['PostScript header'] = { 'pro' }
-input.suffixes['ist'] = { 'ist' }
-input.suffixes['web'] = { 'web', 'ch' }
-input.suffixes['cweb'] = { 'w', 'web', 'ch' }
-input.suffixes['cmap files'] = { 'cmap' }
-input.suffixes['lig files'] = { 'lig' }
-input.suffixes['bitmap font'] = { }
-input.suffixes['MetaPost support'] = { }
-input.suffixes['TeX system documentation'] = { }
-input.suffixes['TeX system sources'] = { }
-input.suffixes['dvips config'] = { }
-input.suffixes['type42 fonts'] = { }
-input.suffixes['web2c files'] = { }
-input.suffixes['other text files'] = { }
-input.suffixes['other binary files'] = { }
-input.suffixes['opentype fonts'] = { 'otf' }
-
-input.suffixes['fmt'] = { 'fmt' }
-input.suffixes['texmfscripts'] = { 'rb','lua','py','pl' }
-
-input.suffixes['pdftex config'] = { }
-input.suffixes['Troff fonts'] = { }
-
-input.suffixes['ls-R'] = { }
-
---[[ldx--
-<p>If you wondered abou tsome of the previous mappings, how about
-the next bunch:</p>
---ldx]]--
-
-input.formats['bib'] = ''
-input.formats['bst'] = ''
-input.formats['mft'] = ''
-input.formats['ist'] = ''
-input.formats['web'] = ''
-input.formats['cweb'] = ''
-input.formats['MetaPost support'] = ''
-input.formats['TeX system documentation'] = ''
-input.formats['TeX system sources'] = ''
-input.formats['Troff fonts'] = ''
-input.formats['dvips config'] = ''
-input.formats['graphic/figure'] = ''
-input.formats['ls-R'] = ''
-input.formats['other text files'] = ''
-input.formats['other binary files'] = ''
-
-input.formats['gf'] = ''
-input.formats['pk'] = ''
-input.formats['base'] = 'MFBASES'
-input.formats['cnf'] = ''
-input.formats['mem'] = 'MPMEMS'
-input.formats['mf'] = 'MFINPUTS'
-input.formats['mfpool'] = 'MFPOOL'
-input.formats['mppool'] = 'MPPOOL'
-input.formats['texpool'] = 'TEXPOOL'
-input.formats['PostScript header'] = 'TEXPSHEADERS'
-input.formats['cmap files'] = 'CMAPFONTS'
-input.formats['type42 fonts'] = 'T42FONTS'
-input.formats['web2c files'] = 'WEB2C'
-input.formats['pdftex config'] = 'PDFTEXCONFIG'
-input.formats['texmfscripts'] = 'TEXMFSCRIPTS'
-input.formats['bitmap font'] = ''
-input.formats['lig files'] = 'LIGFONTS'
diff --git a/tex/context/base/luat-lib.lua b/tex/context/base/luat-lib.lua
deleted file mode 100644
index 06d00e778..000000000
--- a/tex/context/base/luat-lib.lua
+++ /dev/null
@@ -1,174 +0,0 @@
-if not modules then modules = { } end modules ['luat-lib'] = {
- version = 1.001,
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files",
- comment = "companion to luat-lib.tex",
-}
-
--- most code already moved to the l-*.lua and other luat-*.lua files
-
-os.setlocale(nil,nil) -- useless feature and even dangerous in luatex
-
-function os.setlocale()
- -- no way you can mess with it
-end
-
-if arg and (arg[0] == 'luatex' or arg[0] == 'luatex.exe') and arg[1] == "--luaonly" then
- arg[-1]=arg[0] arg[0]=arg[2] for k=3,#arg do arg[k-2]=arg[k] end arg[#arg]=nil arg[#arg]=nil
-end
-
-environment = environment or { }
-environment.arguments = { }
-environment.files = { }
-environment.sortedflags = nil
-
-function environment.initialize_arguments(arg)
- local arguments, files = { }, { }
- environment.arguments, environment.files, environment.sortedflags = arguments, files, nil
- for index, argument in pairs(arg) do
- if index > 0 then
- local flag, value = argument:match("^%-+(.+)=(.-)$")
- if flag then
- arguments[flag] = string.unquote(value or "")
- else
- flag = argument:match("^%-+(.+)")
- if flag then
- arguments[flag] = true
- else
- files[#files+1] = argument
- end
- end
- end
- end
- environment.ownname = environment.ownname or arg[0] or 'unknown.lua'
-end
-
-function environment.showarguments()
- for k,v in pairs(environment.arguments) do
- print(k .. " : " .. tostring(v))
- end
- if #environment.files > 0 then
- print("files : " .. table.concat(environment.files, " "))
- end
-end
-
-function environment.setargument(name,value)
- environment.arguments[name] = value
-end
-
-function environment.argument(name) -- todo: default (plus typecheck on default)
- local arguments, sortedflags = environment.arguments, environment.sortedflags
- if arguments[name] then
- return arguments[name]
- else
- if not sortedflags then
- sortedflags = { }
- for _,v in pairs(table.sortedkeys(arguments)) do
- sortedflags[#sortedflags+1] = "^" .. v
- end
- environment.sortedflags = sortedflags
- end
- for _,v in ipairs(sortedflags) do
- if name:find(v) then
- return arguments[v:sub(2,#v)]
- end
- end
- end
- return nil
-end
-
-function environment.split_arguments(separator) -- rather special, cut-off before separator
- local done, before, after = false, { }, { }
- for _,v in ipairs(environment.original_arguments) do
- if not done and v == separator then
- done = true
- elseif done then
- after[#after+1] = v
- else
- before[#before+1] = v
- end
- end
- return before, after
-end
-
---~ function environment.reconstruct_commandline(arg)
---~ if not arg then arg = environment.original_arguments end
---~ local result = { }
---~ for _,a in ipairs(arg) do -- ipairs 1 .. #n
---~ local kk, vv = a:match("^(%-+.-)=(.+)$")
---~ if kk and vv then
---~ if vv:find(" ") then
---~ vv = vv:unquote()
---~ vv = vv:gsub('"','\\"')
---~ result[#result+1] = kk .. "=" .. vv:quote()
---~ else
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a
---~ end
---~ elseif a:find(" ") then
---~ a = a:unquote()
---~ a = a:gsub('"','\\"')
---~ result[#result+1] = a:quote()
---~ else
---~ result[#result+1] = a
---~ end
---~ end
---~ return table.join(result," ")
---~ end
-
-function environment.reconstruct_commandline(arg,noquote)
- if not arg then arg = environment.original_arguments end
- if noquote and #arg == 1 then
- local a = arg[1]
- a = input.resolve(a)
- a = a:unquote()
- return a
- elseif #arg == 1 then
- local result = { }
- for _,a in ipairs(arg) do -- ipairs 1 .. #n
- a = input.resolve(a)
- a = a:unquote()
- a = a:gsub('"','\\"') -- tricky
- if a:find(" ") then
- result[#result+1] = a:quote()
- else
- result[#result+1] = a
- end
- end
- return table.join(result," ")
- end
-end
-
-if arg then
-
- -- new, reconstruct quoted snippets (maybe better just remnove the " then and add them later)
- local newarg, instring = { }, false
-
- for index, argument in ipairs(arg) do
- if argument:find("^\"") then
- newarg[#newarg+1] = argument:gsub("^\"","")
- if not argument:find("\"$") then
- instring = true
- end
- elseif argument:find("\"$") then
- newarg[#newarg] = newarg[#newarg] .. " " .. argument:gsub("\"$","")
- instring = false
- elseif instring then
- newarg[#newarg] = newarg[#newarg] .. " " .. argument
- else
- newarg[#newarg+1] = argument
- end
- end
- for i=1,-5,-1 do
- newarg[i] = arg[i]
- end
-
- environment.initialize_arguments(newarg)
- environment.original_arguments = newarg
- environment.raw_arguments = arg
-
- arg = { } -- prevent duplicate handling
-
-end
diff --git a/tex/context/base/luat-lib.tex b/tex/context/base/luat-lib.tex
index 9693595b2..ec781f3cf 100644
--- a/tex/context/base/luat-lib.tex
+++ b/tex/context/base/luat-lib.tex
@@ -2,7 +2,7 @@
%D [ file=luat-lib,
%D version=2006.09.11,
%D title=\CONTEXT\ Lua Macros,
-%D subtitle=Unicode Support,
+%D subtitle=Libraries,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,60 +11,41 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-% \writestatus{loading}{Lua Support Macros (libs)}
+% \writestatus{loading}{ConTeXt Lua Macros / Libraries}
-%D For the moment we only load this lib.
+\registerctxluafile{trac-inf} {1.001}
+\registerctxluafile{trac-tra} {1.001}
+\registerctxluafile{trac-log} {1.001}
-%D This will move cq. become configurable. The XML like output is just
-%D an example.
-
-% todo \let\normaleverytoks\everytoks \newtoks\everytoke \normaleverytoks{\the\everytoks}
-
-\chardef\statuswidth=15
-\chardef\statuswrite=16
-
-\newtoks\everywritestring
-
-\def\writedirect {\immediate\write\statuswrite}
-\def\writeline {\writedirect{}}
-\def\writestring#1{\begingroup\the\everywritestring\writedirect{#1}\endgroup}
-
-\ifx\normalmessage \undefined \let\normalmessage \message \fi
-\ifx\normalwritestatus\undefined \def\normalwritestatus#1#2{\writedirect{#1 : #2}} \fi
-
-% this will change once we have proper write overloads
+\registerctxluafile{luat-cbk} {1.001}
-\registerctxluafile{l-string} {1.001}
-\registerctxluafile{l-lpeg} {1.001}
-\registerctxluafile{l-boolean}{1.001}
-\registerctxluafile{l-number} {1.001}
-\registerctxluafile{l-set} {1.001}
-\registerctxluafile{l-math} {1.001}
-\registerctxluafile{l-table} {1.001}
-\registerctxluafile{l-md5} {1.001}
-\registerctxluafile{l-aux} {1.001}
-\registerctxluafile{l-io} {1.001}
-\registerctxluafile{l-os} {1.001}
-\registerctxluafile{l-file} {1.001}
-\registerctxluafile{l-dir} {1.001}
-\registerctxluafile{l-unicode}{1.001}
-\registerctxluafile{l-utils} {1.001}
-\registerctxluafile{l-dimen} {1.001}
-\registerctxluafile{l-url} {1.001}
-\registerctxluafile{l-xml} {1.001}
-%registerctxluafile{l-xmlctx} {1.001}
+\registerctxluafile{data-res} {1.001}
+\registerctxluafile{data-tmp} {1.001}
+\registerctxluafile{data-pre} {1.001}
+\registerctxluafile{data-inp} {1.001}
+\registerctxluafile{data-out} {1.001}
+\registerctxluafile{data-tex} {1.001}
+\registerctxluafile{data-bin} {1.001}
+\registerctxluafile{data-zip} {1.001}
+\registerctxluafile{data-crl} {1.001}
+\registerctxluafile{data-tre} {1.001}
+\registerctxluafile{data-lua} {1.001}
+\registerctxluafile{data-ctx} {1.001}
+\registerctxluafile{data-con} {1.001}
+\registerctxluafile{data-use} {1.001}
-\registerctxluafile{luat-cbk} {1.001}
-\registerctxluafile{luat-lib} {1.001}
-\registerctxluafile{luat-inp} {1.001}
-\registerctxluafile{luat-log} {1.001}
-\registerctxluafile{luat-zip} {1.001}
-\registerctxluafile{luat-tex} {1.001}
+\registerctxluafile{luat-run} {1.001}
+\registerctxluafile{luat-fio} {1.001} % not needed, part of startup file
+\registerctxluafile{luat-cnf} {1.001} % not needed, part of startup file
\registerctxluafile{luat-lua} {1.001}
-\registerctxluafile{luat-tre} {1.001}
+\registerctxluafile{luat-sto} {1.001}
+\registerctxluafile{luat-ini} {1.001}
+\registerctxluafile{luat-env} {1.001}
+
+\registerctxluafile{l-xml} {1.001} % we want tracking
\startruntimeluacode
- \edef\asciia{\ctxlua{tex.sprint(input.logmode())}}
+ \edef\asciia{\ctxlua{tex.sprint(logs.mode)}}
\edef\asciib{xml}
\ifx\asciia\asciib % brrr
\long\def\writebanner #1{\writestring {<m t='banner'>#1</m>}}
@@ -77,15 +58,8 @@
\fi
\stopruntimeluacode
-\registerctxluafile{luat-tmp}{1.001}
-\registerctxluafile{luat-crl}{1.001}
+%registerctxluafile{luat-tmp}{1.001}
\registerctxluafile{luat-exe}{1.001}
\registerctxluafile{luat-iop}{1.001}
-% trace used files (only from trees)
-%
-% \ctxlua{input.register_stop_actions(function() input.save_used_files_in_trees() end)}
-% \ctxlua{table.insert(input.stop_actions, function() input.save_used_files_in_trees() end)}
-% \ctxlua{function input.stop_actions.trace_used_files() input.save_used_files_in_trees() end}
-
\endinput
diff --git a/tex/context/base/luat-log.lua b/tex/context/base/luat-log.lua
deleted file mode 100644
index 3704b3999..000000000
--- a/tex/context/base/luat-log.lua
+++ /dev/null
@@ -1,155 +0,0 @@
-if not modules then modules = { } end modules ['luat-log'] = {
- version = 1.001,
- comment = "companion to luat-lib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This is a prelude to a more extensive logging module. For the sake
-of parsing log files, in addition to the standard logging we will
-provide an <l n='xml'/> structured file. Actually, any logging that
-is hooked into callbacks will be \XML\ by default.</p>
---ldx]]--
-
--- input.logger -> special tracing, driven by log level (only input)
--- input.report -> goes to terminal, depends on verbose, has banner
--- logs.report -> module specific tracing and reporting, no banner but class
-
-
-input = input or { }
-logs = logs or { }
-
---[[ldx--
-<p>This looks pretty ugly but we need to speed things up a bit.</p>
---ldx]]--
-
-logs.levels = {
- ['error'] = 1,
- ['warning'] = 2,
- ['info'] = 3,
- ['debug'] = 4
-}
-
-logs.functions = {
- 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct'
-}
-
-logs.callbacks = {
- 'start_page_number',
- 'stop_page_number',
- 'report_output_pages',
- 'report_output_log'
-}
-
-logs.tracers = {
-}
-
-logs.xml = logs.xml or { }
-logs.tex = logs.tex or { }
-
-logs.level = 0
-
-local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
-
-if texlua then
- write_nl = print
- write = io.write
-end
-
-function logs.xml.report(category,fmt,...) -- new
- write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
-end
-function logs.xml.line(fmt,...) -- new
- write_nl(format("<r>%s</r>",format(fmt,...)))
-end
-
-function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
-function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
-function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
-function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
-
-function logs.tex.report(category,fmt,...) -- new
- -- write_nl(format("%s | %s",category,format(fmt,...))) -- arg to format can be tex comment so .. .
- write_nl(category .. " | " .. format(fmt,...))
-end
-function logs.tex.line(fmt,...) -- new
- write_nl(format(fmt,...))
-end
-
-function logs.set_level(level)
- logs.level = logs.levels[level] or level
-end
-
-function logs.set_method(method)
- for _, v in pairs(logs.functions) do
- logs[v] = logs[method][v] or function() end
- end
- if callback and input[method] then
- for _, cb in pairs(logs.callbacks) do
- callback.register(cb, input[method][cb])
- end
- end
-end
-
-function logs.xml.start_page_number()
- write_nl(format("<p real='%s' page='%s' sub='%s'", tex.count[0], tex.count[1], tex.count[2]))
-end
-
-function logs.xml.stop_page_number()
- write("/>")
- write_nl("")
-end
-
-function logs.xml.report_output_pages(p,b)
- write_nl(format("<v k='pages' v='%s'/>", p))
- write_nl(format("<v k='bytes' v='%s'/>", b))
- write_nl("")
-end
-
-function logs.xml.report_output_log()
-end
-
-function input.logger(...) -- assumes test for input.trace > n
- if input.trace > 0 then
- logs.report(...)
- end
-end
-
-function input.report(fmt,...)
- if input.verbose then
- logs.report(input.banner or "report",format(fmt,...))
- end
-end
-
-function input.reportlines(str) -- todo: <lines></lines>
- for line in str:gmatch("(.-)[\n\r]") do
- logs.report(input.banner or "report",line)
- end
-end
-
-input.moreinfo = [[
-more information about ConTeXt and the tools that come with it can be found at:
-
-maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
-webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
-wiki : http://contextgarden.net
-]]
-
-function input.help(banner,message)
- if not input.verbose then
- input.verbose = true
- -- input.report(banner,"\n")
- end
- input.report(banner,"\n")
- input.report("")
- input.reportlines(message)
- if input.moreinfo and input.moreinfo ~= "" then
- input.report("")
- input.reportlines(input.moreinfo)
- end
-end
-
-logs.set_level('error')
-logs.set_method('tex')
diff --git a/tex/context/base/luat-lua.lua b/tex/context/base/luat-lua.lua
index 128be2f4b..61be6e9d6 100644
--- a/tex/context/base/luat-lua.lua
+++ b/tex/context/base/luat-lua.lua
@@ -23,7 +23,7 @@ if lua then do
end
function lua.flush(...)
- tex.sprint("\\directlua0{lua.flush_delayed(" .. table.concat({...},',') .. ")}")
+ tex.sprint("\\directlua0{lua.flush_delayed(",table.concat({...},','),")}")
end
end end
diff --git a/tex/context/base/luat-run.lua b/tex/context/base/luat-run.lua
new file mode 100644
index 000000000..09fce32c1
--- /dev/null
+++ b/tex/context/base/luat-run.lua
@@ -0,0 +1,69 @@
+if not modules then modules = { } end modules ['luat-run'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, rpadd = string.format, string.rpadd
+
+main = main or { }
+
+local start_actions = { }
+local stop_actions = { }
+
+function main.register_start_actions(...) table.insert(start_actions, ...) end
+function main.register_stop_actions (...) table.insert(stop_actions, ...) end
+
+main.show_tex_stat = main.show_tex_stat or function() end
+main.show_job_stat = main.show_job_stat or statistics.show_job_stat
+
+function main.start()
+ if logs.start_run then
+ logs.start_run()
+ end
+ for _, action in next, start_actions do
+ action()
+ end
+end
+
+function main.stop()
+ for _, action in next, stop_actions do
+ action()
+ end
+ if main.show_job_stat then
+ statistics.show(logs.report_job_stat)
+ end
+ if main.show_tex_stat then
+ for k,v in next, status.list() do
+ logs.report_tex_stat(k,v)
+ end
+ end
+ if logs.stop_run then
+ logs.stop_run()
+ end
+end
+
+function main.start_shipout_page()
+ logs.start_page_number()
+end
+
+function main.stop_shipout_page()
+ logs.stop_page_number()
+end
+
+function main.report_output_pages()
+end
+
+function main.report_output_log()
+end
+
+-- this can be done later
+
+callback.register('start_run', main.start)
+callback.register('stop_run' , main.stop)
+callback.register('report_output_pages', main.report_output_pages)
+callback.register('report_output_log' , main.report_output_log)
+callback.register('start_page_number' , main.start_shipout_page)
+callback.register('stop_page_number' , main.stop_shipout_page)
diff --git a/tex/context/base/luat-soc.lua b/tex/context/base/luat-soc.lua
new file mode 100644
index 000000000..1095ed087
--- /dev/null
+++ b/tex/context/base/luat-soc.lua
@@ -0,0 +1,11 @@
+-- This is just a loader. The package handler knows about the TEX tree.
+
+--~ require "luatex/lua/socket.lua"
+--~ require "luatex/lua/ltn12.lua"
+--~ require "luatex/lua/mime.lua"
+--~ require "luatex/lua/socket/http.lua"
+--~ require "luatex/lua/socket/url.lua"
+--~ require "luatex/lua/socket/tp.lua"
+--~ require "luatex/lua/socket/ftp.lua"
+
+-- "luatex/lua/socket/smtp.lua"
diff --git a/tex/context/base/luat-sta.lua b/tex/context/base/luat-sta.lua
index 15581222c..12fa18219 100644
--- a/tex/context/base/luat-sta.lua
+++ b/tex/context/base/luat-sta.lua
@@ -5,6 +5,8 @@ if not modules then modules = { } end modules ['luat-sta'] = {
license = "see context related readme files"
}
+-- this code is used in the updater
+
states = states or { }
states.data = states.data or { }
states.hash = states.hash or { }
@@ -31,27 +33,32 @@ end
function states.set_by_tag(tag,key,value,default,persistent)
local d, h = states.data[tag], states.hash[tag]
if d then
- local dkey, hkey = key, key
- local pre, post = key:match("(.+)%.([^%.]+)$")
- if pre and post then
- for k in pre:gmatch("[^%.]+") do
- local dk = d[k]
- if not dk then
- dk = { }
- d[k] = dk
+ if type(d) == "table" then
+ local dkey, hkey = key, key
+ local pre, post = key:match("(.+)%.([^%.]+)$")
+ if pre and post then
+ for k in pre:gmatch("[^%.]+") do
+ local dk = d[k]
+ if not dk then
+ dk = { }
+ d[k] = dk
+ end
+ d = dk
end
- d = dk
+ dkey, hkey = post, key
end
- dkey, hkey = post, key
- end
- if type(value) == nil then
- value = value or default
- elseif persistent then
- value = value or d[dkey] or default
- else
- value = value or default
+ if type(value) == nil then
+ value = value or default
+ elseif persistent then
+ value = value or d[dkey] or default
+ else
+ value = value or default
+ end
+ d[dkey], h[hkey] = value, value
+ elseif type(d) == "string" then
+ -- weird
+ states.data[tag], states.hash[tag] = value, value
end
- d[dkey], h[hkey] = value, value
end
end
@@ -171,7 +178,6 @@ end
--~ },
--~ }
-
--~ states.save("teststate", "update")
--~ states.load("teststate", "update")
diff --git a/tex/context/base/luat-sto.lua b/tex/context/base/luat-sto.lua
new file mode 100644
index 000000000..10de76b28
--- /dev/null
+++ b/tex/context/base/luat-sto.lua
@@ -0,0 +1,134 @@
+if not modules then modules = { } end modules ['luat-sto'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next = type, next
+local gmatch, format, write_nl = string.gmatch, string.format, texio.write_nl
+
+storage = storage or { }
+storage.min = 0 -- 500
+storage.max = storage.min - 1
+storage.noftables = storage.noftables or 0
+storage.nofmodules = storage.nofmodules or 0
+storage.data = { }
+storage.evaluators = { }
+
+local evaluators = storage.evaluators -- (evaluate,message,names)
+local data = storage.data
+
+function storage.register(...)
+ data[#data+1] = { ... }
+end
+
+-- evaluators .. messy .. to be redone
+
+function storage.evaluate(name)
+ evaluators[#evaluators+1] = name
+end
+
+function storage.finalize() -- we can prepend the string with "evaluate:"
+ for i=1,#evaluators do
+ local t = evaluators[i]
+ for i, v in next, t do
+ local tv = type(v)
+ if tv == "string" then
+ t[i] = loadstring(v)()
+ elseif tv == "table" then
+ for _, vv in next, v do
+ if type(vv) == "string" then
+ t[i] = loadstring(vv)()
+ end
+ end
+ elseif tv == "function" then
+ t[i] = v()
+ end
+ end
+ end
+end
+
+function storage.dump()
+ for i=1,#data do
+ local d = data[i]
+ local message, original, target, evaluate = d[1], d[2] ,d[3] ,d[4]
+ local name, initialize, finalize, code = nil, "", "", ""
+ for str in gmatch(target,"([^%.]+)") do
+ if name then
+ name = name .. "." .. str
+ else
+ name = str
+ end
+ initialize = format("%s %s = %s or {} ", initialize, name, name)
+ end
+ if evaluate then
+ finalize = "storage.evaluate(" .. name .. ")"
+ end
+ storage.max = storage.max + 1
+ if trace_storage then
+ logs.report('storage','saving %s in slot %s',message,storage.max)
+ code =
+ initialize ..
+ format("logs.report('storage','restoring %s from slot %s') ",message,storage.max) ..
+ table.serialize(original,name) ..
+ finalize
+ else
+ code = initialize .. table.serialize(original,name) .. finalize
+ end
+ lua.bytecode[storage.max] = loadstring(code)
+ end
+end
+
+-- we also need to count at generation time (nicer for message)
+
+if lua.bytecode then -- from 0 upwards
+ local i, b = storage.min, lua.bytecode
+ while b[i] do
+ storage.noftables = i
+ b[i]()
+ b[i] = nil
+ i = i + 1
+ end
+end
+
+statistics.register("stored bytecode data", function()
+ local modules = (storage.nofmodules > 0 and storage.nofmodules) or (status.luabytecodes - 500)
+ local dumps = (storage.noftables > 0 and storage.noftables) or storage.max-storage.min + 1
+ return format("%s modules, %s tables, %s chunks",modules,dumps,modules+dumps)
+end)
+
+if lua.bytedata then
+ storage.register("lua/bytedata",lua.bytedata,"lua.bytedata")
+end
+
+-- wrong place, kind of forward reference
+
+function statistics.report_storage(whereto)
+ whereto = whereto or "term and log"
+ write_nl(whereto," ","stored tables:"," ")
+ for k,v in table.sortedpairs(storage.data) do
+ write_nl(whereto,format("%03i %s",k,v[1]))
+ end
+ write_nl(whereto," ","stored modules:"," ")
+ for k,v in table.sortedpairs(lua.bytedata) do
+ write_nl(whereto,format("%03i %s %s",k,v[2],v[1]))
+ end
+ write_nl(whereto," ","stored attributes:"," ")
+ for k,v in table.sortedpairs(attributes.names) do
+ write_nl(whereto,format("%03i %s",k,v))
+ end
+ write_nl(whereto," ","stored catcodetables:"," ")
+ for k,v in table.sortedpairs(catcodes.names) do
+ write_nl(whereto,format("%03i %s",k,v))
+ end
+ write_nl(whereto," ")
+end
+
+storage.shared = storage.shared or { }
+
+-- Because the storage mechanism assumes tables, we define a table for storing
+-- (non table) values.
+
+storage.register("storage/shared", storage.shared, "storage.shared")
diff --git a/tex/context/base/luat-tex.lua b/tex/context/base/luat-tex.lua
deleted file mode 100644
index 8560c528d..000000000
--- a/tex/context/base/luat-tex.lua
+++ /dev/null
@@ -1,588 +0,0 @@
--- filename : luat-zip.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-tex'] = 1.001
-
--- special functions that deal with io
-
-local format = string.format
-
-if texconfig and not texlua then
-
- input.level = input.level or 0
-
- if input.logmode() == 'xml' then
- function input.show_open(name)
- input.level = input.level + 1
- texio.write_nl("<f l='"..input.level.."' n='"..name.."'>")
- end
- function input.show_close(name)
- texio.write("</f> ")
- input.level = input.level - 1
- end
- function input.show_load(name)
- texio.write_nl("<f l='"..(input.level+1).."' n='"..name.."'/>") -- level?
- end
- else
- function input.show_open () end
- function input.show_close() end
- function input.show_load () end
- end
-
- function input.finders.generic(tag,filename,filetype)
- local foundname = input.find_file(filename,filetype)
- if foundname and foundname ~= "" then
- if input.trace > 0 then
- input.logger('+ finder: %s, file: %s', tag,filename)
- end
- return foundname
- else
- if input.trace > 0 then
- input.logger('- finder: %s, file: %s', tag,filename)
- end
- return unpack(input.finders.notfound)
- end
- end
-
- input.filters.dynamic_translator = nil
- input.filters.frozen_translator = nil -- not used here
- input.filters.utf_translator = nil
- input.filters.user_translator = nil
-
- function input.openers.text_opener(filename,file_handle,tag)
- local u = unicode.utftype(file_handle)
- local t = { }
- if u > 0 then
- if input.trace > 0 then
- input.logger('+ opener: %s (%s), file: %s',tag,unicode.utfname[u],filename)
- end
- local l
- if u > 2 then
- l = unicode.utf32_to_utf8(file_handle:read("*a"),u==4)
- else
- l = unicode.utf16_to_utf8(file_handle:read("*a"),u==2)
- end
- file_handle:close()
- t = {
- utftype = u, -- may go away
- lines = l,
- current = 0, -- line number, not really needed
- handle = nil,
- noflines = #l,
- close = function()
- if input.trace > 0 then
- input.logger('= closer: %s (%s), file: %s',tag,unicode.utfname[u],filename)
- end
- input.show_close(filename)
- t = nil
- end,
---~ getline = function(n)
---~ local line = t.lines[n]
---~ if not line or line == "" then
---~ return ""
---~ else
---~ local translator = input.filters.utf_translator
---~ return (translator and translator(line)) or line
---~ end
---~ end,
- reader = function(self)
- self = self or t
- local current, lines = self.current, self.lines
- if current >= #lines then
- return nil
- else
- current = current + 1
- self.current = current
- local line = lines[current]
- if not line then
- return nil
- elseif line == "" then
- return ""
- else
- translator = filters.utf_translator
- if translator then
- line = translator(line)
- translator = filters.user_translator
- if translator then
- line = translator(line)
- end
- end
- return line
- end
- end
- end
- }
- else
- if input.trace > 0 then
- input.logger('+ opener: %s, file: %s',tag,filename)
- end
- -- todo: file;name -> freeze / eerste regel scannen -> freeze
- local filters = input.filters
- t = {
- reader = function(self)
- local line = file_handle:read()
- if not line then
- return nil
- elseif line == "" then
- return ""
- else
- translator = filters.dynamic_translator or filters.utf_translator
- if translator then
- line = translator(line)
- translator = filters.user_translator
- if translator then
- line = translator(line)
- end
- end
- return line
- end
- end,
- close = function()
- if input.trace > 0 then
- input.logger('= closer: %s, file: %s',tag,filename)
- end
- input.show_close(filename)
- file_handle:close()
- t = nil
- end,
- handle = function()
- return file_handle
- end,
- noflines = function()
- t.noflines = io.noflines(file_handle)
- return t.noflines
- end
- }
- end
- return t
- end
-
- function input.openers.generic(tag,filename)
- if filename and filename ~= "" then
- local f = io.open(filename,"r")
- if f then
- input.show_open(filename)
- return input.openers.text_opener(filename,f,tag)
- end
- end
- if input.trace > 0 then
- input.logger('- opener: %s, file: %s',tag,filename)
- end
- return unpack(input.openers.notfound)
- end
-
- function input.loaders.generic(tag,filename)
- if filename and filename ~= "" then
- local f = io.open(filename,"rb")
- if f then
- input.show_load(filename)
- if input.trace > 0 then
- input.logger('+ loader: %s, file: %s',tag,filename)
- end
- local s = f:read("*a")
- if garbagecollector and garbagecollector.check then garbagecollector.check(#s) end
- f:close()
- if s then
- return true, s, #s
- end
- end
- end
- if input.trace > 0 then
- input.logger('- loader: %s, file: %s',tag,filename)
- end
- return unpack(input.loaders.notfound)
- end
-
- function input.finders.tex(filename,filetype)
- return input.finders.generic('tex',filename,filetype)
- end
- function input.openers.tex(filename)
- return input.openers.generic('tex',filename)
- end
- function input.loaders.tex(filename)
- return input.loaders.generic('tex',filename)
- end
-
-end
-
--- callback into the file io and related things; disabling kpse
-
-
-if texconfig and not texlua then do
-
- -- this is not the right place, because we refer to quite some not yet defined tables, but who cares ...
-
- ctx = ctx or { }
-
- function ctx.writestatus(a,b,c,...)
- if c then
- texio.write_nl(("%-15s: %s\n"):format(a,b:format(c,...)))
- else
- texio.write_nl(("%-15s: %s\n"):format(a,b)) -- b can have %'s
- end
- end
-
- -- this will become: ctx.install_statistics(fnc() return ..,.. end) etc
-
- local statusinfo, n = { }, 0
-
- function ctx.register_statistics(tag,pattern,fnc)
- statusinfo[#statusinfo+1] = { tag, pattern, fnc }
- if #tag > n then n = #tag end
- end
-
- function ctx.memused() -- no math.round yet -)
- -- collectgarbage("collect")
- local round = math.round or math.floor
- return string.format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
- end
-
- function ctx.show_statistics() -- todo: move calls
- local loadtime, register_statistics = input.loadtime, ctx.register_statistics
- if caches then
- register_statistics("used config path", "%s", function() return caches.configpath() end)
- register_statistics("used cache path", "%s", function() return caches.temp() or "?" end)
- end
- if status.luabytecodes > 0 and input.storage and input.storage.done then
- register_statistics("modules/dumps/instances", "%s/%s/%s", function() return status.luabytecodes-500, input.storage.done, status.luastates end)
- end
- if input.instance then
- register_statistics("input load time", "%s seconds", function() return loadtime(input.instance) end)
- end
- if ctx and input.hastimer(ctx) then
- register_statistics("startup time","%s seconds (including runtime option file processing)", function() return loadtime(ctx) end)
- end
- if job then
- register_statistics("jobdata time","%s seconds saving, %s seconds loading", function() return loadtime(job._save_), loadtime(job._load_) end)
- end
- if fonts then
- register_statistics("fonts load time","%s seconds", function() return loadtime(fonts) end)
- end
- if xml then
- register_statistics("xml load time", "%s seconds, lpath calls: %s, cached calls: %s", function()
- local stats = xml.statistics()
- return loadtime(xml), stats.lpathcalls, stats.lpathcached
- end)
- register_statistics("lxml load time", "%s seconds preparation, backreferences: %i", function()
- return loadtime(lxml), #lxml.self
- end)
- end
- if mptopdf then
- register_statistics("mps conversion time", "%s seconds", function() return loadtime(mptopdf) end)
- end
- if nodes then
- register_statistics("node processing time", "%s seconds including kernel", function() return loadtime(nodes) end)
- end
- if kernel then
- register_statistics("kernel processing time", "%s seconds", function() return loadtime(kernel) end)
- end
- if attributes then
- register_statistics("attribute processing time", "%s seconds", function() return loadtime(attributes) end)
- end
- if languages then
- register_statistics("language load time", "%s seconds, n=%s", function() return loadtime(languages), languages.hyphenation.n() end)
- end
- if figures then
- register_statistics("graphics processing time", "%s seconds including tex, n=%s", function() return loadtime(figures), figures.n or "?" end)
- end
- if metapost then
- register_statistics("metapost processing time", "%s seconds, loading: %s seconds, execution: %s seconds, n: %s", function() return loadtime(metapost), loadtime(mplib), loadtime(metapost.exectime), metapost.n end)
- end
- if status.luastate_bytes and ctx.memused then
- register_statistics("current memory usage", "%s", ctx.memused)
- end
- if nodes then
- register_statistics("cleaned up reserved nodes", "%s nodes, %s lists of %s", function() return nodes.cleanup_reserved(tex.count[24]) end) -- \topofboxstack
- end
- if status.node_mem_usage then
- register_statistics("node memory usage", "%s", function() return status.node_mem_usage end)
- end
- if languages then
- register_statistics("loaded patterns", "%s", function() return languages.logger.report() end)
- end
- if fonts then
- register_statistics("loaded fonts", "%s", function() return fonts.logger.report() end)
- end
- if status.cs_count then
- register_statistics("control sequences", "%s of %s", function() return status.cs_count, status.hash_size+status.hash_extra end)
- end
- if status.callbacks and xml then -- xml for being in context -)
- ctx.register_statistics("callbacks", "direct: %s, indirect: %s, total: %s%s", function()
- local total, indirect = status.callbacks, status.indirect_callbacks
- local pages = tex.count['realpageno'] - 1
- if pages > 1 then
- return total-indirect, indirect, total, format(" (%i per page)",total/pages)
- else
- return total-indirect, indirect, total, ""
- end
- end)
- else
- ctx.register_statistics("callbacks", "direct: %s, indirect: %s, total: %s", function()
- local total, indirect = status.callbacks, status.indirect_callbacks
- return total-indirect, indirect, total
- end)
- end
- if xml then -- so we are in mkiv, we need a different check
- register_statistics("runtime", "%s seconds, %i processed pages, %i shipped pages, %.3f pages/second", function()
- input.stoptiming(input.instance)
- local runtime = loadtime(input.instance)
- local shipped = tex.count['nofshipouts']
- local pages = tex.count['realpageno'] - 1
- local persecond = shipped / runtime
- return runtime, pages, shipped, persecond
- end)
- end
- for _, t in ipairs(statusinfo) do
- local tag, pattern, fnc = t[1], t[2], t[3]
- ctx.writestatus("mkiv lua stats", "%s - %s", tag:rpadd(n," "), pattern:format(fnc()))
- end-- input.expanded_path_list("osfontdir")
- end
-
-end end
-
-if texconfig and not texlua then
-
- texconfig.kpse_init = false
- texconfig.trace_file_names = input.logmode() == 'tex'
- texconfig.max_print_line = 100000
-
- -- if still present, we overload kpse (put it off-line so to say)
-
- input.starttiming(input.instance)
-
- if not input.instance then
-
- if not input.instance then -- prevent a second loading
-
- input.instance = input.reset()
- input.instance.progname = 'context'
- input.instance.engine = 'luatex'
- input.instance.validfile = input.validctxfile
-
- input.load()
-
- end
-
- if callback then
- callback.register('find_read_file' , function(id,name) return input.findtexfile(name) end)
- callback.register('open_read_file' , function( name) return input.opentexfile(name) end)
- end
-
- if callback then
- callback.register('find_data_file' , function(name) return input.findbinfile(name,"tex") end)
- callback.register('find_enc_file' , function(name) return input.findbinfile(name,"enc") end)
- callback.register('find_font_file' , function(name) return input.findbinfile(name,"tfm") end)
- callback.register('find_format_file' , function(name) return input.findbinfile(name,"fmt") end)
- callback.register('find_image_file' , function(name) return input.findbinfile(name,"tex") end)
- callback.register('find_map_file' , function(name) return input.findbinfile(name,"map") end)
- callback.register('find_ocp_file' , function(name) return input.findbinfile(name,"ocp") end)
- callback.register('find_opentype_file' , function(name) return input.findbinfile(name,"otf") end)
- callback.register('find_output_file' , function(name) return name end)
- callback.register('find_pk_file' , function(name) return input.findbinfile(name,"pk") end)
- callback.register('find_sfd_file' , function(name) return input.findbinfile(name,"sfd") end)
- callback.register('find_truetype_file' , function(name) return input.findbinfile(name,"ttf") end)
- callback.register('find_type1_file' , function(name) return input.findbinfile(name,"pfb") end)
- callback.register('find_vf_file' , function(name) return input.findbinfile(name,"vf") end)
-
- callback.register('read_data_file' , function(file) return input.loadbinfile(file,"tex") end)
- callback.register('read_enc_file' , function(file) return input.loadbinfile(file,"enc") end)
- callback.register('read_font_file' , function(file) return input.loadbinfile(file,"tfm") end)
- -- format
- -- image
- callback.register('read_map_file' , function(file) return input.loadbinfile(file,"map") end)
- callback.register('read_ocp_file' , function(file) return input.loadbinfile(file,"ocp") end)
---~ callback.register('read_opentype_file' , function(file) return input.loadbinfile(file,"otf") end)
- -- output
- callback.register('read_pk_file' , function(file) return input.loadbinfile(file,"pk") end)
- callback.register('read_sfd_file' , function(file) return input.loadbinfile(file,"sfd") end)
---~ callback.register('read_truetype_file' , function(file) return input.loadbinfile(file,"ttf") end)
---~ callback.register('read_type1_file' , function(file) return input.loadbinfile(file,"pfb") end)
- callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"vf" ) end)
- end
-
- if input.aleph_mode == nil then environment.aleph_mode = true end -- some day we will drop omega font support
-
- if callback and input.aleph_mode then
- callback.register('find_font_file' , function(name) return input.findbinfile(name,"ofm") end)
- callback.register('read_font_file' , function(file) return input.loadbinfile(file,"ofm") end)
- callback.register('find_vf_file' , function(name) return input.findbinfile(name,"ovf") end)
- callback.register('read_vf_file' , function(file) return input.loadbinfile(file,"ovf") end)
- end
-
- if callback then
- callback.register('find_write_file' , function(id,name) return name end)
- end
-
- if callback and (not config or (#config == 0)) then
- callback.register('find_format_file' , function(name) return name end)
- end
-
- if callback and false then
- for k, v in pairs(callback.list()) do
- if not v then texio.write_nl("<w>callback "..k.." is not set</w>") end
- end
- end
-
- if callback then
-
- input.start_actions = { }
- input.stop_actions = { }
-
- function input.register_start_actions(f) table.insert(input.start_actions, f) end
- function input.register_stop_actions (f) table.insert(input.stop_actions, f) end
-
- --~ callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
- --~ callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end end)
-
- end
-
- if callback then
-
- if input.logmode() == 'xml' then
-
- function input.start_page_number()
- texio.write_nl("<p real='" .. tex.count[0] .. "' page='"..tex.count[1].."' sub='"..tex.count[2].."'")
- end
- function input.stop_page_number()
- texio.write("/>")
- texio.write_nl("")
- end
-
- callback.register('start_page_number' , input.start_page_number)
- callback.register('stop_page_number' , input.stop_page_number )
-
- function input.report_output_pages(p,b)
- texio.write_nl("<v k='pages'>"..p.."</v>")
- texio.write_nl("<v k='bytes'>"..b.."</v>")
- texio.write_nl("")
- end
- function input.report_output_log()
- end
-
- callback.register('report_output_pages', input.report_output_pages)
- callback.register('report_output_log' , input.report_output_log )
-
- function input.start_run()
- texio.write_nl("<?xml version='1.0' standalone='yes'?>")
- texio.write_nl("<job xmlns='www.tug.org/luatex/schemas/context-job.rng'>")
- texio.write_nl("")
- end
- function input.stop_run()
- texio.write_nl("</job>")
- end
- function input.show_statistics()
- for k,v in pairs(status.list()) do
- texio.write_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
- end
- end
-
- table.insert(input.start_actions, input.start_run)
- table.insert(input.stop_actions , input.show_statistics)
- table.insert(input.stop_actions , input.stop_run)
-
- else
- table.insert(input.stop_actions , input.show_statistics)
- end
-
- callback.register('start_run', function() for _, a in pairs(input.start_actions) do a() end end)
- callback.register('stop_run' , function() for _, a in pairs(input.stop_actions ) do a() end ctx.show_statistics() end)
-
- end
-
- end
-
- if kpse then
-
- function kpse.find_file(filename,filetype,mustexist)
- return input.find_file(filename,filetype,mustexist)
- end
- function kpse.expand_path(variable)
- return input.expand_path(variable)
- end
- function kpse.expand_var(variable)
- return input.expand_var(variable)
- end
- function kpse.expand_braces(variable)
- return input.expand_braces(variable)
- end
-
- end
-
-end
-
--- program specific configuration (memory settings and alike)
-
-if texconfig and not texlua then
-
- luatex = luatex or { }
-
- luatex.variablenames = {
- 'main_memory', 'extra_mem_bot', 'extra_mem_top',
- 'buf_size','expand_depth',
- 'font_max', 'font_mem_size',
- 'hash_extra', 'max_strings', 'pool_free', 'pool_size', 'string_vacancies',
- 'obj_tab_size', 'pdf_mem_size', 'dest_names_size',
- 'nest_size', 'param_size', 'save_size', 'stack_size',
- 'trie_size', 'hyph_size', 'max_in_open',
- 'ocp_stack_size', 'ocp_list_size', 'ocp_buf_size'
- }
-
- function luatex.variables()
- local t, x = { }, nil
- for _,v in pairs(luatex.variablenames) do
- x = input.var_value(v)
- if x and x:find("^%d+$") then
- t[v] = tonumber(x)
- end
- end
- return t
- end
-
- function luatex.setvariables(tab)
- for k,v in pairs(luatex.variables()) do
- tab[k] = v
- end
- end
-
- if not luatex.variables_set then
- luatex.setvariables(texconfig)
- luatex.variables_set = true
- end
-
- texconfig.max_print_line = 100000
- texconfig.max_in_open = 127
-
-end
-
--- some tex basics, maybe this will move to ctx
-
-if tex then
-
- local texsprint, texwrite = tex.sprint, tex.write
-
- if not cs then cs = { } end
-
- function cs.def(k,v)
- texsprint(tex.texcatcodes, "\\def\\" .. k .. "{" .. v .. "}")
- end
-
- function cs.chardef(k,v)
- texsprint(tex.texcatcodes, "\\chardef\\" .. k .. "=" .. v .. "\\relax")
- end
-
- function cs.boolcase(b)
- if b then texwrite(1) else texwrite(0) end
- end
-
- function cs.testcase(b)
- if b then
- texsprint(tex.texcatcodes, "\\firstoftwoarguments")
- else
- texsprint(tex.texcatcodes, "\\secondoftwoarguments")
- end
- end
-
-end
diff --git a/tex/context/base/luat-tmp.lua b/tex/context/base/luat-tmp.lua
deleted file mode 100644
index 1e3f55380..000000000
--- a/tex/context/base/luat-tmp.lua
+++ /dev/null
@@ -1,433 +0,0 @@
-if not modules then modules = { } end modules ['luat-tmp'] = {
- version = 1.001,
- comment = "companion to luat-lib.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This module deals with caching data. It sets up the paths and
-implements loaders and savers for tables. Best is to set the
-following variable. When not set, the usual paths will be
-checked. Personally I prefer the (users) temporary path.</p>
-
-</code>
-TEXMFCACHE=$TMP;$TEMP;$TMPDIR;$TEMPDIR;$HOME;$TEXMFVAR;$VARTEXMF;.
-</code>
-
-<p>Currently we do no locking when we write files. This is no real
-problem because most caching involves fonts and the chance of them
-being written at the same time is small. We also need to extend
-luatools with a recache feature.</p>
---ldx]]--
-
-local format = string.format
-
-caches = caches or { }
-dir = dir or { }
-texmf = texmf or { }
-
-caches.path = caches.path or nil
-caches.base = caches.base or "luatex-cache"
-caches.more = caches.more or "context"
-caches.direct = false -- true is faster but may need huge amounts of memory
-caches.trace = false
-caches.tree = false
-caches.paths = caches.paths or nil
-caches.force = false
-caches.defaults = { "TEXMFCACHE", "TMPDIR", "TEMPDIR", "TMP", "TEMP", "HOME", "HOMEPATH" }
-
-function caches.temp()
- local cachepath = nil
- local function check(list,isenv)
- if not cachepath then
- for _, v in ipairs(list) do
- cachepath = (isenv and (os.env[v] or "")) or v or ""
- if cachepath == "" then
- -- next
- else
- cachepath = input.clean_path(cachepath)
- if lfs.isdir(cachepath) and file.iswritable(cachepath) then -- lfs.attributes(cachepath,"mode") == "directory"
- break
- elseif caches.force or io.ask(format("\nShould I create the cache path %s?",cachepath), "no", { "yes", "no" }) == "yes" then
- dir.mkdirs(cachepath)
- if lfs.isdir(cachepath) and file.iswritable(cachepath) then
- break
- end
- end
- end
- cachepath = nil
- end
- end
- end
- check(input.clean_path_list("TEXMFCACHE") or { })
- check(caches.defaults,true)
- if not cachepath then
- print("\nfatal error: there is no valid (writable) cache path defined\n")
- os.exit()
- elseif not lfs.isdir(cachepath) then -- lfs.attributes(cachepath,"mode") ~= "directory"
- print(format("\nfatal error: cache path %s is not a directory\n",cachepath))
- os.exit()
- end
- cachepath = input.normalize_name(cachepath)
- function caches.temp()
- return cachepath
- end
- return cachepath
-end
-
-function caches.configpath()
- return table.concat(input.instance.cnffiles,";")
-end
-
-function caches.hashed(tree)
- return md5.hex((tree:lower()):gsub("[\\\/]+","/"))
-end
-
---~ tracing:
-
---~ function caches.hashed(tree)
---~ tree = (tree:lower()):gsub("[\\\/]+","/")
---~ local hash = md5.hex(tree)
---~ if input.verbose then -- temp message
---~ input.report("hashing %s => %s",tree,hash)
---~ end
---~ return hash
---~ end
-
-function caches.treehash()
- local tree = caches.configpath()
- if not tree or tree == "" then
- return false
- else
- return caches.hashed(tree)
- end
-end
-
-function caches.setpath(...)
- if not caches.path then
- if not caches.path then
- caches.path = caches.temp()
- end
- caches.path = input.clean_path(caches.path) -- to be sure
- if lfs then
- caches.tree = caches.tree or caches.treehash()
- if caches.tree then
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more,caches.tree)
- else
- caches.path = dir.mkdirs(caches.path,caches.base,caches.more)
- end
- end
- end
- if not caches.path then
- caches.path = '.'
- end
- caches.path = input.clean_path(caches.path)
- if lfs and not table.is_empty({...}) then
- local pth = dir.mkdirs(caches.path,...)
- return pth
- end
- caches.path = dir.expand_name(caches.path)
- return caches.path
-end
-
-function caches.definepath(category,subcategory)
- return function()
- return caches.setpath(category,subcategory)
- end
-end
-
-function caches.setluanames(path,name)
- return path .. "/" .. name .. ".tma", path .. "/" .. name .. ".tmc"
-end
-
-function caches.loaddata(path,name)
- local tmaname, tmcname = caches.setluanames(path,name)
- local loader = loadfile(tmcname) or loadfile(tmaname)
- if loader then
- return loader()
- else
- return false
- end
-end
-
-function caches.is_writable(filepath,filename)
- local tmaname, tmcname = caches.setluanames(filepath,filename)
- return file.is_writable(tmaname)
-end
-
-function caches.savedata(filepath,filename,data,raw)
- local tmaname, tmcname = caches.setluanames(filepath,filename)
- local reduce, simplify = true, true
- if raw then
- reduce, simplify = false, false
- end
- if caches.direct then
- file.savedata(tmaname, table.serialize(data,'return',true,true,false)) -- no hex
- else
- table.tofile(tmaname, data,'return',true,true,false) -- maybe not the last true
- end
- local cleanup = input.boolean_variable("PURGECACHE", false)
- local strip = input.boolean_variable("LUACSTRIP", true)
- utils.lua.compile(tmaname, tmcname, cleanup, strip)
-end
-
--- here we use the cache for format loading (texconfig.[formatname|jobname])
-
---~ if tex and texconfig and texconfig.formatname and texconfig.formatname == "" then
-if tex and texconfig and (not texconfig.formatname or texconfig.formatname == "") and input and input.instance then
- if not texconfig.luaname then texconfig.luaname = "cont-en.lua" end -- or luc
- texconfig.formatname = caches.setpath("formats") .. "/" .. texconfig.luaname:gsub("%.lu.$",".fmt")
-end
-
---[[ldx--
-<p>Once we found ourselves defining similar cache constructs
-several times, containers were introduced. Containers are used
-to collect tables in memory and reuse them when possible based
-on (unique) hashes (to be provided by the calling function).</p>
-
-<p>Caching to disk is disabled by default. Version numbers are
-stored in the saved table which makes it possible to change the
-table structures without bothering about the disk cache.</p>
-
-<p>Examples of usage can be found in the font related code.</p>
---ldx]]--
-
-containers = { }
-containers.trace = false
-
-do -- local report
-
- local function report(container,tag,name)
- if caches.trace or containers.trace or container.trace then
- logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
- end
- end
-
- local allocated = { }
-
- -- tracing
-
- function containers.define(category, subcategory, version, enabled)
- return function()
- if category and subcategory then
- local c = allocated[category]
- if not c then
- c = { }
- allocated[category] = c
- end
- local s = c[subcategory]
- if not s then
- s = {
- category = category,
- subcategory = subcategory,
- storage = { },
- enabled = enabled,
- version = version or 1.000,
- trace = false,
- path = caches.setpath(category,subcategory),
- }
- c[subcategory] = s
- end
- return s
- else
- return nil
- end
- end
- end
-
- function containers.is_usable(container, name)
- return container.enabled and caches.is_writable(container.path, name)
- end
-
- function containers.is_valid(container, name)
- if name and name ~= "" then
- local storage = container.storage[name]
- return storage and not table.is_empty(storage) and storage.cache_version == container.version
- else
- return false
- end
- end
-
- function containers.read(container,name)
- if container.enabled and not container.storage[name] then
- container.storage[name] = caches.loaddata(container.path,name)
- if containers.is_valid(container,name) then
- report(container,"loaded",name)
- else
- container.storage[name] = nil
- end
- end
- if container.storage[name] then
- report(container,"reusing",name)
- end
- return container.storage[name]
- end
-
- function containers.write(container, name, data)
- if data then
- data.cache_version = container.version
- if container.enabled then
- local unique, shared = data.unique, data.shared
- data.unique, data.shared = nil, nil
- caches.savedata(container.path, name, data)
- report(container,"saved",name)
- data.unique, data.shared = unique, shared
- end
- report(container,"stored",name)
- container.storage[name] = data
- end
- return data
- end
-
- function containers.content(container,name)
- return container.storage[name]
- end
-
-end
-
--- since we want to use the cache instead of the tree, we will now
--- reimplement the saver.
-
-local save_data = input.aux.save_data
-local load_data = input.aux.load_data
-
-input.cachepath = nil -- public, for tracing
-input.usecache = true -- public, for tracing
-
-function input.aux.save_data(dataname, check)
- save_data(dataname, check, function(cachename,dataname)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(cachename))
- else
- return file.join(cachename,dataname)
- end
- end)
-end
-
-function input.aux.load_data(pathname,dataname,filename)
- load_data(pathname,dataname,filename,function(dataname,filename)
- input.usecache = not toboolean(input.expansion("CACHEINTDS") or "false",true)
- if input.usecache then
- input.cachepath = input.cachepath or caches.definepath("trees")
- return file.join(input.cachepath(),caches.hashed(pathname))
- else
- if not filename or (filename == "") then
- filename = dataname
- end
- return file.join(pathname,filename)
- end
- end)
-end
-
--- we will make a better format, maybe something xml or just text or lua
-
-input.automounted = input.automounted or { }
-
-function input.automount(usecache)
- local mountpaths = input.clean_path_list(input.expansion('TEXMFMOUNT'))
- if table.is_empty(mountpaths) and usecache then
- mountpaths = { caches.setpath("mount") }
- end
- if not table.is_empty(mountpaths) then
- input.starttiming(input.instance)
- for k, root in pairs(mountpaths) do
- local f = io.open(root.."/url.tmi")
- if f then
- for line in f:lines() do
- if line then
- if line:find("^[%%#%-]") then -- or %W
- -- skip
- elseif line:find("^zip://") then
- input.report("mounting %s",line)
- table.insert(input.automounted,line)
- input.usezipfile(line)
- end
- end
- end
- f:close()
- end
- end
- input.stoptiming(input.instance)
- end
-end
-
--- store info in format
-
-input.storage = { }
-input.storage.data = { }
-input.storage.min = 0 -- 500
-input.storage.max = input.storage.min - 1
-input.storage.trace = false -- true
-input.storage.done = input.storage.done or 0
-input.storage.evaluators = { }
--- (evaluate,message,names)
-
-function input.storage.register(...)
- input.storage.data[#input.storage.data+1] = { ... }
-end
-
-function input.storage.evaluate(name)
- input.storage.evaluators[#input.storage.evaluators+1] = name
-end
-
-function input.storage.finalize() -- we can prepend the string with "evaluate:"
- for _, t in ipairs(input.storage.evaluators) do
- for i, v in pairs(t) do
- if type(v) == "string" then
- t[i] = loadstring(v)()
- elseif type(v) == "table" then
- for _, vv in pairs(v) do
- if type(vv) == "string" then
- t[i] = loadstring(vv)()
- end
- end
- end
- end
- end
-end
-
-function input.storage.dump()
- for name, data in ipairs(input.storage.data) do
- local evaluate, message, original, target = data[1], data[2], data[3] ,data[4]
- local name, initialize, finalize, code = nil, "", "", ""
- for str in target:gmatch("([^%.]+)") do
- if name then
- name = name .. "." .. str
- else
- name = str
- end
- initialize = format("%s %s = %s or {} ", initialize, name, name)
- end
- if evaluate then
- finalize = "input.storage.evaluate(" .. name .. ")"
- end
- input.storage.max = input.storage.max + 1
- if input.storage.trace then
- logs.report('storage','saving %s in slot %s',message,input.storage.max)
- code =
- initialize ..
- format("logs.report('storage','restoring %s from slot %s') ",message,input.storage.max) ..
- table.serialize(original,name) ..
- finalize
- else
- code = initialize .. table.serialize(original,name) .. finalize
- end
- lua.bytecode[input.storage.max] = loadstring(code)
- end
-end
-
--- we also need to count at generation time (nicer for message)
-
-if lua.bytecode then -- from 0 upwards
- local i = input.storage.min
- while lua.bytecode[i] do
- lua.bytecode[i]()
- lua.bytecode[i] = nil
- i = i + 1
- end
- input.storage.done = i
-end
diff --git a/tex/context/base/luat-tre.lua b/tex/context/base/luat-tre.lua
deleted file mode 100644
index ed1ff59f8..000000000
--- a/tex/context/base/luat-tre.lua
+++ /dev/null
@@ -1,45 +0,0 @@
--- filename : luat-tre.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-tre'] = 1.001
-
--- \input tree://oeps1/**/oeps.tex
-
-do
-
- local done, found = { }, { }
-
- function input.finders.tree(specification,filetype)
- local fnd = found[specification]
- if not fnd then
- local spec = input.splitmethod(specification).path or ""
- if spec ~= "" then
- local path, name = file.dirname(spec), file.basename(spec)
- if path == "" then path = "." end
- local hash = done[path]
- if not hash then
- local pattern = path .. "/*" -- we will use the proper splitter
- hash = dir.glob(pattern)
- done[path] = hash
- end
- local pattern = "/" .. name:gsub("([%.%-%+])", "%%%1") .. "$"
- for k, v in pairs(hash) do
- if v:find(pattern) then
- found[specification] = v
- return v
- end
- end
- end
- fnd = unpack(input.finders.notfound)
- found[specification] = fnd
- end
- return fnd
- end
-
- input.openers.tree = input.openers.generic
- input.loaders.tree = input.loaders.generic
-
-end
diff --git a/tex/context/base/luat-uni.lua b/tex/context/base/luat-uni.lua
deleted file mode 100644
index ef57663bb..000000000
--- a/tex/context/base/luat-uni.lua
+++ /dev/null
@@ -1,21 +0,0 @@
--- filename : luat-uni.lua
--- comment : companion to luat-uni.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-uni'] = 1.001
-
-function unicode.utf8.split(str)
- local t = { }
- for snippet in str:utfcharacters() do
- t[#t+1] = snippet
- end
- return t
-end
-
-function unicode.utf8.each(str,fnc)
- for snippet in str:utfcharacters() do
- fnc(snippet)
- end
-end
diff --git a/tex/context/base/luat-uni.tex b/tex/context/base/luat-uni.tex
deleted file mode 100644
index 453c8e0d8..000000000
--- a/tex/context/base/luat-uni.tex
+++ /dev/null
@@ -1,33 +0,0 @@
-%D \module
-%D [ file=luat-uni,
-%D version=2006.04.25,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=Unicode Support,
-%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.
-
-\writestatus{loading}{Lua Support Macros (unicode)}
-
-\registerctxluafile{luat-uni}{1.001}
-
-% \defconvertedargument\ascii{ÀÁÂÃÄÅàáâãäå}
-%
-% \lua{ tex.print ("\ascii")}
-% \lua{ tex.print(unicode.utf8.reverse ("\ascii"))}
-% \lua{ tex.print(unicode.utf8.lower ("\ascii"))}
-% \lua{ tex.print(unicode.utf8.upper ("\ascii"))}
-% \lua{ tex.print(unicode.utf8.len ("\ascii"))}
-% \lua{ tex.print(table.getn(unicode.utf8.split("\ascii"))}}
-%
-% \lua{unicode.utf8.each("\ascii", function(chr) tex.print("["..chr.."]") end)}
-
-\let\UnicodeOne \gobbleoneargument
-\let\UnicodeTwo \gobbleoneargument
-\let\UnicodeThree\gobbleoneargument
-
-\endinput
diff --git a/tex/context/base/luat-zip.lua b/tex/context/base/luat-zip.lua
deleted file mode 100644
index 40386e570..000000000
--- a/tex/context/base/luat-zip.lua
+++ /dev/null
@@ -1,249 +0,0 @@
--- filename : luat-zip.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
-if not versions then versions = { } end versions['luat-zip'] = 1.001
-
-local format = string.format
-
-if zip and input then
- zip.supported = true
-else
- zip = { }
- zip.supported = false
-end
-
-if not zip.supported then
-
- if not input then input = { } end -- will go away
-
- function zip.openarchive (...) return nil end -- needed ?
- function zip.closenarchive (...) end -- needed ?
- function input.usezipfile (...) end -- needed ?
-
-else
-
- -- zip:///oeps.zip?name=bla/bla.tex
- -- zip:///oeps.zip?tree=tex/texmf-local
-
- local function validzip(str)
- if not str:find("^zip://") then
- return "zip:///" .. str
- else
- return str
- end
- end
-
- zip.archives = { }
- zip.registeredfiles = { }
-
- function zip.openarchive(name)
- if not name or name == "" then
- return nil
- else
- local arch = zip.archives[name]
- if arch then
- return arch
- else
- local full = input.find_file(name) or ""
- local arch = (full ~= "" and zip.open(full)) or false
- zip.archives[name] = arch
- return arch
- end
- end
- end
-
- function zip.closearchive(name)
- if not name or name == "" and zip.archives[name] then
- zip.close(zip.archives[name])
- zip.archives[name] = nil
- end
- end
-
- -- zip:///texmf.zip?tree=/tex/texmf
- -- zip:///texmf.zip?tree=/tex/texmf-local
- -- zip:///texmf-mine.zip?tree=/tex/texmf-projects
-
- function input.locators.zip(specification) -- where is this used? startup zips (untested)
- specification = input.splitmethod(specification)
- local zipfile = specification.path
- local zfile = zip.openarchive(name) -- tricky, could be in to be initialized tree
- if input.trace > 0 then
- if zfile then
- input.logger('! zip locator, found: %s',specification.original)
- else
- input.logger('? zip locator, not found: %s',specification.original)
- end
- end
- end
-
- function input.hashers.zip(tag,name)
- input.report("loading zip file %s as %s",name,tag)
- input.usezipfile(tag .."?tree=" .. name)
- end
-
- function input.concatinators.zip(tag,path,name)
- if not path or path == "" then
- return tag .. '?name=' .. name
- else
- return tag .. '?name=' .. path .. "/" .. name
- end
- end
-
- function input.is_readable.zip(name)
- return true
- end
-
- function input.finders.zip(specification,filetype)
- specification = input.splitmethod(specification)
- if specification.path then
- local q = url.query(specification.query)
- if q.name then
- local zfile = zip.openarchive(specification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('! zip finder, path: %s',specification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- dfile = zfile:close()
- if input.trace > 0 then
- input.logger('+ zip finder, name: %s',q.name)
- end
- return specification.original
- end
- elseif input.trace > 0 then
- input.logger('? zip finder, path %s',specification.path)
- end
- end
- end
- if input.trace > 0 then
- input.logger('- zip finder, name: %s',filename)
- end
- return unpack(input.finders.notfound)
- end
-
- function input.openers.zip(specification)
- local zipspecification = input.splitmethod(specification)
- if zipspecification.path then
- local q = url.query(zipspecification.query)
- if q.name then
- local zfile = zip.openarchive(zipspecification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('+ zip starter, path: %s',zipspecification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- input.show_open(specification)
- return input.openers.text_opener(specification,dfile,'zip')
- end
- elseif input.trace > 0 then
- input.logger('- zip starter, path %s',zipspecification.path)
- end
- end
- end
- if input.trace > 0 then
- input.logger('- zip opener, name: %s',filename)
- end
- return unpack(input.openers.notfound)
- end
-
- function input.loaders.zip(specification)
- specification = input.splitmethod(specification)
- if specification.path then
- local q = url.query(specification.query)
- if q.name then
- local zfile = zip.openarchive(specification.path)
- if zfile then
- if input.trace > 0 then
- input.logger('+ zip starter, path: %s',specification.path)
- end
- local dfile = zfile:open(q.name)
- if dfile then
- input.show_load(filename)
- if input.trace > 0 then
- input.logger('+ zip loader, name: %s',filename)
- end
- local s = dfile:read("*all")
- dfile:close()
- return true, s, #s
- end
- elseif input.trace > 0 then
- input.logger('- zip starter, path: %s',specification.path)
- end
- end
- end
- if input.trace > 0 then
- input.logger('- zip loader, name: %s',filename)
- end
- return unpack(input.openers.notfound)
- end
-
- -- zip:///somefile.zip
- -- zip:///somefile.zip?tree=texmf-local -> mount
-
- function input.usezipfile(zipname)
- zipname = validzip(zipname)
- if input.trace > 0 then
- input.logger('! zip use, file: %s',zipname)
- end
- local specification = input.splitmethod(zipname)
- local zipfile = specification.path
- if zipfile and not zip.registeredfiles[zipname] then
- local tree = url.query(specification.query).tree or ""
- if input.trace > 0 then
- input.logger('! zip register, file: %s',zipname)
- end
- local z = zip.openarchive(zipfile)
- if z then
- local instance = input.instance
- if input.trace > 0 then
- input.logger("= zipfile, registering: %s",zipname)
- end
- input.starttiming(instance)
- input.aux.prepend_hash('zip',zipname,zipfile)
- input.aux.extend_texmf_var(zipname) -- resets hashes too
- zip.registeredfiles[zipname] = z
- instance.files[zipname] = input.aux.register_zip_file(z,tree or "")
- input.stoptiming(instance)
- elseif input.trace > 0 then
- input.logger("? zipfile, unknown: %s",zipname)
- end
- elseif input.trace > 0 then
- input.logger('! zip register, no file: %s',zipname)
- end
- end
-
- function input.aux.register_zip_file(z,tree)
- local files, filter = { }, ""
- if tree == "" then
- filter = "^(.+)/(.-)$"
- else
- filter = "^"..tree.."/(.+)/(.-)$"
- end
- if input.trace > 0 then
- input.logger('= zip filter: %s',filter)
- end
- local register, n = input.aux.register_file, 0
- for i in z:files() do
- local path, name = i.filename:match(filter)
- if path then
- if name and name ~= '' then
- register(files, name, path)
- n = n + 1
- else
- -- directory
- end
- else
- register(files, i.filename, '')
- n = n + 1
- end
- end
- input.logger('= zip entries: %s',n)
- return files
- end
-
-end
diff --git a/tex/context/base/lxml-ent.lua b/tex/context/base/lxml-ent.lua
new file mode 100644
index 000000000..c91d12706
--- /dev/null
+++ b/tex/context/base/lxml-ent.lua
@@ -0,0 +1,115 @@
+if not modules then modules = { } end modules ['lxml-ent'] = {
+ 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 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
+
+--[[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>
+--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)
+ local documententities = root.entities
+ local allentities = xml.entities
+ if documententities then
+ for k, v in next, documententities do
+ allentities[k] = v
+ end
+ end
+end
diff --git a/tex/context/base/lxml-ini.lua b/tex/context/base/lxml-ini.lua
index 6b8d014a7..0c40a4baf 100644
--- a/tex/context/base/lxml-ini.lua
+++ b/tex/context/base/lxml-ini.lua
@@ -6,10 +6,19 @@ if not modules then modules = { } end modules ['lxml-ini'] = {
license = "see context related readme files"
}
-local texsprint, texprint = tex.sprint or print, tex.print or print
+local utf = unicode.utf8
+
+local texsprint, texprint, utfchar = tex.sprint or print, tex.print or print, utf.char
local format, concat, insert, remove = string.format, table.concat, table.insert, table.remove
local type, next, tonumber = type, next, tonumber
+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)
+
-- for the moment here
function table.insert_before_value(t,value,extra)
@@ -59,10 +68,11 @@ document.xml = document.xml or { }
lxml = lxml or { }
lxml.loaded = { }
lxml.myself = { }
+lxml.n = 0
-local loaded = lxml.loaded
-local myself = lxml.myself
-local stack = lxml.stack
+local loaded = lxml.loaded
+local myself = lxml.myself
+local stack = lxml.stack
lxml.self = myself -- be backward compatible for a while
@@ -88,22 +98,22 @@ do
local lf = lpeg.P("\n")
local space = lpeg.S(" \t\f\v")
local newline = crlf + cr + lf
- local spacing = space^0 * newline * space^0
+ 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 = (
- newline^2 * lpeg.Cc("") / texprint +
- newline * lpeg.Cc(" ") / texsprint +
- content / texsprint
+ space^0 * newline^2 * lpeg.Cc("") / texprint +
+ space^0 * newline * space^0 * lpeg.Cc(" ") / texsprint +
+ content / texsprint
)^0
---~ local capture = (
---~ newline^2 * lpeg.Cc("") / function(s) texprint (tex.xmlcatcodes,s) end +
---~ newline * lpeg.Cc(" ") / function(s) texsprint(tex.xmlcatcodes,s) end +
---~ content / function(s) texsprint(tex.xmlcatcodes,s) end
---~ )^0
-
local forceraw, rawroot = false, nil
function lxml.startraw()
@@ -136,12 +146,12 @@ do
local function sprint(root)
if not root then
---~ rawroot = false
+ --~ rawroot = false
-- quit
else
local tr = type(root)
if tr == "string" then -- can also be result of lpath
---~ rawroot = false
+ --~ rawroot = false
capture:match(root)
elseif tr == "table" then
rawroot = forceraw and root
@@ -223,15 +233,15 @@ do
local aftercommand = ""
local capture = (
- newline / function( ) texsprint(tex.texcatcodes,linecommand .. "{}") end +
- verbose / function(s) texsprint(tex.vrbcatcodes,s) end +
- space / function( ) texsprint(tex.texcatcodes,spacecommand .. "{}") end
+ 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(tex.texcatcodes,beforecommand .. "{}") end
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
capture:match(str)
- if aftercommand then texsprint(tex.texcatcodes,aftercommand .. "{}") end
+ if aftercommand then texsprint(texcatcodes,aftercommand,"{}") end
end
function lxml.set_verbatim(before,after,obeyedline,obeyedspace)
@@ -249,23 +259,23 @@ do
-- local capture = (space^0*newline)^0 * capture * (space+newline)^0 * -1
local function toverbatim(str)
- if beforecommand then texsprint(tex.texcatcodes,beforecommand .. "{}") end
+ if beforecommand then texsprint(texcatcodes,beforecommand,"{}") end
-- todo: add this to capture
str = str:gsub("^[ \t]+[\n\r]+","")
str = str:gsub("[ \t\n\r]+$","")
capture:match(str)
- if aftercommand then texsprint(tex.texcatcodes,aftercommand .. "{}") end
+ 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(tex.ctxcatcodes,format("%s[%s]",before,root.tg)) end
+ 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(tex.ctxcatcodes,after) end
+ if after then texsprint(ctxcatcodes,after) end
end
end
function lxml.inlineverbatim(id)
@@ -299,12 +309,12 @@ do
if str then
local a, b, c, d = parser:match(str)
if d then
- texsprint(tex.ctxcatcodes,format("\\xmlcontextdirective{%s}{%s}{%s}{%s}",a,b,c,d))
+ texsprint(ctxcatcodes,format("\\xmlcontextdirective{%s}{%s}{%s}{%s}",a,b,c,d))
end
end
end
- -- print(contextdirective("context-mathml-directive function reduction yes yes "))
+ -- print(contextdirective("context-mathml-directive function reduction yes "))
-- print(contextdirective("context-mathml-directive function "))
function lxml.main(id)
@@ -324,36 +334,46 @@ local xmltprint = xml.tprint
xml.originalload = xml.originalload or xml.load
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
function xml.load(filename)
- input.starttiming(xml)
- local xmldata = xml.convert((filename and input.loadtexfile(filename)) or "")
- input.stoptiming(xml)
+ lxml.n = lxml.n + 1
+ starttiming(xml)
+ local xmldata = xml.convert((filename and resolvers.loadtexfile(filename)) or "")
+ stoptiming(xml)
return xmldata
end
function lxml.load(id,filename)
+ lxml.n = lxml.n + 1
filename = commands.preparedfile(filename)
- if lxml.trace_load then
- ctx.writestatus("lxml","loading file: %s",filename)
+ if trace_loading then
+ commands.writestatus("lxml","loading file: %s",filename)
end
loaded[id] = xml.load(filename)
return loaded[id], filename
end
+function lxml.register(id,xmltable)
+ lxml.n = lxml.n + 1
+ loaded[id] = xmltable
+ return xmltable
+end
+
function lxml.include(id,pattern,attribute,recurse)
- input.starttiming(xml)
+ starttiming(xml)
xml.include(get_id(id),pattern,attribute,recurse,function(filename)
if filename then
filename = commands.preparedfile(filename)
- if lxml.trace_load then
- ctx.writestatus("lxml","including file: %s",filename)
+ if trace_loading then
+ commands.writestatus("lxml","including file: %s",filename)
end
- return input.loadtexfile(filename) or ""
+ return resolvers.loadtexfile(filename) or ""
else
return ""
end
end)
- input.stoptiming(xml)
+ stoptiming(xml)
end
function lxml.utfize(id)
@@ -373,7 +393,11 @@ function lxml.all(id,pattern)
-- xmltprint(xmlcollect(get_id(id),pattern))
traverse(get_id(id), lpath(pattern), function(r,d,k)
-- to be checked for root::
- xmlsprint(d[k])
+ if d then
+ xmlsprint(d[k])
+ else -- new, maybe wrong
+--~ xmlsprint(r)
+ end
return false
end)
end
@@ -522,7 +546,7 @@ 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)
+ texsprint(ns,":",r.tg)
else
texsprint(r.tg)
end
@@ -550,9 +574,9 @@ function lxml.concatrange(id,what,start,stop,separator,lastseparator) -- test th
if i == #t then
-- nothing
elseif i == #t-1 and lastseparator ~= "" then
- texsprint(tex.ctxcatcodes,lastseparator)
+ texsprint(ctxcatcodes,lastseparator)
elseif separator ~= "" then
- texsprint(tex.ctxcatcodes,separator)
+ texsprint(ctxcatcodes,separator)
end
end
end
@@ -580,7 +604,7 @@ function xml.command(root, command)
-- setup
local n = #myself + 1
myself[n] = root
- texsprint(tex.ctxcatcodes,format("\\xmlsetup{%i}{%s}",n,command))
+ texsprint(ctxcatcodes,format("\\xmlsetup{%i}{%s}",n,command))
elseif tc == "function" then
-- function
command(root)
@@ -600,11 +624,7 @@ function lxml.setaction(id,pattern,action)
end
end
-lxml.trace_setups = false
-lxml.trace_load = false
-
function lxml.setsetup(id,pattern,setup)
- local trace = lxml.trace_setups
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
@@ -614,17 +634,17 @@ function lxml.setsetup(id,pattern,setup)
if setup == "-" then
dtdk.command = false
if trace then
- texio.write_nl(format("lpath matched -> %s -> skipped", command))
+ logs.report("lxml","lpath matched -> %s -> skipped", command)
end
elseif setup == "+" then
dtdk.command = true
- if trace then
- texio.write_nl(format("lpath matched -> %s -> text", command))
+ if trace_setups then
+ logs.report("lxml","lpath matched -> %s -> text", command)
end
else
dtdk.command = command
- if trace then
- texio.write_nl(format("lpath matched -> %s -> %s", command, command))
+ if trace_setups then
+ logs.report("lxml","lpath matched -> %s -> %s", command, command)
end
end
end
@@ -637,46 +657,46 @@ function lxml.setsetup(id,pattern,setup)
local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg
if b == "-" then
dtdk.command = false
- if trace then
+ if trace_setups then
if ns == "" then
- texio.write_nl(format("lpath matched -> %s -> skipped", tg))
+ logs.report("lxml","lpath matched -> %s -> skipped", tg)
else
- texio.write_nl(format("lpath matched -> %s:%s -> skipped", ns, tg))
+ logs.report("lxml","lpath matched -> %s:%s -> skipped", ns, tg)
end
end
elseif b == "+" then
dtdk.command = true
- if trace then
+ if trace_setups then
if ns == "" then
- texio.write_nl(format("lpath matched -> %s -> text", tg))
+ logs.report("lxml","lpath matched -> %s -> text", tg)
else
- texio.write_nl(format("lpath matched -> %s:%s -> text", ns, tg))
+ logs.report("lxml","lpath matched -> %s:%s -> text", ns, tg)
end
end
else
dtdk.command = a .. tg
- if trace then
+ if trace_setups then
if ns == "" then
- texio.write_nl(format("lpath matched -> %s -> %s", tg, dtdk.command))
+ logs.report("lxml","lpath matched -> %s -> %s", tg, dtdk.command)
else
- texio.write_nl(format("lpath matched -> %s:%s -> %s", ns, tg, dtdk.command))
+ logs.report("lxml","lpath matched -> %s:%s -> %s", ns, tg, dtdk.command)
end
end
end
end
else
- if trace then
- texio.write_nl(format("lpath pattern -> %s -> %s", pattern, setup))
+ 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 then
+ if trace_setups then
local ns, tg = dtdk.rn or dtdk.ns, dtdk.tg
if ns == "" then
- texio.write_nl(format("lpath matched -> %s -> %s", tg, setup))
+ logs.report("lxml","lpath matched -> %s -> %s", tg, setup)
else
- texio.write_nl(format("lpath matched -> %s:%s -> %s", ns, tg, setup))
+ logs.report("lxml","lpath matched -> %s:%s -> %s", ns, tg, setup)
end
end
end
@@ -722,7 +742,7 @@ local function command(root,pattern,cmd) -- met zonder ''
if type(m) == "table" then -- probably a bug
local n = #myself + 1
myself[n] = m
- texsprint(tex.ctxcatcodes,format("\\xmlsetup{%s}{%s}",n,cmd))
+ texsprint(ctxcatcodes,format("\\xmlsetup{%s}{%s}",n,cmd))
end
end)
end
@@ -739,98 +759,92 @@ end
xml.filters["function"] = dofunction
-do
+--~ <?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 = { }
+}
- --~ <?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)
- if texmf then
- local fullname = input.find_file(filename) or ""
- if fullname ~= "" then
- filename = fullname
- end
- 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
+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.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
+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
- local setup = data[format("%s::%s::%s",element,attribute,value)]
+ 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(tex.ctxcatcodes,format("\\directsetup{%s}",setup))
- else
- setup = data[format("%s::%s::*",element,attribute)]
- if setup then
- setup = setup[category]
- end
- if setup then
- texsprint(tex.ctxcatcodes,format("\\directsetup{%s}",setup:gsub('%*',value)))
- end
+ texsprint(ctxcatcodes,format("\\directsetup{%s}",setup:gsub('%*',value)))
end
end
end
end
-
end
function xml.getbuffer(name) -- we need to make sure that commands are processed
@@ -844,16 +858,20 @@ function lxml.loadbuffer(id,name)
if not name or name == "" then
name = tex.jobname
end
- input.starttiming(xml)
+ starttiming(xml)
loaded[id] = xml.convert(buffers.collect(name or id,"\n"))
- input.stoptiming(xml)
+ stoptiming(xml)
return loaded[id], name or id
end
function lxml.loaddata(id,str)
- input.starttiming(xml)
+ starttiming(xml)
loaded[id] = xml.convert(str or "")
- input.stoptiming(xml)
+ stoptiming(xml)
+ return loaded[id], id
+end
+
+function lxml.loadregistered(id)
return loaded[id], id
end
@@ -862,143 +880,149 @@ end
lxml.set_verbatim("\\xmlcdatabefore", "\\xmlcdataafter", "\\xmlcdataobeyedline", "\\xmlcdataobeyedspace")
lxml.set_cdata()
-do
-
- local traced = { }
+local traced = { }
- function lxml.trace_text_entities(str)
- return str:gsub("&(.-);",function(s)
- traced[s] = (traced[s] or 0) + 1
- return "["..s.."]"
- end)
- end
+function lxml.trace_text_entities(str)
+ return str:gsub("&(.-);",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 = unicode.utf8.char(d)
- texio.write_nl(format("entity: %s / %s / %s / n=%s",h,d,u,traced[v]))
- else
- texio.write_nl(format("entity: %s / n=%s",v,traced[v]))
- 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
--- yes or no ...
+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
-do
+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
+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
+ 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
+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
+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
+-- 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_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.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
+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
- 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
+ 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 = { }
@@ -1011,23 +1035,23 @@ function lxml.installsetup(what,document,setup,where)
if sd[k] == setup then sd[k] = nil break end
end
if what == 1 then
- if lxml.trace_load then
- ctx.writestatus("lxml","prepending setup %s for %s",setup,document)
+ if trace_loading then
+ commands.writestatus("lxml","prepending setup %s for %s",setup,document)
end
insert(sd,1,setup)
elseif what == 2 then
- if lxml.trace_load then
- ctx.writestatus("lxml","appending setup %s for %s",setup,document)
+ if trace_loading then
+ commands.writestatus("lxml","appending setup %s for %s",setup,document)
end
insert(sd,setup)
elseif what == 3 then
- if lxml.trace_load then
- ctx.writestatus("lxml","inserting setup %s for %s before %s",setup,document,where)
+ 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 lxml.trace_load then
- ctx.writestatus("lxml","inserting setup %s for %s after %s",setup,document,where)
+ 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
@@ -1038,26 +1062,25 @@ function lxml.flushsetups(...)
for _, document in ipairs({...}) do
local sd = setups[document]
if sd then
- local tc = tex.ctxcatcodes
for k=1,#sd do
local v= sd[k]
if not done[v] then
- if lxml.trace_load then
- ctx.writestatus("lxml","applying setup %02i = %s to %s",k,v,document)
+ if trace_loading then
+ commands.writestatus("lxml","applying setup %02i = %s to %s",k,v,document)
end
- texsprint(tc,format("\\directsetup{%s}",v))
+ texsprint(ctxcatcodes,format("\\directsetup{%s}",v))
done[v] = true
end
end
- elseif lxml.trace_load then
- ctx.writestatus("lxml","no setups for %s",document)
+ elseif trace_loading then
+ commands.writestatus("lxml","no setups for %s",document)
end
end
end
function lxml.resetsetups(document)
- if lxml.trace_load then
- ctx.writestatus("lxml","resetting all setups for %s",document)
+ if trace_loading then
+ commands.writestatus("lxml","resetting all setups for %s",document)
end
setups[document] = { }
end
@@ -1067,8 +1090,8 @@ function lxml.removesetup(document,setup)
if s then
for i=1,#s do
if s[i] == setup then
- if lxml.trace_load then
- ctx.writestatus("lxml","removing setup %s for %s",setup,document)
+ if trace_loading then
+ commands.writestatus("lxml","removing setup %s for %s",setup,document)
end
remove(t,i)
break
@@ -1092,3 +1115,24 @@ function lxml.doifelsetext (id,pattern) commands.doifelse(found (get_id(id),pat
-- special case: "*" and "" -> self else lpath lookup
function lxml.doifelseempty(id,pattern) commands.doifelse(isempty(get_id(id),pattern ~= "" and pattern ~= nil)) end -- not yet done, pattern
+
+-- status info
+
+statistics.register("xml load time", function()
+ local n = lxml.n
+ if n > 0 then
+ local stats = xml.statistics()
+ return format("%s seconds, lpath calls: %s, cached calls: %s", statistics.elapsedtime(xml), stats.lpathcalls, stats.lpathcached)
+ else
+ return nil
+ end
+end)
+
+statistics.register("lxml load time", function()
+ local n = #lxml.self
+ if n > 0 then
+ return format("%s seconds preparation, backreferences: %i", statistics.elapsedtime(lxml),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/lxml-ini.tex b/tex/context/base/lxml-ini.tex
index 0d03044b2..494e4f0b7 100644
--- a/tex/context/base/lxml-ini.tex
+++ b/tex/context/base/lxml-ini.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=lxml-ini,
%D version=2007.08.17,
-%D title=\CONTEXT\ \LUA\ based \XML\ Support,
+%D title=\CONTEXT\ \XML\ Support,
%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,8 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context L-XML Macros (initialization)}
+\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}
\unprotect
@@ -31,7 +35,7 @@
\def\xmldirectives #1{\ctxlua{lxml.directives.setup("#1")}}
\def\xmldirectivesbefore #1{\ctxlua{lxml.directives.before("#1")}}
\def\xmldirectivesafter #1{\ctxlua{lxml.directives.after("#1")}}
-\def\xmlfilter #1#2{\ctxlua{lxml.filter("#1","#2")}}
+\def\xmlfilter #1#2{\ctxlua{lxml.filter("#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")}}
@@ -47,6 +51,7 @@
\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")}}
@@ -130,6 +135,8 @@
\let\xmlregistersetup \xmlappendsetup
\let\xmlregisterdocumentsetup\xmlappenddocumentsetup
+\def\xmldocument{main}
+
\def\xmlregisteredsetups
{\xmlstarttiming
\xmlflushsetups
@@ -143,8 +150,8 @@
\xmldefaulttotext{#1}% after include
\xmlstoptiming}
-\def\xmlstarttiming{\ctxlua{input.starttiming(lxml)}}
-\def\xmlstoptiming {\ctxlua{input.stoptiming (lxml)}}
+\def\xmlstarttiming{\ctxlua{statistics.starttiming(lxml)}}
+\def\xmlstoptiming {\ctxlua{statistics.stoptiming (lxml)}}
\def\doxmlprocess#1#2#3#4%
{\begingroup
@@ -160,10 +167,11 @@
{\directsetup{#4}}%
\endgroup}
-\def\xmlprocessfile {\doxmlprocess\xmlload}
-\def\xmlprocessdata {\doxmlprocess\xmlloaddata}
-\def\xmlprocessbuffer{\doxmlprocess\xmlloadbuffer}
-\let\xmlprocess \xmlprocessfile
+\def\xmlprocessfile {\doxmlprocess\xmlload}
+\def\xmlprocessdata {\doxmlprocess\xmlloaddata}
+\def\xmlprocessbuffer {\doxmlprocess\xmlloadbuffer}
+\def\xmlprocessregistered{\doxmlprocess\xmlloadregistered}
+\let\xmlprocess \xmlprocessfile
% beware: \xmlmain takes the real root, so also processing
% instructions preceding the root element; well, in some
@@ -244,14 +252,6 @@
\def\inlinemessage #1{\dontleavehmode{\tttf#1}}
\def\displaymessage#1{\blank\inlinemessage{#1}\blank}
-% entities
-
-\def\xmlresolveentities
- {\ctxlua{xml.set_text_cleanup(xml.resolve_text_entities)}}
-
-\def\xmlkeepentities
- {\ctxlua{xml.set_text_cleanup()}}
-
\def\xmltraceentities
{\ctxlua{xml.set_text_cleanup(lxml.trace_text_entities)}%
\appendtoks\ctxlua{lxml.show_text_entities()}\to\everygoodbye}
@@ -268,6 +268,8 @@
% \setupxml[\c!method=mkiv,\c!default=\v!none] % mkiv only, undefined -> hidden
% \setupxml[\c!method=mkiv,\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]
@@ -276,26 +278,49 @@
\def\setupxml[#1]{\getparameters[\??xm][#1]\the\everysetupxml}
-\def\c!entities{entities}
+\def\c!entities{entities} % to be internationalized
\def\s!mkiv {mkiv}
\def\s!mkii {mkii}
+% entities
+
+\newif\ifautoXMLentities
+
+\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
+
\appendtoks
\chardef\xmlprocessingmode\executeifdefined{\??xm:1:\@@xmmethod}\zerocount
\ifcase\xmlprocessingmode
- % mkii
+ % mkii, permits both methods
+ \executeifdefined{\??xm:ii:\@@xmentities}\xmlkeepentities
\or
- % mkiv
-% \or
+ % mkiv, mkiv exclusively
\chardef\xmlprocessingmode\executeifdefined{\??xm:2:\@@xmdefault}\plusone
+ \executeifdefined{\??xm:iv:\@@xmentities}\xmlresolveentities
+ \else
+ % unset
\fi
- \doifelse\@@xmentities\v!yes\xmlresolveentities\xmlkeepentities
\ifcase\xmlprocessingmode
\ctxlua{characters.setmkiientities()}%
\else
@@ -306,7 +331,7 @@
{\ctxlua{xml.strip_cm_and_dt=false}}%
\to \everysetupxml
-\appendtoks\the\everysetupxml\to\everyjob
+\def\xmlinitialize{\the\everysetupxml}
\newcount\charactersactiveoffset \charactersactiveoffset="10000
diff --git a/tex/context/base/lxml-mis.lua b/tex/context/base/lxml-mis.lua
new file mode 100644
index 000000000..a117b1af9
--- /dev/null
+++ b/tex/context/base/lxml-mis.lua
@@ -0,0 +1,106 @@
+if not modules then modules = { } end modules ['lxml-mis'] = {
+ 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 = table.concat
+local type, next, tonumber, tostring, setmetatable, loadstring = type, next, tonumber, tostring, setmetatable, loadstring
+local format, gsub = string.format, string.gsub
+
+--[[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"..string.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)
+
+xml.escaped_pattern = escaped
+xml.unescaped_pattern = unescaped
+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
new file mode 100644
index 000000000..b1afc8d64
--- /dev/null
+++ b/tex/context/base/lxml-pth.lua
@@ -0,0 +1,1555 @@
+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 = string.format, string.lower, string.gmatch, string.gsub, 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. Here we overload a previously defined
+function.</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
+
+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",
+ [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
+
+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_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)*")"}
+
+-- if we use a dedicated namespace then we don't need to pass rt and k
+
+local lp_special = (C(P("name")+P("text")+P("tag"))) * value / function(t,s)
+ if expressions[t] then
+ if s then
+ return "expressions." .. t .. "(r,k," .. s ..")"
+ else
+ return "expressions." .. t .. "(r,k)"
+ end
+ else
+ return "expressions.error(" .. t .. ")"
+ end
+end
+
+local converter = lpeg.Cs ( (
+ lp_position +
+ lp_index +
+ lp_text + lp_name + -- fast one
+ lp_special +
+ lp_noequal + lp_doequal +
+ lp_attribute +
+ lp_lua_function +
+ lp_function +
+1 )^1 )
+
+-- expressions,root,rootdt,k,e,edt,ns,tg,idx,hsh[tg] or 1
+
+local template = [[
+ 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)
+ str = converter:match(str)
+ return str, loadstring(format(template,str))()
+end
+
+local map = { }
+
+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 is_eq = lbracket * atsign * name * eq * value * rbracket
+local is_ne = lbracket * atsign * name * ne * value * rbracket
+local is_attribute = lbracket * atsign * name * rbracket
+local is_value = lbracket * value * rbracket
+local is_number = lbracket * number * rbracket
+
+local nobracket = 1-(lbracket+rbracket) -- must be improved
+local is_expression = lbracket * C(((C(nobracket^1))/make_expression)) * rbracket
+
+local is_expression = lbracket * (C(nobracket^1))/make_expression * rbracket
+
+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 = (period )
+local parent = (period * period ) / function( ) map[#map+1] = { 11 } end
+local subtreeroot = (slash + hat ) / function( ) map[#map+1] = { 12 } end
+local documentroot = (hat * hat ) / function( ) map[#map+1] = { 13 } end
+local any = (star ) / function( ) map[#map+1] = { 14 } end
+local many = (star * star ) / function( ) map[#map+1] = { 15 } end
+local initial = (hat * hat * hat ) / function( ) map[#map+1] = { 16 } end
+
+local match = (is_one ) / function(...) map[#map+1] = { 20, true , ... } end
+local match_one_of = (is_one_of ) / function(...) map[#map+1] = { 21, true , ... } end
+local dont_match = (is_none ) / function(...) map[#map+1] = { 20, false, ... } end
+local dont_match_one_of = (is_none_of ) / function(...) map[#map+1] = { 21, false, ... } end
+
+local match_and_eq = (is_one * is_eq ) / function(...) map[#map+1] = { 22, true , ... } end
+local match_and_ne = (is_one * is_ne ) / function(...) map[#map+1] = { 23, true , ... } end
+local dont_match_and_eq = (is_none * is_eq ) / function(...) map[#map+1] = { 22, false, ... } end
+local dont_match_and_ne = (is_none * is_ne ) / function(...) map[#map+1] = { 23, false, ... } end
+
+local match_one_of_and_eq = (is_one_of * is_eq ) / function(...) map[#map+1] = { 24, true , ... } end
+local match_one_of_and_ne = (is_one_of * is_ne ) / function(...) map[#map+1] = { 25, true , ... } end
+local dont_match_one_of_and_eq = (is_none_of * is_eq ) / function(...) map[#map+1] = { 24, false, ... } end
+local dont_match_one_of_and_ne = (is_none_of * is_ne ) / function(...) map[#map+1] = { 25, false, ... } end
+
+local has_attribute = (is_one * is_attribute) / function(...) map[#map+1] = { 27, true , ... } end
+local has_value = (is_one * is_value ) / function(...) map[#map+1] = { 28, true , ... } end
+local dont_has_attribute = (is_none * is_attribute) / function(...) map[#map+1] = { 27, false, ... } end
+local dont_has_value = (is_none * is_value ) / function(...) map[#map+1] = { 28, false, ... } end
+local position = (is_one * is_number ) / function(...) map[#map+1] = { 30, true, ... } end
+local dont_position = (is_none * is_number ) / function(...) map[#map+1] = { 30, false, ... } end
+
+local expression = (is_one * is_expression)/ function(...) map[#map+1] = { 31, true, ... } end
+local dont_expression = (is_none * is_expression)/ function(...) map[#map+1] = { 31, false, ... } end
+
+local self_expression = ( is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, true, "*", "*", ... } end
+local dont_self_expression = (exclam * is_expression) / function(...) if #map == 0 then map[#map+1] = { 11 } end
+ map[#map+1] = { 31, false, "*", "*", ... } end
+
+local instruction = (instructiontag * text ) / function(...) map[#map+1] = { 40, ... } end
+local nothing = (empty ) / function( ) map[#map+1] = { 15 } end -- 15 ?
+local crap = (1-slash)^1
+
+-- a few ugly goodies:
+
+local docroottag = P('^^') / function( ) map[#map+1] = { 12 } end
+local subroottag = P('^') / function( ) map[#map+1] = { 13 } end
+local roottag = P('root::') / function( ) map[#map+1] = { 12 } end
+local parenttag = P('parent::') / function( ) map[#map+1] = { 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 +
+ 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 +
+ has_attribute + has_value +
+ dont_match_one_of + match_one_of +
+ dont_match + match +
+ many + any +
+ crap + empty
+)
+
+local grammar = P { "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
+ map = { }
+ grammar:match(str)
+ if #map == 0 then
+ return true
+ else
+ 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
+ -- return { { 29, map[2][2], map[2][3], map[2][4], map[2][5] } }
+ map[2][1] = 29
+ return { map[2] }
+ end
+ if m ~= 11 and m ~= 12 and m ~= 13 and m ~= 14 and m ~= 15 and m ~= 16 then
+ insert(map, 1, { 16 })
+ end
+ -- print(gsub(table.serialize(map),"[ \n]+"," "))
+ return map
+ end
+ end
+end
+
+local cache = { }
+
+function xml.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
+
+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 = xml.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(root,rootdt,k) then
+ return false
+ 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(root,rootdt,k) then
+ return false
+ 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 = 0
+ local hsh = { } -- this 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 == 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[5]]
+ elseif command == 28 then -- has value
+ 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
+ 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(root,rootdt,k) then
+ return false
+ end
+ break -- else loop
+ end
+ end
+ end
+ end
+ end
+ end
+ return true
+end
+
+xml.traverse = traverse
+
+--[[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]]--
+
+local traverse, lpath, convert = xml.traverse, xml.lpath, xml.convert
+
+xml.filters = { }
+
+function xml.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 xml.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
+
+function xml.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 xml.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
+
+function xml.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 xml.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 xml.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 xml.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 xml.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 xml.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 ekat[gsub(arguments,"^([\"\'])(.*)%1$","%2")])) or ""
+end
+
+function xml.filters.text(root,pattern,arguments) -- ?? why index, tostring slow
+ local dtk, rt, dt, dk = xml.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 xml.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 xml.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] = ""
+ end
+ else
+ t[#t+1] = tx or ""
+ end
+ else
+ t[#t+1] = ""
+ end
+ end)
+ return t
+end
+
+function xml.collect_tags(root, pattern, nonamespace)
+ local t = { }
+ xml.traverse(root, xml.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
+
+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
+ local xi = xml.convert(data)
+ 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"..string.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")
+
+--~ 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-tab.lua b/tex/context/base/lxml-tab.lua
new file mode 100644
index 000000000..a35e64270
--- /dev/null
+++ b/tex/context/base/lxml-tab.lua
@@ -0,0 +1,783 @@
+if not modules then modules = { } end modules ['lxml-tab'] = {
+ 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"
+}
+
+--[[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
+parent access; a first version used different trickery but was less optimized to we
+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>
+--ldx]]--
+
+xml = xml or { }
+
+--~ local xml = xml
+
+local concat, remove, insert = table.concat, table.remove, table.insert
+local type, next, setmetatable = type, next, setmetatable
+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
+
+--[[ldx--
+<p>First a hack to enable namespace resolving. A namespace is characterized by
+a <l n='url'/>. The following function associates a namespace prefix with a
+pattern. We use <l n='lpeg'/>, which in this case is more than twice as fast as a
+find based solution where we loop over an array of patterns. Less code and
+much cleaner.</p>
+--ldx]]--
+
+xml.xmlns = xml.xmlns or { }
+
+local check = lpeg.P(false)
+local parse = check
+
+--[[ldx--
+<p>The next function associates a namespace prefix with an <l n='url'/>. This
+normally happens independent of parsing.</p>
+
+<typing>
+xml.registerns("mml","mathml")
+</typing>
+--ldx]]--
+
+function xml.registerns(namespace, pattern) -- pattern can be an lpeg
+ check = check + lpeg.C(lpeg.P(lower(pattern))) / namespace
+ parse = lpeg.P { lpeg.P(check) + 1 * lpeg.V(1) }
+end
+
+--[[ldx--
+<p>The next function also registers a namespace, but this time we map a
+given namespace prefix onto a registered one, using the given
+<l n='url'/>. This used for attributes like <t>xmlns:m</t>.</p>
+
+<typing>
+xml.checkns("m","http://www.w3.org/mathml")
+</typing>
+--ldx]]--
+
+function xml.checkns(namespace,url)
+ local ns = parse:match(lower(url))
+ if ns and namespace ~= ns then
+ xml.xmlns[namespace] = ns
+ end
+end
+
+--[[ldx--
+<p>Next we provide a way to turn an <l n='url'/> into a registered
+namespace. This used for the <t>xmlns</t> attribute.</p>
+
+<typing>
+resolvedns = xml.resolvens("http://www.w3.org/mathml")
+</typing>
+
+This returns <t>mml</t>.
+--ldx]]--
+
+function xml.resolvens(url)
+ return parse:match(lower(url)) or ""
+end
+
+--[[ldx--
+<p>A namespace in an element can be remapped onto the registered
+one efficiently by using the <t>xml.xmlns</t> table.</p>
+--ldx]]--
+
+--[[ldx--
+<p>This version uses <l n='lpeg'/>. We follow the same approach as before, stack and top and
+such. This version is about twice as fast which is mostly due to the fact that
+we don't have to prepare the stream for cdata, doctype etc etc. This variant is
+is dedicated to Luigi Scarso, who challenged me with 40 megabyte <l n='xml'/> files that
+took 12.5 seconds to load (1.5 for file io and the rest for tree building). With
+the <l n='lpeg'/> implementation we got that down to less 7.3 seconds. Loading the 14
+<l n='context'/> interface definition files (2.6 meg) went down from 1.05 seconds to 0.55.</p>
+
+<p>Next comes the parser. The rather messy doctype definition comes in many
+disguises so it is no surprice that later on have to dedicate quite some
+<l n='lpeg'/> code to it.</p>
+
+<typing>
+<!DOCTYPE Something PUBLIC "... ..." "..." [ ... ] >
+<!DOCTYPE Something PUBLIC "... ..." "..." >
+<!DOCTYPE Something SYSTEM "... ..." [ ... ] >
+<!DOCTYPE Something SYSTEM "... ..." >
+<!DOCTYPE Something [ ... ] >
+<!DOCTYPE Something >
+</typing>
+
+<p>The code may look a bit complex but this is mostly due to the fact that we
+resolve namespaces and attach metatables. There is only one public function:</p>
+
+<typing>
+local x = xml.convert(somestring)
+</typing>
+
+<p>An optional second boolean argument tells this function not to create a root
+element.</p>
+--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 mt = { __tostring = xml.text }
+
+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
+ end
+ if tag == "xmlns" then
+ xmlns[#xmlns+1] = resolvens(value)
+ at[tag] = value
+ elseif namespace == "xmlns" then
+ xml.checkns(tag,value)
+ at["xmlns:" .. tag] = value
+ else
+ at[tag] = value
+ end
+end
+
+local function add_begin(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local resolved = (namespace == "" and xmlns[#xmlns]) or nsremap[namespace] or namespace
+ top = { ns=namespace or "", rn=resolved, tg=tag, at=at, dt={}, __p__ = stack[#stack] }
+ setmetatable(top, mt)
+ dt = top.dt
+ stack[#stack+1] = top
+ at = { }
+end
+
+local function add_end(spacing, namespace, tag)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ local toclose = remove(stack)
+ top = stack[#stack]
+ if #stack < 1 then
+ errorstr = format("nothing to close with %s %s", tag, xml.check_error(top,toclose) or "")
+ elseif toclose.tg ~= tag then -- no namespace check
+ errorstr = format("unable to close %s with %s %s", toclose.tg, tag, xml.check_error(top,toclose) or "")
+ end
+ dt = top.dt
+ dt[#dt+1] = toclose
+ dt[0] = top
+ 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)
+ else
+ dt[#dt+1] = text
+ end
+end
+
+local function add_special(what, spacing, text)
+ if #spacing > 0 then
+ dt[#dt+1] = spacing
+ end
+ if strip and (what == "@cm@" or what == "@dt@") then
+ -- forget it
+ else
+ dt[#dt+1] = { special=true, ns="", tg=what, dt={text} }
+ end
+end
+
+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 space = S(' \r\n\t')
+local open = P('<')
+local close = P('>')
+local squote = S("'")
+local dquote = S('"')
+local equal = P('=')
+local slash = P('/')
+local colon = P(':')
+local valid = R('az', 'AZ', '09') + S('_-.')
+local name_yes = C(valid^1) * colon * C(valid^1)
+local name_nop = C(P(true)) * C(valid^1)
+local name = name_yes + name_nop
+
+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 somespace = space^1
+local optionalspace = space^0
+
+local value = (squote * C((1 - squote)^0) * squote) + (dquote * C((1 - dquote)^0) * dquote)
+local attribute = (somespace * name * optionalspace * equal * optionalspace * value) / add_attribute
+local attributes = attribute^0
+
+local text = justtext / 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
+local beginelement = (spacing * open * name * attributes * optionalspace * close) / add_begin
+local endelement = (spacing * open * slash * name * optionalspace * close) / add_end
+
+local begincomment = open * P("!--")
+local endcomment = P("--") * close
+local begininstruction = open * P("?")
+local endinstruction = P("?") * close
+local begincdata = open * P("![CDATA[")
+local endcdata = P("]]") * close
+
+local someinstruction = C((1 - endinstruction)^0)
+local somecomment = C((1 - endcomment )^0)
+local somecdata = C((1 - endcdata )^0)
+
+local function entity(k,v) entities[k] = v end
+
+local begindoctype = open * P("!DOCTYPE")
+local enddoctype = close
+local beginset = P("[")
+local endset = P("]")
+local doctypename = C((1-somespace)^0)
+local elementdoctype = optionalspace * P("<!ELEMENT") * (1-close)^0 * close
+local entitydoctype = optionalspace * P("<!ENTITY") * somespace * (doctypename * somespace * value)/entity * optionalspace * close
+local publicdoctype = doctypename * somespace * P("PUBLIC") * somespace * value * somespace * value * somespace
+local systemdoctype = doctypename * somespace * P("SYSTEM") * somespace * value * somespace
+local definitiondoctype= doctypename * somespace * beginset * P(elementdoctype + entitydoctype)^0 * optionalspace * endset
+local simpledoctype = (1-close)^1 -- * balanced^0
+local somedoctype = C((somespace * (publicdoctype + systemdoctype + definitiondoctype + simpledoctype) * optionalspace)^0)
+
+local instruction = (spacing * begininstruction * someinstruction * endinstruction) / function(...) add_special("@pi@",...) end
+local comment = (spacing * begincomment * somecomment * endcomment ) / function(...) add_special("@cm@",...) end
+local cdata = (spacing * begincdata * somecdata * endcdata ) / function(...) add_special("@cd@",...) end
+local doctype = (spacing * begindoctype * somedoctype * enddoctype ) / function(...) add_special("@dt@",...) end
+
+-- nicer but slower:
+--
+-- local instruction = (lpeg.Cc("@pi@") * spacing * begininstruction * someinstruction * endinstruction) / add_special
+-- local comment = (lpeg.Cc("@cm@") * spacing * begincomment * somecomment * endcomment ) / add_special
+-- 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
+
+-- 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",
+ 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,
+}
+
+-- todo: xml.new + properties like entities and strip and such (store in root)
+
+function xml.convert(data, no_root, strip_cm_and_dt, given_entities) -- maybe use table met k/v (given_entities may disapear)
+ strip = strip_cm_and_dt or xml.strip_cm_and_dt
+ stack, top, at, xmlns, errorstr, result, entities = {}, {}, {}, {}, nil, nil, given_entities or {}
+ stack[#stack+1] = top
+ top.dt = { }
+ dt = top.dt
+ if not data or data == "" then
+ errorstr = "empty xml file"
+ elseif not grammar:match(data) then
+ errorstr = "invalid xml file"
+ else
+ errorstr = ""
+ end
+ if errorstr and errorstr ~= "" then
+ result = { dt = { { ns = "", tg = "error", dt = { errorstr }, at={}, er = true } }, error = true }
+ setmetatable(stack, mt)
+ if xml.error_handler then xml.error_handler("load",errorstr) end
+ else
+ result = stack[1]
+ end
+ if not no_root then
+ result = { special = true, ns = "", tg = '@rt@', dt = result.dt, at={}, entities = entities }
+ setmetatable(result, mt)
+ local rdt = result.dt
+ for k=1,#rdt do
+ local v = rdt[k]
+ if type(v) == "table" and not v.special then -- always table -)
+ result.ri = k -- rootindex
+ break
+ end
+ end
+ end
+ return result
+end
+
+--[[ldx--
+<p>Packaging data in an xml like table is done with the following
+function. Maybe it will go away (when not used).</p>
+--ldx]]--
+
+function xml.is_valid(root)
+ return root and root.dt and root.dt[1] and type(root.dt[1]) == "table" and not root.dt[1].er
+end
+
+function xml.package(tag,attributes,data)
+ local ns, tg = tag:match("^(.-):?([^:]+)$")
+ local t = { ns = ns, tg = tg, dt = data or "", at = attributes or {} }
+ setmetatable(t, mt)
+ return t
+end
+
+function xml.is_valid(root)
+ return root and not root.error
+end
+
+xml.error_handler = (logs and logs.report) or (input and logs.report) or print
+
+--[[ldx--
+<p>We cannot load an <l n='lpeg'/> from a filehandle so we need to load
+the whole file first. The function accepts a string representing
+a filename or a file handle.</p>
+--ldx]]--
+
+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"))
+ f:close()
+ return root
+ else
+ return xml.convert("")
+ end
+ elseif filename then -- filehandle
+ return xml.convert(filename:read("*all"))
+ else
+ return xml.convert("")
+ end
+end
+
+--[[ldx--
+<p>When we inject new elements, we need to convert strings to
+valid trees, which is what the next function does.</p>
+--ldx]]--
+
+function xml.toxml(data)
+ if type(data) == "string" then
+ local root = { xml.convert(data,true) }
+ return (#root > 1 and root) or root[1]
+ else
+ return data
+ end
+end
+
+--[[ldx--
+<p>For copying a tree we use a dedicated function instead of the
+generic table copier. Since we know what we're dealing with we
+can speed up things a bit. The second argument is not to be used!</p>
+--ldx]]--
+
+function copy(old,tables)
+ if old then
+ tables = tables or { }
+ local new = { }
+ if not tables[old] then
+ tables[old] = new
+ end
+ for k,v in pairs(old) do
+ new[k] = (type(v) == "table" and (tables[v] or copy(v, tables))) or v
+ end
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+xml.copy = copy
+
+--[[ldx--
+<p>In <l n='context'/> serializing the tree or parts of the tree is a major
+actitivity which is why the following function is pretty optimized resulting
+in a few more lines of code than needed. The variant that uses the formatting
+function for all components is about 15% slower than the concatinating
+alternative.</p>
+--ldx]]--
+
+-- todo: add <?xml version='1.0' standalone='yes'?> when not present
+
+local fallbackhandle = (tex and tex.sprint) or io.write
+
+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
+ local xc = xml.command
+ if xc then
+ xc(e,ec)
+ return
+ end
+ 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)
+ else
+ -- no need to handle any further
+ 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
+ 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
+ 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(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 .. ">")
+ 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
+ end
+ 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
+ end
+ end
+ elseif type(e) == "string" then
+ if textconverter then
+ handle(textconverter(e))
+ else
+ handle(e)
+ 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
+end
+
+xml.serialize = serialize
+
+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
+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]]--
+
+function xml.tostring(root) -- 25% overhead due to collecting
+ if root then
+ if type(root) == 'string' then
+ return root
+ elseif next(root) then -- next is faster than type (and >0 test)
+ local result = { }
+ serialize(root,function(s) result[#result+1] = s end)
+ return concat(result,"")
+ end
+ end
+ return ""
+end
+
+--[[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)
+ 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)
+ end
+ end
+ else
+ handle(e)
+ 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
+
+--[[ldx--
+<p>A few helpers:</p>
+--ldx]]--
+
+function xml.body(root)
+ return (root.ri and root.dt[root.ri]) or root
+end
+
+function xml.text(root)
+ return (root and xml.tostring(root)) or ""
+end
+
+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 ""
+ end
+end
+
+--[[ldx--
+<p>The next helper assigns a tree (or string). Usage:</p>
+
+<typing>
+dt[k] = xml.assign(root) or xml.assign(dt,k,root)
+</typing>
+--ldx]]--
+
+function xml.assign(dt,k,root)
+ if dt and k then
+ dt[k] = (type(root) == "table" and xml.body(root)) or root
+ return dt[k]
+ else
+ return xml.body(root)
+ end
+end
diff --git a/tex/context/base/m-arabtex.tex b/tex/context/base/m-arabtex.tex
index af7213387..61e56e93a 100644
--- a/tex/context/base/m-arabtex.tex
+++ b/tex/context/base/m-arabtex.tex
@@ -21,7 +21,7 @@
% ......
% \stoparabic
-\writestatus{loading}{Context Font Macros / ArabTeX support}
+\writestatus{loading}{ConTeXt Font Macros / ArabTeX support}
%D At the \NTG\ 10\high{th} anniversary meeting Klaus Lagally
%D introduced the audience to arabic typesetting, and after
diff --git a/tex/context/base/m-chemic.mkii b/tex/context/base/m-chemic.mkii
new file mode 100644
index 000000000..e6980e1ff
--- /dev/null
+++ b/tex/context/base/m-chemic.mkii
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=ppchtex (m-chemic),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\ifx\psaxes\undefined \ifx\beginpicture\undefined
+ \usemodule[pictex]
+\fi \fi
+
+\input ppchtex.mkii \relax
+
+\endinput
diff --git a/tex/context/base/m-chemic.mkiv b/tex/context/base/m-chemic.mkiv
new file mode 100644
index 000000000..4cc1e3bd8
--- /dev/null
+++ b/tex/context/base/m-chemic.mkiv
@@ -0,0 +1,19 @@
+%D \module
+%D [ file=ppchtex (m-chemic),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\usemodule[pictex] % we will get rid of this
+
+\input ppchtex.mkiv \relax
+
+\endinput
diff --git a/tex/context/base/m-chemic.tex b/tex/context/base/m-chemic.tex
index 25eb62db5..7bacf4a90 100644
--- a/tex/context/base/m-chemic.tex
+++ b/tex/context/base/m-chemic.tex
@@ -12,14 +12,6 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\ifx\directlua\undefined
- \ifx\psaxes\undefined \ifx\beginpicture\undefined
- \usemodule[pictex]
- \fi \fi
-\else
- \usemodule[pictex]
-\fi
-
-\input ppchtex.tex \relax
+\loadmarkfile{m-chemic}
\endinput
diff --git a/tex/context/base/m-database.tex b/tex/context/base/m-database.tex
index 6cb9a6b6c..c4fba132a 100644
--- a/tex/context/base/m-database.tex
+++ b/tex/context/base/m-database.tex
@@ -265,7 +265,7 @@
\fi}
\def\doprocessseparatedline
- {\doifnextcharelse\bgroup\xdoprocessseparatedline\ydoprocessseparatedline}
+ {\doifnextbgroupelse\xdoprocessseparatedline\ydoprocessseparatedline}
\def\dodoprocessseparatedline
{\doprocessseparatedline}
diff --git a/tex/context/base/m-educat.tex b/tex/context/base/m-educat.tex
index 38567bf4e..ddfb72ff4 100644
--- a/tex/context/base/m-educat.tex
+++ b/tex/context/base/m-educat.tex
@@ -18,39 +18,6 @@
\unprotect
-\startvariables dutch english
- german czech
- italian romanian
-
- answerarea: antwoordgebied answerarea
- answerarea answerarea
- answerarea answerarea
-
-\stopvariables
-
-\startelements dutch english
- german czech
- italian romanian
-
- answerspace: antwoordruimte answerspace
- answerspace answerspace
- answerspace answerspace
- answerlines: antwoordregels answerlines
- answerlines answerlines
- answerlines answerlines
-
-\stopelements
-
-\startcommands dutch english
- german czech
- italian romanian
-
- setupanswerarea: stelantwoordgebiedin setupanswerarea
- setupanswerarea setupanswerarea
- setupanswerarea setupanswerarea
-
-\stopcommands
-
\definesystemvariable{iv}
\definecolor [answerareacolor] [s=.90]
diff --git a/tex/context/base/m-gamma.tex b/tex/context/base/m-gamma.tex
deleted file mode 100644
index 05f5d3a42..000000000
--- a/tex/context/base/m-gamma.tex
+++ /dev/null
@@ -1,230 +0,0 @@
-%D \module
-%D [ file=m-gamma,
-%D version=2002.05.15,
-%D title=\CONTEXT\ Extra Modules,
-%D subtitle=Basic \OMEGA\ Support,
-%D author={Idris Samawi Hamid, Hans Hagen},
-%D date=\currentdate,
-%D copyright={PRAGMA-ADE, Idris Samawi Hamid}]
-%D
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D Most of this module is written by Idris Samawi Hamid.
-
-%D We define a couple of symbolic \OTP\ filters and
-%D sequences. First the filters:
-%D
-%D Todo: better names, no funny abbreviations.
-
-\definefiltersynonym [utf8 to unicode16] [inutf8]
-\definefiltersynonym [IdOCP] [id]
-\definefiltersynonym [BasicLatinTexUni] [lat2uni]
-\definefiltersynonym [BasicLatinUniToFont][uni2lat]
-\definefiltersynonym [GrTexUni] [grpo2uni]
-\definefiltersynonym [GrUniToFont] [uni2greek]
-\definefiltersynonym [ArabUni] [7arb2uni]
-\definefiltersynonym [BerberUni] [7ber2uni]
-\definefiltersynonym [UrduUni] [7urd2uni]
-\definefiltersynonym [AfghaPashtoUni] [7pas2uni]
-\definefiltersynonym [PakiPashtoUni] [7pap2uni]
-\definefiltersynonym [SindhiUni] [7snd2uni]
-\definefiltersynonym [TifinaghUni] [7tbe2uni]
-\definefiltersynonym [LatinBerberUni] [7lbe2uni]
-\definefiltersynonym [UniCUni] [uni2cuni]
-\definefiltersynonym [CUniArab] [cuni2oar]
-\definefiltersynonym [NoKeshidehCUniArab] [cuni2nar]
-
-%D Next we define the sequences.
-
-\definefiltersequence
- [NilOCP]
- [IdOCP]
-
-\definefiltersequence
- [BasicLatinOCP]
- [BasicLatinTexUni,BasicLatinUniToFont]
-
-\definefiltersequence
- [GreekOCP]
- [GrTexUni,GrUniToFont]
-
-\definefiltersequence
- [ArabicOCP]
- [ArabUni,UniCUni,CUniArab]
-
-\definefiltersequence
- [ArabicNoKeshidehOCP]
- [ArabUni,UniCUni,NoKeshidehCUniArab]
-
-\definefiltersequence
- [ArabicBerberOCP]
- [BerberUni,UniCUni,CUniArab]
-
-\definefiltersequence
- [TifinaghOCP]
- [TifinaghUni,BasicLatinUniToFont]
-
-\definefiltersequence
- [LatinBerberOCP]
- [LatinBerberUni,BasicLatinUniToFont]
-
-\definefiltersequence
- [UrduOCP]
- [UrduUni,UniCUni,CUniArab]
-
-\definefiltersequence
- [UrduNoKeshidehOCP]
- [UrduUni,UniCUni,NoKeshidehCUniArab]
-
-\definefiltersequence
- [AfghaPashtoOCP]
- [AfghaPashtoUni,UniCUni,CUniArab]
-
-\definefiltersequence
- [PakiPashtoOCP]
- [PakiPashtoUni,UniCUni,CUniArab]
-
-\definefiltersequence
- [SindhiOCP]
- [SindhiUni,UniCUni,CUniArab]
-
-%D We wrap a couple of languages in environmen tmacros.
-%D beware: this solution is far from perfect!
-%D
-%D Todo: better interface to directional primitives.
-%D
-%D Todo: proper language support (labels etc).
-
-\definestartstop
- [latin]
- [commands=%
- {\usefiltersequence[BasicLatinOCP]%
- \switchtobodyfont[omlgc]}]
-
-\definestartstop
- [greek]
- [commands=%
- {\usefiltersequence[GreekOCP]%
- \switchtobodyfont[omlgc]%
- \language=3\lefthyphenmin2\righthyphenmin=2}]
-
-\definestartstop
- [arab]
- [commands=%
- {\usefiltersequence[ArabicOCP]
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [smallarab]
- [commands=%
- {\usefiltersequence[ArabicNoKeshidehOCP]
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [latberber]
- [commands=%
- {\usefiltersequence[LatinBerberOCP]
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [tifinagh]
- [commands=%
- {\usefiltersequence[TifinaghOCP]
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [berber]
- [commands=%
- {\usefiltersequence[ArabicBerberOCP]
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [urdu]
- [commands=%
- {\usefiltersequence[UrduOCP]%
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [smallurdu]
- [commands=%
- {\usefiltersequence[UrduNoKeshidehOCP]%
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [pashto]
- [commands=%
- {\usefiltersequence[AfghaPashtoOCP]%
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [pashtop]
- [commands=%
- {\usefiltersequence[PakiPashtoOCP]%
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-\definestartstop
- [sindhi]
- [commands=%
- {\usefiltersequence[SindhiOCP]%
- \switchtobodyfont[omarb]%
- \textdir TRT\pardir TRT}]
-
-
-\let\typeout\message \input grlccode.tex
-
-%D We (pre)define a couple of fonts:
-
-\usetypescriptfile[type-omg]
-
-\usetypescript[OmegaArab]
-\usetypescript[OmegaLGC]
-
-%D Dangerous definitions:
-
-\startencoding[omega]
-
- \definecharacter textbraceleft {^^^^f07b}
- \definecharacter textbraceright {^^^^f07d}
- \definecharacter textbackslash {^^^^f05c}
- \definecharacter textbullet {{\clearocplists\mm\sy\char"0F}}
- \definecharacter dotlessi {^^^^0131}
- \definecharacter ssharp {^^^^00df}
-
-\stopencoding
-
-\enableencoding [omega]
-
-%D Some logo's:
-
-\unexpanded \def\OMEGA {{\switchtobodyfont[omlgc]^^^^03a9}}
-\unexpanded \def\OTP {\OMEGA TP}
-
-%D A few funny definitions:
-
-\def\#{^^^^f023}
-\def\${^^^^f024}
-\def\%{^^^^f025}
-\def\&{^^^^f026}
-
-%D I have no idea what this has to do with omega:
-
-\def\heshe {\lohi{he} {she}}
-\def\himher{\lohi{him}{her}}
-\def\hisher{\lohi{his}{her}}
-
-% Brrr
-
-\setuptolerance [verytolerant]
-
-\endinput
diff --git a/tex/context/base/m-mkii.mkiv b/tex/context/base/m-mkii.mkiv
new file mode 100644
index 000000000..cb0da6fcb
--- /dev/null
+++ b/tex/context/base/m-mkii.mkiv
@@ -0,0 +1,21 @@
+% todo
+
+\unprotect
+
+\writestatus\m!systems{loading some mkii compatibility hacks}
+
+% Compatibility for font-ini
+
+\let\normalxi=\xi
+
+\definebodyfontswitch [xii] [\!!twelvepoint]
+\definebodyfontswitch [xi] [\!!elevenpoint]
+\definebodyfontswitch [x] [\!!tenpoint]
+\definebodyfontswitch [ix] [\!!ninepoint]
+\definebodyfontswitch [viii] [\!!eightpoint]
+\definebodyfontswitch [vii] [\!!sevenpoint]
+\definebodyfontswitch [vi] [\!!sixpoint]
+
+\unexpanded\def\xi{\ifmmode\normalxi\else\elevenpoint\fi}
+
+\protect \endinput
diff --git a/tex/context/base/m-newmat.tex b/tex/context/base/m-newmat.tex
index c36119cd4..08ce33b4c 100644
--- a/tex/context/base/m-newmat.tex
+++ b/tex/context/base/m-newmat.tex
@@ -182,7 +182,7 @@
%D defined in Plain \TEX). It allows to get a math character
%D inserted as if it was a text character.
-\gdef\mathhexbox#1#2#3{\mathtext{$\m@th\mathchar"#1#2#3$}}
+\gdef\mathhexbox#1#2#3{\mathtext{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
%D \macros
%D {boxed}
@@ -299,11 +299,11 @@
\def\simplestartsubarray#1%
{\vcenter\bgroup
- \baselineskip\fontdimen10 \scriptfont\tw@
- \advance\baselineskip\fontdimen12 \scriptfont\tw@
- \lineskip\thr@@\fontdimen8 \scriptfont\thr@@
+ \baselineskip\fontdimen10 \scriptfont\plustwo
+ \advance\baselineskip\fontdimen12 \scriptfont\plustwo
+ \lineskip\plusthree\fontdimen8 \scriptfont\plusthree
\lineskiplimit\lineskip
- \ialign\bgroup\ifx c#1\hfil\fi$\m@th\scriptstyle##$\hfil\crcr}
+ \ialign\bgroup\ifx c#1\hfil\fi$\mathsurround\zeropoint\scriptstyle##$\hfil\crcr}
\def\stopsubarray
{\crcr\egroup
@@ -326,8 +326,8 @@
\baselineskip6\ex@
\lineskip1.5\ex@
\lineskiplimit\lineskip
- \ialign\bgroup\hfil$\m@th\scriptstyle##$\hfil&&\thickspace\hfil
- $\m@th\scriptstyle##$\hfil\crcr}
+ \ialign\bgroup\hfil$\mathsurround\zeropoint\scriptstyle##$\hfil&&\thickspace\hfil
+ $\mathsurround\zeropoint\scriptstyle##$\hfil\crcr}
\def\stopsmallmatrix
{\crcr\egroup
diff --git a/tex/context/base/m-pictex.tex b/tex/context/base/m-pictex.tex
index 90bb7b339..abb81b76e 100644
--- a/tex/context/base/m-pictex.tex
+++ b/tex/context/base/m-pictex.tex
@@ -88,11 +88,14 @@
%D redefinition already took place. We save the original
%D meanings, so we can restores them afterwards.
-\let\normalnewdimen = \newdimen
-\let\normalnewskip = \newskip
+% \def\temporarynewdimen {\alloc@1\dimen\dimendef\insc@unt}
+% \def\temporarynewskip {\alloc@2\skip \skipdef \insc@unt}
-\def\temporarynewdimen {\alloc@1\dimen\dimendef\insc@unt}
-\def\temporarynewskip {\alloc@2\skip \skipdef \insc@unt}
+\let\normalnewdimen \newdimen
+\let\normalnewskip \newskip
+
+\let\temporarynewdimen\newdimen
+\let\temporarynewskip \newskip
%D Here comes the trick. Depending on how many \DIMENSIONS\ and
%D \SKIPS\ are allocated, the \type{\newdimen} assigns a
diff --git a/tex/context/base/m-subsub.tex b/tex/context/base/m-subsub.tex
index 3fc71cd50..4395ded8a 100644
--- a/tex/context/base/m-subsub.tex
+++ b/tex/context/base/m-subsub.tex
@@ -12,53 +12,6 @@
\unprotect
-\startvariables dutch english
- german czech
- italian romanian
-
- subsubsubsubsubsection: subsubsubsubsubparagraaf subsubsubsubsubsection
- unterunterunterunterunterabsatz podpodpodpodpodsekce
- sottosottosottosottosottocapoverso subsubsubsubsubsectiune
-
- subsubsubsubsubsubsection: subsubsubsubsubsubparagraaf subsubsubsubsubsubsection
- unterunterunterunterunterunterabsatz podpodpodpodpodpodsekce
- sottosottosottosottosottosottocapoverso subsubsubsubsubsubsectiune
-
- subsubsubsubsubsubsubsection: subsubsubsubsubsubsubparagraaf subsubsubsubsubsubsubsection
- unterunterunterunterunterunterunterabsatz podpodpodpodpodpodpodsekce
- sottosottosottosottosottosottosottocapoverso subsubsubsubsubsubsubsectiune
-
- subsubsubsubsubsubsubsubsection: subsubsubsubsubsubsubsubparagraaf subsubsubsubsubsubsubsubsection
- unterunterunterunterunterunterunterunterabsatz podpodpodpodpodpodpodpodsekce
- sottosottosottosottosottosottosottosottocapoverso subsubsubsubsubsubsubsubsectiune
-
-subsubsubsubsubsubsubsubsubsection: subsubsubsubsubsubsubsubsubparagraaf subsubsubsubsubsubsubsubsubsection
- unterunterunterunterunterunterunterunterunterabsatz podpodpodpodpodpodpodpodpodsekce
- sottosottosottosottosottosottosottosottosottocapoverso subsubsubsubsubsubsubsubsubsectiune
-
- subsubsubsubsubsubject: subsubsubsubsubonderwerp subsubsubsubsubsubject
- unterunterunterunterunterthema podpodpodpodpodtema
- sottosottosottosottosottoargomento subsubsubsubsubsubiect
-
- subsubsubsubsubsubsubject: subsubsubsubsubsubonderwerp subsubsubsubsubsubsubject
- unterunterunterunterunterunterthema podpodpodpodpodpodtema
- sottosottosottosottosottosottoargomento subsubsubsubsubsubsubiect
-
- subsubsubsubsubsubsubsubject: subsubsubsubsubsubsubonderwerp subsubsubsubsubsubsubsubject
- unterunterunterunterunterunterunterthema podpodpodpodpodpodpodtema
- sottosottosottosottosottosottosottoargomento subsubsubsubsubsubsubsubiect
-
- subsubsubsubsubsubsubsubsubject: subsubsubsubsubsubsubsubonderwerp subsubsubsubsubsubsubsubsubject
- unterunterunterunterunterunterunterunterthema podpodpodpodpodpodpodpodtema
- sottosottosottosottosottosottosottosottoargomento subsubsubsubsubsubsubsubsubiect
-
-subsubsubsubsubsubsubsubsubsubject: subsubsubsubsubsubsubsubsubonderwerp subsubsubsubsubsubsubsubsubsubject
- unterunterunterunterunterunterunterunterunterthema podpodpodpodpodpodpodpodpodtema
- sottosottosottosottosottosottosottosottosottoargomento subsubsubsubsubsubsubsubsubsubiect
-
-\stopvariables
-
-
\definesection[\s!section-8]
\definesection[\s!section-9]
\definesection[\s!section-10]
diff --git a/tex/context/base/m-timing.tex b/tex/context/base/m-timing.tex
index 5f543042a..f6b0348c8 100644
--- a/tex/context/base/m-timing.tex
+++ b/tex/context/base/m-timing.tex
@@ -33,185 +33,35 @@
\definecolor[usage:time] [darkblue]
\definecolor[usage:frame][darkgray]
-\startluacode
-do
-
- document = document or { }
- document.progress = document.progress or { }
-
- local defaultfilename = tex.jobname .. "-luatex-progress"
-
- local params = {
- "cs_count",
- "dyn_used",
- "elapsed_time",
- "luabytecode_bytes",
- "luastate_bytes",
- "max_buf_stack",
- "obj_ptr",
- "pdf_mem_ptr",
- "pdf_mem_size",
- "pdf_os_cntr",
- "pool_ptr",
- "str_ptr",
- }
-
- -- storage
-
- local last = os.clock()
- local data = { }
-
- function document.progress.save()
- local f = io.open((name or defaultfilename) .. ".lut","w")
- if f then
- f:write(table.serialize(data,true))
- f:close()
- data = { }
- end
- end
-
- function document.progress.store()
- local c = os.clock()
- local t = {
- elapsed_time = c - last,
- node_memory = tex.node_mem_status(),
- }
- for k, v in pairs(params) do
- if status[v] then t[v] = status[v] end
- end
- data[#data+1] = t
- last = c
- end
-
- -- conversion
+\ctxloadluafile{trac-tim}{}
- local processed = { }
-
- function document.progress.bot(name,tag)
- local d = document.progress.convert(name)
- return d.bot[tag] or 0
- end
- function document.progress.top(name,tag)
- local d = document.progress.convert(name)
- return d.top[tag] or 0
- end
- function document.progress.pages(name,tag)
- local d = document.progress.convert(name)
- return d.pages or 0
- end
- function document.progress.path(name,tag)
- local d = document.progress.convert(name)
- return d.paths[tag] or "origin"
- end
- function document.progress.nodes(name)
- local d = document.progress.convert(name)
- return d.names or { }
- end
- function document.progress.parameters(name)
- local d = document.progress.convert(name)
- return params -- shared
- end
+\startluacode
+local progress = goodies.progress
- function document.progress.convert(name)
- name = ((name ~= "") and name) or defaultfilename
- if not processed[name] then
- local names, top, bot, pages, paths, keys = { }, { }, { }, 0, { }, { }
- local data = io.loaddata(name .. ".lut")
- if data then data = loadstring(data) end
- if data then data = data() end
- if data then
- pages = #data
- if pages > 1 then
- local factor = 100
- for k,v in ipairs(data) do
- for k,v in pairs(v.node_memory) do
- keys[k] = true
- end
- end
- for k,v in ipairs(data) do
- local m = v.node_memory
- for k, _ in pairs(keys) do
- if not m[k] then m[k] = 0 end
- end
- end
- local function path(tag,subtag)
- local b, t, s = nil, nil, { }
- for k,v in ipairs(data) do
- local v = (subtag and v[tag][subtag]) or v[tag]
- if v then
- v = tonumber(v)
- if b then
- if v > t then t = v end
- if v < b then b = v end
- else
- t = v
- b = v
- end
- s[k] = v
- else
- s[k] = 0
- end
- end
- local tagname = subtag or tag
- top[tagname] = (string.format("%.3f",t)):gsub("%.000$","")
- bot[tagname] = (string.format("%.3f",b)):gsub("%.000$","")
- local delta = t-b
- if delta == 0 then
- delta = 1
- else
- delta = factor/delta
- end
- for k, v in ipairs(s) do
- s[k] = "(" .. k .. "," .. (v-b)*delta .. ")"
- end
- paths[tagname] = table.concat(s,"--")
- end
- for _, tag in pairs(params) do
- path(tag)
- end
- for tag, _ in pairs(keys) do
- path("node_memory",tag)
- names[#names+1] = tag
- end
- pages = pages - 1
- end
- end
- table.sort(names)
- processed[name] = {
- names = names,
- top = top,
- bot = bot,
- pages = pages,
- paths = paths,
- }
- end
- return processed[name]
+function progress.show(filename,parameters,nodes,other)
+ for n, name in pairs(parameters or progress.parameters(filename)) do
+ tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or progress.defaultfilename,name,other or ""))
end
-
- function document.progress.show(filename,parameters,nodes,other)
- for n, name in pairs(parameters or document.progress.parameters(filename)) do
- tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or defaultfilename,name,other or ""))
- end
- for n, name in pairs(nodes or document.progress.nodes(filename)) do
- tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or defaultfilename,name,other or ""))
- end
+ for n, name in pairs(nodes or progress.nodes(filename)) do
+ tex.sprint(tex.ctxcatcodes,string.format("\\ShowNamedUsage{%s}{%s}{%s}",filename or progress.defaultfilename,name,other or ""))
end
-
end
\stopluacode
% \everyfirstshipout
-\appendtoks\ctxlua{document.progress.store()}\to\everystarttext
-\appendtoks\ctxlua{document.progress.store()}\to\everyshipout
-
-\ctxlua{table.insert(input.stop_actions, function() document.progress.save() end)}
+\startnotmode[no-timing]
+ \appendtoks\ctxlua{goodies.progress.store()}\to\everystarttext
+ \appendtoks\ctxlua{goodies.progress.store()}\to\everyshipout
+ \ctxlua{main.register_stop_actions(function() goodies.progress.save() end)}
+\stopnotmode
\def\ShowNamedUsage#1#2#3%
{\setbox\scratchbox\vbox\bgroup\startMPcode
begingroup ; save p, q, b, h, w ;
path p, q, b ; numeric h, w ;
- p := \ctxlua{tex.sprint(document.progress.path("#1","#2"))} ;
+ p := \ctxlua{tex.sprint(goodies.progress.path("#1","#2"))} ;
+% p := p shifted -llcorner p ;
if bbwidth(p) > 1 :
h := 100 ; w := 2 * h ;
w := \the\textwidth-3pt ; % correct for pen
@@ -221,7 +71,8 @@ end
draw b withcolor \MPcolor{usage:frame} ;
draw p withcolor \MPcolor{usage:line} ;
if ("#3" <> "") and ("#3" <> "#2") :
- q := \ctxlua{tex.sprint(document.progress.path("#1","#3"))} ;
+ q := \ctxlua{tex.sprint(goodies.progress.path("#1","#3"))} ;
+% q := q shifted -llcorner q ;
if bbwidth(q) > 1 :
q := q xstretched w ;
pickup pencircle scaled 1.5pt ; linecap := butt ;
@@ -236,16 +87,16 @@ end
\startlinecorrection
\box\scratchbox \endgraf
\hbox to \scratchdimen{\tttf\strut\detokenize{#2}\hss
- min:\ctxlua{tex.sprint(document.progress.bot("#1","\detokenize{#2}"))}, %
- max:\ctxlua{tex.sprint(document.progress.top("#1","\detokenize{#2}"))}, %
- pages:\ctxlua{tex.sprint(document.progress.pages("#1"))}%
+ min:\ctxlua{tex.sprint(goodies.progress.bot("#1","\detokenize{#2}"))}, %
+ max:\ctxlua{tex.sprint(goodies.progress.top("#1","\detokenize{#2}"))}, %
+ pages:\ctxlua{tex.sprint(goodies.progress.pages("#1"))}%
}%
\stoplinecorrection
\fi}
-\def\LoadUsage #1{\ctxlua{document.progress.convert("#1")}}
-\def\ShowUsage #1{\ctxlua{document.progress.show("#1",nil,nil,"elapsed_time")}}
-\def\ShowMemoryUsage#1{\ctxlua{document.progress.show("#1",nil,{}, "elapsed_time")}}
-\def\ShowNodeUsage #1{\ctxlua{document.progress.show("#1",{},nil, "elapsed_time")}}
+\def\LoadUsage #1{\ctxlua{goodies.progress.convert("#1")}}
+\def\ShowUsage #1{\ctxlua{goodies.progress.show("#1",nil,nil,"elapsed_time")}}
+\def\ShowMemoryUsage#1{\ctxlua{goodies.progress.show("#1",nil,{}, "elapsed_time")}}
+\def\ShowNodeUsage #1{\ctxlua{goodies.progress.show("#1",{},nil, "elapsed_time")}}
\endinput
diff --git a/tex/context/base/m-track.tex b/tex/context/base/m-track.tex
new file mode 100644
index 000000000..cfcbbabff
--- /dev/null
+++ b/tex/context/base/m-track.tex
@@ -0,0 +1,5 @@
+\doifnotmode{mkiv} {\endinput}
+
+\starttext
+ \showtrackers
+\stoptext
diff --git a/tex/context/base/m-translate.tex b/tex/context/base/m-translate.tex
index a11eef4bc..a9601bdd5 100644
--- a/tex/context/base/m-translate.tex
+++ b/tex/context/base/m-translate.tex
@@ -44,14 +44,14 @@
end
function translators.reset(s)
- input.filters.user_translator = nil
+ resolvers.filters.user_translator = nil
list, compiled = nil, nil
end
function translators.enable(s)
- input.filters.user_translator = translators.translate
+ resolvers.filters.user_translator = translators.translate
end
function translators.disable(s)
- input.filters.user_translator = nil
+ resolvers.filters.user_translator = nil
end
\stopluacode
diff --git a/tex/context/base/m-visual.tex b/tex/context/base/m-visual.tex
index c35e8a1a4..2be669d19 100644
--- a/tex/context/base/m-visual.tex
+++ b/tex/context/base/m-visual.tex
@@ -272,7 +272,6 @@
#2{#3}}
\let\normalPDFcode\PDFcode
-\let\normalspecial\special
\def\showlowlevelstream
{\def\PDFcode{\lowlevelstream\PDFcode\normalPDFcode}%
diff --git a/tex/context/base/math-ali.mkiv b/tex/context/base/math-ali.mkiv
new file mode 100644
index 000000000..f98eb11df
--- /dev/null
+++ b/tex/context/base/math-ali.mkiv
@@ -0,0 +1,1059 @@
+%D \module
+%D [ file=math-ali,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Math Alignments,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Math Macros / Math Alignments}
+
+\unprotect
+
+%D The code here has been moved from other files. Beware: the \MKII\ and
+%D \MKIV\ code is not gathered in files with the same name.
+
+%D \macros
+%D {\definemathalignment, setupmathalignment, startmathalignment}
+%D
+%D Modules may provide additional alignment features. The following
+%D mechanisms are provided by the core.
+
+% n>1 #### needed, strange # interaction in recurse
+
+\def\presetdisplaymath{\displ@y} % some day i will relocate the plain stuff
+
+\def\buildeqalign
+ {\scratchtoks\emptytoks
+ \dorecurse{\mathalignmentparameter\c!m}
+ {\ifnum\recurselevel>\plusone
+ \appendtoks
+ \tabskip\mathalignmentparameter\c!distance&\tabskip\zeropoint
+ \to\scratchtoks
+ \fi
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksa}}%
+ \dorecurse{\numexpr\mathalignmentparameter\c!n-\plusone\relax}
+ {\normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksb}}}}%
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksc}}}
+
+\def\forgetalign
+ {\tabskip\zeropoint\everycr\emptytoks}
+
+\let\firstineqalign\empty
+\let\nextineqalign \empty
+\let\leftofeqalign \empty
+\let\rightofeqalign\empty
+
+\def\mathineqalign#1{$\forgetalign\displaystyle{{}#1{}}$}
+\def\textineqalign#1{$\forgetalign#1$}
+
+\def\eqalign#1% why no halign here, probably because of displaywidth
+ {\null\,\vcenter
+ {\openup.25\bodyfontsize% was: \openup\jot
+ \mathsurround\zeropoint
+ \ialign{\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##{}}$\hfil\crcr#1\crcr}%
+ }\,}
+
+% preamble is scanned for tabskips so we need the span to prevent an error message
+
+\chardef\eqalignmode\plusone
+
+\def\preparereqalignno
+ {\!!toksa{\strut\firstineqalign\hfil\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \!!toksb{&\nextineqalign\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \ifnum\mathraggedstatus=\plusone
+ \!!toksc{\hfil&\span\textineqalign{##}\tabskip\zeropoint}%
+ \else\ifnum\mathraggedstatus=\plusthree
+ \!!toksc{\hfil\tabskip\zeropoint\!!plus 1\!!fill&\span\textineqalign{##}\tabskip\zeropoint}%
+ \else
+ \!!toksc{\hfil\tabskip\centering&\llap{\span\textineqalign{##}}\tabskip\zeropoint}%
+ \fi\fi
+ \global\chardef\mathnumberstatus\zerocount
+ \buildeqalign
+ \presetdisplaymath
+ \tabskip\centering}
+
+\def\prepareleqalignno
+ {\!!toksa{\strut\firstineqalign\hfil\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ \!!toksb{&\nextineqalign\leftofeqalign\span\mathineqalign{##}\rightofeqalign\tabskip\zeropoint}%
+ % problem: number is handled after rest and so ends up in the margin
+ \ifnum\mathraggedstatus=\plusone
+ \!!toksc{\hfil&\kern-\displaywidth\rlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \else\ifnum\mathraggedstatus=\plusthree
+ \!!toksc{\hfil\tabskip\zeropoint\!!plus 1\!!fill&\kern-\displaywidth\span\mrlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \else
+ \!!toksc{\hfil\tabskip\centering&\kern-\displaywidth\rlap{\span\textineqalign{##}}\tabskip\displaywidth}%
+ \fi\fi
+ \global\chardef\mathnumberstatus\zerocount
+ \buildeqalign
+ \presetdisplaymath
+ \tabskip\centering}
+
+\def\dobotheqalignno#1#2%
+ {\ifmmode
+ \displ@y % \let\doplaceformulanumber\relax % strange hack
+ \vcenter\bgroup
+ \let\finishalignno\egroup
+ \else
+ \let\finishalignno\relax
+ \fi
+ #1%
+ \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA {\the\scratchtoks\crcr#2\crcr}%
+ \finishalignno}
+
+\def\dobothaligneqalignno#1%
+ {\ifmmode
+ \displ@y
+ \global\chardef\mathnumberstatus\plusone
+ \ifcase\mathraggedstatus
+ \def\finishalignno{\crcr\egroup}%
+ \else
+ % we're in a mathbox
+ \vcenter\bgroup
+ \def\finishalignno{\crcr\egroup\egroup}%
+ \fi
+ \fi
+ #1%
+ \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA \bgroup\the\scratchtoks\crcr}
+
+\def\mrlap#1%
+ {\setbox\scratchbox\hbox{#1}%
+ \ifdim\wd\scratchbox>\mathnumbercorrection
+ \xdef\mathnumbercorrection{\the\wd\scratchbox}%
+ \fi
+ \box\scratchbox
+ \global\chardef\mathnumberstatus\plustwo}
+
+% \def\dobothaligneqalignno#1%
+% {\ifmmode
+% \displ@y
+% \global\chardef\mathnumberstatus\plusone
+% we're in a mathbox
+% \vcenter\bgroup
+% \def\finishalignno{\crcr\egroup\egroup}%
+% \else
+% \def\finishalignno{\crcr\egroup}%
+% \fi
+% #1%
+% \halign \ifcase\eqalignmode \or to \displaywidth \fi \@EA \bgroup\the\scratchtoks\crcr}
+
+\def\reqalignno {\dobotheqalignno \preparereqalignno}
+\def\leqalignno {\dobotheqalignno \prepareleqalignno}
+\def\alignreqalignno{\dobothaligneqalignno\preparereqalignno}
+\def\alignleqalignno{\dobothaligneqalignno\prepareleqalignno}
+\def\finishalignno {\crcr\egroup}
+
+\let \equalignno \reqalignno
+\let\aligneqalignno\alignreqalignno
+
+%D Here we implement the user interface part.
+
+\def\setupmathalignment
+ {\dodoubleempty\dosetupmathalignment}
+
+\def\dosetupmathalignment[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??eq#1][#2]%
+ \else
+ \getparameters[\??eq][#1]%
+ \fi}
+
+\let\currentmathalignment\empty
+
+\def\mathalignmentparameter#1%
+ {\executeifdefined{\??eq\currentmathalignment#1}{\executeifdefined{\??eq#1}\empty}}
+
+\setupmathalignment
+ [\c!n=2,
+ \c!m=1,
+ \c!distance=1em]
+
+\def\numberedeqalign
+ {\doifelse{\formulaparameter\c!location}\v!left\alignleqalignno\alignreqalignno}
+
+\def\doxxdoubleempty#1#2%
+ {\ifx#2[\expandafter\dodoxxdoubleempty\else\expandafter\noxxdoubleempty\fi#1#2}
+
+\def\dodoxxdoubleempty#1[#2]#3%
+ {\ifx#3[\else\expandafter\nonoxxdoubleempty\fi#1[#2]#3}
+
+\def\noxxdoubleempty #1{#1[][]}
+\def\nonoxxdoubleempty#1[#2]{#1[#2][]}
+
+\newcount\eqaligncolumn
+
+\def\firstineqalign{\global\eqaligncolumn\plusone}
+\def\nextineqalign {\global\advance\eqaligncolumn\plusone}
+\def\leftofeqalign {\getvalue{\??eq:\v!left :\number\eqaligncolumn}}
+\def\rightofeqalign{\getvalue{\??eq:\v!right:\number\eqaligncolumn}}
+
+\def\doseteqaligncolumn#1%
+ {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\empty
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\empty
+ \doif{#1}\v!left {\letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfill}%
+ \doif{#1}\v!right {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfill}%
+ \doif{#1}\v!middle{\letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfill
+ \letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfill}}
+
+\def\dodoalignNC
+ {\gdef\doalignNC##1{&##1}}
+
+\def\doalignNR[#1][#2]%
+ {\donestedformulanumber{#1}{#2}\crcr}
+
+%D \starttyping
+%D \placeformula[eqn0]\startformula \startalign[n=1] a\NR \stopalign \stopformula See \in[eqn0]
+%D \placeformula[eqn1]\startformula \startalign[n=1] a\NR \stopalign \stopformula See \in[eqn1]
+%D \placeformula \startformula \startalign[n=1] a\NR[eqn2] \stopalign \stopformula See \in[eqn2]
+%D \placeformula[eqn3]\startformula \startalign[n=1] a\NR[+] \stopalign \stopformula See \in[eqn3]
+%D \stoptyping
+
+% todo: pop in cell
+
+\def\dostartmathalignment[#1][#2]%
+ {% \begingroup not permitted ($$...assignments...\halign... )
+ \pushmacro\doalignNC
+ \edef\currentmathalignment{#1}%
+ \doifassignmentelse{#2}{\setupmathalignment[#1][#2]}\donothing
+ \def\NC{\doalignNC}%
+ \global\let\doalignNC\dodoalignNC
+ \def\EQ{&=}%
+ \def\NR{&\global\let\doalignNC\dodoalignNC\doxxdoubleempty\doalignNR}%
+ % amstex compatibility mode: (ugly, will disappear)
+ \def\notag{\def\\{&\crcr}}%
+ \doifelse{#2}{*}{\def\\{&\crcr}}{\def\\{&\doalignNR[+][]\crcr}}%
+ % end of compatibility mode
+ \eqaligncolumn\zerocount
+ \processcommacommand
+ [\mathalignmentparameter\c!align]
+ {\advance\eqaligncolumn\plusone\doseteqaligncolumn}% takes argument
+ % the real action
+ \global\eqaligncolumn\plusone
+ \numberedeqalign}
+
+\def\dostopmathalignment
+ {\finishalignno
+ \popmacro\doalignNC}
+
+\def\definemathalignment
+ {\dodoubleempty\dodefinemathalignment}
+
+\def\dodefinemathalignment[#1]% [#2]%
+ {\setvalue{\e!start#1}{\dodoubleempty\dostartmathalignment[#1]}%
+ \setvalue{\e!stop #1}{\dostopmathalignment}%
+ \setupmathalignment[#1]}% [#2]
+
+%D For the moment we only provide english commands.
+
+\definemathalignment[align] % default case (this is what amstex users expect)
+\definemathalignment[\v!mathalignment] % prefered case (this is cleaner, less clashing)
+
+%D \startbuffer
+%D \placeformula \startformula \eqalignno {
+%D a &= b & \formulanumber \cr
+%D c &= d \cr
+%D &= e \cr
+%D &= f & \formulanumber
+%D } \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \EQ b \NR[+]
+%D \NC c \EQ d \NR
+%D \NC \EQ f \NR[for:demo-a-1]
+%D \NC \EQ g \NR[for:demo-a-2][a]
+%D \NC \EQ h \NR[for:demo-a-3][b]
+%D \NC \EQ i \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \EQ b \NR[+]
+%D \NC c \EQ d \NR
+%D \NC \EQ f \NR
+%D \NC \EQ g \NR
+%D \NC \EQ h \NR
+%D \NC \EQ i \NR[+]
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D a &= b \\
+%D c &= d \notag \\
+%D &= e \notag \\
+%D &= f \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D \NC a \NC \eq b \NR[+]
+%D \NC c \NC \neq d \NR
+%D \NC \NC \neq f \NR[for:demo-b-1]
+%D \NC \NC \geq g \NR[for:demo-b-2][a]
+%D \NC \NC \leq h \NR[for:demo-b-3][b]
+%D \NC \NC \neq i \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[*]
+%D a &= b \\
+%D c &= d \\
+%D &= e \\
+%D &= f \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign
+%D x &= y \\
+%D a &= b \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[m=3]
+%D x &= y & x &= y & z &= t \\
+%D a &= b & p &= q & w &= s \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[m=3,distance=0pt]
+%D x &= y &= x &= y &= z &= t \\
+%D a &= b &= p &= q &= w &= s \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=5,distance=0pt]
+%D x &= yy &= xx &= yy &= zz \\
+%D a &= b &= p &= q &= w \\
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={left,middle,right}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={right,middle,left}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startalign[n=3,align={middle,middle,middle}]
+%D \NC l \NC = \NC r \NR
+%D \NC left \NC = \NC right \NR
+%D \stopalign \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformula
+%D \startalign[n=3,align={middle,middle,middle}]
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformulas
+%D \setupmathalignment[n=3,align={middle,middle,middle}]%
+%D \startformula
+%D \startalign
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \startformula
+%D \startalign
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula
+%D \stopformulas
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula
+%D \startformulas
+%D \dorecurse{5}{\startformula
+%D \startalign[n=3,align={middle,middle,middle}]
+%D \NC a \NC = \NC b \NR[+]
+%D \NC 2a \NC = \NC 2b \NR
+%D \stopalign
+%D \stopformula}
+%D \stopformulas
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {definemathcases, setupmathcases, startmathcases}
+%D
+%D Another wish \unknown
+
+\def\setupmathcases
+ {\dodoubleempty\dosetupmathcases}
+
+\def\dosetupmathcases[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??ce#1][#2]%
+ \else
+ \getparameters[\??ce][#1]%
+ \fi}
+
+\let\currentmathcases\empty
+
+\def\mathcasesparameter#1%
+ {\executeifdefined{\??ce\currentmathcases#1}{\executeifdefined{\??ce#1}\empty}}
+
+\setupmathcases
+ [\c!distance=1em,
+ \c!numberdistance=2.5em,
+ \c!left={\left\{\,},
+ \c!right={\right.}]
+
+\def\dodocasesNC
+ {\gdef\docasesNC{\endmath&}}
+
+\let\docasesNR\doalignNR
+
+\def\dostartmathcases[#1][#2]%
+ {\begingroup
+ \edef\currentmathcases{#1}%
+ \doifassignmentelse{#2}{\setupmathcases[#1][#2]}\donothing
+ \mathcasesparameter\c!left
+ \vcenter\bgroup
+ \pushmacro\docasesNC
+ \let\endmath\relax
+ \def\NC{\docasesNC}%
+ \def\MC{\docasesNC\ifmmode\else$\def\endmath{$}\fi}%
+ \global\let\docasesNC\dodocasesNC
+ \def\NR{\unskip\endmath&\global\let\docasesNC\dodocasesNC\doxxdoubleempty\docasesNR}%
+ \normalbaselines
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \global\eqaligncolumn\plusone
+ \halign\bgroup
+ $\mathcasesparameter\c!style##$\hfil
+ &\hskip\mathcasesparameter\c!distance\relax
+ \popmacro\docasesNC##\hfil
+ &\hskip\mathcasesparameter\c!numberdistance\relax
+ \let\formuladistance\!!zeropoint
+ \span\textineqalign{##}%
+ \crcr} % todo: number
+
+\def\dostopmathcases
+ {\crcr
+ \egroup
+ \popmacro\docasesNC
+ \egroup
+ \mathcasesparameter\c!right
+ \endgroup}
+
+\def\definemathcases
+ {\dodoubleempty\dodefinemathcases}
+
+\def\dodefinemathcases[#1]% [#2]%
+ {\setvalue{\e!start#1}{\dodoubleempty\dostartmathcases[#1]}%
+ \setvalue{\e!stop #1}{\dostopmathcases}%
+ \setupmathcases[#1]}% [#2]
+
+\definemathcases[cases]
+\definemathcases[\v!mathcases]
+
+%D \startbuffer
+%D \placeformula \startformula \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR[+]
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula x \startcases
+%D \NC 2 \NC $ y > 0 $ \NR[+]
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \placeformula \startformula x \startcases
+%D \NC 2 \NC $ y > 0 $ \NR
+%D \NC 7 \NC $ x = 7 $ \NR
+%D \NC 4 \NC otherwise \NR
+%D \stopcases \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {definemathmatrix, setupmathmatrix, startmathmatrix}
+%D
+%D Yet another one \unknown
+
+\def\setupmathmatrix
+ {\dodoubleempty\dosetupmathmatrix}
+
+\def\dosetupmathmatrix[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??mx#1][#2]%
+ \else
+ \getparameters[\??mx][#1]%
+ \fi}
+
+\let\currentmathmatrix\empty
+
+\def\mathmatrixparameter#1%
+ {\executeifdefined{\??mx\currentmathmatrix#1}{\executeifdefined{\??mx#1}\empty}}
+
+\setupmathmatrix
+ [\c!distance=1em,
+ \c!left=,
+ \c!right=,
+ \c!align=\v!middle]
+
+\def\dosetmatrixcolumn#1% hh: todo: \definematrixalign
+ {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil
+ \doif{#1}\v!left {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\relax
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil}%
+ \doif{#1}\v!right {\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\relax }%
+ \doif{#1}\v!middle{\letvalue{\??eq:\v!left :\number\eqaligncolumn}\hfil
+ \letvalue{\??eq:\v!right:\number\eqaligncolumn}\hfil}}
+
+\def\buildmathmatrix % beware: etex only
+ {\scratchtoks\emptytoks
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksa}}%
+ \dorecurse{\numexpr\scratchcounter-\plusone\relax}
+ {\normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksb}}}%
+ \normalexpanded{\scratchtoks{\the\scratchtoks\the\!!toksc }}}
+
+\def\preparemathmatrix
+ {\!!toksa{\strut \firstineqalign\leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \!!toksb{&\hskip\mathmatrixparameter\c!distance
+ \nextineqalign\leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \!!toksc{&&\hskip\mathmatrixparameter\c!distance
+ \leftofeqalign \span
+ \textineqalign{\mathmatrixparameter\c!style ##}\rightofeqalign}%
+ \buildmathmatrix
+ \halign \@EA \bgroup\the\scratchtoks \crcr}
+
+\def\definemathmatrix
+ {\dodoubleempty\dodefinemathmatrix}
+
+\def\dodefinemathmatrix[#1]% [#2]%
+ {\setvalue{\e!start#1}{\dodoubleempty\dostartmathmatrix[#1]}%
+ \setvalue{\e!stop #1}{\dostopmathmatrix}%
+ \setupmathmatrix[#1]}% [#2]
+
+\definemathmatrix[matrix]
+\definemathmatrix[\v!mathmatrix]
+
+\def\dodomatrixNC
+ {\gdef\domatrixNC{\endmath&}}
+
+\def\installmathmatrixhandler#1#2%
+ {\setvalue{\??mx:#1}{#2}}
+
+% First alternative:
+%
+% \def\processlowhighmathmatrix#1%
+% {\def\mathmatrixleft
+% {\setbox\nextbox}
+% \def\mathmatrixright
+% {#1.5\dimexpr\nextboxdp-\nextboxht\relax
+% \hbox{$\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right$}}%
+% \let\mathmatrixbox\vbox}
+%
+% \installmathmatrixhandler\v!high {\processlowhighmathmatrix\raise}
+% \installmathmatrixhandler\v!low {\processlowhighmathmatrix\lower}
+%
+% \installmathmatrixhandler\v!top {\processlowhighmathmatrix\raise}
+% \installmathmatrixhandler\v!bottom{\processlowhighmathmatrix\lower}
+%
+% \installmathmatrixhandler\v!lohi
+% {\def\mathmatrixleft {\mathmatrixparameter\c!left}%
+% \def\mathmatrixright{\mathmatrixparameter\c!right}%
+% \let\mathmatrixbox\vcenter}
+%
+% An alternative
+%
+% \let\mathmatrixleft \empty
+% \let\mathmatrixright\empty
+%
+% \def\processlowhighmathmatrix#1%
+% {\dowithnextbox
+% {#1.5\dimexpr\nextboxdp-\nextboxht\relax
+% \hbox{$\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right$}}%
+% \vbox}
+%
+% \def\processlohimathmatrix
+% {\dowithnextbox
+% {\mathmatrixparameter\c!left
+% \vcenter{\unvbox\nextbox}%
+% \mathmatrixparameter\c!right}%
+% \vbox}
+%
+% \installmathmatrixhandler\v!high {\def\mathmatrixbox{\processlowhighmathmatrix\raise}}
+% \installmathmatrixhandler\v!low {\def\mathmatrixbox{\processlowhighmathmatrix\lower}}
+% \installmathmatrixhandler\v!top {\def\mathmatrixbox{\processlowhighmathmatrix\raise}}
+% \installmathmatrixhandler\v!bottom{\def\mathmatrixbox{\processlowhighmathmatrix\lower}}
+% \installmathmatrixhandler\v!lohi {\let\mathmatrixbox \processlohimathmatrix}
+%
+% Final version
+
+\let\mathmatrixleft \empty % experimental hook
+\let\mathmatrixright\empty % experimental hook
+
+\def\processlowhighmathmatrix#1#2%
+ {\dowithnextbox
+ {\scratchdimen\dimexpr(\nextboxdp-\nextboxht)/2 \ifcase#2\or+\mathaxisheight\textfont2\fi\relax
+ \ifcase#1\relax\or\lower\scratchdimen\or\or\raise\scratchdimen\fi
+ \hbox{$\mathmatrixparameter\c!left
+ \vcenter{\unvbox\nextbox}%
+ \mathmatrixparameter\c!right$}}%
+ \vbox}
+
+\installmathmatrixhandler\v!top {\def\mathmatrixbox{\processlowhighmathmatrix\plusthree\plusone }}
+\installmathmatrixhandler\v!high {\def\mathmatrixbox{\processlowhighmathmatrix\plusthree\zerocount}}
+\installmathmatrixhandler\v!lohi {\def\mathmatrixbox{\processlowhighmathmatrix\plustwo \zerocount}}
+\installmathmatrixhandler\v!low {\def\mathmatrixbox{\processlowhighmathmatrix\plusone \zerocount}}
+\installmathmatrixhandler\v!bottom{\def\mathmatrixbox{\processlowhighmathmatrix\plusone \plusone }}
+
+\def\dostartmathmatrix[#1][#2]%
+ {\begingroup
+ \edef\currentmathmatrix{#1}%
+ \doifassignmentelse{#2}{\setupmathmatrix[#1][#2]}\donothing
+ \null
+ \executeifdefined{\??mx:\mathmatrixparameter\c!location}{\getvalue{\??mx:\v!lohi}}%
+ \mathmatrixleft
+ \mathmatrixbox\bgroup
+ \pushmacro\domatrixNC
+ \let\endmath\relax
+ \def\NC{\domatrixNC}%
+ \def\MC{\domatrixNC\ifmmode\else$\def\endmath{$}\fi}%
+ \global\let\domatrixNC\dodomatrixNC
+ \def\NR{\endmath\global\let\domatrixNC\dodomatrixNC\crcr}%
+ \normalbaselines
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \tabskip\zeropoint
+ \eqaligncolumn\zerocount % could be \scratchcounter
+ \processcommacommand[\mathmatrixparameter\c!align]{\advance\eqaligncolumn\plusone\dosetmatrixcolumn}%
+ \scratchcounter=\ifnum\eqaligncolumn>\zerocount \eqaligncolumn \else \plusone \fi
+ \global\eqaligncolumn\plusone
+ \preparemathmatrix } % uses scratchcounter
+
+\def\dostopmathmatrix
+ {\crcr
+ \mathstrut\crcr
+ \noalign{\kern-\baselineskip}%
+ \egroup
+ \popmacro\domatrixNC
+ \egroup
+ \mathmatrixright
+ \endgroup}
+
+%D \startbuffer
+%D \placeformula \startformula[-] \startmatrix
+%D \NC 1 \NC x \NC a \NR
+%D \NC 2 \NC y \NC b \NR
+%D \NC 3 \NC z \NC c \NR
+%D \stopmatrix \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \definemathmatrix[bmatrix][left={\left[\,},right={\,\right]}]
+%D
+%D \startbuffer
+%D \placeformula \startformula[-] \startbmatrix
+%D \NC 1 \NC x \NC a \NR
+%D \NC 2 \NC y \NC b \NR
+%D \NC 3 \NC z \NC c \NR
+%D \stopbmatrix \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D Taco added some code (dedicated to Aditya Mahajan) that gives more
+%D control over aligments:
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix
+%D \NC a + x \NC = \NC a + d \NR
+%D \NC y \NC = \NC d \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix [distance=3pt,align={right,left}]
+%D \NC a + x \NC = a + d \NR
+%D \NC y \NC = d \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix [left=\left(,right=\right)]
+%D \NC a + x \NR
+%D \NC y \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D A bit more complex code:
+%D
+%D \startbuffer
+%D \startformula
+%D \text{Let }{\cal R} = \bigcup_{P_{X_1},P_{X_2}}
+%D \left\{ (R_1, R_2) :
+%D \startmatrix[distance=1em,align={left,left,right}]
+%D \NC R_1 \NC < I(X_1 ; Y \mid X_2) \NC R_1 \NR
+%D \NC \hfill Q_2 \NC < I(X_2 ; Y \mid X_1) \NC R_2 \NR
+%D \NC R_1 + R_2 \NC < I(X_1 ; Y) \NC R_1 + R_2 \NR
+%D \stopmatrix
+%D \right\}
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {startmatrices}
+%D
+%D Just a handy keystroke safer:
+
+\def\startmatrices
+ {\begingroup
+ \setupmathmatrix}
+
+\def\stopmatrices
+ {\endgroup}
+
+%D \startbuffer
+%D \startformula
+%D \startmatrix[left={\left(},right={\right)}]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[left={\left(},right={\right)},location=low]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[left={\left(},right={\right)},location=high]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \startformula
+%D \startmatrices[left={\left(},right={\right)}]
+%D \startmatrix
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[location=bottom]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D =
+%D \startmatrix[location=top]
+%D \NC A \NC B \NR \NC C \NC D \NR
+%D \stopmatrix
+%D \stopmatrices
+%D \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+%D \macros
+%D {startintertext}
+%D
+%D Preliminary feature:
+%D
+%D {\em example code}
+
+\def\startintertext#1\stopintertext
+ {\noalign{\dointertext{#1}}}
+
+\def\intertext#1%
+ {\noalign{\dointertext{#1}}}
+
+\unexpanded\def\dointertext#1%
+ {\penalty\postdisplaypenalty
+ \afterdisplayspace
+ \vbox{\forgetall\noindent#1\par}%
+ \penalty\predisplaypenalty
+ \beforedisplayspace}
+
+% %D \macros
+% %D {substack}
+% %D
+% %D Preliminary code:
+% %D
+% %D \starttyping
+% %D \startformula
+% %D \sum_{%
+% %D \startsubstack
+% %D i = 1 \NR
+% %D i \neq n \NR
+% %D i \neq m
+% %D \stopsubstack
+% %D }a_i
+% %D \stopformula
+% %D \stoptyping
+
+% \def\startsubstack
+% {\begingroup
+% \null
+% \vcenter\bgroup
+% \pushmacro\domatrixNC
+% \let\stopmathmode\relax
+% \def\NC{\domatrixNC}%
+% \def\MC{\domatrixNC\startmathmode}%
+% \global\let\domatrixNC\dodomatrixNC
+% \def\NR
+% {\stopmathmode
+% \global\let\domatrixNC\dodomatrixNC
+% \crcr\noalign{\nointerlineskip}}%
+% \mathsurround\zeropoint
+% \everycr\emptytoks
+% \halign\bgroup\hfil$\scriptstyle\mathstrut##$\hfil\crcr}
+
+% \def\stopsubstack
+% {\crcr
+% \egroup
+% \popmacro\domatrixNC
+% \egroup
+% \endgroup}
+
+%D \macros
+%D {substack}
+%D
+%D Preliminary code:
+%D
+%D \startbuffer
+%D \startformula
+%D \sum_{%
+%D \startsubstack
+%D i = 1 \NR
+%D i \neq n \NR
+%D i \neq m
+%D \stopsubstack
+%D }a_i
+%D \stopformula
+%D \stopbuffer
+%D
+%D \getbuffer which was typed as \typebuffer
+%D
+%D Notice that these macros give the correct spacing for
+%D subscripts. Compare for example
+%D
+%D \startbuffer
+%D \startformula
+%D \sum_{\startsubstack a \NR b \NR \stopsubstack}
+%D \text{ and }
+%D \sum_{\scriptstyle a \atop \scriptstyle}
+%D \stopformula
+%D \typebuffer which gives \getbuffer
+
+\def\startsubstack
+ {\begingroup
+ \vcenter\bgroup
+ \baselineskip\mathstacktotal
+ \lineskip\mathstackvgap
+ \lineskiplimit\lineskip
+ \let\stopmathmode\relax
+ \def\NC{\domatrixNC}%
+ \def\MC{\domatrixNC\startmathmode}%
+ \global\let\domatrixNC\dodomatrixNC
+ \def\NR
+ {\stopmathmode
+ \global\let\domatrixNC\dodomatrixNC
+ \crcr}%
+ \mathsurround\zeropoint
+ \everycr\emptytoks
+ \halign\bgroup\hfil$\scriptstyle##$\hfil\crcr}
+
+\def\stopsubstack
+ {\crcr
+ \egroup
+ \egroup
+ \endgroup}
+
+%D \macros
+%D {bordermatrix}
+%D
+%D In \PLAIN\ \TEX\ the width of a parenthesis is stored in
+%D the \DIMENSION\ \type{\mathparentwd}. This value is derived from
+%D the width of \type{\tenrm B}, so let's take care of it now:
+
+\ifx\mathparentwd\undefined \newdimen\mathparentwd \fi
+
+\let\normalbordermatrix\bordermatrix
+
+\def\bordermatrix
+ {\begingroup
+ \setbox\scratchbox\hbox{\mr\char"239C}%
+ \global\mathparentwd\wd\scratchbox\relax
+ \endgroup
+ \normalbordermatrix}
+
+% to be tested
+%
+% \def\bordermatrix
+% {\begingroup\mr\global\mathparentwd\fontcharwd\font"239C\relax\endgroup
+% \normalbordermatrix}
+
+%D \macros{overset, underset}
+%D
+%D The macros \type{\overset} and \type{\underset} are provided by
+%D \AMS\ packages in \LATEX. These macro allows you to place a symbol
+%D above or below another symbol, irrespective of whether the other
+%D symbol is a relation or something else, and without influencing the
+%D spacing. For most cases there is a better way to do such things
+%D (declaring a math command with limop option, or using accents), but
+%D occasionally these macros can be useful, for example:
+%D
+%D \startbuffer
+%D \startformula
+%D \overset{*}{X} \underset{*}{X}
+%D \stopformula
+%D \stopbuffer
+%D \typebuffer \getbuffer
+%D
+%D Use these macros sparingly. Remember, \TEX\ was designed for
+%D mathematics, so there is usually a proper method for typesetting
+%D common math notation.
+
+%D These macros are a clearer version of \type{\binrel@} and
+%D \type{\binrel@@} macros in \AMSTEX\ packages.
+
+\def\preparebinrel#1%
+ {\begingroup
+ \setbox\scratchbox\hbox
+ {\thinmuskip 0mu
+ \medmuskip -1mu
+ \thickmuskip -1mu
+ \setbox\scratchbox\hbox{$#1\mathsurround\zeropoint$}%
+ \kern-\wd\scratchbox
+ ${}#1{}\mathsurround\zeropoint$}%
+ \normalexpanded
+ {\endgroup
+ \let\noexpand\currentbinrel
+ \ifdim\wd\scratchbox<\zeropoint
+ \mathbin
+ \else\ifdim\wd\scratchbox>\zeropoint
+ \mathrel
+ \else
+ \relax
+ \fi\fi}}
+
+\unexpanded\def\overset#1#2%
+ {\preparebinrel{#2}%
+ \currentbinrel{\mathop{\kern\zeropoint#2}\limits^{#1}}}
+
+\unexpanded\def\underset#1#2%
+ {\preparebinrel{#2}%
+ \currentbinrel{\mathop{\kern\zeropoint#2}\limits_{#1}}}
+
+\protect \endinput
+
+% \placeformula \startformula[-] \startmatrix
+% \NC 1 \NC x \NC a \NR
+% \NC 2 \NC y \NC b \NR
+% \NC 3 \NC z \NC c \NR
+% \stopmatrix \stopformula
+
+% \definemathmatrix[bordermatrix][left={\left[\,},right={\,\right]}]
+
+% \placeformula \startformula[-] \startbordermatrix
+% \NC 1 \NC x \NC a \NR
+% \NC 2 \NC y \NC b \NR
+% \NC 3 \NC z \NC c \NR
+% \stopbordermatrix \stopformula
diff --git a/tex/context/base/math-ams.tex b/tex/context/base/math-ams.tex
index 29fe19e0b..83070d01a 100644
--- a/tex/context/base/math-ams.tex
+++ b/tex/context/base/math-ams.tex
@@ -311,7 +311,7 @@
\stopmathcollection
\def\AMSwidehat#1%
- {\setbox\scratchbox\hbox{$\m@th#1$}%
+ {\setbox\scratchbox\hbox{$\mathsurround\zeropoint#1$}%
\ifdim\wd\scratchbox>2em
\mathaccent"0\purefamilyhex{mb}5B{#1}%
\else
@@ -319,7 +319,7 @@
\fi}
\def\AMSwidetilde#1%
- {\setbox\scratchbox\hbox{$\m@th#1$}%
+ {\setbox\scratchbox\hbox{$\mathsurround\zeropoint#1$}%
\ifdim\wd\scratchbox>2em
\mathaccent"0\purefamilyhex{mb}5D{#1}%
\else
diff --git a/tex/context/base/math-arr.mkii b/tex/context/base/math-arr.mkii
new file mode 100644
index 000000000..3b9abaa91
--- /dev/null
+++ b/tex/context/base/math-arr.mkii
@@ -0,0 +1,391 @@
+%D \module
+%D [ file=math-ext,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Arrows,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Arrows}
+
+\unprotect
+
+%D These will be generalized! Is it still needed in \MKIV?
+
+%D We next define extensible arrows. Extensible arrows are arrows that
+%D change their length according to the width of the text to be placed
+%D above and below the arrow. Since we need to define a lot of arrows,
+%D we first define some helper macros. The basic idea is to measure
+%D the width of the box to be placed above and below the arrow, and
+%D make the \quotation{body} of the arrow as long as the bigger of the
+%D two widths.
+
+\def\mtharrfactor{1}
+\def\mtharrextra {0}
+
+\def\domthxarr#1#2#3#4#5% hm, looks like we do a double mathrel
+ {\begingroup
+ \def\mtharrfactor{1}%
+ \def\mtharrextra {0}%
+ \processaction[#1] % will be sped up
+ [ \v!none=>\def\mtharrfactor{0},
+ \v!small=>\def\mtharrextra{10},
+ \v!medium=>\def\mtharrextra{15},
+ \v!big=>\def\mtharrextra{20},
+ \v!normal=>,
+ \v!default=>,
+ \v!unknown=>\doifnumberelse{#1}{\def\mtharrextra{#1}}\donothing]%
+ \mathsurround\zeropoint
+ \muskip0=\thirdoffourarguments #2mu
+ \muskip2=\fourthoffourarguments #2mu
+ \muskip4=\firstoffourarguments #2mu
+ \muskip6=\secondoffourarguments #2mu
+ \muskip0=\mtharrfactor\muskip0 \advance\muskip0 \mtharrextra mu
+ \muskip2=\mtharrfactor\muskip2 \advance\muskip2 \mtharrextra mu
+ \setbox0\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #5\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \setbox4\hbox{#3\displaystyle}%
+ \dimen0\wd0
+ \ifdim\wd4>\dimen0 \dimen0\wd4 \fi
+ \setbox2\hbox{$\scriptstyle
+ \mkern\muskip4\relax
+ \mkern\muskip0\relax
+ #4\relax
+ \mkern\muskip2\relax
+ \mkern\muskip6\relax
+ $}%
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{#3\displaystyle}%
+ \mathrel{\mathop{\hbox to \dimen0{\hss\copy4\hss}}\limits^{\box0}_{\box2}}
+ \endgroup}
+
+\let\domthxarrsingle\domthxarr
+
+%D There are some arrows which are created by stacking two arrows. The next
+%D macro helps in defining such \quotation{double arrows}.
+
+\def\domthxarrdouble#1#2#3#4#5#6#7% opt l r sp rs top bot
+ {\mathrel
+ {\scratchdimen.32ex\relax % was .22, todo: make configurable
+ \setbox0\hbox{$\domthxarr{#1}{#2}{#4}{\phantom{#6}}{#7}$}%
+ \setbox2\hbox{$\domthxarr{#1}{#3}{#5}{#6}{\phantom{#7}}$}%
+ \raise\scratchdimen\box0
+ \kern-\wd2
+ \lower\scratchdimen\box2}}
+
+%D \macros{definematharrow}
+%D
+%D Macro for defining new arrows. We can define two types of
+%D arrows|<|single arrows and double arrows. Single arrows are defined
+%D as
+%D
+%D \starttyping
+%D \definematharrow [xrightarrow] [0359] [\rightarrowfill]
+%D \stoptyping
+%D
+%D The first argument is the name of the arrow (\tex{xrightarrow} in
+%D this case.) The second argument consists of a set of 4 numbers and
+%D specify the spacing correction in math units~\type{mu}. These
+%D numbers define:
+%D
+%D \startlines
+%D 1st number: arrow||tip correction
+%D 2nd number: arrow||tip correction
+%D 3rd number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D 4th number: space (multiplied by \tex{matharrfactor} and advanced by \tex{matharrextra})
+%D \stoplines
+%D
+%D The third argument is the name of the extensible fill. The third
+%D argument is optional when the arrow is redefined later (this is
+%D useful for font specific tweaking of the skips.) For example,
+%D
+%D \startbuffer
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][0000]
+%D \math{\xrightarrow{above}}
+%D \definematharrow[xrightarrow][55{50}{50}]
+%D \math{\xrightarrow{above}}
+%D \stopbuffer
+%D \typebuffer gives {\getbuffer}
+%D
+%D The double arrows are defined as follows
+%D
+%D \starttyping
+%D \definematharrow [xrightleftharpoons] [3095,0359]
+%D [\rightharpoonupfill,\leftharpoondownfill]
+%D \stoptyping
+%D
+%D The second and the third set of arguments consist of comma
+%D separated values. The first element of the second argument
+%D (\type{3095}) corresponds to the spacing correction of top arrow
+%D fill (\tex{rightarrowupfill}). Similarly, \type{0359} corresponds
+%D to bottom arrow fill \tex{leftharpoondownfill}). Stacking them on
+%D top of each other we get $\xrightleftharpoons[big]{above}{below}$.
+%D The following math arrows are defined
+%D
+%D \placetable[none]{}{\starttable[|l|m|]
+%D \NC \tex{xrightarrow } \NC \xrightarrow [big] \NC \NR
+%D \NC \tex{xleftarrow } \NC \xleftarrow [big] \NC \NR
+%D \NC \tex{xequal } \NC \xequal [big] \NC \NR
+%D \NC \tex{xRightarrow } \NC \xRightarrow [big] \NC \NR
+%D \NC \tex{xLeftarrow } \NC \xLeftarrow [big] \NC \NR
+%D \NC \tex{xLeftrightarrow } \NC \xLeftrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightarrow } \NC \xleftrightarrow [big] \NC \NR
+%D \NC \tex{xmapsto } \NC \xmapsto [big] \NC \NR
+%D \NC \tex{xtwoheadrightarrow } \NC \xtwoheadrightarrow [big] \NC \NR
+%D \NC \tex{xtwoheadleftarrow } \NC \xtwoheadleftarrow [big] \NC \NR
+%D \NC \tex{xrightharpoondown } \NC \xrightharpoondown [big] \NC \NR
+%D \NC \tex{xrightharpoonup } \NC \xrightharpoonup [big] \NC \NR
+%D \NC \tex{xleftharpoondown } \NC \xleftharpoondown [big] \NC \NR
+%D \NC \tex{xleftharpoonup } \NC \xleftharpoonup [big] \NC \NR
+%D \NC \tex{xhookleftarrow } \NC \xhookleftarrow [big] \NC \NR
+%D \NC \tex{xhookrightarrow } \NC \xhookrightarrow [big] \NC \NR
+%D \NC \tex{xleftrightharpoons } \NC \xleftrightharpoons [big] \NC \NR
+%D \NC \tex{xrightleftharpoons } \NC \xrightleftharpoons [big] \NC \NR
+%D \stoptable}
+
+\def\definematharrow
+ {\doquadrupleargument\dodefinematharrow}
+
+\def\dodefinematharrow[#1][#2][#3][#4]% name type[none|both] template command
+ {\iffourthargument
+ \executeifdefined{dodefine#2arrow}\gobblethreearguments{#1}{#3}{#4}%
+ \else\ifthirdargument
+ \dodefinebotharrow{#1}{#2}{#3}%
+ \else\ifsecondargument
+ \redefinebotharrow{#1}{#2}{#3}%
+ \fi\fi\fi}
+
+\def\redefinebotharrow#1#2#3% real dirty, this overload!
+ {\doifdefined{#1}
+ {\pushmacro\dohandlemtharrow
+ \def\dohandlemtharrow[##1][##2]{\setvalue{#1}{\dohandlemtharrow[#2][##2]}}%
+ % == \def\dohandlemtharrow[##1][##2]{\dodefinebotharrow{#1}{#2}{##2}}%
+ \getvalue{#1}%
+ \popmacro\dohandlemtharrow}}
+
+\def\dodefinebotharrow#1#2#3%
+ {\setvalue{#1}{\dohandlemtharrow[#2][#3]}}
+
+\def\dohandlemtharrow
+ {\dotripleempty\doxmtharrow}
+
+\def\doxmtharrow[#1][#2][#3]% #3 == optional arg
+ {\def\dodoxmtharrow{\dododoxmtharrow[#1,\empty,\empty][#2,\empty,\empty][#3]}% {##1}{##2}
+ \dodoublegroupempty\dodoxmtharrow}
+
+\def\dododoxmtharrow[#1,#2,#3][#4,#5,#6][#7]#8#9% [3] is the optional arg
+ {\edef\!!stringa{#2}%
+ \ifx\!!stringa\empty
+ \ifsecondargument
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrsingle{#7}{#1}{#4}{}{#8}}%
+ \fi
+ \else
+ \ifsecondargument
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{#8}{#9}}%
+ \else
+ \mathrel{\domthxarrdouble{#7}{#1}{#2}{#4}{#5}{}{#8}}%
+ \fi
+ \fi}
+
+% Adapted from amsmath.
+
+%D \macros{mtharrowfill,defaultmtharrowfill}
+%D
+%D To extend the arrows we need to define a \quotation{math arrow
+%D fill}. This command takes 8 arguments: the first four correspond
+%D the second argument of \tex{definematharrow} explained above. The
+%D other three specify the tail, body and head of the arrow. The last
+%D argument specifies the math-mode in which the arrow is drawn.
+%D \tex{defaultmtharrowfill} has values tweaked to match Latin Modern
+%D fonts. For fonts that are significantly different (e.g. cows) a
+%D different set of values need to be determined.
+
+\def\mtharrowfill#1#2#3#4#5#6#7#8%
+ {$\mathsurround 0pt
+ \thickmuskip0mu\medmuskip\thickmuskip\thinmuskip\thickmuskip
+ \relax#8#5%
+ \mkern-#1mu
+ \cleaders\hbox{$#8\mkern -#2mu#6\mkern -#3mu$}\hfill
+ \mkern-#4mu#7$}
+
+\def\defaultmtharrowfill{\mtharrowfill 7227}
+
+%D We now define some arrow fills that will be used for defining the
+%D arrows. Plain \TEX\ already defines \tex{leftarrowfill} and
+%D \tex{rightarrowfill}. The \tex{defaultmtharrowfill} command defines an
+%D arrowfill that takes an argument (so that it can also be used
+%D with over and under arrows). However the Plain \TEX\ definitions of
+%D \tex{leftarrowfill} and \tex{rightarrowfill} do not take this extra
+%D argument. To be backward compatible with Plain \TEX, we define two
+%D arrowfills: \tex{specrightarrowfill} which takes an extra argument, and
+%D \tex{rightarrowfill} which does not.
+
+\def\specrightarrowfill {\defaultmtharrowfill \relbar \relbar \rightarrow}
+\def\specleftarrowfill {\defaultmtharrowfill \leftarrow \relbar \relbar}
+
+\def\rightarrowfill {\specrightarrowfill \textstyle}
+\def\leftarrowfill {\specleftarrowfill \textstyle}
+
+\def\equalfill {\defaultmtharrowfill \Relbar \Relbar \Relbar}
+\def\Rightarrowfill {\defaultmtharrowfill \Relbar \Relbar \Rightarrow}
+\def\Leftarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Relbar}
+\def\Leftrightarrowfill {\defaultmtharrowfill \Leftarrow \Relbar \Rightarrow}
+\def\leftrightarrowfill {\defaultmtharrowfill \leftarrow \relbar \rightarrow}
+\def\mapstofill {\defaultmtharrowfill{\mapstochar\relbar} \relbar \rightarrow}
+\def\twoheadrightarrowfill{\defaultmtharrowfill \relbar \relbar \twoheadrightarrow}
+\def\twoheadleftarrowfill {\defaultmtharrowfill \twoheadleftarrow \relbar \relbar}
+\def\rightharpoondownfill {\defaultmtharrowfill \relbar \relbar \rightharpoondown}
+\def\rightharpoonupfill {\defaultmtharrowfill \relbar \relbar \rightharpoonup}
+\def\leftharpoondownfill {\defaultmtharrowfill \leftharpoondown \relbar \relbar}
+\def\leftharpoonupfill {\defaultmtharrowfill \leftharpoonup \relbar \relbar}
+\def\hookleftfill {\defaultmtharrowfill \leftarrow \relbar{\relbar\joinrel\rhook}}
+\def\hookrightfill {\defaultmtharrowfill{\lhook\joinrel\relbar}\relbar \rightarrow}
+\def\relfill {\defaultmtharrowfill \relbar \relbar \relbar}
+
+\def\triplerelbar {\mathrel\equiv}
+\def\triplerelfill{\defaultmtharrowfill\triplerelbar\triplerelbar\triplerelbar}
+
+\def\singlebond{{\xrel}} % or \def\singlebond{{\xrel[2]}}
+\def\doublebond{{\xequal}}
+\def\triplebond{{\xtriplerel}}
+
+%D Now we define most commonly used arrows. These include arrows
+%D defined in \filename{amsmath.sty}, \filename{extarrows.sty},
+%D \filename{extpfel.sty} and \filename{mathtools.sty} packages for
+%D \LATEX\ (plus a few more).
+
+\definematharrow [xrightarrow] [0359] [\specrightarrowfill]
+\definematharrow [xleftarrow] [3095] [\specleftarrowfill]
+\definematharrow [xequal] [0099] [\equalfill]
+\definematharrow [xRightarrow] [0359] [\Rightarrowfill]
+\definematharrow [xLeftarrow] [3095] [\Leftarrowfill]
+\definematharrow [xLeftrightarrow] [0099] [\Leftrightarrowfill]
+\definematharrow [xleftrightarrow] [0099] [\leftrightarrowfill]
+\definematharrow [xmapsto] [3599] [\mapstofill]
+\definematharrow [xtwoheadrightarrow] [5009] [\twoheadrightarrowfill]
+\definematharrow [xtwoheadleftarrow] [0590] [\twoheadleftarrowfill]
+\definematharrow [xrightharpoondown] [0359] [\rightharpoondownfill]
+\definematharrow [xrightharpoonup] [0359] [\rightharpoonupfill]
+\definematharrow [xleftharpoondown] [3095] [\leftharpoondownfill]
+\definematharrow [xleftharpoonup] [3095] [\leftharpoonupfill]
+\definematharrow [xhookleftarrow] [3095] [\hookleftfill]
+\definematharrow [xhookrightarrow] [0395] [\hookrightfill]
+\definematharrow [xrel] [0099] [\relfill]
+\definematharrow [xtriplerel] [0099] [\triplerelfill]
+\definematharrow [xrightoverleftarrow] [0359,3095] [\specrightarrowfill,\specleftarrowfill]
+\definematharrow [xleftrightharpoons] [3399,3399] [\leftharpoonupfill,\rightharpoondownfill]
+\definematharrow [xrightleftharpoons] [3399,3399] [\rightharpoonupfill,\leftharpoondownfill]
+
+%D These arrows can be used as follows:
+%D
+%D \startbuffer
+%D \startformula \xrightarrow{stuff on top}\stopformula
+%D \startformula \xrightarrow{}{stuff on top}\stopformula
+%D \startformula \xrightarrow{stuff below}{}\stopformula
+%D \startformula \xrightarrow{stuff below}{stuff on top}\stopformula
+%D
+%D \startformula \xleftarrow [none]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [small]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [medium]{stuff below}{stuff on top}\stopformula
+%D \startformula \xleftarrow [big]{stuff below}{stuff on top}\stopformula
+%D \stopbuffer
+%D
+%D \typebuffer which gives \getbuffer
+
+%D \macros{definemathoverarrow,defineunderarrow}
+%D
+%D These macros for define math-overarrows are adapted from
+%D \filename{amsmath.sty}
+
+\def\definemathoverarrow
+ {\dotripleargument\dodefinemathoverarrow}
+
+\def\dodefinemathoverarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{#1}{\dohandlemathoverarrow[#2][#3]}%
+ \else
+ \setvalue{#1}{\dohandlemathoverarrow[\zeropoint][#2]}%
+ \fi}
+
+\def\dohandlemathoverarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathoverarrow{#1}{#2}}}
+
+%D Note: \filename{math-pln.tex} has \type{\kern-\onepoint} and
+%D \filename{amsmath.sty} does not. We keep the kern amount
+%D configurable. This is useful for harpoons.
+
+\def\dodohandlemathoverarrow#1#2#3#4%
+ {\vbox{\ialign{##\crcr
+ #2#3\crcr
+ \noalign{\kern#1\nointerlineskip}%
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr}}}
+
+%D Now the under arrows
+
+\def\definemathunderarrow
+ {\dotripleargument\dodefinemathunderarrow}
+
+%D For underarrows the default kern is 0.3ex
+
+\def\dodefinemathunderarrow[#1][#2][#3]%
+ {\ifthirdargument
+ \setvalue{#1}{\dohandlemathunderarrow[#2][#3]}%
+ \else
+ \setvalue{#1}{\dohandlemathunderarrow[0.3ex][#2]}%
+ \fi}
+
+\def\dohandlemathunderarrow[#1][#2]%
+ {\mathpalette{\dodohandlemathunderarrow{#1}{#2}}}
+
+\def\dodohandlemathunderarrow#1#2#3#4%
+ {\vtop{\ialign{##\crcr
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr
+ \noalign{\nointerlineskip\kern#1}%
+ #2#3\crcr}}}
+
+%D Now we define the arrows
+
+\definemathoverarrow [overleftarrow] [\specleftarrowfill]
+\definemathoverarrow [overrightarrow] [\specrightarrowfill]
+\definemathoverarrow [overleftrightarrow] [\leftrightarrowfill]
+\definemathoverarrow [overtwoheadrightarrow] [\twoheadrightarrowfill]
+\definemathoverarrow [overtwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathoverarrow [overrightharpoondown] [1pt] [\rightharpoondownfill]
+\definemathoverarrow [overrightharpoonup] [\rightharpoonupfill]
+\definemathoverarrow [overleftharpoondown] [1pt] [\leftharpoondownfill]
+\definemathoverarrow [overleftharpoonup] [\leftharpoonupfill]
+
+\definemathunderarrow [underleftarrow] [\specleftarrowfill]
+\definemathunderarrow [underrightarrow] [\specrightarrowfill]
+\definemathunderarrow [underleftrightarrow] [\leftrightarrowfill]
+\definemathunderarrow [undertwoheadrightarrow][\twoheadrightarrowfill]
+\definemathunderarrow [undertwoheadleftarrow] [\twoheadleftarrowfill]
+\definemathunderarrow [underrightharpoondown] [\rightharpoondownfill]
+\definemathunderarrow [underrightharpoonup] [\rightharpoonupfill]
+\definemathunderarrow [underleftharpoondown] [\leftharpoondownfill]
+\definemathunderarrow [underleftharpoonup] [\leftharpoonupfill]
+
+%D These can be used as follows:
+%D
+%D \startbuffer
+%D $\overleftarrow{A}$ $\overleftarrow{ABC}$
+%D $a_{\overleftarrow{A}}$ $b_{\overleftarrow{ABC}}$
+%D \stopbuffer
+%D \typebuffer which gives \getbuffer
+
+%D TODO: Possibly have a single arrow command define all the arrows.
+
+\protect \endinput
diff --git a/tex/context/base/math-ext.tex b/tex/context/base/math-arr.mkiv
index cf332ba00..5c6cfc294 100644
--- a/tex/context/base/math-ext.tex
+++ b/tex/context/base/math-arr.mkiv
@@ -1,8 +1,8 @@
%D \module
-%D [ file=math-ext,
+%D [ file=math-arr,
%D version=2007.07.19,
%D title=\CONTEXT\ Math Macros,
-%D subtitle=Extra Macros,
+%D subtitle=Arrows,
%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
%D date=\currentdate,
%D copyright=\PRAGMA]
@@ -11,9 +11,11 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Math Macros / Arrows}
+
\unprotect
-%D These will be generalized!
+%D These will be generalized! Is it still needed in \MKIV?
\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
@@ -271,19 +273,19 @@
%D We now define some arrow fills that will be used for defining the
%D arrows. Plain \TEX\ already defines \tex{leftarrowfill} and
-%D \tex{rightarrowfill}. The \tex{defaultmtharrowfill} command defines an
+%D \tex{rightarrowfill}. The \tex{defaultmtharrowfill} command defines an
%D arrowfill that takes an argument (so that it can also be used
-%D with over and under arrows). However the Plain \TEX\ definitions of
+%D with over and under arrows). However the Plain \TEX\ definitions of
%D \tex{leftarrowfill} and \tex{rightarrowfill} do not take this extra
%D argument. To be backward compatible with Plain \TEX, we define two
-%D arrowfills: \tex{specrightarrowfill} which takes an extra argument, and
+%D arrowfills: \tex{specrightarrowfill} which takes an extra argument, and
%D \tex{rightarrowfill} which does not.
\def\specrightarrowfill {\defaultmtharrowfill \relbar \relbar \rightarrow}
\def\specleftarrowfill {\defaultmtharrowfill \leftarrow \relbar \relbar}
-\def\rightarrowfill {\specrightarrowfill \textstyle}
-\def\leftarrowfill {\specleftarrowfill \textstyle}
+\def\rightarrowfill {\specrightarrowfill \textstyle}
+\def\leftarrowfill {\specleftarrowfill \textstyle}
\def\equalfill {\defaultmtharrowfill \Relbar \Relbar \Relbar}
\def\Rightarrowfill {\defaultmtharrowfill \Relbar \Relbar \Rightarrow}
@@ -377,7 +379,7 @@
{\vbox{\ialign{##\crcr
#2#3\crcr
\noalign{\kern#1\nointerlineskip}%
- $\m@th\hfil#3#4\hfil$\crcr}}}
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr}}}
%D Now the under arrows
@@ -398,7 +400,7 @@
\def\dodohandlemathunderarrow#1#2#3#4%
{\vtop{\ialign{##\crcr
- $\m@th\hfil#3#4\hfil$\crcr
+ $\mathsurround\zeropoint\hfil#3#4\hfil$\crcr
\noalign{\nointerlineskip\kern#1}%
#2#3\crcr}}}
diff --git a/tex/context/base/math-def.mkiv b/tex/context/base/math-def.mkiv
new file mode 100644
index 000000000..9e6ad28c1
--- /dev/null
+++ b/tex/context/base/math-def.mkiv
@@ -0,0 +1,338 @@
+%D \module
+%D [ file=math-tex,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Definitions,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Definitions}
+
+\unprotect
+
+\ifx\mrfam\undefined \chardef\mrfam\plusone \fi
+
+\startluacode
+ mathematics.define()
+ mathematics.register_xml_entities()
+\stopluacode
+
+% special .. todo
+
+\mathcode`\ ="8000 \mathcode`\_="8000 \mathcode`\'="8000
+
+% will be attributes
+
+\setfalse \automathpunctuation
+
+\def\enablemathpunctuation {\settrue \automathpunctuation}
+\def\disablemathpunctuation{\setfalse\automathpunctuation}
+
+\def\v!autopunctuation{autopunctuation}
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!autopunctuation}\v!yes\enablemathpunctuation\disablemathpunctuation
+\to \everysetupmathematics
+
+\appendtoks
+ \ifconditional\automathpunctuation\dosetattribute{mathpunc}\plusone\fi
+\to \everymathematics
+
+\setupmathematics[\v!autopunctuation=\v!yes]
+
+% will go to math-ext
+
+\Umathchardef\braceld=0 \mrfam "FF07A
+\Umathchardef\bracerd=0 \mrfam "FF07B
+\Umathchardef\bracelu=0 \mrfam "FF07C
+\Umathchardef\braceru=0 \mrfam "FF07D
+
+% ctx specific
+
+\def\|{|} % still letter
+
+% The \mfunction macro is an alternative for \hbox with a
+% controlable font switch.
+
+\definemathcommand [arccos] [nolop] {\mfunction{arccos}}
+\definemathcommand [arcsin] [nolop] {\mfunction{arcsin}}
+\definemathcommand [arctan] [nolop] {\mfunction{arctan}}
+\definemathcommand [arg] [nolop] {\mfunction{arg}}
+\definemathcommand [cosh] [nolop] {\mfunction{cosh}}
+\definemathcommand [cos] [nolop] {\mfunction{cos}}
+\definemathcommand [coth] [nolop] {\mfunction{coth}}
+\definemathcommand [cot] [nolop] {\mfunction{cot}}
+\definemathcommand [csc] [nolop] {\mfunction{csc}}
+\definemathcommand [deg] [nolop] {\mfunction{deg}}
+\definemathcommand [det] [limop] {\mfunction{det}}
+\definemathcommand [dim] [nolop] {\mfunction{dim}}
+\definemathcommand [exp] [nolop] {\mfunction{exp}}
+\definemathcommand [gcd] [limop] {\mfunction{gcd}}
+\definemathcommand [hom] [nolop] {\mfunction{hom}}
+\definemathcommand [inf] [limop] {\mfunction{inf}}
+\definemathcommand [injlim] [limop] {\mfunction{inj\,lim}}
+\definemathcommand [ker] [nolop] {\mfunction{ker}}
+\definemathcommand [lg] [nolop] {\mfunction{lg}}
+\definemathcommand [liminf] [limop] {\mfunction{lim\,inf}}
+\definemathcommand [limsup] [limop] {\mfunction{lim\,sup}}
+\definemathcommand [lim] [limop] {\mfunction{lim}}
+\definemathcommand [ln] [nolop] {\mfunction{ln}}
+\definemathcommand [log] [nolop] {\mfunction{log}}
+\definemathcommand [median] [limop] {\mfunction{median}}
+\definemathcommand [max] [limop] {\mfunction{max}}
+\definemathcommand [min] [limop] {\mfunction{min}}
+\definemathcommand [mod] [limop] {\mfunction{mod}}
+\definemathcommand [div] [limop] {\mfunction{div}}
+\definemathcommand [projlim] [limop] {\mfunction{proj\,lim}}
+\definemathcommand [Pr] [limop] {\mfunction{Pr}}
+\definemathcommand [sec] [nolop] {\mfunction{sec}}
+\definemathcommand [sinh] [nolop] {\mfunction{sinh}}
+\definemathcommand [sin] [nolop] {\mfunction{sin}}
+\definemathcommand [sup] [limop] {\mfunction{sup}}
+\definemathcommand [tanh] [nolop] {\mfunction{tanh}}
+\definemathcommand [tan] [nolop] {\mfunction{tan}}
+
+\definemathcommand [integers] {{\mathblackboard Z}}
+\definemathcommand [reals] {{\mathblackboard R}}
+\definemathcommand [rationals] {{\mathblackboard Q}}
+\definemathcommand [naturalnumbers]{{\mathblackboard N}}
+\definemathcommand [complexes] {{\mathblackboard C}}
+\definemathcommand [primes] {{\mathblackboard P}}
+
+% using attributes
+
+\def\choosemathbig#1#2{\dosetattribute{mathsize}{#1}\left#2\right.\doresetattribute{mathsize}}
+
+\definemathcommand [big] {\choosemathbig\plusone }
+\definemathcommand [Big] {\choosemathbig\plustwo }
+\definemathcommand [bigg] {\choosemathbig\plusthree}
+\definemathcommand [Bigg] {\choosemathbig\plusfour }
+
+\definemathcommand [bigl] [open] [one] {\big}
+\definemathcommand [bigm] [rel] [one] {\big}
+\definemathcommand [bigr] [close] [one] {\big}
+\definemathcommand [Bigl] [open] [one] {\Big}
+\definemathcommand [Bigm] [rel] [one] {\Big}
+\definemathcommand [Bigr] [close] [one] {\Big}
+\definemathcommand [biggl] [open] [one] {\bigg}
+\definemathcommand [biggm] [rel] [one] {\bigg}
+\definemathcommand [biggr] [close] [one] {\bigg}
+\definemathcommand [Biggl] [open] [one] {\Bigg}
+\definemathcommand [Biggm] [rel] [one] {\Bigg}
+\definemathcommand [Biggr] [close] [one] {\Bigg}
+
+% special
+
+%AM: Optimize this! Add similar options for sums.
+
+\def\setoperatorlimits#1#2% operator limits
+ {\savenormalmeaning{#1}%
+ \def#1{\getvalue{normal\strippedcsname#1}#2}}
+
+\setoperatorlimits\int \intlimits
+\setoperatorlimits\iint \intlimits
+\setoperatorlimits\iiint \intlimits
+\setoperatorlimits\oint \intlimits
+\setoperatorlimits\oiint \intlimits
+\setoperatorlimits\oiiint \intlimits
+\setoperatorlimits\intclockwise \intlimits
+\setoperatorlimits\ointclockwise \intlimits
+\setoperatorlimits\ointctrclockwise \intlimits
+
+%D This is a temporary hack until we figure out how to do this correctly.
+
+\unexpanded\def\implies {\mathrel{\;\Longrightarrow\;}}
+\unexpanded\def\impliedby{\mathrel{\;\Longleftarrow\;}}
+\unexpanded\def\And {\mathrel{\;\internalAnd\;}}
+\unexpanded\def\iff {\;\Longleftrightarrow\;}
+
+% todo: virtual in math-vfu
+
+% \definemathcommand [mapsto] {\mapstochar\rightarrow}
+% \definemathcommand [hookrightarrow] {\lhook\joinrel\rightarrow}
+% \definemathcommand [hookleftarrow] {\leftarrow\joinrel\rhook}
+% \definemathcommand [bowtie] {\mathrel\triangleright\joinrel\mathrel\triangleleft}
+% \definemathcommand [models] {\mathrel|\joinrel=}
+% \definemathcommand [iff] {\;\Longleftrightarrow\;}
+
+% hm
+
+% ldots = 2026
+% vdots = 22EE
+% cdots = 22EF
+% ddots = 22F1
+% udots = 22F0
+
+% \def\PLAINldots{\ldotp\ldotp\ldotp}
+% \def\PLAINcdots{\cdotp\cdotp\cdotp}
+
+% \def\PLAINvdots
+% {\vbox{\baselineskip.4\bodyfontsize\lineskiplimit\zeropoint\kern.6\bodyfontsize\hbox{.}\hbox{.}\hbox{.}}}
+
+% \def\PLAINddots
+% {\mkern1mu%
+% \raise.7\bodyfontsize\vbox{\kern.7\bodyfontsize\hbox{.}}%
+% \mkern2mu%
+% \raise.4\bodyfontsize\relax\hbox{.}%
+% \mkern2mu%
+% \raise.1\bodyfontsize\hbox{.}%
+% \mkern1mu}
+
+% \definemathcommand [ldots] [inner] {\PLAINldots}
+% \definemathcommand [cdots] [inner] {\PLAINcdots}
+% \definemathcommand [vdots] [nothing] {\PLAINvdots}
+% \definemathcommand [ddots] [inner] {\PLAINddots}
+
+%D \starttyping
+%D $\sqrt[3]{10}$
+%D \stoptyping
+
+\def\rootradical{\Uroot 0 "221A } % can be done in char-def
+
+\def\root#1\of{\rootradical{#1}} % #2
+
+\unexpanded\def\sqrt{\doifnextoptionalelse\rootwithdegree\rootwithoutdegree}
+
+\def\rootwithdegree [#1]{\rootradical{#1}}
+\def\rootwithoutdegree {\rootradical {}}
+
+\def\PLAINmatrix#1%
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}
+
+\definemathcommand [mathstrut] {\vphantom{(}}
+\definemathcommand [joinrel] {\mathrel{\mkern-3mu}}
+
+% \definemathcommand [matrix] {\PLAINmatrix}
+% \definemathcommand [over] {\normalover} % hack, to do
+
+\unexpanded\def\{{\mathortext\lbrace\letterleftbrace }
+\unexpanded\def\}{\mathortext\rbrace\letterrightbrace}
+
+%D The following colon related definitions are provided by Aditya
+%D Mahajan who derived them from \type {mathtools.sty} and \type
+%D {colonequals.sty}.
+
+%D \macros
+%D {centercolon, colonminus, minuscolon, colonequals, equalscolon,
+%D colonapprox, approxcolon, colonsim, simcolon, coloncolon,
+%D coloncolonminus, minuscoloncolon, coloncolonequals,
+%D equalscoloncolon, coloncolonapprox, approxcoloncolon,
+%D colonsim, simcoloncolon}
+%D
+%D In $a := b$ the colon is not vertically centered with the equal
+%D to. Also the distance between colon and equal to is a bit large.
+%D So, we define a vertically centered colon \tex {centercolon} and
+%D a few macros for colon and double colon relation symbols.
+%D
+%D \startlines
+%D \formula {A \centercolon B}
+%D \formula {A \colonminus B}
+%D \formula {A \minuscolon B}
+%D \formula {A \colonequals B}
+%D \formula {A \equalscolon B}
+%D \formula {A \colonapprox B}
+%D \formula {A \approxcolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcolon B}
+%D \formula {A \coloncolon B}
+%D \formula {A \coloncolonminus B}
+%D \formula {A \minuscoloncolon B}
+%D \formula {A \coloncolonequals B}
+%D \formula {A \equalscoloncolon B}
+%D \formula {A \coloncolonapprox B}
+%D \formula {A \approxcoloncolon B}
+%D \formula {A \colonsim B}
+%D \formula {A \simcoloncolon B}
+%D \stoplines
+
+%D The next macros take care of the space between the colon and the
+%D relation symbol.
+
+\definemathcommand [colonsep] {\mkern-1.2mu}
+\definemathcommand [doublecolonsep] {\mkern-0.9mu}
+
+%D The next macro vertically centeres its contents.
+
+\def\@center@math#1%
+ {\vcenter{\hbox{$\mathsurround\zeropoint#1$}}}
+
+\def\@center@colon
+ {\mathpalette\@center@math{\colon}}
+
+%D Now we define all the colon relations.
+
+\definemathcommand [centercolon] [rel] {\@center@colon}
+\definemathcommand [colonminus] [rel] {\centercolon\colonsep\mathrel{-}}
+\definemathcommand [minuscolon] [rel] {\mathrel{-}\colonsep\centercolon}
+\definemathcommand [colonequals] [rel] {\centercolon\colonsep=}
+\definemathcommand [equalscolon] [rel] {=\centercolon\colonsep}
+\definemathcommand [colonapprox] [rel] {\centercolon\colonsep\approx}
+\definemathcommand [approxcolon] [rel] {\approx\centercolon\colonsep}
+\definemathcommand [colonsim] [rel] {\centercolon\colonsep\sim}
+\definemathcommand [simcolon] [rel] {\sim\centercolon\colonsep}
+
+\definemathcommand [coloncolon] [rel] {\centercolon\doublecolonsep\centercolon}
+\definemathcommand [coloncolonminus] [rel] {\coloncolon\colonsep\mathrel{-}}
+\definemathcommand [minuscoloncolon] [rel] {\mathrel{-}\colonsep\coloncolon}
+\definemathcommand [coloncolonequals] [rel] {\coloncolon\colonsep=}
+\definemathcommand [equalscoloncolon] [rel] {=\coloncolon\colonsep}
+\definemathcommand [coloncolonapprox] [rel] {\coloncolon\colonsep\approx}
+\definemathcommand [approxcoloncolon] [rel] {\approx\coloncolon\colonsep}
+\definemathcommand [colonsim] [rel] {\coloncolon\colonsep\sim}
+\definemathcommand [simcoloncolon] [rel] {\sim\coloncolon\colonsep}
+
+%D Goodies. We might move this elsewhere.
+
+\def\underleftarrow #1{\mathop{\Uunderdelimiter 0 "2190 {#1}}}
+\def\overleftarrow #1{\mathop{\Uoverdelimiter 0 "2190 {#1}}}
+\def\underrightarrow#1{\mathop{\Uunderdelimiter 0 "2192 {#1}}}
+\def\overrightarrow #1{\mathop{\Uoverdelimiter 0 "2192 {#1}}}
+
+% todo: \Udelimiterover, \Udelimiterunder
+
+\def\normaldoublebrace {\Umathaccents 0 0 "23DE 0 0 "23DF }
+\def\normaldoubleparent{\Umathaccents 0 0 "23DC 0 0 "23DD }
+
+\let\normaloverbrace \overbrace
+\let\normalunderbrace \underbrace
+\let\normaloverparent \overparent
+\let\normalunderparent \underparent
+\let\normalunderleftarrow \underleftarrow
+\let\normaloverleftarrow \overleftarrow
+\let\normalunderrightarrow\underrightarrow
+\let\normaloverrightarrow \overrightarrow
+
+\unexpanded\def\mathopwithlimits#1#2{\mathop{#1{#2}}\limits}
+\unexpanded\def\stackrel #1#2{\mathrel{\mathop{#2}\limits^{#1}}}
+
+\unexpanded\def\overbrace {\mathopwithlimits\normaloverbrace }
+\unexpanded\def\underbrace {\mathopwithlimits\normalunderbrace }
+\unexpanded\def\doublebrace {\mathopwithlimits\normaldoublebrace }
+\unexpanded\def\overparent {\mathopwithlimits\normaloverparent }
+\unexpanded\def\underparent {\mathopwithlimits\normalunderparent }
+\unexpanded\def\doubleparent {\mathopwithlimits\normaldoubleparent }
+\unexpanded\def\underleftarrow {\mathopwithlimits\normalunderleftarrow }
+\unexpanded\def\overleftarrow {\mathopwithlimits\normaloverleftarrow }
+\unexpanded\def\underrightarrow{\mathopwithlimits\normalunderrightarrow}
+\unexpanded\def\overrightarrow {\mathopwithlimits\normaloverrightarrow }
+
+% todo mathclass=punctuation ord
+
+% \Umathcode"02C="6 "0 "02C
+% \Umathcode"02E="0 "0 "02E
+
+% tricky .. todo
+
+\appendtoks
+ \def\over{\primitive\over}%
+\to \everymathematics
+
+\protect \endinput
diff --git a/tex/context/base/math-del.mkiv b/tex/context/base/math-del.mkiv
new file mode 100644
index 000000000..5ffda1919
--- /dev/null
+++ b/tex/context/base/math-del.mkiv
@@ -0,0 +1,63 @@
+%D \module
+%D [ file=math-del,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Delimiters,
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Delimiters}
+
+\unprotect
+
+%D \macros
+%D {checkdelimiters, fakeleftdelimiter, fakerightdelimiter}
+%D
+%D Handy for non matching situations (as with mathml):
+%D
+%D \starttyping
+%D \checkdelimiters{... bla bla ...}
+%D \fakeleftdelimiter
+%D ... bla bla ...
+%D \fakerightdelimiter
+%D \stoptyping
+
+\newcount\delimitercount
+
+\def\leftfakedelimiter {\advance\delimitercount\minusone\gobbleoneargument}%
+\def\rightfakedelimiter{\advance\delimitercount\plusone \gobbleoneargument}%
+
+\def\checkdelimiters#1%
+ {\delimitercount\zerocount
+ \setbox\scratchbox\hbox\bgroup
+ \let\left \leftfakedelimiter
+ \let\right\rightfakedelimiter
+ $#1\expandafter$\expandafter
+ \egroup
+ \expandafter\delimitercount\the\delimitercount\relax}
+
+\def\fakeleftdelimiter {\ifnum\delimitercount>\zerocount\left .\fi}
+\def\fakerightdelimiter{\ifnum\delimitercount<\zerocount\right.\fi}
+
+%D The following macros are used in the MathML interpreter, so
+%D there is a good change of them never being documented for
+%D other usage.
+
+\let\normalordelimiter\secondoftwoarguments
+\let\normalorfiller \firstoftwoarguments
+
+\def\enabledelimiter {\let\normalordelimiter\secondoftwoarguments}
+\def\disabledelimiter{\let\normalordelimiter\firstoftwoarguments}
+
+\def\enablefiller {\let\normalorfiller\secondoftwoarguments}
+\def\disablefiller {\let\normalorfiller\firstoftwoarguments}
+
+\def\mathopnolimits#1{\mathop{\mr#1}\nolimits} % was \rm, which follows text fonts (used in mml parser)
+\def\mathopdolimits#1{\mathop{\mr#1}} % was \rm, which follows text fonts (used in mml parser)
+
+\protect \endinput
diff --git a/tex/context/base/math-dim.lua b/tex/context/base/math-dim.lua
new file mode 100644
index 000000000..a536f0309
--- /dev/null
+++ b/tex/context/base/math-dim.lua
@@ -0,0 +1,310 @@
+if not modules then modules = { } end modules ['math-dim'] = {
+ version = 1.001,
+ comment = "companion to math-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Beware: only Taco really understands in depth what these dimensions do so
+-- if you run into problems ...
+
+local abs, next = math.abs, next
+
+mathematics = mathematics or { }
+
+local defaults = {
+ ['axis']={
+ ['default']={ "AxisHeight", "axis_height" },
+ },
+ ['accent_base_height']={
+ ['default']={ "AccentBaseHeight", "x_height" },
+ },
+ ['fraction_del_size']={
+ ['default']={ "0", "delim2" },
+ ['cramped_display_style']={ "0", "delim1" },
+ ['display_style']={ "0", "delim1" },
+ },
+ ['fraction_denom_down']={
+ ['default']={ "FractionDenominatorShiftDown", "denom2" },
+ ['cramped_display_style']={ "FractionDenominatorDisplayStyleShiftDown", "denom1" },
+ ['display_style']={ "FractionDenominatorDisplayStyleShiftDown", "denom1" },
+ },
+ ['fraction_denom_vgap']={
+ ['default']={ "FractionDenominatorGapMin", "default_rule_thickness" },
+ ['cramped_display_style']={ "FractionDenominatorDisplayStyleGapMin", "3*default_rule_thickness" },
+ ['display_style']={ "FractionDenominatorDisplayStyleGapMin", "3*default_rule_thickness" },
+ },
+ ['fraction_num_up']={
+ ['default']={ "FractionNumeratorShiftUp", "num2" },
+ ['cramped_display_style']={ "FractionNumeratorDisplayStyleShiftUp", "num1" },
+ ['display_style']={ "FractionNumeratorDisplayStyleShiftUp", "num1" },
+ },
+ ['fraction_num_vgap']={
+ ['default']={ "FractionNumeratorGapMin", "default_rule_thickness" },
+ ['cramped_display_style']={ "FractionNumeratorDisplayStyleGapMin", "3*default_rule_thickness" },
+ ['display_style']={ "FractionNumeratorDisplayStyleGapMin", "3*default_rule_thickness" },
+ },
+ ['fraction_rule']={
+ ['default']={ "FractionRuleThickness", "default_rule_thickness" },
+ },
+ ['limit_above_bgap']={
+ ['default']={ "UpperLimitBaselineRiseMin", "big_op_spacing3" },
+ },
+ ['limit_above_kern']={
+ ['default']={ "0", "big_op_spacing5" },
+ },
+ ['limit_above_vgap']={
+ ['default']={ "UpperLimitGapMin", "big_op_spacing1" },
+ },
+ ['limit_below_bgap']={
+ ['default']={ "LowerLimitBaselineDropMin", "big_op_spacing4" },
+ },
+ ['limit_below_kern']={
+ ['default']={ "0", "big_op_spacing5" },
+ },
+ ['limit_below_vgap']={
+ ['default']={ "LowerLimitGapMin", "big_op_spacing2" },
+ },
+
+--~ ['....']={
+--~ ['default']={ "DisplayOperatorMinHeight", "....." },
+--~ },
+
+ ['overbar_kern']={
+ ['default']={ "OverbarExtraAscender", "default_rule_thickness" },
+ },
+ ['overbar_rule']={
+ ['default']={ "OverbarRuleThickness", "default_rule_thickness" },
+ },
+ ['overbar_vgap']={
+ ['default']={ "OverbarVerticalGap", "3*default_rule_thickness" },
+ },
+ ['quad']={
+ ['default']={ "font_size(f)", "math_quad" },
+ },
+ ['radical_kern']={
+ ['default']={ "RadicalExtraAscender", "default_rule_thickness" },
+ },
+ ['radical_rule']={
+ ['default']={ "RadicalRuleThickness", "<not set>" },
+ },
+ ['radical_vgap']={
+ ['default']={ "RadicalVerticalGap", "default_rule_thickness+(abs(default_rule_thickness)/4)" },
+ ['display_style']={ "RadicalDisplayStyleVerticalGap", "default_rule_thickness+(abs(math_x_height)/4)" },
+ },
+ ['space_after_script']={
+ ['default']={ "SpaceAfterScript", "script_space" },
+ },
+ ['stack_denom_down']={
+ ['default']={ "StackBottomShiftDown", "denom2" },
+ ['cramped_display_style']={ "StackBottomDisplayStyleShiftDown", "denom1" },
+ ['display_style']={ "StackBottomDisplayStyleShiftDown", "denom1" },
+ },
+ ['stack_num_up']={
+ ['default']={ "StackTopShiftUp", "num3" },
+ ['cramped_display_style']={ "StackTopDisplayStyleShiftUp", "num1" },
+ ['display_style']={ "StackTopDisplayStyleShiftUp", "num1" },
+ },
+ ['stack_vgap']={
+ ['default']={ "StackGapMin", "3*default_rule_thickness" },
+ ['cramped_display_style']={ "StackDisplayStyleGapMin", "7*default_rule_thickness" },
+ ['display_style']={ "StackDisplayStyleGapMin", "7*default_rule_thickness" },
+ },
+ ['sub_shift_down']={
+ ['default']={ "SubscriptShiftDown", "sub1" },
+ },
+ ['sub_shift_drop']={
+ ['default']={ "SubscriptBaselineDropMin", "sub_drop" },
+ },
+ ['sub_sup_shift_down']={
+ ['default']={ "SubscriptShiftDown", "sub2" },
+ },
+ ['sub_top_max']={
+ ['default']={ "SubscriptTopMax", "abs(math_x_height*4)/5" },
+ },
+ ['subsup_vgap']={
+ ['default']={ "SubSuperscriptGapMin", "4*default_rule_thickness" },
+ },
+ ['sup_bottom_min']={
+ ['default']={ "SuperscriptBottomMin", "abs(math_x_height)/4" },
+ },
+ ['sup_shift_drop']={
+ ['default']={ "SuperscriptBaselineDropMax", "sup_drop" },
+ },
+ ['sup_shift_up']={
+ ['cramped_display_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_script_script_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_script_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['cramped_text_style']={ "SuperscriptShiftUpCramped", "sup3" },
+ ['display_style']={ "SuperscriptShiftUp", "sup1" },
+ ['script_script_style']={ "SuperscriptShiftUp", "sup2" },
+ ['script_style']={ "SuperscriptShiftUp", "sup2" },
+ ['text_style']={ "SuperscriptShiftUp", "sup2" },
+ },
+ ['sup_sub_bottom_max']={
+ ['default']={ "SuperscriptBottomMaxWithSubscript", "abs(math_x_height*4)/5" },
+ },
+ ['underbar_kern']={
+ ['default']={ "UnderbarExtraDescender", "0" },
+ },
+ ['underbar_rule']={
+ ['default']={ "UnderbarRuleThickness", "default_rule_thickness" },
+ },
+ ['underbar_vgap']={
+ ['default']={ "UnderbarVerticalGap", "3*default_rule_thickness" },
+ },
+ ['connector_overlap_min']={
+ ['default']={ "MinConnectorOverlap", "0.25*default_rule_thickness" },
+ },
+ ['over_delimiter_vgap']={
+ ['default']={ "StretchStackGapBelowMin", "big_op_spacing1" },
+ },
+ ['over_delimiter_bgap']={
+ ['default']={ "StretchStackTopShiftUp", "big_op_spacing3" },
+ },
+ ['under_delimiter_vgap']={
+ ['default']={ "StretchStackGapAboveMin", "big_op_spacing2" },
+ },
+ ['under_delimiter_bgap']={
+ ['default']={ "StretchStackBottomShiftDown", "big_op_spacing4" },
+ },
+ ['radical_degree_before']={
+ ['default']={ "RadicalKernBeforeDegree", "(5/18)*quad" },
+ },
+ ['radical_degree_after']={
+ ['default']={ "RadicalKernAfterDegree", "(-10/18)*quad" },
+ },
+ ['radical_degree_raise']={
+ ['default']={ "RadicalDegreeBottomRaisePercent", "60" },
+ },
+}
+
+local styles = {
+ 'cramped_display_style',
+ 'cramped_script_script_style',
+ 'cramped_script_style',
+ 'cramped_text_style',
+ 'display_style',
+ 'script_script_style',
+ 'script_style',
+ 'text_style',
+}
+
+for k, v in next, defaults do
+ for _, s in next, styles do
+ if not v[s] then
+ v[s] = v.default
+ end
+ end
+end
+
+-- we cannot use a metatable because we do a copy (takes a bit more work)
+--
+-- local mt = { } setmetatable(defaults,mt)
+--
+-- mt.__index = function(t,s)
+-- texio.write_nl("GETTING " .. s)
+-- return t.default or t.text_style or 0
+-- end
+
+function mathematics.dimensions(dimens)
+ if dimens.SpaceAfterScript then
+ return { }, table.fastcopy(dimens)
+ elseif dimens.AxisHeight or dimens.axis_height then
+ local t = { }
+ local math_x_height = dimens.x_height or 10*65526
+ local math_quad = dimens.quad or 10*65526
+ local default_rule_thickness = dimens.FractionDenominatorGapMin or dimens.default_rule_thickness or 0.4*65526
+ dimens["0"] = 0
+ dimens["60"] = 60
+ dimens["0.25*default_rule_thickness"] = default_rule_thickness / 4
+ dimens["3*default_rule_thickness"] = 3 * default_rule_thickness
+ dimens["4*default_rule_thickness"] = 4 * default_rule_thickness
+ dimens["7*default_rule_thickness"] = 7 * default_rule_thickness
+ dimens["(5/18)*quad"] = (math_quad * 5) / 18
+ dimens["(-10/18)*quad"] = - (math_quad * 10) / 18
+ dimens["abs(math_x_height*4)/5"] = abs(math_x_height * 4) / 5
+ dimens["default_rule_thickness+(abs(default_rule_thickness)/4)"] = default_rule_thickness+(abs(default_rule_thickness) / 4)
+ dimens["default_rule_thickness+(abs(math_x_height)/4)"] = default_rule_thickness+(abs(math_x_height) / 4)
+ dimens["abs(math_x_height)/4"] = abs(math_x_height) / 4
+ dimens["abs(math_x_height*4)/5"] = abs(math_x_height * 4) / 5
+ dimens["<not set>"] = false
+ dimens["script_space"] = false -- at macro level
+ for variable, styles in next, defaults do
+ local tt = { }
+ for style, default in next, styles do
+ local one, two = default[1], default[2]
+ local value = dimens[one]
+ if value then
+ tt[style] = value
+ else
+ value = dimens[two]
+ if value == false then
+ tt[style] = nil
+ else
+ tt[style] = value or 0
+ end
+ end
+ end
+ t[variable] = tt
+ end
+ local d = {
+ AxisHeight = t . axis . text_style,
+ AccentBaseHeight = t . accent_base_height . text_style,
+ FractionDenominatorDisplayStyleGapMin = t . fraction_denom_vgap . display_style,
+ FractionDenominatorDisplayStyleShiftDown = t . fraction_denom_down . display_style,
+ FractionDenominatorGapMin = t . fraction_denom_vgap . text_style,
+ FractionDenominatorShiftDown = t . fraction_denom_down . text_style,
+ FractionNumeratorDisplayStyleGapMin = t . fraction_num_vgap . display_style,
+ FractionNumeratorDisplayStyleShiftUp = t . fraction_num_up . display_style,
+ FractionNumeratorGapMin = t . fraction_num_vgap . text_style,
+ FractionNumeratorShiftUp = t . fraction_num_up . text_style,
+ FractionRuleThickness = t . fraction_rule . text_style,
+ LowerLimitBaselineDropMin = t . limit_below_bgap . text_style,
+ LowerLimitGapMin = t . limit_below_vgap . text_style,
+ OverbarExtraAscender = t . overbar_kern . text_style,
+ OverbarRuleThickness = t . overbar_rule . text_style,
+ OverbarVerticalGap = t . overbar_vgap . text_style,
+ RadicalDisplayStyleVerticalGap = t . radical_vgap . display_style,
+ RadicalExtraAscender = t . radical_kern . text_style,
+ RadicalRuleThickness = t . radical_rule . text_style,
+ RadicalVerticalGap = t . radical_vgap . text_style,
+ RadicalKernBeforeDegree = t . radical_degree_before . display_style,
+ RadicalKernAfterDegree = t . radical_degree_after . display_style,
+ RadicalDegreeBottomRaisePercent = t . radical_degree_raise . display_style,
+ SpaceAfterScript = t . space_after_script . text_style,
+ StackBottomDisplayStyleShiftDown = t . stack_denom_down . display_style,
+ StackBottomShiftDown = t . stack_denom_down . text_style,
+ StackDisplayStyleGapMin = t . stack_vgap . display_style,
+ StackGapMin = t . stack_vgap . text_style,
+ StackTopDisplayStyleShiftUp = t . stack_num_up . display_style,
+ StackTopShiftUp = t . stack_num_up . text_style,
+ SubscriptBaselineDropMin = t . sub_shift_drop . text_style,
+ SubscriptShiftDown = t . sub_shift_down . text_style,
+ SubscriptTopMax = t . sub_top_max . text_style,
+ SubSuperscriptGapMin = t . subsup_vgap . text_style,
+ SuperscriptBaselineDropMax = t . sup_shift_drop . text_style,
+ SuperscriptBottomMaxWithSubscript = t . sup_sub_bottom_max . text_style,
+ SuperscriptBottomMin = t . sup_bottom_min . text_style,
+ SuperscriptShiftUp = t . sup_shift_up . text_style,
+ SuperscriptShiftUpCramped = t . sup_shift_up . cramped_text_style,
+ UnderbarExtraDescender = t . underbar_kern . text_style,
+ UnderbarRuleThickness = t . underbar_rule . text_style,
+ UnderbarVerticalGap = t . underbar_vgap . text_style,
+ UpperLimitBaselineRiseMin = t . limit_above_bgap . text_style,
+ UpperLimitGapMin = t . limit_above_vgap . text_style,
+ MinConnectorOverlap = t . connector_overlap_min . text_style,
+ StretchStackGapBelowMin = t . over_delimiter_vgap . text_style,
+ StretchStackTopShiftUp = t . over_delimiter_bgap . text_style,
+ StretchStackGapAboveMin = t . under_delimiter_vgap . text_style,
+ StretchStackBottomShiftDown = t . under_delimiter_bgap . text_style,
+ }
+ d.AccentBaseHeight = 0
+ -- texio.write_nl(table.serialize(d))
+ return t, d -- this might change
+ else
+ return { }, { }
+ end
+end
+
diff --git a/tex/context/base/math-dis.mkiv b/tex/context/base/math-dis.mkiv
new file mode 100644
index 000000000..3eed2b162
--- /dev/null
+++ b/tex/context/base/math-dis.mkiv
@@ -0,0 +1,20 @@
+%D \module
+%D [ file=math-ali,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Display,
+%D author={Hans Hagen, Taco Hoekwater \& Aditya Mahajan},
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Math Macros / Display}
+
+\unprotect
+
+% display spacing code will move here
+
+\protect \endinput
diff --git a/tex/context/base/math-ext.lua b/tex/context/base/math-ext.lua
new file mode 100644
index 000000000..52dce0255
--- /dev/null
+++ b/tex/context/base/math-ext.lua
@@ -0,0 +1,143 @@
+if not modules then modules = { } end modules ['math-ext'] = {
+ version = 1.001,
+ comment = "companion to math-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end)
+
+mathematics = mathematics or { }
+characters = characters or { }
+
+mathematics.extras = mathematics.extras or { }
+characters.math = characters.math or { }
+
+local chardata = characters.data
+local mathdata = characters.math
+
+function mathematics.extras.add(unicode,t)
+ local min, max = mathematics.extrabase, mathematics.privatebase - 1
+ if unicode >= min and unicode <= max then
+ mathdata[unicode], chardata[unicode] = t, t
+ else
+ logs.report("math extra","extra U+%04X should be in range U+%04X - U+%04X",unicode,min,max)
+ end
+end
+
+function mathematics.extras.copy(tfmdata)
+ local math_parameters = tfmdata.math_parameters
+ local MathConstants = tfmdata.MathConstants
+ if (math_parameters and next(math_parameters)) or (MathConstants and next(MathConstants)) then
+ local characters = tfmdata.characters
+ for unicode, extradesc in next, mathdata do
+ -- always, because in an intermediate step we can have a non math font
+ local extrachar = characters[unicode]
+ local nextinsize = extradesc.nextinsize
+ if nextinsize then
+ for i=1,#nextinsize do
+ local nextslot = nextinsize[i]
+ local nextbase = characters[nextslot]
+ if nextbase then
+ local nextnext = nextbase and nextbase.next
+ if nextnext then
+ local nextchar = characters[nextnext]
+ if nextchar then
+ if trace_virtual then
+ logs.report("math extra","extra U+%04X in %s at %s maps on U+%04X (class: %s, name: %s)",unicode,file.basename(tfmdata.fullname),tfmdata.size,nextslot,extradesc.mathclass or "?",extradesc.mathname or "?")
+ end
+ characters[unicode] = nextchar
+ break
+ end
+ end
+ end
+ end
+ if not characters[unicode] then
+ for i=1,#nextinsize do
+ local nextbase = characters[nextinsize[i]]
+ if nextbase then
+ characters[unicode] = nextchar
+ break
+ end
+ end
+ end
+ end
+ end
+ else
+ -- let's not waste time on non-math
+ end
+end
+
+table.insert(fonts.tfm.mathactions,mathematics.extras.copy)
+
+-- 0xFE302 -- 0xFE320 for accents
+
+mathematics.extras.add(0xFE302, {
+ category="mn",
+ description="WIDE MATHEMATICAL HAT",
+ direction="nsm",
+ linebreak="cm",
+ mathclass="accent",
+ mathname="widehat",
+ mathstretch="h",
+ unicodeslot=0xFE302,
+ nextinsize={ 0x00302, 0x0005E },
+} )
+
+mathematics.extras.add(0xFE303, {
+ category="mn",
+ cjkwd="a",
+ description="WIDE MATHEMATICAL TILDE",
+ direction="nsm",
+ linebreak="cm",
+ mathclass="accent",
+ mathname="widetilde",
+ mathstretch="h",
+ unicodeslot=0xFE303,
+ nextinsize={ 0x00303, 0x0007E },
+} )
+
+-- 0xFE321 -- 0xFE340 for missing characters
+
+-- mathematics.extras.add(0xFE321, {
+-- category="sm",
+-- description="SHORT BAR",
+-- -- direction="on",
+-- -- linebreak="nu",
+-- mathclass="relation",
+-- mathname="mapstochar",
+-- unicodeslot=0xFE321,
+-- } )
+
+
+
+
+
+--~ mathematics.extras.add(0xFE304, {
+--~ category="sm",
+--~ description="TOP AND BOTTOM PARENTHESES",
+--~ direction="on",
+--~ linebreak="al",
+--~ mathclass="doubleaccent",
+--~ mathname="doubleparent",
+--~ unicodeslot=0xFE304,
+--~ accents={ 0x023DC, 0x023DD },
+--~ } )
+
+--~ mathematics.extras.add(0xFE305, {
+--~ category="sm",
+--~ description="TOP AND BOTTOM BRACES",
+--~ direction="on",
+--~ linebreak="al",
+--~ mathclass="doubleaccent",
+--~ mathname="doublebrace",
+--~ unicodeslot=0xFE305,
+--~ accents={ 0x023DE, 0x023DF },
+--~ } )
+
+--~ \Umathchardef\braceld="0 "1 "FF07A
+--~ \Umathchardef\bracerd="0 "1 "FF07B
+--~ \Umathchardef\bracelu="0 "1 "FF07C
+--~ \Umathchardef\braceru="0 "1 "FF07D
+
diff --git a/tex/context/base/math-for.mkiv b/tex/context/base/math-for.mkiv
new file mode 100644
index 000000000..87aeaa4e0
--- /dev/null
+++ b/tex/context/base/math-for.mkiv
@@ -0,0 +1,73 @@
+%D \module
+%D [ file=strc-mat,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Math Numbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Math Formulas}
+
+%D This module only provides the code for defining formulas and
+%D fetching parameters. The action takes place later.
+
+\unprotect
+
+\let\currentformula\s!unknown
+
+\def\formulaparameter #1{\csname\doformulaparameter{\??fm\currentformula}#1\endcsname}
+\def\formulaparameterhash#1{\doformulaparameterhash {\??fm\currentformula}#1}
+
+\def\doformulaparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\doformulaparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\doformulaparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\doformulaparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\detokenizedformulaparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??fm\currentformula#1\endcsname}}
+
+\def\doformulaparentparameter #1#2{\ifx#1\relax\s!empty\else\doformulaparameter #1#2\fi}
+\def\doformulaparentparameterhash#1#2{\ifx#1\relax \else\doformulaparameterhash#1#2\fi}
+
+\def\dosetformulaattributes#1#2% style color
+ {\edef\fontattributehash {\formulaparameterhash#1}%
+ \edef\colorattributehash{\formulaparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+%D \macros
+%D {setupformulas}
+
+\newtoks \everysetupformulas
+
+\def\setupformulas
+ {\dodoubleempty\dosetupformulas}
+
+\def\dosetupformulas[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??fm#1][#2]%
+ \else
+ \getparameters[\??fm][#1]%
+ \fi
+ \the\everysetupformulas}
+
+%D Not yet cleanup up:
+
+%D \macros
+%D {setuptextformulas}
+%D
+%D This command sets up in||line math. Most features deals
+%D with grid snapping and are experimental.
+
+\newtoks \everysetuptextformulas
+
+\def\setuptextformulas
+ {\dosingleempty\dosetuptextformulas}
+
+\def\dosetuptextformulas[#1]%
+ {\getparameters[\??mt][#1]%
+ \the\everysetuptextformulas}
+
+\protect \endinput
diff --git a/tex/context/base/math-frc.mkii b/tex/context/base/math-frc.mkii
new file mode 100644
index 000000000..fa319bc4a
--- /dev/null
+++ b/tex/context/base/math-frc.mkii
@@ -0,0 +1,66 @@
+%D \module
+%D [ file=math-frc,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Fractions,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Fractions}
+
+\unprotect
+
+\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+
+\def\domthfrac#1#2#3#4#5#6#7%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #6$}%
+ \setbox2\hbox{$#1 #7$}%
+ \dimen0\wd0
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{\exmthfont#2#3\leaders\hbox{#4}\hss#5}%
+ \mathord{\vcenter{{\offinterlineskip
+ \hbox to \dimen0{\hss\box0\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\copy4\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\box2\hss}}}}%
+ \endgroup}
+
+\def\domthsqrt#1#2#3#4#5%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #5$}%
+ \dimen0=1.05\ht0 \advance\dimen0 1pt \ht0 \dimen0
+ \dimen0=1.05\dp0 \advance\dimen0 1pt \dp0 \dimen0
+ \dimen0\wd0
+ \setbox4\hbox to \dimen0{\exmthfont#2\leaders\hbox{#3}\hfill#4}%
+ \delimitershortfall=0pt
+ \nulldelimiterspace=0pt
+ \setbox2\hbox{$\left\delimiter"0270370 \vrule height\ht0 depth \dp0 width0pt
+ \right.$}%
+ \mathord{\vcenter{\hbox{\copy2
+ \rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
+ \endgroup}
+
+\def\mthfrac#1#2#3#4#5{\mathchoice
+ {\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
+
+\def\mthsqrt#1#2#3{\mathchoice
+ {\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\textstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
+
+% temp here
+
+\protect \endinput
diff --git a/tex/context/base/math-frc.mkiv b/tex/context/base/math-frc.mkiv
new file mode 100644
index 000000000..d40306199
--- /dev/null
+++ b/tex/context/base/math-frc.mkiv
@@ -0,0 +1,209 @@
+%D \module
+%D [ file=math-frc,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Fractions,
+%D author={Hans Hagen \& Taco Hoekwater},
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Fractions}
+
+\unprotect
+
+%D \macros
+%D {frac, xfrac, xxfrac}
+%D
+%D This is another one Tobias asked for. It replaces the
+%D primitive \type {\over}. We also take the opportunity to
+%D handle math style restoring, which makes sure units and
+%D chemicals come out ok.
+%D The \type {\frac} macro kind of replaces the awkward \type
+%D {\over} primitive. Say that we have the following formulas:
+%D
+%D \startbuffer[sample]
+%D test $\frac {1}{2}$ test $$1 + \frac {1}{2} = 1.5$$
+%D test $\xfrac {1}{2}$ test $$1 + \xfrac {1}{2} = 1.5$$
+%D test $\xxfrac{1}{2}$ test $$1 + \xxfrac{1}{2} = 1.5$$
+%D \stopbuffer
+%D
+%D \typebuffer[sample]
+%D
+%D With the most straightforward definitions, we get:
+%D
+%D \startbuffer[code]
+%D \def\dofrac#1#2#3{\relax\mathematics{{{#1{#2}}\over{#1{#3}}}}}
+%D
+%D \def\frac {\dofrac\mathstyle}
+%D \def\xfrac {\dofrac\scriptstyle}
+%D \def\xxfrac{\dofrac\scriptscriptstyle}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D Since this does not work well, we can try:
+%D
+%D \startbuffer[code]
+%D \def\xfrac #1#2{\hbox{$\dofrac\scriptstyle {#1}{#2}$}}
+%D \def\xxfrac#1#2{\hbox{$\dofrac\scriptscriptstyle{#1}{#2}$}}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D This for sure looks better than:
+%D
+%D \startbuffer[code]
+%D \def\xfrac #1#2{{\scriptstyle \dofrac\relax{#1}{#2}}}
+%D \def\xxfrac#1#2{{\scriptscriptstyle\dofrac\relax{#1}{#2}}}
+%D \stopbuffer
+%D
+%D \typebuffer[code] \getbuffer[code,sample]
+%D
+%D So we stick to the next definitions (watch the local
+%D overloading of \type {\xfrac}).
+
+% \def\dofrac#1#2#3{\relax\mathematics{{{#1{#2}}\over{#1{#3}}}}}
+
+\def\dofrac#1#2#3{\relax\mathematics{\Ustack{{#1{#2}}\normalover{#1{#3}}}}}
+\def\nofrac #1#2{\relax\mathematics{\Ustack{{#1}\normalover{#2}}}}
+
+% \chardef\mathfracmode=0 $\frac{1}{2}$
+% \chardef\mathfracmode=1 $\frac{1}{2}$
+% \chardef\mathfracmode=2 $\frac{1}{2}$
+% \chardef\mathfracmode=3 $\frac{1}{2}$
+% \chardef\mathfracmode=4 $\frac{1}{2}$
+% \chardef\mathfracmode=5 $\frac{1}{2}$
+
+\chardef\mathfracmode=0 % 0=auto, 1=displaystyle, 2=textstyle, 3=scriptstyle, 4=scriptscriptstyle, 5=mathstyle
+
+\unexpanded\def\frac
+ {\ifcase\mathfracmode
+ \expandafter\nofrac
+ \or
+ \expandafter\dofrac\expandafter\displaystyle
+ \or
+ \expandafter\dofrac\expandafter\textstyle
+ \or
+ \expandafter\dofrac\expandafter\scriptstyle
+ \or
+ \expandafter\dofrac\expandafter\scriptscriptstyle
+ \else
+ \expandafter\dofrac\expandafter\mathstyle
+ \fi}
+
+\unexpanded\def\xfrac#1#2%
+ {\begingroup
+ \let\xfrac\xxfrac
+ \dofrac\scriptstyle{#1}{#2}%
+ \endgroup}
+
+\unexpanded\def\xxfrac#1#2%
+ {\begingroup
+ \dofrac\scriptscriptstyle{#1}{#2}%
+ \endgroup}
+
+%D The \type {xx} variant looks still ugly, so maybe it's
+%D best to say:
+
+\unexpanded\def\xxfrac#1#2%
+ {\begingroup
+ \dofrac\scriptscriptstyle{#1}{\raise.25ex\hbox{$\scriptscriptstyle#2$}}%
+ \endgroup}
+
+%D Something low level for scientific calculator notation:
+
+\unexpanded\def\scinot#1#2%
+ {#1\times10^{#2}}
+
+%D The next macro, \type {\ch}, is \PPCHTEX\ aware. In
+%D formulas one can therefore best use \type {\ch} instead of
+%D \type {\chemical}, especially in fractions.
+
+% let's see who complains ... \mathstyle is now a primitive
+%
+% \unexpanded\def\ch#1%
+% {\ifundefined\@@chemicalletter
+% \mathstyle{\rm#1}%
+% \else
+% \dosetsubscripts
+% \mathstyle{\@@chemicalletter{#1}}%
+% \doresetsubscripts
+% \fi}
+
+% \unexpanded\def\ch#1%
+% {\ifundefined\@@chemicalletter
+% \mathematics{\rm#1}%
+% \else
+% \dosetsubscripts
+% \mathematics{\@@chemicalletter{#1}}%
+% \doresetsubscripts
+% \fi}
+
+%D \macros
+%D {/}
+%D
+%D Just to be sure, we restore the behavior of some typical
+%D math characters.
+
+\bgroup
+
+\catcode`\/=\@@other \global \let\normalforwardslash/
+\catcode`\/=\@@active \doglobal\appendtoks\let/\normalforwardslash\to\everymathematics
+
+\egroup
+
+% to be checked:
+
+\def\exmthfont#1{\symbolicsizedfont#1\plusone{MathExtension}}
+
+\def\domthfrac#1#2#3#4#5#6#7%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #6$}%
+ \setbox2\hbox{$#1 #7$}%
+ \dimen0\wd0
+ \ifdim\wd2>\dimen0 \dimen0\wd2 \fi
+ \setbox4\hbox to \dimen0{\exmthfont#2#3\leaders\hbox{#4}\hss#5}%
+ \mathord{\vcenter{{\offinterlineskip
+ \hbox to \dimen0{\hss\box0\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\copy4\hss}%
+ \kern \ht4%
+ \hbox to \dimen0{\hss\box2\hss}}}}%
+ \endgroup}
+
+\def\domthsqrt#1#2#3#4#5%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox0\hbox{$#1 #5$}%
+ \dimen0=1.05\ht0 \advance\dimen0 1pt \ht0 \dimen0
+ \dimen0=1.05\dp0 \advance\dimen0 1pt \dp0 \dimen0
+ \dimen0\wd0
+ \setbox4\hbox to \dimen0{\exmthfont#2\leaders\hbox{#3}\hfill#4}%
+ \delimitershortfall=0pt
+ \nulldelimiterspace=0pt
+ \setbox2\hbox{$\left\delimiter"0270370 \vrule height\ht0 depth \dp0 width0pt
+ \right.$}%
+ \mathord{\vcenter{\hbox{\copy2
+ \rlap{\raise\dimexpr\ht2-\ht4\relax\copy4}\copy0}}}%
+ \endgroup}
+
+\def\mthfrac#1#2#3#4#5{\mathchoice
+ {\domthfrac\displaystyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\textstyle \textface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptstyle \scriptface {#1}{#2}{#3}{#4}{#5}}
+ {\domthfrac\scriptscriptstyle\scriptscriptface{#1}{#2}{#3}{#4}{#5}}}
+
+\def\mthsqrt#1#2#3{\mathchoice
+ {\domthsqrt\displaystyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\textstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptstyle \textface {#1}{#2}{#3}}
+ {\domthsqrt\scriptscriptstyle\textface {#1}{#2}{#3}}}
+
+% temp here
+
+\protect \endinput
diff --git a/tex/context/base/math-ini.lua b/tex/context/base/math-ini.lua
index 73b8852b3..5a6889410 100644
--- a/tex/context/base/math-ini.lua
+++ b/tex/context/base/math-ini.lua
@@ -1,4 +1,4 @@
-if not modules then modules = { } end modules ['math-ini'] = {
+if not modules then modules = { } end modules ['math-ext'] = {
version = 1.001,
comment = "companion to math-ini.tex",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
@@ -6,443 +6,249 @@ if not modules then modules = { } end modules ['math-ini'] = {
license = "see context related readme files"
}
---[[ldx--
-<p>Math definitions. This code may move.</p>
---ldx]]--
-
-- if needed we can use the info here to set up xetex definition files
-- the "8000 hackery influences direct characters (utf) as indirect \char's
+local utf = unicode.utf8
+
local texsprint, format, utfchar, utfbyte = tex.sprint, string.format, utf.char, utf.byte
-mathematics = mathematics or { }
-mathematics.data = mathematics.data or { }
-mathematics.slots = mathematics.slots or { }
+local trace_defining = false trackers.register("math.defining", function(v) trace_defining = v end)
-mathematics.classes = {
- ord = 0, -- mathordcomm mathord
- op = 1, -- mathopcomm mathop
- bin = 2, -- mathbincomm mathbin
- rel = 3, -- mathrelcomm mathrel
- open = 4, -- mathopencomm mathopen
- close = 5, -- mathclosecomm mathclose
- punct = 6, -- mathpunctcomm mathpunct
- alpha = 7, -- mathalphacomm firstofoneargument
- accent = 8,
- radical = 9,
- inner = 0, -- mathinnercomm mathinner
- nothing = 0, -- mathnothingcomm firstofoneargument
- choice = 0, -- mathchoicecomm @@mathchoicecomm
- box = 0, -- mathboxcomm @@mathboxcomm
- limop = 1, -- mathlimopcomm @@mathlimopcomm
- nolop = 1, -- mathnolopcomm @@mathnolopcomm
-}
+mathematics = mathematics or { }
-mathematics.classes.alphabetic = mathematics.classes.alpha
-mathematics.classes.unknown = mathematics.classes.nothing
-mathematics.classes.punctuation = mathematics.classes.punct
-mathematics.classes.normal = mathematics.classes.nothing
-mathematics.classes.opening = mathematics.classes.open
-mathematics.classes.closing = mathematics.classes.close
-mathematics.classes.binary = mathematics.classes.bin
-mathematics.classes.relation = mathematics.classes.rel
-mathematics.classes.fence = mathematics.classes.unknown
-mathematics.classes.diacritic = mathematics.classes.accent
-mathematics.classes.large = mathematics.classes.op
-mathematics.classes.variable = mathematics.classes.alphabetic
-mathematics.classes.number = mathematics.classes.nothing
+mathematics.extrabase = 0xFE000 -- here we push some virtuals
+mathematics.privatebase = 0xFF000 -- here we push the ex
-mathematics.families = {
- mr = 0, bs = 8,
- mi = 1, bi = 9,
- sy = 2, sc = 10,
- ex = 3, tf = 11,
- it = 4, ma = 12,
- sl = 5, mb = 13,
- bf = 6, mc = 14,
- nn = 7, md = 15,
+local families = {
+ tf = 0, it = 1, sl = 2, bf = 3, bi = 4, bs = 5, -- virtual fonts or unicode otf
}
-mathematics.families.letters = mathematics.families.mr
-mathematics.families.numbers = mathematics.families.mr
-mathematics.families.variables = mathematics.families.mi
-mathematics.families.operators = mathematics.families.sy
-mathematics.families.lcgreek = mathematics.families.mi
-mathematics.families.ucgreek = mathematics.families.mr
-mathematics.families.vargreek = mathematics.families.mi
-mathematics.families.mitfamily = mathematics.families.mi
-mathematics.families.calfamily = mathematics.families.sy
-
-mathematics.families[0] = mathematics.families.mr
-mathematics.families[1] = mathematics.families.mi
-mathematics.families[2] = mathematics.families.sy
-mathematics.families[3] = mathematics.families.ex
+local classes = {
+ ord = 0, -- mathordcomm mathord
+ op = 1, -- mathopcomm mathop
+ bin = 2, -- mathbincomm mathbin
+ rel = 3, -- mathrelcomm mathrel
+ open = 4, -- mathopencomm mathopen
+ close = 5, -- mathclosecomm mathclose
+ punct = 6, -- mathpunctcomm mathpunct
+ alpha = 7, -- mathalphacomm firstofoneargument
+ accent = 8, -- class 0
+ radical = 9,
+ xaccent = 10, -- class 3
+ topaccent = 11, -- class 0
+ botaccent = 12, -- class 0
+ under = 13,
+ over = 14,
+ delimiter = 15,
+ inner = 0, -- mathinnercomm mathinner
+ nothing = 0, -- mathnothingcomm firstofoneargument
+ choice = 0, -- mathchoicecomm @@mathchoicecomm
+ box = 0, -- mathboxcomm @@mathboxcomm
+ limop = 1, -- mathlimopcomm @@mathlimopcomm
+ nolop = 1, -- mathnolopcomm @@mathnolopcomm
+}
-function mathematics.mathcode(target,class,family,slot)
- if class <= 7 then
- return ("\\omathcode%s=\"%X%02X%04X "):format(target,class,family,slot)
- end
+mathematics.families = families
+mathematics.classes = classes
+
+classes.alphabetic = classes.alpha
+classes.unknown = classes.nothing
+classes.default = classes.nothing
+classes.punctuation = classes.punct
+classes.normal = classes.nothing
+classes.opening = classes.open
+classes.closing = classes.close
+classes.binary = classes.bin
+classes.relation = classes.rel
+classes.fence = classes.unknown
+classes.diacritic = classes.accent
+classes.large = classes.op
+classes.variable = classes.alphabetic
+classes.number = classes.alphabetic
+
+-- there will be proper functions soon (and we will move this code in-line)
+
+local function delcode(target,family,slot)
+ return format('\\Udelcode%s="%X "%X ',target,family,slot)
+end
+local function mathchar(class,family,slot)
+ return format('\\Umathchar "%X "%X "%X ',class,family,slot)
+end
+local function mathaccent(class,family,slot)
+ return format('\\Umathaccent "%X "%X "%X ',0,family,slot) -- no class
+end
+local function delimiter(class,family,slot)
+ return format('\\Udelimiter "%X "%X "%X ',class,family,slot)
end
-function mathematics.delcode(target,small_family,small_slot,large_family,large_slot)
- return ("\\odelcode%s=\"%02X%04X\"%02X%04X "):format(target,small_family,small_slot,large_family,large_slot)
+local function radical(family,slot)
+ return format('\\Uradical "%X "%X ',family,slot)
end
-function mathematics.radical(small_family,small_slot,large_family,large_slot)
- return ("\\radical%s=\"%02X%04X%\"02X%04X "):format(target,small_family,small_slot,large_family,large_slot)
+local function mathchardef(name,class,family,slot)
+ return format('\\Umathchardef\\%s "%X "%X "%X ',name,class,family,slot)
end
-function mathematics.mathchar(class,family,slot)
- return ("\\omathchar\"%X%02X%04X "):format(class,family,slot)
+local function mathcode(target,class,family,slot)
+ return format('\\Umathcode%s="%X "%X "%X ',target,class,family,slot)
end
-function mathematics.mathaccent(class,family,slot)
- return ("\\omathaccent\"%X%02X%04X "):format(class,family,slot)
+local function mathtopaccent(class,family,slot)
+ return format('\\Umathaccent "%X "%X "%X ',0,family,slot) -- no class
end
-function mathematics.delimiter(class,family,slot,largefamily,largeslot)
- return ("\\odelimiter\"%X%02X%04X\"%02X%04X "):format(class,family,slot,largefamily,largeslot)
+local function mathbotaccent(class,family,slot)
+ return format('\\Umathbotaccent "%X "%X "%X ',0,family,slot) -- no class
end
-function mathematics.mathchardef(name,class,family,slot) -- we can avoid this one
- return ("\\omathchardef\\%s\"%X%02X%04X "):format(name,class,family,slot)
+local function mathtopdelimiter(class,family,slot)
+ return format('\\Uoverdelimiter "%X "%X ',0,family,slot) -- no class
+end
+local function mathbotdelimiter(class,family,slot)
+ return format('\\Uunderdelimiter "%X "%X ',0,family,slot) -- no class
end
-function mathematics.setmathsymbol(name,class,family,slot,largefamily,largeslot,unicode)
- class = mathematics.classes[class] or class -- no real checks needed
- family = mathematics.families[family] or family
- -- \unexpanded ? \relax needed for the codes?
- local classes = mathematics.classes
- if largefamily and largeslot then
- largefamily = mathematics.families[largefamily] or largefamily
- if class == classes.radical then
- texsprint(("\\unexpanded\\xdef\\%s{%s }"):format(name,mathematics.radical(class,family,slot,largefamily,largeslot)))
- elseif class == classes.open or class == classes.close then
- texsprint(("\\unexpanded\\xdef\\%s{%s}"):format(name,mathematics.delimiter(class,family,slot,largefamily,largeslot)))
- end
- elseif class == classes.accent then
- texsprint(("\\unexpanded\\xdef\\%s{%s }"):format(name,mathematics.mathaccent(class,family,slot)))
- elseif unicode then
- -- beware, open/close and other specials should not end up here
- local ch = utfchar(unicode)
- if characters.filters.utf.private.escapes[ch] then
- texsprint(("\\xdef\\%s{\\char%s }"):format(name,unicode))
- else
- texsprint(("\\xdef\\%s{%s}"):format(name,ch))
- end
+local escapes = characters.filters.utf.private.escapes
+
+local function setmathsymbol(name,class,family,slot)
+ if class == classes.accent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathaccent(class,family,slot)))
+ elseif class == classes.topaccent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathtopaccent(class,family,slot)))
+ elseif class == classes.botaccent then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathbotaccent(class,family,slot)))
+ elseif class == classes.over then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathtopdelimiter(class,family,slot)))
+ elseif class == classes.under then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathbotdelimiter(class,family,slot)))
+ elseif class == classes.open or class == classes.close then
+ texsprint(delcode(slot,family,slot))
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,delimiter(class,family,slot)))
+ elseif class == classes.delimiter then
+ texsprint(delcode(slot,family,slot))
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,delimiter(0,family,slot)))
+ elseif class == classes.radical then
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,radical(family,slot)))
else
- texsprint(mathematics.mathchardef(name,class,family,slot))
+ -- beware, open/close and other specials should not end up here
+--~ local ch = utfchar(slot)
+--~ if escapes[ch] then
+--~ texsprint(format("\\xdef\\%s{\\char%s }",name,slot))
+--~ else
+ texsprint(format("\\unexpanded\\xdef\\%s{%s}",name,mathchar(class,family,slot)))
+--~ end
end
end
--- direct sub call
-
-function mathematics.setmathcharacter(target,class,family,slot,largefamily,largeslot)
- class = mathematics.classes[class] or class -- no real checks needed
- family = mathematics.families[family] or family
- if largefamily and largeslot then
- largefamily = mathematics.families[largefamily] or largefamily
- texsprint(mathematics.delcode(target,family,slot,largefamily,largeslot))
- else
- texsprint(mathematics.mathcode(target,class,family,slot))
+local function setmathcharacter(class,family,slot,unicode,firsttime)
+ if not firsttime and class <= 7 then
+ texsprint(mathcode(slot,class,family,unicode or slot))
end
end
--- definitions (todo: expand commands to utf instead of codes)
-
-mathematics.trace = false -- false
+local function setmathsynonym(class,family,slot,unicode,firsttime)
+ if not firsttime and class <= 7 then
+ texsprint(mathcode(slot,class,family,unicode))
+ end
+ if class == classes.open or class == classes.close then
+ texsprint(delcode(slot,family,unicode))
+ end
+end
-function mathematics.define(slots)
- local slots = slots or mathematics.slots.current
- local setmathcharacter = mathematics.setmathcharacter
- local setmathsymbol = mathematics.setmathsymbol
- local trace = mathematics.trace
- local function report(k,m,c,f,i,fe,ie)
- local mc = mathematics.classes[m] or m
- if fe then
- logs.report("mathematics","a - %s:%s 0x%05X -> %s -> %s %s (%s %s) -> %s",mc,m,k,c,f,i,fe,ie,utfchar(k))
- elseif c then
- logs.report("mathematics","b - %s:%s 0x%05X -> %s -> %s %s -> %s",mc,m,k,c,f,i,utfchar(k))
- else
- logs.report("mathematics","c - %s:%s 0x%05X -> %s %s -> %s",mc,m,k,f,i,utfchar(k))
- end
+local function report(class,family,unicode,name)
+ local nametype = type(name)
+ if nametype == "string" then
+ logs.report("mathematics","%s:%s %s U+%05X (%s) => %s",classname,class,family,unicode,utfchar(unicode),name)
+ elseif nametype == "number" then
+ logs.report("mathematics","%s:%s %s U+%05X (%s) => U+%05X",classname,class,family,unicode,utfchar(unicode),name)
+ else
+ logs.report("mathematics","%s:%s %s U+%05X (%s)", classname,class,family,unicode,utfchar(unicode))
end
- for k,v in pairs(characters.data) do
- local m = v.mathclass
- -- i need to clean this up a bit
- if m then
- local c = v.mathname
- if c == false then
- -- no command
- local s = slots[k]
- if s then
- local f, i, fe, ie = s[1], s[2], s[3], s[4]
- if trace then
- report(k,m,c,f,i,fe,ie)
- end
- setmathcharacter(k,m,f,i,fe,ie)
+end
+
+-- there will be a combined \(math)chardef
+
+function mathematics.define(slots,family)
+ family = family or 0
+ family = families[family] or family
+ local data = characters.data
+ for unicode, character in next, data do
+ local symbol = character.mathsymbol
+ if symbol then
+ local other = data[symbol]
+ local class = other.mathclass
+ if class then
+ class = classes[class] or class -- no real checks needed
+ if trace_defining then
+ report(class,family,unicode,symbol)
end
- elseif c then
- local s = slots[k]
- if s then
- local f, i, fe, ie = s[1], s[2], s[3], s[4]
- if trace then
- report(k,m,c,f,i,fe,ie)
+ setmathsynonym(class,family,unicode,symbol)
+ end
+ local spec = other.mathspec
+ if spec then
+ for i, m in next, spec do
+ local class = m.class
+ if class then
+ class = classes[class] or class -- no real checks needed
+ setmathsynonym(class,family,unicode,symbol,i)
end
- setmathsymbol(c,m,f,i,fe,ie,k)
- setmathcharacter(k,m,f,i,fe,ie)
end
- elseif v.contextname then
- local s = slots[k]
- local c = v.contextname
- if s then
- local f, i, fe, ie = s[1], s[2], s[3], s[4]
- if trace then
- report(k,m,c,f,i,fe,ie)
+ end
+ end
+ local mathclass = character.mathclass
+ local mathspec = character.mathspec
+ if mathspec then
+ for i, m in next, mathspec do
+ local name = m.name
+ local class = m.class
+ if not class then
+ class = mathclass
+ elseif not mathclass then
+ mathclass = class
+ end
+ if class then
+ class = classes[class] or class -- no real checks needed
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ setmathsymbol(name,class,family,unicode)
+ -- setmathcharacter(class,family,unicode,unicode,i)
+ else
+ name = class == classes.variable or class == classes.number and character.adobename
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ -- setmathcharacter(class,family,unicode,unicode,i)
+ end
end
- -- todo: mathortext
- setmathsymbol(c,m,f,i,fe,ie,k)
- setmathcharacter(k,m,f,i,fe,ie)
+ setmathcharacter(class,family,unicode,unicode,i)
end
+ end
+ end
+ if mathclass then
+ local name = character.mathname
+ local class = classes[mathclass] or mathclass -- no real checks needed
+ if name == false then
+ if trace_defining then
+ report(class,family,unicode,name)
+ end
+ setmathcharacter(class,family,unicode)
else
- local a = v.adobename
- if a and m then
- local s, f, i, fe, ie = slots[k], nil, nil, nil, nil
- if s then
- f, i, fe, ie = s[1], s[2], s[3], s[4]
- elseif m == "variable" then
- f, i = mathematics.families.variables, k
- elseif m == "number" then
- f, i = mathematics.families.numbers, k
+ name = name or character.contextname
+ if name then
+ if trace_defining then
+ report(class,family,unicode,name)
end
- if f and i then
- if trace then
- report(k,m,a,f,i,fe,ie)
- end
- setmathcharacter(k,m,f,i,fe,ie)
+ setmathsymbol(name,class,family,unicode)
+ else
+ if trace_defining then
+ report(class,family,unicode,character.adobename)
end
end
+ setmathcharacter(class,family,unicode,unicode)
end
end
end
end
--- temporary here: will become separate
-
--- maybe we should define a nice virtual font so that we have
--- just the base n families repeated for different styles
-
-mathematics.slots.traditional = {
-
- [0x03B1] = { "lcgreek", 0x0B }, -- alpha
- [0x03B2] = { "lcgreek", 0x0C }, -- beta
- [0x03B3] = { "lcgreek", 0x0D }, -- gamma
- [0x03B4] = { "lcgreek", 0x0E }, -- delta
- [0x03B5] = { "lcgreek", 0x0F }, -- epsilon
- [0x03B6] = { "lcgreek", 0x10 }, -- zeta
- [0x03B7] = { "lcgreek", 0x11 }, -- eta
- [0x03B8] = { "lcgreek", 0x12 }, -- theta
- [0x03B9] = { "lcgreek", 0x13 }, -- iota
- [0x03BA] = { "lcgreek", 0x14 }, -- kappa
- [0x03BB] = { "lcgreek", 0x15 }, -- lambda
- [0x03BC] = { "lcgreek", 0x16 }, -- mu
- [0x03BD] = { "lcgreek", 0x17 }, -- nu
- [0x03BE] = { "lcgreek", 0x18 }, -- xi
- [0x03BF] = { "lcgreek", 0x6F }, -- omicron
- [0x03C0] = { "lcgreek", 0x19 }, -- pi
- [0x03C1] = { "lcgreek", 0x1A }, -- rho
--- [0x03C2] = { "lcgreek", 0x00 }, -- varsigma
- [0x03C3] = { "lcgreek", 0x1B }, -- sigma
- [0x03C4] = { "lcgreek", 0x1C }, -- tau
- [0x03C5] = { "lcgreek", 0x1D }, -- upsilon
--- [0x03C6] = { "lcgreek", 0x1E }, -- varphi
- [0x03C7] = { "lcgreek", 0x1F }, -- chi
- [0x03C8] = { "lcgreek", 0x20 }, -- psi
- [0x03C9] = { "lcgreek", 0x21 }, -- omega
-
- [0x0391] = { "ucgreek", 0x41 }, -- Alpha
- [0x0392] = { "ucgreek", 0x42 }, -- Beta
- [0x0393] = { "ucgreek", 0x00 }, -- Gamma
- [0x0394] = { "ucgreek", 0x01 }, -- Delta
- [0x0395] = { "ucgreek", 0x45 }, -- Epsilon
- [0x0396] = { "ucgreek", 0x5A }, -- Zeta
- [0x0397] = { "ucgreek", 0x48 }, -- Eta
- [0x0398] = { "ucgreek", 0x02 }, -- Theta
- [0x0399] = { "ucgreek", 0x49 }, -- Iota
- [0x039A] = { "ucgreek", 0x4B }, -- Kappa
- [0x039B] = { "ucgreek", 0x03 }, -- Lambda
- [0x039C] = { "ucgreek", 0x4D }, -- Mu
- [0x039D] = { "ucgreek", 0x4E }, -- Nu
- [0x039E] = { "ucgreek", 0x04 }, -- Xi
- [0x039F] = { "ucgreek", 0x4F }, -- Omicron
- [0x03A0] = { "ucgreek", 0x05 }, -- Pi
- [0x03A1] = { "ucgreek", 0x52 }, -- Rho
- [0x03A3] = { "ucgreek", 0x06 }, -- Sigma
- [0x03A4] = { "ucgreek", 0x54 }, -- Tau
- [0x03A5] = { "ucgreek", 0x07 }, -- Upsilon
- [0x03A6] = { "ucgreek", 0x08 }, -- Phi
- [0x03A7] = { "ucgreek", 0x58 }, -- Chi
- [0x03A8] = { "ucgreek", 0x09 }, -- Psi
- [0x03A9] = { "ucgreek", 0x0A }, -- Omega
-
- [0x03F5] = { "vargreek", 0x22 }, -- varepsilon
- [0x03D1] = { "vargreek", 0x23 }, -- vartheta
- [0x03D6] = { "vargreek", 0x24 }, -- varpi
- [0x03F1] = { "vargreek", 0x25 }, -- varrho
- [0x03C2] = { "vargreek", 0x26 }, -- varsigma
-
- -- varphi is part of the alphabet, contrary to the other var*s'
-
- [0x03C6] = { "vargreek", 0x27 }, -- varphi
- [0x03D5] = { "lcgreek", 0x1E }, -- phi
-
- [0x03F0] = { "lcgreek", 0x14 }, -- varkappa, not in tex fonts
-
- [0x0021] = { "mr", 0x21 }, -- !
- [0x0028] = { "mr", 0x28 }, -- (
- [0x0029] = { "mr", 0x29 }, -- )
- [0x002A] = { "sy", 0x03 }, -- *
- [0x002B] = { "mr", 0x2B }, -- +
- [0x002C] = { "mi", 0x3B }, -- ,
- [0x002D] = { "sy", 0x00 }, -- -
- [0x2212] = { "sy", 0x00 }, -- -
- [0x002E] = { "mi", 0x3A }, -- .
- [0x002F] = { "mi", 0x3D }, -- /
- [0x003A] = { "mr", 0x3A }, -- :
- [0x003B] = { "mr", 0x3B }, -- ;
- [0x003C] = { "mi", 0x3C }, -- <
- [0x003D] = { "mr", 0x3D }, -- =
- [0x003E] = { "mi", 0x3E }, -- >
- [0x003F] = { "mr", 0x3F }, -- ?
- [0x005C] = { "sy", 0x6E }, -- \
- [0x007B] = { "sy", 0x66 }, -- {
- [0x007C] = { "sy", 0x6A }, -- |
- [0x007D] = { "sy", 0x67 }, -- }
- [0x00AC] = { "sy", 0x3A }, -- lnot
- [0x00B1] = { "sy", 0x06 }, -- pm
- [0x00B7] = { "sy", 0x01 }, -- cdot
- [0x00D7] = { "sy", 0x02 }, -- times
- [0x00F7] = { "sy", 0x04 }, -- div
- [0x2022] = { "sy", 0x0F }, -- bullet
- [0x2111] = { "sy", 0x3D }, -- Im
- [0x2118] = { "mi", 0x7D }, -- wp
- [0x211C] = { "sy", 0x3C }, -- Re
- [0x2190] = { "sy", 0x20 }, -- leftarrow
- [0x2191] = { "sy", 0x22, "ex", 0x78 }, -- uparrow
- [0x2192] = { "sy", 0x21 }, -- rightarrow
- [0x2193] = { "sy", 0x23, "ex", 0x79 }, -- downarrow
- [0x2194] = { "sy", 0x24 }, -- leftrightarrow
- [0x2195] = { "sy", 0x6C, "ex", 0x3F }, -- updownarrow
- [0x2196] = { "sy", 0x2D }, -- nwarrow
- [0x2197] = { "sy", 0x25 }, -- nearrow
- [0x2198] = { "sy", 0x2E }, -- swarrow
- [0x2199] = { "sy", 0x26 }, -- searrow
- [0x21D0] = { "sy", 0x28 }, -- Leftarrow
- [0x21D1] = { "sy", 0x6C, "ex", 0x7E }, -- Uparrow
- [0x21D2] = { "sy", 0x29 }, -- Rightarrow
- [0x21D3] = { "sy", 0x2B, "ex", 0x7F }, -- Downarrow
- [0x21D4] = { "sy", 0x2C }, -- Leftrightarrow
- [0x21D5] = { "sy", 0x6D, "ex", 0x77 }, -- Updownarrow
- [0x2135] = { "sy", 0x40 }, -- aleph
- [0x2113] = { "mi", 0x60 }, -- ell
--- ...
- [0x2200] = { "sy", 0x38 }, -- forall
--- [0x2201] = { "sy", 0x00 }, -- complement
- [0x2202] = { "mi", 0x40 }, -- partial
- [0x2203] = { "sy", 0x39 }, -- exists
--- [0x2204] = { "sy", 0x00 }, -- not exists
- [0x2205] = { "sy", 0x3B }, -- empty set
--- [0x2206] = { "sy", 0x00 }, -- increment
- [0x2207] = { "sy", 0x72 }, -- nabla
- [0x2208] = { "sy", 0x32 }, -- in
- [0x2209] = { "sy", 0x33 }, -- ni
- [0x220F] = { "ex", 0x51 }, -- prod
- [0x2210] = { "ex", 0x60 }, -- coprod
- [0x2211] = { "ex", 0x50 }, -- sum
--- [0x2212] = { "sy", 0x00 }, -- -
- [0x2213] = { "sy", 0x07 }, -- mp
- [0x2215] = { "sy", 0x3D }, -- / AM: Not sure
- [0x2216] = { "sy", 0x6E }, -- setminus
- [0x2217] = { "sy", 0x03 }, -- *
- [0x2218] = { "sy", 0x0E }, -- circ
- [0x2219] = { "sy", 0x0F }, -- bullet
--- [0x221A] = { "sy", 0x70, "ex", 0x70 }, -- sqrt. AM: Check surd??
--- ...
- [0x221D] = { "sy", 0x2F }, -- propto
- [0x221E] = { "sy", 0x31 }, -- infty
- [0x2225] = { "sy", 0x6B }, -- parallel
- [0x2227] = { "sy", 0x5E }, -- wedge
- [0x2228] = { "sy", 0x5F }, -- vee
- [0x2229] = { "sy", 0x5C }, -- cap
- [0x222A] = { "sy", 0x5B }, -- cup
- [0x222B] = { "ex", 0x52 }, -- intop
--- ... other integrals
- [0x2236] = { "mr", 0x3A }, -- colon
- [0x223C] = { "sy", 0x18 }, -- sim
- [0x2243] = { "sy", 0x27 }, -- simeq
- [0x2248] = { "sy", 0x19 }, -- approx
- [0x225C] = { "ma", 0x2C }, -- triangleq
- [0x2261] = { "sy", 0x11 }, -- equiv
- [0x2264] = { "sy", 0x14 }, -- leq
- [0x2265] = { "sy", 0x15 }, -- geq
- [0x226A] = { "sy", 0x1C }, -- ll
- [0x226B] = { "sy", 0x1D }, -- gg
- [0x227A] = { "sy", 0x1E }, -- prec
- [0x227B] = { "sy", 0x1F }, -- succ
--- [0x227C] = { "sy", 0x16 }, -- preceq, AM:No see 2AAF
--- [0x227D] = { "sy", 0x17 }, -- succeq, AM:No see 2AB0
- [0x2282] = { "sy", 0x1A }, -- subset
- [0x2283] = { "sy", 0x1B }, -- supset
- [0x2286] = { "sy", 0x12 }, -- subseteq
- [0x2287] = { "sy", 0x13 }, -- supseteq
- [0x2293] = { "sy", 0x75 }, -- sqcap
- [0x2294] = { "sy", 0x74 }, -- sqcup
- [0x2295] = { "sy", 0x08 }, -- oplus
- [0x2296] = { "sy", 0x09 }, -- ominus
- [0x2297] = { "sy", 0x0A }, -- otimes
- [0x2298] = { "sy", 0x0B }, -- oslash
- [0x2299] = { "sy", 0x0C }, -- odot
- [0x22A4] = { "sy", 0x3E }, -- top
- [0x22A5] = { "sy", 0x3F }, -- bop
- [0x22C0] = { "ex", 0x56 }, -- bigwedge
- [0x22C1] = { "ex", 0x57 }, -- bigvee
- [0x22C2] = { "ex", 0x54 }, -- bigcap
- [0x22C3] = { "ex", 0x53 }, -- bigcup
- [0x22C4] = { "sy", 0x05 }, -- diamond
- [0x22C5] = { "sy", 0x01 }, -- cdot
- [0x22C6] = { "mi", 0x3F }, -- star
- [0x25B3] = { "sy", 0x34 }, -- triangle up
-
- [0x2220] = { "ma", 0x5C }, -- angle
- [0x2221] = { "ma", 0x5D }, -- measuredangle
- [0x2222] = { "ma", 0x5E }, -- sphericalangle
-
- [0x2245] = { "ma", 0x75 }, -- aproxeq
-
- [0x1D6A4] = { "mi", 0x7B }, -- imath
- [0x1D6A5] = { "mi", 0x7C }, -- jmath
-
- [0x0028] = { "mr", 0x28, "ex", 0x00 }, -- (
- [0x0029] = { "mr", 0x29, "ex", 0x01 }, -- )
- [0x002F] = { "mr", 0x2F, "ex", 0x0E }, -- /
- [0x003C] = { "sy", 0x3C, "ex", 0x0A }, -- <
- [0x003E] = { "sy", 0x3E, "ex", 0x0B }, -- >
- [0x005B] = { "mr", 0x5B, "ex", 0x02 }, -- [
- [0x005D] = { "mr", 0x5D, "ex", 0x03 }, -- ]
- [0x007C] = { "sy", 0x6A, "ex", 0x0C }, -- |
- [0x005C] = { "sy", 0x6E, "ex", 0x0F }, -- \
- [0x007B] = { "sy", 0x66, "ex", 0x08 }, -- {
- [0x007D] = { "sy", 0x67, "ex", 0x09 }, -- }
-
- [0x005E] = { "mr", 0x5E, "ex", 0x62 }, -- widehat
- [0x007E] = { "mr", 0x7E, "ex", 0x65 }, -- widetilde
-
- [0x2AAF] = { "sy", 0x16 }, -- preceq
- [0x2AB0] = { "sy", 0x17 }, -- succeq
-
- [0x2145] = { "mr", 0x44 },
- [0x2146] = { "mr", 0x64 },
- [0x2147] = { "mr", 0x65 },
-
- -- please let lm/gypre math show up soon
-
-}
-
-mathematics.slots.current = mathematics.slots.traditional
+-- needed for mathml analysis
function mathematics.utfmathclass(chr, default)
local cd = characters.data[utfbyte(chr)]
@@ -473,3 +279,42 @@ function mathematics.register_xml_entities()
end
end
end
+
+-- helpers
+
+function mathematics.big(tfmdata,unicode,n)
+ local t = tfmdata.characters
+ local c = t[unicode]
+ if c then
+ local next = c.next
+ while next do
+ if n <= 1 then
+ return next
+ else
+ n = n - 1
+ next = t[next].next
+ end
+ end
+ end
+ return unicode
+end
+
+-- plugins
+
+function mathematics.scaleparameters(t,tfmtable,delta)
+ local math_parameters = tfmtable.math_parameters
+ if math_parameters and next(math_parameters) then
+ delta = delta or 1
+ local _, mp = mathematics.dimensions(math_parameters)
+ for name, value in next, mp do
+ if name ~= "RadicalDegreeBottomRaisePercent" then
+ mp[name] = delta*value
+ else
+ mp[name] = value
+ end
+ end
+ t.MathConstants = mp
+ end
+end
+
+table.insert(fonts.tfm.mathactions,mathematics.scaleparameters)
diff --git a/tex/context/base/math-ini.mkii b/tex/context/base/math-ini.mkii
index 6b0cd71d7..7d87fb365 100644
--- a/tex/context/base/math-ini.mkii
+++ b/tex/context/base/math-ini.mkii
@@ -1,14 +1,681 @@
%D \module
%D [ file=math-ini,
-%D version=2008.01.02,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=Math Initializations,
-%D author=Hans Hagen,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Initializations,
+%D author={Hans Hagen \& Taco Hoekwater},
%D date=\currentdate,
-%D copyright=PRAGMA]
+%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.
-\endinput
+\writestatus{loading}{ConTeXt Math Macros / Initializations}
+
+% todo: make all definitions global since file loaded only once
+
+%D This module provides namespaces for math fonts, thereby
+%D permitting mixed usage of math fonts. Although not strictly
+%D needed, we also provide a family name mapping mechanism as
+%D used in the (original) AMS math definition files, but here
+%D these names can recursively be remapped and if needed,
+%D dynamically be changed. We've tried to minimize the number
+%D of definition commands and use plain \TEX\ definitions as
+%D fallback. We've tried to follow a couple of conventions
+%D from plain and AMS math in order to achieve backward
+%D compatinility. We also kept an eye on future usage of these
+%D modules in the perspective of MathML and unicode fonts.
+
+\unprotect
+
+\def\@ml@{@ml@} % math list (used for collection)
+\def\@mf@{@mf@} % math family
+%def\@mh@{@mh@} % math handler (not used)
+\def\@mt@{@mt@} % math token
+\def\@mc@{@mc@} % math collection
+
+\def\@@mathlimopcomm#1{\mathop{#1}} %no \limits
+\def\@@mathnolopcomm#1{\mathop{#1}\nolimits}
+\def\@@mathboxcomm #1{\dontleavehmode\hbox{$\mathsurround\zeropoint#1$}}
+
+\chardef\mathordcode = 0 \let\mathordcomm \mathord
+\chardef\mathopcode = 1 \let\mathopcomm \mathop
+\chardef\mathbincode = 2 \let\mathbincomm \mathbin
+\chardef\mathrelcode = 3 \let\mathrelcomm \mathrel
+\chardef\mathopencode = 4 \let\mathopencomm \mathopen
+\chardef\mathclosecode = 5 \let\mathclosecomm \mathclose
+\chardef\mathpunctcode = 6 \let\mathpunctcomm \mathpunct
+\chardef\mathalphacode = 7 \let\mathalphacomm \firstofoneargument
+\chardef\mathinnercode = 0 \let\mathinnercomm \mathinner
+\chardef\mathnothingcode= 0 \let\mathnothingcomm \firstofoneargument
+\chardef\mathlimopcode = 1 \let\mathlimopcomm \@@mathlimopcomm
+\chardef\mathnolopcode = 1 \let\mathnolopcomm \@@mathnolopcomm
+\chardef\mathchoicecode = 0 \let\mathchoicecomm \@@mathchoicecomm
+\chardef\mathboxcode = 0 \let\mathboxcomm \@@mathboxcomm
+
+\chardef\mathaccentcode = 8
+\chardef\mathradicalcode= 9
+
+\def\@@mathchoicecomm#1{[todo #1]}
+
+\def\puremathcode#1{\the\csname math#1code\endcsname}
+\def\puremathcomm#1{\csname math#1comm\endcsname}
+
+\newif\iftracemathcollection
+
+% Simple variant:
+%
+% \def\dohandlemathtoken#1%
+% {\csname\@mt@
+% \ifcsname\@mt@\mathcollection#1\endcsname
+% \mathcollection
+% \else\ifcsname\@mt@\nomathcollection#1\endcsname
+% \nomathcollection
+% \fi\fi
+% #1\endcsname}
+
+%D Because a command can have a different meaning in math
+%D and in text mode, we provide a selector. We also provide
+%D the pure alternatives as \type {\mathcharacter} and \type
+%D {\textcharacter}.
+
+% \ifx\dohandlecommand\undefined \wait \fi % troubles ! but not in mkiv so ...
+
+\let\mathcharacter\dohandlemathtoken
+\let\textcharacter\dohandlecommand % better \dohandletexttoken
+
+% More clever layout:
+%
+% \def\dohandlemathtoken#1%
+% {\csname
+% \ifmmode
+% \ifcsname\@mt@\mathcollection#1\endcsname
+% \@mt@\mathcollection
+% \else\ifcsname\@mt@\nomathcollection#1\endcsname
+% \@mt@\nomathcollection
+% \else\ifcsname\characterencoding#1\endcsname
+% \characterencoding
+% \else
+% \nocharacterencoding
+% \fi\fi\fi
+% \else
+% \ifcsname\characterencoding#1\endcsname
+% \characterencoding
+% \else
+% \nocharacterencoding
+% \fi
+% \fi
+% #1\endcsname}
+%
+% fallback to math when in text mode (handy for unicode vectors)
+
+\def\dohandlemathtoken#1%
+ {\csname
+ \ifmmode
+ \ifcsname\@mt@\mathcollection#1\endcsname
+ \@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \@mt@\nomathcollection
+ \else\ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi\fi\fi
+ \else
+ \ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else\ifcsname\nocharacterencoding#1\endcsname
+ \nocharacterencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi
+ \fi
+ #1\endcsname}
+
+%D Now we redefine the text encoding handler.
+
+%D A better fallback:
+
+% Just ETEX which is the default nowadays.
+
+\def\dohandlemathtoken#1%
+ {\csname
+ \ifmmode
+ \ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
+ \@mt@\mathcollection:\outerencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \@mt@\nomathcollection
+ \else\ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi
+ \else
+ \ifcsname\characterencoding#1\endcsname
+ \characterencoding
+ \else\ifcsname\nocharacterencoding#1\endcsname
+ \nocharacterencoding
+ \else\ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
+ \@mt@\mathcollection:\outerencoding
+ \else\ifcsname\@mt@\mathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
+ \else\ifcsname\@mt@\nomathcollection#1\endcsname
+ \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
+ \else
+ \nocharacterencoding
+ \fi\fi\fi\fi\fi
+ \fi
+ #1\endcsname}
+
+\let\dohandlecommand\dohandlemathtoken
+
+\def\definefamilysynonym
+ {\dotripleempty\dodefinefamilysynonym}
+
+\def\dodefinefamilysynonym[#1][#2][#3]% [mathcollection] [] []
+ {\ifthirdargument
+ \setvalue{\@mf@#1#2}{#3}%
+ \else
+ \setvalue{\@mf@ #1}{#2}%
+ \fi}
+
+\let\mathsubfamily\empty
+
+\def\purefamily #1{\csname \truefamily{#1}\mathsubfamily\s!fam\endcsname}
+\def\purefamilyhex#1{\csname hex\truefamily{#1}\mathsubfamily\s!fam\endcsname}
+
+\def\truefamily#1%
+ {\ifcsname\@mf@\mathcollection#1\endcsname
+ \@EA\truefamily\csname\@mf@\mathcollection#1\endcsname
+ \else\ifcsname\@mf@#1\endcsname
+ \@EA\truefamily\csname\@mf@#1\endcsname
+ \else\ifcsname\@mf@\nomathcollection#1\endcsname
+ \@EA\truefamily\csname\@mf@\nomathcollection#1\endcsname
+ \else
+ #1%
+ \fi\fi\fi}
+
+\newif\ifdynamicmathfamilies \dynamicmathfamiliestrue % true per 2003.11.25; needed for mixed bold math
+
+\let\normalpurefamilyhex\purefamilyhex
+
+% todo: reset collection (tok legen) en opnieuw laden met true
+
+\def\definemathsymbol
+ {\dosixtupleempty\dodefinemathsymbol}
+
+\def\dodefinemathsymbol[#1][#2][#3][#4][#5][#6]%
+ {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
+ \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+ \setevalue{\@mt@\mathcollection#1}%
+ {\ifsixthargument
+ \ifnum\puremathcode{#2}=\mathradicalcode
+ \radical"%
+ \else
+ \delimiter"%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \fi
+ \purefamilyhex{#3}\uchexnumbers{#4}%
+ \purefamilyhex{#5}\uchexnumbers{#6}\space
+ \else\iffourthargument
+ \ifnum\puremathcode{#2}=\mathaccentcode
+ \mathaccent\else\mathchar
+ \fi
+ "\ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}\space
+ \fi\fi}%
+ \let\purefamilyhex\normalpurefamilyhex
+ \tracemathsymbol{#1}}
+
+\def\tracemathsymbol#1%
+ {\iftracemathcollection
+ {\endgraf
+ \hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}
+ \endgraf}%
+ \fi}
+
+\def\definemathcharacter
+ {\dosixtupleempty\dodefinemathcharacter}
+
+% \def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
+% {\setmathtoks
+% \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+% \doifnumberelse{#1}
+% {\scratchcounter#1}
+% {\scratchcounter\@EA`\string#1}%
+% \appendetoks
+% \ifsixthargument
+% \delcode\the\scratchcounter="%
+% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+% \purefamilyhex{#3}\uchexnumbers{#4}%
+% \purefamilyhex{#5}\uchexnumbers{#6}\space
+% \else\iffourthargument
+% \mathcode\the\scratchcounter="%
+% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+% \purefamilyhex{#3}\uchexnumbers{#4}\space
+% \fi\fi\to\mathtoks
+% \let\purefamilyhex\normalpurefamilyhex
+% \tracemathcharacter{#1}}
+
+\newtoks\mathscratchtoks
+
+\def\definemathcharacter
+ {\chardef\mathcharactermode\zerocount
+ \dosixtupleempty\dodefinemathcharacter}
+
+\def\redefinemathcharacter
+ {\chardef\mathcharactermode\plusone
+ \dosixtupleempty\dodefinemathcharacter}
+
+\def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
+ {\ifcase\mathcharactermode
+ \setmathtoks
+ \or
+ \let\mathtoks\mathscratchtoks \mathtoks\emptytoks
+ \fi
+ \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
+ \doifnumberelse{#1}
+ {\scratchcounter#1}
+ {\scratchcounter\@EA`\string#1}%
+ \appendetoks
+ \ifsixthargument
+ \delcode\the\scratchcounter="%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}%
+ \purefamilyhex{#5}\uchexnumbers{#6}\space
+ \else\iffourthargument
+ \mathcode\the\scratchcounter="%
+ \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
+ \purefamilyhex{#3}\uchexnumbers{#4}\space
+ \fi\fi
+ \to \mathtoks
+ \let\purefamilyhex\normalpurefamilyhex
+ \ifcase\mathcharactermode
+ \expandafter\tracemathcharacter
+ \or
+ \the\mathtoks
+ \mathtoks\emptytoks
+ \expandafter\gobbleoneargument
+ \fi{#1}} % maybe lookahead
+
+\def\tracemathcharacter#1%
+ {\iftracemathcollection
+ {\endgraf
+ \doifnumberelse{#1}
+ {\hbox{\tttf\rawcharacter{#1}~:~{\mathematics{\rawcharacter{#1}}}}}
+ {\hbox{\type{#1}~:~{\mathematics{#1}}}}
+ \endgraf}%
+ \fi}
+
+\def\definemathcommand
+ {\dotripleempty\dodefinemathcommand}
+
+\def\dodefinemathcommand[#1][#2][#3]#4% command class args meaning
+ {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
+ \ifthirdargument
+ \processaction
+ [#3]
+ [one=>\setvalue{\@mt@\mathcollection#1}##1{\puremathcomm{#2}{#4{##1}}},
+ two=>\setvalue{\@mt@\mathcollection#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
+ \else\ifsecondargument
+ \setvalue{\@mt@\mathcollection#1}{\puremathcomm{#2}{#4}}%
+ \else
+ \setvalue{\@mt@\mathcollection#1}{\puremathcomm{nothing}{#4}}%
+ \fi\fi
+ \tracemathcommand{#1}}
+
+\def\tracemathcommand#1%
+ {\iftracemathcollection
+ \endgraf\hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}\endgraf
+ \fi}
+
+\def\startmathcollection[#1]%
+ {\pushmacro\mathcollection
+ \setmathcollection{#1}}
+
+\def\setmathcollection#1%
+ {\edef\mathcollection{#1}%
+ \doifundefined{\@ml@\mathcollection}
+ {\expandafter\newtoks\csname\@ml@\mathcollection\endcsname}}
+
+\def\stopmathcollection
+ {\popmacro\mathcollection}
+
+\def\startrawmathcollection
+ {\startmathcollection}
+
+\def\stoprawmathcollection
+ {\stopmathcollection}
+
+\newtoks\mathtoks
+
+\def\setmathtoks
+ {\@EA\let\@EA\mathtoks\csname\@ml@\mathcollection\endcsname}
+
+\def\currentmathcollection{\mathcollection}
+
+\let\nomathcollection\s!default
+
+\def\enablemathcollection[#1]%
+ {\doifnot{#1}\s!default
+ {\setmathcollection\s!default
+ \the\csname\@ml@\mathcollection\endcsname}%
+ \setmathcollection{#1}%
+ \the\csname\@ml@\mathcollection\endcsname}
+
+% hook 'm into the font mechanism
+
+\definefilesynonym[\f!mathprefix\s!default][\f!mathprefix tex]
+
+\def\usemathcollection
+ {\dodoubleempty\dousemathcollection}
+
+\def\dousemathcollection[#1][#2]%
+ {\pushmacro\fontclass
+ \pushmacro\mathclass
+ \ifsecondargument
+ \edef\fontclass{#1}%
+ \edef\mathclass{#2}%
+ \else
+ \edef\mathclass{#1}%
+ \fi
+ \doinputonce{\truefilename{\f!mathprefix\mathclass}}%
+ \doifsomething\fontclass{\setevalue{\@mc@\fontclass\@mc@}{\mathclass}}%
+ \popmacro\mathclass
+ \popmacro\fontclass}
+
+\let\mathclass\nomathcollection
+
+\letvalue{\@mc@\@mc@}\nomathcollection
+
+% \def\autoenablemathcollection
+% {\doifdefinedelse{\@mc@\fontclass\@mc@}
+% {\enablemathcollection[\getvalue{\@mc@\fontclass\@mc@}]}
+% {\enablemathcollection[\s!default]}} % ? ? ?
+
+\def\autoenablemathcollection
+ {\expanded{\enablemathcollection[\executeifdefined{\@mc@\fontclass\@mc@}\nomathcollection]}}
+
+\appendtoks\autoenablemathcollection\to\mathstrategies
+
+\fetchruntimecommand \showmathcharacters {\f!mathprefix\s!run.mkii}
+\fetchruntimecommand \showmathtoken {\f!mathprefix\s!run.mkii}
+
+\def\resetmathcollection[#1]%
+ {\def\mathcollection{#1}%
+ \forgetdoingonce{\f!mathprefix\mathcollection}%
+ \setmathtoks
+ \ifx\mathtoks\relax\else\mathtoks\emptytoks\fi}
+
+%D \macros
+%D {ifmathpunctuation, enablemathpunctuation,
+%D definemathpunctuation}
+%D
+%D This will replace periods by comma's:
+%D
+%D \starttyping
+%D \definemathpunctuation . textcomma textperiod
+%D \definemathpunctuation , textcomma textcomma
+%D
+%D \appendtoks
+%D \redefinemathcharacter [.] [ord] [mi] ["3B]%
+%D \to \everymathpunctuation
+%D \stoptyping
+
+% \newif\ifmathpunctuation
+%
+% \def\enablemathpunctuation{\mathpunctuationtrue}
+%
+% \def\definemathpunctuation #1 #2 #3 %
+% {\appendtoks
+% \initializemathpunctuation{#1}{#2}{#3}%
+% \to\everymathematics}
+%
+% \def\initializemathpunctuation#1#2#3% sloowww
+% {\ifmathpunctuation % hm move this test to everymath, or better a separate token list
+% \mathcode`#1="8000
+% \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}%
+% \fi}
+%
+% \unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
+% {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
+% \futurelet\nexttoken\next}
+
+\newtoks\everymathpunctuation
+
+\def\enablemathpunctuation % can be called inside math, so after \everymathematics
+ {\the\everymathpunctuation
+ \appendtoksonce
+ \the\everymathpunctuation
+ \to\everymathematics}
+
+\def\definemathpunctuation #1 #2 #3 %
+ {\appendtoks
+ \initializemathpunctuation{#1}{#2}{#3}%
+ \to\everymathpunctuation}
+
+\def\initializemathpunctuation#1#2#3% sloowww
+ {\mathcode`#1="8000
+ \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}}
+
+\unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
+ {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
+ \futurelet\nexttoken\next}
+
+%D \startbuffer
+%D \enablemathpunctuation$(1,2) (1, 2) (1{,}2) \hbox{foo, not bar}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \blank{\getbuffer}\blank
+
+%D needed for sin, cos etc
+
+\def\mfunction #1{{\mr#1}}
+
+% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}}
+% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}}
+
+%D Taco posted this solution as response to a mail by Olivier, so
+%D let's integrate it here.
+
+% \def\setmathfunctionstyle#1% rm ss tt
+% {\def\mfunction##1% no families, just scaling a la text
+% {\mathchoice
+% {\hbox{\csname#1\endcsname\tf ##1}}
+% {\hbox{\csname#1\endcsname\tf ##1}}
+% {\hbox{\csname#1\endcsname\tfx ##1}}
+% {\hbox{\csname#1\endcsname\tfxx##1}}}}
+
+\def\currentmscaledstyle{rm} % will be plugged into the typeface text=ss option
+
+\def\setmathfunctionstyle#1% rm ss tt
+ {\doifsomething{#1}
+ {\def\currentmscaledstyle{#1}%
+ \def\mathopnolimits##1{\mathop{\mscaledtext{##1}}\nolimits}%
+ \def\mfunction##1{\mscaledtext{##1}}}}
+
+\def\mscaledtext#1%
+ {\mathchoice
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfx #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfxx#1}}}
+
+%D We can force the way functions are typeset by manipulating the text
+%D option:
+%D
+%D \starttyping
+%D \definetypeface[iwona][ss][sans][iwona][default][encoding=texnansi]
+%D \definetypeface[iwona][mm][math][iwona][default][encoding=texnansi,text=ss]
+%D \stoptyping
+%D
+%D This hooks into the math handler with:
+
+\appendtoks
+ \setmathfunctionstyle\currentmathtextstyle
+\to \everybodyfont
+
+%D Usage:
+%D
+%D \starttyping
+%D \setmathfunctionstyle\fontstyle % or {rm} or {ss} or ..
+%D \rm test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \ss test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \tt test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \stoptyping
+
+\edef\hexmrfam {0} \edef\hexbsfam {8}
+\edef\hexmifam {1} \edef\hexbifam {9}
+\edef\hexsyfam {2} \edef\hexscfam {A}
+\edef\hexexfam {3} \edef\hextffam {B}
+\edef\hexitfam {4} \edef\hexmafam {C}
+\edef\hexslfam {5} \edef\hexmbfam {D}
+\edef\hexbffam {6} \edef\hexmcfam {E}
+\edef\hexnnfam {7} \edef\hexmdfam {F}
+
+\definefamilysynonym [default] [letters] [mr]
+\definefamilysynonym [default] [operators] [sy]
+\definefamilysynonym [default] [lcgreek] [mi]
+\definefamilysynonym [default] [ucgreek] [mr]
+\definefamilysynonym [default] [vargreek] [mi]
+\definefamilysynonym [default] [mitfamily] [mi]
+\definefamilysynonym [default] [calfamily] [sy]
+
+\definefamilysynonym [default] [0] [mr]
+\definefamilysynonym [default] [1] [mi]
+\definefamilysynonym [default] [2] [sy]
+\definefamilysynonym [default] [3] [ex]
+
+\enablemathcollection[default]
+
+\usemathcollection [default] [tex]
+\usemathcollection [default] [ams]
+\usemathcollection [default] [uni]
+
+\enablemathcollection[default]
+
+%D Some goodies:
+
+\def\Angstrom{\nomathematics{\Aring}}
+
+%D Bold math:
+%D
+%D \starttyping
+%D \usetypescript [lucida] [texnansi]
+%D
+%D \definetypeface [boldmath] [rm] [serif]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [tt] [mono]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [ss] [sans]
+%D [lucida] [default] [encoding=texnansi]
+%D \definetypeface [boldmath] [mm] [boldmath]
+%D [lucida] [default] [encoding=texnansi]
+%D
+%D \switchtobodyfont[lucida,10pt]
+%D
+%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
+%D
+%D \switchtobodyfont[boldmath,10pt]
+%D
+%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
+%D \stoptyping
+
+%D \macros
+%D {nonknuthmode, donknuthmode}
+%D
+%D The underscore is frequently used in manuals but unfortunately \TEX\ prefers
+%D it to be a math specific character. And since computer modern fonts didn't
+%D have an underscore, one had to use commands to fake one. Nowadays we do
+%D have underscores in latin modern, and since all other fonts have them, we
+%D decided to get away from the restriction to use the underscore character in
+%D text mode.
+%D
+%D \starttyping
+%D \def\test#1{#1}
+%D
+%D \nonknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D
+%D \donknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D \stoptyping
+%D
+%D The result is as expected: the first line typesets ok, while the second
+%D one triggers an error message.
+
+\bgroup
+
+ \ifx\normalsuber\undefined \def\normalsuber{_} \fi
+ \ifx\normalsuper\undefined \def\normalsuper{^} \fi
+
+ \catcode`_=\active
+ \catcode`^=\active
+
+ \gdef\nonknuthmode
+ {\appendtoks\let_\normalsuber\let^\normalsuper\to\everymathematics
+ \mathcode`_="8000
+ \mathcode`^="8000
+ \catcode`_=\@@other
+ \catcode`^=\@@other
+ \let\nonknuthmode\relax}
+
+ \gdef\donknuthmode
+ {\catcode`_=\@@subscript
+ \catcode`^=\@@superscript}
+
+\egroup
+
+%D \macros
+%D {checkdelimiters, fakeleftdelimiter, fakerightdelimiter}
+%D
+%D Handy for non matching situations (as with mathml):
+%D
+%D \starttyping
+%D \checkdelimiters{... bla bla ...}
+%D \fakeleftdelimiter
+%D ... bla bla ...
+%D \fakerightdelimiter
+%D \stoptyping
+
+\newcount\delimitercount
+
+\def\leftfakedelimiter {\advance\delimitercount\minusone\gobbleoneargument}%
+\def\rightfakedelimiter{\advance\delimitercount\plusone \gobbleoneargument}%
+
+\def\checkdelimiters#1%
+ {\delimitercount\zerocount
+ \setbox\scratchbox\hbox\bgroup
+ \let\left \leftfakedelimiter
+ \let\right\rightfakedelimiter
+ $#1\expandafter$\expandafter
+ \egroup
+ \expandafter\delimitercount\the\delimitercount\relax}
+
+\def\fakeleftdelimiter {\ifnum\delimitercount>\zerocount\left .\fi}
+\def\fakerightdelimiter{\ifnum\delimitercount<\zerocount\right.\fi}
+
+%D Needed for unicode:
+
+\def\nulloperator{\mathortext{\mathop{\null}}{\null}}
+
+%D To be dealt with ...
+
+\mathcode`\ ="8000 % \space
+\mathcode`\'="8000 % ^\prime
+\mathcode`\_="8000 % \_
+
+\protect \endinput
+
+\tracemathcollectiontrue
+ \input math-tex \page
+\setupbodyfont[ams] \enablemathcollection[default] \input math-ams \page
+\setupbodyfont[lbr] \enablemathcollection[lbr] \input math-lbr \page
+\setupbodyfont[eul] \enablemathcollection[eul] \input math-eul \stoptext
diff --git a/tex/context/base/math-ini.mkiv b/tex/context/base/math-ini.mkiv
index 062631b39..b87096661 100644
--- a/tex/context/base/math-ini.mkiv
+++ b/tex/context/base/math-ini.mkiv
@@ -1,8 +1,8 @@
%D \module
%D [ file=math-ini,
%D version=2008.01.02,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=Math Initializations,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Initializations,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,39 +11,549 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Math Macros / Initializations}
+
+%D This module provides namespaces for math fonts, thereby
+%D permitting mixed usage of math fonts. Although not strictly
+%D needed, we also provide a family name mapping mechanism as
+%D used in the (original) AMS math definition files, but here
+%D these names can recursively be remapped and if needed,
+%D dynamically be changed. We've tried to minimize the number
+%D of definition commands and use plain \TEX\ definitions as
+%D fallback. We've tried to follow a couple of conventions
+%D from plain and AMS math in order to achieve backward
+%D compatinility. We also kept an eye on future usage of these
+%D modules in the perspective of MathML and unicode fonts.
+
\unprotect
+\ifx\v!compact\undefined \def\v!compact{compact} \fi
+
%D We move these definitions into the format:
% test [[\char948 \ctxlua{tex.sprint(utf.char(948))}]]
% test $[[\char948 \ctxlua{tex.sprint(utf.char(948))}]]$
\registerctxluafile{math-ini}{1.001}
+\registerctxluafile{math-dim}{1.001}
\registerctxluafile{math-ent}{1.001}
+\registerctxluafile{math-ext}{1.001}
+\registerctxluafile{math-vfu}{1.001}
+\registerctxluafile{math-map}{1.001}
+\registerctxluafile{math-noa}{1.001}
+
+\definesystemattribute[mathalph]
+\definesystemattribute[mathsize]
+\definesystemattribute[mathpunc]
+
+% todo: only in mmode
+
+% \def\setmathattribute#1#2{\dosetattribute{mathalph}{\ctxlua{tex.sprint(mathematics.sync_a_both (\number\dogetattribute{mathalph},"#1","#2"))}}}
+% \def\setmathalphabet #1{\dosetattribute{mathalph}{\ctxlua{tex.sprint(mathematics.sync_a_name (\number\dogetattribute{mathalph},"#1"))}}}
+% \def\setmathstyle #1{\dosetattribute{mathalph}{\ctxlua{tex.sprint(mathematics.sync_a_style(\number\dogetattribute{mathalph},"#1"))}}}
+
+\def\setmathattribute#1#2{\ctxlua{mathematics.sync_a_both ("#1","#2")}}
+\def\setmathalphabet #1{\ctxlua{mathematics.sync_a_name ("#1")}}
+\def\setmathstyle #1{\ctxlua{mathematics.sync_a_style("#1")}}
+
+\unexpanded\def\mr {\setmathattribute{regular}{tf}}
+
+\unexpanded\def\mathdefault {\setmathattribute{regular}{it}}
+\unexpanded\def\mathscript {\setmathalphabet{script}}
+\unexpanded\def\mathfraktur {\setmathalphabet{fraktur}}
+\unexpanded\def\mathblackboard{\setmathalphabet{blackboard}}
+
+\unexpanded\def\mathrm{\setmathattribute{rm}{tf}}
+\unexpanded\def\mathss{\setmathattribute{ss}{tf}}
+\unexpanded\def\mathtt{\setmathattribute{tt}{tf}}
+
+\unexpanded\def\mathtf{\setmathstyle{tf}}
+\unexpanded\def\mathbf{\setmathstyle{bf}}
+\unexpanded\def\mathsl{\setmathstyle{sl}}
+\unexpanded\def\mathit{\setmathstyle{it}}
+\unexpanded\def\mathbs{\setmathstyle{bs}}
+\unexpanded\def\mathbi{\setmathstyle{bi}}
+
+\let\tfmath\mathtf % maybe a grouped command
+\let\bfmath\mathbf
+\let\slmath\mathsl
+\let\itmath\mathit
+\let\bsmath\mathbs
+\let\bimath\mathbi
-% \registerctxluafile{math-def}{1.001}
-% \ctxlua{mathematics.traditional()}
+\let\Bbb\mathblackboard
-\ctxlua{mathematics.define()}
-\ctxlua{mathematics.register_xml_entities()}
+\unexpanded\def\frak {\ifmmode\expandafter\mathfraktur \fi}
+\unexpanded\def\cal {\ifmmode\expandafter\mathscript \fi}
+\unexpanded\def\bbd {\ifmmode\expandafter\mathblackboard\fi}
+\unexpanded\def\blackboard{\ifmmode\expandafter\mathblackboard\fi}
+\unexpanded\def\fraktur {\ifmmode\expandafter\mathfraktur \fi}
+\unexpanded\def\gothic {\ifmmode\expandafter\mathfraktur \fi}
+
+\unexpanded\def\mathcal #1{{\setmathalphabet{script}#1}} % for AMS compatibility
+\unexpanded\def\mathfrak#1{{\setmathalphabet{fraktur}#1}} % for AMS compatibility
+\unexpanded\def\mathbb #1{{\setmathalphabet{blackboard}#1}} % for AMS compatibility
+
+\let\normalmr\mr
+
+\prependtoks
+ \let\mr\normalmr
+ \let\rm\mathrm \let\ss\mathss \let\tt\mathtt
+ \let\tf\mathtf \let\bf\mathbf \let\it\mathit \let\sl\mathsl \let\bi\mathbi \let\bs\mathbs
+ \let\frak\mathfraktur \let\cal\mathscript \let\bbd\mathblackboard
+ \mathdefault
+\to \everymathematics
+
+%D \macros
+%D {boldsymbol}
+%D
+%D The math definition is inspired by amsmath.
+%D
+%D \startbuffer
+%D \definetypeface [boldmath] [mm] [boldmath] [latin-modern] [modern] [encoding=texnansi]
+%D
+%D $a \times b$ $a \boldsymbol{\times} b$
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+
+\let\mathboldsymbol\relax % yet unsupported, will be
+
+\def\boldsymbol
+ {\mathortext\mathboldsymbol\bold}
+
+%D Helpers:
\def\utfmathclass #1{\ctxlua{tex.sprint(mathematics.utfmathclass ("#1"))}}
\def\utfmathstretch#1{\ctxlua{tex.sprint(mathematics.utfmathstretch("#1"))}}
\def\utfmathcommand#1{\ctxlua{tex.sprint(mathematics.utfmathcommand("#1"))}}
\def\utfmathfiller #1{\ctxlua{tex.sprint(mathematics.utfmathfiller ("#1"))}}
-\def\utfmathclassdefault #1#2{\ctxlua{
- tex.sprint(mathematics.utfmathclass("#1","#2"))
-}}
+% \def\utfmathclassdefault #1#2{\ctxlua{
+% tex.sprint(mathematics.utfmathclass("#1","#2"))
+% }}
+%
+% \def\utfmathcommanddefault#1#2#3{\ctxlua{
+% local cmd = mathematics.utfmathcommand("#1","") or ""
+% if cmd == "" then
+% commands.cs("#2","#3")
+% else
+% commands.cs(cmd)
+% end}}
+
+% % %
+
+\def\@@mathlimopcomm #1{\mathop{#1}} %no \limits
+\def\@@mathnolopcomm #1{\mathop{#1}\nolimits}
+\def\@@mathboxcomm #1{\dontleavehmode\hbox{$\mathsurround\zeropoint#1$}}
+\def\@@mathchoicecomm#1{[todo #1]}
+
+\chardef\mathordcode = 0 \let\mathordcomm \mathord
+\chardef\mathopcode = 1 \let\mathopcomm \mathop
+\chardef\mathbincode = 2 \let\mathbincomm \mathbin
+\chardef\mathrelcode = 3 \let\mathrelcomm \mathrel
+\chardef\mathopencode = 4 \let\mathopencomm \mathopen
+\chardef\mathclosecode = 5 \let\mathclosecomm \mathclose
+\chardef\mathpunctcode = 6 \let\mathpunctcomm \mathpunct
+\chardef\mathalphacode = 7 \let\mathalphacomm \firstofoneargument
+\chardef\mathinnercode = 0 \let\mathinnercomm \mathinner
+\chardef\mathnothingcode= 0 \let\mathnothingcomm \firstofoneargument
+\chardef\mathlimopcode = 1 \let\mathlimopcomm \@@mathlimopcomm
+\chardef\mathnolopcode = 1 \let\mathnolopcomm \@@mathnolopcomm
+\chardef\mathchoicecode = 0 \let\mathchoicecomm \@@mathchoicecomm
+\chardef\mathboxcode = 0 \let\mathboxcomm \@@mathboxcomm
+
+\chardef\mathaccentcode = 8
+\chardef\mathradicalcode= 9
+
+\def\puremathcode#1{\the\csname math#1code\endcsname}
+\def\puremathcomm#1{\csname math#1comm\endcsname}
+
+% \startlines
+% $\mathopnolimits{\rm d}x$
+% $\mathopnolimits{\kern\zeropoint \rm d}x$
+% $\puremathcomm{nolop}{\rm d}x$
+% $\puremathcomm{nolop}{\kern\zeropoint\rm d}x$
+% \blank
+% $\puremathcomm{nolop}{\mr d}x$
+% $\puremathcomm{nolop}{\kern\zeropoint\mr d}x$
+% $\mathop{\kern\zeropoint\mr d}x$
+% $\mathopnolimits{\kern\zeropoint d}x$
+% \stoplines
+
+\newif\iftracemathcollection
+
+% this will be sorted out:
+
+\let\mathcharacter \getvalue
+\let\textcharacter \getvalue
+\def\definefamilysynonym {\dotripleempty\dodefinefamilysynonym}
+\def\dodefinefamilysynonym [#1][#2][#3]{}
+\def\definemathsymbol {\dosixtupleempty\dodefinemathsymbol}
+\def\dodefinemathsymbol [#1][#2][#3][#4][#5][#6]{}
+\def\definemathcharacter {\dosixtupleempty\dodefinemathcharacter}
+\def\redefinemathcharacter {\dosixtupleempty\dodefinemathcharacter}
+\def\dodefinemathcharacter [#1][#2][#3][#4][#5][#6]{}
+\def\startmathcollection [#1]{}
+\def\setmathcollection #1{}
+\def\stopmathcollection {}
+\def\startrawmathcollection {}
+\def\stoprawmathcollection {}
+\def\setmathtoks {}
+\let\currentmathcollection \s!default
+\let\nomathcollection \s!default
+\let\mathcollection \s!default
+\def\enablemathcollection [#1]{}
+\def\usemathcollection {\dodoubleempty\dousemathcollection}
+\def\dousemathcollection [#1][#2]{}
+\let\mathclass \nomathcollection
+\let\autoenablemathcollection\relax
+\def\resetmathcollection [#1]{}
+
+\def\definemathcommand
+ {\dotripleempty\dodefinemathcommand}
+
+\def\dodefinemathcommand[#1][#2][#3]#4% command class args meaning
+ {\ifthirdargument
+ \processaction
+ [#3]
+ [one=>\unexpanded\setvalue{#1}##1{\puremathcomm{#2}{#4{##1}}},
+ two=>\unexpanded\setvalue{#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
+ \else\ifsecondargument
+ \unexpanded\setvalue{#1}{\puremathcomm{#2}{#4}}%
+ \else
+ \unexpanded\setvalue{#1}{\puremathcomm{nothing}{#4}}%
+ \fi\fi}
+
+%D Moved from font-ini.mkiv:
+%D
+%D \macros
+%D {mf,mbox,enablembox,mathop}
+%D
+%D Todo:
+
+\unexpanded\def\mf
+ {\csname\fontalternative\endcsname}
+
+\let\normalmathop\mathop
+
+\unexpanded\def\mathop
+ {\normalmathop
+ \bgroup
+ \let\rm\mf
+ \let\next=}
+
+\def\normalmbox
+ {\normalhbox\bgroup\mf
+ \dowithnextbox{\flushnextbox\egroup}\normalhbox}
+
+\def\mbox
+ {\ifmmode\normalmbox\else\normalhbox\fi}
+
+\def\enablembox
+ {\appendtoks
+ \ifx\normalhbox\undefined\let\normalhbox\hbox\fi
+ \let\hbox\mbox
+ \to\everymathematics}
+
+%D needed for sin, cos etc
+
+\def\mfunction#1{{\mr#1}}
+
+% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}}
+% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}}
+
+%D Taco posted this solution as response to a mail by Olivier, so
+%D let's integrate it here.
+
+\def\currentmscaledstyle{rm} % will be plugged into the typeface text=ss option
+
+\def\setmathfunctionstyle#1% rm ss tt
+ {\doifsomething{#1}
+ {\def\currentmscaledstyle{#1}%
+ \def\mathopnolimits##1{\mathop{\mscaledtext{##1}}\nolimits}%
+ \def\mfunction##1{\mscaledtext{##1}}}}
+
+\def\mscaledtext#1%
+ {\mathchoice
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfx #1}}
+ {\hbox{\csname\currentmscaledstyle\endcsname\tfxx#1}}}
+
+%D We can force the way functions are typeset by manipulating the text
+%D option:
+%D
+%D \starttyping
+%D \definetypeface[iwona][ss][sans][iwona][default][encoding=texnansi]
+%D \definetypeface[iwona][mm][math][iwona][default][encoding=texnansi,text=ss]
+%D \stoptyping
+%D
+%D This hooks into the math handler with:
+
+\appendtoks
+ \setmathfunctionstyle\currentmathtextstyle
+\to \everybodyfont
+
+%D Usage:
+%D
+%D \starttyping
+%D \setmathfunctionstyle\fontstyle % or {rm} or {ss} or ..
+%D \rm test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \ss test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \tt test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
+%D \stoptyping
+
+%D Some goodies:
+
+\def\Angstrom{\nomathematics{\Aring}}
+
+%D \macros
+%D {nonknuthmode, donknuthmode}
+%D
+%D The underscore is frequently used in manuals but unfortunately \TEX\ prefers
+%D it to be a math specific character. And since computer modern fonts didn't
+%D have an underscore, one had to use commands to fake one. Nowadays we do
+%D have underscores in latin modern, and since all other fonts have them, we
+%D decided to get away from the restriction to use the underscore character in
+%D text mode.
+%D
+%D \starttyping
+%D \def\test#1{#1}
+%D
+%D \nonknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D
+%D \donknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
+%D \stoptyping
+%D
+%D The result is as expected: the first line typesets ok, while the second
+%D one triggers an error message.
+
+\bgroup
+
+ \ifx\normalsuber\undefined \def\normalsuber{_} \fi
+ \ifx\normalsuper\undefined \def\normalsuper{^} \fi
+
+ \catcode`_=\active
+ \catcode`^=\active
+
+ \gdef\nonknuthmode
+ {\appendtoks\let_\normalsuber\let^\normalsuper\to\everymathematics
+ \mathcode`_="8000
+ \mathcode`^="8000
+ \catcode`_=\@@other
+ \catcode`^=\@@other
+ \let\nonknuthmode\relax}
+
+ \gdef\donknuthmode
+ {\catcode`_=\@@subscript
+ \catcode`^=\@@superscript}
+
+\egroup
+
+%D Needed for unicode:
+
+\def\nulloperator{\mathortext{\mathop{\null}}{\null}}
+
+%D To be dealt with ...
+
+\mathcode`\ ="8000 % \space
+\mathcode`\'="8000 % ^\prime
+\mathcode`\_="8000 % \_
+
+%D \macros
+%D {\setupmathematics}
+%D
+%D Configuration for integrals. (If needed we can speed this up and make it
+%D installable; no processaction is needed then).
+
+\newtoks\everysetupmathematics
+
+\def\setupmathematics
+ {\dosingleargument\dosetupmathematics}
+
+\def\dosetupmathematics[#1]%
+ {\getparameters[\??mo][#1]%
+ \the\everysetupmathematics}
+
+\def\mathematicsparameter#1{\ifcsname\??mo#1\endcsname\csname\??mo#1\endcsname\fi}
+
+%D Memory saver:
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!compact}\v!yes
+ {\ctxlua{fonts.vf.math.optional=true}}
+ {\ctxlua{fonts.vf.math.optional=false}}%
+\to \everysetupmathematics
+
+\setupmathematics
+ [\v!compact=no]
+
+%D \macros
+%D {enablemathpunctuation,disablemathpunctuation}
+%D
+%D \startbuffer
+%D \enablemathpunctuation$(1,2) (1, 2) (1{,}2) \hbox{foo, not bar}$
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \blank{\getbuffer}\blank
+
+\setfalse \automathpunctuation
+
+\def\enablemathpunctuation {\settrue \automathpunctuation}
+\def\disablemathpunctuation{\setfalse\automathpunctuation}
+
+\ifx\v!autopunctuation\undefined \def\v!autopunctuation{autopunctuation} \fi
+
+\appendtoks
+ \doifelse{\mathematicsparameter\v!autopunctuation}\v!yes\enablemathpunctuation\disablemathpunctuation
+\to \everysetupmathematics
+
+\appendtoks
+ \ifconditional\automathpunctuation\dosetattribute{mathpunc}\plusone\fi
+\to \everymathematics
+
+\setupmathematics
+ [\v!autopunctuation=\v!no]
+
+%D \macros
+%D {mathstyle}
+%D
+%D If one want to be sure that something is typeset in the
+%D appropriate style, \type {\mathstyle} can be used:
+%D
+%D \starttyping
+%D \mathstyle{something}
+%D \stoptyping
+
+% \def\mathstyle#1%
+% {\mathchoice
+% {\displaystyle #1}%
+% {\textstyle #1}%
+% {\scriptstyle #1}%
+% {\scriptscriptstyle#1}}
+%
+% We now have a primitive operation for this. As the
+% macro overloads a new primitive introduced in \LUATEX,
+% we need to use \type {\normalmathstyle} when we consult
+% the current math style.
+%
+% \let \mathstyle \Ustack % spoils cramped
+%
+% \let \mathstyle \firstofoneargument
+%
+% 0 = display
+% 1 = crampeddisplay
+% 2 = text
+% 3 = crampedtext
+% 4 = script
+% 5 = crampedscript
+% 6 = scriptscript
+% 7 = crampedscriptscript
+
+\def\uncramped#1%
+ {{\ifcase\normalmathstyle
+ \or \displaystyle \or
+ \or \textstyle \or
+ \or \scriptstyle \or
+ \or \scriptscriptstyle \fi
+ #1}}
+
+\def\cramped#1%
+ {{\ifcase\normalmathstyle
+ \crampeddisplaystyle \or \or % 0 -> 1
+ \crampedtextstyle \or \or % 2 -> 3
+ \crampedscriptstyle \or \or % 4 -> 5
+ \crampedscriptscriptstyle \fi % 6 -> 7
+ #1}}
+
+\def\triggermathstyle#1% #1 is number
+ {\ifcase#1\relax
+ \displaystyle \or
+ \crampeddisplaystyle \or
+ \textstyle \or
+ \crampedtextstyle \or
+ \scriptstyle \or
+ \crampedscriptstyle \or
+ \scriptscriptstyle \or
+ \crampedscriptscriptstyle \else
+ % error
+ \fi}
+
+\def\cramped#1%
+ {{\ifcase\normalmathstyle
+ \crampeddisplaystyle \or \or % 0 -> 1
+ \crampedtextstyle \or \or % 2 -> 3
+ \crampedscriptstyle \or \or % 4 -> 5
+ \crampedscriptscriptstyle \fi % 6 -> 7
+ #1}}
+
+%D Something similar can be used in the (re|)|definition
+%D of \type {\text}. This version is a variation on the one
+%D in the math module (see \type{m-math} and|/|or \type
+%D {m-newmat}).
+
+\unexpanded\def\mathtext
+ {\mathortext\domathtext\hbox}
+
+\def\domathtext#1%
+ {\mathchoice
+ {\dodomathtext\displaystyle\textface {#1}}%
+ {\dodomathtext\textstyle \textface {#1}}%
+ {\dodomathtext\textstyle \scriptface {#1}}%
+ {\dodomathtext\textstyle \scriptscriptface{#1}}}
+
+\def\dodomathtext#1#2#3% no \everymath !
+ %{\hbox{\everymath{#1}\switchtobodyfont [#2]#3}} % 15 sec
+ {\hbox{\everymath{#1}\setcurrentfontbody{#2}#3}} % 3 sec (no math)
+
+%D Because we may overload \type {\text} in other (structuring)
+%D macros, we say:
+
+\appendtoks \let\text\mathtext \to \everymathematics
+
+%D The next code is derived from plain \TEX.
+
+\newcount\interdisplaylinepenalty \interdisplaylinepenalty=100
+
+\newif\ifdt@p
+
+\def\displ@y
+ {\global\dt@ptrue
+ \openup\displayopenupvalue % was \openup\jot
+ \everycr
+ {\noalign
+ {\ifdt@p
+ \global\dt@pfalse
+ \ifdim\prevdepth>-\thousandpoint
+ \vskip-\lineskiplimit
+ \vskip\normallineskiplimit
+ \fi
+ \else
+ \penalty\interdisplaylinepenalty
+ \fi}}}
+
+\let\normaldispl@y\displ@y
+
+\def\displ@y{\resetdisplaymatheq\normaldispl@y}
+
+\def\m@th{\mathsurround\zeropoint} % obsolete
+
+%D Text in math:
+
+\def\mathortext
+ {\ifmmode
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+% \defineactivecharacter _ {\mathortext{_}{\_}} text_text $a^2$
-\def\utfmathcommanddefault#1#2#3{\ctxlua{
- local cmd = mathematics.utfmathcommand("#1","") or ""
- if cmd == "" then
- commands.cs("#2","#3")
- else
- commands.cs(cmd)
- end}}
+% force text mode, will be overloaded later
-% \let\math@normal@int\int \def\int{\math@normal@int\intlimits}
+\ifx\text\undefined \let\text\hbox \fi
\protect \endinput
diff --git a/tex/context/base/math-ini.tex b/tex/context/base/math-ini.tex
deleted file mode 100644
index 98738e500..000000000
--- a/tex/context/base/math-ini.tex
+++ /dev/null
@@ -1,688 +0,0 @@
-%D \module
-%D [ file=math-ini,
-%D version=2001.04.12,
-%D title=\CONTEXT\ Math Macros,
-%D subtitle=Basic Macros,
-%D author={Hans Hagen \& Taco Hoekwater},
-%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.
-
-% todo: make all definitions global since file loaded only once
-
-%D This module provides namespaces for math fonts, thereby
-%D permitting mixed usage of math fonts. Although not strictly
-%D needed, we also provide a family name mapping mechanism as
-%D used in the (original) AMS math definition files, but here
-%D these names can recursively be remapped and if needed,
-%D dynamically be changed. We've tried to minimize the number
-%D of definition commands and use plain \TEX\ definitions as
-%D fallback. We've tried to follow a couple of conventions
-%D from plain and AMS math in order to achieve backward
-%D compatinility. We also kept an eye on future usage of these
-%D modules in the perspective of MathML and unicode fonts.
-
-\unprotect
-
-\def\@ml@{@ml@} % math list (used for collection)
-\def\@mf@{@mf@} % math family
-%def\@mh@{@mh@} % math handler (not used)
-\def\@mt@{@mt@} % math token
-\def\@mc@{@mc@} % math collection
-
-\def\@@mathlimopcomm#1{\mathop{#1}} %no \limits
-\def\@@mathnolopcomm#1{\mathop{#1}\nolimits}
-\def\@@mathboxcomm #1{\dontleavehmode\hbox{$\m@th#1$}}
-
-\chardef\mathordcode = 0 \let\mathordcomm \mathord
-\chardef\mathopcode = 1 \let\mathopcomm \mathop
-\chardef\mathbincode = 2 \let\mathbincomm \mathbin
-\chardef\mathrelcode = 3 \let\mathrelcomm \mathrel
-\chardef\mathopencode = 4 \let\mathopencomm \mathopen
-\chardef\mathclosecode = 5 \let\mathclosecomm \mathclose
-\chardef\mathpunctcode = 6 \let\mathpunctcomm \mathpunct
-\chardef\mathalphacode = 7 \let\mathalphacomm \firstofoneargument
-\chardef\mathinnercode = 0 \let\mathinnercomm \mathinner
-\chardef\mathnothingcode= 0 \let\mathnothingcomm \firstofoneargument
-\chardef\mathlimopcode = 1 \let\mathlimopcomm \@@mathlimopcomm
-\chardef\mathnolopcode = 1 \let\mathnolopcomm \@@mathnolopcomm
-\chardef\mathchoicecode = 0 \let\mathchoicecomm \@@mathchoicecomm
-\chardef\mathboxcode = 0 \let\mathboxcomm \@@mathboxcomm
-
-\chardef\mathaccentcode = 8
-\chardef\mathradicalcode= 9
-
-\def\@@mathchoicecomm#1{[todo #1]}
-
-\def\puremathcode#1{\the\csname math#1code\endcsname}
-\def\puremathcomm#1{\csname math#1comm\endcsname}
-
-\newif\iftracemathcollection
-
-% Simple variant:
-%
-% \def\dohandlemathtoken#1%
-% {\csname\@mt@
-% \ifcsname\@mt@\mathcollection#1\endcsname
-% \mathcollection
-% \else\ifcsname\@mt@\nomathcollection#1\endcsname
-% \nomathcollection
-% \fi\fi
-% #1\endcsname}
-
-%D Because a command can have a different meaning in math
-%D and in text mode, we provide a selector. We also provide
-%D the pure alternatives as \type {\mathcharacter} and \type
-%D {\textcharacter}.
-
-\ifx\dohandlecommand\undefined \wait \fi % troubles !
-
-\def\mathcharacter\dohandlemathtoken
-\def\textcharacter\dohandlecommand % better \dohandletexttoken
-
-% More clever layout:
-%
-% \def\dohandlemathtoken#1%
-% {\csname
-% \ifmmode
-% \ifcsname\@mt@\mathcollection#1\endcsname
-% \@mt@\mathcollection
-% \else\ifcsname\@mt@\nomathcollection#1\endcsname
-% \@mt@\nomathcollection
-% \else\ifcsname\characterencoding#1\endcsname
-% \characterencoding
-% \else
-% \nocharacterencoding
-% \fi\fi\fi
-% \else
-% \ifcsname\characterencoding#1\endcsname
-% \characterencoding
-% \else
-% \nocharacterencoding
-% \fi
-% \fi
-% #1\endcsname}
-%
-% fallback to math when in text mode (handy for unicode vectors)
-
-\def\dohandlemathtoken#1%
- {\csname
- \ifmmode
- \ifcsname\@mt@\mathcollection#1\endcsname
- \@mt@\mathcollection
- \else\ifcsname\@mt@\nomathcollection#1\endcsname
- \@mt@\nomathcollection
- \else\ifcsname\characterencoding#1\endcsname
- \characterencoding
- \else
- \nocharacterencoding
- \fi\fi\fi
- \else
- \ifcsname\characterencoding#1\endcsname
- \characterencoding
- \else\ifcsname\nocharacterencoding#1\endcsname
- \nocharacterencoding
- \else\ifcsname\@mt@\mathcollection#1\endcsname
- \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
- \else\ifcsname\@mt@\nomathcollection#1\endcsname
- \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
- \else
- \nocharacterencoding
- \fi\fi\fi\fi
- \fi
- #1\endcsname}
-
-%D Now we redefine the text encoding handler.
-
-%D A better fallback:
-
-% Just ETEX which is the default nowadays.
-
-\def\dohandlemathtoken#1%
- {\csname
- \ifmmode
- \ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
- \@mt@\mathcollection:\outerencoding
- \else\ifcsname\@mt@\mathcollection#1\endcsname
- \@mt@\mathcollection
- \else\ifcsname\@mt@\nomathcollection#1\endcsname
- \@mt@\nomathcollection
- \else\ifcsname\characterencoding#1\endcsname
- \characterencoding
- \else
- \nocharacterencoding
- \fi\fi\fi\fi
- \else
- \ifcsname\characterencoding#1\endcsname
- \characterencoding
- \else\ifcsname\nocharacterencoding#1\endcsname
- \nocharacterencoding
- \else\ifcsname\@mt@\mathcollection:\outerencoding#1\endcsname
- \@mt@\mathcollection:\outerencoding
- \else\ifcsname\@mt@\mathcollection#1\endcsname
- \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\mathcollection
- \else\ifcsname\@mt@\nomathcollection#1\endcsname
- \strippedcsname\mathematics\expandafter\endcsname\csname\@mt@\nomathcollection
- \else
- \nocharacterencoding
- \fi\fi\fi\fi\fi
- \fi
- #1\endcsname}
-
-\let\dohandlecommand\dohandlemathtoken
-
-\def\definefamilysynonym
- {\dotripleempty\dodefinefamilysynonym}
-
-\def\dodefinefamilysynonym[#1][#2][#3]% [mathcollection] [] []
- {\ifthirdargument
- \setvalue{\@mf@#1#2}{#3}%
- \else
- \setvalue{\@mf@ #1}{#2}%
- \fi}
-
-\let\mathsubfamily\empty
-
-\def\purefamily #1{\csname \truefamily{#1}\mathsubfamily\s!fam\endcsname}
-\def\purefamilyhex#1{\csname hex\truefamily{#1}\mathsubfamily\s!fam\endcsname}
-
-\def\truefamily#1%
- {\ifcsname\@mf@\mathcollection#1\endcsname
- \@EA\truefamily\csname\@mf@\mathcollection#1\endcsname
- \else\ifcsname\@mf@#1\endcsname
- \@EA\truefamily\csname\@mf@#1\endcsname
- \else\ifcsname\@mf@\nomathcollection#1\endcsname
- \@EA\truefamily\csname\@mf@\nomathcollection#1\endcsname
- \else
- #1%
- \fi\fi\fi}
-
-\newif\ifdynamicmathfamilies \dynamicmathfamiliestrue % true per 2003.11.25; needed for mixed bold math
-
-\let\normalpurefamilyhex\purefamilyhex
-
-% todo: reset collection (tok legen) en opnieuw laden met true
-
-\def\definemathsymbol
- {\dosixtupleempty\dodefinemathsymbol}
-
-\def\dodefinemathsymbol[#1][#2][#3][#4][#5][#6]%
- {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
- \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
- \setevalue{\@mt@\mathcollection#1}%
- {\ifsixthargument
- \ifnum\puremathcode{#2}=\mathradicalcode
- \radical"%
- \else
- \delimiter"%
- \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
- \fi
- \purefamilyhex{#3}\uchexnumbers{#4}%
- \purefamilyhex{#5}\uchexnumbers{#6}\space
- \else\iffourthargument
- \ifnum\puremathcode{#2}=\mathaccentcode
- \mathaccent\else\mathchar
- \fi
- "\ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
- \purefamilyhex{#3}\uchexnumbers{#4}\space
- \fi\fi}%
- \let\purefamilyhex\normalpurefamilyhex
- \tracemathsymbol{#1}}
-
-\def\tracemathsymbol#1%
- {\iftracemathcollection
- {\endgraf
- \hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}
- \endgraf}%
- \fi}
-
-\def\definemathcharacter
- {\dosixtupleempty\dodefinemathcharacter}
-
-% \def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
-% {\setmathtoks
-% \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
-% \doifnumberelse{#1}
-% {\scratchcounter#1}
-% {\scratchcounter\@EA`\string#1}%
-% \appendetoks
-% \ifsixthargument
-% \delcode\the\scratchcounter="%
-% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
-% \purefamilyhex{#3}\uchexnumbers{#4}%
-% \purefamilyhex{#5}\uchexnumbers{#6}\space
-% \else\iffourthargument
-% \mathcode\the\scratchcounter="%
-% \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
-% \purefamilyhex{#3}\uchexnumbers{#4}\space
-% \fi\fi\to\mathtoks
-% \let\purefamilyhex\normalpurefamilyhex
-% \tracemathcharacter{#1}}
-
-\newtoks\mathscratchtoks
-
-\def\definemathcharacter
- {\chardef\mathcharactermode\zerocount
- \dosixtupleempty\dodefinemathcharacter}
-
-\def\redefinemathcharacter
- {\chardef\mathcharactermode\plusone
- \dosixtupleempty\dodefinemathcharacter}
-
-\def\dodefinemathcharacter[#1][#2][#3][#4][#5][#6]%
- {\ifcase\mathcharactermode
- \setmathtoks
- \or
- \let\mathtoks\mathscratchtoks \mathtoks\emptytoks
- \fi
- \ifdynamicmathfamilies \let\purefamilyhex\relax \fi
- \doifnumberelse{#1}
- {\scratchcounter#1}
- {\scratchcounter\@EA`\string#1}%
- \appendetoks
- \ifsixthargument
- \delcode\the\scratchcounter="%
- \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
- \purefamilyhex{#3}\uchexnumbers{#4}%
- \purefamilyhex{#5}\uchexnumbers{#6}\space
- \else\iffourthargument
- \mathcode\the\scratchcounter="%
- \ifnum\puremathcode{#2}>7 0\else\puremathcode{#2}\fi
- \purefamilyhex{#3}\uchexnumbers{#4}\space
- \fi\fi
- \to \mathtoks
- \let\purefamilyhex\normalpurefamilyhex
- \ifcase\mathcharactermode
- \expandafter\tracemathcharacter
- \or
- \the\mathtoks
- \mathtoks\emptytoks
- \expandafter\gobbleoneargument
- \fi{#1}} % maybe lookahead
-
-\def\tracemathcharacter#1%
- {\iftracemathcollection
- {\endgraf
- \doifnumberelse{#1}
- {\hbox{\tttf\rawcharacter{#1}~:~{\mathematics{\rawcharacter{#1}}}}}
- {\hbox{\type{#1}~:~{\mathematics{#1}}}}
- \endgraf}%
- \fi}
-
-\def\definemathcommand
- {\dotripleempty\dodefinemathcommand}
-
-\def\dodefinemathcommand[#1][#2][#3]#4% command class args meaning
- {\unexpanded\setgvalue{#1}{\dohandlemathtoken{#1}}%
- \ifthirdargument
- \processaction
- [#3]
- [one=>\setvalue{\@mt@\mathcollection#1}##1{\puremathcomm{#2}{#4{##1}}},
- two=>\setvalue{\@mt@\mathcollection#1}##1##2{\puremathcomm{#2}{#4{##1}{##2}}}]%
- \else\ifsecondargument
- \setvalue{\@mt@\mathcollection#1}{\puremathcomm{#2}{#4}}%
- \else
- \setvalue{\@mt@\mathcollection#1}{\puremathcomm{nothing}{#4}}%
- \fi\fi
- \tracemathcommand{#1}}
-
-\def\tracemathcommand#1%
- {\iftracemathcollection
- \endgraf\hbox{\tex{#1}~:~{\mathematics{\getvalue{#1}{}}}}\endgraf
- \fi}
-
-\def\startmathcollection[#1]%
- {\pushmacro\mathcollection
- \setmathcollection{#1}}
-
-\def\setmathcollection#1%
- {\edef\mathcollection{#1}%
- \doifundefined{\@ml@\mathcollection}
- {\expandafter\newtoks\csname\@ml@\mathcollection\endcsname}}
-
-\def\stopmathcollection
- {\popmacro\mathcollection}
-
-\def\startrawmathcollection
- {\startmathcollection}
-
-\def\stoprawmathcollection
- {\stopmathcollection}
-
-\newtoks\mathtoks
-
-\def\setmathtoks
- {\@EA\let\@EA\mathtoks\csname\@ml@\mathcollection\endcsname}
-
-\def\currentmathcollection{\mathcollection}
-
-\let\nomathcollection\s!default
-
-\def\enablemathcollection[#1]%
- {\doifnot{#1}\s!default
- {\setmathcollection\s!default
- \the\csname\@ml@\mathcollection\endcsname}%
- \setmathcollection{#1}%
- \the\csname\@ml@\mathcollection\endcsname}
-
-% hook 'm into the font mechanism
-
-\definefilesynonym[\f!mathprefix\s!default][\f!mathprefix tex]
-
-\def\usemathcollection
- {\dodoubleempty\dousemathcollection}
-
-\def\dousemathcollection[#1][#2]%
- {\pushmacro\fontclass
- \pushmacro\mathclass
- \ifsecondargument
- \edef\fontclass{#1}%
- \edef\mathclass{#2}%
- \else
- \edef\mathclass{#1}%
- \fi
- \doinputonce{\truefilename{\f!mathprefix\mathclass}}%
- \doifsomething\fontclass{\setevalue{\@mc@\fontclass\@mc@}{\mathclass}}%
- \popmacro\mathclass
- \popmacro\fontclass}
-
-\let\mathclass\nomathcollection
-
-\letvalue{\@mc@\@mc@}\nomathcollection
-
-% \def\autoenablemathcollection
-% {\doifdefinedelse{\@mc@\fontclass\@mc@}
-% {\enablemathcollection[\getvalue{\@mc@\fontclass\@mc@}]}
-% {\enablemathcollection[\s!default]}} % ? ? ?
-
-\def\autoenablemathcollection
- {\expanded{\enablemathcollection[\executeifdefined{\@mc@\fontclass\@mc@}\nomathcollection]}}
-
-\appendtoks\autoenablemathcollection\to\mathstrategies
-
-\fetchruntimecommand \showmathcharacters {\f!mathprefix\s!run}
-\fetchruntimecommand \showmathtoken {\f!mathprefix\s!run}
-
-\def\resetmathcollection[#1]%
- {\def\mathcollection{#1}%
- \forgetdoingonce{\f!mathprefix\mathcollection}%
- \setmathtoks
- \ifx\mathtoks\relax\else\mathtoks\emptytoks\fi}
-
-%D \macros
-%D {ifmathpunctuation, enablemathpunctuation,
-%D definemathpunctuation}
-%D
-%D This will replace periods by comma's:
-%D
-%D \starttyping
-%D \definemathpunctuation . textcomma textperiod
-%D \definemathpunctuation , textcomma textcomma
-%D
-%D \appendtoks
-%D \redefinemathcharacter [.] [ord] [mi] ["3B]%
-%D \to \everymathpunctuation
-%D \stoptyping
-
-% \newif\ifmathpunctuation
-%
-% \def\enablemathpunctuation{\mathpunctuationtrue}
-%
-% \def\definemathpunctuation #1 #2 #3 %
-% {\appendtoks
-% \initializemathpunctuation{#1}{#2}{#3}%
-% \to\everymathematics}
-%
-% \def\initializemathpunctuation#1#2#3% sloowww
-% {\ifmathpunctuation % hm move this test to everymath, or better a separate token list
-% \mathcode`#1="8000
-% \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}%
-% \fi}
-%
-% \unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
-% {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
-% \futurelet\nexttoken\next}
-
-\newtoks\everymathpunctuation
-
-\def\enablemathpunctuation % can be called inside math, so after \everymathematics
- {\the\everymathpunctuation
- \appendtoksonce
- \the\everymathpunctuation
- \to\everymathematics}
-
-\def\definemathpunctuation #1 #2 #3 %
- {\appendtoks
- \initializemathpunctuation{#1}{#2}{#3}%
- \to\everymathpunctuation}
-
-\def\initializemathpunctuation#1#2#3% sloowww
- {\mathcode`#1="8000
- \defineactivecharacter #1 {\dohandlemathpunctuation{#2}{#3}}}
-
-\unexpanded\def\dohandlemathpunctuation#1#2% \if fails in mathml interval
- {\def\next{\csname\ifx\space\nexttoken#2\else#1\fi\endcsname}%
- \futurelet\nexttoken\next}
-
-%D \startbuffer
-%D \enablemathpunctuation$(1,2) (1, 2) (1{,}2) \hbox{foo, not bar}$
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \blank{\getbuffer}\blank
-
-%D needed for sin, cos etc
-
-\def\mfunction #1{{\mr#1}}
-
-% \def\mlimitsfunction #1{\mathlimopcomm{{\mr#1}}
-% \def\mnolimitsfunction#1{\mathnolopcomm{{\mr#1}}
-
-%D Taco posted this solution as response to a mail by Olivier, so
-%D let's integrate it here.
-
-% \def\setmathfunctionstyle#1% rm ss tt
-% {\def\mfunction##1% no families, just scaling a la text
-% {\mathchoice
-% {\hbox{\csname#1\endcsname\tf ##1}}
-% {\hbox{\csname#1\endcsname\tf ##1}}
-% {\hbox{\csname#1\endcsname\tfx ##1}}
-% {\hbox{\csname#1\endcsname\tfxx##1}}}}
-
-\def\currentmscaledstyle{rm} % will be plugged into the typeface text=ss option
-
-\def\setmathfunctionstyle#1% rm ss tt
- {\doifsomething{#1}
- {\def\currentmscaledstyle{#1}%
- \def\mathopnolimits##1{\mathop{\mscaledtext{##1}}\nolimits}%
- \def\mfunction##1{\mscaledtext{##1}}}}
-
-\def\mscaledtext#1%
- {\mathchoice
- {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
- {\hbox{\csname\currentmscaledstyle\endcsname\tf #1}}
- {\hbox{\csname\currentmscaledstyle\endcsname\tfx #1}}
- {\hbox{\csname\currentmscaledstyle\endcsname\tfxx#1}}}
-
-%D We can force the way functions are typeset by manipulating the text
-%D option:
-%D
-%D \starttyping
-%D \definetypeface[iwona][ss][sans][iwona][default][encoding=texnansi]
-%D \definetypeface[iwona][mm][math][iwona][default][encoding=texnansi,text=ss]
-%D \stoptyping
-%D
-%D This hooks into the math handler with:
-
-\appendtoks
- \setmathfunctionstyle\currentmathtextstyle
-\to \everybodyfont
-
-%D Usage:
-%D
-%D \starttyping
-%D \setmathfunctionstyle\fontstyle % or {rm} or {ss} or ..
-%D \rm test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
-%D \ss test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
-%D \tt test $\sin{(x^{\sin(x^{\sin(x)})})}$ test
-%D \stoptyping
-
-\edef\hexmrfam {0} \edef\hexbsfam {8}
-\edef\hexmifam {1} \edef\hexbifam {9}
-\edef\hexsyfam {2} \edef\hexscfam {A}
-\edef\hexexfam {3} \edef\hextffam {B}
-\edef\hexitfam {4} \edef\hexmafam {C}
-\edef\hexslfam {5} \edef\hexmbfam {D}
-\edef\hexbffam {6} \edef\hexmcfam {E}
-\edef\hexnnfam {7} \edef\hexmdfam {F}
-
-\definefamilysynonym [default] [letters] [mr]
-\definefamilysynonym [default] [operators] [sy]
-\definefamilysynonym [default] [lcgreek] [mi]
-\definefamilysynonym [default] [ucgreek] [mr]
-\definefamilysynonym [default] [vargreek] [mi]
-\definefamilysynonym [default] [mitfamily] [mi]
-\definefamilysynonym [default] [calfamily] [sy]
-
-\definefamilysynonym [default] [0] [mr]
-\definefamilysynonym [default] [1] [mi]
-\definefamilysynonym [default] [2] [sy]
-\definefamilysynonym [default] [3] [ex]
-
-\enablemathcollection[default]
-
-\usemathcollection [default] [tex]
-\usemathcollection [default] [ams]
-\usemathcollection [default] [uni]
-
-\enablemathcollection[default]
-
-%D Some goodies:
-
-\def\Angstrom{\nomathematics{\Aring}}
-
-%D Bold math:
-%D
-%D \starttyping
-%D \usetypescript [lucida] [texnansi]
-%D
-%D \definetypeface [boldmath] [rm] [serif]
-%D [lucida] [default] [encoding=texnansi]
-%D \definetypeface [boldmath] [tt] [mono]
-%D [lucida] [default] [encoding=texnansi]
-%D \definetypeface [boldmath] [ss] [sans]
-%D [lucida] [default] [encoding=texnansi]
-%D \definetypeface [boldmath] [mm] [boldmath]
-%D [lucida] [default] [encoding=texnansi]
-%D
-%D \switchtobodyfont[lucida,10pt]
-%D
-%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
-%D
-%D \switchtobodyfont[boldmath,10pt]
-%D
-%D \showmathtoken{Gamma} $\Gamma \Delta \alpha \delta \zeta$
-%D \stoptyping
-
-%D \macros
-%D {nonknuthmode, donknuthmode}
-%D
-%D The underscore is frequently used in manuals but unfortunately \TEX\ prefers
-%D it to be a math specific character. And since computer modern fonts didn't
-%D have an underscore, one had to use commands to fake one. Nowadays we do
-%D have underscores in latin modern, and since all other fonts have them, we
-%D decided to get away from the restriction to use the underscore character in
-%D text mode.
-%D
-%D \starttyping
-%D \def\test#1{#1}
-%D
-%D \nonknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
-%D
-%D \donknuthmode $x_2$ x_2 \test{$x_2$} \test{x_2}
-%D \stoptyping
-%D
-%D The result is as expected: the first line typesets ok, while the second
-%D one triggers an error message.
-
-\bgroup
-
- \ifx\normalsuber\undefined \def\normalsuber{_} \fi
- \ifx\normalsuper\undefined \def\normalsuper{^} \fi
-
- \catcode`_=\active
- \catcode`^=\active
-
- \gdef\nonknuthmode
- {\appendtoks\let_\normalsuber\let^\normalsuper\to\everymathematics
- \mathcode`_="8000
- \mathcode`^="8000
- \catcode`_=\@@other
- \catcode`^=\@@other
- \let\nonknuthmode\relax}
-
- \gdef\donknuthmode
- {\catcode`_=\@@subscript
- \catcode`^=\@@superscript}
-
-\egroup
-
-%D \macros
-%D {checkdelimiters, fakeleftdelimiter, fakerightdelimiter}
-%D
-%D Handy for non matching situations (as with mathml):
-%D
-%D \starttyping
-%D \checkdelimiters{... bla bla ...}
-%D \fakeleftdelimiter
-%D ... bla bla ...
-%D \fakerightdelimiter
-%D \stoptyping
-
-\newcount\delimitercount
-
-\def\leftfakedelimiter {\advance\delimitercount\minusone\gobbleoneargument}%
-\def\rightfakedelimiter{\advance\delimitercount\plusone \gobbleoneargument}%
-
-\def\checkdelimiters#1%
- {\delimitercount\zerocount
- \setbox\scratchbox\hbox\bgroup
- \let\left \leftfakedelimiter
- \let\right\rightfakedelimiter
- $#1\expandafter$\expandafter
- \egroup
- \expandafter\delimitercount\the\delimitercount\relax}
-
-\def\fakeleftdelimiter {\ifnum\delimitercount>\zerocount\left .\fi}
-\def\fakerightdelimiter{\ifnum\delimitercount<\zerocount\right.\fi}
-
-% \def\scaledmathdelimiter#1#2%
-% {\begingroup
-% \scratchdimen\lineheight
-% \hbox{$\left#2\vbox\!!to#1\scratchdimen{}\right.\n@space$}%
-% \endgroup}
-%
-% \let\scaledmathdelimiter\@@dobig
-%
-% \def\scaledmathopen #1#2{\mathopen {\scaledmathdelimiter{#1}{#2}}}
-% \def\scaledmathclose#1#2{\mathclose{\scaledmathdelimiter{#1}{#2}}}
-
-%D Needed for unicode:
-
-\def\nulloperator{\mathortext{\mathop{\null}}{\null}}
-
-%D Plugins.
-
-\loadmarkfile{math-ini}
-
-\protect \endinput
-
-\tracemathcollectiontrue
- \input math-tex \page
-\setupbodyfont[ams] \enablemathcollection[default] \input math-ams \page
-\setupbodyfont[lbr] \enablemathcollection[lbr] \input math-lbr \page
-\setupbodyfont[eul] \enablemathcollection[eul] \input math-eul \stoptext
diff --git a/tex/context/base/math-inl.mkiv b/tex/context/base/math-inl.mkiv
new file mode 100644
index 000000000..acbf02de7
--- /dev/null
+++ b/tex/context/base/math-inl.mkiv
@@ -0,0 +1,357 @@
+%D \module
+%D [ file=math-inl,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Inline,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Math Macros / Inline}
+
+\unprotect
+
+%D \macros
+%D {...}
+%D
+%D New and experimental: snapping big inline math!
+
+\newconditional\halfcrazymathlines % \settrue\halfcrazymathlines
+\newconditional\crazymathsnapping % \settrue\crazymathsnapping
+
+\appendtoks
+ \doifelse\@@mtgrid\v!yes \settrue\setfalse\crazymathsnapping
+ \doifelse\@@mtstep\v!halfline\settrue\setfalse\halfcrazymathlines
+\to \everysetuptextformulas
+
+\setuptextformulas
+ [\c!grid=\v!yes,
+ \c!step=\v!line]
+
+\newcount\crazymathhack
+
+\let\lastcrazymathline \!!zeropoint
+\let\lastcrazymathpage \!!zerocount
+\let\lastcrazymathprelines \!!zerocount
+\let\lastcrazymathpostlines\!!zerocount
+
+\def\crazymathtag{amh:\the\crazymathhack}
+\def\crazytexttag{\v!text:\lastcrazymathpage}
+
+\def\crazymathindent{\hskip\MPx\crazymathtag\hskip-\MPx\crazytexttag}
+
+\def\flushcrazymathbox
+ {\nextboxht\strutheight
+ \nextboxdp\strutdepth
+ \hbox{\iftracegridsnapping\ruledhbox\fi{\flushnextbox}}}
+
+\def\snappedinlineformula
+ {\dosingleempty\dosnappedinlineformula}
+
+%D \starttabulate[|Tl|l|]
+%D \NC - \NC half lines \NC \NR
+%D \NC + \NC full lines \NC \NR
+%D \NC = \NC force \NC \NR
+%D \NC < \NC force, minus pre \NC \NR
+%D \NC > \NC force, minus post \NC \NR
+%D \stoptabulate
+
+\def\inlinemathmargin{1pt}
+
+\settrue\autocrazymathsnapping
+
+% FROM NOW ON, CHANGES AS OPTIONS
+
+% TODO: SKYLINE (PREV LINE POS SCAN)
+
+% we can rewrite this in lua but maybe we don't need it
+% any more when we have proper snapping anyway
+
+\def\dosnappedinlineformula[#1]#2%
+ {\ifvmode\dontleavehmode\fi % tricky
+ \strut % prevents funny space at line break
+ \begingroup % interesting: \bgroup can make \vadjust disappear
+ \ifconditional\crazymathsnapping
+ \ifgridsnapping
+ \checktextbackgrounds % we need pos tracking, to be made less redundant
+ \donetrue
+ \else
+ \donefalse
+ \fi
+ \else
+ \donefalse
+ \fi
+ \!!doneafalse % forced or not auto
+ \!!donebfalse % too heigh
+ \!!donecfalse % too low
+ \!!donedfalse % less before
+ \!!doneefalse % less after
+ \ifdone
+ \setbox\nextbox\hbox{$#2$}%
+ \iftracegridsnapping
+ \setbox\nextbox\ruledhbox
+ {\incolortrue\localcolortrue
+ \backgroundline[gray]{\showstruts\strut\flushnextbox}}%
+ \fi
+ \def\docommand##1%
+ {\doif{##1}-{\settrue \halfcrazymathlines}%
+ \doif{##1}+{\setfalse\halfcrazymathlines}%
+ \doif{##1}={\!!doneatrue}%
+ \doif{##1}<{\!!donedtrue}%
+ \doif{##1}>{\!!doneetrue}}%
+ \processcommalist[#1]\docommand
+ \if!!doneb
+ \if!!donec \else
+ \setfalse\halfcrazymathlines
+ \fi
+ \else
+ \if!!donec
+ \setfalse\halfcrazymathlines
+ \fi
+ \fi
+ \donefalse
+ \if!!donea
+ \donetrue
+ \scratchdimen \nextboxht
+ \advance\scratchdimen .5\lineheight
+ \nextboxht\scratchdimen
+ \scratchdimen \nextboxdp
+ \advance\scratchdimen .5\lineheight
+ \nextboxdp\scratchdimen
+ \else\ifdim\nextboxht>\strutht
+ \donetrue
+ \else\ifdim\nextboxdp>\strutdp
+ \donetrue
+ \fi\fi\fi
+ \ifconditional\autocrazymathsnapping \else \if!!donea \else
+ % don't compensate, just snap to strut
+ \donefalse
+ % signal for next else, snap line to strut
+ \!!doneatrue
+ \fi \fi
+ \fi
+ \ifdone
+ % analyze height
+ \scratchdimen\inlinemathmargin
+ \advance\scratchdimen \strutht
+ \ifdim\nextboxht<\scratchdimen \else \!!donebtrue \fi
+ % analyze depth
+ \scratchdimen\inlinemathmargin
+ \advance\scratchdimen \strutdp
+ \ifdim\nextboxdp<\scratchdimen \else \!!donectrue \fi
+ % analyzed or forced
+ \ifdone
+ \global\advance\crazymathhack\plusone
+ \donefalse
+ \ifnum\MPp\crazymathtag=\lastcrazymathpage\relax
+ \ifdim\MPy\crazymathtag=\lastcrazymathline\relax
+ \donetrue
+ \fi
+ \fi
+ \ifnum\MPp\crazymathtag=\zerocount \donefalse \fi
+ \ifdim\MPy\crazymathtag=\zeropoint \donefalse \fi
+ \ifdone
+ % same page and same line
+ \else
+ \global\let\lastcrazymathprelines \!!zerocount
+ \global\let\lastcrazymathpostlines\!!zerocount
+ \xdef\lastcrazymathpage{\MPp\crazymathtag}%
+ \xdef\lastcrazymathline{\MPy\crazymathtag}%
+ \fi
+ \if!!doneb
+ % \getrawnoflines\nextboxht
+ \scratchdimen\nextboxht
+ \advance\scratchdimen-\strutht
+ \getnoflines\scratchdimen
+ \if!!doned \advance\noflines\minusone \fi
+ \scratchcounter\noflines
+ \advance\noflines-\lastcrazymathprelines\relax
+ \ifnum\noflines>\zerocount
+ \xdef\lastcrazymathprelines{\the\scratchcounter}%
+ \scratchdimen\noflines\lineheight
+ \ifconditional\halfcrazymathlines
+ \advance\scratchdimen-.5\lineheight
+ \fi
+ \advance\scratchdimen-\strutdepth
+ \setbox\scratchbox\null
+ \wd\scratchbox2\bodyfontsize
+ \ht\scratchbox\scratchdimen
+ \dp\scratchbox\strutdepth
+ %%% top correction code (see below)
+ \normalvadjust pre
+ {%\allowbreak % sometimes breaks spacing
+ \forgetall
+ \crazymathindent
+ \iftracegridsnapping
+ \setbox\scratchbox\hbox
+ {\incolortrue\localcolortrue\green
+ \ruledhbox{\box\scratchbox}}%
+ \fi
+ \box\scratchbox
+ \endgraf
+ \nobreak}%
+ \else\ifnum\scratchcounter>\zerocount
+ \normalvadjust pre
+ {\nobreak}%
+ \fi\fi
+ \fi
+ \if!!donec
+ % \getrawnoflines\nextboxdp
+ \scratchdimen\nextboxdp
+ \advance\scratchdimen-\strutdp
+ \getnoflines\scratchdimen
+ \if!!donee \advance\noflines\minusone \fi
+ \scratchcounter\noflines
+ \advance\noflines-\lastcrazymathpostlines\relax
+ \ifnum\noflines>\zerocount
+ \donetrue
+ \else\ifnum\lastcrazymathpostlines=\zerocount
+ \donetrue
+ \else
+ \donefalse
+ \fi\fi
+ \else
+ \donefalse
+ \fi
+ \ifdone
+ \xdef\lastcrazymathpostlines{\the\scratchcounter}%
+ \ifnum\lastcrazymathpostlines=\zerocount
+ \global\let\lastcrazymathpostlines\!!plusone
+ \fi
+ \hbox{\setposition\crazymathtag\flushcrazymathbox}%
+ \scratchdimen\noflines\lineheight
+ \advance\scratchdimen-\lineheight
+ \advance\scratchdimen+\strutheight
+ \ifdim\scratchdimen>\zeropoint \else
+ \scratchdimen\strutheight % todo : test for half lines
+ \fi
+ \ifconditional\halfcrazymathlines
+ \advance\scratchdimen-.5\lineheight
+ \fi
+ \setbox\scratchbox\null
+ \wd\scratchbox2\bodyfontsize
+ \ht\scratchbox\scratchdimen
+ \dp\scratchbox\strutdepth
+ \normalvadjust
+ {\forgetall
+ \crazymathindent
+ \iftracegridsnapping
+ \setbox\scratchbox\hbox
+ {\incolortrue\localcolortrue\color[blue]{\ruledhbox{\box\scratchbox}}}%
+ \fi
+ \box\scratchbox
+ \endgraf
+ % precaution: else we stick below the text bottom
+ \ifconditional\halfcrazymathlines
+ \allowbreak
+ \else
+ \vskip-\lineheight
+ \vskip \lineheight
+ \fi}%
+ \else
+ \hbox{\setposition\crazymathtag\flushcrazymathbox}%
+ \fi
+ \else
+ \flushcrazymathbox
+ \fi
+ \else\if!!donea
+ \flushcrazymathbox
+ \else
+ \mathematics{#2}%
+ \fi\fi
+ \endgroup}
+
+\let\tform\mathematics
+\let\gform\snappedinlineformula
+
+% test set:
+%
+% \startbuffer
+% Crazy math \gform {1+x} or \gform {\dorecurse {100} {1+} 1 =
+% 101} and even gore crazy \gform {2^{2^2}_{1_1}}
+% again\dorecurse {20} { and again} \gform {\sqrt {\frac
+% {x^{5^5}} {\frac {1} {2}}}} even gore\dorecurse {50} { and
+% gore} \tform {\dorecurse {12} {\gform {\sqrt {\frac
+% {x^{5^5}} {3}}}+\gform {\sqrt {\frac {x^{5^5}} {\frac {1}
+% {2}}}}+}x=10}\dorecurse{20} { super crazy math}: \tform
+% {\dorecurse {30} {\gform {\sqrt {\frac {x^{5^5}} {3}}}+
+% \gform {\sqrt {\frac {x^{5^5}} {\frac {1} {2}}}}+ }x = 10},
+% and we're\dorecurse {20} { done}!
+% \stopbuffer
+%
+% \setupcolors[state=start] \setuppapersize[S6][S6]
+%
+% \showgrid \tracegridsnappingtrue \showstruts
+%
+% \starttext
+% \setuplayout[grid=yes,lines=15]\getbuffer \page
+% \setuplayout[grid=yes,lines=16]\getbuffer \page
+% \setuplayout[grid=yes,lines=17]\getbuffer \page
+% \setuplayout[grid=yes,lines=18]\getbuffer \page
+% \setuplayout[grid=yes,lines=19]\getbuffer \page
+% \stoptext
+%
+% test
+%
+% \startregels
+% \gform[<]{35 \cdot p^{\frac{3}{4}} = 70}
+% \gform{12{,}4 \cdot d^3 = 200}
+% \gform{a \cdot x^b}.
+% \gform{12x^6 \cdot \negative 3x^4}
+% \gform{\frac{12x^6}{\negative 3x^4}}
+% \gform{(4x^2)^3}
+% \gform{4x \sqrt{x} \cdot 3x^2}
+% \gform{\frac{2x^4}{4x \sqrt{x}}}
+% \gform{y = a \cdot x^b}.
+% \gform{y_1 = \frac{15x^2}{x}}
+% \gform{y_2 = x \cdot \sqrt{x}}
+% \gform{y_3 = \frac{6x^3}{x^2}}
+% \gform[<]{y_4 = \left(2x^2\right)^{\frac{1}{2}}}
+% \gform{y_1 = \frac{4x^5}{x^2}}
+% \gform{y_2 = 4 \cdot \sqrt{x}}
+% \gform{y_3 = 4x^3}
+% \gform{y_4 = \frac{100x}{\sqrt{x}}}
+% \gform[<]{y_5 = 4 \cdot x^{\frac{1}{2}}}
+% \gform{y_6 = \frac{1}{2} x \cdot 4x^2}
+% \gform{y_7 = 2 \cdot x^3}
+% \gform{y_8 = 100 \cdot x^{\frac{1}{2}}}
+% \gform{4x^8 \cdot 8x^3}
+% \gform{\frac{4x^8}{8x^3}}
+% \gform{\left(\negative3x^4\right)^3}
+% \gform{x^3 \sqrt{x} \cdot 3x^2}
+% \gform{\frac{6x^3}{x^2 \sqrt{x}}}
+% \gform{\frac{6}{2x^4}}
+% \gform{\frac{1}{3x^6}}
+% \gform{\frac{12x^8}{4x^{10}}}
+% \gform{\frac{4}{\sqrt{x}}}
+% \gform{\frac{1}{2x \sqrt{x}}}
+% \gform{\frac{2{,}25}{p} = 0{,}35}
+% \gform{4{,}50 + \frac{300}{k} = 4{,}70}
+% \gform{\frac{1200}{k+12} - 42 = 6}
+% \stopregels
+
+%D \macros
+%D {enableautomath}
+%D
+%D The next one can be dangerous, but handy in controlled
+%D situations.
+
+\bgroup \catcode`\$=\active
+
+\gdef\enableautomath
+ {\catcode`\$=\active
+ \def$##1${\snappedinlineformula{##1}}}
+
+% \gdef\enableautomath
+% {\catcode`\$=\active
+% \def${\doifnextcharelse$\doautodmath\doautoimath}%
+% \def\doautoimath##1${\snappedinlineformula{##1}}%
+% \def\doautodmath$##1$${\startformula##1\stopformula}}
+
+\egroup
+
+\protect \endinput
diff --git a/tex/context/base/math-int.mkiv b/tex/context/base/math-int.mkiv
new file mode 100644
index 000000000..8ac2d4776
--- /dev/null
+++ b/tex/context/base/math-int.mkiv
@@ -0,0 +1,87 @@
+%D \module
+%D [ file=math-int,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Scripts,
+%D author={Hans Hagen \& Taco Hoekwater \& Aditya Mahajan},
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Integrals}
+
+\unprotect
+
+%D \startbuffer
+%D $\int_a^b f(x) dx$ and also
+%D $\iint_a^b f(x,y) dxdy$, $\iiint_a^b f(x,y) dxdy$,
+%D $\iiiint_a^b f(x) dx$
+%D \startformula
+%D \int_a^b f(x) dx \quad
+%D \iint_a^b f(x) dx \quad
+%D \iiint_a^b f(x) dx \quad
+%D \iiiint_a^b f(x) dx \quad
+%D \stopformula
+%D \stopbuffer
+%D
+%D Default: \getbuffer
+%D
+%D Displaylimits: \setupmathematics[integral=displaylimits] \getbuffer
+%D
+%D Limits: \setupmathematics[integral=limits] \getbuffer
+
+\chardef\intlimitcode\zerocount % 0 nolimits 1 displaylimits 2 limits
+
+\def\intlimits
+ {\ifcase\intlimitcode \nolimits \or \displaylimits \or \limits \fi}
+
+\ifx\v!integral\undefined \def\v!integral{integral} \fi
+
+\appendtoks
+ \processaction
+ [\mathematicsparameter\v!integral]
+ [ nolimits=>\chardef\intlimitcode\zerocount,
+ displaylimits=>\chardef\intlimitcode\plusone,
+ limits=>\chardef\intlimitcode\plustwo]%
+\to \everysetupmathematics
+
+\setupmathematics
+ [\v!integral=nolimits]
+
+%D More integrals (AM):
+
+\definemathcommand [iint] {\repeatintegral\plusone }
+\definemathcommand [iiint] {\repeatintegral\plustwo }
+\definemathcommand [iiiint] {\repeatintegral\plusthree}
+
+\def\repeatintegral#1%
+ {\scratchtoks\emptytoks
+ \let\dointlimits\donothing
+ \let\dodointlimits\intlimits
+ \dorecurse{#1}{\appendtoks \intop \dointkern \to \scratchtoks}
+ \appendtoks \intop \dointlimits \dodointlimits \to \scratchtoks
+ \edef\dodorepeatintegral{\the\scratchtoks}%
+ \futurelet\next\dorepeatintegral}
+
+%D If the \type{\limits} option is used after \type{\iint}, use
+%D \type{\mathop} and fudge the left hand space a bit to make the
+%D subscript visually centered.
+
+\def\dointkern
+ {\mkern-6mu\mathchoice{\mkern-3mu}{}{}{}}
+
+\def\dorepeatintegral
+ {\ifx\next\limits \dointlimitcorrection \else
+ \ifx\next\displaylimits \dointlimitcorrection \else
+ \ifx\next\nolimits \donothing \else
+ \ifcase\intlimitcode\else \dointlimitcorrection \fi\fi\fi\fi
+ \dodorepeatintegral}
+
+\def\dointlimitcorrection
+ {\mkern-7mu\mathchoice{\mkern-2mu}{}{}{}%
+ \mathop\bgroup\mkern7mu\mathchoice{\mkern2mu}{}{}{}\let\dointlimits\egroup}
+
+\protect \endinput
diff --git a/tex/context/base/math-lbr.tex b/tex/context/base/math-lbr.tex
index ecc3632b1..7ac7c3aff 100644
--- a/tex/context/base/math-lbr.tex
+++ b/tex/context/base/math-lbr.tex
@@ -394,12 +394,12 @@
\stopmathcollection
\def\LBRroot#1#2%
- {\setbox\z@\hbox{$\m@th#1\sqrt{#2}$}
- \dimen@\ht\z@ \advance\dimen@-\dp\z@
- \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-7.5mu \box\z@}
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}
+ \dimen@\ht\zerocount \advance\dimen@-\dp\zerocount
+ \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-7.5mu \box\zerocount}
\def\LBRmatrix#1%
- {\null\,\vcenter{\normalbaselines\m@th
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
\ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
\mathstrut\crcr\noalign{\kern-0.9\baselineskip}
#1\crcr\mathstrut\crcr\noalign{\kern-0.9\baselineskip}}}\,}
diff --git a/tex/context/base/math-map.lua b/tex/context/base/math-map.lua
new file mode 100644
index 000000000..0229790c2
--- /dev/null
+++ b/tex/context/base/math-map.lua
@@ -0,0 +1,365 @@
+if not modules then modules = { } end modules ['math-map'] = {
+ version = 1.001,
+ comment = "companion to math-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>Remapping mathematics alphabets.</p>
+--ldx]]--
+
+-- oldstyle: not really mathematics but happened to be part of
+-- the mathematics fonts in cmr
+--
+-- persian: we will also provide mappers for other
+-- scripts
+
+-- todo: alphabets namespace
+-- maybe: script/scriptscript dynamic,
+
+local type, next = type, next
+
+mathematics = mathematics or { }
+
+-- we could use one level less and have tf etc be tables directly but the
+-- following approach permits easier remapping of a-a, A-Z and 0-9 to
+-- fallbacks; symbols is currently mostly greek
+
+mathematics.alphabets = {
+ regular = {
+ tf = {
+ digits = 0x00030,
+ ucletters = 0x00041,
+ lcletters = 0x00061,
+ symbols = {
+ [0x0391]=0x0391, [0x0392]=0x0392, [0x0393]=0x0393, [0x0394]=0x0394, [0x0395]=0x0395,
+ [0x0396]=0x0396, [0x0397]=0x0397, [0x0398]=0x0398, [0x0399]=0x0399, [0x039A]=0x039A,
+ [0x039B]=0x039B, [0x039C]=0x039C, [0x039D]=0x039D, [0x039E]=0x039E, [0x039F]=0x039F,
+ [0x03A0]=0x03A0, [0x03A1]=0x03A1, [0x03A3]=0x03A3, [0x03A4]=0x03A4, [0x03A5]=0x03A5,
+ [0x03A6]=0x03A6, [0x03A7]=0x03A7, [0x03A8]=0x03A8, [0x03A9]=0x03A9, [0x03B1]=0x03B1,
+ [0x03B2]=0x03B2, [0x03B3]=0x03B3, [0x03B4]=0x03B4, [0x03B5]=0x03B5, [0x03B6]=0x03B6,
+ [0x03B7]=0x03B7, [0x03B8]=0x03B8, [0x03B9]=0x03B9, [0x03BA]=0x03BA, [0x03BB]=0x03BB,
+ [0x03BC]=0x03BC, [0x03BD]=0x03BD, [0x03BE]=0x03BE, [0x03BF]=0x03BF, [0x03C0]=0x03C0,
+ [0x03C1]=0x03C1, [0x03C2]=0x03C2, [0x03C3]=0x03C3, [0x03C4]=0x03C4, [0x03C5]=0x03C5,
+ [0x03C6]=0x03C6, [0x03C7]=0x03C7, [0x03C8]=0x03C8, [0x03C9]=0x03C9, [0x03D1]=0x03D1,
+ [0x03D5]=0x03D5, [0x03D6]=0x03D6, [0x03F0]=0x03F0, [0x03F1]=0x03F1, [0x03F4]=0x03F4,
+ [0x03F5]=0x03F5, [0x2202]=0x2202, [0x2207]=0x2207,
+ },
+ },
+ it = {
+ ucletters = 0x1D434,
+ lcletters = { -- H
+ [0x00061]=0x1D44E, [0x00062]=0x1D44F, [0x00063]=0x1D450, [0x00064]=0x1D451, [0x00065]=0x1D452,
+ [0x00066]=0x1D453, [0x00067]=0x1D454, [0x00068]=0x0210E, [0x00069]=0x1D456, [0x0006A]=0x1D457,
+ [0x0006B]=0x1D458, [0x0006C]=0x1D459, [0x0006D]=0x1D45A, [0x0006E]=0x1D45B, [0x0006F]=0x1D45C,
+ [0x00070]=0x1D45D, [0x00071]=0x1D45E, [0x00072]=0x1D45F, [0x00073]=0x1D460, [0x00074]=0x1D461,
+ [0x00075]=0x1D462, [0x00076]=0x1D463, [0x00077]=0x1D464, [0x00078]=0x1D465, [0x00079]=0x1D466,
+ [0x0007A]=0x1D467,
+ },
+ symbols = {
+ [0x0391]=0x1D6E2, [0x0392]=0x1D6E3, [0x0393]=0x1D6E4, [0x0394]=0x1D6E5, [0x0395]=0x1D6E6,
+ [0x0396]=0x1D6E7, [0x0397]=0x1D6E8, [0x0398]=0x1D6E9, [0x0399]=0x1D6EA, [0x039A]=0x1D6EB,
+ [0x039B]=0x1D6EC, [0x039C]=0x1D6ED, [0x039D]=0x1D6EE, [0x039E]=0x1D6EF, [0x039F]=0x1D6F0,
+ [0x03A0]=0x1D6F1, [0x03A1]=0x1D6F2, [0x03A3]=0x1D6F4, [0x03A4]=0x1D6F5, [0x03A5]=0x1D6F6,
+ [0x03A6]=0x1D6F7, [0x03A7]=0x1D6F8, [0x03A8]=0x1D6F9, [0x03A9]=0x1D6FA, [0x03B1]=0x1D6FC,
+ [0x03B2]=0x1D6FD, [0x03B3]=0x1D6FE, [0x03B4]=0x1D6FF, [0x03B5]=0x1D700, [0x03B6]=0x1D701,
+ [0x03B7]=0x1D702, [0x03B8]=0x1D703, [0x03B9]=0x1D704, [0x03BA]=0x1D705, [0x03BB]=0x1D706,
+ [0x03BC]=0x1D707, [0x03BD]=0x1D708, [0x03BE]=0x1D709, [0x03BF]=0x1D70A, [0x03C0]=0x1D70B,
+ [0x03C1]=0x1D70C, [0x03C2]=0x1D70D, [0x03C3]=0x1D70E, [0x03C4]=0x1D70F, [0x03C5]=0x1D710,
+ [0x03C6]=0x1D711, [0x03C7]=0x1D712, [0x03C8]=0x1D713, [0x03C9]=0x1D714, [0x03D1]=0x1D717,
+ [0x03D5]=0x1D719, [0x03D6]=0x1D71B, [0x03F0]=0x1D718, [0x03F1]=0x1D71A, [0x03F4]=0x1D6F3,
+ [0x03F5]=0x1D716, [0x2202]=0x1D715, [0x2207]=0x1D6FB,
+ },
+ },
+ bf= {
+ digits = 0x1D7CE,
+ ucletters = 0x1D400,
+ lcletters = 0x1D41A,
+ symbols = {
+ [0x0391]=0x1D6A8, [0x0392]=0x1D6A9, [0x0393]=0x1D6AA, [0x0394]=0x1D6AB, [0x0395]=0x1D6AC,
+ [0x0396]=0x1D6AD, [0x0397]=0x1D6AE, [0x0398]=0x1D6AF, [0x0399]=0x1D6B0, [0x039A]=0x1D6B1,
+ [0x039B]=0x1D6B2, [0x039C]=0x1D6B3, [0x039D]=0x1D6B4, [0x039E]=0x1D6B5, [0x039F]=0x1D6B6,
+ [0x03A0]=0x1D6B7, [0x03A1]=0x1D6B8, [0x03A3]=0x1D6BA, [0x03A4]=0x1D6BB, [0x03A5]=0x1D6BC,
+ [0x03A6]=0x1D6BD, [0x03A7]=0x1D6BE, [0x03A8]=0x1D6BF, [0x03A9]=0x1D6C0, [0x03B1]=0x1D6C2,
+ [0x03B2]=0x1D6C3, [0x03B3]=0x1D6C4, [0x03B4]=0x1D6C5, [0x03B5]=0x1D6C6, [0x03B6]=0x1D6C7,
+ [0x03B7]=0x1D6C8, [0x03B8]=0x1D6C9, [0x03B9]=0x1D6CA, [0x03BA]=0x1D6CB, [0x03BB]=0x1D6CC,
+ [0x03BC]=0x1D6CD, [0x03BD]=0x1D6CE, [0x03BE]=0x1D6CF, [0x03BF]=0x1D6D0, [0x03C0]=0x1D6D1,
+ [0x03C1]=0x1D6D2, [0x03C2]=0x1D6D3, [0x03C3]=0x1D6D4, [0x03C4]=0x1D6D5, [0x03C5]=0x1D6D6,
+ [0x03C6]=0x1D6D7, [0x03C7]=0x1D6D8, [0x03C8]=0x1D6D9, [0x03C9]=0x1D6DA, [0x03D1]=0x1D6DD,
+ [0x03D5]=0x1D6DF, [0x03D6]=0x1D6E1, [0x03F0]=0x1D6DE, [0x03F1]=0x1D6E0, [0x03F4]=0x1D6B9,
+ [0x03F5]=0x1D6DC, [0x2202]=0x1D6DB, [0x2207]=0x1D6C1,
+ },
+ },
+ bi = {
+ ucletters = 0x1D468,
+ lcletters = 0x1D482,
+ symbols = {
+ [0x0391]=0x1D71C, [0x0392]=0x1D71D, [0x0393]=0x1D71E, [0x0394]=0x1D71F, [0x0395]=0x1D720,
+ [0x0396]=0x1D721, [0x0397]=0x1D722, [0x0398]=0x1D723, [0x0399]=0x1D724, [0x039A]=0x1D725,
+ [0x039B]=0x1D726, [0x039C]=0x1D727, [0x039D]=0x1D728, [0x039E]=0x1D729, [0x039F]=0x1D72A,
+ [0x03A0]=0x1D72B, [0x03A1]=0x1D72C, [0x03A3]=0x1D72E, [0x03A4]=0x1D72F, [0x03A5]=0x1D730,
+ [0x03A6]=0x1D731, [0x03A7]=0x1D732, [0x03A8]=0x1D733, [0x03A9]=0x1D734, [0x03B1]=0x1D736,
+ [0x03B2]=0x1D737, [0x03B3]=0x1D738, [0x03B4]=0x1D739, [0x03B5]=0x1D73A, [0x03B6]=0x1D73B,
+ [0x03B7]=0x1D73C, [0x03B8]=0x1D73D, [0x03B9]=0x1D73E, [0x03BA]=0x1D73F, [0x03BB]=0x1D740,
+ [0x03BC]=0x1D741, [0x03BD]=0x1D742, [0x03BE]=0x1D743, [0x03BF]=0x1D744, [0x03C0]=0x1D745,
+ [0x03C1]=0x1D746, [0x03C2]=0x1D747, [0x03C3]=0x1D748, [0x03C4]=0x1D749, [0x03C5]=0x1D74A,
+ [0x03C6]=0x1D74B, [0x03C7]=0x1D74C, [0x03C8]=0x1D74D, [0x03C9]=0x1D74E, [0x03D1]=0x1D751,
+ [0x03D5]=0x1D753, [0x03D6]=0x1D755, [0x03F0]=0x1D752, [0x03F1]=0x1D754, [0x03F4]=0x1D72D,
+ [0x03F5]=0x1D750, [0x2202]=0x1D74F, [0x2207]=0x1D735,
+ },
+ },
+ },
+ sansserif = {
+ tf = {
+ digits = 0x1D7E2,
+ ucletters = 0x1D5A0,
+ lcletters = 0x1D5BA,
+ },
+ it = {
+ ucletters = 0x1D608,
+ lcletters = 0x1D622,
+ },
+ bf = {
+ digits = 0x1D7EC,
+ ucletters = 0x1D5D4,
+ lcletters = 0x1D5EE,
+ symbols = {
+ [0x0391]=0x1D756, [0x0392]=0x1D757, [0x0393]=0x1D758, [0x0394]=0x1D759, [0x0395]=0x1D75A,
+ [0x0396]=0x1D75B, [0x0397]=0x1D75C, [0x0398]=0x1D75D, [0x0399]=0x1D75E, [0x039A]=0x1D75F,
+ [0x039B]=0x1D760, [0x039C]=0x1D761, [0x039D]=0x1D762, [0x039E]=0x1D763, [0x039F]=0x1D764,
+ [0x03A0]=0x1D765, [0x03A1]=0x1D766, [0x03A3]=0x1D768, [0x03A4]=0x1D769, [0x03A5]=0x1D76A,
+ [0x03A6]=0x1D76B, [0x03A7]=0x1D76C, [0x03A8]=0x1D76D, [0x03A9]=0x1D76E, [0x03B1]=0x1D770,
+ [0x03B2]=0x1D771, [0x03B3]=0x1D772, [0x03B4]=0x1D773, [0x03B5]=0x1D774, [0x03B6]=0x1D775,
+ [0x03B7]=0x1D776, [0x03B8]=0x1D777, [0x03B9]=0x1D778, [0x03BA]=0x1D779, [0x03BB]=0x1D77A,
+ [0x03BC]=0x1D77B, [0x03BD]=0x1D77C, [0x03BE]=0x1D77D, [0x03BF]=0x1D77E, [0x03C0]=0x1D77F,
+ [0x03C1]=0x1D780, [0x03C2]=0x1D781, [0x03C3]=0x1D782, [0x03C4]=0x1D783, [0x03C5]=0x1D784,
+ [0x03C6]=0x1D785, [0x03C7]=0x1D786, [0x03C8]=0x1D787, [0x03C9]=0x1D788, [0x03D1]=0x1D78B,
+ [0x03D5]=0x1D78D, [0x03D6]=0x1D78F, [0x03F0]=0x1D78C, [0x03F1]=0x1D78E, [0x03F4]=0x1D767,
+ [0x03F5]=0x1D78A, [0x2202]=0x1D789, [0x2207]=0x1D76F,
+ },
+ },
+ bi = {
+ ucletters = 0x1D63C,
+ lcletters = 0x1D656,
+ symbols = {
+ [0x0391]=0x1D790, [0x0392]=0x1D791, [0x0393]=0x1D792, [0x0394]=0x1D793, [0x0395]=0x1D794,
+ [0x0396]=0x1D795, [0x0397]=0x1D796, [0x0398]=0x1D797, [0x0399]=0x1D798, [0x039A]=0x1D799,
+ [0x039B]=0x1D79A, [0x039C]=0x1D79B, [0x039D]=0x1D79C, [0x039E]=0x1D79D, [0x039F]=0x1D79E,
+ [0x03A0]=0x1D79F, [0x03A1]=0x1D7A0, [0x03A3]=0x1D7A2, [0x03A4]=0x1D7A3, [0x03A5]=0x1D7A4,
+ [0x03A6]=0x1D7A5, [0x03A7]=0x1D7A6, [0x03A8]=0x1D7A7, [0x03A9]=0x1D7A8, [0x03B1]=0x1D7AA,
+ [0x03B2]=0x1D7AB, [0x03B3]=0x1D7AC, [0x03B4]=0x1D7AD, [0x03B5]=0x1D7AE, [0x03B6]=0x1D7AF,
+ [0x03B7]=0x1D7B0, [0x03B8]=0x1D7B1, [0x03B9]=0x1D7B2, [0x03BA]=0x1D7B3, [0x03BB]=0x1D7B4,
+ [0x03BC]=0x1D7B5, [0x03BD]=0x1D7B6, [0x03BE]=0x1D7B7, [0x03BF]=0x1D7B8, [0x03C0]=0x1D7B9,
+ [0x03C1]=0x1D7BA, [0x03C2]=0x1D7BB, [0x03C3]=0x1D7BC, [0x03C4]=0x1D7BD, [0x03C5]=0x1D7BE,
+ [0x03C6]=0x1D7BF, [0x03C7]=0x1D7C0, [0x03C8]=0x1D7C1, [0x03C9]=0x1D7C2, [0x03D1]=0x1D7C5,
+ [0x03D5]=0x1D7C7, [0x03D6]=0x1D7C9, [0x03F0]=0x1D7C6, [0x03F1]=0x1D7C8, [0x03F4]=0x1D7A1,
+ [0x03F5]=0x1D7C4, [0x2202]=0x1D7C3, [0x2207]=0x1D7A9,
+ },
+ },
+ },
+ monospaced = {
+ tf = {
+ digits = 0x1D7F6,
+ ucletters = 0x1D670,
+ lcletters = 0x1D68A,
+ },
+ },
+ blackboard = { -- ok
+ tf = {
+ digits = 0x1D7D8,
+ ucletters = { -- C H N P Q R Z
+ [0x00041]=0x1D538, [0x00042]=0x1D539, [0x00043]=0x02102, [0x00044]=0x1D53B, [0x00045]=0x1D53C,
+ [0x00046]=0x1D53D, [0x00047]=0x1D53E, [0x00048]=0x0210D, [0x00049]=0x1D540, [0x0004A]=0x1D541,
+ [0x0004B]=0x1D542, [0x0004C]=0x1D543, [0x0004D]=0x1D544, [0x0004E]=0x02115, [0x0004F]=0x1D546,
+ [0x00050]=0x02119, [0x00051]=0x0211A, [0x00052]=0x0211D, [0x00053]=0x1D54A, [0x00054]=0x1D54B,
+ [0x00055]=0x1D54C, [0x00056]=0x1D54D, [0x00057]=0x1D54E, [0x00058]=0x1D54F, [0x00059]=0x1D550,
+ [0x0005A]=0x02124,
+ },
+ lcletters = 0x1D552,
+ },
+ },
+ fraktur = { -- ok
+ tf= {
+ ucletters = { -- C H I R Z
+ [0x00041]=0x1D504, [0x00042]=0x1D505, [0x00043]=0x0212D, [0x00044]=0x1D507, [0x00045]=0x1D508,
+ [0x00046]=0x1D509, [0x00047]=0x1D50A, [0x00048]=0x0210C, [0x00049]=0x02111, [0x0004A]=0x1D50D,
+ [0x0004B]=0x1D50E, [0x0004C]=0x1D50F, [0x0004D]=0x1D510, [0x0004E]=0x1D511, [0x0004F]=0x1D512,
+ [0x00050]=0x1D513, [0x00051]=0x1D514, [0x00052]=0x0211C, [0x00053]=0x1D516, [0x00054]=0x1D517,
+ [0x00055]=0x1D518, [0x00056]=0x1D519, [0x00057]=0x1D51A, [0x00058]=0x1D51B, [0x00059]=0x1D51C,
+ [0x0005A]=0x02128,
+ },
+ lcletters = 0x1D51E,
+ },
+ bf = {
+ ucletters = 0x1D56C,
+ lcletters = 0x1D586,
+ },
+ },
+ script = {
+ tf= {
+ ucletters = { -- B E F H I L M R -- P 2118
+ [0x00041]=0x1D49C, [0x00042]=0x0212C, [0x00043]=0x1D49E, [0x00044]=0x1D49F, [0x00045]=0x02130,
+ [0x00046]=0x02131, [0x00047]=0x1D4A2, [0x00048]=0x0210B, [0x00049]=0x02110, [0x0004A]=0x1D4A5,
+ [0x0004B]=0x1D4A6, [0x0004C]=0x02112, [0x0004D]=0x02133, [0x0004E]=0x1D4A9, [0x0004F]=0x1D4AA,
+ [0x00050]=0x1D4AB, [0x00051]=0x1D4AC, [0x00052]=0x0211B, [0x00053]=0x1D4AE, [0x00054]=0x1D4AF,
+ [0x00055]=0x1D4B0, [0x00056]=0x1D4B1, [0x00057]=0x1D4B2, [0x00058]=0x1D4B3, [0x00059]=0x1D4B4,
+ [0x0005A]=0x1D4B5,
+ },
+ lcletters = { -- E G O -- L 2113
+ [0x00061]=0x1D4B6, [0x00062]=0x1D4B7, [0x00063]=0x1D4B8, [0x00064]=0x1D4B9, [0x00065]=0x0212F,
+ [0x00066]=0x1D4BB, [0x00067]=0x0210A, [0x00068]=0x1D4BD, [0x00069]=0x1D4BE, [0x0006A]=0x1D4BF,
+ [0x0006B]=0x1D4C0, [0x0006C]=0x1D4C1, [0x0006D]=0x1D4C2, [0x0006E]=0x1D4C3, [0x0006F]=0x02134,
+ [0x00070]=0x1D4C5, [0x00071]=0x1D4C6, [0x00072]=0x1D4C7, [0x00073]=0x1D4C8, [0x00074]=0x1D4C9,
+ [0x00075]=0x1D4CA, [0x00076]=0x1D4CB, [0x00077]=0x1D4CC, [0x00078]=0x1D4CD, [0x00079]=0x1D4CE,
+ [0x0007A]=0x1D4CF,
+ }
+ },
+ bf = {
+ ucletters = 0x1D4D0,
+ lcletters = 0x1D4EA,
+ },
+ },
+}
+
+local alphabets = mathematics.alphabets
+local attribs = { }
+
+for alphabet, styles in next, alphabets do
+ for style, data in next, styles do
+ -- let's keep the long names (for tracing)
+ local n = #attribs+1
+ data.attribute = n
+ data.alphabet = alphabet
+ data.style = style
+ attribs[n] = data
+ end
+end
+
+-- beware, these are shared tables (no problem since they're not
+-- in unicode)
+
+alphabets.regular.it.digits = alphabets.regular.tf.digits
+alphabets.regular.bi.digits = alphabets.regular.bf.digits
+
+alphabets.sansserif.tf.symbols = alphabets.regular.tf.symbols
+alphabets.sansserif.tf.digits = alphabets.regular.tf.digits
+alphabets.sansserif.it.symbols = alphabets.regular.tf.symbols
+alphabets.sansserif.bi.digits = alphabets.regular.bf.digits
+
+alphabets.monospaced.tf.symbols = alphabets.sansserif.tf.symbols
+alphabets.monospaced.it = alphabets.sansserif.tf
+alphabets.monospaced.bf = alphabets.sansserif.tf
+alphabets.monospaced.bi = alphabets.sansserif.bf
+
+alphabets.blackboard.tf.symbols = alphabets.regular.tf.symbols
+alphabets.blackboard.it = alphabets.blackboard.tf
+alphabets.blackboard.bf = alphabets.blackboard.tf
+alphabets.blackboard.bi = alphabets.blackboard.bf
+
+alphabets.fraktur.tf.digits = alphabets.regular.tf.digits
+alphabets.fraktur.tf.symbols = alphabets.regular.tf.symbols
+alphabets.fraktur.bf.digits = alphabets.regular.bf.digits
+alphabets.fraktur.bf.symbols = alphabets.regular.bf.symbols
+alphabets.fraktur.it = alphabets.fraktur.tf
+alphabets.fraktur.bi = alphabets.fraktur.bf
+
+alphabets.script.tf.digits = alphabets.regular.tf.digits
+alphabets.script.tf.symbols = alphabets.regular.tf.symbols
+alphabets.script.bf.digits = alphabets.regular.bf.digits
+alphabets.script.bf.symbols = alphabets.regular.bf.symbols
+alphabets.script.it = alphabets.script.tf
+alphabets.script.bi = alphabets.script.bf
+
+alphabets.tt = alphabets.monospaced
+alphabets.ss = alphabets.sansserif
+alphabets.rm = alphabets.regular
+alphabets.bb = alphabets.blackboard
+alphabets.fr = alphabets.fraktur
+alphabets.sr = alphabets.script
+
+alphabets.serif = alphabets.regular
+alphabets.type = alphabets.monospaced
+alphabets.teletype = alphabets.monospaced
+
+function mathematics.to_a_style(attribute)
+ local r = attribs[attribute]
+ return r and r.style or "tf"
+end
+
+function mathematics.to_a_name(attribute)
+ local r = attribs[attribute]
+ return r and r.alphabet or "regular"
+end
+
+-- of course we could do some div/mod trickery instead
+
+--~ function mathematics.sync_a_both(attribute,alphabet,style)
+--~ local data = alphabets[alphabet or "regular"] or alphabets.regular
+--~ data = data[style or "tf"] or data.tf
+--~ return data and data.attribute or attribute
+--~ end
+
+--~ function mathematics.sync_a_style(attribute,style)
+--~ local r = attribs[attribute]
+--~ local alphabet = r and r.alphabet or "regular"
+--~ local data = alphabets[alphabet][style]
+--~ return data and data.attribute or attribute
+--~ end
+
+--~ function mathematics.sync_a_name(attribute,alphabet)
+--~ local r = attribs[attribute]
+--~ local style = r and r.style or "tf"
+--~ local data = alphabets[alphabet][style]
+--~ return data and data.attribute or attribute
+--~ end
+
+local mathalph = attributes.private("mathalph")
+
+local texattribute = tex.attribute
+
+function mathematics.sync_a_both(alphabet,style)
+ local data = alphabets[alphabet or "regular"] or alphabets.regular
+ data = data[style or "tf"] or data.tf
+ texattribute[mathalph] = data and data.attribute or texattribute[mathalph]
+end
+
+function mathematics.sync_a_style(style)
+ local r = attribs[attribute]
+ local alphabet = r and r.alphabet or "regular"
+ local data = alphabets[alphabet][style]
+ texattribute[mathalph] = data and data.attribute or texattribute[mathalph]
+end
+
+function mathematics.sync_a_name(alphabet)
+ local r = attribs[attribute]
+ local style = r and r.style or "tf"
+ local data = alphabets[alphabet][style]
+ texattribute[mathalph] = data and data.attribute or texattribute[mathalph]
+end
+
+local issymbol = mathematics.alphabets.regular.tf.symbols
+
+function mathematics.remap_alphabets(attribute,char)
+ -- we could use a map[attribute][char] => newchar but first we have
+ -- to finish the table
+ local offset = attribs[attribute]
+ if offset then
+ local newchar
+ if char >= 0x030 and char <= 0x039 then
+ local o = offset.digits
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x030 + o)
+ elseif char >= 0x041 and char <= 0x05A then
+ local o = offset.ucletters
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x041 + o)
+ elseif char >= 0x061 and char <= 0x07A then
+ local o = offset.lcletters
+ newchar = (type(o) == "table" and (o[char] or char)) or (char - 0x061 + o)
+ elseif issymbol[char] then
+ newchar = offset.symbols[char]
+ end
+ return newchar ~= char and newchar
+ end
+ return nil
+end
diff --git a/tex/context/base/math-mis.tex b/tex/context/base/math-mis.tex
deleted file mode 100644
index 1b1193fd4..000000000
--- a/tex/context/base/math-mis.tex
+++ /dev/null
@@ -1,49 +0,0 @@
-%D \module
-%D [ file=math-mis,
-%D version=2001.04.12,
-%D title=\CONTEXT\ Math Macros,
-%D subtitle=Miscelaneous Symbols,
-%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.
-
-\unprotect
-
-%D \starttyping
-%D \usemathcollection[mis]
-%D \stoptyping
-
-\def\styledmathcommand#1%
- {\mathchoice
- {\let\currentmathstyle\displaystyle#1}%
- {\let\currentmathstyle\textstyle#1}%
- {\let\currentmathstyle\scriptstyle#1}%
- {\let\currentmathstyle\scriptscriptstyle#1}}
-
-%D For Hong Feng:
-
-\def\geneq
- {\styledmathcommand\dogeneq}
-
-\def\dogeneq
- {\begingroup
- \setbox\scratchbox\hbox{$\currentmathstyle=$}%
- \hbox to \wd\scratchbox
- {\copy\scratchbox
- \hskip-\wd\scratchbox
- \hss\incolortrue\localcolortrue
- \color[white]{\vrule\!!height.6\ht\scratchbox\!!depth\zeropoint\!!width.2\wd\scratchbox}%
- \hss}%
- \endgroup}
-
-%D \startbuffer
-%D $a\string\geneq b^{a\string\geneq b^{a\string\geneq b}}$
-%D \stopbuffer
-%D
-%D \typebuffer \getbuffer
-
-\protect \endinput
diff --git a/tex/context/base/math-noa.lua b/tex/context/base/math-noa.lua
new file mode 100644
index 000000000..6cdcc0114
--- /dev/null
+++ b/tex/context/base/math-noa.lua
@@ -0,0 +1,336 @@
+if not modules then modules = { } end modules ['math-noa'] = {
+ version = 1.001,
+ comment = "companion to math-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- beware: this is experimental code and there will be a more
+-- generic (attribute value driven) interface too but for the
+-- moment this is ok
+
+local utf = unicode.utf8
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local mlist_to_hlist = node.mlist_to_hlist
+local font_of_family = node.family_font
+local fontdata = fonts.ids
+
+local format, rep = string.format, string.rep
+local utfchar, utfbyte = utf.char, utf.byte
+
+noads = noads or { }
+
+local trace_remapping = false trackers.register("math.remapping", function(v) trace_remapping = v end)
+local trace_processing = false trackers.register("math.processing", function(v) trace_processing = v end)
+local trace_analyzing = false trackers.register("math.analyzing", function(v) trace_analyzing = v end)
+
+local noad_ord = 0
+local noad_op_displaylimits = 1
+local noad_op_limits = 2
+local noad_op_nolimits = 3
+local noad_bin = 4
+local noad_rel = 5
+local noad_open = 6
+local noad_close = 7
+local noad_punct = 8
+local noad_inner = 9
+local noad_under = 10
+local noad_over = 11
+local noad_vcenter = 12
+
+-- obsolete:
+--
+-- math_ord = node.id("ord") -- attr nucleus sub sup
+-- math_op = node.id("op") -- attr nucleus sub sup subtype
+-- math_bin = node.id("bin") -- attr nucleus sub sup
+-- math_rel = node.id("rel") -- attr nucleus sub sup
+-- math_punct = node.id("punct") -- attr nucleus sub sup
+--
+-- math_open = node.id("open") -- attr nucleus sub sup
+-- math_close = node.id("close") -- attr nucleus sub sup
+--
+-- math_inner = node.id("inner") -- attr nucleus sub sup
+-- math_vcenter = node.id("vcenter") -- attr nucleus sub sup
+-- math_under = node.id("under") -- attr nucleus sub sup
+-- math_over = node.id("over") -- attr nucleus sub sup
+
+local math_noad = node.id("noad") -- attr nucleus sub sup
+
+local math_accent = node.id("accent") -- attr nucleus sub sup accent
+local math_radical = node.id("radical") -- attr nucleus sub sup left degree
+local math_fraction = node.id("fraction") -- attr nucleus sub sup left right
+
+local math_box = node.id("sub_box") -- attr list
+local math_sub = node.id("sub_mlist") -- attr list
+local math_char = node.id("math_char") -- attr fam char
+local math_text_char = node.id("math_text_char") -- attr fam char
+local math_delim = node.id("delim") -- attr small_fam small_char large_fam large_char
+local math_style = node.id("style") -- attr style
+local math_choice = node.id("choice") -- attr display text script scriptscript
+local math_fence = node.id("fence") -- attr subtype
+
+local simple_noads = table.tohash {
+ math_noad,
+}
+
+local all_noads = {
+ math_noad,
+ math_box, math_sub,
+ math_char, math_text_char, math_delim, math_style,
+ math_accent, math_radical, math_fraction, math_choice, math_fence,
+}
+
+noads.processors = noads.processors or { }
+
+local function process(start,what,n)
+ if n then n = n + 1 else n = 0 end
+ while start do
+ if trace_processing then
+ texio.write_nl(format("%s%s",rep(" ",n or 0),tostring(start)))
+ end
+ local id = start.id
+ local proc = what[id]
+ if proc then
+ proc(start,what,n)
+ elseif id == math_char or id == math_text_char or id == math_delim then
+ break
+ elseif id == math_style then
+ -- has a next
+ elseif id == math_noad then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ elseif id == math_box or id == math_sub then
+ local noad = start.list if noad then process(noad,what,n) end -- list
+ elseif id == math_fraction then
+ local noad = start.num if noad then process(noad,what,n) end -- list
+ noad = start.denom if noad then process(noad,what,n) end -- list
+ noad = start.left if noad then process(noad,what,n) end -- delimiter
+ noad = start.right if noad then process(noad,what,n) end -- delimiter
+ elseif id == math_choice then
+ local noad = start.display if noad then process(noad,what,n) end -- list
+ noad = start.text if noad then process(noad,what,n) end -- list
+ noad = start.script if noad then process(noad,what,n) end -- list
+ noad = start.scriptscript if noad then process(noad,what,n) end -- list
+ elseif id == math_fence then
+ local noad = start.delim if noad then process(noad,what,n) end -- delimiter
+ elseif id == math_radical then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ noad = start.left if noad then process(noad,what,n) end -- delimiter
+ noad = start.degree if noad then process(noad,what,n) end -- list
+ elseif id == math_accent then
+ local noad = start.nucleus if noad then process(noad,what,n) end -- list
+ noad = start.sup if noad then process(noad,what,n) end -- list
+ noad = start.sub if noad then process(noad,what,n) end -- list
+ noad = start.accent if noad then process(noad,what,n) end -- list
+ noad = start.bot_accent if noad then process(noad,what,n) end -- list
+ else
+ -- glue, penalty, etc
+ end
+ start = start.next
+ end
+end
+
+noads.process = process
+
+-- character remapping
+
+local attribute = attributes.private("mathalph")
+
+noads.processors.relocate = { }
+
+local function report_remap(tag,id,old,new,extra)
+ logs.report("math","remapping %s in font %s from U+%04X (%s) to U+%04X (%s)%s",tag,id,old,utfchar(old),new,utfchar(new),extra or "")
+end
+
+local remap_alphabets = mathematics.remap_alphabets
+local fcs = fonts.color.set
+
+noads.processors.relocate[math_char] = function(pointer)
+ local a = has_attribute(pointer,attribute)
+ if a and a > 0 then
+ local fam = pointer.fam
+ set_attribute(pointer,attribute,0)
+ local char = pointer.char
+ local newchar = remap_alphabets(a,char)
+ if newchar then
+ local id = font_of_family(fam)
+ local tfmdata = fontdata[id]
+ if tfmdata and tfmdata.characters[newchar] then -- we could probably speed this up
+ if trace_remapping then
+ report_remap("char",id,char,newchar)
+ end
+ if trace_analyzing then
+ fcs(pointer,"font:isol")
+ end
+ pointer.char = newchar
+ return
+ elseif trace_remapping then
+ report_remap("char",id,char,newchar," fails")
+ end
+ end
+ end
+ if trace_analyzing then
+ fcs(pointer,"font:medi")
+ end
+end
+
+noads.processors.relocate[math_text_char] = function(pointer)
+ if trace_analyzing then
+ fcs(pointer,"font:init")
+ end
+end
+
+noads.processors.relocate[math_delim] = function(pointer)
+ if trace_analyzing then
+ fcs(pointer,"font:fina")
+ end
+end
+
+function noads.relocate_characters(head,tail,style,penalties)
+ process(head,noads.processors.relocate)
+ return true
+end
+
+-- some resize options (this works ok because the content is
+-- empty and no larger next will be forced)
+--
+-- beware: we don't use \delcode but \Udelcode and as such have
+-- no large_fam; also, we need to check for subtype and/or
+-- small_fam not being 0 because \. sits in 0,0 by default
+--
+-- todo: just replace the character by an ord noad
+-- and remove the right delimiter as well
+
+local attribute = attributes.private("mathsize")
+
+noads.processors.resize = { }
+
+noads.processors.resize[math_fence] = function(pointer)
+ if pointer.subtype == 1 then -- left
+ local a = has_attribute(pointer,attribute)
+ if a and a > 0 then
+ set_attribute(pointer,attribute,0)
+ local d = pointer.delim
+ local df = d.small_fam
+ local id = font_of_family(df)
+ if id > 0 then
+ local ch = d.small_char
+ d.small_char = mathematics.big(fontdata[id],ch,a)
+ end
+ end
+ end
+end
+
+function noads.resize_characters(head,tail,style,penalties)
+ process(head,noads.processors.resize)
+ return true
+end
+
+-- respacing
+
+local attribute = attributes.private("mathpunc")
+
+noads.processors.respace = { }
+
+local chardata = characters.data
+
+-- only [nd,ll,ul][po][nd,ll,ul]
+
+noads.processors.respace[math_noad] = function(pointer)
+ if pointer.subtype == noad_ord then
+ local a = has_attribute(pointer,attribute)
+ if a and a > 0 then
+ set_attribute(pointer,attribute,0)
+ local current_nucleus = pointer.nucleus
+ if current_nucleus.id == math_char then
+ local current_char = current_nucleus.char
+ local fc = chardata[current_char]
+ fc = fc and fc.category
+ if fc == "nd" or fc == "ll" or fc == "lu" then
+ local next_noad = pointer.next
+ if next_noad and next_noad.id == math_noad and next_noad.subtype == noad_punct then
+ local next_nucleus = next_noad.nucleus
+ if next_nucleus.id == math_char then
+ local next_char = next_nucleus.char
+ local nc = chardata[next_char]
+ nc = nc and nc.category
+ if nc == "po" then
+ local last_noad = next_noad.next
+ if last_noad and last_noad.id == math_noad and last_noad.subtype == noad_ord then
+ local last_nucleus = last_noad.nucleus
+ if last_nucleus.id == math_char then
+ local last_char = last_nucleus.char
+ local lc = chardata[last_char]
+ lc = lc and lc.category
+ if lc == "nd" or lc == "ll" or lc == "lu" then
+ local ord = node.new(math_noad) -- todo: pool
+ ord.subtype, ord.nucleus, ord.sub, ord.sup, ord.attr = noad_ord, next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr
+ -- next_noad.nucleus, next_noad.sub, next_noad.sup, next_noad.attr = nil, nil, nil, nil
+ next_noad.nucleus, next_noad.sub, next_noad.sup = nil, nil, nil -- else crash with attributes ref count
+ --~ next_noad.attr = nil
+ ord.next = last_noad
+ pointer.next = ord
+ node.free(next_noad)
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+
+function noads.respace_characters(head,tail,style,penalties)
+ noads.process(head,noads.processors.respace)
+ return true
+end
+
+-- the normal builder
+
+function noads.mlist_to_hlist(head,tail,style,penalties)
+ return mlist_to_hlist(head,style,penalties), true
+end
+
+tasks.new (
+ "math",
+ {
+ "normalizers",
+ "builders",
+ }
+)
+
+--~ tasks.appendaction("math", "normalizers", "noads.relocate_characters", nil, "nohead")
+--~ tasks.appendaction("math", "normalizers", "noads.resize_characters", nil, "nohead")
+--~ tasks.appendaction("math", "normalizers", "noads.respace_characters", nil, "nohead")
+--~ tasks.appendaction("math", "builders", "noads.mlist_to_hlist", nil, "notail")
+
+local actions = tasks.actions("math")
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+function nodes.processors.mlist_to_hlist(head,style,penalties)
+ starttiming(noads)
+ local head, done = actions(head,nil,style,penalties)
+ stoptiming(noads)
+ return head, done
+end
+
+callback.register('mlist_to_hlist',nodes.processors.mlist_to_hlist)
+
+-- tracing
+
+statistics.register("math processing time", function()
+ if statistics.elapsedindeed(noads) then
+ return format("%s seconds", statistics.elapsedtime(noads))
+ end
+end)
diff --git a/tex/context/base/math-pln.tex b/tex/context/base/math-pln.mkii
index ffa16c8f5..0bacc40a2 100644
--- a/tex/context/base/math-pln.tex
+++ b/tex/context/base/math-pln.mkii
@@ -1,8 +1,8 @@
%D \module
%D [ file=math-pln,
%D version=2001.11.16,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Efficient \PLAIN\ \TEX\ loading,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Plain Helpers,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,38 +11,41 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% \points should become \bodyfontsize
+
%D This is a temporary module, some of this code will move to
%D the other math modules.
+\writestatus{loading}{ConTeXt Math Macros / Plain Helpers}
+
\unprotect
-\ifx\displ@y\unefined \let\displ@y\relax\fi
-\ifx\m@th \unefined \let\m@th \relax\fi
+\ifx\displ@y\undefined \let\displ@y\relax\fi
\newbox\rootbox
-\def\root#1\of%
- {\setbox\rootbox\hbox{$\m@th\scriptscriptstyle{#1}$}%
+\def\root#1\of
+ {\setbox\rootbox\hbox{$\mathsurround\zeropoint\scriptscriptstyle{#1}$}%
\mathpalette\r@@t}
\def\r@@t#1#2% will be overloaded
- {\setbox\z@\hbox{$\m@th#1\sqrt{#2}$}\dimen@\ht\z@
- \advance\dimen@-\dp\z@
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}\dimen@\ht\zerocount
+ \advance\dimen@-\dp\zerocount
\mkern5mu\raise.6\dimen@\copy\rootbox
- \mkern-10mu\box\z@}
+ \mkern-10mu\box\zerocount}
\def\mathhexbox#1#2#3%
{\leavevmode
- \hbox{$\m@th\mathchar"#1#2#3$}}
+ \hbox{$\mathsurround\zeropoint\mathchar"#1#2#3$}}
\def\oalign#1%
{\leavevmode
\vtop
- {\baselineskip\z@skip \lineskip.25ex%
+ {\baselineskip\zeroskip \lineskip.25ex%
\ialign{##\crcr#1\crcr}}}
\def\o@lign
- {\lineskiplimit\z@ \oalign}
+ {\lineskiplimit\zeropoint \oalign}
\def\ooalign % chars over each other
{\lineskiplimit-\maxdimen
@@ -54,40 +57,55 @@
\dimen@}
\def\dots
- {\relax\ifmmode\ldots\else$\m@th\ldots\,$\fi}
+ {\relax\ifmmode\ldots\else$\mathsurround\zeropoint\ldots\,$\fi}
\def\hrulefill
{\leaders\hrule\hfill}
\def\dotfill
- {\cleaders\hbox{$\m@th \mkern1.5mu.\mkern1.5mu$}\hfill}
+ {\cleaders\hbox{$\mathsurround\zeropoint \mkern1.5mu.\mkern1.5mu$}\hfill}
\def\rightarrowfill
- {$\m@th\smash-\mkern-7mu%
+ {$\mathsurround\zeropoint\smash-\mkern-7mu%
\cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
\mkern-7mu\mathord\rightarrow$}
\def\leftarrowfill
- {$\m@th\mathord\leftarrow\mkern-7mu%
+ {$\mathsurround\zeropoint\mathord\leftarrow\mkern-7mu%
\cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
\mkern-7mu\smash-$}
% must go to math-tex
-\mathchardef\braceld="37A
-\mathchardef\bracerd="37B
-\mathchardef\bracelu="37C
-\mathchardef\braceru="37D
+\ifx\braceld\undefined
+ % mkii values
+ \mathchardef\braceld="37A
+ \mathchardef\bracerd="37B
+ \mathchardef\bracelu="37C
+ \mathchardef\braceru="37D
+\fi
\def\downbracefill
- {$\m@th\setbox\z@\hbox{$\braceld$}%
- \braceld\leaders\vrule\!!height\ht\z@\!!depth\z@\hfill\braceru
- \bracelu\leaders\vrule\!!height\ht\z@\!!depth\z@\hfill\bracerd$}
+ {$\mathsurround\zeropoint\setbox\zerocount\hbox{$\braceld$}%
+ \braceld\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\braceru
+ \bracelu\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\bracerd$}
\def\upbracefill
- {$\m@th\setbox\z@\hbox{$\braceld$}%
- \bracelu\leaders\vrule\!!height\ht\z@\!!depth\z@\hfill\bracerd
- \braceld\leaders\vrule\!!height\ht\z@\!!depth\z@\hfill\braceru$}
+ {$\mathsurround\zeropoint\setbox\zerocount\hbox{$\braceld$}%
+ \bracelu\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\bracerd
+ \braceld\leaders\vrule\!!height\ht\zerocount\!!depth\zeropoint\hfill\braceru$}
+
+% hm, shouldn't that be \kern3\bodyfontsize
+
+\def\overbrace#1%
+ {\mathop{\vbox{\mathsurround\zeropoint\ialign{##\crcr\noalign{\kern3\points}
+ \downbracefill\crcr\noalign{\kern3\points\nointerlineskip}
+ $\hfil\displaystyle{#1}\hfil$\crcr}}}\limits}
+
+\def\underbrace#1%
+ {\mathop{\vtop{\mathsurround\zeropoint\ialign{##\crcr
+ $\hfil\displaystyle{#1}\hfil$\crcr\noalign{\kern3\points\nointerlineskip}
+ \upbracefill\crcr\noalign{\kern3\points}}}}\limits}
\let\sp=^ % will become obsolete
\let\sb=_ % will become obsolete
@@ -136,31 +154,18 @@
\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow}
\def\overrightarrow#1%
- {\vbox{\m@th\ialign{##\crcr
- \rightarrowfill\crcr\noalign{\kern-\p@\nointerlineskip}
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
+ \rightarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip}
$\hfil\displaystyle{#1}\hfil$\crcr}}}
\def\overleftarrow#1%
- {\vbox{\m@th\ialign{##\crcr
- \leftarrowfill\crcr\noalign{\kern-\p@\nointerlineskip}
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
+ \leftarrowfill\crcr\noalign{\kern-\onepoint\nointerlineskip}
$\hfil\displaystyle{#1}\hfil$\crcr}}}
-\def\overbrace#1%
- {\mathop{\vbox{\m@th\ialign{##\crcr\noalign{\kern3\p@}
- \downbracefill\crcr\noalign{\kern3\p@\nointerlineskip}
- $\hfil\displaystyle{#1}\hfil$\crcr}}}\limits}
-
-\def\underbrace#1%
- {\mathop{\vtop{\m@th\ialign{##\crcr
- $\hfil\displaystyle{#1}\hfil$\crcr\noalign{\kern3\p@\nointerlineskip}
- \upbracefill\crcr\noalign{\kern3\p@}}}}\limits}
-
\def\skew#1#2#3%
- {{\muskip\z@#1mu\divide\muskip\z@\tw@ \mkern\muskip\z@
- #2{\mkern-\muskip\z@{#3}\mkern\muskip\z@}\mkern-\muskip\z@}{}}
-
-\def\n@space
- {\nulldelimiterspace\z@ \m@th}
+ {{\muskip\zerocount#1mu\divide\muskip\zerocount\plustwo \mkern\muskip\zerocount
+ #2{\mkern-\muskip\zerocount{#3}\mkern\muskip\zerocount}\mkern-\muskip\zerocount}{}}
\def\choose{\atopwithdelims()}
\def\brack {\atopwithdelims[]}
@@ -173,32 +178,32 @@
{#1\scriptstyle {#2}}%
{#1\scriptscriptstyle{#2}}}
-\def\cong%
+\def\cong
{\mathrel{\mathpalette\@vereq\sim}} % congruence sign
\def\@vereq#1#2%
- {\lower.5\p@\vbox{\lineskiplimit\maxdimen\lineskip-.5\p@
- \ialign{$\m@th#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
+ {\lower.5\points\vbox{\lineskiplimit\maxdimen\lineskip-.5\points
+ \ialign{$\mathsurround\zeropoint#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
-\def\notin%
+\def\notin% can be mkiv'd
{\mathrel{\mathpalette\c@ncel\in}}
\def\c@ncel#1#2%
- {\m@th\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
+ {\mathsurround\zeropoint\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
\def\rightleftharpoons%
{\mathrel{\mathpalette\rlh@{}}}
\def\rlh@#1%
{\vcenter
- {\m@th
+ {\mathsurround\zeropoint
\hbox
{\ooalign
{\raise2pt\hbox{$#1\rightharpoonup$}\crcr
$#1\leftharpoondown$}}}}
\def\buildrel#1\over#2%
- {\mathrel{\mathop{\kern\z@#2}\limits^{#1}}}
+ {\mathrel{\mathop{\kern\zerocount#2}\limits^{#1}}}
\def\doteq
{\buildrel\textstyle.\over=}
@@ -225,7 +230,7 @@
\,%
\vcenter
{\normalbaselines
- \m@th
+ \mathsurround\zeropoint
\ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}%
\right.}
@@ -233,7 +238,7 @@
{\null
\,%
\vcenter
- {\normalbaselines\m@th
+ {\normalbaselines\mathsurround\zeropoint
\ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
\mathstrut\crcr\noalign{\kern-\baselineskip}
#1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}%
@@ -242,30 +247,30 @@
\def\pmatrix#1%
{\left(\matrix{#1}\right)}
-\newdimen\p@renwd
+\newdimen\mathparentwd
-% \setbox0=\hbox{\tenex B} \p@renwd=\wd0 % width of the big left (
+% \setbox0=\hbox{\tenex B} \mathparentwd=\wd0 % width of the big left (
\def\bordermatrix#1%
{\begingroup
- \m@th
- \setbox\z@\vbox
- {\def\cr{\crcr\noalign{\kern2\p@\global\let\cr\endline}}%
- \ialign{$##$\hfil\kern2\p@\kern\p@renwd&\thinspace\hfil$##$\hfil
+ \mathsurround\zeropoint
+ \setbox\zerocount\vbox
+ {\def\cr{\crcr\noalign{\kern2\points\global\let\cr\endline}}%
+ \ialign{$##$\hfil\kern2\points\kern\mathparentwd&\thinspace\hfil$##$\hfil
&&\quad\hfil$##$\hfil\crcr
\omit\strut\hfil\crcr\noalign{\kern-\baselineskip}%
#1\crcr\omit\strut\cr}}%
- \setbox\tw@\vbox
- {\unvcopy\z@\global\setbox\@ne\lastbox}%
- \setbox\tw@\hbox
- {\unhbox\@ne\unskip\global\setbox\@ne\lastbox}%
- \setbox\tw@\hbox
- {$\kern\wd\@ne\kern-\p@renwd\left(\kern-\wd\@ne
- \global\setbox\@ne\vbox{\box\@ne\kern2\p@}%
- \vcenter{\kern-\ht\@ne\unvbox\z@\kern-\baselineskip}\,\right)$}%
+ \setbox\plustwo\vbox
+ {\unvcopy\zerocount\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {\unhbox\plusone\unskip\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {$\kern\wd\plusone\kern-\mathparentwd\left(\kern-\wd\plusone
+ \global\setbox\plusone\vbox{\box\plusone\kern2\points}%
+ \vcenter{\kern-\ht\plusone\unvbox\zerocount\kern-\baselineskip}\,\right)$}%
\null
\;%
- \vbox{\kern\ht\@ne\box\tw@}%
+ \vbox{\kern\ht\plusone\box\plustwo}%
\endgroup}
% \def\openup{\afterassignment\@penup\dimen@=}
@@ -291,19 +296,19 @@
\,%
\vcenter
{\openup\displayopenupvalue % was \openup\jot
- \m@th
+ \mathsurround\zeropoint
\ialign
{\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil\crcr
#1\crcr}}%
\,}
\def\@lign % restore inside \displ@y
- {\tabskip\z@skip
+ {\tabskip\zeroskip
\everycr{}}
\def\displaylines#1%
{\displ@y
- \tabskip\z@skip
+ \tabskip\zeroskip
\halign
{\hbox to \displaywidth{$\@lign\hfil\displaystyle##\hfil$}\crcr
#1\crcr}}
@@ -312,16 +317,16 @@
{\displ@y
\tabskip\centering
\halign to \displaywidth
- {\hfil$\@lign\displaystyle{##}$\tabskip\z@skip
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
&$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
- &\llap{$\@lign##$}\tabskip\z@skip\crcr
+ &\llap{$\@lign##$}\tabskip\zeroskip\crcr
#1\crcr}}
\def\leqalignno#1%
{\displ@y
\tabskip\centering
\halign to \displaywidth
- {\hfil$\@lign\displaystyle{##}$\tabskip\z@skip
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
&$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
&\kern-\displaywidth\rlap{$\@lign##$}\tabskip\displaywidth\crcr
#1\crcr}}
diff --git a/tex/context/base/math-pln.mkiv b/tex/context/base/math-pln.mkiv
new file mode 100644
index 000000000..23d7d935c
--- /dev/null
+++ b/tex/context/base/math-pln.mkiv
@@ -0,0 +1,298 @@
+%D \module
+%D [ file=math-pln,
+%D version=2001.11.16,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Plain Helpers,
+%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 This is a temporary module, some of this code will move to
+%D the other math modules. Much is copied from Plain \TEX.
+
+% \points should become \bodyfontsize
+
+\writestatus{loading}{ConTeXt Math Macros / Plain Helpers}
+
+\unprotect
+
+\ifx\displ@y\undefined \let\displ@y\relax\fi
+
+\def\oalign#1%
+ {\leavevmode
+ \vtop
+ {\baselineskip\zeroskip \lineskip.25ex%
+ \ialign{##\crcr#1\crcr}}}
+
+\def\o@lign
+ {\lineskiplimit\zeropoint \oalign}
+
+\def\ooalign % chars over each other
+ {\lineskiplimit-\maxdimen
+ \oalign}
+
+\def\sh@ft#1% kern by #1 times the current slant
+ {\dimen@#1%
+ \kern\expandafter\withoutpt\the\slantperpoint
+ \dimen@}
+
+\def\dots
+ {\relax\ifmmode\ldots\else$\mathsurround\zeropoint\ldots\,$\fi}
+
+\def\hrulefill
+ {\leaders\hrule\hfill}
+
+\def\dotfill
+ {\cleaders\hbox{$\mathsurround\zeropoint \mkern1.5mu.\mkern1.5mu$}\hfill}
+
+\def\rightarrowfill
+ {$\mathsurround\zeropoint\smash-\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\mathord\rightarrow$}
+
+\def\leftarrowfill
+ {$\mathsurround\zeropoint\mathord\leftarrow\mkern-7mu%
+ \cleaders\hbox{$\mkern-2mu\smash-\mkern-2mu$}\hfill
+ \mkern-7mu\smash-$}
+
+\let\sp=^ % will become obsolete
+\let\sb=_ % will become obsolete
+
+\ifx\,\undefined \def\,{\mskip \thinmuskip } \fi
+\ifx\>\undefined \def\>{\mskip \medmuskip } \fi
+\ifx\;\undefined \def\;{\mskip \thickmuskip} \fi
+\ifx\!\undefined \def\!{\mskip-\thinmuskip } \fi
+\ifx\*\undefined \def\*{\discretionary{\thinspace\the\textfont2\char2}{}{}} \fi
+
+% {\catcode`\'=\active \gdef'{^\bgroup\prim@s}}
+
+\def\activemathquote{^\bgroup\prim@s}
+
+\def\prim@s
+ {\prime\futurelet\next\pr@m@s}
+
+\def\pr@m@s
+ {\ifx'\next
+ \@EA\pr@@@s
+ \else\ifx^\next
+ \@EAEAEA\pr@@@t
+ \else
+ \@EAEAEA\egroup
+ \fi\fi}
+
+\def\pr@@@s#1%
+ {\prim@s}
+
+\def\pr@@@t#1#2%
+ {#2\egroup}
+
+% {\catcode`\_=\active \global\let_=\_} % _ in math is either subscript or \_
+
+\let\activemathunderscore\_
+
+\def\relbar {\mathrel{\smash-}} % - has the same height as +
+\def\Relbar {\mathrel=}
+
+\def\Longrightarrow {\Relbar\joinrel\Rightarrow}
+\def\longrightarrow {\relbar\joinrel\rightarrow}
+\def\longleftarrow {\leftarrow\joinrel\relbar}
+\def\Longleftarrow {\Leftarrow\joinrel\Relbar}
+\def\longmapsto {\mapstochar\longrightarrow}
+\def\longleftrightarrow{\leftarrow\joinrel\rightarrow}
+\def\Longleftrightarrow{\Leftarrow\joinrel\Rightarrow}
+
+\def\choose{\atopwithdelims()}
+\def\brack {\atopwithdelims[]}
+\def\brace {\atopwithdelims\{\}}
+
+\def\mathpalette#1#2%
+ {\mathchoice
+ {#1\displaystyle {#2}}%
+ {#1\textstyle {#2}}%
+ {#1\scriptstyle {#2}}%
+ {#1\scriptscriptstyle{#2}}}
+
+\def\cong
+ {\mathrel{\mathpalette\@vereq\sim}} % congruence sign
+
+\def\@vereq#1#2%
+ {\lower.5\points\vbox{\lineskiplimit\maxdimen\lineskip-.5\points
+ \ialign{$\mathsurround\zeropoint#1\hfil##\hfil$\crcr#2\crcr=\crcr}}}
+
+\def\notin
+ {\mathrel{\mathpalette\c@ncel\in}}
+
+\def\c@ncel#1#2%
+ {\mathsurround\zeropoint\ooalign{$\hfil#1\mkern1mu/\hfil$\crcr$#1#2$}}
+
+\def\rightleftharpoons
+ {\mathrel{\mathpalette\rlh@{}}}
+
+\def\rlh@#1%
+ {\vcenter
+ {\mathsurround\zeropoint
+ \hbox
+ {\ooalign
+ {\raise2pt\hbox{$#1\rightharpoonup$}\crcr
+ $#1\leftharpoondown$}}}}
+
+\def\buildrel#1\over#2%
+ {\mathrel{\mathop{\kern\zeropoint#2}\limits^{#1}}}
+
+\def\doteq
+ {\buildrel\textstyle.\over=}
+
+\ifx\mfunction\undefined \def\mfunction#1{\mathbin{\rm#1}} \fi
+
+\def\bmod
+ {\nonscript
+ \mskip-\medmuskip
+ \mkern5mu
+ \mfunction{mod}%
+ \penalty900
+ \mkern5mu
+ \nonscript
+ \mskip-\medmuskip}
+
+\def\pmod#1%
+ {\allowbreak
+ \mkern18mu
+ (\mfunction{mod}\,\,#1)}
+
+\def\cases#1%
+ {\left\{%
+ \,%
+ \vcenter
+ {\normalbaselines
+ \mathsurround\zeropoint
+ \ialign{$##\hfil$&\quad##\hfil\crcr#1\crcr}}%
+ \right.}
+
+\def\matrix#1%
+ {\null
+ \,%
+ \vcenter
+ {\normalbaselines\mathsurround\zeropoint
+ \ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
+ \mathstrut\crcr\noalign{\kern-\baselineskip}
+ #1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}%
+ \,}
+
+\def\pmatrix#1%
+ {\left(\matrix{#1}\right)}
+
+\newdimen\mathparentwd
+
+% \setbox0=\hbox{\tenex B} \mathparentwd=\wd0 % width of the big left (
+
+\def\bordermatrix#1%
+ {\begingroup
+ \mathsurround\zeropoint
+ \setbox\zerocount\vbox
+ {\def\cr{\crcr\noalign{\kern2\points\global\let\cr\endline}}%
+ \ialign{$##$\hfil\kern2\points\kern\mathparentwd&\thinspace\hfil$##$\hfil
+ &&\quad\hfil$##$\hfil\crcr
+ \omit\strut\hfil\crcr\noalign{\kern-\baselineskip}%
+ #1\crcr\omit\strut\cr}}%
+ \setbox\plustwo\vbox
+ {\unvcopy\zerocount\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {\unhbox\plusone\unskip\global\setbox\plusone\lastbox}%
+ \setbox\plustwo\hbox
+ {$\kern\wd\plusone\kern-\mathparentwd\left(\kern-\wd\plusone
+ \global\setbox\plusone\vbox{\box\plusone\kern2\points}%
+ \vcenter{\kern-\ht\plusone\unvbox\zerocount\kern-\baselineskip}\,\right)$}%
+ \null
+ \;%
+ \vbox{\kern\ht\plusone\box\plustwo}%
+ \endgroup}
+
+% \def\openup{\afterassignment\@penup\dimen@=}
+%
+% \def\@penup{\advance\lineskip\dimen@
+% \advance\baselineskip\dimen@
+% \advance\lineskiplimit\dimen@}
+
+\def\openup
+ {\afterassignment\doopenup\scratchdimen=}
+
+\def\doopenup
+ {\advance\lineskip \scratchdimen
+ \advance\baselineskip \scratchdimen
+ \advance\lineskiplimit\scratchdimen}
+
+% \def\jot{.25\bodyfontsize} % plain tex: 3 pt (todo: better name and configurable)
+
+\def\displayopenupvalue{.25\bodyfontsize}
+
+\def\eqalign#1%
+ {\null
+ \,%
+ \vcenter
+ {\openup\displayopenupvalue % was \openup\jot
+ \mathsurround\zeropoint
+ \ialign
+ {\strut\hfil$\displaystyle{##}$&$\displaystyle{{}##}$\hfil\crcr
+ #1\crcr}}%
+ \,}
+
+\def\@lign % restore inside \displ@y
+ {\tabskip\zeroskip
+ \everycr{}}
+
+\def\displaylines#1%
+ {\displ@y
+ \tabskip\zeroskip
+ \halign
+ {\hbox to \displaywidth{$\@lign\hfil\displaystyle##\hfil$}\crcr
+ #1\crcr}}
+
+\def\eqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\llap{$\@lign##$}\tabskip\zeroskip\crcr
+ #1\crcr}}
+
+\def\leqalignno#1%
+ {\displ@y
+ \tabskip\centering
+ \halign to \displaywidth
+ {\hfil$\@lign\displaystyle{##}$\tabskip\zeroskip
+ &$\@lign\displaystyle{{}##}$\hfil\tabskip\centering
+ &\kern-\displaywidth\rlap{$\@lign##$}\tabskip\displaywidth\crcr
+ #1\crcr}}
+
+% temporary here
+
+% \startcatcodetable \mthcatcodes
+% \setcatcodetable\ctxcatcodes
+% \catcode`\_ = 13
+% \catcode`\' = 13
+% \stopcatcodetable
+%
+% \letcatcodecommand \mthcatcodes `\_ \activemathunderscore
+% \letcatcodecommand \mthcatcodes `\' \activemathquote
+
+% \appendtoks \setcatcodetable\mthcatcodes \to \everymath : spoils xml
+
+% tricky, but some day we will reimplement math
+
+\bgroup
+ \catcode`\_ = 13
+ \catcode`\' = 13
+ \doglobal\appendtoks
+ \let_\activemathunderscore
+ \let'\activemathquote
+ \to \everymathematics
+\egroup
+
+% so far
+
+\protect \endinput
diff --git a/tex/context/base/math-run.tex b/tex/context/base/math-run.mkii
index affa8d5af..afe5b18b4 100644
--- a/tex/context/base/math-run.tex
+++ b/tex/context/base/math-run.mkii
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Math Macros / Runtime Macros}
+
\unprotect
\ifx\showmathmodern\undefined \global\chardef\showmathmodern\zerocount \fi
diff --git a/tex/context/base/math-scr.mkiv b/tex/context/base/math-scr.mkiv
new file mode 100644
index 000000000..43355679f
--- /dev/null
+++ b/tex/context/base/math-scr.mkiv
@@ -0,0 +1,215 @@
+%D \module
+%D [ file=math-scr,
+%D version=2007.07.19,
+%D title=\CONTEXT\ Math Macros,
+%D subtitle=Scripts,
+%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.
+
+\writestatus{loading}{ConTeXt Math Macros / Scripts}
+
+\unprotect
+
+%D \macros
+%D {super, sub}
+%D
+%D \TEX\ uses \type{^} and \type{_} for entering super- and
+%D subscript mode. We want however a bit more control than
+%D normally provided, and therefore provide \type {\super}
+%D and \type{sub}.
+
+\global\let\normalsuper=^
+\global\let\normalsuber=_
+
+\newcount\supersubmode
+
+\newevery\everysupersub \EverySuperSub
+
+\appendtoks \advance\supersubmode \plusone \to \everysupersub
+
+\appendtoks
+ \gridsupsubstyle
+\to \everysupersub
+
+\appendtoks
+ \doifelse\@@mtsize\v!small
+ {\let\gridsupsubstyle \scriptscriptstyle
+ \let\gridsupsubbodyfont \setsmallbodyfont}%
+ {\let\gridsupsubstyle \scriptstyle
+ \let\gridsupsubbodyfont \relax}%
+\to \everysetuptextformulas
+
+\setuptextformulas
+ [\c!size=\v!normal]
+
+\def\dogridsupsub#1#2%
+ {\begingroup
+ \setbox\nextbox\iftracegridsnapping\ruledhbox\else\hbox\fi
+ {\gridsupsubbodyfont
+ $\strut^{\the\everysupersub#1}_{\the\everysupersub#2}$}%
+ \nextboxht\strutheight
+ \nextboxdp\strutdepth
+ \flushnextbox
+ \endgroup}
+
+\def\gridsupsub
+ {\ifconditional\crazymathsnapping
+ \ifgridsnapping
+ \@EAEAEA\dogridsupsub
+ \else
+ \@EAEAEA\normalsupsub
+ \fi
+ \else
+ \@EA\normalsupsub
+ \fi}
+
+\def\normalsupsub#1#2%
+ {^{\the\everysupersub#1}_{\the\everysupersub#2}}
+
+\appendtoks
+ \let\gridsupsubstyle \relax
+ \let\gridsupsubbodyfont\relax
+ \let\gridsupsub \normalsupsub
+\to \everydisplay
+
+\def\super#1{^{\the\everysupersub#1}}
+\def\suber#1{_{\the\everysupersub#1}}
+\def\supsub#1#2{\super{#1}\suber{#2}}
+\def\subsup#1#2{\suber{#1}\super{#2}}
+
+%\def\super#1{\gridsupsub{#1}{}} %
+%\def\suber#1{\gridsupsub{}{#1}} %
+%
+%\def\supsub#1#2{\gridsupsub{#1}{#2}}
+%\def\subsup#1#2{\gridsupsub{#2}{#1}}
+
+\def\gridsuper#1{\gridsupsub{#1}{}}
+\def\gridsuber#1{\gridsupsub{}{#1}}
+
+% \let\sup\super % math char
+% \let\sub\suber
+
+% test set:
+%
+% \startbuffer
+% \sform{x\frac{1}{2}}
+% \sform{x\sup{\frac{1}{2}} + x\sup{2} + 2}
+% \sform{x\supsub{\frac{1}{2}}{\frac{1}{2}} + x\sup{2} + 2}
+% \stopbuffer
+%
+% \typebuffer
+%
+% \startlines
+% \getbuffer
+% \stoplines
+%
+% \startbuffer
+% $x\frac{1}{2}$
+% $x\sup{\frac{1}{2}} + x^2 + 2$
+% $x\supsub{\frac{1}{2}}{\frac{1}{2}} + x^2 + 2$
+% \stopbuffer
+%
+% \typebuffer
+%
+% \start
+% \enablesupersub
+% \enableautomath
+% \startlines
+% \getbuffer
+% \stoplines
+% \stop
+
+%D \macros
+%D {enablesupersub,enablesimplesupersub}
+%D
+%D We can let \type {^} and \type {_} act like \type {\super}
+%D and \type {\sub} by saying \type {\enablesupersub}.
+
+\bgroup
+\catcode`\^=\@@active
+\catcode`\_=\@@active
+\gdef\enablesupersub
+ {\catcode`\^=\@@active
+ \def^{\ifmmode\expandafter\super\else\expandafter\normalsuper\fi}%
+ \catcode`\_=\@@active
+ \def_{\ifmmode\expandafter\suber\else\expandafter\normalsuber\fi}}
+\egroup
+
+%D \macros
+%D {restoremathstyle}
+%D
+%D We can pick up the current math style by calling \type
+%D {\restoremathstyle}.
+
+\def\restoremathstyle
+ {\ifmmode
+ \ifcase\supersubmode
+ \textstyle
+ \or
+ \scriptstyle
+ \else
+ \scriptscriptstyle
+ \fi
+ \fi}
+
+%D These macros were first needed by Frits Spijker (also
+%D known as Gajes) for typesetting the minus sign that is
+%D keyed into scientific calculators.
+
+% This is the first alternative, which works okay for the
+% minus, but less for the plus.
+%
+% \def\dodoraisedmathord#1#2#3%
+% {\mathord{{#2\raise.#1ex\hbox{#2#3}}}}
+%
+% \def\doraisedmathord#1%
+% {\mathchoice
+% {\dodoraisedmathord5\tf #1}%
+% {\dodoraisedmathord5\tf #1}%
+% {\dodoraisedmathord4\tfx #1}%
+% {\dodoraisedmathord3\tfxx#1}}
+%
+% \def\negative{\doraisedmathord-}
+% \def\positive{\doraisedmathord+}
+%
+% So, now we use the monospaced signs, that we also
+% define as symbol, so that they can be overloaded.
+
+\def\dodoraisedmathord#1#2#3%
+ {\mathord{{#2\raise.#1ex\hbox{#2\symbol[#3]}}}}
+
+\def\doraisedmathord#1%
+ {\mathchoice
+ {\dodoraisedmathord5\tf {#1}}%
+ {\dodoraisedmathord5\tf {#1}}%
+ {\dodoraisedmathord4\tx {#1}}%
+ {\dodoraisedmathord3\txx{#1}}}
+
+\def\dodonumbermathord#1#2%
+ {\setbox\scratchbox\hbox{0}%
+ \mathord{\hbox to \wd\scratchbox{\hss#1\symbol[#2]\hss}}}
+
+\def\donumbermathord#1%
+ {\mathchoice
+ {\dodonumbermathord\tf {#1}}%
+ {\dodonumbermathord\tf {#1}}%
+ {\dodonumbermathord\tx {#1}}%
+ {\dodonumbermathord\txx{#1}}}
+
+\definesymbol[positive] [\getglyph{Mono}{+}]
+\definesymbol[negative] [\getglyph{Mono}{-}]
+\definesymbol[zeroamount][\getglyph{Mono}{-}]
+
+\def\negative {\doraisedmathord{negative}}
+\def\positive {\doraisedmathord{positive}}
+\def\zeroamount{\donumbermathord{zeroamount}}
+
+%D How negative such a symbol looks is demonstrated in:
+%D $\negative 10^{\negative 10^{\negative 10}}$.
+
+\protect \endinput
diff --git a/tex/context/base/math-tex.tex b/tex/context/base/math-tex.tex
index 752f113b7..c833db956 100644
--- a/tex/context/base/math-tex.tex
+++ b/tex/context/base/math-tex.tex
@@ -232,7 +232,7 @@
\stopmathcollection
\def\PLAINangle
- {{\vbox{\ialign{$\m@th\scriptstyle##$\crcr
+ {{\vbox{\ialign{$\mathsurround\zeropoint\scriptstyle##$\crcr
\not\mathrel{\mkern14mu}\crcr
\noalign{\nointerlineskip}
\mkern2.5mu\leaders\hrule height.34pt\hfill\mkern2.5mu\crcr}}}}
@@ -424,12 +424,12 @@
{\cdotp\cdotp\cdotp}
\def\PLAINvdots
- {\vbox{\baselineskip4\p@ \lineskiplimit\z@
- \kern6\p@\hbox{.}\hbox{.}\hbox{.}}}
+ {\vbox{\baselineskip.4\bodyfontsize\lineskiplimit\zeropoint
+ \kern.6\bodyfontsize\hbox{.}\hbox{.}\hbox{.}}}
\def\PLAINddots
- {\mkern1mu\raise7\p@\vbox{\kern7\p@\hbox{.}}\mkern2mu
- \raise4\p@\hbox{.}\mkern2mu\raise\p@\hbox{.}\mkern1mu}
+ {\mkern1mu\raise.7\bodyfontsize\vbox{\kern.7\bodyfontsize\hbox{.}}\mkern2mu
+ \raise.4\bodyfontsize\hbox{.}\mkern2mu\raise.1\bodyfontsize\hbox{.}\mkern1mu}
\startmathcollection[default]
@@ -521,7 +521,7 @@
\def\notsosqrt[#1]{\root#1\of}
-\unexpanded\def\sqrt{\doifnextcharelse[\notsosqrt\normalsqrt}
+\unexpanded\def\sqrt{\doifnextoptionalelse\notsosqrt\normalsqrt}
\def\PLAINbig {\@@dobig{0.85}}
\def\PLAINBig {\@@dobig{1.15}}
@@ -561,12 +561,12 @@
\stopmathcollection
\def\PLAINroot#1#2%
- {\setbox\z@\hbox{$\m@th#1\sqrt{#2}$}\dimen@\ht\z@
- \advance\dimen@-\dp\z@
- \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-10mu\box\z@}
+ {\setbox\zerocount\hbox{$\mathsurround\zeropoint#1\sqrt{#2}$}\dimen@\ht\zerocount
+ \advance\dimen@-\dp\zerocount
+ \mkern5mu\raise.6\dimen@\copy\rootbox \mkern-10mu\box\zerocount}
\def\PLAINmatrix#1%
- {\null\,\vcenter{\normalbaselines\m@th
+ {\null\,\vcenter{\normalbaselines\mathsurround\zeropoint
\ialign{\hfil$##$\hfil&&\quad\hfil$##$\hfil\crcr
\mathstrut\crcr\noalign{\kern-\baselineskip}
#1\crcr\mathstrut\crcr\noalign{\kern-\baselineskip}}}\,}
@@ -651,7 +651,7 @@
%D The next macro vertically centeres its contents.
\def\@center@math#1%
- {\vcenter{\hbox{$\m@th#1$}}}
+ {\vcenter{\hbox{$\mathsurround\zeropoint#1$}}}
\def\@center@colon
{\mathpalette\@center@math{\colon}}
@@ -712,7 +712,6 @@
\mkern7mu\mathchoice{\mkern2mu}{}{}{}%
\let\dointlimits\egroup}
-
\setupmathematics
[integral=nolimits]
diff --git a/tex/context/base/math-tim.tex b/tex/context/base/math-tim.tex
index de6561ba7..3b9aea103 100644
--- a/tex/context/base/math-tim.tex
+++ b/tex/context/base/math-tim.tex
@@ -1,6 +1,6 @@
%D \module
%D [ file=math-tim,
-%D version=2001.04.12,
+%D version=2001.04.12,
%D title=\CONTEXT\ Math Macros,
%D subtitle=Mathtime Specials,
%D author={Hans Hagen \& Taco Hoekwater},
@@ -13,24 +13,24 @@
\endinput % i will clean this up after taco has gone over it
-%D With thanks to Berthold Horn from YandY for providing me
-%D evaluation copies of the MathTimePlus fonts.
+%D With thanks to Berthold Horn from YandY for providing me
+%D evaluation copies of the MathTimePlus fonts.
% version 0 : Michael Spivak
% version 1 : Taco Hoekwater
% version 2 : Hans Hagen
-% version 3 : etc etc etc
+% version 3 : etc etc etc
\unprotect
%D We use the predefined spare families \type {\mcfam} and
-%D \type {\mdfam}.
+%D \type {\mdfam}.
\let\cafam\mcfam \let\hexcafam\hexmcfam
\let\gbfam\mdfam \let\hexgbfam\hexmdfam
\let\gkfam\mdfam \let\hexgkfam\hexmdfam
-% Why is this needed?
+% Why is this needed?
% \font\tenmd =mtgu at 10pt
% \font\sevenmd=mtgu at 7.6pt
@@ -38,7 +38,7 @@
% \font\tenmc =mtms at 10pt
% \font\sevenmc=mtms at 7.6pt
% \font\fivemc =mtms at 6pt
-%
+%
% \textfont \mcfam\tenmc \textfont \mdfam\tenmd
% \scriptfont \mcfam\sevenmc \scriptfont \mdfam\sevenmd
% \scriptscriptfont\mcfam\fivemc \scriptscriptfont\mdfam\fivemd
@@ -52,7 +52,7 @@
% \definealternativestyle[script] [\ca][\ca]
% \definealternativestyle[greek] [\gk][\gk]
-% \definealternativestyle[boldgreek][\gb][\gb]
+% \definealternativestyle[boldgreek][\gb][\gb]
% \definebodyfont
% [5pt,6pt,7pt,8pt,9pt,10pt,11pt,12pt,14.4pt] [rm]
@@ -60,9 +60,9 @@
% gk=mtgu sa 1,
% gb=mtgub sa 1]
-%D Since a font size is a rather fuzzy thing, it will be no
-%D surprise that the Math Times fonts have different specs
-%D than the Computer Modern Roman fonts.
+%D Since a font size is a rather fuzzy thing, it will be no
+%D surprise that the Math Times fonts have different specs
+%D than the Computer Modern Roman fonts.
%D
%D \starttabulate[|Bl|c|c|c|c|c|c|c|c|c|c|]
%D \NC Computer Modern\NC
@@ -71,9 +71,9 @@
%D 6.0\NC6.8\NC7.6\NC8.4\NC9.2\NC10.0\NC10.8\NC11.6\NC13.2\NC--\NC\NR
%D \stoptabulate
%D
-%D The following definitions presume the existence of \type
-%D {tio} and \type {tibio} font alternatives. Definitions for
-%D \type {\tf.} etc and \type {\sc} are left as they are.
+%D The following definitions presume the existence of \type
+%D {tio} and \type {tibio} font alternatives. Definitions for
+%D \type {\tf.} etc and \type {\sc} are left as they are.
%D moved code
@@ -100,10 +100,10 @@
\def\tildehex{7E}
\def\ddothex {7F}
-%D The \type {mtex} fonts need a recalculation of \type
+%D The \type {mtex} fonts need a recalculation of \type
%D {\p@renwd}, which in \CONTEXT\ is done automatically.
-%D The following definitions are mostly copied from the file
+%D The following definitions are mostly copied from the file
%D \type {mtmacs.tex}, which banner said:
%D
%D \starttyping
@@ -112,9 +112,9 @@
%D ALL RIGHTS RESERVED
%D \stoptyping
%D
-%D We reformatted the macros and changed a few bits and
-%D pieces. A further cleanup with regards to the scratch
-%D registers will be done later.
+%D We reformatted the macros and changed a few bits and
+%D pieces. A further cleanup with regards to the scratch
+%D registers will be done later.
\mathchardef\Gamma = "0130
\mathchardef\Delta = "0131
@@ -171,7 +171,7 @@
% like \rm (cf. the texbook page 290)
\def\ifdefaultfamelse#1#2%
- {\ifnum\fam=\m@ne\mathaccent#1\else\mathaccent#2\fi}
+ {\ifnum\fam=\minusone\mathaccent#1\else\mathaccent#2\fi}
\let\noaccents@\relax
@@ -190,10 +190,10 @@
\def\mathhexbox@#1#2#3%
{\relax
\ifmmode
- \mathpalette{}{\m@th\rm\mathchar"#1#2#3}%
+ \mathpalette{}{\mathsurround\zeropoint\rm\mathchar"#1#2#3}%
\else
\leavevmode
- \hbox{$\m@th\rm\mathchar"#1#2#3$}%
+ \hbox{$\mathsurround\zeropoint\rm\mathchar"#1#2#3$}%
\fi}
\def\dag {\edef\next@{0\daghex }\expandafter\mathhexbox@\next@}
@@ -204,16 +204,16 @@
\def\vdots%
{\vbox
- {\baselineskip4\p@
- \lineskiplimit\z@
- \kern6\p@\hbox{$\m@th.$}\hbox{$\m@th.$}\hbox{$\m@th.$}}}
+ {\baselineskip4\points
+ \lineskiplimit\zeropoint
+ \kern6\points\hbox{$\mathsurround\zeropoint.$}\hbox{$\mathsurround\zeropoint.$}\hbox{$\mathsurround\zeropoint.$}}}
\def\ddots%
{\mathinner
{\mkern1mu
- \raise7\p@\vbox{\kern 7\p@\hbox{$\m@th.$}}\mkern2mu
- \raise4\p@\hbox{$\m@th.$}\mkern2mu
- \raise \p@\hbox{$\m@th.$}\mkern1mu}}
+ \raise7\points\vbox{\kern 7\points\hbox{$\mathsurround\zeropoint.$}}\mkern2mu
+ \raise4\points\hbox{$\mathsurround\zeropoint.$}\mkern2mu
+ \raise \points\hbox{$\mathsurround\zeropoint.$}\mkern1mu}}
\def\hbar
{{\mathchoice
@@ -224,10 +224,10 @@
\mkern-6.3muh}}
\def\angle%
- {{\vbox{\ialign{$\m@th\scriptstyle##$\crcr
+ {{\vbox{\ialign{$\mathsurround\zeropoint\scriptstyle##$\crcr
\not\mathrel{\mkern14mu}\crcr
\noalign{\nointerlineskip}
- \mkern2.5mu\leaders\hrule height.48\p@\hfill\mkern2.5mu\crcr}}}}
+ \mkern2.5mu\leaders\hrule height.48\points\hfill\mkern2.5mu\crcr}}}}
\newdimen\amstexex
@@ -235,25 +235,25 @@
\def\varinjlim%
{\mathop{\vtop{\ialign{##\crcr
- \hfil\the\textfont\z@ lim\hfil\crcr
+ \hfil\the\textfont\zerocount lim\hfil\crcr
\noalign{\nointerlineskip}\rightarrowfill\crcr
\noalign{\nointerlineskip\kern-\amstexex}\crcr}}}}
\def\varprojlim%
{\mathop{\vtop{\ialign{##\crcr
- \hfil\the\textfont\z@ lim\hfil\crcr
+ \hfil\the\textfont\zerocount lim\hfil\crcr
\noalign{\nointerlineskip}\leftarrowfill\crcr
\noalign{\nointerlineskip\kern-\amstexex}\crcr}}}}
\def\varliminf{\mathop{\underbar {lim}}} % context-ified
\def\varlimsup{\mathop{\overstrike{lim}}} % context-ified
-\def\spdot {^{\hbox{\raise\amstexex\hbox{\the\textfont\z@ .}}}}
-\def\spddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\z@ ..}}}}
-\def\spdddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\z@ ...}}}}
-\def\spddddot{^{\hbox{\raise\amstexex\hbox{\the\textfont\z@....}}}}
+\def\spdot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount .}}}}
+\def\spddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount ..}}}}
+\def\spdddot {^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount ...}}}}
+\def\spddddot{^{\hbox{\raise\amstexex\hbox{\the\textfont\zerocount....}}}}
-%D Here some code is merged in order to save strings.
+%D Here some code is merged in order to save strings.
\def\domultidot#1#2%
{\setbox0\hbox{$#1#2$}%
@@ -303,29 +303,29 @@
\fi}
\def\root#1\of#2%
- {\setbox\rootbox=\hbox{$\m@th\scriptscriptstyle{#1}$}%
+ {\setbox\rootbox=\hbox{$\mathsurround\zeropoint\scriptscriptstyle{#1}$}%
\mathpalette\r@@t{#2}}
\def\r@@t#1#2%
- {\setbox\z@=\hbox{$\uproot@\z@\leftroot\z@\m@th#1\sqrt{#2}$}%
- \dimen@\ht\z@\advance\dimen@-\dp\z@
+ {\setbox\zerocount\hbox{$\uproot@\zerocount\leftroot\zerocount\mathsurround\zeropoint#1\sqrt{#2}$}%
+ \dimen@\ht\zerocount\advance\dimen@-\dp\zerocount
\dimen@ii\dimen@
- \ifdim\dimen@>30\p@ \advance\dimen@ii-16\p@ \else
- \ifdim\dimen@>24\p@ \advance\dimen@ii -8\p@ \else
- \ifdim\dimen@>18\p@ \advance\dimen@ii -6\p@ \else
- \ifdim\dimen@>12\p@ \advance\dimen@ii -4\p@ \else
- \ifdim\dimen@>10\p@ \advance\dimen@ii -2\p@ \fi\fi\fi\fi\fi
- \setbox\tw@=\hbox{$\m@th#1\mskip\uproot@ mu$}%
- \advance\dimen@ii by1.667\wd\tw@
+ \ifdim\dimen@>30\points \advance\dimen@ii-16\points \else
+ \ifdim\dimen@>24\points \advance\dimen@ii -8\points \else
+ \ifdim\dimen@>18\points \advance\dimen@ii -6\points \else
+ \ifdim\dimen@>12\points \advance\dimen@ii -4\points \else
+ \ifdim\dimen@>10\points \advance\dimen@ii -2\points \fi\fi\fi\fi\fi
+ \setbox\plustwo=\hbox{$\mathsurround\zeropoint#1\mskip\uproot@ mu$}%
+ \advance\dimen@ii by1.667\wd\plustwo
\mkern-\leftroot@ mu\mkern5mu\raise.6\dimen@ii\copy\rootbox
- \mkern-8mu\mkern\leftroot@ mu\box\z@\leftroot\z@\uproot\z@}
+ \mkern-8mu\mkern\leftroot@ mu\box\zerocount\leftroot\zerocount\uproot\zerocount}
\def\space@.{\futurelet\space@\relax} \space@. % really needed ?
\def\jadjust%
- {\mkern-\tw@ mu}
+ {\mkern-\plustwo mu}
-%D For the moment the following code is left unchanged. It is
+%D For the moment the following code is left unchanged. It is
%D not used anyway.
\newif\ifsubscriptcorrection \subscriptcorrectionfalse
@@ -358,11 +358,11 @@
\else
\def\next@.%
{\ifx\next j%
- \mkern-\tw@ mu\else
+ \mkern-\plustwo mu\else
\ifx\next f%
- \mkern-\tw@ mu\else
+ \mkern-\plustwo mu\else
\ifx\next p%
- \mkern-\@ne mu\fi\fi\fi}%
+ \mkern-\plusone mu\fi\fi\fi}%
\fi
\next@.}
diff --git a/tex/context/base/math-vfu.lua b/tex/context/base/math-vfu.lua
new file mode 100644
index 000000000..35d18d77a
--- /dev/null
+++ b/tex/context/base/math-vfu.lua
@@ -0,0 +1,1534 @@
+if not modules then modules = { } end modules ['math-vfu'] = {
+ version = 1.001,
+ comment = "companion to math-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- All these math vectors .. thanks to Aditya and Mojca they become
+-- better and better.
+
+local type, next = type, next
+
+local trace_virtual = false trackers.register("math.virtual", function(v) trace_virtual = v end)
+local trace_timings = false trackers.register("math.timings", function(v) trace_timings = v end)
+
+fonts.enc.math = fonts.enc.math or { }
+
+local shared = { }
+
+fonts.vf.math = fonts.vf.math or { }
+fonts.vf.math.optional = false
+
+local push, pop, back = { "push" }, { "pop" }, { "slot", 1, 0x2215 }
+
+local function negate(main,unicode,basecode)
+ local characters = main.characters
+ if not characters[unicode] then
+ local basechar = characters[basecode]
+ if basechar then
+ local ht, wd = basechar.height, basechar.width
+ characters[unicode] = {
+ width = wd,
+ height = ht,
+ depth = basechar.depth,
+ italic = basechar.italic,
+ kerns = basechar.kerns,
+ commands = {
+ { "slot", 1, basecode },
+ push,
+ { "down", ht/5},
+ { "right", - wd/2},
+ back,
+ push,
+ }
+ }
+ end
+ end
+end
+
+--~ \Umathchardef\braceld="0 "1 "FF07A
+--~ \Umathchardef\bracerd="0 "1 "FF07B
+--~ \Umathchardef\bracelu="0 "1 "FF07C
+--~ \Umathchardef\braceru="0 "1 "FF07D
+
+local function brace(main,unicode,first,rule,left,right,rule,last)
+ local characters = main.characters
+ if not characters[unicode] then
+ characters[unicode] = {
+ horiz_variants = {
+ { extender = 0, glyph = first },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = left },
+ { extender = 0, glyph = right },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = last },
+ }
+ }
+ end
+end
+
+local function arrow(main,unicode,arrow,minus,isleft)
+ if isleft then
+ t = {
+ { extender = 0, glyph = arrow },
+ { extender = 1, glyph = minus },
+ }
+ else
+ t = {
+ { extender = 0, glyph = minus },
+ { extender = 1, glyph = arrow },
+ }
+ end
+--~ main.characters[unicode] = { horiz_variants = t }
+ main.characters[unicode].horiz_variants = t
+end
+
+local function parent(main,unicode,first,rule,last)
+ local characters = main.characters
+ if not characters[unicode] then
+ characters[unicode] = {
+ horiz_variants = {
+ { extender = 0, glyph = first },
+ { extender = 1, glyph = rule },
+ { extender = 0, glyph = last },
+ }
+ }
+ end
+end
+
+local push, pop, step = { "push" }, { "pop" }, 0.2 -- 0.1 is nicer but gives larger files
+
+local function make(main,id,size,n,m)
+ local characters = main.characters
+ local xu = main.parameters.x_height + 0.3*size
+ local xd = 0.3*size
+ local old, upslot, dnslot, uprule, dnrule = 0xFF000+n, 0xFF100+n, 0xFF200+n, 0xFF300+m, 0xFF400+m
+ local c = characters[old]
+ if c then
+ local w, h, d = c.width, c.height, c.depth
+ local thickness = h - d
+ local rulewidth = step*size -- we could use an overlap
+ local slot = { "slot", id, old }
+ local rule = { "rule", thickness, rulewidth }
+ local up = { "down", -xu }
+ local dn = { "down", xd }
+ local ht, dp = xu + 3*thickness, 0
+ if not characters[uprule] then
+ characters[uprule] = { width = rulewidth, height = ht, depth = dp, commands = { push, up, rule, pop } }
+ end
+ characters[upslot] = { width = w, height = ht, depth = dp, commands = { push, up, slot, pop } }
+ local ht, dp = 0, xd + 3*thickness
+ if not characters[dnrule] then
+ characters[dnrule] = { width = rulewidth, height = ht, depth = dp, commands = { push, dn, rule, pop } }
+ end
+ characters[dnslot] = { width = w, height = ht, depth = dp, commands = { push, dn, slot, pop } }
+ end
+end
+
+local function minus(main,id,size,unicode)
+ local characters = main.characters
+ local mu = size/18
+ local minus = characters[0x002D]
+ local width = minus.width - 5*mu
+ characters[unicode] = {
+ width = width, height = minus.height, depth = minus.depth,
+ commands = { push, { "right", -3*mu }, { "slot", id, 0x002D }, pop }
+ }
+end
+
+local function dots(main,id,size,unicode)
+ local characters = main.characters
+ local c = characters[0x002E]
+ local w, h, d = c.width, c.height, c.depth
+ local mu = size/18
+ local right3mu = { "right", 3*mu }
+ local right1mu = { "right", 1*mu }
+ local up1size = { "down", -.1*size }
+ local up4size = { "down", -.4*size }
+ local up7size = { "down", -.7*size }
+ local right2muw = { "right", 2*mu + w }
+ local slot = { "slot", id, 0x002E }
+ if unicode == 0x22EF then
+ local c = characters[0x022C5]
+ if c then
+ local w, h, d = c.width, c.height, c.depth
+ local slot = { "slot", id, 0x022C5 }
+ characters[unicode] = {
+ width = 3*w + 2*3*mu, height = h, depth = d,
+ commands = { push, slot, right3mu, slot, right3mu, slot, pop }
+ }
+ end
+ elseif unicode == 0x22EE then
+ -- weird height !
+ characters[unicode] = {
+ width = w, height = h+(1.4)*size, depth = 0,
+ commands = { push, push, slot, pop, up4size, push, slot, pop, up4size, slot, pop }
+ }
+ elseif unicode == 0x22F1 then
+ characters[unicode] = {
+ width = 3*w + 6*size/18, height = 1.5*size, depth = 0,
+ commands = {
+ push,
+ right1mu,
+ push, up7size, slot, pop,
+ right2muw,
+ push, up4size, slot, pop,
+ right2muw,
+ push, up1size, slot, pop,
+ right1mu,
+ pop
+ }
+ }
+ elseif unicode == 0x22F0 then
+ characters[unicode] = {
+ width = 3*w + 6*size/18, height = 1.5*size, depth = 0,
+ commands = {
+ push,
+ right1mu,
+ push, up1size, slot, pop,
+ right2muw,
+ push, up4size, slot, pop,
+ right2muw,
+ push, up7size, slot, pop,
+ right1mu,
+ pop
+ }
+ }
+ else
+ characters[unicode] = {
+ width = 3*w + 2*3*mu, height = h, depth = d,
+ commands = { push, slot, right3mu, slot, right3mu, slot, pop }
+ }
+ end
+end
+
+function fonts.vf.math.alas(main,id,size)
+ for i=0x7A,0x7D do
+ make(main,id,size,i,1)
+ end
+ brace (main,0x23DE,0xFF17A,0xFF301,0xFF17D,0xFF17C,0xFF301,0xFF17B)
+ brace (main,0x23DF,0xFF27C,0xFF401,0xFF27B,0xFF27A,0xFF401,0xFF27D)
+ parent(main,0x23DC,0xFF17A,0xFF301,0xFF17B)
+ parent(main,0x23DD,0xFF27C,0xFF401,0xFF27D)
+ negate(main,0x2260,0x003D)
+ dots(main,id,size,0x2026) -- ldots
+ dots(main,id,size,0x22EE) -- vdots
+ dots(main,id,size,0x22EF) -- cdots
+ dots(main,id,size,0x22F1) -- ddots
+ dots(main,id,size,0x22F0) -- udots
+ minus(main,id,size,0xFF501)
+ arrow(main,0x2190,0xFE190,0xFF501,true) -- left
+ arrow(main,0x2192,0xFE192,0xFF501,false) -- right
+end
+
+local reverse -- index -> unicode
+
+function fonts.basecopy(tfmtable)
+ local t, c, p = { }, { }, { }
+ for k, v in next, tfmtable do
+ t[k] = v
+ end
+ for k, v in next, tfmtable.characters do
+ c[k] = v
+ end
+ for k, v in next, tfmtable.parameters do
+ p[k] = v
+ end
+ t.characters, t.parameters = c, p
+ return t
+end
+
+function fonts.vf.math.define(specification,set)
+ if not reverse then
+ reverse = { }
+ for k, v in next, fonts.enc.math do
+ local r = { }
+ for u, i in next, v do
+ r[i] = u
+ end
+ reverse[k] = r
+ end
+ end
+ local name = specification.name -- symbolic name
+ local size = specification.size -- given size
+ local fnt, lst, main = { }, { }, nil
+ local start = (trace_virtual or trace_timings) and os.clock()
+--~ texio.write_nl("defining font " .. name .. " " .. size)
+ local okset, n = { }, 0
+ for s=1,#set do
+ local ss = set[s]
+ local ssname = ss.name
+ if ss.optional and fonts.vf.math.optional then
+ if trace_virtual then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s is skipped",name,s,ssname,size)
+ end
+ else
+ if ss.features then ssname = ssname .. "*" .. ss.features end
+ if ss.main then main = s end
+ local f, id = fonts.tfm.read_and_define(ssname,size)
+ if not f then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s is skipped, not found",name,s,ssname,size)
+ else
+ n = n + 1
+ okset[n] = ss
+ fnt[n] = f
+ lst[n] = { id = id, size = size }
+ if not shared[s] then shared[n] = { } end
+ if trace_virtual then
+ logs.report("math virtual","loading font %s subfont %s with name %s at %s as id %s using encoding %s",name,s,ssname,size,id,ss.vector or "none")
+ end
+ end
+ end
+ end
+ -- beware, fnt[1] is already passed to tex (we need to make a simple copy then .. todo)
+ main = fonts.basecopy(fnt[1])
+ main.name, main.fonts, main.virtualized, main.math_parameters = name, lst, true, { }
+ local characters, descriptions = main.characters, main.descriptions
+ main.parameters.x_height = main.parameters.x_height or 0
+ for s=1,n do
+ local ss, fs = okset[s], fnt[s]
+ if not fs then
+ -- skip, error
+ elseif ss.optional and fonts.vf.math.optional then
+ -- skip, redundant
+ else
+ local mm, fp = main.math_parameters, fs.parameters
+ if ss.extension then
+ mm.math_x_height = fp.x_height or 0 -- math_x_height height of x
+ mm.default_rule_thickness = fp[ 8] or 0 -- default_rule_thickness thickness of \over bars
+ mm.big_op_spacing1 = fp[ 9] or 0 -- big_op_spacing1 minimum clearance above a displayed op
+ mm.big_op_spacing2 = fp[10] or 0 -- big_op_spacing2 minimum clearance below a displayed op
+ mm.big_op_spacing3 = fp[11] or 0 -- big_op_spacing3 minimum baselineskip above displayed op
+ mm.big_op_spacing4 = fp[12] or 0 -- big_op_spacing4 minimum baselineskip below displayed op
+ mm.big_op_spacing5 = fp[13] or 0 -- big_op_spacing5 padding above and below displayed limits
+ -- logs.report("math virtual","loading and virtualizing font %s at size %s, setting ex parameters",name,size)
+ elseif ss.parameters then
+ main.parameters.x_height = fp.x_height or main.parameters.x_height
+ mm.x_height = mm.x_height or fp.x_height or 0 -- x_height height of x
+ mm.num1 = fp[ 8] or 0 -- num1 numerator shift-up in display styles
+ mm.num2 = fp[ 9] or 0 -- num2 numerator shift-up in non-display, non-\atop
+ mm.num3 = fp[10] or 0 -- num3 numerator shift-up in non-display \atop
+ mm.denom1 = fp[11] or 0 -- denom1 denominator shift-down in display styles
+ mm.denom2 = fp[12] or 0 -- denom2 denominator shift-down in non-display styles
+ mm.sup1 = fp[13] or 0 -- sup1 superscript shift-up in uncramped display style
+ mm.sup2 = fp[14] or 0 -- sup2 superscript shift-up in uncramped non-display
+ mm.sup3 = fp[15] or 0 -- sup3 superscript shift-up in cramped styles
+ mm.sub1 = fp[16] or 0 -- sub1 subscript shift-down if superscript is absent
+ mm.sub2 = fp[17] or 0 -- sub2 subscript shift-down if superscript is present
+ mm.sup_drop = fp[18] or 0 -- sup_drop superscript baseline below top of large box
+ mm.sub_drop = fp[19] or 0 -- sub_drop subscript baseline below bottom of large box
+ mm.delim1 = fp[20] or 0 -- delim1 size of \atopwithdelims delimiters in display styles
+ mm.delim2 = fp[21] or 0 -- delim2 size of \atopwithdelims delimiters in non-displays
+ mm.axis_height = fp[22] or 0 -- axis_height height of fraction lines above the baseline
+ -- logs.report("math virtual","loading and virtualizing font %s at size %s, setting sy parameters",name,size)
+ end
+ local vectorname = ss.vector
+ if vectorname then
+ local offset = 0xFF000
+ local vector = fonts.enc.math[vectorname]
+ local rotcev = reverse[vectorname]
+ if vector then
+ local fc, fd, si = fs.characters, fs.descriptions, shared[s]
+ local skewchar = ss.skewchar
+ for unicode, index in next, vector do
+ local fci = fc[index]
+ if not fci then
+ -- if trace_virtual then
+ logs.report("math virtual", "unicode point U+%04X has no index %04X in %s",unicode,index,vectorname)
+ -- end
+ else
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local kerns = fci.kerns
+ if kerns then
+ local width = fci.width
+ local krn = { }
+ for k=1,#kerns do
+ local rk = rotcev[k]
+ if rk then
+ krn[rk] = kerns[k]
+ end
+ end
+ if not next(krn) then
+ krn = nil
+ end
+ local t = {
+ width = width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ kerns = krn,
+ commands = ref,
+ }
+ if skewchar and kerns then
+ local k = kerns[skewchar]
+ if k then
+ t.top_accent = width/2 + k
+ end
+ end
+ characters[unicode] = t
+ else
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ }
+ end
+ end
+ end
+ if ss.extension then
+ -- todo: if multiple ex, then 256 offsets per instance
+ local extension = fonts.enc.math["large-to-small"]
+ local variants_done = fs.variants_done
+ for index, fci in next, fc do -- the raw ex file
+ if type(index) == "number" then
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local t = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ }
+ local n = fci.next
+ if n then
+ t.next = offset + n
+ elseif variants_done then
+ local vv = fci.vert_variants
+ if vv then
+ t.vert_variants = vv
+ end
+ local hv = fci.horiz_variants
+ if hv then
+ t.horiz_variants = hv
+ end
+ else
+ local vv = fci.vert_variants
+ if vv then
+ for i=1,#vv do
+ local vvi = vv[i]
+ vvi.glyph = vvi.glyph + offset
+ end
+ t.vert_variants = vv
+ end
+ local hv = fci.horiz_variants
+ if hv then
+ for i=1,#hv do
+ local hvi = hv[i]
+ hvi.glyph = hvi.glyph + offset
+ end
+ t.horiz_variants = hv
+ end
+ end
+ characters[offset + index] = t
+ end
+ end
+ fs.variants_done = true
+ for unicode, index in next, extension do
+ local cu = characters[unicode]
+ if cu then
+ cu.next = offset + index
+ --~ local n, c, d = unicode, cu, { }
+ --~ print("START", unicode)
+ --~ while n do
+ --~ n = c.next
+ --~ if n then
+ --~ print("NEXT", n)
+ --~ c = characters[n]
+ --~ if not c then
+ --~ print("EXIT")
+ --~ elseif d[n] then
+ --~ print("LOOP")
+ --~ break
+ --~ end
+ --~ d[n] = true
+ --~ end
+ --~ end
+ else
+ local fci = fc[index]
+ local ref = si[index]
+ if not ref then
+ ref = { { 'slot', s, index } }
+ si[index] = ref
+ end
+ local kerns = fci.kerns
+ if kerns then
+ local krn = { }
+ for k=1,#kerns do
+ krn[offset + k] = kerns[k]
+ end
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ kerns = krn,
+ next = offset + index,
+ }
+ else
+ characters[unicode] = {
+ width = fci.width,
+ height = fci.height,
+ depth = fci.depth,
+ italic = fci.italic,
+ commands = ref,
+ next = offset + index,
+ }
+ end
+ end
+ end
+ end
+ end
+ end
+ mathematics.extras.copy(main) --not needed here (yet)
+ end
+ end
+ lst[#lst+1] = { id = font.nextid(), size = size }
+ fonts.vf.math.alas(main,#lst,size)
+ if trace_virtual or trace_timings then
+ logs.report("math virtual","loading and virtualizing font %s at size %s took %0.3f seconds",name,size,os.clock()-start)
+ end
+ main.has_italic = true
+ main.type = "virtual" -- not needed
+ mathematics.scaleparameters(main,main,1)
+ return main
+end
+
+function mathematics.make_font(name, set)
+ fonts.define.methods[name] = function(specification)
+ return fonts.vf.math.define(specification,set)
+ end
+end
+
+-- varphi is part of the alphabet, contrary to the other var*s'
+
+fonts.enc.math["large-to-small"] = {
+ [0x00028] = 0x00, -- (
+ [0x00029] = 0x01, -- )
+ [0x0005B] = 0x02, -- [
+ [0x0005D] = 0x03, -- ]
+ [0x0230A] = 0x04, -- lfloor
+ [0x0230B] = 0x05, -- rfloor
+ [0x02308] = 0x06, -- lceil
+ [0x02309] = 0x07, -- rceil
+ [0x0007B] = 0x08, -- {
+ [0x0007D] = 0x09, -- }
+ [0x027E8] = 0x0A, -- <
+ [0x027E9] = 0x0B, -- >
+ [0x0007C] = 0x0C, -- |
+--~ [0x0] = 0x0D, -- lVert rVert Vert
+-- [0x0002F] = 0x0E, -- /
+ [0x0005C] = 0x0F, -- \
+--~ [0x0] = 0x3A, -- lgroup
+--~ [0x0] = 0x3B, -- rgroup
+--~ [0x0] = 0x3C, -- arrowvert
+--~ [0x0] = 0x3D, -- Arrowvert
+ [0x02195] = 0x3F, -- updownarrow
+--~ [0x0] = 0x40, -- lmoustache
+--~ [0x0] = 0x41, -- rmoustache
+ [0x0221A] = 0x70, -- sqrt
+ [0x021D5] = 0x77, -- Updownarrow
+ [0x02191] = 0x78, -- uparrow
+ [0x02193] = 0x79, -- downarrow
+ [0x021D1] = 0x7E, -- Uparrow
+ [0x021D3] = 0x7F, -- Downarrow
+ [0x0220F] = 0x59, -- prod
+ [0x02210] = 0x61, -- coprod
+ [0x02211] = 0x58, -- sum
+ [0x0222B] = 0x5A, -- intop
+ [0x0222E] = 0x49, -- ointop
+ [0xFE302] = 0x62, -- widehat
+ [0xFE303] = 0x65, -- widetilde
+ [0x022C0] = 0x5E, -- bigwedge
+ [0x022C1] = 0x5F, -- bigvee
+ [0x022C2] = 0x5C, -- bigcap
+ [0x022C3] = 0x5B, -- bigcup
+ [0x02044] = 0x0E, -- /
+}
+
+fonts.enc.math["tex-ex"] = {
+ [0x0220F] = 0x51, -- prod
+ [0x0222B] = 0x52, -- intop
+ [0x02210] = 0x60, -- coprod
+ [0x02211] = 0x50, -- sum
+ [0x022C0] = 0x56, -- bigwedge
+ [0x022C1] = 0x57, -- bigvee
+ [0x022C2] = 0x54, -- bigcap
+ [0x022C3] = 0x53, -- bigcup
+ [0x02A04] = 0x55, -- biguplus
+ [0x02A02] = 0x4E, -- bigotimes
+ [0x02A01] = 0x4C, -- bigoplus
+ [0x02A03] = 0x4A, -- bigodot
+ [0x0222E] = 0x48, -- ointop
+ [0x02A06] = 0x46, -- bigsqcup
+}
+
+-- only math stuff is needed, since we always use an lm or gyre
+-- font as main font
+
+fonts.enc.math["tex-mr"] = {
+ [0x00393] = 0x00, -- Gamma
+ [0x00394] = 0x01, -- Delta
+ [0x00398] = 0x02, -- Theta
+ [0x0039B] = 0x03, -- Lambda
+ [0x0039E] = 0x04, -- Xi
+ [0x003A0] = 0x05, -- Pi
+ [0x003A3] = 0x06, -- Sigma
+ [0x003A5] = 0x07, -- Upsilon
+ [0x003A6] = 0x08, -- Phi
+ [0x003A8] = 0x09, -- Psi
+ [0x003A9] = 0x0A, -- Omega
+-- [0x00060] = 0x12, -- [math]grave
+-- [0x000B4] = 0x13, -- [math]acute
+-- [0x002C7] = 0x14, -- [math]check
+-- [0x002D8] = 0x15, -- [math]breve
+-- [0x000AF] = 0x16, -- [math]bar
+-- [0x00021] = 0x21, -- !
+-- [0x00028] = 0x28, -- (
+-- [0x00029] = 0x29, -- )
+-- [0x0002B] = 0x2B, -- +
+-- [0x0002F] = 0x2F, -- /
+-- [0x0003A] = 0x3A, -- :
+-- [0x02236] = 0x3A, -- colon
+-- [0x0003B] = 0x3B, -- ;
+-- [0x0003C] = 0x3C, -- <
+-- [0x0003D] = 0x3D, -- =
+-- [0x0003E] = 0x3E, -- >
+-- [0x0003F] = 0x3F, -- ?
+ [0x00391] = 0x41, -- Alpha
+ [0x00392] = 0x42, -- Beta
+ [0x02145] = 0x44,
+ [0x00395] = 0x45, -- Epsilon
+ [0x00397] = 0x48, -- Eta
+ [0x00399] = 0x49, -- Iota
+ [0x0039A] = 0x4B, -- Kappa
+ [0x0039C] = 0x4D, -- Mu
+ [0x0039D] = 0x4E, -- Nu
+ [0x0039F] = 0x4F, -- Omicron
+ [0x003A1] = 0x52, -- Rho
+ [0x003A4] = 0x54, -- Tau
+ [0x003A7] = 0x58, -- Chi
+ [0x00396] = 0x5A, -- Zeta
+-- [0x0005B] = 0x5B, -- [
+-- [0x0005D] = 0x5D, -- ]
+-- [0x0005E] = 0x5E, -- [math]hat -- the text one
+ [0x00302] = 0x5E, -- [math]hat -- the real math one
+-- [0x002D9] = 0x5F, -- [math]dot
+ [0x02146] = 0x64,
+ [0x02147] = 0x65,
+-- [0x002DC] = 0x7E, -- [math]tilde -- the text one
+ [0x00303] = 0x7E, -- [math]tilde -- the real one
+-- [0x000A8] = 0x7F, -- [math]ddot
+}
+
+fonts.enc.math["tex-mi"] = {
+ [0x1D6E4] = 0x00, -- Gamma
+ [0x1D6E5] = 0x01, -- Delta
+ [0x1D6E9] = 0x02, -- Theta
+ [0x1D6F3] = 0x02, -- varTheta (not present in TeX)
+ [0x1D6EC] = 0x03, -- Lambda
+ [0x1D6EF] = 0x04, -- Xi
+ [0x1D6F1] = 0x05, -- Pi
+ [0x1D6F4] = 0x06, -- Sigma
+ [0x1D6F6] = 0x07, -- Upsilon
+ [0x1D6F7] = 0x08, -- Phi
+ [0x1D6F9] = 0x09, -- Psi
+ [0x1D6FA] = 0x0A, -- Omega
+ [0x1D6FC] = 0x0B, -- alpha
+ [0x1D6FD] = 0x0C, -- beta
+ [0x1D6FE] = 0x0D, -- gamma
+ [0x1D6FF] = 0x0E, -- delta
+ [0x1D716] = 0x0F, -- epsilon TODO: 1D716
+ [0x1D701] = 0x10, -- zeta
+ [0x1D702] = 0x11, -- eta
+ [0x1D703] = 0x12, -- theta TODO: 1D703
+ [0x1D704] = 0x13, -- iota
+ [0x1D705] = 0x14, -- kappa
+ [0x1D718] = 0x14, -- varkappa, not in tex fonts
+ [0x1D706] = 0x15, -- lambda
+ [0x1D707] = 0x16, -- mu
+ [0x1D708] = 0x17, -- nu
+ [0x1D709] = 0x18, -- xi
+ [0x1D70B] = 0x19, -- pi
+ [0x1D70C] = 0x1A, -- rho
+ [0x1D70E] = 0x1B, -- sigma
+ [0x1D70F] = 0x1C, -- tau
+ [0x1D710] = 0x1D, -- upsilon
+ [0x1D719] = 0x1E, -- phi
+ [0x1D712] = 0x1F, -- chi
+ [0x1D713] = 0x20, -- psi
+ [0x1D714] = 0x21, -- omega
+ [0x1D700] = 0x22, -- varepsilon (the other way around)
+ [0x1D717] = 0x23, -- vartheta
+ [0x1D71B] = 0x24, -- varpi
+ [0x1D71A] = 0x25, -- varrho
+ [0x1D70D] = 0x26, -- varsigma
+ [0x1D711] = 0x27, -- varphi (the other way around)
+ [0x021BC] = 0x28, -- leftharpoonup
+ [0x021BD] = 0x29, -- leftharpoondown
+ [0x021C0] = 0x2A, -- righttharpoonup
+ [0x021C1] = 0x2B, -- rightharpoondown
+ -- 0x2C, -- lhook (hook for combining arrows)
+ -- 0x2D, -- rhook (hook for combining arrows)
+ [0x022B3] = 0x2E, -- triangleright (TODO: which one is right?)
+ [0x022B2] = 0x2F, -- triangleleft (TODO: which one is right?)
+-- [0x00041] = 0x30, -- 0
+-- [0x00041] = 0x31, -- 1
+-- [0x00041] = 0x32, -- 2
+-- [0x00041] = 0x33, -- 3
+-- [0x00041] = 0x34, -- 4
+-- [0x00041] = 0x35, -- 5
+-- [0x00041] = 0x36, -- 6
+-- [0x00041] = 0x37, -- 7
+-- [0x00041] = 0x38, -- 8
+-- [0x00041] = 0x39, -- 9
+--~ [0x0002E] = 0x3A, -- .
+ [0x0002C] = 0x3B, -- ,
+ [0x0003C] = 0x3C, -- <
+-- [0x0002F] = 0x3D, -- /, slash, solidus
+ [0x02044] = 0x3D, -- / AM: Not sure
+ [0x0003E] = 0x3E, -- >
+ [0x022C6] = 0x3F, -- star
+ [0x02202] = 0x40, -- partial
+-- [0x00041] = 0x41, -- A
+ [0x1D6E2] = 0x41, -- Alpha
+-- [0x00042] = 0x42, -- B
+ [0x1D6E3] = 0x42, -- Beta
+-- [0x00043] = 0x43, -- C
+-- [0x00044] = 0x44, -- D
+-- [0x00045] = 0x45, -- E
+ [0x1D6E6] = 0x45, -- Epsilon
+-- [0x00046] = 0x46, -- F
+-- [0x00047] = 0x47, -- G
+-- [0x00048] = 0x48, -- H
+ [0x1D6E8] = 0x48, -- Eta
+-- [0x00049] = 0x49, -- I
+ [0x1D6EA] = 0x49, -- Iota
+-- [0x0004A] = 0x4A, -- J
+-- [0x0004B] = 0x4B, -- K
+ [0x1D6EB] = 0x4B, -- Kappa
+-- [0x0004C] = 0x4C, -- L
+-- [0x0004D] = 0x4D, -- M
+ [0x1D6ED] = 0x4D, -- Mu
+-- [0x0004E] = 0x4E, -- N
+ [0x1D6EE] = 0x4E, -- Nu
+-- [0x0004F] = 0x4F, -- O
+ [0x1D6F0] = 0x4F, -- Omicron
+-- [0x00050] = 0x50, -- P
+ [0x1D6F2] = 0x50, -- Rho
+-- [0x00051] = 0x51, -- Q
+-- [0x00052] = 0x52, -- R
+-- [0x00053] = 0x53, -- S
+-- [0x00054] = 0x54, -- T
+ [0x1D6F5] = 0x54, -- Tau
+-- [0x00055] = 0x55, -- U
+-- [0x00056] = 0x56, -- V
+-- [0x00057] = 0x57, -- W
+-- [0x00058] = 0x58, -- X
+ [0x1D6F8] = 0x58, -- Chi
+-- [0x00059] = 0x59, -- Y
+-- [0x0005A] = 0x5A, -- Z
+ [0x1D6E7] = 0x5A, -- Zeta
+ [0x0266D] = 0x5B, -- flat
+ [0x0266E] = 0x5C, -- natural
+ [0x0266F] = 0x5D, -- sharp
+ [0x02323] = 0x5E, -- smile
+ [0x02322] = 0x5F, -- frown
+ [0x02113] = 0x60, -- ell
+-- [0x00061] = 0x61, -- a
+-- [0x00062] = 0x62, -- b
+-- [0x00063] = 0x63, -- c
+-- [0x00064] = 0x64, -- d
+-- [0x00065] = 0x65, -- e
+-- [0x00066] = 0x66, -- f
+-- [0x00067] = 0x67, -- g
+-- [0x00068] = 0x68, -- h
+ [0x0210E] = 0x68, -- plant constant
+-- [0x00069] = 0x69, -- i
+-- [0x0006A] = 0x6A, -- j
+-- [0x0006B] = 0x6B, -- k
+-- [0x0006C] = 0x6C, -- l
+-- [0x0006D] = 0x6D, -- m
+-- [0x0006E] = 0x6E, -- n
+-- [0x0006F] = 0x6F, -- o
+ [0x1D70A] = 0x6F, -- omicron
+-- [0x00070] = 0x70, -- p
+-- [0x00071] = 0x71, -- q
+-- [0x00072] = 0x72, -- r
+-- [0x00073] = 0x73, -- s
+-- [0x00074] = 0x74, -- t
+-- [0x00075] = 0x75, -- u
+-- [0x00076] = 0x76, -- v
+-- [0x00077] = 0x77, -- w
+-- [0x00078] = 0x78, -- x
+-- [0x00079] = 0x79, -- y
+-- [0x0007A] = 0x7A, -- z
+ [0x1D6A4] = 0x7B, -- imath (TODO: also 0131)
+ [0x1D6A5] = 0x7C, -- jmath (TODO: also 0237)
+ [0x02118] = 0x7D, -- wp
+ [0x020D7] = 0x7E, -- vec (TODO: not sure)
+-- 0x7F, -- (no idea what that could be)
+}
+
+fonts.enc.math["tex-ss"] = { }
+fonts.enc.math["tex-tt"] = { }
+fonts.enc.math["tex-bf"] = { }
+fonts.enc.math["tex-bi"] = { }
+fonts.enc.math["tex-fraktur"] = { }
+fonts.enc.math["tex-fraktur-bold"] = { }
+
+function fonts.vf.math.set_letters(font_encoding, name, uppercase, lowercase)
+ local enc = font_encoding[name]
+ for i = 0,25 do
+ enc[uppercase+i] = i + 0x41
+ enc[lowercase+i] = i + 0x61
+ end
+end
+
+function fonts.vf.math.set_digits(font_encoding, name, digits)
+ local enc = font_encoding[name]
+ for i = 0,9 do
+ enc[digits+i] = i + 0x30
+ end
+end
+
+fonts.enc.math["tex-sy"] = {
+ [0x0002D] = 0x00, -- -
+ [0x02212] = 0x00, -- -
+-- [0x02201] = 0x00, -- complement
+-- [0x02206] = 0x00, -- increment
+-- [0x02204] = 0x00, -- not exists
+--~ [0x000B7] = 0x01, -- cdot
+ [0x022C5] = 0x01, -- cdot
+ [0x000D7] = 0x02, -- times
+ [0x0002A] = 0x03, -- *
+ [0x02217] = 0x03, -- *
+ [0x000F7] = 0x04, -- div
+ [0x022C4] = 0x05, -- diamond
+ [0x000B1] = 0x06, -- pm
+ [0x02213] = 0x07, -- mp
+ [0x02295] = 0x08, -- oplus
+ [0x02296] = 0x09, -- ominus
+ [0x02297] = 0x0A, -- otimes
+ [0x02298] = 0x0B, -- oslash
+ [0x02299] = 0x0C, -- odot
+ [0x025EF] = 0x0D, -- bigcirc, Orb (either 25EF or 25CB) -- todo
+ [0x02218] = 0x0E, -- circ
+ [0x02219] = 0x0F, -- bullet
+ [0x02022] = 0x0F, -- bullet
+ [0x0224D] = 0x10, -- asymp
+ [0x02261] = 0x11, -- equiv
+ [0x02286] = 0x12, -- subseteq
+ [0x02287] = 0x13, -- supseteq
+ [0x02264] = 0x14, -- leq
+ [0x02265] = 0x15, -- geq
+ [0x02AAF] = 0x16, -- preceq
+-- [0x0227C] = 0x16, -- preceq, AM:No see 2AAF
+ [0x02AB0] = 0x17, -- succeq
+-- [0x0227D] = 0x17, -- succeq, AM:No see 2AB0
+ [0x0223C] = 0x18, -- sim
+ [0x02248] = 0x19, -- approx
+ [0x02282] = 0x1A, -- subset
+ [0x02283] = 0x1B, -- supset
+ [0x0226A] = 0x1C, -- ll
+ [0x0226B] = 0x1D, -- gg
+ [0x0227A] = 0x1E, -- prec
+ [0x0227B] = 0x1F, -- succ
+ [0x02190] = 0x20, -- leftarrow
+ [0x02192] = 0x21, -- rightarrow
+--~ [0xFE190] = 0x20, -- leftarrow
+--~ [0xFE192] = 0x21, -- rightarrow
+ [0x02191] = 0x22, -- uparrow
+ [0x02193] = 0x23, -- downarrow
+ [0x02194] = 0x24, -- leftrightarrow
+ [0x02197] = 0x25, -- nearrow
+ [0x02198] = 0x26, -- searrow
+ [0x02243] = 0x27, -- simeq
+ [0x021D0] = 0x28, -- Leftarrow
+ [0x021D2] = 0x29, -- Rightarrow
+ [0x021D1] = 0x2A, -- Uparrow
+ [0x021D3] = 0x2B, -- Downarrow
+ [0x021D4] = 0x2C, -- Leftrightarrow
+ [0x02196] = 0x2D, -- nwarrow
+ [0x02199] = 0x2E, -- swarrow
+ [0x0221D] = 0x2F, -- propto
+ [0x02032] = 0x30, -- prime
+ [0x0221E] = 0x31, -- infty
+ [0x02208] = 0x32, -- in
+ [0x0220B] = 0x33, -- ni
+ [0x025B3] = 0x34, -- triangle, bigtriangleup
+ [0x025BD] = 0x35, -- bigtriangledown
+ [0x00338] = 0x36, -- not
+-- 0x37, -- (beginning of arrow)
+ [0x02200] = 0x38, -- forall
+ [0x02203] = 0x39, -- exists
+ [0x000AC] = 0x3A, -- neg, lnot
+ [0x02205] = 0x3B, -- empty set
+ [0x0211C] = 0x3C, -- Re
+ [0x02111] = 0x3D, -- Im
+ [0x022A4] = 0x3E, -- top
+ [0x022A5] = 0x3F, -- bot, perp
+ [0x02135] = 0x40, -- aleph
+ [0x1D49C] = 0x41, -- script A
+ [0x0212C] = 0x42, -- script B
+ [0x1D49E] = 0x43, -- script C
+ [0x1D49F] = 0x44, -- script D
+ [0x02130] = 0x45, -- script E
+ [0x02131] = 0x46, -- script F
+ [0x1D4A2] = 0x47, -- script G
+ [0x0210B] = 0x48, -- script H
+ [0x02110] = 0x49, -- script I
+ [0x1D4A5] = 0x4A, -- script J
+ [0x1D4A6] = 0x4B, -- script K
+ [0x02112] = 0x4C, -- script L
+ [0x02133] = 0x4D, -- script M
+ [0x1D4A9] = 0x4E, -- script N
+ [0x1D4AA] = 0x4F, -- script O
+ [0x1D4AB] = 0x50, -- script P
+ [0x1D4AC] = 0x51, -- script Q
+ [0x0211B] = 0x52, -- script R
+ [0x1D4AE] = 0x53, -- script S
+ [0x1D4AF] = 0x54, -- script T
+ [0x1D4B0] = 0x55, -- script U
+ [0x1D4B1] = 0x56, -- script V
+ [0x1D4B2] = 0x57, -- script W
+ [0x1D4B3] = 0x58, -- script X
+ [0x1D4B4] = 0x59, -- script Y
+ [0x1D4B5] = 0x5A, -- script Z
+ [0x0222A] = 0x5B, -- cup
+ [0x02229] = 0x5C, -- cap
+ [0x0228E] = 0x5D, -- uplus
+ [0x02227] = 0x5E, -- wedge, land
+ [0x02228] = 0x5F, -- vee, lor
+ [0x022A2] = 0x60, -- vdash
+ [0x022A3] = 0x61, -- dashv
+ [0x0230A] = 0x62, -- lfloor
+ [0x0230B] = 0x63, -- rfloor
+ [0x02308] = 0x64, -- lceil
+ [0x02309] = 0x65, -- rceil
+ [0x0007B] = 0x66, -- {, lbrace
+ [0x0007D] = 0x67, -- }, rbrace
+ [0x027E8] = 0x68, -- <, langle
+ [0x027E9] = 0x69, -- >, rangle
+ [0x0007C] = 0x6A, -- |, mid, lvert, rvert
+ [0x02225] = 0x6B, -- parallel, Vert, lVert, rVert, arrowvert
+ [0x02195] = 0x6C, -- updownarrow
+ [0x021D5] = 0x6D, -- Updownarrow
+ [0x0005C] = 0x6E, -- \, backslash, setminus
+ [0x02216] = 0x6E, -- setminus
+ [0x02240] = 0x6F, -- wr
+ [0x0221A] = 0x70, -- sqrt. AM: Check surd??
+ [0x02A3F] = 0x71, -- amalg
+ [0x1D6FB] = 0x72, -- nabla
+-- [0x0222B] = 0x73, -- smallint (TODO: what about intop?)
+ [0x02294] = 0x74, -- sqcup
+ [0x02293] = 0x75, -- sqcap
+ [0x02291] = 0x76, -- sqsubseteq
+ [0x02292] = 0x77, -- sqsupseteq
+ [0x000A7] = 0x78, -- S
+ [0x02020] = 0x79, -- dagger, dag
+ [0x02021] = 0x7A, -- ddagger, ddag
+ [0x000B6] = 0x7B, -- P
+ [0x02663] = 0x7C, -- clubsuit
+ [0x02662] = 0x7D, -- diamondsuit
+ [0x02661] = 0x7E, -- heartsuit
+ [0x02660] = 0x7F, -- spadesuit
+ [0xFE321] = 0x37, -- mapstochar
+}
+
+-- The names in masm10.enc can be trusted best and are shown in the first
+-- column, while in the second column we show the tex/ams names. As usual
+-- it costs hours to figure out such a table.
+
+fonts.enc.math["tex-ma"] = {
+ [0x022A1] = 0x00, -- squaredot \boxdot
+ [0x0229E] = 0x01, -- squareplus \boxplus
+ [0x022A0] = 0x02, -- squaremultiply \boxtimes
+ [0x025A1] = 0x03, -- square \square \Box
+ [0x025A0] = 0x04, -- squaresolid \blacksquare
+ [0x000B7] = 0x05, -- squaresmallsolid \centerdot
+ [0x022C4] = 0x06, -- diamond \Diamond \lozenge
+ [0x029EB] = 0x07, -- diamondsolid \blacklozenge
+ [0x021BA] = 0x08, -- clockwise \circlearrowright
+ [0x021BB] = 0x09, -- anticlockwise \circlearrowleft
+ [0x021CC] = 0x0A, -- harpoonleftright \rightleftharpoons
+ [0x021CB] = 0x0B, -- harpoonrightleft \leftrightharpoons
+ [0x0229F] = 0x0C, -- squareminus \boxminus
+ [0x022A9] = 0x0D, -- forces \Vdash
+ [0x022AA] = 0x0E, -- forcesbar \Vvdash
+ [0x022A8] = 0x0F, -- satisfies \vDash
+ [0x021A0] = 0x10, -- dblarrowheadright \twoheadrightarrow
+ [0x0219E] = 0x11, -- dblarrowheadleft \twoheadleftarrow
+ [0x021C7] = 0x12, -- dblarrowleft \leftleftarrows
+ [0x021C9] = 0x13, -- dblarrowright \rightrightarrows
+ [0x021C8] = 0x14, -- dblarrowup \upuparrows
+ [0x021CA] = 0x15, -- dblarrowdwn \downdownarrows
+ [0x021BE] = 0x16, -- harpoonupright \upharpoonright \restriction
+ [0x021C2] = 0x17, -- harpoondownright \downharpoonright
+ [0x021BF] = 0x18, -- harpoonupleft \upharpoonleft
+ [0x021C3] = 0x19, -- harpoondownleft \downharpoonleft
+ [0x021A3] = 0x1A, -- arrowtailright \rightarrowtail
+ [0x021A2] = 0x1B, -- arrowtailleft \leftarrowtail
+ [0x021C6] = 0x1C, -- arrowparrleftright \leftrightarrows
+-- [0x021C5] = 0x00, -- \updownarrows (missing in lm)
+ [0x021C4] = 0x1D, -- arrowparrrightleft \rightleftarrows
+ [0x021B0] = 0x1E, -- shiftleft \Lsh
+ [0x021B1] = 0x1F, -- shiftright \Rsh
+ [0x021DD] = 0x20, -- squiggleright \leadsto \rightsquigarrow
+ [0x021AD] = 0x21, -- squiggleleftright \leftrightsquigarrow
+ [0x021AB] = 0x22, -- curlyleft \looparrowleft
+ [0x021AC] = 0x23, -- curlyright \looparrowright
+ [0x02257] = 0x24, -- circleequal \circeq
+ [0x0227F] = 0x25, -- followsorequal \succsim
+ [0x02273] = 0x26, -- greaterorsimilar \gtrsim
+ [0x02A86] = 0x27, -- greaterorapproxeql \gtrapprox
+ [0x022B8] = 0x28, -- multimap \multimap
+ [0x02234] = 0x29, -- therefore \therefore
+ [0x02235] = 0x2A, -- because \because
+ [0x02251] = 0x2B, -- equalsdots \Doteq \doteqdot
+ [0x0225C] = 0x2C, -- defines \triangleq
+ [0x0227E] = 0x2D, -- precedesorequal \precsim
+ [0x02272] = 0x2E, -- lessorsimilar \lesssim
+ [0x02A85] = 0x2F, -- lessorapproxeql \lessapprox
+ [0x02A95] = 0x30, -- equalorless \eqslantless
+ [0x02A96] = 0x31, -- equalorgreater \eqslantgtr
+ [0x022DE] = 0x32, -- equalorprecedes \curlyeqprec
+ [0x022DF] = 0x33, -- equalorfollows \curlyeqsucc
+ [0x0227C] = 0x34, -- precedesorcurly \preccurlyeq
+ [0x02266] = 0x35, -- lessdblequal \leqq
+ [0x02A7D] = 0x36, -- lessorequalslant \leqslant
+ [0x02276] = 0x37, -- lessorgreater \lessgtr
+ [0x02035] = 0x38, -- primereverse \backprime
+ -- [0x0] = 0x39, -- axisshort \dabar
+ [0x02253] = 0x3A, -- equaldotrightleft \risingdotseq
+ [0x02252] = 0x3B, -- equaldotleftright \fallingdotseq
+ [0x0227D] = 0x3C, -- followsorcurly \succcurlyeq
+ [0x02267] = 0x3D, -- greaterdblequal \geqq
+ [0x02A7E] = 0x3E, -- greaterorequalslant \geqslant
+ [0x02277] = 0x3F, -- greaterorless \gtrless
+ [0x0228F] = 0x40, -- squareimage \sqsubset
+ [0x02290] = 0x41, -- squareoriginal \sqsupset
+ -- wrong:
+ [0x022B3] = 0x42, -- triangleright \rhd \vartriangleright
+ [0x022B2] = 0x43, -- triangleleft \lhd \vartriangleleft
+ [0x022B5] = 0x44, -- trianglerightequal \unrhd \trianglerighteq
+ [0x022B4] = 0x45, -- triangleleftequal \unlhd \trianglelefteq
+ --
+ [0x02605] = 0x46, -- star \bigstar
+ [0x0226C] = 0x47, -- between \between
+ [0x025BC] = 0x48, -- triangledownsld \blacktriangledown
+ [0x025B6] = 0x49, -- trianglerightsld \blacktriangleright
+ [0x025C0] = 0x4A, -- triangleleftsld \blacktriangleleft
+ -- [0x0] = 0x4B, -- arrowaxisright
+ -- [0x0] = 0x4C, -- arrowaxisleft
+ [0x025B2] = 0x4D, -- triangle \triangleup \vartriangle
+ [0x025B2] = 0x4E, -- trianglesolid \blacktriangle
+ [0x025BC] = 0x4F, -- triangleinv \triangledown
+ [0x02256] = 0x50, -- ringinequal \eqcirc
+ [0x022DA] = 0x51, -- lessequalgreater \lesseqgtr
+ [0x022DB] = 0x52, -- greaterlessequal \gtreqless
+ [0x02A8B] = 0x53, -- lessdbleqlgreater \lesseqqgtr
+ [0x02A8C] = 0x54, -- greaterdbleqlless \gtreqqless
+ [0x000A5] = 0x55, -- Yen \yen
+ [0x021DB] = 0x56, -- arrowtripleright \Rrightarrow
+ [0x021DA] = 0x57, -- arrowtripleleft \Lleftarrow
+ [0x02713] = 0x58, -- check \checkmark
+ [0x022BB] = 0x59, -- orunderscore \veebar
+ [0x022BC] = 0x5A, -- nand \barwedge
+ [0x02306] = 0x5B, -- perpcorrespond \doublebarwedge
+ [0x02220] = 0x5C, -- angle \angle
+ [0x02221] = 0x5D, -- measuredangle \measuredangle
+ [0x02222] = 0x5E, -- sphericalangle \sphericalangle
+ -- [0x0] = 0x5F, -- proportional \varpropto
+ -- [0x0] = 0x60, -- smile \smallsmile
+ -- [0x0] = 0x61, -- frown \smallfrown
+ [0x022D0] = 0x62, -- subsetdbl \Subset
+ [0x022D1] = 0x63, -- supersetdbl \Supset
+ [0x022D3] = 0x64, -- uniondbl \doublecup \Cup
+ [0x00100] = 0x65, -- intersectiondbl \doublecap \Cap
+ [0x022CF] = 0x66, -- uprise \curlywedge
+ [0x022CE] = 0x67, -- downfall \curlyvee
+ [0x022CB] = 0x68, -- multiopenleft \leftthreetimes
+ [0x022CC] = 0x69, -- multiopenright \rightthreetimes
+ [0x02AC5] = 0x6A, -- subsetdblequal \subseteqq
+ [0x02AC6] = 0x6B, -- supersetdblequal \supseteqq
+ [0x0224F] = 0x6C, -- difference \bumpeq
+ [0x0224E] = 0x6D, -- geomequivalent \Bumpeq
+ [0x022D8] = 0x6E, -- muchless \lll \llless
+ [0x022D9] = 0x6F, -- muchgreater \ggg \gggtr
+ [0x0231C] = 0x70, -- rightanglenw \ulcorner
+ [0x0231D] = 0x71, -- rightanglene \urcorner
+ [0x024C7] = 0x72, -- circleR \circledR
+ [0x024C8] = 0x73, -- circleS \circledS
+ [0x022D4] = 0x74, -- fork \pitchfork
+ [0x02245] = 0x75, -- dotplus \dotplus
+ [0x0223D] = 0x76, -- revsimilar \backsim
+ [0x022CD] = 0x77, -- revasymptequal \backsimeq -- AM: Check this! I mapped it to simeq.
+ [0x0231E] = 0x78, -- rightanglesw \llcorner
+ [0x0231F] = 0x79, -- rightanglese \lrcorner
+ [0x02720] = 0x7A, -- maltesecross \maltese
+ [0x02201] = 0x7B, -- complement \complement
+ [0x022BA] = 0x7C, -- intercal \intercal
+ [0x0229A] = 0x7D, -- circlering \circledcirc
+ [0x0229B] = 0x7E, -- circleasterisk \circledast
+ [0x0229D] = 0x7F, -- circleminus \circleddash
+}
+
+fonts.enc.math["tex-mb"] = {
+ -- [0x0] = 0x00, -- lessornotequal \lvertneqq
+ -- [0x0] = 0x01, -- greaterornotequal \gvertneqq
+ [0x02270] = 0x02, -- notlessequal \nleq
+ [0x02271] = 0x03, -- notgreaterequal \ngeq
+ [0x0226E] = 0x04, -- notless \nless
+ [0x0226F] = 0x05, -- notgreater \ngtr
+ [0x02280] = 0x06, -- notprecedes \nprec
+ [0x02281] = 0x07, -- notfollows \nsucc
+ [0x02268] = 0x08, -- lessornotdbleql \lneqq
+ [0x02269] = 0x09, -- greaterornotdbleql \gneqq
+ -- [0x0] = 0x0A, -- notlessorslnteql \nleqslant
+ -- [0x0] = 0x0B, -- notgreaterorslnteql \ngeqslant
+ [0x02A87] = 0x0C, -- lessnotequal \lneq
+ [0x02A88] = 0x0D, -- greaternotequal \gneq
+ -- [0x0] = 0x0E, -- notprecedesoreql \npreceq
+ -- [0x0] = 0x0F, -- notfollowsoreql \nsucceq
+ [0x022E8] = 0x10, -- precedeornoteqvlnt \precnsim
+ [0x022E9] = 0x11, -- followornoteqvlnt \succnsim
+ [0x022E6] = 0x12, -- lessornotsimilar \lnsim
+ [0x022E7] = 0x13, -- greaterornotsimilar \gnsim
+ -- [0x0] = 0x14, -- notlessdblequal \nleqq
+ -- [0x0] = 0x15, -- notgreaterdblequal \ngeqq
+ [0x02AB5] = 0x16, -- precedenotslnteql \precneqq
+ [0x02AB6] = 0x17, -- follownotslnteql \succneqq
+ [0x02AB9] = 0x18, -- precedenotdbleqv \precnapprox
+ [0x02ABA] = 0x19, -- follownotdbleqv \succnapprox
+ [0x02A89] = 0x1A, -- lessnotdblequal \lnapprox
+ [0x02A8A] = 0x1B, -- greaternotdblequal \gnapprox
+ [0x02241] = 0x1C, -- notsimilar \nsim
+ [0x02247] = 0x1D, -- notapproxequal \ncong
+ -- [0x0] = 0x1E, -- upslope \diagup
+ -- [0x0] = 0x1F, -- downslope \diagdown
+ -- [0x0] = 0x20, -- notsubsetoreql \varsubsetneq
+ -- [0x0] = 0x21, -- notsupersetoreql \varsupsetneq
+ -- [0x0] = 0x22, -- notsubsetordbleql \nsubseteqq
+ -- [0x0] = 0x23, -- notsupersetordbleql \nsupseteqq
+ [0x02ACB] = 0x24, -- subsetornotdbleql \subsetneqq
+ [0x02ACC] = 0x25, -- supersetornotdbleql \supsetneqq
+ -- [0x0] = 0x26, -- subsetornoteql \varsubsetneqq
+ -- [0x0] = 0x27, -- supersetornoteql \varsupsetneqq
+ [0x0228A] = 0x28, -- subsetnoteql \subsetneq
+ [0x0228B] = 0x29, -- supersetnoteql \supsetneq
+ [0x02288] = 0x2A, -- notsubseteql \nsubseteq
+ [0x02289] = 0x2B, -- notsuperseteql \nsupseteq
+ [0x02226] = 0x2C, -- notparallel \nparallel
+ [0x02224] = 0x2D, -- notbar \nmid \ndivides
+ -- [0x0] = 0x2E, -- notshortbar \nshortmid
+ -- [0x0] = 0x2F, -- notshortparallel \nshortparallel
+ [0x022AC] = 0x30, -- notturnstile \nvdash
+ [0x022AE] = 0x31, -- notforces \nVdash
+ [0x022AD] = 0x32, -- notsatisfies \nvDash
+ [0x022AF] = 0x33, -- notforcesextra \nVDash
+ [0x022ED] = 0x34, -- nottriangeqlright \ntrianglerighteq
+ [0x022EC] = 0x35, -- nottriangeqlleft \ntrianglelefteq
+ [0x022EA] = 0x36, -- nottriangleleft \ntriangleleft
+ [0x022EB] = 0x37, -- nottriangleright \ntriangleright
+ [0x0219A] = 0x38, -- notarrowleft \nleftarrow
+ [0x0219B] = 0x39, -- notarrowright \nrightarrow
+ [0x021CD] = 0x3A, -- notdblarrowleft \nLeftarrow
+ [0x021CF] = 0x3B, -- notdblarrowright \nRightarrow
+ [0x021CE] = 0x3C, -- notdblarrowboth \nLeftrightarrow
+ [0x021AE] = 0x3D, -- notarrowboth \nleftrightarrow
+ [0x022C7] = 0x3E, -- dividemultiply \divideontimes
+ [0x02300] = 0x3F, -- diametersign \varnothing
+ [0x02204] = 0x40, -- notexistential \nexists
+ [0x1D538] = 0x41, -- A (blackboard A)
+ [0x1D539] = 0x42, -- B
+ [0x02102] = 0x43, -- C
+ [0x1D53B] = 0x44, -- D
+ [0x1D53C] = 0x45, -- E
+ [0x1D53D] = 0x46, -- F
+ [0x1D53E] = 0x47, -- G
+ [0x0210D] = 0x48, -- H
+ [0x1D540] = 0x49, -- I
+ [0x1D541] = 0x4A, -- J
+ [0x1D542] = 0x4B, -- K
+ [0x1D543] = 0x4C, -- L
+ [0x1D544] = 0x4D, -- M
+ [0x02115] = 0x4E, -- N
+ [0x1D546] = 0x4F, -- O
+ [0x02119] = 0x50, -- P
+ [0x0211A] = 0x51, -- Q
+ [0x0211D] = 0x52, -- R
+ [0x1D54A] = 0x53, -- S
+ [0x1D54B] = 0x54, -- T
+ [0x1D54C] = 0x55, -- U
+ [0x1D54D] = 0x56, -- V
+ [0x1D54E] = 0x57, -- W
+ [0x1D54F] = 0x58, -- X
+ [0x1D550] = 0x59, -- Y
+ [0x02124] = 0x5A, -- Z (blackboard Z)
+ [0x02132] = 0x60, -- hatwide \Finv
+ [0x02141] = 0x61, -- hatwider \Game
+ -- [0x0] = 0x62, tildewide
+ -- [0x0] = 0x63, tildewider
+ -- [0x0] = 0x64, Finv
+ -- [0x0] = 0x65, Gmir
+ [0x02127] = 0x66, -- Omegainv \mho
+ [0x000F0] = 0x67, -- eth \eth
+ [0x02242] = 0x68, -- equalorsimilar \eqsim
+ [0x02136] = 0x69, -- beth \beth
+ [0x02137] = 0x6A, -- gimel \gimel
+ [0x02138] = 0x6B, -- daleth \daleth
+ [0x022D6] = 0x6C, -- lessdot \lessdot
+ [0x022D7] = 0x6D, -- greaterdot \gtrdot
+ [0x022C9] = 0x6E, -- multicloseleft \ltimes
+ [0x022CA] = 0x6F, -- multicloseright \rtimes
+ -- [0x0] = 0x70, -- barshort \shortmid
+ -- [0x0] = 0x71, -- parallelshort \shortparallel
+ -- [0x02216] = 0x72, -- integerdivide \smallsetminus (2216 already part of tex-sy
+ -- [0x0] = 0x73, -- similar \thicksim
+ -- [0x0] = 0x74, -- approxequal \thickapprox
+ [0x0224A] = 0x75, -- approxorequal \approxeq
+ [0x02AB8] = 0x76, -- followsorequal \succapprox
+ [0x02AB7] = 0x77, -- precedesorequal \precapprox
+ [0x021B6] = 0x78, -- archleftdown \curvearrowleft
+ [0x021B7] = 0x79, -- archrightdown \curvearrowright
+ [0x003DC] = 0x7A, -- Digamma \digamma
+ [0x003F0] = 0x7B, -- kappa \varkappa
+ [0x1D55C] = 0x7C, -- k \Bbbk (blackboard k)
+ [0x0210F] = 0x7D, -- planckover2pi \hslash
+ [0x00127] = 0x7E, -- planckover2pi1 \hbar
+ [0x003F6] = 0x7F, -- epsiloninv \backepsilon
+}
+
+fonts.enc.math["tex-fraktur"] = {
+-- [0x1D504] = 0x41, -- A (fraktur A)
+-- [0x1D505] = 0x42, -- B
+ [0x0212D] = 0x43, -- C
+-- [0x1D507] = 0x44, -- D
+-- [0x1D508] = 0x45, -- E
+-- [0x1D509] = 0x46, -- F
+-- [0x1D50A] = 0x47, -- G
+ [0x0210C] = 0x48, -- H
+ [0x02111] = 0x49, -- I
+-- [0x1D50D] = 0x4A, -- J
+-- [0x1D50E] = 0x4B, -- K
+-- [0x1D50F] = 0x4C, -- L
+-- [0x1D510] = 0x4D, -- M
+-- [0x1D511] = 0x4E, -- N
+-- [0x1D512] = 0x4F, -- O
+-- [0x1D513] = 0x50, -- P
+-- [0x1D514] = 0x51, -- Q
+ [0x0211C] = 0x52, -- R
+-- [0x1D516] = 0x53, -- S
+-- [0x1D517] = 0x54, -- T
+-- [0x1D518] = 0x55, -- U
+-- [0x1D519] = 0x56, -- V
+-- [0x1D51A] = 0x57, -- W
+-- [0x1D51B] = 0x58, -- X
+-- [0x1D51C] = 0x59, -- Y
+ [0x02128] = 0x5A, -- Z (fraktur Z)
+-- [0x1D51E] = 0x61, -- a (fraktur a)
+-- [0x1D51F] = 0x62, -- b
+-- [0x1D520] = 0x63, -- c
+-- [0x1D521] = 0x64, -- d
+-- [0x1D522] = 0x65, -- e
+-- [0x1D523] = 0x66, -- f
+-- [0x1D524] = 0x67, -- g
+-- [0x1D525] = 0x68, -- h
+-- [0x1D526] = 0x69, -- i
+-- [0x1D527] = 0x6A, -- j
+-- [0x1D528] = 0x6B, -- k
+-- [0x1D529] = 0x6C, -- l
+-- [0x1D52A] = 0x6D, -- m
+-- [0x1D52B] = 0x6E, -- n
+-- [0x1D52C] = 0x6F, -- o
+-- [0x1D52D] = 0x70, -- p
+-- [0x1D52E] = 0x71, -- q
+-- [0x1D52F] = 0x72, -- r
+-- [0x1D530] = 0x73, -- s
+-- [0x1D531] = 0x74, -- t
+-- [0x1D532] = 0x75, -- u
+-- [0x1D533] = 0x76, -- v
+-- [0x1D534] = 0x77, -- w
+-- [0x1D535] = 0x78, -- x
+-- [0x1D536] = 0x79, -- y
+-- [0x1D537] = 0x7A, -- z
+}
+
+-- now that all other vectors are defined ...
+
+fonts.vf.math.set_letters(fonts.enc.math, "tex-mi", 0x1D434, 0x1D44E)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-ss", 0x1D5A0, 0x1D5BA)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-tt", 0x1D670, 0x1D68A)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-bf", 0x1D400, 0x1D41A)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-bi", 0x1D468, 0x1D482)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-fraktur", 0x1D504, 0x1D51E)
+fonts.vf.math.set_letters(fonts.enc.math, "tex-fraktur-bold", 0x1D56C, 0x1D586)
+
+fonts.vf.math.set_digits (fonts.enc.math, "tex-ss", 0x1D7E2)
+fonts.vf.math.set_digits (fonts.enc.math, "tex-tt", 0x1D7F6)
+fonts.vf.math.set_digits (fonts.enc.math, "tex-bf", 0x1D7CE)
+
+-- fonts.vf.math.set_digits (fonts.enc.math, "tex-bi", 0x1D7CE)
+
+-- todo: add ss, tt, bf etc vectors
+-- we can make ss tt etc an option
+
+-- rm-lmr5 : LMMathRoman5-Regular
+-- rm-lmbx5 : LMMathRoman5-Bold ]
+-- lmbsy5 : LMMathSymbols5-BoldItalic
+-- lmsy5 : LMMathSymbols5-Italic
+-- lmmi5 : LMMathItalic5-Italic
+-- lmmib5 : LMMathItalic5-BoldItalic
+
+mathematics.make_font ( "lmroman5-math", {
+ { name = "lmroman5-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr5.tfm", vector = "tex-mr" } ,
+ { name = "lmmi5.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy5.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam5.tfm", vector = "tex-ma" },
+ { name = "msbm5.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx5.tfm", vector = "tex-bf" } ,
+ { name = "lmroman5-bold", "tex-bf" } ,
+ { name = "lmmib5.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans8-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono8-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm5.tfm", vector = "tex-fraktur", optional=true },
+} )
+
+-- rm-lmr6 : LMMathRoman6-Regular
+-- rm-lmbx6 : LMMathRoman6-Bold
+-- lmsy6 : LMMathSymbols6-Italic
+-- lmmi6 : LMMathItalic6-Italic
+
+mathematics.make_font ( "lmroman6-math", {
+ { name = "lmroman6-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr6.tfm", vector = "tex-mr" } ,
+ { name = "lmmi6.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy6.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam5.tfm", vector = "tex-ma" },
+ { name = "msbm5.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx6.tfm", vector = "tex-bf" } ,
+ { name = "lmroman6-bold.otf", "tex-bf" } ,
+ { name = "lmmib5.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans8-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono8-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm6.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb6.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr7 : LMMathRoman7-Regular
+-- rm-lmbx7 : LMMathRoman7-Bold
+-- lmbsy7 : LMMathSymbols7-BoldItalic
+-- lmsy7 : LMMathSymbols7-Italic
+-- lmmi7 : LMMathItalic7-Italic
+-- lmmib7 : LMMathItalic7-BoldItalic
+
+mathematics.make_font ( "lmroman7-math", {
+ { name = "lmroman7-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr7.tfm", vector = "tex-mr" } ,
+ { name = "lmmi7.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy7.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam7.tfm", vector = "tex-ma" },
+ { name = "msbm7.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx7.tfm", vector = "tex-bf" } ,
+ { name = "lmroman7-bold.otf", "tex-bf" } ,
+ { name = "lmmib7.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans8-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono8-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm7.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb7.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr8 : LMMathRoman8-Regular
+-- rm-lmbx8 : LMMathRoman8-Bold
+-- lmsy8 : LMMathSymbols8-Italic
+-- lmmi8 : LMMathItalic8-Italic
+
+mathematics.make_font ( "lmroman8-math", {
+ { name = "lmroman8-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr8.tfm", vector = "tex-mr" } ,
+ { name = "lmmi8.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy8.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam7.tfm", vector = "tex-ma" },
+ { name = "msbm7.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx8.tfm", vector = "tex-bf" } ,
+ { name = "lmroman8-bold.otf", "tex-bf" } ,
+ { name = "lmmib7.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans8-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono8-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm8.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb8.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr9 : LMMathRoman9-Regular
+-- rm-lmbx9 : LMMathRoman9-Bold
+-- lmsy9 : LMMathSymbols9-Italic
+-- lmmi9 : LMMathItalic9-Italic
+
+mathematics.make_font ( "lmroman9-math", {
+ { name = "lmroman9-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr9.tfm", vector = "tex-mr" } ,
+ { name = "lmmi9.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy9.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx9.tfm", vector = "tex-bf" } ,
+ { name = "lmroman9-bold.otf", "tex-bf" } ,
+ { name = "lmmib10.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans9-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono9-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm9.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb9.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr10 : LMMathRoman10-Regular
+-- rm-lmbx10 : LMMathRoman10-Bold
+-- lmbsy10 : LMMathSymbols10-BoldItalic
+-- lmsy10 : LMMathSymbols10-Italic
+-- lmex10 : LMMathExtension10-Regular
+-- lmmi10 : LMMathItalic10-Italic
+-- lmmib10 : LMMathItalic10-BoldItalic
+
+mathematics.make_font ( "lmroman10-math", {
+ { name = "lmroman10-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr10.tfm", vector = "tex-mr" } ,
+ { name = "lmmi10.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx10.tfm", vector = "tex-bf" } ,
+ { name = "lmroman10-bold.otf", "tex-bf" } ,
+ { name = "lmmib10.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans10-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono10-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm10.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb10.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr12 : LMMathRoman12-Regular
+-- rm-lmbx12 : LMMathRoman12-Bold
+-- lmmi12 : LMMathItalic12-Italic
+
+mathematics.make_font ( "lmroman12-math", {
+ { name = "lmroman12-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr12.tfm", vector = "tex-mr" } ,
+ { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx12.tfm", vector = "tex-bf" } ,
+ { name = "lmroman12-bold.otf", "tex-bf" } ,
+ { name = "lmmib10.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans12-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono12-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm10.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb10.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- rm-lmr17 : LMMathRoman17-Regular
+
+mathematics.make_font ( "lmroman17-math", {
+ { name = "lmroman17-regular.otf", features = "virtualmath", main = true },
+ -- { name = "rm-lmr12.tfm", vector = "tex-mr" } ,
+ { name = "lmmi12.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "lmsy10.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "lmex10.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+ -- { name = "rm-lmbx12.tfm", vector = "tex-bf" } ,
+ { name = "lmroman12-bold.otf", "tex-bf" } ,
+ { name = "lmmib10.tfm", vector = "tex-bi", skewchar=0x7F } ,
+ { name = "lmsans17-regular.otf", vector = "tex-ss", optional=true },
+ { name = "lmmono17-regular.otf", vector = "tex-tt", optional=true },
+ { name = "eufm10.tfm", vector = "tex-fraktur", optional=true },
+ { name = "eufb10.tfm", vector = "tex-fraktur-bold", optional=true },
+} )
+
+-- pxr/txr messes up the accents
+
+mathematics.make_font ( "px-math", {
+ { name = "texgyrepagella-regular.otf", features = "virtualmath", main = true },
+ { name = "pxr.tfm", vector = "tex-mr" } ,
+ { name = "pxmi.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "pxsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "pxex.tfm", vector = "tex-ex", extension = true } ,
+ { name = "pxsya.tfm", vector = "tex-ma" },
+ { name = "pxsyb.tfm", vector = "tex-mb" },
+} )
+
+mathematics.make_font ( "tx-math", {
+ { name = "texgyretermes-regular.otf", features = "virtualmath", main = true },
+ { name = "txr.tfm", vector = "tex-mr" } ,
+ { name = "txmi.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "txsy.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "txex.tfm", vector = "tex-ex", extension = true } ,
+ { name = "txsya.tfm", vector = "tex-ma" },
+ { name = "txsyb.tfm", vector = "tex-mb" },
+} )
+
+mathematics.make_font ( "iwona-math", {
+ { name = "file:Iwona-Regular", features = "virtualmath", main = true },
+ { name = "mi-iwonari.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "sy-iwonarz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "ex-iwonar.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+} )
+
+mathematics.make_font ( "iwona-light-math", {
+ { name = "file:IwonaLight-Regular", features = "virtualmath", main = true },
+ { name = "mi-iwonali.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "sy-iwonalz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "ex-iwonal.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+} )
+
+mathematics.make_font ( "iwona-medium-math", {
+ { name = "file:IwonaMedium-Regular", features = "virtualmath", main = true },
+ { name = "mi-iwonami.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "sy-iwonamz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "ex-iwonam.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+} )
+
+mathematics.make_font ( "iwona-heavy-math", {
+ { name = "file:IwonaHeavy-Regular", features = "virtualmath", main = true },
+ { name = "mi-iwonahi.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "sy-iwonahz.tfm", vector = "tex-sy", skewchar=0x30, parameters = true } ,
+ { name = "ex-iwonah.tfm", vector = "tex-ex", extension = true } ,
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+} )
+
+-- not ok, we need adapted vectors !
+
+mathematics.make_font ( "mathtimes-math", {
+ { name = "file:texgyretermes-regular.otf", features = "virtualmath", main = true },
+ { name = "mtmiz.tfm", vector = "tex-mi", skewchar=0x7F },
+ { name = "mtsyn.tfm", vector = "tex-sy", skewchar=0x30, parameters = true },
+ { name = "mtex.tfm", vector = "tex-ex", extension = true },
+ { name = "msam10.tfm", vector = "tex-ma" },
+ { name = "msbm10.tfm", vector = "tex-mb" },
+} )
diff --git a/tex/context/base/meta-ini.mkii b/tex/context/base/meta-ini.mkii
index cb59ed44b..ee7e8a38b 100644
--- a/tex/context/base/meta-ini.mkii
+++ b/tex/context/base/meta-ini.mkii
@@ -20,45 +20,21 @@
\unprotect
-\startmessages dutch library: metapost
- title: metapost
- 1: metapost bibliotheek -- wordt geladen
-\stopmessages
-
-\startmessages english library: metapost
- title: metapost
- 1: loading metapost library --
-\stopmessages
-
-\startmessages german library: metapost
- title: metapost
- 1: Lade metapost Bibliothek --
-\stopmessages
-
-\startmessages czech library: metapost
- title: metapost
- 1: loading metapost library --
-\stopmessages
-
-\startmessages italian library: metapost
- title: metapost
- 1: caricamento della libreria metapost --
-\stopmessages
-
-\startmessages norwegian library: metapost
- title: metapost
- 1: metapost bibliotek -- blir lest inn
-\stopmessages
-
-\startmessages romanian library: metapost
- title: metapost
- 1: se incarca biblioteca metapost --
-\stopmessages
-
-\startmessages french library: metapost
- title: metapost
- 1: chargement de la bibliothèque metapost --
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D This module extends the functionality of the support module
%D \type {supp-mps}, the module that is responsible for
@@ -69,49 +45,48 @@
\maxnofMPgraphics = 4000 % metafun disables the 4K boundary
-\appendtoks \runMPgraphicsfalse \to \everyfastmode
-\appendtoks \insertMPgraphicsfalse \to \everyfastmode
-\appendtoks \flushMPgraphics \to \everygoodbye % \everylastshipout
+\appendtoks \flushMPgraphics \to \everygoodbye % \everylastshipout
\def\@@MPG{@MPG@}
\startMPextensions
- if unknown context_tool: input mp-tool; fi;
- if unknown context_spec: input mp-spec; fi;
- if unknown context_grph: input mp-grph; fi;
+ if unknown context_tool: input mp-tool; fi;
+ if unknown context_spec: input mp-spec; fi;
+ if unknown context_grph: input mp-grph; fi;
\stopMPextensions
%D Since we want lables to follow the document settings, we
%D also set the font related variables.
-\startMPinitializations % scale is not yet ok
- defaultfont:="\truefontname{Regular}";
- defaultscale:=\the\bodyfontsize/10pt;
-\stopMPinitializations
-
-\beginNEWTEX
+\ifnum\texengine=\xetexengine
\startMPinitializations % scale is not yet ok
- defaultfont:="rm-lmtt10";
+ defaultfont:="rm-lmtt10";
+ defaultscale:=\the\bodyfontsize/10pt;
\stopMPinitializations
-\endNEWTEX
+\else
+ \startMPinitializations % scale is not yet ok
+ defaultfont:="\truefontname{Regular}";
+ defaultscale:=\the\bodyfontsize/10pt;
+ \stopMPinitializations
+\fi
%D In order to support fancy text features (like outline
%D fonts), we set:
\startMPextensions
- graphictextformat:="context";
- graphictextdirective "\the\everyMPTEXgraphic";
+ graphictextformat:="context";
+ graphictextdirective "\the\everyMPTEXgraphic";
\stopMPextensions
% \startMPextensions
-% textextdirective "\the\everyMPTEXgraphic";
+% textextdirective "\the\everyMPTEXgraphic";
% \stopMPextensions
%D A signal that we're in combines \CONTEXT||\METAFUN mode:
\startMPextensions
- string contextversion;
- contextversion:="\contextversion";
+ string contextversion;
+ contextversion:="\contextversion";
\stopMPextensions
%D Some safeguards:
diff --git a/tex/context/base/meta-ini.mkiv b/tex/context/base/meta-ini.mkiv
index 8d2f7a724..bcd82c4ed 100644
--- a/tex/context/base/meta-ini.mkiv
+++ b/tex/context/base/meta-ini.mkiv
@@ -15,46 +15,6 @@
\unprotect
-\startmessages dutch library: metapost
- title: metapost
- 1: metapost bibliotheek -- wordt geladen
-\stopmessages
-
-\startmessages english library: metapost
- title: metapost
- 1: loading metapost library --
-\stopmessages
-
-\startmessages german library: metapost
- title: metapost
- 1: Lade metapost Bibliothek --
-\stopmessages
-
-\startmessages czech library: metapost
- title: metapost
- 1: loading metapost library --
-\stopmessages
-
-\startmessages italian library: metapost
- title: metapost
- 1: caricamento della libreria metapost --
-\stopmessages
-
-\startmessages norwegian library: metapost
- title: metapost
- 1: metapost bibliotek -- blir lest inn
-\stopmessages
-
-\startmessages romanian library: metapost
- title: metapost
- 1: se incarca biblioteca metapost --
-\stopmessages
-
-\startmessages french library: metapost
- title: metapost
- 1: chargement de la bibliothèque metapost --
-\stopmessages
-
%D Instead of sharing code with \MKII, I decided to copy
%D the code. Otherwise maintainance becomes a pain and after all,
%D the \MKII\ code will not change.
@@ -77,6 +37,20 @@
\newtoks \everyMPgraphic % mp
\newtoks \everyMPTEXgraphic % tex
+% The next command is, of course, dedicated to Mojca, who
+% needs it for gnuplot. Anyway, the whole multiple engine
+% mechanism is to keep her gnuplot from interfering.
+
+\def\startMPdefinitions
+ {\dosinglegroupempty\dostartMPdefinitions}
+
+\long\def\dostartMPdefinitions#1#2\stopMPdefinitions
+ {\edef\currentMPgraphicinstance{#1}%
+ \ifx\currentMPgraphicinstance\empty
+ \let\currentMPgraphicinstance\defaultMPgraphicinstance
+ \fi
+ \global\MPinstancetoks\expandafter{\the\MPinstancetoks#2}}
+
\long\def\startMPextensions#1\stopMPextensions
{\global\MPextensions\expandafter{\the\MPextensions#1}}
@@ -110,31 +84,163 @@
\def\currentMPformat{metafun}
+% todo:
+%
+% \splitMPgraphicname[a::b] (\currentMPgraphicformat,\currentMPgraphicname)
+% \splitMPgraphicname[a] (\currentMPgraphicformat,\currentMPgraphicname)
+% \splitMPgraphicname[a::b::c] (\currentMPgraphicformat,\currentMPgraphicname)
+%
+% \resetMPformat[extrafun]
+%
+% MPinclusions etc only for metafun, randomseed for all
+%
+% todo: \resetMPformat[instance] -> unload and nil
+% todo: geen page stats
+% todo: textext in plain mp
+
+% test:
+%
+% \let\processMPgraphic\extendedprocessMPgraphic \setupcolors[state=start]
+%
+% \startMPdefinitions{metafun}
+% color MyColor ; MyColor = red ;
+% \stopMPdefinitions
+% \startuseMPgraphic{test1}
+% fill fullcircle scaled 1cm withcolor MyColor ;
+% \stopuseMPgraphic
+% \startuseMPgraphic{test2}
+% color MyColor ; MyColor = green ;
+% fill fullcircle scaled 1cm withcolor MyColor ;
+% \stopuseMPgraphic
+% \startuseMPgraphic{test3}
+% fill fullcircle scaled 1cm withcolor MyColor ;
+% \stopuseMPgraphic
+% \startuseMPgraphic{test4}
+% color MyColor ; MyColor = blue ;
+% \stopuseMPgraphic
+%
+% \useMPgraphic{metafun::test1}
+% \useMPgraphic{metafun::test2}
+% \useMPgraphic{metafun::test3}
+% \useMPgraphic{extrafun::test4}
+% \useMPgraphic{extrafun::test3}
+% \useMPgraphic{metafun::test3}
+% \useMPgraphic{nofun::test4}
+% \useMPgraphic{nofun::test3}
+%
+% \startMPcode
+% fill fullsquare scaled 1cm ;
+% \stopMPcode
+% \startMPcode{metafun}
+% fill fullsquare scaled 1cm withcolor MyColor ;
+% \stopMPcode
+
+\def\@@MPF{@MPF@}
+
+\def\MPinstancetoks{\csname\@@MPF::\currentMPgraphicinstance\endcsname}
+
+\def\defineMPinstance
+ {\dodoubleargument\dodefineMPinstance}
+
+\def\dodefineMPinstance[#1][#2]%
+ {\ifcsname\@@MPF::#1\endcsname\else\expandafter\newtoks\csname\@@MPF::#1\endcsname\fi
+ \MPinstancetoks\emptytoks % in case we redefine
+ \getparameters[\@@MPF#1][\s!format=mpost,\s!extensions=\v!no,\s!initializations=\v!no,#2]}
+
+\def\resetMPinstance[#1]%
+ {\writestatus\m!metapost{reset will be implemented when needed}}
+
+\def\defaultMPgraphicinstance{metafun}
+
+\def\splitMPgraphicname[#1]%
+ {\dosplitMPgraphicname[#1::::]}
+
+\def\dosplitMPgraphicname[#1::#2::#3]% instance ::
+ {\edef\currentMPgraphicname{#2}%
+ \ifx\currentMPgraphicname\empty
+ \edef\currentMPgraphicname{#1}%
+ \let\currentMPgraphicinstance\defaultMPgraphicinstance
+ \else
+ \edef\currentMPgraphicinstance{#1}%
+ \fi
+ \edef\currentMPgraphicformat{\csname\@@MPF\currentMPgraphicinstance\s!format\endcsname}}
+
+\def\currentMPgraphicinstance{\defaultMPgraphicinstance}
+\def\currentMPgraphicformat {\currentMPgraphicinstance}
+
+\defineMPinstance[metafun] [\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[extrafun][\s!format=metafun,\s!extensions=\v!yes,\s!initializations=\v!yes]
+\defineMPinstance[metapost][\s!format=mpost]
+\defineMPinstance[nofun] [\s!format=mpost]
+
+\def\beginMPgraphicgroup#1%
+ {\begingroup
+ \splitMPgraphicname[#1]}
+
+\def\endMPgraphicgroup
+ {\endgroup}
+
+%
+
\newconditional \METAFUNinitialized
+% maybe we need to force black, i.e. fake nodes
+
\long\def\processMPgraphic#1% todo: extensions and inclusions outside beginfig
- {\blabelgroup
+ {\begingroup
\enableincludeMPgraphics
\the\everyMPgraphic
\presetMPdefinitions
\setMPrandomseed % this has to change
% we need to preexpand the token lists
\setbox\MPgraphicbox\hbox\bgroup
- \ifconditional\METAFUNinitialized
- \ctxlua { metapost.graphic(
- "\currentMPformat", \@EA\!!bs\the\MPinitializations;#1;\!!es,
- ""
- ) }%
- \else
- \ctxlua { metapost.graphic(
- "\currentMPformat", \@EA\!!bs\the\MPinitializations;\theMPrandomseed;#1;\!!es, % code
- \@EA\@EA\@EA\!!bs\@EA\the\@EA\MPextensions\@EA;\the\MPuserinclusions;\!!es % optional preamble
- ) }%
- \global\settrue\METAFUNinitialized
- \fi
+ \ctxlua{metapost.graphic("\currentMPformat", "\currentMPformat",
+ \@EA\!!bs\the\MPinitializations;\theMPrandomseed;#1;\!!es, % code
+ \@EA\@EA\@EA\!!bs\@EA\the\@EA\MPextensions\@EA;\the\MPuserinclusions;\!!es % optional preamble
+ )}%
+ \global\settrue\METAFUNinitialized
+ \global\MPextensions\emptytoks
+ \global\MPuserinclusions\emptytoks
\egroup
\placeMPgraphic
- \elabelgroup}
+ \endgroup}
+
+% ! ! ! ! begin temporary ! ! ! !
+
+\let\normalprocessMPgraphic\processMPgraphic
+
+\long\def\processMPgraphic#1% todo: extensions and inclusions outside beginfig
+ {\begingroup % needed?
+ \enableincludeMPgraphics
+ \the\everyMPgraphic
+ \presetMPdefinitions
+ \setMPrandomseed % this has to change
+ % we need to preexpand the token lists
+ \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!yes
+ {\settrue\includeMPextensions\letgvalue{\@@MPF\currentMPgraphicinstance\s!extensions}\v!no}
+ {\setfalse\includeMPextensions}%
+ \doifelsevalue{\@@MPF\currentMPgraphicinstance\s!initializations}\v!yes
+ {\settrue\includeMPinitializations\letgvalue{\@@MPF\currentMPgraphicinstance\s!initializations}\v!no}
+ {\setfalse\includeMPinitializations}%
+ \setbox\MPgraphicbox\hbox\bgroup
+ \normalexpanded{\noexpand\ctxlua{metapost.graphic("\currentMPgraphicinstance", "\currentMPgraphicformat",
+ \!!bs\ifconditional\includeMPinitializations\the\MPinitializations;\fi\theMPrandomseed;#1;\!!es,
+ \!!bs\ifconditional\includeMPextensions\the\MPextensions;\the\MPuserinclusions;\fi\the\MPinstancetoks;\!!es
+ )}}%
+ \egroup
+ \global\MPinstancetoks\emptytoks
+ \global\settrue\METAFUNinitialized % becomes obsolete
+ %\global\MPextensions\emptytoks % multipls instances
+ %\global\MPuserinclusions\emptytoks % multipls instances
+ \placeMPgraphic
+ \endgroup}
+
+\let\extendedprocessMPgraphic\processMPgraphic
+
+\let\processMPgraphic\normalprocessMPgraphic
+% \let\processMPgraphic\extendedprocessMPgraphic
+
+% ! ! ! ! end temporary ! ! ! !
\newif\ifsetMPrandomseed \setMPrandomseedtrue % false by default
@@ -150,10 +256,7 @@
\def\@@MPG{@MPG@}
\def\doifMPgraphicelse#1%
- {\blabelgroup
- \doifdefinedelse{\@@MPG#1}%
- {\elabelgroup\firstoftwoarguments}
- {\elabelgroup\secondoftwoarguments}}
+ {\ifcsname\@@MPG#1\endcsname\expandafter\firstoftwoarguments\else\expandafter\secondoftwoarguments\fi}
\def\includeMPgraphic#1%
{\executeifdefined{\@@MPG#1};} % ; if not found
@@ -165,7 +268,6 @@
\let\MPdrawingdata\empty
\newif\ifMPdrawingdone \MPdrawingdonefalse
-\newif\ifMPshiftdrawing \MPshiftdrawingfalse
\def\resetMPdrawing
{\globallet\MPdrawingdata\empty
@@ -178,9 +280,25 @@
\def\popMPdrawing
{\globalpopmacro\MPdrawingdata}
-\def\getMPdrawing
+\def\getMPdrawing{\dosinglegroupempty\dogetMPdrawing}
+
+\def\nodogetMPdrawing#1%
+ {\ifMPdrawingdone
+ \expandafter\processMPgraphic\expandafter{\MPdrawingdata}%
+ \fi}
+
+\def\dostartMPcode
+ {\iffirstargument
+ \expandafter\dodogetMPdrawing
+ \else
+ \expandafter\nodogetMPdrawing
+ \fi}
+
+\def\dodogetMPdrawing#1%
{\ifMPdrawingdone
+ \beginMPgraphicgroup{#1::\s!dummy}% name does not matter
\expandafter\processMPgraphic\expandafter{\MPdrawingdata}%
+ \endMPgraphicgroup
\fi}
\def\startMPdrawing
@@ -199,7 +317,6 @@
\let\MPdrawingdata\empty
-\newif\ifMPdrawingdone \MPdrawingdonefalse
\newif\ifMPshiftdrawing \MPshiftdrawingfalse
\def\resetMPdrawing
@@ -233,24 +350,24 @@
\let\stopMPdrawing\relax
\long\def\startMPclip#1#2\stopMPclip
- {\blabelgroup
- \long\setgvalue{MPC:#1}{\ctxlua{metapost.getclippath(\!!bs#2\!!es)}}%
- \elabelgroup}
+ {\long\setgvalue{MPC:#1}{\ctxlua{metapost.getclippath(\!!bs#2\!!es)}}}
\let\stopMPclip\relax
\def\grabMPclippath#1#2#3#4#5% #5 is alternative
- {\blabelgroup
+ {\begingroup
\edef\width {#3\space}\let\overlaywidth \width
\edef\height{#4\space}\let\overlayheight\height
- \doifdefinedelse{MPC:#1}
- {\xdef\MPclippath{\getvalue{MPC:#1}}%
- \ifx\MPclippath\empty\xdef\MPclippath{#5}\fi
- \setxvalue{MPC:#1}{\MPclippath}}
- {\xdef\MPclippath{#5}}%
+ \ifcsname MPC:#1\endcsname
+ \xdef\MPclippath{\getvalue{MPC:#1}}%
+ \ifx\MPclippath\empty\xdef\MPclippath{#5}\fi
+ \setxvalue{MPC:#1}{\MPclippath}%
+ \else
+ \xdef\MPclippath{#5}%
+ \fi
% #2 : method is obsolete, only pdf now, we can always
% gsub the result to ps
- \elabelgroup}
+ \endgroup}
%D Next we will use these support macros.
@@ -268,6 +385,8 @@
defaultscale:=\the\bodyfontsize/10pt;
\stopMPinitializations
+% watch out, this is a type1 font because mp can only handle 8 bit fonts
+
\startMPinitializations % scale is not yet ok
defaultfont:="rm-lmtt10";
\stopMPinitializations
@@ -386,18 +505,36 @@
%D \stoptyping
\newcount\MPobjectcounter
-\newif \ifMPshiftdrawing \MPshiftdrawingfalse
\newbox \MPgraphicbox
+%newif \ifMPshiftdrawing \MPshiftdrawingfalse
+
+\chardef\MPboxmode\zerocount
+
+\def\doobeyMPboxdepth % mode = 1
+ {\setbox\MPgraphicbox\hbox{\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}}
+
+\def\doignoreMPboxdepth % mode = 2
+ {\normalexpanded
+ {\noexpand\doobeyMPboxdepth
+ \wd\MPgraphicbox\the\wd\MPgraphicbox
+ \ht\MPgraphicbox\the\ht\MPgraphicbox
+ \dp\MPgraphicbox\the\dp\MPgraphicbox}}
+
+\def\obeyMPboxdepth {\chardef\MPboxmode\plusone}
+\def\ignoreMPboxdepth{\chardef\MPboxmode\plustwo}
+\def\normalMPboxdepth{\chardef\MPboxmode\zerocount}
+
+% compatibility hack:
+
+\let\MPshiftdrawingtrue \ignoreMPboxdepth
+\let\MPshiftdrawingfalse\normalMPboxdepth
\def\placeMPgraphic
- {\ifMPshiftdrawing
- \edef\next
- {\wd\MPgraphicbox\the\wd\MPgraphicbox
- \ht\MPgraphicbox\the\ht\MPgraphicbox
- \dp\MPgraphicbox\the\dp\MPgraphicbox}%
- \setbox\MPgraphicbox\hbox
- {\hskip\MPllx\onebasepoint\raise\MPlly\onebasepoint\box\MPgraphicbox}%
- \next
+ {\ifcase\MPboxmode
+ \or % 1
+ \doobeyMPboxdepth
+ \or % 2
+ \doignoreMPboxdepth
\fi
\box\MPgraphicbox}
@@ -409,10 +546,10 @@
\getobject{MP}{#1}}
\long\def\handleuniqueMPgraphic#1#2#3%
- {\blabelgroup
+ {\begingroup
\def\@@meta{#1:}%
\extendMPoverlaystamp{#2}% incl prepare
- \ifundefined{\@@MPG\overlaystamp:#1}%
+ \ifcsname\@@MPG\overlaystamp:#1\endcsname\else
\enableincludeMPgraphics
\forgetall
\global\advance\MPobjectcounter\plusone
@@ -420,57 +557,51 @@
\setxvalue{\@@MPG\overlaystamp:#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}%
\fi
\getvalue{\@@MPG\overlaystamp:#1}%
- \elabelgroup}
+ \endgroup}
\long\def\startuniqueMPgraphic
- {\blabelgroup
- \dodoublegroupempty\dostartuniqueMPgraphic}
+ {\dodoublegroupempty\dostartuniqueMPgraphic}
\long\def\dostartuniqueMPgraphic#1#2#3\stopuniqueMPgraphic%
- {\long\setgvalue{\@@MPG#1}{\handleuniqueMPgraphic{#1}{#2}{#3}}%
- \elabelgroup}
+ {\long\setgvalue{\@@MPG#1}{\handleuniqueMPgraphic{#1}{#2}{#3}}}
\unexpanded\def\uniqueMPgraphic
{\dodoublegroupempty\douniqueMPgraphic}
\def\douniqueMPgraphic#1#2%
- {\blabelgroup
- \setupMPvariables[#1][#2]%
- \getvalue{\@@MPG#1}\empty
- \elabelgroup}
+ {\beginMPgraphicgroup{#1}%
+ \setupMPvariables[\currentMPgraphicname][#2]%
+ \getvalue{\@@MPG\currentMPgraphicname}\empty
+ \endMPgraphicgroup}
\let\stopuniqueMPcode \relax % so that we can use it in \expanded
\long\def\handleuseMPgraphic#1#2#3%
- {\blabelgroup
+ {\begingroup
\forgetall % check this
\def\@@meta{#1:}%
\prepareMPvariables{#2}%
\enableincludeMPgraphics
\processMPgraphic{#3}%
- \elabelgroup}
+ \endgroup}
\long\def\startuseMPgraphic
- {\blabelgroup
- \dodoublegroupempty\dostartuseMPgraphic}
+ {\dodoublegroupempty\dostartuseMPgraphic}
\long\def\dostartuseMPgraphic#1#2#3\stopuseMPgraphic
- {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}%
- \elabelgroup}
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}}
\long\def\startusableMPgraphic % redundant but handy
- {\blabelgroup
- \dodoublegroupempty\dostartusableMPgraphic}
+ {\dodoublegroupempty\dostartusableMPgraphic}
\long\def\dostartusableMPgraphic#1#2#3\stopusableMPgraphic
- {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}%
- \elabelgroup}
+ {\long\setgvalue{\@@MPG#1}{\handleuseMPgraphic{#1}{#2}{#3}}}
\let\stopuseMPgraphic \relax % so that we can use it in \expanded
\let\stopusableMPgraphic \relax % so that we can use it in \expanded
\long\def\handlereusableMPgraphic#1#2#3%
- {\blabelgroup
+ {\begingroup
\def\@@meta{#1:}%
\prepareMPvariables{#2}%
\enableincludeMPgraphics
@@ -478,15 +609,13 @@
\setobject{MP}{\number\MPobjectcounter}\hbox{\processMPgraphic{#3}}% was vbox, graphic must end up as hbox
\setxvalue{\@@MPG#1}{\noexpand\reuseMPbox{\number\MPobjectcounter}{\MPllx}{\MPlly}{\MPurx}{\MPury}}%
\getvalue{\@@MPG#1}%
- \elabelgroup}
+ \endgroup}
\long\def\startreusableMPgraphic
- {\blabelgroup
- \dodoublegroupempty\dostartreusableMPgraphic}
+ {\dodoublegroupempty\dostartreusableMPgraphic}
\long\def\dostartreusableMPgraphic#1#2#3\stopreusableMPgraphic
- {\long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}{#3}}%
- \elabelgroup}
+ {\long\setgvalue{\@@MPG#1}{\handlereusableMPgraphic{#1}{#2}{#3}}}
\let\stopreusableMPgraphic \relax % so that we can use it in \expanded
@@ -494,10 +623,10 @@
{\dodoublegroupempty\douseMPgraphic}
\def\douseMPgraphic#1#2%
- {\blabelgroup
- \doifsomething{#2}{\setupMPvariables[#1][#2]}%
- \getvalue{\@@MPG#1}\empty
- \elabelgroup}
+ {\beginMPgraphicgroup{#1}%
+ \doifsomething{#2}{\setupMPvariables[\currentMPgraphicname][#2]}%
+ \getvalue{\@@MPG\currentMPgraphicname}\empty
+ \endMPgraphicgroup}
\let\reuseMPgraphic \useMPgraphic % we can save a setup here if needed
\let\reusableMPgraphic\reuseMPgraphic % we can save a setup here if needed
@@ -522,23 +651,21 @@
{\MPpageprefix\overlaywidth:\overlayheight:\overlaydepth:\MPcolor\overlaycolor:\MPcolor\overlaylinecolor}
\long\def\startuniqueMPpagegraphic
- {\blabelgroup
- \dodoublegroupempty\dostartuniqueMPpagegraphic}
+ {\dodoublegroupempty\dostartuniqueMPpagegraphic}
\long\def\dostartuniqueMPpagegraphic#1#2#3\stopuniqueMPpagegraphic
{\long\setgvalue{\@@MPG o:#1}{\handleuniqueMPgraphic{o:#1}{#2}{#3}}%
- \long\setgvalue{\@@MPG e:#1}{\handleuniqueMPgraphic{e:#1}{#2}{#3}}%
- \elabelgroup}
+ \long\setgvalue{\@@MPG e:#1}{\handleuniqueMPgraphic{e:#1}{#2}{#3}}}
\unexpanded\def\uniqueMPpagegraphic
{\dodoublegroupempty\douniqueMPpagegraphic}
\def\douniqueMPpagegraphic#1#2%
- {\blabelgroup
+ {\beginMPgraphicgroup{#1}%
\let\overlaystamp\overlaypagestamp
- \setupMPvariables[\MPpageprefix#1][#2]% prefix is new here
- \getvalue{\@@MPG\MPpageprefix#1}{}%
- \elabelgroup}
+ \setupMPvariables[\MPpageprefix\currentMPgraphicname][#2]% prefix is new here
+ \getvalue{\@@MPG\MPpageprefix\currentMPgraphicname}{}%
+ \endMPgraphicgroup}
%D One way of defining a stamp is:
%D
@@ -553,10 +680,10 @@
%D we introduce a dedicated expansion engine.
\def\prepareMPvariable#1%
- {\ifundefined{\@@framed\@@meta#1}%
- \doprepareMPvariable{\@@meta#1}%
- \else
+ {\ifcsname\@@framed\@@meta#1\endcsname
\doprepareMPvariable{\@@framed\@@meta#1}%
+ \else
+ \doprepareMPvariable{\@@meta#1}%
\fi}
% \startlines
@@ -637,15 +764,35 @@
%D For the moment, the next one is a private macro:
-% TODO ! ! ! ! ! !
-
\def\processMPbuffer
{\dosingleempty\doprocessMPbuffer}
+% this fails (keep):
+%
+% \def\doprocessMPbuffer[#1]%
+% {\doifelsenothing{#1}
+% {\doprocessMPbuffer[\jobname]}
+% {\processMPgraphic{\ctxlua{tex.sprint(tex.ctxcatcodes,buffers.collect("#1"))}}}} % "\\n"
+%
+% this works (keep):
+%
+% \def\doprocessMPbuffer[#1]%
+% {\doifelsenothing{#1}
+% {\doprocessMPbuffer[\jobname]} % #1 can be a list of buffers, otherwise we could use:
+% {\processMPgraphic{\ctxlua{tex.sprint(tex.ctxcatcodes,unpack(buffers.data["#1"]))}}}}
+%
+% this we use:
+
+\newtoks\mpbuffertoks
+
\def\doprocessMPbuffer[#1]%
{\doifelsenothing{#1}
{\doprocessMPbuffer[\jobname]}
- {\processMPgraphic{\ctxlua{tex.sprint(tex.ctxcatcodes,buffers.collect(string.split("#1",",")))}}}}
+ {\beginMPgraphicgroup{#1}%
+ % we need this trick because tex.sprint does not interprets newlines
+ \ctxlua{tex.toks.mpbuffertoks=buffers.collect("\currentMPgraphicname")}%
+ \processMPgraphic{\the\mpbuffertoks}%
+ \endMPgraphicgroup}}
\def\runMPbuffer
{\dosingleempty\dorunMPbuffer}
@@ -718,8 +865,22 @@
%D
%D The most simple case:
-\long\def\startMPcode#1\stopMPcode
- {\processMPgraphic{#1}}
+\def\startMPcode{\dosinglegroupempty\dostartMPcode}
+
+\def\dostartMPcode
+ {\iffirstargument
+ \expandafter\dodostartMPcode
+ \else
+ \expandafter\nodostartMPcode
+ \fi}
+
+\def\dodostartMPcode#1#2\stopMPcode
+ {\beginMPgraphicgroup{#1::\s!dummy}% name does not matter
+ \processMPgraphic{#2}%
+ \endMPgraphicgroup}
+
+\def\nodostartMPcode#1#2\stopMPcode
+ {\processMPgraphic{#2}}
\let\stopMPcode\relax
@@ -749,7 +910,7 @@
%D accomplished by:
\def\douseMPlibrary#1%
- {\ifundefined{\c!file\f!metapostprefix#1}%
+ {\ifcsname\c!file\f!metapostprefix#1\endcsname\else
\letvalueempty{\c!file\f!metapostprefix#1}%
\makeshortfilename[\truefilename{\f!metapostprefix#1}]%
\startreadingfile
@@ -839,7 +1000,7 @@
\to \everyMPgraphic
\appendtoks
- \expanded{\definecolor[currentcolor][\currentcolorname]}%
+ \normalexpanded{\noexpand\definecolor[currentcolor][\currentcolorname]}%
\to \everyMPgraphic
\appendtoks
@@ -1003,9 +1164,9 @@
\long\def\dostartMPcolor[#1][#2]#3\stopMPcolor % slow but sometimes handy
{\startnointerference
- \def\handleMPgraycolor{\expanded{\defineglobalcolor[#1][s=\!MPgMPa1,#2]}}%
- \def\handleMPrgbcolor {\expanded{\defineglobalcolor[#1][r=\!MPgMPa1,g=\!MPgMPa2,b=\!MPgMPa3,#2]}}%
- \def\handleMPcmykcolor{\expanded{\defineglobalcolor[#1][c=\!MPgMPa1,m=\!MPgMPa2,y=\!MPgMPa3,k=\!MPgMPa4,#2]}}%
+ \def\handleMPgraycolor{\normalexpanded{\noexpand\defineglobalcolor[#1][s=\!MPgMPa1,#2]}}%
+ \def\handleMPrgbcolor {\normalexpanded{\noexpand\defineglobalcolor[#1][r=\!MPgMPa1,g=\!MPgMPa2,b=\!MPgMPa3,#2]}}%
+ \def\handleMPcmykcolor{\normalexpanded{\noexpand\defineglobalcolor[#1][c=\!MPgMPa1,m=\!MPgMPa2,y=\!MPgMPa3,k=\!MPgMPa4,#2]}}%
\processMPgraphic{#3}%
\stopnointerference}
@@ -1095,12 +1256,10 @@
{\startreusableMPgraphic{\@@MPG#1@S@}#2\stopreusableMPgraphic}
\long\def\startstaticMPgraphic
- {\blabelgroup
- \dodoublegroupempty\dostartstaticMPgraphic}
+ {\dodoublegroupempty\dostartstaticMPgraphic}
\long\def\dostartstaticMPgraphic#1#2#3\stopstaticMPgraphic
- {\long\setgvalue{\@@MPG#1@S@}{\handlereusableMPgraphic{#1}{#2}{#3}}%
- \elabelgroup}
+ {\long\setgvalue{\@@MPG#1@S@}{\handlereusableMPgraphic{#1}{#2}{#3}}}
%D New:
diff --git a/tex/context/base/meta-pdf.lua b/tex/context/base/meta-pdf.lua
index 39f24aa5b..240778bfa 100644
--- a/tex/context/base/meta-pdf.lua
+++ b/tex/context/base/meta-pdf.lua
@@ -1,228 +1,94 @@
--- filename : meta-pdf.lua
--- comment : companion to meta-pdf.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
-
--- This is the third version. Version 1 converted to Lua code,
--- version 2 gsubbed the file into TeX code, and version 3 uses
--- the new lpeg functionality and streams the result into TeX.
-
--- We will move old stuff to edu.
-
---~ old lpeg 0.4 lpeg 0.5
---~ 100 times test graphic 2.45 (T:1.07) 0.72 (T:0.24) 0.580 (0.560 no table) -- 0.54 optimized for one space (T:0.19)
---~ 100 times big graphic 10.44 4.30/3.35 nogb 2.914 (2.050 no table) -- 1.99 optimized for one space (T:0.85)
---~ 500 times test graphic T:1.29 T:1.16 (T:1.10 no table) -- T:1.10
-
-if not versions then versions = { } end versions['meta-pdf'] = 1.003
-
-mptopdf = { }
-mptopdf.parsers = { }
-mptopdf.parser = 'none'
-
-function mptopdf.reset()
- mptopdf.data = ""
- mptopdf.path = { }
- mptopdf.stack = { }
- mptopdf.texts = { }
- mptopdf.version = 0
- mptopdf.shortcuts = false
- mptopdf.resetpath()
-end
-
-function mptopdf.resetpath()
- mptopdf.stack.close = false
- mptopdf.stack.path = { }
- mptopdf.stack.concat = nil
- mptopdf.stack.special = false
-end
+if not modules then modules = { } end modules ['meta-pdf'] = {
+ version = 1.001,
+ comment = "companion to meta-pdf.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-mptopdf.reset()
+-- Finally we used an optimized version. The test code can be found in
+-- meta-pdh.lua but since we no longer want to overload functione we
+-- use more locals now.
-function mptopdf.parsers.none()
- -- no parser set
-end
+local concat, format, gsub, find = table.concat, string.format, string.gsub, string.find
+local byte = string.byte
+local texsprint = tex.sprint
-function mptopdf.parse()
- mptopdf.parsers[mptopdf.parser]()
-end
+local ctxcatcodes = tex.ctxcatcodes
--- old code
+mptopdf = { }
+mptopdf.n = 0
-mptopdf.steps = { }
+local m_path, m_stack, m_texts, m_version, m_date, m_shortcuts = { }, { }, { }, 0, 0, false
-mptopdf.descapes = {
- ['('] = "\\\\char40 ",
- [')'] = "\\\\char41 ",
- ['"'] = "\\\\char92 "
-}
+local m_stack_close, m_stack_path, m_stack_concat = false, { }, nil
-function mptopdf.descape(str)
- str = str:gsub("\\(%d%d%d)",function(n)
- return "\\char" .. tonumber(n,8) .. " "
- end)
- return str:gsub("\\([%(%)\\])",mptopdf.descapes)
+local function resetpath()
+ m_stack_close = false
+ m_stack_path = { }
+ m_stack_concat = nil
end
-function mptopdf.steps.descape(str)
- str = str:gsub("\\(%d%d%d)",function(n)
- return "\\\\char" .. tonumber(n,8) .. " "
- end)
- return str:gsub("\\([%(%)\\])",mptopdf.descapes)
+local function resetall()
+ m_path, m_stack, m_texts, m_version, m_shortcuts = { }, { }, { }, 0, false
+ resetpath()
end
-function mptopdf.steps.strip() -- .3 per expr
- mptopdf.data = mptopdf.data:gsub("^(.-)%%+Page:.-%c+(.*)%s+%a+%s+%%+EOF.*$", function(preamble, graphic)
- local bbox = "0 0 0 0"
- for b in preamble:gmatch("%%%%%a+oundingBox: +(.-)%c+") do
- bbox = b
- end
- local name, version = preamble:gmatch("%%%%Creator: +(.-) +(.-) ")
- mptopdf.version = tostring(version or "0")
- if preamble:find("/hlw{0 dtransform") then
- mptopdf.shortcuts = true
- end
- -- the boundingbox specification needs to come before data, well, not really
- return bbox .. " boundingbox\n" .. "\nbegindata\n" .. graphic .. "\nenddata\n"
- end, 1)
- mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecials: +(.-)%c+", "%1 specials\n", 1)
- mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecial: +(.-)%c+", "%1 special\n")
- mptopdf.data = mptopdf.data:gsub("%%.-%c+", "")
-end
-
-function mptopdf.steps.cleanup()
- if not mptopdf.shortcuts then
- mptopdf.data = mptopdf.data:gsub("gsave%s+fill%s+grestore%s+stroke", "both")
- mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+exch%s+truncate%s+exch%s+idtransform%s+pop%s+setlinewidth", function(wx,wy)
- if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
- end)
- mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+truncate%s+idtransform%s+setlinewidth%s+pop", function(wx,wy)
- if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
- end)
- end
-end
+resetall()
-function mptopdf.steps.convert()
- mptopdf.data = mptopdf.data:gsub("%c%((.-)%) (.-) (.-) fshow", function(str,font,scale)
- mptopdf.texts[mptopdf.texts+1] = {mptopdf.steps.descape(str), font, scale}
- return "\n" .. #mptopdf.texts .. " textext"
- end)
- mptopdf.data = mptopdf.data:gsub("%[%s*(.-)%s*%]", function(str)
- return str:gsub("%s+"," ")
- end)
- local t
- mptopdf.data = mptopdf.data:gsub("%s*([^%a]-)%s*(%a+)", function(args,cmd)
- if cmd == "textext" then
- t = mptopdf.texts[tonumber(args)]
- return "mps.textext(" .. "\"" .. t[2] .. "\"," .. t[3] .. ",\"" .. t[1] .. "\")\n"
- else
- return "mps." .. cmd .. "(" .. args:gsub(" +",",") .. ")\n"
- end
- end)
-end
+-- code injection, todo: collect and flush packed using node injection
-function mptopdf.steps.process()
- assert(loadstring(mptopdf.data))() -- () runs the loaded chunk
+local function pdfcode(str) -- not used
+ texsprint(ctxcatcodes,"\\MPScode{",str,"}")
end
-
-function mptopdf.parsers.gsub()
- mptopdf.steps.strip()
- mptopdf.steps.cleanup()
- mptopdf.steps.convert()
- mptopdf.steps.process()
-end
-
--- end of old code
-
--- from lua to tex
-
-function mptopdf.pdfcode(str)
- tex.sprint(tex.ctxcatcodes,"\\PDFcode{" .. str .. "}")
-end
-
-function mptopdf.texcode(str)
- tex.sprint(tex.ctxcatcodes,str)
+local function texcode(str)
+ texsprint(ctxcatcodes,str)
end
-- auxiliary functions
-function mptopdf.flushconcat()
- if mptopdf.stack.concat then
- mptopdf.pdfcode(table.concat(mptopdf.stack.concat," ") .. " cm")
- mptopdf.stack.concat = nil
+local function flushconcat()
+ if m_stack_concat then
+ texsprint(ctxcatcodes,"\\MPScode{",concat(m_stack_concat," ")," cm}")
+ m_stack_concat = nil
end
end
-function mptopdf.flushpath(cmd)
- if #mptopdf.stack.path > 0 then
+local function flushpath(cmd)
+ -- faster: no local function
+ if #m_stack_path > 0 then
local path = { }
- if mptopdf.stack.concat then
- local sx, sy = mptopdf.stack.concat[1], mptopdf.stack.concat[4]
- local rx, ry = mptopdf.stack.concat[2], mptopdf.stack.concat[3]
- local tx, ty = mptopdf.stack.concat[5], mptopdf.stack.concat[6]
+ if m_stack_concat then
+ local sx, sy = m_stack_concat[1], m_stack_concat[4]
+ local rx, ry = m_stack_concat[2], m_stack_concat[3]
+ local tx, ty = m_stack_concat[5], m_stack_concat[6]
local d = (sx*sy) - (rx*ry)
- local function concat(px, py)
- return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d
- end
- for _,v in ipairs(mptopdf.stack.path) do
- v[1],v[2] = concat(v[1],v[2])
+ -- local function mpconcat(px, py) -- move this inline
+ -- return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d
+ -- end
+ for k=1,#m_stack_path do
+ local v = m_stack_path[k]
+ local px, py = v[1], v[2] ; v[1], v[2] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[1],v[2])
if #v == 7 then
- v[3],v[4] = concat(v[3],v[4])
- v[5],v[6] = concat(v[5],v[6])
+ local px, py = v[3], v[4] ; v[3], v[4] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[3],v[4])
+ local px, py = v[5], v[6] ; v[5], v[6] = (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d -- mpconcat(v[5],v[6])
end
- path[#path+1] = table.concat(v," ")
+ path[#path+1] = concat(v," ")
end
else
- for _,v in ipairs(mptopdf.stack.path) do
- path[#path+1] = table.concat(v," ")
+ for k=1,#m_stack_path do
+ path[#path+1] = concat(m_stack_path[k]," ")
end
end
- mptopdf.flushconcat()
- mptopdf.texcode("\\MPSpath{" .. table.concat(path," ") .. "}")
- if mptopdf.stack.close then
- mptopdf.texcode("\\MPScode{h " .. cmd .. "}")
+ flushconcat()
+ texcode("\\MPSpath{" .. concat(path," ") .. "}")
+ if m_stack_close then
+ texcode("\\MPScode{h " .. cmd .. "}")
else
- mptopdf.texcode("\\MPScode{" .. cmd .."}")
+ texcode("\\MPScode{" .. cmd .."}")
end
end
- mptopdf.resetpath()
-end
-
-if input and input.instance then
- function mptopdf.loaded(name)
- local ok, n
- mptopdf.reset()
- ok, mptopdf.data, n = input.loadbinfile(name, 'tex') -- we need a binary load !
- return ok
- end
-else
- function mptopdf.loaded(name)
- local f = io.open(name, 'rb')
- if f then
- mptopdf.reset()
- mptopdf.data = f:read('*all')
- f:close()
- return true
- else
- return false
- end
- end
-end
-
-if not mptopdf.parse then
- function mptopdf.parse() end -- forward declaration
-end
-
-function mptopdf.convertmpstopdf(name)
- if mptopdf.loaded(name) then
- input.starttiming(mptopdf)
- mptopdf.parse()
- mptopdf.reset()
- input.stoptiming(mptopdf)
- else
- tex.print("file " .. name .. " not found")
- end
+ resetpath()
end
-- mp interface
@@ -230,171 +96,133 @@ end
mps = mps or { }
function mps.creator(a, b, c)
- mptopdf.version = tonumber(b)
+ m_version = tonumber(b)
end
function mps.creationdate(a)
- mptopdf.date= a
+ m_date = a
end
function mps.newpath()
- mptopdf.stack.path = { }
+ m_stack_path = { }
end
function mps.boundingbox(llx, lly, urx, ury)
- mptopdf.texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
+ texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
end
function mps.moveto(x,y)
- mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"m"}
+ m_stack_path[#m_stack_path+1] = {x,y,"m"}
end
function mps.curveto(ax, ay, bx, by, cx, cy)
- mptopdf.stack.path[#mptopdf.stack.path+1] = {ax,ay,bx,by,cx,cy,"c"}
+ m_stack_path[#m_stack_path+1] = {ax,ay,bx,by,cx,cy,"c"}
end
function mps.lineto(x,y)
- mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"l"}
+ m_stack_path[#m_stack_path+1] = {x,y,"l"}
end
function mps.rlineto(x,y)
local dx, dy = 0, 0
- if #mptopdf.stack.path > 0 then
- dx, dy = mptopdf.stack.path[#mptopdf.stack.path][1], mptopdf.stack.path[#mptopdf.stack.path][2]
+ if #m_stack_path > 0 then
+ dx, dy = m_stack_path[#m_stack_path][1], m_stack_path[#m_stack_path][2]
end
- mptopdf.stack.path[#mptopdf.stack.path+1] = {dx,dy,"l"}
+ m_stack_path[#m_stack_path+1] = {dx,dy,"l"}
end
function mps.translate(tx,ty)
- mptopdf.pdfcode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm")
+ texsprint(ctxcatcodes,"\\MPScode{1 0 0 0 1 ",tx," ",ty," cm}")
end
function mps.scale(sx,sy)
- mptopdf.stack.concat = {sx,0,0,sy,0,0}
+ m_stack_concat = {sx,0,0,sy,0,0}
end
function mps.concat(sx, rx, ry, sy, tx, ty)
- mptopdf.stack.concat = {sx,rx,ry,sy,tx,ty}
+ m_stack_concat = {sx,rx,ry,sy,tx,ty}
end
function mps.setlinejoin(d)
- mptopdf.pdfcode(d .. " j")
+ texsprint(ctxcatcodes,"\\MPScode{",d," j}")
end
function mps.setlinecap(d)
- mptopdf.pdfcode(d .. " J")
+ texsprint(ctxcatcodes,"\\MPScode{",d," J}")
end
function mps.setmiterlimit(d)
- mptopdf.pdfcode(d .. " M")
+ texsprint(ctxcatcodes,"\\MPScode{",d," M}")
end
function mps.gsave()
- mptopdf.pdfcode("q")
+ texsprint(ctxcatcodes,"\\MPScode{q}")
end
function mps.grestore()
- mptopdf.pdfcode("Q")
+ texsprint(ctxcatcodes,"\\MPScode{Q}")
end
-function mps.setdash(...)
+function mps.setdash(...) -- can be made faster, operate on t = { ... }
local n = select("#",...)
- mptopdf.pdfcode("[" .. table.concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d")
+ texsprint(ctxcatcodes,"\\MPScode{","[",concat({...}," ",1,n-1),"] ",select(n,...)," d}")
end
function mps.resetdash()
- mptopdf.pdfcode("[ ] 0 d")
+ texsprint(ctxcatcodes,"\\MPScode{[ ] 0 d}")
end
function mps.setlinewidth(d)
- mptopdf.pdfcode(d .. " w")
+ texsprint(ctxcatcodes,"\\MPScode{",d," w}")
end
function mps.closepath()
- mptopdf.stack.close = true
+ m_stack_close = true
end
function mps.fill()
- mptopdf.flushpath('f')
+ flushpath('f')
end
function mps.stroke()
- mptopdf.flushpath('S')
+ flushpath('S')
end
function mps.both()
- mptopdf.flushpath('B')
+ flushpath('B')
end
function mps.clip()
- mptopdf.flushpath('W n')
+ flushpath('W n')
end
function mps.textext(font, scale, str) -- old parser
local dx, dy = 0, 0
- if #mptopdf.stack.path > 0 then
- dx, dy = mptopdf.stack.path[1][1], mptopdf.stack.path[1][2]
+ if #m_stack_path > 0 then
+ dx, dy = m_stack_path[1][1], m_stack_path[1][2]
end
- mptopdf.flushconcat()
- mptopdf.texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
- mptopdf.resetpath()
+ flushconcat()
+ texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+ resetpath()
end
---~ function mps.handletext(font,scale.str,dx,dy)
---~ local one, two = string.match(str, "^(%d+)::::(%d+)")
---~ if one and two then
---~ mptopdf.texcode("\\MPTOPDFtextext{"..font.."}{"..scale.."}{"..one.."}{"..two.."}{"..dx.."}{"..dy.."}")
---~ else
---~ mptopdf.texcode("\\MPTOPDFtexcode{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
---~ end
---~ end
-
-if false and ctx and ctx.aux and ctx.aux.definecolor then
-
- logs.report("mptopdf", "using attribute based mps colors")
-
- -- does not work due to Q-q mess-up
-
- function mps.setrgbcolor(r,g,b) -- extra check
- r, g, b = tonumber(r), tonumber(g), tonumber(b) -- needed when we use lpeg
- if r == 0.0123 and g < 0.1 then -- g is extra check
- mptopdf.texcode("\\doresetattribute{transparency}\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
- elseif r == 0.123 and g < 0.1 then -- g is extra check
- mptopdf.texcode("\\doresetattribute{transparency}\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
- else
- mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'rgb',r,g,b) .. "}")
- end
- end
-
- function mps.setcmykcolor(c,m,y,k)
- mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'cmyk',tonumber(c),tonumber(m),tonumber(y),tonumber(k)) .. "}")
- end
-
- function mps.setgray(s)
- mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'gray',tonumber(s)) .. "}")
- end
-
-else
-
- function mps.setrgbcolor(r,g,b) -- extra check
- r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
- if r == 0.0123 and g < 0.1 then
- mptopdf.texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
- elseif r == 0.123 and g < 0.1 then
- mptopdf.texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
- else
- mptopdf.texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}")
- end
- end
-
- function mps.setcmykcolor(c,m,y,k)
- mptopdf.texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}")
+function mps.setrgbcolor(r,g,b) -- extra check
+ r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
+ if r == 0.0123 and g < 0.1 then
+ texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
+ elseif r == 0.123 and g < 0.1 then
+ texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
+ else
+ texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}")
end
+end
- function mps.setgray(s)
- mptopdf.texcode("\\MPSgray{" .. s .. "}")
- end
+function mps.setcmykcolor(c,m,y,k)
+ texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}")
+end
+function mps.setgray(s)
+ texcode("\\MPSgray{" .. s .. "}")
end
function mps.specials(version,signal,factor) -- 2.0 123 1000
@@ -402,7 +230,7 @@ end
function mps.special(...) -- 7 1 0.5 1 0 0 1 3
local n = select("#",...)
- mptopdf.texcode("\\MPSbegin\\MPSset{" .. table.concat({...},"}\\MPSset{",2,n) .. "}\\MPSend")
+ texcode("\\MPSbegin\\MPSset{" .. concat({...},"}\\MPSset{",2,n) .. "}\\MPSend")
end
function mps.begindata()
@@ -414,43 +242,8 @@ end
function mps.showpage()
end
-mps.n = mps.newpath -- n
-mps.p = mps.closepath -- h
-mps.l = mps.lineto -- l
-mps.r = mps.rlineto -- r
-mps.m = mps.moveto -- m
-mps.c = mps.curveto -- c
-mps.hlw = mps.setlinewidth
-mps.vlw = mps.setlinewidth
-
-mps.C = mps.setcmykcolor -- k
-mps.G = mps.setgray -- g
-mps.R = mps.setrgbcolor -- rg
-
-mps.lj = mps.setlinejoin -- j
-mps.ml = mps.setmiterlimit -- M
-mps.lc = mps.setlinecap -- J
-mps.sd = mps.setdash -- d
-mps.rd = mps.resetdash
-
-mps.S = mps.stroke -- S
-mps.F = mps.fill -- f
-mps.B = mps.both -- B
-mps.W = mps.clip -- W
-
-mps.q = mps.gsave -- q
-mps.Q = mps.grestore -- Q
-
-mps.s = mps.scale -- (not in pdf)
-mps.t = mps.concat -- (not the same as pdf anyway)
-
-mps.P = mps.showpage
-
--- experimental
-
function mps.attribute(id,value)
- mptopdf.texcode("\\attribute " .. id .. "=" .. value .. " ")
--- mptopdf.texcode("\\dompattribute{" .. id .. "}{" .. value .. "}")
+ texcode("\\attribute " .. id .. "=" .. value .. " ")
end
-- lpeg parser
@@ -459,160 +252,178 @@ end
-- that MetaPost produces. It's my first real lpeg code, which may
-- show. Because the parser binds to functions, we define it last.
-do -- assumes \let\c\char
+local lpegP, lpegR, lpegS, lpegC, lpegCc, lpegCs = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs
+
+local digit = lpegR("09")
+local eol = lpegS('\r\n')^1
+local sp = lpegP(' ')^1
+local space = lpegS(' \r\n')^1
+local number = lpegS('0123456789.-+')^1
+local nonspace = lpegP(1-lpegS(' \r\n'))^1
+
+local spec = digit^2 * lpegP("::::") * digit^2
+local text = lpegCc("{") * (
+ lpegP("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
+ lpegP(" ") / function(n) return "\\c32" end + -- never in new mp
+ lpegP(1) / function(n) return "\\c" .. byte(n) end
+ ) * lpegCc("}")
+local package = lpegCs(spec + text^0)
+
+function mps.fshow(str,font,scale) -- lpeg parser
+ mps.textext(font,scale,package:match(str))
+end
+
+local cnumber = lpegC(number)
+local cstring = lpegC(nonspace)
+
+local specials = (lpegP("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
+local special = (lpegP("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
+local boundingbox = (lpegP("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+local highresboundingbox = (lpegP("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+
+local setup = lpegP("%%BeginSetup") * (1 - lpegP("%%EndSetup") )^1
+local prolog = lpegP("%%BeginProlog") * (1 - lpegP("%%EndProlog"))^1
+local comment = lpegP('%')^1 * (1 - eol)^1
+
+local curveto = ((cnumber * sp)^6 * lpegP("curveto") ) / mps.curveto
+local lineto = ((cnumber * sp)^2 * lpegP("lineto") ) / mps.lineto
+local rlineto = ((cnumber * sp)^2 * lpegP("rlineto") ) / mps.rlineto
+local moveto = ((cnumber * sp)^2 * lpegP("moveto") ) / mps.moveto
+local setrgbcolor = ((cnumber * sp)^3 * lpegP("setrgbcolor") ) / mps.setrgbcolor
+local setcmykcolor = ((cnumber * sp)^4 * lpegP("setcmykcolor") ) / mps.setcmykcolor
+local setgray = ((cnumber * sp)^1 * lpegP("setgray") ) / mps.setgray
+local newpath = ( lpegP("newpath") ) / mps.newpath
+local closepath = ( lpegP("closepath") ) / mps.closepath
+local fill = ( lpegP("fill") ) / mps.fill
+local stroke = ( lpegP("stroke") ) / mps.stroke
+local clip = ( lpegP("clip") ) / mps.clip
+local both = ( lpegP("gsave fill grestore")) / mps.both
+local showpage = ( lpegP("showpage") )
+local setlinejoin = ((cnumber * sp)^1 * lpegP("setlinejoin") ) / mps.setlinejoin
+local setlinecap = ((cnumber * sp)^1 * lpegP("setlinecap") ) / mps.setlinecap
+local setmiterlimit = ((cnumber * sp)^1 * lpegP("setmiterlimit") ) / mps.setmiterlimit
+local gsave = ( lpegP("gsave") ) / mps.gsave
+local grestore = ( lpegP("grestore") ) / mps.grestore
+
+local setdash = (lpegP("[") * (cnumber * sp^0)^0 * lpegP("]") * sp * cnumber * sp * lpegP("setdash")) / mps.setdash
+local concat = (lpegP("[") * (cnumber * sp^0)^6 * lpegP("]") * sp * lpegP("concat") ) / mps.concat
+local scale = ( (cnumber * sp^0)^6 * sp * lpegP("concat") ) / mps.concat
+
+local fshow = (lpegP("(") * lpegC((1-lpegP(")"))^1) * lpegP(")") * space * cstring * space * cnumber * space * lpegP("fshow")) / mps.fshow
+local fshow = (lpegP("(") * lpegCs( ( lpegP("\\(")/"\\050" + lpegP("\\)")/"\\051" + (1-lpegP(")")) )^1 )
+ * lpegP(")") * space * cstring * space * cnumber * space * lpegP("fshow")) / mps.fshow
+
+local setlinewidth_x = (lpegP("0") * sp * cnumber * sp * lpegP("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
+local setlinewidth_y = (cnumber * sp * lpegP("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
+
+local c = ((cnumber * sp)^6 * lpegP("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too
+local l = ((cnumber * sp)^2 * lpegP("l") ) / mps.lineto
+local r = ((cnumber * sp)^2 * lpegP("r") ) / mps.rlineto
+local m = ((cnumber * sp)^2 * lpegP("m") ) / mps.moveto
+local vlw = ((cnumber * sp)^1 * lpegP("vlw")) / mps.setlinewidth
+local hlw = ((cnumber * sp)^1 * lpegP("hlw")) / mps.setlinewidth
+
+local R = ((cnumber * sp)^3 * lpegP("R") ) / mps.setrgbcolor
+local C = ((cnumber * sp)^4 * lpegP("C") ) / mps.setcmykcolor
+local G = ((cnumber * sp)^1 * lpegP("G") ) / mps.setgray
+
+local lj = ((cnumber * sp)^1 * lpegP("lj") ) / mps.setlinejoin
+local ml = ((cnumber * sp)^1 * lpegP("ml") ) / mps.setmiterlimit
+local lc = ((cnumber * sp)^1 * lpegP("lc") ) / mps.setlinecap
+
+local n = lpegP("n") / mps.newpath
+local p = lpegP("p") / mps.closepath
+local S = lpegP("S") / mps.stroke
+local F = lpegP("F") / mps.fill
+local B = lpegP("B") / mps.both
+local W = lpegP("W") / mps.clip
+local P = lpegP("P") / mps.showpage
+
+local q = lpegP("q") / mps.gsave
+local Q = lpegP("Q") / mps.grestore
+
+local sd = (lpegP("[") * (cnumber * sp^0)^0 * lpegP("]") * sp * cnumber * sp * lpegP("sd")) / mps.setdash
+local rd = ( lpegP("rd")) / mps.resetdash
+
+local s = ( (cnumber * sp^0)^2 * lpegP("s") ) / mps.scale
+local t = (lpegP("[") * (cnumber * sp^0)^6 * lpegP("]") * sp * lpegP("t") ) / mps.concat
- local byte = string.byte
- local digit = lpeg.R("09")
- local spec = digit^2 * lpeg.P("::::") * digit^2
- local text = lpeg.Cc("{") * (
- lpeg.P("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
- lpeg.P(" ") / function(n) return "\\c32" end + -- never in new mp
- lpeg.P(1) / function(n) return "\\c" .. byte(n) end
- ) * lpeg.Cc("}")
- local package = lpeg.Cs(spec + text^0)
+-- experimental
- function mps.fshow(str,font,scale) -- lpeg parser
- mps.textext(font,scale,package:match(str))
+local attribute = ((cnumber * sp)^2 * lpegP("attribute")) / mps.attribute
+local A = ((cnumber * sp)^2 * lpegP("A")) / mps.attribute
+
+local preamble = (
+ prolog + setup +
+ boundingbox + highresboundingbox + specials + special +
+ comment
+)
+
+local procset = (
+ lj + ml + lc +
+ c + l + m + n + p + r +
+ A +
+ R + C + G +
+ S + F + B + W +
+ vlw + hlw +
+ Q + q +
+ sd + rd +
+ t + s +
+ fshow +
+ P
+)
+
+local verbose = (
+ curveto + lineto + moveto + newpath + closepath + rlineto +
+ setrgbcolor + setcmykcolor + setgray +
+ attribute +
+ setlinejoin + setmiterlimit + setlinecap +
+ stroke + fill + clip + both +
+ setlinewidth_x + setlinewidth_y +
+ gsave + grestore +
+ concat + scale +
+ fshow +
+ setdash + -- no resetdash
+ showpage
+)
+
+-- order matters in terms of speed / we could check for procset first
+
+local captures_old = ( space + verbose + preamble )^0
+local captures_new = ( space + procset + preamble + verbose )^0
+
+local function parse(m_data)
+ if find(m_data,"%%%%BeginResource: procset mpost") then
+ captures_new:match(m_data)
+ else
+ captures_old:match(m_data)
end
-
end
-do
-
- local eol = lpeg.S('\r\n')^1
- local sp = lpeg.P(' ')^1
- local space = lpeg.S(' \r\n')^1
- local number = lpeg.S('0123456789.-+')^1
- local nonspace = lpeg.P(1-lpeg.S(' \r\n'))^1
-
- local cnumber = lpeg.C(number)
- local cstring = lpeg.C(nonspace)
-
- local specials = (lpeg.P("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
- local special = (lpeg.P("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
- local boundingbox = (lpeg.P("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
- local highresboundingbox = (lpeg.P("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
-
- local setup = lpeg.P("%%BeginSetup") * (1 - lpeg.P("%%EndSetup") )^1
- local prolog = lpeg.P("%%BeginProlog") * (1 - lpeg.P("%%EndProlog"))^1
- local comment = lpeg.P('%')^1 * (1 - eol)^1
-
- local curveto = ((cnumber * sp)^6 * lpeg.P("curveto") ) / mps.curveto
- local lineto = ((cnumber * sp)^2 * lpeg.P("lineto") ) / mps.lineto
- local rlineto = ((cnumber * sp)^2 * lpeg.P("rlineto") ) / mps.rlineto
- local moveto = ((cnumber * sp)^2 * lpeg.P("moveto") ) / mps.moveto
- local setrgbcolor = ((cnumber * sp)^3 * lpeg.P("setrgbcolor") ) / mps.setrgbcolor
- local setcmykcolor = ((cnumber * sp)^4 * lpeg.P("setcmykcolor") ) / mps.setcmykcolor
- local setgray = ((cnumber * sp)^1 * lpeg.P("setgray") ) / mps.setgray
- local newpath = ( lpeg.P("newpath") ) / mps.newpath
- local closepath = ( lpeg.P("closepath") ) / mps.closepath
- local fill = ( lpeg.P("fill") ) / mps.fill
- local stroke = ( lpeg.P("stroke") ) / mps.stroke
- local clip = ( lpeg.P("clip") ) / mps.clip
- local both = ( lpeg.P("gsave fill grestore")) / mps.both
- local showpage = ( lpeg.P("showpage") )
- local setlinejoin = ((cnumber * sp)^1 * lpeg.P("setlinejoin") ) / mps.setlinejoin
- local setlinecap = ((cnumber * sp)^1 * lpeg.P("setlinecap") ) / mps.setlinecap
- local setmiterlimit = ((cnumber * sp)^1 * lpeg.P("setmiterlimit") ) / mps.setmiterlimit
- local gsave = ( lpeg.P("gsave") ) / mps.gsave
- local grestore = ( lpeg.P("grestore") ) / mps.grestore
-
- local setdash = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("setdash")) / mps.setdash
- local concat = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("concat") ) / mps.concat
- local scale = ( (cnumber * sp^0)^6 * sp * lpeg.P("concat") ) / mps.concat
-
- local fshow = (lpeg.P("(") * lpeg.C((1-lpeg.P(")"))^1) * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
- local fshow = (lpeg.P("(") *
- lpeg.Cs( ( lpeg.P("\\(")/"\\050" + lpeg.P("\\)")/"\\051" + (1-lpeg.P(")")) )^1 )
- * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
-
- local setlinewidth_x = (lpeg.P("0") * sp * cnumber * sp * lpeg.P("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
- local setlinewidth_y = (cnumber * sp * lpeg.P("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
-
- local c = ((cnumber * sp)^6 * lpeg.P("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too
- local l = ((cnumber * sp)^2 * lpeg.P("l") ) / mps.lineto
- local r = ((cnumber * sp)^2 * lpeg.P("r") ) / mps.rlineto
- local m = ((cnumber * sp)^2 * lpeg.P("m") ) / mps.moveto
- local vlw = ((cnumber * sp)^1 * lpeg.P("vlw")) / mps.setlinewidth
- local hlw = ((cnumber * sp)^1 * lpeg.P("hlw")) / mps.setlinewidth
-
- local R = ((cnumber * sp)^3 * lpeg.P("R") ) / mps.setrgbcolor
- local C = ((cnumber * sp)^4 * lpeg.P("C") ) / mps.setcmykcolor
- local G = ((cnumber * sp)^1 * lpeg.P("G") ) / mps.setgray
-
- local lj = ((cnumber * sp)^1 * lpeg.P("lj") ) / mps.setlinejoin
- local ml = ((cnumber * sp)^1 * lpeg.P("ml") ) / mps.setmiterlimit
- local lc = ((cnumber * sp)^1 * lpeg.P("lc") ) / mps.setlinecap
-
- local n = lpeg.P("n") / mps.newpath
- local p = lpeg.P("p") / mps.closepath
- local S = lpeg.P("S") / mps.stroke
- local F = lpeg.P("F") / mps.fill
- local B = lpeg.P("B") / mps.both
- local W = lpeg.P("W") / mps.clip
- local P = lpeg.P("P") / mps.showpage
-
- local q = lpeg.P("q") / mps.gsave
- local Q = lpeg.P("Q") / mps.grestore
-
- local sd = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("sd")) / mps.setdash
- local rd = ( lpeg.P("rd")) / mps.resetdash
-
- local s = ( (cnumber * sp^0)^2 * lpeg.P("s") ) / mps.scale
- local t = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("t") ) / mps.concat
-
- -- experimental
-
- local attribute = ((cnumber * sp)^2 * lpeg.P("attribute")) / mps.attribute
- local A = ((cnumber * sp)^2 * lpeg.P("A")) / mps.attribute
-
- local preamble = (
- prolog + setup +
- boundingbox + highresboundingbox + specials + special +
- comment
- )
-
- local procset = (
- lj + ml + lc +
- c + l + m + n + p + r +
- A +
- R + C + G +
- S + F + B + W +
- vlw + hlw +
- Q + q +
- sd + rd +
- t + s +
- fshow +
- P
- )
-
- local verbose = (
- curveto + lineto + moveto + newpath + closepath + rlineto +
- setrgbcolor + setcmykcolor + setgray +
- attribute +
- setlinejoin + setmiterlimit + setlinecap +
- stroke + fill + clip + both +
- setlinewidth_x + setlinewidth_y +
- gsave + grestore +
- concat + scale +
- fshow +
- setdash + -- no resetdash
- showpage
- )
-
- -- order matters in terms of speed / we could check for procset first
-
- local captures_old = ( space + verbose + preamble )^0
- local captures_new = ( space + procset + preamble + verbose )^0
-
- function mptopdf.parsers.lpeg()
- if mptopdf.data:find("%%%%BeginResource: procset mpost") then
- captures_new:match(mptopdf.data)
- else
- captures_old:match(mptopdf.data)
- end
- end
+-- main converter
+function mptopdf.convertmpstopdf(name)
+ resetall()
+ local ok, m_data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load !
+ if ok then
+ statistics.starttiming(mptopdf)
+ mptopdf.n = mptopdf.n + 1
+ parse(m_data)
+ resetall()
+ statistics.stoptiming(mptopdf)
+ else
+ tex.print("file " .. name .. " not found")
+ end
end
-mptopdf.parser = 'lpeg'
+
+-- status info
+
+statistics.register("mps conversion time",function()
+ local n = mptopdf.n
+ if n > 0 then
+ return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/meta-pdf.mkii b/tex/context/base/meta-pdf.mkii
index d1a803604..2099b0d37 100644
--- a/tex/context/base/meta-pdf.mkii
+++ b/tex/context/base/meta-pdf.mkii
@@ -1,8 +1,8 @@
%D \module
%D [ file=meta-pdf,
%D version=2006.06.07,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=\METAPOST\ to \PDF\ conversion,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Conversion to \PDF,
%D author=Hans Hagen \& others (see text),
%D date=\currentdate,
%D copyright=\PRAGMA]
@@ -11,12 +11,171 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D Formerly known as supp-pdf.tex and supp-mpe.tex.
+
+%D We will clean up the color mess later.
+
+%D These macros are written as generic as possible. Some
+%D general support macro's are loaded from a small module
+%D especially made for non \CONTEXT\ use. In this module I
+%D use a matrix transformation macro written by Tanmoy
+%D Bhattacharya. Thanks to extensive testing by Sebastian
+%D Ratz I was able to complete this module within reasonable
+%D time. This module has support for \METAPOST\ extensions
+%D built in.
+%D
+%D Daniel H. Luecking came up with a better (more precise)
+%D transformation method. You can recognize his comment by
+%D his initials. (We keep the old code around because it's a
+%D nice illustration on how a module like this evolves.)
+
+% Beware, we cannot use 0pt here by defaukt since it may be
+% defined in the range \dimen 0 - 20 which we happen to use
+% as scratch registers; for this reason we start allocating
+% scratch registers > 20
+
+%D This module handles some \PDF\ conversion and insertions
+%D topics. By default, the macros use the \PDFTEX\ primitive
+%D \type{\pdfliteral} when available. Since \PDFTEX\ is now the
+%D default engine for \TEX\ distributions, we need a more complex
+%D test.
+
+\writestatus{loading}{MetaPost Graphics / MPS to PDF}
+
\unprotect
-%D These are the main macros.
+\ifx\PDFcode \undefined \let\PDFcode \gobbleoneargument \fi
+\ifx\PDFcomment\undefined \def\PDFcomment#1{\PDFcode{\letterpercent\space#1}} \fi
+
+%D First we define a handy constant:
+
+\bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup
+
+%D \macros
+%D {pdfimage,pdfimages,pdfclippedimage}
+%D
+%D Starting with pdftex version 14, images are included more
+%D natural to the form embedding. This enables alternative
+%D images to be embedded.
+%D
+%D \starttyping
+%D \pdfimage <optional dimensions> {file}
+%D \pdfimages <optional dimensions> {high res file} {low res file}
+%D \stoptyping
+%D
+%D The first one replaces the pre||version||14 original,
+%D while the latter provides alternative images.
+%D
+%D The next macro is dedicated to Maarten Gelderman, who
+%D needed to paste prepared \PDF\ pages into conference
+%D proceedings.
+%D
+%D \starttyping
+%D \pdfclippedimage <optional dimensions> {file} {l} {r} {t} {b}
+%D \stoptyping
+
+\ifx\pdftexversion\undefined \else \ifnum\pdftexversion>13 % still relevant?
+
+ \def\pdfimage#1#%
+ {\dopdfimage{#1}}
+
+ \def\dopdfimage#1#2%
+ {\immediate\pdfximage#1{#2}%
+ \pdfrefximage\pdflastximage}
+
+ \def\pdfimages#1#%
+ {\dopdfimages{#1}}
+
+ \def\dopdfimages#1#2#3%
+ {\immediate\pdfximage#1{#2}%
+ \immediate\pdfobj{[ << /Image \the\pdflastximage\space0 R /DefaultForPrinting true >> ]}%
+ \immediate\pdfximage#1 attr {/Alternates \the\pdflastobj\space0 R}{#3}%
+ \pdfrefximage\pdflastximage}
+
+ \def\pdfclippedimage#1#% specs {file}{left}{right}{top}{bottom}
+ {\dopdfclippedimage{#1}}
+
+ \def\dopdfclippedimage#1#2#3#4#5#6%
+ {\bgroup
+ \pdfximage#1{#2}%
+ \setbox\scratchbox\hbox{\pdfrefximage\pdflastximage}%
+ \hsize\dimexpr\wd\scratchbox-#3-#4\relax
+ \vsize\dimexpr\ht\scratchbox-#5-#6\relax
+ \setbox\scratchbox\vbox to \vsize
+ {\vskip-#5\hbox to \hsize{\hskip-#3\box\scratchbox\hss}}%
+ \pdfxform\scratchbox
+ \pdfrefxform\pdflastxform
+ \egroup}
-\def\mkconvertMPtoPDF % #1#2#3%
- {\vbox\bgroup
+\fi \fi
+
+%D \macros
+%D {convertMPtoPDF}
+%D
+%D The next set of macros implements \METAPOST\ to \PDF\
+%D conversion. The traditional method is in the MkII file.
+
+%D The main conversion command is:
+%D
+%D \starttyping
+%D \convertMPtoPDF {filename} {x scale} {y scale}
+%D \stoptyping
+%D
+%D The dimensions are derived from the bounding box. So we
+%D only have to say:
+%D
+%D \starttyping
+%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
+%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
+%D \stoptyping
+
+%D \macros
+%D {makeMPintoPDFobject,lastPDFMPobject}
+%D
+%D For experts there are a few more options. When attributes
+%D are to be added, the code must be embedded in an object
+%D accompanied with the appropriate directives. One can
+%D influence this process with \type {\makeMPintoPDFobject}.
+%D
+%D This option defaults to~0, because \CONTEXT\ takes care
+%D of objects at another level, which saves some bytes.
+%D
+%D \starttabulate[|l|l|p|]
+%D \NC 0 \NC never \NC don't use an object \NC\NR
+%D \NC 1 \NC always \NC always use an object \NC\NR
+%D \NC 2 \NC optional \NC use object when needed \NC\NR
+%D \stoptabulate
+%D
+%D The last object number used is avaliable in the macro
+%D \type {\lastPDFMPobject}.
+
+\ifx\makeMPintoPDFobject \undefined \chardef\makeMPintoPDFobject \zerocount \fi
+\ifx\blackoutMPgraphic \undefined \chardef\blackoutMPgraphic \plusone \fi
+\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion \fi
+
+\let\lastPDFMPobject \!!zerocount
+\let\currentPDFresources\empty
+\let\setMPextensions \relax
+
+\def\PDFMPformoffset
+ {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}
+
+\def\resetMPvariables#1#2#3%
+ {\global\let\MPwidth \!!zeropoint
+ \global\let\MPheight\!!zeropoint
+ \global\let\MPllx \!!zerocount
+ \global\let\MPlly \!!zerocount
+ \global\let\MPurx \!!zerocount
+ \global\let\MPury \!!zerocount
+ \xdef\MPxscale {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
+ \xdef\MPyscale {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
+ \xdef\MPfilename {#1}}
+
+%D The main macro:
+
+\def\convertMPtoPDF#1#2#3%
+ {\resetMPvariables{#1}{#2}{#3}%
+ \vbox\bgroup
\forgetall
\offinterlineskip
\ifx\pdfdecimaldigits\undefined\else \pdfdecimaldigits=5 \fi % new
@@ -31,6 +190,12 @@
\ifcase\blackoutMPgraphic\or\PDFcode{0 g 0 G}\fi
\doprocessMPtoPDFfile}
+\def\processMPtoPDFfile#1#2#3% obsolete
+ {\resetMPvariables{#1}{#2}{#3}%
+ \bgroup
+ \let\finishMPgraphic\egroup
+ \doprocessMPtoPDFfile}
+
\def\doprocessMPtoPDFfile
{\setMPspecials
\setMPextensions
@@ -64,16 +229,764 @@
\egroup
\endinput}
-\def\mkprocessMPtoPDFfile % file xscale yscale / obsolete
+%D A common hook.
+
+\let\MPfshowcommand\empty
+
+%D Objects.
+
+\def\dopackageMPgraphic#1% #1 = boxregister
+ {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
+ % an existing value of 2 signals object support (set elsewhere)
+ \chardef\makeMPintoPDFobject\plusone
+ \fi\fi
+ \ifcase\makeMPintoPDFobject
+ \box#1%
+ \or
+ \scratchdimen\PDFMPformoffset\relax
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \setbox#1\vbox spread 2\scratchdimen
+ {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
+ \fi
+ \setMPPDFobject{\currentPDFresources}{#1}%
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \vbox to \MPheight
+ {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
+ \else
+ \getMPPDFobject
+ \fi
+ \global\let\currentPDFresources\empty
+ \else
+ \box#1%
+ \fi}
+
+\def\setMPPDFobject#1#2% resources boxnumber
+ {\ifx\pdfxform\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifx\pdftexversion\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifnum\pdftexversion<14
+ \def\getMPPDFobject{\box#2}%
+ \else
+ \ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi
+ \immediate\pdfxform resources{#1}#2%
+ \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}%
+ \fi\fi\fi}
+
+\let\getMPPDFobject\relax
+
+%D \macros
+%D {deleteMPgraphic,
+%D startMPresources,
+%D stopMPresources}
+
+\ifx\deleteMPgraphic\undefined
+ \def\deleteMPgraphic#1{}
+\fi
+
+\ifx\startMPresources\undefined
+ \let\startMPresources\relax
+ \let\stopMPresources\relax
+\fi
+
+%D We implement extensions by using the \METAPOST\ special
+%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
+%D are flushed before or after the graphic data, but thereby
+%D are no longer connected to a position.
+%D
+%D We implement specials by overloading the \type {fill}
+%D operator. By counting the fills, we can let the converter
+%D treat the appropriate fill in a special way. The
+%D specification of the speciality can have two forms,
+%D determined by the setting of a boolean variable:
+%D
+%D \starttyping
+%D _inline_specials_ := false ; % comment like code (default)
+%D _inline_specials_ := true ; % command like code
+%D \stoptyping
+%D
+%D When the specification is embedded as comment, it looks
+%D like:
+%D
+%D \starttyping
+%D %%MetaPostSpecial <size> <data> <number> <identifier>
+%D \stoptyping
+%D
+%D The in||line alternative is more tuned for \POSTSCRIPT,
+%D since it permits us to define a macro \type {special}.
+%D
+%D \starttyping
+%D inline : <data> <number> <identifier> <size> special
+%D \stoptyping
+%D
+%D The \type {identifier} determines what to do, and the data
+%D can be used to accomplish this. A type~2 shading function
+%D has identifier~2. Alltogether, the number of parameters is
+%D specified in \type {size}. The \type {number} is the number
+%D of the fill that needs the special treatment. For a type~2
+%D and~3 shaded fill, the datablock contains the following
+
+%D data:
+%D
+%D \starttyping
+%D from to n inner_r g b x y outer_r g b x y
+%D from to n inner_r g b x y radius outer_r g b x y radius
+%D \stoptyping
+
+\newconditional\manyMPspecials \settrue\manyMPspecials
+
+%D In case of \PDF, we need to prepare resourcs.
+
+\newtoks\MPstartresources
+\newtoks\MPstopresources
+
+\def\startMPresources
+ {\the\MPstartresources}
+
+\def\stopMPresources
+ {\the\MPstopresources}
+
+%D Some day we may consider collecting local resources.
+
+\appendtoks
+ \global\let\currentPDFresources\empty % kind of redundant
+\to \MPstartresources
+
+% \appendtoks
+% \collectPDFresources
+% \global\let\currentPDFresources\collectedPDFresources
+% \to \MPstopresources
+
+\appendtoksonce
+ \the\everyPDFxform
+\to \MPstopresources
+
+%D Since colors are not subjected to transformations, we can
+%D only use colors as signal. In our case, we use a dummy colored
+%D path with a red color component of \type {0.n}, so \type
+%D {0.001} is the first path and \type {0.010} the tenth. Since
+%D \METAPOST strips trailing zeros, we have to padd the string.
+
+\newif\ifMPcmykcolors
+\newif\ifMPspotcolors
+
+\def\dohandleMPrgb #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmyk#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgray #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspot#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Specials:
+
+\settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty
+
+\def\@@MP {@@MP}
+\def\@@MPSK{@MPSK@}
+
+\def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}
+
+\def\defineMPspecial#1#2%
+ {\setvalue{\@@MPSK\@@MPSK#1}{#2}}
+
+%D Special number~1 is dedicated to \CMYK\ support. If you
+%D want to know why: look at this:
+%D
+%D \startbuffer[mp]
+%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
+%D \stopbuffer
+%D
+%D \startbuffer[cmyk]
+%D \startcombination[4*1]
+%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
+%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
+%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
+%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure
+%D {\CMYK\ support disabled,
+%D conversion to \RGB.}
+%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no support in \METAPOST.}
+%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no conversion to \RGB,
+%D support in \METAPOST}
+%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
+
+\defineMPspecial{1}
+ {\ifMPcmykcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPcmykcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+ \fi}
+
+\defineMPspecial{2}
+ {\ifMPspotcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPspotcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+% \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}%
+ \fi}
+
+% \def\checkMPspot#1#2#3#4%
+% {\expanded{\resolveMPspotcolor#1 #2 #3 #4}\end
+% \ifx\MPspotspace\MPresolvedspace
+% \edef\MPspotspacespec{/\MPspotspace\space}%
+% \doifinstringelse\MPspotspacespec\currentMPcolorspaces
+% \donothing\registerMPcolorspace
+% \fi}
+
+\let\revokeMPtransparencyspecial\relax
+
+\def\dohandleMPrgbcolor #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmykcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgraycolor #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspotcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Transparency support used specials 60 (rgb) and 61
+%D (cmyk).
+%D
+%D \startbufferFshade
+
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
+%D fill p rotated 210 withcolor transparent(1,.5,green) ;
+%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D One can also communicate colors between \CONTEXT\ and
+%D \METAPOST:
+%D
+%D \startbuffer
+%D \definecolor[tcyan] [c=1,k=.2,t=.5]
+%D \definecolor[tmagenta][m=1,k=.2,t=.5]
+%D \definecolor[tyellow] [y=1,k=.2,t=.5]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
+%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
+%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
+%D \stopbuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D We save all the three components needed in one macro,
+%D just to save hash space.
+
+\def\dohandleMPrgbtransparency #1#2#3#4#5{\execcolorR #1:#2:#3:#4:#5\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPcmyktransparency#1#2#3#4#5#6{\execcolorC#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPgraytransparency #1#2#3{\execcolorS #1:#2:#3\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPspottransparency#1#2#3#4#5#6{\execcolorP#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+
+\def\dorevokeMPtransparencyspecial
+ {\PDFcode{\PDFtransparencyresetidentifier\space gs}%
+ \let\revokeMPtransparencyspecial\relax}
+
+\defineMPspecial{3} % rgb
+ {\setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPrgbtransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{4} % cmyk
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPcmyktransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{5} % spot
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPspottransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}%
+ }%\checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}
+
+%D Shading is an example of a more advanced graphic feature,
+%D but users will seldom encounter those complications. Here
+%D we only show a few simple examples, but many other
+%D alternatives are possible by setting up the functions built
+%D in \PDF\ in the appropriate way.
+%D
+%D Shading has to do with interpolation between two or more
+%D points or user supplied ranges. In \PDF, the specifications
+%D of a shade has to be encapsulated in objects and passed on
+%D as resources. This is a \PDF\ level 1.3. feature. One can
+%D simulate three dimensional shades as well and define simple
+%D functions using a limited set of \POSTSCRIPT\ primitives.
+%D Given the power of \METAPOST\ and these \PDF\ features, we
+%D can achieve superb graphic effects.
+%D
+%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
+%D we can stick to high level \CONTEXT\ command, as shown in
+%D the following exmples.
+%D
+%D \startbuffer
+%D \startuniqueMPgraphic{CircularShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D circular_shade(p,0,.2red,.9red) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{LinearShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,0,.2blue,.9blue) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{DuotoneShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,2,.5green,.5red) ;
+%D \stopuniqueMPgraphic
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These graphics can be hooked into the overlay mechanism,
+%D which is available in many commands.
+%D
+%D \startbuffer
+%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
+%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
+%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These backgrounds can for instance be applied to \type
+%D {\framed}:
+%D
+%D \startbuffer
+%D \setupframed[width=3cm,height=2cm,frame=off]
+%D \startcombination[3*1]
+%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
+%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
+%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D There are a few more alternatives, determined by the second
+%D parameter passed to \type {circular_shade} and alike.
+%D
+%D \def\SomeShade#1#2#3#4#5%
+%D {\startuniqueMPgraphic{Shade-#1}
+%D width := \overlaywidth ;
+%D height := \overlayheight ;
+%D path p ; p := unitsquare xscaled width yscaled height ;
+%D #2_shade(p,#3,#4,#5) ;
+%D \stopuniqueMPgraphic
+%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
+%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
+%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
+%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
+%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
+%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
+%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
+%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
+%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
+%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[4*1]
+%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
+%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
+%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
+%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D These macros closely cooperate with the \METAPOST\ module
+%D \type {mp-spec.mp}, which is part of the \CONTEXT\
+%D distribution.
+%D
+%D The low level (\PDF) implementation is based on the \TEX\
+%D based \METAPOST\ to \PDF\ converter. Shading is supported
+%D by overloading the \type {fill} operator as implemented
+%D earlier. In \PDF\ type~2 and~3 shading functions are
+%D specified in terms of:
+%D
+%D \starttabulate[|Tl|l|]
+%D \NC /Domain \NC sort of meeting range \NC \NR
+%D \NC /C0 \NC inner shade \NC \NR
+%D \NC /C1 \NC outer shade \NC \NR
+%D \NC /N \NC smaller values, bigger inner circles \NC \NR
+%D \stoptabulate
+
+\newcount\currentPDFshade % 0 % global (document wide) counter
+
+% \def\dosetMPsomePDFshade#1#2% generic but needs refs
+% {\global\advance\currentPDFshade \plusone
+% \doPDFdictionaryobject{FDF}{ftn:Sh:\the\currentPDFshade}
+% {/FunctionType 2
+% /Domain [\gMPs1 \gMPs2]
+% /C0 [\MPshadeA]
+% /C1 [\MPshadeB]
+% /N \gMPs3}%
+% \doPDFgetobjectreference{FDF}{ftn:Sh:\the\currentPDFshade}\PDFobjectreference
+% \doPDFdictionaryobject{FDF}{obj:Sh:\the\currentPDFshade}
+% {/ShadingType #1
+% /ColorSpace /\MPresolvedspace
+% /Function \PDFobjectreference\space
+% /Coords [\MPshadeC]
+% /Extend [true true]}%
+% \doPDFgetobjectreference{FDF}{obj:Sh:\the\currentPDFshade}\PDFobjectreference
+% \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\PDFobjectreference}%
+% \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+
+\def\dosetMPsomePDFshade#1#2%
+ {\immediate\pdfobj
+ {<</FunctionType 2
+ /Domain [\gMPs1 \gMPs2]
+ /C0 [\MPshadeA]
+ /C1 [\MPshadeB]
+ /N \gMPs3>>}%
+ \immediate\pdfobj
+ {<</ShadingType #1
+ /ColorSpace /\MPresolvedspace
+ /Function \the\pdflastobj\space 0 R
+ /Coords [\MPshadeC]
+ /Extend [true true]>>}%
+ \global\advance\currentPDFshade \plusone
+ \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
+ \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+
+\def\dosetMPlinearshade {\dosetMPsomePDFshade2}% #1
+\def\dosetMPcircularshade{\dosetMPsomePDFshade3}% #1
+
+\defineMPspecial{30}
+ {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \expanded{\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
+ \dosetMPlinearshade{\gMPs{14}}}
+
+\defineMPspecial{31}
+ {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \expanded{\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
+ \dosetMPcircularshade{\gMPs{16}}}
+
+\defineMPspecial{32}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{33}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+\defineMPspecial{34}
+ {\expanded{\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{35}
+ {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+
+\newconditional\ignoreMPpath
+
+\def\dohandleMPshade#1%
+ {\revokeMPtransparencyspecial
+ \settrue\ignoreMPpath
+ \def\extraMPpathcode{/Sh#1 sh Q}%
+ \chardef\finiMPpath\zerocount
+ \PDFcode{q /Pattern cs}}
+
+%D Figure inclusion is kind of strange to \METAPOST, but when
+%D Santiago Muelas started discussing this with me, I was able
+%D to cook up a solution using specials.
+
+\defineMPspecial{10}
+ {\setxvalue{\@@MPSK\gMPs8}%
+ {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}
+
+\def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
+ {\global\letvalue{\@@MPSK#8}\empty
+ \vbox to \zeropoint
+ {\vss
+ \hbox to \zeropoint
+ {\ifcase\pdfoutput\or % will be hooked into the special driver
+ \doiffileelse{#7}
+ {\doifundefinedelse{mps:x:#7}
+ {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
+ \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
+ {\message{[reusing figure #7]}}%
+ \PDFcode{q #1 #2 #3 #4 #5 #6 cm}%
+ \rlap{\getvalue{mps:x:#7}}%
+ \PDFcode{Q}}
+ {\message{[unknown figure #7]}}%
+ \fi
+ \hss}}}
+
+%D An example of using both special features is the
+%D following.
+%D
+%D \starttyping
+%D \startMPpage
+%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
+%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
+%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
+%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
+%D path q ; q := p rotatedaround(center p,90) ;
+%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
+%D path s ; s := boundingbox currentpicture enlarged 5mm ;
+%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
+%D circular_shade(s,0,.2red,.9red) ;
+%D addto currentpicture also c ;
+%D \stopMPpage
+%D \stoptyping
+
+%D This is some experimental hyperlink driver that I wrote
+%D for Mark Wicks.
+
+\defineMPspecial{20}
+ {\setxvalue{\@@MPSK\gMPs6}%
+ {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}
+
+\def\handleMPhyperlink#1#2#3#4#5#6%
+ {\global\letvalue{\@@MPSK#6}\empty
+ \setbox\scratchbox\hbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
+ \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
+ \incolorfalse
+ \gotobox{\box\scratchbox}[#5]}%
+ \setbox\scratchbox\hbox
+ {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
+ \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}
+
+%D This special (number 50) passes positions to a tex file.
+%D This method uses a two||pass approach an (mis|)|used the
+%D context positioning macros. In \type {core-pos} we will
+%D implement the low level submacro needed.
+%D
+%D \startbuffer
+%D \definelayer[test]
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-1},y=\MPy{somepos-1}]
+%D {Whatever we want here!}
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-2},y=\MPy{somepos-2}]
+%D {Whatever we need there!}
+%D
+%D \startuseMPgraphic{oeps}
+%D draw fullcircle scaled 6cm withcolor red ;
+%D register ("somepos-1",1cm,2cm,center currentpicture) ;
+%D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
+%D \stopuseMPgraphic
+%D
+%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Here the width and height are not realy used, but one can
+%D imagine situations where tex has to work with values
+%D calculated by \METAPOST.
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D Later we will implement a more convenient macro:
+%D
+%D \starttyping
+%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
+%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
+%D \stoptyping
+
+\defineMPspecial{50} % x y width height label
+ {\dosavepositionwhd
+ {\gMPs5}%
+ {0}%
+ {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
+ {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}%
+ {\the\dimexpr\gMPs3\onebasepoint\relax}%
+ {\the\dimexpr\gMPs4\onebasepoint\relax}%
+ {0pt}}
+
+%D A few auxiliary macros. This will move to colo-ini.
+
+\def\MPgrayspace{DeviceGray}
+\def\MPrgbspace {DeviceRGB}
+\def\MPcmykspace{DeviceCMYK}
+\let\MPspotspace\MPgrayspace
+
+\def\MPcmykBlack{0 0 0 0}
+\def\MPcmykWhite{0 0 0 1}
+
+\def\startMPcolorresolve
{\bgroup
- \let\finishMPgraphic\egroup
- \doprocessMPtoPDFfile}
+ \def\dostartgraycolormode##1%
+ {\global\let\MPresolvedspace\MPgrayspace
+ \xdef\MPresolvedcolor{##1}}%
+ \def\dostartrgbcolormode ##1##2##3%
+ {\global\let\MPresolvedspace\MPrgbspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3}}%
+ \def\dostartcmykcolormode##1##2##3##4%
+ {\global\let\MPresolvedspace\MPcmykspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}%
+ \def\dostartspotcolormode##1##2%
+ {\global\let\MPspotspace\empty % left over ?
+ \xdef\MPresolvedspace{##1}%
+ \xdef\MPresolvedcolor{##2}%
+ \global\let\MPspotspace\MPresolvedspace}% signal
+ \dostartgraycolormode\!!zerocount} % kind of hackery initialization
+
+\let\stopMPcolorresolve\egroup
+
+\def\resolveMPrgbcolor#1#2#3\to#4%
+ {\startMPcolorresolve
+ \execcolorR#1:#2:#3:0:0\od
+ \stopMPcolorresolve
+ \let#4\MPresolvedcolor}
+
+\def\resolveMPcmykcolor#1#2#3#4\to#5%
+ {\startMPcolorresolve
+ \execcolorC#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+\def\resolveMPgraycolor#1\end\to#2%
+ {\startMPcolorresolve
+ \execcolorS#1:0:0\od
+ \stopMPcolorresolve
+ \let#2\MPresolvedcolor}
+
+\def\resolveMPspotcolor#1#2#3#4\end\to#5%
+ {\startMPcolorresolve
+ \ifnum#2>\plusone
+ \checkmultitonecolor{#1}%
+ \fi
+ \execcolorP#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+%D \macros
+%D {dogetPDFmediabox}
+%D
+%D The next macro can be used to find the mediabox of a \PDF\
+%D illustration.
+%D
+%D \starttyping
+%D \dogetPDFmediabox
+%D {filename}
+%D {new dimen}{new dimen}{new dimen}{new dimen}
+%D \stoptyping
+%D
+%D Beware of dimen clashes: this macro uses the 5~default
+%D scratch registers! When no file or mediabox is found, the
+%D dimensions are zeroed.
+\def\dogetPDFmediabox#1#2#3#4#5%
+ {\bgroup
+ \def\PDFxscale{1}%
+ \def\PDFyscale{1}%
+ \uncatcodespecials
+ \endlinechar\minusone
+ \def\checkPDFtypepage##1/Type /Page##2##3\done%
+ {\ifx##2\relax
+ \else\if##2s% accept /Page and /Pages
+ \let\doprocessPDFline\findPDFmediabox
+ \else
+ \let\doprocessPDFline\findPDFmediabox
+ \fi\fi}%
+ \def\findPDFtypepage
+ {\expandafter\checkPDFtypepage\fileline/Type /Page\relax\done}%
+ \def\checkPDFmediabox##1/MediaBox##2##3\done%
+ {\ifx##2\relax \else
+ \setPDFmediabox##2##3\done
+ \fileprocessedtrue
+ \fi}%
+ \def\findPDFmediabox
+ {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}%
+ \let\doprocessPDFline\findPDFtypepage
+ \doprocessfile\scratchread{#1}\doprocessPDFline
+ \egroup
+ \ifx\PDFxoffset\undefined
+ #2=\zeropoint
+ #3=\zeropoint
+ #4=\zeropoint
+ #5=\zeropoint
+ \else
+ #2=\PDFxoffset\onebasepoint
+ #3=\PDFyoffset\onebasepoint
+ #4=\PDFwidth
+ #5=\PDFheight
+ \fi}
+
+\def\setPDFboundingbox#1#2#3#4#5#6%
+ {\dimen0=#1\dimen0=#5\dimen0
+ \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset
+ \dimen0=#3\dimen0=#5\dimen0
+ \xdef\PDFwidth{\the\dimen0}%
+ \dimen0=#2\dimen0=#6\dimen0
+ \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset
+ \dimen0=#4\dimen0=#6\dimen0
+ \xdef\PDFheight{\the\dimen0}%
+ \global\let\PDFxoffset\PDFxoffset
+ \global\let\PDFyoffset\PDFyoffset}
+
+\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done
+ {\dimen2=#2\onebasepoint\dimen2=-\dimen2 % \dimen2=-#2\onebasepoint also works since tex handles --
+ \dimen4=#3\onebasepoint\dimen4=-\dimen4 % \dimen4=-#3\onebasepoint also works since tex handles --
+ \dimen6=#4\onebasepoint\advance\dimen6 \dimen2
+ \dimen8=#5\onebasepoint\advance\dimen8 \dimen4
+ \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale}
+
+%D End of soon obsolete code.
+
+\startMPinitializations
+ mp_shade_version := 2 ;
+\stopMPinitializations
+
+%D Here comes the traditional \MKII\ converter.
+%D
%D Because we want to test as fast as possible, we first
%D define the \POSTSCRIPT\ operators that \METAPOST\ uses.
%D We don't define irrelevant ones, because these are
%D skipped anyway.
-
+%D
%D The converter can be made a bit faster by replacing the
%D two test macros (the ones with the many \type {\if's}) by
%D a call to named branch macros (something \typ {\getvalue
@@ -1215,9 +2128,6 @@
%D
%D But, this one is still too inaccurate, so we now have:
-%D We cannot use \type {\beginETEX} here since in plain we
-%D get \type {\outer} problems, sigh.
-
%D DHL: Ideally, $r_x$, $r_y$, $s_x$, $s_y$ should be in macros, not
%D dimensions (they are scalar quantities after all, not lengths). I
%D suppose the authors decided to do calculations with integer
@@ -1726,7 +2636,7 @@
{\ifcase\inlineMPspecials\or
\advance\nofMParguments \minusone % pop the size
\fi
- \ifundefined\MPspecial
+ \ifundefined\MPspecial % beware, no real \if
\message{[unknown \MPspecial]}%
\else
\csname\MPspecial\endcsname
diff --git a/tex/context/base/meta-pdf.mkiv b/tex/context/base/meta-pdf.mkiv
index eded7d59d..23981815c 100644
--- a/tex/context/base/meta-pdf.mkiv
+++ b/tex/context/base/meta-pdf.mkiv
@@ -1,8 +1,8 @@
%D \module
%D [ file=meta-pdf,
-%D version=2006.29.09,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=\METAPOST\ to \PDF\ conversion,
+%D version=2006.06.07,
+%D title=\METAPOST\ Graphics,
+%D subtitle=Conversion to \PDF,
%D author=Hans Hagen \& others (see text),
%D date=\currentdate,
%D copyright=\PRAGMA]
@@ -11,10 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+%D Formerly known as supp-pdf.tex and supp-mpe.tex.
-% Using test case at end of meta-pdf.tex:
-%
% \useMPgraphic{1}
% \testfeatureonce{250}{\setbox0\hbox{\convertMPtoPDF{test-mps-mpgraph.1}{1}{1}}}
%
@@ -26,10 +24,86 @@
\registerctxluafile{meta-pdf}{1.003}
-%D Plugin.
+%D We will clean up the color mess later.
+
+\writestatus{loading}{MetaPost Graphics / MPS to PDF}
+
+\unprotect
+
+\ifx\PDFcode \undefined \let\PDFcode \gobbleoneargument \fi
+\ifx\PDFcomment\undefined \def\PDFcomment#1{\PDFcode{\letterpercent\space#1}} \fi
+
+%D First we define a handy constant:
+
+\bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup
+
+%D \macros
+%D {convertMPtoPDF}
+%D
+%D The next set of macros implements \METAPOST\ to \PDF\
+%D conversion. The traditional method is in the MkII file.
+%D
+%D The main conversion command is:
+%D
+%D \starttyping
+%D \convertMPtoPDF {filename} {x scale} {y scale}
+%D \stoptyping
+%D
+%D The dimensions are derived from the bounding box. So we
+%D only have to say:
+%D
+%D \starttyping
+%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
+%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
+%D \stoptyping
+
+%D \macros
+%D {makeMPintoPDFobject,lastPDFMPobject}
+%D
+%D For experts there are a few more options. When attributes
+%D are to be added, the code must be embedded in an object
+%D accompanied with the appropriate directives. One can
+%D influence this process with \type {\makeMPintoPDFobject}.
+%D
+%D This option defaults to~0, because \CONTEXT\ takes care
+%D of objects at another level, which saves some bytes.
+%D
+%D \starttabulate[|l|l|p|]
+%D \NC 0 \NC never \NC don't use an object \NC\NR
+%D \NC 1 \NC always \NC always use an object \NC\NR
+%D \NC 2 \NC optional \NC use object when needed \NC\NR
+%D \stoptabulate
+%D
+%D The last object number used is avaliable in the macro
+%D \type {\lastPDFMPobject}.
+
+\ifx\makeMPintoPDFobject \undefined \chardef\makeMPintoPDFobject \zerocount \fi
+\ifx\blackoutMPgraphic \undefined \chardef\blackoutMPgraphic \plusone \fi
+\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion \fi
+
+\let\lastPDFMPobject \!!zerocount
+\let\currentPDFresources\empty
+\let\setMPextensions \relax
+
+\def\PDFMPformoffset
+ {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}
-\def\mkconvertMPtoPDF % watch the transparency reset
- {\vbox\bgroup
+\def\resetMPvariables#1#2#3%
+ {\global\let\MPwidth \!!zeropoint
+ \global\let\MPheight\!!zeropoint
+ \global\let\MPllx \!!zerocount
+ \global\let\MPlly \!!zerocount
+ \global\let\MPurx \!!zerocount
+ \global\let\MPury \!!zerocount
+ \xdef\MPxscale {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
+ \xdef\MPyscale {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
+ \xdef\MPfilename {#1}}
+
+%D The main macro:
+
+\def\convertMPtoPDF#1#2#3% watch the transparency reset
+ {\resetMPvariables{#1}{#2}{#3}%
+ \vbox\bgroup
\forgetall
\offinterlineskip
%\ifcase\blackoutMPgraphic\or\PDFcode{0 g 0 G}\fi % fixed in mp
@@ -61,19 +135,657 @@
\dopackageMPgraphic\scratchbox
\egroup}
-\let\mkprocessMPtoPDFfile\mkconvertMPtoPDF
+\let\processMPtoPDFfile\convertMPtoPDF
+
+%D A common hook.
+
+\let\MPfshowcommand\empty
+
+%D Objects.
+
+\def\dopackageMPgraphic#1% #1 = boxregister
+ {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
+ % an existing value of 2 signals object support (set elsewhere)
+ \chardef\makeMPintoPDFobject\plusone
+ \fi\fi
+ \ifcase\makeMPintoPDFobject
+ \box#1%
+ \or
+ \scratchdimen\PDFMPformoffset\relax
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \setbox#1\vbox spread 2\scratchdimen
+ {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
+ \fi
+ \setMPPDFobject{\currentPDFresources}{#1}%
+ \ifdim\scratchdimen>\zeropoint % compensate for error
+ \vbox to \MPheight
+ {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
+ \else
+ \getMPPDFobject
+ \fi
+ \global\let\currentPDFresources\empty
+ \else
+ \box#1%
+ \fi}
+
+\def\setMPPDFobject#1#2% resources boxnumber
+ {\ifx\pdfxform\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifx\pdftexversion\undefined
+ \def\getMPPDFobject{\box#2}%
+ \else\ifnum\pdftexversion<14
+ \def\getMPPDFobject{\box#2}%
+ \else
+ \ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi
+ \immediate\pdfxform resources{#1}#2%
+ \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}%
+ \fi\fi\fi}
+
+\let\getMPPDFobject\relax
+
+%D \macros
+%D {deleteMPgraphic,
+%D startMPresources,
+%D stopMPresources}
+
+\ifx\deleteMPgraphic\undefined
+ \def\deleteMPgraphic#1{}
+\fi
+
+\ifx\startMPresources\undefined
+ \let\startMPresources\relax
+ \let\stopMPresources\relax
+\fi
+
+%D We implement extensions by using the \METAPOST\ special
+%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
+%D are flushed before or after the graphic data, but thereby
+%D are no longer connected to a position.
+%D
+%D We implement specials by overloading the \type {fill}
+%D operator. By counting the fills, we can let the converter
+%D treat the appropriate fill in a special way. The
+%D specification of the speciality can have two forms,
+%D determined by the setting of a boolean variable:
+%D
+%D \starttyping
+%D _inline_specials_ := false ; % comment like code (default)
+%D _inline_specials_ := true ; % command like code
+%D \stoptyping
+%D
+%D When the specification is embedded as comment, it looks
+%D like:
+%D
+%D \starttyping
+%D %%MetaPostSpecial <size> <data> <number> <identifier>
+%D \stoptyping
+%D
+%D The in||line alternative is more tuned for \POSTSCRIPT,
+%D since it permits us to define a macro \type {special}.
+%D
+%D \starttyping
+%D inline : <data> <number> <identifier> <size> special
+%D \stoptyping
+%D
+%D The \type {identifier} determines what to do, and the data
+%D can be used to accomplish this. A type~2 shading function
+%D has identifier~2. Alltogether, the number of parameters is
+%D specified in \type {size}. The \type {number} is the number
+%D of the fill that needs the special treatment. For a type~2
+%D and~3 shaded fill, the datablock contains the following
+
+%D data:
+%D
+%D \starttyping
+%D from to n inner_r g b x y outer_r g b x y
+%D from to n inner_r g b x y radius outer_r g b x y radius
+%D \stoptyping
+
+\newconditional\manyMPspecials \settrue\manyMPspecials
+
+%D In case of \PDF, we need to prepare resourcs.
+
+\newtoks\MPstartresources
+\newtoks\MPstopresources
+
+\def\startMPresources
+ {\the\MPstartresources}
+
+\def\stopMPresources
+ {\the\MPstopresources}
+
+%D Some day we may consider collecting local resources.
+
+\appendtoks
+ \global\let\currentPDFresources\empty % kind of redundant
+\to \MPstartresources
+
+% \appendtoks
+% \collectPDFresources
+% \global\let\currentPDFresources\collectedPDFresources
+% \to \MPstopresources
+
+\appendtoksonce
+ \the\everyPDFxform
+\to \MPstopresources
+
+%D Since colors are not subjected to transformations, we can
+%D only use colors as signal. In our case, we use a dummy colored
+%D path with a red color component of \type {0.n}, so \type
+%D {0.001} is the first path and \type {0.010} the tenth. Since
+%D \METAPOST strips trailing zeros, we have to padd the string.
+
+\newif\ifMPcmykcolors
+\newif\ifMPspotcolors
+
+\def\dohandleMPrgb #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmyk#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgray #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspot#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Specials:
+
+\settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty
+
+\def\@@MP {@@MP}
+\def\@@MPSK{@MPSK@}
+
+\def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}
+
+\def\defineMPspecial#1#2%
+ {\setvalue{\@@MPSK\@@MPSK#1}{#2}}
+
+%D Special number~1 is dedicated to \CMYK\ support. If you
+%D want to know why: look at this:
+%D
+%D \startbuffer[mp]
+%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
+%D \stopbuffer
+%D
+%D \startbuffer[cmyk]
+%D \startcombination[4*1]
+%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
+%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
+%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
+%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \placefigure
+%D {\CMYK\ support disabled,
+%D conversion to \RGB.}
+%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no support in \METAPOST.}
+%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
+%D
+%D \placefigure
+%D {\CMYK\ support enabled,
+%D no conversion to \RGB,
+%D support in \METAPOST}
+%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
+
+\defineMPspecial{1}
+ {\ifMPcmykcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPcmykcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+ \fi}
+
+\defineMPspecial{2}
+ {\ifMPspotcolors
+ \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPspotcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
+% \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}%
+ \fi}
+
+% \def\checkMPspot#1#2#3#4%
+% {\normalexpanded{\noexpand\resolveMPspotcolor#1 #2 #3 #4}\end
+% \ifx\MPspotspace\MPresolvedspace
+% \edef\MPspotspacespec{/\MPspotspace\space}%
+% \doifinstringelse\MPspotspacespec\currentMPcolorspaces
+% \donothing\registerMPcolorspace
+% \fi}
+
+\let\revokeMPtransparencyspecial\relax
+
+\def\dohandleMPrgbcolor #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
+\def\dohandleMPcmykcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
+\def\dohandleMPgraycolor #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
+\def\dohandleMPspotcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
+
+%D Transparency support used specials 60 (rgb) and 61
+%D (cmyk).
+%D
+%D \startbufferFshade
+
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
+%D fill p rotated 210 withcolor transparent(1,.5,green) ;
+%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D One can also communicate colors between \CONTEXT\ and
+%D \METAPOST:
+%D
+%D \startbuffer
+%D \definecolor[tcyan] [c=1,k=.2,t=.5]
+%D \definecolor[tmagenta][m=1,k=.2,t=.5]
+%D \definecolor[tyellow] [y=1,k=.2,t=.5]
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
+%D
+%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
+%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
+%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
+%D \stopbuffer
+%D
+%D \startlinecorrection \processMPbuffer \stoplinecorrection
+%D
+%D We save all the three components needed in one macro,
+%D just to save hash space.
+
+\def\dohandleMPrgbtransparency #1#2#3#4#5{\execcolorR #1:#2:#3:#4:#5\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPcmyktransparency#1#2#3#4#5#6{\execcolorC#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPgraytransparency #1#2#3{\execcolorS #1:#2:#3\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+\def\dohandleMPspottransparency#1#2#3#4#5#6{\execcolorP#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
+
+\def\dorevokeMPtransparencyspecial
+ {\PDFcode{\PDFtransparencyresetidentifier\space gs}%
+ \let\revokeMPtransparencyspecial\relax}
+
+\defineMPspecial{3} % rgb
+ {\setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPrgbtransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{4} % cmyk
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPcmyktransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}}
+
+\defineMPspecial{5} % spot
+ {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPspottransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}%
+ }%\checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}
+
+%D Shading is an example of a more advanced graphic feature,
+%D but users will seldom encounter those complications. Here
+%D we only show a few simple examples, but many other
+%D alternatives are possible by setting up the functions built
+%D in \PDF\ in the appropriate way.
+%D
+%D Shading has to do with interpolation between two or more
+%D points or user supplied ranges. In \PDF, the specifications
+%D of a shade has to be encapsulated in objects and passed on
+%D as resources. This is a \PDF\ level 1.3. feature. One can
+%D simulate three dimensional shades as well and define simple
+%D functions using a limited set of \POSTSCRIPT\ primitives.
+%D Given the power of \METAPOST\ and these \PDF\ features, we
+%D can achieve superb graphic effects.
+%D
+%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
+%D we can stick to high level \CONTEXT\ command, as shown in
+%D the following exmples.
+%D
+%D \startbuffer
+%D \startuniqueMPgraphic{CircularShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D circular_shade(p,0,.2red,.9red) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{LinearShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,0,.2blue,.9blue) ;
+%D \stopuniqueMPgraphic
+%D
+%D \startuniqueMPgraphic{DuotoneShade}
+%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
+%D linear_shade(p,2,.5green,.5red) ;
+%D \stopuniqueMPgraphic
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These graphics can be hooked into the overlay mechanism,
+%D which is available in many commands.
+%D
+%D \startbuffer
+%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
+%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
+%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D These backgrounds can for instance be applied to \type
+%D {\framed}:
+%D
+%D \startbuffer
+%D \setupframed[width=3cm,height=2cm,frame=off]
+%D \startcombination[3*1]
+%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
+%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
+%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
+%D \stopcombination
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D There are a few more alternatives, determined by the second
+%D parameter passed to \type {circular_shade} and alike.
+%D
+%D \def\SomeShade#1#2#3#4#5%
+%D {\startuniqueMPgraphic{Shade-#1}
+%D width := \overlaywidth ;
+%D height := \overlayheight ;
+%D path p ; p := unitsquare xscaled width yscaled height ;
+%D #2_shade(p,#3,#4,#5) ;
+%D \stopuniqueMPgraphic
+%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
+%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
+%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
+%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
+%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
+%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[5*1]
+%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
+%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
+%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
+%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
+%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D \blank
+%D
+%D \startlinecorrection
+%D \startcombination[4*1]
+%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
+%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
+%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
+%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
+%D \stopcombination
+%D \stoplinecorrection
+%D
+%D These macros closely cooperate with the \METAPOST\ module
+%D \type {mp-spec.mp}, which is part of the \CONTEXT\
+%D distribution.
+%D
+%D The low level (\PDF) implementation is based on the \TEX\
+%D based \METAPOST\ to \PDF\ converter. Shading is supported
+%D by overloading the \type {fill} operator as implemented
+%D earlier. In \PDF\ type~2 and~3 shading functions are
+%D specified in terms of:
+%D
+%D \starttabulate[|Tl|l|]
+%D \NC /Domain \NC sort of meeting range \NC \NR
+%D \NC /C0 \NC inner shade \NC \NR
+%D \NC /C1 \NC outer shade \NC \NR
+%D \NC /N \NC smaller values, bigger inner circles \NC \NR
+%D \stoptabulate
+
+\newcount\currentPDFshade % 0 % global (document wide) counter
+
+\def\dosetMPsomePDFshade#1#2%
+ {\immediate\pdfobj
+ {<</FunctionType 2
+ /Domain [\gMPs1 \gMPs2]
+ /C0 [\MPshadeA]
+ /C1 [\MPshadeB]
+ /N \gMPs3>>}%
+ \immediate\pdfobj
+ {<</ShadingType #1
+ /ColorSpace /\MPresolvedspace
+ /Function \the\pdflastobj\space 0 R
+ /Coords [\MPshadeC]
+ /Extend [true true]>>}%
+ \global\advance\currentPDFshade \plusone
+ \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
+ \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
+
+\def\dosetMPlinearshade {\dosetMPsomePDFshade2}% #1
+\def\dosetMPcircularshade{\dosetMPsomePDFshade3}% #1
+
+\defineMPspecial{30}
+ {\normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
+ \dosetMPlinearshade{\gMPs{14}}}
+
+\defineMPspecial{31}
+ {\normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
+ \dosetMPcircularshade{\gMPs{16}}}
+
+\defineMPspecial{32}
+ {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{33}
+ {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+\defineMPspecial{34}
+ {\normalexpanded{\noexpand\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
+ \dosetMPlinearshade{\gMPs{16}}}
+
+\defineMPspecial{35}
+ {\normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
+ \normalexpanded{\noexpand\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
+ \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
+ \dosetMPcircularshade{\gMPs{18}}}
+
+\newconditional\ignoreMPpath
+
+\def\dohandleMPshade#1%
+ {\revokeMPtransparencyspecial
+ \settrue\ignoreMPpath
+ \def\extraMPpathcode{/Sh#1 sh Q}%
+ \chardef\finiMPpath\zerocount
+ \PDFcode{q /Pattern cs}}
+
+\defineMPspecial{10}
+ {\setxvalue{\@@MPSK\gMPs8}%
+ {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}
+
+\def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
+ {\global\letvalue{\@@MPSK#8}\empty
+ \vbox to \zeropoint
+ {\vss
+ \hbox to \zeropoint
+ {\ifcase\pdfoutput\or % will be hooked into the special driver
+ \doiffileelse{#7}
+ {\doifundefinedelse{mps:x:#7}
+ {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
+ \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
+ {\message{[reusing figure #7]}}%
+ \PDFcode{q #1 #2 #3 #4 #5 #6 cm}%
+ \rlap{\getvalue{mps:x:#7}}%
+ \PDFcode{Q}}
+ {\message{[unknown figure #7]}}%
+ \fi
+ \hss}}}
+
+%D An example of using both special features is the
+%D following.
+%D
+%D \starttyping
+%D \startMPpage
+%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
+%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
+%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
+%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
+%D path q ; q := p rotatedaround(center p,90) ;
+%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
+%D path s ; s := boundingbox currentpicture enlarged 5mm ;
+%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
+%D circular_shade(s,0,.2red,.9red) ;
+%D addto currentpicture also c ;
+%D \stopMPpage
+%D \stoptyping
-% \def\TEXcode#1#2#3#4#5%
-% {\setbox\scratchbox\hbox
-% {\font\temp=#1\space at #2\onebasepoint
-% \temp
-% \MPfshowcommand{#3}}%
-% \setbox\scratchbox\hbox
-% {\hskip#4\onebasepoint
-% \raise#5\onebasepoint
-% \box\scratchbox}%
-% \smashbox\scratchbox
-% \box\scratchbox}
+\defineMPspecial{20}
+ {\setxvalue{\@@MPSK\gMPs6}%
+ {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}
+
+\def\handleMPhyperlink#1#2#3#4#5#6%
+ {\global\letvalue{\@@MPSK#6}\empty
+ \setbox\scratchbox\hbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
+ \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
+ \incolorfalse
+ \gotobox{\box\scratchbox}[#5]}%
+ \setbox\scratchbox\hbox
+ {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
+ \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
+ \box\scratchbox}%
+ \smashbox\scratchbox
+ \box\scratchbox}
+
+%D This special (number 50) passes positions to a tex file.
+%D This method uses a two||pass approach an (mis|)|used the
+%D context positioning macros. In \type {core-pos} we will
+%D implement the low level submacro needed.
+%D
+%D \startbuffer
+%D \definelayer[test]
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-1},y=\MPy{somepos-1}]
+%D {Whatever we want here!}
+%D
+%D \setlayer
+%D [test]
+%D [x=\MPx{somepos-2},y=\MPy{somepos-2}]
+%D {Whatever we need there!}
+%D
+%D \startuseMPgraphic{oeps}
+%D draw fullcircle scaled 6cm withcolor red ;
+%D register ("somepos-1",1cm,2cm,center currentpicture) ;
+%D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
+%D \stopuseMPgraphic
+%D
+%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Here the width and height are not realy used, but one can
+%D imagine situations where tex has to work with values
+%D calculated by \METAPOST.
+%D
+%D \startlinecorrection
+%D \getbuffer
+%D \stoplinecorrection
+%D
+%D Later we will implement a more convenient macro:
+%D
+%D \starttyping
+%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
+%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
+%D \stoptyping
+
+\defineMPspecial{50} % x y width height label
+ {\dosavepositionwhd
+ {\gMPs5}%
+ {0}%
+ {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
+ {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}%
+ {\the\dimexpr\gMPs3\onebasepoint\relax}%
+ {\the\dimexpr\gMPs4\onebasepoint\relax}%
+ {0pt}}
+
+%D A few auxiliary macros. This will move to colo-ini.
+
+\def\MPgrayspace{DeviceGray}
+\def\MPrgbspace {DeviceRGB}
+\def\MPcmykspace{DeviceCMYK}
+\let\MPspotspace\MPgrayspace
+
+\def\MPcmykBlack{0 0 0 0}
+\def\MPcmykWhite{0 0 0 1}
+
+\def\startMPcolorresolve
+ {\bgroup
+ \def\dostartgraycolormode##1%
+ {\global\let\MPresolvedspace\MPgrayspace
+ \xdef\MPresolvedcolor{##1}}%
+ \def\dostartrgbcolormode ##1##2##3%
+ {\global\let\MPresolvedspace\MPrgbspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3}}%
+ \def\dostartcmykcolormode##1##2##3##4%
+ {\global\let\MPresolvedspace\MPcmykspace
+ \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}%
+ \def\dostartspotcolormode##1##2%
+ {\global\let\MPspotspace\empty % left over ?
+ \xdef\MPresolvedspace{##1}%
+ \xdef\MPresolvedcolor{##2}%
+ \global\let\MPspotspace\MPresolvedspace}% signal
+ \dostartgraycolormode\!!zerocount} % kind of hackery initialization
+
+\let\stopMPcolorresolve\egroup
+
+\def\resolveMPrgbcolor#1#2#3\to#4%
+ {\startMPcolorresolve
+ \execcolorR#1:#2:#3:0:0\od
+ \stopMPcolorresolve
+ \let#4\MPresolvedcolor}
+
+\def\resolveMPcmykcolor#1#2#3#4\to#5%
+ {\startMPcolorresolve
+ \execcolorC#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+\def\resolveMPgraycolor#1\end\to#2%
+ {\startMPcolorresolve
+ \execcolorS#1:0:0\od
+ \stopMPcolorresolve
+ \let#2\MPresolvedcolor}
+
+\def\resolveMPspotcolor#1#2#3#4\end\to#5%
+ {\startMPcolorresolve
+ \ifnum#2>\plusone
+ \checkmultitonecolor{#1}%
+ \fi
+ \execcolorP#1:#2:#3:#4:0:0\od
+ \stopMPcolorresolve
+ \let#5\MPresolvedcolor}
+
+\startMPinitializations
+ mp_shade_version := 2 ;
+\stopMPinitializations
% will be done better
@@ -152,4 +864,83 @@
\let\MPSgray\dohandleMPgray
\let\MPSspot\dohandleMPspot
+%D Test code:
+
+% \startMPcode
+% fill fullcircle scaled 3cm withcolor red ;
+% fill fullcircle scaled 2cm withcolor green ;
+% fill fullcircle scaled 1cm withcolor blue ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
+% fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
+% fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% draw fullcircle scaled 3cm dashed evenly ;
+% draw fullcircle scaled 2cm dashed withdots ;
+% draw origin withpen pencircle scaled 3mm;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
+% fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
+% fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
+% fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
+% currentpicture := currentpicture shifted (12cm,-4cm) ;
+% draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% % bug: shift
+% draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ;
+% draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
+% filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
+% currentpicture := currentpicture shifted (-4cm,0) ;
+% % shade cannot handle shift
+% circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
+% circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
+% filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ;
+% \stopMPcode
+
+% We cannot use attributes for switching colors in mp literals because
+% grouping (qQ) interferes.
+
+\ifx\colorversion\undefined \else \ifnum\colorversion>\plusone
+
+ \def\dohandleMPgraycolor #1{\ctxlua{ctx.pdffinishtransparency()
+ ctx.pdfgrayliteral(\the\currentcolormodel,#1)}}
+ \def\dohandleMPrgbcolor #1#2#3{\ctxlua{ctx.pdffinishtransparency()
+ ctx.pdfrgbliteral (\the\currentcolormodel,#1,#2,#3)}}
+ \def\dohandleMPcmykcolor#1#2#3#4{\ctxlua{ctx.pdffinishtransparency()
+ ctx.pdfcmykliteral(\the\currentcolormodel,#1,#2,#3,#4)}}
+ \def\dohandleMPspotcolor#1#2#3#4{\ctxlua{ctx.pdffinishtransparency()
+ ctx.pdfspotliteral(\the\currentcolormodel,"#1",#2,"#3","#4")}}
+
+ % we can combine the next calls
+
+ \def\dohandleMPgraytransparency #1#2#3{\ctxlua{ctx.pdfgrayliteral(\the\currentcolormodel,#1)
+ ctx.pdftransparencyliteral(#2,#3)}}
+ \def\dohandleMPrgbtransparency #1#2#3#4#5{\ctxlua{ctx.pdfrgbliteral (\the\currentcolormodel,#1,#2,#3)
+ ctx.pdftransparencyliteral(#4,#5)}}
+ \def\dohandleMPcmyktransparency#1#2#3#4#5#6{\ctxlua{ctx.pdfcmykliteral(\the\currentcolormodel,#1,#2,#3,#4)
+ ctx.pdftransparencyliteral(#5,#6)}}
+ \def\dohandleMPspottransparency#1#2#3#4#5#6{\ctxlua{ctx.pdfspotliteral(\the\currentcolormodel,"#1",#2,"#3","#4")
+ ctx.pdftransparencyliteral(#5,#6)}}
+
+ \def\dohandleMPresettransparency {\ctxlua{ctx.pdffinishtransparency()}}
+
+ \def\resolveMPgraycolor #1\to#2{\ctxlua{ctx.resolvempgraycolor("\strippedcsname#2","MPresolvedspace",\number\currentcolormodel,#1)}}
+ \def\resolveMPrgbcolor #1#2#3\to#4{\ctxlua{ctx.resolvemprgbcolor ("\strippedcsname#4","MPresolvedspace",\number\currentcolormodel,#1,#2,#3)}}
+ \def\resolveMPcmykcolor#1#2#3#4\to#5{\ctxlua{ctx.resolvempcmykcolor("\strippedcsname#5","MPresolvedspace",\number\currentcolormodel,#1,#2,#3,#4)}}
+
+ \def\resolveMPspotcolor#1#2#3#4\to#5% unchecked
+ {\ctxlua{ctx.resolvempspotcolor("\strippedcsname#5","MPresolvedspace",\number\currentcolormodel,"#1",#2,"#3","#4")}%
+ \xdef\MPresolvedspace{#1}%
+ \xdef\MPresolvedcolor{#4}%
+ \global\let\MPspotspace\MPresolvedspace}
+
+ % used as callers
+
+ \let\MPSgray\dohandleMPgraycolor
+ \let\MPSrgb \dohandleMPrgbcolor
+ \let\MPScmyk\dohandleMPcmykcolor
+ \let\MPspot \dohandleMPspotcolor
+
+\fi \fi
+
\protect \endinput
diff --git a/tex/context/base/meta-pdf.tex b/tex/context/base/meta-pdf.tex
deleted file mode 100644
index 8bf976f97..000000000
--- a/tex/context/base/meta-pdf.tex
+++ /dev/null
@@ -1,1020 +0,0 @@
-%D \module
-%D [ file=meta-pdf,
-%D version=2006.06.07,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=\METAPOST\ to \PDF\ conversion,
-%D author=Hans Hagen \& others (see text),
-%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 Formerly known as supp-pdf.tex and supp-mpe.tex.
-
-%D We will clean up the color mess later.
-
-%D These macros are written as generic as possible. Some
-%D general support macro's are loaded from a small module
-%D especially made for non \CONTEXT\ use. In this module I
-%D use a matrix transformation macro written by Tanmoy
-%D Bhattacharya. Thanks to extensive testing by Sebastian
-%D Ratz I was able to complete this module within reasonable
-%D time. This module has support for \METAPOST\ extensions
-%D built in.
-%D
-%D Daniel H. Luecking came up with a better (more precise)
-%D transformation method. You can recognize his comment by
-%D his initials. (We keep the old code around because it's a
-%D nice illustration on how a module like this evolves.)
-
-% Beware, we cannot use 0pt here by defaukt since it may be
-% defined in the range \dimen 0 - 20 which we happen to use
-% as scratch registers; for this reason we start allocating
-% scratch registers > 20
-
-%D This module handles some \PDF\ conversion and insertions
-%D topics. By default, the macros use the \PDFTEX\ primitive
-%D \type{\pdfliteral} when available. Since \PDFTEX\ is now the
-%D default engine for \TEX\ distributions, we need a more complex
-%D test.
-
-\writestatus{loading}{Context Support Macros / MPS to PDF}
-
-\unprotect
-
-\ifx\PDFcode \undefined \let\PDFcode \gobbleoneargument \fi
-\ifx\PDFcomment\undefined \def\PDFcomment#1{\PDFcode{\letterpercent\space#1}} \fi
-
-%D First we define a handy constant:
-
-\bgroup \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup
-
-%D \macros
-%D {pdfimage,pdfimages,pdfclippedimage}
-%D
-%D Starting with pdftex version 14, images are included more
-%D natural to the form embedding. This enables alternative
-%D images to be embedded.
-%D
-%D \starttyping
-%D \pdfimage <optional dimensions> {file}
-%D \pdfimages <optional dimensions> {high res file} {low res file}
-%D \stoptyping
-%D
-%D The first one replaces the pre||version||14 original,
-%D while the latter provides alternative images.
-%D
-%D The next macro is dedicated to Maarten Gelderman, who
-%D needed to paste prepared \PDF\ pages into conference
-%D proceedings.
-%D
-%D \starttyping
-%D \pdfclippedimage <optional dimensions> {file} {l} {r} {t} {b}
-%D \stoptyping
-
-\ifx\pdftexversion\undefined \else \ifnum\pdftexversion>13 % still relevant?
-
- \def\pdfimage#1#%
- {\dopdfimage{#1}}
-
- \def\dopdfimage#1#2%
- {\immediate\pdfximage#1{#2}%
- \pdfrefximage\pdflastximage}
-
- \def\pdfimages#1#%
- {\dopdfimages{#1}}
-
- \def\dopdfimages#1#2#3%
- {\immediate\pdfximage#1{#2}%
- \immediate\pdfobj{[ << /Image \the\pdflastximage\space0 R /DefaultForPrinting true >> ]}%
- \immediate\pdfximage#1 attr {/Alternates \the\pdflastobj\space0 R}{#3}%
- \pdfrefximage\pdflastximage}
-
- \def\pdfclippedimage#1#% specs {file}{left}{right}{top}{bottom}
- {\dopdfclippedimage{#1}}
-
- \def\dopdfclippedimage#1#2#3#4#5#6%
- {\bgroup
- \pdfximage#1{#2}%
- \setbox\scratchbox\hbox{\pdfrefximage\pdflastximage}%
- \hsize\dimexpr\wd\scratchbox-#3-#4\relax
- \vsize\dimexpr\ht\scratchbox-#5-#6\relax
- \setbox\scratchbox\vbox to \vsize
- {\vskip-#5\hbox to \hsize{\hskip-#3\box\scratchbox\hss}}%
- \pdfxform\scratchbox
- \pdfrefxform\pdflastxform
- \egroup}
-
-\fi \fi
-
-%D \macros
-%D {convertMPtoPDF}
-%D
-%D The next set of macros implements \METAPOST\ to \PDF\
-%D conversion. The traditional method is in the MkII file.
-
-%D The main conversion command is:
-%D
-%D \starttyping
-%D \convertMPtoPDF {filename} {x scale} {y scale}
-%D \stoptyping
-%D
-%D The dimensions are derived from the bounding box. So we
-%D only have to say:
-%D
-%D \starttyping
-%D \convertMPtoPDF{mp-pra-1.eps}{1}{1}
-%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5}
-%D \stoptyping
-
-%D \macros
-%D {makeMPintoPDFobject,lastPDFMPobject}
-%D
-%D For experts there are a few more options. When attributes
-%D are to be added, the code must be embedded in an object
-%D accompanied with the appropriate directives. One can
-%D influence this process with \type {\makeMPintoPDFobject}.
-%D
-%D This option defaults to~0, because \CONTEXT\ takes care
-%D of objects at another level, which saves some bytes.
-%D
-%D \starttabulate[|l|l|p|]
-%D \NC 0 \NC never \NC don't use an object \NC\NR
-%D \NC 1 \NC always \NC always use an object \NC\NR
-%D \NC 2 \NC optional \NC use object when needed \NC\NR
-%D \stoptabulate
-%D
-%D The last object number used is avaliable in the macro
-%D \type {\lastPDFMPobject}.
-
-\ifx\makeMPintoPDFobject \undefined \chardef\makeMPintoPDFobject \zerocount \fi
-\ifx\blackoutMPgraphic \undefined \chardef\blackoutMPgraphic \plusone \fi
-\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion \fi
-
-\let\lastPDFMPobject \!!zerocount
-\let\currentPDFresources\empty
-\let\setMPextensions \relax
-
-\def\PDFMPformoffset
- {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}
-
-\def\resetMPvariables#1#2#3%
- {\global\let\MPwidth \!!zeropoint
- \global\let\MPheight\!!zeropoint
- \global\let\MPllx \!!zerocount
- \global\let\MPlly \!!zerocount
- \global\let\MPurx \!!zerocount
- \global\let\MPury \!!zerocount
- \xdef\MPxscale {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
- \xdef\MPyscale {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
- \xdef\MPfilename {#1}}
-
-%D The main macro:
-
-\def\convertMPtoPDF#1#2#3%
- {\resetMPvariables{#1}{#2}{#3}%
- \mkconvertMPtoPDF}
-
-\def\processMPtoPDFfile#1#2#3% obsolete
- {\resetMPvariables{#1}{#2}{#3}%
- \mkprocessMPtoPDFfile}
-
-%D A common hook.
-
-\let\MPfshowcommand\empty
-
-%D Objects.
-
-\def\dopackageMPgraphic#1% #1 = boxregister
- {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
- % an existing value of 2 signals object support (set elsewhere)
- \chardef\makeMPintoPDFobject\plusone
- \fi\fi
- \ifcase\makeMPintoPDFobject
- \box#1%
- \or
- \scratchdimen\PDFMPformoffset\relax
- \ifdim\scratchdimen>\zeropoint % compensate for error
- \setbox#1\vbox spread 2\scratchdimen
- {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}%
- \fi
- \setMPPDFobject{\currentPDFresources}{#1}%
- \ifdim\scratchdimen>\zeropoint % compensate for error
- \vbox to \MPheight
- {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}%
- \else
- \getMPPDFobject
- \fi
- \global\let\currentPDFresources\empty
- \else
- \box#1%
- \fi}
-
-\def\setMPPDFobject#1#2% resources boxnumber
- {\ifx\pdfxform\undefined
- \def\getMPPDFobject{\box#2}%
- \else\ifx\pdftexversion\undefined
- \def\getMPPDFobject{\box#2}%
- \else\ifnum\pdftexversion<14
- \def\getMPPDFobject{\box#2}%
- \else
- \ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi
- \immediate\pdfxform resources{#1}#2%
- \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}%
- \fi\fi\fi}
-
-\let\getMPPDFobject\relax
-
-%D \macros
-%D {deleteMPgraphic,
-%D startMPresources,
-%D stopMPresources}
-
-\ifx\deleteMPgraphic\undefined
- \def\deleteMPgraphic#1{}
-\fi
-
-\ifx\startMPresources\undefined
- \let\startMPresources\relax
- \let\stopMPresources\relax
-\fi
-
-%D We implement extensions by using the \METAPOST\ special
-%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
-%D are flushed before or after the graphic data, but thereby
-%D are no longer connected to a position.
-%D
-%D We implement specials by overloading the \type {fill}
-%D operator. By counting the fills, we can let the converter
-%D treat the appropriate fill in a special way. The
-%D specification of the speciality can have two forms,
-%D determined by the setting of a boolean variable:
-%D
-%D \starttyping
-%D _inline_specials_ := false ; % comment like code (default)
-%D _inline_specials_ := true ; % command like code
-%D \stoptyping
-%D
-%D When the specification is embedded as comment, it looks
-%D like:
-%D
-%D \starttyping
-%D %%MetaPostSpecial <size> <data> <number> <identifier>
-%D \stoptyping
-%D
-%D The in||line alternative is more tuned for \POSTSCRIPT,
-%D since it permits us to define a macro \type {special}.
-%D
-%D \starttyping
-%D inline : <data> <number> <identifier> <size> special
-%D \stoptyping
-%D
-%D The \type {identifier} determines what to do, and the data
-%D can be used to accomplish this. A type~2 shading function
-%D has identifier~2. Alltogether, the number of parameters is
-%D specified in \type {size}. The \type {number} is the number
-%D of the fill that needs the special treatment. For a type~2
-%D and~3 shaded fill, the datablock contains the following
-
-%D data:
-%D
-%D \starttyping
-%D from to n inner_r g b x y outer_r g b x y
-%D from to n inner_r g b x y radius outer_r g b x y radius
-%D \stoptyping
-
-\newconditional\manyMPspecials \settrue\manyMPspecials
-
-%D In case of \PDF, we need to prepare resourcs.
-
-\newtoks\MPstartresources
-\newtoks\MPstopresources
-
-\def\startMPresources
- {\the\MPstartresources}
-
-\def\stopMPresources
- {\the\MPstopresources}
-
-%D Some day we may consider collecting local resources.
-
-\appendtoks
- \global\let\currentPDFresources\empty % kind of redundant
-\to \MPstartresources
-
-% \appendtoks
-% \collectPDFresources
-% \global\let\currentPDFresources\collectedPDFresources
-% \to \MPstopresources
-
-\appendtoksonce
- \the\everyPDFxform
-\to \MPstopresources
-
-%D Since colors are not subjected to transformations, we can
-%D only use colors as signal. In our case, we use a dummy colored
-%D path with a red color component of \type {0.n}, so \type
-%D {0.001} is the first path and \type {0.010} the tenth. Since
-%D \METAPOST strips trailing zeros, we have to padd the string.
-
-\newif\ifMPcmykcolors
-\newif\ifMPspotcolors
-
-\def\dohandleMPrgb #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
-\def\dohandleMPcmyk#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
-\def\dohandleMPgray #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
-\def\dohandleMPspot#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
-
-%D Specials:
-
-\settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty
-
-\def\@@MP {@@MP}
-\def\@@MPSK{@MPSK@}
-
-\def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}
-
-\def\defineMPspecial#1#2%
- {\setvalue{\@@MPSK\@@MPSK#1}{#2}}
-
-%D Special number~1 is dedicated to \CMYK\ support. If you
-%D want to know why: look at this:
-%D
-%D \startbuffer[mp]
-%D fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
-%D \stopbuffer
-%D
-%D \startbuffer[cmyk]
-%D \startcombination[4*1]
-%D {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
-%D {\definecolor[test][c=.9,y=.15] \processMPbuffer[mp]} {c=.9 y=.15}
-%D {\definecolor[test][c=.25,y=.8] \processMPbuffer[mp]} {c=.25 y=.8}
-%D {\definecolor[test][c=.45,y=.1] \processMPbuffer[mp]} {c=.45 y=.1}
-%D \stopcombination
-%D \stopbuffer
-%D
-%D \placefigure
-%D {\CMYK\ support disabled,
-%D conversion to \RGB.}
-%D {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
-%D
-%D \placefigure
-%D {\CMYK\ support enabled,
-%D no support in \METAPOST.}
-%D {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
-%D
-%D \placefigure
-%D {\CMYK\ support enabled,
-%D no conversion to \RGB,
-%D support in \METAPOST}
-%D {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}
-
-\defineMPspecial{1}
- {\ifMPcmykcolors
- \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPcmykcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
- \fi}
-
-\defineMPspecial{2}
- {\ifMPspotcolors
- \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPspotcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
-% \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}%
- \fi}
-
-% \def\checkMPspot#1#2#3#4%
-% {\expanded{\resolveMPspotcolor#1 #2 #3 #4}\end
-% \ifx\MPspotspace\MPresolvedspace
-% \edef\MPspotspacespec{/\MPspotspace\space}%
-% \doifinstringelse\MPspotspacespec\currentMPcolorspaces
-% \donothing\registerMPcolorspace
-% \fi}
-
-\let\revokeMPtransparencyspecial\relax
-
-\def\dohandleMPrgbcolor #1#2#3{\revokeMPtransparencyspecial\execcolorR #1:#2:#3:0:0\od}
-\def\dohandleMPcmykcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
-\def\dohandleMPgraycolor #1{\revokeMPtransparencyspecial\execcolorS #1:0:0\od}
-\def\dohandleMPspotcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}
-
-%D Transparency support used specials 60 (rgb) and 61
-%D (cmyk).
-%D
-%D \startbufferFshade
-
-%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
-%D
-%D fill p rotated 90 withcolor transparent(1,.5,yellow) ;
-%D fill p rotated 210 withcolor transparent(1,.5,green) ;
-%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection \processMPbuffer \stoplinecorrection
-%D
-%D One can also communicate colors between \CONTEXT\ and
-%D \METAPOST:
-%D
-%D \startbuffer
-%D \definecolor[tcyan] [c=1,k=.2,t=.5]
-%D \definecolor[tmagenta][m=1,k=.2,t=.5]
-%D \definecolor[tyellow] [y=1,k=.2,t=.5]
-%D \stopbuffer
-%D
-%D \typebuffer \getbuffer
-%D
-%D \startbuffer
-%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
-%D
-%D fill p rotated 90 withcolor \MPcolor{tcyan} ;
-%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
-%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
-%D \stopbuffer
-%D
-%D \startlinecorrection \processMPbuffer \stoplinecorrection
-%D
-%D We save all the three components needed in one macro,
-%D just to save hash space.
-
-\def\dohandleMPrgbtransparency #1#2#3#4#5{\execcolorR #1:#2:#3:#4:#5\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
-\def\dohandleMPcmyktransparency#1#2#3#4#5#6{\execcolorC#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
-\def\dohandleMPgraytransparency #1#2#3{\execcolorS #1:#2:#3\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
-\def\dohandleMPspottransparency#1#2#3#4#5#6{\execcolorP#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
-
-\def\dorevokeMPtransparencyspecial
- {\PDFcode{\PDFtransparencyresetidentifier\space gs}%
- \let\revokeMPtransparencyspecial\relax}
-
-\defineMPspecial{3} % rgb
- {\setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPrgbtransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs1}{\gMPs2}}}
-
-\defineMPspecial{4} % cmyk
- {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPcmyktransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}}
-
-\defineMPspecial{5} % spot
- {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPspottransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}%
- }%\checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}
-
-%D Shading is an example of a more advanced graphic feature,
-%D but users will seldom encounter those complications. Here
-%D we only show a few simple examples, but many other
-%D alternatives are possible by setting up the functions built
-%D in \PDF\ in the appropriate way.
-%D
-%D Shading has to do with interpolation between two or more
-%D points or user supplied ranges. In \PDF, the specifications
-%D of a shade has to be encapsulated in objects and passed on
-%D as resources. This is a \PDF\ level 1.3. feature. One can
-%D simulate three dimensional shades as well and define simple
-%D functions using a limited set of \POSTSCRIPT\ primitives.
-%D Given the power of \METAPOST\ and these \PDF\ features, we
-%D can achieve superb graphic effects.
-%D
-%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
-%D we can stick to high level \CONTEXT\ command, as shown in
-%D the following exmples.
-%D
-%D \startbuffer
-%D \startuniqueMPgraphic{CircularShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
-%D circular_shade(p,0,.2red,.9red) ;
-%D \stopuniqueMPgraphic
-%D
-%D \startuniqueMPgraphic{LinearShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
-%D linear_shade(p,0,.2blue,.9blue) ;
-%D \stopuniqueMPgraphic
-%D
-%D \startuniqueMPgraphic{DuotoneShade}
-%D path p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
-%D linear_shade(p,2,.5green,.5red) ;
-%D \stopuniqueMPgraphic
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D These graphics can be hooked into the overlay mechanism,
-%D which is available in many commands.
-%D
-%D \startbuffer
-%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
-%D \defineoverlay[demo 2][\uniqueMPgraphic {LinearShade}]
-%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \getbuffer
-%D
-%D These backgrounds can for instance be applied to \type
-%D {\framed}:
-%D
-%D \startbuffer
-%D \setupframed[width=3cm,height=2cm,frame=off]
-%D \startcombination[3*1]
-%D {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
-%D {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
-%D {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
-%D \stopcombination
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D \startlinecorrection
-%D \getbuffer
-%D \stoplinecorrection
-%D
-%D There are a few more alternatives, determined by the second
-%D parameter passed to \type {circular_shade} and alike.
-%D
-%D \def\SomeShade#1#2#3#4#5%
-%D {\startuniqueMPgraphic{Shade-#1}
-%D width := \overlaywidth ;
-%D height := \overlayheight ;
-%D path p ; p := unitsquare xscaled width yscaled height ;
-%D #2_shade(p,#3,#4,#5) ;
-%D \stopuniqueMPgraphic
-%D \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
-%D \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
-%D
-%D \startlinecorrection
-%D \startcombination[5*1]
-%D {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
-%D {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
-%D {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
-%D {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
-%D {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
-%D \stopcombination
-%D \stoplinecorrection
-%D
-%D \blank
-%D
-%D \startlinecorrection
-%D \startcombination[5*1]
-%D {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
-%D {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
-%D {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
-%D {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
-%D {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
-%D \stopcombination
-%D \stoplinecorrection
-%D
-%D \blank
-%D
-%D \startlinecorrection
-%D \startcombination[4*1]
-%D {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
-%D {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
-%D {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
-%D {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
-%D \stopcombination
-%D \stoplinecorrection
-%D
-%D These macros closely cooperate with the \METAPOST\ module
-%D \type {mp-spec.mp}, which is part of the \CONTEXT\
-%D distribution.
-%D
-%D The low level (\PDF) implementation is based on the \TEX\
-%D based \METAPOST\ to \PDF\ converter. Shading is supported
-%D by overloading the \type {fill} operator as implemented
-%D earlier. In \PDF\ type~2 and~3 shading functions are
-%D specified in terms of:
-%D
-%D \starttabulate[|Tl|l|]
-%D \NC /Domain \NC sort of meeting range \NC \NR
-%D \NC /C0 \NC inner shade \NC \NR
-%D \NC /C1 \NC outer shade \NC \NR
-%D \NC /N \NC smaller values, bigger inner circles \NC \NR
-%D \stoptabulate
-
-\newcount\currentPDFshade % 0 % global (document wide) counter
-
-% \def\dosetMPsomePDFshade#1#2% generic but needs refs
-% {\global\advance\currentPDFshade \plusone
-% \doPDFdictionaryobject{FDF}{ftn:Sh:\the\currentPDFshade}
-% {/FunctionType 2
-% /Domain [\gMPs1 \gMPs2]
-% /C0 [\MPshadeA]
-% /C1 [\MPshadeB]
-% /N \gMPs3}%
-% \doPDFgetobjectreference{FDF}{ftn:Sh:\the\currentPDFshade}\PDFobjectreference
-% \doPDFdictionaryobject{FDF}{obj:Sh:\the\currentPDFshade}
-% {/ShadingType #1
-% /ColorSpace /\MPresolvedspace
-% /Function \PDFobjectreference\space
-% /Coords [\MPshadeC]
-% /Extend [true true]}%
-% \doPDFgetobjectreference{FDF}{obj:Sh:\the\currentPDFshade}\PDFobjectreference
-% \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\PDFobjectreference}%
-% \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
-
-\def\dosetMPsomePDFshade#1#2%
- {\immediate\pdfobj
- {<</FunctionType 2
- /Domain [\gMPs1 \gMPs2]
- /C0 [\MPshadeA]
- /C1 [\MPshadeB]
- /N \gMPs3>>}%
- \immediate\pdfobj
- {<</ShadingType #1
- /ColorSpace /\MPresolvedspace
- /Function \the\pdflastobj\space 0 R
- /Coords [\MPshadeC]
- /Extend [true true]>>}%
- \global\advance\currentPDFshade \plusone
- \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
- \setxvalue{\@@MPSK#2}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}
-
-\def\dosetMPlinearshade {\dosetMPsomePDFshade2}% #1
-\def\dosetMPcircularshade{\dosetMPsomePDFshade3}% #1
-
-\defineMPspecial{30}
- {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
- \expanded{\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
- \dosetMPlinearshade{\gMPs{14}}}
-
-\defineMPspecial{31}
- {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
- \expanded{\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
- \dosetMPcircularshade{\gMPs{16}}}
-
-\defineMPspecial{32}
- {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
- \expanded{\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
- \dosetMPlinearshade{\gMPs{16}}}
-
-\defineMPspecial{33}
- {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
- \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
- \dosetMPcircularshade{\gMPs{18}}}
-
-\defineMPspecial{34}
- {\expanded{\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
- \expanded{\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
- \dosetMPlinearshade{\gMPs{16}}}
-
-\defineMPspecial{35}
- {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
- \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
- \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
- \dosetMPcircularshade{\gMPs{18}}}
-
-
-\newconditional\ignoreMPpath
-
-\def\dohandleMPshade#1%
- {\revokeMPtransparencyspecial
- \settrue\ignoreMPpath
- \def\extraMPpathcode{/Sh#1 sh Q}%
- \chardef\finiMPpath\zerocount
- \PDFcode{q /Pattern cs}}
-
-%D Figure inclusion is kind of strange to \METAPOST, but when
-%D Santiago Muelas started discussing this with me, I was able
-%D to cook up a solution using specials.
-
-\defineMPspecial{10}
- {\setxvalue{\@@MPSK\gMPs8}%
- {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}
-
-\def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
- {\global\letvalue{\@@MPSK#8}\empty
- \vbox to \zeropoint
- {\vss
- \hbox to \zeropoint
- {\ifcase\pdfoutput\or % will be hooked into the special driver
- \doiffileelse{#7}
- {\doifundefinedelse{mps:x:#7}
- {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
- \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
- {\message{[reusing figure #7]}}%
- \PDFcode{q #1 #2 #3 #4 #5 #6 cm}%
- \rlap{\getvalue{mps:x:#7}}%
- \PDFcode{Q}}
- {\message{[unknown figure #7]}}%
- \fi
- \hss}}}
-
-%D An example of using both special features is the
-%D following.
-%D
-%D \starttyping
-%D \startMPpage
-%D externalfigure "hakker1b.png" scaled 22cm rotated 10 shifted (-2cm,0cm);
-%D externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
-%D externalfigure "hakker1b.png" scaled 7cm rotated 45 shifted (8cm,12cm) ;
-%D path p ; p := unitcircle xscaled 15cm yscaled 20cm;
-%D path q ; q := p rotatedaround(center p,90) ;
-%D path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
-%D path s ; s := boundingbox currentpicture enlarged 5mm ;
-%D picture c ; c := currentpicture ; currentpicture := nullpicture ;
-%D circular_shade(s,0,.2red,.9red) ;
-%D addto currentpicture also c ;
-%D \stopMPpage
-%D \stoptyping
-
-%D This is some experimental hyperlink driver that I wrote
-%D for Mark Wicks.
-
-\defineMPspecial{20}
- {\setxvalue{\@@MPSK\gMPs6}%
- {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}
-
-\def\handleMPhyperlink#1#2#3#4#5#6%
- {\global\letvalue{\@@MPSK#6}\empty
- \setbox\scratchbox\hbox
- {\setbox\scratchbox\null
- \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
- \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
- \incolorfalse
- \gotobox{\box\scratchbox}[#5]}%
- \setbox\scratchbox\hbox
- {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
- \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
- \box\scratchbox}%
- \smashbox\scratchbox
- \box\scratchbox}
-
-%D This special (number 50) passes positions to a tex file.
-%D This method uses a two||pass approach an (mis|)|used the
-%D context positioning macros. In \type {core-pos} we will
-%D implement the low level submacro needed.
-%D
-%D \startbuffer
-%D \definelayer[test]
-%D
-%D \setlayer
-%D [test]
-%D [x=\MPx{somepos-1},y=\MPy{somepos-1}]
-%D {Whatever we want here!}
-%D
-%D \setlayer
-%D [test]
-%D [x=\MPx{somepos-2},y=\MPy{somepos-2}]
-%D {Whatever we need there!}
-%D
-%D \startuseMPgraphic{oeps}
-%D draw fullcircle scaled 6cm withcolor red ;
-%D register ("somepos-1",1cm,2cm,center currentpicture) ;
-%D register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
-%D \stopuseMPgraphic
-%D
-%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
-%D \stopbuffer
-%D
-%D \typebuffer
-%D
-%D Here the width and height are not realy used, but one can
-%D imagine situations where tex has to work with values
-%D calculated by \METAPOST.
-%D
-%D \startlinecorrection
-%D \getbuffer
-%D \stoplinecorrection
-%D
-%D Later we will implement a more convenient macro:
-%D
-%D \starttyping
-%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
-%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
-%D \stoptyping
-
-\defineMPspecial{50} % x y width height label
- {\dosavepositionwhd
- {\gMPs5}%
- {0}%
- {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
- {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}%
- {\the\dimexpr\gMPs3\onebasepoint\relax}%
- {\the\dimexpr\gMPs4\onebasepoint\relax}%
- {0pt}}
-
-%D A few auxiliary macros. This will move to colo-ini.
-
-\def\MPgrayspace{DeviceGray}
-\def\MPrgbspace {DeviceRGB}
-\def\MPcmykspace{DeviceCMYK}
-\let\MPspotspace\MPgrayspace
-
-\def\MPcmykBlack{0 0 0 0}
-\def\MPcmykWhite{0 0 0 1}
-
-\def\startMPcolorresolve
- {\bgroup
- \def\dostartgraycolormode##1%
- {\global\let\MPresolvedspace\MPgrayspace
- \xdef\MPresolvedcolor{##1}}%
- \def\dostartrgbcolormode ##1##2##3%
- {\global\let\MPresolvedspace\MPrgbspace
- \xdef\MPresolvedcolor{##1 ##2 ##3}}%
- \def\dostartcmykcolormode##1##2##3##4%
- {\global\let\MPresolvedspace\MPcmykspace
- \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}%
- \def\dostartspotcolormode##1##2%
- {\global\let\MPspotspace\empty % left over ?
- \xdef\MPresolvedspace{##1}%
- \xdef\MPresolvedcolor{##2}%
- \global\let\MPspotspace\MPresolvedspace}% signal
- \dostartgraycolormode\!!zerocount} % kind of hackery initialization
-
-\let\stopMPcolorresolve\egroup
-
-\def\resolveMPrgbcolor#1#2#3\to#4%
- {\startMPcolorresolve
- \execcolorR#1:#2:#3:0:0\od
- \stopMPcolorresolve
- \let#4\MPresolvedcolor}
-
-\def\resolveMPcmykcolor#1#2#3#4\to#5%
- {\startMPcolorresolve
- \execcolorC#1:#2:#3:#4:0:0\od
- \stopMPcolorresolve
- \let#5\MPresolvedcolor}
-
-\def\resolveMPgraycolor#1\end\to#2%
- {\startMPcolorresolve
- \execcolorS#1:0:0\od
- \stopMPcolorresolve
- \let#2\MPresolvedcolor}
-
-\def\resolveMPspotcolor#1#2#3#4\end\to#5%
- {\startMPcolorresolve
- \ifnum#2>\plusone
- \checkmultitonecolor{#1}%
- \fi
- \execcolorP#1:#2:#3:#4:0:0\od
- \stopMPcolorresolve
- \let#5\MPresolvedcolor}
-
-%D \macros
-%D {dogetPDFmediabox}
-%D
-%D The next macro can be used to find the mediabox of a \PDF\
-%D illustration.
-%D
-%D \starttyping
-%D \dogetPDFmediabox
-%D {filename}
-%D {new dimen}{new dimen}{new dimen}{new dimen}
-%D \stoptyping
-%D
-%D Beware of dimen clashes: this macro uses the 5~default
-%D scratch registers! When no file or mediabox is found, the
-%D dimensions are zeroed.
-
-\def\dogetPDFmediabox#1#2#3#4#5%
- {\bgroup
- \def\PDFxscale{1}%
- \def\PDFyscale{1}%
- \uncatcodespecials
- \endlinechar\minusone
- \def\checkPDFtypepage##1/Type /Page##2##3\done%
- {\ifx##2\relax
- \else\if##2s% accept /Page and /Pages
- \let\doprocessPDFline\findPDFmediabox
- \else
- \let\doprocessPDFline\findPDFmediabox
- \fi\fi}%
- \def\findPDFtypepage
- {\expandafter\checkPDFtypepage\fileline/Type /Page\relax\done}%
- \def\checkPDFmediabox##1/MediaBox##2##3\done%
- {\ifx##2\relax \else
- \setPDFmediabox##2##3\done
- \fileprocessedtrue
- \fi}%
- \def\findPDFmediabox
- {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}%
- \let\doprocessPDFline\findPDFtypepage
- \doprocessfile\scratchread{#1}\doprocessPDFline
- \egroup
- \ifx\PDFxoffset\undefined
- #2=\zeropoint
- #3=\zeropoint
- #4=\zeropoint
- #5=\zeropoint
- \else
- #2=\PDFxoffset\onebasepoint
- #3=\PDFyoffset\onebasepoint
- #4=\PDFwidth
- #5=\PDFheight
- \fi}
-
-\def\setPDFboundingbox#1#2#3#4#5#6%
- {\dimen0=#1\dimen0=#5\dimen0
- \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset
- \dimen0=#3\dimen0=#5\dimen0
- \xdef\PDFwidth{\the\dimen0}%
- \dimen0=#2\dimen0=#6\dimen0
- \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset
- \dimen0=#4\dimen0=#6\dimen0
- \xdef\PDFheight{\the\dimen0}%
- \global\let\PDFxoffset\PDFxoffset
- \global\let\PDFyoffset\PDFyoffset}
-
-\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done
- {\dimen2=#2\onebasepoint\dimen2=-\dimen2 % \dimen2=-#2\onebasepoint also works since tex handles --
- \dimen4=#3\onebasepoint\dimen4=-\dimen4 % \dimen4=-#3\onebasepoint also works since tex handles --
- \dimen6=#4\onebasepoint\advance\dimen6 \dimen2
- \dimen8=#5\onebasepoint\advance\dimen8 \dimen4
- \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale}
-
-%D End of soon obsolete code.
-
-%D The plugins:
-
-\startMPinitializations
- mp_shade_version := 2 ;
-\stopMPinitializations
-
-\loadmarkfile{meta-pdf}
-
-%D Test code:
-
-% \startMPcode
-% fill fullcircle scaled 3cm withcolor red ;
-% fill fullcircle scaled 2cm withcolor green ;
-% fill fullcircle scaled 1cm withcolor blue ;
-% currentpicture := currentpicture shifted (-4cm,0) ;
-% fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
-% fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
-% fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ;
-% currentpicture := currentpicture shifted (-4cm,0) ;
-% draw fullcircle scaled 3cm dashed evenly ;
-% draw fullcircle scaled 2cm dashed withdots ;
-% draw origin withpen pencircle scaled 3mm;
-% currentpicture := currentpicture shifted (-4cm,0) ;
-% fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
-% fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
-% fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
-% fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
-% currentpicture := currentpicture shifted (12cm,-4cm) ;
-% draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
-% currentpicture := currentpicture shifted (-4cm,0) ;
-% % bug: shift
-% draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30 ;
-% draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
-% filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
-% currentpicture := currentpicture shifted (-4cm,0) ;
-% % shade cannot handle shift
-% circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
-% circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
-% filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ;
-% \stopMPcode
-
-% This code will move to meta-pdf.mkiv and the call to lua will move to the
-% converter code (saves a lua call). We will do this when we made the final
-% move to attribute bases color. Actually, we cannot use attributes for
-% switching colors in mp literals because grouping (qQ) interferes.
-
-\ifx\colorversion\undefined \else \ifnum\colorversion>\plusone
-
- \def\dohandleMPgraycolor #1{\ctxlua{ctx.pdffinishtransparency()
- ctx.pdfgrayliteral(\the\currentcolormodel,#1)}}
- \def\dohandleMPrgbcolor #1#2#3{\ctxlua{ctx.pdffinishtransparency()
- ctx.pdfrgbliteral (\the\currentcolormodel,#1,#2,#3)}}
- \def\dohandleMPcmykcolor#1#2#3#4{\ctxlua{ctx.pdffinishtransparency()
- ctx.pdfcmykliteral(\the\currentcolormodel,#1,#2,#3,#4)}}
- \def\dohandleMPspotcolor#1#2#3#4{\ctxlua{ctx.pdffinishtransparency()
- ctx.pdfspotliteral(\the\currentcolormodel,"#1",#2,"#3","#4")}}
-
- % we can combine the next calls
-
- \def\dohandleMPgraytransparency #1#2#3{\ctxlua{ctx.pdfgrayliteral(\the\currentcolormodel,#1)
- ctx.pdftransparencyliteral(#2,#3)}}
- \def\dohandleMPrgbtransparency #1#2#3#4#5{\ctxlua{ctx.pdfrgbliteral (\the\currentcolormodel,#1,#2,#3)
- ctx.pdftransparencyliteral(#4,#5)}}
- \def\dohandleMPcmyktransparency#1#2#3#4#5#6{\ctxlua{ctx.pdfcmykliteral(\the\currentcolormodel,#1,#2,#3,#4)
- ctx.pdftransparencyliteral(#5,#6)}}
- \def\dohandleMPspottransparency#1#2#3#4#5#6{\ctxlua{ctx.pdfspotliteral(\the\currentcolormodel,"#1",#2,"#3","#4")
- ctx.pdftransparencyliteral(#5,#6)}}
-
- \def\dohandleMPresettransparency {\ctxlua{ctx.pdffinishtransparency()}}
-
- \def\resolveMPgraycolor #1\to#2{\ctxlua{ctx.resolvempgraycolor("\strippedcsname#2","MPresolvedspace",\number\currentcolormodel,#1)}}
- \def\resolveMPrgbcolor #1#2#3\to#4{\ctxlua{ctx.resolvemprgbcolor ("\strippedcsname#4","MPresolvedspace",\number\currentcolormodel,#1,#2,#3)}}
- \def\resolveMPcmykcolor#1#2#3#4\to#5{\ctxlua{ctx.resolvempcmykcolor("\strippedcsname#5","MPresolvedspace",\number\currentcolormodel,#1,#2,#3,#4)}}
-
- \def\resolveMPspotcolor#1#2#3#4\to#5% unchecked
- {\ctxlua{ctx.resolvempspotcolor("\strippedcsname#5","MPresolvedspace",\number\currentcolormodel,"#1",#2,"#3","#4")}%
- \xdef\MPresolvedspace{#1}%
- \xdef\MPresolvedcolor{#4}%
- \global\let\MPspotspace\MPresolvedspace}
-
- % used as callers
-
- \let\MPSgray\dohandleMPgraycolor
- \let\MPSrgb \dohandleMPrgbcolor
- \let\MPScmyk\dohandleMPcmykcolor
- \let\MPspot \dohandleMPspotcolor
-
-\fi \fi
-
-\protect \endinput
diff --git a/tex/context/base/meta-pdh.lua b/tex/context/base/meta-pdh.lua
new file mode 100644
index 000000000..e05529cc8
--- /dev/null
+++ b/tex/context/base/meta-pdh.lua
@@ -0,0 +1,630 @@
+if not modules then modules = { } end modules ['meta-pdf'] = {
+ version = 1.001,
+ comment = "companion to meta-pdf.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This file contains the history of the converter. We keep it around as it
+-- relates to the development of luatex.
+
+-- This is the third version. Version 1 converted to Lua code,
+-- version 2 gsubbed the file into TeX code, and version 3 uses
+-- the new lpeg functionality and streams the result into TeX.
+
+-- We will move old stuff to edu.
+
+--~ old lpeg 0.4 lpeg 0.5
+--~ 100 times test graphic 2.45 (T:1.07) 0.72 (T:0.24) 0.580 (0.560 no table) -- 0.54 optimized for one space (T:0.19)
+--~ 100 times big graphic 10.44 4.30/3.35 nogb 2.914 (2.050 no table) -- 1.99 optimized for one space (T:0.85)
+--~ 500 times test graphic T:1.29 T:1.16 (T:1.10 no table) -- T:1.10
+
+-- only needed for mp output on disk
+
+local concat, format = table.concat, string.format
+
+local ctxcatcodes = tex.ctxcatcodes
+
+mptopdf = { }
+mptopdf.parsers = { }
+mptopdf.parser = 'none'
+mptopdf.n = 0
+
+function mptopdf.reset()
+ mptopdf.data = ""
+ mptopdf.path = { }
+ mptopdf.stack = { }
+ mptopdf.texts = { }
+ mptopdf.version = 0
+ mptopdf.shortcuts = false
+ mptopdf.resetpath()
+end
+
+function mptopdf.resetpath()
+ mptopdf.stack.close = false
+ mptopdf.stack.path = { }
+ mptopdf.stack.concat = nil
+ mptopdf.stack.special = false
+end
+
+mptopdf.reset()
+
+function mptopdf.parsers.none()
+ -- no parser set
+end
+
+function mptopdf.parse()
+ mptopdf.parsers[mptopdf.parser]()
+end
+
+-- old code
+
+mptopdf.steps = { }
+
+mptopdf.descapes = {
+ ['('] = "\\\\char40 ",
+ [')'] = "\\\\char41 ",
+ ['"'] = "\\\\char92 "
+}
+
+function mptopdf.descape(str)
+ str = str:gsub("\\(%d%d%d)",function(n)
+ return "\\char" .. tonumber(n,8) .. " "
+ end)
+ return str:gsub("\\([%(%)\\])",mptopdf.descapes)
+end
+
+function mptopdf.steps.descape(str)
+ str = str:gsub("\\(%d%d%d)",function(n)
+ return "\\\\char" .. tonumber(n,8) .. " "
+ end)
+ return str:gsub("\\([%(%)\\])",mptopdf.descapes)
+end
+
+function mptopdf.steps.strip() -- .3 per expr
+ mptopdf.data = mptopdf.data:gsub("^(.-)%%+Page:.-%c+(.*)%s+%a+%s+%%+EOF.*$", function(preamble, graphic)
+ local bbox = "0 0 0 0"
+ for b in preamble:gmatch("%%%%%a+oundingBox: +(.-)%c+") do
+ bbox = b
+ end
+ local name, version = preamble:gmatch("%%%%Creator: +(.-) +(.-) ")
+ mptopdf.version = tostring(version or "0")
+ if preamble:find("/hlw{0 dtransform") then
+ mptopdf.shortcuts = true
+ end
+ -- the boundingbox specification needs to come before data, well, not really
+ return bbox .. " boundingbox\n" .. "\nbegindata\n" .. graphic .. "\nenddata\n"
+ end, 1)
+ mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecials: +(.-)%c+", "%1 specials\n", 1)
+ mptopdf.data = mptopdf.data:gsub("%%%%MetaPostSpecial: +(.-)%c+", "%1 special\n")
+ mptopdf.data = mptopdf.data:gsub("%%.-%c+", "")
+end
+
+function mptopdf.steps.cleanup()
+ if not mptopdf.shortcuts then
+ mptopdf.data = mptopdf.data:gsub("gsave%s+fill%s+grestore%s+stroke", "both")
+ mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+exch%s+truncate%s+exch%s+idtransform%s+pop%s+setlinewidth", function(wx,wy)
+ if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
+ end)
+ mptopdf.data = mptopdf.data:gsub("([%d%.]+)%s+([%d%.]+)%s+dtransform%s+truncate%s+idtransform%s+setlinewidth%s+pop", function(wx,wy)
+ if tonumber(wx) > 0 then return wx .. " setlinewidth" else return wy .. " setlinewidth" end
+ end)
+ end
+end
+
+function mptopdf.steps.convert()
+ mptopdf.data = mptopdf.data:gsub("%c%((.-)%) (.-) (.-) fshow", function(str,font,scale)
+ mptopdf.texts[mptopdf.texts+1] = {mptopdf.steps.descape(str), font, scale}
+ return "\n" .. #mptopdf.texts .. " textext"
+ end)
+ mptopdf.data = mptopdf.data:gsub("%[%s*(.-)%s*%]", function(str)
+ return str:gsub("%s+"," ")
+ end)
+ local t
+ mptopdf.data = mptopdf.data:gsub("%s*([^%a]-)%s*(%a+)", function(args,cmd)
+ if cmd == "textext" then
+ t = mptopdf.texts[tonumber(args)]
+ return "mps.textext(" .. "\"" .. t[2] .. "\"," .. t[3] .. ",\"" .. t[1] .. "\")\n"
+ else
+ return "mps." .. cmd .. "(" .. args:gsub(" +",",") .. ")\n"
+ end
+ end)
+end
+
+function mptopdf.steps.process()
+ assert(loadstring(mptopdf.data))() -- () runs the loaded chunk
+end
+
+function mptopdf.parsers.gsub()
+ mptopdf.steps.strip()
+ mptopdf.steps.cleanup()
+ mptopdf.steps.convert()
+ mptopdf.steps.process()
+end
+
+-- end of old code
+
+-- from lua to tex
+
+function mptopdf.pdfcode(str)
+ tex.sprint(ctxcatcodes,"\\PDFcode{" .. str .. "}") -- \\MPScode
+end
+
+function mptopdf.texcode(str)
+ tex.sprint(ctxcatcodes,str)
+end
+
+-- auxiliary functions
+
+function mptopdf.flushconcat()
+ if mptopdf.stack.concat then
+ mptopdf.pdfcode(concat(mptopdf.stack.concat," ") .. " cm")
+ mptopdf.stack.concat = nil
+ end
+end
+
+function mptopdf.flushpath(cmd)
+ -- faster: no local function and ipairs
+ if #mptopdf.stack.path > 0 then
+ local path = { }
+ if mptopdf.stack.concat then
+ local sx, sy = mptopdf.stack.concat[1], mptopdf.stack.concat[4]
+ local rx, ry = mptopdf.stack.concat[2], mptopdf.stack.concat[3]
+ local tx, ty = mptopdf.stack.concat[5], mptopdf.stack.concat[6]
+ local d = (sx*sy) - (rx*ry)
+ local function mpconcat(px, py)
+ return (sy*(px-tx)-ry*(py-ty))/d, (sx*(py-ty)-rx*(px-tx))/d
+ end
+ local stackpath = mptopdf.stack.path
+ for k=1,#stackpath do
+ local v = stackpath[k]
+ v[1],v[2] = mpconcat(v[1],v[2])
+ if #v == 7 then
+ v[3],v[4] = mpconcat(v[3],v[4])
+ v[5],v[6] = mpconcat(v[5],v[6])
+ end
+ path[#path+1] = concat(v," ")
+ end
+ else
+ local stackpath = mptopdf.stack.path
+ for k=1,#stackpath do
+ path[#path+1] = concat(stackpath[k]," ")
+ end
+ end
+ mptopdf.flushconcat()
+ mptopdf.texcode("\\MPSpath{" .. concat(path," ") .. "}")
+ if mptopdf.stack.close then
+ mptopdf.texcode("\\MPScode{h " .. cmd .. "}")
+ else
+ mptopdf.texcode("\\MPScode{" .. cmd .."}")
+ end
+ end
+ mptopdf.resetpath()
+end
+
+function mptopdf.loaded(name)
+ local ok, n
+ mptopdf.reset()
+ ok, mptopdf.data, n = resolvers.loadbinfile(name, 'tex') -- we need a binary load !
+ return ok
+end
+
+if not mptopdf.parse then
+ function mptopdf.parse() end -- forward declaration
+end
+
+function mptopdf.convertmpstopdf(name)
+ if mptopdf.loaded(name) then
+ mptopdf.n = mptopdf.n + 1
+ statistics.starttiming(mptopdf)
+ mptopdf.parse()
+ mptopdf.reset()
+ statistics.stoptiming(mptopdf)
+ else
+ tex.print("file " .. name .. " not found")
+ end
+end
+
+-- mp interface
+
+mps = mps or { }
+
+function mps.creator(a, b, c)
+ mptopdf.version = tonumber(b)
+end
+
+function mps.creationdate(a)
+ mptopdf.date= a
+end
+
+function mps.newpath()
+ mptopdf.stack.path = { }
+end
+
+function mps.boundingbox(llx, lly, urx, ury)
+ mptopdf.texcode("\\MPSboundingbox{" .. llx .. "}{" .. lly .. "}{" .. urx .. "}{" .. ury .. "}")
+end
+
+function mps.moveto(x,y)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"m"}
+end
+
+function mps.curveto(ax, ay, bx, by, cx, cy)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {ax,ay,bx,by,cx,cy,"c"}
+end
+
+function mps.lineto(x,y)
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {x,y,"l"}
+end
+
+function mps.rlineto(x,y)
+ local dx, dy = 0, 0
+ if #mptopdf.stack.path > 0 then
+ dx, dy = mptopdf.stack.path[#mptopdf.stack.path][1], mptopdf.stack.path[#mptopdf.stack.path][2]
+ end
+ mptopdf.stack.path[#mptopdf.stack.path+1] = {dx,dy,"l"}
+end
+
+function mps.translate(tx,ty)
+ mptopdf.pdfcode("1 0 0 0 1 " .. tx .. " " .. ty .. " cm")
+end
+
+function mps.scale(sx,sy)
+ mptopdf.stack.concat = {sx,0,0,sy,0,0}
+end
+
+function mps.concat(sx, rx, ry, sy, tx, ty)
+ mptopdf.stack.concat = {sx,rx,ry,sy,tx,ty}
+end
+
+function mps.setlinejoin(d)
+ mptopdf.pdfcode(d .. " j")
+end
+
+function mps.setlinecap(d)
+ mptopdf.pdfcode(d .. " J")
+end
+
+function mps.setmiterlimit(d)
+ mptopdf.pdfcode(d .. " M")
+end
+
+function mps.gsave()
+ mptopdf.pdfcode("q")
+end
+
+function mps.grestore()
+ mptopdf.pdfcode("Q")
+end
+
+function mps.setdash(...)
+ local n = select("#",...)
+ mptopdf.pdfcode("[" .. concat({...}," ",1,n-1) .. "] " .. select(n,...) .. " d")
+end
+
+function mps.resetdash()
+ mptopdf.pdfcode("[ ] 0 d")
+end
+
+function mps.setlinewidth(d)
+ mptopdf.pdfcode(d .. " w")
+end
+
+function mps.closepath()
+ mptopdf.stack.close = true
+end
+
+function mps.fill()
+ mptopdf.flushpath('f')
+end
+
+function mps.stroke()
+ mptopdf.flushpath('S')
+end
+
+function mps.both()
+ mptopdf.flushpath('B')
+end
+
+function mps.clip()
+ mptopdf.flushpath('W n')
+end
+
+function mps.textext(font, scale, str) -- old parser
+ local dx, dy = 0, 0
+ if #mptopdf.stack.path > 0 then
+ dx, dy = mptopdf.stack.path[1][1], mptopdf.stack.path[1][2]
+ end
+ mptopdf.flushconcat()
+ mptopdf.texcode("\\MPStextext{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+ mptopdf.resetpath()
+end
+
+--~ function mps.handletext(font,scale.str,dx,dy)
+--~ local one, two = string.match(str, "^(%d+)::::(%d+)")
+--~ if one and two then
+--~ mptopdf.texcode("\\MPTOPDFtextext{"..font.."}{"..scale.."}{"..one.."}{"..two.."}{"..dx.."}{"..dy.."}")
+--~ else
+--~ mptopdf.texcode("\\MPTOPDFtexcode{"..font.."}{"..scale.."}{"..str.."}{"..dx.."}{"..dy.."}")
+--~ end
+--~ end
+
+if false and ctx and ctx.aux and ctx.aux.definecolor then
+
+ logs.report("mptopdf", "using attribute based mps colors")
+
+ -- does not work due to Q-q mess-up
+
+ function mps.setrgbcolor(r,g,b) -- extra check
+ r, g, b = tonumber(r), tonumber(g), tonumber(b) -- needed when we use lpeg
+ if r == 0.0123 and g < 0.1 then -- g is extra check
+ mptopdf.texcode("\\doresetattribute{transparency}\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
+ elseif r == 0.123 and g < 0.1 then -- g is extra check
+ mptopdf.texcode("\\doresetattribute{transparency}\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
+ else
+ mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'rgb',r,g,b) .. "}")
+ end
+ end
+
+ function mps.setcmykcolor(c,m,y,k)
+ mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'cmyk',tonumber(c),tonumber(m),tonumber(y),tonumber(k)) .. "}")
+ end
+
+ function mps.setgray(s)
+ mptopdf.texcode("\\doresetattribute{transparency}\\dosetattribute{color}{" .. colors.register('color',nil,'gray',tonumber(s)) .. "}")
+ end
+
+else
+
+ function mps.setrgbcolor(r,g,b) -- extra check
+ r, g = tonumber(r), tonumber(g) -- needed when we use lpeg
+ if r == 0.0123 and g < 0.1 then
+ mptopdf.texcode("\\MPSspecial{" .. g*10000 .. "}{" .. b*10000 .. "}")
+ elseif r == 0.123 and g < 0.1 then
+ mptopdf.texcode("\\MPSspecial{" .. g* 1000 .. "}{" .. b* 1000 .. "}")
+ else
+ mptopdf.texcode("\\MPSrgb{" .. r .. "}{" .. g .. "}{" .. b .. "}")
+ end
+ end
+
+ function mps.setcmykcolor(c,m,y,k)
+ mptopdf.texcode("\\MPScmyk{" .. c .. "}{" .. m .. "}{" .. y .. "}{" .. k .. "}")
+ end
+
+ function mps.setgray(s)
+ mptopdf.texcode("\\MPSgray{" .. s .. "}")
+ end
+
+end
+
+function mps.specials(version,signal,factor) -- 2.0 123 1000
+end
+
+function mps.special(...) -- 7 1 0.5 1 0 0 1 3
+ local n = select("#",...)
+ mptopdf.texcode("\\MPSbegin\\MPSset{" .. concat({...},"}\\MPSset{",2,n) .. "}\\MPSend")
+end
+
+function mps.begindata()
+end
+
+function mps.enddata()
+end
+
+function mps.showpage()
+end
+
+mps.n = mps.newpath -- n
+mps.p = mps.closepath -- h
+mps.l = mps.lineto -- l
+mps.r = mps.rlineto -- r
+mps.m = mps.moveto -- m
+mps.c = mps.curveto -- c
+mps.hlw = mps.setlinewidth
+mps.vlw = mps.setlinewidth
+
+mps.C = mps.setcmykcolor -- k
+mps.G = mps.setgray -- g
+mps.R = mps.setrgbcolor -- rg
+
+mps.lj = mps.setlinejoin -- j
+mps.ml = mps.setmiterlimit -- M
+mps.lc = mps.setlinecap -- J
+mps.sd = mps.setdash -- d
+mps.rd = mps.resetdash
+
+mps.S = mps.stroke -- S
+mps.F = mps.fill -- f
+mps.B = mps.both -- B
+mps.W = mps.clip -- W
+
+mps.q = mps.gsave -- q
+mps.Q = mps.grestore -- Q
+
+mps.s = mps.scale -- (not in pdf)
+mps.t = mps.concat -- (not the same as pdf anyway)
+
+mps.P = mps.showpage
+
+-- experimental
+
+function mps.attribute(id,value)
+ mptopdf.texcode("\\attribute " .. id .. "=" .. value .. " ")
+-- mptopdf.texcode("\\dompattribute{" .. id .. "}{" .. value .. "}")
+end
+
+-- lpeg parser
+
+-- The lpeg based parser is rather optimized for the kind of output
+-- that MetaPost produces. It's my first real lpeg code, which may
+-- show. Because the parser binds to functions, we define it last.
+
+do -- assumes \let\c\char
+
+ local byte = string.byte
+ local digit = lpeg.R("09")
+ local spec = digit^2 * lpeg.P("::::") * digit^2
+ local text = lpeg.Cc("{") * (
+ lpeg.P("\\") * ( (digit * digit * digit) / function(n) return "c" .. tonumber(n,8) end) +
+ lpeg.P(" ") / function(n) return "\\c32" end + -- never in new mp
+ lpeg.P(1) / function(n) return "\\c" .. byte(n) end
+ ) * lpeg.Cc("}")
+ local package = lpeg.Cs(spec + text^0)
+
+ function mps.fshow(str,font,scale) -- lpeg parser
+ mps.textext(font,scale,package:match(str))
+ end
+
+end
+
+do
+
+ local eol = lpeg.S('\r\n')^1
+ local sp = lpeg.P(' ')^1
+ local space = lpeg.S(' \r\n')^1
+ local number = lpeg.S('0123456789.-+')^1
+ local nonspace = lpeg.P(1-lpeg.S(' \r\n'))^1
+
+ local cnumber = lpeg.C(number)
+ local cstring = lpeg.C(nonspace)
+
+ local specials = (lpeg.P("%%MetaPostSpecials:") * sp * (cstring * sp^0)^0 * eol) / mps.specials
+ local special = (lpeg.P("%%MetaPostSpecial:") * sp * (cstring * sp^0)^0 * eol) / mps.special
+ local boundingbox = (lpeg.P("%%BoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+ local highresboundingbox = (lpeg.P("%%HiResBoundingBox:") * sp * (cnumber * sp^0)^4 * eol) / mps.boundingbox
+
+ local setup = lpeg.P("%%BeginSetup") * (1 - lpeg.P("%%EndSetup") )^1
+ local prolog = lpeg.P("%%BeginProlog") * (1 - lpeg.P("%%EndProlog"))^1
+ local comment = lpeg.P('%')^1 * (1 - eol)^1
+
+ local curveto = ((cnumber * sp)^6 * lpeg.P("curveto") ) / mps.curveto
+ local lineto = ((cnumber * sp)^2 * lpeg.P("lineto") ) / mps.lineto
+ local rlineto = ((cnumber * sp)^2 * lpeg.P("rlineto") ) / mps.rlineto
+ local moveto = ((cnumber * sp)^2 * lpeg.P("moveto") ) / mps.moveto
+ local setrgbcolor = ((cnumber * sp)^3 * lpeg.P("setrgbcolor") ) / mps.setrgbcolor
+ local setcmykcolor = ((cnumber * sp)^4 * lpeg.P("setcmykcolor") ) / mps.setcmykcolor
+ local setgray = ((cnumber * sp)^1 * lpeg.P("setgray") ) / mps.setgray
+ local newpath = ( lpeg.P("newpath") ) / mps.newpath
+ local closepath = ( lpeg.P("closepath") ) / mps.closepath
+ local fill = ( lpeg.P("fill") ) / mps.fill
+ local stroke = ( lpeg.P("stroke") ) / mps.stroke
+ local clip = ( lpeg.P("clip") ) / mps.clip
+ local both = ( lpeg.P("gsave fill grestore")) / mps.both
+ local showpage = ( lpeg.P("showpage") )
+ local setlinejoin = ((cnumber * sp)^1 * lpeg.P("setlinejoin") ) / mps.setlinejoin
+ local setlinecap = ((cnumber * sp)^1 * lpeg.P("setlinecap") ) / mps.setlinecap
+ local setmiterlimit = ((cnumber * sp)^1 * lpeg.P("setmiterlimit") ) / mps.setmiterlimit
+ local gsave = ( lpeg.P("gsave") ) / mps.gsave
+ local grestore = ( lpeg.P("grestore") ) / mps.grestore
+
+ local setdash = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("setdash")) / mps.setdash
+ local concat = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("concat") ) / mps.concat
+ local scale = ( (cnumber * sp^0)^6 * sp * lpeg.P("concat") ) / mps.concat
+
+ local fshow = (lpeg.P("(") * lpeg.C((1-lpeg.P(")"))^1) * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
+ local fshow = (lpeg.P("(") *
+ lpeg.Cs( ( lpeg.P("\\(")/"\\050" + lpeg.P("\\)")/"\\051" + (1-lpeg.P(")")) )^1 )
+ * lpeg.P(")") * space * cstring * space * cnumber * space * lpeg.P("fshow")) / mps.fshow
+
+ local setlinewidth_x = (lpeg.P("0") * sp * cnumber * sp * lpeg.P("dtransform truncate idtransform setlinewidth pop")) / mps.setlinewidth
+ local setlinewidth_y = (cnumber * sp * lpeg.P("0 dtransform exch truncate exch idtransform pop setlinewidth") ) / mps.setlinewidth
+
+ local c = ((cnumber * sp)^6 * lpeg.P("c") ) / mps.curveto -- ^6 very inefficient, ^1 ok too
+ local l = ((cnumber * sp)^2 * lpeg.P("l") ) / mps.lineto
+ local r = ((cnumber * sp)^2 * lpeg.P("r") ) / mps.rlineto
+ local m = ((cnumber * sp)^2 * lpeg.P("m") ) / mps.moveto
+ local vlw = ((cnumber * sp)^1 * lpeg.P("vlw")) / mps.setlinewidth
+ local hlw = ((cnumber * sp)^1 * lpeg.P("hlw")) / mps.setlinewidth
+
+ local R = ((cnumber * sp)^3 * lpeg.P("R") ) / mps.setrgbcolor
+ local C = ((cnumber * sp)^4 * lpeg.P("C") ) / mps.setcmykcolor
+ local G = ((cnumber * sp)^1 * lpeg.P("G") ) / mps.setgray
+
+ local lj = ((cnumber * sp)^1 * lpeg.P("lj") ) / mps.setlinejoin
+ local ml = ((cnumber * sp)^1 * lpeg.P("ml") ) / mps.setmiterlimit
+ local lc = ((cnumber * sp)^1 * lpeg.P("lc") ) / mps.setlinecap
+
+ local n = lpeg.P("n") / mps.newpath
+ local p = lpeg.P("p") / mps.closepath
+ local S = lpeg.P("S") / mps.stroke
+ local F = lpeg.P("F") / mps.fill
+ local B = lpeg.P("B") / mps.both
+ local W = lpeg.P("W") / mps.clip
+ local P = lpeg.P("P") / mps.showpage
+
+ local q = lpeg.P("q") / mps.gsave
+ local Q = lpeg.P("Q") / mps.grestore
+
+ local sd = (lpeg.P("[") * (cnumber * sp^0)^0 * lpeg.P("]") * sp * cnumber * sp * lpeg.P("sd")) / mps.setdash
+ local rd = ( lpeg.P("rd")) / mps.resetdash
+
+ local s = ( (cnumber * sp^0)^2 * lpeg.P("s") ) / mps.scale
+ local t = (lpeg.P("[") * (cnumber * sp^0)^6 * lpeg.P("]") * sp * lpeg.P("t") ) / mps.concat
+
+ -- experimental
+
+ local attribute = ((cnumber * sp)^2 * lpeg.P("attribute")) / mps.attribute
+ local A = ((cnumber * sp)^2 * lpeg.P("A")) / mps.attribute
+
+ local preamble = (
+ prolog + setup +
+ boundingbox + highresboundingbox + specials + special +
+ comment
+ )
+
+ local procset = (
+ lj + ml + lc +
+ c + l + m + n + p + r +
+ A +
+ R + C + G +
+ S + F + B + W +
+ vlw + hlw +
+ Q + q +
+ sd + rd +
+ t + s +
+ fshow +
+ P
+ )
+
+ local verbose = (
+ curveto + lineto + moveto + newpath + closepath + rlineto +
+ setrgbcolor + setcmykcolor + setgray +
+ attribute +
+ setlinejoin + setmiterlimit + setlinecap +
+ stroke + fill + clip + both +
+ setlinewidth_x + setlinewidth_y +
+ gsave + grestore +
+ concat + scale +
+ fshow +
+ setdash + -- no resetdash
+ showpage
+ )
+
+ -- order matters in terms of speed / we could check for procset first
+
+ local captures_old = ( space + verbose + preamble )^0
+ local captures_new = ( space + procset + preamble + verbose )^0
+
+ function mptopdf.parsers.lpeg()
+ if mptopdf.data:find("%%%%BeginResource: procset mpost") then
+ captures_new:match(mptopdf.data)
+ else
+ captures_old:match(mptopdf.data)
+ end
+ end
+
+end
+
+mptopdf.parser = 'lpeg'
+
+-- status info
+
+statistics.register("mps conversion time",function()
+ local n = mptopdf.n
+ if n > 0 then
+ return format("%s seconds, %s conversions", statistics.elapsedtime(mptopdf),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/meta-tex.mkii b/tex/context/base/meta-tex.mkii
index 5766f659f..bf733d550 100644
--- a/tex/context/base/meta-tex.mkii
+++ b/tex/context/base/meta-tex.mkii
@@ -191,7 +191,7 @@
\filtersometxt}
\long\def\filtersometxt#1\sometxt
- {\doifnextcharelse[\redofiltersometxt\dodofiltersometxt}
+ {\doifnextoptionalelse\redofiltersometxt\dodofiltersometxt}
% cleaner in mkiv
%
diff --git a/tex/context/base/metatex.tex b/tex/context/base/metatex.tex
new file mode 100644
index 000000000..c7ceb005d
--- /dev/null
+++ b/tex/context/base/metatex.tex
@@ -0,0 +1,145 @@
+%D \module
+%D [ file=metatex,
+%D version=2008.10.10,
+%D title=\METATEX,
+%D subtitle=\METATEX\ Format Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen / \CONTEXT\ Development Team]
+%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 This format is just a minimal layer on top of the \LUATEX\
+%D engine and will not provide high level functionality. It can
+%D be used as basis for dedicated (specialized) macro packages.
+%D
+%D A format is generated with the command;
+%D
+%D \starttyping
+%D luatools --make --compile metatex
+%D \stoptyping
+%D
+%D Remark: this is far from complete. We will gradually add
+%D more. Also, it's not yet clean what exactly will be part
+%D of it. This is a prelude to a configureable macro package.
+
+\catcode`\{=1 \catcode`\}=2 \catcode`\#=6
+
+\edef\metatexformat {\jobname}
+\edef\metatexversion{2007.04.03 13:01}
+
+\let\fmtname \metatexformat
+\let\fmtversion\metatexversion
+
+\ifx\normalinput\undefined \let\normalinput\input \fi
+
+\def\loadcorefile#1{\normalinput#1\relax}
+
+\loadcorefile{syst-ini.tex} % some basic commands and allocations that are expected down the line
+\loadcorefile{syst-pln.tex} % plain tex initializations of internal registers (no further code)
+
+\loadcorefile{luat-cod.tex} %
+\loadcorefile{luat-bas.tex} %
+\loadcorefile{luat-lib.tex} %
+
+% needs stripping:
+
+\loadcorefile{catc-ini.mkiv} % catcode table management
+\loadcorefile{catc-act.tex} % active character definition mechanisms
+\loadcorefile{catc-def.tex} % some generic catcode tables
+\loadcorefile{catc-ctx.tex} % a couple of context specific tables but expected by later modules
+\loadcorefile{catc-sym.tex} % some definitions related to \letter<tokens>
+
+% helpers, maybe less
+
+\loadcorefile{syst-aux.tex} % a whole lot of auxiliary macros
+%loadcorefile{syst-lua.tex} % some helpers using lua instead
+%loadcorefile{syst-con.mkiv} % some rather basic conversions
+%loadcorefile{syst-fnt.mkiv}
+%loadcorefile{syst-str.mkiv}
+%loadcorefile{syst-rtp.mkiv}
+
+% not needed
+
+% \loadmarkfile{supp-fil}
+% \loadmarkfile{supp-dir}
+
+% characters
+
+\loadcorefile{char-utf.tex}
+\loadcorefile{char-ini.tex}
+\loadcorefile{char-enc.tex} % \registerctxluafile{char-enc}{1.001}
+
+% nodes
+
+\loadcorefile{node-ini.tex}
+%loadcorefile{node-fin.tex}
+%loadcorefile{node-par.tex}
+
+% attributes, not needed:
+
+%loadcorefile{attr-ini.tex}
+
+% regimes
+
+% \loadcorefile{regi-ini.mkiv}
+% \loadcorefile{regi-syn.tex}
+
+% languages
+
+% fonts
+
+% \loadcorefile{enco-ini.mkiv}
+% \loadcorefile{hand-ini.mkiv}
+
+\registerctxluafile{font-ini}{1.001}
+
+\registerctxluafile{node-fnt}{1.001}
+
+\registerctxluafile{font-enc}{1.001}
+\registerctxluafile{font-map}{1.001}
+\registerctxluafile{font-syn}{1.001}
+\registerctxluafile{font-tfm}{1.001}
+\registerctxluafile{font-afm}{1.001}
+\registerctxluafile{font-cid}{1.001}
+\registerctxluafile{font-ott}{1.001}
+\registerctxluafile{font-otf}{1.001}
+\registerctxluafile{font-otb}{1.001}
+\registerctxluafile{font-otn}{1.001}
+\registerctxluafile{font-ota}{1.001}
+\registerctxluafile{font-otp}{1.001}
+\registerctxluafile{font-otc}{1.001}
+%registerctxluafile{font-vf} {1.001}
+\registerctxluafile{font-def}{1.001}
+%registerctxluafile{font-ctx}{1.001}
+\registerctxluafile{font-xtx}{1.001}
+%registerctxluafile{font-fbk}{1.001}
+%registerctxluafile{font-ext}{1.001}
+\registerctxluafile{font-pat}{1.001}
+%registerctxluafile{font-chk}{1.001}
+
+%registerctxluafile{math-ini}{1.001}
+%registerctxluafile{math-dim}{1.001}
+%registerctxluafile{math-ent}{1.001}
+%registerctxluafile{math-ext}{1.001}
+%registerctxluafile{math-vfu}{1.001}
+%registerctxluafile{math-map}{1.001}
+%registerctxluafile{math-noa}{1.001}
+
+\registerctxluafile{task-ini}{1.001}
+
+%registerctxluafile{l-xml}{1.001} % needed for font database
+
+% plain
+
+%loadcorefile{syst-stp.tex} % stripped plain
+
+% why not ...
+
+\pdfoutput\plusone
+
+% done
+
+\errorstopmode \dump \endinput
diff --git a/tex/context/base/mlib-ctx.lua b/tex/context/base/mlib-ctx.lua
index 6ada8ad19..8109003ca 100644
--- a/tex/context/base/mlib-ctx.lua
+++ b/tex/context/base/mlib-ctx.lua
@@ -14,8 +14,8 @@ local sprint = tex.sprint
metapost = metapost or {}
metapost.defaultformat = "metafun"
-function metapost.graphic(mpsformat,str,preamble)
- local mpx = metapost.format(mpsformat or metapost.defaultformat)
+function metapost.graphic(instance,mpsformat,str,preamble)
+ local mpx = metapost.format(instance,mpsformat or metapost.defaultformat)
metapost.graphic_base_pass(mpx,str,preamble)
end
@@ -29,7 +29,7 @@ function metapost.filterclippath(result)
for o=1,#objects do
local object = objects[o]
if object.type == "start_clip" then
- return join(flushnormalpath(object.path,{ }),"\n")
+ return join(metapost.flushnormalpath(object.path,{ }),"\n")
end
end
end
@@ -37,3 +37,13 @@ function metapost.filterclippath(result)
end
return ""
end
+
+statistics.register("metapost processing time", function()
+ local n = metapost.n
+ if n > 0 then
+ return format("%s seconds, loading: %s seconds, execution: %s seconds, n: %s",
+ statistics.elapsedtime(metapost), statistics.elapsedtime(mplib), statistics.elapsedtime(metapost.exectime),n)
+ else
+ return nil
+ end
+end)
diff --git a/tex/context/base/mlib-pdf.lua b/tex/context/base/mlib-pdf.lua
index a12db3d82..9c5775a2d 100644
--- a/tex/context/base/mlib-pdf.lua
+++ b/tex/context/base/mlib-pdf.lua
@@ -6,10 +6,14 @@ if not modules then modules = { } end modules ['mlib-pdf'] = {
license = "see context related readme files",
}
-local format, join = string.format, table.concat
-local sprint = tex.sprint
+local format, concat = string.format, table.concat
+local texsprint = tex.sprint
local abs, sqrt, round = math.abs, math.sqrt, math.round
+local copy_node, write_node = node.copy, node.write
+
+local ctxcatcodes = tex.ctxcatcodes
+
metapost = metapost or { }
metapost.multipass = false
metapost.n = 0
@@ -52,35 +56,71 @@ function metapost.convert(result, trialrun, flusher, multipass)
return true -- done
end
-function metapost.comment(message)
- if message then
- sprint(tex.ctxcatcodes,format("\\MPLIBtoPDF{\\letterpercent\\space mps graphic %s: %s}", metapost.n, message))
+metapost.flushers = { }
+metapost.flushers.pdf = { }
+
+local savedliterals = nil
+
+local mpsliteral = nodes.register(node.new("whatsit",8))
+
+function metapost.flush_literal(d) -- \def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
+ if savedliterals then
+ local literal = copy_node(mpsliteral)
+ literal.data = savedliterals[d]
+ write_node(literal)
+ else
+ logs.report("metapost","problem flushing literal %s",d)
end
end
-metapost.flushers = { }
-metapost.flushers.pdf = { }
+function metapost.flush_reset()
+ savedliterals = nil
+end
+
+function metapost.flushers.pdf.comment(message)
+ if message then
+ message = format("%% mps graphic %s: %s", metapost.n, message)
+ if savedliterals then
+ local last = #savedliterals + 1
+ savedliterals[last] = message
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ else
+ savedliterals = { message }
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ end
+ end
+end
function metapost.flushers.pdf.startfigure(n,llx,lly,urx,ury,message)
+ savedliterals = nil
metapost.n = metapost.n + 1
- sprint(tex.ctxcatcodes,format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
- if message then metapost.comment(message) end
+ texsprint(ctxcatcodes,format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
+ if message then metapost.flushers.pdf.comment(message) end
end
function metapost.flushers.pdf.stopfigure(message)
- if message then metapost.comment(message) end
- sprint(tex.ctxcatcodes,"\\stopMPLIBtoPDF")
+ if message then metapost.flushers.pdf.comment(message) end
+ texsprint(ctxcatcodes,"\\stopMPLIBtoPDF")
+ texsprint(ctxcatcodes,"\\ctxlua{metapost.flush_reset()}") -- maybe just at the beginning
end
function metapost.flushers.pdf.flushfigure(pdfliterals) -- table
if #pdfliterals > 0 then
- sprint(tex.ctxcatcodes,"\\MPLIBtoPDF{",join(pdfliterals,"\n"),"}")
+ pdfliterals = concat(pdfliterals,"\n")
+ if savedliterals then
+ local last = #savedliterals + 1
+ savedliterals[last] = pdfliterals
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{",last,"}")
+ else
+ savedliterals = { pdfliterals }
+ texsprint(ctxcatcodes,"\\MPLIBtoPDF{1}")
+ end
end
end
function metapost.flushers.pdf.textfigure(font,size,text,width,height,depth) -- we could save the factor
text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost (i have to check if this is true for mplib)
- sprint(tex.ctxcatcodes,format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-number.dimenfactors.bp*depth))
+ texsprint(ctxcatcodes,format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-number.dimenfactors.bp*depth))
end
local bend_tolerance = 131/65536
@@ -99,15 +139,15 @@ local function pen_characteristics(object)
end
end
-local function concat(px, py) -- no tx, ty here
+local function mpconcat(px, py) -- no tx, ty here / we can move this one inline if needed
return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
end
local function curved(ith,pth)
local d = pth.left_x - ith.right_x
- if abs(ith.right_x-ith.x_coord-d) <= bend_tolerance and abs(pth.x_coord-pth.left_x-d) <= bend_tolerance then
+ if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
d = pth.left_y - ith.right_y
- if abs(ith.right_y-ith.y_coord-d) <= bend_tolerance and abs(pth.y_coord-pth.left_y-d) <= bend_tolerance then
+ if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
return false
end
end
@@ -148,33 +188,35 @@ local function flushconcatpath(path, t, open)
for i=1,#path do
pth = path[i]
if not ith then
- t[#t+1] = format("%f %f m",concat(pth.x_coord,pth.y_coord))
+ t[#t+1] = format("%f %f m",mpconcat(pth.x_coord,pth.y_coord))
elseif curved(ith,pth) then
- local a, b = concat(ith.right_x,ith.right_y)
- local c, d = concat(pth.left_x,pth.left_y)
- t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
+ local a, b = mpconcat(ith.right_x,ith.right_y)
+ local c, d = mpconcat(pth.left_x,pth.left_y)
+ t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(pth.x_coord,pth.y_coord))
else
- t[#t+1] = format("%f %f l",concat(pth.x_coord, pth.y_coord))
+ t[#t+1] = format("%f %f l",mpconcat(pth.x_coord, pth.y_coord))
end
ith = pth
end
if not open then
local one = path[1]
if curved(pth,one) then
- local a, b = concat(pth.right_x,pth.right_y)
- local c, d = concat(one.left_x,one.left_y)
- t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
+ local a, b = mpconcat(pth.right_x,pth.right_y)
+ local c, d = mpconcat(one.left_x,one.left_y)
+ t[#t+1] = format("%f %f %f %f %f %f c",a,b,c,d,mpconcat(one.x_coord, one.y_coord))
else
- t[#t+1] = format("%f %f l",concat(one.x_coord,one.y_coord))
+ t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
end
elseif #path == 1 then
-- special case .. draw point
local one = path[1]
- t[#t+1] = format("%f %f l",concat(one.x_coord,one.y_coord))
+ t[#t+1] = format("%f %f l",mpconcat(one.x_coord,one.y_coord))
end
return t
end
+metapost.flushnormalpath = flushnormalpath
+
metapost.specials = metapost.specials or { }
-- we have two extension handlers, one for pre and postscripts, and one for colors
@@ -287,7 +329,7 @@ function metapost.flush(result,flusher) -- pdf flusher, table en dan concat is s
end
local dl = currentobject.dash
if dl then
- local d = format("[%s] %i d",join(dl.dashes or {}," "),dl.offset)
+ local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
if d ~= dashed then
dashed = d
t[#t+1] = dashed
@@ -404,7 +446,7 @@ do
local flusher = {
startfigure = function()
t = { }
- sprint(tex.ctxcatcodes,"\\startnointerference")
+ texsprint(ctxcatcodes,"\\startnointerference")
end,
flushfigure = function(literals)
for i=1, #literals do
@@ -412,7 +454,7 @@ do
end
end,
stopfigure = function()
- sprint(tex.ctxcatcodes,"\\stopnointerference")
+ texsprint(ctxcatcodes,"\\stopnointerference")
end
}
@@ -428,9 +470,12 @@ function metapost.totable(result)
if figure then
local t = { }
local objects = figure:objects()
- for _, object in ipairs(objects) do
+ for o=1,#objects do
+ local object = objects[o]
local tt = { }
- for _, field in ipairs(mplib.fields(object)) do
+ local fields = mplib.fields(object)
+ for f=1,#fields do
+ local field = fields[f]
tt[field] = object[field]
end
t[#t+1] = tt
@@ -460,105 +505,3 @@ function metapost.colorconverter()
end
end
end
-
---~ -- obsolete code
---~
---~ -- the pen calculations are taken from metapost, first converted by
---~ -- taco from c to lua, and then optimized by hans, so all errors are his
---~
---~ local aspect_bound = 10/65536
---~ local aspect_default = 1/65536
---~ local eps = 0.0001
---~
---~ local function pyth(a,b)
---~ return sqrt(a*a + b*b) -- much faster than sqrt(a^2 + b^2)
---~ end
---~
---~ local function coord_range_x(h, dz) -- direction x
---~ local zlo, zhi = 0, 0
---~ for i=1, #h do
---~ local p = h[i]
---~ local z = p.x_coord
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ z = p.right_x
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ z = p.left_x
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ end
---~ return (zhi - zlo <= dz and aspect_bound) or aspect_default
---~ end
---~
---~ local function coord_range_y(h, dz) -- direction y
---~ local zlo, zhi = 0, 0
---~ for i=1, #h do
---~ local p = h[i]
---~ local z = p.y_coord
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ z = p.right_y
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ z = p.left_y
---~ if z < zlo then zlo = z elseif z > zhi then zhi = z end
---~ end
---~ return (zhi - zlo <= dz and aspect_bound) or aspect_default
---~ end
---~
---~ local function pen_characteristics(object)
---~ local p = object.pen[1]
---~ local x_coord, y_coord, left_x, left_y, right_x, right_y = p.x_coord, p.y_coord, p.left_x, p.left_y, p.right_x, p.right_y
---~ local wx, wy, width
---~ if right_x == x_coord and left_y == y_coord then
---~ wx = abs(left_x - x_coord)
---~ wy = abs(right_y - y_coord)
---~ else
---~ wx = pyth(left_x - x_coord, right_x - x_coord)
---~ wy = pyth(left_y - y_coord, right_y - y_coord)
---~ end
---~ if wy/coord_range_x(object.path, wx) >= wx/coord_range_y(object.path, wy) then
---~ width = wy
---~ else
---~ width = wx
---~ end
---~ sx, rx, ry, sy, tx, ty = left_x, left_y, right_x, right_y, x_coord, y_coord
---~ sx, rx, ry, sy = (sx-tx), (rx-ty), (ry-tx), (sy-ty) -- combine with previous
---~ if width ~= 1 then
---~ if width == 0 then
---~ sx, sy = 1, 1
---~ else
---~ rx, ry, sx, sy = rx/width, ry/width, sx/width, sy/width
---~ end
---~ end
---~ -- sx rx ry sy tx ty -> 1 0 0 1 0 0 is ok, but 0 0 0 0 0 0 not
---~ if true then
---~ if abs(sx) < eps then sx = eps end
---~ if abs(sy) < eps then sy = eps end
---~ else
---~ -- this block looks complicated but it only captures invalid transforms
---~ -- to be checked rx vs sx and so
---~ local det = sx/sy - ry/rx
---~ local aspect = 4*aspect_bound + aspect_default
---~ if abs(det) < aspect then
---~ local s
---~ if det >= 0 then
---~ s, aspect = 1, aspect - det
---~ else
---~ s, aspect = -1, -aspect - det -- - ?
---~ end
---~ local absrx, absry, abssy, abssx = abs(rx), abs(ry), abs(sy), abs(sx)
---~ if abssx + abssy >= absry + absrx then -- was yy
---~ if abssx > abssy then
---~ sy = sy + (aspect + s*abssx) / sx
---~ else
---~ sx = sx + (aspect + s*abssy) / sy
---~ end
---~ else
---~ if absry > absrx then
---~ rx = rx + (aspect + s*absry) / ry
---~ else
---~ ry = ry + (aspect + s*absrx) / rx
---~ end
---~ end
---~ end
---~ end
---~ divider = sx*sy - rx*ry
---~ return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), width
---~ end
diff --git a/tex/context/base/mlib-pdf.tex b/tex/context/base/mlib-pdf.tex
index b7b8506ad..9a04d188f 100644
--- a/tex/context/base/mlib-pdf.tex
+++ b/tex/context/base/mlib-pdf.tex
@@ -15,7 +15,9 @@
\registerctxluafile{mlib-pdf}{1.001}
-\let\MPLIBtoPDF\pdfliteral
+% \let\MPLIBtoPDF\pdfliteral
+
+\def\MPLIBtoPDF#1{\ctxlua{metapost.flush_literal(#1)}}
\def\MPLIBboundingbox#1#2#3#4%
{\xdef\MPllx{#1}%
@@ -26,7 +28,7 @@
\xdef\MPheight{\the\dimexpr#4\onebasepoint-#2\onebasepoint\relax}}
\def\startMPLIBtoPDF#1#2#3#4% watch the transparency reset
- {\hbox\bgroup
+ {\naturalhbox\bgroup
\MPLIBboundingbox{#1}{#2}{#3}{#4}%
\forgetall
\setbox\scratchbox\vbox\bgroup
diff --git a/tex/context/base/mlib-pps.lua b/tex/context/base/mlib-pps.lua
index 3d5187c0f..e210e4ee1 100644
--- a/tex/context/base/mlib-pps.lua
+++ b/tex/context/base/mlib-pps.lua
@@ -9,8 +9,13 @@ if not modules then modules = { } end modules ['mlib-pps'] = { -- prescript, pos
-- current limitation: if we have textext as well as a special color then due to
-- prescript/postscript overload we can have problems
-local format, concat, round = string.format, table.concat, math.round
+local format, gmatch, concat, round, match = string.format, string.gmatch, table.concat, math.round, string.match
local sprint = tex.sprint
+local tonumber, type = tonumber, type
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local trace_textexts = false trackers.register("metapost.textexts", function(v) trace_textexts = v end)
colors = colors or { }
@@ -35,10 +40,11 @@ local colordata = { {}, {}, {}, {}, {} }
--~ => rest : r=123 g=n>10 b=whatever
function metapost.specials.register(str) -- only colors
- local size, content, n, class = str:match("^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$")
+ local size, content, n, class = match(str,"^%%%%MetaPostSpecial: (%d+) (.*) (%d+) (%d+)$")
if class then
+ -- use lpeg splitter
local data = { }
- for s in content:gmatch("[^ ]+") do
+ for s in gmatch(content,"[^ ]+") do
data[#data+1] = s
end
class, n = tonumber(class), tonumber(n)
@@ -110,7 +116,7 @@ function metapost.colorspec(cs)
end
function metapost.specials.tr(specification,object,result)
- local a, t = specification:match("^(.+),(.+)$")
+ local a, t = match(specification,"^(.+),(.+)$")
local before = a and t and function()
result[#result+1] = format("/Tr%s gs",transparencies.register('mp',a,t))
return object, result
@@ -122,23 +128,8 @@ function metapost.specials.tr(specification,object,result)
return object, before, nil, after
end
---~ -- possible speedup: hash registered colors
---~
---~ function metapost.specials.sp(specification,object,result) -- todo: color conversion
---~ local s = object.color[1]
---~ object.color = nil
---~ local before = function()
---~ local spec = specification:split(" ")
---~ ctx.registerspotcolor(spec[1])
---~ result[#result+1] = ctx.pdfcolor(colors.model,colors.register('color',nil,'spot',spec[1],spec[2],spec[3],s))
---~ return object, result
---~ end
---~ local after = function()
---~ result[#result+1] = "0 g 0 G"
---~ return object, result
---~ end
---~ return object, before, nil, nil
---~ end
+local specificationsplitter = lpeg.Ct(lpeg.splitat(" "))
+local colorsplitter = lpeg.Ct(lpeg.splitat(":"))
-- Unfortunately we cannot use cmyk colors natively because there is no
-- generic color allocation primitive ... it's just an rgbcolor color.. This
@@ -151,11 +142,11 @@ end
-- This is also an example of a simple plugin.
--~ function metapost.specials.cc(specification,object,result)
---~ object.color = specification:split(" ")
+--~ object.color = specificationsplitter:match(specification)
--~ return object, nil, nil, nil
--~ end
--~ function metapost.specials.cc(specification,object,result)
---~ local c = specification:split(" ")
+--~ local c = specificationsplitter:match(specification)
--~ local o = object.color[1]
--~ c[1],c[2],c[3],c[4] = o*c[1],o*c[2],o*c[3],o*c[4]
--~ return object, nil, nil, nil
@@ -176,7 +167,7 @@ function metapost.specials.fg(specification,object,result,flusher)
if sy == 0 then sy = 0.00001 end
local before = specification and function()
flusher.flushfigure(result)
- sprint(tex.ctxcatcodes,format("\\MPLIBfigure{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,specification))
+ sprint(ctxcatcodes,format("\\MPLIBfigure{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,specification))
return object, { }
end
return { } , before, nil, nil -- replace { } by object for tracing
@@ -210,22 +201,22 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color
nofshades = nofshades + 1
flusher.flushfigure(result)
result = { }
- local t = specification:split(" ")
+ local t = specificationsplitter:match(specification)
-- we need a way to move/scale
- local ca = t[4]:split(":")
- local cb = t[8]:split(":")
+ local ca = colorsplitter:match(t[4])
+ local cb = colorsplitter:match(t[8])
if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
if type(ca) == "string" then
-- spot color, not supported, maybe at some point use the fallbacks
- sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}",
nofshades,
t[1], t[2], 0, 1, 1, "DeviceGray",
t[5], t[6], t[7], t[9], t[10], t[11]))
-- terrible hack, somehow does not work
--~ local a = ca:match("^([^ ]+)")
--~ local b = cb:match("^([^ ]+)")
---~ sprint(tex.ctxcatcodes,format("\\xMPLIBcircularshade{%s}{%s %s}{%s}{%s}{%s}{%s}{%s %s %s %s %s %s}",
+--~ sprint(ctxcatcodes,format("\\xMPLIBcircularshade{%s}{%s %s}{%s}{%s}{%s}{%s}{%s %s %s %s %s %s}",
--~ nofshades,
--~ --~ t[1], t[2], a, b, 1, "DeviceN",
--~ 0, 1, a, b, 1, "DeviceN",
@@ -250,7 +241,7 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color
ca[1], ca[2], ca[3] = a, a, a
cb[1], cb[2], cb[3] = b, b, b
end
- sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}",
nofshades,
t[1], t[2], ca[1], ca[2], ca[3], cb[1], cb[2], cb[3], 1, "DeviceRGB",
t[5], t[6], t[7], t[9], t[10], t[11]))
@@ -262,7 +253,7 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color
ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1]
cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1]
end
- sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s %s %s}",
nofshades,
t[1], t[2], ca[1], ca[2], ca[3], ca[4], cb[1], cb[2], cb[3], cb[4], 1, "DeviceCMYK",
t[5], t[6], t[7], t[9], t[10], t[11]))
@@ -274,7 +265,7 @@ function metapost.specials.cs(specification,object,result,flusher) -- spot color
ca[1] = rgbtogray(ca[1],ca[2],ca[3])
cb[1] = rgbtogray(cb[1],cb[2],cb[3])
end
- sprint(tex.ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBcircularshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s %s %s}",
nofshades,
t[1], t[2], ca[1], cb[1], 1, "DeviceGray",
t[5], t[6], t[7], t[9], t[10], t[11]))
@@ -296,15 +287,15 @@ function metapost.specials.ls(specification,object,result,flusher)
nofshades = nofshades + 1
flusher.flushfigure(result)
result = { }
- local t = specification:split(" ")
+ local t = specificationsplitter:match(specification)
-- we need a way to move/scale
- local ca = t[4]:split(":")
- local cb = t[7]:split(":")
+ local ca = colorsplitter:match(t[4])
+ local cb = colorsplitter:match(t[7])
if round(ca[1]*10000) == 123 then ca = metapost.colorspec(ca) end
if round(cb[1]*10000) == 123 then cb = metapost.colorspec(cb) end
if type(ca) == "string" then
-- spot color, not supported, maybe at some point use the fallbacks
- sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}",
nofshades,
t[1], t[2], 0, 1, 1, "DeviceGray",
t[5], t[6], t[8], t[9]))
@@ -327,7 +318,7 @@ function metapost.specials.ls(specification,object,result,flusher)
ca[1], ca[2], ca[3] = a, a, a
cb[1], cb[2], cb[3] = b, b, b
end
- sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f}{%.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}",
nofshades,
t[1], t[2], ca[1], ca[2], ca[3], cb[1], cb[2], cb[3], 1, "DeviceRGB",
t[5], t[6], t[8], t[9]))
@@ -339,7 +330,7 @@ function metapost.specials.ls(specification,object,result,flusher)
ca[1], ca[2], ca[3], ca[4] = 0, 0, 0, ca[1]
cb[1], cb[2], cb[3], ca[4] = 0, 0, 0, ca[1]
end
- sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f %.3f %.3f %.3f}{%.3f %.3f %.3f %.3f}{%s}{%s}{%s %s %s %s}",
nofshades,
t[1], t[2], ca[1], ca[2], ca[3], ca[4], cb[1], cb[2], cb[3], cb[4], 1, "DeviceCMYK",
t[5], t[6], t[8], t[9]))
@@ -351,7 +342,7 @@ function metapost.specials.ls(specification,object,result,flusher)
ca[1] = rgbtogray(ca[1],ca[2],ca[3])
cb[1] = rgbtogray(cb[1],cb[2],cb[3])
end
- sprint(tex.ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}",
+ sprint(ctxcatcodes,format("\\MPLIBlinearshade{%s}{%s %s}{%.3f}{%.3f}{%s}{%s}{%s %s %s %s}",
nofshades,
t[1], t[2], ca[1], cb[1], 1, "DeviceGray",
t[5], t[6], t[8], t[9]))
@@ -373,10 +364,9 @@ end
local current_format, current_graphic
---~ metapost.first_box, metapost.last_box = 1000, 1100
-
+metapost.first_box = metapost.first_box or 1000
+metapost.last_box = metapost.last_box or 1100
metapost.textext_current = metapost.first_box
-metapost.trace_texttexts = false
metapost.multipass = false
function metapost.free_boxes()
@@ -393,49 +383,55 @@ end
function metapost.specials.tf(specification,object)
--~ print("setting", metapost.textext_current)
- local n, str = specification:match("^(%d+):(.+)$")
- if metapost.textext_current < metapost.last_box then
- metapost.textext_current = metapost.first_box + n - 1
- end
- if metapost.trace_texttexts then
- print("metapost", format("first pass: order %s, box %s",n,metapost.textext_current))
+ local n, str = match(specification,"^(%d+):(.+)$")
+ if n and str then
+ if metapost.textext_current < metapost.last_box then
+ metapost.textext_current = metapost.first_box + n - 1
+ end
+ if trace_textexts then
+ logs.report("metapost","first pass: order %s, box %s",n,metapost.textext_current)
+ end
+ sprint(ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",metapost.textext_current,str))
+ metapost.multipass = true
end
- sprint(tex.ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",metapost.textext_current,str))
- metapost.multipass = true
return { }, nil, nil, nil
end
function metapost.specials.ts(specification,object,result,flusher)
-- print("getting", metapost.textext_current)
- local n, str = specification:match("^(%d+):(.+)$")
- if metapost.trace_texttexts then
- print("metapost", format("second pass: order %s, box %s",n,metapost.textext_current))
- end
- local op = object.path
- local first, second, fourth = op[1], op[2], op[4]
- local tx, ty = first.x_coord , first.y_coord
- local sx, sy = second.x_coord - tx, fourth.y_coord - ty
- local rx, ry = second.y_coord - ty, fourth.x_coord - tx
- if sx == 0 then sx = 0.00001 end
- if sy == 0 then sy = 0.00001 end
- if not metapost.trace_texttexts then
- object.path = nil
- end
- local before = function() -- no need for function
- --~ flusher.flushfigure(result)
- --~ sprint(tex.ctxcatcodes,format("\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,metapost.textext_current))
- --~ result = { }
- result[#result+1] = format("q %f %f %f %f %f %f cm", sx,rx,ry,sy,tx,ty)
- flusher.flushfigure(result)
- if metapost.textext_current < metapost.last_box then
- metapost.textext_current = metapost.first_box + n - 1
+ local n, str = match(specification,"^(%d+):(.+)$")
+ if n and str then
+ if trace_textexts then
+ logs.report("metapost","second pass: order %s, box %s",n,metapost.textext_current)
end
- local b = metapost.textext_current
- sprint(tex.ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",b, metapost.sxsy(tex.wd[b],tex.ht[b],tex.dp[b])))
- result = { "Q" }
- return object, result
+ local op = object.path
+ local first, second, fourth = op[1], op[2], op[4]
+ local tx, ty = first.x_coord , first.y_coord
+ local sx, sy = second.x_coord - tx, fourth.y_coord - ty
+ local rx, ry = second.y_coord - ty, fourth.x_coord - tx
+ if sx == 0 then sx = 0.00001 end
+ if sy == 0 then sy = 0.00001 end
+ if not trace_textexts then
+ object.path = nil
+ end
+ local before = function() -- no need for function
+ --~ flusher.flushfigure(result)
+ --~ sprint(ctxcatcodes,format("\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",sx,rx,ry,sy,tx,ty,metapost.textext_current))
+ --~ result = { }
+ result[#result+1] = format("q %f %f %f %f %f %f cm", sx,rx,ry,sy,tx,ty)
+ flusher.flushfigure(result)
+ if metapost.textext_current < metapost.last_box then
+ metapost.textext_current = metapost.first_box + n - 1
+ end
+ local b = metapost.textext_current
+ sprint(ctxcatcodes,format("\\MPLIBgettextscaled{%s}{%s}{%s}",b, metapost.sxsy(tex.wd[b],tex.ht[b],tex.dp[b])))
+ result = { "Q" }
+ return object, result
+ end
+ return { }, before, nil, nil -- replace { } by object for tracing
+ else
+ return { }, nil, nil, nil -- replace { } by object for tracing
end
- return { }, before, nil, nil -- replace { } by object for tracing
end
function metapost.colorconverter()
@@ -689,24 +685,25 @@ do
end
---~ local factor = 65536*(7200/7227)
local factor = 65536*(7227/7200)
function metapost.edefsxsy(wd,ht,dp) -- helper for figure
- commands.edef("sx",(wd ~= 0 and 1/( wd /(factor))) or 0)
- commands.edef("sy",(wd ~= 0 and 1/((ht+dp)/(factor))) or 0)
+ local hd = ht + dp
+ commands.edef("sx",(wd ~= 0 and factor/wd) or 0)
+ commands.edef("sy",(hd ~= 0 and factor/hd) or 0)
end
function metapost.sxsy(wd,ht,dp) -- helper for text
- return (wd ~= 0 and 1/(wd/(factor))) or 0, (wd ~= 0 and 1/((ht+dp)/(factor))) or 0
+ local hd = ht + dp
+ return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
end
function metapost.text_texts_data()
local t, n = { }, 0
for i = metapost.first_box, metapost.last_box do
n = n + 1
- if metapost.trace_texttexts then
- print("metapost", format("passed data: order %s, box %s",n,i))
+ if trace_textexts then
+ logs.report("metapost","passed data: order %s, box %s",n,i)
end
if tex.box[i] then
t[#t+1] = format("_tt_w_[%i]:=%f;_tt_h_[%i]:=%f;_tt_d_[%i]:=%f;", n,tex.wd[i]/factor, n,tex.ht[i]/factor, n,tex.dp[i]/factor)
@@ -740,7 +737,7 @@ function metapost.graphic_base_pass(mpsformat,str,preamble)
local flushed = metapost.process(mpsformat, {
preamble,
"beginfig(1); ",
- "_trial_run_ := true ;",
+ "if unknown _trial_run_ : boolean _trial_run_ fi ; _trial_run_ := true ;",
str,
"endfig ;"
-- }, true, nil, true )
@@ -753,7 +750,7 @@ function metapost.graphic_base_pass(mpsformat,str,preamble)
if not flushed or not metapost.optimize then
-- tricky, we can only ask once for objects and therefore
-- we really need a second run when not optimized
- sprint(tex.ctxcatcodes,"\\ctxlua{metapost.graphic_extra_pass()}")
+ sprint(ctxcatcodes,"\\ctxlua{metapost.graphic_extra_pass()}")
end
else
metapost.process(mpsformat, {
@@ -782,17 +779,17 @@ end
function metapost.getclippath(data)
local mpx = metapost.format("metafun")
if mpx and data then
- input.starttiming(metapost)
- input.starttiming(metapost.exectime)
+ statistics.starttiming(metapost)
+ statistics.starttiming(metapost.exectime)
local result = mpx:execute(format("beginfig(1);%s;endfig;",data))
- input.stoptiming(metapost.exectime)
+ statistics.stoptiming(metapost.exectime)
if result.status > 0 then
print("error", result.status, result.error or result.term or result.log)
result = ""
else
result = metapost.filterclippath(result)
end
- input.stoptiming(metapost)
+ statistics.stoptiming(metapost)
sprint(result)
end
end
@@ -842,7 +839,7 @@ do -- not that beautiful but ok, we could save a md5 hash in the tui file !
local result = { }
if io.exists(mpyfile) then
local data = io.loaddata(mpyfile)
- for figure in data:gmatch("beginfig(.-)endfig") do
+ for figure in gmatch(data,"beginfig(.-)endfig") do
result[#result+1] = format("begingraphictextfig%sendgraphictextfig ;\n", figure)
end
io.savedata(mpyfile,concat(result,""))
diff --git a/tex/context/base/mlib-pps.tex b/tex/context/base/mlib-pps.tex
index 546b94f28..beaef044e 100644
--- a/tex/context/base/mlib-pps.tex
+++ b/tex/context/base/mlib-pps.tex
@@ -20,11 +20,6 @@
\immediate\pdfobj{<</ShadingType 3 /ColorSpace /#6 /Function \the\pdflastobj\space 0 R /Coords [#7] /Extend [true true]>>}%
\appendtoPDFdocumentshades{/MpSh#1 \the\pdflastobj\space0 R }}
-% \def\xMPLIBcircularshade#1#2#3#4#5#6#7% nr domain color-a color-b ? colorspace oordinates
-% {\immediate\pdfobj{<</FunctionType 2 /Domain [#2] /C0 #3 /C1 #4 /N #5>>}%
-% \immediate\pdfobj{<</ShadingType 3 /ColorSpace /#6 /Function \the\pdflastobj\space 0 R /Coords [#7] /Extend [true true]>>}%
-% \appendtoPDFdocumentshades{/MpSh#1 \the\pdflastobj\space0 R }}
-
\def\MPLIBlinearshade#1#2#3#4#5#6#7% nr domain color-a color-b ? colorspace oordinates
{\immediate\pdfobj{<</FunctionType 2 /Domain [#2] /C0 [#3] /C1 [#4] /N #5>>}%
\immediate\pdfobj{<</ShadingType 2 /ColorSpace /#6 /Function \the\pdflastobj\space 0 R /Coords [#7] /Extend [true true]>>}%
@@ -50,20 +45,17 @@
% \pdfliteral{Q}}
\def\MPLIBgettextscaled#1#2#3%
- {\vbox to \zeropoint{\vss\hbox to \zeropoint{\scale[sx=#2,sy=#3]{\raise\dp#1\copy#1}\hss}}}
+ {\vbox to \zeropoint{\vss\hbox to \zeropoint{\black\scale[sx=#2,sy=#3]{\raise\dp#1\copy#1}\hss}}}
\def\MPLIBallocate#1%
{\newbox\MPLIBfirst
- \dorecurse{\numexpr#1-1\relax}{\newbox\MPLIBlast}%
+ \dorecurse{\numexpr#1-1\relax}{\let\MPLIBlast\relax\newbox\MPLIBlast}%
\MPLIBregister}
-\def\MPLIBregister
+\def\MPLIBregister % after allocate!
{\ctxlua{metapost.first_box, metapost.last_box = \number\MPLIBfirst, \number\MPLIBlast}}
-\appendtoks \MPLIBallocate{1000}\to \everydump
-\appendtoks \MPLIBregister \to \everyjob
-
\def\MPLIBgraphictext#1%
- {\startTEXpage[scale=10000]#1\stopTEXpage}
+ {\startTEXpage[\c!scale=10000]#1\stopTEXpage}
\protect \endinput
diff --git a/tex/context/base/mlib-run.lua b/tex/context/base/mlib-run.lua
index 1edd00be7..9a7ed6f39 100644
--- a/tex/context/base/mlib-run.lua
+++ b/tex/context/base/mlib-run.lua
@@ -23,7 +23,7 @@ if not modules then modules = { } end modules ['mlib-run'] = {
<p>The directional helpers and pen analysis are more or less translated from the
<l n='c'/> code. It really helps that Taco know that source so well. Taco and I spent
quite some time on speeding up the <l n='lua'/> and <l n='c'/> code. There is not
-much to gain, especially if on ekeeps in mind that when integrated in <l n='tex'/>
+much to gain, especially if one keeps in mind that when integrated in <l n='tex'/>
only a part of the time is spent in <l n='metapost'/>. Of course an integrated
approach is way faster than an external <l n='metapost'/> and processing time
nears zero.</p>
@@ -33,13 +33,20 @@ local format = string.format
metapost = metapost or { }
+metapost.showlog = false
+metapost.lastlog = ""
+
+function metapost.resetlastlog()
+ metapost.lastlog = ""
+end
+
local function finder(name, mode, ftype)
if mode=="w" then
return name
- elseif input.aux.qualified_path(name) then
+ elseif file.is_qualified_path(name) then
return name
else
- return input.find_file(name,ftype)
+ return resolvers.find_file(name,ftype)
end
end
@@ -80,27 +87,27 @@ input %s ; dump ;
end
function metapost.make(name, target, version)
- input.starttiming(mplib)
+ statistics.starttiming(mplib)
target = file.replacesuffix(target or name, "mem")
local mpx = mplib.new ( table.merged (
metapost.parameters,
{
ini_version = true,
find_file = finder,
- job_name = file.stripsuffix(target),
+ job_name = file.removesuffix(target),
}
) )
if mpx then
- input.starttiming(metapost.exectime)
+ statistics.starttiming(metapost.exectime)
local result = mpx:execute(format(preamble,version or "unknown",name))
- input.stoptiming(metapost.exectime)
+ statistics.stoptiming(metapost.exectime)
mpx:finish()
end
- input.stoptiming(mplib)
+ statistics.stoptiming(mplib)
end
function metapost.load(name)
- input.starttiming(mplib)
+ statistics.starttiming(mplib)
local mpx = mplib.new ( table.merged (
metapost.parameters,
{
@@ -111,24 +118,24 @@ function metapost.load(name)
) )
local result
if mpx then
-if not mplib.pen_info then -- temp compatibility hack
- input.starttiming(metapost.exectime)
- result = mpx:execute("\\")
- input.stoptiming(metapost.exectime)
-end
+ if not mplib.pen_info then -- temp compatibility hack
+ statistics.starttiming(metapost.exectime)
+ result = mpx:execute("\\")
+ statistics.stoptiming(metapost.exectime)
+ end
else
result = { status = 99, error = "out of memory"}
end
- input.stoptiming(mplib)
+ statistics.stoptiming(mplib)
return mpx, result
end
function metapost.unload(mpx)
- input.starttiming(mplib)
+ statistics.starttiming(mplib)
if mpx then
mpx:finish()
end
- input.stoptiming(mplib)
+ statistics.stoptiming(mplib)
end
function metapost.reporterror(result)
@@ -143,6 +150,7 @@ function metapost.reporterror(result)
metapost.report("mp error: %s",(e=="" and "?") or e)
end
if not t and not e and l then
+ metapost.lastlog = metapost.lastlog .. "\n" .. l
metapost.report("mp log: %s",l)
else
metapost.report("mp error: unknown, no error, terminal or log messages")
@@ -153,21 +161,21 @@ function metapost.reporterror(result)
return true
end
-function metapost.checkformat(mpsinput, mpsformat)
+function metapost.checkformat(mpsinput, mpsformat, dirname)
mpsinput = file.addsuffix(mpsinput or "metafun", "mp")
- mpsformat = file.stripsuffix(file.basename(mpsformat or texconfig.formatname or tex.formatname or mpsinput))
- local mpsbase = file.stripsuffix(file.basename(mpsinput))
+ mpsformat = file.removesuffix(file.basename(mpsformat or texconfig.formatname or (tex and tex.formatname) or mpsinput))
+ local mpsbase = file.removesuffix(file.basename(mpsinput))
if mpsbase ~= mpsformat then
mpsformat = mpsformat .. "-" .. mpsbase
end
mpsformat = file.addsuffix(mpsformat, "mem")
- local pth = file.dirname(texconfig.formatname or "")
+ local pth = dirname or file.dirname(texconfig.formatname or "")
if pth ~= "" then
mpsformat = file.join(pth,mpsformat)
end
local the_version = environment.version or "unset version"
if lfs.isfile(mpsformat) then
- commands.writestatus("mplib","loading format: %s, name: %s", mpsinput, mpsformat)
+ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat)
local mpx, result = metapost.load(mpsformat)
if mpx then
local result = mpx:execute("show mp_parent_version ;")
@@ -183,31 +191,28 @@ function metapost.checkformat(mpsinput, mpsformat)
end
end
else
- commands.writestatus("mplib","error in loading format: %s, name: %s", mpsinput, mpsformat)
+ commands.writestatus("mplib","error in loading '%s' from '%s'", mpsinput, mpsformat)
metapost.reporterror(result)
end
end
- commands.writestatus("mplib","making format: %s, name: %s", mpsinput, mpsformat)
+ commands.writestatus("mplib","making '%s' into '%s'", mpsinput, mpsformat)
metapost.make(mpsinput,mpsformat,the_version) -- somehow return ... fails here
if lfs.isfile(mpsformat) then
- commands.writestatus("mplib","loading format: %s, name: %s", mpsinput, mpsformat)
+ commands.writestatus("mplib","loading '%s' from '%s'", mpsinput, mpsformat)
return metapost.load(mpsformat)
else
- commands.writestatus("mplib","problems with format: %s, name: %s", mpsinput, mpsformat)
+ commands.writestatus("mplib","problems with '%s' from '%s'", mpsinput, mpsformat)
end
end
---~ if environment.initex then
---~ metapost.unload(metapost.checkformat("metafun"))
---~ end
-
-local mpxformats = {}
+local mpxformats = { }
-function metapost.format(name)
- local mpx = mpxformats[name]
+function metapost.format(instance,name)
+ name = name or instance
+ local mpx = mpxformats[instance]
if not mpx then
mpx = metapost.checkformat(name)
- mpxformats[name] = mpx
+ mpxformats[instance] = mpx
end
return mpx
end
@@ -231,26 +236,25 @@ function metapost.reset(mpx)
end
end
-metapost.showlog = false
-
function metapost.process(mpx, data, trialrun, flusher, multipass)
local converted, result = false, {}
if type(mpx) == "string" then
mpx = metapost.format(mpx) -- goody
end
if mpx and data then
- input.starttiming(metapost)
+ statistics.starttiming(metapost)
if type(data) == "table" then
for i=1,#data do
local d = data[i]
if d then
- input.starttiming(metapost.exectime)
+ statistics.starttiming(metapost.exectime)
result = mpx:execute(d)
- input.stoptiming(metapost.exectime)
+ statistics.stoptiming(metapost.exectime)
if not metapost.reporterror(result) then
if metapost.showlog then
local str = (result.term ~= "" and result.term) or "no terminal output"
if not str:is_empty() then
+ metapost.lastlog = metapost.lastlog .. "\n" .. str
metapost.report("mp log: %s",str)
end
end
@@ -263,21 +267,25 @@ function metapost.process(mpx, data, trialrun, flusher, multipass)
end
end
else
- input.starttiming(metapost.exectime)
+ statistics.starttiming(metapost.exectime)
result = mpx:execute(data)
- input.stoptiming(metapost.exectime)
+ statistics.stoptiming(metapost.exectime)
-- todo: error message
if not result then
metapost.report("mp error: no result object returned")
elseif result.status > 0 then
metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
- elseif metapost.showlog then
- metapost.report("mp info: %s",result.term or "no-term")
- elseif result.fig then
- converted = metapost.convert(result, trialrun, flusher, multipass)
+ else
+ if metapost.showlog then
+ metapost.lastlog = metapost.lastlog .. "\n" .. result.term
+ metapost.report("mp info: %s",result.term or "no-term")
+ end
+ if result.fig then
+ converted = metapost.convert(result, trialrun, flusher, multipass)
+ end
end
end
- input.stoptiming(metapost)
+ statistics.stoptiming(metapost)
end
return converted, result
end
@@ -289,3 +297,64 @@ end
function metapost.report(...)
logs.report("mplib",...)
end
+
+-- handy
+
+function metapost.directrun(formatname,filename,outputformat,astable,mpdata)
+ local fullname = file.addsuffix(filename,"mp")
+ local data = mpdata or io.loaddata(fullname)
+ if outputformat ~= "svg" then
+ outputformat = "mps"
+ end
+ if not data then
+ logs.simple("unknown file '%s'",filename or "?")
+ else
+ local mpx = metapost.checkformat(formatname,formatname,caches.setpath("formats"))
+ if not mpx then
+ logs.simple("unknown format '%s'",formatname or "?")
+ else
+ logs.simple("processing '%s'",(mpdata and (filename or "data")) or fullname)
+ local result = mpx:execute(data)
+ if not result then
+ logs.simple("error: no result object returned")
+ elseif result.status > 0 then
+ logs.simple("error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
+ else
+ if metapost.showlog then
+ metapost.lastlog = metapost.lastlog .. "\n" .. result.term
+ logs.simple("info: %s",result.term or "no-term")
+ end
+ local figures = result.fig
+ if figures then
+ local sorted = table.sortedkeys(figures)
+ if astable then
+ local result = { }
+ logs.simple("storing %s figures in table",#sorted)
+ for k, v in ipairs(sorted) do
+ if outputformat == "mps" then
+ result[v] = figures[v]:postscript()
+ else
+ result[v] = figures[v]:svg() -- (3) for prologues
+ end
+ end
+ return result
+ else
+ local basename = file.removesuffix(file.basename(filename))
+ for k, v in ipairs(sorted) do
+ local output
+ if outputformat == "mps" then
+ output = figures[v]:postscript()
+ else
+ output = figures[v]:svg() -- (3) for prologues
+ end
+ local outname = format("%s-%s.%s",basename,v,outputformat)
+ logs.simple("saving %s bytes in '%s'",#output,outname)
+ io.savedata(outname,output)
+ end
+ return #sorted
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/tex/context/base/mtx-context-arrange.tex b/tex/context/base/mtx-context-arrange.tex
new file mode 100644
index 000000000..9d0bb901b
--- /dev/null
+++ b/tex/context/base/mtx-context-arrange.tex
@@ -0,0 +1,105 @@
+% engine=luatex
+
+%D \module
+%D [ file=mtx-context-arrange,
+%D version=2009.03.21,
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Arrange Files,
+%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 This is a \TEXEXEC\ features that has been moved to \MKIV.
+
+% begin help
+%
+% usage: context --extra=arrange [options] list-of-files
+%
+% --sort : sort filenames first
+% --paperoffset=dimension : left-top-offset
+% --noduplex : singlesided (doublesided is default)
+% --backspace=dimension : extra left offset
+% --topspace=dimension : extra top offset
+% --marking : add cutmarks
+% --addempty=list : add empty pages at/after (comma separated list)
+% --printformat : 2UP, etc
+%
+% end help
+
+\doifdocumentargument {paperoffset} {
+ \definepapersize
+ [offset=\getdocumentargument{paperoffset}]
+}
+
+\doifdocumentargumentelse {noduplex} {yes} {
+ \setuppagenumbering
+ [alternative=doublesided]
+ \setdocumentargument{sided}{doublesided}
+} {
+ \setdocumentargument{sided}{singlesided}
+}
+
+\setdefaultdocumentargument {textwidth} {0cm}
+\setdefaultdocumentargument {backspace} {0cm}
+\setdefaultdocumentargument {topspace} {0cm}
+
+\setuplayout
+ [backspace=\getdocumentargument{backspace},
+ topspace=\getdocumentargument{topspace},
+ width=middle,
+ height=middle,
+ location=middle,
+ header=0pt,
+ footer=0pt]
+
+\doifdocumentargument {marking} {yes} {
+ \setuplayout
+ [marking=on]
+}
+
+\startluacode
+ local printformat = document.arguments.printformat or ""
+ if printformat == "" then
+ printformat = "normal"
+ elseif string.find(printformat,".*up") then
+ printformat = "2UP,\\v!rotated"
+ elseif string.find(printformat,".*down") then
+ printformat = "2DOWN,\\v!rotated"
+ elseif string.find(printformat,".*side") then
+ printformat = "2SIDE,\\v!rotated"
+ end
+ document.setargument("printformat",printformat)
+\stopluacode
+
+\setuparranging
+ [\getdocumentargument{sided},
+ \getdocumentargument{printformat}]
+
+\starttext
+
+\startluacode
+ local format = string.format
+ local fprint = function(...) tex.sprint(tex.ctxcatcodes,format(...)) end
+
+ if #document.files > 0 then
+ if document.arguments.sort then
+ table.sort(document.files)
+ end
+ local emptypages = document.arguments.addempty or ""
+ local textwidth = document.arguments.textwidth or "0cm"
+ for _, filename in ipairs(document.files) do
+ if not string.find(filename,"^mtx%-context%-") then
+ fprint("\\insertpages[%s][%s][width=%s]",filename,emptypages,textwidth)
+ end
+ end
+ else
+ fprint("no files given")
+ end
+\stopluacode
+
+\stoptext
+
diff --git a/tex/context/base/mtx-context-combine.tex b/tex/context/base/mtx-context-combine.tex
new file mode 100644
index 000000000..991e974ae
--- /dev/null
+++ b/tex/context/base/mtx-context-combine.tex
@@ -0,0 +1,146 @@
+% engine=luatex
+
+%D \module
+%D [ file=mtx-context-combine,
+%D version=2009.03.21,
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Combine Files,
+%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 This is a \TEXEXEC\ features that has been moved to \MKIV.
+
+% begin help
+%
+% usage: context --extra=combine [options] list-of-files
+%
+% --sort : sort filenames first
+% --paperoffset=dimension : left-top-offset
+% --nobanner : no footer etc
+% --combination : h*v or hxv
+% --paperformat : paper*print or paperxprint
+% --nobanner : no footerlines
+% --bannerheight : height of banner
+% --bannerstring : height of bannerstring
+%
+% end help
+
+\doifdocumentargumentelse {paperoffset} {
+
+ \setuplayout
+ [topspace=\getdocumentargument{paperoffset},
+ backspace=\getdocumentargument{paperoffset}]
+
+} {
+
+ \setuplayout
+ [topspace=0pt,
+ backspace=0pt]
+
+}
+
+\setuplayout
+ [header=0pt,
+ footer=0pt,
+ width=middle,
+ height=middle]
+
+\startluacode
+ local combination = document.arguments['combination'] or '2*2'
+ local nx, ny = string.match(combination,"^(%d+)%s*[%*x]%s*(%d+)$")
+ if not nx then
+ nx, ny = 2, 2
+ elseif not ny then
+ nx = tonumber(combination) or 2
+ ny = nx
+ else
+ nx = tonumber(nx) or 2
+ ny = tonumber(ny) or nx or 2
+ end
+ document.setargument("nx",nx)
+ document.setargument("ny",ny)
+\stopluacode
+
+\startluacode
+ local paperformat = document.arguments['paperformat'] or 'A4*A4'
+ paperformat = string.upper(paperformat)
+ local f, t = string.match(paperformat,"^(.-)%s*[%*xX]%s*(.-)$")
+ if not f then
+ f, t = "A4", "A4"
+ elseif not t then
+ t = f
+ end
+ document.setargument("from",f)
+ document.setargument("to",t)
+\stopluacode
+
+\setuppapersize
+ [\getdocumentargument{from}]
+ [\getdocumentargument{to}]
+
+\doifnotdocumentargument {bannerheight} {
+ \setuplayout
+ [footer=1cm]
+}
+
+\doifdocumentargumentelse {nobanner} {yes} {
+ \setuplayout
+ [footer=0cm]
+ \setupbackgrounds
+ [page]
+ [background=]
+} {
+ \definelayer
+ [page]
+ [width=\paperwidth,
+ height=\paperheight]
+
+ \setupbackgrounds
+ [page]
+ [background=page]
+}
+
+\setupexternalfigures
+ [directory=]
+
+\starttext
+
+\startluacode
+ local format = string.format
+ local fprint = function(...) tex.sprint(tex.ctxcatcodes,format(...)) end
+
+ if #document.files > 0 then
+ if document.arguments["sort"] then
+ table.sort(document.files)
+ end
+ local dobanner = not document.arguments["nobanner"]
+ local bannerheight = document.arguments["bannerheight"]
+ local nx = document.arguments.nx or 2
+ local ny = document.arguments.ny or 2
+ for _, filename in ipairs(document.files) do
+ if not string.find(filename,"^mtx%-context%-") then
+ -- could be a macro
+ local bannerstring = format("\\tttf\\detokenize{%s}\\quad\\quad\\currentdate\\quad\\quad\\pagenumber",file.basename(filename))
+ if dobanner then
+ if bannerheight then
+ fprint("\\setuptexttexts[{\\setlayerframed[page][preset=middlebottom][frame=off,height=%s]{%s}}]",bannerheight,bannerstring)
+ else
+ fprint("\\setupfootertexts[{%s}]",bannerstring)
+ end
+ end
+ fprint("\\combinepages[%s][nx=%s,ny=%s]",filename,nx,ny)
+ fprint("\\page")
+ end
+ end
+ else
+ fprint("no files given")
+ end
+\stopluacode
+
+\stoptext
+
diff --git a/tex/context/base/mtx-context-ideas.tex b/tex/context/base/mtx-context-ideas.tex
new file mode 100644
index 000000000..f1ef1d35f
--- /dev/null
+++ b/tex/context/base/mtx-context-ideas.tex
@@ -0,0 +1,54 @@
+% engine=luatex
+
+%D \module
+%D [ file=mtx-context-ideas,
+%D version=2009.03.21,
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Placeholder File,
+%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.
+
+% The hard coded goodies in texexec are now external. We also use this
+% opportunity to explore mixed tex/lua user interfacing so you will see
+% some old and new tricks here that might disappear or become extended.
+%
+% if users want to add their own ... go ahead but use a different
+% namespace:
+%
+% mtx-context-third-somename.tex
+% mtx-context-user-somename.tex
+
+% \startluacode
+% -- some day we might move the whole ui to lua
+% context = context or { }
+% function interfaces.tosetups(setups)
+% if not setups then
+% return ""
+% elseif type(setups) == "table" then
+% local t = { }
+% for k,v in next, setups do
+% t[k] = "{" .. v .. "}"
+% end
+% return table.concat(t,",")
+% else
+% return setups
+% end
+% end
+% function context.setuplayout(category,setups)
+% setups = setups or category
+% tex.sprint(string.format("\\setuplayout[%s]",interfaces.tosetups(setups))
+% end
+% local topspace = document.arguments["topspace"] or 0
+% if dimen(topspace) > dimen(0) then
+% context.setuplayout { topspace = dimen(topspace) }
+% end
+% local backspace = document.arguments["backspace"] or 0
+% if dimen(topspace) > dimen(0) then
+% context.setuplayout { backspace = dimen(backspace) }
+% end
+% \stopluacode
diff --git a/tex/context/base/mtx-context-listing.tex b/tex/context/base/mtx-context-listing.tex
new file mode 100644
index 000000000..5c978fc6a
--- /dev/null
+++ b/tex/context/base/mtx-context-listing.tex
@@ -0,0 +1,76 @@
+% engine=luatex
+
+%D \module
+%D [ file=mtx-context-listing,
+%D version=2008.11.10, % about that time i started playing with this
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Listing Files,
+%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 This is a \TEXEXEC\ features that has been moved to \MKIV.
+
+% begin help
+%
+% usage: context --extra=listing [options] list-of-files
+%
+% --sort : sort filenames first
+% --topspace=dimension : distance above first line
+% --backspace=dimension : distance before left margin
+% --pretty : pretty print comform suffix (temporarily disabled)
+%
+% end help
+
+\setupbodyfont
+ [11pt,tt]
+
+\setuplayout
+ [header=0cm,
+ footer=1.5cm,
+ width=middle,
+ height=middle]
+
+% todo: use \arguments{topspace}
+
+\startluacode
+ local topspace = document.arguments["topspace"] or 0
+ if dimen(topspace) > dimen(0) then
+ tex.sprint(string.format("\\setuplayout[topspace=%s]",dimen(topspace)))
+ end
+ local backspace = document.arguments["backspace"] or 0
+ if dimen(topspace) > dimen(0) then
+ tex.sprint(string.format("\\setuplayout[backspace=%s]",dimen(backspace)))
+ end
+\stopluacode
+
+\setuptyping
+ [lines=yes]
+
+\setuptyping
+ [option=color]
+
+\starttext
+
+\startluacode
+ if #document.files > 0 then
+ if document.arguments["sort"] then
+ table.sort(document.files)
+ end
+ for _, filename in ipairs(document.files) do
+ if not string.find(filename,"^mtx%-context%-") then
+ tex.sprint("\\page\n")
+ tex.sprint(string.format("\\setupfootertexts[\\detokenize{%s}][\\pagenumber]\n",file.basename(filename)))
+ tex.sprint(string.format("\\typefile{%s}",filename))
+ end
+ end
+ else
+ tex.sprint(tex.ctxcatcodes,"no files given")
+ end
+\stopluacode
+
+\stoptext
diff --git a/tex/context/base/mtx-context-timing.tex b/tex/context/base/mtx-context-timing.tex
new file mode 100644
index 000000000..51e6427f6
--- /dev/null
+++ b/tex/context/base/mtx-context-timing.tex
@@ -0,0 +1,46 @@
+% engine=luatex
+
+%D \module
+%D [ file=mtx-context-timing,
+%D version=2009.03.21,
+%D title=\CONTEXT\ Extra Trickry,
+%D subtitle=Timing Runs,
+%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.
+
+% begin help
+%
+% usage: context --extra=timing filename
+%
+% end help
+
+\enablemode[no-timing] \usemodule[timing]
+
+\setuplayout
+ [topspace=1cm,
+ bottomspace=.5cm,
+ header=0pt,
+ width=middle,
+ height=middle,
+ style=\tt]
+
+\setupfootertexts
+ [\getdocumentfilename{1}-luatex-progress.lut -- \pagenumber]
+
+\setupcolors
+ [state=start]
+
+\starttext
+
+ \doifsomething {\getdocumentfilename{1}} {
+ \LoadUsage{\getdocumentfilename{1}-luatex-progress}
+ \ShowUsage{\getdocumentfilename{1}-luatex-progress}
+ }
+
+\stoptext
+
diff --git a/tex/context/base/mult-chk.lua b/tex/context/base/mult-chk.lua
new file mode 100644
index 000000000..1c74d2e38
--- /dev/null
+++ b/tex/context/base/mult-chk.lua
@@ -0,0 +1,66 @@
+if not modules then modules = { } end modules ['mult-chk'] = {
+ version = 1.001,
+ comment = "companion to mult-chk.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+local type = type
+local texsprint = tex.sprint
+local ctxcatcodes = tex.ctxcatcodes
+
+interfaces = interfaces or { }
+
+interfaces.syntax = {
+ test = { keys = table.tohash { "a","b","c","d","e","f","g" } }
+}
+
+function interfaces.invalidkey(kind,key)
+ commands.writestatus("syntax","invalid key '%s' for '%s' in line %s",key,kind,tex.inputlineno)
+end
+
+function interfaces.setvalidkeys(kind,list)
+ local s = interfaces.syntax[kind]
+ if not s then
+ interfaces.syntax[kind] = {
+ keys = aux.settings_to_set(list)
+ }
+ else
+ s.keys = aux.settings_to_set(list)
+ end
+end
+
+function interfaces.addvalidkeys(kind,list)
+ local s = interfaces.syntax[kind]
+ if not s then
+ interfaces.syntax[kind] = {
+ keys = aux.settings_to_set(list)
+ }
+ else
+ aux.settings_to_set(list,s.keys)
+ end
+end
+
+local prefix, kind, keys
+
+local function set(key,value)
+ if keys and not keys[key] then
+ interfaces.invalidkey(kind,key)
+ else
+ texsprint(ctxcatcodes,format("\\setsomevalue{%s}{%s}{%s}",prefix,key,value))
+ end
+end
+
+local pattern = aux.make_settings_to_hash_pattern(set,true)
+
+function commands.getcheckedparameters(k,p,s)
+ if s and s ~= "" then
+ prefix, kind = p, k
+ keys = k and k ~= "" and interfaces.syntax[k].keys
+ pattern:match(s)
+ end
+end
+
+_gcp_ = commands.getcheckedparameters
diff --git a/tex/context/base/mult-chk.mkii b/tex/context/base/mult-chk.mkii
new file mode 100644
index 000000000..6299d0cda
--- /dev/null
+++ b/tex/context/base/mult-chk.mkii
@@ -0,0 +1,26 @@
+%D \module
+%D [ file=mult-chk,
+%D version=2009.04.13,
+%D title=\CONTEXT\ Multilingual Macros,
+%D subtitle=Checking,
+%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.
+
+\writestatus{loading}{ConTeXt Multilingual Macros / Checking}
+
+%D No checking in \MKII.
+
+\def\setvalidparameterkeys{\gobbleparameters} % forward reference, so no \let
+\def\addvalidparameterkeys{\gobbleparameters} % forward reference, so no \let
+
+\let\enablecheckparameters \relax
+\let\disablecheckparameters\relax
+
+\def\getcheckedparameters[#1]{\getparameters} % just ignore the checking
+
+\endinput
diff --git a/tex/context/base/mult-chk.mkiv b/tex/context/base/mult-chk.mkiv
new file mode 100644
index 000000000..7b40bd64a
--- /dev/null
+++ b/tex/context/base/mult-chk.mkiv
@@ -0,0 +1,103 @@
+%D \module
+%D [ file=mult-chk,
+%D version=2009.04.13,
+%D title=\CONTEXT\ Multilingual Macros,
+%D subtitle=Checking,
+%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.
+
+\writestatus{loading}{ConTeXt Multilingual Macros / Checking}
+
+%D This is very experimental code that eventually might be used
+%D once we have split the whole code base.
+
+%D \startbuffer
+%D \getcheckedparameters[MyTest][MyNamespace][a=1,b=2,c=3,d=4,crap=whatever]
+%D
+%D \MyNamespacea\quad
+%D \MyNamespaceb\quad
+%D \MyNamespacec\quad
+%D \MyNamespaced\quad
+%D crap is \ifdefined\MyNamespacecrap\else un\fi defined
+%D \stopbuffer
+%D
+%D \enablecheckparameters
+%D
+%D \setvalidparameterkeys[MyTest][a,b,c,d] \getbuffer \par
+%D \addvalidparameterkeys[MyTest][crap] \getbuffer \par
+
+\unprotect
+
+\registerctxluafile{mult-chk}{1.001}
+
+\def\setvalidparameterkeys{\dodoubleargument\dosetvalidparameterkeys}
+\def\addvalidparameterkeys{\dodoubleargument\doaddvalidparameterkeys}
+
+\def\dosetvalidparameterkeys[#1][#2]{\ctxlua{interfaces.setvalidkeys("#1",\!!bs#2\!!es)}}
+\def\doaddvalidparameterkeys[#1][#2]{\ctxlua{interfaces.addvalidkeys("#1",\!!bs#2\!!es)}}
+
+\def\getcheckedparametersyes[#1]#2[#3]#4[#5%
+ {\if\noexpand#5]%
+ \expandafter\gobblethreearguments
+ \else
+ \let\setsomevalue\dosetvalue
+ \expandafter\dogetcheckedparametersyes
+ \fi{#1}{#3}#5}
+
+\def\dogetcheckedparametersyes#1#2#3]%
+ {\ctxlua{_gcp_("#1","#2",\!!bs\detokenize{#3}\!!es)}}
+
+\def\getcheckedparametersnop[#1]#2[#3]#4[#5%
+ {\if\noexpand#5]%
+ \expandafter\gobbletwoarguments
+ \else
+ \let\setsomevalue\dosetvalue
+ \expandafter\dogetcheckedparametersnop
+ \fi{#3}#5}
+
+\def\dogetcheckedparametersnop#1#2]%
+ {\def\p!dogetparameter{\p!doassign#1}%
+ \xprocesscommaitem#2,],\@relax@}
+
+\def\disablecheckparameters{\let\getcheckedparameters\getcheckedparametersnop}
+\def\enablecheckparameters {\let\getcheckedparameters\getcheckedparametersyes}
+
+\disablecheckparameters
+
+\protect \endinput
+
+\starttext
+
+\testfeatureonce{10000}{\getcheckedparameters[test][xx][a=b,c= d, e = f]} % 0.20 seconds
+
+\enablecheckparameters
+
+\testfeatureonce{10000}{\getcheckedparameters[test][xx][a=b,c= d, e = f]} % 0.35 seconds
+
+\getcheckedparameters[test][xx][a=a]
+\getcheckedparameters[test][xx][b= b]
+\getcheckedparameters[test][xx][c = c]
+\getcheckedparameters[test][xx][d = d d , e = e ,f = f ]
+\getcheckedparameters[test][xx][g={oeps {oeps}}]
+\getcheckedparameters[test][xx][crap=whatever]
+
+\startlines
+[a:\getvalue{xxa}][a]
+[b:\getvalue{xxb}][b]
+[c:\getvalue{xxc}][c]
+[d:\getvalue{xxd}][d d ]
+[e:\getvalue{xxe}][e ]
+[f:\getvalue{xxf}][f ]
+[g:\getvalue{xxg}][\detokenize\expandafter{\xxg}]
+\stoplines
+
+\setvalidparameterkeys[test][crap]
+
+\getcheckedparameters[test][xx][crap=whatever]
+
+\stoptext
diff --git a/tex/context/base/mult-de.tex b/tex/context/base/mult-de.tex
index b408dad2f..8c47126fe 100644
--- a/tex/context/base/mult-de.tex
+++ b/tex/context/base/mult-de.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{nach}
\setinterfacevariable{all}{alles}
\setinterfacevariable{always}{immer}
+\setinterfacevariable{answerarea}{answerarea}
\setinterfacevariable{appendices}{anhaenge}
\setinterfacevariable{appendix}{anhang}
\setinterfacevariable{april}{April}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{lefthanging}
\setinterfacevariable{leftmargin}{linkerrand}
\setinterfacevariable{leftpage}{linkerseite}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legende}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{zeile}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normal}
\setinterfacevariable{nospacing}{nospacing}
\setinterfacevariable{not}{nicht}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{nothanging}
\setinterfacevariable{nothyphenated}{nothyphenated}
\setinterfacevariable{november}{November}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{righthanging}
\setinterfacevariable{rightmargin}{rechterrand}
\setinterfacevariable{rightpage}{rechterseite}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{antiqua}
\setinterfacevariable{romannumerals}{roemischezahlen}
\setinterfacevariable{rotate}{drehe}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{unterunterunterunterthema}
\setinterfacevariable{subsubsubsubsubsection}{unterunterunterunterunterabsatz}
\setinterfacevariable{subsubsubsubsubsubject}{unterunterunterunterunterthema}
+\setinterfacevariable{subsubsubsubsubsubsection}{unterunterunterunterunterunterabsatz}
+\setinterfacevariable{subsubsubsubsubsubsubject}{unterunterunterunterunterunterthema}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{unterunterunterunterunterunterunterabsatz}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{unterunterunterunterunterunterunterthema}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{unterunterunterunterunterunterunterunterabsatz}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{unterunterunterunterunterunterunterunterthema}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{unterunterunterunterunterunterunterunterunterabsatz}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{unterunterunterunterunterunterunterunterunterthema}
\setinterfacevariable{sunday}{sonntag}
\setinterfacevariable{support}{support}
\setinterfacevariable{sym}{sym}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{fliesstext}
\setinterfaceconstant{bookmark}{bookmark}
\setinterfaceconstant{bottom}{unten}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{abstandunten}
\setinterfaceconstant{bottomframe}{untenrahmen}
\setinterfaceconstant{bottomoffset}{untenoffset}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{component}
\setinterfaceconstant{compoundhyphen}{compoundhyphen}
\setinterfaceconstant{compress}{compress}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{fortsetzen}
\setinterfaceconstant{contrastcolor}{kontrastfarbe}
\setinterfaceconstant{controls}{controls}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{fieldlayer}
\setinterfaceconstant{fieldoffset}{feldoffset}
\setinterfaceconstant{file}{datei}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusout}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{hoehe}
\setinterfaceconstant{hfactor}{hfaktor}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{hoffset}
\setinterfaceconstant{horoffset}{rumpfabstand}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{nummer}
\setinterfaceconstant{numbercolor}{nummernfarbe}
\setinterfaceconstant{numbercommand}{nummerbefehl}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{numberdistance}
\setinterfaceconstant{numbering}{nummerierung}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{nummernseperator}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{nummernstil}
\setinterfaceconstant{numberwidth}{numberwidth}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{seitenbegrenzung}
\setinterfaceconstant{pagecolor}{seitenfarbe}
\setinterfaceconstant{pagecommand}{seitenbefehl}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{seitennummer}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{pagestate}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{seitenstil}
\setinterfaceconstant{palet}{palette}
\setinterfaceconstant{paper}{papier}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{setzetrenner}
\setinterfaceconstant{position}{position}
\setinterfaceconstant{prefix}{prefix}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{voreinstellung}
\setinterfaceconstant{preview}{vorschau}
\setinterfaceconstant{previous}{vorige}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{reduktion}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{referenz}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{referieren}
\setinterfaceconstant{regionin}{regionin}
\setinterfaceconstant{regionout}{regionaus}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{liniendicke}
\setinterfaceconstant{samepage}{selbeseite}
\setinterfaceconstant{sample}{muster}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{format}
\setinterfaceconstant{scope}{bereich}
\setinterfaceconstant{screen}{raster}
\setinterfaceconstant{section}{abschnitt}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{abschnittsnummer}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{seperator}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{setups}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{yschritt}
% definitions for interface elements for language de
%
+\setinterfaceelement{answerlines}{answerlines}
+\setinterfaceelement{answerspace}{answerspace}
\setinterfaceelement{begin}{anfang}
\setinterfaceelement{complete}{vollende}
\setinterfaceelement{coupled}{verknuepft}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{settext}
\setinterfacecommand{settextvariable}{settextvariable}
\setinterfacecommand{setupalign}{stelleausrichtungein}
+\setinterfacecommand{setupanswerarea}{setupanswerarea}
\setinterfacecommand{setuparranging}{stelleanordnenein}
\setinterfacecommand{setupbackground}{stellehintergrundein}
\setinterfacecommand{setupbackgrounds}{stellehintergruendeein}
diff --git a/tex/context/base/mult-def.lua b/tex/context/base/mult-def.lua
index b0999fd2e..b447f2467 100644
--- a/tex/context/base/mult-def.lua
+++ b/tex/context/base/mult-def.lua
@@ -3571,6 +3571,16 @@ return {
["pe"]="بارگذاری‌تنظیم",
["ro"]="seteazaalinierea",
},
+ ["setupanswerarea"]={
+ ["cs"]="setupanswerarea",
+ ["de"]="setupanswerarea",
+ ["en"]="setupanswerarea",
+ ["fr"]="setupanswerarea",
+ ["it"]="setupanswerarea",
+ ["nl"]="stelantwoordgebiedin",
+ ["pe"]="setupanswerarea",
+ ["ro"]="setupanswerarea",
+ },
["setuparranging"]={
["cs"]="nastavusporadani",
["de"]="stelleanordnenein",
@@ -6912,6 +6922,12 @@ return {
["pe"]="پایین",
["ro"]="jos",
},
+ ["bottomafter"]={
+ ["en"]="bottomafter",
+ },
+ ["bottombefore"]={
+ ["en"]="bottombefore",
+ },
["bottomdistance"]={
["cs"]="vzdalenostspodku",
["de"]="abstandunten",
@@ -7182,6 +7198,9 @@ return {
["pe"]="فشردن",
["ro"]="compress",
},
+ ["connector"]={
+ ["en"]="connector",
+ },
["continue"]={
["cs"]="pokracovat",
["de"]="fortsetzen",
@@ -7642,6 +7661,9 @@ return {
["pe"]="پرونده",
["ro"]="fisier",
},
+ ["filtercommand"]={
+ ["en"]="filtercommand",
+ },
["focus"]={
["cs"]="zaostreni",
["de"]="focus",
@@ -7710,7 +7732,6 @@ return {
["it"]="coloreprimopiano",
["nl"]="voorgrondkleur",
["pe"]="رنگ‌پیش‌زمینه",
-
["ro"]="foregroundcolor",
},
["foregroundstyle"]={
@@ -7973,6 +7994,9 @@ return {
["pe"]="پرکردن‌ارتفاع",
["ro"]="hfil",
},
+ ["hidenumber"]={
+ ["en"]="hidenumber",
+ },
["hoffset"]={
["cs"]="hoffset",
["de"]="hoffset",
@@ -8853,6 +8877,12 @@ return {
["pe"]="فرمان‌شماره",
["ro"]="comandanumar",
},
+ ["numberconversion"]={
+ ["en"]="numberconversion",
+ },
+ ["numberconversionset"]={
+ ["en"]="numberconversionset",
+ },
["numberdistance"]={
["cs"]="numberdistance",
["de"]="numberdistance",
@@ -8873,6 +8903,15 @@ return {
["pe"]="شماره‌گذاری",
["ro"]="numerotare",
},
+ ["numberorder"]={
+ ["en"]="numberorder",
+ },
+ ["numberprefix"]={
+ ["en"]="numberprefix",
+ },
+ ["numbersegments"]={
+ ["en"]="numbersegments",
+ },
["numberseparator"]={
["cs"]="oddelovaccisla",
["de"]="nummernseperator",
@@ -8883,6 +8922,15 @@ return {
["pe"]="جداکننده‌شماره",
["ro"]="separatornumar",
},
+ ["numberseparatorset"]={
+ ["en"]="numberseparatorset",
+ },
+ ["numberset"]={
+ ["en"]="numberset",
+ },
+ ["numberstopper"]={
+ ["en"]="numberstopper",
+ },
["numberstyle"]={
["cs"]="stylcisla",
["de"]="nummernstil",
@@ -9073,6 +9121,12 @@ return {
["pe"]="فرمان‌صفحه",
["ro"]="comandapagina",
},
+ ["pageconversion"]={
+ ["en"]="pageconversion",
+ },
+ ["pageconversionset"]={
+ ["en"]="pageconversionset",
+ },
["pagenumber"]={
["cs"]="cislostranky",
["de"]="seitennummer",
@@ -9083,6 +9137,39 @@ return {
["pe"]="شماره‌صفحه",
["ro"]="numarpagina",
},
+ ["pageprefix"]={
+ ["en"]="pageprefix",
+ },
+ ["pageprefixconnector"]={
+ ["en"]="pageprefixconnector",
+ },
+ ["pageprefixconversion"]={
+ ["en"]="pageprefixconversion",
+ },
+ ["pageprefixconversionset"]={
+ ["en"]="pageprefixconversionset",
+ },
+ ["pageprefixsegments"]={
+ ["en"]="pageprefixsegments",
+ },
+ ["pageprefixseparatorset"]={
+ ["en"]="pageprefixseparatorset",
+ },
+ ["pageprefixset"]={
+ ["en"]="pageprefixset",
+ },
+ ["pageprefixstopper"]={
+ ["en"]="pageprefixstopper",
+ },
+ ["pagesegments"]={
+ ["en"]="pagesegments",
+ },
+ ["pageseparatorset"]={
+ ["en"]="pageseparatorset",
+ },
+ ["pageset"]={
+ ["en"]="pageset",
+ },
["pagestate"]={
["cs"]="pagestate",
["de"]="pagestate",
@@ -9093,6 +9180,9 @@ return {
["pe"]="وضعیت‌صفحه",
["ro"]="pagestate",
},
+ ["pagestopper"]={
+ ["en"]="pagestopper",
+ },
["pagestyle"]={
["cs"]="stylstranky",
["de"]="seitenstil",
@@ -9183,6 +9273,27 @@ return {
["pe"]="پیشوند",
["ro"]="prefix",
},
+ ["prefixconnector"]={
+ ["en"]="prefixconnector",
+ },
+ ["prefixconversion"]={
+ ["en"]="prefixconversion",
+ },
+ ["prefixconversionset"]={
+ ["en"]="prefixconversionset",
+ },
+ ["prefixsegments"]={
+ ["en"]="prefixsegments",
+ },
+ ["prefixseparatorset"]={
+ ["en"]="prefixseparatorset",
+ },
+ ["prefixset"]={
+ ["en"]="prefixset",
+ },
+ ["prefixstopper"]={
+ ["en"]="prefixstopper",
+ },
["preset"]={
["cs"]="prednastaveni",
["de"]="voreinstellung",
@@ -9283,6 +9394,9 @@ return {
["pe"]="مرجع",
["ro"]="referinta",
},
+ ["referenceprefix"]={
+ ["en"]="referenceprefix",
+ },
["referencing"]={
["cs"]="odkazujici",
["de"]="referieren",
@@ -9593,6 +9707,9 @@ return {
["pe"]="نمونه",
["ro"]="exemplu",
},
+ ["saveinlist"]={
+ ["en"]="saveinlist",
+ },
["scale"]={
["cs"]="meritko",
["de"]="format",
@@ -9633,6 +9750,12 @@ return {
["pe"]="بخش",
["ro"]="sectiune",
},
+ ["sectionconversion"]={
+ ["en"]="sectionconversion",
+ },
+ ["sectionconversionset"]={
+ ["en"]="sectionconversionset",
+ },
["sectionnumber"]={
["cs"]="cislooddilu",
["de"]="abschnittsnummer",
@@ -9643,6 +9766,18 @@ return {
["pe"]="شماره‌بخش",
["ro"]="numarsectiune",
},
+ ["sectionsegments"]={
+ ["en"]="sectionsegments",
+ },
+ ["sectionseparatorset"]={
+ ["en"]="sectionseparatorset",
+ },
+ ["sectionset"]={
+ ["en"]="sectionset",
+ },
+ ["sectionstopper"]={
+ ["en"]="sectionstopper",
+ },
["separator"]={
["cs"]="oddelovac",
["de"]="seperator",
@@ -10615,6 +10750,26 @@ return {
},
},
["elements"]={
+ ["answerlines"]={
+ ["cs"]="answerlines",
+ ["de"]="answerlines",
+ ["en"]="answerlines",
+ ["fr"]="answerlines",
+ ["it"]="answerlines",
+ ["nl"]="antwoordregels",
+ ["pe"]="answerlines",
+ ["ro"]="answerlines",
+ },
+ ["answerspace"]={
+ ["cs"]="answerspace",
+ ["de"]="answerspace",
+ ["en"]="answerspace",
+ ["fr"]="answerspace",
+ ["it"]="answerspace",
+ ["nl"]="antwoordruimte",
+ ["pe"]="answerspace",
+ ["ro"]="answerspace",
+ },
["begin"]={
["cs"]="zacatek",
["de"]="anfang",
@@ -11537,6 +11692,16 @@ return {
["pe"]="همواره",
["ro"]="totdeauna",
},
+ ["answerarea"]={
+ ["cs"]="answerarea",
+ ["de"]="answerarea",
+ ["en"]="answerarea",
+ ["fr"]="answerarea",
+ ["it"]="answerarea",
+ ["nl"]="antwoordgebied",
+ ["pe"]="answerarea",
+ ["ro"]="answerarea",
+ },
["appendices"]={
["cs"]="dodatky",
["de"]="anhaenge",
@@ -13227,6 +13392,16 @@ return {
["pe"]="صفحه‌چپ",
["ro"]="paginastanga",
},
+ ["lefttoright"]={
+ ["cs"]="lefttoright",
+ ["de"]="lefttoright",
+ ["en"]="lefttoright",
+ ["fr"]="lefttoright",
+ ["it"]="lefttoright",
+ ["nl"]="lefttoright",
+ ["pe"]="lefttoright",
+ ["ro"]="lefttoright",
+ },
["legend"]={
["cs"]="legenda",
["de"]="legende",
@@ -13807,6 +13982,9 @@ return {
["pe"]="بدون",
["ro"]="nu",
},
+ ["note"]={
+ ["en"]="note",
+ },
["nothanging"]={
["cs"]="nothanging",
["de"]="nothanging",
@@ -14447,6 +14625,16 @@ return {
["pe"]="صفحه‌راست",
["ro"]="paginadreapta",
},
+ ["righttoleft"]={
+ ["cs"]="righttoleft",
+ ["de"]="righttoleft",
+ ["en"]="righttoleft",
+ ["fr"]="righttoleft",
+ ["it"]="righttoleft",
+ ["nl"]="righttoleft",
+ ["pe"]="righttoleft",
+ ["ro"]="righttoleft",
+ },
["roman"]={
["cs"]="antikva",
["de"]="antiqua",
@@ -15137,6 +15325,86 @@ return {
["pe"]="زیرزیرزیرزیرزیرموضوع",
["ro"]="subsubsubsubsubsubiect",
},
+ ["subsubsubsubsubsubsection"]={
+ ["cs"]="podpodpodpodpodpodsekce",
+ ["de"]="unterunterunterunterunterunterabsatz",
+ ["en"]="subsubsubsubsubsubsection",
+ ["fr"]="soussoussoussoussoussoussection",
+ ["it"]="sottosottosottosottosottosottocapoverso",
+ ["nl"]="subsubsubsubsubsubparagraaf",
+ ["pe"]="زیرزیرزیرزیرزیرزیربخش",
+ ["ro"]="subsubsubsubsubsubsectiune",
+ },
+ ["subsubsubsubsubsubsubject"]={
+ ["cs"]="podpodpodpodpodpodtema",
+ ["de"]="unterunterunterunterunterunterthema",
+ ["en"]="subsubsubsubsubsubsubject",
+ ["fr"]="soussoussoussoussoussoussujet",
+ ["it"]="sottosottosottosottosottosottoargomento",
+ ["nl"]="subsubsubsubsubsubonderwerp",
+ ["pe"]="زیرزیرزیرزیرزیرزیرموضوع",
+ ["ro"]="subsubsubsubsubsubsubiect",
+ },
+ ["subsubsubsubsubsubsubsection"]={
+ ["cs"]="podpodpodpodpodpodpodsekce",
+ ["de"]="unterunterunterunterunterunterunterabsatz",
+ ["en"]="subsubsubsubsubsubsubsection",
+ ["fr"]="soussoussoussoussoussoussoussection",
+ ["it"]="sottosottosottosottosottosottosottocapoverso",
+ ["nl"]="subsubsubsubsubsubsubparagraaf",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیربخش",
+ ["ro"]="subsubsubsubsubsubsubsectiune",
+ },
+ ["subsubsubsubsubsubsubsubject"]={
+ ["cs"]="podpodpodpodpodpodpodtema",
+ ["de"]="unterunterunterunterunterunterunterthema",
+ ["en"]="subsubsubsubsubsubsubsubject",
+ ["fr"]="soussoussoussoussoussoussoussujet",
+ ["it"]="sottosottosottosottosottosottosottoargomento",
+ ["nl"]="subsubsubsubsubsubsubonderwerp",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیرموضوع",
+ ["ro"]="subsubsubsubsubsubsubsubiect",
+ },
+ ["subsubsubsubsubsubsubsubsection"]={
+ ["cs"]="podpodpodpodpodpodpodpodsekce",
+ ["de"]="unterunterunterunterunterunterunterunterabsatz",
+ ["en"]="subsubsubsubsubsubsubsubsection",
+ ["fr"]="soussoussoussoussoussoussoussoussection",
+ ["it"]="sottosottosottosottosottosottosottosottocapoverso",
+ ["nl"]="subsubsubsubsubsubsubsubparagraaf",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیرزیربخش",
+ ["ro"]="subsubsubsubsubsubsubsubsectiune",
+ },
+ ["subsubsubsubsubsubsubsubsubject"]={
+ ["cs"]="podpodpodpodpodpodpodpodtema",
+ ["de"]="unterunterunterunterunterunterunterunterthema",
+ ["en"]="subsubsubsubsubsubsubsubsubject",
+ ["fr"]="soussoussoussoussoussoussoussoussujet",
+ ["it"]="sottosottosottosottosottosottosottosottoargomento",
+ ["nl"]="subsubsubsubsubsubsubsubonderwerp",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیرزیرموضوع",
+ ["ro"]="subsubsubsubsubsubsubsubsubiect",
+ },
+ ["subsubsubsubsubsubsubsubsubsection"]={
+ ["cs"]="podpodpodpodpodpodpodpodpodsekce",
+ ["de"]="unterunterunterunterunterunterunterunterunterabsatz",
+ ["en"]="subsubsubsubsubsubsubsubsubsection",
+ ["fr"]="soussoussoussoussoussoussoussoussoussection",
+ ["it"]="sottosottosottosottosottosottosottosottosottocapoverso",
+ ["nl"]="subsubsubsubsubsubsubsubsubparagraaf",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیرزیرزیربخش",
+ ["ro"]="subsubsubsubsubsubsubsubsubsectiune",
+ },
+ ["subsubsubsubsubsubsubsubsubsubject"]={
+ ["cs"]="podpodpodpodpodpodpodpodpodtema",
+ ["de"]="unterunterunterunterunterunterunterunterunterthema",
+ ["en"]="subsubsubsubsubsubsubsubsubsubject",
+ ["fr"]="soussoussoussoussoussoussoussoussoussujet",
+ ["it"]="sottosottosottosottosottosottosottosottosottoargomento",
+ ["nl"]="subsubsubsubsubsubsubsubsubonderwerp",
+ ["pe"]="زیرزیرزیرزیرزیرزیرزیرزیرزیرموضوع",
+ ["ro"]="subsubsubsubsubsubsubsubsubsubiect",
+ },
["sunday"]={
["cs"]="nedele",
["de"]="sonntag",
diff --git a/tex/context/base/mult-def.tex b/tex/context/base/mult-def.tex
index c49e6ffac..cff9fb074 100644
--- a/tex/context/base/mult-def.tex
+++ b/tex/context/base/mult-def.tex
@@ -22,6 +22,14 @@
\setvalue{@interface@persian@}{pe}
\setvalue{@interface@romanian@}{ro}
-\input mult-\ifcsname @interface@\defaultinterface @\endcsname\csname @interface@\defaultinterface @\endcsname\else en\fi\relax
+% \def\userinterfacetag
+% {\ifcsname @interface@\defaultinterface @\endcsname\csname @interface@\defaultinterface @\endcsname\else en\fi}
+\def\userinterfacetag
+ {\ifcsname @interface@\currentinterface @\endcsname\csname @interface@\currentinterface @\endcsname\else en\fi}
+\def\userresponsestag
+ {\ifcsname @interface@\currentresponses @\endcsname\csname @interface@\currentresponses @\endcsname\else en\fi}
+
+\input mult-\userinterfacetag \relax
+\input mult-m\userresponsestag \relax
\protect \endinput
diff --git a/tex/context/base/mult-en.tex b/tex/context/base/mult-en.tex
index 1fdc9799e..16058f794 100644
--- a/tex/context/base/mult-en.tex
+++ b/tex/context/base/mult-en.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{after}
\setinterfacevariable{all}{all}
\setinterfacevariable{always}{always}
+\setinterfacevariable{answerarea}{answerarea}
\setinterfacevariable{appendices}{appendices}
\setinterfacevariable{appendix}{appendix}
\setinterfacevariable{april}{April}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{lefthanging}
\setinterfacevariable{leftmargin}{leftmargin}
\setinterfacevariable{leftpage}{leftpage}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legend}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{line}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normal}
\setinterfacevariable{nospacing}{nospacing}
\setinterfacevariable{not}{not}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{nothanging}
\setinterfacevariable{nothyphenated}{nothyphenated}
\setinterfacevariable{november}{November}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{righthanging}
\setinterfacevariable{rightmargin}{rightmargin}
\setinterfacevariable{rightpage}{rightpage}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{roman}
\setinterfacevariable{romannumerals}{romannumerals}
\setinterfacevariable{rotate}{rotate}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{subsubsubsubsubject}
\setinterfacevariable{subsubsubsubsubsection}{subsubsubsubsubsection}
\setinterfacevariable{subsubsubsubsubsubject}{subsubsubsubsubsubject}
+\setinterfacevariable{subsubsubsubsubsubsection}{subsubsubsubsubsubsection}
+\setinterfacevariable{subsubsubsubsubsubsubject}{subsubsubsubsubsubsubject}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsection}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubject}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubsection}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubsubject}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubsubsection}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubsubsubject}
\setinterfacevariable{sunday}{sunday}
\setinterfacevariable{support}{support}
\setinterfacevariable{sym}{sym}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{bodyfont}
\setinterfaceconstant{bookmark}{bookmark}
\setinterfaceconstant{bottom}{bottom}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{bottomdistance}
\setinterfaceconstant{bottomframe}{bottomframe}
\setinterfaceconstant{bottomoffset}{bottomoffset}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{component}
\setinterfaceconstant{compoundhyphen}{compoundhyphen}
\setinterfaceconstant{compress}{compress}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{continue}
\setinterfaceconstant{contrastcolor}{contrastcolor}
\setinterfaceconstant{controls}{controls}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{fieldlayer}
\setinterfaceconstant{fieldoffset}{fieldoffset}
\setinterfaceconstant{file}{file}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusout}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{height}
\setinterfaceconstant{hfactor}{hfactor}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{hoffset}
\setinterfaceconstant{horoffset}{horoffset}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{number}
\setinterfaceconstant{numbercolor}{numbercolor}
\setinterfaceconstant{numbercommand}{numbercommand}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{numberdistance}
\setinterfaceconstant{numbering}{numbering}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{numberseparator}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{numberstyle}
\setinterfaceconstant{numberwidth}{numberwidth}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{pageboundaries}
\setinterfaceconstant{pagecolor}{pagecolor}
\setinterfaceconstant{pagecommand}{pagecommand}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{pagenumber}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{pagestate}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{pagestyle}
\setinterfaceconstant{palet}{palet}
\setinterfaceconstant{paper}{paper}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{placestopper}
\setinterfaceconstant{position}{position}
\setinterfaceconstant{prefix}{prefix}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{preset}
\setinterfaceconstant{preview}{preview}
\setinterfaceconstant{previous}{previous}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{reduction}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{reference}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{referencing}
\setinterfaceconstant{regionin}{regionin}
\setinterfaceconstant{regionout}{regionout}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{rulethickness}
\setinterfaceconstant{samepage}{samepage}
\setinterfaceconstant{sample}{sample}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{scale}
\setinterfaceconstant{scope}{scope}
\setinterfaceconstant{screen}{screen}
\setinterfaceconstant{section}{section}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{sectionnumber}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{separator}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{setups}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{ystep}
% definitions for interface elements for language en
%
+\setinterfaceelement{answerlines}{answerlines}
+\setinterfaceelement{answerspace}{answerspace}
\setinterfaceelement{begin}{begin}
\setinterfaceelement{complete}{complete}
\setinterfaceelement{coupled}{coupled}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{settextcontent}
\setinterfacecommand{settextvariable}{settextvariable}
\setinterfacecommand{setupalign}{setupalign}
+\setinterfacecommand{setupanswerarea}{setupanswerarea}
\setinterfacecommand{setuparranging}{setuparranging}
\setinterfacecommand{setupbackground}{setupbackground}
\setinterfacecommand{setupbackgrounds}{setupbackgrounds}
diff --git a/tex/context/base/mult-fr.tex b/tex/context/base/mult-fr.tex
index 1dc2b2b4f..11a305ac8 100644
--- a/tex/context/base/mult-fr.tex
+++ b/tex/context/base/mult-fr.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{apres}
\setinterfacevariable{all}{tout}
\setinterfacevariable{always}{toujours}
+\setinterfacevariable{answerarea}{answerarea}
\setinterfacevariable{appendices}{annexes}
\setinterfacevariable{appendix}{annexe}
\setinterfacevariable{april}{avril}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{lefthanging}
\setinterfacevariable{leftmargin}{margegauche}
\setinterfacevariable{leftpage}{pagegauche}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legende}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{ligne}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normal}
\setinterfacevariable{nospacing}{sansespacement}
\setinterfacevariable{not}{pas}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{nonsuspendu}
\setinterfacevariable{nothyphenated}{nothyphenated}
\setinterfacevariable{november}{novembre}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{righthanging}
\setinterfacevariable{rightmargin}{margedroite}
\setinterfacevariable{rightpage}{pagedroite}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{roman}
\setinterfacevariable{romannumerals}{chiffresromains}
\setinterfacevariable{rotate}{oriente}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{soussoussoussoussujet}
\setinterfacevariable{subsubsubsubsubsection}{soussoussoussoussoussection}
\setinterfacevariable{subsubsubsubsubsubject}{soussoussoussoussoussujet}
+\setinterfacevariable{subsubsubsubsubsubsection}{soussoussoussoussoussoussection}
+\setinterfacevariable{subsubsubsubsubsubsubject}{soussoussoussoussoussoussujet}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{soussoussoussoussoussoussoussection}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{soussoussoussoussoussoussoussujet}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{soussoussoussoussoussoussoussoussection}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{soussoussoussoussoussoussoussoussujet}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{soussoussoussoussoussoussoussoussoussection}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{soussoussoussoussoussoussoussoussoussujet}
\setinterfacevariable{sunday}{dimanche}
\setinterfacevariable{support}{support}
\setinterfacevariable{sym}{sym}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{policecorps}
\setinterfaceconstant{bookmark}{marquepage}
\setinterfaceconstant{bottom}{inf}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{distanceinf}
\setinterfaceconstant{bottomframe}{cadreinf}
\setinterfaceconstant{bottomoffset}{decalageinf}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{composant}
\setinterfaceconstant{compoundhyphen}{compoundhyphen}
\setinterfaceconstant{compress}{compress}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{continue}
\setinterfaceconstant{contrastcolor}{coleurcontraste}
\setinterfaceconstant{controls}{controles}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{calquechamp}
\setinterfaceconstant{fieldoffset}{offsetchamp}
\setinterfaceconstant{file}{fichier}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusout}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{hauteur}
\setinterfaceconstant{hfactor}{facteurhauteur}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{decalagehauteur}
\setinterfaceconstant{horoffset}{horoffset}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{numero}
\setinterfaceconstant{numbercolor}{couleurnumero}
\setinterfaceconstant{numbercommand}{commandenumero}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{numberdistance}
\setinterfaceconstant{numbering}{numerotation}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{separateurnumbero}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{stylenumero}
\setinterfaceconstant{numberwidth}{numberwidth}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{limitespage}
\setinterfaceconstant{pagecolor}{couleurpage}
\setinterfaceconstant{pagecommand}{commandepage}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{numeropage}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{etatpage}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{stylepage}
\setinterfaceconstant{palet}{palette}
\setinterfaceconstant{paper}{papier}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{emplacementstopper}
\setinterfaceconstant{position}{position}
\setinterfaceconstant{prefix}{prefixe}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{prereglage}
\setinterfaceconstant{preview}{previsualisation}
\setinterfaceconstant{previous}{precedent}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{reduction}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{reference}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{referencing}
\setinterfaceconstant{regionin}{entreregion}
\setinterfaceconstant{regionout}{regionexterieure}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{epaisseurligne}
\setinterfaceconstant{samepage}{memepage}
\setinterfaceconstant{sample}{echantillon}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{echelle}
\setinterfaceconstant{scope}{scope}
\setinterfaceconstant{screen}{ecran}
\setinterfaceconstant{section}{section}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{numerosection}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{separateur}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{reglages}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{ystep}
% definitions for interface elements for language fr
%
+\setinterfaceelement{answerlines}{answerlines}
+\setinterfaceelement{answerspace}{answerspace}
\setinterfaceelement{begin}{debut}
\setinterfaceelement{complete}{complete}
\setinterfaceelement{coupled}{couple}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{settext}
\setinterfacecommand{settextvariable}{affectevariabletexte}
\setinterfacecommand{setupalign}{reglealignement}
+\setinterfacecommand{setupanswerarea}{setupanswerarea}
\setinterfacecommand{setuparranging}{reglearrangement}
\setinterfacecommand{setupbackground}{reglearriereplan}
\setinterfacecommand{setupbackgrounds}{reglearriereplans}
diff --git a/tex/context/base/mult-his.tex b/tex/context/base/mult-his.tex
index 40010499d..fe87d4bcf 100644
--- a/tex/context/base/mult-his.tex
+++ b/tex/context/base/mult-his.tex
@@ -33,7 +33,7 @@
%D message : floatblocks/13
%D variables : sorttype compress autohang
-\writestatus{loading}{Context Multilingual Macros / Initialization}
+\writestatus{loading}{ConTeXt Multilingual Macros / Initialization}
\unprotect
@@ -328,11 +328,7 @@
%D example of a library.
%D
%D \starttyping
-%D \startmessages english library: alfa
-%D title: something
-%D 1: first message
-%D 2: second (--) message --
-%D \stopmessages
+%D % messages moved
%D \stoptyping
%D
%D The first message is a simple one and can be shown with:
@@ -361,9 +357,7 @@
%D once. We can add messages to a library in the following way:
%D
%D \starttyping
-%D \startmessages english library: alfa
-%D 10: tenth message
-%D \stopmessages
+%D % messages moved
%D \stoptyping
%D
%D Because such definitions can take place in different
@@ -1141,9 +1135,7 @@
{\writeline\writebanner{\contextbanner}\writeline}
\edef\formatversion
- {\ifx\normalyear \undefined\the\year \else\the\normalyear \fi.%
- \ifx\normalmonth\undefined\the\month\else\the\normalmonth\fi.%
- \ifx\normalday \undefined\the\day \else\the\normalday \fi}
+ {\the\normalyear.\the\normalmonth.\the\normalday}
\ifx\contextversion\undefined
\def\contextversion {unknown}
@@ -1153,9 +1145,8 @@
\edef\contextversionnumber{\expandafter\contextversionnumber\contextversion\relax\space\contextmark}
\fi
-\ifx\undefined\normaldump
+\ifx\undefined\everydump
\newtoks\everydump
- \let\normaldump\dump
\def\dump{\the\everydump\normaldump}
\fi
diff --git a/tex/context/base/mult-ini.lua b/tex/context/base/mult-ini.lua
index 9133633eb..1eee9a656 100644
--- a/tex/context/base/mult-ini.lua
+++ b/tex/context/base/mult-ini.lua
@@ -6,47 +6,56 @@ if not modules then modules = { } end modules ['mult-ini'] = {
license = "see context related readme files"
}
-local format = string.format
+local format, gmatch = string.format, string.gmatch
interfaces = interfaces or { }
interfaces.messages = interfaces.messages or { }
interfaces.constants = interfaces.constants or { }
interfaces.variables = interfaces.variables or { }
-input.storage.register(false,"interfaces/messages", interfaces.messages, "interfaces.messages" )
-input.storage.register(false,"interfaces/constants", interfaces.constants, "interfaces.constants")
-input.storage.register(false,"interfaces/variables", interfaces.variables, "interfaces.variables")
+storage.register("interfaces/messages", interfaces.messages, "interfaces.messages" )
+storage.register("interfaces/constants", interfaces.constants, "interfaces.constants")
+storage.register("interfaces/variables", interfaces.variables, "interfaces.variables")
-function interfaces.setmessage(category,str)
+function interfaces.setmessages(category,str)
local m = interfaces.messages[category] or { }
- for k, v in str:gmatch("(%S+) *: *(.-) *[\n\r]") do
+ for k, v in gmatch(str,"(%S+) *: *(.-) *[\n\r]") do
m[k] = v:gsub("%-%-","%%s")
end
interfaces.messages[category] = m
end
+function interfaces.setmessage(category,tag,message)
+ local m = interfaces.messages[category]
+ if not m then
+ m = { }
+ interfaces.messages[category] = m
+ end
+ m[tag] = message:gsub("%-%-","%%s")
+end
+
function interfaces.getmessage(category,tag)
local m = interfaces.messages[category]
return (m and m[tag]) or "unknown message"
end
+local messagesplitter = lpeg.splitat(",")
+
function interfaces.makemessage(category,tag,arguments)
local m = interfaces.messages[category]
- m = (m and m[tag] ) or "unknown message"
+ m = (m and m[tag] ) or format("unknown message, category '%s', tag '%s'",category,tag)
if not m then
return m .. " " .. tag
elseif not arguments then
return m
- elseif arguments:find(",") then
- return format(m,unpack(arguments:splitchr(",")))
else
- return format(m,arguments)
+ return format(m,messagesplitter:match(arguments))
end
end
function interfaces.showmessage(category,tag,arguments)
local m = interfaces.messages[category]
- ctx.writestatus((m and m.title) or "unknown title",interfaces.makemessage(category,tag,arguments))
+ commands.writestatus((m and m.title) or "unknown title",interfaces.makemessage(category,tag,arguments))
end
function interfaces.setvariable(variable,given)
diff --git a/tex/context/base/mult-ini.mkii b/tex/context/base/mult-ini.mkii
index 8697057c8..c2bb40861 100644
--- a/tex/context/base/mult-ini.mkii
+++ b/tex/context/base/mult-ini.mkii
@@ -15,7 +15,7 @@
%D which we keep around as \type {mult-kep.tex} for sentimental
%D reasons. There you will find some more historic information.
-\writestatus{loading}{Context Multilingual Macros / Initialization}
+\writestatus{loading}{ConTeXt Multilingual Macros / Initialization}
\unprotect
@@ -438,7 +438,7 @@
{\definemessageconstant{#2}% handy for modules
\bgroup
\obeylines
- \doifundefined{\m!prefix!#2}{\setgvalue{\m!prefix!#2}{#2}}%
+ \ifcsname\m!prefix!#2\endcsname\else\setgvalue{\m!prefix!#2}{#2}\fi
\doifinsetelse{#1}{\currentresponses,all}
{\def\next
{\def\currentmessagelibrary{#2}%
@@ -460,6 +460,10 @@
\setxvalue{\??ms\currentmessagelibrary#1}{#2}%
\futurelet\next\getinterfacemessage}
+\def\setinterfacemessage#1#2#3%
+ {\ifcsname\m!prefix!#1\endcsname\else\setgvalue{\m!prefix!#1}{#1}\fi
+ \expandafter\def\csname\??ms#1#2\endcsname{#3}}
+
%D \macros
%D {ifshowwarnings, ifshowmessages}
%D
@@ -911,9 +915,7 @@
{\writeline\writebanner{\contextbanner}\writeline}
\edef\formatversion
- {\ifx\normalyear \undefined\the\year \else\the\normalyear \fi.%
- \ifx\normalmonth\undefined\the\month\else\the\normalmonth\fi.%
- \ifx\normalday \undefined\the\day \else\the\normalday \fi}
+ {\the\normalyear.\the\normalmonth.\the\normalday}
\ifx\contextversion\undefined
\def\contextversion {unknown}
@@ -923,9 +925,8 @@
\edef\contextversionnumber{\expandafter\contextversionnumber\contextversion\relax\space\contextmark}
\fi
-\ifx\undefined\normaldump
+\ifx\undefined\everydump
\newtoks\everydump
- \let\normaldump\dump
\def\dump{\the\everydump\normaldump}
\fi
diff --git a/tex/context/base/mult-ini.mkiv b/tex/context/base/mult-ini.mkiv
index c83a0b61d..2d1e2cc0e 100644
--- a/tex/context/base/mult-ini.mkiv
+++ b/tex/context/base/mult-ini.mkiv
@@ -15,7 +15,7 @@
%D which we keep around as \type {mult-kep.tex} for sentimental
%D reasons. There you will find some more historic information.
-\writestatus{loading}{Context Multilingual Macros / Initialization}
+\writestatus{loading}{ConTeXt Multilingual Macros / Initialization}
\unprotect
@@ -107,13 +107,14 @@
%D used more than once. Savings like this should of course be
%D implemented in english, just because \TEX\ is english.
-\def\!!width {width}
-\def\!!height {height}
-\def\!!depth {depth}
-\def\!!plus {plus}
-\def\!!minus {minus}
-\def\!!fill {fill}
-\def\!!to {to}
+\def\!!width {width}
+\def\!!height{height}
+\def\!!depth {depth}
+\def\!!plus {plus}
+\def\!!minus {minus}
+\def\!!fill {fill}
+\def\!!to {to}
+\def\!!spread{spread}
%D \macros
%D {defineinterfaceconstant,
@@ -240,8 +241,8 @@
\fi
-\ifx\currentinterface\undefined \let\currentinterface=\defaultinterface \fi
-\ifx\currentresponses\undefined \let\currentresponses=\defaultinterface \fi
+\ifx\currentinterface\undefined \let\currentinterface\defaultinterface \fi
+\ifx\currentresponses\undefined \let\currentresponses\defaultinterface \fi
%D \macros
%D {startinterface}
@@ -356,12 +357,16 @@
\doifinsetelse{#1}{\currentresponses,all}\dostartmessages\nostartmessages{#2}}
\def\dostartmessages#1#2\stopmessages
- {\ctxlua{interfaces.setmessage("#1",[[#2]])}%
+ {\ctxlua{interfaces.setmessages("#1",\!!bs#2\!!es)}%
\egroup}
\def\nostartmessages#1#2\stopmessages
{\egroup}
+\def\setinterfacemessage#1#2#3%
+ {\ifcsname\m!prefix!#1\endcsname\else\setgvalue{\m!prefix!#1}{#1}\fi
+ \ctxlua{interfaces.setmessage("#1","#2",\!!bs#3\!!es)}}
+
\unexpanded\def\setmessagetext #1#2{\edef\currentmessagetext{\ctxlua{tex.sprint(tex.ctxcatcodes,interfaces.getmessage("#1","#2"))}}}
\unexpanded\def\getmessage #1#2{\ctxlua{tex.sprint(tex.ctxcatcodes,interfaces.getmessage("#1","#2"))}}
\unexpanded\def\makemessage #1#2#3{\ctxlua{tex.sprint(tex.ctxcatcodes,interfaces.makemessage("#1","#2","#3"))}}
@@ -821,9 +826,7 @@
{\writeline\writebanner{\contextbanner}\writeline}
\edef\formatversion
- {\ifx\normalyear \undefined\the\year \else\the\normalyear \fi.%
- \ifx\normalmonth\undefined\the\month\else\the\normalmonth\fi.%
- \ifx\normalday \undefined\the\day \else\the\normalday \fi}
+ {\the\normalyear .\the\normalmonth.\the\normalday}
\ifx\contextversion\undefined
\def\contextversion {unknown}
@@ -833,9 +836,8 @@
\edef\contextversionnumber{\expandafter\contextversionnumber\contextversion\relax\space\contextmark}
\fi
-\ifx\undefined\normaldump
+\ifx\undefined\everydump
\newtoks\everydump
- \let\normaldump\dump
\def\dump{\the\everydump\normaldump}
\fi
diff --git a/tex/context/base/mult-it.tex b/tex/context/base/mult-it.tex
index e08d169d1..b62c5bdb3 100644
--- a/tex/context/base/mult-it.tex
+++ b/tex/context/base/mult-it.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{dopo}
\setinterfacevariable{all}{tutti}
\setinterfacevariable{always}{sempre}
+\setinterfacevariable{answerarea}{answerarea}
\setinterfacevariable{appendices}{appendici}
\setinterfacevariable{appendix}{appendice}
\setinterfacevariable{april}{aprile}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{lefthanging}
\setinterfacevariable{leftmargin}{marginesinistro}
\setinterfacevariable{leftpage}{paginasinistra}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legenda}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{riga}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normale}
\setinterfacevariable{nospacing}{nospacing}
\setinterfacevariable{not}{non}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{nonsospeso}
\setinterfacevariable{nothyphenated}{nonsillabato}
\setinterfacevariable{november}{novembre}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{righthanging}
\setinterfacevariable{rightmargin}{marginedestro}
\setinterfacevariable{rightpage}{paginadestra}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{roman}
\setinterfacevariable{romannumerals}{numeriromani}
\setinterfacevariable{rotate}{ruota}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{sottosottosottosottoargomento}
\setinterfacevariable{subsubsubsubsubsection}{sottosottosottosottosottocapoverso}
\setinterfacevariable{subsubsubsubsubsubject}{sottosottosottosottosottoargomento}
+\setinterfacevariable{subsubsubsubsubsubsection}{sottosottosottosottosottosottocapoverso}
+\setinterfacevariable{subsubsubsubsubsubsubject}{sottosottosottosottosottosottoargomento}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{sottosottosottosottosottosottosottocapoverso}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{sottosottosottosottosottosottosottoargomento}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{sottosottosottosottosottosottosottosottocapoverso}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{sottosottosottosottosottosottosottosottoargomento}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{sottosottosottosottosottosottosottosottosottocapoverso}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{sottosottosottosottosottosottosottosottosottoargomento}
\setinterfacevariable{sunday}{domenica}
\setinterfacevariable{support}{supporto}
\setinterfacevariable{sym}{sim}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{fonttesto}
\setinterfaceconstant{bookmark}{segnalibro}
\setinterfaceconstant{bottom}{fondo}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{distanzafondo}
\setinterfaceconstant{bottomframe}{cornicefondo}
\setinterfaceconstant{bottomoffset}{offsetfondo}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{component}
\setinterfaceconstant{compoundhyphen}{compoundhyphen}
\setinterfaceconstant{compress}{compress}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{continua}
\setinterfaceconstant{contrastcolor}{colorecontrasto}
\setinterfaceconstant{controls}{controlli}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{fieldlayer}
\setinterfaceconstant{fieldoffset}{offsetcampo}
\setinterfaceconstant{file}{file}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusout}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{altezza}
\setinterfaceconstant{hfactor}{hfactor}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{hoffset}
\setinterfaceconstant{horoffset}{horoffset}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{numero}
\setinterfaceconstant{numbercolor}{colorenumero}
\setinterfaceconstant{numbercommand}{comandonumero}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{numberdistance}
\setinterfaceconstant{numbering}{numerazione}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{separatorenumero}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{stilenumero}
\setinterfaceconstant{numberwidth}{numberwidth}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{limitipagina}
\setinterfaceconstant{pagecolor}{colorepagina}
\setinterfaceconstant{pagecommand}{comandopagina}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{numeropagina}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{statopagina}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{stilepagina}
\setinterfaceconstant{palet}{tavolozza}
\setinterfaceconstant{paper}{carta}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{mettistopper}
\setinterfaceconstant{position}{posizione}
\setinterfaceconstant{prefix}{prefisso}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{preimpostato}
\setinterfaceconstant{preview}{anteprima}
\setinterfaceconstant{previous}{precedente}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{riduzione}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{riferimento}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{referencing}
\setinterfaceconstant{regionin}{entraregione}
\setinterfaceconstant{regionout}{esciregione}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{spessorelinea}
\setinterfaceconstant{samepage}{stessapagina}
\setinterfaceconstant{sample}{campione}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{scala}
\setinterfaceconstant{scope}{scope}
\setinterfaceconstant{screen}{schermo}
\setinterfaceconstant{section}{sezione}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{numerosezione}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{separatore}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{setups}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{ystep}
% definitions for interface elements for language it
%
+\setinterfaceelement{answerlines}{answerlines}
+\setinterfaceelement{answerspace}{answerspace}
\setinterfaceelement{begin}{inizio}
\setinterfaceelement{complete}{completo}
\setinterfaceelement{coupled}{accoppiato}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{settext}
\setinterfacecommand{settextvariable}{setvariabiletesto}
\setinterfacecommand{setupalign}{impostaallineamento}
+\setinterfacecommand{setupanswerarea}{setupanswerarea}
\setinterfacecommand{setuparranging}{impostaparranging}
\setinterfacecommand{setupbackground}{impostasfondo}
\setinterfacecommand{setupbackgrounds}{impostasfondi}
diff --git a/tex/context/base/mult-mcs.tex b/tex/context/base/mult-mcs.tex
new file mode 100644
index 000000000..bee7b777d
--- /dev/null
+++ b/tex/context/base/mult-mcs.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{neznama reference --}
+\setinterfacemessage{references}{3}{neznamy typ reference --}
+\setinterfacemessage{references}{2}{duplicitni reference -- na strane --}
+\setinterfacemessage{references}{4}{nedovolena reference --}
+\setinterfacemessage{references}{title}{reference}
+\setinterfacemessage{references}{30}{neznamy objekt --}
+\setinterfacemessage{references}{31}{duplicitni object --}
+\setinterfacemessage{references}{21}{dokument -- nacten}
+\setinterfacemessage{references}{22}{dokument -- neni interaktivni}
+\setinterfacemessage{references}{23}{obskurni (nejasna) reference -- (prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{system}
+\setinterfacemessage{systems}{41}{externi soubor -- ve skupine -- neexistuje}
+\setinterfacemessage{systems}{9}{-- nenalezeno/nezpracovano}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{nova verze pomocneho souboru, je treba druheho behu}
+\setinterfacemessage{systems}{21}{pomocny soubor necten}
+\setinterfacemessage{systems}{20}{vyznam (trideni) -- nacten}
+\setinterfacemessage{systems}{5}{makra z -- nactena}
+\setinterfacemessage{systems}{4}{prikaz -- je jiz definovan}
+\setinterfacemessage{systems}{27}{verze}
+\setinterfacemessage{systems}{26}{registry}
+\setinterfacemessage{systems}{25}{reference}
+\setinterfacemessage{systems}{24}{plovouci bloky}
+\setinterfacemessage{systems}{1}{nacteni pomocneho souboru odlozeno (typemode)}
+\setinterfacemessage{systems}{23}{-- upraveno na --}
+\setinterfacemessage{systems}{22}{pouzijte platny pomocny soubor}
+\setinterfacemessage{systems}{2}{-- nacteno}
+\setinterfacemessage{systems}{19}{vyznam (synonyma) -- nacten}
+\setinterfacemessage{systems}{18}{synonymum -- -- neexistuje}
+\setinterfacemessage{systems}{7}{makra z -- jsou jiz nactena}
+\setinterfacemessage{systems}{6}{zadna makra v -- nenalezena}
+\setinterfacemessage{systems}{14}{vynucena nova stranka v seznamu na --}
+\setinterfacemessage{systems}{15}{uklada se buffer --}
+\setinterfacemessage{systems}{16}{sazi se buffer --}
+\setinterfacemessage{systems}{17}{sazi se doslovny (verbatim) buffer --}
+\setinterfacemessage{systems}{13}{znacka -- definovana --}
+\setinterfacemessage{systems}{12}{pomosny soubor neni setriden, pouzijte texutil}
+\setinterfacemessage{systems}{11}{vytvarim jednoduchy pomocny soubor}
+\setinterfacemessage{systems}{10}{nepouzivejte em v --}
+\setinterfacemessage{floatblocks}{1}{-- precislovano / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- presunuto}
+\setinterfacemessage{floatblocks}{2}{-- ulozeno}
+\setinterfacemessage{floatblocks}{5}{poradi prizpusobeno}
+\setinterfacemessage{floatblocks}{4}{-- umisteno}
+\setinterfacemessage{floatblocks}{7}{pocet spodnich plovoucich objektu je omezen na --}
+\setinterfacemessage{floatblocks}{6}{pocet hornich plovoucich objektu je omezen na --}
+\setinterfacemessage{floatblocks}{9}{poradi naruseno}
+\setinterfacemessage{floatblocks}{8}{radku je mene nez --}
+\setinterfacemessage{floatblocks}{title}{plovouciobjekty}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{nedefinovano}
+\setinterfacemessage{floatblocks}{11}{nedan zadny blok}
+\setinterfacemessage{floatblocks}{10}{-- omezeno}
+\setinterfacemessage{interactions}{1}{pomer -- x -- (s x v)}
+\setinterfacemessage{interactions}{3}{neaktivni}
+\setinterfacemessage{interactions}{2}{aktivni}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{zadna strankova synchronizace (--) v hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interakce}
+\setinterfacemessage{interactions}{21}{-- kod vlozen}
+\setinterfacemessage{structures}{1}{zacatek oddilu (sekce) --}
+\setinterfacemessage{structures}{title}{struktury}
+\setinterfacemessage{structures}{2}{konec oddilu (sekce) --}
+\setinterfacemessage{linguals}{1}{vzory -- pro -- nacteny (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{deleni slov -- pro -- nacteno (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{zadne vzory -- pro -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{vzory pro -- nenacteny}
+\setinterfacemessage{linguals}{4}{zadne deleni slov -- pro -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{specificke volby jazyka [--] zavadeji -- (zavlecenou) mezeru}
+\setinterfacemessage{linguals}{6}{jazyk -- neni definovan}
+\setinterfacemessage{linguals}{9}{language -- is active}
+\setinterfacemessage{linguals}{8}{specificke volby jazyka [--] bez mezer pripojeny}
+\setinterfacemessage{linguals}{title}{jazyky}
+\setinterfacemessage{linguals}{10}{vzory --nacteny}
+\setinterfacemessage{regimes}{1}{kodovani --}
+\setinterfacemessage{regimes}{3}{nezname kodovani --}
+\setinterfacemessage{regimes}{2}{je nacteno kodovani --}
+\setinterfacemessage{regimes}{title}{kodovani}
+\setinterfacemessage{filters}{1}{filter -- is loaded}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{soubor -- neexistuje}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{kodovani --}
+\setinterfacemessage{encodings}{3}{nezname kodovani --}
+\setinterfacemessage{encodings}{2}{je nacteno kodovani --}
+\setinterfacemessage{encodings}{title}{kodovani}
+\setinterfacemessage{columns}{1}{je mozno pouze -- sloupcu}
+\setinterfacemessage{columns}{3}{problem, vypina se vyvazovani}
+\setinterfacemessage{columns}{2}{pouzijte \string\filbreak\space jako alternativu}
+\setinterfacemessage{columns}{5}{spodni plovouci objekt jeste neni podporovan}
+\setinterfacemessage{columns}{4}{horni plovouci objekt jeste neni podporovan}
+\setinterfacemessage{columns}{7}{vyvazovani ukonceno po 100 krocich}
+\setinterfacemessage{columns}{6}{-- plovouci objekt(y) odlozeny}
+\setinterfacemessage{columns}{9}{kontrola nerovnost}
+\setinterfacemessage{columns}{8}{vyvazeno v -- krocich}
+\setinterfacemessage{columns}{title}{sloupce}
+\setinterfacemessage{columns}{13}{siroky plovouci objekt je presunut nad sloupce}
+\setinterfacemessage{columns}{12}{plovouci objekt je presunut do nasledujiciho sloupce / --}
+\setinterfacemessage{columns}{11}{plovouci objekt je pro sloupec prilis siroky}
+\setinterfacemessage{columns}{10}{zbyl (mene nez) 1 radek}
+\setinterfacemessage{textblocks}{1}{nova verze, je treba druhy beh}
+\setinterfacemessage{textblocks}{3}{ctu bloky z --}
+\setinterfacemessage{textblocks}{2}{zapisuji bloky do --}
+\setinterfacemessage{textblocks}{5}{-- neni skryto}
+\setinterfacemessage{textblocks}{4}{je treba druhy beh}
+\setinterfacemessage{textblocks}{7}{-- skryto}
+\setinterfacemessage{textblocks}{6}{-- skryto a zpracovano}
+\setinterfacemessage{textblocks}{9}{-- nevysazeno}
+\setinterfacemessage{textblocks}{8}{-- vysazeno}
+\setinterfacemessage{textblocks}{title}{textovyblok}
+\setinterfacemessage{textblocks}{12}{-- preskoceno}
+\setinterfacemessage{textblocks}{11}{-- nacteno a vysazeno}
+\setinterfacemessage{textblocks}{10}{-- nacteno a zpracovano}
+\setinterfacemessage{symbols}{1}{nacita se soubor symbolu --}
+\setinterfacemessage{symbols}{title}{symboly}
+\setinterfacemessage{versions}{1}{postradam @+}
+\setinterfacemessage{versions}{3}{oznacene strany: --}
+\setinterfacemessage{versions}{2}{oznacuji se strany}
+\setinterfacemessage{versions}{title}{verze}
+\setinterfacemessage{specials}{1}{-- nacteno}
+\setinterfacemessage{specials}{3}{-- je resetovano}
+\setinterfacemessage{specials}{2}{neni dovoleno hlubsi zanoreni --}
+\setinterfacemessage{specials}{5}{nacita se definicni soubor --}
+\setinterfacemessage{specials}{4}{prikaz -- neexistuje}
+\setinterfacemessage{specials}{7}{neznamy ovladac (driver) --}
+\setinterfacemessage{specials}{6}{zanoreni neni dovoleno}
+\setinterfacemessage{specials}{title}{speciality}
+\setinterfacemessage{javascript}{1}{nacita se soubor skriptu --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{neznama preambule --}
+\setinterfacemessage{fonts}{1}{kodovani --}
+\setinterfacemessage{fonts}{3}{neznama varianta --}
+\setinterfacemessage{fonts}{2}{varianta -- je nactena}
+\setinterfacemessage{fonts}{5}{styl -- neni definovan}
+\setinterfacemessage{fonts}{4}{zakladni font -- neni definovan}
+\setinterfacemessage{fonts}{7}{neznamy format --}
+\setinterfacemessage{fonts}{6}{-- je nacten}
+\setinterfacemessage{fonts}{14}{bodyfont -- is defined (can better be done global)}
+\setinterfacemessage{fonts}{8}{styl -- definovan}
+\setinterfacemessage{fonts}{title}{zakladnifont}
+\setinterfacemessage{fonts}{10}{neznamy font --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{global file --}
+\setinterfacemessage{databases}{2}{local file --}
+\setinterfacemessage{databases}{4}{unknown file --}
+\setinterfacemessage{databases}{title}{databases}
+\setinterfacemessage{colors}{1}{system -- je globalne aktivovana}
+\setinterfacemessage{colors}{3}{-- neni definovana --}
+\setinterfacemessage{colors}{2}{system -- je lokalne activovana}
+\setinterfacemessage{colors}{5}{neznamy system --}
+\setinterfacemessage{colors}{4}{system -- je nacten}
+\setinterfacemessage{colors}{7}{palette -- neni k dispozici}
+\setinterfacemessage{colors}{6}{palette -- je k dispozici}
+\setinterfacemessage{colors}{9}{-- prostor barev neni podporovan}
+\setinterfacemessage{colors}{8}{specifikace -- v barve -- bude cerna}
+\setinterfacemessage{colors}{title}{barva}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{barva je prevedena na sed}
+\setinterfacemessage{colors}{10}{-- prostor barev je podporovan}
+\setinterfacemessage{layouts}{1}{vyska textu prizpusobena s -- na strane --}
+\setinterfacemessage{layouts}{3}{-- krat text odlozen}
+\setinterfacemessage{layouts}{2}{-- krat odlozeny text umisten}
+\setinterfacemessage{layouts}{5}{okrajove bloky neaktivni}
+\setinterfacemessage{layouts}{4}{okrajove bloky aktivni}
+\setinterfacemessage{layouts}{7}{pocita se misto pro logo}
+\setinterfacemessage{layouts}{6}{sada stran -- zpracovana (velikost --)}
+\setinterfacemessage{layouts}{9}{aktualne ne vice nez -- urovne/urovni vyctu}
+\setinterfacemessage{layouts}{8}{pocita se pozadi}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{svisla mezera -- neni povolena v pevnem radkovem rejstriku}
+\setinterfacemessage{layouts}{10}{-- a -- nedava dohromady 1.0}
+\setinterfacemessage{check}{1}{postradam '=' po '--' na radku --}
+\setinterfacemessage{check}{3}{-- -- nahrazuje makro, uzijte VERZALKY!}
+\setinterfacemessage{check}{2}{ocekavam -- argument(y) na radku --}
+\setinterfacemessage{check}{title}{kontrola}
+\setinterfacemessage{metapost}{1}{loading metapost library --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{synonymum souboru -- je jiz pouzito pro --}
+\setinterfacemessage{files}{title}{soubory}
+\setinterfacemessage{figures}{1}{obraz -- nelze nalezt}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{obraz -- nepritomen}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimenze obrazu -- nacteny primo z jeho souboru}
+\setinterfacemessage{figures}{6}{dimenze obrazu -- spocteny programem rlxtools}
+\setinterfacemessage{figures}{8}{obrazovy objekt -- je znovu pouzit}
+\setinterfacemessage{figures}{title}{obrazy}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mde.tex b/tex/context/base/mult-mde.tex
new file mode 100644
index 000000000..a80ac4306
--- /dev/null
+++ b/tex/context/base/mult-mde.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{unbekannte Referenz --}
+\setinterfacemessage{references}{3}{unbekannte Referenz Typ --}
+\setinterfacemessage{references}{2}{doppelte Referenz -- auf Seite --}
+\setinterfacemessage{references}{4}{illegale Referenz --}
+\setinterfacemessage{references}{title}{referenzen}
+\setinterfacemessage{references}{30}{unbekanntes Object --}
+\setinterfacemessage{references}{31}{doppeltes Object --}
+\setinterfacemessage{references}{21}{Dokument -- geladen}
+\setinterfacemessage{references}{22}{Dokument -- ist nicht aktiv}
+\setinterfacemessage{references}{23}{Obskure Referenz -- (Prefix=--)}
+\setinterfacemessage{documents}{1}{Blatt --}
+\setinterfacemessage{documents}{title}{Blaetter}
+\setinterfacemessage{documents}{2}{Nummer --}
+\setinterfacemessage{handlings}{1}{Font Verarbeitung --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{Font Verarbeitung -- ist geladen}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{system}
+\setinterfacemessage{systems}{41}{Externe Datei -- in Gruppe -- existiert nicht}
+\setinterfacemessage{systems}{9}{-- nicht gefunden/verarbeitet}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{Neue Version der Hilfsdatei, zweiter Durchlauf benoetigt}
+\setinterfacemessage{systems}{21}{Die Hilfsdatei ist nicht geladen}
+\setinterfacemessage{systems}{20}{Bedeutung (sortieren) von -- geladen}
+\setinterfacemessage{systems}{5}{Modul -- geladen}
+\setinterfacemessage{systems}{4}{Befehl -- ist bereits definiert}
+\setinterfacemessage{systems}{27}{Version}
+\setinterfacemessage{systems}{26}{Register}
+\setinterfacemessage{systems}{25}{Referenzen}
+\setinterfacemessage{systems}{24}{Fliessbloecke}
+\setinterfacemessage{systems}{1}{Laden der Hilfsdatei aufgeschoben (Eingabe-Modus)}
+\setinterfacemessage{systems}{23}{-- angeordnet auf --}
+\setinterfacemessage{systems}{22}{Benoetige gueltige Hilfsdateie}
+\setinterfacemessage{systems}{2}{-- geladen}
+\setinterfacemessage{systems}{19}{Bedeutung (synonyme) von -- geladen}
+\setinterfacemessage{systems}{18}{Synonym -- -- existiert nicht}
+\setinterfacemessage{systems}{7}{Modul -- bereits geladen}
+\setinterfacemessage{systems}{6}{Modul -- gefunden}
+\setinterfacemessage{systems}{14}{Erzwungendes Seitenumbruch in Liste bei --}
+\setinterfacemessage{systems}{15}{Speichere Buffer --}
+\setinterfacemessage{systems}{16}{Setzte Buffer --}
+\setinterfacemessage{systems}{17}{Setzte tippen-Buffer --}
+\setinterfacemessage{systems}{13}{Beschriftung -- definiert --}
+\setinterfacemessage{systems}{12}{Die Hilfdatei ist nicht sortiert, verwende texutil}
+\setinterfacemessage{systems}{11}{Erstelle einfache Hilfdatei}
+\setinterfacemessage{systems}{10}{Benutzte kein em in --}
+\setinterfacemessage{floatblocks}{1}{-- neu nummeriert / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- verschoben}
+\setinterfacemessage{floatblocks}{2}{-- gespeichert}
+\setinterfacemessage{floatblocks}{5}{Reihenfolge angepasst}
+\setinterfacemessage{floatblocks}{4}{-- plaziert}
+\setinterfacemessage{floatblocks}{7}{Anz. der unteren Gleitobjekte beschraengt auf --}
+\setinterfacemessage{floatblocks}{6}{Anz. der oberen Gleitobjekte beschraengt auf --}
+\setinterfacemessage{floatblocks}{9}{Reigenfolge gestoert}
+\setinterfacemessage{floatblocks}{8}{weniger als -- zeilen}
+\setinterfacemessage{floatblocks}{title}{Gleitobjektbloecke}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{undefiniert}
+\setinterfacemessage{floatblocks}{11}{kein Block gegeben}
+\setinterfacemessage{floatblocks}{10}{-- begrenzt}
+\setinterfacemessage{interactions}{1}{Seitenverhaeltnis -- x -- (B x H)}
+\setinterfacemessage{interactions}{3}{inaktiv}
+\setinterfacemessage{interactions}{2}{aktiv}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{keine Seitensynchronisation (--) im hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{Interaktion}
+\setinterfacemessage{interactions}{21}{-- Code eingefuegt}
+\setinterfacemessage{structures}{1}{Begin des Abschnittsblocks --}
+\setinterfacemessage{structures}{title}{struktur}
+\setinterfacemessage{structures}{2}{Ende des Abschnittsblocks --}
+\setinterfacemessage{linguals}{1}{Trennmuster -- fuer -- geladen (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{Trenndefinitionen -- fuer -- geladen (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{Keine Trennmuster -- fuer -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{Trennmuster fuer -- nicht geladen}
+\setinterfacemessage{linguals}{4}{Keine Trenndefinitionen -- fuer -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{Sprachenspezifische Option [--] fuegt eine Luecke von -- ein}
+\setinterfacemessage{linguals}{6}{Sprache -- ist undefiniert}
+\setinterfacemessage{linguals}{9}{Sprache -- ist aktiv}
+\setinterfacemessage{linguals}{8}{Sprachenspezifische Option [--] nahtlos hinzugefuegt}
+\setinterfacemessage{linguals}{title}{Sprache}
+\setinterfacemessage{linguals}{10}{Trennmuster --geladen}
+\setinterfacemessage{regimes}{1}{Kodierung --}
+\setinterfacemessage{regimes}{3}{Unbekannte Kodierung --}
+\setinterfacemessage{regimes}{2}{Kodierung -- ist geladen}
+\setinterfacemessage{regimes}{title}{Kodierung}
+\setinterfacemessage{filters}{1}{filter -- ist geladen}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{Datei -- existiert nicht}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{Kodierung --}
+\setinterfacemessage{encodings}{3}{Unbekannte Kodierung --}
+\setinterfacemessage{encodings}{2}{Kodierung -- ist geladen}
+\setinterfacemessage{encodings}{title}{Kodierung}
+\setinterfacemessage{columns}{1}{nur -- Spalten moeglich}
+\setinterfacemessage{columns}{3}{Problem, verwende [ausgleich=nein]}
+\setinterfacemessage{columns}{2}{benutzte \string\filbreak\space als Alternative}
+\setinterfacemessage{columns}{5}{Gleitobjekt unten ncoh nicht unterstuetzt}
+\setinterfacemessage{columns}{4}{Gleitobjekt oben ncoh nicht unterstuetzt}
+\setinterfacemessage{columns}{7}{ausgleich nach 100 Schritten abgebrocheb}
+\setinterfacemessage{columns}{6}{-- Gleitobjekt(e) verschoben}
+\setinterfacemessage{columns}{9}{Ausrichtung ueberpruefen}
+\setinterfacemessage{columns}{8}{ausgeglichen nach -- Schritt(en)}
+\setinterfacemessage{columns}{title}{Spalten}
+\setinterfacemessage{columns}{13}{breites Gleitobjekt an den Anfang der Spalten verschoben}
+\setinterfacemessage{columns}{12}{Gleitobjekt in naechste Zeile verschoben / --}
+\setinterfacemessage{columns}{11}{Gleitobjekt zu breit fuer Spalte}
+\setinterfacemessage{columns}{10}{(weniger als) 1 Zeile uebrig}
+\setinterfacemessage{textblocks}{1}{neue Version, zweiter Durchlauf benoetigt}
+\setinterfacemessage{textblocks}{3}{lese Bloecke von --}
+\setinterfacemessage{textblocks}{2}{schreibe Bloecke zu --}
+\setinterfacemessage{textblocks}{5}{-- nicht verborgen}
+\setinterfacemessage{textblocks}{4}{zweiter Durchlauf benoetigt}
+\setinterfacemessage{textblocks}{7}{-- verborgen}
+\setinterfacemessage{textblocks}{6}{-- verborgen und verarbeitet}
+\setinterfacemessage{textblocks}{9}{-- nicht gesetzt}
+\setinterfacemessage{textblocks}{8}{-- gesetzt}
+\setinterfacemessage{textblocks}{title}{textblock}
+\setinterfacemessage{textblocks}{12}{-- ausgelassen}
+\setinterfacemessage{textblocks}{11}{-- geladen und gesetzt}
+\setinterfacemessage{textblocks}{10}{-- geladen und verarbeitet}
+\setinterfacemessage{symbols}{1}{Lade Symboldatei --}
+\setinterfacemessage{symbols}{title}{Symbole}
+\setinterfacemessage{versions}{1}{fehlendes @+}
+\setinterfacemessage{versions}{3}{Ausgewaehlte Seiten: --}
+\setinterfacemessage{versions}{2}{Erstelle Seiten}
+\setinterfacemessage{versions}{title}{Version}
+\setinterfacemessage{specials}{1}{-- geladen}
+\setinterfacemessage{specials}{3}{-- ist zurueckgesetzt}
+\setinterfacemessage{specials}{2}{keine tiefere Verschachtelung erlaubt --}
+\setinterfacemessage{specials}{5}{lade Definitionsdatei --}
+\setinterfacemessage{specials}{4}{Befehl -- existiert nicht}
+\setinterfacemessage{specials}{7}{unbekante Driver --}
+\setinterfacemessage{specials}{6}{Verschachtelung nicht erlaubt}
+\setinterfacemessage{specials}{title}{spezielles}
+\setinterfacemessage{javascript}{1}{Lade Scriptdatei --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{unbekannte Preamble --}
+\setinterfacemessage{fonts}{1}{Kodierung --}
+\setinterfacemessage{fonts}{3}{Unbekannte Variante --}
+\setinterfacemessage{fonts}{2}{Variante -- ist geladen}
+\setinterfacemessage{fonts}{5}{Stil -- ist nicht definiert}
+\setinterfacemessage{fonts}{4}{Fliesstext -- ist nicht definiert}
+\setinterfacemessage{fonts}{7}{unbekanntes Format --}
+\setinterfacemessage{fonts}{6}{-- ist geladen}
+\setinterfacemessage{fonts}{14}{Fliesstext -- wurde definiert (besser waere globale Definition)}
+\setinterfacemessage{fonts}{8}{Stil -- definiert}
+\setinterfacemessage{fonts}{title}{Fliesstext}
+\setinterfacemessage{fonts}{10}{unbekanntes Font --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{globale Datei --}
+\setinterfacemessage{databases}{2}{lokale Datei --}
+\setinterfacemessage{databases}{4}{unbekannte Datei --}
+\setinterfacemessage{databases}{title}{Datenbank}
+\setinterfacemessage{colors}{1}{system -- ist global aktiviert}
+\setinterfacemessage{colors}{3}{-- ist undefiniert --}
+\setinterfacemessage{colors}{2}{system -- ist lokal aktiviert}
+\setinterfacemessage{colors}{5}{unbekanntes System --}
+\setinterfacemessage{colors}{4}{system -- ist geladen}
+\setinterfacemessage{colors}{7}{palette -- ist nicht verfuegbar}
+\setinterfacemessage{colors}{6}{palette -- ist verfuegbar}
+\setinterfacemessage{colors}{9}{-- Farbraum wird nicht unterstuetzt}
+\setinterfacemessage{colors}{8}{Spezifikation -- bei Farbe -- wird schwarz}
+\setinterfacemessage{colors}{title}{farbe}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{Farbe wird in Grau umgewandelt}
+\setinterfacemessage{colors}{10}{-- Farbraum wird unterstuetzt}
+\setinterfacemessage{layouts}{1}{Texthoehe angepasst mit -- auf Seite --}
+\setinterfacemessage{layouts}{3}{-- mal Text verschoben}
+\setinterfacemessage{layouts}{2}{-- mal verschobener Text plaziert}
+\setinterfacemessage{layouts}{5}{marginalbloecke inaktiv}
+\setinterfacemessage{layouts}{4}{marginalbloecke aktiv}
+\setinterfacemessage{layouts}{7}{berechne Platzbedarf des Logos}
+\setinterfacemessage{layouts}{6}{Unterseitenfolge -- verarbeitet (Groesse --)}
+\setinterfacemessage{layouts}{9}{z.Z. nicht mehr als -- Ebenen in Aufzaehlungen}
+\setinterfacemessage{layouts}{8}{berechne Hintergrund}
+\setinterfacemessage{layouts}{title}{Layout}
+\setinterfacemessage{layouts}{11}{Zwischenraum -- nicht im Grittermoduserlau}
+\setinterfacemessage{layouts}{10}{-- und -- ergeben zusammen nicht 1.0}
+\setinterfacemessage{check}{1}{Fehlendes '=' nach '--' in Zeile --}
+\setinterfacemessage{check}{3}{-- -- ersetzt ein Makro, verwende VERSALIEN!}
+\setinterfacemessage{check}{2}{-- Argument(e) in Zeile -- erwartet}
+\setinterfacemessage{check}{title}{check}
+\setinterfacemessage{metapost}{1}{Lade metapost Bibliothek --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{Dateisynonym -- wird bereits fuer -- benutzt}
+\setinterfacemessage{files}{title}{files}
+\setinterfacemessage{figures}{1}{Abbildung -- kann nicht gefunden werden}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{Abbildung -- wird nicht erstellt}
+\setinterfacemessage{figures}{5}{Dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{Dimensionen von -- geladen aus der Abbildungsdatei selbst}
+\setinterfacemessage{figures}{6}{Dimensionen von -- ausgerechnet durch rlxtools}
+\setinterfacemessage{figures}{8}{Abbildungobjekt -- wurde wiederverwandt}
+\setinterfacemessage{figures}{title}{Abbildungen}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-men.tex b/tex/context/base/mult-men.tex
new file mode 100644
index 000000000..8335d2911
--- /dev/null
+++ b/tex/context/base/mult-men.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{unknown reference --}
+\setinterfacemessage{references}{3}{unknown reference type --}
+\setinterfacemessage{references}{2}{duplicate reference -- on page --}
+\setinterfacemessage{references}{4}{illegal reference --}
+\setinterfacemessage{references}{title}{references}
+\setinterfacemessage{references}{30}{unknown object --}
+\setinterfacemessage{references}{31}{duplicate object --}
+\setinterfacemessage{references}{21}{document -- loaded}
+\setinterfacemessage{references}{22}{document -- is not interactive}
+\setinterfacemessage{references}{23}{obscure reference -- (prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{system}
+\setinterfacemessage{systems}{41}{external file -- in group -- does not exist}
+\setinterfacemessage{systems}{9}{-- not found/processed}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{new version of utility file, second pass needed}
+\setinterfacemessage{systems}{21}{no utility data is loaded}
+\setinterfacemessage{systems}{20}{meaning (sorts) of -- loaded}
+\setinterfacemessage{systems}{5}{module -- loaded}
+\setinterfacemessage{systems}{4}{command -- is already defined}
+\setinterfacemessage{systems}{27}{Version}
+\setinterfacemessage{systems}{26}{Registers}
+\setinterfacemessage{systems}{25}{References}
+\setinterfacemessage{systems}{24}{Floatblocks}
+\setinterfacemessage{systems}{1}{loading utility-file postponed (typemode)}
+\setinterfacemessage{systems}{23}{-- arranged at --}
+\setinterfacemessage{systems}{22}{use a valid utilityfile}
+\setinterfacemessage{systems}{2}{-- loaded}
+\setinterfacemessage{systems}{19}{meaning (synonyms) of -- loaded}
+\setinterfacemessage{systems}{18}{synonym -- -- does not exist}
+\setinterfacemessage{systems}{7}{module -- already loaded}
+\setinterfacemessage{systems}{6}{module -- not found}
+\setinterfacemessage{systems}{14}{forced newpage in list at --}
+\setinterfacemessage{systems}{15}{saving buffer --}
+\setinterfacemessage{systems}{16}{typesetting buffer --}
+\setinterfacemessage{systems}{17}{typesetting verbatim buffer --}
+\setinterfacemessage{systems}{13}{mark -- defined --}
+\setinterfacemessage{systems}{12}{the utility-file is not sorted, use texutil}
+\setinterfacemessage{systems}{11}{building simple util}
+\setinterfacemessage{systems}{10}{don't use em in --}
+\setinterfacemessage{floatblocks}{1}{-- renumbered / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- moved}
+\setinterfacemessage{floatblocks}{2}{-- saved}
+\setinterfacemessage{floatblocks}{5}{order adapted}
+\setinterfacemessage{floatblocks}{4}{-- placed}
+\setinterfacemessage{floatblocks}{7}{n of bottom floats limited to --}
+\setinterfacemessage{floatblocks}{6}{n of top floats limited to --}
+\setinterfacemessage{floatblocks}{9}{order disturbed}
+\setinterfacemessage{floatblocks}{8}{less than -- lines}
+\setinterfacemessage{floatblocks}{title}{floatblocks}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{undefined}
+\setinterfacemessage{floatblocks}{11}{no block given}
+\setinterfacemessage{floatblocks}{10}{-- limited}
+\setinterfacemessage{interactions}{1}{aspect ratio -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{inactive}
+\setinterfacemessage{interactions}{2}{active}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{no pagesynchronisation (--) in hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interaction}
+\setinterfacemessage{interactions}{21}{-- code inserted}
+\setinterfacemessage{structures}{1}{begin of sectionblock --}
+\setinterfacemessage{structures}{title}{structure}
+\setinterfacemessage{structures}{2}{end of sectionblock --}
+\setinterfacemessage{linguals}{1}{patterns -- for -- loaded (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{hyphenations -- for -- loaded (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{no patterns -- for -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{patterns for -- not loaded}
+\setinterfacemessage{linguals}{4}{no hyphenations -- for -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{language specific options [--] introduce a -- skip}
+\setinterfacemessage{linguals}{6}{language -- is undefined}
+\setinterfacemessage{linguals}{9}{language -- is active}
+\setinterfacemessage{linguals}{8}{language specific options [--] seamless appended}
+\setinterfacemessage{linguals}{title}{language}
+\setinterfacemessage{linguals}{10}{patterns --loaded}
+\setinterfacemessage{regimes}{1}{regime --}
+\setinterfacemessage{regimes}{3}{unknown regime --}
+\setinterfacemessage{regimes}{2}{regime -- is loaded}
+\setinterfacemessage{regimes}{title}{regime}
+\setinterfacemessage{filters}{1}{filter -- is loaded}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{file -- does not exist}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{coding --}
+\setinterfacemessage{encodings}{3}{unknown coding --}
+\setinterfacemessage{encodings}{2}{coding -- is loaded}
+\setinterfacemessage{encodings}{title}{encoding}
+\setinterfacemessage{columns}{1}{only -- columns possible}
+\setinterfacemessage{columns}{3}{problems, disable balancing}
+\setinterfacemessage{columns}{2}{use \string\filbreak\space as alternative}
+\setinterfacemessage{columns}{5}{bottom float not yet supported}
+\setinterfacemessage{columns}{4}{top float not yet supported}
+\setinterfacemessage{columns}{7}{balancing aborted after 100 steps}
+\setinterfacemessage{columns}{6}{-- float(s) postponed}
+\setinterfacemessage{columns}{9}{check raggedness}
+\setinterfacemessage{columns}{8}{balanced in -- step(s)}
+\setinterfacemessage{columns}{title}{columns}
+\setinterfacemessage{columns}{13}{wide float moved to top of columns}
+\setinterfacemessage{columns}{12}{float moved to next column / --}
+\setinterfacemessage{columns}{11}{float too wide for column}
+\setinterfacemessage{columns}{10}{(less than) 1 line left}
+\setinterfacemessage{textblocks}{1}{new version, second pass needed}
+\setinterfacemessage{textblocks}{3}{reading blocks from --}
+\setinterfacemessage{textblocks}{2}{writing blocks to --}
+\setinterfacemessage{textblocks}{5}{-- not hidden}
+\setinterfacemessage{textblocks}{4}{second pass needed}
+\setinterfacemessage{textblocks}{7}{-- hidden}
+\setinterfacemessage{textblocks}{6}{-- hidden and processed}
+\setinterfacemessage{textblocks}{9}{-- not typeset}
+\setinterfacemessage{textblocks}{8}{-- typeset}
+\setinterfacemessage{textblocks}{title}{textblocks}
+\setinterfacemessage{textblocks}{12}{-- skipped}
+\setinterfacemessage{textblocks}{11}{-- loaded and typeset}
+\setinterfacemessage{textblocks}{10}{-- loaded and processed}
+\setinterfacemessage{symbols}{1}{loading symbolset --}
+\setinterfacemessage{symbols}{title}{symbols}
+\setinterfacemessage{versions}{1}{missing @+}
+\setinterfacemessage{versions}{3}{selected pages: --}
+\setinterfacemessage{versions}{2}{marking pages}
+\setinterfacemessage{versions}{title}{version}
+\setinterfacemessage{specials}{1}{-- loaded}
+\setinterfacemessage{specials}{3}{-- is reset}
+\setinterfacemessage{specials}{2}{no deeper nesting is permitted --}
+\setinterfacemessage{specials}{5}{loading definition file --}
+\setinterfacemessage{specials}{4}{command -- does not exist}
+\setinterfacemessage{specials}{7}{unknown driver --}
+\setinterfacemessage{specials}{6}{nesting is not permitted}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{loading script set --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{unknown preamble --}
+\setinterfacemessage{fonts}{1}{coding --}
+\setinterfacemessage{fonts}{3}{unknown variant --}
+\setinterfacemessage{fonts}{2}{variant -- is loaded}
+\setinterfacemessage{fonts}{5}{style -- is not defined}
+\setinterfacemessage{fonts}{4}{bodyfont -- is not defined}
+\setinterfacemessage{fonts}{7}{unknown format --}
+\setinterfacemessage{fonts}{6}{-- is loaded}
+\setinterfacemessage{fonts}{14}{bodyfont -- is defined (can better be done global)}
+\setinterfacemessage{fonts}{8}{style -- defined}
+\setinterfacemessage{fonts}{title}{bodyfont}
+\setinterfacemessage{fonts}{10}{unknown font file --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{global file --}
+\setinterfacemessage{databases}{2}{local file --}
+\setinterfacemessage{databases}{4}{unknown file --}
+\setinterfacemessage{databases}{title}{databases}
+\setinterfacemessage{colors}{1}{system -- is global activated}
+\setinterfacemessage{colors}{3}{-- is not defined --}
+\setinterfacemessage{colors}{2}{system -- is local activated}
+\setinterfacemessage{colors}{5}{unknown system --}
+\setinterfacemessage{colors}{4}{system -- is loaded}
+\setinterfacemessage{colors}{7}{palette -- is not available}
+\setinterfacemessage{colors}{6}{palette -- is available}
+\setinterfacemessage{colors}{9}{-- color space is not supported}
+\setinterfacemessage{colors}{8}{specification -- at color -- becomes black}
+\setinterfacemessage{colors}{title}{color}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{color is converted to gray}
+\setinterfacemessage{colors}{10}{-- color space is supported}
+\setinterfacemessage{layouts}{1}{textheight adapted with -- at page --}
+\setinterfacemessage{layouts}{3}{-- times text postponed}
+\setinterfacemessage{layouts}{2}{-- times postponed text placed}
+\setinterfacemessage{layouts}{5}{marginblocks inactive}
+\setinterfacemessage{layouts}{4}{marginblocks active}
+\setinterfacemessage{layouts}{7}{calculating logospace}
+\setinterfacemessage{layouts}{6}{subpage set -- processed (size --)}
+\setinterfacemessage{layouts}{9}{currently no more than -- levels in itemizations}
+\setinterfacemessage{layouts}{8}{calculating backgrounds}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{spacing -- not permitted in gridmode}
+\setinterfacemessage{layouts}{10}{-- and -- don't add up to 1.0}
+\setinterfacemessage{check}{1}{missing or ungrouped '=' after '--' in line --}
+\setinterfacemessage{check}{3}{-- -- replaces a macro, use CAPITALS!}
+\setinterfacemessage{check}{2}{-- argument(s) expected in line --}
+\setinterfacemessage{check}{title}{check}
+\setinterfacemessage{metapost}{1}{loading metapost library --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{file synonym -- is already used for --}
+\setinterfacemessage{files}{title}{files}
+\setinterfacemessage{figures}{1}{figure -- can not be found}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{figure -- is not preset}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimensions of -- loaded from figurefile itself}
+\setinterfacemessage{figures}{6}{dimensions of -- calculated by rlxtools}
+\setinterfacemessage{figures}{8}{figureobject -- is reused}
+\setinterfacemessage{figures}{title}{figures}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mes.lua b/tex/context/base/mult-mes.lua
new file mode 100644
index 000000000..6d177fd8f
--- /dev/null
+++ b/tex/context/base/mult-mes.lua
@@ -0,0 +1,2005 @@
+return {
+ ["check"]={
+ ["1"]={
+ ["cs"]="postradam '=' po '--' na radku --",
+ ["de"]="Fehlendes '=' nach '--' in Zeile --",
+ ["en"]="missing or ungrouped '=' after '--' in line --",
+ ["fr"]="manquant ou dégroupé '=' après '--' à la ligne --",
+ ["it"]="'=' mancante o non raggruppato dopo '--' alla riga --",
+ ["nl"]="'=' ontbreekt of zonder {} na '--' in regel --",
+ ["no"]="manglende '=' etter '--' i linje --",
+ ["ro"]="lipseste '=' dupa '--' in linia --",
+ },
+ ["2"]={
+ ["cs"]="ocekavam -- argument(y) na radku --",
+ ["de"]="-- Argument(e) in Zeile -- erwartet",
+ ["en"]="-- argument(s) expected in line --",
+ ["fr"]="-- argument(s) attendu(s) à la ligne --",
+ ["it"]="-- argomento/i attesi alla riga --",
+ ["nl"]="-- argument(en) verwacht in regel --",
+ ["no"]="-- argument forventet i linje --",
+ ["ro"]="argumentul(ele) -- sunt asteptate in linia --",
+ },
+ ["3"]={
+ ["cs"]="-- -- nahrazuje makro, uzijte VERZALKY!",
+ ["de"]="-- -- ersetzt ein Makro, verwende VERSALIEN!",
+ ["en"]="-- -- replaces a macro, use CAPITALS!",
+ ["fr"]="-- -- remplace une macro, utilisez des MAJUSCULES !",
+ ["it"]="-- -- sostituisce una macro, usare le MAIUSCOLE!",
+ ["nl"]="-- -- vervangt een macro, gebruik HOOFDLETTERS!",
+ ["no"]="-- -- overskygger en makro, bruk STORE BOKSTAVER!",
+ ["ro"]="-- -- inlocuieste un macro, folositi MAJUSCULE!",
+ },
+ ["files"]={ "mult-sys.tex" },
+ ["title"]={
+ ["cs"]="kontrola",
+ ["de"]="check",
+ ["en"]="check",
+ ["fr"]="vérification",
+ ["it"]="controllo",
+ ["nl"]="controle",
+ ["no"]="kontroll",
+ ["ro"]="verificari",
+ },
+ },
+ ["colors"]={
+ ["1"]={
+ ["cs"]="system -- je globalne aktivovana",
+ ["de"]="system -- ist global aktiviert",
+ ["en"]="system -- is global activated",
+ ["fr"]="le système -- est globalement activé",
+ ["it"]="sistema -- attivato globalmente",
+ ["nl"]="systeem -- is globaal actief",
+ ["no"]="system -- er aktivert globalt",
+ ["ro"]="sistem -- este activata global",
+ },
+ ["10"]={
+ ["cs"]="-- prostor barev je podporovan",
+ ["de"]="-- Farbraum wird unterstuetzt",
+ ["en"]="-- color space is supported",
+ ["fr"]="-- l'espace de couleur est supporté",
+ ["it"]="spazio dei colori -- supportato",
+ ["nl"]="-- kleurruimte wordt ondersteund",
+ ["no"]="-- fargerom er støttet",
+ ["ro"]="spatiul de culoare -- este suportat",
+ },
+ ["11"]={
+ ["cs"]="barva je prevedena na sed",
+ ["de"]="Farbe wird in Grau umgewandelt",
+ ["en"]="color is converted to gray",
+ ["fr"]="la couleur est convertie en niveau de gris",
+ ["it"]="il colore ø convertito in grigio",
+ ["nl"]="kleur wordt vertaald in grijs",
+ ["no"]="fargen vil bli vist som grø",
+ ["ro"]="culoarea este convertita la gri",
+ },
+ ["12"]={
+ ["cs"]="-- is registered",
+ ["de"]="-- is registered",
+ ["en"]="-- is registered",
+ ["fr"]="-- est enregistré",
+ ["it"]="-- is registered",
+ ["nl"]="-- is geregistreerd",
+ ["no"]="-- is registered",
+ ["ro"]="-- is registered",
+ },
+ ["2"]={
+ ["cs"]="system -- je lokalne activovana",
+ ["de"]="system -- ist lokal aktiviert",
+ ["en"]="system -- is local activated",
+ ["fr"]="le système -- est localement activé",
+ ["it"]="sistema -- attivato localmente",
+ ["nl"]="systeem -- is lokaal actief",
+ ["no"]="system -- er aktivert lokalt",
+ ["ro"]="sistem -- este activata local",
+ },
+ ["3"]={
+ ["cs"]="-- neni definovana --",
+ ["de"]="-- ist undefiniert --",
+ ["en"]="-- is not defined --",
+ ["fr"]="-- n'est pas défini --",
+ ["it"]="-- non definito --",
+ ["nl"]="-- is niet gedefinieerd --",
+ ["no"]="-- er udefinert --",
+ ["ro"]="-- nu este definita --",
+ },
+ ["4"]={
+ ["cs"]="system -- je nacten",
+ ["de"]="system -- ist geladen",
+ ["en"]="system -- is loaded",
+ ["fr"]="le système -- est chargé",
+ ["it"]="sistema -- caricato",
+ ["nl"]="systeem -- wordt geladen",
+ ["no"]="system -- er lest inn",
+ ["ro"]="sistem -- este incarcata",
+ },
+ ["5"]={
+ ["cs"]="neznamy system --",
+ ["de"]="unbekanntes System --",
+ ["en"]="unknown system --",
+ ["fr"]="système -- inconnu",
+ ["it"]="sistema -- sconosciuto",
+ ["nl"]="onbekend systeem --",
+ ["no"]="ukjent system --",
+ ["ro"]="sistem -- necunoscuta",
+ },
+ ["6"]={
+ ["cs"]="palette -- je k dispozici",
+ ["de"]="palette -- ist verfuegbar",
+ ["en"]="palette -- is available",
+ ["fr"]="la palette -- est disponible",
+ ["it"]="tavolozza -- resa disponibile",
+ ["nl"]="palet -- is beschikbaar",
+ ["no"]="palett -- er tilgjengelig",
+ ["ro"]="paleta -- este disponibila",
+ },
+ ["7"]={
+ ["cs"]="palette -- neni k dispozici",
+ ["de"]="palette -- ist nicht verfuegbar",
+ ["en"]="palette -- is not available",
+ ["fr"]="le palette -- n'est pas disponible",
+ ["it"]="tavolozza -- non disponibile",
+ ["nl"]="palet -- is niet beschikbaar",
+ ["no"]="palett -- er ikke tilgjengelig",
+ ["ro"]="palette -- nu este disponibila",
+ },
+ ["8"]={
+ ["cs"]="specifikace -- v barve -- bude cerna",
+ ["de"]="Spezifikation -- bei Farbe -- wird schwarz",
+ ["en"]="specification -- at color -- becomes black",
+ ["fr"]="la spécification -- de la couleur -- devient noire",
+ ["it"]="specifica -- del colore -- convertita in nero",
+ ["nl"]="specificatie -- bij -- wordt zwart",
+ ["no"]="spesifikasjon -- for farge -- gir kun svart",
+ ["ro"]="specificatia -- la culoarea -- devine neagra",
+ },
+ ["9"]={
+ ["cs"]="-- prostor barev neni podporovan",
+ ["de"]="-- Farbraum wird nicht unterstuetzt",
+ ["en"]="-- color space is not supported",
+ ["fr"]="l'espace de couleur -- n'est pas supporté",
+ ["it"]="spazio dei colori -- non supportato",
+ ["nl"]="-- kleurruimte wordt niet ondersteund",
+ ["no"]="-- fargerom er ikke støttet",
+ ["ro"]="spatiul de culoare -- nu este suportat",
+ },
+ ["files"]={ "colo-ini.tex" },
+ ["title"]={
+ ["cs"]="barva",
+ ["de"]="farbe",
+ ["en"]="color",
+ ["fr"]="couleurs",
+ ["it"]="colore",
+ ["nl"]="kleur",
+ ["no"]="farge",
+ ["ro"]="culori",
+ },
+ },
+ ["columns"]={
+ ["1"]={
+ ["cs"]="je mozno pouze -- sloupcu",
+ ["de"]="nur -- Spalten moeglich",
+ ["en"]="only -- columns possible",
+ ["fr"]="seules -- colonnes possibles",
+ ["it"]="solo -- colonne possibili",
+ ["nl"]="maximaal -- kolommen",
+ ["no"]="maksimalt -- kolonner",
+ ["ro"]="este posibil numai -- coloane",
+ },
+ ["10"]={
+ ["cs"]="zbyl (mene nez) 1 radek",
+ ["de"]="(weniger als) 1 Zeile uebrig",
+ ["en"]="(less than) 1 line left",
+ ["fr"]="(moins de) 1 ligne restante",
+ ["it"]="(meno di) una riga rimasta",
+ ["nl"]="(minder dan) 1 regel over",
+ ["no"]="(mindre enn) 1 linje igjen",
+ ["ro"]="a mai ramas (mai putin de) 1 linie",
+ },
+ ["11"]={
+ ["cs"]="plovouci objekt je pro sloupec prilis siroky",
+ ["de"]="Gleitobjekt zu breit fuer Spalte",
+ ["en"]="float too wide for column",
+ ["fr"]="flottant mis à la largeur de la colonne",
+ ["it"]="oggetto mobile troppo ampio per la colonna",
+ ["nl"]="plaatsblok te breed voor kolom",
+ ["no"]="flytblokk for bredt for kolonna",
+ ["ro"]="blocul este prea lat pentru coloana",
+ },
+ ["12"]={
+ ["cs"]="plovouci objekt je presunut do nasledujiciho sloupce / --",
+ ["de"]="Gleitobjekt in naechste Zeile verschoben / --",
+ ["en"]="float moved to next column / --",
+ ["fr"]="flottant déplacé à la colonne suivante / --",
+ ["it"]="oggetto mobile spostata alla colonna successiva / --",
+ ["nl"]="plaatsblok verplaatst naar volgende kolom / --",
+ ["no"]="flytblokk forskjøvet til neste kolonne / --",
+ ["ro"]="blocul este mutat pe urmatoarea coloana / --",
+ },
+ ["13"]={
+ ["cs"]="siroky plovouci objekt je presunut nad sloupce",
+ ["de"]="breites Gleitobjekt an den Anfang der Spalten verschoben",
+ ["en"]="wide float moved to top of columns",
+ ["fr"]="flottant large déplacé dans la partie supérieure de la colonne",
+ ["it"]="oggetto mobile ampio spostato sopra le colonne",
+ ["nl"]="breed figuur geplaatst boven kolommen",
+ ["no"]="bred flytblokk forksjøvet til toppen av kolonnene",
+ ["ro"]="blocul lat este mutat in partea de sus a coloanelor",
+ },
+ ["2"]={
+ ["cs"]="pouzijte \\string\\filbreak\\space jako alternativu",
+ ["de"]="benutzte \\string\\filbreak\\space als Alternative",
+ ["en"]="use \\string\\filbreak\\space as alternative",
+ ["fr"]="utilisez \\string\\filbreak\\space en tant qu'alternative",
+ ["it"]="in alternativa, usare \\string\\filbreak",
+ ["nl"]="gebruik eventueel \\string\\filbreak",
+ ["no"]="bruk \\string\\filbreak\\space som et alternativ",
+ ["ro"]="folositi \\string\\filbreak\\space ca alternativa",
+ },
+ ["3"]={
+ ["cs"]="problem, vypina se vyvazovani",
+ ["de"]="Problem, verwende [ausgleich=nein]",
+ ["en"]="problems, disable balancing",
+ ["fr"]="problèmes, désactive l'équilibrage",
+ ["it"]="problemi, disabilitare il bilanciamento",
+ ["nl"]="probleempje, probeer [balanceren=nee]",
+ ["no"]="problemer, slår av balansering",
+ ["ro"]="probleme, se dezactiveaza alinierea",
+ },
+ ["4"]={
+ ["cs"]="horni plovouci objekt jeste neni podporovan",
+ ["de"]="Gleitobjekt oben ncoh nicht unterstuetzt",
+ ["en"]="top float not yet supported",
+ ["fr"]="flottant en partie supérieure pas encore supporté",
+ ["it"]="float in cima non ancora supportato",
+ ["nl"]="plaatsblok boven nog niet mogelijk",
+ ["no"]="flytblokker øverst er ikke støttet enda",
+ ["ro"]="cadrele top (top float) nu sunt inca suportate",
+ },
+ ["5"]={
+ ["cs"]="spodni plovouci objekt jeste neni podporovan",
+ ["de"]="Gleitobjekt unten ncoh nicht unterstuetzt",
+ ["en"]="bottom float not yet supported",
+ ["fr"]="flottant en partie inférieure pas encore supporté",
+ ["it"]="float in fondo non ancora supportato",
+ ["nl"]="plaatsblok onder nog niet mogelijk",
+ ["no"]="flytblokker nedert er ikke støttet enda",
+ ["ro"]="cadrele bottom (bottom float) nu sunt inca suportate",
+ },
+ ["6"]={
+ ["cs"]="-- plovouci objekt(y) odlozeny",
+ ["de"]="-- Gleitobjekt(e) verschoben",
+ ["en"]="-- float(s) postponed",
+ ["fr"]="-- flottant(s) reporté(s)",
+ ["it"]="-- float(s) posticipate",
+ ["nl"]="-- plaatsblok(en) opgeschort",
+ ["no"]="-- flytblokk forskjøvet",
+ ["ro"]="-- blocurile sunt amanate",
+ },
+ ["7"]={
+ ["cs"]="vyvazovani ukonceno po 100 krocich",
+ ["de"]="ausgleich nach 100 Schritten abgebrocheb",
+ ["en"]="balancing aborted after 100 steps",
+ ["fr"]="équilibrage abandonné après 100 pas",
+ ["it"]="bilanciamento annullato dopo 100 passi",
+ ["nl"]="balanceren afgebroken na 100 stappen",
+ ["no"]="balansering avbrutt etter 100 iterasjoner",
+ ["ro"]="alinierea este oprita dupa 100 de incercari",
+ },
+ ["8"]={
+ ["cs"]="vyvazeno v -- krocich",
+ ["de"]="ausgeglichen nach -- Schritt(en)",
+ ["en"]="balanced in -- step(s)",
+ ["fr"]="équilibré en -- pas",
+ ["it"]="bilanciamento in -- passo/i",
+ ["nl"]="gebalanceerd in -- stap(pen)",
+ ["no"]="balansert etter -- iterasjoner",
+ ["ro"]="aliniat in -- pas(i)",
+ },
+ ["9"]={
+ ["cs"]="kontrola nerovnost",
+ ["de"]="Ausrichtung ueberpruefen",
+ ["en"]="check raggedness",
+ ["fr"]="vérification des irrégularités",
+ ["it"]="controllare seghettamento",
+ ["nl"]="uitlijnen controleren!",
+ ["no"]="kontroller tekstlayout!",
+ ["ro"]="verificat alinierea",
+ },
+ ["files"]={ "page-ini.tex" },
+ ["title"]={
+ ["cs"]="sloupce",
+ ["de"]="Spalten",
+ ["en"]="columns",
+ ["fr"]="colonnes",
+ ["it"]="colonne",
+ ["nl"]="kolommen",
+ ["no"]="kolonner",
+ ["ro"]="coloane",
+ },
+ },
+ ["databases"]={
+ ["1"]={
+ ["cs"]="--",
+ ["de"]="--",
+ ["en"]="--",
+ ["fr"]="--",
+ ["it"]="--",
+ ["nl"]="--",
+ ["no"]="--",
+ ["ro"]="--",
+ },
+ ["2"]={
+ ["cs"]="local file --",
+ ["de"]="lokale Datei --",
+ ["en"]="local file --",
+ ["fr"]="fichier local --",
+ ["it"]="file locale --",
+ ["nl"]="lokaal bestand --",
+ ["no"]="lokal fil --",
+ ["ro"]="fisier local --",
+ },
+ ["3"]={
+ ["cs"]="global file --",
+ ["de"]="globale Datei --",
+ ["en"]="global file --",
+ ["fr"]="fichier global --",
+ ["it"]="file globale --",
+ ["nl"]="globaal bestand --",
+ ["no"]="global fil --",
+ ["ro"]="fisier global --",
+ },
+ ["4"]={
+ ["cs"]="unknown file --",
+ ["de"]="unbekannte Datei --",
+ ["en"]="unknown file --",
+ ["fr"]="fichier inconnu --",
+ ["it"]="file sconosciuto --",
+ ["nl"]="onbekend bestand --",
+ ["no"]="ukjent fil --",
+ ["ro"]="fisier necunoscut --",
+ },
+ ["files"]={ "core-dat.tex" },
+ ["title"]={
+ ["cs"]="databases",
+ ["de"]="Datenbank",
+ ["en"]="databases",
+ ["fr"]="bases de données",
+ ["it"]="database",
+ ["nl"]="database",
+ ["no"]="databaser",
+ ["ro"]="baze de date",
+ },
+ },
+ ["documents"]={
+ ["1"]={
+ ["de"]="Blatt --",
+ ["en"]="sheet --",
+ ["nl"]="sheet --",
+ },
+ ["2"]={
+ ["de"]="Nummer --",
+ ["en"]="number --",
+ ["nl"]="nummer --",
+ },
+ ["files"]={ "docs-bri.tex", "docs-she.tex" },
+ ["title"]={
+ ["de"]="Blaetter",
+ ["en"]="sheets",
+ ["nl"]="sheets",
+ },
+ },
+ ["encodings"]={
+ ["1"]={
+ ["cs"]="kodovani --",
+ ["de"]="Kodierung --",
+ ["en"]="coding --",
+ ["fr"]="encodage --",
+ ["it"]="codifica --",
+ ["nl"]="codering --",
+ ["no"]="koding --",
+ ["ro"]="codificarea --",
+ },
+ ["2"]={
+ ["cs"]="je nacteno kodovani --",
+ ["de"]="Kodierung -- ist geladen",
+ ["en"]="coding -- is loaded",
+ ["fr"]="l'encodage -- est chargé",
+ ["it"]="codifica -- caricata",
+ ["nl"]="codering -- wordt geladen",
+ ["no"]="koding -- er lest inn",
+ ["ro"]="codificarea -- este Encarcata",
+ },
+ ["3"]={
+ ["cs"]="nezname kodovani --",
+ ["de"]="Unbekannte Kodierung --",
+ ["en"]="unknown coding --",
+ ["fr"]="encodage -- inconnu",
+ ["it"]="codifica sconosciuta --",
+ ["nl"]="onbekende codering --",
+ ["no"]="ukjent koding --",
+ ["ro"]="codificarea -- este necunoscuta",
+ },
+ ["files"]={ "enco-ini.mkii" },
+ ["title"]={
+ ["cs"]="kodovani",
+ ["de"]="Kodierung",
+ ["en"]="encoding",
+ ["fr"]="encodage",
+ ["it"]="codifica",
+ ["nl"]="encoding",
+ ["no"]="koding",
+ ["ro"]="codificari",
+ },
+ },
+ ["figures"]={
+ ["1"]={
+ ["cs"]="obraz -- nelze nalezt",
+ ["de"]="Abbildung -- kann nicht gefunden werden",
+ ["en"]="figure -- can not be found",
+ ["fr"]="la figure -- ne peut être trouvée",
+ ["it"]="figura -- non trovata",
+ ["nl"]="figuur -- is niet te vinden",
+ ["ro"]="figura -- nu poate fi gasita",
+ },
+ ["2"]={
+ ["cs"]="obraz -- nepritomen",
+ ["de"]="Abbildung -- wird nicht erstellt",
+ ["en"]="figure -- is not preset",
+ ["fr"]="la figure -- n'est pas pré-sélectionnée",
+ ["it"]="la figura -- non è preimpostata",
+ ["nl"]="figuur -- wordt niet preset",
+ ["ro"]="figura -- nu este presetata",
+ },
+ ["3"]={
+ ["cs"]="dimensions of -- are determined externally",
+ ["de"]="dimensions of -- are determined externally",
+ ["en"]="dimensions of -- are determined externally",
+ ["fr"]="dimensions of -- are determined externally",
+ ["it"]="dimensions of -- are determined externally",
+ ["nl"]="maten van -- worden extern vastgesteld",
+ ["ro"]="dimensions of -- are determined externally",
+ },
+ ["4"]={
+ ["cs"]="dimenze obrazu -- nacteny primo z jeho souboru",
+ ["de"]="Dimensionen von -- geladen aus der Abbildungsdatei selbst",
+ ["en"]="dimensions of -- loaded from figurefile itself",
+ ["fr"]="les dimensions de -- chargées implicitement à partir du fichier de figure",
+ ["it"]="dimensioni di -- caricate dal file di immagini stesso",
+ ["nl"]="maten van -- geladen uit figuurfile zelf",
+ ["ro"]="dimensiunea figurii -- se incarca din fisierul insusi",
+ },
+ ["5"]={
+ ["cs"]="dimensions of -- are unknown",
+ ["de"]="Dimensions of -- are unknown",
+ ["en"]="dimensions of -- are unknown",
+ ["fr"]="dimensions of -- are unknown",
+ ["it"]="dimensions of -- are unknown",
+ ["nl"]="maten van -- zijn onbekend",
+ ["ro"]="dimensions of -- are unknown",
+ },
+ ["6"]={
+ ["cs"]="dimenze obrazu -- spocteny programem rlxtools",
+ ["de"]="Dimensionen von -- ausgerechnet durch rlxtools",
+ ["en"]="dimensions of -- calculated by rlxtools",
+ ["fr"]="les dimensions de -- calculées par rlxtools",
+ ["it"]="dimensioni di -- calcolate da rlxtools",
+ ["nl"]="maten van -- berekend door rlxtools",
+ ["ro"]="dimensiunea figurii -- este calculata de rlxtools",
+ },
+ ["8"]={
+ ["cs"]="obrazovy objekt -- je znovu pouzit",
+ ["de"]="Abbildungobjekt -- wurde wiederverwandt",
+ ["en"]="figureobject -- is reused",
+ ["fr"]="figureobject -- est réutilisé",
+ ["it"]="oggetto-figura -- riutilizzato",
+ ["nl"]="figuurobject -- wordt opnieuw gebruikt",
+ ["ro"]="obiectul figura -- este refolosit",
+ },
+ ["files"]={ "core-inc.mkii" },
+ ["title"]={
+ ["cs"]="obrazy",
+ ["de"]="Abbildungen",
+ ["en"]="figures",
+ ["fr"]="figures",
+ ["it"]="figure",
+ ["nl"]="figuren",
+ ["ro"]="figuri",
+ },
+ },
+ ["files"]={
+ ["1"]={
+ ["cs"]="synonymum souboru -- je jiz pouzito pro --",
+ ["de"]="Dateisynonym -- wird bereits fuer -- benutzt",
+ ["en"]="file synonym -- is already used for --",
+ ["fr"]="le synonyme de fichier -- est déjà utilisé pour --",
+ ["it"]="sinonimo file -- già in uso per --",
+ ["nl"]="file synoniem -- is al in gebruik voor --",
+ ["no"]="filesynonym -- er allerede brukt for --",
+ ["ro"]="sinonimul fisierelor -- este folosit deja pentru --",
+ },
+ ["files"]={ "core-fil.tex" },
+ ["title"]={
+ ["cs"]="soubory",
+ ["de"]="files",
+ ["en"]="files",
+ ["fr"]="fichiers",
+ ["it"]="file",
+ ["nl"]="files",
+ ["no"]="filer",
+ ["ro"]="fisiere",
+ },
+ },
+ ["filters"]={
+ ["1"]={
+ ["cs"]="filter -- is loaded",
+ ["de"]="filter -- ist geladen",
+ ["en"]="filter -- is loaded",
+ ["fr"]="le filtre -- est chargé",
+ ["it"]="filtro -- caricato",
+ ["nl"]="filter -- wordt geladen",
+ },
+ ["2"]={
+ ["cs"]="unknown filter --",
+ ["de"]="unknown filter --",
+ ["en"]="unknown filter --",
+ ["fr"]="filtre -- inconnu",
+ ["it"]="filtro sconosciuto --",
+ ["nl"]="onbekend filter --",
+ },
+ ["files"]={ "filt-ini.tex" },
+ ["title"]={
+ ["cs"]="filter",
+ ["de"]="filter",
+ ["en"]="filter",
+ ["fr"]="filtre",
+ ["it"]="filtri",
+ ["nl"]="filter",
+ },
+ },
+ ["floatblocks"]={
+ ["1"]={
+ ["cs"]="-- precislovano / -- => --",
+ ["de"]="-- neu nummeriert / -- => --",
+ ["en"]="-- renumbered / -- => --",
+ ["fr"]="-- renuméroté / -- => --",
+ ["it"]="-- rinumerato / -- => --",
+ ["nl"]="-- hernummerd / -- => --",
+ ["no"]="-- renummerert / -- => --",
+ ["ro"]="-- renumerotat / -- => --",
+ },
+ ["10"]={
+ ["cs"]="-- omezeno",
+ ["de"]="-- begrenzt",
+ ["en"]="-- limited",
+ ["fr"]="-- limité",
+ ["it"]="-- limitato",
+ ["nl"]="-- begrensd",
+ ["no"]="-- begrenset",
+ ["ro"]="-- limitat",
+ },
+ ["11"]={
+ ["cs"]="nedan zadny blok",
+ ["de"]="kein Block gegeben",
+ ["en"]="no block given",
+ ["fr"]="pas de bloc donné",
+ ["it"]="nessun oggetto specificato",
+ ["nl"]="geen blok opgegeven",
+ ["no"]="ingen blokk oppgitt",
+ ["ro"]="nu este dat nici un bloc",
+ },
+ ["12"]={
+ ["cs"]="nedefinovano",
+ ["de"]="undefiniert",
+ ["en"]="undefined",
+ ["fr"]="indéfini",
+ ["it"]="non definito",
+ ["nl"]="niet gedefinieerd",
+ ["no"]="udefinert",
+ ["ro"]="nedefinit",
+ },
+ ["13"]={
+ ["cs"]="there is nothing to split",
+ ["de"]="there is nothing to split",
+ ["en"]="there is nothing to split",
+ ["fr"]="there is nothing to split",
+ ["it"]="there is nothing to split",
+ ["nl"]="er is niets te splitsen",
+ ["no"]="there is nothing to split",
+ ["ro"]="there is nothing to split",
+ },
+ ["2"]={
+ ["cs"]="-- ulozeno",
+ ["de"]="-- gespeichert",
+ ["en"]="-- saved",
+ ["fr"]="-- sauvegardé",
+ ["it"]="-- salvato",
+ ["nl"]="-- bewaard",
+ ["no"]="-- lagret",
+ ["ro"]="-- salvat",
+ },
+ ["3"]={
+ ["cs"]="-- presunuto",
+ ["de"]="-- verschoben",
+ ["en"]="-- moved",
+ ["fr"]="-- déplacé",
+ ["it"]="-- mosso",
+ ["nl"]="-- verplaatst",
+ ["no"]="-- flyttet",
+ ["ro"]="-- mutat",
+ },
+ ["4"]={
+ ["cs"]="-- umisteno",
+ ["de"]="-- plaziert",
+ ["en"]="-- placed",
+ ["fr"]="-- placé",
+ ["it"]="-- sistemato",
+ ["nl"]="-- geplaatst",
+ ["no"]="-- plassert",
+ ["ro"]="-- plasat",
+ },
+ ["5"]={
+ ["cs"]="poradi prizpusobeno",
+ ["de"]="Reihenfolge angepasst",
+ ["en"]="order adapted",
+ ["fr"]="ordre adapté",
+ ["it"]="ordine aggiustato",
+ ["nl"]="volgorde aangepast",
+ ["no"]="rekkefølge tilpasset",
+ ["ro"]="ordinea adaptata",
+ },
+ ["6"]={
+ ["cs"]="pocet hornich plovoucich objektu je omezen na --",
+ ["de"]="Anz. der oberen Gleitobjekte beschraengt auf --",
+ ["en"]="n of top floats limited to --",
+ ["fr"]="n flottants de haut de page limité à --",
+ ["it"]="n di top floats limitato a --",
+ ["nl"]="maximaal -- boven",
+ ["no"]="maksimalt -- flytblokker øverst",
+ ["ro"]="nr. cadrelor de sus limitat la --",
+ },
+ ["7"]={
+ ["cs"]="pocet spodnich plovoucich objektu je omezen na --",
+ ["de"]="Anz. der unteren Gleitobjekte beschraengt auf --",
+ ["en"]="n of bottom floats limited to --",
+ ["fr"]="n flottants de bas de page limité à --",
+ ["it"]="n di bottom floats limitato a --",
+ ["nl"]="maximaal -- onder",
+ ["no"]="maksimalt -- flytblokker nederst",
+ ["ro"]="nr. blocurilor de jos limitat la --",
+ },
+ ["8"]={
+ ["cs"]="radku je mene nez --",
+ ["de"]="weniger als -- zeilen",
+ ["en"]="less than -- lines",
+ ["fr"]="moins de -- lignes",
+ ["it"]="meno di -- righe",
+ ["nl"]="minder dan -- regels",
+ ["no"]="mindre enn -- linjer",
+ ["ro"]="mai putin de -- linii",
+ },
+ ["9"]={
+ ["cs"]="poradi naruseno",
+ ["de"]="Reigenfolge gestoert",
+ ["en"]="order disturbed",
+ ["fr"]="ordre perturbé",
+ ["it"]="ordine disturbato",
+ ["nl"]="volgorde verstoord",
+ ["no"]="rekkefølge endret",
+ ["ro"]="ordinea deranjata",
+ },
+ ["files"]={ "page-flt.tex", "strc-flt.tex" },
+ ["title"]={
+ ["cs"]="plovouciobjekty",
+ ["de"]="Gleitobjektbloecke",
+ ["en"]="floatblocks",
+ ["fr"]="blocs de flottants",
+ ["it"]="oggetti mobili",
+ ["nl"]="plaatsblokken",
+ ["no"]="flytblokker",
+ ["ro"]="Blocuri",
+ },
+ },
+ ["fonts"]={
+ ["1"]={
+ ["cs"]="kodovani --",
+ ["de"]="Kodierung --",
+ ["en"]="coding --",
+ ["fr"]="encodage --",
+ ["it"]="codifica --",
+ ["nl"]="codering --",
+ ["no"]="koding --",
+ ["ro"]="codificarea --",
+ },
+ ["10"]={
+ ["cs"]="neznamy font --",
+ ["de"]="unbekanntes Font --",
+ ["en"]="unknown font file --",
+ ["fr"]="fichier de police -- inconnu",
+ ["it"]="file di font sconosciuto --",
+ ["nl"]="onbekende font file --",
+ ["no"]="ukjent fontfil --",
+ ["ro"]="fisier font necunoscut --",
+ },
+ ["14"]={
+ ["cs"]="bodyfont -- is defined (can better be done global)",
+ ["de"]="Fliesstext -- wurde definiert (besser waere globale Definition)",
+ ["en"]="bodyfont -- is defined (can better be done global)",
+ ["fr"]="policecorps -- est défini (une définition globale pourrait être plus adéquat)",
+ ["it"]="corpo del testo -- definito (sarebbe meglio globale)",
+ ["nl"]="korps -- is gedefinieerd (kan beter globaal plaatsvinden)",
+ ["no"]="bodyfont -- is defined (can better be done global)",
+ ["ro"]="bodyfont -- is defined (can better be done global)",
+ },
+ ["2"]={
+ ["cs"]="varianta -- je nactena",
+ ["de"]="Variante -- ist geladen",
+ ["en"]="variant -- is loaded",
+ ["fr"]="la variante -- est chargée",
+ ["it"]="variante -- caricata",
+ ["nl"]="variant -- wordt geladen",
+ ["no"]="variant -- er lest inn",
+ ["ro"]="varianta -- este incarcata",
+ },
+ ["3"]={
+ ["cs"]="neznama varianta --",
+ ["de"]="Unbekannte Variante --",
+ ["en"]="unknown variant --",
+ ["fr"]="variante -- inconnue",
+ ["it"]="variante sconosciuta --",
+ ["nl"]="onbekende variant --",
+ ["no"]="ukjent variant --",
+ ["ro"]="varianta necunoscuta --",
+ },
+ ["4"]={
+ ["cs"]="zakladni font -- neni definovan",
+ ["de"]="Fliesstext -- ist nicht definiert",
+ ["en"]="bodyfont -- is not defined",
+ ["fr"]="policecorps -- n'est pas définie",
+ ["it"]="corpo del testo -- non definito",
+ ["nl"]="korps -- is niet gedefinieerd",
+ ["no"]="hovedfont -- er ikke definert",
+ ["ro"]="corpul de litere -- nu este definit",
+ },
+ ["5"]={
+ ["cs"]="styl -- neni definovan",
+ ["de"]="Stil -- ist nicht definiert",
+ ["en"]="style -- is not defined",
+ ["fr"]="le style -- n'est pas défini",
+ ["it"]="stile -- non definito",
+ ["nl"]="stijl -- is niet gedefinieerd",
+ ["no"]="stil -- er ikke definert",
+ ["ro"]="stilul -- nu este definit",
+ },
+ ["6"]={
+ ["cs"]="-- je nacten",
+ ["de"]="-- ist geladen",
+ ["en"]="-- is loaded",
+ ["fr"]="-- est chargé",
+ ["it"]="-- caricato",
+ ["nl"]="-- wordt geladen",
+ ["no"]="-- er lest inn",
+ ["ro"]="-- este incarcat",
+ },
+ ["7"]={
+ ["cs"]="neznamy format --",
+ ["de"]="unbekanntes Format --",
+ ["en"]="unknown format --",
+ ["fr"]="format -- inconnu",
+ ["it"]="formato sconosciuto --",
+ ["nl"]="onbekend formaat --",
+ ["no"]="ukjent format --",
+ ["ro"]="format necunoscut --",
+ },
+ ["8"]={
+ ["cs"]="styl -- definovan",
+ ["de"]="Stil -- definiert",
+ ["en"]="style -- defined",
+ ["fr"]="style -- défini",
+ ["it"]="stile -- definito",
+ ["nl"]="stijl -- gedefinieerd",
+ ["no"]="stil -- definert",
+ ["ro"]="stilul -- definit",
+ },
+ ["files"]={ "font-ini.mkii", "font-ini.mkiv" },
+ ["title"]={
+ ["cs"]="zakladnifont",
+ ["de"]="Fliesstext",
+ ["en"]="bodyfont",
+ ["fr"]="corps de texte",
+ ["it"]="font del corpo",
+ ["nl"]="korps",
+ ["no"]="hovedfont",
+ ["ro"]="corp de litere",
+ },
+ },
+ ["handlings"]={
+ ["1"]={
+ ["cs"]="font handling --",
+ ["de"]="Font Verarbeitung --",
+ ["en"]="font handling --",
+ ["fr"]="manipulation -- de police",
+ ["it"]="font handling --",
+ ["nl"]="font afhandeling --",
+ ["no"]="font handling --",
+ ["ro"]="font handling --",
+ },
+ ["2"]={
+ ["cs"]="font handling -- is loaded",
+ ["de"]="Font Verarbeitung -- ist geladen",
+ ["en"]="font handling -- is loaded",
+ ["fr"]="la manipulation -- de police est chargée",
+ ["it"]="font handling -- is loaded",
+ ["nl"]="font afhandeling -- wordt geladen",
+ ["no"]="font handling -- is loaded",
+ ["ro"]="font handling -- is loaded",
+ },
+ ["3"]={
+ ["cs"]="unknown font handling --",
+ ["de"]="unknown font handling --",
+ ["en"]="unknown font handling --",
+ ["fr"]="manipulation -- inconnue de police",
+ ["it"]="unknown font handling --",
+ ["nl"]="onbekende font afhandeling --",
+ ["no"]="unknown font handling --",
+ ["ro"]="unknown font handling --",
+ },
+ ["files"]={ "hand-ini.mkii" },
+ ["title"]={
+ ["cs"]="handling",
+ ["de"]="handling",
+ ["en"]="handling",
+ ["fr"]="manipulation",
+ ["it"]="handling",
+ ["nl"]="handling",
+ ["no"]="handling",
+ ["ro"]="handling",
+ },
+ },
+ ["interactions"]={
+ ["1"]={
+ ["cs"]="pomer -- x -- (s x v)",
+ ["de"]="Seitenverhaeltnis -- x -- (B x H)",
+ ["en"]="aspect ratio -- x -- (b x h)",
+ ["fr"]="ratio d'aspect -- x -- (b x h)",
+ ["it"]="rapporto -- x -- (b x a)",
+ ["nl"]="aspect ratio -- x -- (b x h)",
+ ["no"]="forholdstall -- x -- (b x h)",
+ ["ro"]="aspectul -- x -- (b x h)",
+ },
+ ["2"]={
+ ["cs"]="aktivni",
+ ["de"]="aktiv",
+ ["en"]="active",
+ ["fr"]="actif",
+ ["it"]="attiva",
+ ["nl"]="actief",
+ ["no"]="aktiv",
+ ["ro"]="activ",
+ },
+ ["21"]={
+ ["cs"]="-- kod vlozen",
+ ["de"]="-- Code eingefuegt",
+ ["en"]="-- code inserted",
+ ["fr"]="-- code inseré",
+ ["it"]="codice -- inserito",
+ ["nl"]="-- code tussengevoegd",
+ ["no"]="-- kode satt inn / tilføyd",
+ ["ro"]="-- cod inserat",
+ },
+ ["3"]={
+ ["cs"]="neaktivni",
+ ["de"]="inaktiv",
+ ["en"]="inactive",
+ ["fr"]="inactif",
+ ["it"]="inattiva",
+ ["nl"]="niet actief",
+ ["no"]="inaktiv",
+ ["ro"]="inactiv",
+ },
+ ["4"]={
+ ["cs"]="zadna strankova synchronizace (--) v hmode",
+ ["de"]="keine Seitensynchronisation (--) im hmode",
+ ["en"]="no pagesynchronisation (--) in hmode",
+ ["fr"]="pas de synchronisation de page (--) dans le hmode",
+ ["it"]="sincronizzazione di pagina (--) non disponibile in hmode",
+ ["nl"]="geen paginasynchronisatie (--) in hmode",
+ ["no"]="ingen sidesynkronisering (--) i hmode",
+ ["ro"]="nu exista sincronizare pt. pagini (--) in hmode",
+ },
+ ["5"]={
+ ["cs"]="unknown attachment --",
+ ["de"]="unknown attachment --",
+ ["en"]="unknown attachment --",
+ ["fr"]="le fichier joint -- est inconnu",
+ ["it"]="unknown attachment --",
+ ["nl"]="onbekend attachment --",
+ ["no"]="unknown attachment --",
+ ["ro"]="unknown attachment --",
+ },
+ ["6"]={
+ ["cs"]="attachment file -- does not exist",
+ ["de"]="attachment file -- does not exist",
+ ["en"]="attachment file -- does not exist",
+ ["fr"]="le fichier joint -- n'existe pas",
+ ["it"]="attachment file -- does not exist",
+ ["nl"]="attachment file -- bestaat niet",
+ ["no"]="attachment file -- does not exist",
+ ["ro"]="attachment file -- does not exist",
+ },
+ ["files"]={ "core-int.tex", "spec-ini.tex" },
+ ["title"]={
+ ["cs"]="interakce",
+ ["de"]="Interaktion",
+ ["en"]="interaction",
+ ["fr"]="interaction",
+ ["it"]="interazione",
+ ["nl"]="interactie",
+ ["no"]="interaksjon",
+ ["ro"]="interactiuni",
+ },
+ },
+ ["javascript"]={
+ ["1"]={
+ ["cs"]="nacita se soubor skriptu --",
+ ["de"]="Lade Scriptdatei --",
+ ["en"]="loading script set --",
+ ["fr"]="chargement du jeu de script --",
+ ["it"]="caricamento dello script set --",
+ ["nl"]="script set -- wordt geladen",
+ ["no"]="leser inn scriptsett --",
+ ["ro"]="se incarca scriptul --",
+ },
+ ["2"]={
+ ["cs"]="neznama preambule --",
+ ["de"]="unbekannte Preamble --",
+ ["en"]="unknown preamble --",
+ ["fr"]="préambule -- inconnu",
+ ["it"]="preambolo sconosciuto --",
+ ["nl"]="onbekende preamble --",
+ ["no"]="ukjent 'preamble' --",
+ ["ro"]="preambul necunoscut --",
+ },
+ ["files"]={ "java-ini.tex" },
+ ["title"]={
+ ["cs"]="javascript",
+ ["de"]="javascript",
+ ["en"]="javascript",
+ ["fr"]="javascript",
+ ["it"]="javascript",
+ ["nl"]="javascript",
+ ["no"]="javascript",
+ ["ro"]="javascript",
+ },
+ },
+ ["layouts"]={
+ ["1"]={
+ ["cs"]="vyska textu prizpusobena s -- na strane --",
+ ["de"]="Texthoehe angepasst mit -- auf Seite --",
+ ["en"]="textheight adapted with -- at page --",
+ ["fr"]="hauteurtexte adaptée avec -- à la page --",
+ ["it"]="altezza del testo adattata con -- a pagina --",
+ ["nl"]="teksthoogte aangepast met -- op pagina --",
+ ["no"]="teksthøyde tilpasset med -- på side --",
+ ["ro"]="textheight adaptat cu -- la pagina --",
+ },
+ ["10"]={
+ ["cs"]="-- a -- nedava dohromady 1.0",
+ ["de"]="-- und -- ergeben zusammen nicht 1.0",
+ ["en"]="-- and -- don't add up to 1.0",
+ ["fr"]="-- et -- ne sont pas ajoutés à 1.0",
+ ["it"]="-- e -- non sommano a 1.0",
+ ["nl"]="-- en -- tellen niet op tot 1.0",
+ ["no"]="-- og -- er ikke 1.0 til sammen",
+ ["ro"]="-- si -- nu se adauga pana la 1.0",
+ },
+ ["11"]={
+ ["cs"]="svisla mezera -- neni povolena v pevnem radkovem rejstriku",
+ ["de"]="Zwischenraum -- nicht im Grittermoduserlau",
+ ["en"]="spacing -- not permitted in gridmode",
+ ["fr"]="espacement -- non permis en modegrille",
+ ["it"]="spaziatura -- non permessa in modo griglia",
+ ["nl"]="interlinie -- niet toegestaan in gridmode",
+ ["no"]="mellomrom -- ikke tillatt i gridmodus",
+ ["ro"]="spatierea -- nu este permisa in gridmode",
+ },
+ ["2"]={
+ ["cs"]="-- krat odlozeny text umisten",
+ ["de"]="-- mal verschobener Text plaziert",
+ ["en"]="-- times postponed text placed",
+ ["fr"]="-- times postponed text placed",
+ ["it"]="posizionato testo posticipato -- volte",
+ ["nl"]="-- maal uitgestelde tekst tussengevoegd",
+ ["no"]="-- ganger forskjøvet tekst plassert",
+ ["ro"]="textul amanat de -- ori a fost plasat",
+ },
+ ["3"]={
+ ["cs"]="-- krat text odlozen",
+ ["de"]="-- mal Text verschoben",
+ ["en"]="-- times text postponed",
+ ["fr"]="-- times text postponed",
+ ["it"]="testo posticipato -- volte",
+ ["nl"]="-- maal tekst plaatsen uitstellen",
+ ["no"]="-- ganger tekst forskjøvet",
+ ["ro"]="textul amanat de -- ori",
+ },
+ ["4"]={
+ ["cs"]="okrajove bloky aktivni",
+ ["de"]="marginalbloecke aktiv",
+ ["en"]="marginblocks active",
+ ["fr"]="blocsmarge actifs",
+ ["it"]="blocchi in margine attivi",
+ ["nl"]="margeblokken actief",
+ ["no"]="margblokker aktive",
+ ["ro"]="blocuri marginale active",
+ },
+ ["5"]={
+ ["cs"]="okrajove bloky neaktivni",
+ ["de"]="marginalbloecke inaktiv",
+ ["en"]="marginblocks inactive",
+ ["fr"]="blocsmarge inactifs",
+ ["it"]="blocchi in margine inattivi",
+ ["nl"]="margeblokken inactief",
+ ["no"]="margblokker inaktive",
+ ["ro"]="blocuri marginale inactive",
+ },
+ ["6"]={
+ ["cs"]="sada stran -- zpracovana (velikost --)",
+ ["de"]="Unterseitenfolge -- verarbeitet (Groesse --)",
+ ["en"]="subpage set -- processed (size --)",
+ ["fr"]="jeu de souspage -- traité (taille --)",
+ ["it"]="gruppo di sottopagine -- elaborato (dimensione --)",
+ ["nl"]="subpagina reeks -- verwerkt (aantal --)",
+ ["no"]="delside sett -- behandlet (størrelse --)",
+ ["ro"]="setul -- de subpagini procesat (dimensiunea --)",
+ },
+ ["7"]={
+ ["cs"]="pocita se misto pro logo",
+ ["de"]="berechne Platzbedarf des Logos",
+ ["en"]="calculating logospace",
+ ["fr"]="calcul de l'espace pour le logo",
+ ["it"]="calcolo dello spazio per logo",
+ ["nl"]="beeldmerken berekenen",
+ ["no"]="beregner plass for logo",
+ ["ro"]="se calculeaza spatiul pentru logo",
+ },
+ ["8"]={
+ ["cs"]="pocita se pozadi",
+ ["de"]="berechne Hintergrund",
+ ["en"]="calculating backgrounds",
+ ["fr"]="calcul des arrières-plans",
+ ["it"]="calcolo dello sfondo",
+ ["nl"]="achtergronden berekenen",
+ ["no"]="beregner bakgrunn",
+ ["ro"]="se calculeaza fundalurile",
+ },
+ ["9"]={
+ ["cs"]="aktualne ne vice nez -- urovne/urovni vyctu",
+ ["de"]="z.Z. nicht mehr als -- Ebenen in Aufzaehlungen",
+ ["en"]="currently no more than -- levels in itemizations",
+ ["fr"]="pas plus de -- niveaux pour l'instant dans les élémentarisations",
+ ["it"]="attualmente non più di -- livelli di elencazione",
+ ["nl"]="momenteel maximaal -- niveaus in opsommingen",
+ ["no"]="for øyeblikket maksimalt -- nivåer i opplisting",
+ ["ro"]="acum nu se supota mai mult de -- nivele de adancime la iteratii",
+ },
+ ["files"]={ "core-itm.tex", "page-bck.mkii", "page-bck.mkiv", "page-ini.tex", "page-log.tex", "strc-itm.tex" },
+ ["title"]={
+ ["cs"]="layout",
+ ["de"]="Layout",
+ ["en"]="layout",
+ ["fr"]="calque",
+ ["it"]="layout",
+ ["nl"]="layout",
+ ["no"]="layout",
+ ["ro"]="aranjamente",
+ },
+ },
+ ["linguals"]={
+ ["1"]={
+ ["cs"]="vzory -- pro -- nacteny (n=--,e=--,m=--)",
+ ["de"]="Trennmuster -- fuer -- geladen (n=--,e=--,m=--)",
+ ["en"]="patterns -- for -- loaded (n=--,e=--,m=--)",
+ ["fr"]="les motifs -- pour -- sont chargés (n=--,e=--,m=--)",
+ ["it"]="schemi -- per -- caricati (n=--,e=--,m=--)",
+ ["nl"]="afbreekpatronen -- voor -- geladen (n=--,e=--,m=--)",
+ ["no"]="orddelingsmønster -- for -- er lest inn (n=--,e=--,m=--)",
+ ["ro"]="sablonul -- pentru -- s-a incarcat (n=--,e=--,m=--)",
+ },
+ ["10"]={
+ ["cs"]="vzory --nacteny",
+ ["de"]="Trennmuster --geladen",
+ ["en"]="patterns --loaded",
+ ["fr"]="motifs -- chargés",
+ ["it"]="schemi -- caricati",
+ ["nl"]="patronen --geladen",
+ ["no"]="orddelingsmønster -- er lest inn",
+ ["ro"]="sabloanele -- incarcate",
+ },
+ ["2"]={
+ ["cs"]="zadne vzory -- pro -- (n=--,e=--,m=--) (--,--)",
+ ["de"]="Keine Trennmuster -- fuer -- (n=--,e=--,m=--) (--,--)",
+ ["en"]="no patterns -- for -- (n=--,e=--,m=--) (--,--)",
+ ["fr"]="pas de motifs -- pour -- (n=--,e=--,m=--) (--,--)",
+ ["it"]="niente schemi -- per -- (n=--,e=--,m=--) (--,--)",
+ ["nl"]="geen afbreekpatronen -- voor -- (n=--,e=--,m=--) (--,--)",
+ ["no"]="ingen orddelingsmønster -- for -- (n=--,e=--,m=--) (--,--)",
+ ["ro"]="nu exista sabloane -- pentru -- (n=--,e=--,m=--) (--,--)",
+ },
+ ["3"]={
+ ["cs"]="deleni slov -- pro -- nacteno (n=--,e=--,m=--)",
+ ["de"]="Trenndefinitionen -- fuer -- geladen (n=--,e=--,m=--)",
+ ["en"]="hyphenations -- for -- loaded (n=--,e=--,m=--)",
+ ["fr"]="hyphenations -- pour -- chargés (n=--,e=--,m=--)",
+ ["it"]="sillabazione -- per -- caricata (n=--,e=--,m=--)",
+ ["nl"]="afbreekdefinities -- voor -- geladen (n=--,e=--,m=--)",
+ ["no"]="orddelingsdefinisjon -- for -- er lest inn (n=--,e=--,m=--)",
+ ["ro"]="despartirea in silabe -- pentru -- s-a incarcat (n=--,e=--,m=--)",
+ },
+ ["4"]={
+ ["cs"]="zadne deleni slov -- pro -- (n=--,e=--,m=--)",
+ ["de"]="Keine Trenndefinitionen -- fuer -- (n=--,e=--,m=--)",
+ ["en"]="no hyphenations -- for -- (n=--,e=--,m=--)",
+ ["fr"]="pas d'hyphenations -- pour -- (n=--,e=--,m=--)",
+ ["it"]="niente sillabazione -- per -- (n=--,e=--,m=--)",
+ ["nl"]="geen afbreekdefinities -- voor -- (n=--,e=--,m=--)",
+ ["no"]="ingen orddelingsdefinisjon -- for -- (n=--,e=--,m=--)",
+ ["ro"]="nu exista despartire in silabe -- pentru -- (n=--,e=--,m=--)",
+ },
+ ["5"]={
+ ["cs"]="vzory pro -- nenacteny",
+ ["de"]="Trennmuster fuer -- nicht geladen",
+ ["en"]="patterns for -- not loaded",
+ ["fr"]="les motifs pour -- ne sont pas chargés",
+ ["it"]="schemi per -- non caricati",
+ ["nl"]="afbreekpatronen voor -- niet geladen",
+ ["no"]="orddelingsmønster for -- er ikke lest inn",
+ ["ro"]="sabloanele pentru -- nu sunt incarcate",
+ },
+ ["6"]={
+ ["cs"]="jazyk -- neni definovan",
+ ["de"]="Sprache -- ist undefiniert",
+ ["en"]="language -- is undefined",
+ ["fr"]="langue -- non définie",
+ ["it"]="lingua -- non definita",
+ ["nl"]="taal -- is niet gedefinieerd",
+ ["no"]="spràk -- er udefinert",
+ ["ro"]="limba -- nu este definita",
+ },
+ ["7"]={
+ ["cs"]="specificke volby jazyka [--] zavadeji -- (zavlecenou) mezeru",
+ ["de"]="Sprachenspezifische Option [--] fuegt eine Luecke von -- ein",
+ ["en"]="language specific options [--] introduce a -- skip",
+ ["fr"]="les options spécifiques de langue [--] introduisent un -- saut",
+ ["it"]="opzioni specifiche per la lingua [--] introducono un salto --",
+ ["nl"]="taal specifieke opties [--] introduceren een skip van --",
+ ["no"]="spràk spesifikk opsjon [--] introduserer et -- hopp",
+ ["ro"]="optiunile specifice ale limbii [--] introduc un spatiu --",
+ },
+ ["8"]={
+ ["cs"]="specificke volby jazyka [--] bez mezer pripojeny",
+ ["de"]="Sprachenspezifische Option [--] nahtlos hinzugefuegt",
+ ["en"]="language specific options [--] seamless appended",
+ ["fr"]="les options spécifiques de langue [--] sont ajoutés en douceur",
+ ["it"]="opzioni specifiche per la lingua [--] aggiunte trasparentemente",
+ ["nl"]="taal specifieke opties [--] naadloos toegevoegd",
+ ["no"]="spràk spesifikk opsjon [--] problemfritt tilføyd",
+ ["ro"]="optiunile specifice ale limbii [--] adaugate",
+ },
+ ["9"]={
+ ["cs"]="language -- is active",
+ ["de"]="Sprache -- ist aktiv",
+ ["en"]="language -- is active",
+ ["fr"]="la langue -- est active",
+ ["it"]="lingua -- attiva",
+ ["nl"]="taal -- is actief",
+ ["no"]="spràk -- er aktivt",
+ ["ro"]="limba -- este activa",
+ },
+ ["files"]={ "lang-ini.mkii", "lang-ini.mkiv" },
+ ["title"]={
+ ["cs"]="jazyky",
+ ["de"]="Sprache",
+ ["en"]="language",
+ ["fr"]="langue",
+ ["it"]="lingua",
+ ["nl"]="taal",
+ ["no"]="sprøk",
+ ["ro"]="limbi",
+ },
+ },
+ ["metapost"]={
+ ["1"]={
+ ["cs"]="loading metapost library --",
+ ["de"]="Lade metapost Bibliothek --",
+ ["en"]="loading metapost library --",
+ ["fr"]="chargement de la bibliothèque metapost --",
+ ["it"]="caricamento della libreria metapost --",
+ ["nl"]="metapost bibliotheek -- wordt geladen",
+ ["no"]="metapost bibliotek -- blir lest inn",
+ ["ro"]="se incarca biblioteca metapost --",
+ },
+ ["files"]={ "meta-ini.mkii", "meta-ini.mkiv" },
+ ["title"]={
+ ["cs"]="metapost",
+ ["de"]="metapost",
+ ["en"]="metapost",
+ ["fr"]="metapost",
+ ["it"]="metapost",
+ ["nl"]="metapost",
+ ["no"]="metapost",
+ ["ro"]="metapost",
+ },
+ },
+ ["references"]={
+ ["1"]={
+ ["cs"]="neznama reference --",
+ ["de"]="unbekannte Referenz --",
+ ["en"]="unknown reference --",
+ ["fr"]="réference -- inconnue",
+ ["it"]="riferimento sconosciuto --",
+ ["nl"]="onbekende verwijzing --",
+ ["no"]="ukjent referanse --",
+ ["ro"]="referinta necunoscuta --",
+ },
+ ["2"]={
+ ["cs"]="duplicitni reference -- na strane --",
+ ["de"]="doppelte Referenz -- auf Seite --",
+ ["en"]="duplicate reference -- on page --",
+ ["fr"]="réference -- dupliquée à la page --",
+ ["it"]="riferimento duplicato -- a pagina --",
+ ["nl"]="dubbele verwijzing -- op pagina --",
+ ["no"]="duplikat referanse -- pø side --",
+ ["ro"]="referinta duplicat -- la pagina --",
+ },
+ ["21"]={
+ ["cs"]="dokument -- nacten",
+ ["de"]="Dokument -- geladen",
+ ["en"]="document -- loaded",
+ ["fr"]="document -- chargé",
+ ["it"]="documento -- caricato",
+ ["nl"]="document -- geladen",
+ ["no"]="dokument -- er lest inn",
+ ["ro"]="documentul -- este incarcat",
+ },
+ ["22"]={
+ ["cs"]="dokument -- neni interaktivni",
+ ["de"]="Dokument -- ist nicht aktiv",
+ ["en"]="document -- is not interactive",
+ ["fr"]="le document -- n'est pas interactif",
+ ["it"]="il documento -- non ø interattivo",
+ ["nl"]="document -- is niet interactief",
+ ["no"]="dokument -- er ikke interaktivt",
+ ["ro"]="documentul -- nu este interactiv",
+ },
+ ["23"]={
+ ["cs"]="obskurni (nejasna) reference -- (prefix=--)",
+ ["de"]="Obskure Referenz -- (Prefix=--)",
+ ["en"]="obscure reference -- (prefix=--)",
+ ["fr"]="reference -- indéterminé (préfixe=--)",
+ ["it"]="riferimento ambiguo -- (prefisso=--)",
+ ["nl"]="onduidelijke verwijzing -- (prefix=--)",
+ ["no"]="obskur referanse -- (Prefix=--)",
+ ["ro"]="referinta obscura -- (prefix=--)",
+ },
+ ["3"]={
+ ["cs"]="neznamy typ reference --",
+ ["de"]="unbekannte Referenz Typ --",
+ ["en"]="unknown reference type --",
+ ["fr"]="type -- de réference inconnu",
+ ["it"]="riferimento di tipo sconosciuto --",
+ ["nl"]="type verwijzing -- onbekend",
+ ["no"]="ukjent referansetype --",
+ ["ro"]="tip necunoscut de referinta --",
+ },
+ ["30"]={
+ ["cs"]="neznamy objekt --",
+ ["de"]="unbekanntes Object --",
+ ["en"]="unknown object --",
+ ["fr"]="objet -- inconnu",
+ ["it"]="oggetto sconosciuto --",
+ ["nl"]="onbekend object --",
+ ["no"]="ukjent objekt --",
+ ["ro"]="obiect necunoscut --",
+ },
+ ["31"]={
+ ["cs"]="duplicitni object --",
+ ["de"]="doppeltes Object --",
+ ["en"]="duplicate object --",
+ ["fr"]="objet -- dupliqué",
+ ["it"]="oggetto duplicato --",
+ ["nl"]="dubbel object --",
+ ["no"]="duplikat objekt --",
+ ["ro"]="obiect duplicat --",
+ },
+ ["4"]={
+ ["cs"]="nedovolena reference --",
+ ["de"]="illegale Referenz --",
+ ["en"]="illegal reference --",
+ ["fr"]="réference -- inconnue",
+ ["it"]="riferimento illecito --",
+ ["nl"]="verboden verwijzing --",
+ ["no"]="ulovlig referanse --",
+ ["ro"]="referinta eronata --",
+ },
+ ["files"]={ "core-obj.tex", "core-ref.tex", "strc-ref.tex" },
+ ["title"]={
+ ["cs"]="reference",
+ ["de"]="referenzen",
+ ["en"]="references",
+ ["fr"]="réferences",
+ ["it"]="riferimenti",
+ ["nl"]="verwijzingen",
+ ["no"]="referanser",
+ ["ro"]="referinte",
+ },
+ },
+ ["regimes"]={
+ ["1"]={
+ ["cs"]="kodovani --",
+ ["de"]="Kodierung --",
+ ["en"]="regime --",
+ ["fr"]="encodage --",
+ ["it"]="codifica --",
+ ["nl"]="regime --",
+ ["no"]="koding --",
+ ["ro"]="codificarea --",
+ },
+ ["2"]={
+ ["cs"]="je nacteno kodovani --",
+ ["de"]="Kodierung -- ist geladen",
+ ["en"]="regime -- is loaded",
+ ["fr"]="l'encodage -- est chargé",
+ ["it"]="codifica -- caricata",
+ ["nl"]="regime -- wordt geladen",
+ ["no"]="koding -- er lest inn",
+ ["ro"]="codificarea -- este Encarcata",
+ },
+ ["3"]={
+ ["cs"]="nezname kodovani --",
+ ["de"]="Unbekannte Kodierung --",
+ ["en"]="unknown regime --",
+ ["fr"]="encodage -- inconnu",
+ ["it"]="codifica sconosciuta --",
+ ["nl"]="onbekend regime --",
+ ["no"]="ukjent koding --",
+ ["ro"]="codificarea -- este necunoscuta",
+ },
+ ["files"]={ "regi-ini.mkii" },
+ ["title"]={
+ ["cs"]="kodovani",
+ ["de"]="Kodierung",
+ ["en"]="regime",
+ ["fr"]="encodage",
+ ["it"]="codifica",
+ ["nl"]="regime",
+ ["no"]="koding",
+ ["ro"]="codificari",
+ },
+ },
+ ["specials"]={
+ ["1"]={
+ ["cs"]="-- nacteno",
+ ["de"]="-- geladen",
+ ["en"]="-- loaded",
+ ["fr"]="-- chargé",
+ ["it"]="-- caricato",
+ ["nl"]="-- geladen",
+ ["no"]="-- er lest inn",
+ ["ro"]="-- incarcat",
+ },
+ ["2"]={
+ ["cs"]="neni dovoleno hlubsi zanoreni --",
+ ["de"]="keine tiefere Verschachtelung erlaubt --",
+ ["en"]="no deeper nesting is permitted --",
+ ["fr"]="pas d'imbracations plus profondes ne sont permises --",
+ ["it"]="non ø permesso un annidamento maggiore --",
+ ["nl"]="verdere nesting is niet toegestaan --",
+ ["no"]="dypere 'nesting' er ikke tillatt --",
+ ["ro"]="nu este permis un nivel de imbricare mai mare --",
+ },
+ ["3"]={
+ ["cs"]="-- je resetovano",
+ ["de"]="-- ist zurueckgesetzt",
+ ["en"]="-- is reset",
+ ["fr"]="-- est remis à zéro",
+ ["it"]="-- reimpostato",
+ ["nl"]="-- gereset",
+ ["no"]="-- er tilbakestilt",
+ ["ro"]="-- s-a resetat",
+ },
+ ["4"]={
+ ["cs"]="prikaz -- neexistuje",
+ ["de"]="Befehl -- existiert nicht",
+ ["en"]="command -- does not exist",
+ ["fr"]="la commande -- n'existe pas",
+ ["it"]="il comando -- non esiste",
+ ["nl"]="commando -- bestaat niet",
+ ["no"]="kommando -- eksisterer ikke",
+ ["ro"]="comanda -- nu exista",
+ },
+ ["5"]={
+ ["cs"]="nacita se definicni soubor --",
+ ["de"]="lade Definitionsdatei --",
+ ["en"]="loading definition file --",
+ ["fr"]="chargement du fichier de définition --",
+ ["it"]="caricamento del file di definizione --",
+ ["nl"]="definitiefile -- wordt geladen",
+ ["no"]="leser inn definisjonsfil for --",
+ ["ro"]="se incarca fisierul de definitii --",
+ },
+ ["6"]={
+ ["cs"]="zanoreni neni dovoleno",
+ ["de"]="Verschachtelung nicht erlaubt",
+ ["en"]="nesting is not permitted",
+ ["fr"]="l'imbrication n'est pas permise",
+ ["it"]="annidamento non permesso",
+ ["nl"]="nesting is niet toegestaan",
+ ["no"]="'nesting' er ikke tillatt",
+ ["ro"]="imbricarea nu este permisa",
+ },
+ ["7"]={
+ ["cs"]="neznamy ovladac (driver) --",
+ ["de"]="unbekante Driver --",
+ ["en"]="unknown driver --",
+ ["fr"]="pilote -- inconnu",
+ ["it"]="driver sconosciuto --",
+ ["nl"]="onbekende driver --",
+ ["no"]="ukjent driver --",
+ ["ro"]="driver necunoscut --",
+ },
+ ["files"]={ "spec-ini.tex" },
+ ["title"]={
+ ["cs"]="speciality",
+ ["de"]="spezielles",
+ ["en"]="specials",
+ ["fr"]="specials",
+ ["it"]="specialitø",
+ ["nl"]="specials",
+ ["no"]="specials",
+ ["ro"]="specials",
+ },
+ },
+ ["structures"]={
+ ["1"]={
+ ["cs"]="zacatek oddilu (sekce) --",
+ ["de"]="Begin des Abschnittsblocks --",
+ ["en"]="begin of sectionblock --",
+ ["fr"]="début de blocsection --",
+ ["it"]="inizio del blocco (sezione) --",
+ ["nl"]="begin van sectieblok --",
+ ["no"]="starten av blokk -- (seksjon)",
+ ["ro"]="inceput de bloc sectiune --",
+ },
+ ["2"]={
+ ["cs"]="konec oddilu (sekce) --",
+ ["de"]="Ende des Abschnittsblocks --",
+ ["en"]="end of sectionblock --",
+ ["fr"]="fin de blocsection --",
+ ["it"]="fine del blocco (sezione) --",
+ ["nl"]="eind van sectieblok --",
+ ["no"]="slutten av blokk -- (seksjon)",
+ ["ro"]="sfarsit de bloc sectiune --",
+ },
+ ["files"]={ "core-sec.mkii", "core-sec.mkiv", "strc-sbe.tex" },
+ ["title"]={
+ ["cs"]="struktury",
+ ["de"]="struktur",
+ ["en"]="structure",
+ ["fr"]="structure",
+ ["it"]="struttura",
+ ["nl"]="structuur",
+ ["no"]="struktur",
+ ["ro"]="structuri",
+ },
+ },
+ ["symbols"]={
+ ["1"]={
+ ["cs"]="nacita se soubor symbolu --",
+ ["de"]="Lade Symboldatei --",
+ ["en"]="loading symbolset --",
+ ["fr"]="chargement du jeu de symbole --",
+ ["it"]="caricamento gruppo di simboli --",
+ ["nl"]="symboolset -- wordt geladen",
+ ["no"]="leser inn symbolsett --",
+ ["ro"]="se incarca setul de simboluri --",
+ },
+ ["files"]={ "symb-ini.tex" },
+ ["title"]={
+ ["cs"]="symboly",
+ ["de"]="Symbole",
+ ["en"]="symbols",
+ ["fr"]="symboles",
+ ["it"]="simboli",
+ ["nl"]="symbolen",
+ ["no"]="symboler",
+ ["ro"]="simboluri",
+ },
+ },
+ ["systems"]={
+ ["1"]={
+ ["cs"]="nacteni pomocneho souboru odlozeno (typemode)",
+ ["de"]="Laden der Hilfsdatei aufgeschoben (Eingabe-Modus)",
+ ["en"]="loading utility-file postponed (typemode)",
+ ["fr"]="chargement de fichier utilitaire reporté (typemode)",
+ ["it"]="caricamento dei file supplementari posticipato (typemode)",
+ ["nl"]="laden hulpfile uitgesteld (typemode)",
+ ["no"]="innlesning av hjelpefila utsatt (typemode)",
+ ["ro"]="se incarca utilitarul-fisierul este amanat (typemode)",
+ },
+ ["10"]={
+ ["cs"]="nepouzivejte em v --",
+ ["de"]="Benutzte kein em in --",
+ ["en"]="don't use em in --",
+ ["fr"]="n'utilisez pas em dans --",
+ ["it"]="non usare em in --",
+ ["nl"]="gebruik geen em in --",
+ ["no"]="ikke bruk em i --",
+ ["ro"]="nu folositi em in --",
+ },
+ ["11"]={
+ ["cs"]="vytvarim jednoduchy pomocny soubor",
+ ["de"]="Erstelle einfache Hilfdatei",
+ ["en"]="building simple util",
+ ["fr"]="construction util simple",
+ ["it"]="costruzione di un semplice supplemento",
+ ["nl"]="aanmaken basale hulpfile",
+ ["no"]="lager enkel hjelpefil",
+ ["ro"]="se creeaza un utilitar simplu",
+ },
+ ["12"]={
+ ["cs"]="pomosny soubor neni setriden, pouzijte texutil",
+ ["de"]="Die Hilfdatei ist nicht sortiert, verwende texutil",
+ ["en"]="the utility-file is not sorted, use texutil",
+ ["fr"]="le fichier utilitaire n'est pas trié, utilise texutil",
+ ["it"]="file di supplemento non ordinato, usare texutil",
+ ["nl"]="de hulpfile is niet gesorteerd, gebruik texutil",
+ ["no"]="hjelpefila er ikke sortert, bruk texutil",
+ ["ro"]="fisierul utilitar nu este sortat, folositi texutil",
+ },
+ ["13"]={
+ ["cs"]="znacka -- definovana --",
+ ["de"]="Beschriftung -- definiert --",
+ ["en"]="mark -- defined --",
+ ["fr"]="marquage -- defini --",
+ ["it"]="marcatura -- definita --",
+ ["nl"]="markering -- gedefinieerd --",
+ ["no"]="markering -- definert --",
+ ["ro"]="marcajul -- definit --",
+ },
+ ["14"]={
+ ["cs"]="vynucena nova stranka v seznamu na --",
+ ["de"]="Erzwungendes Seitenumbruch in Liste bei --",
+ ["en"]="forced newpage in list at --",
+ ["fr"]="nouvellepage forcée dans la liste à --",
+ ["it"]="nuova pagina obbligata in lista a --",
+ ["nl"]="geforceerde paginaovergang in lijst voor --",
+ ["no"]="tvunget sideskift i liste ved --",
+ ["ro"]="s-a fortat trecere pa pagina noua in lista la --",
+ },
+ ["15"]={
+ ["cs"]="uklada se buffer --",
+ ["de"]="Speichere Buffer --",
+ ["en"]="saving buffer --",
+ ["fr"]="sauvegarde du tampon (buffer) --",
+ ["it"]="salvataggio del buffer --",
+ ["nl"]="wegschrijven buffer --",
+ ["no"]="lagrer Buffer --",
+ ["ro"]="buffer salvat --",
+ },
+ ["16"]={
+ ["cs"]="sazi se buffer --",
+ ["de"]="Setzte Buffer --",
+ ["en"]="typesetting buffer --",
+ ["fr"]="composition du tampon (buffer) --",
+ ["it"]="composizione del buffer --",
+ ["nl"]="inlezen buffer --",
+ ["no"]="tegnsetter buffer --",
+ ["ro"]="buffer-ul -- s-a cules",
+ },
+ ["17"]={
+ ["cs"]="sazi se doslovny (verbatim) buffer --",
+ ["de"]="Setzte tippen-Buffer --",
+ ["en"]="typesetting verbatim buffer --",
+ ["fr"]="composition textuelle du tampon (buffer) --",
+ ["it"]="composizione verbatim del buffer --",
+ ["nl"]="verbatim inlezen buffer --",
+ ["no"]="tegnsetter verbatim-buffer --",
+ ["ro"]="se culege buffer-ul verbatim --",
+ },
+ ["18"]={
+ ["cs"]="synonymum -- -- neexistuje",
+ ["de"]="Synonym -- -- existiert nicht",
+ ["en"]="synonym -- -- does not exist",
+ ["fr"]="le synonyme -- -- n'existe pas",
+ ["it"]="sinonimo -- -- non esistente",
+ ["nl"]="synoniem -- -- bestaat niet",
+ ["no"]="synonym -- -- eksisterer ikke",
+ ["ro"]="sinonimul -- -- nu exista",
+ },
+ ["19"]={
+ ["cs"]="vyznam (synonyma) -- nacten",
+ ["de"]="Bedeutung (synonyme) von -- geladen",
+ ["en"]="meaning (synonyms) of -- loaded",
+ ["fr"]="signification (synonymes) de -- chargée",
+ ["it"]="significato (sinonimi) di -- caricato",
+ ["nl"]="betekenissen (synoniemen) van -- geladen",
+ ["no"]="betydning (synonymer) av -- er lest inn",
+ ["ro"]="intelesul (sinonimele) pentru -- incarcat",
+ },
+ ["2"]={
+ ["cs"]="-- nacteno",
+ ["de"]="-- geladen",
+ ["en"]="-- loaded",
+ ["fr"]="-- chargé",
+ ["it"]="-- caricato",
+ ["nl"]="-- geladen",
+ ["no"]="-- er lest inn",
+ ["ro"]="-- s-a incarcat",
+ },
+ ["20"]={
+ ["cs"]="vyznam (trideni) -- nacten",
+ ["de"]="Bedeutung (sortieren) von -- geladen",
+ ["en"]="meaning (sorts) of -- loaded",
+ ["fr"]="signification (tris) de -- chargée",
+ ["it"]="significato (specie) di -- caricato",
+ ["nl"]="betekenissen (sorteren) van -- geladen",
+ ["no"]="betydning (sorterer) av -- er lest inn",
+ ["ro"]="intelesul (ordinea) pentru -- incarcat",
+ },
+ ["21"]={
+ ["cs"]="pomocny soubor necten",
+ ["de"]="Die Hilfsdatei ist nicht geladen",
+ ["en"]="no utility data is loaded",
+ ["fr"]="pas de données utilitaires chargées",
+ ["it"]="nessuna informazione supplementare caricata",
+ ["nl"]="de hulpfile is niet geladen",
+ ["no"]="hjelpefila er ikke lest inn",
+ ["ro"]="nici o data utilitara nu este incarcata",
+ },
+ ["22"]={
+ ["cs"]="pouzijte platny pomocny soubor",
+ ["de"]="Benoetige gueltige Hilfsdateie",
+ ["en"]="use a valid utilityfile",
+ ["fr"]="utilise un fichier utilitaire valide",
+ ["it"]="usare un file supplementare valido",
+ ["nl"]="gebruik een goede hulpfile",
+ ["no"]="bruk en gyldig hjelpefil",
+ ["ro"]="folositi un fisier utilitar valid",
+ },
+ ["23"]={
+ ["cs"]="-- upraveno na --",
+ ["de"]="-- angeordnet auf --",
+ ["en"]="-- arranged at --",
+ ["fr"]="-- arrangé à --",
+ ["it"]="-- sistemato a --",
+ ["nl"]="-- gearrangeerd op --",
+ ["no"]="-- arrangert på --",
+ ["ro"]="-- aranjat la --",
+ },
+ ["24"]={
+ ["cs"]="plovouci bloky",
+ ["de"]="Fliessbloecke",
+ ["en"]="Floatblocks",
+ ["fr"]="blocsflottants",
+ ["it"]="Oggetti mobili",
+ ["nl"]="Plaatsblokken",
+ ["no"]="Flytblokker",
+ ["ro"]="Blocuri",
+ },
+ ["25"]={
+ ["cs"]="reference",
+ ["de"]="Referenzen",
+ ["en"]="References",
+ ["fr"]="Réferences",
+ ["it"]="Riferimenti",
+ ["nl"]="Verwijzingen",
+ ["no"]="Referanser",
+ ["ro"]="Referinte",
+ },
+ ["26"]={
+ ["cs"]="registry",
+ ["de"]="Register",
+ ["en"]="Registers",
+ ["fr"]="Registres",
+ ["it"]="Registri",
+ ["nl"]="Registers",
+ ["no"]="Registere",
+ ["ro"]="Registri",
+ },
+ ["27"]={
+ ["cs"]="verze",
+ ["de"]="Version",
+ ["en"]="Version",
+ ["fr"]="Version",
+ ["it"]="Versione",
+ ["nl"]="Versie",
+ ["no"]="Versjon",
+ ["ro"]="Versiune",
+ },
+ ["4"]={
+ ["cs"]="prikaz -- je jiz definovan",
+ ["de"]="Befehl -- ist bereits definiert",
+ ["en"]="command -- is already defined",
+ ["fr"]="la commande -- est déjà définie",
+ ["it"]="comando -- già definito",
+ ["nl"]="commando -- is al gedefinieerd",
+ ["no"]="kommando -- er allerede definert",
+ ["ro"]="comanda -- este deja definita",
+ },
+ ["41"]={
+ ["cs"]="externi soubor -- ve skupine -- neexistuje",
+ ["de"]="Externe Datei -- in Gruppe -- existiert nicht",
+ ["en"]="external file -- in group -- does not exist",
+ ["fr"]="le fichier externe -- du groupe -- n'existe pas",
+ ["it"]="il file esterno -- del gruppo -- non esiste",
+ ["nl"]="externe file -- in groep -- bestaat niet",
+ ["no"]="ekstern fil -- i gruppe -- eksisterer ikke",
+ ["ro"]="fisierul extern -- din grupul -- nu exista",
+ },
+ ["5"]={
+ ["cs"]="makra z -- nactena",
+ ["de"]="Modul -- geladen",
+ ["en"]="module -- loaded",
+ ["fr"]="module -- chargé",
+ ["it"]="macro del modulo -- caricate",
+ ["nl"]="module -- geladen",
+ ["no"]="makroene i modul -- er lest inn",
+ ["ro"]="macro-urile din modulul -- s-au incarcat",
+ },
+ ["6"]={
+ ["cs"]="zadna makra v -- nenalezena",
+ ["de"]="Modul -- gefunden",
+ ["en"]="module -- not found",
+ ["fr"]="module -- non trouvé",
+ ["it"]="nessuna macro trovata nel modulo --",
+ ["nl"]="geen module -- gevonden",
+ ["no"]="ingen makroer funnet i modul ---",
+ ["ro"]="nu s-au gasit macro-uri in modulul --",
+ },
+ ["7"]={
+ ["cs"]="makra z -- jsou jiz nactena",
+ ["de"]="Modul -- bereits geladen",
+ ["en"]="module -- already loaded",
+ ["fr"]="module -- déjà chargé",
+ ["it"]="macro del modulo -- già caricate",
+ ["nl"]="module -- reeds geladen",
+ ["no"]="makroene i modul -- er allerede lest inn",
+ ["ro"]="macro-urile din modulul -- s-au incarcat deja",
+ },
+ ["8"]={
+ ["cs"]="nova verze pomocneho souboru, je treba druheho behu",
+ ["de"]="Neue Version der Hilfsdatei, zweiter Durchlauf benoetigt",
+ ["en"]="new version of utility file, second pass needed",
+ ["fr"]="nouvelle version de fichier utilitaire, seconde passe nécessaire",
+ ["it"]="nuova versione del file supplementare, seconda passata necessaria",
+ ["nl"]="nieuwe versie hulpfile, tweede run nodig",
+ ["no"]="ny versjon av hjelpefil, andre gjennomkjøring nødvendig",
+ ["ro"]="o noua versiune de fisier utilitar, este necesara o noua trecere",
+ },
+ ["9"]={
+ ["cs"]="-- nenalezeno/nezpracovano",
+ ["de"]="-- nicht gefunden/verarbeitet",
+ ["en"]="-- not found/processed",
+ ["fr"]="-- non trouvé/traité",
+ ["it"]="-- non trovato/elaborato",
+ ["nl"]="-- niet gevonden/geplaatst",
+ ["no"]="-- ikke funnet/behandlet",
+ ["ro"]="-- nu este gasit/procesat",
+ },
+ ["91"]={
+ ["en"]="papertray --",
+ ["nl"]="papierlade --",
+ },
+ ["files"]={ "core-mis.tex", "page-ini.tex", "prag-gen.tex", "strc-mar.tex" },
+ ["title"]={
+ ["cs"]="system",
+ ["de"]="system",
+ ["en"]="system",
+ ["fr"]="système",
+ ["it"]="sistema",
+ ["nl"]="systeem",
+ ["no"]="system",
+ ["ro"]="sistem",
+ },
+ },
+ ["textblocks"]={
+ ["1"]={
+ ["cs"]="nova verze, je treba druhy beh",
+ ["de"]="neue Version, zweiter Durchlauf benoetigt",
+ ["en"]="new version, second pass needed",
+ ["fr"]="nouvelle version, une seconde passe est nécessaire",
+ ["it"]="nuova versione, seconda passata necessaria",
+ ["nl"]="nieuwe versie, tweede run nodig",
+ ["no"]="ny versjon, andre gjennomkjøring nødvendig",
+ ["ro"]="o noua versiune, este nevoie de inca o trecere",
+ },
+ ["10"]={
+ ["cs"]="-- nacteno a zpracovano",
+ ["de"]="-- geladen und verarbeitet",
+ ["en"]="-- loaded and processed",
+ ["fr"]="-- chargé et traité",
+ ["it"]="-- caricato ed elaborato",
+ ["nl"]="-- geladen en verwerkt",
+ ["no"]="-- lest inn og behandlet",
+ ["ro"]="-- incarcat si procesat",
+ },
+ ["11"]={
+ ["cs"]="-- nacteno a vysazeno",
+ ["de"]="-- geladen und gesetzt",
+ ["en"]="-- loaded and typeset",
+ ["fr"]="-- chargé et composé",
+ ["it"]="-- caricato e composto",
+ ["nl"]="-- geladen en geplaatst",
+ ["no"]="-- lest inn og tegnsatt",
+ ["ro"]="-- incarcat si cules",
+ },
+ ["12"]={
+ ["cs"]="-- preskoceno",
+ ["de"]="-- ausgelassen",
+ ["en"]="-- skipped",
+ ["fr"]="-- sauté",
+ ["it"]="-- saltato",
+ ["nl"]="-- overgeslagen",
+ ["no"]="-- utelatt",
+ ["ro"]="-- sarit peste",
+ },
+ ["2"]={
+ ["cs"]="zapisuji bloky do --",
+ ["de"]="schreibe Bloecke zu --",
+ ["en"]="writing blocks to --",
+ ["fr"]="ecriture des blocs vers --",
+ ["it"]="scrittura dei blocchi su --",
+ ["nl"]="wegschrijven blokken naar --",
+ ["no"]="skriver blokker til --",
+ ["ro"]="se scriu blocurile in --",
+ },
+ ["3"]={
+ ["cs"]="ctu bloky z --",
+ ["de"]="lese Bloecke von --",
+ ["en"]="reading blocks from --",
+ ["fr"]="lecture des blocs en provenance de --",
+ ["it"]="lettura dei blocchi da --",
+ ["nl"]="inlezen blokken uit --",
+ ["no"]="leser blokker fra --",
+ ["ro"]="se citesc blocurile din --",
+ },
+ ["4"]={
+ ["cs"]="je treba druhy beh",
+ ["de"]="zweiter Durchlauf benoetigt",
+ ["en"]="second pass needed",
+ ["fr"]="seconde passe nécessaire",
+ ["it"]="seconda passata necessaria",
+ ["nl"]="er is een tweede run nodig",
+ ["no"]="andre gjennomkjøring nødvendig",
+ ["ro"]="este nevoie de inca o trecere",
+ },
+ ["5"]={
+ ["cs"]="-- neni skryto",
+ ["de"]="-- nicht verborgen",
+ ["en"]="-- not hidden",
+ ["fr"]="-- non caché",
+ ["it"]="-- non nascosto",
+ ["nl"]="-- niet verborgen",
+ ["no"]="-- ikke skjult",
+ ["ro"]="-- nu este ascuns",
+ },
+ ["6"]={
+ ["cs"]="-- skryto a zpracovano",
+ ["de"]="-- verborgen und verarbeitet",
+ ["en"]="-- hidden and processed",
+ ["fr"]="-- caché et traité",
+ ["it"]="-- nascosto ed elaborato",
+ ["nl"]="-- verborgen en verwerkt",
+ ["no"]="-- skjult og behandlet",
+ ["ro"]="-- ascuns si procesat",
+ },
+ ["7"]={
+ ["cs"]="-- skryto",
+ ["de"]="-- verborgen",
+ ["en"]="-- hidden",
+ ["fr"]="-- caché",
+ ["it"]="-- nascosto",
+ ["nl"]="-- verborgen",
+ ["no"]="-- skjult",
+ ["ro"]="-- ascuns",
+ },
+ ["8"]={
+ ["cs"]="-- vysazeno",
+ ["de"]="-- gesetzt",
+ ["en"]="-- typeset",
+ ["fr"]="-- composé",
+ ["it"]="-- composto",
+ ["nl"]="-- gehandhaafd",
+ ["no"]="-- tegnsatt",
+ ["ro"]="-- cules",
+ },
+ ["9"]={
+ ["cs"]="-- nevysazeno",
+ ["de"]="-- nicht gesetzt",
+ ["en"]="-- not typeset",
+ ["fr"]="-- non composé",
+ ["it"]="-- non composto",
+ ["nl"]="-- niet gehandhaafd",
+ ["no"]="-- ikke tegnsatt",
+ ["ro"]="-- nu este cules",
+ },
+ ["files"]={ "core-blk.tex" },
+ ["title"]={
+ ["cs"]="textovyblok",
+ ["de"]="textblock",
+ ["en"]="textblocks",
+ ["fr"]="blocs de texte",
+ ["it"]="blocchi di testo",
+ ["nl"]="tekstblokken",
+ ["no"]="tekstblokker",
+ ["ro"]="blocuri de text",
+ },
+ },
+ ["verbatims"]={
+ ["1"]={
+ ["cs"]="soubor -- neexistuje",
+ ["de"]="Datei -- existiert nicht",
+ ["en"]="file -- does not exist",
+ ["fr"]="le fichier -- n'existe pas",
+ ["it"]="il file -- non esiste",
+ ["nl"]="file -- bestaat niet",
+ ["no"]="fil -- eksisterer ikke",
+ ["ro"]="fisierul -- nu exista",
+ },
+ ["files"]={ "core-ver.tex" },
+ ["title"]={
+ ["cs"]="verbatim",
+ ["de"]="verbatim",
+ ["en"]="verbatim",
+ ["fr"]="verbatim",
+ ["it"]="verbatim",
+ ["nl"]="typen",
+ ["no"]="verbatim",
+ ["ro"]="verbatim",
+ },
+ },
+ ["versions"]={
+ ["1"]={
+ ["cs"]="postradam @+",
+ ["de"]="fehlendes @+",
+ ["en"]="missing @+",
+ ["fr"]="@+ manquant",
+ ["it"]="@+ mancante",
+ ["nl"]="er mankeert een @+",
+ ["no"]="manglende @+",
+ ["ro"]="lipseste @+",
+ },
+ ["2"]={
+ ["cs"]="oznacuji se strany",
+ ["de"]="Erstelle Seiten",
+ ["en"]="marking pages",
+ ["fr"]="marquage des pages",
+ ["it"]="marcatura pagine",
+ ["nl"]="markeren pagina's",
+ ["no"]="markerer sider",
+ ["ro"]="pagini marcate",
+ },
+ ["3"]={
+ ["cs"]="oznacene strany: --",
+ ["de"]="Ausgewaehlte Seiten: --",
+ ["en"]="selected pages: --",
+ ["fr"]="pages sélectionnées : --",
+ ["it"]="pagine selezionate: --",
+ ["nl"]="geselecteerde pagina's: --",
+ ["no"]="valgte sider: --",
+ ["ro"]="pagini selectate: --",
+ },
+ ["files"]={ "core-int.tex" },
+ ["title"]={
+ ["cs"]="verze",
+ ["de"]="Version",
+ ["en"]="version",
+ ["fr"]="version",
+ ["it"]="version",
+ ["nl"]="versie",
+ ["no"]="versjon",
+ ["ro"]="versiuni",
+ },
+ },
+} \ No newline at end of file
diff --git a/tex/context/base/mult-mfr.tex b/tex/context/base/mult-mfr.tex
new file mode 100644
index 000000000..ecfd88ecc
--- /dev/null
+++ b/tex/context/base/mult-mfr.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{réference -- inconnue}
+\setinterfacemessage{references}{3}{type -- de réference inconnu}
+\setinterfacemessage{references}{2}{réference -- dupliquée à la page --}
+\setinterfacemessage{references}{4}{réference -- inconnue}
+\setinterfacemessage{references}{title}{réferences}
+\setinterfacemessage{references}{30}{objet -- inconnu}
+\setinterfacemessage{references}{31}{objet -- dupliqué}
+\setinterfacemessage{references}{21}{document -- chargé}
+\setinterfacemessage{references}{22}{le document -- n'est pas interactif}
+\setinterfacemessage{references}{23}{reference -- indéterminé (préfixe=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{manipulation -- de police}
+\setinterfacemessage{handlings}{3}{manipulation -- inconnue de police}
+\setinterfacemessage{handlings}{2}{la manipulation -- de police est chargée}
+\setinterfacemessage{handlings}{title}{manipulation}
+\setinterfacemessage{systems}{title}{système}
+\setinterfacemessage{systems}{41}{le fichier externe -- du groupe -- n'existe pas}
+\setinterfacemessage{systems}{9}{-- non trouvé/traité}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{nouvelle version de fichier utilitaire, seconde passe nécessaire}
+\setinterfacemessage{systems}{21}{pas de données utilitaires chargées}
+\setinterfacemessage{systems}{20}{signification (tris) de -- chargée}
+\setinterfacemessage{systems}{5}{module -- chargé}
+\setinterfacemessage{systems}{4}{la commande -- est déjà définie}
+\setinterfacemessage{systems}{27}{Version}
+\setinterfacemessage{systems}{26}{Registres}
+\setinterfacemessage{systems}{25}{Réferences}
+\setinterfacemessage{systems}{24}{blocsflottants}
+\setinterfacemessage{systems}{1}{chargement de fichier utilitaire reporté (typemode)}
+\setinterfacemessage{systems}{23}{-- arrangé à --}
+\setinterfacemessage{systems}{22}{utilise un fichier utilitaire valide}
+\setinterfacemessage{systems}{2}{-- chargé}
+\setinterfacemessage{systems}{19}{signification (synonymes) de -- chargée}
+\setinterfacemessage{systems}{18}{le synonyme -- -- n'existe pas}
+\setinterfacemessage{systems}{7}{module -- déjà chargé}
+\setinterfacemessage{systems}{6}{module -- non trouvé}
+\setinterfacemessage{systems}{14}{nouvellepage forcée dans la liste à --}
+\setinterfacemessage{systems}{15}{sauvegarde du tampon (buffer) --}
+\setinterfacemessage{systems}{16}{composition du tampon (buffer) --}
+\setinterfacemessage{systems}{17}{composition textuelle du tampon (buffer) --}
+\setinterfacemessage{systems}{13}{marquage -- defini --}
+\setinterfacemessage{systems}{12}{le fichier utilitaire n'est pas trié, utilise texutil}
+\setinterfacemessage{systems}{11}{construction util simple}
+\setinterfacemessage{systems}{10}{n'utilisez pas em dans --}
+\setinterfacemessage{floatblocks}{1}{-- renuméroté / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- déplacé}
+\setinterfacemessage{floatblocks}{2}{-- sauvegardé}
+\setinterfacemessage{floatblocks}{5}{ordre adapté}
+\setinterfacemessage{floatblocks}{4}{-- placé}
+\setinterfacemessage{floatblocks}{7}{n flottants de bas de page limité à --}
+\setinterfacemessage{floatblocks}{6}{n flottants de haut de page limité à --}
+\setinterfacemessage{floatblocks}{9}{ordre perturbé}
+\setinterfacemessage{floatblocks}{8}{moins de -- lignes}
+\setinterfacemessage{floatblocks}{title}{blocs de flottants}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{indéfini}
+\setinterfacemessage{floatblocks}{11}{pas de bloc donné}
+\setinterfacemessage{floatblocks}{10}{-- limité}
+\setinterfacemessage{interactions}{1}{ratio d'aspect -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{inactif}
+\setinterfacemessage{interactions}{2}{actif}
+\setinterfacemessage{interactions}{5}{le fichier joint -- est inconnu}
+\setinterfacemessage{interactions}{4}{pas de synchronisation de page (--) dans le hmode}
+\setinterfacemessage{interactions}{6}{le fichier joint -- n'existe pas}
+\setinterfacemessage{interactions}{title}{interaction}
+\setinterfacemessage{interactions}{21}{-- code inseré}
+\setinterfacemessage{structures}{1}{début de blocsection --}
+\setinterfacemessage{structures}{title}{structure}
+\setinterfacemessage{structures}{2}{fin de blocsection --}
+\setinterfacemessage{linguals}{1}{les motifs -- pour -- sont chargés (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{hyphenations -- pour -- chargés (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{pas de motifs -- pour -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{les motifs pour -- ne sont pas chargés}
+\setinterfacemessage{linguals}{4}{pas d'hyphenations -- pour -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{les options spécifiques de langue [--] introduisent un -- saut}
+\setinterfacemessage{linguals}{6}{langue -- non définie}
+\setinterfacemessage{linguals}{9}{la langue -- est active}
+\setinterfacemessage{linguals}{8}{les options spécifiques de langue [--] sont ajoutés en douceur}
+\setinterfacemessage{linguals}{title}{langue}
+\setinterfacemessage{linguals}{10}{motifs -- chargés}
+\setinterfacemessage{regimes}{1}{encodage --}
+\setinterfacemessage{regimes}{3}{encodage -- inconnu}
+\setinterfacemessage{regimes}{2}{l'encodage -- est chargé}
+\setinterfacemessage{regimes}{title}{encodage}
+\setinterfacemessage{filters}{1}{le filtre -- est chargé}
+\setinterfacemessage{filters}{title}{filtre}
+\setinterfacemessage{filters}{2}{filtre -- inconnu}
+\setinterfacemessage{verbatims}{1}{le fichier -- n'existe pas}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{encodage --}
+\setinterfacemessage{encodings}{3}{encodage -- inconnu}
+\setinterfacemessage{encodings}{2}{l'encodage -- est chargé}
+\setinterfacemessage{encodings}{title}{encodage}
+\setinterfacemessage{columns}{1}{seules -- colonnes possibles}
+\setinterfacemessage{columns}{3}{problèmes, désactive l'équilibrage}
+\setinterfacemessage{columns}{2}{utilisez \string\filbreak\space en tant qu'alternative}
+\setinterfacemessage{columns}{5}{flottant en partie inférieure pas encore supporté}
+\setinterfacemessage{columns}{4}{flottant en partie supérieure pas encore supporté}
+\setinterfacemessage{columns}{7}{équilibrage abandonné après 100 pas}
+\setinterfacemessage{columns}{6}{-- flottant(s) reporté(s)}
+\setinterfacemessage{columns}{9}{vérification des irrégularités}
+\setinterfacemessage{columns}{8}{équilibré en -- pas}
+\setinterfacemessage{columns}{title}{colonnes}
+\setinterfacemessage{columns}{13}{flottant large déplacé dans la partie supérieure de la colonne}
+\setinterfacemessage{columns}{12}{flottant déplacé à la colonne suivante / --}
+\setinterfacemessage{columns}{11}{flottant mis à la largeur de la colonne}
+\setinterfacemessage{columns}{10}{(moins de) 1 ligne restante}
+\setinterfacemessage{textblocks}{1}{nouvelle version, une seconde passe est nécessaire}
+\setinterfacemessage{textblocks}{3}{lecture des blocs en provenance de --}
+\setinterfacemessage{textblocks}{2}{ecriture des blocs vers --}
+\setinterfacemessage{textblocks}{5}{-- non caché}
+\setinterfacemessage{textblocks}{4}{seconde passe nécessaire}
+\setinterfacemessage{textblocks}{7}{-- caché}
+\setinterfacemessage{textblocks}{6}{-- caché et traité}
+\setinterfacemessage{textblocks}{9}{-- non composé}
+\setinterfacemessage{textblocks}{8}{-- composé}
+\setinterfacemessage{textblocks}{title}{blocs de texte}
+\setinterfacemessage{textblocks}{12}{-- sauté}
+\setinterfacemessage{textblocks}{11}{-- chargé et composé}
+\setinterfacemessage{textblocks}{10}{-- chargé et traité}
+\setinterfacemessage{symbols}{1}{chargement du jeu de symbole --}
+\setinterfacemessage{symbols}{title}{symboles}
+\setinterfacemessage{versions}{1}{@+ manquant}
+\setinterfacemessage{versions}{3}{pages sélectionnées : --}
+\setinterfacemessage{versions}{2}{marquage des pages}
+\setinterfacemessage{versions}{title}{version}
+\setinterfacemessage{specials}{1}{-- chargé}
+\setinterfacemessage{specials}{3}{-- est remis à zéro}
+\setinterfacemessage{specials}{2}{pas d'imbracations plus profondes ne sont permises --}
+\setinterfacemessage{specials}{5}{chargement du fichier de définition --}
+\setinterfacemessage{specials}{4}{la commande -- n'existe pas}
+\setinterfacemessage{specials}{7}{pilote -- inconnu}
+\setinterfacemessage{specials}{6}{l'imbrication n'est pas permise}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{chargement du jeu de script --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{préambule -- inconnu}
+\setinterfacemessage{fonts}{1}{encodage --}
+\setinterfacemessage{fonts}{3}{variante -- inconnue}
+\setinterfacemessage{fonts}{2}{la variante -- est chargée}
+\setinterfacemessage{fonts}{5}{le style -- n'est pas défini}
+\setinterfacemessage{fonts}{4}{policecorps -- n'est pas définie}
+\setinterfacemessage{fonts}{7}{format -- inconnu}
+\setinterfacemessage{fonts}{6}{-- est chargé}
+\setinterfacemessage{fonts}{14}{policecorps -- est défini (une définition globale pourrait être plus adéquat)}
+\setinterfacemessage{fonts}{8}{style -- défini}
+\setinterfacemessage{fonts}{title}{corps de texte}
+\setinterfacemessage{fonts}{10}{fichier de police -- inconnu}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{fichier global --}
+\setinterfacemessage{databases}{2}{fichier local --}
+\setinterfacemessage{databases}{4}{fichier inconnu --}
+\setinterfacemessage{databases}{title}{bases de données}
+\setinterfacemessage{colors}{1}{le système -- est globalement activé}
+\setinterfacemessage{colors}{3}{-- n'est pas défini --}
+\setinterfacemessage{colors}{2}{le système -- est localement activé}
+\setinterfacemessage{colors}{5}{système -- inconnu}
+\setinterfacemessage{colors}{4}{le système -- est chargé}
+\setinterfacemessage{colors}{7}{le palette -- n'est pas disponible}
+\setinterfacemessage{colors}{6}{la palette -- est disponible}
+\setinterfacemessage{colors}{9}{l'espace de couleur -- n'est pas supporté}
+\setinterfacemessage{colors}{8}{la spécification -- de la couleur -- devient noire}
+\setinterfacemessage{colors}{title}{couleurs}
+\setinterfacemessage{colors}{12}{-- est enregistré}
+\setinterfacemessage{colors}{11}{la couleur est convertie en niveau de gris}
+\setinterfacemessage{colors}{10}{-- l'espace de couleur est supporté}
+\setinterfacemessage{layouts}{1}{hauteurtexte adaptée avec -- à la page --}
+\setinterfacemessage{layouts}{3}{-- times text postponed}
+\setinterfacemessage{layouts}{2}{-- times postponed text placed}
+\setinterfacemessage{layouts}{5}{blocsmarge inactifs}
+\setinterfacemessage{layouts}{4}{blocsmarge actifs}
+\setinterfacemessage{layouts}{7}{calcul de l'espace pour le logo}
+\setinterfacemessage{layouts}{6}{jeu de souspage -- traité (taille --)}
+\setinterfacemessage{layouts}{9}{pas plus de -- niveaux pour l'instant dans les élémentarisations}
+\setinterfacemessage{layouts}{8}{calcul des arrières-plans}
+\setinterfacemessage{layouts}{title}{calque}
+\setinterfacemessage{layouts}{11}{espacement -- non permis en modegrille}
+\setinterfacemessage{layouts}{10}{-- et -- ne sont pas ajoutés à 1.0}
+\setinterfacemessage{check}{1}{manquant ou dégroupé '=' après '--' à la ligne --}
+\setinterfacemessage{check}{3}{-- -- remplace une macro, utilisez des MAJUSCULES !}
+\setinterfacemessage{check}{2}{-- argument(s) attendu(s) à la ligne --}
+\setinterfacemessage{check}{title}{vérification}
+\setinterfacemessage{metapost}{1}{chargement de la bibliothèque metapost --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{le synonyme de fichier -- est déjà utilisé pour --}
+\setinterfacemessage{files}{title}{fichiers}
+\setinterfacemessage{figures}{1}{la figure -- ne peut être trouvée}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{la figure -- n'est pas pré-sélectionnée}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{les dimensions de -- chargées implicitement à partir du fichier de figure}
+\setinterfacemessage{figures}{6}{les dimensions de -- calculées par rlxtools}
+\setinterfacemessage{figures}{8}{figureobject -- est réutilisé}
+\setinterfacemessage{figures}{title}{figures}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mit.tex b/tex/context/base/mult-mit.tex
new file mode 100644
index 000000000..0efb03e90
--- /dev/null
+++ b/tex/context/base/mult-mit.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{riferimento sconosciuto --}
+\setinterfacemessage{references}{3}{riferimento di tipo sconosciuto --}
+\setinterfacemessage{references}{2}{riferimento duplicato -- a pagina --}
+\setinterfacemessage{references}{4}{riferimento illecito --}
+\setinterfacemessage{references}{title}{riferimenti}
+\setinterfacemessage{references}{30}{oggetto sconosciuto --}
+\setinterfacemessage{references}{31}{oggetto duplicato --}
+\setinterfacemessage{references}{21}{documento -- caricato}
+\setinterfacemessage{references}{22}{il documento -- non ø interattivo}
+\setinterfacemessage{references}{23}{riferimento ambiguo -- (prefisso=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{sistema}
+\setinterfacemessage{systems}{41}{il file esterno -- del gruppo -- non esiste}
+\setinterfacemessage{systems}{9}{-- non trovato/elaborato}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{nuova versione del file supplementare, seconda passata necessaria}
+\setinterfacemessage{systems}{21}{nessuna informazione supplementare caricata}
+\setinterfacemessage{systems}{20}{significato (specie) di -- caricato}
+\setinterfacemessage{systems}{5}{macro del modulo -- caricate}
+\setinterfacemessage{systems}{4}{comando -- già definito}
+\setinterfacemessage{systems}{27}{Versione}
+\setinterfacemessage{systems}{26}{Registri}
+\setinterfacemessage{systems}{25}{Riferimenti}
+\setinterfacemessage{systems}{24}{Oggetti mobili}
+\setinterfacemessage{systems}{1}{caricamento dei file supplementari posticipato (typemode)}
+\setinterfacemessage{systems}{23}{-- sistemato a --}
+\setinterfacemessage{systems}{22}{usare un file supplementare valido}
+\setinterfacemessage{systems}{2}{-- caricato}
+\setinterfacemessage{systems}{19}{significato (sinonimi) di -- caricato}
+\setinterfacemessage{systems}{18}{sinonimo -- -- non esistente}
+\setinterfacemessage{systems}{7}{macro del modulo -- già caricate}
+\setinterfacemessage{systems}{6}{nessuna macro trovata nel modulo --}
+\setinterfacemessage{systems}{14}{nuova pagina obbligata in lista a --}
+\setinterfacemessage{systems}{15}{salvataggio del buffer --}
+\setinterfacemessage{systems}{16}{composizione del buffer --}
+\setinterfacemessage{systems}{17}{composizione verbatim del buffer --}
+\setinterfacemessage{systems}{13}{marcatura -- definita --}
+\setinterfacemessage{systems}{12}{file di supplemento non ordinato, usare texutil}
+\setinterfacemessage{systems}{11}{costruzione di un semplice supplemento}
+\setinterfacemessage{systems}{10}{non usare em in --}
+\setinterfacemessage{floatblocks}{1}{-- rinumerato / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- mosso}
+\setinterfacemessage{floatblocks}{2}{-- salvato}
+\setinterfacemessage{floatblocks}{5}{ordine aggiustato}
+\setinterfacemessage{floatblocks}{4}{-- sistemato}
+\setinterfacemessage{floatblocks}{7}{n di bottom floats limitato a --}
+\setinterfacemessage{floatblocks}{6}{n di top floats limitato a --}
+\setinterfacemessage{floatblocks}{9}{ordine disturbato}
+\setinterfacemessage{floatblocks}{8}{meno di -- righe}
+\setinterfacemessage{floatblocks}{title}{oggetti mobili}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{non definito}
+\setinterfacemessage{floatblocks}{11}{nessun oggetto specificato}
+\setinterfacemessage{floatblocks}{10}{-- limitato}
+\setinterfacemessage{interactions}{1}{rapporto -- x -- (b x a)}
+\setinterfacemessage{interactions}{3}{inattiva}
+\setinterfacemessage{interactions}{2}{attiva}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{sincronizzazione di pagina (--) non disponibile in hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interazione}
+\setinterfacemessage{interactions}{21}{codice -- inserito}
+\setinterfacemessage{structures}{1}{inizio del blocco (sezione) --}
+\setinterfacemessage{structures}{title}{struttura}
+\setinterfacemessage{structures}{2}{fine del blocco (sezione) --}
+\setinterfacemessage{linguals}{1}{schemi -- per -- caricati (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{sillabazione -- per -- caricata (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{niente schemi -- per -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{schemi per -- non caricati}
+\setinterfacemessage{linguals}{4}{niente sillabazione -- per -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{opzioni specifiche per la lingua [--] introducono un salto --}
+\setinterfacemessage{linguals}{6}{lingua -- non definita}
+\setinterfacemessage{linguals}{9}{lingua -- attiva}
+\setinterfacemessage{linguals}{8}{opzioni specifiche per la lingua [--] aggiunte trasparentemente}
+\setinterfacemessage{linguals}{title}{lingua}
+\setinterfacemessage{linguals}{10}{schemi -- caricati}
+\setinterfacemessage{regimes}{1}{codifica --}
+\setinterfacemessage{regimes}{3}{codifica sconosciuta --}
+\setinterfacemessage{regimes}{2}{codifica -- caricata}
+\setinterfacemessage{regimes}{title}{codifica}
+\setinterfacemessage{filters}{1}{filtro -- caricato}
+\setinterfacemessage{filters}{title}{filtri}
+\setinterfacemessage{filters}{2}{filtro sconosciuto --}
+\setinterfacemessage{verbatims}{1}{il file -- non esiste}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{codifica --}
+\setinterfacemessage{encodings}{3}{codifica sconosciuta --}
+\setinterfacemessage{encodings}{2}{codifica -- caricata}
+\setinterfacemessage{encodings}{title}{codifica}
+\setinterfacemessage{columns}{1}{solo -- colonne possibili}
+\setinterfacemessage{columns}{3}{problemi, disabilitare il bilanciamento}
+\setinterfacemessage{columns}{2}{in alternativa, usare \string\filbreak}
+\setinterfacemessage{columns}{5}{float in fondo non ancora supportato}
+\setinterfacemessage{columns}{4}{float in cima non ancora supportato}
+\setinterfacemessage{columns}{7}{bilanciamento annullato dopo 100 passi}
+\setinterfacemessage{columns}{6}{-- float(s) posticipate}
+\setinterfacemessage{columns}{9}{controllare seghettamento}
+\setinterfacemessage{columns}{8}{bilanciamento in -- passo/i}
+\setinterfacemessage{columns}{title}{colonne}
+\setinterfacemessage{columns}{13}{oggetto mobile ampio spostato sopra le colonne}
+\setinterfacemessage{columns}{12}{oggetto mobile spostata alla colonna successiva / --}
+\setinterfacemessage{columns}{11}{oggetto mobile troppo ampio per la colonna}
+\setinterfacemessage{columns}{10}{(meno di) una riga rimasta}
+\setinterfacemessage{textblocks}{1}{nuova versione, seconda passata necessaria}
+\setinterfacemessage{textblocks}{3}{lettura dei blocchi da --}
+\setinterfacemessage{textblocks}{2}{scrittura dei blocchi su --}
+\setinterfacemessage{textblocks}{5}{-- non nascosto}
+\setinterfacemessage{textblocks}{4}{seconda passata necessaria}
+\setinterfacemessage{textblocks}{7}{-- nascosto}
+\setinterfacemessage{textblocks}{6}{-- nascosto ed elaborato}
+\setinterfacemessage{textblocks}{9}{-- non composto}
+\setinterfacemessage{textblocks}{8}{-- composto}
+\setinterfacemessage{textblocks}{title}{blocchi di testo}
+\setinterfacemessage{textblocks}{12}{-- saltato}
+\setinterfacemessage{textblocks}{11}{-- caricato e composto}
+\setinterfacemessage{textblocks}{10}{-- caricato ed elaborato}
+\setinterfacemessage{symbols}{1}{caricamento gruppo di simboli --}
+\setinterfacemessage{symbols}{title}{simboli}
+\setinterfacemessage{versions}{1}{@+ mancante}
+\setinterfacemessage{versions}{3}{pagine selezionate: --}
+\setinterfacemessage{versions}{2}{marcatura pagine}
+\setinterfacemessage{versions}{title}{version}
+\setinterfacemessage{specials}{1}{-- caricato}
+\setinterfacemessage{specials}{3}{-- reimpostato}
+\setinterfacemessage{specials}{2}{non ø permesso un annidamento maggiore --}
+\setinterfacemessage{specials}{5}{caricamento del file di definizione --}
+\setinterfacemessage{specials}{4}{il comando -- non esiste}
+\setinterfacemessage{specials}{7}{driver sconosciuto --}
+\setinterfacemessage{specials}{6}{annidamento non permesso}
+\setinterfacemessage{specials}{title}{specialitø}
+\setinterfacemessage{javascript}{1}{caricamento dello script set --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{preambolo sconosciuto --}
+\setinterfacemessage{fonts}{1}{codifica --}
+\setinterfacemessage{fonts}{3}{variante sconosciuta --}
+\setinterfacemessage{fonts}{2}{variante -- caricata}
+\setinterfacemessage{fonts}{5}{stile -- non definito}
+\setinterfacemessage{fonts}{4}{corpo del testo -- non definito}
+\setinterfacemessage{fonts}{7}{formato sconosciuto --}
+\setinterfacemessage{fonts}{6}{-- caricato}
+\setinterfacemessage{fonts}{14}{corpo del testo -- definito (sarebbe meglio globale)}
+\setinterfacemessage{fonts}{8}{stile -- definito}
+\setinterfacemessage{fonts}{title}{font del corpo}
+\setinterfacemessage{fonts}{10}{file di font sconosciuto --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{file globale --}
+\setinterfacemessage{databases}{2}{file locale --}
+\setinterfacemessage{databases}{4}{file sconosciuto --}
+\setinterfacemessage{databases}{title}{database}
+\setinterfacemessage{colors}{1}{sistema -- attivato globalmente}
+\setinterfacemessage{colors}{3}{-- non definito --}
+\setinterfacemessage{colors}{2}{sistema -- attivato localmente}
+\setinterfacemessage{colors}{5}{sistema -- sconosciuto}
+\setinterfacemessage{colors}{4}{sistema -- caricato}
+\setinterfacemessage{colors}{7}{tavolozza -- non disponibile}
+\setinterfacemessage{colors}{6}{tavolozza -- resa disponibile}
+\setinterfacemessage{colors}{9}{spazio dei colori -- non supportato}
+\setinterfacemessage{colors}{8}{specifica -- del colore -- convertita in nero}
+\setinterfacemessage{colors}{title}{colore}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{il colore ø convertito in grigio}
+\setinterfacemessage{colors}{10}{spazio dei colori -- supportato}
+\setinterfacemessage{layouts}{1}{altezza del testo adattata con -- a pagina --}
+\setinterfacemessage{layouts}{3}{testo posticipato -- volte}
+\setinterfacemessage{layouts}{2}{posizionato testo posticipato -- volte}
+\setinterfacemessage{layouts}{5}{blocchi in margine inattivi}
+\setinterfacemessage{layouts}{4}{blocchi in margine attivi}
+\setinterfacemessage{layouts}{7}{calcolo dello spazio per logo}
+\setinterfacemessage{layouts}{6}{gruppo di sottopagine -- elaborato (dimensione --)}
+\setinterfacemessage{layouts}{9}{attualmente non più di -- livelli di elencazione}
+\setinterfacemessage{layouts}{8}{calcolo dello sfondo}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{spaziatura -- non permessa in modo griglia}
+\setinterfacemessage{layouts}{10}{-- e -- non sommano a 1.0}
+\setinterfacemessage{check}{1}{'=' mancante o non raggruppato dopo '--' alla riga --}
+\setinterfacemessage{check}{3}{-- -- sostituisce una macro, usare le MAIUSCOLE!}
+\setinterfacemessage{check}{2}{-- argomento/i attesi alla riga --}
+\setinterfacemessage{check}{title}{controllo}
+\setinterfacemessage{metapost}{1}{caricamento della libreria metapost --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{sinonimo file -- già in uso per --}
+\setinterfacemessage{files}{title}{file}
+\setinterfacemessage{figures}{1}{figura -- non trovata}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{la figura -- non è preimpostata}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimensioni di -- caricate dal file di immagini stesso}
+\setinterfacemessage{figures}{6}{dimensioni di -- calcolate da rlxtools}
+\setinterfacemessage{figures}{8}{oggetto-figura -- riutilizzato}
+\setinterfacemessage{figures}{title}{figure}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mnl.tex b/tex/context/base/mult-mnl.tex
new file mode 100644
index 000000000..5c52f7aff
--- /dev/null
+++ b/tex/context/base/mult-mnl.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{onbekende verwijzing --}
+\setinterfacemessage{references}{3}{type verwijzing -- onbekend}
+\setinterfacemessage{references}{2}{dubbele verwijzing -- op pagina --}
+\setinterfacemessage{references}{4}{verboden verwijzing --}
+\setinterfacemessage{references}{title}{verwijzingen}
+\setinterfacemessage{references}{30}{onbekend object --}
+\setinterfacemessage{references}{31}{dubbel object --}
+\setinterfacemessage{references}{21}{document -- geladen}
+\setinterfacemessage{references}{22}{document -- is niet interactief}
+\setinterfacemessage{references}{23}{onduidelijke verwijzing -- (prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{nummer --}
+\setinterfacemessage{handlings}{1}{font afhandeling --}
+\setinterfacemessage{handlings}{3}{onbekende font afhandeling --}
+\setinterfacemessage{handlings}{2}{font afhandeling -- wordt geladen}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{systeem}
+\setinterfacemessage{systems}{41}{externe file -- in groep -- bestaat niet}
+\setinterfacemessage{systems}{9}{-- niet gevonden/geplaatst}
+\setinterfacemessage{systems}{91}{papierlade --}
+\setinterfacemessage{systems}{8}{nieuwe versie hulpfile, tweede run nodig}
+\setinterfacemessage{systems}{21}{de hulpfile is niet geladen}
+\setinterfacemessage{systems}{20}{betekenissen (sorteren) van -- geladen}
+\setinterfacemessage{systems}{5}{module -- geladen}
+\setinterfacemessage{systems}{4}{commando -- is al gedefinieerd}
+\setinterfacemessage{systems}{27}{Versie}
+\setinterfacemessage{systems}{26}{Registers}
+\setinterfacemessage{systems}{25}{Verwijzingen}
+\setinterfacemessage{systems}{24}{Plaatsblokken}
+\setinterfacemessage{systems}{1}{laden hulpfile uitgesteld (typemode)}
+\setinterfacemessage{systems}{23}{-- gearrangeerd op --}
+\setinterfacemessage{systems}{22}{gebruik een goede hulpfile}
+\setinterfacemessage{systems}{2}{-- geladen}
+\setinterfacemessage{systems}{19}{betekenissen (synoniemen) van -- geladen}
+\setinterfacemessage{systems}{18}{synoniem -- -- bestaat niet}
+\setinterfacemessage{systems}{7}{module -- reeds geladen}
+\setinterfacemessage{systems}{6}{geen module -- gevonden}
+\setinterfacemessage{systems}{14}{geforceerde paginaovergang in lijst voor --}
+\setinterfacemessage{systems}{15}{wegschrijven buffer --}
+\setinterfacemessage{systems}{16}{inlezen buffer --}
+\setinterfacemessage{systems}{17}{verbatim inlezen buffer --}
+\setinterfacemessage{systems}{13}{markering -- gedefinieerd --}
+\setinterfacemessage{systems}{12}{de hulpfile is niet gesorteerd, gebruik texutil}
+\setinterfacemessage{systems}{11}{aanmaken basale hulpfile}
+\setinterfacemessage{systems}{10}{gebruik geen em in --}
+\setinterfacemessage{floatblocks}{1}{-- hernummerd / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- verplaatst}
+\setinterfacemessage{floatblocks}{2}{-- bewaard}
+\setinterfacemessage{floatblocks}{5}{volgorde aangepast}
+\setinterfacemessage{floatblocks}{4}{-- geplaatst}
+\setinterfacemessage{floatblocks}{7}{maximaal -- onder}
+\setinterfacemessage{floatblocks}{6}{maximaal -- boven}
+\setinterfacemessage{floatblocks}{9}{volgorde verstoord}
+\setinterfacemessage{floatblocks}{8}{minder dan -- regels}
+\setinterfacemessage{floatblocks}{title}{plaatsblokken}
+\setinterfacemessage{floatblocks}{13}{er is niets te splitsen}
+\setinterfacemessage{floatblocks}{12}{niet gedefinieerd}
+\setinterfacemessage{floatblocks}{11}{geen blok opgegeven}
+\setinterfacemessage{floatblocks}{10}{-- begrensd}
+\setinterfacemessage{interactions}{1}{aspect ratio -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{niet actief}
+\setinterfacemessage{interactions}{2}{actief}
+\setinterfacemessage{interactions}{5}{onbekend attachment --}
+\setinterfacemessage{interactions}{4}{geen paginasynchronisatie (--) in hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- bestaat niet}
+\setinterfacemessage{interactions}{title}{interactie}
+\setinterfacemessage{interactions}{21}{-- code tussengevoegd}
+\setinterfacemessage{structures}{1}{begin van sectieblok --}
+\setinterfacemessage{structures}{title}{structuur}
+\setinterfacemessage{structures}{2}{eind van sectieblok --}
+\setinterfacemessage{linguals}{1}{afbreekpatronen -- voor -- geladen (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{afbreekdefinities -- voor -- geladen (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{geen afbreekpatronen -- voor -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{afbreekpatronen voor -- niet geladen}
+\setinterfacemessage{linguals}{4}{geen afbreekdefinities -- voor -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{taal specifieke opties [--] introduceren een skip van --}
+\setinterfacemessage{linguals}{6}{taal -- is niet gedefinieerd}
+\setinterfacemessage{linguals}{9}{taal -- is actief}
+\setinterfacemessage{linguals}{8}{taal specifieke opties [--] naadloos toegevoegd}
+\setinterfacemessage{linguals}{title}{taal}
+\setinterfacemessage{linguals}{10}{patronen --geladen}
+\setinterfacemessage{regimes}{1}{regime --}
+\setinterfacemessage{regimes}{3}{onbekend regime --}
+\setinterfacemessage{regimes}{2}{regime -- wordt geladen}
+\setinterfacemessage{regimes}{title}{regime}
+\setinterfacemessage{filters}{1}{filter -- wordt geladen}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{onbekend filter --}
+\setinterfacemessage{verbatims}{1}{file -- bestaat niet}
+\setinterfacemessage{verbatims}{title}{typen}
+\setinterfacemessage{encodings}{1}{codering --}
+\setinterfacemessage{encodings}{3}{onbekende codering --}
+\setinterfacemessage{encodings}{2}{codering -- wordt geladen}
+\setinterfacemessage{encodings}{title}{encoding}
+\setinterfacemessage{columns}{1}{maximaal -- kolommen}
+\setinterfacemessage{columns}{3}{probleempje, probeer [balanceren=nee]}
+\setinterfacemessage{columns}{2}{gebruik eventueel \string\filbreak}
+\setinterfacemessage{columns}{5}{plaatsblok onder nog niet mogelijk}
+\setinterfacemessage{columns}{4}{plaatsblok boven nog niet mogelijk}
+\setinterfacemessage{columns}{7}{balanceren afgebroken na 100 stappen}
+\setinterfacemessage{columns}{6}{-- plaatsblok(en) opgeschort}
+\setinterfacemessage{columns}{9}{uitlijnen controleren!}
+\setinterfacemessage{columns}{8}{gebalanceerd in -- stap(pen)}
+\setinterfacemessage{columns}{title}{kolommen}
+\setinterfacemessage{columns}{13}{breed figuur geplaatst boven kolommen}
+\setinterfacemessage{columns}{12}{plaatsblok verplaatst naar volgende kolom / --}
+\setinterfacemessage{columns}{11}{plaatsblok te breed voor kolom}
+\setinterfacemessage{columns}{10}{(minder dan) 1 regel over}
+\setinterfacemessage{textblocks}{1}{nieuwe versie, tweede run nodig}
+\setinterfacemessage{textblocks}{3}{inlezen blokken uit --}
+\setinterfacemessage{textblocks}{2}{wegschrijven blokken naar --}
+\setinterfacemessage{textblocks}{5}{-- niet verborgen}
+\setinterfacemessage{textblocks}{4}{er is een tweede run nodig}
+\setinterfacemessage{textblocks}{7}{-- verborgen}
+\setinterfacemessage{textblocks}{6}{-- verborgen en verwerkt}
+\setinterfacemessage{textblocks}{9}{-- niet gehandhaafd}
+\setinterfacemessage{textblocks}{8}{-- gehandhaafd}
+\setinterfacemessage{textblocks}{title}{tekstblokken}
+\setinterfacemessage{textblocks}{12}{-- overgeslagen}
+\setinterfacemessage{textblocks}{11}{-- geladen en geplaatst}
+\setinterfacemessage{textblocks}{10}{-- geladen en verwerkt}
+\setinterfacemessage{symbols}{1}{symboolset -- wordt geladen}
+\setinterfacemessage{symbols}{title}{symbolen}
+\setinterfacemessage{versions}{1}{er mankeert een @+}
+\setinterfacemessage{versions}{3}{geselecteerde pagina's: --}
+\setinterfacemessage{versions}{2}{markeren pagina's}
+\setinterfacemessage{versions}{title}{versie}
+\setinterfacemessage{specials}{1}{-- geladen}
+\setinterfacemessage{specials}{3}{-- gereset}
+\setinterfacemessage{specials}{2}{verdere nesting is niet toegestaan --}
+\setinterfacemessage{specials}{5}{definitiefile -- wordt geladen}
+\setinterfacemessage{specials}{4}{commando -- bestaat niet}
+\setinterfacemessage{specials}{7}{onbekende driver --}
+\setinterfacemessage{specials}{6}{nesting is niet toegestaan}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{script set -- wordt geladen}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{onbekende preamble --}
+\setinterfacemessage{fonts}{1}{codering --}
+\setinterfacemessage{fonts}{3}{onbekende variant --}
+\setinterfacemessage{fonts}{2}{variant -- wordt geladen}
+\setinterfacemessage{fonts}{5}{stijl -- is niet gedefinieerd}
+\setinterfacemessage{fonts}{4}{korps -- is niet gedefinieerd}
+\setinterfacemessage{fonts}{7}{onbekend formaat --}
+\setinterfacemessage{fonts}{6}{-- wordt geladen}
+\setinterfacemessage{fonts}{14}{korps -- is gedefinieerd (kan beter globaal plaatsvinden)}
+\setinterfacemessage{fonts}{8}{stijl -- gedefinieerd}
+\setinterfacemessage{fonts}{title}{korps}
+\setinterfacemessage{fonts}{10}{onbekende font file --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{globaal bestand --}
+\setinterfacemessage{databases}{2}{lokaal bestand --}
+\setinterfacemessage{databases}{4}{onbekend bestand --}
+\setinterfacemessage{databases}{title}{database}
+\setinterfacemessage{colors}{1}{systeem -- is globaal actief}
+\setinterfacemessage{colors}{3}{-- is niet gedefinieerd --}
+\setinterfacemessage{colors}{2}{systeem -- is lokaal actief}
+\setinterfacemessage{colors}{5}{onbekend systeem --}
+\setinterfacemessage{colors}{4}{systeem -- wordt geladen}
+\setinterfacemessage{colors}{7}{palet -- is niet beschikbaar}
+\setinterfacemessage{colors}{6}{palet -- is beschikbaar}
+\setinterfacemessage{colors}{9}{-- kleurruimte wordt niet ondersteund}
+\setinterfacemessage{colors}{8}{specificatie -- bij -- wordt zwart}
+\setinterfacemessage{colors}{title}{kleur}
+\setinterfacemessage{colors}{12}{-- is geregistreerd}
+\setinterfacemessage{colors}{11}{kleur wordt vertaald in grijs}
+\setinterfacemessage{colors}{10}{-- kleurruimte wordt ondersteund}
+\setinterfacemessage{layouts}{1}{teksthoogte aangepast met -- op pagina --}
+\setinterfacemessage{layouts}{3}{-- maal tekst plaatsen uitstellen}
+\setinterfacemessage{layouts}{2}{-- maal uitgestelde tekst tussengevoegd}
+\setinterfacemessage{layouts}{5}{margeblokken inactief}
+\setinterfacemessage{layouts}{4}{margeblokken actief}
+\setinterfacemessage{layouts}{7}{beeldmerken berekenen}
+\setinterfacemessage{layouts}{6}{subpagina reeks -- verwerkt (aantal --)}
+\setinterfacemessage{layouts}{9}{momenteel maximaal -- niveaus in opsommingen}
+\setinterfacemessage{layouts}{8}{achtergronden berekenen}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{interlinie -- niet toegestaan in gridmode}
+\setinterfacemessage{layouts}{10}{-- en -- tellen niet op tot 1.0}
+\setinterfacemessage{check}{1}{'=' ontbreekt of zonder {} na '--' in regel --}
+\setinterfacemessage{check}{3}{-- -- vervangt een macro, gebruik HOOFDLETTERS!}
+\setinterfacemessage{check}{2}{-- argument(en) verwacht in regel --}
+\setinterfacemessage{check}{title}{controle}
+\setinterfacemessage{metapost}{1}{metapost bibliotheek -- wordt geladen}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{file synoniem -- is al in gebruik voor --}
+\setinterfacemessage{files}{title}{files}
+\setinterfacemessage{figures}{1}{figuur -- is niet te vinden}
+\setinterfacemessage{figures}{3}{maten van -- worden extern vastgesteld}
+\setinterfacemessage{figures}{2}{figuur -- wordt niet preset}
+\setinterfacemessage{figures}{5}{maten van -- zijn onbekend}
+\setinterfacemessage{figures}{4}{maten van -- geladen uit figuurfile zelf}
+\setinterfacemessage{figures}{6}{maten van -- berekend door rlxtools}
+\setinterfacemessage{figures}{8}{figuurobject -- wordt opnieuw gebruikt}
+\setinterfacemessage{figures}{title}{figuren}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mno.tex b/tex/context/base/mult-mno.tex
new file mode 100644
index 000000000..676c2cb2c
--- /dev/null
+++ b/tex/context/base/mult-mno.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{ukjent referanse --}
+\setinterfacemessage{references}{3}{ukjent referansetype --}
+\setinterfacemessage{references}{2}{duplikat referanse -- pø side --}
+\setinterfacemessage{references}{4}{ulovlig referanse --}
+\setinterfacemessage{references}{title}{referanser}
+\setinterfacemessage{references}{30}{ukjent objekt --}
+\setinterfacemessage{references}{31}{duplikat objekt --}
+\setinterfacemessage{references}{21}{dokument -- er lest inn}
+\setinterfacemessage{references}{22}{dokument -- er ikke interaktivt}
+\setinterfacemessage{references}{23}{obskur referanse -- (Prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{system}
+\setinterfacemessage{systems}{41}{ekstern fil -- i gruppe -- eksisterer ikke}
+\setinterfacemessage{systems}{9}{-- ikke funnet/behandlet}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{ny versjon av hjelpefil, andre gjennomkjøring nødvendig}
+\setinterfacemessage{systems}{21}{hjelpefila er ikke lest inn}
+\setinterfacemessage{systems}{20}{betydning (sorterer) av -- er lest inn}
+\setinterfacemessage{systems}{5}{makroene i modul -- er lest inn}
+\setinterfacemessage{systems}{4}{kommando -- er allerede definert}
+\setinterfacemessage{systems}{27}{Versjon}
+\setinterfacemessage{systems}{26}{Registere}
+\setinterfacemessage{systems}{25}{Referanser}
+\setinterfacemessage{systems}{24}{Flytblokker}
+\setinterfacemessage{systems}{1}{innlesning av hjelpefila utsatt (typemode)}
+\setinterfacemessage{systems}{23}{-- arrangert på --}
+\setinterfacemessage{systems}{22}{bruk en gyldig hjelpefil}
+\setinterfacemessage{systems}{2}{-- er lest inn}
+\setinterfacemessage{systems}{19}{betydning (synonymer) av -- er lest inn}
+\setinterfacemessage{systems}{18}{synonym -- -- eksisterer ikke}
+\setinterfacemessage{systems}{7}{makroene i modul -- er allerede lest inn}
+\setinterfacemessage{systems}{6}{ingen makroer funnet i modul ---}
+\setinterfacemessage{systems}{14}{tvunget sideskift i liste ved --}
+\setinterfacemessage{systems}{15}{lagrer Buffer --}
+\setinterfacemessage{systems}{16}{tegnsetter buffer --}
+\setinterfacemessage{systems}{17}{tegnsetter verbatim-buffer --}
+\setinterfacemessage{systems}{13}{markering -- definert --}
+\setinterfacemessage{systems}{12}{hjelpefila er ikke sortert, bruk texutil}
+\setinterfacemessage{systems}{11}{lager enkel hjelpefil}
+\setinterfacemessage{systems}{10}{ikke bruk em i --}
+\setinterfacemessage{floatblocks}{1}{-- renummerert / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- flyttet}
+\setinterfacemessage{floatblocks}{2}{-- lagret}
+\setinterfacemessage{floatblocks}{5}{rekkefølge tilpasset}
+\setinterfacemessage{floatblocks}{4}{-- plassert}
+\setinterfacemessage{floatblocks}{7}{maksimalt -- flytblokker nederst}
+\setinterfacemessage{floatblocks}{6}{maksimalt -- flytblokker øverst}
+\setinterfacemessage{floatblocks}{9}{rekkefølge endret}
+\setinterfacemessage{floatblocks}{8}{mindre enn -- linjer}
+\setinterfacemessage{floatblocks}{title}{flytblokker}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{udefinert}
+\setinterfacemessage{floatblocks}{11}{ingen blokk oppgitt}
+\setinterfacemessage{floatblocks}{10}{-- begrenset}
+\setinterfacemessage{interactions}{1}{forholdstall -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{inaktiv}
+\setinterfacemessage{interactions}{2}{aktiv}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{ingen sidesynkronisering (--) i hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interaksjon}
+\setinterfacemessage{interactions}{21}{-- kode satt inn / tilføyd}
+\setinterfacemessage{structures}{1}{starten av blokk -- (seksjon)}
+\setinterfacemessage{structures}{title}{struktur}
+\setinterfacemessage{structures}{2}{slutten av blokk -- (seksjon)}
+\setinterfacemessage{linguals}{1}{orddelingsmønster -- for -- er lest inn (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{orddelingsdefinisjon -- for -- er lest inn (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{ingen orddelingsmønster -- for -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{orddelingsmønster for -- er ikke lest inn}
+\setinterfacemessage{linguals}{4}{ingen orddelingsdefinisjon -- for -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{spràk spesifikk opsjon [--] introduserer et -- hopp}
+\setinterfacemessage{linguals}{6}{spràk -- er udefinert}
+\setinterfacemessage{linguals}{9}{spràk -- er aktivt}
+\setinterfacemessage{linguals}{8}{spràk spesifikk opsjon [--] problemfritt tilføyd}
+\setinterfacemessage{linguals}{title}{sprøk}
+\setinterfacemessage{linguals}{10}{orddelingsmønster -- er lest inn}
+\setinterfacemessage{regimes}{1}{koding --}
+\setinterfacemessage{regimes}{3}{ukjent koding --}
+\setinterfacemessage{regimes}{2}{koding -- er lest inn}
+\setinterfacemessage{regimes}{title}{koding}
+\setinterfacemessage{filters}{1}{filter -- is loaded}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{fil -- eksisterer ikke}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{koding --}
+\setinterfacemessage{encodings}{3}{ukjent koding --}
+\setinterfacemessage{encodings}{2}{koding -- er lest inn}
+\setinterfacemessage{encodings}{title}{koding}
+\setinterfacemessage{columns}{1}{maksimalt -- kolonner}
+\setinterfacemessage{columns}{3}{problemer, slår av balansering}
+\setinterfacemessage{columns}{2}{bruk \string\filbreak\space som et alternativ}
+\setinterfacemessage{columns}{5}{flytblokker nedert er ikke støttet enda}
+\setinterfacemessage{columns}{4}{flytblokker øverst er ikke støttet enda}
+\setinterfacemessage{columns}{7}{balansering avbrutt etter 100 iterasjoner}
+\setinterfacemessage{columns}{6}{-- flytblokk forskjøvet}
+\setinterfacemessage{columns}{9}{kontroller tekstlayout!}
+\setinterfacemessage{columns}{8}{balansert etter -- iterasjoner}
+\setinterfacemessage{columns}{title}{kolonner}
+\setinterfacemessage{columns}{13}{bred flytblokk forksjøvet til toppen av kolonnene}
+\setinterfacemessage{columns}{12}{flytblokk forskjøvet til neste kolonne / --}
+\setinterfacemessage{columns}{11}{flytblokk for bredt for kolonna}
+\setinterfacemessage{columns}{10}{(mindre enn) 1 linje igjen}
+\setinterfacemessage{textblocks}{1}{ny versjon, andre gjennomkjøring nødvendig}
+\setinterfacemessage{textblocks}{3}{leser blokker fra --}
+\setinterfacemessage{textblocks}{2}{skriver blokker til --}
+\setinterfacemessage{textblocks}{5}{-- ikke skjult}
+\setinterfacemessage{textblocks}{4}{andre gjennomkjøring nødvendig}
+\setinterfacemessage{textblocks}{7}{-- skjult}
+\setinterfacemessage{textblocks}{6}{-- skjult og behandlet}
+\setinterfacemessage{textblocks}{9}{-- ikke tegnsatt}
+\setinterfacemessage{textblocks}{8}{-- tegnsatt}
+\setinterfacemessage{textblocks}{title}{tekstblokker}
+\setinterfacemessage{textblocks}{12}{-- utelatt}
+\setinterfacemessage{textblocks}{11}{-- lest inn og tegnsatt}
+\setinterfacemessage{textblocks}{10}{-- lest inn og behandlet}
+\setinterfacemessage{symbols}{1}{leser inn symbolsett --}
+\setinterfacemessage{symbols}{title}{symboler}
+\setinterfacemessage{versions}{1}{manglende @+}
+\setinterfacemessage{versions}{3}{valgte sider: --}
+\setinterfacemessage{versions}{2}{markerer sider}
+\setinterfacemessage{versions}{title}{versjon}
+\setinterfacemessage{specials}{1}{-- er lest inn}
+\setinterfacemessage{specials}{3}{-- er tilbakestilt}
+\setinterfacemessage{specials}{2}{dypere 'nesting' er ikke tillatt --}
+\setinterfacemessage{specials}{5}{leser inn definisjonsfil for --}
+\setinterfacemessage{specials}{4}{kommando -- eksisterer ikke}
+\setinterfacemessage{specials}{7}{ukjent driver --}
+\setinterfacemessage{specials}{6}{'nesting' er ikke tillatt}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{leser inn scriptsett --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{ukjent 'preamble' --}
+\setinterfacemessage{fonts}{1}{koding --}
+\setinterfacemessage{fonts}{3}{ukjent variant --}
+\setinterfacemessage{fonts}{2}{variant -- er lest inn}
+\setinterfacemessage{fonts}{5}{stil -- er ikke definert}
+\setinterfacemessage{fonts}{4}{hovedfont -- er ikke definert}
+\setinterfacemessage{fonts}{7}{ukjent format --}
+\setinterfacemessage{fonts}{6}{-- er lest inn}
+\setinterfacemessage{fonts}{14}{bodyfont -- is defined (can better be done global)}
+\setinterfacemessage{fonts}{8}{stil -- definert}
+\setinterfacemessage{fonts}{title}{hovedfont}
+\setinterfacemessage{fonts}{10}{ukjent fontfil --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{global fil --}
+\setinterfacemessage{databases}{2}{lokal fil --}
+\setinterfacemessage{databases}{4}{ukjent fil --}
+\setinterfacemessage{databases}{title}{databaser}
+\setinterfacemessage{colors}{1}{system -- er aktivert globalt}
+\setinterfacemessage{colors}{3}{-- er udefinert --}
+\setinterfacemessage{colors}{2}{system -- er aktivert lokalt}
+\setinterfacemessage{colors}{5}{ukjent system --}
+\setinterfacemessage{colors}{4}{system -- er lest inn}
+\setinterfacemessage{colors}{7}{palett -- er ikke tilgjengelig}
+\setinterfacemessage{colors}{6}{palett -- er tilgjengelig}
+\setinterfacemessage{colors}{9}{-- fargerom er ikke støttet}
+\setinterfacemessage{colors}{8}{spesifikasjon -- for farge -- gir kun svart}
+\setinterfacemessage{colors}{title}{farge}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{fargen vil bli vist som grø}
+\setinterfacemessage{colors}{10}{-- fargerom er støttet}
+\setinterfacemessage{layouts}{1}{teksthøyde tilpasset med -- på side --}
+\setinterfacemessage{layouts}{3}{-- ganger tekst forskjøvet}
+\setinterfacemessage{layouts}{2}{-- ganger forskjøvet tekst plassert}
+\setinterfacemessage{layouts}{5}{margblokker inaktive}
+\setinterfacemessage{layouts}{4}{margblokker aktive}
+\setinterfacemessage{layouts}{7}{beregner plass for logo}
+\setinterfacemessage{layouts}{6}{delside sett -- behandlet (størrelse --)}
+\setinterfacemessage{layouts}{9}{for øyeblikket maksimalt -- nivåer i opplisting}
+\setinterfacemessage{layouts}{8}{beregner bakgrunn}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{mellomrom -- ikke tillatt i gridmodus}
+\setinterfacemessage{layouts}{10}{-- og -- er ikke 1.0 til sammen}
+\setinterfacemessage{check}{1}{manglende '=' etter '--' i linje --}
+\setinterfacemessage{check}{3}{-- -- overskygger en makro, bruk STORE BOKSTAVER!}
+\setinterfacemessage{check}{2}{-- argument forventet i linje --}
+\setinterfacemessage{check}{title}{kontroll}
+\setinterfacemessage{metapost}{1}{metapost bibliotek -- blir lest inn}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{filesynonym -- er allerede brukt for --}
+\setinterfacemessage{files}{title}{filer}
+\setinterfacemessage{figures}{1}{figure -- can not be found}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{figure -- is not preset}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimensions of -- loaded from figurefile itself}
+\setinterfacemessage{figures}{6}{dimensions of -- calculated by rlxtools}
+\setinterfacemessage{figures}{8}{figureobject -- is reused}
+\setinterfacemessage{figures}{title}{figures}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mpe.tex b/tex/context/base/mult-mpe.tex
new file mode 100644
index 000000000..8335d2911
--- /dev/null
+++ b/tex/context/base/mult-mpe.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{unknown reference --}
+\setinterfacemessage{references}{3}{unknown reference type --}
+\setinterfacemessage{references}{2}{duplicate reference -- on page --}
+\setinterfacemessage{references}{4}{illegal reference --}
+\setinterfacemessage{references}{title}{references}
+\setinterfacemessage{references}{30}{unknown object --}
+\setinterfacemessage{references}{31}{duplicate object --}
+\setinterfacemessage{references}{21}{document -- loaded}
+\setinterfacemessage{references}{22}{document -- is not interactive}
+\setinterfacemessage{references}{23}{obscure reference -- (prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{system}
+\setinterfacemessage{systems}{41}{external file -- in group -- does not exist}
+\setinterfacemessage{systems}{9}{-- not found/processed}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{new version of utility file, second pass needed}
+\setinterfacemessage{systems}{21}{no utility data is loaded}
+\setinterfacemessage{systems}{20}{meaning (sorts) of -- loaded}
+\setinterfacemessage{systems}{5}{module -- loaded}
+\setinterfacemessage{systems}{4}{command -- is already defined}
+\setinterfacemessage{systems}{27}{Version}
+\setinterfacemessage{systems}{26}{Registers}
+\setinterfacemessage{systems}{25}{References}
+\setinterfacemessage{systems}{24}{Floatblocks}
+\setinterfacemessage{systems}{1}{loading utility-file postponed (typemode)}
+\setinterfacemessage{systems}{23}{-- arranged at --}
+\setinterfacemessage{systems}{22}{use a valid utilityfile}
+\setinterfacemessage{systems}{2}{-- loaded}
+\setinterfacemessage{systems}{19}{meaning (synonyms) of -- loaded}
+\setinterfacemessage{systems}{18}{synonym -- -- does not exist}
+\setinterfacemessage{systems}{7}{module -- already loaded}
+\setinterfacemessage{systems}{6}{module -- not found}
+\setinterfacemessage{systems}{14}{forced newpage in list at --}
+\setinterfacemessage{systems}{15}{saving buffer --}
+\setinterfacemessage{systems}{16}{typesetting buffer --}
+\setinterfacemessage{systems}{17}{typesetting verbatim buffer --}
+\setinterfacemessage{systems}{13}{mark -- defined --}
+\setinterfacemessage{systems}{12}{the utility-file is not sorted, use texutil}
+\setinterfacemessage{systems}{11}{building simple util}
+\setinterfacemessage{systems}{10}{don't use em in --}
+\setinterfacemessage{floatblocks}{1}{-- renumbered / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- moved}
+\setinterfacemessage{floatblocks}{2}{-- saved}
+\setinterfacemessage{floatblocks}{5}{order adapted}
+\setinterfacemessage{floatblocks}{4}{-- placed}
+\setinterfacemessage{floatblocks}{7}{n of bottom floats limited to --}
+\setinterfacemessage{floatblocks}{6}{n of top floats limited to --}
+\setinterfacemessage{floatblocks}{9}{order disturbed}
+\setinterfacemessage{floatblocks}{8}{less than -- lines}
+\setinterfacemessage{floatblocks}{title}{floatblocks}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{undefined}
+\setinterfacemessage{floatblocks}{11}{no block given}
+\setinterfacemessage{floatblocks}{10}{-- limited}
+\setinterfacemessage{interactions}{1}{aspect ratio -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{inactive}
+\setinterfacemessage{interactions}{2}{active}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{no pagesynchronisation (--) in hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interaction}
+\setinterfacemessage{interactions}{21}{-- code inserted}
+\setinterfacemessage{structures}{1}{begin of sectionblock --}
+\setinterfacemessage{structures}{title}{structure}
+\setinterfacemessage{structures}{2}{end of sectionblock --}
+\setinterfacemessage{linguals}{1}{patterns -- for -- loaded (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{hyphenations -- for -- loaded (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{no patterns -- for -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{patterns for -- not loaded}
+\setinterfacemessage{linguals}{4}{no hyphenations -- for -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{language specific options [--] introduce a -- skip}
+\setinterfacemessage{linguals}{6}{language -- is undefined}
+\setinterfacemessage{linguals}{9}{language -- is active}
+\setinterfacemessage{linguals}{8}{language specific options [--] seamless appended}
+\setinterfacemessage{linguals}{title}{language}
+\setinterfacemessage{linguals}{10}{patterns --loaded}
+\setinterfacemessage{regimes}{1}{regime --}
+\setinterfacemessage{regimes}{3}{unknown regime --}
+\setinterfacemessage{regimes}{2}{regime -- is loaded}
+\setinterfacemessage{regimes}{title}{regime}
+\setinterfacemessage{filters}{1}{filter -- is loaded}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{file -- does not exist}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{coding --}
+\setinterfacemessage{encodings}{3}{unknown coding --}
+\setinterfacemessage{encodings}{2}{coding -- is loaded}
+\setinterfacemessage{encodings}{title}{encoding}
+\setinterfacemessage{columns}{1}{only -- columns possible}
+\setinterfacemessage{columns}{3}{problems, disable balancing}
+\setinterfacemessage{columns}{2}{use \string\filbreak\space as alternative}
+\setinterfacemessage{columns}{5}{bottom float not yet supported}
+\setinterfacemessage{columns}{4}{top float not yet supported}
+\setinterfacemessage{columns}{7}{balancing aborted after 100 steps}
+\setinterfacemessage{columns}{6}{-- float(s) postponed}
+\setinterfacemessage{columns}{9}{check raggedness}
+\setinterfacemessage{columns}{8}{balanced in -- step(s)}
+\setinterfacemessage{columns}{title}{columns}
+\setinterfacemessage{columns}{13}{wide float moved to top of columns}
+\setinterfacemessage{columns}{12}{float moved to next column / --}
+\setinterfacemessage{columns}{11}{float too wide for column}
+\setinterfacemessage{columns}{10}{(less than) 1 line left}
+\setinterfacemessage{textblocks}{1}{new version, second pass needed}
+\setinterfacemessage{textblocks}{3}{reading blocks from --}
+\setinterfacemessage{textblocks}{2}{writing blocks to --}
+\setinterfacemessage{textblocks}{5}{-- not hidden}
+\setinterfacemessage{textblocks}{4}{second pass needed}
+\setinterfacemessage{textblocks}{7}{-- hidden}
+\setinterfacemessage{textblocks}{6}{-- hidden and processed}
+\setinterfacemessage{textblocks}{9}{-- not typeset}
+\setinterfacemessage{textblocks}{8}{-- typeset}
+\setinterfacemessage{textblocks}{title}{textblocks}
+\setinterfacemessage{textblocks}{12}{-- skipped}
+\setinterfacemessage{textblocks}{11}{-- loaded and typeset}
+\setinterfacemessage{textblocks}{10}{-- loaded and processed}
+\setinterfacemessage{symbols}{1}{loading symbolset --}
+\setinterfacemessage{symbols}{title}{symbols}
+\setinterfacemessage{versions}{1}{missing @+}
+\setinterfacemessage{versions}{3}{selected pages: --}
+\setinterfacemessage{versions}{2}{marking pages}
+\setinterfacemessage{versions}{title}{version}
+\setinterfacemessage{specials}{1}{-- loaded}
+\setinterfacemessage{specials}{3}{-- is reset}
+\setinterfacemessage{specials}{2}{no deeper nesting is permitted --}
+\setinterfacemessage{specials}{5}{loading definition file --}
+\setinterfacemessage{specials}{4}{command -- does not exist}
+\setinterfacemessage{specials}{7}{unknown driver --}
+\setinterfacemessage{specials}{6}{nesting is not permitted}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{loading script set --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{unknown preamble --}
+\setinterfacemessage{fonts}{1}{coding --}
+\setinterfacemessage{fonts}{3}{unknown variant --}
+\setinterfacemessage{fonts}{2}{variant -- is loaded}
+\setinterfacemessage{fonts}{5}{style -- is not defined}
+\setinterfacemessage{fonts}{4}{bodyfont -- is not defined}
+\setinterfacemessage{fonts}{7}{unknown format --}
+\setinterfacemessage{fonts}{6}{-- is loaded}
+\setinterfacemessage{fonts}{14}{bodyfont -- is defined (can better be done global)}
+\setinterfacemessage{fonts}{8}{style -- defined}
+\setinterfacemessage{fonts}{title}{bodyfont}
+\setinterfacemessage{fonts}{10}{unknown font file --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{global file --}
+\setinterfacemessage{databases}{2}{local file --}
+\setinterfacemessage{databases}{4}{unknown file --}
+\setinterfacemessage{databases}{title}{databases}
+\setinterfacemessage{colors}{1}{system -- is global activated}
+\setinterfacemessage{colors}{3}{-- is not defined --}
+\setinterfacemessage{colors}{2}{system -- is local activated}
+\setinterfacemessage{colors}{5}{unknown system --}
+\setinterfacemessage{colors}{4}{system -- is loaded}
+\setinterfacemessage{colors}{7}{palette -- is not available}
+\setinterfacemessage{colors}{6}{palette -- is available}
+\setinterfacemessage{colors}{9}{-- color space is not supported}
+\setinterfacemessage{colors}{8}{specification -- at color -- becomes black}
+\setinterfacemessage{colors}{title}{color}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{color is converted to gray}
+\setinterfacemessage{colors}{10}{-- color space is supported}
+\setinterfacemessage{layouts}{1}{textheight adapted with -- at page --}
+\setinterfacemessage{layouts}{3}{-- times text postponed}
+\setinterfacemessage{layouts}{2}{-- times postponed text placed}
+\setinterfacemessage{layouts}{5}{marginblocks inactive}
+\setinterfacemessage{layouts}{4}{marginblocks active}
+\setinterfacemessage{layouts}{7}{calculating logospace}
+\setinterfacemessage{layouts}{6}{subpage set -- processed (size --)}
+\setinterfacemessage{layouts}{9}{currently no more than -- levels in itemizations}
+\setinterfacemessage{layouts}{8}{calculating backgrounds}
+\setinterfacemessage{layouts}{title}{layout}
+\setinterfacemessage{layouts}{11}{spacing -- not permitted in gridmode}
+\setinterfacemessage{layouts}{10}{-- and -- don't add up to 1.0}
+\setinterfacemessage{check}{1}{missing or ungrouped '=' after '--' in line --}
+\setinterfacemessage{check}{3}{-- -- replaces a macro, use CAPITALS!}
+\setinterfacemessage{check}{2}{-- argument(s) expected in line --}
+\setinterfacemessage{check}{title}{check}
+\setinterfacemessage{metapost}{1}{loading metapost library --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{file synonym -- is already used for --}
+\setinterfacemessage{files}{title}{files}
+\setinterfacemessage{figures}{1}{figure -- can not be found}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{figure -- is not preset}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimensions of -- loaded from figurefile itself}
+\setinterfacemessage{figures}{6}{dimensions of -- calculated by rlxtools}
+\setinterfacemessage{figures}{8}{figureobject -- is reused}
+\setinterfacemessage{figures}{title}{figures}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-mro.tex b/tex/context/base/mult-mro.tex
new file mode 100644
index 000000000..3f52fbc70
--- /dev/null
+++ b/tex/context/base/mult-mro.tex
@@ -0,0 +1,198 @@
+\setinterfacemessage{references}{1}{referinta necunoscuta --}
+\setinterfacemessage{references}{3}{tip necunoscut de referinta --}
+\setinterfacemessage{references}{2}{referinta duplicat -- la pagina --}
+\setinterfacemessage{references}{4}{referinta eronata --}
+\setinterfacemessage{references}{title}{referinte}
+\setinterfacemessage{references}{30}{obiect necunoscut --}
+\setinterfacemessage{references}{31}{obiect duplicat --}
+\setinterfacemessage{references}{21}{documentul -- este incarcat}
+\setinterfacemessage{references}{22}{documentul -- nu este interactiv}
+\setinterfacemessage{references}{23}{referinta obscura -- (prefix=--)}
+\setinterfacemessage{documents}{1}{sheet --}
+\setinterfacemessage{documents}{title}{sheets}
+\setinterfacemessage{documents}{2}{number --}
+\setinterfacemessage{handlings}{1}{font handling --}
+\setinterfacemessage{handlings}{3}{unknown font handling --}
+\setinterfacemessage{handlings}{2}{font handling -- is loaded}
+\setinterfacemessage{handlings}{title}{handling}
+\setinterfacemessage{systems}{title}{sistem}
+\setinterfacemessage{systems}{41}{fisierul extern -- din grupul -- nu exista}
+\setinterfacemessage{systems}{9}{-- nu este gasit/procesat}
+\setinterfacemessage{systems}{91}{papertray --}
+\setinterfacemessage{systems}{8}{o noua versiune de fisier utilitar, este necesara o noua trecere}
+\setinterfacemessage{systems}{21}{nici o data utilitara nu este incarcata}
+\setinterfacemessage{systems}{20}{intelesul (ordinea) pentru -- incarcat}
+\setinterfacemessage{systems}{5}{macro-urile din modulul -- s-au incarcat}
+\setinterfacemessage{systems}{4}{comanda -- este deja definita}
+\setinterfacemessage{systems}{27}{Versiune}
+\setinterfacemessage{systems}{26}{Registri}
+\setinterfacemessage{systems}{25}{Referinte}
+\setinterfacemessage{systems}{24}{Blocuri}
+\setinterfacemessage{systems}{1}{se incarca utilitarul-fisierul este amanat (typemode)}
+\setinterfacemessage{systems}{23}{-- aranjat la --}
+\setinterfacemessage{systems}{22}{folositi un fisier utilitar valid}
+\setinterfacemessage{systems}{2}{-- s-a incarcat}
+\setinterfacemessage{systems}{19}{intelesul (sinonimele) pentru -- incarcat}
+\setinterfacemessage{systems}{18}{sinonimul -- -- nu exista}
+\setinterfacemessage{systems}{7}{macro-urile din modulul -- s-au incarcat deja}
+\setinterfacemessage{systems}{6}{nu s-au gasit macro-uri in modulul --}
+\setinterfacemessage{systems}{14}{s-a fortat trecere pa pagina noua in lista la --}
+\setinterfacemessage{systems}{15}{buffer salvat --}
+\setinterfacemessage{systems}{16}{buffer-ul -- s-a cules}
+\setinterfacemessage{systems}{17}{se culege buffer-ul verbatim --}
+\setinterfacemessage{systems}{13}{marcajul -- definit --}
+\setinterfacemessage{systems}{12}{fisierul utilitar nu este sortat, folositi texutil}
+\setinterfacemessage{systems}{11}{se creeaza un utilitar simplu}
+\setinterfacemessage{systems}{10}{nu folositi em in --}
+\setinterfacemessage{floatblocks}{1}{-- renumerotat / -- => --}
+\setinterfacemessage{floatblocks}{3}{-- mutat}
+\setinterfacemessage{floatblocks}{2}{-- salvat}
+\setinterfacemessage{floatblocks}{5}{ordinea adaptata}
+\setinterfacemessage{floatblocks}{4}{-- plasat}
+\setinterfacemessage{floatblocks}{7}{nr. blocurilor de jos limitat la --}
+\setinterfacemessage{floatblocks}{6}{nr. cadrelor de sus limitat la --}
+\setinterfacemessage{floatblocks}{9}{ordinea deranjata}
+\setinterfacemessage{floatblocks}{8}{mai putin de -- linii}
+\setinterfacemessage{floatblocks}{title}{Blocuri}
+\setinterfacemessage{floatblocks}{13}{there is nothing to split}
+\setinterfacemessage{floatblocks}{12}{nedefinit}
+\setinterfacemessage{floatblocks}{11}{nu este dat nici un bloc}
+\setinterfacemessage{floatblocks}{10}{-- limitat}
+\setinterfacemessage{interactions}{1}{aspectul -- x -- (b x h)}
+\setinterfacemessage{interactions}{3}{inactiv}
+\setinterfacemessage{interactions}{2}{activ}
+\setinterfacemessage{interactions}{5}{unknown attachment --}
+\setinterfacemessage{interactions}{4}{nu exista sincronizare pt. pagini (--) in hmode}
+\setinterfacemessage{interactions}{6}{attachment file -- does not exist}
+\setinterfacemessage{interactions}{title}{interactiuni}
+\setinterfacemessage{interactions}{21}{-- cod inserat}
+\setinterfacemessage{structures}{1}{inceput de bloc sectiune --}
+\setinterfacemessage{structures}{title}{structuri}
+\setinterfacemessage{structures}{2}{sfarsit de bloc sectiune --}
+\setinterfacemessage{linguals}{1}{sablonul -- pentru -- s-a incarcat (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{3}{despartirea in silabe -- pentru -- s-a incarcat (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{2}{nu exista sabloane -- pentru -- (n=--,e=--,m=--) (--,--)}
+\setinterfacemessage{linguals}{5}{sabloanele pentru -- nu sunt incarcate}
+\setinterfacemessage{linguals}{4}{nu exista despartire in silabe -- pentru -- (n=--,e=--,m=--)}
+\setinterfacemessage{linguals}{7}{optiunile specifice ale limbii [--] introduc un spatiu --}
+\setinterfacemessage{linguals}{6}{limba -- nu este definita}
+\setinterfacemessage{linguals}{9}{limba -- este activa}
+\setinterfacemessage{linguals}{8}{optiunile specifice ale limbii [--] adaugate}
+\setinterfacemessage{linguals}{title}{limbi}
+\setinterfacemessage{linguals}{10}{sabloanele -- incarcate}
+\setinterfacemessage{regimes}{1}{codificarea --}
+\setinterfacemessage{regimes}{3}{codificarea -- este necunoscuta}
+\setinterfacemessage{regimes}{2}{codificarea -- este Encarcata}
+\setinterfacemessage{regimes}{title}{codificari}
+\setinterfacemessage{filters}{1}{filter -- is loaded}
+\setinterfacemessage{filters}{title}{filter}
+\setinterfacemessage{filters}{2}{unknown filter --}
+\setinterfacemessage{verbatims}{1}{fisierul -- nu exista}
+\setinterfacemessage{verbatims}{title}{verbatim}
+\setinterfacemessage{encodings}{1}{codificarea --}
+\setinterfacemessage{encodings}{3}{codificarea -- este necunoscuta}
+\setinterfacemessage{encodings}{2}{codificarea -- este Encarcata}
+\setinterfacemessage{encodings}{title}{codificari}
+\setinterfacemessage{columns}{1}{este posibil numai -- coloane}
+\setinterfacemessage{columns}{3}{probleme, se dezactiveaza alinierea}
+\setinterfacemessage{columns}{2}{folositi \string\filbreak\space ca alternativa}
+\setinterfacemessage{columns}{5}{cadrele bottom (bottom float) nu sunt inca suportate}
+\setinterfacemessage{columns}{4}{cadrele top (top float) nu sunt inca suportate}
+\setinterfacemessage{columns}{7}{alinierea este oprita dupa 100 de incercari}
+\setinterfacemessage{columns}{6}{-- blocurile sunt amanate}
+\setinterfacemessage{columns}{9}{verificat alinierea}
+\setinterfacemessage{columns}{8}{aliniat in -- pas(i)}
+\setinterfacemessage{columns}{title}{coloane}
+\setinterfacemessage{columns}{13}{blocul lat este mutat in partea de sus a coloanelor}
+\setinterfacemessage{columns}{12}{blocul este mutat pe urmatoarea coloana / --}
+\setinterfacemessage{columns}{11}{blocul este prea lat pentru coloana}
+\setinterfacemessage{columns}{10}{a mai ramas (mai putin de) 1 linie}
+\setinterfacemessage{textblocks}{1}{o noua versiune, este nevoie de inca o trecere}
+\setinterfacemessage{textblocks}{3}{se citesc blocurile din --}
+\setinterfacemessage{textblocks}{2}{se scriu blocurile in --}
+\setinterfacemessage{textblocks}{5}{-- nu este ascuns}
+\setinterfacemessage{textblocks}{4}{este nevoie de inca o trecere}
+\setinterfacemessage{textblocks}{7}{-- ascuns}
+\setinterfacemessage{textblocks}{6}{-- ascuns si procesat}
+\setinterfacemessage{textblocks}{9}{-- nu este cules}
+\setinterfacemessage{textblocks}{8}{-- cules}
+\setinterfacemessage{textblocks}{title}{blocuri de text}
+\setinterfacemessage{textblocks}{12}{-- sarit peste}
+\setinterfacemessage{textblocks}{11}{-- incarcat si cules}
+\setinterfacemessage{textblocks}{10}{-- incarcat si procesat}
+\setinterfacemessage{symbols}{1}{se incarca setul de simboluri --}
+\setinterfacemessage{symbols}{title}{simboluri}
+\setinterfacemessage{versions}{1}{lipseste @+}
+\setinterfacemessage{versions}{3}{pagini selectate: --}
+\setinterfacemessage{versions}{2}{pagini marcate}
+\setinterfacemessage{versions}{title}{versiuni}
+\setinterfacemessage{specials}{1}{-- incarcat}
+\setinterfacemessage{specials}{3}{-- s-a resetat}
+\setinterfacemessage{specials}{2}{nu este permis un nivel de imbricare mai mare --}
+\setinterfacemessage{specials}{5}{se incarca fisierul de definitii --}
+\setinterfacemessage{specials}{4}{comanda -- nu exista}
+\setinterfacemessage{specials}{7}{driver necunoscut --}
+\setinterfacemessage{specials}{6}{imbricarea nu este permisa}
+\setinterfacemessage{specials}{title}{specials}
+\setinterfacemessage{javascript}{1}{se incarca scriptul --}
+\setinterfacemessage{javascript}{title}{javascript}
+\setinterfacemessage{javascript}{2}{preambul necunoscut --}
+\setinterfacemessage{fonts}{1}{codificarea --}
+\setinterfacemessage{fonts}{3}{varianta necunoscuta --}
+\setinterfacemessage{fonts}{2}{varianta -- este incarcata}
+\setinterfacemessage{fonts}{5}{stilul -- nu este definit}
+\setinterfacemessage{fonts}{4}{corpul de litere -- nu este definit}
+\setinterfacemessage{fonts}{7}{format necunoscut --}
+\setinterfacemessage{fonts}{6}{-- este incarcat}
+\setinterfacemessage{fonts}{14}{bodyfont -- is defined (can better be done global)}
+\setinterfacemessage{fonts}{8}{stilul -- definit}
+\setinterfacemessage{fonts}{title}{corp de litere}
+\setinterfacemessage{fonts}{10}{fisier font necunoscut --}
+\setinterfacemessage{databases}{1}{--}
+\setinterfacemessage{databases}{3}{fisier global --}
+\setinterfacemessage{databases}{2}{fisier local --}
+\setinterfacemessage{databases}{4}{fisier necunoscut --}
+\setinterfacemessage{databases}{title}{baze de date}
+\setinterfacemessage{colors}{1}{sistem -- este activata global}
+\setinterfacemessage{colors}{3}{-- nu este definita --}
+\setinterfacemessage{colors}{2}{sistem -- este activata local}
+\setinterfacemessage{colors}{5}{sistem -- necunoscuta}
+\setinterfacemessage{colors}{4}{sistem -- este incarcata}
+\setinterfacemessage{colors}{7}{palette -- nu este disponibila}
+\setinterfacemessage{colors}{6}{paleta -- este disponibila}
+\setinterfacemessage{colors}{9}{spatiul de culoare -- nu este suportat}
+\setinterfacemessage{colors}{8}{specificatia -- la culoarea -- devine neagra}
+\setinterfacemessage{colors}{title}{culori}
+\setinterfacemessage{colors}{12}{-- is registered}
+\setinterfacemessage{colors}{11}{culoarea este convertita la gri}
+\setinterfacemessage{colors}{10}{spatiul de culoare -- este suportat}
+\setinterfacemessage{layouts}{1}{textheight adaptat cu -- la pagina --}
+\setinterfacemessage{layouts}{3}{textul amanat de -- ori}
+\setinterfacemessage{layouts}{2}{textul amanat de -- ori a fost plasat}
+\setinterfacemessage{layouts}{5}{blocuri marginale inactive}
+\setinterfacemessage{layouts}{4}{blocuri marginale active}
+\setinterfacemessage{layouts}{7}{se calculeaza spatiul pentru logo}
+\setinterfacemessage{layouts}{6}{setul -- de subpagini procesat (dimensiunea --)}
+\setinterfacemessage{layouts}{9}{acum nu se supota mai mult de -- nivele de adancime la iteratii}
+\setinterfacemessage{layouts}{8}{se calculeaza fundalurile}
+\setinterfacemessage{layouts}{title}{aranjamente}
+\setinterfacemessage{layouts}{11}{spatierea -- nu este permisa in gridmode}
+\setinterfacemessage{layouts}{10}{-- si -- nu se adauga pana la 1.0}
+\setinterfacemessage{check}{1}{lipseste '=' dupa '--' in linia --}
+\setinterfacemessage{check}{3}{-- -- inlocuieste un macro, folositi MAJUSCULE!}
+\setinterfacemessage{check}{2}{argumentul(ele) -- sunt asteptate in linia --}
+\setinterfacemessage{check}{title}{verificari}
+\setinterfacemessage{metapost}{1}{se incarca biblioteca metapost --}
+\setinterfacemessage{metapost}{title}{metapost}
+\setinterfacemessage{files}{1}{sinonimul fisierelor -- este folosit deja pentru --}
+\setinterfacemessage{files}{title}{fisiere}
+\setinterfacemessage{figures}{1}{figura -- nu poate fi gasita}
+\setinterfacemessage{figures}{3}{dimensions of -- are determined externally}
+\setinterfacemessage{figures}{2}{figura -- nu este presetata}
+\setinterfacemessage{figures}{5}{dimensions of -- are unknown}
+\setinterfacemessage{figures}{4}{dimensiunea figurii -- se incarca din fisierul insusi}
+\setinterfacemessage{figures}{6}{dimensiunea figurii -- este calculata de rlxtools}
+\setinterfacemessage{figures}{8}{obiectul figura -- este refolosit}
+\setinterfacemessage{figures}{title}{figuri}
+%
+\endinput \ No newline at end of file
diff --git a/tex/context/base/mult-nl.tex b/tex/context/base/mult-nl.tex
index 827b8fd80..30f0b36e6 100644
--- a/tex/context/base/mult-nl.tex
+++ b/tex/context/base/mult-nl.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{na}
\setinterfacevariable{all}{alles}
\setinterfacevariable{always}{altijd}
+\setinterfacevariable{answerarea}{antwoordgebied}
\setinterfacevariable{appendices}{bijlagen}
\setinterfacevariable{appendix}{bijlage}
\setinterfacevariable{april}{april}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{linkshangend}
\setinterfacevariable{leftmargin}{linkermarge}
\setinterfacevariable{leftpage}{linkerpagina}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legenda}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{regel}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normaal}
\setinterfacevariable{nospacing}{geenspatiering}
\setinterfacevariable{not}{niet}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{niethangend}
\setinterfacevariable{nothyphenated}{nietafgebroken}
\setinterfacevariable{november}{november}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{rechtshangend}
\setinterfacevariable{rightmargin}{rechtermarge}
\setinterfacevariable{rightpage}{rechterpagina}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{romaan}
\setinterfacevariable{romannumerals}{romeins}
\setinterfacevariable{rotate}{roteer}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{subsubsubsubonderwerp}
\setinterfacevariable{subsubsubsubsubsection}{subsubsubsubsubparagraaf}
\setinterfacevariable{subsubsubsubsubsubject}{subsubsubsubsubonderwerp}
+\setinterfacevariable{subsubsubsubsubsubsection}{subsubsubsubsubsubparagraaf}
+\setinterfacevariable{subsubsubsubsubsubsubject}{subsubsubsubsubsubonderwerp}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{subsubsubsubsubsubsubparagraaf}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubonderwerp}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubparagraaf}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubonderwerp}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubsubparagraaf}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubsubonderwerp}
\setinterfacevariable{sunday}{zondag}
\setinterfacevariable{support}{support}
\setinterfacevariable{sym}{sym}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{korps}
\setinterfaceconstant{bookmark}{bookmark}
\setinterfaceconstant{bottom}{onder}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{onderafstand}
\setinterfaceconstant{bottomframe}{onderkader}
\setinterfaceconstant{bottomoffset}{onderoffset}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{component}
\setinterfaceconstant{compoundhyphen}{koppelteken}
\setinterfaceconstant{compress}{comprimeren}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{doorgaan}
\setinterfaceconstant{contrastcolor}{contrastkleur}
\setinterfaceconstant{controls}{sturing}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{veldlaag}
\setinterfaceconstant{fieldoffset}{veldoffset}
\setinterfaceconstant{file}{file}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusuit}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{hoogte}
\setinterfaceconstant{hfactor}{hfactor}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{hoffset}
\setinterfaceconstant{horoffset}{rugoffset}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{nummer}
\setinterfaceconstant{numbercolor}{nummerkleur}
\setinterfaceconstant{numbercommand}{nummercommando}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{nummerafstand}
\setinterfaceconstant{numbering}{nummeren}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{nummerscheider}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{nummerletter}
\setinterfaceconstant{numberwidth}{nummerbreedte}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{paginaovergangen}
\setinterfaceconstant{pagecolor}{paginakleur}
\setinterfaceconstant{pagecommand}{paginacommando}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{paginanummer}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{paginastatus}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{paginaletter}
\setinterfaceconstant{palet}{palet}
\setinterfaceconstant{paper}{papier}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{plaatsafsluiter}
\setinterfaceconstant{position}{positie}
\setinterfaceconstant{prefix}{prefix}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{preset}
\setinterfaceconstant{preview}{preview}
\setinterfaceconstant{previous}{vorige}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{reductie}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{verwijzing}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{refereren}
\setinterfaceconstant{regionin}{gebiedin}
\setinterfaceconstant{regionout}{gebieduit}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{lijndikte}
\setinterfaceconstant{samepage}{zelfdepagina}
\setinterfaceconstant{sample}{monster}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{schaal}
\setinterfaceconstant{scope}{scope}
\setinterfaceconstant{screen}{raster}
\setinterfaceconstant{section}{sectie}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{sectienummer}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{scheider}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{setups}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{ystap}
% definitions for interface elements for language nl
%
+\setinterfaceelement{answerlines}{antwoordregels}
+\setinterfaceelement{answerspace}{antwoordruimte}
\setinterfaceelement{begin}{beginvan}
\setinterfaceelement{complete}{volledige}
\setinterfaceelement{coupled}{gekoppelde}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{steltekstinhoudin}
\setinterfacecommand{settextvariable}{kentekstvariabeletoe}
\setinterfacecommand{setupalign}{steluitlijnenin}
+\setinterfacecommand{setupanswerarea}{stelantwoordgebiedin}
\setinterfacecommand{setuparranging}{stelarrangerenin}
\setinterfacecommand{setupbackground}{stelachtergrondin}
\setinterfacecommand{setupbackgrounds}{stelachtergrondenin}
diff --git a/tex/context/base/mult-ro.tex b/tex/context/base/mult-ro.tex
index 297a57be9..ed3cf7e22 100644
--- a/tex/context/base/mult-ro.tex
+++ b/tex/context/base/mult-ro.tex
@@ -68,6 +68,7 @@
\setinterfacevariable{after}{dupa}
\setinterfacevariable{all}{tot}
\setinterfacevariable{always}{totdeauna}
+\setinterfacevariable{answerarea}{answerarea}
\setinterfacevariable{appendices}{apendixuri}
\setinterfacevariable{appendix}{apendix}
\setinterfacevariable{april}{aprilie}
@@ -237,6 +238,7 @@
\setinterfacevariable{lefthanging}{lefthanging}
\setinterfacevariable{leftmargin}{marginestanga}
\setinterfacevariable{leftpage}{paginastanga}
+\setinterfacevariable{lefttoright}{lefttoright}
\setinterfacevariable{legend}{legenda}
\setinterfacevariable{lesshyphenation}{lesshyphenation}
\setinterfacevariable{line}{linie}
@@ -295,6 +297,7 @@
\setinterfacevariable{normal}{normal}
\setinterfacevariable{nospacing}{nospacing}
\setinterfacevariable{not}{nu}
+\setinterfacevariable{note}{note}
\setinterfacevariable{nothanging}{nothanging}
\setinterfacevariable{nothyphenated}{nedespsilabe}
\setinterfacevariable{november}{noiembrie}
@@ -359,6 +362,7 @@
\setinterfacevariable{righthanging}{righthanging}
\setinterfacevariable{rightmargin}{marginedreapta}
\setinterfacevariable{rightpage}{paginadreapta}
+\setinterfacevariable{righttoleft}{righttoleft}
\setinterfacevariable{roman}{roman}
\setinterfacevariable{romannumerals}{numereromane}
\setinterfacevariable{rotate}{rotit}
@@ -428,6 +432,14 @@
\setinterfacevariable{subsubsubsubsubject}{subsubsubsubsubiect}
\setinterfacevariable{subsubsubsubsubsection}{subsubsubsubsubsectiune}
\setinterfacevariable{subsubsubsubsubsubject}{subsubsubsubsubsubiect}
+\setinterfacevariable{subsubsubsubsubsubsection}{subsubsubsubsubsubsectiune}
+\setinterfacevariable{subsubsubsubsubsubsubject}{subsubsubsubsubsubsubiect}
+\setinterfacevariable{subsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsectiune}
+\setinterfacevariable{subsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubiect}
+\setinterfacevariable{subsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubsectiune}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubsubiect}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsection}{subsubsubsubsubsubsubsubsubsectiune}
+\setinterfacevariable{subsubsubsubsubsubsubsubsubsubject}{subsubsubsubsubsubsubsubsubsubiect}
\setinterfacevariable{sunday}{duminica}
\setinterfacevariable{support}{suport}
\setinterfacevariable{sym}{sym}
@@ -520,6 +532,8 @@
\setinterfaceconstant{bodyfont}{fonttext}
\setinterfaceconstant{bookmark}{semncarte}
\setinterfaceconstant{bottom}{jos}
+\setinterfaceconstant{bottomafter}{bottomafter}
+\setinterfaceconstant{bottombefore}{bottombefore}
\setinterfaceconstant{bottomdistance}{distantajos}
\setinterfaceconstant{bottomframe}{framejos}
\setinterfaceconstant{bottomoffset}{offsetjos}
@@ -547,6 +561,7 @@
\setinterfaceconstant{component}{component}
\setinterfaceconstant{compoundhyphen}{compoundhyphen}
\setinterfaceconstant{compress}{compress}
+\setinterfaceconstant{connector}{connector}
\setinterfaceconstant{continue}{continua}
\setinterfaceconstant{contrastcolor}{culoarecontrast}
\setinterfaceconstant{controls}{controale}
@@ -593,6 +608,7 @@
\setinterfaceconstant{fieldlayer}{fieldlayer}
\setinterfaceconstant{fieldoffset}{offsetcamp}
\setinterfaceconstant{file}{fisier}
+\setinterfaceconstant{filtercommand}{filtercommand}
\setinterfaceconstant{focus}{focus}
\setinterfaceconstant{focusin}{focusin}
\setinterfaceconstant{focusout}{focusout}
@@ -626,6 +642,7 @@
\setinterfaceconstant{height}{inaltime}
\setinterfaceconstant{hfactor}{hfactor}
\setinterfaceconstant{hfil}{hfil}
+\setinterfaceconstant{hidenumber}{hidenumber}
\setinterfaceconstant{hoffset}{hoffset}
\setinterfaceconstant{horoffset}{offsetoriz}
\setinterfaceconstant{hyphen}{hyphen}
@@ -714,9 +731,17 @@
\setinterfaceconstant{number}{numar}
\setinterfaceconstant{numbercolor}{culoarenumar}
\setinterfaceconstant{numbercommand}{comandanumar}
+\setinterfaceconstant{numberconversion}{numberconversion}
+\setinterfaceconstant{numberconversionset}{numberconversionset}
\setinterfaceconstant{numberdistance}{numberdistance}
\setinterfaceconstant{numbering}{numerotare}
+\setinterfaceconstant{numberorder}{numberorder}
+\setinterfaceconstant{numberprefix}{numberprefix}
+\setinterfaceconstant{numbersegments}{numbersegments}
\setinterfaceconstant{numberseparator}{separatornumar}
+\setinterfaceconstant{numberseparatorset}{numberseparatorset}
+\setinterfaceconstant{numberset}{numberset}
+\setinterfaceconstant{numberstopper}{numberstopper}
\setinterfaceconstant{numberstyle}{stilnumar}
\setinterfaceconstant{numberwidth}{numberwidth}
\setinterfaceconstant{nx}{nx}
@@ -736,8 +761,22 @@
\setinterfaceconstant{pageboundaries}{marginipagina}
\setinterfaceconstant{pagecolor}{culoarepagina}
\setinterfaceconstant{pagecommand}{comandapagina}
+\setinterfaceconstant{pageconversion}{pageconversion}
+\setinterfaceconstant{pageconversionset}{pageconversionset}
\setinterfaceconstant{pagenumber}{numarpagina}
+\setinterfaceconstant{pageprefix}{pageprefix}
+\setinterfaceconstant{pageprefixconnector}{pageprefixconnector}
+\setinterfaceconstant{pageprefixconversion}{pageprefixconversion}
+\setinterfaceconstant{pageprefixconversionset}{pageprefixconversionset}
+\setinterfaceconstant{pageprefixsegments}{pageprefixsegments}
+\setinterfaceconstant{pageprefixseparatorset}{pageprefixseparatorset}
+\setinterfaceconstant{pageprefixset}{pageprefixset}
+\setinterfaceconstant{pageprefixstopper}{pageprefixstopper}
+\setinterfaceconstant{pagesegments}{pagesegments}
+\setinterfaceconstant{pageseparatorset}{pageseparatorset}
+\setinterfaceconstant{pageset}{pageset}
\setinterfaceconstant{pagestate}{pagestate}
+\setinterfaceconstant{pagestopper}{pagestopper}
\setinterfaceconstant{pagestyle}{stilpagina}
\setinterfaceconstant{palet}{paleta}
\setinterfaceconstant{paper}{hartie}
@@ -747,6 +786,13 @@
\setinterfaceconstant{placestopper}{punestopper}
\setinterfaceconstant{position}{pozitie}
\setinterfaceconstant{prefix}{prefix}
+\setinterfaceconstant{prefixconnector}{prefixconnector}
+\setinterfaceconstant{prefixconversion}{prefixconversion}
+\setinterfaceconstant{prefixconversionset}{prefixconversionset}
+\setinterfaceconstant{prefixsegments}{prefixsegments}
+\setinterfaceconstant{prefixseparatorset}{prefixseparatorset}
+\setinterfaceconstant{prefixset}{prefixset}
+\setinterfaceconstant{prefixstopper}{prefixstopper}
\setinterfaceconstant{preset}{preset}
\setinterfaceconstant{preview}{previzualizare}
\setinterfaceconstant{previous}{precendent}
@@ -757,6 +803,7 @@
\setinterfaceconstant{reduction}{reducere}
\setinterfaceconstant{ref}{ref}
\setinterfaceconstant{reference}{referinta}
+\setinterfaceconstant{referenceprefix}{referenceprefix}
\setinterfaceconstant{referencing}{referinta}
\setinterfaceconstant{regionin}{regiuneintrare}
\setinterfaceconstant{regionout}{regiuneiesire}
@@ -788,11 +835,18 @@
\setinterfaceconstant{rulethickness}{grosimerigla}
\setinterfaceconstant{samepage}{aceeasipagina}
\setinterfaceconstant{sample}{exemplu}
+\setinterfaceconstant{saveinlist}{saveinlist}
\setinterfaceconstant{scale}{scala}
\setinterfaceconstant{scope}{scop}
\setinterfaceconstant{screen}{ecran}
\setinterfaceconstant{section}{sectiune}
+\setinterfaceconstant{sectionconversion}{sectionconversion}
+\setinterfaceconstant{sectionconversionset}{sectionconversionset}
\setinterfaceconstant{sectionnumber}{numarsectiune}
+\setinterfaceconstant{sectionsegments}{sectionsegments}
+\setinterfaceconstant{sectionseparatorset}{sectionseparatorset}
+\setinterfaceconstant{sectionset}{sectionset}
+\setinterfaceconstant{sectionstopper}{sectionstopper}
\setinterfaceconstant{separator}{separator}
\setinterfaceconstant{set}{set}
\setinterfaceconstant{setups}{setups}
@@ -892,6 +946,8 @@
\setinterfaceconstant{ystep}{ystep}
% definitions for interface elements for language ro
%
+\setinterfaceelement{answerlines}{answerlines}
+\setinterfaceelement{answerspace}{answerspace}
\setinterfaceelement{begin}{inceput}
\setinterfaceelement{complete}{complet}
\setinterfaceelement{coupled}{cuplat}
@@ -1277,6 +1333,7 @@
\setinterfacecommand{settextcontent}{settextcontent}
\setinterfacecommand{settextvariable}{setvariabilatext}
\setinterfacecommand{setupalign}{seteazaalinierea}
+\setinterfacecommand{setupanswerarea}{setupanswerarea}
\setinterfacecommand{setuparranging}{seteazaaranjareapag}
\setinterfacecommand{setupbackground}{seteazafundal}
\setinterfacecommand{setupbackgrounds}{seteazafundaluri}
diff --git a/tex/context/base/mult-sys.tex b/tex/context/base/mult-sys.tex
index 407146901..0fb64d98a 100644
--- a/tex/context/base/mult-sys.tex
+++ b/tex/context/base/mult-sys.tex
@@ -15,7 +15,7 @@
%D system constants. By doing so we save lots of memory while
%D at the same time we prevent ourself from typing errors.
-\writestatus{loading}{Context Multilingual Macros / System}
+\writestatus{loading}{ConTeXt Multilingual Macros / System}
\unprotect
@@ -39,7 +39,7 @@
\definesystemconstant {arabic} \definesystemconstant {ar}
\definesystemconstant {catalan} \definesystemconstant {ca}
\definesystemconstant {chinese} \definesystemconstant {cn}
-\definesystemconstant {croation} \definesystemconstant {hr}
+\definesystemconstant {croatian} \definesystemconstant {hr}
\definesystemconstant {czech} \definesystemconstant {cs} \definesystemconstant {cz}
\definesystemconstant {danish} \definesystemconstant {da}
\definesystemconstant {dutch} \definesystemconstant {nl}
@@ -116,10 +116,16 @@
\definemessageconstant {textblocks}
\definemessageconstant {verbatims}
\definemessageconstant {versions}
+\definemessageconstant {metapost}
+\definemessageconstant {chemicals}
%D Net come some \CONTEXT\ constants, used in the definition
%D of private commands:
+\definesystemconstant {tex}
+\definesystemconstant {xml}
+\definesystemconstant {lua}
+
\definesystemconstant {next}
\definesystemconstant {pickup}
\definesystemconstant {ascii}
@@ -144,6 +150,12 @@
\definesystemconstant {section} \let\v!sectionlevel\s!section % for old times sake
\definesystemconstant {handler}
\definesystemconstant {counter}
+\definesystemconstant {single}
+\definesystemconstant {multi}
+
+\definesystemconstant {hasnumber}
+\definesystemconstant {hastitle}
+\definesystemconstant {hascaption}
%D A more experienced \TEX\ user will recognize the next four
%D constants. We need these because font-definitions are
@@ -184,6 +196,10 @@
\definesystemconstant {black}
\definesystemconstant {white}
+\definesystemconstant {format}
+\definesystemconstant {extensions}
+\definesystemconstant {initializations}
+
%D Just to be complete we define the standard \TEX\ units.
\definesystemconstant {cm}
@@ -210,8 +226,11 @@
\definesystemconstant {see}
\definesystemconstant {from}
\definesystemconstant {to}
-\definesystemconstant {page}
\definesystemconstant {line}
+\definesystemconstant {page}
+\definesystemconstant {realpage}
+\definesystemconstant {userpage}
+\definesystemconstant {subpage}
\definesystemconstant {synonym}
@@ -332,22 +351,11 @@
\def\!!twelvepoint {12pt}
\def\!!fourteenpointfour {14.4pt}
-\newdimen \onepoint \onepoint = 1pt
-\newdimen \onebasepoint \onebasepoint = 1bp
-\chardef \scaledpoint = 1
-
\let\onerealpoint\onepoint % needed for latex
-\newcount\medcard \medcard\!!medcard % used in font module
-\newcount\maxcard \maxcard\!!maxcard % used in font module
-
-\ifx\thousandpoint\undefined \newdimen\thousandpoint \fi
-
-\thousandpoint=1000pt
-
-%D Another optimization is:
-
-\let\points\onepoint
+% D Another optimization is:
+%
+% \let\points\onepoint
%D A rough test is:
%D
@@ -402,6 +410,7 @@
\definesystemvariable {ck} % Character Kerning
\definesystemvariable {cl} % kleur (CoLor setup)
\definesystemvariable {cn} % CollumN
+\definesystemvariable {cm} % CheMical
\definesystemvariable {co} % COmbinaties
\definesystemvariable {cp} % CliP
\definesystemvariable {cr} % kleur (ColoR)
@@ -438,9 +447,11 @@
\definesystemvariable {fm} % ForMules
\definesystemvariable {fn} % subformulas
\definesystemvariable {fp} % FilegroeP
+\definesystemvariable {fq} % Features
\definesystemvariable {fr} % ForM
\definesystemvariable {fs} % FileSynonym
\definesystemvariable {ft} % FonTs
+\definesystemvariable {fu} % FontSolution
\definesystemvariable {fv} % FontVariant
\definesystemvariable {fx} % FoXet
\definesystemvariable {ha} % HAng
@@ -484,6 +495,7 @@
\definesystemvariable {ln} % LijNen
\definesystemvariable {lo} % LOgos
\definesystemvariable {lt} % LiTeratuur
+\definesystemvariable {ls} % languageScript
\definesystemvariable {ly} % LaYout
\definesystemvariable {ma} % MargeAchtergrond
\definesystemvariable {mb} % MargeBlokken
@@ -492,14 +504,16 @@
\definesystemvariable {mk} % MarKering
\definesystemvariable {mt} % inline MaTh
\definesystemvariable {mo} % Math Options
-\definesystemvariable {nm} % Nummering
\definesystemvariable {mx} % MatriX
\definesystemvariable {ng} % parbuilders
+\definesystemvariable {nh} % new heads (structure)
+\definesystemvariable {nm} % Nummering
\definesystemvariable {np} % NaastPlaatsen
\definesystemvariable {nr} % Nummeren
\definesystemvariable {of} % OFfset
\definesystemvariable {oi} % OmlijndInstellingen
\definesystemvariable {ol} % OmLijnd
+\definesystemvariable {od} % Omlijnd Defaults (simple)
\definesystemvariable {on} % ONderstreep
\definesystemvariable {oo} % OpsOmmingen
\definesystemvariable {op} % OPsomming
@@ -786,63 +800,23 @@
% \ifinterfacetranslation \else % interfacetranslation is obsolete
-\startmessages dutch library: check
- title: controle
- 1: '=' ontbreekt of zonder {} na '--' in regel --
- 2: -- argument(en) verwacht in regel --
- 3: -- -- vervangt een macro, gebruik HOOFDLETTERS!
-\stopmessages
+% messages moved
-\startmessages english library: check
- title: check
- 1: missing or ungrouped '=' after '--' in line --
- 2: -- argument(s) expected in line --
- 3: -- -- replaces a macro, use CAPITALS!
-\stopmessages
+% messages moved
% 1: to be adapted
-\startmessages german library: check
- title: check
- 1: Fehlendes '=' nach '--' in Zeile --
- 2: -- Argument(e) in Zeile -- erwartet
- 3: -- -- ersetzt ein Makro, verwende VERSALIEN!
-\stopmessages
-
-\startmessages czech library: check
- title: kontrola
- 1: postradam '=' po '--' na radku --
- 2: ocekavam -- argument(y) na radku --
- 3: -- -- nahrazuje makro, uzijte VERZALKY!
-\stopmessages
-
-\startmessages italian library: check
- title: controllo
- 1: '=' mancante o non raggruppato dopo '--' alla riga --
- 2: -- argomento/i attesi alla riga --
- 3: -- -- sostituisce una macro, usare le MAIUSCOLE!
-\stopmessages
-
-\startmessages norwegian library: check
- title: kontroll
- 1: manglende '=' etter '--' i linje --
- 2: -- argument forventet i linje --
- 3: -- -- overskygger en makro, bruk STORE BOKSTAVER!
-\stopmessages
-
-\startmessages romanian library: check
- title: verificari
- 1: lipseste '=' dupa '--' in linia --
- 2: argumentul(ele) -- sunt asteptate in linia --
- 3: -- -- inlocuieste un macro, folositi MAJUSCULE!
-\stopmessages
-
-\startmessages french library: check
- title: vérification
- 1: manquant ou dégroupé '=' après '--' à la ligne --
- 2: -- argument(s) attendu(s) à la ligne --
- 3: -- -- remplace une macro, utilisez des MAJUSCULES !
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
% \fi
diff --git a/tex/context/base/node-dum.lua b/tex/context/base/node-dum.lua
new file mode 100644
index 000000000..274e0cdd6
--- /dev/null
+++ b/tex/context/base/node-dum.lua
@@ -0,0 +1,24 @@
+if not modules then modules = { } end modules ['node-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+nodes = nodes or { }
+
+function nodes.simple_font_dummy(head,tail)
+ return tail
+end
+
+function nodes.simple_font_handler(head)
+ local tail = node.slide(head)
+-- lang.hyphenate(head,tail)
+ head = nodes.process_characters(head,tail)
+ nodes.inject_kerns(head)
+ nodes.protect_glyphs(head)
+ tail = node.ligaturing(head,tail)
+ tail = node.kerning(head,tail)
+ return head
+end
diff --git a/tex/context/base/node-ext.lua b/tex/context/base/node-ext.lua
new file mode 100644
index 000000000..b098829cd
--- /dev/null
+++ b/tex/context/base/node-ext.lua
@@ -0,0 +1,30 @@
+if not modules then modules = { } end modules ['node-ext'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>Serializing nodes can be handy for tracing. Also, saving and
+loading node lists can come in handy as soon we are going to
+use external applications to process node lists.</p>
+--ldx]]--
+
+function nodes.show(stack)
+-- texio.write_nl(table.serialize(stack))
+end
+
+function nodes.save(stack,name) -- *.ltn : luatex node file
+-- if name then
+-- file.savedata(name,table.serialize(stack))
+-- else
+-- texio.write_nl('log',table.serialize(stack))
+-- end
+end
+
+function nodes.load(name)
+-- return file.loaddata(name)
+-- -- todo
+end
diff --git a/tex/context/base/node-fin.lua b/tex/context/base/node-fin.lua
new file mode 100644
index 000000000..3810b7a85
--- /dev/null
+++ b/tex/context/base/node-fin.lua
@@ -0,0 +1,363 @@
+if not modules then modules = { } end modules ['node-fin'] = {
+ version = 1.001,
+ comment = "companion to node-fin.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this module is being reconstructed
+
+local next, type, format = next, type, string.format
+local texsprint = tex.sprint
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local rule = node.id('rule')
+local whatsit = node.id('whatsit')
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+
+local has_attribute = node.has_attribute
+local copy_node = node.copy
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+states = states or { }
+shipouts = shipouts or { }
+
+local numbers = attributes.numbers
+local trigger = attributes.private('trigger')
+local triggering = false
+
+-- these two will be like trackers
+
+function states.enabletriggering()
+ triggering = true
+end
+function states.disabletriggering()
+ triggering = false
+end
+
+--
+
+states.collected = states.collected or { }
+
+storage.register("states/collected", states.collected, "states.collected")
+
+local collected = states.collected
+
+function states.collect(str)
+ collected[#collected+1] = str
+end
+
+function states.flush()
+ if #collected > 0 then
+ for i=1,#collected do
+ texsprint(ctxcatcodes,collected[i]) -- we're in context mode anyway
+ end
+ collected = { }
+ states.collected = collected
+ end
+end
+
+function states.check()
+ texio.write_nl(concat(collected,"\n"))
+end
+
+-- we used to do the main processor loop here and call processor for each node
+-- but eventually this was too much a slow down (1 sec on 23 for 120 pages mk)
+-- so that we moved looping to the processor itself; this may lead to a bit of
+-- duplicate code once that we have more state handlers
+
+local function process_attribute(head,plugin) -- head,attribute,enabled,initializer,resolver,processor,finalizer
+ starttiming(attributes)
+ local done, used, ok = false, nil, false
+ local attribute = numbers[plugin.name] -- todo: plugin.attribute
+ local namespace = plugin.namespace
+ if namespace.enabled then
+ local processor = plugin.processor
+ if processor then
+ local initializer = plugin.initializer
+ local resolver = plugin.resolver
+ local inheritance = (resolver and resolver()) or -0x7FFFFFFF -- we can best use nil and skip !
+ if initializer then
+ initializer(namespace,attribute,head)
+ end
+ head, ok = processor(namespace,attribute,head,inheritance)
+ if ok then
+ local finalizer = plugin.finalizer
+ if finalizer then
+ head, ok, used = finalizer(namespace,attribute,head)
+ if used then
+ local flusher = plugin.flusher
+ if flusher then
+ local h, d = flusher(namespace,attribute,head,used)
+ head = h
+ end
+ end
+ end
+ done = true
+ end
+ end
+ end
+ stoptiming(attributes)
+ return head, done
+end
+
+nodes.process_attribute = process_attribute
+
+function nodes.install_attribute_handler(plugin)
+ return function(head)
+ return process_attribute(head,plugin)
+ end
+end
+
+-- a few handlers
+
+local current, current_selector, used, done = 0, 0, { }, false
+
+local function insert(n,stack,previous,head) -- there is a helper, we need previous because we are not slided
+ if n then
+ if type(n) == "function" then
+ n = n()
+ end
+ if n then
+ n = copy_node(n)
+ n.next = stack
+ if previous then
+ previous.next = n
+ else
+ head = n
+ end
+ previous = n -- ?
+ else
+ -- weird
+ end
+ end
+ return stack, head
+end
+
+function states.initialize(what, attribute, stack)
+ current, current_selector, used, done = 0, 0, { }, false
+end
+
+function states.finalize(namespace,attribute,head) -- is this one ok?
+ if current > 0 then
+ local nn = namespace.none
+ if nn then
+ local id = head.id
+ if id == hlist or id == vlist then
+ local list = head.list
+ if list then
+ local _, h = insert(nn,list,nil,list)
+ head.list = h
+ end
+ else
+ stack, head = insert(nn,head,nil,head)
+ end
+ return head, true, true
+ end
+ end
+ return head, false, false
+end
+
+local function process(namespace,attribute,head,inheritance,default) -- one attribute
+ local trigger = triggering and namespace.triggering and trigger
+ local stack, previous, done = head, nil, false
+ local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
+ while stack do
+ local id = stack.id
+ -- we need to deal with literals too (reset as well as oval)
+--~ if id == glyph or (id == whatsit and stack.subtype == 8) or (id == rule and stack.width ~= 0) or (id == glue and stack.leader) then -- or disc
+ if id == glyph or (id == rule and stack.width ~= 0) or (id == glue and stack.leader) then -- or disc
+ local c = has_attribute(stack,attribute)
+ if c then
+ if default and c == inheritance then
+ if current ~= default then
+ local data = nsdata[default] or nsreviver(default)
+ stack, head = insert(data,stack,previous,head)
+ current, done, used[default] = default, true, true
+ end
+ elseif current ~= c then
+ local data = nsdata[c] or nsreviver(c)
+ stack, head = insert(data,stack,previous,head)
+ current, done, used[c] = c, true, true
+ end
+ -- here ? compare selective
+ if id == glue then --leader
+ -- same as *list
+ local content = stack.leader
+ if content then
+ local savedcurrent = current
+ local ci = content.id
+ if ci == hlist or ci == vlist then
+ -- else we reset inside a box unneeded, okay, the downside is
+ -- that we trigger color in each repeated box, so there is room
+ -- for improvement here
+ current = 0
+ end
+ local ok = false
+ if trigger and has_attribute(stack,trigger) then
+ local outer = has_attribute(stack,attribute)
+ if outer ~= inheritance then
+ stack.leader, ok = process(namespace,attribute,content,inheritance,outer)
+ else
+ stack.leader, ok = process(namespace,attribute,content,inheritance,default)
+ end
+ else
+ stack.leader, ok = process(namespace,attribute,content,inheritance,default)
+ end
+ current = savedcurrent
+ done = done or ok
+ end
+ end
+ elseif default and inheritance then
+ if current ~= default then
+ local data = nsdata[default] or nsreviver(default)
+ stack, head = insert(data,stack,previous,head)
+ current, done, used[default] = default, true, true
+ end
+ elseif current > 0 then
+ stack, head = insert(nsnone,stack,previous,head)
+ current, done, used[0] = 0, true, true
+ end
+ elseif id == hlist or id == vlist then
+ local content = stack.list
+ if content then
+ local ok = false
+ if trigger and has_attribute(stack,trigger) then
+ local outer = has_attribute(stack,attribute)
+ if outer ~= inheritance then
+ stack.list, ok = process(namespace,attribute,content,inheritance,outer)
+ else
+ stack.list, ok = process(namespace,attribute,content,inheritance,default)
+ end
+ else
+ stack.list, ok = process(namespace,attribute,content,inheritance,default)
+ end
+ done = done or ok
+ end
+ end
+ previous = stack
+ stack = stack.next
+ end
+ -- we need to play safe
+-- i need a proper test set for this, maybe controlled per feature
+--~ if current > 0 then
+--~ stack, head = insert(nsnone,stack,previous,head)
+--~ current, current_selector, done, used[0] = 0, 0, true, true
+--~ end
+ return head, done
+end
+
+states.process = process
+
+-- we can force a selector, e.g. document wide color spaces, saves a little
+-- watch out, we need to check both the selector state (like colorspace) and
+-- the main state (like color), otherwise we get into troubles when a selector
+-- state changes while the main state stays the same (like two glyphs following
+-- each other with the same color but different color spaces e.g. \showcolor)
+
+local function selective(namespace,attribute,head,inheritance,default) -- two attributes
+ local trigger = triggering and namespace.triggering and trigger
+ local stack, previous, done = head, nil, false
+ local nsforced, nsselector = namespace.forced, namespace.selector
+ local nsdata, nsreviver, nsnone = namespace.data, namespace.reviver, namespace.none
+ while stack do
+ local id = stack.id
+ -- we need to deal with literals too (reset as well as oval)
+--~ if id == glyph or (id == whatsit and stack.subtype == 8) or (id == rule and stack.width ~= 0) or (id == glue and stack.leader) then -- or disc
+ if id == glyph or (id == rule and stack.width ~= 0) or (id == glue and stack.leader) then -- or disc
+ local c = has_attribute(stack,attribute)
+ if c then
+ if default and c == inheritance then
+ if current ~= default then
+ local data = nsdata[default] or nsreviver(default)
+ stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
+ current, done, used[default] = default, true, true
+ end
+ else
+ local s = has_attribute(stack,nsselector)
+ if current ~= c or current_selector ~= s then
+ local data = nsdata[c] or nsreviver(c)
+ stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
+ current, current_selector, done, used[c] = c, s, true, true
+ end
+ end
+ elseif default and inheritance then
+ if current ~= default then
+ local data = nsdata[default] or nsreviver(default)
+ stack, head = insert(data[nsforced or has_attribute(stack,nsselector) or nsselector],stack,previous,head)
+ current, done, used[default] = default, true, true
+ end
+ elseif current > 0 then
+ stack, head = insert(nsnone,stack,previous,head)
+ current, current_selector, done, used[0] = 0, 0, true, true
+ end
+ if id == glue then -- leader
+ -- same as *list
+ local content = stack.leader
+ if content then
+ local savedcurrent = current
+ local ci = content.id
+ if ci == hlist or ci == vlist then
+ -- else we reset inside a box unneeded, okay, the downside is
+ -- that we trigger color in each repeated box, so there is room
+ -- for improvement here
+ current = 0
+ end
+ local ok = false
+ if trigger and has_attribute(stack,trigger) then
+ local outer = has_attribute(stack,attribute)
+ if outer ~= inheritance then
+ stack.leader, ok = selective(namespace,attribute,content,inheritance,outer)
+ else
+ stack.leader, ok = selective(namespace,attribute,content,inheritance,default)
+ end
+ else
+ stack.leader, ok = selective(namespace,attribute,content,inheritance,default)
+ end
+ current = savedcurrent
+ done = done or ok
+ end
+ end
+ elseif id == hlist or id == vlist then
+ local content = stack.list
+ if content then
+ local ok = false
+ if trigger and has_attribute(stack,trigger) then
+ local outer = has_attribute(stack,attribute)
+ if outer ~= inheritance then
+ stack.list, ok = selective(namespace,attribute,content,inheritance,outer)
+ else
+ stack.list, ok = selective(namespace,attribute,content,inheritance,default)
+ end
+ else
+ stack.list, ok = selective(namespace,attribute,content,inheritance,default)
+ end
+ done = done or ok
+ end
+ end
+ previous = stack
+ stack = stack.next
+ end
+ -- we need to play safe, this is subptimal since now we end each box
+ -- even if it's not needed
+-- i need a proper test set for this, maybe controlled per feature
+--~ if current > 0 then
+--~ stack, head = insert(nsnone,stack,previous,head)
+--~ current, current_selector, done, used[0] = 0, 0, true, true
+--~ end
+ return head, done
+end
+
+states.selective = selective
+
+statistics.register("attribute processing time", function()
+ if statistics.elapsedindeed(attributes) then
+ return format("%s seconds",statistics.elapsedtime(attributes))
+ end
+end)
diff --git a/tex/context/base/node-fin.tex b/tex/context/base/node-fin.tex
new file mode 100644
index 000000000..787706ff2
--- /dev/null
+++ b/tex/context/base/node-fin.tex
@@ -0,0 +1,78 @@
+%D \module
+%D [ file=attr-ini,
+%D version=2007.06.06, % probably a bit older
+%D title=\CONTEXT\ Node Macros,
+%D subtitle=Finalizing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Node Support / Finalizing}
+
+% Objects are processed indepently \unknown\ actually we may
+% need a proper callback.
+
+\unprotect
+
+\registerctxluafile{node-fin}{1.001} % we might generalize this one
+
+\definesystemattribute[trigger] % feature inheritance
+
+\newbox\finalizedshipoutbox
+
+\def\finalizeobjectbox#1{\ctxlua{nodes.process_page(tex.box[\number#1])}}
+
+\def\finalizeshipoutbox#1% % hack till we have access to pdf backend
+ {\global\setbox\finalizedshipoutbox\hbox{#1}%
+ \finalizeobjectbox\finalizedshipoutbox
+ \hbox{\ctxlua{states.flush()}\box\finalizedshipoutbox}}
+
+% tricky stuff:
+
+\newcount\attributeboxcount
+
+\edef\startinheritattributes{\dosetattribute {trigger}{1}}
+\edef\stopinheritattributes {\doresetattribute{trigger}}
+
+\def\doattributedcopy {\afterassignment\dodoattributedcopy\attributeboxcount}
+\def\doattributedbox {\afterassignment\dodoattributedbox \attributeboxcount}
+
+\def\dodoattributedcopy
+ {\startinheritattributes
+ \ifvbox\attributeboxcount
+ \vbox{\unvcopy\attributeboxcount}%
+ \else
+ \hbox{\unhcopy\attributeboxcount}%
+ \fi
+ \stopinheritattributes}
+
+\def\dodoattributedbox
+ {\startinheritattributes
+ \ifvbox\attributeboxcount
+ \vbox{\unvbox\attributeboxcount}%
+ \else
+ \hbox{\unhbox\attributeboxcount}%
+ \fi
+ \stopinheritattributes}
+
+\def\enableattributeinheritance
+ {\ctxlua{states.enabletriggering()}%
+ \let\attributedcopy\doattributedcopy
+ \let\attributedbox \doattributedbox}
+
+\def\disableattributeinheritance
+ {\ctxlua{states.disabletriggering()}%
+ \let\attributedcopy\copy
+ \let\attributedbox \box}
+
+\disableattributeinheritance
+
+% \appendtoks
+% \enableattributeinheritance % will become default
+% \to\everyjob
+
+\protect \endinput
diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua
new file mode 100644
index 000000000..3ad9060c3
--- /dev/null
+++ b/tex/context/base/node-fnt.lua
@@ -0,0 +1,206 @@
+if not modules then modules = { } end modules ['node-fnt'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+
+local trace_characters = false trackers.register("nodes.characters", function(v) trace_characters = v end)
+
+local glyph = node.id('glyph')
+
+local traverse_id = node.traverse_id
+local has_attribute = node.has_attribute
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local fontdata = fonts.ids
+
+-- some tests with using an array of dynamics[id] and processes[id] demonstrated
+-- that there was nothing to gain (unless we also optimize other parts)
+--
+-- maybe getting rid of the intermediate shared can save some time
+
+-- potential speedup: check for subtype < 256 so that we can remove that test
+-- elsewhere, danger: injected nodes will not be dealt with but that does not
+-- happen often; we could consider processing sublists but that might need mor
+-- checking later on; the current approach also permits variants
+
+if tex.attribute[0] < 0 then
+
+ texio.write_nl("log","!")
+ texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
+ texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
+ texio.write_nl("log","! purposed so setting them at the TeX end might break the font handler.")
+ texio.write_nl("log","!")
+
+ tex.attribute[0] = 0 -- else no features
+
+end
+
+function nodes.process_characters(head)
+ -- either next or not, but definitely no already processed list
+ starttiming(nodes)
+ local usedfonts, attrfonts, done = { }, { }, false
+ local a, u, prevfont, prevattr = 0, 0, nil, 0
+ for n in traverse_id(glyph,head) do
+ local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts, preset to 0 is faster (first match)
+ if attr and attr > 0 then
+ if font ~= prevfont or attr ~= prevattr then
+ local used = attrfonts[font]
+ if not used then
+ used = { }
+ attrfonts[font] = used
+ end
+ if not used[attr] then
+ -- we do some testing outside the function
+ local tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ if shared then
+ local dynamics = shared.dynamics
+ if dynamics then
+ local d = shared.set_dynamics(font,dynamics,attr) -- still valid?
+ if d then
+ used[attr] = d
+ a = a + 1
+ end
+ end
+ end
+ end
+ prevfont, prevattr = font, attr
+ end
+ elseif font ~= prevfont then
+ prevfont, prevattr = font, 0
+ local used = usedfonts[font]
+ if not used then
+ local tfmdata = fontdata[font]
+ if tfmdata then
+ local shared = tfmdata.shared -- we need to check shared, only when same features
+ if shared then
+ local processors = shared.processes
+ if processors and #processors > 0 then
+ usedfonts[font] = processors
+ u = u + 1
+ end
+ end
+ else
+ -- probably nullfont
+ end
+ end
+ else
+ prevattr = attr
+ end
+ end
+ -- we could combine these and just make the attribute nil
+ if u == 1 then
+ local font, processors = next(usedfonts)
+ local n = #processors
+ if n > 0 then
+ local h, d = processors[1](head,font,false)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,0) -- false)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ elseif u > 0 then
+ for font, processors in next, usedfonts do
+ local n = #processors
+ local h, d = processors[1](head,font,false)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,0) -- false)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ end
+ if a == 1 then
+ local font, dynamics = next(attrfonts)
+ for attribute, processors in next, dynamics do -- attr can switch in between
+ local n = #processors
+ local h, d = processors[1](head,font,attribute)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,attribute)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ elseif a > 0 then
+ for font, dynamics in next, attrfonts do
+ for attribute, processors in next, dynamics do -- attr can switch in between
+ local n = #processors
+ local h, d = processors[1](head,font,attribute)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,attribute)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ end
+ end
+ stoptiming(nodes)
+ if trace_characters then
+ nodes.report(head,done)
+ end
+ return head, true
+end
+
+if node.protect_glyphs then
+
+ nodes.protect_glyphs = node.protect_glyphs
+ nodes.unprotect_glyphs = node.unprotect_glyphs
+
+else do
+
+ -- initial value subtype : X000 0001 = 1 = 0x01 = char
+ --
+ -- expected before linebreak : X000 0000 = 0 = 0x00 = glyph
+ -- X000 0010 = 2 = 0x02 = ligature
+ -- X000 0100 = 4 = 0x04 = ghost
+ -- X000 1010 = 10 = 0x0A = leftboundary lig
+ -- X001 0010 = 18 = 0x12 = rightboundary lig
+ -- X001 1010 = 26 = 0x1A = both boundaries lig
+ -- 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
+ local s = g.subtype
+ if s == 1 then
+ done, g.subtype = true, 256
+ elseif s <= 256 then
+ done, g.subtype = true, 256 + s
+ end
+ end
+ return done
+ end
+
+ function nodes.unprotect_glyphs(head)
+ local done = false
+ for g in traverse_id(glyph,head) do
+ local s = g.subtype
+ if s > 256 then
+ done, g.subtype = true, s - 256
+ end
+ end
+ return done
+ end
+
+end end
diff --git a/tex/context/base/node-ini.lua b/tex/context/base/node-ini.lua
index 8b451124e..8185e3033 100644
--- a/tex/context/base/node-ini.lua
+++ b/tex/context/base/node-ini.lua
@@ -7,225 +7,68 @@ if not modules then modules = { } end modules ['node-ini'] = {
}
--[[ldx--
-<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
-implement a few helper functions. These functions are rather optimized.</p>
+<p>Most of the code that had accumulated here is now separated in
+modules.</p>
--ldx]]--
-local format = string.format
-
-nodes = nodes or { }
-nodes.trace = false
-nodes.ignore = nodes.ignore or false
-
-local hlist = node.id('vlist')
-local vlist = node.id('hlist')
-local glyph = node.id('glyph')
-local disc = node.id('disc')
-local mark = node.id('mark')
-local glue = node.id('glue')
-local whatsit = node.id('whatsit')
-
--- handy helpers
-
-if node.protect_glyphs then
-
- nodes.protect_glyphs = node.protect_glyphs
- nodes.unprotect_glyphs = node.unprotect_glyphs
+-- this module is being reconstructed
-else do
+local utf = unicode.utf8
+local next, type = next, type
+local format, concat, match, utfchar = string.format, table.concat, string.match, utf.char
- -- initial value subtype : X000 0001 = 1 = 0x01 = char
- --
- -- expected before linebreak : X000 0000 = 0 = 0x00 = glyph
- -- X000 0010 = 2 = 0x02 = ligature
- -- X000 0100 = 4 = 0x04 = ghost
- -- X000 1010 = 10 = 0x0A = leftboundary lig
- -- X001 0010 = 18 = 0x12 = rightboundary lig
- -- X001 1010 = 26 = 0x1A = both boundaries lig
- -- X000 1100 = 12 = 0x1C = leftghost
- -- X001 0100 = 20 = 0x14 = rightghost
+local chardata = characters and characters.data
+--[[ldx--
+<p>We start with a registration system for atributes so that we can use the
+symbolic names later on.</p>
+--ldx]]--
- local traverse_id = node.traverse_id
-
- function nodes.protect_glyphs(head)
- local done = false
- for g in traverse_id(glyph,head) do
- local s = g.subtype
- if s == 1 then
- done, g.subtype = true, 256
- elseif s <= 256 then
- done, g.subtype = true, 256 + s
- end
- end
- return done
- end
-
- function nodes.unprotect_glyphs(head)
- local done = false
- for g in traverse_id(glyph,head) do
- local s = g.subtype
- if s > 256 then
- done, g.subtype = true, s - 256
- end
- end
- return done
- end
-
-end end
-
-do
-
- local remove, free = node.remove, node.free
-
- function nodes.remove(head, current, free_too)
- local t = current
- head, current = remove(head,current)
- if t then
- if free_too then
- free(t)
- t = nil
- else
- t.next, t.prev = nil, nil
- end
- end
- return head, current, t
- end
-
---~ function nodes.remove(head, current, delete)
---~ local t = current
---~ if current == head then
---~ current = current.next
---~ if current then
---~ current.prev = nil
---~ end
---~ head = current
---~ else
---~ local prev, next = current.prev, current.next
---~ if prev then
---~ prev.next = next
---~ end
---~ if next then
---~ next.prev = prev
---~ end
---~ current = next -- not: or next
---~ end
---~ if t then
---~ if free_too then
---~ free(t)
---~ t = nil
---~ else
---~ t.next, t.prev = nil, nil
---~ end
---~ end
---~ return head, current, t
---~ end
-
+attributes = attributes or { }
- function nodes.delete(head,current)
- return nodes.remove(head,current,true)
- end
+attributes.names = attributes.names or { }
+attributes.numbers = attributes.numbers or { }
+attributes.list = attributes.list or { }
+attributes.unsetvalue = -0x7FFFFFFF
- nodes.before = node.insert_before -- broken
- nodes.after = node.insert_after
+storage.register("attributes/names", attributes.names, "attributes.names")
+storage.register("attributes/numbers", attributes.numbers, "attributes.numbers")
+storage.register("attributes/list", attributes.list, "attributes.list")
- function nodes.before(h,c,n)
- if c then
- if c == h then
- n.next = h
- n.prev = nil
- h.prev = n
- else
- local cp = c.prev
- n.next = c
- n.prev = cp
- if cp then
- cp.next = n
- end
- c.prev = n
- return h, n
- end
- end
- return n, n
- end
+local names, numbers, list = attributes.names, attributes.numbers, attributes.list
- function nodes.after(h,c,n)
- if c then
- local cn = c.next
- if cn then
- n.next = cn
- cn.prev = n
- else
- n.next = nil
- end
- c.next = n
- n.prev = c
---~ if c ~= h then
- return h, n
---~ end
- end
- return n, n
+function attributes.define(name,number) -- at the tex end
+ if not numbers[name] then
+ numbers[name], names[number], list[number] = number, name, { }
end
-
- function nodes.show_list(head, message)
- if message then
- texio.write_nl(message)
- end
- for n in node.traverse(head) do
- texio.write_nl(tostring(n))
- end
- end
-
end
--- will move
+--[[ldx--
+<p>We can use the attributes in the range 127-255 (outside user space). These
+are only used when no attribute is set at the \TEX\ end which normally
+happens in <l n='context'/>.</p>
+--ldx]]--
-nodes.processors = { }
-nodes.processors.char = { }
-nodes.processors.char.proc = { }
+storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127
-function nodes.report(t,done)
- if nodes.trace then -- best also test this before calling
- if done then
- if status.output_active then
- texio.write(format("<++ %s>",nodes.count(t)))
- else
- texio.write(format("<+ %s>",nodes.count(t)))
- end
- else
- if status.output_active then
- texio.write(format("<-- %s>",nodes.count(t)))
- else
- texio.write(format("<- %s>",nodes.count(t)))
- end
+function attributes.private(name) -- at the lua end (hidden from user)
+ local number = numbers[name]
+ if not number then
+ local last = storage.shared.attributes_last_private or 127
+ if last < 255 then
+ last = last + 1
+ storage.shared.attributes_last_private = last
end
+ number = last
+ numbers[name], names[number], list[number] = number, name, { }
end
+ return number
end
-do
-
- local function count(stack,flat)
- local n = 0
- while stack do
- local id = stack.id
- if not flat and id == hlist or id == vlist then
- local list = stack.list
- if list then
- n = n + 1 + count(list) -- self counts too
- else
- n = n + 1
- end
- else
- n = n + 1
- end
- stack = stack.next
- end
- return n
- end
-
- nodes.count = count
-
-end
+--[[ldx--
+<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
+implement a few helper functions. These functions are rather optimized.</p>
+--ldx]]--
--[[ldx--
<p>When manipulating node lists in <l n='context'/>, we will remove
@@ -255,963 +98,136 @@ into the <l n='tex'/> engine, but this is a not so natural extension.</p>
also ignore the empty nodes. [This is obsolete!]</p>
--ldx]]--
+nodes = nodes or { }
---[[ldx--
-<p>Serializing nodes can be handy for tracing. Also, saving and
-loading node lists can come in handy as soon we are going to
-use external applications to process node lists.</p>
---ldx]]--
-
-function nodes.show(stack)
---~ texio.write_nl(table.serialize(stack))
-end
-
-function nodes.save(stack,name) -- *.ltn : luatex node file
---~ if name then
---~ file.savedata(name,table.serialize(stack))
---~ else
---~ texio.write_nl('log',table.serialize(stack))
---~ end
-end
-
-function nodes.load(name)
---~ return file.loaddata(name)
-end
-
--- node-cap.lua
-
---~ nodes.capture = { } -- somehow fails
-
---~ function nodes.capture.start(cbk)
---~ local head, tail = nil, nil
---~ callbacks.push(cbk, function(t)
---~ if tail then
---~ tail.next = t
---~ else
---~ head, tail = t, t
---~ end
---~ while tail.next do
---~ tail = tail.next
---~ end
---~ return false
---~ end)
---~ function nodes.capture.stop()
---~ function nodes.capture.stop() end
---~ function nodes.capture.get()
---~ function nodes.capture.get() end
---~ return head
---~ end
---~ callbacks.pop(cbk)
---~ end
---~ function nodes.capture.get() end -- error
---~ end
-
---~ nodes.capture.stop = function() end
---~ nodes.capture.get = function() end
-
--- node-gly.lua
-
-fonts = fonts or { }
-fonts.otf = fonts.otf or { }
-fonts.tfm = fonts.tfm or { }
-fonts.tfm.id = fonts.tfm.id or { }
-
-local tfm = fonts.tfm
-local otf = fonts.otf
-local tfmid = fonts.tfm.id
-
-do
-
- local has_attribute = node.has_attribute
- local traverse_id = node.traverse_id
-
- local pairs = pairs
-
- local starttiming, stoptiming = input.starttiming, input.stoptiming
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+local kern = node.id('kern')
+local whatsit = node.id('whatsit')
- function nodes.process_characters(head)
- -- not ok yet; we need a generic blocker
- -- if status.output_active then
- if false then -- status.output_active then
- return head, false -- true
+local traverse_id = node.traverse_id
+local traverse = node.traverse
+local slide_nodes = node.slide
+local free_node = node.free
+local remove_node = node.remove
+
+function nodes.remove(head, current, free_too)
+ local t = current
+ head, current = remove_node(head,current)
+ if t then
+ if free_too then
+ free_node(t)
+ t = nil
else
- -- either next or not, but definitely no already processed list
- starttiming(nodes)
- local usedfonts, attrfonts, done = { }, { }, false
- -- todo: should be independent of otf
- local set_dynamics = otf.set_dynamics -- todo: font-var.lua so that we can global this one
- local a, u, prevfont, prevattr = 0, 0, nil, 0
- for n in traverse_id(glyph,head) do
- local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts, preset to 0 is faster (first match)
- if attr and attr > 0 then
- if font ~= prevfont or attr ~= prevattr then
- local used = attrfonts[font]
- if not used then
- used = { }
- attrfonts[font] = used
- end
- if not used[attr] then
- local d = set_dynamics(tfmid[font],attr) -- todo, script, language -> n.language also axis
- if d then
- used[attr] = d
- a = a + 1
- end
- end
- prevfont, prevattr = font, attr
- end
- elseif font ~= prevfont then
- prevfont, prevattr = font, 0
- local used = usedfonts[font]
- if not used then
- local data = tfmid[font]
- if data then
- local shared = data.shared -- we need to check shared, only when same features
- if shared then
- local processors = shared.processors
- if processors and #processors > 0 then
- usedfonts[font] = processors
- u = u + 1
- end
- end
- else
- -- probably nullfont
- end
- end
- else
- prevattr = attr
- end
- end
- -- we could combine these and just make the attribute nil
- if u > 0 then
- for font, processors in pairs(usedfonts) do
- local n = #processors
- if n == 1 then
- local h, d = processors[1](head,font,false)
- head, done = h or head, done or d
- else
- for i=1,#processors do
- local h, d = processors[i](head,font,false)
- head, done = h or head, done or d
- end
- end
- end
- end
- if a > 0 then -- we need to get rid of a loop here
- for font, dynamics in pairs(attrfonts) do
- for attribute, processors in pairs(dynamics) do -- attr can switch in between
- local n = #processors
- if n == 1 then
- local h, d = processors[1](head,font,attribute)
- head, done = h or head, done or d
- else
- for i=1,n do
- local h, d = processors[i](head,font,attribute)
- head, done = h or head, done or d
- end
- end
- end
- end
- end
- stoptiming(nodes)
- if nodes.trace then
- nodes.report(head,done)
- end
- return head, true
- end
- end
-
-end
-
--- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional
--- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional
-
-do
-
- local has_attribute, set, attribute = node.has_attribute, node.set_attribute, tex.attribute
-
- function nodes.inherit_attributes(n) -- still ok ?
- if n then
- local i = 1
- while true do
- local a = attribute[i]
- if a < 0 then
- break
- else
- local ai = has_attribute(n,i)
- if not ai then
- set(n,i,a)
- end
- i = i + 1
- end
- end
+ t.next, t.prev = nil, nil
end
- end
-
+ end
+ return head, current, t
end
-function nodes.length(head)
- if head then
- local m = 0
- for n in node.traverse(head) do
- m = m + 1
- end
- return m
- else
- return 0
- end
+function nodes.delete(head,current)
+ return nodes.remove(head,current,true)
end
-lists = lists or { }
-chars = chars or { }
-words = words or { } -- not used yet
-
-callbacks.trace = false
-
-do
+nodes.before = node.insert_before -- broken
+nodes.after = node.insert_after
- kernel = kernel or { }
+-- we need to test this, as it might be fixed
- local starttiming, stoptiming = input.starttiming, input.stoptiming
- local hyphenate, ligaturing, kerning = lang.hyphenate, node.ligaturing, node.kerning
-
- function kernel.hyphenation(head,tail) -- lang.hyphenate returns done
- if head == tail then
- return head, tail, false
- else
- starttiming(kernel)
- local done = head ~= tail and hyphenate(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
- end
- function kernel.ligaturing(head,tail) -- node.ligaturing returns head,tail,done
- if head == tail then
- return head, tail, false
+function nodes.before(h,c,n)
+ if c then
+ if c == h then
+ n.next = h
+ n.prev = nil
+ h.prev = n
else
- starttiming(kernel)
- local head, tail, done = ligaturing(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
- end
- function kernel.kerning(head,tail) -- node.kerning returns head,tail,done
- if head == tail then
- return head, tail, false
- else
- starttiming(kernel)
- local head, tail, done = kerning(head,tail)
- stoptiming(kernel)
- return head, tail, done
- end
- end
-
-end
-
-callback.register('hyphenate' , function(head,tail) return tail end)
-callback.register('ligaturing', function(head,tail) return tail end)
-callback.register('kerning' , function(head,tail) return tail end)
-
-nodes.tasks = nodes.tasks or { }
-nodes.tasks.data = nodes.tasks.data or { }
-
-function nodes.tasks.new(name,list)
- local tasklist = sequencer.reset()
- nodes.tasks.data[name] = { list = tasklist, runner = false }
- for _, task in ipairs(list) do
- sequencer.appendgroup(tasklist,task)
- end
-end
-
-function nodes.tasks.appendaction(name,group,action,where,kind)
- local data = nodes.tasks.data[name]
- sequencer.appendaction(data.list,group,action,where,kind)
- data.runner = false
-end
-
-function nodes.tasks.prependaction(name,group,action,where,kind)
- local data = nodes.tasks.data[name]
- sequencer.prependaction(data.list,group,action,where,kind)
- data.runner = false
-end
-
-function nodes.tasks.removeaction(name,group,action)
- local data = nodes.tasks.data[name]
- sequencer.removeaction(data.list,group,action)
- data.runner = false
-end
-
-function nodes.tasks.showactions(name,group,action,where,kind)
- local data = nodes.tasks.data[name]
- logs.report("nodes","task %s, list:\n%s",name,sequencer.nodeprocessor(data.list))
-end
-
-function nodes.tasks.actions(name)
- local data = nodes.tasks.data[name]
- return function(head,tail)
- local runner = data.runner
- if not runner then
- if nodes.trace_tasks then
- logs.report("nodes","creating task runner '%s'",name)
+ local cp = c.prev
+ n.next = c
+ n.prev = cp
+ if cp then
+ cp.next = n
end
- runner = sequencer.compile(data.list,sequencer.nodeprocessor)
- data.runner = runner
+ c.prev = n
+ return h, n
end
- return runner(head,tail)
end
+ return n, n
end
-nodes.tasks.new (
- "processors",
- {
- "before", -- for users
- "normalizers",
- "characters",
- "words",
- "fonts",
- "lists",
- "after", -- for users
- }
-)
-
--- these definitions will move
-
-nodes.tasks.appendaction("processors", "normalizers", "nodes.normalize_fonts", nil)
-nodes.tasks.appendaction("processors", "characters", "chars.handle_mirroring", nil, "notail")
-nodes.tasks.appendaction("processors", "characters", "chars.handle_casing", nil, "notail")
-nodes.tasks.appendaction("processors", "characters", "chars.handle_breakpoints", nil, "notail")
-nodes.tasks.appendaction("processors", "words", "kernel.hyphenation", nil)
-nodes.tasks.appendaction("processors", "words", "languages.words.check", nil, "notail")
-nodes.tasks.appendaction("processors", "fonts", "nodes.process_characters", nil, "notail")
-nodes.tasks.appendaction("processors", "fonts", "nodes.protect_glyphs", nil, "nohead")
-nodes.tasks.appendaction("processors", "fonts", "kernel.ligaturing", nil)
-nodes.tasks.appendaction("processors", "fonts", "kernel.kerning", nil)
-nodes.tasks.appendaction("processors", "lists", "lists.handle_spacing", nil, "notail")
-nodes.tasks.appendaction("processors", "lists", "lists.handle_kerning", nil, "notail")
-
-
-local free = node.free
-
-local function cleanup_page(head) -- rough
- local prev, start = nil, head
- while start do
- local id, nx = start.id, start.next
- if id == disc or id == mark then
- if prev then
- prev.next = nx
- end
- if start == head then
- head = nx
- end
- local tmp = start
- start = nx
- free(tmp)
- elseif id == hlist or id == vlist then
- local sl = start.list
- if sl then
- start.list = cleanup_page(sl)
- end
- prev, start = start, nx
+function nodes.after(h,c,n)
+ if c then
+ local cn = c.next
+ if cn then
+ n.next = cn
+ cn.prev = n
else
- prev, start = start, nx
+ n.next = nil
end
+ c.next = n
+ n.prev = c
+ return h, n
end
- return head
-end
-
-nodes.cleanup_page_first = false
-
-function nodes.cleanup_page(head)
- if nodes.cleanup_page_first then
- head = cleanup_page(head)
- end
- return head, false
-end
-
-nodes.tasks.new (
- "shipouts",
- {
- "before", -- for users
- "normalizers",
- "finishers",
- "after", -- for users
- }
-)
-
-nodes.tasks.appendaction("shipouts", "normalizers", "nodes.cleanup_page", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_color", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_transparency", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_overprint", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_negative", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_effect", nil, "notail")
-nodes.tasks.appendaction("shipouts", "finishers", "shipouts.handle_viewerlayer", nil, "notail")
-
-local actions = nodes.tasks.actions("shipouts")
-
-function nodes.process_page(head) -- problem, attr loaded before node, todo ...
- return actions(head) -- no tail
+ return n, n
end
--- or just: nodes.process_page = nodes.tasks.actions("shipouts")
-
-
-do -- remove these
-
- local actions = nodes.tasks.actions("processors")
- local first_character = node.first_character
- local slide = node.slide
-
- local n = 0
-
- local function reconstruct(head)
- local t = { }
- local h = head
- while h do
- local id = h.id
- if id == glyph then
- t[#t+1] = utf.char(h.char)
- else
- t[#t+1] = "[]"
- end
- h = h.next
- end
- return table.concat(t)
- end
-
- local function tracer(what,state,head,groupcode,before,after,show)
- if not groupcode then
- groupcode = "unknown"
- elseif groupcode == "" then
- groupcode = "mvl"
- end
- n = n + 1
- if show then
- texio.write_nl(format("%s %s: %s, group: %s, nodes: %s -> %s, string: %s",what,n,state,groupcode,before,after,reconstruct(head)))
+function nodes.replace(head,current,new)
+ if current and next then
+ local p, n = current.prev, current.next
+ new.prev, new.next = p, n
+ if p then
+ p.next = new
else
- texio.write_nl(format("%s %s: %s, group: %s, nodes: %s -> %s",what,n,state,groupcode,before,after))
- end
- end
-
- function nodes.processors.pre_linebreak_filter(head,groupcode) -- todo: tail
- local first, found = first_character(head)
- if found then
- if callbacks.trace then
- local before = nodes.count(head,true)
- local head, tail, done = actions(head,slide(head))
- local after = nodes.count(head,true)
- if done then
- tracer("pre_linebreak","changed",head,groupcode,before,after,true)
- else
- tracer("pre_linebreak","unchanged",head,groupcode,before,after,true)
- end
- return (done and head) or true
- else
- local head, tail, done = actions(head,slide(head))
- return (done and head) or true
- end
- else
- if callbacks.trace then
- local n = nodes.count(head,false)
- tracer("pre_linebreak","no chars",head,groupcode,n,n)
- end
- return true
- end
- end
-
- function nodes.processors.hpack_filter(head,groupcode) -- todo: tail
- local first, found = first_character(head)
- if found then
- if callbacks.trace then
- local before = nodes.count(head,true)
- local head, tail, done = actions(head,slide(head))
- local after = nodes.count(head,true)
- if done then
- tracer("hpack","changed",head,groupcode,before,after,true)
- else
- tracer("hpack","unchanged",head,groupcode,before,after,true)
- end
- return (done and head) or true
- else
- local head, tail, done = actions(head,slide(head))
- return (done and head) or true
- end
- end
- if callbacks.trace then
- local n = nodes.count(head,false)
- tracer("hpack","no chars",head,groupcode,n,n)
- end
- return true
- end
-
-end
-
-callback.register('pre_linebreak_filter', nodes.processors.pre_linebreak_filter)
-callback.register('hpack_filter' , nodes.processors.hpack_filter)
-
-do
-
- -- beware, some field names will change in a next release of luatex
-
- local expand = table.tohash {
- "list", -- list_ptr & ins_ptr & adjust_ptr
- "pre", --
- "post", --
- "spec", -- glue_ptr
- "top_skip", --
- "attr", --
- "replace", -- nobreak
- "components", -- lig_ptr
- "box_left", --
- "box_right", --
- "glyph", -- margin_char
- "leader", -- leader_ptr
- "action", -- action_ptr
- "value", -- user_defined nodes with subtype 'a' en 'n'
- }
-
- -- page_insert: "height", "last_ins_ptr", "best_ins_ptr"
- -- split_insert: "height", "last_ins_ptr", "best_ins_ptr", "broken_ptr", "broken_ins"
-
- local ignore = table.tohash {
- "page_insert",
- "split_insert",
- "ref_count",
- }
-
- local dimension = table.tohash {
- "width", "height", "depth", "shift",
- "stretch", "shrink",
- "xoffset", "yoffset",
- "surround",
- "kern",
- "box_left_width", "box_right_width"
- }
-
- -- flat: don't use next, but indexes
- -- verbose: also add type
- -- can be sped up
-
- nodes.dimensionfields = dimension
- nodes.listablefields = expand
- nodes.ignorablefields = ignore
-
- -- not ok yet:
-
- function nodes.astable(n,sparse) -- not yet ok
- local f, t = node.fields(n.id,n.subtype), { }
- for i=1,#f do
- local v = f[i]
- local d = n[v]
- if d then
- if ignore[v] or v == "id" then
- -- skip
- elseif expand[v] then -- or: type(n[v]) ~= "string" or type(n[v]) ~= "number" or type(n[v]) ~= "table"
- t[v] = "pointer to list"
- elseif sparse then
- if (type(d) == "number" and d ~= 0) or (type(d) == "string" and d ~= "") then
- t[v] = d
- end
- else
- t[v] = d
- end
- end
- end
- t.type = node.type(n.id)
- return t
- end
-
- local nodefields = node.fields
- local nodetype = node.type
-
- -- under construction:
-
- local function totable(n,flat,verbose)
- local function to_table(n)
- local f = nodefields(n.id,n.subtype)
- local tt = { }
- for k=1,#f do
- local v = f[k]
- local nv = n[v]
- if nv then
- if ignore[v] then
- -- skip
- elseif expand[v] then
- if type(nv) == "number" or type(nv) == "string" then
- tt[v] = nv
- else
- tt[v] = totable(nv,flat,verbose)
- end
- elseif type(nv) == "table" then
- tt[v] = nv -- totable(nv,flat,verbose) -- data
- else
- tt[v] = nv
- end
- end
- end
- if verbose then
- tt.type = nodetype(tt.id)
- end
- return tt
+ head = new
end
if n then
- if flat then
- local t = { }
- while n do
- t[#t+1] = to_table(n)
- n = n.next
- end
- return t
- else
- local t = to_table(n)
- if n.next then
- t.next = totable(n.next,flat,verbose)
- end
- return t
- end
- else
- return { }
+ n.prev = new
end
+ free_node(current)
end
+ return head, current
+end
- nodes.totable = totable
-
- local function key(k)
- return ((type(k) == "number") and "["..k.."]") or k
- end
-
- -- not ok yet; this will become a module
+-- will move
- local function serialize(root,name,handle,depth,m)
- handle = handle or print
- if depth then
- depth = depth .. " "
- handle(("%s%s={"):format(depth,key(name)))
- else
- depth = ""
- local tname = type(name)
- if tname == "string" then
- if name == "return" then
- handle("return {")
- else
- handle(name .. "={")
- end
- elseif tname == "number"then
- handle("[" .. name .. "]={")
- else
- handle("t={")
- end
- end
- if root then
- local fld
- if root.id then
- fld = nodefields(root.id,root.subtype) -- we can cache these (todo)
+local function count(stack,flat)
+ local n = 0
+ while stack do
+ local id = stack.id
+ if not flat and id == hlist or id == vlist then
+ local list = stack.list
+ if list then
+ n = n + 1 + count(list) -- self counts too
else
- fld = table.sortedkeys(root)
- end
- if type(root) == 'table' and root['type'] then -- userdata or table
- handle(("%s %s=%q,"):format(depth,'type',root['type']))
- end
- for _,k in ipairs(fld) do
- if k == "ref_count" then
- -- skip
- elseif k then
- local v = root[k]
- local t = type(v)
- if t == "number" then
- if v == 0 then
- -- skip
- else
- handle(("%s %s=%s,"):format(depth,key(k),v))
- end
- elseif t == "string" then
- if v == "" then
- -- skip
- else
- handle(("%s %s=%q,"):format(depth,key(k),v))
- end
- elseif v then -- userdata or table
- serialize(v,k,handle,depth,m+1)
- end
- end
- end
- if root['next'] then -- userdata or table
- serialize(root['next'],'next',handle,depth,m+1)
+ n = n + 1
end
- end
- if m and m > 0 then
- handle(("%s},"):format(depth))
else
- handle(("%s}"):format(depth))
+ n = n + 1
end
+ stack = stack.next
end
-
- function nodes.serialize(root,name)
- local t = { }
- local function flush(s)
- t[#t+1] = s
- end
- serialize(root, name, flush, nil, 0)
- return table.concat(t,"\n")
- end
-
- function nodes.serializebox(n,flat,verbose)
- return nodes.serialize(nodes.totable(tex.box[n],flat,verbose))
- -- return nodes.serialize(tex.box[n])
- end
-
- function nodes.visualizebox(...)
- -- tex.sprint(tex.ctxcatcodes,"\\starttyping\n" .. nodes.serializebox(...) .. "\n\\stoptyping\n")
- tex.print(tex.ctxcatcodes,"\\starttyping")
- tex.print(nodes.serializebox(...))
- tex.print("\\stoptyping")
- end
-
- function nodes.list(head,n) -- name might change to nodes.type
- if not n then
- tex.print(tex.ctxcatcodes,"\\starttyping")
- end
- while head do
- local id = head.id
- tex.print(string.rep(" ",n or 0) .. tostring(head) .. "\n")
- if id == hlist or id == vlist then
- nodes.list(head.list,(n or 0)+1)
- end
- head = head.next
- end
- if not n then
- tex.print("\\stoptyping")
- end
- end
-
- function nodes.print(head,n)
- while head do
- local id = head.id
- texio.write_nl(string.rep(" ",n or 0) .. tostring(head))
- if id == hlist or id == vlist then
- nodes.print(head.list,(n or 0)+1)
- end
- head = head.next
- end
- end
-
- function nodes.check_for_leaks(sparse)
- local l = { }
- local q = node.usedlist()
- for p in node.traverse(q) do
- local s = table.serialize(nodes.astable(p,sparse),node.type(p.id))
- l[s] = (l[s] or 0) + 1
- end
- node.flush_list(q)
- for k, v in pairs(l) do
- texio.write_nl(format("%s * %s", v, k))
- end
- end
-
-end
-
-if not node.list_has_attribute then -- no longer needed
-
- function node.list_has_attribute(list,attribute)
- if list and attribute then
- for n in node.traverse(list) do
- local a = has_attribute(n,attribute)
- if a then return a end
- end
- end
- return false
- end
-
+ return n
end
-function nodes.pack_list(head)
- local t = { }
- for n in node.traverse(head) do
- t[#t+1] = tostring(n)
- end
- return t
-end
+nodes.count = count
-do
+-- new
- function nodes.leftskip(n)
- while n do
- local id = n.id
- if id == glue then
- if n.subtype == 8 then -- 7 in c/web source
- return (n.spec and n.spec.width) or 0
- else
- return 0
- end
- elseif id == whatsit then
- n = n.next
- elseif id == hlist then
- return n.width
- else
- break
- end
- end
- return 0
- end
- function nodes.rightskip(n)
- if n then
- n = node.slide(n)
- while n do
- local id = n.id
- if id == glue then
- if n.subtype == 9 then -- 8 in the c/web source
- return (n.spec and n.spec.width) or 0
- else
- return 0
- end
- elseif id == whatsit then
- n = n.prev
- else
- break
- end
- end
+function attributes.ofnode(n)
+ local a = n.attr
+ if a then
+ local names = attributes.names
+ a = a.next
+ while a do
+ local number, value = a.number, a.value
+ texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?'))
+ a = a.next
end
- return false
- end
-
+ end
end
--- goodie
---
--- if node.valid(tex.box[0]) then print("valid node") end
-
---~ do
---~ local n = node.new(0,0)
---~ local m = getmetatable(n)
---~ m.__metatable = 'node'
---~ node.free(n)
-
---~ function node.valid(n)
---~ return n and getmetatable(n) == 'node'
---~ end
---~ end
+local left, space = lpeg.P("<"), lpeg.P(" ")
--- for the moment we put this here:
-
-do
-
- nodes.tracers = { }
- nodes.tracers.characters = { }
-
- local function collect(head,list,tag,n)
- n = n or 0
- local ok, fn = false, nil
- while head do
- local id = head.id
- if id == glyph then
- local f = head.font
- if f ~= fn then
- ok, fn = false, f
- end
- local c = head.char
- local d = tfmid[f].descriptions[c]
- local i = (d and d.index) or -1
- if not ok then
- ok = true
- n = n + 1
- list[n] = list[n] or { }
- list[n][tag] = { }
- end
- local l = list[n][tag]
- l[#l+1] = { c, f, i }
- elseif id == disc then
- -- skip
- else
- ok = false
- end
- head = head.next
- end
- end
-
- function nodes.tracers.characters.equal(ta, tb)
- if #ta ~= #tb then
- return false
- else
- for i=1,#ta do
- local a, b = ta[i], tb[i]
- if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then
- return false
- end
- end
- end
- return true
- end
- function nodes.tracers.characters.string(t)
- local tt = { }
- for i=1,#t do
- tt[i] = utf.char(t[i][1])
- end
- return table.concat(tt,"")
- end
- function nodes.tracers.characters.unicodes(t,decimal)
- local tt = { }
- for i=1,#t do
- if decimal then
- tt[i] = t[i][1]
- else
- tt[i] = format("%04X",t[i][1])
- end
- end
- return table.concat(tt," ")
- end
- function nodes.tracers.characters.indices(t,decimal)
- local tt = { }
- for i=1,#t do
- if decimal then
- tt[i] = t[i][3]
- else
- tt[i] = format("%04X",t[i][3])
- end
- end
- return table.concat(tt," ")
- end
- function nodes.tracers.characters.fonts(t)
- local f = t[1] and t[1][2]
- return (f and file.basename(tfmid[f].filename or "unknown")) or "unknown"
- end
-
- function nodes.tracers.characters.start()
- local npc = nodes.process_characters
- local list = { }
- function nodes.process_characters(head)
- local n = #list
- collect(head,list,'before',n)
- local h, d = npc(head)
- collect(head,list,'after',n)
- if #list > n then
- list[#list+1] = { }
- end
- return h, d
- end
- function nodes.tracers.characters.stop()
- tracers.list['characters'] = list
- lmx.set('title', 'ConTeXt Character Processing Information')
- lmx.set('color-background-one', lmx.get('color-background-yellow'))
- lmx.set('color-background-two', lmx.get('color-background-purple'))
- lmx.show('context-characters.lmx')
- lmx.restore()
- nodes.process_characters = npc
- end
- end
-
- local stack = { }
-
- function nodes.tracers.start(tag)
- stack[#stack+1] = tag
- local tracer = nodes.tracers[tag]
- if tracer and tracer.start then
- tracer.start()
- end
- end
- function nodes.tracers.stop()
- local tracer = stack[#stack]
- if tracer and tracer.stop then
- tracer.stop()
- end
- stack[#stack] = nil
- end
-
-end
+nodes.filterkey = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0)
diff --git a/tex/context/base/node-ini.tex b/tex/context/base/node-ini.tex
index c033a1f7b..210f21229 100644
--- a/tex/context/base/node-ini.tex
+++ b/tex/context/base/node-ini.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=node-ini,
%D version=2006.08.20,
-%D title=\CONTEXT\ Character Macros,
-%D subtitle=Node Support (Initialization),
+%D title=\CONTEXT\ Node Macros,
+%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,10 +11,59 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Node Support (initialization)}
+\writestatus{loading}{ConTeXt Node Support / Initialization}
+
+\unprotect
+
+\newcount\filterstate \filterstate\plusone
-\registerctxluafile{node-seq}{1.001}
\registerctxluafile{node-ini}{1.001}
+\registerctxluafile{node-tst}{1.001}
+\registerctxluafile{node-tra}{1.001} % we might split it off (module)
+\registerctxluafile{node-seq}{1.001} % we might generalize this one
+\registerctxluafile{node-tsk}{1.001}
+\registerctxluafile{node-tex}{1.001}
+\registerctxluafile{node-res}{1.001}
+\registerctxluafile{node-pro}{1.001}
+\registerctxluafile{node-shp}{1.001}
+\registerctxluafile{node-ser}{1.001}
+\registerctxluafile{node-ext}{1.001}
+\registerctxluafile{node-inj}{1.001} % we might split it off
+
+\newtoks \attributesresetlist
+
+\ifdefined \v!global \else \def\v!global{global} \fi % for metatex
+
+\def\defineattribute
+ {\dodoubleempty\dodefineattribute}
+
+\def\dodefineattribute[#1][#2]% alternatively we can let lua do the housekeeping
+ {\expandafter\newattribute\csname @attr@#1\endcsname
+ \expandafter \xdef\csname :attr:#1\endcsname{\number\lastallocatedattribute}%
+ \ctxlua{attributes.define("#1",\number\lastallocatedattribute)}%
+ %\writestatus\m!systems{defining attribute #1 with number \number\lastallocatedattribute}%
+ \doifnotinset\v!global{#2}{\appendetoks\csname @attr@#1\endcsname\attributeunsetvalue\to\attributesresetlist}}
+
+\def\definesystemattribute
+ {\dodoubleempty\dodefinesystemattribute}
+
+\def\dodefinesystemattribute[#1][#2]% alternatively we can let lua do the housekeeping
+ {\scratchcounter\ctxlua{tex.print(attributes.private("#1"))}\relax
+ \global\expandafter\attributedef\csname @attr@#1\endcsname\scratchcounter
+ \expandafter \xdef\csname :attr:#1\endcsname{\number\scratchcounter}%
+ %\writestatus\m!systems{defining system attribute #1 with number \number\scratchcounter}%
+ \doifnotinset\v!global{#2}{\appendetoks\csname @attr@#1\endcsname\attributeunsetvalue\to\attributesresetlist}}
+
+% expandable so we can \edef them for speed
+
+\def\dosetattribute#1#2{\csname @attr@#1\endcsname#2\relax}
+\def\doresetattribute#1{\csname @attr@#1\endcsname\attributeunsetvalue}
+\def\dogetattribute #1{\number\csname @attr@#1\endcsname}
+\def\dogetattributeid#1{\csname :attr:#1\endcsname}
+
+\let\dompattribute\gobbletwoarguments
+
+\def\resetallattributes{\the\attributesresetlist}
% \appendtoks
% \ctxlua {
@@ -54,4 +103,4 @@
% \stoptracingnodes
% \stoptext
-\endinput
+\protect \endinput
diff --git a/tex/context/base/node-inj.lua b/tex/context/base/node-inj.lua
new file mode 100644
index 000000000..6ba21b39d
--- /dev/null
+++ b/tex/context/base/node-inj.lua
@@ -0,0 +1,608 @@
+if not modules then modules = { } end modules ['node-inj'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- tricky ... fonts.ids is not yet defined .. to be solved (maybe general tex ini)
+
+-- This is very experimental (this will change when we have luatex > .50 and
+-- a few pending thingies are available. Also, Idris needs to make a few more
+-- test fonts.
+
+local next = next
+
+local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local fontdata = fonts.ids
+
+local glyph = node.id('glyph')
+local kern = node.id('kern')
+
+local traverse_id = node.traverse_id
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+
+local newkern = nodes.kern
+
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local cursives = { }
+local marks = { }
+local kerns = { }
+
+-- currently we do gpos/kern in a bit inofficial way but when we
+-- have the extra fields in glyphnodes to manipulate ht/dp/wd
+-- explicitly i will provide an alternative; also, we can share
+-- tables
+
+function nodes.set_cursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+ local ws, wn = tfmstart.width, tfmnext.width
+ local bound = #cursives + 1
+ set_attribute(start,cursbase,bound)
+ set_attribute(nxt,curscurs,bound)
+ cursives[bound] = { rlmode, dx, dy, ws, wn }
+ return dx, dy, bound
+end
+
+function nodes.set_pair(current,factor,rlmode,spec,tfmchr)
+ local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
+ -- dy = y - h
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
+ local bound = has_attribute(current,kernpair)
+ if bound then
+ local kb = kerns[bound]
+ kb[2], kb[3], kb[4], kb[5] = kb[2] + x, kb[3] + y, kb[4] + w, kb[5] + h
+ else
+ bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, x, y, w, h }
+ end
+ return x, y, w, h, bound
+ end
+ return x, y, w, h -- no bound
+end
+
+function nodes.set_kern(current,factor,rlmode,x,tfmchr)
+ local dx = factor*x
+ if dx ~= 0 then
+ local bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, dx }
+ end
+ return dx, bound
+end
+
+function nodes.set_mark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
+ local bound = has_attribute(base,markbase)
+ if bound then
+ local mb = marks[bound]
+ if mb then
+ if not index then index = #mb + 1 end
+ mb[index] = { dx, dy }
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ return dx, dy, bound
+ else
+ logs.report("nodes mark", "possible problem, U+%04X is base without data (id: %s)",base.char,bound)
+ end
+ end
+ index = index or 1
+ bound = #marks + 1
+ set_attribute(base,markbase,bound)
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ marks[bound] = { [index] = { dx, dy } }
+ return dx, dy, bound
+end
+
+function nodes.trace_injection(head)
+ local function dir(n)
+ return (n<0 and "r-to-l") or (n>0 and "l-to-r") or ("unset")
+ end
+ local function report(...)
+ logs.report("nodes finisher",...)
+ end
+ report("begin run")
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ local kp = has_attribute(n,kernpair)
+ local mb = has_attribute(n,markbase)
+ local mm = has_attribute(n,markmark)
+ local md = has_attribute(n,markdone)
+ local cb = has_attribute(n,cursbase)
+ local cc = has_attribute(n,curscurs)
+ report("char U+%05X, font=%s",n.char,n.font)
+ if kp then
+ local k = kerns[kp]
+ if k[3] then
+ report(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2],k[3],k[4],k[5])
+ else
+ report(" kern: dir=%s, dx=%s",dir(k[1]),k[2])
+ end
+ end
+ if mb then
+ report(" markbase: bound=%s",mb)
+ end
+ if mm then
+ local m = marks[mm]
+ if mb then
+ local m = m[mb]
+ if m then
+ report(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,j,m[1],m[2])
+ else
+ report(" markmark: bound=%s, missing index",mm)
+ end
+ else
+ m = m[1]
+ report(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1],m[2])
+ end
+ end
+ if cb then
+ report(" cursbase: bound=%s",cb)
+ end
+ if cc then
+ local c = cursives[cc]
+ report(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2],c[3])
+ end
+ end
+ end
+ report("end run")
+end
+
+-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
+
+function nodes.inject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, rl, valid, cx, wx = false, { }, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ rl[n] = kk[1] -- could move in test
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+ cx[n] = dx
+ rl[n] = rlmode
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ -- local rlmode = d[3] -- not used
+ -- if rlmode and rlmode < 0 then
+ -- n.xoffset = p.xoffset + d[1]
+ -- else
+ n.xoffset = p.xoffset - d[1]
+ -- end
+ n.yoffset = p.yoffset + d[2]
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ if k ~= 0 then
+ local rln = rl[n]
+ if rln and rln < 0 then
+ insert_node_before(head,n,newkern(-k))
+ else
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end
+
+-- -- -- KEEP OLD ONE, THE NEXT IS JUST OPTIMIZED -- -- --
+
+function nodes.XXXXXXXxinject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, valid, cx, wx = false, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+if rlmode < 0 then
+ cx[n] = -dx
+else
+ cx[n] = dx
+end
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ local d1, d2 = d[1], d[2]
+ if d1 ~= 0 then
+ n.xoffset = p.xoffset - d[1]
+ end
+ if d2 ~= 0 then
+ n.yoffset = p.yoffset + d[2]
+ end
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end
diff --git a/tex/context/base/node-par.lua b/tex/context/base/node-par.lua
index 7dd95ea5d..f275a1035 100644
--- a/tex/context/base/node-par.lua
+++ b/tex/context/base/node-par.lua
@@ -11,7 +11,7 @@ parbuilders.constructors = parbuilders.constructors or { }
parbuilders.names = parbuilders.names or { }
parbuilders.attribute = attributes.numbers['parbuilder'] or 999
-input.storage.register(false, "parbuilders.names", parbuilders.names, "parbuilders.names")
+storage.register("parbuilders.names", parbuilders.names, "parbuilders.names")
-- store parbuilders.names
diff --git a/tex/context/base/node-par.tex b/tex/context/base/node-par.tex
index 2e628c066..7f7ca9977 100644
--- a/tex/context/base/node-par.tex
+++ b/tex/context/base/node-par.tex
@@ -1,5 +1,5 @@
%D \module
-%D [ file=core-spa,
+%D [ file=node-par,
%D version=2008.09.30,
%D title=\CONTEXT\ Node Macros,
%D subtitle=Paragraph Building,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Paragraph Building}
+\writestatus{loading}{ConTeXt Node Macros / Paragraph Building}
%D This is very experimental, undocumented, subjected to changes, etc. just as
%D the underlying interfaces.
@@ -30,7 +30,7 @@
\registerctxluafile{node-par}{1.001}
-\defineattribute[parbuilder]
+\definesystemattribute[parbuilder]
\newcount\nofparbuilders
diff --git a/tex/context/base/node-pro.lua b/tex/context/base/node-pro.lua
new file mode 100644
index 000000000..575941fe5
--- /dev/null
+++ b/tex/context/base/node-pro.lua
@@ -0,0 +1,155 @@
+if not modules then modules = { } end modules ['node-pro'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+local format, concat = string.format, table.concat
+
+local trace_callbacks = false trackers.register("nodes.callbacks", function(v) trace_callbacks = v end)
+
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+local glyph = node.id('glyph')
+local disc = node.id('disc')
+local mark = node.id('mark')
+
+local slide_nodes = node.slide
+local free_node = node.free
+local first_character = node.first_character
+
+nodes.processors = nodes.processors or { }
+
+-- vbox: grouptype: vbox vtop output split_off split_keep | box_type: exactly|aditional
+-- hbox: grouptype: hbox adjusted_hbox(=hbox_in_vmode) | box_type: exactly|aditional
+
+lists = lists or { }
+chars = chars or { }
+words = words or { } -- not used yet
+
+-- or just:
+--
+-- nodes.process_page = tasks.actions("shipouts")
+
+local actions = tasks.actions("processors")
+
+local n = 0
+
+local function reconstruct(head)
+ local t = { }
+ local h = head
+ while h do
+ local id = h.id
+ if id == glyph then
+ t[#t+1] = utf.char(h.char)
+ else
+ t[#t+1] = "[]"
+ end
+ h = h.next
+ end
+ return concat(t)
+end
+
+local function tracer(what,state,head,groupcode,before,after,show)
+ if not groupcode then
+ groupcode = "unknown"
+ elseif groupcode == "" then
+ groupcode = "mvl"
+ end
+ n = n + 1
+ if show then
+ texio.write_nl(format("%s %s: %s, group: %s, nodes: %s -> %s, string: %s",what,n,state,groupcode,before,after,reconstruct(head)))
+ else
+ texio.write_nl(format("%s %s: %s, group: %s, nodes: %s -> %s",what,n,state,groupcode,before,after))
+ end
+end
+
+nodes.processors.enabled = true -- thsi will become a proper state (like trackers)
+
+function nodes.processors.pre_linebreak_filter(head,groupcode) -- todo: tail
+ local first, found = first_character(head)
+ if found then
+ if trace_callbacks then
+ local before = nodes.count(head,true)
+ local head, tail, done = actions(head,slide_nodes(head))
+ local after = nodes.count(head,true)
+ if done then
+ tracer("pre_linebreak","changed",head,groupcode,before,after,true)
+ else
+ tracer("pre_linebreak","unchanged",head,groupcode,before,after,true)
+ end
+ return (done and head) or true
+ else
+ local head, tail, done = actions(head,slide_nodes(head))
+ return (done and head) or true
+ end
+ elseif trace_callbacks then
+ local n = nodes.count(head,false)
+ tracer("pre_linebreak","no chars",head,groupcode,n,n)
+ end
+ return true
+end
+
+function nodes.processors.hpack_filter(head,groupcode) -- todo: tail
+ local first, found = first_character(head)
+ if found then
+ if trace_callbacks then
+ local before = nodes.count(head,true)
+ local head, tail, done = actions(head,slide_nodes(head))
+ local after = nodes.count(head,true)
+ if done then
+ tracer("hpack","changed",head,groupcode,before,after,true)
+ else
+ tracer("hpack","unchanged",head,groupcode,before,after,true)
+ end
+ return (done and head) or true
+ else
+ local head, tail, done = actions(head,slide_nodes(head))
+ return (done and head) or true
+ end
+ elseif trace_callbacks then
+ local n = nodes.count(head,false)
+ tracer("hpack","no chars",head,groupcode,n,n)
+ end
+ return true
+end
+
+callback.register('pre_linebreak_filter', nodes.processors.pre_linebreak_filter)
+callback.register('hpack_filter' , nodes.processors.hpack_filter)
+
+local actions = tasks.actions("finalizers")
+
+function nodes.processors.post_linebreak_filter(head,groupcode) -- todo: tail
+ local first, found = first_character(head)
+ if found then
+ if trace_callbacks then
+ local before = nodes.count(head,true)
+ local head, tail, done = actions(head,slide_nodes(head))
+ local after = nodes.count(head,true)
+ if done then
+ tracer("finalizer","changed",head,groupcode,before,after,true)
+ else
+ tracer("finalizer","unchanged",head,groupcode,before,after,true)
+ end
+ return (done and head) or true
+ else
+ local head, tail, done = actions(head,slide_nodes(head))
+ return (done and head) or true
+ end
+ elseif trace_callbacks then
+ local n = nodes.count(head,false)
+ tracer("finalizer","no chars",head,groupcode,n,n)
+ end
+ return true
+end
+
+callback.register('post_linebreak_filter', nodes.processors.post_linebreak_filter)
+
+statistics.register("h-node processing time", function()
+ if statistics.elapsedindeed(nodes) then
+ return format("%s seconds including kernel", statistics.elapsedtime(nodes))
+ end
+end)
diff --git a/tex/context/base/node-res.lua b/tex/context/base/node-res.lua
new file mode 100644
index 000000000..c8d815be4
--- /dev/null
+++ b/tex/context/base/node-res.lua
@@ -0,0 +1,110 @@
+if not modules then modules = { } end modules ['node-res'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local gmatch, format = string.gmatch, string.format
+local copy_node, free_node, new_node = node.copy, node.free, node.new
+
+--[[ldx--
+<p>The next function is not that much needed but in <l n='context'/> we use
+for debugging <l n='luatex'/> node management.</p>
+--ldx]]--
+
+nodes = nodes or { }
+
+local reserved = { }
+
+function nodes.register(n)
+ reserved[#reserved+1] = n
+ return n
+end
+
+function nodes.cleanup_reserved(nofboxes) -- todo
+ nodes.tracers.steppers.reset() -- todo: make a registration subsystem
+ local nr, nl = #reserved, 0
+ for i=1,nr do
+ free_node(reserved[i])
+ end
+ if nofboxes then
+ local tb = tex.box
+ for i=0,nofboxes do
+ local l = tb[i]
+ if l then
+ free_node(tb[i])
+ nl = nl + 1
+ end
+ end
+ end
+ reserved = { }
+ return nr, nl, nofboxes -- can be nil
+end
+
+function nodes.usage()
+ local t = { }
+ for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
+ t[tag] = n
+ end
+ return t
+end
+
+local pdfliteral = nodes.register(new_node("whatsit",8)) pdfliteral.mode = 1
+local disc = nodes.register(new_node("disc"))
+local kern = nodes.register(new_node("kern",1))
+local penalty = nodes.register(new_node("penalty"))
+local glue = nodes.register(new_node("glue"))
+local glue_spec = nodes.register(new_node("glue_spec"))
+local glyph = nodes.register(new_node("glyph",0))
+local textdir = nodes.register(new_node("whatsit",7))
+
+function nodes.glyph(fnt,chr)
+ local n = copy_node(glyph)
+ if fnt then n.font = fnt end
+ if chr then n.char = chr end
+ return n
+end
+function nodes.penalty(p)
+ local n = copy_node(penalty)
+ n.penalty = p
+ return n
+end
+function nodes.kern(k)
+ local n = copy_node(kern)
+ n.kern = k
+ return n
+end
+function nodes.glue(width,stretch,shrink)
+ local n, s = copy_node(glue), copy_node(glue_spec)
+ s.width, s.stretch, s.shrink = width, stretch, shrink
+ n.spec = s
+ return n
+end
+function nodes.glue_spec(width,stretch,shrink)
+ local s = copy_node(glue_spec)
+ s.width, s.stretch, s.shrink = width, stretch, shrink
+ return s
+end
+function nodes.disc()
+ return copy_node(disc)
+end
+function nodes.pdfliteral(str)
+ local t = copy_node(pdfliteral)
+ t.data = str
+ return t
+end
+function nodes.textdir(dir)
+ local t = copy_node(textdir)
+ t.dir = dir
+ return t
+end
+
+statistics.register("cleaned up reserved nodes", function()
+ return format("%s nodes, %s lists of %s", nodes.cleanup_reserved(tex.count["lastallocatedbox"]))
+end) -- \topofboxstack
+
+statistics.register("node memory usage", function() -- comes after cleanup !
+ return status.node_mem_usage
+end)
diff --git a/tex/context/base/node-seq.lua b/tex/context/base/node-seq.lua
index 2fd4f81aa..2794c34b9 100644
--- a/tex/context/base/node-seq.lua
+++ b/tex/context/base/node-seq.lua
@@ -6,12 +6,28 @@ if not modules then modules = { } end modules ['node-seq'] = {
license = "see context related readme files"
}
--- we assume namespace usage, i.e. unique names for functions
+--[[ldx--
+<p>Here we implement a mechanism for chaining the special functions
+that we use in <l n="context"> to deal with mode list processing. We
+assume that namespaces for the functions are used, but for speed we
+use locals to refer to them when compiling the chain.</p>
+--ldx]]--
-local format, concat = string.format, table.concat
+local format, gsub, concat, gmatch = string.format, string.gsub, table.concat, string.gmatch
sequencer = sequencer or { }
+local function validaction(action)
+ local g = _G
+ for str in gmatch(action,"[^%.]+") do
+ g = g[str]
+ if not g then
+ return false
+ end
+ end
+ return true
+end
+
function sequencer.reset()
return {
list = { },
@@ -34,18 +50,18 @@ function sequencer.appendgroup(t,group,where)
list[group] = { }
end
-function sequencer.prependaction(t,group,action,where,kind)
+function sequencer.prependaction(t,group,action,where,kind,force)
local g = t.list[group]
- if g then
+ if g and (force or validaction(action)) then
table.remove_value(g,action)
table.insert_before_value(g,where,action)
t.kind[action] = kind
end
end
-function sequencer.appendaction(t,group,action,where,kind)
+function sequencer.appendaction(t,group,action,where,kind,force)
local g = t.list[group]
- if g then
+ if g and (force or validaction(action)) then
table.remove_value(g,action)
table.insert_after_value(g,where,action)
t.kind[action] = kind
@@ -56,9 +72,9 @@ function sequencer.setkind(t,action,kind)
t.kind[action] = kind
end
-function sequencer.removeaction(t,group,action)
+function sequencer.removeaction(t,group,action,force)
local g = t.list[group]
- if g then
+ if g and (force or validaction(action)) then
table.remove_value(g,action)
end
end
@@ -75,7 +91,7 @@ function sequencer.compile(t,compiler)
end
local function localize(str)
- return str:gsub("%.","_")
+ return (gsub(str,"%.","_"))
end
local template = [[
@@ -96,12 +112,12 @@ function sequencer.tostring(t)
calls[#calls+1] = format(" %s(...) -- %s %i", localized, group, i)
end
end
- return template:format(concat(vars,"\n"),concat(calls,"\n"))
+ return format(template,concat(vars,"\n"),concat(calls,"\n"))
end
local template = [[
%s
-return function(head,tail)
+return function(head,tail,...)
local ok, done = false, false
%s
return head, tail, done
@@ -117,15 +133,16 @@ function sequencer.nodeprocessor(t)
local localized = localize(action)
vars[#vars+1] = format("local %s = %s",localized,action)
if kind[action] == "nohead" then
- calls[#calls+1] = format(" ok = %s(head,tail) done = done or ok -- %s %i",localized,group,i)
+ calls[#calls+1] = format(" ok = %s(head,tail,...) done = done or ok -- %s %i",localized,group,i)
elseif kind[action] == "notail" then
- calls[#calls+1] = format(" head, ok = %s(head,tail) done = done or ok -- %s %i",localized,group,i)
+ calls[#calls+1] = format(" head, ok = %s(head,tail,...) done = done or ok -- %s %i",localized,group,i)
else
- calls[#calls+1] = format(" head, tail, ok = %s(head,tail) done = done or ok -- %s %i",localized,group,i)
+ calls[#calls+1] = format(" head, tail, ok = %s(head,tail,...) done = done or ok -- %s %i",localized,group,i)
end
end
end
- return template:format(concat(vars,"\n"),concat(calls,"\n"))
+ local processor = format(template,concat(vars,"\n"),concat(calls,"\n"))
+ return processor
end
--~ hans = {}
diff --git a/tex/context/base/node-ser.lua b/tex/context/base/node-ser.lua
new file mode 100644
index 000000000..65c071c00
--- /dev/null
+++ b/tex/context/base/node-ser.lua
@@ -0,0 +1,274 @@
+if not modules then modules = { } end modules ['node-ser'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- beware, some field names will change in a next releases
+-- of luatex; this is pretty old code that needs an overhaul
+
+local type, format, concat = type, string.format, table.concat
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+
+local traverse = node.traverse
+local node_fields = node.fields
+local node_type = node.type
+
+local expand = table.tohash {
+ "list", -- list_ptr & ins_ptr & adjust_ptr
+ "pre", --
+ "post", --
+ "spec", -- glue_ptr
+ "top_skip", --
+ "attr", --
+ "replace", -- nobreak
+ "components", -- lig_ptr
+ "box_left", --
+ "box_right", --
+ "glyph", -- margin_char
+ "leader", -- leader_ptr
+ "action", -- action_ptr
+ "value", -- user_defined nodes with subtype 'a' en 'n'
+}
+
+-- page_insert: "height", "last_ins_ptr", "best_ins_ptr"
+-- split_insert: "height", "last_ins_ptr", "best_ins_ptr", "broken_ptr", "broken_ins"
+
+local ignore = table.tohash {
+ "page_insert",
+ "split_insert",
+ "ref_count",
+}
+
+local dimension = table.tohash {
+ "width", "height", "depth", "shift",
+ "stretch", "shrink",
+ "xoffset", "yoffset",
+ "surround",
+ "kern",
+ "box_left_width", "box_right_width"
+}
+
+-- flat: don't use next, but indexes
+-- verbose: also add type
+-- can be sped up
+
+nodes.dimensionfields = dimension
+nodes.listablefields = expand
+nodes.ignorablefields = ignore
+
+-- not ok yet:
+
+function nodes.astable(n,sparse) -- not yet ok
+ local f, t = node_fields(n.id,n.subtype), { }
+ for i=1,#f do
+ local v = f[i]
+ local d = n[v]
+ if d then
+ if ignore[v] or v == "id" then
+ -- skip
+ elseif expand[v] then -- or: type(n[v]) ~= "string" or type(n[v]) ~= "number" or type(n[v]) ~= "table"
+ t[v] = "pointer to list"
+ elseif sparse then
+ if (type(d) == "number" and d ~= 0) or (type(d) == "string" and d ~= "") then
+ t[v] = d
+ end
+ else
+ t[v] = d
+ end
+ end
+ end
+ t.type = node_type(n.id)
+ return t
+end
+
+-- under construction:
+
+local function totable(n,flat,verbose)
+ -- todo: no local function
+ local function to_table(n,flat,verbose)
+ local f = node_fields(n.id,n.subtype)
+ local tt = { }
+ for k=1,#f do
+ local v = f[k]
+ local nv = n[v]
+ if nv then
+ if ignore[v] then
+ -- skip
+ elseif expand[v] then
+ if type(nv) == "number" or type(nv) == "string" then
+ tt[v] = nv
+ else
+ tt[v] = totable(nv,flat,verbose)
+ end
+ elseif type(nv) == "table" then
+ tt[v] = nv -- totable(nv,flat,verbose) -- data
+ else
+ tt[v] = nv
+ end
+ end
+ end
+ if verbose then
+ tt.type = node_type(tt.id)
+ end
+ return tt
+ end
+ if n then
+ if flat then
+ local t = { }
+ while n do
+ t[#t+1] = to_table(n,flat,verbise)
+ n = n.next
+ end
+ return t
+ else
+ local t = to_table(n)
+ if n.next then
+ t.next = totable(n.next,flat,verbose)
+ end
+ return t
+ end
+ else
+ return { }
+ end
+end
+
+nodes.totable = totable
+
+local function key(k)
+ return ((type(k) == "number") and "["..k.."]") or k
+end
+
+-- not ok yet; this will become a module
+
+local function serialize(root,name,handle,depth,m)
+ handle = handle or print
+ if depth then
+ depth = depth .. " "
+ handle(format("%s%s={",depth,key(name)))
+ else
+ depth = ""
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ handle("[" .. name .. "]={")
+ else
+ handle("t={")
+ end
+ end
+ if root then
+ local fld
+ if root.id then
+ fld = node_fields(root.id,root.subtype) -- we can cache these (todo)
+ else
+ fld = table.sortedkeys(root)
+ end
+ if type(root) == 'table' and root['type'] then -- userdata or table
+ handle(format("%s %s=%q,",depth,'type',root['type']))
+ end
+ for f=1,#fld do
+ local k = fld[f]
+ if k == "ref_count" then
+ -- skip
+ elseif k then
+ local v = root[k]
+ local t = type(v)
+ if t == "number" then
+ if v == 0 then
+ -- skip
+ else
+ handle(format("%s %s=%s,",depth,key(k),v))
+ end
+ elseif t == "string" then
+ if v == "" then
+ -- skip
+ else
+ handle(format("%s %s=%q,",depth,key(k),v))
+ end
+ elseif v then -- userdata or table
+ serialize(v,k,handle,depth,m+1)
+ end
+ end
+ end
+ if root['next'] then -- userdata or table
+ serialize(root['next'],'next',handle,depth,m+1)
+ end
+ end
+ if m and m > 0 then
+ handle(format("%s},",depth))
+ else
+ handle(format("%s}",depth))
+ end
+end
+
+function nodes.serialize(root,name)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root, name, flush, nil, 0)
+ return concat(t,"\n")
+end
+
+function nodes.serializebox(n,flat,verbose,name)
+ return nodes.serialize(nodes.totable(tex.box[n],flat,verbose),name)
+end
+
+function nodes.visualizebox(...)
+ tex.print(ctxcatcodes,"\\starttyping")
+ tex.print(nodes.serializebox(...))
+ tex.print("\\stoptyping")
+end
+
+function nodes.list(head,n) -- name might change to nodes.type
+ if not n then
+ tex.print(ctxcatcodes,"\\starttyping")
+ end
+ while head do
+ local id = head.id
+ tex.print(string.rep(" ",n or 0) .. tostring(head) .. "\n")
+ if id == hlist or id == vlist then
+ nodes.list(head.list,(n or 0)+1)
+ end
+ head = head.next
+ end
+ if not n then
+ tex.print("\\stoptyping")
+ end
+end
+
+function nodes.print(head,n)
+ while head do
+ local id = head.id
+ texio.write_nl(string.rep(" ",n or 0) .. tostring(head))
+ if id == hlist or id == vlist then
+ nodes.print(head.list,(n or 0)+1)
+ end
+ head = head.next
+ end
+end
+
+function nodes.check_for_leaks(sparse)
+ local l = { }
+ local q = node.usedlist()
+ for p in traverse(q) do
+ local s = table.serialize(nodes.astable(p,sparse),node_type(p.id))
+ l[s] = (l[s] or 0) + 1
+ end
+ node.flush_list(q)
+ for k, v in next, l do
+ texio.write_nl(format("%s * %s", v, k))
+ end
+end
+
diff --git a/tex/context/base/node-shp.lua b/tex/context/base/node-shp.lua
new file mode 100644
index 000000000..0383d8c40
--- /dev/null
+++ b/tex/context/base/node-shp.lua
@@ -0,0 +1,66 @@
+if not modules then modules = { } end modules ['node-shp'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+local disc = node.id('disc')
+local mark = node.id('mark')
+
+local free_node = node.free
+
+local function cleanup_page(head) -- rough
+ local prev, start = nil, head
+ while start do
+ local id, nx = start.id, start.next
+ if id == disc or id == mark then
+ if prev then
+ prev.next = nx
+ end
+ if start == head then
+ head = nx
+ end
+ local tmp = start
+ start = nx
+ free_node(tmp)
+ elseif id == hlist or id == vlist then
+ local sl = start.list
+ if sl then
+ start.list = cleanup_page(sl)
+ prev, start = start, nx
+ else
+ if prev then
+ prev.next = nx
+ end
+ if start == head then
+ head = nx
+ end
+ local tmp = start
+ start = nx
+ free_node(tmp)
+ end
+ else
+ prev, start = start, nx
+ end
+ end
+ return head
+end
+
+nodes.cleanup_page_first = false
+
+function nodes.cleanup_page(head)
+ if nodes.cleanup_page_first then
+ head = cleanup_page(head)
+ end
+ return head, false
+end
+
+local actions = tasks.actions("shipouts")
+
+function nodes.process_page(head) -- problem, attr loaded before node, todo ...
+ return actions(head) -- no tail
+end
diff --git a/tex/context/base/node-tex.lua b/tex/context/base/node-tex.lua
new file mode 100644
index 000000000..563e6a397
--- /dev/null
+++ b/tex/context/base/node-tex.lua
@@ -0,0 +1,54 @@
+if not modules then modules = { } end modules ['node-tex'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+kernel = kernel or { }
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+local hyphenate, ligaturing, kerning = lang.hyphenate, node.ligaturing, node.kerning
+
+function kernel.hyphenation(head,tail) -- lang.hyphenate returns done
+ if head == tail then
+ return head, tail, false
+ else
+ -- starttiming(kernel)
+ -- local done = hyphenate(head,tail)
+ -- stoptiming(kernel)
+ -- return head, tail, done
+ return head, tail, hyphenate(head,tail)
+ end
+end
+
+function kernel.ligaturing(head,tail) -- node.ligaturing returns head,tail,done
+ if head == tail then
+ return head, tail, false
+ else
+ -- starttiming(kernel)
+ -- local head, tail, done = ligaturing(head,tail)
+ -- stoptiming(kernel)
+ -- return head, tail, done
+ return ligaturing(head,tail)
+ end
+end
+
+function kernel.kerning(head,tail) -- node.kerning returns head,tail,done
+ if head == tail then
+ return head, tail, false
+ else
+ -- starttiming(kernel)
+ -- local head, tail, done = kerning(head,tail)
+ -- stoptiming(kernel)
+ -- return head, tail, done
+ return kerning(head,tail)
+ end
+end
+
+callback.register('hyphenate' , false)
+callback.register('ligaturing', false)
+callback.register('kerning' , false)
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
new file mode 100644
index 000000000..ef13499f9
--- /dev/null
+++ b/tex/context/base/node-tra.lua
@@ -0,0 +1,399 @@
+if not modules then modules = { } end modules ['node-tra'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>This is rather experimental. We need more control and some of this
+might become a runtime module instead.</p>
+--ldx]]--
+
+local utf = unicode.utf8
+local format, match, concat, utfchar = string.format, string.match, table.concat, utf.char
+
+local ctxcatcodes = tex.ctxcatcodes
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+nodes = nodes or { }
+nodes.tracers = nodes.tracers or { }
+nodes.tracers.characters = nodes.tracers.characters or { }
+nodes.tracers.steppers = nodes.tracers.steppers or { }
+
+local glyph = node.id('glyph')
+local disc = node.id('disc')
+local glue = node.id('glue')
+local kern = node.id('kern')
+local whatsit = node.id('whatsit')
+
+local copy_node_list = node.copy_list
+local hpack_node_list = node.hpack
+local free_node_list = node.flush_list
+local first_character = node.first_character
+local node_type = node.type
+local traverse_nodes = node.traverse
+
+local texsprint = tex.sprint
+local fontdata = fonts.ids
+
+function nodes.tracers.characters.collect(head,list,tag,n)
+ n = n or 0
+ local ok, fn = false, nil
+ while head do
+ local id = head.id
+ if id == glyph then
+ local f = head.font
+ if f ~= fn then
+ ok, fn = false, f
+ end
+ local c = head.char
+ local i = fontdata[f].indices[c] or 0
+ if not ok then
+ ok = true
+ n = n + 1
+ list[n] = list[n] or { }
+ list[n][tag] = { }
+ end
+ local l = list[n][tag]
+ l[#l+1] = { c, f, i }
+ elseif id == disc then
+ -- skip
+ else
+ ok = false
+ end
+ head = head.next
+ end
+end
+
+function nodes.tracers.characters.equal(ta, tb)
+ if #ta ~= #tb then
+ return false
+ else
+ for i=1,#ta do
+ local a, b = ta[i], tb[i]
+ if a[1] ~= b[1] or a[2] ~= b[2] or a[3] ~= b[3] then
+ return false
+ end
+ end
+ end
+ return true
+end
+
+function nodes.tracers.characters.string(t)
+ local tt = { }
+ for i=1,#t do
+ tt[i] = utfchar(t[i][1])
+ end
+ return concat(tt,"")
+end
+
+function nodes.tracers.characters.unicodes(t,decimal)
+ local tt = { }
+ for i=1,#t do
+ local n = t[i][1]
+ if n == 0 then
+ tt[i] = "-"
+ elseif decimal then
+ tt[i] = n
+ else
+ tt[i] = format("U+%04X",n)
+ end
+ end
+ return concat(tt," ")
+end
+
+function nodes.tracers.characters.indices(t,decimal)
+ local tt = { }
+ for i=1,#t do
+ local n = t[i][3]
+ if n == 0 then
+ tt[i] = "-"
+ elseif decimal then
+ tt[i] = n
+ else
+ tt[i] = format("U+%04X",n)
+ end
+ end
+ return concat(tt," ")
+end
+
+function nodes.tracers.characters.start()
+ local npc = nodes.process_characters
+ local list = { }
+ function nodes.process_characters(head)
+ local n = #list
+ nodes.tracers.characters.collect(head,list,'before',n)
+ local h, d = npc(head)
+ nodes.tracers.characters.collect(head,list,'after',n)
+ if #list > n then
+ list[#list+1] = { }
+ end
+ return h, d
+ end
+ function nodes.tracers.characters.stop()
+ tracers.list['characters'] = list
+ lmx.set('title', 'ConTeXt Character Processing Information')
+ lmx.set('color-background-one', lmx.get('color-background-yellow'))
+ lmx.set('color-background-two', lmx.get('color-background-purple'))
+ lmx.show('context-characters.lmx')
+ lmx.restore()
+ nodes.process_characters = npc
+ tasks.restart("processors", "characters")
+ end
+ tasks.restart("processors", "characters")
+end
+
+local stack = { }
+
+function nodes.tracers.start(tag)
+ stack[#stack+1] = tag
+ local tracer = nodes.tracers[tag]
+ if tracer and tracer.start then
+ tracer.start()
+ end
+end
+function nodes.tracers.stop()
+ local tracer = stack[#stack]
+ if tracer and tracer.stop then
+ tracer.stop()
+ end
+ stack[#stack] = nil
+end
+
+-- experimental
+
+local collection, collecting, messages = { }, false, { }
+
+function nodes.tracers.steppers.start()
+ collecting = true
+end
+
+function nodes.tracers.steppers.stop()
+ collecting = false
+end
+
+function nodes.tracers.steppers.reset()
+ for i=1,#collection do
+ local c = collection[i]
+ if c then
+ free_node_list(c)
+ end
+ end
+ collection, messages = { }, { }
+end
+
+function nodes.tracers.steppers.nofsteps()
+ return tex.write(#collection)
+end
+
+function nodes.tracers.steppers.glyphs(n,i)
+ local c = collection[i]
+ if c then
+ tex.box[n] = hpack_node_list(copy_node_list(c))
+ end
+end
+
+function nodes.tracers.steppers.features()
+-- local f = first_character(collection[1])
+-- if f then -- something fishy with first_character
+ local f = collection[1]
+ while f do
+ if f.id == glyph then
+ local tfmdata, t = fontdata[f.font], { }
+ for feature, value in table.sortedpairs(tfmdata.shared.features) do
+ if feature == "number" or feature == "features" then
+ -- private
+ elseif type(value) == "boolean" then
+ if value then
+ t[#t+1] = format("%s=yes",feature)
+ else
+ -- skip
+ end
+ else
+ t[#t+1] = format("%s=%s",feature,value)
+ end
+ end
+ if #t > 0 then
+ texsprint(ctxcatcodes,concat(t,", "))
+ else
+ texsprint(ctxcatcodes,"no features")
+ end
+ return
+ end
+ f = f.next
+ end
+end
+
+function nodes.tracers.fontchar(font,char)
+ local n = nodes.glyph()
+ n.font, n.char, n.subtype = font, char, 256
+ node.write(n)
+end
+
+function nodes.tracers.steppers.codes(i,command)
+ local c = collection[i]
+ while c do
+ local id = c.id
+ if id == glyph then
+ if command then
+ texsprint(ctxcatcodes,format("%s{%s}{%s}",command,c.font,c.char))
+ else
+ texsprint(ctxcatcodes,format("[%s:U+%04X]",c.font,c.char))
+ end
+ elseif id == whatsit and (c.subtype == 6 or c.subtype == 7) then
+ texsprint(ctxcatcodes,format("[%s]",c.dir))
+ else
+ texsprint(ctxcatcodes,format("[%s]",node_type(id)))
+ end
+ c = c.next
+ end
+end
+
+function nodes.tracers.steppers.messages(i,command,split)
+ local list = messages[i] -- or { "no messages" }
+ if list then
+ for i=1,#list do
+ local l = list[i]
+ if split then
+ local a, b = match(l,"^(.-)%s*:%s*(.*)$")
+ texsprint(ctxcatcodes,format("%s{%s}{%s}",command,a or l,b or ""))
+ else
+ texsprint(ctxcatcodes,format("%s{%s}",command,l))
+ end
+ end
+ end
+end
+
+-- hooks into the node list processor (see otf)
+
+function nodes.tracers.steppers.check(head)
+ if collecting then
+ nodes.tracers.steppers.reset()
+ local n = copy_node_list(head)
+ nodes.inject_kerns(n,nil,true)
+ nodes.protect_glyphs(n) -- can be option
+ collection[1] = n
+ end
+end
+
+function nodes.tracers.steppers.register(head)
+ if collecting then
+ local nc = #collection+1
+ if messages[nc] then
+ local n = copy_node_list(head)
+ nodes.inject_kerns(n,nil,true)
+ nodes.protect_glyphs(n) -- can be option
+ collection[nc] = n
+ end
+ end
+end
+
+function nodes.tracers.steppers.message(str,...)
+ str = format(str,...)
+ if collecting then
+ local n = #collection + 1
+ local m = messages[n]
+ if not m then m = { } messages[n] = m end
+ m[#m+1] = str
+ end
+ return str -- saves an intermediate var in the caller
+end
+
+-- this will be reorganized:
+
+function nodes.show_list(head, message)
+ if message then
+ texio.write_nl(message)
+ end
+ for n in traverse(head) do
+ texio.write_nl(tostring(n))
+ end
+end
+
+function nodes.check_glyphs(head,message)
+ local t = { }
+ for g in traverse_id(glyph,head) do
+ t[#t+1] = format("U+%04X:%s",g.char,g.subtype)
+ end
+ if #t > 0 then
+ logs.report(message or "nodes","%s glyphs: %s",#t,concat(t," "))
+ end
+ return false
+end
+
+function nodes.tosequence(start,stop)
+ if start then
+ local t = { }
+ while start do
+ if start.id == glyph then
+ t[#t+1] = format("U+%04X:%s",start.char,utfchar(start.char))
+ else
+ t[#t+1] = match(tostring(start),": (%S+)")
+ end
+ if start == stop then
+ break
+ else
+ start = start.next
+ end
+ end
+ return concat(t," ")
+ else
+ return "<empty>"
+ end
+end
+
+function nodes.report(t,done)
+ if done then
+ if status.output_active then
+ texio.write(format("<++ %s>",count(t)))
+ else
+ texio.write(format("<+ %s>",count(t)))
+ end
+ else
+ if status.output_active then
+ texio.write(format("<-- %s>",count(t)))
+ else
+ texio.write(format("<- %s>",count(t)))
+ end
+ end
+end
+
+function nodes.pack_list(head)
+ local t = { }
+ for n in traverse(head) do
+ t[#t+1] = tostring(n)
+ end
+ return t
+end
+
+function nodes.ids_to_string(head)
+ local t, last_id, last_n = { }, nil, 0
+ for n in traverse_nodes(head) do
+ local id = n.id
+ if not last_id then
+ last_id, last_n = id, 1
+ elseif last_id == id then
+ last_n = last_n + 1
+ else
+ if last_n > 1 then
+ t[#t+1] = format("[%s*%s]",last_n,node_type(last_id) or "?")
+ else
+ t[#t+1] = format("[%s]",node_type(last_id) or "?")
+ end
+ last_id, last_n = id, 1
+ end
+ end
+ if not last_id then
+ t[#t+1] = "no nodes"
+ elseif last_n > 1 then
+ t[#t+1] = format("[%s*%s]",last_n,node_type(last_id) or "?")
+ else
+ t[#t+1] = format("[%s]",node_type(last_id) or "?")
+ end
+ return concat(t," ")
+end
diff --git a/tex/context/base/node-tsk.lua b/tex/context/base/node-tsk.lua
new file mode 100644
index 000000000..f20c544c4
--- /dev/null
+++ b/tex/context/base/node-tsk.lua
@@ -0,0 +1,113 @@
+if not modules then modules = { } end modules ['node-tsk'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_tasks = false trackers.register("tasks", function(v) trace_tasks = v end)
+
+tasks = tasks or { }
+tasks.data = tasks.data or { }
+
+function tasks.new(name,list)
+ local tasklist = sequencer.reset()
+ tasks.data[name] = { list = tasklist, runner = false }
+ for l=1,#list do
+ sequencer.appendgroup(tasklist,list[l])
+ end
+end
+
+function tasks.restart(name,group)
+ local data = tasks.data[name]
+ if data then
+ data.runner = false
+ end
+end
+
+function tasks.appendaction(name,group,action,where,kind)
+ local data = tasks.data[name]
+ if data then
+ sequencer.appendaction(data.list,group,action,where,kind)
+ data.runner = false
+ end
+end
+
+function tasks.prependaction(name,group,action,where,kind)
+ local data = tasks.data[name]
+ if data then
+ sequencer.prependaction(data.list,group,action,where,kind)
+ data.runner = false
+ end
+end
+
+function tasks.removeaction(name,group,action)
+ local data = tasks.data[name]
+ if data then
+ sequencer.removeaction(data.list,group,action)
+ data.runner = false
+ end
+end
+
+function tasks.showactions(name,group,action,where,kind)
+ local data = tasks.data[name]
+ if data then
+ logs.report("nodes","task %s, list:\n%s",name,sequencer.nodeprocessor(data.list))
+ end
+end
+
+function tasks.actions(name)
+ local data = tasks.data[name]
+ if data then
+ return function(head,tail,...)
+ local runner = data.runner
+ if not runner then
+ if trace_tasks then
+ logs.report("nodes","creating task runner '%s'",name)
+ end
+ runner = sequencer.compile(data.list,sequencer.nodeprocessor)
+ data.runner = runner
+ end
+ return runner(head,tail,...)
+ end
+ else
+ return nil
+ end
+end
+
+tasks.new (
+ "processors",
+ {
+ "before", -- for users
+ "normalizers",
+ "characters",
+ "words",
+ "fonts",
+ "lists",
+ "after", -- for users
+ }
+)
+
+tasks.new (
+ "finalizers",
+ {
+ "before", -- for users
+ "normalizers",
+-- "characters",
+-- "finishers",
+ "fonts",
+-- "lists",
+ "after", -- for users
+ }
+)
+
+tasks.new (
+ "shipouts",
+ {
+ "before", -- for users
+ "normalizers",
+ "finishers",
+ "after", -- for users
+ }
+)
diff --git a/tex/context/base/node-tst.lua b/tex/context/base/node-tst.lua
new file mode 100644
index 000000000..e8b1146f8
--- /dev/null
+++ b/tex/context/base/node-tst.lua
@@ -0,0 +1,108 @@
+if not modules then modules = { } end modules ['node-tst'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+function nodes.leftskip(n)
+ while n do
+ local id = n.id
+ if id == glue then
+ if n.subtype == 8 then -- 7 in c/web source
+ return (n.spec and n.spec.width) or 0
+ else
+ return 0
+ end
+ elseif id == whatsit then
+ n = n.next
+ elseif id == hlist then
+ return n.width
+ else
+ break
+ end
+ end
+ return 0
+end
+
+function nodes.rightskip(n)
+ if n then
+ n = slide_nodes(n)
+ while n do
+ local id = n.id
+ if id == glue then
+ if n.subtype == 9 then -- 8 in the c/web source
+ return (n.spec and n.spec.width) or 0
+ else
+ return 0
+ end
+ elseif id == whatsit then
+ n = n.prev
+ else
+ break
+ end
+ end
+ end
+ return false
+end
+
+function nodes.somespace(n,all)
+ if n then
+ local id = n.id
+ if id == glue then
+ return (all or (n.spec.width ~= 0)) and glue
+ elseif id == kern then
+ return (all or (n.kern ~= 0)) and kern
+ elseif id == glyph then
+ local category = chardata[n.char].category
+ -- maybe more category checks are needed
+ return (category == "zs") and glyph
+ end
+ end
+ return false
+end
+
+function nodes.somepenalty(n,value)
+ if n then
+ local id = n.id
+ if id == penalty then
+ if value then
+ return n.penalty == value
+ else
+ return true
+ end
+ end
+ end
+ return false
+end
+
+function nodes.is_display_math(head)
+ local n = head.prev
+ while n do
+ local id = n.id
+ if id == penalty then
+ elseif id == glue then
+ if n.subtype == 6 then -- above_display_short_skip
+ return true
+ end
+ else
+ break
+ end
+ n = n.prev
+ end
+ n = head.next
+ while n do
+ local id = n.id
+ if id == penalty then
+ elseif id == glue then
+ if n.subtype == 7 then -- below_display_short_skip
+ return true
+ end
+ else
+ break
+ end
+ n = n.next
+ end
+ return false
+end
diff --git a/tex/context/base/norm-alo.tex b/tex/context/base/norm-alo.tex
new file mode 100644
index 000000000..d47f49037
--- /dev/null
+++ b/tex/context/base/norm-alo.tex
@@ -0,0 +1,36 @@
+%D \module
+%D [ file=norm-alo,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\ALEPH\ and \OMEGA,
+%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 This file will become obsolete!
+
+% omega primitives
+
+\let\textdir = \textdir
+\let\pagedir = \pagedir
+\let\mathdir = \mathdir
+\let\pardir = \pardir
+\let\bodydir = \bodydir
+\let\leftghost = \leftghost
+\let\rightghost = \rightghost
+\let\localleftbox = \localleftbox
+\let\localrightbox = \localrightbox
+\let\localinterlinepenalty = \localinterlinepenalty
+\let\localbrokenpenalty = \localbrokenpenalty
+
+% aleph primitives
+
+\let\boxdir = \boxdir
+\let\pagebottomoffset = \pagebottomoffset
+\let\pagerightoffset = \pagerightoffset
+
+\endinput
diff --git a/tex/context/base/norm-ctx.tex b/tex/context/base/norm-ctx.tex
new file mode 100644
index 000000000..707705d89
--- /dev/null
+++ b/tex/context/base/norm-ctx.tex
@@ -0,0 +1,16 @@
+%D \module
+%D [ file=norm-ctx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\ALEPH\ and \OMEGA,
+%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 A few more might end up here (like the weird ones in syst-ini).
+
+\let\normalreqno = \normaleqno
diff --git a/tex/context/base/norm-etx.tex b/tex/context/base/norm-etx.tex
new file mode 100644
index 000000000..3edd8e7ef
--- /dev/null
+++ b/tex/context/base/norm-etx.tex
@@ -0,0 +1,79 @@
+%D \module
+%D [ file=norm-etx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\ETEX,
+%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.
+
+% etex primitives
+
+\let \normalbotmarks = \botmarks
+\let \normalclubpenalties = \clubpenalties
+\let \normalcurrentgrouplevel = \currentgrouplevel
+\let \normalcurrentgrouptype = \currentgrouptype
+\let \normalcurrentifbranch = \currentifbranch
+\let \normalcurrentiflevel = \currentiflevel
+\let \normalcurrentiftype = \currentiftype
+\let \normaldetokenize = \detokenize
+\let \normaldimexpr = \dimexpr
+\let \normaldisplaywidowpenalties = \displaywidowpenalties
+\let \normaleTeXVersion = \eTeXVersion
+\let \normaleTeXminorversion = \eTeXminorversion
+\let \normaleTeXrevision = \eTeXrevision
+\let \normaleTeXversion = \eTeXversion
+\let \normaleveryeof = \everyeof
+\let \normalfirstmarks = \firstmarks
+\let \normalfontchardp = \fontchardp
+\let \normalfontcharht = \fontcharht
+\let \normalfontcharic = \fontcharic
+\let \normalfontcharwd = \fontcharwd
+\let \normalglueexpr = \glueexpr
+\let \normalglueshrink = \glueshrink
+\let \normalglueshrinkorder = \glueshrinkorder
+\let \normalgluestretch = \gluestretch
+\let \normalgluestretchorder = \gluestretchorder
+\let \normalgluetomu = \gluetomu
+\let \normalifcsname = \ifcsname
+\let \normalifdefined = \ifdefined
+\let \normaliffontchar = \iffontchar
+\let \normalinteractionmode = \interactionmode
+\let \normalinterlinepenalties = \interlinepenalties
+\let \normallastlinefit = \lastlinefit
+\let \normallastnodetype = \lastnodetype
+\let \normalmarks = \marks
+\let \normalmuexpr = \muexpr
+\let \normalmutoglue = \mutoglue
+\let \normalnumexpr = \numexpr
+\let \normalpagediscards = \pagediscards
+\let \normalparshapedimen = \parshapedimen
+\let \normalparshapeindent = \parshapeindent
+\let \normalparshapelength = \parshapelength
+\let \normalpredisplaydirection = \predisplaydirection
+\let \normalprotected = \protected
+\let \normalreadline = \readline
+\let \normalsavinghyphcodes = \savinghyphcodes
+\let \normalsavingvdiscards = \savingvdiscards
+\let \normalscantokens = \scantokens
+\let \normalshowgroups = \showgroups
+\let \normalshowifs = \showifs
+\let \normalshowtokens = \showtokens
+\let \normalsplitbotmarks = \splitbotmarks
+\let \normalsplitdiscards = \splitdiscards
+\let \normalsplitfirstmarks = \splitfirstmarks
+\let \normaltopmarks = \topmarks
+\let \normaltracingassigns = \tracingassigns
+\let \normaltracinggroups = \tracinggroups
+\let \normaltracingifs = \tracingifs
+\let \normaltracingnesting = \tracingnesting
+\let \normaltracingscantokens = \tracingscantokens
+\let \normalunexpanded = \unexpanded
+\let \normalunless = \unless
+\let \normalwidowpenalties = \widowpenalties
+
+\endinput
diff --git a/tex/context/base/norm-ltx.tex b/tex/context/base/norm-ltx.tex
new file mode 100644
index 000000000..c83a49b90
--- /dev/null
+++ b/tex/context/base/norm-ltx.tex
@@ -0,0 +1,177 @@
+%D \module
+%D [ file=norm-ltx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\LUATEX,
+%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 This file will become obsolete!
+
+% luatex primitives
+
+\let \normalUdelcode = \Udelcode
+\let \normalUdelcodenum = \Udelcodenum
+\let \normalUdelimiter = \Udelimiter
+\let \normalUmathaccent = \Umathaccent
+\let \normalUmathaccents = \Umathaccents
+\let \normalUmathaxis = \Umathaxis
+\let \normalUmathbinbinspacing = \Umathbinbinspacing
+\let \normalUmathbinclosespacing = \Umathbinclosespacing
+\let \normalUmathbininnerspacing = \Umathbininnerspacing
+\let \normalUmathbinopenspacing = \Umathbinopenspacing
+\let \normalUmathbinopspacing = \Umathbinopspacing
+\let \normalUmathbinordspacing = \Umathbinordspacing
+\let \normalUmathbinpunctspacing = \Umathbinpunctspacing
+\let \normalUmathbinrelspacing = \Umathbinrelspacing
+\let \normalUmathbotaccent = \Umathbotaccent
+\let \normalUmathchar = \Umathchar
+\let \normalUmathchardef = \Umathchardef
+\let \normalUmathcharnum = \Umathcharnum
+\let \normalUmathclosebinspacing = \Umathclosebinspacing
+\let \normalUmathcloseclosespacing = \Umathcloseclosespacing
+\let \normalUmathcloseinnerspacing = \Umathcloseinnerspacing
+\let \normalUmathcloseopenspacing = \Umathcloseopenspacing
+\let \normalUmathcloseopspacing = \Umathcloseopspacing
+\let \normalUmathcloseordspacing = \Umathcloseordspacing
+\let \normalUmathclosepunctspacing = \Umathclosepunctspacing
+\let \normalUmathcloserelspacing = \Umathcloserelspacing
+\let \normalUmathcode = \Umathcode
+\let \normalUmathcodenum = \Umathcodenum
+\let \normalUmathconnectoroverlapmin = \Umathconnectoroverlapmin
+\let \normalUmathfractiondelsize = \Umathfractiondelsize
+\let \normalUmathfractiondenomdown = \Umathfractiondenomdown
+\let \normalUmathfractiondenomvgap = \Umathfractiondenomvgap
+\let \normalUmathfractionnumup = \Umathfractionnumup
+\let \normalUmathfractionnumvgap = \Umathfractionnumvgap
+\let \normalUmathfractionrule = \Umathfractionrule
+\let \normalUmathinnerbinspacing = \Umathinnerbinspacing
+\let \normalUmathinnerclosespacing = \Umathinnerclosespacing
+\let \normalUmathinnerinnerspacing = \Umathinnerinnerspacing
+\let \normalUmathinneropenspacing = \Umathinneropenspacing
+\let \normalUmathinneropspacing = \Umathinneropspacing
+\let \normalUmathinnerordspacing = \Umathinnerordspacing
+\let \normalUmathinnerpunctspacing = \Umathinnerpunctspacing
+\let \normalUmathinnerrelspacing = \Umathinnerrelspacing
+\let \normalUmathlimitabovebgap = \Umathlimitabovebgap
+\let \normalUmathlimitabovekern = \Umathlimitabovekern
+\let \normalUmathlimitabovevgap = \Umathlimitabovevgap
+\let \normalUmathlimitdownbgap = \Umathlimitdownbgap
+\let \normalUmathlimitdownkern = \Umathlimitdownkern
+\let \normalUmathlimitdownvgap = \Umathlimitdownvgap
+\let \normalUmathopbinspacing = \Umathopbinspacing
+\let \normalUmathopclosespacing = \Umathopclosespacing
+\let \normalUmathopenbinspacing = \Umathopenbinspacing
+\let \normalUmathopenclosespacing = \Umathopenclosespacing
+\let \normalUmathopeninnerspacing = \Umathopeninnerspacing
+\let \normalUmathopenopenspacing = \Umathopenopenspacing
+\let \normalUmathopenopspacing = \Umathopenopspacing
+\let \normalUmathopenordspacing = \Umathopenordspacing
+\let \normalUmathopenpunctspacing = \Umathopenpunctspacing
+\let \normalUmathopenrelspacing = \Umathopenrelspacing
+\let \normalUmathoperatorsize = \Umathoperatorsize
+\let \normalUmathopinnerspacing = \Umathopinnerspacing
+\let \normalUmathopopenspacing = \Umathopopenspacing
+\let \normalUmathopopspacing = \Umathopopspacing
+\let \normalUmathopordspacing = \Umathopordspacing
+\let \normalUmathoppunctspacing = \Umathoppunctspacing
+\let \normalUmathoprelspacing = \Umathoprelspacing
+\let \normalUmathordbinspacing = \Umathordbinspacing
+\let \normalUmathordclosespacing = \Umathordclosespacing
+\let \normalUmathordinnerspacing = \Umathordinnerspacing
+\let \normalUmathordopenspacing = \Umathordopenspacing
+\let \normalUmathordopspacing = \Umathordopspacing
+\let \normalUmathordordspacing = \Umathordordspacing
+\let \normalUmathordpunctspacing = \Umathordpunctspacing
+\let \normalUmathordrelspacing = \Umathordrelspacing
+\let \normalUmathoverbarkern = \Umathoverbarkern
+\let \normalUmathoverbarrule = \Umathoverbarrule
+\let \normalUmathoverbarvgap = \Umathoverbarvgap
+\let \normalUmathoverdelimiterbgap = \Umathoverdelimiterbgap
+\let \normalUmathoverdelimitervgap = \Umathoverdelimitervgap
+\let \normalUmathpunctbinspacing = \Umathpunctbinspacing
+\let \normalUmathpunctclosespacing = \Umathpunctclosespacing
+\let \normalUmathpunctinnerspacing = \Umathpunctinnerspacing
+\let \normalUmathpunctopenspacing = \Umathpunctopenspacing
+\let \normalUmathpunctopspacing = \Umathpunctopspacing
+\let \normalUmathpunctordspacing = \Umathpunctordspacing
+\let \normalUmathpunctpunctspacing = \Umathpunctpunctspacing
+\let \normalUmathpunctrelspacing = \Umathpunctrelspacing
+\let \normalUmathquad = \Umathquad
+\let \normalUmathradicaldegreeafter = \Umathradicaldegreeafter
+\let \normalUmathradicaldegreebefore = \Umathradicaldegreebefore
+\let \normalUmathradicaldegreeraise = \Umathradicaldegreeraise
+\let \normalUmathradicalkern = \Umathradicalkern
+\let \normalUmathradicalrule = \Umathradicalrule
+\let \normalUmathradicalvgap = \Umathradicalvgap
+\let \normalUmathrelbinspacing = \Umathrelbinspacing
+\let \normalUmathrelclosespacing = \Umathrelclosespacing
+\let \normalUmathrelinnerspacing = \Umathrelinnerspacing
+\let \normalUmathrelopenspacing = \Umathrelopenspacing
+\let \normalUmathrelopspacing = \Umathrelopspacing
+\let \normalUmathrelordspacing = \Umathrelordspacing
+\let \normalUmathrelpunctspacing = \Umathrelpunctspacing
+\let \normalUmathrelrelspacing = \Umathrelrelspacing
+\let \normalUmathspaceafterscript = \Umathspaceafterscript
+\let \normalUmathstackdenomdown = \Umathstackdenomdown
+\let \normalUmathstacknumup = \Umathstacknumup
+\let \normalUmathstackvgap = \Umathstackvgap
+\let \normalUmathsubshiftdown = \Umathsubshiftdown
+\let \normalUmathsubshiftdrop = \Umathsubshiftdrop
+\let \normalUmathsubsupshiftdown = \Umathsubsupshiftdown
+\let \normalUmathsubsupvgap = \Umathsubsupvgap
+\let \normalUmathsubtopmax = \Umathsubtopmax
+\let \normalUmathsupbottommin = \Umathsupbottommin
+\let \normalUmathsupshiftdrop = \Umathsupshiftdrop
+\let \normalUmathsupshiftup = \Umathsupshiftup
+\let \normalUmathsupsubbottommax = \Umathsupsubbottommax
+\let \normalUmathunderbarkern = \Umathunderbarkern
+\let \normalUmathunderbarrule = \Umathunderbarrule
+\let \normalUmathunderbarvgap = \Umathunderbarvgap
+\let \normalUmathunderdelimiterbgap = \Umathunderdelimiterbgap
+\let \normalUmathunderdelimitervgap = \Umathunderdelimitervgap
+\let \normalUoverdelimiter = \Uoverdelimiter
+\let \normalUradical = \Uradical
+\let \normalUroot = \Uroot
+\let \normalUunderdelimiter = \Uunderdelimiter
+\let \normalattribute = \attribute
+\let \normalattributedef = \attributedef
+\let \normalcatcodetable = \catcodetable
+\let \normalclearmarks = \clearmarks
+\let \normalcrampeddisplaystyle = \crampeddisplaystyle
+\let \normalcrampedscriptscriptstyle = \crampedscriptscriptstyle
+\let \normalcrampedscriptstyle = \crampedscriptstyle
+\let \normalcrampedtextstyle = \crampedtextstyle
+\let \normalformatname = \formatname
+\let \normalifabsdim = \ifabsdim
+\let \normalifabsnum = \ifabsnum
+\let \normalifprimitive = \ifprimitive
+\let \normalinitcatcodetable = \initcatcodetable
+\let \normallatelua = \latelua
+\let \normalluaescapestring = \luaescapestring
+\let \normalluastartup = \luastartup
+\let \normalluatexdatestamp = \luatexdatestamp
+\let \normalluatexrevision = \luatexrevision
+\let \normalluatexversion = \luatexversion
+\let \normalnokerns = \nokerns
+\let \normalnoligs = \noligs
+\let \normalpageleftoffset = \pageleftoffset
+\let \normalpagetopoffset = \pagetopoffset
+\let \normalpostexhyphenchar = \postexhyphenchar
+\let \normalposthyphenchar = \posthyphenchar
+\let \normalpreexhyphenchar = \preexhyphenchar
+\let \normalprehyphenchar = \prehyphenchar
+\let \normalprimitive = \primitive
+\let \normalsavecatcodetable = \savecatcodetable
+\let \normalscantextokens = \scantextokens
+\let \normalsuppressfontnotfounderror = \suppressfontnotfounderror
+\let \normalsuppressifcsnameerror = \suppressifcsnameerror
+\let \normalsuppresslongerror = \suppresslongerror
+\let \normalsynctex = \synctex
+
+\endinput
diff --git a/tex/context/base/norm-ptx.tex b/tex/context/base/norm-ptx.tex
new file mode 100644
index 000000000..992fd38ff
--- /dev/null
+++ b/tex/context/base/norm-ptx.tex
@@ -0,0 +1,130 @@
+%D \module
+%D [ file=norm-ptx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\PDFTEX,
+%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.
+
+\let \normalefcode = \efcode
+\let \normalexpanded = \expanded
+\let \normalifincsname = \ifincsname
+\let \normalifpdfabsdim = \ifpdfabsdim
+\let \normalifpdfabsnum = \ifpdfabsnum
+\let \normalifpdfprimitive = \ifpdfprimitive
+\let \normalleftmarginkern = \leftmarginkern
+\let \normalletterspacefont = \letterspacefont
+\let \normallpcode = \lpcode
+\let \normalpdfadjustspacing = \pdfadjustspacing
+\let \normalpdfannot = \pdfannot
+\let \normalpdfcatalog = \pdfcatalog
+\let \normalpdfcolorstack = \pdfcolorstack
+\let \normalpdfcolorstackinit = \pdfcolorstackinit
+\let \normalpdfcompresslevel = \pdfcompresslevel
+\let \normalpdfcopyfont = \pdfcopyfont
+\let \normalpdfcreationdate = \pdfcreationdate
+\let \normalpdfdecimaldigits = \pdfdecimaldigits
+\let \normalpdfdest = \pdfdest
+\let \normalpdfdestmargin = \pdfdestmargin
+\let \normalpdfdraftmode = \pdfdraftmode
+\let \normalpdfeachlinedepth = \pdfeachlinedepth
+\let \normalpdfeachlineheight = \pdfeachlineheight
+\let \normalpdfendlink = \pdfendlink
+\let \normalpdfendthread = \pdfendthread
+\let \normalpdffirstlineheight = \pdffirstlineheight
+\let \normalpdffontattr = \pdffontattr
+\let \normalpdffontexpand = \pdffontexpand
+\let \normalpdffontname = \pdffontname
+\let \normalpdffontobjnum = \pdffontobjnum
+\let \normalpdffontsize = \pdffontsize
+\let \normalpdfforcepagebox = \pdfforcepagebox
+\let \normalpdfgamma = \pdfgamma
+\let \normalpdfgentounicode = \pdfgentounicode
+\let \normalpdfglyphtounicode = \pdfglyphtounicode
+\let \normalpdfhorigin = \pdfhorigin
+\let \normalpdfignoreddimen = \pdfignoreddimen
+\let \normalpdfimageapplygamma = \pdfimageapplygamma
+\let \normalpdfimagegamma = \pdfimagegamma
+\let \normalpdfimagehicolor = \pdfimagehicolor
+\let \normalpdfimageresolution = \pdfimageresolution
+\let \normalpdfincludechars = \pdfincludechars
+\let \normalpdfinclusioncopyfonts = \pdfinclusioncopyfonts
+\let \normalpdfinclusionerrorlevel = \pdfinclusionerrorlevel
+\let \normalpdfinfo = \pdfinfo
+\let \normalpdfinsertht = \pdfinsertht
+\let \normalpdflastannot = \pdflastannot
+\let \normalpdflastlinedepth = \pdflastlinedepth
+\let \normalpdflastlink = \pdflastlink
+\let \normalpdflastobj = \pdflastobj
+\let \normalpdflastxform = \pdflastxform
+\let \normalpdflastximage = \pdflastximage
+\let \normalpdflastximagecolordepth = \pdflastximagecolordepth
+\let \normalpdflastximagepages = \pdflastximagepages
+\let \normalpdflastxpos = \pdflastxpos
+\let \normalpdflastypos = \pdflastypos
+\let \normalpdflinkmargin = \pdflinkmargin
+\let \normalpdfliteral = \pdfliteral
+\let \normalpdfmapfile = \pdfmapfile
+\let \normalpdfmapline = \pdfmapline
+\let \normalpdfminorversion = \pdfminorversion
+\let \normalpdfmovechars = \pdfmovechars
+\let \normalpdfnames = \pdfnames
+\let \normalpdfnoligatures = \pdfnoligatures
+\let \normalpdfnormaldeviate = \pdfnormaldeviate
+\let \normalpdfobj = \pdfobj
+\let \normalpdfobjcompresslevel = \pdfobjcompresslevel
+\let \normalpdfoptionalwaysusepdfpagebox = \pdfoptionalwaysusepdfpagebox
+\let \normalpdfoptionpdfinclusionerrorlevel = \pdfoptionpdfinclusionerrorlevel
+\let \normalpdfoptionpdfminorversion = \pdfoptionpdfminorversion
+\let \normalpdfoutline = \pdfoutline
+\let \normalpdfoutput = \pdfoutput
+\let \normalpdfpageattr = \pdfpageattr
+\let \normalpdfpagebox = \pdfpagebox
+\let \normalpdfpageheight = \pdfpageheight
+\let \normalpdfpageref = \pdfpageref
+\let \normalpdfpageresources = \pdfpageresources
+\let \normalpdfpagesattr = \pdfpagesattr
+\let \normalpdfpagewidth = \pdfpagewidth
+\let \normalpdfpkmode = \pdfpkmode
+\let \normalpdfpkresolution = \pdfpkresolution
+\let \normalpdfprimitive = \pdfprimitive
+\let \normalpdfprotrudechars = \pdfprotrudechars
+\let \normalpdfpxdimen = \pdfpxdimen
+\let \normalpdfrandomseed = \pdfrandomseed
+\let \normalpdfrefobj = \pdfrefobj
+\let \normalpdfrefxform = \pdfrefxform
+\let \normalpdfrefximage = \pdfrefximage
+\let \normalpdfreplacefont = \pdfreplacefont
+\let \normalpdfrestore = \pdfrestore
+\let \normalpdfretval = \pdfretval
+\let \normalpdfsave = \pdfsave
+\let \normalpdfsavepos = \pdfsavepos
+\let \normalpdfsetmatrix = \pdfsetmatrix
+\let \normalpdfsetrandomseed = \pdfsetrandomseed
+\let \normalpdfstartlink = \pdfstartlink
+\let \normalpdfstartthread = \pdfstartthread
+\let \normalpdftexbanner = \pdftexbanner
+\let \normalpdftexrevision = \pdftexrevision
+\let \normalpdftexversion = \pdftexversion
+\let \normalpdfthread = \pdfthread
+\let \normalpdfthreadmargin = \pdfthreadmargin
+\let \normalpdftracingfonts = \pdftracingfonts
+\let \normalpdftrailer = \pdftrailer
+\let \normalpdfuniformdeviate = \pdfuniformdeviate
+\let \normalpdfuniqueresname = \pdfuniqueresname
+\let \normalpdfvorigin = \pdfvorigin
+\let \normalpdfxform = \pdfxform
+\let \normalpdfxformname = \pdfxformname
+\let \normalpdfximage = \pdfximage
+\let \normalpdfximagebbox = \pdfximagebbox
+\let \normalquitvmode = \quitvmode
+\let \normalrightmarginkern = \rightmarginkern
+\let \normalrpcode = \rpcode
+\let \normaltagcode = \tagcode
+
+\endinput
diff --git a/tex/context/base/norm-tex.tex b/tex/context/base/norm-tex.tex
new file mode 100644
index 000000000..61f9740ef
--- /dev/null
+++ b/tex/context/base/norm-tex.tex
@@ -0,0 +1,351 @@
+%D \module
+%D [ file=norm-etx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\TEX,
+%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 Since \LUATEX\ can generate these lists internally it started
+%D to make sense to cleanup this \type {\normalstuff} for \MKII\ as
+%D well. The tables are generated with a \LUA\ script.
+
+% tex primitives
+
+% Beware, we already redefined \dump, \outer and \everyjob !
+
+% \normal = \
+% \normal- = \-
+% \normal/ = \/
+\let \normalabove = \above
+\let \normalabovedisplayshortskip = \abovedisplayshortskip
+\let \normalabovedisplayskip = \abovedisplayskip
+\let \normalabovewithdelims = \abovewithdelims
+\let \normalaccent = \accent
+\let \normaladjdemerits = \adjdemerits
+\let \normaladvance = \advance
+\let \normalafterassignment = \afterassignment
+\let \normalaftergroup = \aftergroup
+\let \normalatop = \atop
+\let \normalatopwithdelims = \atopwithdelims
+\let \normalbadness = \badness
+\let \normalbaselineskip = \baselineskip
+\let \normalbatchmode = \batchmode
+\let \normalbegingroup = \begingroup
+\let \normalbelowdisplayshortskip = \belowdisplayshortskip
+\let \normalbelowdisplayskip = \belowdisplayskip
+\let \normalbinoppenalty = \binoppenalty
+\let \normalbotmark = \botmark
+\let \normalbox = \box
+\let \normalboxmaxdepth = \boxmaxdepth
+\let \normalbrokenpenalty = \brokenpenalty
+\let \normalcatcode = \catcode
+\let \normalchar = \char
+\let \normalchardef = \chardef
+\let \normalcleaders = \cleaders
+\let \normalclosein = \closein
+\let \normalcloseout = \closeout
+\let \normalclubpenalty = \clubpenalty
+\let \normalcopy = \copy
+\let \normalcount = \count
+\let \normalcountdef = \countdef
+\let \normalcr = \cr
+\let \normalcrcr = \crcr
+\let \normalcsname = \csname
+\let \normalday = \day
+\let \normaldeadcycles = \deadcycles
+\let \normaldef = \def
+\let \normaldefaulthyphenchar = \defaulthyphenchar
+\let \normaldefaultskewchar = \defaultskewchar
+\let \normaldelcode = \delcode
+\let \normaldelimiter = \delimiter
+\let \normaldelimiterfactor = \delimiterfactor
+\let \normaldelimitershortfall = \delimitershortfall
+\let \normaldimen = \dimen
+\let \normaldimendef = \dimendef
+\let \normaldirectlua = \directlua
+\let \normaldiscretionary = \discretionary
+\let \normaldisplayindent = \displayindent
+\let \normaldisplaylimits = \displaylimits
+\let \normaldisplaystyle = \displaystyle
+\let \normaldisplaywidowpenalty = \displaywidowpenalty
+\let \normaldisplaywidth = \displaywidth
+\let \normaldivide = \divide
+\let \normaldoublehyphendemerits = \doublehyphendemerits
+\let \normaldp = \dp
+% \normaldump = \dump
+\let \normaledef = \edef
+\let \normalelse = \else
+\let \normalemergencystretch = \emergencystretch
+\let \normalend = \end
+\let \normalendcsname = \endcsname
+\let \normalendgroup = \endgroup
+\let \normalendinput = \endinput
+\let \normalendlinechar = \endlinechar
+\let \normaleqno = \eqno
+\let \normalerrhelp = \errhelp
+\let \normalerrmessage = \errmessage
+\let \normalerrorcontextlines = \errorcontextlines
+\let \normalerrorstopmode = \errorstopmode
+\let \normalescapechar = \escapechar
+\let \normaleverycr = \everycr
+\let \normaleverydisplay = \everydisplay
+\let \normaleveryhbox = \everyhbox
+% \normaleveryjob = \everyjob
+\let \normaleverymath = \everymath
+\let \normaleverypar = \everypar
+\let \normaleveryvbox = \everyvbox
+\let \normalexhyphenchar = \exhyphenchar
+\let \normalexhyphenpenalty = \exhyphenpenalty
+\let \normalexpandafter = \expandafter
+\let \normalfam = \fam
+\let \normalfi = \fi
+\let \normalfinalhyphendemerits = \finalhyphendemerits
+\let \normalfirstmark = \firstmark
+\let \normalfloatingpenalty = \floatingpenalty
+\let \normalfont = \font
+\let \normalfontdimen = \fontdimen
+\let \normalfontname = \fontname
+\let \normalfuturelet = \futurelet
+\let \normalgdef = \gdef
+\let \normalglobal = \global
+\let \normalglobaldefs = \globaldefs
+\let \normalhalign = \halign
+\let \normalhangafter = \hangafter
+\let \normalhangindent = \hangindent
+\let \normalhbadness = \hbadness
+\let \normalhbox = \hbox
+\let \normalhfil = \hfil
+\let \normalhfill = \hfill
+\let \normalhfilneg = \hfilneg
+\let \normalhfuzz = \hfuzz
+\let \normalhoffset = \hoffset
+\let \normalholdinginserts = \holdinginserts
+\let \normalhrule = \hrule
+\let \normalhsize = \hsize
+\let \normalhskip = \hskip
+\let \normalhss = \hss
+\let \normalht = \ht
+\let \normalhyphenation = \hyphenation
+\let \normalhyphenchar = \hyphenchar
+\let \normalhyphenpenalty = \hyphenpenalty
+\let \normalif = \if
+\let \normalifcase = \ifcase
+\let \normalifcat = \ifcat
+\let \normalifdim = \ifdim
+\let \normalifeof = \ifeof
+\let \normaliffalse = \iffalse
+\let \normalifhbox = \ifhbox
+\let \normalifhmode = \ifhmode
+\let \normalifinner = \ifinner
+\let \normalifmmode = \ifmmode
+\let \normalifnum = \ifnum
+\let \normalifodd = \ifodd
+\let \normaliftrue = \iftrue
+\let \normalifvbox = \ifvbox
+\let \normalifvmode = \ifvmode
+\let \normalifvoid = \ifvoid
+\let \normalifx = \ifx
+\let \normalignorespaces = \ignorespaces
+\let \normalimmediate = \immediate
+\let \normalindent = \indent
+% \normalinput = \input
+\let \normalinputlineno = \inputlineno
+\let \normalinsert = \insert
+\let \normalinsertpenalties = \insertpenalties
+\let \normalinterlinepenalty = \interlinepenalty
+\let \normaljobname = \jobname
+\let \normalkern = \kern
+\let \normallanguage = \language
+\let \normallastbox = \lastbox
+\let \normallastkern = \lastkern
+\let \normallastpenalty = \lastpenalty
+\let \normallastskip = \lastskip
+\let \normallccode = \lccode
+\let \normalleaders = \leaders
+\let \normalleft = \left
+\let \normallefthyphenmin = \lefthyphenmin
+\let \normalleftskip = \leftskip
+\let \normalleqno = \leqno
+\let \normallet = \let
+\let \normallimits = \limits
+\let \normallinepenalty = \linepenalty
+\let \normallineskip = \lineskip
+\let \normallineskiplimit = \lineskiplimit
+\let \normallong = \long
+\let \normallooseness = \looseness
+\let \normallower = \lower
+\let \normallowercase = \lowercase
+\let \normalmag = \mag
+\let \normalmark = \mark
+\let \normalmathaccent = \mathaccent
+\let \normalmathbin = \mathbin
+\let \normalmathchar = \mathchar
+\let \normalmathchardef = \mathchardef
+\let \normalmathchoice = \mathchoice
+\let \normalmathclose = \mathclose
+\let \normalmathcode = \mathcode
+\let \normalmathinner = \mathinner
+\let \normalmathop = \mathop
+\let \normalmathopen = \mathopen
+\let \normalmathord = \mathord
+\let \normalmathpunct = \mathpunct
+\let \normalmathrel = \mathrel
+\let \normalmathsurround = \mathsurround
+\let \normalmaxdeadcycles = \maxdeadcycles
+\let \normalmaxdepth = \maxdepth
+\let \normalmeaning = \meaning
+\let \normalmedmuskip = \medmuskip
+\let \normalmessage = \message
+\let \normalmiddle = \middle
+\let \normalmkern = \mkern
+\let \normalmonth = \month
+\let \normalmoveleft = \moveleft
+\let \normalmoveright = \moveright
+\let \normalmskip = \mskip
+\let \normalmultiply = \multiply
+\let \normalmuskip = \muskip
+\let \normalmuskipdef = \muskipdef
+\let \normalnewlinechar = \newlinechar
+\let \normalnoalign = \noalign
+\let \normalnoboundary = \noboundary
+\let \normalnoexpand = \noexpand
+\let \normalnoindent = \noindent
+\let \normalnolimits = \nolimits
+\let \normalnonscript = \nonscript
+\let \normalnonstopmode = \nonstopmode
+\let \normalnulldelimiterspace = \nulldelimiterspace
+\let \normalnullfont = \nullfont
+\let \normalnumber = \number
+\let \normalomit = \omit
+\let \normalopenin = \openin
+\let \normalopenout = \openout
+\let \normalor = \or
+% \normalouter = \outer
+\let \normaloutput = \output
+\let \normaloutputpenalty = \outputpenalty
+\let \normalover = \over
+\let \normaloverfullrule = \overfullrule
+\let \normaloverline = \overline
+\let \normaloverwithdelims = \overwithdelims
+\let \normalpagedepth = \pagedepth
+\let \normalpagefilllstretch = \pagefilllstretch
+\let \normalpagefillstretch = \pagefillstretch
+\let \normalpagefilstretch = \pagefilstretch
+\let \normalpagegoal = \pagegoal
+\let \normalpageshrink = \pageshrink
+\let \normalpagestretch = \pagestretch
+\let \normalpagetotal = \pagetotal
+\let \normalpar = \par
+\let \normalparfillskip = \parfillskip
+\let \normalparindent = \parindent
+\let \normalparshape = \parshape
+\let \normalparskip = \parskip
+\let \normalpatterns = \patterns
+\let \normalpausing = \pausing
+\let \normalpenalty = \penalty
+\let \normalpostdisplaypenalty = \postdisplaypenalty
+\let \normalpredisplaypenalty = \predisplaypenalty
+\let \normalpredisplaysize = \predisplaysize
+\let \normalpretolerance = \pretolerance
+\let \normalprevdepth = \prevdepth
+\let \normalprevgraf = \prevgraf
+\let \normalradical = \radical
+\let \normalraise = \raise
+\let \normalread = \read
+\let \normalrelax = \relax
+\let \normalrelpenalty = \relpenalty
+\let \normalright = \right
+\let \normalrighthyphenmin = \righthyphenmin
+\let \normalrightskip = \rightskip
+\let \normalromannumeral = \romannumeral
+\let \normalscriptfont = \scriptfont
+\let \normalscriptscriptfont = \scriptscriptfont
+\let \normalscriptscriptstyle = \scriptscriptstyle
+\let \normalscriptspace = \scriptspace
+\let \normalscriptstyle = \scriptstyle
+\let \normalscrollmode = \scrollmode
+\let \normalsetbox = \setbox
+\let \normalsetlanguage = \setlanguage
+\let \normalsfcode = \sfcode
+\let \normalshipout = \shipout
+\let \normalshow = \show
+\let \normalshowbox = \showbox
+\let \normalshowboxbreadth = \showboxbreadth
+\let \normalshowboxdepth = \showboxdepth
+\let \normalshowlists = \showlists
+\let \normalshowthe = \showthe
+\let \normalskewchar = \skewchar
+\let \normalskip = \skip
+\let \normalskipdef = \skipdef
+\let \normalspacefactor = \spacefactor
+\let \normalspaceskip = \spaceskip
+\let \normalspan = \span
+\let \normalspecial = \special
+\let \normalsplitbotmark = \splitbotmark
+\let \normalsplitfirstmark = \splitfirstmark
+\let \normalsplitmaxdepth = \splitmaxdepth
+\let \normalsplittopskip = \splittopskip
+\let \normalstring = \string
+\let \normaltabskip = \tabskip
+\let \normaltextfont = \textfont
+\let \normaltextstyle = \textstyle
+\let \normalthe = \the
+\let \normalthickmuskip = \thickmuskip
+\let \normalthinmuskip = \thinmuskip
+\let \normaltime = \time
+\let \normaltoks = \toks
+\let \normaltoksdef = \toksdef
+\let \normaltolerance = \tolerance
+\let \normaltopmark = \topmark
+\let \normaltopskip = \topskip
+\let \normaltracingcommands = \tracingcommands
+\let \normaltracinglostchars = \tracinglostchars
+\let \normaltracingmacros = \tracingmacros
+\let \normaltracingonline = \tracingonline
+\let \normaltracingoutput = \tracingoutput
+\let \normaltracingpages = \tracingpages
+\let \normaltracingparagraphs = \tracingparagraphs
+\let \normaltracingrestores = \tracingrestores
+\let \normaltracingstats = \tracingstats
+\let \normaluccode = \uccode
+\let \normaluchyph = \uchyph
+\let \normalunderline = \underline
+\let \normalunhbox = \unhbox
+\let \normalunhcopy = \unhcopy
+\let \normalunkern = \unkern
+\let \normalunpenalty = \unpenalty
+\let \normalunskip = \unskip
+\let \normalunvbox = \unvbox
+\let \normalunvcopy = \unvcopy
+\let \normaluppercase = \uppercase
+\let \normalvadjust = \vadjust
+\let \normalvalign = \valign
+\let \normalvbadness = \vbadness
+\let \normalvbox = \vbox
+\let \normalvcenter = \vcenter
+\let \normalvfil = \vfil
+\let \normalvfill = \vfill
+\let \normalvfilneg = \vfilneg
+\let \normalvfuzz = \vfuzz
+\let \normalvoffset = \voffset
+\let \normalvrule = \vrule
+\let \normalvsize = \vsize
+\let \normalvskip = \vskip
+\let \normalvsplit = \vsplit
+\let \normalvss = \vss
+\let \normalvtop = \vtop
+\let \normalwd = \wd
+\let \normalwidowpenalty = \widowpenalty
+\let \normalwrite = \write
+\let \normalxdef = \xdef
+\let \normalxleaders = \xleaders
+\let \normalxspaceskip = \xspaceskip
+\let \normalyear = \year
+
+\endinput
diff --git a/tex/context/base/sort-def.mkiv b/tex/context/base/norm-xtx.tex
index 8cc92a02e..3da944656 100644
--- a/tex/context/base/sort-def.mkiv
+++ b/tex/context/base/norm-xtx.tex
@@ -1,16 +1,18 @@
%D \module
-%D [ file=sort-def,
-%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
-%D subtitle=Defaults,
+%D [ file=norm-xtx,
+%D version=2009.03.19,
+%D title=\CONTEXT\ Norm Macros,
+%D subtitle=\XETEX,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%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.
-% nothing here
+% xetex primitives
+
+% nothing yet (also defined pdftex primitives)
\endinput
diff --git a/tex/context/base/page-app.tex b/tex/context/base/page-app.tex
index 6e477903c..005ea6dd4 100644
--- a/tex/context/base/page-app.tex
+++ b/tex/context/base/page-app.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-app, % from meta-fig
%D version=1998.01.15,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Independent page building,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Applications}
+\writestatus{loading}{ConTeXt Page Macros / Applications}
%D The fitting page code is moved from \type {meta-fig} to
%D here.
diff --git a/tex/context/base/page-bck.tex b/tex/context/base/page-bck.mkii
index 10123fec6..0b4ad779a 100644
--- a/tex/context/base/page-bck.tex
+++ b/tex/context/base/page-bck.mkii
@@ -11,43 +11,27 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Backgrounds}
+\writestatus{loading}{ConTeXt Page Macros / Backgrounds}
% \chardef\kindofpagetextareas=1 will isolate graphics from backgrounds
\unprotect
-\startmessages dutch library: layouts
- 8: achtergronden berekenen
-\stopmessages
+% messages moved
-\startmessages english library: layouts
- 8: calculating backgrounds
-\stopmessages
+% messages moved
-\startmessages german library: layouts
- 8: berechne Hintergrund
-\stopmessages
+% messages moved
-\startmessages czech library: layouts
- 8: pocita se pozadi
-\stopmessages
+% messages moved
-\startmessages italian library: layouts
- 8: calcolo dello sfondo
-\stopmessages
+% messages moved
-\startmessages norwegian library: layouts
- 8: beregner bakgrunn
-\stopmessages
+% messages moved
-\startmessages romanian library: layouts
- 8: se calculeaza fundalurile
-\stopmessages
+% messages moved
-\startmessages french library: layouts
- 8: calcul des arrières-plans
-\stopmessages
+% messages moved
%D \macros
%D {recalculatebackgrounds}
@@ -384,9 +368,7 @@
\processcommalist[#1]\docommand
\else\ifsecondargument
\global\somebackgroundtrue
- \doifcommonelse{#1}{\v!text,\v!hidden,%
- %\v!linkertekst,\v!rechtertekst,%
- \v!paper,\v!page,\v!leftpage,\v!rightpage}
+ \doifcommonelse{#1}{\v!text,\v!hidden,\v!paper,\v!page,\v!leftpage,\v!rightpage}
{\def\docommand##1{\getparameters[\??ma##1][#2]\checkbackground{##1}}%
\processcommalist[#1]\docommand}%
{\setupbackgrounds
@@ -409,8 +391,6 @@
\let\pagebackgroundoffset\!!zeropoint
\let\pagebackgrounddepth \!!zeropoint
-\appendtoks\global\newbackgroundfalse\to\everyjob
-
%D Each areas (currently there are $1+3+25+1=30$ of them)
%D has its own low level framed object associated.
@@ -470,10 +450,8 @@
%D The stand alone text area inherits from the page too.
-\dodocommand\v!text \empty
-%dodocommand\v!linkertekst \empty
-%dodocommand\v!rechtertekst\empty
-\dodocommand\v!hidden \empty
+\dodocommand\v!text \empty
+\dodocommand\v!hidden\empty
%D We now define all 25 main areas in a row.
diff --git a/tex/context/base/page-bck.mkiv b/tex/context/base/page-bck.mkiv
new file mode 100644
index 000000000..2522c882d
--- /dev/null
+++ b/tex/context/base/page-bck.mkiv
@@ -0,0 +1,521 @@
+%D \module
+%D [ file=page-bck, % copied from main-001
+%D version=1997.03.31,
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Backgrounds,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Page Macros / Backgrounds}
+
+% \chardef\kindofpagetextareas=1 will isolate graphics from backgrounds
+
+\unprotect
+
+%D \macros
+%D {recalculatebackgrounds}
+%D
+%D We use a couple of switches so that we can minimize the
+%D amount of background calculations. The main switch is set
+%D by the recalculate directive.
+%D
+%D \starttyping
+%D \recalculatebackgrounds
+%D \stoptyping
+%D
+%D Other modules may not directly set the switches
+%D themselves.
+
+\newif\ifnewbackground
+\newif\ifsomebackground
+
+%D For special purposes, users can question the \type
+%D {*background} mode. This mode is only available when
+%D typesetting the pagebody.
+%D
+%D \starttyping
+%D \startmode[*background] ...
+%D \stoptyping
+
+\appendtoks
+ \ifsomebackground \ifnewbackground \setsystemmode\v!background \fi \fi
+\to \everybeforepagebody
+
+%D \macros
+%D {addmainbackground, addtextbackground,
+%D addpagebackground, addprintbackground}
+%D
+%D Apart from the previously mentioned directive, the
+%D interface between this module and the other modules
+%D is made up by four macros that add background to parts of
+%D the layout.
+%D
+%D \starttyping
+%D \addmainbackground <box>
+%D \addtextbackground <box>
+%D \addpagebackground <box>
+%D \addprintbackground <box>
+%D \stoptyping
+
+%D To minimize calculations, we keep track of the state of the
+%D background of each area. A previous implementation did
+%D check each call to the background calculation macro, but
+%D using an intermediate usage flag instead of testing each
+%D time saves about 3\% on a run with a couple of backgrounds.
+%D (On the 824 pages maps bibliography runtime went down from
+%D 309 to 299 seconds.)
+
+\let\currentotrbackground\empty
+
+\def\@@docheckbackground#1#2%
+ {\ifcsname\currentotrbackground#1\endcsname
+ \edef\!!stringa{\csname\currentotrbackground#1\endcsname}\ifx\!!stringa#2\!!doneatrue\fi
+ \fi}
+
+\def\@@nocheckbackground#1#2%
+ {\ifcsname\currentotrbackground#1\endcsname
+ \edef\!!stringa{\csname\currentotrbackground#1\endcsname}\ifx\!!stringa#2\else\!!doneatrue\fi
+ \fi}
+
+\def\checkbackground#1%
+ {\edef\currentotrbackground{\??ma#1}%
+ \begingroup
+ \!!doneafalse
+ \if!!donea\else\@@nocheckbackground\c!background \empty
+ \if!!donea\else\@@docheckbackground\c!frame \v!on
+ \if!!donea\else\@@nocheckbackground\c!foregroundcolor\empty
+ \if!!donea\else\@@docheckbackground\c!leftframe \v!on
+ \if!!donea\else\@@docheckbackground\c!rightframe \v!on
+ \if!!donea\else\@@docheckbackground\c!topframe \v!on
+ \if!!donea\else\@@docheckbackground\c!bottomframe \v!on \fi\fi\fi\fi\fi\fi\fi
+ \if!!donea
+ \endgroup\setusage \currentotrbackground
+ \else
+ \endgroup\resetusage\currentotrbackground
+ \fi}
+
+\def\ifsomebackgroundfound#1%
+ {\ifusage{\??ma#1}}
+
+\def\doifsomebackgroundelse#1%
+ {\ifusage{\??ma#1}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D The background mechanism falls back on the \type {\framed}
+%D macro. This means that all normal frame and overlay
+%D features can be used.
+
+\def\addsomebackground#1#2#3#4% area box width height / zero test added
+ {\ifsomebackgroundfound#1\ifdim#3>\zeropoint\ifdim#4>\zeropoint
+ \ifcsname\??ma#1\c!setups\endcsname % to be done
+ \doifvaluesomething{\??ma#1\c!setups}{\setups[\getvalue{\??ma#1\c!setups}]}% should not produce funny spaces !
+ \fi
+ \setbox#2\vbox\fastlocalframed
+ [\??ma#1]
+ [\c!component=#1,\c!width=#3,\c!height=#4]% are width and height used?
+ {\dp#2\zeropoint\box#2}%
+ \fi\fi\fi}
+
+%D There are quite some backgrounds. At the bottom layer,
+%D there is the {\em paper} background. This one is only
+%D used for special purposes, like annotations to documents.
+
+\def\addprintbackground#1%
+ {\addsomebackground\v!paper#1\printpaperwidth\printpaperheight}
+
+%D The page backgrounds can be put behind the {\em left
+%D page}, the {\em right page} or {\em each page}. As with
+%D the paper background, these are calculated on each page.
+
+\def\addpagebackground#1%
+ {\doifbothsidesoverruled
+ {\addsomebackground\v!rightpage#1\paperwidth\paperheight}
+ {\addsomebackground\v!rightpage#1\paperwidth\paperheight}
+ {\addsomebackground\v!leftpage #1\paperwidth\paperheight}%
+ \addsomebackground\v!page #1\paperwidth\paperheight}
+
+%D Then there are the 25 areas that make up the layout: {\em
+%D top, header, text, footer, bottom} times {\em left edge,
+%D left margin, text, right margin, right edge}. These are
+%D only recalculated when they change or when the \type
+%D {status} is set to \type {repeat}.
+
+\newbox\leftbackground
+\newbox\rightbackground
+
+\def\addmainbackground#1% todo: dimension spec
+ {\ifsomebackground
+ \ifnewbackground \setbackgroundboxes \fi
+ \setbox#1\vbox
+ {\offinterlineskip
+ \doifmarginswapelse{\copy\leftbackground}{\copy\rightbackground}%
+ \box#1}%
+ \fi}
+
+%D Finaly there is an aditional {\em text} background, again
+%D useful for special purposes only. This one is calculated
+%D each time. The hidden backgrounds are not meant for users!
+
+\newconditional\hiddenbackgroundenabled
+
+\def\addtextbackground#1%
+ {\ifconditional\hiddenbackgroundenabled
+ \addsomebackground\v!hidden#1\makeupwidth\textheight % mine !
+ \fi
+ \addsomebackground\v!text#1\makeupwidth\textheight}
+
+%D The next couple of macros implement the area backgrounds.
+%D As said, these are cached in dedicated boxes. The offsets
+%D and depth of the page are used for alignment purposes.
+
+\newdimen\pageoffset % bleed
+\newdimen\pagedepth
+
+\let\pagebackgroundhoffset\!!zeropoint
+\let\pagebackgroundvoffset\!!zeropoint
+\let\pagebackgrounddepth \!!zeropoint
+
+% \def\setbackgroundboxes
+% {\showmessage\m!layouts8\empty
+% \setbackgroundbox\leftbackground\relax
+% \ifdoublesided
+% \setbackgroundbox\rightbackground\doswapmargins
+% \fi
+% \doifnot\@@mastatus\v!herhaal{\global\newbackgroundfalse}}
+
+%D We need a bit more clever mechanism in order to handle
+%D layers well. This means that we cannot calculate both
+%D background at the same time since something may have
+%D changed halfway a page.
+
+\chardef\newrightbackground\zerocount
+\chardef\newleftbackground \zerocount
+
+\def\recalculatebackgrounds
+ {\global\newbackgroundtrue}
+
+\def\setbackgroundboxes
+ {\ifnewbackground
+ \global\chardef\newrightbackground\plusone
+ \global\chardef\newleftbackground\plusone
+ \global\setbox\leftbackground\emptybox
+ \global\setbox\rightbackground\emptybox
+ \fi
+ \doifbothsides
+ {\ifcase\newleftbackground \else
+ % \showmessage\m!layouts8\empty
+ \setbackgroundbox\leftbackground\relax
+ \global\chardef\newleftbackground\zerocount
+ \global\chardef\newrightbackground\zerocount
+ \fi}
+ {\ifcase\newleftbackground \else
+ % \showmessage\m!layouts8\empty
+ \setbackgroundbox\leftbackground\relax
+ \global\chardef\newleftbackground\zerocount
+ \fi}
+ {\ifcase\newrightbackground \else
+ % \showmessage\m!layouts8\empty
+ \setbackgroundbox\rightbackground\doswapmargins
+ \global\chardef\newrightbackground\zerocount
+ \fi}%
+ \ifx\@@mastate\v!repeat\else\global\newbackgroundfalse\fi}
+
+\def\addmainbackground#1% todo: dimension spec
+ {\ifsomebackground
+ \setbackgroundboxes
+ \setbox#1\vbox
+ {\offinterlineskip
+ \doifmarginswapelse{\copy\leftbackground}{\copy\rightbackground}%
+ \box#1}%
+ \fi}
+
+\def\setbackgroundoffsets
+ {\ifsomebackground \ifnewbackground
+ \global\let\pagebackgroundhoffset\!!zeropoint
+ \global\let\pagebackgroundvoffset\!!zeropoint
+ \global\let\pagebackgrounddepth \!!zeropoint
+ \doifsomebackgroundelse{\v!text\v!text}\donetrue\donefalse
+ \ifdone\else\doifsomebackgroundelse\v!text\donetrue\donothing\fi
+ \ifdone
+ \bgroup
+ \scratchdimen\getvalue{\??ma\v!page\c!offset}%
+ \doifsomebackgroundelse{\v!top\v!text}\donothing
+ {\doifsomebackgroundelse{\v!bottom\v!text}\donothing
+ {\xdef\pagebackgroundhoffset{\the\scratchdimen}}}%
+ \doifsomebackgroundelse{\v!text\v!rightedge}\donothing
+ {\doifsomebackgroundelse{\v!text\v!leftedge}\donothing
+ {\xdef\pagebackgroundvoffset{\the\scratchdimen}%
+ \scratchdimen\getvalue{\??ma\v!page\c!depth}%
+ \xdef\pagebackgrounddepth{\the\scratchdimen}}}%
+ \egroup
+ \fi
+ \fi \fi}
+
+\appendtoks \setbackgroundoffsets \to \everybeforepagebody
+
+\newconditional\swapbackgroundmargins \settrue\swapbackgroundmargins
+
+\def\setbackgroundbox#1#2%
+ {\global\setbox#1\vbox
+ {\dontcomplain
+ \swapmargins
+ \ifconditional\swapbackgroundmargins
+ \doifmarginswapelse \donothing
+ {\swapmacros\v!rightmargin\v!leftmargin
+ \swapmacros\v!rightedge \v!leftedge}%
+ \fi
+ \calculatereducedvsizes
+ \offinterlineskip
+ #2\relax
+ \vskip\dimexpr-\topheight-\topdistance\relax
+ \dodopagebodybackground\v!top\topheight
+ \vskip\topdistance
+ \dodopagebodybackground\v!header\headerheight
+ \vskip\headerdistance
+ \dodopagebodybackground\v!text\textheight
+ \vskip\footerdistance
+ \dodopagebodybackground\v!footer\footerheight
+ \vskip\bottomdistance
+ \dodopagebodybackground\v!bottom\bottomheight
+ \vfilll}%
+ \smashbox#1}
+
+\def\dodopagebodybackground#1#2%
+ {\ifdim#2>\zeropoint % added, faster
+ \setbox\scratchbox\vbox to #2
+ \bgroup\hbox\bgroup
+ % \swapmargins
+ \goleftonpage
+ \dododopagebodybackground\leftedgewidth #2#1\v!leftedge
+ \hskip\leftedgedistance
+ \dododopagebodybackground\leftmarginwidth #2#1\v!leftmargin
+ \hskip\leftmargindistance
+ \dododopagebodybackground\makeupwidth #2#1\v!text
+ \hskip\rightmargindistance
+ \dododopagebodybackground\rightmarginwidth#2#1\v!rightmargin
+ \hskip\rightedgedistance
+ \dododopagebodybackground\rightedgewidth #2#1\v!rightedge
+ \egroup\egroup
+ \wd\scratchbox\zeropoint
+ \box\scratchbox\relax
+ \fi}
+
+\def\dododopagebodybackground#1#2#3#4% width height pos pos
+ {\ifsomebackgroundfound{#3#4}%
+ \ifdim#2>\zeropoint\relax
+ \ifdim#1>\zeropoint\relax
+ \ifcsname\??ma#3#4\c!setups\endcsname % to be done
+ \doifvaluesomething{\??ma#3#4\c!setups}{\setups[\getvalue{\??ma#3#4\c!setups}]}% should not produce funny spaces !
+ \fi
+ \fastlocalframed
+ [\??ma#3#4]
+ [\c!component=#3-#4]
+ {\vbox to #2{\vss\hbox to#1{\hss\getvalue{\??ma#3#4\c!command}\hss}\vss}}%
+ \else
+ \hskip#1%
+ \fi
+ \else
+ \hskip#1%
+ \fi
+ \else
+ \hskip#1%
+ \fi}
+
+%D The background mechanism is quite demanding in terms or
+%D resources. We used to delay these definitions till runtime
+%D usage, but since today's \TEX's are large, we now do the
+%D work on forehand.
+%D
+%D \starttyping
+%D \setupbackgrounds [settings]
+%D \setupbackgrounds [paper,page,text,..] [settings]
+%D \setupbackgrounds [top,...] [leftedge,...] [settings]
+%D \stoptyping
+%D
+%D \showsetup{setupbackgrounds}
+%D
+%D Because the number of arguments runs from one to three,
+%D we need to check for it.
+
+\def\setupbackgrounds
+ {\dotripleempty\dosetupbackgrounds}
+
+\def\dosetupbackgrounds[#1][#2][#3]%
+ {\ifthirdargument
+ \global\somebackgroundtrue
+ \def\docommand##1%
+ {\doifinsetelse{##1}{\v!paper,\v!page,\v!leftpage,\v!rightpage}
+ {\getparameters[\??ma##1][#3]\checkbackground{##1}}
+ {\def\dodocommand####1{\getparameters[\??ma##1####1][#3]\checkbackground{##1####1}}%
+ \processcommalist[#2]\dodocommand}}%
+ \processcommalist[#1]\docommand
+ \else\ifsecondargument
+ \global\somebackgroundtrue
+ \doifcommonelse{#1}{\v!text,\v!hidden,\v!paper,\v!page,\v!leftpage,\v!rightpage}
+ {\def\docommand##1{\getparameters[\??ma##1][#2]\checkbackground{##1}}%
+ \processcommalist[#1]\docommand}%
+ {\setupbackgrounds
+ [#1]%
+ [\v!leftedge,\v!leftmargin,\v!text,\v!rightmargin,\v!rightedge]%
+ [#2]}%
+ \else\iffirstargument
+ \getparameters[\??ma][#1]%
+ \fi\fi\fi
+ \doifelsevalue{\??ma\v!page\c!offset}\v!overlay
+ {\global\pageoffset\zeropoint}
+ {\global\pageoffset\getvalue{\??ma\v!page\c!offset}}%
+ \global\pagedepth\getvalue{\??ma\v!page\c!depth}%
+ \xdef\pagebackgroundoffset{\the\pageoffset}%
+ \xdef\pagebackgrounddepth {\the\pagedepth }%
+ \doifelse\@@mastate\v!stop
+ {\global\newbackgroundfalse}
+ {\global\newbackgroundtrue }}
+
+\let\pagebackgroundoffset\!!zeropoint
+\let\pagebackgrounddepth \!!zeropoint
+
+%D Each areas (currently there are $1+3+25+1=30$ of them)
+%D has its own low level framed object associated.
+
+\def\installsomebackground#1#2{\inheritlocalframed[\??ma#1#2][\??od]}
+
+\installsomebackground \v!paper \empty
+\installsomebackground \v!page \empty
+\installsomebackground \v!leftpage \empty
+\installsomebackground \v!rightpage \empty
+
+%D The stand alone text area inherits from the page too.
+
+\installsomebackground \v!text \empty
+\installsomebackground \v!hidden \empty
+
+%D We save some keying by defining the areas using a helper:
+
+\def\docommand#1%
+ {\installsomebackground#1\v!leftedge
+ \installsomebackground#1\v!leftmargin
+ \installsomebackground#1\v!text
+ \installsomebackground#1\v!rightmargin
+ \installsomebackground#1\v!rightedge}
+
+\docommand \v!top
+\docommand \v!header
+\docommand \v!text
+\docommand \v!footer
+\docommand \v!bottom
+
+%D We need some cleanup now.
+
+\let\docommand\relax
+
+%D We now set up the individual areas to use reasonable
+%D defaults.
+
+\installsomebackground \v!paper \empty
+\installsomebackground \v!page \empty
+\installsomebackground \v!leftpage \empty
+\installsomebackground \v!rightpage \empty
+
+\getparameters
+ [\??ma\v!page]
+ [\c!offset=\!!zeropoint, % hm, so we need to force overlay elsewhere
+ \c!depth=\!!zeropoint]
+
+%D General setup:
+
+\setupbackgrounds
+ [\c!state=\c!start]
+
+%D The hidden layer can be populated by extending the
+%D following comma separated list. This only happens in core
+%D modules.
+
+% todo page-2 .. page+2 achter pagina -> bleed
+% spread-2 .. spread+2 achter spread -> spread (repeat 2 times)
+
+\def\enablehiddenbackground
+ {\global\settrue\hiddenbackgroundenabled
+ \global\somebackgroundtrue
+ \recalculatebackgrounds}
+
+\def\disablehiddenbackground
+ {\global\setfalse\hiddenbackgroundenabled}
+
+\def\hiddenbackground
+ {\v!text-2,\v!text-1,\v!foreground,\v!text+1,\v!text+2}
+
+\setupbackgrounds
+ [\v!hidden]
+ [\c!background=\hiddenbackground]
+
+% The next series is used in local (for instance floating)
+% backgrounds.
+
+\installsomebackground \v!local \empty % not really a background, invisible for users
+
+\getparameters
+ [\??ma\v!local]
+ [\c!component=local,
+ \c!background=\localbackground]
+
+\def\localbackground
+ {\v!local-2,\v!local-1,\v!foreground,\v!local+1,\v!local+2}
+
+\defineoverlay[\v!local-2][\positionoverlay{\v!local-2}]
+\defineoverlay[\v!local-1][\positionoverlay{\v!local-1}]
+\defineoverlay[\v!local+1][\positionoverlay{\v!local+1}]
+\defineoverlay[\v!local+2][\positionoverlay{\v!local+2}]
+
+\def\addlocalbackgroundtobox
+ {\ifconditional\hiddenbackgroundenabled
+ \expandafter\doaddlocalbackground
+ \else
+ \resetglobal \expandafter\gobbleoneargument
+ \fi}
+
+\def\doaddlocalbackground#1%
+ {\dodoglobal\setbox#1\hbox{\fastlocalframed[\??ma\v!local][]{\registerMPlocaltextarea{\box#1}}}%
+ \resetglobal % redundant
+ \doglobal\increment\localpositionnumber\relax} % afterwards !
+
+% Test how previous macro behaves with depth:
+%
+% \startcolumnset
+% \input tufte
+% \placefigure{none}{\framed[lines=5]{xxx}}
+% \input tufte
+% \placefigure{none}{\starttabulate\NC test\nc test\NC\NR\stoptabulate}
+% \input tufte
+% \stopcolumnset
+
+%D Because we haven't really set up backgrounds yet, we set
+%D the main efficiency switch to false.
+
+\somebackgroundfalse
+
+\protect \endinput
+
+%D Removed \quote {features}:
+%D
+%D \starttyping
+%D \startinteraction
+%D \doifmarginswapelse
+%D {\copy\leftbackground}
+%D {\copy\rightbackground}%
+%D \stopinteraction
+%D \stoptyping
+%D
+%D \starttyping
+%D \edef\setpagebackgrounddepth%
+%D {\dp#2=\the\dp#2}%
+%D \setbox#2=\vbox\localframed[\??ma#1]{...}
+%D \setpagebackgrounddepth
+%D \stoptyping
diff --git a/tex/context/base/page-flt.tex b/tex/context/base/page-flt.tex
index a0b297981..91cb25e6b 100644
--- a/tex/context/base/page-flt.tex
+++ b/tex/context/base/page-flt.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-flt,
%D version=2000.10.20,
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Floating Bodies,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Floating Bodies}
+\writestatus{loading}{ConTeXt Page Macros / Floating Bodies}
%D Some of the sidefloat settings should move to page-sid; now it's quite
%D fuzzy the way the variables are set/reset.
@@ -19,169 +19,24 @@
\unprotect
\ifx\addlocalbackgroundtobox\undefined \def\addlocalbackgroundtobox{\resetglobal\gobbleoneargument} \fi
-
-% naar supp-box.tex
-
-\def\voidbox{\box\voidb@x}
-
-\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
- {\bgroup
- \ifhbox#1\relax
- \setbox2\voidbox
- \unhbox#1%
- \doloop
- {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
- \setbox0\lastbox
- \ifvoid0
- \exitloop
- \else
- \setbox2\hbox
- {\ifhbox0 \spreadhbox0\else\box0\fi
- \ifvoid2 \else\hss\unhbox2\fi}%
- \fi}%
- \ifvoid2\else\unhbox2\fi
- \else
- \box#1%
- \fi
- \egroup}
\def\placefloats{\doflushfloats} % keep this one
-\startmessages dutch library: floatblocks
- title: plaatsblokken
- 1: -- hernummerd / -- => --
- 2: -- bewaard
- 3: -- verplaatst
- 4: -- geplaatst
- 5: volgorde aangepast
- 6: maximaal -- boven
- 7: maximaal -- onder
- 8: minder dan -- regels
- 9: volgorde verstoord
- 10: -- begrensd
- 11: geen blok opgegeven
- 12: niet gedefinieerd
- 13: er is niets te splitsen
-\stopmessages
-
-\startmessages english library: floatblocks
- title: floatblocks
- 1: -- renumbered / -- => --
- 2: -- saved
- 3: -- moved
- 4: -- placed
- 5: order adapted
- 6: n of top floats limited to --
- 7: n of bottom floats limited to --
- 8: less than -- lines
- 9: order disturbed
- 10: -- limited
- 11: no block given
- 12: undefined
- 13: there is nothing to split
-\stopmessages
-
-\startmessages german library: floatblocks
- title: Gleitobjektbloecke
- 1: -- neu nummeriert / -- => --
- 2: -- gespeichert
- 3: -- verschoben
- 4: -- plaziert
- 5: Reihenfolge angepasst
- 6: Anz. der oberen Gleitobjekte beschraengt auf --
- 7: Anz. der unteren Gleitobjekte beschraengt auf --
- 8: weniger als -- zeilen
- 9: Reigenfolge gestoert
- 10: -- begrenzt
- 11: kein Block gegeben
- 12: undefiniert
- 13: there is nothing to split
-\stopmessages
-
-\startmessages czech library: floatblocks
- title: plovouciobjekty
- 1: -- precislovano / -- => --
- 2: -- ulozeno
- 3: -- presunuto
- 4: -- umisteno
- 5: poradi prizpusobeno
- 6: pocet hornich plovoucich objektu je omezen na --
- 7: pocet spodnich plovoucich objektu je omezen na --
- 8: radku je mene nez --
- 9: poradi naruseno
- 10: -- omezeno
- 11: nedan zadny blok
- 12: nedefinovano
- 13: there is nothing to split
-\stopmessages
-
-\startmessages italian library: floatblocks
- title: oggetti mobili
- 1: -- rinumerato / -- => --
- 2: -- salvato
- 3: -- mosso
- 4: -- sistemato
- 5: ordine aggiustato
- 6: n di top floats limitato a --
- 7: n di bottom floats limitato a --
- 8: meno di -- righe
- 9: ordine disturbato
- 10: -- limitato
- 11: nessun oggetto specificato
- 12: non definito
- 13: there is nothing to split
-\stopmessages
-
-\startmessages norwegian library: floatblocks
- title: flytblokker
- 1: -- renummerert / -- => --
- 2: -- lagret
- 3: -- flyttet
- 4: -- plassert
- 5: rekkefølge tilpasset
- 6: maksimalt -- flytblokker øverst
- 7: maksimalt -- flytblokker nederst
- 8: mindre enn -- linjer
- 9: rekkefølge endret
- 10: -- begrenset
- 11: ingen blokk oppgitt
- 12: udefinert
- 13: there is nothing to split
-\stopmessages
-
-\startmessages romanian library: floatblocks
- title: Blocuri
- 1: -- renumerotat / -- => --
- 2: -- salvat
- 3: -- mutat
- 4: -- plasat
- 5: ordinea adaptata
- 6: nr. cadrelor de sus limitat la --
- 7: nr. blocurilor de jos limitat la --
- 8: mai putin de -- linii
- 9: ordinea deranjata
- 10: -- limitat
- 11: nu este dat nici un bloc
- 12: nedefinit
- 13: there is nothing to split
-\stopmessages
-
-\startmessages french library: floatblocks
- title: blocs de flottants
- 1: -- renuméroté / -- => --
- 2: -- sauvegardé
- 3: -- déplacé
- 4: -- placé
- 5: ordre adapté
- 6: n flottants de haut de page limité à --
- 7: n flottants de bas de page limité à --
- 8: moins de -- lignes
- 9: ordre perturbé
- 10: -- limité
- 11: pas de bloc donné
- 12: indéfini
- 13: there is nothing to split
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
\def\floatparameter #1{\csname\??fl\currentfloat#1\endcsname}
\def\floatcaptionparameter#1{\csname\??kj\currentfloat#1\endcsname}
@@ -395,8 +250,6 @@
\hsize\localhsize
\fi}
-\newevery \everyinsidefloat \relax
-
\appendtoks
\everyinsidefloat\emptytoks % in case it's called earlier
\dogetfloatdata
@@ -618,6 +471,7 @@
\c!leftframe=\@@bkleftframe,
\c!rightframe=\@@bkrightframe,
\c!frameoffset=\@@bkframeoffset,
+ \c!framecolor=\@@bkframecolor,
%\c!local=\@@bklocal,
\c!textmethod=\@@bktextmethod,
\c!sidemethod=\@@bksidemethod,
@@ -687,32 +541,6 @@
% \setupfloat[...][leftmargindistance=1cm,default={left,none}]
-% \def\redodefinefloat[#1][#2][#3]% same label/number
-% {\presetlocalframed[\??fl#1]%
-% \copylocalframed[\??fl#1][\??fl#3]%
-% \copyparameters[\??fl#1][\??fl#3]
-% [\c!width,\c!height,%\c!local,
-% \c!maxwidth,\c!maxheight,\c!minwidth,
-% \c!margin,\c!sidespacebefore,\c!sidespaceafter,\c!sidealign,
-% \c!leftmargindistance,\c!rightmargindistance,\c!criterium,
-% \c!leftmargin,\c!rightmargin,\c!innermargin,\c!outermargin,
-% \c!frame,\c!radius,\c!corner,\c!location,\c!background,\c!framecolor,
-% \c!backgroundscreen,\c!backgroundcolor,\c!backgroundoffset,
-% \c!topframe,\c!bottomframe,\c!leftframe,\c!rightframe,
-% \c!frameoffset,\c!pageboundaries,\c!default,
-% \c!textmethod,\c!sidemethod,\c!method]%
-% \copyparameters[\??kj#1][\??kj#3]
-% [\c!location,\c!before,\c!inbetween,\c!after,
-% \c!spacebefore,\c!spaceinbetween,\c!spaceafter,
-% \c!width,\c!headstyle,\c!headcolor,\c!style,\c!color,
-% \c!textstyle,\c!textcolor,\c!minwidth,
-% \c!align,\c!number,\c!way,\c!blockway,\c!setups,
-% \c!leftmargin,\c!rightmargin,\c!innermargin,\c!outermargin,
-% \c!sectionnumber,\c!separator,\c!stopper,\c!suffix,\c!distance,\c!conversion]%
-% \definenumber[#1][#3]%
-% \presetlabeltext[#1=\labeltext{#3}]%
-% \dodefinefloatcommands[#1][#2]}
-
\def\redodefinefloat[#1][#2][#3]% same label/number
{\presetlocalframed[\??fl#1]%
\copylocalframed[\??fl#1][\??fl#3]%
@@ -906,7 +734,7 @@
\fi
\else
\global\savednoffloats\zerocount
- \global\setbox\floatbox\box\voidb@x
+ \global\setbox\floatbox\emptybox
\fi}
\def\uncenteredfloatbox
@@ -2126,257 +1954,8 @@
\fi
\global\insidefloatfalse}
-\newif\ifmargeblokken
-
-\def\dosetupmarginblocks[#1]%
- {\getparameters[\??mb][#1]%
- \doifelse\@@mbstate\v!start
- {\showmessage\m!layouts4\empty
- \margeblokkentrue
- \let\somenextfloat\dosomenextfloat
- \let\startmarginblock\dostartmarginblock
- \let\stopmarginblock\dostopmarginblock}%
- {\showmessage\m!layouts5\empty
- \margeblokkenfalse
- \def\somenextfloat[##1]%
- {\someelsefloat[##1,\v!here]}%
- \let\startmarginblock\dontstartmargeblok
- \let\stopmarginblock\dontstopmargeblok}}
-
-\def\setupmarginblocks
- {\dosingleargument\dosetupmarginblocks}
-
-\newbox\marginbox
-
-\def\dosomenextfloat[#1]%
- {\global\setbox\marginbox\vbox
- {\hsize\@@mbwidth
- \unvcopy\marginbox
- \ifvoid\marginbox\else\expandafter\@@mbinbetween\fi
- \box\floatbox\filbreak}%
- \ifdim\ht\marginbox>\textheight
- \dosavefloatinfo
- \else
- \doinsertfloatinfo
- \fi}
-
-\newbox\preparedmarginbox
-
-\def\reshapemargin
- {\ifdim\ht\preparedmarginbox>\zeropoint
- \beginofshapebox
- \unvbox\preparedmarginbox
- \endofshapebox
- \reshapebox
- {\box\shapebox}%
- \setbox\preparedmarginbox\vbox to \textheight
- {\@@mbtop
- \flushshapebox
- \@@mbbottom}%
- \fi}
-
-\def\plaatsrechtermargeblok
- {\hskip\rightmarginwidth}
-
-\def\plaatslinkermargeblok
- {\hskip\leftmarginwidth}
-
-\def\checkmargeblokken
- {\ifvoid\marginbox\else\docheckmargeblokken\fi}
-
-\def\docheckmargeblokken % erg inefficient
- {\setbox\preparedmarginbox\vbox
- {\forgetall
- \splittopskip\topskip
- \ifvoid\marginbox\else
- \ifdim\ht\marginbox>\textheight
- \vsplit\marginbox to \textheight
- \else
- \unvbox\marginbox
- \fi
- \fi}%
- \reshapemargin
- \setbox\preparedmarginbox\vbox
- {\@@mbbefore\box\preparedmarginbox\@@mbafter}%
- \def\rightmarginbox
- {\def\plaatsrechtermargeblok
- {\setbox\preparedmarginbox\hbox to \rightmarginwidth
- {\@@mbleft\box\preparedmarginbox\@@mbright}%
- \vsmashbox\preparedmarginbox
- \box\preparedmarginbox}}%
- \def\leftmarginbox
- {\def\plaatslinkermargeblok
- {\setbox\preparedmarginbox\hbox to \leftmarginwidth
- {\@@mbright\box\preparedmarginbox\@@mbleft}%
- \vsmashbox\preparedmarginbox
- \box\preparedmarginbox}}%
- \processaction % traag
- [\@@mblocation]
- [ \v!inmargin=>\doifbothsidesoverruled\rightmarginbox\rightmarginbox\leftmarginbox,
- \v!middle=>\doifbothsidesoverruled\rightmarginbox\leftmarginbox\rightmarginbox,
- \v!left=>\leftmarginbox,
- \v!right=>\rightmarginbox,
- \s!unknown=>\setbox\preparedmarginbox\hbox{}]}
-
-\def\dostartmarginblock % 2 maal \vbox ivm \unvbox elders
- {\global\setbox\marginbox\vtop\bgroup\vbox\bgroup
- \hsize\@@mbwidth
- \ifvoid\marginbox\else
- \unvbox\marginbox
- \@@mbinbetween
- \fi
- \setupalign[\@@mbalign]%
- \dostartattributes\??mb\c!style\c!color{}%
- \begstrut\ignorespaces}
-
-\def\dostopmarginblock
- {\unskip\endstrut
- \dostopattributes
- \egroup
- \egroup}
-
-\def\dontstartmargeblok
- {\@@mbbefore
- \bgroup
- \dostartattributes\??mb\c!style\c!color\empty}
-
-\def\dontstopmargeblok
- {\dostopattributes
- \egroup
- \@@mbafter}
-
-\newcounter\nofpostponedblocks
-
-\newif\ifinpostponing
-
-\newevery\everytopofpage\relax
-
-\appendtoks \the\everytopofpage \to\everystarttext
-\appendtoks\global\everytopofpage\emptytoks\to\everystoptext
-
-% \startpostponing [pagenumber] [+pageoffset]
-%
-% \startpostponing[2]
-% PAGE 2 \blank
-% \stoppostponing
-%
-% \startpostponing[+1]
-% PAGE +1 \blank
-% \stoppostponing
-%
-% \startpostponing[+2]
-% PAGE +2 \blank
-% \stoppostponing
-%
-% \starttext \dorecurse{4}{\input tufte \page} \stoptext
-
-\newtoks \postponedpageblocks
-\newcounter\nofpostponedpageblocks
-
-% \ifinpostponing: handhaven, want gebruikt in stijlen ! ! ! ! !
-
-\def\flushpagefloats
- {\doifoddpageelse
- {\ifvoid\collectedleftpagefloats
- \ifvoid\collectedrightpagefloats\else
- \unvbox\collectedrightpagefloats
- \page
- %\the\everytopofpage
- \fi
- \fi}
- {\ifvoid\collectedleftpagefloats\else
- \unvbox\collectedleftpagefloats
- \page
- %\the\everytopofpage
- \fi
- \ifvoid\collectedrightpagefloats\else
- \unvbox\collectedrightpagefloats
- \page
- %\the\everytopofpage
- \fi}%
- \ifvoid\collectedpagefloats\else
- % message
- \unvbox\collectedpagefloats
- \fi}
-
-% \def\flushrestfloats
-% {\doif\@@bkcache\v!no\doflushfloats}
-
-% \let\flushrestfloats\relax
-
-\def\dopostponeblock
- {\bgroup % new may 2004
- \setsystemmode\v!postponing % new may 2004
- \the\everytopofpage
-% \flushrestfloats
- \flushpagefloats
- \donefalse
- \ifinpostponing \else
- \ifcase\nofpostponedblocks \else \donetrue \fi
- \ifcase\nofpostponedpageblocks \else \donetrue \fi
- \fi
- \ifdone
- \bgroup % we need the color/font switch, else problems inside split verbatim
- \setnormalcatcodes % postponing in verbatim
- \pushpostponedpagecolor
- \restoreglobalbodyfont % The \nof-test is
- \global\pagetotal\zeropoint % recently added and
- \global\inpostponingtrue % definitely needed else
- \the\postponedpageblocks % we can loose or disorder
- \dorecurse\nofpostponedblocks % floats; anyhow, this
- {\getbuffer[pbuf-\recurselevel]}% % mechanism is still
- \doflushfloats % new but potential dangerous % suboptimal and needs a
- \doglobal\newcounter\nofpostponedblocks % proper analysis
- \global\inpostponingfalse
- \poppostponedpagecolor
- \egroup
- \fi
- \egroup} % new may 2004
-
-\def\getpostponedblock#1#2%
- {\doif{#1}\realfolio{\getbuffer[rbuf-#2]}} % no \ifnum, avoid \fi
-
-% beware, \dosingleempty conflicts with buffers (feeds back the \par)
-
-\setvalue{\e!start\v!postponing}%
- {\bgroup
- \obeylines
- \doifnextcharelse[%
- {\egroup\nodostartpostponing}{\egroup\dodostartpostponing}}
-
-\def\nodostartpostponing[#1]%
- {\doglobal\increment\nofpostponedpageblocks
- \bgroup % a little bit of misusing grouping
- \doifinstring{+}{#1}\advance \realpageno#1\relax % ugly but efficient
- \doglobal\appendetoks\noexpand\getpostponedblock
- {\realfolio}{\nofpostponedpageblocks}\to\postponedpageblocks
- \egroup
- \showmessage\m!layouts3\nofpostponedpageblocks
- \dostartbuffer[rbuf-\nofpostponedpageblocks]%
- [\e!start\v!postponing][\e!stop\v!postponing]}
-
-\def\dodostartpostponing
- {\doglobal\increment\nofpostponedblocks
- \showmessage\m!layouts3\nofpostponedblocks
- \expanded{\dostartbuffer[pbuf-\nofpostponedblocks][\e!start\v!postponing][\e!stop\v!postponing]}}
-
\def\dooutput{\sidefloatoutput} % redefinition of \dooutput
-\setupmarginblocks
- [\c!state=\v!start,
- \c!location=\v!inmargin,
- \c!width=\rightmarginwidth,
- \c!style=,
- \c!color=,
- \c!align=,
- \c!left=,
- \c!right=,
- \c!top=,
- \c!inbetween=\blank,
- \c!bottom=\vfill,
- \c!before=,
- \c!after=]
-
\definefloat
[\v!figure]
[\v!figures]
@@ -2447,6 +2026,7 @@
\c!bottomframe=,
\c!leftframe=,
\c!rightframe=,
+ \c!framecolor=,
\c!frameoffset=\!!zeropoint,
\c!before=,
\c!after=,
diff --git a/tex/context/base/page-flw.tex b/tex/context/base/page-flw.tex
index 1a8ffd3c4..3eb867a78 100644
--- a/tex/context/base/page-flw.tex
+++ b/tex/context/base/page-flw.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-flw,
%D version=2003.04.19, % from test-002 (1997) profile experiment
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Text Flows,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Text Flows}
+\writestatus{loading}{ConTeXt Page Macros / Text Flows}
%D This is high experimental and especially flushing may change (proper
%D spacing is the driving force here).
diff --git a/tex/context/base/page-imp.tex b/tex/context/base/page-imp.tex
index a16f0031f..e4ece04a6 100644
--- a/tex/context/base/page-imp.tex
+++ b/tex/context/base/page-imp.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-imp, % was: core-pag,
%D version=1998.01.15,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Pagebody Building (Imposition),
%D author=Hans Hagen,
%D date=\currentdate,
@@ -13,7 +13,7 @@
% much of this can more to run time loading !
-\writestatus{loading}{Context Core Macros / Pagebody Building}
+\writestatus{loading}{ConTeXt Page Macros / Pagebody Building}
\unprotect
@@ -115,13 +115,26 @@
% moved code:
+% \def\myshipout#1%
+% {\beforeshipout % voor de pagebody dus !
+% \dontshowcomposition
+% \ifarrangingpages\@EA\actualarrange\else\@EA\actualshipout\fi
+% {\thisisrealpage\realfolio#1}%
+% \gotonextrealpage
+% \aftershipout}
+
+\def\installpagehandler#1#2% % a handler takes one argument: something to be boxed
+ {\setvalue{\??pp:\c!method:#1}{#2}} % and shipped out (don't depend on the exact package)
+
+\installpagehandler\v!normal
+ {\ifarrangingpages\expandafter\actualarrange\else\expandafter\actualshipout\fi}
+
\def\myshipout#1%
- {\beforeshipout % voor de pagebody dus !
- \dontshowcomposition
- \ifarrangingpages\@EA\actualarrange\else\@EA\actualshipout\fi
- {\thisisrealpage\realfolio#1}%
- \gotonextrealpage
- \aftershipout}
+ {\beforeshipout % voor de pagebody dus !
+ \dontshowcomposition
+ \executeifdefined{\??pp:\c!method:\@@ppmethod}\gobbleoneargument{\thisisrealpage\realfolio#1}%
+ \gotonextrealpage
+ \aftershipout}
\newbox\postponedcontent
diff --git a/tex/context/base/page-ini.tex b/tex/context/base/page-ini.mkii
index 61cd91b2b..e5c3aa41a 100644
--- a/tex/context/base/page-ini.tex
+++ b/tex/context/base/page-ini.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Initializations}
+\writestatus{loading}{ConTeXt Page Macros / Initializations}
% still a dutch/english mess
@@ -25,368 +25,6 @@
%D mechanism use a different way of looping over columns.
\unprotect
-
-% message will be distributed
-
-\startmessages dutch library: systems
- title: systeem
- 1: laden hulpfile uitgesteld (typemode)
- 2: -- geladen
-% 3: probeer LaTeX eens
- 4: commando -- is al gedefinieerd
- 5: module -- geladen
- 6: geen module -- gevonden
- 7: module -- reeds geladen
- 8: nieuwe versie hulpfile, tweede run nodig
- 9: -- niet gevonden/geplaatst
- 10: gebruik geen em in --
- 11: aanmaken basale hulpfile
- 12: de hulpfile is niet gesorteerd, gebruik texutil
- 13: markering -- gedefinieerd --
- 14: geforceerde paginaovergang in lijst voor --
- 15: wegschrijven buffer --
- 16: inlezen buffer --
- 17: verbatim inlezen buffer --
- 18: synoniem -- -- bestaat niet
- 19: betekenissen (synoniemen) van -- geladen
- 20: betekenissen (sorteren) van -- geladen
- 21: de hulpfile is niet geladen
- 22: gebruik een goede hulpfile
- 23: -- gearrangeerd op --
- 24: Plaatsblokken
- 25: Verwijzingen
- 26: Registers
- 27: Versie
-\stopmessages
-
-\startmessages english library: systems
- title: system
- 1: loading utility-file postponed (typemode)
- 2: -- loaded
-% 3: try LaTeX
- 4: command -- is already defined
- 5: module -- loaded
- 6: module -- not found
- 7: module -- already loaded
- 8: new version of utility file, second pass needed
- 9: -- not found/processed
- 10: don't use em in --
- 11: building simple util
- 12: the utility-file is not sorted, use texutil
- 13: mark -- defined --
- 14: forced newpage in list at --
- 15: saving buffer --
- 16: typesetting buffer --
- 17: typesetting verbatim buffer --
- 18: synonym -- -- does not exist
- 19: meaning (synonyms) of -- loaded
- 20: meaning (sorts) of -- loaded
- 21: no utility data is loaded
- 22: use a valid utilityfile
- 23: -- arranged at --
- 24: Floatblocks
- 25: References
- 26: Registers
- 27: Version
-\stopmessages
-
-\startmessages german library: systems
- title: system
- 1: Laden der Hilfsdatei aufgeschoben (Eingabe-Modus)
- 2: -- geladen
-% 3: Versuche LaTeX
- 4: Befehl -- ist bereits definiert
- 5: Modul -- geladen
- 6: Modul -- gefunden
- 7: Modul -- bereits geladen
- 8: Neue Version der Hilfsdatei, zweiter Durchlauf benoetigt
- 9: -- nicht gefunden/verarbeitet
- 10: Benutzte kein em in --
- 11: Erstelle einfache Hilfdatei
- 12: Die Hilfdatei ist nicht sortiert, verwende texutil
- 13: Beschriftung -- definiert --
- 14: Erzwungendes Seitenumbruch in Liste bei --
- 15: Speichere Buffer --
- 16: Setzte Buffer --
- 17: Setzte tippen-Buffer --
- 18: Synonym -- -- existiert nicht
- 19: Bedeutung (synonyme) von -- geladen
- 20: Bedeutung (sortieren) von -- geladen
- 21: Die Hilfsdatei ist nicht geladen
- 22: Benoetige gueltige Hilfsdateie
- 23: -- angeordnet auf --
- 24: Fliessbloecke
- 25: Referenzen
- 26: Register
- 27: Version
-\stopmessages
-
-\startmessages czech library: systems
- title: system
- 1: nacteni pomocneho souboru odlozeno (typemode)
- 2: -- nacteno
-% 3: zkuste LaTeX
- 4: prikaz -- je jiz definovan
- 5: makra z -- nactena
- 6: zadna makra v -- nenalezena
- 7: makra z -- jsou jiz nactena
- 8: nova verze pomocneho souboru, je treba druheho behu
- 9: -- nenalezeno/nezpracovano
- 10: nepouzivejte em v --
- 11: vytvarim jednoduchy pomocny soubor
- 12: pomosny soubor neni setriden, pouzijte texutil
- 13: znacka -- definovana --
- 14: vynucena nova stranka v seznamu na --
- 15: uklada se buffer --
- 16: sazi se buffer --
- 17: sazi se doslovny (verbatim) buffer --
- 18: synonymum -- -- neexistuje
- 19: vyznam (synonyma) -- nacten
- 20: vyznam (trideni) -- nacten
- 21: pomocny soubor necten
- 22: pouzijte platny pomocny soubor
- 23: -- upraveno na --
- 24: plovouci bloky
- 25: reference
- 26: registry
- 27: verze
-\stopmessages
-
-\startmessages italian library: systems
- title: sistema
- 1: caricamento dei file supplementari posticipato (typemode)
- 2: -- caricato
-% 3: provare LaTeX
- 4: comando -- già definito
- 5: macro del modulo -- caricate
- 6: nessuna macro trovata nel modulo --
- 7: macro del modulo -- già caricate
- 8: nuova versione del file supplementare, seconda passata necessaria
- 9: -- non trovato/elaborato
- 10: non usare em in --
- 11: costruzione di un semplice supplemento
- 12: file di supplemento non ordinato, usare texutil
- 13: marcatura -- definita --
- 14: nuova pagina obbligata in lista a --
- 15: salvataggio del buffer --
- 16: composizione del buffer --
- 17: composizione verbatim del buffer --
- 18: sinonimo -- -- non esistente
- 19: significato (sinonimi) di -- caricato
- 20: significato (specie) di -- caricato
- 21: nessuna informazione supplementare caricata
- 22: usare un file supplementare valido
- 23: -- sistemato a --
- 24: Oggetti mobili
- 25: Riferimenti
- 26: Registri
- 27: Versione
-\stopmessages
-
-\startmessages norwegian library: systems
- title: system
- 1: innlesning av hjelpefila utsatt (typemode)
- 2: -- er lest inn
-% 3: forsøker LaTeX
- 4: kommando -- er allerede definert
- 5: makroene i modul -- er lest inn
- 6: ingen makroer funnet i modul ---
- 7: makroene i modul -- er allerede lest inn
- 8: ny versjon av hjelpefil, andre gjennomkjøring nødvendig
- 9: -- ikke funnet/behandlet
- 10: ikke bruk em i --
- 11: lager enkel hjelpefil
- 12: hjelpefila er ikke sortert, bruk texutil
- 13: markering -- definert --
- 14: tvunget sideskift i liste ved --
- 15: lagrer Buffer --
- 16: tegnsetter buffer --
- 17: tegnsetter verbatim-buffer --
- 18: synonym -- -- eksisterer ikke
- 19: betydning (synonymer) av -- er lest inn
- 20: betydning (sorterer) av -- er lest inn
- 21: hjelpefila er ikke lest inn
- 22: bruk en gyldig hjelpefil
- 23: -- arrangert på --
- 24: Flytblokker
- 25: Referanser
- 26: Registere
- 27: Versjon
-\stopmessages
-
-\startmessages romanian library: systems
- title: sistem
- 1: se incarca utilitarul-fisierul este amanat (typemode)
- 2: -- s-a incarcat
-% 3: incercati LaTeX
- 4: comanda -- este deja definita
- 5: macro-urile din modulul -- s-au incarcat
- 6: nu s-au gasit macro-uri in modulul --
- 7: macro-urile din modulul -- s-au incarcat deja
- 8: o noua versiune de fisier utilitar, este necesara o noua trecere
- 9: -- nu este gasit/procesat
- 10: nu folositi em in --
- 11: se creeaza un utilitar simplu
- 12: fisierul utilitar nu este sortat, folositi texutil
- 13: marcajul -- definit --
- 14: s-a fortat trecere pa pagina noua in lista la --
- 15: buffer salvat --
- 16: buffer-ul -- s-a cules
- 17: se culege buffer-ul verbatim --
- 18: sinonimul -- -- nu exista
- 19: intelesul (sinonimele) pentru -- incarcat
- 20: intelesul (ordinea) pentru -- incarcat
- 21: nici o data utilitara nu este incarcata
- 22: folositi un fisier utilitar valid
- 23: -- aranjat la --
- 24: Blocuri
- 25: Referinte
- 26: Registri
- 27: Versiune
-\stopmessages
-
-\startmessages french library: systems
- title: système
- 1: chargement de fichier utilitaire reporté (typemode)
- 2: -- chargé
-% 3: try LaTeX
- 4: la commande -- est déjà définie
- 5: module -- chargé
- 6: module -- non trouvé
- 7: module -- déjà chargé
- 8: nouvelle version de fichier utilitaire, seconde passe nécessaire
- 9: -- non trouvé/traité
- 10: n'utilisez pas em dans --
- 11: construction util simple
- 12: le fichier utilitaire n'est pas trié, utilise texutil
- 13: marquage -- defini --
- 14: nouvellepage forcée dans la liste à --
- 15: sauvegarde du tampon (buffer) --
- 16: composition du tampon (buffer) --
- 17: composition textuelle du tampon (buffer) --
- 18: le synonyme -- -- n'existe pas
- 19: signification (synonymes) de -- chargée
- 20: signification (tris) de -- chargée
- 21: pas de données utilitaires chargées
- 22: utilise un fichier utilitaire valide
- 23: -- arrangé à --
- 24: blocsflottants
- 25: Réferences
- 26: Registres
- 27: Version
-\stopmessages
-
-\startmessages dutch library: layouts
- title: layout
- 1: teksthoogte aangepast met -- op pagina --
- 2: -- maal uitgestelde tekst tussengevoegd
- 3: -- maal tekst plaatsen uitstellen
- 4: margeblokken actief
- 5: margeblokken inactief
- 6: subpagina reeks -- verwerkt (aantal --)
-% 7: beeldmerken berekenen
-% 8: achtergronden berekenen
- 10: -- en -- tellen niet op tot 1.0
- 11: interlinie -- niet toegestaan in gridmode
-\stopmessages
-
-\startmessages english library: layouts
- title: layout
- 1: textheight adapted with -- at page --
- 2: -- times postponed text placed
- 3: -- times text postponed
- 4: marginblocks active
- 5: marginblocks inactive
- 6: subpage set -- processed (size --)
-% 7: calculating logospace
-% 8: calculating backgrounds
- 10: -- and -- don't add up to 1.0
- 11: spacing -- not permitted in gridmode
-\stopmessages
-
-\startmessages german library: layouts
- title: Layout
- 1: Texthoehe angepasst mit -- auf Seite --
- 2: -- mal verschobener Text plaziert
- 3: -- mal Text verschoben
- 4: marginalbloecke aktiv
- 5: marginalbloecke inaktiv
- 6: Unterseitenfolge -- verarbeitet (Groesse --)
-% 7: berechne Platz des Logo
-% 8: berechne Hintergrund
- 10: -- und -- ergeben zusammen nicht 1.0
- 11: Zwischenraum -- nicht im Grittermoduserlau
-\stopmessages
-
-\startmessages czech library: layouts
- title: layout
- 1: vyska textu prizpusobena s -- na strane --
- 2: -- krat odlozeny text umisten
- 3: -- krat text odlozen
- 4: okrajove bloky aktivni
- 5: okrajove bloky neaktivni
- 6: sada stran -- zpracovana (velikost --)
-% 7: pocita se misto pro logo
-% 8: pocita se pozadi
- 10: -- a -- nedava dohromady 1.0
- 11: svisla mezera -- neni povolena v pevnem radkovem rejstriku
-\stopmessages
-
-\startmessages italian library: layouts
- title: layout
- 1: altezza del testo adattata con -- a pagina --
- 2: posizionato testo posticipato -- volte
- 3: testo posticipato -- volte
- 4: blocchi in margine attivi
- 5: blocchi in margine inattivi
- 6: gruppo di sottopagine -- elaborato (dimensione --)
-% 7: calcolo dello spazio per logo
-% 8: calcolo dello sfondo
- 10: -- e -- non sommano a 1.0
- 11: spaziatura -- non permessa in modo griglia
-\stopmessages
-
-\startmessages norwegian library: layouts
- title: layout
- 1: teksthøyde tilpasset med -- på side --
- 2: -- ganger forskjøvet tekst plassert
- 3: -- ganger tekst forskjøvet
- 4: margblokker aktive
- 5: margblokker inaktive
- 6: delside sett -- behandlet (størrelse --)
-% 7: beregner plass for logo
-% 8: beregner bakgrunn
- 10: -- og -- er ikke 1.0 til sammen
- 11: mellomrom -- ikke tillatt i gridmodus
-\stopmessages
-
-\startmessages romanian library: layouts
- title: aranjamente
- 1: textheight adaptat cu -- la pagina --
- 2: textul amanat de -- ori a fost plasat
- 3: textul amanat de -- ori
- 4: blocuri marginale active
- 5: blocuri marginale inactive
- 6: setul -- de subpagini procesat (dimensiunea --)
-% 7: se calculeaza spatiul pentru logo
-% 8: se calculeaza fundalurile
- 10: -- si -- nu se adauga pana la 1.0
- 11: spatierea -- nu este permisa in gridmode
-\stopmessages
-
-\startmessages french library: layouts
- title: calque
- 1: hauteurtexte adaptée avec -- à la page --
- 2: -- times postponed text placed
- 3: -- times text postponed
- 4: blocsmarge actifs
- 5: blocsmarge inactifs
- 6: jeu de souspage -- traité (taille --)
-% 7: calculating logospace
-% 8: calculating backgrounds
- 10: -- et -- ne sont pas ajoutés à 1.0
- 11: espacement -- non permis en modegrille
-\stopmessages
\def\m!otr{otr}
@@ -420,7 +58,12 @@
\ifx\realpageno\undefined
- \countdef\realpageno\zerocount \realpageno\plusone
+ \countdef\realpageno = 0 \realpageno = 1
+ \countdef\userpageno = 1 \userpageno = 1
+ \countdef\subpageno = 2 \subpageno = 0 % !!
+ \countdef\arrangeno = 3 \arrangeno = 0 % !!
+
+ \let\pageno\userpageno
\fi
@@ -490,141 +133,21 @@
%
% tricky in balancing mode, a la huidige multi columns
-\startmessages dutch library: columns
- title: kolommen
- 1: maximaal -- kolommen
- 2: gebruik eventueel \string\filbreak
- 3: probleempje, probeer [balanceren=nee]
- 4: plaatsblok boven nog niet mogelijk
- 5: plaatsblok onder nog niet mogelijk
- 6: -- plaatsblok(en) opgeschort
- 7: balanceren afgebroken na 100 stappen
- 8: gebalanceerd in -- stap(pen)
- 9: uitlijnen controleren!
- 10: (minder dan) 1 regel over
- 11: plaatsblok te breed voor kolom
- 12: plaatsblok verplaatst naar volgende kolom / --
- 13: breed figuur geplaatst boven kolommen
-\stopmessages
-
-\startmessages english library: columns
- title: columns
- 1: only -- columns possible
- 2: use \string\filbreak\space as alternative
- 3: problems, disable balancing
- 4: top float not yet supported
- 5: bottom float not yet supported
- 6: -- float(s) postponed
- 7: balancing aborted after 100 steps
- 8: balanced in -- step(s)
- 9: check raggedness
- 10: (less than) 1 line left
- 11: float too wide for column
- 12: float moved to next column / --
- 13: wide float moved to top of columns
-\stopmessages
-
-\startmessages german library: columns
- title: Spalten
- 1: nur -- Spalten moeglich
- 2: benutzte \string\filbreak\space als Alternative
- 3: Problem, verwende [ausgleich=nein]
- 4: Gleitobjekt oben ncoh nicht unterstuetzt
- 5: Gleitobjekt unten ncoh nicht unterstuetzt
- 6: -- Gleitobjekt(e) verschoben
- 7: ausgleich nach 100 Schritten abgebrocheb
- 8: ausgeglichen nach -- Schritt(en)
- 9: Ausrichtung ueberpruefen
- 10: (weniger als) 1 Zeile uebrig
- 11: Gleitobjekt zu breit fuer Spalte
- 12: Gleitobjekt in naechste Zeile verschoben / --
- 13: breites Gleitobjekt an den Anfang der Spalten verschoben
-\stopmessages
-
-\startmessages czech library: columns
- title: sloupce
- 1: je mozno pouze -- sloupcu
- 2: pouzijte \string\filbreak\space jako alternativu
- 3: problem, vypina se vyvazovani
- 4: horni plovouci objekt jeste neni podporovan
- 5: spodni plovouci objekt jeste neni podporovan
- 6: -- plovouci objekt(y) odlozeny
- 7: vyvazovani ukonceno po 100 krocich
- 8: vyvazeno v -- krocich
- 9: kontrola nerovnost
- 10: zbyl (mene nez) 1 radek
- 11: plovouci objekt je pro sloupec prilis siroky
- 12: plovouci objekt je presunut do nasledujiciho sloupce / --
- 13: siroky plovouci objekt je presunut nad sloupce
-\stopmessages
-
-\startmessages italian library: columns
- title: colonne
- 1: solo -- colonne possibili
- 2: in alternativa, usare \string\filbreak
- 3: problemi, disabilitare il bilanciamento
- 4: float in cima non ancora supportato
- 5: float in fondo non ancora supportato
- 6: -- float(s) posticipate
- 7: bilanciamento annullato dopo 100 passi
- 8: bilanciamento in -- passo/i
- 9: controllare seghettamento
- 10: (meno di) una riga rimasta
- 11: oggetto mobile troppo ampio per la colonna
- 12: oggetto mobile spostata alla colonna successiva / --
- 13: oggetto mobile ampio spostato sopra le colonne
-\stopmessages
-
-\startmessages norwegian library: columns
- title: kolonner
- 1: maksimalt -- kolonner
- 2: bruk \string\filbreak\space som et alternativ
- 3: problemer, slår av balansering
- 4: flytblokker øverst er ikke støttet enda
- 5: flytblokker nedert er ikke støttet enda
- 6: -- flytblokk forskjøvet
- 7: balansering avbrutt etter 100 iterasjoner
- 8: balansert etter -- iterasjoner
- 9: kontroller tekstlayout!
- 10: (mindre enn) 1 linje igjen
- 11: flytblokk for bredt for kolonna
- 12: flytblokk forskjøvet til neste kolonne / --
- 13: bred flytblokk forksjøvet til toppen av kolonnene
-\stopmessages
-
-\startmessages romanian library: columns
- title: coloane
- 1: este posibil numai -- coloane
- 2: folositi \string\filbreak\space ca alternativa
- 3: probleme, se dezactiveaza alinierea
- 4: cadrele top (top float) nu sunt inca suportate
- 5: cadrele bottom (bottom float) nu sunt inca suportate
- 6: -- blocurile sunt amanate
- 7: alinierea este oprita dupa 100 de incercari
- 8: aliniat in -- pas(i)
- 9: verificat alinierea
- 10: a mai ramas (mai putin de) 1 linie
- 11: blocul este prea lat pentru coloana
- 12: blocul este mutat pe urmatoarea coloana / --
- 13: blocul lat este mutat in partea de sus a coloanelor
-\stopmessages
-
-\startmessages french library: columns
- title: colonnes
- 1: seules -- colonnes possibles
- 2: utilisez \string\filbreak\space en tant qu'alternative
- 3: problèmes, désactive l'équilibrage
- 4: flottant en partie supérieure pas encore supporté
- 5: flottant en partie inférieure pas encore supporté
- 6: -- flottant(s) reporté(s)
- 7: équilibrage abandonné après 100 pas
- 8: équilibré en -- pas
- 9: vérification des irrégularités
- 10: (moins de) 1 ligne restante
- 11: flottant mis à la largeur de la colonne
- 12: flottant déplacé à la colonne suivante / --
- 13: flottant large déplacé dans la partie supérieure de la colonne
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
\ifx\dosetuplayout\undefined % overloaded in page-lay !
@@ -636,8 +159,8 @@
\ifx\mkprocesspagecontents \undefined\let\mkprocesspagecontents \gobbleoneargument\fi
\ifx\mkprocessboxcontents \undefined\let\mkprocessboxcontents \gobbleoneargument\fi
-\def\normalejectpenalty{-\@M} \let\ejectpenalty\normalejectpenalty
-\def\normalsuperpenalty{-\@MM} \let\superpenalty\normalsuperpenalty
+\def\normalejectpenalty{-\plustenthousand } \let\ejectpenalty\normalejectpenalty
+\def\normalsuperpenalty{-\plustwentythousand} \let\superpenalty\normalsuperpenalty
%D In case we're not running \ETEX, we need to bypass a
%D couple of primitives.
@@ -707,7 +230,7 @@
\newtoks \mainoutput
\newcount\otrlevel
-% When issuing two \par\penalty-\@M's, only the first
+% When issuing two \par\penalty-\plustenthousand's, only the first
% triggers the otr; obscure feature or optimization?
\def\outputcounter{-100010} % -10010
@@ -919,8 +442,8 @@
% to be replaced by \page[now] \page[final] / merged
-% \def\eject {\par\penalty-\@M } % == {\par\break} % plain
-% \def\supereject {\par\penalty-\@MM} % also plain
+% \def\eject {\par\penalty-\plustenthousand } % == {\par\break} % plain
+% \def\supereject {\par\penalty-\plustwentythousand} % also plain
\def\eject {\par\ifvmode\penalty\ejectpenalty\fi\resetpagebreak} % == {\par\break} % plain
\def\supereject {\par\ifvmode\penalty\superpenalty\fi\resetpagebreak} % also plain
@@ -1382,7 +905,7 @@
% not here
-\newif\ifpaginageblokkeerd \paginageblokkeerdfalse
+\newif\ifpagebreakdisabled \pagebreakdisabledfalse
% \chardef\testpagemethod=0 % todo: \testnewpage[method=,lines=,voffset=]
%
@@ -1392,7 +915,7 @@
% \def\dotestpage[#1][#2][#3]%
% {%\relax % needed before \if
% \endgraf
-% \ifpaginageblokkeerd
+% \ifpagebreakdisabled
% % do nothing
% \else
% %ifnum#1=\plusone\synchronizeoutput\fi
@@ -1446,7 +969,7 @@
\def\dotestpage[#1][#2][#3]% don't change, only add more methods
{\relax % needed before \if
- \ifpaginageblokkeerd
+ \ifpagebreakdisabled
\endgraf
\else
% new from here
@@ -1545,7 +1068,7 @@
\def\page{\pagebreak} % the short form of \pagebreak (mult-com one)
\def\resetpagebreak
- {\global\paginageblokkeerdfalse}
+ {\global\pagebreakdisabledfalse}
\def\simplifypagebreak
{\def\dopagebreak[##1]{\goodbreak}}
@@ -1628,10 +1151,10 @@
\resetpagebreak}
\installpagebreakhandler \v!disable
- {\global\paginageblokkeerdtrue}
+ {\global\pagebreakdisabledtrue}
\installpagebreakhandler \v!yes
- {\ifpaginageblokkeerd\else
+ {\ifpagebreakdisabled\else
\ejectinsert
\gotonextpage
\ifinsidecolumns % this will move to MUL
@@ -1640,7 +1163,7 @@
\fi}
\installpagebreakhandler \v!makeup % ??
- {\ifpaginageblokkeerd\else
+ {\ifpagebreakdisabled\else
\eject
\fi}
@@ -1650,12 +1173,12 @@
\fi}
\installpagebreakhandler \v!no
- {\ifpaginageblokkeerd\else
+ {\ifpagebreakdisabled\else
\dosomebreak\nobreak
\fi}
\installpagebreakhandler \v!preference
- {\ifpaginageblokkeerd\else
+ {\ifpagebreakdisabled\else
\ifinsidecolumns % this will move to MUL
\dosomebreak\goodbreak
\else
@@ -1664,7 +1187,7 @@
\fi}
\installpagebreakhandler \v!bigpreference
- {\ifpaginageblokkeerd\else
+ {\ifpagebreakdisabled\else
\ifinsidecolumns % this will move to MUL
\dosomebreak\goodbreak
\else
@@ -1817,8 +1340,6 @@
% We don't want spurious last pages (due to left over marks):
-\ifx\undefined\normalshipout \let\normalshipout=\shipout \fi
-
\def\noshipout
{\writestatus\m!systems{ignoring further shipouts}%
\global\advance\realpageno\minusone % else no flush of resources
diff --git a/tex/context/base/page-ini.mkiv b/tex/context/base/page-ini.mkiv
new file mode 100644
index 000000000..4aedf171e
--- /dev/null
+++ b/tex/context/base/page-ini.mkiv
@@ -0,0 +1,1549 @@
+%D \module
+%D [ file=page-ini,
+%D version=2000.10.20,
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Initializations,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Page Macros / Initializations}
+
+% still a dutch/english mess
+
+%D This class of modules implements the output routines and
+%D floating body support. Although the modules are relatively
+%D new, the code herein is rather old. This reordering was
+%D needed when column sets were implemented and sharing code
+%D started to make sense.
+
+%D The history shows from the code, since both column
+%D mechanism use a different way of looping over columns.
+
+\unprotect
+
+\def\m!otr{otr}
+
+\chardef\normalpagebox=255
+
+\newbox\pagebox
+
+\ifx\recalculatelayout\undefined
+
+ \let \recalculatelayout \relax
+
+\fi
+
+\ifx\recalculatelogos\undefined
+
+ \let \recalculatelogos \relax
+ \let \addlogobackground \gobbleoneargument % <box>
+
+\fi
+
+\ifx\recalculatebackgrounds\undefined
+
+ \let \recalculatebackgrounds \relax
+ \let \addmainbackground \gobbleoneargument % <box>
+ \let \addtextbackground \gobbleoneargument % <box>
+ \let \addpagebackground \gobbleoneargument % <box>
+ \let \addprintbackground \gobbleoneargument % <box>
+ \let \addstatusinfo \gobbleoneargument % <box>
+
+\fi
+
+\ifx\realpageno\undefined
+
+ \countdef\realpageno = 0 \realpageno = 1
+ \countdef\userpageno = 1 \userpageno = 1
+ \countdef\subpageno = 2 \subpageno = 0 % !!
+ \countdef\arrangeno = 3 \arrangeno = 0 % !!
+
+ \let\pageno\userpageno
+
+\fi
+
+\ifx\realfolio\undefined
+
+ \def\realfolio{\the\realpageno}
+
+\fi
+
+\newcount\nofshipouts
+
+\appendtoks
+ \global\advance\nofshipouts\plusone
+\to \everyaftershipout
+
+% principle:
+%
+% multiple otr's
+%
+% (1) single column, simple routine (old one)
+% (2) multi column, collect and split routine (old one)
+% (3) multi column, page by page (new one, needed for taco)
+% (4) single column, spread handling (for fun)
+% (5) multi column, page by page, spread handling (as challenge)
+%
+% common components
+%
+% (1) float placement
+% (2) float flushing
+% (3) page body building
+% (4) ...
+%
+% ort
+%
+% + balancing
+% - mixed / one / multi / balancetofit
+% + backgrounds
+% + pre / post
+% + distances / heights
+% + ragged / baseline / normal
+% - pos sync
+% - last page
+%
+% - itemize / subtexts -> old mechanism
+%
+% floats
+%
+% - top / bottom / side / page / column / spead
+% - flush / packed flush / current page / next page / area
+%
+% footnotes
+%
+% + carry over pre column / local to column
+% + last column / pre last column / each column
+% - multiple classes
+% - area / page / end
+%
+% areas
+%
+% - top / bottom / mid in spread
+%
+% IMPORTANT
+%
+% switchtobodyfont in between ivm top
+
+% floats:
+%
+% tricky in balancing mode, a la huidige multi columns
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+\ifx\dosetuplayout\undefined % overloaded in page-lay !
+
+ \def\setuplayout{\dodoubleempty\getparameters[\??ly]}
+
+\fi
+
+\ifx\mkprocesscolumncontents\undefined\let\mkprocesscolumncontents\gobbleoneargument\fi
+\ifx\mkprocesspagecontents \undefined\let\mkprocesspagecontents \gobbleoneargument\fi
+\ifx\mkprocessboxcontents \undefined\let\mkprocessboxcontents \gobbleoneargument\fi
+
+\def\normalejectpenalty{-\plustenthousand } \let\ejectpenalty\normalejectpenalty
+\def\normalsuperpenalty{-\plustwentythousand} \let\superpenalty\normalsuperpenalty
+
+%D In case we're not running \ETEX, we need to bypass a
+%D couple of primitives.
+
+% ONE = single column
+% MUL = multi column
+% SET = columns sets
+
+\def\@@OTR{OTR}
+
+\let\OTRdefault\empty
+
+\def\OTRcommand#1%
+ {\csname\@@OTR
+ \ifcsname\@@OTR\OTRidentifier\strippedcsname#1\endcsname
+ \OTRidentifier
+ \else\ifcsname\@@OTR\OTRdefault\strippedcsname#1\endcsname % fallback
+ \OTRdefault
+ \fi\fi
+ \strippedcsname#1\endcsname}
+
+% obsolete
+
+\def\installotr#1% andere naam, beter \connectotr of zo
+ {\def\OTRidentifier{#1}}
+
+\def\activateotr#1#2%
+ {\def\OTRidentifier{#1}%
+ \def\OTRdefault {#2}}
+
+%D The initialization of the \type {\hsize} and \type {\vsize}
+%D depends on the OTR used.
+
+\def\setvsize {\OTRcommand\setvsize}
+\def\sethsize {\OTRcommand\sethsize}
+\def\finalsidefloatoutput {\OTRcommand\finalsidefloatoutput}
+\def\dopagecontents {\OTRcommand\dopagecontents}
+
+\def\dosettopinserts {\OTRcommand\dosettopinserts}
+\def\dosetbotinserts {\OTRcommand\dosetbotinserts}
+\def\dotopinsertions {\OTRcommand\dotopinsertions}
+\def\dobotinsertions {\OTRcommand\dobotinsertions}
+\def\dosetbothinserts {\OTRcommand\dosetbothinserts}
+
+\def\doflushfloats {\OTRcommand\doflushfloats}
+\def\flushfloatbox {\OTRcommand\flushfloatbox}
+\def\docheckiffloatfits {\OTRcommand\docheckiffloatfits}
+
+\def\someherefloat {\OTRcommand\someherefloat}
+\def\somefixdfloat {\OTRcommand\somefixdfloat}
+\def\somepagefloat {\OTRcommand\somepagefloat}
+\def\sometopsfloat {\OTRcommand\sometopsfloat}
+\def\somebotsfloat {\OTRcommand\somebotsfloat}
+\def\somesidefloat {\OTRcommand\somesidefloat}
+
+\def\flushsavedfloats {\OTRcommand\flushsavedfloats}
+
+\def\synchronizehsize {\OTRcommand\synchronizehsize}
+
+\def\gotonextpage {\OTRcommand\gotonextpage }
+\def\gotonextpageX{\OTRcommand\gotonextpageX} % will become obsolete
+
+% beter een \installotr#1 met #1 = macro en auto test
+
+\newif \iftraceotr
+\newif \ifinotr
+\newtoks \mainoutput
+\newcount\otrlevel
+
+% When issuing two \par\penalty-\plustenthousand's, only the first
+% triggers the otr; obscure feature or optimization?
+
+\def\outputcounter{-100010} % -10010
+
+\def\doinvokeoutput
+ {\iftraceotr
+ \expandafter\dodotracedoutput
+ \else
+ \expandafter\dodoinvokeoutput
+ \fi}
+
+\def\outputmessage#1#2#3%
+ {\iftraceotr\writestatus\m!otr{#1 #2 \number#3}\fi}
+
+\def\dodoinvokeoutput#1%
+ {\outputmessage+{special}{#1}%
+ \bgroup\par\penalty#1\relax\egroup
+ \outputmessage-{special}{#1}}
+
+\def\dodotracedoutput#1%
+ {\outputmessage+{traced}{#1/\the\outputpenalty}%
+ \writestatus\m!otr{c:\number\mofcolumns,v:\the\vsize,g:\the\pagegoal,t:\the\pagetotal}%
+ \dodoinvokeoutput{#1}%
+ \writestatus\m!otr{c:\number\mofcolumns,v:\the\vsize,g:\the\pagegoal,t:\the\pagetotal}%
+ \outputmessage-{traced}{#1/\the\outputpenalty}}
+
+\def\installoutput#1#2% \invoke \action
+ {\decrement\outputcounter
+ \edef#1{\noexpand\doinvokeoutput{\outputcounter}}%
+ \setvalue{\@@OTR\outputcounter}{#2}}
+
+\def\invokeoutputroutine
+ {\outputmessage+{trying}\outputpenalty
+ \executeifdefined{\@@OTR\the\outputpenalty}\dodonormaloutput
+ \outputmessage-{trying}\outputpenalty}
+
+\def\dodonormaloutput
+ {\outputmessage+{normal}\outputpenalty
+ \the\OTRcommand\output
+ \outputmessage-{normal}\outputpenalty}
+
+\mainoutput{\invokeoutputroutine} \output{\inotrtrue\the\mainoutput}
+
+%D Some hooks:
+
+\output{\inotrtrue\the\everybeforeoutput\the\mainoutput\the\everyafteroutput}
+
+\ifx\pagediscards\undefined \let\pagediscards\relax \fi
+
+\installoutput\synchronizeoutput % maybe add pagediscards
+ {\ifvoid\normalpagebox\else
+ \unvbox\normalpagebox
+ \pagediscards % maybe not needed ?
+ \fi}
+
+\installoutput\discardpage
+ {\setbox\scratchbox\box\normalpagebox}
+
+%D In order to force consistent use of variables, we
+%D predefine a lot of them here.
+
+%D The next two registers can be used to store pre column
+%D material as well as footnotes or so.
+
+\newbox\precolumnbox \newdimen\precolumnboxheight
+\newbox\postcolumnbox \newdimen\postcolumnboxheight
+
+%D We reserve a counter for the number of columns as well as
+%D the current column. Both are not to be changed by users!
+
+\newcount\nofcolumns \nofcolumns = 1
+\newcount\mofcolumns \mofcolumns = 1
+
+\chardef\maxnofcolumns = 50
+\chardef\allocatednofcolumns = 0
+
+%D The next dimensions reports the final column height
+
+\newdimen\finalcolumnheights
+\newcount\finalcolumnlines
+
+%D During initialization the temporary boxes are allocated.
+%D This enables us to use as much columns as we want, without
+%D exhausting the pool of boxes too fast. We could have packed
+%D them in one box, but we've got enough boxes.
+%D
+%D Two sets of boxes are declared, the txtboxes are used for
+%D the text, the topboxes are for moved column floats.
+
+\def\@col@{@col@}
+
+\def\initializecolumns#1%
+ {\ifnum#1>\maxnofcolumns
+ \showmessage\m!columns1\maxnofcolumns
+ \nofcolumns\maxnofcolumns
+ \else
+ \nofcolumns#1\relax
+ \fi
+ \ifnum\nofcolumns>\allocatednofcolumns
+ \dorecurse\nofcolumns
+ {\ifnum\recurselevel>\allocatednofcolumns\relax
+ % \newbox\next \letgvalue{\@col@-\recurselevel-t}=\next
+ \@EA\newbox\csname\@col@-\recurselevel-t\endcsname % text
+ \@EA\newbox\csname\@col@-\recurselevel-f\endcsname % foot
+ \@EA\newbox\csname\@col@-\recurselevel-h\endcsname % top insert
+ \@EA\newbox\csname\@col@-\recurselevel-l\endcsname % top insert
+ \fi}%
+ \global\chardef\allocatednofcolumns=\nofcolumns
+ \fi}
+
+\def\firstcolumnbox {\columntextbox\plusone}
+\def\currentcolumnbox {\columntextbox\mofcolumns}
+\def\lastcolumnbox {\columntextbox\nofcolumns}
+
+\def\firsttopcolumnbox {\columntopbox \plusone}
+\def\currenttopcolumnbox{\columntopbox \mofcolumns}
+\def\lasttopcolumnbox {\columntopbox \nofcolumns}
+
+\def\columntextbox#1{\csname\@col@-\number#1-t\endcsname}
+\def\columnfootbox#1{\csname\@col@-\number#1-f\endcsname}
+\def\columntopbox #1{\csname\@col@-\number#1-h\endcsname}
+\def\columnbotbox #1{\csname\@col@-\number#1-l\endcsname}
+
+\def\columnsettextbox{\global\setbox\columntextbox}
+\def\columnsetfootbox{\global\setbox\columnfootbox}
+\def\columnsettopbox {\global\setbox\columntopbox}
+\def\columnsetbotbox {\global\setbox\columnbotbox}
+
+\def\columngettextbox{\copy\columntextbox}
+\def\columngetfootbox{\copy\columnfootbox}
+\def\columngettopbox {\copy\columntopbox}
+\def\columngetbotbox {\copy\columnbotbox}
+
+\def\columnerasetextboxes{\dorecurse\allocatednofcolumns{\columnsettextbox\recurselevel\emptybox}}
+\def\columnerasefootboxes{\dorecurse\allocatednofcolumns{\columnsetfootbox\recurselevel\emptybox}}
+\def\columnerasetopboxes {\dorecurse\allocatednofcolumns{\columnsettopbox \recurselevel\emptybox}}
+\def\columnerasebotboxes {\dorecurse\allocatednofcolumns{\columnsetbotbox \recurselevel\emptybox}}
+
+%D Without going in details we present two macro's which handle
+%D the columns. The action which is transfered by the the first
+%D and only parameter can do something with \type
+%D {\currentcolumnbox}. In case of the mid columns, \type
+%D {\firstcolumnbox} and \type {\lastcolumnbox} are handled
+%D outside these macro's.
+
+\def\dohandlecolumn#1%
+ {\mofcolumns\recurselevel
+ \let\currentcolumn\recurselevel
+ #1\relax}
+
+\def\dohandleallcolumns#1%
+ {\dorecurse\nofcolumns{\dohandlecolumn{#1}}}
+
+\def\dohandlerevcolumns#1%
+ {\dostepwiserecurse\nofcolumns\plusone\minusone{\dohandlecolumn{#1}}}
+
+\def\dohandlemidcolumns#1%
+ {\dohandleallcolumns
+ {\ifnum\recurselevel>\plusone
+ \ifnum\recurselevel<\nofcolumns
+ \dohandlecolumn{#1}%
+ \fi
+ \fi}}
+
+%D This register can be used as a temporary storage for page
+%D content.
+
+\newbox\restofpage
+
+%D Features.
+
+\newif\ifintermediatefootnotes
+\newif\ifcarryoverfootnotes %\carryoverfootnotestrue
+\newif\iflastcolumnfootnotes %\lastcolumnfootnotestrue
+\newif\ifbalancecolumns %\balancecolumnstrue
+\newif\ifbalancetoheight %\balancetoheighttrue
+\newif\ifforcecolumngrid \forcecolumngridtrue
+\newif\ifstretchcolumns \stretchcolumnsfalse
+\newif\ifinheritcolumns \inheritcolumnsfalse
+\newif\ifheightencolumns \heightencolumnsfalse
+
+\newif\ifbalancingcolumns
+\newif\ifcollectingcontent
+\newif\ifcolumnoverflow
+\newif\iffinalflushingfloats
+\newif\ifpackflushedfloats \packflushedfloatstrue % for the moment
+
+\newdimen\intercolumnwidth
+\newdimen\localcolumnwidth
+\newdimen\savedpagetotal
+
+\chardef\columndirection=0 % 0:lr 1:rl
+
+\def\minbalancetoplines {1}
+\def\minfreecolumnlines {2}
+
+\newif\ifrecentercolumnbox \recentercolumnboxtrue
+\newif\ifrerecentercolumnbox \rerecentercolumnboxtrue
+\newif\ifpackcolumnfloats \packcolumnfloatstrue
+
+\newbox\collectedpagefloats
+\newbox\collectedleftpagefloats
+\newbox\collectedrightpagefloats
+
+%D The \type {\ifdim} test is needed, because otherwise the
+%D last line of a text end up on top of the baseline instead of
+%D on the baseline, as is the case with preceding pages.
+%D Also, a \type {\vfil} better than a \type {\vfill}.
+
+% to be replaced by \page[now] \page[final] / merged
+
+% \def\eject {\par\penalty-\plustenthousand } % == {\par\break} % plain
+% \def\supereject {\par\penalty-\plustwentythousand} % also plain
+
+\def\eject {\par\ifvmode\penalty\ejectpenalty\fi\resetpagebreak} % == {\par\break} % plain
+\def\supereject {\par\ifvmode\penalty\superpenalty\fi\resetpagebreak} % also plain
+
+\def\doejectpage {\par\ifvmode\ifdim\pagetotal>\pagegoal\else\normalvfil\fi\fi} % pg set to \textheight
+\def\ejectpage {\doejectpage\eject}
+\def\superejectpage{\doejectpage\supereject}
+
+\ifx\bye\undefined \def\bye{\par\vfill\supereject\end} \fi % plain tex command
+
+% floats
+%
+% \def\ejectinsert
+% {\flushnotes
+% \bgroup
+% \noftopfloats\plusthousand
+% \nofbotfloats\zerocount
+% \doflushfloats
+% \egroup}
+
+\def\ejectinsert
+ {\flushnotes
+ \bgroup
+ \noftopfloats\plusthousand
+ \nofbotfloats\zerocount
+ % this is needed in case a float that has been stored
+ % ends up at the current page; this border case occurs when
+ % the calculated room is 'eps' smaller that the room available
+ % when just flushing; so now we have (maybe optional):
+ \pagebaselinecorrection
+ % alas, this is tricky but needed (first surfaced in prikkels)
+ \doflushfloats
+ \egroup}
+
+\def\ejectdummypage
+ {\endgraf \ifvmode
+ \ejectinsert
+ \hardespatie % will be different
+ \vfill
+ \gotonextpage
+ \fi}
+
+\def\beforefinaloutput
+ {}
+
+\def\afterfinaloutput
+ {\forgetall
+ \vskip\zeropoint\relax
+ \ifvoid\normalpagebox \else
+ \unvbox\normalpagebox
+ \penalty\outputpenalty
+ \fi
+ % not really needed, replaced by \flushsavedfloats
+ \ifnum\outputpenalty>\superpenalty \else % better use a proper otr signal
+ \dosupereject
+ \fi
+ % but does not hurt either (we're still in the otr!)
+ \inpagebodytrue % needed for enabling \blank !
+ \flushsavedfloats % was \dosetbothinserts; only otr one !
+ \setvsize % this is needed for interacting components, like floats and multicolumns
+ \adaptfuzzypagegoal} % watch this hack!
+
+\def\dofinaloutput#1#2% \vbox: prevents spurious spaces in every..pagebody
+ {\beforefinaloutput
+ \the\everybeforeshipout % brrr not in shipout
+ \the\pageboundsettings
+ \myshipout{\hbox{\vbox{\dopagebody#1#2\setpagecounters}}}%
+ \the\everyaftershipout
+ \afterfinaloutput
+ \popproperties} % ... and here ...
+
+\def\donofinaloutput#1#2%
+ {\beforefinaloutput
+ \the\everybeforeshipout
+ \setpagecounters
+ \message{[-\the\realpageno]}%
+ \setbox\scratchbox\hbox
+ {%\the\everyshipout % still needed here ?
+ \dopagebody#1#2}%
+ \deadcycles\zerocount
+ \gotonextrealpage
+ \the\everyaftershipout
+ \afterfinaloutput
+ \popproperties} % ... and here
+
+% beware: \ifprocessingpages is in use
+
+\ifx\checkpageversion\undefined \let\checkpageversion\relax \fi % todo: hook into \everybeforeshipout
+\ifx\doflushspread \undefined \let\doflushspread \relax \fi % todo
+
+\def\finaloutput#1#2%
+ {\checkpageversion
+ \ifprocessingpages
+ \ifpageselected
+ \@EAEAEA\dofinaloutput
+ \else
+ \@EAEAEA\donofinaloutput
+ \fi
+ \else
+ \ifpageselected
+ \@EAEAEA\donofinaloutput
+ \else
+ \@EAEAEA\dofinaloutput
+ \fi
+ \fi#1#2%
+ \resetselectiepagina
+ \incrementpagenumber
+ \checkpagedimensions
+ \ifnum\outputpenalty>\superpenalty \else
+ \dosupereject
+ \fi
+ \doflushspread
+ \dopostponeblock}
+
+\def\dooutput
+ {\finaloutput\unvbox\normalpagebox}
+
+\maxdeadcycles=1000
+
+% will be installable tracer; better use chardef
+
+% this needs a real cleanup
+
+\def\doplaceversiontext#1#2%
+ {\doifsomething{#2}
+ {\defconvertedcommand\ascii{#2}%
+ \space#1:\space\ascii\space
+ \!!doneatrue}}
+
+\def\placeversioninfo % nog engels maken
+ {\ifcase\conceptmode
+ % 0 : nothing
+ \or
+ % 1 : simple
+ \vskip\!!sixpoint
+ \hbox to \makeupwidth
+ {\infofont
+ \v!concept:\space\currentdate
+ \hss\reportpagedimensions}%
+ \else
+ % 2/3 : extensive
+ \vskip\!!sixpoint
+ \hbox to \makeupwidth
+ {\infofont
+ \getmessage\m!systems{27}:\space\currentdate\space
+ \doplaceversiontext\v!project \currentproject
+ \doplaceversiontext\v!product \currentproduct
+ \doplaceversiontext\v!component\currentcomponent
+ \if!!donea\else\space\v!file:\space\jobname\fi
+ \hss\reportpagedimensions}%
+ \fi}
+
+% tot hier
+
+\def\doversion[#1]%
+ {\chardef\conceptmode\zerocount
+ \overfullrule\zeropoint
+ \processaction % \v!final=>
+ [#1]
+ [ \v!concept=>\chardef\conceptmode\plusone, % simple banner
+ \v!file=>\chardef\conceptmode\plustwo, % full banner
+ \v!temporary=>\chardef\conceptmode\plusthree % full banner plus
+ \overfullrule5\points]} % info in the margin
+
+\def\version
+ {\dosingleargument\doversion}
+
+\def\addstatusinfo
+ {\ifcase\conceptmode
+ \@EA\gobbleoneargument
+ \else
+ \@EA\doaddstatusinfo
+ \fi}
+
+\def\doaddstatusinfo#1%
+ {\setbox#1\vbox to \paperheight
+ {\vsmashbox#1\box#1%
+ \offinterlineskip
+ \vskip\topspace
+ \hsize\paperwidth
+ \hfill\hbox{\placetestinfo\hskip.5cm}\vss
+ \settexthoffset\hskip\texthoffset % brrrr
+ %\tlap{\placeversioninfo}\vskip.5cm
+ \vbox to 1cm{\vss\placeversioninfo\vss}}}
+
+\def\dotestinfo#1#2#3%
+ {\ifinpagebody\else\ifnum\conceptmode=\plusthree
+ \begingroup
+ \defconvertedcommand\ascii{#3}%
+ \xdef\extratestinfo
+ {#2\space\ascii}%
+ \gdef\totaltestinfo
+ {\global\setbox#1\vbox
+ {\unvbox#1\relax
+ \infofont \setupinterlinespace
+ \hbox
+ {\strut
+ \expanded{\doboundtext{\extratestinfo}{12em}{..}}%
+ \quad}}}%
+ \endgroup
+ \ifinner
+ \aftergroup\totaltestinfo
+ \else
+ \totaltestinfo
+ \fi
+ \fi\fi}
+
+% this will be inserts some day
+
+% \installinsertion\referenceinfobox
+% \installinsertion\registerinfobox
+% \installinsertion\floatinfobox
+
+\newbox\referenceinfobox
+\newbox\registerinfobox
+\newbox\floatinfobox
+
+\def\referenceinfo{\dotestinfo\referenceinfobox}
+\def\registerinfo {\dotestinfo\registerinfobox}
+\def\floatinfo {\dotestinfo\floatinfobox}
+
+\def\placetestinfo
+ {\vbox to \makeupheight
+ {\forgetall
+ \infofont
+ \hsize10em
+ \ifvoid\floatinfobox\else
+ \strut \getmessage\m!systems{24}%
+ \vskip\!!sixpoint
+ \unvbox\floatinfobox
+ \vskip\!!twelvepoint
+ \fi
+ \ifvoid\referenceinfobox\else
+ \strut \getmessage\m!systems{25}%
+ \vskip\!!sixpoint
+ \unvbox\referenceinfobox
+ \vskip\!!twelvepoint
+ \fi
+ \ifvoid\registerinfobox\else
+ \strut \getmessage\m!systems{26}%
+ \vskip\!!sixpoint
+ \unvbox\registerinfobox
+ \fi
+ \vss}}
+
+\version[\v!final]
+
+% bewaren tvb documentatie
+%
+% \hbox to \hsize
+% {\en
+% \switchnaarkorps[5pt]%
+% \emergencystretch2em
+% \dimen0=\baselineskip
+% \baselineskip=\dimen0 plus 1pt
+% \hsize=.2\hsize
+% \vsize=2\hsize
+% \ruledvbox to \vsize{\input tufte \par}\hss
+% \ruledvbox to \vsize{\input tufte \par\kern-\prevdepth}\hss
+% \ruledvbox to \vsize{\input tufte \par\kern0pt}\hss
+% \ruledvbox to \vsize{\input tufte \par\vfill}\hss
+% \ruledvbox to \vsize{\input tufte \par\kern-\prevdepth\vfill}}
+%
+% \hbox to \hsize
+% {\en
+% \switchnaarkorps[5pt]%
+% \emergencystretch2em
+% \dimen0=\baselineskip
+% \baselineskip=\dimen0 plus 1pt
+% \hsize=.18\hsize
+% \vsize=2.5\hsize
+% \setbox0=\vbox{\input tufte\relax}%
+% \ruledvbox to \vsize{\unvcopy0}\hss
+% \ruledvbox to \vsize{\unvcopy0\kern-\dp0}\hss
+% \ruledvbox to \vsize{\unvcopy0\kern0pt}\hss
+% \ruledvbox to \vsize{\unvcopy0\vfill}\hss
+% \ruledvbox to \vsize{\unvcopy0\kern-\dp0\vfill}}
+
+\newtoks\afterpage \newtoks\aftereverypage
+\newtoks\beforepage \newtoks\beforeeverypage
+
+\chardef\showgridstate=0
+
+\def\showgrid
+ {\dosingleempty\doshowgrid}
+
+\def\doshowgrid[#1]%
+ {\chardef\showgridstate \plusone % downward compatible default
+ \chardef\gridboxlinemode \plusone
+ \chardef\gridboxlinenomode\plusone
+ \processallactionsinset
+ [#1]%
+ [ \v!reset=>\chardef\showgridstate \zerocount,
+ \v!bottom=>\chardef\showgridstate \plusone,
+ \v!top=>\chardef\showgridstate \plustwo,
+ \v!none=>\chardef\gridboxlinemode \zerocount,
+ \v!all=>\chardef\gridboxlinemode \plusone,
+ \v!lines=>\chardef\gridboxlinemode \plustwo,
+ \v!frame=>\chardef\gridboxlinemode \plusthree,
+ \v!nonumber=>\chardef\gridboxlinenomode\zerocount,
+ \v!right=>\chardef\gridboxlinenomode\plusone,
+ \v!left=>\chardef\gridboxlinenomode\plustwo]}
+
+\def\buildpagebox#1%
+ {\setbox#1\vbox to \paperheight
+ {\hsize\paperwidth
+ \vskip\topspace
+ \doifbothsides
+ {\hskip\backspace}
+ {\hskip\backspace}
+ {\hskip\paperwidth \hskip-\backspace \hskip-\makeupwidth}%
+ \box#1}%
+ \dp#1\zeropoint}
+
+% \newif\ifpagebodyornaments \pagebodyornamentstrue
+%
+% \appendtoks
+% \global\pagebodyornamentstrue
+% \to \everyaftershipout
+
+\newif\ifarrangingpages \arrangingpagesfalse
+
+\chardef\pageornamentstate\zerocount % 0=on 1=one-off 2=always-off
+
+\def\pagebodyornamentstrue {\chardef\pageornamentstate\zerocount} % for a while
+\def\pagebodyornamentsfalse{\chardef\pageornamentstate\plusone} % for a while
+
+\appendtoks
+ \ifcase\pageornamentstate\or
+ \chardef\pageornamentstate\zerocount
+ \fi
+\to \everyaftershipout
+
+\let\poparrangedpages\relax
+\let\pusharrangedpage\relax
+
+\ifx\shiftprintpagebox\undefined
+ \let\shiftprintpagebox\gobbleoneargument
+ \let\shiftpaperpagebox\gobbleoneargument
+\fi
+
+\ifx\registerpageposition\undefined
+ \let\registerpageposition\gobbleoneargument
+\fi
+
+\def\reportarrangedpage#1%
+ {\showmessage\m!systems
+ {23}{\the\realpageno.\the\pageno\ifnum\subpageno>0 .\the\subpageno\fi,#1}}
+
+\newif\ifsavepagebody \newbox\savedpagebody
+
+% beware, \??ly is used before defined, i.e. bad module design
+
+\setuplayout[\c!method=\v!normal]
+
+\def\buildpagebody#1#2%
+ {\ifsavepagebody\global\setbox\savedpagebody\fi
+ \vbox
+ {\beginrestorecatcodes
+ \forgetall % igv problemen, check: \boxmaxdepth\maxdimen
+ \boxmaxdepth\maxdimen % new
+ \dontcomplain
+ % the following plugin uses and sets pagebox; beware: this
+ % will change and is for my (hh) personal experiments
+ \executeifdefined{\??ly\c!method\@@lymethod}%
+ {\getvalue{\??ly\c!method\v!normal}}#1#2%
+ % the finishing touch
+ \ifcase\pageornamentstate
+ \addpagebackground \pagebox
+ \fi
+ \registerpageposition\pagebox
+ \ifarrangingpages
+ \shiftpaperpagebox \pagebox % \v!paper
+ \else
+ \clippagebox \pagebox
+ \addpagecutmarks \pagebox
+ \replicatepagebox \pagebox
+ \scalepagebox \pagebox
+ \mirrorpaperbox \pagebox
+ \orientpaperbox \pagebox
+ \addpagecolormarks \pagebox
+ \centerpagebox \pagebox
+ \addprintbackground\pagebox
+ \mirrorprintbox \pagebox
+ \orientprintbox \pagebox
+ \shiftprintpagebox \pagebox % \v!page
+ \offsetprintbox \pagebox
+ \negateprintbox \pagebox
+ \fi
+ \box\pagebox
+ \endrestorecatcodes}%
+ \ifsavepagebody\copy\savedpagebody\fi}
+
+\setvalue{\??ly\c!method\v!normal}#1#2%
+ {\setbox\pagebox\vbox
+ {\offinterlineskip
+ \ifcase\pageornamentstate
+ \bgroup % else footnotes get inconsistent font/baseline
+ \dostartattributes\??ly\c!style\c!color\empty
+ \offinterlineskip
+ \gettextboxes
+ \dostopattributes
+ \egroup
+ \fi
+ \getmainbox#1#2}% including footnotes
+ \ifcase\pageornamentstate
+ \addmainbackground \pagebox
+ \addlogobackground \pagebox
+ \fi
+ \buildpagebox \pagebox
+ \addstatusinfo \pagebox}
+
+\def\finishpagebox#1%
+ {\ifarrangingpages
+ \addpagecutmarks #1%
+ \addpagecolormarks#1%
+ \centerpagebox #1%
+ \mirrorprintbox #1%
+ \orientprintbox #1%
+ \offsetprintbox #1%
+ \negateprintbox #1%
+ \fi}
+
+\appendtoks \restoreglobalbodyfont \to \everybeforepagebody
+\appendtoks \restorecolumnsettings \to \everybeforepagebody
+
+\ifx\nestednewbox\undefined \newbox\nestednextbox \fi
+
+\prependtoks \let\nextbox\nestednextbox \to \everybeforepagebody
+
+\def\dopagebody#1#2%
+ {%\getallmarks % now in following token register
+ \the\everybeforepagebody
+ \starttextproperties
+ \gotonextsubpage % nog eens: als in pagina (tbv standaard opmaak)
+ \dontshowboxes % dan hier blokkeren en verderop resetten
+% \shipoutfacingpage
+ \checkmargeblokken
+ \the\beforeeverypage
+ \flushtoks\beforepage
+ \inpagebodytrue\buildpagebody#1#2%
+ \flushtoks\afterpage
+ \the\aftereverypage
+ \resetpagebreak
+ %updatelistreferences % now in aftereverypage
+ \resetlayouttextlines % will go to \aftereverypage
+ \stoptextproperties
+ \the\everyafterpagebody}
+
+\newtoks\pageboundsettings
+
+\prependtoks \initializepaper \to \pageboundsettings
+
+% not here
+
+\newif\ifpagebreakdisabled \pagebreakdisabledfalse
+
+% \chardef\testpagemethod=0 % todo: \testnewpage[method=,lines=,voffset=]
+%
+% \def\testpage {\dotripleempty\dotestpage[\plusone]}
+% \def\testpageonly{\dotripleempty\dotestpage[\plustwo]}
+%
+% \def\dotestpage[#1][#2][#3]%
+% {%\relax % needed before \if
+% \endgraf
+% \ifpagebreakdisabled
+% % do nothing
+% \else
+% %ifnum#1=\plusone\synchronizeoutput\fi
+% \ifdim\pagegoal<\maxdimen \relax
+% \ifdim\pagetotal<\pagegoal \relax
+% \scratchdimen\lineheight
+% \multiply\scratchdimen#2\relax
+% \advance\scratchdimen \pagetotal
+% \ifdim\lastskip<\parskip
+% \advance\scratchdimen \parskip
+% \fi
+% \ifthirdargument
+% \advance\scratchdimen#3\relax
+% \fi
+% \ifcase\testpagemethod
+% \ifdim\scratchdimen>.99\pagegoal
+% \vfill\eject % \penalty-\!!tenthousand\relax
+% \fi
+% \or
+% \advance\scratchdimen-\pagegoal
+% \ifdim\scratchdimen>-\lineheight
+% \vfill\eject % \penalty-\!!tenthousand\relax
+% \fi
+% \or
+% \getnoflines\pagegoal
+% \advance\scratchdimen-\noflines\lineheight \relax
+% \ifdim\scratchdimen>-\lineheight
+% \vfill\eject % \penalty-\!!tenthousand\relax
+% \fi
+% \or % same as 0 but more accurate
+% \advance\scratchdimen-10\s!sp\relax
+% \ifdim\scratchdimen>\pagegoal
+% \vfill\eject % \penalty-\!!tenthousand\relax
+% \fi
+% \fi
+% \else
+% % force page break / new
+% % \vfill\eject % \penalty-\!!tenthousand\relax
+% \fi
+% \else
+% \ifnum#1=\plusone\goodbreak\fi
+% \fi
+% \fi}
+
+\chardef\testpagemethod \zerocount % todo: \testnewpage[method=,lines=,voffset=]
+\chardef\testpagetrigger\zerocount
+
+\def\testpage {\dotripleempty\dotestpage[\plusone ]} %
+\def\testpageonly{\dotripleempty\dotestpage[\plustwo ]} % no penalties added to the mvl
+\def\testpagesync{\dotripleempty\dotestpage[\plusthree]} % force sync
+
+\def\dotestpage[#1][#2][#3]% don't change, only add more methods
+ {\relax % needed before \if
+ \ifpagebreakdisabled
+ \endgraf
+ \else
+ % new from here
+ \ifcase\testpagetrigger
+ \endgraf
+ \or
+ \ifvmode
+ \dosomebreak\allowbreak
+ \else % indeed?
+ \vadjust{\allowbreak}%
+ \endgraf
+ \fi
+ \fi
+ % till here
+ \ifdim\pagegoal<\maxdimen \relax
+ \ifdim\pagetotal<\pagegoal \relax
+ \scratchdimen\lineheight
+ \multiply\scratchdimen#2\relax
+ \advance\scratchdimen \pagetotal
+ \ifdim\lastskip<\parskip
+ \advance\scratchdimen \parskip
+ \fi
+ \ifthirdargument
+ \advance\scratchdimen#3\relax
+ \fi
+ \ifcase\testpagemethod
+ \ifdim\scratchdimen>.99\pagegoal
+ \penalty-\!!tenthousand\relax
+ \fi
+ \or
+ \advance\scratchdimen-\pagegoal
+ \ifdim\scratchdimen>-\lineheight
+ \penalty-\!!tenthousand\relax
+ \fi
+ \or
+ \getnoflines\pagegoal
+ \advance\scratchdimen-\noflines\lineheight \relax
+ \ifdim\scratchdimen>-\lineheight
+ \penalty-\!!tenthousand\relax
+ \fi
+ \or % same as 0 but more accurate
+ \advance\scratchdimen-10\s!sp\relax
+ \ifdim\scratchdimen>\pagegoal
+ \penalty-\!!tenthousand\relax
+ \fi
+ \fi
+ \else
+ \ifnum#1=\plusthree
+ \flushpagesofar
+ \fi
+ \fi
+ \else
+ \ifnum#1=\plusone\goodbreak\fi
+ \fi
+ \fi}
+
+\def\flushpagesofar
+ {\endgraf
+ \ifdim\pagetotal>\pagegoal
+ \ifdim\dimexpr\pagetotal-\pageshrink\relax>\pagegoal
+ \goodbreak % \penalty0
+ \else
+ \page
+ \fi
+ \else
+ \fi}
+
+\def\testcolumn
+ {\dodoubleempty\dotestcolumn}
+
+\def\dotestcolumn[#1][#2]%
+ {%\relax % needed before \if !
+ \endgraf
+ \ifdim\pagegoal<\maxdimen \ifdim\pagetotal<\pagegoal % \relax
+ \scratchdimen\pagegoal
+ \advance\scratchdimen-\pagetotal
+ \ifdim\lastskip<\parskip
+ \advance\scratchdimen \parskip
+ \fi
+ \ifsecondargument
+ \advance\scratchdimen#2%
+ \fi
+ \getrawnoflines\scratchdimen % raw !
+ % \message{[\number#1>\number\noflines ?}\wait
+ \ifnum#1>\noflines
+ \column
+ \fi
+ \else
+ \penalty-\!!tenthousand % untested ! ! \column
+ \fi \fi}
+
+\let\resetcurrentsectionmarks\relax
+
+% was: \resetsectionmarks\firstsection, zie \handlepagebreak
+
+\def\page{\pagebreak} % the short form of \pagebreak (mult-com one)
+
+\def\resetpagebreak
+ {\global\pagebreakdisabledfalse}
+
+\def\simplifypagebreak
+ {\def\dopagebreak[##1]{\goodbreak}}
+
+\def\disablepagebreaks
+ {\def\dopagebreak[##1]{}}
+
+\def\executepagebreakhandler#1%
+ {\edef\@@pagespecification{#1}%
+ \doifdefinedelse{\??pe:\@@pagespecification}
+ {\getvalue{\??pe:\@@pagespecification}}
+ {\doifdefinedelse{\??pe::\@@pagespecification}
+ {\executepagebreakhandlers{\getvalue{\??pe::\@@pagespecification}}}
+ {\getvalue{\??pe:\s!unknown}}}}
+
+\long\def\installpagebreakhandler#1#2%
+ {\long\setvalue{\??pe:#1}{#2}}
+
+% \definecomplexorsimple\pagebreak
+
+% \def\simplepagebreak
+% {\executepagebreakhandler\v!ja}
+
+% \def\complexpagebreak[#1]% if empty, do nothing and avoid processing,
+% {\flushnotes % see head's; watch how we group
+% \doifsomething{#1}{\bgroup\executepagebreakhandlers{#1}\egroup}}
+
+\unexpanded\def\pagebreak
+ {\dosingleempty\dopagebreak}
+
+\def\dopagebreak[#1]% so, page ornaments are reset after a pagebreak command, unless set
+ {\bgroup
+ \edef\prevrealpageno{\the\realpageno}%
+ \ifcase\pageornamentstate \or
+ % disable reset after shipout
+ \global\chardef\pageornamentstate\plustwo
+ \fi
+ \iffirstargument % or if empty i.e. []
+ \flushnotes\executepagebreakhandlers{#1}%
+ \else % so, no pagebreak when \pagebreak[] ! ! !
+ \flushnotes\executepagebreakhandler\v!yes
+ \fi
+ \ifnum\prevrealpageno<\realpageno
+ \global\chardef\pageornamentstate\zerocount
+ \fi
+ \egroup}
+
+\def\executepagebreakhandlers#1%
+ {\processcommacommand[#1]\executepagebreakhandler}
+
+\installpagebreakhandler \s!dummy
+ {\ejectinsert
+ \gotonextpage
+ \ejectdummypage}
+
+\installpagebreakhandler \v!frame
+ {\page\bgroup\showframe\page[\v!empty]\egroup}
+
+\installpagebreakhandler \s!unknown
+ {\doifinstringelse{+}\@@pagespecification
+ {\ejectinsert
+ \gotonextpage
+ \dorecurse\@@pagespecification\ejectdummypage}
+ {\doifnumberelse\@@pagespecification
+ {\ejectinsert
+ \gotonextpage
+ \doloop
+ {\ifnum\userpageno<\@@pagespecification\relax
+ \ejectdummypage
+ \else
+ \exitloop
+ \fi}}
+ {}}}
+
+\installpagebreakhandler \s!default
+ {} % do nothing if empty
+
+\installpagebreakhandler \v!reset
+ {% better not: \global\chardef\pageornamentstate\zerocount
+ \resetpagebreak}
+
+\installpagebreakhandler \v!disable
+ {\global\pagebreakdisabledtrue}
+
+\installpagebreakhandler \v!yes
+ {\ifpagebreakdisabled\else
+ \ejectinsert
+ \gotonextpage
+ \ifinsidecolumns % this will move to MUL
+ \ejectpage % anders soms geen overgang
+ \fi
+ \fi}
+
+\installpagebreakhandler \v!makeup % ??
+ {\ifpagebreakdisabled\else
+ \eject
+ \fi}
+
+\installpagebreakhandler \v!blank
+ {\ifcase\pageornamentstate
+ \global\chardef\pageornamentstate\plusone
+ \fi}
+
+\installpagebreakhandler \v!no
+ {\ifpagebreakdisabled\else
+ \dosomebreak\nobreak
+ \fi}
+
+\installpagebreakhandler \v!preference
+ {\ifpagebreakdisabled\else
+ \ifinsidecolumns % this will move to MUL
+ \dosomebreak\goodbreak
+ \else
+ \testpage[3][\zeropoint]%
+ \fi
+ \fi}
+
+\installpagebreakhandler \v!bigpreference
+ {\ifpagebreakdisabled\else
+ \ifinsidecolumns % this will move to MUL
+ \dosomebreak\goodbreak
+ \else
+ \testpage[5][\zeropoint]%
+ \fi
+ \fi}
+
+\installpagebreakhandler \v!empty
+ {\ejectinsert
+ \gotonextpage
+ \doifnotvalue{\??tk\v!header\c!state}\v!stop{\setupheader[\c!state=\v!empty]}%
+ \doifnotvalue{\??tk\v!footer\c!state}\v!stop{\setupfooter[\c!state=\v!empty]}%
+ \ejectdummypage}
+
+\installpagebreakhandler \v!left
+ {\ejectinsert
+ \gotonextpageX % will become \gotonextpage
+ \doifbothsidesoverruled{}{\resetcurrentsectionmarks\ejectdummypage}{}}
+
+\installpagebreakhandler \v!right
+ {\ejectinsert
+ \gotonextpageX % will become \gotonextpage
+ \doifbothsidesoverruled{}{}{\resetcurrentsectionmarks\ejectdummypage}}
+
+\installpagebreakhandler \v!even
+ {\page
+ \doifoddpageelse{\resetcurrentsectionmarks\ejectdummypage}\donothing}
+
+\installpagebreakhandler \v!odd
+ {\page
+ \doifoddpageelse\donothing{\resetcurrentsectionmarks\ejectdummypage}}
+
+\installpagebreakhandler \v!quadruple % not yet ok inside columnsets
+ {\ifdoublesided
+ \!!counta\realpageno
+ \!!countb\realpageno
+ \divide\!!counta 4
+ \divide\!!countb 2
+ \ifnum\!!counta=\!!countb
+ \else
+ \executepagebreakhandler\v!yes
+ \executepagebreakhandler\v!empty
+ \executepagebreakhandler\v!empty
+ \fi
+ \fi}
+
+\installpagebreakhandler \v!last
+ {\ejectinsert
+ \gotonextpageX % will become \gotonextpage
+ \relax
+ \doifbothsidesoverruled
+ {\shipoutfacingpage}
+ {}
+ {\noheaderandfooterlines \ejectdummypage}%
+ \filluparrangedpages}
+
+\installpagebreakhandler \v!lastpage % handy for backpage preceded by empty pages
+ {\executepagebreakhandler\v!yes
+ \ifdoublesided
+ \executepagebreakhandler\v!left
+ \executepagebreakhandler\v!empty
+ \executepagebreakhandler\v!empty
+ \fi}
+
+\installpagebreakhandler \v!start
+ {\globallet\shipout\normalshipout}
+
+\installpagebreakhandler \v!stop
+ {\globallet\shipout\noshipout}
+
+% nb: \executepagebreakhandler\v!hoofd in other ones
+
+\installpagebreakhandler \v!header
+ {\doifnotvalue{\??tk\v!header\c!state}\v!stop{\setupheader[\c!state=\v!empty]}}
+
+\installpagebreakhandler \v!footer
+ {\doifnotvalue{\??tk\v!footer\c!state}\v!stop{\setupfooter[\c!state=\v!empty]}}
+
+% \definepagebreak
+% [chapter]
+% [yes,header,right]
+%
+% \setuphead
+% [chapter]
+% [page=chapter,
+% header=empty,
+% footer=chapter]
+%
+% \definepagebreak % untested
+% [lastpage]
+% [left,{empty,right},{empty,left}]
+
+% public page handler, beware: definepage already in use (core-ref)
+%
+% \definepagebreak[instance][forsure]
+% \definepagebreak[forsure][yes,+4]
+
+\def\definepagebreak
+ {\dodoubleargument\dodefinepagebreak}
+
+\def\dodefinepagebreak[#1][#2]% non recursive, meant for simple mappings
+ {\setvalue{\??pe::#1}{#2}}
+
+% hier nog uti blokkeren
+
+% don't change this / test case:
+%
+% \setupbackgrounds[state=repeat]
+% \setupbackgrounds[text][text][background=whatever]
+% \couplepage[chapter][before={\defineoverlay[whatever][ON]}]
+% \setuphead[chapter][before={\pagetype[chapter]}]
+% \chapter{First} \page test \chapter{second} \page test
+
+\long\def\installcolumnbreakhandler#1#2#3% #1=otr-id #2=tag
+ {\long\setvalue{\??cn:#1:#2}{#3}}
+
+\def\definecolumnbreak
+ {\dodoubleargument\dodefinecolumnbreak}
+
+\def\dodefinecolumnbreak[#1][#2]% non recursive, meant for simple mappings
+ {\setvalue{\??cn::#1}{#2}}
+
+%\def\columnbreak
+% {\dosingleempty\docolumnbreak}
+%
+%\def\docolumnbreak[#1]%
+% {\expanded{\nextcolumn[\executeifdefined{\??cn::#1}{#1}]}}
+
+\definecomplexorsimple\columnbreak
+
+\def\simplecolumnbreak
+ {\executecolumnbreakhandler\v!yes}
+
+\def\complexcolumnbreak[#1]% if empty, do nothing and avoid processing
+ {\doifsomething{#1}{\executecolumnbreakhandlers{#1}}}
+
+\def\executecolumnbreakhandlers#1%
+ {\processcommacommand[#1]\executecolumnbreakhandler}
+
+\def\executecolumnbreakhandler#1% here no commalist
+ {\edef\@@columnspecification{#1}%
+ \doifdefinedelse{\??cn:\OTRidentifier:\@@columnspecification}
+ {\getvalue{\??cn:\OTRidentifier:\@@columnspecification}}
+ {\doifdefinedelse{\??cn::\@@columnspecification}
+ {\executecolumnbreakhandlers{\getvalue{\??cn::\@@columnspecification}}}
+ {\getvalue{\??cn:\OTRidentifier:\s!unknown}}}}
+
+%let\nextcolumn\columnbreak
+\let\column \columnbreak
+
+% We don't want spurious last pages (due to left over marks):
+
+\def\noshipout
+ {\writestatus\m!systems{ignoring further shipouts}%
+ \global\advance\realpageno\minusone % else no flush of resources
+ \dowithnextbox{\deadcycles\zerocount}}
+
+% \def\doignorerestoftext
+% {\ifarrangingpages \else \ifnum\textlevel>\zerocount \else
+% \globallet\shipout\noshipout
+% \fi \fi}
+%
+% better:
+
+\def\doignorerestoftext
+ {\ifarrangingpages \else \ifnum\textlevel=\plusone
+ \globallet\shipout\noshipout
+ \fi \fi}
+
+\let\ignorerestoftext\donothing
+
+\prependtoks % only ignore in a symmetrical doc
+ \globallet\ignorerestoftext\doignorerestoftext
+\to \everystarttext
+
+% \appendtoks
+% \ignorerestoftext
+% \to \everylastshipout
+
+\newif\ifpageselected \pageselectedtrue
+\newif\ifselectingpages \selectingpagesfalse
+\newif\ifprocessingpages\processingpagestrue
+
+\let\pageselection \empty
+\let\currentpageselection\empty
+\let\aftershipout \relax
+\let\beforeshipout \relax
+
+\def\dodobeforeshipout#1%
+ {\global\let\beforeshipout\relax
+ \getvalue{\??pg#1\c!before}}
+
+\def\dobeforeshipout
+ {\doifsomething\currentpageselection
+ {\processcommacommand[\currentpageselection]\dodobeforeshipout}}
+
+\def\dododoaftershipout#1%
+ {\global\let\aftershipout\relax
+ \global\let\currentpageselection\empty
+ \getvalue{\??pg#1\c!after}}
+
+\def\dodoaftershipout#1%
+ {\doifelsevalue{\??pg#1\c!option}\v!doublesided
+ {\doifbothsidesoverruled
+ {\dododoaftershipout{#1}}
+ {\dododoaftershipout{#1}}
+ {}}
+ {\dododoaftershipout{#1}}}
+
+\def\doaftershipout
+ {\doifsomething\currentpageselection
+ {\processcommacommand[\currentpageselection]\dodoaftershipout}}
+
+% Dit wordt eigenlijk nooit en moet worden vervangen door
+% het meer algemene mechanisme.
+
+\def\dopagetype[#1]%
+ {\edef\desoortpagina{#1}%
+ \ifx\desoortpagina\empty \else
+ \@EA\doglobal\@EA\addtocommalist\@EA{\desoortpagina}\currentpageselection
+ \ifselectingpages
+ \fullexpandtwoargsafter\doifcommon\desoortpagina\pageselection
+ {\global\pageselectedtrue}%
+ \fi
+ \gdef\beforeshipout{\dobeforeshipout}%
+ \gdef\aftershipout {\doaftershipout}%
+ \fi}
+
+\def\pagetype
+ {\dosingleargument\dopagetype}
+
+\def\docouplepage[#1][#2]%
+ {\getparameters
+ [\??pg]
+ [\c!before=,
+ \c!after=,
+ \c!option=,
+ #2]%
+ \def\docommand##1%
+ {\getparameters
+ [\??pg##1]
+ [\c!before=\@@pgbefore,
+ \c!after=\@@pgafter,
+ \c!option=\@@pgoption]}%
+ \processcommalist[#1]\docommand}%
+
+\def\couplepage
+ {\dodoubleargument\docouplepage}
+
+\def\doprocesspage[#1][#2]%
+ {\processaction
+ [#2]
+ [\v!yes=>\global\processingpagestrue,
+ \v!no=>\global\processingpagesfalse]%
+ \gdef\pageselection{#1}%
+ \global\selectingpagestrue
+ \global\pageselectedfalse}
+
+\def\processpage
+ {\dodoubleargument\doprocesspage}
+
+\def\resetselectiepagina
+ {\ifselectingpages
+ \doifbothsidesoverruled{\global\pageselectedfalse}{}{\global\pageselectedfalse}%
+ \fi}
+
+\newif\ifregistertextareas
+\newif\iftracetextareas
+
+\newbox\registertextbox
+
+% \def\registeredtextarea#1#2#3% #1=lower-dp #2=correct-ht #3=box
+% {\hbox{\box#3}}
+
+\def\enabletextarearegistration{\global\registertextareastrue}
+
+\def\registeredtextarea#1#2#3% #1=lower-dp #2=correct-ht #3=box
+ {\hbox\bgroup
+ \ifregistertextareas \ifx\registerMPtextarea\undefined \else
+ \setbox\registertextbox\null
+ \wd\registertextbox\wd#3%
+ \ht\registertextbox\ht#3%
+ \dp\registertextbox\dp#3%
+ \ifcase#1\or % 1
+ \setbox\registertextbox\hbox{\lower\strutdp\box\registertextbox}%
+ \fi
+ \ifcase#2\or % 1
+ \setbox\registertextbox\hbox{\raise\topskip\hbox{\lower\strutht\box\registertextbox}}%
+ \dp\registertextbox\strutdp
+ \fi
+ \dp\registertextbox\strutdp % needed
+ %\setbox\registertextbox\hbox
+ % {\iftracetextareas\gray\boxrulewidth2pt\ruledhbox\fi
+ % {\registerMPtextarea{\box\registertextbox}}}%
+ \setbox\registertextbox\hbox
+ {\registerMPtextarea{\box\registertextbox}}%
+ \smashbox\registertextbox
+ \box\registertextbox
+ \fi \fi
+ \box#3%
+ \egroup}
+
+%D \macros
+%D {setupoppositeplacing,startopposite}
+%D
+%D \starttyping
+%D \starttext
+%D test \startopposite \blackrule[width=3cm,height=4cm] \stopopposite test
+%D test \startopposite \blackrule[width=3cm,height=4cm] \stopopposite test
+%D \stoptext
+%D \stoptyping
+
+% Moved from page-mar.tex, made english, cleaned up, but still to be
+% redesigned
+
+\newbox\facingpage
+
+\def\setupoppositeplacing
+ {\dodoubleargument\getparameters[\??np]}
+
+\def\startopposite
+ {\dowithnextboxcontent
+ {\hsize\makeupwidth}%
+ {\global\setbox\facingpage\vbox
+ {\ifvoid\facingpage
+ \@@npbefore
+ \else
+ \@@npinbetween
+ \unvbox\facingpage
+ \fi
+ \box\nextbox}}%
+ \vbox\bgroup}
+
+\def\stopopposite
+ {\egroup}
+
+\def\finishfacingpage
+ {\ifvoid\facingpage\else
+ \global\setbox\facingpage\vbox to \makeupheight
+ {\unvbox\facingpage
+ \@@npafter
+ \vss}%
+ \fi}
+
+\def\shipoutfacingpage
+ {\doif\@@npstate\v!start
+ {\ifvoid\facingpage\else
+ \ifnum\realpageno>\plusone
+ \bgroup
+ \chardef\pageornamentstate\plusone
+ \finishfacingpage
+ \myshipout{\buildpagebody\box\facingpage}%
+ \egroup
+ \else
+ \global\setbox\facingpage\emptybox
+ \fi
+ \fi}}
+
+\setupoppositeplacing
+ [\c!state=\v!start,
+ \c!before=,
+ \c!inbetween=\blank,
+ \c!after=]
+
+\protect \endinput
diff --git a/tex/context/base/page-lay.tex b/tex/context/base/page-lay.tex
index 9e86bcae2..0db7fc167 100644
--- a/tex/context/base/page-lay.tex
+++ b/tex/context/base/page-lay.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Layout Specification}
+\writestatus{loading}{ConTeXt Page Macros / Layout Specification}
%D This module is now etex dependent.
@@ -1241,7 +1241,8 @@
\c!dx=\zeropoint,
\c!dy=\zeropoint,
\c!nx=1,
- \c!ny=1]
+ \c!ny=1,
+ \c!method=\v!normal]
\setuppapersize
[\c!option=\v!max,
diff --git a/tex/context/base/page-lin.lua b/tex/context/base/page-lin.lua
index a8d868f36..0efb6314e 100644
--- a/tex/context/base/page-lin.lua
+++ b/tex/context/base/page-lin.lua
@@ -8,95 +8,103 @@ if not modules then modules = { } end modules ['page-lin'] = {
-- experimental
+local format = string.format
+local texsprint, texbox = tex.sprint, tex.box
+
+local ctxcatcodes = tex.ctxcatcodes
+
nodes = nodes or { }
nodes.lines = nodes.lines or { }
nodes.lines.data = nodes.lines.data or { } -- start step tag
-do
-
- -- if there is demand for it, we can support multiple numbering streams
- -- and use more than one attibute
+-- if there is demand for it, we can support multiple numbering streams
+-- and use more than one attibute
- local hlist, vlist, whatsit = node.id('hlist'), node.id('vlist'), node.id('whatsit')
+local hlist, vlist, whatsit = node.id('hlist'), node.id('vlist'), node.id('whatsit')
- local display_math = attributes.numbers['display-math'] or 121
- local line_number = attributes.numbers['line-number'] or 131
- local line_reference = attributes.numbers['line-reference'] or 132
+local display_math = attributes.private('display-math')
+local line_number = attributes.private('line-number')
+local line_reference = attributes.private('line-reference')
- local current_list = { }
- local cross_references = { }
- local chunksize = 250 -- not used in boxed
+local current_list = { }
+local cross_references = { }
+local chunksize = 250 -- not used in boxed
- local has_attribute = node.has_attribute
- local traverse_id = node.traverse_id
- local copy = node.copy
- local format = string.format
- local sprint = tex.sprint
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local traverse = node.traverse
+local copy_node = node.copy
- local data = nodes.lines.data
+local data = nodes.lines.data
- nodes.lines.scratchbox = nodes.lines.scratchbox or 0
+nodes.lines.scratchbox = nodes.lines.scratchbox or 0
- -- cross referencing
+-- cross referencing
- function nodes.lines.number(n)
- local cr = cross_references[n] or 0
- cross_references[n] = nil
- return cr
- end
+function nodes.lines.number(n)
+ local cr = cross_references[n] or 0
+ cross_references[n] = nil
+ return cr
+end
- local function resolve(n,m)
- while n do
- local id = n.id
- if id == whatsit then
- local a = has_attribute(n,line_reference)
- if a then
- cross_references[a] = m
- end
- elseif id == hlist or id == vlist then
- resolve(n.list,m)
+local function resolve(n,m)
+ while n do
+ local id = n.id
+ if id == whatsit then
+ local a = has_attribute(n,line_reference)
+ if a then
+ cross_references[a] = m
end
- n = n.next
+ elseif id == hlist or id == vlist then
+ resolve(n.list,m)
end
+ n = n.next
end
+end
- -- boxed variant
+-- boxed variant
- nodes.lines.boxed = { }
+nodes.lines.boxed = { }
- function nodes.lines.boxed.register(configuration)
- data[#data+1] = configuration
- return #data
+function nodes.lines.boxed.register(configuration)
+ data[#data+1] = configuration
+ return #data
+end
+function nodes.lines.boxed.setup(n,configuration)
+ local d = data[n]
+ if d then
+ for k,v in pairs(configuration) do d[k] = v end
+ else
+ data[n] = configuration
end
- function nodes.lines.boxed.setup(n,configuration)
- local d = data[n]
- if d then
- for k,v in pairs(configuration) do d[k] = v end
+ return n
+end
+
+local leftskip = nodes.leftskip
+
+local function check_number(n,a) -- move inline
+ local d = data[a]
+ if d then
+ local s = d.start
+ current_list[#current_list+1] = { n, s }
+ if d.start % d.step == 0 then
+ texsprint(ctxcatcodes, format("\\makenumber{%s}{%s}{%s}{%s}{%s}\\endgraf", d.tag or "", s, n.shift, n.width, leftskip(n.list)))
else
- data[n] = configuration
+ texsprint(ctxcatcodes, "\\skipnumber\\endgraf")
end
- return n
+ d.start = s + 1 -- (d.step or 1)
end
+end
- local leftskip = nodes.leftskip
-
- function nodes.lines.boxed.stage_one(n)
- current_list = { }
- local head = tex.box[n].list
- local function check_number(n,a) -- move inline
- local d = data[a]
- if d then
- local s = d.start
- current_list[#current_list+1] = { n, s }
- if d.start % d.step == 0 then
- sprint(tex.ctxcatcodes, format("\\makenumber{%s}{%s}{%s}{%s}{%s}\\endgraf", d.tag or "", s, n.shift, n.width, leftskip(n.list)))
- else
- sprint(tex.ctxcatcodes, "\\skipnumber\\endgraf")
- end
- d.start = s + 1 -- (d.step or 1)
- end
- end
- for n in traverse_id(hlist,head) do -- attr test here and quit as soon as zero found
+function nodes.lines.boxed.stage_one(n)
+ current_list = { }
+ local head = texbox[n]
+ if head then
+ local list = head.list
+ --~ while list.id == vlist and not list.next do
+ --~ list = list.list
+ --~ end
+ for n in traverse_id(hlist,list) do -- attr test here and quit as soon as zero found
if n.height == 0 and n.depth == 0 then
-- skip funny hlists
else
@@ -115,14 +123,17 @@ do
end
end
end
+end
- function nodes.lines.boxed.stage_two(n,m)
+function nodes.lines.boxed.stage_two(n,m)
+ if #current_list > 0 then
m = m or nodes.lines.scratchbox
local t, i = { }, 0
- for l in traverse_id(hlist,tex.box[m].list) do
- t[#t+1] = copy(l)
+ for l in traverse_id(hlist,texbox[m].list) do
+ t[#t+1] = copy_node(l)
end
- for _, l in ipairs(current_list) do
+ for j=1,#current_list do
+ local l = current_list[j]
local n, m = l[1], l[2]
i = i + 1
t[i].next = n.list
@@ -130,107 +141,107 @@ do
resolve(n,m)
end
end
+end
- -- flow variant
- --
- -- it's too hard to make this one robust, so for the moment it's not
- -- available; todo: line refs
+-- flow variant
+--
+-- it's too hard to make this one robust, so for the moment it's not
+-- available; todo: line refs
- if false then
+if false then
- nodes.lines.flowed = { }
+ nodes.lines.flowed = { }
- function nodes.lines.flowed.prepare()
- for i=1,#data do
- sprint(tex.ctxcatcodes,format("\\ctxlua{nodes.lines.flowed.prepare_a(%s)}\\ctxlua{nodes.lines.flowed.prepare_b(%s)}",i, i))
- end
+ function nodes.lines.flowed.prepare(tag)
+ for i=1,#data do -- ??
+ texsprint(ctxcatcodes,format("\\ctxlua{nodes.lines.flowed.prepare_a(%s)}\\ctxlua{nodes.lines.flowed.prepare_b(%s)}",i,i))
end
+ end
- function nodes.lines.flowed.prepare_a(i)
- local d = data[i]
- local p = d.present
- if p < chunksize then
- local b = nodes.lines.scratchbox
- sprint(tex.ctxcatcodes, format("{\\forgetall\\global\\setbox%s=\\vbox{\\unvbox%s\\relax\\offinterlineskip", b, b))
- while p < chunksize do
- sprint(tex.ctxcatcodes, format("\\mkmaketextlinenumber{%s}{%s}\\endgraf",d.start,1))
- p = p + 1
- d.start = d.start + d.step
- end
- d.present = p
- sprint(tex.ctxcatcodes, "}}")
+ function nodes.lines.flowed.prepare_a(i)
+ local d = data[i]
+ local p = d.present
+ if p and p < chunksize then
+ local b = nodes.lines.scratchbox
+ texsprint(ctxcatcodes, format("{\\forgetall\\global\\setbox%s=\\vbox{\\unvbox%s\\relax\\offinterlineskip", b, b))
+ while p < chunksize do
+ texsprint(ctxcatcodes, format("\\mkmaketextlinenumber{%s}{%s}\\endgraf",d.start,1))
+ p = p + 1
+ d.start = d.start + d.step
end
+ d.present = p
+ texsprint(ctxcatcodes, "}}")
end
+ end
- function nodes.lines.flowed.prepare_b(i)
- local d = data[i]
- local b = nodes.lines.scratchbox
- local l = tex.box[b]
- if l then
- l = l.list
- local n = d.numbers
- while l do
- if l.id == hlist then
- local m = node.copy(l)
- m.next = nil
- if n then
- n.next = m
- else
- d.numbers = m
- end
- n = m
+ function nodes.lines.flowed.prepare_b(i)
+ local d = data[i]
+ local b = nodes.lines.scratchbox
+ local l = texbox[b]
+ if l then
+ l = l.list
+ local n = d.numbers
+ while l do
+ if l.id == hlist then
+ local m = copy_node(l)
+ m.next = nil
+ if n then
+ n.next = m
+ else
+ d.numbers = m
end
- l = l.next
+ n = m
end
+ l = l.next
end
- tex.box[b] = nil
end
+ tex.box[b] = nil
+ end
- function nodes.lines.flowed.cleanup(i)
- if i then
+ function nodes.lines.flowed.cleanup(i)
+ if i then
+ node.flush_list(data[i].numbers)
+ else
+ for i=1,#data do
node.flush_list(data[i].numbers)
- else
- for i=1,#data do
- node.flush_list(data[i].numbers)
- end
end
end
+ end
- function nodes.lines.flowed.apply(head)
- local function check_number(n,a)
- local d = data[a]
- if d then
- local m = d.numbers
- if m then
- d.numbers = m.next
- m.next = n.list
- n.list = m
- d.present = d.present - 1
- end
- end
+ local function check_number(n,a)
+ local d = data[a]
+ if d then
+ local m = d.numbers
+ if m then
+ d.numbers = m.next
+ m.next = n.list
+ n.list = m
+ d.present = d.present - 1
end
- for n in node.traverse(head) do
- local id = n.id
- if id == hlist then
- if n.height == 0 and n.depth == 0 then
- -- skip funny hlists
- else
- local a = has_attribute(n,line_number)
- if a and a > 0 then
- if has_attribute(n,display_math) then
- if nodes.is_display_math(n) then
- check_number(n,a)
- end
- else
+ end
+ end
+
+ function nodes.lines.flowed.apply(head)
+ for n in node.traverse(head) do
+ local id = n.id
+ if id == hlist then
+ if n.height == 0 and n.depth == 0 then
+ -- skip funny hlists
+ else
+ local a = has_attribute(n,line_number)
+ if a and a > 0 then
+ if has_attribute(n,display_math) then
+ if nodes.is_display_math(n) then
check_number(n,a)
end
+ else
+ check_number(n,a)
end
end
end
end
- return head, true
end
-
+ return head, true
end
end
diff --git a/tex/context/base/page-lin.mkii b/tex/context/base/page-lin.mkii
index 357283252..a04804ce6 100644
--- a/tex/context/base/page-lin.mkii
+++ b/tex/context/base/page-lin.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Line Numbering}
+\writestatus{loading}{ConTeXt Core Macros / Line Numbering}
\unprotect
diff --git a/tex/context/base/page-lin.mkiv b/tex/context/base/page-lin.mkiv
index f803c206d..ad84fc8b2 100644
--- a/tex/context/base/page-lin.mkiv
+++ b/tex/context/base/page-lin.mkiv
@@ -13,17 +13,16 @@
% generic or not ... maybe not bother too much and simplify to mkiv only
-\writestatus{loading}{Context Core Macros / Line Numbering}
+\writestatus{loading}{ConTeXt Core Macros / Line Numbering}
\unprotect
% low level interface
-\defineattribute[line-number]
-\defineattribute[line-reference]
-
\registerctxluafile{page-lin}{1.001}
-% \ctxluafileload{page-lin}{1.001}
+
+\definesystemattribute[line-number]
+\definesystemattribute[line-reference]
\appendtoksonce\doresetattribute{line-number}\to\everyforgetall
\appendtoksonce\dosetattribute{display-math}{1}\to\everybeforedisplayformula
@@ -64,6 +63,8 @@
\def\makenumber#1#2{\hbox{\llap{#1\quad\hskip#2\scaledpoint}}\endgraf}%
+\newconditional\boxcontentneedsprocessing
+
\def\mkdoprocesspagecontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone}
\def\mkdoprocessboxcontents #1{\mkaddtextlinenumbers{#1}\plusone \plusone}
\def\mkdoprocesscolumncontents#1{\mkaddtextlinenumbers{#1}\currentcolumn\nofcolumns}
@@ -80,6 +81,7 @@
\def\mkstarttextlinenumbering#1#2%
{\globallet\mkprocesspagecontents \mkdoprocesspagecontents
\globallet\mkprocesscolumncontents\mkdoprocesscolumncontents
+ \global\settrue\boxcontentneedsprocessing % see core-rul.mkiv
\ifcase#2\relax
% continue
\or
@@ -409,8 +411,8 @@
\appendtoks\ctxlua{nodes.lines.flowed.cleanup()}\to\everybye
\def\mkstarttextlinenumbering#1#2%
- {\ctxlua{nodes.lines.flowed.prepare(#1)}%
- \dosetattribute{line-number}{#1}}
+ {\ctxlua{nodes.lines.flowed.prepare("#1")}%
+ \dosetattribute{line-number}{#2}}
\def\mkstoptextlinenumbering
{\doresetattribute{line-number}}
diff --git a/tex/context/base/page-log.tex b/tex/context/base/page-log.tex
index ad8a37a9b..e52c36288 100644
--- a/tex/context/base/page-log.tex
+++ b/tex/context/base/page-log.tex
@@ -11,41 +11,25 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Logos}
+\writestatus{loading}{ConTeXt Page Macros / Logos}
\unprotect
-\startmessages dutch library: layouts
- 7: beeldmerken berekenen
-\stopmessages
+% messages moved
-\startmessages english library: layouts
- 7: calculating logospace
-\stopmessages
+% messages moved
-\startmessages german library: layouts
- 7: berechne Platzbedarf des Logos
-\stopmessages
+% messages moved
-\startmessages czech library: layouts
- 7: pocita se misto pro logo
-\stopmessages
+% messages moved
-\startmessages italian library: layouts
- 7: calcolo dello spazio per logo
-\stopmessages
+% messages moved
-\startmessages norwegian library: layouts
- 7: beregner plass for logo
-\stopmessages
+% messages moved
-\startmessages romanian library: layouts
- 7: se calculeaza spatiul pentru logo
-\stopmessages
+% messages moved
-\startmessages french library: layouts
- 7: calcul de l'espace pour le logo
-\stopmessages
+% messages moved
%D Although logos can conveniently be implemented on top of
%D background and text areas, we provide a dedicated mechanism
diff --git a/tex/context/base/page-lyr.tex b/tex/context/base/page-lyr.tex
index af84900b2..fe542233f 100644
--- a/tex/context/base/page-lyr.tex
+++ b/tex/context/base/page-lyr.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Layers}
+\writestatus{loading}{ConTeXt Page Macros / Layers}
%D This module is now etex dependent.
@@ -138,8 +138,8 @@
{\edef\currentlayerwidth {\thelayerwidth {#2#1}}%
\edef\currentlayerheight{\thelayerheight{#2#1}}}
-\def\thelayerwidth #1{\the\wd\executeifdefined{\@@layerbox#1}\voidbox}
-\def\thelayerheight#1{\the\ht\executeifdefined{\@@layerbox#1}\voidbox}
+\def\thelayerwidth #1{\the\wd\executeifdefined{\@@layerbox#1}\emptybox}
+\def\thelayerheight#1{\the\ht\executeifdefined{\@@layerbox#1}\emptybox}
\def\setlayer
{\dotripleempty\dosetlayer}
@@ -620,7 +620,7 @@
\newskip\xdimension \newskip\ydimension
\newskip\xoffset \newskip\yoffset
-\newbox\positionbox
+% already defined \newbox\positionbox
\def\startpositioning
{\bgroup
diff --git a/tex/context/base/page-mak.tex b/tex/context/base/page-mak.tex
index 1637e6327..040feb1d2 100644
--- a/tex/context/base/page-mak.tex
+++ b/tex/context/base/page-mak.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / MakeUp}
+\writestatus{loading}{ConTeXt Page Macros / MakeUp}
\unprotect
@@ -164,8 +164,11 @@
\global\pageselectedfalse
\fi}
+% \def\pushpagestate{\globalpushmacro\@@pnstate}
+% \def\poppagestate {\globalpopmacro \@@pnstate}
+
\def\doshipoutmakeup
- {\globalpushmacro\@@pnstate % new
+ {\pushpagestate % new
\makeupparameter\c!before
\setbox\makeupbox\vbox{\hbox{\color[\makeupparameter\c!color]{\box\makeupbox}}}%
% \ifgridsnapping
@@ -190,7 +193,7 @@
\null
\page}]%
\fi \fi
- \globalpopmacro\@@pnstate} % new
+ \poppagestate} % new
%D The text surrounding the main body text can be influenced
%D by setting their associated status variables. The
diff --git a/tex/context/base/page-mar.tex b/tex/context/base/page-mar.tex
index 2ca82a79e..f7c5328f3 100644
--- a/tex/context/base/page-mar.tex
+++ b/tex/context/base/page-mar.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-mar, % moved here from main-001
%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Marginal Things,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -16,7 +16,7 @@
%D extended en enhanced. Therefore it's always good to watch
%D out for unexpected side effects.
-\writestatus{loading}{Context Core Macros / Maginal Things}
+\writestatus{loading}{ConTeXt Page Macros / Maginal Things}
\unprotect
@@ -599,7 +599,7 @@
% \def\dodoinmargin[#1][#2][#3][#4][#5]#6%
% {\bgroup
% \forgetall % otherwise sidefloat problems, added 2005/07/20, maybe dangerous
-% \postponefootnotes % group is (somehow) needed
+% \postponenotes % group is (somehow) needed
% \doifinsetelse\v!low{#4}
% {\chardef\margincontentdisplacement\plusone}
% {\chardef\margincontentdisplacement\zerocount}%
@@ -645,7 +645,7 @@
\chardef\marginpagecheckmethod \executeifdefined{\??im\currentmargincontent\c!splitmethod}\plusone
% so far
\forgetall % otherwise sidefloat problems, added 2005/07/20, maybe dangerous
- \postponefootnotes % group is (somehow) needed
+ \postponenotes % group is (somehow) needed
\doifinsetelse\v!low{#4}
{\chardef\margincontentdisplacement\plusone}
{\chardef\margincontentdisplacement\zerocount}%
@@ -693,7 +693,7 @@
\def\marginword {\margintext}
\def\margintitle{\margintext} % txt mark as well
-\newtoks\collectedmargintexts
+\newtoks\collectedmargintexts % so .. delayed!
\chardef\margintextcollected \zerocount
\def\domargincontent[#1][#2]#3% we used to check for #2/#1 being number, no longer now
diff --git a/tex/context/base/page-mis.tex b/tex/context/base/page-mis.tex
new file mode 100644
index 000000000..bd029f896
--- /dev/null
+++ b/tex/context/base/page-mis.tex
@@ -0,0 +1,268 @@
+%D \module
+%D [ file=page-mis,
+%D version=2008.11.17, % was part of page-flt.tex / 2000.10.20
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Misc Float Things,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Page Macros / Misc Float Things}
+
+\unprotect
+
+\newif\ifmargeblokken
+
+\def\dosetupmarginblocks[#1]%
+ {\getparameters[\??mb][#1]%
+ \doifelse\@@mbstate\v!start
+ {\showmessage\m!layouts4\empty
+ \margeblokkentrue
+ \let\somenextfloat\dosomenextfloat
+ \let\startmarginblock\dostartmarginblock
+ \let\stopmarginblock\dostopmarginblock}%
+ {\showmessage\m!layouts5\empty
+ \margeblokkenfalse
+ \def\somenextfloat[##1]%
+ {\someelsefloat[##1,\v!here]}%
+ \let\startmarginblock\dontstartmargeblok
+ \let\stopmarginblock\dontstopmargeblok}}
+
+\def\setupmarginblocks
+ {\dosingleargument\dosetupmarginblocks}
+
+\newbox\marginbox
+
+\def\dosomenextfloat[#1]%
+ {\global\setbox\marginbox\vbox
+ {\hsize\@@mbwidth
+ \unvcopy\marginbox
+ \ifvoid\marginbox\else\expandafter\@@mbinbetween\fi
+ \box\floatbox\filbreak}%
+ \ifdim\ht\marginbox>\textheight
+ \dosavefloatinfo
+ \else
+ \doinsertfloatinfo
+ \fi}
+
+\newbox\preparedmarginbox
+
+\def\reshapemargin
+ {\ifdim\ht\preparedmarginbox>\zeropoint
+ \beginofshapebox
+ \unvbox\preparedmarginbox
+ \endofshapebox
+ \reshapebox
+ {\box\shapebox}%
+ \setbox\preparedmarginbox\vbox to \textheight
+ {\@@mbtop
+ \flushshapebox
+ \@@mbbottom}%
+ \fi}
+
+\def\plaatsrechtermargeblok
+ {\hskip\rightmarginwidth}
+
+\def\plaatslinkermargeblok
+ {\hskip\leftmarginwidth}
+
+\def\checkmargeblokken
+ {\ifvoid\marginbox\else\docheckmargeblokken\fi}
+
+\def\docheckmargeblokken % erg inefficient
+ {\setbox\preparedmarginbox\vbox
+ {\forgetall
+ \splittopskip\topskip
+ \ifvoid\marginbox\else
+ \ifdim\ht\marginbox>\textheight
+ \vsplit\marginbox to \textheight
+ \else
+ \unvbox\marginbox
+ \fi
+ \fi}%
+ \reshapemargin
+ \setbox\preparedmarginbox\vbox
+ {\@@mbbefore\box\preparedmarginbox\@@mbafter}%
+ \def\rightmarginbox
+ {\def\plaatsrechtermargeblok
+ {\setbox\preparedmarginbox\hbox to \rightmarginwidth
+ {\@@mbleft\box\preparedmarginbox\@@mbright}%
+ \vsmashbox\preparedmarginbox
+ \box\preparedmarginbox}}%
+ \def\leftmarginbox
+ {\def\plaatslinkermargeblok
+ {\setbox\preparedmarginbox\hbox to \leftmarginwidth
+ {\@@mbright\box\preparedmarginbox\@@mbleft}%
+ \vsmashbox\preparedmarginbox
+ \box\preparedmarginbox}}%
+ \processaction % traag
+ [\@@mblocation]
+ [ \v!inmargin=>\doifbothsidesoverruled\rightmarginbox\rightmarginbox\leftmarginbox,
+ \v!middle=>\doifbothsidesoverruled\rightmarginbox\leftmarginbox\rightmarginbox,
+ \v!left=>\leftmarginbox,
+ \v!right=>\rightmarginbox,
+ \s!unknown=>\setbox\preparedmarginbox\hbox{}]}
+
+\def\dostartmarginblock % 2 maal \vbox ivm \unvbox elders
+ {\global\setbox\marginbox\vtop\bgroup\vbox\bgroup
+ \hsize\@@mbwidth
+ \ifvoid\marginbox\else
+ \unvbox\marginbox
+ \@@mbinbetween
+ \fi
+ \setupalign[\@@mbalign]%
+ \dostartattributes\??mb\c!style\c!color{}%
+ \begstrut\ignorespaces}
+
+\def\dostopmarginblock
+ {\unskip\endstrut
+ \dostopattributes
+ \egroup
+ \egroup}
+
+\def\dontstartmargeblok
+ {\@@mbbefore
+ \bgroup
+ \dostartattributes\??mb\c!style\c!color\empty}
+
+\def\dontstopmargeblok
+ {\dostopattributes
+ \egroup
+ \@@mbafter}
+
+\newcounter\nofpostponedblocks
+
+\newif\ifinpostponing
+
+\newevery\everytopofpage\relax
+
+\appendtoks \the\everytopofpage \to\everystarttext
+\appendtoks\global\everytopofpage\emptytoks\to\everystoptext
+
+% \startpostponing [pagenumber] [+pageoffset]
+%
+% \startpostponing[2]
+% PAGE 2 \blank
+% \stoppostponing
+%
+% \startpostponing[+1]
+% PAGE +1 \blank
+% \stoppostponing
+%
+% \startpostponing[+2]
+% PAGE +2 \blank
+% \stoppostponing
+%
+% \starttext \dorecurse{4}{\input tufte \page} \stoptext
+
+\newtoks \postponedpageblocks
+\newcounter\nofpostponedpageblocks
+
+% \ifinpostponing: handhaven, want gebruikt in stijlen ! ! ! ! !
+
+\def\flushpagefloats
+ {\doifoddpageelse
+ {\ifvoid\collectedleftpagefloats
+ \ifvoid\collectedrightpagefloats\else
+ \unvbox\collectedrightpagefloats
+ \page
+ %\the\everytopofpage
+ \fi
+ \fi}
+ {\ifvoid\collectedleftpagefloats\else
+ \unvbox\collectedleftpagefloats
+ \page
+ %\the\everytopofpage
+ \fi
+ \ifvoid\collectedrightpagefloats\else
+ \unvbox\collectedrightpagefloats
+ \page
+ %\the\everytopofpage
+ \fi}%
+ \ifvoid\collectedpagefloats\else
+ % message
+ \unvbox\collectedpagefloats
+ \fi}
+
+% \def\flushrestfloats
+% {\doif{\floatsharedparameter\c!cache}\v!no\doflushfloats}
+
+% \let\flushrestfloats\relax
+
+\def\dopostponeblock
+ {\bgroup % new may 2004
+ \setsystemmode\v!postponing % new may 2004
+ \the\everytopofpage
+ %\flushrestfloats
+ \flushpagefloats
+ \donefalse
+ \ifinpostponing \else
+ \ifcase\nofpostponedblocks \else \donetrue \fi
+ \ifcase\nofpostponedpageblocks \else \donetrue \fi
+ \fi
+ \ifdone
+ \bgroup % we need the color/font switch, else problems inside split verbatim
+ \setnormalcatcodes % postponing in verbatim
+ \pushpostponedpagecolor
+ \restoreglobalbodyfont % The \nof-test is
+ \global\pagetotal\zeropoint % recently added and
+ \global\inpostponingtrue % definitely needed else
+ \the\postponedpageblocks % we can loose or disorder
+ \dorecurse\nofpostponedblocks % floats; anyhow, this
+ {\getbuffer[pbuf-\recurselevel]}% % mechanism is still
+ \doflushfloats % new but potential dangerous % suboptimal and needs a
+ \doglobal\newcounter\nofpostponedblocks % proper analysis
+ \global\inpostponingfalse
+ \poppostponedpagecolor
+ \egroup
+ \fi
+ \egroup} % new may 2004
+
+\def\getpostponedblock#1#2%
+ {\doif{#1}\realfolio{\getbuffer[rbuf-#2]}} % no \ifnum, avoid \fi
+
+% beware, \dosingleempty conflicts with buffers (feeds back the \par)
+
+\setvalue{\e!start\v!postponing}%
+ {\bgroup
+ \obeylines
+ \doifnextoptionalelse{\egroup\nodostartpostponing}{\egroup\dodostartpostponing}}
+
+\def\nodostartpostponing[#1]%
+ {\doglobal\increment\nofpostponedpageblocks
+ \bgroup % a little bit of misusing grouping
+ \doifinstring{+}{#1}\advance \realpageno#1\relax % ugly but efficient
+ \doglobal\appendetoks\noexpand\getpostponedblock
+ {\realfolio}{\nofpostponedpageblocks}\to\postponedpageblocks
+ \egroup
+ \showmessage\m!layouts3\nofpostponedpageblocks
+ \dostartbuffer[rbuf-\nofpostponedpageblocks]%
+ [\e!start\v!postponing][\e!stop\v!postponing]}
+
+\def\dodostartpostponing
+ {\doglobal\increment\nofpostponedblocks
+ \showmessage\m!layouts3\nofpostponedblocks
+ \expanded{\dostartbuffer[pbuf-\nofpostponedblocks][\e!start\v!postponing][\e!stop\v!postponing]}}
+
+% Setups:
+
+\setupmarginblocks
+ [\c!state=\v!start,
+ \c!location=\v!inmargin,
+ \c!width=\rightmarginwidth,
+ \c!style=,
+ \c!color=,
+ \c!align=,
+ \c!left=,
+ \c!right=,
+ \c!top=,
+ \c!inbetween=\blank,
+ \c!bottom=\vfill,
+ \c!before=,
+ \c!after=]
+
+\protect \endinput
diff --git a/tex/context/base/page-mul.tex b/tex/context/base/page-mul.tex
index 5c98d7226..c78af074a 100644
--- a/tex/context/base/page-mul.tex
+++ b/tex/context/base/page-mul.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-mul, % was: core-mul
%D version=1998.03.15,
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Multi Column Output,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Simple Multi Column}
+\writestatus{loading}{ConTeXt Page Macros / Simple Multi Column}
%D This module is mostly a copy from the original multi column
%D routine as implemented in \type {core-mul}. When the main
@@ -464,7 +464,7 @@
\global\output{\continuousmulticolumnsout}%
\setcolumnfloats
\dohandleallcolumns
- {\global\setbox\currenttopcolumnbox\box\voidb@x}%
+ {\global\setbox\currenttopcolumnbox\emptybox}%
\checkbegincolumnfootnotes
\activateotr{MUL}{ONE}% todo ! ! ! !
\let\sethsize\setcolumnhsize
@@ -642,7 +642,7 @@
{\ifdim-\ht\currenttopcolumnbox<\scratchdimen
\scratchdimen-\ht\currenttopcolumnbox
\fi
- \global\setbox\currenttopcolumnbox\box\voidb@x}%
+ \global\setbox\currenttopcolumnbox\emptybox}%
\advance\scratchdimen \ht\columnpagebox
\setbox\scratchbox\hbox to \columntextwidth
{\vrule
diff --git a/tex/context/base/page-not.tex b/tex/context/base/page-not.tex
index 151f957f4..9c67f18f1 100644
--- a/tex/context/base/page-not.tex
+++ b/tex/context/base/page-not.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Footnotes}
+\writestatus{loading}{ConTeXt Page Macros / Footnotes}
%D Terrible hacks: we need to share save/restore
diff --git a/tex/context/base/page-num.tex b/tex/context/base/page-num.tex
index cad7d6790..95eeea806 100644
--- a/tex/context/base/page-num.tex
+++ b/tex/context/base/page-num.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-num, % moved here from main-001
%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Numbering,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Numbering}
+\writestatus{loading}{ConTeXt Page Macros / Numbering}
% todo: {}{}{} ipv ...--...-...-...--... in pag ref
@@ -171,6 +171,8 @@
\countdef\subpageno = 2 \subpageno = 0 % !!
\countdef\arrangeno = 3 \arrangeno = 0 % !!
+\let\pageno\userpageno
+
% we don't want conflicts when \pageno is used by other
% packages, like CWEB, so we redefine \pageno
@@ -279,7 +281,10 @@
% \@@pnstatus global, but \@@nmstatus local and only start/stop
-\global\let\@@pnstate\@@pnstate
+\global\let\@@pnstate\@@pnstate % brrr
+
+\def\pushpagestate{\globalpushmacro\@@pnstate}
+\def\poppagestate {\globalpopmacro \@@pnstate}
\def\dosetuppagenumber[#1]%
{\getparameters[\??pn][\c!number=,#1]%
@@ -432,11 +437,11 @@
\def\preparepageprefix#1%
{\def\dopreparepageprefix##1%
- {\letvalue{#1\getvalue{\??by##1}\v!number}\v!no}% %v
+ {\ifcsname\??by##1\endcsname\letvalue{#1\csname\??by##1\endcsname\v!number}\v!no\fi}% %v
\rawprocesscommalist[\@@kolist]\dopreparepageprefix
\def\dopreparepageprefix##1%
{\doifvalue{#1##1\v!number}\v!yes %v
- {\letvalue{#1\getvalue{\??by##1}\v!number}\v!yes}}%
+ {\ifcsname\??by##1\endcsname\letvalue{#1\csname\??by##1\endcsname\v!number}\v!yes\fi}}%
\rawprocesscommalist[\@@kolist]\dopreparepageprefix}
\def\dodopageprefix#1% uti seperator --
diff --git a/tex/context/base/page-one.tex b/tex/context/base/page-one.mkii
index f33aa4602..1affc24d0 100644
--- a/tex/context/base/page-one.tex
+++ b/tex/context/base/page-one.mkii
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-one,
%D version=2000.10.20,
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Default Routine,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Default Routine}
+\writestatus{loading}{ConTeXt Page Macros / Default Routine}
%D This is just the good old \CONTEXT\ output routine, which
%D has been there right from the start.
diff --git a/tex/context/base/page-one.mkiv b/tex/context/base/page-one.mkiv
new file mode 100644
index 000000000..19ab43889
--- /dev/null
+++ b/tex/context/base/page-one.mkiv
@@ -0,0 +1,662 @@
+%D \module
+%D [ file=page-one,
+%D version=2000.10.20,
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Default Routine,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Page Macros / Default Routine}
+
+%D This is just the good old \CONTEXT\ output routine, which
+%D has been there right from the start.
+
+\unprotect
+
+% OTRONE: basic single column
+
+\activateotr{ONE}{} % the default one
+
+\newtoks\OTRONEoutput
+
+\def\OTRONEgotonextpage
+ {\ejectpage}
+
+\def\OTRONEgotonextpageX % will become obsolete
+ {\superejectpage}
+
+\def\OTRONEsethsize
+ {\global\hsize\textwidth}
+
+% keep (original one)
+%
+% \def\OTRONEsetvsize
+% {\ifdim\vsize=\teksthoogte \else
+% \bgroup
+% \scratchdimen-\vsize
+% \advance\scratchdimen \teksthoogte
+% \global\advance\vsize \scratchdimen
+% \relax \ifdim\pagegoal<\maxdimen
+% \advance\scratchdimen \pagegoal
+% \global\pagegoal\scratchdimen
+% \fi
+% \egroup
+% \fi}
+%
+% no (keep)
+%
+% \def\OTRONEsetvsize
+% {\ifdim\vsize=\teksthoogte \else
+% \bgroup
+% \scratchdimen-\vsize
+% \advance\scratchdimen \teksthoogte
+% \ifgridsnapping
+% \getrawnoflines\scratchdimen
+% \scratchdimen\noflines\openlineheight
+% \ifdim\scratchdimen>\noflinesheight % available afterwards
+% \advance\scratchdimen-\openlineheight
+% \fi
+% \ifdim\scratchdimen<\zeropoint
+% \scratchdimen\zeropoint
+% \fi
+% \fi
+% \global\advance\vsize \scratchdimen
+% \relax \ifdim\pagegoal<\maxdimen
+% \advance\scratchdimen \pagegoal
+% \global\pagegoal\scratchdimen
+% \fi
+% \egroup
+% \fi}
+
+% \def\OTRONEsetvsize
+% {\ifgridsnapping
+% \ifcase\layoutlines
+% \getrawnoflines\teksthoogte
+% \else
+% \noflines\layoutlines
+% \fi
+% \global\vsize\noflines\openlineheight
+% \else
+% \global\vsize\teksthoogte
+% \fi
+% \ifdim\pagegoal<\maxdimen
+% \global\pagegoal\vsize
+% \fi}
+
+\newdimen\oldvsize
+
+\def\OTRONEsetvsize
+ {\ifgridsnapping
+ \ifcase\layoutlines
+ \getrawnoflines\textheight
+ \else
+ \noflines\layoutlines
+ \fi
+ \global\vsize\noflines\openlineheight
+ \else
+ \global\vsize\textheight
+ \fi
+ \ifdim\pagegoal<\maxdimen
+ \ifdim\oldvsize=\vsize
+ % let's assume that the layout didn't change
+ \else
+ \bgroup
+ \global\oldvsize\vsize
+ \advance\vsize-\topinserted
+ \advance\vsize-\botinserted
+ \global\pagegoal\vsize
+ \egroup
+ \fi
+ \fi}
+
+\chardef\kindofpagetextareas=2 % whole page (public variable! never change)
+
+\def\OTRONEregisteredtextarea#1%
+ {\ifregistertextareas
+ \setbox0\vbox{#1}%
+ \wd0\makeupwidth % somehow a space creeps in
+ \vbox{\registeredtextarea000}%
+ \else
+ #1%
+ \fi}
+
+% \chardef\kindofpagetextareas\plusone
+
+\def\doOTRONEregisteredtextareaA#1%
+ {\ifregistertextareas
+ \xypos{pbd:\realfolio:b}% we could save bytes by only saving the y
+ \endgraf
+ \begingroup
+ \scratchdimen\MPy{pbd:\realfolio:b}%
+ \advance\scratchdimen-\MPy{pbd:\realfolio:e}%
+ \setbox\scratchbox\null
+ \wd\scratchbox\makeupwidth
+ \ht\scratchbox\scratchdimen
+ \vsmash{\registeredtextarea00\scratchbox}%
+ \endgroup
+ #1%
+ \endgraf
+ \xypos{pbd:\realfolio:e}%
+ \else
+ #1%
+ \fi}
+
+\def\doOTRONEregisteredtextareaB#1%
+ {\ifregistertextareas
+ \setbox0\vbox{#1}%
+ \wd0\makeupwidth % somehow a space creeps in
+ \vbox{\registeredtextarea000}%
+ \else
+ #1%
+ \fi}
+
+\let\OTRONEregisteredtextareaA\firstofoneargument
+\let\OTRONEregisteredtextareaB\firstofoneargument
+
+\def\OTRONEdopagecontents#1#2% \box<n> \unvbox<n>
+ {\bgroup % niet breedte zetten, kan fractie zijn!
+ \ifcase\kindofpagetextareas
+ \or % partial page (experimental)
+ \let\OTRONEregisteredtextareaA\doOTRONEregisteredtextareaA
+ \or % whole page (default)
+ \let\OTRONEregisteredtextareaB\doOTRONEregisteredtextareaB
+ \or % partial page (only works well with no stretch!)
+ \let\OTRONEregisteredtextareaA\doOTRONEregisteredtextareaB
+ \fi
+ \setbox0\vbox \ifbottomnotes to \textheight \fi
+ {\edef\currentpagedepth{\the\dp#2}% still to be derived from #1
+ \dotopinsertions
+ \ifgridsnapping
+ \OTRONEregisteredtextareaA{#1#2}%
+ \vskip-\currentpagedepth\vskip\openstrutdepth
+ \pushproperties % moved from just after #1#2
+ \prevdepth\openstrutdepth
+ \dobotinsertions
+ \vfil
+ \else\ifr@ggedbottom
+ \OTRONEregisteredtextareaA{#1#2}%
+ \vskip-\currentpagedepth\vskip\openstrutdepth
+ \pushproperties % moved from just after #1#2
+ \prevdepth\openstrutdepth
+ \dobotinsertions
+ \vfil
+ \else\ifb@selinebottom
+ \OTRONEregisteredtextareaA{#1#2}%
+ \kern-\currentpagedepth\kern\maxdepth
+ \pushproperties % moved from just after #1#2
+ \dobotinsertions
+ \else
+ \OTRONEregisteredtextareaA{#1#2}%
+ \pushproperties % moved from just after #1#2
+ \dobotinsertions % added
+ \fi\fi\fi
+ \fakepagenotes}% was \fakenotes, but wrong! (check with \setupalign[height])
+ \ifbottomnotes
+ \ifgridsnapping
+\ifcase\layoutlines % todo: make macro of this
+ \getrawnoflines\textheight
+\else
+ \noflines\layoutlines
+\fi
+% \getnoflines\textheight
+ \advance\noflines \minusone
+ \scratchdimen\noflines\lineheight
+ \advance\scratchdimen \topskip
+ \else
+ \scratchdimen\ht0
+ \fi
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \setbox2\hbox
+ {\checksinglecolumnfootnotes
+ \lower\scratchdimen\vbox{\placebottomnotes}}%
+ \smashbox2% % needed here
+ \ifbottomnotes
+ \ht0\zeropoint
+ \fi
+ \OTRONEregisteredtextareaB
+ {\vbox to \textheight
+ {\box0\box2\ifbottomnotes\else\vfill\fi}}%
+ \egroup}
+
+\def\OTRONEfinalsidefloatoutput
+ {\finaloutput\unvbox\normalpagebox}
+
+\OTRONEoutput
+ {\sidefloatoutput}
+
+%D Insertions
+
+\newif\iftopofinsert
+
+% \def\OTRONEdosettopinserts
+% {\bgroup
+% \ifsomefloatwaiting
+% \noffloatinserts\zerocount
+% \let\totaltopinserted\!!zeropoint
+% \OTRONEdodosettopinserts
+% \ifnum\@@bknbottom=\zerocount
+% \ifnum\@@bknlines>\zerocount
+% \ifdim\totaltopinserted>\zeropoint\relax
+% \dimen0=\lineheight
+% \dimen0=\@@bknlines\dimen0
+% \advance\dimen0 \totaltopinserted\relax
+% \ifdim\dimen0>\textheight
+% \showmessage\m!floatblocks8\@@bknlines
+% \vfilll\eject
+% \fi
+% \fi
+% \fi
+% \fi
+% \fi
+% \egroup}
+
+\def\OTRONEdosettopinserts
+ {\bgroup
+ \ifsomefloatwaiting
+ \noffloatinserts\zerocount
+ \let\totaltopinserted\!!zeropoint
+ \OTRONEdodosettopinserts
+ \ifnum\@@bknbottom=\zerocount
+ \ifnum\@@bknlines>\zerocount
+ \ifdim\totaltopinserted>\zeropoint\relax
+ \ifdim\dimexpr\@@bknlines\lineheight+\totaltopinserted\relax>\textheight
+ \showmessage\m!floatblocks8\@@bknlines
+ \vfilll\eject
+ \fi
+ \fi
+ \fi
+ \fi
+ \fi
+ \egroup}
+
+\def\OTRONEdodosettopinserts
+ {\ifnum\noffloatinserts<\noftopfloats
+ \dogetfloat
+ \ifdim\topinserted=\zeropoint
+ \topofinserttrue
+ \else
+ \topofinsertfalse
+ \fi
+ \global\advance\topinserted\dimexpr\ht\floatbox+\dp\floatbox+\floatbottomskip\relax
+ \ifdim\topinserted<\textheight\relax
+ \xdef\totaltopinserted{\the\topinserted}%
+ \insert\topins
+ {\forgetall
+ \iftopofinsert
+ \topskipcorrection % [xx] new: see icare topbleed
+ \kern-\lineskip\par
+ \prevdepth\maxdimen
+ \else
+ %\blank[-\@@bkspaceafter,\@@bkspacebefore]% inserts can't look back
+ \betweenfloatblanko
+ \fi
+ \flushfloatbox
+ \blank[\@@bkspaceafter]}%
+ \ifsomefloatwaiting
+ \advance\noffloatinserts \plusone
+ \else
+ \noffloatinserts\noftopfloats\relax
+ \fi
+ \dofloatflushedinfo
+ \else
+ \doresavefloat
+ \noffloatinserts\noftopfloats\relax
+ \fi
+ \else
+ \ifsomefloatwaiting
+ \showmessage\m!floatblocks6{\the\noftopfloats}%
+ \fi
+ \let\OTRONEdodosettopinserts\relax
+ \fi
+ \OTRONEdodosettopinserts}
+
+\def\OTRONEdosetbotinserts
+ {\bgroup
+ \ifsomefloatwaiting
+ \noffloatinserts\zerocount
+ \OTRONEdodosetbotinserts
+ \fi
+ \egroup}
+
+\def\OTRONEdodosetbotinserts
+ {\ifnum\noffloatinserts<\nofbotfloats\relax
+ \dogetfloat
+ \global\advance\botinserted \ht\floatbox\relax
+ \global\advance\botinserted \dp\floatbox\relax
+ \global\advance\botinserted \floattopskip\relax
+ \ifdim\botinserted<\pagegoal\relax
+ \insert\botins
+ {\forgetall
+ \blank[\@@bkspacebefore]%
+ \flushfloatbox}%
+ \ifsomefloatwaiting
+ \advance\noffloatinserts \plusone
+ \else
+ \noffloatinserts\nofbotfloats
+ \fi
+ \dofloatflushedinfo
+ \else
+ \doresavefloat
+ \noffloatinserts\nofbotfloats\relax
+ \fi
+ \global\nofloatpermittedtrue % vgl topfloats s!
+ \else
+ \ifsomefloatwaiting
+ \showmessage\m!floatblocks7{\the\nofbotfloats}%
+ \fi
+ \let\OTRONEdodosetbotinserts\relax
+ \fi
+ \OTRONEdodosetbotinserts}
+
+\def\OTRONEdosetbothinserts
+ {\global\topinserted\zeropoint
+ \global\botinserted\zeropoint
+ \ifflushingfloats \else
+ \OTRONEdosettopinserts
+ \OTRONEdosetbotinserts
+ \ifsomefloatwaiting
+ \doif\@@bkcache\v!no\doflushfloats
+ \fi
+ \fi}
+
+% \def\OTRONEdotopinsertions
+% {\ifvoid\topins\else
+% \ifgridsnapping
+% \box\topins
+% \vskip-\topskip \vskip\strutheight % [xx] new: see icare topbleed
+% \else
+% \unvbox\topins
+% \fi
+% \fi
+% \global\topinserted\zeropoint}
+
+\chardef\topinserttopskipmode=0 % 1 no topskip
+
+\def\OTRONEdotopinsertions
+ {\ifvoid\topins\else
+ \ifgridsnapping
+ \box\topins
+ \vskip-\topskip
+ \vskip\strutheight % [xx] new: see icare topbleed
+ \else
+ \ifcase\topinserttopskipmode
+ % 0: default, do nothing
+ \or
+ % 1: no topskip (crossed fingers)
+ \vskip-\topskip
+ \vskip\strutheight
+ \fi
+ \unvbox\topins
+ \fi
+ \fi
+ \global\topinserted\zeropoint}
+
+\def\OTRONEdobotinsertions
+ {\ifvoid\botins\else
+ \ifgridsnapping
+ % \floatparameter\c!bottombefore
+ \snaptogrid\hbox{\box\botins}%
+ % \floatparameter\c!bottomafter
+ \else
+ \floatparameter\c!bottombefore
+ \unvbox\botins
+ \floatparameter\c!bottomafter
+ \fi
+ \fi
+ \global\botinserted\zeropoint
+ \global\nofloatpermittedfalse}
+
+\def\OTRONEdoflushfloats
+ {\global\flushingfloatstrue
+ \ifsomefloatwaiting
+ \par
+ % if kept, then option and definitely off in gridmode ! ! ! !
+ % \ifvmode \prevdepth\maxdimen \fi % prevents whitespace; problematic in icare tests
+ \OTRONEdodoflushfloats
+ \fi
+ \global\savednoffloats\zerocount
+ \global\somefloatwaitingfalse
+ \global\flushingfloatsfalse}
+
+\def\OTRONEflushfloatbox % nog verder doorvoeren en meer info in marge
+ {\ifcenterfloatbox \ifdim\wd\floatbox<\hsize
+ \setbox\floatbox\hbox to \hsize{\hss\box\floatbox\hss}%
+ \fi \fi
+ \snaptogrid\hbox{\iftestfloatbox\ruledhbox\fi{\copy\floatbox}}}
+
+\def\OTRONEdodoflushfloats % much in common with OTRSET
+ {\ifsomefloatwaiting
+ \ifpackflushedfloats
+ \centerfloatboxfalse
+ \dogetfloat
+ \ifdim\wd\floatbox>\makeupwidth
+ \global\setbox\floatbox\hbox to \makeupwidth{\hss\box\floatbox\hss}%
+ \fi
+ \OTRONEsetvsize
+ \!!widtha\wd\floatbox
+ \dofloatflushedinfo
+ \doloop
+ {\ifsomefloatwaiting
+ \dosavefloatstatus
+ \dogetfloat
+ \advance\!!widtha 1em % variable
+ \advance\!!widtha \wd\floatbox\relax
+ \ifdim\!!widtha>\hsize
+ \dorestorefloatstatus
+ \global\somefloatwaitingtrue
+ \exitloop
+ \else
+ \global\setbox\floatbox\hbox
+ {\ifcase\columndirection % nog document wide
+ \ifvoid\savedfloatbox\else
+ \ifhbox\savedfloatbox\unhbox\else\box\fi\savedfloatbox\hfil
+ \fi
+ \ifhbox\floatbox\unhbox\else\box\fi\floatbox
+ \else
+ \ifhbox\floatbox\unhbox\else\box\fi\floatbox
+ \ifvoid\savedfloatbox\else
+ \hfil\ifhbox\savedfloatbox\unhbox\else\box\fi\savedfloatbox
+ \fi
+ \fi}%
+ \dofloatflushedinfo
+ \fi
+ \else
+ \exitloop
+ \fi}%
+ \global\setbox\floatbox\hbox to \hsize
+ {\hfil\ifhbox\floatbox\unhbox\else\box\fi\floatbox\hfil}%
+ \else
+ %\bgroup % \box\floatbox can be in use!? messy
+ \dogetfloat
+ %\doplacefloatbox
+ %\egroup
+ \dofloatflushedinfo
+ \fi
+ % there is a chance that due to rounding errors, the float
+ % fits on a page where it was first rejected, in which case
+ % the prevdepth is -maxdimen and we cannot obey the grid
+ \doplacefloatbox
+ \expandafter\OTRONEdodoflushfloats
+ \fi}
+
+\def\OTRONEdocheckiffloatfits % vervangen ivm downward comp
+ {\ifnofloatpermitted
+ \global\roomforfloatfalse
+ \else
+ % new per 31/5/2004, should be an option, only one column mode
+ \begingroup
+ \scratchdimen\dimexpr\pagetotal+\lineheight\relax
+ \ifdim\scratchdimen>\pagegoal
+ \goodbreak % hack ? needed in icare-az
+ \fi
+ % should be an option
+ \endgroup
+ \dimen0\dimexpr\pagetotal+\ht\floatbox+\dp\floatbox+\floattopskip-\pageshrink\relax
+ %\message{c:\the\mofcolumns,t:\the\pagetotal,g:\the\pagegoal}%\wait
+ \dimen2\pagegoal
+ \relax % needed
+ \ifcase\textfloatmethod
+ % method 0 : raw
+ \or
+ % method 1 : safe
+ \dimen2 .99\pagegoal
+ \or
+ % method 2 : tight
+ \advance\dimen0 -\onepoint
+ \fi
+ \relax % really needed ! ! ! !
+ \ifdim\dimen0>\dimen2
+ \global\roomforfloatfalse
+ \else
+ \global\roomforfloattrue
+ \fi
+ \fi}
+
+\def\OTRONEflushsavedfloats
+ {\dosetbothinserts}
+
+% TODO: TEST FIRST, NO CORRECTION NEEDED IN GRID MODE, EVT OPTION
+
+\def\OTRONEsomeherefloat[#1]% spacing between two successive must be better
+ {\baselinecorrection % not really needed in grid mode:
+ %\ifgridsnapping \else \baselinecorrection \fi % ! ! ! test test test ! ! ! !
+ \doplacefloatbox
+ \doinsertfloatinfo
+ \dohandlenextfloatindent}
+
+% \def\OTRONEsomefixdfloat % [#1]
+% {\docheckiffloatfits
+% \ifroomforfloat\else
+% \goodbreak
+% \fi
+% \showmessage\m!floatblocks9\empty
+% \someherefloat} % [#1]
+%
+% better:
+%
+% \dorecurse{50}
+% {[before normal] \input thuan
+% \placefigure{normal}{\framed[height=1cm,width=8cm]{}}
+% \placefigure{normal}{\framed[height=2cm,width=8cm]{}}
+% [before force] \input thuan
+% \placefigure[force]{force}{\framed[height=8cm,width=8cm]{}}}
+
+\chardef\fixedfloatmethod=3
+
+% \def\OTRONEsomefixdfloat % [#1]
+% {\docheckiffloatfits
+% \ifroomforfloat\else
+% \ifzeropt\pagetotal
+% % let's assume that there is room
+% \else
+% \ifcase\fixedfloatmethod
+% % disabled
+% \or % 1 (old method)
+% \goodbreak
+% \or % 2 (safe method)
+% \page
+% \or % 3 (keeps in stream)
+% \vskip\textheight
+% \vskip-\textheight
+% \or % 4 (also keeps in place)
+% \dosomebreak\nobreak
+% \fi
+% \fi
+% \fi
+% \showmessage\m!floatblocks9\empty
+% \someherefloat} % [#1]
+
+\def\OTRONEsomefixdfloat % [#1]
+ {% there is (in mkii) no good way to prevent a break
+ % so better fail than mess, we can get loose from
+ % heads, so be it
+ \showmessage\m!floatblocks9\empty
+ \OTRONEsomeherefloat} % [#1]
+
+\def\OTRONEsomesidefloat[#1]% links, rechts NOG TESTEN EN AANPASSEN
+ {\ifinsidecolumns
+ \someelsefloat[\v!here]%
+ \else
+ %\checkwaitingfloats{#1}%
+ \def\logsidefloat
+ {\doinsertfloatinfo}%
+ \setbox\floatbox\vbox{\box\floatbox}%
+ \wd\floatbox\floatwidth
+ \processfirstactioninset
+ [#1]
+ [ \v!left=>\leftfloat {\box\floatbox},
+ \v!right=>\rightfloat {\box\floatbox},
+ \v!inleft=>\leftmarginfloat {\box\floatbox},
+ \v!inright=>\rightmarginfloat{\box\floatbox},
+ \v!leftmargin=>\leftmarginfloat {\box\floatbox},
+ \v!rightmargin=>\rightmarginfloat{\box\floatbox},
+ \v!leftedge=>\leftedgefloat {\box\floatbox},
+ \v!rightedge=>\rightedgefloat {\box\floatbox},
+ \v!backspace=>\backspacefloat {\box\floatbox},
+ \v!cutspace=>\cutspacefloat {\box\floatbox},
+ \v!inmargin=>\cutspacefloat {\box\floatbox}]%
+ \doifinset\v!tall{#1}\flushsidefloatsafterpar
+ \fi}
+
+\def\OTRONEdosomepagefloat#1[#2]%
+ {%\checkwaitingfloats{#1}%
+ \global\setbox#1\vbox
+ {\unvbox#1%
+ \vbox to \textheight
+ {\doifnotinset\v!high{#2}\vfill
+ \box\floatbox
+ \doifnotinset\v!low{#2}\vfill}%
+ \goodbreak}%
+ \doinsertfloatinfo}
+
+\def\OTRONEsomepagefloat {\OTRONEdosomepagefloat\collectedpagefloats}
+\def\OTRONEsomeleftpagefloat {\OTRONEdosomepagefloat\collectedleftpagefloats}
+\def\OTRONEsomerightpagefloat{\OTRONEdosomepagefloat\collectedrightpagefloats}
+
+\def\OTRONEsometopsfloat[#1]%
+ {\ifdim\topinserted=\zeropoint
+ \topofinserttrue
+ \else
+ \topofinsertfalse
+ \fi
+ \global\advance\topinserted \ht\floatbox
+ \global\advance\topinserted \dp\floatbox
+ \global\advance\topinserted \floatbottomskip
+ \insert\topins
+ {\forgetall
+ \iftopofinsert
+ \topskipcorrection % [xx] new: see icare topbleed
+ \kern-\lineskip\par\prevdepth\maxdimen
+ \else
+ %\blank[-\@@bkspaceafter,\@@bkspacebefore]% inserts can't look back
+ \betweenfloatblanko
+ \fi
+ \flushfloatbox
+ \blank[\@@bkspaceafter]}%
+ \doinsertfloatinfo}
+
+\def\OTRONEsomebotsfloat[#1]%
+ {\global\advance\botinserted \ht\floatbox
+ \global\advance\botinserted \dp\floatbox
+ \global\advance\botinserted \floattopskip
+ \insert\botins
+ {\forgetall
+ \blank[\@@bkspacebefore]%
+ \flushfloatbox}%
+ %\global\nofloatpermittedtrue
+ \doinsertfloatinfo}
+
+\def\OTRONEsomefacefloat[#1]% untested
+ {\startopposite\flushfloatbox\stopopposite}
+
+\def\OTRONEnextcolumn[#1]%
+ {}
+
+\protect \endinput
diff --git a/tex/context/base/page-par.tex b/tex/context/base/page-par.tex
index fa1723d37..a5dea2e63 100644
--- a/tex/context/base/page-par.tex
+++ b/tex/context/base/page-par.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-par, % copied from page-lin
%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Line Numbering,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Paragraph Numbering}
+\writestatus{loading}{ConTeXt Page Macros / Paragraph Numbering}
\unprotect
diff --git a/tex/context/base/page-plg.tex b/tex/context/base/page-plg.tex
index 486d4e183..3203b923c 100644
--- a/tex/context/base/page-plg.tex
+++ b/tex/context/base/page-plg.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-pls,
%D version=2003.03.16,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Page Setup,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -13,7 +13,7 @@
\ifx\pageareabox\undefined \else \endinput \fi
-\writestatus{loading}{Context Core Macros / Extra Page Building}
+\writestatus{loading}{ConTeXt Page Macros / Extra Page Building}
%D This feature has been present for a while but has never been
%D exploited: pluggable pagebuilders. The next example code
diff --git a/tex/context/base/page-run.tex b/tex/context/base/page-run.tex
index 302a1b5a0..ae5af81e9 100644
--- a/tex/context/base/page-run.tex
+++ b/tex/context/base/page-run.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Runtime Macros}
+\writestatus{loading}{ConTeXt Page Macros / Runtime Macros}
\unprotect
diff --git a/tex/context/base/page-set.tex b/tex/context/base/page-set.tex
index 16a9dcc99..a9d42bce8 100644
--- a/tex/context/base/page-set.tex
+++ b/tex/context/base/page-set.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-set,
%D version=2000.10.20,
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Column Sets,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -15,7 +15,7 @@
% some day: cleanup and go etex
-\writestatus{loading}{Context OTR Macros / Column Sets}
+\writestatus{loading}{ConTeXt Page Macros / Column Sets}
% todo : last longer than previous
% todo : block span over last column if footnotes
@@ -217,13 +217,13 @@
\edef\!!stringb{\the\scratchcounter}%
\dostepwiserecurse \zerocount \columnmaxcells \plusone
{\ifcsname\@otr@:\!!stringa:\recurselevel\endcsname
- \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box
+ \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
\ifcsname\@otr@:\!!stringb:\recurselevel\endcsname
- \csname\@otr@:\!!stringb:\recurselevel\endcsname
+ \box\csname\@otr@:\!!stringb:\recurselevel\endcsname
%\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\csname\@otr@:\!!stringb:\recurselevel\endcsname
\else
- \voidb@x
- %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
+ \emptybox
+ %\global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\emptybox
\expandafter\newbox\csname\@otr@:\!!stringb:\recurselevel\endcsname
\fi
\else
@@ -239,7 +239,7 @@
{\let\!!stringa\recurselevel
\dostepwiserecurse \zerocount \columnmaxcells \plusone
{\ifcsname\@otr@:\!!stringa:\recurselevel\endcsname
- \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\box\voidb@x
+ \global\setbox\csname\@otr@:\!!stringa:\recurselevel\endcsname\emptybox
\else
\expandafter\newbox\csname\@otr@:\!!stringa:\recurselevel\endcsname
\fi}}%
@@ -266,7 +266,7 @@
{\doOTRSETsetgridcells{\copy\placeholderboxb}}
\def\OTRSETerasegridcells#1#2#3#4%
- {\doOTRSETsetgridcells{\box\voidb@x}{#1}{#2}{#3}{#4}{\box\voidb@x}}
+ {\doOTRSETsetgridcells{\emptybox}{#1}{#2}{#3}{#4}{\emptybox}}
\def\setupcolumnsetlines{\doquintupleempty\dosetupcolumnsettrick[l]}
\def\setupcolumnsetstart{\doquintupleempty\dosetupcolumnsettrick[s]}
@@ -298,15 +298,15 @@
\ifnum\csname#1\mofcolumns\endcsname=\zerocount
#2%
\else
- \number\numexpr(\ifnum\csname#1\mofcolumns\endcsname<\zerocount
- \columnmaxcells+\fi\csname#1\mofcolumns\endcsname)%
+ \number\numexpr\ifnum\csname#1\mofcolumns\endcsname<\zerocount
+ \columnmaxcells+\fi\csname#1\mofcolumns\endcsname\relax
\fi
\else\ifcsname#10\endcsname
\ifnum\csname#10\endcsname=\zerocount
#2%
\else
- \number\numexpr(\ifnum\csname#10\endcsname<\zerocount
- \columnmaxcells+\fi\csname#10\endcsname)%
+ \number\numexpr\ifnum\csname#10\endcsname<\zerocount
+ \columnmaxcells+\fi\csname#10\endcsname\relax
\fi
\else
#2%
diff --git a/tex/context/base/page-sid.tex b/tex/context/base/page-sid.tex
index 02c4261fb..90d6ec1a7 100644
--- a/tex/context/base/page-sid.tex
+++ b/tex/context/base/page-sid.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-sid,
%D version=2000.10.20,
-%D title=\CONTEXT\ OTR Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Side Floats,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Side Floats}
+\writestatus{loading}{ConTeXt Page Macros / Side Floats}
\unprotect
diff --git a/tex/context/base/page-spr.tex b/tex/context/base/page-spr.tex
index 53d508752..06947a36a 100644
--- a/tex/context/base/page-spr.tex
+++ b/tex/context/base/page-spr.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Spreading}
+\writestatus{loading}{ConTeXt Page Macros / Spreading}
% This module is experimental and not yet official!
diff --git a/tex/context/base/page-str.tex b/tex/context/base/page-str.tex
index 1a68adf52..2fb53bc6a 100644
--- a/tex/context/base/page-str.tex
+++ b/tex/context/base/page-str.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=page-str,
%D version=2006.03.21,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Page Macros,
%D subtitle=Page Streams,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Page Macros / Page Streams}
+\writestatus{loading}{ConTeXt Page Macros / Page Streams}
%D The first version of this component of \CONTEXT\ was written
%D for Thomas Schmitz who asked for parallel page streams. While
@@ -92,7 +92,7 @@
\def\saveoutputstream[#1]%
{\writestatus{otr}{saving otr stream #1}%
\ifvoid\normalpagebox
- \global\setbox\outputstreamtag{#1}\voidbox
+ \global\setbox\outputstreamtag{#1}\emptybox
\else
\global\setbox\outputstreamtag{#1}\vbox
{\presetoutputstream
diff --git a/tex/context/base/page-txt.tex b/tex/context/base/page-txt.mkii
index b40ecb16e..9fe73bec1 100644
--- a/tex/context/base/page-txt.tex
+++ b/tex/context/base/page-txt.mkii
@@ -13,7 +13,7 @@
% \setuplayouttext in manual
-\writestatus{loading}{Context Page Macros / Texts}
+\writestatus{loading}{ConTeXt Page Macros / Texts}
\unprotect
@@ -430,9 +430,9 @@
\stoplayoutcomponent}%
\addtextbackground\scratchpagebox
\addtextgridlayer\scratchpagebox
- \localstarttextcolor
+ \localstarttextcolor % does not work in mkiv
\box\scratchpagebox
- \localstoptextcolor
+ \localstoptextcolor % so we have to change this
\bgroup
\hskip\rightmargindistance
\ifdim\rightmarginwidth>\zeropoint
diff --git a/tex/context/base/page-txt.mkiv b/tex/context/base/page-txt.mkiv
new file mode 100644
index 000000000..57bc02882
--- /dev/null
+++ b/tex/context/base/page-txt.mkiv
@@ -0,0 +1,808 @@
+%D \module
+%D [ file=page-txt, % copied from main-001,
+%D version=1997.03.31,
+%D title=\CONTEXT\ Page Macros,
+%D subtitle=Texts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% where we can do some mkiv cleanup
+
+% \setuplayouttext in manual
+
+\writestatus{loading}{ConTeXt Page Macros / Texts}
+
+\unprotect
+
+\let\dodummypageskip\gobbleoneargument % obsolete
+
+%D Interfacing between this and other modules is handled by
+%D the following macros. The current state of a text line
+%D (header, footer, etc.) is checked by:
+%D
+%D \starttyping
+%D \resetlayouttextlines
+%D \stoptyping
+%D
+%D The main text box is finished by the following macro:
+%D
+%D \starttyping
+%D \getmainbox <box> <\vbox|\unvbox>
+%D \stoptyping
+%D
+%D The text lines are collected with:
+%D
+%D \starttyping
+%D \gettextboxes
+%D \stoptyping
+%D
+%D It is possible to extens the default content of the text
+%D areas by appending content to the following token list
+%D registers:
+
+\newtoks\toptextcontent \newtoks\leftedgetextcontent
+\newtoks\headertextcontent \newtoks\leftmargintextcontent
+\newtoks\footertextcontent \newtoks\rightmargintextcontent
+\newtoks\bottomtextcontent \newtoks\rightedgetextcontent
+
+\newtoks\texttextcontent
+
+%D \macros
+%D {setuptop, setupheader, setuptext,
+%D setupfooter, setupbottom}
+%D
+%D The macros in this module sometimes look a bit more complicated
+%D than needed, which is a direct result of the fact that their
+%D ancestors are quite old and upward compatibility is a must.
+%D
+%D \showsetup{setuptop}
+%D \showsetup{setupheader}
+%D \showsetup{setuptext}
+%D \showsetup{setupfooter}
+%D \showsetup{setupbottom}
+
+\def\setuplayouttext
+ {\dotripleempty\dosetuplayouttext}
+
+\def\dosetuplayouttext[#1][#2][#3]% beware, non global
+ {\ifthirdargument
+ \getparameters[\??tk#1#2][#3]%
+ \else
+ %\getparameters[\??tk#1\v!text][#2]%
+ \edef\previoustextstate{\getvalue{\??tk#1\c!state}}%
+ \getparameters[\??tk#1][#2]%
+ \doifnotvalue{\??tk#1\c!state}\previoustextstate
+ {%\checkcurrentlayout % no
+ \edef\currenttextstate{\getvalue{\??tk#1\c!state}}%
+ % speed optimization (calculating backgrounds takes time)
+ \doifcommon{\previoustextstate,\currenttextstate}{\v!high,\v!none}
+ {\calculatevsizes
+ \recalculatebackgrounds
+ \recalculatelogos}}%
+ \fi}
+
+\def\setuptop {\dotripleempty\dosetuplayouttext[\v!top]}
+\def\setupheader {\dotripleempty\dosetuplayouttext[\v!header]}
+\def\setuptext {\dotripleempty\dosetuplayouttext[\v!text]}
+\def\setupfooter {\dotripleempty\dosetuplayouttext[\v!footer]}
+\def\setupbottom {\dotripleempty\dosetuplayouttext[\v!bottom]}
+
+%D \macros
+%D {noheaderandfooterlines,notopandbottomlines}
+%D
+%D Although not really needed, the following shortcuts
+%D sometimes come in handy.
+%D
+%D \showsetup{noheaderandfooterlines}
+%D \showsetup{notopandbottomlines}
+
+\def\noheaderandfooterlines
+ {\setupheader[\c!state=\v!empty]%
+ \setupfooter[\c!state=\v!empty]}
+
+\def\notopandbottomlines
+ {\setuptop [\c!state=\v!empty]%
+ \setupbottom[\c!state=\v!empty]}
+
+%D \macros
+%D {setuptoptexts, setupheadertexts, setuptexttexts,
+%D setupfootertexts, setupbottomtexts}
+%D
+%D The next macros take one or more arguments. The exact setup
+%D depends on the number of arguments. Although not that
+%D intuitive, the current scheme evolved out of the original.
+%D When margin and edge texts as well as middle texts showed
+%D up, the current odd|/|even scheme surfaced.
+%D
+%D \showsetup{setuptoptexts}
+%D \showsetup{setupheadertexts}
+%D \showsetup{setuptexttexts}
+%D \showsetup{setupfootertexts}
+%D \showsetup{setupbottomtexts}
+
+\def\setuptoptexts {\dosixtupleempty\dosetuptexts[\v!top]}
+\def\setupheadertexts {\dosixtupleempty\dosetuptexts[\v!header]}
+\def\setuptexttexts {\dosixtupleempty\dosetuptexts[\v!text]}
+\def\setupfootertexts {\dosixtupleempty\dosetuptexts[\v!footer ]}
+\def\setupbottomtexts {\dosixtupleempty\dosetuptexts[\v!bottom]}
+
+%D The left, right and center variables can also be set
+%D directly using the previously discussed macros.
+
+\def\dosetuptexts[#1][#2][#3][#4][#5][#6]%
+ {\ifsixthargument
+ \setvalue{\??tk#1#2\c!lefttext}%
+ {\dodoubletexts{\??tk#1}{#2}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#3}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#6}}%
+ \setvalue{\??tk#1#2\c!righttext}%
+ {\dodoubletexts{\??tk#1}{#2}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#4}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#5}}%
+ \else\iffifthargument
+ \setvalue{\??tk#1\v!text\c!lefttext}%
+ {\dodoubletexts{\??tk#1}\v!text
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#2}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#5}}%
+ \setvalue{\??tk#1\v!text\c!righttext}%
+ {\dodoubletexts{\??tk#1}\v!text
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#3}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#4}}%
+ \else\iffourthargument
+ \setvalue{\??tk#1#2\c!lefttext}%
+ {\dodoubletexts{\??tk#1}{#2}
+ {\c!leftstyle\c!leftcolor\c!leftwidth}{#3}%
+ {\c!leftstyle\c!leftcolor\c!leftwidth}{#3}}%
+ \setvalue{\??tk#1#2\c!righttext}%
+ {\dodoubletexts{\??tk#1}{#2}
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#4}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#4}}%
+ \else\ifthirdargument
+ \setvalue{\??tk#1\v!text\c!lefttext}%
+ {\dodoubletexts{\??tk#1}\v!text
+ {\c!leftstyle\c!leftcolor\c!leftwidth}{#2}%
+ {\c!leftstyle\c!leftcolor\c!leftwidth}{#2}}%
+ \setvalue{\??tk#1\v!text\c!righttext}%
+ {\dodoubletexts{\??tk#1}\v!text
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#3}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#3}}%
+ \else\ifsecondargument % new
+ \letvalue{\??tk#1\v!text\c!lefttext }\empty
+ \letvalue{\??tk#1\v!text\c!righttext}\empty
+ \setvalue{\??tk#1\v!text\c!middletext }%
+ {\dosingletexts{\??tk#1}\v!text\c!style\c!color\c!width{#2}}%
+ \else
+ \dosixtupleempty\dosetuptexts[#1][\v!text][][][][]%
+ \dosixtupleempty\dosetuptexts[#1][\v!margin][][][][]%
+ \dosixtupleempty\dosetuptexts[#1][\v!edge ][][][][]%
+ \fi\fi\fi\fi\fi}
+
+%D Left and right texts are swapped on odd and even pages, but
+%D only when double sided typesetting is enabled.
+
+\def\dodoubletexts#1#2#3#4#5#6%
+ {\doifoddpageelse
+ {\dosingletexts{#1}{#2}#3{#4}} % #3 => provides three arguments
+ {\dosingletexts{#1}{#2}#5{#6}}} % #5 => provides three arguments
+
+%D The next macro will be cleaned up amd made less messy and
+%D dependent.
+
+\def\placetextlinestrut#1%
+ {\doifvalue{#1\c!strut}\v!yes{\setstrut\strut}}
+
+% \def\dosingletexts#1#2#3#4#5#6%
+% {\bgroup
+% \defconvertedargument\ascii{#6}%
+% \doifsomething\ascii
+% {\doattributes{#1#2}#3#4%
+% {\placetextlinestrut{#1}% here !
+% %\doifdefinedelse{\??mk\ascii\c!coupling} % brrr
+% \doifelsemarking\ascii
+% {\dolimitatetexts{#1#2#5}{\getmarking[\ascii][\v!first]}}
+% {\ConvertConstantAfter\doifelse\v!pagenumber{#6}
+% \placelocationpagenumber % pretty low level
+% {\ConvertConstantAfter\doifelse\v!date{#6}
+% {\currentdate}
+% {% #6{}{}{} -> {} needed for macros that look
+% % ahead, like \uniqueMPgraphic
+% \ignorecrlf\dolimitatetexts{#1#2#5}{#6{}{}{}}}}}}}%
+% \egroup}
+
+\def\dosingletexts#1#2#3#4#5#6%
+ {\bgroup
+ \defconvertedargument\ascii{#6}% no longer \defconvertedargument
+ \ifx\ascii\empty\else
+ \dostartattributes{#1#2}#3#4\empty
+ \placetextlinestrut{#1}% here !
+ \doifelsemarking\ascii
+ {\dolimitatetexts{#1#2#5}{\getmarking[\ascii][\v!first]}}%
+ {\ifcsname\??tk->\ascii\endcsname
+ \csname\??tk->\ascii\endcsname
+ \else
+ % #6{}{}{} -> {} needed for macros that look
+ % ahead, like \uniqueMPgraphic
+ \ignorecrlf\dolimitatetexts{#1#2#5}{#6{}{}{}}%
+ \fi}%
+ \dostopattributes
+ \fi
+ \egroup}
+
+\setvalue{\??tk->\v!pagenumber}{\placelocationpagenumber}
+\setvalue{\??tk->\v!date }{\currentdate}
+
+%D When specified, the texts are automatically limited in
+%D length.
+
+\def\dolimitatetexts#1#2%
+ {\doifelsevaluenothing{#1}{#2}{\limitatetext{#2}{\getvalue{#1}}{\unknown}}}
+
+%D The placement of text is hooked into the token lists
+%D associated to the area at hand.
+
+\appendtoks \placelayouttextline\v!top \topheight \to \toptextcontent
+\appendtoks \placelayouttextline\v!header\headerheight \to \headertextcontent
+\appendtoks \placelayouttextline\v!text \textheight \to \texttextcontent
+\appendtoks \placelayouttextline\v!footer\footerheight \to \footertextcontent
+\appendtoks \placelayouttextline\v!bottom\bottomheight \to \bottomtextcontent
+
+%D Texts can be disabled, moved up and ignored, depending in
+%D the \type {status} variable. This is handled by the next
+%D couple of macros.
+
+\def\settextlinestatus #1{\edef\textlinestatus{\csname\??tk#1\c!state\endcsname}}
+%def\resettextlinestatus#1{\letgvalue{\??tk#1\c!state}\v!normal}
+
+\def\resettextlinestatus#1% postpone
+ {\setgvalue{\??tk#1\s!reset}{\letgvalue{\??tk#1\c!state}\v!normal}}
+
+\def\placelayouttextline#1% #2
+ {\settextlinestatus{#1}%
+ \csname\string\placelayouttextline
+ \ifcsname\string\placelayouttextline\textlinestatus\endcsname
+ \textlinestatus
+ \else
+ \s!unknown
+ \fi
+ \endcsname{#1}} % {#2}
+
+\def\doifelselayouttextline#1% shown or not
+ {\doifinsetelse{\getvalue{\??tk#1\c!state}}{\v!normal,\v!start}}
+
+\def\doifelselayoutsomeline#1% present or not
+ {\edef\!!stringa{\csname\??tk#1\c!state\endcsname}%
+ \ifx\!!stringa\v!none
+ \@EA\secondoftwoarguments
+ \else\ifx\!!stringa\v!high
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi\fi}
+
+% \doplacelayouttextline does the actual placement (when a non-zero height)
+
+\newconditional\resyncaftertextline
+
+\setvalue{\string\placelayouttextline\v!normal }{\doplacelayouttextline}
+\setvalue{\string\placelayouttextline }{\doplacelayouttextline}
+
+\setvalue{\string\placelayouttextline\v!none}#1#2%
+ {}
+
+\setvalue{\string\placelayouttextline\v!high}#1#2%
+ {\global\settrue\resyncaftertextline
+ \resettextlinestatus{#1}}
+
+\setvalue{\string\placelayouttextline\v!empty}#1#2%
+ {\resettextlinestatus{#1}}
+
+\setvalue{\string\placelayouttextline\v!start}#1#2%
+ {\resettextlinestatus{#1}%
+ \doplacelayouttextline{#1}{#2}}
+
+\setvalue{\string\placelayouttextline\v!stop}#1#2%
+ {}
+
+\setvalue{\string\placelayouttextline\v!nomarking}#1#2%
+ {\bgroup
+ \resettextlinestatus{#1}%
+ \let\dogetmarking\nogetmarking
+ \doplacelayouttextline{#1}{#2}%
+ \egroup}
+
+\setvalue{\string\placelayouttextline\s!unknown}#1#2%
+ {\global\settrue\resyncaftertextline
+ \bgroup % new
+ \resettextlinestatus{#1}%
+ \getvalue{\??tk#1\textlinestatus}%
+ \getvalue{\??tk#1\v!text \textlinestatus}%
+ \getvalue{\??tk#1\v!margin\textlinestatus}%
+ \getvalue{\??tk#1\v!edge \textlinestatus}%
+ \doplacelayouttextline{#1}{#2}%
+ \egroup}
+
+%D The following macro has to be called after a page
+%D is flushed.
+
+\def\resetlayouttextline#1%
+ {\getvalue {\??tk#1\s!reset}%
+ \letgvalue{\??tk#1\s!reset}\relax}
+
+\def\resetlayouttextlines
+ {\resetlayouttextline\v!top
+ \resetlayouttextline\v!header
+ \resetlayouttextline\v!text
+ \resetlayouttextline\v!footer
+ \resetlayouttextline\v!bottom
+ \ifconditional\resyncaftertextline
+ \doglobal\calculatevsizes
+ \recalculatebackgrounds
+ \recalculatelogos
+ \global\setfalse\resyncaftertextline
+ \fi}
+
+% \settext[header][text][middle][xxx][yyy]
+
+\def\settextcontent
+ {\doquintupleempty\dosettextcontent}
+
+\def\dosettextcontent[#1][#2][#3][#4][#5]% header text middle text/text
+ {\iffifthargument
+ \setvalue{\??tk#1#2\executeifdefined{:\c!text:#3:}\c!middletext}%
+ {\dodoubletexts{\??tk#1}{#2}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#4}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#5}}%
+ \else\iffourthargument
+ \setvalue{\??tk#1#2\executeifdefined{:\c!text:#3:}\c!middletext}%
+ {\dodoubletexts{\??tk#1}{#2}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#4}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#4}}%
+ \else\ifthirdargument
+ \setvalue{\??tk#1#2\c!middletext}%
+ {\dodoubletexts{\??tk#1}{#2}%
+ {\c!leftstyle \c!leftcolor \c!leftwidth }{#3}%
+ {\c!rightstyle\c!rightcolor\c!rightwidth}{#3}}%
+ \fi\fi\fi}
+
+\def\resettextcontent
+ {\dotripleempty\doresettextcontent}
+
+\def\doresettextcontent[#1][#2][#3]% header text middle
+ {\ifthirdargument
+ \letvalue{\??tk#1#2\executeifdefined{:\c!text:#3:}\c!middletext}\empty
+ \else\ifsecondargument
+ \letvalue{\??tk#1#2\c!lefttext }\empty
+ \letvalue{\??tk#1#2\c!middletext}\empty
+ \letvalue{\??tk#1#2\c!righttext }\empty
+ \fi\fi}
+
+\let\settext \settextcontent % downward compatibility
+\let\resettext\resettextcontent % downward compatibility
+
+\setvalue{:\c!middle:\c!text:}{\c!middletext}
+\setvalue{:\c!left :\c!text:}{\c!lefttext }
+\setvalue{:\c!right :\c!text:}{\c!righttext }
+
+%D The next series of macros is not that easy to read,
+%D because they hook into the main page building macros. By
+%D using token list registers for the text content, we can
+%D easily hook in other code, like menu generators.
+%D
+%D Beware: the token lists are always expanded, also when the
+%D height of an area is zero. This is because reset actions can
+%D be part of them.
+
+\newbox\scratchpagebox
+
+\def\gettextboxes
+ {\setbox\scratchpagebox\vbox
+ {\dontcomplain
+ \calculatereducedvsizes
+ \swapmargins
+ \offinterlineskip
+ \vskip\dimexpr-\topheight-\topdistance\relax
+ \the\toptextcontent
+ \vskip\dimexpr\topheight+\topdistance\relax
+ \the\headertextcontent
+ \vskip\dimexpr\headerheight+\headerdistance\relax
+ \placepositionanchors
+ \vskip-\textheight
+ \the\texttextcontent
+ \vskip\textheight
+ \the\everyendoftextbody
+ \vskip\footerdistance
+ \the\footertextcontent
+ \vskip\dimexpr\footerheight+\bottomdistance\relax
+ \the\bottomtextcontent
+ \vskip\bottomheight
+ \vfilll}%
+ \smashbox\scratchpagebox
+ \box\scratchpagebox}
+
+\def\getmainbox#1#2%
+ {\setbox\scratchpagebox\vbox
+ {\offinterlineskip % na \paginaletter !
+ \calculatereducedvsizes
+ \calculatehsizes
+ \swapmargins
+ \vskip\dimexpr\headerheight+\headerdistance+\layoutparameter\c!textdistance\relax
+ \hbox to \makeupwidth
+ {\bgroup
+ \swapmargins
+ \goleftonpage
+ \ifdim\leftedgewidth>\zeropoint
+ \the\leftedgetextcontent
+ \hskip\leftedgewidth
+ \fi
+ \hskip\leftedgedistance
+ \ifdim\leftmarginwidth>\zeropoint
+ \the\leftmargintextcontent
+ \hskip\leftmarginwidth
+ \fi
+ \hskip\leftmargindistance
+ \egroup
+ \mkprocesspagecontents{#2}%
+ \settextpagecontent\scratchpagebox{#1}{#2}%
+ \setbox\scratchpagebox\vbox % can we avoid this extra box
+ {\startlayoutcomponent{textbody}{text body}%
+ \box\scratchpagebox
+ \stoplayoutcomponent}%
+ \addtextbackground\scratchpagebox
+ \addtextgridlayer\scratchpagebox
+ \localstarttextcolor % does not work in mkiv
+ \box\scratchpagebox
+ \localstoptextcolor % so we have to change this
+ \bgroup
+ \hskip\rightmargindistance
+ \ifdim\rightmarginwidth>\zeropoint
+ \the\rightmargintextcontent
+ \hskip\rightmarginwidth
+ \fi
+ \hskip\rightedgedistance
+ \ifdim\rightedgewidth>\zeropoint
+ \the\rightedgetextcontent
+ \hskip\rightedgewidth
+ \fi
+ \egroup
+ \hss}}%
+ \smashbox\scratchpagebox
+ \box\scratchpagebox}
+
+%D The main text area has to be combined with some additional
+%D (tracing) information.
+
+% will be overloaded in page-lyr
+
+\def\settextpagecontent#1#2#3% #2 and #3 will disappear
+ {\setbox#1\hbox to \makeupwidth
+ {\hss % so don't change this
+ \vbox to \textheight
+ {\offinterlineskip
+ \freezetextwidth
+ \hsize\textwidth % local variant of \sethsize
+ \boxmaxdepth\maxdepth
+ \noindent % content can be < \hsize
+ \dopagecontents#2#3}%
+ \hss}%
+ \dp#1\zeropoint}
+
+\definepalet
+ [layout]
+ [grid=red,
+ page=green]
+
+\def\addtextgridlayer#1% tzt run time
+ {\ifcase\showgridstate\else % 1=bottom 2=top
+ \setgridbox\scratchbox\makeupwidth\textheight
+ \setbox#1\hbox
+ {\ifcase\showgridstate\or\or\box#1\hskip-\makeupwidth\fi
+ \bgroup % color
+ \startlayoutcomponent{gridcolumns}{grid columns}%
+ \incolortrue
+ \ifcase\layoutcolumns\else
+ \gray
+ \hbox to \makeupwidth
+ {\dorecurse\layoutcolumns
+ {\hskip\layoutcolumnwidth
+ \ifnum\recurselevel<\layoutcolumns
+ \vrule
+ \!!height\ht\scratchbox
+ \!!depth\dp\scratchbox
+ \!!width\layoutcolumndistance
+ \fi}}%
+ \hskip-\makeupwidth
+ \fi
+ \stoplayoutcomponent
+ \startlayoutcomponent{gridlines}{grid lines}%
+ \startcolor[layout:grid]\box\scratchbox\stopcolor
+ \stoplayoutcomponent
+ \egroup
+ \ifcase\showgridstate\or\hskip-\makeupwidth\box#1\fi}%
+ \fi}
+
+%D The placement of a whole line is handled by the next two
+%D macros. These are hooked into the general purpose token
+%D list registers mentioned before.
+
+\def\ignoredlinebreak{\unskip\space\ignorespaces}
+
+\def\doplacelayouttextline#1#2%
+ {\ifdim#2>\zeropoint\relax % prevents pagenumbers when zero height
+ \goleftonpage
+ \hbox
+ {\setbox\scratchpagebox\vbox to #2
+ {%\forgetall
+ \vsize#2\relax
+ \normalbaselines
+ \let\\\ignoredlinebreak
+ \let\crlf\ignoredlinebreak
+ %\getvalue{\??tk#1\v!text\c!before}%
+ \getvalue{\??tk#1\c!before}%
+ \doifbothsidesoverruled
+ {\dodoplacelayouttextline#1\c!lefttext \c!middletext\c!righttext\gobbleoneargument\getvalue}
+ {\dodoplacelayouttextline#1\c!lefttext \c!middletext\c!righttext\gobbleoneargument\getvalue}
+ {\dodoplacelayouttextline#1\c!righttext\c!middletext\c!lefttext \getvalue\gobbleoneargument}%
+ %\getvalue{\??tk#1\v!text\c!after}%
+ \getvalue{\??tk#1\c!after}%
+ \kern\zeropoint}% keep the \dp, beware of \vtops, never change this!
+ \dp\scratchpagebox\zeropoint
+ \box\scratchpagebox}%
+ \vskip-#2\relax
+ \fi}
+
+\def\dodoplacelayouttextline#1#2#3#4#5#6% \hsize toegevoegd, \hss's niet meer wijzigen
+ {\hbox
+ {\ifdim\leftedgewidth>\zeropoint
+ \dododoplacelayouttextline\leftedgewidth{#1}\v!edge
+ {\hss\getvalue{\??tk#1\v!edge#2}}%
+ \hskip\leftedgedistance
+ \fi
+ \ifdim\leftmarginwidth>\zeropoint
+ \dododoplacelayouttextline\leftmarginwidth{#1}\v!margin
+ {\hbox to \leftmarginwidth
+ {\hss\getvalue{\??tk#1\v!margin#2}}%
+ \hskip-\leftmarginwidth
+ \hbox to \leftmarginwidth
+ {\hss#5{\??tk#1\v!margin\c!margintext}}}%
+ \hskip\leftmargindistance
+ \fi
+ \ifdim\makeupwidth>\zeropoint
+ \dododoplacelayouttextline\makeupwidth{#1}\v!text
+ {\hbox to \makeupwidth
+ {\@@nmpre{#5{\??tk#1\v!text\c!marginedgetext}}%
+ \getvalue{\??tk#1\v!text#2}\hss}%
+ \hskip-\makeupwidth
+ \hbox to \makeupwidth
+ {\hss\getvalue{\??tk#1\v!text#3}\hss}%
+ \hskip-\makeupwidth
+ \hbox to \makeupwidth
+ {\hss\getvalue{\??tk#1\v!text#4}%
+ \@@nmpos{#6{\??tk#1\v!text\c!marginedgetext}}}}%
+ \fi
+ \ifdim\rightmarginwidth>\zeropoint
+ \hskip\rightmargindistance
+ \dododoplacelayouttextline\rightmarginwidth{#1}\v!margin
+ {\hbox to \rightmarginwidth
+ {\getvalue{\??tk#1\v!margin#4}\hss}%
+ \hskip-\rightmarginwidth
+ \hbox to \rightmarginwidth
+ {#6{\??tk#1\v!margin\c!margintext}\hss}}%
+ \fi
+ \ifdim\rightedgewidth>\zeropoint
+ \hskip\rightedgedistance
+ \dododoplacelayouttextline\rightedgewidth{#1}\v!edge
+ {\getvalue{\??tk#1\v!edge#4}\hss}%
+ \fi}}
+
+% \def\dododoplacelayouttextline#1#2#3#4%
+% {\vbox % to \vsize
+% {\hsize#1\relax
+% \getvalue{\??tk#2#3\c!voor}
+% \hbox to #1{#4}%
+% \getvalue{\??tk#2#3\c!na}}}
+
+\def\dododoplacelayouttextline#1#2#3#4%
+ {\vbox % to \vsize
+ {\hsize#1\relax
+ \getvalue{\??tk#2#3\c!before}%
+ \startlayoutcomponent{t:#2:#3}{area #2 #3}%
+ \hbox to #1{#4}%
+ \stoplayoutcomponent
+ \getvalue{\??tk#2#3\c!after}}}
+
+%D Although it is far better to use backgrounds for this
+%D purpose, one can add a rule in the following way. This
+%D method makes the rules disappear in case of an empty text
+%D line. Consider this a feature.
+%D
+%D \starttyping
+%D \setupheadertexts[left][right]
+%D
+%D \setupheader[text][after=\hrule,style=bold]
+%D
+%D \starttext
+%D \input tufte \page
+%D \setupheader[state=empty]
+%D \input tufte \page
+%D \stoptext
+%D \stoptyping
+
+%D The next twosome will be done differently (using an
+%D existing auxiliary macro).
+
+% \def\@@nmpre#1{\setbox0\hbox{#1}\ifdim\wd0=\zeropoint\else\unhbox0\tfskip\fi}
+% \def\@@nmpos#1{\setbox0\hbox{#1}\ifdim\wd0=\zeropoint\else\tfskip\unhbox0\fi}
+
+% cleaner
+
+\def\@@nmpre#1{\doiftext{#1}{{#1}\tfskip}}
+\def\@@nmpos#1{\doiftext{#1}{\tfskip{#1}}}
+
+% newer
+
+\def\@@nmprepos#1#2#3#4#5%
+ {\doifelsenothing\@@nmwidth
+ {\doiftext{#5}{#1{#5}#2}}
+ {\doiftext{#5}{\hbox to \@@nmwidth{#3{#5}#4}}}}
+
+\def\@@nmpre{\@@nmprepos\empty\tfskip\relax\hss}
+\def\@@nmpos{\@@nmprepos\tfskip\empty\hss\relax}
+
+%D This code will move to \type {page-flt.tex}.
+
+\appendtoks
+ \plaatsrechtermargeblok \hskip-\rightmarginwidth
+\to \rightmargintextcontent
+
+\appendtoks
+ \plaatslinkermargeblok \hskip-\leftmarginwidth
+\to \leftmargintextcontent
+
+%D The next hook will later be used for keeping track of
+%D positions, i.e.\ it will provide a proper (page
+%D dependent) reference point.
+
+\ifx\undefined\placepositionanchors
+ \def\placepositionanchors{\vskip\textheight}
+\fi
+
+%D \macros
+%D {definetext}
+%D
+%D Some macros ago, we implemented the \type {status} option
+%D \type {unknown}. This one is used to take care of
+%D symbolic texts handlers.
+%D
+%D \showsetup{definetext}
+%D
+%D The next example demonstrates how we can use this
+%D mechanism to provide page (event) dependent text lines.
+%D
+%D \starttyping
+%D \definetext[chapter][footer][pagenumber]
+%D \setuphead[chapter][header=high,footer=chapter]
+%D \setupheadertexts[pagenumber]
+%D \setupfootertexts[left][right]
+%D \chapter{eerste} \dorecurse{20}{\input tufte \relax}
+%D \chapter{tweede} \dorecurse{20}{\input tufte \relax}
+%D \stoptyping
+
+\def\definetext
+ {\doseventupleempty\dodefinetext}
+
+\def\dodefinetext[#1][#2][#3][#4][#5][#6][#7]%
+ {\ifseventhargument
+ \setvalue{\??tk#2#3#1}{\dosixtupleempty\dosetuptexts[#2][#3][#4][#5][#6][#7]}%
+ \else\ifsixthargument
+ \setvalue{\??tk #2#1}{\dosixtupleempty\dosetuptexts[#2][#3][#4][#5][#6]}%
+ \else\iffifthargument
+ \setvalue{\??tk#2#3#1}{\dosixtupleempty\dosetuptexts[#2][#3][#4][#5]}%
+ \else\iffourthargument
+ \setvalue{\??tk #2#1}{\dosixtupleempty\dosetuptexts[#2][#3][#4]}%
+ \else
+ \setvalue{\??tk #2#1}{\dosixtupleempty\dosetuptexts[#2][#3]}%
+ \fi\fi\fi\fi}
+
+%D The rest of this file is dedicated to setting up the
+%D texts. This code is not that impressive.
+
+\setupheadertexts [\v!text] [] []
+\setupheadertexts [\v!margin] [] []
+\setupheadertexts [\v!edge] [] []
+
+\setupfootertexts [\v!text] [] []
+\setupfootertexts [\v!margin] [] []
+\setupfootertexts [\v!edge] [] []
+
+\setuptexttexts [\v!text] [] []
+\setuptexttexts [\v!margin] [] []
+\setuptexttexts [\v!edge] [] []
+
+\setupbottomtexts [\v!text] [] []
+\setupbottomtexts [\v!margin] [] []
+\setupbottomtexts [\v!edge] [] []
+
+\setuptoptexts [\v!text] [] []
+\setuptoptexts [\v!margin] [] []
+\setuptoptexts [\v!edge] [] []
+
+% alternative
+%
+% \def\resetlayouttekst%
+% {\dodoubleempty\doresetlayouttekst}
+%
+% \def\doresetlayouttekst[#1][#2]%
+% {\ifsecondargument
+% \dodoresetlayouttekst[#1][#2]%
+% \else
+% \dodoresetlayouttekst[#1][\v!tekst]%
+% \fi}
+%
+% \def\dodoresetlayouttekst[#1][#2]%
+% {...}
+%
+% \def\docommand#1%
+% {\resetlayouttekst[#1][\v!tekst]%
+% \resetlayouttekst[#1][\v!marge]%
+% \resetlayouttekst[#1][\v!rand]}
+
+%D We combine a lot of similar settings in a macro that
+%D we will later dispose.
+
+\def\dodocommand[#1][#2]%
+ {\getparameters
+ [\??tk#1#2]
+ [%\c!state=\v!normal, % moved
+ \c!before=, % both global and local are used
+ \c!after=, % both global and local are used
+ \c!strut=, % the local one, not (yet) used
+ \c!style=\getvalue{\??tk#1\c!style},% hm, got lost
+ \c!color=\getvalue{\??tk#1\c!color}, % hm, got lost
+ \c!lefttext=,
+ \c!middletext=,
+ \c!righttext=,
+ \c!marginedgetext=,
+ \c!margintext=,
+ \c!width=]%
+ \inheritparameter[\??tk#1#2][\c!leftstyle ][\c!style ]%
+ \inheritparameter[\??tk#1#2][\c!rightstyle ][\c!style ]%
+ \inheritparameter[\??tk#1#2][\c!leftcolor ][\c!color ]%
+ \inheritparameter[\??tk#1#2][\c!rightcolor ][\c!color ]%
+ \inheritparameter[\??tk#1#2][\c!leftwidth ][\c!width]%
+ \inheritparameter[\??tk#1#2][\c!rightwidth][\c!width]}
+
+\def\docommand#1%
+ {\dodocommand[#1][\v!text]%
+ \dodocommand[#1][\v!margin]%
+ \dodocommand[#1][\v!edge]}
+
+\docommand\v!top
+\docommand\v!header
+\docommand\v!footer
+\docommand\v!text
+\docommand\v!bottom
+
+\let\docommand \relax
+\let\dodocommand\relax
+
+%D While the header and footer lines are moved away from the
+%D main text, the top and bottom lines are centered.
+
+\setuptop [\c!state=\v!normal,\c!before=\vss,\c!after=\vss,\c!strut=]
+\setupheader[\c!state=\v!normal,\c!before=, \c!after=\vss,\c!strut=\v!yes]
+\setuptext [\c!state=\v!normal,\c!before=\vss,\c!after=\vss,\c!strut=]
+\setupfooter[\c!state=\v!normal,\c!before=\vss,\c!after=, \c!strut=\v!yes]
+\setupbottom[\c!state=\v!normal,\c!before=\vss,\c!after=\vss,\c!strut=]
+
+\setuptop [\c!style=,\c!color=]
+\setupheader[\c!style=,\c!color=]
+\setuptext [\c!style=,\c!color=]
+\setupfooter[\c!style=,\c!color=]
+\setupbottom[\c!style=,\c!color=]
+
+\protect \endinput
diff --git a/tex/context/base/ppchtex.tex b/tex/context/base/ppchtex.mkii
index a7800acd4..285b0004e 100644
--- a/tex/context/base/ppchtex.tex
+++ b/tex/context/base/ppchtex.mkii
@@ -56,7 +56,7 @@
% getoont. Buiten Context genereren we een melding:
\doifundefined{usemodule}
- {\writestatus{loading}{Context Chemical Macro's / 1996.3.1}}
+ {\writestatus{loading}{ConTeXt Chemical Macro's / 1996.3.1}}
% Er kan gebruik worden gemaakt van PiCTeX of PStricks. Een
% van deze pakketten moet van te voren zijn geladen.
@@ -337,6 +337,13 @@
\endlatexmathmodehack
\fi}
+\ifx\Umathchar\undefined \else
+ % for the moment we nil them, soon we will have a proper
+ % way to deal with this
+ \let\setsubscripts \relax
+ \let\resetsubscripts\relax
+\fi
+
\def\doresetsubscripts
{\resetsubscripts}
@@ -404,7 +411,7 @@
\def\doifchemicalnumber#1#2#3%
{\doifnumberelse{#1}
- {\ifnum#1>\maxchemical
+ {\ifnum#1>\maxchemical\relax
\writestatus{ppchtex}{number #1 is skipped}%
\else
#3%
@@ -1161,14 +1168,15 @@
{\def\@@chemicalframe{\chemicalframe}}
{\def\@@chemicalframe{}}%
\dosetsubscripts
- \setbox2=\hbox{$\@@dochemicalstyle{\@@localchemicalformat \chemicaltext}$}%
+ \setbox2=\hbox{\@@dochemicalcolor
+ $\@@dochemicalstyle{\@@localchemicalformat \chemicaltext}$}%
\setbox4=\hbox{$\@@dochemicalstyle{\@@localchemicalformat C_2^2}$}%
\setbox6=\hbox{$\@@dochemicalstyle{\@@localchemicalformat O}$}% or C
\doresetsubscripts
\doifnot\@@chemicallocation\v!intext
{\ht2=\ht4
\dp2=\dp4}%
- \setbox2=\hbox{\@@chemicalframe{\@@dochemicalcolor\box2}}%
+ \setbox2=\hbox{\@@chemicalframe{\box2}}%
\ifdim\wd2>\wd6
\doifelse{#1}{0}
{\doifnot{#2}{0}{\wd2=\wd6}}
@@ -3374,24 +3382,35 @@ RT##3##4##5=>\processchemicaltextelement{RN}{##3##4##5}{#1}{0}{},
%D \item position tracking
%D \stopitemize
-
\ifCONTEXT \else \protect \endinput \fi
+\let\@@chemicalrulecolor\empty
+\let\@@chemicalcolor \empty
+
+% \def\setchemicalattributes
+% {\scratchdimen\@@chemicalchemicalrulethickness
+% \def\chemicalattributes
+% {withpen pencircle scaled \the\scratchdimen\space
+% withcolor }%
+% \doifelsenothing\@@chemicalchemicalrulecolor
+% {\edef\chemicalattributes{\chemicalattributes black}}
+% {\edef\chemicalattributes{\chemicalattributes \MPcolor{\@@chemicalchemicalrulecolor}}}%
+% \startMPdrawing
+% drawoptions (\chemicalattributes) ;
+% \stopMPdrawing}
+
\def\setchemicalattributes
- {\scratchdimen\@@chemicalchemicalrulethickness
+ {\scratchdimen\@@chemicalrulethickness
\def\chemicalattributes
{withpen pencircle scaled \the\scratchdimen\space
withcolor }%
- \doifelsenothing\@@chemicalchemicalrulecolor
+ \doifelsenothing\@@chemicalrulecolor
{\edef\chemicalattributes{\chemicalattributes black}}
- {\edef\chemicalattributes
- {\chemicalattributes \MPcolor{\@@chemicalchemicalrulecolor}}}%
+ {\edef\chemicalattributes{\chemicalattributes \MPcolor{\@@chemicalrulecolor}}}%
\startMPdrawing
drawoptions (\chemicalattributes) ;
\stopMPdrawing}
-\let\@@chemicalcolor\empty
-
\def\@@dochemicalcolor
{\doifsomething\@@chemicalcolor{\color[\@@chemicalcolor]}}
diff --git a/tex/context/base/ppchtex.mkiv b/tex/context/base/ppchtex.mkiv
new file mode 100644
index 000000000..fb9e610e9
--- /dev/null
+++ b/tex/context/base/ppchtex.mkiv
@@ -0,0 +1,3359 @@
+%D \module
+%D [ file=ppchtex (m-chemie),
+%D version=1997.03.19,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=\PPCHTEX\ (Plain Pictex Context cHemie \TEX),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten},
+%D suggestions={Tobias Burnus, Dirk Kuypers \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% option=test => boxes
+% dummy => file
+% final => file / local run
+%
+% constante van phantom in definitie ONE: \setchemicaltextwidth 300
+%
+% it would be interesting to rewrite this module with todays
+% experiences and new context functionality, maybe ...
+
+% Deze module ondersteunt het zetten van chemische
+% (structuur)formules. Hoewel de macro' zijn afgestemd op
+% CONTEXT, zijn ze ook buiten deze zetomgeving te gebruiken.
+%
+% Dit is, afgezien van updates, de definitieve versie van
+% PPCHTEX. Gebruikersgemak, eenvoud, flexibiliteit, en
+% snelheid zijn inmiddels redelijk geoptimaliseerd. Dit neemt
+% niet weg dat hier en daar nog verbetering mogelijk is. Dit
+% zal dan ook nog gebeuren.
+%
+% Volgende versies zullen tenminste dezelfde functionaliteit
+% hebben. We houden ons natuurlijk het recht voor de kwaliteit
+% van de output te verbeteren. Daarnaast staan nog op het
+% wensenlijstje:
+%
+% - optimaliseren in termen van proces-tijd
+% - aanpassen naamgeving van interne macro's
+% - toevoegen van functionaliteit
+% - in \x!-vorm omzetten van GIVES, TB enz.
+%
+% De mix tussen engels en nederlands lijkt soms verwarrend.
+% Meestal zijn verborgen macro's engels en zichtbare macro's
+% nederlands. Het gebruik van [ ] en { } sluit aan op andere
+% Context-macro's. Hetzelfde geldt voor instellingen en
+% \start-\stop-constructies.
+%
+% De schijnbaar overbodige \bgroup-\egroup constructie
+% garandeert aansluiting bij de Context-macro's voor het
+% plaatsen van figuren, tabellen en andere floats.
+%
+% Binnen Context worden de macro's geladen met
+% \gebruikextras[chemie]. Daarbij wordt een passende melding
+% getoont. Buiten Context genereren we een melding:
+
+\doifundefined{usemodule}
+ {\writestatus{loading}{ConTeXt Chemical Macro's / 1996.3.1}}
+
+% Er kan gebruik worden gemaakt van PiCTeX of PStricks. Een
+% van deze pakketten moet van te voren zijn geladen.
+%
+% \input prepictex.tex (i.g.v. LaTeX)
+% \input pictex.tex
+% \input postpictex.tex (i.g.v. LaTeX)
+%
+% of:
+%
+% \input multido.tex
+% \input pstricks.tex
+% \input pst-plot.tex
+%
+% In \CONTEXT\ kan men de modules m-pictex en m-pstricks
+% gebruiken. De eerste module laad of efficiente wijze PiCTeX
+% en de tweede module koppelt het PSTRICKS kleurmechanisme
+% aan dat van \CONTEXT.
+%
+
+% PSTricks: {-\chemicalangle} instead of {*0}, which produces
+% faulty ps code when \chemicalangle=0
+
+\startcommands dutch english german
+
+ gotochemical: naarchemie gotochemical zurchemie
+ setupchemical: stelchemiein setupchemical stellechemieein
+ startchemical: startchemie startchemical startchemie
+ stopchemical: stopchemie stopchemical stopchemie
+ definechemical: definieerchemie definechemical definierechemie
+ chemical: chemie chemical chemie
+ toptext: boventekst toptext textueber
+ bottext: ondertekst bottext textunter
+ midtext: middentekst midtext textmitte
+
+\stopcommands
+
+\doifundefined{fiverm} % In the more recent LaTeX versions
+ {\font\fiverm=cmr5 } % \fiverm is no longer (pre)defined.
+
+\doifdefinedelse{beginpicture} % PiCTeX
+ {\doifdefinedelse{startMPdrawing}
+ {\chardef\chemicaldrawingmode=2 } % MetaPost
+ {\chardef\chemicaldrawingmode=0 }} % raw
+ {\doifdefinedelse{psaxes}
+ {\chardef\chemicaldrawingmode=1 } % PSTricks
+ {\chardef\chemicaldrawingmode=3 }} % unknown
+
+\ifcase\chemicaldrawingmode
+ \writestatus{ppchtex}{using PiCTeX}
+\or
+ \writestatus{ppchtex}{using PSTricks (still experimental)}
+ \writestatus{ppchtex}{automatic sizing not (yet) supported}
+\or
+ \writestatus{ppchtex}{using PiCTeX and MetaPost}
+\else
+ \writestatus{ppchtex}{load PiCTeX (+pre/post) or PSTricks (+pst_plot) first}
+ \bgroup
+ \read16 to \exit
+ \egroup
+ \expandafter\endinput
+\fi
+
+%I n=Chemie
+%I c=\stelchemiein,\chemie
+%I
+%I Chemische formules kunnen worden gezet met behulp van de
+%I onderstaande commando's:
+%I
+%I buiten $ en $$ :
+%I
+%I \chemie[segmenten][symbolen]
+%I
+%I \startchemie[instellingen]
+%I \chemie...
+%I \chemie...
+%I \stopchemie
+%I
+%I en binnen $ en $$:
+%I
+%I \chemie{}{}
+%I
+%I Voor tekst, uitleg en voorbeelde verwijzen we vooralsnog
+%I naar de handleiding.
+%P
+%I Het gedrag van de macro's kan worden ingesteld met:
+%I
+%I \stelchemiein[breedte=,hoogte=,links=,rechts=,boven=,
+%I onder=,korps=,schaal=,status=,assenstelsel=,kader=,
+%I variant=,optie=,formaat=,tekstformaat=,resolutie=,
+%I offset=,letter=]
+%I
+%I Structuren kunnen worden voorgedefinieerd met het commando
+%I
+%I \definieerchemie[naam]{\chemie...}
+
+%S \startsetup
+%S \command
+%S [\!stelchemiein]
+%S \type
+%S [\c!vars!]
+%S \variable
+%S [\c!breedte]
+%S [\c!number!,\v!passend]
+%S [0]
+%S \variable
+%S [\c!hoogte]
+%S [\c!number!,\v!passend]
+%S [0]
+%S \variable
+%S [\c!links]
+%S [\c!number!]
+%S [0]
+%S \variable
+%S [\c!rechts]
+%S [\c!number!]
+%S [0]
+%S \variable
+%S [\c!boven]
+%S [\c!number!]
+%S [0]
+%S \variable
+%S [\c!onder]
+%S [\c!number!]
+%S [0]
+%S \variable
+%S [\c!resolutie]
+%S [\c!number!]
+%S [\outputresolution]
+%S \variable
+%S [\c!korps]
+%S [10pt,11pt,12pt]
+%S [\bodyfontsize]
+%S \variable
+%S [\c!schaal]
+%S [\v!klein,\v!middel,\v!groot]
+%S [\v!middel]
+%S \variable
+%S [\c!formaat]
+%S [\v!klein,\v!middel,\v!groot]
+%S [\v!groot]
+%S \variable
+%S [\c!tekstformaat]
+%S [\v!klein,\v!middel,\v!groot]
+%S [\v!groot]
+%S \variable
+%S [\c!status]
+%S [\v!start,\v!stop]
+%S [\v!start]
+%S \variable
+%S [\c!kader]
+%S [\v!aan,\v!uit]
+%S [\v!uit]
+%S \variable
+%S [\c!assenstelsel]
+%S [\v!aan,\v!uit]
+%S [\v!uit]
+%S \variable
+%S [\c!optie]
+%S [\v!test]
+%S []
+%S \variable
+%S [\c!variant]
+%S [1,2]
+%S [1]
+%S \variable
+%S [\c!offset]
+%S [HIGH,LOW]
+%S [LOW]
+%S \variable
+%S [\c!letter]
+%S [\c!command!]
+%S [\rm]
+%S \stopsetup
+
+%S \startsetup
+%S \command
+%S [\v!startchemie]
+%S \type
+%S [\c!vars!\c!stp!]
+%S \inheritvariable
+%S [\v!stelchemiein]
+%S []
+%S \stopsetup
+
+%S \startsetup
+%S \command
+%S [\v!chemie]
+%S \type
+%S [\c!vals!\c!vals!]
+%S \value
+%S [\c!list!]
+%S []
+%S \value
+%S [\c!list!]
+%S []
+%S \stopsetup
+
+%S \startsetup
+%S \command
+%S [definieerchemie]
+%S \type
+%S [\c!val!\c!arg!]
+%S \value
+%S [\c!text!]
+%S []
+%S \stopsetup
+
+\unprotect
+
+% Om te voorkomen dat sub- en superscripts botsen passen we
+% wat fontdimen's aan (Knuth, The TeXBook, p179). Helaas
+% kunnen deze instellingen niet lokaal worden gehouden door
+% groeperen, vandaar dat een en ander moet worden geset n
+% gereset.
+%
+% Er dient een relatie te worden gelegd met de afmetingen
+% van de letters. In een eerdere versie werden daartoe de
+% \fontdimen's opgehoogd. Omdat dit problemen gaf bij
+% scaled fonts, is bij nader inzien gekozen voor de
+% onderstaande oplossing, waarbij de nieuwe waarden worden
+% afgeleid van de x-height (\fontexheight). De factor 0.70
+% is min of meer experimenteel vastgesteld. Soms worden de
+% regels iets verder uit elkaar gezet. Jammer. Italic fonts
+% hebben grotere cijfers en vallen min of meer uit de boot.
+
+\newif\ifloweredsubscripts
+
+% Due to some upward incompatibality of LaTeX to LaTeX2.09
+% and/or LaTeX2e we had to force \@@dochemicalstyle. Otherwise
+% some weird \nullfont error comes up.
+
+\def\beginlatexmathmodehack
+ {\ifmmode
+ \let\endlatexmathmodehack=\relax
+ \else
+ \def\endlatexmathmodehack{$}$\@@dochemicalstyle\empty
+ \fi}
+
+\def\setsubscripts%
+ {\beginlatexmathmodehack
+ \def\dosetsubscript##1##2##3%
+ {\dimen0=##3\fontexheight##2%
+ \setxvalue{@@\string##1\string##2}{\the##1##2\relax}%
+ ##1##2=\dimen0\relax}%
+ \def\dodosetsubscript##1##2%
+ {\dosetsubscript{##1}{\textfont 2}{##2}%
+ \dosetsubscript{##1}{\scriptfont 2}{##2}%
+ \dosetsubscript{##1}{\scriptscriptfont2}{##2}}%
+ %dodosetsubscript\mathsupnormal {?}%
+ \dodosetsubscript\mathsubnormal {.7}%
+ \dodosetsubscript\mathsubcombined{.7}%
+ \global\loweredsubscriptstrue
+ \endlatexmathmodehack}
+
+\def\resetsubscripts
+ {\ifloweredsubscripts
+ \beginlatexmathmodehack
+ \def\doresetsubscript##1##2%
+ {\dimen0=\getvalue{@@\string##1\string##2}\relax
+ ##1##2=\dimen0}%
+ \def\dodoresetsubscript##1%
+ {\doresetsubscript{##1}{\textfont2}%
+ \doresetsubscript{##1}{\scriptfont2}%
+ \doresetsubscript{##1}{\scriptscriptfont2}}%
+ %dodoresetsubscript\mathsupnormal
+ \dodoresetsubscript\mathsubnormal
+ \dodoresetsubscript\mathsubcombined
+ \global\loweredsubscriptsfalse
+ \endlatexmathmodehack
+ \fi}
+
+\ifx\Umathchar\undefined \else
+ % for the moment we nil them, soon we will have a proper
+ % way to deal with this
+ \let\setsubscripts \relax
+ \let\resetsubscripts\relax
+\fi
+
+\def\doresetsubscripts
+ {\resetsubscripts}
+
+\def\sethighsubscripts
+ {\resetsubscripts
+ \let\dosetsubscripts=\relax}
+
+\def\setlowsubscripts
+ {\def\dosetsubscripts{\setsubscripts}}
+
+\setlowsubscripts
+
+\newcount\horchemical % t.z.t. \newcounter
+\newcount\verchemical % t.z.t. \newcounter
+\newcount\txtchemical % t.z.t. \newcounter
+\newcount\levchemical % t.z.t. \newcounter
+
+\newif\ifinchemical \inchemicalfalse
+\newif\iffixedchemical \fixedchemicalfalse
+
+\newbox\chemicalsymbols
+
+% Eigenlijk moeten de constanten en variabelen in cont-nl.tex
+% staan. Dit pakket is echter relatief onafhankelijk van CONTEXT.
+
+\definesystemvariable {chemical}
+
+\definesystemconstant {chemical}
+
+\definesystemconstant {translate}
+\definesystemconstant {distance}
+\definesystemconstant {mirror}
+\definesystemconstant {rotate}
+\definesystemconstant {substitute}
+\definesystemconstant {angle}
+
+\definesystemconstant {executechemical}
+\definesystemconstant {chemicaltextelement}
+\definesystemconstant {chemicallinesegment}
+\definesystemconstant {chemicalcircsegment}
+
+\def\chemicalspace {\quad}
+
+% begin van experiment:
+%
+% De onderstaande twee macro's kunnen worden gebruikt voor
+% bijvoorbeeld een interactiemechanisme.
+%
+% \localgotochemical {verwijzing} {tekst}
+% \localthisischemical {verwijzing}
+
+\def\dowithchemical%
+ {}
+
+\doifdefinedelse{@@iastate}
+ {\def\localgotochemical#1#2{\naarbox{#2}[#1]}%
+ \def\localthisischemical#1{\pagereference[#1]}}
+ {\def\localgotochemical#1{}%
+ \def\localthisischemical#1{}}
+
+% eind van experiment
+
+\def\setchemicalmaximum #1
+ {\def\maxchemical{#1}}
+
+\def\doifchemicalnumber#1#2#3%
+ {\doifnumberelse{#1}
+ {\ifnum#1>\maxchemical\relax
+ \writestatus{ppchtex}{number #1 is skipped}%
+ \else
+ #3%
+ \fi}
+ {\unknownchemical{#2}}}%
+
+\newif\ifsmallchemicaltext
+
+\let\@@localchemicalstyle\empty
+
+\def\setupchemicalformat[#1]%
+ {\processaction
+ [\getvalue{#1\c!size}]
+ [ \v!small=>\def\@@localchemicalformat{\scriptscriptstyle},
+ \v!medium=>\def\@@localchemicalformat{\ifsmallchemicaltext\scriptscriptstyle\else\scriptstyle\fi},
+ \v!big=>\def\@@localchemicalformat{\ifsmallchemicaltext\scriptstyle\else\textstyle\fi},
+ \s!unknown=>\def\@@localchemicalformat{\getvalue{#1\c!size}}]%
+ \processaction
+ [\getvalue{#1\c!textsize}]
+ [ \v!small=>\def\@@localchemicalstyle{\scriptscriptstyle},
+ \v!medium=>\def\@@localchemicalstyle{\ifsmallchemicaltext\scriptscriptstyle\else\scriptstyle\fi},
+ \v!big=>\def\@@localchemicalstyle{\ifsmallchemicaltext\scriptstyle\else\textstyle\fi},
+ \s!unknown=>\def\@@localchemicalstyle{\getvalue{#1\c!textsize}}]%
+ \processaction
+ [\getvalue{#1\c!scale}]
+ [ \v!small=>\def\@@localchemicalscale{500},
+ \v!medium=>\def\@@localchemicalscale{625},
+ \v!big=>\def\@@localchemicalscale{750},
+ \s!unknown=>\def\@@localchemicalscale{\getvalue{#1\c!scale}}]}
+
+\def\@@currentchemicalformat
+ {\ifinchemical
+ \@@localchemicalformat
+ \else
+ \@@localchemicalstyle
+ \fi}
+
+\def\dosetupchemical[#1]%
+ {\getparameters[\??chemical\s!chemical][#1]%
+ \doifelse{\@@chemicalchemicaloffset}{LOW}
+ {\setlowsubscripts}
+ {\sethighsubscripts}%
+ \setupchemicalformat[\??chemical\s!chemical]%
+ \ignorespaces}
+
+\def\setupchemical
+ {\dosingleargument\dosetupchemical}
+
+\def\@@dochemicalstyle% % default mapping
+ {\@@chemicalstyle}
+
+\def\@@dochemicalcolor% % no mapping yet
+ {}
+
+\def\@@chemicalstyle % $inner-style$ % (overloaded)
+ {\@@chemicalchemicalstyle} % $$outer-style$$
+
+\def\@@writechemicalstate#1#2%
+ {}
+
+\def\@@beginchemicallocalpicture
+ {\ifcase\chemicaldrawingmode
+ \beginpicture
+ \or
+ \pspicture(0,0)(0,0) % is this permitted ?
+ \or
+ \pushMPdrawing
+ \startMPdrawing
+ %prologues := 1 ;
+ %input mp-tool ;
+ u := 10*\@@chemicalunit;
+ bboxmargin := 0pt ;
+ pickup pencircle scaled 2u ; % ???
+ \stopMPdrawing
+ \beginpicture
+ \fi}
+
+\def\@@endchemicallocalpicture#1#2%
+ {\ifcase\chemicaldrawingmode
+ \endpicture
+ \or
+ \endpspicture
+ \or
+ \resetchemicalcoordinates
+ \setbox2\hbox{\MPshiftdrawingtrue\MPstaticgraphictrue\getMPdrawing}%
+ \wd2=\!!zeropoint
+ \ht2=\!!zeropoint
+ \dp2=\!!zeropoint
+ \put {\box2} at 0 0
+ \endpicture
+ \popMPdrawing
+ \fi}
+
+\def\@@beginchemicalpicture#1#2#3#4%
+ {\ifnum\chemicaldrawingmode=1
+ \pspicture(#1,#3)(#2,#4)%
+ \def\account##1##2{}%
+ \psaxes[axesstyle=none,labels=none,ticks=none](#1,#3)(#2,#4)%
+ \else
+ \beginpicture
+ \setplotarea
+ x from {#1} to {#2},
+ y from {#3} to {#4}
+ \iffixedchemical
+ \accountingon
+ \def\account##1##2%
+ {\put {} at {##1} {##2} }%
+ \else
+ \accountingoff
+ \def\account##1##2{}%
+ \fi
+ \fi
+ \ignorespaces}
+
+\def\@@endchemicalpicture%
+ {\ifcase\chemicaldrawingmode
+ \put {\box\chemicalsymbols} at 0 0 % elders
+ \endpicture
+ \or
+ \rput(0,0){\box\chemicalsymbols}%
+ \endpspicture
+ \or
+ \put {\box\chemicalsymbols} at 0 0 % elders
+ \ifMPdrawingdone
+ \resetchemicalcoordinates
+ \setbox2\hbox{\MPshiftdrawingtrue\MPstaticgraphictrue\getMPdrawing}%
+ \wd2=\!!zeropoint
+ \ht2=\!!zeropoint
+ \dp2=\!!zeropoint
+ \put {\box2} at 0 0 %
+ \fi
+ \endpicture
+ \fi}
+
+\def\@@setchemicalcoordinatesystem#1%
+ {\edef\@@chemicalunit{#1}%
+ \ifcase\chemicaldrawingmode
+ \setcoordinatesystem units <\@@chemicalunit,\@@chemicalunit> %
+ \or
+ \psset{unit=\@@chemicalunit}%
+ \or
+ \setcoordinatesystem units <\@@chemicalunit,\@@chemicalunit> %
+ \startMPdrawing
+ %input mp-tool ;
+ %prologues := 1 ;
+ u := 10*#1;
+ bboxmargin := 0pt ;
+ pickup pencircle scaled 2u ; % ???
+ \stopMPdrawing
+ \fi}
+
+\ifx\MPdivten\undefined % hack to prevent overflows in mp
+ \def\MPdivten[#1]{\withoutpt\the\dimexpr#1pt/10\relax}
+\fi
+
+\def\@@setchemicalaxis#1#2#3#4%
+ {\ifcase\chemicaldrawingmode
+ \axis
+ bottom shiftedto y=0
+ ticks from {#1} to {#2} by 500 /
+ \axis
+ left shiftedto x=0
+ ticks from {#3} to {#4} by 500 / %
+ \or
+ \psaxes[labels=none,Dx=500,Dy=500](0,0)(#1,#3)(#2,#4)%
+ \or
+ \global\MPdrawingdonetrue
+ % we need to div beforehand because of mp limitations
+ \startMPdrawing
+ x1 := \MPdivten[#1]u ; x2 := \MPdivten[#2]u;
+ y1 := \MPdivten[#3]u ; y2 := \MPdivten[#4]u;
+ draw z1--(x2,y1)--z2--(x1,y2)--cycle ;
+ d := 50u ; dd := 10u ;
+ draw (x1,0)--(x2,0) ;
+ draw (0,y1)--(0,y2) ;
+ for i=d step -d until x1: draw (i,dd)--(i,-dd) ; endfor ;
+ for i=d step d until x2: draw (i,dd)--(i,-dd) ; endfor ;
+ for i=d step -d until y1: draw (-dd,i)--(dd,i) ; endfor ;
+ for i=d step d until y2: draw (-dd,i)--(dd,i) ; endfor ;
+ \stopMPdrawing
+ \fi}
+
+\def\@@setsecondchemicalplotsymbol%
+ {\ifcase\chemicaldrawingmode
+ \!!widtha=50.8mm
+ \divide\!!widtha by \@@chemicalresolution\relax
+ \plotsymbolspacing=\!!widtha
+ \setplotsymbol({\vrule\!!height\!!widtha\!!width\!!widtha})%
+ \fi}
+
+% Something for Dirk:
+
+\newcount \currentchemical
+
+%\newif \ifskipchemical
+
+\def\setchemicaldimensions#1#2#3%
+ {\bgroup
+ \global\advance\currentchemical by 1
+ \dimen0=#1\relax
+ \dimen2=#2\relax
+ \dimen4=#3\relax
+ \setxvalue{chemical::\the\currentchemical}%
+ {\noexpand\docommand{\the\dimen0}{\the\dimen2}{\the\dimen4}}%
+ \egroup}
+
+\ifx\normalchemicalframe\undefined
+ \let\normalchemicalframe\hbox % hook for educational purposes
+\fi
+
+\unexpanded\def\complexstartchemical[#1]%
+ {\copyparameters
+ [\??chemical][\??chemical\s!chemical]
+ [\c!width,\c!height,\c!left,\c!right,\c!top,\c!bottom,
+ \c!bodyfont,\c!size,\c!scale,\c!state,\c!frame,\c!axis,\c!factor,
+ \c!location,\c!option,\c!alternative,\c!resolution,\c!offset,\c!style,
+ \c!color,\c!rulecolor,\c!rulethickness]%
+ \getparameters
+ [\??chemical]
+ [#1]%
+ %
+ \setupchemicalformat[\??chemical]%
+ %
+ \ifnum\chemicaldrawingmode=2
+ \resetMPdrawing
+ \fi
+ %
+ \doif{\@@chemicalalternative}{2}
+ {\@@setsecondchemicalplotsymbol}%
+ %
+ \doif{\@@chemicalaxis}\v!on
+ {\let\chemicalframe\hbox}%
+ %
+ \!!counta=250000
+ \divide\!!counta by \@@localchemicalscale
+ \!!widtha=\@@chemicalbodyfont
+ \divide\!!widtha by \!!counta
+ \@@setchemicalcoordinatesystem{\the\!!widtha}%
+ %
+ % \!!counta = -x \!!countc = -y
+ % \!!countb = +x \!!countd = +y
+ %
+ \def\calculateaxis##1##2##3##4##5%
+ {##1=##3\relax
+ ##2=##4\relax
+ \ifnum##5=0
+ \ifnum##3=0
+ \ifnum##4=0
+ ##1=2000
+ ##2=2000
+ \fi
+ \fi
+ \else
+ \ifnum##3=0
+ \ifnum##4=0
+ ##1=##5\relax
+ \divide##1 by 2
+ ##2=##1\relax
+ \else
+ ##1=##5\relax
+ \advance##1 by -##2\relax
+ \fi
+ \else
+ \ifnum##4=0
+ ##2=##5\relax
+ \advance##2 by -##1\relax
+ \fi
+ \fi
+ \fi}%
+ \fixedchemicalfalse
+ \doif\@@chemicalwidth\v!fit
+ {\edef\@@chemicalwidth
+ {\ifnum\chemicaldrawingmode=1 2000 \else 1 \fi}%
+ \fixedchemicaltrue}%
+ \doif\@@chemicalheight\v!fit
+ {\edef\@@chemicalheight
+ {\ifnum\chemicaldrawingmode=1 2000 \else 1 \fi}%
+ \fixedchemicaltrue}%
+ \doifelse\@@chemicallocation\v!intext
+ {\!!counta=0 \!!countb=0
+ \!!counta=0 \!!countd=0 }
+ {\calculateaxis
+ \!!counta\!!countb
+ \@@chemicalleft\@@chemicalright\@@chemicalwidth
+ \calculateaxis
+ \!!countc\!!countd
+ \@@chemicalbottom\@@chemicaltop\@@chemicalheight}%
+ %
+ \edef\@@chemheight {\the\!!countc}%
+ \edef\@@chemdepth {\the\!!countd}%
+ \edef\@@chemicaltop {\the\!!countc}%
+ \edef\@@chemicalbottom{\the\!!countd}%
+ %
+ \doifinsetelse\v!on{\@@chemicalframe,\@@chemicalaxis}
+ {\def\@@chemicalborder{\chemicalframe}}
+ {\def\@@chemicalborder{\normalchemicalframe}}%
+ %
+ \setbox0=\hbox\bgroup % this was a \vbox which took \hsize
+ %
+ \@@beginchemicalpicture
+ {-\the\!!counta}{\the\!!countb}
+ {-\the\!!countc}{\the\!!countd}%
+ \doif{\@@chemicalstate}\v!start
+ {\doif\@@chemicalaxis\v!on
+ {\@@setchemicalaxis
+ {-\the\!!counta}{\the\!!countb}
+ {-\the\!!countc}{\the\!!countd}}}%
+ \doifelse\@@chemicaloption\v!test
+ {\def\@@writechemicalstate##1##2%
+ {\convertargument##2\to\ascii
+ \writestatus{##1}{\ascii}}}
+ {\def\@@writechemicalstate##1##2{}}%
+ \ignorespaces}
+
+\def\dostartchemical%
+ {\catcode`\^=\@@superscript% t.b.v. \enableduplication
+ \catcode`\_=\@@subscript % t.b.v. de zekerheid
+ \begingroup
+ \inchemicaltrue
+ \def\toptext##1{\gdef\thetoptext{##1}\ignorespaces}\toptext{}%
+ \def\bottext##1{\gdef\thebottext{##1}\ignorespaces}\bottext{}%
+ \def\midtext##1{\gdef\themidtext{##1}\ignorespaces}\midtext{}%
+ \def\@@chemicalpostponed{}%
+ \complexorsimpleempty\startchemical}
+
+\def\startchemical
+ {\bgroup % t.b.v. ungrouped floats
+ \dostartchemical}
+
+\def\stopchemical
+ {\checkchemicalpicture
+ \@@endchemicalpicture
+ \egroup
+ \ifnum\chemicaldrawingmode=1
+ \dimen0=\@@chemicalunit
+ \setbox0=\hbox{\lower\@@chemdepth\dimen0\box0}%
+ \ht0=\@@chemheight\dimen0
+ \dp0=\@@chemdepth\dimen0
+ \fi
+ \dimen0=\ht0
+ \advance\dimen0 by \dp0
+ \inchemicalfalse % enables \chemie{} in text
+ \setbox4=\alignedchemical\themidtext
+ \setbox6=\alignedchemical\thetoptext
+ \setbox8=\alignedchemical\thebottext
+ \setbox4=\hbox to \wd0
+ {\strut\hss$\vcenter{\box4}$\hss}%
+ \setbox2=\vbox to \dimen0
+ {\hbox to \wd0{\strut\hss\box6\hss}
+ \vfill
+ \hbox to \wd0{\strut\hss\box8\hss}
+ \vss}% disables the depth
+ \wd0=0pt \wd4=0pt
+ \ht2=\ht0 \dp2=\dp0
+ \ht4=\ht0 \dp4=\dp0
+ \@@chemicalborder{\box0\box4\box2}% text on top of chemicals
+ \endgroup
+ \ignorespaces
+ \egroup} % t.b.v. ungrouped floats
+
+\def\alignedchemical#1%
+ {\vtop
+ {\def\par{\egroup\hbox\bgroup\strut}%
+ \let\\=\par
+ \let\endgraf=\par
+ \hbox\bgroup\strut#1\egroup}}
+
+% \setchemicalcoordinates{#1}{#2}
+%
+% #1: verplaatsing in x-richting
+% #2: verplaatsing in y-richting
+
+\newif\ifchemicaldirection
+
+\def\checkchemicaldirection#1#2%
+ {\ifchemicaldirection
+ \ifnum#1>0 \advance\horchemical -\chemicaldirection \fi
+ \ifnum#1<0 \advance\horchemical +\chemicaldirection \fi
+ \ifnum#2>0 \advance\verchemical -\chemicaldirection \fi
+ \ifnum#2<0 \advance\verchemical +\chemicaldirection \fi
+ \chemicaldirectionfalse
+ \fi}
+
+\def\processchemicaldirection%
+ {\chemicaldirectiontrue\processchemicaltranslate}
+
+\def\setchemicalcoordinates#1#2%
+ {\advance\horchemical #1\relax
+ \advance\verchemical #2\relax
+ \checkchemicaldirection{#1}{#2}%
+ \!!counta=-\horchemical\edef\chemicalxoffset{\the\!!counta}%
+ \!!countb=-\verchemical\edef\chemicalyoffset{\the\!!countb}%
+ \ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \setcoordinatesystem point at {\the\horchemical} {\the\verchemical}
+ \fi}
+
+\def\resetchemicalcoordinates
+ {\horchemical=0
+ \verchemical=0
+ \edef\chemicalxoffset{0}%
+ \edef\chemicalyoffset{0}%
+ \ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \setcoordinatesystem point at 0 0
+ \fi}
+
+\def\restorechemicalcoordinates
+ {%\writestatus{ppchtex}{restoring \the\horchemical,\the\verchemical}%
+ \edef\chemicalxoffset{\the\horchemical}%
+ \edef\chemicalyoffset{\the\verchemical}%
+ \ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \setcoordinatesystem point at {\the\horchemical} {\the\verchemical}
+ \fi}
+
+\def\setchemicaltranslate #1 #2 #3
+ {\setvalue{\s!translate#1}{\setchemicalcoordinates{#2}{#3}}}
+
+\def\processchemicaltranslate#1%
+ {\def\doprocess[##1##2]%
+ {\doifchemicalnumber{##1}{MOV#1}
+ {\ifnum##1=0
+ \def\chemicaloffset{0}% incompatible change
+ \resetchemicalcoordinates
+ \else
+ \getvalue{\s!translate##1}%
+ \dochemicaloffset{##1}%
+ \def\chemicaloffset{0}%
+ \fi}}%
+ \doprocess[#1]}
+
+\def\setchemicaldistance #1
+ {\setvalue{\s!distance1}{\setchemicalcoordinates{-#1}{ 0}}%
+ \setvalue{\s!distance2}{\setchemicalcoordinates{ 0}{ #1}}%
+ \setvalue{\s!distance3}{\setchemicalcoordinates{ #1}{ 0}}%
+ \setvalue{\s!distance4}{\setchemicalcoordinates{ 0}{-#1}}}
+
+\def\setchemicaldirection #1
+ {\def\chemicaldirection{#1}}
+
+\def\processchemicaldistance#1%
+ {\def\doprocess[##1##2]%
+ {\doifchemicalnumber{##1}{ADJ#1}
+ {\ifnum##1=0
+ \resetchemicalcoordinates
+ \else
+ \def\@@chemicalpostponed{\getvalue{\s!distance##1}}%
+ \@@chemicalpostponed
+ \fi}}%
+ \doprocess[#1]}
+
+\def\setchemicalsubstitute #1
+ {\setvalue{\s!substitute1}{\setchemicalcoordinates{-#1}{ 0}}%
+ \setvalue{\s!substitute2}{\setchemicalcoordinates{ 0}{ #1}}%
+ \setvalue{\s!substitute3}{\setchemicalcoordinates{ #1}{ 0}}%
+ \setvalue{\s!substitute4}{\setchemicalcoordinates{ 0}{-#1}}}
+
+\def\processchemicalsubstitute#1%
+ {\def\doprocess[##1##2]%
+ {\doifchemicalnumber{##1}{SUB#1}
+ {\ifnum##1=0
+ \resetchemicalcoordinates
+ \else
+ \def\@@chemicalpostponed{\getvalue{\s!substitute##1}}%
+ \@@chemicalpostponed
+ \fi}}%
+ \doprocess[#1]}
+
+% Het is mogelijk een offset of move meerdere malen uit te
+% voeren, door een nummer voor het commando te plaatsen.
+
+\def\chemicalrepeat {1}
+
+\def\redoprocesschemical[#1#2]%
+ {\doifinstringelse{#1}{0123456789.}
+ {\edef\chemicalrepeat{\chemicalrepeat#1}%
+ \redoprocesschemical[#2]}
+ {\processchemical[#1#2]%
+ \def\chemicalrepeat{1}}}
+
+\def\doprocesschemical[#1#2]#3%
+ {\doifinstringelse{#1}{0123456789.}
+ {\def\chemicalrepeat{#1}%
+ \redoprocesschemical[#2]}
+ {#3}}
+
+% \dochemicaloffset{#1}
+%
+% #1: binding
+
+\def\chemicaloffset{0}
+
+\def\processchemicaloffset#1%
+ {\dimen0=62500 sp % real calc on cardinals, funny number
+ \dimen0=\chemicalrepeat\dimen0
+ \divide\dimen0 by \@@localchemicalscale
+ \!!counta=\dimen0
+ \def\doprocess[##1##2]%
+ {\doifinstringelse{##1}{128}
+ {\edef\chemicaloffset{\the\!!counta}}
+ {\doifinstringelse{##1}{456}
+ {\edef\chemicaloffset{-\the\!!counta}}
+ {\doifelse{##1}{0}
+ {\edef\chemicaloffset{0}}
+ {\unknownchemical{OFF#1}}}}}%
+ \doprocess[#1]}
+
+\def\dochemicaloffset#1%
+ {\ifnum\chemicaloffset=0
+ \def\undochemicaloffset{}%
+ \else
+ \setchemicalcoordinates{-\chemicaloffset}{0}%
+ \def\undochemicaloffset%
+ {\setchemicalcoordinates{\chemicaloffset}{0}%
+ \def\undochemicaloffset{}}%
+ \fi}
+
+\def\processchemicalphantom#1#2%
+ {\setbox0=\hbox
+ {\def\splitoff##1????{##1}%
+ $\@@dochemicalstyle{\@@localchemicalformat\splitoff#2}$}%
+ \dimen0=.25\wd0
+ \divide\dimen0 by \@@localchemicalscale
+ \!!counta=\dimen0
+ \doifinstringelse{#1}{128}
+ {\edef\chemicaloffset{\the\!!counta}}
+ {\doifinstringelse{#1}{456}
+ {\edef\chemicaloffset{-\the\!!counta}}
+ {\doifelse{#1}{0}
+ {\edef\chemicaloffset{0}}
+ {\unknownchemical{OF#1:#2}}}}}
+
+% \dosetchemicalrotation{#1}{#2}
+%
+% #1: cos(phi)
+% #2: sin(phi)
+
+\def\chemicalrotation {1}
+\def\chemicalangle {0}
+\def\chemicalxoffset {0}
+\def\chemicalyoffset {0}
+
+\def\setchemicalmirror#1%
+ {\setvalue{\s!mirror#1}{*}}
+
+\def\resetchemicalmirror#1%
+ {\resetvalue{\s!mirror#1}}
+
+\def\togglechemicalmirror#1%
+ {\doifelse{\getvalue{\s!mirror#1}}{*}
+ {\resetchemicalmirror{#1}}
+ {\setchemicalmirror{#1}}}
+
+\def\setchemicalrotation #1 #2 #3 #4 #5 #6 #7 #8 #9
+ {\setvalue{\s!rotate1.#1}{\dosetchemicalrotation{#2}{#3}}%
+ \setvalue{\s!rotate2.#1}{\dosetchemicalrotation{#4}{#5}}%
+ \setvalue{\s!rotate3.#1}{\dosetchemicalrotation{#6}{#7}}%
+ \setvalue{\s!rotate4.#1}{\dosetchemicalrotation{#8}{#9}}}
+
+\def\setchemicalangle #1 #2 #3 #4 #5
+ {\setvalue{\s!angle1.#1}{\dosetchemicalangle{#2}}%
+ \setvalue{\s!angle2.#1}{\dosetchemicalangle{#3}}%
+ \setvalue{\s!angle3.#1}{\dosetchemicalangle{#4}}%
+ \setvalue{\s!angle4.#1}{\dosetchemicalangle{#5}}}
+
+\def\chemicalrotate[#1]%
+ {\doifdefinedelse{\s!mirror#1}
+ {\getvalue{\s!rotate\chemicalrotation.#1\getvalue{\s!mirror#1}}%
+ \getvalue{\s!angle\chemicalrotation.#1\getvalue{\s!mirror#1}}}
+ {\getvalue{\s!rotate\chemicalrotation.#1}%
+ \getvalue{\s!angle\chemicalrotation.#1}}}
+
+\def\dosetchemicalangle#1% zwak zie onder
+ {\def\chemicalangle{#1}}
+
+\def\dosetchemicalrotation#1#2%
+ {\ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \startrotation by {#1} {#2} %% \stoprotation (t.b.v. testen)
+ \fi}
+
+\def\doresetchemicalrotation
+ {\ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \stoprotation
+ \fi}
+
+\def\processchemicalrotation#1%
+ {\def\doprocess[##1##2]%
+ {\doifnumberelse{##1}
+ {\def\chemicalrotation{##1}}
+ {\unknownchemical{ROT#1}}}%
+ \doprocess[#1]}
+
+% \filtertextelement[#1][#2][#3][#4]
+%
+% #1: volgnummer
+% #2: offset in uitlijningen
+% #3: lijst met uitlijningen -> \chemicalloca
+% #4: lijst met teksten -> \chemicaltext
+
+\def\setchemicallocation#1%
+ {\doifelse{#1}{}
+ {\edef\chemicalloca{c}}
+ {\edef\chemicalloca{#1}}}
+
+\newif\iffixedchemicaltext
+
+\def\filterchemicaltextelement[#1][#2][#3][#4]%
+ {\ifchemicaltextconstant
+ \def\chemicaltext{#4}%
+ \setchemicallocation{}%
+ \else
+ \ifnum#1=0\relax
+ \setchemicallocation{}%
+ \else
+ \iffixedchemicaltext
+ \!!counta#2
+ \else
+ \!!counta=\chemicalrotation
+ \advance\!!counta -1
+ \multiply\!!counta #2
+ \advance\!!counta #1
+ \fi
+ \getfromcommalist[#3][\the\!!counta]%
+ \setchemicallocation\commalistelement
+ \fi
+ \ifchemicalpicture
+ \let\chemicaltext\relax
+ \else
+ \advance\txtchemical 1
+ \getfromcommalist[#4][\txtchemical]%
+ \let\chemicaltext\commalistelement
+ \fi
+ \fi
+ \fixedchemicaltextfalse}
+
+% \putchemicaltext{#1}{#2}
+%
+% #1 : x-coordinaat
+% #2 : y-coordinaat
+%
+% \chemicaltext en \chemicalloca worden met \gettextelement
+% opgehaald uit de tweede set bij \chemie
+%
+% Ten behoeve van testdoeleinden wordt gebruik gemaakt van
+% \chemicalframe in plaats van het meer sjieke, maar tevens
+% meer trage \framed.
+
+\ifx\ruledhbox\undefined
+ \def\chemicalframe#1%
+ {\hbox
+ {\vrule\hskip-.4pt
+ \vbox{\hrule\vskip-.4pt\hbox{#1}\vskip-.4pt\hrule}%
+ \hskip-.4pt\vrule}}
+\else
+ \def\chemicalframe#1%
+ {\ruledhbox{#1}}
+\fi
+
+\def\doputchemicaltext#1 [#2] at #3 #4 %
+ {\ifnum\chemicaldrawingmode=1
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\expanded{\rput[#2]{\chemicalangle}(#3,#4){#1}}}%
+ \else
+ \put {#1} [#2] at {#3} {#4} %
+ \fi}
+
+\def\dodoifsinglelocation#1#2\\#3%
+ {\ifx#2\relax#3\fi}
+
+\def\doifsinglelocationelse#1%
+ {\expandafter\dodoifsinglelocationelse#1\relax\\}
+
+\def\putchemicaltext#1#2%
+ {\enablechemicalspecials
+ \ifchemicalpicture
+ \setchemicalpicture{#1}{#2}%
+ \else
+ \doifelse\@@chemicaloption\v!test
+ {\def\@@chemicalframe{\chemicalframe}}
+ {\def\@@chemicalframe{}}%
+ \dosetsubscripts
+ \setbox2=\hbox{\@@dochemicalcolor
+ $\@@dochemicalstyle{\@@localchemicalformat \chemicaltext}$}%
+ \setbox4=\hbox{$\@@dochemicalstyle{\@@localchemicalformat C_2^2}$}%
+ \setbox6=\hbox{$\@@dochemicalstyle{\@@localchemicalformat O}$}% or C
+ \doresetsubscripts
+ \doifnot\@@chemicallocation\v!intext
+ {\ht2=\ht4
+ \dp2=\dp4}%
+ \setbox2=\hbox{\@@chemicalframe{\box2}}%
+ \ifdim\wd2>\wd6
+ \doifelse{#1}{0}
+ {\doifnot{#2}{0}{\wd2=\wd6}}
+ {%\doifsinglelocation\chemicalloca
+ {\doifinset{\chemicalloca}{t,b}{\wd2=\wd6}}}% common ?
+ \fi
+ \expanded
+ {\doputchemicaltext
+ {\noexpand\dowithchemical{\copy2}} % per se \copy2 i.p.v. \box2
+ [\chemicalloca] at {#1} {#2} }
+ \nomoreaccounting
+ \fi
+ \disablechemicalspecials}
+
+\def\setchemicaltextelement #1 #2 #3
+ {\setvalue{\s!chemicaltextelement#1}{\putchemicaltext{#2}{#3}}}
+
+\def\getchemicalfixedtextelement%
+ {\fixedchemicaltexttrue
+ \getchemicaltextelement}
+
+\def\getchemicaltextelement[#1][#2][#3][#4][#5]%
+ {\filterchemicaltextelement[#2][#3][#4][#5]%
+ \doifelse{#2}{0}
+ {\dochemicaloffset{#2}% % incompatible change
+ \putchemicaltext{0}{0}%
+ \undochemicaloffset} % incompatible change
+ {\chemicalrotate[#2]%
+ \dochemicaloffset{#2}%
+ \def\chemicaltextelementnumber{#2}%
+ \getvalue{\s!chemicaltextelement#1}%
+ \getvalue{\s!chemicaltextelement#11}%
+ \getvalue{\s!chemicaltextelement#12}%
+ \getvalue{\s!chemicaltextelement#13}%
+ \undochemicaloffset}}
+
+\def\processchemicaltextelement#1#2#3#4#5%
+ {\def\doprocess[##1##2##3##4##5]%
+ {\doifelse{##1}{?}
+ {\doprocess[1..\maxchemical ????]}
+ {\doifchemicalnumber{##1}{#1#2}
+ {\doifelse{##2##3}{..}
+ {\doifchemicalnumber{##4}{#1#2}
+ {\getchemicaltextelement[#1][##1][#4][#5][#3]%
+ \doifnot{##1}{##4}
+ {\!!counta=##1\relax
+ \advance\!!counta by 1
+ \edef\nextsegment{\the\!!counta}%
+ \doprocess[\nextsegment..##4##5]}}}
+ {\getchemicaltextelement[#1][##1][#4][#5][#3]%
+ \doifnot{##2}{?}{\doprocess[##2##3##4##5]}}}}}%
+ \doprocess[#2]%
+ \smallchemicaltextfalse}
+
+\def\processchemicalsmalltextelement%
+ {\smallchemicaltexttrue\processchemicaltextelement}
+
+\def\processchemicalsmalltextconstant%
+ {\smallchemicaltexttrue\processchemicaltextconstant}
+
+\def\processchemicalunrotatedtextelement#1#2#3#4#5#6%
+ {\bgroup
+ \xdef\@@xxx{0}%
+ \xdef\@@yyy{0}%
+ \def\putchemicaltext##1##2%
+ {\xdef\@@xxx{##1}%
+ \xdef\@@yyy{##2}}%
+ \getvalue{\s!chemicaltextelement#1}%
+ \egroup
+ \bgroup
+ \def\doputchemicaltext##1 [##2] at ##3 ##4 %
+ {\ifnum\chemicaldrawingmode=1
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\rput{\chemicalangle}(\@@xxx,\@@yyy){\expanded{\rput[##2](##3,##4){##1}}}}%
+ \else
+ \put
+ {\stoprotation \setcoordinatesystem point at 0 0
+ \expanded{\put {##1} [##2] at {##3} {##4} }}
+ at {\@@xxx} {\@@yyy}
+ \fi}%
+ \processchemicaltextelement{#2}{#3}{#4}{#5}{#6}%
+ \egroup}
+
+\newif\ifchemicaltextconstant
+
+\def\processchemicaltextconstant#1#2#3#4%
+ {\chemicaltextconstanttrue
+ \let\@@oldchemicalframe\@@chemicalframe
+ \let\@@chemicalframe\relax
+ \processchemicaltextelement{#1}{#2}{#3}{#4}{}%
+ \let\@@chemicalframe\@@oldchemicalframe
+ \chemicaltextconstantfalse}
+
+% \plotchemicalline{#1}{#2}{#3}{#4}
+%
+% #1: x-coordinaat beginpunt
+% #2: y-coordinaat beginpunt
+% #3: x-coordinaat eindpunt
+% #4: y-coordinaat eindpunt
+
+\chardef\chemicallinetype=0
+
+\def\doplotchemicalline
+ {\!!counte=\!!countc \advance\!!counte by -\!!counta
+ \!!countf=\!!countd \advance\!!countf by -\!!countb
+ \bgroup
+ \ifcase\chemicaldrawingmode
+ \ifcase\chemicallinetype
+ % 0 : normal line
+ \plot {\!!counta} {\!!countb} {\!!countc} {\!!countd} /%
+ \or
+ % 1 : normal arrow
+ \arrow <5pt> [.2,.67] from {\!!counta} {\!!countb} to {\!!countc} {\!!countd}
+ \or
+ % 2 : reverse arrow
+ \arrow <5pt> [.2,.67] from {\!!countc} {\!!countd} to {\!!counta} {\!!countb}
+ \or
+ % 3 : unrotated line
+ \put {\stoprotation \setcoordinatesystem point at 0 0
+ \plot 0 0 {\!!counte} {\!!countf} /}
+ [\chemicallineposition] at {\!!counta} {\!!countb}
+ \else
+ % 4 : dashed line
+ \findlength {\plot {\!!counta} {\!!countb} {\!!countc} {\!!countd} /}%
+ \setdashesnear <2pt> for <\totalarclength>%
+ \plot {\!!counta} {\!!countb} {\!!countc} {\!!countd} /%
+ \fi
+ \or
+ \ifcase\chemicallinetype
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psline(\!!counta,\!!countb)(\!!countc,\!!countd)}%
+ \or
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psline{->}(\!!counta,\!!countb)(\!!countc,\!!countd)}%
+ \or
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psline{<-}(\!!counta,\!!countb)(\!!countc,\!!countd)}%
+ \or
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\expanded{\rput[\chemicallineposition]{-\chemicalangle}%
+ (\!!counta,\!!countb){\psline(0,0)(\!!counte,\!!countf)}}}%
+ \else
+ \psset{linestyle=dashed}%
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psline(\!!counta,\!!countb)(\!!countc,\!!countd)}%
+ \fi
+ \or
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ x0 := \MPdivten[\chemicalxoffset]u ;
+ y0 := \MPdivten[\chemicalyoffset]u ;
+ x1 := \MPdivten[\the\!!counta]u ;
+ y1 := \MPdivten[\the\!!countb]u ;
+ x2 := \MPdivten[\the\!!countc]u ;
+ y2 := \MPdivten[\the\!!countd]u ;
+ x3 := \MPdivten[\the\!!counte]u ;
+ y3 := \MPdivten[\the\!!countf]u ;
+ \ifcase\chemicallinetype
+ % 0 : normal line
+ draw ((z1--z2) rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \or
+ % 1 : normal arrow
+ drawarrow ((z1--z2) rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \or
+ % 2 : reverse arrow
+ drawarrow ((z2--z1) rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \or
+ % 3 : unrotated line % nog \chemicalineposition: t/b
+ draw (origin--z3)
+ shifted (z1 rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \else
+ % 4 : dashed line
+ draw ((z1--z2) rotatedaround(origin,-\chemicalangle))
+ shifted z0 dashed dashpattern(on 5.5u off 6u) ;
+ \fi
+ \stopMPdrawing
+ \fi
+ \egroup
+ \account\!!counta\!!countb
+ \account\!!countc\!!countd}
+
+\def\plotchemicalline#1#2#3#4%
+ {\!!counta=#1\!!countb=#2\!!countc=#3\!!countd=#4\relax
+ \doplotchemicalline}
+
+\def\plotchemicalfactorline#1#2#3#4%
+ {\!!counta=#1\!!countb=#2\!!countc=#3\!!countd=#4\relax
+ \ifdim\@@chemicalfactor\onepoint=\onepoint \else
+ \scratchdimen\!!counta\s!sp \multiply\scratchdimen1000 \scratchdimen\@@chemicalfactor\scratchdimen \divide\scratchdimen1000 \!!counta\scratchdimen
+ \scratchdimen\!!countc\s!sp \multiply\scratchdimen1000 \scratchdimen\@@chemicalfactor\scratchdimen \divide\scratchdimen1000 \!!countc\scratchdimen
+ \fi
+ \doplotchemicalline}
+
+\def\plotchemicalzline#1#2#3#4%
+ {\!!counta=#1\!!countb=#2\!!countc=#3\!!countd=#4\relax
+ \ifnum\chemicaldrawingmode=2
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ x0 := \MPdivten[\chemicalxoffset]u ;
+ y0 := \MPdivten[\chemicalyoffset]u ;
+ x1 := \MPdivten[\the\!!counta]u ;
+ y1 := \MPdivten[\the\!!countb]u ;
+ x2 := \MPdivten[\the\!!countc]u ;
+ y2 := \MPdivten[\the\!!countd]u ;
+ filldraw ((
+ \ifnum\chemicalangle>180
+ z1--z2
+ \else\ifnum\chemicalangle<90
+ z1--(z2 shifted (-2u,+2u))--(z2 shifted (+2u,-2u))
+ \else\ifnum\chemicalangle=90
+ (z1 shifted (-2u,+2u))--(z1 shifted (+2u,-2u))--
+ (z2 shifted (+2u,+2u))--(z2 shifted (-2u,-2u))
+ \else
+ (z1 shifted (+2u,+2u))--(z1 shifted (-2u,-2u))--z2
+ \fi\fi\fi
+ --cycle) rotatedaround(origin,-\chemicalangle)) shifted z0 ;
+ \stopMPdrawing
+ \else
+ \doplotchemicalline
+ \ifnum\chemicalangle>180 \else
+ \ifnum\chemicalangle=90
+ \advance\!!counta by -20 \advance\!!countc by -20
+ \doplotchemicalline
+ \advance\!!counta by 40 \advance\!!countc by 40
+ \else\ifnum\chemicalangle<90
+ \advance\!!countc by -20 \advance\!!countd by +20
+ \doplotchemicalline
+ \advance\!!countc by +40 \advance\!!countd by -40
+ \else
+ \advance\!!counta by 20 \advance\!!countb by 20
+ \doplotchemicalline
+ \advance\!!counta by -40 \advance\!!countb by -40
+ \fi\fi
+ \fi
+ \doplotchemicalline
+ \fi}
+
+\def\plotchemicaldeltaline#1#2#3#4%
+ {\!!counta=#1\!!countb=#2\!!countc=#3\!!countd=#4\relax
+ \ifnum\chemicaldrawingmode=2
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ x0 := \MPdivten[\chemicalxoffset]u ;
+ y0 := \MPdivten[\chemicalyoffset]u ;
+ x1 := \MPdivten[\the\!!counta]u ;
+ y1 := \MPdivten[\the\!!countb]u ;
+ x2 := \MPdivten[\the\!!countc]u ;
+ y2 := \MPdivten[\the\!!countd]u ;
+ filldraw ((z1--(z2 rotatedaround(z1,5))--(z2 rotatedaround(z1,-5))
+ --cycle) rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \stopMPdrawing
+ \account{#1}{#2}%
+ \account{#3}{#4}%
+ \else
+ \doplotchemicalline
+ \advance\!!countc by 16 \advance\!!countd by -21
+ \doplotchemicalline
+ \advance\!!countc by -4 \advance\!!countd by 7
+ \doplotchemicalline
+ \advance\!!countc by -4 \advance\!!countd by 7
+ \doplotchemicalline
+ \advance\!!countc by -8 \advance\!!countd by 14
+ \doplotchemicalline
+ \advance\!!countc by -4 \advance\!!countd by 7
+ \doplotchemicalline
+ \advance\!!countc by -4 \advance\!!countd by 7
+ \doplotchemicalline
+ \advance\!!countc by -4 \advance\!!countd by 7
+ \doplotchemicalline
+ \fi}
+
+\def\setchemicallinesegment #1 #2 #3 #4 #5
+ {\setvalue{\s!chemicallinesegment#1}{\plotchemicalline{#2}{#3}{#4}{#5}}}
+
+\def\setchemicalfactorlinesegment #1 #2 #3 #4 #5
+ {\setvalue{\s!chemicallinesegment#1}{\plotchemicalfactorline{#2}{#3}{#4}{#5}}}
+
+\def\getchemicallinesegment[#1][#2]%
+ {\chemicalrotate[#1]%
+ \dochemicaloffset{#1}%
+ \getvalue{\s!chemicallinesegment#2}%
+ \getvalue{\s!chemicallinesegment#21}%
+ \getvalue{\s!chemicallinesegment#22}%
+ \undochemicaloffset}
+
+\def\getprivatechemicallinesegment[#1][#2]%
+ {\chemicalrotate[#1]%
+ \getvalue{\s!chemicallinesegment#2#1}}
+
+\def\doprocesschemicallinesegment#1#2#3#4#5%
+ {\chardef\chemicallinetype=#1
+ \def\chemicallineposition{#2}%
+ \def\doprocess[##1##2##3##4##5]%
+ {\doifelse{##1}{?}
+ {\doprocess[1..\maxchemical ????]}
+ {\doifchemicalnumber{##1}{#4#5}
+ {\doifelse{##2##3}{..}
+ {\doifchemicalnumber{##4}{#4#5}
+ {#3[##1][#4]%
+ \doifnot{##1}{##4}
+ {\!!counta=##1\relax
+ \advance\!!counta by 1
+ \edef\nextsegment{\the\!!counta}%
+ \doprocess[\nextsegment..##4##5]}}}
+ {#3[##1][#4]%
+ \doifnot{##2}{?}
+ {\doprocess[##2##3##4##5]}}}}}%
+ \doprocess[#5]}
+
+\def\processchemicallinesegment
+ {\doprocesschemicallinesegment0c\getchemicallinesegment}
+
+\def\processchemicalzlinesegment#1#2%
+ {%\doprocesschemicallinesegment0c\getchemicallinesegment{#1}{#2}%
+ \bgroup
+ \def\plotchemicalline{\plotchemicalzline}%
+ \doprocesschemicallinesegment0c\getchemicallinesegment{#1}{#2}%
+ \egroup}
+
+\def\processchemicaldeltalinesegment#1#2%
+ {%\doprocesschemicallinesegment0c\getchemicallinesegment{#1}{#2}%
+ \bgroup
+ \def\plotchemicalline{\plotchemicaldeltaline}%
+ \doprocesschemicallinesegment0c\getchemicallinesegment{#1}{#2}%
+ \egroup}
+
+\def\processprivatechemicallinesegment%
+ {\doprocesschemicallinesegment0c\getprivatechemicallinesegment}
+
+\def\processchemicaldownarrowsegment%
+ {\doprocesschemicallinesegment1c\getchemicallinesegment}
+
+\def\processchemicaluparrowsegment%
+ {\doprocesschemicallinesegment2c\getchemicallinesegment}
+
+\def\processchemicalunrotatedlinesegment#1%
+ {\doprocesschemicallinesegment3{#1}\getchemicallinesegment}
+
+\def\processchemicaldashedlinesegment%
+ {\doprocesschemicallinesegment4c\getchemicallinesegment}
+
+\def\processchemicalopenend#1#2%
+ {\doprocesschemicallinesegment0c\doprocesschemicalopenend{#1}{#2}}
+
+\def\doprocesschemicalopenend[#1][#2]%
+ {\chemicalrotate[#1]%
+ \dochemicaloffset{#1}%
+ \ifcase\chemicaldrawingmode
+ \beginpicture
+ \setquadratic\plot
+ 300 0 400 0
+ 500 0 550 75
+ 600 0 650 -75
+ 700 0 750 75
+ 800 0 850 -75
+ 900 0 950 0
+ 1050 0 /
+ \endpicture
+ \or
+ \rput{-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psline(300,0)(500,0)%
+ \rput(500,0){\psplot[yunit=75,plotstyle=curve]{0}{720}{x sin}}%
+ \psline(950,0)(1050,0)}%
+ \or
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ x0 := \MPdivten[\chemicalxoffset]u ;
+ y0 := \MPdivten[\chemicalyoffset]u ;
+ draw
+ (((30.0u,0)--(50.0u,0){up}..(55.0u,7.5u)..
+ (60.0u,0)..(65.0u,-7.5u)..(70.0u,0)..
+ (75.0u,7.5u)..(80.0u,0)..(85.0u,-7.5u)..{up}
+ (90.0u,0)--(105.0u,0)) rotatedaround(origin,-\chemicalangle))
+ shifted z0 ;
+ \stopMPdrawing
+ \fi
+ \undochemicaloffset}
+
+% \plotchemicalcircle{#1}{#2}{#3}{#4}
+%
+% #1: lengte van de boog in graden
+% #2: x-coordinaat eindpunt
+% #3: y-coordinaat eindpunt
+
+\newif\ifchemicaldotted
+
+\def\plotchemicalcircle#1#2#3#4#5#6%
+ {\bgroup
+ \ifcase\chemicaldrawingmode
+ \ifchemicaldotted
+ \findlength{\circulararc {#4} degrees from {#5} {#6} center at {0} {0} }%
+ \divide\totalarclength by 6
+ \def\b{\the\totalarclength}%
+ \divide\totalarclength by 2
+ \def\a{\the\totalarclength}%
+ \setdashpattern <\a,\b,\b,\b,\b,\b,\a>
+ \fi
+ \circulararc {#4} degrees from {#5} {#6} center at {0} {0} %
+ \or
+ \ifchemicaldotted
+ \psset{linestyle=dashed}%
+ \fi
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\psarc(0,0){#3}{#1}{#2}}%
+ \or
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ r := \MPdivten[#3]*2u;
+ x0 := \MPdivten[\chemicalxoffset]u ;
+ y0 := \MPdivten[\chemicalyoffset]u ;
+ draw ((subpath (#1/45,#2/45) of (fullcircle scaled (r)))
+ rotatedaround (origin,\chemicalangle+150))
+ shifted z0 \ifchemicaldotted dashed withdots \fi ;
+ \stopMPdrawing
+ \fi
+ \egroup}
+
+\def\setchemicalcircsegment #1 #2 #3 #4 #5 #6 #7
+ {\setvalue{\s!chemicalcircsegment#1}{\plotchemicalcircle{#2}{#3}{#4}{#5}{#6}{#7}}}
+
+\def\getchemicalcircsegment[#1][#2]%
+ {\chemicalrotate[#1]%
+ \getvalue{\s!chemicalcircsegment#2}}
+
+\def\doprocesschemicalcircsegment#1#2%
+ {\def\doprocess[##1##2##3##4##5]%
+ {\doifelse{##1}{?}
+ {\doprocess[1..\maxchemical ????]}
+ {\doifchemicalnumber{##1}{#1#2}
+ {\doifelse{##2##3}{..}
+ {\doifchemicalnumber{##4}{#1#2}
+ {\getchemicalcircsegment[##1][#1]%
+ \doifnot{##1}{##4}
+ {\!!counta=##1\relax
+ \advance\!!counta by 1
+ \edef\nextsegment{\the\!!counta}%
+ \doprocess[\nextsegment..##4##5]}}}
+ {\getchemicalcircsegment[##1][#1]%
+ \doifnot{##2}{?}
+ {\doprocess[##2##3##4##5]}}}}}%
+ \doprocess[#2]}
+
+\def\processchemicalcircsegment%
+ {\chemicaldottedfalse\doprocesschemicalcircsegment}
+
+\def\processchemicaldottsegment%
+ {\chemicaldottedtrue\doprocesschemicalcircsegment}
+
+\let\endchemicalpicture = \relax
+\let\checkchemicalpicture = \relax
+\let\nomoreaccounting = \relax
+
+\newif\ifchemicalpicture
+
+\def\beginchemicalpicture#1% NO PSTRICKS SUPPORT YET
+ {\checkchemicalpicture
+ \bgroup % DOES NOT HANDLE AUTOWIDTH/HEIGHT
+ \chemicalpicturetrue
+ \processchemical[#1]}
+
+\def\setchemicalpicture#1#2%
+ {\chemicalpicturefalse
+ \def\endchemicalpicture%
+ {\@@endchemicallocalpicture{#1}{#2}%
+ \egroup
+ \ifnum\chemicaldrawingmode=1
+ \rput
+ {-\chemicalangle}(\chemicalxoffset,\chemicalyoffset)%
+ {\expanded{\rput[\chemicalloca]{\chemicalangle}(#1,#2){\box\nextbox}}}%
+ \else
+ \expanded{\put{\box\nextbox}[\chemicalloca] at {#1} {#2} }
+ \fi
+ \egroup}%
+ \def\checkchemicalpicture%
+ {\ifx\endchemicalpicture\relax \else
+ \writestatus{ppchtex}{missing end of picture (PE)}%
+ \endchemicalpicture
+ \fi}%
+ \setbox\nextbox=\hbox\bgroup
+ \@@beginchemicallocalpicture
+ % alternatief: gewoon accounting, en zelf l,r afhandelen
+ \ifnum\chemicaldrawingmode=1
+ % njet
+ \else
+ \accountingon
+ \let\nomoreaccounting=\accountingoff
+ \fi}
+
+\def\doskipchemical[#1][#2]%
+ {{\tt[ppchtex]}}
+
+\def\skipchemical%
+ {\dodoubleargument\doskipchemical}
+
+\def\complexchemical% met \expandafter
+ {\ifinchemical
+ \expandafter\dochemical
+ \else
+ \writestatus{ppchtex}{the [][]-alternative is not permitted here}%
+ \expandafter\skipchemical
+ \fi}
+
+\newif\ifinnerchemical
+
+\def\dosimplechemical#1#2#3%
+ {\doifdefinedelse{\??chemical\c!location}
+ {\writestatus{ppchtex}{the {}{}-alternative is not permitted here}}
+ {\ifinnerchemical
+ \let\chemicalsign = \chemicalinnersign
+ \let\chemicalmolecule = \chemicalinnermolecule
+ \let\chemicalsinglearrow = \chemicalsingleinnerarrow
+ \let\chemicaldoublearrow = \chemicaldoubleinnerarrow
+ \let\chemicaltwintiparrow = \chemicaltwintipinnerarrow
+ \else
+ \let\chemicalsign = \chemicaloutersign
+ \let\chemicalmolecule = \chemicaloutermolecule
+ \let\chemicalsinglearrow = \chemicalsingleouterarrow
+ \let\chemicaldoublearrow = \chemicaldoubleouterarrow
+ \let\chemicaltwintiparrow = \chemicaltwintipouterarrow
+ \fi
+ \disablechemicalspecials
+ \unexpandedprocessallactionsinset
+ [#1]
+ [ HIGH=>\sethighsubscripts,
+ LOW=>\setlowsubscripts,
+ PLUS=>\chemicalsign{+},
+ GIVES=>\chemicalsinglearrow{#2}{#3},
+ EQUILIBRIUM=>\chemicaldoublearrow{#2}{#3},
+ MESOMERIC=>\chemicaltwintiparrow{#2}{#3},
+ SINGLE=>\singlechemicalbond,
+ DOUBLE=>\doublechemicalbond,
+ TRIPLE=>\triplechemicalbond,
+ +=>\chemicalsign{+},
+ ->=>\chemicalsinglearrow{#2}{#3},
+ <->=>\chemicaldoublearrow{#2}{#3},
+ <>=>\chemicaltwintiparrow{#2}{#3},
+ -=>\singlechemicalbond,
+ --=>\doublechemicalbond,
+ ---=>\triplechemicalbond,
+ \s!unknown=>\enablechemicalspecials
+ \chemicalmolecule{\commalistelement}{#2}{#3}]}}
+
+\def\dosimplechemicalA#1#2#3% % evt: {#1,\relax}
+ {\let\chemicalspace=\relax
+ \@EA\dosimplechemical\@EA{\@@chemicalchemicaloffset,#1}{#2}{#3}%
+ \egroup}
+
+\def\dosimplechemicalB#1#2#3%
+ {\dosimplechemical{#1}{#2}{#3}%
+ \egroup}
+
+\def\dosimplechemicalC#1#2#3%
+ {$\simplechemical{#1}{#2}{#3}$%
+ \egroup} % erbij
+
+\def\simplechemical
+ {\ifinner
+ \innerchemicaltrue
+ \else
+ \innerchemicalfalse
+ \fi
+ \bgroup
+ \catcode`\^=\@@superscript % t.b.v. \enableduplication
+ \catcode`\_=\@@subscript % t.b.v. de zekerheid
+ \ifmmode
+ \ifinnerchemical
+ \def\next{\dotriplegroupempty\dosimplechemicalA}%
+ \else
+ \def\next{\dotriplegroupempty\dosimplechemicalB}%
+ \fi
+ \else
+ \def\next{\dotriplegroupempty\dosimplechemicalC}%
+ \fi
+ \next}
+
+\definecomplexorsimple\chemical
+
+\def\dogotochemical#1#2%
+ {\def\dowithchemical% % experiment
+ {\localgotochemical{#1}}% % experiment
+ \chemical} % experiment
+
+\def\gotochemical% % experiment
+ {\dosingleargument\dogotochemical} % experiment
+
+\def\dododochemical#1[#2][#3]% % experiment
+ {\def\simpledododochemical% % experiment
+ {#1[#2][#3]}% % experiment
+ \def\complexdododochemical[##1]% % experiment
+ {\def\dowithchemical% % experiment
+ {\localthisischemical{#2}}% % experiment
+ #1[#3][##1]}% % experiment
+ \complexorsimple\dododochemical} % experiment
+
+\def\dodochemical[#1][#2]%
+ {\ignorespaces
+ \ifinchemical
+ \drawchemical[#1][#2]%
+ \ignorespaces
+ \else
+ \startchemical[\c!location=\v!intext]%
+ \drawchemical[#1][#2]%
+ \expandafter\stopchemical
+ \fi
+ \ignorespaces}
+
+\def\dochemical[#1]%
+ {\def\simpledochemical%
+ {\@@writechemicalstate{ppchtex}{[#1][]}%
+ \dodochemical[#1][]}%
+ %
+ \def\complexdochemical[##1]%
+ {\@@writechemicalstate{ppchtex}{[#1][##1]}%
+ \txtchemical=0%
+ \dodochemical[#1][##1]}%
+ %
+ \def\complexdochemical[##1]% % experiment
+ {\@@writechemicalstate{ppchtex}{[#1][##1]}% % experiment
+ \txtchemical=0% % experiment
+ \dododochemical\dodochemical[#1][##1]}% % experiment
+ %
+ \complexorsimple\dochemical}
+
+% \processlocalchemicals{#1}
+%
+% #1: commando's
+
+\def\dodoprocesschemical#1%
+ {\processchemical[#1????]}
+
+\def\processlocalchemicals#1%
+ {\processcommalist[#1]\dodoprocesschemical}
+
+% \drawchemical[#1][#2]
+%
+% #1: bindingen enz.
+% #2: atomen enz.
+
+\def\localdodochemical[#1][#2]%
+ {\@@writechemicalstate{ppchtex}{[#1][#2]}%
+ %\bgroup % koppelen en afmetingen gaat fout, vandaar:
+ \advance\levchemical 1
+ \letvalue{\??chemical\s!unknown\the\levchemical}\unknownchemical
+ \setevalue{\??chemical\c!text\the\levchemical}{\the\txtchemical}%
+ \txtchemical=0
+ \dodochemical[#1][#2]%
+ % \@EA\txtchemical\@EA\csname\??chemical\c!text\the\levchemical\endcsname
+ \txtchemical\csname\??chemical\c!text\the\levchemical\endcsname
+ \@EA\let\@EA\unknownchemical\csname\??chemical\s!unknown\the\levchemical\endcsname
+ \advance\levchemical -1
+ %\egroup
+ \ignorespaces}
+
+\def\drawchemical[#1][#2]%
+ {\ignorespaces
+ \def\dodochemical[##1][##2]%
+ {\drawchemical[##1][##2]%
+ \ignorespaces}%
+ \def\dochemical[##1]%
+ {\def\simpledochemical%
+ {\@@writechemicalstate{ppchtex}{[##1][#2]}%
+ \dodochemical[##1][#2]%
+ \ignorespaces}%
+ \def\complexdochemical[####1]%
+ {\dododochemical\localdodochemical[##1][####1,#2]}%
+ \complexorsimple\dochemical}%
+ \doif\@@chemicalstate\v!start
+ {\doifelse\chemicalname\s!unknown
+ {\getvalue{\s!executechemical\defaultchemical}[#2]}
+ {\getvalue{\s!executechemical\chemicalname}[#2]}%
+ \def\unknownchemical##1%
+ {\processunknownchemical[##1][#2]}%
+ \processcommalist[\@@chemicaloffset,#1]\dodoprocesschemical}%
+ \ignorespaces}
+
+\unexpanded\def\chemicaloxidation#1#2#3%
+ {\chemicaltop
+ {\ifnum#20=0
+ 0%
+ \else
+ #1\expandafter\uppercase\expandafter{\romannumeral#2}%
+ \fi}
+ {#3}}
+
+\def\chemicaltfraction{\ifinchemical.60\else.8\fi}
+\def\chemicalbfraction{\ifinchemical.45\else.6\fi}
+\def\chemicallfraction{\ifinchemical.1\else.1\fi}
+\def\chemicalrfraction{\ifinchemical.1\else.1\fi}
+
+\def\chemicaltighttext
+ {\def\chemicaltfraction{\ifinchemical.3\else.6\fi}%
+ \def\chemicalbfraction{\ifinchemical.2\else.4\fi}%
+ \def\chemicallfraction{\ifinchemical 0\else 0\fi}%
+ \def\chemicalrfraction{\ifinchemical 0\else 0\fi}}
+
+\def\dochemicaltop#1#2#3#4%
+ {\vbox
+ {\@@dochemicalcolor
+ \baselineskip=\chemicaltfraction\baselineskip \lineskip0pt
+ \halign
+ {#1###2\cr
+ $\@@dochemicalstyle{\scriptscriptstyle#3}$\cr
+ $\@@dochemicalstyle{\@@currentchemicalformat#4}$\cr}}}
+
+\def\dochemicalbottom#1#2#3#4%
+ {\vtop
+ {\@@dochemicalcolor
+ \baselineskip=\chemicalbfraction\baselineskip \lineskip0pt
+ \halign
+ {#1###2\cr
+ $\@@dochemicalstyle{\@@currentchemicalformat#4}$\cr
+ $\@@dochemicalstyle{\scriptscriptstyle#3}$\cr}}}
+
+\def\chemicalleft#1#2%
+ {\hbox
+ {\@@dochemicalcolor
+ $\@@dochemicalstyle{\scriptscriptstyle#1}$%
+ $\@@dochemicalstyle{\@@currentchemicalformat\hskip\chemicallfraction em#2}$}}
+
+\def\chemicalright#1#2%
+ {\hbox
+ {\@@dochemicalcolor
+ $\@@dochemicalstyle{\@@currentchemicalformat#2\hskip\chemicalrfraction em}$%
+ $\@@dochemicalstyle{\scriptscriptstyle#1}$}}
+
+\def\chemicalcentered#1%
+ {\setbox0=\hbox{$\@@dochemicalstyle{\scriptscriptstyle#1}$}%
+ \setbox2=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat C}$}%
+ \dimen0=.5\ht2
+ \advance\dimen0 by -.5\ht0
+ \advance\dimen0 by \dp0
+ \hbox{\@@dochemicalcolor\raise\dimen0\box0}}
+
+\def\chemicalleftcentered#1#2%
+ {\hbox
+ {\@@dochemicalcolor
+ \chemicalcentered{#1}%
+ $\@@dochemicalstyle{\@@currentchemicalformat\hskip\chemicallfraction em#2}$}}
+
+\def\chemicalrightcentered#1#2%
+ {\hbox
+ {\@@dochemicalcolor
+ $\@@dochemicalstyle{\@@currentchemicalformat#2\hskip\chemicalrfraction em}$%
+ \chemicalcentered{#1}}}
+
+\def\chemicaltop {\dochemicaltop \hss \hss }
+\def\chemicallefttop {\dochemicaltop \relax \hss }
+\def\chemicalrighttop {\dochemicaltop \hss \relax}
+\def\chemicalbottom {\dochemicalbottom \hss \hss }
+\def\chemicalleftbottom {\dochemicalbottom \relax \hss }
+\def\chemicalrightbottom {\dochemicalbottom \hss \relax}
+
+\def\chemicaltopleft #1{\chemicalleft {\chemicallefttop {#1}{}}}
+\def\chemicalbottomleft #1{\chemicalleft {\chemicalleftbottom{#1}{}}}
+\def\chemicaltopright #1{\chemicalright{\chemicallefttop {#1}{}}}
+\def\chemicalbottomright#1{\chemicalright{\chemicalleftbottom{#1}{}}}
+
+\def\chemicalsmashedleft#1%
+ {\hbox\bgroup
+ \@@dochemicalcolor
+ \setbox0=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat C}$}%
+ \setbox2=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat#1}$}%
+ \wd2=\wd0
+ \box2
+ \egroup}
+
+\def\chemicalsmashedmiddle#1%
+ {\hbox\bgroup
+ \@@dochemicalcolor
+ \setbox0=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat C}$}%
+ \setbox2=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat#1}$}%
+ \hbox{\hskip-.5\wd2\hskip.5\wd0\box2}
+ \egroup}
+
+\def\chemicalsmashedright#1%
+ {\hbox\bgroup
+ \@@dochemicalcolor
+ \setbox0=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat C}$}%
+ \setbox2=\hbox{$\@@dochemicalstyle{\@@currentchemicalformat#1}$}%
+ \hbox to \wd0{\hskip-\wd2\hskip\wd0\box2}%
+ \egroup}
+
+\def\+{\tabalign} % is \long in Plain
+
+\def\chemicalforever#1#2%
+ {\bgroup
+ \setbox0=\hbox
+ {\@@dochemicalcolor
+ $\@@dochemicalstyle{\scriptscriptstyle\hskip-.15em#2}$}%
+ \wd0=0pt
+ \big#1_{\hskip.1em\box0}%
+ \egroup}
+
+\def\disablechemicalspecials%
+ {\def\+##1{##1}\def\-##1{##1}%
+ \def\[{[}\def\]{]}%
+ \def\1{}\def\2{}\def\3{}\def\4{}\def\5{}\def\6{}\def\7{}%
+ \def\X{}%
+ \def\T{}\def\B{}\def\L{}\def\R{}\def\LC{}\def\RC{}%
+ \def\TL{}\def\BL{}\def\TR{}\def\BR{}%
+ \def\LT{}\def\LB{}\def\RT{}\def\RB{}%
+ \def\SL{}\def\SM{}\def\SR{}}
+
+\def\enablechemicalspecials%
+ {\def\+{\dodoublegroupempty\chemicaloxidation{+}}% {} needed!
+ \def\-{\dodoublegroupempty\chemicaloxidation{-}}% {} needed!
+ \def\[{\dodoublegroupempty\chemicalforever {[}}% {} needed!
+ \def\]{\dodoublegroupempty\chemicalforever {]}}% {} needed!
+ \def\1{\chemicaloxidation\relax1}%
+ \def\2{\chemicaloxidation\relax2}%
+ \def\3{\chemicaloxidation\relax3}%
+ \def\4{\chemicaloxidation\relax4}%
+ \def\5{\chemicaloxidation\relax5}%
+ \def\6{\chemicaloxidation\relax6}%
+ \def\7{\chemicaloxidation\relax7}%
+ \def\X{\chemicaltighttext}%
+ \def\T{\chemicaltop}%
+ \def\B{\chemicalbottom}%
+ \def\L{\chemicalleft}%
+ \def\LC{\chemicalleftcentered}%
+ \def\R{\chemicalright}%
+ \def\RC{\chemicalrightcentered}%
+ \def\TL{\chemicaltopleft}%
+ \def\BL{\chemicalbottomleft}%
+ \def\TR{\chemicaltopright}%
+ \def\BR{\chemicalbottomright}%
+ \def\LT{\chemicallefttop}%
+ \def\LB{\chemicalleftbottom}%
+ \def\RT{\chemicalrighttop}%
+ \def\RB{\chemicalrightbottom}%
+ \def\SL{\chemicalsmashedleft}%
+ \def\SM{\chemicalsmashedmiddle}%
+ \def\SR{\chemicalsmashedright}}
+
+% \reversechemical#1#2#3
+%
+% #1: prefix
+% #2: volgnummer enz
+% #3: tegengestelde volgnummers
+
+\def\reversechemical#1#2#3%
+ {\def\doprocess[##1##2]%
+ {\doifchemicalnumber{##1}{#1#2}%
+ {\getfromcommalist[#3][##1]%
+ \let\reversechemicalaction=\commalistelement
+ \processchemical[#1\reversechemicalaction##2]}}%
+ \doprocess[#2]}
+
+% \processunknownchemical[#1????][#2]
+%
+% #1: bindingen enz.
+% #2: atomen enz.
+
+\def\defaultchemical%
+ {SIX}
+
+\def\processunknownchemical[#1????][#2]%
+ {\processaction
+ [#1]
+ [ SAVE=>\executechemicalSAVE,
+ RESTORE=>\executechemicalRESTORE,
+ HIGH=>\sethighsubscripts,
+ LOW=>\setlowsubscripts,
+ \s!default=>,
+ \s!unknown=>\doifdefinedelse{\s!executechemical#1}
+ {\def\chemicalrotation{1}%
+ \def\chemicaloffset{0}%
+ \doifdefined{\s!executechemical#1}
+ {\getvalue{\s!executechemical#1}[#2]}%
+ \@@chemicalpostponed}
+ {\getpredefinedchemical{#1}}]}
+
+\newcount\chemicalstack % tzt \newwounter
+
+\setvalue{\s!chemical\c!x1}{0}
+\setvalue{\s!chemical\c!y1}{0}
+
+\def\executechemicalSAVE
+ {%\writestatus{ppchtex}{saving \the\horchemical,\the\verchemical}%
+ \advance\chemicalstack by 1
+ \letvalue {\s!chemical n\the\chemicalstack}=\chemicalname
+ %\letvalue {\s!chemical p\the\chemicalstack}=\@@chemicalpostponed
+ \setevalue{\s!chemical x\the\chemicalstack}{\the\horchemical}%
+ \setevalue{\s!chemical y\the\chemicalstack}{\the\verchemical}}
+
+\def\restorechemicalvalues#1%
+ {\let\oldprocesschemical=\processchemical
+ \doifdefined{\s!executechemical#1}{\getvalue{\s!executechemical#1}[]}%
+ \let\processchemical=\oldprocesschemical}
+
+\def\executechemicalRESTORE
+ {\ifnum\chemicalstack=0\relax
+ \horchemical=\getvalue{\s!chemical x1}\relax
+ \verchemical=\getvalue{\s!chemical y1}\relax
+ \else
+ \restorechemicalvalues{\getvalue{\s!chemical n\the\chemicalstack}}%
+ %\@EA\let\@EA\@@chemicalpostponed\@EA=\csname\s!chemical p\the\chemicalstack\endcsname
+ \let\@@chemicalpostponed=\relax
+ \horchemical=\getvalue{\s!chemical x\the\chemicalstack}\relax
+ \verchemical=\getvalue{\s!chemical y\the\chemicalstack}\relax
+ \advance\chemicalstack by -1
+ \fi
+ \restorechemicalcoordinates}
+
+% De onderstaande macro's zijn verantwoordelijk voor het zetten
+% van de + en pijlen. De +, en dus ook de pijlen, worden omhoog
+% gehaald. Dit oogt m.i. fraaier.
+
+\def\chemicalinnerclip#1%
+ {{\setbox0=\hbox{#1}\ht0\ht\strutbox\dp0\dp\strutbox\box0}}
+
+\def\chemicalraise#1#2%
+ {\chemicalinnerclip
+ {\setbox0=\hbox{$#1+$}%
+ \raise\dp0\hbox{$#1#2$}}}
+
+\def\chemicalinnersign#1% todo: \@@chemicaltextcolor
+ {\chemicalraise{\@@localchemicalstyle}{#1}}
+
+\def\chemicaloutersign#1%
+ {\chemicalraise{}{\@@dochemicalcolor#1}}
+
+\def\chemicalsingleinnerarrow#1#2%
+ {\chemicalraise{\@@localchemicalstyle}{\longrightarrow}}
+
+\def\chemicaldoubleinnerarrow#1#2% todo: \@@chemicaltextcolor
+ {\chemicalinnerclip
+ {\lower.2ex\hbox
+ {\setbox0=\hbox{$\@@localchemicalstyle\longrightarrow$}%
+ \setbox2=\hbox{$\@@localchemicalstyle\longleftarrow$}%
+ \wd0=0pt\raise\ht0\box0\box2}}}
+
+\def\chemicaltwintipinnerarrow#1#2% todo: \@@chemicaltextcolor
+ {\chemicalinnerclip
+ {\setbox0=\hbox{\chemicalraise{\@@localchemicalstyle}{\longrightarrow}}%
+ \setbox2=\hbox{\chemicalraise{\@@localchemicalstyle}{\longleftarrow}}%
+ \wd0=0pt\box0\box2}}
+
+\def\dochemicalouterarrow#1#2#3%
+ {\bgroup
+ \setbox0=\hbox{$\longrightarrow$}%
+ \setbox2=\hbox{$\@@dochemicalstyle{\scriptstyle\quad#2\quad}$}%
+ \setbox4=\hbox{$\@@dochemicalstyle{\scriptstyle\quad#3\quad}$}%
+ \dimen2=\wd0 % \dimen0 is used elsewhere
+ \ifdim\wd2>\dimen2 \dimen0=\wd2 \fi
+ \ifdim\wd4>\dimen2 \dimen0=\wd4 \fi
+ \chemicaloutermolecule
+ {#1}
+ {\ifdim\ht2>\!!zeropoint\box2\fi} % expands to \empty in test
+ {\ifdim\ht4>\!!zeropoint\box4\fi}% % expands to \empty in test
+ \egroup}
+
+\def\chemicalsingleouterarrow
+ {\dochemicalouterarrow
+ {\hbox to \dimen2{\rightarrowfill}}}
+
+\def\chemicaldoubleouterarrow
+ {\dochemicalouterarrow
+ {\lower.5\ht0\vbox
+ {\offinterlineskip
+ \hbox to \dimen2{\rightarrowfill}
+ \hbox to \dimen2{\leftarrowfill}}}}
+
+\def\chemicaltwintipouterarrow
+ {\dochemicalouterarrow
+ {\hbox
+ {\hbox to \dimen2{\rightarrowfill}%
+ \hskip-\dimen2
+ \hbox to \dimen2{\leftarrowfill}}}}
+
+\def\chemicalinnermolecule#1#2#3% no mathop here, can generate space
+ {\chemicalspace % todo: \@@chemicaltextcolor
+ \chemicalinnerclip
+ {\dosetsubscripts
+ $\@@dochemicalstyle{\@@localchemicalstyle\strut#1}$%
+ \doresetsubscripts}%
+ \chemicalspace}
+
+\def\chemicaloutermolecule#1#2#3%
+ {\chemicalspace
+ \bgroup
+ \@@dochemicalcolor
+ \setbox0=\hbox % else the font is reset
+ {\dosetsubscripts
+ \hbox{$\@@dochemicalstyle{\strut#1}$}%
+ \doresetsubscripts}%
+ \mathop{\box0}%
+ \ifthirdargument
+ \doifnot{#2}{}
+ {^{\@@dochemicalstyle{\strut#2}}}%
+ \doifnot{#3}{}
+ {_{\@@dochemicalstyle{\strut#3}}}%
+ \else
+ \doifnot{#2}{}
+ {_{\@@dochemicalstyle{\strut#2}}}%
+ \fi
+ \egroup
+ \chemicalspace}
+
+\def\chemicalsinglepicturearrow#1%
+ {\lower.5ex\hbox
+ {\@@dochemicalstyle
+ $\chemicalspace
+ \buildrel
+ \@@dochemicalstyle{\scriptstyle\quad#1\quad}%
+ \over{\overrightarrow
+ {\hphantom{\@chemicalstyle{\scriptstyle\quad#1\quad}}}}%
+ \chemicalspace$}}
+
+\def\chemicaldoublepicturearrow#1%
+ {\lower.5ex\hbox
+ {\@@dochemicalstyle
+ $\chemicalspace
+ \buildrel
+ \@@dochemicalstyle{\scriptstyle\quad#1\quad}%
+ \over{\overrightarrow{\overleftarrow
+ {\hphantom{\@@dochemicalstyle{\scriptstyle\quad#1\quad}}}}}%
+ \chemicalspace$}}
+
+% Bij de in-line bindingen wordt gebruik gemaakt van
+% een \hrule. De maatvoering wordt bepaald door een
+% kunstmatige em (\wd0).
+
+\def\somechemicalbond%
+ {\hrule width \wd0 height .4pt}
+
+\def\dochemicalbonds#1#2#3% todo: \@@chemicaltextstyle
+ {{\setbox0=\hbox
+ {${\@@localchemicalstyle M}$}%
+ \vbox to \ht0
+ {\@@dochemicalcolor
+ \hsize\wd0
+ \vskip.1\wd0#1\vfill#2\vfill#3\vskip.1\wd0}}}
+
+\def\singlechemicalbond%
+ {\dochemicalbonds{}{\somechemicalbond}{}}
+
+\def\doublechemicalbond%
+ {\dochemicalbonds{\somechemicalbond}{}{\somechemicalbond}}
+
+\def\triplechemicalbond%
+ {\dochemicalbonds{\somechemicalbond}{\somechemicalbond}{\somechemicalbond}}
+
+% In plaats van \def\naam{\chemie[...]...} kan beter gebruik
+% worden gemaakt van het commando
+%
+% \definieerchemie[naam]{commando's}
+%
+% De naam krijgt, om problemen met bestaande macro's te
+% voorkomen, een prefix. Bij het ophalen van een commando
+% worden beide definities afgehandeld.
+
+\def\dodefinechemical[#1]#2%
+ {\doifdefined{\??chemical#1}
+ {\writestatus{ppchtex}{chemical definition #1 is redefined}}%
+ \setvalue{\??chemical#1}{#2}}
+
+\def\definechemical%
+ {\dosingleargument\dodefinechemical}
+
+\def\getpredefinedchemical#1%
+ {\doifdefinedelse{\??chemical#1}
+ {\getvalue{\??chemical#1}}
+ {\doifdefinedelse{#1}
+ {\getvalue{#1}}
+ {\writestatus{ppchtex}{unknown chemical definition #1}}}}
+
+% Hieronder zijn de definities van de structuren opgenomen. De
+% naam van de structuur is als volgt opgebouwd:
+%
+% \executechemicalNUMBER[#1]
+%
+% waarbij [#1] betrekking heeft op de tekstelementen van \chemie,
+% de [tweede lijst] dus.
+%
+% De aan \chemie[#1][#2] meegegeven lijst van segmenten wordt
+% deels door de in \execute gedefinieerde macro's afgehandeld,
+% deels door algemene macro's. Segmenten hebben de vorm:
+%
+% [+|-|]identifier[X|XYZ|X..Y]
+%
+% Voorbeelden van segmenten zijn:
+%
+% R1
+% R1..4
+% R135
+% -R1
+% +R35
+
+\setchemicalmaximum 0
+
+\def\processchemical[#1]%
+ {\unknownchemical{#1}}
+
+\def\setchemicalname#1 %
+ {\def\chemicalname{#1}}
+
+\let\chemicalname=\s!unknown
+
+% Vooruitlopend op een gedetailleerde documentatie, zijn hier
+% vast enkele gebruikte afmetingen:
+%
+% lengte radikalen : 500
+% afstand radikalen : 100
+% afstand dubbele radikalen : 260
+% afstand substituenten : +125
+
+\def\executechemicalONE[#1]%
+ {\setchemicalname ONE
+ %
+ \setchemicalmaximum 8
+ \setchemicaldistance 0
+ \setchemicalsubstitute 625
+ \setchemicaldirection 303
+ %
+ \setchemicalrotation 1 1 0 1 0 1 0 1 0
+ \setchemicalrotation 2 0.707 -0.707 0.707 -0.707 0.707 -0.707 0.707 -0.707
+ \setchemicalrotation 3 0 -1 0 -1 0 -1 0 -1
+ \setchemicalrotation 4 -0.707 -0.707 -0.707 -0.707 -0.707 -0.707 -0.707 -0.707
+ \setchemicalrotation 5 -1 0 -1 0 -1 0 -1 0
+ \setchemicalrotation 6 -0.707 0.707 -0.707 0.707 -0.707 0.707 -0.707 0.707
+ \setchemicalrotation 7 0 1 0 1 0 1 0 1
+ \setchemicalrotation 8 0.707 0.707 0.707 0.707 0.707 0.707 0.707 0.707
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 45 135 225 315
+ \setchemicalangle 3 90 180 270 0
+ \setchemicalangle 4 135 225 315 45
+ \setchemicalangle 5 180 270 0 90
+ \setchemicalangle 6 225 315 45 135
+ \setchemicalangle 7 270 0 90 180
+ \setchemicalangle 8 315 45 135 225
+ %
+ \setchemicaltranslate 1 -1000 0
+ \setchemicaltranslate 2 -1000 1000
+ \setchemicaltranslate 3 0 1000
+ \setchemicaltranslate 4 1000 1000
+ \setchemicaltranslate 5 1000 0
+ \setchemicaltranslate 6 1000 -1000
+ \setchemicaltranslate 7 0 -1000
+ \setchemicaltranslate 8 -1000 -1000
+ %
+ \setchemicallinesegment SB 300 0 700 0
+ \setchemicallinesegment DB1 300 50 700 50
+ \setchemicallinesegment DB2 300 -50 700 -50
+ %
+ %setchemicallinesegment EP 200 125 200 -125
+ \setchemicalfactorlinesegment EP 200 125 200 -125
+ %
+ \setchemicaltextelement ES 200 0
+ \setchemicaltextelement ED1 200 50
+ \setchemicaltextelement ED2 200 -50
+ \setchemicaltextelement ET1 200 75
+ \setchemicaltextelement ET2 200 0
+ \setchemicaltextelement ET3 200 -75
+ \setchemicaltextelement HB1 300 0
+ \setchemicaltextelement HB2 475 0
+ \setchemicaltextelement HB3 650 0
+ %
+ \setchemicaltextelement Z 800 0
+ \setchemicaltextelement RZ 950 0
+ \setchemicaltextelement ZN 500 0
+ \setchemicaltextelement ZTN 500 150
+ \setchemicaltextelement ZBN 500 -150
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\doprocesschemical[##1##2##3##4##5]
+ {\processaction
+ [##1##2##3##4##5]
+ [ PB:##4##5=>\beginchemicalpicture{##4##5},
+ PE????=>\endchemicalpicture,
+ SUB##4##5=>\processchemicalsubstitute{##4##5},
+ ADJ##4##5=>\processchemicaldistance{##4##5},
+ MOV##4##5=>\processchemicaltranslate{##4##5},
+ DIR##4##5=>\processchemicaldirection{##4##5},
+ OFF##4##5=>\processchemicaloffset{##4##5},
+ CCD##4##5=>\processchemicaldottsegment{CC}{##4##5},
+ LDD##4##5=>\processchemicaldashedlinesegment{DB1}{##4##5}%
+ \processchemicallinesegment{DB2}{##4##5},
+ RDD##4##5=>\processchemicallinesegment{DB1}{##4##5}%
+ \processchemicaldashedlinesegment{DB2}{##4##5},
+ OF##3:##5=>\processchemicalphantom{##3}{##5},
+ OE##3##4##5=>\processchemicalopenend{OE}{##3##4##5},
+ EP##3##4##5=>\processchemicallinesegment{EP}{##3##4##5},
+ ES##3##4##5=>\processchemicaltextconstant{ES}{##3##4##5}{\hbox{$\cdot$}}{0},
+ ED##3##4##5=>\processchemicaltextconstant{ED}{##3##4##5}{\hbox{$\cdot$}}{0},
+ ET##3##4##5=>\processchemicaltextconstant{ET}{##3##4##5}{\hbox{$\cdot$}}{0},
+ HB##3##4##5=>\processchemicaltextconstant{HB}{##3##4##5}{\hbox{$\cdot$}}{0},
+ SB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5},
+ DB##3##4##5=>\processchemicallinesegment{DB}{##3##4##5},
+ SB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5},
+ BB##3##4##5=>\processchemicaldeltalinesegment{SB}{##3##4##5},
+ SD##3##4##5=>\processchemicaldashedlinesegment{SB}{##3##4##5},
+ TB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5}%
+ \processchemicallinesegment{DB}{##3##4##5},
+ CZ##3##4##5=>\processchemicaltextelement{RZ}{##3##4##5}{#1}{0}{},
+ ZTN##4##5=>\processchemicalsmalltextconstant{ZTN}{##4##5}{\chemicaltextelementnumber}{0},
+ ZTT##4##5=>\processchemicalsmalltextelement{ZTN}{##4##5}{#1}{0}{},
+ ZBN##4##5=>\processchemicalsmalltextconstant{ZBN}{##4##5}{\chemicaltextelementnumber}{0},
+ ZBT##4##5=>\processchemicalsmalltextelement{ZBN}{##4##5}{#1}{0}{},
+ ZN##3##4##5=>\processchemicaltextconstant{ZN}{##3##4##5}{\chemicaltextelementnumber}{0},
+ ZT##3##4##5=>\processchemicaltextelement{ZN}{##3##4##5}{#1}{0}{},
+ Z##2##3##4##5=>\processchemicaltextelement{Z}{##2##3##4##5}{#1}{0}
+ {l,l,t,r,r,r,b,l},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}}
+
+\def\executechemicalTHREE[#1]%
+ {\setchemicalname THREE
+ %
+ \setchemicalmaximum 3
+ \setchemicaldistance 289
+ \setchemicalsubstitute 952
+ %
+ \setchemicalrotation 1 1 0 0 -1 -1 0 0 1
+ \setchemicalrotation 2 -0.5 -0.866 -0.866 0.5 0.5 0.866 0.866 -0.5
+ \setchemicalrotation 3 -0.5 0.866 0.866 0.5 0.5 -0.866 -0.866 -0.5
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 120 210 300 30
+ \setchemicalangle 3 240 330 60 150
+ %
+ \setchemicaltranslate 1 -1000 0
+ \setchemicaltranslate 2 0 1000
+ \setchemicaltranslate 3 1000 0
+ \setchemicaltranslate 4 0 -1000
+ %
+ \setchemicallinesegment B 577 0 -289 -500
+ \setchemicallinesegment SB 352 -130 -64 -370
+ \setchemicallinesegment -SB 352 -130 -289 -500
+ \setchemicallinesegment +SB 577 0 -64 -370
+ \setchemicallinesegment DB1 327 -87 -89 -327
+ \setchemicallinesegment DB2 377 -172 -39 -413
+ \setchemicallinesegment R 577 0 1077 0
+ \setchemicallinesegment -R 577 0 1010 250
+ \setchemicallinesegment +R 577 0 1010 -250
+ \setchemicallinesegment ER1 577 50 1077 50
+ \setchemicallinesegment ER2 577 -50 1077 -50
+ \setchemicallinesegment SR 837 0 1077 0
+ \setchemicallinesegment -SR 802 130 1010 250
+ \setchemicallinesegment +SR 802 -130 1010 -250
+ \setchemicallinesegment DR1 837 50 1077 50
+ \setchemicallinesegment DR2 837 -50 1077 -50
+ %
+ \setchemicaltextelement Z 577 0
+ \setchemicaltextelement RZ 1177 0
+ \setchemicaltextelement -RZ 1097 300
+ \setchemicaltextelement +RZ 1097 -300
+ \setchemicaltextelement CRZ 1077 0
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\processaction
+ [##1##2##3##4]
+ [ ROT##4=>\processchemicalrotation{##4},
+ MOV##4=>\processchemicaltranslate{##4},
+ SUB##4=>\processchemicalsubstitute{##4},
+ ADJ##4=>\processchemicaldistance{##4},
+ -RZ##4=>\processchemicaltextelement{-RZ}{##4}{#1}{3}
+ {l,t,r, l,r,l, r,b,l, r,l,r},
+ +RZ##4=>\processchemicaltextelement{+RZ}{##4}{#1}{3}
+ {l,r,b, r,r,l, r,l,t, l,l,r},
+ -SB##4=>\processchemicallinesegment{-SB}{##4},
+ +SB##4=>\processchemicallinesegment{+SB}{##4},
+ -SR##4=>\processchemicallinesegment{-SR}{##4},
+ +SR##4=>\processchemicallinesegment{+SR}{##4},
+ CRZ##4=>\processchemicaltextelement{CRZ}{##4}{#1}{0}
+ {},
+ DB##3##4=>\processchemicallinesegment{DB}{##3##4},
+ DR##3##4=>\processchemicallinesegment{DR}{##3##4},
+ RZ##3##4=>\processchemicaltextelement{RZ}{##3##4}{#1}{3}
+ {l,r,r, t,r,l, r,l,l, b,l,r},
+ ER##3##4=>\processchemicallinesegment{ER}{##3##4},
+ SB##3##4=>\processchemicallinesegment{SB}{##3##4},
+ SR##3##4=>\processchemicallinesegment{SR}{##3##4},
+ -R##3##4=>\processchemicallinesegment{-R}{##3##4},
+ +R##3##4=>\processchemicallinesegment{+R}{##3##4},
+ B##2##3##4=>\processchemicallinesegment{B}{##2##3##4},
+ R##2##3##4=>\processchemicallinesegment{R}{##2##3##4},
+ Z##2##3##4=>\processchemicaltextelement{Z}{##2##3##4}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+\def\executechemicalFOUR[#1]%
+ {\setchemicalname FOUR
+ %
+ \setchemicalmaximum 4
+ \setchemicaldistance 500
+ \setchemicalsubstitute 0
+ %
+ \setchemicalrotation 1 1 0 0 -1 -1 0 0 1
+ \setchemicalrotation 2 0 -1 -1 0 0 1 1 0
+ \setchemicalrotation 3 -1 0 0 1 1 0 0 -1
+ \setchemicalrotation 4 0 1 1 0 0 -1 -1 0
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 90 180 270 0
+ \setchemicalangle 3 180 270 0 90
+ \setchemicalangle 4 270 0 90 180
+ %
+ \setchemicaltranslate 1 -1000 0
+ \setchemicaltranslate 2 0 1000
+ \setchemicaltranslate 3 1000 0
+ \setchemicaltranslate 4 0 -1000
+ %
+ \setchemicallinesegment B 500 500 500 -500
+ \setchemicallinesegment SB 500 240 500 -240
+ \setchemicallinesegment -SB 500 240 500 -500
+ \setchemicallinesegment +SB 500 500 500 -240
+ \setchemicallinesegment DB1 450 240 450 -240
+ \setchemicallinesegment DB2 550 240 550 -240
+ \setchemicallinesegment EB 360 300 360 -300
+ \setchemicallinesegment R 500 500 854 854
+ \setchemicallinesegment -R 500 500 500 1000
+ \setchemicallinesegment +R 500 500 1000 500
+ \setchemicallinesegment ER1 465 535 819 889
+ \setchemicallinesegment ER2 535 465 889 819
+ \setchemicallinesegment SR 684 684 854 854
+ \setchemicallinesegment -SR 500 760 500 1000
+ \setchemicallinesegment +SR 760 500 1000 500
+ \setchemicallinesegment DR1 649 719 819 889
+ \setchemicallinesegment DR2 719 649 889 819
+ %
+ \setchemicaltextelement Z 500 500
+ \setchemicaltextelement RZ 925 925
+ \setchemicaltextelement -RZ 500 1100
+ \setchemicaltextelement +RZ 1100 500
+ \setchemicaltextelement CRZ 1038 1038
+ %
+ \setchemicaltextelement ZN 350 350
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\processaction
+ [##1##2##3##4]
+ [ PB:##4=>\beginchemicalpicture{##4},
+ PE????=>\endchemicalpicture,
+ ROT##4=>\processchemicalrotation{##4},
+ SUB##4=>\processchemicalsubstitute{##4},
+ ADJ##4=>\processchemicaldistance{##4},
+ MOV##4=>\processchemicaltranslate{##4},
+ -RZ##4=>\processchemicaltextelement{-RZ}{##4}{#1}{4}
+ {b,l,t,r, l,t,r,b, t,r,b,l, r,b,l,t},
+ +RZ##4=>\processchemicaltextelement{+RZ}{##4}{#1}{4}
+ {l,t,r,b, t,r,b,l, r,b,l,t, b,l,t,r},
+ -SB##4=>\processchemicallinesegment{-SB}{##4},
+ +SB##4=>\processchemicallinesegment{+SB}{##4},
+ -SR##4=>\processchemicallinesegment{-SR}{##4},
+ +SR##4=>\processchemicallinesegment{+SR}{##4},
+ CRZ##4=>\processchemicaltextelement{CRZ}{##4}{#1}{0}{},
+ ZN##3##4=>\processchemicaltextconstant{ZN}{##3##4}{\chemicaltextelementnumber}{0},
+ ZT##3##4=>\processchemicaltextelement{ZN}{##3##4}{#1}{0}{},
+ DB##3##4=>\processchemicallinesegment{DB}{##3##4},
+ DR##3##4=>\processchemicallinesegment{DR}{##3##4},
+ EB##3##4=>\processchemicallinesegment{EB}{##3##4},
+ ER##3##4=>\processchemicallinesegment{ER}{##3##4},
+ RZ##3##4=>\processchemicaltextelement{RZ}{##3##4}{#1}{4}
+ {lb,lt,rt,rb, lt,rt,rb,lb, rt,rb,lb,lt, rb,lb,lt,rt},
+ SB##3##4=>\processchemicallinesegment{SB}{##3##4},
+ SR##3##4=>\processchemicallinesegment{SR}{##3##4},
+ -R##3##4=>\processchemicallinesegment{-R}{##3##4},
+ +R##3##4=>\processchemicallinesegment{+R}{##3##4},
+ B##2##3##4=>\processchemicallinesegment{B}{##2##3##4},
+ R##2##3##4=>\processchemicallinesegment{R}{##2##3##4},
+ Z##2##3##4=>\processchemicaltextelement{Z}{##2##3##4}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+\def\executechemicalFIVE[#1]%
+ {\setchemicalname FIVE
+ %
+ \setchemicalmaximum 5
+ \setchemicaldistance 688
+ \setchemicalsubstitute 1226
+ %
+ \setchemicalrotation 1 1 0 0 -1 -1 0 0 1
+ \setchemicalrotation 2 0.309 -0.951 -0.951 -0.309 -0.309 0.940 0.951 0.309
+ \setchemicalrotation 3 -0.809 -0.588 -0.588 0.809 0.809 0.588 0.588 -0.809
+ \setchemicalrotation 4 -0.809 0.588 0.588 0.809 0.809 -0.588 -0.588 -0.809
+ \setchemicalrotation 5 0.309 0.951 0.951 -0.309 -0.309 -0.951 -0.951 0.309
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 72 162 252 342
+ \setchemicalangle 3 144 234 324 54
+ \setchemicalangle 4 216 306 36 126
+ \setchemicalangle 5 288 18 108 198
+ %
+ \setchemicaltranslate 1 -1376 0
+ \setchemicaltranslate 2 -425 1304
+ \setchemicaltranslate 3 1113 809
+ \setchemicaltranslate 4 1113 -809
+ \setchemicaltranslate 5 -425 -1304
+ %
+ \setchemicallinesegment A 1188 500 1188 -500
+ \setchemicallinesegment B 688 500 688 -500
+ \setchemicallinesegment S -263 808 688 -500
+ \setchemicallinesegment SS -116 606 541 -298
+ \setchemicallinesegment -SS -263 808 541 -298
+ \setchemicallinesegment +SS -116 606 688 -500
+ \setchemicallinesegment SB 688 240 688 -240
+ \setchemicallinesegment -SB 688 240 688 -500
+ \setchemicallinesegment +SB 688 500 688 -240
+ \setchemicallinesegment DB1 638 240 638 -240
+ \setchemicallinesegment DB2 738 240 738 -240
+ \setchemicallinesegment EB 548 340 548 -340
+ \setchemicallinesegment R 688 500 1093 794
+ \setchemicallinesegment -R 688 500 688 1000
+ \setchemicallinesegment +R 688 500 1163 345
+ \setchemicallinesegment ER1 659 540 1064 834
+ \setchemicallinesegment ER2 727 460 1122 754
+ \setchemicallinesegment SR 898 653 1093 794
+ \setchemicallinesegment -SR 688 760 688 1000
+ \setchemicallinesegment +SR 935 420 1163 345
+ \setchemicallinesegment DR1 869 693 1064 834
+ \setchemicallinesegment DR2 927 613 1122 754
+ %
+ \setchemicaltextelement Z 688 500
+ \setchemicaltextelement RZ 1188 863
+ \setchemicaltextelement -RZ 688 1100
+ \setchemicaltextelement +RZ 1258 315
+ \setchemicaltextelement CRZ 1323 947
+ %
+ \setchemicalcircsegment C -36 36 590 72 475 -345
+ \setchemicalcircsegment CC -72 0 590 72 182 -561
+ %
+ \setchemicaltextelement ZN 468 350
+ \setchemicaltextelement RN 860 625 % 1.25 Z
+ \setchemicaltextelement RTN 785 728 % .12 / 103 75
+ \setchemicaltextelement RBN 935 522
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\processaction
+ [##1##2##3##4]
+ [ FRONT????=>{\executechemicalFIVEFRONT[#1]},
+ PB:##4=>\beginchemicalpicture{##4},
+ PE????=>\endchemicalpicture,
+ ROT##4=>\processchemicalrotation{##4},
+ SUB##4=>\processchemicalsubstitute{##4},
+ ADJ##4=>\processchemicaldistance{##4},
+ MOV##4=>\processchemicaltranslate{##4},
+ -RZ##4=>\processchemicaltextelement{-RZ}{##4}{#1}{5}
+ {b,l,t,r,r, l,t,r,r,l, t,r,r,l,l, r,b,l,t,r},
+ +RZ##4=>\processchemicaltextelement{+RZ}{##4}{#1}{5}
+ {l,t,r,r,b, t,r,r,l,l, r,r,l,l,r, b,l,l,r,r},
+ -SB##4=>\processchemicallinesegment{-SB}{##4},
+ +SB##4=>\processchemicallinesegment{+SB}{##4},
+ -SR##4=>\processchemicallinesegment{-SR}{##4},
+ +SR##4=>\processchemicallinesegment{+SR}{##4},
+ -RD##4=>\processchemicaldashedlinesegment{-R}{##4},
+ +RD##4=>\processchemicaldashedlinesegment{+R}{##4},
+ -RB##4=>\processchemicaldeltalinesegment{-R}{##4},
+ +RB##4=>\processchemicaldeltalinesegment{+R}{##4},
+ CRZ##4=>\processchemicaltextelement{CRZ}{##4}{#1}{0}{},
+ RTN##4=>\processchemicaltextconstant{RTN}{##4}{\chemicaltextelementnumber}{0},
+ RTT##4=>\processchemicaltextelement{RTN}{##4}{#1}{0}{},
+ RBN##4=>\processchemicaltextconstant{RBN}{##4}{\chemicaltextelementnumber}{0},
+ RBT##4=>\processchemicaltextelement{RBN}{##4}{#1}{0}{},
+ -SS##4=>\processchemicallinesegment{-SS}{##4},
+ +SS##4=>\processchemicallinesegment{+SS}{##4},
+ CCD##4=>\processchemicaldottsegment{CC}{##4},
+ SS##3##4=>\processchemicallinesegment{SS}{##3##4},
+ RD##3##4=>\processchemicaldashedlinesegment{R}{##3##4},
+ RB##3##4=>\processchemicaldeltalinesegment{R}{##3##4},
+ ZN##3##4=>\processchemicaltextconstant{ZN}{##3##4}{\chemicaltextelementnumber}{0},
+ ZT##3##4=>\processchemicaltextelement{ZN}{##3##4}{#1}{0}{},
+ RN##3##4=>\processchemicaltextconstant{RN}{##3##4}{\chemicaltextelementnumber}{0},
+ RT##3##4=>\processchemicaltextelement{RN}{##3##4}{#1}{0}{},
+ AU##3##4=>\processchemicaluparrowsegment{A}{##3##4},
+ AD##3##4=>\processchemicaldownarrowsegment{A}{##3##4},
+ CC##3##4=>\processchemicalcircsegment{CC}{##3##4},
+ CD##3##4=>\processchemicaldottsegment{C}{##3##4},
+ DB##3##4=>\processchemicallinesegment{DB}{##3##4},
+ DR##3##4=>\processchemicallinesegment{DR}{##3##4},
+ EB##3##4=>\processchemicallinesegment{EB}{##3##4},
+ ER##3##4=>\processchemicallinesegment{ER}{##3##4},
+ RZ##3##4=>\processchemicaltextelement{RZ}{##3##4}{#1}{5}
+ {l,l,r,r,r, l,r,r,b,l, r,r,b,l,t, r,l,l,t,r},
+ SB##3##4=>\processchemicallinesegment{SB}{##3##4},
+ SR##3##4=>\processchemicallinesegment{SR}{##3##4},
+ -R##3##4=>\processchemicallinesegment{-R}{##3##4},
+ +R##3##4=>\processchemicallinesegment{+R}{##3##4},
+ B##2##3##4=>\processchemicallinesegment{B}{##2##3##4},
+ C##2##3##4=>\processchemicalcircsegment{C}{##2##3##4},
+ R##2##3##4=>\processchemicallinesegment{R}{##2##3##4},
+ S##2##3##4=>\processchemicallinesegment{S}{##2##3##4},
+ Z##2##3##4=>\processchemicaltextelement{Z}{##2##3##4}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+\def\executechemicalSIX[#1]%
+ {\setchemicalname SIX
+ %
+ \setchemicalmaximum 6
+ \setchemicalsubstitute 1375
+ \setchemicaldistance 866
+ %
+ \setchemicalrotation 1 1 0 0 -1 -1 0 0 1
+ \setchemicalrotation 2 0.5 -0.866 -0.866 -0.5 -0.5 0.866 0.866 0.5
+ \setchemicalrotation 3 -0.5 -0.866 -0.866 0.5 0.5 0.866 0.866 -0.5
+ \setchemicalrotation 4 -1 0 0 1 1 0 0 -1
+ \setchemicalrotation 5 -0.5 0.866 0.866 0.5 0.5 -0.866 -0.866 -0.5
+ \setchemicalrotation 6 0.5 0.866 0.866 -0.5 -0.5 -0.866 -0.866 0.5
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 60 150 240 330
+ \setchemicalangle 3 120 210 300 30
+ \setchemicalangle 4 180 270 0 90
+ \setchemicalangle 5 240 330 60 150
+ \setchemicalangle 6 300 30 120 210
+ %
+ \setchemicaltranslate 1 -1732 0
+ \setchemicaltranslate 2 -866 1500
+ \setchemicaltranslate 3 866 1500
+ \setchemicaltranslate 4 1732 0
+ \setchemicaltranslate 5 866 -1500
+ \setchemicaltranslate 6 -866 -1500
+ %
+ \setchemicallinesegment A 1386 500 1386 -500
+ \setchemicallinesegment S 0 1000 866 -500
+ \setchemicallinesegment SS 125 783 741 -283
+ \setchemicallinesegment -SS 0 1000 741 -283
+ \setchemicallinesegment +SS 125 783 866 -500
+ \setchemicallinesegment B 866 500 866 -500
+ \setchemicallinesegment SB 866 240 866 -240
+ \setchemicallinesegment -SB 866 240 866 -500
+ \setchemicallinesegment +SB 866 500 866 -240
+ \setchemicallinesegment DB1 816 240 816 -240
+ \setchemicallinesegment DB2 916 240 916 -240
+ \setchemicallinesegment EB 726 340 726 -340
+ \setchemicallinesegment R 866 500 1299 750
+ \setchemicallinesegment -R 866 500 866 1000
+ \setchemicallinesegment +R 866 500 1299 250
+ \setchemicallinesegment ER1 841 543 1274 793
+ \setchemicallinesegment ER2 891 457 1324 707
+ \setchemicallinesegment SR 1091 630 1299 750
+ \setchemicallinesegment -SR 866 740 866 1000
+ \setchemicallinesegment +SR 1091 370 1299 250
+ \setchemicallinesegment DR1 1066 673 1274 793
+ \setchemicallinesegment DR2 1116 588 1324 707
+ \setchemicallinesegment MID1 0 1000 -150 200
+ \setchemicallinesegment MID2 0 -1000 -150 -200
+ \setchemicallinesegment MIDS1 0 1000 -180 0
+ \setchemicallinesegment MIDS2 0 -1000 -180 0
+ %
+ \setchemicalcircsegment C -30 30 700 60 600 -346
+ \setchemicalcircsegment CC -60 0 700 60 350 -606
+ %
+ \setchemicaltextelement Z 866 500
+ \setchemicaltextelement RZ 1386 800
+ \setchemicaltextelement -RZ 866 1100
+ \setchemicaltextelement +RZ 1386 200
+ \setchemicaltextelement CRZ 1524 880
+ \setchemicaltextelement MIDZ -150 0
+ %
+ \setchemicaltextelement ZN 589 350
+ \setchemicaltextelement RN 1083 625 % 1.25 Z
+ \setchemicaltextelement RTN 1008 755 % .12 / 130 75
+ \setchemicaltextelement RBN 1158 495
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\processaction
+ [##1##2##3##4##5]
+ [ FRONT????=>{\executechemicalSIXFRONT[#1]},
+ MID????=>\processchemicallinesegment{MID}{1????},
+ MIDS????=>\processchemicallinesegment{MIDS}{1????},
+ MIDZ????=>\processchemicaltextelement{MIDZ}{1????}{#1}{0}{},
+ PB:##4##5=>\beginchemicalpicture{##4##5},
+ PE????=>\endchemicalpicture,
+ ROT##4##5=>\processchemicalrotation{##4##5},
+ SUB##4##5=>\processchemicalsubstitute{##4##5},
+ ADJ##4##5=>\processchemicaldistance{##4##5},
+ MOV##4##5=>\processchemicaltranslate{##4##5},
+ -RZ##4##5=>\processchemicaltextelement{-RZ}{##4##5}{#1}{6}
+ {b,l,l,t,r,r, l,l,r,r,r,l, t,r,r,b,l,l, r,r,l,l,l,r},
+ +RZ##4##5=>\processchemicaltextelement{+RZ}{##4##5}{#1}{6}
+ {l,t,r,r,b,l, r,r,r,l,l,l, r,b,l,l,t,r, l,l,l,r,r,r},
+ -SB##4##5=>\processchemicallinesegment{-SB}{##4##5},
+ +SB##4##5=>\processchemicallinesegment{+SB}{##4##5},
+ -SR##4##5=>\processchemicallinesegment{-SR}{##4##5},
+ +SR##4##5=>\processchemicallinesegment{+SR}{##4##5},
+ -RD##4##5=>\processchemicaldashedlinesegment{-R}{##4##5},
+ +RD##4##5=>\processchemicaldashedlinesegment{+R}{##4##5},
+ -RB##4##5=>\processchemicaldeltalinesegment{-R}{##4##5},
+ +RB##4##5=>\processchemicaldeltalinesegment{+R}{##4##5},
+ CRZ##4##5=>\processchemicaltextelement{CRZ}{##4##5}{#1}{0}{},
+ -SS##4##5=>\processchemicallinesegment{-SS}{##4##5},
+ +SS##4##5=>\processchemicallinesegment{+SS}{##4##5},
+ CCD##4##5=>\processchemicaldottsegment{CC}{##4##5},
+RTN##4##5=>\processchemicaltextconstant{RTN}{##4##5}{\chemicaltextelementnumber}{0},
+RTT##4##5=>\processchemicaltextelement{RTN}{##4##5}{#1}{0}{},
+RBN##4##5=>\processchemicaltextconstant{RBN}{##4##5}{\chemicaltextelementnumber}{0},
+RBT##4##5=>\processchemicaltextelement{RBN}{##4##5}{#1}{0}{},
+ SS##3##4##5=>\processchemicallinesegment{SS}{##3##4##5},
+ RD##3##4##5=>\processchemicaldashedlinesegment{R}{##3##4##5},
+ RB##3##4##5=>\processchemicaldeltalinesegment{R}{##3##4##5},
+ ZN##3##4##5=>\processchemicaltextconstant{ZN}{##3##4##5}{\chemicaltextelementnumber}{0},
+ ZT##3##4##5=>\processchemicaltextelement{ZN}{##3##4##5}{#1}{0}{},
+RN##3##4##5=>\processchemicaltextconstant{RN}{##3##4##5}{\chemicaltextelementnumber}{0},
+RT##3##4##5=>\processchemicaltextelement{RN}{##3##4##5}{#1}{0}{},
+ AU##3##4##5=>\processchemicaluparrowsegment{A}{##3##4##5},
+ AD##3##4##5=>\processchemicaldownarrowsegment{A}{##3##4##5},
+ CD##3##4##5=>\processchemicaldottsegment{C}{##3##4##5},
+ CC##3##4##5=>\processchemicalcircsegment{CC}{##3##4##5},
+ DB##3##4##5=>\processchemicallinesegment{DB}{##3##4##5},
+ EB##3##4##5=>\processchemicallinesegment{EB}{##3##4##5},
+ ER##3##4##5=>\processchemicallinesegment{ER}{##3##4##5},
+ RZ##3##4##5=>\processchemicaltextelement{RZ}{##3##4##5}{#1}{6}
+ {l,l,t,r,r,b, l,r,r,r,l,l, r,r,b,l,l,t, r,l,l,l,r,r},
+ SB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5},
+ SR##3##4##5=>\processchemicallinesegment{SR}{##3##4##5},
+ DR##3##4##5=>\processchemicallinesegment{DR}{##3##4##5},
+ -R##3##4##5=>\processchemicallinesegment{-R}{##3##4##5},
+ +R##3##4##5=>\processchemicallinesegment{+R}{##3##4##5},
+ B##2##3##4##5=>\processchemicallinesegment{B}{##2##3##4##5},
+ C##2##3##4##5=>\processchemicalcircsegment{C}{##2##3##4##5},
+ R##2##3##4##5=>\processchemicallinesegment{R}{##2##3##4##5},
+ S##2##3##4##5=>\processchemicallinesegment{S}{##2##3##4##5},
+ Z##2##3##4##5=>\processchemicaltextelement{Z}{##2##3##4##5}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}
+
+\def\executechemicalSEVEN[#1]% incomplete !
+ {\setchemicalname SEVEN
+ %
+ \setchemicalmaximum 7
+ \setchemicalsubstitute -
+ \setchemicaldistance 1038
+ %
+ \setchemicalrotation 1 .623 .782 - - - - - -
+ \setchemicalrotation 2 -.223 .975 - - - - - -
+ \setchemicalrotation 3 -.901 .434 - - - - - -
+ \setchemicalrotation 4 -.901 -.434 - - - - - -
+ \setchemicalrotation 5 -.223 -.975 - - - - - -
+ \setchemicalrotation 6 .623 -.782 - - - - - -
+ \setchemicalrotation 7 1 0 - - - - - -
+ %
+ \setchemicalangle 1 0 - - -
+ \setchemicalangle 2 51.429 - - -
+ \setchemicalangle 3 102.857 - - -
+ \setchemicalangle 4 154.286 - - -
+ \setchemicalangle 5 205.714 - - -
+ \setchemicalangle 6 257.143 - - -
+ \setchemicalangle 7 308.571 - - -
+ %
+ \setchemicaltranslate 1 - -
+ \setchemicaltranslate 2 - -
+ \setchemicaltranslate 3 - -
+ \setchemicaltranslate 4 - -
+ \setchemicaltranslate 5 - -
+ \setchemicaltranslate 6 - -
+ \setchemicaltranslate 7 - -
+ %
+ \setchemicallinesegment B 1038 500 1038 -500
+ \setchemicallinesegment SB 1038 240 1038 -240
+ \setchemicallinesegment -SB 1038 240 1038 -500
+ \setchemicallinesegment +SB 1038 500 1038 -240
+ %
+ \setchemicaltextelement Z 1038 500
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\processaction
+ [##1##2##3##4##5]
+ [ PB:##4##5=>\beginchemicalpicture{##4##5},
+ PE????=>\endchemicalpicture,
+ %ROT##4##5=>\processchemicalrotation{##4},
+ %SUB##4##5=>\processchemicalsubstitute{##4##5},
+ %ADJ##4##5=>\processchemicaldistance{##4##5},
+ %MOV##4##5=>\processchemicaltranslate{##4##5},
+ -SB##4##5=>\processchemicallinesegment{-SB}{##4##5},
+ +SB##4##5=>\processchemicallinesegment{+SB}{##4##5},
+ SB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5},
+ B##2##3##4##5=>\processchemicallinesegment{B}{##2##3##4##5},
+ Z##2##3##4##5=>\processchemicaltextelement{Z}{##2##3##4##5}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}
+
+\def\executechemicalEIGHT[#1]% incomplete !
+ {\setchemicalname EIGHT
+ %
+ \setchemicalmaximum 8
+ %\setchemicalsubstitute 1307
+ \setchemicaldistance 1207
+ %
+ \setchemicalrotation 1 .707 .707 - - - - - -
+ \setchemicalrotation 2 0 1 - - - - - -
+ \setchemicalrotation 3 -.707 .707 - - - - - -
+ \setchemicalrotation 4 -1 0 - - - - - -
+ \setchemicalrotation 5 -.707 -.707 - - - - - -
+ \setchemicalrotation 6 0 -1 - - - - - -
+ \setchemicalrotation 7 .707 -.707 - - - - - -
+ \setchemicalrotation 8 1 0 - - - - - -
+ %
+ \setchemicalangle 1 45 - - -
+ \setchemicalangle 2 90 - - -
+ \setchemicalangle 3 135 - - -
+ \setchemicalangle 4 180 - - -
+ \setchemicalangle 5 225 - - -
+ \setchemicalangle 6 270 - - -
+ \setchemicalangle 7 315 - - -
+ \setchemicalangle 8 0 - - -
+ %
+ \setchemicaltranslate 1 -2414 0
+ \setchemicaltranslate 2 -1706 1706
+ \setchemicaltranslate 3 0 2414
+ \setchemicaltranslate 4 1706 1706
+ \setchemicaltranslate 5 2414 0
+ \setchemicaltranslate 6 1706 -1706
+ \setchemicaltranslate 7 0 -2414
+ \setchemicaltranslate 8 -1706 -1706
+ %
+ \setchemicallinesegment B 1207 500 1207 -500
+ \setchemicallinesegment SB 1207 240 1207 -240
+ \setchemicallinesegment -SB 1207 240 1207 -500
+ \setchemicallinesegment +SB 1207 500 1207 -240
+ %
+ \setchemicaltextelement Z 1207 500
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\processaction
+ [##1##2##3##4##5]
+ [ PB:##4##5=>\beginchemicalpicture{##4##5},
+ PE????=>\endchemicalpicture,
+ %SUB##4##5=>\processchemicalsubstitute{##4##5},
+ ADJ##4##5=>\processchemicaldistance{##4##5},
+ MOV##4##5=>\processchemicaltranslate{##4##5},
+ -SB##4##5=>\processchemicallinesegment{-SB}{##4##5},
+ +SB##4##5=>\processchemicallinesegment{+SB}{##4##5},
+ SB##3##4##5=>\processchemicallinesegment{SB}{##3##4##5},
+ B##2##3##4##5=>\processchemicallinesegment{B}{##2##3##4##5},
+ Z##2##3##4##5=>\processchemicaltextelement{Z}{##2##3##4##5}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}
+
+\def\executechemicalFIVEFRONT[#1]%
+ {\executechemicalFIVE[]%
+ %
+ \setchemicalname FIVEFRONT
+ %
+ \setchemicallinesegment -R 688 500 688 100
+ \setchemicallinesegment +R 688 500 688 900
+ %
+ \setchemicaltextelement -RZ 0 -1300
+ \setchemicaltextelement +RZ 0 1300
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\def\chemicalrotation{2}%
+ \processaction
+ [##1##2##3##4]
+ [ -RZ##4=>\processchemicalunrotatedtextelement{Z}{-RZ}{##4}{#1}{5}
+ {,,,,, t,t,t,t,t},
+ +RZ##4=>\processchemicalunrotatedtextelement{Z}{+RZ}{##4}{#1}{5}
+ {,,,,, b,b,b,b,b},
+ -SB##4=>\processchemicallinesegment{-SB}{##4},
+ +SB##4=>\processchemicallinesegment{+SB}{##4},
+ SB##3##4=>\processchemicallinesegment{SB}{##3##4},
+ -R##3##4=>\processchemicalunrotatedlinesegment{t}{-R}{##3##4},
+ +R##3##4=>\processchemicalunrotatedlinesegment{b}{+R}{##3##4},
+ BB##3##4=>\processchemicalzlinesegment{B}{##3##4},
+ R##2##3##4=>\processchemicalunrotatedlinesegment{t}{-R}{##2##3##4}%
+ \processchemicalunrotatedlinesegment{b}{+R}{##2##3##4},
+ B##2##3##4=>\processchemicallinesegment{B}{##2##3##4},
+ Z##2##3##4=>\processchemicaltextelement{Z}{##2##3##4}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+\def\executechemicalSIXFRONT[#1]%
+ {\executechemicalSIX[]%
+ %
+ \setchemicalname SIXFRONT
+ %
+ \setchemicallinesegment -R 866 500 866 100
+ \setchemicallinesegment +R 866 500 866 900
+ %
+ \setchemicaltextelement -RZ 0 -1300
+ \setchemicaltextelement +RZ 0 1300
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\def\chemicalrotation{2}%
+ \processaction
+ [##1##2##3##4]
+ [ -RZ##4=>\processchemicalunrotatedtextelement{Z}{-RZ}{##4}{#1}{6}
+ {,,,,,, t,t,t,t,t,t},
+ +RZ##4=>\processchemicalunrotatedtextelement{Z}{+RZ}{##4}{#1}{6}
+ {,,,,,, b,b,b,b,b,b},
+ -SB##4=>\processchemicallinesegment{-SB}{##4},
+ +SB##4=>\processchemicallinesegment{+SB}{##4},
+ SB##3##4=>\processchemicallinesegment{SB}{##3##4},
+ -R##3##4=>\processchemicalunrotatedlinesegment{t}{-R}{##3##4},
+ +R##3##4=>\processchemicalunrotatedlinesegment{b}{+R}{##3##4},
+ BB##3##4=>\processchemicalzlinesegment{B}{##3##4},
+ R##2##3##4=>\processchemicalunrotatedlinesegment{t}{-R}{##2##3##4}%
+ \processchemicalunrotatedlinesegment{b}{+R}{##2##3##4},
+ B##2##3##4=>\processchemicallinesegment{B}{##2##3##4},
+ Z##2##3##4=>\processchemicaltextelement{Z}{##2##3##4}{#1}{0}{},
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+% 1 : 0
+% 2 : -115
+% 3* : -195
+% 3 : -165
+% 4 : -245
+
+\def\executechemicalCARBON[#1]%
+ {\setchemicalname CARBON
+ %
+ \setchemicalmaximum 4
+ \setchemicaldistance 0
+ \setchemicalsubstitute 0
+ %
+ \setchemicalrotation 1 1 0 0 -1 -1 0 0 1
+ \setchemicalrotation 2 -0.423 -0.906 -0.906 0.423 0.423 0.906 0.906 -0.423
+ \setchemicalrotation 3 -0.966 -0.259 -0.259 0.966 0.966 0.259 0.259 -0.966
+ \setchemicalrotation 3* -0.966 0.259 0.259 0.966 0.966 -0.259 -0.259 -0.966
+ \setchemicalrotation 4 -0.423 0.906 0.906 0.423 0.423 -0.906 -0.906 -0.423
+ %
+ \setchemicalangle 1 0 90 180 270
+ \setchemicalangle 2 115 205 295 25
+ \setchemicalangle 3 165 255 345 75
+ \setchemicalangle 3* 195 285 15 105
+ \setchemicalangle 4 245 335 65 155
+ %
+ \setchemicaltranslate 1 -1500 0
+ \setchemicaltranslate 2 0 1500
+ \setchemicaltranslate 3 1500 0
+ \setchemicaltranslate 4 0 -1500
+ %
+ \setchemicallinesegment B1 500 0 1000 0
+ \setchemicallinesegment B2 300 0 1000 0
+ \setchemicallinesegment B3 500 0 1000 0
+ \setchemicallinesegment B4 300 0 1000 0
+ %
+ \setchemicaltextelement Z 1100 0
+ %
+ \setchemicalcircsegment C 0 360 500 360 0 -500
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\processaction
+ [##1##2##3##4##5]
+ [ MIR????=>\setchemicalmirror{3},
+ -MIR????=>\resetchemicalmirror{3},
+ *MIR????=>\togglechemicalmirror{3},
+ CB????=>\processlocalchemicals{B,C,Z},
+ C????=>\processchemicalcircsegment{C}{1????},
+ -ROT##5=>\reversechemical{ROT}{##5}{3,4,1,2},
+ ROT##4##5=>\processchemicalrotation{##4##5},
+ MOV##4##5=>\processchemicaltranslate{##4##5},
+ CB##3##4##5=>\processlocalchemicals
+ {ROT##3,C,B,Z2..4,
+ MOV##3,*MIR,-ROT##3,C,B,Z2..4},
+ B##2##3##4##5=>\processprivatechemicallinesegment{B}{##2##3##4##5},
+ Z##2##3##4##5=>\processchemicaltextelement{Z}{##2##3##4##5}{#1}{4}
+ {l,t,r,b, t,r,b,l, r,b,l,t, b,l,t,r},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}
+
+% 1: 45 2: -90 3: -225
+% 4: -45 5: -135 6: -270
+
+\newif\ifNEWMANstagger \NEWMANstaggertrue
+
+\def\executechemicalNEWMANSTAGGER%
+ {\NEWMANstaggertrue\executechemicalNEWMAN}
+
+\def\executechemicalNEWMANECLIPSE%
+ {\NEWMANstaggerfalse\executechemicalNEWMAN}
+
+\def\executechemicalNEWMAN[#1]%
+ {\setchemicalname NEWMAN
+ %
+ \setchemicalmaximum 6
+ \setchemicaldistance 0
+ \setchemicalsubstitute 0
+ %
+ \ifNEWMANstagger
+ \setchemicalrotation 1 0.707 0.707 0.707 -0.707 -0.707 -0.707 -0.707 0.707
+ \setchemicalrotation 2 0 -1 -1 0 0 1 1 0
+ \setchemicalrotation 3 -0.707 0.707 0.707 0.707 0.707 -0.707 -0.707 -0.707
+ \else
+ \setchemicalrotation 1 .866 -.5 -.5 -.866 -.866 .5 .5 .866
+ \setchemicalrotation 2 -.259 .966 .966 .259 .259 -.966 -.966 -.259
+ \setchemicalrotation 3 -.5 -.866 -.866 .5 .5 .866 .866 -.5
+ \fi
+ \setchemicalrotation 4 0.707 -0.707 -0.707 -0.707 -0.707 0.707 0.707 0.707
+ \setchemicalrotation 5 -0.707 -0.707 -0.707 0.707 0.707 0.707 0.707 -0.707
+ \setchemicalrotation 6 0 1 1 0 0 -1 -1 0
+ %
+ \ifNEWMANstagger
+ \setchemicalangle 1 315 45 135 225
+ \setchemicalangle 2 90 180 270 0
+ \setchemicalangle 3 225 315 45 135
+ \else
+ \setchemicalangle 1 30 120 210 300
+ \setchemicalangle 2 255 345 75 165
+ \setchemicalangle 3 120 210 300 30
+ \fi
+ \setchemicalangle 4 45 135 225 315
+ \setchemicalangle 5 135 225 315 45
+ \setchemicalangle 6 270 0 90 180
+ %
+ \setchemicaltranslate 1 -1500 0
+ \setchemicaltranslate 2 0 1500
+ \setchemicaltranslate 3 1500 0
+ \setchemicaltranslate 4 0 -1500
+ %
+ \setchemicallinesegment B1 0 0 1000 0
+ \setchemicallinesegment B2 0 0 1000 0
+ \setchemicallinesegment B3 0 0 1000 0
+ \setchemicallinesegment B4 500 0 1000 0
+ \setchemicallinesegment B5 500 0 1000 0
+ \setchemicallinesegment B6 500 0 1000 0
+ %
+ \setchemicaltextelement Z 1100 0
+ %
+ \setchemicalcircsegment C 0 360 500 360 0 -500
+ %
+ \def\processchemical[##1##2##3##4]%
+ {\processaction
+ [##1##2##3##4]
+ [STAGGER????=>{\executechemicalNEWMANSTAGGER[#1]},
+ ECLIPSE????=>{\executechemicalNEWMANECLIPSE[#1]},
+ B????=>\processlocalchemicals{B1..6},
+ CB????=>\processlocalchemicals{B1..6,C,Z1..6},
+ C????=>\processchemicalcircsegment{C}{1????},
+ ROT##4=>\processchemicalrotation{##4},
+ MOV##4=>\processchemicaltranslate{##4},
+ B##2##3##4=>\processprivatechemicallinesegment{B}{##2##3##4},
+ Z##2##3##4=>\ifNEWMANstagger
+ \processchemicaltextelement{Z}{##2##3##4}{#1}{6}
+ {l,t,r,l,r,b, l,r,l,r,r,l, r,b,l,r,l,t, r,l,r,l,l,r}%
+ \else
+ \processchemicaltextelement{Z}{##2##3##4}{#1}{6}
+ {l,r,t,t,r,b, t,b,r,r,b,l, r,l,b,b,l,t, b,t,l,l,t,r}%
+ \fi,
+ \s!unknown=>\unknownchemical{##1##2##3##4}]}}
+
+\def\executechemicalCHAIR[#1]% smaller
+ {\setchemicalname CHAIR
+ %
+ \setchemicalmaximum 6
+ %
+ \setchemicallinesegment B1 1600 800 2800 -800
+ \setchemicallinesegment B2 2800 -800 800 0
+ \setchemicallinesegment B3 800 0 -1600 -800
+ \setchemicallinesegment B4 -1600 -800 -2800 800
+ \setchemicallinesegment B5 -2800 800 -800 0
+ \setchemicallinesegment B6 -800 0 1600 800
+ %
+ \setchemicallinesegment +R1 1600 800 1600 1600
+ \setchemicallinesegment +R2 2800 -800 2800 -1600
+ \setchemicallinesegment +R3 800 0 800 800
+ \setchemicallinesegment +R4 -1600 -800 -1600 -1600
+ \setchemicallinesegment +R5 -2800 800 -2800 1600
+ \setchemicallinesegment +R6 -800 0 -800 -800
+ %
+ \setchemicallinesegment -R1 1600 800 2350 522 % 750 278
+ \setchemicallinesegment -R2 2800 -800 3493 -400
+ \setchemicallinesegment -R3 800 0 1329 -600 % 528 600
+ \setchemicallinesegment -R4 -1600 -800 -2350 -522 % 750 278
+ \setchemicallinesegment -R5 -2800 800 -3493 400
+ \setchemicallinesegment -R6 -800 0 -1329 600 % 528 600
+ %
+ \setchemicaltextelement +RZ1 1600 1800
+ \setchemicaltextelement +RZ2 2800 -1800
+ \setchemicaltextelement +RZ3 800 1000
+ \setchemicaltextelement +RZ4 -1600 -1800
+ \setchemicaltextelement +RZ5 -2800 1800
+ \setchemicaltextelement +RZ6 -800 -1000
+ %
+ \setchemicaltextelement -RZ1 2538 453 % 200 lang
+ \setchemicaltextelement -RZ2 3666 -300
+ \setchemicaltextelement -RZ3 1460 -750
+ \setchemicaltextelement -RZ4 -2538 -453
+ \setchemicaltextelement -RZ5 -3666 300
+ \setchemicaltextelement -RZ6 -1460 750
+ %
+ \def\processchemical[##1##2##3##4##5]%
+ {\def\chemicalrotation{1}%
+ \processaction
+ [##1##2##3##4##5]
+ [ B????=>\processlocalchemicals{B1,B2,B3,B4,B5,B6},
+ -R????=>\processlocalchemicals{-R1,-R2,-R3,-R4,-R5,-R6},
+ +R????=>\processlocalchemicals{+R1,+R2,+R3,+R4,+R5,+R6},
+ B##2????=>{\getchemicallinesegment[0][B##2]},
+ -RZ##4????=>{\getchemicalfixedtextelement[-RZ##4][1][##4][l,l,tc,r,r,bc][#1]},
+ +RZ##4????=>{\getchemicalfixedtextelement[+RZ##4][1][##4][c][#1]},
+ -R##3????=>{\getchemicallinesegment[0][-R##3]},
+ +R##3????=>{\getchemicallinesegment[0][+R##3]},
+ \s!unknown=>\unknownchemical{##1##2##3##4##5}]}}
+
+\def\executechemicalarrow#1#2[#3]%
+ {\dogetcommalistelement1\from#3\to\toptext
+ \dogetcommalistelement2\from#3\to\bottext
+ \def\dochemicaltext##1%
+ {\dosetsubscripts%
+ $\@@dochemicalstyle{\@@localchemicalformat\strut##1}$%
+ \doresetsubscripts}%
+ \doifelse\@@chemicallocation\v!intext
+ {#1{\dochemicaltext\toptext}}%
+ {\setbox\chemicalsymbols=\hbox
+ {\box\chemicalsymbols
+ \vbox{\halign{##\cr
+ \hbox to 3em{\hss\dochemicaltext{\toptext}\hss}\cr
+ #2%
+ \hbox to 3em{\hss\dochemicaltext{\bottext}\hss}\cr}}}}}
+
+\def\executechemicalGIVES
+ {\executechemicalarrow
+ {\chemicalsinglepicturearrow}% nodig
+ {\rightarrowfill\cr}}
+
+\def\executechemicalEQUILIBRIUM
+ {\executechemicalarrow
+ {\chemicaldoublepicturearrow}% nodig
+ {\rightarrowfill\cr\leftarrowfill\cr}}
+
+\def\executechemicalMESOMERIC
+ {\executechemicalarrow
+ {\chemicalsinglepicturearrow}% nodig
+ {$\leftarrow\hskip-1em$\rightarrowfill\cr}}
+
+\def\executechemicalsign#1[#2]%
+ {\doifelse\@@chemicallocation\v!intext
+ {\dosetsubscripts
+ $\@@dochemicalstyle{\@@localchemicalformat#1}$%
+ \doresetsubscripts}
+ {\setbox\chemicalsymbols\hbox
+ {\box\chemicalsymbols
+ \dosetsubscripts
+ $\@@dochemicalstyle{\@@localchemicalformat#1}$%
+ \doresetsubscripts}}}
+
+\def\executechemicalPLUS
+ {\executechemicalsign{+}}
+
+\def\executechemicalMINUS
+ {\executechemicalsign{-}}
+
+\def\executechemicalEQUAL
+ {\executechemicalsign{=}}
+
+\def\executechemicalSPACE[#1]%
+ {\doifnot\@@chemicallocation\v!intext
+ {\setbox\chemicalsymbols\hbox
+ {\box\chemicalsymbols
+ \quad}}}
+
+\def\executechemicalCHEM[#1]%
+ {\doifnot\@@chemicallocation\v!intext
+ {\setbox\chemicalsymbols\hbox
+ {\box\chemicalsymbols
+ $\@@dochemicalstyle{\@@localchemicalformat#1}$}}}
+
+\def\executechemicalTEXT[#1]%
+ {\doifnot\@@chemicallocation\v!intext
+ {\setbox\chemicalsymbols\hbox
+ {\box\chemicalsymbols#1}}}
+
+%\def\executechemicalLOW[#1]%
+% {\setlowsubscripts}
+%
+%\def\executechemicalHIGH[#1]%
+% {\sethighsubscripts}
+
+\def\putchemicalrule#1#2#3#4%
+ {\ifcase\chemicaldrawingmode
+ \putrule from {#1} {#2} to {#3} {#4}
+ \or
+ \psline(#1,#2)(#3,#4)%
+ \or
+ \bgroup
+ \!!counta=#1\!!countb=#2\!!countc=#3\!!countd=#4\relax
+ \global\MPdrawingdonetrue
+ \setchemicalattributes
+ \startMPdrawing
+ x1 := \MPdivten[\the\!!counta]u ;
+ y1 := \MPdivten[\the\!!countb]u ;
+ x2 := \MPdivten[\the\!!countc]u ;
+ y2 := \MPdivten[\the\!!countd]u ;
+ draw z1--z2 ;
+ \stopMPdrawing
+ \egroup
+ \fi}
+
+\def\executechemicalcomplex#1%
+ {\bgroup
+ \putchemicalrule {0} {-\@@chemicalbottom} {0} {\@@chemicaltop}%
+ \putchemicalrule {0} {\@@chemicaltop} {#1150} {\@@chemicaltop}%
+ \putchemicalrule {0} {-\@@chemicalbottom} {#1150} {-\@@chemicalbottom}%
+ \egroup}
+
+\def\executechemicalOPENCOMPLEX[#1]%
+ {\executechemicalcomplex+\ignorespaces
+ \executechemicalSPACE[]}
+
+\def\executechemicalCLOSECOMPLEX[#1]%
+ {\executechemicalSPACE[]%
+ \executechemicalcomplex-\ignorespaces}
+
+% nog niet door midden as!
+
+\def\executechemicalverticalsymbol#1#2%
+ {\executechemicalTEXT
+ [$\left#1\relax
+ \dimen0=\@@chemicalunit
+ \scratchcounter=\@@chemicaltop
+ \advance\scratchcounter by \@@chemicalbottom
+ \dimen0=\scratchcounter\dimen0
+ \vcenter to \dimen0{}
+ \dimen2=\@@chemicalunit
+ \dimen2=\@@chemicalright\dimen0
+ \vcenter{\leftskip1em\hsize\dimen2\relax\strut#2\strut}%
+ \right.$]}%
+
+\def\executechemicalUPARROW[#1]%
+ {\executechemicalverticalsymbol\uparrow{#1}}
+
+\def\executechemicalDOWNARROW[#1]%
+ {\executechemicalverticalsymbol\downarrow{#1}}
+
+\def\executechemicalUPDOWNARROW[#1]%
+ {\executechemicalverticalsymbol\updownarrow{#1}}
+
+\let\setchemicalattributes\relax
+
+\setupchemical
+ [\c!width=0,
+ \c!height=0,
+ \c!left=0,
+ \c!right=0,
+ \c!top=0,
+ \c!bottom=0,
+ \c!bodyfont=\the\bodyfontsize,
+ \c!resolution=\outputresolution,
+ \c!scale=\v!medium,
+ \c!size=\v!medium,
+ \c!textsize=\v!big,
+ \c!frame=\v!off,
+ \c!axis=\v!off,
+ \c!state=\v!start,
+ \c!style=\rm,
+ \c!location=,
+ \c!option=,
+ \c!offset=LOW,
+ \c!alternative=1,
+ \c!color=,
+ \c!rulethickness=,
+ \c!rulecolor=,
+ \c!factor=1]
+
+% Tijdelijk plaatsen we deze extra macro's hier.
+%
+% mathontop: \mtop {} {}
+% textontop: \ttop {} {}
+
+\def\putontop#1#2%
+ {\vbox
+ {\halign
+ {\strut\hss##\hss\cr
+ #1\cr
+ #2\cr}}}
+
+\def\ttop#1#2%
+ {\putontop{\tx#1}{#2}}
+
+\def\mtop#1#2%
+ {\vbox
+ {\offinterlineskip
+ \halign
+ {\hss##\hss\cr
+ $\scriptscriptstyle#1$\cr
+ \noalign{\vskip.5ex}%
+ $#2$\cr}}}
+
+\def\ctop#1#2%
+ {\vbox
+ {\offinterlineskip
+ \halign
+ {\hss##\hss\cr
+ $\@@dochemicalstyle{\@@localchemicalformat\scriptscriptstyle#1}$\cr
+ \noalign{\vskip.5ex}%
+ $\@@dochemicalstyle{\@@localchemicalformat#2}$\cr}}}
+
+%D Here are a couple of goodies:
+%D
+%D \startitemize
+%D \item styles hooked into \CONTEXT\ style mechanism
+%D \item support for color and rulethickness (mp mode only)
+%D \item position tracking
+%D \stopitemize
+
+\let\@@chemicalrulecolor\empty
+\let\@@chemicalcolor \empty
+
+\def\setchemicalattributes
+ {\scratchdimen\@@chemicalrulethickness
+ \def\chemicalattributes
+ {withpen pencircle scaled \the\scratchdimen\space
+ withcolor }%
+ \doifelsenothing\@@chemicalrulecolor
+ {\edef\chemicalattributes{\chemicalattributes black}}
+ {\edef\chemicalattributes{\chemicalattributes \MPcolor{\@@chemicalrulecolor}}}%
+ \startMPdrawing
+ drawoptions (\chemicalattributes) ;
+ \stopMPdrawing}
+
+\def\@@dochemicalcolor
+ {\doifsomething\@@chemicalcolor{\color[\@@chemicalcolor]}}
+
+\def\@@dochemicalstyle
+ {\doconvertfont\@@chemicalstyle}
+
+\setupchemical
+ [\c!rulethickness=\linewidth,
+ \c!rulecolor=,
+ \c!color=]
+
+\def\cpos#1#2%
+ {\iftrialtypesetting
+ #2%
+ \else
+ \bgroup
+ \globalpushmacro\dowithchemical
+ \gdef\dowithchemical##1{\hpos{#1}{##1}\globalpopmacro\dowithchemical}%
+ #2%
+ \egroup
+ \fi}
+
+\protect \endinput
+
+% \startchemical[axis=on,frame=yes]
+% \chemical[SIX,ROT2,B,R36,RZ6][CH_3]
+% \chemical[PB:RZ3,ONE,Z05,SB5,EP37,PE][O,H]
+% \stopchemical
+
+% \startchemical[size=big,scale=small,axis=on,frame=yes,factor=1.5]
+% \chemical[SIX,ROT2,B,R36,RZ6][CH_3]
+% \chemical[PB:RZ3,ONE,Z05,SB5,EP37,PE][O,H]
+% \stopchemical
+
+% \startchemical[size=big,scale=medium,axis=on,frame=yes,factor=1.5]
+% \chemical[SIX,ROT2,B,R36,RZ6][CH_3]
+% \chemical[PB:RZ3,ONE,Z05,SB5,EP37,PE][O,H]
+% \stopchemical
+
+% \startchemical[size=big,scale=big,axis=on,frame=yes,factor=1.5]
+% \chemical[SIX,ROT2,B,R36,RZ6][CH_3]
+% \chemical[PB:RZ3,ONE,Z05,SB5,EP37,PE][O,H]
+% \stopchemical
diff --git a/tex/context/base/prop-ini.tex b/tex/context/base/prop-ini.mkii
index 084842fdd..035a40c93 100644
--- a/tex/context/base/prop-ini.tex
+++ b/tex/context/base/prop-ini.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Property Macros / initialization}
+\writestatus{loading}{ConTeXt Property Macros / Initialization}
%D Welcome to the third alternative of this yet undocumented module,
%D which means that there is no public interface yet!
@@ -28,7 +28,7 @@
% more efficient:
-\def\currentproperty {\csname\??py:c:\number\propertylevel\endcsname} % string
+\def\currentproperty {\csname\??py:c:\number\propertylevel\endcsname} % string
\def\currentpropertytype {\csname\??py\currentproperty\c!type\endcsname}
\def\docheckproperty % watch the s instead of e
@@ -73,14 +73,11 @@
\def\defineproperty
{\dotripleempty\dodefineproperty}
-\def\defineproperty
- {\dotripleempty\dodefineproperty}
-
\def\dodefineproperty[#1]%
- {\ifundefined{\??py#1\c!global}%
- \expandafter\dododefineproperty
- \else
+ {\ifcsname\??py#1\c!global\endcsname
\expandafter\nododefineproperty
+ \else
+ \expandafter\dododefineproperty
\fi[#1]}
% due to initializations/counters, definitions are always global
@@ -92,10 +89,12 @@
\def\dododefineproperty[#1][#2][#3]% global ! ! !
{\getgparameters[\??py#1][\c!global=\v!no,\c!type=#2,\c!method=\v!none,#3]% global ! ! ! !
- \expandafter\newcount\csname\??py:l:#2\endcsname % current level
- \expandafter\newcount\csname\??py:p:#2\endcsname % previous level
- \global\csname\??py:p:#2\endcsname\minusone
- \global\expandafter\expandafter\let\csname\??py:c:0\endcsname\empty
+ \ifcsname\??py:l:#2\endcsname \else
+ \expandafter\newcount\csname\??py:l:#2\endcsname % current level
+ \expandafter\newcount\csname\??py:p:#2\endcsname % previous level
+ \global\csname\??py:p:#2\endcsname\minusone
+ \global\expandafter\expandafter\let\csname\??py:c:0\endcsname\empty
+ \fi
\letgvalue{\??py\s!check#1}\docheckproperty
\doifelsevalue{\??py#1\c!method}\v!command
{\doifelsevalue{\??py#1\c!global}\v!yes
diff --git a/tex/context/base/prop-ini.mkiv b/tex/context/base/prop-ini.mkiv
new file mode 100644
index 000000000..2320f1069
--- /dev/null
+++ b/tex/context/base/prop-ini.mkiv
@@ -0,0 +1,150 @@
+%D \module
+%D [ file=prop-ini,
+%D version=2003.04.20,
+%D title=\CONTEXT\ Property Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Property Macros / Initialization}
+
+%D Welcome to the third alternative of this yet undocumented module,
+%D which means that there is no public interface yet!
+
+\unprotect
+
+\newcount\propertylevel
+
+\def\currentpropertylevel {\csname\??py:l:\currentpropertytype\endcsname} % counter
+\def\previouspropertylevel{\csname\??py:p:\currentpropertytype\endcsname} % counter
+
+\def\currentproperty {\csname\??py:c:\number\currentpropertylevel \endcsname} % string
+\def\previousproperty {\csname\??py:c:\number\previouspropertylevel\endcsname} % string
+
+% more efficient:
+
+\def\currentproperty {\csname\??py:c:\number\propertylevel\endcsname} % string
+\def\currentpropertytype {\csname\??py\currentproperty\c!type\endcsname}
+
+\def\docheckproperty % watch the s instead of e
+ {\csname\s!check\currentpropertytype property\endcsname
+ \global\expandafter\let\csname\??py\s!check\currentproperty\endcsname\empty}
+
+\def\checkproperty[#1]%
+ {\bgroup
+ \def\currentproperty{#1}%
+ \csname\??py\s!check\currentproperty\endcsname
+ \egroup}
+
+\unexpanded\def\property[#1]%
+ {\groupedcommand{\dostartproperty{#1}}\dostopproperty}
+
+\unexpanded\def\startproperty[#1]%
+ {\dostartproperty{#1}}
+
+\unexpanded\def\stopproperty
+ {\dostopproperty}
+
+\def\dostartgproperty
+ {\begingroup\dostartproperty}
+
+\def\dostopgproperty
+ {\dostopproperty\endgroup}
+
+\def\dostartproperty#1% evt pack: {current}{level}{
+ {\global\advance\propertylevel\plusone
+ \@EAEAEA\xdef\currentproperty{#1}%
+ \global\advance\previouspropertylevel\plusone
+ \global\advance\currentpropertylevel\plusone
+ \csname\??py\s!check\currentproperty\endcsname
+ \csname\s!start\currentpropertytype\s!property\endcsname}
+
+\def\dostopproperty
+ {\csname\s!stop\currentpropertytype\s!property\endcsname
+ \global\advance\currentpropertylevel\minusone
+ \global\advance\previouspropertylevel\minusone
+ \global\advance\propertylevel\minusone}
+
+\def\defineproperty
+ {\dotripleempty\dodefineproperty}
+
+\def\dodefineproperty[#1]%
+ {\ifcsname\??py#1\c!global\endcsname
+ \expandafter\nododefineproperty
+ \else
+ \expandafter\dododefineproperty
+ \fi[#1]}
+
+% due to initializations/counters, definitions are always global
+%
+% global : yes : ungrouped
+% no : grouped
+% method : command : define commands
+% none : no commands
+
+\def\dododefineproperty[#1][#2][#3]% global ! ! !
+ {\getgparameters[\??py#1][\c!global=\v!no,\c!type=#2,\c!method=\v!none,#3]% global ! ! ! !
+ \ifcsname\??py:l:#2\endcsname \else
+ \expandafter\newcount\csname\??py:l:#2\endcsname % current level
+ \expandafter\newcount\csname\??py:p:#2\endcsname % previous level
+ \global\csname\??py:p:#2\endcsname\minusone
+ \global\expandafter\expandafter\let\csname\??py:c:0\endcsname\empty
+ \fi
+ \letgvalue{\??py\s!check#1}\docheckproperty
+ \doifelsevalue{\??py#1\c!method}\v!command
+ {\doifelsevalue{\??py#1\c!global}\v!yes
+ {\unexpanded\setgvalue{\e!start#1}{\dostartproperty{#1}}%
+ \unexpanded\setgvalue{\e!stop #1}{\dostopproperty}}%
+ {\unexpanded\setgvalue{\e!start#1}{\dostartgproperty{#1}}%
+ \unexpanded\setgvalue{\e!stop #1}{\dostopgproperty}}}%
+ {\doifelsevalue{\??py#1\c!global}\v!yes
+ {\unexpanded\setgvalue{\e!start#2}[##1]{\dostartproperty{##1}}%
+ \unexpanded\setgvalue{\e!stop #2}{\dostopproperty}}%
+ {\unexpanded\setgvalue{\e!start#2}[##1]{\dostartgproperty{##1}}%
+ \unexpanded\setgvalue{\e!stop #2}{\dostopgproperty}}}}
+
+\def\nododefineproperty[#1][#2][#3]%
+ {}
+
+\def\doifelseproperty#1{\doifdefinedelse{\??py#1\c!global}}
+
+\def\setupproperty
+ {\dodoubleempty\dosetupproperty}
+
+\def\dosetupproperty[#1][#2]% local
+ {\ifsecondargument
+ \getparameters[\??py#1][#2]%
+ \else
+ \getparameters[\??py][#1]%
+ \fi}
+
+\letvalue{\??py\s!empty}\empty
+
+% beware, normally \*parameter concerns the current one
+
+\def\propertyparameter#1#2% expands to #1 when not defined (see \define...)
+ {\csname\??py
+ \ifcsname\??py#1#2\endcsname
+ #1#2%
+ \else\ifcsname\??py\csname\??py#1\c!type\endcsname#2\endcsname
+ \csname\??py#1\c!type\endcsname#2%
+ \else
+ \s!empty
+ \fi\fi
+ \endcsname}
+
+\def\currentpropertyparameter % self and class
+ {\propertyparameter\currentproperty}
+
+\def\checkedpropertyparameter#1% only self
+ {\executeifdefined{\??py\currentproperty#1}}
+
+\def\definepropertyhandler#1{\setvalue{\??py*#1}}
+\def\propertyhandler #1{\getvalue{\??py*#1}}
+
+\protect \endinput
diff --git a/tex/context/base/prop-lay.mkii b/tex/context/base/prop-lay.mkii
index 5dce6c33b..aeec94bb2 100644
--- a/tex/context/base/prop-lay.mkii
+++ b/tex/context/base/prop-lay.mkii
@@ -11,6 +11,11 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Property Macros / Layers}
+
+%D Highly experimental, will probably change/evolve. Also, quite certainly
+%D we will no longer share code between mkii and mkiv.
+
\unprotect
\let\currentlayerproperty\empty
@@ -41,4 +46,98 @@
\expandafter\gobbleoneargument
\fi}
+\setglobalsystemreference \rt!exec \v!HideLayer {hidelayer}
+\setglobalsystemreference \rt!exec \v!VideLayer {videlayer}
+\setglobalsystemreference \rt!exec \v!ToggleLayer {togglelayer}
+
+\setexecutecommandcheck {hidelayer} \domakelayerpropertylist
+\setexecutecommandcheck {videlayer} \domakelayerpropertylist
+\setexecutecommandcheck {togglelayer} \domakelayerpropertylist
+
+% \currentlayerproperty
+% \checklayerproperty
+% \startlayerproperty
+% \stoplayerproperty
+% \domakelayerpropertylist
+
+%D \starttext
+%D
+%D \setuppapersize[S4][S4]
+%D \setuplayout[middle]
+%D \setupcolors[state=start]
+%D \setupinteraction[state=start,color=,contrastcolor=]
+%D
+%D \defineproperty [L1] [layer] [title=layer 1]
+%D \defineproperty [L2] [layer] [title=layer 2]
+%D
+%D \button{HIDE L1}[HideLayer{L1}]
+%D \button{VIDE L1}[VideLayer{L1}]
+%D \button{TOGGLE L1}[ToggleLayer{L1}]
+%D
+%D \button{HIDE L2}[HideLayer{L2}]
+%D \button{VIDE L2}[VideLayer{L2}]
+%D \button{TOGGLE L2}[ToggleLayer{L2}]
+%D
+%D \noheaderandfooterlines \centerbox{\startoverlay
+%D {\definedfont[Mono at 150pt]%
+%D \startproperty[L1]\red TEST\stopproperty}
+%D {\definedfont[Mono at 150pt]%
+%D \startproperty[L2]\green TEST\stopproperty}
+%D \stopoverlay} \page
+%D
+%D \noheaderandfooterlines \centerbox{\startoverlay
+%D {\definedfont[Mono at 15pt]%
+%D \goto{\startproperty[L1]\red TEST\stopproperty}[CloseDocument]}
+%D {\definedfont[Mono at 15pt]%
+%D \goto{\startproperty[L2]\green TEST\stopproperty}[CloseDocument]}
+%D \stopoverlay} \page
+%D
+%D \startproperty[L1]
+%D level 1 \startproperty[L2]level 2 \stopproperty level 1
+%D \stopproperty
+%D
+%D \startproperty[L1]
+%D level 1 \page \startproperty[L2]level 2 \stopproperty level 1
+%D \stopproperty
+%D
+%D \stoptext
+
+%D Handy for tracing:
+
+\def\showlayoutcomponents
+ {\let\startlayoutcomponent\dostartlayoutcomponent
+ \let\stoplayoutcomponent \dostoplayoutcomponent}
+
+\def\dodefinelayoutcomponent#1#2%
+ {\doifelsenothing{#2}%
+ {\defineproperty[#1][\s!layer]}%
+ {\defineproperty[#1][\s!layer][\c!title=#2]}}
+
+\def\dostartlayoutcomponent#1#2%
+ {\doifelseproperty{#1}\donothing{\dodefinelayoutcomponent{#1}{#2}}%
+ \startproperty[#1]}
+
+\def\dostoplayoutcomponent
+ {\stopproperty}
+
+\let\startlayoutcomponent\gobbletwoarguments
+\let\stoplayoutcomponent \relax
+
\protect \endinput
+
+% \def\remaplayering
+% {\dodoubleargument\doremaplayering}
+%
+% \def\remaplayering[#1][#2]%
+% {\setvalue{\??lm#1}{#2}}
+%
+% \def\remappedlayering#1%
+% {\ifcsname\??lm#1\endcsname
+% \@EA\remappedlayering\csname\??lm#1\endcsname\else#1%
+% \fi}
+%
+% \def\startshowlayering#1#2%
+% {\ifshowlayering
+% \defineproperty[\remappedlayering{#1}][\s!layer][\c!titel=#2]%
+% \startproperty[\remappedlayering{#1}]%
+% \fi}
diff --git a/tex/context/base/prop-lay.mkiv b/tex/context/base/prop-lay.mkiv
index 051e2e5be..0cd4bc2c8 100644
--- a/tex/context/base/prop-lay.mkiv
+++ b/tex/context/base/prop-lay.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=prop-lay,
-%D version=2008.09.16,
+%D version=2003.04.20,
%D title=\CONTEXT\ Property Macros,
%D subtitle=Layers,
%D author=Hans Hagen,
@@ -11,6 +11,11 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Property Macros / Layers}
+
+%D Highly experimental, will probably change/evolve. Also, quite certainly
+%D we will no longer share code between mkii and mkiv.
+
% test, nesting is somewhat special with layers
%
% \defineproperty[hans][layer]
@@ -49,4 +54,106 @@
\expandafter\gobbleoneargument
\fi}
+\ifdefined\setglobalsystemreference
+
+ \setglobalsystemreference \rt!exec \v!HideLayer {hidelayer}
+ \setglobalsystemreference \rt!exec \v!VideLayer {videlayer}
+ \setglobalsystemreference \rt!exec \v!ToggleLayer {togglelayer}
+
+ \setexecutecommandcheck {hidelayer} \domakelayerpropertylist
+ \setexecutecommandcheck {videlayer} \domakelayerpropertylist
+ \setexecutecommandcheck {togglelayer} \domakelayerpropertylist
+
+\else
+
+ % todo, but after a full split (saves dev time)
+
+\fi
+
+% \currentlayerproperty
+% \checklayerproperty
+% \startlayerproperty
+% \stoplayerproperty
+% \domakelayerpropertylist
+
+%D \starttext
+%D
+%D \setuppapersize[S4][S4]
+%D \setuplayout[middle]
+%D \setupcolors[state=start]
+%D \setupinteraction[state=start,color=,contrastcolor=]
+%D
+%D \defineproperty [L1] [layer] [title=layer 1]
+%D \defineproperty [L2] [layer] [title=layer 2]
+%D
+%D \button{HIDE L1}[HideLayer{L1}]
+%D \button{VIDE L1}[VideLayer{L1}]
+%D \button{TOGGLE L1}[ToggleLayer{L1}]
+%D
+%D \button{HIDE L2}[HideLayer{L2}]
+%D \button{VIDE L2}[VideLayer{L2}]
+%D \button{TOGGLE L2}[ToggleLayer{L2}]
+%D
+%D \noheaderandfooterlines \centerbox{\startoverlay
+%D {\definedfont[Mono at 150pt]%
+%D \startproperty[L1]\red TEST\stopproperty}
+%D {\definedfont[Mono at 150pt]%
+%D \startproperty[L2]\green TEST\stopproperty}
+%D \stopoverlay} \page
+%D
+%D \noheaderandfooterlines \centerbox{\startoverlay
+%D {\definedfont[Mono at 15pt]%
+%D \goto{\startproperty[L1]\red TEST\stopproperty}[CloseDocument]}
+%D {\definedfont[Mono at 15pt]%
+%D \goto{\startproperty[L2]\green TEST\stopproperty}[CloseDocument]}
+%D \stopoverlay} \page
+%D
+%D \startproperty[L1]
+%D level 1 \startproperty[L2]level 2 \stopproperty level 1
+%D \stopproperty
+%D
+%D \startproperty[L1]
+%D level 1 \page \startproperty[L2]level 2 \stopproperty level 1
+%D \stopproperty
+%D
+%D \stoptext
+
+%D Handy for tracing:
+
+\def\showlayoutcomponents
+ {\let\startlayoutcomponent\dostartlayoutcomponent
+ \let\stoplayoutcomponent \dostoplayoutcomponent}
+
+\def\dodefinelayoutcomponent#1#2%
+ {\doifelsenothing{#2}%
+ {\defineproperty[#1][\s!layer]}%
+ {\defineproperty[#1][\s!layer][\c!title=#2]}}
+
+\def\dostartlayoutcomponent#1#2%
+ {\doifelseproperty{#1}\donothing{\dodefinelayoutcomponent{#1}{#2}}%
+ \startproperty[#1]}
+
+\def\dostoplayoutcomponent
+ {\stopproperty}
+
+\let\startlayoutcomponent\gobbletwoarguments
+\let\stoplayoutcomponent \relax
+
\protect \endinput
+
+% \def\remaplayering
+% {\dodoubleargument\doremaplayering}
+%
+% \def\remaplayering[#1][#2]%
+% {\setvalue{\??lm#1}{#2}}
+%
+% \def\remappedlayering#1%
+% {\ifcsname\??lm#1\endcsname
+% \@EA\remappedlayering\csname\??lm#1\endcsname\else#1%
+% \fi}
+%
+% \def\startshowlayering#1#2%
+% {\ifshowlayering
+% \defineproperty[\remappedlayering{#1}][\s!layer][\c!titel=#2]%
+% \startproperty[\remappedlayering{#1}]%
+% \fi}
diff --git a/tex/context/base/prop-lay.tex b/tex/context/base/prop-lay.tex
deleted file mode 100644
index 2f6b2ef02..000000000
--- a/tex/context/base/prop-lay.tex
+++ /dev/null
@@ -1,105 +0,0 @@
-%D \module
-%D [ file=prop-lay,
-%D version=2003.04.20,
-%D title=\CONTEXT\ Property Macros,
-%D subtitle=Layers,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Property Macros / layers}
-
-%D Highly experimental, will probably change/evolve. Also, quite certainly
-%D we will no longer share code between mkii and mkiv.
-
-\unprotect
-
-%D Plugin:
-
-\loadmarkfile{prop-lay}
-
-% \currentlayerproperty
-% \checklayerproperty
-% \startlayerproperty
-% \stoplayerproperty
-% \domakelayerpropertylist
-
-%D shared interface, rest in mk files
-
-\setglobalsystemreference \rt!exec \v!HideLayer {hidelayer}
-\setglobalsystemreference \rt!exec \v!VideLayer {videlayer}
-\setglobalsystemreference \rt!exec \v!ToggleLayer {togglelayer}
-
-\setexecutecommandcheck {hidelayer} \domakelayerpropertylist
-\setexecutecommandcheck {videlayer} \domakelayerpropertylist
-\setexecutecommandcheck {togglelayer} \domakelayerpropertylist
-
-% \defineproperty [debugging] [\s!layer] [title=debugging]
-% \defineproperty [navigation] [\s!layer] [title=navigation]
-
-%D \starttext
-%D
-%D \setuppapersize[S4][S4]
-%D \setuplayout[middle]
-%D \setupcolors[state=start]
-%D \setupinteraction[state=start,color=,contrastcolor=]
-%D
-%D \defineproperty [L1] [layer] [title=layer 1]
-%D \defineproperty [L2] [layer] [title=layer 2]
-%D
-%D \button{HIDE L1}[HideLayer{L1}]
-%D \button{VIDE L1}[VideLayer{L1}]
-%D \button{TOGGLE L1}[ToggleLayer{L1}]
-%D
-%D \button{HIDE L2}[HideLayer{L2}]
-%D \button{VIDE L2}[VideLayer{L2}]
-%D \button{TOGGLE L2}[ToggleLayer{L2}]
-%D
-%D \noheaderandfooterlines \centerbox{\startoverlay
-%D {\definedfont[Mono at 150pt]%
-%D \startproperty[L1]\red TEST\stopproperty}
-%D {\definedfont[Mono at 150pt]%
-%D \startproperty[L2]\green TEST\stopproperty}
-%D \stopoverlay} \page
-%D
-%D \noheaderandfooterlines \centerbox{\startoverlay
-%D {\definedfont[Mono at 15pt]%
-%D \goto{\startproperty[L1]\red TEST\stopproperty}[CloseDocument]}
-%D {\definedfont[Mono at 15pt]%
-%D \goto{\startproperty[L2]\green TEST\stopproperty}[CloseDocument]}
-%D \stopoverlay} \page
-%D
-%D \startproperty[L1]
-%D level 1 \startproperty[L2]level 2 \stopproperty level 1
-%D \stopproperty
-%D
-%D \startproperty[L1]
-%D level 1 \page \startproperty[L2]level 2 \stopproperty level 1
-%D \stopproperty
-%D
-%D \stoptext
-
-\fetchruntimecommand \showlayoutcomponents {\f!propprefix\s!run}
-
-\protect \endinput
-
-% \def\remaplayering
-% {\dodoubleargument\doremaplayering}
-%
-% \def\remaplayering[#1][#2]%
-% {\setvalue{\??lm#1}{#2}}
-%
-% \def\remappedlayering#1%
-% {\ifcsname\??lm#1\endcsname
-% \@EA\remappedlayering\csname\??lm#1\endcsname\else#1%
-% \fi}
-%
-% \def\startshowlayering#1#2%
-% {\ifshowlayering
-% \defineproperty[\remappedlayering{#1}][\s!layer][\c!titel=#2]%
-% \startproperty[\remappedlayering{#1}]%
-% \fi}
diff --git a/tex/context/base/prop-mis.mkii b/tex/context/base/prop-mis.mkii
index 3b372546d..d8e9ab173 100644
--- a/tex/context/base/prop-mis.mkii
+++ b/tex/context/base/prop-mis.mkii
@@ -11,8 +11,41 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Property Macros / Miscelaneous}
+
+%D This module contains some code that has been in use in some
+%D private modules (p-*). These features depend on the fact
+%D that pdftex writes the page content as one stream.
+
+%D EXPERIMENTAL
+
\unprotect
+%D Stream based overprint and knockout:
+
+\defineproperty[\v!overprint][\s!overprint] [\c!method=\v!command]
+\defineproperty[\v!knockout] [\s!overprint] [\c!method=\v!command]
+
+%D Negation.
+
+\defineproperty [\v!negative] [\s!negative] [\c!method=\v!command]
+\defineproperty [\v!positive] [\s!negative] [\c!method=\v!command]
+
+%D Special font effects.
+
+\setupproperty
+ [\s!effect]
+ [\c!rulethickness=\zeropoint,
+ \c!stretch=0]
+
+\defineproperty [\v!inner] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!outer] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!both] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!normal] [\s!effect]
+\defineproperty [\v!hidden] [\s!effect]
+
+\defineproperty [\v!stretch] [\s!effect] [\c!stretch=1]
+
%D Overprint cum suis.
\definepropertyhandler \v!overprint {\dostartoverprint}
@@ -110,6 +143,7 @@
\definepropertyhandler \v!outer {1}
\definepropertyhandler \v!both {2}
\definepropertyhandler \v!hidden {3}
+\definepropertyhandler \v!stretch{0}
\def\effectpropertydata#1%
{{\propertyhandler{#1}}%
diff --git a/tex/context/base/prop-mis.mkiv b/tex/context/base/prop-mis.mkiv
index ee292155e..623b10f13 100644
--- a/tex/context/base/prop-mis.mkiv
+++ b/tex/context/base/prop-mis.mkiv
@@ -11,8 +11,41 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt Property Macros / Miscelaneous}
+
+%D This module contains some code that has been in use in some
+%D private modules (p-*). These features depend on the fact
+%D that pdftex writes the page content as one stream.
+
+%D EXPERIMENTAL
+
\unprotect
+%D Stream based overprint and knockout:
+
+\defineproperty[\v!overprint][\s!overprint] [\c!method=\v!command]
+\defineproperty[\v!knockout] [\s!overprint] [\c!method=\v!command]
+
+%D Negation.
+
+\defineproperty [\v!negative] [\s!negative] [\c!method=\v!command]
+\defineproperty [\v!positive] [\s!negative] [\c!method=\v!command]
+
+%D Special font effects.
+
+\setupproperty
+ [\s!effect]
+ [\c!rulethickness=\zeropoint,
+ \c!stretch=0]
+
+\defineproperty [\v!inner] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!outer] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!both] [\s!effect] [\c!rulethickness=.25pt]
+\defineproperty [\v!normal] [\s!effect]
+\defineproperty [\v!hidden] [\s!effect]
+
+\defineproperty [\v!stretch] [\s!effect] [\c!stretch=1]
+
%D Overprint cum suis.
\definepropertyhandler \v!overprint {\dotriggeroverprint\v!overprint}
@@ -39,6 +72,7 @@
\definepropertyhandler \v!outer {\mktriggereffect\v!outer }
\definepropertyhandler \v!both {\mktriggereffect\v!both }
\definepropertyhandler \v!hidden {\mktriggereffect\v!hidden}
+\definepropertyhandler \v!stretch{\mktriggereffect\v!normal}
\def\starteffectproperty{\mktriggereffect\currentproperty}
\def\stopeffectproperty {\mktriggereffect\v!normal }
diff --git a/tex/context/base/prop-mis.tex b/tex/context/base/prop-mis.tex
deleted file mode 100644
index d78e0c584..000000000
--- a/tex/context/base/prop-mis.tex
+++ /dev/null
@@ -1,53 +0,0 @@
-%D \module
-%D [ file=prop-mis,
-%D version=2004.05.29, % some code moved from private modules
-%D title=\CONTEXT\ Property Macros,
-%D subtitle=Miscelaneous,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Property Macros / initialization}
-
-%D This module contains some code that has been in use in some
-%D private modules (p-*). These features depend on the fact
-%D that pdftex writes the page content as one stream.
-
-%D EXPERIMENTAL
-
-\unprotect
-
-%D Stream based overprint and knockout:
-
-\defineproperty[\v!overprint][\s!overprint] [\c!method=\v!command]
-\defineproperty[\v!knockout] [\s!overprint] [\c!method=\v!command]
-
-%D Negation.
-
-\defineproperty [\v!negative] [\s!negative] [\c!method=\v!command]
-\defineproperty [\v!positive] [\s!negative] [\c!method=\v!command]
-
-%D Special font effects.
-
-\setupproperty
- [\s!effect]
- [\c!rulethickness=\zeropoint,
- \c!stretch=0]
-
-\defineproperty [\v!inner] [\s!effect] [\c!rulethickness=.25pt]
-\defineproperty [\v!outer] [\s!effect] [\c!rulethickness=.25pt]
-\defineproperty [\v!both] [\s!effect] [\c!rulethickness=.25pt]
-\defineproperty [\v!normal] [\s!effect]
-\defineproperty [\v!hidden] [\s!effect]
-
-\defineproperty [\v!stretch] [\s!effect] [\c!stretch=1]
-
-%D Plugin:
-
-\loadmarkfile{prop-mis}
-
-\protect \endinput
diff --git a/tex/context/base/prop-run.tex b/tex/context/base/prop-run.tex
deleted file mode 100644
index 4eb853b42..000000000
--- a/tex/context/base/prop-run.tex
+++ /dev/null
@@ -1,39 +0,0 @@
-%D \module
-%D [ file=prop-run,
-%D version=2003.04.20,
-%D title=\CONTEXT\ Property Macros,
-%D subtitle=Runtime Macros,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\doglobal\newif\ifshowcomponents
-
-\gdef\showlayoutcomponents
- {\showcomponentstrue}
-
-% By postponing loading of the next two macro's till their usage, we
-% don't put a burden on the system when they are not used.
-
-\gdef\startlayoutcomponent#1#2%
- {\ifshowcomponents
- \doifelseproperty{#1}
- \donothing
- {\doifelsenothing{#2}%
- {\defineproperty[#1][\s!layer]}% [\c!title=#1]
- {\defineproperty[#1][\s!layer][\c!title=#2]}}%
- \startproperty[#1]%
- \fi}
-
-\gdef\stoplayoutcomponent
- {\ifshowcomponents
- \stopproperty
- \fi}
-
-\protect \endinput
diff --git a/tex/context/base/regi-ini.lua b/tex/context/base/regi-ini.lua
index 72e93e67d..04b93db35 100644
--- a/tex/context/base/regi-ini.lua
+++ b/tex/context/base/regi-ini.lua
@@ -6,59 +6,60 @@ if not modules then modules = { } end modules ['regi-ini'] = {
license = "see context related readme files"
}
+local utf = unicode.utf8
+local char, utfchar = string.char, utf.char
+local texsprint = tex.sprint
+
+local ctxcatcodes = tex.ctxcatcodes
+
--[[ldx--
<p>Regimes take care of converting the input characters into
<l n='utf'/> sequences. The conversion tables are loaded at
runtime.</p>
--ldx]]--
-regimes = regimes or { }
-regimes.data = regimes.data or { }
-regimes.utf = regimes.utf or { }
-regimes.context = regimes.context or { }
+regimes = regimes or { }
+regimes.data = regimes.data or { }
+regimes.utf = regimes.utf or { }
+regimes.synonyms = regimes.synonyms or { }
-local char, utfchar = string.char, unicode.utf8.char
+storage.register("regimes/synonyms", regimes.synonyms, "regimes.synonyms")
-- setmetatable(regimes.data,_empty_table_)
-regimes.currentregime = ""
+regimes.currentregime = "utf"
--[[ldx--
<p>We will hook regime handling code into the input methods.</p>
--ldx]]--
-input = input or { }
-input.filters = input.filters or { }
-
function regimes.number(n)
if type(n) == "string" then return tonumber(n,16) else return n end
end
-function regimes.define(c) -- is this used at all?
- local r, u, s = c.regime, c.unicodeslot, c.slot
- regimes.data[r] = regimes.data[r] or { }
- if s then
- if u then
- regimes.data[r][regimes.number(s)] = regimes.number(u)
- else
- regimes.data[r][regimes.number(s)] = 0
- end
- else
- logs.report("regime","unknown vector %s/%s",r,s) -- ctx.statusmessage
- end
+function regimes.setsynonym(synonym,target)
+ regimes.synonyms[synonym] = target
+end
+
+function regimes.truename(regime)
+ texsprint(ctxcatcodes,(regime and regimes.synonyms[synonym] or regime) or regimes.currentregime)
end
function regimes.load(regime)
- environment.loadluafile("regi-"..regime, 1.001)
- if regimes.data[regime] then
- regimes.utf[regime] = { }
- for k,v in pairs(regimes.data[regime]) do
- regimes.utf[regime][char(k)] = utfchar(v)
+ regime = regimes.synonyms[regime] or regime
+ if not regimes.data[regime] then
+ environment.loadluafile("regi-"..regime, 1.001)
+ if regimes.data[regime] then
+ regimes.utf[regime] = { }
+ for k,v in pairs(regimes.data[regime]) do
+ regimes.utf[regime][char(k)] = utfchar(v)
+ end
end
end
end
function regimes.translate(line,regime)
+ regime = regimes.synonyms[regime] or regime
if regime and line then
local rur = regimes.utf[regime]
if rur then
@@ -69,44 +70,19 @@ function regimes.translate(line,regime)
end
function regimes.enable(regime)
+ regime = regimes.synonyms[regime] or regime
if regimes.data[regime] then
regimes.currentregime = regime
local translate = regimes.translate
- input.filters.dynamic_translator = function(s)
+ resolvers.install_text_filter('input',function(s)
return translate(s,regime)
- end
+ end)
else
regimes.disable()
end
end
function regimes.disable()
- regimes.currentregime = ""
- input.filters.dynamic_translator = nil
-end
-
-function input.filters.frozen_translator(regime)
- return function(s)
- return regimes.translate(s,regime)
- end
-end
-
---[[ldx--
-<p>The following code is rather <l n='context'/> specific.</p>
---ldx]]--
-
-function regimes.context.show(regime)
- local flush, tc = tex.sprint, tex.ctxcatcodes
- local r = regimes.data[regime]
- if r then
- flush(tc, "\\starttabulate[|rT|T|rT|lT|lT|lT|]")
- for k, v in ipairs(r) do
- flush(tc, string.format("\\NC %s\\NC\\getvalue{%s}\\NC %s\\NC %s\\NC %s\\NC %s\\NC\\NR", k,
- characters.contextname(v), characters.hexindex(v), characters.contextname(v),
- characters.category(v), characters.description(v)))
- end
- flush(tc, "\\stoptabulate")
- else
- flush(tc, "unknown regime " .. regime)
- end
+ regimes.currentregime = "utf"
+ resolvers.install_text_filter('input',nil)
end
diff --git a/tex/context/base/regi-ini.mkii b/tex/context/base/regi-ini.mkii
index 538db3bcf..9ba567145 100644
--- a/tex/context/base/regi-ini.mkii
+++ b/tex/context/base/regi-ini.mkii
@@ -13,51 +13,25 @@
\unprotect
-%D Plugs into the common interface.
-
-\beginOLDTEX
-
- \def\mkloadregime#1%
- {\makeshortfilename[\truefilename{\f!regimeprefix#1}]%
- \startreadingfile
- \readsysfile\shortfilename
- {\showmessage\m!regimes2{#1}}
- {\showmessage\m!regimes3{#1}}%
- \stopreadingfile}
-
- \def\mkenableregime#1%
- {\the\executeifdefined{\@reg@#1}\emptytoks}
-
- \def\mkwalkregime#1%
- {\the\executeifdefined{\@reg@\currentregime}\emptytoks}
-
- \def\mkautosetregime#1#2%
- {\ifnum#2>127
- \expanded{\defineactivetoken #2 \@EA\noexpand\csname#1\endcsname}%
- \fi}
+%D Remark: regimes accumulate, so there is no explicit reset in
+%D mkii mode.
-\endOLDTEX
+%D Variables.
-\beginXETEX
+\def\@reg@{@r@eg@} % regime prefix
- \let\mkloadregime \gobbleoneargument
- \let\mkenableregime \gobbleoneargument
- \let\mkwalkregime \gobbleoneargument
- \let\mkautosetregime\gobbletwoarguments
+%D \macros
+%D {currentregime}
- % \def\mkenableregime#1%
- % {\XeTeXinputencoding "#1"\relax}
+\let\currentregime\empty
+\let\defaultregime\s!default
- \def\mkenableregime#1%
- {\doifelse{#1}{utf}%
- {\writestatus\m!regimes{mapping utf to utf-8}%
- \XeTeXinputencoding{utf-8}}
- {\XeTeXinputencoding{#1}}}
+%D Some low level inheritance stuff (mkii).
-\endXETEX
-
-%D Remark: regimes accumulate, so there is no explicit reset in
-%D mkii mode.
+\def\doautosetregime#1#2%
+ {\ifnum#2>127
+ \expanded{\defineactivetoken #2 \@EA\noexpand\csname#1\endcsname}%
+ \fi}
%D \macros
%D {startregime}
@@ -153,27 +127,104 @@
{\setregimetoks
\regimetoks\expandafter{\the\regimetoks\defineactivecharacter#1 {#2}}}
-% D This is kind of obsolete (replaced by previous code).
-%
-% \def\definetoken #1 % #1 = rawtoken or number
-% {\doifnumberelse{\string#1}
-% {\expanded{\dodefinetoken{\rawcharacter{#1}}}}
-% {\expanded{\dodefinetoken{\string#1}}}}
-%
-% \def\dodefinetoken#1#2%
-% {\defineactivecharacter#1 {\dohandletoken{#1}} %
-% \setvalue{\@reg@:t:\currentregime#1}{#2}}
-%
-% \def\dohandletoken#1%
-% {\csname\ifcsname \@reg@:t:\currentregime#1\endcsname % regi-def sets the defaults
-% \@reg@:t:\currentregime\else\defaultregime\fi#1\endcsname}
-
-%D Preloading:
-
-\beginOLDTEX
+%D \macros
+%D {defineregimesynonym,trueregimename}
+
+\def\defineregimesynonym
+ {\dodoubleargument\dodefineregimesynonym}
+
+\def\dodefineregimesynonym[#1][#2]%
+ {\setevalue{\@reg@:s:#1}{#2}}
+
+\def\trueregimename#1%
+ {\executeifdefined{\@reg@:s:#1}{#1}}
+
+%D \macros
+%D {useregime}
+
+\def\useregime[#1]%
+ {\processcommalist[#1]\douseregime}
+
+\def\douseregime#1%
+ {\doifundefined{\c!file\f!regimeprefix#1}%
+ {\letgvalue{\c!file\f!regimeprefix#1}\empty
+ \makeshortfilename[\truefilename{\f!regimeprefix#1}]%
+ \startreadingfile
+ \readsysfile\shortfilename
+ {\showmessage\m!regimes2{#1}}
+ {\showmessage\m!regimes3{#1}}%
+ \stopreadingfile}}
+
+%D \macros
+%D {enableregime,disableregime}
+
+\let\enabledregime\empty
+
+\def\enableregime[#1]%
+ {\edef\currentregime{\trueregimename{#1}}%
+ \doifelsenothing\currentregime
+ {\disableregime}
+ {\douseregime\currentregime
+ \the\executeifdefined{\@reg@\currentregime}\emptytoks}}
+
+\def\disableregime
+ {\let\currentregime\empty}
+
+%D \macros
+%D {protectregime, settoletterunlessactive, settocodeunlessactive}
+%D
+%D The next boolean is used later on to prevent unwanted
+%D catcode changes. Use it with care.
+
+\newif\ifprotectregime \protectregimetrue
+
+\def\settoletterunlessactive#1%
+ {\ifprotectregime\ifnum\catcode#1=\active\else
+ \catcode#1\@@letter
+ \fi\else
+ \catcode#1\@@letter
+ \fi}
+
+\def\settootherunlessactive#1%
+ {\ifprotectregime\ifnum\catcode#1=\active\else
+ \catcode#1=\@@other
+ \fi\else
+ \catcode#1=\@@other
+ \fi}
+
+\def\settocodeunlessactive#1#2%
+ {\ifprotectregime\ifnum\catcode#1=\active\else
+ \catcode#1=#2\relax
+ \fi\else
+ \catcode#1=#2\relax
+ \fi}
+
+%D Sort related:
+
+\def\dowalkregime#1%
+ {\the\executeifdefined{\@reg@#1}\emptytoks}
+
+%D Simplify matters for \XETEX.
+
+\ifnum\texengine=\xetexengine
+
+ \def\enableregime[#1]%
+ {\doifelse{#1}{utf}%
+ {\writestatus\m!regimes{mapping utf to utf-8}%
+ \XeTeXinputencoding{utf-8}}
+ {\XeTeXinputencoding{#1}}}
+
+ \def\disableregime
+ {\XeTeXinputencoding{utf-8}}
+
+ \def\loadregime[#1]{}
+ \let\walkregime \gobbleoneargument
+ \let\doautosetregime \gobbletwoarguments
+
+\else
\useregime[def,uni,utf] % we load the rest runtime
-\endOLDTEX
+\fi
\protect \endinput
diff --git a/tex/context/base/regi-ini.mkiv b/tex/context/base/regi-ini.mkiv
index 763903fa1..5a3be77a2 100644
--- a/tex/context/base/regi-ini.mkiv
+++ b/tex/context/base/regi-ini.mkiv
@@ -1,7 +1,7 @@
%D \module
-%D [ file=char-reg,
+%D [ file=regi-ini,
%D version=2005.04.25,
-%D title=\CONTEXT\ Lua Macros,
+%D title=\CONTEXT\ Regime Macros,
%D subtitle=Regime Support,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -17,25 +17,39 @@
\registerctxluafile{regi-ini}{1.001}
-\def\mkloadregime #1{\ctxlua{regimes.load("#1")}}
-\def\mkenableregime #1{\ctxlua{regimes.enable("#1")}}
-\def\mkdisableregime {\ctxlua{regimes.disable()}}
-\def\mkshowregime #1{\ctxlua{regimes.context.show("#1")}}
+%D \macros
+%D {currentregime}
-% hm, this kind of disables regimes .. too tricky
-%
-% \appendtoks
-% \pushmacro\currentregime
-% \disableregime
-% \to \everystartreadingfile
+\def\currentregime{utf}
-% \appendtoks
-% \popmacro\currentregime
-% \enableregime[\currentregime]%
-% \to \everystopreadingfile
+%D \macros
+%D {defineregimesynonym,trueregimename}
-\protect \endinput
+\def\defineregimesynonym
+ {\dodoubleargument\dodefineregimesynonym}
+
+\def\dodefineregimesynonym[#1][#2]%
+ {\ctxlua{regimes.setsynonym("#1","#2")}}
+
+\def\trueregimename#1%
+ {\ctxlua{regimes.truename("#1")}}
+
+%D \macros
+%D {useregime}
+
+\def\useregime[#1]%
+ {\processcommalist[#1]\douseregime}
-% \starttext
-% \showregimetable{cp1250}
-% \stoptext
+\def\douseregime#1%
+ {\ctxlua{regimes.load("#1")}}
+
+%D \macros
+%D {enableregime,disableregime}
+
+\def\enableregime[#1]%
+ {\edef\currentregime{\ctxlua{regimes.load("#1") regimes.enable("#1") regimes.truename()}}}
+
+\def\disableregime
+ {\edef\currentregime{\ctxlua{regimes.disable()}}}
+
+\protect \endinput
diff --git a/tex/context/base/regi-ini.tex b/tex/context/base/regi-ini.tex
deleted file mode 100644
index 42bbf9718..000000000
--- a/tex/context/base/regi-ini.tex
+++ /dev/null
@@ -1,182 +0,0 @@
-%D \module
-%D [ file=regi-ini,
-%D version=2000.12.27, % 1998.12.03,
-%D title=\CONTEXT\ Regime Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-%D Messages (to be translated).
-
-\startmessages dutch library: regimes
- title: regime
- 1: regime --
- 2: regime -- wordt geladen
- 3: onbekend regime --
-\stopmessages
-
-\startmessages english library: regimes
- title: regime
- 1: regime --
- 2: regime -- is loaded
- 3: unknown regime --
-\stopmessages
-
-\startmessages german library: regimes
- title: Kodierung
- 1: Kodierung --
- 2: Kodierung -- ist geladen
- 3: Unbekannte Kodierung --
-\stopmessages
-
-\startmessages czech library: regimes
- title: kodovani
- 1: kodovani --
- 2: je nacteno kodovani --
- 3: nezname kodovani --
-\stopmessages
-
-\startmessages italian library: regimes
- title: codifica
- 1: codifica --
- 2: codifica -- caricata
- 3: codifica sconosciuta --
-\stopmessages
-
-\startmessages norwegian library: regimes
- title: koding
- 1: koding --
- 2: koding -- er lest inn
- 3: ukjent koding --
-\stopmessages
-
-\startmessages romanian library: regimes
- title: codificari
- 1: codificarea --
- 2: codificarea -- este Encarcata
- 3: codificarea -- este necunoscuta
-\stopmessages
-
-\startmessages french library: regimes
- title: encodage
- 1: encodage --
- 2: l'encodage -- est chargé
- 3: encodage -- inconnu
-\stopmessages
-
-%D Variables.
-
-\def\@reg@{@r@eg@} % regime prefix
-
-%D \macros
-%D {currentregime}
-
-\let\currentregime\empty
-\let\defaultregime\s!default
-
-%D Plugin interface.
-
-\let\mkloadregime \gobbleoneargument
-\let\mkenableregime \gobbleoneargument
-\let\mkdisableregime\relax
-\let\mkshowregime \gobbleoneargument
-\let\mkwalkregime \gobbleoneargument
-\let\mkautosetregime\gobbletwoarguments
-
-%D Some low level inheritance stuff (mkii).
-
-\def\doautosetregime{\mkautosetregime}
-
-%D \macros
-%D {defineregimesynonym,trueregimename}
-
-\def\defineregimesynonym
- {\dodoubleargument\dodefineregimesynonym}
-
-\def\dodefineregimesynonym[#1][#2]%
- {\setevalue{\@reg@:s:#1}{#2}}
-
-\def\trueregimename#1%
- {\executeifdefined{\@reg@:s:#1}{#1}}
-
-%D \macros
-%D {useregime}
-
-\def\useregime[#1]%
- {\processcommalist[#1]\douseregime}
-
-\def\douseregime#1%
- {\doifundefined{\c!file\f!regimeprefix#1}%
- {\letgvalue{\c!file\f!regimeprefix#1}\empty
- \mkloadregime{#1}}}
-
-%D \macros
-%D {enableregime,disableregime}
-
-\let\enabledregime\empty
-
-\def\enableregime[#1]%
- {\edef\currentregime{\trueregimename{#1}}%
- \doifelsenothing\currentregime
- {\disableregime}
- {\douseregime\currentregime
- \mkenableregime\currentregime}}
-
-\def\disableregime
- {\let\currentregime\empty
- \mkdisableregime}
-
-%D \macros
-%D {protectregime, settoletterunlessactive, settocodeunlessactive}
-%D
-%D The next boolean is used later on to prevent unwanted
-%D catcode changes. Use it with care.
-
-\newif\ifprotectregime \protectregimetrue
-
-\def\settoletterunlessactive#1%
- {\ifprotectregime\ifnum\catcode#1=\active\else
- \catcode#1\@@letter
- \fi\else
- \catcode#1\@@letter
- \fi}
-
-\def\settootherunlessactive#1%
- {\ifprotectregime\ifnum\catcode#1=\active\else
- \catcode#1=\@@other
- \fi\else
- \catcode#1=\@@other
- \fi}
-
-\def\settocodeunlessactive#1#2%
- {\ifprotectregime\ifnum\catcode#1=\active\else
- \catcode#1=#2\relax
- \fi\else
- \catcode#1=#2\relax
- \fi}
-
-%D Sort related:
-
-\def\dowalkregime{\mkwalkregime} % #1
-
-%D \macros
-%D {showregime}
-
-\def\showregime
- {\dosingleempty\doshowregime}
-
-\def\doshowregime[#1]%
- {\mkshowregime{#1}}
-
-%D Plugins.
-
-\loadmarkfile{regi-ini}
-
-\protect \endinput
diff --git a/tex/context/base/regi-syn.tex b/tex/context/base/regi-syn.tex
index b29c06775..7a8a9c146 100644
--- a/tex/context/base/regi-syn.tex
+++ b/tex/context/base/regi-syn.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Regime Macros (synonyms)}
+\writestatus{loading}{ConTeXt Regime Macros / Synonyms}
\unprotect
diff --git a/tex/context/base/regi-utf.tex b/tex/context/base/regi-utf.tex
index 2662c0017..5b30e85ee 100644
--- a/tex/context/base/regi-utf.tex
+++ b/tex/context/base/regi-utf.tex
@@ -11,6 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\ifnum\texengine>\pdftexengine
+ \endinput
+\fi
+
%D This regime activates the characters $>192$ and let them
%D handle \UTF\ encoded content streams. This regime runs on
%D top of the \type {unic} modules. We use an active inspector
@@ -29,14 +33,6 @@
% Ýýÿ
% ß
-\beginXETEX
- \expandafter \endinput
-\endXETEX
-
-\beginLUATEX
- \expandafter \endinput
-\endLUATEX
-
\unprotect
\startregime[utf]
diff --git a/tex/context/base/s-fnt-01.tex b/tex/context/base/s-fnt-01.tex
index a0ff16a22..69c8efab9 100644
--- a/tex/context/base/s-fnt-01.tex
+++ b/tex/context/base/s-fnt-01.tex
@@ -1,5 +1,5 @@
%D \module
-%D [ file=s-tnf-01,
+%D [ file=s-fnt-01,
%D version=2001.08.22,
%D title=\CONTEXT\ Style File,
%D subtitle=Font Environment 1,
@@ -12,7 +12,7 @@
%C details.
%D This file is used by the \type {texfont.pl} installation
-%D script.
+%D script. It is of no use for \MKIV.
%D Modes: compact
diff --git a/tex/context/base/s-fnt-10.tex b/tex/context/base/s-fnt-10.tex
index 86fffd7b6..95e9282b8 100644
--- a/tex/context/base/s-fnt-10.tex
+++ b/tex/context/base/s-fnt-10.tex
@@ -1,6 +1,102 @@
-% engine=luatex
+%D \module
+%D [ file=s-fnt-01,
+%D version=2006.10.10, % guess
+%D title=\CONTEXT\ Style File,
+%D subtitle=Listing Glyphs in Large Fonts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-\ctxloadluafile{s-fnt-10}{}
+\startluacode
+local format, sprint = string.format, tex.sprint
+
+function fonts.otf.show_all()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata and tfmdata.shared then
+ local otfdata = tfmdata.shared.otfdata
+ if otfdata and otfdata.luatex then
+ local unicodes = otfdata.luatex.unicodes
+ sprint(tex.ctxcatcodes,format("\\starttabulate[|l|r|c|]"))
+ for i, name in ipairs(table.sortedkeys(unicodes)) do
+ local unicode = unicodes[name]
+ if unicode >= 0 then
+ sprint(tex.ctxcatcodes,format("\\NC %s \\NC %s \\NC \\char%s \\NC\\NR",name,unicode,unicode))
+ end
+ end
+ sprint(tex.ctxcatcodes,format("\\stoptabulate"))
+ end
+ end
+end
+
+function fonts.show_all()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ local chars = tfmdata.characters
+ local descs = tfmdata.descriptions or { }
+ local data = characters.data
+ sprint(tex.ctxcatcodes,format("\\setuptabulate[header=repeat]"))
+ sprint(tex.ctxcatcodes,format("\\starttabulatehead"))
+ sprint(tex.ctxcatcodes,"\\NC\\bf unicode\\NC\\bf visual\\NC\\bf index\\NC\\bf glyph\\NC\\bf adobe\\NC\\bf context\\NC\\NR")
+ sprint(tex.ctxcatcodes,"\\HL")
+ sprint(tex.ctxcatcodes,format("\\stoptabulatehead"))
+ sprint(tex.ctxcatcodes,format("\\starttabulate[|l|c|l|p|p|p|]"))
+ for k, unicode in ipairs(table.sortedkeys(chars)) do
+ if unicode >= 0 then
+ local chr, des, dat = chars[unicode], descs[unicode], data[unicode]
+ local index = chr.index or 0
+ local cname = (dat and dat.contextname) or ""
+ local aname = (dat and dat.adobename) or ""
+ local gname = (des and des.name) or ""
+ local mname = dat and dat.mathname
+ if type(mname) ~= "string" then
+ mname = ""
+ end
+ local mspec = dat and dat.mathspec
+ if mspec then
+ for m=1,#mspec do
+ local n = mspec[m].name
+ if n then
+ if mname == "" then
+ mname = n
+ else
+ mname = mname .. " " .. n
+ end
+ end
+ end
+ end
+ if mname ~= "" then
+ mname = "m: " .. mname
+ if cname ~= "" then
+ cname = cname .. " " .. mname
+ else
+ cname = mname
+ end
+ end
+ sprint(tex.ctxcatcodes,format("\\NC\\tttf U+%05X\\NC\\char%s\\NC\\tttf %05X\\NC\\tttf %s\\NC\\tttf %s\\NC\\tttf %s\\NC\\NR",unicode,unicode,index,gname,aname,cname))
+ end
+ end
+ sprint(tex.ctxcatcodes,format("\\stoptabulate"))
+ else
+ sprint(tex.ctxcatcodes,"problems")
+ end
+end
+
+function fonts.show_glyphs()
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ local chars = tfmdata.characters
+ for k, v in ipairs(table.sortedkeys(chars)) do
+ if v >=0 then
+ sprint(tex.ctxcatcodes,format("\\dontleavehmode{\\strut\\char%s}\\endgraf",v))
+ end
+ end
+ end
+end
+\stopluacode
\def\ShowCompleteFont#1#2#3%
{\bgroup
diff --git a/tex/context/base/s-fnt-11.tex b/tex/context/base/s-fnt-11.tex
new file mode 100644
index 000000000..8f855cc72
--- /dev/null
+++ b/tex/context/base/s-fnt-11.tex
@@ -0,0 +1,61 @@
+%D \module
+%D [ file=s-fnt-11,
+%D version=2006.02.01, % or so
+%D title=\CONTEXT\ Style File,
+%D subtitle=Listing Installed Fonts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This code usd to be in the kernel but since it's hardly used
+%D it's now a module.
+%D
+%D \starttyping
+%D \showinstalledfonts[officinasans.*][all]
+%D \showinstalledfonts[officinaserif.*][all]
+%D \showinstalledfonts[officina.*itc.*][all]
+%D
+%D \showinstalledfonts[officina.*itc.*][all,new]
+%D \stoptyping
+
+\startluacode
+function fonts.names.table(pattern,reload,all)
+ local t = fonts.names.list(pattern,reload)
+ if t then
+ tex.sprint(tex.ctxcatcodes,"\\start\\nonknuthmode\\starttabulate[|T|T|T|T|T|]")
+ tex.sprint(tex.ctxcatcodes,"\\NC hashname\\NC type\\NC fontname\\NC filename\\NC\\NR\\HL")
+ for v,tv in table.sortedpairs(t) do
+ local kind, name, file = tv[1], tv[2], tv[3]
+ if all or v == string.lower(name) then
+ if kind and name and file then
+ tex.sprint(tex.ctxcatcodes,string.format("\\NC %s\\NC %s\\NC %s\\NC %s\\NC\\NR",v,kind,name,file))
+ else
+ logs.report("font table", "skipping %s", v)
+ end
+ end
+ end
+ tex.sprint(tex.ctxcatcodes,"\\stoptabulate\\stop")
+ end
+end
+\stopluacode
+
+\unprotect
+
+\def\showinstalledfonts
+ {\dodoubleempty\doshowinstalledfonts}
+
+\def\doshowinstalledfonts[#1][#2]%
+ {\bgroup
+ \def\pattern{#1}%
+ \def\all{false}%
+ \def\reload{false}%
+ \doifnothing\pattern{\def\pattern{.*}}%
+ \processallactionsinset[#2][\v!new=>\def\reload{true},\v!all=>\def\all{true}]%
+ \ctxlua{fonts.names.table("#1",\reload,\all)}%
+ \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/s-fnt-20.tex b/tex/context/base/s-fnt-20.tex
new file mode 100644
index 000000000..a57c0ba47
--- /dev/null
+++ b/tex/context/base/s-fnt-20.tex
@@ -0,0 +1,140 @@
+%D \module
+%D [ file=s-fnt-20,
+%D version=2009.01.10,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Tracing Feature Application (1),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This file is used by Idris and me in the process of getting the
+%D best arabic fonts getting rendered best. As such it might change.
+
+% \setvariables
+% [otftracker]
+% [title=Reverse Chaining,
+% figure=test-003-volt.pdf,
+% font=husayni,
+% sample={ببب بببب ببببب بببببب}]
+
+\def\checkedfeature#1#2{\ifnum\featureattribute{#1}=\zerocount#2\else#1\fi}
+
+% we can consider adding a dir key to features
+
+\definefontfeature
+ [otftracker-default]
+ [default]
+ [mode=node]
+
+\definefontfeature
+ [otftracker-arabtype]
+ [mode=node,analyze=yes,
+ language=dflt,script=arab,ccmp=yes,
+ init=yes,medi=yes,fina=yes,isol=yes,
+ liga=yes,dlig=yes,rlig=yes,clig=yes,
+ mark=yes,mkmk=yes,kern=yes,curs=yes]
+
+% \definefontfeature
+% [otftracker-husayni]
+% [analyze=yes,mode=node,
+% language=dflt,script=arab,ccmp=yes,
+% init=yes,medi=yes,fina=yes,isol=yes,
+% calt=yes,
+% mark=yes,mkmk=yes,kern=yes,curs=yes]
+
+\definefontfeature
+ [otftracker-husayni]
+ [analyze=yes,mode=node,
+ language=dflt,script=arab,ccmp=no,
+ init=yes,medi=yes,fina=yes,
+ rlig=yes,
+ ccmp=yes,
+ ss01=yes, % full Allah, Muhammad, Allahumma
+ ss05=yes, % full Jiim stacking
+ ss09=yes, % full Haa stacking
+ ss10=yes, % partial dipped Miim
+ % ss11=yes, % full dipped Miim
+ ss13=yes, % full stacked Miim
+ ss15=yes, % full stacked Laam-on-Miim
+ ss17=yes, % full stacked Ayn-on-Miim
+ ss19=yes, % LM_im
+ ss24=yes,ss25=yes,ss26=yes, % BX, LH_im, full Yaa.final specials
+ ss27=yes, % partial thin Miim.final
+ ss31=yes, % partial Raa.final contexts
+ ss34=yes, % partial Raa.final contexts
+ ss35=yes, % full Kaaf contexts
+ ss36=yes, % full Laam contexts
+ ss37=yes, % Miim-Miim contexts
+ ss38=yes, % fancy thin Haa.medial-Miim.final
+ ss39=yes, % high and low Baa strings
+ ss40=yes, % diagonal entry
+ ss41=yes, % initial alternates
+ % js06=yes,js08=yes,js10=yes,js11=yes,js17=yes,
+ % ttwl=yes,
+ mark=yes,mkmk=yes,
+ kern=yes,curs=yes]
+
+\definefontfeature
+ [otftracker-simplenaskhi]
+ [analyze=yes,mode=node,
+ language=dflt,script=arab,
+ init=yes,medi=yes,fina=yes,calt=yes,
+ rlig=yes,liga=yes,dlig=yes,
+ mark=yes,mkmk=yes,curs=yes]
+
+\setvalue{otftracker-direction-arabtype}{-1}
+\setvalue{otftracker-direction-husayni}{-1}
+\setvalue{otftracker-direction-simplenaskhi}{-1}
+
+\setvariables
+ [otftracker]
+ [font=Serif,
+ features=\checkedfeature{otftracker-\getvariable{otftracker}{font}}{otftracker-default},
+ size=48pt,
+ figure=,
+ title=Feature Check,
+ sample=no sample,
+ direction=\executeifdefined{otftracker-direction-\getvariable{otftracker}{font}}{0},
+ set=\setups{otftracker}]
+
+\setuplayout
+ [topspace=1.5cm,
+ backspace=1.5cm,
+ width=middle,
+ height=middle,
+ header=1.5cm,
+ footer=1.5cm]
+
+\setuphead
+ [chapter]
+ [header=high,
+ number=no]
+
+\setupfootertexts
+ [chapter]
+
+\setupalign
+ [flushleft]
+
+\setupcolors
+ [state=start]
+
+\startsetups otftracker
+ \setupbodyfont[tt,10pt]
+ \starttext
+ \chapter{\getvariable{otftracker}{title}}
+ \doifsomething {\getvariable{otftracker}{figure}} {
+ \startlinecorrection
+ \externalfigure[\getvariable{otftracker}{figure}]
+ \stoplinecorrection
+ }
+ \showotfcomposition
+ {\getvariable{otftracker}{font}*\getvariable{otftracker}{features} at \getvariable{otftracker}{size}}
+ {\getvariable{otftracker}{direction}}
+ {\getvariable{otftracker}{sample}}
+ \stoptext
+\stopsetups
diff --git a/tex/context/base/s-fnt-21.tex b/tex/context/base/s-fnt-21.tex
new file mode 100644
index 000000000..dd8de398d
--- /dev/null
+++ b/tex/context/base/s-fnt-21.tex
@@ -0,0 +1,46 @@
+%D \module
+%D [ file=s-fnt-20,
+%D version=2009.01.10,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Tracing Feature Application (2),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This module is related to:
+
+\usemodule[fnt-20]
+
+\setvariables
+ [otftracker]
+ [set=\setups{araball}]
+
+\startsetups araball
+ \begingroup
+ \setupcolors[state=start]%
+ \enabletrackers[otf.analyzing]% beware, kind of global
+ \ruledhbox \bgroup
+ \definedfont[\getvariable{otftracker}{font}*\getvariable{otftracker}{features} at \getvariable{otftracker}{size}]%
+ \ifnum\getvariable{otftracker}{direction}<0 \textdir TRT\else\ifnum\getvariable{otftracker}{direction}>0 \textdir TLT\fi\fi\relax
+ \getvariable{otftracker}{sample}%
+ \egroup
+ \disabletrackers[otf.analyzing]%
+ \endgroup
+\stopsetups
+
+\def\ShowOtfTrackerSample#1%
+ {\doiffile{#1}
+ {\blank
+ \startlinecorrection
+ \vbox \bgroup
+ \forgetall
+ \setbox\scratchbox\hbox{\component #1 \relax}
+ \hbox{\copy\scratchbox\quad\lower\dp\scratchbox\hbox{\ruledhbox{\externalfigure[#1-volt.pdf][height=\htdp\scratchbox]}}}
+ \hbox{\strut\tttf#1}%
+ \egroup
+ \stoplinecorrection
+ \blank}}
diff --git a/tex/context/base/s-fnt-23.tex b/tex/context/base/s-fnt-23.tex
new file mode 100644
index 000000000..096c8fbf5
--- /dev/null
+++ b/tex/context/base/s-fnt-23.tex
@@ -0,0 +1,272 @@
+%D \module
+%D [ file=s-fnt-23,
+%D version=2009.03.04,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Tracing Feature Application (3),
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startluacode
+ local last_data = nil
+ local format = string.format
+ local function tpf(...)
+-- print("!!!!",...)
+ tex.print(tex.ctxcatcodes,format(...))
+ end
+ function fonts.otf.show_shape(n)
+ local tfmdata = fonts.ids[font.current()]
+ lastdata = tfmdata
+ local charnum = tonumber(n)
+ if not charnum then
+ charnum = tfmdata.unicodes[n]
+ end
+ local c = tfmdata.characters[charnum]
+ local d = tfmdata.descriptions[charnum]
+ if d then
+ local factor = (tfmdata.size/tfmdata.units)*((7200/7227)/65536)
+ local llx, lly, urx, ury = unpack(d.boundingbox)
+ llx, lly, urx, ury = llx*factor, lly*factor, urx*factor, ury*factor
+ local width, italic = (d.width or 0)*factor, (d.italic or 0)*factor
+ local top_accent, bot_accent = (d.top_accent or 0)*factor, (d.bot_accent or 0)*factor
+ local anchors, math = d.anchors, d.math
+ tpf("\\startMPcode")
+ tpf("pickup pencircle scaled .25bp ; ")
+ tpf('picture p ; p := image(draw textext.drt("\\gray\\char%s");); draw p ;',charnum)
+ tpf('draw (%s,%s)--(%s,%s)--(%s,%s)--(%s,%s)--cycle withcolor green ;',llx,lly,urx,lly,urx,ury,llx,ury)
+ tpf('draw (%s,%s)--(%s,%s) withcolor green ;',llx,0,urx,0)
+ tpf('draw boundingbox p withcolor .2white withpen pencircle scaled .065bp ;')
+ tpf("defaultscale := 0.05 ; ")
+ -- inefficient but non critical
+ local function slant_1(v,dx,dy,txt,xsign,ysign,loc,labloc)
+ if #v > 0 then
+ local l = { }
+ for kk, vv in ipairs(v) do
+ local h, k = vv.height, vv.kern
+ if h and k then
+ l[#l+1] = format("((%s,%s) shifted (%s,%s))",xsign*k*factor,ysign*h*factor,dx,dy)
+ end
+ end
+ tpf("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled .25) withcolor .5white;", xsign*v[1].kern*factor,lly,dx,dy,l[1])
+ tpf("draw laddered (%s) withcolor .5white ;",table.concat(l,".."))
+ tpf("draw ((%s,%s) shifted (%s,%s))--%s dashed (evenly scaled .25) withcolor .5white;", xsign*v[#v].kern*factor,ury,dx,dy,l[#l])
+ for k, v in ipairs(l) do
+ tpf("draw %s withcolor blue withpen pencircle scaled 1bp;",v)
+ end
+ end
+ end
+ local function slant_2(v,dx,dy,txt,xsign,ysign,loc,labloc)
+ if #v > 0 then
+ local l = { }
+ for kk, vv in ipairs(v) do
+ local h, k = vv.height, vv.kern
+ if h and k then
+ l[#l+1] = format("((%s,%s) shifted (%s,%s))",xsign*k*factor,ysign*h*factor,dx,dy)
+ end
+ end
+ if loc == "top" then
+ tpf('label.%s("\\type{%s}",%s shifted (0,-1bp)) ;',loc,txt,l[#l])
+ else
+ tpf('label.%s("\\type{%s}",%s shifted (0,2bp)) ;',loc,txt,l[1])
+ end
+ for kk, vv in ipairs(v) do
+ local h, k = vv.height, vv.kern
+ if h and k then
+ tpf('label.top("(%s,%s)",%s shifted (0,-2bp));',k,h,l[kk])
+ end
+ end
+ end
+ end
+ if math then
+ local kerns = math.kerns
+ if kerns then
+ for _, slant in ipairs { slant_1, slant_2 } do
+ for k,v in pairs(kerns) do
+ if k == "top_right" then
+ slant(v,width+italic,0,k,1,1,"top","ulft")
+ elseif k == "bottom_right" then
+ slant(v,width,0,k,1,1,"bot","lrt")
+ elseif k == "top_left" then
+ slant(v,0,0,k,-1,1,"top","ulft")
+ elseif k == "bottom_left" then
+ slant(v,0,0,k,-1,1,"bot","lrt")
+ end
+ end
+ end
+ end
+ end
+ local function show(x,y,txt)
+ local xx, yy = x*factor, y*factor
+ tpf("draw (%s,%s) withcolor blue withpen pencircle scaled 1bp;",xx,yy)
+ tpf('label.top("\\type{%s}",(%s,%s-2bp)) ;',txt,xx,yy)
+ tpf('label.bot("(%s,%s)",(%s,%s+2bp)) ;',x,y,xx,yy)
+ end
+ if anchors then
+ local a = anchors.baselig
+ if a then
+ for k, v in pairs(a) do
+ for kk, vv in ipairs(v) do
+ show(vv[1],vv[2],k .. ":" .. kk)
+ end
+ end
+ end
+ local a = anchors.mark
+ if a then
+ for k, v in pairs(a) do
+ show(v[1],v[2],k)
+ end
+ end
+ local a = anchors.basechar
+ if a then
+ for k, v in pairs(a) do
+ show(v[1],v[2],k)
+ end
+ end
+ local ba = anchors.centry
+ if a then
+ for k, v in pairs(a) do
+ show(v[1],v[2],k)
+ end
+ end
+ local a = anchors.cexit
+ if a then
+ for k, v in pairs(a) do
+ show(v[1],v[2],k)
+ end
+ end
+ end
+ if italic ~= 0 then
+ tpf('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width,ury,width,ury)
+ tpf('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width+italic,ury,width+italic,ury)
+ tpf('draw (%s,%s-1bp)--(%s,%s-1bp) withcolor blue;',width,ury,width+italic,ury)
+ tpf('label.lft("\\type{%s}",(%s+2bp,%s-1bp));',"italic",width,ury)
+ tpf('label.rt("%s",(%s-2bp,%s-1bp));',d.italic,width+italic,ury)
+ end
+ if top_accent ~= 0 then
+ tpf('draw (%s,%s+1bp)--(%s,%s-1bp) withcolor blue;',top_accent,ury,top_accent,ury)
+ tpf('label.bot("\\type{%s}",(%s,%s+1bp));',"top_accent",top_accent,ury)
+ tpf('label.top("%s",(%s,%s-1bp));',d.top_accent,top_accent,ury)
+ end
+ if bot_accent ~= 0 then
+ tpf('draw (%s,%s+1bp)--(%s,%s-1bp) withcolor blue;',bot_accent,lly,bot_accent,lly)
+ tpf('label.top("\\type{%s}",(%s,%s-1bp));',"bot_accent",top_accent,ury)
+ tpf('label.bot("%s",(%s,%s+1bp));',d.bot_accent,bot_accent,lly)
+ end
+ tpf('draw origin withcolor red withpen pencircle scaled 1bp;')
+ tpf("setbounds currentpicture to boundingbox currentpicture enlarged 1bp ;")
+ tpf("currentpicture := currentpicture scaled 8 ;")
+ tpf("\\stopMPcode")
+ elseif c then
+ local factor = (7200/7227)/65536
+ tpf("\\startMPcode")
+ tpf("pickup pencircle scaled .25bp ; ")
+ tpf('picture p ; p := image(draw textext.drt("\\gray\\char%s");); draw p ;',charnum)
+ tpf('draw boundingbox p withcolor .2white withpen pencircle scaled .065bp ;')
+ tpf("defaultscale := 0.05 ; ")
+ local italic, top_accent, bot_accent = (c.italic or 0)*factor, (c.top_accent or 0)*factor, (c.bot_accent or 0)*factor
+ local width, height, depth = (c.width or 0)*factor, (c.height or 0)*factor, (c.depth or 0)*factor
+ local ury = height
+ if italic ~= 0 then
+ tpf('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width,ury,width,ury)
+ tpf('draw (%s,%s-1bp)--(%s,%s-0.5bp) withcolor blue;',width+italic,ury,width+italic,ury)
+ tpf('draw (%s,%s-1bp)--(%s,%s-1bp) withcolor blue;',width,ury,width+italic,height)
+ tpf('label.lft("\\type{%s}",(%s+2bp,%s-1bp));',"italic",width,height)
+ tpf('label.rt("%6.3f bp",(%s-2bp,%s-1bp));',italic,width+italic,height)
+ end
+ if top_accent ~= 0 then
+ tpf('draw (%s,%s+1bp)--(%s,%s-1bp) withcolor blue;',top_accent,ury,top_accent,height)
+ tpf('label.bot("\\type{%s}",(%s,%s+1bp));',"top_accent",top_accent,height)
+ tpf('label.top("%6.3f bp",(%s,%s-1bp));',top_accent,top_accent,height)
+ end
+ if bot_accent ~= 0 then
+ tpf('draw (%s,%s+1bp)--(%s,%s-1bp) withcolor blue;',bot_accent,lly,bot_accent,height)
+ tpf('label.top("\\type{%s}",(%s,%s-1bp));',"bot_accent",top_accent,height)
+ tpf('label.bot("%6.3f bp",(%s,%s+1bp));',bot_accent,bot_accent,height)
+ end
+ tpf('draw origin withcolor red withpen pencircle scaled 1bp;')
+ tpf("setbounds currentpicture to boundingbox currentpicture enlarged 1bp ;")
+ tpf("currentpicture := currentpicture scaled 8 ;")
+ tpf("\\stopMPcode")
+ else
+ tpf("no such shape: %s",n)
+ end
+ end
+ function fonts.otf.show_all_shapes(start,stop)
+ local tfmdata = fonts.ids[font.current()]
+ lastdata = tfmdata
+ start, stop = start or "\\startTEXpage\\gobbleoneargument", stop or "\\stopTEXpage"
+ local unicodes, indices, descriptions = tfmdata.unicodes, tfmdata.indices, tfmdata.descriptions
+ for _, unicode in next, table.sortedkeys(descriptions) do
+ local d = descriptions[unicode]
+ local name = d.name
+ tpf("%s{%s}%%",start,unicode)
+ tpf("\\writestatus{glyph}{U+%04X -> %s}%%",unicode,name)
+ fonts.otf.show_shape(unicode)
+ tpf(stop)
+ end
+ end
+ function fonts.otf.show_shape_field(unicode,name)
+ local tfmdata = lastdata or fonts.ids[font.current()]
+ local d = tfmdata.descriptions[unicode]
+ if d then
+ if name == "unicode" then
+ tpf("U+%04X",unicode)
+ else
+ d = d[name]
+ if d then
+ tpf(d)
+ end
+ end
+ end
+ end
+\stopluacode
+
+\setupcolors
+ [state=start]
+
+\def\GetGlyphField#1#2%
+ {\ctxlua{fonts.otf.show_shape_field(#1,"#2")}}
+
+\def\StartShowGlyphShape#1%
+ {\startTEXpage
+ \nonknuthmode
+ \def\GlyphUnicode{#1}}
+
+\def\StopShowGlyphShape
+ {\par
+ \midaligned{\tttf\setstrut\strut\GetGlyphField\GlyphUnicode{unicode}: \GetGlyphField\GlyphUnicode{name}}%
+ \stopTEXpage}
+
+\def\ShowGlyphShape#1#2#3% name size glyph
+ {\begingroup
+ \definedfont[#1 at #2]%
+ \obeyMPboxdepth
+ \ctxlua{fonts.otf.show_shape("#3")}%
+ \endgroup}
+
+\def\ShowAllGlyphShapes#1#2% name size
+ {\begingroup
+ \nonknuthmode
+ \definedfont[#1 at #2]%
+ \ctxlua{fonts.otf.show_all_shapes("\\StartShowGlyphShape","\\StopShowGlyphShape")}%
+ \endgroup}
+
+\setupcolors
+ [state=start]
+
+\doifnotmode{demo}{\endinput}
+
+\starttext
+
+\startTEXpage \ShowGlyphShape{simplenaskhi}{100bp}{0x62A} \stopTEXpage
+\startTEXpage \ShowGlyphShape{simplenaskhi}{100bp}{0x2004} \stopTEXpage
+\startTEXpage \ShowGlyphShape{simplenaskhi}{100bp}{0xF0299} \stopTEXpage
+\startTEXpage \ShowGlyphShape{simplenaskhi}{100bp}{NameMe.1190} \stopTEXpage
+
+\ShowAllGlyphShapes{simplenaskhi}{100bp}
+
+\stoptext
diff --git a/tex/context/base/s-fnt-24.tex b/tex/context/base/s-fnt-24.tex
new file mode 100644
index 000000000..073588033
--- /dev/null
+++ b/tex/context/base/s-fnt-24.tex
@@ -0,0 +1,83 @@
+%D \module
+%D [ file=s-fnt-24,
+%D version=2009.02.06,
+%D title=\CONTEXT\ Style File,
+%D subtitle=CJK Glyph Combination Testing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\unprotect
+
+\def\ShowChineseCombiChar#1#2#3#4%
+ {\blank[small]
+ \dontleavehmode
+ \hbox\bgroup
+ \dontcomplain
+ \setstrut
+ \hbox to 7em{\ruledhbox{\char#1}\hskip.25em\type{+}\hskip.25em\ruledhbox{\char#2}\hskip.25em\type{=}\hskip.25em\ruledhbox{\char#1\char#2}\hss}\relax
+ \ruledvtop{\hsize1em\char#1\char#2}\relax
+ \hskip2em
+ \ruledvtop{\hsize.625em\char#1\char#2}\relax
+ \hskip2em
+ \ruledvtop{\hsize1.5em\char#1\char#2}\relax
+ \hskip2em
+ \type{#3 + #4}\relax
+ \egroup
+ \blank[small]}
+
+\startluacode
+local example = {
+ korean = 0x0AC00,
+ chinese = 0x04E55,
+ full_width_open = 0x03008,
+ full_width_close = 0x03009,
+ half_width_open = 0x02018,
+ half_width_close = 0x02019,
+ hyphen = 0x02026,
+ non_starter = 0x03005,
+ other = 0x0004D, -- M
+}
+
+function fonts.analyzers.cjktest(first,second)
+ for k, v in next, example do
+ if (not first or first == "") or first == k then
+ for kk, vv in next, example do
+ if (not second or second == "") or second == kk then
+ tex.sprint(tex.ctxcatcodes,string.format("\\ShowChineseCombiChar{%s}{%s}{%s}{%s}",v,vv,k,kk))
+ end
+ end
+ end
+ end
+end
+\stopluacode
+
+\def\ShowCombinationsKorean
+ {\dodoubleempty\doShowCombinationsKorean}
+
+\def\doShowCombinationsKorean[#1][#2]%
+ {\startpacked
+ \setscript[hangul]
+ \setupcolors[\c!state=\v!start]
+ \enabletrackers[cjk.analyzing]
+ \ctxlua{fonts.analyzers.cjktest("#1","#2")}\par % !
+ \disabletrackers[cjk.analyzing]
+ \stoppacked}
+
+\def\ShowCombinationsChinese
+ {\dodoubleempty\doShowCombinationsChinese}
+
+\def\doShowCombinationsChinese[#1][#2]%
+ {\startpacked
+ \setscript[hanzi]
+ \setupcolors[\c!state=\v!start]
+ \enabletrackers[cjk.analyzing]
+ \ctxlua{fonts.analyzers.cjktest("#1","#2")}\par % !
+ \disabletrackers[cjk.analyzing]
+ \stoppacked}
+
+\protect \endinput
diff --git a/tex/context/base/s-fnt-25.tex b/tex/context/base/s-fnt-25.tex
new file mode 100644
index 000000000..83a3ee586
--- /dev/null
+++ b/tex/context/base/s-fnt-25.tex
@@ -0,0 +1,162 @@
+%D \module
+%D [ file=s-fnt-25,
+%D version=2009.01.25,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Math Glyph Checking,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\def\showmathfontcharacters
+ {\dodoubleempty\doshowmathfontcharacters}
+
+\def\doshowmathfontcharacters[#1][#2]%
+ {\begingroup
+ \doifelsenothing{#1}
+ {\definedfont[MathRoman*math-text]}
+ {\definedfont[#1]}%
+ \doifelsenothing{#2}
+ {\ctxlua{document.showmathfont(font.current())}}
+ {\def\dodoshowmathfontcharacters##1{\ctxlua{document.showmathfont(font.current(),##1)}}%
+ \processcommalist[#2]\dodoshowmathfontcharacters}%
+ \endgroup}
+
+\def\startmathfontlist
+ {\startpacked}
+
+\def\stopmathfontlist
+ {\stoppacked}
+
+\def\startmathfontlistentry
+ {\blank
+ \begingroup}
+
+\def\stopmathfontlistentry
+ {\endgroup
+ \blank}
+
+\def\mathfontlistentryhexdectit#1#2#3%
+ {#1: \ruledhbox{\char#2}\enspace#3\par
+ \advance\leftskip 1em\relax}
+
+\def\mathfontlistentrywdhtdpic#1#2#3#4%
+ {width: #1, height: #2, depth: #3, italic: #4\par}
+
+\def\mathfontlistentrynext#1#2%
+ {#1~\ruledhbox{\char#2}}
+
+\def\mathfontlistentrynextlist#1%
+ {next: #1\par}
+
+\def\fontlistentryvariants#1#2%
+ {#1~\ruledhbox{\char#2}}
+
+\def\mathfontlistentryvariantslist#1%
+ {variants: #1\par}
+
+\def\mathfontlistentrynextvariantslist#1#2%
+ {next: #1 => variants: #2\par}
+
+\def\mathfontlistentryclassname#1#2%
+ {mathclass: #1, mathname: #2\par}
+
+\def\mathfontlistentrysymbol#1#2%
+ {mathsymbol: #1~\ruledhbox{\char#2}\par}
+
+\startluacode
+function document.showmathfont(id,slot)
+ local data = characters.data
+ local tfmdata = fonts.ids[id]
+ local characters = tfmdata.characters
+ local sorted = (slot and { slot }) or table.sortedkeys(characters)
+ local function report(...)
+ tex.sprint(tex.ctxcatcodes,string.format(...))
+ end
+ for _, s in next, sorted do
+ local char = characters[s]
+ if char then
+ local info = data[s]
+ local cnext, cvert_variants, choriz_variants = char.next, char.vert_variants, char.horiz_variants
+ report("\\startmathfontlistentry")
+ report("\\mathfontlistentryhexdectit{U+%05X}{%s}{%s}",s,s,string.lower(info.description or "no description, private to font"))
+ report("\\mathfontlistentrywdhtdpic{%s}{%s}{%s}{%s}",char.width or 0,char.height or 0,char.depth or 0,char.italic or 0)
+ if info.mathclass then
+ report("\\mathfontlistentryclassname{%s}{%s}",info.mathclass,info.mathname or "no name")
+ end
+ if info.mathspec then
+ for i=1,#info.mathspec do
+ report("\\mathfontlistentryclassname{%s}{%s}",info.mathspec[i].class,info.mathspec[i].name or "no name")
+ end
+ end
+ if info.mathsymbol then
+ report("\\mathfontlistentrysymbol{U+%05X}{%s}",info.mathsymbol,info.mathsymbol)
+ end
+ if cnext then
+ local t, done = { }, { }
+ while cnext do
+ if done[cnext] then
+ t[#t+1] = "CYCLE"
+ break
+ else
+ done[cnext] = true
+ t[#t+1] = string.format("\\mathfontlistentrynext{U+%05X}{%s}",cnext,cnext)
+ cnext = characters[cnext]
+ cvert_variants = cnext.vert_variants or cvert_variants
+ choriz_variants = cnext.horiz_variants or choriz_variants
+ if cnext then
+ cnext = cnext.next
+ end
+ end
+ end
+ cnext = t
+ end
+ if cvert_variants then
+ local t = { }
+ for k, v in next, cvert_variants do
+ t[#t+1] = string.format("\\fontlistentryvariants{U+%05X}{%s}",v.glyph,v.glyph)
+ end
+ cvert_variants = t
+ end
+ if choriz_variants then
+ local t = { }
+ for k, v in next, choriz_variants do
+ t[#t+1] = string.format("\\fontlistentryvariants{%s}",v.glyph)
+ end
+ choriz_variants = t
+ end
+ local cvariants = choriz_variants or cvert_variants
+ if cvariants and cnext then
+ report("\\mathfontlistentrynextvariantslist{%s}{%s}",table.concat(cnext," => "),table.concat(cvariants," => "))
+ else
+ if cnext then
+ report("\\mathfontlistentrynextlist{%s}",table.concat(cnext," => "))
+ end
+ if variants then
+ report("\\mathfontlistentryvariantslist{%s}",table.concat(cvariants," "))
+ end
+ end
+ report("\\stopmathfontlistentry")
+ end
+ end
+end
+\stopluacode
+
+\endinput
+
+\startbuffer mathtest
+ \begingroup\mm\mr\showmathfontcharacters\endgroup
+\stopbuffer
+
+\starttext
+ \usetypescript[cambria] \setupbodyfont[cambria, 12pt] \getbuffer[mathtest]
+ \usetypescript[lmvirtual] \setupbodyfont[lmvirtual,12pt] \getbuffer[mathtest]
+ \usetypescript[pxvirtual] \setupbodyfont[pxvirtual,12pt] \getbuffer[mathtest]
+ \usetypescript[txvirtual] \setupbodyfont[txvirtual,12pt] \getbuffer[mathtest]
+ \usetypescript[palatino] \setupbodyfont[palatino, 10pt] \getbuffer[mathtest]
+ \usetypescript[mathtimes] \setupbodyfont[mathtimes,12pt] \getbuffer[mathtest]
+\stoptext
+
diff --git a/tex/context/base/s-fnt-30.tex b/tex/context/base/s-fnt-30.tex
new file mode 100644
index 000000000..81b6c8d19
--- /dev/null
+++ b/tex/context/base/s-fnt-30.tex
@@ -0,0 +1,42 @@
+%D \module
+%D [ file=s-fnt-30,
+%D version=2006.05.10, % abou tthen, quite old already
+%D title=\CONTEXT\ Style File,
+%D subtitle=Showing Character Data,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\startluacode
+function document.show_character_data(n)
+ local n = characters.number(n)
+ local d = characters.data[n]
+ if d then
+ local function entry(label,name)
+ texsprint(tex.ctxcatcodes,format("\\NC %s\\NC %s\\NC\\NR",label,characters.valid(d[name])))
+ end
+ texsprint(tex.ctxcatcodes,"\\starttabulate[|Tl|Tl|]")
+ entry("unicode index" , "unicodeslot")
+ entry("context name" , "contextname")
+ entry("adobe name" , "adobename")
+ entry("category" , "category")
+ entry("description" , "description")
+ entry("uppercase code", "uccode")
+ entry("lowercase code", "lccode")
+ entry("specials" , "specials")
+ texsprint(tex.ctxcatcodes,"\\stoptabulate ")
+ end
+end
+\stopluacode
+
+\def\ShowCharacterData#1%
+ {\ctxlua{document.show_character_data(#1)}}
+
+% \ShowCharacterData{123}
+% \ShowCharacterData{0x7B}
+
+% \dostepwiserecurse{`A}{`Z}{1}{\ShowCharacterData{#1}}
diff --git a/tex/context/base/s-pre-60.tex b/tex/context/base/s-pre-60.tex
index bd6b6ae4f..89ddbbba4 100644
--- a/tex/context/base/s-pre-60.tex
+++ b/tex/context/base/s-pre-60.tex
@@ -45,7 +45,7 @@
[set=\setups{set-stepper},
nofsteps=50]
-\defineproperty[step:busy][layer][state=start]
+\defineproperty[step:busy][layer][state=start,global=no]
\definereference [SetupStepper] [JS(SetupStepper{step,\StepMaximum})]
\definereference [ResetStepper] [JS(ResetStepper)]
@@ -62,20 +62,36 @@
\def\NextStepLayer {step:\the\numexpr\StepCounter+1\relax}
\def\FirstStepLayer{step:1}
-\def\StartStep
- {\ifvmode
- \scratchskip\lastskip
- \vskip-\scratchskip
- \startproperty[\StepLayer]%
- \vskip\scratchskip
- \else
- \startproperty[\StepLayer]%
- \fi
- \ignorespaces}
-
-\def\StopStep
- {\removeunwantedspaces
- \stopproperty}
+\startmode[mkiv]
+
+ \def\StartStep
+ {\startproperty[\StepLayer]%
+ \ignorespaces}
+
+ \def\StopStep
+ {\removeunwantedspaces
+ \stopproperty}
+
+\stopmode
+
+\startnotmode[mkiv]
+
+ \def\StartStep
+ {\ifvmode
+ \scratchskip\lastskip
+ \vskip-\scratchskip
+ \startproperty[\StepLayer]%
+ \vskip\scratchskip
+ \else
+ \startproperty[\StepLayer]%
+ \fi
+ \ignorespaces}
+
+ \def\StopStep
+ {\removeunwantedspaces
+ \stopproperty}
+
+\stopnotmode
\def\StartSteps{\iftrialtypesetting\else\ResetStep\NextStep\StartStep\fi}
\def\StopSteps {\iftrialtypesetting\else\StopStep \PrevStep \fi}
diff --git a/tex/context/base/s-pre-61.tex b/tex/context/base/s-pre-61.tex
index c2040a0d9..216bb9a00 100644
--- a/tex/context/base/s-pre-61.tex
+++ b/tex/context/base/s-pre-61.tex
@@ -15,9 +15,13 @@
\usemodule[pre-60]
-\usetypescriptfile[type-ghz]
-
-\definetypeface[mainface][ss][sans][optima-nova][default][encoding=\defaultencoding]
+\doifmodeelse {mkiv} {
+ \usetypescriptfile[type-hgz]
+ \definetypeface[mainface][ss][sans][optima-nova][default]
+} {
+ \usetypescriptfile[type-ghz]
+ \definetypeface[mainface][ss][sans][optima-nova][default][encoding=\defaultencoding]
+}
\setupbodyfont[mainface,ss,18pt]
\setupinterlinespace[line=3.25ex]
@@ -168,9 +172,7 @@
style=\HeadFont]
\setupheadertexts
- [\doiftextelse{\placeheadtext[Topic]}
- {\placeheadtext[Topic]}
- {\placeheadtext[Nopic]}]
+ [\doiftextelse{\currentheadnumber}{\placeheadtext[Topic]}{\placeheadtext[Nopic]}]
[]
\setuppagenumbering
diff --git a/tex/context/base/s-pre-62.tex b/tex/context/base/s-pre-62.tex
index c3683cbfa..64bb3495b 100644
--- a/tex/context/base/s-pre-62.tex
+++ b/tex/context/base/s-pre-62.tex
@@ -207,4 +207,22 @@
\def\TitlePage {\doTitlePage\TitleFont\relax}
\def\SubTitlePage{\doTitlePage\TitleFont\SubTitleFont}
-\endinput
+\doifnotmode{demo} {\endinput}
+
+\starttext
+
+\StartTitlePage
+bla\\bla bla\\bla
+\StopTitlePage
+
+\StartRemark {Bla Bla}
+ Bla Bla Bla. \FlushStep
+ Bla Bla Bla. \FlushStep
+\StopRemark
+
+\StartRemark {Bla Bla}
+ Bla Bla Bla. \FlushStep
+ Bla Bla Bla. \FlushStep
+\StopRemark
+
+\stoptext
diff --git a/tex/context/base/s-pre-66.tex b/tex/context/base/s-pre-66.tex
new file mode 100644
index 000000000..916a7de66
--- /dev/null
+++ b/tex/context/base/s-pre-66.tex
@@ -0,0 +1,133 @@
+%D \module
+%D [ file=s-pre-66,
+%D version=2009.02.24,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Presentation Environment 66,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=Hans Hagen]
+%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 Cambria (made in the aftermath of testing \OPENTYPE\ math).
+
+% \enablemode[paper]
+
+\usemodule[pre-60]
+\usemodule[abr-01]
+
+\definepapersize
+ [wide]
+ [width=960pt,
+ height=600pt]
+
+\setuppapersize
+ [wide]
+ [wide]
+
+\setuplayout
+ [topspace=20pt,
+ bottomspace=20pt,
+ header=0pt,
+ footer=0pt,
+ backspace=20pt,
+ height=middle,
+ rightmargin=0pt,
+ rightedge=\dimexpr220pt-40pt\relax,
+ rightedgedistance=40pt,
+ leftedge=0pt,
+ leftmargin=0pt,
+ cutspace=220pt,
+ width=\dimexpr960pt-40pt-220pt\relax]
+
+\definebodyfontenvironment
+ [20pt]
+
+\definefontfeature[default][default][mode=node,script=latn]
+
+\usetypescript
+ [cambria]
+
+\setupbodyfont
+ [cambria,20pt] \bf
+
+\setupwhitespace
+ [big]
+
+\setupcolors
+ [state=start]
+
+\definecolor[pagecolor][s=.25]
+\definecolor[edgecolor][b=.50,g=.75,r=.75]
+
+\setupinteraction
+ [state=start,
+ click=no,
+ color=,
+ contrastcolor=]
+
+\defineoverlay[pagegraphic][\reuseMPgraphic{pagegraphic}]
+
+\startuseMPgraphic{pagegraphic}
+ StartPage ;
+ fill Page enlarged 10pt withcolor \MPcolor{pagecolor} ;
+ fill Page enlarged 10pt leftenlarged (CutSpace - bbwidth(Page) - 10pt) withcolor \MPcolor{edgecolor} ;
+ % fill Field[Text][RightEdge] withcolor green ;
+ % fill Field[Text][Text] withcolor yellow ;
+ StopPage ;
+\stopuseMPgraphic
+
+\setupbackgrounds
+ [page]
+ [background=pagegraphic]
+
+\setupbackgrounds
+ [text]
+ [rightedge]
+ [background=edge]
+
+\definelayer
+ [edge]
+ [width=\rightedgewidth,
+ state=repeat]
+
+\setuphead
+ [chapter]
+ [style=\bfc,
+ color=edgecolor]
+
+\setupcolors
+ [textcolor=edgecolor]
+
+\newcounter\MyCounter
+
+\def\StartRemark#1%
+ {\doglobal\increment\MyCounter % hm, we could use the autoref (todo in cont-xp)
+ \title[topic:\MyCounter]{#1}
+ \setlayer[edge][preset=middletop,y=\thelayerheight{edge}]{\strut\color[pagecolor]{\bf\goto{#1}[topic:\MyCounter]}}
+ \StartSteps}
+
+\def\StopRemark
+ {\StopSteps
+ \page}
+
+\def\StartRemark#1%
+ {\doglobal\increment\MyCounter % hm, we could use the autoref (todo in cont-xp)
+ \title[topic:\MyCounter]{#1}
+ \StartSteps
+ \def\StopRemark
+ {\StopSteps
+ \page
+ \setlayer[edge][preset=middletop,y=\thelayerheight{edge}]{\strut\color[pagecolor]{\bf\goto{#1}[topic:\MyCounter]}}}}
+
+\def\StartTitlePage
+ {\startstandardmakeup[top=\vss,bottom=\vss\vss]
+ \definedfont[Bold sa 4]
+ \raggedcenter
+ \setupinterlinespace
+ \baselineskip=1\baselineskip plus 1fil minus 1fil\relax}
+
+\def\StopTitlePage
+ {\stopstandardmakeup}
diff --git a/tex/context/base/s-pre-71.tex b/tex/context/base/s-pre-71.tex
index 3d92830b9..91075d54d 100644
--- a/tex/context/base/s-pre-71.tex
+++ b/tex/context/base/s-pre-71.tex
@@ -28,11 +28,11 @@
\setuplayout[page]
-\setupbodyfont[15pt]
+% \setupbodyfont[15pt]
\usetypescriptfile[type-hgz]
\usetypescript[palatino-informal]
-\setupbodyfont[palatino-informal]
+\setupbodyfont[palatino-informal,15pt]
\setupsorting[logo][style=]
@@ -57,7 +57,8 @@
\definecolor[TopicColor-0][t=.5,a=1,s=.5]
\definecolor[TopicColor] [s=1]
-\setupcolors[state=start,textcolor=TopicColor]
+\setupcolors[state=start]
+\setupcolors[textcolor=TopicColor]
\startluacode
local locations = {
@@ -182,6 +183,7 @@
\logo [METAPOST] {MetaPost}
\definefont[TitleFont][SansBold at 60pt]
+\definefont[TempFont] [SansBold at 12pt]
\doifnotmode{demo}{\endinput}
diff --git a/tex/context/base/s-reg-01.tex b/tex/context/base/s-reg-01.tex
new file mode 100644
index 000000000..123b97384
--- /dev/null
+++ b/tex/context/base/s-reg-01.tex
@@ -0,0 +1,50 @@
+%D \module
+%D [ file=s-reg-01,
+%D version=2005.04.25,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Extra Regime Support,
+%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 {showregime}
+%D
+%D This code is moved from the kernel to here. (We could make it
+%D auto-loadable).
+
+\startluacode
+--[[ldx--
+<p>The following code is rather <l n='context'/> specific.</p>
+--ldx]]--
+
+function regimes.show(regime)
+ regime = regimes.synonyms[regime] or regime
+ local r = regimes.data[regime]
+ if r then
+ tex.sprint(tc,"\\starttabulate[|rT|T|rT|lT|lT|lT|]")
+ for k, v in ipairs(r) do
+ tex.sprint(tex.ctxcatcodes, string.format("\\NC %s\\NC\\getvalue{%s}\\NC %s\\NC %s\\NC %s\\NC %s\\NC\\NR", k,
+ characters.contextname(v), characters.hexindex(v), characters.contextname(v),
+ characters.category(v), characters.description(v)))
+ end
+ tex.sprint(tex.ctxcatcodes,"\\stoptabulate")
+ else
+ tex.sprint(tex.ctxcatcodes,"unknown regime " .. regime)
+ end
+end
+\stopluacode
+
+\unprotect
+
+\def\showregime
+ {\dosingleempty\doshowregime}
+
+\def\doshowregime[#1]%
+ {\ctxlua{regimes.show("#1")}}
+
+\protect \endinput
diff --git a/tex/context/base/scrp-cjk.lua b/tex/context/base/scrp-cjk.lua
new file mode 100644
index 000000000..a452673fa
--- /dev/null
+++ b/tex/context/base/scrp-cjk.lua
@@ -0,0 +1,576 @@
+if not modules then modules = { } end modules ['scrp-cjk'] = {
+ version = 1.001,
+ comment = "companion to scrp-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local has_attribute = node.has_attribute
+local make_glue_node = nodes.glue
+local make_penalty_node = nodes.penalty
+local insert_node_after = node.insert_after
+local insert_node_before = node.insert_before
+local remove_node = nodes.remove
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+
+local preproc = attributes.private('preproc')
+local prestat = attributes.private('prestat')
+
+scripts.cjk = scripts.cjk or { }
+
+local kind_to_number = scripts.kind_to_number
+local number_to_kind = scripts.number_to_kind
+local hash = scripts.hash
+local cjk = scripts.cjk
+local fontdata = fonts.ids
+
+-- raggedleft is controlled by leftskip and we might end up with a situation where
+-- the intercharacter spacing interferes with this; the solution is to patch the
+-- nodelist but better is to use veryraggedleft
+
+local inter_char_stretch = 0
+local inter_char_half_shrink = 0
+local inter_char_hangul_penalty = 0
+
+local function set_parameters(font,data)
+ -- beware: parameters can be nil in e.g. punk variants
+ local parameters = fontdata[font].parameters
+ local quad = (parameters and parameters.quad or parameters[6]) or 0
+ inter_char_half_shrink = data.inter_char_half_shrink_factor * quad
+ inter_char_stretch = data.inter_char_stretch_factor * quad
+ inter_char_hangul_penalty = data.inter_char_hangul_penalty
+end
+
+-- a test version did compensate for crappy halfwidth but we can best do that
+-- at font definition time and/or just assume a correct font
+
+local function nobreak(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+end
+local function stretch_break(head,current)
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+local function shrink_break(head,current)
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+end
+local function nobreak_stretch(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+local function korean_break(head,current)
+ insert_node_before(head,current,make_penalty_node(inter_char_hangul_penalty))
+end
+
+local function nobreak_shrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+end
+local function nobreak_autoshrink(head,current)
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+end
+
+local function nobreak_stretch_nobreak_shrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+end
+local function nobreak_stretch_nobreak_autoshrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+end
+
+local function nobreak_shrink_nobreak_stretch(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+local function nobreak_autoshrink_nobreak_stretch(head,current)
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+
+local function nobreak_shrink_break_stretch(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+local function nobreak_autoshrink_break_stretch(head,current)
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+
+local function nobreak_shrink_break_stretch_nobreak_shrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+end
+local function nobreak_autoshrink_break_stretch_nobreak_autoshrink(head,current)
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+end
+local function nobreak_autoshrink_break_stretch_nobreak_shrink(head,current)
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+end
+local function nobreak_shrink_break_stretch_nobreak_autoshrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ if true then
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ end
+end
+
+local function nobreak_stretch_break_shrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+end
+local function nobreak_stretch_break_autoshrink(head,current)
+ insert_node_before(head,current,make_penalty_node(10000))
+ insert_node_before(head,current,make_glue_node(0,inter_char_stretch,0))
+ if true then
+ insert_node_before(head,current,make_glue_node(0,0,inter_char_half_shrink))
+ end
+end
+
+-- hangul (korean)
+
+local injectors = { -- [previous] [current]
+ jamo_final = {
+ jamo_initial = korean_break,
+ korean = korean_break,
+ chinese = korean_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = korean_break,
+ other = korean_break,
+ },
+ korean = {
+ jamo_initial = korean_break,
+ korean = korean_break,
+ chinese = korean_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = korean_break,
+ other = korean_break,
+ },
+ chinese = {
+ jamo_initial = korean_break,
+ korean = korean_break,
+ chinese = korean_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = korean_break,
+ other = korean_break,
+ },
+ hyphen = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = stretch_break,
+ other = stretch_break,
+ },
+ start = {
+ -- jamo_initial = nil,
+ -- korean = nil,
+ -- chinese = nil,
+ -- half_width_open = nil,
+ -- half_width_close = nil,
+ -- full_width_open = nil,
+ -- full_width_close = nil,
+ -- hyphen = nil,
+ -- non_starter = nil,
+ -- other = nil,
+ },
+ other = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = stretch_break,
+ other = stretch_break,
+ },
+ non_starter = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak,
+ full_width_open = stretch_break,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = nobreak,
+ other = nobreak,
+ },
+ full_width_open = {
+ jamo_initial = nobreak,
+ korean = nobreak,
+ chinese = nobreak,
+ half_width_open = nobreak,
+ half_width_close = nobreak,
+ full_width_open = nobreak,
+ full_width_close = nobreak,
+ hyphen = nobreak,
+ non_starter = nobreak,
+ other = nobreak,
+ },
+ half_width_open = {
+ jamo_initial = nobreak,
+ korean = nobreak,
+ chinese = nobreak,
+ half_width_open = nobreak,
+ half_width_close = nobreak,
+ full_width_open = nobreak,
+ full_width_close = nobreak,
+ hyphen = nobreak,
+ non_starter = nobreak,
+ other = nobreak,
+ },
+ full_width_close = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak_stretch,
+ full_width_open = stretch_break,
+ full_width_close = nobreak_stretch,
+ hyphen = nobreak_stretch,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ half_width_close = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = stretch_break,
+ half_width_close = nobreak_stretch,
+ full_width_open = stretch_break,
+ full_width_close = nobreak_stretch,
+ hyphen = nobreak_stretch,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+}
+
+local dataset = {
+ inter_char_stretch_factor = 0.50, -- of quad
+ inter_char_half_shrink_factor = 0.50, -- of quad
+ inter_char_hangul_penalty = 50,
+}
+
+local function process(head,first,last)
+ if first ~= last then
+ local lastfont, previous, originals, last = nil, "start", nil, nil
+ while true do
+ local upcoming, id = first.next, first.id
+ if id == glyph then
+ local a = has_attribute(first,prestat)
+ local current = number_to_kind[a]
+ local action = injectors[previous]
+ if action then
+ action = action[current]
+ if action then
+ local font = first.font
+ if font ~= lastfont then
+ lastfont, done = font, true
+ set_parameters(font,dataset)
+ end
+ action(head,first)
+ end
+ end
+ previous = current
+ else -- glue
+ local p, n = first.prev, upcoming
+ if p and n then
+ local pid, nid = p.id, n.id
+ if pid == glyph and nid == glyph then
+ local pa, na = has_attribute(p,prestat), has_attribute(n,prestat)
+ local pcjk, ncjk = pa and number_to_kind[pa], na and number_to_kind[na]
+ if not pcjk or not ncjk
+ or pcjk == "korean" or ncjk == "korean"
+ or pcjk == "other" or ncjk == "other"
+ or pcjk == "jamo_final" or ncjk == "jamo_initial" then
+ previous = "start"
+ else -- if head ~= first then
+ remove_node(head,first,true)
+ previous = pcjk
+ -- else
+ -- previous = pcjk
+ end
+ else
+ previous = "start"
+ end
+ else
+ previous = "start"
+ end
+ end
+ if upcoming == stop then
+ break
+ else
+ first = upcoming
+ end
+ end
+ end
+end
+
+scripts.install {
+ name = "hangul",
+ process = process,
+}
+
+-- hanzi (chinese)
+
+local injectors = { -- [previous] [current]
+ jamo_final = {
+ jamo_initial = korean_break,
+ korean = korean_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ -- hyphen = nil,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ korean = {
+ jamo_initial = korean_break,
+ korean = korean_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ -- hyphen = nil,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ chinese = {
+ jamo_initial = korean_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ hyphen = nobreak_stretch,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ hyphen = {
+ jamo_initial = korean_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ -- hyphen = nil,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ start = {
+ -- jamo_initial = nil,
+ -- korean = nil,
+ -- chinese = nil,
+ half_width_open = nobreak_autoshrink,
+ half_width_close = nil,
+ full_width_open = nobreak_shrink,
+ full_width_close = nobreak,
+ -- hyphen = nil,
+ non_starter = nobreak,
+ -- other = nil,
+ },
+ other = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ -- hyphen = nil,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ non_starter = {
+ jamo_initial = stretch_break,
+ korean = stretch_break,
+ chinese = stretch_break,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ -- hyphen = nil,
+ non_starter = nobreak_stretch,
+ other = stretch_break,
+ },
+ full_width_open = {
+ jamo_initial = nobreak_stretch,
+ korean = nobreak_stretch,
+ chinese = nobreak_stretch,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_break_shrink,
+ full_width_close = nobreak_stretch,
+ hyphen = nobreak_stretch,
+ non_starter = nobreak_stretch,
+ other = nobreak_stretch,
+ },
+ half_width_open = {
+ jamo_initial = nobreak_stretch,
+ korean = nobreak_stretch,
+ chinese = nobreak_stretch,
+ half_width_open = nobreak_stretch_break_autoshrink,
+ half_width_close = nobreak_stretch,
+ full_width_open = nobreak_stretch_nobreak_shrink,
+ full_width_close = nobreak_stretch,
+ hyphen = nobreak_stretch,
+ non_starter = nobreak_stretch,
+ other = nobreak_stretch,
+ },
+ full_width_close = {
+ jami_initial = nobreak_shrink_break_stretch,
+ korean = nobreak_shrink_break_stretch,
+ chinese = nobreak_shrink_break_stretch,
+ half_width_open = nobreak_shrink_break_stretch_nobreak_autoshrink,
+ half_width_close = nobreak_shrink_nobreak_stretch,
+ full_width_open = nobreak_shrink_break_stretch_nobreak_shrink,
+ full_width_close = nobreak_shrink_nobreak_stretch,
+ hyphen = nobreak_shrink_break_stretch,
+ non_starter = nobreak_shrink_break_stretch,
+ other = nobreak_shrink_break_stretch,
+ },
+ half_width_close = {
+ jami_initial = nobreak_shrink_break_stretch,
+ korean = nobreak_autoshrink_break_stretch,
+ chinese = nobreak_autoshrink_break_stretch,
+ half_width_open = nobreak_autoshrink_break_stretch_nobreak_autoshrink,
+ half_width_close = nobreak_autoshrink_nobreak_stretch,
+ full_width_open = nobreak_autoshrink_break_stretch_nobreak_shrink,
+ full_width_close = nobreak_autoshrink_nobreak_stretch,
+ hyphen = nobreak_autoshrink_break_stretch,
+ non_starter = nobreak_autoshrink_break_stretch,
+ other = nobreak_autoshrink_break_stretch,
+ },
+}
+
+local dataset = {
+ inter_char_stretch_factor = 0.50, -- of quad
+ inter_char_half_shrink_factor = 0.50, -- of quad
+ inter_char_hangul_penalty = 50,
+}
+
+local function process(head,first,last)
+ if first ~= last then
+ local lastfont, previous, originals, last = nil, "start", nil, nil
+ while true do
+ local upcoming, id = first.next, first.id
+ if id == glyph then
+ local a = has_attribute(first,prestat)
+ local current = number_to_kind[a]
+ local action = injectors[previous]
+ if action then
+ action = action[current]
+ if action then
+ local font = first.font
+ if font ~= lastfont then
+ lastfont, done = font, true
+ set_parameters(font,dataset)
+ end
+ action(head,first)
+ end
+ end
+ previous = current
+ else -- glue
+ local p, n = first.prev, upcoming
+ if p and n then
+ local pid, nid = p.id, n.id
+ if pid == glyph and nid == glyph then
+ local pa, na = has_attribute(p,prestat), has_attribute(n,prestat)
+ local pcjk, ncjk = pa and number_to_kind[pa], na and number_to_kind[na]
+ if not pcjk or not ncjk
+ or pcjk == "korean" or ncjk == "korean"
+ or pcjk == "other" or ncjk == "other"
+ or pcjk == "jamo_final" or ncjk == "jamo_initial" then
+ previous = "start"
+ else -- if head ~= first then
+ remove_node(head,first,true)
+ previous = pcjk
+ -- else
+ -- previous = pcjk
+ end
+ else
+ previous = "start"
+ end
+ else
+ previous = "start"
+ end
+ end
+ if upcoming == stop then
+ break
+ else
+ first = upcoming
+ end
+ end
+ end
+end
+
+scripts.install {
+ name = "hanzi",
+ process = process,
+}
diff --git a/tex/context/base/scrp-ini.lua b/tex/context/base/scrp-ini.lua
new file mode 100644
index 000000000..a55573284
--- /dev/null
+++ b/tex/context/base/scrp-ini.lua
@@ -0,0 +1,386 @@
+if not modules then modules = { } end modules ['scrp-ini'] = {
+ version = 1.001,
+ comment = "companion to scrp-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_analyzing = false trackers.register("scripts.analyzing", function(v) trace_analyzing = v end)
+local trace_injections = false trackers.register("scripts.injections", function(v) trace_injections = v end)
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local first_character = node.first_character
+local traverse_id = node.traverse_id
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+
+local fcs = (fonts.color and fonts.color.set) or function() end
+local fcr = (fonts.color and fonts.color.reset) or function() end
+
+local state = attributes.private('state')
+local preproc = attributes.private('preproc')
+local prestat = attributes.private('prestat')
+
+local fontdata = fonts.ids
+
+scripts = scripts or { }
+scripts.handlers = scripts.handlers or { }
+
+scripts.names = scripts.names or { }
+scripts.numbers = scripts.numbers or { }
+scripts.hash = scripts.hash or { }
+
+storage.register("scripts/hash", scripts.hash, "scripts.hash")
+
+if not next(scripts.hash) then
+
+ local hash = {
+ --
+ -- half width opening parenthesis
+ [0x0028] = "half_width_open",
+ [0x005B] = "half_width_open",
+ [0x007B] = "half_width_open",
+ [0x2018] = "half_width_open", -- ‘
+ [0x201C] = "half_width_open", -- “
+ --
+ -- full width opening parenthesis
+ --
+ [0x3008] = "full_width_open", -- 〈 Left book quote
+ [0x300A] = "full_width_open", -- 《 Left double book quote
+ [0x300C] = "full_width_open", -- 「 left quote
+ [0x300E] = "full_width_open", -- 『 left double quote
+ [0x3010] = "full_width_open", -- 【 left double book quote
+ [0x3014] = "full_width_open", -- 〔 left book quote
+ [0x3016] = "full_width_open", --〖 left double book quote
+ [0x3018] = "full_width_open", -- left tortoise bracket
+ [0x301A] = "full_width_open", -- left square bracket
+ [0x301D] = "full_width_open", -- reverse double prime qm
+ [0xFF08] = "full_width_open", -- ( left parenthesis
+ [0xFF3B] = "full_width_open", -- [ left square brackets
+ [0xFF5B] = "full_width_open", -- { left curve bracket
+ [0xFF62] = "full_width_open", -- left corner bracket
+ --
+ -- half width closing parenthesis
+ [0x0029] = "half_width_close",
+ [0x005D] = "half_width_close",
+ [0x007D] = "half_width_close",
+ [0x2019] = "half_width_close", -- ’ right quote, right
+ [0x201D] = "half_width_close", -- ” right double quote
+ --
+ -- full width closing parenthesis
+ --
+ [0x3009] = "full_width_close", -- 〉 book quote
+ [0x300B] = "full_width_close", -- 》 double book quote
+ [0x300D] = "full_width_close", -- 」 right quote, right
+ [0x300F] = "full_width_close", -- 』 right double quote
+ [0x3011] = "full_width_close", -- 】 right double book quote
+ [0x3015] = "full_width_close", -- 〕 right book quote
+ [0x3017] = "full_width_close", -- 〗 right double book quote
+ [0x3019] = "full_width_close", -- right tortoise bracket
+ [0x301B] = "full_width_close", -- right square bracket
+ [0x301E] = "full_width_close", -- double prime qm
+ [0x301F] = "full_width_close", -- low double prime qm
+ [0xFF09] = "full_width_close", -- ) right parenthesis
+ [0xFF3D] = "full_width_close", -- ] right square brackets
+ [0xFF5D] = "full_width_close", -- } right curve brackets
+ [0xFF63] = "full_width_close", -- right corner bracket
+ --
+ -- vertical opening vertical
+ --
+ -- 0xFE35, 0xFE37, 0xFE39, 0xFE3B, 0xFE3D, 0xFE3F, 0xFE41, 0xFE43, 0xFE47,
+ --
+ -- vertical closing
+ --
+ -- 0xFE36, 0xFE38, 0xFE3A, 0xFE3C, 0xFE3E, 0xFE40, 0xFE42, 0xFE44, 0xFE48,
+ --
+ -- half width opening punctuation
+ --
+ -- <empty>
+ --
+ -- full width opening punctuation
+ --
+ -- 0x2236, -- ∶
+ -- 0xFF0C, -- ,
+ --
+ -- half width closing punctuation_hw
+ --
+ [0x0021] = "half_width_close", -- !
+ [0x002C] = "half_width_close", -- ,
+ [0x002E] = "half_width_close", -- .
+ [0x003A] = "half_width_close", -- :
+ [0x003B] = "half_width_close", -- ;
+ [0x003F] = "half_width_close", -- ?
+ [0xFF61] = "half_width_close", -- hw full stop
+ --
+ -- full width closing punctuation
+ [0x3001] = "full_width_close", -- 、
+ [0x3002] = "full_width_close", -- 。
+ [0xFF01] = "full_width_close", -- !
+ [0xFF0C] = "full_width_close", -- ,
+ [0xFF0E] = "full_width_close", -- .
+ [0xFF1A] = "full_width_close", -- :
+ [0xFF1B] = "full_width_close", -- ;
+ [0xFF1F] = "full_width_close", -- ?
+ --
+ -- non starter
+ --
+ [0x3005] = "non_starter", [0x3041] = "non_starter", [0x3043] = "non_starter", [0x3045] = "non_starter", [0x3047] = "non_starter",
+ [0x3049] = "non_starter", [0x3063] = "non_starter", [0x3083] = "non_starter", [0x3085] = "non_starter", [0x3087] = "non_starter",
+ [0x308E] = "non_starter", [0x3095] = "non_starter", [0x3096] = "non_starter", [0x309B] = "non_starter", [0x309C] = "non_starter",
+ [0x309D] = "non_starter", [0x309E] = "non_starter", [0x30A0] = "non_starter", [0x30A1] = "non_starter", [0x30A3] = "non_starter",
+ [0x30A5] = "non_starter", [0x30A7] = "non_starter", [0x30A9] = "non_starter", [0x30C3] = "non_starter", [0x30E3] = "non_starter",
+ [0x30E5] = "non_starter", [0x30E7] = "non_starter", [0x30EE] = "non_starter", [0x30F5] = "non_starter", [0x30F6] = "non_starter",
+ [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31F0] = "non_starter", [0x31F1] = "non_starter",
+ [0x30F2] = "non_starter", [0x30F3] = "non_starter", [0x30F4] = "non_starter", [0x31F5] = "non_starter", [0x31F6] = "non_starter",
+ [0x30F7] = "non_starter", [0x30F8] = "non_starter", [0x30F9] = "non_starter", [0x31FA] = "non_starter", [0x31FB] = "non_starter",
+ [0x30FC] = "non_starter", [0x30FD] = "non_starter", [0x30FE] = "non_starter", [0x31FF] = "non_starter",
+ --
+ -- hyphenation
+ --
+ [0x2026] = "hyphen", -- … ellipsis
+ [0x2014] = "hyphen", -- — hyphen
+ }
+
+ for i=0x03040,0x0309F do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x030A0,0x030FF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x031F0,0x031FF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x03400,0x04DFF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x04E00,0x09FFF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x0F900,0x0FAFF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x0FF00,0x0FFEF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x20000,0x2A6DF do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x2F800,0x2FA1F do if not hash[i] then hash[i] = "chinese" end end
+ for i=0x0AC00,0x0D7A3 do if not hash[i] then hash[i] = "korean" end end
+ for i=0x01100,0x0115F do if not hash[i] then hash[i] = "jamo_initial" end end
+ for i=0x01160,0x011A7 do if not hash[i] then hash[i] = "jamo_medial" end end
+ for i=0x011A8,0x011FF do if not hash[i] then hash[i] = "jamo_final" end end
+
+ scripts.hash = hash
+
+end
+
+scripts.colors = { -- todo: just named colors
+ korean = "font:isol",
+ chinese = "font:rest",
+ full_width_open = "font:init",
+ full_width_close = "font:fina",
+ half_width_open = "font:init",
+ half_width_close = "font:fina",
+ hyphen = "font:medi",
+ non_starter = "font:isol",
+ jamo_initial = "font:init",
+ jamo_medial = "font:medi",
+ jamo_final = "font:fina",
+
+}
+
+scripts.number_to_kind = {
+ "korean",
+ "chinese",
+ "full_width_open",
+ "full_width_close",
+ "half_width_open",
+ "half_width_close",
+ "hyphen",
+ "non_starter",
+ "jamo_initial",
+ "jamo_medial",
+ "jamo_final",
+}
+
+scripts.kind_to_number = {
+ korean = 1,
+ chinese = 2,
+ full_width_open = 3,
+ full_width_close = 4,
+ half_width_open = 5,
+ half_width_close = 6,
+ hyphen = 7,
+ non_starter = 8,
+ jamo_initial = 9,
+ jamo_medial = 10,
+ jamo_final = 11,
+}
+
+local kind_to_number = scripts.kind_to_number
+local number_to_kind = scripts.number_to_kind
+
+-- no, this time loading the lua always precedes the definitions
+--
+-- storage.register("scripts/names", scripts.names, "scripts.names")
+-- storage.register("scripts/numbers", scripts.numbers, "scripts.numbers")
+
+local handlers = scripts.handlers
+local names = scripts.names
+local numbers = scripts.numbers
+local hash = scripts.hash
+local colors = scripts.colors
+
+-- maybe also process
+
+function scripts.install(handler)
+ local name = handler.name
+ if not names[name] then
+ local n = #numbers + 1
+ numbers[n] = name
+ names[name] = n
+ handlers[n] = handler
+ end
+ return names[name]
+end
+
+function scripts.define(name)
+ tex.write(names[name] or attributes.unsetvalue)
+end
+
+-- some time i will make a fonts.originals[id]
+
+local function colorize(start,stop)
+ for n in traverse_id(glyph,start) do
+ local kind = number_to_kind[has_attribute(n,prestat)]
+ if kind then
+ local ac = colors[kind]
+ if ac then
+ fcs(n,ac)
+ end
+ end
+ if n == stop then
+ break
+ end
+ end
+end
+
+local function traced_process(head,first,last,process,a)
+ if start ~= last then
+ local f, l = first, last
+ logs.report("preprocess","before %s: %s",names[a] or "?",nodes.tosequence(f,l))
+ process(head,first,last)
+ logs.report("preprocess","after %s: %s", names[a] or "?",nodes.tosequence(f,l))
+ end
+end
+
+-- eventually we might end up with more extensive parsing
+-- todo: pass t[start..stop] == original
+
+function scripts.preprocess(head)
+ local start = first_character(head)
+ if not start then
+ return head, false
+ else
+ local last_a, normal_process, lastfont, originals = nil, nil, nil, nil
+ local done, first, last, ok = false, nil, nil, false
+ while start do
+ local id = start.id
+ if id == glyph then
+ local a = has_attribute(start,preproc)
+ if a then
+ if a ~= last_a then
+ if first then
+ if ok then
+ if trace_analyzing then
+ colorize(first,last)
+ end
+ if trace_injections then
+ traced_process(head,first,last,normal_process,last_a)
+ else
+ normal_process(head,first,last)
+ end
+ ok, done = false, true
+ end
+ first, last = nil, nil
+ end
+ last_a = a
+ local handler = handlers[a]
+ normal_process = handler.process
+ end
+ if normal_process then
+ local f = start.font
+ if f ~= lastfont then
+ originals = fontdata[f].originals
+ lastfont = f
+ end
+ local c = start.char
+ if originals then c = originals[c] or c end
+ local h = hash[c]
+ if h then
+ set_attribute(start,prestat,kind_to_number[h])
+ if not first then
+ first, last = start, start
+ else
+ last = start
+ end
+ -- if cjk == "chinese" or cjk == "korean" then -- we need to prevent too much ( ) processing
+ ok = true
+ -- end
+ elseif first then
+ if ok then
+ if trace_analyzing then
+ colorize(first,last)
+ end
+ if trace_injections then
+ traced_process(head,first,last,normal_process,last_a)
+ else
+ normal_process(head,first,last)
+ end
+ ok, done = false, true
+ end
+ first, last = nil, nil
+ end
+ end
+ elseif first then
+ if ok then
+ if trace_analyzing then
+ colorize(first,last)
+ end
+ if trace_injections then
+ traced_process(head,first,last,normal_process,last_a)
+ else
+ normal_process(head,first,last)
+ end
+ ok, done = false, true
+ end
+ first, last = nil, nil
+ end
+ elseif id == glue then
+ if ok then
+ -- continue
+ elseif first then
+ -- no chinese or korean
+ first, last = nil, nil
+ end
+ elseif first then
+ if ok then
+ -- some chinese or korean
+ if trace_analyzing then
+ colorize(first,last)
+ end
+ if trace_injections then
+ traced_process(head,first,last,normal_process,last_a)
+ else
+ normal_process(head,first,last)
+ end
+ first, last, ok, done = nil, nil, false, true
+ elseif first then
+ first, last = nil, nil
+ end
+ end
+ start = start.next
+ end
+ if ok then
+ if trace_analyzing then
+ colorize(first,last)
+ end
+ if trace_injections then
+ traced_process(head,first,last,normal_process,last_a)
+ else
+ normal_process(head,first,last)
+ end
+ done = true
+ end
+ return head, done
+ end
+end
diff --git a/tex/context/base/scrp-ini.tex b/tex/context/base/scrp-ini.tex
new file mode 100644
index 000000000..3382ef4b6
--- /dev/null
+++ b/tex/context/base/scrp-ini.tex
@@ -0,0 +1,91 @@
+%D \module
+%D [ file=scrp-ini,
+%D version=2009.02.06,
+%D title=\CONTEXT\ Script Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% here we collect code from other places (was organized differently)
+
+\registerctxluafile{scrp-ini}{1.001}
+\registerctxluafile{scrp-cjk}{1.001}
+
+\definesystemattribute[preproc]
+\definesystemattribute[prestat]
+
+%D Since scripts need specific \LUA\ code we use hard coded attribute
+%D values, but we might have more tricks at some time, so we use a
+%D proper define macro too.
+
+\unprotect
+
+\def\s!attribute{attribute}
+
+\def\namedscriptparameter#1#2%
+ {\csname\doscriptparameter{\??ls#1}#2\endcsname}
+
+\def\scriptparameter#1%
+ {\csname\doscriptparameter{\??ls\currentscript}#1\endcsname}
+
+\def\doscriptparameter#1#2%
+ {\ifcsname#1#2\endcsname#1#2\else\expandafter\doscriptparentparameter\csname#1\s!parent\endcsname#2\fi}
+
+\def\doscriptparentparameter#1#2%
+ {\ifx#1\relax\s!empty\else\doscriptparameter#1#2\fi}
+
+% \def\scriptparameterhash#1%
+% {\doscriptparameterhash{\??ls\currentscript}#1}
+%
+% \def\doscriptparameterhash#1#2%
+% {\ifcsname#1#2\endcsname#1\else\expandafter\doscriptparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+%
+% \def\doscriptparentparameterhash#1#2%
+% {\ifx#1\relax\else\doscriptparameterhash#1#2\fi}
+
+% when #2 == string, then only synonym, no settings
+
+\def\definescript
+ {\dodoubleargument\dodefinescript}
+
+\def\dodefinescript[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\getparameters[\??ls#1][\c!method=,\s!parent=,#2]%
+ \doifelsenothing{\namedscriptparameter{#1}\c!method}
+ {\letvalue {\??ls#1\s!attribute}\attributeunsetvalue}%
+ {\setevalue{\??ls#1\s!attribute}{\ctxlua{scripts.define("\namedscriptparameter{#1}\c!method")}}}}%
+ {\getparameters[\??ls#1][\s!parent=#2]}%
+ \setvalue{#1}{\dosetscript{#1}}}
+
+\def\setupscript
+ {\dodoubleargument\dosetupscript}
+
+\def\dosetupscript[#1][#2]%
+ {\getparameters[\??ls#1][#2]}
+
+\def\dosetscript#1%
+ {\def\currentscript{#1}%
+ \edef\currentscriptattribute{\scriptparameter\s!attribute}%
+ \ifx\currentscriptattribute\empty
+ \let\currentscript\empty
+ \doresetattribute{preproc}%
+ \else
+ \dosetattribute{preproc}\currentscriptattribute % we can speed this up by storing the attribute in ??ls:a:#1
+ \fi}
+
+\def\setscript [#1]{\dosetscript{#1}}
+\def\startscript[#1]{\begingroup\dosetscript{#1}}
+\def\stopscript {\endgroup}
+
+% \setscript[hangul] \hangul \startscript[hangul]
+
+\definescript[latin] [\c!method=] % resets the attribute
+\definescript[hangul][\c!method=hangul]
+\definescript[hanzi] [\c!method=hanzi]
+
+\protect \endinput
diff --git a/tex/context/base/sort-def.mkii b/tex/context/base/sort-def.mkii
deleted file mode 100644
index 10dc31b14..000000000
--- a/tex/context/base/sort-def.mkii
+++ /dev/null
@@ -1,450 +0,0 @@
-%D \module
-%D [ file=sort-def,
-%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
-%D subtitle=Defaults,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module replaces existing sort key handling and is meant to be
-%D used with the new texutil functionality. Here we define the default
-%D mappings
-
-\exportsortexpansion{aeligature} {ae}
-\exportsortexpansion{AEligature} {AE}
-\exportsortexpansion{ijligature} {ij}
-\exportsortexpansion{IJligature} {IJ}
-\exportsortexpansion{oeligature} {oe}
-\exportsortexpansion{OEligature} {OE}
-
-\exportsortexpansion{ssharp} {ss}
-\exportsortexpansion{Ssharp} {SS}
-
-\exportsortexpansion{thorn} {}
-\exportsortexpansion{Thorn} {}
-
-\exportsortexpansion{eth} {}
-\exportsortexpansion{Eth} {}
-
-\exportsortexpansion{dj} {dstroke}
-\exportsortexpansion{Dj} {Dstroke}
-
-\exportsortexpansion{Acircumflex} {}
-\exportsortexpansion{acircumflex} {}
-\exportsortexpansion{Ccircumflex} {}
-\exportsortexpansion{ccircumflex} {}
-\exportsortexpansion{Ecircumflex} {}
-\exportsortexpansion{ecircumflex} {}
-\exportsortexpansion{Gcircumflex} {}
-\exportsortexpansion{gcircumflex} {}
-\exportsortexpansion{Hcircumflex} {}
-\exportsortexpansion{hcircumflex} {}
-\exportsortexpansion{Icircumflex} {}
-\exportsortexpansion{icircumflex} {}
-\exportsortexpansion{Jcircumflex} {}
-\exportsortexpansion{jcircumflex} {}
-\exportsortexpansion{Ocircumflex} {}
-\exportsortexpansion{ocircumflex} {}
-\exportsortexpansion{Scircumflex} {}
-\exportsortexpansion{scircumflex} {}
-\exportsortexpansion{Ucircumflex} {}
-\exportsortexpansion{ucircumflex} {}
-\exportsortexpansion{Wcircumflex} {}
-\exportsortexpansion{wcircumflex} {}
-\exportsortexpansion{Ycircumflex} {}
-\exportsortexpansion{ycircumflex} {}
-
-\exportsortexpansion{Agrave} {}
-\exportsortexpansion{agrave} {}
-\exportsortexpansion{Egrave} {}
-\exportsortexpansion{egrave} {}
-\exportsortexpansion{Igrave} {}
-\exportsortexpansion{igrave} {}
-\exportsortexpansion{Ograve} {}
-\exportsortexpansion{ograve} {}
-\exportsortexpansion{Ugrave} {}
-\exportsortexpansion{ugrave} {}
-\exportsortexpansion{Ygrave} {}
-\exportsortexpansion{ygrave} {}
-
-\exportsortexpansion{Atilde} {}
-\exportsortexpansion{atilde} {}
-\exportsortexpansion{Itilde} {}
-\exportsortexpansion{itilde} {}
-\exportsortexpansion{Ntilde} {}
-\exportsortexpansion{ntilde} {}
-\exportsortexpansion{Otilde} {}
-\exportsortexpansion{otilde} {}
-\exportsortexpansion{Utilde} {}
-\exportsortexpansion{utilde} {}
-\exportsortexpansion{Ytilde} {}
-\exportsortexpansion{ytilde} {}
-
-\exportsortexpansion{Adiaeresis} {}
-\exportsortexpansion{adiaeresis} {}
-\exportsortexpansion{Ediaeresis} {}
-\exportsortexpansion{ediaeresis} {}
-\exportsortexpansion{Idiaeresis} {}
-\exportsortexpansion{idiaeresis} {}
-\exportsortexpansion{Odiaeresis} {}
-\exportsortexpansion{odiaeresis} {}
-\exportsortexpansion{Udiaeresis} {}
-\exportsortexpansion{udiaeresis} {}
-\exportsortexpansion{Ydiaeresis} {}
-\exportsortexpansion{ydiaeresis} {}
-
-\exportsortexpansion{Aacute} {}
-\exportsortexpansion{aacute} {}
-\exportsortexpansion{Cacute} {}
-\exportsortexpansion{cacute} {}
-\exportsortexpansion{Eacute} {}
-\exportsortexpansion{eacute} {}
-\exportsortexpansion{Iacute} {}
-\exportsortexpansion{iacute} {}
-\exportsortexpansion{Lacute} {}
-\exportsortexpansion{lacute} {}
-\exportsortexpansion{Nacute} {}
-\exportsortexpansion{nacute} {}
-\exportsortexpansion{Oacute} {}
-\exportsortexpansion{oacute} {}
-\exportsortexpansion{Racute} {}
-\exportsortexpansion{racute} {}
-\exportsortexpansion{Sacute} {}
-\exportsortexpansion{sacute} {}
-\exportsortexpansion{Uacute} {}
-\exportsortexpansion{uacute} {}
-\exportsortexpansion{Yacute} {}
-\exportsortexpansion{yacute} {}
-\exportsortexpansion{Zacute} {}
-\exportsortexpansion{zacute} {}
-
-\exportsortexpansion{dstroke} {}
-\exportsortexpansion{Dstroke} {}
-\exportsortexpansion{Hstroke} {}
-\exportsortexpansion{hstroke} {}
-\exportsortexpansion{Tstroke} {}
-\exportsortexpansion{tstroke} {}
-
-\exportsortexpansion{Cdotaccent} {}
-\exportsortexpansion{cdotaccent} {}
-\exportsortexpansion{Edotaccent} {}
-\exportsortexpansion{edotaccent} {}
-\exportsortexpansion{Gdotaccent} {}
-\exportsortexpansion{gdotaccent} {}
-\exportsortexpansion{Idotaccent} {}
-\exportsortexpansion{idotaccent} {}
-\exportsortexpansion{Zdotaccent} {}
-\exportsortexpansion{zdotaccent} {}
-
-\exportsortexpansion{Amacron} {}
-\exportsortexpansion{amacron} {}
-\exportsortexpansion{Emacron} {}
-\exportsortexpansion{emacron} {}
-\exportsortexpansion{Imacron} {}
-\exportsortexpansion{imacron} {}
-\exportsortexpansion{Omacron} {}
-\exportsortexpansion{omacron} {}
-\exportsortexpansion{Umacron} {}
-\exportsortexpansion{umacron} {}
-
-\exportsortexpansion{Ccedilla} {}
-\exportsortexpansion{ccedilla} {}
-\exportsortexpansion{Kcedilla} {}
-\exportsortexpansion{kcedilla} {}
-\exportsortexpansion{Lcedilla} {}
-\exportsortexpansion{lcedilla} {}
-\exportsortexpansion{Ncedilla} {}
-\exportsortexpansion{ncedilla} {}
-\exportsortexpansion{Rcedilla} {}
-\exportsortexpansion{rcedilla} {}
-\exportsortexpansion{Scedilla} {}
-\exportsortexpansion{scedilla} {}
-\exportsortexpansion{Tcedilla} {}
-\exportsortexpansion{tcedilla} {}
-
-\exportsortexpansion{Ohungarumlaut} {}
-\exportsortexpansion{ohungarumlaut} {}
-\exportsortexpansion{Uhungarumlaut} {}
-\exportsortexpansion{uhungarumlaut} {}
-
-\exportsortexpansion{Aogonek} {}
-\exportsortexpansion{aogonek} {}
-\exportsortexpansion{Eogonek} {}
-\exportsortexpansion{eogonek} {}
-\exportsortexpansion{Iogonek} {}
-\exportsortexpansion{iogonek} {}
-\exportsortexpansion{Uogonek} {}
-\exportsortexpansion{uogonek} {}
-
-\exportsortexpansion{Aring} {}
-\exportsortexpansion{aring} {}
-\exportsortexpansion{Uring} {}
-\exportsortexpansion{uring} {}
-
-\exportsortexpansion{Abreve} {}
-\exportsortexpansion{abreve} {}
-\exportsortexpansion{Ebreve} {}
-\exportsortexpansion{ebreve} {}
-\exportsortexpansion{Gbreve} {}
-\exportsortexpansion{gbreve} {}
-\exportsortexpansion{Ibreve} {}
-\exportsortexpansion{ibreve} {}
-\exportsortexpansion{Obreve} {}
-\exportsortexpansion{obreve} {}
-\exportsortexpansion{Ubreve} {}
-\exportsortexpansion{ubreve} {}
-
-\exportsortexpansion{Ccaron} {}
-\exportsortexpansion{ccaron} {}
-\exportsortexpansion{Dcaron} {}
-\exportsortexpansion{dcaron} {}
-\exportsortexpansion{Ecaron} {}
-\exportsortexpansion{ecaron} {}
-\exportsortexpansion{Lcaron} {}
-\exportsortexpansion{lcaron} {}
-\exportsortexpansion{Ncaron} {}
-\exportsortexpansion{ncaron} {}
-\exportsortexpansion{Rcaron} {}
-\exportsortexpansion{rcaron} {}
-\exportsortexpansion{Scaron} {}
-\exportsortexpansion{scaron} {}
-\exportsortexpansion{Tcaron} {}
-\exportsortexpansion{tcaron} {}
-\exportsortexpansion{Ycaron} {}
-\exportsortexpansion{ycaron} {}
-\exportsortexpansion{Zcaron} {}
-\exportsortexpansion{zcaron} {}
-
-\exportsortexpansion{Lstroke} {}
-\exportsortexpansion{lstroke} {}
-\exportsortexpansion{Ostroke} {}
-\exportsortexpansion{ostroke} {}
-
-\exportsortexpansion{aumlaut} {}
-\exportsortexpansion{eumlaut} {}
-\exportsortexpansion{iumlaut} {}
-\exportsortexpansion{oumlaut} {}
-\exportsortexpansion{uumlaut} {}
-
-\exportsortexpansion{Aumlaut} {}
-\exportsortexpansion{Eumlaut} {}
-\exportsortexpansion{Iumlaut} {}
-\exportsortexpansion{Oumlaut} {}
-\exportsortexpansion{Uumlaut} {}
-
-\exportsortexpansion{scommaaccent} {}
-\exportsortexpansion{Scommaaccent} {}
-\exportsortexpansion{tcommaaccent} {}
-\exportsortexpansion{Tcommaaccent} {}
-
-\exportsortexpansion{Etilde} {}
-\exportsortexpansion{etilde} {}
-
-\exportsortexpansion{Ahook} {}
-\exportsortexpansion{ahook} {}
-\exportsortexpansion{Ehook} {}
-\exportsortexpansion{ehook} {}
-\exportsortexpansion{Ihook} {}
-\exportsortexpansion{ihook} {}
-\exportsortexpansion{Ohook} {}
-\exportsortexpansion{ohook} {}
-\exportsortexpansion{Uhook} {}
-\exportsortexpansion{uhook} {}
-\exportsortexpansion{Yhook} {}
-\exportsortexpansion{yhook} {}
-
-\exportsortexpansion{Acircumflexgrave} {}
-\exportsortexpansion{Acircumflexacute} {}
-\exportsortexpansion{Acircumflextilde} {}
-\exportsortexpansion{Acircumflexhook} {}
-\exportsortexpansion{acircumflexgrave} {}
-\exportsortexpansion{acircumflexacute} {}
-\exportsortexpansion{acircumflextilde} {}
-\exportsortexpansion{acircumflexhook} {}
-\exportsortexpansion{Ecircumflexgrave} {}
-\exportsortexpansion{Ecircumflexacute} {}
-\exportsortexpansion{Ecircumflextilde} {}
-\exportsortexpansion{Ecircumflexhook} {}
-\exportsortexpansion{ecircumflexgrave} {}
-\exportsortexpansion{ecircumflexacute} {}
-\exportsortexpansion{ecircumflextilde} {}
-\exportsortexpansion{ecircumflexhook} {}
-\exportsortexpansion{Ocircumflexgrave} {}
-\exportsortexpansion{Ocircumflexacute} {}
-\exportsortexpansion{Ocircumflextilde} {}
-\exportsortexpansion{Ocircumflexhook} {}
-\exportsortexpansion{ocircumflexgrave} {}
-\exportsortexpansion{ocircumflexacute} {}
-\exportsortexpansion{ocircumflextilde} {}
-\exportsortexpansion{ocircumflexhook} {}
-
-\exportsortexpansion{Abrevegrave} {}
-\exportsortexpansion{Abreveacute} {}
-\exportsortexpansion{Abrevetilde} {}
-\exportsortexpansion{Abrevehook} {}
-\exportsortexpansion{abrevegrave} {}
-\exportsortexpansion{abreveacute} {}
-\exportsortexpansion{abrevetilde} {}
-\exportsortexpansion{abrevehook} {}
-
-\exportsortexpansion{Adotbelow} {}
-\exportsortexpansion{adotbelow} {}
-\exportsortexpansion{Edotbelow} {}
-\exportsortexpansion{edotbelow} {}
-\exportsortexpansion{Idotbelow} {}
-\exportsortexpansion{idotbelow} {}
-\exportsortexpansion{Odotbelow} {}
-\exportsortexpansion{odotbelow} {}
-\exportsortexpansion{Udotbelow} {}
-\exportsortexpansion{udotbelow} {}
-\exportsortexpansion{Ydotbelow} {}
-\exportsortexpansion{ydotbelow} {}
-\exportsortexpansion{Ohorndotbelow} {}
-\exportsortexpansion{ohorndotbelow} {}
-\exportsortexpansion{Uhorndotbelow} {}
-\exportsortexpansion{uhorndotbelow} {}
-
-\exportsortexpansion{Acircumflexdotbelow} {}
-\exportsortexpansion{acircumflexdotbelow} {}
-\exportsortexpansion{Ecircumflexdotbelow} {}
-\exportsortexpansion{ecircumflexdotbelow} {}
-\exportsortexpansion{Ocircumflexdotbelow} {}
-\exportsortexpansion{ocircumflexdotbelow} {}
-\exportsortexpansion{Abrevedotbelow} {}
-\exportsortexpansion{abrevedotbelow} {}
-
-\exportsortexpansion{Ohorn} {}
-\exportsortexpansion{Ohorngrave} {}
-\exportsortexpansion{Ohornacute} {}
-\exportsortexpansion{Ohorntilde} {}
-\exportsortexpansion{Ohornhook } {}
-\exportsortexpansion{ohorn} {}
-\exportsortexpansion{ohorngrave} {}
-\exportsortexpansion{ohornacute} {}
-\exportsortexpansion{ohorntilde} {}
-\exportsortexpansion{ohornhook } {}
-\exportsortexpansion{Uhorn} {}
-\exportsortexpansion{Uhorngrave} {}
-\exportsortexpansion{Uhornacute} {}
-\exportsortexpansion{Uhorntilde} {}
-\exportsortexpansion{Uhornhook } {}
-\exportsortexpansion{uhorn} {}
-\exportsortexpansion{uhorngrave} {}
-\exportsortexpansion{uhornacute} {}
-\exportsortexpansion{uhorntilde} {}
-\exportsortexpansion{uhornhook} {}
-
-\exportsortexpansion{eszett} {ssharp}
-\exportsortexpansion{Eszett} {Ssharp}
-
-\exportsortexpansion{lslash} {lstroke}
-\exportsortexpansion{Lslash} {Lstroke}
-\exportsortexpansion{dslash} {dstroke}
-\exportsortexpansion{Dslash} {Dstroke}
-\exportsortexpansion{oslash} {ostroke}
-\exportsortexpansion{Oslash} {Ostroke}
-
-\exportsortexpansion{dcroat} {dstroke}
-\exportsortexpansion{Dcroat} {Dstroke}
-
-% more
-
-\exportsortshortcut{\^ A} {\Acircumflex} \exportsortshortcut{\^ a} {\acircumflex}
-\exportsortshortcut{\^ C} {\Ccircumflex} \exportsortshortcut{\^ c} {\ccircumflex}
-\exportsortshortcut{\^ E} {\Ecircumflex} \exportsortshortcut{\^ e} {\ecircumflex}
-\exportsortshortcut{\^ G} {\Gcircumflex} \exportsortshortcut{\^ g} {\gcircumflex}
-\exportsortshortcut{\^ H} {\Hcircumflex} \exportsortshortcut{\^ h} {\hcircumflex}
-\exportsortshortcut{\^ I} {\Icircumflex} \exportsortshortcut{\^ i} {\icircumflex} \exportsortshortcut{\^\i} {\icircumflex}
-\exportsortshortcut{\^ J} {\Jcircumflex} \exportsortshortcut{\^ j} {\jcircumflex} \exportsortshortcut{\^\j} {\jcircumflex}
-\exportsortshortcut{\^ O} {\Ocircumflex} \exportsortshortcut{\^ o} {\ocircumflex}
-\exportsortshortcut{\^ S} {\Scircumflex} \exportsortshortcut{\^ s} {\scircumflex}
-\exportsortshortcut{\^ U} {\Ucircumflex} \exportsortshortcut{\^ u} {\ucircumflex}
-\exportsortshortcut{\^ W} {\Wcircumflex} \exportsortshortcut{\^ w} {\wcircumflex}
-\exportsortshortcut{\^ Y} {\Ycircumflex} \exportsortshortcut{\^ y} {\ycircumflex}
-
-\exportsortshortcut{\` A} {\Agrave} \exportsortshortcut{\` a} {\agrave}
-\exportsortshortcut{\` E} {\Egrave} \exportsortshortcut{\` e} {\egrave}
-\exportsortshortcut{\` I} {\Igrave} \exportsortshortcut{\` i} {\igrave} \exportsortshortcut{\`\i} {\igrave}
-\exportsortshortcut{\` O} {\Ograve} \exportsortshortcut{\` o} {\ograve}
-\exportsortshortcut{\` U} {\Ugrave} \exportsortshortcut{\` u} {\ugrave}
-\exportsortshortcut{\` Y} {\Ygrave} \exportsortshortcut{\` y} {\ygrave}
-
-\exportsortshortcut{\~ A} {\Atilde} \exportsortshortcut{\~ a} {\atilde}
-\exportsortshortcut{\~ I} {\Itilde} \exportsortshortcut{\~ i} {\itilde} \exportsortshortcut{\~\i} {\itilde}
-\exportsortshortcut{\~ O} {\Otilde} \exportsortshortcut{\~ o} {\otilde}
-\exportsortshortcut{\~ U} {\Utilde} \exportsortshortcut{\~ u} {\utilde}
-
-\exportsortshortcut{\" A} {\Adiaeresis} \exportsortshortcut{\" a} {\adiaeresis}
-\exportsortshortcut{\" E} {\Ediaeresis} \exportsortshortcut{\" e} {\ediaeresis}
-\exportsortshortcut{\" I} {\Idiaeresis} \exportsortshortcut{\" i} {\idiaeresis} \exportsortshortcut{\"\i} {\idiaeresis}
-\exportsortshortcut{\" O} {\Odiaeresis} \exportsortshortcut{\" o} {\odiaeresis}
-\exportsortshortcut{\" U} {\Udiaeresis} \exportsortshortcut{\" u} {\udiaeresis}
-\exportsortshortcut{\" Y} {\Ydiaeresis} \exportsortshortcut{\" y} {\ydiaeresis}
-
-\exportsortshortcut{\' A} {\Aacute} \exportsortshortcut{\' a} {\aacute}
-\exportsortshortcut{\' C} {\Cacute} \exportsortshortcut{\' c} {\cacute}
-\exportsortshortcut{\' E} {\Eacute} \exportsortshortcut{\' e} {\eacute}
-\exportsortshortcut{\' I} {\Iacute} \exportsortshortcut{\' i} {\iacute} \exportsortshortcut{\'\i} {\iacute}
-\exportsortshortcut{\' L} {\Lacute} \exportsortshortcut{\' l} {\lacute}
-\exportsortshortcut{\' N} {\Nacute} \exportsortshortcut{\' n} {\nacute}
-\exportsortshortcut{\' O} {\Oacute} \exportsortshortcut{\' o} {\oacute}
-\exportsortshortcut{\' R} {\Racute} \exportsortshortcut{\' r} {\racute}
-\exportsortshortcut{\' S} {\Sacute} \exportsortshortcut{\' s} {\sacute}
-\exportsortshortcut{\' U} {\Uacute} \exportsortshortcut{\' u} {\uacute}
-\exportsortshortcut{\' Y} {\Yacute} \exportsortshortcut{\' y} {\yacute}
-\exportsortshortcut{\' Z} {\Zacute} \exportsortshortcut{\' z} {\zacute}
-
-\exportsortshortcut{\. C} {\Cdotaccent} \exportsortshortcut{\. c} {\cdotaccent}
-\exportsortshortcut{\. E} {\Edotaccent} \exportsortshortcut{\. e} {\edotaccent}
-\exportsortshortcut{\. G} {\Gdotaccent} \exportsortshortcut{\. g} {\gdotaccent}
-\exportsortshortcut{\. I} {\Idotaccent} \exportsortshortcut{\. i} {\idotaccent} \exportsortshortcut{\.\i} {\idotaccent}
-\exportsortshortcut{\. Z} {\Zdotaccent} \exportsortshortcut{\. z} {\zdotaccent}
-
-\exportsortshortcut{\= A} {\Amacron} \exportsortshortcut{\= a} {\amacron}
-\exportsortshortcut{\= E} {\Emacron} \exportsortshortcut{\= e} {\emacron}
-\exportsortshortcut{\= I} {\Imacron} \exportsortshortcut{\= i} {\imacron} \exportsortshortcut{\=\i} {\imacron}
-\exportsortshortcut{\= O} {\Omacron} \exportsortshortcut{\= o} {\omacron}
-\exportsortshortcut{\= U} {\Umacron} \exportsortshortcut{\= u} {\umacron}
-
-\exportsortshortcut{\c C} {\Ccedilla} \exportsortshortcut{\c c} {\ccedilla}
-\exportsortshortcut{\c K} {\Kcedilla} \exportsortshortcut{\c k} {\kcedilla}
-\exportsortshortcut{\c L} {\Lcedilla} \exportsortshortcut{\c l} {\lcedilla}
-\exportsortshortcut{\c N} {\Ncedilla} \exportsortshortcut{\c n} {\ncedilla}
-\exportsortshortcut{\c R} {\Rcedilla} \exportsortshortcut{\c r} {\rcedilla}
-\exportsortshortcut{\c S} {\Scedilla} \exportsortshortcut{\c s} {\scedilla}
-\exportsortshortcut{\c T} {\Tcedilla} \exportsortshortcut{\c t} {\tcedilla}
-
-\exportsortshortcut{\H O} {\Ohungarumlaut} \exportsortshortcut{\H o} {\ohungarumlaut}
-\exportsortshortcut{\H u} {\uhungarumlaut} \exportsortshortcut{\H U} {\Uhungarumlaut}
-
-\exportsortshortcut{\k A} {\Aogonek} \exportsortshortcut{\k a} {\aogonek}
-\exportsortshortcut{\k E} {\Eogonek} \exportsortshortcut{\k e} {\eogonek}
-\exportsortshortcut{\k I} {\Iogonek} \exportsortshortcut{\k i} {\iogonek}
-\exportsortshortcut{\k U} {\Uogonek} \exportsortshortcut{\k u} {\uogonek}
-
-\exportsortshortcut{\r A} {\Aring} \exportsortshortcut{\r a} {\aring}
-\exportsortshortcut{\r U} {\Uring} \exportsortshortcut{\r u} {\uring}
-
-\exportsortshortcut{\u A} {\Abreve} \exportsortshortcut{\u a} {\abreve}
-\exportsortshortcut{\u E} {\Ebreve} \exportsortshortcut{\u e} {\ebreve}
-\exportsortshortcut{\u G} {\Gbreve} \exportsortshortcut{\u g} {\gbreve}
-\exportsortshortcut{\u I} {\Ibreve} \exportsortshortcut{\u i} {\ibreve} \exportsortshortcut{\u\i} {\ibreve}
-\exportsortshortcut{\u O} {\Obreve} \exportsortshortcut{\u o} {\obreve}
-\exportsortshortcut{\u U} {\Ubreve} \exportsortshortcut{\u u} {\ubreve}
-
-\exportsortshortcut{\v C} {\Ccaron} \exportsortshortcut{\v c} {\ccaron}
-\exportsortshortcut{\v D} {\Dcaron} \exportsortshortcut{\v d} {\dcaron}
-\exportsortshortcut{\v E} {\Ecaron} \exportsortshortcut{\v e} {\ecaron}
-\exportsortshortcut{\v L} {\Lcaron} \exportsortshortcut{\v l} {\lcaron}
-\exportsortshortcut{\v N} {\Ncaron} \exportsortshortcut{\v n} {\ncaron}
-\exportsortshortcut{\v R} {\Rcaron} \exportsortshortcut{\v r} {\rcaron}
-\exportsortshortcut{\v S} {\Scaron} \exportsortshortcut{\v s} {\scaron}
-\exportsortshortcut{\v T} {\Tcaron} \exportsortshortcut{\v t} {\tcaron}
-\exportsortshortcut{\v Z} {\Zcaron} \exportsortshortcut{\v z} {\zcaron}
-
-\endinput
diff --git a/tex/context/base/sort-def.tex b/tex/context/base/sort-def.tex
index 502fb787f..10dc31b14 100644
--- a/tex/context/base/sort-def.tex
+++ b/tex/context/base/sort-def.tex
@@ -15,6 +15,436 @@
%D used with the new texutil functionality. Here we define the default
%D mappings
-\loadmarkfile{sort-def}
+\exportsortexpansion{aeligature} {ae}
+\exportsortexpansion{AEligature} {AE}
+\exportsortexpansion{ijligature} {ij}
+\exportsortexpansion{IJligature} {IJ}
+\exportsortexpansion{oeligature} {oe}
+\exportsortexpansion{OEligature} {OE}
+
+\exportsortexpansion{ssharp} {ss}
+\exportsortexpansion{Ssharp} {SS}
+
+\exportsortexpansion{thorn} {}
+\exportsortexpansion{Thorn} {}
+
+\exportsortexpansion{eth} {}
+\exportsortexpansion{Eth} {}
+
+\exportsortexpansion{dj} {dstroke}
+\exportsortexpansion{Dj} {Dstroke}
+
+\exportsortexpansion{Acircumflex} {}
+\exportsortexpansion{acircumflex} {}
+\exportsortexpansion{Ccircumflex} {}
+\exportsortexpansion{ccircumflex} {}
+\exportsortexpansion{Ecircumflex} {}
+\exportsortexpansion{ecircumflex} {}
+\exportsortexpansion{Gcircumflex} {}
+\exportsortexpansion{gcircumflex} {}
+\exportsortexpansion{Hcircumflex} {}
+\exportsortexpansion{hcircumflex} {}
+\exportsortexpansion{Icircumflex} {}
+\exportsortexpansion{icircumflex} {}
+\exportsortexpansion{Jcircumflex} {}
+\exportsortexpansion{jcircumflex} {}
+\exportsortexpansion{Ocircumflex} {}
+\exportsortexpansion{ocircumflex} {}
+\exportsortexpansion{Scircumflex} {}
+\exportsortexpansion{scircumflex} {}
+\exportsortexpansion{Ucircumflex} {}
+\exportsortexpansion{ucircumflex} {}
+\exportsortexpansion{Wcircumflex} {}
+\exportsortexpansion{wcircumflex} {}
+\exportsortexpansion{Ycircumflex} {}
+\exportsortexpansion{ycircumflex} {}
+
+\exportsortexpansion{Agrave} {}
+\exportsortexpansion{agrave} {}
+\exportsortexpansion{Egrave} {}
+\exportsortexpansion{egrave} {}
+\exportsortexpansion{Igrave} {}
+\exportsortexpansion{igrave} {}
+\exportsortexpansion{Ograve} {}
+\exportsortexpansion{ograve} {}
+\exportsortexpansion{Ugrave} {}
+\exportsortexpansion{ugrave} {}
+\exportsortexpansion{Ygrave} {}
+\exportsortexpansion{ygrave} {}
+
+\exportsortexpansion{Atilde} {}
+\exportsortexpansion{atilde} {}
+\exportsortexpansion{Itilde} {}
+\exportsortexpansion{itilde} {}
+\exportsortexpansion{Ntilde} {}
+\exportsortexpansion{ntilde} {}
+\exportsortexpansion{Otilde} {}
+\exportsortexpansion{otilde} {}
+\exportsortexpansion{Utilde} {}
+\exportsortexpansion{utilde} {}
+\exportsortexpansion{Ytilde} {}
+\exportsortexpansion{ytilde} {}
+
+\exportsortexpansion{Adiaeresis} {}
+\exportsortexpansion{adiaeresis} {}
+\exportsortexpansion{Ediaeresis} {}
+\exportsortexpansion{ediaeresis} {}
+\exportsortexpansion{Idiaeresis} {}
+\exportsortexpansion{idiaeresis} {}
+\exportsortexpansion{Odiaeresis} {}
+\exportsortexpansion{odiaeresis} {}
+\exportsortexpansion{Udiaeresis} {}
+\exportsortexpansion{udiaeresis} {}
+\exportsortexpansion{Ydiaeresis} {}
+\exportsortexpansion{ydiaeresis} {}
+
+\exportsortexpansion{Aacute} {}
+\exportsortexpansion{aacute} {}
+\exportsortexpansion{Cacute} {}
+\exportsortexpansion{cacute} {}
+\exportsortexpansion{Eacute} {}
+\exportsortexpansion{eacute} {}
+\exportsortexpansion{Iacute} {}
+\exportsortexpansion{iacute} {}
+\exportsortexpansion{Lacute} {}
+\exportsortexpansion{lacute} {}
+\exportsortexpansion{Nacute} {}
+\exportsortexpansion{nacute} {}
+\exportsortexpansion{Oacute} {}
+\exportsortexpansion{oacute} {}
+\exportsortexpansion{Racute} {}
+\exportsortexpansion{racute} {}
+\exportsortexpansion{Sacute} {}
+\exportsortexpansion{sacute} {}
+\exportsortexpansion{Uacute} {}
+\exportsortexpansion{uacute} {}
+\exportsortexpansion{Yacute} {}
+\exportsortexpansion{yacute} {}
+\exportsortexpansion{Zacute} {}
+\exportsortexpansion{zacute} {}
+
+\exportsortexpansion{dstroke} {}
+\exportsortexpansion{Dstroke} {}
+\exportsortexpansion{Hstroke} {}
+\exportsortexpansion{hstroke} {}
+\exportsortexpansion{Tstroke} {}
+\exportsortexpansion{tstroke} {}
+
+\exportsortexpansion{Cdotaccent} {}
+\exportsortexpansion{cdotaccent} {}
+\exportsortexpansion{Edotaccent} {}
+\exportsortexpansion{edotaccent} {}
+\exportsortexpansion{Gdotaccent} {}
+\exportsortexpansion{gdotaccent} {}
+\exportsortexpansion{Idotaccent} {}
+\exportsortexpansion{idotaccent} {}
+\exportsortexpansion{Zdotaccent} {}
+\exportsortexpansion{zdotaccent} {}
+
+\exportsortexpansion{Amacron} {}
+\exportsortexpansion{amacron} {}
+\exportsortexpansion{Emacron} {}
+\exportsortexpansion{emacron} {}
+\exportsortexpansion{Imacron} {}
+\exportsortexpansion{imacron} {}
+\exportsortexpansion{Omacron} {}
+\exportsortexpansion{omacron} {}
+\exportsortexpansion{Umacron} {}
+\exportsortexpansion{umacron} {}
+
+\exportsortexpansion{Ccedilla} {}
+\exportsortexpansion{ccedilla} {}
+\exportsortexpansion{Kcedilla} {}
+\exportsortexpansion{kcedilla} {}
+\exportsortexpansion{Lcedilla} {}
+\exportsortexpansion{lcedilla} {}
+\exportsortexpansion{Ncedilla} {}
+\exportsortexpansion{ncedilla} {}
+\exportsortexpansion{Rcedilla} {}
+\exportsortexpansion{rcedilla} {}
+\exportsortexpansion{Scedilla} {}
+\exportsortexpansion{scedilla} {}
+\exportsortexpansion{Tcedilla} {}
+\exportsortexpansion{tcedilla} {}
+
+\exportsortexpansion{Ohungarumlaut} {}
+\exportsortexpansion{ohungarumlaut} {}
+\exportsortexpansion{Uhungarumlaut} {}
+\exportsortexpansion{uhungarumlaut} {}
+
+\exportsortexpansion{Aogonek} {}
+\exportsortexpansion{aogonek} {}
+\exportsortexpansion{Eogonek} {}
+\exportsortexpansion{eogonek} {}
+\exportsortexpansion{Iogonek} {}
+\exportsortexpansion{iogonek} {}
+\exportsortexpansion{Uogonek} {}
+\exportsortexpansion{uogonek} {}
+
+\exportsortexpansion{Aring} {}
+\exportsortexpansion{aring} {}
+\exportsortexpansion{Uring} {}
+\exportsortexpansion{uring} {}
+
+\exportsortexpansion{Abreve} {}
+\exportsortexpansion{abreve} {}
+\exportsortexpansion{Ebreve} {}
+\exportsortexpansion{ebreve} {}
+\exportsortexpansion{Gbreve} {}
+\exportsortexpansion{gbreve} {}
+\exportsortexpansion{Ibreve} {}
+\exportsortexpansion{ibreve} {}
+\exportsortexpansion{Obreve} {}
+\exportsortexpansion{obreve} {}
+\exportsortexpansion{Ubreve} {}
+\exportsortexpansion{ubreve} {}
+
+\exportsortexpansion{Ccaron} {}
+\exportsortexpansion{ccaron} {}
+\exportsortexpansion{Dcaron} {}
+\exportsortexpansion{dcaron} {}
+\exportsortexpansion{Ecaron} {}
+\exportsortexpansion{ecaron} {}
+\exportsortexpansion{Lcaron} {}
+\exportsortexpansion{lcaron} {}
+\exportsortexpansion{Ncaron} {}
+\exportsortexpansion{ncaron} {}
+\exportsortexpansion{Rcaron} {}
+\exportsortexpansion{rcaron} {}
+\exportsortexpansion{Scaron} {}
+\exportsortexpansion{scaron} {}
+\exportsortexpansion{Tcaron} {}
+\exportsortexpansion{tcaron} {}
+\exportsortexpansion{Ycaron} {}
+\exportsortexpansion{ycaron} {}
+\exportsortexpansion{Zcaron} {}
+\exportsortexpansion{zcaron} {}
+
+\exportsortexpansion{Lstroke} {}
+\exportsortexpansion{lstroke} {}
+\exportsortexpansion{Ostroke} {}
+\exportsortexpansion{ostroke} {}
+
+\exportsortexpansion{aumlaut} {}
+\exportsortexpansion{eumlaut} {}
+\exportsortexpansion{iumlaut} {}
+\exportsortexpansion{oumlaut} {}
+\exportsortexpansion{uumlaut} {}
+
+\exportsortexpansion{Aumlaut} {}
+\exportsortexpansion{Eumlaut} {}
+\exportsortexpansion{Iumlaut} {}
+\exportsortexpansion{Oumlaut} {}
+\exportsortexpansion{Uumlaut} {}
+
+\exportsortexpansion{scommaaccent} {}
+\exportsortexpansion{Scommaaccent} {}
+\exportsortexpansion{tcommaaccent} {}
+\exportsortexpansion{Tcommaaccent} {}
+
+\exportsortexpansion{Etilde} {}
+\exportsortexpansion{etilde} {}
+
+\exportsortexpansion{Ahook} {}
+\exportsortexpansion{ahook} {}
+\exportsortexpansion{Ehook} {}
+\exportsortexpansion{ehook} {}
+\exportsortexpansion{Ihook} {}
+\exportsortexpansion{ihook} {}
+\exportsortexpansion{Ohook} {}
+\exportsortexpansion{ohook} {}
+\exportsortexpansion{Uhook} {}
+\exportsortexpansion{uhook} {}
+\exportsortexpansion{Yhook} {}
+\exportsortexpansion{yhook} {}
+
+\exportsortexpansion{Acircumflexgrave} {}
+\exportsortexpansion{Acircumflexacute} {}
+\exportsortexpansion{Acircumflextilde} {}
+\exportsortexpansion{Acircumflexhook} {}
+\exportsortexpansion{acircumflexgrave} {}
+\exportsortexpansion{acircumflexacute} {}
+\exportsortexpansion{acircumflextilde} {}
+\exportsortexpansion{acircumflexhook} {}
+\exportsortexpansion{Ecircumflexgrave} {}
+\exportsortexpansion{Ecircumflexacute} {}
+\exportsortexpansion{Ecircumflextilde} {}
+\exportsortexpansion{Ecircumflexhook} {}
+\exportsortexpansion{ecircumflexgrave} {}
+\exportsortexpansion{ecircumflexacute} {}
+\exportsortexpansion{ecircumflextilde} {}
+\exportsortexpansion{ecircumflexhook} {}
+\exportsortexpansion{Ocircumflexgrave} {}
+\exportsortexpansion{Ocircumflexacute} {}
+\exportsortexpansion{Ocircumflextilde} {}
+\exportsortexpansion{Ocircumflexhook} {}
+\exportsortexpansion{ocircumflexgrave} {}
+\exportsortexpansion{ocircumflexacute} {}
+\exportsortexpansion{ocircumflextilde} {}
+\exportsortexpansion{ocircumflexhook} {}
+
+\exportsortexpansion{Abrevegrave} {}
+\exportsortexpansion{Abreveacute} {}
+\exportsortexpansion{Abrevetilde} {}
+\exportsortexpansion{Abrevehook} {}
+\exportsortexpansion{abrevegrave} {}
+\exportsortexpansion{abreveacute} {}
+\exportsortexpansion{abrevetilde} {}
+\exportsortexpansion{abrevehook} {}
+
+\exportsortexpansion{Adotbelow} {}
+\exportsortexpansion{adotbelow} {}
+\exportsortexpansion{Edotbelow} {}
+\exportsortexpansion{edotbelow} {}
+\exportsortexpansion{Idotbelow} {}
+\exportsortexpansion{idotbelow} {}
+\exportsortexpansion{Odotbelow} {}
+\exportsortexpansion{odotbelow} {}
+\exportsortexpansion{Udotbelow} {}
+\exportsortexpansion{udotbelow} {}
+\exportsortexpansion{Ydotbelow} {}
+\exportsortexpansion{ydotbelow} {}
+\exportsortexpansion{Ohorndotbelow} {}
+\exportsortexpansion{ohorndotbelow} {}
+\exportsortexpansion{Uhorndotbelow} {}
+\exportsortexpansion{uhorndotbelow} {}
+
+\exportsortexpansion{Acircumflexdotbelow} {}
+\exportsortexpansion{acircumflexdotbelow} {}
+\exportsortexpansion{Ecircumflexdotbelow} {}
+\exportsortexpansion{ecircumflexdotbelow} {}
+\exportsortexpansion{Ocircumflexdotbelow} {}
+\exportsortexpansion{ocircumflexdotbelow} {}
+\exportsortexpansion{Abrevedotbelow} {}
+\exportsortexpansion{abrevedotbelow} {}
+
+\exportsortexpansion{Ohorn} {}
+\exportsortexpansion{Ohorngrave} {}
+\exportsortexpansion{Ohornacute} {}
+\exportsortexpansion{Ohorntilde} {}
+\exportsortexpansion{Ohornhook } {}
+\exportsortexpansion{ohorn} {}
+\exportsortexpansion{ohorngrave} {}
+\exportsortexpansion{ohornacute} {}
+\exportsortexpansion{ohorntilde} {}
+\exportsortexpansion{ohornhook } {}
+\exportsortexpansion{Uhorn} {}
+\exportsortexpansion{Uhorngrave} {}
+\exportsortexpansion{Uhornacute} {}
+\exportsortexpansion{Uhorntilde} {}
+\exportsortexpansion{Uhornhook } {}
+\exportsortexpansion{uhorn} {}
+\exportsortexpansion{uhorngrave} {}
+\exportsortexpansion{uhornacute} {}
+\exportsortexpansion{uhorntilde} {}
+\exportsortexpansion{uhornhook} {}
+
+\exportsortexpansion{eszett} {ssharp}
+\exportsortexpansion{Eszett} {Ssharp}
+
+\exportsortexpansion{lslash} {lstroke}
+\exportsortexpansion{Lslash} {Lstroke}
+\exportsortexpansion{dslash} {dstroke}
+\exportsortexpansion{Dslash} {Dstroke}
+\exportsortexpansion{oslash} {ostroke}
+\exportsortexpansion{Oslash} {Ostroke}
+
+\exportsortexpansion{dcroat} {dstroke}
+\exportsortexpansion{Dcroat} {Dstroke}
+
+% more
+
+\exportsortshortcut{\^ A} {\Acircumflex} \exportsortshortcut{\^ a} {\acircumflex}
+\exportsortshortcut{\^ C} {\Ccircumflex} \exportsortshortcut{\^ c} {\ccircumflex}
+\exportsortshortcut{\^ E} {\Ecircumflex} \exportsortshortcut{\^ e} {\ecircumflex}
+\exportsortshortcut{\^ G} {\Gcircumflex} \exportsortshortcut{\^ g} {\gcircumflex}
+\exportsortshortcut{\^ H} {\Hcircumflex} \exportsortshortcut{\^ h} {\hcircumflex}
+\exportsortshortcut{\^ I} {\Icircumflex} \exportsortshortcut{\^ i} {\icircumflex} \exportsortshortcut{\^\i} {\icircumflex}
+\exportsortshortcut{\^ J} {\Jcircumflex} \exportsortshortcut{\^ j} {\jcircumflex} \exportsortshortcut{\^\j} {\jcircumflex}
+\exportsortshortcut{\^ O} {\Ocircumflex} \exportsortshortcut{\^ o} {\ocircumflex}
+\exportsortshortcut{\^ S} {\Scircumflex} \exportsortshortcut{\^ s} {\scircumflex}
+\exportsortshortcut{\^ U} {\Ucircumflex} \exportsortshortcut{\^ u} {\ucircumflex}
+\exportsortshortcut{\^ W} {\Wcircumflex} \exportsortshortcut{\^ w} {\wcircumflex}
+\exportsortshortcut{\^ Y} {\Ycircumflex} \exportsortshortcut{\^ y} {\ycircumflex}
+
+\exportsortshortcut{\` A} {\Agrave} \exportsortshortcut{\` a} {\agrave}
+\exportsortshortcut{\` E} {\Egrave} \exportsortshortcut{\` e} {\egrave}
+\exportsortshortcut{\` I} {\Igrave} \exportsortshortcut{\` i} {\igrave} \exportsortshortcut{\`\i} {\igrave}
+\exportsortshortcut{\` O} {\Ograve} \exportsortshortcut{\` o} {\ograve}
+\exportsortshortcut{\` U} {\Ugrave} \exportsortshortcut{\` u} {\ugrave}
+\exportsortshortcut{\` Y} {\Ygrave} \exportsortshortcut{\` y} {\ygrave}
+
+\exportsortshortcut{\~ A} {\Atilde} \exportsortshortcut{\~ a} {\atilde}
+\exportsortshortcut{\~ I} {\Itilde} \exportsortshortcut{\~ i} {\itilde} \exportsortshortcut{\~\i} {\itilde}
+\exportsortshortcut{\~ O} {\Otilde} \exportsortshortcut{\~ o} {\otilde}
+\exportsortshortcut{\~ U} {\Utilde} \exportsortshortcut{\~ u} {\utilde}
+
+\exportsortshortcut{\" A} {\Adiaeresis} \exportsortshortcut{\" a} {\adiaeresis}
+\exportsortshortcut{\" E} {\Ediaeresis} \exportsortshortcut{\" e} {\ediaeresis}
+\exportsortshortcut{\" I} {\Idiaeresis} \exportsortshortcut{\" i} {\idiaeresis} \exportsortshortcut{\"\i} {\idiaeresis}
+\exportsortshortcut{\" O} {\Odiaeresis} \exportsortshortcut{\" o} {\odiaeresis}
+\exportsortshortcut{\" U} {\Udiaeresis} \exportsortshortcut{\" u} {\udiaeresis}
+\exportsortshortcut{\" Y} {\Ydiaeresis} \exportsortshortcut{\" y} {\ydiaeresis}
+
+\exportsortshortcut{\' A} {\Aacute} \exportsortshortcut{\' a} {\aacute}
+\exportsortshortcut{\' C} {\Cacute} \exportsortshortcut{\' c} {\cacute}
+\exportsortshortcut{\' E} {\Eacute} \exportsortshortcut{\' e} {\eacute}
+\exportsortshortcut{\' I} {\Iacute} \exportsortshortcut{\' i} {\iacute} \exportsortshortcut{\'\i} {\iacute}
+\exportsortshortcut{\' L} {\Lacute} \exportsortshortcut{\' l} {\lacute}
+\exportsortshortcut{\' N} {\Nacute} \exportsortshortcut{\' n} {\nacute}
+\exportsortshortcut{\' O} {\Oacute} \exportsortshortcut{\' o} {\oacute}
+\exportsortshortcut{\' R} {\Racute} \exportsortshortcut{\' r} {\racute}
+\exportsortshortcut{\' S} {\Sacute} \exportsortshortcut{\' s} {\sacute}
+\exportsortshortcut{\' U} {\Uacute} \exportsortshortcut{\' u} {\uacute}
+\exportsortshortcut{\' Y} {\Yacute} \exportsortshortcut{\' y} {\yacute}
+\exportsortshortcut{\' Z} {\Zacute} \exportsortshortcut{\' z} {\zacute}
+
+\exportsortshortcut{\. C} {\Cdotaccent} \exportsortshortcut{\. c} {\cdotaccent}
+\exportsortshortcut{\. E} {\Edotaccent} \exportsortshortcut{\. e} {\edotaccent}
+\exportsortshortcut{\. G} {\Gdotaccent} \exportsortshortcut{\. g} {\gdotaccent}
+\exportsortshortcut{\. I} {\Idotaccent} \exportsortshortcut{\. i} {\idotaccent} \exportsortshortcut{\.\i} {\idotaccent}
+\exportsortshortcut{\. Z} {\Zdotaccent} \exportsortshortcut{\. z} {\zdotaccent}
+
+\exportsortshortcut{\= A} {\Amacron} \exportsortshortcut{\= a} {\amacron}
+\exportsortshortcut{\= E} {\Emacron} \exportsortshortcut{\= e} {\emacron}
+\exportsortshortcut{\= I} {\Imacron} \exportsortshortcut{\= i} {\imacron} \exportsortshortcut{\=\i} {\imacron}
+\exportsortshortcut{\= O} {\Omacron} \exportsortshortcut{\= o} {\omacron}
+\exportsortshortcut{\= U} {\Umacron} \exportsortshortcut{\= u} {\umacron}
+
+\exportsortshortcut{\c C} {\Ccedilla} \exportsortshortcut{\c c} {\ccedilla}
+\exportsortshortcut{\c K} {\Kcedilla} \exportsortshortcut{\c k} {\kcedilla}
+\exportsortshortcut{\c L} {\Lcedilla} \exportsortshortcut{\c l} {\lcedilla}
+\exportsortshortcut{\c N} {\Ncedilla} \exportsortshortcut{\c n} {\ncedilla}
+\exportsortshortcut{\c R} {\Rcedilla} \exportsortshortcut{\c r} {\rcedilla}
+\exportsortshortcut{\c S} {\Scedilla} \exportsortshortcut{\c s} {\scedilla}
+\exportsortshortcut{\c T} {\Tcedilla} \exportsortshortcut{\c t} {\tcedilla}
+
+\exportsortshortcut{\H O} {\Ohungarumlaut} \exportsortshortcut{\H o} {\ohungarumlaut}
+\exportsortshortcut{\H u} {\uhungarumlaut} \exportsortshortcut{\H U} {\Uhungarumlaut}
+
+\exportsortshortcut{\k A} {\Aogonek} \exportsortshortcut{\k a} {\aogonek}
+\exportsortshortcut{\k E} {\Eogonek} \exportsortshortcut{\k e} {\eogonek}
+\exportsortshortcut{\k I} {\Iogonek} \exportsortshortcut{\k i} {\iogonek}
+\exportsortshortcut{\k U} {\Uogonek} \exportsortshortcut{\k u} {\uogonek}
+
+\exportsortshortcut{\r A} {\Aring} \exportsortshortcut{\r a} {\aring}
+\exportsortshortcut{\r U} {\Uring} \exportsortshortcut{\r u} {\uring}
+
+\exportsortshortcut{\u A} {\Abreve} \exportsortshortcut{\u a} {\abreve}
+\exportsortshortcut{\u E} {\Ebreve} \exportsortshortcut{\u e} {\ebreve}
+\exportsortshortcut{\u G} {\Gbreve} \exportsortshortcut{\u g} {\gbreve}
+\exportsortshortcut{\u I} {\Ibreve} \exportsortshortcut{\u i} {\ibreve} \exportsortshortcut{\u\i} {\ibreve}
+\exportsortshortcut{\u O} {\Obreve} \exportsortshortcut{\u o} {\obreve}
+\exportsortshortcut{\u U} {\Ubreve} \exportsortshortcut{\u u} {\ubreve}
+
+\exportsortshortcut{\v C} {\Ccaron} \exportsortshortcut{\v c} {\ccaron}
+\exportsortshortcut{\v D} {\Dcaron} \exportsortshortcut{\v d} {\dcaron}
+\exportsortshortcut{\v E} {\Ecaron} \exportsortshortcut{\v e} {\ecaron}
+\exportsortshortcut{\v L} {\Lcaron} \exportsortshortcut{\v l} {\lcaron}
+\exportsortshortcut{\v N} {\Ncaron} \exportsortshortcut{\v n} {\ncaron}
+\exportsortshortcut{\v R} {\Rcaron} \exportsortshortcut{\v r} {\rcaron}
+\exportsortshortcut{\v S} {\Scaron} \exportsortshortcut{\v s} {\scaron}
+\exportsortshortcut{\v T} {\Tcaron} \exportsortshortcut{\v t} {\tcaron}
+\exportsortshortcut{\v Z} {\Zcaron} \exportsortshortcut{\v z} {\zcaron}
\endinput
diff --git a/tex/context/base/sort-ini.lua b/tex/context/base/sort-ini.lua
index 3e367173d..b75950860 100644
--- a/tex/context/base/sort-ini.lua
+++ b/tex/context/base/sort-ini.lua
@@ -1,8 +1,10 @@
--- filename : sort-ini.lua
--- comment : companion to sort-ini.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['sort-ini'] = {
+ version = 1.001,
+ comment = "companion to sort-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-- todo:
--
@@ -11,7 +13,9 @@
-- texutil compatible
-- always expand to utf
-if not versions then versions = { } end versions['sort-ini'] = 1.001
+local utf = unicode.utf8
+local gsub = string.gsub
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
sorters = { }
sorters.comparers = { }
@@ -21,8 +25,7 @@ sorters.mappings = { }
sorters.replacements = { }
sorters.language = 'en'
-function sorters.comparers.basic(a,b,i) -- [2] has entry, key, cmp
- local sort_a, sort_b = a[2][i][3], b[2][i][3]
+function sorters.comparers.basic(sort_a,sort_b)
if #sort_a > #sort_b then
if #sort_b == 0 then
return 1
@@ -62,67 +65,35 @@ function sorters.comparers.basic(a,b,i) -- [2] has entry, key, cmp
return -1
end
end
- sort_a, sort_b = a[2][i][2], b[2][i][2]
- if sort_a == "" then sort_a = a[2][i][1] end
- if sort_b == "" then sort_b = b[2][i][1] end
- if sort_a < sort_b then
- return -1
- elseif sort_a > sort_b then
- return 1
- else
- return 0
- end
- end
-end
-
-function sorters.prepare(data,split,n)
- local strip = sorters.strip
- for k,v in ipairs(data) do
- for i=1,n do
- local vv = v[2][i]
- if vv then
- if vv[2] then
- if vv[2] ~= "" then
- vv[3] = split(strip(vv[2]))
- else
- vv[3] = split(strip(vv[1]))
- end
- else
- vv[2] = { }
- vv[3] = split(strip(vv[1]))
- end
- else
- v[2][i] = { {}, {}, {} }
- end
- end
+ return 0
end
end
function sorters.strip(str) -- todo: only letters and such utf.gsub("([^%w%d])","")
- str = str:gsub("\\%S*","")
- str = str:gsub("[%s%[%](){}%$\"\']*","")
- str = str:gsub("(%d+)",function(s) return (" "):rep(10-#s) .. s end) -- sort numbers properly
+ str = gsub(str,"\\%S*","")
+ str = gsub(str,"[%s%[%](){}%$\"\']*","")
+ str = gsub(str,"(%d+)",function(s) return (" "):rep(10-#s) .. s end) -- sort numbers properly
return str
end
sorters.defaultlanguage = 'en'
-function sorters.splitters.utf(str)
+function sorters.splitters.utf(str) -- brrr, todo: language
local r = sorters.replacements[sorters.language] or sorters.replacements[sorters.defaultlanguage] or { }
local m = sorters.mappings [sorters.language] or sorters.mappings [sorters.defaultlanguage] or { }
local u = characters.uncompose
local b = utf.byte
local t = { }
- for _,v in pairs(r) do
- str = str:gsub(v[1],v[2])
+ for _,v in next, r do
+ str = gsub(str,v[1],v[2])
end
- for c in str:utfcharacters() do
+ for c in utfcharacters(str) do
if m[c] then
t[#t+1] = m[c]
elseif #c == 1 then
t[#t+1] = b(c)
else
- for cc in string.characters(u(c)) do
+ for cc in string.characters(u(c)) do -- utf ?
t[#t+1] = m[cc] or b(cc)
end
end
@@ -130,52 +101,30 @@ function sorters.splitters.utf(str)
return t
end
-function sorters.sort(data,cmp)
- table.sort(data,function(a,b) return cmp(a,b) == -1 end)
+function sorters.sort(entries,cmp)
+ table.sort(entries,function(a,b) return cmp(a,b) == -1 end)
end
-function sorters.cleanup(data)
- for k,v in ipairs(data) do
- for kk,vv in ipairs(v[2]) do
- if vv and #vv[1] == 0 then
- v[1][kk] = nil
- else
- vv[3] = nil
- end
- end
- for kk,vv in pairs(v) do
- if vv == "" then
- v[kk] = nil
- end
- end
- end
-end
+-- temp workaround (is gone)
-function sorters.unique(data)
- local prev, last = nil, 0
- for _,v in ipairs(data) do
- if not prev or not table.are_equal(prev,v,2,3) then -- check range
- last = last + 1
- data[last] = v
- prev = v
- end
- end
- for i=last+1,#data do
- data[i] = nil
- end
+function sorters.process()
+ -- gone
end
-function sorters.process(kind,data)
- if data.entries then
- if not data.sorted then
- sorters.language = data.language or sorters.language
- sorters[kind].prepare(data.entries)
- sorters[kind].sort(data.entries)
- sorters[kind].unique(data.entries)
- data.sorted = true
- end
- return sorters[kind].flush(sorters[kind].finalize(data.entries),data.class,data.flush)
- else
- return { }
- end
-end
+-- was:
+
+--~ function sorters.process(kind,data)
+--~ if data.entries then
+--~ if not data.sorted then
+--~ sorters.language = data.language or sorters.language
+--~ sorters[kind].prepare(data.entries)
+--~ sorters[kind].sort(data.entries)
+--~ sorters[kind].unique(data.entries)
+--~ data.sorted = true
+--~ end
+--~ return sorters[kind].flush(sorters[kind].finalize(data.entries),data.class,data.flush)
+--~ else
+--~ return { }
+--~ end
+--~ end
+
diff --git a/tex/context/base/sort-ini.mkii b/tex/context/base/sort-ini.mkii
index 1a8a5a543..f26f4febe 100644
--- a/tex/context/base/sort-ini.mkii
+++ b/tex/context/base/sort-ini.mkii
@@ -1,7 +1,7 @@
%D \module
%D [ file=sort-ini,
%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
+%D title=\CONTEXT\ Sorting Macros,
%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -17,6 +17,12 @@
%D used with the new texutil functionality. This module defines a few
%D auxiliary macros.
+\writestatus{loading}{ConTeXt Sorting Macros / Initialization}
+
+%D This module replaces existing sort key handling and is meant to be
+%D used with the new texutil functionality. This module defines a few
+%D auxiliary macros.
+
\ifx\exportsortaction\undefined \else \endinput \fi
%D The sorting method is largely bases on the one used in the old version
@@ -72,6 +78,14 @@
\unprotect
+\def\savesortkeys
+ {\ifproductionrun
+ \the\everysavesortkeys
+ \global\everysavesortkeys\emptytoks
+ \fi}
+
+\appendtoks \savesortkeys \to \everyshipout
+
\let\currentexportclass\empty
\def\exportsortaction#1#2#3%
diff --git a/tex/context/base/sort-ini.mkiv b/tex/context/base/sort-ini.mkiv
index 9c87edb11..a4dc2f6ba 100644
--- a/tex/context/base/sort-ini.mkiv
+++ b/tex/context/base/sort-ini.mkiv
@@ -11,11 +11,9 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\registerctxluafile{sort-ini}{1.001}
-
-\let\savesortlanguage\gobbleoneargument
+\writestatus{loading}{ConTeXt Sorting Macros / Initialization}
-\readfile{sort-def.tex}{}{} % runtime loaded in mkii
-\readfile{sort-lan.tex}{}{} % runtime loaded in mkii
+\registerctxluafile{sort-ini}{1.001}
+\registerctxluafile{sort-lan}{1.001}
\endinput
diff --git a/tex/context/base/sort-ini.tex b/tex/context/base/sort-ini.tex
deleted file mode 100644
index 2baa609fb..000000000
--- a/tex/context/base/sort-ini.tex
+++ /dev/null
@@ -1,32 +0,0 @@
-%D \module
-%D [ file=sort-ini,
-%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
-%D subtitle=Initialization,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module replaces existing sort key handling and is meant to be
-%D used with the new texutil functionality. This module defines a few
-%D auxiliary macros.
-
-\writestatus{loading}{Context Sorting Macros (ini)}
-
-\newevery \everysavesortkeys \relax
-
-\def\savesortkeys
- {\ifproductionrun
- \the\everysavesortkeys
- \global\everysavesortkeys\emptytoks
- \fi}
-
-\appendtoks \savesortkeys \to \everyshipout
-
-\loadmarkfile{sort-ini}
-
-\endinput
diff --git a/tex/context/base/sort-lan.lua b/tex/context/base/sort-lan.lua
index 8d8fdb1a0..394cbabe1 100644
--- a/tex/context/base/sort-lan.lua
+++ b/tex/context/base/sort-lan.lua
@@ -1,10 +1,12 @@
--- filename : sort-lan.lua
--- comment : companion to sort-lan.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['sort-lan'] = {
+ version = 1.001,
+ comment = "companion to sort-lan.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['sort-lan'] = 1.001
+local utf = unicode.utf8
-- this is a rather preliminary and incomplete file
-- maybe we should load this kind of stuff runtime
@@ -51,9 +53,8 @@ sorters.mappings ['nl'] = sorters.mappings['en']
-- czech
-
-local uc = unicode.utf8.char
-local ub = unicode.utf8.byte
+local uc = utf.char
+local ub = utf.byte
sorters.replacements['cz'] = {
[1] = { "ch", uc(0xFF01) }
diff --git a/tex/context/base/sort-lan.mkii b/tex/context/base/sort-lan.mkii
deleted file mode 100644
index ad5232b02..000000000
--- a/tex/context/base/sort-lan.mkii
+++ /dev/null
@@ -1,203 +0,0 @@
-%D \module
-%D [ file=sort-lan,
-%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
-%D subtitle=Language Definitions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% for testing:
-
-\startmode[sortorder-en]
- \exportsortexpansion{aacute}{a+1}
- \exportsortexpansion{Aacute}{A+2}
- \exportsortexpansion{agrave}{a+1}
- \exportsortexpansion{Agrave}{A+2}
-\stopmode
-
-%D This module replaces existing sort key handling and is meant to be
-%D used with the new texutil functionality. Here we define the language
-%D specific sort rules.
-
-% slovenian
-%
-% a-c, ccaron, cacute, d, dstroke, e-s, scaron, t-z, zcaron
-
-% \enableregime[utf]
-% \mainlanguage[sl]
-% \starttext
-% \ccaron\index{\ccaron\space 1}
-% \Ccaron\index{\Ccaron\space 1}
-% č\index{č 2}
-% Č\index{Č 2}
-% \v c\index{\v c 3}
-% \v C\index{\v C 3}
-% \placeindex
-% \stoptext
-
-% \startmode[sortorder-sl]
-% \exportsortexpansion {ccaron} {cz}
-% \exportsortexpansion {cacute} {czz}
-% \exportsortexpansion {dstroke} {dz}
-% \exportsortexpansion {scaron} {sz}
-% \exportsortexpansion {zacron} {zz}
-
-% \exportsortdivision {cz} {ccaron}
-% \exportsortdivision {czz} {cacute}
-% \exportsortdivision {dz} {dstroke}
-% \exportsortdivision {sz} {scaron}
-% \exportsortdivision {zz} {zacron}
-% \stopmode
-%
-% \startmode[sortorder-sl]
-% \exportsortexpansion {ccaron} {c+1}
-% \exportsortexpansion {cacute} {c+2}
-% \exportsortexpansion {dstroke} {d+1}
-% \exportsortexpansion {scaron} {s+1}
-% \exportsortexpansion {zacron} {z+1}
-%
-% \exportsortdivision {c+1} {ccaron}
-% \exportsortdivision {c+2} {cacute}
-% \exportsortdivision {d+1} {dstroke}
-% \exportsortdivision {s+1} {scaron}
-% \exportsortdivision {z+1} {zacron}
-% \stopmode
-
-\startmode[sortorder-sl]
- \exportsortrule {ccaron} {c+1}
- \exportsortrule {cacute} {c+2}
- \exportsortrule {dstroke} {d+1}
- \exportsortrule {scaron} {s+1}
- \exportsortrule {zacron} {z+1}
-\stopmode
-
-% finnish
-%
-% a-u, v+w sorted together, x-z, aring, adiaeresis, odiaeresis
-
-\startmode[sortorder-fi]
- \exportsortrule {v} {w}
- \exportsortrule {aring} {z+1}
- \exportsortrule {adiaeresis} {z+2}
- \exportsortrule {odiaeresis} {z+3}
-\stopmode
-
-% swedish
-%
-% a-z, aring, adiaeresis, odiaeresis
-
-% \mainlanguage[sv]
-% \starttext
-% a\index{a}
-% a\index{a}
-% z\index{z}
-% z\index{z}
-% q\index{q}
-% q\index{q}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \index{}
-% \aring\index{\aring}
-% \adiaeresis\index{\adiaeresis}
-% \odiaeresis\index{\odiaeresis}
-% A\index{A}
-% \index{}
-% \index{}
-% \index{}
-% \Aring\index{\Aring}
-% \Adiaeresis\index{\Adiaeresis}
-% \Odiaeresis\index{\Odiaeresis}
-% \placeindex
-% \stoptext
-
-\startmode[sortorder-sv]
- \exportsortrule {aring} {z+1}
- \exportsortrule {adiaeresis} {z+2}
- \exportsortrule {odiaeresis} {z+3}
-\stopmode
-
-% norwegian, danish
-%
-% a-z, aeligature, oslash, aring
-
-\startmode[sortorder-no,sortorder-da]
- \exportsortrule {aeligature} {z+1}
- \exportsortrule {oslash} {z+2}
- \exportsortrule {aring} {z+3}
-\stopmode
-
-% islandic
-%
-% a, aacute, b, c, d, eth, e, eacute, f-i, iacute, j-o, oacute, p-u, uacute, v, w (?), x, y, yacute, z, aeligature, oslash, thorn
-
-% estonian
-%
-% a-s, scaron, z, zcaron, t-w, otilde, adiaeresis, odiaeresis, udiaeresis, x, y
-
-% czech
-%
-% a) make a single group for: "a", "", "A", ""
-% b) make a different two groups for: "c", "C" and "c", "C"
-% c) sorting rule: "A" < "" < "a" < "" < "C" < "c" < "C" < "c"
-% d) sorting rule: "h" < "ch" < "i" ("c" < "h")
-
-\gdef\czsortdivisionch{ch}
-\gdef\czsortdivisionCh{Ch}
-
-\startmode[sortorder-cz]
- \exportsortexpansion {aacute} {a+1}
- \exportsortexpansion {Aacute} {A+1}
- \exportsortexpansion {ccaron} {c+1}
- \exportsortexpansion {Ccaron} {C+1}
- \exportsortdivision {c+1} {ccaron}
- \exportsortexpansion {dcaron} {d+1}
- \exportsortexpansion {Dcaron} {D+1}
- \exportsortdivision {d+1} {dcaron}
- \exportsortexpansion {eacute} {e+1}
- \exportsortexpansion {Eacute} {E+1}
- \exportsortexpansion {ecaron} {e+2}
- \exportsortexpansion {Ecaron} {E+2}
- \exportsortreduction {ch} {h+1}
- \exportsortexpansion {ch} {h+1}
- \exportsortreduction {Ch} {H+1}
- \exportsortexpansion {Ch} {H+1}
- \exportsortdivision {h+1} {czsortdivisionch}
- \exportsortexpansion {iacute} {i+1}
- \exportsortexpansion {Iacute} {I+1}
- \exportsortexpansion {ncaron} {n+1}
- \exportsortexpansion {Ncaron} {N+1}
- \exportsortdivision {n+1} {ncaron}
- \exportsortexpansion {oacute} {o+1}
- \exportsortexpansion {Oacute} {O+1}
- \exportsortexpansion {rcaron} {r+1}
- \exportsortexpansion {Rcaron} {R+1}
- \exportsortdivision {r+1} {rcaron}
- \exportsortexpansion {scaron} {s+1}
- \exportsortexpansion {Scaron} {S+1}
- \exportsortdivision {s+1} {scaron}
- \exportsortexpansion {tcaron} {t+1}
- \exportsortexpansion {Tcaron} {T+1}
- \exportsortdivision {t+1} {tcaron}
- \exportsortexpansion {uacute} {u+1}
- \exportsortexpansion {Uacute} {U+1}
- \exportsortexpansion {uring} {u+2}
- \exportsortexpansion {Uring} {U+2}
- \exportsortexpansion {yacute} {y+1}
- \exportsortexpansion {Yacute} {Y+1}
- \exportsortexpansion {zcaron} {z+1}
- \exportsortexpansion {Zcaron} {Z+1}
- \exportsortdivision {z+1} {zcaron}
-\stopmode
-
-\endinput
diff --git a/tex/context/base/sort-lan.mkiv b/tex/context/base/sort-lan.mkiv
deleted file mode 100644
index 918f7f9b7..000000000
--- a/tex/context/base/sort-lan.mkiv
+++ /dev/null
@@ -1,16 +0,0 @@
-%D \module
-%D [ file=sort-lan,
-%D version=2005.08.08,
-%D title=\CONTEXT\ Sort Macros,
-%D subtitle=Language Definitions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\registerctxluafile{sort-lan}{1.001}
-
-\endinput
diff --git a/tex/context/base/sort-lan.tex b/tex/context/base/sort-lan.tex
index 1eadae407..ad5232b02 100644
--- a/tex/context/base/sort-lan.tex
+++ b/tex/context/base/sort-lan.tex
@@ -11,8 +11,193 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Sorting Macros (languages)}
+% for testing:
-\loadmarkfile{sort-lan}
+\startmode[sortorder-en]
+ \exportsortexpansion{aacute}{a+1}
+ \exportsortexpansion{Aacute}{A+2}
+ \exportsortexpansion{agrave}{a+1}
+ \exportsortexpansion{Agrave}{A+2}
+\stopmode
+
+%D This module replaces existing sort key handling and is meant to be
+%D used with the new texutil functionality. Here we define the language
+%D specific sort rules.
+
+% slovenian
+%
+% a-c, ccaron, cacute, d, dstroke, e-s, scaron, t-z, zcaron
+
+% \enableregime[utf]
+% \mainlanguage[sl]
+% \starttext
+% \ccaron\index{\ccaron\space 1}
+% \Ccaron\index{\Ccaron\space 1}
+% č\index{č 2}
+% Č\index{Č 2}
+% \v c\index{\v c 3}
+% \v C\index{\v C 3}
+% \placeindex
+% \stoptext
+
+% \startmode[sortorder-sl]
+% \exportsortexpansion {ccaron} {cz}
+% \exportsortexpansion {cacute} {czz}
+% \exportsortexpansion {dstroke} {dz}
+% \exportsortexpansion {scaron} {sz}
+% \exportsortexpansion {zacron} {zz}
+
+% \exportsortdivision {cz} {ccaron}
+% \exportsortdivision {czz} {cacute}
+% \exportsortdivision {dz} {dstroke}
+% \exportsortdivision {sz} {scaron}
+% \exportsortdivision {zz} {zacron}
+% \stopmode
+%
+% \startmode[sortorder-sl]
+% \exportsortexpansion {ccaron} {c+1}
+% \exportsortexpansion {cacute} {c+2}
+% \exportsortexpansion {dstroke} {d+1}
+% \exportsortexpansion {scaron} {s+1}
+% \exportsortexpansion {zacron} {z+1}
+%
+% \exportsortdivision {c+1} {ccaron}
+% \exportsortdivision {c+2} {cacute}
+% \exportsortdivision {d+1} {dstroke}
+% \exportsortdivision {s+1} {scaron}
+% \exportsortdivision {z+1} {zacron}
+% \stopmode
+
+\startmode[sortorder-sl]
+ \exportsortrule {ccaron} {c+1}
+ \exportsortrule {cacute} {c+2}
+ \exportsortrule {dstroke} {d+1}
+ \exportsortrule {scaron} {s+1}
+ \exportsortrule {zacron} {z+1}
+\stopmode
+
+% finnish
+%
+% a-u, v+w sorted together, x-z, aring, adiaeresis, odiaeresis
+
+\startmode[sortorder-fi]
+ \exportsortrule {v} {w}
+ \exportsortrule {aring} {z+1}
+ \exportsortrule {adiaeresis} {z+2}
+ \exportsortrule {odiaeresis} {z+3}
+\stopmode
+
+% swedish
+%
+% a-z, aring, adiaeresis, odiaeresis
+
+% \mainlanguage[sv]
+% \starttext
+% a\index{a}
+% a\index{a}
+% z\index{z}
+% z\index{z}
+% q\index{q}
+% q\index{q}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \index{}
+% \aring\index{\aring}
+% \adiaeresis\index{\adiaeresis}
+% \odiaeresis\index{\odiaeresis}
+% A\index{A}
+% \index{}
+% \index{}
+% \index{}
+% \Aring\index{\Aring}
+% \Adiaeresis\index{\Adiaeresis}
+% \Odiaeresis\index{\Odiaeresis}
+% \placeindex
+% \stoptext
+
+\startmode[sortorder-sv]
+ \exportsortrule {aring} {z+1}
+ \exportsortrule {adiaeresis} {z+2}
+ \exportsortrule {odiaeresis} {z+3}
+\stopmode
+
+% norwegian, danish
+%
+% a-z, aeligature, oslash, aring
+
+\startmode[sortorder-no,sortorder-da]
+ \exportsortrule {aeligature} {z+1}
+ \exportsortrule {oslash} {z+2}
+ \exportsortrule {aring} {z+3}
+\stopmode
+
+% islandic
+%
+% a, aacute, b, c, d, eth, e, eacute, f-i, iacute, j-o, oacute, p-u, uacute, v, w (?), x, y, yacute, z, aeligature, oslash, thorn
+
+% estonian
+%
+% a-s, scaron, z, zcaron, t-w, otilde, adiaeresis, odiaeresis, udiaeresis, x, y
+
+% czech
+%
+% a) make a single group for: "a", "", "A", ""
+% b) make a different two groups for: "c", "C" and "c", "C"
+% c) sorting rule: "A" < "" < "a" < "" < "C" < "c" < "C" < "c"
+% d) sorting rule: "h" < "ch" < "i" ("c" < "h")
+
+\gdef\czsortdivisionch{ch}
+\gdef\czsortdivisionCh{Ch}
+
+\startmode[sortorder-cz]
+ \exportsortexpansion {aacute} {a+1}
+ \exportsortexpansion {Aacute} {A+1}
+ \exportsortexpansion {ccaron} {c+1}
+ \exportsortexpansion {Ccaron} {C+1}
+ \exportsortdivision {c+1} {ccaron}
+ \exportsortexpansion {dcaron} {d+1}
+ \exportsortexpansion {Dcaron} {D+1}
+ \exportsortdivision {d+1} {dcaron}
+ \exportsortexpansion {eacute} {e+1}
+ \exportsortexpansion {Eacute} {E+1}
+ \exportsortexpansion {ecaron} {e+2}
+ \exportsortexpansion {Ecaron} {E+2}
+ \exportsortreduction {ch} {h+1}
+ \exportsortexpansion {ch} {h+1}
+ \exportsortreduction {Ch} {H+1}
+ \exportsortexpansion {Ch} {H+1}
+ \exportsortdivision {h+1} {czsortdivisionch}
+ \exportsortexpansion {iacute} {i+1}
+ \exportsortexpansion {Iacute} {I+1}
+ \exportsortexpansion {ncaron} {n+1}
+ \exportsortexpansion {Ncaron} {N+1}
+ \exportsortdivision {n+1} {ncaron}
+ \exportsortexpansion {oacute} {o+1}
+ \exportsortexpansion {Oacute} {O+1}
+ \exportsortexpansion {rcaron} {r+1}
+ \exportsortexpansion {Rcaron} {R+1}
+ \exportsortdivision {r+1} {rcaron}
+ \exportsortexpansion {scaron} {s+1}
+ \exportsortexpansion {Scaron} {S+1}
+ \exportsortdivision {s+1} {scaron}
+ \exportsortexpansion {tcaron} {t+1}
+ \exportsortexpansion {Tcaron} {T+1}
+ \exportsortdivision {t+1} {tcaron}
+ \exportsortexpansion {uacute} {u+1}
+ \exportsortexpansion {Uacute} {U+1}
+ \exportsortexpansion {uring} {u+2}
+ \exportsortexpansion {Uring} {U+2}
+ \exportsortexpansion {yacute} {y+1}
+ \exportsortexpansion {Yacute} {Y+1}
+ \exportsortexpansion {zcaron} {z+1}
+ \exportsortexpansion {Zcaron} {Z+1}
+ \exportsortdivision {z+1} {zcaron}
+\stopmode
\endinput
diff --git a/tex/context/base/spec-def.mkii b/tex/context/base/spec-def.mkii
deleted file mode 100644
index a151461c4..000000000
--- a/tex/context/base/spec-def.mkii
+++ /dev/null
@@ -1,20 +0,0 @@
-%D \module
-%D [ file=spec-def,
-%D version=1996.01.25,
-%D title=\CONTEXT\ Special Macros,
-%D subtitle=Definitions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This file is empty.
-
-\appendtoks
- \setupoutput[dvips]%
-\to \everydump
-
-\endinput
diff --git a/tex/context/base/spec-def.mkiv b/tex/context/base/spec-def.mkiv
deleted file mode 100644
index eaf20753c..000000000
--- a/tex/context/base/spec-def.mkiv
+++ /dev/null
@@ -1,23 +0,0 @@
-%D \module
-%D [ file=spec-def,
-%D version=2006.09.18,
-%D title=\CONTEXT\ Special Macros,
-%D subtitle=Definitions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D We load the lua scripts here because we don't want to load
-%D them multiple times.
-
-\registerctxluafile{spec-pdf}{1.001}
-
-\appendtoks
- \setupoutput[pdftex]%
-\to \everydump
-
-\endinput
diff --git a/tex/context/base/spec-def.tex b/tex/context/base/spec-def.tex
index 74fac733a..ad1a9bb1d 100644
--- a/tex/context/base/spec-def.tex
+++ b/tex/context/base/spec-def.tex
@@ -14,7 +14,7 @@
%D This module used to be integrated in \type {spec-ini},
%D but testing optimization is more convenient this way.
-\writestatus{loading}{Context Special Macros / Definitions}
+\writestatus{loading}{ConTeXt Special Macros / Definitions}
\unprotect
@@ -1006,11 +1006,11 @@
%D \setupoutput [pdftex]
%D \stoptyping
-\loadmarkfile{spec-def}
-
%D Please let me know if we need more. From now on we default
%D to:
-% \setupoutput [dvips] % see mkii/mkiv files
+\appendtoks
+ \setupoutput[dvips]%
+\to \everydump
\protect \endinput
diff --git a/tex/context/base/spec-dpx.tex b/tex/context/base/spec-dpx.tex
index 0753d173c..ed49ea843 100644
--- a/tex/context/base/spec-dpx.tex
+++ b/tex/context/base/spec-dpx.tex
@@ -84,6 +84,8 @@
%D
%D A simple one.
+\let\PDFpagexyzspec\relax \def\PDFpagexyzspec{@xpos @ypos 0} % untested
+
\definespecial\dosetuppaper#1#2#3%
{\bgroup
\scratchdimen#2\edef\width {\the\scratchdimen\space}%
@@ -733,7 +735,7 @@
{\vbox to \the\ht#2%
{\vss
\hbox to \the\wd#2%
- {\scratchdimen\wd#2\scratchdimen.5\scratchdimen\hskip-\the\scratchdimen
+ {%\scratchdimen\wd#2\scratchdimen.5\scratchdimen\hskip-\the\scratchdimen
\special{pdf:uxobj @MPPDF::\MPPDFobjectcounter}}}}%
\expanded{\doDVIPDFMXstartobject\zerocount{MPPDF}\MPPDFobjectcounter{\the\wd#2}{\the\ht#2}{\the\dp#2}}%
\finalizeobjectbox#2%
diff --git a/tex/context/base/spec-fdf.mkii b/tex/context/base/spec-fdf.mkii
deleted file mode 100644
index 1ada3e880..000000000
--- a/tex/context/base/spec-fdf.mkii
+++ /dev/null
@@ -1,146 +0,0 @@
-%D \module
-%D [ file=spec-fdf,
-%D version=1998.05.18,
-%D title=\CONTEXT\ \PDF\ Macros,
-%D subtitle=Support Macros,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\chardef\safePDFcode=`-
-
-\def\setPDFdestination#1%
- {\bgroup
- \retainlccodes
- \lccode`\/\safePDFcode \lccode`\#\safePDFcode
- \lccode`\<\safePDFcode \lccode`\>\safePDFcode
- \lccode`\[\safePDFcode \lccode`\]\safePDFcode
- \lccode`\(\safePDFcode \lccode`\)\safePDFcode
- \ifovercomePDFspace
- \lccode`\ \safePDFcode
- \fi
- \ifovercomePDFbugs
- \xdef\PDFdestination{'#1'}%
- \else
- \xdef\PDFdestination{#1}%
- \fi
- % nicer \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}%
- \lowercase\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}%
- \egroup}
-
-%D This is much faster since we don't have to set the full
-%D range of lc-codes; about 5 sec on a 1000mhz PIII for
-%D 20K named destinations "x(x) x"). Of course when you use
-%D page destinations, the saving is nil.
-
-% \doifnotmode{atpragma}{\let\next\setPDFdestination} % experimental
-%
-% \catcode`\/=\@@active \catcode`\#=\@@active
-% \catcode`\<=\@@active \catcode`\>=\@@active
-% \catcode`\[=\@@active \catcode`\]=\@@active
-% \catcode`\(=\@@active \catcode`\)=\@@active
-%
-% \gdef\PDFrepchar{-}
-%
-% \gdef\setPDFdcharacters
-% {\catcode`\/=\@@active \let/\PDFrepchar
-% \catcode`\#=\@@active \let#\PDFrepchar
-% \catcode`\<=\@@active \let<\PDFrepchar
-% \catcode`\>=\@@active \let>\PDFrepchar
-% \catcode`\[=\@@active \let[\PDFrepchar
-% \catcode`\]=\@@active \let]\PDFrepchar
-% \catcode`\(=\@@active \let(\PDFrepchar
-% \catcode`\)=\@@active \let)\PDFrepchar}
-%
-% \egroup
-%
-% \def\setPDFdestination#1% expansion is needed, otherwise embedded
-% {\bgroup % macros will not expand under the new
-% \setPDFdcharacters % catcode regime
-% \ifovercomePDFspace
-% \catcode32=\@@ignore
-% \fi
-% \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}%
-% \scantokens\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}%
-% \egroup}
-%
-% \doifnotmode{atpragma}{\let\setPDFdestination\next} % experimental
-
-%D This is a slow one, that uses \type{\lccode}'s to
-%D change the glyph as well as converts sensisitve ones into a
-%D \PDF\ command sequence, so \type{(} becomes \type{\(}. In
-%D fact we translate the string to lowercase inactive and non
-%D special characters, limit their number and finaly convert
-%D some of the characters to save ones.
-
-\chardef\maxPDFstringsize=60
-
-\def\sanitizePDFstring#1\to#2% bugged
- {\bgroup
- \retainlccodes
- \lccode`( \zerocount \lccode`) \zerocount
- \lccode`< \zerocount \lccode`> \zerocount
- \lccode`[ \zerocount \lccode`] \zerocount
- \lccode`\\\zerocount \lccode`/ \zerocount
- \lowercase{\defconvertedargument\ascii{#1}}%
- % by integrating the split in the loop below
- % \splitofftokens\maxPDFstringsize\from\ascii\to\ascii
- % we diminish the processing time considerably
- \scratchcounter\maxPDFstringsize
- \def\docommand##1%
- {\ifcase\scratchcounter\else
- \advance\scratchcounter \minusone
- \ifcase\lccode`##1\relax
- \xdef#2{#2\expandafter\string\csname##1\endcsname}%
- \else
- \xdef#2{#2##1}%
- \fi
- \fi}%
- %\global\let#2=\empty
- % or to permit #2 to be \ascii too:
- \global\@EA\let\@EA#2\@EA\empty
- \@EA\handletokens\ascii\with\docommand
- \egroup}
-
-% \doifnotmode{atpragma}{\let\next\sanitizePDFstring} % experimental
-%
-% \bgroup
-%
-% \catcode`\.=\@@escape
-%
-% .catcode`./=.@@active
-% .catcode`.<=.@@active .catcode`.>=.@@active
-% .catcode`.[=.@@active .catcode`.]=.@@active
-% .catcode`.(=.@@active .catcode`.)=.@@active
-%
-% .gdef.setPDFscharacters%
-% {.catcode`.\=.@@other
-% .catcode`./=.@@active .def/{.noexpand./}%
-% .catcode`.<=.@@active .def<{.noexpand.<}%
-% .catcode`.>=.@@active .def>{.noexpand.>}%
-% .catcode`.[=.@@active .def[{.noexpand.[}%
-% .catcode`.]=.@@active .def]{.noexpand.]}%
-% .catcode`.(=.@@active .def({.noexpand.(}%
-% .catcode`.)=.@@active .def){.noexpand.)}}
-%
-% .gdef.sanitizePDFstring#1.to#2%
-% {.bgroup
-% .setPDFscharacters
-% .catcode`=.@@escape
-% .edef.next{.strippedcsname#2}%
-% .scantokens{setxvalue{next}{#1}}%
-% .egroup}
-%
-% .egroup
-%
-% \doifnotmode{atpragma}{\let\sanitizePDFstring\next} % experimental
-%
-% There is an unicode variant in spec-tst!
-
-\protect \endinput
diff --git a/tex/context/base/spec-fdf.mkiv b/tex/context/base/spec-fdf.mkiv
deleted file mode 100644
index d6937ec1b..000000000
--- a/tex/context/base/spec-fdf.mkiv
+++ /dev/null
@@ -1,31 +0,0 @@
-%D \module
-%D [ file=spec-fdf,
-%D version=2006.09.18,
-%D title=\CONTEXT\ \PDF\ Macros,
-%D subtitle=Support Macros,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% \setupinteraction[
-% state=start,
-% title={ÀÂÆ ÇÉÈÊË ÎÏÔŒ ÙÜŸ},
-% subtitle={àâæ çéèêë îïôœ ùûüÿ},
-% author={àâæ ÀÂÆ},
-% keyword={àâæ çéèêë îïôœ ùûüÿ}]
-
-\unprotect
-
-\ctxloadluafile{spec-pdf}{}
-
-\PDFunicodetrue \let\enablePDFdocencoding\PDFunicodetrue
-
-\def\setPDFdestination #1{\xdef\PDFdestination{\ctxlua{pdf.cleandestination("\luaescapestring{#1}")}}}
-\def\sanitizePDFencoding#1\to#2{\xdef#2{\ctxlua{pdf.hexify("\luaescapestring{#1}")}}}
-\def\hexifiedPDFstring #1{\ctxlua{pdf.hexify("\luaescapestring{#1}")}}
-
-\protect \endinput
diff --git a/tex/context/base/spec-fdf.tex b/tex/context/base/spec-fdf.tex
index ff801c95f..da29a5b38 100644
--- a/tex/context/base/spec-fdf.tex
+++ b/tex/context/base/spec-fdf.tex
@@ -337,11 +337,14 @@
\def\flushPDFwhateverbox#1#2%
{\doifsomething{#1}{\doPDFpageattribute{/#2Box #1}}}
+\def\flushPDFpageboxes
+ {\flushPDFwhateverbox\currentPDFartbox {Art}%
+ \flushPDFwhateverbox\currentPDFcropbox {Crop}%
+ \flushPDFwhateverbox\currentPDFbleedbox{Bleed}%
+ \flushPDFwhateverbox\currentPDFtrimbox {Trim}}
+
\appendtoksonce
- \flushPDFwhateverbox\currentPDFartbox {Art}%
- \flushPDFwhateverbox\currentPDFcropbox {Crop}%
- \flushPDFwhateverbox\currentPDFbleedbox{Bleed}%
- \flushPDFwhateverbox\currentPDFtrimbox {Trim}%
+ \flushPDFpageboxes
\to \everyshipout
\def\doPDFsetupidentity#1#2#3#4#5#6%
@@ -470,8 +473,6 @@
\def\doPDFstartthisislocation#1%
{\bgroup
\setPDFdestination{#1}%
- %\doifsomething{\PDFdestination}
- % {\doPDFdestination{\PDFdestination}}%
\ifx\PDFdestination\empty \else
\doPDFdestination{\PDFdestination}%
\fi
@@ -701,9 +702,14 @@
\def\doPDFstartexecutecommand#1#2#3#4%
{\doifdefined{PDFexecute#3}
{\bgroup
- \@EA\dogetcommalistelement\@EA1\@EA\from#4\to\argumentA
- \@EA\dogetcommalistelement\@EA2\@EA\from#4\to\argumentB
\edef\argument{#4}%
+ \ifx\argument\empty
+ \let\argumentA\empty
+ \let\argumentB\empty
+ \else
+ \@EA\dogetcommalistelement\@EA1\@EA\from#4\to\argumentA
+ \@EA\dogetcommalistelement\@EA2\@EA\from#4\to\argumentB
+ \fi
\edef\action%
{/S \getvalue{PDFexecute#3}}%
\ifsecondaryreference
@@ -1653,7 +1659,7 @@
\def\PDFpageviewkey{fit}
\def\PDFpageviewwrd{/Fit}
\def\PDFpageview {/View [\PDFpageviewwrd] }
-\def\PDFpagexyzspec{0 0 0} % hack, pdftex does handle this
+\let\PDFpagexyzspec\relax % 0 0 0 hack, pdftex does handle this, for dvipdfmx we need height
\def\dosetuppageview#1% watch the v-h swapping here
{\processaction
@@ -1663,9 +1669,16 @@
\v!height=>\def\PDFpageviewkey {fitv}\def\PDFpageviewwrd{/FitV},
\v!minwidth=>\def\PDFpageviewkey{fitbh}\def\PDFpageviewwrd{/FitBH},
\v!minheight=>\def\PDFpageviewkey{fitbv}\def\PDFpageviewwrd{/FitBV},
- \v!standard=>\def\PDFpageviewkey{xyz \PDFpagexyzspec}\def\PDFpageviewwrd{/XYZ \PDFpagexyzspec},
+ \v!standard=>\ifx\PDFpagexyzspec\relax
+ % empty does not work too wel with dpx
+ \def\PDFpageviewkey{fit}%
+ \def\PDFpageviewwrd{/Fit}%
+ \else
+ \edef\PDFpageviewkey{xyz \PDFpagexyzspec}%
+ \edef\PDFpageviewwrd{/XYZ \PDFpagexyzspec}%
+ \fi,
\s!unknown=>\def\PDFpageviewkey {fit}\def\PDFpageviewwrd{/Fit}]%
- \edef\PDFpageview{/View [\PDFpageviewwrd]}}
+ \edef\PDFpageview{\ifx\PDFpageviewwrd\empty\else/View [\PDFpageviewwrd]\fi}}
%D \macros
%D {setFDFkids}
@@ -2148,7 +2161,6 @@
% we can (in etex) share more by testing on this
\def\savesecondaryPDFreference#1%
- %{\setxvalue{PDF-SR:\the\nofsecondaryreferences}{#1}}
{\@EA\xdef\csname PDF-SR:\the\nofsecondaryreferences\endcsname{#1}}
\def\savesecondaryPDFreference % #1 == \action
@@ -2350,7 +2362,7 @@
%D A bit out of place, but useful:
-\newevery\everysetfield\relax
+\ifdefined\everysetfield \else \newtoks\everysetfield \fi
\appendtoksonce
\enablePDFdocencoding
@@ -2574,7 +2586,8 @@
\PointsToBigPoints{\dimen2}#3}
\def\doPDFovalbox#1#2#3#4#5#6#7#8% todo: \scratchdimen/\scatchbox
- {\bgroup
+ {\forcecolorhack
+ \bgroup
\dimen0=#4\divide\dimen0 \plustwo
\doPDFovalcalc{0pt}{+\dimen0}\xmin
\doPDFovalcalc{#1}{-\dimen0}\xmax
@@ -2973,10 +2986,8 @@
% 180=>\PDFcode{-1 0 0 -1 0 0 cm},
% 270=>\PDFcode{ 0 -1 1 0 0 0 cm},
% 360=>\PDFcode{ 1 0 0 1 0 0 cm},
-% #1=>%\calculatecos{#1}% already calculated in core macro
-% %\calculatesin{#1}% already calculated in core macro
-% \edef\cos{\calculatedcos{#1}}%
-% \edef\sin{\calculatedsin{#1}}%
+% #1=>\setcalculatedcos\cos{#1}%
+% \setcalculatedsin\sin{#1}%
% \PDFcode{\cos \space % cos
% \sin \space % sin
% \negated\sin\space % -sin
@@ -2987,10 +2998,9 @@
% can use the next alternative without running into inaccuracies.
\def\doPDFstartrotation#1% grouped
- {\calculatecos{#1}% already calculated in core macro
- \calculatesin{#1}% already calculated in core macro
- \edef\cos{\calculatedcos{#1}}%
- \edef\sin{\calculatedsin{#1}}%
+ {\setcalculatedcos\cos{#1}%
+ \setcalculatedsin\sin{#1}%
+ \forcecolorhack
\PDFcode{q \cos\space\sin\space\negated\sin\space\cos\space0 0 cm}}
\def\doPDFstoprotation
@@ -3004,7 +3014,8 @@
\def\@@PDFzeroscale{.0001}
\def\doPDFstartscaling#1#2% the test is needed because acrobat is bugged!
- {\PDFcode{q \ifdim#1\points=\zeropoint\@@PDFzeroscale\else#1\fi\space 0 0
+ {\forcecolorhack
+ \PDFcode{q \ifdim#1\points=\zeropoint\@@PDFzeroscale\else#1\fi\space 0 0
\ifdim#2\points=\zeropoint\@@PDFzeroscale\else#2\fi\space 0 0 cm}}
% \def\doPDFstartscaling#1#2% the test is needed because acrobat is bugged!
@@ -3253,8 +3264,8 @@
%D Handy for the \METAPOST\ to \PDF\ converter:
-\newevery \everyPDFximage \relax
-\newevery \everyPDFxform \relax
+\ifdefined\everyPDFximage \else \newtoks\everyPDFximage \fi
+\ifdefined\everyPDFxform \else \newtoks\everyPDFxform \fi
\appendtoksonce
\collectPDFresources
@@ -3275,7 +3286,7 @@
\xdef\collectedPDFresources{\collectedPDFresources/ColorSpace \PDFobjectreference}}\donothing
\global\let\collectPDFresources\relax}
-%D And that was all.
+%D And that was about all.
\stopspecials
@@ -3290,6 +3301,146 @@
\fi
-\loadmarkfile{spec-fdf}
+%D Temporary hack:
+
+\def\TransparencyHack % png: /CS /DeviceRGB /I true
+ {\appendtoks
+ \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}%
+ \to \everyPDFxform
+ \appendtoks
+ \doPDFpageattribute{/Group << /S /Transparency /I true /K true>>}%
+ \to \everyshipout}
+
+%D We still need to implement a few helpers:
+
+\chardef\safePDFcode=`-
+
+\def\setPDFdestination#1%
+ {\bgroup
+ \retainlccodes
+ \lccode`\/\safePDFcode \lccode`\#\safePDFcode
+ \lccode`\<\safePDFcode \lccode`\>\safePDFcode
+ \lccode`\[\safePDFcode \lccode`\]\safePDFcode
+ \lccode`\(\safePDFcode \lccode`\)\safePDFcode
+ \ifovercomePDFspace
+ \lccode`\ \safePDFcode
+ \fi
+ \ifovercomePDFbugs
+ \xdef\PDFdestination{'#1'}%
+ \else
+ \xdef\PDFdestination{#1}%
+ \fi
+ % nicer \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}%
+ \lowercase\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}%
+ \egroup}
+
+%D This is much faster since we don't have to set the full
+%D range of lc-codes; about 5 sec on a 1000mhz PIII for
+%D 20K named destinations "x(x) x"). Of course when you use
+%D page destinations, the saving is nil.
+
+% \doifnotmode{atpragma}{\let\next\setPDFdestination} % experimental
+%
+% \catcode`\/=\@@active \catcode`\#=\@@active
+% \catcode`\<=\@@active \catcode`\>=\@@active
+% \catcode`\[=\@@active \catcode`\]=\@@active
+% \catcode`\(=\@@active \catcode`\)=\@@active
+%
+% \gdef\PDFrepchar{-}
+%
+% \gdef\setPDFdcharacters
+% {\catcode`\/=\@@active \let/\PDFrepchar
+% \catcode`\#=\@@active \let#\PDFrepchar
+% \catcode`\<=\@@active \let<\PDFrepchar
+% \catcode`\>=\@@active \let>\PDFrepchar
+% \catcode`\[=\@@active \let[\PDFrepchar
+% \catcode`\]=\@@active \let]\PDFrepchar
+% \catcode`\(=\@@active \let(\PDFrepchar
+% \catcode`\)=\@@active \let)\PDFrepchar}
+%
+% \egroup
+%
+% \def\setPDFdestination#1% expansion is needed, otherwise embedded
+% {\bgroup % macros will not expand under the new
+% \setPDFdcharacters % catcode regime
+% \ifovercomePDFspace
+% \catcode32=\@@ignore
+% \fi
+% \xdef\PDFdestination{\ifovercomePDFbugs'\fi#1\ifovercomePDFbugs'\fi}%
+% \scantokens\@EA{\@EA\xdef\@EA\PDFdestination\@EA{\PDFdestination}}%
+% \egroup}
+%
+% \doifnotmode{atpragma}{\let\setPDFdestination\next} % experimental
+
+%D This is a slow one, that uses \type{\lccode}'s to
+%D change the glyph as well as converts sensisitve ones into a
+%D \PDF\ command sequence, so \type{(} becomes \type{\(}. In
+%D fact we translate the string to lowercase inactive and non
+%D special characters, limit their number and finaly convert
+%D some of the characters to save ones.
+
+\chardef\maxPDFstringsize=60
+
+\def\sanitizePDFstring#1\to#2% bugged
+ {\bgroup
+ \retainlccodes
+ \lccode`( \zerocount \lccode`) \zerocount
+ \lccode`< \zerocount \lccode`> \zerocount
+ \lccode`[ \zerocount \lccode`] \zerocount
+ \lccode`\\\zerocount \lccode`/ \zerocount
+ \lowercase{\defconvertedargument\ascii{#1}}%
+ % by integrating the split in the loop below
+ % \splitofftokens\maxPDFstringsize\from\ascii\to\ascii
+ % we diminish the processing time considerably
+ \scratchcounter\maxPDFstringsize
+ \def\docommand##1%
+ {\ifcase\scratchcounter\else
+ \advance\scratchcounter \minusone
+ \ifcase\lccode`##1\relax
+ \xdef#2{#2\expandafter\string\csname##1\endcsname}%
+ \else
+ \xdef#2{#2##1}%
+ \fi
+ \fi}%
+ %\global\let#2=\empty
+ % or to permit #2 to be \ascii too:
+ \global\@EA\let\@EA#2\@EA\empty
+ \@EA\handletokens\ascii\with\docommand
+ \egroup}
+
+% \doifnotmode{atpragma}{\let\next\sanitizePDFstring} % experimental
+%
+% \bgroup
+%
+% \catcode`\.=\@@escape
+%
+% .catcode`./=.@@active
+% .catcode`.<=.@@active .catcode`.>=.@@active
+% .catcode`.[=.@@active .catcode`.]=.@@active
+% .catcode`.(=.@@active .catcode`.)=.@@active
+%
+% .gdef.setPDFscharacters%
+% {.catcode`.\=.@@other
+% .catcode`./=.@@active .def/{.noexpand./}%
+% .catcode`.<=.@@active .def<{.noexpand.<}%
+% .catcode`.>=.@@active .def>{.noexpand.>}%
+% .catcode`.[=.@@active .def[{.noexpand.[}%
+% .catcode`.]=.@@active .def]{.noexpand.]}%
+% .catcode`.(=.@@active .def({.noexpand.(}%
+% .catcode`.)=.@@active .def){.noexpand.)}}
+%
+% .gdef.sanitizePDFstring#1.to#2%
+% {.bgroup
+% .setPDFscharacters
+% .catcode`=.@@escape
+% .edef.next{.strippedcsname#2}%
+% .scantokens{setxvalue{next}{#1}}%
+% .egroup}
+%
+% .egroup
+%
+% \doifnotmode{atpragma}{\let\sanitizePDFstring\next} % experimental
+%
+% There is an unicode variant in spec-tst!
\protect \endinput
diff --git a/tex/context/base/spec-ini.tex b/tex/context/base/spec-ini.tex
index 221b8f4a2..4f3d884be 100644
--- a/tex/context/base/spec-ini.tex
+++ b/tex/context/base/spec-ini.tex
@@ -31,129 +31,41 @@
%D tried to overcome this problem by implementing specials as
%D a sort of drivers themselves.
-\writestatus{loading}{Context Special Macros / Initialization}
+\writestatus{loading}{ConTeXt Special Macros / Initialization}
\unprotect
-\startmessages dutch library: specials
- title: specials
- 1: -- geladen
- 2: verdere nesting is niet toegestaan --
- 3: -- gereset
- 4: commando -- bestaat niet
- 5: definitiefile -- wordt geladen
- 6: nesting is niet toegestaan
- 7: onbekende driver --
-\stopmessages
-
-\startmessages english library: specials
- title: specials
- 1: -- loaded
- 2: no deeper nesting is permitted --
- 3: -- is reset
- 4: command -- does not exist
- 5: loading definition file --
- 6: nesting is not permitted
- 7: unknown driver --
-\stopmessages
-
-\startmessages german library: specials
- title: spezielles
- 1: -- geladen
- 2: keine tiefere Verschachtelung erlaubt --
- 3: -- ist zurueckgesetzt
- 4: Befehl -- existiert nicht
- 5: lade Definitionsdatei --
- 6: Verschachtelung nicht erlaubt
- 7: unbekante Driver --
-\stopmessages
-
-\startmessages czech library: specials
- title: speciality
- 1: -- nacteno
- 2: neni dovoleno hlubsi zanoreni --
- 3: -- je resetovano
- 4: prikaz -- neexistuje
- 5: nacita se definicni soubor --
- 6: zanoreni neni dovoleno
- 7: neznamy ovladac (driver) --
-\stopmessages
-
-\startmessages italian library: specials
- title: specialitø
- 1: -- caricato
- 2: non ø permesso un annidamento maggiore --
- 3: -- reimpostato
- 4: il comando -- non esiste
- 5: caricamento del file di definizione --
- 6: annidamento non permesso
- 7: driver sconosciuto --
-\stopmessages
-
-\startmessages norwegian library: specials
- title: specials
- 1: -- er lest inn
- 2: dypere 'nesting' er ikke tillatt --
- 3: -- er tilbakestilt
- 4: kommando -- eksisterer ikke
- 5: leser inn definisjonsfil for --
- 6: 'nesting' er ikke tillatt
- 7: ukjent driver --
-\stopmessages
-
-\startmessages romanian library: specials
- title: specials
- 1: -- incarcat
- 2: nu este permis un nivel de imbricare mai mare --
- 3: -- s-a resetat
- 4: comanda -- nu exista
- 5: se incarca fisierul de definitii --
- 6: imbricarea nu este permisa
- 7: driver necunoscut --
-\stopmessages
-
-\startmessages french library: specials
- title: specials
- 1: -- chargé
- 2: pas d'imbracations plus profondes ne sont permises --
- 3: -- est remis à zéro
- 4: la commande -- n'existe pas
- 5: chargement du fichier de définition --
- 6: l'imbrication n'est pas permise
- 7: pilote -- inconnu
-\stopmessages
-
-\startmessages dutch library: interactions
- 21: -- code tussengevoegd
-\stopmessages
-
-\startmessages english library: interactions
- 21: -- code inserted
-\stopmessages
-
-\startmessages german library: interactions
- 21: -- Code eingefuegt
-\stopmessages
-
-\startmessages czech library: interactions
- 21: -- kod vlozen
-\stopmessages
-
-\startmessages italian library: interactions
- 21: codice -- inserito
-\stopmessages
-
-\startmessages norwegian library: interactions
- 21: -- kode satt inn / tilføyd
-\stopmessages
-
-\startmessages romanian library: interactions
- 21: -- cod inserat
-\stopmessages
-
-\startmessages french library: interactions
- 21: -- code inseré
-\stopmessages
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
+
+% messages moved
%D \TEX\ produces files in the \DVI\ format. This format is
%D well defined and stable. In this format one||byte commands
@@ -201,7 +113,7 @@
%D
%D Now what will this one do? We'll see in a few lines.
-\newevery \everyresetspecials \relax
+\newtoks \everyresetspecials
\appendtoksonce
\ifx\setjobsuffix\undefined\else\setjobsuffix{dvi}\fi
diff --git a/tex/context/base/spec-mis.tex b/tex/context/base/spec-mis.tex
index bfd253205..3d263eace 100644
--- a/tex/context/base/spec-mis.tex
+++ b/tex/context/base/spec-mis.tex
@@ -16,7 +16,7 @@
%D Acrobat Distiller. This module implements some common
%D features.
-\writestatus{loading}{Context Special Macros / Miscellaneous Macros}
+\writestatus{loading}{ConTeXt Special Macros / Miscellaneous Macros}
\unprotect
@@ -93,8 +93,6 @@
\def\dofileinsertion#1#2{\executeifdefined{do#1insert#2}\donothing}
\def\dofilechecker #1#2{\executeifdefined{do#1check#2} \donothing}
-\newevery \everyresetspecials \relax
-
\appendtoks \let\supportedfileinsertions\empty \to \everyresetspecials
\appendtoks \let\supportedfilecheckers \empty \to \everyresetspecials
@@ -234,13 +232,17 @@
\noexpand\installprogram{dvipos -o \jobname.tuo \jobname.dvi }%
\global\noexpand\let\noexpand\flushDVIpositionpapersize\relax}}
- \beginXETEX
- \def\dosetpositionpapersize#1#2%
- {\xdef\flushDVIpositionpapersize
- {\special{pos:papersize \number#1 \number#2}%
- \noexpand\installprogram{dvipos -o \jobname.tuo \jobname.xdv }%
- \global\noexpand\let\noexpand\flushDVIpositionpapersize\relax}}
- \endXETEX
+ % kind of obsolete since nowadays xetex supports \pdfsavepos as well
+
+ \ifnum\texengine=\xetexengine
+
+ \def\dosetpositionpapersize#1#2%
+ {\xdef\flushDVIpositionpapersize
+ {\special{pos:papersize \number#1 \number#2}%
+ \noexpand\installprogram{dvipos -o \jobname.tuo \jobname.xdv }%
+ \global\noexpand\let\noexpand\flushDVIpositionpapersize\relax}}
+
+ \fi
\prependtoksonce \flushDVIpositionpapersize \to \everyshipout
@@ -278,7 +280,7 @@
%D Handy to have this available asap:
-\newevery \everyPDFxform \relax
-\newevery \everyPDFximage \relax
+\ifdefined\everyPDFxform \newtoks\everyPDFxform \fi
+\ifdefined\everyPDFximage \newtoks\everyPDFximage \fi
\protect \endinput
diff --git a/tex/context/base/spec-pdf.lua b/tex/context/base/spec-pdf.lua
deleted file mode 100644
index 051a8794f..000000000
--- a/tex/context/base/spec-pdf.lua
+++ /dev/null
@@ -1,67 +0,0 @@
-if not modules then modules = { } end modules ['spec-pdf'] = {
- version = 1.001,
- comment = "companion to spec-fdf.tex",
- author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
- copyright = "PRAGMA ADE / ConTeXt Development Team",
- license = "see context related readme files"
-}
-
---[[ldx--
-<p>This module implements a couple of cleanup methods. We need these
-in order to meet the <l n='pdf'/> specification. Watch the double
-parenthesis; they are needed because otherwise we would pass more
-than one argument to <l n='tex'/>.</p>
---ldx]]--
-
-local char, byte, format = string.char, string.byte, string.format
-local texsprint, texwrite = tex.sprint, tex.write
-
-pdf = pdf or { }
-
-function pdf.cleandestination(str)
- texsprint((str:gsub("[%/%#%<%>%[%]%(%)%-%s]+","-")))
-end
-
-function pdf.cleandestination(str)
- texsprint((str:gsub("[%/%#%<%>%[%]%(%)%-%s]+","-")))
-end
-
-function pdf.sanitizedstring(str)
- texsprint((str:gsub("([\\/#<>%[%]%(%)])","\\%1")))
-end
-
---~ function pdf.hexify(str)
---~ texwrite("feff" .. utf.gsub(str,".",function(c)
---~ local b = byte(c)
---~ if b < 0x10000 then
---~ return ("%04x"):format(b)
---~ else
---~ return ("%04x%04x"):format(b/1024+0xD800,b%1024+0xDC00)
---~ end
---~ end))
---~ end
-
-function pdf.hexify(str)
- texwrite("feff")
- for b in str:utfvalues() do
- if b < 0x10000 then
- texwrite(("%04x"):format(b))
- else
- texwrite(("%04x%04x"):format(b/1024+0xD800,b%1024+0xDC00))
- end
- end
-end
-
-function pdf.utf8to16(s,offset) -- derived from j. sauter's post on the list
- offset = (offset and 0x110000) or 0 -- so, only an offset when true
- texwrite(char(offset+254,offset+255))
- for c in string.utfvalues(s) do
- if c < 0x10000 then
- texwrite(char(offset+c/256,offset+c%256))
- else
- c = c - 0x10000
- local c1, c2 = c / 1024 + 0xD800, c % 1024 + 0xDC00
- texwrite(char(offset+c1/256,offset+c1%256,offset+c2/256,offset+c2%256))
- end
- end
-end
diff --git a/tex/context/base/spec-tpd.mkii b/tex/context/base/spec-tpd.mkii
deleted file mode 100644
index 918dafb8e..000000000
--- a/tex/context/base/spec-tpd.mkii
+++ /dev/null
@@ -1,18 +0,0 @@
-%D \module
-%D [ file=spec-tpd,
-%D version=1996.01.25,
-%D title=\CONTEXT\ Special Macros,
-%D subtitle=\PDFTEX,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D At some point I will really rewrite the drivers.
-
-\unprotect
-
-\protect \endinput
diff --git a/tex/context/base/spec-tpd.mkiv b/tex/context/base/spec-tpd.mkiv
deleted file mode 100644
index c2f6b27b5..000000000
--- a/tex/context/base/spec-tpd.mkiv
+++ /dev/null
@@ -1,37 +0,0 @@
-%D \module
-%D [ file=spec-tpd,
-%D version=1996.01.25,
-%D title=\CONTEXT\ Special Macros,
-%D subtitle=\PDFTEX,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D Sorry for the mess. Some day I will clean it up.
-
-\unprotect
-
-\def\doPDFinsertbookmark#1#2#3#4#5% level sublevels text page open=1
- {\bgroup
- \doPDFgetpagereference{#4}\PDFobjectreference
- \pdfoutline
- user {<</S /GoTo /D [\PDFobjectreference\space\PDFpageviewwrd]>>}%
- \ifcase#2 \else count \ifcase#5-\fi#2 \fi
- {<\hexifiedPDFstring{#3}>}%
- \egroup}
-
-\def\doPDFsetupidentity#1#2#3#4#5#6%
- {\expanded{\doPDFaddtoinfo
- {/Title <\hexifiedPDFstring{#1}>
- /Subject <\hexifiedPDFstring{#2}>
- /Author <\hexifiedPDFstring{#3}>
- /Creator <\hexifiedPDFstring{#4}>
- /ModDate (#4)
- /ID (\jobname.#5) % needed for pdf/x
- /Keywords <\hexifiedPDFstring{#6}>}}}
-
-\protect \endinput
diff --git a/tex/context/base/spec-tpd.tex b/tex/context/base/spec-tpd.tex
index 49aabb3f6..597993e0a 100644
--- a/tex/context/base/spec-tpd.tex
+++ b/tex/context/base/spec-tpd.tex
@@ -75,17 +75,17 @@
\unprotect
\ifx\pdftexversion\undefined
- \writestatus{\m!systems}{you should use pdfTeX binaries}\wait
+ \writestatus\m!systems{you should use pdfTeX binaries}\wait
\protect\expandafter\endinput
\fi
\ifnum\pdftexversion<13
- \writestatus{\m!systems}{your pdfTeX version is much too old}\wait
+ \writestatus\m!systems{your pdfTeX version is much too old}\wait
\protect\expandafter\endinput
\fi
\ifnum\pdftexversion<14
- \writestatus{\m!systems}{please update your pdfTeX binaries}
+ \writestatus\m!systems{please update your pdfTeX binaries}
\fi
\ifnum\pdftexversion>19
@@ -206,8 +206,8 @@
%D
%D This token register is flushed before an ximage is loaded.
-\newevery \everyPDFximage \relax
-\newevery \everyPDFxform \relax
+\ifdefined\everyPDFximage \else \newtoks\everyPDFximage \fi
+\ifdefined\everyPDFxform \else \newtoks\everyPDFxform \fi
%D \macros
%D {dosetuppaper}
@@ -740,7 +740,7 @@
\definespecial\dostartgotorealpage{\doPDFstartgotorealpage}
\definespecial\dostartgotoJS {\doPDFstartgotoJS}
-\let\PDFpagexyzspec\empty % hack, pdftex does not accept spec
+\let\PDFpagexyzspec\empty % pdftex does not accept spec
%D \macros
%D {doflushJSpreamble}
@@ -1048,32 +1048,6 @@
\ifnum\pdftexversion>13
\def\doPDFaction#1#2#3%
- {\ifcollectreferenceactions
- \xdef\lastPDFaction{#3}%
- \else
- \ifsharePDFactions
- \ifcase\similarreference\relax
- \xdef\lastPDFaction{<<#3>>}%
- \or
- \immediate\pdfobj{<<#3>>}%
- \xdef\lastPDFaction{\PDFobjref\pdflastobj}%
- \else
- % leave \lastPDFaction untouched
- \fi
- \else
- \xdef\lastPDFaction{<<#3>>}%
- \fi
- \pdfannot
- width #1 height #2 depth \zeropoint
- {/Subtype /Link
- /Border [0 0 0]
- \ifhighlighthyperlinks \else /H /N \fi
- /A \lastPDFaction}%
- \fi}
-
- % less #2 passing
-
- \def\doPDFaction#1#2#3%
{\xdef\lastPDFcontent{#3}%
\ifcollectreferenceactions
\global\let\lastPDFaction\lastPDFcontent
@@ -1355,8 +1329,6 @@
%D Now we can finish this module.
-\loadmarkfile{spec-tpd}
-
\stopspecials
\protect \endinput
diff --git a/tex/context/base/spec-var.tex b/tex/context/base/spec-var.tex
index ba04565a2..8d561dc6f 100644
--- a/tex/context/base/spec-var.tex
+++ b/tex/context/base/spec-var.tex
@@ -14,7 +14,7 @@
%D This module used to be integrated in \type {spec-ini},
%D but testing optimization is more convenient this way.
-\writestatus{loading}{Context Special Macros / Variables}
+\writestatus{loading}{ConTeXt Special Macros / Variables}
% new approach, 'global' variables, since we run out of
% arguments
diff --git a/tex/context/base/strc-bkm.lua b/tex/context/base/strc-bkm.lua
new file mode 100644
index 000000000..1104157bd
--- /dev/null
+++ b/tex/context/base/strc-bkm.lua
@@ -0,0 +1,133 @@
+if not modules then modules = { } end modules ['strc-bkm'] = {
+ version = 0.200,
+ comment = "companion to strc-bkm.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- todo: move some code to backend
+
+local format, concat, gsub = string.format, table.concat, string.gsub
+local texsprint, utfvalues = tex.sprint, string.utfvalues
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local lists = structure.lists
+
+-- todo: backend code
+
+local function pdfhexified(str)
+ local t = { }
+ t[#t+1] = "feff"
+ for b in utfvalues(str) do
+ if b < 0x10000 then
+ t[#t+1] = format("%04x",b)
+ else
+ t[#t+1] = format("%04x%04x",b/1024+0xD800,b%1024+0xDC00)
+ end
+ end
+ return concat(t)
+end
+
+-- todo: lpeg cleaner
+
+local function pdfbookmark(level,n,text,page,open)
+ text = gsub(text,"\\([A-Z]+)","%1") -- \LOGO
+ text = gsub(text,"\\ "," ") -- \
+ text = gsub(text,"\\([A-Za-z]+) *{(.-)}","%1") -- \bla{...}
+ text = gsub(text," +"," ") -- spaces
+ text = pdfhexified(text) -- somehow must happen here
+ texsprint(ctxcatcodes,format("\\doinsertbookmark{%s}{%s}{%s}{%s}{%s}",level,n,text,page,open))
+end
+
+-- end of todo
+
+local levelmap = structure.sections.levelmap
+
+structure.bookmarks = structure.bookmarks or { }
+
+local bookmarks = structure.bookmarks
+
+local function nofchildren(list,current,currentlevel)
+ local i = current + 1
+ local li = list[i]
+ if li then
+ local nextlevel = levelmap[li.metadata.name]
+ if nextlevel and nextlevel > currentlevel then
+ local n = 1
+ i = i + 1
+ li = list[i]
+ while li do
+ local somelevel = levelmap[li.metadata.name]
+ if somelevel then
+ if somelevel == nextlevel then
+ n = n + 1
+ elseif somelevel < nextlevel then
+ break
+ end
+ end
+ i = i + 1
+ li = list[i]
+ end
+ return n
+ end
+ end
+ return 0
+end
+
+local names, opened = "", ""
+
+function bookmarks.register(n,o)
+ if names == "" then names = n else names = names .. "," .. n end
+ if opened == "" then opened = o else opened = opened .. "," .. o end
+end
+
+function bookmarks.place()
+ if name ~= "" then
+ local list = lists.filter(names,"all",nil,lists.collected)
+ if #list > 0 then
+ local allopen = (opened == interfaces.variables.all) and 1
+ opened = aux.settings_to_set(opened)
+ for i=1,#list do
+ local li = list[i]
+ local metadata = li.metadata
+ if not metadata.nolist and levelmap[metadata.name] then
+ local name, titledata = metadata.name, li.titledata
+ if titledata then
+ local level = levelmap[name]
+ local children = nofchildren(list,i,level)
+ local title = titledata.bookmark or titledata.title or "?"
+ local realpage = li.references and li.references.realpage
+ if realpage then
+ local open = allopen or (opened[name] and 1)
+ pdfbookmark(level,children,title,realpage,allopen or open or 0)
+ end
+ end
+ end
+ end
+ bookmarks.place = function() end
+ end
+ end
+end
+
+function bookmarks.overload(name,text)
+ local l, ls = lists.tobesaved, nil
+ if #l == 0 then
+ -- no entries
+ elseif name == "" then
+ ls = l[#l]
+ else
+ for i=#l,0,-1 do
+ local li = l[i]
+ local metadata = li.metadata
+ if metadata and not metadata.nolist and metadata.name == name then
+ ls = li
+ break
+ end
+ end
+ end
+ if ls then
+ ls.titledata.bookmark = text
+ end
+end
diff --git a/tex/context/base/strc-bkm.tex b/tex/context/base/strc-bkm.tex
new file mode 100644
index 000000000..dd6352356
--- /dev/null
+++ b/tex/context/base/strc-bkm.tex
@@ -0,0 +1,90 @@
+%D \module
+%D [ file=strc-bkm,
+%D version=2009.04.01,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Bookmarks,
+%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.
+
+\writestatus{loading}{ConTeXt Structure Macros / Bookmarks}
+
+\registerctxluafile{strc-bkm}{1.001}
+
+\unprotect
+
+%D Due to requests I finally decided to support bookmarks, a
+%D driver dependant way of showing tables of content. The most
+%D simple way of support is hooking bookmark generation into
+%D the existing list mechanisms. That way users can generate
+%D bookmarks automatically, although its entirely valid to add
+%D bookmarks by defining alternative ones. These will be added
+%D at the appropriate place in the list.
+
+% \hoofdstuk{het eerste hoofdstuk}
+%
+% \bookmark {de eerste bookmark} % optional overruled hoofdstuk
+%
+% .... text ....
+%
+% \placebookmarks [hoofdstuk,paragraaf,subparagraaf,subsubparagraaf,mylist]
+% [open list]
+%
+% \bookmark[mylist]{whatever}
+
+%D This will go away.
+
+\let\flushpostponedbookmark\relax
+
+%D We have better ways now.
+
+\unexpanded\def\bookmark
+ {\dosingleempty\dobookmark}
+
+\def\dobookmark[#1]#2%
+ {\begingroup
+ \simplifycommands
+ \ctxlua{structure.bookmarks.overload("#1",\!!bs\detokenize\expandafter{\normalexpanded{#2}}\!!es)}%
+ \endgroup}
+
+%D Placement \unknown\ look how simple compared to \MKII:
+
+\def\placebookmarks
+ {\dodoubleempty\doplacebookmarks}
+
+\def\doplacebookmarks[#1][#2]%
+ {\iflocation
+ \iffirstargument
+ \ctxlua{structure.bookmarks.register("#1","#2")}%
+ \else
+ \normalexpanded{\noexpand\placebookmarks[\getvalue{\??ih\v!content\c!list}]}%
+ \fi
+ \fi}
+
+\appendtoks\ctxlua{structure.bookmarks.place()}\to\everystoptext
+
+\protect \endinput
+
+% \starttext
+% \setupinteraction[state=start]\setupinteractionscreen[option=bookmark]
+% \placebookmarks[chapter,section,subsection][chapter]
+% \chapter{First}
+% \bookmark{The First Indeed}
+% \section{alpha}
+% \bookmark[chapter]{The First Indeed Again}
+% \section{beta}
+% \chapter{Second}
+% \bookmark{The Second Indeed}
+% \section{gamma \tex{radiation}}
+% \subsection{a}
+% \subsection{b}
+% \section{delta}
+% \section{epsilon}
+% \chapter{Third \relax}
+% \chapter{我〈能吞下玻璃而不傷身〉體。} % whatever that means
+% \chapter{Idris Samawi Hamid ادريس سماوي حامد}
+% \stoptext
diff --git a/tex/context/base/core-blk.lua b/tex/context/base/strc-blk.lua
index 1007273d5..33dbb0b7c 100644
--- a/tex/context/base/core-blk.lua
+++ b/tex/context/base/strc-blk.lua
@@ -1,6 +1,6 @@
-if not modules then modules = { } end modules ['core-blk'] = {
+if not modules then modules = { } end modules ['strc--blk'] = {
version = 1.001,
- comment = "companion to core-blk.mkiv",
+ comment = "companion to strc--blk.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
@@ -8,7 +8,9 @@ if not modules then modules = { } end modules ['core-blk'] = {
-- this one runs on top of buffers and structure
-local texprint, format = tex.print, string.format
+local texprint, format, gmatch = tex.print, string.format, string.gmatch
+
+local ctxcatcodes = tex.ctxcatcodes
structure = structure or { }
structure.blocks = structure.blocks or { }
@@ -22,20 +24,18 @@ blocks.states = blocks.states or { }
local tobesaved, collected, states = blocks.tobesaved, blocks.collected, blocks.states
local function initializer()
- tobesaved, collected, states = blocks.tobesaved, blocks.collected, blocks.states
+ collected, tobesaved = blocks.collected, blocks.tobesaved
end
--- not used, todo: option to do single or double pass
-
--- job.register('structure.blocks.collected', structure.blocks.tobesaved, initializer, nil)
+job.register('structure.blocks.collected', structure.blocks.tobesaved, initializer)
local printer = (lpeg.linebyline/texprint)^0
function blocks.print(name,data,hide)
if hide then
- texprint(tex.ctxcatcodes,format("\\dostarthiddenblock{%s}",name))
+ texprint(ctxcatcodes,format("\\dostarthiddenblock{%s}",name))
else
- texprint(tex.ctxcatcodes,format("\\dostartnormalblock{%s}",name))
+ texprint(ctxcatcodes,format("\\dostartnormalblock{%s}",name))
end
if type(data) == "table" then
for i=1,#data do
@@ -45,9 +45,9 @@ function blocks.print(name,data,hide)
printer:match(data)
end
if hide then
- texprint(tex.ctxcatcodes,"\\dostophiddenblock")
+ texprint(ctxcatcodes,"\\dostophiddenblock")
else
- texprint(tex.ctxcatcodes,"\\dostopnormalblock")
+ texprint(ctxcatcodes,"\\dostopnormalblock")
end
end
@@ -58,7 +58,7 @@ end
function blocks.setstate(state,name,tag)
local all = tag == ""
local tags = not all and aux.settings_to_array(tag)
- for n in name:gmatch("%s*([^,]+)") do
+ for n in gmatch(name,"%s*([^,]+)") do
local sn = states[n]
if not sn then
-- error
@@ -72,6 +72,8 @@ function blocks.setstate(state,name,tag)
end
end
+--~ filter_collected(names, criterium, number, collected)
+
function blocks.select(state,name,tag,criterium)
criterium = criterium or "text"
if tag:find("=") then tag = "" end
@@ -80,17 +82,18 @@ function blocks.select(state,name,tag,criterium)
local tags = not all and aux.settings_to_set(tag)
local hide = state == "process"
local n = structure.sections.number_at_depth(criterium)
- local result = structure.lists.filter_collected("all", criterium, n, tobesaved)
+ local result = structure.lists.filter_collected("all", criterium, n, collected)
for i=1,#result do
- local b = result[i].entry
- if names[b.name] then
- local btags = b.tags
+ local ri = result[i]
+ local metadata = ri.metadata
+ if names[metadata.name] then
if all then
- blocks.print(name,b.data,hide)
+ blocks.print(name,ri.data,hide)
else
+ local mtags = metadata.tags
for tag, sta in pairs(tags) do
- if btags[tag] then
- blocks.print(name,b.data,hide)
+ if mtags[tag] then
+ blocks.print(name,ri.data,hide)
break
end
end
@@ -99,22 +102,23 @@ function blocks.select(state,name,tag,criterium)
end
end
-function blocks.save(name,tag,buffer)
+function blocks.save(name,tag,buffer) -- wrong, not yet adapted
local data = buffers.data[buffer]
local tags = aux.settings_to_set(tag)
local plus, minus = false, false
if tags['+'] then plus = true tags['+'] = nil end
if tags['-'] then minus = true tags['-'] = nil end
- local slt = structure.lists.tobesaved
tobesaved[#tobesaved+1] = {
- entry = {
+ metadata = {
name = name,
tags = tags,
- data = data or "error",
plus = plus,
minus = minus,
},
- sectionnumber = slt[#slt] and slt[#slt].sectionnumber
+ references = {
+ section = structure.sections.currentid(),
+ },
+ data = data or "error",
}
local allstate = states[name].all
if not next(tags) then
@@ -139,7 +143,3 @@ function blocks.save(name,tag,buffer)
end
buffers.data[buffer] = nil
end
-
--- function sections.getnumber()
--- structure.sections.number(entry, { }, "sectionnumber", "sectionnumber")
--- end
diff --git a/tex/context/base/core-blk.mkiv b/tex/context/base/strc-blk.tex
index 9d1f4deb4..90d2ff9ab 100644
--- a/tex/context/base/core-blk.mkiv
+++ b/tex/context/base/strc-blk.tex
@@ -1,20 +1,21 @@
%D \module
-%D [ file=core-blk,
+%D [ file=strc-blk,
%D version=2008.10.20,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Structure Macros,
%D subtitle=Blockmoves,
%D author=Hans Hagen,
%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%D copyright=PRAGMA-ADE / Hans Hagen]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+\writestatus{loading}{ConTeXt Structure Macros / Blockmoves}
+
+\registerctxluafile{strc-blk}{1.001}
-% \registerctxluafile{core-blk}{1.001}
-\ctxloadluafile{core-blk}{}
+\unprotect
% we run on top of buffers and sections
%
@@ -45,7 +46,7 @@
\letvalue{\e!end#1}\relax}
\long\def\dobeginofblock[#1][#2]%
- {\expanded{\dodowithbuffer{@block@}{\e!begin#1}{\e!end#1}}
+ {\normalexpanded{\noexpand\dodowithbuffer{@block@}{\e!begin#1}{\e!end#1}}
{}{\ctxlua{structure.blocks.save("#1","#2","@block@")}}}% before after
\def\dostarthiddenblock
@@ -106,4 +107,4 @@
\def\processblocks{\doquadrupleempty\doselectblocks[process]}
\def\selectblocks {\doquadrupleempty\doselectblocks[use]}
-\protect
+\protect \endinput
diff --git a/tex/context/base/strc-def.tex b/tex/context/base/strc-def.tex
new file mode 100644
index 000000000..f24ee2023
--- /dev/null
+++ b/tex/context/base/strc-def.tex
@@ -0,0 +1,302 @@
+%D [ file=strc-def,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Definitions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Definitions}
+
+% \registerctxluafile{strc-def}{1.001}
+
+\unprotect
+
+% \def\installparameterhandler#1#2#3#4#5#6#7#8#9{%
+% \def#3##1{\csname#5{#1#2}##1\endcsname}%
+% \def#4##1{#6{#1#2}##1}%
+% %
+% \def#5##1##2{\ifcsname##1##2\endcsname##1##2\else\expandafter#7\csname##1\s!parent\endcsname##2\fi}%
+% \def#6##1##2{\ifcsname##1##2\endcsname ##1\else\expandafter#8\csname##1\s!parent\endcsname##2\fi}%
+% %
+% \def#7##1##2{\ifx##1\relax\s!empty\else#5##1##2\fi}%
+% \def#8##1##2{\ifx##1\relax \else#6##1##2\fi}%
+% %
+% \def#9##1##2% style color
+% {\edef\fontattributehash {#4##1}%
+% \edef\colorattributehash{#4##2}%
+% \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash ##1\fi
+% \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash##2\fi}%
+% %
+% }
+
+% \installparameterhandler
+% \empty
+% \@@framed
+% \framedparameter
+% \framedparameterhash
+% \doframedparameter
+% \doframedparameterhash
+% \doframedparentparameter
+% \doframedparentparameterhash
+% \dosetframedattributes
+
+
+% \setupheads
+
+\setupstructureheads[%
+ %\c!after=,
+ %\c!align=,
+ %\c!aligntitle=,
+ \c!alternative=\v!normal,
+ %\c!before=,
+ %\c!color=,
+ \c!command=\normalplacehead,
+ \c!continue=\v!yes,
+ %\c!coupling=,
+ %\c!deepnumbercommand=,
+ %\c!deeptextcommand=,
+ %\c!default=,
+ \c!distance=\!!zeropoint,
+ \c!expansion=\v!no,
+ %\c!file=,
+ %\c!footer=,
+ %\c!grid=,
+ \c!hang=\v!none,
+ %\c!header=,
+ \c!incrementnumber=\v!yes,
+ \c!indentnext=\v!no,
+ %\c!label=,
+ \c!limittext=\v!yes,
+ \c!margin=\zeropoint,
+ %\c!margintext=,
+ \c!number=\v!yes,
+ \c!numbercolor=\structureheadparameter\c!color,
+ %\c!numbercommand=,
+ \c!numberstyle=\structureheadparameter\c!style,
+ \c!ownnumber=\v!no,
+ %\c!page=,
+ \c!placehead=\v!yes,
+ %\c!prefix=,
+ \c!previousnumber=\v!yes,
+ \c!resetnumber=\v!yes,
+ %\c!section=,
+ \c!sectionconversionset=\s!default,
+ \c!sectionnumber=\v!yes,
+ %\c!sectionsegments=,
+ \c!sectionseparatorset=\s!default,
+ \c!sectionset=\v!all,
+ %\c!sectionstopper=,
+ %\c!strut=,
+ %\c!style=,
+ %\c!text=,
+ \c!textcolor=\structureheadparameter\c!color,
+ %\c!textcommand=,
+ \c!textstyle=\structureheadparameter\c!style,
+ %\c!tolerance=
+ ]
+
+% \setupstructureblock[appendix][sectionconversionset=appendix]
+% \setupstructurehead[chapter][sectionconversionset=\structureblockparameter\c!sectionconversionset] % \structureblockparameter]
+
+\definestructureseparatorset [\s!default] [] [.]
+\definestructureconversionset [\s!default] [] [numbers]
+\definestructureresetset [\s!default] [] [0]
+\definestructureprefixset [\s!default] [section-1,section-2,section-3] []
+
+\definestructureprefixset [\v!all] [section-1,section-2,section-3,section-4,section-5,section-6,section-7,section-8] []
+
+\definestructureprefixset [\v!part] [section-1] []
+\definestructureprefixset [\v!chapter] [section-2] []
+
+\definestructureseparatorset [\v!appendix:\s!default] [] [.]
+\definestructureconversionset [\v!appendix:\s!default] [Romannumerals,Characters] [numbers]
+\definestructureresetset [\v!appendix:\s!default] [] [0]
+
+% \definesectionblock
+
+\definestructureblock [\v!frontpart] [\v!frontmatter] [\c!number=\v!no]
+\definestructureblock [\v!bodypart] [\v!bodymatter] [\c!number=\v!yes]
+\definestructureblock [\v!appendix] [\v!appendices] [\c!number=\v!yes]
+\definestructureblock [\v!backpart] [\v!backmatter] [\c!number=\v!no]
+
+\setstructureblock [\v!bodypart] % default
+
+\appendtoks
+ \setstructureblock [\v!bodypart]% default
+\to \everyjob
+
+% \definesection
+
+\definestructuresection[\s!section-1] % part
+\definestructuresection[\s!section-2] % chapter
+\definestructuresection[\s!section-3] % section
+\definestructuresection[\s!section-4] % subsection
+\definestructuresection[\s!section-5] % subsubsection
+\definestructuresection[\s!section-6] % subsubsubsection
+\definestructuresection[\s!section-7] % subsubsubsubsection
+
+% \definehead
+
+\definestructurehead
+ [\v!part]
+ [\c!section=\s!section-1]
+
+\definestructurehead
+ [\v!chapter]
+ [\c!section=\s!section-2]
+
+\definestructurehead
+ [\v!section]
+ [\c!section=\s!section-3]
+
+\definestructurehead
+ [\v!subsection]
+ [\c!section=\s!section-4,
+ \c!default=\v!section]
+
+\definestructurehead
+ [\v!subsubsection]
+ [\c!section=\s!section-5,
+ \c!default=\v!subsection]
+
+\definestructurehead
+ [\v!subsubsubsection]
+ [\c!section=\s!section-6,
+ \c!default=\v!subsubsection]
+
+\definestructurehead
+ [\v!subsubsubsubsection]
+ [\c!section=\s!section-7,
+ \c!default=\v!subsubsubsection]
+
+\definestructurehead
+ [\v!title]
+ [\c!coupling=\v!chapter,
+ \c!default=\v!chapter,
+ \c!incrementnumber=\v!no]
+
+\definestructurehead
+ [\v!subject]
+ [\c!coupling=\v!section,
+ \c!default=\v!section,
+ \c!incrementnumber=\v!no]
+
+\definestructurehead
+ [\v!subsubject]
+ [\c!coupling=\v!subsection,
+ \c!default=\v!subsection,
+ \c!incrementnumber=\v!no]
+
+\definestructurehead
+ [\v!subsubsubject]
+ [\c!coupling=\v!subsubsection,
+ \c!default=\v!subsubsection,
+ \c!incrementnumber=\v!no]
+
+\definestructurehead
+ [\v!subsubsubsubject]
+ [\c!coupling=\v!subsubsubsection,
+ \c!default=\v!subsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\definestructurehead
+ [\v!subsubsubsubsubject]
+ [\c!coupling=\v!subsubsubsubsection,
+ \c!default=\v!subsubsubsubsection,
+ \c!incrementnumber=\v!no]
+
+\setupstructurehead
+ [\v!part]
+ [\c!placehead=\v!no]
+
+\setupstructurehead
+ [\v!chapter]
+ [\v!appendix\c!label=\v!appendix,
+ \v!bodypart\c!label=\v!chapter] % bijlageconversie=\Character
+
+\setupstructurehead
+ [\v!section]
+ [\v!appendix\c!label=\v!section,
+ \v!bodypart\c!label=\v!section] % bijlageconversie=\Character
+
+\setupstructurehead
+ [\v!subsection]
+ [\v!appendix\c!label=\v!subsection,
+ \v!bodypart\c!label=\v!subsection] % bijlageconversie=\Character
+
+\setupstructurehead
+ [\v!subsubsection]
+ [\v!appendix\c!label=\v!subsubsection,
+ \v!bodypart\c!label=\v!subsubsection] % bijlageconversie=\Character
+
+% \setuphead
+
+\setupstructurehead
+ [\v!part,\v!chapter]
+ [%\c!align=,
+ %\c!indentnext=\v!no,
+ \c!continue=\v!no,
+ \c!page=\v!right,
+ \c!header=,
+ \c!style=\tfc,
+ \c!distance=.75em,
+ \c!before={\blank[2*\v!big]},
+ \c!after={\blank[2*\v!big]}]
+
+\setupstructurehead
+ [\v!section]
+ [%\c!align=,
+ %\c!indentnext=\v!no,
+ \c!style=\tfa,
+ \c!distance=.75em,
+ \c!before={\blank[2*\v!big]},
+ \c!after=\blank]
+
+\setupstructurehead % nieuw
+ [\v!subsection]
+ [\c!page=]
+
+% brrr
+
+% \definestructurecounter[\v!page][\c!start=1] % todo: setup
+
+% lists
+
+\definecombinedlist
+ [\v!content]
+ [\v!part,
+ \v!chapter,
+ \v!section,
+ \v!subsection,
+ \v!subsubsection,
+ \v!subsubsubsection,
+ \v!subsubsubsubsection]
+ [\c!level=\v!subsubsubsubsection,
+ \c!criterium=\v!local]
+
+\setuplist
+ [\v!part]
+ [\c!before={\blank\page[\v!preference]},
+ \c!after=\blank,
+ \c!label=\v!yes,
+ \c!distance=1em]
+
+\setuplist
+ [\v!chapter]
+ [\c!before={\blank\page[\v!preference]},
+ \c!after=]
+
+\setuplist [\v!part] [\c!width=0em]
+\setuplist [\v!chapter] [\c!width=2em]
+\setuplist [\v!section] [\c!width=3em]
+\setuplist [\v!subsection] [\c!width=4em]
+\setuplist [\v!subsubsection] [\c!width=5em]
+\setuplist [\v!subsubsubsection] [\c!width=6em]
+\setuplist [\v!subsubsubsubsection] [\c!width=7em]
+
+\protect \endinput
diff --git a/tex/context/base/strc-des.lua b/tex/context/base/strc-des.lua
new file mode 100644
index 000000000..0d548e61f
--- /dev/null
+++ b/tex/context/base/strc-des.lua
@@ -0,0 +1,9 @@
+if not modules then modules = { } end modules ['strc-des'] = {
+ version = 1.001,
+ comment = "companion to strc-des.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- empty
diff --git a/tex/context/base/strc-des.tex b/tex/context/base/strc-des.tex
new file mode 100644
index 000000000..1b196974a
--- /dev/null
+++ b/tex/context/base/strc-des.tex
@@ -0,0 +1,1018 @@
+%D \module
+%D [ file=strc-blk,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Descriptions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Descriptions}
+
+\registerctxluafile{strc-des}{1.001}
+
+%D In order to be more flexible with theorems Aditya Mahajan added
+%D support for titles and endsymbols. At the same time we added more
+%D flexible support for inheriting numbers.
+%D
+%D \startbuffer
+%D \defineenumeration[one]
+%D \defineenumeration[two] [one]
+%D \defineenumeration[three] [number=one,style=slanted]
+%D \defineenumeration[four] [three]
+%D \defineenumeration[five] [three] [number=five]
+%D
+%D \startone test test 1 \stopone
+%D \starttwo test test 2 \stoptwo
+%D \startthree test test 3 \stopthree
+%D \startfour test test 4 \stopfour
+%D \startfive test test 1 \stopfive
+%D \stopbuffer
+%D
+%D \typebuffer \start \getbuffer \stop
+
+% list and titles are experimental
+%
+% \definedescription[test] [location=left,hang=4,headalign={right},distance=1em,list=test]
+% \defineenumeration[lemma][title=yes,right=:,textdistance=1em, location=top, titlestyle=\bs,list=lemma]
+% \defineenumeration[ammel][title=yes,right=:,textdistance=.5em,location=left,titlestyle=\it,width=9em]
+%
+% \placelist[enumeration:lemma]
+% \placelist[description:test][width=0pt]
+%
+% \starttest {something something something} \input zapf \stoptest
+% \startlemma {with a title of a certain length} \input tufte \stoplemma
+% \startammel {with a title} \input zapf \stopammel
+%
+% \defineenumeration[lemma][...]
+% \defineenumeration[titledlemma][lemma][title=yes,right=:,text=lemma,list=lemma]
+
+\unprotect
+
+% description parameters
+
+\def\descriptionparameter #1{\csname\dodescriptionparameter{\??dd\currentdescription }#1\endcsname}
+\def\descriptionmainparameter #1{\csname\dodescriptionparameter{\??dd\currentdescriptionmain }#1\endcsname}
+\def\descriptionnumberparameter#1{\csname\dodescriptionparameter{\??dd\currentdescriptionnumber}#1\endcsname}
+
+\def\detokenizeddescriptionparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??dd\currentdescription#1\endcsname}}
+
+\def\dodescriptionparameter#1#2%
+ {\ifcsname#1#2\endcsname#1#2\else\expandafter\dodescriptionparentparameter\csname#1\s!parent\endcsname#2\fi}
+
+\def\dodescriptionparentparameter#1#2%
+ {\ifx#1\relax\s!empty\else\dodescriptionparameter#1#2\fi}
+
+% description hashes (needed for style/color)
+
+\def\descriptionparameterhash #1{\dodescriptionparameterhash{\??dd\currentdescription }#1}
+\def\descriptionmainparameterhash#1{\dodescriptionparameterhash{\??dd\currentdescriptionmain}#1}
+
+\def\dodescriptionparameterhash#1#2%
+ {\ifcsname#1#2\endcsname#1\else\expandafter\dodescriptionparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dodescriptionparentparameterhash#1#2%
+ {\ifx#1\relax\else\dodescriptionparameterhash#1#2\fi}
+
+\def\dosetdescriptionattributes#1#2% style color
+ {\edef\fontattributehash {\descriptionparameterhash#1}%
+ \edef\colorattributehash{\descriptionparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+% typesetting code
+
+\newbox \descriptionheadbox
+\newskip \leftdescriptionskip
+\newskip \rightdescriptionskip
+\newdimen \descriptionsheadwidth % replaces \!!widtha
+\newdimen \descriptionsheaddistance % replaces \!!widthb
+
+\setvalue{@@description\v!left }{\@@descriptionhang\@@descriptionleftpure \@@descriptionlefthang \@@descriptionleftmargin }
+\setvalue{@@description\v!right}{\@@descriptionhang\@@descriptionrightpure\@@descriptionrighthang\@@descriptionrightmargin}
+
+\def\@@descriptionhang#1#2#3% \next still needed?
+ {\processaction
+ [\descriptionparameter\c!hang]
+ [ \v!none=>\let\next#1,%
+ 0=>\let\next#1,%
+ \v!margin=>\let\next#3,%
+ \s!unknown=>\let\next#2,%
+ \s!default=>\let\next#1]%
+ \next}
+
+\def\@@descriptionleftpure
+ {\def\\{\crlf}%
+ \noindent
+ \leftskip\dimexpr\leftdescriptionskip+\descriptionsheadwidth\relax
+ \rightskip\rightdescriptionskip
+ \@@makedescriptionpurebox\raggedright
+ \advance\leftskip\descriptionsheaddistance
+ \llap
+ {\hbox to \leftskip
+ {\hskip\leftdescriptionskip
+ \copy\descriptionheadbox\hss}}%
+ \@@dodescription}
+
+\def\@@descriptionrightpure
+ {\def\\{\crlf}%
+ \noindent
+ \leftskip\leftdescriptionskip
+ \rightskip\dimexpr\rightdescriptionskip+\descriptionsheadwidth\relax
+ \@@makedescriptionpurebox\raggedleft
+ \rlap
+ {\hskip\dimexpr\hsize-\leftskip-\rightskip\relax
+ \copy\descriptionheadbox
+ \hskip\rightdescriptionskip}%
+ \advance\rightskip \descriptionsheaddistance
+ \@@dodescription}
+
+\def\@@descriptionleftmargin
+ {\def\\{\crlf}%
+ \noindent
+ \llap
+ {\@@makedescriptionpurebox\raggedright
+ \hbox to \descriptionparameter\c!width{\copy\descriptionheadbox\hss}%
+ \hskip\descriptionparameter\c!distance}%
+ \@@dodescription}
+
+\def\@@descriptionrightmargin % whatever this means
+ {\def\\{\crlf}%
+ \noindent
+ \rlap
+ {\hskip\descriptionparameter\c!distance
+ \@@makedescriptionpurebox\raggedright
+ \hbox to \descriptionparameter\c!width{\copy\descriptionheadbox\hss}}%
+ \@@dodescription}
+
+\def\@@makedescriptionpurebox#1%
+ {\setbox\descriptionheadbox\vtop
+ {\dontcomplain
+ \hsize\descriptionsheadwidth
+ \leftskip\zeropoint
+ \rightskip\zeropoint
+ #1\setupalign[\descriptionparameter\c!align]%
+ \ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox}%
+ \ht\descriptionheadbox\strutht
+ \dp\descriptionheadbox\strutdp}
+
+\def\@@descriptionlefthang
+ {\def\\{\crlf}%
+ \dontcomplain
+ \advance\descriptionsheadwidth \descriptionsheaddistance
+ \hangindent\descriptionsheadwidth
+ \@@makedescriptionhangbox\raggedright{\advance\rightskip \descriptionsheaddistance}%
+ \noindent
+ \llap
+ {\dontshowcomposition
+ \vtop to \zeropoint{\box\descriptionheadbox}}%
+ \@@dodescription}
+
+\def\@@descriptionrighthang
+ {\def\\{\crlf}%
+ \dontcomplain
+ \advance\descriptionsheadwidth \descriptionsheaddistance
+ \hangindent-\descriptionsheadwidth
+ \@@makedescriptionhangbox\raggedleft{\advance\leftskip \descriptionsheaddistance}%
+ \noindent
+ \rlap
+ {\dontcomplain
+ \dontshowcomposition
+ \hbox to \dimexpr\hsize-\leftskip-\rightskip\relax % can be a macro
+ {\hss\vtop to \zeropoint{\box\descriptionheadbox}}}%
+ \@@dodescription}
+
+\def\@@makedescriptionhangbox#1#2%
+ {\setbox\descriptionheadbox\vtop % \vbox gaat fout in hang
+ {\forgetall
+ \dontcomplain
+ \hsize\descriptionsheadwidth
+ #1\setupalign[\descriptionparameter\c!align]#2%
+ \ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox}%
+ \ht\descriptionheadbox\strutht
+ \dp\descriptionheadbox\strutdp
+ \doifsomething{\descriptionparameter\c!hang}
+ {\doifinsetelse{\descriptionparameter\c!hang}{\v!fit,\v!broad}
+ {\scratchdimen\htdp\descriptionheadbox
+ \doif{\descriptionparameter\c!hang}\v!broad
+ {\advance\scratchdimen .5\strutht}%
+ \getnoflines\scratchdimen
+ \hangafter-\noflines}
+ {\hangafter-\descriptionparameter\c!hang}}}
+
+\setvalue{@@description\v!top}%
+ {%\page[\v!preference]% % Weg ermee!
+ %\dosomebreak{\goodbreak}% % Dit is beter en nodig!
+ \dohandlepagebreakX\plusone % En dit moet het maar worden.
+ \let\\=\space
+ \noindent
+ \copy\descriptionheadbox\par
+ \nobreak
+ %\descriptionparameter\c!inbetween % .. brrrr ... :
+ \doifelsenothing{\descriptionparameter\c!inbetween}{\blank}{\descriptionparameter\c!inbetween}%
+ \nobreak
+ \@@dodescription}
+
+\def\do@@description#1%
+ {\def\\{\crlf}%
+ \noindent
+ #1{\ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox}%
+ \@@dodescription}
+
+\setvalue{@@description\v!inmargin }{\do@@description\inmargin}
+\setvalue{@@description\v!inleft }{\do@@description\inleft }
+\setvalue{@@description\v!inright }{\do@@description\inright }
+\setvalue{@@description\v!margin }{\do@@description\inmargin}
+\setvalue{@@description\v!leftmargin }{\do@@description\inleft }
+\setvalue{@@description\v!rightmargin }{\do@@description\inright }
+\setvalue{@@description\v!innermargin }{\do@@description\ininner }
+\setvalue{@@description\v!outermargin }{\do@@description\inouter }
+
+\setvalue{@@description\v!serried\v!fit}%
+ {\def\\{\crlf}%
+ \noindent
+ \ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox
+ \hskip\descriptionsheaddistance % toegevoegd
+ \@@dodescription}
+
+\setvalue{@@description\v!serried\v!broad}%
+ {\def\\{\crlf}%
+ \noindent
+ \ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox
+ \hskip\descriptionsheaddistance \!!plus .5\descriptionsheaddistance \!!minus .25\descriptionsheaddistance
+ \@@dodescription}
+
+\setvalue{@@description\v!serried\v!wide}%
+ {\def\\{\crlf}%
+ \noindent
+ \hbox to \descriptionsheadwidth
+ {\ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox\hss}%
+ \hskip\descriptionsheaddistance
+ \@@dodescription}
+
+\setvalue{@@description\v!serried}%
+ {\processaction
+ [\descriptionparameter\c!width]
+ [ \v!fit=>\let\next\v!fit,
+ \v!broad=>\let\next\v!broad,
+ \s!unknown=>\let\next\v!wide,
+ \s!default=>\let\next\v!broad]%
+ \getvalue{@@description\v!serried\next}}
+
+\setvalue{@@description\v!hanging}%
+ {\def\\{\crlf}%
+ \noindent
+ \advance\leftskip -\leftskipadaption \relax
+ \ifdim\leftskipadaption=\zeropoint
+ \leftskipadaption1.5em\relax % just some default
+ \ifnum\nesteddescriptionstate=\plusone
+ \ifdim\leftskip>\zeropoint \relax
+ \leftskipadaption\leftskip
+ \fi
+ \fi
+ \fi
+ \ifnum\nesteddescriptionstate>\zerocount % was \ifnum\nesteddescriptionstate=\plusone
+ \advance\leftskip \leftskipadaption % but we're already further on
+ \fi
+ \hskip-\leftskipadaption
+ \ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox
+ \kern\ifdim\descriptionsheaddistance=\zeropoint .75em\else\descriptionsheaddistance\fi
+ \@@dodescription}
+
+%D A bonus definition
+%D
+%D \starttyping
+%D \setupfootnotedefinition[location=command,headcommand=\llap]
+%D \stoptyping
+
+% \setvalue{@@description\v!command}%
+% {\do@@description{\executeifdefined{\descriptionparameterhash\c!headcommand}\framed}}
+
+\setvalue{@@description\v!command}%
+ {\noindent
+ \descriptionparameter\c!headcommand{\ifhbox\descriptionheadbox\unhcopy\else\copy\fi\descriptionheadbox}%
+ \@@dodescription}
+
+%D A new key 'headalign' in definitions.
+
+\def\resetdescriptions % to be used in e.g. footnotes
+ {\chardef\nesteddescriptionstate\zerocount}
+
+\resetdescriptions
+
+\def\@@dostartdescription
+ {\descriptionparameter\c!before
+ \begingroup
+ \doadaptleftskip{\descriptionparameter\c!margin}%
+ \showcomposition
+ \descriptionsheaddistance\descriptionparameter\c!distance\relax
+ \ifdim\descriptionsheaddistance=\zeropoint\relax
+ \doif{\descriptionparameter\c!width}\v!broad{\descriptionsheaddistance=1em}%
+ \fi
+ \setbox\descriptionheadbox\hbox
+ {\forgetall\dontcomplain
+ \trialtypesettingtrue
+ \doifelsenothing{\descriptionparameter\c!sample}
+ {\dodescriptionhandler
+ {\begstrut\descriptionparameter\c!text\ignorespaces\currentdescriptiontext\endstrut}}%
+ {\dodescriptionhandler
+ {\begstrut\descriptionparameter\c!text\descriptionparameter\c!sample\endstrut}}}%
+ \assignwidth
+ \descriptionsheadwidth
+ {\descriptionparameter\c!width}
+ {\unhcopy\descriptionheadbox}
+ \descriptionsheaddistance
+ \setbox\descriptionheadbox\hbox
+ {\forgetall\dontcomplain
+ \doifelse{\descriptionparameter\c!location}\v!serried % brrr, hack
+ {\dodescriptionhandler
+ {\begstrut\descriptionparameter\c!text\currentdescriptiontext\endstrut}}
+ {\dodescriptionhandler
+ {\vtop
+ {\hsize\dimexpr\descriptionsheadwidth-\descriptionsheaddistance\relax
+ \begstrut\descriptionparameter\c!text\ignorespaces\currentdescriptiontext\endstrut}}}}%
+ \doifelse{\descriptionparameter\c!aligntitle}\v!no
+ {\leftdescriptionskip\leftskip\rightdescriptionskip\rightskip}
+ {\ifcase\nesteddescriptionstate\leftdescriptionskip\leftskip\rightdescriptionskip\rightskip\fi}%
+ \normalexpanded{\noexpand\indenting[\descriptionparameter\c!indenting]}%
+ % better a system mode
+ \ifcase\nesteddescriptionstate
+ \chardef\nesteddescriptionstate\plusone
+ \or
+ \chardef\nesteddescriptionstate\plustwo
+ \fi % now happens elsewhere : \noindent\ignorespaces
+ \@@resetdescriptionclosesymbol}
+
+\def\@@stopdescription
+ {\@@placedescriptionclosesymbol
+ \par % else we loose
+ \endgroup
+ \descriptionparameter\c!after % which currentdescription is taken here?
+ \egroup % temporary hack
+ \checknextindentation[\descriptionparameter\c!indentnext]
+ \dorechecknextindentation}
+
+\def\@@dodescription
+ {\dosetdescriptionattributes\c!style\c!color
+ \ignorespaces}
+
+% starters:
+
+\def\@@startdescription[#1]%
+ {\doifelse{\descriptionparameter\c!title}\v!yes
+ {\permitspacesbetweengroups
+ \dodoublegroupempty{\dohandledescriptionstart[#1]}}
+ {\dohandledescriptionstart[#1]{}}}
+
+\def\@@description[#1]%
+ {\doifelse{\descriptionparameter\c!title}\v!yes
+ {\permitspacesbetweengroups
+ \dodoublegroupempty{\dohandledescriptiondo[#1]}}
+ {\dohandledescriptiondo[#1]{}}}
+
+% these call:
+
+\long\def\@@somedescription[#1]#2%
+ {\dowithpar
+ {\bgroup % temporary hack
+ \@@makedescription[#1]{#2}}%
+ {\@@stopdescription}}
+
+\long\def\@@startsomedescription[#1]#2%
+ {\bgroup % temporary hack
+ \BeforePar{\@@makedescription[#1]{#2}}%
+ \GotoPar}
+
+\def\@@dostartdescriptionindeed
+ {\edef\currentdescriptionlocation{\descriptionparameter\c!location}%
+ \ifx\currentdescriptionlocation\empty
+ \let\currentdescriptionlocation\v!left
+ \fi
+ \ifcsname @@description\currentdescriptionlocation\endcsname \else
+ \let\currentdescriptionlocation\v!left
+ \fi
+ \@@dostartdescription
+ \csname @@description\currentdescriptionlocation\endcsname} % args not needed
+
+\def\@@makedescription[#1]#2%
+ {\postponenotes % new, assumes grouping
+ \doenumerationcheckconditions
+ \dodescriptioncomponent[\c!reference=#1,\c!label={\descriptionparameter\c!text},\c!title={#2},\c!bookmark=,][]%
+ \@@dostartdescriptionindeed}
+
+\def\dostartstoreddescription
+ {\@@dostartdescriptionindeed}
+
+\def\dostopstoreddescription
+ {\@@stopdescription}
+
+% % % % % % % % % % % %
+
+% helpers
+
+% todo: \dosetfontattributewithhash \descriptionparameterhash\c!headstyle
+
+% setup descriptions
+
+\def\setupdescriptions
+ {\dodoubleempty\dosetupdescriptions}
+
+\def\dosetupdescriptions[#1][#2]% % beter: \iffirstargument
+ {\ifsecondargument
+ \dodoubleargumentwithset\dodosetupdescriptions[#1][#2]%
+ \else
+ \dodosetupdescriptions[][#1]%
+ \fi}
+
+\def\dodosetupdescriptions[#1]% [#2]%
+ {\getparameters[\??dd#1]} % [#2]}
+
+% define descriptions
+
+\def\definedescription
+ {\dotripleemptywithset\dodefinedescription}
+
+\def\dodefinedescription[#1][#2][#3]% to be simplified cf enumeration
+ {\dodescriptioninit{#1}%
+ \getparameters[\??dd#1][\c!text=,\s!handler=\v!description,\c!title=\v!yes]%
+ \ifsecondargument\doifassignmentelse{#2}\donetrue\donefalse\else\donetrue\fi
+ \ifdone
+ \getparameters[\??dd#1][\s!parent=\??dd,\c!text=,\s!handler=\v!description,#2]%
+ \dodefinedescriptioncommands{#1}{\??dd}%
+ \else % clone
+ \getparameters[\??dd#1][\s!parent=\??dd#2,\c!text=,\s!handler=\v!description,#3]% clone
+ \dodefinedescriptioncommands{#1}{\??dd#2}%
+ \fi}
+
+\def\dodefinedescriptioncommands#1#2%
+ {\unexpanded\setevalue {#1}{\noexpand\dodescriptioncommand{#1}}%
+ \unexpanded\setevalue{\e!start#1}{\noexpand\dodescriptionstart {#1}}%
+ \unexpanded\setevalue{\e!stop #1}{\noexpand\dodescriptionstop {#1}}}
+
+% handle descriptions
+
+\def\dodescriptioninit#1%
+ {\let\currentdescriptionmain \empty
+ \let\currentdescriptionlevel \empty
+ \edef\currentdescriptionname {#1}%
+ \edef\currentdescription {#1}}
+
+\def\dodescriptioncommand#1{\dodescriptioninit{#1}\dosingleempty\@@description}
+\def\dodescriptionstart #1{\dodescriptioninit{#1}\dosingleempty\@@startdescription}
+\def\dodescriptionstop #1{\dodescriptioninit{#1}\@@stopdescription}
+
+\def\dodescriptionhandler {\csname\??dd:\descriptionparameter\s!handler:\s!handler \endcsname}
+\def\dohandledescriptiondo {\csname\??dd:\descriptionparameter\s!handler:\s!handler:\s!do \endcsname}
+\def\dohandledescriptionstart{\csname\??dd:\descriptionparameter\s!handler:\s!handler:\s!start\endcsname}
+
+% implementation
+
+% beware: with footnotes #2 can be something messy but then #1 is
+% empty anyway, so we have an extra safeguard
+
+\newtoks \everydescription
+
+\setvalue{\??dd:\v!description:\s!handler }{\@@dodescriptionhandler}
+\setvalue{\??dd:\v!description:\s!handler:\s!do }{\@@somedescription}
+\setvalue{\??dd:\v!description:\s!handler:\s!start}{\@@startsomedescription}
+
+\def\@@dodescriptionhandler#1%
+ {\strut
+ \dodescriptionheadtext{#1}%
+ \iftrialtypesetting \else
+ \currentdescriptionsynchronize
+ \fi}
+
+\def\dodescriptionheadtext#1% title
+ {\begingroup
+ \dosetdescriptionattributes\c!headstyle\c!headcolor
+ \the\everydescription
+ \descriptionparameter\c!command{\strut#1}% probably incomplete
+ \endgroup}
+
+% setup enumerations
+
+\def\setupenumerations
+ {\dodoubleempty\dosetupenumerations}
+
+\def\dodosetupenumerations[#1][#2]%
+ {\doenumerationinit{#1}{1}\empty
+ \getparameters[\??dd#1][#2]%
+ \dosetupenumerationcounter{#1}}
+
+\def\dosetupenumerations[#1][#2]%
+ {\ifsecondargument
+ \dodoubleargumentwithset\dodosetupenumerations[#1][#2]%
+ \else
+ \getparameters[\??dn][#1]%
+ \fi}
+
+% define enumerations
+
+\def\defineenumeration
+ {\dotripleemptywithset\dodefineenumeration}
+
+\def\dodefineenumeration[#1][#2][#3]% #2 or #3 assignment
+ {\doenumerationinit{#1}{1}\empty
+ \getparameters[\??dd#1][\c!text=#1,\c!state=\v!start,\s!handler=\v!enumeration,\c!levels=4]%
+ \ifsecondargument\doifassignmentelse{#2}\donetrue\donefalse\else\donetrue\fi
+ \ifdone % independent
+ \getparameters[\??dd#1][\s!counter=#1,#2]%
+ \dodefineenumerationcommands{#1}{1}{}{\??dn}%
+ \let\@@subslevel\empty
+ \dostepwiserecurse{2}{\descriptionparameter\c!levels}{1}
+ {\normalexpanded{\noexpand\dodefineenumerationcommands{#1}{\recurselevel}{\@@subslevel\v!sub}{\??dd\@@subslevel#1}}%
+ \edef\@@subslevel{\@@subslevel\v!sub}}%
+ \else % clone
+ \getparameters[\??dd#1][\s!counter=#2,#3]%
+ \let\@@subslevel\empty
+ \dorecurse{\descriptionparameter\c!levels}
+ {\noemalexpanded{\noexpand\dodefineenumerationcommands{#1}{\recurselevel}{\@@subslevel}{\??dd\@@subslevel#2}}%
+ \edef\@@subslevel{\@@subslevel\v!sub}}%
+ \fi
+ \edef\currentdescriptioncounter{\descriptionparameter\c!number}%
+ \ifx\currentdescriptioncounter\empty
+ \ifdone\dodefineenumerationcounter{#1}\fi
+ \else\ifx\currentdescriptioncounter\v!yes
+ \ifdone\dodefineenumerationcounter{#1}\fi
+ \else\ifx\currentdescriptioncounter\v!no
+ \ifdone\dodefineenumerationcounter{#1}\fi
+ \else
+ \letvalue{\??dd#1\s!counter}\currentdescriptioncounter % ?
+ \doifstructurecounterelse{\currentdescriptioncounter}{}{\dodefineenumerationcounter\currentdescriptioncounter}%
+ \fi\fi\fi}
+
+\newtoks\everysetupenumerationcounter
+\let\currentenumerationcountername\empty
+
+\def\dosetupenumerationcounter#1%
+ {\edef\currentenumerationcountername{#1}% only used in the token list
+ \edef\currentdiscription{#1}%
+ \the\everysetupenumerationcounter}
+
+\appendtoks
+ \dostructurecountersetup\currentenumerationcountername\descriptionparameter
+\to \everysetupenumerationcounter
+
+\def\dodefineenumerationcounter#1% todo: fast inheritance (was mainparameter
+ {\definestructurecounter[#1]%
+ \dosetupenumerationcounter{#1}}
+
+\def\dodefineenumerationcommands#1#2#3#4% since we use \currentdescription, we need an edef
+ {\setevalue{\??dd#3#1\s!parent}{#4}%
+ \unexpanded\setevalue {#3#1}{\noexpand\doenumerationcommand{#1}{#2}{#3}}%
+ \unexpanded\setevalue{\e!start#3#1}{\noexpand\doenumerationstart {#1}{#2}{#3}}%
+ \unexpanded\setevalue{\e!stop #3#1}{\noexpand\doenumerationstop {#1}{#2}{#3}}}
+
+% handle enumeration
+
+\def\currentdescriptionnumber {\csname\??dd\currentdescriptionmain\s!counter\endcsname}% no edef (yet)
+\def\specificdescriptionnumber#1{\csname\??dd#1\s!counter\endcsname}% no edef (yet)
+
+\def\doenumerationinit#1#2#3%
+ {\edef\currentdescriptionmain {#1}%
+ \edef\currentdescriptionlevel{#2}%
+ \edef\currentdescriptionname {#1}%
+ \edef\currentdescription {#3#1}}
+
+\def\doenumerationcommand#1#2#3{\doenumerationinit{#1}{#2}{#3}\dosingleempty\@@description}
+\def\doenumerationstart #1#2#3{\doenumerationinit{#1}{#2}{#3}\dosingleempty\@@startdescription}
+\def\doenumerationstop #1#2#3{\doenumerationinit{#1}{#2}{#3}\@@stopdescription}
+
+\def\doresetenumerationnumber#1#2#3{\doresetsubstructurecounter [\specificdescriptionnumber{#1}][#2]}
+\def\dosetenumerationnumber#1#2#3#4{\dosetsubstructurecounter [\specificdescriptionnumber{#1}][#2]{#4}}
+\def\donextenumerationnumber #1#2#3{\doincrementsubstructurecounter[\specificdescriptionnumber{#1}][#2]}
+
+% implementation
+
+\newtoks \everyenumeration
+\newconditional\enumerationnumberenabled
+\chardef \enumerationcouplingmode \zerocount
+\def \enumerationdisablenumbersignal {-}
+
+\appendtoks \disablepseudocaps \to \everyenumeration % sorry, uppercase causes troubles
+
+\letvalue{\??dd:\c!couplingway:\v!local }\plusone
+\letvalue{\??dd:\c!couplingway:\v!global}\plustwo
+
+\setvalue{\??dd:\v!enumeration:\s!handler }{\@@doenumerationhandler}
+\setvalue{\??dd:\v!enumeration:\s!handler:\s!do }{\@@somedescription}
+\setvalue{\??dd:\v!enumeration:\s!handler:\s!start}{\@@startsomedescription}
+
+\def\@@doenumerationhandler#1%
+ {\strut
+ \ifconditional\enumerationnumberenabled
+ \iftrialtypesetting
+ \doenumerationfullnumber\showdntext{#1}%
+ \doenumerationcouplingsymbol
+ \else
+ \doenumerationregistercoupling
+ \doenumerationfullnumber\showdntext{#1}%
+ \doenumerationcouplingsymbol
+ \fi
+ \else
+ \doenumerationfullnumber\showdnpuretext{#1}%
+ \fi
+ \iftrialtypesetting \else
+ \currentdescriptionsynchronize
+ \fi}
+
+\def\doenumerationsavecounter {\savestructurecounter[\currentdescriptionnumber]}
+\def\doenumerationrestorecounter {\restorestructurecounter[\currentdescriptionnumber]}
+\def\doenumerationincrementcounter{\doincrementsubstructurecounter[\currentdescriptionnumber][\currentdescriptionlevel]}
+
+\def\doenumerationcheckconditions
+ {\doifelse{\descriptionparameter\c!number}\v!yes
+ {\ifx\currentdescriptionreference\enumerationdisablenumbersignal
+ \setfalse\enumerationnumberenabled \else \settrue\enumerationnumberenabled
+ \fi}%
+ {\setfalse\enumerationnumberenabled}%
+ \chardef\enumerationcouplingmode \iflocation
+ \executeifdefined{\??dd:\c!couplingway:\descriptionparameter\c!coupling}\zerocount
+ \else
+ \zerocount
+ \fi}
+
+\def\doenumerationregistercoupling
+ {\iflocation
+ \ifcase\enumerationcouplingmode
+ \or
+ % todo
+ \or
+ % todo
+ \fi
+ \fi}
+
+\def\doenumerationcouplingsymbol
+ {\iflocation\ifcase\enumerationcouplingmode \else
+ % todo
+ \fi\fi}
+
+\def\currentdescriptiontext
+ {\ctxlua{structure.lists.savedtitle("\currentdescriptionmain",\currentdescriptionnumberentry)}}
+
+\def\currentenumerationfullnumber
+ {\ctxlua{structure.lists.savednumber("\currentdescriptionmain",\currentdescriptionnumberentry)}}
+
+\def\doenumerationfullnumber#1#2% text, title
+ {\begingroup
+ \dosetdescriptionattributes\c!headstyle\c!headcolor
+ \the\everyenumeration
+ \descriptionparameter\c!command
+ {\strut
+ #1%
+ \descriptionparameter\c!left
+ \currentenumerationfullnumber
+ % save cq. treat expansion etc
+ \doifsomething{#2}
+ {\doif{\descriptionparameter\c!title}\v!yes
+ {\begingroup
+ \dosetdescriptionattributes\c!titlestyle\c!titlecolor
+ \hskip\descriptionparameter\c!titledistance
+ \descriptionparameter\c!titlecommand
+ {\descriptionparameter\c!titleleft
+ \begstrut#2\endstrut
+ \descriptionparameter\c!titleright}%
+ \endgroup}}%
+ %
+ \descriptionparameter\c!stopper
+ \descriptionparameter\c!right}%
+ \endgroup}
+
+\def\showdnpuretext{\strut\descriptionparameter\c!text} % geen spatie
+\def\showdnlisttext{\descriptionparameter\c!listtext} % space in default
+\def\showdntext {\doifsomething{\descriptionparameter\c!text}{\descriptionparameter\c!text\removeunwantedspaces\fixedspace}}
+
+\unexpanded\def\structurecounterreference#1%
+ {[enumref: #1]}
+
+% you can use \placeclosesymbol or \qed to place a symbol at the end of a
+% description
+
+\def\@@resetdescriptionclosesymbol
+ {\global\@EA\settrue\csname\??dd\currentdescription:mrk\endcsname
+ \let\placeclosesymbol\@@placedescriptionclosesymbol
+ \let\qed \@@placedescriptionclosesymbol}
+
+\def\@@placedescriptionclosesymbol
+ {\ifconditional\csname\??dd\currentdescription:mrk\endcsname
+ \global\@EA\setfalse\csname\??dd\currentdescription:mrk\endcsname
+ \doifsomething{\descriptionparameter\c!closesymbol}{\descriptionparameter\c!closecommand{\descriptionparameter\c!closesymbol}}%
+ \fi}
+
+\newif\ifnodescriptioncaption
+
+\def\doifelsedescriptioncomponent
+ {\ctxlua{structure.lists.doifstoredelse(currentdescriptionnumberentry)}}
+
+\def\dodescriptioncomponent
+ {\doifelsedescriptioncomponent\nododescriptioncomponent\dododescriptioncomponent}
+
+\def\nododescriptioncomponent[#1][#2]% #1=interfaced-settings, #2=optional user data
+ {}
+
+\def\dododescriptioncomponent[#1][#2]% #1=interfaced-settings, #2=optional user data
+ {\begingroup % similar to structure so we might generalize this
+ \getparameters[\??dd\currentdescription][#1]%
+ \edef\currentdescriptionexpansion{\descriptionparameter\c!expansion}%
+ \ifx\currentdescriptionexpansion\s!xml
+ \xdef\currentdescriptiontitle {\detokenizeddescriptionparameter\c!title}%
+ \xdef\currentdescriptionbookmark{\detokenizeddescriptionparameter\c!bookmark}%
+ \xmlstartraw
+ \xdef\currentdescriptionlisttitle {\descriptionparameter\c!title}%
+ \xmlstopraw
+ \globallet\currentdescriptioncoding\s!xml
+ \else
+ \ifx\currentdescriptionexpansion\v!yes
+ \xdef\currentdescriptiontitle {\descriptionparameter\c!title}%
+ \xdef\currentdescriptionbookmark{\descriptionparameter\c!bookmark}%
+ \else
+ \xdef\currentdescriptiontitle {\detokenizeddescriptionparameter\c!title}%
+ \xdef\currentdescriptionbookmark{\detokenizeddescriptionparameter\c!bookmark}%
+ \fi
+ \globallet\currentdescriptionlisttitle \currentdescriptiontitle
+ \globallet\currentdescriptioncoding\s!tex
+ \fi
+ \xdef\currentdescriptionlabel {\descriptionparameter\c!label}%
+ \xdef\currentdescriptionreference {\descriptionparameter\c!reference}%
+ %
+ \doif{\descriptionparameter\c!title}\v!none{\global\nodescriptioncaptiontrue\global\nodescriptionnumbertrue}% will become obsolete
+ %
+ \ifconditional\enumerationnumberenabled
+ \doifelsedescriptioncomponent\donothing\doenumerationincrementcounter
+ \fi
+ %
+ \ifnodescriptioncaption
+ \glet\currentdescriptionlistnumber \relax
+ \glet\currentdescriptionsynchronize\relax
+ \else
+ \setnextinternalreference
+ \xdef\currentdescriptionnumberentry{\ctxlua{structure.lists.push{
+ metadata = {
+ kind = "description",
+ name = "\currentdescriptionname",
+ level = structure.sections.currentlevel(),
+ catcodes = \the\catcodetable,
+ },
+ references = {
+ internal = \nextinternalreference,
+ reference = "\currentdescriptionreference",
+ referenceprefix = "\referenceprefix",
+ block = "\currentstructureblock",
+ section = structure.sections.currentid(),
+ },
+ titledata = {
+ label = \!!bs\detokenize\expandafter{\currentdescriptionlabel }\!!es,
+ title = \!!bs\detokenize\expandafter{\currentdescriptiontitle }\!!es,
+ \ifx\currentdescriptionbookmark\currentdescriptiontitle \else
+ bookmark = \!!bs\detokenize\expandafter{\currentdescriptionbookmark}\!!es,
+ \fi
+ \ifx\currentdescriptionlisttitle\currentdescriptiontitle \else % \ifx\currentdescriptionsaveinlist\v!no
+ list = \!!bs\detokenize\expandafter{\currentdescriptionlisttitle }\!!es,
+ \fi % \fi
+ },
+ \ifconditional\enumerationnumberenabled
+ prefixdata = {
+ prefix = "\descriptionparameter\c!prefix",
+ separatorset = "\descriptionparameter\c!prefixseparatorset",
+ conversion = \!!bs\descriptionparameter\c!prefixconversion\!!es,
+ conversionset = "\descriptionparameter\c!prefixconversionset",
+ set = "\descriptionparameter\c!prefixset",
+ segments = "\descriptionparameter\c!prefixsegments",
+ connector = \!!bs\descriptionparameter\c!prefixconnector\!!es,
+ },
+ numberdata = {
+ numbers = structure.counters.compact("\currentdescriptionname",nil,true),
+ separatorset = "\descriptionparameter\c!numberseparatorset",
+ conversion = "\descriptionparameter\c!numberconversion",
+ conversionset = "\descriptionparameter\c!numberconversionset",
+ stopper = \!!bs\descriptionparameter\c!numberstopper\!!es,
+ segments = "\descriptionparameter\c!numbersegments",
+ },
+ \fi
+ userdata = structure.helpers.touserdata(\!!bs\detokenize{#2}\!!es)
+ }
+ }}%
+ \xdef\currentdescriptionsynchronize % make this a macro because shared
+ {\noexpand\ctxlua{jobreferences.setinternalreference(nil,nil,\nextinternalreference)}%
+ \noexpand\ctxlatelua{structure.lists.enhance(\currentdescriptionnumberentry)}}%
+ \fi
+ \endgroup}
+
+\installstructurelistprocessor{description}{\usestructurelistprocessor{number+title}}
+
+% labels, we could share with enumerations and forget about the text; anyhow, figure
+% labels etc can use enumerations; we keep labels for compatibility reasons; we need
+% the slightly different namespace; we can still define structure counters directly
+% (multiple levels) and use an enumeration without following text
+
+% unfinished
+
+\def\setuplabels
+ {\getparameters[\??db]}
+
+\def\definelabel
+ {\dotripleargumentwithset\dodefinelabel}
+
+\def\dodefinelabel[#1][#2][#3]% #2 or #3 assignment
+ {\doenumerationinit{#1}{1}\empty
+ \getparameters[\??dd#1][\c!command=,\c!state=\v!start,\c!location=,\c!text=#1]%
+ \ifsecondargument\doifassignmentelse{#2}\donetrue\donefalse\else\donetrue\fi
+ \ifdone
+ % an independent one
+ \getparameters[\??dd#1][\s!counter=#1,\s!parent=\??db,#2]%
+ \dodefinelabelcommands{#1}{\??db}%
+ \dodefineenumerationcounter{#1}%
+ \else
+ \getparameters[\??dd#1][\s!counter=#1,\s!parent=\??dd#2,#3]%
+ \dodefinelabelcommands{#1}{\??dd#2}%
+ \fi}
+
+\def\dodefinelabelcommands#1#2%
+ {\unexpanded\setevalue {#1}{\noexpand\dolabelnumbercommand {#1}}%
+ \unexpanded\setevalue{\c!reset #1}{\noexpand\doresetlabelnumber {#1}}%
+ %\unexpanded\setevalue{\c!set #1}{\noexpand\dosetlabelnumber {#1}}% [#2] or {#2} ?
+ \unexpanded\setevalue{\e!next #1}{\noexpand\donextlabelnumber {#1}}%
+ \unexpanded\setevalue{\e!increment#1}{\noexpand\doincrementlabelnumber{#1}}%
+ \unexpanded\setevalue{\c!current #1}{\noexpand\docurrentlabelnumber {#1}}}
+
+% this is just for downward compatibility, we might drop it
+
+\setvalue{\??db:\c!location:\v!inmargin}{\inmargin}
+\setvalue{\??db:\c!location:\v!inleft }{\inleft}
+\setvalue{\??db:\c!location:\v!inright }{\inright}
+\setvalue{\??db:\c!location:\v!margin }{\inmargin}
+
+\def\dolabelinit#1%
+ {\def\currentdescriptionmain{#1}%
+ \def\currentdescription {#1}%
+ \def\currentdescriptionlevel{1}}
+
+\def\docurrentlabelnumber #1{\dolabelinit{#1}\dosingleempty\dodocurrentlabelnumber}
+\def\donextlabelnumber #1{\dolabelinit{#1}\dosingleempty\dodonextlabelnumber}
+\def\dolabelnumbercommand #1{\dolabelinit{#1}\dosingleempty\dodolabelnumbercommand}
+
+\def\doresetlabelnumber #1{\dolabelinit{#1}\doresetsubstructurecounter [\currentdescriptionnumber][\currentdescriptionlevel]}
+\def\dosetlabelnumber #1#2{\dolabelinit{#1}\dosetsubstructurecounter [\currentdescriptionnumber][\currentdescriptionlevel]{#2}}
+\def\doincrementlabelnumber #1{\dolabelinit{#1}\doincrementsubstructurecounter[\currentdescriptionnumber][\currentdescriptionlevel]}
+
+\def\dodocurrentlabelnumber[#1]%
+ {\dontleavehmode
+ \writestatus{!!!}{todo: reference of label}%
+% \rawreference{lab}{#1}{\composedsectionnumber}%
+ \dotextprefix{\descriptionparameter\c!text}%
+ \convertedsubstructurecounter[\currentdescriptionnumber][\currentdescriptionlevel]}
+
+\def\dodonextlabelnumber[#1]% todo: ref
+ {\doincrementsubstructurecounter[\currentdescriptionnumber][\currentdescriptionlevel]%
+ \dodocurrentlabelnumber[\currentdescriptionnumber]}
+
+\def\dodolabelnumbercommand[#1]% todo: ref
+ {\dontleavehmode
+ \descriptionparameter\c!before
+ \begingroup
+ \doincrementsubstructurecounter[\currentdescriptionnumber][\currentdescriptionlevel]%
+ \dosetdescriptionattributes\c!headstyle\c!headcolor
+ \executeifdefined{\??db:\c!location:\descriptionparameter\c!location}{\descriptionparameter\c!command}{\dodocurrentlabelnumber[#1]}%
+ \endgroup
+ \descriptionparameter\c!after}
+
+% to be reimplmented
+
+\def\setupindentations
+ {\dodoubleempty\dosetupindentations}
+
+\def\dosetupindentations[#1][#2]%
+ {\ifsecondargument
+ \dodoubleargumentwithset\dodosetupindentations[#1][#2]%
+ \else
+ \dodosetupindentations[][#1]%
+ \fi}
+
+\def\dodosetupindentations[#1][#2]%
+ {\getparameters[\??ds#1][#2]}
+
+\def\defineindenting
+ {\dodoubleargumentwithset\dodefineindenting}
+
+\def\dodefineindenting[#1][#2]%
+ {\copyparameters[\??ds#1][\??ds]
+ [\c!text,\c!separator,\c!width,\c!style,\c!color,
+ \c!headstyle,\c!sample,\c!before,\c!after,\c!distance]%
+ \getparameters[\??ds#1][#2]%
+ \unexpanded\setvalue {#1}{\dododefineindenting{#1}{0}{1}}%
+ \unexpanded\setvalue {\v!sub#1}{\dododefineindenting{#1}{1}{2}}%
+ \unexpanded\setvalue{\v!sub\v!sub#1}{\dododefineindenting{#1}{2}{3}}}
+
+\def\dododefineindenting#1#2#3%
+ {\par
+ \getvalue{\??ds#1\c!before}%
+ \begingroup
+ \doifvaluenothing{\??ds#1\c!sample}
+ {\setvalue{\??ds#1\c!sample}{\getvalue{\??ds#1\c!text}}}%
+ \assignwidth
+ {\descriptionsheadwidth}
+ {\getvalue{\??ds#1\c!width}}
+ {\doattributes
+ {\??ds#1}\c!headstyle\c!headcolor
+ {\getvalue{\??ds#1\c!sample}%
+ \spr{\getvalue{\??ds#1\c!separator}}}}
+ {\getvalue{\??ds#1\c!distance}}%
+ \advance\descriptionsheadwidth \getvalue{\??ds#1\c!distance}%
+ \setbox\scratchbox\hbox to \descriptionsheadwidth
+ {\doattributes
+ {\??ds#1}\c!headstyle\c!headcolor
+ {\strut
+ \getvalue{\??ds#1\c!text}%
+ \hss
+ \spr{\getvalue{\??ds#1\c!separator}}%
+ \hskip\getvalue{\??ds#1\c!distance}}}%
+ \parindent\zeropoint
+ \hskip#2\descriptionsheadwidth\indent\box\scratchbox
+ \hangindent#3\descriptionsheadwidth
+ \doattributes{\??ds#1}\c!style\c!color\empty
+ \AfterPar{\endgroup\getvalue{\??ds#1\c!after}}% must be redone
+ \GetPar}
+
+\setupdescriptions
+ [\c!location=\v!left,
+ \c!headstyle=\v!bold,
+ \c!titlestyle=\v!bold,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!headcolor=,
+ \c!titlecolor=,
+ \c!width=8em,
+ \c!distance=0pt,
+ \c!titledistance=0.5em,
+ \c!hang=,
+ \c!sample=,
+ \c!align=,
+ \c!margin=\v!no,
+ \c!before=\blank,
+ \c!inbetween=\blank,
+ \c!after=\blank,
+ \c!indentnext=\v!yes,
+ \c!indenting=\v!never,
+ \c!titleleft=(,
+ \c!titleright=),
+ \c!closesymbol=,
+ \c!closecommand=\wordright,
+ \c!command=,
+ \c!titlecommand=]
+
+\setupenumerations
+ [\c!location=\v!top,
+% \c!headstyle=\v!bold,
+% \c!titlestyle=\v!bold,
+% \c!style=\v!normal,
+% \c!headcolor=,
+% \c!titlecolor=,
+% \c!color=,
+% \c!width=8em,
+% \c!distance=0pt,
+% \c!titledistance=0.5em,
+% \c!hang=,
+% \c!sample=,
+% \c!align=,
+% \c!margin=\v!no,
+% \c!before=\blank,
+% \c!inbetween=\blank,
+% \c!after=\blank,
+% \c!indentnext=\v!yes,
+% \c!indenting=\v!never,
+% \c!titleleft=(,
+% \c!titleright=),
+% \c!closesymbol=,
+% \c!closecommand=\wordright,
+% \c!command=,
+% \c!titlecommand=,
+ \c!text=,
+ \c!way=\v!by\v!text,
+ \c!prefixconnector=.,
+ \c!stopper=,
+ \c!number=\v!yes, % else description
+ \c!start=0,
+ \s!parent=\??dd]
+
+\setuplabels
+ [\s!parent=\??dn]
+
+\setupindentations
+ [\c!style=\v!normal,
+ \c!headstyle=\v!normal,
+ \c!color=,
+ \c!headcolor=,
+ \c!width=\v!fit,
+ \c!text=\unknown,
+ \c!sample=,
+ \c!before=\blank,
+ \c!after=\blank,
+ \c!distance=1em,
+ \c!separator={ :}]
+
+\protect \endinput
diff --git a/tex/context/base/strc-doc.lua b/tex/context/base/strc-doc.lua
new file mode 100644
index 000000000..e0df8294a
--- /dev/null
+++ b/tex/context/base/strc-doc.lua
@@ -0,0 +1,569 @@
+if not modules then modules = { } end modules ['strc-doc'] = {
+ version = 1.001,
+ comment = "companion to strc-doc.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+local format, gsub, find, concat = string.format, string.gsub, string.find, table.concat
+local texsprint, texwrite = tex.sprint, tex.write
+
+local ctxcatcodes = tex.ctxcatcodes
+
+if not trackers then trackers = { register = function() end } end
+
+local trace_sectioning = false trackers.register("structure.sectioning", function(v) trace_sectioning = v end)
+
+local function report(...)
+--~ print(...)
+ logs.report("sectioning:",...)
+end
+
+structure = structure or { }
+structure.helpers = structure.helpers or { }
+structure.documents = structure.documents or { }
+structure.sections = structure.sections or { }
+structure.sets = structure.sets or { }
+structure.processors = structure.processors or { }
+
+local helpers = structure.helpers
+local documents = structure.documents
+local sections = structure.sections
+local sets = structure.sets
+local processors = structure.processors
+
+-- -- -- document -- -- --
+
+local data
+
+function documents.initialize()
+ data = {
+ numbers = { },
+ ownnumbers = { },
+ status = { },
+ checkers = { },
+ depth = 0,
+ blocks = { },
+ block = "",
+ }
+ documents.data = data
+end
+
+function documents.reset()
+ data.numbers = { }
+ data.ownnumbers = { }
+ data.status = { }
+ data.checkers = { }
+ data.depth = 0
+end
+
+documents.initialize()
+
+-- -- -- sections -- -- --
+
+jobsections = jobsections or { }
+jobsections.collected = jobsections.collected or { }
+jobsections.tobesaved = jobsections.tobesaved or { }
+
+local collected, tobesaved = jobsections.collected, jobsections.tobesaved
+
+--~ local function initializer()
+--~ collected, tobesaved = jobsections.collected, jobsections.tobesaved
+--~ end
+
+--~ job.register('jobsections.collected', jobsections.tobesaved, initializer)
+
+function sections.currentid()
+ return #tobesaved
+end
+
+function sections.save(sectiondata)
+-- local sectionnumber = helpers.simplify(section.sectiondata) -- maybe done earlier
+ local numberdata = sectiondata.numberdata
+ if not numberdata or sectiondata.metadata.nolist then
+ return #tobesaved
+ else
+ local n = #tobesaved + 1
+ tobesaved[n] = numberdata
+ if not collected[n] then
+ collected[n] = numberdata
+ end
+ return n
+ end
+end
+
+function sections.load()
+ setmetatable(collected,nil)
+ local l = structure.lists.collected
+ for i=1,#l do
+ local li = l[i]
+ local lm = li.metadata
+ if lm and lm.kind == "section" and not lm.nolist then
+ local ln = li.numberdata
+ if ln then
+ collected[#collected+1] = ln
+ end
+ end
+ end
+ sections.load = nil
+end
+
+setmetatable(collected, {
+ __index = function(t,i)
+ sections.load()
+ return t[i] or { }
+ end
+})
+
+--
+
+structure.sections.levelmap = structure.sections.levelmap or { }
+
+local levelmap = structure.sections.levelmap
+
+storage.register("structure/sections/levelmap", structure.sections.levelmap, "structure.sections.levelmap")
+
+sections.verbose = true
+
+function sections.setlevel(name,level) -- level can be number or parent (=string)
+ local l = tonumber(level)
+ if not l then
+ l = levelmap[level]
+ end
+ if l and l > 0 then
+ levelmap[name] = l
+ else
+ -- error
+ end
+end
+
+function sections.getlevel(name)
+ return levelmap[name] or 0
+end
+
+function sections.way(way,by)
+ texsprint(ctxcatcodes,(gsub(way,"^"..by,"")))
+end
+
+function sections.setblock(name)
+ local block = name or data.block or "unknown" -- can be used to set the default
+ data.block = block
+ texwrite(block)
+end
+
+function sections.pushblock(name)
+ local block = name or data.block
+ data.blocks[#data.blocks+1] = block
+ data.block = block
+ documents.reset()
+ texwrite(block)
+end
+
+function sections.popblock()
+ data.blocks[#data.blocks] = nil
+ local block = data.blocks[#data.blocks] or data.block
+ data.block = block
+ documents.reset()
+ texwrite(block)
+end
+
+function sections.currentblock()
+ return data.block or data.blocks[#data.blocks] or "unknown"
+end
+
+function sections.currentlevel()
+ return data.depth
+end
+
+function sections.getcurrentlevel()
+ texwrite(data.depth)
+end
+
+function sections.nextlevel()
+ local depth = data.depth + 1
+ data.depth = depth
+ return depth
+end
+
+function sections.prevlevel()
+ local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
+ local resetter = sets.getall("structure:resets",data.block,status[depth].resets or "")
+ local rd = resetter and resetter[depth]
+ numbers[depth] = (rd and rd > 0 and rd < depth and numbers[depth]) or 0
+ status[depth] = nil
+ depth = depth - 1
+ data.depth = depth
+ return depth
+end
+
+function sections.somelevel(t)
+ local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
+ local d = tonumber(levelmap[t.metadata.name] or (depth > 0 and depth) or 1)
+ local resetter = sets.getall("structure:resets",data.block,(t and t.resets) or "")
+ local previous = { }
+ if d > depth then
+ local rd = resetter and resetter[i]
+ for i=depth+1,d do
+ numbers[i] = (rd and rd[i] and rd[i] > 0 and rd[i] < i and numbers[i]) or 0
+ status[i] = { }
+ end
+ elseif d < depth then
+ local rd = resetter and resetter[i]
+ for i=depth,d+1,-1 do
+ numbers[i] = (rd and rd[i] and rd[i] > 0 and rd[i] < i and numbers[i]) or 0
+ status[i] = nil
+ end
+ end
+ for i=1,d do
+ -- selective resetter
+ if numbers[i] == 0 then
+ ownnumbers[i] = ""
+ end
+ end
+ -- a trick to permits userdata to overload title, ownnumber and reference
+ -- normally these are passed as argument but nowadays we provide several
+ -- interfaces (we need this because we want to be compatible)
+ local u = t.userdata
+ if u then
+ if u.reference and u.reference ~= "" then t.metadata.reference = u.reference ; u.reference = nil end
+ if u.ownnumber and u.ownnumber ~= "" then t.numberdata.ownnumber = u.ownnumber ; u.ownnumber = nil end
+ if u.title and u.title ~= "" then t.titledata.title = u.title ; u.title = nil end
+ if u.bookmark and u.bookmark ~= "" then t.titledata.bookmark = u.bookmark ; u.bookmark = nil end
+ if u.label and u.label ~= "" then t.titledata.label = u.label ; u.label = nil end
+ end
+ -- so far for the trick
+ ownnumbers[d] = t.numberdata.ownnumber or ""
+ t.numberdata.ownnumber = nil
+-- t.numberdata = helpers.simplify(t.numberdata)
+ data.depth = d
+ sections.pluslevel(t)
+end
+
+function sections.writestatus()
+ if sections.verbose then
+ local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
+ local d = status[depth]
+ local o = concat(ownnumbers,".",1,depth)
+ local n = (numbers and concat(numbers,".",1,depth)) or 0
+ local l = d.titledata.title or ""
+ local t = (l ~= "" and l) or d.titledata.title or "[no title]"
+ local m = d.metadata.name
+ if o and not find(o,"^%.*$") then
+ commands.writestatus("structure","%s @ level %i : (%s) %s -> %s",m,depth,n,o,t)
+ elseif d.directives and d.directives.hidenumber then
+ commands.writestatus("structure","%s @ level %i : (%s) -> %s",m,depth,n,t)
+ else
+ commands.writestatus("structure","%s @ level %i : %s -> %s",m,depth,n,t)
+ end
+ end
+end
+
+function sections.pluslevel(t)
+ -- data has saved level data
+ local numbers, ownnumbers, status, depth = data.numbers, data.ownnumbers, data.status, data.depth
+ local directives = t.directives
+ local resetter = sets.getall("structure:resets",data.block, (directives and directives.resetset) or "")
+ if not (directives and directives.hidenumber) then
+ if numbers[depth] then
+ numbers[depth] = numbers[depth] + 1
+ else
+ numbers[depth] = 1
+ end
+ end
+ for k, v in pairs(resetter) do -- sparse
+ if v > 0 and depth == v then
+ numbers[k] = 0
+ end
+ end
+ status[depth] = t or { }
+ for k, v in pairs(data.checkers) do
+ if v[1] == depth and v[2] then
+ v[2](k)
+ end
+ end
+ local numberdata= t.numberdata
+ if not numberdata then
+ -- probably simplified to nothing
+ numberdata = { }
+ t.numberdata = numberdata
+ end
+ numberdata.numbers = table.fastcopy(numbers)
+ if #ownnumbers > 0 then
+ numberdata.ownnumbers = table.fastcopy(ownnumbers)
+ end
+ t.references.section = sections.save(t)
+--~ t.numberdata = nil
+end
+
+function sections.setnumber(depth,n)
+ local numbers, depth = data.numbers, data.depth
+ local d = numbers[depth]
+ if type(n) == "string" then
+ if n:find("^[%+%-]") then
+ d = d + tonumber(n)
+ else
+ d = tonumber(n)
+ end
+ else
+ d = n
+ end
+ numbers[depth] = d
+ -- todo reset
+end
+
+function sections.number_at_depth(depth)
+ return data.numbers[tonumber(depth) or sections.getlevel(depth) or 0] or 0
+end
+
+function sections.getnumber(depth)
+ return texwrite(data.numbers[depth] or 0)
+end
+
+function sections.set(key,value)
+ data.status[data.depth][key] = value -- may be nil for a reset
+end
+
+function sections.cct()
+ local metadata = data.status[data.depth].metadata
+ texsprint((metadata and metadata.catcodes) or ctxcatcodes)
+end
+
+function sections.get(key,default,honorcatcodetable)
+ local data = data.status[data.depth]
+ local d = data
+ for k in key:gmatch("([^.]+)") do
+ if type(d) == "table" then
+ d = d[k]
+ if not d then
+ -- unknown key
+ break
+ end
+ end
+ if type(d) == "string" then
+ if honorcatcodetable then
+ local metadata = data.metadata
+ texsprint((metadata and metadata.catcodes) or ctxcatcodes,d)
+ else
+ texsprint(ctxcatcodes,d)
+ end
+ return
+ end
+ end
+ if default then
+ texsprint(ctxcatcodes,default)
+ end
+end
+
+function sections.getuser(key,default)
+ local userdata = data.status[data.depth].userdata
+ local str = (userdata and userdata[key]) or default
+ if str then
+ texsprint(ctxcatcodes,str)
+ end
+end
+
+function sections.setchecker(name,level,command)
+ data.checkers[name] = (name and command and level > 0 and { level, command }) or nil
+end
+
+function sections.current()
+ return data.status[data.depth]
+end
+
+function sections.depthnumber(n)
+ local depth = data.depth
+ if not n or n == 0 then
+ n = depth
+ elseif n < 0 then
+ n = depth + n
+ end
+ return texwrite(data.numbers[n] or 0)
+end
+
+function sections.autodepth(numbers)
+ for i=#numbers,1,-1 do
+ if numbers[i] ~= 0 then
+ return i
+ end
+ end
+ return 0
+end
+
+--
+
+function structure.currentsectionnumber() -- brr, namespace wrong
+ local sc = sections.current()
+ return sc and sc.numberdata
+end
+
+-- \dorecurse{3} {
+-- \chapter{Blabla} \subsection{bla 1 1} \subsection{bla 1 2}
+-- \section{bla 2} \subsection{bla 2 1} \subsection{bla 2 2}
+-- }
+
+function sections.typesetnumber(entry,kind,...) -- kind='section','number','prefix'
+ if entry then
+ local separatorset = ""
+ local conversionset = ""
+ local conversion = ""
+ local stopper = ""
+ local connector = ""
+ local set = ""
+ local segments = ""
+ for _, data in ipairs { ... } do
+ if data then
+ if separatorset == "" then separatorset = data.separatorset or "" end
+ if conversionset == "" then conversionset = data.conversionset or "" end
+ if conversion == "" then conversion = data.conversion or "" end
+ if stopper == "" then stopper = data.stopper or "" end
+ if connector == "" then connector = data.connector or "" end
+ if set == "" then set = data.set or "" end
+ if segments == "" then segments = data.segments or "" end
+ end
+ end
+ if separatorset == "" then separatorset = "default" end
+ if conversionset == "" then conversionset = "default" end
+ if conversion == "" then conversion = nil end
+ if stopper == "" then stopper = nil end
+ if connector == "" then connector = nil end
+ if set == "" then set = "default" end
+ if segments == "" then segments = nil end
+ --
+ local firstprefix, lastprefix = 0, 100
+ if segments then
+ local f, l = (tostring(segments)):match("^(.-):(.+)$")
+ if f and l then
+ -- 0:100, chapter:subsubsection
+ firstprefix = tonumber(f) or sections.getlevel(f) or 0
+ lastprefix = tonumber(l) or sections.getlevel(l) or 100
+ else
+ -- 3, section
+ local fl = tonumber(segments) or sections.getlevel(segments) -- generalize
+ if fl then
+ firstprefix, lastprefix = fl, fl
+ end
+ end
+ end
+ --
+ local numbers, ownnumbers = entry.numbers, entry.ownnumbers
+ if numbers then
+ local done, preceding = false, false
+ local function process(index) -- move to outer
+ local number = numbers and (numbers[index] or 0)
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > 0 or (ownnumber ~= "") then
+ local block = entry.block
+ if preceding then
+ local separator = sets.get("structure:separators",b,s,preceding,".")
+ if separator then
+ processors.sprint(ctxcatcodes,separator)
+ end
+ preceding = false
+ end
+ if ownnumber ~= "" then
+ processors.sprint(ctxcatcodes,ownnumber)
+ -- elseif conversion and conversion ~= "" then
+ -- tex.sprint(ctxcatcodes,format("\\convertnumber{%s}{%s}",conversion,number))
+ elseif conversion and conversion ~= "" then
+ -- traditional (e.g. used in itemgroups)
+ tex.sprint(ctxcatcodes,format("\\convertnumber{%s}{%s}",conversion,number))
+ else
+ local theconversion = sets.get("structure:conversions",block,conversion,index,"numbers")
+ processors.sprint(ctxcatcodes,theconversion,function(str)
+ return format("\\convertnumber{%s}{%s}",str or "numbers",number)
+ end)
+ end
+ preceding, done = index, true
+ else
+ preceding = preceding or false
+ end
+ end
+ --
+ local prefixlist = set and sets.getall("structure:prefixes","",set) -- "" == block
+ --
+ if prefixlist and (kind == 'section' or kind == 'prefix') then
+ -- find valid set (problem: for sectionnumber we should pass the level)
+ -- if kind == "section" then
+ -- no holes
+ local b, e, bb, ee = 1, #prefixlist, 0, 0
+ -- find last valid number
+ for k=e,b,-1 do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ local number = numbers and numbers[index]
+ if number then
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > 0 or (ownnumber ~= "") then
+ break
+ else
+ e = k -1
+ end
+ end
+ end
+ end
+ -- find valid range
+ for k=b,e do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ local number = numbers and numbers[index]
+ if number then
+ local ownnumber = ownnumbers and ownnumbers[index] or ""
+ if number > 0 or (ownnumber ~= "") then
+ if bb == 0 then bb = k end
+ ee = k
+ else
+ bb, ee = 0, 0
+ end
+ else
+ break
+ end
+ end
+ end
+ -- print valid range
+ for k=bb,ee do
+ local prefix = prefixlist[k]
+ local index = sections.getlevel(prefix) or k
+ if index >= firstprefix and index <= lastprefix then
+ process(index)
+ end
+ end
+ -- else
+ -- for k=1,#prefixlist do
+ -- local prefix = prefixlist[k]
+ -- local index = sections.getlevel(prefix) or k
+ -- if index >= firstprefix and index <= lastprefix then
+ -- process(index)
+ -- end
+ -- end
+ -- end
+ else
+ -- also holes check
+ for prefix=firstprefix,lastprefix do
+ process(prefix)
+ end
+ end
+ --
+ if done and connector and kind == 'prefix' then
+ processors.sprint(ctxcatcodes,connector)
+ elseif done and stopper then
+ processors.sprint(ctxcatcodes,stopper)
+ end
+ else
+ report("error: no numbers")
+ end
+ end
+end
+
+function sections.fullnumber(depth)
+ local data = data.status[depth or data.depth]
+ if data then
+ local sectiondata = jobsections.collected[data.references.section]
+ if sectiondata then
+ sections.typesetnumber(sectiondata,'section',sectiondata)
+ end
+ end
+end
diff --git a/tex/context/base/strc-doc.tex b/tex/context/base/strc-doc.tex
new file mode 100644
index 000000000..e76e015a9
--- /dev/null
+++ b/tex/context/base/strc-doc.tex
@@ -0,0 +1,166 @@
+%D \module
+%D [ file=strc-doc,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Document Structure,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Document Structure}
+
+\registerctxluafile{strc-doc}{1.001}
+
+\unprotect
+
+% We operate in a \type {@@ns} namespace. All data is passed through
+% variables. Of course we can built another interface on top of this
+% that accepts multiple arguments. We might change this approach and
+% remove this layer.
+
+\def\currentstructurecounter{0}
+
+\definesystemvariable {ns}
+
+\def\structureparameter#1{\csname\??ns#1\endcsname}
+
+\def\detokenizedstructureparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??ns#1\endcsname}}
+
+\def\structurecomponent{\dodoubleempty\dostructurecomponent}
+
+\getparameters % initialization, used not grouped anyway
+ [\??ns]
+ [\c!number=,\c!level=,\c!name=,\c!title=,\c!bookmark=,\c!label=,\c!coupling=,\c!ownnumber=,
+ \c!sectionseparatorset=\s!default,\c!sectionconversionset=\s!default,
+ \c!sectionstopper=,\c!sectionsegments=,
+ \c!reset=,\c!reference=,
+ \c!expansion=\v!no,
+ \c!saveinlist=\v!yes,
+ \c!command=\showstructuredata]
+
+\def\dostructurecomponent[#1][#2]% #1=interfaced-settings, #2=optional user data (not yet supported)
+ {\begingroup
+ \getparameters[\??ns][#1]%
+ \xdef\currentstructurename {\structureparameter\c!name}%
+ \xdef\currentstructurecoupling {\structureparameter\c!coupling}%
+ \xdef\currentstructureownnumber{\structureparameter\c!ownnumber}% optional own number
+ \xdef\currentstructurelevel {\structureparameter\c!level}%
+ \edef\currentstructureexpansion{\structureparameter\c!expansion}
+ \ifx\currentstructureexpansion\s!xml
+ % goes via lua anyway
+ \xdef\currentstructuretitle {\detokenizedstructureparameter\c!title}%
+ \xdef\currentstructurebookmark{\detokenizedstructureparameter\c!bookmark}%
+ %
+ \xmlstartraw
+ \xdef\currentstructurelisttitle {\structureparameter\c!title}%
+ \xmlstopraw
+ \globallet\currentstructurecoding\s!xml
+ \else
+ \ifx\currentstructureexpansion\v!yes
+ \xdef\currentstructuretitle {\structureparameter\c!title}%
+ \xdef\currentstructurebookmark{\structureparameter\c!bookmark}%
+ \else
+ \xdef\currentstructuretitle {\detokenizedstructureparameter\c!title}%
+ \xdef\currentstructurebookmark{\detokenizedstructureparameter\c!bookmark}%
+ \iflocation \ifx\currentstructurebookmark\empty
+ \begingroup
+ \simplifycommands
+ \xdef\currentstructurebookmark{\detokenize\expandafter{\normalexpanded{\structureparameter\c!title}}}%
+ \endgroup
+ \fi \fi
+ \fi
+ \globallet\currentstructurelisttitle \currentstructuretitle
+ \globallet\currentstructurecoding\s!tex
+ \fi
+ \xdef\currentstructurelabel {\structureparameter\c!label}%
+ \xdef\currentstructurereference {\structureparameter\c!reference}%
+ \xdef\currentstructurereferenceprefix{\structureparameter\c!referenceprefix}%
+ \xdef\currentstructureshownumber {\structureparameter\c!number}%
+ \xdef\currentstructuresaveinlist {\structureparameter\c!saveinlist}%
+ \xdef\currentstructureincrementnumber{\structureparameter\c!incrementnumber}%
+ \setnextinternalreference
+ \xdef\currentstructurenumber{\ctxlua{ % todo: combine with next call, adapt marks accordingly
+ structure.sections.somelevel {
+ references = {
+ internal = \nextinternalreference,
+ block = "\currentstructureblock",
+ reference = "\currentstructurereference",
+ referenceprefix = "\currentstructurereferenceprefix",
+ },
+ directives = {
+ resetset = "\structureparameter\c!reset",
+ hidenumber = not toboolean("\currentstructureincrementnumber",true), % incremented but hidden
+ },
+ metadata = {
+ kind = "section",
+ name = "\currentstructurename",
+ catcodes = \the\catcodetable,
+ coding = "\currentstructurecoding",
+ xmlroot = \ifx\currentstructurecoding\s!xml "\xmldocument" \else nil \fi,
+ \ifx\currentstructuresaveinlist\v!no
+ nolist = true,
+ \fi
+ },
+ titledata = { % we can add mark and reference
+ label = \!!bs\detokenize\expandafter{\currentstructurelabel }\!!es,
+ title = \!!bs\detokenize\expandafter{\currentstructuretitle }\!!es,
+ \ifx\currentstructurebookmark\currentstructuretitle \else
+ bookmark = \!!bs\detokenize\expandafter{\currentstructurebookmark }\!!es,
+ \fi
+ \ifx\currentstructurelisttitle\currentstructuretitle \else \ifx\currentstructuresaveinlist\v!no
+ list = \!!bs\detokenize\expandafter{\currentstructurelisttitle}\!!es,
+ \fi \fi
+ },
+ numberdata = {
+ separatorset = "\structureparameter\c!sectionseparatorset",
+ conversion = "\structureparameter\c!sectionconversion", % for good old times sake
+ conversionset = "\structureparameter\c!sectionconversionset",
+ stopper = \!!bs\structureparameter\c!sectionstopper\!!es,
+ set = "\structureparameter\c!sectionset",
+ segments = "\structureparameter\c!sectionsegments",
+ ownnumber = "\currentstructureownnumber",
+ hidenumber = \ifx\currentstructureshownumber\v!no true\else nil\fi, % titles
+ },
+ userdata = structure.helpers.touserdata(\!!bs\detokenize{#2}\!!es)
+ }
+ }}%
+ \xdef\currentstructurelistnumber{\ctxlua{structure.lists.push(structure.sections.current())}}%
+ % \currentstructuresynchronize has to be called someplace, since it introduces a node
+ \setstructuresynchronization\currentstructurelistnumber
+ \structureparameter\c!command
+ \endgroup}
+
+\let\currentstructurenumber \!!zerocount
+\let\currentstructurecounter \!!zerocount
+\let\previousstructurecounter\!!zerocount
+
+\def\setstructuresynchronization#1%
+ {\xdef\currentstructuresynchronize
+ {\noexpand\ctxlua{jobreferences.setinternalreference("\currentstructurereferenceprefix","\currentstructurereference",\nextinternalreference)}%
+ \noexpand\ctxlatelua{structure.lists.enhance(#1)}}}
+
+\def\reportcurrentstructure{\ctxlua{structure.sections.writestatus()}}
+
+% Beware: we need to flush the data to the list explicitly. This is because
+% node in inserted and we may want control over when that happens.
+
+\def\showstructuredata
+ {\par
+ \dontleavehmode
+ \currentstructuresynchronize
+ [\currentstructurename: \showstructurelevel: \currentstructuretitle]
+ \par}
+
+% We can access the (stored) data with the following macros.
+
+\def\structurevalue #1{\ctxlua{structure.sections.get("#1")}}
+\def\structureuservalue#1{\ctxlua{structure.sections.getuser("#1")}}
+\def\structurenumber {\ctxlua{structure.sections.fullnumber()}}
+
+\def\structurecctvalue #1{\ctxlua{structure.sections.get("#1",nil,true)}}
+
+\protect \endinput
diff --git a/tex/context/base/strc-flt.lua b/tex/context/base/strc-flt.lua
new file mode 100644
index 000000000..f6f3e19cc
--- /dev/null
+++ b/tex/context/base/strc-flt.lua
@@ -0,0 +1,9 @@
+if not modules then modules = { } end modules ['strc-flt'] = {
+ version = 1.001,
+ comment = "companion to strc-flt.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- nothing
diff --git a/tex/context/base/strc-flt.tex b/tex/context/base/strc-flt.tex
new file mode 100644
index 000000000..b0ff9893b
--- /dev/null
+++ b/tex/context/base/strc-flt.tex
@@ -0,0 +1,2173 @@
+%D \module
+%D [ file=strc-flt,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Float Numbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Float Numbering}
+
+\registerctxluafile{strc-flt}{1.001}
+
+\unprotect
+
+%D This module needs a cleanup and will be split in
+%D strc-flt.tex and page-flt.mkiv cq. page-flt.mkii.
+
+\ifx\addlocalbackgroundtobox\undefined \def\addlocalbackgroundtobox{\resetglobal\gobbleoneargument} \fi
+
+\def\placefloats{\doflushfloats} % keep this one
+
+\let\currentfloat\empty
+
+\def\letfloatparameter #1{\expandafter\csname\??fl\currentfloat#1\endcsname}
+
+\def\floatparameter #1{\csname\dofloatparameter{\??fl\currentfloat}#1\endcsname}
+\def\floatsharedparameter#1{\csname \??fl #1\endcsname}
+\def\floatparameterhash #1{\dofloatparameterhash {\??fl\currentfloat}#1}
+
+\def\dofloatparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dofloatparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dofloatparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dofloatparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dofloatparentparameter #1#2{\ifx#1\relax\s!empty\else\dofloatparameter #1#2\fi}
+\def\dofloatparentparameterhash#1#2{\ifx#1\relax \else\dofloatparameterhash#1#2\fi}
+
+\def\detokenizedfloatparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??fl\currentfloat#1\endcsname}}
+
+\def\dosetfloatattributes#1#2% style color
+ {\edef\fontattributehash {\floatparameterhash#1}%
+ \edef\colorattributehash{\floatparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\def\floatcaptionparameter #1{\csname\dofloatcaptionparameter{\??kj\currentfloat}#1\endcsname}
+\def\floatcaptionparameterhash#1{\dofloatcaptionparameterhash {\??kj\currentfloat}#1}
+
+\def\dofloatcaptionparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dofloatcaptionparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dofloatcaptionparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dofloatcaptionparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dofloatcaptionparentparameter #1#2{\ifx#1\relax\s!empty\else\dofloatcaptionparameter #1#2\fi}
+\def\dofloatcaptionparentparameterhash#1#2{\ifx#1\relax \else\dofloatcaptionparameterhash#1#2\fi}
+
+\def\detokenizedcaptionparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??kj\currentfloat#1\endcsname}}
+
+\def\dosetfloatcaptionattributes#1#2% style color
+ {\edef\fontattributehash {\floatcaptionparameterhash#1}%
+ \edef\colorattributehash{\floatcaptionparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\def\dohandlenextfloatindent
+ {\checknextindentation[\floatparameter\c!indentnext]%
+ \dorechecknextindentation}
+
+%D The two shared (parent) definitions:
+
+% todo: everysetupfloat everysetupcaption for all floats
+
+\def\setupfloats {\dosingleargument\dosetupfloats} % was \??bk
+\def\setupcaptions{\dosingleargument\dosetupcaptions}
+
+\let\alldefinedfloats\empty
+
+\def\doprocessallfloats#1%
+ {\def\doprocesssomefloat##1{\def\currentfloat{##1}#1}%
+ \processcommacommand[\alldefinedfloats]\doprocesssomefloat}
+
+\def\dosetupfloats [#1]{\getparameters[\??fl][#1]\doprocessallfloats{\the\everysetupfloat}}
+\def\dosetupcaptions[#1]{\getparameters[\??kj][#1]\doprocessallfloats{\the\everysetupcaption}}
+
+% \def\dosetupfloats [#1]{\getparameters[\??fl][#1]}
+% \def\dosetupcaptions[#1]{\getparameters[\??kj][#1]}
+
+\setupcaptions
+ [\c!location=\v!bottom,
+ \c!grid=,
+ \c!before=, % not used (yet)
+ \c!inbetween={\blank[\v!medium]},
+ \c!after=, % not used (yet)
+ \c!spacebefore=,
+ \c!spaceinbetween=, % replaces fuzzy inbetween dual usage
+ \c!spaceafter=,
+ \c!width=\v!fit,
+ \c!minwidth=\v!fit, % id est: the width of the floatbox in some cases
+ \c!headstyle=\v!bold,
+ \c!headcolor=,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\zeropoint,
+ \c!outermargin=\zeropoint,
+ \c!innermargin=\zeropoint,
+ \c!setups=,
+ \c!style=\v!normal,
+ \c!color=,
+ \c!textstyle=,
+ \c!textcolor=,
+ \c!align=,
+ \c!number=\v!yes,
+\c!prefix=\v!no,
+\c!prefixconnector=.,
+\c!way=bychapter,
+\c!prefixsegments=2:2,
+% \c!way=\@@nrway,
+% \c!blockway=\@@nrblockway,
+% \c!sectionnumber=\@@nrsectionnumber,
+% \c!separator=\@@koseparator,
+% \c!stopper=\@@kostopper,
+% \c!suffix=\floatcaptionsuffix, % hook
+ \c!distance=1em,
+ \c!conversion=\v!numbers,
+ \c!command=]
+
+% we can comment some of these
+
+\setupfloats
+ [\c!location=\v!middle,
+ \c!width=8\lineheight,
+ \c!height=6\lineheight,
+ \c!offset=\v!overlay,
+ \c!frame=\v!off,
+ \c!strut=\v!no,
+ \c!radius=.5\bodyfontsize,
+ \c!corner=\v!rectangular,
+ \c!background=,
+ \c!backgroundscreen=,
+ \c!backgroundcolor=,
+ \c!backgroundoffset=\!!zeropoint,
+ \c!topframe=,
+ \c!bottomframe=,
+ \c!leftframe=,
+ \c!rightframe=,
+ \c!frameoffset=\!!zeropoint,
+ \c!before=,
+ \c!after=,
+ \c!spacebefore=\v!big,
+ \c!spaceafter=\v!big,
+ \c!sidespacebefore=\floatsharedparameter\c!spacebefore,
+ \c!sidespaceafter=\floatsharedparameter\c!spaceafter,
+ \c!sidealign=\v!normal,
+ \c!textmethod=\ifgridsnapping2\else0\fi, % 0=raw 1=safe (.99pg) 2=tight (-1pt)
+ \c!sidemethod=\ifgridsnapping2\else1\fi, % 0=raw 1=safe (.99pg) 2=tight (-1pt)
+ \c!indentnext=\v!no,
+ \c!margin=1em,
+ \c!method=1,
+ \c!cache=\v!yes, % when no, then intermediate flush
+ \c!leftmargin=\zeropoint, % displacement in 'normal floats'
+ \c!rightmargin=\zeropoint, % idem
+ \c!innermargin=\zeropoint, % idem
+ \c!outermargin=\zeropoint, % idem
+ \c!leftmargindistance=\zeropoint,
+ \c!rightmargindistance=\floatparameter\c!leftmargindistance,
+ \c!ntop=2,
+ \c!nbottom=0,
+ \c!nlines=4,
+ \c!local=,
+ \c!bottombefore=, % e.g. \vfill
+ \c!bottomafter=,
+ \c!default=\v!figure,
+ \c!numbering=\v!yes]
+
+\def\@@bknumbering {\floatsharedparameter\c!numbering } % global one
+\def\@@bkspaceafter {\floatsharedparameter\c!spaceafter } % global one
+\def\@@bkspacebefore{\floatsharedparameter\c!spacebefore} % global one
+\def\@@bknbottom {\floatsharedparameter\c!nbottom } % global one
+\def\@@bkntop {\floatsharedparameter\c!ntop } % global one
+\def\@@bknlines {\floatsharedparameter\c!nlines } % global one
+\def\@@bkmargin {\floatsharedparameter\c!margin } % global one
+\def\@@bkcache {\floatsharedparameter\c!cache } % global one
+
+% float
+%
+% [%\c!width=8\lineheight, % 15\bodyfontsize,
+% %\c!height=6\lineheight, % 10\bodyfontsize,
+% \c!offset=\v!overlay,
+% \c!width=\v!fit,
+% \c!height=\v!fit,
+% \c!minwidth=,
+% \c!maxwidth=,
+% \c!maxheight=,
+% \c!criterium=,
+% % inherited
+% \c!pageboundaries=,
+% \c!default=]%
+
+% number
+%
+% [\c!text=#1,
+% \c!location=\v!intext,
+% \c!way=\floatcaptionparameter\c!way,
+% \c!blockway=\floatcaptionparameter\c!blockway,
+% \c!sectionnumber=\floatcaptionparameter\c!sectionnumber,
+% \c!conversion=\floatcaptionparameter\c!conversion]%
+
+
+%D Individial settings:
+
+\def\setupfloat {\dodoubleargument\dosetupfloat}
+\def\setupcaption{\dodoubleargument\dosetupcaption}
+
+\newtoks\everysetupfloat
+\newtoks\everysetupcaption
+
+\def\dosetupfloat[#1][#2]%
+ {\def\docommand##1{\getparameters[\??fl##1][#2]\the\everysetupfloat}%
+ \processcommalist[#1]\docommand}
+
+\def\dosetupcaption[#1][#2]%
+ {\def\docommand##1{\getparameters[\??kj##1][#2]\the\everysetupcaption}%
+ \processcommalist[#1]\docommand}
+
+\appendtoks
+ \dostructurecountersetup\currentfloat\floatcaptionparameter
+\to \everysetupcaption
+
+%D Definitions:
+
+\def\definefloat
+ {\dotripleempty\dodefinefloat}
+
+\def\dodefinefloat[#1][#2][#3]% #1=naam #2=meervoud #3=parent
+ {\ifthirdargument
+ \redodefinefloat[#1][#2][#3]%
+ \else\ifsecondargument
+ \dododefinefloat[#1][#2]%
+ \else
+ \dododefinefloat[#1][#1]%
+ \fi\fi}
+
+\presetlocalframed[\??fl]
+
+\def\dododefinefloat[#1][#2]%
+ {\copylocalframed[\??fl#1][\??fl]%
+ \definestructurecounter[#1]%
+ \addtocommalist{#1}\alldefinedfloats
+ \setupfloat[#1][\s!parent=\??fl]%
+ \setupcaption[#1][\s!parent=\??kj]%
+ \definelist[#1]%
+ \presetlabeltext[#1=\Word{#1}~]%
+ \presetheadtext[#2=\Word{#2}]%
+ \dodefinefloatcommands[#1][#2]%
+ }% \newnodelocation{\v!float\@@thenumber{#1}}}
+
+\def\redodefinefloat[#1][#2][#3]%
+ {\copylocalframed[\??fl#1][\??fl#3]%
+ \setupfloat[#1][\s!parent=\??fl#3]%
+ \setupcaption[#1][\s!parent=\??kj#3]%
+ \definestructurecounter[#1][#3]%
+ \definelist[#1][#3]%
+ \presetlabeltext[#1=\Word{#3}]%
+ \presetheadtext[#2=\Word{#2}]%
+ \dodefinefloatcommands[#1][#2]}
+
+\def\dodefinefloatcommands[#1][#2]%
+ {\setvalue {\e!place\e!listof#2}{\dodoubleempty\doplacelist[#1]}%
+ \setvalue {\e!complete\e!listof#2}{\dotripleempty\dodocompletelist[#1][#2]}%
+ \setvalue {\e!place#1}{\dotripleempty\docomplexplacefloat[#1]}%
+ \setvalue {\e!reserve#1}{\doquadrupleempty\docomplexreserveblock[#1]}%
+ \setvalue {\e!start#1\e!text}{\dotripleempty\docomplexstarttextblock[#1]}%
+ \setvalue {\e!stop#1\e!text}{\dostoptextfloat}%
+ \setvalue{\e!start\e!reserve#1\e!text}{\doquadrupleempty\docomplexstartreservetextblock[#1]}%
+ \setvalue {\e!stop\e!reserve#1\e!text}{\dostoptextfloat}%
+ \setvalue {\e!emptyone#1}{\doemptyfloatblock{#1}}%
+ \setvalue {\e!emptytwo#1}{\doemptyfloatblock{#1}}}
+
+%D Fallback float body:
+
+\def\doemptyfloatblock#1%
+ {\framed
+ [\c!frame=\v!on,
+ \c!width=\floatsharedparameter\c!width,
+ \c!height=\floatsharedparameter\c!height,
+ \c!location=\v!normal,
+ \c!offset=\floatsharedparameter\c!offset]%
+ {\getmessage\m!floatblocks{12}\empty}}
+
+%D Data. We can generalize this to lists.
+
+\newif\ifnofloatcaption
+\newif\ifnofloatnumber
+\newif\ifemptyfloatcaption
+
+\def\getfloatparameters {\getparameters[\??fl\currentfloat]}
+\def\getcaptionparameters{\getparameters[\??kj\currentfloat]}
+
+\installstructurelistprocessor{float}{\usestructurelistprocessor{number+title}}
+
+\def\thecurrentfloatnumber
+ {\ifnofloatcaption \else \ifnofloatnumber \else
+% \labeltexts\currentfloat{\convertedstructurecounter[\currentfloat]}% ! ! todo: use a lua call instead
+\ifx\currentfloatnumber\relax\else
+ \labeltexts\currentfloat{\ctxlua{structure.lists.savednumber("\currentfloat",\currentfloatnumber)}}%
+\fi
+ \fi \fi}
+
+\def\thecurrentfloatcaption
+ {\ifnofloatcaption \else
+\ifx\currentfloatnumber\relax\else
+ \ctxlua{structure.lists.savedtitle("\currentfloat",\currentfloatnumber)}%
+\fi
+ \fi}
+
+%D Captions.
+
+\let\floatcaptionsuffix\empty % an optional suffix
+\let\floatcaptionnumber\empty % a logical counter
+
+% the split is needed when for instance the float goes into
+% a multi page field and the list of figs becomes larger than
+% one page: cycle between 'only flush when object ref ok'
+% and 'one/many page fig list'; see "uguide finometer"
+%
+% potential sync bug with sectionblocks, see uguide.tex
+
+% NOT YET REDONE ! ! ! ! !
+
+ \def\placefloatcaption
+ {\dodoubleempty\doplacefloatcaption}
+
+ \long\def\doplacefloatcaption[#1][#2]#3%
+ {\setfloatcaption[#1][#2]{#3}%
+ \placefloatcaptiontext[#1]%
+ \placefloatcaptionreference[#1]}
+
+ \def\setfloatcaption % \dosetfloatcaption already in use
+ {\dodoubleempty\dodosetfloatcaption} % beware, name clash
+
+ \long\def\dodosetfloatcaption[#1][#2]#3% to do namespace for number/ascii
+ {\ifnofloatnumber % also handle trialtypesetting
+ \letgvalue{@fl@r@#1}\relax
+ \letgvalue{@fl@t@#1}\relax
+ \else
+ \preparefloatnumber{#1}%
+ \letgvalue{@fl@n@#1}\composedsectionnumber
+ % indirect macro can be more efficient
+ \setgvalue{@fl@r@#1}%
+ {\tracefloatnumber{#1}%
+ \ifconditional\retainfloatnumber\else
+ % \dowritetolist{#1}{\getvalue{@fl@n@#1}}{#3}{#1}%
+ % \gdefconvertedargument\flasciititle{#3}% \asciititle is global
+ % \doifsomething{#2}{\rawreference\s!flt{#2}{{\getvalue{@fl@n@#1}}{\flasciititle}}}%
+ \fi
+ \letgvalue{@fl@r@#1}\relax}% nils
+ \setgvalue{@fl@t@#1}%
+ {\preparefullnumber{\??kj#1}{\getvalue{@fl@n@#1}}\preparednumber
+ \begingroup
+ \dosetfloatcaptionattributes\c!style\c!color
+ \begingroup
+ \dosetfloatcaptionattributes\c!headstyle\c!headcolor
+ \labeltexts{#1}{\preparednumber}%
+ \endgroup
+ \begingroup
+ \dosetfloatcaptionattributes\c!textstyle\c!textcolor
+ \dotfskip{\floatcaptionparameter\c!distance}#3%
+ \endgroup
+ \endgroup}%
+ \fi}
+
+ \long\def\dodosetfloatcaption[#1][#2]#3% to do namespace for number/ascii
+ {\letgvalue{@fl@r@#1}\relax
+ \letgvalue{@fl@t@#1}\relax}
+
+ \def\placefloatcaptiontext [#1]{\getvalue{@fl@t@#1}}
+ \def\placefloatcaptionnumber [#1]{\getvalue{@fl@n@#1}}
+ \def\placefloatcaptionreference[#1]{\getvalue{@fl@r@#1}}
+
+ % still needed for uguide
+
+ \let\placefloatlabel \placefloatcaption
+ \let\placefloatlabeltext \placefloatcaptiontext
+ \let\placefloatlabelreference \placefloatcaptionreference
+
+% TILL HERE
+
+\newbox\captionbox
+
+\long\def\putcompletecaption#1#2%
+ {\doifsomething{\floatcaptionparameter\c!spacebefore}{\blank[\floatcaptionparameter\c!spacebefore]}%
+ %\floatcaptionparameter\c!before % test for side effects first
+ \noindent
+ \gdef\lastcaptiontag{\strut#1}% was xdef
+ \begingroup
+ \dosetfloatcaptionattributes\c!style\c!color
+ \ifnofloatnumber
+ \else
+ \hbox{\dosetfloatcaptionattributes\c!headstyle\c!headcolor\strut#1}%
+ \ifnofloatcaption \else \ifemptyfloatcaption \else
+ \doifelsenothing{\floatcaptionparameter\c!spaceinbetween}
+ {\scratchskip\floatcaptionparameter\c!distance\relax
+ \dotfskip\scratchskip\emergencystretch.5\scratchskip}
+ {\blank[\floatcaptionparameter\c!spaceinbetween]}%
+ \fi \fi
+ \fi
+ \ifnofloatcaption
+ \globallet\lastcaptionht\!!zeropoint
+ \globallet\lastcaptiondp\!!zeropoint
+ \else
+ \dosetfloatcaptionattributes\c!textstyle\c!textcolor
+ \xdef\lastcaptionht{\strutheight}%
+ \xdef\lastcaptiondp{\strutdepth}%
+ \begstrut#2\endstrut\endgraf
+ \fi
+ \endgroup
+ %\floatcaptionparameter\c!after % test for side effects first
+ \doifsomething{\floatcaptionparameter\c!spaceafter}{\blank[\floatcaptionparameter\c!spaceafter]}}
+
+\let\lastcaptionht\!!zeropoint
+\let\lastcaptiondp\!!zeropoint
+
+\newbox\tempcaptionbox
+
+\newif\iftracecaptions
+
+\def\settracedcaptionbox
+ {\iftracecaptions\setbox\tempcaptionbox\ruledhbox{\box\tempcaptionbox}\fi}
+
+% \definefloat [figure-1] [figure]
+% \definefloat [figure-2] [figure]
+% \setupfloat [figure-1] [location=left,leftmargin=10mm]
+% \setupfloat [figure-2] [location=left,leftmargin=-5mm]
+% \setupcaption [figure-1] [align=flushleft]
+% \setupcaption [figure-2] [align=flushleft,leftmargin=15mm]
+%
+% \startsetups somefigure
+% \ifdim\wd\nextbox>\textwidth
+% \placefloat[figure-2][][]{}{\box\nextbox}
+% \else
+% \placefloat[figure-1][][]{}{\box\nextbox}
+% \fi
+% \stopsetups
+%
+% \def\setupswithbox[#1]{\dowithnextbox{\setups[#1]}\vbox}
+%
+% test \setupswithbox[somefigure]{\framed[width=3cm] {}} test
+% test \setupswithbox[somefigure]{\framed[width=\dimexpr\textwidth+3cm\relax]{}} test
+
+\def\dosetcaptionthings
+ {\setups[\floatcaptionparameter\c!setups]% expanded ?
+ %\advance\leftskip \floatcaptionparameter\c!leftmargin
+ %\advance\rightskip\floatcaptionparameter\c!rightmargin
+ \relax}
+
+\def\dofakecaptionthings
+ {\hbox{\dosetcaptionthings\hskip\leftskip\hskip\rightskip}}
+
+\long\def\docheckcaptioncontent#1#2%
+ {\ifnofloatcaption \else
+ \setbox\tempcaptionbox\hbox
+ {\trialtypesettingtrue
+ \notesenabledfalse
+ \putcompletecaption{#1}{#2}}%
+ % new, \placefigure{\XMLflush{somecaption}}{} passes earlier empty check
+ % so here we misuse the scratch box; actually this means that the previous
+ % test can go away (some day, when i redo this module)
+ \ifdim\wd\tempcaptionbox=\zeropoint
+ \global\emptyfloatcaptiontrue
+ \ifnofloatnumber
+ \global\nofloatcaptiontrue
+ \fi
+ \else
+ \setbox\tempcaptionbox\hbox{\dosetcaptionthings\hskip\leftskip\box\tempcaptionbox}% yet incomplete
+ \fi
+ \fi}
+
+% the tricky part of getting float related two pass data is
+% that we should fetch is early but can only save it with
+% the composed float box; this determines the order: get it
+% before saving it
+
+\definetwopasslist{\s!float\s!data} \newcounter\noffloatdata
+
+\let\twopassfloatdata\realpageno % used for odd/even determination, can be combined with nodelocation
+
+\def\dosavefloatdata % \expanded
+ {\doglobal\increment\noffloatdata
+ \lazysavetaggedtwopassdata{\s!float\s!data}{\noffloatdata}{\noffloatpages}{\noexpand\realfolio}}% later {}{}{}{} and \getfirst...
+
+\def\dogetfloatdata % precedes save !
+ {\doglobal\increment\noffloatpages
+ \findtwopassdata{\s!float\s!data}{\noffloatpages}%
+ \iftwopassdatafound
+ \globallet\twopassfloatdata\twopassdata
+ \else
+ \globallet\twopassfloatdata\realpageno % \realfolio
+ \fi}
+
+\def\tracefloatnumber#1%
+ {\doifnot{\floatsharedparameter\c!numbering}\v!nocheck{\tagnodelocation{\v!float\@@thenumber{#1}}}}
+
+\newconditional\retainfloatnumber
+
+\def\preparefloatnumber#1%
+ {\xdef\floatcaptionnumber{#1}%
+ \doifelsenodelocation{\v!float\@@thenumber{#1}}
+ \donothing {\chardef\nodelocationmode\zerocount}%
+ \doifelse{\floatsharedparameter\c!numbering}\v!nocheck
+ {\incrementnumber[#1]%
+ \makesectionnumber[#1]%
+ \ifconditional\retainfloatnumber\decrementnumber[#1]\fi}
+ {\ifinsidecolumns
+ \chardef\nodelocationmode\zerocount
+ % to be perfected:
+ % \chardef\nodelocationmode\plustwo
+ \fi
+% FOR THE MOMENT NOT AVAILABLE
+\chardef\nodelocationmode\zerocount
+% BUT NOT THAT HARD TO DO
+ \ifcase\nodelocationmode
+ \incrementnumber[#1]%
+ \makesectionnumber[#1]%
+ \ifconditional\retainfloatnumber\decrementnumber[#1]\fi
+ \else
+ % force check, so that we get a proper way-sync and
+ % can use the accumulated number
+ % \checknumber[#1]% \incrementnumber does this
+ \incrementnumber[#1]%
+ \savenumber[#1]%
+ % the real work is done here
+ \nextnodelocation{\v!float\@@thenumber{#1}}% better \nextfloatnumber
+ \analyzenodelocation{\v!float\@@thenumber{#1}}%
+ \scratchcounter\getnodelocationo{\v!float\@@thenumber{#1}}%
+ \advance\scratchcounter\minusone
+ % here we correct for 'per whatever handling'
+ \advance\scratchcounter-\accumulatednumber[#1]%
+ \setnumber[#1]\scratchcounter
+ \incrementnumber[#1]%
+ \makesectionnumber[#1]%
+ \restorenumber[#1]%
+ % now we're back to normal numbering
+ \fi}}
+
+%D test case:
+%D
+%D \starttyping
+%D \setupfloat[figure][criterium=\marginwidth,fallback=bottom]
+%D \dorecurse{3}{
+%D \chapter{test}
+%D \placefigure[bottom]{1}{\framed{bottom}}
+%D test
+%D \placetable[bottom]{1}{\framed{table}}
+%D test
+%D \placetable{2}{\framed{table}}
+%D test
+%D \placefigure[left]{2}{\framed{left but way too wide}}
+%D \input tufte
+%D \placefigure[left]{3}{\framed{left but ok}}
+%D \input tufte }
+%D \stoptyping
+
+% A complication is that we may have to handle a pagebreak
+% first, which in turn may issue a (postponed) float.
+% Therefore we may not trust on variable assignments before
+% we're realy dealing with the float. Some day I'll root out
+% the global settings.
+
+\def\docomplexplacefloat[#1][#2]% [#3]#4%
+ {\edef\currentfloat{#1}%
+ \doifnothing\currentfloat{\let\currentfloat\v!figure}%
+ \doifelsenothing{#2}
+ {\edef\floatlocation{\floatparameter\c!default}}
+ {\edef\floatlocation{#2}}%
+ \doifinsetelse\v!split{#2}
+ {\normalexpanded{\noexpand\dodocomplexsplitfloat[\currentfloat][\floatlocation]}}
+ {\normalexpanded{\noexpand\dodocomplexplacefloat[\currentfloat][\floatlocation]}}}
+
+\long\def\dodocomplexsplitfloat[#1][#2][#3]#4%
+ {\splitfloat{\dodocomplexplacefloat[#1][#2][#3]{#4}}}
+
+\def\flushfloatslist
+ {\v!left,\v!right,\v!inner,\v!outer,%
+ \v!backspace,\v!cutspace,%
+ \v!inleft,\v!inright,\v!inmargin,%
+ \v!leftmargin,\v!rightmargin,\v!leftedge,\v!rightedge,%
+ \v!innermargin,\v!outermargin,\v!inneredge,\v!outeredge,%
+ \v!text,\v!opposite}% \v!page
+
+\long\def\dodocomplexplacefloat[#1][#2][#3]#4%
+ {\flushnotes
+ \flushsidefloats % here !
+ \ifsomefloatwaiting
+ % this was \checkwaitingfloats spread all over
+ \doifinsetelse\v!always{#2}
+ {\showmessage\m!floatblocks5\empty}
+ {\normalexpanded{\noexpand\doifcommonelse{#2}{\flushfloatslist}}\doflushfloats\donothing}%
+ % but which should be done before using box \floatbox
+ \fi
+ \ifmargeblokken
+ \doifinset\v!margin{#2}\endgraf
+ \fi
+ \global\insidefloattrue
+ \begingroup % **
+ \ifmargeblokken
+ \doifinset\v!margin{#2}{\hsize\@@mbwidth}%
+ \fi
+ \the\everyinsidefloat
+ \let\@@extrafloat\empty
+ \presetmorefloatvariables{#2}%
+ \dowithnextboxcontent % better a \the\everyfloattoks
+ {\setlocalfloathsize
+ \floatparameter\c!inner
+ \fuzzysnappingfalse
+ \postponenotes} % new
+ {\doifsomething{\floatparameter\c!criterium}
+ {\ifdim\wd\nextbox>\floatparameter\c!criterium\relax
+ \edef\forcedfloatmethod{\floatvariable\c!fallback}%
+ \ifx\forcedfloatmethod\empty\let\forcedfloatmethod\v!here\fi
+ \fi}%
+ \xdocompletefloat{#1}{#3}{#2}{#4}% ** not yet done
+ % we need to carry over the par because of side floats
+ \doifnotinset\v!text{#2}{\carryoverpar\endgroup}%
+ \global\sidefloatdownshift \zeropoint
+ \global\sidefloatextrashift\zeropoint
+ \ifparfloat
+ \doifinset\v!reset{#2}\forgetsidefloats
+ \doinhibitblank
+ \fi}% better move this to side floats
+ \vbox}
+
+\def\xxdocompletefloat#1#2%
+ {\rightorleftpageaction{\let\@@extrafloat#1}{\let\@@extrafloat#2}}
+
+\chardef\textfloatmethod=0 % 0=raw 1=safe (.99) 2=tight (-1pt)
+\chardef\sidefloatmethod=1 % 0=raw 1=safe (.99) 2=tight (-1pt)
+
+\let\floatrotation\!!zerocount
+
+\long\def\presetfloatvariables#1#2#3#4%
+ {\doifcommonelse
+ {#2}
+ {\v!left,\v!right,\v!inner,\v!outer,%
+ \v!inleft,\v!inright,\v!inmargin,%
+ \v!backspace,\v!cutspace,%
+ \v!innermargin,\v!outermargin,\v!inneredge,\v!outeredge,%
+ \v!leftmargin,\v!leftedge,\v!rightmargin,\v!rightedge}
+ {\global\parfloattrue}
+ {\global\parfloatfalse}%
+ \ifinsidecolumns
+ \global\parfloatfalse
+ \fi
+ \global\sidefloatshift\zeropoint
+ \global\sidefloatmaximum\zeropoint
+ \global\chardef\sidefloatmethod\floatparameter\c!sidemethod
+ \global\chardef\textfloatmethod\floatparameter\c!textmethod
+ \global\chardef\sidefloatalign\zerocount
+ \globallet\floatrotation\!!zerocount
+ \calculatefloatskips
+ \ifparfloat
+ \processaction
+ [\floatparameter\c!sidealign]
+ [\v!height=>\global\chardef\sidefloatalign\plusone,%
+ \v!line=>\global\chardef\sidefloatalign\plustwo,% (***)
+ \v!depth=>\global\chardef\sidefloatalign\plusthree,%
+ \v!grid=>\global\chardef\sidefloatalign\plusfour,%
+ \v!halfline=>\global\chardef\sidefloatalign\plusfive]%
+ % todo (test first): \doifinset\v!lokaal{#2}{\chardef\sidefloatalign\zerocount}%
+ \ifcase\sidefloatalign\relax % todo: optie v!lokaal => \else
+ \doifinset\v!height {#2}{\global\chardef\sidefloatalign\plusone}%
+ \doifinset\v!line {#2}{\global\chardef\sidefloatalign\plustwo}%
+ \doifinset\v!depth {#2}{\global\chardef\sidefloatalign\plusthree}%
+ \doifinset\v!grid {#2}{\global\chardef\sidefloatalign\plusfour}%
+ \doifinset\v!halfline{#2}{\global\chardef\sidefloatalign\plusfive}% meant for 'none'
+ \fi
+ \doifinset\v!high{#2}{\global\sidefloattopskip \zeropoint}%
+ \doifinset\v!low {#2}{\global\sidefloatbottomskip\zeropoint}%
+ \doifinset\v!fit {#2}
+ {\global\sidefloattopskip \zeropoint
+ \global\sidefloatbottomskip\zeropoint
+ \global\floatsideskip \zeropoint}%
+ \else
+ \processallactionsinset
+ [#2]
+ [ 90=>\globallet\floatrotation\commalistelement,%
+ 180=>\globallet\floatrotation\commalistelement,%
+ 270=>\globallet\floatrotation\commalistelement]%
+ \fi
+ \doifinsetelse\v!nonumber{#2}
+ {\global\nofloatnumbertrue}
+ {\doifelse{\floatcaptionparameter\c!number}\v!yes
+ {\global\nofloatnumberfalse}
+ {\global\nofloatnumbertrue}}%
+ % this has to change
+ \ConvertToConstant\doifelse{#4}{}
+ {\global\emptyfloatcaptiontrue}
+ {\global\emptyfloatcaptionfalse}%
+ \doifinsetelse\v!none{#2}
+ {\global\nofloatcaptiontrue}
+ {\ConvertToConstant\doifelse{#4}\v!none
+ {\global\nofloatcaptiontrue}
+ {\global\nofloatcaptionfalse}}%
+ \doif{\floatcaptionparameter\c!number}\v!none % new
+ {\global\nofloatcaptiontrue}%
+ \ifemptyfloatcaption \ifnofloatnumber
+ \global\nofloatcaptiontrue
+ \fi \fi}
+
+% documenteren in details
+
+\def\presetmorefloatvariables#1%
+ {\doifelse{\floatparameter\c!local}\v!yes % fout keyword
+ \globalcenterfloatboxtrue
+ \globalcenterfloatboxfalse
+ \ifglobalcenterfloatbox
+ \localcenterfloatboxtrue
+ \else
+ \doifinsetelse\v!local{#1}
+ \localcenterfloatboxtrue
+ \localcenterfloatboxfalse
+ \fi
+ \doifnotcommon{\v!always,\v!here,\v!force}{#1} % ! ! ! ! ! !
+ {\globalcenterfloatboxfalse
+ \localcenterfloatboxfalse}}
+
+\let\naturalfloatheight\!!zeropoint
+\let\naturalfloatwidth \!!zeropoint
+\let\naturalfloatdepth \!!zeropoint
+
+\def\setnaturalfloatdimensions#1%
+ {\xdef\naturalfloatheight{\the\ht#1}%
+ \xdef\naturalfloatwidth {\the\wd#1}%
+ \xdef\naturalfloatdepth {\the\dp#1}}
+
+\long\def\doifelsemainfloatbody#1#2%
+ {\ifinsidesplitfloat\ifconditional\splitfloatfirstdone#2\else#1\fi\else#1\fi}
+
+% todo: optional user pars
+
+\long\def\docompletefloat#1#2#3#4#5% #1:floatclass #2:reference #3:optionlist #4:caption #5:box number
+ {\presetfloatvariables{#1}{#3}{#2}{#5}% check this one
+ \bgroup
+ % prepare structure data
+ %
+ % \dofloatcomponent[\c!name=#1,\c!reference=#2,\c!bookmark=,\c!title={#4}][]% ifnofloatnumber ifnofloatcaption \tracefloatnumber{#1}%
+ %
+ \dostructurecountercomponent
+ {float}%
+ \getcaptionparameters
+ \floatcaptionparameter
+ \detokenizedcaptionparameter
+ \relax
+ \relax
+ \relax
+ [\c!name=\currentfloat,\s!counter=\currentfloat,%
+ \s!hascaption=\ifnofloatcaption \v!no\else\v!yes\fi,%
+ \s!hasnumber=\ifnofloatnumber \v!no\else\v!yes\fi,%
+ \s!hastitle=\ifemptyfloatcaption\v!no\else\v!yes\fi,%
+ \c!reference=#2,\c!title={#4},\c!bookmark=]%
+ []%
+ \globallet\currentfloatnumber \laststructurecounternumber
+ \globallet\currentfloatsynchronize\laststructurecountersynchronize
+ %
+ % check float box
+ \setnaturalfloatdimensions#5%
+ \global\setbox\floatbox\vbox{\floatparameter\c!command{\box#5}}%
+ \setnaturalfloatdimensions\floatbox
+ \ifdim\htdp\floatbox=\zeropoint
+ \showmessage\m!floatblocks{11}\empty
+ \global\setbox\floatbox\vbox{\doemptyfloatblock{#1}}%
+ \fi
+ % deal with lack of caption
+ \global\setbox\floatbox\vbox
+ {\doifelsemainfloatbody\currentfloatsynchronize\donothing
+ \unvbox\floatbox
+ \ifnofloatcaption
+ \vss
+ \fi}% gets rid of the depth (unless tabulate)
+ \egroup
+ % place the float
+ \dofloat{#3}{\thecurrentfloatnumber}{\thecurrentfloatcaption}%
+ \global\insidefloatfalse}
+
+\def\setlocalfloathsize
+ {\iflocalcenterfloatbox
+ \seteffectivehsize
+ \hsize\localhsize
+ \fi}
+
+\newevery \everyinsidefloat \relax
+
+\appendtoks
+ \everyinsidefloat\emptytoks % in case it's called earlier
+ \dogetfloatdata
+\to \everyinsidefloat
+
+%\appendtoks
+% \fuzzysnappingfalse
+%\to \everyinsidefloat
+
+\def\doifrightpagefloatelse
+ {\ifdoublesided
+ \ifsinglesided
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\doifoddfloatpageelse
+ \fi
+ \else
+ \@EA\firstoftwoarguments
+ \fi}
+
+\def\doifoddfloatpageelse
+ {\ifodd\purenumber\twopassfloatdata\space
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\appendtoks
+ \let\rightorleftpageaction\doifrightpagefloatelse
+\to \everyinsidefloat
+
+\newif\ifextrafloatactions \extrafloatactionstrue
+
+% \let\movesidefloat\gobbleoneargument
+
+% new : \place...[leftmargin,-2*line]; we need to catch fxtb:2*3
+% watch out: line alone aligns on the line ! ! !
+
+\def\movesidefloat[#1]% (-)n*line|x=,y=
+ {\global\sidefloatdownshift \zeropoint
+ \global\sidefloatextrashift\zeropoint
+ \doifassignmentelse{#1}%
+ {\bgroup
+ \getparameters[\??fl][\c!x=\zeropoint,\c!y=\zeropoint,#1]%
+ \ifgridsnapping
+ \getnoflines\@@fly
+ \global\sidefloatdownshift\noflines\lineheight
+ \else
+ \global\sidefloatdownshift\@@fly
+ \fi
+ \global\sidefloatextrashift\@@flx
+ \egroup}
+ {\movedownsidefloat[#1]}}
+
+\def\movedownsidefloat[#1]% already in core
+ {\bgroup
+ \cleanupfeatures
+ \doifinstringelse{:}{#1}
+ \donothing
+ {\def\docommand##1%
+ {\processaction
+ [##1]%
+ [ \v!line=>\dodocommand+,%
+ +\v!line=>\dodocommand+,%
+ -\v!line=>\dodocommand-]}%
+ \def\dodocommand##1%
+ {\ifdone\else\global\sidefloatdownshift\zeropoint\donetrue\fi
+ \global\advance\sidefloatdownshift##1\lineheight}%
+ \donefalse\normalexpanded{\noexpand\dorepeatwithcommand[#1]}\docommand
+ \def\docommand##1%
+ {\processaction
+ [##1]%
+ [ \v!hang=>\dodocommand+,%
+ +\v!hang=>\dodocommand+,%
+ -\v!hang=>\dodocommand-]}%
+ \def\dodocommand##1% inefficient but who cares
+ {\ifdone\else\global\sidefloatsidelines\zeropoint\donetrue\fi
+ \global\advance\sidefloatsidelines\plusone\relax}%
+ \donefalse\normalexpanded{\noexpand\dorepeatwithcommand[#1]}\docommand}%
+ \egroup}
+
+\def\hangsidefloat[#1]%
+ {\global\sidefloatsidelines#1\relax}
+
+\long\def\xdocompletefloat#1#2#3#4%
+ {\ifextrafloatactions
+ \doifinsetelse\v!text{#3}
+ {% fuzzy, text overloads left, since then it's a directive
+ \docompletefloat{#1}{#2}{#3}{#4}\nextbox}
+ {\let\@@extrafloat\empty
+ % \sidefloatdownshift will be reset afterwards, and can
+ % already be set at this point
+ \processallactionsinset
+ [#3] % ininner/inouter : for old times sake
+ [ \v!inner=>\xxdocompletefloat\v!left \v!right,
+ \v!outer=>\xxdocompletefloat\v!right \v!left,
+ \v!innermargin=>\xxdocompletefloat\v!leftmargin \v!rightmargin,
+ \v!outermargin=>\xxdocompletefloat\v!rightmargin\v!leftmargin,
+ \v!inneredge=>\xxdocompletefloat\v!leftedge \v!rightedge,
+ \v!outeredge=>\xxdocompletefloat\v!rightedge \v!leftedge,
+ \v!backspace=>\xxdocompletefloat\v!backspace \v!cutspace,
+ \v!cutspace=>\xxdocompletefloat\v!cutspace \v!backspace,
+% \v!margin=>\xxdocompletefloat\v!cutspace \v!backspace,
+ \v!left=>\xxdocompletefloat\v!left \v!left,
+ \v!right=>\xxdocompletefloat\v!right \v!right,
+ \v!line=>, % only -n*line is handled (see ***)
+ \s!unknown=>{\movedownsidefloat[\commalistelement]}]%
+ \ifx\@@extrafloat\empty
+ \docompletefloat{#1}{#2}{#3}{#4}\nextbox
+ \else
+ \docompletefloat{#1}{#2}{\@@extrafloat,#3}{#4}\nextbox
+ \fi}%
+ \else % downward compatible
+ \docompletefloat{#1}{#2}{#3}{#4}\nextbox
+ \fi}
+
+% pas op, maxbreedte niet instellen als plaats=links/rechts
+
+\def\setlocalfloatdimensions#1%
+ {\global\sidefloatshift \zeropoint % duplicate
+ \global\sidefloatmaximum\zeropoint\relax % duplicate
+ \ifextrafloatactions
+ \ifdim\sidefloatdownshift=\zeropoint\else
+ \global\setbox\floatbox\vbox
+ {\vskip\sidefloatdownshift\nointerlineskip\box\floatbox}%
+ \fi
+ \doifsomething{\floatparameter\c!minwidth}
+ {\scratchdimen\floatparameter\c!minwidth\relax
+ \ifdim\wd\floatbox<\scratchdimen
+ \global\setbox\floatbox\hbox to \scratchdimen
+ {\doifnot{\floatparameter\c!location}\v!left \hss
+ \box\floatbox%
+ \doifnot{\floatparameter\c!location}\v!right\hss}%
+ \fi}%
+ % todo: rand / rug
+ \doifinset\v!hanging{#1}
+ {\doifcommonelse{\v!inleft,\v!leftmargin}{#1}
+ {\letfloatparameter\c!maxwidth\leftmarginwidth}%
+ {\doifcommon{\v!inright,\v!rightmargin}{#1}
+ {\letfloatparameter\c!maxwidth\rightmarginwidth}}}%
+ \doifsomething{\floatparameter\c!maxwidth}
+ {\scratchdimen\floatparameter\c!maxwidth\relax
+ \ifdim\wd\floatbox>\scratchdimen
+ \doifcommonelse{\v!inright,\v!rightmargin,\v!rightedge
+ \v!inleft,\v!leftmargin,\v!leftedge}{#1}
+ {\global\sidefloatmaximum\scratchdimen}
+ {\global\setbox\floatbox\hbox to \scratchdimen
+ {\doifcommonelse{\v!right,\v!left}{#1}
+ {\doifnotinset\v!right{#1}\hss
+ \box\floatbox
+ \doifnotinset\v!left{#1}\hss}%
+ {\doifnot{\floatparameter\c!location}\v!left\hss
+ \box\floatbox
+ \doifnot{\floatparameter\c!location}\v!right\hss}}}%
+ \fi}%
+ \fi}
+
+\def\docomplexstarttextblock[#1][#2][#3]%
+ {\flushnotes
+ \flushsidefloats % hoort eigenlijk niet hier
+ \docomplexplacefloat[#1][\v!text,#2,\v!left][#3]}
+
+\long\def\docomplexreserveblock[#1][#2][#3][#4]#5%
+ {\getvalue{\e!place#1}[#3][#4]{#5}{\localframed[\??fl#1][#2]{#1}}}
+
+\def\docomplexstartreservetextblock[#1][#2][#3][#4]%
+ {\flushsidefloats % hoort eigenlijk niet hier
+ \docomplexreserveblock[#1][#2][\v!text,#3,\v!left][#4]}
+
+\def\placefloat
+ {\dotripleempty\docomplexplacefloat}
+
+\installinsertion\topins
+\installinsertion\botins
+
+\newdimen\botinserted
+\newdimen\topinserted
+
+%D Extra float registers.
+
+\newif\ifsomefloatwaiting \somefloatwaitingfalse
+\newif\ifroomforfloat \roomforfloattrue
+\newif\ifnofloatpermitted \nofloatpermittedfalse
+
+\newcount\totalnoffloats \totalnoffloats =0
+\newcount\savednoffloats \savednoffloats =0
+\newcount\noffloatinserts \noffloatinserts=0
+
+\newbox\floatlist
+\newbox\savedfloatlist
+
+\newif\ifflushingfloats \flushingfloatsfalse
+
+\newbox\floattext
+
+\newdimen\floattextwidth
+\newdimen\floattextheight
+
+\newbox\floatbox
+\newbox\savedfloatbox
+
+\newdimen\floatwidth
+\newdimen\floatheight
+
+% In \dofloatinfomessage wordt {{ }} gebruikt omdat anders
+% binnen \startpostponing...\stoppostponing geen goede
+% melding in de marge volgt: \ifinner is dan namelijk true.
+
+\def\dofloatinfomessage#1#2#3%
+ {\bgroup
+ \showmessage\m!floatblocks{#2}{#3}%
+ \setmessagetext\m!floatblocks{#2}%
+ \@EA\floatinfo\@EA#1\@EA{\currentmessagetext}%
+ \egroup}
+
+\def\dosavefloatinfo
+ {\dofloatinfomessage>2{\the\totalnoffloats}}
+
+\def\dofloatflushedinfo
+ {\bgroup
+ \!!counta\totalnoffloats
+ \advance\!!counta -\savednoffloats
+ \dofloatinfomessage<3{\the\!!counta}%
+ \egroup}
+
+\def\doinsertfloatinfo
+ {\dofloatinfomessage<4{\the\totalnoffloats}}
+
+\def\dogetfloat
+ {\ifsomefloatwaiting
+ \global\setbox\floatlist\vbox
+ {\unvbox\floatlist
+ \global\setbox\globalscratchbox\lastbox}%
+ \ifcenterfloatbox
+ \ifdim\wd\globalscratchbox<\hsize
+ \setbox\floatbox\hbox to \hsize{\hss\box\globalscratchbox\hss}%
+ \else
+ \setbox\floatbox\box\globalscratchbox % local !
+ % retain special alignments
+ \ifinsidecolumns
+ \ifdim\wd\floatbox>\makeupwidth
+ \wd\floatbox\makeupwidth
+ \fi
+ \fi
+ \fi
+ \else
+ \setbox\floatbox\box\globalscratchbox % local !
+ \fi
+ \global\advance\savednoffloats \minusone
+ \ifcase\savednoffloats
+ \global\somefloatwaitingfalse
+ \fi
+ \else
+ \global\savednoffloats\zerocount
+ \global\setbox\floatbox\emptybox
+ \fi}
+
+\def\uncenteredfloatbox
+ {\ifcenterfloatbox
+ \ifhbox\floatbox\relax % remove centering
+ \ifdim\wd\floatbox=\hsize
+ \ifhbox\floatbox
+ \setbox\scratchbox\hbox
+ {\unhbox\floatbox
+ \unskip\unskip
+ \global\setbox\globalscratchbox\lastbox}%
+ \box\globalscratchbox
+ \else
+ \box\floatbox
+ \fi
+ \else
+ \box\floatbox
+ \fi
+ \else
+ \box\floatbox
+ \fi
+ \else
+ \box\floatbox
+ \fi}
+
+\def\dosavefloat
+ {\global\setbox\floatlist\vbox
+ {\nointerlineskip
+ \uncenteredfloatbox
+ \unvbox\floatlist}%
+ \global\advance\savednoffloats \plusone
+ \global\somefloatwaitingtrue
+ \dosavefloatinfo
+ \nonoindentation}
+
+\def\doresavefloat
+ {\global\setbox\floatlist\vbox
+ {\nointerlineskip
+ \unvbox\floatlist
+ \uncenteredfloatbox}%
+ \global\advance\savednoffloats \plusone
+ \global\somefloatwaitingtrue}
+
+\def\doreversesavefloat
+ {\global\setbox\floatlist\vbox
+ {\nointerlineskip
+ \unvbox\floatlist
+ \uncenteredfloatbox}%
+ \global\advance\savednoffloats \plusone
+ \global\somefloatwaitingtrue
+ \dosavefloatinfo}
+
+% better (todo): \savednofsavedfloats
+
+\def\dosavefloatstatus
+ {\global\setbox\savedfloatlist\copy\floatlist
+ \global\setbox\savedfloatbox \copy\floatbox
+ \xdef\dorestorefloatstatus
+ {\global\setbox\floatlist\box\savedfloatlist
+ \global\setbox\floatbox \box\savedfloatbox
+ \global\savednoffloats\the\savednoffloats}}
+
+\let\dorestorefloatstatus\relax
+
+\ifx\doflushfloats\undefined \let\doflushfloats\relax \fi
+\ifx\flushfloatbox\undefined \let\flushfloatbox\relax \fi
+
+% needed in the splitter:
+
+\newcount\savedsavednoffloats
+
+\let\dopopsavedfloats\relax
+
+\def\dopushsavedfloats
+ {\global\setbox\savedfloatlist\box\floatlist
+ \global\savedsavednoffloats\savednoffloats
+ \global\savednoffloats\savednoffloats
+ \global\somefloatwaitingfalse
+ \gdef\dopopsavedfloats
+ {\global\advance\savednoffloats\savedsavednoffloats
+ \global\setbox\floatlist\vbox\bgroup
+ \ifvoid\floatlist \else\unvbox\floatlist \fi
+ \ifvoid\savedfloatlist\else\unvbox\savedfloatlist\fi
+ \egroup
+ \global\ifcase\savednoffloats
+ \somefloatwaitingfalse\else\somefloatwaitingtrue\fi
+ \globallet\dopopsavedfloats\relax}}
+
+\def\doflushsavedfloats % simplified \OTRONEdodoflushfloats
+ {\doloop
+ {\ifsomefloatwaiting
+ \dogetfloat
+ \dofloatflushedinfo
+ \docheckiffloatfits
+ \ifroomforfloat
+ \doplacefloatbox
+ \else
+ \doreversesavefloat
+ \exitloop
+ \fi
+ \else
+ \exitloop
+ \fi}}
+
+% top and bottom
+
+\newif\iftopofinsert
+\newif\iftestfloatbox
+\newif\ifcenterfloatbox \centerfloatboxtrue
+\newif\iflocalcenterfloatbox \localcenterfloatboxfalse
+\newif\ifglobalcenterfloatbox \globalcenterfloatboxfalse
+
+% beter de laatste skip buiten de \insert uitvoeren,
+% bovendien bij volle flush onder baseline.
+
+\def\betweenfloatblanko% assumes that spaceafter is present
+ {\bgroup
+ \setbox0\vbox{\strut\blank[\floatsharedparameter\c!spacebefore]\strut}%
+ \setbox2\vbox{\strut\blank[\floatsharedparameter\c!spaceafter]\strut}%
+ \ifdim\ht0>\ht2
+ \blank[-\floatsharedparameter\c!spaceafter,\floatsharedparameter\c!spacebefore]%
+ \fi
+ \egroup}
+
+\def\doplacefloatbox
+ {%\forgetall % NO
+ \whitespace
+ \blank[\floatsharedparameter\c!spacebefore]
+ \flushfloatbox
+ \blank[\floatsharedparameter\c!spaceafter]}
+
+\ifx\someherefloat\undefined \let\someherefloat\doplacefloatbox \fi
+\ifx\somefixdfloat\undefined \let\somefixdfloat\doplacefloatbox \fi
+\ifx\somepagefloat\undefined \let\somepagefloat\doplacefloatbox \fi
+\ifx\sometopsfloat\undefined \let\sometopsfloat\doplacefloatbox \fi
+\ifx\somebotsfloat\undefined \let\somebotsfloat\doplacefloatbox \fi
+
+\ifx\somesidefloat\undefined \let\somesidefloat\doplacefloatbox \fi
+\ifx\somefacefloat\undefined \let\somefacefloat\doplacefloatbox \fi
+\ifx\sometextfloat\undefined \let\sometextfloat\doplacefloatbox \fi
+
+% brr, wordt deze niet overladen in page-one? weg er mee
+
+% \def\somepagefloat[#1]% links, rechts, midden, hoog, midden, laag
+% {%\checkwaitingfloats{#1}%
+% \global\setbox\collectedpagefloats\vbox
+% {\unvbox\collectedpagefloats
+% \vbox to \textheight
+% {\doifnotinset\v!high{#1}\vfill
+% \box\floatbox
+% \doifnotinset\v!low{#1}\vfill}%
+% \goodbreak}%
+% \doinsertfloatinfo}
+
+% \def\OTRONEsomepagefloat[#1]%
+% {%\checkwaitingfloats{#1}%
+% \global\setbox\collectedpagefloats\vbox
+% {\ifvoid\collectedpagefloats\else\unvbox\collectedpagefloats\fi
+% \vbox to \textheight % vss and unvbox catch too high and limited floats
+% {\vss
+% \doifnotinset\v!high{#1}\vfill
+% \unvbox\floatbox
+% \doifnotinset\v!low{#1}\vfill
+% \vss}%
+% \goodbreak}%
+% \doinsertfloatinfo}
+
+% test case:
+%
+% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=0.9\textheight,color=green]}
+% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=1.0\textheight,color=green]}
+% \placefigure[page,none]{}{\blackrule[width=\textwidth,height=1.1\textheight,color=green]}
+
+\def\sometextfloat[#1]% lang, links, rechts, hoog, midden, laag, offset
+ {%\checkwaitingfloats{#1}%
+ \gdef\dostoptextfloat{\dodostoptextfloat[#1]}% brr global
+ \global\floattextwidth\hsize
+ \global\floatwidth\wd\floatbox
+ \global\floatheight\ht\floatbox % forget about the depth
+ \global\advance\floattextwidth -\floatwidth
+ \global\advance\floattextwidth -\floatsharedparameter\c!margin\relax % was \tfskipsize
+ \doifinsetelse\v!tall{#1}
+ {\floattextheight\pagegoal
+ \advance\floattextheight -\pagetotal
+ \advance\floattextheight -\bigskipamount % lelijk
+ \ifdim\floattextheight>\textheight
+ \floattextheight\textheight
+ \fi
+ \boxmaxdepth\zeropoint \relax % toegevoegd
+ \ifdim\floattextheight<\floatheight
+ \floattextheight\floatheight
+ \fi
+ \setbox\floattext\vbox to \floattextheight}
+ {\setbox\floattext\vbox}%
+ \bgroup
+ \forgetall \setupblank \setupwhitespace % new, also needed for footnotes
+ \blank[\v!disable]
+ \hsize\floattextwidth
+ \ignorespaces}
+
+\def\dodostoptextfloat[#1]% % de tekst kan beter in een soort
+ {\egroup % kadertekst zonder kader, is flexibeler
+ \doifnotinset\v!tall{#1}% en beter
+ {\ifdim\ht\floattext<\floatheight
+ \floattextheight\floatheight
+ \else
+ \floattextheight\ht\floattext
+ \fi}%
+ \setbox\floatbox\vbox to \floattextheight
+ {\hsize\floatwidth
+ \doifinsetelse\v!both{#1}%
+ {\doifinsetelse\v!low{#1}
+ {\vfill\box\floatbox}
+ {\doifinsetelse\v!middle{#1}
+ {\vfill\box\floatbox\vfill}
+ {\box\floatbox\vfill}}}
+ {\box\floatbox\vfill}}%
+ \setbox\floattext\vbox to \floattextheight
+ {\hsize\floattextwidth
+ \doifinsetelse\v!low{#1}
+ {\vfill
+ \box\floattext
+ \doifinset\c!offset{#1}{\whitespace\blank}}
+ {\doifinsetelse\v!middle{#1}
+ {\vfill
+ \box\floattext
+ \vfill}
+ {\doifinset\v!offset{#1}{\whitespace\blank}%
+ \box\floattext
+ \vfill}}}%
+ \doifinsetelse\v!right{#1}% \floatmethod
+ {\setbox\floatbox\hbox to \hsize
+ {\box\floattext
+ \hfill
+ \box\floatbox}}
+ {\setbox\floatbox\hbox to \hsize
+ {\box\floatbox
+ \hfill
+ \box\floattext}}%
+ \baselinecorrection
+ \whitespace
+ \blank[\floatsharedparameter\c!spacebefore]%
+ \doifnotinset\v!tall{#1}%
+ {\dp\floatbox\openstrutdepth}% dp\strutbox}% % toegevoegd
+ \box\floatbox
+ \blank[\floatsharedparameter\c!spaceafter]%
+ \endgroup % **
+ \doinsertfloatinfo}
+
+\def\somefacefloat[#1]% links, rechts, midden, hoog, midden, laag
+ {%\checkwaitingfloats{#1}%
+ \startopposite\box\floatbox\stopopposite
+ \doinsertfloatinfo}
+
+\def\someelsefloat[#1]%
+ {\doifinsetelse\v!here{#1}
+ {\doifinsetelse\v!always{#1}
+ {\page[\v!preference]%
+ \docheckiffloatfits
+ \ifroomforfloat
+ \placesomeherefloat[#1]%
+ \else
+ \showmessage\m!floatblocks9\empty
+ \doreversesavefloat
+ \fi}
+ {\ifsomefloatwaiting
+ \dosavefloat
+ \else
+ \page[\v!preference]%
+ \docheckiffloatfits
+ \ifroomforfloat
+ \placesomeherefloat[#1]%
+ \else
+ \dosavefloat
+ \fi
+ \fi}}
+ {\doifinsetelse\v!always{#1}
+ {\docheckiffloatfits
+ \ifroomforfloat
+ \sometopbottomfloat[#1]
+ \else
+ \showmessage\m!floatblocks9\empty
+ \doreversesavefloat
+ \fi}
+ {\docheckiffloatfits
+ \ifroomforfloat
+ \sometopbottomfloat[#1]
+ \else
+ \dosavefloat
+ \fi}}}
+
+\def\floatautofactor{.5}
+
+\def\sometopbottomfloat[#1]%
+ {\doifelse\floatmethod\v!auto
+ {\ifdim\pagetotal<\floatautofactor\pagegoal % when empty page, maxdimen
+ \placesometopsfloat[#1]%
+ \else
+ \placesomebotsfloat[#1]%
+ \fi}
+ {\doifelse\floatmethod\v!top
+ {\placesometopsfloat[#1]}
+ {\doifelse\floatmethod\v!bottom
+ {\placesomebotsfloat[#1]}
+ {\placesomeherefloat[#1]}}}}
+
+% De onderstaande macro wordt gebruikt bij de macros
+% voor het plaatsen van tabellen en figuren (klopt niet
+% meer).
+%
+% \dofloat {plaats} {label1} {label2}
+% \docompletefloat {nummer} {referentie} {plaats} {label} {inhoud}
+% \box\floatbox inhoud+referentie
+% \do???float#1 #1 = boxnummer
+
+\newdimen\floatsideskip \floatsideskip =12pt
+\newdimen\floattopskip \floattopskip =\floattopskip
+\newdimen\floatbottomskip \floatbottomskip=\floattopskip
+
+\newdimen\sidefloattopskip \sidefloattopskip =\floattopskip
+\newdimen\sidefloatbottomskip \sidefloatbottomskip=\floatbottomskip
+
+\newskip\sidefloatdownshift
+\newskip\sidefloatleftshift
+\newskip\sidefloatrightshift
+
+\def\sidefloattopoffset {\openstrutdepth} % {\strutdp}
+
+\newcount\noftopfloats \noftopfloats=2
+\newcount\nofbotfloats \nofbotfloats=0
+
+\def\docalculatefloatskip#1#2%
+ {\doifelsenothing{#2}
+ {\global#1\zeropoint}
+ {\doifelse{#2}\v!none
+ {\global#1\zeropoint}
+ {\setbox\scratchbox\vbox{\whitespace\normalexpanded{\noexpand\blank[#2]}}%
+ \global#1\ht\scratchbox}}}
+
+\def\calculatefloatskips
+ {{\docalculatefloatskip\floattopskip{\floatsharedparameter\c!spacebefore}%
+ \docalculatefloatskip\floatbottomskip{\floatsharedparameter\c!spaceafter}%
+ \docalculatefloatskip\sidefloattopskip{\floatsharedparameter\c!sidespacebefore}%
+ \docalculatefloatskip\sidefloatbottomskip{\floatsharedparameter\c!sidespaceafter}%
+ \gdef\sidefloattopoffset{\openstrutdepth}% was \def
+ \global\floatsideskip\floatsharedparameter\c!margin
+ \global\sidefloatleftshift\floatparameter\c!leftmargindistance
+ \global\sidefloatrightshift\floatparameter\c!rightmargindistance
+ \global\noftopfloats\floatsharedparameter\c!ntop\relax
+ \global\nofbotfloats\floatsharedparameter\c!nbottom\relax}}
+
+\def\borderedfloatbox
+ {\localframed
+ [\??fl\currentfloat]
+ [\c!location=\v!normal,\c!width=\wd\floatbox,\c!height=\htdp\floatbox]
+ {\box\floatbox}}
+
+\newbox\tempfloatbox
+
+% minwidth=fit,width=max : no overshoot, as wide as graphic
+
+\ifx\moveboxontogrid\undefined \let\movecaptionontogrid\gobblethreearguments \fi
+
+\def\locatefloatbox
+ {\chardef\alignstrutmode\zerocount
+ \shiftalignedline
+ {\floatparameter\c!leftmargin }{\floatparameter\c!rightmargin}%
+ {\floatparameter\c!innermargin}{\floatparameter\c!outermargin}%
+ \alignedline{\floatparameter\c!location}\v!middle}
+
+\def\locatecaptionbox
+ {\chardef\alignstrutmode\zerocount
+ \shiftalignedline
+ {\floatcaptionparameter\c!leftmargin }{\floatcaptionparameter\c!rightmargin}%
+ {\floatcaptionparameter\c!innermargin}{\floatcaptionparameter\c!outermargin}%
+ \alignedline{\floatparameter\c!location}\v!middle}
+
+\long\def\dosetpagfloat#1#2#3% \copy wegwerken
+ {\bgroup
+ \setlocalfloathsize
+ \ifnum\floatrotation>0
+ \swapdimens\hsize\vsize
+ \fi
+ \forgetall
+ \postponenotes
+ \dontcomplain
+ \setbox\tempfloatbox\vbox{\borderedfloatbox}%
+ \let\locatefloat \locatefloatbox
+ \let\locatecaption\locatecaptionbox
+ \docheckcaptioncontent{#2}{#3}%
+ \ifcase\floatparameter\c!method
+ \or % automatic
+ \ifnofloatcaption
+ \dopreparenocaption{#1}{#2}{#3}%
+ \edef\width{\the\wd\floatbox}%
+ \doglobal\addlocalbackgroundtobox\floatbox
+ \else
+ % todo: installable maken, variant/method=auto vs macro
+ \dopreparedocaption{#1}{#2}{#3}%
+ \settracedcaptionbox
+ \edef\width{\the\wd\tempfloatbox}%
+ \addlocalbackgroundtobox\tempfloatbox
+ \setbox\tempcaptionbox\hbox
+ {\dosetcaptionthings
+ \floatcaptionparameter\c!command{\box\tempcaptionbox}}%
+ \moveboxontogrid\tempcaptionbox{\floatcaptionparameter\c!grid}\lastcaptionht
+ \addlocalbackgroundtobox\tempcaptionbox
+ \buildfloatbox
+ \fi
+ \or % semi automatic
+ \or % manual
+ \fi
+ \ifnum\floatrotation>0
+ \global\setbox\floatbox\vbox
+ {\rotate[\c!rotation=\floatrotation]{\box\floatbox}}%
+ \edef\width{\the\wd\tempfloatbox}%
+ \else
+ \postcenterfloatbox\width
+ \fi
+ \egroup}
+
+\def\captionminwidth {15\bodyfontsize}
+\def\captionovershoot {2em}
+
+\def\dopreparenocaption#1#2#3%
+ {\global\setbox\floatbox\vbox % pas op als wd groter dan hsize
+ {\ifinsidecolumns\ifdim\wd\tempfloatbox>\hsize
+ \let\locatefloat\relax
+ \fi\fi
+ \locatefloat{\copy\tempfloatbox}}}
+
+\def\dopreparedocaption#1#2#3%
+ {\doifinsetelse{\floatcaptionparameter\c!location}{\v!top,\v!bottom}
+ {\doifinsetelse{\floatcaptionparameter\c!width}{\v!fit,\v!max}
+ {\doifelse{\floatcaptionparameter\c!minwidth}\v!fit
+ {\doifelse{\floatcaptionparameter\c!width}\v!max
+ {\dopreparestackcaptionmax{#1}{#2}{#3}}
+ {\ifdim\wd\tempcaptionbox>\wd\tempfloatbox % wider caption
+ \doifelse{\floatcaptionparameter\c!width}\v!fit
+ {\dopreparestackcaptionaut{#1}{#2}{#3}}
+ {\dopreparestackcaptionwid{#1}{#2}{#3}}%
+ \else
+ \dopreparestackcaptionmin{#1}{#2}{#3}%
+ \fi}}
+ {\dopreparestackcaptionfix{#1}{#2}{#3}}}%
+ {\dopreparesidewidthcaption{#1}{#2}{#3}}}% new, special effects (see icare)
+ {\doifinsetelse{\floatcaptionparameter\c!width}{\v!fit,\v!max}
+ {\dopreparesideautocaption{#1}{#2}{#3}}
+ {\dopreparesidewidthcaption{#1}{#2}{#3}}}}
+
+% \def\dosettempcaptionbox
+% {\dosetraggedvbox{\floatcaptionparameter\c!align}%
+% \setbox\tempcaptionbox\raggedbox}
+
+\def\dosettempcaptionbox
+ {\setbox\tempcaptionbox\vbox\bgroup
+ %expanded{\setupalign[\v!new,\v!reset,\floatcaptionparameter\c!align,\v!old]}% wrong! see icare
+ \normalexpanded{\noexpand\setupalign[\v!reset,\floatcaptionparameter\c!align]}% i need to check what reset does
+ \dosetcaptionthings
+ \let\next}
+
+\def\dopreparesideautocaption#1#2#3%
+ {\scratchdimen\dimexpr\hsize-\wd\tempfloatbox-\floatparameter\c!margin\relax % was \tfskipsize\relax
+ \ifdim\wd\tempcaptionbox>\scratchdimen
+ \ifdim\wd\tempcaptionbox<1.3\scratchdimen
+ \scratchdimen0.8\scratchdimen
+ \fi
+ \fi
+ \dosettempcaptionbox
+ {\hsize\scratchdimen
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparesidewidthcaption#1#2#3%
+ {\dosettempcaptionbox
+ {\hsize\floatcaptionparameter\c!width
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparestackcaptionfix#1#2#3%
+ {\dosettempcaptionbox
+ {\hsize\floatcaptionparameter\c!minwidth % special effects
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparestackcaptionmax#1#2#3%
+ {\dosettempcaptionbox
+ {\hsize\wd\tempfloatbox
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparestackcaptionwid#1#2#3%
+ {\dosettempcaptionbox
+ {\hsize\floatcaptionparameter\c!width
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparestackcaptionmin#1#2#3%
+ {\dosettempcaptionbox
+ {\hsize\wd\tempfloatbox
+ \doifnothing{\floatcaptionparameter\c!align}\raggedcenter % on purpose overloads align !
+ \putcompletecaption{#2}{#3}}}
+
+\def\dopreparestackcaptionaut#1#2#3%
+ {\doifsomething{\floatcaptionparameter\c!align}
+ {\doifnotinset{\v!middle}{\floatcaptionparameter\c!align}%
+ {\let\captionovershoot\!!zeropoint}}%
+ \edef\captionhsize{\the\wd\tempfloatbox}%
+ \ifdim\captionhsize>\hsize
+ % float is wider than \hsize
+ \dosettempcaptionbox
+ {\trialtypesettingtrue
+ \hsize\captionhsize
+ \notesenabledfalse
+ \putcompletecaption{#2}{#3}}%
+ \ifdim\ht\scratchbox>\lineheight % more lines
+ \dosettempcaptionbox
+ {\hsize\captionhsize
+ \advance\hsize -\captionovershoot\relax
+ \ifdim\hsize<\captionminwidth\relax
+ \hsize\captionhsize
+ \fi
+ \putcompletecaption{#2}{#3}}%
+ \else
+ \dosettempcaptionbox
+ {\hsize\captionhsize
+ \putcompletecaption{#2}{#3}}%
+ \fi
+ \else
+ % float is smaller of equal to \hsize
+ \ifdim\captionhsize<\captionminwidth\relax
+ \scratchdimen\captionminwidth % float smaller than min width
+ \edef\captionhsize{\the\scratchdimen}%
+ \fi
+ \setbox\scratchbox\vbox % test with overshoot
+ {\trialtypesettingtrue
+ \scratchdimen\captionhsize
+ \advance\scratchdimen \captionovershoot
+ \advance\scratchdimen 3em % an average word length
+ \ifdim\scratchdimen<\hsize \hsize\scratchdimen \fi
+ \notesenabledfalse
+ \putcompletecaption{#2}{#3}}%
+ \ifdim\ht\scratchbox>\lineheight
+ % at least an average word longer than a line
+ \dosettempcaptionbox
+ {\scratchdimen\captionhsize
+ \advance\scratchdimen \captionovershoot
+ \ifdim\scratchdimen<\hsize \hsize\scratchdimen \fi
+ \putcompletecaption{#2}{#3}}%
+ \else
+ % just over a line, don't use an overshoot % % % todo: outer/inner and such
+ \doifcommonelse{\floatcaptionparameter\c!align}{\v!left,\v!right,\v!flushleft,\v!flushright}
+ {\dosettempcaptionbox
+ {\hsize\captionhsize
+ % strange : \raggedcenter
+ \putcompletecaption{#2}{#3}}}
+ {% nicer
+ \dosettempcaptionbox
+ {\hsize\captionhsize
+ \doifnothing{\floatcaptionparameter\c!align}\raggedcenter% overloads
+ \putcompletecaption{#2}{#3}}}%
+ \fi
+ \fi}
+
+\def\dopreparesidecaption#1#2#3%
+ {\scratchdimen\dimexpr\hsize-\wd\tempfloatbox-\floatparameter\c!margin\relax % was \tfskipsize\relax
+ \ifdim\wd\tempcaptionbox>\scratchdimen
+ \ifdim\wd\tempcaptionbox<1.3\scratchdimen
+ \scratchdimen0.8\scratchdimen
+ \fi
+ \fi
+ \dosettempcaptionbox % \setbox\tempcaptionbox\vbox
+ {\hsize\scratchdimen
+ \doifnothing{\floatcaptionparameter\c!align}\raggedright % on purpose overloads align !
+ \putcompletecaption{#2}{#3}}}
+
+\newdimen\tempfloatheight
+\newdimen\tempfloatwidth
+
+\def\dofloatboxbetweenstack
+ {\endgraf\nointerlineskip\floatcaptionparameter\c!inbetween\endgraf}
+
+\def\dofloatboxdefaultbuilder % done
+ {\locatefloat{\box\tempfloatbox}}
+
+\def\dofloatboxnextrightbuilder#1%
+ {\ifparfloat \hbox \else \expandafter \locatefloat \fi
+ {\tempfloatheight\ht\tempfloatbox
+ \box\tempfloatbox
+ \normalexpanded{\noexpand\doifnotinset{\v!hang}{\floatcaptionparameter\c!location}}{\dotfskip{\floatcaptionparameter\c!distance}}%
+ \vbox to\tempfloatheight{#1}}}
+
+\def\dofloatboxnextleftbuilder#1%
+ {\ifparfloat \hbox \else \expandafter \locatefloat \fi
+ {\tempfloatheight\ht\tempfloatbox
+ \vbox to\tempfloatheight{#1}%
+ \normalexpanded{\noexpand\doifnotinset{\v!hang}{\floatcaptionparameter\c!location}}{\dotfskip{\floatcaptionparameter\c!distance}}%
+ \box\tempfloatbox}}
+
+\def\dofloatboxnextouterbuilder
+ {\doifrightpagefloatelse\dofloatboxnextrightbuilder\dofloatboxnextleftbuilder}
+\def\dofloatboxnextinnerbuilder
+ {\doifrightpagefloatelse\dofloatboxnextleftbuilder\dofloatboxnextrightbuilder}
+
+\def\dofloatboxnextrighthangbuilder#1%
+ {\ifparfloat \hbox \else \expandafter \locatefloat \fi
+ {\tempfloatheight\ht\tempfloatbox
+ \box\tempfloatbox
+ \vbox to\tempfloatheight{#1}}}
+
+\def\dofloatboxnextlefthangbuilder#1%
+ {\ifparfloat \hbox \else \expandafter \locatefloat \fi
+ {\tempfloatheight\ht\tempfloatbox
+ \vbox to\tempfloatheight{#1}%
+ \box\tempfloatbox}}
+
+\def\dodofloatboxnextrightmarginbuilder#1#2%
+ {\ifparfloat
+ \hbox\bgroup
+ \tempfloatheight\ht\tempfloatbox
+ \box\tempfloatbox
+ \hsmash{\hskip#1\vbox to\tempfloatheight{#2}}%
+ \egroup
+ \else
+ \begingroup
+ \tempfloatheight\ht\tempfloatbox
+ \everyrightofalignedline{\hsmash{\hskip#1\vbox to\tempfloatheight{#2}}}%
+ \locatefloat{\box\tempfloatbox}%
+ \endgroup
+ \fi}
+
+\def\dodofloatboxnextleftmarginbuilder#1#2%
+ {\ifparfloat
+ \hbox\bgroup
+ \tempfloatheight\ht\tempfloatbox
+ \hsmash{\hskip-\dimexpr#1+\wd\tempcaptionbox\relax\vbox to\tempfloatheight{#2}}%
+ \box\tempfloatbox
+ \egroup
+ \else
+ \begingroup
+ \tempfloatheight\ht\tempfloatbox
+ \everyleftofalignedline{\hsmash{\hskip-\dimexpr#1+\wd\tempcaptionbox\relax\vbox to\tempfloatheight{#2}}}%
+ \locatefloat{\box\tempfloatbox}%
+ \endgroup
+ \fi}
+
+\def\dofloatboxnextrightmarginbuilder{\dodofloatboxnextrightmarginbuilder\rightmargindistance}
+\def\dofloatboxnextleftmarginbuilder {\dodofloatboxnextleftmarginbuilder \leftmargindistance }
+
+\def\dofloatboxnextoutermarginbuilder
+ {\doifrightpagefloatelse
+ {\dodofloatboxnextrightmarginbuilder\rightmargindistance}
+ {\dodofloatboxnextleftmarginbuilder \rightmargindistance}}
+
+\def\dofloatboxnextinnermarginbuilder
+ {\doifrightpagefloatelse
+ {\dodofloatboxnextleftmarginbuilder \leftmargindistance}
+ {\dodofloatboxnextrightmarginbuilder\leftmargindistance}}
+
+\def\dofloatboxnextbuilder % beware, we first check on left/rightmargin because there can be left/right also
+ {\let\next\dofloatboxnextleftbuilder
+ \normalexpanded{\noexpand\processallactionsinset[\floatcaptionparameter\c!location]}
+ [ \v!outermargin=>\let\next\dofloatboxnextoutermarginbuilder,
+ \v!innermargin=>\let\next\dofloatboxnextinnermarginbuilder,
+ \v!leftmargin=>\let\next\dofloatboxnextleftmarginbuilder,
+ \v!rightmargin=>\let\next\dofloatboxnextrightmarginbuilder,
+ \v!lefthanging=>\let\next\dofloatboxnextlefthangbuilder,
+ \v!righthanging=>\let\next\dofloatboxnextrighthangbuilder,
+ \v!outer=>\let\next\dofloatboxnextouterbuilder,
+ \v!inner=>\let\next\dofloatboxnextinnerbuilder,
+ \v!left=>\let\next\dofloatboxnextleftbuilder,
+ \v!right=>\let\next\dofloatboxnextrightbuilder]%
+ \next}
+
+\def\dofloatboxsidebuilder
+ {\ifparfloat
+ \let\next\dofloatboxhighbuilder
+ \else
+ \let\next\dofloatboxmiddlebuilder
+ \expanded{\processallactionsinset[\floatcaptionparameter\c!location]}
+ [ \v!low=>\let\next\dofloatboxlowbuilder,
+ \v!middle=>\let\next\dofloatboxmiddlebuilder,
+ \v!high=>\let\next\dofloatboxhighbuilder]%
+ \fi
+ \next}
+
+\def\doflushfloatleftcaptionhang
+ {\hsmash{\llap{\box\tempcaptionbox\dotfskip{\floatcaptionparameter\c!distance}}}}
+\def\doflushfloatrightcaptionhang
+ {\hsmash{\rlap{\dotfskip{\floatcaptionparameter\c!distance}\box\tempcaptionbox}}}
+
+\def\doflushfloatcaptionhang
+ {\expanded{\doifinsetelse{\v!righthanging}{\floatcaptionparameter\c!location}}
+ {\doflushfloatrightcaptionhang}
+ {\expanded{\doifinsetelse{\v!lefthanging}{\floatcaptionparameter\c!location}}
+ {\doflushfloatleftcaptionhang}
+ {\expanded{\doifinsetelse{\v!hang}{\floatcaptionparameter\c!location}}
+ {\expanded{\doifinsetelse{\v!outer}{\floatcaptionparameter\c!location}}
+ {\doifrightpagefloatelse{\doflushfloatrightcaptionhang}{\doflushfloatleftcaptionhang}}
+ {\expanded{\doifinsetelse{\v!right}{\floatcaptiondirectives}}
+ {\doflushfloatrightcaptionhang}
+ {\doflushfloatleftcaptionhang}}}
+ {\box\tempcaptionbox}}}}
+
+\def\dofloatboxhighbuilder
+ {\dofloatboxnextbuilder{\dofloatboxbetweenstack\doflushfloatcaptionhang\vfill}}
+
+\def\dofloatboxlowbuilder
+ {\dofloatboxnextbuilder{\vfill\doflushfloatcaptionhang\dofloatboxbetweenstack}}
+
+\def\dofloatboxmiddlebuilder
+ {\dofloatboxnextbuilder{\vfill\box\tempcaptionbox\vfill}}
+
+% \definefloat
+% [lefty][lefties][figure]
+% \setupfloat
+% [lefty]
+% [default=left,
+% rightmargindistance=-2cm,
+% leftmargindistance=-2cm]
+% \setupcaption
+% [lefty]
+% [location={bottom,overlay}]
+%
+% \starttext
+% \placelefty{}{} \input tufte \input tufte
+% \placelefty{}{} \input tufte \input tufte
+% \stoptext
+
+\def\bothangfloat#1{\ruledvbox to \ht\tempfloatbox{#1\vss}}
+\def\tophangfloat#1{\ruledvbox to \ht\tempfloatbox{\vss#1}}
+
+\def\dofloatboxnormaltopstackbuilder
+ {\expanded{\doifinset{\v!overlay}{\floatcaptionparameter\c!location}}\tophangfloat
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \hbox{\locatesidefloat{\box\tempcaptionbox}}%
+ \dofloatboxbetweenstack
+ \hbox{\hbox {\box\tempfloatbox }}%
+ \else
+ \hbox{\locatetextfloat{\box\tempcaptionbox}}
+ \dofloatboxbetweenstack
+ \hbox{\locatefloat {\box\tempfloatbox }}%
+ \fi}}
+
+\def\dofloatboxnormalbotstackbuilder
+ {\expanded{\doifinset{\v!overlay}{\floatcaptionparameter\c!location}}\bothangfloat
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \hbox{\hbox {\box\tempfloatbox }}%
+ \dofloatboxbetweenstack
+ \hbox{\locatesidefloat{\box\tempcaptionbox}}%
+ \else
+ \hbox{\locatefloat {\box\tempfloatbox }}%
+ \dofloatboxbetweenstack
+ \hbox{\locatetextfloat{\box\tempcaptionbox}}%
+ \fi}}
+
+\def\dofloatboxgridtopstackbuilder
+ {\dp\tempcaptionbox\strutdepth
+ \setbox\scratchbox\vbox
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \locatesidefloat{\box\tempcaptionbox}%
+ \vss\dofloatboxbetweenstack
+ \hbox {\box\tempfloatbox }%
+ \else
+ \locatetextfloat{\box\tempcaptionbox}%
+ \vss\dofloatboxbetweenstack
+ \locatefloat {\box\tempfloatbox }%
+ \fi}%
+ \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
+ \vbox to \noflines\lineheight{\unvbox\scratchbox}}
+
+\def\dofloatboxgridbotstackbuilder
+ {\dp\tempcaptionbox\strutdepth
+ \setbox\scratchbox\vbox
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \hbox {\box\tempfloatbox }%
+ \vss\dofloatboxbetweenstack
+ \locatesidefloat{\box\tempcaptionbox}%
+ \else
+ \locatefloat {\box\tempfloatbox }%
+ \vss\dofloatboxbetweenstack
+ \locatetextfloat{\box\tempcaptionbox}%
+ \fi}%
+ \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
+ \vbox to \noflines\lineheight{\unvbox\scratchbox}}
+
+\def\dofloatboxstretchtopstackbuilder
+ {\dp\tempcaptionbox\strutdepth
+ \setbox\scratchbox\vbox
+ {\locatecaption{\copy\tempcaptionbox}%
+ \locatefloat {\copy\tempfloatbox }}%
+ \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
+ \vbox to \noflines\lineheight
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \locatesidefloat{\box\tempcaptionbox}%
+ \vss\dofloatboxbetweenstack\vss
+ \hbox {\box\tempfloatbox }%
+ \else
+ \locatetextfloat{\box\tempcaptionbox}%
+ \vss\dofloatboxbetweenstack\vss
+ \locatefloat {\box\tempfloatbox }%
+ \fi}}
+
+\def\dofloatboxstretchbotstackbuilder
+ {\dp\tempcaptionbox\strutdepth
+ \setbox\scratchbox\vbox
+ {\locatefloat {\copy\tempfloatbox }%
+ \locatecaption{\copy\tempcaptionbox}}%
+ \getnoflines{\dimexpr\htdp\scratchbox-10\scaledpoint\relax}% get rid of inaccuracy
+ \vbox to \noflines\lineheight
+ {\tempfloatwidth\wd\tempfloatbox
+ \ifparfloat
+ \hbox {\box\tempfloatbox }%
+ \vss\dofloatboxbetweenstack\vss
+ \locatesidefloat{\box\tempcaptionbox}
+ \else
+ \locatefloat {\box\tempfloatbox }%
+ \vss\dofloatboxbetweenstack\vss
+ \locatetextfloat{\box\tempcaptionbox}%
+ \fi}}
+
+\def\dofloatboxtopbuilder
+ {\let\next\dofloatboxnormaltopstackbuilder
+ \expanded{\processfirstactioninset[\floatcaptionparameter\c!location]}
+ [ \v!grid=>\let\next\dofloatboxgridstackbuilder,
+ \v!stretch=>\let\next\dofloatboxstretchstackbuilder]%
+ \next}
+
+\def\dofloatboxbottombuilder
+ {\let\next\dofloatboxnormalbotstackbuilder
+ \expanded{\processfirstactioninset[\floatcaptionparameter\c!location]}
+ [ \v!grid=>\let\next\dofloatboxgridstackbuilder,
+ \v!stretch=>\let\next\dofloatboxstretchstackbuilder]%
+ \next}
+
+\def\relocatecaptionright#1{\locatecaption{\hbox to \tempfloatwidth{\hss#1}}}
+\def\relocatecaptionleft #1{\locatecaption{\hbox to \tempfloatwidth{#1\hss}}}
+
+\long\def\installfloatboxbuilder#1#2{\setvalue{\??kj:#1}{#2}}
+
+\def\buildfloatbox
+ {\global\setbox\floatbox\vbox
+ {\setlocalfloathsize
+ \forgetall
+ \let\floatcaptionarrangement\s!default
+ \def\docommand##1%
+ {\doifdefined{\??kj:##1}{\def\floatcaptionarrangement{##1}\quitcommalist}}%
+ \processcommacommand[\floatcaptionparameter\c!location]\docommand
+ \executeifdefined{\??kj:\floatcaptionarrangement}{\getvalue{\??kj:\s!default}}}}
+
+\def\locatetextfloat
+ {\let\next\locatecaption
+ \expanded{\processallactionsinset[\floatcaptionparameter\c!location]}
+ [ \v!left=>\let\next\relocatecaptionleft,
+ \v!right=>\let\next\relocatecaptionright,
+ \v!inner=>\doifrightpagefloatelse{\let\next\relocatecaptionleft }{\let\next\relocatecaptionright},
+ \v!outer=>\doifrightpagefloatelse{\let\next\relocatecaptionright}{\let\next\relocatecaptionleft }]%
+ \next}
+
+\installfloatboxbuilder \v!none \dofloatboxdefaultbuilder
+\installfloatboxbuilder \s!default \dofloatboxdefaultbuilder
+\installfloatboxbuilder \v!high \dofloatboxhighbuilder
+\installfloatboxbuilder \v!low \dofloatboxlowbuilder
+\installfloatboxbuilder \v!middle \dofloatboxmiddlebuilder
+
+\installfloatboxbuilder \v!left \dofloatboxsidebuilder
+\installfloatboxbuilder \v!right \dofloatboxsidebuilder
+
+\installfloatboxbuilder \v!top \dofloatboxtopbuilder
+\installfloatboxbuilder \v!bottom \dofloatboxbottombuilder
+
+% \setuplayout[grid=yes] \showgrid \setupcaptions[style=smallbodyfont,location=grid,inbetween=]
+%
+% \starttext
+% test \placefigure{} {\externalfigure[cow.pdf][frame=on,grid=yes]} test \page
+% test \placefigure{\input zapf\relax}{\externalfigure[cow.pdf][frame=on,grid=yes]} test \page
+% test \placefigure{} {\externalfigure[cow.pdf][frame=on,grid=depth]} test \page
+% test \placefigure{\input zapf\relax}{\externalfigure[cow.pdf][frame=on,grid=depth]} test \page
+% \stoptext
+
+\newif\ifpostponecolumnfloats \postponecolumnfloatsfalse % don't change
+
+\chardef\postcenterfloatmethod\plusone
+
+\def\postcenterfloatbox#1%
+ {\scratchdimen
+ \ifcase\postcenterfloatmethod
+ #1% \wd\floatbox
+ \or\ifinsidecolumns
+ \ifpostponecolumnfloats\makeupwidth\else#1\fi
+ \else\ifdim#1>\hsize
+ \hsize
+ \else
+ \wd\floatbox
+ \fi\fi\fi
+ \global\setbox\floatbox\hbox to \scratchdimen
+ % {\hfill\box\floatbox\hfill}} % geen \hss, gaat mis in kolommen !
+ % {\hss \box\floatbox\hss }} % wel \hss, anders mis in colset
+ {\ifglobalcenterfloatbox
+ \donetrue
+ \else\iflocalcenterfloatbox
+ \donetrue
+ \else
+ \donefalse
+ \fi\fi
+ \ifdim\scratchdimen>\effectivehsize
+ \donefalse
+ \fi
+ \hss\ifdone\hskip\effectiveleftskip\fi
+ \box\floatbox
+ \ifdone\hskip\effectiverightskip\fi\hss}}
+
+\long\def\dosetparfloat#1#2#3%
+ {\bgroup
+ \forgetall
+ \postponenotes
+ \dontcomplain
+ %\showcomposition
+ \setbox\tempfloatbox\vbox{\borderedfloatbox}%
+ \addlocalbackgroundtobox\tempfloatbox % no \doglobal
+ \docheckcaptioncontent{#2}{#3}%
+ \ifnofloatcaption
+ \global\setbox\floatbox\vbox{\box\tempfloatbox}%
+ \else
+ \dopreparedosidecaption{#1}{#2}{#3}%
+ \settracedcaptionbox
+ \setbox\tempcaptionbox\hbox{\floatcaptionparameter\c!command{\box\tempcaptionbox}}%
+ \moveboxontogrid\tempcaptionbox{\floatcaptionparameter\c!grid}\lastcaptionht
+ \addlocalbackgroundtobox\tempcaptionbox % no \doglobal
+ \buildsidefloatbox
+ \fi
+ \egroup}
+
+\def\dopreparedosidecaption#1#2#3% will be enhanced
+ {\doifelse{\floatcaptionparameter\c!width}\v!max
+ {\dosettempcaptionbox
+ {\hsize\wd\tempfloatbox
+ \putcompletecaption{#2}{#3}}}%
+ {\doifelse{\floatcaptionparameter\c!width}\v!fit
+ {\ifdim\wd\tempcaptionbox>\wd\tempfloatbox\relax
+ \setbox\tempcaptionbox\vbox
+ {\forgetall % needed?
+ \hsize\wd\tempfloatbox
+ \dosetcaptionthings
+ \putcompletecaption{#2}{#3}}%
+ \else
+ \setbox\tempcaptionbox\hbox to \wd\tempfloatbox
+ {\hss\box\tempcaptionbox\hss}%
+ \fi}
+ {\dosettempcaptionbox
+ {\hsize\floatcaptionparameter\c!width % \wd\tempfloatbox
+ \putcompletecaption{#2}{#3}}}}}
+
+\def\buildsidefloatbox
+ {\let\locatefloat \relax
+ \let\locatecaption\relax
+ \def\locatesidefloat##1%
+ {\begingroup
+ \chardef\alignstrutmode\zerocount
+ \hsize\tempfloatwidth \forgetall
+ \alignedline{\floatparameter\c!location}\v!middle{##1}%
+ \endgroup}%
+ \buildfloatbox}
+
+\newif\ifparfloat
+
+\long\def\dosetfloatbox#1#2#3% todo : \global\setbox
+ {\ifvisible
+ \par
+ \edef\floatcaptiondirectives{\floatparameter\c!location,\floatcaptionparameter\c!location}%
+ \ifparfloat\@EA\dosetparfloat\else\@EA\dosetpagfloat\fi{#1}{#2}{#3}%
+ \setlocalfloatdimensions{#1}%
+ \setbox\floatbox\hbox
+ {\dosavefloatdata\restoretextcolor{\box\floatbox}}%
+ \global\floatheight\ht\floatbox
+ \global\advance\floatheight \dp\floatbox
+ \global\floatwidth\wd\floatbox
+ \global\advance\totalnoffloats \plusone
+ \doifnotinset\v!margin{#1} % gaat namelijk nog fout
+ {\setbox\floatbox\vbox
+ {\parindent\zeropoint
+ \doifconcepttracing{\inleftmargin{\framed{\infofont\the\totalnoffloats}}}%
+ \box\floatbox}}%
+ \wd\floatbox\floatwidth
+ \dimen0=\floatheight
+ \advance\dimen0 \lineheight
+ \ifdim\dimen0<\textheight
+ \else
+ \global\floatheight\textheight
+ \global\advance\floatheight -\lineheight
+ \ht\floatbox\floatheight
+ \dp\floatbox\zeropoint
+ \showmessage\m!floatblocks{10}{\the\totalnoffloats}%
+ \fi
+ \fi}
+
+\newcounter\noxfloatlocations
+
+\long\def\dofloat#1#2#3% #1 is optionlist
+ {\dosetfloatbox{#1}{#2}{#3}%
+ \dogetfloatbox{#1}\empty}
+
+\def\dooutput{\sidefloatoutput} % redefinition of \dooutput
+
+\definefloat
+ [\v!figure]
+ [\v!figures]
+
+\definefloat
+ [\v!table]
+ [\v!tables]
+
+\setupfloat
+ [\v!table]
+ [\c!frame=\v!off]
+
+\definefloat
+ [\v!intermezzo]
+ [\v!intermezzi]
+
+\definefloat
+ [\v!graphic]
+ [\v!graphics]
+
+% float strategy, replaces some of the above macros
+
+\let\floatmethod \empty
+\let\floatcolumn \empty
+\let\floatrow \empty
+\let\forcedfloatmethod\empty
+
+\def\dogetfloatbox#1#2%
+ {\ifvisible
+ \doifelsenothing{#2}
+ {\getfromcommalist[#1][1]%
+ \@EA\beforesplitstring\commalistelement\at:\to\floatmethod
+ \@EA\aftersplitstring \commalistelement\at:\to\floatcolumn
+ \@EA\aftersplitstring \floatcolumn\at*\to\floatrow
+ \@EA\beforesplitstring\floatcolumn\at*\to\floatcolumn
+ % todo: nog algemeen otr
+ \ifx\OTRSETsetpreferedcolumnslot\undefined\else
+ \OTRSETsetpreferedcolumnslot\floatcolumn\floatrow
+ \fi}
+ {\let\floatcolumn\empty
+ \let\floatrow\empty
+ \edef\floatmethod{#2}}%
+ \doifundefined{\string\floatmethod\floatmethod}
+ {\let\floatmethod\v!here}%
+ \doifsomething\forcedfloatmethod
+ {\edef\floatmethod{\forcedfloatmethod}}%
+ %\getvalue{\string\floatmethod\floatmethod}[#1]%
+ \getvalue{\string\floatmethod\floatmethod}[\floatmethod,#1]%
+ \fi}
+
+\def\installfloathandler#1#2% #1=keyword #2=handler
+ {\setvalue{\string\floatmethod#1}{#2}}
+
+\installfloathandler \v!here \someherefloat
+\installfloathandler \v!force \somefixdfloat
+\installfloathandler \v!left \someleftsidefloat
+\installfloathandler \v!right \somerightsidefloat
+\installfloathandler \v!text \sometextfloat
+\installfloathandler \v!top \sometopfloat
+\installfloathandler \v!bottom \somebottomfloat
+\installfloathandler \v!auto \someautofloat
+\installfloathandler \v!margin \somemarginfloat
+\installfloathandler \v!opposite \somefacefloat
+\installfloathandler \v!page \somepagefloat
+\installfloathandler \v!leftpage \someleftpagefloat
+\installfloathandler \v!rightpage \somerightpagefloat
+\installfloathandler \v!inmargin \someinmarginfloat
+\installfloathandler \v!inleft \someinleftmarginfloat
+\installfloathandler \v!inright \someinrightmarginfloat
+\installfloathandler \v!leftmargin \someinleftmarginfloat
+\installfloathandler \v!rightmargin \someinrightmarginfloat
+\installfloathandler \v!leftedge \someinleftedgefloat
+\installfloathandler \v!rightedge \someinrightedgefloat
+
+\installfloathandler \v!backspace \somebackspacefloat
+\installfloathandler \v!cutspace \somecutspacefloat
+
+\installfloathandler {tblr} \someslotfloat
+\installfloathandler {lrtb} \someslotfloat
+\installfloathandler {tbrl} \someslotfloat
+\installfloathandler {rltb} \someslotfloat
+\installfloathandler {btlr} \someslotfloat
+\installfloathandler {lrbt} \someslotfloat
+\installfloathandler {btrl} \someslotfloat
+\installfloathandler {rlbt} \someslotfloat
+\installfloathandler {fxtb} \someslotfloat
+\installfloathandler {fxbt} \someslotfloat
+
+\def\placesomeslotfloat {\OTRcommand\someslotfloat}
+\def\placesomeherefloat {\OTRcommand\someherefloat}
+\def\placesomefixdfloat {\OTRcommand\somefixdfloat}
+\def\placesomepagefloat {\OTRcommand\somepagefloat}
+\def\placesomeleftpagefloat {\OTRcommand\someleftpagefloat}
+\def\placesomerightpagefloat{\OTRcommand\somerightpagefloat}
+\def\placesometopsfloat {\OTRcommand\sometopsfloat}
+\def\placesomebotsfloat {\OTRcommand\somebotsfloat}
+\def\placesomesidefloat {\OTRcommand\somesidefloat}
+\def\placesomefacefloat {\OTRcommand\somefacefloat}
+
+\def\someleftsidefloat [#1]{\somesidefloat[#1]\presetindentation}
+\def\somerightsidefloat [#1]{\somesidefloat[#1]}
+\def\sometopfloat [#1]{\someelsefloat[#1]\nonoindentation}
+\def\somebottomfloat [#1]{\someelsefloat[#1]}
+\def\someautofloat [#1]{\someelsefloat[#1]}
+\def\somemarginfloat [#1]{\somenextfloat[#1]\nonoindentation}
+\def\someinleftmarginfloat [#1]{\somesidefloat[#1]}
+\def\someinrightmarginfloat[#1]{\somesidefloat[#1]}
+\def\someinleftedgefloat [#1]{\somesidefloat[#1]}
+\def\someinrightedgefloat [#1]{\somesidefloat[#1]}
+\def\someinmarginfloat [#1]{\somesidefloat[#1]}
+\def\someherefloat [#1]{\someelsefloat[\v!here,#1]}
+
+\def\somebackspacefloat [#1]{\somesidefloat[#1]}
+\def\somecutspacefloat [#1]{\somesidefloat[#1]}
+
+\def\somefixdfloat {\placesomefixdfloat}
+\def\somepagefloat {\placesomepagefloat}
+\def\someleftpagefloat {\placesomeleftpagefloat}
+\def\somerightpagefloat{\placesomerightpagefloat}
+\def\somefacefloat {\placesomefacefloat}
+\def\someslotfloat {\placesomeslotfloat}
+
+\protect \endinput
diff --git a/tex/context/base/strc-ini.lua b/tex/context/base/strc-ini.lua
new file mode 100644
index 000000000..552435e81
--- /dev/null
+++ b/tex/context/base/strc-ini.lua
@@ -0,0 +1,276 @@
+if not modules then modules = { } end modules ['strc-ini'] = {
+ version = 1.001,
+ comment = "companion to strc-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[
+
+The restructuring is the (intermediate) result of quite some experiments. I started
+with the basic structure, followed by lists, numbers, enumerations, itemgroups
+and floats. All these have something in common, like pagenumbers and section
+prefixes. I played with some generic datastructure (in order to save space) but
+the code at both the lua and tex end then quickly becomes messy due to the fact
+that access to variables is too different. So, eventually I ended up with
+dedicated structures combined with sharing data. In lua this is quite efficient
+because tables are referenced. However, some precautions are to be taken in
+order to keep the utility file small. Utility data and process data share much
+but it does not make sense to store all processdata.
+
+]]--
+
+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 = tex.ctxcatcodes
+
+-- move this
+
+commands = commands or { }
+
+function commands.first_in_list(str)
+ local first = match(str,"^([^,]+),")
+ texsprint(ctxcatcodes,first or str)
+end
+
+-- -- -- namespace -- -- --
+
+structure = structure or { }
+
+-- -- -- cache -- -- --
+
+structure.shares = structure.shares or { }
+structure.shares.cache = structure.shares.cache or { }
+
+local shares = structure.shares
+local cache = shares.cache
+
+function shares.put(data)
+ cache[#cache+1] = data
+ return #cache
+end
+
+function shares.get(n) -- n can be string
+ n = tonumber(n) or -1
+ return cache[n]
+end
+
+-- -- -- specials -- -- --
+
+-- we can store information and get back a reference; this permits
+-- us to store rather raw data in references
+
+local specials = { } structure.specials = specials
+
+specials.collected = specials.collected or { }
+specials.tobesaved = specials.collected or { }
+
+local collected, tobesaved = specials.collected, specials.tobesaved
+
+local function initializer()
+ collected, tobesaved = specials.collected, specials.tobesaved
+end
+
+if job then
+ job.register('structure.specials.collected', structure.specials.tobesaved, initializer)
+end
+
+function specials.store(class,data)
+ if class and data then
+ local s = tobesaved[class]
+ if not s then
+ s = { }
+ tobesaved[class] = s
+ end
+ s[#s+1] = data
+ texwrite(#s)
+ else
+ texwrite(0)
+ end
+end
+
+function specials.retrieve(class,n)
+ if class and n then
+ local c = collected[class]
+ return c and c[n]
+ end
+end
+
+-- -- -- helpers -- -- --
+
+structure.helpers = structure.helpers or { }
+
+local helpers = structure.helpers
+
+function helpers.touserdata(str)
+ local hash = str and str ~= "" and aux.settings_to_hash(str)
+ if hash and next(hash) then
+ return hash
+ end
+end
+
+local function simplify(d,nodefault)
+ if d then
+ local t = { }
+ for k, v in next, d do
+ local tv = type(v)
+ if tv == "table" then
+ if next(v) then t[k] = simplify(v) end
+ elseif tv == "string" then
+ if v ~= "" and v ~= "default" then t[k] = v end
+ elseif tv == "boolean" then
+ if v then t[k] = v end
+ else
+ t[k] = v
+ end
+ end
+--~ print(table.serialize(d,"before"))
+--~ print(table.serialize(t,"after"))
+ return next(t) and t
+ elseif nodefault then
+ return nil
+ else
+ return { }
+ end
+end
+
+helpers.simplify = simplify
+
+function helpers.merged(...)
+ local h, t = { ... }, { }
+ for k=1, #h do
+ local v = h[k]
+ if v and v ~= "" and not t[k] then
+ t[k] = v
+ end
+ end
+ return t
+end
+
+local tag = "ctx:tocentry"
+
+function helpers.title(title,metadata)
+ if title and title ~= "" then
+ if metadata then
+ if metadata.coding == "xml" then
+ buffers.set(tag,format("<?xml version='1.0'?><%s>%s</%s>",tag,title,tag))
+ texsprint(ctxcatcodes,format("\\xmlprocessbuffer{%s}{%s}{}",metadata.xmlroot or "main",tag))
+ else
+ texsprint(metadata.catcodes,title)
+ end
+ else
+ texsprint(title) -- no catcode switch
+ end
+ end
+end
+
+-- -- -- processors -- -- -- syntax: processor->data
+
+local processors = { } structure.processors = processors
+
+local registered = { }
+
+function processors.register(p)
+ registered[p] = true
+end
+
+function processors.reset(p)
+ registered[p] = nil
+end
+
+local splitter = lpeg.splitat("->",true)
+
+function processors.split(str)
+ local p, s = splitter:match(str)
+ if registered[p] then
+ return p, s
+ else
+ return false, str
+ end
+end
+
+function processors.sprint(catcodes,str,fnc,...)
+ local p, s = splitter:match(str)
+ if registered[p] then
+ texsprint(catcodes,format("\\applyprocessor{%s}{%s}",p,(fnc and fnc(s,...)) or s))
+ else
+ texsprint(catcodes,(fnc and fnc(str,...)) or str)
+ end
+end
+
+function processors.apply(str)
+ local p, s = splitter:match(str)
+ if registered[p] then
+ return format("\\applyprocessor{%s}{%s}",p,s)
+ else
+ return str
+ end
+end
+
+-- -- -- sets -- -- --
+
+structure.sets = structure.sets or { }
+structure.sets.setlist = structure.sets.setlist or { }
+
+storage.register("structure/sets/setlist", structure.sets.setlist, "structure.sets.setlist")
+
+local sets = structure.sets
+local setlist = sets.setlist
+
+function sets.define(namespace,name,values,default,numbers)
+ local dn = setlist[namespace]
+ if not dn then
+ dn = { }
+ setlist[namespace] = dn
+ end
+ if values == "" then
+ dn[name] = { { }, default }
+ else
+ local split = aux.settings_to_array(values)
+ if numbers then
+ -- convert to numbers (e.g. for reset)
+ for i=1,#split do
+ split[i] = tonumber(split[i]) or 0
+ end
+ end
+ dn[name] = { split, default }
+ end
+end
+
+function sets.getall(namespace,block,name)
+ local ds = setlist[namespace]
+ if not ds then
+ return { }
+ else
+ local dn
+ if block and block ~= "" then
+ dn = ds[block..":"..name] or ds[name] or ds[block] or ds.default
+ else
+ dn = ds[name] or ds.default
+ end
+ return (dn and dn[1]) or { }
+ end
+end
+
+function sets.get(namespace,block,name,level,default)
+ local ds = setlist[namespace]
+ if not ds then
+ return default
+ end
+ local dn
+ if name and name ~= "" then
+ if block and block ~= "" then
+ dn = ds[block..":"..name] or ds[name] or ds[block] or ds.default
+ else
+ dn = ds[name] or ds.default
+ end
+ end
+ if not dn then
+ return default
+ end
+ local dl = dn[1][level]
+ return dl or dn[2] or default
+end
diff --git a/tex/context/base/strc-ini.tex b/tex/context/base/strc-ini.tex
new file mode 100644
index 000000000..619442998
--- /dev/null
+++ b/tex/context/base/strc-ini.tex
@@ -0,0 +1,88 @@
+%D \module
+%D [ file=strc-flt,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Initialization \& Helpers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Initialization & Helpers}
+
+\registerctxluafile{strc-ini}{1.001}
+
+\unprotect
+
+% \def\zerosection{0}
+% \def\resetsectionmarks{}
+% \setuppagenumbering
+
+% maybe use structurecomponent more consistently as name below
+
+% segments: 0:100 2:3 chapter:subsection 3 (=self+2) (alternative: sectionset)
+
+% section : [sectionnumber(s)]
+% sectionseparatorset (default) sectionconversionset (default) sectionstopper () sectionset sectionsegments
+
+% lists : [sectionnumber(s)] [text] [prefix(es)[separator]][pagenumber(s)]
+% sectionseparatorset (default) sectionconversionset (default) sectionstopper sectionset sectionsegments
+% prefixseparatorset (default) prefixconversionset (default) prefixstopper (.) prefixset prefixsegments
+% pageseparatorset (default) pageconversionset (default) pagestopper () pagesegments
+% prefix (no)
+
+% counter : [prefix(es)[separator]][number(s)]
+% prefixseparatorset (default) prefixconversionset (default) prefixstopper (.) prefixset prefixsegments
+% numberseparatorset (default) numberconversionset (default) numberstopper () numbersegments
+% prefix (no)
+
+% pagenumber: [prefix(es)[separator]][pagenumber(s)]
+% prefixseparatorset (default) prefixconversionset (default) prefixstopper (.) prefixset prefixsegments
+% pageseparatorset (default) pageconversionset (default) pagestopper ()
+% prefix (no)
+
+% text mark reference list
+% section P P P P
+% float P.N P.N P.N
+% itemize P.N P.N
+% enumerate P.N P.N P.N
+% formula P.N P.N
+% footnote P.N P.N P.N
+% number P.N P.N
+
+% number prefix section page
+
+% [text|marking|reference|list]:[number|prefix|pagenumber|pageprefix]:[separatorset|conversionset|conversion|stopper|set|segments|resetset|order]
+
+% figure caption : text:number:* text:prefix:* -> \setupcaption[figure][...]; stores defaults
+% figure list : list:number:* list:prefix:* list:pagenumber:* list:pageprefix:* -> \setuplist[figure][...]; takes stored defaults for number and pagenumber]
+% figure reference: reference:number:* reference:prefix:* reference:pagenumber:* reference:pageprefix:* -> \setupreference[figure]]...]; takes stored defaults
+
+% This module deals with structure: section headers, list and
+% numbering and eventually cross referencing. These components are
+% rather interwoven and therefore an inbetween layer is used.
+% Eventually this will replace the corresponding code in core-sec,
+% core-lst, core-num and core-ref.
+
+% We collect operations that deal with things like formatting on each
+% level of a number in sets. This is all handles at the \LUA\ end.
+% References to such sets travel with the multipass information.
+
+\def\definestructureresetset {\dotripleempty\dodefinestructureresetset}
+\def\definestructureseparatorset {\dotripleempty\dodefinestructureseparatorset}
+\def\definestructureconversionset{\dotripleempty\dodefinestructureconversionset}
+\def\definestructureprefixset {\dotripleempty\dodefinestructureprefixset}
+
+\def\dodefinestructureresetset [#1][#2][#3]{\ctxlua{structure.sets.define("structure:resets", "#1","\luaescapestring{\detokenize{#2}}","\luaescapestring{\detokenize{#3}}",true)}}
+\def\dodefinestructureseparatorset [#1][#2][#3]{\ctxlua{structure.sets.define("structure:separators", "#1","\luaescapestring{\detokenize{#2}}","\luaescapestring{\detokenize{#3}}")}}
+\def\dodefinestructureconversionset[#1][#2][#3]{\ctxlua{structure.sets.define("structure:conversions","#1","\luaescapestring{\detokenize{#2}}","\luaescapestring{\detokenize{#3}}")}}
+\def\dodefinestructureprefixset [#1][#2][#3]{\ctxlua{structure.sets.define("structure:prefixes", "#1","\luaescapestring{\detokenize{#2}}","\luaescapestring{\detokenize{#3}}")}}
+
+% \definestructureseparatorset [weird][!,?,*][:] % tex content
+% \definestructureconversionset[weird][numbers,characters,romannumerals][numbers] % symbolic names
+% \definestructureresetset [weird][0,0,1][0] % numbers
+
+\protect \endinput
diff --git a/tex/context/base/strc-itm.lua b/tex/context/base/strc-itm.lua
new file mode 100644
index 000000000..fc609b448
--- /dev/null
+++ b/tex/context/base/strc-itm.lua
@@ -0,0 +1,24 @@
+if not modules then modules = { } end modules ['strc-itm'] = {
+ version = 1.001,
+ comment = "companion to strc-itm.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+structure = structure or { }
+structure.itemgroups = structure.itemgroups or { }
+
+local itemgroups = structure.itemgroups
+
+function itemgroups.register(name,nofitems,maxwidth)
+ jobpasses.savedata("itemgroup", { nofitems, maxwidth })
+end
+
+function itemgroups.nofitems(name,index)
+ jobpasses.getfield("itemgroup", index, 1, 0)
+end
+
+function itemgroups.maxwidth(name,index)
+ jobpasses.getfield("itemgroup", index, 2, 0)
+end
diff --git a/tex/context/base/strc-itm.tex b/tex/context/base/strc-itm.tex
new file mode 100644
index 000000000..dd639d72b
--- /dev/null
+++ b/tex/context/base/strc-itm.tex
@@ -0,0 +1,1195 @@
+%D \module
+%D [ file=strc-itm,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Itemgroups,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Itemgroups}
+
+\registerctxluafile{strc-itm}{1.001}
+
+\unprotect
+
+\newconditional\sublistitem \setfalse\sublistitem
+\newconditional\symbollistitem \setfalse\symbollistitem
+\newconditional\headlistitem \setfalse\headlistitem
+\newconditional\introlistitem \setfalse\introlistitem
+\newconditional\randomizeitems \setfalse\randomizeitems
+\newconditional\autointrolistitem \setfalse\autointrolistitem
+\newconditional\optimizelistitem \settrue \optimizelistitem
+\newconditional\packlistitem \setfalse\packlistitem
+\newconditional\paragraphlistitem \setfalse\paragraphlistitem
+\newconditional\textlistitem \setfalse\textlistitem
+\newconditional\firstlistitem \setfalse\firstlistitem
+\newconditional\beforelistitem \setfalse\beforelistitem
+\newconditional\afterlistitem \setfalse\afterlistitem
+\newconditional\nowhitelistitem \setfalse\nowhitelistitem
+\newconditional\joinedlistitem \setfalse\joinedwhitelistitem
+\newconditional\reverselistitem \setfalse\reverselistitem
+\newconditional\continuelistitems \setfalse\continuelistitems
+\newconditional\fittinglistitems \setfalse\fittinglistitems
+
+\newcount\noflists
+\newcount\currentnoflists
+\newcount\noflistelements
+\newcount\itemcolumndepth
+\newcount\itemdepth
+\newcount\maxitemdepth \maxitemdepth=6
+
+\newdimen\itemgrouplistwidth
+\newdimen\itemgroupaskedwidth
+\newbox \itemgroupitembox
+
+\def\currentitemgroupcounter{itemgroup:\currentitemgroup}
+
+\let\currentitemlevel \!!zerocount
+\let\currentitemgroup \empty
+\let\currentnofitems \!!zerocount
+\def\currentitemnumber {\dorawsubstructurecounter[\currentitemgroupcounter][\currentitemlevel]}
+\let\currentrepeatstart \empty
+
+\def\dolistreference
+ {\iftrialtypesetting \else % no need for different treatment of \continuelistitems
+ \ctxlua{structure.itemgroups.register("\currentitemgroup",\number\noflistelements,"\getitemparameter\currentitemlevel\c!maxwidth")}%
+ \fi}
+
+\def\checkcurrentnofitems % we could do this at the lua end and save a call
+ {\edef\currentnofitems {\ctxlua{structure.itemgroups.nofitems("\currentitemgroup",\number\currentnoflists)}}%
+ \edef\currentitemmaxwidth{\ctxlua{structure.itemgroups.maxwidth("\currentitemgroup",\number\currentnoflists)}\scaledpoint}}
+
+\def\dohandleitemreference % we will make a decent number helper
+ {\ifx\currentitemreference \empty \else
+ \setnextinternalreference
+ \ctxlua {
+ jobreferences.set("\s!full", "\referenceprefix","\currentitemreference",
+ {
+ metadata = {
+ kind = "list",
+ catcodes = \the\catcodetable,
+ xmlroot = \ifx\currentreferencecoding\s!xml "\xmldocument" \else nil \fi, % only useful when text
+ },
+ references = {
+ internal = \nextinternalreference,
+ section = structure.sections.currentid(),
+ },
+ numberdata = structure.helpers.simplify {
+ numbers = structure.counters.compact("\currentitemgroupcounter",nil,true),
+ separatorset = "\structurecounterparameter\currentitemgroupcounter\c!numberseparatorset",
+ conversion = "\structurecounterparameter\currentitemgroupcounter\c!numberconversion",
+ conversionset = "\structurecounterparameter\currentitemgroupcounter\c!numberconversionset",
+ % for the moment no stopper, we need to make references configurable first
+ % stopper = \!!bs\structurecounterparameter\currentitemgroupcounter\c!numberstopper\!!es,
+ segments = "\structurecounterparameter\currentitemgroupcounter\c!numbersegments",
+ },
+ })
+ jobreferences.setinternalreference("\referenceprefix","\currentitemreference",\nextinternalreference)
+ }%
+ \fi}
+
+% \startitemize[n,packed]
+% \item test \item test \item test
+% \stopitemize
+%
+% \startitemize[n,packed,reverse]
+% \item test \item test \item test
+% \stopitemize
+%
+% \startitemize[n,packed,reverse] \item test \item test \stopitemize
+% \startitemize[continue]
+% \item test \startitemize[n,packed] \item test \item test \stopitemize
+% \item test
+% \item test
+% \stopitemize
+% \startitemize[continue] \item test \stopitemize
+%
+% \startitemize[n,packed] \item test \item test \stopitemize
+% \startitemize[continue] \item test \stopitemize
+% \startitemize[continue] \item test \stopitemize
+
+\def\itemparameter #1#2{\csname\doitemparameter{\??op\currentitemgroup#1}#2\endcsname}
+\def\itemparameterhash#1#2{\doitemparameterhash {\??op\currentitemgroup#1}#2}
+
+
+\def\doitemparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\doitemparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\doitemparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\doitemparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\doitemparentparameter #1#2{\ifx#1\relax\s!empty\else\doitemparameter #1#2\fi}
+\def\doitemparentparameterhash#1#2{\ifx#1\relax \else\doitemparameterhash#1#2\fi}
+
+\def\dosetitemattributes#1#2#3% style color
+ {\edef\fontattributehash {\itemparameterhash#1#2}%
+ \edef\colorattributehash{\itemparameterhash#1#3}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #2\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#3\fi}
+
+\def\setitemparameter #1#2{\@EA \def\csname\??op\currentitemgroup#1#2\endcsname} % #3 -> {#3}
+\def\esetitemparameter#1#2{\@EA\edef\csname\??op\currentitemgroup#1#2\endcsname} % #3 -> {#3}
+\def\xsetitemparameter#1#2{\@EA\xdef\csname\??op\currentitemgroup#1#2\endcsname} % #3 -> {#3}
+\def\letitemparameter #1#2{\@EA \let\csname\??op\currentitemgroup#1#2\endcsname}
+\let\getitemparameter \itemparameter
+
+\def\@@globalitemsymbol #1{\??op\currentitemgroup\c!symbol\s!global#1}
+\def\@@localitemsymbol #1{\??op\currentitemgroup\c!symbol\s!local #1}
+\def\@@currentitemsymbol#1{\??op\currentitemgroup\c!symbol #1}
+
+\def\@@itemcounter{\s!itemcount\currentitemgroup}
+
+\def\doitembreak#1{\ifconditional\optimizelistitem\ifconditional\textlistitem\else\dosomebreak#1\fi\fi}
+
+\def\allowitembreak {\doitembreak\allowbreak}
+\def\noitembreak {\doitembreak\nobreak}
+\def\itembreakspecial {\doitembreak\itembreak}
+\def\noitembreakspecial{\doitembreak\itemnobreak}
+
+\def\itembreak {\flushnotes\penalty-5\relax} % -10
+\def\itemnobreak{\flushnotes\penalty+5\ifinsidecolumns\else00\fi\relax} % +5
+
+\def\initializeitemgrouplevel#1%
+ {\ifcsname\??op\currentitemgroup#1\s!parent\endcsname
+ % ok
+ \else\ifnum#1>\plusone
+ \setevalue{\??op\currentitemgroup#1\s!parent}{\??op\currentitemgroup\the\numexpr#1-1\relax}%
+ \else
+ \setevalue{\??op\currentitemgroup#1\s!parent}{\??op\currentitemgroup}%
+ \fi\fi}
+
+\def\defineitemgroup
+ {\dotripleempty\dodefineitemgroup}
+
+\def\dodefineitemgroup[#1][#2][#3]% todo: clone
+ {\doifsomething{#1}
+ {\pushmacro\currentitemgroup
+ \def\currentitemgroup{#1}%
+ \setvalue{\e!start#1}{\startitemgroup[#1]}%
+ \setvalue{\e!stop#1}{\stopitemgroup}%
+ \setvalue{\e!setup#1\e!endsetup}{\setupitemgroup[#1]}% for old times sake
+ \doifelsenothing{#2}
+ {\getparameters[\??op#1][\s!parent=\??oo,#3]}%
+ {\doifassignmentelse{#2}
+ {\getparameters[\??op#1][\s!parent=\??oo,#2]}%
+ {\getparameters[\??op#1][\s!parent=\??op#2,#3]}}%
+ \dorecurse\maxitemdepth{\initializeitemgrouplevel\recurselevel}%
+ \definestructurecounter[itemgroup:#1]%
+ \popmacro\currentitemgroup}}
+
+\def\setupitemgroups % [#1]
+ {\dodoubleargument\getparameters[\??oo]} % [#1]
+
+\def\packitems
+ {\ifcase\currentitemlevel \else \settrue\packlistitem \fi}
+
+\def\dosetupitemgroupvariable[#1]% [#2]% niveau instellingen
+ {\doifelsenothing{#1}
+ {\getparameters[\??op\currentitemgroup\currentitemlevel]}%
+ {\getparameters[\??op\currentitemgroup#1]}}
+
+\def\dosetupitemgroupconstant#1%
+ {\global\setitemparameter\currentitemlevel\c!maxwidth{0}%
+ \processcommacommand[#1]\dodosetupitemgroupconstant} % expansion of #2 is handy for xml
+
+\def\dodosetupitemgroupconstant#1%
+ {\edef\itemgroupconstantvalue{#1}%
+ \ifx\itemgroupconstantvalue\empty\else
+ \splitstring\itemgroupconstantvalue\at*\to\itemgroupfirst\and\itemgroupsecond
+ \ifcsname\??op:::\itemgroupfirst\endcsname\csname\??op:::\itemgroupfirst\endcsname\fi
+ \fi}
+
+\newconditional\inlinelistitem \setfalse\inlinelistitem
+
+\setvalue{\??op:::\v!packed }{\packitems}
+\setvalue{\??op:::\v!intro }{\settrue\introlistitem} % here? not set to false
+\setvalue{\??op:::\v!autointro}{\settrue\autointrolistitem}
+\setvalue{\??op:::\v!broad }{\ifx\itemgroupsecond\empty\def\itemgroupsecond{1}\fi
+ \letitemparameter\currentitemlevel\c!factor\itemgroupsecond}
+\setvalue{\??op:::\v!text }{\settrue\textlistitem
+ \settrue\inlinelistitem
+ \settrue\joinedlistitem
+ \packitems}
+\setvalue{\??op:::\v!columns }{\packitems}
+\setvalue{\??op:::\v!before }{\settrue\beforelistitem}
+\setvalue{\??op:::\v!after }{\settrue\afterlistitem}
+\setvalue{\??op:::\v!nowhite }{\settrue\nowhitelistitem}
+\setvalue{\??op:::\v!margin }{\setitemparameter\currentitemlevel\c!width{-2em}} % signal
+\setvalue{\??op:::\v!inmargin }{\setitemparameter\currentitemlevel\c!width{-2em}} % signal
+\setvalue{\??op:::\v!atmargin }{\doifnot\currentitemlevel{1}{\setitemparameter\currentitemlevel\c!width{0em}}} % signal
+\setvalue{\??op:::\v!intext }{\settrue\inlinelistitem}
+\setvalue{\??op:::\v!loose }{\setfalse\optimizelistitem}
+\setvalue{\??op:::\v!fit }{\settrue\fittinglistitems}
+\setvalue{\??op:::\v!nofit }{\setfalse\fittinglistitems}
+\setvalue{\??op:v:\v!paragraph}{\settrue\paragraphlistitem
+ \packitems}
+\setvalue{\??op:::\v!joinedup }{\settrue\joinedlistitem
+ \packitems}
+\setvalue{\??op:::\v!serried }{\edef\itemgroupsecond{-\ifx\itemgroupsecond\empty1\else\itemgroupsecond\fi}%
+ \letitemparameter\currentitemlevel\c!factor\itemgroupsecond}
+\setvalue{\??op:::\v!stopper }{\letitemparameter\currentitemlevel\c!placestopper\v!yes} % keep {}
+\setvalue{\??op:::\v!unpacked }{\setfalse\packlistitem}
+\setvalue{\??op:::\v!repeat }{\settrue\repeatlistitem}
+\setvalue{\??op:::\v!reverse }{\settrue\reverselistitem}
+\setvalue{\??op:::\v!standard }{\dosetupstandarditemgroup\currentitemlevel}
+
+\def\dosetupstandarditemgroup#1%
+ {\getparameters
+ [\??op\currentitemgroup#1]
+ [\c!width=1.5em,\c!factor=0,\c!distance=.5em,\c!inner=,
+ \c!beforehead=,\c!afterhead=\blank,\c!before=\blank,\c!inbetween=\blank,\c!after=\blank]}
+
+% \def\packeditemspacing{\empty}
+
+% \setupwhitespace[big]
+% \starttext
+% test \startitemize[joinedup] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite,before] \item test \item test \stopitemize test \par
+% test \startitemize[joinedup,nowhite,after] \item test \item test \stopitemize test \par
+% \stoptext
+
+\def\itembeforecommand
+ {\ifconditional\nowhitelistitem
+ \ifconditional\beforelistitem
+ \ifcase\currentitemlevel\or\getitemparameter\currentitemlevel\c!before\fi
+ \else
+ \nowhitespace
+ \fi
+ \else\ifconditional\joinedlistitem
+ % \empty
+ \else
+ \getitemparameter\currentitemlevel\c!before
+ \fi\fi}
+
+\def\itemaftercommand
+ {\ifconditional\nowhitelistitem
+ \ifconditional\afterlistitem
+ \ifcase\currentitemlevel\or\getitemparameter\currentitemlevel\c!after\fi
+ \else
+ \nowhitespace
+ \fi
+ \else\ifconditional\joinedlistitem
+ % \empty
+ \else
+ \getitemparameter\currentitemlevel\c!after
+ \fi\fi}
+
+\def\iteminbetweencommand
+ {\ifconditional\nowhitelistitem
+ \nowhitespace
+ \else\ifconditional\joinedlistitem
+ % \empty
+ \else
+ \getitemparameter\currentitemlevel\c!inbetween
+ \fi\fi}
+
+\def\itembeforeheadcommand
+ {\ifconditional\nowhitelistitem
+ \nowhitespace
+ \else\ifconditional\joinedlistitem
+ % \empty
+ \else
+ \getitemparameter\currentitemlevel\c!beforehead
+ \fi\fi}
+
+\def\itemafterheadcommand
+ {\ifconditional\nowhitelistitem
+ \nowhitespace
+ \else\ifconditional\joinedlistitem
+ % \empty
+ \else
+ \getitemparameter\currentitemlevel\c!afterhead
+ \fi\fi}
+
+\def\dododododosetupitemgroup[#1][#2]%
+ {\doifassignmentelse{#2}%
+ {\dosetupitemgroupvariable[#1][#2]}%
+ {\setitemparameter{#1}\c!option{#2}}}%
+
+\def\dodododosetupitemgroup[#1][#2]%
+ {\doifsomething{#2}
+ {\doifelse{#1}\v!each
+ {\dorecurse\maxitemdepth{\normalexpanded{\noexpand\dododododosetupitemgroup[\recurselevel]}[#2]}}
+ {\normalexpanded{\noexpand\dododododosetupitemgroup[#1]}[#2]}}}
+
+% \def\dododosetupitemgroup[#1][#2]%
+% {\doifelsenothing{#2}
+% {\doifelsenothing{#1}
+% {\dodododosetupitemgroup[\currentitemlevel][#2]}
+% {\dodododosetupitemgroup[#1][#2]}}
+% {\ifcase\currentitemlevel\relax
+% \dodododosetupitemgroup[\v!each][#1]%
+% \else
+% \dodododosetupitemgroup[\currentitemlevel][#1]%
+% \fi}}
+
+\def\dododosetupitemgroup[#1][#2]%
+ {\doifelsenothing{#2}
+ {\doifsomething{#1}
+ {\ifcase\currentitemlevel\relax
+ \dodododosetupitemgroup[\v!each][#1]%
+ \else
+ \dodododosetupitemgroup[\currentitemlevel][#1]%
+ \fi}}%
+ {\doifelsenothing{#1}
+ {\ifcase\currentitemlevel\relax
+ \dodododosetupitemgroup[\v!each][#2]%
+ \else
+ \dodododosetupitemgroup[\currentitemlevel][#2]%
+ \fi}
+ {\dodododosetupitemgroup[#1][#2]}}}
+
+\def\dodosetupitemgroup[#1][#2][#3][#4]%
+ {\pushmacro\currentitemgroup
+ \def\currentitemgroup{#1}%
+ \dododosetupitemgroup[#2][#3]%
+ \doifsomething{#4}{\dododosetupitemgroup[#2][#4]}%
+ \popmacro\currentitemgroup}
+
+\def\dosetupitemgroup[#1][#2][#3][#4]%
+ {\def\docommand##1{\dodosetupitemgroup[##1][#2][#3][#4]}%
+ \processcommalist[#1]\docommand}
+
+\def\setupitemgroup
+ {\doquadrupleempty\dosetupitemgroup}
+
+\def\doadvanceitem
+ {\ifconditional\sublistitem\else\ifconditional\symbollistitem\else
+ \doincrementsubstructurecounter[\currentitemgroupcounter][\currentitemlevel]%
+ \fi\fi}
+
+\def\setitemlevel#1%
+ {\ifnum\currentitemlevel>\zerocount
+ \settrue\firstlistitem
+ \ifconditional\continuelistitems\else
+ \dorestartsubstructurecounter[\currentitemgroupcounter][\currentitemlevel]{\the\numexpr\getitemparameter\currentitemlevel\c!start-1\relax}%
+ \fi
+ \fi}
+
+\unexpanded\def\actualitemnumber
+ {\ifconditional\repeatlistitem
+ \ifcase\currentitemlevel\or\else
+ \doactualitemnumber
+ \fi
+ \else
+ \doactualitemnumber
+ \fi}
+
+\def\doactualitemnumber
+ {\begingroup
+ \setupstructurecounter
+ [\currentitemgroupcounter]
+ [\c!prefix=\v!no,
+ \c!numberorder=\ifconditional\reverselistitem\v!reverse\else\v!normal\fi,
+ \c!numberstopper=\expdoif{\getitemparameter\currentitemlevel\c!placestopper}\v!yes{\getitemparameter\currentitemlevel\c!stopper},
+ %\c!numberseparatorset=,
+ %\c!numberconversionset=,
+ \c!numberconversion=\currentitemsymbol,
+ \c!numbersegments=\ifx\currentrepeatstart\empty\else\currentrepeatstart:\fi\number\currentitemlevel]%
+ \ifconditional\reverselistitem
+ \convertedstructurecounter[\currentitemgroupcounter]% [\number\currentitemlevel]%
+ \else
+ \convertedstructurecounter[\currentitemgroupcounter]% [\number\currentitemlevel]%
+ \fi
+ \dohandleitemreference
+ \endgroup}
+
+\def\unknownitemsymbol{?}
+
+\def\setitemmark#1% % en pas op: resets \docommand ; todo: conversionset
+ {\doifsymboldefinedelse{#1}
+ {\edef\currentitemsymbol{#1}%
+ \setxvalue{\@@globalitemsymbol\currentitemlevel}{\currentitemsymbol}%
+ \setgvalue{\@@localitemsymbol \currentitemlevel}{\unknownitemsymbol}%
+ \def\listitem{\symbol[\currentitemsymbol]}%
+ \let\@@opsymbol\empty}%
+ {\doifconversiondefinedelse{#1}
+ {\edef\currentitemsymbol{#1}%
+ \setxvalue{\@@globalitemsymbol\currentitemlevel}{\currentitemsymbol}%
+ \setgvalue{\@@localitemsymbol\currentitemlevel }{\actualitemnumber }%
+ \def\listitem
+ {\ifconditional\textlistitem
+ % maybe block stopper here, but one can as well clone an
+ % itemgroup then
+ \getitemparameter\currentitemlevel\c!lefttext
+ \getvalue{\@@localitemsymbol\currentitemlevel}%
+ \getitemparameter\currentitemlevel\c!righttext
+ \else
+ \getitemparameter\currentitemlevel\c!left
+ \getvalue{\@@localitemsymbol\currentitemlevel}%
+ \getitemparameter\currentitemlevel\c!right
+ \fi}%
+ \let\@@opsymbol\empty}%
+ {}}}
+
+\def\calculatelistwidth#1% distance deals with 'broad'
+ {\itemgrouplistwidth\getitemparameter#1\c!distance\relax
+ \ifnum\getitemparameter#1\c!factor>\zerocount
+ \ifdim\itemgrouplistwidth=\zeropoint \itemgrouplistwidth=.5em\fi
+ \fi
+ \multiply\itemgrouplistwidth \getitemparameter#1\c!factor
+ \advance \itemgrouplistwidth \getitemparameter#1\c!width\relax}
+
+% The next conditionals deal with \item \startitemgroup. It
+% looks like a hack to skip back, but that way we preserve
+% the indentation and bullet placement. It's a rather
+% untested feature.
+
+\newconditional\concatnextitem \setfalse\concatnextitem
+\newconditional\autoconcatnextitem \settrue \autoconcatnextitem
+\newsignal \itemsignal
+
+\def\startitemgroup
+ {\dotripleempty\dostartitemgroup}
+
+\def\dostartitemgroup[#1][#2][#3]%
+ {\bgroup
+ \ifnum\currentitemlevel=\zerocount
+ \def\currentitemgroup{#1}% no nested mixing of itemgroups
+ \fi
+ \ifthirdargument
+ \dodostartitemgroup[#2][#3]%
+ \else
+ \doifassignmentelse{#2}
+ {\dodostartitemgroup[][#2]}
+ {\dodostartitemgroup[#2][]}%
+ \fi}
+
+\def\dodostartitemgroup[#1]% [#2]%
+ {\relax % prevents lookahead
+ \ifnum\currentitemlevel=\maxitemdepth\relax
+ \showmessage\m!layouts9{\number\maxitemdepth}%
+ \let\itemincrement\zerocount
+ \else
+ \let\itemincrement\plusone
+ \fi
+ \global\advance\itemdepth\itemincrement
+ \xdef\currentitemlevel{\number\itemdepth}%
+ \edef\itemgroupoptions{\getitemparameter\currentitemlevel\c!option}%
+ \ifx\itemgroupoptions\empty
+ \edef\itemgroupoptions{#1}%
+ \else
+ \doifsomething{#1}{\edef\itemgroupoptions{\itemgroupoptions,#1}}%
+ \fi
+ \normalexpanded{\noexpand\redostartitemgroup[\itemgroupoptions]}}% [#2]
+
+\let\startcollectitems\relax
+\let\stopcollectitems \relax
+
+%D A nice example of a plugin:
+%D
+%D \startbuffer
+%D \startitemize[a,random,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D
+%D \startitemize[a,random,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D
+%D \startitemize[a,packed]
+%D \startitem first \stopitem \startitem second \stopitem
+%D \startitem third \stopitem \startitem fourth \stopitem
+%D \stopitemize
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+% better collectitems als conditional and a real plugin mechanism (some day)
+
+\@EA\long\@EA\def\@EA\collectitemgroupitem\@EA#\@EA1\csname\e!stop\v!item\endcsname
+ {\increment\itemcollectcounter
+ \long\setvalue{\v!item*\itemcollectcounter}{\item#1\par}}
+
+\def\flushcollecteditems
+ {\ifconditional\randomizeitems
+ \getrandomnumber\itemcollectcounternow\plusone\itemcollectcounter
+ \else
+ \increment\itemcollectcounternow
+ \fi
+ \doifdefined{\v!item*\itemcollectcounternow}
+ {\getvalue{\v!item*\itemcollectcounternow}%
+ \letbeundefined{\v!item*\itemcollectcounternow}%
+ \increment\itemcollectcounterdone}%
+ \ifnum\itemcollectcounterdone<\itemcollectcounter\relax
+ \expandafter\flushcollecteditems
+ \fi}
+
+\def\stopcollectitems
+ {\ifconditional\randomizeitems
+ \newcounter\itemcollectcounterdone
+ \ifnum\itemcollectcounter>\zerocount
+ \@EAEAEA\flushcollecteditems
+ \fi
+ \fi}
+
+\def\startcollectitems
+ {\ifconditional\randomizeitems
+ \newcounter\itemcollectcounter
+ \letvalue{\e!start\v!item}\collectitemgroupitem
+ \fi}
+
+%D End of plugin.
+
+\ifx\startcolumns\undefined \def\startcolumns[#1]{} \fi
+\ifx\stopcolumns \undefined \let\stopcolumns\relax \fi
+
+\def\dosetsymalign#1% hm, we should use one of the core-spa macros or make a helper
+ {\processaction
+ [#1]
+ [ \v!flushleft=>\let\symalignleft\relax,
+ \v!right=>\let\symalignleft\relax,
+ \v!flushright=>\let\symalignleft\hfill,
+ \v!left=>\let\symalignleft\hfill,
+ \v!middle=>\let\symalignleft\hfil,
+ \v!center=>\let\symalignleft\hfil]}
+
+\def\redostartitemgroup[#1][#2]%
+ {\setfalse\inlinelistitem % new, no indent (leftskip)
+ \setfalse\concatnextitem % new, concat
+ \setfalse\txtlistitem
+ \ifhmode
+ \ifconditional\autoconcatnextitem % new, concat
+ \ifdim\lastskip=\itemsignal % new, concat
+ \settrue\concatnextitem % new, concat
+ \fi % new, concat
+ \fi % new, concat
+ \ifconditional\textlistitem\else\doifnotinset\v!text{#1}\par\fi % suboptimal
+ \fi
+ \begingroup
+ % new where, ok or not / we should integrate random, intro, continue here
+ % beware, the following no longer inherit from the previous level, is this ok?
+ \setfalse\reverselistitem
+ \setfalse\introlistitem
+ \setfalse\autointrolistitem
+ \setfalse\beforelistitem
+ \setfalse\afterlistitem
+ \setfalse\nowhitelistitem
+ \setfalse\randomizeitems
+ %
+ \doifinsetelse\v!intro {#1}{\settrue\introlistitem }{\setfalse\introlistitem }%
+ \doifinsetelse\v!random {#1}{\settrue\randomizeitems }{\setfalse\randomizeitems }%
+ \doifinsetelse\v!continue{#1}{\settrue\continuelistitems}{\setfalse\continuelistitems}%
+ % == \doifinsetelse\v!intro{#1}\settrue\setfalse\introlistitem
+ \global\advance\noflists\plusone
+ \currentnoflists\noflists
+ \noflistelements\zerocount
+ \setfalse\headlistitem
+ \setfalse\sublistitem
+ \setfalse\symbollistitem
+ \let\marsymbol\relax
+ \globallet\doitemdestination\empty
+ \let\symsymbol\empty
+ \let\symalignleft\relax
+ \the\itemgroupcommands
+ \checkcurrentnofitems
+ % \getitemparameter\currentitemlevel\empty
+ \let\listitem\empty % ** start value
+ \doifelsenothing{#1} % iffirstargument
+ {\edef\@@opsymbol{\noexpand\getitemparameter\currentitemlevel\noexpand\c!symbol}%
+ \letgvalueempty{\@@globalitemsymbol\currentitemlevel}%
+ \global\letitemparameter\currentitemlevel\v!continue\empty
+ \dosetupitemgroupvariable[\currentitemlevel][#2]}
+ {\dosetupitemgroupconstant{#1}%
+ \dosetupitemgroupvariable[\currentitemlevel][#2]%
+ \ifconditional\continuelistitems
+ \edef\@@opsymbol{\executeifdefined{\@@globalitemsymbol\currentitemlevel}{\currentitemlevel}}%
+ \getitemparameter\currentitemlevel\v!continue
+ \else
+ \edef\@@opsymbol{\noexpand\getitemparameter\currentitemlevel\noexpand\c!symbol}%
+ \global\setitemparameter\currentitemlevel\v!continue
+ {\dosetupitemgroupconstant{#1}%
+ \dosetupitemgroupvariable[\currentitemlevel][#2]}%
+ \fi
+ \def\docommand##1% \setitemmark resets \docommand
+ {\doifnot{##1}{0}{\setitemmark{##1}}}%
+ % \processcommalist[#1,\@@opsymbol]\docommand
+ \processcommalist[#1]\docommand}% ** preset sequence or provided sequence
+ % moved to here, after settings
+ \ifnum\currentitemlevel=\plusone % NIEUW
+ \doadaptleftskip {\getitemparameter\currentitemlevel\c!margin}%
+ \doadaptleftskip {\getitemparameter\currentitemlevel\c!leftmargin}%
+ \doadaptrightskip{\getitemparameter\currentitemlevel\c!rightmargin}%
+ \fi
+ \dosetraggedcommand{\getitemparameter\currentitemlevel\c!align}\raggedcommand
+ \dosetsymalign{\getitemparameter\currentitemlevel\c!symalign}%
+ \doifsomething{\getitemparameter\currentitemlevel\c!indenting}
+ {\normalexpanded{\noexpand\setupindenting[\getitemparameter\currentitemlevel\c!indenting]}}%
+ %
+ \setitemlevel{#1}% moved to here
+ \ifx\listitem\empty
+ \setitemmark\@@opsymbol % ** default value
+ \ifx\listitem\empty
+ \edef\currentitemsymbol{\currentitemlevel}% ** fall back
+ \fi
+ \fi
+ \ifconditional\autointrolistitem\ifnum\prevgraf<3
+ \settrue\introlistitem
+ \fi\fi
+ \ifconditional\paragraphlistitem
+ \ifnum\currentitemlevel>\plusone
+ \letitemparameter\currentitemlevel\c!inbetween\empty
+ \fi
+ \fi
+ \ifconditional\packlistitem
+ \letitemparameter\currentitemlevel\c!inbetween\empty
+ \fi
+ \doifinset\v!columns{#1}%
+ {\ifinsidecolumns\else\ifcase\itemcolumndepth
+ \global\itemcolumndepth\currentitemlevel\relax
+ \itembeforecommand
+ \processfirstactioninset
+ [#1]
+ [ \v!one=>\setitemparameter\currentitemlevel\c!n{1},
+ \v!two=>\setitemparameter\currentitemlevel\c!n{2},
+ \v!three=>\setitemparameter\currentitemlevel\c!n{3},
+ \v!four=>\setitemparameter\currentitemlevel\c!n{4},
+ \v!five=>\setitemparameter\currentitemlevel\c!n{5},
+ \s!unknown=>\@EA\!!counta\getitemparameter\currentitemlevel\c!n]%
+ \startcolumns
+ [\c!n=\getitemparameter\currentitemlevel\c!n,
+ \c!height=,
+ \c!rule=\v!off,
+ \c!balance=\v!yes,
+ \c!align=\v!no]%
+ \fi\fi}%
+ \ifconditional\fittinglistitems
+ \ifdim\currentitemmaxwidth>\zeropoint
+ \esetitemparameter\currentitemlevel\c!width{\currentitemmaxwidth}%
+ \fi
+ \fi
+ \calculatelistwidth\currentitemlevel
+ \ifdim\itemgrouplistwidth>\zeropoint\relax
+ \ifconditional\inlinelistitem\else
+ \advance\leftskip\itemgrouplistwidth\relax
+ \fi
+ \fi
+ \startcollectitems}
+
+% test / example
+%
+% \startnarrower[left] \startcolumns[n=3] \startitemize
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \stopcolumns\stopnarrower \blank
+%
+% \startnarrower[left] \startitemize[columns,three]
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \stopnarrower \blank
+%
+% \setupitemize[leftmargin=1.5em] \startitemize[columns,three]
+% \item \input ward \item \input ward \item \input ward
+% \stopitemize \blank
+
+\def\stopitemgroup
+ {\stopcollectitems
+ \ifconditional\textlistitem
+ \removeunwantedspaces\space\ignorespaces
+ \else
+ \par
+ \fi
+ \dolistreference
+ \ifconditional\firstlistitem \else \endgroup \fi % toegevoegd, eerste \som opent groep
+ \ifnum\itemcolumndepth=\currentitemlevel\relax
+ \stopcolumns
+ \global\itemcolumndepth\zerocount
+ \itemaftercommand
+ \dontrechecknextindentation
+ \else
+ \ifnum\currentitemlevel=\plusone
+ \allowitembreak
+ \itemaftercommand
+ \checknextindentation[\getitemparameter\currentitemlevel\c!indentnext]%
+ \else
+ % nieuw, not yet nobreak handling
+ \ifcase\autoitemgroupspacing
+ \itemaftercommand
+ \or
+ \itemaftercommand
+ \fi
+ \dontrechecknextindentation
+ \fi
+ \fi
+ % new test, needed in sidefloats (surfaced in volker's proceedings)
+ \ifconditional\textlistitem % else forgotten
+ \endgroup
+ \global\advance\itemdepth-\itemincrement
+ \xdef\currentitemlevel{\number\itemdepth}%
+ \egroup
+ \else
+ \endgroup
+ \global\advance\itemdepth-\itemincrement
+ \xdef\currentitemlevel{\number\itemdepth}%
+ \egroup
+ \par
+ \fi
+ \dorechecknextindentation}
+
+\newtoks\itemgroupcommands
+
+\def\itemgroupitem
+ {\doitemgroupitem}
+
+\def\itemgroupnoitem
+ {\doitemgroupnoitem}
+
+\def\itemgroupbutton[#1]%
+ {\gdef\doitemdestination{#1}%
+ \itemgroupitem}
+
+\def\itemgroupdummy
+ {\itemgroupsymbol{\strut}\strut}
+
+\def\itemgroupsubitem
+ {\settrue\sublistitem
+ \itemgroupitem}
+
+\def\itemgroupsymbol#1%
+ {\def\symsymbol{#1}%
+ \settrue\symbollistitem
+ \itemgroupitem}
+
+\def\itemgroupedge#1%
+ {\itemgroupsymbol
+ {\calculatelistwidth\currentitemlevel
+ \hbox to \itemgrouplistwidth
+ {#1\hskip\getitemparameter\currentitemlevel\c!distance}}}
+
+\def\itemgrouphead
+ {\settrue\headlistitem\doitemgrouphead}
+
+\def\itemgroupitems
+ {\dosingleempty\doitemgroupitems}
+
+\def\doitemgroupitems[#1]%
+ {\itemgroupedge
+ {\dorecurse{0\getitemparameter\currentitemlevel\c!items}{\listitem\hss}%
+ \unskip}}
+
+\def\itemgroupmargin#1%
+ {\def\marsymbol
+ {\llap
+ {\dosetitemattributes\currentitemlevel\c!marstyle\c!marcolor{#1}%
+ \hskip\leftskip\hskip\leftmargindistance}}%
+ \itemgroupitem}
+
+\appendtoks \let\item \itemgroupitem \to \itemgroupcommands
+\appendtoks \let\noitem \itemgroupnoitem \to \itemgroupcommands
+\appendtoks \letvalue\v!item \itemgroupitem \to \itemgroupcommands
+\appendtoks \let\itm \itemgroupitem \to \itemgroupcommands
+\appendtoks \let\but \itemgroupbutton \to \itemgroupcommands
+\appendtoks \let\nop \itemgroupdummy \to \itemgroupcommands
+\appendtoks \letvalue\v!sub \itemgroupsubitem \to \itemgroupcommands
+\appendtoks \letvalue\v!sym \itemgroupsymbol \to \itemgroupcommands
+\appendtoks \letvalue\v!ran \itemgroupedge \to \itemgroupcommands
+\appendtoks \letvalue\v!head \itemgrouphead \to \itemgroupcommands
+\appendtoks \letvalue\v!its \itemgroupitems \to \itemgroupcommands
+\appendtoks \letvalue\v!mar \itemgroupmargin \to \itemgroupcommands
+
+% todo : \startitem .. \stopitem
+
+\appendtoks
+ \letvalue{\e!start\v!item}\itemgroupitem
+ \letvalue{\e!stop \v!item}\endgraf
+\to \itemgroupcommands
+
+\appendtoks
+ \setvalue{\e!start\v!head}#1{\itemgrouphead#1\par}%
+ \letvalue{\e!stop \v!head}\endgraf
+\to \itemgroupcommands
+
+% \startitemize
+% \starthead {xx} test \stophead
+% \startitem test \stopitem
+% \startitem test \stopitem
+% \stopitemize
+
+% Sometimes the user demands get pretty weird:
+%
+% \startitemize
+% \item test
+% \item test
+% \headsym{xx} test \par test
+% \stopitemize
+
+% aligned items
+%
+% \startitemize[n,fit,broad][itemalign=flushright]
+% \dorecurse{100}{\item The first item.}
+% \stopitemize
+%
+% \setupitemgroup[itemize][each][fit]
+% \setupitemgroup[itemize][each][distance=.5em,factor=1,itemalign=flushright]
+%
+% \startitemize[n]
+% \dorecurse{100}{\item The first item.}
+% \stopitemize
+
+\appendtoks \let\headsym \itemgroupheadsym \to \itemgroupcommands
+
+\def\itemgroupheadsym#1%
+ {\def\symsymbol{#1}%
+ \settrue\symbollistitem
+ \settrue\headlistitem
+ \doitemgrouphead}
+
+% \defineitemgroup[gbitemize]
+% \setupitemgroup[gbitemize][each][headstyle=bold]
+
+% \startgbitemize
+% \txt{italian} some italians like this kind of cross||breed between
+% an itemize and a description
+% \txt{sicilians} i wonder how many sicilian mathematicians do a thesis
+% on the math involved in predicting the next big bang of the vulcano
+% \stopgbitemize
+
+\appendtoks \letvalue\v!txt\itemgrouptext \to \itemgroupcommands
+
+\newconditional\txtlistitem \setfalse\txtlistitem
+
+\def\itemgrouptext#1%
+ {\def\symsymbol{#1}%
+ \settrue\symbollistitem
+ \settrue\txtlistitem
+ \itemgroupitem}
+
+\def\dodotxtitem
+ {\scratchdimen\wd\itemgroupitembox
+ \advance \scratchdimen \getitemparameter\currentitemlevel\c!distance\relax
+ \ifdim\scratchdimen>\itemgrouplistwidth
+ \advance\scratchdimen -\itemgrouplistwidth
+ \else
+ \scratchdimen\zeropoint
+ \fi
+ \llap{\hbox to \itemgrouplistwidth{\ifconditional\sublistitem\llap{+}\fi\box\itemgroupitembox\hss}}% was: \hfill
+ \hskip\scratchdimen}
+
+\def\optimizelistitemsbreak
+ {\ifcase\itemcolumndepth \ifconditional\optimizelistitem
+ \ifcase \currentnofitems \else
+ \ifnum\currentnofitems=\plusthree
+ \ifnum\noflistelements>\plusone
+ \noitembreakspecial
+ \fi
+ \else\ifnum\currentnofitems>\plusthree
+ \ifnum\noflistelements=\plustwo
+ \ifconditional\introlistitem
+ \noitembreak
+ \else
+ \noitembreakspecial
+ \fi
+ \else\ifnum\currentnofitems=\noflistelements\relax
+ \noitembreakspecial
+ \else\ifnum\noflistelements>\plustwo
+ \itembreakspecial
+ \else
+ \ifconditional\introlistitem\else\itembreakspecial\fi
+ \fi\fi\fi
+ \fi\fi
+ \fi
+ \fi\fi}
+
+\def\dolistitem % evt aantal items opslaan per niveau, scheelt zoeken
+ {\ifconditional\textlistitem
+ % begin of item
+ \else
+ \par
+ \fi
+ \advance\noflistelements\plusone
+ \optimizelistitemsbreak
+ \noindent
+ \setbox\itemgroupitembox\hbox
+ {\ifconditional\headlistitem
+ \ifconditional\symbollistitem
+ \dosetitemattributes\currentitemlevel\c!symstyle\c!symcolor{\symsymbol}%
+ \else
+ \dosetitemattributes\currentitemlevel\c!headstyle\c!headcolor{\listitem}%
+ \fi
+ \else
+ \ifconditional\symbollistitem
+ \dosetitemattributes\currentitemlevel\c!symstyle\c!symcolor{\symsymbol}%
+ \else
+ \dosetitemattributes\currentitemlevel\c!style\c!color{\listitem}%
+ \fi
+ \fi}%
+ \ifconditional\fittinglistitems
+ \ifdim\wd\itemgroupitembox>\getitemparameter\currentitemlevel\c!maxwidth sp\relax
+ \xsetitemparameter\currentitemlevel\c!maxwidth{\number\wd\itemgroupitembox}%
+ \fi
+ \ifdim\currentitemmaxwidth>\zeropoint
+ \setbox\itemgroupitembox\simplealignedbox{\getitemparameter\currentitemlevel\c!itemalign}{\currentitemmaxwidth}{\box\itemgroupitembox}%
+ \fi
+ \fi
+ \doifsomething\doitemdestination
+ {\setbox\itemgroupitembox\hbox{\goto{\box\itemgroupitembox}[\doitemdestination]}}%
+ \globallet\doitemdestination\empty
+ \itemgroupaskedwidth\getitemparameter\currentitemlevel\c!width\relax
+ % new, prevents loops when symbol is (not yet found) graphic
+ \ht\itemgroupitembox\strutheight
+ \dp\itemgroupitembox\strutdepth
+ % so that content differs per run (esp mp graphics afterwards)
+ \checkforrepeatedlistitem
+ \ifdim\itemgroupaskedwidth<\zeropoint\relax
+ \llap{\ifconditional\sublistitem\llap{+}\fi\box\itemgroupitembox\hskip\leftmargindistance}%
+ \else
+ \ifdim\itemgroupaskedwidth=\zeropoint\relax
+ \calculatelistwidth1%
+ \else
+ \calculatelistwidth\currentitemlevel
+ \fi
+ \ifconditional\textlistitem
+ \hbox{\ifconditional\sublistitem+\fi\box\itemgroupitembox\hskip\interwordspace}\nobreak
+ \else\ifconditional\inlinelistitem
+ \hbox to \itemgrouplistwidth{\ifconditional\sublistitem\llap{+}\fi\box\itemgroupitembox\hss}% was: \hfill
+ \else\ifconditional\txtlistitem
+ \dodotxtitem
+ \else
+ % todo: align+marge binnen de hbox
+ \llap{\hbox to \itemgrouplistwidth{\ifconditional\sublistitem\llap{+}\fi
+ \symalignleft
+ \box\itemgroupitembox\hfil
+ \hskip\getitemparameter\currentitemlevel\c!distance% T h
+ }}%
+ \fi\fi\fi
+ \fi
+ \forceunexpanded % needed for m conversion (\os) / i need to look into this
+ \setevalue{\@@currentitemsymbol\currentitemlevel}%
+ {\getvalue{\@@localitemsymbol\currentitemlevel}}% still problems with \uchar ?
+ %{\noexpand\getvalue{\@@localitemsymbol\currentitemlevel}}% no, spoils subrefs
+ \resetunexpanded
+ \setfalse\headlistitem
+ \setfalse\sublistitem
+ \setfalse\symbollistitem
+ \EveryPar{\ignorespaces}% needed ?
+ \ignorespaces}
+
+% For Wolfgang Schuster
+
+% \startitemize[n,repeat]
+% \noitem \startitemize[a] \item Item 1.a. \item Item 1.b. \stopitemize
+% \noitem \startitemize[a] \item Item 2.a. \item Item 2.b. \stopitemize
+% \stopitemize
+
+\def\donolistitem % reduced \dolistitem
+ {\advance\noflistelements\plusone
+ \setbox\itemgroupitembox\hbox
+ {\dosetitemattributes\currentitemlevel\c!style\c!color{\listitem}}%
+ \checkforrepeatedlistitem
+ \ignorespaces}
+
+\def\doitemgroupnoitem
+ {\doadvanceitem\donolistitem}
+
+% For Frank Grieshaber and Mojca Miklavec:
+
+\newconditional\repeatlistitem
+
+\def\checkforrepeatedlistitem
+ {\ifconditional\repeatlistitem
+ \ifx\currentrepeatstart\empty
+ \edef\currentrepeatstart{\the\numexpr\currentitemlevel-1}%
+ \fi
+ \setbox\itemgroupitembox\hbox to \wd\itemgroupitembox{\hskip-\itemgroupaskedwidth\box\itemgroupitembox}% what a hack !
+ \fi}
+
+% \startbuffer
+% \item
+% \startitemize[n]
+% \item item 1.1
+% \item item 1.2
+% \startitemize[n] \item item 1.2.1 \item item 1.2.2 \stopitemize
+% \item item 1.3
+% \stopitemize
+% \item
+% \startitemize[n] \item item 2.1 \item item 2.2 \stopitemize
+% \item item 3
+% \startitemize[n] \item item 3.1 \item item 3.2 \stopitemize
+% \item
+% \startitemize[n] \item item 4.1 \item item 4.2 \stopitemize
+% \stopbuffer
+%
+% \startitemize[n,repeat,6*broad,packed] \getbuffer \stopitemize \blank[3*big]
+% \startitemize[n,repeat,packed] \getbuffer \stopitemize \blank[3*big]
+% \setupitemize[each][atmargin][width=3em]
+% \startitemize[n,repeat,packed] \getbuffer \stopitemize
+
+\chardef\autoitemgroupspacing=2 % 0 = voor/na, 1=tussen als geen voor 2=(prev)tussen=old/normal
+
+\def\complexdoitemgroupitem[#1]%
+ {\def\currentitemreference{#1}%
+ \ifconditional\textlistitem
+ % begin of item
+ \else
+ \par
+ \fi
+ \ifconditional\concatnextitem % new, concat
+ \noitembreak % new, concat
+ \fi % new, concat
+ \doadvanceitem
+ \ifconditional\firstlistitem
+ \setfalse\firstlistitem
+ \begingroup
+ \ifcase\currentitemlevel
+ \or % 1
+ \ifcase\itemcolumndepth
+ \ifconditional\introlistitem\noitembreak\fi
+ \itembeforecommand
+ \ifconditional\introlistitem\noitembreak\fi
+ \fi
+ \else % 2 en hoger
+ \ifconditional\paragraphlistitem \else
+ \edef\previtemlevel{\the\numexpr\currentitemlevel-1}%
+ \ifcase\autoitemgroupspacing\relax % nieuw
+ \itembeforecommand
+ \or
+ \doifelsenothing\itembeforecommand\itembeforecommand{\getitemparameter\previtemlevel\c!inbetween}%
+ \else
+ \getitemparameter\previtemlevel\c!inbetween
+ \fi
+ \fi
+ \fi
+ \else
+ \ifconditional\textlistitem % was bugged: \inlinelistitem
+ \removeunwantedspaces\hskip\emwidth\!!plus\interwordstretch\!!minus\interwordshrink\relax % new per 2006/10/20
+ \else
+ \iteminbetweencommand
+ \fi
+ \fi
+ \ifconditional\concatnextitem
+ \vskip-\dimexpr\lastskip+\lineheight\relax
+ \nobreak
+ \fi
+ \dolistitem
+ \relax
+ \ifconditional\packlistitem
+ \setupwhitespace[\v!none]%
+ \fi
+ \getitemparameter\currentitemlevel\c!inner
+ \marsymbol
+ \let\marsymbol\relax
+ \strut % added 11-08-99
+% \dohandleitemreference
+ \setfalse\concatnextitem % new, concat
+ \nobreak % else problems with intext items
+ \hskip\itemsignal % new, concat
+ \getitemparameter\currentitemlevel\c!command} % \defaultitemcommand
+
+\def\defaultitemcommand
+ {\EveryPar{\ignorespaces}% needed ?
+ \ignorespaces}
+
+% For Giuseppe "Oblomov" Bilotta, inspired on a suggestion by Taco
+% Hoekwater.
+%
+% \def\MyItemCommand#1{{\bf#1}\quad}
+% \setupitemgroup[itemize][command=\MyItemCommand]
+%
+% \startitemize
+% \item {test} is this okay?
+% \item {test} is this okay?
+% \item {test} is this okay?
+% \stopitemize
+
+\def\complexitem[#1]#2\par % todo: no two pass data
+ {\startitemgroup[#1]%
+ \complexdoitemgroupitem[]\begstrut#2\endstrut\par
+ \stopitemgroup}
+
+\definecomplexorsimpleempty\item
+\definecomplexorsimpleempty\doitemgroupitem
+
+\def\complexhead[#1]#2\par#3\par
+ {\startitemgroup[#1]%
+ \complexdoitemgrouphead[]\begstrut#2\endstrut\par\begstrut#3\endstrut\par
+ \stopitemgroup}
+
+% the next solution accepts \head test \type{x{x}x} test ...
+
+\def\complexdoitemgrouphead[#1]% beter in \complexdosom hangen met een if
+ {\ifconditional\firstlistitem\else\allowitembreak\fi
+ \ifconditional\packlistitem\else\itembeforeheadcommand\fi
+ \ifconditional\firstlistitem\ifconditional\introlistitem\else\ifcase\currentitemlevel % incr in \complexdosom
+ \allowitembreak
+ \fi\fi\fi
+ \complexdoitemgroupitem[#1]%
+ \bgroup
+ \dosetitemattributes\currentitemlevel\c!headstyle\c!headcolor\empty
+ \ignorespaces
+ \let\par\enditemhead} % brrrr but simple anyway
+
+\def\enditemhead
+ {\removeunwantedspaces
+ \egroup
+ \ifconditional\textlistitem
+ \space\ignorespaces
+ \else
+ \par
+ \fi
+ \noitembreak
+ \ifconditional\packlistitem\else\itemafterheadcommand\fi
+ \noitembreak
+ \noindentation}
+
+\definecomplexorsimpleempty\head
+\definecomplexorsimpleempty\doitemgrouphead
+
+\def\sym#1%
+ {\noindent
+ \begingroup
+ \setbox\scratchbox\hbox{\trialtypesettingtrue#1}%
+ \setbox\scratchbox\hbox
+ \ifdim\wd\scratchbox<1em to 1.5\else spread 1\fi em{#1\hfil}%
+ \normalexpanded{\box\scratchbox\endgroup\hangindent\the\wd\scratchbox}%
+ \ignorespaces}
+
+\setupitemgroups
+ [\c!margin=\zeropoint,
+ \c!leftmargin=\zeropoint,
+ \c!rightmargin=\zeropoint,
+ \c!indentnext=\v!yes,
+ \c!width=1.5em,
+ \c!factor=0,
+ \c!distance=.5em,
+ %\c!align=\v!normal, % definitely not \v!normal, see mails and
+ %\c!align=, % debug reports of David A & Patrick G on context list
+ %\c!symalign=,
+ %\c!color=,
+ %\c!indenting=, % untouched if empty
+ %\c!style=,
+ \c!marstyle=\c!type, % \c! ???
+ %\c!symstyle=,
+ %\c!headstyle=,
+ %\c!marcolor=,
+ %\c!symcolor=,
+ %\c!headcolor=,
+ %\c!beforehead=,
+ \c!afterhead=\blank,
+ \c!before=\blank,
+ \c!inbetween=\blank,
+ \c!after=\blank,
+ %\c!stopper=.,
+ \c!placestopper=\v!yes,
+ \c!stopper=.,
+ %\c!inner=,
+ \c!n=2,
+ \c!items=4,
+ \c!lefttext=(,
+ \c!righttext=),
+ \c!start=1,
+ %\c!option=,
+ \c!command=\defaultitemcommand,
+ \c!symbol=\currentitemlevel]
+
+\setupitemgroups
+ [\c!numberseparatorset=,
+ \c!numberconversionset=,
+ \c!numberstopper=.,
+ \c!numbersegments=1]
+
+\defineitemgroup [\v!itemize]
+
+\protect \endinput
diff --git a/tex/context/base/strc-lst.lua b/tex/context/base/strc-lst.lua
new file mode 100644
index 000000000..48e2bf07d
--- /dev/null
+++ b/tex/context/base/strc-lst.lua
@@ -0,0 +1,392 @@
+if not modules then modules = { } end modules ['strc-lst'] = {
+ version = 1.001,
+ comment = "companion to strc-lst.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- when all datastructures are stable a packer will be added which will
+-- bring down memory consumption a bit; we can use for instance a pagenumber,
+-- section, metadata cache (internal then has to move up one level) or a
+-- shared cache [we can use a fast and stupid serializer]
+
+local format, tonumber = string.format, tonumber
+local texsprint, texprint, texwrite, count = tex.sprint, tex.print, tex.write, tex.count
+
+local ctxcatcodes = tex.ctxcatcodes
+
+structure.lists = structure.lists or { }
+structure.sections = structure.sections or { }
+structure.helpers = structure.helpers or { }
+structure.documents = structure.documents or { }
+structure.pages = structure.pages or { }
+
+local lists = structure.lists
+local sections = structure.sections
+local helpers = structure.helpers
+local documents = structure.documents
+local pages = structure.pages
+
+lists.collected = lists.collected or { }
+lists.tobesaved = lists.tobesaved or { }
+lists.enhancers = lists.enhancers or { }
+lists.internals = lists.internals or { }
+lists.ordered = lists.ordered or { }
+
+local variables = interfaces.variables
+
+local function initializer()
+ -- create a cross reference between internal references
+ -- and list entries
+ local collected = lists.collected
+ local internals = lists.internals
+ local ordered = lists.ordered
+ for i=1,#collected do
+ local c = collected[i]
+ local m = c.metadata
+ local r = c.references
+ if m then
+ -- access by internal reference
+ local internal = r and r.internal
+ if internal then
+ internals[internal] = c
+ end
+ -- access by order in list
+ local kind, name = m.kind, m.name
+ if kind and name then
+ local ok = ordered[kind]
+ if ok then
+ local on = ok[name]
+ if on then
+ on[#on+1] = c
+ else
+ ok[name] = { c }
+ end
+ else
+ ordered[kind] = { [name] = { c } }
+ end
+ end
+ end
+ end
+end
+
+if job then
+ job.register('structure.lists.collected', structure.lists.tobesaved, initializer)
+end
+
+local cached = { }
+local pushed = { }
+
+function lists.push(t)
+ local r = t.references
+ local i = (r and r.internal) or 0 -- brrr
+ local p = pushed[i]
+ if not p then
+ p = #cached + 1
+ cached[p] = helpers.simplify(t)
+ pushed[i] = p
+ end
+ texwrite(p)
+end
+
+function lists.doifstoredelse(n)
+ commands.doifelse(cached[tonumber(n)])
+end
+
+-- this is the main pagenumber enhancer
+
+function lists.enhance(n)
+ -- todo: symbolic names for counters
+ local l = cached[n]
+ if l then
+ -- save space
+ l.directives = nil
+ -- save in the right order (happen sat shipout)
+ lists.tobesaved[#lists.tobesaved+1] = l
+ -- default enhancer (cross referencing)
+ l.references.realpage = count[0]
+ -- specific enhancer (kind of obsolete)
+ local kind = l.metadata.kind
+ local enhancer = kind and lists.enhancers[kind]
+ if enhancer then
+ enhancer(l)
+ end
+ end
+end
+
+-- we can use level instead but we can also decide to remove level from the metadata
+
+-- we need level instead of cnumbers and we also need to deal with inbetween
+
+local function filter_collected(names, criterium, number, collected)
+ local numbers, depth = documents.data.numbers, documents.data.depth
+ local hash, result, all = { }, { }, not names or names == "" or names == variables.all
+ if not all then
+ for s in names:gmatch("[^, ]+") do
+ hash[s] = true
+ end
+ end
+ if criterium == variables.all or criterium == variables.text then
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then
+ local sectionnumber = (r.section == 0) or jobsections.collected[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local metadata = v.metadata
+ if metadata and not metadata.nolist and (all or hash[metadata.name or false]) then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ elseif criterium == variables.current then
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then
+ local sectionnumber = jobsections.collected[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers > depth then
+ local ok = true
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif criterium == variables.here then
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then
+ local sectionnumber = jobsections.collected[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers >= depth then
+ local ok = true
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif criterium == variables.previous then
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then
+ local sectionnumber = jobsections.collected[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers >= depth then
+ local ok = true
+ for d=1,depth-1 do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif criterium == variables["local"] then
+ if sections.autodepth(documents.data.numbers) == 0 then
+ return filter_collected(names,variables.all,number,collected)
+ else
+ return filter_collected(names,variables.current,number,collected)
+ end
+ else -- sectionname, number
+ local depth = sections.getlevel(criterium)
+ local number = tonumber(number) or 0
+ for i=1,#collected do
+ local v = collected[i]
+ local r = v.references
+ if r then
+ local sectionnumber = jobsections.collected[r.section]
+ if sectionnumber then -- and not sectionnumber.hidenumber then
+ local cnumbers = sectionnumber.numbers
+ local metadata = v.metadata
+ if cnumbers then
+ if metadata and not metadata.nolist and (all or hash[metadata.name or false]) and #cnumbers >= depth and cnumbers[depth] == number then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ end
+ return result
+end
+
+lists.filter_collected = filter_collected
+
+function lists.filter(names, criterium, number)
+ return filter_collected(names, criterium, number, lists.collected)
+end
+
+lists.result = { }
+
+function lists.process(...)
+ lists.result = lists.filter(...)
+ for i=1,#lists.result do
+ local r = lists.result[i]
+ local m = r.metadata
+ texsprint(ctxcatcodes,format("\\processlistofstructure{%s}{%s}{%i}",m.name,m.kind,i))
+ end
+end
+
+function lists.analyze(...)
+ lists.result = lists.filter(...)
+end
+
+function lists.userdata(name,r,tag)
+ local str = lists.result[r]
+ str = str and str.userdata
+ str = str and str[tag]
+ if str then
+ texsprint(ctxcatcodes,str)
+ end
+end
+
+function lists.uservalue(name,r,tag,default)
+ local str = lists.result[r]
+ str = str and str.userdata
+ str = str and str[tag]
+ return str or default
+end
+
+function lists.size()
+ texprint(#lists.result)
+end
+
+function lists.location(name,n)
+ local l = lists.result[n]
+ texsprint(l.references.internal or n)
+end
+
+function lists.sectionnumber(name,n,spec)
+ local data = lists.result[n]
+ local sectiondata = jobsections.collected[data.references.section]
+ sections.typesetnumber(sectiondata,"prefix",spec,sectiondata) -- data happens to contain the spec too
+end
+
+-- some basics (todo: helpers for pages)
+
+function lists.title(name,n,tag) -- tag becomes obsolete
+ local data = lists.result[n]
+ if data then
+ local titledata = data.titledata
+ if titledata then
+ texsprint(ctxcatcodes,titledata[tag] or titledata.title or "")
+ end
+ end
+end
+
+function lists.savedtitle(name,n,tag)
+ local data = cached[tonumber(n)]
+ if data then
+ local titledata = data.titledata
+ if titledata then
+ texsprint(ctxcatcodes,titledata[tag] or titledata.title or "")
+ end
+ end
+end
+
+function lists.savednumber(name,n)
+ local data = cached[tonumber(n)]
+ if data then
+ local numberdata = data.numberdata
+ if numberdata then
+ sections.typesetnumber(numberdata,"number",numberdata or false)
+ end
+ end
+end
+
+function lists.savedprefixednumber(name,n)
+ local data = cached[tonumber(n)]
+ if data then
+ helpers.prefix(data,data.prefixdata)
+ local numberdata = data.numberdata
+ if numberdata then
+ sections.typesetnumber(numberdata,"number",numberdata or false)
+ end
+ end
+end
+
+function lists.prefix(name,n,spec)
+ helpers.prefix(lists.result[n],spec)
+end
+
+function lists.page(name,n,pagespec)
+ helpers.page(lists.result[n],pagespec)
+end
+
+function lists.prefixedpage(name,n,prefixspec,pagespec)
+ helpers.prefixpage(lists.result[n],prefixspec,pagespec)
+end
+
+function lists.realpage(name,n)
+ local data = lists.result[n]
+ if data then
+ local references = data.references
+ texsprint(references and references.realpage or 0)
+ else
+ texsprint(0)
+ end
+end
+
+-- numbers stored in entry.numberdata + entry.numberprefix
+
+function lists.number(name,n,spec)
+ local data = lists.result[n]
+ if data then
+ local numberdata = data.numberdata
+ if numberdata then
+ sections.typesetnumber(numberdata,"number",spec or false,numberdata or false)
+ end
+ end
+end
+
+function lists.prefixednumber(name,n,prefixspec,numberspec)
+ local data = lists.result[n]
+ if data then
+ helpers.prefix(data,prefixspec)
+ local numberdata = data.numberdata
+ if numberdata then
+ sections.typesetnumber(numberdata,"number",spec or false,numberdata or false)
+ end
+ end
+end
diff --git a/tex/context/base/strc-lst.tex b/tex/context/base/strc-lst.tex
new file mode 100644
index 000000000..22c189c77
--- /dev/null
+++ b/tex/context/base/strc-lst.tex
@@ -0,0 +1,944 @@
+%D \module
+%D [ file=strc-lst,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Lists,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Lists}
+
+\registerctxluafile{strc-lst}{1.001}
+
+\unprotect
+
+\def\currentstructurelistnumber{0}
+
+% nmstate -> no pagenumber if not start
+% autocrossdocument -> todo
+% expansion -> todo
+% auto refs to lists (chain) -> todo (\dododowritetolist)
+% todo: \normalexpanded{\noexpand\everylistentry\emptytoks\the\everylistentry}% \emptytoks, else loop
+
+% \def\linklisttoelement#1#2#3#4{#4}% list location format page data
+
+\def\linklisttoelement#1#2#3#4% % list location format page data
+ {\gotonextinternal\currentlist{#1}{#3}{#4}}
+
+% interface to lua
+
+% we have to deal with compatible processing, i.e. list elements that have two
+% elements plus a pagenumber
+
+\let\listentry\gobblesixarguments
+
+\def\currentlist {\s!unknown}
+\def\currentlistmethod{entry}
+\def\currentlistindex {0}
+
+\def\setlistparameter#1#2#3{\@EA\def\csname\??li#1#2\endcsname{#3}} % often
+%def\listparameter #1{\ifcsname\??li\currentlist#1\endcsname\csname\??li\currentlist#1\endcsname\fi}
+
+% interface
+
+\def\listparameter #1{\csname\dolistparameter{\??li\currentlist}#1\endcsname}
+\def\namedlistparameter#1#2{\csname\dolistparameter{\??li #1}#2\endcsname}
+\def\listparameterhash #1{\dolistparameterhash {\??li\currentlist}#1}
+
+\def\dolistparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dolistparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dolistparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dolistparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dolistparentparameter #1#2{\ifx#1\relax\s!empty\else\dolistparameter #1#2\fi}
+\def\dolistparentparameterhash#1#2{\ifx#1\relax \else\dolistparameterhash#1#2\fi}
+
+\def\dosetlistattributes#1#2% style color
+ {\edef\fontattributehash {\listparameterhash#1}%
+ \edef\colorattributehash{\listparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\def\donestedlistattributes#1#2%
+ {\dosetlistattributes#1#2%
+ \ifx\colorattributehash\empty \else
+ \resetinteractionparameter\c!color
+ \resetinteractionparameter\c!contrastcolor
+ \fi}
+
+% handling
+
+
+% The next code injects data into the list at the current level.
+
+\def\structurelistinject{\dotripleempty\dostructurelistinject}
+
+\def\dostructurelistinject[#1][#2][#3]%
+ {\begingroup
+ \edef\currentlistname{#1}%
+ \setnextinternalreference
+ \edef\currentlistnumber{\ctxlua{structure.lists.push{
+ references = {
+ internal = \nextinternalreference,
+ section = structure.sections.currentid(),
+ },
+ metadata = {
+ kind = "#2",
+ name = "\currentlistname",
+ level = structure.sections.currentlevel(),
+ catcodes = \the\catcodetable,
+ },
+ userdata = structure.helpers.touserdata(\!!bs\detokenize{#3}\!!es)
+ }}}%
+ \expanded{\ctxlatelua{structure.lists.enhance(\currentlistnumber)}}%
+ \endgroup}
+
+\def\structurelistlocation
+ {\ctxlua{structure.lists.location("\currentlist",\currentlistindex)}}
+
+\def\structurelistpagenumber
+ {\ctxlua{structure.lists.prefixedpage(
+ "\currentlist",
+ \currentlistindex,
+ {
+ separatorset = "\listparameter\c!pageprefixseparatorset",
+ conversionset = "\listparameter\c!pageprefixconversionset",
+ set = "\listparameter\c!pageprefixset",
+ segments = "\listparameter\c!pageprefixsegments",
+ connector = \!!bs\listparameter\c!pageprefixconnector\!!es,
+ },
+ {
+ prefix = "\listparameter\c!pageprefix",
+ conversionset = "\listparameter\c!pageconversionset",
+ stopper = \!!bs\listparameter\c!pagestopper\!!es,
+ }
+ )}}
+
+\def\structurelistrealpagenumber
+ {\ctxlua{structure.lists.realpage("\currentlist",\currentlistindex)}}
+
+\def\structurelistfirst
+ {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"first")}}
+
+\def\structurelistsecond
+ {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"second")}}
+
+% \appendtoks
+% \to \everystructurelist
+
+\def\placestructurelist#1#2#3%
+ {\ctxlua{structure.lists.process("#1","#2","#3")}}
+
+\def\analysestructurelist#1#2#3%
+ {\ctxlua{structure.lists.analyze("#1","#2","#3")}}
+
+\def\firststructureelementinlist#1%
+ {\ctxlua{commands.first_in_list("#1")}}
+
+\def\structurelistsize
+ {\ctxlua{structure.lists.size()}}
+
+\def\@@structurelistprocess{structurelist:process:}
+
+\def\installstructurelistprocessor#1#2%
+ {\expandafter\def\csname\@@structurelistprocess#1\endcsname{#2}}
+
+\def\usestructurelistprocessor#1%
+ {\csname\@@structurelistprocess#1\endcsname}
+
+\installstructurelistprocessor\s!default
+ {no list method}
+
+\def\processlistofstructure#1#2#3% name, method, n
+ {\edef\currentlist {#1}%
+ \edef\currentlistmethod{#2}%
+ \edef\currentlistindex {#3}%
+ \csname\@@structurelistprocess
+ \ifcsname\@@structurelistprocess\currentlist:\currentlistmethod\endcsname\currentlist:\currentlistmethod\else
+ \ifcsname\@@structurelistprocess\currentlistmethod \endcsname\currentlistmethod \else
+ \ifcsname\@@structurelistprocess\currentlist \endcsname\currentlist \else
+ \s!default \fi\fi\fi
+ \endcsname}
+
+% \installstructcurelistprocessor{pubs:userdata}
+% {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"bibref")}}
+
+\installstructurelistprocessor{command}
+ {\ctxlua{structure.lists.userdata("\currentlist",\currentlistindex,"command")}}
+
+\installstructurelistprocessor{section}
+ {\dodolistelement
+ \currentlist
+ \structurelistlocation
+ \structurelistgenericnumber
+ \structurelistgenerictitle
+ \structurelistpagenumber
+ \structurelistrealpagenumber}
+
+% so far (todo: also recursive)
+
+\def\listalternativeparameter#1%
+ {\csname\??li\??li\listparameter\c!alternative#1\endcsname}
+
+\def\setuplistalternative[#1]%
+ {\dodoubleargument\getparameters[\??li\??li#1]}
+
+\def\listfill {\listalternativeparameter\c!command }
+\def\listskip {\listalternativeparameter\c!distance}
+\def\listwidth {\listalternativeparameter\c!width }
+\def\liststretch{\listalternativeparameter\c!stretch }
+
+% a : nr - tit - pag
+% b : nr - tit - fill - pag
+% c : nr - tit - dots - pag
+
+\setuplistalternative[a][\c!distance=0pt,\c!width=2em,\c!stretch=10em,\c!command=\hskip.25em\relax]
+\setuplistalternative[b][\c!distance=5em,\c!width=2em,\c!stretch=10em,\c!command=\hfill]
+\setuplistalternative[c][\c!distance=5em,\c!width=0pt,\c!stretch=10em,\c!command=\hskip.5em\listdots\hskip.5em\relax]
+
+\def\listdots{\leaders\hbox to .5em{\hss.\hss}\hfill}
+
+\setvalue{\??li\c!alternative}{\getvalue{\??li\c!alternative b}}
+\getvalue{\??li\c!alternative}
+
+\def\dosetuplist[#1][#2]% slow -)
+ {\def\docommand##1{\getparameters[\??li##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+\def\setuplist
+ {\dodoubleargument\dosetuplist}
+
+\def\dodefinelist[#1][#2][#3]%
+ {\presetlocalframed[\??li#1]% still inefficient (will change when we redu core-rul)
+ \doifassignmentelse{#2}
+ {\getparameters[\??li#1][\s!parent=\??li,#2]}
+ {\doifelsenothing{#2}
+ {\getparameters[\??li#1][\s!parent=\??li]}
+ {\getparameters[\??li#1][\s!parent=\??li#2,#3]}}}
+
+\def\setuplists % new, but not for users (hardly handy)
+ {\dodoubleargument\getparameters[\??li]}
+
+\setuplists
+ [\c!height=\v!broad,
+ \c!depth=\v!broad,
+ \c!offset=0.25em,
+ %\c!maxwidth=,
+ \c!state=\v!start,
+ \c!coupling=\v!off,
+ \c!criterium=\v!local,
+ \c!number=0,
+ \c!width=3em,
+ \c!alternative=\c!b,
+ \c!style=\v!normal,
+ \c!textstyle=\listparameter\c!style,
+ \c!numberstyle=\listparameter\c!style,
+ \c!pagestyle=\listparameter\c!style,
+ %\c!color=,
+ \c!textcolor=\listparameter\c!color,
+ \c!numbercolor=\listparameter\c!color,
+ \c!pagecolor=\listparameter\c!color,
+ \c!numbercommand=\listnumbercommand,
+ \c!textcommand=\listtextcommand,
+ \c!pagecommand=\listpagecommand,
+ \c!pagenumber=\v!yes,
+ \c!headnumber=\v!yes,
+ %\c!pageboundaries=,
+ \c!margin=\!!zeropoint,
+ %\c!aligntitle=,
+ %\c!before=,
+ %\c!after=,
+ %\c!inbetween=,
+ %\c!symbol=,
+ \c!interaction=\v!sectionnumber,
+ \c!label=\v!no,
+ \c!distance=\!!zeropoint,
+ \c!limittext=\@@kolimittext,
+ %\c!sectionseparatorset=,
+ %\c!sectionconversionset=,
+ %\c!sectionstopper=,
+ %\c!sectionset=,
+ %\c!sectionsegments=,
+ %\c!prefix=\v!no,
+ %\c!prefixseparatorset=,
+ %\c!prefixconversionset=,
+ %\c!prefixstopper=.,
+ %\c!prefixset=,
+ %\c!prefixsegments=,
+ %\c!pageseparatorset=,
+ %\c!pageconversionset=,
+ %\c!pagestopper=,
+ %\c!expansion=,
+ % \c!prefixconnector=., % maybe inherit from setupheads
+ % \c!pageprefix=\v!no, % is unset, inherits
+ % \c!pageprefixconnector=\listparameter\c!prefixconnector,
+ ]% \c!pagesegments=2:2]
+
+\def\definelist
+ {\dotripleempty\dodefinelist}
+
+\def\placelist
+ {\dodoubleempty\doplacelist}
+
+\def\placerawlist
+ {\dodoubleempty\doplacerawlist}
+
+\def\dobeginoflist
+ {\begingroup
+ \startpacked[\v!blank]}
+
+\def\doendoflist
+ {\stoppacked
+ \endgroup}
+
+\def\doplacelist[#1][#2]%
+ {\dobeginoflist
+ \doplacerawlist[#1][#2]%
+ \doendoflist}
+
+\newtoks\everystructurelist
+
+% writing to lists
+
+\def\writetolist[#1]{\gobbletwoarguments}
+\let\dowritetolist \gobblefourarguments
+\let\dodowritetolist\gobblefourarguments
+
+\def\writebetweenlist[#1]#2%
+ {\doif{\namedlistparameter{#1}\c!state}\v!start{\structurelistinject[#1][command][command={#2}]}}
+
+\def\writedatatolist
+ {\dodoubleargument\dowritedatatolist}
+
+\def\dowritedatatolist[#1][#2]%
+ {\doif{\namedlistparameter{#1}\c!state}\v!start{\structurelistinject[#1][userdata][#2]}}
+
+\def\writetolist[#1]#2#3%
+ {\doif{\namedlistparameter{#1}\c!state}\v!start{\structurelistinject[#1][simple][first={#2},second={#3}]}}
+
+\installstructurelistprocessor{simple}
+ {\dodolistelement
+ \currentlist
+ \structurelistlocation
+ \structurelistfirst
+ \structurelistsecond
+ \structurelistpagenumber
+ \structurelistrealpagenumber}
+
+% % %
+
+\def\doplacerawlist[#1][#2]% listreferences will be redone
+ {\begingroup
+ \dosetuplist[#1][#2]%
+ \edef\currentlist{\firststructureelementinlist{#1}}%
+ \the\everystructurelist
+ \doif{\listparameter\c!coupling}\v!on{\startlistreferences{#1}}%
+ \placestructurelist{#1}{\listparameter\c!criterium}{\listparameter\c!number}%
+ \stoplistreferences
+ \endgroup
+ \dosetlistmode}
+
+\def\dosetlistmode % utilitydone will disappear
+ {\ifcase\structurelistsize\relax
+ \utilitydonefalse \resetsystemmode\v!list
+ \else
+ \utilitydonetrue \setsystemmode \v!list
+ \fi}
+
+\def\systemsuppliedchapter {\getvalue{\v!chapter}} % brrr
+\def\systemsuppliedtitle {\getvalue{\v!title}} % brrr
+
+\def\dodocompletelist[#1][#2][#3]% enkelvoud, meervoud, instellingen
+ {\normalexpanded{\noexpand\systemsuppliedtitle[#2]{\noexpand\headtext{#2}}}% expansion needed for v! vs french !
+ \doplacelist[#1][#3]}
+
+\def\docompletelist[#1][#2]%
+ {\dodocompletelist[#1][#1][#2]}
+
+\def\completelist
+ {\dodoubleempty\docompletelist}
+
+\def\listelements {} % list of page breaks
+\def\listnumbercommand #1{#1} % no strut due to interactive version
+\def\listtextcommand #1{\begstrut#1\endstrut}
+\def\listpagecommand #1{\strut#1}
+
+\def\doassigndimen#1#2#3%
+ {\doifinsetelse{#2}{\v!fit,\v!broad}{#1=#3}{#1=#2}\relax}
+
+\def\listsymbol[#1]#2%
+ {\begingroup
+ \edef\currentlist{#1}%
+ \edef\currentlistnumber{#2}%
+ \currentlistsymbol
+ \endgroup}
+
+% Beware, the list symbol macro gets an argument passed, i.e. when this
+% argument is not picked up, the symbol becomes a kind of prefix.
+
+% for historical reasons we're stuck to symbols, so in order to generalize,
+% we have to hook it into the symbol handler; we need a beter clean up later
+%
+% < 2005
+%
+% \def\dosetlistsymbol % #1
+% {\executeifdefined{listsymbol@\listparameter\c!symbol}\listsymbol@default} % {#1}
+%
+% >= 2005
+%
+% at this symbol level, we have access to the raw 'number' in
+% \currentlistnumber
+
+\definesymbol[\v!list][\v!none ][\listsymbol@none ]
+\definesymbol[\v!list][\v!one ][\listsymbol@one ]
+\definesymbol[\v!list][\v!two ][\listsymbol@two ]
+\definesymbol[\v!list][\v!three ][\listsymbol@three ]
+\definesymbol[\v!list][\s!default][\listsymbol@default]
+\definesymbol[\v!list][\s!unknown][\listsymbol@unknown]
+
+\def\currentlistsymbol
+ {\doifinsymbolsetelse\v!list{\listparameter\c!symbol}
+ {\directsymbol\v!list{\listparameter\c!symbol}}
+ {\directsymbol\v!list\s!default}}
+
+\def\listsymbol@none
+ {\doassigndimen\scratchdimen{\listparameter\c!width}{1.5em}%
+ \hbox to \scratchdimen{}}
+
+\def\listsymbol@one
+ {\strut$\bullet$}
+
+\def\listsymbol@two
+ {\vrule\!!width1em\!!height1ex\!!depth\zeropoint}
+
+\def\listsymbol@three
+ {\begingroup
+ \doassigndimen{\dimen0}{\listparameter\c!width }{1.5em}%
+ \doassigndimen{\dimen2}{\listparameter\c!height}{1ex}%
+ \doassigndimen{\dimen4}{\listparameter\c!depth }\zeropoint
+ \vrule\!!width\dimen0\!!height\dimen2\!!depth\dimen4%
+ \endgroup}
+
+\def\listsymbol@default
+ {% prefix = no, none, yes
+ \strut
+ \doif{\listparameter\c!label}\v!yes{\leftlabeltext\currentlist}%
+ \currentlistnumber
+ \listparameter\c!stopper
+ \doif{\listparameter\c!label}\v!yes{\rightlabeltext\currentlist}}
+
+\def\listsymbol@default
+ {% todo:
+ % prefix=no (first gone)|none (all gone)|yes
+ % number=no|yes
+ \strut
+ \doifelse{\listparameter\c!label}\v!yes
+ {\leftlabeltext\currentlist
+ \currentlistnumber
+ \listparameter\c!stopper
+ \rightlabeltext\currentlist}
+ {\currentlistnumber
+ \listparameter\c!stopper}}
+
+\def\listsymbol@unknown
+ {\listparameter\c!symbol}
+
+% so far for list symbols
+
+\def\@@dodolistelement{dodolistelement}
+
+\def\dosomelistelement#1#2#3{#1 #2 #3}
+
+\setvalue{\@@dodolistelement a}{\let\dosomelistelement\dodofixdlistelementABC}
+\setvalue{\@@dodolistelement b}{\let\dosomelistelement\dodofixdlistelementABC}
+\setvalue{\@@dodolistelement c}{\let\dosomelistelement\dodofixdlistelementABC}
+\setvalue{\@@dodolistelement d}{\let\dosomelistelement\dodofixdlistelementD}
+\setvalue{\@@dodolistelement e}{\let\dosomelistelement\dodofixdlistelementE}
+\setvalue{\@@dodolistelement f}{\let\dosomelistelement\dodofixdlistelementF}
+\setvalue{\@@dodolistelement g}{\let\dosomelistelement\dodofixdlistelementG}
+
+\setvalue{\@@dodolistelement\v!none }{\def\dosomelistelement{\dodofreevlistelement}}
+\setvalue{\@@dodolistelement\v!vertical }{\def\dosomelistelement{\dodofreevlistelement}}
+\setvalue{\@@dodolistelement\v!horizontal}{\def\dosomelistelement{\dodofreehlistelement}}
+\setvalue{\@@dodolistelement\v!command }{\let\dosomelistelement\dodocommandlistelement}
+
+% \setuplist
+% [section]
+% [alternative=MyListItem,
+% after=\blank,
+% before=\blank]
+%
+% \definelistplacement[MyListItem][none]#1#2#3%
+% {(#1) (#2) (#3)}
+
+\def\definelistplacement
+ {\dodoubleempty\dodefinelistplacement}
+
+\def\dodefinelistplacement[#1][#2]%
+ {\setvalue{\@@dodolistelement#1}%
+ {\doifelsenothing{#2}
+ {\getvalue{\@@dodolistelement\v!command}}%
+ {\executeifdefined{\@@dodolistelement#2}{\getvalue{\@@dodolistelement\v!command}}}%
+ \setvalue{\??li\currentlist\c!command}{\getvalue{\@@dodolistelement::#1}}}%
+ \setvalue{\@@dodolistelement::#1}}
+
+% don't mess arround with endgraf/grouping else we loose leftskip
+
+% \strippedcsname\dodolistelement
+
+\def\newlineinlist{\space}
+
+\let\currentlist\s!unknown
+
+\def\docurrentlistalternative
+ {\edef\currentlistalternative{\listparameter\c!alternative}%
+ \ifx\currentlistalternative\empty
+ [unknown list alternative]%
+ \else
+ \executeifdefined{\@@dodolistelement\currentlistalternative}{[unknown list alternative: \currentlistalternative]}%
+ \fi}
+
+\def\dodolistelement#1#2#3#4#5#6%
+ {\edef\currentlist{#1}%
+ \edef\currentlistnumber{#3}%
+ \docurrentlistalternative
+ %\showcomposition
+ \let\@@iawidth\!!zeropoint % moet boolean worden
+ \begingroup
+ \edef\listelements{\listparameter\c!pageboundaries}%
+ \normalexpanded{\noexpand\doifinset{#3}{\listelements}}
+ {\showmessage\m!systems{14}{#3}%
+ \page}%
+ \endgroup
+ \dontcomplain
+ %\setfullsectionnumber{\??li\currentlist}% todo
+ \dosomelistelement{#1}{#2}{#3}{#4}{#5}{#6}%
+ \global\utilitydonetrue} % ?
+
+\def\dodocommandlistelement#1#2#3#4#5#6%
+ {\doifdefinedelse{\??li#1\c!command}
+ {\listparameter\c!command{#3}{#4}{#5}}
+ {[\currentlist: #3 -- #4 -- #5]}}
+
+\def\dodofreelistelement#1#2#3#4#5#6#7#8%
+ {\def\makelistelement##1##2%
+ {\noindent % new and needed
+ \hbox
+ {\doifelse{\listparameter\c!interaction}{##1} % \??li ipv \??ia
+ {\setbox0\hbox{\showcontrastlocation{\??li\currentlist}{#6}{##2}}%
+ \linklisttoelement{#2}{#5}{#6}{\box0}}%{\copy0}}%
+ {##2}}}%
+ \listparameter\c!before% can be \hskip
+ \doifdefinedelse{\??li#1\c!command}
+ {\makelistelement{\listparameter\c!interaction}% this forces all
+ {\listparameter\c!command
+ {#3}% geen conversies etc
+ {#4}% geen conversies etc
+ {#5}}}% geen command
+ {#7%
+ \vbox
+ {\forgetall
+ \makelistelement\v!all
+ {\doif{\listparameter\c!headnumber}\v!yes
+ {\makelistelement\v!sectionnumber
+ {\donestedlistattributes\c!numberstyle\c!numbercolor
+ {\listparameter\c!numbercommand{\currentlistsymbol}}}}%
+ \makelistelement\v!text
+ {\donestedlistattributes\c!textstyle\c!textcolor
+ {\let\\=\newlineinlist
+ \dontconvertfont
+ \listparameter\c!textcommand{#4}}}%
+ \doif{\listparameter\c!pagenumber}\v!yes
+ {\doifsomething{#5}
+ {\makelistelement\v!pagenumber
+ {\donestedlistattributes\c!pagestyle\c!pagecolor
+ {\listparameter\c!pagecommand{#5}}}}}}}%
+ #8}%
+ \listparameter\c!after}
+
+\def\dodofreehlistelement#1#2#3#4#5#6%
+ {\dodofreelistelement{#1}{#2}{#3}{#4}{#5}{#6}
+ {\noindent}{}}
+
+\def\dodofreevlistelement#1#2#3#4#5#6% % \nointerlineskip needed,
+ {\dodofreelistelement{#1}{#2}{#3}{#4}{#5}{#6} % otherwise wrong spacing
+ {\ifvmode\nointerlineskip\fi} % at multi-line lists
+ {\ifvmode\nointerlineskip\fi\endgraf\allowbreak}} % test is saveguard
+
+% to be documented: align, hang
+
+\def\limitatedlistentry#1%
+ {\doifelsenothing{\listparameter\c!maxwidth}
+ {\listparameter\c!textcommand{#1}}
+ {\listparameter\c!textcommand
+ {\limitatetext
+ {#1}%
+ {\listparameter\c!maxwidth}%
+ {\splitsymbol{\listparameter\c!limittext}}}}}
+
+\def\dodofixdlistelementABC#1#2#3#4#5#6% weeden
+ {\endgraf
+ \leftskip\listparameter\c!margin% na de \endgraf !
+ \listparameter\c!before
+ \!!widthc\listparameter\c!distance
+ \doifelse{\listparameter\c!width}\v!fit
+ {\!!widtha\zeropoint}
+ {\doifelsenothing{#3}
+ {\doifelse{\listparameter\c!aligntitle}\v!yes
+ {\!!widtha\zeropoint
+ \!!widthc\zeropoint}
+ {\!!widtha\listparameter\c!width}}
+ {\!!widtha\listparameter\c!width}}%
+ \getvalue{\??li\c!alternative\listparameter\c!alternative}%
+ \endgraf
+ \def\makelistelement##1##2%
+ {\doifelse{\listparameter\c!interaction}{##1}
+ {\setbox0\hbox{\showcontrastlocation\??ia{#6}{##2}}%
+ \linklisttoelement{#2}{#5}{#6}{\box0}}%{\copy0}}%
+ {\hbox{##2}}}%
+ \doif{\listparameter\c!interaction}\v!text % not supported ! ! ! ! ! ! text == all
+ {\setlistparameter\currentlist\c!interaction\v!all}%
+ % \dontleavehmode % new, else no margin, but wrong, better (else \indent as well):
+ \noindent
+ \makelistelement\v!all
+ {\setlocalhsize
+ \hsize\localhsize
+ \hbox to \hsize
+ {\forgetall
+ \dosetlistattributes\c!style\c!color
+ \!!widthb\hsize
+ \doifelse{\listparameter\c!headnumber}\v!yes
+ {\setbox2\hbox \ifdim\!!widtha>\zeropoint to \!!widtha \fi
+ {\makelistelement\v!sectionnumber
+ {\donestedlistattributes\c!numberstyle\c!numbercolor
+ {\listparameter\c!numbercommand{\currentlistsymbol}}%
+ \hfill}}}
+ {\!!widtha\zeropoint
+ \!!widthc\zeropoint
+ \setbox2\hbox{}}%
+ \setbox4\hbox
+ {\doif{\listparameter\c!pagenumber}\v!yes
+ {\doifsomething{#5} % \listwidth is new ; temp hack
+ {\hbox \ifdim\listwidth>\zeropoint to \listwidth\fi
+ {\hfill
+ \makelistelement\v!pagenumber
+ {\donestedlistattributes\c!pagestyle\c!pagecolor
+ {\listparameter\c!pagecommand{#5}}}}}}}%
+ \vbox
+ {\hsize\!!widthb
+ \setupalign[\listparameter\c!align]%
+ \ifdim\!!widtha<\hsize
+ \hangindent\wd2
+ \dimen2=\!!widthc % \listparameter\c!distance
+ \advance\hangindent \dimen2
+ \hangafter\plusone
+ \doif{\listparameter\c!hang}\v!no{\hangafter\zerocount}%
+ \ifdim\wd4=\zeropoint % \ifvoid4
+ % we kunnen gewoon afbreken aan het eind
+ \else
+ \ifdim\listskip>\zeropoint\relax
+ \rightskip\listskip\!!plus\liststretch\relax
+ \parfillskip-\rightskip
+ \fi
+ \fi
+ \else
+ \dimen2\zeropoint
+ \fi
+ \parindent\zeropoint\relax
+ \leavevmode
+ \box2\relax
+ \hskip\dimen2
+ \bgroup
+ \donestedlistattributes\c!textstyle\c!textcolor
+ {\let\\=\newlineinlist
+ \dontconvertfont
+ %\listparameter\c!textcommand{#4}}%
+ \limitatedlistentry{#4}}%
+ %\carryoverpar % new otherwise wrong linespacing
+ \egroup
+ \ifdim\wd4=\zeropoint\relax % \ifvoid4
+ % \ifdim\!!widtha<\hsize \hfill\strut \fi % spoils align
+ \else
+ \nobreak\listfill
+ \box4\relax
+ \relax
+ \fi}%
+ \hss}}% new
+ \endgraf % new, else problems with nointerlinespace and prevdepth
+ \nointerlineskip % anders verkeerde spatiering bij multi-line
+ \endgraf
+ \allowbreak
+ \listparameter\c!after}
+
+% % example from the context list
+%
+% \setuphead [part] [page=right,placehead=yes]
+% \setuplist [chapter] [alternative=d,before=\blank,after=\blank]
+% \setuplist [part] [before=\blank,after=\blank]
+%
+% \starttext
+% \startnarrower[2*right] \placecontent \stopnarrower
+% \blank[4*big]
+% \startsetups chapter
+% \blank \startnarrower[3*middle] \placecontent[criterium=local] \stopnarrower
+% \stopsetups
+% \placelist[part][criterium=text,after=\setups{chapter}]
+%
+% \part{First part} \chapter{Chapter one} \chapter{Chapter two}
+% \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
+% \part{Second part} \chapter{Chapter one} \chapter{Chapter two}
+% \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
+% \part{Third part} \chapter{Chapter one} \chapter{Chapter two}
+% \chapter{Chapter three} \chapter{Chapter four} \chapter{Chapter five}
+% \stoptext
+
+% overrulen interactie kan sneller, bv door hulpconstanten
+% te gebruiken en die te letten
+
+\def\dodofixdlistelementD#1#2#3#4#5#6%
+ {%\leftskip=\listparameter\c!margin
+ \ifvmode
+ \advance\leftskip\listparameter\c!margin% AANGEPAST
+ \fi
+ \bgroup
+ \ifvmode
+ \noindent\leavevmode % leavevmode ? ? ?
+ \fi
+ \doif{\listparameter\c!interaction}\v!text % not supported
+ {\setlistparameter\currentlist\c!interaction\v!sectionnumber}%
+ \doif{\listparameter\c!interaction}\v!all % not supported
+ {\setlistparameter\currentlist\c!interaction\v!sectionnumber}%
+ \def\makelistelement##1##2%
+ {\doifelse{\listparameter\c!interaction}{##1}
+ {\setbox0\hbox{\showcontrastlocation\??ia{#6}{##2}}%
+ \linklisttoelement{#2}{#5}{#6}{\box0}}%{\copy0}}%
+ {\hbox{##2}}}%
+ \setbox4\hbox
+ {\doif{\listparameter\c!pagenumber}\v!yes
+ {\doifsomething{#5}
+ {\makelistelement\v!pagenumber
+ {\donestedlistattributes\c!pagestyle\c!pagecolor
+ {\listparameter\c!pagecommand{#5}}}}}}%
+ \doif{\listparameter\c!headnumber}\v!yes
+ {\donetrue
+ \doifnothing{#3}{\doifnothing{\listparameter\c!symbol}\donefalse}%
+ % == \doifnothing{#3\listparameter\c!symbol}\donefalse
+ \ifdone
+ \hbox
+ {\listparameter\c!left
+ \makelistelement\v!sectionnumber
+ {\donestedlistattributes\c!numberstyle\c!numbercolor
+ {\listparameter\c!numbercommand{\currentlistsymbol}}}%
+ \listparameter\c!right
+ \hskip.5em}%
+ \nobreak
+ \fi}%
+ \tolerance3500 % niet zomaar veranderen
+ \donestedlistattributes\c!textstyle\c!textcolor
+ {\let\\=\newlineinlist
+ \dontconvertfont
+ %\listparameter\c!textcommand{#4}}%
+ \limitatedlistentry{#4}}%
+ \ifvoid4\else
+ \nobreak
+ \hskip.75em\relax
+ \nobreak
+ \box4
+ \fi
+ \dimen0=\listparameter\c!distance\relax
+ \ifdim\dimen0<1em\relax
+ \hskip1em\!!plus1em\!!minus.25em\relax
+ \else
+ \hskip\dimen0\!!plus.5\dimen0\!!minus.25\dimen0\relax
+ \fi
+ \egroup}
+
+\def\dodofixdlistelementE#1%
+ {\dodofixdlistelementEFG
+ {\setupinteraction[\c!strut=\v!no]}
+ {\localframed[\??li\currentlist][\c!depth=\!!zeropoint,\c!color=]}
+ {}}
+
+\def\dodofixdlistelementF#1%
+ {\dodofixdlistelementEFG
+ {}
+ {\dosetraggedhbox{\listparameter\c!align}\raggedbox}
+ {}}
+
+\def\dodofixdlistelementG#1%
+ {\dodofixdlistelementEFG
+ {}
+ \midaligned
+ {}}
+
+\def\dodofixdlistelementEFG#1#2#3#4#5#6#7#8%
+ {\noindent
+ \bgroup
+ \def\makelistelement##1##2% isolated by Wolfgang Schuster
+ {\doifelse{\listparameter\c!interaction}{##1}
+ {#2{##2}}
+ {\setbox0\hbox{#2{\showcontrastlocation\??ia{#8}{##2}}}%
+ \linklisttoelement{#4}{#7}{#8}{\box0}}}%
+ \makelistelement\v!no
+ {\let\\=\newlineinlist
+ #1% in case E nils the strut (still needed?)
+ \dosetlistattributes\c!style\c!color
+ \ignorespaces\dontconvertfont\setstrut
+ \begstrut
+ \limitatedlistentry{#6}%
+ \endstrut}%
+ \egroup
+ \par
+ \listparameter\c!inbetween}
+
+\def\listlength{\utilitylistlength}
+\def\listwidth {\utilitylistwidth}
+\def\listheight{\utilitylistheight}
+
+\def\utilitylistlength {0}
+\def\utilitylistwidth {0pt} % no longer supported
+\def\utilitylistheight {0pt} % no longer supported
+
+\def\dodeterminelistcharacteristics[#1][#2]%
+ {\begingroup
+ \dosetuplist[#1][#2]%
+ \edef\currentlist{\firststructureelementinlist{#1}}%
+ \the\everystructurelist
+ \analysestructurelist{#1}{\listparameter\c!criterium}{\listparameter\c!number}%
+ \xdef\utilitylistlength{\structurelistsize}%
+ \endgroup
+ \dosetlistmode}
+
+\def\determinelistcharacteristics
+ {\dodoubleempty\dodeterminelistcharacteristics}
+
+\def\combinedlistparameter#1{\csname\??ih\currentcombinedlist#1\endcsname}
+
+\def\setupcombinedlist
+ {\dodoubleargument\dosetupcombinedlist}
+
+\def\dosetupcombinedlist[#1][#2]%
+ {\getparameters[\??ih#1][#2]%
+ \edef\currentcombinedlist{#1}%
+ \normalexpanded{\noexpand\setuplist[\combinedlistparameter\c!list]}[#2]}
+
+\def\definecombinedlist
+ {\dotripleempty\dodefinecombinedlist}
+
+\def\dodefinecombinedlist[#1][#2][#3]%
+ {\getparameters
+ [\??ih#1]
+ [\c!criterium=\v!local,\c!number=0,\c!list={#2},#3]%
+ \setvalue{\e!setup#1\e!endsetup}{\dodoubleempty\dosetupcombinedlist[#1]}%
+ \setvalue{\e!place#1}{\dodoubleempty\doplacecombinedlist[#1]}%
+ \setvalue{\e!complete#1}{\dodoubleempty\docompletecombinedlist[#1]}}
+
+\def\placecombinedlist
+ {\dodoubleempty\doplacecombinedlist}
+
+\def\doplacecombinedlist[#1][#2]% we can move much of the analysis to lua
+ {\begingroup
+ % level is no longer supported
+ \def\currentcombinedlist{#1}%
+ \getparameters[\??ih#1][#2]%
+ \edef\combinedlist{\combinedlistparameter\c!list}%
+ \the\everystructurelist
+ \doif{\combinedlistparameter\c!coupling}\v!on{\startlistreferences{#1}}%
+ \dobeginoflist
+ \normalexpanded{\noexpand\dosetuplist[\combinedlist][#2]}%
+ \placestructurelist{\combinedlist}{\combinedlistparameter\c!criterium}{\combinedlistparameter\c!number}%
+ \doendoflist
+ \stoplistreferences
+ \endgroup
+ \dosetlistmode}
+
+\def\docompletecombinedlist[#1][#2]%
+ {\normalexpanded{\noexpand\systemsuppliedtitle[#1]{\noexpand\headtext{#1}}}% expansion due to v! vs french !
+ \doplacecombinedlist[#1][#2]}
+
+% lists that have a number/title are kind of generic and can share code
+
+\installstructurelistprocessor{number+title}
+ {\dodolistelement
+ \currentlist
+ \structurelistlocation
+ \structurelistgenericnumber
+ \structurelistgenerictitle
+ \structurelistpagenumber
+ \structurelistrealpagenumber}
+
+\def\structurelistgenerictitle
+ {\ctxlua{structure.lists.title("\currentlist",\currentlistindex)}}
+
+\def\structurelistgenericnumber{\ctxlua{
+ structure.lists.prefixednumber("\currentlist",\currentlistindex, {
+ prefix = "\listparameter\c!prefix",
+ separatorset = "\listparameter\c!prefixseparatorset",
+ conversionset = "\listparameter\c!prefixconversionset",
+ stopper = \!!bs\listparameter\c!prefixstopper\!!es,
+ set = "\listparameter\c!prefixset",
+ segments = "\listparameter\c!prefixsegments",
+ connector = \!!bs\listparameter\c!prefixconnector\!!es,
+ },
+ {
+ separatorset = "\listparameter\c!numberseparatorset",
+ conversionset = "\listparameter\c!numberconversionset",
+ stopper = \!!bs\listparameter\c!numberstopper\!!es,
+ segments = "\listparameter\c!numbersegments",
+ } )}}
+
+% new and yet undocumented (used in cocoa qa), temporarily disabled in mkiv
+%
+% \setupremaininglistlength
+% [left=\hss nog~,right=~ingangen]
+%
+% \resetremaininglistlength
+% [section][settings]
+%
+% \placelist
+% [section]
+% [before=\showremaininglistlength]
+%
+% \dorecurse{100}{\section{hans}}
+%
+% \definesystemvariable {ll} % ListLength
+%
+% \def\setupremaininglistlength[#1]%
+% {\getparameters[\??ll][#1]%
+% \globallet\listlengthcounter\!!zerocount}
+%
+% \setupremaininglistlength
+% [\c!left=\hss,\c!right=,\c!number=\v!yes,
+% \c!before=\blank,\c!after=\page,
+% \c!style=\v!smallnormal,\c!color=]
+%
+% \def\resetremaininglistlength
+% {\dodoubleempty\doresetremaininglistlength}
+%
+% \def\doresetremaininglistlength[#1][#2]%
+% {\determinelistcharacteristics[#1][#2]%
+% \xdef\listlengthcounter{\number\utilitylistlength}}
+%
+% \def\showremaininglistlength
+% {\bgroup
+% \ifnum\listlengthcounter>\plusone
+% \setbox\scratchbox\vbox
+% {\@@llbefore\par\horizontalstrut\par\horizontalstrut\par\@@llafter}%
+% \scratchdimen\pagetotal
+% \advance\scratchdimen \ht\scratchbox
+% \advance\scratchdimen \dp\scratchbox
+% \ifdim\scratchdimen>\pagegoal
+% \@@llbefore
+% \nobreak\hbox to \hsize
+% {\doifnot\@@llnumber\v!yes{\let\listlengthcounter\empty}%
+% \doattributes\??ll\c!style\c!color{\@@llleft\listlengthcounter\@@llright}}
+% \@@llafter
+% \fi
+% \fi
+% \doglobal\decrement\listlengthcounter\relax
+% \egroup}
+
+\protect \endinput
diff --git a/tex/context/base/strc-mar.lua b/tex/context/base/strc-mar.lua
new file mode 100644
index 000000000..14eac8c2c
--- /dev/null
+++ b/tex/context/base/strc-mar.lua
@@ -0,0 +1,18 @@
+if not modules then modules = { } end modules ['strc-mar'] = {
+ version = 1.001,
+ comment = "companion to strc-mar.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+structure.marks = structure.marks or { }
+
+function structure.marks.title(tag,n)
+ structure.lists.savedtitle(tag,n,"mark")
+end
+
+function structure.marks.number(tag,n) -- no spec
+ -- no prefix (as it is the prefix)
+ structure.lists.savednumber(tag,n)
+end
diff --git a/tex/context/base/strc-mar.tex b/tex/context/base/strc-mar.tex
new file mode 100644
index 000000000..8dbbb232c
--- /dev/null
+++ b/tex/context/base/strc-mar.tex
@@ -0,0 +1,493 @@
+%D \module
+%D [ file=strc-mar,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Markings,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Markings}
+
+\registerctxluafile{strc-mar}{1.001}
+
+\unprotect
+
+%D Old stuff.
+
+\newtoks \listofmarks
+
+\let \getmarks \gobbleoneargument
+\let \getallmarks \relax
+\let \getsplitmarks \gobbleoneargument
+\let \getallsplitmarks \relax
+
+%D \macros
+%D {expandmarks}
+%D
+%D We can force expansion of marks with the following switch.
+
+% Synchronizing marks is a rather tricky and messy business. When
+% setting a mark, a node is added to the list in order for to \TEX\
+% be able to figure out the 3 current marks when a page is made
+% (last mark on previous page, first on current page, last on
+% current page; in \LUATEX\ we might at one point have the first on
+% the next page as well).
+
+% Resetting a mark is not easy. An empty one will not erase the last
+% one on the previous page for instance. In \LUATEX\ we can clear a
+% marks state register with \type {\clearmarks} but since this is an
+% immediate operation it might have unwanted side effects when \TEX\
+% has collected several pages of text and finishing off these pages
+% uses marks.
+
+% In \MKIV\ we provide a model that permits some control over the
+% way marks are used. It is not entirely compatible with \MKII\ but
+% in practice this is not a real problem. Quality has a price.
+
+% In fact we define multiple marks per visible mark and define
+% additional ones on the fly. This has some price in terms of used
+% mark registers but given the way that we fill marks in \MKIV\
+% their accumulated content is not really the issue. Also,
+% periodically we cleanup any leftovers.
+
+\newif\ifexpandmarks \expandmarkstrue
+
+\def\marksomecs #1#2{\csname\string#1:m:\number#2\endcsname}
+\def\markautocs #1{\csname\string#1:m:\number\csname\string#1:s\endcsname\endcsname}
+\def\markmaincs #1{\csname\string#1:m\endcsname}
+\def\markresetcs #1{\csname\string#1:r\endcsname}
+\def\markstatecs #1{\csname\string#1:s\endcsname}
+\def\markcurrentcs#1{\csname\string#1:c\endcsname}
+\def\marktokscs #1{\csname\string#1:t\endcsname}
+
+\def\renewmarks#1%
+ {\ifx#1\relax
+ % \writestatus\m!systems{defining low level mark: \string#1}%
+ \newmarks#1%
+ \else
+ \clearmarks#1%
+ \fi}
+
+\def\definenewmark#1%
+ {\ifcsname\string#1:m\endcsname\else
+ \@EA\@EA\@EA\newcount \markstatecs #1\global\markstatecs#1\plusone
+ \@EA\@EA\@EA\renewmarks\markautocs #1%
+ \@EA\@EA\@EA\renewmarks\markmaincs #1%
+ \@EA\@EA\@EA\renewmarks\markresetcs #1%
+ \@EA\@EA\@EA\newtoks \marktokscs #1%
+ \@EA\@EA\@EA\let \markcurrentcs#1\empty
+ \listofmarks\expandafter{\the\listofmarks\checkmark#1}%
+ \fi}
+
+\long\def\setmark#1#2% marks expand
+ {\@EA\@EA\@EA\xdef \markcurrentcs#1{\ifexpandmarks#2\else\normalunexpanded{#2}\fi}%
+ \marks\markautocs #1{\ifexpandmarks#2\else\normalunexpanded{#2}\fi}% we could expand current one level
+ \marks\markmaincs #1{\ifexpandmarks#2\else\normalunexpanded{#2}\fi}% we could expand current one level
+ \marks\markresetcs #1{\number\markstatecs#1}}
+
+\def\resetmark#1%
+ {\global\advance\markstatecs#1\plusone
+ \@EA\@EA\@EA\glet\markcurrentcs#1\empty
+ \@EA\@EA\@EA\renewmarks\markautocs#1%
+ \the\marktokscs#1\relax}
+
+\def\addmarkreset#1#2%
+ {\global\marktokscs#2\@EA{\the\marktokscs#2\resetmark#1}}
+
+% already there: \prependtoks \getallmarks \to \everybeforepagebody
+%
+% \def\getallmarks{\the\listofmarks}
+
+\let\checkmark\gobbleoneargument
+
+\prependtoks \clearmarkswhenemptypage \to \everybeforepagebody
+
+\def\clearmarkswhenemptypage
+ {\iffalse % check if page is empty
+ \clearallmarks
+ \fi}
+
+\def\clearallmarks
+ {\let\checkmark\clearmarkchain
+ \the\listofmarks
+ \let\checkmark\gobbleoneargument}
+
+\def\clearmarkchain#1%
+ {\@EA\@EA\@EA\clearmarks\markmaincs#1%
+ \@EA\@EA\@EA\clearmarks\markresetcs#1%
+ \@EA\doclearmarkchain\@EA{\number\csname\string#1:s\endcsname}#1%
+ \@EA\@EA\@EA\glet\markcurrentcs#1\empty
+ \global\markstatecs#1\plusone}
+
+\def\doclearmarkchain#1#2%
+ {\@EA\@EA\@EA\clearmarks\marksomecs#1{#2}%
+ \@EA\doclearmarkchain\@EA#1\@EA{\number\numexpr#2+\minusone}}
+
+% Fetching (expandable versions, so no intermediate counter):
+
+\def\currenttopmarknumber #1{\number0\topmarks \markresetcs#1}
+\def\currentfirstmarknumber#1{\number0\firstmarks\markresetcs#1}
+\def\currentbotmarknumber #1{\number0\botmarks \markresetcs#1}
+
+\def\checkedcurrentmarkrange#1{[\currenttopmarknumber#1,\currentfirstmarknumber#1,\currentbotmarknumber#1]}
+
+\def\checkedcurrentmarks{\markcurrentcs} % #1 shared current mark
+
+\let\currentsplittopmarknumber\currenttopmarknumber
+\let\normalsplittopmarks \normaltopmarks
+
+\def\uncheckedautotopmark {\normaltopmarks \markautocs} % #1
+\def\uncheckedautofirstmark {\normalfirstmarks \markautocs} % #1
+\def\uncheckedautobotmark {\normalbotmarks \markautocs} % #1
+\def\uncheckedautosplittopmark {\normalsplittopmarks \markautocs} % #1
+\def\uncheckedautosplitfirstmark {\normalsplitfirstmarks\markautocs} % #1
+\def\uncheckedautosplitbotmark {\normalsplitbotmarks \markautocs} % #1
+
+\def\uncheckedmaintopmark {\normaltopmarks \markmaincs} % #1
+\def\uncheckedmainfirstmark {\normalfirstmarks \markmaincs} % #1
+\def\uncheckedmainbotmark {\normalbotmarks \markmaincs} % #1
+\def\uncheckedmainsplittopmark {\normalsplittopmarks \markmaincs} % #1
+\def\uncheckedmainsplitfirstmark {\normalsplitfirstmarks\markmaincs} % #1
+\def\uncheckedmainsplitbotmark {\normalsplitbotmarks \markmaincs} % #1
+
+\def\checkedpagetopmarks #1{\ifcase\currentbotmarknumber #1\else\normaltopmarks \marksomecs#1{\currentbotmarknumber #1}\fi}
+\def\checkedpagefirstmarks #1{\ifcase\currentbotmarknumber #1\else\normalfirstmarks \marksomecs#1{\currentbotmarknumber #1}\fi}
+\def\checkedpagebotmarks #1{\ifcase\currentbotmarknumber #1\else\normalbotmarks \marksomecs#1{\currentbotmarknumber #1}\fi}
+\def\checkedpagesplittopmarks #1{\ifcase\currentsplitbotmarknumber #1\else\normalsplittopmarks \marksomecs#1{\currentsplitbotmarknumber #1}\fi}
+\def\checkedpagesplitfirstmarks#1{\ifcase\currentsplitbotmarknumber #1\else\normalsplitfirstmarks\marksomecs#1{\currentsplitbotmarknumber #1}\fi}
+\def\checkedpagesplitbotmarks #1{\ifcase\currentsplitbotmarknumber #1\else\normalsplitbotmarks \marksomecs#1{\currentsplitbotmarknumber #1}\fi}
+
+\def\checkedfulltopmarks #1{\ifcase\currenttopmarknumber #1\else\normaltopmarks \marksomecs#1{\currenttopmarknumber #1}\fi}
+\def\checkedfullfirstmarks #1{\ifcase\currentfirstmarknumber #1\else\normalfirstmarks \marksomecs#1{\currentfirstmarknumber #1}\fi}
+\def\checkedfullbotmarks #1{\ifcase\currentbotmarknumber #1\else\normalbotmarks \marksomecs#1{\currentbotmarknumber #1}\fi}
+\def\checkedfullsplittopmarks #1{\ifcase\currentsplittopmarknumber #1\else\normalsplittopmarks \marksomecs#1{\currentsplittopmarknumber #1}\fi}
+\def\checkedfullsplitfirstmarks#1{\ifcase\currentsplitfirstmarknumber#1\else\normalsplitfirstmarks\marksomecs#1{\currentsplitfirstmarknumber#1}\fi}
+\def\checkedfullsplitbotmarks #1{\ifcase\currentsplitbotmarknumber #1\else\normalsplitbotmarks \marksomecs#1{\currentsplitbotmarknumber #1}\fi}
+
+% Interface macros:
+
+\def\getcurrentmark {\checkedcurrentmarks }
+\def\gettopmark {\checkedfulltopmarks }
+\def\getfirstmark {\checkedfullfirstmarks }
+\def\getbotmark {\checkedfullbotmarks }
+\def\getsplittopmark {\checkedfullsplittopmarks }
+\def\getsplitfirstmark {\checkedfullsplitfirstmarks}
+\def\getsplitbotmark {\checkedfullsplitbotmarks }
+
+\def\getbottommark {\getbotmark}
+\def\getsplitbottommark{\getsplitbotmark}
+
+%D Some of these will go away (in the process of rewriting).
+
+\let \newmark \definenewmark
+\let \newpersistentmark \newmarks
+\let \normalsetmark \setmark
+\let \rawnewmark \newmarks
+\let \rawdefinemark \newmarks
+\let \rawsetmark \normalmarks
+\let \rawgettopmark \normaltopmarks
+\let \rawgetfirstmark \normalfirstmarks
+\let \rawgetbotmark \normalbotmarks
+\let \rawgetsplitbotmark \normalsplitbotmarks
+\let \rawgetsplitfirstmark \normalsplitfirstmarks
+\let \rawgetsplittopmark \normalsplitfirstmarks
+
+\let \noninterferingmarks \relax % old color interference related hack
+
+%D Next comes the layer around the previous mechanism.
+%D
+%D Parameters
+
+\def\markingparameter #1#2{\csname\domarkingparameter{\??mk#1}#2\endcsname}
+\def\domarkingparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\@EA\domarkingparentparameter\csname#1\s!parent\endcsname#2\fi}
+\def\domarkingparentparameter#1#2{\ifx#1\relax\s!empty\else\domarkingparameter#1#2\fi}
+\def\markingcoupling #1{\ifcsname\??mk#1\c!coupling\endcsname\@EA\markingcoupling\csname\??mk#1\c!coupling\endcsname\else#1\fi}
+
+\let\mainmarking\markingcoupling % compatibility
+
+\def\doifelsemarking#1%
+ {\ifcsname\??mk#1\c!coupling\endcsname
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\dowithmarkcommandone#1#2% \command {mark}
+ {\expandafter#1\csname\??mk:\markingcoupling{#2}\endcsname}
+
+\def\dowithmarkcommandtwo#1#2#3% \command {mark} {mark}
+ {\expandafter#1\csname\??mk:\markingcoupling{#2}\expandafter\endcsname\csname\??mk:\markingcoupling{#3}\endcsname}
+
+\def\setupmarking
+ {\dodoubleargument\dosetupmarking}
+
+\def\dosetupmarking[#1][#2]%
+ {\def\docommand##1{\getparameters[\??mk##1][#2]}%
+ \processcommalist[#1]\docommand}
+
+%D The filtercommand key is used to hook in a filtering command. Users are
+%D adviced not to misuse this key.
+
+\getparameters
+ [\??mk]
+ [\c!expansion=\v!no, % saves a macro
+ \c!separator={\space\emdash\space},
+ \c!limittext=\@@kolimittext,
+ \c!filtercommand=\firstofoneargument,
+ \c!state=\v!start]
+
+\let\alldefinedmarks\empty
+
+\def\definemarking
+ {\dodoubleempty\dodefinemarking}
+
+\def\dodefinemarking[#1][#2]%
+ {\doifelsenothing{#2}\donormaldefinemarking\docloneddefinemarking[#1][#2]}
+
+\def\donormaldefinemarking[#1][#2]% #2 empty
+ {\ifcsname\??mk#1\s!parent\endcsname
+ % already defined
+ \else
+ \letgvalue{\??mk#1\s!parent}\??mk
+ \dowithmarkcommandone\newmark{#1}%
+ \doglobal\addtocommalist{#2}\alldefinedmarks
+ \ifproductionrun\showmessage\m!systems{13}{#1,[#1]}\fi
+ \fi}
+
+\def\docloneddefinemarking[#1][#2]%
+ {\ifcsname\??mk#1\s!parent\endcsname \else \ifcsname\??mk#2\s!parent\endcsname
+ \doifnot{#1}{#2}%
+ {\setxvalue{\??mk#1\s!parent}{\??mk#2}%
+ \setxvalue{\??mk#1\c!coupling}{#2}%
+ \ifproductionrun\showmessage\m!systems{13}{#1,[#2]}\fi}%
+ \fi \fi}
+
+\def\decouplemarking[#1]%
+ {\letbeundefined{\??mk#1\c!coupling}}
+
+\def\couplemarking[#1]#2[#3]% couple 1 to 2 (this macro is not really needed)
+ {\setvalue{\??mk#1\c!coupling}{#3}}
+
+\def\relatemarking[#1]#2[#3]% define 1 as child of 2
+ {\dowithmarkcommandtwo\addmarkreset{#1}{#3}}
+
+\def\definerawmarking[#1]%
+ {\dododefinemarking[#1][#1]%
+ \getgparameters[\??mk#1][\c!limittext=]} % global !
+
+% \decouplemarking[#1]% % no coupling with sections
+
+\def\fastresetmarker#1%
+ {\ifcsname\??mk#1\s!parent\endcsname
+ \dowithmarkcommandone\resetmark{#1}%
+ \fi}
+
+\def\fastresetmarkerlist[#1]%
+ {\normalexpanded{\noexpand\rawprocesscommalist[#1]}\fastresetmarker}
+
+\def\resetmarking
+ {\dosingleargument\doresetmarking}
+
+\def\doresetmarking[#1]%
+ {\processcommalist[#1]\fastresetmarker}
+
+%D Used elsewhere:
+
+\let\nomarking\empty
+
+%D Basic fetching:
+
+\letvalue{\??mk::\??mk::\v!previous}\firstoffourarguments
+\letvalue{\??mk::\??mk::\v!first }\secondoffourarguments
+\letvalue{\??mk::\??mk::\v!last }\thirdoffourarguments
+\letvalue{\??mk::\??mk::\v!current }\fourthoffourarguments
+
+\letvalue{\??mk\??mk\v!previous}\gettopmark
+\letvalue{\??mk\??mk\v!first }\getfirstmark
+\letvalue{\??mk\??mk\v!last }\getbotmark
+\letvalue{\??mk\??mk\v!current }\getcurrentmark
+
+\letvalue{\??mk\??mk\v!column:\v!first}\getsplitfirstmark
+\letvalue{\??mk\??mk\v!column:\v!last }\getsplitbottommark
+
+\def\fetchmark[#1]#2[#3]% % expandable / never use \unexpanded
+ {\ifcsname\??mk::#1\endcsname % saved mark
+ \markingparameter{#1}\c!filtercommand{\csname\??mk::\??mk::#3\@EA\@EA\@EA\endcsname\csname\??mk::#1\endcsname}%
+ \else\ifcsname\??mk#1\s!parent\endcsname % real mark
+ \markingparameter{#1}\c!filtercommand{\expandafter\dowithmarkcommandone\csname\??mk\??mk#3\endcsname{#1}}%
+ \fi\fi}
+
+\def\fetchtwomarks[#1]%
+ {\dofetchtwomarks[#1][#1]}
+
+\def\fetchallmarks[#1]%
+ {\dofetchallmarks[#1][#1]}
+
+\def\dofetchtwomarks[#1][#2]% class class:tag
+ {\doifsomething{\fetchmark[#2][\v!first]}
+ {\fetchmark[#2][\v!first]%
+ \doifsomething{\fetchmark[#2][\v!last]}
+ {\doifnot{\fetchmark[#2][\v!first]}{\fetchmark[#2][\v!last]}
+ {\markingparameter{#1}\c!separator\fetchmark[#2][\v!last]}}}}
+
+\def\dofetchallmarks[#1][#2]%
+ {\doifsomething{\fetchmark[#2][\v!first]}
+ {\doifsomething{\fetchmark[#2][\v!previous]}
+ {\doifnot{\fetchmark[#2][\v!previous]}{\fetchmark[#2][\v!first]}
+ {\fetchmark[#2][\v!previous]\markingparameter{#1}\c!separator}}}%
+ \fetchtwomarks[#1][#2]}
+
+% \newtoks \everymarking
+
+% \def\Interesting{\doifmodeelse{*\v!marking}{Interesting}{Boring}}
+% \setupheadertexts[chapter]
+% \starttext
+% \chapter{This Is \Interesting}
+% \stoptext
+
+\def\markingnomarking#1{\splitsequence{\markingparameter{#1}\c!limittext}} % #2
+
+\def\dogetmarking[#1][#2][#3]%
+ {\doif{\markingparameter{#1}\c!state}\v!start
+ {\bgroup
+ \setsystemmode\v!marking
+ \the\everymarking
+ \def\nomarking{\markingnomarking{#1}}% just for good old times, might disappear
+ \ifthirdargument
+ \dodogetmarking{#3}{#1}{#1:#2}{#3}%
+ \else
+ \dodogetmarking{#2}{#1}{#1}{#2}%
+ \fi
+ \egroup}}
+
+\def\dodogetmarking#1#2#3#4% to be made faster
+ {\processaction % slow
+ [#1]
+ [ \v!both=>{\dofetchtwomarks[#2][#3]},
+ \v!all=>{\dofetchallmarks[#2][#3]},
+ \s!default=>{\fetchmark[#3][\v!first]},
+ \s!unknown=>{\fetchmark[#3][#4]}]}
+
+\def\nogetmarking[#1][#2][#3]%
+ {}
+
+\unexpanded\def\getmarking
+ {\dotripleargument\dogetmarking}
+
+\let\setsomemark\setmark
+
+\def\setmarking
+ {\dosingleargument\dosetmarking}
+
+\def\dosetmarking[#1]#2%
+ {\ifcsname\??mk#1\s!parent\endcsname
+ \begingroup
+ \doifelse{\markingparameter{#1}\c!expansion}\v!yes\expandmarkstrue\expandmarksfalse
+ \dowithmarkcommandone\setsomemark{#1}{#2}%
+ \endgroup
+ \fi}
+
+\let\marking\setmarking
+
+% to be adapted for mkiv:
+%
+% this version can be used when a page is built up in steps without
+% feedback of the otr'd list to the mvl (i.e.\ a page made of pages,
+% as in column sets where content is buffered)
+
+% reset at begin
+% preset before page
+% bubble in column
+% refresh at end
+
+% marks is a kind of toks, so maybe we need a low level \the\marks
+%
+% use \normalunexpanded here
+
+\def\refreshsavedmark[#1][#2]% mark tag (packing saves many hash entries)
+ {\setxvalue{\??mk::#1:#2}%
+ {{\@EA\ifx\csname\??mk::#1:pp\endcsname\relax
+ % empty
+ \else
+ \csname\??mk::#1:pp\endcsname
+ \fi}%
+ {\@EA\ifx\csname\??mk::#1:ff\endcsname\relax
+ \fetchmark[#1][\v!first]%
+ \else
+ \csname\??mk::#1:ff\endcsname
+ \fi}%
+ {\fetchmark[#1][\v!last]}%
+ {\fetchmark[#1][\v!current]}}%
+ \setxvalue{\??mk::#1:pp}{\fetchmark[#1][\v!first]}%
+ \letgvalue{\??mk::#1:ff}\relax
+ }
+
+\def\bubblesavedmark[#1][#2]% no packing (not now, maybe make a six-pack later)
+ {\@EA\ifx\csname\??mk::#1:ff\endcsname\relax
+ \setxvalue{\??mk::#1:ff}{\fetchmark[#1][\v!first]}%
+ \fi}
+
+\def\resetsavedmark[#1][#2]% mark tag
+ {\doifelsenothing{\fetchmark[#1][\v!previous]}
+ {\letgvalue{\??mk::#1:pp}\relax}
+ {\setxvalue{\??mk::#1:pp}{\fetchmark[#1][\v!previous]}}%
+ \doifelsenothing{\fetchmark[#1][\v!first]}
+ {\letgvalue{\??mk::#1:ff}\relax}
+ {\setxvalue{\??mk::#1:ff}{\fetchmark[#1][\v!first]}}%
+ \letgvalue{\??mk::#1:#2}\emptysavedmark}
+
+\def\presetsavedmark[#1][#2]% mark tag
+ {\letgvalue{\??mk::#1:#2}\emptysavedmark}
+
+\def\emptysavedmark{{}{}{}{}}
+
+% new (can be used in column sets)
+%
+% \getsavedmarking[M][previous]
+% \getsavedmarking[M][first]
+% \getsavedmarking[M][last]
+
+\def\getsavedmarking
+ {\dodoubleargument\dogetsavedmarking}
+
+\def\dogetsavedmarking[#1][#2]%
+ {\doifelse{#2}\v!previous
+ {\getmarking[#1][1][\v!previous]}
+ {\doifelse{#2}\v!first
+ {\getmarking[#1][1][\v!first]}
+ {\getmarking[#1][\v!last]}}}
+
+%D And then \unknown\ we had a chaptertitle packaged in a
+%D makeup environment. And we don't want to loose marks there!
+
+\newbox\collectedmarks
+
+\def\flushmarks % use with care to avoid empty pages
+ {\ifvoid\collectedmarks\else\unhbox\collectedmarks\fi}
+
+\def\postponemarks
+ {\let\setsomemark\postponemark}
+
+\def\postponemark#1#2%
+ {\global\setbox\collectedmarks\hbox{\unhbox\collectedmarks\setmark{#1}{#2}}}
+
+\protect \endinput
+
+% todo: make it work in balancing
+%
+% \definemarking[vers][]
+% \setupheadertexts
+% [\doiftext{\getmarking[vers][first]}
+% {\doiftextelse{\getmarking[vers][column:last]}
+% {\getmarking[vers][first] -- \getmarking[vers][column:last]}
+% {\getmarking[vers][first]}}]
+% \starttext
+% \startcolumns[n=2,balance=no]
+% \dorecurse{10}{\normalexpanded{\noexpand\marking[vers]{\recurselevel}} \recurselevel:\dorecurse{4}{\input ward } \endgraf}
+% \stopcolumns
+% \stoptext
diff --git a/tex/context/base/strc-mat.lua b/tex/context/base/strc-mat.lua
new file mode 100644
index 000000000..ba64bf9db
--- /dev/null
+++ b/tex/context/base/strc-mat.lua
@@ -0,0 +1,51 @@
+if not modules then modules = { } end modules ['strc-mat'] = {
+ version = 1.001,
+ comment = "companion to strc-mat.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+structure = structure or { }
+structure.helpers = structure.helpers or { }
+structure.lists = structure.lists or { }
+structure.lists.enhancers = structure.lists.enhancers or { }
+structure.sections = structure.sections or { }
+structure.helpers = structure.helpers or { }
+structure.formulas = structure.formulas or { }
+
+local lists = structure.lists
+local sections = structure.sections
+local floats = structure.floats
+local helpers = structure.helpers
+local formulas = structure.formulas
+
+-- maybe we want to do clever things with formulas, the store might go away
+
+local formuladata = { }
+
+function formulas.store(data)
+ formuladata[#formuladata+1] = data
+ tex.write(#formuladata)
+end
+
+function formulas.current()
+ return formuladata[#formuladata]
+end
+
+function helpers.formulanumber(data,spec)
+ if data then
+ local formulanumber = data.formulanumber
+ if formulanumber then
+ sections.number(data,spec,"formulanumber","formulanumber",'number')
+ end
+ end
+end
+
+function formulas.simplify(entry)
+ return helpers.simplify(table.copy(entry or formuladata[#formuladata]))
+end
+
+function lists.formulanumber(name,n,spec)
+ helpers.formulanumber(lists.result[n])
+end
diff --git a/tex/context/base/strc-mat.tex b/tex/context/base/strc-mat.tex
new file mode 100644
index 000000000..482426b48
--- /dev/null
+++ b/tex/context/base/strc-mat.tex
@@ -0,0 +1,933 @@
+%D \module
+%D [ file=strc-mat,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Math Numbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Math Numbering}
+
+\registerctxluafile{strc-mat}{1.001}
+
+\unprotect
+
+\definestructureconversionset[\v!formula][number,characters]
+
+\setupformulas
+ [%\c!way=\@@nrway,
+ %\c!blockway=,
+ %\c!sectionnumber=\@@nrsectionnumber,
+ %\c!conversion=\v!numbers,
+ \c!location=\v!right,
+ \c!left=(,
+ \c!right=),
+ %\c!numberstyle=,
+ %\c!numbercolor=,
+ %\c!numbercommand=,
+ \c!spacebefore=\v!big,
+ \c!spaceafter=\formulaparameter\c!spacebefore,
+ \c!leftmargin=\!!zeropoint,
+ \c!rightmargin=\!!zeropoint,
+ %\c!margin=,
+ \c!indentnext=\v!no,
+ \c!alternative=\s!default,
+ %\c!align=,
+ \c!strut=\v!no,
+ %\c!separator=\@@koseparator,
+ %\c!grid=,
+ \c!distance=1em]
+
+\definestructurecounter
+ [\v!formula]
+
+\setupstructurecounter
+ [\v!formula]
+ [\c!numberconversionset=\v!formula]
+
+\def\storecurrentformulanumber#1#2#3% ref, todo:str, \sync % todo: title etc (like float)
+ {\dostructurecountercomponent
+ {formula}%
+ \getfloatparameters
+ \formulaparameter
+ \detokenizedformulaparameter
+ \relax
+ \relax
+ \relax
+ [\c!name=\currentformula,\s!counter=\currentformula,%
+ \s!hascaption=\v!yes,\s!hasnumber=\v!yes,\s!hastitle=\v!yes,%
+ \c!reference=#1,\c!title=,\c!bookmark=]%
+ [#2]%
+ \globallet\currentformulanumber\laststructurecounternumber
+ \globallet#3\laststructurecountersynchronize}
+
+\def\thecurrentformulanumber
+ {%\ifnoformulacaption \else \ifnoformulanumber \else
+ \labeltexts\currentformula{\convertedstructurecounter[formula]}% ! ! todo: use a lua call instead
+ }%\fi \fi}
+
+\def\placecurrentformulanumber
+ {\currentformulassynchronize
+ \currentformulasynchronize
+ \currentsubformulasynchronize
+ \thecurrentformulanumber} %\convertedstructurecounter[\v!formula]\relax}
+
+\def\doformulareference#1#2%
+ {\doifsomething{#1}{\doifnotinset{#1}{+,-}{\rawreference\s!for{#1}{#2}}}}
+
+\def\doformulanumber
+ {\dotripleempty\dodoformulanumber}
+
+\def\dodoformulanumber[#1][#2][#3]%
+ {\doquadruplegroupempty\dododoformulanumber{#1}{#2}{#3}}
+
+\let\subformulasreference\empty % temp hack
+
+\let\currentformulasynchronize \relax
+\let\currentformulassynchronize\relax
+
+\def\dododoformulanumber#1#2#3#4% (#1,#2)=outer(ref,sub) (#3,#4)=inner(ref,sub)
+ {\hbox\bgroup
+ \ifconditional\handleformulanumber
+ \ifconditional\incrementformulanumber
+ \ifconditional\insidesubformulas
+ \incrementsubstructurecounter[\v!formula][2]%
+ \else
+ \incrementstructurecounter[\v!formula]%
+ \fi
+ \fi
+ %
+ % main counter
+ \setbox0\hbox{\ignorespaces#2\unskip}%
+ \ifdim\wd0>\zeropoint
+ \setsubstructurecounterown[\v!formula][2]{#2}% \detokenize?
+ \fi
+ \edef\currentformulareference{#1}%
+ \ifx\currentformulareference\empty
+ \glet\currentformulasynchronize\relax
+ \else
+ \storecurrentformulanumber\currentformulareference\empty\currentformulasynchronize
+ \fi
+ % subcounter
+ \setbox0\hbox{\ignorespaces#4\unskip}%
+ \ifdim\wd0>\zeropoint
+ \setsubstructurecounterown[\v!formula][2]{#4}% \detokenize?
+ \fi
+ \edef\currentsubformulareference{#3}%
+ \ifx\currentsubformulareference\empty
+ \glet\currentsubformulasynchronize\relax
+ \else
+ \storecurrentformulanumber\currentsubformulareference\empty\currentsubformulasynchronize
+ \fi
+ %
+ \rm % nodig ?
+ \doif{\formulaparameter\c!location}\v!right{\hskip\formulaparameter\c!distance}%
+ \formulaparameter\c!numbercommand
+ {\dosetformulaattributes\c!numberstyle\c!numbercolor
+ \strut
+ \formulaparameter\c!left
+ \labeltexts\v!formula{\ignorespaces\placecurrentformulanumber\unskip}%
+ \formulaparameter\c!right}%
+ \doif{\formulaparameter\c!location}\v!left{\hskip\formulaparameter\c!distance}%
+ \fi
+ \egroup}
+
+\let\donestedformulanumber\gobbletwoarguments
+
+\definelist[\v!formula]
+
+\global\let\doflushformulalistentry\gobbleoneargument
+
+\def\setformulalistentry#1%
+ {\gdef\doflushformulalistentry##1%
+ {\normalexpanded{\noexpand\writetolist[\v!formula]{##1}}{#1}%
+ \global\let\doflushformulalistentry\gobbleoneargument}}
+
+\newconditional\handleformulanumber
+\newconditional\incrementformulanumber
+\newconditional\insidesubformulas
+
+\newif\ifinformula
+
+\let\doplaceformulanumber\empty
+
+%D We need a hook into the plain math alignment macros
+%D
+%D \starttyping
+%D \displaylines
+%D \eqalignno
+%D \eqalignno
+%D \stoptyping
+%D
+%D Otherwise we get a missing \type {$$} error reported.
+
+\def\resetdisplaymatheq
+ {\let\normalleqno\relax \let\leqno\relax
+ \let\normalreqno\relax \let\eqno \relax
+ \let\doplaceformulanumber\empty}
+
+%D
+
+\def\defineformula
+ {\dodoubleempty\dodefineformula}
+
+\def\dodefineformula[#1][#2]%
+ {\doifsomething{#1}
+ {\getparameters[\??fm#1][\s!parent=\??fm,#2]%
+ \definelist[#1]%
+ \setvalue{\e!start#1\v!formula}{\dostartformula{#1}}%
+ \setvalue{\e!stop #1\v!formula}{\dostopformula}}}
+
+\def\defineformulaalternative
+ {\dotripleargument\dodefineformulaalternative}
+
+\def\dodefineformulaalternative[#1][#2][#3]%
+ {\setvalue{\e!start#1\v!formula}{#2}%
+ \setvalue{\e!stop #1\v!formula}{#3}}
+
+% sp = single line paragraph sd = single line display
+% mp = multi line paragraph md = multy line display
+
+\defineformulaalternative[\s!default][\startdisplaymath][\stopdisplaymath]
+\defineformulaalternative[\s!single] [\startdisplaymath][\stopdisplaymath]
+\defineformulaalternative[\s!multi] [\startdisplaymath][\stopdisplaymath]
+
+\defineformula
+ [sp]
+ [\c!spacebefore=\v!none,
+ \c!spaceafter=\v!none,
+ \c!indentnext=\v!no,
+ \c!alternative=\s!single]
+
+\defineformula
+ [sd]
+ [\c!spacebefore=\v!none,
+ \c!spaceafter=\v!none,
+ \c!indentnext=\v!yes,
+ \c!alternative=\s!single]
+
+\defineformula
+ [mp]
+ [\c!indentnext=\v!no,
+ \c!alternative=\s!multi]
+
+\defineformula
+ [md]
+ [\c!indentnext=\v!yes,
+ \c!alternative=\s!multi]
+
+%D \macros
+%D {setupsubformulas, startsubformulas}
+
+\def\subformulaparameter#1{\ifcname\??fn#1\endcsname\cname\??fn#1\endcsname\fi}
+
+\def\setupsubformulas
+ {\dodoubleargument\getparameters[\??fn]}
+
+\setupsubformulas
+ [\c!indentnext=\formulaparameter\c!indentnext]
+
+% \setupsubformulas[conversion=romannumerals]
+%
+% \placeformula
+% \startsubformulas[Maxwell]
+% \startformulas
+% \startformula \startalign
+% \NC \nabla\cdot\bf E \NC = \frac{\rho}{\varepsilon_0} \NR[Maxwell 1]
+% \NC \nabla\times\bf E \NC = - \frac{\partial\bf B}{\partial t} \NR[Maxwell II]
+% \stopalign \stopformula
+% \startformula \startalign
+% \NC \nabla\cdot \bf B \NC = 0 \NR[Maxwell III]
+% \NC \nabla\times\bf B \NC = \mu_0{\bf j}+\varepsilon_0\mu_0\frac{\partial\bf E}{\partial t} \NR[Maxwell IV]
+% \stopalign \stopformula
+% \stopformulas
+% \stopsubformulas
+%
+% Maxwell : \in [Maxwell] and II : \in [Maxwell II]
+
+%D Tricky stuff:
+
+\newdimen\lastlinewidth
+
+% test \par \dorecurse{10}{test } \moveformula \startformula test \stopformula test \endgraf
+% test \par \dorecurse{10}{test } \startformula test \stopformula test \endgraf
+% \dorecurse{30}{\bpar \dorecurse\recurselevel{test } \epar \startformula formula \stopformula}
+
+\def\setlastlinewidth
+ {\resetlastlinewidth
+ \ifoptimizedisplayspacing\ifmmode\else\ifhmode
+ \bgroup
+ \forgetdisplayskips
+ \displaywidowpenalty\widowpenalty % brrr, else widowpenalty does not work
+ \everymath \emptytoks
+ \everydisplay\emptytoks
+ $$\strut\global\lastlinewidth\predisplaysize$$
+ \vskip-\lineheight
+ \vskip\zeropoint
+ \egroup
+ \fi\fi\fi}
+
+\def\resetlastlinewidth
+ {\global\lastlinewidth\zeropoint\relax}
+
+\abovedisplayskip \zeropoint
+\abovedisplayshortskip \zeropoint % evt. 0pt minus 3pt
+\belowdisplayskip \zeropoint
+\belowdisplayshortskip \zeropoint % evt. 0pt minus 3pt
+
+\predisplaypenalty \zerocount
+\postdisplaypenalty \zerocount % -5000 gaat mis, zie penalty bij \paragraaf
+
+% we don't use the skip's
+
+\def\displayskipsize#1#2% obsolete
+ {\ifdim\ctxparskip>\zeropoint
+ #1\ctxparskip\!!plus#2\ctxparskip\!!minus#2\ctxparskip\relax
+ \else
+ #1\lineheight\!!plus#2\lineheight\!!minus#2\lineheight\relax
+ \fi}
+
+\def\forgetdisplayskips % to do
+ {\abovedisplayskip \zeropoint
+ \belowdisplayskip \zeropoint
+ \abovedisplayshortskip\zeropoint
+ \belowdisplayshortskip\zeropoint}
+
+\setvalue{\e!start\v!formula}{\dostartformula{}}
+\setvalue{\e!stop \v!formula}{\dostopformula}
+
+\def\predisplaysizethreshhold{2em} % was 3em
+
+\def\leftdisplayskip {\leftskip}
+\def\rightdisplayskip {\rightskip}
+\def\leftdisplaymargin {\formulaparameter\c!leftmargin}
+\def\rightdisplaymargin {\formulaparameter\c!rightmargin}
+\def\displaygridsnapping{\formulaparameter\c!grid}
+
+\def\beforedisplayspace
+ {\doifnot{\formulaparameter\c!spacebefore}\v!none{\blank[\formulaparameter\c!spacebefore]}}
+
+\def\afterdisplayspace
+ {\doifnot{\formulaparameter\c!spaceafter }\v!none{\blank[\formulaparameter\c!spaceafter ]}}
+
+\def\setpredisplaysize#1%
+ {\predisplaysize#1\relax
+ \ifdim\predisplaysize<\maxdimen
+ \ifdim\predisplaysize>\zeropoint
+ \advance\predisplaysize \predisplaysizethreshhold
+ \fi
+ \advance\predisplaysize \displayindent % needed ?
+ \ifdim\predisplaysize>\hsize
+ \predisplaysize\hsize
+ \fi
+ \else
+ \predisplaysize\zeropoint
+ \fi}
+
+\def\setdisplaydimensions
+ {\displayindent\leftdisplayskip
+ \advance\displayindent\leftdisplaymargin
+ \displaywidth\hsize
+% \setlocalhsize
+% \displaywidth\localhsize
+ \ifdim\hangindent>\zeropoint
+ \advance\displayindent\hangindent
+ \else
+ \advance\displaywidth\hangindent
+ \fi
+ \advance\displaywidth\dimexpr-\displayindent-\rightdisplayskip-\rightdisplaymargin\relax
+ \hsize\displaywidth} % new, else overfull in itemize
+
+\newif\ifoptimizedisplayspacing
+
+\def\dostartformula#1%
+ {\dodoubleempty\dodostartformula[#1]}
+
+\newskip\formulaparskip
+\newskip\formulastrutht
+\newskip\formulastrutdp
+
+% hm, invoke otr in hmode in order to move skips to mvl, could be an option
+
+%D \startbuffer
+%D \startformula[9pt] x = 1 \stopformula
+%D \startformula[7pt] x = 1 \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\dodostartformula[#1][#2]% setting leftskip adaption is slow !
+ {% todo: test first
+ %
+ % \ifdim\lastskip>\zeropoint
+ % \resetlastlinewidth % else problems with in between stuff without \epar
+ % \fi
+ \bgroup % HERE
+ \def\currentformula{#1}%
+ \the\everybeforedisplayformula
+ \formulaparskip\parskip
+ \formulastrutdp\strutdepth
+ \formulastrutht\strutheight
+ \doifsomething{#2}{\switchtoformulabodyfont[#2]}%
+ \parskip\formulaparskip
+ % may look better in itemizations
+ \doif{\formulaparameter\c!option}\v!middle
+ {\def\leftdisplayskip{\zeropoint}%
+ \def\rightdisplayskip{\zeropoint}}%
+ % this was an experiment
+ \doifsomething{\formulaparameter\c!margin}% so we test first
+ {\dosetleftskipadaption{\formulaparameter\c!margin}%
+ \edef\leftdisplaymargin{\the\leftskipadaption}}% overloaded
+ \long\def\dostartformula##1{\bgroup\let\dostopformula\egroup}%
+ \freezedimenmacro\leftdisplayskip
+ \freezedimenmacro\rightdisplayskip
+ \freezedimenmacro\leftdisplaymargin
+ \freezedimenmacro\rightdisplaymargin
+ \freezedimenmacro\predisplaysizethreshhold
+ \forgetdisplayskips
+ \ifoptimizedisplayspacing
+ \ifdim\lastlinewidth>\zeropoint
+ \abovedisplayshortskip-\strutht\relax
+ \fi
+ \else
+ \resetlastlinewidth
+ \fi
+ \getvalue{\e!start\formulaparameter\c!alternative\v!formula}}
+
+\def\switchtoformulabodyfont{\switchtobodyfont}
+
+\setvalue{\v!formula}{\dosingleempty\doformula}
+
+\def\doformula[#1]#2%
+ {\begingroup
+ \doifsomething{#1}{\switchtoformulabodyfont[#1]}%
+ % not : \def\doformula[##1]##2{\mathematics{##2}}%
+ \mathematics{#2}%
+ \endgroup}
+
+\def\dostopformula
+ {\doplaceformulanumber
+ \getvalue{\e!stop\formulaparameter\c!alternative\v!formula}%
+ \resetlastlinewidth
+ \nonoindentation
+ \checknextindentation[\formulaparameter\c!indentnext]%
+ \egroup
+ \hangafter\minusone % added for side floats
+ \hangindent\zeropoint % added for side floats
+ \setfalse\handleformulanumber
+ \dorechecknextindentation} % here ?
+
+\def\startdisplaymath
+ {\ifgridsnapping
+ \beforedisplayspace
+ \snapmathtogrid\vbox
+ \bgroup
+ \informulatrue
+ %\forgetall % breaks side floats
+ \else
+ \bgroup
+ \parskip\formulaparskip % ! !
+ \informulatrue
+ %\forgetall % otherwise backgrounds fail
+ \ifdim\lastskip<\zeropoint\else
+ \par
+ \ifvmode \ifdim\parskip>\zeropoint\relax
+ \whitespace \vskip-\parskip % kind of forces and cancels again
+ \fi \fi
+ \fi
+ \doif\displaygridcorrection{-\v!top}{\kern-\strutht}% new, currently only option/default
+ \beforedisplayspace
+ \par
+ \ifvmode
+ \prevdepth-\maxdimen % texbook pagina 79-80
+ % otherwise problems at the top of a page
+ \verticalstrut
+ \vskip-\struttotal
+ \vskip-\baselineskip
+ \fi
+ \fi
+ $$\setdisplaydimensions
+ \setpredisplaysize\lastlinewidth
+ \startinnermath}
+
+\def\stopdisplaymath
+ {\stopinnermath
+ $$%
+ \ifgridsnapping
+ \egroup
+ \afterdisplayspace
+ \else
+ \par\ifvmode\ifdim\parskip>\zeropoint\whitespace\vskip-\parskip\fi\fi
+ \afterdisplayspace
+ \egroup
+ \fi
+ \globallet\displaylinecorrection\empty
+ \gdef\displaygridcorrection{\displaygridsnapping}}
+
+\newif\ifclipdisplaymath \clipdisplaymathtrue
+\def\displaymathclipfactor{1.1}
+
+\def\snapmathtogrid % to do \dp
+ {\dowithnextbox
+ {\bgroup
+ \donefalse
+ \ifclipdisplaymath
+ \ifdim\nextboxht<\displaymathclipfactor\lineheight
+ \donetrue
+ \fi
+ \fi
+ \ifdone
+ \nextboxht\lineheight
+ \else
+ \getnoflines\nextboxht
+ \setbox\nextbox\vbox to \noflines\lineheight{\vfill\flushnextbox\vfill}%
+ \setbox\nextbox\hbox{\lower\strutdepth\flushnextbox}%
+ \fi
+ \snaptogrid[\displaygridcorrection]\hbox{\flushnextbox}%
+ \egroup}}
+
+\def\displaygridcorrection{\displaygridsnapping}
+\let\displaygridcorrection\empty
+
+\def\moveformula
+ {\dosingleempty\domoveformula}
+
+\def\domoveformula[#1]% brr gaat mogelijk fout
+ {\iffirstargument
+ \xdef\displaygridcorrection{#1}%
+ \else
+ \gdef\displaygridcorrection{-\v!top}% handy with short preline
+ \fi
+ \globallet\displaylinecorrection\displaygridcorrection}
+
+\let\startinnermath\empty
+\let\stopinnermath \empty
+
+% \defineformulaalternative[multi][\begindmath][\enddmath]
+%
+% \fakewords{20}{40}\epar
+% \placeformula {a} $$ \fakespacingformula $$
+% \fakewords{20}{40}\epar
+% \placeformula {b} \startformule \fakespacingformula \stopformule
+% \placeformula {b} \startformule \fakespacingformula \stopformule
+% \fakewords{20}{40}\epar
+% \placeformula {c} \startmdformule \fakespacingformula \stopmdformule
+% \placeformula {c} \startmdformule \fakespacingformula \stopmdformule
+% \fakewords{20}{40}\epar
+% \placeformula {d} \startmpformule \fakespacingformula \stopmpformule
+% \placeformula {d} \startmpformule \fakespacingformula \stopmpformule
+% \fakewords{20}{40}\epar
+% \placeformula {e} \startsdformule \fakespacingformula \stopsdformule
+% \placeformula {e} \startsdformule \fakespacingformula \stopsdformule
+% \fakewords{20}{40}\epar
+% \placeformula {f} \startspformule \fakespacingformula \stopspformule
+% \placeformula {f} \startspformule \fakespacingformula \stopspformule
+% \fakewords{20}{40}
+
+\def\placeformula
+ {\settrue\incrementformulanumber
+ \dodoubleempty\doplaceformula}
+
+\def\placesubformula
+ {\setfalse\incrementformulanumber
+ \dodoubleempty\doplaceformula}
+
+\def\startsubformulas
+ {\dosingleempty\dostartsubformulas}
+
+\def\dostartsubformulas[#1]%
+ {\ifconditional\incrementformulanumber
+ \incrementstructurecounter[\v!formula]%
+ \edef\subformulasreference{#1}% messy
+ \ifx\subformulasreference\empty
+ \glet\currentformulassynchronize\relax
+ \else
+ \storecurrentformulanumber\subformulasreference\empty\currentformulassynchronize
+ \fi
+ \fi
+ \settrue\insidesubformulas}
+
+\def\stopsubformulas
+ {\setfalse\insidesubformulas
+ \resetlastlinewidth
+ \nonoindentation
+ \checknextindentation[\formulaparameter\c!indentnext]%
+ \dorechecknextindentation} % here ?
+
+%D Named subformulas
+
+\def\startnamedsubformulas
+ {\dosingleempty\dostartnamedsubformulas}
+
+\def\dostartnamedsubformulas[#1]#2%
+ {\setformulalistentry{#2}%
+ \startsubformulas[#1]}
+
+\def\stopnamedsubformulas
+ {\stopsubformulas}
+
+%D Experimental goodie:
+%D
+%D \startbuffer
+%D \placelist[formula][criterium=text] \blank[2*big]
+%D \placenamedformula[one]{first} \startformula a = 1 \stopformula \endgraf
+%D \placeformula \startformula a = 2 \stopformula \endgraf
+%D \placenamedformula {second} \startformula a = 3 \stopformula \endgraf
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\placenamedformula
+ {\dosingleempty\doplacenamedformula}
+
+\def\doplacenamedformula[#1]#2%
+ {\iffirstargument
+ \def\next{\placeformula[#1]}%
+ \else
+ \let\next\placeformula
+ \fi
+ \setformulalistentry{#2}%
+ \next}
+
+%D The implementation of placement is a bit ugly:
+
+\def\doplaceformula[#1][#2]% #2 = dummy, gobbles spaces
+ {\def\redoplaceformula
+ {\bgroup
+ \ifx\next\bgroup
+ \egroup \@EA\moreplaceformula % [ref]{}
+ \else
+ \let\nextnext$% no def
+ \ifx\next\nextnext
+ \egroup \@EAEAEA\dispplaceformula % [ref]$$
+ \else
+ \egroup \@EAEAEA\dodoplaceformula % [ref]\start
+ \fi
+ \fi[#1]{}}%
+ \futurelet\next\redoplaceformula}
+
+\long\def\moreplaceformula[#1]#2#3#4% #2 dummy #4 gobbles spaces
+ {\def\redoplaceformula
+ {\bgroup
+ \let\nextnext$% no def
+ \ifx\next\nextnext
+ \egroup \@EA\dispplaceformula % [ref]$$
+ \else
+ \egroup \@EA\dodoplaceformula % [ref]\start
+ \fi
+ [#1]{#3}}%
+ \futurelet\next\redoplaceformula#4}
+
+\let\startplaceformula\placeformula
+\let\stopplaceformula \relax
+
+\def\startformulas#1\stopformulas % new / to be internationalized
+ {\bgroup
+ \let\currentformula\empty
+ \forgetdisplayskips
+ \startdisplaymath
+ \setlocalhsize
+ \long\def\startformula##1\stopformula
+ {\advance\scratchcounter\plusone}%
+ \scratchcounter\zerocount
+ #1% preroll
+ \ifcase\scratchcounter\else
+ \divide \hsize \scratchcounter
+ \fi
+ \hbox to \localhsize \bgroup
+ \hss
+ \def\normalstartformula{\vskip-\strutdepth$$}% i hate this
+ \def\normalstopformula {$$}%
+ \def\startformula {$\vcenter\bgroup\normalstartformula}%
+ \def\stopformula {\normalstopformula\egroup$\hss}%
+ #1%
+ \egroup
+ \stopdisplaymath
+ \egroup
+ \hangafter\minusone % added for side floats
+ \hangindent\zeropoint} % added for side floats
+
+\def\dispplaceformula[#1]#2$$#3$$%
+ {\dodoplaceformula[#1]{#2}\dostartformula{}#3\dostopformula}
+
+\def\dodoplaceformula[#1]#2% messy, needs a clean up
+ {\doifelse{#1}{-}
+ {\setfalse\handleformulanumber}
+ {\doifelse{#2}{-}
+ {\setfalse\handleformulanumber}
+ {\settrue\handleformulanumber}}%
+ \ifconditional\handleformulanumber
+ \def\formulanumber
+ {%\global\let\subformulanumber\doformulanumber % no, bug
+ \doformulanumber[#1][#2]}%
+ \def\donestedformulanumber##1##2%
+ {\doifsomething{##1}
+ {\doifelse{##1}{+}{\doformulanumber[#1]}{\doformulanumber[##1]}[##2][]{}}}%
+ \def\subformulanumber
+ {\setfalse\incrementformulanumber
+ \formulanumber}%
+ \gdef\doplaceformulanumber
+ {\global\let\doplaceformulanumber\empty
+ \doifelse{\formulaparameter\c!location}\v!left
+ {\normalleqno{\doformulanumber[#1][#2][]{}}}
+ {\normalreqno{\doformulanumber[#1][#2][]{}}}}%
+ \else
+ \def\formulanumber{\doformulanumber[#1][#2]}%
+ \let\donestedformulanumber\gobbletwoarguments
+ \let\subformulanumber\doformulanumber % was \global
+ \global\let\doplaceformulanumber\empty
+ \fi}
+
+%D Here we implement a basic math alignment mechanism. Numbers
+%D are also handled. The macros \type {\startinnermath} and
+%D \type {\stopinnermath} can be overloaded in specialized
+%D modules.
+
+\def\startinnermath
+ {\getvalue{\e!start\??fm\formulaparameter\c!align}}
+
+\def\stopinnermath
+ {\getvalue{\e!stop \??fm\formulaparameter\c!align}}
+
+\def\mathinnerstrut
+ {\doif{\formulaparameter\c!strut}\v!yes\strut}
+
+\long\def\defineinnermathhandler#1#2#3%
+ {\setvalue{\e!start\??fm#1}{#2}%
+ \setvalue{\e!stop \??fm#1}{#3}}
+
+\newif\iftracemath
+
+\def\mathhbox
+ {\iftracemath\ruledhbox\else\hbox\fi}
+
+\chardef\mathraggedstatus=0 % normal left center right
+\chardef\mathnumberstatus=0 % nothing normal shift_right
+\let\mathnumbercorrection\!!zeropoint
+
+\def\startmathbox#1%
+ {\hsize\displaywidth
+ \global\chardef\mathnumberstatus\plusone
+ \chardef\mathraggedstatus#1\relax
+ \let\mathnumbercorrection\!!zeropoint
+ \global\let\@eqno \empty \def\eqno {\gdef\@eqno }%
+ \global\let\@leqno\empty \def\leqno{\gdef\@leqno}%
+ % added
+ \let\normalreqno\eqno
+ \let\normalleqno\leqno
+ % added
+ \doplaceformulanumber
+ \setbox\scratchbox\mathhbox to \displaywidth\bgroup
+ \mathinnerstrut
+ $%
+ \displaystyle
+ \ifcase\mathraggedstatus\or\hfill\or\hfill\fi}
+
+\def\llappedmathno
+ {\ifcase\mathraggedstatus\or
+ \@eqno
+ \or
+ \llap{\@eqno}%
+ \or
+ \llap{\@eqno}%
+ \fi}
+
+\def\rlappedmathno
+ {\ifcase\mathraggedstatus\or
+ \rlap{\@leqno}%
+ \or
+ \rlap{\@leqno}%
+ \or
+ \@leqno
+ \fi}
+
+\def\stopmathbox
+ {$%
+ \ifcase\mathraggedstatus\or\or\hfill\or\hfill\fi
+ \egroup
+ \setbox0\hbox{\unhcopy\scratchbox}%
+ \scratchdimen\wd0
+ \ifdim\scratchdimen>\displaywidth
+ \donetrue
+ \else
+ \donefalse
+ \fi
+ \hbox to \displaywidth\bgroup
+ \ifcase\mathnumberstatus
+ \box\scratchbox
+ \or
+ \ifx\@leqno\empty
+ \ifx\@eqno\empty
+ \box\scratchbox
+ \else
+ \ifdone
+ \vbox{\box\scratchbox\hbox to \displaywidth{\hss\llappedmathno}}%
+ \else
+ \hss\box\scratchbox\llappedmathno % hss makes room for number
+ \fi
+ \fi
+ \else
+ \ifdone
+ \vbox{\hbox to \displaywidth{\rlappedmathno\hss}\box\scratchbox}%
+ \else
+ \rlappedmathno\box\scratchbox\hss % hss makes room for number
+ \fi
+ \fi
+ \or
+ \hskip\mathnumbercorrection
+ \box\scratchbox
+ \hss
+ \else
+ \box\scratchbox
+ \fi
+ \egroup}
+
+\defineinnermathhandler\v!left {\startmathbox\plusone }{\stopmathbox}
+\defineinnermathhandler\v!middle {\startmathbox\plustwo }{\stopmathbox}
+\defineinnermathhandler\v!right {\startmathbox\plusthree}{\stopmathbox}
+\defineinnermathhandler\v!flushleft {\startmathbox\plusthree}{\stopmathbox}
+\defineinnermathhandler\v!center {\startmathbox\plustwo }{\stopmathbox}
+\defineinnermathhandler\v!flushright{\startmathbox\plusone }{\stopmathbox}
+
+%D [The examples below are in english and don't process in the
+%D documentation style, which will be english some day.]
+%D
+%D Normally a formula is centered, but in case you want to
+%D align it left or right, you can set up formulas to behave
+%D that way. Normally a formula will adapt is left indentation
+%D to the environment:
+%D
+%D \startbuffer
+%D \fakewords{20}{40}\epar
+%D \startitemize
+%D \item \fakewords{20}{40}\epar
+%D \placeformula \startformula \fakeformula \stopformula
+%D \item \fakewords{20}{40}\epar
+%D \stopitemize
+%D \fakewords{20}{40}\epar
+%D \stopbuffer
+%D
+%D % \getbuffer
+%D
+%D In the next examples we explicitly align formulas to the
+%D left (\type {\raggedleft}), center and right (\type
+%D {\raggedright}):
+%D
+%D \startbuffer
+%D \setupformulas[align=left]
+%D \startformula\fakeformula\stopformula
+%D \setupformulas[align=middle]
+%D \startformula\fakeformula\stopformula
+%D \setupformulas[align=right]
+%D \startformula\fakeformula\stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Or in print:
+%D
+%D % {\getbuffer}
+%D
+%D With formula numbers these formulas look as follows:
+%D
+%D \startbuffer
+%D \setupformulas[align=left]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \setupformulas[align=middle]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \setupformulas[align=right]
+%D \placeformula \startformula\fakeformula\stopformula
+%D \stopbuffer
+%D
+%D % {\getbuffer}
+%D
+%D This was keyed in as:
+%D
+%D \typebuffer
+%D
+%D When tracing is turned on (\type {\tracemathtrue}) you can
+%D visualize the bounding box of the formula,
+%D
+%D % {\tracemathtrue\getbuffer}
+%D
+%D As you can see, the dimensions are the natural ones, but if
+%D needed you can force a normalized line:
+%D
+%D \startbuffer
+%D \setupformulas[strut=yes]
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This time we get a more spacy result.
+%D
+%D % {\tracemathtrue\getbuffer}
+%D
+%D We will now show a couple of more settings and combinations
+%D of settings. In centered formulas, the number takes no space
+%D
+%D \startbuffer
+%D \setupformulas[align=middle]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D You can influence the placement of the whole box with the
+%D parameters \type {leftmargin} and \type {rightmargin}.
+%D
+%D \startbuffer
+%D \setupformulas[align=right,leftmargin=3em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D
+%D \setupformulas[align=left,rightmargin=1em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D You can also inherit the margin from the environment.
+%D
+%D \startbuffer
+%D \setupformulas[align=right,margin=standard]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+%D
+%D The distance between the formula and the number is only
+%D applied when the formula is left or right aligned.
+%D
+%D \startbuffer
+%D \setupformulas[align=left,distance=2em]
+%D \startformula \fakeformula \stopformula
+%D \placeformula \startformula \fakeformula \stopformula
+%D \stopbuffer
+%D
+%D \typebuffer % {\tracemathtrue\getbuffer}
+
+\protect \endinput
+
+% \abovedisplayshortskip0pt \belowdisplayshortskip0pt \abovedisplayskip0pt \belowdisplayskip0pt \forgetall
+%
+% test \par $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test \par $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test plus \par \prevdepth \maxdimen $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test minus \par \prevdepth-\maxdimen $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+%
+% \parskip\baselineskip
+%
+% test \par $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test \par $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test plus \par \prevdepth \maxdimen $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
+% test minus \par \prevdepth-\maxdimen $$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx$$ \par test \par
diff --git a/tex/context/base/strc-not.lua b/tex/context/base/strc-not.lua
new file mode 100644
index 000000000..78e7b6acd
--- /dev/null
+++ b/tex/context/base/strc-not.lua
@@ -0,0 +1,248 @@
+if not modules then modules = { } end modules ['strc-not'] = {
+ version = 1.001,
+ comment = "companion to strc-not.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+local next = next
+local texsprint, texwrite = tex.sprint, tex.write
+
+local ctxcatcodes = tex.ctxcatcodes
+
+structure = structure or { }
+structure.helpers = structure.helpers or { }
+structure.lists = structure.lists or { }
+structure.sections = structure.sections or { }
+structure.counters = structure.counters or { }
+structure.notes = structure.notes or { }
+
+structure.notes.states = structure.notes.states or { }
+structure.lists.enhancers = structure.lists.enhancers or { }
+
+storage.register("structure/notes/states", structure.notes.states, "structure.notes.states")
+
+local helpers = structure.helpers
+local lists = structure.lists
+local sections = structure.sections
+local counters = structure.counters
+local notes = structure.notes
+
+local notestates = structure.notes.states
+local notedata = { }
+
+-- state: store, insert, postpone
+
+function notes.store(tag,n)
+ local nd = notedata[tag]
+ if not nd then
+ nd = { }
+ notedata[tag] = nd
+ end
+ nd[#nd+1] = n
+ local state = notestates[tag]
+ if state.kind ~= "insert" then
+ state.start = #nd
+ end
+ tex.write(#nd)
+end
+
+function notes.get(tag,n)
+ local nd = notedata[tag]
+ if nd then
+ nd = nd[n or #notedata]
+ if nd then
+ return structure.lists.collected[nd]
+ end
+ end
+end
+
+function notes.define(tag,kind,number)
+ local state = notes.setstate(tag,kind)
+ state.number = number
+end
+
+function notes.save(tag,newkind)
+ local state = notestates[tag]
+ if state and not state.saved then
+ state.saved = notedata[tag]
+ state.savedkind = state.kind
+ state.kind = newkind or state.kind
+ notedata[tag] = { }
+ end
+end
+
+function notes.restore(tag)
+ local state = notestates[tag]
+ if state and state.saved then
+ state.saved = nil
+ state.kind = state.savedkind
+ notedata[tag] = state.saved
+ end
+end
+
+function notes.setstate(tag,newkind)
+ local state = notestates[tag]
+ if not state then
+ state = {
+ kind = newkind
+ }
+ notestates[tag] = state
+ elseif newkind == "insert" then
+ if not state.start then
+ state.kind = newkind
+ end
+ else
+ state.kind = newkind
+ end
+ return state
+end
+
+function notes.getstate(tag)
+ local state = notestates[tag]
+ texsprint((state and state.kind ) or "unknown")
+end
+
+function notes.doifcontent(tag)
+ local ok = notestates[tag]
+ if ok then
+ if ok.kind == "insert" then
+ ok = tex.box[ok.number]
+ if ok then
+ ok = tbs.list
+ ok = lst and lst.next
+ end
+ else
+ ok = ok.start
+ end
+ end
+ commands.doif(ok)
+end
+
+local function internal(tag,n)
+ local nd = notes.get(tag,n)
+ if nd then
+ local r = nd.references
+ if r then
+ local i = r.internal
+ return i and lists.internals[i]
+ end
+ end
+ return nil
+end
+
+local function ordered(kind,name,n)
+ local o = lists.ordered[kind]
+ o = o and o[name]
+ return o and o[n]
+end
+
+function notes.checkpagechange(tag) -- called before increment !
+ local nd = notedata[tag] -- can be unset at first entry
+ if nd then
+ local current = ordered("note",tag,#nd)
+ local nextone = ordered("note",tag,#nd+1)
+ if nextone then
+ -- we can use data from the previous pass
+ if nextone.pagenumber.number > current.pagenumber.number then
+ counters.reset(tag)
+ end
+ elseif current then
+ -- we need to locate the next one, best guess
+ if tex.count[0] > current.pagenumber.number then
+ counters.reset(tag)
+ end
+ end
+ end
+end
+
+function notes.deltapage(tag,n)
+ -- 0:unknown 1:textbefore, 2:textafter, 3:samepage
+ local what = 0
+ local li = internal(tag,n)
+ if li then
+ local metadata, pagenumber = li.metadata, li.pagenumber
+ if metadata and pagenumber then
+ local symbolpage = metadata.symbolpage or 0
+ local notepage = pagenumber.number or 0
+ if notepage > 0 and symbolpage > 0 then
+ if notepage < symbolpage then
+ what = 1
+ elseif notepage > symbolpage then
+ what = 2
+ else
+ what = 3
+ end
+ end
+ else
+ -- might be a note that is not flushed due to to deep
+ -- nesting in a vbox
+ what = 3
+ end
+ end
+ tex.write(what)
+end
+
+function notes.postpone()
+ for tag, state in next, notestates do
+ if state.kind ~= "store" then
+ notes.setstate(tag,"postpone")
+ end
+ end
+end
+
+function notes.setsymbolpage(tag,n)
+ local nd = notes.get(tag,n)
+ if nd then
+ nd.metadata.symbolpage = tex.count[0] -- realpage
+ end
+end
+
+function notes.getsymbolpage(tag,n)
+ local nd = notes.get(tag,n)
+ nd = nd and nd.metadata.symbolpage
+ texwrite(nd or 0)
+end
+
+function notes.getnumberpage(tag,n)
+ local li = internal(tag,n)
+ li = li and li.pagenumber
+ li = li and li.numbers
+ li = li and li[1]
+ texwrite(li or 0)
+end
+
+function notes.flush(tag,whatkind) -- store and postpone
+ local nd = notedata[tag]
+ if nd then
+ local state = notestates[tag]
+ local ns = state and state.start -- first index
+ if ns then
+ local kind = state.kind
+ if kind == whatkind then
+ if kind == "postpone" then
+ for i=ns,#nd do
+ texsprint(ctxcatcodes,format("\\handlenoteinsert{%s}{%s}",tag,i))
+ end
+ state.start = nil
+ state.kind = "insert"
+ elseif kind == "store" then
+ for i=ns,#nd do
+ texsprint(ctxcatcodes,format("\\handlenoteitself{%s}{%s}",tag,i))
+ end
+ state.start = nil
+ end
+ end
+ end
+ end
+end
+
+function notes.title(tag,n)
+ structure.lists.savedtitle(tag,notedata[tag][n])
+end
+
+function notes.number(tag,n,spec)
+ structure.lists.savedprefixednumber(tag,notedata[tag][n])
+end
diff --git a/tex/context/base/strc-not.tex b/tex/context/base/strc-not.tex
new file mode 100644
index 000000000..ca0d3c0a4
--- /dev/null
+++ b/tex/context/base/strc-not.tex
@@ -0,0 +1,1154 @@
+%D \module
+%D [ file=strc-not,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Note Handling,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Note Handling}
+
+\registerctxluafile{strc-not}{1.001}
+
+\unprotect
+
+% obsolete
+
+\let\autopostponenotes\relax
+
+% removed:
+%
+% \pushsomestates
+%
+% core-ins -> obsolete
+%
+% saveinsertiondata
+% restoreinsertiondata
+% saveinsertionbox
+% eraseinsertionbackup
+% restoreinsertionbackup
+%
+% \def\doprocessnotescs#1#2% #1 == \cs that takes arg
+% {\def\currentnote{#2}\@EA#1\csname\??vn:\currentnote\endcsname}
+% \def\processnotescs#1{\processcommacommand[\noteinsertions]{\doprocessnotescs#1}}
+% \def\noteinsertion #1{\csname\??vn:#1\endcsname}
+
+\def\savenotedata {\writestatus{todo}{save note data}}
+\def\restorenotedata {\writestatus{todo}{restore note data}}
+\def\savenotecontent {\writestatus{todo}{save note content}}
+\def\restorenotecontent{\writestatus{todo}{restore note content}}
+\def\erasenotebackup {\writestatus{todo}{erase note backup}}
+
+% page-set:
+
+\def\enablenotes {\writestatus{todo}{enable notes}}
+\def\disablenotes {\writestatus{todo}{disable notes}}
+\def\savenotes {\writestatus{todo}{save notes}}
+\def\flushsavednotes{\writestatus{todo}{flush notes}}
+
+% experiment: (compare scope=text and scope=page)
+%
+% \definenote[mynote][way=bytext,location=text,width=\leftmarginwidth,scope=page,rule=,before=,after=,factor=0]
+% \setuptexttexts[margin][\vbox to \textheight{\placenotes[mynote]\vfill}][]
+
+%D Footnotes are can be characterized by three components:
+%D
+%D \startitemize[packed]
+%D \item a small number \footnote {a footnote number} or
+%D symbol {\setupfootnotes [conversion=set 2]\footnote
+%D {a footnote}}
+%D \item and a similar mark at the bottom of the page
+%D \item followed by some additional text
+%D \stopitemize
+%D
+%D Because footnotes are declared at the location of their
+%D reference they can be seen as a special kind of
+%D floating bodies. Their placement is postponed but has to be
+%D taken into account in the pagebreak calculations. This kind
+%D of calculations are forced by using \type{\insert}s and dealing
+%D with all cases is not trivial.
+
+%D \macros
+%D {notesenabled}
+%D
+%D We need a couple of states because at some moments we don't want
+%D to mess around with inserts at all. Take for instance a table
+%D of contents. And so we can temporary disable footnotes by saying
+%D
+%D \starttyping
+%D \notesenabledfalse
+%D \stoptyping
+
+\newif\ifnotesenabled \notesenabledtrue
+
+\appendtoks \notesenabledfalse \to \everymarking
+
+%D Often we need to process the whole set of notes and to make that
+%D fast, we use a token register:
+
+\newtoks\tobeprocessednotes
+
+\def\processnotes#1% #1: \macro that uses \currentnote
+ {\def\doprocesssomenote##1{\edef\currentdescription{##1}\edef\currentnote{##1}#1}%
+ \the\tobeprocessednotes}
+
+%D Notes have their own paremater handlers. The complication here
+%D is that we use descriptions to typeset the note, so we have several
+%D resolvers.
+
+\let\currentnote\v!footnote
+
+\def\noteparameter #1{\csname\donoteparameter{\??vn\currentnote}#1\endcsname}
+\def\noteparameterhash#1{\donoteparameterhash {\??vn\currentnote}#1}
+
+\def\donoteparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\donoteparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\donoteparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\donoteparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\donoteparentparameter #1#2{\ifx#1\relax\s!empty\else\donoteparameter #1#2\fi}
+\def\donoteparentparameterhash#1#2{\ifx#1\relax \else\donoteparameterhash#1#2\fi}
+
+\def\detokenizednoteparameter#1{\detokenize\expandafter\expandafter\expandafter{\csname\??vn#1\endcsname}}
+
+\def\dosetnoteattributes#1#2% style color
+ {\edef\fontattributehash {\noteparameterhash#1}%
+ \edef\colorattributehash{\noteparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+%D \macros
+%D {setupnote,setupnotedefinition}
+%D
+%D We can influence footnote typesetting with the setup
+%D command:
+%D
+%D \showsetup{setupnotes}
+%D \showsetup{setupnote}
+%D
+%D The definition command indicate that we can frame the footnote
+%D area. The footnotes themselves are treated as descriptions.
+%D
+%D \showsetup{definenote}
+%D
+%D It's sort of a custom to precede footnotes by a horizontal
+%D rule and although fancy rules like
+%D
+%D \starttyping
+%D \hbox to 10em{\hskip-3em\dotfill}
+%D \stoptyping
+%D
+%D Are quite ligitimate, we default to a simple one 20\% of the
+%D text width.
+
+\def\setupnotes
+ {\dodoubleargument\getparameters[\??vn]}
+
+\setupnotes
+ [\c!location=\v!page,
+ \c!way=\v!by\v!part,
+ \c!sectionnumber=\v!no,
+ %\c!conversion=,
+ \c!rule=\v!on,
+ \c!before=\blank,
+ \c!bodyfont=\v!small,
+ %\c!style=,
+ %\c!color=,
+ %\c!after=,
+ %\c!rulecolor=,
+ \c!rulethickness=\linewidth,
+ \c!frame=\v!off,
+ \c!margindistance=.5em,
+ \c!columndistance=1em,
+ \c!distance=.125em,
+ \c!align=\v!normal,
+ \c!tolerance=\v!tolerant,
+ \c!split=\v!tolerant,
+ %\c!width=\makeupwidth,
+ %\c!width=\ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi,
+ \c!width=\defaultnotewidth,
+ \c!height=\textheight,
+ \c!numbercommand=\high,
+ \c!command=\noteparameter\c!numbercommand, % downward compatible
+ \c!separator=,% \@@koseparator,
+ \c!textcommand=\high,
+ \c!textstyle=\tx,
+ %\c!textcolor=,
+ \c!interaction=\v!yes,
+ %\c!factor=,
+ %\c!scope=, % \v!text \v!page
+\c!prefixconnector=.,
+\c!prefix=\v!no,
+ \c!next=\autoinsertnextspace, % new, experimental with startnotes
+ \c!n=1]
+
+\def\@@defaultnotedefloc{\v!inleft}
+\def\@@defaultnotedefdis{\!!zeropoint}
+
+% also s!root
+%
+% \definedescription
+% [\??vn\??vn]
+% [\c!location=\@@defaultnotedefloc,
+% \c!distance=\@@defaultnotedefdis,
+% \c!width=\v!fit,
+% \c!headstyle=\noteparameter\c!style,
+% \c!headcolor=\noteparameter\c!color,
+% \c!before=,
+% \c!after=]
+
+\def\startnotedef{\resetdescriptions\csname\e!start\??vn\??vn\currentnote\endcsname}
+\def\stopnotedef {\csname\e!stop \??vn\??vn\currentnote\endcsname}
+
+\def\currentnoteins{\csname\??vn:\currentnote\endcsname}
+
+\newtoks \everysetupnote
+
+\def\definenote
+ {\dodoubleempty\dodefinenote}
+
+\def\dodefinenote[#1][#2]%
+ {\edef\currentnote{#1}%
+ \ifcsname\??vn:\currentnote\endcsname\else
+ \@EA\installinsertion\csname\??vn:\currentnote\endcsname\relax
+ \appendtoks\doprocesssomenote{#1}\to\tobeprocessednotes
+ \fi
+ \defineenumeration % description
+ [\currentnote]
+ [\c!location=\@@defaultnotedefloc,
+ \c!distance=\@@defaultnotedefdis,
+ \c!width=\v!fit,
+ \c!headstyle=\noteparameter\c!style,
+ \c!headcolor=\noteparameter\c!color,
+\s!handler=\v!note,
+ \c!text=,
+ \c!before=,
+ \c!after=]%
+ \setupenumerations
+ [\currentnote]
+ [\s!parent=\??vn\currentnote,
+ \c!number=\v!yes] % no inheritance from decriptions which is okay
+ \presetlocalframed
+ [\??vn\currentnote]%
+ \getparameters
+ [\??vn\currentnote]
+ [\s!parent=\??vn,#2]%
+ \definestructurecounter
+ [\currentnote]%
+ \ctxlua{structure.notes.define("\currentnote","insert",\number\csname\??vn:\currentnote\endcsname)}%
+ \the\everysetupnote}
+
+\let\setupnotedefinition\setupenumerations
+
+\appendtoks
+ \setupenumerations[\currentnote][]%
+\to \everysetupnote
+
+\def\setupnote
+ {\dodoubleempty\dosetupnote}
+
+\def\dosetupnote[#1][#2]%
+ {\edef\currentnote{#1}%
+ \ifsecondargument
+ \getparameters[\??vn\currentnote][#2]%
+ \the\everysetupnote
+ \fi
+ \dochecknote}
+
+\appendtoks
+ \letvalue{\??vn\c!rule:\currentnote}\normalnoterule % hm
+\to \everysetupnote
+
+\appendtoks
+ \processaction
+ [\noteparameter\c!rule]
+ [ \v!on=>\letvalue{\??vn\c!rule:\currentnote}\normalnoterule,
+ \v!off=>\letvalue{\??vn\c!rule:\currentnote}\relax,
+ \s!default=>\letvalue{\??vn\c!rule:\currentnote}\relax,
+ \s!unknown=>\setvalue{\??vn\c!rule:\currentnote}{\noteparameter\c!rule}]%
+\to \everysetupnote
+
+\appendtoks
+ \processaction % todo
+ [\noteparameter\c!split]
+ [ \v!tolerant=>\notepenalty\zeropoint,
+ \v!strict=>\notepenalty9999,
+ \v!verystrict=>\notepenalty\maxdimen,
+ \s!default=>\notepenalty\zeropoint,
+ \s!unknown=>\notepenalty\commalistelement]%
+\to \everysetupnote
+
+%D The following switch can be used to disable limiting the
+%D height of the footnote area, something that is needed in
+%D multi column balancing. Use this switch with care.
+
+\newif\ifnotelimit \notelimittrue % shared
+
+% bottomnotes endnotes
+% clevernotes
+
+\appendtoks
+ \doifsomething{\noteparameter\c!factor}
+ {\ifnum\noteparameter\c!factor<\zerocount\else
+ \count\currentnoteins\noteparameter\c!factor
+ \fi}%
+\to \everysetupnote
+
+% compatibility (will go away)
+
+\newif\ifendnotes
+\newif\ifbottomnotes
+
+% locations:
+
+\def\s!noteloc{nodeloc} % 1=page 2=columns 3=lastcolumn 4=firstcolumn 5=none
+\def\s!notepos{nodepos} % 0=nothing 1=high 2=bottom
+\def\s!notefmt{nodefmt} % 1 text
+\def\s!notecol{nodecol}
+
+\def\clevernotes % compatibility hack
+ {\numexpr\ifcase\noteparameter\s!noteloc\or0\or2\or2\or1\else0\fi\relax}
+
+\def\setnotelocation #1{\expandafter\chardef\csname\??vn\currentnote\s!noteloc\endcsname#1\relax}
+\def\setnoteposition #1{\expandafter\chardef\csname\??vn\currentnote\s!notepos\endcsname#1\relax}
+\def\setnoteformatting#1{\expandafter\chardef\csname\??vn\currentnote\s!notefmt\endcsname#1\relax}
+\def\setnotecolumns #1{\expandafter\chardef\csname\??vn\currentnote\s!notecol\endcsname#1\relax}
+
+\def\currentnofcolumns{\@@kln}
+
+\def\dochecknote
+ {% node states
+ \setnotelocation\plusone
+ \setnoteposition\plustwo
+ \processallactionsinset
+ [\noteparameter\c!location]
+ [ \v!page=>\setnotelocation \plusone,
+ \v!columns=>\setnotelocation \plustwo,
+ \v!firstcolumn=>\setnotelocation \plusthree,
+ \v!lastcolumn=>\setnotelocation \plusfour,
+ \v!none=>\setnotelocation \plusfive,
+ \v!text=>\setnotelocation \plusfive
+ \setnoteformatting\plusone, % test
+ \v!high=>\setnoteposition \plusone,
+ \v!bottom=>\setnoteposition \plustwo]%
+ % compatibility hack
+ \ifnum\noteparameter\s!noteloc=\plusfive \endnotestrue \else \endnotesfalse \fi
+ \ifnum\noteparameter\s!notepos=\plustwo \bottomnotestrue \else \bottomnotesfalse \fi
+ % set column multiplier
+ \edef\currentnotenofcolumns{\noteparameter\c!n}%
+ \ifx\currentnotenofcolumns\empty
+ \let\currentnotenofcolumns\!!plusone
+ \fi
+ \ifcase\noteparameter\s!noteloc\or
+ % page
+ \scratchcounter \currentnotenofcolumns
+ \or
+ % columns
+ \scratchcounter\ifnum\currentnofcolumns=\zerocount \plusone \else \currentnotenofcolumns \fi \relax
+ \or
+ % firstcolumn
+ \scratchcounter\plusone
+ \or
+ % lastcolumn
+ \scratchcounter\plusone
+ \or
+ % text
+ \scratchcounter\currentnotenofcolumns
+ \fi
+ % column factor
+ \global\count\currentnoteins\plusthousand
+ \global\count\currentnoteins\numexpr\plusthousand/\scratchcounter\relax
+ % maximize height
+ \ifnotelimit
+ \global\dimen\currentnoteins\dimexpr\noteparameter\c!height*\scratchcounter\relax
+ \fi
+ % distance
+ \begingroup
+ \setbox\scratchbox\vbox
+ {\forgetall
+ \noteparameter\c!before
+ \placenoterule
+ \noteparameter\c!after}%
+ \global\skip\currentnoteins\ht\scratchbox
+ \endgroup
+ % play safe
+ \ifnum\noteparameter\s!noteloc=\plusfive
+ \ctxlua{structure.notes.setstate("\currentnote","store")}%
+ % text notes (e.g. end notes) but we don't use inserts anyway
+ \global\dimen\currentnoteins\maxdimen
+ \global\count\currentnoteins\zerocount
+ \global\skip \currentnoteins\zeropoint
+ \fi}
+
+\def\checknotes
+ {\processnotes\dochecknote}
+
+% D When \type{n} exceeds~1, footnotes are typeset in
+% D multi||columns, using the algoritm presented on page~397
+% D of \TEX book. Footnotes can be places on a per page basis
+% D or whereever suitable. When we set~\type{n} to~0, we get a
+% D rearanged paragraph, typeset by the algoritms on pages 398
+% D and~389 (at least in \MKII). We definitely did not reinvent
+% D that wheel.
+
+% Example of using factor:
+%
+% \definenote[mynote][way=bypage,location=text,width=\marginwidth,rule=,before=,factor=0]
+% \setuplayout[backspace=5cm,margin=3cm,margindistance=.5cm,width=middle]
+% \setuptexttexts[margin][\vbox to \textheight{\placenotes[mynote]\vfill}][]
+% \starttext
+% \dorecurse{10}{test \mynote{one one one one one one} \input zapf \mynote{one one one one one one} }
+% \stoptext
+
+%D The noterule can be a graphic and therefore calling this
+%D setup macro at every skipswitch is tricky (many many MP
+%D runs). Let's just reserve a few points, that probably match
+%D those of the stretch component.
+
+\def\placenoterule
+ {\getvalue{\??vn\c!rule:\currentnote}}
+
+\def\normalnoterule
+ {\ifvmode
+ \color
+ [\noteparameter\c!rulecolor]
+ {\hrule\!!width .2\hsize\!!height\noteparameter\c!rulethickness\!!depth \zeropoint}%
+ \kern\strutdepth
+ \fi}
+
+\ifx\setnotehsize\undefined
+
+ \def\setnotehsize{\hsize\noteparameter\c!width\relax} % can be overloaded
+
+\fi
+
+%D The formatting depends on the width of the table, so we
+%D have to set \type {n} to zero.
+%D
+%D \starttyping
+%D \startbuffer
+%D \bTABLE
+%D \bTR \bTD one \footnote{\dorecurse{10}{abcd }} \eTD \bTD two \eTD \eTR
+%D \bTR \bTD three fout five six seven eight nine \eTD \bTD ten \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \startlocalfootnotes[n=0,location={text,none}]
+%D \placelegend[n=2]{\getbuffer}{\placelocalfootnotes}
+%D \stoplocalfootnotes
+%D \stoptyping
+
+%D \macros
+%D {footnote}
+%D
+%D A footnote can have a reference as optional argument and
+%D therefore its formal specification looks like:
+%D
+%D \showsetup{footnote}
+%D
+%D This command has one optional command: the reference. By
+%D saying \type{[-]} the number is omitted. The footnote
+%D command is not that sensitive to spacing, so it's quite
+%D legal to say:
+%D
+%D \startbuffer
+%D Users of \CONTEXT\ must keep both feet \footnote{Given they
+%D have two.} on the ground and not get confused \footnote{Or
+%D even crazy.} by all those obscure \footnote{But fortunately
+%D readable.} parameters.
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D When setting the \type{conversion} to \type{set 2} we get
+%D something like:
+%D
+%D \bgroup
+%D \startnarrower
+%D \setupfootnotes[conversion=set 1]
+%D \getbuffer
+%D \stopnarrower
+%D \egroup
+%D
+%D Typesetting footnotes is, at least for the moment, disabled
+%D when reshaping boxes.
+%D
+%D The additional macro \type {\footnotetext} and the
+%D associated \type {\note} macro were implemented at
+%D request of users on the mailing list and a suggestion by
+%D taco to split of the symbol placement. I decided to
+%D merge this functionality with the existing \type {\note}
+%D functionality.
+
+%D The next implementation runs on top of enumerations (only in \MKIV).
+
+% TODO: \ifnotesenabled
+
+\newif\ifnotesymbol \notesymboltrue
+
+\def\setnote [#1]{\getvalue{#1}}
+\def\setnotetext[#1]{\global\settrue\skipnoteplacement\getvalue{#1}}
+
+\def\domovednote#1#2#3#4%
+ {\ifcase\ctxlua{structure.notes.deltapage("#1",#2)}\or\symbol[#3]\or\symbol[#4]\fi}
+
+\setvalue{\??dd:\v!note:\s!handler }{\@@doenumerationhandler}
+\setvalue{\??dd:\v!note:\s!handler:\s!do }{\@@somenotedescription}
+\setvalue{\??dd:\v!note:\s!handler:\s!start}{\@@startsomenotedescription}
+
+\def\@@somenotedescription {\@@notemakedescription}
+\def\@@startsomenotedescription{\@@notemakedescription}
+
+\newconditional\skipnoteplacement
+
+\def\@@notemakedescription[#1]#2#3% todo ... proper [key=value] etc
+ {\begingroup
+ \doenumerationcheckconditions
+ \let\currentnote\currentdescriptionmain
+ \dodescriptioncomponent[\c!reference=#1,\c!label={\descriptionparameter\c!text},\c!title={#3},\c!bookmark=,][]%
+ \xdef\currentnotenumber{\ctxlua{structure.notes.store("\currentnote",\currentdescriptionnumberentry)}}%
+ \settrue\processingnote
+ \ifconditional\skipnoteplacement
+ \globallet\lastnotesymbol\dolastnotesymbol
+ \else
+ \iftypesettinglines % otherwise problems with \type <crlf> {xxx}
+ \ignorelines % makes footnotes work in \startlines ... \stoplines
+ \fi
+ \ifnotesymbol
+ \dolastnotesymbol
+ \else
+ \unskip\unskip
+ \globallet\lastnotesymbol\dolastnotesymbol
+ \fi
+ \fi
+ \ifconditional\postponingnotes
+ \global\settrue\postponednote
+ \else
+ \handlenoteinsert\currentnote\currentnotenumber
+ \fi
+ \ifconditional\skipnoteplacement \else
+ \kern\notesignal\relax % \relax is needed to honor spaces
+ \iftrialtypesetting \else \global\setfalse\skipnoteplacement \fi
+ \fi
+ \endgroup}
+
+\def\dolastnotesymbol{\typesetsomenotesymbol\currentnote\currentnotenumber}
+
+\def\dotypesetsomenotesymbol#1#2%
+ {\dodonotesymbol
+ {\synchronizesomenotesymbol{#1}{#2}%
+ \ctxlua{structure.notes.number("\currentnote",\currentnotenumber)}% \currentdescriptionnumberentry
+ \domovednote{#1}{#2}\v!previouspage\v!nextpage}}
+
+\def\typesetsomenotesymbol#1#2%
+ {\removeunwantedspaces
+ \doifitalicelse\/\donothing % Charles IV \footnote{the fourth}
+ \ifdim\lastkern=\notesignal
+ \dodonotesymbol{\kern\noteparameter\c!distance}% gets the font right, hack !
+ \fi
+ \nobreak
+ \doifelse{\noteparameter\c!interaction}\v!no
+ {\dotypesetsomenotesymbol{#1}{#2}}
+ {\gotobox{\dotypesetsomenotesymbol{#1}{#2}}[page(\ctxlua{structure.notes.getnumberpage("#1",\number#2)})]}% f:
+ \globallet\lastnotesymbol\relax}
+
+\def\currentnotedescriptiontext % todo: can be other number
+ {\ctxlua{structure.notes.title("\currentnote",\currentdescriptionnumberentry)}}
+
+\def\currentnoteenumerationfullnumber
+ {\doifelse{\noteparameter\c!interaction}\v!no
+ {\docurrentnoteenumerationfullnumber}%
+ {\gotobox
+ {\docurrentnoteenumerationfullnumber}%
+ [page(\ctxlua{structure.notes.getsymbolpage("\currentnote",\currentdescriptionnumberentry)})]}}
+
+\def\docurrentnoteenumerationfullnumber
+ {\noteparameter\c!numbercommand
+ {\ctxlua{structure.notes.number("\currentnote",\currentdescriptionnumberentry)}%
+ \domovednote\currentdescription\currentdescriptionnumberentry\v!nextpage\v!previouspage}}
+
+\def\synchronizesomenotesymbol#1#2% called more often than needed
+ {\expanded{\noexpand\ctxlatelua{structure.notes.setsymbolpage("#1",#2)}}}
+
+\def\handlenoteinsert#1#2%
+ {\begingroup
+ \edef\currentnote{#1}%
+ \the\everybeforenoteinsert
+ \insert\currentnoteins\bgroup
+ \the\everyinsidenoteinsert
+ \handlenoteitself{#1}{#2}%
+ \egroup
+ \the\everyafternoteinsert
+ \endgroup}
+
+\def\handlenoteitself#1#2% tg, id
+ {\edef\currentdescription{#1}%
+ \edef\currentnote{#1}%
+ \edef\currentdescriptionnumberentry{#2}%
+ \let\currentdescriptiontext\currentnotedescriptiontext
+ \let\currentenumerationfullnumber\currentnoteenumerationfullnumber
+ \dostartstoreddescription\begstrut\currentnotedescriptiontext\endstrut\dostopstoreddescription}
+
+\def\dostartstoreddescription
+ {\bgroup\@@dostartdescriptionindeed}
+
+\def\dostopstoreddescription
+ {\@@stopdescription}
+
+%D The main typesetting routine is more or less the same as the
+%D \PLAIN\ \TEX\ one, except that we only handle one type while
+%D \PLAIN\ also has something \type{\v...}. In most cases
+%D footnotes can be handled by a straight insert, but we do so
+%D by using an indirect call to the \type{\insert} primitive.
+
+%D Making footnote numbers active is not always that logical,
+%D Making footnote numbers active is not always that logical,
+%D especially when we keep the reference and text at one page.
+%D On the other hand we need interactivity when we refer to
+%D previous notes or use end notes. Therefore we support
+%D interactive footnote numbers in two ways \footnote{This
+%D feature was implemented years after we were able to do so,
+%D mainly because endnotes had to be supported.} that is,
+%D automatically (vise versa) and by user supplied reference.
+
+\newcount\internalnotereference
+
+\let\startpushnote=\relax
+\let\stoppushnote =\relax
+
+\newsignal\notesignal
+\newcount \notepenalty
+
+\notepenalty=0 % needed in order to split in otrset
+
+\newconditional\processingnote
+\newconditional\postponednote
+
+\newtoks\everybeforenoteinsert
+\newtoks\everyinsidenoteinsert
+\newtoks\everyafternoteinsert
+
+\appendtoks
+ \let\doflushnotes\relax
+ \let\postponenotes\relax
+ \forgetall
+\to \everybeforenoteinsert
+
+\appendtoks
+ \doif{\noteparameter\c!scope}\v!page{\floatingpenalty\maxdimen}% experiment
+ \penalty\notepenalty
+ \forgetall
+ \setnotebodyfont
+ \redoconvertfont % to undo \undo calls in in headings etc
+ \splittopskip\strutht % not actually needed here
+ \splitmaxdepth\strutdp % not actually needed here
+ \leftmargindistance\noteparameter\c!margindistance
+ \rightmargindistance\leftmargindistance
+ \ifnum\noteparameter\c!n=\zerocount % no ifcase new 31-07-99 ; always ?
+ \doifnotinset{\noteparameter\c!width}{\v!fit,\v!broad}\setnotehsize % ?
+ \fi
+\to \everyinsidenoteinsert
+
+\let\lastnotesymbol\relax
+
+%D \macros
+%D {note}
+%D
+%D Refering to a note is accomplished by the rather short
+%D command:
+%D
+%D \showsetup{note}
+%D
+%D This command is implemented rather straightforward as:
+
+\def\notesymbol
+ {\dodoubleempty\donotesymbol}
+
+\def\donotesymbol[#1][#2]%
+ {\bgroup
+ \ifnotesenabled
+ \edef\currentnote{#1}%
+ \ifsecondargument
+ \unskip
+ \dodonotesymbol{\in[#2]}%
+ \else
+ \dodonotesymbol\lastnotesymbol
+ \fi
+ \fi
+ \egroup}
+
+\def\dodonotesymbol#1%
+ {\noteparameter\c!textcommand{\dosetnoteattributes\c!textstyle\c!textcolor#1}}
+
+%D Normally footnotes are saved as inserts that are called upon
+%D as soon as the pagebody is constructed. The footnote
+%D insertion routine looks just like the \PLAIN\ \TEX\ one,
+%D except that we check for the end note state.
+
+% testcase for split bottom alignment see (a) below
+%
+% \dorecurse{6}{\input tufte\footnote{\input ward \input tufte \relax}}
+
+\def\placenoteinserts
+ {\processnotes\doplacenoteinserts}
+
+\def\unvboxed {\ifvmode\unvbox \else\box \fi}
+\def\unvcopied{\ifvmode\unvcopy\else\copy\fi}
+
+\def\doplacenoteinserts
+ {\relax\ifdim\ht\currentnoteins>\zeropoint\relax
+ \ifnum\noteparameter\s!noteloc=\plusfive
+ \else
+ \endgraf
+ \ifvmode
+ \whitespace
+ \noteparameter\c!before
+ \fi
+ \placenoterule % alleen in ..mode
+ \bgroup
+ \setnotebodyfont
+ \setbox\scratchbox\hbox
+ {% this should be checked, smells like a mix-up
+ % does not split: \ifcase\noteparameter\c!n\unvbox\else\box\fi\currentnoteins
+ \ifcase\noteparameter\c!n\relax
+ \iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteins
+ \or
+ \iftrialtypesetting\copy\else\box\fi\currentnoteins
+ \obeydepth % (a) added , since split footnotes will not align properly
+ \else
+ \iftrialtypesetting\unvcopied\else\unvboxed\fi\currentnoteins
+ \fi}%
+ \setbox\scratchbox\hbox
+ {\localframed
+ [\??vn\currentnote]
+ [\c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!strut=\v!no,
+ \c!offset=\v!overlay]
+ {\ifdim\dp\scratchbox=\zeropoint % this hack is needed because \vadjust
+ \hbox{\lower\strutdp\box\scratchbox}% % in margin number placement
+ \else % hides the (always) present depth
+ \box\scratchbox
+ \fi}}%
+ \setbox\scratchbox\hbox{\lower\strutdepth\box\scratchbox}%
+ \dp\scratchbox\strutdepth % so we know that it has the note bodyfont depth
+ \box\scratchbox
+ \egroup
+ \endgraf
+ \ifvmode
+ \noteparameter\c!after
+ \fi
+ \fi
+ \fi}
+
+%D Supporting end notes is surprisingly easy. Even better, we
+%D can combine this feature with solving the common \TEX\
+%D problem of disappearing inserts when they're called for in
+%D deeply nested boxes. The general case looks like:
+%D
+%D \starttyping
+%D \postponenotes
+%D \.box{whatever we want with footnotes}
+%D \flushnotes
+%D \stoptyping
+%D
+%D This alternative can be used in headings, captions, tables
+%D etc. The latter one sometimes calls for notes local to
+%D the table, which can be realized by saying
+%D
+%D \starttyping
+%D \setlocalfootnotes
+%D some kind of table with local footnotes
+%D \placelocalfootnotes
+%D \stoptyping
+%D
+%D Postponing is accomplished by simply redefining the (local)
+%D insert operation. A not too robust method uses the
+%D \type{\insert} primitive when possible. This method fails in
+%D situations where it's not entirely clear in what mode \TEX\
+%D is. Therefore the auto method can is to be overruled when
+%D needed.
+
+\newconditional\postponingnotes
+
+% we need a proper state: normal, postponing, flushing
+
+\def\postponenotes
+ {\ifconditional\postponingnotes\else
+ \global\settrue\postponingnotes
+ \ctxlua{structure.notes.postpone()}%
+ \fi}
+
+% \def\flushnotes
+% {\ifconditional\processingnote \else
+% \ifconditional\postponednote
+% \ifinner \else
+% \ifinpagebody \else
+% %ifvmode % less interference, but also less secure
+% \doflushnotes
+% %fi
+% \fi
+% \fi
+% \fi
+% \fi}
+
+\def\flushnotes
+ {\ifconditional\postponednote
+ \flushnotesindeed
+ \fi}
+
+\def\flushnotesindeed
+ {\ifconditional\processingnote \else
+ \ifinner \else
+ \ifinpagebody \else
+ %ifvmode % less interference, but also less secure
+ \doflushnotes
+ %fi
+ \fi
+ \fi
+ \fi}
+
+\def\doflushnotes % also called directly, \ifvoid is needed !
+ {\begingroup
+ \let\doflushnotes\relax
+ \let\postponenotes\relax
+ \ifconditional\processingnote \else
+ \ifconditional\postponednote
+ \processnotes\dodoflushnotes
+ \global\setfalse\postponednote
+ \setfalse\postponingnotes
+ \fi
+ \fi
+ \endgroup}
+
+\def\dodoflushnotes % per class, todo: handle endnotes here
+ {%\writestatus{notes}{flushing \currentnote}%
+ \global\setfalse\postponingnotes
+ \ctxlua{structure.notes.flush("\currentnote","postpone")}}
+
+%D \macros
+%D {startlocalfootnotes,placelocalfootnotes}
+%D
+%D The next two macros can be used in for instance tables, as
+%D we'll demonstrate later on.
+%D
+%D \showsetup{startlocalfootnotes}
+%D \showsetup{placelocalfootnotes}
+
+% todo: compatibility mode: when first arg is assignment or missing, then all
+
+\newtoks\everyplacelocalnotes
+
+\appendtoks
+ \let\doflushnotes\relax
+ \let\postponenotes\relax
+\to \everyplacelocalnotes
+
+\def\defaultnotewidth{\makeupwidth} % {\ifdim\hsize<\makeupwidth\hsize\else\makeupwidth\fi}
+
+\def\startlocalnotes
+ {\dosingleempty\dostartlocalnotes}
+
+\def\dostartlocalnotes[#1]%
+ {\def\localnoteslist{#1}%
+ \processcommacommand[\localnoteslist]\dodostartlocalnotes}
+
+\def\stoplocalnotes
+ {\processcommacommand[\localnoteslist]\dodostoplocalnotes}
+
+\def\dodostartlocalnotes#1%
+ {\savestructurecounter[#1]%
+ \resetstructurecounter[#1]%
+ \ctxlua{structure.notes.save("#1","store")}}
+
+\def\dodostoplocalnotes#1%
+ {\restorestructurecounter[#1]%
+ \ctxlua{structure.notes.restore("#1")}}
+
+\def\placelocalnotes
+ {\dodoubleempty\doplacelocalnotes}
+
+\def\doplacelocalnotes[#1][#2]%
+ {\doif{\ctxlua{structure.notes.getstate("#1")}}{store}{\dodoplacelocalnotes{#2}{#1}}}
+
+\def\dodoplacelocalnotes#1#2% settings note
+ {\begingroup
+ \the\everyplacelocalnotes
+ % beware, we cannot trust setting \currentnote here
+ \getparameters[\??vn#2][\c!width=\v!fit,\c!height=\v!fit,\c!strut=\v!no,\c!offset=\v!overlay,#1]% we only need a selective one
+ \donotealternative{#2}%
+ \endgroup
+ \dochecknote} % we need to restore the old state
+
+%D These commands can be used like:
+%D
+%D \startbuffer
+%D \startlocalnotes[width=.3\hsize,n=0]
+%D \placetable
+%D {Some Table}
+%D \placeontopofeachother
+%D {\starttable[|l|r|]
+%D \HL
+%D \VL Nota\footnote{Bene} \VL Bene\footnote{Nota} \VL\SR
+%D \VL Bene\footnote{Nota} \VL Nota\footnote{Bene} \VL\SR
+%D \HL
+%D \stoptable}
+%D {\placelocalnotes}
+%D \stoplocalnotes
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Because this table placement macro expect box content, and
+%D thanks to the grouping of the local footnotes, we don't need
+%D additional braces.
+%D
+%D \getbuffer
+
+%D \macros
+%D {placefootnotes}
+%D
+%D We still have no decent command for placing footnotes
+%D somewhere else than at the bottom of the page (for which no
+%D user action is needed). Footnotes (endnotes) can be
+%D placed by using
+%D
+%D \showsetup{placefootnotes}
+
+\def\placebottomnotes
+ {\processnotes\placenoteinserts}
+
+\def\placenotes
+ {\dodoubleempty\doplacenotes}
+
+\def\doplacenotes[#1][#2]%
+ {\processcommalist[#1]{\dodoplacenotes{#2}}}
+
+\def\dodoplacenotes#1#2% settings note
+ {\edef\currentnote{#2}%
+ \doifelse{\ctxlua{structure.notes.getstate("#1")}}{store}
+ \dodoplacelocalnotes
+ \dodoplaceglobalnotes
+ {#1}{#2}}
+
+\def\dodoplaceglobalnotes#1#2%
+ {\begingroup
+ \setupnote[#2][#1]%
+ \doplacenoteinserts
+ \endgroup
+ \the\everysetupnote} % to be checkes
+
+%D Placement
+
+\long\def\installnotealternative#1#2%
+ {\setvalue{\??vn:\c!alternative:#1}{#2}}
+
+\def\doifnotescollected#1%
+ {\ctxlua{structure.notes.doifcontent("#1")}}
+
+\def\donotealternative#1%
+ {\edef\currentnote{#1}%
+ \doifnotescollected\currentnote
+ {\endgraf
+ \ifvmode
+ \whitespace
+ \noteparameter\c!before
+ \fi
+ \begingroup
+ \setnotebodyfont
+ \getvalue{\??vn:\c!alternative:\noteparameter\c!alternative}%
+ \endgroup
+ \ifvmode
+ \noteparameter\c!after
+ \fi}}
+
+\setvalue{\??vn:\c!alternative:}{\getvalue{\??vn:\c!alternative:\v!none}}
+
+%D A stupid alternative is also provided:
+%D
+%D \starttyping
+%D \setupfootnotes[location=text,alternative=none]
+%D \stoptyping
+
+\def\flushlocalnotes#1{\ctxlua{structure.notes.flush("#1","store")}}
+
+\installnotealternative \v!none
+ {\flushlocalnotes\currentnote}
+
+\installnotealternative \v!grid % test if n > 0
+ {\snaptogrid\hbox
+ {\localframed
+ [\??vn\currentnote]
+ {\flushlocalnotes\currentnote}}}
+
+\installnotealternative \v!fixed % test if n > 0
+ {\localframed
+ [\??vn\currentnote]
+ {\flushlocalnotes\currentnote}}
+
+\installnotealternative \v!columns % redundant
+ {\localframed
+ [\??vn\currentnote]
+ {\edef\currentnotewidth{\noteparameter\c!width}%
+ \doifdimensionelse\currentnotewidth\donothing
+ {\edef\currentnotewidth{\the\hsize}}%
+% \setupinmargin[\c!align=\v!left]%
+ \startsimplecolumns[\c!distance=\noteparameter\c!columndistance,\c!n=\noteparameter\c!n,\c!width=\currentnotewidth]%
+ \flushlocalnotes\currentnote
+ \stopsimplecolumns}}
+
+%D \macros
+%D {fakenotes}
+
+ \def\fakenotes
+ {\ifhmode\endgraf\fi\ifvmode
+ \calculatetotalclevernoteheight
+ \ifdim\totalnoteheight>\zeropoint \kern\totalnoteheight \fi
+ \fi}
+
+ \def\fakepagenotes
+ {\ifhmode\endgraf\fi\ifvmode
+ \calculatetotalpagenoteheight
+ \ifdim\totalnoteheight>\zeropoint \kern\totalnoteheight \fi
+ \fi}
+
+ \newdimen\totalnoteheight
+
+ \def\doaddtototalnoteheight#1%
+ {\ifdim\ht#1>\zeropoint
+ \advance\totalnoteheight\ht #1%
+ \advance\totalnoteheight\skip#1%
+ \fi}
+
+ \def\docalculatetotalnoteheight
+ {\ifcase\clevernotes % tricky here ! ! ! to be sorted out ! ! !
+ \doaddtototalnoteheight\currentnoteins
+ \else
+ \doaddtototalnoteheight\currentbackupnoteins
+ \fi}
+
+ \def\docalculatetotalclevernoteheight
+ {\ifcase\clevernotes \else % tricky here ! ! ! to be sorted out ! ! !
+ \doaddtototalnoteheight\currentnoteins
+ \fi}
+
+ \def\docalculatetotalpagenoteheight
+ {\doaddtototalnoteheight\currentnoteins}
+
+ \def\calculatetotalnoteheight {\totalnoteheight\zeropoint\processnotes\docalculatetotalnoteheight}
+ \def\calculatetotalclevernoteheight{\totalnoteheight\zeropoint\processnotes\docalculatetotalclevernoteheight}
+ \def\calculatetotalpagenoteheight {\totalnoteheight\zeropoint\processnotes\docalculatetotalpagenoteheight}
+
+ \newif\ifnotespresent
+
+ \def\dochecknotepresence
+ {\ifdim\ht\currentnoteins>\zeropoint
+ \notespresenttrue
+ \fi}
+
+ \def\checknotepresence
+ {\notespresentfalse
+ \processnotes\dochecknotepresence}
+
+%D Now how can this mechanism be hooked into \CONTEXT\ without
+%D explictly postponing footnotes? The solution turned out to
+%D be rather simple:
+%D
+%D \starttyping
+%D \everypar {...\flushnotes...}
+%D \neverypar {...\postponenotes}
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D \def\ejectinsert%
+%D {...
+%D \flushnotes
+%D ...}
+%D \stoptyping
+%D
+%D We can use \type{\neverypar} because in most commands
+%D sensitive to footnote gobbling we disable \type{\everypar}
+%D in favor for \type{\neverypar}. In fact, this footnote
+%D implementation is the first to use this scheme.
+
+%D This is a nasty and new secondary footnote flusher. It
+%D can be hooked into \type {\everypar} like:
+%D
+%D \starttyping
+%D \appendtoks \synchronizenotes \to \everypar
+%D \stoptyping
+
+ % \def\dosynchronizenotes
+ % {\ifvoid\currentnoteins\else\insert\currentnoteins{\unvbox\currentnoteins}\fi}
+ %
+ % \def\synchronizenotes
+ % {\processnotes\dosynchronizenotes}
+
+\let\synchronizenotes\relax
+
+%D When typesetting footnotes, we have to return to the
+%D footnote specific bodyfont size, which is in most cases derived
+%D from the global document bodyfont size. In the previous macros
+%D we already used a footnote specific font setting macro.
+
+\def\setnotebodyfont
+ {\let\setnotebodyfont\relax
+ \restoreglobalbodyfont
+ \switchtobodyfont[\noteparameter\c!bodyfont]%
+ \setuptolerance[\noteparameter\c!tolerance]%
+ \setupalign[\noteparameter\c!align]}
+
+%D The footnote mechanism defaults to a traditional one
+%D column way of showing them. By default we precede them by
+%D a small line.
+
+\ifx\v!endnote\undefined \def\v!endnote{endnote} \fi
+
+\definenote [\v!footnote]
+\definenote [\v!endnote ] [\c!location=\v!none] % else no break
+
+%D Compatibility macros:
+
+ \def\setupfootnotedefinition{\setupnotedefinition [\v!footnote]}
+ \def\setupfootnotes {\setupnote [\v!footnote]}
+%unexpanded \def\footnote {\setnote [\v!footnote]}
+\unexpanded \def\footnotetext {\setnotetext [\v!footnote]}
+ %def\note {\dodoubleempty\notesymbol [\v!footnote]} % alleen footnote
+ \def\placefootnotes {\dodoubleempty\doplacefootnotes [\v!footnote]}
+ \def\placelocalfootnotes {\dodoubleempty\doplacelocalfootnotes[\v!footnote]}
+ \def\startlocalfootnotes {\startlocalnotes [\v!footnote]} % alleen footnote
+ \def\stoplocalfootnotes {\stoplocalnotes }
+ \def\flushfootnotes {\flushnotes}
+ \def\doflushfootnotes {\doflushnotes}
+
+\def\doplacefootnotes [#1][#2]{\ifsecondargument\placenotes [#1][#2,\c!height=\textheight]\else\placenotes [#1]\fi}
+\def\doplacelocalfootnotes[#1][#2]{\ifsecondargument\placelocalnotes[#1][#2,\c!height=\textheight]\else\placelocalnotes[#1]\fi}
+
+\def\note{\dodoubleempty\donote}
+
+\def\donote[#1][#2]{\ifsecondargument\donotesymbol[#1][#2]\else\secondargumenttrue\donotesymbol[\v!footnote][#1]\fi}
+
+%D New trickery:
+
+\def\ownnotesymbol#1% #1 gets number passed
+ {\executeifdefined{\??vn::\currentnote}\empty}
+
+\def\setnotesymbol[#1]#2#3%
+ {\prewordbreak % prevent lookback
+ \setgvalue{\??vn::#1}{#3}
+ \dolastnotesymbol}
+
+\def\ownnote[#1]#2#3#4%
+ {\setnotesymbol[#1]{#2}{#3}%
+ \setnotetext [#1]{#4}}
+
+\defineconversion
+ [ownnote]
+ [\ownnotesymbol]
+
+\protect \endinput
diff --git a/tex/context/base/strc-num.lua b/tex/context/base/strc-num.lua
new file mode 100644
index 000000000..8918346c6
--- /dev/null
+++ b/tex/context/base/strc-num.lua
@@ -0,0 +1,457 @@
+if not modules then modules = { } end modules ['strc-num'] = {
+ version = 1.001,
+ comment = "companion to strc-num.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+local next, type = next, type
+local texsprint = tex.sprint
+
+structure = structure or { }
+structure.helpers = structure.helpers or { }
+structure.sections = structure.sections or { }
+structure.counters = structure.counters or { }
+structure.documents = structure.documents or { }
+
+structure.counters = structure.counters or { }
+structure.counters.data = structure.counters.data or { }
+
+local helpers = structure.helpers
+local sections = structure.sections
+local counters = structure.counters
+local documents = structure.documents
+
+local variables = interfaces.variables
+
+-- state: start stop none reset
+
+local counterdata = counters.data
+local counterranges, tbs = { }, 0
+
+counters.collected = counters.collected or { }
+counters.tobesaved = counters.tobesaved or { }
+
+storage.register("structure/counters/data", structure.counters.data, "structure.counters.data")
+storage.register("structure/counters/tobesaved", structure.counters.tobesaved, "structure.counters.tobesaved")
+
+local collected, tobesaved = counters.collected, counters.tobesaved
+
+local function finalizer()
+ local ct = counters.tobesaved
+ for name, cd in next, counterdata do
+ local cs = tobesaved[name]
+ local data = cd.data
+ for i=1,#data do
+ local d = data[i]
+ local r = d.range
+ cs[i][r] = d.number
+ d.range = r + 1
+ end
+ end
+end
+
+local function initializer()
+ collected, tobesaved = counters.collected, counters.tobesaved
+end
+
+if job then
+ job.register('structure.counters.collected', structure.counters.tobesaved, initializer, finalizer)
+end
+
+local function constructor(t,s,name,i)
+ if s == "last" then
+ local cc = collected[name]
+ t.stop = (cc and cc[i] and cc[i][t.range]) or 0 -- stop is available for diagnostics purposes only
+ if t.offset then
+ return t.stop - t.step
+ else
+ return t.stop
+ end
+ elseif s == "first" then
+ if t.offset then
+ return t.start + t.step + 1
+ else
+ return t.start + 1
+ end
+ elseif s == "prev" or s == "previous" then
+ return math.max(t.first,t.number-1) -- todo: step
+ elseif s == "next" then
+ return math.min(t.last,t.number+1) -- todo: step
+ elseif s == "subs" then
+ local cc = collected[name]
+ t.subs = (cc and cc[i+1] and cc[i+1][t.range]) or 0
+ return t.subs
+ else
+ return nil -- was 0, but that is fuzzy in testing for e.g. own
+ end
+end
+
+local enhance = function()
+ for name, cd in next, counterdata do
+ local data = cd.data
+ for i=1,#data do
+ local ci = data[i]
+ setmetatable(ci, { __index = function(t,s) return constructor(t,s,name,i) end })
+ end
+ end
+ enhance = nil
+end
+
+local function allocate(name,i)
+ local cd = counterdata[name]
+ if not cd then
+ cd = {
+ level = 1,
+ numbers = nil,
+ state = interfaces.variables.start, -- true
+ data = { }
+ }
+ tobesaved[name] = { }
+ counterdata[name] = cd
+ end
+ cd = cd.data
+ local ci = cd[i]
+ if not ci then
+ ci = {
+ number = 0,
+ start = 0,
+ saved = 0,
+ step = 1,
+ range = 1,
+ offset = false,
+ -- via metatable: last, first, and for tracing:
+ stop = 0,
+ }
+ setmetatable(ci, { __index = function(t,s) return constructor(t,s,name,i) end })
+ cd[i] = ci
+ tobesaved[name][i] = { }
+ else
+ if enhance then enhance() end -- not stored in bytecode
+ end
+ return ci
+end
+
+local function savevalue(name,i)
+ local cd = counterdata[name].data[i]
+ local cs = tobesaved[name][i]
+ local cc = collected[name]
+ local cr = cd.range
+ local old = (cc and cc[i] and cc[i][cr]) or 0
+ cs[cr] = cd.number
+ cd.range = cr + 1
+ return old
+end
+
+function counters.define(name, start, counter) -- todo: step
+ local d = allocate(name,1)
+ d.start = start
+ if counter and counter > 0 then
+ d.counter = counter -- only for special purposes
+ end
+end
+
+function counters.trace(name)
+ local cd = counterdata[name]
+ if cd then
+ texsprint(format("[%s:",name))
+ local data = cd.data
+ for i=1,#data do
+ local d = data[i]
+ texsprint(format(" (%s: %s,%s,%s s:%s r:%s)",i,(d.start or 0),d.number or 0,d.last,d.step or 0,d.range or 0))
+ end
+ texsprint("]")
+ end
+end
+
+function counters.raw(name)
+ return counterdata[name]
+end
+
+function counters.compact(name,level,onlynumbers)
+ local cd = counterdata[name]
+--~ print(name,cd)
+ if cd then
+ local data = cd.data
+ local compact = { }
+ for i=1,level or #data do
+ local d = data[i]
+ if d.number ~= 0 then
+ compact[i] = (onlynumbers and d.number) or d
+ end
+ end
+ return compact
+ end
+end
+
+-- depends on when incremented, before or after (driven by d.offset)
+
+function counters.doifelse(name)
+ commands.doifelse(counterdata[name])
+end
+
+function counters.previous(name,n)
+ texsprint(allocate(name,n).previous)
+end
+
+function counters.next(name,n)
+ texsprint(allocate(name,n).next)
+end
+
+counters.prev = counters.previous
+
+function counters.current(name,n)
+ texsprint(allocate(name,n).number)
+end
+
+function counters.first(name,n)
+ texsprint(allocate(name,n).first)
+end
+
+function counters.last(name,n)
+ texsprint(allocate(name,n).last)
+end
+
+function counters.subs(name,n)
+ texsprint(counterdata[name].data[n].subs or 0)
+end
+
+function counters.setvalue(name,tag,value)
+ local cd = counterdata[name]
+ if cd then
+ cd[tag] = value
+ end
+end
+
+function counters.setstate(name,value) -- true/false
+ value = interfaces.variables[value]
+ if value then
+ counters.setvalue(name,"state",value)
+ end
+end
+
+function counters.setlevel(name,value)
+ counters.setvalue(name,"level",value)
+end
+
+function counters.setoffset(name,value)
+ counters.setvalue(name,"offset",value)
+end
+
+function counters.reset(name,n)
+ local cd = counterdata[name]
+ if cd then
+ for i=n or 1,#cd.data do
+ local d = cd.data[i]
+ savevalue(name,i)
+ d.number = d.start or 0
+ d.own = nil
+ -- if d.counter then tex.count[d.counter] = d.number end
+ end
+ cd.numbers = nil
+ end
+end
+
+function counters.set(name,n,value)
+ local cd = counterdata[name]
+ if cd then
+ local d = allocate(name,n)
+ d.number = value or 0
+ d.own = nil
+ -- if d.counter then tex.count[d.counter] = d.number end
+ end
+end
+
+local function check(name,data,start,stop)
+ for i=start or 1,stop or #data do
+ local d = data[i]
+ savevalue(name,i)
+ d.number = d.start or 0
+ d.own = nil
+ -- if d.counter then tex.count[d.counter] = d.number end
+ end
+end
+
+function counters.setown(name,n,value)
+ local cd = counterdata[name]
+ if cd then
+ local d = allocate(name,n)
+ d.own = value
+ d.number = (d.number or d.start or 0) + (d.step or 0)
+ if cd.level and cd.level > 0 then -- 0 is signal that we reset manually
+ check(name,data,n+1) -- where is check defined
+ end
+ end
+end
+
+function counters.restart(name,n,newstart)
+ local cd = counterdata[name]
+ if cd then
+ newstart = tonumber(newstart)
+ if newstart then
+ local d = allocate(name,n)
+ d.start = newstart
+ counters.reset(name,n)
+ end
+ end
+end
+
+function counters.save(name) -- or just number
+ local cd = counterdata[name]
+ if cd then
+ cd.saved = table.copy(cd.data)
+ end
+end
+
+function counters.restore(name)
+ local cd = counterdata[name]
+ if cd and cd.saved then
+ cd.data = cd.saved
+ cd.saved = nil
+ end
+end
+
+function counters.add(name,n,delta)
+ local cd = counterdata[name]
+ if cd and cd.state == interfaces.variables.start then
+ local data = cd.data
+ local d = allocate(name,n)
+ d.number = (d.number or d.start or 0) + delta*(d.step or 0)
+ if cd.level and cd.level > 0 then -- 0 is signal that we reset manually
+ check(name,data,n+1)
+ end
+ return d.number
+ end
+ return 0
+end
+
+function counters.check(level)
+ for _, v in next, counterdata do
+ if v.level == level then -- is level for whole counter!
+ local data = v.data
+ check(name,data)
+ end
+ end
+end
+
+function counters.get(name,n,key)
+ local d = allocate(name,n)
+ d = d and d[key]
+ if not d then
+ return 0
+ elseif type(d) == "function" then
+ return d()
+ else
+ return d
+ end
+end
+
+function counters.value(name,n) -- what to do with own
+ tex.write(counters.get(name,n or 1,'number') or 0)
+end
+
+function counters.converted(name,spec) -- name can be number and reference to storage
+ local cd
+ if type(name) == "number" then
+ cd = specials.retrieve("counter",name)
+ cd = cd and cd.counter
+ else
+ cd = counterdata[name]
+ end
+ if cd then
+ local vars = interfaces.variables
+ local spec = spec or { }
+ local numbers, ownnumbers = { }, { }
+ local reverse = spec.order == vars["reverse"]
+ local kind = spec.type or "number"
+ local v_first, v_next, v_previous, v_last = vars.first, vars.next, vars.previous, vars.last
+ local data = cd.data
+ for k=1,#data do
+ local v = data[k]
+ -- somewhat messy, what if subnr? only last must honour kind?
+ local vn
+ if v.own then
+ numbers[k], ownnumbers[k] = v.number, v.own
+ else
+ if kind == v_first then
+ vn = v.first
+ elseif kind == v_next then
+ vn = v.next
+ elseif kind == v_previous then
+ vn = v.prev
+ elseif kind == v_last then
+ vn = v.last
+ else
+ vn = v.number
+ if reverse then
+ local vf = v.first
+ local vl = v.last
+ if vl > 0 then
+ vn = vl - vn + 1 + vf
+ end
+ end
+ end
+ numbers[k], ownnumbers[k] = vn or v.number, nil
+ end
+ end
+ cd.numbers = numbers
+ cd.ownnumbers = ownnumbers
+ sections.typesetnumber(cd,'number',spec)
+ cd.numbers = nil
+ cd.ownnumbers = nil
+ end
+end
+
+-- move to strc-pag.lua
+
+function counters.analyse(name,counterspecification)
+ local cd = counterdata[name]
+ -- safeguard
+ if not cd then
+ return false, false, "no counter data"
+ end
+ -- section data
+ local sectiondata = sections.current()
+ if not sectiondata then
+ return cd, false, "not in section"
+ end
+ local references = sectiondata.references
+ if not references then
+ return cd, false, "no references"
+ end
+ local section = references.section
+ if not section then
+ return cd, false, "no section"
+ end
+ sectiondata = jobsections.collected[references.section]
+ if not sectiondata then
+ return cd, false, "no section data"
+ end
+ -- local preferences
+ local no = variables.no
+ if counterspecification and counterspecification.prefix == no then
+ return cd, false, "current spec blocks prefix"
+ end
+ -- stored preferences (not used)
+ if cd.prefix == no then
+ return cd, false, "entry blocks prefix"
+ end
+ -- sectioning
+ -- if sectiondata.prefix == no then
+ -- return false, false, "sectiondata blocks prefix"
+ -- end
+ -- final verdict
+ return cd, sectiondata, "okay"
+end
+
+function counters.prefixedconverted(name,prefixspec,numberspec)
+ local cd, prefixdata, result = counters.analyse(name,prefixspec)
+ if cd then
+ if prefixdata then
+ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,cd or false)
+ end
+ counters.converted(name,numberspec)
+ end
+end
diff --git a/tex/context/base/strc-num.tex b/tex/context/base/strc-num.tex
new file mode 100644
index 000000000..8b723575b
--- /dev/null
+++ b/tex/context/base/strc-num.tex
@@ -0,0 +1,440 @@
+%D \module
+%D [ file=strc-num,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Basic Numbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Basic Numbering}
+
+\registerctxluafile{strc-num}{1.001}
+
+\unprotect
+
+% we need to rework this, i.e. clone like itm, des etc with \s!parent
+
+% numbering
+
+% \definestructurecounter[name]
+% \setupstructurecounter[name][wijze=,blok=,tekst=,plaats=,conversie=,start=]
+% \setstructurecounter[name]{value}
+% \resetstructurecounter[name]
+% \incrementstructurecounter[name]
+% \decrementstructurecounter[name]
+% \savestructurecounter[name]
+% \restorestructurecounter[name]
+% \convertedstructurecounter[name] % depricated: \getstructurecounter[name]
+% \rawstructurecounter[name]
+
+% private (defined in core-sec.tex)
+%
+% \nextstructurecounter[name][tag][reference]
+% \currentstructurecounter[name]
+
+% todo: better inheritane system
+
+\definesystemvariable {nn}
+
+\def\setupstructurecountering{\dodoubleempty\getparameters[\??nn]}
+
+\setupstructurecountering
+ [\c!way=\v!by\v!chapter,
+% \c!blockway=,
+% \c!prefixstopper=,
+\c!prefixconnector=.,
+\c!prefixsegments=\thenamedstructurecounterlevel\currentstructurecounter,
+\c!start=0,
+\c!state=\v!start,
+ \c!prefix=\v!yes,
+ \c!state=\v!start]
+
+% \letvalue{\??nn\s!empty}\empty
+
+\def\structurecounterparameter#1#2%
+ {\csname
+ \ifcsname\??nn#1#2\endcsname
+ \??nn#1#2%
+ \else\ifcsname\??nn\@@thestructurecounter{#1}#2\endcsname
+ \??nn\@@thestructurecounter{#1}#2%
+ \else\ifcsname\??nn#2\endcsname
+ \??nn#2%
+ \else
+ \s!empty
+ \fi\fi\fi
+ \endcsname}
+
+\def\@@thestructurecounter#1%
+ {\ifcsname\??nn#1\c!number\endcsname
+ \expandafter\@@thestructurecounter\csname\??nn#1\c!number\endcsname
+ \else
+ #1%
+ \fi}
+
+% \def\structurecounterparameter #1#2{\csname\dostructurecounterparameter{\??nn#1}#2\endcsname}
+% \def\dostructurecounterparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dostructurecounterparentparameter\csname#1\s!number\endcsname#2\fi}
+% \def\dostructurecounterparentparameter#1#2{\ifx#1\relax\s!empty\else\dostructurecounterparameter#1#2\fi}
+
+%
+
+\def\definestructurecounter
+ {\dodoubleempty\dodefinestructurecounter}
+
+\def\dodefinestructurecounter[#1][#2]%
+ {\doifassignmentelse{#2}
+ {\dododefinestructurecounter[#1][#2]}
+ {\doifelsenothing{#2}
+ {\dododefinestructurecounter[#1][]}
+ {\donodefinestructurecounter[#1][#2]}}}
+
+\def\dododefinestructurecounter[#1][#2]%
+ {\getparameters
+ [\??nn#1]
+ [\s!counter=,#2]% counter is for internal purposes
+ \ctxlua{structure.counters.define("#1",
+ tonumber("\structurecounterparameter{#1}\c!start") or 0,
+ tonumber("\structurecounterparameter{#1}\s!counter") or 0
+ )}%
+ \docheckstructurecountersetup{#1}}
+
+\def\donodefinestructurecounter[#1][#2]%
+ {\getparameters[\??nn#1][\c!number=#2]%
+ \docheckstructurecountersetup{#1}}
+
+\def\setupstructurecounter
+ {\dodoubleargument\dosetupstructurecounter}
+
+\def\dosetupstructurecounter[#1][#2]%
+ {\getparameters[\??nn#1][\c!start=,#2]%
+ \docheckstructurecountersetup{#1}}
+
+\def\structurecounterway#1% slow, we need to store it at the tex end
+ {\ctxlua{structure.sections.way("\structurecounterparameter{#1}\c!way","\v!by")}}
+
+\def\thenamedstructurecounterlevel#1%
+% {\thenamedstructureheadlevel{\structurecounterway{\structurecounterparameter{#1}\c!way}}}
+ {\thenamedstructureheadlevel{\structurecounterway{#1}}}
+
+\def\docheckstructurecountersetup#1%
+ {% this can be done at the lua end / a bit messy here ... todo ...
+ \ifcsname\??nn#1\c!number\endcsname
+ \doifelsevalue {\??nn#1\c!number}{#1} {\letbeundefined{\??nn#1\c!number}}%
+ {\doifvaluenothing{\??nn#1\c!number} {\letbeundefined{\??nn#1\c!number}}}%
+ \fi
+ \ifcsname\??nn#1\c!number\endcsname
+ % it's a clone
+ \else
+ \edef\currentstructurecounterlevel{\thenamedstructurecounterlevel{#1}}%
+ \ctxlua{
+ structure.counters.restart("#1",1,"\structurecounterparameter{#1}\c!start")
+ structure.counters.setstate("#1","\structurecounterparameter{#1}\c!state")
+ structure.counters.setlevel("#1",\currentstructurecounterlevel)
+ structure.sections.setchecker("#1",\currentstructurecounterlevel,structure.counters.reset)
+ }%
+ \fi}
+
+\def\doifstructurecounterelse#1{\ctxlua{structure.counters.doifelse("\@@thestructurecounter{#1}")}}
+\def\doifstructurecounter #1{\ctxlua{structure.counters.doif ("\@@thestructurecounter{#1}")}}
+\def\doifnotstructurecounter #1{\ctxlua{structure.counters.doifnot ("\@@thestructurecounter{#1}")}}
+
+\def\setstructurecounter [#1]#2{\ctxlua{structure.counters.set ("\@@thestructurecounter{#1}",1,\number#2)}}
+\def\setstructurecounterown [#1]#2{\ctxlua{structure.counters.setown ("\@@thestructurecounter{#1}",1,"#2")}}
+\def\resetstructurecounter [#1]{\ctxlua{structure.counters.reset ("\@@thestructurecounter{#1}",1)}}
+\def\restartstructurecounter [#1]#2{\ctxlua{structure.counters.restart("\@@thestructurecounter{#1}",1,#2)}}
+\def\savestructurecounter [#1]{\ctxlua{structure.counters.save ("\@@thestructurecounter{#1}")}}
+\def\restorestructurecounter [#1]{\ctxlua{structure.counters.restore("\@@thestructurecounter{#1}")}}
+\def\incrementstructurecounter [#1]{\ctxlua{structure.counters.add ("\@@thestructurecounter{#1}",1,1)}}
+\def\decrementstructurecounter [#1]{\ctxlua{structure.counters.add ("\@@thestructurecounter{#1}",1,-1)}}
+\def\rawstructurecounter [#1]{\ctxlua{structure.counters.value ("\@@thestructurecounter{#1}",1)}}
+\def\laststructurecounter [#1]{\ctxlua{structure.counters.last ("\@@thestructurecounter{#1}",1)}}
+\def\firststructurecounter [#1]{\ctxlua{structure.counters.first ("\@@thestructurecounter{#1}",1)}}
+\def\nextstructurecounter [#1]{\ctxlua{structure.counters.next ("\@@thestructurecounter{#1}",1)}}
+\def\prevstructurecounter [#1]{\ctxlua{structure.counters.prev ("\@@thestructurecounter{#1}",1)}}
+\def\structurecountersubs [#1]{\ctxlua{structure.counters.subs ("\@@thestructurecounter{#1}",1)}}
+
+\def\tracestructurecounter [#1]{\ctxlua{structure.counters.trace ("\@@thestructurecounter{#1}")}}
+
+\def\incrementedstructurecounter[#1]{\ctxlua{tex.write(structure.counters.add("\@@thestructurecounter{#1}",1,1))}}
+\def\decrementedstructurecounter[#1]{\ctxlua{tex.write(structure.counters.add("\@@thestructurecounter{#1}",1,-1))}}
+
+\def\setsubstructurecounter {\dodoubleargument\dosetsubstructurecounter}
+\def\setsubstructurecounterown {\dodoubleargument\dosetsubstructurecounterown}
+\def\resetsubstructurecounter {\dodoubleargument\doresetsubstructurecounter}
+\def\restartsubstructurecounter {\dodoubleargument\dorestartsubstructurecounter}
+\def\incrementsubstructurecounter {\dodoubleargument\doincrementsubstructurecounter}
+\def\decrementsubstructurecounter {\dodoubleargument\dodecrementsubstructurecounter}
+\def\rawsubstructurecounter {\dodoubleargument\dorawsubstructurecounter}
+
+\def\dosetsubstructurecounter [#1][#2]#3{\ctxlua{structure.counters.set ("\@@thestructurecounter{#1}",#2,\number#3)}}
+\def\dosetsubstructurecounterown [#1][#2]#3{\ctxlua{structure.counters.setown ("\@@thestructurecounter{#1}",#2,"#3")}}
+\def\doresetsubstructurecounter [#1][#2]{\ctxlua{structure.counters.reset ("\@@thestructurecounter{#1}",#2)}}
+\def\dorestartsubstructurecounter [#1][#2]#3{\ctxlua{structure.counters.restart("\@@thestructurecounter{#1}",#2,#3)}}
+\def\doincrementsubstructurecounter [#1][#2]{\ctxlua{structure.counters.add ("\@@thestructurecounter{#1}",#2,1)}}
+\def\dodecrementsubstructurecounter [#1][#2]{\ctxlua{structure.counters.add ("\@@thestructurecounter{#1}",#2,-1)}}
+\def\dorawsubstructurecounter [#1][#2]{\ctxlua{structure.counters.value ("\@@thestructurecounter{#1}",#2)}}
+\def\dolastsubstructurecounter [#1][#2]{\ctxlua{structure.counters.last ("\@@thestructurecounter{#1}",#2)}}
+\def\dofirstsubstructurecounter [#1][#2]{\ctxlua{structure.counters.first ("\@@thestructurecounter{#1}",#2)}}
+\def\dosubstructurecountersubs [#1][#2]{\ctxlua{structure.counters.subs ("\@@thestructurecounter{#1}",#2)}}
+
+% The bypage check needs a multipass reference and therefore
+% we only check for it when we increment and know that some
+% content will be placed. We could also check for spreads.
+
+% to be checked !
+
+\def\docheckstructurecounterbypage#1% since we call lua to get the way we can as well do all in lua
+ {\doif{\structurecounterway{#1}}\v!page{\checkpagechange{#1}\ifpagechanged\resetstructurecounter[#1]\fi}}
+
+\def\incrementstructurecounter[#1]%
+ {\docheckstructurecounterbypage{#1}%
+ \ctxlua{structure.counters.add("\@@thestructurecounter{#1}",1,1)}}
+
+\def\doincrementsubstructurecounter[#1][#2]%
+ {\docheckstructurecounterbypage{#1}
+ \ctxlua{structure.counters.add("\@@thestructurecounter{#1}",#2,1)}}
+
+\def\convertedstructurecounter
+ {\dodoubleempty\doconvertedstructurecounter}
+
+\def\doconvertedstructurecounter[#1][#2]%
+ {\begingroup
+ \ifsecondargument\getparameters[\??nn#1][#2]\fi
+ \ctxlua{structure.counters.prefixedconverted(
+ "\@@thestructurecounter{#1}",
+ {
+ prefix = "\structurecounterparameter{#1}\c!prefix",
+ separatorset = "\structurecounterparameter{#1}\c!prefixseparatorset",
+ conversion = "\structurecounterparameter{#1}\c!prefixconversion",
+ conversionset = "\structurecounterparameter{#1}\c!prefixconversionset",
+ stopper = \!!bs\structurecounterparameter{#1}\c!prefixstopper\!!es,
+ set = "\structurecounterparameter{#1}\c!prefixset",
+ segments = "\structurecounterparameter{#1}\c!prefixsegments",
+ connector = \!!bs\structurecounterparameter{#1}\c!prefixconnector\!!es,
+ },
+ {
+ order = "\structurecounterparameter{#1}\c!numberorder",
+ separatorset = "\structurecounterparameter{#1}\c!numberseparatorset",
+ conversion = \!!bs\structurecounterparameter{#1}\c!numberconversion\!!es,
+ conversionset = "\structurecounterparameter{#1}\c!numberconversionset",
+ stopper = \!!bs\structurecounterparameter{#1}\c!numberstopper\!!es,
+ segments = "\structurecounterparameter{#1}\c!numbersegments",
+ type = "\structurecounterparameter{#1}\c!type",
+ }
+ )}%
+ \endgroup}
+
+\def\convertedsubstructurecounter
+ {\dotripleempty\doconvertedsubstructurecounter}
+
+\def\doconvertedsubstructurecounter[#1][#2][#3]% #2 can be n or n:m
+ {\ifsecondargument
+ \doconvertedstructurecounter[#1][\c!numbersegments=#2,#3]%
+ \else
+ \secondargumentfalse\doconvertedstructurecounter[#1][]%
+ \fi}
+
+\let\getstructurecounter\convertedstructurecounter
+
+\def\doifdefinedstructurecounter #1{\doifdefined {\csname\s!structurecounter#1\c!number\endcsname}}
+\def\doifundefinedstructurecounter #1{\doifundefined {\csname\s!number#1\c!number\endcsname}}
+\def\doifdefinedstructurecounterelse#1{\doifdefinedelse{\csname\s!number#1\c!number\endcsname}}
+
+\ifx\checkstructurecounter\undefined \def\checkstructurecounter[#1]{} \fi
+
+\def\checkstructurecounter[#1]{}
+
+%D What follows is a compatibility layer. This will be phased out (at
+%D least from core usage).
+
+\def\reset
+ {\dosingleargument\doreset}
+
+\def\doreset[#1]%
+ {\processcommalist[#1]\dodoreset}
+
+\def\dodoreset#1%
+ {\csname\s!reset#1\endcsname}%
+
+\let \numberparameter \structurecounterparameter % {name}\c!key
+
+\let \definenumber \definestructurecounter % [name]
+\let \setupnumber \setupstructurecounter % [name][setups]
+
+\let \setnumber \setstructurecounter % [name]{value}
+\let \resetnumber \resetstructurecounter % [name]
+\let \savenumber \savestructurecounter % [name]
+\let \restorenumber \restorestructurecounter % [name]
+\let \incrementnumber \incrementstructurecounter % [name]
+\let \decrementnumber \decrementstructurecounter % [name]
+\let \rawnumber \rawstructurecounter % [name]
+\let \getnumber \getstructurecounter % [name]
+\let \convertednumber \getstructurecounter % [name]
+
+\let \doifdefinednumber \doifstructurecounter % {number}{true}
+\let \doifundefinednumber \doifnotstructurecounter % {number}{true}
+\let \doifdefinednumberelse \doifstructurecounterelse % {number}{true}{false}
+
+% weird one
+
+\def\accumulatednumber[#1]{}
+
+% funny, here, todo: these are the defaults
+
+\def\setupnumbering
+ {\dodoubleempty\getparameters[\??nr]}
+
+\setupnumbering
+ [\c!way=\v!by\v!chapter,
+ \c!blockway=,
+ \c!sectionnumber=\v!yes,
+ \c!state=\v!start]
+
+%D Helpers:
+
+% call:
+%
+% \dostructurecountercomponent
+% \currentfloat
+% \getfloatparameters \floatparameter \detokenizedfloatparameter
+% \hascaption \hastitle \hasnumber
+% [settings][userdata]
+%
+% sets:
+%
+% \laststructurecounternumber
+% \laststructurecountersynchronize
+
+\newconditional\hasstructurecountercaption
+\newconditional\hasstructurecountertitle
+\newconditional\hasstructurecounternumber
+
+\def\dostructurecountercomponent#1#2#3#4#5#6#7[#8][#9]%
+ {\begingroup
+ %
+ #2[#8]%
+ \edef\hasstructurecountercaption{#3\s!hascaption}%
+ \edef\hasstructurecountertitle{#3\s!hastitle}%
+ \edef\hasstructurecounternumber{#3\s!hasnumber}%
+ %
+ \edef\currentname{#3\c!name}%
+ \ifx\currentname\empty
+ \edef\currentname{#1}%
+ \fi
+ \edef\currentcounter{#3\s!counter}%
+ \ifx\currentcounter\empty
+ \let\currentcounter\currentname
+ \fi
+ %
+ \doif{#3\c!title}\v!none{\setfalse\hasstructurecountercaption\setfalse\hasstructurecounternumber}% will become obsolete
+ %
+ \ifx\hasstructurecounternumber\v!yes
+ \incrementstructurecounter[\currentcounter]%
+ \fi
+ %
+ \ifx\hasstructurecountercaption\v!yes
+ \edef\currentexpansion{#3\c!expansion}%
+ \ifx\currentexpansion\s!xml
+ \edef\currenttitle{#4\c!title}%
+ \edef\currentbookmark{#4\c!bookmark}%
+ \xmlstartraw
+ \edef\currentlisttitle{#3\c!title}%
+ \xmlstopraw
+ \let\currentcoding\s!xml
+ \else
+ \ifx\currentexpansion\v!yes
+ \edef\currenttitle{#3\c!title}%
+ \edef\currentbookmark{#3\c!bookmark}%
+ \else
+ \edef\currenttitle{#4\c!title}%
+ \edef\currentbookmark{#4\c!bookmark}%
+ \fi
+ \let\currentlisttitle\currenttitle
+ \let\currentcoding\s!tex
+ \fi
+ \edef\currentlabel{#3\c!label}%
+ \edef\currentreference{#3\c!reference}%
+ \setnextinternalreference
+ \xdef\laststructurecounternumber{\ctxlua{structure.lists.push{
+ metadata = {
+ kind = "#1",
+ name = "\currentname",
+ level = structure.sections.currentlevel(),
+ catcodes = \the\catcodetable,
+ },
+ references = {
+ internal = \nextinternalreference,
+ reference = "\currentreference",
+ referenceprefix = "\referenceprefix",
+ block = "\currentstructureblock",
+ section = structure.sections.currentid(),
+ },
+ titledata = {
+ label = \!!bs\detokenize\expandafter{\currentlabel }\!!es,
+ title = \!!bs\detokenize\expandafter{\currenttitle }\!!es,
+ \ifx\currentbookmark\currenttitle \else
+ bookmark = \!!bs\detokenize\expandafter{\currentbookmark }\!!es,
+ \fi
+ \ifx\currentlisttitle\currenttitle \else
+ list = \!!bs\detokenize\expandafter{\currentlisttitle}\!!es,
+ \fi
+ },
+ \ifx\hasstructurecountercaption\v!yes
+ prefixdata = {
+ prefix = "#3\c!prefix",
+ separatorset = "#3\c!prefixseparatorset",
+ conversion = \!!bs#3\c!prefixconversion\!!es,
+ conversionset = "#3\c!prefixconversionset",
+ set = "#3\c!prefixset",
+ segments = "#3\c!prefixsegments",
+ connector = \!!bs#3\c!prefixconnector\!!es,
+ },
+ numberdata = {
+ numbers = structure.counters.compact("\currentcounter",nil,true),
+ separatorset = "#3\c!numberseparatorset",
+ conversion = \!!bs#3\c!numberconversion\!!es,
+ conversionset = "#3\c!numberconversionset",
+ stopper = \!!bs#3\c!numberstopper\!!es,
+ segments = "#3\c!numbersegments",
+ },
+ \fi
+ userdata = structure.helpers.touserdata(\!!bs\detokenize{#9}\!!es)
+ }
+ }}%
+ \xdef\laststructurecountersynchronize % make this a macro because shared
+ {\noexpand\ctxlua{jobreferences.setinternalreference(nil,nil,\nextinternalreference)}%
+ \noexpand\ctxlatelua{structure.lists.enhance(\laststructurecounternumber)}}%
+ \else
+ \glet\laststructurecounternumber \relax
+ \glet\laststructurecountersynchronize\relax
+ \fi
+ \endgroup}
+
+\def\dostructurecountersetup#1#2% name \someparameter
+ {\setupstructurecounter
+ [#1]
+ [ \c!start=#2\c!start,
+ \c!state=#2\c!state,
+ \c!way=#2\c!way,
+ %
+ \c!prefix=#2\c!prefix,
+ \c!prefixseparatorset=#2\c!prefixseparatorset,
+ \c!prefixconversion=#2\c!prefixconversion,
+ \c!prefixconversionset=#2\c!prefixconversionset,
+ \c!prefixstopper=#2\c!prefixstopper,
+ \c!prefixset=#2\c!prefixset,
+ \c!prefixsegments=#2\c!prefixsegments,
+ \c!prefixset=#2\c!prefixset,
+ \c!prefixconnector=#2\c!prefixconnector,
+ %
+ \c!numberseparatorset=#2\c!numberseparatorset,
+ \c!numberconversion=#2\c!numberconversion,
+ \c!numberconversionset=#2\c!numberconversionset,
+ \c!numberstopper=#2\c!numberstopper,
+ \c!numbersegments=#2\c!numbersegments]}
+
+\protect \endinput
diff --git a/tex/context/base/strc-pag.lua b/tex/context/base/strc-pag.lua
new file mode 100644
index 000000000..bb2de7881
--- /dev/null
+++ b/tex/context/base/strc-pag.lua
@@ -0,0 +1,206 @@
+if not modules then modules = { } end modules ['strc-pag'] = {
+ version = 1.001,
+ comment = "companion to strc-pag.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local count, format = tex.count, string.format
+
+local ctxcatcodes = tex.ctxcatcodes
+local texsprint = tex.sprint
+
+structure.pages = structure.pages or { }
+
+local helpers = structure.helpers or { }
+local sections = structure.sections or { }
+local pages = structure.pages or { }
+local processors = structure.processors or { }
+local sets = structure.sets or { }
+
+local variables = interfaces.variables
+
+-- storage
+
+jobpages = jobpages or { }
+jobpages.collected = jobpages.collected or { }
+jobpages.tobesaved = jobpages.tobesaved or { }
+
+local collected, tobesaved = jobpages.collected, jobpages.tobesaved
+
+local function initializer()
+ collected, tobesaved = jobpages.collected, jobpages.tobesaved
+end
+
+job.register('jobpages.collected', jobpages.tobesaved, initializer)
+
+local specification = { }
+
+function pages.save(userspec)
+ local realpage, userpage = count[0], count[1]
+ local data = {
+ number = userpage,
+ specification = helpers.simplify(userspec or specification),
+ block = sections.currentblock(),
+ }
+ tobesaved[realpage] = data
+ if not collected[realpage] then
+ collected[realpage] = data
+ end
+end
+
+function pages.pagenumber(localspec)
+ local deltaspec
+ if localspec then
+ for k,v in next, localspec do
+ if v ~= "" and v ~= specification[k] then
+ if not deltaspec then deltaspec = { } end
+ deltaspec[k] = v
+ end
+ end
+ end
+ if deltaspec then
+ return { realpage = count[0], specification = deltaspec }
+ else
+ return { realpage = count[0] }
+ end
+end
+
+--
+
+local function convertnumber(str,n)
+ return format("\\convertnumber{%s}{%s}",str or "numbers",n)
+end
+
+function pages.number(realdata,pagespecification)
+ local userpage, block = realdata.number, realdata.block or ""
+ local conversionset = (pagespecification and pagespecification.conversionset) or realdata.conversionset or ""
+ local conversion = (pagespecification and pagespecification.conversion ) or realdata.conversion or ""
+ local stopper = (pagespecification and pagespecification.stopper ) or realdata.stopper or ""
+ if conversion ~= "" then
+ texsprint(ctxcatcodes,format("\\convertnumber{%s}{%s}",conversion,number))
+ else
+ if conversionset == "" then conversionset = "default" end
+ local theconversion = sets.get("structure:conversions",block,conversionset,index,"numbers")
+ processors.sprint(ctxcatcodes,theconversion,convertnumber,userpage)
+ end
+ if stopper ~= "" then
+ processors.sprint(ctxcatcodes,stopper)
+ end
+end
+
+-- (pagespec.prefix == yes|unset) and (pages.prefix == yes) => prefix
+
+function pages.analyse(entry,pagespecification)
+ -- safeguard
+ if not entry then
+ return false, false, "no entry"
+ end
+ local references = entry.references
+ if not references then
+ return false, false, "no references"
+ end
+ local realpage = references.realpage
+ if not realpage then
+ return false, false, "no realpage"
+ end
+ local pagedata = collected[realpage]
+ if not pagedata then
+ return false, false, "no pagedata"
+ end
+ local section = references.section
+ if not section then
+ return pagedata, false, "no section"
+ end
+ local no = variables.no
+ -- local preferences
+ if pagespecification and pagespecification.prefix == no then
+ return pagedata, false, "current spec blocks prefix"
+ end
+ -- stored preferences
+ if entry.prefix == no then
+ return pagedata, false, "entry blocks prefix"
+ end
+ -- stored page state
+ pagespecification = pagedata.specification
+ if pagespecification and pagespecification.prefix == no then
+ return pagedata, false, "pagedata blocks prefix"
+ end
+ -- final verdict
+ return pagedata, jobsections.collected[references.section], "okay"
+end
+
+function helpers.page(data,pagespec)
+ if data then
+ local pagedata = pages.analyse(data,pagespec)
+ if pagedata then
+ pages.number(pagedata,pagespec)
+ end
+ end
+end
+
+function helpers.prefixpage(data,prefixspec,pagespec)
+ if data then
+ local pagedata, prefixdata = pages.analyse(data,pagespec)
+ if pagedata then
+ if prefixdata then
+ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,prefixdata or false,pagedata.specification or false)
+ end
+ pages.number(pagedata,pagespec)
+ end
+ end
+end
+
+function helpers.prefixlastpage(data,prefixspec,pagespec)
+ if data then
+ local r = data.references
+ local ls, lr = r.section, r.realpage
+ r.section, r.realpage = r.lastsection, r.lastrealpage
+ helpers.prefixpage(data,prefixspec,pagespec)
+ r.section, r.realpage = ls, lr
+ end
+end
+
+--
+
+function helpers.analyse(entry,specification)
+ -- safeguard
+ if not entry then
+ return false, false, "no entry"
+ end
+ local no = variables.no
+ -- section data
+ local references = entry.references
+ if not references then
+ return entry, false, "no references"
+ end
+ local section = references.section
+ if not section then
+ return entry, false, "no section"
+ end
+ sectiondata = jobsections.collected[references.section]
+ if not sectiondata then
+ return entry, false, "no section data"
+ end
+ -- local preferences
+ if specification and specification.prefix == no then
+ return entry, false, "current spec blocks prefix"
+ end
+ -- stored preferences (not used)
+ local prefixdata = entry.prefixdata
+ if prefixdata and prefixdata.prefix == no then
+ return entry, false, "entry blocks prefix"
+ end
+ -- final verdict
+ return entry, sectiondata, "okay"
+end
+
+function helpers.prefix(data,prefixspec)
+ if data then
+ local _, prefixdata = helpers.analyse(data,prefixspec)
+ if prefixdata then
+ sections.typesetnumber(prefixdata,"prefix",prefixspec or false,data.prefixdata or false,prefixdata or false)
+ end
+ end
+end
diff --git a/tex/context/base/strc-pag.tex b/tex/context/base/strc-pag.tex
new file mode 100644
index 000000000..2b7c3fc21
--- /dev/null
+++ b/tex/context/base/strc-pag.tex
@@ -0,0 +1,506 @@
+%D \module
+%D [ file=strc-pag,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Pagenumbering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Pagenumbering}
+
+\registerctxluafile{strc-pag}{1.001}
+
+\unprotect
+
+% Hacks:
+
+\let\preparepageprefix\gobbleoneargument
+\let\checkrealpage \relax
+\let\checksubpages \relax
+\let\setpagecounters \relax
+
+% Allocation:
+
+\countdef\realpageno = 0 \realpageno = 1
+\countdef\userpageno = 1 \userpageno = 1
+\countdef\subpageno = 2 \subpageno = 0 % !!
+\countdef\arrangeno = 3 \arrangeno = 0 % !!
+
+\let\pageno\userpageno
+
+\def\realfolio{\the\realpageno}
+\def\userfolio{\the\userpageno}
+\def\subfolio {\the\subpageno }
+
+\newtoks\everyinitializepagecounters
+
+\def\initializepagecounters{\the\everyinitializepagecounters}
+
+\appendtoks
+ \initializepagecounters
+\to \everyjob
+
+% Page numbers are kind of independent of each other and therefore they
+% all get their own counter. After all, it's easier to combine them in
+% a pseudo counterset than to deal with a complex set itself.
+
+% \definestructureprefixset [mine][section-1,section-2]
+% \definestructureseparatorset[mine][:]
+%
+% \setupuserpagenumber
+% [way=bypart,
+% prefix=yes,
+% prefixset=mine,
+% prefixseparatorset=mine]
+
+\definestructurecounter[\s!realpage][\c!prefix=\v!no,\c!start=1,\c!prefixsegments=] % [\s!counter=0]
+\definestructurecounter[\s!userpage][\c!prefix=\v!no,\c!start=1,\c!prefixsegments=] % [\s!counter=1]
+\definestructurecounter[\s!subpage] [\c!prefix=\v!no,\c!start=1,\c!prefixsegments=] % [\s!counter=2]
+
+\newtoks\everysetuprealpagenumber % todo: set state: none, start, stop, reset
+\newtoks\everysetupuserpagenumber % todo: set state: none, start, stop, reset
+\newtoks\everysetupsubpagenumber % todo: set state: none, start, stop, reset
+
+\def\setuprealpagenumber{\dosingleargument\dosetuprealpagenumber}
+\def\setupuserpagenumber{\dosingleargument\dosetupuserpagenumber}
+\def\setupsubpagenumber {\dosingleargument\dosetupsubpagenumber}
+
+\def\dosavepagenumberstate#1{\edef\oldpagenumberstate{\structurecounterparameter#1\c!state}}
+
+\def\dosetuprealpagenumber[#1]{\dosavepagenumberstate\s!realpage\dosetupstructurecounter[\s!realpage][#1]\the\everysetuprealpagenumber}
+\def\dosetupuserpagenumber[#1]{\dosavepagenumberstate\s!userpage\dosetupstructurecounter[\s!userpage][#1]\the\everysetupuserpagenumber}
+\def\dosetupsubpagenumber [#1]{\dosavepagenumberstate\s!subpage \dosetupstructurecounter[\s!subpage ][#1]\the\everysetupsubpagenumber }
+
+\def\resetrealpagenumber {} % not permitted
+\def\resetuserpagenumber {\resetstructurecounter[\s!userpage]}
+\def\resetsubpagenumber {\resetstructurecounter[\s!subpage]}
+
+\appendtoks
+ \setstructurecounter[\s!realpage]\realpageno
+ \setstructurecounter[\s!userpage]\userpageno
+ \setstructurecounter[\s!subpage] \subpageno
+\to \everyinitializepagecounters
+
+\let\setuppagenumber\setupuserpagenumber
+\let\resetpagenumber\resetuserpagenumber
+
+% {
+% prefix = "\structurecounterparameter{#1}\c!prefix",
+% separatorset = "\structurecounterparameter{#1}\c!prefixseparatorset",
+% conversion = "\structurecounterparameter{#1}\c!prefixconversion",
+% conversionset = "\structurecounterparameter{#1}\c!prefixconversionset",
+% stopper = \!!bs\structurecounterparameter{#1}\c!prefixstopper\!!es,
+% set = "\structurecounterparameter{#1}\c!prefixset",
+% segments = "\structurecounterparameter{#1}\c!prefixsegments",
+% connector = \!!bs\structurecounterparameter{#1}\c!prefixconnector\!!es,
+% },
+% {
+% order = "\structurecounterparameter{#1}\c!numberorder",
+% separatorset = "\structurecounterparameter{#1}\c!numberseparatorset",
+% conversion = "\structurecounterparameter{#1}\c!numberconversion",
+% conversionset = "\structurecounterparameter{#1}\c!numberconversionset",
+% stopper = \!!bs\structurecounterparameter{#1}\c!numberstopper\!!es,
+% segments = "\structurecounterparameter{#1}\c!numbersegments",
+% type = "\structurecounterparameter{#1}\c!type",
+% }
+
+\def\savecurrentpagestate
+ {\ctxlua{structure.pages.save {
+ prefix = "\structurecounterparameter\s!userpage\c!prefix",
+ separatorset = "\structurecounterparameter\s!userpage\c!prefixseparatorset",
+ conversion = "\structurecounterparameter\s!userpage\c!prefixconversion",
+ conversionset = "\structurecounterparameter\s!userpage\c!prefixconversionset",
+ set = "\structurecounterparameter\s!userpage\c!prefixset",
+ stopper = \!!bs\structurecounterparameter\s!userpage\c!prefixstopper\!!es,
+ segments = "\structurecounterparameter\s!userpage\c!prefixsegments",
+ connector = \!!bs\structurecounterparameter\s!userpage\c!prefixconnector\!!es,
+ }}}
+
+\prependtoks
+ \savecurrentpagestate
+\to \everyshipout
+
+\def\pushpagestate{\setxvalue{\??nm:\s!userpage:\c!state}{\structurecounterparameter\s!userpage\c!state}}
+\def\poppagestate {\normalexpanded{\noexpand\setuppagenumber[\c!state=\getvalue{\??nm:\s!userpage:\c!state}]}}
+
+\setuppagenumber
+ [\c!way=\v!by\v!text,
+ \c!prefix=\v!no,
+ \c!prefixset=\v!part,
+ \c!prefixconnector=\endash,
+ \c!state=\v!start]
+
+\setupsubpagenumber
+ [\c!way=\v!by\v!part,
+ \c!state=\v!stop]
+
+% We don't want conflicts when \type {\pageno} is used by other
+% packages, like \CWEB, so we redefine \type {\pageno}.
+
+\newcount\pageno \pageno\userpageno \let\folio\userfolio
+
+\appendtoks
+ \global\pageno\userpageno
+\to \everyinitializepagecounters
+
+% Counters
+
+\def\firstpage {1} \def\prevpage {1} \def\nextpage {1} \def\lastpage {1}
+\def\firstuserpage{1} \def\prevuserpage{1} \def\nextuserpage{1} \def\lastuserpage{1}
+\def\firstsubpage {1} \def\prevsubpage {1} \def\nextsubpage {1} \def\lastsubpage {1}
+
+% Renderers:
+
+\def\realpagenumber{\convertedstructurecounter[\s!realpage]}
+\def\userpagenumber{\convertedstructurecounter[\s!userpage]}
+\def\subpagenumber {\convertedstructurecounter[\s!subpage]}
+
+\def\pagenumber {\rawstructurecounter[\s!userpage]}
+\def\prefixedpagenumber{\convertedstructurecounter[\s!userpage]} % \userpagenumber
+
+\def\firstrealpagenumber{\convertedstructurecounter[\s!realpage][\c!type=\v!first]}
+\def\firstuserpagenumber{\convertedstructurecounter[\s!userpage][\c!type=\v!first]}
+\def\firstsubpagenumber {\convertedstructurecounter[\s!subpage ][\c!type=\v!first]}
+
+\def\lastrealpagenumber {\convertedstructurecounter[\s!realpage][\c!type=\v!last]}
+\def\lastuserpagenumber {\convertedstructurecounter[\s!userpage][\c!type=\v!last]}
+\def\lastsubpagenumber {\convertedstructurecounter[\s!subpage ][\c!type=\v!last]}
+
+\def\prevrealpagenumber {\convertedstructurecounter[\s!realpage][\c!type=\v!previous]}
+\def\prevuserpagenumber {\convertedstructurecounter[\s!userpage][\c!type=\v!previous]}
+\def\prevsubpagenumber {\convertedstructurecounter[\s!subpage ][\c!type=\v!previous]}
+
+\def\nextrealpagenumber {\convertedstructurecounter[\s!realpage][\c!type=\v!next]}
+\def\nextuserpagenumber {\convertedstructurecounter[\s!userpage][\c!type=\v!next]}
+\def\nextsubpagenumber {\convertedstructurecounter[\s!subpage ][\c!type=\v!next]}
+
+\appendtoks
+ \decrementstructurecounter[\s!realpage]%
+ \decrementstructurecounter[\s!userpage]%
+ \decrementstructurecounter[\s!subpage]%
+\to\everygoodbye
+
+% Equivalents (compatibility):
+%
+% todo: maybe leave lastpage etc lua calls
+
+\def\realpage{\realfolio}
+\def\userpage{\userfolio}
+\def\subpage {\subfolio}
+
+% \def\firstrealpage{\firstpage}
+% \def\prevrealpage {\prevpage}
+% \def\nextrealpage {\nextpage}
+% \def\lastrealpage {\lastpage}
+
+\def\firstrealpage{\firststructurecounter[\s!realpage]}
+\def\prevrealpage {\prevstructurecounter[\s!realpage]}
+\def\nextrealpage {\nextstructurecounter[\s!realpage]}
+\def\lastrealpage {\laststructurecounter[\s!realpage]}
+
+\let\firstpage\firstrealpage
+\let\prevpage \prevrealpage
+\let\nextpage \nextrealpage
+\let\lastpage \lastrealpage
+
+\def\nofrealpages {\lastrealpage} \def\totalnumberofpages{\lastrealpage}
+\def\nofuserpages {\lastuserpage} \def\lastpagenumber {\lastuserpage}
+\def\nofsubpages {\lastsubpage }
+
+% Hooks:
+
+\appendtoks
+% \xdef\lastpage{\laststructurecounter[\s!realpage]}%
+ \xdef\currentpage{\the\realpageno}%
+ \ifnum\realpageno>\lastpage \globallet\lastpage\lastrealpage\fi
+\to \everyinitializepagecounters
+
+% \def\savenofpages
+% {\global\realpageno\decrementedstructurecounter[\s!realpage]\relax
+% \global\pageno \decrementedstructurecounter[\s!userpage]\relax}
+
+\let\savenofpages\relax
+
+% States:
+
+\newif\ifrightpage \rightpagetrue
+\newif\ifdoublesided
+\newif\ifsinglesided
+
+% Real page numbers:
+
+\def\gotonextrealpage
+ {\global\realpageno\incrementedstructurecounter[\s!realpage]\relax
+ \ifnum\realpageno>\lastpage
+ \xdef\lastpage{\realfolio}%
+ \fi
+ \setpagereference\v!firstpage\firstpage
+ \setpagereference\v!lastpage\lastpage
+ \ifnum\realpageno>\plusone
+ \xdef\prevpage{\the\numexpr\realpageno+\minusone}%
+ \setpagereference\v!backward\prevpage
+ \else
+ \global\let\prevpage\firstpage
+ \setpagereference\v!backward\lastpage
+ \fi
+ \setpagereference\v!previouspage\prevpage
+ \ifnum\realpageno<\lastpage\relax
+ \xdef\nextpage{\the\numexpr\realpageno+\plusone}%
+ \setpagereference\v!page\nextpage
+ \setpagereference\v!forward\nextpage
+ \glet\nextnextpage\nextpage
+ \ifodd\nextpage\relax
+ \setpagereference\v!nextoddpage\nextnextpage
+ \else
+ \setpagereference\v!nextevenpage\nextnextpage
+ \fi
+ \xdef\nextnextpage{\the\numexpr\realpageno+\plustwo}%
+ \ifnum\nextnextpage>\lastpage\else
+ \ifodd\nextnextpage\relax
+ \setpagereference\v!nextoddpage\nextnextpage
+ \else
+ \setpagereference\v!nextevenpage\nextnextpage
+ \fi
+ \fi
+ \else
+ \glet\nextpage\lastpage
+ \setpagereference\v!page\firstpage
+ \setpagereference\v!forward\firstpage
+ \setpagereference\v!nextoddpage\lastpage
+ \setpagereference\v!nextevenpage\lastpage
+ \fi
+ \setpagereference\v!nextpage\realfolio}
+
+% Pagenumbers:
+
+\def\dodecrementpagenumber{\global\userpageno\decrementedstructurecounter[\s!userpage]\relax\global\pageno\userpageno}
+\def\doincrementpagenumber{\global\userpageno\incrementedstructurecounter[\s!userpage]\relax\global\pageno\userpageno}
+
+\def\dosynchronizepagenumber{\global\let\@@pnstate\v!start}
+
+\def\decrementpagenumber{\getvalue{\??pn-\structurecounterparameter\s!userpage\c!state}}
+\def\incrementpagenumber{\getvalue{\??pn+\structurecounterparameter\s!userpage\c!state}}
+
+\letvalue{\??pn-\v!start}\dodecrementpagenumber
+\letvalue{\??pn-\v!none }\dodecrementpagenumber
+\letvalue{\??pn-\v!empty}\dodecrementpagenumber
+
+\letvalue{\??pn+\v!start}\doincrementpagenumber
+\letvalue{\??pn+\v!none }\doincrementpagenumber
+\setvalue{\??pn+\v!empty}{\doincrementpagenumber\dosynchronizepagenumber}
+\letvalue{\??pn+\v!keep }\dosynchronizepagenumber
+
+% todo: check if number set, and reset it after testing; also take care of \global\shiftedrealpagenotrue
+
+% Subpagenumbers:
+
+\def\gotonextsubpage
+ {\global\subpageno\incrementedstructurecounter[\s!subpage]\relax
+ \ifnum\subpageno>\lastsubpage
+ \xdef\lastsubpage{\subfolio}%
+ \fi
+ \setpagereference\v!firstsubpage\firstsubpage
+ \setpagereference\v!lastsubpage\lastsubpage
+ \ifnum\subpageno>\plusone
+ \xdef\prevsubpage{\the\numexpr\subpageno+\minusone}%
+ \setpagereference\v!subbackward\prevsubpage
+ \else
+ \global\let\prevsubpage\firstsubpage
+ \setpagereference\v!subbackward\lastsubpage
+ \fi
+ \setpagereference\v!previoussubpage\prevsubpage
+ \ifnum\subpageno<\lastsubpage\relax
+ \xdef\nextsubpage{\the\numexpr\subpageno+\plusone}%
+ \setpagereference\v!subpage\nextsubpage
+ \setpagereference\v!subforward\nextsubpage
+ \glet\nextnextpage\nextsubpage
+ \xdef\nextnextpage{\the\numexpr\subpageno+\plustwo}%
+ \else
+ \glet\nextsubpage\lastsubpage
+ \setpagereference\v!subpage\firstsubpage
+ \setpagereference\v!subforward\firstsubpage
+ \fi
+ \setpagereference\v!nextsubpage\subfolio}
+
+% Control:
+
+\def\getpagestatus % hierboven gebruiken
+ {\ifdoublesided
+ \global\rightpagetrue
+ % todo: \global\rightpagetrue or \global\rightpagefalse
+ \else
+ \global\rightpagetrue
+ \fi}
+
+% Setup general page numbering
+
+\newtoks\everysetuppagenumbering
+
+\def\setuppagenumbering
+ {\dosingleempty\dosetuppagenumbering}
+
+\def\dosetuppagenumbering[#1]%
+ {\getparameters[\??nm][#1]\the\everysetuppagenumbering}
+
+\appendtoks
+ \singlesidedfalse
+ \doublesidedfalse
+ \ExpandFirstAfter\processallactionsinset
+ [\@@nmalternative]
+ [ \v!singlesided=>\singlesidedtrue,
+ \v!doublesided=>\doublesidedtrue]%
+ \ifx\trackingmarginnotestrue\undefined\else
+ \ifdoublesided
+ \trackingmarginnotestrue
+ \else
+ \trackingmarginnotesfalse
+ \fi
+ \fi
+ \dosetpagenumberlocation
+\to \everysetuppagenumbering
+
+\appendtoks
+ \ifdefined \recalculatebackgrounds \recalculatebackgrounds \fi
+\to \everysetuppagenumbering
+
+% The numbered location handler is there because we need to be downward
+% compatible. So, in fact there can be multiple handlers active at the
+% same time, but only the current one does something.
+%
+% thsi code might move to page-txt
+
+\newcount\currentpagenumberlocation
+
+\def\dosetpagenumberlocation
+ {\advance\currentpagenumberlocation\plusone
+ \ifx\@@nmlocation\empty \else
+ \let\@@pagenumbervlocation\v!footer
+ \let\@@pagenumberhlocation\v!text
+ \let\@@pagenumberxlocation\c!middletext
+ \normalexpanded{\noexpand\processallactionsinset[\@@nmlocation]}
+ [ \v!header=>\let\@@pagenumbervlocation\v!header,
+ \v!footer=>\let\@@pagenumbervlocation\v!footer,
+ \v!middle=>\let\@@pagenumberhlocation\v!text \let\@@pagenumberxlocation\c!middletext,
+ \v!left=>\let\@@pagenumberhlocation\v!text \let\@@pagenumberxlocation\c!lefttext,
+ \v!right=>\let\@@pagenumberhlocation\v!text \let\@@pagenumberxlocation\c!righttext,
+ \v!inleft=>\let\@@pagenumberhlocation\v!margin\let\@@pagenumberxlocation\c!lefttext,
+ \v!inright=>\let\@@pagenumberhlocation\v!margin\let\@@pagenumberxlocation\c!righttext,
+ \v!inmargin=>\let\@@pagenumberhlocation\v!margin\def\@@pagenumberxlocation{\ifdoublesided\c!margintext\else\c!righttext\fi},
+ \v!margin=>\let\@@pagenumberhlocation\v!margin\def\@@pagenumberxlocation{\ifdoublesided\c!margintext\else\c!righttext\fi},
+ \v!atmargin=>\let\@@pagenumberhlocation\v!text \let\@@pagenumberxlocation\c!marginedgetext,
+ \v!marginedge=>\let\@@pagenumberhlocation\v!text \let\@@pagenumberxlocation\c!marginedgetext]%
+ \normalexpanded{\noexpand\setspecificlayouttext
+ {\@@pagenumbervlocation}{\@@pagenumberhlocation}{\@@pagenumberxlocation}%
+ {\noexpand\doplacepagenumberatlocation{\number\currentpagenumberlocation}}}%
+ \fi}
+
+\def\setspecificlayouttext#1#2#3#4{\setvalue{\??tk#1#2#3}{#4}} % weird place
+
+\appendtoks
+ \dosetpagenumberlocation
+\to \everyinitializepagecounters
+
+\def\doplacepagenumberatlocation#1%
+ {\ifnum#1=\currentpagenumberlocation\relax\expandafter\placelocationpagenumber\fi}
+
+% Rendering:
+
+\unexpanded\def\placelocationpagenumber
+ {\ifnum\userpagenumberstate=\plustwo
+ \ifnum\overallpagenumberstate=\plusone
+ \doif\@@nmstrut\v!yes\strut
+ \@@nmcommand{\doattributes\??nm\c!style\c!color{\@@nmleft\labeltexts\v!pagenumber{\prefixedpagenumber}\@@nmright}}%
+ \fi
+ \fi}
+
+\unexpanded\def\completepagenumber
+ {\ifnum\userpagenumberstate=\plustwo
+ \ifnum\overallpagenumberstate=\plusone
+ \@@nmleft\labeltexts\v!pagenumber\prefixedpagenumber\@@nmright
+ \fi
+ \fi}
+
+\unexpanded\def\placepagenumber
+ {\ifnum\userpagenumberstate=\plustwo
+ \ifnum\overallpagenumberstate=\plusone
+ \labeltexts\v!pagenumber\pagenumber
+ \fi
+ \fi}
+
+\unexpanded\def\referencepagenumber[#1]%
+ {\doifelsenothing{#1}{?}{}}
+
+% The numbered location handler is there because we need to be downward
+% compatible. So, in fact there can be multiple handlers active at the
+% same time, but only the current one does something.
+
+\chardef\realpagenumberstate =2 % counter state : 0=stop, 1=start, 2=start and visible
+\chardef\userpagenumberstate =2 % counter state : 0=stop, 1=start, 2=start and visible
+\chardef\subpagenumberstate =2 % counter state : 0=stop, 1=start, 2=start and visible
+\chardef\overallpagenumberstate=1 % general number: 0=invisible, 1=visible
+
+\def\checkpagenumberstatechange#1#2%
+ {\edef\newpagenumberstate{\structurecounterparameter#1\c!state}%
+ \ifx\newpagenumberstate\oldpagenumberstate \else
+ \doifelse\newpagenumberstate\v!start
+ {\chardef#2\plustwo}%
+ {\chardef#2\zerocount}%
+ \fi}
+
+\appendtoks % todo: set state: none, start, stop, reset
+ \checkpagenumberstatechange\s!realpage\realpagenumberstate
+\to \everysetuprealpagenumber
+
+\appendtoks % todo: set state: none, start, stop, reset
+ \checkpagenumberstatechange\s!userpage\userpagenumberstate
+\to \everysetupuserpagenumber
+
+\appendtoks % todo: set state: none, start, stop, reset
+ \checkpagenumberstatechange\s!subpage\subpagenumberstate
+\to \everysetupsubpagenumber
+
+\appendtoks % todo: set state: none, start, stop, reset
+ \doifelse\@@nmstate\v!start
+ {\chardef\overallpagenumberstate\plusone}%
+ {\chardef\overallpagenumberstate\zerocount}%
+\to \everysetuppagenumbering
+
+% Done
+
+% \c!way=\v!by\v!part
+% \c!text=
+% \v!chapter\v!number=\v!no
+% \v!part\v!number=\v!yes
+% \c!numberseparator=--
+% \c!conversion=\v!numbers
+
+\setuppagenumbering
+ [\c!alternative=\v!singlesided,
+ \c!location={\v!header,\v!middle},
+ \c!width=, % in geval van \v!marginedge
+ \c!left=,
+ \c!right=,
+ \c!textseparator=\tfskip,
+ \c!state=\v!start,
+ \c!command=,
+ \c!strut=\v!yes,
+ \c!style=, % empty, otherwise conflict
+ \c!color=]
+
+% just for downward compatbility
+
+\appendtoks
+ \edef\askeduserpagenumber{\structurecounterparameter\s!userpage\c!number}%
+ \ifx\askeduserpagenumber\empty \else
+ \normalexpanded{\noexpand\setuppagenumber[\c!start=\structurecounterparameter\s!userpage\c!number,\c!number=]}%
+ \fi
+\to\everysetupuserpagenumber % todo: set state: none, start, stop, reset
+
+\initializepagecounters
+
+\protect \endinput
diff --git a/tex/context/base/strc-prc.lua b/tex/context/base/strc-prc.lua
new file mode 100644
index 000000000..35e7000db
--- /dev/null
+++ b/tex/context/base/strc-prc.lua
@@ -0,0 +1,9 @@
+if not modules then modules = { } end modules ['strc-prc'] = {
+ version = 1.001,
+ comment = "companion to strc-prc.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- code will move from strc-ini to here
diff --git a/tex/context/base/strc-prc.tex b/tex/context/base/strc-prc.tex
new file mode 100644
index 000000000..a81cfddd1
--- /dev/null
+++ b/tex/context/base/strc-prc.tex
@@ -0,0 +1,84 @@
+%D \module
+%D [ file=strc-prc,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Processors,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Processors}
+
+\registerctxluafile{strc-prc}{1.001}
+
+\unprotect
+
+%D Processors are used when we cannot easily associate typesetting directives
+%D with (for instance) structural elements. Instead of ending up with numerous
+%D additional definitions we can group treatments in so called processors.
+%D
+%D An example of where processors can be used is in separator sets (these are
+%D related to typesetting numbers using structure).
+%D
+%D \starttyping
+%D \defineprocessor[demo][style=\bfb,color=red]
+%D \stoptyping
+%D
+%D This defines a processor named \type {demo}. Such a name ends up as prefix in
+%D for instance:
+%D
+%D \starttyping
+%D \definestructureseparatorset [demosep] [demo->!,demo->?,demo->!,demo->?] [demo->@]
+%D \stoptyping
+%D
+%D Here the \type {!} and \type {?} are just the seperator characters that end
+%D up between part, chapter, section, etc.\ numbers. The third argument defines the
+%D default. When a separator is inserted, the \type{demo} processor will be applied.
+%D Here the number will be separated by red slightly bigger than normal bold
+%D exclamation marks and questionmarks
+%D
+%D Valid keys for defining a processor are \type {style}, \type {color}, \type {left},
+%D \type {right}, and \type {command} (the given command takes one argument).
+
+\def\defineprocessor
+ {\dodoubleargument\dodefineprocessor}
+
+\def\dodefineprocessor[#1][#2]%
+ {\ifsecondargument
+ \letbeundefined{\??po#1\c!command}%
+ \ctxlua{structure.processors.register("#1")}%
+ \getparameters[\??po#1][\c!style=,\c!color=,\c!left=,\c!right=,#2]%
+ \else
+ \letbeundefined{\??po#1\c!style}%
+ \ctxlua{structure.processors.reset("#1")}%
+ \fi}
+
+%D The following command can be used by users but normally it will be
+%D invoked behind the screens. After all, processor prefixes need to
+%D be split off first.
+
+\unexpanded\def\applyprocessor#1%
+ {\ifcsname\??po#1\c!style\endcsname
+ \expandafter\dodoapplyprocessor
+ \else
+ \expandafter\secondoftwoarguments
+ \fi{#1}}
+
+\def\dodoapplyprocessor#1#2%
+ {\begingroup
+ \dostartattributes{\??po#1}\c!style\c!color
+ \csname\??po#1\c!left\endcsname
+ \ifcsname\??po#1\c!command\endcsname
+ \csname\??po#1\c!command\endcsname{#2}%
+ \else
+ #2%
+ \fi
+ \csname\??po#1\c!right\endcsname
+ \dostopattributes
+ \endgroup}
+
+\protect \endinput
diff --git a/tex/context/base/strc-ref.lua b/tex/context/base/strc-ref.lua
new file mode 100644
index 000000000..3ee01b127
--- /dev/null
+++ b/tex/context/base/strc-ref.lua
@@ -0,0 +1,875 @@
+if not modules then modules = { } end modules ['strc-ref'] = {
+ version = 1.001,
+ comment = "companion to strc-ref.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, gmatch, texsprint, texwrite, count = string.format, string.gmatch, tex.sprint, tex.write, tex.count
+
+local ctxcatcodes = tex.ctxcatcodes
+
+-- beware, this is a first step in the rewrite (just getting rid of
+-- the tuo file); later all access and parsing will also move to lua
+
+jobreferences = jobreferences or { }
+jobreferences.tobesaved = jobreferences.tobesaved or { }
+jobreferences.collected = jobreferences.collected or { }
+jobreferences.documents = jobreferences.documents or { }
+jobreferences.defined = jobreferences.defined or { } -- indirect ones
+jobreferences.derived = jobreferences.derived or { } -- taken from lists
+jobreferences.specials = jobreferences.specials or { } -- system references
+jobreferences.runners = jobreferences.runners or { }
+jobreferences.internals = jobreferences.internals or { }
+
+storage.register("jobreferences/defined", jobreferences.defined, "jobreferences.defined")
+
+local tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
+local defined, derived, specials, runners = jobreferences.defined, jobreferences.derived, jobreferences.specials, jobreferences.runners
+
+local currentreference = nil
+
+jobreferences.initializers = jobreferences.initializers or { }
+
+function jobreferences.registerinitializer(func) -- we could use a token register instead
+ jobreferences.initializers[#jobreferences.initializers+1] = func
+end
+
+local function initializer()
+ tobesaved, collected = jobreferences.tobesaved, jobreferences.collected
+ for k,v in ipairs(jobreferences.initializers) do
+ v(tobesaved,collected)
+ end
+end
+
+if job then
+ job.register('jobreferences.collected', jobreferences.tobesaved, initializer)
+end
+
+function jobreferences.set(kind,prefix,tag,data)
+ for ref in gmatch(tag,"[^,]+") do
+ local p, r = ref:match("^(%-):(.-)$")
+ if p and r then
+ prefix, ref = p, r
+ else
+ prefix = ""
+ end
+ if ref ~= "" then
+ local pd = tobesaved[prefix]
+ if not pd then
+ pd = { }
+ tobesaved[prefix] = pd
+ end
+ pd[ref] = data
+ texsprint(ctxcatcodes,format("\\dofinish%sreference{%s}{%s}",kind,prefix,ref))
+ end
+ end
+end
+
+function jobreferences.enhance(prefix,tag,spec)
+ local l = tobesaved[prefix][tag]
+ if l then
+ l.references.realpage = tex.count[0]
+ end
+end
+
+-- this reference parser is just an lpeg version of the tex based one
+
+local result = { }
+
+local lparent, rparent, lbrace, rbrace, dcolon = lpeg.P("("), lpeg.P(")"), lpeg.P("{"), lpeg.P("}"), lpeg.P("::")
+
+local reset = lpeg.P("") / function (s) result = { } end
+local outer = (1-dcolon-lparent-lbrace )^1 / function (s) result.outer = s end
+local operation = (1-rparent-rbrace-lparent-lbrace)^1 / function (s) result.operation = s end
+local arguments = (1-rbrace )^0 / function (s) result.arguments = s end
+local special = (1-lparent-lbrace-lparent-lbrace)^1 / function (s) result.special = s end
+local inner = (1-lparent-lbrace )^1 / function (s) result.inner = s end
+
+local outer_reference = (outer * dcolon)^0
+
+operation = outer_reference * operation -- special case: page(file::1) and file::page(1)
+
+local optional_arguments = (lbrace * arguments * rbrace)^0
+local inner_reference = inner * optional_arguments
+local special_reference = special * lparent * (operation * optional_arguments + operation^0) * rparent
+
+local scanner = (reset * outer_reference * (special_reference + inner_reference)^-1 * -1) / function() return result end
+
+function jobreferences.analyse(str)
+ return scanner:match(str)
+end
+
+local splittemplate = "\\setreferencevariables{%s}{%s}{%s}{%s}{%s}" -- will go away
+
+function jobreferences.split(str)
+ local t = scanner:match(str or "")
+ texsprint(ctxcatcodes,format(splittemplate,t.special or "",t.operation or "",t.arguments or "",t.outer or "",t.inner or ""))
+ return t
+end
+
+--~ print(table.serialize(jobreferences.analyse("")))
+--~ print(table.serialize(jobreferences.analyse("inner")))
+--~ print(table.serialize(jobreferences.analyse("special(operation{argument,argument})")))
+--~ print(table.serialize(jobreferences.analyse("special(operation)")))
+--~ print(table.serialize(jobreferences.analyse("special()")))
+--~ print(table.serialize(jobreferences.analyse("inner{argument}")))
+--~ print(table.serialize(jobreferences.analyse("outer::")))
+--~ print(table.serialize(jobreferences.analyse("outer::inner")))
+--~ print(table.serialize(jobreferences.analyse("outer::special(operation{argument,argument})")))
+--~ print(table.serialize(jobreferences.analyse("outer::special(operation)")))
+--~ print(table.serialize(jobreferences.analyse("outer::special()")))
+--~ print(table.serialize(jobreferences.analyse("outer::inner{argument}")))
+--~ print(table.serialize(jobreferences.analyse("special(outer::operation)")))
+
+-- -- -- related to strc-ini.lua -- -- --
+
+jobreferences.resolvers = jobreferences.resolvers or { }
+
+function jobreferences.resolvers.section(var)
+ local vi = structure.lists.collected[var.i[2]]
+ if vi then
+ var.i = vi
+ var.r = (vi.references and vi.references.realpage) or 1
+ else
+ var.i = nil
+ var.r = 1
+ end
+end
+
+jobreferences.resolvers.float = jobreferences.resolvers.section
+jobreferences.resolvers.description = jobreferences.resolvers.section
+jobreferences.resolvers.formula = jobreferences.resolvers.section
+jobreferences.resolvers.note = jobreferences.resolvers.section
+
+function jobreferences.resolvers.reference(var)
+ local vi = var.i[2]
+ if vi then
+ var.i = vi
+ var.r = (vi.references and vi.references.realpage) or 1
+ else
+ var.i = nil
+ var.r = 1
+ end
+end
+
+local function register_from_lists(collected,derived)
+ for i=1,#collected do
+ local entry = collected[i]
+ local m, r = entry.metadata, entry.references
+ if m and r then
+ local prefix, reference = r.referenceprefix or "", r.reference or ""
+ if reference ~= "" then
+ local kind, realpage = m.kind, r.realpage
+ if kind and realpage then
+ local d = derived[prefix] if not d then d = { } derived[prefix] = d end
+ d[reference] = { kind, i }
+ end
+ end
+ end
+ end
+end
+
+jobreferences.registerinitializer(function() register_from_lists(structure.lists.collected,derived) end)
+
+-- urls
+
+jobreferences.urls = jobreferences.urls or { }
+jobreferences.urls.data = jobreferences.urls.data or { }
+
+local urls = jobreferences.urls.data
+
+function jobreferences.urls.define(name,url,file,description)
+ if name and name ~= "" then
+ urls[name] = { url or "", file or "", description or url or file or ""}
+ end
+end
+
+function jobreferences.urls.get(name,method,space) -- method: none, before, after, both, space: yes/no
+ local u = urls[name]
+ if u then
+ local url, file = u[1], u[2]
+ if file ~= "" then
+ texsprint(ctxcatcodes,url,"/",file)
+ else
+ texsprint(ctxcatcodes,url)
+ end
+ end
+end
+
+-- files
+
+jobreferences.files = jobreferences.files or { }
+jobreferences.files.data = jobreferences.files.data or { }
+
+local files = jobreferences.files.data
+
+function jobreferences.files.define(name,file,description)
+ if name and name ~= "" then
+ files[name] = { file or "", description or file or ""}
+ end
+end
+
+function jobreferences.files.get(name,method,space) -- method: none, before, after, both, space: yes/no
+ local f = files[name]
+ if f then
+ texsprint(ctxcatcodes,f[1])
+ end
+end
+
+-- programs
+
+jobreferences.programs = jobreferences.programs or { }
+jobreferences.programs.data = jobreferences.programs.data or { }
+
+local programs = jobreferences.programs.data
+
+function jobreferences.programs.define(name,file,description)
+ if name and name ~= "" then
+ programs[name] = { file or "", description or file or ""}
+ end
+end
+
+function jobreferences.programs.get(name)
+ local f = programs[name]
+ if f then
+ texsprint(ctxcatcodes,f[1])
+ end
+end
+
+-- shared by urls and files
+
+function jobreferences.from(name,method,space)
+ local u = urls[name]
+ if u then
+ local url, file, description = u[1], u[2], u[3]
+ if description ~= "" then
+ texsprint(ctxcatcodes,description)
+ elseif file then
+ texsprint(ctxcatcodes,url,"/",file)
+ else
+ texsprint(ctxcatcodes,url)
+ end
+ else
+ local f = files[name]
+ if f then
+ local description, file = f[1], f[2]
+ if description ~= "" then
+ texsprint(ctxcatcodes,description)
+ else
+ texsprint(ctxcatcodes,file)
+ end
+ end
+ end
+end
+
+function jobreferences.load(name)
+ if name then
+ local jdn = jobreferences.documents[name]
+ if not jdn then
+ jdn = { }
+ local fn = files[name]
+ if fn then
+ jdn.filename = fn[1]
+ local data = io.loaddata(file.replacesuffix(fn[1],"tuc")) or ""
+ if data ~= "" then
+ -- quick and dirty, assume sane { } usage inside strings
+ local lists = data:match("structure%.lists%.collected=({.-[\n\r]+})[\n\r]")
+ if lists and lists ~= "" then
+ lists = loadstring("return" .. lists)
+ if lists then
+ jdn.lists = lists()
+ jdn.derived = { }
+ register_from_lists(jdn.lists,jdn.derived)
+ else
+ commands.writestatus("error","invalid structure data in %s",filename)
+ end
+ end
+ local references = data:match("jobreferences%.collected=({.-[\n\r]+})[\n\r]")
+ if references and references ~= "" then
+ references = loadstring("return" .. references)
+ if references then
+ jdn.references = references()
+ else
+ commands.writestatus("error","invalid reference data in %s",filename)
+ end
+ end
+ end
+ end
+ jobreferences.documents[name] = jdn
+ end
+ return jdn
+ else
+ return nil
+ end
+end
+
+function jobreferences.define(prefix,reference,list)
+ local d = defined[prefix] if not d then d = { } defined[prefix] = d end
+ d[reference] = { "defined", list }
+end
+
+--~ function jobreferences.registerspecial(name,action,...)
+--~ specials[name] = { action, ... }
+--~ end
+
+function jobreferences.reset(prefix,reference)
+ local d = defined[prefix]
+ if d then
+ d[reference] = nil
+ end
+end
+
+-- \primaryreferencefoundaction
+-- \secondaryreferencefoundaction
+-- \referenceunknownaction
+
+-- t.special t.operation t.arguments t.outer t.inner
+
+local settings_to_array = aux.settings_to_array
+
+local function resolve(prefix,reference,args,set) -- we start with prefix,reference
+ if reference and reference ~= "" then
+ set = set or { }
+ local r = settings_to_array(reference)
+ for i=1,#r do
+ local ri = r[i]
+ local d = defined[prefix][ri] or defined[""][ri]
+ if d then
+ resolve(prefix,d[2],nil,set)
+ else
+ local var = scanner:match(ri)
+ if var then
+ var.reference = ri
+ if not var.outer and var.inner then
+ local d = defined[prefix][var.inner] or defined[""][var.inner]
+ if d then
+ resolve(prefix,d[2],var.arguments,set) -- args can be nil
+ else
+ if args then var.arguments = args end
+ set[#set+1] = var
+ end
+ else
+ if args then var.arguments = args end
+ set[#set+1] = var
+ end
+ else
+ -- logs.report("references","funny pattern: %s",ri or "?")
+ end
+ end
+ end
+ return set
+ else
+ return { }
+ end
+end
+
+-- prefix == "" is valid prefix which saves multistep lookup
+
+local function identify(prefix,reference)
+ local set = resolve(prefix,reference)
+ local bug = false
+ for i=1,#set do
+ local var = set[i]
+ local special, inner, outer, arguments, operation = var.special, var.inner, var.outer, var.arguments, var.operation
+ if special then
+ local s = specials[special]
+--~ print(table.serialize(specials))
+ if s then
+ if outer then
+ if operation then
+ -- special(outer::operation)
+ var.kind = "special outer with operation"
+ else
+ -- special()
+ var.kind = "special outer"
+ end
+ elseif operation then
+ if arguments then
+ -- special(operation{argument,argument})
+ var.kind = "special operation with arguments"
+ else
+ -- special(operation)
+ var.kind = "special operation"
+ end
+ else
+ -- special()
+ var.kind = "special"
+ end
+ else
+ var.error = "unknown special"
+ end
+ elseif outer then
+ local e = jobreferences.load(outer)
+ if e then
+ local f = e.filename
+ if f then
+ if inner then
+ local r = e.references
+ if r then
+ r = r[prefix]
+ if r then
+ r = r[inner]
+ if r then
+ if arguments then
+ -- outer::inner{argument}
+ var.kind = "outer with inner with arguments"
+ else
+ -- outer::inner
+ var.kind = "outer with inner"
+ end
+ var.i = { "reference", r }
+ jobreferences.resolvers.reference(var)
+ var.f = f
+ end
+ end
+ end
+ if not r then
+ r = e.derived
+ if r then
+ r = r[prefix]
+ if r then
+ r = r[inner]
+ if r then
+ -- outer::inner
+ if arguments then
+ -- outer::inner{argument}
+ var.kind = "outer with inner with arguments"
+ else
+ -- outer::inner
+ var.kind = "outer with inner"
+ end
+ var.i = r
+ jobreferences.resolvers[r[1]](var)
+ var.f = f
+ end
+ end
+ end
+ end
+ if not r then
+ var.error = "unknown outer"
+ end
+ elseif special then
+ local s = specials[special]
+ if s then
+ if operation then
+ if arguments then
+ -- outer::special(operation{argument,argument})
+ var.kind = "outer with special and operation and arguments"
+ else
+ -- outer::special(operation)
+ var.kind = "outer with special and operation"
+ end
+ else
+ -- outer::special()
+ var.kind = "outer with special"
+ end
+ var.f = f
+ else
+ var.error = "unknown outer with special"
+ end
+ else
+ -- outer::
+ var.kind = "outer"
+ var.f = f
+ end
+ else
+ var.error = "unknown outer"
+ end
+ else
+ var.error = "unknown outer"
+ end
+ else
+ if arguments then
+ local s = specials[inner]
+ if s then
+ -- inner{argument}
+ var.kind = "special with arguments"
+ else
+ var.error = "unknown inner or special"
+ end
+ else
+ -- inner
+--~ local i = tobesaved[prefix]
+ local i = collected[prefix]
+ i = i and i[inner]
+ if i then
+ var.i = { "reference", i }
+ jobreferences.resolvers.reference(var)
+ var.kind = "inner"
+ var.p = prefix
+ else
+ i = derived[prefix]
+ i = i and i[inner]
+ if i then
+ var.kind = "inner"
+ var.i = i
+ jobreferences.resolvers[i[1]](var)
+ var.p = prefix
+ else
+ i = collected[prefix]
+ i = i and i[inner]
+ if i then
+ var.kind = "inner"
+ var.i = { "reference", i }
+ jobreferences.resolvers.reference(var)
+ var.p = prefix
+ else
+ local s = specials[inner]
+ if s then
+ var.kind = "special"
+ else
+--~ i = (tobesaved[""] and tobesaved[""][inner]) or
+--~ (derived [""] and derived [""][inner]) or
+--~ (collected[""] and collected[""][inner])
+ i = (collected[""] and collected[""][inner]) or
+ (derived [""] and derived [""][inner]) or
+ (tobesaved[""] and tobesaved[""][inner])
+ if i then
+ var.kind = "inner"
+ var.i = { "reference", i }
+ jobreferences.resolvers.reference(var)
+ var.p = ""
+ else
+ var.error = "unknown inner or special"
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ bug = bug or var.error
+ set[i] = var
+ end
+--~ print(prefix,reference,table.serialize(set))
+ return set, bug
+end
+
+jobreferences.identify = identify
+
+function jobreferences.doifelse(prefix,reference)
+ local set, bug = identify(prefix,reference)
+ local unknown = bug or #set == 0
+ if unknown then
+ currentreference = nil
+ else
+ currentreference = set[1]
+ end
+ commands.doifelse(not unknown)
+end
+
+function jobreferences.analysis(prefix,reference)
+ local set, bug = identify(prefix,reference)
+ local unknown = bug or #set == 0
+ if unknown then
+ currentreference = nil
+ texwrite(0) -- unknown
+ else
+ currentreference = set[1]
+ texwrite(1) -- whatever
+--~ texwrite(2) -- forward, following page
+--~ texwrite(3) -- backward, preceding page
+--~ texwrite(4) -- forward, same page
+--~ texwrite(5) -- backward, same page
+ end
+end
+
+function jobreferences.handle(prefix,reference) -- todo: use currentreference is possible
+ local set, bug = identify(prefix,reference)
+ if bug or #set == 0 then
+ texsprint(ctxcatcodes,"\\referenceunknownaction")
+ else
+ for i=2,#set do
+ local s = set[i]
+currentreference = s
+ -- not that needed, but keep it for a while
+ texsprint(ctxcatcodes,format(splittemplate,s.special or "",s.operation or "",s.arguments or "",s.outer or "",s.inner or ""))
+ --
+ if s.error then
+ texsprint(ctxcatcodes,"\\referenceunknownaction")
+ else
+ local runner = runners[s.kind]
+ if runner then
+ texsprint(ctxcatcodes,runner(s,"\\secondaryreferencefoundaction"))
+ end
+ end
+ end
+ local s = set[1]
+currentreference = s
+ -- not that needed, but keep it for a while
+ texsprint(ctxcatcodes,format(splittemplate,s.special or "",s.operation or "",s.arguments or "",s.outer or "",s.inner or ""))
+ --
+ if s.error then
+ texsprint(ctxcatcodes,"\\referenceunknownaction")
+ else
+ local runner = runners[s.kind]
+ if runner then
+ texsprint(ctxcatcodes,runner(s,"\\primaryreferencefoundaction"))
+ end
+ end
+ end
+end
+
+local thisdestinationyes = "\\thisisdestination{%s:%s}"
+local thisdestinationnop = "\\thisisdestination{%s}"
+local thisdestinationaut = "\\thisisdestination{aut:%s}"
+
+function jobreferences.setinternalreference(prefix,tag,internal)
+ if tag then
+ for ref in gmatch(tag,"[^,]+") do
+ if not prefix or prefix == "" then
+ texsprint(ctxcatcodes,format(thisdestinationnop,ref))
+ else
+ texsprint(ctxcatcodes,format(thisdestinationyes,prefix,ref))
+ end
+ end
+ end
+ texsprint(ctxcatcodes,format(thisdestinationaut,internal))
+ -- texsprint(ctxcatcodes,"[["..internal.."]]")
+end
+
+--
+
+jobreferences.filters = jobreferences.filters or { }
+
+local filters = jobreferences.filters
+local helpers = structure.helpers
+local sections = structure.sections
+
+function jobreferences.filter(name) -- number page title ...
+ local data = currentreference and currentreference.i
+ if data then
+ local kind = data.metadata and data.metadata.kind
+ if kind then
+ local filter = filters[kind] or filters.generic
+ filter = filter and (filter[name] or filters.generic[name])
+ if filter then
+ filter(data)
+ end
+ end
+ end
+end
+
+filters.generic = { }
+
+function filters.generic.title(data)
+ if data then
+ local titledata = data.titledata
+ if titledata then
+ helpers.title(titledata.title or "?",data.metadata)
+ end
+ end
+end
+
+function filters.generic.number(data) -- todo: spec and then no stopper
+ if data then
+ helpers.prefix(data)
+ local numberdata = data.numberdata
+ if numberdata then
+ sections.typesetnumber(numberdata,"number",numberdata or false)
+ end
+ end
+end
+
+function filters.generic.page(data,prefixspec,pagespec)
+ helpers.prefixpage(data,prefixspec,pagespec)
+end
+
+filters.text = { }
+
+function filters.text.title(data)
+-- texsprint(ctxcatcodes,"[text title]")
+ helpers.title(data.entries.text or "?",data.metadata)
+end
+
+function filters.text.number(data)
+-- texsprint(ctxcatcodes,"[text number]")
+ helpers.title(data.entries.text or "?",data.metadata)
+end
+
+function filters.text.page(data,prefixspec,pagespec)
+ helpers.prefixpage(data,prefixspec,pagespec)
+end
+
+--~ filters.section = { }
+
+--~ filters.section.title = filters.generic.title
+--~ filters.section.number = filters.generic.number
+--~ filters.section.page = filters.generic.page
+
+--~ filters.float = { }
+
+--~ filters.float.title = filters.generic.title
+--~ filters.float.number = filters.generic.number
+--~ filters.float.page = filters.generic.page
+
+-- each method gets its own call, so that we can later move completely to lua
+
+local gotoinner = "\\gotoinner{%s}{%s}{%s}{%s}" -- prefix inner page data
+local gotoouterfilelocation = "\\gotoouterfilelocation{%s}{%s}{%s}{%s}" -- file location page data
+local gotoouterfilepage = "\\gotoouterfilepage{%s}{%s}{%s}" -- file page data
+local gotoouterurl = "\\gotoouterurl{%s}{%s}{%s}" -- url args data
+local gotoinnerpage = "\\gotoinnerpage{%s}{%s}" -- page data
+local gotospecial = "\\gotospecial{%s}{%s}{%s}{%s}{%s}" -- action, special, operation, arguments, data
+
+runners["inner"] = function(var,content)
+ -- inner
+ currentreference = var
+ local r = var.r
+ return (r and format(gotoinner,var.p or "",var.inner,r,content)) or "error"
+end
+
+runners["inner with arguments"] = function(var,content)
+ -- inner{argument}
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["outer"] = function(var,content)
+ -- outer::
+ -- todo: resolve url/file name
+ currentreference = var
+ local url = ""
+ local file = var.o
+ return format(gotoouterfilepage,url,file,1,content)
+end
+
+runners["outer with inner"] = function(var,content)
+ -- outer::inner
+ -- todo: resolve url/file name
+ currentreference = var
+ local r = var.r
+ return (r and format(gotoouterfilelocation,var.f,var.inner,r,content)) or "error"
+end
+
+runners["special outer with operation"] = function(var,content)
+ -- special(outer::operation)
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["special outer"] = function(var,content)
+ -- special()
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["special"] = function(var,content)
+ -- special(operation)
+ currentreference = var
+ local handler = specials[var.special]
+ if handler then
+ return handler(var,content) -- var.special wegwerken
+ else
+ return ""
+ end
+end
+
+runners["outer with inner with arguments"] = function(var,content)
+ -- outer::inner{argument}
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["outer with special and operation and arguments"] = function(var,content)
+ -- outer::special(operation{argument,argument})
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["outer with special"] = function(var,content)
+ -- outer::special()
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["outer with special and operation"] = function(var,content)
+ -- outer::special(operation)
+ currentreference = var
+ return "todo: " .. var.kind or "?"
+end
+
+runners["special operation"] = runners["special"]
+runners["special operation with arguments"] = runners["special"]
+
+local gotoactionspecial = "\\gotoactionspecial{%s}{%s}{%s}{%s}"
+local gotopagespecial = "\\gotopagespecial{%s}{%s}{%s}{%s}"
+local gotourlspecial = "\\gotourlspecial{%s}{%s}{%s}{%s}"
+local gotofilespecial = "\\gotofilespecial{%s}{%s}{%s}{%s}"
+local gotoprogramspecial = "\\gotoprogramspecial{%s}{%s}{%s}{%s}"
+local gotojavascriptspecial = "\\gotojavascriptspecial{%s}{%s}{%s}{%s}"
+
+function specials.action(var,content)
+ return format(gotoactionspecial,var.special,var.operation,var.arguments or "",content)
+end
+
+function specials.page(var,content)
+ -- we need to deal with page(inner) and page(outer::1) and outer::page(1)
+ return format(gotopagespecial,var.special,var.operation,var.arguments or "",content)
+end
+
+function specials.url(var,content)
+ local url = var.operation
+ if url then
+ local u = urls[url]
+ if u then
+ local u, f = u[1], u[2]
+ if f and f ~= "" then
+ url = u .. "/" .. f
+ else
+ url = u
+ end
+ end
+ end
+ return format(gotourlspecial,var.special,url,var.arguments or "",content)
+end
+
+function specials.file(var,content)
+ local file = var.operation
+ if file then
+ local f = files[file]
+ if f then
+ file = f[1]
+ end
+ end
+ return format(gotofilespecial,var.special,file,var.arguments or "",content)
+end
+
+function specials.program(var,content)
+ local program = var.operation
+ if program then
+ local p = programs[program]
+ if p then
+ programs = p[1]
+ end
+ end
+ return format(gotoprogramspecial,var.special,program,var.arguments or "",content)
+end
+
+function specials.javascript(var,content)
+ -- todo: store js code in lua
+ return format(gotojavascriptspecial,var.special,var.operation,var.arguments or "",content)
+end
+
+specials.JS = specials.javascript
+
+structure.references = structure.references or { }
+structure.helpers = structure.helpers or { }
+
+local references = structure.references
+local helpers = structure.helpers
+
+function references.sectiontitle(n)
+ helpers.sectiontitle(lists.collected[tonumber(n) or 0])
+end
+
+function references.sectionnumber(n)
+ helpers.sectionnumber(lists.collected[tonumber(n) or 0])
+end
+
+function references.sectionpage(n,prefixspec,pagespec)
+ helpers.prefixedpage(lists.collected[tonumber(n) or 0],prefixspec,pagespec)
+end
+
diff --git a/tex/context/base/strc-ref.tex b/tex/context/base/strc-ref.tex
new file mode 100644
index 000000000..23fc3e01e
--- /dev/null
+++ b/tex/context/base/strc-ref.tex
@@ -0,0 +1,1905 @@
+%D \module
+%D [ file=strc-ref,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Cross Referencing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Cross Referencing}
+
+\registerctxluafile{strc-ref}{1.001}
+
+\unprotect
+
+%D This module is a (partial) rewrite of core-ref.tex for \MKIV. As
+%D such it will be a moving target for a while.
+
+%D Later we will do a further cleanup and move much of the code to
+%D \LUA\ (i.e.\ better backend integration).
+
+\let\mainreference\gobblefivearguments
+
+% this will go when we got rid of the tuo file
+
+\let\currentfolioreference \!!zerocount % only used in xml-fo
+\let\resetreferences \relax
+\let\setreferences \relax
+\let\showcurrentreference \relax
+\let\setexecutecommandcheck\gobbletwoarguments
+
+\def\s!full{full}
+\def\s!text{text}
+\def\s!page{page}
+
+% todo : unknown/illegal reference no arg
+% todo : +n pages check on 'samepage' (contrastcolor)
+% todo : multiple text in reference
+
+% Makes more sense to build action data first, especially now
+% openaction etc are supported.
+%
+% \definespecial\doexecuteactionchain w h
+% \definespecial\dosetgotolocation
+% \definespecial\dosetexecuteJScode
+% ...
+
+%D This module deals with referencing. In \CONTEXT\ referencing
+%D is one of the core features, although at a first glance
+%D probably nobody will notice. This is good, because
+%D referencing should be as hidden as possible.
+%D
+%D In paper documents, referencing comes down to cross
+%D referencing, but in their interactive counterparts, is also
+%D involves navigation. Many features implemented here are
+%D therefore closely related to navigation.
+%D
+%D Many \CONTEXT\ commands can optionally be fed with a
+%D reference. Such a reference, when called upon, returns the
+%D number of a figure, table, chapter etc, a piece of text, or
+%D a pagenumber.
+%D
+%D There are three ways of defining a reference:
+%D
+%D \starttyping
+%D \pagereference[here]
+%D \textreference[here]{some text}
+%D \stoptyping
+%D
+%D the third alternative combines them in:
+%D
+%D \starttyping
+%D \reference[here]{some text}
+%D \stoptyping
+
+\def\textreference {\dosingleargument\dotextreference}
+\def\pagereference {\dosingleargument\dopagereference}
+\def\reference {\dosingleargument\doreference }
+
+%D These are implemented in a low level form as:
+
+\def\dotextreference[#1]{\dosetreference\s!text{#1}}
+\def\dopagereference[#1]{\dosetreference\s!page{#1}{}}
+\def\doreference [#1]{\dosetreference\s!full{#1}}
+
+%D Actually there is not much difference between a text and a
+%D full reference, but it's the concept that counts. The low
+%D level implementation is:
+
+\newcount\crossreferencenumber
+
+\def\dofinishfullreference#1#2%
+ {\normalexpanded{\noexpand\ctxlatelua{jobreferences.enhance("#1","#2")}}%
+ \referenceinfo>{#1\letterbar#2}}
+
+\let\dofinishpagereference\dofinishfullreference
+
+\def\dofinishtextreference#1#2%
+ {\normalexpanded{\noexpand\ctxlatelua{jobreferences.enhance("#1","#2",{})}}%
+ \referenceinfo>{#1\letterbar#2}}
+
+\def\dosetreference#1#2#3% kind labels text -> todo: userdata
+ {\ifreferencing
+ \global\advance\crossreferencenumber\plusone
+ \edef\currentreferencekind{#1}%
+ \edef\currentreferencelabels{#2}%
+ \edef\currentreferenceexpansion{\@@rfexpansion}% {\referenceparameter\c!expansion}
+ \ifx\currentreferencelabels\empty \else
+ \ifx\currentreferenceexpansion\s!xml
+ \xmlstartraw
+ \xdef\currentreferencetext{#3}%
+ \xmlstopraw
+ \globallet\currentreferencecoding\s!xml
+ \else
+ \ifx\currentreferenceexpansion\v!yes
+ \xdef\currentreferencetext{#3}%
+ \else
+ \xdef\currentreferencetext{\detokenize{#3}}%
+ \fi
+ \globallet\currentreferencecoding\s!tex
+ \fi
+ \setnextinternalreference
+ \ctxlua {
+ jobreferences.set("\currentreferencekind", "\referenceprefix","\currentreferencelabels",
+ {
+ references = {
+ internal = \nextinternalreference,
+ block = "\currentstructureblock",
+ section = structure.sections.currentid(),
+ },
+ metadata = {
+ kind = "#1",
+ catcodes = \the\catcodetable,
+ xmlroot = \ifx\currentreferencecoding\s!xml "\xmldocument" \else nil \fi, % only useful when text
+ },
+ entries = {
+ text = \!!bs\currentreferencetext\!!es
+ }
+ })
+ jobreferences.setinternalreference("\referenceprefix","\currentreferencelabels",\nextinternalreference)
+ }%
+ \fi
+ \fi}
+
+%D For compatibility we provide:
+
+\def\rawreference #1#2#3{\dosetreference\s!full{#2}{#3}} % tag, labels, text
+\def\rawpagereference #1#2{\dosetreference\s!page{#2}{}} % tag, labels
+\def\rawtextreference#1#2#3{\dosetreference\s!text{#2}{#3}} % tag, labels, text
+
+\def\defaultreferencepage#1{[[[#1]]]}
+\def\defaultreferencetext#1{[[[#1]]]}
+
+%D These macros depend on three other ones,
+%D \type {\makesectionformat}, that generated \type
+%D {\sectionformat}, \type {\pagenumber}. The not yet used
+%D argument \type{#1} is a tag that specifies the type of
+%D reference.
+
+%D \macros
+%D {everyreference}
+%D
+%D For rather tricky purposes, one can assign sanitizing
+%D macros to \type{\everyreference} (no longer that relevant).
+
+\newevery \everyreference \relax
+
+%D This is really needed, since for instance Polish has a
+%D different alphabet and needs accented entries in registers.
+
+\appendtoks
+ \cleanupfeatures
+\to \everyreference
+
+%D We did not yet discuss prefixing. Especially in interactive
+%D documents, it's not always easy to keep track of duplicate
+%D references. The prefix mechanism, which we will describe
+%D later on, solves this problem. By (automatically) adding a
+%D prefix one keeps references local, but the global ones in
+%D view. To enable this feature, we explictly split the prefix
+%D from the reference.
+
+\let\referenceprefix\empty
+
+%D For a long time the only way to access an external file was
+%D to use the file prefix (\type {somefile::}. However, when
+%D you split up a document, redefining the references may be
+%D such a pain, that another approach is feasible. By setting
+%D the \type {autofile} variable to \type {yes} or \type
+%D {page}, you can access the reference directly.
+%D
+%D \starttabulate[||||]
+%D \NC filename::tag \NC page(filename::pnum) \NC tag \NC\NR
+%D \NC $\star$ \NC \NC \NC\NR
+%D \NC $\star$ \NC $\star$ \NC $\star$ \NC\NR
+%D \NC \NC $\star$ \NC \NC\NR
+%D \stoptabulate
+
+\def\usereferences[#1]%
+ {\writestatus\m!systems{references from other files are handled automatically}}
+
+%D As mentioned we will also use the cross reference mechanism
+%D for navigational purposes. The main reason for this is that
+%D we want to treat both categories alike:
+%D
+%D \starttyping
+%D \goto{go back}[PreviousJump]
+%D \goto{colofon}[colofon page]
+%D \stoptyping
+%D
+%D Here \type{PreviousJump} is handled by the viewer, while the
+%D \type{colofon page} reference is, apart from hyperlinking, a
+%D rather normal reference.
+%D
+%D We already saw that cross refences are written to and read
+%D from a file. The pure navigational ones don't need to be
+%D written to file, but both for fast processing and
+%D transparant integration, they are saved internally as a sort
+%D of reference. We can easily distinguish such system
+%D references from real cross reference ones by their tag.
+%D
+%D We also use the odd/even characteristic to determine the
+%D page state.
+
+\let\currentrealreference \empty
+\let\currentpagereference \empty
+\let\currenttextreference \empty
+\let\currentreferenceorder \empty
+\let\currentsubtextreference \empty
+\let\currentsubsubtextreference\empty
+
+%D System references only have one component:
+
+\newif\ifforwardreference
+\newif\ifrealreferencepage
+
+\def\docheckrealreferencepage#1% todo
+ {\doifnumberelse{#1}
+ {\ifnum#1=\realpageno
+ \realreferencepagetrue
+ \else
+ \realreferencepagefalse
+ \fi}
+ {\realreferencepagefalse}}
+
+%D Text references can contain more than one entry and
+%D therefore we check for
+%D
+%D \starttyping
+%D {entry}
+%D \stoptyping
+%D
+%D or
+%D
+%D \starttyping
+%D {{entry}{entry}{entry}}
+%D \stoptyping
+%D
+%D and split accordingly.
+
+% todo:
+
+\def\doifforwardreferenceelse#1#2% todo
+ {\iffalse}
+
+%D Cross references appear as numbers (figure~1.1, chapter~2)
+%D or pagenumbers (page~2, page 3--2), and are called with
+%D \type{\in} and \type{\at}. In interactive documents we also
+%D have \type{\goto}, \type{\button} and alike. These are more
+%D versatile and look like:
+%D
+%D \starttyping
+%D \goto[reference]
+%D \goto[outer reference::]
+%D \goto[outer reference::inner reference]
+%D \goto[operation(argument)]
+%D \goto[operation(action{argument,argument})]
+%D \goto[action]
+%D \goto[action{argument}]
+%D \stoptyping
+%D
+%D The first one is a normal reference, the second and third
+%D are references to a file or \URL. The brace delimited
+%D references for instance refer to a \JAVASCRIPT. The last
+%D example shows that we can pass arguments to the actions.
+%D
+%D When we split off the components of such a reference, the
+%D results are available in:
+%D
+%D \starttyping
+%D \currentreferencespecial
+%D \currentreferenceoperation
+%D \currentreferencearguments
+%D \currentinnerreference
+%D \currentouterreference
+%D \currentfullreference
+%D \stoptyping
+
+\newif\ifreferencefound
+
+\let\currentfullreference \empty
+\let\currentreferencespecial \empty
+\let\currentreferenceoperation\empty
+\let\currentreferencearguments\empty
+\let\currentouterreference \empty
+\let\currentinnerreference \empty
+
+\def\setreferencevariables#1#2#3#4#5%
+ {\def\currentreferencespecial {#1}%
+ \def\currentreferenceoperation{#2}%
+ \def\currentreferencearguments{#3}%
+ \def\currentouterreference {#4}%
+ \def\currentinnerreference {#5}}
+
+%D Now we've come to the testing step. As we can see below,
+%D this macro does bit more than testing: it also resolves
+%D the reference. This means that whenever we test for the
+%D existance of a reference at an outer level, we have all the
+%D relevant properties of that reference avaliable inside the
+%D true branche~(\type{#2}).
+%D
+%D The prefix has to do with localizing references. When a
+%D prefix is set, looking for a reference comes to looking for
+%D the prefixed one, and when not found, looking for the non
+%D prefixed one. Consider for instance the prefix set to
+%D \type{sidetrack}.
+%D
+%D \starttyping
+%D \pagereference[important]
+%D \pagereference[unimportant]
+%D \setupreferencing[prefix=sidetrack]
+%D \pagereference[important]
+%D \stoptyping
+%D
+%D results in saving (writing) the references
+%D
+%D \starttyping
+%D ...{}{important}
+%D ...{}{unimportant}
+%D ...{sidetrack}{important}...
+%D \stoptyping
+%D
+%D Now when we call for \type{unimportant}, we will indeed get
+%D the pagenumber associated to this reference. But when we
+%D call for \type{important}, while the prefix is still set, we
+%D will get the pagenumber bound to the prefixed one.
+%D
+%D {\em Some day, when processing time and memory are no longer
+%D performance factors, we will introduce multi||level
+%D prefixes.}
+%D
+%D Before we start analyzing, I introduce a general
+%D definition macro. Consider:
+%D
+%D \starttyping
+%D \goto{do}[JS(My_Script{"test",123}),titlepage]
+%D \stoptyping
+%D
+%D This can also be achieved by:
+%D
+%D \starttyping
+%D \definereference[startup][JS(My_Script{"test",123}),titlepage]
+%D \goto{do}[REF(startup)]
+%D \stoptyping
+%D
+%D Now is this is a handy feature or not?
+%D
+%D \showsetup{definereference}
+%D
+%D We can trace references by setting the next switch to
+%D true.
+
+\def\definereference
+ {\dodoubleempty\dodefinereference}
+
+\def\dodefinereference[#1][#2]%
+ {\ctxlua{jobreferences.define("\referenceprefix","#1",\!!bs\detokenize{#2}\!!es)}}
+
+\def\resetreference[#1]%
+ {\ctxlua{jobreferences.reset("\referenceprefix","#1")}}
+
+\def\setpagereference#1#2% name, specification
+ {\ctxlua{jobreferences.define("","#1",\!!bs\v!page(\luaescapestring{#2})\!!es)}}
+
+%D Chained references are defined as:
+%D
+%D \starttyping
+%D \goto{somewhere}[JS(somescript),nextpage,JS(anotherscript)]
+%D \stoptyping
+%D
+%D Actually supporting chains is up to the special driver. Here
+%D we only provide the hooks.
+
+\newif \ifsecondaryreference
+\newcount\nofsecondaryreferences
+
+% the counter stuff should move to the (mkiv) backend
+
+\def\doifreferencefoundelse#1%
+ {\ctxlua{jobreferences.doifelse("\referenceprefix","#1")}}
+
+\def\doprocessreferenceelse#1#2#3%
+ {\doresetgotowhereever
+ \nofsecondaryreferences\zerocount
+ \def\primaryreferencefoundaction {\secondaryreferencefalse#2}%
+ \def\secondaryreferencefoundaction{\advance\nofsecondaryreferences\plusone\secondaryreferencetrue#2}%
+ \def\referenceunknownaction {#3}%
+ \ctxlua{jobreferences.handle("\referenceprefix","#1")}%
+ \doresetgotowhereever} % to prevent problems with direct goto's
+
+%D The inner case is simple. Only two cases have to be taken
+%D care of:
+%D
+%D \starttyping
+%D \goto{some text}[reference]
+%D \goto{some text}[prefix:reference]
+%D \stoptyping
+%D
+%D References to other files however are treated strict or
+%D tolerant, depending on their loading and availability:
+%D
+%D \starttyping
+%D \useexternaldocument[somefile][filename][a nice description]
+%D
+%D \goto{checked reference}[somefile::reference]
+%D \goto{unchecked reference}[somefile::]
+%D \goto{unchecked reference}[anotherfile::reference]
+%D \stoptyping
+%D
+%D An unknown reference is reported on the screen, in the log
+%D file and, when enabled, in the left margin of the text.
+
+\def\reportreferenceerror#1#2% only once (keep track in lua)
+ {\ifinpagebody \else
+ \doifconcepttracing{\doifsomething{#2}{\inleft{\infofont\doboundtext{#2}{\dimexpr\leftmarginwidth-2em\relax}{..}->}}}%
+ \fi
+ \showmessage\m!references{#1}{[\referenceprefix][#2]}}
+
+\def\unknownreference{\reportreferenceerror1}
+\def\illegalreference{\reportreferenceerror4}
+
+%D When a reference is not found, we typeset a placeholder
+%D (two glyphs are often enough to represent the reference
+%D text).
+
+\def\dummyreference{{\tttf ??}}
+
+%D To prevent repetitive messages concerning a reference
+%D being defined, we set such an unknown reference to an empty
+%D one after the first encounter.
+
+%D Sometimes we want to temporary put a reference out of
+%D order. An example can be found in the menu macros.
+%D
+%D \starttyping
+%D \doifreferencepermittedelse{reference}{set}{true}{false}
+%D \stoptyping
+%D
+%D The second argument can be a comma seperated list.
+
+\let\permittedreferences\empty
+
+ \def\doifreferencepermittedelse#1#2#3% ref found notfound
+ {\doprocessreferenceelse{#1}
+ {\donetrue
+ \ifx\permittedreferences\empty \else
+ \docheckifreferencepermitted{#1}%
+ \fi
+ \ifdone#2\else#3\fi}
+ {#3\unknownreference{#1}}}
+
+ \def\docheckifreferencepermitted#1%
+ {\ifx\currentinnerreference\empty
+ \ifx\currentouterreference\empty \else
+ \doifinstring{\currentouterreference::}\permittedreferences\donefalse
+ \fi
+ \else\ifx\currentouterreference\empty
+ \doifinstring{\currentinnerreference}\permittedreferences\donefalse
+ \else
+ \doifinstring{\currentouterreference::\currentinnerreference}\permittedreferences\donefalse
+ \fi\fi}
+
+%D Apart from cross references supplied by the user, \CONTEXT\
+%D generates cross references itself. Most of them are not
+%D saved as a reference, but stored with their source, for
+%D instance a list or an index entry. Such automatically
+%D generated, for the user invisible, references are called
+%D {\em internal references}. The user supplied ones are
+%D labeled as {\em external references}.
+%D
+%D A second important characteristic is that when we want to
+%D support different backends (viewers), we need to support
+%D named destinations as well as page numbers. I invite readers
+%D to take a glance at the special driver modules to understand
+%D the fine points of this. As a result we will deal with {\em
+%D locations} as well as {\em real page numbers}. We explictly
+%D call this pagenumber a real one, because it is independant
+%D of the page numbering scheme used in the document.
+%D
+%D One of the reasons for \CONTEXT\ being the first \TEX\ base
+%D macropackage to support sophisticated interactive \PDF\
+%D files, lays in the mere fact that real page numbers are
+%D available in most two pass data, like references, list data
+%D and index entries.
+%D
+%D We will speak of \type{thisis...} when we are marking a
+%D location, and \type{goto...} when we point to such a
+%D location. The latter one can be seen as a hyperlink to the
+%D former one. In the next macros one we use constructs like:
+%D
+%D \starttyping
+%D \dostart...
+%D \dostop...
+%D \stoptyping
+%D
+%D Such macros are used to invoke the relevant specials from
+%D the special driver modules (see \type{spec-ini}). The flag
+%D \type{\iflocation} signals if we're in interactive mode.
+
+\def\thisisdestination#1% destination
+ {\iflocation \ifusepagedestinations \else
+ \dostartthisislocation{#1}\dostopthisislocation
+ \fi \fi}
+
+\def\thisisrealpage#1% pagenumber
+ {\iflocation
+ \dostartthisisrealpage{#1}\dostopthisisrealpage
+ \fi}
+
+%D The previous tho macros were easy ones, opposite to their
+%D counterparts. A common component in these is:
+%D
+%D \starttyping
+%D \dohandlegoto{..}{..}{..}
+%D \stoptyping
+%D
+%D Here data can be whatever needs highlighting, e.g. {\em
+%D figure 2.4}, and the start and stop entries handle the
+%D specials. The two \DIMENSIONS\ \type{\buttonwidth} and
+%D \type{\buttonheight} have to be set when handling the
+%D data~(\type{#2}).
+
+\ifx\buttonheight\undefined \newdimen\buttonheight \fi
+\ifx\buttonwidth \undefined \newdimen\buttonwidth \fi
+
+\def\gotodestination#1#2#3#4#5% url file destination page data
+ {\iflocation
+ \ifusepagedestinations
+ \gotorealpage{#1}{#2}{\number#4}{#5}%
+ \else
+ \dohandlegoto
+ {#5}%
+ {\the\everyreference\dostartgotolocation\buttonwidth\buttonheight{#1}{#2}{#3}{\number#4}}%
+ {\dostopgotolocation}%
+ \fi
+ \else
+ {#5}%
+ \fi}
+
+ \def\gotorealpage#1#2#3#4% url file page data
+ {\iflocation
+ \dohandlegoto
+ {#4}%
+ {\dostartgotorealpage\buttonwidth\buttonheight{#1}{#2}{\number#3}}%
+ {\dostopgotorealpage}%
+ \else
+ {#4}%
+ \fi}
+
+\def\gotoinnerpage#1#2% page data
+ {\iflocation
+ \dohandlegoto
+ {#2}%
+ {\dostartgotorealpage\buttonwidth\buttonheight\empty\empty{\number#1}}%
+ {\dostopgotorealpage}%
+ \else
+ {#2}%
+ \fi}
+
+\def\gotoouterfilepage#1#2#3% file page data
+ {\iflocation
+ \dohandlegoto
+ {#3}%
+ {\dostartgotorealpage\buttonwidth\buttonheight\empty{#1}{\number#2}}%
+ {\dostopgotorealpage}%
+ \else
+ {#3}%
+ \fi}
+
+%D \macros
+%D {setreferencefilename}
+%D
+%D This command can be used in the special drivers to
+%D uppercase filenames. This is needed when one wants to
+%D produce \CDROM's conforming to ISO9660. We consider is the
+%D savest to enable this feature by default. We cannot handle
+%D uppercase here, since the suffix is handled in the special
+%D driver. Conversion is taken care of by:
+%D
+%D \starttyping
+%D \setreferencefilename somefilename\to\SomeFileName
+%D \stoptyping
+
+\chardef\referencefilecase=0
+
+ \def\setreferencefilename#1\to#2%
+ {\ifcase\referencefilecase
+ \edef#2{#1}%
+ \or
+ \uppercasestring#1\to#2%
+ \or
+ \lowercasestring#1\to#2%
+ \else
+ \edef#2{#1}%
+ \fi}
+
+%D Internal references can best be set using the next few
+%D macros. Setting such references to unique values is
+%D completely up to the macros that call them.
+%D
+%D \starttyping
+%D \thisissomeinternal{tag}{identifier}
+%D \gotosomeinternal {tag}{identifier}{pagenumber}{text}
+%D \stoptyping
+
+\def\thisissomeinternal#1#2% tag reference
+ {\doifsomething{#2}{\thisisdestination{#1:#2}}}
+
+\def\gotosomeinternal#1#2% #3#4
+ {\gotodestination\empty\empty{#1:#2}}
+
+%D An automatic mechanism is provided too:
+%D
+%D \starttyping
+%D \thisisnextinternal{tag}
+%D \gotonextinternal {tag}{number}{pagenumber}{text}
+%D \stoptyping
+%D
+%D The first macro increments a counter. The value of this
+%D counter is available in the macro \type{\nextinternalreference}
+%D and should be saved somewhere (for instance in a file) for
+%D future reference. The second argument of
+%D \type {\gotonextinternal} takes such a saved number. One can
+%D turn on tracing these references, in which case the
+%D references are a bit more verbose.
+
+\newcount\locationcount
+
+\newif\ifinternalnamedreferences \internalnamedreferencestrue
+
+\def\nextinternalreference
+ {\the\locationcount}
+
+\def\setnextinternalreference
+ {\global\advance\locationcount\plusone}
+
+\def\thisisnextinternal#1% #1 will be removed when we are done with mkiv
+ {\ifinternalnamedreferences
+ \thisisdestination{\s!aut:\nextinternalreference}%
+ \fi}
+
+\def\insertnextinternal#1%
+ {\ifinternalnamedreferences
+ \thisisdestination{\s!aut:\number#1}%
+ \fi}
+
+\def\gotonextinternal#1#2#3#4% #1 will be removed when we are done with mkiv
+ {\ifinternalnamedreferences
+ \gotodestination\empty\empty{\s!aut:#2}{#3}{#4}%
+ \else
+ \gotorealpage\empty\empty{#3}{#4}%
+ \fi}
+
+%D We already went through a lot of problems to sort out what
+%D kind of reference we're dealing with. Sorting out the user
+%D supplied cross references (show/goto this or that) as well
+%D as user supplied system references (invoke this or that) is
+%D already taken care of in the test routine, but we still have
+%D to direct the request to the right (first) routine.
+
+\def\gotolocation#1#2{\doprocessreferenceelse{#1}{#2}{\unknownreference{#1}}} % obsolete
+
+%D An inner reference refers to some place in the document
+%D itself.
+
+ \def\gotoinnerlocation#1% #2%
+ {\gotodestination\empty\empty{\referenceprefix\currentinnerreference}\currentrealreference} % {#2}
+
+\def\gotoinner#1#2#3% prefix inner page data
+ {\gotodestination\empty\empty{#1#2}{#3}} % {#4}
+
+%D The outer location refers to another document, specified as
+%D file or \URL.
+
+ \def\gotoouterlocation#1#2% % page checken!
+ {\bgroup
+ \let\referenceprefix\empty
+ \setouterlocation\currentouterreference
+ \ifx\currentinnerreference\empty
+ \gotorealpage\otherURL\otherfile1{#2}%
+ \else
+ \gotodestination\otherURL\otherfile\currentinnerreference\currentrealreference{#2}%
+ \fi
+ \egroup}
+
+\def\gotoouterfile#1#2% file location page data #3 #4
+ {\doifelsenothing{#2}{\gotorealpage\empty{#1}}{\gotodestination\empty{#1}{#2}}}
+
+\def\gotoouterfilepage#1% file page data
+ {\gotorealpage\empty{#1}\empty}
+
+\def\gotoouterfilelocation% file location page data
+ {\gotodestination\empty}
+
+\def\gotoouterurl#1#2% url args data #2
+ {\gotodestination{#1}\empty{#2}1}
+
+%D Special locations are those that are accessed by saying
+%D things like:
+%D
+%D \starttyping
+%D \goto{calculate total}[JS(summarize{10,23,56}]
+%D \stoptyping
+%D
+%D After several intermediate steps this finally arrives at
+%D the next macro and expands into (simplified):
+%D
+%D \starttyping
+%D \gotoJSlocation{total{summarize{10,23,56}}}{calculate total}
+%D \stoptyping
+%D
+%D The first argument is the full reference, the second one
+%D is the text, in some kind of manipulated form. In practice
+%D we split references, so we get:
+%D
+%D \starttyping
+%D \gotoJSlocation{summarize{10,23,56}}{calculate}
+%D \gotoJSlocation{summarize{10,23,56}}{total}
+%D \stoptyping
+%D
+%D where \type{calculate} and \type{total} are colored, boxed
+%D or whatever \type{\goto} is told to do.
+%D
+%D The macro \type{\gotoJSlocation} can use \type
+%D {\currentreferenceoperation} (in our example
+%D \type{summarize}) and \type{\currentreference} (here
+%D being \type {10,23,56}) to perform its task.
+
+ \def\gotospeciallocation
+ {\executeifdefined{goto\currentreferencespecial location}\gobbleoneargument}
+
+%D Such special macros can be defined by:
+
+ \def\definespeciallocation#1%
+ {\setvalue{goto#1location}}
+
+%D The associated test is to be defined by:
+
+\def\definespecialtest#1%
+ {\setvalue{\s!do:\v!test:#1}}
+
+%D This \type{\def} alike macro is to be used as:
+%D
+%D \starttyping
+%D \definespeciallocation{JS}#1#2{... #1 ... #2 ...}
+%D \stoptyping
+%D
+%D In module \type {java-ini} one can see that \type
+%D {\gotoJSlocation} looks much like the previous goto
+%D definitions.
+
+%D In this module we define three system references: one for
+%D handling navigational, viewer specific, commands, another
+%D for jumping to special pages, like the first or last one,
+%D and a third reference for linking tree like lists, like
+%D tables of contents. The latter two adapt themselves to the
+%D current state.
+%D
+%D An example of an action is:
+%D
+%D \starttyping
+%D \goto{some action}[PreviousJump]
+%D \stoptyping
+%D
+%D as well as:
+%D
+%D \starttyping
+%D \goto{some text}[\v!action(PreviousJump]
+%D \stoptyping
+
+% compatibility hack
+
+\def\setglobalsystemreference#1#2#3{\definereference[#2][\v!action(#3)]}
+
+% action actions
+
+\def\gotoactionspecial#1#2#3#4% special operation arguments data
+ {\begingroup
+ \iflocation
+ \dohandlegoto
+ {#4}%
+ {\dostartexecutecommand\buttonwidth\buttonheight{#2}{#3}}%
+ {\dostopexecutecommand}%
+ \else
+ #4%
+ \fi
+ \endgroup}
+
+\def\gotopagespecial#1#2#3#4% page(n) page(+n) page(-n) page(file::1)
+ {\begingroup
+ \iflocation
+ \doifnonzeropositiveelse{#2}
+ {\doifinstringelse+{#2}
+ {\edef\currenttargetpage{\the\numexpr\realpageno#2}}
+ {\doifinstringelse-{#2}
+ {\edef\currenttargetpage{\the\numexpr\realpageno#2}}
+ {\edef\currenttargetpage{#2}}}}%
+ {\edef\currenttargetpage{1}}%
+ \docheckrealreferencepage\currenttargetpage % new
+ \gotorealpage\empty\empty\currenttargetpage{#4}%
+ \else
+ #4%
+ \fi
+ \endgroup}
+
+%D It is possible to disable the writing of references to the
+%D utility file by setting:
+
+\newif\ifreferencing \referencingtrue
+
+%D One can also activate an automatic prefix mechanism. By
+%D setting the \type{\prefix} variable to \type{+}, the prefix
+%D is incremented, when set to \type{-} or empty, the prefix is
+%D reset. Other values become the prefix.
+
+\newcount\prefixcounter
+
+%D These settings are accomplished by:
+%D
+%D \showsetup{setupreferencing}
+%D
+%D In interactive documents verbose references don't always
+%D make sense (what is a page number in an unnumbered
+%D document). By setting the \type{interaction} variable, one
+%D can influences the way interactive references are set.
+
+\chardef\autocrossfilereferences=0
+
+\def\setupreferencing
+ {\dosingleargument\dosetupreferencing}
+
+\def\dosetupreferencing[#1]%
+ {\getparameters
+ [\??rf]
+ [\c!prefix=\s!unknown,#1]%
+ \processaction
+ [\@@rfstate]
+ [ \v!stop=>\referencingfalse,
+ \v!start=>\referencingtrue]%
+ \processaction
+ [\@@rfinteraction]
+ [ \v!all=>\let\dowantedreference\docompletereference,
+ \v!label=>\let\dowantedreference\dolabelonlyreference,
+ \v!text=>\let\dowantedreference\dotextonlyreference,
+ \v!symbol=>\let\dowantedreference\dosymbolreference]%
+ \chardef\autocrossfilereferences\zerocount
+ \processaction
+ [\@@rfautofile]
+ [ \v!yes=>\chardef\autocrossfilereferences\plusone,
+ \v!page=>\chardef\autocrossfilereferences\plustwo]%
+ \chardef\referencefilecase\zerocount
+ \processaction[\@@rfconvertfile]
+ [ \v!yes=>\chardef\referencefilecase\plusone,
+ \v!big=>\chardef\referencefilecase\plusone,
+ \v!small=>\chardef\referencefilecase\plustwo]%
+ \setupreferenceprefix[\@@rfprefix]%
+ \doifelse\@@rfglobal\v!yes
+ {\settrue \autoglobalfilereferences}
+ {\setfalse\autoglobalfilereferences}}
+
+\def\incrementreferenceprefix{+}
+\def\decrementreferenceprefix{-}
+
+\def\setupreferenceprefix[#1]%
+ {\edef\@@rfprefix{#1}%
+ \ifx\@@rfprefix\empty
+ \let\referenceprefix\empty
+ \else\ifx\@@rfprefix\incrementreferenceprefix
+ \advance\prefixcounter \plusone % should be global
+ \edef\referenceprefix{\the\prefixcounter:}%
+ \let\@@rfprefix\s!unknown
+ \else\ifx\@@rfprefix\decrementreferenceprefix
+ \let\referenceprefix\empty
+ \let\@@rfprefix\s!unknown
+ \else\ifx\@@rfprefix\s!unknown
+ % forget about it
+ \else
+ \edef\referenceprefix{\@@rfprefix:}%
+ \fi\fi\fi\fi}
+
+%D \macros
+%D {handlereferenceactions,
+%D collectreferenceactions}
+%D
+%D Sometimes we need to pass the actions connected to
+%D references to variables instead of rectangular areas on
+%D which one can click. The next macro collects the actions
+%D and passes them to a handle. This is a rather dreadfull
+%D hack!
+%D
+%D \starttyping
+%D \handlereferenceactions{references}\handle
+%D \stoptyping
+%D
+%D So, \type {\handle} does the final job, which in for
+%D instance the \PDF\ drivers comes down to doing something
+%D with \type {\lastPDFaction}.
+
+\newif\ifcollectreferenceactions
+
+\def\handlereferenceactions#1#2%
+ {\doifsomething{#1}
+ {\bgroup
+ \collectreferenceactionstrue
+ \doprocessreferenceelse{#1}{#2}{\unknownreference{#1}}%
+ \egroup}}
+
+%D The most straightforward way of retrieving references is
+%D using \type{\ref}. Consider the reference:
+%D
+%D \startbuffer
+%D \reference[my ref]{{Look}{Here}{I am}}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D We can ask for upto five reference components:
+%D
+%D \startbuffer
+%D user page reference: \ref[p][my ref]
+%D text reference: \ref[t][my ref]
+%D real page reference: \ref[r][my ref]
+%D sub text reference: \ref[s][my ref]
+%D extra text reference: \ref[e][my ref]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D And get back:
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+\def\ref{\dodoubleargument\doref}
+
+\def\reftypep{\currentpagereference}
+\def\reftypet{\currenttextreference}
+\def\reftyper{\currentrealreference}
+\def\reftypes{\currentsubtextreference}
+\def\reftypee{\currentsubsubtextreference}
+
+\def\doref[#1][#2]%
+ {\ifsecondargument
+% \doifreferencefoundelse{#2}
+% {\executeifdefined{reftype#1}\reftypep}
+% {\unknownreference{#2}\dummyreference}%
+ \else
+ \dummyreference
+ \fi}
+
+%D We can typeset a reference using \type{\in}, \type{\at} and
+%D \type{\about} and goto specific locations using
+%D \type{\goto}. The last one does not make that much sense in
+%D a paper document. To complicate things, \PLAIN\ \TEX\ also
+%D implements an \type {\in} but fortunately that one only
+%D makes sense in math mode.
+%D
+%D Typesetting the reference is a bit more complicated than one
+%D would at first sight expect. This is due to the fact that we
+%D distinguish three (five) alternative calls:
+%D
+%D \placefigure
+%D [here][three calls]
+%D {Three alternatives reference calls.}
+%D {\startcombination[1*3]
+%D {\framed{\type{ \in }}} {a}
+%D {\framed{\type{ \at }}} {b}
+%D {\framed{\type{\goto}}} {c}
+%D \stopcombination}
+%D
+%D \startbuffer
+%D \in figure[fig:three calls]
+%D \in{figure}[fig:three calls]
+%D \in figure a[fig:three calls]
+%D \in{figure}{a}[fig:three calls]
+%D figure~\in[fig:three calls]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D This turns up as:
+%D
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D
+%D The dual \type{{}} results in a split reference. In a
+%D document meant for paper, one is tempted to use the last
+%D (most straightforward) alternative. When a document is also
+%D meant voor electronic distribution, the former alternatives
+%D have preference, because everything between the \type{\in}
+%D and~\type{[} becomes active (and when asked for, typeset
+%D in a different color and typeface).
+
+\definecommand in {\dospecialin}
+\definecommand at {\dospecialat}
+\definecommand about {\dospecialabout}
+\definecommand from {\dospecialfrom}
+\definecommand over {\dospecialabout} % needed here, else math problems
+
+\def\currentreferencenumber{\ctxlua{jobreferences.filter("number")}}
+\def\currentreferencepage {\ctxlua{jobreferences.filter("page")}}
+\def\currentreferencetitle {\ctxlua{jobreferences.filter("title")}}
+
+\unexpanded\def\dospecialin{\doinatreference\currentreferencenumber}
+\unexpanded\def\dospecialat{\doinatreference\currentreferencepage}
+
+\def\doinatreference#1%
+ {\doifnextoptionalelse{\dodoinatreference{#1}{}}{\dodoinatreference{#1}}}
+
+\def\dodoinatreference#1%
+ {\def\dododoinatreference{\dodododoinatreference{#1}}%
+ \futurelet\next\dododoinatreference}
+
+\unexpanded\def\dospecialabout[#1]%
+ {\dontleavehmode
+ \bgroup
+ \@@rfleft
+ \doprocessreferenceelse{#1}
+ {\let\crlf\space
+ \let\\\space
+ \let\dogotofixed\dogotospace
+ \dogotospace{\limitatetext\currentreferencetitle\@@rfwidth\unknown}[#1]}
+ {\unknownreference{#1}\dummyreference}%
+ \@@rfright
+ \referenceinfo{<}{#1}%
+ \egroup}
+
+%D We arrived at the last step. Before we do the typesetting,
+%D we forget all previous (paragraph bound) settings and make
+%D sure that we remain in horizontal mode. Next we choose
+%D among the several representations.
+
+%D The previously discussed setup macro lets us specify the
+%D representation of references. A symbol reference does not
+%D show the specific data, like the number of a figure, but
+%D shows one of: \hbox {$^\goforwardcharacter$
+%D $^\gobackwardcharacter$ $^\gonowherecharacter$}, depending
+%D on the direction to go.
+
+ \def\dosymbolreference#1#2[#3]% todo
+ {\bgroup
+ \setupsymbolset[\@@iasymbolset]%
+ \removelastskip
+ \ifx\currentreferencespecial\empty
+ \ifx\currentouterreference\empty
+ \ifnum0\currentrealreference=\zerocount
+ \ifhmode\strut\high{\symbol[\v!nowhere]}\fi
+ \else\ifnum0\currentrealreference>\realpageno
+ \dodosymbolreference{#2}{\high{\symbol[\v!next]}}%
+ \else\ifnum0\currentrealreference<\realpageno
+ \dodosymbolreference{#2}{\high{\symbol[\v!previous]}}%
+ \else
+ \ifhmode\strut\high{\symbol[\v!nowhere]}\fi
+ \fi\fi\fi
+ \else
+ \gotoouterlocation{#3}{\showlocation{\high{\symbol[\v!somewhere]}}}%
+ \fi
+ \else
+ \gotospeciallocation{#3}{\showlocation{\high{\symbol[\v!somewhere]}}}%
+ \fi
+ \egroup}
+
+ \def\dodosymbolreference#1#2% todo
+ {#1\hbox{\gotorealpage\empty\empty\currentrealreference{\dolocationattributes\??ia\c!style\c!color{#2}}}}
+
+%D The other alternatives just conform their names: only the
+%D label, only the text, or the label and the text.
+
+\def\dounknownreference#1#2[#3]%
+ {\unknownreference{#3}\dotextprefix{#2}\dummyreference}%
+
+\def\docompletereference#1#2[#3]%
+ {\iflocationsplit
+ \doifsomespaceelse{#2}\dogotospace\dogotofixed{\dotextprefix{#2}#1}[#3]%
+ \else
+ \dogotofixed{\dotextprefix{#2}#1}[#3]%
+ \fi}
+
+\def\dolabelonlyreference#1#2[#3]%
+ {\doifsomespaceelse{#2}
+ {\doifsomething{#2}{\dogotospace{#2}[#3]}}
+ {\dogotofixed{\dotextprefix{#2}}[#3]}}
+
+\def\dotextonlyreference#1#2[#3]%
+ {\dotextprefix{#2}\dogotofixed{#1}[#3]}
+
+\let\dowantedreference\docompletereference
+
+%D \macros
+%D {definereferenceformat}
+%D
+%D The next few macros were made for for David Arnold and Taco
+%D Hoekwater. They can be used for predefining reference
+%D texts, and thereby stimulate efficiency.
+%D
+%D [more documentation will be added]
+%D
+%D \starttyping
+%D \definereferenceformat[informula] [left=(,right=),text=formula]
+%D \definereferenceformat[informulas] [left=(,right=),text=formulas]
+%D \definereferenceformat[andformula] [left=(,right=),text=and]
+%D \definereferenceformat[andformulas][left=(,right=),text=and]
+%D
+%D \informula [b] and \informula [for:c]
+%D the \informula {formulas}[b] \informula {and} [for:c]
+%D the \informulas {formulas}[b] \informula {and} [for:c]
+%D the \informulas [b] \informula {en} [for:c]
+%D the \informulas [b] \andformula [for:c]
+%D \stoptyping
+%D
+%D Instead of a text, one can specify a label, which should
+%D be defined with \type {\setuplabeltext}.
+
+% todo: inherit
+
+\def\definereferenceformat
+ {\dodoubleargument\dodefinereferenceformat}
+
+\def\dodefinereferenceformat[#1][#2]%
+ {\iffirstargument
+ \getparameters[\??rf#1]
+ [\c!left=, % of the number
+ \c!right=, % of the number
+ \c!text=, % before the number
+ \c!label=, % can be {left}{right}
+ \c!command=\in,
+ #2]%
+ \unexpanded\setvalue{#1}%
+ {\dontleavehmode\doexecutereferenceformat{#1}}%
+ \fi}
+
+\def\noexecutelabelreferenceformat#1%
+ {\doifvaluesomething{\??rf#1\c!text}
+ {\gdef\textofreference{\csname\??rf#1\c!text\endcsname}}%
+ \csname\??rf#1\c!command\endcsname}
+
+\def\doexecutelabelreferenceformat#1%
+ {\csname\??rf#1\c!command\endcsname
+ {\leftlabeltext {\csname\??rf#1\c!label\endcsname}}%
+ {\rightlabeltext{\csname\??rf#1\c!label\endcsname}}}
+
+\def\doexecutereferenceformat#1%
+ {\gdef\leftofreference {\csname\??rf#1\c!left \endcsname}%
+ \gdef\rightofreference{\csname\??rf#1\c!right\endcsname}%
+ \global\let\textofreference\empty % otherwise ~ added
+ \doifelsevaluenothing{\??rf#1\c!label}
+ \noexecutelabelreferenceformat\doexecutelabelreferenceformat{#1}}
+
+\let\leftofreference \relax
+\let\rightofreference\relax
+\let\textofreference \relax
+
+% fails on metafun {\leftofreference#1\ignorespaces#3\removeunwantedspaces\rightofreference}{#2}[#4]%
+
+\def\dodododoinatreference#1#2#3[#4]% no \removeunwantedspaces (fails on metafun)
+ {\ifx\next\bgroup
+ \dododododoinatreference{\leftofreference#1\ignorespaces#3\rightofreference}{#2}[#4]%
+ \else
+ \dododododoinatreference{\leftofreference#1\rightofreference}{#2#3}[#4]%
+ \fi}
+
+\let\dosymbolreference\dowantedreference
+
+\def\dododododoinatreference#1#2[#3]%
+ {\dontleavehmode % replaces \leaveoutervmode
+ \begingroup
+ \forgetall
+ \postponenotes
+ \doifreferencefoundelse{#3}
+ {\doifelsenothing{#1}\dosymbolreference\dowantedreference{#1}{#2}[#3]}%
+ {\dounknownreference{#1}{#2}[#3]}%
+ \referenceinfo<{#3}%
+ \endgroup}
+
+
+%D In interactive documents going to a specific location is not
+%D bound to cross references. The \type{\goto} commands can be
+%D used to let users access another part of the document. In
+%D this respect, interactive tables of contents and registers
+%D can be considered goto's. Because in fact a \type{\goto} is
+%D just a reference without reference specific data, the
+%D previous macros are implemented using the goto
+%D functionality.
+%D
+%D \showsetup{goto}
+%D
+%D One important chaacteristic is that the first argument of
+%D \type{\goto} (and therefore \type{\at} and \type{\in} is
+%D split at spaces. This means that, although hyphenation is
+%D prevented, long references can cross line endings.
+
+\newif\ifsharesimilarreferences \sharesimilarreferencestrue
+\newcount\similarreference % 0=noppes 1=create/refer 2,3,..=refer
+
+\unexpanded\def\goto#1#2%
+ {\dogoto{#1}#2}
+
+\def\dogoto#1[#2]%
+ {\dontleavehmode
+ \bgroup
+ \postponenotes
+ % todo: handle empty #1
+ \doifelsenothing{#1}
+ {\dosymbolreference{}{}[#2]}
+ {\dogotospace{#1}[#2]}%
+ \egroup
+ \referenceinfo{<}{#2}}
+
+% inefficient, we need to save the shared one (just reuse last command in lua)
+
+\def\dogotospace#1[#2]%
+ {\iflocationsplit
+ \ifsecondaryreference
+ \setbox\scratchbox\hbox % will change anyway
+ \fi % due to space insertion
+ {\let\dogotospace\dogotofixed
+ \iflocation
+ \def\processisolatedword##1%
+ {\ifisolatedwords\ifsharesimilarreferences
+ \global\advance\similarreference \plusone
+ \fi\fi
+ \hbox\bgroup
+ \doprocessreferenceelse{#2}{##1\presetgoto}{\unknownreference{#2}##1\relax}%
+ \egroup}%
+ \doattributes\??ia\c!style\c!color{\processisolatedwords{#1}\processisolatedword}%
+ \else
+ #1\relax % \relax prevents #1's next macros from gobbling \fi
+ \fi}%
+ \else
+ \iflocation
+ \hbox{\doattributes\??ia\c!style\c!color{\doprocessreferenceelse{#2}{#1\presetgoto}{\unknownreference{#2}#1\relax}}}%
+ \else
+ #1\relax % \relax prevents #1's next macros from gobbling \fi
+ \fi
+ \fi
+ \global\similarreference\zerocount}
+
+\def\dogotofixed#1[#2]%
+ {{\iflocation
+ \hbox{\doattributes\??ia\c!style\c!color{\doprocessreferenceelse{#2}{#1\presetgoto}{\unknownreference{#2}#1\relax}}}%
+ \else
+ #1%
+ \fi}}
+
+%D In case the auto split feature is not needed or even not
+%D even wanted, \type{\gotobox} can be used.
+
+\unexpanded\def\gotobox#1[#2]%
+ {\dontleavehmode
+ \bgroup
+ \locationstrutfalse
+ \doprocessreferenceelse{#2}
+ {\dogotofixed{#1}[#2]}
+ {\hbox{\unknownreference{#2}#1}}%
+ \referenceinfo{<}{#2}%
+ \egroup}
+
+%D An reference to another document can be specified as a file
+%D or as an \URL. Both are handled by the same mechanism and
+%D can be issued by saying something like:
+%D
+%D \starttyping
+%D \goto[dictionary::the letter a]
+%D \stoptyping
+%D
+%D One can imagine that many references to such a dictionary
+%D are made, so in most cases such a document reference in an
+%D indirect one.
+%D
+%D \showsetup{useexternaldocument}
+%D
+%D For example:
+%D
+%D \starttyping
+%D \useexternaldocument
+%D [dictionary][engldict]
+%D [The Famous English Dictionary]
+%D \stoptyping
+%D
+%D The next macro implements these relations, and also take
+%D care of loading the document specific references.
+%D
+%D The \URL\ alternative takes four arguments:
+%D
+%D \showsetup{useURL}
+%D
+%D like:
+%D
+%D \starttyping
+%D \useURL
+%D [dictionary][http://www.publisher.com/public][engldict]
+%D [The Famous English Dictionary]
+%D \stoptyping
+%D
+%D Several specifications are possible:
+%D
+%D \starttyping
+%D \useURL [id] [url] [file] [description]
+%D \useURL [id] [url] [file]
+%D \useURL [id] [url]
+%D \stoptyping
+%D
+%D This time we don't load the references when no file is
+%D specified. This is logical when one keeps in mind that a
+%D valid \URL\ can also be a mail address.
+
+\def\usefile{\dotripleargument\dousefile}
+\def\useurl {\doquadrupleempty\douseurl}
+
+\let\useURL \useurl
+\let\useexternaldocument\usefile
+
+\def\douseurl[#1][#2][#3][#4]%
+ {\ctxlua{jobreferences.urls.define("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es,\!!bs\detokenize{#4}\!!es)}}
+
+\def\dousefile[#1][#2][#3]%
+ {\ctxlua{jobreferences.files.define("#1",\!!bs\detokenize{#2}\!!es,\!!bs\detokenize{#3}\!!es)}}
+
+% \doifsomething\@@urstyle{\let\@@iastyle\@@urstyle\let\@@urstyle\empty}%
+% \doifsomething\@@urcolor{\let\@@iacolor\@@urcolor\let\@@urcolor\empty}%
+
+%D \macros
+%D {url,setupurl}
+%D
+%D We also have: \type{\url} for directly calling the
+%D description. So we can say:
+%D
+%D \starttyping
+%D \useURL [one] [http://www.test.nl]
+%D \useURL [two] [http://www.test.nl] [] [Some Site]
+%D
+%D \url[one] or \from[two] or \goto{Whatever Site}[URL(two)]
+%D \stoptyping
+%D
+%D An \URL\ can be set up with
+%D
+%D \showsetup{setupurl}
+
+\def\setupurl
+ {\dodoubleargument\getparameters[\??ur]}
+
+\unexpanded\def\url[#1]%
+ {\dontleavehmode
+ \begingroup
+ \dosetfontattribute\??ur\c!style
+ \dosetcolorattribute\??ur\c!color
+ \ctxlua{jobreferences.urls.get("#1","\@@uralternative","\@@urspace")}%
+ \dostopattributes
+ \endgroup}
+
+%D This macro is hooked into a support macro, and thereby
+%D \URL's break ok, according to the setting of a switch,
+%D
+%D \startbuffer
+%D \useURL
+%D [test]
+%D [sentence_sentence%sentence#sentence~sentence/sentence//sentence:sentence.sentence]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Such an \URL\ is, depending on the settings, hyphenated as:
+%D
+%D \getbuffer
+%D
+%D \startlinecorrection
+%D \hbox to \hsize
+%D {\hss\en
+%D \setupreferencing[urlalternative=both]%
+%D \vbox{\hsize.25cm\hbox{\bf both}\prewordbreak\url[test]}%
+%D \hss
+%D \setupreferencing[urlalternative=before]%
+%D \vbox{\hsize.25cm\hbox{\bf before}\prewordbreak\url[test]}%
+%D \hss
+%D \setupreferencing[urlalternative=after]%
+%D \vbox{\hsize.25cm\hbox{\bf after}\prewordbreak\url[test]}%
+%D \hss}
+%D \stoplinecorrection
+%D
+%D By setting \type{urlspace=yes} one can get slightly better
+%D spacing when using very long \URL's.
+%D
+%D When defining the external source of information, one can
+%D also specify a suitable name (the last argument). This name
+%D can be called upon with:
+%D
+%D \showsetup{from}
+
+\def\dospecialfrom
+ {\dosingleempty\dodospecialfrom}
+
+\def\dodospecialfrom[#1]%
+ {\dontleavehmode\ctxlua{jobreferences.from("#1","","")}}
+
+%D We also support:
+%D
+%D \starttyping
+%D \goto{some text}[file(identifier{location}]
+%D \stoptyping
+%D
+%D which is completely equivalent with
+%D
+%D \starttyping
+%D \goto{some text}[identifier::location]
+%D \stoptyping
+
+\def\gotofilespecial#1#2#3#4% special operation arguments data
+ {\begingroup\iflocation\gotoouterfile{#2}{#3}{#4}\else#4\fi\endgroup}
+
+\def\gotourlspecial#1#2#3#4% special operation arguments data
+ {\begingroup\iflocation\gotoouterurl{#2}{#3}{#4}\else#4\fi\endgroup}
+
+%D A special case of references are those to programs. These,
+%D very system dependant references are implemented by abusing
+%D some of the previous macros.
+%D
+%D \showsetup{setupprograms}
+%D \showsetup{defineprogram}
+%D \showsetup{program} % changed functionality !
+%D
+%D The latter gives access to the description of the program,
+%D being the last argument to the definition command.
+
+% also lua, like urls and files
+
+\def\setupprograms
+ {\dodoubleargument\getparameters[\??pr]}
+
+\def\defineprogram
+ {\dotripleargument\dodefineprogram}
+
+\def\dodefineprogram[#1][#2][#3]%
+ {\ctxlua{jobreferences.programs.define("#1","#2","#3")}}
+
+\def\program[#1]% incompatible, more consistent, hardy used anyway
+ {\dontleavehmode
+ \begingroup
+ \dosetfontattribute\??pr\c!style
+ \dosetcolorattribute\??pr\c!color
+ \ctxlua{jobreferences.programs.get("#1","\@@pralternative","\@@prspace")}%
+ \endgroup}
+
+% needs an update: program(abc{arg})
+
+\def\gotoprogramspecial#1#2#3#4% special operation arguments data
+ {\begingroup
+ \iflocation
+ \dohandlegoto
+ {#4}%
+ {\dostartrunprogram\buttonwidth\buttonheight{\@@prdirectory#2}{#3}}%
+ {\dostoprunprogram}%
+ \else
+ #4%
+ \fi
+ \endgroup}
+
+%D As we can see, we directly use the special reference
+%D mechanism, which means that
+%D
+%D \starttyping
+%D \goto{some text}[program(name{args})]
+%D \stoptyping
+%D
+%D is valid.
+
+%D The next macro provides access to the actual pagenumbers.
+%D When documenting and sanitizing the original reference
+%D macros, I decided to keep the present meaning as well as to
+%D make this meaning available as a special reference method.
+%D So now one can use:
+%D
+%D \starttyping
+%D \gotopage{some text}[location]
+%D \gotopage{some text}[number]
+%D \gotopage{some text}[file::number]
+%D \stoptyping
+%D
+%D as well as:
+%D
+%D \starttyping
+%D \goto{some text}[page(location)]
+%D \goto{some text}[page(number)]
+%D \goto{some text}[file::page(number)]
+%D \stoptyping
+%D
+%D Here location is a keyword like \type{nextpage}.
+%D
+%D \showsetup{gotopage}
+
+\def\definepage
+ {\dodoubleargument\dodefinepage}
+
+\def\dodefinepage[#1][#2]%
+ {\definereference[#1][page(#1)]}
+
+\def\gotopage#1[#2]%
+ {\goto{#1}[\v!page(#2)]}
+
+%D The previous definitions are somewhat obsolete so we don't
+%D use it here.
+
+%D A still very rudimentary|/|experimental forward|/|backward
+%D reference mechanism is provided by the macro \type{\atpage}:
+%D
+%D \starttyping
+%D ... \somewhere{backward text}{forward text}[someref] ...
+%D ... \atpage[someref] ...
+%D \stoptyping
+%D
+%D In future versions there will be more sophisticated
+
+%D support, also suitable for references to floating bodies.
+
+\def\analysedreference#1%
+ {\ctxlua{jobreferences.analysis("\referenceprefix","#1")}}
+
+\unexpanded\def\somewhere#1#2#3[#4]% #3 gobbles space around #2 % todo
+ {\dontleavehmode
+ \ifcase\analysedreference{#4}\relax
+ \unknownreference{#4}#1/#2%
+ \or
+ \doifelsenothing{#2}{\dosymbolreference{}{}[#4]}{\dogotospace{#2}[#4]}%
+ \or % forward
+ \doifelsenothing{#1}{\dosymbolreference{}{}[#4]}{\dogotospace{#1}[#4]}%
+ \or % backward
+ \doifelsenothing{#2}{\dosymbolreference{}{}[#4]}{\dogotospace{#2}[#4]}%
+ \fi
+ \referenceinfo{<}{#4}}
+
+\unexpanded\def\atpage[#1]% todo
+ {\dontleavehmode
+% \docheckrealreferencepage{}%
+% \doifreferencefoundelse{#1}
+% {\ifrealreferencepage
+% \ifforwardreference
+% \dogotofixed{\labeltext\v!hencefore}[#1]%
+% \else
+% \dogotofixed{\labeltext\v!hereafter}[#1]%
+% \fi
+% \else
+% \dogotofixed{\labeltexts\v!atpage\currentpagereference}[#1]%
+% \fi}
+% {\unknownreference{#1}%
+% \labeltexts\v!page\dummyreference}%
+ \referenceinfo{<}{#1}}
+
+%D We can cross link documents by using:
+%D
+%D \showsetup{coupledocument}
+%D
+%D like:
+%D
+%D \starttyping
+%D \coupledocument[print][somefile][chapter,section]
+%D \stoptyping
+%D
+%D After which when applicable, we have available the
+%D references:
+%D
+%D \starttyping
+%D \goto{print version}[print::chapter]
+%D \stoptyping
+%D
+%D and alike. The title placement definition macros have a
+%D key \type{file}, which is interpreted as the file to jump
+%D to, that is, when one clicks on the title.
+
+\newif\ifautocrossdocument
+
+\def\coupledocument
+ {\doquadrupleempty\docoupledocument}
+
+\def\docoupledocument[#1][#2][#3][#4]% [name] [file] [sections] [description]
+ {\ifthirdargument
+ % this will be done differently (when it's needed)
+ \fi}
+
+%D Buttons are just what their names says: things that can be
+%D clicked (pushed) on. They are similar to \type{\goto},
+%D except that the text argument is not interpreted.
+%D Furthermore one can apply anything to them that can be done
+%D with \type{\framed}.
+%D
+%D \startbuffer
+%D \button[width=3cm,height=1.5cm]{Exit}[ExitViewer]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \getbuffer
+%D
+%D This command is formally specified as:
+%D
+%D \showsetup{button}
+%D
+%D The characteristics can be set with:
+%D
+%D \showsetup{setupbuttons}
+
+\def\setupbuttons
+ {\dodoubleargument\getparameters[\??bt]}
+
+\definecomplexorsimpleempty\button
+
+\def\complexbutton
+ {\docomplexbutton\??bt}
+
+\presetlocalframed[\??bt]
+
+\long\def\docomplexbutton#1[#2]#3#4% get rid of possible space before [#4]
+ {\dodocomplexbutton#1[#2]{#3}#4} % #4 == [
+
+\def\buttonframed{\dodoubleempty\localframed[\??bt]} % goodie
+
+\long\def\dodocomplexbutton#1[#2]#3[#4]% #3 can contain [] -> {#3} later
+ {\begingroup
+ \doifvalue{#1\c!state}\v!stop\locationfalse
+ \iflocation
+ \resetgoto
+ \ConvertConstantAfter\doifelse{#3}\v!none\hphantom\hbox
+ {\doifelsenothing{#4}
+ {\setlocationboxnop#1[#2]{#3}[#4]}
+ {\doifreferencefoundelse{#4} % INEFFICIENT
+ {\setlocationboxyes#1[#2]{#3}[#4]}
+ {\unknownreference{#4}%
+ \setlocationboxnop#1[#2]{#3}[#4]}}}%
+ \fi
+ \endgroup}
+
+%D Interaction buttons, in fact a row of tiny buttons, are
+%D typically only used for navigational purposed. The next
+%D macro builds such a row based on a specification list.
+%D
+%D \startbuffer
+%D \interactionbuttons
+%D [width=\hsize][page,PreviousJump,ExitViewer]
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D gives
+%D
+%D \getbuffer
+%D
+%D Apart from individual entries, one can use \type{page} and
+%D \type {subpage} as shortcuts to their four associated buttons.
+%D The symbols are derived from the symbols linked to the
+%D entries.
+
+% does not work well with for instance SomeRef{whatever}
+
+\def\interactionbuttons
+ {\dodoubleempty\dointeractionbuttons}
+
+\def\dointeractionbuttons[#1][#2]% er is een verdeel macro \horizontalfractions
+ {\iflocation
+ % BUG: fails when frame=off; best is to rewrite this macro
+ \bgroup
+ \doif\@@ibstate\v!stop\locationfalse
+ \iflocation
+ \ifsecondargument
+ \setupinteractionbar[#1]%
+ \checkinteractionbar{1.5em}\v!broad\!!zeropoint % brrrrr
+ \setbox2\hbox{\localframed[\??ib][\c!background=]{\symbol[\@@iasymbolset][\v!previouspage]}}%
+ \!!heighta\ht2 % needed because we default to nothing
+ \setupinteractionbar[\c!strut=\v!no]%
+ \setinteractionparameter\c!width\!!zeropoint
+ \!!counta\zerocount % new, was 1
+ \processallactionsinset
+ [#2]
+ [ \v!page=>\advance\!!counta 4,
+ \v!subpage=>\advance\!!counta 4,
+ \s!unknown=>\advance\!!counta 1]%
+ \ifdim\@@ibwidth=\zeropoint
+ \!!widtha2em
+ \advance\!!widtha \@@ibdistance % new
+ \!!widthb\!!counta\!!widtha
+ \advance\!!widthb -\@@ibdistance % new
+ \else
+ \!!widtha\@@ibwidth
+ \!!widthb\@@ibdistance % new
+ \multiply\!!widthb \!!counta % new
+ \advance\!!widthb -\@@ibdistance % new
+ \advance\!!widtha -\!!widthb % new
+ \divide\!!widtha \!!counta
+ \!!widthb\@@ibwidth
+ \fi
+ \def\goto##1% clash ?
+ {\setnostrut
+ \edef\localreference{##1}%
+ \normalexpanded{\noexpand\dodocomplexbutton\??ib[\c!height=\the\!!heighta,\c!width=\the\!!widtha]}%
+ {\dontleavehmode\symbol[\@@iasymbolset][\localreference]}%
+ [\localreference]%
+ \hss}%
+ \hbox to \!!widthb
+ {\processallactionsinset
+ [#2]
+ [ \v!page=>\goto\v!firstpage
+ \goto\v!nextpage
+ \goto\v!previouspage
+ \goto\v!lastpage,
+ \v!subpage=>\goto\v!firstsubpage
+ \goto\v!nextsubpage
+ \goto\v!previoussubpage
+ \goto\v!lastsubpage,
+ \s!unknown=>\goto\commalistelement]%
+ \unskip}%
+ \else
+ \interactionbuttons[][#1]%
+ \fi
+ \fi
+ \egroup
+ \fi}
+
+%D \macros
+%D {overlaybutton}
+%D
+%D For converience we provide:
+%D
+%D \starttyping
+%D \overlaybutton[reference]
+%D \stoptyping
+%D
+%D This command can be used to define overlays an/or can be
+%D used in the whatevertext areas, like:
+%D
+%D \starttyping
+%D \defineoverlay[PrevPage][\overlaybutton{PrevPage}]
+%D \setupbackgrounds[page][background=PrevPage]
+%D \setuptexttexts[\overlaybutton{NextPage}]
+%D \stoptyping
+%D
+%D For practical reasons, this macro accepts square brackets
+%D as well as braces.
+
+\definecomplexorsimple\overlaybutton
+
+\def\simpleoverlaybutton#1%
+ {\complexoverlaybutton[#1]}
+
+\def\complexoverlaybutton[#1]%
+ {\iflocation
+ \doprocessreferenceelse{#1}
+ {\overlayfakebox {#1}}
+ {\unknownreference{#1}}%
+ \fi}
+
+\def\overlayfakebox#1%
+ {\hbox
+ {\setbox\scratchbox\null
+ \wd\scratchbox\overlaywidth
+ \ht\scratchbox\overlayheight
+ \locationstrutfalse
+ \box\scratchbox}}
+
+%D \macros
+%D {dotextprefix}
+%D
+%D In previous macros we used \type {\dotextprefix} to
+%D generate a space between a label and a number.
+%D
+%D \starttyping
+%D \dotextprefix{text}
+%D \stoptyping
+%D
+%D Only when \type {text} is not empty, a space is inserted.
+
+\def\dotextprefix#1%
+ {\begingroup
+ \global\labeltextdonefalse % this is an ugly dependancy,
+ \setbox\scratchbox\hbox{#1}% to be solved some day
+ \ifdim\wd\scratchbox>\zeropoint
+ \unhbox\scratchbox
+ \iflabeltextdone\else\@@rfseparator\fi
+ \else
+ \unhbox\scratchbox
+ \fi
+ \endgroup}
+
+%D In the next settings we see some variables that were not
+%D used here and that concern the way the pagenumbers refered
+%D to are typeset.
+
+\setupreferencing
+ [\c!state=\v!start,
+ \c!autofile=\v!no,
+ \v!part\c!number=\v!yes,
+ \v!chapter\c!number=\v!no,
+ \c!interaction=\v!all,
+ \c!convertfile=\v!no,
+ %\c!strut=\v!no, % some day an option
+ \c!prefix=,
+ \c!width=.75\makeupwidth,
+ \c!left=\quotation\bgroup,
+ \c!right=\egroup,
+ \c!global=\v!no,
+ \c!expansion=\v!no,
+ \c!separator=\nonbreakablespace]
+
+\setupurl
+ [\c!alternative=\v!both,
+ \c!space=\v!no,
+ \c!style=\v!type,
+ \c!color=]
+
+\setupprograms
+ [\c!directory=,
+ \c!alternative=\v!both,
+ \c!space=\v!no,
+ \c!style=\v!type,
+ \c!color=]
+
+\definereference [\v!CloseDocument ] [action(close)]
+\definereference [\v!ExitViewer ] [action(exit)]
+\definereference [\v!FirstPage ] [action(first)]
+\definereference [\v!LastPage ] [action(last)]
+\definereference [\v!NextJump ] [action(forward)]
+\definereference [\v!NextPage ] [action(next)]
+\definereference [\v!PauseMovie ] [action(pausemovie)]
+\definereference [\v!PauseSound ] [action(pausesound)]
+\definereference [\v!PauseRendering ] [action(pauserendering)]
+\definereference [\v!PreviousJump ] [action(backward)]
+\definereference [\v!PreviousPage ] [action(previous)]
+\definereference [\v!PrintDocument ] [action(print)]
+\definereference [\v!SaveForm ] [action(exportform)]
+\definereference [\v!LoadForm ] [action(importform)]
+\definereference [\v!ResetForm ] [action(resetform)]
+\definereference [\v!ResumeMovie ] [action(resumemovie)]
+\definereference [\v!ResumeSound ] [action(resumesound)]
+\definereference [\v!ResumeRendering ] [action(resumerendering)]
+\definereference [\v!SaveDocument ] [action(save)]
+\definereference [\v!SaveNamedDocument] [action(savenamed)]
+\definereference [\v!OpenNamedDocument] [action(opennamed)]
+\definereference [\v!SearchDocument ] [action(search)]
+\definereference [\v!SearchAgain ] [action(searchagain)]
+\definereference [\v!StartMovie ] [action(startmovie)]
+\definereference [\v!StartSound ] [action(startsound)]
+\definereference [\v!StartRendering ] [action(startrendering)]
+\definereference [\v!StopMovie ] [action(stopmovie)]
+\definereference [\v!StopSound ] [action(stopsound)]
+\definereference [\v!StopRendering ] [action(stoprendering)]
+\definereference [\v!SubmitForm ] [action(submitform)]
+\definereference [\v!ToggleViewer ] [action(toggle)]
+\definereference [\v!ViewerHelp ] [action(help)]
+\definereference [\v!HideField ] [action(hide)]
+\definereference [\v!ShowField ] [action(show)]
+\definereference [\v!GotoPage ] [action(gotopage)]
+\definereference [\v!GotoPage ] [action(gotopage)]
+\definereference [\v!Query ] [action(query)]
+\definereference [\v!QueryAgain ] [action(queryagain)]
+\definereference [\v!FitWidth ] [action(fitwidth)]
+\definereference [\v!FitHeight ] [action(fitheight)]
+\definereference [\v!ShowThumbs ] [action(thumbnails)]
+\definereference [\v!ShowBookmarks ] [action(bookmarks)]
+
+\definereference [\v!firstpage] [page(\firstpage)]
+\definereference [\v!previouspage] [page(\prevpage)]
+\definereference [\v!nextpage] [page(\nextpage)]
+\definereference [\v!lastpage] [page(\lastpage)]
+\definereference [\v!firstsubpage] [page(\firstsubpage)]
+\definereference [\v!previoussubpage] [page(\prevsubpage)]
+\definereference [\v!nextsubpage] [page(\nextsubpage)]
+\definereference [\v!lastsubpage] [page(\lastsubpage)]
+\definereference [\v!first] [page(\firstpage)]
+\definereference [\v!previous] [page(\prevpage)]
+\definereference [\v!next] [page(\nextpage)]
+\definereference [\v!last] [page(\lastpage)]
+\definereference [\v!first\v!sub] [page(\firstsubpage)]
+\definereference [\v!previous\v!sub] [page(\prevsubpage)]
+\definereference [\v!next\v!sub] [page(\nextsubpage)]
+\definereference [\v!last\v!sub] [page(\lastsubpage)]
+
+%D We cannot set up buttons (not yet, this one calls a menu macro):
+
+\protect \endinput
diff --git a/tex/context/base/strc-reg.lua b/tex/context/base/strc-reg.lua
new file mode 100644
index 000000000..74dbf90e2
--- /dev/null
+++ b/tex/context/base/strc-reg.lua
@@ -0,0 +1,578 @@
+if not modules then modules = { } end modules ['strc-reg'] = {
+ version = 1.001,
+ comment = "companion to strc-reg.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texwrite, texsprint, count, format, gmatch = tex.write, tex.sprint, tex.count, string.format, string.gmatch
+
+local ctxcatcodes = tex.ctxcatcodes
+
+local variables = interfaces.variables
+
+local helpers = structure.helpers
+local sections = structure.sections
+local documents = structure.documents
+local pages = structure.pages
+
+-- to be shared, but tested first
+
+local function filter_collected(names,criterium,number,collected,prevmode)
+ if not criterium or criterium == "" then criterium = variables.all end
+ local data = documents.data
+ local numbers, depth = data.numbers, data.depth
+ local hash, result, all = { }, { }, not names or names == "" or names == variables.all
+ if not all then
+ for s in gmatch(names,"[^, ]+") do
+ hash[s] = true
+ end
+ end
+ if criterium == variables.all or criterium == variables.text then
+ for i=1,#collected do
+ local v = collected[i]
+ if all then
+ result[#result+1] = v
+ else
+ local vmn = v.metadata and v.metadata.name
+ if hash[vmn] then
+ result[#result+1] = v
+ end
+ end
+ end
+ elseif criterium == variables.current then
+ for i=1,#collected do
+ local v = collected[i]
+ local sectionnumber = jobsections.collected[v.references.section]
+ if sectionnumber then
+ local cnumbers = sectionnumber.numbers
+ if prevmode then
+ if (all or hash[v.metadata.name]) and #cnumbers >= depth then -- is the = ok for lists as well?
+ local ok = true
+ for d=1,depth do
+ if not (cnumbers[d] == numbers[d]) then -- no zero test
+ ok = false
+ break
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ else
+ if (all or hash[v.metadata.name]) and #cnumbers > depth then
+ local ok = true
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ elseif criterium == variables.previous then
+ for i=1,#collected do
+ local v = collected[i]
+ local sectionnumber = jobsections.collected[v.references.section]
+ if sectionnumber then
+ local cnumbers = sectionnumber.numbers
+ if (all or hash[v.metadata.name]) and #cnumbers >= depth then
+ local ok = true
+ if prevmode then
+ for d=1,depth do
+ if not (cnumbers[d] == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ else
+ for d=1,depth do
+ local cnd = cnumbers[d]
+ if not (cnd == 0 or cnd == numbers[d]) then
+ ok = false
+ break
+ end
+ end
+ end
+ if ok then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ elseif criterium == variables["local"] then
+ if sections.autodepth(data.numbers) == 0 then
+ return filter_collected(names,variables.all,number,collected,prevmode)
+ else
+ return filter_collected(names,variables.current,number,collected,prevmode)
+ end
+ else -- sectionname, number
+ local depth = sections.getlevel(criterium)
+ local number = tonumber(number) or 0
+ for i=1,#collected do
+ local v = collected[i]
+ local sectionnumber = jobsections.collected[v.references.section]
+ if sectionnumber then
+ local cnumbers = sectionnumber.numbers
+ if (all or hash[v.metadata.name]) and #cnumbers >= depth then -- was >
+ if cnumbers[depth] == number then
+ result[#result+1] = v
+ end
+ end
+ end
+ end
+ end
+ return result
+end
+
+structure.filter_collected = filter_collected
+
+-- we follow a different strategy than by lists, where we have a global
+-- result table; we might do that here as well but since sorting code is
+-- older we delay that decision
+
+jobregisters = jobregisters or { }
+jobregisters.collected = jobregisters.collected or { }
+jobregisters.tobesaved = jobregisters.tobesaved or { }
+
+local tobesaved, collected = jobregisters.tobesaved, jobregisters.collected
+
+local function initializer()
+ tobesaved, collected = jobregisters.tobesaved, jobregisters.collected
+end
+
+job.register('jobregisters.collected', jobregisters.tobesaved, initializer)
+
+local function allocate(class)
+ local d = tobesaved[class]
+ if not d then
+ d = {
+ metadata = {
+ language = 'en',
+ sorted = false,
+ class = class
+ },
+ entries = { },
+ }
+ tobesaved[class] = d
+ end
+ return d
+end
+
+jobregisters.define = allocate
+
+local entrysplitter = lpeg.Ct(lpeg.splitat('+'))
+
+function jobregisters.store(rawdata)
+ local data = allocate(rawdata.metadata.name).entries
+ local entries = rawdata.entries
+ local et = entrysplitter:match(entries[1]) -- alse &
+ local kt = entrysplitter:match(entries[2]) -- alse &
+ entries = { }
+ for k=1,#et do
+ entries[k] = { et[k] or "", kt[k] or "" }
+ end
+ rawdata.list = entries
+ rawdata.entries = nil
+ data[#data+1] = rawdata
+ texwrite(#data)
+end
+
+function jobregisters.enhance(name,n)
+ local r = tobesaved[name].entries[n]
+ if r then
+ r.references.realpage = tex.count[0]
+ end
+end
+
+function jobregisters.extend(name,n,lastsection)
+ local r = tobesaved[name].entries[n]
+ if r then
+ r.references.lastrealpage = tex.count[0]
+ r.references.lastsection = lastsection
+
+ end
+end
+
+-- sorting and rendering
+
+function jobregisters.compare(a,b)
+ local result = 0
+ local compare = sorters.comparers.basic
+ local ea, eb = a.split, b.split
+ local na, nb = #ea, #eb
+ local max = na
+ if nb < max then max = nb end
+ for i=1,max do
+ if result == 0 then
+ result = compare(ea[i],eb[i])
+ else
+ return result
+ end
+ end
+ if result ~= 0 then
+ return result
+ elseif na > nb then
+ return 1
+ elseif nb > na then
+ return -1
+ elseif a.metadata.kind == 'entry' then -- e/f/t
+ local page_a, page_b = a.references.realpage, b.references.realpage
+ if page_a < page_b then
+ return -1
+ elseif page_a > page_b then
+ return 1
+ end
+ else
+ return 0
+ end
+end
+
+function jobregisters.filter(data,options)
+ data.result = structure.filter_collected(nil,options.criterium,options.number,data.entries,true)
+end
+
+function jobregisters.prepare(data)
+ -- data has 'list' table
+ local strip = sorters.strip
+ local splitter = sorters.splitters.utf
+ local result = data.result
+ if result then
+ for i=1, #result do
+ local entry, split = result[i], { }
+ local list = entry.list
+ for l=1,#list do
+ local ll = list[l]
+ local key, word = ll[1], ll[2]
+ if key == "" then
+ key = word
+ end
+ split[l] = splitter(strip(key))
+ end
+ entry.split = split
+ end
+ end
+end
+
+function jobregisters.sort(data,options)
+ sorters.sort(data.entries,jobregisters.compare)
+end
+
+function jobregisters.unique(data,options)
+ local result, prev, equal = { }, nil, table.are_equal
+ for _,v in ipairs(data.result) do
+ if not prev then
+ result[#result+1], prev = v, v
+ else
+ local pr, vr = prev.references, v.references
+ if not equal(prev.list,v.list) then
+ result[#result+1], prev = v, v
+ elseif pr.realpage ~= vr.realpage then
+ result[#result+1], prev = v, v
+ else
+ local pl, vl = pr.lastrealpage, vr.lastrealpage
+ if pl or vl then
+ if not vl then
+ result[#result+1], prev = v, v
+ elseif not pl then
+ result[#result+1], prev = v, v
+ elseif pl ~= vl then
+ result[#result+1], prev = v, v
+ end
+ end
+ end
+ end
+ end
+ data.result = result
+end
+
+function jobregisters.finalize(data,options)
+ local result = data.result
+ data.metadata.nofsorted = #result
+ local split = { }
+ -- maps character to index (order)
+ local se = sorters.entries[options.language or sorters.defaultlanguage] or sorters.entries[sorters.defaultlanguage]
+ for k=1,#result do
+ local v = result[k]
+ local entry, tag = v.split[1][1], ""
+ if se and se[entry] then
+ if type(se[entry]) == "number" then
+ entry = se[entry]
+ end
+ tag = se[entry]
+ else
+ entry = 0
+ tag = "unknown"
+ end
+ local s = split[entry]
+ if not s then
+ s = { tag = tag, data = { } }
+ split[entry] = s
+ end
+ s.data[#s.data+1] = v
+ end
+ data.result = split
+end
+
+function jobregisters.analysed(class,options)
+ local data = collected[class]
+ if data and data.entries then
+ jobregisters.filter(data,options) -- filter entries into results (criteria)
+ jobregisters.prepare(data,options) -- adds split table parallel to list table
+ jobregisters.sort(data,options) -- sorts results
+ jobregisters.unique(data,options) -- get rid of duplicates
+ jobregisters.finalize(data,options) -- split result in ranges
+ data.metadata.sorted = true
+ return data.metadata.nofsorted or 0
+ else
+ return 0
+ end
+end
+
+-- todo take conversion from index
+
+function jobregisters.flush(data,options,prefixspec,pagespec)
+ local equal = table.are_equal
+ texsprint(ctxcatcodes,"\\startregisteroutput")
+ local collapse_singles = options.compress == interfaces.variables.yes
+ local collapse_ranges = options.compress == interfaces.variables.all
+ local result = data.result
+ -- todo ownnumber
+ local function pagenumber(entry)
+ texsprint(ctxcatcodes,"\\registeronepage{")
+ helpers.prefixpage(entry,prefixspec,pagespec)
+ texsprint(ctxcatcodes,"}")
+ end
+ local function pagerange(f_entry,t_entry,is_last)
+ texsprint(ctxcatcodes,"\\registerpagerange{")
+ helpers.prefixpage(f_entry,prefixspec,pagespec)
+ texsprint(ctxcatcodes,"}{")
+ if is_last then
+ helpers.prefixpage(t_entry,prefixspec,pagespec)
+ else
+ helpers.prefixlastpage(t_entry,prefixspec,pagespec)
+ end
+ texsprint(ctxcatcodes,"}")
+ end
+ -- ranges need checking !
+ for k, letter in ipairs(table.sortedkeys(result)) do
+ local sublist = result[letter]
+ local done = { false, false, false, false }
+ local data = sublist.data
+ local d, n = 0, 0
+ texsprint(ctxcatcodes,format("\\startregistersection{%s}",sublist.tag))
+ while d < #data do
+ d = d + 1
+ local entry = data[d]
+ local e = { false, false, false, false }
+ for i=1,4 do -- max 4
+ if entry.list[i] then
+ e[i] = entry.list[i][1]
+ end
+ if e[i] ~= done[i] then
+ if e[i] and e[i] ~= "" then
+ done[i] = e[i]
+ if n == i then
+ texsprint(ctxcatcodes,format("\\stopregisterentries\\startregisterentries{%s}",n))
+ else
+ while n > i do
+ n = n - 1
+ texsprint(ctxcatcodes,"\\stopregisterentries")
+ end
+ while n < i do
+ n = n + 1
+ texsprint(ctxcatcodes,format("\\startregisterentries{%s}",n))
+ end
+ end
+ texsprint(ctxcatcodes,format("\\registerentry{%s}",e[i]))
+ else
+ done[i] = false
+ end
+ end
+ end
+ local kind = entry.metadata.kind
+ if kind == 'entry' then
+ texsprint(ctxcatcodes,"\\startregisterpages")
+ if collapse_singles or collapse_ranges then
+ -- we collapse ranges and keep existing ranges as they are
+ -- so we get prebuilt as well as built ranges
+ local first, last, prev = entry, nil, entry
+ local pages = { }
+ local dd = d
+ while dd < #data do
+ dd = dd + 1
+ local next = data[dd]
+ local el, nl = entry.list, next.list
+ if not equal(el,nl) then
+ dd = dd - 1
+ --~ first = nil
+ break
+ elseif next.references.lastrealpage then
+ if first then
+ pages[#pages+1] = { first, last or first }
+ else
+ pages[#pages+1] = { entry, entry }
+ end
+ pages[#pages+1] = { next, next }
+ first, last, prev = nil, nil, nil
+ elseif not first then
+ first, prev = next, next
+ elseif next.references.realpage - prev.references.realpage == 1 then
+ last, prev = next, next
+ else
+ pages[#pages+1] = { first, last or first }
+ first, last, prev = next, nil, next
+ end
+ end
+ if first then
+ pages[#pages+1] = { first, last or first }
+ end
+ if collapse_ranges and #pages > 1 then
+ -- ok, not that efficient
+ local function doit()
+ local function bubble(i)
+ for j=i,#pages-1 do
+ pages[j] = pages[j+1]
+ end
+ pages[#pages] = nil
+ end
+ for i=2,#pages do
+ local first, second = pages[i-1], pages[i]
+ local first_first, first_last, second_first, second_last = first[1], first[2], second[1], second[2]
+ local first_last_pn = first_last .references.realpage
+ local second_first_pn = second_first.references.realpage
+ local second_last_pn = second_last .references.realpage
+ local first_last_last = first_last.references.lastrealpage
+ local second_first_last = second_first.references.lastrealpage
+ if first_last_last then
+ first_last_pn = first_last_last
+ if second_first == second_last and second_first_pn <= first_last_pn then
+ -- 2=8, 5 -> 12=8
+ bubble(i)
+ return true
+ elseif second_first == second_last and second_first_pn > first_last_pn then
+ -- 2=8, 9 -> 2-9
+ pages[i-1] = { first_first, second_last }
+ bubble(i)
+ return true
+ elseif second_last_pn < first_last_pn then
+ -- 2=8, 3-4 -> 2=8
+ bubble(i)
+ return true
+ elseif first_last_pn < second_last_pn then
+ -- 2=8, 3-9 -> 2-9
+ pages[i-1] = { first_first, second_last }
+ bubble(i)
+ return true
+ elseif first_last_pn + 1 == second_first_pn and second_last_pn > first_last_pn then
+ -- 2=8, 9-11 -> 2-11
+ pages[i-1] = { first_first, second_last }
+ bubble(i)
+ return true
+ elseif second_first.references.lastrealpage then
+ -- 2=8, 9=11 -> 2-11
+ pages[i-1] = { first_first, second_last }
+ bubble(i)
+ return true
+ end
+ elseif second_first_last then
+ second_first_pn = second_first_last
+ if first_last_pn == second_first_pn then
+ -- 2-4, 5=9 -> 2-9
+ pages[i-1] = { first_first, second_last }
+ bubble(i)
+ return true
+ end
+ elseif first_last_pn == second_first_pn then
+ -- 2-3, 3-4 -> 2-4
+ pages[i-1] = { first_last, second_last }
+ bubble(i)
+ return true
+ end
+ end
+ return false
+ end
+ while doit() do end
+ end
+ --
+ if #pages > 0 then -- or 0
+ d = dd
+ for p=1,#pages do
+ local first, last = pages[p][1], pages[p][2]
+ if first == last then
+ if first.references.lastrealpage then
+ pagerange(first,first,true)
+ else
+ pagenumber(first)
+ end
+ elseif last.references.lastrealpage then
+ pagerange(first,last,true)
+ else
+ pagerange(first,last,false)
+ end
+ end
+ else
+ if entry.references.lastrealpage then
+ pagerange(entry,entry,true)
+ else
+ pagenumber(entry)
+ end
+ end
+ else
+ while true do
+ if entry.references.lastrealpage then
+ pagerange(entry,entry,true)
+ else
+ pagenumber(entry)
+ end
+ if d == #data then
+ break
+ else
+ d = d + 1
+ local next = data[d]
+ if not equal(entry.list,next.list) then
+ d = d - 1
+ break
+ else
+ entry = next
+ end
+ end
+ end
+ end
+ texsprint(ctxcatcodes,"\\stopregisterpages")
+ elseif kind == 'see' then
+ -- maybe some day more words
+ texsprint(ctxcatcodes,"\\startregisterseewords")
+ texsprint(ctxcatcodes,format("\\registeroneword{%s}",entry.seeword.text))
+ texsprint(ctxcatcodes,"\\stopregisterseewords")
+ end
+ end
+ while n > 0 do
+ texsprint(ctxcatcodes,"\\stopregisterentries")
+ n = n - 1
+ end
+ texsprint(ctxcatcodes,"\\stopregistersection")
+ end
+ texsprint(ctxcatcodes,"\\stopregisteroutput")
+ -- for now, maybe at some point we will do a multipass or so
+ data.result = nil
+ data.metadata.sorted = false
+end
+
+function jobregisters.analyse(class,options)
+ texwrite(jobregisters.analysed(class,options))
+end
+
+function jobregisters.process(class,...)
+ if jobregisters.analysed(class,...) > 0 then
+ jobregisters.flush(collected[class],...)
+ end
+end
+
diff --git a/tex/context/base/strc-reg.tex b/tex/context/base/strc-reg.tex
new file mode 100644
index 000000000..b764525e1
--- /dev/null
+++ b/tex/context/base/strc-reg.tex
@@ -0,0 +1,907 @@
+%D \module
+%D [ file=strc-reg,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Registers,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Registers}
+
+\registerctxluafile{strc-reg}{1.001}
+
+\unprotect
+
+% todo: tag:: becomes rendering
+% todo: language, character, linked, location
+
+%D Helper:
+
+\def\doflushatpar{\ifvmode\expandafter\dogotopar\else\expandafter\firstofoneargument\fi}
+
+% In plaats van + kan een & worden gebruikt. Ook kan als
+% eerste karakter worden opgegeven wat de scheider is.
+%
+% \index {entry}
+% \index[key] {entry}
+% \index[pageclass::] {entry}
+% \index[pageclass::key]{entry}
+% \index {textclass::entry}
+% \index[key] {textclass::entry}
+% \index[pageclass::] {textclass::entry}
+% \index[pageclass::key]{textclass::entry}
+
+%D Parameters:
+
+\let\currentregister\empty
+
+\def\registerparameter#1{\csname\??id\currentregister#1\endcsname}
+
+\def\registerparameter #1{\csname\doregisterparameter{\??id\currentregister}#1\endcsname}
+\def\registerparameterhash#1{\doregisterparameterhash {\??id\currentregister}#1}
+
+\def\doregisterparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\doregisterparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\doregisterparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\doregisterparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\doregisterparentparameter #1#2{\ifx#1\relax\s!empty\else\doregisterparameter #1#2\fi}
+\def\doregisterparentparameterhash#1#2{\ifx#1\relax \else\doregisterparameterhash#1#2\fi}
+
+\def\dosetregisterattributes#1#2% style color
+ {\edef\fontattributehash {\registerparameterhash#1}%
+ \edef\colorattributehash{\registerparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+%D Setup:
+
+\newtoks\everysetupregister
+
+\def\setupregisters
+ {\dotripleempty\dosetupregisters}
+
+\def\dosetupregisters[#1][#2][#3]%
+ {\ifthirdargument
+ \def\dodosetupregister##1{\getparameters[\??id##1#2][#3]}%
+ \processcommalist[#1]\dodosetupregister
+ \else\ifsecondargument
+ \def\dodosetupregister##1{\edef\currentregister{##1}\getparameters[\??id##1][#2]\the\everysetupregister}%
+ \processcommalist[#1]\dodosetupregister
+ \else
+ \getparameters[\??id][#1]%
+ \fi\fi}
+
+\let\setupregister\setupregisters
+
+\setupregisters
+ [\c!n=2,
+ \c!balance=\v!yes, % \v!no komt niet zo vaak voor
+ \c!align=\v!flushleft,
+ \c!tolerance=\v!stretch,
+ \c!before=\blank,
+ %\c!after=,
+ %\c!symbol=,
+ \c!compress=\v!no,
+ \c!interaction=\v!pagenumber,
+ \c!alternative=\v!a,
+ \c!distance=1em,
+ \c!style=\v!bold,
+ \c!pagestyle=\v!slanted,
+ \c!indicator=\v!yes,
+ \c!criterium=\v!all,
+ %\c!command=,
+ \c!referencing=\v!on,
+ \c!location=\v!middle,
+ %\c!maxwidth=,
+ \c!number=\v!no,
+ \c!unknownreference=\v!empty,
+ \c!prefix=\v!both,
+ %\c!expansion=,
+ \c!pageprefixconnector=\endash,
+ \c!pagesegments=2:2,
+ \c!file=\jobname,
+ %\c!deeptextcommand=, % undefined by default !
+ \s!language=\currentmainlanguage]%
+
+%D Definition:
+
+\def\defineregister
+ {\dodoubleargument\dodefineregister}
+
+\def\dodefineregister[#1][#2]% #2?
+ {\setupregister[#1][\s!parent=\??id]%
+ \ctxlua{jobregisters.define('#1')}%
+ \presetheadtext[#1=\Word{#1}]%
+ \unexpanded\setvalue{#1}{\dodoubleempty\doregister[#1]}%
+ \unexpanded\setvalue{\e!see#1}{\dodoubleempty\doseeregister[#1]}%
+% \unexpanded\setvalue{\e!coupled#1}{\dolinkedregister{#1}}%
+ \setvalue{\e!place#1}{\placeregister[#1]}%
+ \setvalue{\e!complete#1}{\completeregister[#1]}%
+ \setvalue{\e!setup#1\e!endsetup}[##1]{\getparameters[\??id#1][##1]}}
+
+%D Registering:
+
+\newif\ifwritetoregister \writetoregistertrue
+
+% tzt variant met n entries, parameters en userdata (altnum)
+
+\def\doprocesspageregister#1#2#3#4#5% register tag key altnum entry
+ {\begingroup
+ \edef\currentregister{#1}%
+ \edef\currentregistertag{#2}%
+ \edef\currentregisterexpansion{\registerparameter\c!expansion}%
+ \edef\currentregisterownnumber{\registerparameter\c!ownnumber}%
+ \ifx\currentregisterexpansion\s!xml
+ \xmlstartraw
+ \xdef\currentregisterentries{\detokenize{#5}}% not ok yet
+ \xmlstopraw
+ \globallet\currentregistercoding\s!xml
+ \else
+ \ifx\currentregisterexpansion\v!yes
+ \xdef\currentregisterentries{#5}% not ok yet
+ \else
+ \xdef\currentregisterentries{\detokenize{#5}}% not ok yet
+ \fi
+ \globallet\currentregistercoding\s!tex
+ \fi
+ \setnextinternalreference
+ % we could consider storing register entries in list
+ \xdef\currentregisternumber{\ctxlua{
+ jobregisters.store {
+ metadata = {
+ kind = "entry",
+ name = "\currentregister",
+ level = structure.sections.currentlevel(),
+ catcodes = \the\catcodetable,
+ own = \ifx\currentregisterownnumber\v!yes "#4" \else nil \fi, % can be used instead of pagenumber
+ },
+ references = {
+ internal = \nextinternalreference,
+ section = structure.sections.currentid(),
+ },
+ entries = {
+ % we need a special one for xml, this is just a single one
+ \!!bs\currentregisterentries\!!es, \!!bs#3\!!es
+ },
+ }
+ } }%
+ \xdef\currentregistersynchronize % make this a macro because shared
+ {\noexpand\ctxlua{jobreferences.setinternalreference(nil,nil,\nextinternalreference)}%
+ \ifx\currentregisterownnumber\v!yes \else
+ \noexpand\ctxlatelua{jobregisters.enhance("\currentregister",\currentregisternumber)}%
+ \fi}%
+ \ifx\currentregistertag\empty \else
+ \setxvalue{\??id#1->#2}{\noexpand\dofinishpageregister{\currentregister}{\currentregisternumber}}%
+ \fi
+ \currentregistersynchronize % here?
+ \endgroup}
+
+\def\dofinishpageregister#1#2%
+ {\ctxlatelua{jobregisters.extend("#1",#2,\ctxlua{tex.write(structure.currentsectionnumber())}}}
+
+\def\doregister[#1][#2]%
+ {\def\currentregister{#1}%
+ \doifelse{\registerparameter\c!ownnumber}\v!yes\dodoregister\donoregister{#1}{#2}}
+
+\def\donoregister #1#2{\doflushatpar{\doprocesspageregister{#1}{}{}{#2}}} % register key - entry
+\def\dodoregister#1#2#3{\doflushatpar{\doprocesspageregister{#1}{}{#2}{#3}}} % register key altnum entry
+
+\def\startregister{\doquadrupleempty\dostartregister}
+\def\stopregister {\dodoubleargument\dostopregister}
+
+% a synonym, so that we can nest with overlap without syntax check problems
+
+\let\openregisterrange \startregister
+\let\closeregisterrange\stopregister
+
+\def\dostartregister[#1][#2][#3][#4]#5%
+ {\iffourthargument
+ % #1=register #2=tag #3=own #4=sortkey #5=entry
+ \doflushatpar{\doprocesspageregister{#1}{#2}{#4}{#3}{#5}}%
+ \else
+ % #1=register #2=tag #3=sortkey #5=entry
+ \doflushatpar{\doprocesspageregister{#1}{#2}{#3}{}{#5}}%
+ \fi}
+
+\def\dostopregister[#1][#2]%
+ {\ifcsname\??id#1->#2\endcsname
+ \getvalue{\??id#1->#2}%
+ \letgvalue{\??id#1->#2}\relax
+ \fi}
+
+\def\doseeregister[#1][#2]#3#4%
+ {\doflushatpar{\doprocessseeregister{#1}{#2}{#3}{#4}}}
+
+\def\doprocessseeregister#1#2#3#4% register key entry seeword
+ {\begingroup
+ \edef\currentregister{#1}%
+ \edef\currentregisterexpansion{\registerparameter\c!expansion}%
+ \ifx\currentregisterexpansion\s!xml
+ \xmlstartraw
+ \xdef\currentregisterentries{\detokenize{#3}}% not ok yet
+ \xdef\currentregisterseeword{\detokenize{#4}}% not ok yet
+ \xmlstopraw
+ \globallet\currentregistercoding\s!xml
+ \else
+ \ifx\currentregisterexpansion\v!yes
+ \xdef\currentregisterentries{#3}% not ok yet
+ \xdef\currentregisterseeword{#4}% not ok yet
+ \else
+ \xdef\currentregisterentries{\detokenize{#3}}% not ok yet
+ \xdef\currentregisterseeword{\detokenize{#4}}% not ok yet
+ \fi
+ \globallet\currentregistercoding\s!tex
+ \fi
+ \setnextinternalreference
+ % we could consider storing register entries in list
+ \ctxlua{ jobregisters.store {
+ metadata = {
+ kind = "see",
+ name = "\currentregister",
+ level = structure.sections.currentlevel(),
+ catcodes = \the\catcodetable,
+ },
+ references = {
+ internal = \nextinternalreference,
+ section = structure.sections.currentid(),
+ },
+ entries = {
+ % we need a special one for xml, this is just a single one
+ "\currentregisterentries", "#2"
+ },
+ seeword = {
+ text = "\currentregisterseeword"
+ },
+ }
+ }%
+ \endgroup}
+
+%D Rendering:
+
+\let\utilityregisterlength\!!zerocount
+
+\def\determineregistercharacteristics
+ {\dodoubleempty\dodetermineregistercharacteristics}
+
+\def\dodetermineregistercharacteristics[#1][#2]%
+ {\edef\utilityregisterlength{\ctxlua{jobregisters.analyse('\currentregister')}}%
+ \ifcase\utilityregisterlength\relax
+ \resetsystemmode\v!register
+ \else
+ \setsystemmode \v!register
+ \fi}
+
+\newtoks\everyplaceregister
+
+\appendtoks
+ \dontcomplain
+\to \everyplaceregister
+
+\def\placeregister
+ {\dodoubleempty\doplaceregister}
+
+\def\doplaceregister[#1][#2]%
+ {\iffirstargument
+ \begingroup
+ \edef\currentregister{#1}%
+ \setupregister[\currentregister][#2]%
+ \the\everyplaceregister
+ \startcolumns
+ [\c!n=\registerparameter\c!n,
+ \c!balance=\registerparameter\c!balance,
+ \c!align=\registerparameter\c!align,
+ \c!tolerance=\registerparameter\c!tolerance]%
+ \startpacked[\v!blank]%
+ \ctxlua{jobregisters.process('\currentregister',{
+ language = "\registerparameter\s!language",
+ compress = "\registerparameter\c!compress",
+ criterium = "\registerparameter\c!criterium",
+ },
+ {
+% prefix = "\registerparameter\c!pageprefix",
+ separatorset = "\registerparameter\c!pageprefixseparatorset",
+ conversionset = "\registerparameter\c!pageprefixconversionset",
+ stopper = \!!bs\registerparameter\c!pageprefixstopper\!!es,
+ set = "\registerparameter\c!pageprefixset",
+ segments = "\registerparameter\c!pageprefixsegments",
+ connector = \!!bs\registerparameter\c!pageprefixconnector\!!es,
+ },
+ {
+ prefix = "\registerparameter\c!pageprefix",
+ separatorset = "\registerparameter\c!pageseparatorset",
+ conversionset = "\registerparameter\c!pageconversionset",
+ stopper = \!!bs\registerparameter\c!pagestopper\!!es,
+ segments = "\registerparameter\c!pagesegments",
+ }
+ )}%
+ \stoppacked
+ \stopcolumns
+ \endgroup
+ \fi}
+
+\def\dolimitedregisterentry#1{\limitatetext{#1}\currentregistermaxwidth\unknown}%
+
+\appendtoks
+ \edef\currentregistermaxwidth{\registerparameter\c!maxwidth}%
+ \ifx\currentregistermaxwidth\empty
+ \let\limitedregisterentry\firstofoneargument
+ \else
+ \let\limitedregisterentry\dolimitedregisterentry
+ \fi
+\to \everyplaceregister
+
+\def\completeregister
+ {\dodoubleempty\docompleteregister}
+
+\def\docompleteregister[#1][#2]%
+ {\iffirstargument
+ \begingroup
+ \edef\currentregister{#1}%
+ % the expansion is needed because we don't want \v!'s in the tuo file (french)
+ \normalexpanded{\noexpand\systemsuppliedchapter[\currentregister]{\noexpand\headtext{\currentregister}}}%
+ \placeregister[\currentregister][#2]%
+ \page[\v!yes]%
+ \endgroup
+ \fi}
+
+% test case for collapsing (experimental, for Steffen Wolfrum)
+%
+% \starttext
+% \placeregister[index][collapse=no] \blank[2*big]
+% \placeregister[index][collapse=yes] \blank[2*big]
+% \placeregister[index][collapse=akk] \page
+% \dorecurse{10}{test 1:!\index{test} test \page}
+% \dorecurse{5} {test 2:\recurselevel \page}
+% \dorecurse{10}{test 3:!\index{test} test \page}
+% \dorecurse{5} {test 4:\recurselevel \page}
+% \dorecurse{1} {test 5:!\index{test} test \page}
+% \dorecurse{5} {test 6:\recurselevel \page}
+% \dorecurse{10}{test 7:!\index{test} test \page}
+% \dorecurse{5} {test 8:\recurselevel \page}
+% oeps \index{oeps}
+% xxxx \index{xxxx}
+% todo \index{todo}
+% \stoptext
+
+%D Character rendering (sections):
+
+\def\defaultregistercharacter#1%
+ {\doifsomething{#1}
+ {\doifelse{\registerparameter\c!indicator}\v!yes
+ {\executeifdefined{\strippedcsname\doregistercharacter\registerparameter\c!alternative}\doregistercharactera{#1}}
+ {\noregistercharacter{#1}}}}
+
+\def\noregistercharacter#1%
+ {\registerparameter\c!before
+ \goodbreak}
+
+% a = <before> <goodbreak> <character> <par> <after> <nobreak>
+
+\def\doregistercharactera#1%
+ {\registerparameter\c!before
+ \vskip\lineheight\goodbreak\vskip-\lineheight
+ \ifhmode\unskip\else\noindent\fi % brrr
+ \begingroup\dosetregisterattributes\c!style\c!color
+ \registerparameter\c!command{\strut#1}%
+ \endgroup
+ \registerparameter\c!after
+ \par\nobreak}
+
+% b = <goodbreak> <before> <character> <after> <nobreak>
+
+\def\doregistercharacterb#1% here no lineheight hackery ! ! !
+ {\registerparameter\c!before
+ \ifhmode\unskip\else\noindent\fi % brrr
+ \begingroup\dosetregisterattributes\c!style\c!color
+ \registerparameter\c!command{\strut#1}%
+ \endgroup
+ \registerparameter\c!after
+ \nobreak}
+
+% extra:
+
+\def\doregistercharacterA#1{\doregistercharactera{\WORD{#1}}}
+\def\doregistercharacterB#1{\doregistercharacterb{\WORD{#1}}}
+
+%D The following macros are the interface to the rendering. These are
+%D generated by \LUA. This might change.
+
+\def\startregisteroutput
+ {\endgraf}
+
+\def\stopregisteroutput
+ {\endgraf}
+
+\def\startregisterentries#1% depth
+ {\endgraf
+ \begingroup
+ \dosetregisterattributes\c!textstyle\c!textcolor
+ \advance\leftskip\numexpr#1-1\relax\dimexpr\registerparameter\c!distance\relax
+ \hangindent\registerparameter\c!distance\hangafter\plusone}
+
+\def\stopregisterentries
+ {\endgraf
+ \endgroup}
+
+\def\startregistersection#1% title
+ {\registercharacter{#1}\endgraf}
+
+\def\stopregistersection
+ {\endgraf}
+
+\newconditional\registerpagedone
+
+\def\startregisterpages
+ {\begingroup
+ \setfalse\registerpagedone
+ \dosetregisterattributes\c!pagestyle\c!pagecolor}
+
+\def\stopregisterpages
+ {\endgroup}
+
+\def\startregisterseewords
+ {\begingroup
+ \setfalse\registerpagedone
+ \dosetregisterattributes\c!pagestyle\c!pagecolor}
+
+\def\stopregisterseewords
+ {\endgroup}
+
+\def\registerpageseparator% todo: , configurable
+ {\ifconditional\registerpagedone
+ \registerpageseparatorsymbol
+ \else
+ \hskip\registerparameter\c!distance\relax
+ \settrue\registerpagedone
+ \fi}
+
+\def\registeronepage#1% content
+ {\registerpageseparator\registerparameter\c!pagecommand{#1}}
+
+\def\registerpagerange#1#2% content, content todo: -- configurable
+ {\registerpageseparator\registerparameter\c!pagecommand{#1}|--|\registerparameter\c!pagecommand{#2}}
+
+\def\registeroneword#1% content
+ {\registerpageseparator\registerseeword{#1}}
+
+\def\defaultregisterentry #1{\registerparameter\c!textcommand{\limitedregisterentry{\registerparameter\c!deeptextcommand{#1}}}}
+\def\defaultregisterseeword#1{\labeltexts\v!see{#1}}
+
+\let\registerseeword \defaultregisterseeword
+\let\registerentry \defaultregisterentry
+\let\registercharacter\defaultregistercharacter
+
+%D A few specific rendering variants:
+
+% \def\doregisterpagelocation#1#2%
+% {\nextregisterpage
+% \hbox to 1em{\hss\doregisterpagehowto{#1}{#2}\hss}}
+
+% todo: \installregisterpagehandler
+
+\def\registerpagebuttonsymbol{\vrule\!!width1em\!!height1ex\!!depth\zeropoint\relax}
+
+\setvalue{\??id:\c!symbol :\c!n}{\def\registerpageseparatorsymbol{, }\let\registerpagenumberhandler\firstofoneargument}
+\setvalue{\??id:\c!symbol :\c!a}{\def\registerpageseparatorsymbol{, }\let\registerpagenumberhandler\firstofoneargument} % now done via conversion
+\setvalue{\??id:\c!symbol:\v!none}{\let\registerpageseparatorsymbol\empty\let\registerpagenumberhandler\gobbleoneargument}
+\setvalue{\??id:\c!symbol :1}{\let\registerpageseparatorsymbol\space\def\registerpagenumberhandler{\symbol[1]\gobbleoneargument}}
+\setvalue{\??id:\c!symbol :2}{\let\registerpageseparatorsymbol\space\def\registerpagenumberhandler{\registerpagebuttonsymbol\gobbleoneargument}}
+
+\def\setregisterpagerendering
+ {\edef\currentregisterpagesymbol{\registerparameter\c!symbol}%
+ \ifx\currentregisterpagesymbol\empty
+ \csname\??id:\c!symbol:\c!n\endcsname
+ \else\ifcsname\??id:\c!symbol:\currentregisterpagesymbol\endcsname
+ \csname\??id:\c!symbol:\currentregisterpagesymbol\endcsname
+ \else
+ \let\registerpageseparatorsymbol\space
+ \def\registerpagenumberhandle{\registerparameter\c!symbol\gobbleoneargument}%
+ \fi\fi}
+
+\appendtoks
+ \setregisterpagerendering
+\to \everyplaceregister
+
+%D Don't use \type{\string#2}; another hack is needed, since
+%D \type {#2} can be \type {\string} itself.
+%
+% \def\doregisterreference[#1]#2%
+% {\doifsomething{#2}
+% {\doif{\registerparameter\c!referencing}\v!on
+% {\pagereference[#1:\strippedcsname#2]}}}
+
+% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+% % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % % %
+
+%D The following code will be reimplemented (not that hard) when it's needed
+%D again and/or when I'm bored.
+
+% \def\getalllistreferences#1#2%
+% {\gdefconvertexpanded\currentregisterentry{\getvalue{\??id#1\c!expansion}}{#2}%
+% \doifdefinedelse{\??id#1\??id\currentregisterentry}
+% {\edef\alllistreferences%
+% {\getvalue{\??id#1\??id\currentregisterentry}}%
+% \beforesplitstring\alllistreferences\at::\to\internallistreference
+% \aftersplitstring \alllistreferences\at::\to\alllistreferences}
+% {\let\alllistreferences\empty
+% \def\internallistreference{0}}}
+
+% \def\dosetlinkregister#1% is die page reference echt nodig?
+% {\setregisterpage{#1}%
+% \global\let\currentregisterentry\empty
+% \global\firstsubentrytrue % not needed
+% \global\firstsubsubentrytrue % not needed too
+% \setvalue{#1\s!entrya}##1{\dosetlinkregisterentrya{#1}{##1}}%
+% \setvalue{#1\s!entry }##1{\dosetpageregisterletter{#1}{##1}}}
+
+% \def\dosetlinkregisterentrya#1#2%
+% {\global\utilitydonetrue
+% \c!entryletter
+% \iflocation
+% \getalllistreferences{#1}{#2}%
+% % no \endgraf
+% \hangindent1em\noindent\c!entryreference
+% %
+% %\thisissomeinternal{\s!lin}{\internallistreference}%
+% %
+% \pagereference[-:\s!lin:\internallistreference]% -: added
+% %
+% \getcommacommandsize[\alllistreferences]%
+% \getfromcommacommand[\alllistreferences][1]%
+% \ifnum\commalistsize=1
+% \let\firstlistreference\empty
+% \let\midlistreference\commalistelement
+% \let\lastlistreference\empty
+% \else
+% \let\firstlistreference\commalistelement
+% \getfromcommacommand[\alllistreferences][\commalistsize]%
+% \let\lastlistreference\commalistelement
+% \ifnum\commalistsize=2
+% \let\midlistreference\empty
+% \else
+% \!!counta\commalistsize
+% \divide\!!counta 2
+% \getfromcommacommand[\alllistreferences][\!!counta]%
+% \let\midlistreference\commalistelement
+% \fi
+% \fi
+% % aangepast
+% \def\dodocommand[##1-##2]%
+% {\gotonextinternal{\s!ind}{##1}{##2}{\box0}}%
+% \doifelsevalue{\??id#1\c!interaction}\v!pagenumber
+% {\limitedregisterentry{#1}{#2}} % paginanummer
+% {{\setbox0\hbox{\limitedregisterentry{#1}{\begstrut#2}}%
+% \ifx\firstlistreference\empty % tekst,alles
+% \ifx\midlistreference\empty
+% \box0
+% \else
+% \expandafter\dodocommand\expandafter[\midlistreference]%
+% \fi
+% \else
+% \expandafter\dodocommand\expandafter[\firstlistreference]%
+% \fi}}%
+% \doifvalue{\??id#1\c!number}\v!yes
+% {\hskip\getvalue{\??id#1\c!distance}(\commalistsize)}%
+% \doifnotvalue{\??id#1\c!interaction}\v!text % paginanummer,alles
+% {\def\docommand##1##2%
+% {{\setbox0\hbox{\showlocation{\hbox to 1em{\hss\symbol[##2]\hss}}}%
+% \ifx##1\empty
+% % \hskip\wd0 % (optioneel maken)
+% \else
+% \expandafter\dodocommand\expandafter[##1]%
+% \fi}}%
+% \hskip\getvalue{\??id#1\c!distance}%
+% \docommand\firstlistreference\v!previous
+% \docommand\midlistreference\v!somewhere
+% \docommand\lastlistreference\v!next}%
+% % tot hier
+% \else
+% % no \endgraf
+% \noindent\c!entryreference
+% \limitedregisterentry{#1}{#2}%
+% \fi
+% \endgraf}
+
+% \def\dosetregister#1%
+% {\doifelsevalue{\??id#1\c!coupling}\v!yes
+% {\ifautoregisterhack
+% \dosetautoregister{#1}%
+% \else
+% \dosetlinkregister{#1}%
+% \fi}
+% {\dosetpageregister{#1}}}
+
+\def\dosetregister#1%
+ {\dosetpageregister{#1}}
+
+% \newcounter\internallistreference
+
+% \def\doloadregisterlinks#1%
+% {\setregisterpage{#1}%
+% \global\let\currentregisterentry\empty
+% \global\firstregisterpagetrue
+% \setvalue{#1\s!entrya}##1%
+% {\global\firstregisterpagetrue
+% \gdefconvertedargument\currentregisterentry{##1}% global nodig?
+% \doglobal\increment\internallistreference}%
+% \setvalue{#1\s!from}%
+% {\getvalue{#1\s!page}}%
+% \ifautoregisterhack
+% \setvalue{#1\s!page}##1##2##3##4%
+% {\doifreglevelelse[##3]
+% {\global\utilitydonetrue
+% \iffirstregisterpage
+% \@EA\xdef\csname\??id#1\??id\currentregisterentry\endcsname
+% {\internallistreference::##4}%
+% \else % catches errors in index
+% \ifcsname\??id#1\??id\currentregisterentry\endcsname
+% \@EA\xdef\csname\??id#1\??id\currentregisterentry\endcsname
+% {\csname\??id#1\??id\currentregisterentry\endcsname,##4}%
+% \fi
+% \fi}
+% {}}%
+% \else
+% \setvalue{#1\s!page}##1##2##3##4%
+% {\doifreglevelelse[##3]
+% {\global\utilitydonetrue
+% \iffirstregisterpage
+% \global\firstregisterpagefalse
+% \@EA\xdef\csname\??id#1\??id\currentregisterentry\endcsname
+% {\internallistreference::##2-##4}%
+% \else % catches errors in index
+% \ifcsname\??id#1\??id\currentregisterentry\endcsname
+% \@EA\xdef\csname\??id#1\??id\currentregisterentry\endcsname
+% {\csname\??id#1\??id\currentregisterentry\endcsname,##2-##4}%
+% \fi
+% \fi}
+% {}}%
+% \fi}
+
+% \def\docoupleregister[#1][#2]%
+% {\iflocation
+% \ifcase0\countervalue{autolink:#1}\relax % only once
+% \begingroup
+% \let\dosetregister\doloadregisterlinks
+% \def\currentregister{#1}%
+% \setupregister[#1][#2]%
+% \mkloadregister\currentregister\dobeforeplaceregister\doafterplaceregister
+% \endgroup
+% \ifautoregisterhack
+% \doinitializeautoregister{#1}%
+% \else
+% \doinitializelinkregister{#1}%
+% \fi
+% \fi
+% \fi}
+
+% \def\coupleregister
+% {\dodoubleempty\docoupleregister}
+
+% \def\dodocommandprolinrefAA[#1-#2]%
+% {\def\lastlistreference{#1-#2}}
+
+% \def\dodocommandprolinrefA[#1-#2]%
+% {\def\lastlistreference{#1-#2}%
+% \ifx\firstlistreference\empty
+% \let\firstlistreference\lastlistreference
+% \fi
+% \ifnum#1<\nextinternalreference\relax
+% \let\prevlistreference\lastlistreference
+% \else\ifnum#1>\nextinternalreference\relax
+% \let\nextlistreference\lastlistreference
+% \let\dodocommandprolinrefA\dodocommandprolinrefAA
+% \else
+% \let\selflistreference\lastlistreference
+% \fi\fi}
+
+% \def\docommandprolinrefA#1%
+% {\dodocommandprolinrefA[#1]}
+
+% \def\dodocommandprolinrefB[#1-#2]%
+% {\gotonextinternal{\s!ind}{#1}{#2}{\box0}}
+
+% \def\docommandprolinrefB#1#2#3%
+% {\bgroup
+% \ifx#2\empty
+% \doifvalue{\??id#1\c!unknownreference}\v!empty{\hskip1em}%
+% \else
+% \setbox0\hbox to 1em{\hss\showlocation{\symbol[#3]}\hss}%
+% \expandafter\dodocommandprolinrefB\expandafter[#2]%
+% \fi
+% \egroup}
+
+% \def\doprocesslinkregister[#1][#2]#3%
+% {\hbox
+% {\doprocesspageregister{}{#2}{}{#3}%
+% \let\firstlistreference\empty
+% \let\lastlistreference\empty
+% \let\selflistreference\empty
+% \let\prevlistreference\empty
+% \let\nextlistreference\empty
+% \getalllistreferences{#1}{#3}%
+% \ifx\alllistreferences\empty \else
+% \normalexpanded{\noexpand\rawprocesscommalist[\alllistreferences]}\docommandprolinrefA
+% \fi
+% \ifx\prevlistreference\empty
+% \let\prevlistreference\lastlistreference
+% \fi
+% \ifx\nextlistreference\empty
+% \let\nextlistreference\firstlistreference
+% \fi
+% \ifx\prevlistreference\selflistreference
+% \let\prevlistreference\empty
+% \let\nextlistreference\empty
+% \fi
+% \setalignmentswitch{\getvalue{\??id#1\c!location}}%
+% \ifcase\alignmentswitch
+% % links
+% \docommandprolinrefB{#1}\prevlistreference\v!previous
+% \docommandprolinrefB{#1}\nextlistreference\v!next
+% \or
+% % midden
+% \docommandprolinrefB{#1}\prevlistreference\v!previous
+% \or
+% % rechts
+% \fi
+% \doifreferencefoundelse{\s!lin:\internallistreference}
+% {\gotosomeinternal
+% \s!lin \internallistreference \currentrealreference
+% {\showlocation{\limitedregisterentry{#1}{#3}}}}
+% {\hbox{\limitedregisterentry{#1}{#3}}}%
+% \ifcase\alignmentswitch
+% % links
+% \or
+% % midden
+% \docommandprolinrefB{#1}\nextlistreference\v!next
+% \or
+% % rechts
+% \docommandprolinrefB{#1}\prevlistreference\v!previous
+% \docommandprolinrefB{#1}\nextlistreference\v!next
+% \fi}}
+
+% \def\doprocesslinkedregister[#1][#2]#3% page auto link
+% {\bgroup
+% \chardef\registerpagestatus\plusone
+% \def\currentregister{#1}%
+% \iflocation % \next is not needed
+% \ifautoregisterhack
+% \def\next{\doprocessautoregister[#1][#2]}%
+% \else
+% \def\next{\doprocesslinkregister[#1][#2]}%
+% \fi
+% \else
+% \def\next{\doprocesspageregister{}{#2}{}}%
+% \fi
+% \next{#3}%
+% \egroup}
+
+% \def\dodolinkedregister[#1][#2]#3% page auto link
+% {\doflushatpar{\doprocesslinkedregister[#1][#2]{#3}}}
+
+% \def\dolinkedregister#1%
+% {\dodoubleempty\dodolinkedregister[#1]}
+
+% \def\dosetautoregister#1%
+% {\makecounter{autolink:#1}%
+% \setregisterpage{#1}%
+% \global\let\currentregisterentry\empty
+% \global\firstsubentrytrue % not needed
+% \global\firstsubsubentrytrue % not needed too
+% \setvalue{#1\s!entrya}##1{\dosetautoregisterentrya{#1}{##1}}%
+% \setvalue{#1\s!entry }##1{\dosetpageregisterletter{#1}{##1}}}
+
+% \def\dosetautoregisterentrya#1#2%
+% {\global\utilitydonetrue
+% \c!entryletter
+% \iflocation
+% \getalllistreferences{#1}{#2}%
+% \endgraf\hangindent1em\noindent\c!entryreference
+% \pagereference[-:\s!lin:\internallistreference]%
+% \pluscounter{autolink:#1}%
+% \bgroup
+% %\setupinteraction[\c!color=,\c!contrastcolor=,\c!style=]% kan sneller
+% \resetinteractionparameter\c!color
+% \resetinteractionparameter\c!contrastcolor
+% \resetinteractionparameter\c!style
+% \gotobox
+% {\limitedregisterentry{#1}{\begstrut#2}}%
+% [JS(SetRegisterEntry{\v!register,\countervalue{autolink:#1},#2,{\alllistreferences}})]%
+% \egroup
+% \else
+% \endgraf\noindent\c!entryreference
+% \limitedregisterentry{#1}{#2}%
+% \fi}
+
+% \def\doprocessautoregister[#1][#2]#3%
+% {\hbox
+% {\doprocesspageregister{}{#2}{}{#3}%
+% \doifreferencefoundelse{\s!lin:\internallistreference}
+% {\gotosomeinternal \s!lin
+% {\internallistreference}{\currentrealreference}
+% {\showlocation{\limitedregisterentry{#1}{#3}}}}
+% {\hbox{\limitedregisterentry{#1}{#3}}}}}
+
+% \appendmacro aan openpaginaactie (in shipout)
+
+%D The first implementation used one main field with clones.
+%D In a 2500 page document this resulted in a rather (anoying)
+%D long start||up time. This \quote {every page its own field}
+%D solution, combined with a \quote {page open action}, works
+%D much faster, but is conceptually pretty weak.
+
+% \def\complexregisterfield[#1]%
+% {\definefield[#1:\realfolio][line][\v!register]%
+% \field[#1:\realfolio]}
+
+% \def\simpleregisterfield
+% {\complexregisterfield[\v!register]}
+
+% \definecomplexorsimple\registerfield
+
+% \appendtoks
+% % for now
+% \setupfield
+% [\v!register]
+% [\c!width=10em,
+% \c!height=3ex,
+% \c!align=\v!middle,
+% \c!option=\v!readonly,
+% \c!location=\v!low]
+% \to \everydump
+
+% \def\doinitializeautoregister#1%
+% {\useJSscripts[reg]%
+% \useJSpreamblenow{LinkedRegisters}%
+% \setupinteraction[\c!openpageaction=JS(UpdateRegisterField{\v!register})]%
+% \definereference[\v!reset\v!register][JS(ResetRegisterEntry{\v!register})]%
+% \definereference[\v!first\v!register][JS(GotoFirstRegisterEntry{\v!register})]%
+% \definereference[\v!previous\v!register][JS(GotoPreviousRegisterEntry{\v!register})]%
+% \definereference[\v!next\v!register][JS(GotoNextRegisterEntry{\v!register})]%
+% \definereference[\v!last\v!register][JS(GotoLastRegisterEntry{\v!register})]}
+
+% \def\doinitializelinkregister#1%
+% {}
+
+% todo ruwe register
+
+%D Default index:
+
+\defineregister
+ [\v!index]
+ [\v!indices]
+
+% \setupregister[index][koppeling=ja]
+%
+% \stelveldenin
+% [register][achtergrond=raster,kader=uit]
+%
+% \stelvoettekstenin
+% [{\field[index]}]
+%
+% \stelhoofdtekstenin
+% [{\naar {first}[eersteindex]\quad
+% \naar{previous}[vorigeindex]\quad
+% \naar {next}[volgendeindex]\quad
+% \naar {last}[laatsteindex]\quad\quad
+% \naar {index}[index]}]
+%
+% \starttekst
+%
+% oeps~~~\gekoppeldeindex{oeps} \blanko
+% flop~~~\gekoppeldeindex{flop} \blanko
+% test~~~\gekoppeldeindex{test} \pagina
+% flop~~~\gekoppeldeindex{flop} \blanko
+% test~~~\gekoppeldeindex{test} \pagina
+% oeps~~~\gekoppeldeindex{oeps} \blanko
+% test~~~\gekoppeldeindex{test} \pagina
+% flop~~~\gekoppeldeindex{flop} \blanko
+% oeps~~~\gekoppeldeindex{oeps} \pagina
+%
+% \volledigeindex
+
+\protect \endinput
diff --git a/tex/context/base/strc-ren.tex b/tex/context/base/strc-ren.tex
new file mode 100644
index 000000000..c2b8ffd83
--- /dev/null
+++ b/tex/context/base/strc-ren.tex
@@ -0,0 +1,467 @@
+%D \module
+%D [ file=strc-ren,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Section Rendering,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Section Rendering}
+
+\unprotect
+
+\chardef\headtimingmode=0
+
+% \chardef\headtimingmode=1 % 0 also works ok now too
+%
+% Martin Kolarik's problem:
+%
+% \setuphead[section][command=\doTitle]
+% \def\doTitle#1#2{\ruledvbox{\forgetall \hsize=4cm \ruledhbox{\ruledvtop{#1}\ruledvtop{#2}}}}
+% \section{test test test test test test test test test test test test test test test test test}
+
+\newevery \everyheadstart \relax
+
+\def\placeheadmargintexts
+ {\the\everyheadstart
+ \doif{\structureheadparameter\c!margintext}\v!yes\placemargincontent}
+
+\def\doplaceheadtextcomponent#1#2%
+ {\begingroup
+ \dosetstructureheadattributes\c!style\c!color
+ \dosetstructureheadattributes\c!textstyle\c!textcolor
+ \dontconvertfont
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \setupinterlinespace
+ \else
+ \setupspacing
+ \fi
+ % \ifcase\headtimingmode#1\fi % can introduce cr
+ \structureheadparameter\c!commandbefore
+ \placeheadmargintexts
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \structureheadparameter\c!textcommand% struts can be nilled with \setnostrut
+ {\setstrut
+ \begstrut
+ \ifcase\headtimingmode\hbox{#1}\fi
+ \executeifdefined{\??nh\currentstructurehead\c!deeptextcommand}\firstofoneargument{#2}%
+ \endstrut}% \hbox prevents break
+ \xdef\localheadheight {\the\strutht}%
+ \xdef\localheaddepth {\the\strutdp}%
+ \xdef\localheadlineheight{\the\lineheight}%
+ % == \globallet\localheaddepth\strutdepth
+ \else
+ \ifcase\headtimingmode#1\fi
+ \structureheadparameter\c!textcommand
+ {\executeifdefined{\??nh\currentstructurehead\c!deeptextcommand}\firstofoneargument{#2}}%
+ \fi
+ \structureheadparameter\c!commandafter
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \endgraf
+ \fi
+ \endgroup}
+
+\def\doplaceheadnumbercomponent#1#2%
+ {\begingroup
+ \dosetstructureheadattributes\c!style\c!color
+ \dosetstructureheadattributes\c!numberstyle\c!numbercolor
+ % \getvalue{\??ko\currentstructurehead\c!commandbefore}% strange, why here? moved 21/11/2005
+ \placeheadmargintexts
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ % can be nilled with \setnostrut
+ \structureheadparameter\c!numbercommand
+ {\setstrut
+ \begstrut
+ \executeifdefined{\??nh\currentstructurehead\c!deepnumbercommand}\firstofoneargument{#2}%
+ \endstrut}%
+ \else
+ \structureheadparameter\c!numbercommand
+ {\executeifdefined{\??nh\currentstructurehead\c!deepnumbercommand}\firstofoneargument{#2}}%
+ \fi
+ \endgroup}
+
+% \newif\ifheadnumbercontent
+% \newif\ifemptyhead
+% \newif\ifdisplaysectionhead
+
+\def\doplacestructureheadtext#1#2#3% nodes, text, endstuff
+ {\beginheadplacement
+\postponenotes
+ \doresettructureheadnumbercontent
+ \ifconditional\structureheadleaveempty % \ifemptyhead
+ \setbox\sectionheadbox\ifvertical\vbox\else\hbox\fi to \zeropoint{#1}%
+ \makestrutofbox\sectionheadbox
+ \else
+ \setbox\sectionheadbox\ifvertical\vbox\else\hbox\fi
+ {\doresettructureheadnumbercontent
+ \ifcase\headtimingmode\or#1\fi % outerside font determines distance
+ \dosetfontattribute{\??nh\currentstructurehead}\c!style % but we don't want color to influence user command, todo: get the if-else out of it
+ \structureheadparameter\c!command{}{\doplaceheadtextcomponent{#1}{#2}}}%
+ \fi
+ \endheadplacement{#3}}
+
+\def\doplacestructureheadnumbertext#1#2#3#4% nodes number text nodes
+ {\beginheadplacement
+\postponenotes
+ \doiftextelse{#2}\dosettructureheadnumbercontent\doresettructureheadnumbercontent
+ \ifconditional\structureheadleaveempty % \ifemptyhead % = needed
+ \setbox\sectionheadbox\ifvertical\vbox\else\hbox\fi to \zeropoint{#1}%
+ \makestrutofbox\sectionheadbox
+ \else % = needed
+ \setbox\sectionheadbox\ifvertical\vbox\else\hbox\fi
+ {\ifcase\headtimingmode\or#1\fi
+ \dosetfontattribute{\??nh\currentstructurehead}\c!style
+ \structureheadparameter\c!command{\doplaceheadnumbercomponent{#1}{#2}}{\doplaceheadtextcomponent{#1}{#3}}}%
+ \fi
+ \endheadplacement{#4}}
+
+\def\placestructureheadnumbertext
+ {\doplacestructureheadnumbertext\empty\getstructureheadnumber\getstructureheadtitle\getstructureheadsyncs}
+
+\def\placestructureheadtext
+ {\doplacestructureheadtext\empty\getstructureheadtitle\getstructureheadsyncs}
+
+\def\placestructureheadnothing
+ {\getstructureheadsyncs}
+
+%D \starttyping
+%D \def\StretchedBox#1%
+%D {\framed
+%D [frame=off,offset=.5em,align=middle,width=broad]
+%D {\sc\def\stretchedspaceamount{.3em}\stretchednormalcase{#1}}}
+%D
+%D \definehead[MySubject][subject]
+%D \setuphead [MySubject][deeptextcommand=\StretchedBox]
+%D
+%D \MySubject{feeling stretched feeling stretched feeling stretched feeling stretched}
+%D \stoptyping
+
+\let\headlastlinewidth\!!zeropoint
+
+\def\localheadheight {\strutht}
+\def\localheaddepth {\strutdp}
+\def\localheadlineheight{\lineheight}
+
+\def\dolocalheadsetup % koppeling met standaard kopcommando / engels
+ {\forgetall % traag dus ...
+ \doifsomething{\structureheadparameter\c!align } {\normalexpanded{\noexpand\setupalign [\structureheadparameter\c!align ]}}%
+ \doifsomething{\structureheadparameter\c!tolerance} {\normalexpanded{\noexpand\setuptolerance[\structureheadparameter\c!tolerance]}}%
+ \doif {\structureheadparameter\c!strut }\v!no{\setnostrut}% new
+ \def\\{\crlf\strut\ignorespaces}}
+
+\def\beginheadplacement
+ {\bgroup
+ \setsystemmode\currentstructurehead
+ \ifgridsnapping\iftracegridsnapping\showstruts\fi\fi
+ \xdef\localheadheight {\the\strutht}%
+ \xdef\localheaddepth {\the\strutdp}%
+ \xdef\localheadlineheight{\the\lineheight}%
+ % == \globallet\localheaddepth\strutdp
+ \everypar\emptytoks % needed indeed
+ \noindent % ipv \whitespace elders, na \forgetall !
+ \bgroup
+ \doifinsetelse{\structureheadparameter\c!aligntitle}{\v!yes,\v!float}% new
+ {\skip0 1\leftskip
+ \skip2 1\rightskip
+ \xdef\localheadskip{\the\skip0}%
+ \forgetall
+ \leftskip\skip0
+ \rightskip\skip2
+ \setlocalhsize\hsize\localhsize
+ \forgetbothskips}
+ {\globallet\localheadskip\!!zeropoint
+ \forgetall}%
+ \dontcomplain
+ \postponenotes
+ \iflocation
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \else
+ \noninterferingmarks
+ \fi
+ \fi
+ \resetinteractionparameter\c!style
+ \resetinteractionparameter\c!color
+ \resetinteractionparameter\c!contrastcolor
+ %\strictouterreferencestrue % tzt instelling
+ \let\localheadsetup\dolocalheadsetup
+ \startsynchronization}
+
+% \setuphead[chapter] [style=\bfd,after=,hang=line] % fit broad 2
+% \setuphead[section] [style=\bfc,after=,hang=line]
+% \setuphead[subsection] [style=\bfb,after=,hang=line]
+% \setuphead[subsubsection] [style=\bfa,after=,hang=line]
+% \setuphead[subsubsubsection][style=\bf ,after=,hang=line]
+%
+% \chapter {Test} \input tufte \page
+% \section {Test} \input tufte \page
+% \subsection {Test} \input tufte \page
+% \subsubsection {Test} \input tufte \page
+% \subsubsubsection{Test} \input tufte \page
+%
+% \chapter {Test\\Test} \input tufte \page
+% \section {Test\\Test} \input tufte \page
+% \subsection {Test\\Test} \input tufte \page
+% \subsubsection {Test\\Test} \input tufte \page
+% \subsubsubsection{Test\\Test} \input tufte \page
+
+\def\hangheadplacement
+ {\scratchdimen\localheadlineheight
+ \bgroup
+ \openlineheight\scratchdimen
+ \scratchdimen\htdp0%
+ \getnoflines\scratchdimen
+ \advance\noflines\minusone
+ \normalexpanded{\egroup\noflines\the\noflines}% brrr
+ \setbox0\hbox{\lower\noflines\scratchdimen\box0}%
+ \scratchdimen\dimexpr\htdp0-\localheadheight+\strutdp\relax
+ \ht0 \strutht
+ \dp0 \strutdp
+ \edef\localheaddepth{\the\strutdp}}
+
+\newconditional\continuoussectionhead % oeps, \newif\ifcontinuoushead got lost
+\newbox\sectionheadbox
+
+\def\endheadplacement#1%
+ {\doifelse{\structureheadparameter\c!state}\v!start
+ {\doifnothing{\structureheadparameter\c!file}{\autocrossdocumentfalse}}
+ {\autocrossdocumentfalse}%
+ % no message needed here, should be a proper switch
+ \noflines\zerocount
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ % new (tod tight == one following line up)
+ \processaction
+ [\structureheadparameter\c!hang]
+ [ \v!line=>\hangheadplacement\noflines\zerocount,
+ \v!broad=>\hangheadplacement\getnoflines\scratchdimen,
+ \v!fit=>\hangheadplacement\getrawnoflines\scratchdimen,
+ \v!none=>\noflines\zerocount,
+ \v!default=>\noflines\zerocount,
+ \v!unknown=>\hangheadplacement\noflines\numexpr0\commalistelement-1\relax]%
+ % so far
+ \let\headlastlinewidth\!!zeropoint
+ \snaptogrid[\structureheadparameter\c!grid]\hbox
+ {\hskip\localheadskip
+ \hskip\structureheadparameter\c!margin\relax
+ \iflocation
+% \ifautocrossdocument
+% \doifreferencefoundelse{\structureheadparameter\c!file::\currentstructurehead}
+% {\edef\currentinnerreference{\s!aut:\currenttextreference}% stored in
+% \gotoouterlocation{}{\box\sectionheadbox}} % text slot
+% {\hbox{\box\sectionheadbox}}%
+% \else
+ \hbox{\box\sectionheadbox}%
+% \fi
+ \else
+ \hbox{\box\sectionheadbox}%
+ \fi}%
+ \doflushnotes % new, not really needed
+ \endgraf
+ \ifvmode
+ \ifnum\noflines>\zerocount
+ \dorecurse\noflines{\nointerlineskip\dosomebreak\nobreak\strut\endgraf}% to be checked
+ \fi
+ \nointerlineskip
+ \dosomebreak\nobreak
+ \fi
+ #1%
+ \else
+ \strut
+ \doflushnotes % new, here since we're in par mode
+ \iflocation
+ \ifautocrossdocument
+ \hhboxindent=\ifconditional\continuoussectionhead\headlastlinewidth\else\zeropoint\fi
+ \unhhbox\sectionheadbox\with{\gotobox{\box\hhbox}[\structureheadparameter\c!file::\currentstructurehead]}%
+ \advance\lasthhboxwidth by \numberheaddistance
+ \xdef\headlastlinewidth{\the\lasthhboxwidth}%
+ \else
+ \unhbox\sectionheadbox
+ \globallet\headlastlinewidth\!!zeropoint
+ \fi
+ \else
+ \unhbox\sectionheadbox
+ \globallet\headlastlinewidth\!!zeropoint
+ \fi
+ #1%
+ \hskip\numberheaddistance\!!plus\numberheaddistance\!!minus.25\dimexpr\numberheaddistance\relax
+ \hskip\continuousstructureheadsignal\ignorespaces
+ \fi
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \ifvmode
+ \ifgridsnapping % important, font related depth, see comment
+ \prevdepth\strutdp
+ \else
+ \prevdepth\localheaddepth
+ \fi
+ \fi
+ \fi
+ \stopsynchronization
+ \egroup
+ \egroup
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \checknextindentation[\structureheadparameter\c!indentnext]%
+ \else
+ \nonoindentation % recently added, was a bug
+ \fi}
+
+% nice testcase
+%
+% \setupheads[aligntitle=yes]
+%
+% \startnarrower
+% \subject{\dorecurse{100}{x }}
+% \section{\dorecurse{100}{x }}
+% \input tufte \par
+% \setupheads[alternative=inmargin]
+% \subject{\dorecurse{100}{x }}
+% \section{\dorecurse{100}{x }}
+% \input tufte \par
+% \stopnarrower
+
+\let\numberheadalternative\v!normal
+
+\def\defineheadplacement
+ {\dodoubleargument\dodefineheadplacement}
+
+\def\dodefineheadplacement[#1][#2]% #3#4
+ {\setvalue{\??ns:#1}{#2}%
+ \setvalue{\??ns::#1}}
+
+\def\normalplacehead
+ {\executeifdefined
+ {\??ns::\numberheadalternative}
+ {\getvalue{\??ns::\v!normal}}}
+
+\defineheadplacement[\v!paragraph][\v!vertical]#1#2%
+ {\vbox
+ {\localheadsetup
+ \begstrut
+ \ifconditional\structureheadshownumber % \ifheadnumbercontent
+ #1\hskip\numberheaddistance
+ \fi
+ #2}}
+
+% \defineheadplacement[\v!normal][\v!vertical]#1#2%
+% {\ifconditional\structureheadshownumber % \ifheadnumbercontent
+% \setbox0\hbox{{#1}\hskip\numberheaddistance}%
+% \vbox
+% {\localheadsetup
+% \hangindent 1\wd0
+% \hangafter 1
+% \noindent
+% \unhbox0 % don't use \strut's here!
+% #2}%
+% \else
+% \vbox
+% {\localheadsetup\noindent#2}%
+% \fi}
+%
+% enhanced version:
+
+% \setuphead
+% [chapter]
+% [numberwidth=2cm,hang=line,after={\blank[3*line]}]
+%
+% \chapter{Oeps oeps oeps} \input tufte \section{Oeps}
+% \chapter{Oeps oeps oeps} \section{Oeps} \input tufte
+
+\defineheadplacement[\v!normal][\v!vertical]#1#2%
+ {\vbox
+ {\localheadsetup
+ \edef\headwidth {\structureheadparameter\c!width }%
+ \edef\headnumberwidth{\structureheadparameter\c!numberwidth}%
+ \edef\headtextwidth {\structureheadparameter\c!textwidth }%
+ \ifconditional\structureheadshownumber % \ifheadnumbercontent
+ \ifx\headwidth\empty
+ \else
+ \ifx\headnumberwidth\empty
+ \ifx\headtextwidth\empty\else
+ \edef\headnumberwidth{\the\dimexpr\headwidth-\headtextwidth\relax}%
+ \fi
+ \else
+ \ifx\headtextwidth\empty
+ \edef\headtextwidth{\the\dimexpr\headwidth-\headnumberwidth\relax}%
+ \fi
+ \fi
+ \hsize\headwidth
+ \fi
+ \ifx\headnumberwidth\empty\else
+ \let\numberheaddistance\!!zeropoint
+ \fi
+ \setbox\scratchbox\hbox \ifx\headnumberwidth\empty\else to \headnumberwidth\fi{{#1}}%
+ \scratchdimen\dimexpr\wd\scratchbox+\numberheaddistance\relax
+ \ifx\headtextwidth\empty\else
+ \hsize\dimexpr\scratchdimen+\headparameter\c!textwidth\relax
+ \fi
+ \hangindent\scratchdimen
+ \hangafter \plusone
+ \noindent
+ \box\scratchbox\hskip\numberheaddistance
+ \else
+ \ifx\headtextwidth\empty
+ \ifx\headwidth\empty
+ \else
+ \hsize\headwidth
+ \fi
+ \else
+ \hsize\headtextwidth
+ \fi
+ \noindent
+ \fi
+ #2}}
+
+\def\placeheadmargin#1#2%
+ {\vbox
+ {\localheadsetup
+ \begstrut % use one \strut here!
+ \dontleavehmode % in case there is no strut, else side effects with llap
+ \ifconditional\structureheadshownumber % \ifheadnumbercontent
+ \llap{\hbox to 5em{\hfill{#1}\hskip\localheadskip\hskip\leftmargindistance}}% introduces whitespace
+ % maybe better:
+ % \inleftmargin{\hbox{\hss{#1}\hskip\localheadskip}}%
+ \fi
+ {#2}}}
+
+\defineheadplacement[\v!inmargin][\v!vertical]#1#2{\placeheadmargin{#1}{#2}}
+\defineheadplacement[\v!margin] [\v!vertical]#1#2{\placeheadmargin{#1}{#2}}
+
+\defineheadplacement[\v!middle][\v!vertical]#1#2%
+ {\vbox
+ {\localheadsetup
+ \veryraggedcenter
+ \let\\\endgraf
+ \let\crlf\endgraf
+ \ifconditional\structureheadshownumber % \ifheadnumbercontent
+ \strut#1\par
+ \fi
+ \begstrut#2}}
+
+\defineheadplacement[\v!text][\v!horizontal]#1#2%
+ {\bgroup
+ \localheadsetup % no stretch in distance
+ \ifconditional\structureheadshownumber % \ifheadnumbercontent
+ {#1}\kern\numberheaddistance
+ \fi
+ {\begstrut#2}%
+ \egroup}
+
+\def\placeheadlohi#1#2#3%
+ {\ifconditional\structureheadshownumber % \ifheadnumbercontent
+ \setbox0\hbox{#2}
+ \setbox2=#1{\localheadsetup\advance\hsize-\wd0\relax#3}%
+ \hbox{\box0\hskip\numberheaddistance\box2}%
+ \else
+ #1{\localheadsetup\noindent#3}%
+ \fi}
+
+% onder/boven lijnt het nummer op de onderste/bovenste regel
+% uit van een meerregelige kop
+
+\defineheadplacement[\v!bottom][\v!vertical]#1#2{\placeheadlohi\vbox{#1}{#2}}
+\defineheadplacement[\v!top] [\v!vertical]#1#2{\placeheadlohi\vtop{#1}{#2}}
+
+\protect \endinput
diff --git a/tex/context/base/strc-sbe.tex b/tex/context/base/strc-sbe.tex
new file mode 100644
index 000000000..de7c2af63
--- /dev/null
+++ b/tex/context/base/strc-sbe.tex
@@ -0,0 +1,137 @@
+%D \module
+%D [ file=strc-sbe,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Section Block Environments,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Section Block Environments}
+
+\unprotect
+
+% \def\ChapterEntry#1#2#3%
+% {chapter : \hbox to \hsize{\strut\bf#2\hss#3}\endgraf\placelist[section]}
+%
+% \startfrontmatter % optional
+% \placelist[chapter][alternative=command,command=\ChapterEntry,criterium=text] \page
+% \stopfrontmatter % optional
+%
+% \startbodymatter % optional
+% \chapter{first} \section{one} test \section{two} test \page
+% \chapter{second} \section{alpha} test \section{beta} test \page
+% \stopbodymatter % optional
+
+\definesystemvariable {nb}
+
+\def\v!structureblockenvironment{structureblockenvironment}
+
+\def\definestructureblock{\dotripleargument\dodefinestructureblock}
+\def\setupstructureblock {\dodoubleargument\dosetupstructureblock}
+\def\setstructureblock {\dosingleargument\dosetstructureblock}
+
+% \def\structureblockparameter#1{\executeifdefined{\??nb\currentstructureblock#1}\empty}
+
+\def\structureblockparameter#1%
+ {\csname
+ \ifcsname\??nb\currentstructureblock#1\endcsname\??nb\currentstructureblock#1\else\s!empty\fi
+ \endcsname}
+
+\newtoks \everybeforestructureblock
+\newtoks \everyafterstructureblock
+
+\def\dodefinestructureblock[#1][#2][#3]% singular plural settings
+ {\getparameters
+ [\??nb#1]
+ [\c!number=\v!yes,
+ \c!page=\v!right, % anders worden marks te vroeg gereset !
+ #3]%
+ \expandafter\newif\csname if#2\endcsname % better a mode
+ \setstructureblockenvironment{#1}\empty
+ \setvalue {\e!start#2}{\startstructureblock[#1]}%
+ \setvalue {\e!stop #2}{\stopstructureblock}}
+
+\appendtoks
+ \doifsomething{\structureblockparameter\c!page}{\page[\structureblockparameter\c!page]}%
+% TODO \resetsectionmarks\zerosection
+ \getstructureblockenvironment\currentstructureblock
+ \structureblockparameter\c!before % don't move
+\to \everybeforestructureblock
+
+\appendtoks
+ \structureblockparameter\c!after % don't move
+ \doifsomething{\structureblockparameter\c!page}{\page[\structureblockparameter\c!page]}%
+% TODO \resetsectionmarks\zerosection
+\to \everyafterstructureblock
+
+\def\dosetupstructureblock[#1]%
+ {\getparameters[\??nb#1]}% [#2]
+
+\def\dosetstructureblock[#1]% used to set the default
+ {\edef\currentstructureblock{\ctxlua{structure.sections.setblock("#1")}}}
+
+\let\currentstructureblock\s!unknown
+
+\def\startstructureblock[#1]%
+ {\begingroup
+ \edef\currentstructureblock{\ctxlua{structure.sections.pushblock("#1")}}%
+ \csname #1true\endcsname % for old times sake
+ \setsystemmode\currentstructureblock
+ \the\everybeforestructureblock\relax
+ \showmessage\m!structures1\currentstructureblock}
+
+\def\stopstructureblock
+ {\showmessage\m!structures2\currentstructureblock
+ \the\everyafterstructureblock\relax
+ \edef\currentstructureblock{\ctxlua{structure.sections.popblock()}}%
+ \endgroup}
+
+\long\def\setstructureblockenvironment#1#2%
+ {\long\setvalue{\??nb\s!do#1}{\do{#2}}}
+
+\def\getstructureblockenvironment#1%
+ {\let\do\firstofoneargument
+ \structureblockparameter{\s!do#1}}
+
+%D \starttyping
+%D \startsectionblockenvironment[frontpart]
+%D \setuppagenumbering[conversion=romannumerals]
+%D \stopsectionblockenvironment
+%D
+%D \startsectionblockenvironment[bodypart]
+%D \setuppagenumber[number=1]
+%D \stopsectionblockenvironment
+%D
+%D \startsectionblockenvironment[frontpart]
+%D \setuppagenumbering[conversion=character]
+%D \stopsectionblockenvironment
+%D
+%D \starttext
+%D \startfrontmatter \chapter{test} \stopfrontmatter
+%D \startbodymatter \chapter{test} \stopbodymatter
+%D \startappendices \chapter{test} \stopappendices
+%D \stoptext
+%D \stoptyping
+
+\setvalue{\e!start\v!structureblockenvironment}%
+ {\dosingleargument\dostartstructureblockenvironment}
+
+\def\dostartstructureblockenvironment[#1]% evt \pushendofline \popendofline
+ {\long\def\do##1##2{\setstructureblockenvironment{#1}{##1##2}}%
+ \grabuntil{\e!stop\v!structureblockenvironment}{\structureblockparameter{\s!do#1}}}
+
+% this will become: (we ran in parallel for a while during transition)
+
+\setvalue{\e!start\v!sectionblockenvironment}%
+ {\dosingleargument\dostartsectionblockenvironment}
+
+\def\dostartsectionblockenvironment[#1]% evt \pushendofline \popendofline
+ {\long\def\do##1##2{\setstructureblockenvironment{#1}{##1##2}}%
+ \grabuntil{\e!stop\v!sectionblockenvironment}{\structureblockparameter{\s!do#1}}}
+
+\protect \endinput
diff --git a/tex/context/base/strc-sec.tex b/tex/context/base/strc-sec.tex
new file mode 100644
index 000000000..a45564c43
--- /dev/null
+++ b/tex/context/base/strc-sec.tex
@@ -0,0 +1,667 @@
+%D \module
+%D [ file=strc-sec,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Sectioning,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Sectioning}
+
+\unprotect
+
+% compatibility issue:
+%
+% \def\setfullsectionnumber #1{}
+% \def\preparefullnumber #1{}
+% \def\fullsectionnumber {1--1--1}
+% \def\makesectionnumber [#1]{}
+% \def\makesectionformat {}
+% \def\sectionformat {1--1-1-1-1-1-1}
+% \def\composedsectionnumber{}
+% \def\@@kolist{}
+
+% \setuphead[section] [separator=\separatorlist{?,!,*}]
+% \setuphead[subsection][separator=\separatorlist{??,!!,**}]
+%
+% \let\spr\separatorlist % this will enable this feature
+%
+% \setuphead[section] [separator={?,!,*}]
+% \setuphead[subsection][separator={??,!!,**}]
+%
+% \setupheads[separator={A,B,C,D,E,F}]
+% \chapter{test}
+% \section{test} \subsection{test} \subsection{test}
+% \section{test} \subsection{test} \subsection{test}
+
+% lua interface
+
+\def\setstructurelevel #1#2{\ctxlua{structure.sections.setlevel("#1","#2")}} % name, level|parent
+\def\getstructurelevel #1{\ctxlua{structure.sections.getcurrentlevel("#1")}}% name
+\def\setstructurenumber #1#2{\ctxlua{structure.sections.setnumber(#1,"#2")}} % level, number (+/-)
+\def\getstructurenumber #1{\ctxlua{structure.sections.getnumber(#1)}} % level
+\def\getfullstructurenumber#1{\ctxlua{structure.sections.fullnumber(#1)}} % level
+
+% interface
+
+\def\structureheadparameter #1{\csname\dostructureheadparameter{\??nh\currentstructurehead}#1\endcsname}
+\def\structureheadparameterhash#1{\dostructureheadparameterhash {\??nh\currentstructurehead}#1}
+
+\def\dostructureheadparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dostructureheadparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dostructureheadparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dostructureheadparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dostructureheadparentparameter #1#2{\ifx#1\relax\s!empty\else\dostructureheadparameter #1#2\fi}
+\def\dostructureheadparentparameterhash#1#2{\ifx#1\relax \else\dostructureheadparameterhash#1#2\fi}
+
+\def\dosetstructureheadattributes#1#2% style color
+ {\edef\fontattributehash {\structureheadparameterhash#1}%
+ \edef\colorattributehash{\structureheadparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+% so far
+
+\newcount\maxstructuredepth
+
+\let\laststructuresectionname\empty
+
+\def\definestructuresection[#1]%
+ {\doifundefined{\??nh#1}
+ {\global\advance\maxstructuredepth\plusone
+ \setevalue{\??nh#1\c!level}{\the\maxstructuredepth}%
+ \setstructurelevel{#1}{\the\maxstructuredepth}%
+% \letvalue{\??nh#1\c!marking}\empty % ?
+ %\writestatus{structure}{#1\ifx\laststructuresectionname\empty\else\space->\space\laststructuresectionname\fi}%
+ \normalexpanded{\noexpand\getparameters[\??nh#1][\s!parent=\??nh\laststructuresectionname]}%
+ \definemarking[#1]%
+ \ifnum\maxstructuredepth>\plusone
+% \normalexpanded{\noexpand\couplemarking[#1][\laststructuresectionname]}% so, the child inherits settings from the parent
+ \normalexpanded{\noexpand\relatemarking[#1][\laststructuresectionname]}% so, the parent will reset the child
+ \fi
+ \xdef\laststructuresectionname{#1}}}
+
+\def\setupstructuresection
+ {\dotripleempty\dosetupstructuresection}
+
+\def\dosetupstructuresection[#1]%
+ {\doifdefinedelse{\??nh#1}
+ {\dodosetupstructuresection[#1]}
+ {\dodosetupstructuresection[\structuresectionheadsection{#1}]}}
+
+\def\dodosetupstructuresection[#1][#2][#3]%
+ {\ifthirdargument
+ \getparameters[\??nh#1#2][#3]% ? probably sectionblock
+ \else
+ \getparameters[\??nh#1][#2]%
+ \fi}
+
+\def\structuresectionlevel#1%
+ {\executeifdefined{\??nh#1\c!level}0}
+
+% head -> structurehead
+
+\let\currentstructurehead\empty
+\newtoks\everystructureheadsetup
+
+\def\setupstructureheads{\dosingleargument\dosetupstructureheads}
+\def\setupstructurehead {\dodoubleempty\dosetupstructurehead}
+\def\definestructurehead{\dodoubleempty\dodefinestructurehead}
+
+\newif\ifsectionnumber % maybe conditional
+
+\def\dosetupstructureheads[#1]%
+ {\getparameters[\??nh][#1]%
+ \doifelse{\structureheadparameter\c!sectionnumber}\v!yes\sectionnumbertrue\sectionnumberfalse}
+
+\def\dosetupstructurehead[#1][#2]% we move the test for command being nothing elsewhere (needed, else hard to trace)
+ {\processcommalist[#1]{\dodosetupstructurehead{#2}}}
+
+\def\dodosetupstructurehead#1#2%
+ {\getparameters[\??nh#2][#1]%
+ \the\everystructureheadsetup}
+
+\def\dodefinestructurehead[#1][#2]%
+ {\processcommalist[#1]{\dododefinestructurehead{#2}}}
+
+\def\dododefinestructurehead#1#2% #1: parameters|parent, #2: self
+ {\doifsomethingelse{#2}
+ {\doifassignmentelse{#1}
+ \dodefineuniquestructurehead
+ {\doifdefinedelse{\??nh#1\s!parent} % just a check
+ \dodefineclonedstructurehead
+ \dodefineerrorstructurehead}}
+ \dodefineerrorstructurehead
+ {#2}{#1}}
+
+\def\dodefineerrorstructurehead#1#2%
+ {\setvalue{#1}{\par error: #1 is undefined\par}}
+
+% deeptextcommand and deepnumbercommand are left undefined !
+
+\def\dodefineuniquestructurehead#1#2% class, parameters
+ {\def\currentstructurehead{#1}%
+ \presetlabeltext[#1=]%
+ \getparameters[\??nh#1][\c!label=#1,#2]%
+ \edef\currentstructureheaddefault{\structureheadparameter\c!default}%
+ \edef\currentstructureheadsection{\structureheadparameter\c!section}%
+ \edef\currentstructureheadparent
+ {\??nh
+ \ifx\currentstructurehead\currentstructureheaddefault
+ \currentstructureheadsection
+ \else\ifx\currentstructureheaddefault\empty
+ \currentstructureheadsection
+ \else
+ \currentstructureheaddefault
+ \fi\fi}%
+ \normalexpanded{\noexpand\getparameters[\??nh#1][\s!parent=\currentstructureheadparent]}% \setevalue{\??nh#1\s!parent}{\currentstructureheadparent}%
+ \ifx\currentstructureheadsection\empty
+ %\writestatus{structure}{#1->\currentstructureheadparent}%
+ \else
+ %\writestatus{structure}{#1->\currentstructureheadparent\space(\currentstructureheadsection)}%
+ % todo: filtercommand
+ \definemarking[#1][\currentstructureheadsection]%
+ \definemarking[#1\v!number][#1]%
+ \setupmarking[#1][\c!filtercommand=\sectionheadmarkingtitle{#1}]%
+ \setupmarking[#1\c!number][\c!filtercommand=\sectionheadmarkingnumber{#1}]%
+ \fi
+ \doifundefined{\??li#1}{\definelist[#1][\c!prefix=\v!no]}% definestructurelist ?
+ \the\everystructureheadsetup}
+
+\def\sectionheadmarkingtitle #1#2{\ctxlua{structure.marks.title("#1","#2")}}
+\def\sectionheadmarkingnumber#1#2{\ctxlua{structure.marks.number("#1","#2")}}
+
+\def\dodefineclonedstructurehead#1#2% class parent
+ {\def\currentstructurehead{#1}%
+ \presetlabeltext[#1=]%
+ \doifelse{#1}{#2}
+ {\getparameters[\??nh#1][\c!label=#1]%
+ \doifundefined{\??li#1}{\definelist[#1][\c!prefix=\v!no]}}% definestructurelist ?
+ {\getparameters[\??nh#1][\s!parent=\??nh#2,\c!label=#1]%
+ \definemarking[#1][#2]%
+ \definemarking[#1\v!number][#2\c!number]%
+ \doifundefined{\??li#1}{\definelist[#1][#2][\c!prefix=\v!no]}}% definestructurelist ?
+ \the\everystructureheadsetup}
+
+\appendtoks
+ \setstructurelevel\currentstructurehead{\structuresectionheadsection{\structuresectionheadcoupling\currentstructurehead}}%
+ \doifelse{\structureheadparameter\c!ownnumber}\v!yes
+ {\setevalue\currentstructurehead{\noexpand\dohandlestructureheadown[\currentstructurehead]}}
+ {\setevalue\currentstructurehead{\noexpand\dohandlestructureheadnop[\currentstructurehead]}}%
+ \setevalue{\e!start\currentstructurehead}{\noexpand\dostartstructurehead[\currentstructurehead]}%
+ \setevalue{\e!stop\currentstructurehead }{\noexpand\dostopstructurehead[\currentstructurehead]}%
+\to \everystructureheadsetup
+
+% todo, check if section is defined
+
+\def\structuresectionheadcoupling#1%
+ {\ifcsname\??nh#1\c!coupling\endcsname
+ \expandafter\structuresectionheadcoupling\csname\??nh#1\c!coupling\endcsname\else#1%
+ \fi}
+
+\def\structuresectionheadsection#1%
+ {\ifcsname\??nh#1\c!section\endcsname
+ \expandafter\structuresectionheadcoupling\csname\??nh#1\c!section\endcsname\else#1%
+ \fi}
+
+% head construction
+
+\def\dohandlestructureheadown{\dodoubleempty\dodohandlestructureheadown} % [ref] {nr} {title}
+\def\dohandlestructureheadnop{\dodoubleempty\dodohandlestructureheadnop} % [ref] {title}
+\def\dostartstructurehead {\dotripleempty\dodostartstructurehead} % [settings] [userdata]
+
+\newconditional\currentstructureown
+
+\def\dodohandlestructureheadown[#1][#2]#3#4%
+ {\settrue\currentstructureown
+ \dohandlestructurehead{#1}{\c!reference=#2,\c!ownnumber={#3},\c!title={#4}}{}} % name ref nr title --
+
+\def\dodohandlestructureheadnop[#1][#2]#3%
+ {\setfalse\currentstructureown
+ \dohandlestructurehead{#1}{\c!reference=#2,\c!title={#3}}{}} % name ref nr title --
+
+\newtoks\everybeforestructurehead % hook, todo: before/after keys
+\newtoks\everyafterstructurehead % hook, todo: before/after keys
+
+\def\dodostartstructurehead[#1][#2][#3]% for the moment no grouping, too annoying with page breaks
+ {\setfalse\currentstructureown
+ \globalpushmacro\currentstructurehead
+ \xdef\currentstructurehead{#1}%
+ \the\everybeforestructurehead
+ \dohandlestructurehead{#1}{#2}{#3}} % name -- -- -- userdata
+
+\def\dostopstructurehead[#1]%
+ {\globalpopmacro\currentstructurehead
+ \doifnot{#1}\currentstructurehead{\writestatus\m!systems{missing \letterbackslash\e!stop#1}}%
+ \xdef\currentstructurehead{#1}% recover
+ \the\everyafterstructurehead}
+
+% \newconditional\structurereversesectionnumbers % todo: key/val
+
+\newconditional\structureheadtolist
+\newconditional\structureheaddoincrement
+\newconditional\structureheaddoplace
+\newconditional\structureheadleaveempty
+\newconditional\structureheadshownumber
+\newconditional\structureheadisdisplay
+
+\let\structureheadprefix\empty \def\structureheadprefixplus{+}
+
+% When do we reset the referenceprefix? This needs to be checked. Does it work
+% at all?
+
+\def\setstructureheadreference#1% reference
+ {\edef\structureheadreference{#1}%
+ \edef\structureheadreferenceprefix{\structureheadparameter\c!prefix}%
+ \ifx\structureheadreferenceprefix\empty
+ \setupreferenceprefix[]% yes or no?
+ \else\ifx\structureheadreferenceprefix\structureheadreferenceprefixplus
+ \ifx\structureheadreference\empty
+ \setupreferenceprefix[\structureheadreferenceprefixplus]
+ \else
+ \setupreferenceprefix[#1]% we assume just one reference
+ \fi
+ \else
+ \setupreferenceprefix[\structureheadreferenceprefix]%
+ \fi\fi}
+
+\setvalue{\??nh:\c!incrementnumber:\v!yes }{\settrue \structureheaddoincrement\settrue \structureheadtolist}
+\setvalue{\??nh:\c!incrementnumber:\v!no }{\setfalse\structureheaddoincrement\setfalse\structureheadtolist}
+\setvalue{\??nh:\c!incrementnumber:\v!list }{\setfalse\structureheaddoincrement\settrue \structureheadtolist}
+\setvalue{\??nh:\c!incrementnumber:\s!empty}{\settrue \structureheaddoincrement\settrue \structureheadtolist}
+
+\def\setstructureheadincrement
+ {\edef\currentstructureheadincrement{\structureheadparameter\c!incrementnumber}%
+ \ifcsname\??nh:\c!incrementnumber:\currentstructureheadincrement\endcsname
+ \csname\??nh:\c!incrementnumber:\currentstructureheadincrement\endcsname
+ \else
+ \settrue \structureheaddoincrement\settrue \structureheadtolist
+ % \filterstructureheadnumber
+ \fi}
+
+\def\filterstructureheadnumber
+ {\settrue\structureheaddoincrement
+ \settrue\structureheadtolist
+ \ifx\currentproduct\empty
+ % todo : filter from other toc (number, file, title)
+ % use : \currentstructureheadincrement as spec
+ \fi}
+
+\def\setstructureheadplacement
+ {\settrue\structureheaddoplace
+ \setfalse\structureheadleaveempty
+ \processaction
+ [\structureheadparameter\c!placehead]
+ [ \v!yes=>,
+ \v!empty=>\settrue\structureheadleaveempty,
+ \v!no=>\settrue\structureheadleaveempty\setfalse\structureheaddoplace]}
+
+\def\setstructureheadreset % todo, also set resetset here
+ {\doifelse{\structureheadparameter\c!resetnumber}\v!no
+ {\setfalse\@@resetsubheadnumbers}%
+ {\settrue \@@resetsubheadnumbers}}
+
+\def\setstructureheaddisplay
+ {\doifelsevalue{\??nh:\structureheadparameter\c!alternative}\v!horizontal
+ {\setfalse\structureheadisdisplay}
+ {\settrue \structureheadisdisplay}}
+
+\def\dosettructureheadnumbercontent
+ {\setsystemmode \v!sectionnumber
+ \settrue\structureheadshownumber}
+
+\def\doresettructureheadnumbercontent
+ {\resetsystemmode\v!sectionnumber
+ \setfalse\structureheadshownumber}
+
+\def\setstructureheadnumber
+ {\ifsectionnumber
+ \doifelse{\structureblockparameter\c!number}\v!yes % todo
+ {\doifelse{\structureheadparameter\c!number}\v!yes
+ {\settrue\structureheadshownumber}
+ {\setfalse\structureheadshownumber}}
+ {\setfalse\structureheadshownumber}%
+ \else
+ \setfalse\structureheadshownumber
+ \fi}
+
+% \defconvertexpanded\asciititle{\getvalue{\??ko#1\c!expansion}}{#4}%
+
+% \unexpanded\def\\{\space}
+
+\def\thestructureheadsynchonization
+ {\pagetype[\currentstructureheadcoupling]% hm also number
+ \normalexpanded{\noexpand\setmarking[\currentstructureheadcoupling]{\currentstructurelistnumber}}%
+ \currentstructuresynchronize}
+
+\def\thestructureheadnumber{\labeltexts{\structureheadparameter\c!label}{\structurenumber}}
+\def\thestructureheadtitle {\structurecctvalue{titledata.title}}
+
+\let\currentstructurehead \empty
+\let\currentstructureheadcoupling\empty
+\let\currentstructureheadsection \empty
+\let\currentstructureheadlevel \!!zerocount
+\let\currentstructureheadcounter \!!zerocount
+
+\def\doregisterstructurehead#1#2#3% name data userdata
+ {\structurecomponent
+ [\c!label={\structureheadparameter\c!label},
+ \c!incrementnumber=\ifconditional\structureheaddoincrement\v!yes\else\v!no\fi, % not that needed
+ \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!bookmark=,
+ \c!expansion=\structureheadparameter\c!expansion,
+ \c!reset=\structureheadparameter\c!reset,
+ \c!sectionseparatorset=\structureheadparameter\c!sectionseparatorset,
+ \c!sectionconversionset=\structureheadparameter\c!sectionconversionset,
+ \c!sectionconversion=\structureheadparameter\c!conversion, % just for compatibility
+ \c!sectionstopper=\structureheadparameter\c!sectionstopper,
+ \c!sectionset=\structureheadparameter\c!sectionset,
+ \c!sectionsegments=\structureheadparameter\c!sectionsegments,
+ \c!reference=\structureheadreference,
+ \c!referenceprefix=\structureheadreferenceprefix,
+ \c!command=,
+ #2]%
+ [#3]%
+ \reportcurrentstructure}
+
+\unexpanded\def\placeheadtext {\doquintupleempty\doplaceheadtextornumber[\c!textstyle] [\c!textcolor] [\empty]}
+\unexpanded\def\placeheadnumber{\doquintupleempty\doplaceheadtextornumber[\c!numberstyle][\c!numbercolor][\v!number]}
+
+\def\doplaceheadtextornumber[#1][#2][#3][#4][#5]%
+ {\dontleavehmode
+ \begingroup
+ \xdef\currentstructurehead {\iffifthargument#5\else#4\fi}%
+ \xdef\currentstructureheadcoupling{\structuresectionheadcoupling\currentstructurehead}%
+ \xdef\currentstructureheadsection {\structuresectionheadsection \currentstructureheadcoupling}%
+ \xdef\currentstructureheadlevel {\structuresectionlevel \currentstructureheadsection}%
+ \dosetstructureheadattributes\c!style\c!color
+ \dosetstructureheadattributes#1#2%
+ \dontconvertfont
+ \setupinterlinespace
+ % temp hack most be fixed (see s-pre-61)
+ % \begstrut\getmarking[#4#3]\endstrut
+ \doifelse{#3}\v!number\currentheadnumber\currentheadtext
+ \endgraf
+ \endgroup}
+
+\def\dohandlestructurehead#1#2#3% name data userdata
+ {\xdef\currentstructurehead {#1}%
+ \xdef\currentstructureheadcoupling{\structuresectionheadcoupling\currentstructurehead}%
+ \xdef\currentstructureheadsection {\structuresectionheadsection \currentstructureheadcoupling}%
+ \xdef\currentstructureheadlevel {\structuresectionlevel \currentstructureheadsection}%
+ %writestatus\m!systems{setup: \currentstructurehead,\currentstructureheadcoupling,\currentstructureheadsection,\currentstructureheadlevel}%
+ %
+ \setstructureheadreference{#3}% will change
+ \setstructureheadincrement
+ \setstructureheadplacement
+ \setstructureheadreset
+ \setstructureheaddisplay
+ \setstructureheadnumber
+ %
+ \unexpanded\def\\{\space}%
+ \flushingcolumnfloatsfalse
+ %
+ % todo: also mark (for header)
+ %
+ % we might remove the lower level
+ %
+ % not here, after optional \page: \doregisterstructurehead{#1}{#2}{#3}%
+ %
+% \xdef\currentstructureheadcounter{\currentstructurecounter}% lua call
+ %
+ % \currentstructuresynchronize % will move
+ %
+ \edef\numberheaddistance {\structureheadparameter\c!distance }% compatibility
+ \edef\numberheadalternative{\structureheadparameter\c!alternative}% compatibility
+ %
+ \let\getstructureheadnumber\empty
+ \let\getstructureheadtitle \empty
+ \let\getstructureheadsyncs \empty
+ \ifconditional\structureheaddoincrement
+ \ifconditional\structureheaddoplace
+ \dostructureheadspacingbeforeyes
+ \doregisterstructurehead{#1}{#2}{#3}% after optional \page
+ \let\getstructureheadsyncs\thestructureheadsynchonization
+ \let\getstructureheadtitle\thestructureheadtitle
+ \ifconditional\structureheadshownumber
+ \let\getstructureheadnumber\thestructureheadnumber
+ \placestructureheadnumbertext
+ \else
+ \placestructureheadtext
+ \fi
+ \dostructureheadspacingafteryes
+ \else
+ \dostructureheadspacingbeforenop % toegevoegd ivm subpaginanr / tug sheets
+ \doregisterstructurehead{#1}{#2}{#3}% after optional \page
+ \let\getstructureheadsyncs\thestructureheadsynchonization
+ \placestructureheadnothing % just flush 'm
+ \dostructureheadspacingafternop
+ \fi
+ \else
+ \ifconditional\structureheaddoplace
+ \dostructureheadspacingbeforeyes
+ \doregisterstructurehead{#1}{#2}{#3}% after optional \page
+ \let\getstructureheadtitle\thestructureheadtitle
+ \let\getstructureheadsyncs\thestructureheadsynchonization
+ \placestructureheadtext
+ \dostructureheadspacingafteryes
+ \else
+ % do nothing / should be vbox to 0pt
+ \dostructureheadspacingbeforenop
+ \doregisterstructurehead{#1}{#2}{#3}% after optional \page
+ \let\getstructureheadsyncs\thestructureheadsynchonization
+ \placestructureheadnothing % just flush 'm
+ \dostructureheadspacingafternop
+ \fi
+ \fi
+ \flushingcolumnfloatstrue
+ \setfalse\ignorehandlepagebreak
+ % ignorespaces prevents spaces creeping in when after=\dontleavehmode
+ \ifconditional\structureheadisdisplay % \ifdisplaysectionhead
+ \ignorespaces
+ \else
+ \expandafter\GotoPar
+ \fi}
+
+% typesetting
+
+\def\placestructureheadnumbertext
+ {\getstructureheadnumber/\getstructureheadtitle
+ \getstructureheadsyncs}
+
+\def\placestructureheadtext
+ {\getstructureheadtitle
+ \getstructureheadsyncs}
+
+\def\placestructureheadnothing
+ {\getstructureheadsyncs}
+
+% pagebreaks
+
+\newcount\precedingstructurelevel \precedingstructurelevel\plusone
+\newconditional\ignorehandlepagebreak
+
+\def\dostructureheadspacingbeforeyes
+ {\docheckstructureheadbefore\dohandlestructureheadpagebreak
+ \structureheadparameter\c!inbetween}
+
+\def\dostructureheadspacingbeforenop
+ {\docheckstructureheadbefore\docheckstructureheadlayout
+ \structureheadparameter\c!inbetween}
+
+\def\dostructureheadspacingafteryes
+ {\ifconditional\structureheadisdisplay
+ \dosomebreak\nobreak
+ \ifconditional\structureheadleaveempty % inlined \emptyheadcorrection (with after=\blank)
+ \vskip-\lineheight
+ \dosomebreak\nobreak
+ \kern\zeropoint
+ \prevdepth\strutdepth
+ \fi
+ \structureheadparameter\c!after
+ \fi}
+
+\def\dostructureheadspacingafternop
+ {}
+
+\newsignal\continuousstructureheadsignal
+
+\def\docheckstructureheadbefore#1%
+ {\ifhmode
+ \scratchcounter\lastpenalty\unpenalty % no beauty in this
+ \ifdim\lastskip=\continuousstructureheadsignal
+ % no page break
+ \ifconditional\ignorehandlepagebreak
+ \setfalse\ignorehandlepagebreak
+ \else
+ \global\precedingstructurelevel\currentstructureheadlevel
+ \nobreak
+ \fi
+ \global\settrue\continuoussectionhead
+ \else
+ \penalty\scratchcounter
+ \global\setfalse\continuoussectionhead
+ #1%
+ \fi
+ \else
+ \global\setfalse\continuoussectionhead
+ #1%
+ \fi}
+
+\def\dodocheckstructureheadlayout#1#2%
+ {\doifelselayouttextline{#1}
+ {\doifsomething{\structureheadparameter#2}{\expanded{\setuplayouttext[#1][\c!state=\structureheadparameter#2]}}}
+ \donothing}
+
+\def\docheckstructureheadlayout
+ {\doifsomething{\structureheadparameter\c!page}
+ {\page[\structureheadparameter\c!page]%
+ \dodocheckstructureheadlayout\v!header\c!header
+ \dodocheckstructureheadlayout\v!text \c!text
+ \dodocheckstructureheadlayout\v!footer\c!footer}}
+
+\def\currentstructurecounter {\ctxlua{structure.sections.depthnumber(\thenamedstructureheadlevel\currentstructurehead)}}
+\def\previousstructurecounter{\ctxlua{structure.sections.depthnumber(\thenamedstructureheadlevel\currentstructurehead-1)}}
+
+\def\dohandlestructureheadpagebreak
+ {%[[\currentstructurehead @\thenamedstructureheadlevel\currentstructurehead/prev:\previousstructurecounter/curr:\currentstructurecounter]]
+ \ifconditional\ignorehandlepagebreak
+ \setfalse\ignorehandlepagebreak
+ \else
+ \ifnum\lastpenalty>\zerocount
+ \global\pagebreakdisabledtrue
+ \fi
+ % beware, these numbers are not yet know here
+ \doifelse{\structureheadparameter\c!continue}\v!yes
+ {\ifnum\previousstructurecounter=\zerocount
+ \docheckstructureheadlayout
+ \else\ifnum\currentstructurecounter>\zerocount
+ \docheckstructureheadlayout
+ \fi\fi}%
+ {\docheckstructureheadlayout}%
+ \doifnot{\structureheadparameter\c!aligntitle}\v!float\flushsidefloats
+ \structureheadparameter\c!before
+ \relax
+ \ifpagebreakdisabled
+ \global\pagebreakdisabledfalse
+ \else
+ \dopreventbreakafterstructureheadauto
+ \fi
+ \doif{\structureheadparameter\c!aligntitle}\v!float\indent
+ \global\precedingstructurelevel\currentstructureheadlevel
+ \fi}
+
+% the next one was: \somebreakmethod
+
+\chardef\somestructureheadbreakmethod\plusone % 0=nothing, 1=weighted, 2=strict, 3=vspacing
+
+\def\dopreventbreakafterstructureheadauto % used after \c!before
+ {\ifcase\somestructureheadbreakmethod
+ % 0 = nothing
+ \or
+ % 1 = old weighted version
+ \ifnum\currentstructureheadlevel>\precedingstructurelevel
+ \dosomebreak{\penalty\numexpr20000+500*\currentstructureheadlevel\relax}%
+ \else
+ \dosomebreak\allowbreak % brr
+ \fi
+ \or
+ % 2 = strict version
+ \dosomebreak{\penalty\maxdimen}%
+ \or
+ % 3 = vspacing
+ \vspacing[\v!samepage]% if preceded by ! then a loop
+ \else
+ % nothing
+ \fi}
+
+\def\dopreventbreakafterstructureheadspec#1% see enumerations etc
+ {\ifcase\somestructureheadbreakmethod
+ % 0 = nothing
+ \or
+ % 1 = old weighted version
+ \dosomebreak{\penalty\numexpr20000+500*(\currentstructureheadlevel+#1)\relax}%
+ \or
+ % 2 = strict version
+ \dosomebreak{\penalty\maxdimen}%
+ \or
+ % 3 = vspacing
+ \vspacing[\v!samepage]%
+ \else
+ % nothing
+ \fi}
+
+\def\dohandlepagebreakX{\dopreventbreakafterstructureheadspec} % no \let so we can redefind
+
+% todo:
+
+\def\thecurrentstructureheadlevel#1%
+ {\getstructurelevel{#1}}
+
+\def\thenamedstructureheadlevel#1%
+ {\structuresectionlevel{\structuresectionheadsection{\structuresectionheadcoupling{#1}}}}
+
+\def\setupheadnumber
+ {\dodoubleargument\dosetupheadnumber}
+
+\def\dosetupheadnumber[#1][#2]% todo: reset if at other level
+ {\setstructurenumber{\thecurrentstructureheadlevel{#1}}{#2}}
+
+\def\currentstructureheadnumber{0} % ==> \currentheadnumber
+
+\def\determineheadnumber[#1]%
+ {\xdef\currentstructureheadnumber{\getstructurenumber{\thecurrentstructureheadlevel{#1}}}}
+
+\def\structureheadnumber
+ {\dosingleempty\dostructureheadnumber}
+
+\def\dostructureheadnumber[#1]% simple case is just a number
+ {\getfullstructurenumber{\iffirstargument\thecurrentstructureheadlevel{#1}\fi}}
+
+% compatibility code (after all, we might offer different structure handlers as well
+
+\let\definesectionblock \definestructureblock
+\let\definesection \definestructuresection
+\let\setupsection \setupstructuresection
+\let\setupheads \setupstructureheads
+\let\definehead \definestructurehead
+\let\setuphead \setupstructurehead
+\let\headnumber \structureheadnumber
+\let\setupsectionblock \setupstructureblock
+\let\currentheadnumber \thestructureheadnumber
+\let\currentheadtext \thestructureheadtitle
+\let\sectioncountervalue\structurevalue
+
+% list references, will be redone in lua when we need it
+
+\let\startlistreferences\relax
+\let\stoplistreferences \relax
+
+\protect \endinput
diff --git a/tex/context/base/strc-syn.lua b/tex/context/base/strc-syn.lua
new file mode 100644
index 000000000..00ee2fdc2
--- /dev/null
+++ b/tex/context/base/strc-syn.lua
@@ -0,0 +1,185 @@
+if not modules then modules = { } end modules ['str-syn'] = {
+ version = 1.001,
+ comment = "companion to str-syn.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+local texwrite, texsprint, format = tex.write, tex.sprint, string.format
+
+local ctxcatcodes = tex.ctxcatcodes
+
+-- interface to tex end
+
+joblists = joblists or { }
+joblists.collected = joblists.collected or { }
+joblists.tobesaved = joblists.tobesaved or { }
+
+local collected, tobesaved = joblists.collected, joblists.tobesaved
+
+local function initializer()
+ collected, tobesaved = joblists.collected, joblists.tobesaved
+end
+
+local function finalizer()
+ tobesaved.hash = nil
+end
+
+job.register('joblists.collected', joblists.tobesaved, initializer, finalizer)
+
+local function allocate(class)
+ local d = tobesaved[class]
+ if not d then
+ d = {
+ metadata = {
+ language = 'en',
+ sorted = false,
+ class = class
+ },
+ entries = {
+ },
+ hash = {
+ }
+ }
+ tobesaved[class] = d
+ end
+ return d
+end
+
+function joblists.define(class,kind)
+ local data = allocate(class)
+ data.metadata.kind = kind
+end
+
+function joblists.register(class,kind,spec)
+ local data = allocate(class)
+ data.metadata.kind = kind -- runtime, not saved in format (yet)
+ data.entries[#data.entries+1] = spec
+ data.hash[spec.definition.tag or ""] = spec
+end
+
+function joblists.synonym(class,tag)
+ local data = allocate(class).hash
+ local d = data[tag]
+ if d then
+ local de = d.definition
+ de.used = true
+ texsprint(ctxcatcodes,de.synonym)
+ end
+end
+
+function joblists.meaning(class,tag)
+ local data = allocate(class).hash
+ local d = data[tag]
+ if d then
+ local de = d.definition
+ de.used = true
+ texsprint(ctxcatcodes,de.meaning)
+ end
+end
+
+function joblists.compare(a,b)
+ return sorters.comparers.basic(a.split,b.split)
+end
+
+function joblists.filter(data,options)
+ local result = { }
+ local entries = data.entries
+ local all = options and options.criterium == interfaces.variables.all
+ for i=1,#entries do
+ local entry = entries[i]
+ if all or entry.definition.used then
+ result[#result+1] = entry
+ end
+ end
+ data.result = result
+end
+
+function joblists.prepare(data)
+ local strip = sorters.strip
+ local splitter = sorters.splitters.utf
+ local result = data.result
+ if result then
+ for i=1, #result do
+ local r = result[i]
+ local rd = r.definition
+ if rd then
+ local rt = rd.tag
+ local sortkey = (rt and rt ~= "" and rt) or rd.synonym
+ r.split = splitter(strip(sortkey))
+ end
+ end
+ end
+end
+
+function joblists.sort(data,options)
+ sorters.sort(data.result,joblists.compare)
+end
+
+function joblists.finalize(data,options)
+ local result = data.result
+ data.metadata.nofsorted = #result
+ local split = { }
+ local se = sorters.entries[options.language or sorters.defaultlanguage] or sorters.entries[sorters.defaultlanguage]
+ for k=1,#result do
+ local v = result[k]
+ local entry, tag = v.split[1], ""
+ if se and se[entry] then
+ if type(se[entry]) == "number" then
+ entry = se[entry]
+ end
+ tag = se[entry]
+ else
+ entry = 0
+ tag = "unknown"
+ end
+ local s = split[entry]
+ if not s then
+ s = { tag = tag, data = { } }
+ split[entry] = s
+ end
+ s.data[#s.data+1] = v
+ end
+ data.result = split
+end
+
+function joblists.flush(data,options) -- maybe pass the settings differently
+ local kind = data.metadata.kind -- hack, will be done better
+ texsprint(ctxcatcodes,format("\\start%soutput",kind))
+ local result = data.result
+ for k, letter in ipairs(table.sortedkeys(result)) do
+ local sublist = result[letter]
+ local data = sublist.data
+ texsprint(ctxcatcodes,format("\\start%ssection{%s}",kind,sublist.tag))
+ for d=1,#data do
+ local entry = data[d].definition
+ texsprint(ctxcatcodes,format("\\%sentry{%s}{%s}{%s}",kind,d,entry.synonym,entry.meaning))
+ end
+ texsprint(ctxcatcodes,format("\\stop%ssection",kind))
+ end
+ texsprint(ctxcatcodes,format("\\stop%soutput",kind))
+ -- for now, maybe at some point we will do a multipass or so
+ data.result = nil
+ data.metadata.sorted = false
+end
+
+function joblists.analysed(class,options)
+ local data = joblists.collected[class]
+ if data and data.entries then
+ joblists.filter(data,options) -- filters entries to result
+ joblists.prepare(data,options) -- adds split table parallel to list table
+ joblists.sort(data,options) -- sorts entries in result
+ joblists.finalize(data,options) -- do things with data.entries
+ data.metadata.sorted = true
+ end
+ return data and data.metadata.sorted and data.result and next(data.result)
+end
+
+function joblists.process(class,options)
+ if joblists.analysed(class,options) then
+ joblists.flush(joblists.collected[class],options)
+ end
+end
+
diff --git a/tex/context/base/strc-syn.tex b/tex/context/base/strc-syn.tex
new file mode 100644
index 000000000..a739be902
--- /dev/null
+++ b/tex/context/base/strc-syn.tex
@@ -0,0 +1,392 @@
+%D \module
+%D [ file=strc-syn,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=Synonyms and Sorting,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / Synonyms and Sorting}
+
+\registerctxluafile{strc-syn}{1.001}
+
+\unprotect
+
+% general help, can be shared
+
+% simplifiedcommands -> flag in lua
+%
+% expansion
+% criterium -> when start, then flag in list
+% command-> wanneer?
+% state -> flagging enabled
+% conversion ?
+% todo: register xml mode etc
+
+% split but common in lua
+
+\def\preprocessexpansion#1#2#3#4%
+ {\ifx#1\s!xml
+ \xmlstartraw
+ \xdef#2{#4}%
+ \xmlstopraw
+ \globallet#3\s!xml
+ \else
+ \ifx#1\v!yes
+ \xdef#2{#4}%
+ \else
+ \xdef#2{\detokenize{#4}}%
+ \fi
+ \globallet#3\s!tex
+ \fi}
+
+\let\currentsynonym\empty
+
+\def\synonymparameter #1{\csname\dosynonymparameter{\??sm\currentsynonym}#1\endcsname}
+\def\synonymparameterhash#1{\dosynonymparameterhash {\??sm\currentsynonym}#1}
+
+\def\dosynonymparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dosynonymparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dosynonymparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dosynonymparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dosynonymparentparameter #1#2{\ifx#1\relax\s!empty\else\dosynonymparameter #1#2\fi}
+\def\dosynonymparentparameterhash#1#2{\ifx#1\relax \else\dosynonymparameterhash#1#2\fi}
+
+\def\dosetsynonymattributes#1#2% style color
+ {\edef\fontattributehash {\synonymparameterhash#1}%
+ \edef\colorattributehash{\synonymparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\newtoks\everysetupsynonyms
+
+\def\setupsynonyms
+ {\dodoubleargument\dosetupsynonyms}
+
+\def\dosetupsynonyms[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??sm#1][#2]%
+ \else
+ \getparameters[\??sm][#1]%
+ \fi
+ \the\everysetupsynonyms}
+
+\setupsynonyms
+ [\c!state=\v!start,
+ %\c!synonymstyle=,
+ %\c!textstyle=,
+ %\c!headstyle=,
+ %\c!headcolor=,
+ %\c!criterium=,
+ \c!location=\v!left,
+ \c!width=5em,
+ \c!distance=0pt,
+ %\c!sample=,
+ %\c!hang=,
+ %\c!align=,
+ %\c!before=,
+ %\c!inbetween=,
+ %\c!after=,
+ \c!indentnext=\v!no,
+ %\c!expansion=,
+ \s!language=\currentmainlanguage]
+
+\def\definesynonyms
+ {\doquadrupleempty\dodefinesynonyms}
+
+\def\dodefinesynonyms[#1][#2][#3][#4]% name plural \meaning \use
+ {\iffourthargument
+ \unexpanded\def#4##1{\doinsertsynonym{#1}{##1}}% name tag
+ \ifthirdargument
+ \unexpanded\def#3##1{\doinsertsynonymmeaning{#1}{##1}}% \meaning
+ \fi
+ \setvalue{#1}{\definesynonym[\v!no][#1]}% \name
+ \else
+ \ifthirdargument
+ \unexpanded\def#3##1{\doinsertsynonymmeaning{#1}{##1}}% \meaning
+ \fi
+ \setvalue{#1}{\definesynonym[\v!yes][#1]}% \name
+ \fi
+ \getparameters[\??sm#1][\s!parent=\??sm]%
+ \presetheadtext[#2=\Word{#2}]% changes the \if...argument
+ %\ctxlua{joblists.define('#1')}%
+ \setvalue{\e!setup #2\e!endsetup}{\dodoubleargument\getparameters[\??sm#1]}% to be obsolete
+ \setvalue{\e!place \e!listof#2}{\doplacelistofsynonyms{#1}{#2}}%
+ \setvalue{\e!complete\e!listof#2}{\docompletelistofsynonyms{#1}{#2}}}
+
+\def\definesynonym
+ {\dotripleempty\dodefinesynonym}
+
+\def\dodefinesynonym[#1][#2][#3]#4#5%
+ {\begingroup
+ \edef\currentsynonym{#2}%
+ \edef\currentsynonymtag{#3}%
+ \ifx\currentsynonymtag\empty
+ \edef\currentsynonymtag{#4}%
+ \fi
+ \ifx\currentsynonymtag\empty
+ % todo: error message
+ \else
+ \edef\currentsynonymexpansion{\synonymparameter\c!expansion}%
+ \preprocessexpansion\currentsynonymexpansion\currentsynonymtext \currentsynonymcoding{#4}%
+ \preprocessexpansion\currentsynonymexpansion\currentsynonymmeaning\currentsynonymcoding{#5}%
+ \ctxlua{joblists.register("\currentsynonym", "synonym", {
+ metadata = {
+ catcodes = \the\catcodetable,
+ coding = "\currentsynonymcoding",
+ xmlroot = \ifx\currentsynonymcoding\s!xml "\xmldocument" \else nil \fi,
+ },
+ definition = {
+ tag = "\currentsynonymtag",
+ synonym = \!!bs\currentsynonymtext\!!es,
+ meaning = \!!bs\currentsynonymmeaning\!!es,
+ used = false,
+ }
+ })}%
+ \doif{#1}\v!yes{\unexpanded\setxvalue\currentsynonymtag{\noexpand\doinsertsynonym{\currentsynonym}{\currentsynonymtag}}}%
+ \fi
+ \endgroup}
+
+\def\doinsertsynonym#1#2% name tag
+ {\begingroup
+ % no kap currently, of .. we need to map cap onto WORD
+ \dosetsynonymattributes\c!synonymstyle\c!synonymcolor
+ \ctxlua{joblists.synonym("#1","#2")}%
+ \endgroup}
+
+\def\doinsertsynonymmeaning#1#2% name tag
+ {\begingroup
+ % no kap currently, of .. we need to map cap onto WORD
+ \dosetsynonymattributes\c!textstyle\c!textcolor
+ \ctxlua{joblists.meaning("#1","#2")}%
+ \endgroup}
+
+\def\doplacelistofsynonyms#1#2%
+ {\begingroup
+ \def\currentsynonym{#1}%
+\definedescription % todo, per class
+ [syndef]
+ [\c!location=\synonymparameter\c!location,
+ \c!width=\synonymparameter\c!width,
+ \c!distance=\synonymparameter\c!distance,
+ \c!sample=\synonymparameter\c!sample,
+ \c!hang=\synonymparameter\c!hang,
+ \c!align=\synonymparameter\c!align,
+ \c!before=\synonymparameter\c!before,
+ \c!inbetween=\synonymparameter\c!inbetween,
+ \c!after=\synonymparameter\c!after,
+ \c!indentnext=\synonymparameter\c!indentnext,
+ \c!headstyle=\synonymparameter\c!headstyle,
+ \c!headcolor=\synonymparameter\c!headcolor,
+ \c!style=,
+ \c!color=]%
+ \startpacked
+ \ctxlua{joblists.process('#1',{ criterium = "\synonymparameter\c!criterium" })}%
+ \stoppacked
+ \endgroup}
+
+\def\docompletelistofsynonyms#1#2% expansion needed to avoid v! (due to french active !)
+ {\normalexpanded{\noexpand\systemsuppliedchapter[#1]{\noexpand\headtext{#2}}}%
+ \doplacelistofsynonyms{#1}{#2}%
+ \page[\v!yes]}
+
+\let\startsynonymoutput \relax
+\let\stopsynonymoutput \relax
+\let\startsynonymsection\gobbleoneargument
+\let\stopsynonymsection \relax
+
+\def\synonymentry#1#2#3%
+ {\syndef{\dosetsynonymattributes\c!textstyle\c!textcolor#2}#3\par}
+
+\let\currentsorting\empty
+
+% we can share if we also have synonymprefix = so
+
+\def\sortingparameter #1{\csname\dosortingparameter{\??so\currentsorting}#1\endcsname}
+\def\sortingparameterhash#1{\dosortingparameterhash {\??so\currentsorting}#1}
+
+\def\dosortingparameter #1#2{\ifcsname#1#2\endcsname#1#2\else\expandafter\dosortingparentparameter \csname#1\s!parent\endcsname#2\fi}
+\def\dosortingparameterhash#1#2{\ifcsname#1#2\endcsname #1\else\expandafter\dosortingparentparameterhash\csname#1\s!parent\endcsname#2\fi}
+
+\def\dosortingparentparameter #1#2{\ifx#1\relax\s!empty\else\dosortingparameter #1#2\fi}
+\def\dosortingparentparameterhash#1#2{\ifx#1\relax \else\dosortingparameterhash#1#2\fi}
+
+\def\dosetsortingattributes#1#2% style color
+ {\edef\fontattributehash {\sortingparameterhash#1}%
+ \edef\colorattributehash{\sortingparameterhash#2}%
+ \ifx\fontattributehash \empty\else\dosetfontattribute \fontattributehash #1\fi
+ \ifx\colorattributehash\empty\else\dosetcolorattribute\colorattributehash#2\fi}
+
+\newtoks\everysetupsorting
+
+\def\setupsorting
+ {\dodoubleargument\dosetupsorting}
+
+\def\dosetupsorting[#1][#2]%
+ {\ifsecondargument
+ \getparameters[\??so#1][#2]%
+ \else
+ \getparameters[\??so][#1]%
+ \fi
+ \the\everysetupsorting}
+
+\setupsorting
+ [\c!state=\v!start,
+ %\c!command=, % we test for defined !
+ %\c!criterium=,
+ %\c!style=,
+ %\c!before=,
+ \c!after=\endgraf,
+ %\c!expansion=,
+ \s!language=\currentmainlanguage]
+
+\def\definesorting
+ {\dotripleempty\dodefinesorting}
+
+% if #3=\relax or \v!none, then no command but still protected
+
+\def\dodefinesorting[#1][#2][#3]%
+ {\ifthirdargument
+ \doifnot{#3}\v!none
+ {\ifx#3\relax \else
+ \def#3##1{\doinsertsort{#1}{##1}}%
+ \fi}%
+ \setvalue{#1}{\definesort[\v!no][#1]}%
+ \else
+ \setvalue{#1}{\definesort[\v!yes][#1]}%
+ \fi
+ \getparameters[\??so#1][\s!parent=\??so]%
+ \presetheadtext[#2=\Word{#2}]% after \ifthirdargument -)
+ %\ctxlua{joblists.define('#1')}%
+ \setvalue{\e!setup #2\e!endsetup}{\dodoubleargument\getparameters[\??so#1]}% to be obsolete
+ \setvalue{\e!place \e!listof#2}{\doplacelistofsortings{#1}{#2}}%
+ \setvalue{\e!complete\e!listof#2}{\docompletelistofsortings{#1}{#2}}}
+
+
+\def\definesort
+ {\dotripleempty\dodefinesort}
+
+\def\dodefinesort[#1][#2][#3]#4%
+ {\begingroup
+ \edef\currentsorting{#2}%
+ \edef\currentsortingtag{#3}%
+ \ifx\currentsortingtag\empty
+ \edef\currentsortingtag{#4}%
+ \fi
+ \ifx\currentsortingtag\empty
+ % todo: error message
+ \else
+ \edef\currentsortingexpansion{\sortingparameter\c!expansion}%
+ \preprocessexpansion\currentsortingexpansion\currentsortingtext\currentsortingcoding{#4}%
+ \ctxlua{joblists.register("\currentsorting", "sorting", {
+ metadata = {
+ catcodes = \the\catcodetable,
+ coding = "\currentsortingcoding",
+ xmlroot = \ifx\currentsortingcoding\s!xml "\xmldocument" \else nil \fi,
+ },
+ definition = {
+ tag = "\currentsortingtag",
+ synonym = \!!bs\currentsortingtext\!!es,
+ % used = false,
+ }
+ })}%
+ \doif{#1}\v!yes{\unexpanded\setxvalue\currentsortingtag{\noexpand\doinsertsort{\currentsorting}{\currentsortingtag}}}%
+ \fi
+ \endgroup}
+
+\def\doinsertsort#1#2% name tag
+ {\begingroup
+ % no kap currently, of .. we need to map cap onto WORD
+ \dosetsynonymattributes\c!style\c!color
+ \ctxlua{joblists.synonym("#1","#2")}%
+ \endgroup}
+
+% before after
+%
+% maybe just 'commandset' and then combine
+
+\def\doplacelistofsorts#1% NOG EEN RUWE VERSIE MAKEN ZONDER WITRUIMTE ETC ETC
+ {\begingroup
+ \def\currentsorting{#1}%
+ \startpacked
+ \ctxlua{joblists.process('#1',{})}%
+ \stoppacked
+ \endgroup}
+
+\def\docompletelistofsorts#1#2%
+ {\normalexpanded{\noexpand\systemsuppliedchapter[#1]{\noexpand\headtext{#2}}}%
+ \doplacelistofsorts{#1}%
+ \page[\v!yes]}
+
+\let\startsortingoutput \relax
+\let\stopsortingoutput \relax
+\let\startsortingsection\gobbleoneargument
+\let\stopsortingsection \relax
+
+\def\sortingentry#1#2#3%
+ {\begingroup\dosetsortingattributes\c!style\c!color#2\endgroup\par} % todo
+
+%D Here we define a support macro that can sort simple comma
+%D separated lists. It's a multi-list variant of a prototype
+%D written by Taco.
+
+% \def\mkloadsortedlist#1% class
+% {\bgroup
+% \getvalue{\s!set#1}%
+% \ctxlua{joblists.process('#1')}%
+% \getvalue{\s!reset#1}%
+% \egroup}
+
+% \def\processlistofsorts[#1]%
+% {\mkloadsortedlist{#1}}
+
+% \newcounter\nofsortedalphalists
+
+% \def\sortalphacommacommand#1%
+% {\begingroup
+% \doglobal\increment\nofsortedalphalists
+% \edef\currentsortedalphalist{alpha:\nofsortedalphalists}%
+% \definesorting[\currentsortedalphalist][\currentsortedalphalist]%
+% \processcommacommand[#1]{\getvalue\currentsortedalphalist}%
+% \global\let\sortedcommalist\empty
+% \def\makesortedlist##1{\doglobal\appendtocommalist{##1}\sortedcommalist}%
+% \setupsorting[\currentsortedalphalist][\c!criterium=\v!all,\c!command=\makesortedlist]%
+% \processlistofsorts[\currentsortedalphalist]%
+% \endgroup
+% \dodoglobal\let#1\sortedcommalist}
+
+% \starttext
+% \def\whatever{a,b,q,d,r,f} \sortalphacommacommand\whatever \whatever \endgraf
+% \def\whatever{ax,bx,qx,dx,rx,fx} \sortalphacommacommand\whatever \whatever \endgraf
+% \stoptext
+
+%D Presets.
+
+\definesynonyms
+ [\v!abbreviation]
+ [\v!abbreviations]
+ [\infull]
+
+\setupsynonyms
+ [\v!abbreviation]
+ [\c!textstyle=\v!capital]
+
+\definesorting
+ [\v!logo]
+ [\v!logos]
+ % no [\logogram]
+
+\definesynonyms
+ [\v!unit]
+ [\v!units]
+ [\unitmeaning]
+
+\setupsynonyms
+ [\v!unit]
+ [\c!textstyle=\dimension]
+
+\protect \endinput
diff --git a/tex/context/base/strc-xml.tex b/tex/context/base/strc-xml.tex
new file mode 100644
index 000000000..04c5e71b8
--- /dev/null
+++ b/tex/context/base/strc-xml.tex
@@ -0,0 +1,87 @@
+%D \module
+%D [ file=strc-xml,
+%D version=2008.10.20,
+%D title=\CONTEXT\ Structure Macros,
+%D subtitle=XML Processing,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE / Hans Hagen]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Structure Macros / XML Processing}
+
+\unprotect
+
+\startxmlsetups xml:ctx:tocentry
+ \xmlsetsetup{\xmldocument}{ctx:tocentry}{xml:ctx:tocentry}
+\stopxmlsetups
+
+\xmlregistersetup{xml:ctx:tocentry}
+
+\startxmlsetups xml:ctx:tocentry
+ \xmlflush{#1}
+\stopxmlsetups
+
+\protect \endinput
+
+% test.xml
+
+<?xml version='1.0' standalone='yes?>
+
+<document>
+ <section>
+ <title>Some <b>bold</b> title <b>bold <i>bold</i> oeps</b> and more</title>
+ <content>
+ <p>a paragraph of text</p>
+ <p>another paragraph of text</p>
+ </content>
+ </section>
+ <section>
+ <title>Another <b>bold</b> title <b>bold <i>bold</i> oeps</b> and more</title>
+ <content>
+ <p>a paragraph of text</p>
+ <p>another paragraph of text</p>
+ </content>
+ </section>
+</document>
+
+% test.tex
+
+\setupstructurehead[chapter][expansion=xml]
+
+\startxmlsetups xml:demo:define:base
+ \xmlsetsetup{demo}{document|section|p|b|i}{xml:demo:*}
+\stopxmlsetups
+
+\xmlregisterdocumentsetup{demo}{xml:demo:define:base}
+
+\startxmlsetups xml:demo:document
+ \title{Contents}
+ \placelist[chapter]
+ \page
+ \xmlflush{#1}
+\stopxmlsetups
+
+\startxmlsetups xml:demo:section
+ \chapter{\xmltext{#1}{/title}}
+ \xmlfirst{#1}{/content}
+\stopxmlsetups
+
+\startxmlsetups xml:demo:p
+ \xmlflush{#1}\endgraf
+\stopxmlsetups
+
+\startxmlsetups xml:demo:b
+ \bgroup\bf\xmlflush{#1}\egroup
+\stopxmlsetups
+
+\startxmlsetups xml:demo:i
+ \bgroup\it\xmlflush{#1}\egroup
+\stopxmlsetups
+
+\starttext
+ \xmlprocessfile{demo}{oeps.xml}{}
+\stoptext
diff --git a/tex/context/base/supp-box.tex b/tex/context/base/supp-box.tex
index 02a28cb4e..dc6833e6a 100644
--- a/tex/context/base/supp-box.tex
+++ b/tex/context/base/supp-box.tex
@@ -15,27 +15,12 @@
%D are quite simple, some are more advanced and when understood
%D well, all can be of use.
-\writestatus{loading}{Context Support Macros / Boxes}
+%D No longer generic, why bother.
-\unprotect
-
-% watch this: \setbox4\emptybox \wd4\onepoint \the\wd4, no dimensions for void
+\writestatus{loading}{ConTeXt Support Macros / Boxes}
-%D First a couple of hacks to make this module loadable
-%D in plain \TEX.
-
-\ifx\myalloc@\undefined % seems like we're not in context
- \def\newbox{\alloc@4\box\chardef\insc@unt}
-\fi
-
-\ifx \scratchbox\undefined \newbox \scratchbox \fi
-\ifx\globalscratchbox\undefined \newbox\globalscratchbox \fi
+\unprotect
-\ifx\normalhbox \undefined \let\normalhbox \hbox \fi
-\ifx\normalvbox \undefined \let\normalvbox \vbox \fi
-\ifx\normalvtop \undefined \let\normalvtop \vtop \fi
-\ifx\normalvcenter\undefined \let\normalvcenter\vcenter \fi
-
%D \macros
%D {strutdp,strutht,strutwd}
%D
@@ -55,8 +40,12 @@
%D Let's start with an easy one. The next macro hides the
%D ugly \type {@} in \type {\voidb@x}.
-\def\emptybox {\box\voidb@x}
-\def\resetbox#1{\setbox#1\box\voidb@x}
+\ifx\voidbox\undefined \newbox\voidbox \fi
+\ifx\voidb@x\undefined \let\voidb@x\voidbox \fi
+
+\def\emptybox {\box \voidbox}
+\def\unvoidbox {\unhbox\voidbox}
+\def\resetbox#1{\setbox#1\box\voidbox}
%D \macros
%D {nextdepth}
@@ -211,7 +200,7 @@
\next}
\def\mathsm@sh#1#2% redefined plain macro
- {\finsm@sh{$\m@th#1{#2}$}}
+ {\finsm@sh{$\mathsurround\zeropoint#1{#2}$}}
\def\makesm@sh#1% redefined plain macro (handles t b h d w)
{\if#1w\nextboxwd\zeropoint\else
@@ -239,8 +228,8 @@
%D not grab an argument in the non||math case, which is better.
\unexpanded\def\phantom {\ph@nt\nextbox\nextbox\nextbox}
-\unexpanded\def\vphantom{\ph@nt\nextbox\nextbox\voidb@x}
-\unexpanded\def\hphantom{\ph@nt\voidb@x\voidb@x\nextbox}
+\unexpanded\def\vphantom{\ph@nt\nextbox\nextbox\voidbox}
+\unexpanded\def\hphantom{\ph@nt\voidbox\voidbox\nextbox}
%D Due to a complicated call to \type {\mathpallete} and
%D thereby \type {\mathchoice}, the next macro looks ugly.
@@ -249,7 +238,7 @@
\def\ph@nt#1#2#3%
{\def\doph@nt
{\ifmmode
- \def\mathph@nt####1####2{\makeph@nt#1#2#3{$\m@th####1{####2}$}}%
+ \def\mathph@nt####1####2{\makeph@nt#1#2#3{$\mathsurround\zeropoint####1{####2}$}}%
\def\nextph@nt{\mathpalette\mathph@nt}%
\else\ifx\nextph@nt\bgroup
\def\nextph@nt{\makeph@nt#1#2#3}%
@@ -260,7 +249,7 @@
\futurelet\nextph@nt\doph@nt}
\def\makeph@nt#1#2#3%
- {\begingroup % why no \bgroup
+ {\begingroup
\dowithnextbox
{\setbox\scratchbox\null
\ht\scratchbox\ht#1%
@@ -470,9 +459,11 @@
%D \doiftext {data} {then branch}
%D \stoptyping
+\newif\iftrialtypesetting
+
\def\doiftextelse#1%
{\bgroup
- \setbox\scratchbox\normalhbox{\ignorespaces#1\removeunwantedspaces}%
+ \setbox\scratchbox\normalhbox{\trialtypesettingtrue\ignorespaces#1\removeunwantedspaces}%
\ifzeropt\wd\scratchbox
\egroup\@EA\secondoftwoarguments
\else
@@ -637,9 +628,9 @@
\def\doclap{\begingroup\dowithnextbox{\normalhbox to \zeropoint
{\normalhss\flushnextbox\normalhss}\endgroup}\normalhbox}
-\def\domathclap{\mathpalette\dodomathclap} \def\dodomathclap#1#2{\doclap{$\m@th#1#2$}}
-\def\domathllap{\mathpalette\dodomathllap} \def\dodomathllap#1#2{\dollap{$\m@th#1#2$}}
-\def\domathrlap{\mathpalette\dodomathrlap} \def\dodomathrlap#1#2{\dorlap{$\m@th#1#2$}}
+\def\domathclap{\mathpalette\dodomathclap} \def\dodomathclap#1#2{\doclap{$\mathsurround\zeropoint#1#2$}}
+\def\domathllap{\mathpalette\dodomathllap} \def\dodomathllap#1#2{\dollap{$\mathsurround\zeropoint#1#2$}}
+\def\domathrlap{\mathpalette\dodomathrlap} \def\dodomathrlap#1#2{\dorlap{$\mathsurround\zeropoint#1#2$}}
\unexpanded\def\rlap{\mathortext\domathrlap\dorlap}
\unexpanded\def\llap{\mathortext\domathllap\dollap}
@@ -817,73 +808,65 @@
\ifx\originalshapebox\undefined \let\originalshapebox\oldshapebox \fi
-\beginTEX
-
-\def\insertshapesignal
- {\normalhbox to \shapesignal{\strut\hss}% plus \strut
- \prevdepth\strutdp} % never \nointerlineskip
-
-% \def\restoreshapebox
-% {\global\setbox\tmpshapebox\copy\originalshapebox} % \oldshapebox
-
-\def\restoreshapebox % compensates for the signal
- {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
-
-\def\shapeboxstrut % put this in front if needed !
- {\vrule\!!width\zeropoint\!!height\ht\shapebox\!!depth\dp\shapebox}
-
-\def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
- {\ifzeropt\lastskip % \ifdim\lastskip=\zeropoint\relax
- \ifzeropt\lastkern % \ifdim\lastkern=\zeropoint\relax
- \ifcase\lastpenalty % \ifnum\lastpenalty=\zerocount
- \setbox\shapebox\lastbox
- \ifvoid\shapebox
- \unskip\unpenalty\unkern
- \else
- \ifdim\wd\shapebox=\shapesignal\relax
- \exitloop
- \else
- \shapecounter\zerocount
- \global\setbox\tmpshapebox\normalvbox{#1\unvbox\tmpshapebox}%
- \fi
- \fi
- \else
- \shapepenalty\lastpenalty
- \global\setbox\tmpshapebox\normalvbox{#2\unvbox\tmpshapebox}%
- \unpenalty
- \fi
- \else
- \shapekern\lastkern
- \global\setbox\tmpshapebox\normalvbox{#3\unvbox\tmpshapebox}%
- \unkern
- \fi
- \else
- \shapeskip\lastskip
- \global\setbox\tmpshapebox\normalvbox{#4\unvbox\tmpshapebox}%
- \unskip
- \fi
- \ifnum\shapecounter>100 % can be less
- \global\reshapingfailedtrue
- \message{!!forced exit from shapebox!!}%
- \restoreshapebox
- \exitloop
- \else
- \advance\shapecounter \plusone
- \fi}
-
-\endTEX
-
-% Now that the lastnode bugfixes are wide spread we can use:
-
-\beginETEX \lastnodetype
+% %D The old traditional tex variant:
+%
+% \def\insertshapesignal
+% {\normalhbox to \shapesignal{\strut\hss}% plus \strut
+% \prevdepth\strutdp} % never \nointerlineskip
+%
+% \def\restoreshapebox % compensates for the signal
+% {\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
+%
+% \def\shapeboxstrut % put this in front if needed !
+% {\vrule\!!width\zeropoint\!!height\ht\shapebox\!!depth\dp\shapebox}
+%
+% \def\dodoreshapebox#1#2#3#4% \shapebox, \shapepenalty, \shapekern, \shapeskip
+% {\ifzeropt\lastskip % \ifdim\lastskip=\zeropoint\relax
+% \ifzeropt\lastkern % \ifdim\lastkern=\zeropoint\relax
+% \ifcase\lastpenalty % \ifnum\lastpenalty=\zerocount
+% \setbox\shapebox\lastbox
+% \ifvoid\shapebox
+% \unskip\unpenalty\unkern
+% \else
+% \ifdim\wd\shapebox=\shapesignal\relax
+% \exitloop
+% \else
+% \shapecounter\zerocount
+% \global\setbox\tmpshapebox\normalvbox{#1\unvbox\tmpshapebox}%
+% \fi
+% \fi
+% \else
+% \shapepenalty\lastpenalty
+% \global\setbox\tmpshapebox\normalvbox{#2\unvbox\tmpshapebox}%
+% \unpenalty
+% \fi
+% \else
+% \shapekern\lastkern
+% \global\setbox\tmpshapebox\normalvbox{#3\unvbox\tmpshapebox}%
+% \unkern
+% \fi
+% \else
+% \shapeskip\lastskip
+% \global\setbox\tmpshapebox\normalvbox{#4\unvbox\tmpshapebox}%
+% \unskip
+% \fi
+% \ifnum\shapecounter>100 % can be less
+% \global\reshapingfailedtrue
+% \message{!!forced exit from shapebox!!}%
+% \restoreshapebox
+% \exitloop
+% \else
+% \advance\shapecounter \plusone
+% \fi}
+%
+% But now that the lastnode bugfixes are wide spread we can use:
+%
+% We will turn this into a \MKIV\ variant.
\def\insertshapesignal
{\normalhbox to \shapesignal{\strut\hss}% plus \strut
\prevdepth\strutdp} % never \nointerlineskip
-% \def\restoreshapebox
-% {\global\setbox\tmpshapebox\copy\originalshapebox} % \oldshapebox
-
\def\restoreshapebox % compensates for the signal
{\global\setbox\tmpshapebox\vbox{\vskip-\lineheight\unvcopy\oldshapebox}}
@@ -921,8 +904,6 @@
\advance\shapecounter \plusone
\fi}
-\endETEX
-
\def\beginofshapebox
{\setbox\oldshapebox\normalvbox
\bgroup
@@ -1038,8 +1019,22 @@
%D preparing a long list of words we decided to show the
%D hyphens, but had to find out that the \PLAIN\ alternative
%D can hardly be used and|/|or adapted to typesetting. The next
-%D two macros do the job and a little more.
-%D
+%D two macros do the job and a little more. First we define the
+%D (slightly adapted) plain variant:
+
+\def\showhyphens#1%
+ {\begingroup
+ \setbox\scratchbox\vbox
+ {\parfillskip\zerocount
+ \hsize\maxdimen
+ %\tenrm
+ \pretolerance\minusone
+ \tolerance\minusone
+ \hbadness\zerocount
+ \showboxdepth\zerocount
+ \ #1}%
+ \endgroup}
+
%D The simple command \type{\hyphenatedword} accepts one
%D argument and gives the hyphenated word. This macro calls for
%D
@@ -2262,11 +2257,13 @@
\hskip-\scratchdimen
\normalhbox to \scratchdimen{\hss\flushnextbox\hss}}}
-\def\startoverlay
+\unexpanded\def\startoverlay
{\bgroup
\let\stopoverlay\egroup
\processboxes\dooverlaybox}
+\let\stopoverlay\relax
+
% %D \macros
% %D {starthspread}
% %D
@@ -2700,31 +2697,35 @@
%D \normalhbox{y:\foundbox{two}{a}} \par
%D \stoptyping
-% a first version
+% we keep it around as a demonstration of good old tex code:
%
% \def\@@stackbox{boxstack:b:}
% \def\@@stackmax{boxstack:m:}
% \def\@@stacktag{boxstack:t:}
+% \def\@@stacklst{boxstack:l:}
%
% \def\initializeboxstack#1%
% {\ifundefined{\@@stackbox#1}%
% \@EA\newbox\csname\@@stackbox#1\endcsname
% \else
% \global\setbox\csname\@@stackbox#1\endcsname\normalvbox{}%
+% \def\docommand##1{\global\letbeundefined{\@@stacktag#1:##1}}%
+% \processcommacommand[\getvalue{\@@stacklst#1}]\docommand
% \fi
-% % actually we should erase the old values
-% \setgvalue{\@@stackmax#1}{0}}
+% \global\letvalue{\@@stacklst#1}\empty
+% \global\letvalue{\@@stackmax#1}\!!zeropoint}
%
% \def\savebox#1#2% stack name
% {\dowithnextbox
% {\doifdefined{\@@stackbox#1}
% {\@EA\doglobal\@EA\increment\csname\@@stackmax#1\endcsname
-% \setxvalue{\@@stacktag#2}{\csname\@@stackmax#1\endcsname}%
-% \global\setbox\csname\@@stackbox#1\endcsname=\normalvbox
+% \setxvalue{\@@stacktag#1:#2}{\csname\@@stackmax#1\endcsname}%
+% \setxvalue{\@@stacklst#1}{\getvalue{\@@stacklst#1},#2}%
+% \global\setbox\csname\@@stackbox#1\endcsname\normalvbox
% {\forgetall
-% \setbox\scratchbox=\normalvbox{\flushnextbox}
-% \ht\scratchbox=\onepoint
-% \dp\scratchbox=\zeropoint
+% \setbox\scratchbox\normalvbox{\flushnextbox}
+% \ht\scratchbox\onepoint
+% \dp\scratchbox\zeropoint
% \unvbox\csname\@@stackbox#1\endcsname
% \offinterlineskip
% \allowbreak
@@ -2734,76 +2735,21 @@
% \def\foundbox#1#2%
% {\normalvbox
% {\doifdefined{\@@stackbox#1}
-% {\doifdefined{\@@stacktag#2}
-% {\setbox\scratchbox=\normalvbox
+% {\doifdefined{\@@stacktag#1:#2}
+% {\setbox\scratchbox\normalvbox
% {\splittopskip\zeropoint
-% \setbox0=\copy\csname\@@stackbox#1\endcsname
-% \dimen0=\getvalue{\@@stacktag#2}pt
-% \advance\dimen0 by -\onepoint
-% \setbox2=\vsplit0 to \dimen0
+% \setbox0\copy\csname\@@stackbox#1\endcsname
+% \dimen0=\getvalue{\@@stacktag#1:#2}\points
+% \advance\dimen0 -\onepoint
+% \setbox2\vsplit0 to \dimen0
% \ifdim\ht0>\onepoint
-% \setbox0=\vsplit0 to \onepoint
+% \setbox0\vsplit0 to \onepoint
% \fi
-% \unvbox0\setbox0=\lastbox\unvbox0}%
+% \unvbox0\setbox0\lastbox\unvbox0}%
% \unvbox\scratchbox}}}}
-
-\beginTEX \newbox
-
-\def\@@stackbox{boxstack:b:}
-\def\@@stackmax{boxstack:m:}
-\def\@@stacktag{boxstack:t:}
-\def\@@stacklst{boxstack:l:}
-
-\def\initializeboxstack#1%
- {\ifundefined{\@@stackbox#1}%
- \@EA\newbox\csname\@@stackbox#1\endcsname
- \else
- \global\setbox\csname\@@stackbox#1\endcsname\normalvbox{}%
- \def\docommand##1{\global\letbeundefined{\@@stacktag#1:##1}}%
- \processcommacommand[\getvalue{\@@stacklst#1}]\docommand
- \fi
- \global\letvalue{\@@stacklst#1}\empty
- \global\letvalue{\@@stackmax#1}\!!zeropoint}
-
-\def\savebox#1#2% stack name
- {\dowithnextbox
- {\doifdefined{\@@stackbox#1}
- {\@EA\doglobal\@EA\increment\csname\@@stackmax#1\endcsname
- \setxvalue{\@@stacktag#1:#2}{\csname\@@stackmax#1\endcsname}%
- \setxvalue{\@@stacklst#1}{\getvalue{\@@stacklst#1},#2}%
- \global\setbox\csname\@@stackbox#1\endcsname\normalvbox
- {\forgetall
- \setbox\scratchbox\normalvbox{\flushnextbox}
- \ht\scratchbox\onepoint
- \dp\scratchbox\zeropoint
- \unvbox\csname\@@stackbox#1\endcsname
- \offinterlineskip
- \allowbreak
- \box\scratchbox}}}%
- \normalvbox}
-
-\def\foundbox#1#2%
- {\normalvbox
- {\doifdefined{\@@stackbox#1}
- {\doifdefined{\@@stacktag#1:#2}
- {\setbox\scratchbox\normalvbox
- {\splittopskip\zeropoint
- \setbox0\copy\csname\@@stackbox#1\endcsname
- \dimen0=\getvalue{\@@stacktag#1:#2}\points
- \advance\dimen0 -\onepoint
- \setbox2\vsplit0 to \dimen0
- \ifdim\ht0>\onepoint
- \setbox0\vsplit0 to \onepoint
- \fi
- \unvbox0\setbox0\lastbox\unvbox0}%
- \unvbox\scratchbox}}}}
-
-\def\doifboxelse#1#2%
- {\doifdefinedelse{\@@stacktag#1:#2}}
-
-\endTEX
-
-\beginETEX \newbox
+%
+% \def\doifboxelse#1#2%
+% {\doifdefinedelse{\@@stacktag#1:#2}}
\def\@@stackbox{@box@}
\def\@@stacklst{@xob@}
@@ -2992,13 +2938,6 @@
\def\setdimentoatleast#1#2%
{\ifdim#1>\zeropoint\else#1=#2\fi}
-%D We need'm raw.
-
-\ifx \normalhbox \undefined \let \normalhbox = \hbox \fi
-\ifx \normalvbox \undefined \let \normalvbox = \vbox \fi
-\ifx \normalvtop \undefined \let \normalvtop = \vtop \fi
-\ifx \normalvcenter \undefined \let \normalvcenter = \vcenter \fi
-
%D And even rawer:
\let\naturalhbox \normalhbox
@@ -3006,13 +2945,13 @@
\let\naturalvtop \normalvtop
\let\naturalvcenter \normalvtop
-\beginOMEGA dir
+\ifdefined\textdir
-\def\naturalhbox{\normalhbox dir TLT}
-\def\naturalvbox{\normalvbox dir TLT}
-%def\naturalvtop{\normalvtop dir TLT}
+ \def\naturalhbox{\normalhbox dir TLT}
+ \def\naturalvbox{\normalvbox dir TLT}
+ %def\naturalvtop{\normalvtop dir TLT}
-\endOMEGA
+\fi
%D \macros
%D {vcenter}
@@ -3044,27 +2983,17 @@
%D
%D A prelude to an extended \TEX:
-% it's about time to drop tex in favour of etex / TEX VERSION TO BE TESTED
-
-\beginTEX
-
- \def\setboxllx #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@x\number#1}{\the\scratchdimen}}}
- \def\setboxlly #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@y\number#1}{\the\scratchdimen}}}
-
- \def\gsetboxllx#1#2{\bgroup\scratchdimen#2\setxvalue{b@@x\number#1}{\the\scratchdimen}\egroup}
- \def\gsetboxlly#1#2{\bgroup\scratchdimen#2\setxvalue{b@@y\number#1}{\the\scratchdimen}\egroup}
-
-\endTEX
-
-\beginETEX
-
- \def\setboxllx#1#2{\setevalue{b@@x\number#1}{\the\dimexpr(#2)}}
- \def\setboxlly#1#2{\setevalue{b@@y\number#1}{\the\dimexpr(#2)}}
+% \def\setboxllx #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@x\number#1}{\the\scratchdimen}}}
+% \def\setboxlly #1#2{\bgroup\scratchdimen#2\expanded{\egroup\noexpand\setevalue{b@@y\number#1}{\the\scratchdimen}}}
+%
+% \def\gsetboxllx#1#2{\bgroup\scratchdimen#2\setxvalue{b@@x\number#1}{\the\scratchdimen}\egroup}
+% \def\gsetboxlly#1#2{\bgroup\scratchdimen#2\setxvalue{b@@y\number#1}{\the\scratchdimen}\egroup}
- \def\gsetboxllx{\global\setboxllx}
- \def\gsetboxlly{\global\setboxlly}
+\def\setboxllx#1#2{\setevalue{b@@x\number#1}{\the\dimexpr#2\relax}}
+\def\setboxlly#1#2{\setevalue{b@@y\number#1}{\the\dimexpr#2\relax}}
-\endETEX
+\def\gsetboxllx{\global\setboxllx}
+\def\gsetboxlly{\global\setboxlly}
\def\getboxllx#1{\executeifdefined{b@@x\number#1}\zeropoint}
\def\getboxlly#1{\executeifdefined{b@@y\number#1}\zeropoint}
@@ -3094,6 +3023,32 @@
\interactionmode\scratchcounter
\egroup}}
+\def\spreadhbox#1% rebuilds \hbox{<box><hss><box><hss><box>}
+ {\bgroup
+ \ifhbox#1\relax
+ \setbox2\emptybox
+ \unhbox#1%
+ \doloop
+ {\unpenalty\unskip\unpenalty\unskip\unpenalty\unskip
+ \setbox0\lastbox
+ \ifvoid0
+ \exitloop
+ \else
+ \setbox2\hbox
+ {\ifhbox0 \spreadhbox0\else\box0\fi
+ \ifvoid2 \else\hss\unhbox2\fi}%
+ \fi}%
+ \ifvoid2\else\unhbox2\fi
+ \else
+ \box#1%
+ \fi
+ \egroup}
+
+% makes sense:
+
+\showboxbreadth\maxdimen
+\showboxdepth \maxdimen
+
\protect \endinput
% a bit of test code:
diff --git a/tex/context/base/supp-dir.mkii b/tex/context/base/supp-dir.mkii
new file mode 100644
index 000000000..41cd1b56f
--- /dev/null
+++ b/tex/context/base/supp-dir.mkii
@@ -0,0 +1,41 @@
+%D \module
+%D [ file=supp-dir,
+%D version=2004.11.11,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=Directional Things,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Inspired by and needed for Adam Lindsay's \XETEX\ efforts:
+%D
+%D \starttyping
+%D \starttext
+%D \input tufte \par
+%D \pardir TRT \input tufte \par \input tufte \par
+%D \pardir TLT \input tufte \par
+%D \stoptext
+%D \stoptyping
+
+\unprotect
+
+\chardef\inlinedirection\zerocount % 0==notset 1==LR 2==RL
+
+\def\pardir#1#2#3% messages end up in a higher level command
+ {\global\TeXXeTstate\plusone
+ \if#2L\chardef\inlinedirection\plusone\else
+ \if#2R\chardef\inlinedirection\plustwo\fi\fi
+ \checkinlinedirection} % needed / added
+
+\def\checkinlinedirection
+ {\ifcase\inlinedirection\or\beginL\or\beginR\fi}
+
+% see core-ini.tex
+%
+% \appendtoks \checkinlinedirection \to \everypar
+
+\protect \endinput
diff --git a/tex/context/base/supp-dir.mkiv b/tex/context/base/supp-dir.mkiv
new file mode 100644
index 000000000..7d2e10070
--- /dev/null
+++ b/tex/context/base/supp-dir.mkiv
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=supp-dir,
+%D version=2004.11.11,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=Directional Things,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We no longer have the \ETEX\ direction primitives.
+
+\unprotect
+
+\chardef \inlinedirection \zerocount % 0==notset 1==LR 2==RL
+\let \checkinlinedirection \donothing
+
+\protect \endinput
diff --git a/tex/context/base/supp-dir.tex b/tex/context/base/supp-dir.tex
deleted file mode 100644
index ad14eab1d..000000000
--- a/tex/context/base/supp-dir.tex
+++ /dev/null
@@ -1,70 +0,0 @@
-%D \module
-%D [ file=supp-dir,
-%D version=2004.11.11,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=Directional Things,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D Inspired by and needed for Adam Lindsay's \XETEX\ efforts:
-%D
-%D \starttyping
-%D \starttext
-%D \input tufte \par
-%D \pardir TRT \input tufte \par \input tufte \par
-%D \pardir TLT \input tufte \par
-%D \stoptext
-%D \stoptyping
-
-\unprotect
-
-\chardef \inlinedirection \zerocount % 0==notset 1==LR 2==RL
-\let \checkinlinedirection \donothing
-
-\beginETEX \beginL
-
- \ifx\pardir \undefined
-
- \def\pardir#1#2#3% messages end up in a higher level command
- {\global\TeXXeTstate\plusone
- \if#2L\chardef\inlinedirection\plusone\else
- \if#2R\chardef\inlinedirection\plustwo\fi\fi
- \checkinlinedirection} % needed / added
-
- \let\normalpardir\pardir
-
- \def\checkinlinedirection
- {\ifcase\inlinedirection\or\beginL\or\beginR\fi}
-
- \else
-
-% \let\normalpardir\pardir
-
-% \def\pardir#1#2#3%
-% {\if#2L\chardef\inlinedirection\plusone\else
-% \if#2R\chardef\inlinedirection\plustwo\fi\fi
-% \normalpardir#1#2#3}
-
-% \def\beginL
-% {} % todo: \normalpardir...
-
-% \def\beginR
-% {} % todo: \normalpardir...
-
-% \def\checkinlinedirection
-% {\ifcase\inlinedirection\or\beginL\or\beginR\fi}
-
- \fi
-
-\endETEX
-
-% see core-ini.tex
-%
-% \appendtoks \checkinlinedirection \to \everypar
-
-\protect \endinput
diff --git a/tex/context/base/supp-eps.tex b/tex/context/base/supp-eps.tex
index 0a3cfa2b6..5684b25dd 100644
--- a/tex/context/base/supp-eps.tex
+++ b/tex/context/base/supp-eps.tex
@@ -19,7 +19,7 @@
%D were put in \type{supp-pdf}, I considered it more suitable
%D to give the \EPS\ macros their own module.
-\writestatus{loading}{Context Support Macros / EPS}
+\writestatus{loading}{ConTeXt Support Macros / EPS}
%D \macros
%D {dogetEPSboundingbox}
diff --git a/tex/context/base/supp-fil.lua b/tex/context/base/supp-fil.lua
index 32c5fb865..a93b0bce9 100644
--- a/tex/context/base/supp-fil.lua
+++ b/tex/context/base/supp-fil.lua
@@ -12,26 +12,30 @@ if not modules then modules = { } end modules ['supp-fil'] = {
at the <l n='tex'/> side.</p>
--ldx]]--
+local find, gsub, match = string.find, string.gsub, string.match
+
+local ctxcatcodes = tex.ctxcatcodes
+
support = support or { }
environment = environment or { }
environment.outputfilename = environment.outputfilename or environment.jobname
function support.checkfilename(str) -- "/whatever..." "c:..." "http://..."
- cs.chardef("kindoffile",boolean.tonumber(str:find("^/") or str:find("[%a]:")))
+ commands.chardef("kindoffile",boolean.tonumber(find(str,"^/") or find(str,"[%a]:")))
end
function support.thesanitizedfilename(str)
- tex.write((str:gsub("\\","/")))
+ tex.write((gsub(str,"\\","/")))
end
function support.splitfilename(fullname)
local path, name, base, suffix, kind = '', fullname, fullname, '', 0
- local p, n = fullname:match("^(.+)/(.-)$")
+ local p, n = match(fullname,"^(.+)/(.-)$")
if p and n then
path, name, base = p, n, n
end
- local b, s = base:match("^(.+)%.(.-)$")
+ local b, s = match(base,"^(.+)%.(.-)$")
if b and s then
name, suffix = b, s
end
@@ -42,38 +46,43 @@ function support.splitfilename(fullname)
else
kind = 2
end
---~ print(fullname,path,base,name,suffix)
- cs.def("splitofffull", fullname)
- cs.def("splitoffpath", path)
- cs.def("splitoffbase", base)
- cs.def("splitoffname", name)
- cs.def("splitofftype", suffix)
- cs.chardef("splitoffkind", kind)
+ commands.def("splitofffull", fullname)
+ commands.def("splitoffpath", path)
+ commands.def("splitoffbase", base)
+ commands.def("splitoffname", name)
+ commands.def("splitofftype", suffix)
+ commands.chardef("splitoffkind", kind)
end
function support.splitfiletype(fullname)
local name, suffix = fullname, ''
- local n, s = fullname:match("^(.+)%.(.-)$")
+ local n, s = match(fullname,"^(.+)%.(.-)$")
if n and s then
name, suffix = n, s
end
- cs.def("splitofffull", fullname)
- cs.def("splitoffpath", "")
- cs.def("splitoffname", name)
- cs.def("splitofftype", suffix)
+ commands.def("splitofffull", fullname)
+ commands.def("splitoffpath", "")
+ commands.def("splitoffname", name)
+ commands.def("splitofftype", suffix)
end
function support.doifparentfileelse(n)
- cs.testcase(n==environment.jobname or n==environment.jobname..'.tex' or n==environment.outputfilename)
+ commands.testcase(n==environment.jobname or n==environment.jobname..'.tex' or n==environment.outputfilename)
end
-- saves some .15 sec on 12 sec format generation
+local lastexistingfile = ""
+
function support.doiffileexistelse(name)
if not name or name == "" then
- return cs.testcase(false)
+ lastexistingfile = ""
else
- local n = input.findtexfile(name)
- return cs.testcase(n and n ~= "")
+ lastexistingfile = resolvers.findtexfile(name) or ""
end
+ return commands.testcase(lastexistingfile ~= "")
+end
+
+function support.lastexistingfile()
+ tex.sprint(ctxcatcodes,lastexistingfile)
end
diff --git a/tex/context/base/supp-fil.mkii b/tex/context/base/supp-fil.mkii
index ff4a2ab01..1e86498e4 100644
--- a/tex/context/base/supp-fil.mkii
+++ b/tex/context/base/supp-fil.mkii
@@ -9,12 +9,185 @@
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details
+%C details.
+
+%D \TEX\ operates on files, so one wouldn't wonder that there
+%D is a separate module for file support. In \CONTEXT\ files
+%D are used for several purposes:
+%D
+%D \startitemize[packed]
+%D \item general textual input
+%D \item logging status information
+%D \item saving registers, lists and references
+%D \item buffering defered textual input
+%D \stopitemize
+%D
+%D When dealing with files we can load them as a whole, using
+%D the \type{\input} primitive or load them on a line||by||line
+%D basis, using \type{\read}. Writing is always done line by
+%D line, using \type{\write}.
+
+\writestatus{loading}{ConTeXt Support Macros / Files}
\unprotect
+\ifx\undefined\f!pathseparator
+ \def\f!pathseparator{/}
+ \def\f!currentpath {.}
+ \def\f!parentpath {..}
+\fi
+
\def\openinputfile #1#2{\immediate\openin #1="#2"\relax} \def\closeinputfile #1{\immediate\closein #1}
\def\openoutputfile#1#2{\immediate\openout#1="#2"\relax} \def\closeoutputfile#1{\immediate\closeout#1}
+
+%D \macros
+%D {pushendofline,popendofline}
+%D
+%D When we are loading files in the middle of the typesetting
+%D process, for instance when we load references, we have to be
+%D sure that the reading process does not generate so called
+%D 'spurious spaces'. This can be prevented by assigning the
+%D line ending character the \CATCODE\ comment. This is
+%D accomplished by
+%D
+%D \starttyping
+%D \pushendofline
+%D ... reading ...
+%D \popendofline
+%D \stoptyping
+%D
+%D Just to be sure, we save the current meaning of \type{^^M}
+%D in \type{\poppedendofline}.
+
+% \chardef\poppedendofline\catcode`\^^M
+%
+% \def\pushendofline
+% {\chardef\poppedendofline\catcode`\^^M\relax
+% \catcode`\^^M\@@comment\relax}
+%
+% \def\popendofline
+% {\catcode`\^^M\poppedendofline}
+%
+% support for nested usage:
+
+\newcount \endoflinelevel
+
+\ifx\newlinecode\undefined \chardef\newlinecode=`\^^M \fi
+
+\def\pushendofline
+ {\advance\endoflinelevel\plusone
+ \expandafter\chardef\csname :eol:\number\endoflinelevel\endcsname\catcode\newlinecode
+ \catcode\newlinecode\@@comment\relax}
+
+\def\popendofline
+ {\catcode\newlinecode\csname :eol:\number\endoflinelevel\endcsname
+ \advance\endoflinelevel\minusone}
+
+\def\restoreendofline
+ {\catcode\newlinecode\@@endofline}
+
+%D \macros
+%D {scratchread, scratchwrite}
+%D
+%D We define a scratch file for reading. Keep in mind that
+%D the number of files is limited to~16, so use this one when
+%D possible. We also define a scratch output file.
+
+\ifx\undefined\scratchread \newread \scratchread \fi
+\ifx\undefined\scratchwrite \newwrite\scratchwrite \fi
+
+%D \macros
+%D {unlinkfile}
+%D
+%D Sometimes we want to make sure a file is deleted, so here
+%D is a macro that does the job. It's named after the \PERL\
+%D one.
+
+\def\unlinkfile#1%
+ {\openoutputfile \scratchwrite{#1}%
+ \closeoutputfile\scratchwrite}
+
+%D \macros
+%D {writeln}
+%D
+%D This saves a few tokens:
+
+\def\writeln#1{\write#1{}}
+
+\def\doiffileexistselse#1%
+ {\doifelsenothing{#1}
+ {\secondoftwoarguments}
+ {\openinputfile\scratchread{#1}%
+ \ifeof\scratchread
+ \closeinputfile\scratchread
+ \expandafter\secondoftwoarguments
+ \else
+ \closeinputfile\scratchread
+ \expandafter\firstoftwoarguments
+ \fi}}
+
+%D \macros
+%D {doprocessfile,fileline,fileprocessedtrue,dofinishfile}
+%D
+%D The next macro offers a framework for processing files on a
+%D line by line basis.
+%D
+%D \starttyping
+%D \doprocessfile \identifier {name} \action
+%D \stoptyping
+%D
+%D The first argument can for instance be \type{\scratchread}.
+%D The action must do something with \type{\fileline}, which
+%D holds the current line. One can halfway step out using
+%D \type{\dofinishfile} and ise \type{\iffileprocessed} to
+%D see if indeed some content was found.
+
+\newif\iffileprocessed
+
+\let\fileline\empty
+
+\def\doprocessfile#1#2#3%
+ {\openinputfile{#1}{#2}%
+ \ifeof#1%
+ \fileprocessedfalse
+ \closeinputfile#1%
+ \else
+ \fileprocessedtrue
+ \gdef\dofinishfile
+ {\closeinputfile#1%
+ \global\let\doprocessline\relax}%
+ \gdef\doprocessline
+ {\ifeof#1%
+ \expandafter\dofinishfile
+ \else
+ \global\read#1 to \fileline
+ #3\relax
+ \expandafter\doprocessline
+ \fi}%
+ \expandafter\doprocessline
+ \fi}
+
+%D \macros
+%D {pathplusfile,assignfullfilename,sanitizefilename}
+%D
+%D Use \type{\pathplusfile} to compose a full file name, like
+%D in:
+%D
+%D \starttyping
+%D \pathplusfile{path}{file}
+%D \stoptyping
+%D
+%D By default, this expands into {\tt \pathplusfile{path}{file}}.
+
+\def\pathplusfile#1#2{#1\f!pathseparator#2}
+
+%D This one constructs a filename from a (possible empty)
+%D path and filename.
+
+\def\assignfullfilename#1#2\to#3%
+ {\doifelsenothing{#1}
+ {\edef#3{#2}}
+ {\edef#3{#1\f!pathseparator#2}}}
%D For the moment, we limit sanitizing to taking care of
%D active \type {/}.
@@ -40,6 +213,10 @@
\egroup
+%D NEW:
+
+\chardef\kindoffile=0 % 0=normal 1=full path spec (or http)
+
\def\checkfilename#1%
{\doifinstringelse{@@/}{@@#1}% unix: /full/path
{\chardef\kindoffile\plusone}
@@ -47,6 +224,443 @@
{\chardef\kindoffile\plusone}
{\chardef\kindoffile\zerocount}}}
+%D \macros
+%D {input, normalinput}
+%D
+%D Sometimes we run into troubles when \type {\input} wants to get
+%D expanded, e.g. in a \type {\write} (which happens in the metafun
+%D manual when we permit long MP lines). So, instead of fixing that,
+%D we go for a redefinition of \type {\input}. Of course it's better
+%D to use \type {\readfile} or \type {\processfile}.
+
+\unexpanded\def\input{\normalinput}
+
+\def\inputgivenfile#1{\normalinput"#1"\relax}
+
+%D \macros
+%D {readfile,ReadFile,maxreadlevel}
+%D
+%D One cannot be sure if a file exists. When no file can be
+%D found, the \type{\input} primitive gives an error message
+%D and switches to interactive mode. The macro \type{\readfile}
+%D takes care of non||existing files. This macro has two faces.
+%D
+%D \starttyping
+%D \ReadFile {filename}
+%D \readfile {filename} {before loading} {not found}
+%D \stoptyping
+%D
+%D Many \TEX\ implementations have laid out some strategy for
+%D locating files. This can lead to unexpected results,
+%D especially when one loads files that are not found in the
+%D current directory. Let's give an example of this. In
+%D \CONTEXT\ illustrations can be defined in an external file.
+%D The resizing macro first looks if an illustration is defined
+%D in the local definitions file. When no such file is found,
+%D it searches for a global file and when this file is not
+%D found either, the illustration itself is scanned for
+%D dimensions. One can imagine what happens if an adapted,
+%D localy stored illustration, is scaled according to
+%D dimensions stored somewhere else.
+%D
+%D When some \TEX\ implementation starts looking for a file, it
+%D normally first looks in the current directory. When no file
+%D is found, \TEX\ starts searching on the path where format
+%D and|/|or style files are stored. Depending on the implementation
+%D this can considerably slow down processing speed.
+%D
+%D In \CONTEXT, we support a project||wise ordening of files.
+%D In such an approach it seems feasible to store common files
+%D in a lower directory. When for instance searching for a
+%D general layout file, we therefore have to backtrack.
+%D
+%D These three considerations have lead to a more advanced
+%D approach for loading files.
+%D
+%D We first present an earlier implementation of
+%D \type{\readfile}. This command backtracks parent
+%D directories, upto a predefined level. Users can change this
+%D level, but we default to~3.
+%D
+%D \starttyping
+%D \def\maxreadlevel {3}
+%D \stoptyping
+%D
+%D This is a pseudo \COUNTER.
+%D
+%D We use \type{\normalinput} instead of \type{\input}
+%D because we want to be able to redefine the original
+%D \type{\input} when needed, for instance when loading third
+%D party libraries.
+
+\newevery \everybeforereadfile \EveryBeforeReadFile
+\newevery \everyafterreadfile \EveryAfterReadFile
+
+\let \everyreadfile \everybeforereadfile
+
+\newif\iftracefiles
+
+\newcount\readlevel
+
+\def\maxreadlevel{3}
+
+\newconditional\trackfilenames
+\let\trackedfilename\empty
+
+% We need to postpone loading, else we got frozen type-* files and so when
+% a format is generated on a source path.
+
+\def\doreadfile#1#2#3#4%
+ {\sanitizefilename#2\to\readfilename
+ \ifx\readfilename\empty
+ % silently ignore
+ \else
+ \let\trackedfilename\readfilename
+ \ifconditional\trackfilenames
+ \doifundefinedelse{fn..\trackedfilename}\donetrue\donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \iftracefiles\writestatus\m!systems{searching for \readfilename\space on #1}\fi
+ % not a full path or url, check for existence
+ \doifelsenothing{#1}
+ {\def\next{\redoreadfile\readfilename{#3}{#4}}}%
+ {\def\next{\redoreadfile{\pathplusfile{#1}{\readfilename}}{#3}{#4}}}%
+ \else
+ % a full path or url, no further checking done
+ \doiffileexistselse\readfilename
+ {\iftracefiles\writestatus\m!systems{located \readfilename}\fi
+ \def\next{#3\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{not found \readfilename}\fi
+ \def\next{#4}}%
+ \fi
+ \else
+ \edef\readfilename{\getvalue{fn..\readfilename}}%
+ \iftracefiles\writestatus\m!systems{already located \readfilename}\fi
+ \def\next{#3\dodoreadfile}%
+ \fi
+ \expandafter\next
+ \fi}
+
+\def\redoreadfile#1#2#3%
+ {\doiffileexistselse{#1}%
+ {\edef\readfilename{#1}%
+ \iftracefiles\writestatus\m!systems{#1 located}\fi
+ \def\next{#2\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{cannot locate #1}\fi
+ \advance\readlevel\minusone
+ \ifnum\readlevel>\zerocount
+ \edef\readfilename{\pathplusfile{\f!parentpath}{\readfilename}}%
+ \def\next{\redoreadfile\readfilename{#2}{#3}}%
+ \else
+ \def\next{#3}%
+ \fi}%
+ \next}
+
+\def\dodoreadfile % we provide hooks, for instance for \enableXML
+ {\ifconditional\trackfilenames
+ \setxvalue{fn..\trackedfilename}{\readfilename}%
+ \fi
+ \the\everybeforereadfile
+% \normalinput\readfilename\relax
+ \relax\inputgivenfile\readfilename\relax
+ \the\everyafterreadfile}
+
+% too less:
+%
+% \unexpanded\def\readfile% #1%
+% {\readlevel\maxreadlevel
+% \doreadfile\empty} % {#1}
+%
+% too much:
+%
+% \unexpanded\def\readfile#1#2#3%
+% {\readlocfile{#1}{#2}
+% {\readjobfile{#1}{#2}
+% {\readsysfile{#1}{#2}{#3}}}}
+%
+% just ok:
+
+\unexpanded\def\readfile#1#2#3%
+ {\readlocfile{#1}{#2}{\readsysfile{#1}{#2}{#3}}}
+
+\def\readtexfile#1#2#3%
+ {\pushcatcodetable \catcodetable \ctxcatcodes
+ \readfile{#1}{#2}{#3}%
+ \popcatcodetable}
+
+\def\readxmlfile#1#2#3%
+ {\pushcatcodetable \catcodetable \xmlcatcodes
+ \readfile{#1}{#2}{#3}%
+ \popcatcodetable}
+
+\unexpanded\def\ReadFile#1%
+ {\readfile{#1}\donothing\donothing}
+
+%D \macros
+%D {readjobfile,readlocfile,readsysfile,
+%D readfixfile,readsetfile}
+%D
+%D This implementation honnors the third situation, but we
+%D still can get unwanted files loaded and/or can get involved
+%D in extensive searching.
+%D
+%D Due to different needs, we decided to offer four alternative
+%D loading commands. With \type{\readjobfile} we load a local
+%D file and do no backtracking, while \type{\readlocfile}
+%D backtracks~\number\readlevel\ directories, including the current
+%D one.
+
+\unexpanded\def\readjobfile % #1% current path, no backtracking
+ {\readlevel\zerocount
+ \doreadfile\f!currentpath} % {#1}}
+
+\unexpanded\def\readlocfile % #1% current path, backtracking
+ {\readlevel\maxreadlevel
+ \doreadfile\f!currentpath} % {#1}}
+
+%D System files can be anywhere and therefore
+%D \type{\readsysfile} is not bound to the current directory
+%D and obeys the \TEX\ implementation.
+
+\unexpanded\def\readsysfile % #1% current path, obeys tex search
+ {\readlevel\zerocount
+ \doreadfile\empty} % {#1}}
+
+%D Of the last two, \type{\readfixfile} searches on the
+%D directory specified and backtracks too, while
+%D \type{\readsetfile} does only search on the specified path.
+
+\unexpanded\def\readfixfile % #1#2% specified path, backtracking
+ {\readlevel\maxreadlevel
+ \doreadfile} % {#1}{#2}}
+
+\unexpanded\def\readsetfile % #1#2% specified path, no backtracking
+ {\readlevel\zerocount
+ \doreadfile} % {#1}{#2}}
+
+%D After having defined this commands, we reconsidered the
+%D previously defined \type{\readfile}. This time we more or
+%D less impose the search order.
+
+\unexpanded\def\readfile#1#2#3%
+ {\readlocfile{#1}{#2}
+ {\readjobfile{#1}{#2}
+ {\readsysfile{#1}{#2}{#3}}}}
+
+%D So now we've got ourselves five file loading commands:
+%D
+%D \starttyping
+%D \readfile {filename} {before loading} {not found}
+%D
+%D \readjobfile {filename} {before loading} {not found}
+%D \readlocfile {filename} {before loading} {not found}
+%D \readfixfile {filename} {before loading} {not found}
+%D \readsysfile {directory} {filename} {before loading} {not found}
+%D \stoptyping
+
+%D \macros
+%D {readjobfile,readlocfile,readsysfile,readfixfile}
+%D
+%D The next four alternatives can be used for opening files
+%D for reading on a line||by||line basis. These commands get
+%D an extra argument, the filetag. Explicit closing is done
+%D in the normal way by \type{\closein}.
+
+\def\doopenin#1#2%
+ {\sanitizefilename#2\to\readfilename
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \advance\readlevel\plusone
+ \openinputfile{#1}\readfilename
+ \ifeof#1% \relax
+ \ifnum\readlevel>\maxreadlevel % \relax
+ \else
+ \closeinputfile#1% \relax
+ \doopenin{#1}{\pathplusfile\f!parentpath{#2}}%
+ \fi
+ \fi
+ \fi}
+
+\def\openjobin#1#2%
+ {\readlevel\zerocount
+ \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
+
+\def\opensysin % #1#2%
+ {\readlevel\maxreadlevel
+ \doopenin} % {#1}{#2}}
+
+\def\openlocin#1#2%
+ {\readlevel\maxreadlevel
+ \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
+
+\def\openfixin#1#2#3%
+ {\readlevel\maxreadlevel
+ \doopenin{#1}{\pathplusfile{#2}{#3}}}
+
+%D \macros
+%D {doiffileelse,doiflocfileelse}
+%D
+%D The next alternative only looks if a file is present. No
+%D loading is done. This one obeys the standard \TEX\
+%D implementation method.
+%D
+%D \starttyping
+%D \doiffileelse {filename} {found} {not found}
+%D \stoptyping
+%D
+%D \starttyping
+%D \doiflocfileelse {filename} {before loading} {not found}
+%D \stoptyping
+
+\def\doiffileelse {\doiffileexistselse}
+\def\doiffile #1{\doiffileexistselse{#1}\firstofoneargument\gobbleoneargument}
+\def\doifnotfile #1{\doiffileexistselse{#1}\gobbleoneargument\firstofoneargument}
+
+\def\doiflocfileelse#1%
+ {\makelocreadfilename{#1}%
+ \doiffileelse\readfilename}
+
+\def\makelocreadfilename#1%
+ {\sanitizefilename#1\to\readfilename
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \edef\readfilename{\pathplusfile\f!currentpath{#1}}%
+ \fi}
+
+%D \macros
+%D {doonlyonce, doinputonce, doendinputonce}
+%D
+%D Especially macropackages need only be loaded once.
+%D Repetitive loading not only costs time, relocating registers
+%D often leads to abortion of the processing because \TEX's
+%D capacity is limited. One can prevent multiple execution and
+%D loading by using one of both:
+%D
+%D \starttyping
+%D \doonlyonce{actions}
+%D \doinputonce{filename}
+%D \doendinputonce{filename}
+%D \stoptyping
+%D
+%D This command obeys the standard method for locating files.
+
+\long\def\doonlyonce#1%
+ {\doifundefinedelse{@@@#1@@@}
+ {\letgvalue{@@@#1@@@}\empty
+ \firstofoneargument}
+ {\gobbleoneargument}}
+
+\def\doinputonce#1%
+% {\doonlyonce{#1}{\doiffileelse{#1}{\normalinput#1\relax}\donothing}}
+ {\doonlyonce{#1}{\doiffileelse{#1}{\inputgivenfile{#1}}\donothing}}
+
+\def\doendinputonce#1%
+ {\doifdefined{@@@#1@@@}\endinput}
+
+\def\forgetdoingonce#1%
+ {\global\letbeundefined{@@@#1@@@}}
+
+%D \macros
+%D {doifparentfileelse}
+%D
+%D The test \type{\doifelse{\jobname}{filename}} does not give
+%D the desired result, simply because \type{\jobname} expands
+%D to characters with \CATCODE~12, while the characters in
+%D \type{filename} have \CATCODE~11. So we can better use:
+%D
+%D \starttyping
+%D \doifparentfileelse{filename}{yes}{no}
+%D \stoptyping
+%D
+%D Since \TEXEXEC\ (and thereby \CONTEXT) supports renaming of
+%D the outputfile, we also need to check on that alternative
+%D name.
+
+\ifx\outputfilename\undefined \def\outputfilename{\jobname} \fi
+
+\def\doifparentfileelse#1%
+ {\doifsamestringelse{#1}{\jobname }\firstoftwoarguments
+ {\doifsamestringelse{#1}{\jobname.\c!tex}\firstoftwoarguments
+ {\doifsamestringelse{#1}{\outputfilename}\firstoftwoarguments\secondoftwoarguments}}}
+
+\def\normalless {<} % geen \let !
+\def\normalmore {>} % geen \let !
+\def\normalequal {=} % geen \let !
+\def\normaldblquote{"} % geen \let !
+
+\newcount\readingfilelevel
+
+\def\popfilecharacter#1#2%
+ {\ifnum\catcode`#1=\@@other \ifnum#2=\@@other \else
+ %\message{[popping catcode #1 to #2]}%
+ \catcode`#1=#2\relax
+ \fi \fi}
+
+\ifx\\\undefined \let\\\relax \fi
+
+%D This changing catcodes is a direct result from the fact
+%D that we support some long standing conventions with
+%D regards to active characters (german ", polish /,
+%D french : and ;).
+
+%D We need to redo this: catcode sets and such
+
+\newtoks \everystartreadingfile
+\newtoks \everystopreadingfile
+
+\def\startreadingfile% beter een every en \setnormalcatcodes
+ {\global\advance\readingfilelevel\plusone
+ \the\everystartreadingfile
+ \beginrestorecatcodes
+ \setcatcodetable\prtcatcodes}
+
+\def\stopreadingfile
+ {\endrestorecatcodes
+ \the\everystopreadingfile
+ \global\advance\readingfilelevel\minusone}
+
+\let\normalstartreadingfile\startreadingfile
+\let\normalstopreadingfile \stopreadingfile
+
+%D \macros
+%D {splitfilename}
+%D
+%D I should have made this one sooner. This macro was first needed when
+%D ran into graphic with a period in the pathpart.
+%D
+%D \startbuffer
+%D \def\showfilesplit
+%D {\bgroup \tttf
+%D \hbox{(full: \splitofffull)}\space
+%D \hbox{(path: \splitoffpath)}\space
+%D \hbox{(base: \splitoffbase)}\space
+%D \hbox{(name: \splitoffname)}\space
+%D \hbox{(type: \splitofftype)}\space
+%D \egroup}
+%D
+%D \splitfilename{c:/aa/bb/cc/dd.ee.ff} \showfilesplit \endgraf
+%D \splitfilename{c:/aa/bb/cc/dd.ee} \showfilesplit \endgraf
+%D \splitfilename{c:/aa/bb/cc/dd} \showfilesplit \endgraf
+%D
+%D \splitfilename{dd.ee.ff} \showfilesplit \endgraf
+%D \splitfilename{dd.ee} \showfilesplit \endgraf
+%D \splitfilename{dd} \showfilesplit \endgraf
+%D \stopbuffer
+%D
+%D \start \typebuffer \getbuffer \stop
+
+\def\splitoffroot{.} \chardef\splitoffkind\zerocount
+
+\let\splitofffull\empty
+\let\splitoffpath\empty
+\let\splitoffbase\empty
+\let\splitoffname\empty
+\let\splitofftype\empty
+
% \def\splitfilename#1%
% {\edef\splitofffull{#1}% normally outside this call: \sanitizefilename#1\to\sanitizedfilename
% \greedysplitstring\splitofffull\at/\to\splitoffpath\and\splitoffbase
@@ -91,9 +705,4 @@
\let\splitoffpath\empty
\greedysplitstring\splitofffull\at.\to\splitoffname\and\splitofftype}
-\def\doifparentfileelse#1%
- {\doifsamestringelse{#1}{\jobname }\firstoftwoarguments
- {\doifsamestringelse{#1}{\jobname.\c!tex}\firstoftwoarguments
- {\doifsamestringelse{#1}{\outputfilename}\firstoftwoarguments\secondoftwoarguments}}}
-
\protect \endinput
diff --git a/tex/context/base/supp-fil.mkiv b/tex/context/base/supp-fil.mkiv
index 586004259..caeaa67cd 100644
--- a/tex/context/base/supp-fil.mkiv
+++ b/tex/context/base/supp-fil.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=supp-fil,
-%D version=2006.09.18,
+%D version=1995.10.10,
%D title=\CONTEXT\ Support Macros,
%D subtitle=Files,
%D author=Hans Hagen,
@@ -9,24 +9,610 @@
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details
+%C details.
-% \input supp-fil.mkii \endinput
+%D \TEX\ operates on files, so one wouldn't wonder that there
+%D is a separate module for file support. In \CONTEXT\ files
+%D are used for several purposes:
+%D
+%D \startitemize[packed]
+%D \item general textual input
+%D \item logging status information
+%D \item saving registers, lists and references
+%D \item buffering defered textual input
+%D \stopitemize
+%D
+%D When dealing with files we can load them as a whole, using
+%D the \type{\input} primitive or load them on a line||by||line
+%D basis, using \type{\read}. Writing is always done line by
+%D line, using \type{\write}.
+
+\writestatus{loading}{ConTeXt Support Macros / Files}
\registerctxluafile{supp-fil}{1.001}
-% \def\sanitizefilename#1\to#2%
-% {\edef#2{\ctxlua{support.thesanitizedfilename("\luaescapestring{#1}")}}}
-% \def\checkfilename #1{\ctxlua{support.checkfilename("\luaescapestring{#1}")}}
-% \def\splitfilename #1{\ctxlua{support.splitfilename("\luaescapestring{#1}")}}
-% \def\splitfiletype #1{\ctxlua{support.splitfiletype("\luaescapestring{#1}")}}
-% \def\doifparentfileelse#1{\ctxlua{support.doifparentfileelse("\luaescapestring{#1}")}}
+\unprotect
+
+\ifx\undefined\f!pathseparator
+ \def\f!pathseparator{/}
+ \def\f!currentpath {.}
+ \def\f!parentpath {..}
+\fi
+
+% \def\openinputfile #1#2{\immediate\openin #1="#2"\relax} \def\closeinputfile #1{\immediate\closein #1}
+% \def\openoutputfile#1#2{\immediate\openout#1="#2"\relax} \def\closeoutputfile#1{\immediate\closeout#1}
+
+\def\openinputfile #1#2{\immediate\openin #1=#2\relax} \def\closeinputfile #1{\immediate\closein #1}
+\def\openoutputfile#1#2{\immediate\openout#1=#2\relax} \def\closeoutputfile#1{\immediate\closeout#1}
+
+%D \macros
+%D {pushendofline,popendofline}
+%D
+%D When we are loading files in the middle of the typesetting
+%D process, for instance when we load references, we have to be
+%D sure that the reading process does not generate so called
+%D 'spurious spaces'. This can be prevented by assigning the
+%D line ending character the \CATCODE\ comment. This is
+%D accomplished by
+%D
+%D \starttyping
+%D \pushendofline
+%D ... reading ...
+%D \popendofline
+%D \stoptyping
+%D
+%D Just to be sure, we save the current meaning of \type{^^M}
+%D in \type{\poppedendofline}.
+
+\newcount \endoflinelevel
+
+\ifx\newlinecode\undefined \chardef\newlinecode=`\^^M \fi
+
+\def\pushendofline
+ {\advance\endoflinelevel\plusone
+ \expandafter\chardef\csname :eol:\number\endoflinelevel\endcsname\catcode\newlinecode
+ \catcode\newlinecode\@@comment\relax}
+
+\def\popendofline
+ {\catcode\newlinecode\csname :eol:\number\endoflinelevel\endcsname
+ \advance\endoflinelevel\minusone}
+
+\def\restoreendofline
+ {\catcode\newlinecode\@@endofline}
+
+%D \macros
+%D {scratchread, scratchwrite}
+%D
+%D We define a scratch file for reading. Keep in mind that
+%D the number of files is limited to~16, so use this one when
+%D possible. We also define a scratch output file.
+
+\ifx\undefined\scratchread \newread \scratchread \fi
+\ifx\undefined\scratchwrite \newwrite\scratchwrite \fi
+
+%D \macros
+%D {unlinkfile}
+%D
+%D Sometimes we want to make sure a file is deleted, so here
+%D is a macro that does the job. It's named after the \PERL\
+%D one.
+
+\def\unlinkfile#1{\ctxlua{os.remove([[#1]])}}
+
+%D \macros
+%D {writeln}
+%D
+%D This saves a few tokens:
+
+\def\writeln#1{\write#1{}}
+
+\def\doiffileexistselse #1{\ctxlua{support.doiffileexistelse([[#1]])}}
+\def\lastfoundexistingfile {\ctxlua{support.lastexistingfile()}}
+
+%D \macros
+%D {doprocessfile,fileline,fileprocessedtrue,dofinishfile}
+%D
+%D The next macro offers a framework for processing files on a
+%D line by line basis.
+%D
+%D \starttyping
+%D \doprocessfile \identifier {name} \action
+%D \stoptyping
+%D
+%D The first argument can for instance be \type{\scratchread}.
+%D The action must do something with \type{\fileline}, which
+%D holds the current line. One can halfway step out using
+%D \type{\dofinishfile} and ise \type{\iffileprocessed} to
+%D see if indeed some content was found.
+
+\newif\iffileprocessed
+
+\let\fileline\empty
+
+\def\doprocessfile#1#2#3%
+ {\openinputfile{#1}{#2}%
+ \ifeof#1%
+ \fileprocessedfalse
+ \closeinputfile#1%
+ \else
+ \fileprocessedtrue
+ \gdef\dofinishfile
+ {\closeinputfile#1%
+ \global\let\doprocessline\relax}%
+ \gdef\doprocessline
+ {\ifeof#1%
+ \expandafter\dofinishfile
+ \else
+ \global\read#1 to \fileline
+ #3\relax
+ \expandafter\doprocessline
+ \fi}%
+ \expandafter\doprocessline
+ \fi}
+
+%D \macros
+%D {pathplusfile,assignfullfilename,sanitizefilename}
+%D
+%D Use \type{\pathplusfile} to compose a full file name, like
+%D in:
+%D
+%D \starttyping
+%D \pathplusfile{path}{file}
+%D \stoptyping
+%D
+%D By default, this expands into {\tt \pathplusfile{path}{file}}.
+
+\def\pathplusfile#1#2{#1\f!pathseparator#2}
+
+%D This one constructs a filename from a (possible empty)
+%D path and filename.
+
+\def\assignfullfilename#1#2\to#3%
+ {\doifelsenothing{#1}
+ {\edef#3{#2}}
+ {\edef#3{#1\f!pathseparator#2}}}
\def\sanitizefilename#1\to#2{\edef#2{\ctxlua{support.thesanitizedfilename([[#1]])}}}
-\def\checkfilename #1{\ctxlua{support.checkfilename([[#1]])}}
-\def\splitfilename #1{\ctxlua{support.splitfilename([[#1]])}}
-\def\splitfiletype #1{\ctxlua{support.splitfiletype([[#1]])}}
-\def\doifparentfileelse #1{\ctxlua{support.doifparentfileelse([[#1]])}}
-\def\doiffileexistselse #1{\ctxlua{support.doiffileexistelse([[#1]])}}
-\endinput
+%D NEW:
+
+\chardef\kindoffile=0 % 0=normal 1=full path spec (or http) / set at the lua end
+
+\def\checkfilename#1{\ctxlua{support.checkfilename([[#1]])}}
+
+%D \macros
+%D {input, normalinput}
+%D
+%D Sometimes we run into troubles when \type {\input} wants to get
+%D expanded, e.g. in a \type {\write} (which happens in the metafun
+%D manual when we permit long MP lines). So, instead of fixing that,
+%D we go for a redefinition of \type {\input}. Of course it's better
+%D to use \type {\readfile} or \type {\processfile}.
+
+\unexpanded\def\input{\normalinput}
+
+\def\inputgivenfile#1{\normalinput"#1"\relax}
+
+%D \macros
+%D {readfile,ReadFile,maxreadlevel}
+%D
+%D One cannot be sure if a file exists. When no file can be
+%D found, the \type{\input} primitive gives an error message
+%D and switches to interactive mode. The macro \type{\readfile}
+%D takes care of non||existing files. This macro has two faces.
+%D
+%D \starttyping
+%D \ReadFile {filename}
+%D \readfile {filename} {before loading} {not found}
+%D \stoptyping
+%D
+%D Many \TEX\ implementations have laid out some strategy for
+%D locating files. This can lead to unexpected results,
+%D especially when one loads files that are not found in the
+%D current directory. Let's give an example of this. In
+%D \CONTEXT\ illustrations can be defined in an external file.
+%D The resizing macro first looks if an illustration is defined
+%D in the local definitions file. When no such file is found,
+%D it searches for a global file and when this file is not
+%D found either, the illustration itself is scanned for
+%D dimensions. One can imagine what happens if an adapted,
+%D localy stored illustration, is scaled according to
+%D dimensions stored somewhere else.
+%D
+%D When some \TEX\ implementation starts looking for a file, it
+%D normally first looks in the current directory. When no file
+%D is found, \TEX\ starts searching on the path where format
+%D and|/|or style files are stored. Depending on the implementation
+%D this can considerably slow down processing speed.
+%D
+%D In \CONTEXT, we support a project||wise ordening of files.
+%D In such an approach it seems feasible to store common files
+%D in a lower directory. When for instance searching for a
+%D general layout file, we therefore have to backtrack.
+%D
+%D These three considerations have lead to a more advanced
+%D approach for loading files.
+%D
+%D We first present an earlier implementation of
+%D \type{\readfile}. This command backtracks parent
+%D directories, upto a predefined level. Users can change this
+%D level, but we default to~3.
+%D
+%D \starttyping
+%D \def\maxreadlevel {3}
+%D \stoptyping
+%D
+%D This is a pseudo \COUNTER.
+%D
+%D We use \type{\normalinput} instead of \type{\input}
+%D because we want to be able to redefine the original
+%D \type{\input} when needed, for instance when loading third
+%D party libraries.
+
+\newevery \everybeforereadfile \EveryBeforeReadFile
+\newevery \everyafterreadfile \EveryAfterReadFile
+
+\let \everyreadfile \everybeforereadfile
+
+\newif\iftracefiles
+
+\newcount\readlevel
+
+\def\maxreadlevel{3}
+
+\newconditional\trackfilenames
+\let\trackedfilename\empty
+
+% We need to postpone loading, else we got frozen type-* files and so when
+% a format is generated on a source path.
+
+\def\doreadfile#1#2#3#4%
+ {\sanitizefilename#2\to\readfilename
+ \ifx\readfilename\empty
+ % silently ignore
+ \else
+ \let\trackedfilename\readfilename
+ \ifconditional\trackfilenames
+ \doifundefinedelse{fn..\trackedfilename}\donetrue\donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \iftracefiles\writestatus\m!systems{searching for \readfilename\space on #1}\fi
+ % not a full path or url, check for existence
+ \doifelsenothing{#1}
+ {\def\next{\redoreadfile\readfilename{#3}{#4}}}%
+ {\def\next{\redoreadfile{\pathplusfile{#1}{\readfilename}}{#3}{#4}}}%
+ \else
+ % a full path or url, no further checking done
+ \doiffileexistselse\readfilename
+ {\iftracefiles\writestatus\m!systems{located \readfilename}\fi
+ \def\next{#3\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{not found \readfilename}\fi
+ \def\next{#4}}%
+ \fi
+ \else
+ \edef\readfilename{\getvalue{fn..\readfilename}}%
+ \iftracefiles\writestatus\m!systems{already located \readfilename}\fi
+ \def\next{#3\dodoreadfile}%
+ \fi
+ \expandafter\next
+ \fi}
+
+\def\redoreadfile#1#2#3%
+ {\doiffileexistselse{#1}%
+ {\edef\readfilename{#1}%
+ \iftracefiles\writestatus\m!systems{#1 located}\fi
+ \def\next{#2\dodoreadfile}}%
+ {\iftracefiles\writestatus\m!systems{cannot locate #1}\fi
+ \advance\readlevel\minusone
+ \ifnum\readlevel>\zerocount
+ \edef\readfilename{\pathplusfile{\f!parentpath}{\readfilename}}%
+ \def\next{\redoreadfile\readfilename{#2}{#3}}%
+ \else
+ \def\next{#3}%
+ \fi}%
+ \next}
+
+\def\dodoreadfile % we provide hooks, for instance for \enableXML
+ {\ifconditional\trackfilenames
+ \setxvalue{fn..\trackedfilename}{\readfilename}%
+ \fi
+ \the\everybeforereadfile
+ \relax\inputgivenfile\readfilename\relax
+ \the\everyafterreadfile}
+
+% too less:
+%
+% \unexpanded\def\readfile% #1%
+% {\readlevel\maxreadlevel
+% \doreadfile\empty} % {#1}
+%
+% too much:
+%
+% \unexpanded\def\readfile#1#2#3%
+% {\readlocfile{#1}{#2}
+% {\readjobfile{#1}{#2}
+% {\readsysfile{#1}{#2}{#3}}}}
+%
+% just ok:
+
+\unexpanded\def\readfile#1#2#3%
+ {\readlocfile{#1}{#2}{\readsysfile{#1}{#2}{#3}}}
+
+\def\readtexfile#1#2#3%
+ {\pushcatcodetable \catcodetable \ctxcatcodes
+ \readfile{#1}{#2}{#3}%
+ \popcatcodetable}
+
+\def\readxmlfile#1#2#3%
+ {\pushcatcodetable \catcodetable \xmlcatcodes
+ \readfile{#1}{#2}{#3}%
+ \popcatcodetable}
+
+\unexpanded\def\ReadFile#1%
+ {\readfile{#1}\donothing\donothing}
+
+%D \macros
+%D {readjobfile,readlocfile,readsysfile,
+%D readfixfile,readsetfile}
+%D
+%D This implementation honnors the third situation, but we
+%D still can get unwanted files loaded and/or can get involved
+%D in extensive searching.
+%D
+%D Due to different needs, we decided to offer four alternative
+%D loading commands. With \type{\readjobfile} we load a local
+%D file and do no backtracking, while \type{\readlocfile}
+%D backtracks~\number\readlevel\ directories, including the current
+%D one.
+
+\unexpanded\def\readjobfile % #1% current path, no backtracking
+ {\readlevel\zerocount
+ \doreadfile\f!currentpath} % {#1}}
+
+\unexpanded\def\readlocfile % #1% current path, backtracking
+ {\readlevel\maxreadlevel
+ \doreadfile\f!currentpath} % {#1}}
+
+%D System files can be anywhere and therefore
+%D \type{\readsysfile} is not bound to the current directory
+%D and obeys the \TEX\ implementation.
+
+\unexpanded\def\readsysfile % #1% current path, obeys tex search
+ {\readlevel\zerocount
+ \doreadfile\empty} % {#1}}
+
+%D Of the last two, \type{\readfixfile} searches on the
+%D directory specified and backtracks too, while
+%D \type{\readsetfile} does only search on the specified path.
+
+\unexpanded\def\readfixfile % #1#2% specified path, backtracking
+ {\readlevel\maxreadlevel
+ \doreadfile} % {#1}{#2}}
+
+\unexpanded\def\readsetfile % #1#2% specified path, no backtracking
+ {\readlevel\zerocount
+ \doreadfile} % {#1}{#2}}
+
+%D After having defined this commands, we reconsidered the
+%D previously defined \type{\readfile}. This time we more or
+%D less impose the search order.
+
+\unexpanded\def\readfile#1#2#3%
+ {\readlocfile{#1}{#2}
+ {\readjobfile{#1}{#2}
+ {\readsysfile{#1}{#2}{#3}}}}
+
+%D So now we've got ourselves five file loading commands:
+%D
+%D \starttyping
+%D \readfile {filename} {before loading} {not found}
+%D
+%D \readjobfile {filename} {before loading} {not found}
+%D \readlocfile {filename} {before loading} {not found}
+%D \readfixfile {filename} {before loading} {not found}
+%D \readsysfile {directory} {filename} {before loading} {not found}
+%D \stoptyping
+
+%D \macros
+%D {readjobfile,readlocfile,readsysfile,readfixfile}
+%D
+%D The next four alternatives can be used for opening files
+%D for reading on a line||by||line basis. These commands get
+%D an extra argument, the filetag. Explicit closing is done
+%D in the normal way by \type{\closein}.
+
+\def\doopenin#1#2%
+ {\sanitizefilename#2\to\readfilename
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \advance\readlevel\plusone
+ \openinputfile{#1}\readfilename
+ \ifeof#1% \relax
+ \ifnum\readlevel>\maxreadlevel % \relax
+ \else
+ \closeinputfile#1% \relax
+ \doopenin{#1}{\pathplusfile\f!parentpath{#2}}%
+ \fi
+ \fi
+ \fi}
+
+\def\openjobin#1#2%
+ {\readlevel\zerocount
+ \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
+
+\def\opensysin % #1#2%
+ {\readlevel\maxreadlevel
+ \doopenin} % {#1}{#2}}
+
+\def\openlocin#1#2%
+ {\readlevel\maxreadlevel
+ \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
+
+\def\openfixin#1#2#3%
+ {\readlevel\maxreadlevel
+ \doopenin{#1}{\pathplusfile{#2}{#3}}}
+
+%D \macros
+%D {doiffileelse,doiflocfileelse}
+%D
+%D The next alternative only looks if a file is present. No
+%D loading is done. This one obeys the standard \TEX\
+%D implementation method.
+%D
+%D \starttyping
+%D \doiffileelse {filename} {found} {not found}
+%D \stoptyping
+%D
+%D \starttyping
+%D \doiflocfileelse {filename} {before loading} {not found}
+%D \stoptyping
+
+\def\doiffileelse {\doiffileexistselse}
+\def\doiffile #1{\doiffileexistselse{#1}\firstofoneargument\gobbleoneargument}
+\def\doifnotfile #1{\doiffileexistselse{#1}\gobbleoneargument\firstofoneargument}
+
+\def\doiflocfileelse#1%
+ {\makelocreadfilename{#1}%
+ \doiffileelse\readfilename}
+
+\def\makelocreadfilename#1%
+ {\sanitizefilename#1\to\readfilename
+ \checkfilename\readfilename
+ \ifcase\kindoffile
+ \edef\readfilename{\pathplusfile\f!currentpath{#1}}%
+ \fi}
+
+%D \macros
+%D {doonlyonce, doinputonce, doendinputonce}
+%D
+%D Especially macropackages need only be loaded once.
+%D Repetitive loading not only costs time, relocating registers
+%D often leads to abortion of the processing because \TEX's
+%D capacity is limited. One can prevent multiple execution and
+%D loading by using one of both:
+%D
+%D \starttyping
+%D \doonlyonce{actions}
+%D \doinputonce{filename}
+%D \doendinputonce{filename}
+%D \stoptyping
+%D
+%D This command obeys the standard method for locating files.
+
+\long\def\doonlyonce#1%
+ {\doifundefinedelse{@@@#1@@@}
+ {\letgvalue{@@@#1@@@}\empty
+ \firstofoneargument}
+ {\gobbleoneargument}}
+
+\def\doinputonce#1%
+ {\doonlyonce{#1}{\doiffileelse{#1}{\inputgivenfile{#1}}\donothing}}
+
+\def\doendinputonce#1%
+ {\doifdefined{@@@#1@@@}\endinput}
+
+\def\forgetdoingonce#1%
+ {\global\letbeundefined{@@@#1@@@}}
+
+%D \macros
+%D {doifparentfileelse}
+%D
+%D The test \type{\doifelse{\jobname}{filename}} does not give
+%D the desired result, simply because \type{\jobname} expands
+%D to characters with \CATCODE~12, while the characters in
+%D \type{filename} have \CATCODE~11. So we can better use:
+%D
+%D \starttyping
+%D \doifparentfileelse{filename}{yes}{no}
+%D \stoptyping
+%D
+%D Since \TEXEXEC\ (and thereby \CONTEXT) supports renaming of
+%D the outputfile, we also need to check on that alternative
+%D name.
+
+\ifx\outputfilename\undefined \def\outputfilename{\jobname} \fi
+
+\def\doifparentfileelse#1{\ctxlua{support.doifparentfileelse([[#1]])}}
+
+\def\normalless {<} % geen \let !
+\def\normalmore {>} % geen \let !
+\def\normalequal {=} % geen \let !
+\def\normaldblquote{"} % geen \let !
+
+\newcount\readingfilelevel
+
+\def\popfilecharacter#1#2%
+ {\ifnum\catcode`#1=\@@other \ifnum#2=\@@other \else
+ %\message{[popping catcode #1 to #2]}%
+ \catcode`#1=#2\relax
+ \fi \fi}
+
+\ifx\\\undefined \let\\\relax \fi
+
+%D This changing catcodes is a direct result from the fact
+%D that we support some long standing conventions with
+%D regards to active characters (german ", polish /,
+%D french : and ;).
+
+%D We need to redo this: catcode sets and such
+
+\newtoks \everystartreadingfile
+\newtoks \everystopreadingfile
+
+\def\startreadingfile% beter een every en \setnormalcatcodes
+ {\global\advance\readingfilelevel\plusone
+ \the\everystartreadingfile
+ \beginrestorecatcodes
+ \setcatcodetable\prtcatcodes}
+
+\def\stopreadingfile
+ {\endrestorecatcodes
+ \the\everystopreadingfile
+ \global\advance\readingfilelevel\minusone}
+
+\let\normalstartreadingfile\startreadingfile
+\let\normalstopreadingfile \stopreadingfile
+
+%D \macros
+%D {splitfilename}
+%D
+%D I should have made this one sooner. This macro was first needed when
+%D ran into graphic with a period in the pathpart.
+%D
+%D \startbuffer
+%D \def\showfilesplit
+%D {\bgroup \tttf
+%D \hbox{(full: \splitofffull)}\space
+%D \hbox{(path: \splitoffpath)}\space
+%D \hbox{(base: \splitoffbase)}\space
+%D \hbox{(name: \splitoffname)}\space
+%D \hbox{(type: \splitofftype)}\space
+%D \egroup}
+%D
+%D \splitfilename{c:/aa/bb/cc/dd.ee.ff} \showfilesplit \endgraf
+%D \splitfilename{c:/aa/bb/cc/dd.ee} \showfilesplit \endgraf
+%D \splitfilename{c:/aa/bb/cc/dd} \showfilesplit \endgraf
+%D
+%D \splitfilename{dd.ee.ff} \showfilesplit \endgraf
+%D \splitfilename{dd.ee} \showfilesplit \endgraf
+%D \splitfilename{dd} \showfilesplit \endgraf
+%D \stopbuffer
+%D
+%D \start \typebuffer \getbuffer \stop
+
+\def\splitoffroot{.} \chardef\splitoffkind\zerocount
+
+\let\splitofffull\empty
+\let\splitoffpath\empty
+\let\splitoffbase\empty
+\let\splitoffname\empty
+\let\splitofftype\empty
+
+\def\splitfilename#1{\ctxlua{support.splitfilename([[#1]])}}
+\def\splitfiletype#1{\ctxlua{support.splitfiletype([[#1]])}}
+
+\protect \endinput
diff --git a/tex/context/base/supp-fil.tex b/tex/context/base/supp-fil.tex
deleted file mode 100644
index 4d31bfd28..000000000
--- a/tex/context/base/supp-fil.tex
+++ /dev/null
@@ -1,655 +0,0 @@
-%D \module
-%D [ file=supp-fil,
-%D version=1995.10.10,
-%D title=\CONTEXT\ Support Macros,
-%D subtitle=Files,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D \TEX\ operates on files, so one wouldn't wonder that there
-%D is a separate module for file support. In \CONTEXT\ files
-%D are used for several purposes:
-%D
-%D \startitemize[packed]
-%D \item general textual input
-%D \item logging status information
-%D \item saving registers, lists and references
-%D \item buffering defered textual input
-%D \stopitemize
-%D
-%D When dealing with files we can load them as a whole, using
-%D the \type{\input} primitive or load them on a line||by||line
-%D basis, using \type{\read}. Writing is always done line by
-%D line, using \type{\write}.
-
-\writestatus{loading}{Context Support Macros / Files}
-
-\unprotect
-
-\ifx\undefined\f!pathseparator
- \def\f!pathseparator{/}
- \def\f!currentpath {.}
- \def\f!parentpath {..}
-\fi
-
-%D \macros
-%D {normalwrite, normalimmediate}
-%D
-%D We save a few primitives first.
-
-\let\normalwrite \write
-\let\normalimmediate\immediate
-
-% \def\openinputfile #1#2{\immediate\openin #1="#2"\relax} \def\closeinputfile #1{\immediate\closein #1}
-% \def\openoutputfile#1#2{\immediate\openout#1="#2"\relax} \def\closeoutputfile#1{\immediate\closeout#1}
-
-\def\openinputfile #1#2{\immediate\openin #1=#2\relax} \def\closeinputfile #1{\immediate\closein #1}
-\def\openoutputfile#1#2{\immediate\openout#1=#2\relax} \def\closeoutputfile#1{\immediate\closeout#1}
-
-%D \macros
-%D {pushendofline,popendofline}
-%D
-%D When we are loading files in the middle of the typesetting
-%D process, for instance when we load references, we have to be
-%D sure that the reading process does not generate so called
-%D 'spurious spaces'. This can be prevented by assigning the
-%D line ending character the \CATCODE\ comment. This is
-%D accomplished by
-%D
-%D \starttyping
-%D \pushendofline
-%D ... reading ...
-%D \popendofline
-%D \stoptyping
-%D
-%D Just to be sure, we save the current meaning of \type{^^M}
-%D in \type{\poppedendofline}.
-
-% \chardef\poppedendofline\catcode`\^^M
-%
-% \def\pushendofline
-% {\chardef\poppedendofline\catcode`\^^M\relax
-% \catcode`\^^M\@@comment\relax}
-%
-% \def\popendofline
-% {\catcode`\^^M\poppedendofline}
-%
-% support for nested usage:
-
-\newcount \endoflinelevel
-
-\ifx\newlinecode\undefined \chardef\newlinecode=`\^^M \fi
-
-\def\pushendofline
- {\advance\endoflinelevel\plusone
- \expandafter\chardef\csname :eol:\number\endoflinelevel\endcsname\catcode\newlinecode
- \catcode\newlinecode\@@comment\relax}
-
-\def\popendofline
- {\catcode\newlinecode\csname :eol:\number\endoflinelevel\endcsname
- \advance\endoflinelevel\minusone}
-
-\def\restoreendofline
- {\catcode\newlinecode\@@endofline}
-
-%D \macros
-%D {scratchread, scratchwrite}
-%D
-%D We define a scratch file for reading. Keep in mind that
-%D the number of files is limited to~16, so use this one when
-%D possible. We also define a scratch output file.
-
-\ifx\undefined\scratchread \newread \scratchread \fi
-\ifx\undefined\scratchwrite \newwrite\scratchwrite \fi
-
-%D \macros
-%D {unlinkfile}
-%D
-%D Sometimes we want to make sure a file is deleted, so here
-%D is a macro that does the job. It's named after the \PERL\
-%D one.
-
-\def\unlinkfile#1%
- {\openoutputfile \scratchwrite{#1}%
- \closeoutputfile\scratchwrite}
-
-%D \macros
-%D {writeln}
-%D
-%D This saves a few tokens:
-
-\def\writeln#1{\write#1{}}
-
-\def\doiffileexistselse#1%
- {\doifelsenothing{#1}
- {\secondoftwoarguments}
- {\openinputfile\scratchread{#1}%
- \ifeof\scratchread
- \closeinputfile\scratchread
- \expandafter\secondoftwoarguments
- \else
- \closeinputfile\scratchread
- \expandafter\firstoftwoarguments
- \fi}}
-
-%D \macros
-%D {doprocessfile,fileline,fileprocessedtrue,dofinishfile}
-%D
-%D The next macro offers a framework for processing files on a
-%D line by line basis.
-%D
-%D \starttyping
-%D \doprocessfile \identifier {name} \action
-%D \stoptyping
-%D
-%D The first argument can for instance be \type{\scratchread}.
-%D The action must do something with \type{\fileline}, which
-%D holds the current line. One can halfway step out using
-%D \type{\dofinishfile} and ise \type{\iffileprocessed} to
-%D see if indeed some content was found.
-
-\newif\iffileprocessed
-
-\let\fileline\empty
-
-\def\doprocessfile#1#2#3%
- {\openinputfile{#1}{#2}%
- \ifeof#1%
- \fileprocessedfalse
- \closeinputfile#1%
- \else
- \fileprocessedtrue
- \gdef\dofinishfile
- {\closeinputfile#1%
- \global\let\doprocessline\relax}%
- \gdef\doprocessline
- {\ifeof#1%
- \expandafter\dofinishfile
- \else
- \global\read#1 to \fileline
- #3\relax
- \expandafter\doprocessline
- \fi}%
- \expandafter\doprocessline
- \fi}
-
-%D \macros
-%D {pathplusfile,assignfullfilename,sanitizefilename}
-%D
-%D Use \type{\pathplusfile} to compose a full file name, like
-%D in:
-%D
-%D \starttyping
-%D \pathplusfile{path}{file}
-%D \stoptyping
-%D
-%D By default, this expands into {\tt \pathplusfile{path}{file}}.
-
-\def\pathplusfile#1#2{#1\f!pathseparator#2}
-
-%D This one constructs a filename from a (possible empty)
-%D path and filename.
-
-\def\assignfullfilename#1#2\to#3%
- {\doifelsenothing{#1}
- {\edef#3{#2}}
- {\edef#3{#1\f!pathseparator#2}}}
-
-\def\sanitizefilename#1\to#2{\def#2{#1}} % overloaded in mk
-
-%D NEW:
-
-\chardef\kindoffile=0 % 0=normal 1=full path spec (or http)
-
-\def\checkfilename{\chardef\kindoffile\zerocount} % overloaded in mk
-
-%D \macros
-%D {input, normalinput}
-%D
-%D Sometimes we run into troubles when \type {\input} wants to get
-%D expanded, e.g. in a \type {\write} (which happens in the metafun
-%D manual when we permit long MP lines). So, instead of fixing that,
-%D we go for a redefinition of \type {\input}. Of course it's better
-%D to use \type {\readfile} or \type {\processfile}.
-
-\ifx\normalinput\undefined \let\normalinput\input \fi
-
-\unexpanded\def\input{\normalinput}
-
-\def\inputgivenfile#1{\normalinput"#1"\relax}
-
-%D \macros
-%D {readfile,ReadFile,maxreadlevel}
-%D
-%D One cannot be sure if a file exists. When no file can be
-%D found, the \type{\input} primitive gives an error message
-%D and switches to interactive mode. The macro \type{\readfile}
-%D takes care of non||existing files. This macro has two faces.
-%D
-%D \starttyping
-%D \ReadFile {filename}
-%D \readfile {filename} {before loading} {not found}
-%D \stoptyping
-%D
-%D Many \TEX\ implementations have laid out some strategy for
-%D locating files. This can lead to unexpected results,
-%D especially when one loads files that are not found in the
-%D current directory. Let's give an example of this. In
-%D \CONTEXT\ illustrations can be defined in an external file.
-%D The resizing macro first looks if an illustration is defined
-%D in the local definitions file. When no such file is found,
-%D it searches for a global file and when this file is not
-%D found either, the illustration itself is scanned for
-%D dimensions. One can imagine what happens if an adapted,
-%D localy stored illustration, is scaled according to
-%D dimensions stored somewhere else.
-%D
-%D When some \TEX\ implementation starts looking for a file, it
-%D normally first looks in the current directory. When no file
-%D is found, \TEX\ starts searching on the path where format
-%D and|/|or style files are stored. Depending on the implementation
-%D this can considerably slow down processing speed.
-%D
-%D In \CONTEXT, we support a project||wise ordening of files.
-%D In such an approach it seems feasible to store common files
-%D in a lower directory. When for instance searching for a
-%D general layout file, we therefore have to backtrack.
-%D
-%D These three considerations have lead to a more advanced
-%D approach for loading files.
-%D
-%D We first present an earlier implementation of
-%D \type{\readfile}. This command backtracks parent
-%D directories, upto a predefined level. Users can change this
-%D level, but we default to~3.
-%D
-%D \starttyping
-%D \def\maxreadlevel {3}
-%D \stoptyping
-%D
-%D This is a pseudo \COUNTER.
-%D
-%D We use \type{\normalinput} instead of \type{\input}
-%D because we want to be able to redefine the original
-%D \type{\input} when needed, for instance when loading third
-%D party libraries.
-
-\newevery \everybeforereadfile \EveryBeforeReadFile
-\newevery \everyafterreadfile \EveryAfterReadFile
-
-\let \everyreadfile \everybeforereadfile
-
-\newif\iftracefiles
-
-\newcount\readlevel
-
-\def\maxreadlevel{3}
-
-\newconditional\trackfilenames
-
-% We need to postpone loading, else we got frozen type-* files and so when
-% a format is generated on a source path.
-
-\appendtoks \settrue\trackfilenames \to \everyjob
-
-\let\trackedfilename\empty
-
-\def\doreadfile#1#2#3#4%
- {\sanitizefilename#2\to\readfilename
- \ifx\readfilename\empty
- % silently ignore
- \else
- \let\trackedfilename\readfilename
- \ifconditional\trackfilenames
- \doifundefinedelse{fn..\trackedfilename}\donetrue\donefalse
- \else
- \donetrue
- \fi
- \ifdone
- \checkfilename\readfilename
- \ifcase\kindoffile
- \iftracefiles\writestatus\m!systems{searching for \readfilename\space on #1}\fi
- % not a full path or url, check for existence
- \doifelsenothing{#1}
- {\def\next{\redoreadfile\readfilename{#3}{#4}}}%
- {\def\next{\redoreadfile{\pathplusfile{#1}{\readfilename}}{#3}{#4}}}%
- \else
- % a full path or url, no further checking done
- \doiffileexistselse\readfilename
- {\iftracefiles\writestatus\m!systems{located \readfilename}\fi
- \def\next{#3\dodoreadfile}}%
- {\iftracefiles\writestatus\m!systems{not found \readfilename}\fi
- \def\next{#4}}%
- \fi
- \else
- \edef\readfilename{\getvalue{fn..\readfilename}}%
- \iftracefiles\writestatus\m!systems{already located \readfilename}\fi
- \def\next{#3\dodoreadfile}%
- \fi
- \expandafter\next
- \fi}
-
-\def\redoreadfile#1#2#3%
- {\doiffileexistselse{#1}%
- {\edef\readfilename{#1}%
- \iftracefiles\writestatus\m!systems{#1 located}\fi
- \def\next{#2\dodoreadfile}}%
- {\iftracefiles\writestatus\m!systems{cannot locate #1}\fi
- \advance\readlevel\minusone
- \ifnum\readlevel>\zerocount
- \edef\readfilename{\pathplusfile{\f!parentpath}{\readfilename}}%
- \def\next{\redoreadfile\readfilename{#2}{#3}}%
- \else
- \def\next{#3}%
- \fi}%
- \next}
-
-\def\dodoreadfile % we provide hooks, for instance for \enableXML
- {\ifconditional\trackfilenames
- \setxvalue{fn..\trackedfilename}{\readfilename}%
- \fi
- \the\everybeforereadfile
-% \normalinput\readfilename\relax
- \relax\inputgivenfile\readfilename\relax
- \the\everyafterreadfile}
-
-% too less:
-%
-% \unexpanded\def\readfile% #1%
-% {\readlevel\maxreadlevel
-% \doreadfile\empty} % {#1}
-%
-% too much:
-%
-% \unexpanded\def\readfile#1#2#3%
-% {\readlocfile{#1}{#2}
-% {\readjobfile{#1}{#2}
-% {\readsysfile{#1}{#2}{#3}}}}
-%
-% just ok:
-
-\unexpanded\def\readfile#1#2#3%
- {\readlocfile{#1}{#2}{\readsysfile{#1}{#2}{#3}}}
-
-\def\readtexfile#1#2#3%
- {\pushcatcodetable \catcodetable \ctxcatcodes
- \readfile{#1}{#2}{#3}%
- \popcatcodetable}
-
-\def\readxmlfile#1#2#3%
- {\pushcatcodetable \catcodetable \xmlcatcodes
- \readfile{#1}{#2}{#3}%
- \popcatcodetable}
-
-\unexpanded\def\ReadFile#1%
- {\readfile{#1}\donothing\donothing}
-
-%D \macros
-%D {readjobfile,readlocfile,readsysfile,
-%D readfixfile,readsetfile}
-%D
-%D This implementation honnors the third situation, but we
-%D still can get unwanted files loaded and/or can get involved
-%D in extensive searching.
-%D
-%D Due to different needs, we decided to offer four alternative
-%D loading commands. With \type{\readjobfile} we load a local
-%D file and do no backtracking, while \type{\readlocfile}
-%D backtracks~\number\readlevel\ directories, including the current
-%D one.
-
-\unexpanded\def\readjobfile % #1% current path, no backtracking
- {\readlevel\zerocount
- \doreadfile\f!currentpath} % {#1}}
-
-\unexpanded\def\readlocfile % #1% current path, backtracking
- {\readlevel\maxreadlevel
- \doreadfile\f!currentpath} % {#1}}
-
-%D System files can be anywhere and therefore
-%D \type{\readsysfile} is not bound to the current directory
-%D and obeys the \TEX\ implementation.
-
-\unexpanded\def\readsysfile % #1% current path, obeys tex search
- {\readlevel\zerocount
- \doreadfile\empty} % {#1}}
-
-%D Of the last two, \type{\readfixfile} searches on the
-%D directory specified and backtracks too, while
-%D \type{\readsetfile} does only search on the specified path.
-
-\unexpanded\def\readfixfile % #1#2% specified path, backtracking
- {\readlevel\maxreadlevel
- \doreadfile} % {#1}{#2}}
-
-\unexpanded\def\readsetfile % #1#2% specified path, no backtracking
- {\readlevel\zerocount
- \doreadfile} % {#1}{#2}}
-
-%D After having defined this commands, we reconsidered the
-%D previously defined \type{\readfile}. This time we more or
-%D less impose the search order.
-
-\unexpanded\def\readfile#1#2#3%
- {\readlocfile{#1}{#2}
- {\readjobfile{#1}{#2}
- {\readsysfile{#1}{#2}{#3}}}}
-
-%D So now we've got ourselves five file loading commands:
-%D
-%D \starttyping
-%D \readfile {filename} {before loading} {not found}
-%D
-%D \readjobfile {filename} {before loading} {not found}
-%D \readlocfile {filename} {before loading} {not found}
-%D \readfixfile {filename} {before loading} {not found}
-%D \readsysfile {directory} {filename} {before loading} {not found}
-%D \stoptyping
-
-%D \macros
-%D {readjobfile,readlocfile,readsysfile,readfixfile}
-%D
-%D The next four alternatives can be used for opening files
-%D for reading on a line||by||line basis. These commands get
-%D an extra argument, the filetag. Explicit closing is done
-%D in the normal way by \type{\closein}.
-
-\def\doopenin#1#2%
- {\sanitizefilename#2\to\readfilename
- \checkfilename\readfilename
- \ifcase\kindoffile
- \advance\readlevel\plusone
- \openinputfile{#1}\readfilename
- \ifeof#1% \relax
- \ifnum\readlevel>\maxreadlevel % \relax
- \else
- \closeinputfile#1% \relax
- \doopenin{#1}{\pathplusfile\f!parentpath{#2}}%
- \fi
- \fi
- \fi}
-
-\def\openjobin#1#2%
- {\readlevel\zerocount
- \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
-
-\def\opensysin % #1#2%
- {\readlevel\maxreadlevel
- \doopenin} % {#1}{#2}}
-
-\def\openlocin#1#2%
- {\readlevel\maxreadlevel
- \doopenin{#1}{\pathplusfile\f!currentpath{#2}}}
-
-\def\openfixin#1#2#3%
- {\readlevel\maxreadlevel
- \doopenin{#1}{\pathplusfile{#2}{#3}}}
-
-%D \macros
-%D {doiffileelse,doiflocfileelse}
-%D
-%D The next alternative only looks if a file is present. No
-%D loading is done. This one obeys the standard \TEX\
-%D implementation method.
-%D
-%D \starttyping
-%D \doiffileelse {filename} {found} {not found}
-%D \stoptyping
-%D
-%D \starttyping
-%D \doiflocfileelse {filename} {before loading} {not found}
-%D \stoptyping
-
-\def\doiffileelse {\doiffileexistselse}
-\def\doiffile #1{\doiffileexistselse{#1}\firstofoneargument\gobbleoneargument}
-\def\doifnotfile #1{\doiffileexistselse{#1}\gobbleoneargument\firstofoneargument}
-
-\def\doiflocfileelse#1%
- {\makelocreadfilename{#1}%
- \doiffileelse\readfilename}
-
-\def\makelocreadfilename#1%
- {\sanitizefilename#1\to\readfilename
- \checkfilename\readfilename
- \ifcase\kindoffile
- \edef\readfilename{\pathplusfile\f!currentpath{#1}}%
- \fi}
-
-%D \macros
-%D {doonlyonce, doinputonce, doendinputonce}
-%D
-%D Especially macropackages need only be loaded once.
-%D Repetitive loading not only costs time, relocating registers
-%D often leads to abortion of the processing because \TEX's
-%D capacity is limited. One can prevent multiple execution and
-%D loading by using one of both:
-%D
-%D \starttyping
-%D \doonlyonce{actions}
-%D \doinputonce{filename}
-%D \doendinputonce{filename}
-%D \stoptyping
-%D
-%D This command obeys the standard method for locating files.
-
-\long\def\doonlyonce#1%
- {\doifundefinedelse{@@@#1@@@}
- {\letgvalue{@@@#1@@@}\empty
- \firstofoneargument}
- {\gobbleoneargument}}
-
-\def\doinputonce#1%
-% {\doonlyonce{#1}{\doiffileelse{#1}{\normalinput#1\relax}\donothing}}
- {\doonlyonce{#1}{\doiffileelse{#1}{\inputgivenfile{#1}}\donothing}}
-
-\def\doendinputonce#1%
- {\doifdefined{@@@#1@@@}\endinput}
-
-\def\forgetdoingonce#1%
- {\global\letbeundefined{@@@#1@@@}}
-
-%D \macros
-%D {doifparentfileelse}
-%D
-%D The test \type{\doifelse{\jobname}{filename}} does not give
-%D the desired result, simply because \type{\jobname} expands
-%D to characters with \CATCODE~12, while the characters in
-%D \type{filename} have \CATCODE~11. So we can better use:
-%D
-%D \starttyping
-%D \doifparentfileelse{filename}{yes}{no}
-%D \stoptyping
-%D
-%D Since \TEXEXEC\ (and thereby \CONTEXT) supports renaming of
-%D the outputfile, we also need to check on that alternative
-%D name.
-
-\ifx\outputfilename\undefined \def\outputfilename{\jobname} \fi
-
-\let\doifparentfileelse\gobblethreearguments % defined in mk
-
-\def\normalless {<} % geen \let !
-\def\normalmore {>} % geen \let !
-\def\normalequal {=} % geen \let !
-\def\normaldblquote{"} % geen \let !
-
-\newcount\readingfilelevel
-
-\def\popfilecharacter#1#2%
- {\ifnum\catcode`#1=\@@other \ifnum#2=\@@other \else
- %\message{[popping catcode #1 to #2]}%
- \catcode`#1=#2\relax
- \fi \fi}
-
-\ifx\\\undefined \let\\\relax \fi
-
-%D This changing catcodes is a direct result from the fact
-%D that we support some long standing conventions with
-%D regards to active characters (german ", polish /,
-%D french : and ;).
-
-%D We need to redo this: catcode sets and such
-
-\newtoks \everystartreadingfile
-\newtoks \everystopreadingfile
-
-\def\startreadingfile% beter een every en \setnormalcatcodes
- {\global\advance\readingfilelevel\plusone
- \the\everystartreadingfile
- \beginrestorecatcodes
- \setcatcodetable\prtcatcodes}
-
-\def\stopreadingfile
- {\endrestorecatcodes
- \the\everystopreadingfile
- \global\advance\readingfilelevel\minusone}
-
-\let\normalstartreadingfile\startreadingfile
-\let\normalstopreadingfile \stopreadingfile
-
-%D \macros
-%D {splitfilename}
-%D
-%D I should have made this one sooner. This macro was first needed when
-%D ran into graphic with a period in the pathpart.
-%D
-%D \startbuffer
-%D \def\showfilesplit
-%D {\bgroup \tttf
-%D \hbox{(full: \splitofffull)}\space
-%D \hbox{(path: \splitoffpath)}\space
-%D \hbox{(base: \splitoffbase)}\space
-%D \hbox{(name: \splitoffname)}\space
-%D \hbox{(type: \splitofftype)}\space
-%D \egroup}
-%D
-%D \splitfilename{c:/aa/bb/cc/dd.ee.ff} \showfilesplit \endgraf
-%D \splitfilename{c:/aa/bb/cc/dd.ee} \showfilesplit \endgraf
-%D \splitfilename{c:/aa/bb/cc/dd} \showfilesplit \endgraf
-%D
-%D \splitfilename{dd.ee.ff} \showfilesplit \endgraf
-%D \splitfilename{dd.ee} \showfilesplit \endgraf
-%D \splitfilename{dd} \showfilesplit \endgraf
-%D \stopbuffer
-%D
-%D \start \typebuffer \getbuffer \stop
-
-\def\splitoffroot{.} \chardef\splitoffkind\zerocount
-
-\let\splitofffull\empty
-\let\splitoffpath\empty
-\let\splitoffbase\empty
-\let\splitoffname\empty
-\let\splitofftype\empty
-
-\let\splitfilename\gobbleoneargument % defined in mk
-\let\splitfiletype\gobbleoneargument % defined in mk
-
-\loadmarkfile{supp-fil}
-
-\protect \endinput
diff --git a/tex/context/base/supp-fun.tex b/tex/context/base/supp-fun.tex
index fdeb5bbe8..6b2643703 100644
--- a/tex/context/base/supp-fun.tex
+++ b/tex/context/base/supp-fun.tex
@@ -22,7 +22,7 @@
\ifx \undefined \writestatus \input supp-mis.tex \relax \fi
-\writestatus{loading}{Context Support Macros / Fun Stuff}
+\writestatus{loading}{ConTeXt Support Macros / Fun Stuff}
\ifx\definefont\undefined
\def\definedfont[#1]{\font\temp#1\relax\temp}
@@ -346,8 +346,8 @@
\forgetall
\bgroup
#1%
- \setbox0\box\voidb@x
- \setbox2\box\voidb@x
+ \setbox0\emptybox
+ \setbox2\emptybox
\def\grabfirstline##1 %
{\setbox2\hbox
{\ifvoid0
@@ -356,8 +356,8 @@
\unhcopy0\ {#4{##1}}%
\fi}%
\ifdim\wd2=\zeropoint
- \setbox0\box\voidb@x
- \setbox2\box\voidb@x
+ \setbox0\emptybox
+ \setbox2\emptybox
\@EA\grabfirstline
\else\ifdim\wd2>\hsize
\hbox to \hsize{\strut\unhbox0}#2\egroup
diff --git a/tex/context/base/supp-ini.tex b/tex/context/base/supp-ini.tex
deleted file mode 100644
index afa8b12d9..000000000
--- a/tex/context/base/supp-ini.tex
+++ /dev/null
@@ -1,18 +0,0 @@
-%D \module
-%D [ file=supp-ini,
-%D version=1995.10.10,
-%D title=\CONTEXT\ Support ystem Macros,
-%D subtitle=Initializations,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Support Macros / Initializations}
-
-\unprotect
-
-\protect \endinput
diff --git a/tex/context/base/supp-lan.tex b/tex/context/base/supp-lan.tex
index 87bf4c3fb..8d781546f 100644
--- a/tex/context/base/supp-lan.tex
+++ b/tex/context/base/supp-lan.tex
@@ -31,7 +31,7 @@
\unprotect
-\writestatus{loading}{Context Support Macros / Language Options}
+\writestatus{loading}{ConTeXt Support Macros / Language Options}
%D \CONTEXT\ originates in the wish to typeset educational
%D materials, especially in a technical environment. In
@@ -872,7 +872,7 @@
\ifx\hspaceamount\undefined
- \def\hspaceamount#1#2{\kern.16667em}
+ \def\hspaceamount#1#2{16667em}
\fi
diff --git a/tex/context/base/supp-mat.tex b/tex/context/base/supp-mat.tex
index 3215a132b..1a51164e6 100644
--- a/tex/context/base/supp-mat.tex
+++ b/tex/context/base/supp-mat.tex
@@ -15,7 +15,7 @@
%D a support module. There is nothing spectacular here. It may move
%D back to math-ini.
-\writestatus{loading}{Context Support Macros / Math}
+\writestatus{loading}{ConTeXt Support Macros / Math}
\unprotect
@@ -195,6 +195,13 @@
%D \TEX provides no primitive to force in cramped math mode. Here is
%D a macro that does so. It is based on a solution by Don Knuth (\useurl
%D {http://www.ctan.org/tex-archive/digests/tex-implementors/042}).
+%D
+%D \startbuffer
+%D \ruledhbox{$\left\{{x^2\over y^2}\right\}$}
+%D \ruledhbox{$\cramped{\left\{ {x^2\over y^2}\right\}}$}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
\def\cramped
{\mathpalette\docramped}
@@ -209,7 +216,7 @@
% \def\docramped#1#2%
% {\setbox\scratchbox\hbox
% {\nulldelimiterspace\zeropoint
-% $\m@th#1\radical\zerocount{#2}$}%
+% $\mathsurround\zeropoint#1\radical\zerocount{#2}$}%
% \ifx#1\displaystyle
% \scratchdimen\fontdimen8\textfont3
% \advance\scratchdimen .25\fontdimen5\textfont2
@@ -229,7 +236,7 @@
{\begingroup % added HH, made even more cramped
\setbox\scratchbox\hbox
{\nulldelimiterspace\zeropoint
- $\m@th#1\radical\zerocount{#2}$}%
+ $\mathsurround\zeropoint#1\radical\zerocount{#2}$}%
\ht\scratchbox-\dimexpr
\ifx#1\displaystyle
\fontdimen8\textfont3
diff --git a/tex/context/base/supp-mis.tex b/tex/context/base/supp-mis.tex
index 57661e591..5b45d8b9d 100644
--- a/tex/context/base/supp-mis.tex
+++ b/tex/context/base/supp-mis.tex
@@ -80,7 +80,6 @@
%D Outside \CONTEXT\ we will not be \ETEX||aware.
\long\def\beginETEX #1\endETEX {}
-\long\def\beginOMEGA#1\endOMEGA{}
\let\beginTEX\relax \let\endTEX\relax
@@ -99,7 +98,7 @@
%D Let's see if it works.
-\writestatus{loading}{Context Support Macros / Miscellaneous (2004.10.26)}
+\writestatus{loading}{ConTeXt Support Macros / Miscellaneous (2004.10.26)}
%D \macros
%D {protect,unprotect}
diff --git a/tex/context/base/supp-mpe.tex b/tex/context/base/supp-mpe.tex
index 35a940edc..67b27919c 100644
--- a/tex/context/base/supp-mpe.tex
+++ b/tex/context/base/supp-mpe.tex
@@ -41,7 +41,7 @@
\ifx\writestatus\undefined
\immediate\write16{[Loading MPS to PDF extensions.]}
\else
- \writestatus{loading}{Context Support Macros / MPS extensions}
+ \writestatus{loading}{ConTeXt Support Macros / MPS extensions}
\fi
%D We implement extensions by using the \METAPOST\ special
diff --git a/tex/context/base/supp-mps.tex b/tex/context/base/supp-mps.tex
index 83deb4678..9864cd9a1 100644
--- a/tex/context/base/supp-mps.tex
+++ b/tex/context/base/supp-mps.tex
@@ -11,6 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+%D Forget about generic modules \unknown\ ...
+
+\ifx \undefined \contextversion \endinput \fi
+
%D \METAPOST\ is John Hobbys alternative for \METAFONT\ and
%D produces superior \POSTSCRIPT\ code. In this module we
%D integrate \METAPOST\ support int \CONTEXT. We offer two
@@ -36,11 +40,7 @@
%D
%D Ok then, let's start:
-\ifx \undefined \writestatus \input supp-mis.tex \relax \fi
-\ifx \undefined \letterhash \else \input supp-ini.tex \relax \fi
-\ifx \undefined \startMPgraphic \else \expandafter \endinput \fi
-
-\writestatus{loading}{Context Support Macros / MetaPost Inclusion}
+\writestatus{loading}{ConTeXt Support Macros / MetaPost Inclusion}
\unprotect
@@ -514,7 +514,7 @@
\newtoks\MPTEXgraphicchecks
\long\def\writecheckedMPgraphic#1%
- {\ifgrTEXgraphic
+ {\ifforceMPTEXgraphic
\global\MPTEXgraphictrue
\else
\global\MPTEXgraphicfalse
@@ -861,7 +861,9 @@
%D \stoptyping
\def\translateMPinput#1%
- {\xdef\MPinputtranslation{\letterpercent -translate-file=#1\space}}
+% {\xdef\MPinputtranslation{\letterpercent -translate-file=#1\space}} % at some point
+% {\xdef\MPinputtranslation{\letterpercent --8bit}} % some time later
+ {\globallet\MPinputtranslation\empty} % the new mpost is 8 bit clean
%D \macros
%D {setMPrandomseed}
@@ -2123,9 +2125,9 @@
%D away once the version supporting \type {--8bit} is
%D widespread.
-\beginXETEX
- \let\obeyMPlines\relax
- \longMPlinesfalse % alas
-\endXETEX
+\ifnum\texengine=\xetexengine
+ \let\obeyMPlines\relax
+ \longMPlinesfalse % alas
+\fi
\protect \endinput
diff --git a/tex/context/base/supp-mrk.tex b/tex/context/base/supp-mrk.tex
index eb03b5251..eb1865471 100644
--- a/tex/context/base/supp-mrk.tex
+++ b/tex/context/base/supp-mrk.tex
@@ -31,25 +31,7 @@
%D direct calls. The \TEX\ based multiple marks needs to store
%D the mark data but \ETEX\ uses a different approach.
-\writestatus{loading}{Context Support Macros / Marks}
-
-\let\normalmark = \mark
-\let\normaltopmark = \topmark
-\let\normalbotmark = \botmark
-\let\normalfirstmark = \firstmark
-\let\normalsplitbotmark = \splitbotmark
-\let\normalsplitfirstmark = \splitfirstmark
-
-\beginETEX \marks cum suis
-
-\let\normalmarks = \marks
-\let\normaltopmarks = \topmarks
-\let\normalbotmarks = \botmarks
-\let\normalfirstmarks = \firstmarks
-\let\normalsplitbotmarks = \splitbotmarks
-\let\normalsplitfirstmarks = \splitfirstmarks
-
-\endETEX
+\writestatus{loading}{ConTeXt Support Macros / Marks}
\unprotect
@@ -290,13 +272,6 @@
%D found, this macro is reassigned and from then on serves
%D in building the new list.
-% Although the next couple of macros are already defined
-% in syst-gen.tex, we repeat them here.
-
-\let\normalfi \fi % replaces \@fi
-\let\normalelse \else % replaces \@else
-\let\normalor \or % replaces \@or
-
% Hm, resetting \!!toksa got lost and took me a half a day to
% trace down ([] showed up in the pagebody); I really have
% to clean up this messy module (write it from scratch).
diff --git a/tex/context/base/supp-num.tex b/tex/context/base/supp-num.tex
index eb2cf49ea..130fd3938 100644
--- a/tex/context/base/supp-num.tex
+++ b/tex/context/base/supp-num.tex
@@ -2,7 +2,7 @@
%D [ file=supp-num,
%D version=1998.05.15,
%D title=\CONTEXT\ Support Macros,
-%D subtitle=Number (Digit) Handling,
+%D subtitle=Numbers,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Support Macros / Number (Digit) Handling}
+\writestatus{loading}{ConTeXt Support Macros / Numbers}
\unprotect
@@ -96,14 +96,12 @@
\ifx\mbox\undefined \let\mbox\normalhbox \fi
% \unexpanded\def\digits
-% {\bgroup\let~@\doifnextcharelse\bgroup\dodigits\grabdigit}
+% {\bgroup\let~@\doifnextbgroupelse\dodigits\grabdigit}
\unexpanded\def\digits
{\bgroup
\let~@%
- \doifnextcharelse\bgroup
- \dodigits
- {\doifnextcharelse\normalmathshift\domathdigits\grabdigit}}
+ \doifnextbgroupelse\dodigits{\doifnextcharelse\normalmathshift\domathdigits\grabdigit}}
\def\dodigits#1%
{\grabdigit#1\relax}
@@ -197,10 +195,23 @@
%D Although we could do with one pass, a second pass for
%D handling the stored sequence is more readable.
-\def\dohandledigits
- {\mathcode`\,="013B \mathcode`\.="013A % pretty hard coded
- \expandafter\handletokens\collecteddigits\with\scandigits
- \ifcase\powerdigits\else\digitpowerseparator^{\savedpowerdigits}\fi}
+\startmode[mkiv]
+
+ \def\dohandledigits
+ {\mathcode`\,="003B \mathcode`\.="003A % pretty hard coded
+ \expandafter\handletokens\collecteddigits\with\scandigits
+ \ifcase\powerdigits\else\digitpowerseparator^{\savedpowerdigits}\fi}
+
+\stopmode
+
+\startnotmode[mkiv]
+
+ \def\dohandledigits
+ {\mathcode`\,="013B \mathcode`\.="013A % pretty hard coded
+ \expandafter\handletokens\collecteddigits\with\scandigits
+ \ifcase\powerdigits\else\digitpowerseparator^{\savedpowerdigits}\fi}
+
+\stopnotmode
\def\doscandigit#1%
{\ifcase\skipdigit\@EA\hbox\else\@EA\hphantom\fi\bgroup
diff --git a/tex/context/base/supp-pat.tex b/tex/context/base/supp-pat.tex
index 6c11c1d92..d91083076 100644
--- a/tex/context/base/supp-pat.tex
+++ b/tex/context/base/supp-pat.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=supp-pat,
%D version=2005.02.12,
-%D title=\CONTEXT\ Language Macros,
-%D subtitle=Loading (Generic) Patterns,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=Patterns,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -32,7 +32,7 @@
\ifx\writestatus\undefined \else
- \writestatus{loading}{Context Language Macros / Loading Generic Patterns}
+ \writestatus{loading}{ConTeXt Support Macros / Patterns}
\fi
diff --git a/tex/context/base/supp-pdf.tex b/tex/context/base/supp-pdf.tex
index 95730939d..c54b0c6bc 100644
--- a/tex/context/base/supp-pdf.tex
+++ b/tex/context/base/supp-pdf.tex
@@ -14,7 +14,7 @@
\ifx\writestatus\undefined
\immediate\write16{[Loading MPS to PDF converter (version 2006.09.02).]}
\else
- \writestatus{loading}{Context Support Macros / PDF}
+ \writestatus{loading}{ConTeXt Support Macros / PDF}
\fi
%D This module is not optimized because it is used outside
diff --git a/tex/context/base/supp-ran.lua b/tex/context/base/supp-ran.lua
new file mode 100644
index 000000000..9e4330f57
--- /dev/null
+++ b/tex/context/base/supp-ran.lua
@@ -0,0 +1,46 @@
+if not modules then modules = { } end modules ['supp-ran'] = {
+ version = 1.001,
+ comment = "companion to supp-ran.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- We cannot ask for the current seed, so we need some messy hack
+-- here.
+
+commands = commands or { }
+
+local texwrite, random, seed, last = tex.write, math.random, false, 1
+
+function commands.getrandomcounta(min,max)
+ last = random(min,max)
+ texwrite(last)
+end
+
+function commands.getrandomcountb(min,max)
+ last = random(min,max)/65536
+ texwrite(last)
+end
+
+function commands.setrandomseed(n)
+ last = n
+ math.randomseed(n)
+end
+
+function commands.getrandomseed(n)
+ texwrite(last)
+end
+
+function commands.freezerandomseed()
+ if seed == false then
+ seed = last
+ end
+end
+
+function commands.defrostrandomseed()
+ if seed ~= false then
+ math.randomseed(last)
+ seed = false
+ end
+end
diff --git a/tex/context/base/supp-ran.tex b/tex/context/base/supp-ran.mkii
index 8c76ab443..d595fffaf 100644
--- a/tex/context/base/supp-ran.tex
+++ b/tex/context/base/supp-ran.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Third Party Macros / Random Number Generation}
+\writestatus{loading}{ConTeXt Support Macros / Random Number Generation}
%D \macros
%D {getrandomcount, getrandomdimen,
@@ -46,72 +46,36 @@
%D \getrandomseed\randomseed
%D \stoptyping
-\ifx\nextrandom\undefined
+\input thrd-ran.tex
- \readfile{random.tex}
- {\writestatus{loading}{Donald Arseneau's 'random.tex' (found)}}
- {\writestatus{loading}{Donald Arseneau's 'random.tex' (not found)}}
+\ifx\uniformdeviate\undefined
-\fi
-
-\ifx\nextrandom\undefined
-
- \writestatus{loading}{using fake randomizer}
-
- \newcount\randomi
-
- \def\setrandim#1#2#3{\scratchdimen #2\relax#1\scratchdimen }
- \def\setrannum#1#2#3{\scratchcounter#2\relax#1\scratchcounter}
-
- \let\nextrandom\relax
-
-\fi
+ \let\verynormalnextrandom\nextrandom
-\ifx\nextrandom\undefined \endinput \fi
-
-\ifx\normaluniformdeviate\undefined
-
- \let\verynormalnextrandom\nextrandom
-
- \def\normalnextrandom
- {\bgroup
- \let\time \normaltime
- \let\day \normalday
- \let\month\normalmonth
- \let\year \normalyear
- \verynormalnextrandom
- \egroup}
+ \def\normalnextrandom
+ {\bgroup
+ \let\time \normaltime
+ \let\day \normalday
+ \let\month\normalmonth
+ \let\year \normalyear
+ \verynormalnextrandom
+ \egroup}
\else
- % Yet untested.
-
- \writestatus{loading}{using tex's built in randomizer (overloading macro)}
+ \writestatus{loading}{using TeX's built in randomizer (overloading macro)}
- % For the meaning of the magic number, see \type {thrd-ran.tex}.
-
- % \def\normalnextrandom
- % {\setrandomseed\randomi
- % \global\randomi\normaluniformdeviate2147483647\relax}
-
- % Taco suggested to use the following alternative because \type
- % {\normaluniformdeviate} can return a zero (as expected) while
- % Donalds's alternative has a minimum of~1.
-
- \beginTEX
- \def\nextrandom
- {\normalsetrandomseed\randomi
- \global\randomi\normaluniformdeviate2147483646%
- \global\advance\randomi\plusone}
- \endTEX
+ % For the meaning of the magic number, see \type {thrd-ran.tex}.
+ %
+ % Taco suggested to use the following alternative because \type
+ % {\uniformdeviate} can return a zero (as expected) while
+ % Donalds Arseneau's alternative has a minimum of~1.
- \beginETEX \numexpr
\def\nextrandom
- {\normalsetrandomseed\randomi
+ {\normalsetrandomseed\randomi\relax
\global\randomi\numexpr\normaluniformdeviate2147483646+1\relax}
- \endETEX
- \let\normalnextrandom\nextrandom
+ \let\normalnextrandom\nextrandom
\fi
diff --git a/tex/context/base/supp-ran.mkiv b/tex/context/base/supp-ran.mkiv
new file mode 100644
index 000000000..9d429598f
--- /dev/null
+++ b/tex/context/base/supp-ran.mkiv
@@ -0,0 +1,30 @@
+%D \module
+%D [ file=supp-ran,
+%D version=2008-10-31,
+%D title=\CONTEXT\ Support Macros,
+%D subtitle=Random Number Generation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Support Macros / Random Number Generation}
+
+%D This module is downward compatible in the sense that we've kept
+%D the user interface (which uses intermediate variables).
+
+\registerctxluafile{supp-ran}{1.001}
+
+\def\getrandomcount #1#2#3{#1=\ctxlua{commands.getrandomcounta(\number#2,\number#3)}}
+\def\getrandomdimen #1#2#3{#1=\ctxlua{commands.getrandomcounta(\number\dimexpr#2,\number\dimexpr#3)}\scaledpoint}
+\def\getrandomnumber#1#2#3{\edef#1{\ctxlua{commands.getrandomcounta(\number#2,\number#3)}}}
+\def\getrandomfloat #1#2#3{\edef#1{\ctxlua{commands.getrandomcountb(\number\dimexpr#2\points,\number\dimexpr#3\points)}}}
+\def\setrandomseed #1{\ctxlua{commands.setrandomseed(\number#1)}}
+\def\getrandomseed {\ctxlua{commands.getrandomseed()}}
+\def\freezerandomseed {\ctxlua{commands.freezerandomseed()}}
+\def\defrostrandomseed {\ctxlua{commands.defrostrandomseed()}}
+
+\endinput
diff --git a/tex/context/base/supp-spe.tex b/tex/context/base/supp-spe.tex
index d84859b59..8cb8e2ac1 100644
--- a/tex/context/base/supp-spe.tex
+++ b/tex/context/base/supp-spe.tex
@@ -8,60 +8,60 @@
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-%D This module implements some \type{\special} manipulation
-%D macros. I needed these when I implemented the code that
-%D handles the conversion of \TPIC\ specials to \PDF\ code.
+%D This module implements some \type{\special} manipulation
+%D macros. I needed these when I implemented the code that
+%D handles the conversion of \TPIC\ specials to \PDF\ code.
\ifx \undefined \writestatus \input supp-mis.tex \relax \fi
\ifx \undefined \redefinespecial \else \expandafter \endinput \fi
-\writestatus{loading}{Context Support Macros / Specials}
+\writestatus{loading}{ConTeXt Support Macros / Specials}
\unprotect
%D When interpreting specials we need to do some basic scanning.
-%D For the moment we distinguish between three cases. We need
-%D
+%D For the moment we distinguish between three cases. We need
+%D
%D \starttyping
%D \special{tag: arguments}
%D \special{tag arguments}
%D \special{tag}
%D \stoptyping
-%D
-%D We cannot be sure that the first case isn't
-%D
+%D
+%D We cannot be sure that the first case isn't
+%D
%D \starttyping
%D \special{tag:arguments}
%D \stoptyping
-%D
-%D So we have to take care of that one too.
+%D
+%D So we have to take care of that one too.
%D \macros
%D {redefinespecial}
-%D
-%D Specials that are to be interpreted are defined with
+%D
+%D Specials that are to be interpreted are defined with
%D commands like:
-%D
+%D
%D \startbuffer[tmp-1]
%D \redefinespecial a: \using#1\endspecial%
%D {let's execute special 'a:' using '#1'}
-%D
+%D
%D \redefinespecial a \using#1\endspecial%
%D {let's execute special 'a' using '#1'}
-%D
+%D
%D \redefinespecial a \using#1\endspecial%
%D {let's execute special 'a' using nothing}
%D \stopbuffer
%D
%D \typebuffer[tmp-1]
-%D
-%D The first two always take an argument, the last one not.
-%D The definition of this redefinition macro is not that
-%D complex. The names are internally tagged with \type{\@rds@}
-%D which saves both time and space.
+%D
+%D The first two always take an argument, the last one not.
+%D The definition of this redefinition macro is not that
+%D complex. The names are internally tagged with \type{\@rds@}
+%D which saves both time and space.
\def\@rds@{@rds@}
@@ -70,14 +70,14 @@
%D \macros
%D {mimmickspecials}
%D
-%D Mimmicking specials is activated by saying:
+%D Mimmicking specials is activated by saying:
%D
%D \starttyping
%D \mimmickspecials
%D \stoptyping
%D
-%D This commands redefines the \PLAIN\ \TEX\ primitive
-%D \type{\special}.
+%D This commands redefines the \PLAIN\ \TEX\ primitive
+%D \type{\special}.
\def\mimmickspecials
{\let\special\domimmickspecial}
@@ -85,7 +85,7 @@
%D The special mimmicking macro first looks if it can find an
%D colon terminated tag, next it searches for a tag that end
%D with a space. If both cannot find, the tag itself is treated
-%D without argument.
+%D without argument.
\def\domimmickspecial#1%
{\domimmickcolonspecial#1:\relax/:\relax/\end}
@@ -107,25 +107,25 @@
\def\dodomimmickspecial#1\using#2\endspecial
{\expandafter\ifx\csname\@rds@#1\endcsname\relax % \doifdefinedelse
\defaultspecial{#1 #2}%
- \else
- %\message{[mimmick special #1 with #2]}%
+ \else
+ %\message{[mimmick special #1 with #2]}%
\getvalue{\@rds@#1}\using#2\endspecial
\fi}
-%D Now let's show that things work the way we want, using the
+%D Now let's show that things work the way we want, using the
%D previous definitions of tag~a.
-%D
+%D
%D \startbuffer[tmp-2]
%D \mimmickspecials
%D \special{a: 1 2 3 4 5}
%D \special{a: 1 2 3 4 5}
%D \special{a}
%D \stopbuffer
-%D
+%D
%D \typebuffer[tmp-2]
-%D
+%D
%D Which results in:
-%D
+%D
%D \startlines
%D \getbuffer[tmp-1]
%D \getbuffer[tmp-2]
@@ -133,11 +133,11 @@
%D \macros
%D {mimmickspecial}
-%D
-%D When needed, one can call a mimmicked special directly by
-%D saying for instance:
-%D
-%D \starttyping
+%D
+%D When needed, one can call a mimmicked special directly by
+%D saying for instance:
+%D
+%D \starttyping
%D \mimmickspecial a: \using...\endspecial
%D \stoptyping
%D
@@ -147,18 +147,18 @@
%D \macros
%D {normalspecial,defaultspecial}
-%D
-%D Unknown specials are passed to the default special handler.
+%D
+%D Unknown specials are passed to the default special handler.
%D One can for instance ignore all further specials by saying
%D \type{\normalspecial}:
-%D
+%D
%D \starttyping
%D \def\defaultspecial#1{}
%D \stoptyping
-%D
-%D But here we default to idle.
+%D
+%D But here we default to idle.
-\let\normalspecial =\special
-\let\defaultspecial=\special
+\let\normalspecial \special
+\let\defaultspecial\special
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/supp-tpi.tex b/tex/context/base/supp-tpi.tex
index e4bc5cc72..ac38ea392 100644
--- a/tex/context/base/supp-tpi.tex
+++ b/tex/context/base/supp-tpi.tex
@@ -19,14 +19,16 @@
%D \type{supp-spe} as well as the \METAPOST\ run||time support
%D implemented in \type{supp-mps}.
-\beginLUATEX \endinput \endLUATEX % to be sure, we don't want to load the following
+\ifnum\texengine=\luatexengine
+ \endinput
+\fi
\ifx\undefined\writestatus \input supp-mis \relax \fi
\ifx\undefined\mimmickspecials \input supp-spe \relax \fi
\ifx\undefined\MPgraphicbox \input supp-mps \relax \fi
\ifx\undefined\dogetEPSboundingbox \input supp-eps \relax \fi
-\writestatus{loading}{Context Support Macros / TPIC Conversion}
+\writestatus{loading}{ConTeXt Support Macros / TPIC Conversion}
%D Beware: we haven't activated both mechanism yet. This is
%D to be done in the calling module.
diff --git a/tex/context/base/supp-vis.tex b/tex/context/base/supp-vis.tex
index 1c3daf1e1..82ada9202 100644
--- a/tex/context/base/supp-vis.tex
+++ b/tex/context/base/supp-vis.tex
@@ -11,18 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\ifx\contextversion\undefined
-
- \let \normalunexpanded \unexpanded
- \let \unexpanded \protected
-
-\fi
-
-\ifx\unexpanded\undefined
-
- \let\unexpanded\relax
-
-\fi
+% no longer generic, who cares ...
%D \gdef\ShowBufferedExample% private typeseting macro
%D {\startlinecorrection
@@ -91,7 +80,7 @@
%D That's why we've implemented a mechanism that shows some of
%D the inner secrets of \TEX.
-\writestatus{loading}{Context Support Macros / Visualization}
+\writestatus{loading}{ConTeXt Support Macros / Visualization}
%D In this module we are going to redefine some \TEX\
%D primitives and \PLAIN\ macro's. Their original meaning is
@@ -159,10 +148,7 @@
%D baseline behavior. Especially \type{\vtop}'s need our
%D special attention.
-\ifx \normalhbox \undefined \let \normalhbox = \hbox \fi
-\ifx \normalvbox \undefined \let \normalvbox = \vbox \fi
-\ifx \normalvtop \undefined \let \normalvtop = \vtop \fi
-\ifx \normalvcenter \undefined \let \normalvcenter = \vcenter \fi
+% already saved
%D \macros
%D {normalhskip,
@@ -171,8 +157,7 @@
%D Next come the flexible skips, which come in two flavors
%D too. Like boxes these are handled with \TEX\ primitives.
-\let\normalhskip = \hskip
-\let\normalvskip = \vskip
+% already saved
%D \macros
%D {normalpenalty,
@@ -182,8 +167,7 @@
%D primitives. This means that when making them visible, we
%D have to take the current mode into account.
-\let\normalpenalty = \penalty
-\let\normalkern = \kern
+% already saved
%D \macros
%D {normalhglue,
@@ -193,8 +177,8 @@
%D As we will see, their definitions make the implementation of
%D their visible counterparts a bit more \TeX{}nical.
-\let\normalhglue = \hglue
-\let\normalvglue = \vglue
+\let\normalhglue = \hglue
+\let\normalvglue = \vglue
%D \macros
%D {normalmkern,
@@ -206,8 +190,7 @@
%D with other dimensions. As a result, the visual appearance
%D of these primitives is kept primitive too.
-\let\normalmkern = \mkern
-\let\normalmskip = \mskip
+% already saved
%D \macros
%D {hfilneg,
@@ -231,12 +214,7 @@
%D The positive stretch primitives are used independant and in
%D combination with \type{\leaders}.
-\let\normalhss = \hss
-\let\normalhfil = \hfil
-\let\normalhfill = \hfill
-\let\normalvss = \vss
-\let\normalvfil = \vfil
-\let\normalvfill = \vfill
+% already saved
%D \macros
%D {normalhfilneg,normalhfillneg,
@@ -247,9 +225,7 @@
%D in standard \TEX\ documentation. They can nevertheless be
%D used at will.
-\let\normalhfilneg = \hfilneg
\let\normalhfillneg = \hfillneg
-\let\normalvfilneg = \vfilneg
\let\normalvfillneg = \vfillneg
%D Visualization is not always wanted. Instead of turning this
@@ -1927,10 +1903,4 @@
%D lines in this two column index don't allign, then this is
%D due to some still unknown interference.
-\ifx\contextversion\undefined
-
- \let \unexpanded \normalunexpanded
-
-\fi
-
\endinput
diff --git a/tex/context/base/symb-ini.tex b/tex/context/base/symb-ini.tex
index 3cf50e411..291e22790 100644
--- a/tex/context/base/symb-ini.tex
+++ b/tex/context/base/symb-ini.tex
@@ -15,50 +15,10 @@
%D {core-con} module. I decided to move them here when
%D symbolsets saw the light. Let their light shine.
-\writestatus{loading}{Context Symbol Libraries / Initialization}
+\writestatus{loading}{ConTeXt Symbol Libraries / Initialization}
\unprotect
-\startmessages dutch library: symbols
- title: symbolen
- 1: symboolset -- wordt geladen
-\stopmessages
-
-\startmessages english library: symbols
- title: symbols
- 1: loading symbolset --
-\stopmessages
-
-\startmessages german library: symbols
- title: Symbole
- 1: Lade Symboldatei --
-\stopmessages
-
-\startmessages czech library: symbols
- title: symboly
- 1: nacita se soubor symbolu --
-\stopmessages
-
-\startmessages italian library: symbols
- title: simboli
- 1: caricamento gruppo di simboli --
-\stopmessages
-
-\startmessages norwegian library: symbols
- title: symboler
- 1: leser inn symbolsett --
-\stopmessages
-
-\startmessages romanian library: symbols
- title: simboluri
- 1: se incarca setul de simboluri --
-\stopmessages
-
-\startmessages french library: symbols
- title: symboles
- 1: chargement du jeu de symbole --
-\stopmessages
-
%D \macros
%D {definesymbol, symbol}
%D
diff --git a/tex/context/base/symb-jmn.tex b/tex/context/base/symb-jmn.tex
index 21a0d1562..392cac552 100644
--- a/tex/context/base/symb-jmn.tex
+++ b/tex/context/base/symb-jmn.tex
@@ -146,7 +146,6 @@
\stopsymbolset
-
% 1 left : 065 067 073 075
% 2 left : 128 132 144 148
% 3 left : 129 133 145 149
diff --git a/tex/context/base/symb-mis.tex b/tex/context/base/symb-mis.tex
index c63053abb..d108b8902 100644
--- a/tex/context/base/symb-mis.tex
+++ b/tex/context/base/symb-mis.tex
@@ -16,7 +16,7 @@
%D We predefine some common symbols and conversions that will
%D be understood by many commands.
-% \mathematics no longer needed
+% \mathematics no longer needed, although only math fonts might have these
\definesymbol [\v!none] []
\definesymbol [bullet] [\mathematics{\bullet}]
@@ -24,7 +24,6 @@
\definesymbol [star] [\mathematics{\star}]
\definesymbol [triangle] [\mathematics{\triangleright}]
\definesymbol [circle] [\mathematics{\circ}]
-%definesymbol [medcircle] [\hbox{\setsmallbodyfont\raise\onepoint\hbox{\mathematics{\bigcirc}}}]
\definesymbol [square] [\mathematics{\square}]
\definesymbol [diamond] [\mathematics{\diamond}]
@@ -32,7 +31,6 @@
\definesymbol [medcircle] [\hbox{\raise.1ex\hbox{\mathematics{\scriptstyle \bigcirc}}}]
\definesymbol [bigcircle] [\mathematics{\bigcirc}]
-
\definesymbol [1] [{\symbol[bullet]}]
\definesymbol [2] [{\symbol[dash]}]
\definesymbol [3] [{\symbol[star]}]
@@ -113,9 +111,6 @@
\def\gonowherecharacter
{\mathematics{\bullet}}
-%\def\gotosomewherecharacter% {} permits ^\...
-% {{\hbox{\hsmash{\gobackwardcharacter}\goforwardcharacter}}}
-
\def\gotosomewherecharacter
{{\hbox{\hsmash{\symbol[\v!previous]}\symbol[\v!next]}}}
diff --git a/tex/context/base/syst-aux.tex b/tex/context/base/syst-aux.tex
new file mode 100644
index 000000000..3b9d6803f
--- /dev/null
+++ b/tex/context/base/syst-aux.tex
@@ -0,0 +1,6841 @@
+%D \module
+%D [ file=syst-gen,
+%D version=1996.03.20,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=General,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Some of the macros will move to syst-obs as they might become
+%D obsolete once we've redone the bibliography module. Of course
+%D the handy helpers will stay.
+
+%D This is a stripped down combination of:
+%D
+%D \startitemize
+%D \item \type {syst-gen.tex}
+%D \item \type {syst-ext.tex}
+%D \item \type {syst-new.tex}
+%D \stopitemize
+%D
+%D We keep them around (for \MKII) so you can find comments,
+%D experiences, intermediate versions and cleaner variants
+%D there (and also non-\ETEX\ variants).
+%D
+%D Contrary to the older files, we now assume that this one
+%D is used in \CONTEXT\ and therefore we might also assume that
+%D some basic functionality is available.
+%D
+%D Some of the macros here are used in the bibliography module. They
+%D will be moved to a separate syst module some once the bib module
+%D is made \MKIV.
+
+\unprotect
+
+\let\reportprotectionstate\relax
+
+%D \macros
+%D {doifolderversionelse}
+%D
+%D We start with a macro specially for Aditya who wants to be able
+%D to use development versions of \MKIV\ for real documents.
+%D
+%D \starttyping
+%D \doifolderversionelse\contextversion{2001.02.03}{yes}{no}
+%D \doifolderversionelse\contextversion{3001.02.03}{yes}{no}
+%D \stoptyping
+%D
+%D The \type {yyyy.mm.dd} syntax is rather strict.
+
+\def\@@versiontonumber#1.#2.#3#4#5\relax
+ {\numexpr#1*\plustenthousand+#2*\plushundred+#3#4\relax}
+
+\def\doifolderversionelse#1#2%
+ {\normalexpanded{\noexpand\ifnum\noexpand\@@versiontonumber#1\relax<\noexpand\@@versiontonumber#2\relax}\relax
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {normalspace}
+%D
+%D There is already \type{\space} but just to be sure we also
+%D provide:
+
+\def\normalspace{ }
+
+%D \macros
+%D {!!count, !!toks, !!dimen, !!box,
+%D !!width, !!height, !!depth, !!string, !!done}
+%D
+%D We define some more \COUNTERS\ and \DIMENSIONS. We also
+%D define some shortcuts to the local scatchregisters~0, 2, 4,
+%D 6 and~8.
+
+\newcount\!!counta \newtoks\!!toksa \newdimen\!!dimena \newbox\!!boxa
+\newcount\!!countb \newtoks\!!toksb \newdimen\!!dimenb \newbox\!!boxb
+\newcount\!!countc \newtoks\!!toksc \newdimen\!!dimenc \newbox\!!boxc
+\newcount\!!countd \newtoks\!!toksd \newdimen\!!dimend \newbox\!!boxd
+\newcount\!!counte \newtoks\!!tokse \newdimen\!!dimene \newbox\!!boxe
+\newcount\!!countf \newtoks\!!toksf \newdimen\!!dimenf \newbox\!!boxf
+ \newdimen\!!dimeng
+ \newdimen\!!dimenh
+ \newdimen\!!dimeni
+ \newdimen\!!dimenj
+ \newdimen\!!dimenk
+
+\let\!!stringa\empty \let\!!stringb\empty \let\!!stringc\empty
+\let\!!stringd\empty \let\!!stringe\empty \let\!!stringf\empty
+
+\newdimen\!!widtha \newdimen\!!heighta \newdimen\!!deptha
+\newdimen\!!widthb \newdimen\!!heightb \newdimen\!!depthb
+\newdimen\!!widthc \newdimen\!!heightc \newdimen\!!depthc
+\newdimen\!!widthd \newdimen\!!heightd \newdimen\!!depthd
+
+\newif\if!!donea \newif\if!!doneb \newif\if!!donec
+\newif\if!!doned \newif\if!!donee \newif\if!!donef
+
+\def\!!zerocount {0} % alongside \zerocount
+\def\!!minusone {-1} % alongside \minusone
+\def\!!plusone {1} % alongside \plusone
+
+\ifdefined\data \else \let\data \relax \fi % dep checker
+
+%D \macros
+%D {s!,c!,e!,p!,v!,@@,??}
+%D
+%D To save memory, we use constants (sometimes called
+%D variables). Redefining these constants can have disastrous
+%D results.
+
+\def\v!prefix! {v!} \def\c!prefix! {c!}
+\def\s!prefix! {s!} \def\p!prefix! {p!}
+
+\def\s!next {next} \def\s!default {default}
+\def\s!dummy {dummy} \def\s!unknown {unknown}
+
+\def\s!do {do} \def\s!dodo {dodo}
+
+\def\s!complex {complex} \def\s!start {start}
+\def\s!simple {simple} \def\s!stop {stop}
+
+\def\s!empty {empty}
+
+%D \macros
+%D {@EA,@EAEA,@EAEAEA,@EAEAEAEAEAEA,expanded,startexpanded}
+%D
+%D When in unprotected mode, to be entered with
+%D \type{\unprotect}, one can use \type{\@EA} as equivalent
+%D of \type{\expandafter}.
+
+\let\@NX\noexpand
+\let\@EA\expandafter
+
+\def\@EAEA {\expandafter\expandafter}
+\def\@EAEAEA{\expandafter\expandafter\expandafter}
+
+\def\@EAEAEAEAEAEA{\expandafter\@EAEAEA\expandafter}
+
+%D Sometimes we pass macros as arguments to commands that
+%D don't expand them before interpretation. Such commands can
+%D be enclosed with \type{\expanded}, like:
+%D
+%D \starttyping
+%D \expanded{\setupsomething[\alfa]}
+%D \stoptyping
+%D
+%D Such situations occur for instance when \type{\alfa} is a
+%D commalist or when data stored in macros is fed to index of
+%D list commands. If needed, one should use \type{\noexpand}
+%D inside the argument. Later on we will meet some more clever
+%D alternatives to this command.
+
+\long\def\@@expanded{} % always long; global (less restores)
+
+\long\def\expanded#1%
+ {\long\xdef\@@expanded{\noexpand#1}\@@expanded}
+
+%D Beware, the next one has no \type {\noexpand} before its
+%D argument.
+
+\long\def\startexpanded#1\stopexpanded % see x-fo for example
+ {\long\xdef\@@expanded{#1}\@@expanded}
+
+%D Recent \TEX's have a primitive \expanded
+
+% \long\def\expanded
+% {\normalexpanded\bgroup\noexpand\gobblenexttoken}
+
+%D \macros
+%D {safeexpanded,everysafeexpanded}
+%D
+%D In addition we provide:
+
+\newtoks\everysafeexpanded
+
+\long\def\safeexpanded#1% why the \noexpand
+ {\begingroup
+ \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#1}%
+ \endgroup
+ \@@expanded}
+
+\def\safeedef#1#2%
+ {\begingroup
+ \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}%
+ \endgroup
+ \let#1\@@expanded}
+
+\def\safexdef#1#2%
+ {\begingroup
+ \the\everysafeexpanded\long\xdef\@@expanded{\noexpand#2}%
+ \endgroup
+ \global\let#1\@@expanded}
+
+%D You can append protective measures to the token register if
+%D needed, as we will do later.
+
+%D \macros
+%D {expandoneargafter,expandtwoargsafter}
+%D
+%D These two commands make macros more readable by hiding a
+%D lot of \type {\expandafter}'s. They expand the arguments
+%D after the first command.
+%D
+%D \starttyping
+%D \expandoneargafter \command{\abc}
+%D \expandtwoargsafter\command{\abc}{\def}
+%D \stoptyping
+%D
+%D These commands expect the arguments to be macros.
+
+\def\expandoneargafter #1{\@EA#1\@EA}
+\def\expandtwoargsafter#1#2{\@EA\@EA\@EA#1\@EA\@EA\@EA{\@EA#2\@EA}\@EA}
+
+%D These two do a full expansion:
+
+\def\fullexpandoneargafter #1#2{\long\xdef\@@expanded{\noexpand#1{#2}}\@@expanded}
+\def\fullexpandtwoargsafter#1#2#3{\long\xdef\@@expanded{\noexpand#1{#2}{#3}}\@@expanded}
+
+%D \macros
+%D {gobbleoneargument,gobble...arguments}
+%D
+%D The next set of macros just do nothing, except that they
+%D get rid of a number of arguments.
+
+\long\def\gobbleoneargument #1{}
+\long\def\gobbletwoarguments #1#2{}
+\long\def\gobblethreearguments #1#2#3{}
+\long\def\gobblefourarguments #1#2#3#4{}
+\long\def\gobblefivearguments #1#2#3#4#5{}
+\long\def\gobblesixarguments #1#2#3#4#5#6{}
+\long\def\gobblesevenarguments #1#2#3#4#5#6#7{}
+\long\def\gobbleeightarguments #1#2#3#4#5#6#7#8{}
+\long\def\gobbleninearguments #1#2#3#4#5#6#7#8#9{}
+\long\def\gobbletenarguments #1{\gobbleninearguments}
+
+%D \macros
+%D {doifnextcharelse}
+%D
+%D When we started using \TEX\ in the late eighties, our
+%D first experiences with programming concerned a simple shell
+%D around \LATEX. The commands probably use most at \PRAGMA,
+%D are the itemizing ones. One of those few shell commands took
+%D care of an optional argument, that enabled us to specify
+%D what kind of item symbol we wanted. Without understanding
+%D anything we were able to locate a \LATEX\ macro that could
+%D be used to inspect the next character.
+%D
+%D It's this macro that the ancester of the next one presented
+%D here. It executes one of two actions, dependant of the next
+%D character. Disturbing spaces and line endings, which are
+%D normally interpreted as spaces too, are skipped.
+%D
+%D \starttyping
+%D \doifnextcharelse {karakter} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This macro differs from the original in the use of \type
+%D {\localnext} because we don't want clashes with \type
+%D {\next}.
+
+\long\def\doifnextcharelse#1#2#3% #1 should not be {} !
+ {\let\charactertoken=#1% = needed here
+ \def\!!stringa{#2}%
+ \def\!!stringb{#3}%
+ \futurelet\nexttoken\inspectnextcharacter}
+
+\def\inspectnextcharacter
+ {\ifx\nexttoken\blankspace
+ \@EA\reinspectnextcharacter
+ \else
+ \@EA\inspectnextcharacterindeed
+ \fi}
+\def\inspectnextcharacterindeed
+ {\ifx\nexttoken\charactertoken
+ \@EA\!!stringa
+ \else
+ \@EA\!!stringb
+ \fi}
+
+%D Because we will mostly use this macro for testing if the next
+%D character is \type {[}, we also make a slightly faster variant
+%D as it is not uncommon to have tens of thousands of calls to this
+%D test in a run. Of course it also is more convenient to read a
+%D trace then.
+
+\let\nextoptionalcharactertoken=[
+
+\long\def\doifnextoptionalelse#1#2%
+ {\def\nextoptionalcommandyes{#1}%
+ \def\nextoptionalcommandnop{#2}%
+ \futurelet\nexttoken\inspectnextoptionalcharacter}
+
+\def\inspectnextoptionalcharacter
+ {\ifx\nexttoken\blankspace
+ \@EA\reinspectnextoptionalcharacter
+ \else
+ \@EA\inspectnextoptionalcharacterindeed
+ \fi}
+\def\inspectnextoptionalcharacterindeed
+ {\ifx\nexttoken\nextoptionalcharactertoken
+ \@EA\nextoptionalcommandyes
+ \else
+ \@EA\nextoptionalcommandnop
+ \fi}
+
+\let\nextbgroupcharactertoken\bgroup
+
+\long\def\doifnextbgroupelse#1#2%
+ {\def\nextbgroupcommandyes{#1}%
+ \def\nextbgroupcommandnop{#2}%
+ \futurelet\nexttoken\inspectnextbgroupcharacter}
+
+\def\inspectnextbgroupcharacter
+ {\ifx\nexttoken\blankspace
+ \@EA\reinspectnextbgroupcharacter
+ \else
+ \@EA\inspectnextbgroupcharacterindeed
+ \fi}
+\def\inspectnextbgroupcharacterindeed
+ {\ifx\nexttoken\nextbgroupcharactertoken
+ \@EA\nextbgroupcommandyes
+ \else
+ \@EA\nextbgroupcommandnop
+ \fi}
+
+%D This macro uses some auxiliary macros. Although we were able
+%D to program quite complicated things, I only understood these
+%D after rereading the \TEX book. The trick is in using a
+%D command with a one character name. Such commands differ from
+%D the longer ones in the fact that trailing spaces are {\em
+%D not} skipped. This enables us to indirectly define a long
+%D named macro that gobbles a space.
+%D
+%D In the first line we define \type{\blankspace}. Next we
+%D make \type{\:} equivalent to \type{\reinspect...}. This
+%D one||character command is expanded before the next
+%D \type{\def} comes into action. This way the space after
+%D \type{\:} becomes a delimiter of the longer named
+%D \type{\reinspectnextcharacter}.
+
+\let\next\:
+
+\def\:{\let\blankspace= } \:
+
+\def\:{\reinspectnextcharacter}
+\expandafter\def\: {\futurelet\nexttoken\inspectnextcharacter}
+
+\def\:{\reinspectnextoptionalcharacter}
+\expandafter\def\: {\futurelet\nexttoken\inspectnextoptionalcharacter}
+
+\def\:{\reinspectnextbgroupcharacter}
+\expandafter\def\: {\futurelet\nexttoken\inspectnextbgroupcharacter}
+
+\let\:\next
+
+%D \macros
+%D {setvalue,setgvalue,setevalue,setxvalue,
+%D letvalue,letgvalue,getvalue,resetvalue,
+%D undefinevalue,ignorevalue}
+%D
+%D \TEX's primitive \type{\csname} can be used to construct
+%D all kind of commands that cannot be defined with
+%D \type{\def} and \type{\let}. Every macro programmer sooner
+%D or later wants macros like these.
+%D
+%D \starttyping
+%D \setvalue {name}{...} = \def\name{...}
+%D \setgvalue {name}{...} = \gdef\name{...}
+%D \setevalue {name}{...} = \edef\name{...}
+%D \setxvalue {name}{...} = \xdef\name{...}
+%D \letvalue {name}=\... = \let\name=\...
+%D \letgvalue {name}=\... = \global\let\name=\...
+%D \getvalue {name} = \name
+%D \resetvalue {name} = \def\name{}
+%D \stoptyping
+%D
+%D As we will see, \CONTEXT\ uses these commands many times,
+%D which is mainly due to its object oriented and parameter
+%D driven character.
+
+\def\setvalue #1{\expandafter \def\csname#1\endcsname}
+\def\setgvalue #1{\expandafter\gdef\csname#1\endcsname}
+\def\setevalue #1{\expandafter\edef\csname#1\endcsname}
+\def\setxvalue #1{\expandafter\xdef\csname#1\endcsname}
+\def\getvalue #1{\csname#1\endcsname}
+\def\letvalue #1{\expandafter\let\csname#1\endcsname}
+\def\letgvalue #1{\global\expandafter\let\csname#1\endcsname}
+\def\resetvalue #1{\expandafter\let\csname#1\endcsname\empty}
+\def\undefinevalue#1{\expandafter\let\csname#1\endcsname\undefined}
+\def\ignorevalue#1#2{\expandafter\let\csname#1\endcsname\empty}
+
+%D \macros
+%D {globallet,glet}
+%D
+%D In \CONTEXT\ of May 2000 using \type {\globallet}
+%D instead of the two tokens will save us some
+%D $300\times4=1200$ bytes of format file on a 32~bit
+%D system. So:
+
+\def\globallet{\global\let} \let\glet\globallet
+
+%D \macros
+%D {donottest,unexpanded}
+%D
+%D When expansion of a macro gives problems, we can precede it
+%D by \type{\donottest}. It seems that protection is one of the
+%D burdens of developers of packages, so maybe that's why in
+%D \ETEX\ protection is solved in a more robust way.
+%D
+%D Because we use thi smodule onl in \MKIV, we have removed the
+%D old protection code.
+%D
+%D \starttyping
+%D \unexpanded\def\somecommand{... ... ...}
+%D \stoptyping
+
+\let \donottest \firstofoneargument % we need to weed
+\let \honorunexpanded \empty % we need to weed
+\let \forceunexpanded \empty % we need to weed
+\let \resetunexpanded \empty % we need to weed
+
+\let \unexpanded \normalprotected
+
+%D \macros
+%D {doifundefined,doifdefined,
+%D doifundefinedelse,doifdefinedelse,
+%D doifalldefinedelse}
+%D
+%D The standard way of testing if a macro is defined is
+%D comparing its meaning with another undefined one, usually
+%D \type{\undefined}. To garantee correct working of the next
+%D set of macros, \type{\undefined} may never be defined!
+%D
+%D \starttyping
+%D \doifundefined {string} {...}
+%D \doifdefined {string} {...}
+%D \doifundefinedelse {string} {then ...} {else ...}
+%D \doifdefinedelse {string} {then ...} {else ...}
+%D \doifalldefinedelse {commalist} {then ...} {else ...}
+%D \stoptyping
+%D
+%D Every macroname that \TEX\ builds gets an entry in the hash
+%D table, which is of limited size. It is expected that e-\TeX\
+%D will offer a less memory||consuming alternative.
+
+%D Although it will probably never be a big problem, it is good
+%D to be aware of the difference between testing on a macro
+%D name to be build by using \type{\csname} and
+%D \type{\endcsname} and testing the \type{\name} directly.
+%D
+%D \starttyping
+%D \expandafter\ifx\csname NameA\endcsname\relax ... \else ... \fi
+%D
+%D \ifundefined\NameB ... \else ... \fi
+%D \stoptyping
+
+\def\ifundefined#1% ongelukkige naam .. obsolete
+ {\unless\ifcsname#1\endcsname}
+
+% \def\p!doifundefined#1%
+% {\edef\p!defined{#1}%
+% \unless\ifcsname\detokenize\@EA{\p!defined}\endcsname}
+
+% \def\doifundefinedelse#1%
+% {\edef\p!defined{#1}%
+% \ifcsname\detokenize\@EA{\p!defined}\endcsname
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\firstoftwoarguments
+% \fi}
+
+% \def\doifdefinedelse#1%
+% {\edef\p!defined{#1}%
+% \ifcsname\detokenize\@EA{\p!defined}\endcsname
+% \expandafter\firstoftwoarguments
+% \else
+% \expandafter\secondoftwoarguments
+% \fi}
+
+% \def\doifundefined#1%
+% {\edef\p!defined{#1}%
+% \ifcsname\detokenize\@EA{\p!defined}\endcsname
+% \expandafter\gobbleoneargument
+% \else
+% \expandafter\firstofoneargument
+% \fi}
+
+% \def\doifdefined#1%
+% {\edef\p!defined{#1}%
+% \ifcsname\detokenize\@EA{\p!defined}\endcsname
+% \expandafter\firstofoneargument
+% \else
+% \expandafter\gobbleoneargument
+% \fi}
+
+\ifdefined\suppressifcsnameerror
+
+ \suppressifcsnameerror\plusone
+
+ \def\doifundefinedelse#1%
+ {\ifcsname#1\endcsname
+ \@EA\secondoftwoarguments\else\@EA\firstoftwoarguments
+ \fi}
+
+ \def\doifdefinedelse#1%
+ {\ifcsname#1\endcsname
+ \@EA\firstoftwoarguments\else\@EA\secondoftwoarguments
+ \fi}
+
+ \def\doifundefined#1%
+ {\ifcsname#1\endcsname
+ \@EA\gobbleoneargument\else\@EA\firstofoneargument
+ \fi}
+
+ \def\doifdefined#1%
+ {\ifcsname#1\endcsname
+ \@EA\firstofoneargument\else\@EA\gobbleoneargument
+ \fi}
+
+\else
+
+ \def\doifundefinedelse#1%
+ {\ifcsname\detokenize\@EA{\normalexpanded{#1}}\endcsname
+ \@EA\secondoftwoarguments\else\@EA\firstoftwoarguments
+ \fi}
+
+ \def\doifdefinedelse#1%
+ {\ifcsname\detokenize\@EA{\normalexpanded{#1}}\endcsname
+ \@EA\firstoftwoarguments\else\@EA\secondoftwoarguments
+ \fi}
+
+ \def\doifundefined#1%
+ {\ifcsname\detokenize\@EA{\normalexpanded{#1}}\endcsname
+ \@EA\gobbleoneargument\else\@EA\firstofoneargument
+ \fi}
+
+ \def\doifdefined#1%
+ {\ifcsname\detokenize\@EA{\normalexpanded{#1}}\endcsname
+ \@EA\firstofoneargument\else\@EA\gobbleoneargument
+ \fi}
+
+\fi
+
+%D \macros
+%D {letbeundefined}
+%D
+%D Testing for being undefined comes down to testing on \type
+%D {\relax} when we use \type {\csname}, but when using \type
+%D {\ifx}, we test on being \type {\undefined}! In \ETEX\ we
+%D have \type {\ifcsname} and that way of testing on existance
+%D is not the same as the one described here. Therefore we
+%D introduce:
+
+\def\letbeundefined#1% potential stack buildup when used \global
+ {\expandafter\let\csname#1\endcsname\undefined}
+
+\def\localundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi}
+
+\def\globalundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\global\let\csname#1\endcsname\undefined\fi}
+
+%D Beware, being \type {\undefined} in \ETEX\ means that the macro
+%D {\em is} defined!
+
+%D When we were developing the scientific units module, we
+%D encountered different behavior in text and math mode, which
+%D was due to this grouping subtilities. We therefore decided
+%D to use \type{\begingroup} instead of \type{\bgroup}.
+
+\def\docheckonedefined#1%
+ {\ifcsname#1\endcsname\else
+ \donefalse
+ \expandafter\quitcommalist % added
+ \fi}
+
+\def\doifalldefinedelse#1%
+ {\begingroup
+ \donetrue \processcommalist[#1]\docheckonedefined
+ \ifdone
+ \endgroup\expandafter\firstoftwoarguments
+ \else
+ \endgroup\expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doif,doifelse,doifnot,
+%D donottest}
+%D
+%D Programming in \TEX\ differs from programming in procedural
+%D languages like \MODULA. This means that one --- well, let me
+%D speek for myself --- tries to do the things in the well
+%D known way. Therefore the next set of \type{\ifthenelse}
+%D commands were between the first ones we needed. A few years
+%D later, the opposite became true: when programming in
+%D \MODULA, I sometimes miss handy things like grouping,
+%D runtime redefinition, expansion etc. While \MODULA\ taught
+%D me to structure, \TEX\ taught me to think recursive.
+%D
+%D \starttyping
+%D \doif {string1} {string2} {...}
+%D \doifnot {string1} {string2} {...}
+%D \doifelse {string1} {string2} {then ...}{else ...}
+%D \stoptyping
+%D
+%D When expansion gives problems, we can precede the
+%D troublemaker with \type{\donottest}.
+
+\long\def\doif#1#2%
+ {\edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\doifnot#1#2%
+ {\edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\long\def\doifelse#1#2%
+ {\edef\!!stringa{#1}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifempty,doifemptyelse,doifnotempty}
+%D
+%D We complete our set of conditionals with:
+%D
+%D \starttyping
+%D \doifempty {string} {...}
+%D \doifnotempty {string} {...}
+%D \doifemptyelse {string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This time, the string is not expanded.
+
+\long\def\doifemptyelse#1%
+ {\def\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\long\def\doifempty#1%
+ {\def\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\doifnotempty#1%
+ {\def\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D \macros
+%D {doifinset,doifnotinset,doifinsetelse}
+%D
+%D We can check if a string is present in a comma separated
+%D set of strings. Depending on the result, some action is
+%D taken.
+%D
+%D \starttyping
+%D \doifinset {string} {string,...} {...}
+%D \doifnotinset {string} {string,...} {...}
+%D \doifinsetelse {string} {string,...} {then ...} {else ...}
+%D \stoptyping
+
+% !0nop=\doifinsetelse{ccc}{,}{yes}{nop}
+% !0nop=\doifinsetelse{ccc}{,,}{yes}{nop}
+% !0nop=\doifinsetelse{ccc}{,,,}{yes}{nop}
+
+% !1nop=\doifinsetelse{}{}{yes}{nop}
+% !2yes=\doifinsetelse{aaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
+% !3nop=\doifinsetelse{aaa}{bbb}{yes}{nop}
+% !4yes=\doifinsetelse{aaa}{aaa}{yes}{nop}
+% !5nop=\doifinsetelse{aaaa}{bbb,ccc,ddd,aaa,eee}{yes}{nop}
+% !6nop=\doifinsetelse{}{}{yes}{nop}
+% !7nop=\doifinsetelse{}{aaa}{yes}{nop}
+% !8nop=\doifinsetelse{aaa}{}{yes}{nop}
+
+% !1=\doifinset{}{}{yes}
+% !2yes=\doifinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
+% !3=\doifinset{aaa}{bbb}{yes}
+% !4yes=\doifinset{aaa}{aaa}{yes}
+% !5=\doifinset{}{}{yes}
+% !6=\doifinset{aaa}{}{yes}
+
+% !1yes=\doifnotinset{}{}{yes}
+% !2=\doifnotinset{aaa}{bbb,ccc,ddd,aaa,eee}{yes}
+% !3yes=\doifnotinset{aaa}{bbb}{yes}
+% !4=\doifnotinset{aaa}{aaa}{yes}
+% !5yes=\doifnotinset{}{}{yes}
+% !6yes=\doifnotinset{aaa}{}{yes}
+
+\def\rightoptionalbracket{]}
+
+\long\def\doquitifiteminsetelse#1],\relax{\firstoftwoarguments}
+\long\def\doquitifiteminset #1],\relax{\firstofoneargument}
+\long\def\doquitifitemnotinset #1],\relax{\gobbleoneargument}
+
+\long\def\redoifinsetelse{\expandafter\docheckifiteminsetelse\!!stringb,],\relax}
+\long\def\redoifinset {\expandafter\docheckifiteminset \!!stringb,],\relax}
+\long\def\redoifnotinset {\expandafter\docheckifitemnotinset \!!stringb,],\relax}
+
+\long\def\doifinsetelse#1% make this two step too
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\thirdofthreearguments
+ \else
+ \expandafter\dodoifinsetelse
+ \fi}
+\long\def\dodoifinsetelse#1%
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\redoifinsetelse
+ \fi}
+
+\long\def\doifinset#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\dodoifinset
+ \fi}
+\long\def\dodoifinset#1%
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\redoifinset
+ \fi}
+
+\long\def\doifnotinset#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\dodoifnotinset
+ \fi}
+\long\def\dodoifnotinset#1%
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\redoifnotinset % ...]{true}
+ \fi}
+
+\def\docheckifiteminsetelse#1,#2% #2 eats up preceding space
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\docheckifiteminsetelse
+ \else
+ \expandafter\dodocheckifiteminsetelse
+ \fi#2}
+\def\dodocheckifiteminsetelse
+ {\ifx\!!stringb\rightoptionalbracket
+ \expandafter\thirdofthreearguments
+ \else
+ \expandafter\dododocheckifiteminsetelse
+ \fi}
+\def\dododocheckifiteminsetelse
+ {\ifx\!!stringa\!!stringb
+ \expandafter\doquitifiteminsetelse
+ \else
+ \expandafter\docheckifiteminsetelse
+ \fi}
+
+\def\docheckifiteminset#1,#2% #2 eats up preceding space
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\docheckifiteminset
+ \else
+ \expandafter\dodocheckifiteminset
+ \fi#2}
+\def\dodocheckifiteminset
+ {\ifx\!!stringb\rightoptionalbracket
+ \expandafter\gobbletwoarguments
+ \else
+ \expandafter\dododocheckifiteminset
+ \fi}
+\def\dododocheckifiteminset
+ {\ifx\!!stringa\!!stringb
+ \expandafter\doquitifiteminset
+ \else
+ \expandafter\docheckifiteminset
+ \fi}
+
+\def\docheckifitemnotinset#1,#2% #2 eats up preceding space
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\empty
+ \expandafter\docheckifitemnotinset
+ \else
+ \expandafter\dodocheckifitemnotinset
+ \fi#2}
+\def\dodocheckifitemnotinset
+ {\ifx\!!stringb\rightoptionalbracket
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\dododocheckifitemnotinset
+ \fi}
+\def\dododocheckifitemnotinset
+ {\ifx\!!stringa\!!stringb
+ \expandafter\doquitifitemnotinset
+ \else
+ \expandafter\docheckifitemnotinset
+ \fi}
+
+%D \macros
+%D {doifcommon,doifnotcommon,doifcommonelse}
+%D
+%D Probably the most time consuming tests are those that test
+%D for overlap in sets of strings.
+%D
+%D \starttyping
+%D \doifcommon {string,...} {string,...} {...}
+%D \doifnotcommon {string,...} {string,...} {...}
+%D \doifcommonelse {string,...} {string,...} {then ...} {else ...}
+%D \stoptyping
+
+% !1yes=\doifcommonelse{aaa,bbb,ccc}{aaa,bbb,ccc}{yes}{nop}
+% !2nop=\doifcommonelse{aaa,bbb,ccc}{ddd,eee,fff}{yes}{nop}
+% !3nop=\doifcommonelse{aaa}{ddd,eee,fff}{yes}{nop}
+% !4yes=\doifcommonelse{aaa}{aaa}{yes}{nop}
+% !5nop=\doifcommonelse{bbb}{aaa}{yes}{nop}
+% !6nop=\doifcommonelse{}{aaa,bbb,ccc}{yes}{nop}
+% !7nop=\doifcommonelse{aaa,bbb,ccc}{}{yes}{nop}
+% !8nop=\doifcommonelse{}{}{yes}{nop}
+
+% !9nop=\doifcommonelse{,,}{,,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,,a,}{,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,a,}{,,,a,}{yes}{nop}
+% !9yes=\doifcommonelse{,,a,}{,,,a,}{yes}{nop}
+
+% \def\p!doifcommonelse#1#2#3#4%
+% {\donefalse
+% \def\p!docommoncheck##1{\doifinset{##1}{#4}\donetrue\ifdone\quitcommalist\fi}%
+% \processcommalist[#3]\p!docommoncheck
+% \ifdone\expandafter#1\else\expandafter#2\fi}
+%
+% \def\doifcommonelse
+% {\p!doifcommonelse\firstoftwoarguments\secondoftwoarguments}
+%
+% \def\doifcommon
+% {\p!doifcommonelse\firstofoneargument \gobbleoneargument}
+%
+% \def\doifnotcommon
+% {\p!doifcommonelse\gobbleoneargument \firstofoneargument}
+
+\long\def\doquitifcommonelse#1],\relax#2],\relax{\firstoftwoarguments}
+
+\long\def\doquitifcommonelsenop{\secondoftwoarguments}
+
+\def\docheckifcommonelseone#1,#2%
+ {\edef\!!stringc{#1}%
+ \ifx\!!stringc\rightoptionalbracket
+ \expandafter\thirdofthreearguments
+ \else
+ \expandafter\p!docommoncheck
+ \fi#2}
+
+\def\docheckifcommonelsetwo#1,#2% we can do an empty #1 check too
+ {\edef\commalistelement{#1}%
+ \ifx\commalistelement\rightoptionalbracket
+ \expandafter\redocheckifcommonelseone
+ \else
+ \expandafter\dodocheckifcommonelsetwo
+ \fi#2}
+
+\def\dodocheckifcommonelsetwo
+ {\ifx\commalistelement\empty
+ \expandafter\docheckifcommonelsetwo
+ \else
+ \expandafter\dododocheckifcommonelsetwo
+ \fi}
+
+\def\dododocheckifcommonelsetwo
+ {\ifx\!!stringc\commalistelement
+ \expandafter\doquitifcommonelse
+ \else
+ \expandafter\docheckifcommonelsetwo
+ \fi}
+
+\def\redocheckifcommonelseone#1{\docheckifcommonelseone}
+
+\def\p!doifcommonelse#1#2#3#4%
+ {\edef\!!stringa{#3}%
+ \edef\!!stringb{#4}%
+ \ifx\!!stringa\empty
+ \expandafter\secondoftwoarguments
+ \else\ifx\!!stringb\empty
+ \expandafter\expandafter\expandafter\secondoftwoarguments
+ \else
+ \expandafter\expandafter\expandafter\pp!doifcommonelse
+ \fi\fi
+ #1#2}
+
+% \def\p!doifcommonelse#1#2#3%
+% {\edef\!!stringa{#3}%
+% \ifx\!!stringa\empty
+% \expandafter\secondofthreearguments
+% \else
+% \expandafter\p!dodoifcommonelse
+% \fi
+% #1#2} % #4
+
+% \def\p!dodoifcommonelse#1#2#3%
+% {\edef\!!stringb{#3}%
+% \ifx\!!stringb\empty
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\pp!doifcommonelse
+% \fi#1#2}
+
+\def\pp!doifcommonelse
+ {\def\p!docommoncheck{\expandafter\docheckifcommonelsetwo\!!stringb,],\relax}%
+ \expandafter\docheckifcommonelseone\!!stringa,],\relax}
+
+\def\doifcommonelse{\p!doifcommonelse\firstoftwoarguments\secondoftwoarguments}
+\def\doifcommon {\p!doifcommonelse\firstofoneargument \gobbleoneargument }
+\def\doifnotcommon {\p!doifcommonelse\gobbleoneargument \firstofoneargument }
+
+%D \macros
+%D {processcommalist,processcommacommand,quitcommalist,
+%D processcommalistwithparameters}
+%D
+%D We've already seen some macros that take care of comma
+%D separated lists. Such list can be processed with
+%D
+%D \starttyping
+%D \processcommalist[string,string,...]\commando
+%D \stoptyping
+%D
+%D The user supplied command \type{\commando} receives one
+%D argument: the string. This command permits nesting and
+%D spaces after commas are skipped. Empty sets are no problem.
+%D
+%D \startbuffer
+%D \def\dosomething#1{(#1)}
+%D
+%D 1: \processcommalist [\hbox{$a,b,c,d,e,f$}] \dosomething \par
+%D 2: \processcommalist [{a,b,c,d,e,f}] \dosomething \par
+%D 3: \processcommalist [{a,b,c},d,e,f] \dosomething \par
+%D 4: \processcommalist [a,b,{c,d,e},f] \dosomething \par
+%D 5: \processcommalist [a{b,c},d,e,f] \dosomething \par
+%D 6: \processcommalist [{a,b}c,d,e,f] \dosomething \par
+%D 7: \processcommalist [] \dosomething \par
+%D 8: \processcommalist [{[}] \dosomething \par
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Before we show the result, we present the macro's:
+
+\newcount\commalevel
+
+\def\dododoprocesscommaitem
+ {\csname\s!next\the\commalevel\endcsname}
+
+% \def\dodoprocesscommaitem
+% {\ifx\nexttoken\blankspace
+% \@EA\redoprocesscommaitem
+% \else\ifx\nexttoken]%
+% \@EAEAEA\gobbleoneargument
+% \else
+% \@EAEAEA\dododoprocesscommaitem
+% \fi\fi}
+
+\def\dodoprocesscommaitem
+ {\ifx\nexttoken\blankspace
+ \@EA\redoprocesscommaitem
+ \else
+ \@EA\dodoprocesscommaitemindeed
+ \fi}
+\def\dodoprocesscommaitemindeed
+ {\ifx\nexttoken]%
+ \@EA\gobbleoneargument
+ \else
+ \@EA\dododoprocesscommaitem
+ \fi}
+
+\def\doprocesscommaitem
+ {\futurelet\nexttoken\dodoprocesscommaitem}
+
+%D Empty arguments are not processed. Empty items (\type{,,})
+%D however are treated. We have to check for the special case
+%D \type{[{a,b,c}]}.
+
+\def\processcommalist[%
+ {\futurelet\nexttoken\docheckcommaitem}
+
+\def\docheckcommaitem
+ {\ifx\nexttoken]%
+ \expandafter\gobblethreearguments
+ \else
+ \expandafter\doprocesscommalist
+ \fi
+ \relax} % this one preserved the next {}
+
+\def\doprocesscommalist#1]#2%
+ {\global\advance\commalevel \plusone
+ \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
+ {#2{##1}\doprocesscommaitem}%
+ \@EA\dodoprocesscommaitem\gobbleoneargument#1,]\relax
+ \global\advance\commalevel \minusone }
+
+%D One way of quitting a commalist halfway is:
+
+\def\quitcommalist
+ {\begingroup\let\doprocesscommaitem\doquitcommalist}
+
+\def\doquitcommalist#1]%
+ {\endgroup}
+
+\def\quitprevcommalist
+ {\begingroup\let\doprocesscommaitem\doquitprevcommalist}
+
+\def\doquitprevcommalist#1]%
+ {\let\doprocesscommaitem\doquitcommalist}
+
+%D The hack we used for checking the next character
+%D \type {\doifnextcharelse} is also used here.
+
+\def\:{\redoprocesscommaitem}
+
+\expandafter\def\: {\futurelet\nexttoken\dodoprocesscommaitem}
+
+%D The previous examples lead to:
+%D
+%D \getbuffer
+
+%D When a list is saved in a macro, we can use a construction
+%D like:
+%D
+%D \starttyping
+%D \expandafter\processcommalist\expandafter[\list]\command
+%D \stoptyping
+%D
+%D Such solutions suit most situations, but we wanted a bit
+%D more.
+%D
+%D \starttyping
+%D \processcommacommand[string,\stringset,string]\commando
+%D \stoptyping
+%D
+%D where \type{\stringset} is a predefined set, like:
+%D
+%D \starttyping
+%D \def\first{aap,noot,mies}
+%D \def\second{laatste}
+%D
+%D \processcommacommand[\first]\message
+%D \processcommacommand[\first,second,third]\message
+%D \processcommacommand[\first,between,\second]\message
+%D \stoptyping
+%D
+%D Commands that are part of the list are expanded, so the
+%D use of this macro has its limits.
+
+% \def\processcommacommand[#1]%
+% {\expanded{\processcommalist[#1]}}
+
+\def\processcommacommand[#1]%
+ {\expandafter\processcommalist\expandafter[\normalexpanded{#1}]}
+
+%D The argument to \type{\command} is not delimited. Because
+%D we often use \type{[]} as delimiters, we also have:
+%D
+%D \starttyping
+%D \processcommalistwithparameters[string,string,...]\command
+%D \stoptyping
+%D
+%D where \type{\command} looks like:
+%D
+%D \starttyping
+%D \def\command[#1]{... #1 ...}
+%D \stoptyping
+
+\def\processcommalistwithparameters[#1]#2%
+ {\def\docommand##1{#2[##1]}%
+ \processcommalist[#1]\docommand}
+
+%D \macros
+%D {processaction,
+%D processfirstactioninset,
+%D processallactionsinset}
+%D
+%D \CONTEXT\ makes extensive use of a sort of case or switch
+%D command. Depending of the presence of one or more provided
+%D items, some actions is taken. These macros can be nested
+%D without problems.
+%D
+%D \starttyping
+%D \processaction [x] [a=>\a,b=>\b,c=>\c]
+%D \processfirstactioninset [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \processallactionsinset [x,y,z] [a=>\a,b=>\b,c=>\c]
+%D \stoptyping
+%D
+%D We can supply both a \type{default} action and an action
+%D to be undertaken when an \type{unknown} value is met:
+%D
+%D \starttyping
+%D \processallactionsinset
+%D [x,y,z]
+%D [ a=>\a,
+%D b=>\b,
+%D c=>\c,
+%D default=>\default,
+%D unknown=>\unknown{... \commalistelement ...}]
+%D \stoptyping
+%D
+%D When \type{#1} is empty, this macro scans list \type{#2} for
+%D the keyword \type{default} and executed the related action
+%D if present. When \type{#1} is non empty and not in the list,
+%D the action related to \type{unknown} is executed. Both
+%D keywords must be at the end of list \type{#2}. Afterwards,
+%D the actually found keyword is available in
+%D \type{\commalistelement}. An advanced example of the use of
+%D this macro can be found in \PPCHTEX, where we completely
+%D rely on \TEX\ for interpreting user supplied keywords like
+%D \type{SB}, \type{SB1..6}, \type{SB125} etc.
+
+\newcount\processlevel
+
+\def\p!compareprocessactionA[#1=>#2][#3]%
+ {\edef\!!stringb{#1}%
+ \ifx\!!stringb\s!default
+ \let\commalistelement\empty
+ #2%
+ \fi}
+
+% met \quitcommalist tot meer dan 25\% sneller
+
+\def\p!compareprocessactionB[#1=>#2][#3]%
+ {\expandedaction\!!stringb{#1}%
+ \ifx\!!stringa\!!stringb
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitcommalist
+ \else
+ \edef\!!stringb{#1}%
+ \ifx\!!stringb\s!unknown
+ \def\commalistelement{#3}% beware of loops
+ #2%
+ \fi
+ \fi}
+
+\def\processaction[#1]#2[%
+ {\expandedaction\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \let\p!compareprocessaction\p!compareprocessactionA
+ \else
+ \let\p!compareprocessaction\p!compareprocessactionB
+ \fi
+ \def\p!doprocessaction##1%
+ {\p!compareprocessaction[##1][#1]}%
+ \processnextcommalist\relax\expandactions\p!doprocessaction[}
+
+\def\p!compareprocessactionC[#1=>#2][#3]%
+ {\expandedaction\!!stringa{#1}%
+ \expandedaction\!!stringb{#3}%
+ \ifx\!!stringa\!!stringb
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitprevcommalist
+ \else
+ \edef\!!stringa{#1}%
+ \ifx\!!stringa\s!unknown
+ \def\commalistelement{#3}%
+ #2%
+ \fi
+ \fi}
+
+\def\processfirstactioninset[#1]%
+ {\expandedaction\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\processaction
+ \else
+ \expandafter\processfirstactionsinsetindeed
+ \fi
+ [#1]}
+
+\def\processfirstactionsinsetindeed[#1]#2[#3]%
+ {\def\p!doprocessaction##1%
+ {\def\p!dodoprocessaction####1%
+ {\p!compareprocessactionC[####1][##1]}%
+ \processcommalist[#3]\p!dodoprocessaction}%
+ \processcommalist[#1]\p!doprocessaction
+ \expandactions}
+
+\def\p!compareprocessactionD[#1=>#2][#3]%
+ {\expandedaction\!!stringa{#1}%
+ \expandedaction\!!stringb{#3}%
+ \ifx\!!stringa\!!stringb
+ \def\commalistelement{#3}%
+ #2%
+ \expandafter\quitcommalist
+ \else
+ \edef\!!stringa{#1}%
+ \ifx\!!stringa\s!unknown
+ \def\commalistelement{#3}%
+ #2%
+ \fi
+ \fi}
+
+\def\doprocessallactionsinset
+ {\csname\s!do\the\processlevel\endcsname}
+
+\def\processallactionsinset[#1]%
+ {\expandedaction\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\processaction
+ \else
+ \expandafter\processallactionsinsetindeed
+ \fi
+ [#1]}
+
+\def\processallactionsinsetindeed[#1]#2[#3]%
+ {\advance\processlevel \plusone
+ \expandafter\def\csname\s!do\the\processlevel\endcsname##1%
+ {\def\p!dodoprocessaction####1%
+ {\p!compareprocessactionD[####1][##1]}%
+ \processcommalist[#3]\p!dodoprocessaction}%
+ \processcommalist[#1]\doprocessallactionsinset
+ \advance\processlevel \minusone
+ \expandactions}
+
+%D These macros use:
+
+\def\processnextcommalist#1#2#3[#4#5]%
+ {#1%
+ \let\nexttoken#4%
+ \global\advance\commalevel \plusone
+ \long\expandafter\def\csname\s!next\the\commalevel\endcsname##1,%
+ {#3{##1}\doprocesscommaitem}%
+ \dodoprocesscommaitem#4#5,]\relax
+ \global\advance\commalevel \minusone
+ #2}
+
+%D \macros
+%D {unexpandedprocessaction,
+%D unexpandedprocessfirstactioninset,
+%D unexpandedprocessallactionsinset}
+%D
+%D Now what are those expansion commands doing there. Well,
+%D sometimes we want to compare actions that may consist off
+%D commands (i.e. are no constants). In such occasions we can
+%D use the a bit slower alternatives:
+
+\def\unexpandedprocessfirstactioninset{\dontexpandactions\processfirstactioninset}
+\def\unexpandedprocessaction {\dontexpandactions\processaction}
+\def\unexpandedprocessallactionsinset {\dontexpandactions\processallactionsinset}
+
+%D By default we expand actions:
+
+\def\expandactions{\let\expandedaction\edef} \expandactions
+
+%D But when needed we convert the strings to meaningful
+%D sequences of characters.
+
+\def\unexpandedaction#1>{}
+
+\def\noexpandedaction#1#2%
+ {\def\@@convertedargument{#2}%
+ \@EA\edef\@EA#1\@EA{\@EA\unexpandedaction\meaning\@@convertedargument}}
+
+\def\dontexpandactions
+ {\let\expandedaction\noexpandedaction}
+
+%D \macros
+%D {getfirstcharacter, firstcharacter, remainingcharacters, doiffirstcharacter}
+%D
+%D Sometimes the action to be undertaken depends on the
+%D next character. This macro get this character and puts it in
+%D \type{\firstcharacter}.
+%D
+%D \starttyping
+%D \getfirstcharacter {string}
+%D \stoptyping
+%D
+%D A two step expansion is used to prevent problems with
+%D complicated arguments, for instance arguments that
+%D consist of two or more expandable tokens.
+
+\def\dogetfirstcharacter#1#2\relax
+ {\def\firstcharacter{#1}%
+ \def\remainingcharacters{#2}}
+
+\def\getfirstcharacter#1%
+ {\edef\!!stringa{#1}%
+ \expandafter\dogetfirstcharacter\!!stringa\relax}
+
+\def\doiffirstcharelse#1#2% char string
+% kort (maar onleesbaar)
+% {\expanded{\dogetfirstcharacter#2}\\\doifelse{#1}\firstcharacter}
+% korter (en begrijpelijk))
+ {\getfirstcharacter{#2}\doifelse{#1}\firstcharacter}
+% snel (maar zelden gebruikt, dus niet zo belangrijk)
+% {\getfirstcharacter{#2}%
+% \edef\!!stringa{#1}%
+% \ifx\!!stringa\firstcharacter
+% \expandafter\firstoftwoarguments
+% \else
+% \expandafter\secondoftwoarguments
+% \fi}
+
+%D \macros
+%D {doifinstringelse, doifincsnameelse}
+%D
+%D We can check for the presence of a substring in a given
+%D sequence of characters.
+%D
+%D \starttyping
+%D \doifinsetelse {substring} {string} {then ...} {else ...}
+%D \stoptyping
+
+\long\def\doifinstringelse#1%
+ {\edef\@@@instring{#1}% expand #1 here
+ \ifx\@@@instring\empty
+ \@EA\thirdofthreearguments
+ \else
+ \@EA\dodoifinstringelse
+ \fi}
+
+\long\def\dodoifinstringelse#1%
+ {\p!doifinstringelse\@@@instring{#1}%
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\long\def\doifinstring#1%%
+ {\edef\@@@instring{#1}% expand #1 here
+ \ifx\@@@instring\empty
+ \@EA\gobbletwoarguments
+ \else
+ \@EA\dodoifinstring
+ \fi}
+
+\long\def\dodoifinstring#1%
+ {\p!doifinstringelse\@@@instring{#1}%
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+\long\def\doifnotinstring#1%%
+ {\edef\@@@instring{#1}% expand #1 here
+ \ifx\@@@instring\empty
+ \@EA\gobbletwoarguments
+ \else
+ \@EA\dodoifnotinstring
+ \fi}
+
+\long\def\dodoifnotinstring#1%
+ {\p!doifinstringelse\@@@instring{#1}%
+ \@EA\gobbleoneargument
+ \else
+ \@EA\firstofoneargument
+ \fi}
+
+% replaces prev
+
+% \long\def\p!doifinstringelse#1#2% ##2 can be {abc}
+% {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war{\unless\if##2@}% expand #1 here
+% \expanded{\pp!doifinstringelse#2#1}@@\war} % expand #2 here
+
+\long\def\p!doifinstringelse#1#2% ##2 can be {abc}
+ {\long\@EA\def\@EA\pp!doifinstringelse\@EA##\@EA1#1##2##3\war{\unless\if##2@}% expand #1 here
+ \expandafter\pp!doifinstringelse\normalexpanded{#2#1}@@\war} % expand #2 here
+
+% faster but at some costs
+%
+% \def\setp!doifinstringelse#1#2% ##2 can be {abc}
+% {\long\expandafter\gdef\csname @diie:#1\@EA\endcsname\@EA##\@EA1#1##2##3\war{\unless\if##2@}}% expand #1 here
+%
+% \long\def\p!doifinstringelse#1#2% ##2 can be {abc}
+% {\ifcsname @diie:#1\endcsname \else
+% \setp!doifinstringelse{#1}{#2}%
+% \fi
+% \csname @diie:#1\expandafter\endcsname\normalexpanded{#2#1}@@\war} % expand #2 here
+
+%D The next alternative proved to be upto twice as fast on
+%D tasks like checking reserved words in pretty verbatim
+%D typesetting! This is mainly due to the fact that passing
+%D (expanded) strings is much slower that passing a macro.
+%D
+%D \starttyping
+%D \doifincsnameelse {substring} {\string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D Where \type{\doifinstringelse} does as much expansion as
+%D possible, the latter alternative does minimal (one level)
+%D expansion.
+
+\long\def\p!doifincsnameelse#1#2%
+ {\long\def\pp!doifincsnameelse##1#1##2##3\war
+ {\unless\if##2@}%
+ \@EA\pp!doifincsnameelse#2#1@@\war}
+
+\long\def\doifincsnameelse#1#2% % #3#4%
+ {\edef\@@@instring{#1}%
+ \@EA\p!doifincsnameelse\@EA{\@@@instring}{#2}% % #3\else#4\fi}
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifnumberelse}
+%D
+%D The next macro executes a command depending of the outcome
+%D of a test on numerals. This is probably one of the fastest
+%D test possible, exept from a less robust 10||step
+%D \type{\if}||ladder or some tricky \type{\lcode} checking.
+%D
+%D \starttyping
+%D \doifnumberelse {string} {then ...} {else ...}
+%D \stoptyping
+%D
+%D The macro accepts \type{123}, \type{abc}, \type{{}},
+%D \type{\getal} and \type{\the\count...}. This macro is a
+%D rather dirty one.
+
+\long\def\doifnumberelse#1% does not accept counters
+ {\ifcase0\ifcase1#1\or\or\or\or\or\or\or\or\or\else1\fi\space
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+%D \macros
+%D {makerawcommalist,
+%D rawdoinsetelse,
+%D rawprocesscommalist,
+%D rawprocessaction}
+%D
+%D Some of the commands mentioned earlier are effective but
+%D slow. When one is desperately in need of faster alternatives
+%D and when the conditions are predictable safe, the \type{\raw}
+%D alternatives come into focus. A major drawback is that
+%D they do not take \type{\c!constants} into account, simply
+%D because no expansion is done. This is no problem with
+%D \type{\rawprocesscommalist}, because this macro does not
+%D compare anything. Expandable macros are permitted as search
+%D string.
+%D
+%D \starttyping
+%D \makerawcommalist[string,string,...]\stringlist
+%D \rawdoifinsetelse{string}{string,...}{...}{...}
+%D \rawprocesscommalist[string,string,...]\commando
+%D \rawprocessaction[x][a=>\a,b=>\b,c=>\c]
+%D \stoptyping
+%D
+%D Spaces embedded in the list, for instance after commas,
+%D spoil the search process. The gain in speed depends on the
+%D length of the argument (the longer the argument, the less
+%D we gain).
+
+\def\makerawcommalist[#1]#2% use \processnext ... here
+ {\def\domakerawcommalist##1% we don't expand ##1
+ {\ifx#2\empty
+ \def#2{##1}%
+ \else
+ \@EA\def\@EA#2\@EA{#2,##1}%
+ \fi}%
+ \let#2\empty
+ \processcommalist[#1]\domakerawcommalist}
+
+\def\rawprocesscommaitem#1,#2% #2 eats up preceding space
+ {\if]#1\else
+ \csname\s!next\the\commalevel\endcsname{#1}%
+ \expandafter\rawprocesscommaitem
+ \fi#2}
+
+\def\rawprocesscommalist[#1]#2% accepteert ook [\cs]
+ {\global\advance\commalevel \plusone
+ \expandafter\let\csname\s!next\the\commalevel\endcsname#2%
+ \expandafter\rawprocesscommaitem#1,],% \relax
+ \global\advance\commalevel \minusone }
+
+\def\rawprocesscommacommand[#1]% not really needed
+ {\expanded{\rawprocesscommalist[#1]}}
+
+% \def\rawdoifinsetelse#1#2{\doifinstringelse{,#1,}{,#2,}}
+% \def\rawdoifinset #1#2{\doifinstring {,#1,}{,#2,}}
+
+\def\@@rawempty{,,}
+
+\long\def\rawdoifinsetelse#1%
+ {\edef\@@@instring{,#1,}% expand #1 here
+ \ifx\@@@instring\@@rawempty
+ \@EA\thirdofthreearguments
+ \else
+ \@EA\rawdodoifinsetelse
+ \fi}
+
+\long\def\rawdodoifinsetelse#1%
+ {\p!doifinstringelse\@@@instring{,#1,}%
+ \@EA\firstoftwoarguments
+ \else
+ \@EA\secondoftwoarguments
+ \fi}
+
+\long\def\rawdoifinset#1%
+ {\edef\@@@instring{,#1,}% expand #1 here
+ \ifx\@@@instring\@@rawempty
+ \@EA\gobbletwoarguments
+ \else
+ \@EA\rawdodoifinset
+ \fi}
+
+\long\def\rawdodoifinset#1%%
+ {\p!doifinstringelse\@@@instring{,#1,}%
+ \@EA\firstofoneargument
+ \else
+ \@EA\gobbleoneargument
+ \fi}
+
+%D Some more raw material:
+
+\def\p!rawprocessaction[#1][#2]%
+ {\def\pp!rawprocessaction##1,#1=>##2,##3\war%
+ {\if##3@\else
+ \def\!!processaction{##2}%
+ \fi}%
+ \pp!rawprocessaction,#2,#1=>,@\war}
+
+\def\rawprocessaction[#1]#2[#3]%
+ {\edef\!!stringa{#1}%
+ \edef\!!stringb{undefined}% better \!!undefined
+ \let\!!processaction\!!stringb
+ \ifx\!!stringa\empty
+ \@EA\p!rawprocessaction\@EA[\s!default][#3]%
+ \else
+ \expandafter\p!rawprocessaction\expandafter[\!!stringa][#3]%
+ \ifx\!!processaction\!!stringb
+ \@EA\p!rawprocessaction\@EA[\s!unknown][#3]%
+ \fi
+ \fi
+ \ifx\!!processaction\!!stringb
+ \else
+ \!!processaction
+ \fi}
+
+%D When we process the list \type{a,b,c,d,e}, the raw routine
+%D takes over 30\% less time, when we feed $20+$ character
+%D strings we gain about 20\%. Alternatives which use
+%D \type{\futurelet} perform worse. Part of the speedup is
+%D due to the \type{\let} and \type{\expandafter} in the test.
+
+%D \macros
+%D {dosetvalue,dosetevalue,dosetgvalue,docopyvalue,doresetvalue,
+%D dogetvalue}
+%D
+%D When we are going to do assignments, we have to take
+%D multi||linguality into account. For the moment we keep
+%D things simple and single||lingual.
+%D
+%D \starttyping
+%D \dosetvalue {label} {variable} {value}
+%D \dosetevalue {label} {variable} {value}
+%D \dosetgvalue {label} {variable} {value}
+%D \docopyvalue {to label} {from label} {variable}
+%D \doresetvalue {label} {variable}
+%D \stoptyping
+%D
+%D These macros are in fact auxiliary ones and are not meant
+%D for use outside the assignment macros.
+
+\def\dosetvalue#1#2% #3
+ {\@EA\def\csname#1#2\endcsname} % {#3}}
+
+\def\dosetevalue#1#2% #3
+ {\@EA\edef\csname#1#2\endcsname} % {#3}}
+
+\def\dosetgvalue#1#2% #3
+ {\@EA\gdef\csname#1#2\endcsname} % {#3}}
+
+\def\doresetvalue#1#2%
+ {\@EA\let\csname#1#2\endcsname\empty}
+
+\def\doignorevalue#1#2#3%
+ {\@EA\let\csname#1#2\endcsname\empty}
+
+\def\docopyvalue#1#2#3%
+ {\@EA\def\csname#1#3\endcsname{\csname#2#3\endcsname}}
+
+%D \macros
+%D {doassign,undoassign,doassignempty}
+%D
+%D Assignments are the backbone of \CONTEXT. Abhorred by the
+%D concept of style file hacking, we took a considerable effort
+%D in building a parameterized system. Unfortunately there is a
+%D price to pay in terms of speed. Compared to other packages
+%D and taking the functionality of \CONTEXT\ into account, the
+%D total size of the format file is still very acceptable. Now
+%D how are these assignments done.
+%D
+%D Assignments can be realized with:
+%D
+%D \starttyping
+%D \doassign[label][variable=value]
+%D \undoassign[label][variable=value]
+%D \stoptyping
+%D
+%D and:
+%D
+%D \starttyping
+%D \doassignempty[label][variable=value]
+%D \stoptyping
+%D
+%D Assignments like \type{\doassign} are compatible with:
+%D
+%D \starttyping
+%D \def\labelvariable{value}
+%D \stoptyping
+%D
+%D We do check for the presence of an \type{=} and loudly
+%D complain of it's missed. We will redefine this macro later
+%D on, when a more advanced message mechanism is implemented.
+
+\newif\iferrorisfatal
+
+\def\waitonfatalerror
+ {\iferrorisfatal\wait\fi}
+
+\def\showassignerror#1#2%
+ {\writestatus{setup}{missing or ungrouped '=' after '#1' in line #2}%
+ \waitonfatalerror}
+
+\def\doassignempty[#1][#2=#3]%
+ {\ifcsname#1#2\endcsname\else\dosetvalue{#1}{#2}{#3}\fi}
+
+%D \macros
+%D {getparameters,geteparameters,getgparameters,
+%D forgetparameters}
+%D
+%D Using the assignment commands directly is not our
+%D ideal of user friendly interfacing, so we take some further
+%D steps.
+%D
+%D \starttyping
+%D \getparameters [label] [...=...,...=...]
+%D \forgetparameters [label] [...=...,...=...]
+%D \stoptyping
+%D
+%D Again, the label identifies the category a variable
+%D belongs to. The second argument can be a comma separated
+%D list of assignments.
+%D
+%D \starttyping
+%D \getparameters
+%D [demo]
+%D [alfa=1,
+%D beta=2]
+%D \stoptyping
+%D
+%D is equivalent to
+%D
+%D \starttyping
+%D \def\demoalfa{1}
+%D \def\demobeta{2}
+%D \stoptyping
+%D
+%D
+%D In the pre||multi||lingual stadium \CONTEXT\ took the next
+%D approach. With
+%D
+%D \starttyping
+%D \def\??demo {@@demo}
+%D \def\!!alfa {alfa}
+%D \def\!!beta {beta}
+%D \stoptyping
+%D
+%D calling
+%D
+%D \starttyping
+%D \getparameters
+%D [\??demo]
+%D [\!!alfa=1,
+%D \!!beta=2]
+%D \stoptyping
+%D
+%D lead to:
+%D
+%D \starttyping
+%D \def\@@demoalfa{1}
+%D \def\@@demobeta{2}
+%D \stoptyping
+%D
+%D Because we want to be able to distinguish the \type{!!}
+%D pre||tagged user supplied variables from internal
+%D counterparts, we will introduce a slightly different tag in
+%D the multi||lingual modules. There we will use \type{c!} or
+%D \type{v!}, depending on the context.
+%D
+%D By calling \type{\p!doassign} directly, we save ourselves
+%D some argument passing and gain some speed. Whatever
+%D optimizations we do, this command will always be one of the
+%D bigger bottlenecks.
+%D
+%D The alternative \type{\geteparameters} --- it's funny to
+%D see that this alternative saw the light so lately --- can be
+%D used to do expanded assigments.
+
+\let\currentvalue\empty
+
+\def\getparameters {\dogetparameters\dosetvalue}
+\def\geteparameters {\dogetparameters\dosetevalue}
+\def\getgparameters {\dogetparameters\dosetgvalue}
+\def\forgetparameters{\dogetparameters\doignorevalue}
+
+\let\getexpandedparameters=\geteparameters
+
+% \def\dogetparameters#1[#2]#3[#4%
+% {\if\noexpand#4]%
+% \expandafter\gobbleoneargument
+% \else
+% \def\p!dogetparameter{\p!doassign#1#2}%
+% \expandafter\xdogetparameters
+% \fi#4}
+
+\def\dogetparameters#1[#2]#3[#4%
+ {\if\noexpand#4]%
+ \expandafter\gobbleoneargument
+ \else
+ \let\setsomevalue#1%
+ \def\p!dogetparameter{\p!doassign#2}%
+ \expandafter\xdogetparameters
+ \fi#4}
+
+\def\xdogetparameters#1]%
+ {\xprocesscommaitem#1,],\@relax@}
+
+\long\def\xprocesscommaitem#1,#2% #2 takes space before ,
+ {\if,#1,% dirty trick for testing #1=empty
+ \@EA\xprocesscommaitem
+ \else\if]#1%
+ \@EAEAEA\gobbleoneargument
+ \else
+ \p!dogetparameter\@relax@#1==\empty\@relax@
+ \@EAEAEA\xprocesscommaitem
+ \fi\fi#2}
+
+\def\xshowassignerror#1#2#3%
+ {\showassignerror{#2}{\the\inputlineno\space(#1)}}
+
+% \def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@
+% {\ifx\empty#3\empty
+% \@EA\xshowassignerror
+% \else\ifx#5\empty
+% \@EAEAEA\xshowassignerror
+% \else
+% \@EAEAEA#1%
+% \fi\fi
+% {#2}{#3}{#4}}
+
+% \def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@
+% {\ifx\empty#3\empty
+% \@EA\xshowassignerror
+% \else\ifx#5\empty
+% \@EAEAEA\xshowassignerror
+% \else
+% \ifcsname#2#3\endcsname
+% \@EA\let\@EA\currentvalue\csname#2#3\endcsname
+% \else
+% \let\currentvalue\empty
+% \fi
+% \@EAEAEA#1%
+% \fi\fi
+% {#2}{#3}{#4}}
+
+\def\p!n!doassign#1\@relax@#2=#3=#4#5\@relax@
+ {\ifx\empty#2\empty
+ \@EA\xshowassignerror
+ \else\ifx#4\empty
+ \@EAEAEA\xshowassignerror
+ \else
+ \@EAEAEA\setsomevalue
+ \fi\fi
+ {#1}{#2}{#3}}
+
+
+\def\p!e!doassign#1\@relax@#2=#3=#4#5\@relax@
+ {\ifx\empty#2\empty
+ \@EA\xshowassignerror
+ \else\ifx#4\empty
+ \@EAEAEA\xshowassignerror
+ \else
+ \ifcsname#1#2\endcsname
+ \@EA\let\@EA\currentvalue\csname#1#2\endcsname
+ \else
+ \let\currentvalue\empty
+ \fi
+ \@EAEAEA\setsomevalue
+ \fi\fi
+ {#1}{#2}{#3}}
+
+\let\p!doassign\p!n!doassign
+
+% \def\doassign [#1][#2]{\p!doassign\dosetvalue #1\@relax@#2==\empty\@relax@}
+% \def\doeassign [#1][#2]{\p!doassign\dosetevalue #1\@relax@#2==\empty\@relax@}
+% \def\undoassign[#1][#2]{\p!doassign\doresetvalue#1\@relax@#2==\empty\@relax@}
+
+\def\doassign [#1][#2]{\let\setsomevalue\dosetvalue \p!doassign#1\@relax@#2==\empty\@relax@}
+\def\doeassign [#1][#2]{\let\setsomevalue\dosetevalue \p!doassign#1\@relax@#2==\empty\@relax@}
+\def\undoassign[#1][#2]{\let\setsomevalue\doresetvalue\p!doassign#1\@relax@#2==\empty\@relax@}
+
+%D \macros{currentvalue}
+%D
+%D Just in case a \type{\getparameter} argument itself ends up
+%D inside a \type{\write} or other expandable location, our
+%D new macro needs a default value.
+%D
+%D \starttyping
+%D \getparameters[xxx][aaa=bbb]\par
+%D \getparameters[xxx][=bbb]\par
+%D \getparameters[xxx][aaa=]\par
+%D \getparameters[xxx][=]\par
+%D \getparameters[xxx][aaa]\par
+%D \stoptyping
+
+%D \macros {expandparameters}
+%D
+%D Example usage:
+%D
+%D \startbuffer
+%D \getparameters[taco][name=taco]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \expandparameters \getparameters[taco][name=\currentvalue\space hoekwater]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \getparameters[taco][name=\currentvalue\space hoekwater]
+%D \convertcommand\taconame\to\ascii \ascii
+%D \stopbuffer
+%D
+%D \typebuffer
+%D \startlines
+%D \getbuffer
+%D \stoplines
+
+%D Here we hook in the code (beware, this is the optimized get **):
+
+\def\xdoget@n@parameters#1]%
+ {\xprocesscommaitem#1,],\@relax@}
+
+\def\xdoget@e@parameters#1]%
+ {\let\dosetnvalue\dosetvalue
+ \let\dosetvalue\dosetevalue
+ \let\p!doassign\p!e!doassign
+ \xprocesscommaitem#1,],\@relax@
+ \let\p!doassign\p!n!doassign
+ \let\dosetvalue\dosetnvalue
+ \let\xdogetparameters\xdoget@n@parameters
+ \let\currentvalue\empty}
+
+\let\xdogetparameters\xdoget@n@parameters % **
+
+\def\expandparameters{\let\xdogetparameters\xdoget@e@parameters}
+
+%D \macros
+%D {getemptyparameters}
+%D
+%D Sometimes we explicitly want variables to default to an
+%D empty string, so we welcome:
+%D
+%D \starttyping
+%D \getemptyparameters [label] [...=...,...=...]
+%D \stoptyping
+
+\def\getemptyparameters[#1]#2[#3]%
+ {\def\p!dogetemptyparameter##1{\doassignempty[#1][##1]}%
+ \processcommalist[#3]\p!dogetemptyparameter}
+
+%D \macros
+%D {copyparameters}
+%D
+%D Some \CONTEXT\ commands take their default setups from
+%D others. All commands that are able to provide backgounds
+%D or rules around some content, for instance default to the
+%D standard command for ruled boxes. Is situations like this
+%D we can use:
+%D
+%D \starttyping
+%D \copyparameters [to-label] [from-label] [name1,name2,...]
+%D \stoptyping
+%D
+%D For instance
+%D
+%D \starttyping
+%D \copyparameters
+%D [internal][external]
+%D [alfa,beta]
+%D \stoptyping
+%D
+%D Leads to:
+%D
+%D \starttyping
+%D \def\internalalfa {\externalalfa}
+%D \def\internalbeta {\externalbeta}
+%D \stoptyping
+%D
+%D By using \type{\docopyvalue} we've prepared this command
+%D for use in a multi||lingual environment.
+
+\def\copyparameters[#1]#2[#3]#4[#5]%
+ {\doifnot{#1}{#3}
+ {\def\docopyparameter{\docopyvalue{#1}{#3}}% ##1
+ \processcommalist[#5]\docopyparameter}}
+
+%D \macros
+%D {ifparameters,checkparameters}
+%D
+%D A slightly different one is \type{\checkparameters}, which
+%D also checks on the presence of a~\type{=}.
+%D
+%D The boolean \type{\ifparameters} can be used afterwards.
+%D Combining both in one \type{\if}||macro would lead to
+%D problems with nested \type{\if}'s.
+%D
+%D \starttyping
+%D \checkparameters[argument]
+%D \stoptyping
+
+\newif\ifparameters
+
+\def\p!checkparameters#1=#2#3\war%
+ {\if#2@\parametersfalse\else\parameterstrue\fi}
+
+\def\checkparameters[#1]%
+ {\p!checkparameters#1=@@\war}
+
+%D \macros
+%D {getfromcommalist,getfromcommacommand,
+%D commalistelement,
+%D getcommalistsize,getcommacommandsize}
+%D
+%D It's possible to get an element from a commalist or a
+%D command representing a commalist.
+%D
+%D \starttyping
+%D \getfromcommalist [string] [n]
+%D \getfromcommacommand [string,\strings,string,...] [n]
+%D \stoptyping
+%D
+%D The difference betwee the two of them is the same as the
+%D difference between \type{\processcomma...}. The found string
+%D is stored in \type{\commalistelement}.
+%D
+%D We can calculate the size of a comma separated list by
+%D using:
+%D
+%D \starttyping
+%D \getcommalistsize [string,string,...]
+%D \getcommacommandsize [string,\strings,string,...]
+%D \stoptyping
+%D
+%D Afterwards, the length is available in the macro
+%D \type{\commalistsize} (not a \COUNTER).
+
+\newcount\commalistcounter
+
+\def\commalistsize{0}
+
+\def\p!dogetcommalistsize#1%
+ {\advance\commalistcounter\plusone}
+
+\def\getcommalistsize#1]% don't loose [{#1}]
+ {\commalistcounter\zerocount
+ \processcommalist#1]\p!dogetcommalistsize % was [{#1}]
+ \edef\commalistsize{\the\commalistcounter}}
+
+\def\getcommacommandsize[#1]%
+ {\edef\commacommand{#1}%
+ \scratchtoks\expandafter{\expandafter[\commacommand]}%
+ \expandafter\getcommalistsize\the\scratchtoks }
+
+% to be tested first
+%
+% \def\getcommacommandsize[#1]%
+% {\expanded{\getcommalistsize[#1]}}
+
+% \def\p!dogetfromcommalist#1%
+% {\advance\commalistcounter \minusone
+% \ifcase\commalistcounter
+% \def\commalistelement{#1}%
+% \begingroup\def\doprocesscommaitem##1]{\endgroup}%
+% \fi}
+
+\def\p!dogetfromcommalist#1%
+ {\advance\commalistcounter \minusone
+ \ifcase\commalistcounter
+ \def\commalistelement{#1}%
+ \expandafter\quitcommalist
+ \fi}
+
+\def\getfromcommalist[#1]#2[#3]%
+ {\let\commalistelement\empty
+ \commalistcounter#3\relax
+ \processcommalist[#1]\p!dogetfromcommalist}
+
+\def\getfromcommacommand[#1]%
+ {\expanded{\getfromcommalist[#1]}}
+
+%D Watertight (and efficient) solutions are hard to find, due
+%D to the handling of braces during parameters passing and
+%D scanning. Nevertheless:
+%D
+%D \startbuffer
+%D \def\dosomething#1{(#1=\commalistsize) }
+%D
+%D \getcommalistsize [\hbox{$a,b,c,d,e,f$}] \dosomething 1
+%D \getcommalistsize [{a,b,c,d,e,f}] \dosomething 1
+%D \getcommalistsize [{a,b,c},d,e,f] \dosomething 4
+%D \getcommalistsize [a,b,{c,d,e},f] \dosomething 4
+%D \getcommalistsize [a{b,c},d,e,f] \dosomething 4
+%D \getcommalistsize [{a,b}c,d,e,f] \dosomething 4
+%D \getcommalistsize [] \dosomething 0
+%D \getcommalistsize [{[}] \dosomething 1
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D reports:
+%D
+%D \getbuffer
+
+%D \macros
+%D {dogetcommalistelement,dogetcommacommandelement}
+%D
+%D For low level (fast) purposes, we can also use the next
+%D alternative, which can handle 8~elements at most.
+%D
+%D \starttyping
+%D \dogetcommalistelement1\from a,b,c\to\commalistelement
+%D \stoptyping
+
+\def\dodogetcommalistelement#1\from#2,#3,#4,#5,#6,#7,#8\to#9%
+ {\edef#9{\ifcase#1\relax\or#2\or#3\or#4\or#5\or#6\or#7\or#8\fi}}
+
+\def\dogetcommalistelement#1\from#2\to%
+ {\dodogetcommalistelement#1\from#2,,,,,,\to}
+
+% check sources
+
+\def\dogetcommacommandelement#1\from#2\to%
+ {\@EA\dodogetcommalistelement\@EA#1\@EA\from#2,,,,,,\to}
+
+%D \macros
+%D {dosingleargument,dodoubleargument,dotripleargument,
+%D doquadrupleargument,doquintupleargument,dosixtupleargument,
+%D doseventupleargument}
+%D
+%D When working with delimited arguments, spaces and
+%D lineendings can interfere. The next set of macros uses
+%D \TEX' internal scanner for grabbing everything between
+%D arguments. Forgive me the funny names.
+%D
+%D \starttyping
+%D \dosingleargument\commando = \commando[#1]
+%D \dodoubleargument\commando = \commando[#1][#2]
+%D \dotripleargument\commando = \commando[#1][#2][#3]
+%D \doquadrupleargument\commando = \commando[#1][#2][#3][#4]
+%D \doquintupleargument\commando = \commando[#1][#2][#3][#4][#5]
+%D \dosixtupleargument\commando = \commando[#1][#2][#3][#4][#5][#6]
+%D \doseventupleargument\command = \commando[#1][#2][#3][#4][#5][#6][#7]
+%D \stoptyping
+%D
+%D These macros are used in the following way:
+%D
+%D \starttyping
+%D \def\dosetupsomething[#1][#2]%
+%D {... #1 ... #2 ...}
+%D
+%D \def\setupsomething
+%D {\dodoubleargument\dosetupsomething}
+%D \stoptyping
+%D
+%D The implementation can be surprisingly simple and needs no
+%D further explanation, like:
+%D
+%D \starttyping
+%D \def\dosingleargument#1[#2]%
+%D {#1[#2]}
+%D \def\dotripleargument#1[#2]#3[#4]#5[#6]%
+%D {#1[#2][#4][#6]}
+%D \def\doquintupleargument#1%
+%D {\def\dodoquintupleargument[##1]##2[##3]##4[##5]##6[##7]##8[##9]%
+%D {#1[##1][##3][##5][##7][##9]}%
+%D \dodoquintupleargument}
+%D \stoptyping
+%D
+%D Because \TEX\ accepts 9~arguments at most, we have to use
+%D two||step solution when getting five or more arguments.
+%D
+%D When developing more and more of the real \CONTEXT, we
+%D started using some alternatives that provided empty
+%D arguments (in fact optional ones) whenever the user failed
+%D to supply them. Because this more complicated macros enable
+%D us to do some checking, we reimplemented the non||empty
+%D ones.
+
+\def\dosingleargument {\let\expectedarguments\plusone \dosingleempty }
+\def\dodoubleargument {\let\expectedarguments\plustwo \dodoubleempty }
+\def\dotripleargument {\let\expectedarguments\plusthree \dotripleempty }
+\def\doquadrupleargument {\let\expectedarguments\plusfour \doquadrupleempty }
+\def\doquintupleargument {\let\expectedarguments\plusfive \doquintupleempty }
+\def\dosixtupleargument {\let\expectedarguments\plussix \dosixtupleempty }
+\def\doseventupleargument{\let\expectedarguments\plusseven \doseventupleempty}
+
+%D \macros
+%D {iffirstagument,ifsecondargument,ifthirdargument,
+%D iffourthargument,iffifthargument,ifsixthargument,
+%D ifseventhargument}
+%D
+%D We use some signals for telling the calling macros if all
+%D wanted arguments are indeed supplied by the user.
+
+\newif\iffirstargument
+\newif\ifsecondargument
+\newif\ifthirdargument
+\newif\iffourthargument
+\newif\iffifthargument
+\newif\ifsixthargument
+\newif\ifseventhargument
+
+%D \macros
+%D {dosingleempty,dodoubleempty,dotripleempty,
+%D doquadrupleempty,doquintupleempty,dosixtupeempty,
+%D doseventupleempty}
+%D
+%D The empty argument supplying macros mentioned before, look
+%D like:
+%D
+%D \starttyping
+%D \dosingleempty \command
+%D \dodoubleempty \command
+%D \dotripleempty \command
+%D \doquadrupleempty \command
+%D \doquintupleempty \command
+%D \dosixtupleempty \command
+%D \doseventupleempty\command
+%D \stoptyping
+%D
+%D So \type{\dodoubleempty} leades to:
+%D
+%D \starttyping
+%D \command[#1][#2]
+%D \command[#1][]
+%D \command[][]
+%D \stoptyping
+%D
+%D Depending of the generousity of the user. Afterwards one can
+%D use the \type{\if...argument} boolean. For novice: watch
+%D the stepwise doubling of \type{#}'s
+
+% idea: \ignorespaces afterwards
+
+\chardef\noexpectedarguments=0
+\chardef\expectedarguments =0
+
+\def\showargumenterror#1#2%
+ {\writestatus{systems}{\number#1 argument(s) expected in line #2}}
+
+\def\doshowargumenterror
+ {\ifnum\expectedarguments>\noexpectedarguments
+ \showargumenterror{\number\expectedarguments}{\number\inputlineno}%
+ \fi
+ \noshowargumenterror}
+
+\def\noshowargumenterror
+ {\let\expectedarguments\noexpectedarguments}
+
+\long\def\dogetargument#1#2#3#4%
+ {\let\charactertoken=#1%
+ \def\!!stringa{\noshowargumenterror#3\dodogetargument}%
+ \def\!!stringb{\doshowargumenterror#4\dodogetargument#1#2}%
+ \futurelet\nexttoken\inspectnextcharacter}
+
+\def\getsingleempty#1#2#3%
+ {\def\dodogetargument%
+ {#3}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getdoubleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\gettripleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument#1####1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2%
+ #1{####1}#2}%
+ \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getquadrupleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument#1####1#2%
+ {\def\dodogetargument#1########1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2%
+ #1{####1}#2%
+ #1{########1}#2}%
+ \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+ \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getquintupleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument#1####1#2%
+ {\def\dodogetargument#1########1#2%
+ {\def\dodogetargument#1################1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2%
+ #1{####1}#2%
+ #1{########1}#2%
+ #1{################1}#2}%
+ \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}%
+ \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+ \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getsixtupleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument#1####1#2%
+ {\def\dodogetargument#1########1#2%
+ {\def\dodogetargument#1################1#2%
+ {\def\dodogetargument#1################################1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2%
+ #1{####1}#2%
+ #1{########1}#2%
+ #1{################1}#2%
+ #1{################################1}#2}%
+ \dogetargument#1#2\sixthargumenttrue\sixthargumentfalse}%
+ \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}%
+ \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+ \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\getseventupleempty#1#2#3%
+ {\def\dodogetargument#1##1#2%
+ {\def\dodogetargument#1####1#2%
+ {\def\dodogetargument#1########1#2%
+ {\def\dodogetargument#1################1#2%
+ {\def\dodogetargument#1################################1#2%
+ {\def\dodogetargument#1################################%
+ ################################1#2%
+ {\def\dodogetargument%
+ {#3#1{##1}#2%
+ #1{####1}#2%
+ #1{########1}#2%
+ #1{################1}#2%
+ #1{################################1}#2%
+ #1{################################%
+ ################################1}#2}%
+ \dogetargument#1#2\seventhargumenttrue\seventhargumentfalse}%
+ \dogetargument#1#2\sixthargumenttrue\sixthargumentfalse}%
+ \dogetargument#1#2\fifthargumenttrue\fifthargumentfalse}%
+ \dogetargument#1#2\fourthargumenttrue\fourthargumentfalse}%
+ \dogetargument#1#2\thirdargumenttrue\thirdargumentfalse}%
+ \dogetargument#1#2\secondargumenttrue\secondargumentfalse}%
+ \dogetargument#1#2\firstargumenttrue\firstargumentfalse}
+
+\def\dosingleempty {\getsingleempty []}
+\def\dodoubleempty {\getdoubleempty []}
+\def\dotripleempty {\gettripleempty []}
+\def\doquadrupleempty {\getquadrupleempty []}
+\def\doquintupleempty {\getquintupleempty []}
+\def\dosixtupleempty {\getsixtupleempty []}
+\def\doseventupleempty{\getseventupleempty[]}
+
+%D Because some of these are called quite often, we will now
+%D replace the more general version by alternatives tuned for
+%D speed.
+
+\def\dosingleempty#1%
+ {\noshowargumenterror % \relax % prevents lookahead, brr
+ \doifnextoptionalelse
+ {\firstargumenttrue#1}
+ {\dosinglefakeempty#1}}
+
+\def\dodoubleempty#1%
+ {\noshowargumenterror % \relax % prevents lookahead, brr
+ \doifnextoptionalelse
+ {\dodoubletestempty#1}
+ {\dodoublefakeempty#1}}
+
+\def\dotripleempty#1%
+ {\noshowargumenterror % \relax % prevents lookahead, brr
+ \doifnextoptionalelse
+ {\dotripletestempty#1}
+ {\dotriplefakeempty#1}}
+
+\def\dosinglefakeempty#1%
+ {\firstargumentfalse#1[]}
+
+\def\dodoublefakeempty#1%
+ {\firstargumentfalse\secondargumentfalse#1[][]}
+
+\def\dotriplefakeempty#1%
+ {\firstargumentfalse\secondargumentfalse\thirdargumentfalse#1[][][]}
+
+\long\def\dodoubletestempty#1[#2]%
+ {\firstargumenttrue
+ \doifnextoptionalelse
+ {\secondargumenttrue #1[{#2}]}
+ {\secondargumentfalse#1[{#2}][]}}
+
+\long\def\dotripletestempty#1[#2]%
+ {\firstargumenttrue
+ \doifnextoptionalelse
+ {\dotripletestemptyx #1[{#2}]}
+ {\secondargumentfalse
+ \thirdargumentfalse #1[{#2}][][]}}
+
+\long\def\dotripletestemptyx#1[#2][#3]%
+ {\secondargumenttrue
+ \doifnextoptionalelse
+ {\thirdargumenttrue #1[{#2}][{#3}]}
+ {\thirdargumentfalse#1[{#2}][{#3}][]}}
+
+%D \macros
+%D {strippedcsname}
+%D
+%D The next macro can be very useful when using \type{\csname}
+%D like in:
+%D
+%D \starttyping
+%D \csname if\strippedcsname\something\endcsname
+%D \stoptyping
+%D
+%D This expands to \type{\ifsomething}.
+
+\def\strippedcsname
+ {\expandafter\gobbleoneargument\string}
+
+%D \macros
+%D {complexorsimple,complexorsimpleempty}
+%D
+%D Setups can be optional. A command expecting a setup is
+%D prefixed by \type{\complex}, a command without one gets the
+%D prefix \type{\simple}. Commands like this can be defined by:
+%D
+%D \starttyping
+%D \complexorsimple\command
+%D \stoptyping
+%D
+%D When \type{\command} is followed by a \type{[setup]}, then
+%D
+%D \starttyping
+%D \complexcommand [setup]
+%D \stoptyping
+%D
+%D executes, else we get
+%D
+%D \starttyping
+%D \simplecommand
+%D \stoptyping
+%D
+%D An alternative for \type{\complexorsimple} is:
+%D
+%D \starttyping
+%D \complexorsimpleempty {command}
+%D \stoptyping
+%D
+%D Depending on the presence of \type{[setup]}, this one
+%D leads to one of:
+%D
+%D \starttyping
+%D \complexcommando [setup]
+%D \complexcommando []
+%D \stoptyping
+%D
+%D Many \CONTEXT\ commands started as complex or simple ones,
+%D but changed into more versatile (more object oriented) ones
+%D using the \type{\get..argument} commands.
+
+\def\complexorsimple#1%
+ {% \relax % prevents lookahead, brrr
+ \doifnextoptionalelse
+ {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
+ {\firstargumentfalse\csname\s!simple \strippedcsname#1\endcsname}}
+
+\def\complexorsimpleempty#1%
+ {% \relax % prevents lookahead, brrr
+ \doifnextoptionalelse
+ {\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
+ {\firstargumentfalse\csname\s!complex\strippedcsname#1\endcsname[]}}
+
+%D \macros
+%D {definecomplexorsimple,definecomplexorsimpleempty}
+%D
+%D The previous commands are used that often that we found it
+%D worthwile to offer two more alternatives. Watch the build
+%D in protection.
+
+\def\docomplexorsimple#1#2%
+ {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#2}}
+
+\def\docomplexorsimpleempty#1%
+ {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
+
+\def\definecomplexorsimple#1%
+ {\unexpanded\edef#1%
+ {\noexpand\docomplexorsimple
+ \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname
+ \@EA\noexpand\csname\s!simple \strippedcsname#1\endcsname}}
+
+\def\definecomplexorsimpleempty#1%
+ {\unexpanded\edef#1%
+ {\noexpand\docomplexorsimpleempty
+ \@EA\noexpand\csname\s!complex\strippedcsname#1\endcsname}}
+
+%D These commands are called as:
+%D
+%D \starttyping
+%D \definecomplexorsimple\command
+%D \stoptyping
+%D
+%D Of course, we must have available
+%D
+%D \starttyping
+%D \def\complexcommand[#1]{...}
+%D \def\simplecommand {...}
+%D \stoptyping
+%D
+%D Using this construction saves a few string now and then.
+
+%D \macros
+%D {dosinglegroupempty,dodoublegroupempty,dotriplegroupempty,
+%D doquadruplegroupempty, doquintuplegroupempty}
+%D
+%D We've already seen some commands that take care of
+%D optional arguments between \type{[]}. The next two commands
+%D handle the ones with \type{{}}. They are called as:
+%D
+%D \starttyping
+%D \dosinglegroupempty \ineedONEargument
+%D \dodoublegroupempty \ineedTWOarguments
+%D \dotriplegroupempty \ineedTHREEarguments
+%D \doquadruplegroupempty \ineedFOURarguments
+%D \doquintuplegroupempty \ineedFIVEarguments
+%D \stoptyping
+
+%D We can add additional definitions later when we have defined
+%D \type {\appendtoks}.
+
+\def \permitspacesbetweengroups{\let\@@permitspacesbetweengroups\zerocount}
+\def\dontpermitspacesbetweengroups{\let\@@permitspacesbetweengroups\plusone}
+
+\dontpermitspacesbetweengroups
+
+%D We can avoid the nasty if handling in \type {syst-gen} by splitting
+%D the lot in pieces so that we have no nested \type {\nextarguments}
+%D potentially being an \type {conditional} token. Okay, these macros
+%D are not called that often but it saves crap when tracing.
+
+\def\dogetgroupargument#1#2%
+ {\let\dogroupargumentyes#1%
+ \let\dogroupargumentnop#2%
+ \futurelet\nextargument\dodogetgroupargument}
+
+\def\dodogetgroupargument
+ {\ifx\nextargument\bgroup
+ \expandafter\dodogetgroupargumentA
+ \else
+ \expandafter\dodogetgroupargumentB
+ \fi}
+
+\def\dodogetgroupargumentA
+ {\noshowargumenterror
+ \dogroupargumentyes\dodogetargument}
+
+\def\dodogetgroupargumentB
+ {\ifcase\@@permitspacesbetweengroups
+ \expandafter\dodogetgroupargumentC
+ \else
+ \expandafter\dodogetgroupargumentD
+ \fi}
+
+\def\dodogetgroupargumentC
+ {\ifx\nextargument\lineending
+ \expandafter\dodogetgroupargumentE
+ \else
+ \expandafter\dodogetgroupargumentF
+ \fi}
+
+\def\dodogetgroupargumentD
+ {\doshowargumenterror
+ \dogroupargumentnop\dodogetargument{}}
+
+\def\dodogetgroupargumentE
+ {\begingroup\def\\ {\endgroup\dogetgroupargument\dogroupargumentyes\dogroupargumentnop}\\}
+
+\def\dodogetgroupargumentF
+ {\ifx\nextargument\blankspace
+ \expandafter\dodogetgroupargumentE % G
+ \else
+ \expandafter\dodogetgroupargumentD % H
+ \fi}
+
+\def\dogetgroupargument#1#2%
+ {\let\dogroupargumentyes#1%
+ \let\dogroupargumentnop#2%
+ \futurelet\nextargument\dodogetgroupargument}
+
+\def\dosinglegroupempty#1%
+ {\def\dodogetargument%
+ {\dontpermitspacesbetweengroups
+ #1}%
+ \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\dodoublegroupempty#1%
+ {\def\dodogetargument##1%
+ {\def\dodogetargument%
+ {\dontpermitspacesbetweengroups
+ #1{##1}}%
+ \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+ \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\dotriplegroupempty#1%
+ {\def\dodogetargument##1%
+ {\def\dodogetargument####1%
+ {\def\dodogetargument%
+ {\dontpermitspacesbetweengroups
+ #1{##1}{####1}}%
+ \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
+ \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+ \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\doquadruplegroupempty#1%
+ {\def\dodogetargument##1%
+ {\def\dodogetargument####1%
+ {\def\dodogetargument########1%
+ {\def\dodogetargument%
+ {\dontpermitspacesbetweengroups
+ #1{##1}{####1}{########1}}%
+ \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}%
+ \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
+ \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+ \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+\def\doquintuplegroupempty#1%
+ {\def\dodogetargument##1%
+ {\def\dodogetargument####1%
+ {\def\dodogetargument########1%
+ {\def\dodogetargument################1%
+ {\def\dodogetargument%
+ {\dontpermitspacesbetweengroups
+ #1{##1}{####1}{########1}{################1}}%
+ \dogetgroupargument\fifthargumenttrue\fifthargumentfalse}%
+ \dogetgroupargument\fourthargumenttrue\fourthargumentfalse}%
+ \dogetgroupargument\thirdargumenttrue\thirdargumentfalse}%
+ \dogetgroupargument\secondargumenttrue\secondargumentfalse}%
+ \dogetgroupargument\firstargumenttrue\firstargumentfalse}
+
+%D These macros can explictly take care of spaces, which means
+%D that the next definition and calls are valid:
+%D
+%D \starttyping
+%D \def\test#1#2#3{[#1#2#3]}
+%D
+%D \dotriplegroupempty\test {a}{b}{c}
+%D \dotriplegroupempty\test {a}{b}
+%D \dotriplegroupempty\test {a}
+%D \dotriplegroupempty\test
+%D \dotriplegroupempty\test {a} {b} {c}
+%D \dotriplegroupempty\test {a} {b}
+%D \dotriplegroupempty\test
+%D {a}
+%D {b}
+%D \stoptyping
+%D
+%D And alike.
+
+%D \macros
+%D {firstofoneargument, firstoftwoarguments, firstofthreearguments
+%D secondoftwoarguments, secondofthreearguments,
+%D thirdofthreearguments}
+%D
+%D The next six macros (dedicated to Taco) can conveniently
+%D used to select arguments. Their names explain their
+%D functionality.
+
+\long\def\firstofoneargument #1{#1}
+
+\long\def\firstoftwoarguments #1#2{#1}
+\long\def\secondoftwoarguments #1#2{#2}
+
+\long\def\firstofthreearguments #1#2#3{#1}
+\long\def\secondofthreearguments #1#2#3{#2}
+\long\def\thirdofthreearguments #1#2#3{#3}
+
+\long\def\firstoffourarguments #1#2#3#4{#1}
+\long\def\secondoffourarguments #1#2#3#4{#2}
+\long\def\thirdoffourarguments #1#2#3#4{#3}
+\long\def\fourthoffourarguments #1#2#3#4{#4}
+
+\long\def\firstoffivearguments #1#2#3#4#5{#1}
+\long\def\secondoffivearguments #1#2#3#4#5{#2}
+\long\def\thirdoffivearguments #1#2#3#4#5{#3}
+\long\def\fourthoffivearguments #1#2#3#4#5{#4}
+\long\def\fifthoffivearguments #1#2#3#4#5{#5}
+
+\long\def\firstofsixarguments #1#2#3#4#5#6{#1}
+\long\def\secondofsixarguments#1#2#3#4#5#6{#2}
+\long\def\thirdofsixarguments #1#2#3#4#5#6{#3}
+\long\def\fourthofsixarguments#1#2#3#4#5#6{#4}
+\long\def\fifthofsixarguments #1#2#3#4#5#6{#5}
+\long\def\sixthofsixarguments #1#2#3#4#5#6{#6}
+
+%D \macros
+%D {globalletempty,letempty,letvalueempty,letgvalueempty}
+%D
+%D Trivial:
+
+\def\letempty #1{\let#1\empty}
+\def\globalletempty#1{\global\let#1\empty}
+
+\def\letvalueempty #1{\expandafter\let\csname#1\endcsname\empty}
+\def\letgvalueempty#1{\global\expandafter\let\csname#1\endcsname\empty}
+
+%D \macros
+%D {wait}
+%D
+%D The next macro hardly needs explanation. Because no
+%D nesting is to be expected, we can reuse \type{\wait} within
+%D \type{\wait} itself.
+
+\def\wait
+ {\begingroup
+ \read16 to \wait
+ \endgroup}
+
+%D \macros
+%D {writestring,writeline,writebanner,
+%D writestatus,statuswidth,normalwritestatus}
+%D
+%D Maybe one didn't notice, but we've already introduced a
+%D macro for showing messages. In the multi||lingual modules,
+%D we will also introduce a mechanism for message passing. For
+%D the moment we stick to the core macros:
+%D
+%D \starttyping
+%D \writestring {string}
+%D \writeline
+%D \writestatus {category} {message}
+%D \stoptyping
+%D
+%D Messages are formatted. One can provide the maximum with
+%D of the identification string with the macro \type
+%D {\statuswidth}.
+
+\chardef\statuswidth=15
+\chardef\statuswrite=16
+
+\ifdefined\writestring \else
+
+ \newtoks\everywritestring
+
+ \def\writedirect {\immediate\write\statuswrite}
+ \def\writeline {\writedirect{}}
+ \def\writestring#1{\begingroup\the\everywritestring\writedirect{#1}\endgroup}
+
+\fi
+
+\def\normalwritestatus#1#2%
+ {\writestring{\expandafter\dosplitstatus\expandafter\statuswidth#1%
+ \space\space\space\space\space\space\space
+ \space\space\space\space\space\space\space
+ \space\space\space\space\space\space\end
+ \space:\space#2}}
+
+\def\dosplitstatus#1#2%
+ {\ifcase#1 \expandafter\nosplitstatus\fi#2%
+ \expandafter\dosplitstatus\expandafter{\the\numexpr#1+\minusone\relax}}
+
+\def\nosplitstatus#1\end
+ {}
+
+%D \macros
+%D {debuggerinfo}
+%D
+%D For debugging purposes we can enhance macros with the
+%D next alternative. Here \type{debuggerinfo} stands for both
+%D a macro accepting two arguments and a boolean (in fact a
+%D few macro's too).
+
+\newif\ifdebuggerinfo
+
+\def\debuggerinfo#1#2%
+ {\ifdebuggerinfo
+ \writestatus{debugger}{#1:: #2}%
+ \fi}
+
+\ifdefined\writestatus \else \let\writestatus\normalwritestatus \fi
+\ifdefined\writebanner \else \def\writebanner{\writestring} \fi
+
+% % % % % % % % % % % % % % % % % % % % % % % %
+
+%D \macros
+%D {rawgetparameters}
+%D
+%D A raw and dirty alternative for \type {\getparameters}; no
+%D checking is done!
+
+\def\rawsetparameter#1=#2,%
+ {\if]#1\else
+ \expandafter\def\csname\rawparameterprefix#1\endcsname{#2}%
+ \expandafter\rawsetparameter
+ \fi}
+
+\def\rawgetparameters[#1][#2% some 5-10% faster
+ {\ifx#2]% test is needed, else bomb on [#1][]
+ \expandafter\gobbleoneargument
+ \else
+ \def\rawparameterprefix{#1}%
+ \expandafter\dorawgetparameters
+ \fi#2}
+
+\def\dorawgetparameters#1]%
+ {\expandafter\rawsetparameter#1,]=,}
+
+%D \macros
+%D {doglobal,
+%D redoglobal,dodoglobal,resetglobal}
+%D
+%D The two macros \type {\redoglobal} and \type{\dodoglobal} are
+%D used in this and some other modules to enforce a user
+%D specified \type {\doglobal} action. The last and often only
+%D global assignment in a macro is done with
+%D \type {\dodoglobal}, but all preceding ones with
+%D \type {\redoglobal}. When using only alternatives, one can
+%D reset this mechanism with \type {\resetglobal}.
+
+\def\resetglobal
+ {\let\redoglobal\relax
+ \let\dodoglobal\relax}
+
+\resetglobal
+
+\def\doglobal
+ {\ifx\redoglobal\relax
+ \let\redoglobal\global
+ \let\dodoglobal\@@dodoglobal
+ \fi}
+
+\def\@@dodoglobal
+ {\resetglobal\global}
+
+\def\saveglobal
+ {\let\@@dodoglobal\dodoglobal
+ \let\@@redoglobal\redoglobal}
+
+\def\restoreglobal
+ {\let\redoglobal\@@redoglobal
+ \let\dodoglobal\@@dodoglobal}
+
+%D A very useful application of this macro is \type {\newif},
+%D \TEX's fake boolean type. Not being a primitive,
+%D \type {\global} hopelessly fails here. But a slight
+%D adaption of Knuth's original macro permits:
+%D
+%D \starttyping
+%D \doglobal\newif\iftest
+%D \stoptyping
+%D
+%D Of course one can still say:
+%D
+%D \starttyping
+%D \global\testtrue
+%D \global\testfalse
+%D \stoptyping
+%D
+%D Apart from the prefixes, a few more \type{\expandafters}
+%D are needed:
+
+\def\newif#1%
+ {\scratchcounter\escapechar
+ \escapechar\minusone
+ \expandafter\expandafter\expandafter
+ \redoglobal\expandafter\expandafter\expandafter
+ \edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}%
+ \expandafter\expandafter\expandafter
+ \redoglobal\expandafter\expandafter\expandafter
+ \edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}%
+ \dodoglobal\@if#1{false}%
+ \escapechar\scratchcounter}
+
+%D Also new:
+
+\def\define#1%
+ {\ifdefined#1%
+ \message{[\noexpand#1is already defined]}%
+ \expandafter\def\expandafter\gobbleddefinition
+ \else
+ \expandafter\def
+ \fi#1}
+
+\def\redefine#1%
+ {\ifdefined#1%
+ \message{[\noexpand#1is redefined]}%
+ \fi
+ \def#1}
+
+% \define\hans{hans}
+% \redefine\hans{hans}
+% \define\hans#1[]#2#3{hans}
+
+%D The next variant fits nicely in the setups syntax:
+%D
+%D \starttyping
+%D \starttexdefinition bagger [#1] #2
+%D oeps
+%D #1
+%D oeps
+%D \stoptexdefinition
+%D
+%D \bagger [a] {b}
+%D \stoptyping
+
+\bgroup \obeylines
+
+\gdef\starttexdefinition%
+ {\bgroup%
+ \obeylines%
+ \dostarttexdefinition}
+
+\gdef\dostarttexdefinition #1 #2
+ {\catcode13=\@@ignore%
+ \dodostarttexdefinition{#1}{#2}}%
+
+\long\gdef\dodostarttexdefinition#1#2#3\stoptexdefinition%
+ {\egroup%
+ \long\setvalue{#1}#2{#3}}
+
+\egroup
+
+%D \macros
+%D {newcounter,
+%D increment,decrement}
+%D
+%D Unfortunately the number of \COUNTERS\ in \TEX\ is limited,
+%D but fortunately we can store numbers in a macro. We can
+%D increment such pseudo \COUNTERS\ with \type{\increment}.
+%D
+%D \starttyping
+%D \increment(\counter,20)
+%D \increment(\counter,-4)
+%D \increment(\counter)
+%D \increment\counter
+%D \stoptyping
+%D
+%D After this sequence of commands, the value of
+%D \type{\counter} is 20, 16, 17 and~18. Of course there is
+%D also the complementary command \type{\decrement}.
+%D
+%D Global assignments are possible too, using \type{\doglobal}:
+%D
+%D \starttyping
+%D \doglobal\increment\counter
+%D \stoptyping
+%D
+%D When \type{\counter} is undefined, it's value is initialized
+%D at~0. It is nevertheless better to define a \COUNTER\
+%D explicitly. One reason could be that the \COUNTER\ can be
+%D part of a test with \type{\ifnum} and this conditional does
+%D not accept undefined macro's. The \COUNTER\ in our example
+%D can for instance be defined with:
+%D
+%D \starttyping
+%D \newcounter\counter
+%D \stoptyping
+%D
+%D The command \type{\newcounter} must not be confused with
+%D \type{\newcount}! Of course this mechanism is much slower
+%D than using \TEX's \COUNTERS\ directly. In practice
+%D \COUNTERS\ (and therefore our pseudo counters too) are
+%D seldom the bottleneck in the processing of a text. Apart
+%D from some other incompatilities we want to mention a pitfal
+%D when using \type{\ifnum}.
+%D
+%D \starttyping
+%D \ifnum\normalcounter=\pseudocounter \doif \else \doelse \fi
+%D \ifnum\pseudocounter=\normalcounter \doif \else \doelse \fi
+%D \stoptyping
+%D
+%D In the first test, \TEX\ continues it's search for the
+%D second number after reading \type{\pseudocounter}, while
+%D in the second test, it stops reading after having
+%D encountered a real one. Tests like the first one therefore
+%D can give unexpected results, for instance execution
+%D of \type{\doif} even if both numbers are unequal.
+
+\def\zerocountervalue{0}
+
+\def\newcounter#1%
+ {\dodoglobal\let#1\zerocountervalue}
+
+%D Nowadays we don't mind a few more tokens if we can gain a
+%D bit of speed.
+
+\def\doincrement#1%
+ {\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\plusone \relax}}
+\def\dodecrement#1%
+ {\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+\minusone\relax}}
+
+\def\dododoincrement#1,#2)%
+ {\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi+#2\relax}}
+\def\dodododecrement#1,#2)%
+ {\dodoglobal\edef#1{\the\numexpr\ifdefined#1\ifx#1\relax\else#1\fi\fi-#2\relax}}
+
+\def\dodoincrement(#1%
+ {\doifnextcharelse,{\dododoincrement#1}{\dododoincrement#1,\plusone}}
+\def\dododecrement(#1%
+ {\doifnextcharelse,{\dodododecrement#1}{\dodododecrement#1,\plusone}}
+
+\def\fastincrement#1{\dodoglobal\edef#1{\the\numexpr#1+\plusone \relax}}
+\def\fastdecrement#1{\dodoglobal\edef#1{\the\numexpr#1+\minusone\relax}}
+
+\def\increment{\doifnextcharelse(\dodoincrement\doincrement}
+\def\decrement{\doifnextcharelse(\dododecrement\dodecrement}
+
+\def\incrementvalue#1{\expandafter\increment\csname#1\endcsname}
+\def\decrementvalue#1{\expandafter\decrement\csname#1\endcsname}
+
+%D \macros
+%D {newsignal}
+%D
+%D When writing advanced macros, we cannot do without
+%D signaling. A signal is a small (invisible) kern or penalty
+%D that signals the next macro that something just happened.
+%D This macro can take any action depending on the previous
+%D signal. Signals must be unique and the next macro takes care
+%D of that.
+%D
+%D \starttyping
+%D \newsignal\somesignal
+%D \stoptyping
+%D
+%D Signals old dimensions and can be used in skips, kerns and
+%D tests like \type{\ifdim}.
+
+\newdimen\maximumsignal % step is about 0.00025pt
+
+\def\newsignal#1%
+ {\ifdefined#1\else
+ \advance\maximumsignal 2sp % to be save in rounding
+ \edef#1{\the\maximumsignal}%
+ \fi}
+
+\let\newskimen\newdimen % it's all etex or later now
+
+%D \macros
+%D {strippedcsname}
+%D
+%D The next macro can be very useful when using \type{\csname}
+%D like in:
+%D
+%D \starttyping
+%D \csname if\strippedcsname\something\endcsname
+%D \stoptyping
+
+\ifdefined\letterbackslash \else
+ {\catcode`.=0 .catcode`.\ 12 .xdef.letterbackslash{.string\}} % hack
+\fi
+
+\def\strippedcsname#1% this permits \strippedcsname{\xxx} and \strippedcsname{xxx}
+ {\expandafter\dostrippedcsname\string#1}
+
+\def\dostrippedcsname#1%
+ {\if\noexpand#1\letterbackslash\else#1\fi}
+
+%D \macros
+%D {savenormalmeaning}
+%D
+%D We will use this one in:
+
+\def\savenormalmeaning#1%
+ {\ifcsname normal\strippedcsname#1\endcsname \else
+ \letvalue{normal\strippedcsname#1}#1%
+ \fi}
+
+%D \macros
+%D {newconditional,
+%D settrue, setfalse,
+%D ifconditional}
+%D
+%D \TEX's lacks boolean variables, although the \PLAIN\ format
+%D implements \type{\newif}. The main disadvantage of this
+%D scheme is that it takes three hash table entries. A more
+%D memory saving alternative is presented here. A conditional
+%D is defined by:
+%D
+%D \starttyping
+%D \newconditional\doublesided
+%D \setfalse
+%D \stoptyping
+%D Setting a conditional is done by \type{\settrue} and
+%D \type{\setfalse}:
+%D
+%D \starttyping
+%D \settrue\doublesided
+%D \setfalse
+%D \stoptyping
+%D while testing is accomplished by:
+%D
+%D \starttyping
+%D \ifconditional\doublesided ... \else ... \fi
+%D \setfalse
+%D \stoptyping
+%D We cannot use the simple scheme:
+%D
+%D \starttyping
+%D \def\settrue#1{\let#1=\iftrue}
+%D \def\settrue#1{\let#1=\iffalse}
+%D \stoptyping
+%D
+%D Such an implementation gives problems with nested
+%D conditionals. The next implementation is abaou as fast
+%D and just as straightforward:
+
+% \def\settrue #1{\chardef#1\zerocount}
+% \def\setfalse#1{\chardef#1\plusone}
+
+\def\settrue #1{\let#1\zerocount}
+\def\setfalse#1{\let#1\plusone}
+
+\let\newconditional = \setfalse
+\let\ifconditional = \ifcase
+
+%D \macros
+%D {ifzeropt}
+%D
+%D The next macro is both cosmetic and byte saving. It is
+%D pretty \type{\if}||safe too. It can be used in cases
+%D like:
+%D
+%D \starttyping
+%D \ifzeropt \somedimen ... \else ... \fi
+%D \stoptyping
+
+\let\ifzeropt\ifcase
+
+%D \macros
+%D {dorecurse,recurselevel,recursedepth,
+%D dostepwiserecurse,
+%D for}
+%D
+%D \TEX\ does not offer us powerfull for||loop mechanisms. On
+%D the other hand its recursion engine is quite unique. We
+%D therefore identify the for||looping macros by this method.
+%D The most simple alternative is the one that only needs a
+%D number.
+%D
+%D \starttyping
+%D \dorecurse {n} {whatever we want}
+%D \stoptyping
+%D
+%D This macro can be nested without problems and therefore be
+%D used in situations where \PLAIN\ \TEX's \type{\loop} macro
+%D ungracefully fails. The current value of the counter is
+%D available in \type{\recurselevel}, before as well as after
+%D the \typ{whatever we wat} stuff.
+%D
+%D \starttyping
+%D \dorecurse % inner loop
+%D {10}
+%D {\recurselevel: % outer value
+%D \dorecurse % inner loop
+%D {\recurselevel} % outer value
+%D {\recurselevel} % inner value
+%D \dorecurse % inner loop
+%D {\recurselevel} % outer value
+%D {\recurselevel} % inner value
+%D \endgraf}
+%D \stoptyping
+%D
+%D In this example the first, second and fourth
+%D \type{\recurselevel} concern the outer loop, while the third
+%D and fifth one concern the inner loop. The depth of the
+%D nesting is available for inspection in \type{\recursedepth}.
+%D
+%D Both \type{\recurselevel} and \type{\recursedepth} are
+%D macros. The real \COUNTERS\ are hidden from the user because
+%D we don't want any interference.
+
+\newcount\outerrecurse
+\newcount\innerrecurse
+
+\def\recursedepth{\the\outerrecurse}
+\def\recurselevel{0}
+
+\let\nextrecurse\relax
+
+\def\@@irecurse{@@ir@@} % ecurse} % stepper
+\def\@@arecurse{@@ar@@} % ecurse} % action
+
+\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{#4}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \ifnum#3>0\relax
+ \ifnum#2<#1\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwiserecurse
+ \fi
+ \else
+ \ifnum#3<0\relax
+ \ifnum#1<#2\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwisereverse
+ \fi
+ \else
+ \let\nextrecurse\exitstepwiserecurse
+ \fi
+ \fi\expanded{\nextrecurse{\number#1}{\number#2}{\number#3}}}
+
+\long\def\dodostepwiserecurse#1#2#3% from to step
+ {\ifnum#1>#2\relax
+ \@EA\nodostepwiserecurse
+ \else
+ \def\recurselevel{#1}%
+ \@EAEAEA\redostepwiserecurse\@EA
+ \fi\@EA{\the\numexpr\recurselevel+#3\relax}{#2}{#3}}
+
+\def\expandrecursecontent
+ {\csname\@@arecurse\recursedepth\endcsname}
+
+\def\redostepwiserecurse
+ {\expandrecursecontent\dodostepwiserecurse}
+
+\long\def\dodostepwisereverse#1#2#3% from to step
+ {\ifnum#1<#2\relax
+ \@EA\nodostepwiserecurse
+ \else
+ \def\recurselevel{#1}%
+ \@EAEAEA\redostepwisereverse\@EA
+ \fi\@EA{\the\numexpr\recurselevel#3\relax}{#2}{#3}}
+
+\long\def\dodostepwisereverse#1#2#3% from to step
+ {\ifnum#1<#2\relax
+ \@EA\nodostepwiserecurse
+ \else
+ \def\recurselevel{#1}%
+ \innerrecurse#1\relax
+ \advance\innerrecurse#3\relax
+ \@EAEAEA\redostepwisereverse\@EA
+ \fi\@EA{\the\innerrecurse}{#2}{#3}}
+
+\def\redostepwisereverse
+ {\expandrecursecontent\dodostepwisereverse}
+
+\def\exitstepwiserecurse
+ {\nodostepwiserecurse\relax}
+
+\def\nodostepwiserecurse#1#2#3#4%
+ {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone}
+
+\def\nonostepwiserecurse#1#2#3%
+ {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone}
+
+\def\dorecurse#1%
+ {\dostepwiserecurse1{#1}1}
+
+%D As we can see here, the simple command \type{\dorecurse} is
+%D a special case of the more general:
+%D
+%D \starttyping
+%D \dostepwiserecurse {from} {to} {step} {action}
+%D \stoptyping
+%D
+%D This commands accepts positive and negative steps. Illegal
+%D values are handles as good as possible and the macro accepts
+%D numbers and \COUNTERS.
+%D
+%D \starttyping
+%D \dostepwiserecurse {1} {10} {2} {...}
+%D \dostepwiserecurse {10} {1} {-2} {...}
+%D \stoptyping
+%D
+%D Because the simple case is used often, we implement it
+%D more efficiently:
+
+\long\def\dorecurse#1%
+ {\ifcase#1\relax
+ \expandafter\gobbletwoarguments
+ \or
+ \expandafter\ydorecurse
+ \else
+ \expandafter\xdorecurse
+ \fi{#1}}
+
+\long\def\xdorecurse#1#2%
+ {\global\advance\outerrecurse \plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname{#2}%
+ \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
+ #2%
+ \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone}
+
+\long\def\dodorecurse#1#2% from to
+ {\ifnum#1>#2\relax
+ \@EA\nodorecurse
+ \else
+ \def\recurselevel{#1}%
+ \@EAEAEA\redorecurse
+ \fi\@EA{\the\numexpr\recurselevel+\plusone\relax}{#2}}
+
+\long\def\dodorecurse#1#2% from to
+ {\ifnum#1>#2\relax
+ \@EA\nodorecurse
+ \else
+ \def\recurselevel{#1}%
+ \innerrecurse#1\advance\innerrecurse\plusone
+ \@EAEAEA\redorecurse
+ \fi\@EA{\the\innerrecurse}{#2}}
+
+\def\redorecurse
+ {\expandrecursecontent\dodorecurse}
+
+\def\nodorecurse#1#2#3%
+ {\@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse \minusone }
+
+%D \macros
+%D {doloop,exitloop}
+%D
+%D Sometimes loops are not determined by counters, but by
+%D (a combinations of) conditions. We therefore implement a
+%D straightforward loop, which can only be left when we
+%D explictly exit it. Nesting is supported. First we present
+%D a more extensive alternative.
+%D
+%D \starttyping
+%D \doloop
+%D {Some kind of typesetting punishment \par
+%D \ifnum\pageno>100 \exitloop \fi}
+%D \stoptyping
+%D
+%D When needed, one can call for \type{\looplevel} and
+%D \type{\loopdepth}.
+
+\let\endofloop\donothing
+
+\long\def\doloop#1%
+ {\global\advance\outerrecurse \plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname{#1}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \let\endofloop\dodoloop
+ \dodoloop1} % no \plusone else \recurselevel wrong
+
+\long\def\dodoloop#1%
+ {\def\recurselevel{#1}%
+ \@EA\redoloop\@EA{\the\numexpr\recurselevel+\plusone\relax}}
+
+\def\redoloop
+ {\expandrecursecontent\endofloop}
+
+\def\nodoloop#1%
+ {\let\endofloop\dodoloop % new, permits nested \doloop's
+ \@EA\let\@EA\recurselevel\csname\@@irecurse\recursedepth\endcsname
+ \global\advance\outerrecurse\minusone}
+
+\def\exitloop % \exitloop quits at end
+ {\let\endofloop\nodoloop}
+
+\long\def\exitloopnow#1\endofloop % \exitloopnow quits directly
+ {\nodoloop}
+
+%D The loop is executed at least once, so beware of situations
+%D like:
+%D
+%D \starttyping
+%D \doloop {\exitloop some commands}
+%D \stoptyping
+%D
+%D It's just a matter of putting the text into the \type{\if}
+%D statement that should be there anyway, like in:
+%D
+%D \starttyping
+%D \doloop {\ifwhatever \exitloop \else some commands\fi}
+%D \stoptyping
+%D
+%D You can also quit a loop immediately, by using \type
+%D {\exitloopnow} instead. Beware, this is more sensitive
+%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 level as \type {#1} and the less favoured depth as \type {#2}. The
+%D intended usage is:
+%D
+%D \starttyping
+%D \dorecurse{3}{\definesymbol[test-#1][xx-#1]}
+%D
+%D \def\test{\dorecurse{3}{\definesymbol[test-##1][xx-##1]}} \test
+%D
+%D \symbol[test-1]\quad\symbol[test-2]\quad\symbol[test-3]
+%D \stoptyping
+%D
+%D Since the hashed arguments are expanded, we don't need tricky
+%D expansion here.
+%D
+%D \starttyping
+%D \dorecurse{3}{\expanded{\definesymbol[test-\recurselevel][xx-\recurselevel]}}
+%D \stoptyping
+
+\def\expandrecursecontent
+ {\csname\@@arecurse\recursedepth\@EA\@EA\@EA\endcsname\@EA\@EA\@EA{\@EA\recurselevel\@EA}\@EA{\recursedepth}}
+
+\long\def\xdorecurse#1#2%
+ {\global\advance\outerrecurse \plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#2}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \@EA\dodorecurse\@EA1\@EA{\number#1}}
+
+\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}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \ifnum#3>0\relax
+ \ifnum#2<#1\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwiserecurse
+ \fi
+ \else
+ \ifnum#3<0\relax
+ \ifnum#1<#2\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwisereverse
+ \fi
+ \else
+ \let\nextrecurse\exitstepwiserecurse
+ \fi
+ \fi\expanded{\nextrecurse{\number#1}{\number#2}{\number#3}}}
+
+\long\def\doloop#1%
+ {\global\advance\outerrecurse \plusone
+ \long\global\@EA\def\csname\@@arecurse\recursedepth\endcsname##1##2{#1}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \let\endofloop\dodoloop
+ \dodoloop1} % no \plusone else \recurselevel wrong
+
+% EXPERIMENT
+
+% faster
+
+\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}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \ifnum#3>\zerocount
+ \ifnum#2<#1\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwiserecurse
+ \fi
+ \else
+ \ifnum#3<\zerocount
+ \ifnum#1<#2\relax
+ \let\nextrecurse\exitstepwiserecurse
+ \else
+ \let\nextrecurse\dodostepwisereverse
+ \fi
+ \else
+ \let\nextrecurse\exitstepwiserecurse
+ \fi
+ \fi
+ \expandafter\nextrecurse\normalexpanded{{\number#1}{\number#2}{\number#3}}}
+
+% slightly faster
+
+\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}%
+ \global\@EA\let\csname\@@irecurse\recursedepth\endcsname\recurselevel
+ \csname @swr%
+ \ifnum#3>\zerocount
+ \ifnum#2<#1\else d\fi
+ \else\ifnum#3<\zerocount
+ \ifnum#1<#2\else r\fi
+ \fi\fi
+ \expandafter\endcsname\normalexpanded{{\number#1}{\number#2}{\number#3}}}
+
+\let\@swr \exitstepwiserecurse
+\let\@swrd\dodostepwiserecurse
+\let\@swrr\dodostepwisereverse
+
+%D For special purposes:
+
+\newcount\fastrecursecounter
+\newcount\lastrecursecounter
+\newcount\steprecursecounter
+
+\def\dofastrecurse#1#2#3#4%
+ {\def\fastrecursebody{#4}%
+ \fastrecursecounter#1\relax
+ \lastrecursecounter#2\relax
+ \steprecursecounter#3\relax
+ \def\recurselevel{\number\fastrecursecounter}%
+ \dodofastrecurse}
+
+\def\dodofastrecurse
+ {\ifnum\fastrecursecounter>\lastrecursecounter\else
+ \fastrecursebody
+ \advance\fastrecursecounter\steprecursecounter
+ \expandafter\dodofastrecurse
+ \fi}
+
+%D This alternative looks a bit different and uses a
+%D pseudo counter. When this macro is nested, we have to use
+%D different counters. This time we use keywords.
+%D
+%D \starttyping
+%D \def\alfa{2} \def\beta{100} \def\gamma{3}
+%D
+%D \for \n=55 \to 100 \step 1 \do {... \n ...}
+%D \for \n=\alfa \to \beta \step \gamma \do {... \n ...}
+%D \for \n=\n \to 120 \step 1 \do {... \n ...}
+%D \for \n=120 \to 100 \step -3 \do {... \n ...}
+%D \for \n=55 \to 100 \step 2 \do {... \n ...}
+%D \stoptyping
+%D
+%D Only in the third example we need to predefine \type{\n}.
+%D The use of \type{\od} as a dilimiter would have made nested
+%D use more problematic.
+
+%D Don't use this one, it's kind of obsolete.
+
+\def\for#1=#2\to#3\step#4\do#5%
+ {\dostepwiserecurse{#2}{#3}{#4}
+ {\let#1\recurselevel#5\let#1\recurselevel}}
+
+%D \macros
+%D {newevery,everyline,EveryLine,EveryPar}
+%D
+%D Lets skip to something quite different. It's common use
+%D to use \type {\everypar} for special purposes. In \CONTEXT\
+%D we use this primitive for locating sidefloats. This means
+%D that when user assignments to \type {\everypar} can interfere
+%D with those of the package. We therefore introduce
+%D \type {\EveryPar}.
+%D
+%D The same goes for \type {\EveryLine}. Because \TEX\ offers
+%D no \type {\everyline} primitive, we have to call for
+%D \type {\everyline} when we are working on a line by line
+%D basis. Just by calling \type {\EveryPar{}} and
+%D \type {\EveryLine{}} we restore the old situation.
+
+% \dorecurse{2}{
+% \expanded{\everypar{before \recurselevel\space}}
+% \EveryPar{x } [before \recurselevel\space x] \par
+% \EveryPar{y } [before \recurselevel\space y] \par
+% \EveryPar{} [before \recurselevel] \par
+% \EveryPar{x } \EveryPar{y } \EveryPar{} [before \recurselevel] \par
+% \EveryPar{y } \everypar{before } [before] \par
+% }
+
+% retrofit this into mkii
+
+\def\dowithevery#1%
+ {\expandafter\removetoks\expandafter\the\csname t\strippedcsname#1\endcsname\from#1%
+ \expandafter\appendtoks\expandafter\the\csname t\strippedcsname#1\endcsname\to #1%
+ \csname t\strippedcsname#1\endcsname}
+
+\def\newevery#1#2%
+ {\newtoks#1% we test for redefinition elsewhere
+ \ifx#2\relax\else\ifdefined#2\else
+ \expandafter\newtoks\csname t\strippedcsname#1\endcsname
+ \def#2{\dowithevery#1}%
+ \fi\fi}
+
+%D This one permits definitions like:
+
+\newevery \everypar \EveryPar % we get a warning which is ok
+\newevery \everyline \EveryLine
+
+%D and how about:
+
+\newevery \neverypar \NeveryPar
+
+%D Which we're going to use indeed! When the second argument
+%D equals \type {\relax}, the first token list is created
+%D unless it is already defined.
+
+%D Technically spoken we could have used the method we are
+%D going to present in the visual debugger. First we save
+%D the primitive \type{\everypar}:
+%D
+%D \starttyping
+%D \let\normaleverypar=\everypar
+%D \stoptyping
+%D
+%D Next we allocate a \TOKENLIST\ named \type{\everypar},
+%D which means that \type{\everypar} is no longer a primitive
+%D but something like \type{\toks44}.
+%D
+%D \starttyping
+%D \newtoks\everypar
+%D \stoptyping
+%D
+%D Because \TEX\ now executes \type{\normaleverypar} instead
+%D of \type{\everypar}, we are ready to assign some tokens to
+%D this internally known and used \TOKENLIST.
+%D
+%D \starttyping
+%D \normaleverypar={all the things the system wants to do \the\everypar}
+%D \stoptyping
+%D
+%D Where the user can provide his own tokens to be expanded
+%D every time he expects them to expand.
+%D
+%D \starttyping
+%D \everypar={something the user wants to do}
+%D \stoptyping
+%D
+%D We don't use this method because it undoubtly leads to
+%D confusing situations, especially when other packages are
+%D used, but it's this kind of tricks that make \TEX\ so
+%D powerful.
+
+%D \macros
+%D {convertargument,convertcommand,convertvalue}
+%D
+%D Some persistent experimenting led us to the next macro. This
+%D macro converts a parameter or an expanded macro to it's
+%D textual meaning.
+%D
+%D \starttyping
+%D \convertargument ... \to \command
+%D \stoptyping
+%D
+%D For example,
+%D
+%D \starttyping
+%D \convertargument{one \two \three{four}}\to\ascii
+%D \stoptyping
+%D
+%D The resulting macro \type{\ascii} can be written to a file
+%D or the terminal without problems. In \CONTEXT\ we use this
+%D macro for generating registers and tables of contents.
+%D
+%D The second conversion alternative accepts a command:
+%D
+%D \starttyping
+%D \convertcommand\command\to\ascii
+%D \stoptyping
+%D
+%D Both commands accept the prefix \type{\doglobal} for global
+%D assignments.
+
+\def\convertvalue#1\to
+ {\expandafter\convertcommand\csname#1\endcsname\to}
+
+\def\defconvertedvalue#1#2% less sensitive for \to
+ {\@EA\defconvertedcommand\@EA#1\csname#2\endcsname}
+
+%D \macros
+%D {doifassignmentelse}
+%D
+%D A lot of \CONTEXT\ commands take optional arguments, for
+%D instance:
+%D
+%D \starttyping
+%D \dothisorthat[alfa,beta]
+%D \dothisorthat[first=foo,second=bar]
+%D \dothisorthat[alfa,beta][first=foo,second=bar]
+%D \stoptyping
+%D
+%D Although a combined solution is possible, we prefer a
+%D seperation. The next command takes care of propper
+%D handling of such multi||faced commands.
+%D
+%D \starttyping
+%D \doifassignmentelse {...} {then ...} {else ...}
+%D \stoptyping
+
+% \def\doifassignmentelse#1%
+% {\convertargument#1\to\ascii
+% \doifinstringelse=\ascii}
+
+% \def\doifassignmentelse#1%
+% {\edef\ascii{\detokenize{#1}}%
+% \ifx\ascii\empty
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\docheckifassignmentelse
+% \fi}
+
+% \long\def\dodoifassignmentelse
+% {\expandafter\dododoifnotassignmentelse\ascii=@@\@end@
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\firstoftwoarguments
+% \fi}
+
+\long\def\docheckifassignmentelse#1=#2#3\@end@{\if#2@}%
+
+\long\def\doifassignmentelse#1%
+ {\expandafter\docheckifassignmentelse\detokenize{#1}=@@\@end@
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+% D \macros
+% D {convertasciiafter}
+% D
+% D Sometimes we need to convert an argument to a string (letters
+% D only), for instance when we compare it with another string:
+% D
+% D \starttyping
+% D \convertasciiafter\doifinstringelse{em}{\ascii}{...}
+% D \stoptyping
+%
+% \def\convertasciiafter#1#2%
+% {\@EA#1\@EA{\detokenize{#2}}}
+
+%D In \ETEX\ we can use \type {\detokenize} and gain some
+%D speed, but in general far less that 1\% for \type
+%D {\convertargument} and nil for \type {\convertcommand}.
+%D This macro is more robust than the pure \TEX\ one,
+%D something I found out when primitives like \type
+%D {\jobname} were fed (or something undefined).
+
+\long\def\convertargument#1\to#2{\dodoglobal\edef#2{\detokenize{#1}}}
+\long\def\convertcommand #1\to#2{\dodoglobal\edef#2{\@EA\detokenize\@EA{#1}}} % hm, only second is also ok
+
+\long\def\defconvertedargument #1#2{\edef#1{\detokenize {#2}}}
+\long\def\defconvertedcommand #1#2{\edef#1{\detokenize\@EA{#2}}}
+\long\def\edefconvertedargument#1#2{\edef#1{#2}%
+ \edef#1{\detokenize\@EA{#1}}}
+\long\def\gdefconvertedargument#1#2{\xdef#1{\detokenize {#2}}}
+\long\def\gdefconvertedcommand #1#2{\xdef#1{\detokenize\@EA{#2}}}
+\long\def\xdefconvertedargument#1#2{\xdef#1{#2}%
+ \xdef#1{\detokenize\@EA{#1}}}
+
+%D When you try to convert a primitive command, you'll find
+%D out that the \ETEX\ method fails on for instance \type
+%D {\jobname} in the sense that it returns the filename
+%D instead of just \type {\jobname}. So far this does not
+%D give real problems.
+
+%D This is typically a macro that one comes to after reading
+%D the \TEX book carefully. Even then, the definite solution
+%D was found after rereading the \TEX book. The first
+%D implementation was:
+%D
+%D \starttyping
+%D \def\doconvertargument#1->#2\\\\{#2}
+%D \stoptyping
+%D
+%D The \type{-}, the delimiter \type{\\\\} and the the second
+%D argument are completely redundant.
+
+%D \macros
+%D {showvalue,showargument}
+%D
+%D Two handy macros for testing purposes only:
+
+\def\showvalue#1%
+ {\expandafter\show\csname#1\endcsname}
+
+\def\showvalue#1%
+ {\ifcsname#1\endcsname
+ \expandafter\show\csname#1\endcsname
+ \else
+ \show\undefined
+ \fi}
+
+%D \macros
+%D {doifmeaningelse}
+%D
+%D We can use both commands in testing, but alas, not all
+%D meanings expand to something \type {->}. This is no problem
+%D in the \ETEX\ implementation, but since we want
+%D compatibility, we need:
+%D
+%D \starttyping
+%D \doifmeaningelse {\next} {\something} {true} {false}
+%D \stoptyping
+%D
+%D Watch the one level expansion of the second argument.
+
+\def\doifmeaningelse#1#2%
+ {\edef\!!stringa{\meaning#1}%
+ \def \!!stringb{#2}%
+ \edef\!!stringb{\meaning\!!stringb}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifsamestringselse,doifsamestring,doifnotsamestring}
+%D
+%D The next comparison macro converts the arguments into
+%D expanded strings. This command can be used to compare for
+%D instance \type {\jobname} with a name stored in a macro.
+%D
+%D \starttyping
+%D \doifelse {\jobname}{oeps}{YES}{NO}
+%D \doifsamestringelse{\jobname}{oeps}{YES}{NO}
+%D \stoptyping
+
+% \def\@@doifsamestringelse#1#2#3#4%
+% {\edef\!!stringa{#3}\convertcommand\!!stringa\to\!!stringa
+% \edef\!!stringb{#4}\convertcommand\!!stringb\to\!!stringb
+% \ifx\!!stringa\!!stringb\expandafter#1\else\expandafter#2\fi}
+
+\def\@@doifsamestringelse#1#2#3#4%
+ {\edef\!!stringa{\detokenize\expandafter{\normalexpanded{#3}}}%
+ \edef\!!stringb{\detokenize\expandafter{\normalexpanded{#4}}}%
+ \ifx\!!stringa\!!stringb\expandafter#1\else\expandafter#2\fi}
+
+\def\doifsamestringelse{\@@doifsamestringelse\firstoftwoarguments\secondoftwoarguments}
+\def\doifsamestring {\@@doifsamestringelse\firstofoneargument\gobbleoneargument}
+\def\doifnotsamestring {\@@doifsamestringelse\gobbleoneargument\firstofoneargument}
+
+%D \macros
+%D {ExpandFirstAfter,ExpandSecondAfter,ExpandBothAfter}
+%D
+%D These three commands support expansion of arguments before
+%D executing the commands that uses them. We can best
+%D illustrate this with an example.
+%D
+%D \starttyping
+%D \def\first {alfa,beta,gamma}
+%D \def\second {alfa,epsilon,zeta}
+%D
+%D \ExpandFirstAfter \doifcommon {\first} {alfa} {\message{OK}}
+%D \ExpandSecondAfter \doifcommon {alfa} {\second} {\message{OK}}
+%D \ExpandBothAfter \doifcommon {\first} {\second} {\message{OK}}
+%D
+%D \ExpandFirstAfter\processcommalist[\first]\message
+%D
+%D \ExpandAfter \doifcommon {\first} {alfa} {\message{OK}}
+%D \stoptyping
+%D
+%D The first three calls result in the threefold message
+%D \type{OK}, the fourth one shows the three elements of
+%D \type{\first}. The command \type{\ExpandFirstAfter} takes
+%D care of (first) arguments that are delimited by \type{[ ]},
+%D but the faster \type{\ExpandAfter} does not.
+
+\def\simpleExpandFirstAfter#1%
+ {\long\xdef\@@expanded{\noexpand\ExpandCommand{#1}}\@@expanded}
+
+\def\complexExpandFirstAfter[#1]%
+ {\long\xdef\@@expanded{\noexpand\ExpandCommand[#1]}\@@expanded}
+
+\def\ExpandFirstAfter#1%
+ {\let\ExpandCommand#1%
+ \doifnextoptionalelse\complexExpandFirstAfter\simpleExpandFirstAfter}
+
+\def\ExpandSecondAfter#1#2#3%
+ {\scratchtoks{#2}%
+ \long\xdef\@@expanded{\noexpand#1{\the\scratchtoks}{#3}}\@@expanded}
+
+\def\ExpandBothAfter#1#2#3%
+ {\long\xdef\@@expanded{\noexpand#1{#2}{#3}}\@@expanded}
+
+\def\ExpandAfter#1#2%
+ {\long\xdef\@@expanded{\noexpand#1{#2}}\@@expanded}
+
+%D Now we can for instance define \type{\ifinstringelse} as:
+
+\def\ifinstringelse
+ {\ExpandBothAfter\p!doifinstringelse}
+
+%D \macros
+%D {ConvertToConstant,ConvertConstantAfter}
+%D
+%D When comparing arguments with a constant, we can get into
+%D trouble when this argument consists of tricky expandable
+%D commands. One solution for this is converting the
+%D argument to a string of unexpandable characters. To make
+%D comparison possible, we have to convert the constant too
+%D
+%D \starttyping
+%D \ConvertToConstant\doifelse {...} {...} {then ...} {else ...}
+%D \stoptyping
+%D
+%D This construction is only needed when the first argument
+%D can give troubles. Misuse can slow down processing.
+%D
+%D \starttyping
+%D \ConvertToConstant\doifelse{\c!alfa} {\c!alfa}{...}{...}
+%D \ConvertToConstant\doifelse{alfa} {\c!alfa}{...}{...}
+%D \ConvertToConstant\doifelse{alfa} {alfa} {...}{...}
+%D \ConvertToConstant\doifelse{alfa \alfa test}{\c!alfa}{...}{...}
+%D \stoptyping
+%D
+%D In examples~2 and~3 both arguments equal, in~1 and~4
+%D they differ.
+
+\long\def\ConvertToConstant#1#2#3%
+ {\edef\!!stringa{\expandafter\detokenize\expandafter{#2}}%
+ \edef\!!stringb{\expandafter\detokenize\expandafter{#3}}%
+ #1{\!!stringa}{\!!stringb}}
+
+%D When the argument \type{#1} consists of commands, we had
+%D better use
+%D
+%D \starttyping
+%D \ConvertConstantAfter\processaction[#1][...]
+%D \ConvertConstantAfter\doifelse{#1}{\v!something}{}{}
+%D \stoptyping
+%D
+%D This commands accepts things like:
+%D
+%D \starttyping
+%D \v!constant
+%D constant
+%D \hbox to \hsize{\rubish}
+%D \stoptyping
+%D
+%D As we will see in the core modules, this macro permits
+%D constructions like:
+%D
+%D \starttyping
+%D \setupfootertexts[...][...]
+%D \setupfootertexts[margin][...][...]
+%D \setupfootertexts[\v!margin][...][...]
+%D \stoptyping
+%D
+%D where \type{...} can be anything legally \TEX.
+
+\def\CheckConstantAfter#1#2%
+ {\@EA\convertargument\v!prefix!\to\ascii
+ \convertargument#1\to#2\relax
+ \doifinstringelse\ascii{#2}
+ {\expandafter\convertargument#1\to#2}
+ {}}
+
+\def\ConvertConstantAfter#1#2#3%
+ {\CheckConstantAfter{#2}\asciia
+ \CheckConstantAfter{#3}\asciib
+ #1{\asciia}{\asciib}}
+
+%D \macros
+%D {assignifempty}
+%D
+%D We can assign a default value to an empty macro using:
+%D
+%D \starttyping
+%D \assignifempty \macros {default value}
+%D \stoptyping
+%D
+%D We don't explicitly test if the macro is defined.
+
+\def\assignifempty#1#2% can be sped up
+ {\doifsomething{#1}{\def#1{#2}}} % {\doifnot{#1}{}{\def#1{#2}}}
+
+%D \macros
+%D {gobbleuntil,grabuntil,gobbleuntilrelax,
+%D processbetween,processuntil}
+%D
+%D In \TEX\ gobbling usually stand for skipping arguments, so
+%D here are our gobbling macros.
+%D
+%D In \CONTEXT\ we use a lot of \type{\start}||\type{\stop}
+%D like constructions. Sometimes, the \type{\stop} is used as a
+%D hard coded delimiter like in:
+%D
+%D \starttyping
+%D \def\startcommand#1\stopcommand%
+%D {... #1 ...}
+%D \stoptyping
+%D
+%D In many cases the \type{\start}||\type{\stop} pair is
+%D defined at format generation time or during a job. This
+%D means that we cannot hardcode the \type{\stop} criterium.
+%D Only after completely understanding \type{\csname} and
+%D \type{\expandafter} I was able to to implement a solution,
+%D starting with:
+%D
+%D \starttyping
+%D \grabuntil{stop}\command
+%D \stoptyping
+%D
+%D This commands executes, after having encountered
+%D \type {\stop} the command \type {\command}. This command
+%D receives as argument the text preceding the \type {\stop}.
+%D This means that:
+%D
+%D \starttyping
+%D \def\starthello%
+%D {\grabuntil{stophello}\message}
+%D
+%D \starthello Hello world!\stophello
+%D \stoptyping
+%D
+%D results in: \type{\message{Hello world!}}.
+
+\def\dograbuntil#1#2%
+ {\long\def\next##1#1{#2{##1}}\next}
+
+\def\grabuntil#1%
+ {\expandafter\dograbuntil\expandafter{\csname#1\endcsname}}
+
+%D The next command build on this mechanism:
+%D
+%D \starttyping
+%D \processbetween{string}\command
+%D \stoptyping
+%D
+%D Here:
+%D
+%D \starttyping
+%D \processbetween{hello}\message
+%D \starthello Hello again!\stophello
+%D \stoptyping
+%D
+%D leads to: \type{\message{Hello again!}}. The command
+%D
+%D \starttyping
+%D \gobbleuntil{sequence}
+%D \stoptyping
+%D
+%D is related to these commands. This one simply throws away
+%D everything preceding \type{\command}.
+
+\long\def\processbetween#1#2%
+ {\setvalue{\s!start#1}{\grabuntil{\s!stop#1}{#2}}}
+
+\def\gobbleuntil#1%
+ {\long\def\next##1#1{}\next}
+
+\def\gobbleuntilrelax#1\relax
+ {}
+
+%D The next one simply expands the pickup up tokens.
+%D
+%D \starttyping
+%D \processuntil{sequence}
+%D \stoptyping
+
+\def\processuntil#1%
+ {\long\def\next##1#1{##1}\next}
+
+%D \macros
+%D {groupedcommand}
+%D
+%D Commands often manipulate argument as in:
+%D
+%D \starttyping
+%D \def\doezomaarwat#1{....#1....}
+%D \stoptyping
+%D
+%D A disadvantage of this approach is that the tokens that
+%D form \type{#1} are fixed the the moment the argument is read
+%D in. Normally this is no problem, but for instance verbatim
+%D environments adapt the \CATCODES\ of characters and therefore
+%D are not always happy with already fixed tokens.
+%D
+%D Another problem arises when the argument is grouped not by
+%D \type{{}} but by \type{\bgroup} and \type{\egroup}. Such an
+%D argument fails, because the \type{\bgroup} is een as the
+%D argument (which is quite normal).
+%D
+%D The next macro offers a solution for both unwanted
+%D situations:
+%D
+%D \starttyping
+%D \groupedcommand {before} {after}
+%D \stoptyping
+%D
+%D Which can be used like:
+%D
+%D \starttyping
+%D \def\cite%
+%D {\groupedcommand{\rightquote\rightquote}{\leftquote\leftquote}}
+%D \stoptyping
+%D
+%D This command is equivalent to, but more 'robust' than:
+%D
+%D \starttyping
+%D \def\cite#1%
+%D {\rightquote\rightquote#1\leftquote\leftquote}
+%D \stoptyping
+%D
+%D \starttyping
+%D \def\rightword%
+%D {\groupedcommand{\hfill\hbox}{\parfillskip\!!zeropoint}}
+%D
+%D .......... \rightword{the right way}
+%D \stoptyping
+%D
+%D Here \TEX\ typesets \type{\bf the right way} unbreakable
+%D at the end of the line. The solution mentioned before does
+%D not work here. We also handle
+%D
+%D \starttyping
+%D to be \bold{bold} or not, that's the question
+%D \stoptyping
+%D
+%D and
+%D
+%D \starttyping
+%D to be {\bold bold} or not, that's the question
+%D \stoptyping
+%D
+%D This alternative checks for a \type{\bgroup} token first.
+%D The internal alternative does not accept the box handling
+%D mentioned before, but further nesting works all right. The
+%D extra \type{\bgroup}||\type{\egroup} is needed to keep
+%D \type{\AfterGroup} both into sight and local.
+
+\long\def\HandleGroup#1#2%
+ {\bgroup
+ \long\def\BeforeGroup{\bgroup#1\bgroup\aftergroup\AfterGroup}%
+ \long\def\AfterGroup {#2\egroup\egroup}%
+ \afterassignment\BeforeGroup
+ \let\next=}
+
+\long\def\HandleSimpleGroup#1#2% no inner group (so no kerning interference)
+ {\bgroup
+ %long\def\BeforeGroup{\bgroup#1\aftergroup\AfterGroup}% interferes
+ \long\def\BeforeGroup{\bgroup\aftergroup\AfterGroup#1}%
+ \long\def\AfterGroup {#2\egroup}%
+ \afterassignment\BeforeGroup
+ \let\next=}
+
+\long\def\HandleNoGroup#1#2%
+ {\long\def\AfterGroup{#2\egroup}%
+ \bgroup\aftergroup\AfterGroup#1}
+
+%D I considered it a nuisance that
+%D
+%D \starttyping
+%D \color[green]
+%D {as grass}
+%D \stoptyping
+%D
+%D was not interpreted as one would expect. This is due to the
+%D fact that \type{\futurelet} obeys blank spaces, and a
+%D line||ending token is treated as a blank space. So the final
+%D implementation became:
+
+\long\unexpanded\def\groupedcommand#1#2%
+ {\doifnextbgroupelse{\HandleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
+
+\long\unexpanded\def\simplegroupedcommand#1#2%
+ {\doifnextbgroupelse{\HandleSimpleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
+
+%D Users should be aware of the fact that grouping can
+%D interfere with ones paragraph settings that are executed
+%D after the paragraph is closed. One should therefore
+%D explictly close the paragraph with \type{\par}, else the
+%D settings will be forgotten and not applied. So it's:
+%D
+%D \starttyping
+%D \def\BoldRaggedCenter%
+%D {\groupedcommand{\raggedcenter\bf}{\par}}
+%D \stoptyping
+
+%D \macros
+%D {checkdefined}
+%D
+%D The bigger the system, the greater the change that
+%D user defined commands collide with those that are part of
+%D the system. The next macro gives a warning when a command is
+%D already defined. We considered blocking the definition, but
+%D this is not always what we want.
+%D
+%D \starttyping
+%D \checkdefined {category} {class} {command}
+%D \stoptyping
+%D
+%D The user is warned with the suggestion to use
+%D \type{CAPITALS}. This suggestion is feasible, because
+%D \CONTEXT only defines lowcased macros.
+
+\def\showdefinederror#1#2%
+ {\writestatus\m!systems{#1 #2 replaces a macro, use CAPITALS!}}
+
+\def\checkdefined#1#2#3%
+ {\doifdefined{#3}{\showdefinederror{#2}{#3}}}
+
+%D \macros
+%D {GotoPar,GetPar}
+%D
+%D Typesetting a paragraph in a special way can be done by
+%D first grabbing the contents of the paragraph and processing
+%D this contents grouped. The next macro for instance typesets
+%D a paragraph in boldface.
+%D
+%D \starttyping
+%D \def\remark#1\par%
+%D {\bgroup\bf#1\egroup}
+%D \stoptyping
+%D
+%D This macro has to be called like
+%D
+%D \starttyping
+%D \remark some text ... ending with \par
+%D \stoptyping
+%D
+%D Instead of \type{\par} we can of course use an empty line.
+%D When we started typesetting with \TEX, we already had
+%D produced lots of text in plain \ASCII. In producing such
+%D simple formatted texts, we adopted an open layout, and when
+%D switching to \TEX, we continued this open habit. Although
+%D \TEX\ permits a cramped and badly formatted source, it adds
+%D to confusion and sometimes introduces errors. So we prefer:
+%D
+%D \starttyping
+%D \remark
+%D
+%D some text ... ending with an empty line
+%D \stoptyping
+%D
+%D We are going to implement a mechanism that allows such open
+%D specifications. The definition of the macro handling
+%D \type{\remark} becomes:
+%D
+%D \starttyping
+%D \def\remark%
+%D {\BeforePar{\bgroup\bf}%
+%D \AfterPar{\egroup}%
+%D \GetPar}
+%D \stoptyping
+%D
+%D A macro like \type{\GetPar} can be defined in several
+%D ways. The recent version, the fourth one in a row,
+%D originally was far more complicated, but some functionality
+%D has been moved to other macros.
+%D
+%D We start with the more simple but in some cases more
+%D appropriate alternative is \type{\GotoPar}. This one leaves
+%D \type{\par} unchanged and is therefore more robust. On the
+%D other hand, \type{\AfterPar} is not supported.
+
+\newtoks\BeforePar
+\newtoks\AfterPar
+
+\let\endoflinetoken=^^M
+
+\def\redowithpar\par
+ {\doifnextcharelse\par\redowithpar\dodowithpar}%
+
+\def\dowithpar#1#2%
+ {\def\dodowithpar##1\par{#1##1#2}%
+ \redowithpar\par}
+
+\def\redogotopar\par
+ {\doifnextcharelse\par\redogotopar\dodogotopar}%
+
+\def\dogotopar#1%
+ {\def\dodogotopar{#1}%
+ \redogotopar\par}
+
+\def\GetPar
+ {\expanded
+ {\dowithpar
+ {\the\BeforePar
+ \BeforePar\emptytoks}
+ {\the\AfterPar
+ \BeforePar\emptytoks
+ \AfterPar\emptytoks}}}
+
+\def\GotoPar
+ {\expanded
+ {\dogotopar
+ {\the\BeforePar
+ \BeforePar\emptytoks}}}
+
+%D \macros
+%D {dowithpargument,dowithwargument}
+%D
+%D The next macros are a variation on \type{\GetPar}. When
+%D macros expect an argument, it interprets a grouped sequence
+%D of characters a one token. While this adds to robustness and
+%D less ambiguous situations, we sometimes want to be a bit
+%D more flexible, or at least want to be a bit more tolerant
+%D to user input.
+%D
+%D We start with a commands that acts on paragraphs. This
+%D command is called as:
+%D
+%D \starttyping
+%D \dowithpargument\command
+%D \dowithpargument{\command ... }
+%D \stoptyping
+%D
+%D In \CONTEXT\ we use this one to read in the titles of
+%D chapters, sections etc. The commands responsible for these
+%D activities accept several alternative ways of argument
+%D passing. In these examples, the \type{\par} can be omitted
+%D when an empty line is present.
+%D
+%D \starttyping
+%D \command{...}
+%D \command ... \par
+%D \command
+%D {...}
+%D \command
+%D ... \par
+%D \stoptyping
+
+\def\dowithpargument#1%
+ {\def\nextpar##1 \par{#1{##1}}%
+ \def\nextarg##1{#1{##1}}%
+ \doifnextbgroupelse\nextarg{\doifnextcharelse\par{#1{}}\nextpar}}
+
+%D The \type{p} in the previous command stands for paragraph.
+%D When we want to act upon words we can use the \type{w}
+%D alternative.
+%D
+%D \starttyping
+%D \dowithwargument\command
+%D \dowithwargument{... \command ...}
+%D \stoptyping
+%D
+%D The main difference bwteen two alternatives is in the
+%D handling of \type{\par}'s. This time the space token acts
+%D as a delimiter.
+%D
+%D \starttyping
+%D \command{...}
+%D \command ...
+%D \command
+%D {...}
+%D \command
+%D ...
+%D \stoptyping
+
+\def\dowithwargument#1%
+ {\def\nextwar##1 {#1{##1}}%
+ \def\nextarg##1{#1{##1}}%
+ \doifnextbgroupelse\nextarg\nextwar}
+
+%D \macros
+%D {dorepeat,dorepeatwithcommand}
+%D
+%D When doing repetitive tasks, we stromgly advice to use
+%D \type{\dorecurse}. The next alternative however, suits
+%D better some of the \CONTEXT\ interface commands.
+%D
+%D \starttyping
+%D \dorepeat[n*\command]
+%D \stoptyping
+%D
+%D The value of the used \COUNTER\ can be called within
+%D \type{\command} by \type{\repeater}.
+%D
+%D A slightly different alternative is:
+%D
+%D \starttyping
+%D \dorepeatwithcommand[n*{...}]\command
+%D \stoptyping
+%D
+%D When we call for something like:
+%D
+%D \starttyping
+%D \dorepeatwithcommand[3*{Hello}]\message
+%D \stoptyping
+%D
+%D we get ourselves three \type{\message{Hello}} messages in
+%D a row. In both commands, the \type{n*} is optional. When this
+%D specification is missing, the command executes once.
+
+% this one is obsolete:
+
+\def\dorepeat[#1]%
+ {\dodorepeat#1*\empty*\relax}
+
+\long\def\dodorepeat#1*#2#3*#4\relax
+ {\ifx#2\empty#1\else\dorecurse{#1}{#2#3}\fi}
+
+\def\repeater
+ {\recurselevel}
+
+% this one will be kept
+
+\def\dorepeatwithcommand[#1]%
+ {\dodorepeatwithcommand#1*\empty*\relax}
+
+\long\def\dodorepeatwithcommand#1*#2#3*#4\relax#5%
+ {\ifx#2\empty\redorepeatwithcommand[#1]#5\else\dododorepeatwithcommand{#1}{#2}{#3}#5\fi}
+
+\long\def\dododorepeatwithcommand#1#2#3#4%
+ {\ifx#2\empty % redundant but gives cleaner extensions
+ #4{#1}%
+ \else\ifnum#1<\zerocount
+ \bgroup\scratchcounter#1%
+ \expanded{\egroup\noexpand\dorecurse{\number-\scratchcounter}}{#4{-#2#3}}%
+ \else\ifx#2+%
+ \dorecurse{#1}{#4{#3}}%
+ \else
+ \dorecurse{#1}{#4{#2#3}}%
+ \fi\fi\fi}
+
+\def\redorepeatwithcommand[#1]#2%
+ {#2{#1}}
+
+%D The extension hook permits something like:
+%D
+%D \starttyping
+%D \bgroup
+%D
+%D \catcode`\*=\@@superscript
+%D
+%D \gdef\redorepeatwithcommand[#1]%
+%D {\redodorepeatwithcommand#1*\empty*\relax}
+%D
+%D \long\gdef\redodorepeatwithcommand#1*#2#3*#4\relax#5%
+%D {\dododorepeatwithcommand{#1}{#2}{#3}#5}
+%D
+%D \egroup
+%D \stoptyping
+%D
+%D although one may wonder if changing the catcode of \type {*} is wise.
+
+%D \macros
+%D {normalbgroup,normalgroup}
+%D
+%D No comment.
+
+\let\normalbgroup\bgroup
+\let\normalegroup\egroup
+
+%D \macros
+%D {doifstringinstringelse}
+%D
+%D The next macro is meant for situations where both strings
+%D are macros. This save some unneeded expansion.
+%D
+%D \starttyping
+%D \long\def\doifstringinstringelse#1#2%
+%D {\p!doifinstringelse#1#2%
+%D \@EA\firstoftwoarguments
+%D \else
+%D \@EA\secondoftwoarguments
+%D \fi}
+%D \stoptyping
+%D
+%D A bit faster is:
+
+\def\pp!doifstringinstringelse#1%
+ {\if#1@%
+ \@EA\secondoftwoarguments
+ \else
+ \@EA\firstoftwoarguments
+ \fi}
+
+\long\def\doifstringinstringelse#1#2%
+ {\long\@EA\def\@EA\p!doifstringinstringelse\@EA##\@EA1#1##2##3\war
+ {\pp!doifstringinstringelse##2}%
+ \@EA\@EA\@EA\p!doifstringinstringelse\@EA#2#1@@\war}
+
+%D \macros
+%D {appendtoks,prependtoks,appendtoksonce,prependtoksonce,
+%D doifintokselse,flushtoks,dotoks}
+%D
+%D We use \TOKENLISTS\ sparsely within \CONTEXT, because the
+%D comma separated lists are more suitable for the user
+%D interface. Nevertheless we have:
+%D
+%D \starttyping
+%D (\doglobal) \appendtoks ... \to\tokenlist
+%D (\doglobal) \prependtoks ... \to\tokenlist
+%D (\doglobal) \flushtoks\tokenlist
+%D \dotoks\tokenlist
+%D \stoptyping
+%D
+%D Er worden eerst enkele klad||registers gedefinieerd. These
+%D macros are clones of the ones implemented in page~378 of
+%D Knuth's \TeX book.
+
+\newtoks\@@scratchtoks
+
+\def\appendtoks {\doappendtoks \relax}
+\def\prependtoks {\doprependtoks \relax}
+\def\appendtoksonce {\doappendtoksonce \relax}
+\def\prependtoksonce{\doprependtoksonce\relax}
+
+\def\dodoappendtoks
+ {\dodoglobal\@@toks\@EAEAEA{\@EA\the\@EA\@@toks\the\@@scratchtoks}}
+
+\def\dodoprependtoks
+ {\dodoglobal\@@toks\@EAEAEA{\@EA\the\@EA\@@scratchtoks\the\@@toks}}
+
+\long\def\doappendtoks#1\to#2%
+ {\def\@@toks{#2}%
+ \@@scratchtoks\@EA{\gobbleoneargument#1}\dodoappendtoks}
+
+\long\def\doprependtoks#1\to#2%
+ {\def\@@toks{#2}%
+ \@@scratchtoks\@EA{\gobbleoneargument#1}\dodoprependtoks}
+
+\long\def\doappendtoksonce#1\to#2%
+ {\def\@@toks{#2}%
+ \@@scratchtoks\@EA{\gobbleoneargument#1}%
+ \doifintokselse\@@scratchtoks\@@toks\donothing\dodoappendtoks}
+
+\long\def\doprependtoksonce#1\to#2%
+ {\def\@@toks{#2}%
+ \@@scratchtoks\@EA{\gobbleoneargument#1}%
+ \doifintokselse\@@scratchtoks\@@toks\donothing\dodoprependtoks}
+
+%D The test macro:
+
+\def\doifintokselse#1#2% #1 en #2 zijn toks
+ {\edef\asciia{\detokenize\expandafter{\the#1}}%
+ \edef\asciib{\detokenize\expandafter{\the#2}}%
+ \doifstringinstringelse\asciia\asciib}
+
+%D A nice one too:
+
+% {\scratchtoks{abc} \removetoks b\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{abc} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{xaa} \removetoks x\from\scratchtoks [\the\scratchtoks]}
+% {\scratchtoks{a\relax b} \removetoks \relax\from\scratchtoks [\showthe\scratchtoks]}
+
+\def\removetoks#1\from#2%
+ {\def\doremovetoks##1#1##2\empty\empty\empty##3\\%
+ {\def\!!stringa{##3}%
+ \ifx\!!stringa\empty#2{##1}\else#2{##1##2}\fi}%
+ \expandafter\doremovetoks\the#2\empty\empty\empty#1\empty\empty\empty\\}
+
+%D Also:
+
+\def\appendetoks #1\to{\normalexpanded{\noexpand\appendtoks #1}\to}
+\def\prependetoks#1\to{\normalexpanded{\noexpand\prependtoks#1}\to}
+
+%D Hm.
+
+\def\flushtoks#1% nb: can reassing to #1 again, hence the indirectness
+ {\@@scratchtoks#1\relax
+ \dodoglobal#1\emptytoks
+ \the\@@scratchtoks\relax}
+
+\let\dotoks\the
+
+%D \macros
+%D {makecounter,pluscounter,minuscounter,
+%D resetcounter,setcounter,countervalue}
+%D
+%D Declaring, setting and resetting \COUNTERS\ can be done
+%D with the next set of commands.
+%D
+%D \starttyping
+%D \makecounter {name}
+%D \pluscounter {name}
+%D \minuscounter {name}
+%D \resetcounter {name}
+%D \setcounter {name} {value}
+%D \countervalue {name}
+%D \stoptyping
+
+\def\makecounter#1%
+ {\global\@EA\let\csname#1\endcsname\zerocountervalue} % see earlier
+
+\def\countervalue#1%
+ {\ifcsname#1\endcsname\csname#1\endcsname\fi}
+
+\def\pluscounter#1%
+ {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname#1\endcsname+\plusone\relax}}
+
+\def\minuscounter#1%
+ {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname#1\endcsname-\plusone\relax}}
+
+\def\resetcounter#1%
+ {\global\@EA\let\csname#1\endcsname\zerocountervalue}
+
+\def\setcounter#1#2%
+ {\@EA\xdef\csname#1\endcsname{\the\numexpr#2\relax}}
+
+\def\savecounter#1%
+ {\@EA\xdef\csname ! #1 !\endcsname{\the\numexpr\csname#1\endcsname\relax}}
+
+\def\restorecounter#1%
+ {\@EA\xdef\csname#1\endcsname{\the\numexpr\csname ! #1 !\endcsname\relax}}
+
+%D \macros
+%D {beforesplitstring,aftersplitstring}
+%D
+%D These both commands split a string at a given point in two
+%D parts, so \type{x.y} becomes \type{x} or \type{y}.
+%D
+%D \starttyping
+%D \beforesplitstring test.tex\at.\to\filename
+%D \aftersplitstring test.tex\at.\to\extension
+%D \stoptyping
+%D
+%D The first routine looks (and is indeed) a bit simpler than
+%D the second one. The alternative looking more or less like
+%D the first one did not always give the results we needed.
+%D Both implementations show some insight in the manipulation
+%D of arguments.
+
+\def\beforesplitstring#1\at#2\to#3%
+ {\def\dosplitstring##1#2##2#2##3\\%
+ {\def#3{##1}}%
+ \@EA\dosplitstring#1#2#2\\}
+
+\def\aftersplitstring#1\at#2\to#3%
+ {\def\dosplitstring##1#2##2@@@##3\\%
+ {\def#3{##2}}%
+ \@EA\dosplitstring#1@@@#2@@@\\}
+
+%D \macros
+%D {splitstring,greedysplitstring}
+%D
+%D A bonus macro.
+
+\def\splitstring#1\at#2\to#3\and#4%
+ {\def\dosplitstring##1#2##2\empty\empty\empty##3\\%
+ {\def#3{##1}%
+ \def\dosplitstring{##3}%
+ \ifx\dosplitstring\empty
+ \let#4\empty
+ \else
+ \def#4{##2}%
+ \fi}%
+ \@EA\dosplitstring#1\empty\empty\empty#2\empty\empty\empty\\}
+
+\def\greedysplitstring#1\at#2\to#3\and#4%
+ {\edef\asciib{#1}%
+ \let\asciic\asciib
+ \let#3\empty
+ \let#4\empty
+ \doloop
+ {\expandafter\splitstring\asciib\at#2\to\asciia\and\asciib
+ \ifx\asciib\empty
+ \exitloop
+ \else
+ % not \edef#3{\ifx#3\empty\else#3#2\fi\asciia} else
+ % /root/path fails because then #3==empty
+ \edef#3{\ifcase\recurselevel\or\else#3#2\fi\asciia}%
+ \let#4\asciib
+ \fi}%
+ \ifx#3\empty\let#3\asciic\fi}
+
+%D \macros
+%D {beforetestandsplitstring,
+%D aftertestandsplitstring,
+%D testandsplitstring}
+
+\def\beforetestandsplitstring#1\at#2\to#3%
+ {\def\dosplitstring##1#2##2#2##3##4\\%
+ {\ifx##3\empty\let#3\empty\else\def#3{##1}\fi}%
+ \@EA\dosplitstring#1#2#2\empty\\}
+
+\def\aftertestandsplitstring#1\at#2\to#3%
+ {\def\dosplitstring ##1#2##2@@@##3##4\\%
+ {\ifx##3\empty\let#3\empty\else\def#3{##2}\fi}%
+ \@EA\dosplitstring #1@@@#2@@@\empty\\}
+
+\def\testandsplitstring#1\at#2\to#3\and#4%
+ {\def\dosplitstring##1#2##2#2##3##4\\%
+ {\ifx##3\empty\let#3\empty\let#4\empty\else\def#3{##1}\def#4{##2}\fi}%
+ \@EA\dosplitstring#1#2#2\empty\\}
+
+%D \macros
+%D {removesubstring}
+%D
+%D A first application of the two routines defined above is:
+%D
+%D \starttyping
+%D \removesubstring-\from first-last\to\nothyphenated
+%D \stoptyping
+%D
+%D Which in terms of \TEX\ looks like:
+
+\def\removesubstring#1\from#2\to#3%
+ {\splitstring#2\to\!!stringa\and\!!stringb
+ \dodoglobal#3{\!!stringa\!!stringb}}
+
+%D \macros
+%D {appendtocommalist,prependtocommalist,
+%D addtocommalist,removefromcommalist}
+%D
+%D When working with comma separated lists, one sooner or
+%D later want the tools to append or remove items from such a
+%D list. When we add an item, we first check if it's already
+%D there. This means that every item in the list is unique.
+%D
+%D \starttyping
+%D \addtocommalist {alfa} \name
+%D \addtocommalist {beta} \name
+%D \addtocommalist {gamma} \name
+%D \removefromcommalist {beta} \name
+%D \stoptyping
+%D
+%D These commands can be prefixed with \type{\doglobal}. The
+%D implementation of the second command is more complecated,
+%D because we have to take leading spaces into account. Keep in
+%D mind that users may provide lists with spaces after the
+%D commas. When one item is left, we also have to get rid of
+%D trailing spaces.
+%D
+%D \starttyping
+%D \def\words{alfa, beta, gamma, delta}
+%D \def\words{alfa,beta,gamma,delta}
+%D \stoptyping
+%D
+%D Removing an item takes more time than adding one.
+%D
+%D A fast appending alternative, without any testing, is
+%D also provided:
+%D
+%D \starttyping
+%D \appendtocommalist {something} \name
+%D \prependtocommalist {something} \name
+%D \stoptyping
+%D
+%D This can be implemented as follows:
+%D
+%D \starttyping
+%D \def\appendtocommalist#1#2%
+%D {\ifx#2\empty
+%D \dodoglobal\edef#2{#1}%
+%D \else % no test on empty
+%D \dodoglobal\edef#2{#2,#1}%
+%D \fi}
+%D
+%D \def\prependtocommalist#1#2%
+%D {\ifx#2\empty
+%D \dodoglobal\edef#2{#1}%
+%D \else % no test on empty
+%D \dodoglobal\edef#2{#1,#2}%
+%D \fi}
+%D \stoptyping
+%D
+%D The faster alternatives are:
+
+\def\appendtocommalist#1#2%
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}
+
+\def\prependtocommalist#1#2%
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}
+
+\def\addtocommalist#1#2% {item} \cs
+ {\rawdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+\def\pretocommalist#1#2% {item} \cs
+ {\rawdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
+
+\def\robustdoifinsetelse#1#2%
+ {\edef\!!stringa{\detokenize\expandafter{\normalexpanded{#1}}}%
+ \edef\!!stringb{\detokenize\expandafter{\normalexpanded{#2}}}%
+ \rawdoifinsetelse\!!stringa\!!stringb}
+
+\def\robustaddtocommalist#1#2% {item} \cs
+ {\robustdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\edef#2{\ifx#2\empty\else#2,\fi#1}}}
+
+\def\robustpretocommalist#1#2% {item} \cs
+ {\robustdoifinsetelse{#1}#2\resetglobal
+ {\dodoglobal\edef#2{#1\ifx#2\empty\else,#2\fi}}}
+
+\def\xsplitstring#1#2% \cs {str}
+ {\def\dosplitstring##1,#2,##2,#2,##3\\%
+ {\edef\!!stringa{\bcleanedupcommalist##1\empty\empty\relax}%
+ \edef\!!stringb{\acleanedupcommalist##2,,\relax}}%
+ \@EA\dosplitstring\@EA,#1,,#2,,#2,\\}
+
+\def\bcleanedupcommalist#1#2#3\relax{\if#1,\else#1\fi\if#2,\else#2\fi#3}
+\def\bcleanedupcommalist#1#2\relax{\if#1,\else#1\fi#2}
+\def\acleanedupcommalist#1,,#2\relax{#1}
+
+\def\removefromcommalist#1#2% to be sped up
+ {\rawdoifinsetelse{#1}#2%
+ {\normalexpanded{\noexpand\xsplitstring\noexpand#2{#1}}%
+ \dodoglobal\edef#2%
+ {\ifx\!!stringa\empty
+ \!!stringb
+ \else
+ \!!stringa\ifx\!!stringb\empty\else,\!!stringb\fi
+ \fi}}
+ \resetglobal}
+
+%D \macros
+%D {substituteincommalist}
+%D
+%D Slow but seldom used, so for the moment we stick to this
+%D implementation.
+%D
+%D \starttyping
+%D \substituteincommalist{old}{new}{list}
+%D \stoptyping
+
+\def\substituteincommalist#1#2#3% old, new, list (slooow)
+ {\edef\!!stringb{#1}%
+ \edef\!!stringd{#2}%
+ \let\!!stringa#3%
+ \let#3\empty
+ \def\dosubstituteincommalist##1%
+ {\edef\!!stringc{##1}%
+ \ifx\!!stringb\!!stringc
+ \ifx\!!stringd\empty\else
+ \edef#3{#3\ifx#3\empty\else,\fi\!!stringd}%
+ \fi
+ \def\docommand####1{\edef#3{#3,####1}}%
+ \else
+ \edef#3{#3\ifx#3\empty\else,\fi##1}%
+ \fi}%
+ \@EA\rawprocesscommacommand\@EA[\!!stringa]\dosubstituteincommalist}
+
+%D A not so useful macro:
+
+\def\dodofrontstrip[#1#2]#3%
+ {\ifx#1\space
+ \def#3{#2}%
+ \else
+ \def#3{#1#2}%
+ \fi}
+
+\def\dofrontstrip#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty \else
+ \@EA\dodofrontstrip\@EA[#1]#1%
+ \fi}
+
+%D \macros
+%D {replaceincommalist}
+%D
+%D The next macro can be used to replace an indexed element
+%D in a commalist:
+%D
+%D \starttyping
+%D \replaceincommalist\MyList{2}
+%D \stoptyping
+%D
+%D Element~2 will be replaced by the current meaning of the macro
+%D \type {\newcommalistelement}. The old meaning is saved in
+%D \type {\commalistelement}. The replacement honors grouped items,
+%D like in:
+%D
+%D \starttyping
+%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,b,c,d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,{b,c},d,e,f} \replaceincommalist\MyList{3}
+%D \def\MyList{a,b,c,{d,e,f}} \replaceincommalist\MyList{3}
+%D \stoptyping
+
+\let\newcommalistelement\empty
+
+\def\replaceincommalist#1#2% #1 = commalistelement #2 = position starts at 1
+ {\def\doreplaceincommalist##1%
+ {\ifnum\commalistcounter=#2\relax
+ \ifx\newcommalistelement\empty\else
+ \ifx\newcommalist\empty
+ \let\newcommalist\newcommalistelement
+ \else
+ \@EA\@EA\@EA\def\@EA\@EA\@EA\newcommalist\@EA\@EA\@EA
+ {\@EA\newcommalist\@EA,\newcommalistelement}%
+ \fi
+ \fi
+ \def\commalistelement{##1}%
+ \else
+ \ifx\newcommalist\empty
+ \ifx\nexttoken\bgroup % is known -)
+ \def\newcommalist{{##1}}%
+ \else
+ \def\newcommalist{##1}%
+ \fi
+ \else
+ \ifx\nexttoken\bgroup % is known -)
+ \@EA\def\@EA\newcommalist\@EA{\newcommalist,{##1}}%
+ \else
+ \@EA\def\@EA\newcommalist\@EA{\newcommalist,##1}%
+ \fi
+ \fi
+ \fi
+ \advance\commalistcounter\plusone}%
+ \let\commalistelement\empty
+ \let\newcommalist\empty
+ \commalistcounter\plusone
+ \@EA\processcommalist\@EA[#1]\doreplaceincommalist
+ \dodoglobal\let#1\newcommalist}
+
+%D \macros
+%D {globalprocesscommalist}
+%D
+%D The commalist processing commands are characterized by the
+%D fact that the way they handle expansion as well as the fact
+%D that they can be nested. This makes them kind of useless for
+%D handling comma lists in alignments. In these situations the
+%D next macro can be of use.
+
+\def\globalprocesscommaitem#1,%
+ {\if]#1\else
+ \globalcommacommand{#1}%
+ \expandafter\globalprocesscommaitem
+ \fi}
+
+\def\globalprocesscommalist[#1]#2%
+ {\global\let\globalcommacommand#2%
+ \expandafter\globalprocesscommaitem#1,],}
+
+%D \macros
+%D {withoutpt,PtToCm,
+%D numberofpoints,dimensiontocount}
+%D
+%D We can convert point into centimeters with:
+%D
+%D \starttyping
+%D \PtToCm{dimension}
+%D \stoptyping
+
+{\catcode`\.=\@@other
+ \catcode`\p=\@@other
+ \catcode`\t=\@@other
+ \gdef\WITHOUTPT#1pt{#1}}
+
+\def\withoutpt#1%
+ {\expandafter\WITHOUTPT#1}
+
+%D The capitals are needed because \type{p} and \type{t} have
+%D \CATCODE~12, while macronames only permit tokens with the
+%D \CATCODE~11. As a result we cannot use the \type{.group}
+%D primitives. Those who want to know more about this kind of
+%D manipulations, we advice to study the \TEX book in detail.
+%D Because this macro does not do any assignment, we can use it
+%D in the following way too.
+
+\def\PtToCm#1%
+ {\withoutpt\the\dimexpr0.0351459804\dimexpr#1\relax\relax cm}
+
+%D We also support:
+%D
+%D \starttyping
+%D \numberofpoints {dimension}
+%D \dimensiontocount {dimension} {\count}
+%D \stoptyping
+%D
+%D Both macros return a rounded number.
+
+% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt}
+% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt}
+
+\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax}
+\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax}
+
+%D \macros
+%D {swapdimens,swapmacros}
+%D
+%D Simple but effective are the next two macros. There name
+%D exactly states their purpose. The \type{\scratchdimen} and
+%D \type{\!!stringa} can only be swapped when being the first
+%D argument.
+
+\def\swapdimens#1#2%
+ {\scratchdimen #1\redoglobal #1#2\dodoglobal #2\scratchdimen}
+
+\def\swapmacros#1#2%
+ {\let\!!stringa#1\redoglobal\let#1#2\dodoglobal\let#2\!!stringa}
+
+%D \macros
+%D {pushmacro,popmacro}
+%D
+%D Premature and a bit of beta, we offer:
+%D
+%D \starttyping
+%D \pushmacro\macro
+%D \popmacro\macro
+%D \stoptyping
+%D
+%D Beware: global!
+
+\def\@sl@{@sl@}
+\def\@sg@{@sg@}
+
+\let\@@pushedmacro\empty
+
+\def\globalpushmacro#1%
+ {\xdef\@@pushedmacro{\string#1}%
+ \ifcsname\@sg@\@@pushedmacro\endcsname \else
+ \@EA\newcount\csname\@sg@\@@pushedmacro\endcsname
+ \fi
+ \global\advance\csname\@sg@\@@pushedmacro\endcsname \plusone
+ \global\@EA\let\csname\the\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1}
+
+\def\globalpopmacro#1%
+ {\xdef\@@pushedmacro{\string#1}%
+ \global\@EA\let\@EA#1\csname\the\csname\@sg@\@@pushedmacro\endcsname\@@pushedmacro\endcsname
+ \global\advance\csname\@sg@\@@pushedmacro\endcsname \minusone}
+
+\def\localpushmacro#1% this one can be used to push a value over an \egroup
+ {\xdef\@@pushedmacro{\string#1}%
+ \ifcsname\@sl@\@@pushedmacro\endcsname \else
+ \@EA\newcount\csname\@sl@\@@pushedmacro\endcsname
+ \fi
+ \global\advance\csname\@sl@\@@pushedmacro\endcsname \plusone
+ \global\@EA\let\csname\the\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname#1}
+
+\def\localpopmacro#1%
+ {\xdef\@@pushedmacro{\string#1}%
+ \@EA\let\@EA#1\csname\the\csname\@sl@\@@pushedmacro\endcsname\@@pushedmacro\endcsname
+ \global\advance\csname\@sl@\@@pushedmacro\endcsname \minusone }
+
+\let\pushmacro\localpushmacro
+\let\popmacro \localpopmacro
+
+%D \macros
+%D {setlocalhsize}
+%D
+%D Sometimes we need to work with the \type{\hsize} that is
+%D corrected for indentation and left and right skips. The
+%D corrected value is available in \type{\localhsize}, which
+%D needs to be calculated with \type{\setlocalhsize} first.
+%D
+%D \starttyping
+%D \setlocalhsize \hbox to \localhsize{...}
+%D \setlocalhsize[-1em] \hbox to \localhsize{...}
+%D \setlocalhsize[.5ex] \hbox to \localhsize{...}
+%D \stoptyping
+%D
+%D These examples show us that an optional can be used. The
+%D value provided is added to \type{\localhsize}.
+
+\newdimen\localhsize
+
+\def\complexsetlocalhsize[#1]% don't change !
+ {\localhsize\hsize
+ \ifnum\hangafter<\zerocount
+ \advance\localhsize\ifdim\hangindent>\zeropoint-\fi\hangindent
+ \fi
+ \advance\localhsize -\leftskip
+ \advance\localhsize -\rightskip
+ \advance\localhsize #1\relax}
+
+\def\simplesetlocalhsize
+ {\complexsetlocalhsize[\zeropoint]}
+
+\definecomplexorsimple\setlocalhsize
+
+%D \macros
+%D {doifvalue,doifnotvalue,doifelsevalue,
+%D doifnothing,doifsomething,doifelsenothing,
+%D doifvaluenothing,doifvaluesomething,doifelsevaluenothing}
+%D
+%D These long named \type{\if} commands can be used to access
+%D macros (or variables) that are normally accessed by using
+%D \type{\getvalue}. Using these alternatives safes us three
+%D tokens per call. Anyone familiar with the not||values
+%D ones, can derive their meaning from the definitions.
+
+ \def\doifvalue#1{\doif {\csname#1\endcsname}}
+ \def\doifnotvalue#1{\doifnot {\csname#1\endcsname}}
+ \def\doifelsevalue#1{\doifelse{\csname#1\endcsname}}
+
+ \def\doifnothing#1{\doif {#1}{}}
+ \def\doifsomething#1{\doifnot {#1}{}}
+ \def\doifelsenothing#1{\doifelse{#1}{}}
+
+ \def\doifvaluenothing#1{\doif {\csname#1\endcsname}{}}
+ \def\doifvaluesomething#1{\doifnot {\csname#1\endcsname}{}}
+\def\doifelsevaluenothing#1{\doifelse{\csname#1\endcsname}{}}
+
+%D Faster but spoiling inheritance (copying parameters):
+%D
+%D \starttyping
+%D \def\doifelsevaluesomething#1#2#3%
+%D {\expandafter\ifx\csname#1\endcsname\empty#3\else#2\fi}
+%D
+%D \def\doifvaluesomething#1#2%
+%D {\expandafter\ifx\csname#1\endcsname\empty\else#2\fi}
+%D
+%D \def\doifvaluenothing#1#2%
+%D {\expandafter\ifx\csname#1\endcsname\empty#2\fi}
+%D \stoptyping
+%D
+%D Slightly more efficient:
+
+ \def\doifnothing{\doif \empty}
+ \def\doifsomething{\doifnot \empty}
+\def\doifelsenothing{\doifelse\empty}
+
+%D The somewhat faster alternatives are:
+
+\long\def\doifvalue#1#2%
+ {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\doifnotvalue#1#2%
+ {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\long\def\doifelsevalue#1#2%
+ {\edef\!!stringa{\csname#1\endcsname}\edef\!!stringb{#2}%
+ \ifx\!!stringa\!!stringb
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\long\def\doifnothing#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\doifsomething#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\long\def\doifelsenothing#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\long\def\doifsomethingelse#1%
+ {\edef\!!stringa{#1}%
+ \ifx\!!stringa\empty
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+\long\def\doifvaluenothing#1%
+ {\edef\!!stringa{\csname#1\endcsname}%
+ \ifx\!!stringa\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\long\def\doifvaluesomething#1%
+ {\edef\!!stringa{\csname#1\endcsname}%
+ \ifx\!!stringa\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\long\def\doifelsevaluenothing#1%
+ {\edef\!!stringa{\csname#1\endcsname}%
+ \ifx\!!stringa\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+%D \macros
+%D {doifemptyelsevalue, doifemptyvalue, doifnotemptyvalue}
+%D
+%D Also handy:
+
+\def\doifemptyelsevalue#1%
+ {\@EA\ifx\csname#1\endcsname\empty
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\doifemptyvalue#1%
+ {\@EA\ifx\csname#1\endcsname\empty
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\doifnotemptyvalue#1%
+ {\@EA\ifx\csname#1\endcsname\empty
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D \macros
+%D {doifallcommonelse}
+%D
+%D A complete match of two sets can be tested with
+%D \type {\doifallcommonelse}, where the first two
+%D arguments are sets.
+
+\def\@@doifallcommonelse#1#2#3#4% slow
+ {\def\p!docommoncheck##1%
+ {\doifnotinset{##1}{#4}\donefalse
+ \ifdone\else\expandafter\quitcommalist\fi}%
+ \donetrue
+ \processcommalist[#3]\p!docommoncheck
+ \ifdone\expandafter#1\else\expandafter#2\fi}
+
+\def\doifallcommonelse
+ {\@@doifallcommonelse\firstoftwoarguments\secondoftwoarguments}
+
+\def\doifallcommon
+ {\@@doifallcommonelse\firstofonearguments\gobbleoneargument}
+
+\def\doifnotallcommon
+ {\@@doifallcommonelse\gobbleoneargument\firstofonearguments}
+
+%D \macros
+%D {DOIF,DOIFELSE,DOIFNOT}
+%D
+%D \TEX\ is case sensitive. When comparing arguments, this
+%D feature sometimes is less desirable, for instance when we
+%D compare filenames. The next three alternatives upcase their
+%D arguments before comparing them.
+%D
+%D \starttyping
+%D \DOIF {string1} {string2} {...}
+%D \DOIFNOT {string1} {string2} {...}
+%D \DOIFELSE {string1} {string2} {then ...}{else ...}
+%D \stoptyping
+%D
+%D We have to use a two||step implementation, because the
+%D expansion has to take place outside \type{\uppercase}.
+
+\def\p!DOIF#1#2%
+ {\uppercase{\ifinstringelse{$#1$}{$#2$}}%
+ \expandafter\firstofoneargument
+ \else
+ \expandafter\gobbleoneargument
+ \fi}
+
+\def\p!DOIFNOT#1#2%
+ {\uppercase{\ifinstringelse{$#1$}{$#2$}}%
+ \expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+\def\p!DOIFELSE#1#2%
+ {\uppercase{\ifinstringelse{$#1$}{$#2$}}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\p!DOIFINSTRINGELSE#1#2%
+ {\uppercase{\ifinstringelse{#1}{#2}}%
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\def\DOIF {\ExpandBothAfter\p!DOIF}
+\def\DOIFNOT {\ExpandBothAfter\p!DOIFNOT}
+\def\DOIFELSE {\ExpandBothAfter\p!DOIFELSE}
+\def\DOIFINSTRINGELSE {\ExpandBothAfter\p!DOIFINSTRINGELSE}
+
+%D \macros
+%D {dosingleargumentwithset,
+%D dodoubleargumentwithset,dodoubleemptywithset,
+%D dotripleargumentwithset,dotripleemptywithset}
+%D
+%D These maybe too mysterious macros enable us to handle more
+%D than one setup at once.
+%D
+%D \starttyping
+%D \dosingleargumentwithset \command[#1]
+%D \dodoubleargumentwithset \command[#1][#2]
+%D \dotripleargumentwithset \command[#1][#2][#3]
+%D \dodoubleemptywithset \command[#1][#2]
+%D \dotripleemptywithset \command[#1][#2][#3]
+%D \stoptyping
+%D
+%D The first macro calls \type{\command[##1]} for each string
+%D in the set~\type{#1}. The second one calls for
+%D \type{\commando[##1][#2]} and the third, well one may guess.
+%D These commands support constructions like:
+%D
+%D \starttyping
+%D \def\dodefinesomething[#1][#2]%
+%D {\getparameters[\??xx#1][#2]}
+%D
+%D \def\definesomething%
+%D {\dodoubleargumentwithset\dodefinesomething}
+%D \stoptyping
+%D
+%D Which accepts calls like:
+%D
+%D \starttyping
+%D \definesomething[alfa,beta,...][variable=...,...]
+%D \stoptyping
+%D
+%D Now a whole bunch of variables like \type{\@@xxalfavariable}
+%D and \type{\@@xxbetavariable} is defined.
+
+\def\dodoublewithset[#1][#2]%
+ {\doifsomething{#1}
+ {\def\@@dodowithsetcommand##1{\@@dowithsetcommand[##1][#2]}%
+ \processcommalist[#1]\@@dodowithsetcommand}}
+
+\def\dotriplewithset[#1][#2][#3]%
+ {\doifsomething{#1}
+ {\def\@@dodowithsetcommand##1{\@@dowithsetcommand[##1][#2][#3]}%
+ \processcommalist[#1]\@@dodowithsetcommand}}
+
+\def\dodoubleemptywithset #1{\let\@@dowithsetcommand#1\dodoubleempty \dodoublewithset} % \command
+\def\dodoubleargumentwithset#1{\let\@@dowithsetcommand#1\dodoubleargument\dodoublewithset} % \command
+
+\def\dotripleemptywithset #1{\let\@@dowithsetcommand#1\dotripleempty \dotriplewithset} % \command
+\def\dotripleargumentwithset#1{\let\@@dowithsetcommand#1\dotripleargument\dotriplewithset} % \command
+
+%D \macros
+%D {stripcharacters,stripspaces}
+%D
+%D The next command was needed first when we implemented
+%D the \CONTEXT\ interactivity macros. When we use labeled
+%D destinations, we often cannot use all the characters we
+%D want. We therefore strip some of the troublemakers, like
+%D spaces, from the labels before we write them to the
+%D \DVI||file, which passes them to for instance a PostScript
+%D file.
+%D
+%D \starttyping
+%D \stripspaces\from\one\to\two
+%D \stoptyping
+%D
+%D Both the old string \type{\one} and the new one \type{\two}
+%D are expanded. This command is a special case of:
+%D
+%D \starttyping
+%D \stripcharacter\char\from\one\to\two
+%D \stoptyping
+%D
+%D As we can see below, spaces following a control sequence are
+%D to enclosed in \type{{}}.
+
+\def\stripcharacter#1\from#2\to#3%
+ {\def\dostripcharacter##1#1##2\end
+ {\edef\!!strippedstring{\!!strippedstring##1}%
+ \doifnotempty{##2}{\dostripcharacter##2\end}}%
+ \let\!!strippedstring\empty
+ \edef\!!stringa{#2}%
+ \@EA\dostripcharacter\!!stringa#1\end
+ \dodoglobal\let#3\!!strippedstring}
+
+\def\stripspaces\from#1\to#2% will become \unspacestring#1\from#2
+ {\stripcharacter{ }\from#1\to#2}
+
+%D \macros
+%D {unspacestring}
+%D
+%D The next macro does the same but is more compatible with other macros,
+%D like \type {\convert...}.
+
+\def\unspacestring#1\to#2%
+ {\stripcharacter{ }\from#1\to#2}
+
+%D \macros
+%D {executeifdefined}
+%D
+%D \CONTEXT\ uses one auxiliary file for all data concerning
+%D tables of contents, references, two||pass optimizations,
+%D sorted lists etc. This file is loaded as many times as
+%D needed. During such a pass we skip the commands thate are of
+%D no use at that moment. Because we don't want to come into
+%D trouble with undefined auxiliary commands, we call the
+%D macros in a way similar to \type{\getvalue}. The next macro
+%D take care of such executions and when not defined, gobbles
+%D the unwanted arguments.
+%D
+%D \starttyping
+%D \executeifdefined{name}\gobbleoneargument
+%D \stoptyping
+%D
+%D We can of course gobble more arguments using the
+%D appropriate gobbling command.
+
+\newif\ifexecuted % general purpose
+
+\def\executeifdefined#1% #2 / never change this one again
+ {\ifcsname#1\endcsname
+ \csname#1\expandafter\expandafter\expandafter\endcsname\expandafter\gobbleoneargument
+ \else
+ \expandafter\firstofoneargument
+ \fi}
+
+%D This one also has the advantage that it is fully
+%D expandable and that it can be used after an assignment.
+
+%D \macros
+%D {doifsomespaceelse}
+%D
+%D The next command checks a string on the presence of a space
+%D and executed a command accordingly.
+%D
+%D \starttyping
+%D \doifsomespaceelse {tekst} {then ...} {else ...}
+%D \stoptyping
+%D
+%D We use this command in \CONTEXT\ for determing if an
+%D argument must be broken into words when made interactive.
+%D Watch the use of \type{\noexpand}.
+
+%D Is this one still needed?
+
+\def\p!doifsomespaceelse#1 #2#3\war{\if\noexpand#2@}
+
+\long\def\doifsomespaceelse#1% % #2#3%
+ {\p!doifsomespaceelse#1 @ @\war % #3\else#2\fi}
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+%D \macros
+%D {adaptdimension,balancedimensions}
+%D
+%D Again we introduce some macros that are closely related to
+%D an interface aspect of \CONTEXT. The first command can be
+%D used to adapt a \DIMENSION.
+%D
+%D \starttyping
+%D \adaptdimension {dimension} {value}
+%D \stoptyping
+%D
+%D When the value is preceed by a \type{+} or minus, the
+%D dimension is advanced accordingly, otherwise it gets the
+%D value.
+
+\def\doadaptdimension#1#2\\#3\\%
+ {\if#1+%
+ \dodoglobal\advance
+ \else\if#1-%
+ \dodoglobal\advance
+ \else
+ \dodoglobal
+ \fi\fi
+ #3 #1#2\relax}
+
+\def\adaptdimension#1#2%
+ {\expandafter\doadaptdimension#2\\#1\\}
+
+%D A second command takes two \DIMENSIONS. Both are adapted,
+%D depending on the sign of the given value.
+%D maat. This time we take the value as it is, and don't look
+%D explicitly at the preceding sign.
+%D
+%D \starttyping
+%D \balancedimensions {dimension 1} {dimension 2} {value}
+%D \stoptyping
+%D
+%D When a positive value is given, the first dimension is
+%D incremented, the second ond is decremented. A negative value
+%D has the opposite result.
+
+\def\balancedimensions#1#2#3%
+ {\scratchdimen#3\relax
+ \redoglobal\advance#1 \scratchdimen
+ \dodoglobal\advance#2 -\scratchdimen}
+
+%D Both commands can be preceded by \type{\doglobal}. Here we
+%D use \type{\redo} first, because \type{\dodo} resets the
+%D global character.
+
+%D \macros
+%D {processseparatedlist}
+%D
+%D Maybe a bit late, but here is a more general version of the
+%D \type{\processcommalist} command. This time we don't handle
+%D nesting but accept arbitrary seperators.
+%D
+%D \starttyping
+%D \processseparatedlist[list][separator]\command
+%D \stoptyping
+%D
+%D One can think of things like:
+%D
+%D \starttyping
+%D \processseparatedlist[alfa+beta+gamma][+]\message
+%D \stoptyping
+%D
+%D We want to handle all situations, like:
+%D
+%D \startbuffer
+%D \processseparatedlist[{aap noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[{aap} {noot}][ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[aap {noot}] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \processseparatedlist[aap noot] [ ]{\def\xxx} \convertcommand\xxx\to\ascii {\tttf\ascii}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D Therefore we smuggle a \type {\relax} in front of the
+%D argument, which we remove afterwards.
+
+\def\doprocessseparatedlist#1]#2[#3]#4%
+ {\def\dodoprocessseparatedlist##1##2#3%
+ {\def\!!stringa{##2}% suggested by VZ
+ \if]##1%
+ \let\dodoprocessseparatedlist\relax
+ \else\ifx\blankspace\!!stringa
+ #4{##1}%
+ \else\if]##2%
+ \let\dodoprocessseparatedlist\relax
+ \else
+ #4{##1##2}%
+ \fi\fi\fi
+ \dodoprocessseparatedlist}%
+ \@EA\dodoprocessseparatedlist\gobbleoneargument#1#3]#3}
+
+\def\processseparatedlist[%
+ {\doprocessseparatedlist\relax}
+
+%D \macros
+%D {processlist}
+%D
+%D An even more general list processing macro is the
+%D following one:
+%D
+%D \starttyping
+%D \processlist{beginsym}{endsym}{separator}\docommand list
+%D \stoptyping
+%D
+%D This one supports arbitrary open and close symbols as well
+%D as user defined separators.
+%D
+%D \starttyping
+%D \processlist(){=>}\docommand(a=>b=>c=>d)
+%D \stoptyping
+
+\long\def\processlist#1#2#3#4% no blank skipping !
+ {\def\doprocesslist##1#2%
+ {\def\dodoprocesslist####1####2#3%
+ {\ifx#2####1%
+ \let\dodoprocesslist\relax
+ \else\ifx#2####2%
+ \let\dodoprocesslist\relax
+ \else
+ #4{####1####2}%
+ \fi\fi
+ \dodoprocesslist}%
+ \expandafter\dodoprocesslist\gobbleoneargument##1#3#2#3}%
+ \def\dodoprocesslist#1%
+ {\doprocesslist\relax}%
+ \dodoprocesslist}
+
+%D \macros
+%D {processassignlist}
+%D
+%D Is possible to combine an assignment list with one
+%D containing keywords. Assignments are treated accordingly,
+%D keywords are treated by \type{\command}.
+%D
+%D \starttyping
+%D \processassignlist[...=...,...=...,...]\commando
+%D \stoptyping
+%D
+%D This command can be integrated in \type{\getparameters}, but
+%D we decided best not to do so.
+
+\def\processassignlist#1[#2]#3%
+ {\def\p!dodogetparameter[##1=##2=##3]%
+ {\doifnot{##3}\relax{#3{##1}}}%
+ \def\p!dogetparameter##1%
+ {\p!dodogetparameter[##1==\relax]}%
+ \processcommalist[#2]\p!dogetparameter}
+
+%D \macros
+%D {untextargument
+%D untexcommand}
+%D
+%D When manipulating data(bases) and for instance generating
+%D index entries, the next three macros can be of help:
+%D
+%D \starttyping
+%D \untextargument{...}\to\name
+%D \untexcommand {...}\to\name
+%D \stoptyping
+%D
+%D They remove braces and backslashes and give us something to
+%D sort.
+
+\def\untexsomething
+ {\begingroup
+ \catcode`\{=\@@ignore
+ \catcode`\}=\@@ignore
+ \escapechar\minusone
+ \dountexsomething}
+
+\long\def\dountexsomething#1#2\to#3%
+ {\doglobal#1#2\to\untexedargument
+ \endgroup
+ \let#3\untexedargument}
+
+\def\untexargument{\untexsomething\convertargument}
+\def\untexcommand {\untexsomething\convertcommand}
+
+%D \macros
+%D {ScaledPointsToBigPoints,ScaledPointsToWholeBigPoints}
+%D
+%D One characteristic of \POSTSCRIPT\ and \PDF\ is that both
+%D used big points (\TEX's bp). The next macros convert points
+%D and scaled points into big points.
+%D
+%D \starttyping
+%D \ScaledPointsToBigPoints {number} \target
+%D \ScaledPointsToWholeBigPoints {number} \target
+%D \stoptyping
+%D
+%D The magic factor $72/72.27$ can be found in most \TEX\
+%D related books.
+
+% \PointsToBigPoints{10.53940pt}\test \test
+% \PointsToBigPoints{10.53941pt}\test \test
+% \PointsToBigPoints{10.53942pt}\test \test
+
+% \PointsToWholeBigPoints{10.53940pt}\test \test
+% \PointsToWholeBigPoints{10.53941pt}\test \test
+% \PointsToWholeBigPoints{10.53942pt}\test \test
+
+\def\PointsToBigPoints#1#2%
+ {\edef#2{\withoutpt\the\dimexpr.996264\dimexpr#1\relax\relax}}
+
+\def\PointsToWholeBigPoints#1#2%
+ {\edef#2{\the\numexpr\dimexpr.996264\dimexpr#1\relax\relax/\maxcard\relax}}
+
+\def\ScaledPointsToBigPoints #1{\PointsToBigPoints {\number#1\scaledpoint}}
+\def\ScaledPointsToWholeBigPoints#1{\PointsToWholeBigPoints{\number#1\scaledpoint}}
+
+%D \macros
+%D {PointsToReal}
+%D
+%D Points can be stripped from their suffix by using
+%D \type{\withoutpt}. The next macro enveloppes this macro.
+%D
+%D \starttyping
+%D \PointsToReal {dimension} \target
+%D \stoptyping
+
+\def\PointsToReal#1#2%
+ {\scratchdimen#1%
+ \edef#2{\withoutpt\the\scratchdimen}}
+
+%D \macros
+%D {dontleavehmode}
+%D
+%D Sometimes when we enter a paragraph with some command, the
+%D first token gets the whole first line. We can prevent this
+%D by saying:
+%D
+%D \starttyping
+%D \dontleavehmode
+%D \stoptyping
+%D
+%D This command is used in for instance the language module
+%D \type{lang-ini}. The first version was:
+%D
+%D \starttyping
+%D \def\dontleavehmode{\ifhmode\else\ifmmode\else$ $\fi\fi}
+%D \stoptyping
+%D
+%D Next, Taco came with a better alternative (using mathsurround):
+%D
+%D \starttyping
+%D \def\dontleavehmode
+%D {\ifhmode\else \ifmmode\else
+%D {\mathsurround\zeropoint\everymath\emptytoks$ $}%
+%D \fi \fi}
+%D \stoptyping
+%D
+%D And finaly we got the following alternative, one that avoids
+%D interfering grouping at the cost of a box.
+
+\newbox\@@dlhbox
+
+\unexpanded \def\dontleavehmode
+ {\ifhmode\else \ifmmode\else
+ \setbox\@@dlhbox\hbox{\mathsurround\zeropoint\everymath\emptytoks$ $}\unhbox\@@dlhbox
+ \fi \fi}
+
+%D But, if you run a recent version of \TEX, we can use the new
+%D primitive:
+
+\ifdefined\normalquitvmode \let\dontleavehmode\normalquitvmode \fi
+
+%D \macros
+%D {uppercasestring,lowercasestring}
+%D
+%D The names tell what they do:
+%D
+%D \starttyping
+%D \uppercasestring somestring\to\somestring
+%D \lowercasestring somestring\to\somestring
+%D \stoptyping
+%D
+%D the first argument may be a \type{\macro}.
+
+\def\uppercasestring#1\to#2% first @EA redundant
+ {\uppercase\@EA{\@EA\dodoglobal\@EA\edef\@EA#2\@EA{\normalexpanded{#1}}}}
+
+\def\lowercasestring#1\to#2% first @EA redundant
+ {\lowercase\@EA{\@EA\dodoglobal\@EA\edef\@EA#2\@EA{\normalexpanded{#1}}}}
+
+%D \macros
+%D {handletokens}
+%D
+%D With the next macro we enter a critical area of macro
+%D expansion. What we want is a macro that looks like:
+%D
+%D \starttyping
+%D \handletokens some tokens\with \somemacro
+%D \stoptyping
+%D
+%D A bonus example:
+%D
+%D \starttyping
+%D \hbox{\handletokens tekst en meer tekst\with\ruledhbox}
+%D
+%D \def\weetikveel#1{\if#1\blankspace\space\else\ruledhbox{#1}\fi}
+%D
+%D \hbox{\handletokens tekst en meer tekst\with\weetikveel}
+%D \stoptyping
+
+%D \macros
+%D {counttoken,counttokens}
+%D
+%D For the few occasions that we want to know the number of
+%D specific tokens in a string, we can use:
+%D
+%D \starttyping
+%D \counttoken token\in string\to \somecount
+%D \counttokens string\to \somecount
+%D \stoptyping
+%D
+%D This macro, that for instance is used in \type{cont-tab},
+%D takes a real counter. The macro can be preceded by \type
+%D {\doglobal}.
+
+\def\counttoken#1\in#2\to#3%
+ {\scratchcounter\zerocount
+ \def\!!stringa{#1}%
+ \def\!!stringb{\end}%
+ \def\docounttoken##1% obeys {}
+ {\def\!!stringc{##1}%
+ \ifx\!!stringb\!!stringc \else
+ \ifx\!!stringa\!!stringc
+ \advance\scratchcounter\plusone
+ \fi
+ \expandafter\docounttoken
+ \fi}%
+ \docounttoken#2\end
+ \dodoglobal#3\scratchcounter}
+
+\def\counttokens#1\to#2%
+ {\scratchcounter\zerocount
+ \def\docounttoken##1{\advance\scratchcounter\plusone}%
+ \handletokens#1\with\docounttoken
+ \dodoglobal#2\scratchcounter}
+
+%D \macros
+%D {splitofftokens}
+%D
+%D Running this one not always gives the expected results.
+%D Consider for instance the macro for which I originally
+%D wrote this token handler.
+
+\long\def\splitofftokens#1\from#2\to#3% slow but hardly used
+ {\ifnum#1>\zerocount
+ \scratchcounter#1\relax
+ \def\dosplitofftokens##1%
+ {\ifnum\scratchcounter>\zerocount
+ \advance\scratchcounter \minusone
+ \edef#3{#3##1}%
+ \fi}%
+ % \let#3\empty % #3 can be #2, so:
+ \@EA\let\@EA#3\@EA\empty
+ \@EA\handletokens#2\with\dosplitofftokens
+ \else
+ \edef#3{#2}%
+ \fi}
+
+%D This macro can be called like:
+%D
+%D \startbuffer[example]
+%D \splitofftokens10\from01234567 890123456789\to\test [\test]
+%D \stopbuffer
+%D
+%D However, the characters that we expect to find in
+%D \type{\test} just don't show up there. The reason for this
+%D is not that logical but follows from \TEX's sometimes
+%D mysterious way of expanding. Look at this:
+%D
+%D \startbuffer[next]
+%D \def\next{a} \edef\test{\next} [\test]
+%D \let\next=b \edef\test{\test\next} [\test]
+%D \let\next=c \edef\test{\next} [\test]
+%D \let\next=d \edef\test{\test\next} [\test]
+%D \let\next=e \@EA\edef\@EA\test\@EA{\test\next} [\test]
+%D \stopbuffer
+%D
+%D \typebuffer[next]
+%D
+%D Careful reading shows that inside an \type{\edef} macro's
+%D that are \type{\let} are not expanded!
+%D
+%D \unprotect\getbuffer[next]\protect
+%D
+%D That's why we finally end up with a macro that looks
+%D ahead by using an assignment, this time by using \type
+%D {\futurelet}, and grabbing an argument as well. That
+%D way we can handle the sentinal, a blank space and grouped
+%D tokens.
+
+\def\dohandletokens % \nexthandledtoken is part of interface
+ {\futurelet\nexthandledtoken\dodohandletokens}
+
+\long\def\handletokens#1\with#2%
+ {\gdef\dododohandletokens{#2}% permits more complex #2's
+ \dohandletokens#1\end}
+
+\def\dodohandletokens
+ {\ifx\nexthandledtoken\blankspace
+ \expandafter\dodohandletokensone
+ \else\ifx\nexthandledtoken\end
+ \expandafter\expandafter\expandafter\gobbletwoarguments % also gobble the \end
+ \else
+ \expandafter\expandafter\expandafter\dodohandletokenstwo
+ \fi\fi *}
+
+\def\dodohandletokensone * %
+ {\dododohandletokens{ }\dohandletokens}
+
+\long\def\dodohandletokenstwo *#1%
+ {\dododohandletokens{#1}\dohandletokens}
+
+%D This macro is tested on:
+%D
+%D \def\xxx#1{[#1]}
+%D
+%D \startlines
+%D \handletokens abc\with\xxx
+%D \handletokens a b c\with\xxx
+%D \handletokens a b c\with\xxx
+%D \handletokens a{bc}d\with\xxx
+%D \handletokens a\space bc \with\xxx
+%D \stoplines
+%D
+%D And our previous example shows up as:
+%D
+%D \getbuffer[example]
+
+%D \macros
+%D {iftrialtypesetting, ifvisible}
+%D
+%D The next boolean is at first sight a strange one. Sometimes
+%D one does a trial typesetting run, for instance to determine
+%D dimensions. Some mechanisms, like object inclusion, can fail
+%D on such trials. Temporary setting the next boolean to true,
+%D helps a lot. The second boolena can be used to inhibit
+%D processing completely.
+
+\newif\iftrialtypesetting \trialtypesettingfalse
+\newif\ifvisible \visibletrue
+
+%D \macros
+%D {startlocal, startglobal}
+%D
+%D The next four macros are rather self explaining:
+%D
+%D \starttyping
+%D \startlocal
+%D whatever assignments
+%D \stoplocal
+%D
+%D \startglobal
+%D whatever assignments
+%D \stopglobal
+%D \stoptyping
+%D
+%D These macros are meant for those who know the difference
+%D between local and global assignments and are aware of the
+%D possible unwanted side effect
+
+\def\dostartglobaldefs#1#2%
+ {\scratchcounter\globaldefs
+ \ifnum\globaldefs#1\zerocount
+ \globaldefs-\globaldefs
+ \fi
+ \advance\globaldefs#2\plusone
+ \expandafter\chardef\csname@gd@\the\globaldefs\endcsname\scratchcounter}
+
+\def\dostopglobaldefs
+ {\globaldefs\ifcsname @gd@\the\globaldefs\endcsname\zerocount}
+
+\def\startlocal {\dostartglobaldefs>-}
+\def\stoplocal {\dostopglobaldefs}
+\def\startglobal {\dostartglobaldefs<+}
+\def\stopglobal {\dostopglobaldefs}
+
+%D \macros
+%D {twodigitrounding}
+%D
+%D When using \type {\special}s or \type {\pdfliteral}s, it
+%D sometimes makes sense to limit the precission. The next
+%D macro rounds a real number to two digits. It takes one
+%D argument and only works in \ETEX.
+
+\def\dointegerrounding #1.#2\relax {#1}
+\def\doonedigitrounding #1.#2#3\relax {\ifx#2*#1\else#1.#2\fi}
+\def\dotwodigitrounding #1.#2#3#4\relax {\ifx#2*#1\else#1.#2#3\fi}
+\def\dothreedigitrounding#1.#2#3#4#5\relax{\ifx#2*#1\else#1.#2#3#4\fi}
+
+\def\integerrounding#1%
+ {\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.5\points \relax .\relax}
+\def\onedigitrounding#1%
+ {\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.05\points \relax 00.*0\relax}
+\def\twodigitrounding#1%
+ {\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.005\points \relax 000.*00\relax}
+\def\threedigitrounding#1%
+ {\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax0000.*00\relax}
+
+%D \macros
+%D {processcontent}
+%D
+%D This is the first occasion where \TEX\ and \ETEX\ are no
+%D longer compatible, although in many cases things go ok.
+%D Beware of verbatim, i.e. catcode changes.
+%D
+%D \starttyping
+%D \def\starthans%
+%D {\processcontent{stophans}\test{\message{\test}\wait}}
+%D \stoptyping
+%D
+%D This macro is first used in the tabulation macros.
+
+\def\processcontent#1%
+ {\begingroup\@EA\doprocesscontent\csname#1\endcsname}
+
+\def\doprocesscontent#1#2#3%
+ {\long\def\doprocesscontent##1#1%
+ {\endgroup\long\def#2{##1}#3}%
+ \doprocesscontent}
+
+%D \macros
+%D {dogobblesingleempty, dogobbledoubleempty}
+%D
+%D These two macros savely grab and dispose two arguments.
+
+\def\dogobblesingleempty{\dosingleempty\dodogobblesingleempty}
+\def\dogobbledoubleempty{\dodoubleempty\dodogobbledoubleempty}
+
+\def\dodogobblesingleempty [#1]{}
+\def\dodogobbledoubleempty[#1][#2]{}
+
+\let\gobblesingleempty\dogobblesingleempty % also used
+\let\gobbledoubleempty\dogobbledoubleempty % also used
+
+%D \macros
+%D {sortcommalist,sortcommacommand,
+%D donumericcompare,comparedresult}
+%D
+%D Sometimes we need to sort a commalist, so here is Taco's
+%D solution. This will in many cases be a list that is stored
+%D in a \type{\csname}, so both commalist and commacommands are
+%D supported. The sorting algorithm is very simple, so the list
+%D should not be too long or sorting will be very slow.
+%D
+%D \starttyping
+%D \sortcommalist[10,2,4,5,6,1,2,3,4,10,20]\donumericcompare
+%D
+%D \def\test{10,2,4,5,6,1,2,3,4,10,20}
+%D
+%D \sortcommacommand[\test]\donumericcompare
+%D \stoptyping
+%D
+%D In both cases, the result is available in the macro \type
+%D {\sortedcommalist}.
+%D
+%D Parameter \type{#2} is a macro that should accept two
+%D parameters, and it has to decide which one is larger, by
+%D setting the counter \type{\comparedresult} to~0 (for equal),
+%D 1~(if it's first argument is larger), or~2 (if it's second
+%D argument is larger).
+%D
+%D As said, these macro are largely written by Taco, and are
+%D (maybe therefore) also the first application of \type
+%D {\replaceincommalist}.
+
+\newcount\comparedresult
+
+\def\sortcommacommand[#1]%
+ {\@EA\sortcommalist\@EA[#1]}
+
+\def\sortcommalist[#1]#2%
+ {\getcommalistsize[#1]%
+ \ifnum\commalistsize>1
+ \let\sortedcommalist\empty
+ \let\comparecommand#2%
+ \processcommalist[#1]\dosortcommacommand
+ \else
+ \def\sortedcommalist{#1}%
+ \fi}
+
+\def\dosortcommacommand#1%
+ {\ifx\sortedcommalist\empty
+ \def\sortedcommalist{#1}%
+ \else
+ \def\!!tempa{#1}%
+ \ifx\!!tempa\empty\else
+ \scratchcounter\plusone
+ \@EA\getcommalistsize\@EA[\sortedcommalist]%
+ \@EA\processcommalist\@EA[\sortedcommalist]\docompareitems
+ \fi
+ \fi}
+
+%D All those \type{\expandafter}'s are there because I do not
+%D want to use \type{\edef}.
+
+\def\docompareitems#1%
+ {\doifnotempty{#1}
+ {\@EA\comparecommand\@EA{\!!tempa}{#1}\relax
+ %\ifcase\compareresult % equal
+ \ifnum\comparedresult<2
+ \ifnum\scratchcounter=\commalistsize
+ \@EA\@EA\@EA\def\@EA\@EA\@EA\sortedcommalist
+ \@EA\@EA\@EA{\@EA\sortedcommalist\@EA,\!!tempa}%
+ \fi
+ %\or % new element larger
+ % \ifnum\scratchcounter=\commalistsize
+ % \@EA\@EA\@EA\def\@EA\@EA\@EA\sortedcommalist
+ % \@EA\@EA\@EA{\@EA\sortedcommalist\@EA,\!!tempa}%
+ % \fi
+ \else % old element larger
+ \@EA\def\@EA\newcommalistelement\@EA{\!!tempa,#1}%
+ \replaceincommalist\sortedcommalist\scratchcounter
+ \expandafter\quitcommalist
+ \fi}%
+ \advance\scratchcounter \plusone} % bug, was \minusone
+
+%D The macro \type{\donumericcompare} considers everything
+%D that is not a number to be larger than any number.
+
+% 0: both are equal, 1: #1 is larger, 2: #2 is larger
+
+\def\thenumericcompare#1#2% no \relax es inside hee
+ {\doifnumberelse{#1}
+ {\doifnumberelse{#2}{\ifnum#1>#2 \plusone\else\ifnum#1<#2 \plustwo\else\zerocount\fi\fi}\plustwo}
+ \plusone}
+
+\def\donumericcompare
+ {\comparedresult\thenumericcompare}
+
+%D \macros
+%D {@True, @False, @Not, @And}
+%D
+%D Some predicate logic functions, used in for instance the
+%D math module.
+
+\def\@True {00}
+\def\@False {01}
+\def\@Not #1{0\ifcase#11 \or\@EA 1\else \@EA 0\fi}
+\def\@And #1#2{0\ifcase#1#2 \@EA 0\else \@EA 1\fi}
+
+%D \macros
+%D {setdimensionwithunit, freezedimensionwithunit}
+%D
+%D The next assignments are all valid:
+%D
+%D \starttyping
+%D \setdimensionwithunit\scratchdimen{10} {cm}
+%D \setdimensionwithunit\scratchdimen{10cm}{cm}
+%D \setdimensionwithunit\scratchdimen{10cm}{}
+%D \freezedimensionwithunit\SomeWidth{\textwidth}
+%D \freezedimensionwithunit\SomeDepth{\dp\strutbox}
+%D \stoptyping
+%D
+%D As an alternative for the next macro we can use a global
+%D assignment inside a box. The \type{\empty}'s permits
+%D gobbling while preventing spurious \type{\relax}'s.
+
+\def\setdimensionwithunit#1#2#3% number unit dimension / nice trick
+ {\afterassignment\gobblefourarguments#1=#2#3pt\relax\empty\empty\empty\empty}
+
+\def\freezedimensionwithunit#1#2%
+ {\setdimensionwithunit\scratchdimen#1{#2}\edef#1{\the\scratchdimen}}
+
+%D \macros
+%D {doifsometokselse}
+%D
+%D Not that fast I guess, but here's a way to test for token
+%D registers being empty.
+
+\def\doifsometokselse#1% % #2#3%
+ {\edef\!!stringa{\the#1}%
+ \ifx\!!stringa\empty % #3\else#2\fi}
+ \expandafter\secondoftwoarguments
+ \else
+ \expandafter\firstoftwoarguments
+ \fi}
+
+%D \macros
+%D {startstrictinspectnextcharacter}
+%D
+%D This one if for Taco's bibliography module:
+
+\let\normalinspectnextcharacter\inspectnextcharacter
+
+\def\strictinspectnextcharacter% no user macro !
+ {\ifx\nexttoken\charactertoken
+ \expandafter\!!stringa
+ \else
+ \expandafter\!!stringb
+ \fi}
+
+% better: push/pop
+
+\def\startstrictinspectnextcharacter
+ {\let\inspectnextcharacter\strictinspectnextcharacter}
+
+\def\stopstrictinspectnextcharacter
+ {\let\inspectnextcharacter\normalinspectnextcharacter}
+
+%D \macros
+%D {gobblespacetokens}
+%D
+%D This macro needs a speed-up!
+
+%\def\gobblespacetokens
+% {\doifnextcharelse\empty\donothing\donothing} % no {}\do\do !
+
+\def\gobblespacetokens
+ {\afterassignment\nexttoken\let\nexttoken=}
+
+%D \macros
+%D {verbatimargument}
+%D
+%D As the name says, this macro converts its argument to a
+%D (rather safe) string.
+
+\let\verbatimstring\detokenize
+
+%D These are needed in ordinal number conversions:
+
+\def\lastdigit#1%
+ {\@EA\thelastdigit\number#1\relax}
+
+\def\thelastdigit#1#2%
+ {\ifx#2\relax#1\else\@EA\thelastdigit\@EA#2\fi}
+
+\def\lasttwodigits#1%
+ {\@EA\thelasttwodigits\@EA0\number#1\relax}
+
+\def\thelasttwodigits#1#2#3% 0 dig ... \relax
+ {\ifx#3\relax#1#2\else\@EA\thelasttwodigits\@EA#2\@EA#3\fi}
+
+%D \macros
+%D {serializecommalist}
+%D
+%D Concatenate commalists:
+
+\def\serializecommalist[#1]%
+ {\let\serializedcommalist\empty
+ \def\docommand##1{\edef\serializedcommalist{\serializedcommalist##1}}%
+ \processcommacommand[#1]\docommand}
+
+%D \macros
+%D {purenumber}
+%D
+%D Sometimes we need control over when \TEX\ stops reading a
+%D number, especially in full expandable macros where using
+%D \type {\relax} would lead to disasters.
+%D
+%D \starttyping
+%D \ifodd\purenumber{...}\space ... \else ... \fi
+%D \stoptyping
+%D
+%D Here we use a space as number delimiter in combination
+%D with a space- and relax-less \type {\purenumber}. This
+%D macro works ok with \type {\the}, \type {\number} as well
+%D as \ETEX's \type {\numexpr}.
+
+\def\purenumber#1{\@EA\firstofoneargument\@EA{\number#1}}
+
+%D \macros
+%D {filterfromvalue}
+%D
+%D \starttyping
+%D \setvalue{xx}{{A}{B}{C}}
+%D
+%D \filterfromvalue{xx}{3}{3}
+%D \filterfromvalue{xx}{3}{2}
+%D \filterfromvalue{xx}{3}{1}
+%D \stoptyping
+%D
+%D An alternative is to store 'max' in the list, say:
+%D
+%D \starttyping
+%D \setvalue{xx}{3{A}{B}{C}}
+%D
+%D \filterfromvalues{3}{xx}{3}
+%D \filterfromvalues{3}{xx}{2}
+%D \filterfromvalues{3}{xx}{1}
+%D \stoptyping
+%D
+%D I'll implement this when I'm in \quotation {writing dirty
+%D macros mood}.
+
+\def\dofilterfromstr#1#2% max n % no need to be fast
+ {\expandafter \expandafter \expandafter \strippedcsname
+ \ifcase#1\or \ifcase#2\or
+ \firstofoneargument \else
+ \gobbleoneargument \fi
+ \or \ifcase#2\or
+ \firstoftwoarguments \or
+ \secondoftwoarguments \else
+ \gobbletwoarguments \fi
+ \or \ifcase#2\or
+ \firstofthreearguments \or
+ \secondofthreearguments \or
+ \thirdofthreearguments \else
+ \gobblethreearguments \fi
+ \or \ifcase#2\or
+ \firstoffourarguments \or
+ \secondoffourarguments \or
+ \thirdoffourarguments \or
+ \fourthoffourarguments \else
+ \gobblefourarguments \fi
+ \or \ifcase#2\or
+ \firstoffivearguments \or
+ \secondoffivearguments \or
+ \thirdoffivearguments \or
+ \fourthoffivearguments \or
+ \fifthoffivearguments \else
+ \gobblefivearguments \fi
+ \fi}
+
+\def\filterfromvalue#1#2#3% value max n
+ {\@EA\@EAEAEA\csname % we use the fact that an
+ \@EA\ifx\csname#1\endcsname\relax % undefined cs has become \relax
+ \strippedcsname\gobbleoneargument % which we then gobble here
+ \else
+ \dofilterfromstr{#2}{#3}%
+ \fi
+ \endcsname\csname#1\endcsname}
+
+\def\filterfromnext#1#2% max n {..}{..}{..}{..}
+ {\csname\dofilterfromstr{#1}{#2}\endcsname}
+
+%D \macros
+%D {definemeasure}
+%D
+%D \starttyping
+%D \definemeasure[mywidth][\dimexpr(\textwidth-1cm)]
+%D
+%D ... \measure{mywidth} ...
+%D \stoptyping
+
+\def\??dm{@@dm} % brrr
+
+\def\definemeasure
+ {\dodoubleargument\dodefinemeasure}
+
+\def\dodefinemeasure[#1][#2]%
+ {\expandafter\def\csname\??dm#1\endcsname{#2}}
+
+% #2 could be omitted, but we want to support spaces
+%
+% \setmeasure {x} {1cm}
+% \setmeasure {xx} {1cm}
+% \setmeasure {xxx}{1cm}
+
+\def\setmeasure #1#2{\expandafter\def \csname\??dm#1\endcsname{#2}} % quick way
+\def\setemeasure#1#2{\expandafter\edef\csname\??dm#1\endcsname{#2}} % quick way
+\def\setgmeasure#1#2{\expandafter\gdef\csname\??dm#1\endcsname{#2}} % quick way
+\def\setxmeasure#1#2{\expandafter\xdef\csname\??dm#1\endcsname{#2}} % quick way
+
+\def\measure#1%
+ {\ifcsname\??dm#1\endcsname\csname\??dm#1\endcsname\else\zeropoint\fi}
+
+%D \macros
+%D {doifdimensionelse}
+%D
+%D This is a dirty one: we simply append a unit and discard it when needed.
+
+\def\doifdimensionelse#1%
+ {\afterassignment\dodoifdimensionelse\scratchdimen#1pt\relax}
+
+\def\dodoifdimensionelse#1%
+ {\ifx#1\relax
+ \expandafter\secondoftwoarguments
+ \else % #1=p ... t\relax
+ \expandafter\thirdoffourarguments
+ \fi}
+
+%D \macros
+%D {comparedimension,comparedimensioneps}
+%D
+%D This is a dirty one: we simply append a unit and discard it when needed.
+
+\newdimen\roundingeps \roundingeps=10sp
+
+\def\comparedimension#1#2%
+ {\chardef\compresult
+ \ifdim#1<#2%
+ \zerocount
+ \else\ifdim#1<#2%
+ \plusone
+ \else
+ \plustwo
+ \fi\fi}
+
+\def\comparedimensioneps#1#2% todo: use eps feature
+ {\chardef\compresult
+ \ifdim\dimexpr#1-#2\relax<\roudingeps
+ \zerocount
+ \else\ifdim\dimexpr#2-#1\relax<\roudingeps
+ \zerocount
+ \else\ifdim#1<#2%
+ \plusone
+ \else
+ \plustwo
+ \fi\fi\fi}
+
+% % % % % % % % % % % % % % % % % % % % % %
+
+% pretty ugly but fast
+
+% \copycsname xxx\endcsname\csname ..\endcsname
+
+\def\copycsname{\@EA\@EA\@EA\let\@EA\@EA\csname}
+
+% \letcscsname \crap \csname ..\endcsname
+% \letcsnamecs \csname ..\endcsname\crap
+% \letcsnamecsname\csname ..\endcsname\csname ..\endcsname
+
+\def\letcscsname {\@EA\let\@EA}
+\def\letcsnamecs {\@EA\let}
+\def\letcsnamecsname{\@EA\@EA\@EA\let\@EA\@EA}
+
+% another one, add an item to a commalist
+
+\def\addvalue#1#2% cs item
+ {\ifcsname#1\endcsname\else\expandafter\let\csname#1\endcsname\empty\fi
+ \normalexpanded{\noexpand\addtocommalist{#2}\@EA\noexpand\csname#1\endcsname}}
+
+\def\unspaced#1%
+ {\dounspaced#1\end}
+
+\def\dounspaced#1%
+ {\ifx#1\end
+ \@EA\gobbleoneargument
+ \else
+ \ifx#1\blankspace\else#1\fi
+ \fi
+ \dounspaced}
+
+\def\unspaceargument#1\to#2%
+ {\scratchcounter\catcode32\relax
+ \catcode32\@@ignore\scantextokens{\edef#2{#1}}%
+ \catcode32\scratchcounter}
+
+\def\unspaceafter#1#2%
+ {\unspaceargument#2\to\ascii
+ \expandafter#1\expandafter{\ascii}}
+
+% sometimes handy:
+
+\def\doifhasspaceelse#1%
+ {\edef\!!stringa{#1}%
+ \normalexpanded{\noexpand\dodoifhasspaceelse#1\space}\empty\relax}
+
+\def\dodoifhasspaceelse#1 #2#3\relax % \space\empty\relax
+ {\ifx\!!stringa\space
+ \@EA\firstoftwoarguments
+ \else\ifx#2\empty
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \@EAEAEA\firstoftwoarguments
+ \fi\fi}
+
+% this will replace loadfile once and alike !!! todo
+
+\def\@flg@{@flg@}
+
+\def\setflag #1{\@EA\dodoglobal\@EA\let\csname\@flg@#1\endcsname\zerocount}
+\def\resetflag#1{\@EA\dodoglobal\@EA\let\csname\@flg@#1\endcsname\plusone}
+
+\let\ifflagged\ifcase
+
+\def\flag#1{\csname\@flg@#1\endcsname}
+
+\def\doifelseflagged#1%
+ {\@EA\ifx\csname\@flg@#1\endcsname\relax
+ \@EA\secondoftwoarguments
+ \else\ifcase\csname\@flg@#1\endcsname
+ \@EAEAEA\firstoftwoarguments
+ \else
+ \@EAEAEA\secondoftwoarguments
+ \fi\fi}
+
+\def\doifnotflagged#1%
+ {\@EA\ifx\csname\@flg@#1\endcsname\relax
+ \@EA\firstofoneargument
+ \else\ifcase\csname\@flg@#1\endcsname
+ \@EAEAEA\gobbleoneargument
+ \else
+ \@EAEAEA\firstofoneargument
+ \fi\fi}
+
+\def\inheritparameter[#1]#2[#3]#4[#5]% tag tokey fromkey % [bypasses k!prefix]
+ {\@EA\def\csname#1#3\@EA\endcsname\@EA{\csname#1#5\endcsname}}
+
+% \buildarray[test][aa,bb,cc,dd,ee,ff]
+% \setarrayelement{test}{1}{qq}
+% \arrayelement{test}{1}
+% \arraylength{test}
+%
+% \def\buildarray[#1][#2]%
+% {\scratchcounter=0
+% \def\docommand##1%
+% {\advance\scratchcounter by 1
+% \setvalue{@@aa#1\the\scratchcounter}{##1}}%
+% \processcommalist[#2]\docommand
+% \setevalue{@@aa#1}{\the\scratchcounter}}%
+%
+% \def\setarrayelement#1#2{\setvalue{@@aa#1#2}}
+% \def\arrayelement #1#2{\getvalue{@@aa#1#2}}
+% \def\arraylength #1{\getvalue{@@aa#1}}
+
+% \newsignal\junksignal
+%
+% \def\setjunksignal%
+% {\ifhmode
+% \hskip\junksignal
+% \let\removejunkspaces\doremovejunkspaces
+% \else
+% \let\removejunkspaces\relax
+% \fi}
+%
+% \def\doremovejunkspaces%
+% {\doloop{\ifdim\lastskip=\junksignal\unskip\else\exitloop\fi}}
+
+\def\dodoifnonzeropositiveelse#1#2\end % #3#4%
+ {\ifx#1\relax
+ \ifcase\scratchcounter
+ \endgroup
+ \@EAEAEA\secondoftwoarguments
+ \else
+ \endgroup
+ \@EAEAEA\firstoftwoarguments
+ \fi
+ \else
+ \endgroup
+ \@EA\secondoftwoarguments
+ \fi}
+
+\def\doifnonzeropositiveelse#1%
+ {\begingroup\afterassignment\dodoifnonzeropositiveelse\scratchcounter=0#1\relax\empty\end}
+
+% here ?
+
+\def\dosetrawvalue #1#2#3{\@EA \def\csname#1#2\endcsname{#3}}
+\def\dosetrawevalue#1#2#3{\@EA\edef\csname#1#2\endcsname{#3}}
+\def\dosetrawgvalue#1#2#3{\@EA\gdef\csname#1#2\endcsname{#3}}
+\def\dosetrawxvalue#1#2#3{\@EA\xdef\csname#1#2\endcsname{#3}}
+
+\def\getrawparameters {\dogetparameters\dosetrawvalue }
+\def\getraweparameters {\dogetparameters\dosetrawevalue}
+\def\getrawgparameters {\dogetparameters\dosetrawgvalue}
+\def\getrawxparameters {\dogetparameters\dosetrawxvalue}
+
+\def\globalgetrawparameters{\dogetparameters\dosetrawgvalue} % obsolete
+
+\def\splitskip#1%
+ {\scratchskip#1\relax
+ \dimen0\scratchskip
+ \dimen2\gluestretch\scratchskip
+ \dimen4\glueshrink\scratchskip}
+
+\newcount\modcounter
+
+\def\dosetmodulo#1#2#3%
+ {\modcounter#1\divide\modcounter#2\multiply\modcounter#2%
+ #3#1\advance#3-\modcounter}
+
+\def\dosetdivision#1#2#3%
+ {#3#1\divide#3 #2\relax}
+
+\def\DoMod#1by#2to#3{\dosetmodulo {#1}{#2}{#3}}
+\def\DoDiv#1by#2to#3{\dosetdivision{#1}{#2}{#3}}
+
+\def\dounprotected#1\par
+ {#1\protect}
+
+\def\unprotected
+ {\unprotect\dounprotected}
+
+% awaiting the definitive implementation
+
+\ifdefined\resettimer \else
+ \let\resettimer \relax
+ \newcount\elapsedtime
+\fi
+
+\newcount\featuretest
+
+\def\testfeature#1#2%
+ {\def\dotestfeature
+ {\advance\featuretest \plusone
+ \ifnum\featuretest>#1\else#2\expandafter\dotestfeature\fi}%
+ \retestfeature}
+
+\def\retestfeature % timer support is new per 10/5/2005
+ {\bgroup
+ \ifcase\interactionmode\let\wait\relax\fi
+ \writestatus\m!systems{starting feature test}\wait
+ \resettimer
+ \featuretest\zerocount \dotestfeature
+ \writestatus\m!systems{feature test done (\elapsedseconds s)}%
+ \wait
+ \egroup}
+
+\def\elapsedseconds{\expandafter\withoutpt\the\dimexpr\elapsedtime sp\relax}
+
+\def\showtimer#1%
+ {\writestatus{runtime}{\elapsedseconds\space s / #1}}
+
+\def\testfeatureonce#1#2%
+ {\let\wait\relax\testfeature{#1}{#2}\end}
+
+%D \macros
+%D {freezedimenmacro}
+%D
+%D This macro is use as:
+%D
+%D \starttyping
+%D \freezedimenmacro\leftmargindistance
+%D \stoptyping
+
+\def\freezedimenmacro#1%
+ {\edef#1{\the\dimexpr#1}}
+
+%D The next macro negates a macro (dimension or number, or actually, whatever.
+%D It's a typical example of \type {\if} usage:
+%D
+%D \starttyping
+%D \if-\whatever \else-\whatever\fi => else => -whatever
+%D \if--\whatever\else-\whatever\fi => then => whatever
+%D \stoptyping
+
+\def\negated#1{\if-#1\else-#1\fi} % does only work in macros or text
+
+% This permits things like ^\index{hans}^, where hans is
+% duplicated in the text.
+
+\newif\ifduplicate
+
+\bgroup
+
+\gdef\checkduplication % in line with Knuth
+ {\ifmmode\expandafter^\else\expandafter\startduplication\fi}
+
+\gdef\insideduplication
+ {\ifmmode\expandafter^\else\expandafter\egroup\fi}
+
+\catcode`\^=\@@active
+
+\gdef\enableduplication
+ {\catcode`\^=\@@active \let^\checkduplication}
+
+\gdef\disableduplication
+ {\catcode`\^=\@@superscript}
+
+\gdef\startduplication
+ {\bgroup \duplicatetrue \let^\insideduplication}
+
+\egroup
+
+\def\gobbleassigndimen#1\\{}
+
+\def\assigndimen#1#2%
+ {\afterassignment\gobbleassigndimen#1=#2\!!zeropoint\\}
+
+\def\setusage#1%
+ {\@EA\let\csname#1\endcsname\iftrue}
+
+\def\resetusage#1%
+ {\@EA\let\csname#1\endcsname\iffalse}
+
+\def\ifusage#1%
+ {\ifcsname#1\endcsname\else
+ \resetusage{#1}%
+ \fi
+ \csname#1\endcsname}
+
+%D Very handy, more efficient than \type{{}}, and more readable
+%D than \type {\empty}.
+
+\let\donothing\empty
+
+% The following macros are used in XML handling.
+
+\long\setvalue{@u@s@"}#1#2"{#2} \long\setvalue{@g@s@"}#1#2"{\scratchtoks{#2}}
+\long\setvalue{@u@s@'}#1#2'{#2} \long\setvalue{@g@s@'}#1#2'{\scratchtoks{#2}}
+\long\setvalue{@u@s@ }#1#2 {#2} \long\setvalue{@g@s@ }#1#2 {\scratchtoks{#2}}
+
+\long\def\unstringed#1{\csname\ifcsname @u@s@#1\endcsname @u@s@#1\else\s!empty\fi\endcsname#1}
+\long\def\grabstring#1{\csname\ifcsname @g@s@#1\endcsname @g@s@#1\else\s!empty\fi\endcsname#1}
+
+\def\dowithgrabbedstring#1%
+ {\def\@@dowithgrabbedstring{#1}%
+ \afterassignment\@@dowithgrabbedstring\grabstring}
+
+\def\expifequalelse#1#2%
+ {\@@ifequal#1\relax\relax\@@and#2\relax\relax\@@then}
+
+\def\@@ifequal#1#2\@@and#3%
+ {\ifx#1\relax
+ \ifx#3\relax
+ \@EAEAEA\@@if@@equal@@true
+ \else
+ \@EAEAEA\@@if@@equal@@false
+ \fi
+ \else
+ \ifx#3\relax
+ \@EAEAEAEAEAEA\@@if@@equal@@false
+ \else\ifx#1#3%
+ % go on
+ \else
+ \@EAEAEAEAEAEA\@@if@@equal@@false
+ \fi\fi
+ \fi
+ \@@ifequal#2\@@and}
+
+\long\def\@@if@@equal@@true #1\@@then#2#3{#2}
+\long\def\@@if@@equal@@false#1\@@then#2#3{#3}
+
+%D new stuff :
+
+\def\partialexpanded#1%
+ {\let\@@notexpanded\noexpand
+ \long\xdef\@@expanded{\noexpand#1}%
+ \let\@@notexpanded\empty
+ \@@expanded}
+
+\def\appended#1#2#3{\@EA#1\@EA#2\@EA{#2#3}}
+\def\appendvalue #1{\@EA\appended\@EA \def\csname#1\endcsname}
+\def\appendgvalue#1{\@EA\appended\@EA\gdef\csname#1\endcsname}
+
+\def\prepended#1#2#3{\scratchtoks{#3}\@EA\@EA\@EA#1\@EA\@EA\@EA#2\@EA\@EA\@EA{\@EA\the\@EA\scratchtoks#2}}
+\def\prependvalue #1{\@EA\prepended\@EA \def\csname#1\endcsname}
+\def\prependgvalue#1{\@EA\prepended\@EA\gdef\csname#1\endcsname}
+
+%D \macros
+%D {compresscommacommandnrs,compresscommalistnrs,compressedcommalistnrs,
+%D compresscommacommand,compresscommalist,compressedcommalist,
+%D reversecommacommand,reversecommalist,reversedcommalist}
+%D
+%D The following two list processing macros are needed by Taco's
+%D bibliography module. The numbers compressor converts the
+%D list in a list of ranges. The normal compressor remove duplicate
+%D and empty entries.
+
+\def\compresscommalistnrs[#1]%
+ {\let\compressedlist\empty
+ \!!counta\maxdimen
+ \!!countb\maxdimen
+ \processcommalist[#1]\docompresslistnrs
+ \ifnum\!!counta=\maxdimen\else\dodocompresslistnrs\fi}
+
+\def\compresscommacommandnrs[#1]%
+ {\normalexpanded{\noexpand\compresscommalistnrs[#1]}}
+
+\def\docompresslistnrs#1%
+ {\edef\commalistelement{#1}%
+ \ifx\commalistelement\empty\else
+ \ifnum\!!counta=\maxdimen
+ \!!counta\commalistelement\relax
+ \!!countb\!!counta
+ \else
+ \advance\!!countb\plusone
+ \ifnum\commalistelement>\!!countb
+ \advance\!!countb\minusone
+ \dodocompresslistnrs
+ \!!counta\commalistelement\relax
+ \!!countb\!!counta
+ \fi
+ \fi
+ \fi}
+
+\def\dodocompresslistnrs
+ {\edef\compressedlist
+ {\ifx\compressedlist\empty\else\compressedlist,\fi
+ {\the\!!counta}{\ifnum\!!countb>\!!counta\the\!!countb\fi}}}
+
+%D \def\test#1{{\tttf#1->\compresscommalistnrs[#1]\defconvertedcommand\ascii\compressedlist\ascii}}
+%D \startlines
+%D \test{}
+%D \test{1}
+%D \test{1,3}
+%D \test{1,3,4}
+%D \test{1,3,3,4,5}
+%D \test{1,3,3,4,5,8}
+%D \test{1,3,3,4,5,5,8,10}
+%D \test{1,3,4,5,8,10,11}
+%D \test{1,,3,,4,,5,,8,,10,,11,}
+%D \stoplines
+
+\def\compresscommalist[#1]%
+ {\let\compressedlist\empty
+ \let\!!stringa\empty
+ \processcommalist[#1]\docompresslist}
+
+\def\compresscommacommand[#1]%
+ {\normalexpanded{\noexpand\compresscommalist[#1]}}
+
+\def\docompresslist#1%
+ {\edef\commalistelement{#1}%
+ \ifx\commalistelement\empty \else
+ \ifx\!!stringa\commalistelement \else
+ \ifx\compressedlist\empty
+ \def\compressedlist{#1}%
+ \else
+ \appended\def\compressedlist{,#1}%
+ \fi
+ \let\!!stringa\commalistelement
+ \fi
+ \fi}
+
+%D \def\test#1{{\tttf#1->\compresscommalist[#1]\defconvertedcommand\ascii\compressedlist\ascii}}
+%D \startlines
+%D \test{}
+%D \test{1}
+%D \test{1,3}
+%D \test{1,3,4}
+%D \test{1,3,3,4,5}
+%D \test{1,3,3,4,5,8}
+%D \test{1,3,3,4,5,5,8,10}
+%D \test{1,3,4,5,8,10,11}
+%D \test{1,,3,,4,,5,,8,,10,,11,}
+%D \stoplines
+
+\def\reversecommalist[#1]%
+ {\let\reversedlist\empty
+ \processcommalist[#1]\doreverselist}
+
+\def\doreverselist#1%
+ {\ifx\reversedlist\empty
+ \def\reversedlist{#1}%
+ \else
+ \prepended\def\reversedlist{#1,}%
+ \fi}
+
+\def\reversecommacommand[#1]%
+ {\normalexpanded{\noexpand\reversecommalist[#1]}}
+
+%D \def\test#1{{\tttf#1->\reversecommalist[#1]\defconvertedcommand\ascii\reversedlist\ascii}}
+%D \startlines
+%D \test{}
+%D \test{1}
+%D \test{1,3}
+%D \test{1,3,4}
+%D \test{1,3,3,4,5}
+%D \test{1,3,3,4,5,8}
+%D \test{1,3,3,4,5,5,8,10}
+%D \test{1,3,4,5,8,10,11}
+%D \test{1,,3,,4,,5,,8,,10,,11,}
+%D \stoplines
+
+%D \macros
+%D {stripstring}
+%D
+%D Needed in bookmarks:
+%D
+%D \starttyping
+%D {\sanitizePDFdocencoding test \CONTEXT\ test \to\oeps\stripstring\oeps\tttf[\oeps]}
+%D \stoptyping
+
+\def\stripstring#1% #1 is \cs
+ {\edef\cs{\ctxlua
+ {tex.sprint(tex.vrbcatcodes,string.strip(\!!bs\detokenize\expandafter{#1}\!!es))}}}
+
+%D \macros
+%D {dowithrange}
+%D
+%D This one is for Mojca Miklavec, who made me aware of the fact that
+%D \type {page-imp.tex} was not the best place to hide it.
+
+\def\dowithrange#1#2% #2 takes number
+ {\splitstring#1\at:\to\fromrange\and\torange
+ \ifx\torange\empty\let\torange\fromrange\fi
+ \dostepwiserecurse\fromrange\torange1{#2{\recurselevel}}}
+
+%D \macros {uncompresslist}
+%D
+%D When given a list like \type{1,4-7,9} as argument, this macro
+%D will store the expanded commalist in \type{\uncompressedlist}.
+%D
+%D \startbuffer
+%D \def\MojcaHasToDoTheTasks[#1]#2%
+%D {{\uncompresslist[#1]%
+%D \def\processitem##1{I have to do ##1 #2\par}%
+%D \processcommacommand[\uncompressedlist]\processitem}}
+%D
+%D \MojcaHasToDoTheTasks [1-4,7,9-11] {until tomorrow}
+%D \stopbuffer
+%D
+%D Here is an example of how to use \type {\uncompresslist}:
+%D \typebuffer
+%D
+%D The output of this is:
+%D
+%D \getbuffer
+
+\def\uncompresslist[#1]% by TH
+ {\let\uncompressedlist\empty
+ \def\docompressedlistitem##1-##2-%
+ {\@EA\dorecurse\@EA
+ {\the\numexpr1+##2-##1\relax}%
+ {\@EA\appendtocommalist\@EA{\the\numexpr##1-1+####1\relax}\uncompressedlist}}%
+ \def\douncompresslist##1%
+ {\doifinstringelse{-}{##1}
+ {\docompressedlistitem##1-}
+ {\appendtocommalist{##1}\uncompressedlist}}%
+ \processcommalist[#1]\douncompresslist}
+
+%D \macros
+%D {ignoreimplicitspaces}
+%D
+%D \startbuffer
+%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignorespaces}
+%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
+%D \def\whatever[#1]{\expanded{\definedfont[#1 at 12pt]}\ignoreimplicitspaces}
+%D {a\whatever[Serif]b a\whatever[Serif] b a\whatever[Serif]\space b}
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\ignoreimplicitspaces
+ {\doifnextcharelse\relax\relax\relax}
+
+% new
+%
+% \startnointerference
+% all kind of code
+% \stopnointerference
+
+\newbox\nointerferencebox
+
+\def\startnointerference % not even grouped !
+ {\setbox\nointerferencebox\vbox
+ \bgroup}
+
+\def\stopnointerference
+ {\egroup
+ \setbox\nointerferencebox\emptybox}
+
+% \def\appendtovaluelist#1#2%
+% {\ifcsname#1\endcsname
+% \expandafter\ifx\csname#1\endcsname\empty
+% \expandafter\def\csname#1\endcsname{#2}%
+% \else
+% \expandafter\def\csname#1\expandafter\expandafter\expandafter\endcsname
+% \expandafter\expandafter\expandafter{\csname#1\endcsname,#2}%
+% \fi
+% \else
+% \expandafter\def\csname#1\endcsname{#2}%
+% \fi}
+%
+% or
+%
+% \def\appendtovaluelist#1%
+% {\ifcsname#1\endcsname
+% \expandafter\ifx\csname#1\endcsname\empty
+% \expandafter\noappendtovaluelist\csname#1\expandafter\expandafter\expandafter\endcsname
+% \else
+% \expandafter\doappendtovaluelist\csname#1\expandafter\expandafter\expandafter\endcsname
+% \fi
+% \else
+% \expandafter\noappendtovaluelist\csname#1\expandafter\endcsname
+% \fi}
+
+% \def\doappendtovaluelist#1#2{\expandafter\def\expandafter#1\expandafter{#1,#2}}
+% \def\noappendtovaluelist#1#2{\def#1{#2}}
+
+% \appendtovaluelist{mylist}{aap}
+% \appendtovaluelist{mylist}{noot}
+% \appendtovaluelist{mylist}{mies}
+
+% \showvalue{mylist}
+
+\protect \endinput
diff --git a/tex/context/base/syst-cat.mkii b/tex/context/base/syst-cat.mkii
deleted file mode 100644
index 614610258..000000000
--- a/tex/context/base/syst-cat.mkii
+++ /dev/null
@@ -1,61 +0,0 @@
-%D \module
-%D [ file=syst-cat,
-%D version=2006.09.18,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Catcode Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\def\newcatcodetable#1%
- {\global\advance\cctdefcounter\plusone
- \global\mathchardef#1\cctdefcounter
- \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
- \expandafter\newtoks\csname @@cct:\number\cctdefcounter\endcsname}
-
-\mathchardef\currentcatcodetable\zerocount
-
-\newtoks \setdefaultlowercatcodes
-\newtoks \setdefaultuppercatcodes
-
-\def\next#1% we don't have a proper loop defined yet
- {\edef\nextnext{#1{\the#1\catcode\the\cctcountera\space\ifnum\catcode\cctcountera=11 11\else12\fi}}%
- \nextnext\ifnum\cctcountera<\cctcounterb \advance\cctcountera\plusone \expandafter\next\expandafter#1\fi}
-
-\cctcountera 0 \cctcounterb 127 \next\setdefaultlowercatcodes
-\cctcountera 128 \cctcounterb 255 \next\setdefaultuppercatcodes
-
-% \chardef\activehackcode=`~
-
-% \def\next#1% we don't have a proper loop defined yet
-% {\catcode\cctcountera 13
-% \cctcounterc\uccode\activehackcode
-% \uccode\activehackcode\cctcountera
-% \catcode\uccode\activehackcode 13
-% \uppercase{\edef~{\detokenize{~}}}%
-% \uccode\activehackcode\cctcounterc
-% \ifnum\cctcountera<\cctcounterb \advance\cctcountera\plusone \expandafter\next\expandafter#1\fi}
-
-% \cctcountera 128 \cctcounterb 255 \next\setdefaultuppercatcodes
-
-\recatcodeuppercharactersfalse
-
-\def\catcodetable#1%
- {\mathchardef\currentcatcodetable#1%
- \the\setdefaultlowercatcodes
- \ifrecatcodeuppercharacters\the\setdefaultuppercatcodes\fi
- \the\csname @@cct:\number#1\endcsname}
-
-\long\def\startcatcodetable#1#2\stopcatcodetable
- {\global\csname @@cct:\number#1\endcsname{#2}}
-
-\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
- {\global\csname @@cct:\number#1\endcsname\expandafter{\the\csname @@cct:\number#1\endcsname#2}}
-
-\protect \endinput
diff --git a/tex/context/base/syst-cat.mkiv b/tex/context/base/syst-cat.mkiv
deleted file mode 100644
index b387eb2ed..000000000
--- a/tex/context/base/syst-cat.mkiv
+++ /dev/null
@@ -1,124 +0,0 @@
-%D \module
-%D [ file=syst-cat,
-%D version=2006.09.18,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Catcode Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-\def\newcatcodetable#1%
- {\global\advance\cctdefcounter\plusone
- \expandafter\xdef\csname @@ccn:\number\cctdefcounter\endcsname{\string#1}% logging
- \global\mathchardef#1\cctdefcounter}
-
-\newcatcodetable \scratchcatcodetable \initcatcodetable\scratchcatcodetable
-
-\ifx\nilcatcodes \undefined \newcatcodetable \nilcatcodes \fi
-\ifx\texcatcodes \undefined \newcatcodetable \texcatcodes \fi
-\ifx\ctxcatcodes \undefined \newcatcodetable \ctxcatcodes \fi
-\ifx\notcatcodes \undefined \newcatcodetable \notcatcodes \fi
-\ifx\mthcatcodes \undefined \newcatcodetable \mthcatcodes \fi % brrr
-\ifx\vrbcatcodes \undefined \newcatcodetable \vrbcatcodes \fi
-\ifx\prtcatcodes \undefined \newcatcodetable \prtcatcodes \fi
-\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 % < >
-
-\newtoks \setdefaultcatcodes
-
-\setdefaultcatcodes
- {\catcode`\\ 12
- \catcode`\^^M 12
- \catcode`\ 12
- \catcode`\% 12
- \catcode127 12 }
-
-\long\def\startcatcodetable#1#2\stopcatcodetable
- {\bgroup
- \catcodetable\scratchcatcodetable
- \the\setdefaultcatcodes
- #2%
- \savecatcodetable#1\relax
- \egroup}
-
-\newcatcodetable\dummycatcodes
-
-% \long\def\startextendcatcodetable#1#2\stopextendcatcodetable
-% {\bgroup
-% \catcodetable#1\relax
-% #2%
-% \savecatcodetable\dummycatcodes
-% \catcodetable\dummycatcodes
-% \savecatcodetable#1\relax
-% \egroup}
-
-\long\def\startextendcatcodetable#1#2\stopextendcatcodetable
- {\bgroup
- \catcodetable#1\relax
- \globaldefs\plusone
- #2%
- \globaldefs\zerocount
- \egroup}
-
-% ==
-%
-% \long\def\startextendcatcodetable#1#2\stopextendcatcodetable
-% {\bgroup
-% \scratchcounter\the\catcodetable
-% \catcodetable #1 #2
-% \catcodetable\scratchcounter
-% \egroup}
-
-\def\letcatcodecommand
- {\afterassignment\letcatcodecommanda\cctcountera}
-
-\def\letcatcodecommanda
- {\afterassignment\letcatcodecommandb\cctcounterb}
-
-% construct the definition in lua
-%
-% \def\letcatcodecommandb
-% {\scratchcounter\catcode\cctcounterb \catcode\cctcounterb=13
-% \directlua\CTXlua{tex.print(tex.texcatcodes,"\\xdef " .. string.char(\number\cctcounterb)
-% .. "{\\noexpand\\catcodecommand{\number\cctcounterb}}")}%
-% \catcode\cctcounterb\scratchcounter
-% \expandafter\let\csname cc:\number\cctcountera:\number\cctcounterb\endcsname}
-%
-% or less messy:
-%
-% \def\letcatcodecommandb
-% {\chardef\savedcctcode\catcode\cctcounterb
-% \catcode\cctcounterb=13
-% \expandafter\edef\directlua\CTXlua{tex.sprint(tex.texcatcodes,string.char(\number\cctcounterb))}%
-% {\noexpand\catcodecommand{\number\cctcounterb}}%
-% \catcode\cctcounterb\savedcctcode
-% \expandafter\let\csname cc:\number\cctcountera:\number\cctcounterb\endcsname}
-
-\let\currentcatcodetable\catcodetable
-
-\startruntimectxluacode
- tex.nilcatcodes = \number\nilcatcodes ;
- tex.texcatcodes = \number\texcatcodes ;
- tex.ctxcatcodes = \number\ctxcatcodes ;
- tex.notcatcodes = \number\notcatcodes ;
- tex.mthcatcodes = \number\mthcatcodes ;
- tex.vrbcatcodes = \number\vrbcatcodes ;
- tex.prtcatcodes = \number\prtcatcodes ;
- tex.xmlcatcodes = \number\xmlcatcodesn ;
- tex.xmlcatcodesn = \number\xmlcatcodesn ; % normal
- tex.xmlcatcodese = \number\xmlcatcodese ; % entitle
- tex.xmlcatcodesr = \number\xmlcatcodesr ; % reduce
- tex.typcatcodesa = \number\typcatcodesa ; % { }
- tex.typcatcodesb = \number\typcatcodesb ; % < >
-\stopruntimectxluacode
-
-\protect \endinput
diff --git a/tex/context/base/syst-cat.tex b/tex/context/base/syst-cat.tex
deleted file mode 100644
index c7fe7142f..000000000
--- a/tex/context/base/syst-cat.tex
+++ /dev/null
@@ -1,517 +0,0 @@
-%D \module
-%D [ file=syst-cat,
-%D version=2006.09.18,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Catcode Handling,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D A long standing wish has been the availability of catcode
-%D arrays. Because traditional \TEX\ does ot provide this we
-%D implement a fake method in the Mark II file.
-
-\ifx\zerocount\undefined \chardef \zerocount= 0 \fi
-\ifx\plusone \undefined \chardef \plusone = 1 \fi
-\ifx\minusone \undefined \newcount\minusone \minusone =-1 \fi
-
-\newif \ifrecatcodeuppercharacters % only used in good old tex
-
-% \newcount\cctdefcounter \cctdefcounter\plusone % 0 = signal
-\newcount\cctdefcounter \cctdefcounter\zerocount % 0 = signal, so advance before allocate
-
-\newcount\cctcountera
-\newcount\cctcounterb
-\newcount\cctcounterc
-
-\loadmarkfile{syst-cat}
-
-%D The next command can be defined in a cleaner way in the
-%D Mk IV file but we want to have a fast one with a minimal
-%D chance for interference.
-
-\chardef\activehackcode=`\~
-
-%D Once a catcode is assigned, the next assignments will happen faster.
-
-% (expandable) let
-
-\def\letcatcodecommand {\afterassignment\letcatcodecommanda\cctcountera}
-\def\letcatcodecommanda{\afterassignment\letcatcodecommandb\cctcounterb}
-
-\def\letcatcodecommandb % each time
- {\ifcsname CCL:\number\cctcountera:\number\cctcounterb\endcsname
- \csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
- \else
- \expandafter\letcatcodecommandc
- \fi}
-
-\def\letcatcodecommandc % only first time
- {\expandafter\gdef\csname CCL:\number\cctcountera:\number\cctcounterb\expandafter\endcsname\expandafter
- {\expandafter\let\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname}%
- \reinstatecatcodecommanda
- \csname CCL:\number\cctcountera:\number\cctcounterb\endcsname}
-
-% expandable def
-
-\def\defcatcodecommand {\afterassignment\defcatcodecommanda\cctcountera}
-\def\defcatcodecommanda{\afterassignment\defcatcodecommandb\cctcounterb}
-
-\def\defcatcodecommandb % each time
- {\ifcsname CCD:\number\cctcountera:\number\cctcounterb\endcsname
- \csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
- \else
- \expandafter\defcatcodecommandc
- \fi}
-
-\def\defcatcodecommandc % only first time
- {\expandafter\gdef\csname CCD:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
- \expandafter##\expandafter1\expandafter
- {\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
- \reinstatecatcodecommanda
- \csname CCD:\number\cctcountera:\number\cctcounterb\endcsname}
-
-% un expandable def (e.g. used for discretionaries)
-
-\def\uedcatcodecommand {\afterassignment\uedcatcodecommanda\cctcountera}
-\def\uedcatcodecommanda{\afterassignment\uedcatcodecommandb\cctcounterb}
-
-\def\uedcatcodecommandb % each time
- {\ifcsname CCU:\number\cctcountera:\number\cctcounterb\endcsname
- \csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
- \else
- \expandafter\uedcatcodecommandc
- \fi}
-
-\def\uedcatcodecommandc % only first time
- {\expandafter\gdef\csname CCU:\number\cctcountera:\number\cctcounterb\expandafter\endcsname
- \expandafter##\expandafter1\expandafter
- {\expandafter\unexpanded\expandafter\def\csname CCC:\number\cctcountera:\number\cctcounterb\endcsname{##1}}%
- \reinstatecatcodecommanda
- \csname CCU:\number\cctcountera:\number\cctcounterb\endcsname}
-
-\def\reinstatecatcodecommand{\afterassignment\reinstatecatcodecommanda\cctcounterb}
-
-\def\reinstatecatcodecommanda % can be used when a direct definition has been done
- {\bgroup % and the selector has been lost
- \uccode\activehackcode\cctcounterb
- \catcode\uccode\activehackcode13
- \uppercase{\xdef~{\noexpand\catcodecommand{\number\cctcounterb}}}%
- \egroup}
-
-\chardef\defaultcatcodetable\zerocount
-
-\def\catcodecommand#1%
- {\csname CCC:\number
- \ifcsname CCC:\number\currentcatcodetable:\number#1\endcsname
- \currentcatcodetable \else \defaultcatcodetable
- \fi
- :\number#1\endcsname}
-
-%D Here we define some catcode regimes:
-
-\ifx\nilcatcodes \undefined \newcatcodetable \nilcatcodes \fi
-\ifx\texcatcodes \undefined \newcatcodetable \texcatcodes \fi
-\ifx\ctxcatcodes \undefined \newcatcodetable \ctxcatcodes \fi
-\ifx\notcatcodes \undefined \newcatcodetable \notcatcodes \fi
-\ifx\vrbcatcodes \undefined \newcatcodetable \vrbcatcodes \fi
-\ifx\prtcatcodes \undefined \newcatcodetable \prtcatcodes \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 % < >
-
-% was redefined in core-job anyway: \catcode`\^^L = 13 % ascii form-feed
-
-\startcatcodetable \nilcatcodes
- \catcode`\^^I = 10 % ascii tab is a blank space
- \catcode`\^^M = 5 % ascii return is end-line
- \catcode`\^^L = 5 % ascii form-feed
- \catcode`\ = 10 % ascii space is blank space
- \catcode`\^^Z = 9 % ascii eof is ignored
-\stopcatcodetable
-
-\startcatcodetable \vrbcatcodes % probably less needed
- \catcode`\^^I = 12
- \catcode`\^^M = 12
- \catcode`\^^L = 12
- \catcode`\ = 12
- \catcode`\^^Z = 12
-\stopcatcodetable
-
-\startcatcodetable \typcatcodesa
- \catcode`\^^I = 12
- \catcode`\^^M = 12
- \catcode`\^^L = 12
- \catcode`\ = 12
- \catcode`\^^Z = 12
- \catcode`\{ = 1
- \catcode`\} = 2
-\stopcatcodetable
-
-\startcatcodetable \typcatcodesb
- \catcode`\^^I = 12
- \catcode`\^^M = 12
- \catcode`\^^L = 12
- \catcode`\ = 12
- \catcode`\^^Z = 12
- \catcode`\< = 1
- \catcode`\> = 2
-\stopcatcodetable
-
-\startcatcodetable \texcatcodes
- \catcode`\^^I = 10
- \catcode`\^^M = 5
- \catcode`\^^L = 5
- \catcode`\ = 10
- \catcode`\^^Z = 9
- \catcode`\\ = 0
- \catcode`\{ = 1
- \catcode`\} = 2
- \catcode`\$ = 3
- \catcode`\& = 4
- \catcode`\# = 6
- \catcode`\^ = 7
- \catcode`\_ = 8
- \catcode`\% = 14
-\stopcatcodetable
-
-\startcatcodetable \ctxcatcodes
- \catcode`\^^I = 10
- \catcode`\^^M = 5
-% \catcode`\^^J = 10 % new
- \catcode`\^^L = 5
- \catcode`\ = 10
- \catcode`\^^Z = 9
- \catcode`\\ = 0
- \catcode`\{ = 1
- \catcode`\} = 2
- \catcode`\$ = 3
- \catcode`\& = 4
- \catcode`\# = 6
- \catcode`\^ = 7
- \catcode`\_ = 8
- \catcode`\% = 14
- \catcode`\~ = 13
- \catcode`\| = 13
-\stopcatcodetable
-
-\startcatcodetable \notcatcodes
- \catcode`\^^I = 10 % ascii tab is a blank space
- \catcode`\^^M = 5 % ascii return is end-line
- \catcode`\^^L = 5 % ascii form-feed
- \catcode`\ = 10 % ascii space is blank space
- \catcode`\^^Z = 9 % ascii eof is ignored
- \catcode`\~ = 12
- \catcode`\# = 12 % probably too much, in principle
- \catcode`\$ = 12 % nilcatcodes would be ok too
- \catcode`\% = 12
- \catcode`\^ = 12
- \catcode`\& = 12
- \catcode`\_ = 12
- \catcode`\< = 12
- \catcode`\> = 12
- \catcode`\{ = 12
- \catcode`\} = 12
- \catcode`\" = 12
- \catcode`\' = 12
- \catcode`\/ = 12
- \catcode`\\ = 12
- \catcode`\| = 12
-\stopcatcodetable
-
-\startcatcodetable \mthcatcodes
- \catcode`\^^I = 10
- \catcode`\^^M = 5
- %\catcode`\^^J = 10 % new
- \catcode`\^^L = 5
- \catcode`\ = 10
- \catcode`\^^Z = 9
- \catcode`\\ = 0
- \catcode`\{ = 1
- \catcode`\} = 2
- \catcode`\$ = 3
- \catcode`\& = 4
- \catcode`\# = 6
- \catcode`\^ = 7
- \catcode`\_ = 8
- \catcode`\% = 14
- %\catcode`\~ = 13
- %\catcode`\| = 13
-\stopcatcodetable
-
-\startcatcodetable \prtcatcodes
- \catcode`\^^I = 10
- \catcode`\^^M = 5
- \catcode`\^^L = 5
- \catcode`\ = 10
- \catcode`\^^Z = 9
- \catcode`\\ = 0
- \catcode`\{ = 1
- \catcode`\} = 2
- \catcode`\$ = 3
- \catcode`\& = 4
- \catcode`\# = 6
- \catcode`\^ = 7
- \catcode`\_ = 8
- \catcode`\% = 14
- \catcode`\@ = 11
- \catcode`\! = 11
- \catcode`\? = 11
- \catcode`\~ = 13
- \catcode`\| = 13
-\stopcatcodetable
-
-\startcatcodetable \xmlcatcodesn
- \catcode`\^^I = 10 % ascii tab is a blank space
- \catcode`\^^M = 5 % ascii return is end-line
- \catcode`\^^L = 5 % ascii form-feed
- \catcode`\ = 10 % ascii space is blank space
- \catcode`\^^Z = 9 % ascii eof is ignored
- \catcode`\& = 13 % entity
- \catcode`\< = 13 % element
- \catcode`\> = 12
- \catcode`\" = 12 % probably not needed any more
- \catcode`\/ = 12 % probably not needed any more
- \catcode`\' = 12 % probably not needed any more
- \catcode`\~ = 12 % probably not needed any more
- \catcode`\# = 12 % probably not needed any more
- \catcode`\\ = 12 % probably not needed any more
-\stopcatcodetable
-
-\startcatcodetable \xmlcatcodese
- \catcode`\^^I = 10 % ascii tab is a blank space
- \catcode`\^^M = 5 % ascii return is end-line
- \catcode`\^^L = 5 % ascii form-feed
- \catcode`\ = 10 % ascii space is blank space
- \catcode`\^^Z = 9 % ascii eof is ignored
- \catcode`\& = 13 % entity
- \catcode`\< = 13 % element
- \catcode`\> = 12
- \catcode`\# = 13
- \catcode`\$ = 13
- \catcode`\% = 13
- \catcode`\\ = 13
- \catcode`\^ = 13
- \catcode`\_ = 13
- \catcode`\{ = 13
- \catcode`\} = 13
- \catcode`\| = 13
- \catcode`\~ = 13
-\stopcatcodetable
-
-\startcatcodetable \xmlcatcodesr
- \catcode`\^^I = 10 % ascii tab is a blank space
- \catcode`\^^M = 5 % ascii return is end-line
- \catcode`\^^L = 5 % ascii form-feed
- \catcode`\ = 10 % ascii space is blank space
- \catcode`\^^Z = 9 % ascii eof is ignored
- \catcode`\& = 13 % entity
- \catcode`\< = 13 % element
- \catcode`\> = 12
- \catcode`\# = 13
- \catcode`\$ = 13
- \catcode`\% = 13
- \catcode`\\ = 13
- \catcode`\^ = 13
- \catcode`\_ = 13
- \catcode`\{ = 13
- \catcode`\} = 13
- \catcode`\| = 13
- \catcode`\~ = 13
-\stopcatcodetable
-
-\letcatcodecommand \ctxcatcodes `\| \relax
-\letcatcodecommand \ctxcatcodes `\~ \relax
-
-%letcatcodecommand \prtcatcodes `\| \relax % falls back on ctx
-%letcatcodecommand \prtcatcodes `\~ \relax % falls back on ctx
-
-\letcatcodecommand \xmlcatcodesn `\& \relax
-\letcatcodecommand \xmlcatcodesn `\< \relax
-
-\letcatcodecommand \xmlcatcodese `\& \relax
-\letcatcodecommand \xmlcatcodese `\< \relax
-
-\letcatcodecommand \xmlcatcodesr `\& \relax
-\letcatcodecommand \xmlcatcodesr `\< \relax
-
-\letcatcodecommand \xmlcatcodese `\# \relax
-\letcatcodecommand \xmlcatcodese `\$ \relax
-\letcatcodecommand \xmlcatcodese `\% \relax
-\letcatcodecommand \xmlcatcodese `\\ \relax
-\letcatcodecommand \xmlcatcodese `\^ \relax
-\letcatcodecommand \xmlcatcodese `\_ \relax
-\letcatcodecommand \xmlcatcodese `\{ \relax
-\letcatcodecommand \xmlcatcodese `\} \relax
-\letcatcodecommand \xmlcatcodese `\| \relax
-\letcatcodecommand \xmlcatcodese `\~ \relax
-
-\letcatcodecommand \xmlcatcodesr `\# \relax
-\letcatcodecommand \xmlcatcodesr `\$ \relax
-\letcatcodecommand \xmlcatcodesr `\% \relax
-\letcatcodecommand \xmlcatcodesr `\\ \relax
-\letcatcodecommand \xmlcatcodesr `\^ \relax
-\letcatcodecommand \xmlcatcodesr `\_ \relax
-\letcatcodecommand \xmlcatcodesr `\{ \relax
-\letcatcodecommand \xmlcatcodesr `\} \relax
-\letcatcodecommand \xmlcatcodesr `\| \relax
-\letcatcodecommand \xmlcatcodesr `\~ \relax
-
- \catcodetable \ctxcatcodes
-\let\defaultcatcodetable\ctxcatcodes
-\let\xmlcatcodes \xmlcatcodesn
-
-%D \macros
-%D {restorecatcodes,
-%D beginrestorecatcodes,endrestorecatcodes}
-%D
-%D We're not finished dealing \CATCODES\ yet. In \CONTEXT\ we
-%D use only one auxiliary file, which deals with tables of
-%D contents, registers, two pass tracking, references etc. This
-%D file, as well as files concerning graphics, is processed when
-%D needed, which can be in the mid of typesetting verbatim.
-%D However, when reading in data in verbatim mode, we should
-%D temporary restore the normal \CATCODES, and that's exactly
-%D what the next macros do. Saving the catcodes can be
-%D disabled by saying \type{\localcatcodestrue}.
-
-\let\savedcatcodetable\relax
-
-\newcount\catcoderestorelevel
-
-\def\pushcatcodetable
- {\advance\catcoderestorelevel\plusone
- \tracepushcatcodetable
- \expandafter\mathchardef\csname scct:\number\catcoderestorelevel\endcsname\currentcatcodetable}
-
-% \def\popcatcodetable
-% {\expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
-% \tracepopcatcodetable
-% \advance\catcoderestorelevel\minusone}
-
-\def\popcatcodetable
- {\ifcase\catcoderestorelevel
- \immediate\write16{}%
- \immediate\write16{Fatal error: catcode push/pop mismatch. Fix this!}\wait\end
- \immediate\write16{}%
- \else
- \expandafter\catcodetable\csname scct:\number\catcoderestorelevel\endcsname
- \tracepopcatcodetable
- \advance\catcoderestorelevel\minusone
- \fi}
-
-\def\restorecatcodes % takes previous level
- {\ifnum\catcoderestorelevel>\plusone
- \expandafter\catcodetable\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname
- \fi}
-
-\newtoks\everycatcodetable
-
-\def\setcatcodetable#1%
- {\catcodetable#1%
- \the\everycatcodetable
- \tracesetcatcodetable}
-
-\def\dotracecatcodetable#1{\immediate\write16{[#1]}}
-
-\def\tracecatcodetables
- {\def\tracesetcatcodetable {\dotracecatcodetable{set \catcodetablename\space at \number\catcoderestorelevel}}%
- \def\tracepushcatcodetable{\dotracecatcodetable{push \catcodetablename\space from \catcodetableprev\space at \number\catcoderestorelevel}}%
- \def\tracepopcatcodetable {\dotracecatcodetable{pop \catcodetablename\space to \catcodetableprev\space at \number\catcoderestorelevel}}}
-
-\def\catcodetableprev
- {\ifnum\numexpr\catcoderestorelevel-1\relax>\zerocount
- \csname @@ccn:\number\csname scct:\number\numexpr\catcoderestorelevel-1\relax\endcsname\endcsname
- \else
- -%
- \fi}
-
-\def\catcodetablename
- {\ifnum\currentcatcodetable>\zerocount
- \csname @@ccn:\number\currentcatcodetable\endcsname
- \else
- -%
- \fi}
-
-\ifx\empty\undefined \def\empty{} \fi
-
-\let\tracesetcatcodetable \empty
-\let\tracepushcatcodetable\empty
-\let\tracepopcatcodetable \empty
-
-% \def\beginrestorecatcodes{\pushcatcodetable\catcodetable\ctxcatcodes}
-% \def\endrestorecatcodes {\popcatcodetable}
-
-\def\beginrestorecatcodes{\pushcatcodetable}
-\def\endrestorecatcodes {\popcatcodetable}
-
-\def\unprotect {\pushcatcodetable\setcatcodetable\prtcatcodes}
-\def\protect {\popcatcodetable}
-
-%D \macros
-%D {installactivecharacter}
-
-\def\installactivecharacter#1 %
- {\edef\temp{\detokenize{#1}}%
- \cctcounterc\expandafter`\temp\relax % relax needed
- \expandafter\startextendcatcodetable
- \expandafter\ctxcatcodes\expandafter\catcode\the\cctcounterc=13
- \stopextendcatcodetable
- \letcatcodecommand \ctxcatcodes \cctcounterc \temp \relax
- \ifnum\currentcatcodetable=\ctxcatcodes \setcatcodetable\ctxcatcodes \fi}
-
-%D \macros
-%D {defineactivecharacter}
-%D
-%D Use this one with care, esp in combination with catcode
-%D vectors. There are better ways now.
-
-\chardef\activehackcode=`~
-
-% \def\defineactivecharacter #1 #2%
-% {\cctcounterc\uccode\activehackcode
-% \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1}\empty`#1%
-% \catcode\uccode\activehackcode13
-% \uppercase{\def\next{~}}%
-% \uccode\activehackcode\cctcounterc
-% \expandafter\expandafter\expandafter\def\expandafter\next\expandafter
-% {\expandafter\dohandleactivecharacter\next{#2}}}
-%
-% \defineactivecharacter "0EFFF {oeps} \utfchar{0xEFFF}
-
-\def\defineactivecharacter #1#2 #3%
- {\cctcounterc\uccode\activehackcode
- \if#1"\uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty #1#2\else
- \uccode\activehackcode\expandafter\doifnumberelse\expandafter{\string#1#2}\empty`#1#2\fi
- \catcode\uccode\activehackcode13
- \uppercase{\def\next{~}}%
- \uccode\activehackcode\cctcounterc
- \expandafter\expandafter\expandafter\def\expandafter\next\expandafter
- {\expandafter\dohandleactivecharacter\next{#3}}}
-
-\chardef\activecharactermode\plusone % overloading still backward compatible
-
-\def\dodohandleactivecharacter#1#2{#2}
-\def\donthandleactivecharacter#1#2{\noexpand#1}
-
-\def\dohandleactivecharacter
- {\ifcase\activecharactermode
- \expandafter\donthandleactivecharacter
- \else
- \expandafter\dodohandleactivecharacter
- \fi}
-
-\def\makecharacteractive #1 {\catcode`#1\active}
-
-%D Handy for debugging:
-
-% \tracecatcodetables
-
-\endinput
diff --git a/tex/context/base/syst-con.lua b/tex/context/base/syst-con.lua
index 5e916575f..b2f6c42af 100644
--- a/tex/context/base/syst-con.lua
+++ b/tex/context/base/syst-con.lua
@@ -13,23 +13,13 @@ converters = converters or { }
the top of <l n='luatex'/>'s char range but outside the unicode range.</p>
--ldx]]--
-do
- local char, texsprint, format = unicode.utf8.char, tex.sprint, string.format
+local char, texsprint, format = unicode.utf8.char, tex.sprint, string.format
- function converters.hexstringtonumber(n) texsprint(tonumber(n,16)) end
- function converters.octstringtonumber(n) texsprint(tonumber(n, 8)) end
- function converters.rawcharacter (n) texsprint(char(0x110000+n)) end
-
- function converters.lchexnumber (n) texsprint(format("%x" ,n)) end
- function converters.uchexnumber (n) texsprint(format("%X" ,n)) end
- function converters.lchexnumbers (n) texsprint(format("%02x",n)) end
- function converters.uchexnumbers (n) texsprint(format("%02X",n)) end
- function converters.octnumber (n) texsprint(format("%03o",n)) end
-
- function converters.lchexnumber (n) texsprint(("%x" ):format(n)) end
- function converters.uchexnumber (n) texsprint(("%X" ):format(n)) end
- function converters.lchexnumbers (n) texsprint(("%02x"):format(n)) end
- function converters.uchexnumbers (n) texsprint(("%02X"):format(n)) end
- function converters.octnumber (n) texsprint(("%03o"):format(n)) end
-
-end
+function converters.hexstringtonumber(n) texsprint(tonumber(n,16)) end
+function converters.octstringtonumber(n) texsprint(tonumber(n, 8)) end
+function converters.rawcharacter (n) texsprint(char(0x110000+n)) end
+function converters.lchexnumber (n) texsprint(format("%x" ,n)) end
+function converters.uchexnumber (n) texsprint(format("%X" ,n)) end
+function converters.lchexnumbers (n) texsprint(format("%02x",n)) end
+function converters.uchexnumbers (n) texsprint(format("%02X",n)) end
+function converters.octnumber (n) texsprint(format("%03o",n)) end
diff --git a/tex/context/base/syst-con.mkii b/tex/context/base/syst-con.mkii
index d5d044f31..877aad32a 100644
--- a/tex/context/base/syst-con.mkii
+++ b/tex/context/base/syst-con.mkii
@@ -11,8 +11,43 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+\writestatus{loading}{ConTeXt System Macros / Conversions}
+
\unprotect
+%D When the number of conversions grew, it did no longer make
+%D sense to spread them over multiple files. So, instead of
+%D defining these in \type {font-ini}, we now have a dedicated
+%D module.
+
+\catcode127=12 % other, just to be sure
+
+%D \macros
+%D {lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
+%D
+%D In addition to the uppercase hex conversion, as needed in
+%D math families, we occasionally need a lowercase one, for
+%D instance when we want to compose gbsong fontnames.
+%D
+%D The ugly indirectness is needed to get rid of \TEX\
+%D induced spaces and \type {\relax}'s.
+%D
+%D \starttyping
+%D [\uchexnumber{0}]
+%D [\uchexnumber\scratchcounter]
+%D [\uchexnumber\zerocount]
+%D [\uchexnumber{\number0}]
+%D [\uchexnumber{\number\scratchcounter}]
+%D [\uchexnumber{\number\zerocount}]
+%D [\uchexnumber{\the\scratchcounter}]
+%D [\uchexnumber{\the\zerocount}]
+%D [\expandafter\uchexnumber\expandafter{\number0}]
+%D [\expandafter\uchexnumber\expandafter{\number\scratchcounter}]
+%D [\expandafter\uchexnumber\expandafter{\number\zerocount}]
+%D [\expandafter\uchexnumber\expandafter{\the\scratchcounter}]
+%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
+%D \stoptyping
+%D
%D These macros may look slow but are actually rather fast due to
%D the fact that \TEX\ handles conditional pretty fast. We need
%D a two step approach in order to stay relax clean in fully
@@ -64,6 +99,18 @@
E0\or E1\or E2\or E3\or E4\or E5\or E6\or E7\or E8\or E9\or EA\or EB\or EC\or ED\or EE\or EF\or
F0\or F1\or F2\or F3\or F4\or F5\or F6\or F7\or F8\or F9\or FA\or FB\or FC\or FD\or FE\or FF\fi}
+\def\lchexnumber #1{\@EA\dolchexnumber \number#1\relax}
+\def\uchexnumber #1{\@EA\douchexnumber \number#1\relax}
+\def\lchexnumbers#1{\@EA\dolchexnumbers\number#1\relax}
+\def\uchexnumbers#1{\@EA\douchexnumbers\number#1\relax}
+
+\let\hexnumber\uchexnumber
+
+%D \macros
+%D {octnumber}
+%D
+%D For unicode remapping purposes, we need octal numbers.
+
\def\dooctnumber#1\relax
{\ifcase#1
000\or 001\or 002\or 003\or 004\or 005\or 006\or 007\or
@@ -99,13 +146,55 @@
360\or 361\or 362\or 363\or 364\or 365\or 366\or 367\or
370\or 371\or 372\or 373\or 374\or 375\or 376\or 377\fi}
-\def\lchexnumber #1{\@EA\dolchexnumber \number#1\relax}
-\def\uchexnumber #1{\@EA\douchexnumber \number#1\relax}
-\def\lchexnumbers#1{\@EA\dolchexnumbers\number#1\relax}
-\def\uchexnumbers#1{\@EA\douchexnumbers\number#1\relax}
-\def\octnumber #1{\@EA\dooctnumber \number#1\relax}
-
-%D No beauty but ok:
+\def\octnumber#1{\@EA\dooctnumber\number#1\relax}
+
+%D \macros
+%D {twodigits, threedigits}
+%D
+%D These macros provides two or three digits always:
+
+\def\twodigits #1{\ifnum #1<10 0\fi\number#1}
+\def\threedigits#1{\ifnum#1<100 \ifnum#1<10 0\fi0\fi\number#1}
+
+%D \macros{modulonumber}
+%D
+%D In the conversion macros described in \type {core-con} we
+%D need a wrap||around method. The following solution is
+%D provided by Taco.
+%D
+%D The \type {modulonumber} macro expands to the mathematical
+%D modulo of a positive integer. It is crucial for it's
+%D application that this macro is fully exandable.
+%D
+%D The expression inside the \type {\numexpr} itself is
+%D somewhat bizarre because \ETEX\ uses a rounding
+%D division instead of truncation. If \ETEX's division
+%D would have behaved like \TEX's normal\type{\divide}, then
+%D the expression could have been somewhat simpler, like
+%D \type {#2-(#2/#1)*#1}. This works just as well, but a bit
+%D more complex.
+
+\def\modulonumber#1#2%
+ {\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+
+%D \macros{modulatednumber}
+%D
+%D Modulo numbers run from zero to one less than the limit,
+%D but for conversion sets, we need a value between 1 and the
+%D limit. The \type{\modulatednumber} arranges that. This
+%D macro also needs to be fully expandable, resulting in
+%D two \type{\numexpr}s.
+
+\def\modulatednumber#1#2%
+ {\ifnum\the\numexpr\modulonumber{#1}{#2}\relax=0 #1%
+ \else \the\numexpr\modulonumber{#1}{#2}\relax \fi}
+
+%D \macros
+%D {hexstringtonumber}
+%D
+%D This macro converts a two character hexadecimal number into
+%D a decimal number, thereby taking care of lowercase characters
+%D as well.
\dostepwiserecurse{0}{9}{1}{\setevalue{@@uc@@\recurselevel}{\recurselevel}}
@@ -122,10 +211,16 @@
\def\dohexstringtonumber#1#2% FF
{"\csname @@uc@@#1\endcsname\csname @@uc@@#2\endcsname}
+%D \macros
+%D {rawcharacter}
+%D
%D The next conversion macro produces raw characters. We have to
%D construct the macro in a special way to avoid problems with
%D characters with special meanings. So, we revert to the
%D lowercase conversion trick to bypass \TEX's input parser.
+%D
+%D This macro can be used to produce proper 8 bit characters
+%D that we sometimes need in backends and round||trips.
\bgroup
diff --git a/tex/context/base/syst-con.mkiv b/tex/context/base/syst-con.mkiv
index 2f84395f0..f7d4150a6 100644
--- a/tex/context/base/syst-con.mkiv
+++ b/tex/context/base/syst-con.mkiv
@@ -1,6 +1,6 @@
%D \module
%D [ file=syst-con,
-%D version=2006.09.16,
+%D version=2006.09.16, % real old stuff ... 2000.12.10
%D title=\CONTEXT\ System Macros,
%D subtitle=Conversions,
%D author=Hans Hagen,
@@ -15,13 +15,131 @@
\unprotect
-\def\lchexnumber #1{\ctxlua{converters.lchexnumber(\number#1)}}
-\def\uchexnumber #1{\ctxlua{converters.uchexnumber(\number#1)}}
-\def\lchexnumbers #1{\ctxlua{converters.lchexnumbers(\number#1)}}
-\def\uchexnumbers #1{\ctxlua{converters.uchexnumbers(\number#1)}}
-\def\octnumber #1{\ctxlua{converters.octnumber(\number#1)}}
+%D When the number of conversions grew, it did no longer make
+%D sense to spread them over multiple files. So, instead of
+%D defining these in \type {font-ini}, we now have a dedicated
+%D module.
+
+%D \macros
+%D {lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
+%D
+%D In addition to the uppercase hex conversion, as needed in
+%D math families, we occasionally need a lowercase one, for
+%D instance when we want to compose gbsong fontnames.
+%D
+%D The ugly indirectness is needed to get rid of \TEX\
+%D induced spaces and \type {\relax}'s.
+%D
+%D \starttyping
+%D [\uchexnumber{0}]
+%D [\uchexnumber\scratchcounter]
+%D [\uchexnumber\zerocount]
+%D [\uchexnumber{\number0}]
+%D [\uchexnumber{\number\scratchcounter}]
+%D [\uchexnumber{\number\zerocount}]
+%D [\uchexnumber{\the\scratchcounter}]
+%D [\uchexnumber{\the\zerocount}]
+%D [\expandafter\uchexnumber\expandafter{\number0}]
+%D [\expandafter\uchexnumber\expandafter{\number\scratchcounter}]
+%D [\expandafter\uchexnumber\expandafter{\number\zerocount}]
+%D [\expandafter\uchexnumber\expandafter{\the\scratchcounter}]
+%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
+%D \stoptyping
+
+\def\lchexnumber #1{\ctxlua{converters.lchexnumber(\number#1)}}
+\def\uchexnumber #1{\ctxlua{converters.uchexnumber(\number#1)}}
+\def\lchexnumbers#1{\ctxlua{converters.lchexnumbers(\number#1)}}
+\def\uchexnumbers#1{\ctxlua{converters.uchexnumbers(\number#1)}}
+
+\let\hexnumber\uchexnumber
+
+%D \macros
+%D {octnumber}
+%D
+%D For unicode remapping purposes, we need octal numbers.
+
+\def\octnumber#1{\ctxlua{converters.octnumber(\number#1)}}
+
+%D \macros
+%D {hexstringtonumber,octstringtonumber}
+%D
+%D This macro converts a two character hexadecimal number into
+%D a decimal number, thereby taking care of lowercase characters
+%D as well.
+
\def\hexstringtonumber#1{\ctxlua{converters.hexstringtonumber("#1")}}
\def\octstringtonumber#1{\ctxlua{converters.octstringtonumber("#1")}}
-\def\rawcharacter #1{\ctxlua{converters.rawcharacter(\number#1)}}
+
+%D \macros
+%D {rawcharacter}
+%D
+%D This macro can be used to produce proper 8 bit characters
+%D that we sometimes need in backends and round||trips.
+
+\def\rawcharacter#1{\ctxlua{converters.rawcharacter(\number#1)}}
+
+%D \macros
+%D {twodigits, threedigits}
+%D
+%D These macros provides two or three digits always:
+
+\def\twodigits #1{\ifnum #1<10 0\fi\number#1}
+\def\threedigits#1{\ifnum#1<100 \ifnum#1<10 0\fi0\fi\number#1}
+
+%D \macros{modulonumber}
+%D
+%D In the conversion macros described in \type {core-con} we
+%D need a wrap||around method. The following solution is
+%D provided by Taco.
+%D
+%D The \type {modulonumber} macro expands to the mathematical
+%D modulo of a positive integer. It is crucial for it's
+%D application that this macro is fully exandable.
+%D
+%D The expression inside the \type {\numexpr} itself is
+%D somewhat bizarre because \ETEX\ uses a rounding
+%D division instead of truncation. If \ETEX's division
+%D would have behaved like \TEX's normal\type{\divide}, then
+%D the expression could have been somewhat simpler, like
+%D \type {#2-(#2/#1)*#1}. This works just as well, but a bit
+%D more complex.
+
+\def\modulonumber#1#2%
+ {\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+
+%D \macros{modulatednumber}
+%D
+%D Modulo numbers run from zero to one less than the limit,
+%D but for conversion sets, we need a value between 1 and the
+%D limit. The \type{\modulatednumber} arranges that. This
+%D macro also needs to be fully expandable, resulting in
+%D two \type{\numexpr}s.
+
+\def\modulatednumber#1#2%
+ {\ifnum\the\numexpr\modulonumber{#1}{#2}\relax=0 #1%
+ \else \the\numexpr\modulonumber{#1}{#2}\relax \fi}
+
+%D \macros
+%D {realnumber} % used?
+
+\def\realnumber#1{\withoutpt\the\dimexpr#1\s!pt\relax} % brrr
+
+%D \macros
+%D {setcalculatedsin,setcalculatedcos,setcalculatedtan}
+%D
+%D This saves some 2K in the format. At some point we will redo the
+%D code that calls this. Beware: in \MKII\ this is a separate module.
+
+% \let\calculatesin\gobbleoneargument
+% \let\calculatecos\gobbleoneargument
+% \let\calculatetan\gobbleoneargument
+
+% \def\calculatedsin#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.sin(#1))}}
+% \def\calculatedcos#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.cos(#1))}}
+% \def\calculatedtan#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.tan(#1))}}
+
+\def\setcalculatedsin#1#2{\edef#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.sind(#2))}}}
+\def\setcalculatedcos#1#2{\edef#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.cosd(#2))}}}
+\def\setcalculatedtan#1#2{\edef#1{\ctxlua{tex.sprint(tex.ctxcatcodes,math.tand(#2))}}}
\protect \endinput
diff --git a/tex/context/base/syst-con.tex b/tex/context/base/syst-con.tex
deleted file mode 100644
index 653d68928..000000000
--- a/tex/context/base/syst-con.tex
+++ /dev/null
@@ -1,144 +0,0 @@
-%D \module
-%D [ file=syst-con,
-%D version=2000.12.10, % actually very old -)
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Conversions,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context System Macro's / Conversions}
-
-\unprotect
-
-%D When the number of conversions grew, it did no longer make
-%D sense to spread them over multiple files. So, instead of
-%D defining these in \type {font-ini}, we now have a dedicated
-%D module.
-
-\catcode127=12 % other, just to be sure
-
-%D \macros
-%D {lchexnumber,uchexnumber,lchexnumbers,uchexnumbers}
-%D
-%D In addition to the uppercase hex conversion, as needed in
-%D math families, we occasionally need a lowercase one, for
-%D instance when we want to compose gbsong fontnames.
-%D
-%D The ugly indirectness is needed to get rid of \TEX\
-%D induced spaces and \type {\relax}'s.
-%D
-%D \starttyping
-%D [\uchexnumber{0}]
-%D [\uchexnumber\scratchcounter]
-%D [\uchexnumber\zerocount]
-%D [\uchexnumber{\number0}]
-%D [\uchexnumber{\number\scratchcounter}]
-%D [\uchexnumber{\number\zerocount}]
-%D [\uchexnumber{\the\scratchcounter}]
-%D [\uchexnumber{\the\zerocount}]
-%D [\expandafter\uchexnumber\expandafter{\number0}]
-%D [\expandafter\uchexnumber\expandafter{\number\scratchcounter}]
-%D [\expandafter\uchexnumber\expandafter{\number\zerocount}]
-%D [\expandafter\uchexnumber\expandafter{\the\scratchcounter}]
-%D [\expandafter\uchexnumber\expandafter{\the\zerocount}]
-%D \stoptyping
-
-\let\lchexnumber \gobbleoneargument
-\let\uchexnumber \gobbleoneargument
-\let\lchexnumbers\gobbleoneargument
-\let\uchexnumbers\gobbleoneargument
-
-%D \macros
-%D {octnumber}
-%D
-%D For unicode remapping purposes, we need octal numbers.
-
-\let\octnumber\gobbleoneargument
-
-%D \macros
-%D {hexstringtonumber}
-%D
-%D This macro converts a two character hexadecimal number into
-%D a decimal number, thereby taking care of lowercase characters
-%D as well.
-
-\let\hexstringtonumber\gobbleoneargument
-
-%D \macros
-%D {rawcharacter}
-%D
-%D This macro can be used to produce proper 8 bit characters
-%D that we sometimes need in backends and round||trips.
-
-\let\rawcharacter\gobbleoneargument
-
-%D \macros
-%D {twodigits, threedigits}
-%D
-%D These macros provides two or three digits always:
-
-\def\twodigits #1{\ifnum #1<10 0\fi\number#1}
-\def\threedigits#1{\ifnum#1<100 \ifnum#1<10 0\fi0\fi\number#1}
-
-%D \macros{modulonumber}
-%D
-%D In the conversion macros described in \type {core-con} we
-%D need a wrap||around method. The following solution is
-%D provided by Taco.
-%D
-%D The \type {modulonumber} macro expands to the mathematical
-%D modulo of a positive integer. It is crucial for it's
-%D application that this macro is fully exandable.
-%D
-%D The expression inside the \type {\numexpr} itself is
-%D somewhat bizarre because \ETEX\ uses a rounding
-%D division instead of truncation. If \ETEX's division
-%D would have behaved like \TEX's normal\type{\divide}, then
-%D the expression could have been somewhat simpler, like
-%D \type {#2-(#2/#1)*#1}. This works just as well, but a bit
-%D more complex.
-
-\beginETEX
-
-\def\modulonumber#1#2%
- {\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
-
-\endETEX
-
-%D \macros{modulatednumber}
-%D
-%D Modulo numbers run from zero to one less than the limit,
-%D but for conversion sets, we need a value between 1 and the
-%D limit. The \type{\modulatednumber} arranges that. This
-%D macro also needs to be fully expandable, resulting in
-%D two \type{\numexpr}s.
-
-\beginETEX
-
-\def\modulatednumber#1#2%
- {\ifnum\the\numexpr\modulonumber{#1}{#2}\relax=0 #1%
- \else \the\numexpr\modulonumber{#1}{#2}\relax \fi}
-
-\endETEX
-
-%D When not running \ETEX\ you're left with the maximum:
-
-\beginTEX
-
-\def\modulatednumber#1#2%
- {\ifnum#2>#1 #1\else#2\fi}
-
-\endTEX
-
-%D Plugins
-
-\loadmarkfile{syst-con}
-
-\let\hexnumber\uchexnumber
-
-\protect \endinput
diff --git a/tex/context/base/syst-etx.tex b/tex/context/base/syst-etx.tex
deleted file mode 100644
index 6ccfa25e0..000000000
--- a/tex/context/base/syst-etx.tex
+++ /dev/null
@@ -1,298 +0,0 @@
-%D \module
-%D [ file=syst-etx,
-%D version=1999.03.17, % some time ...
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Efficient \PLAIN\ \TEX\ loading,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module prepares \CONTEXT\ for \ETEX. We don't use
-%D the definition files that come with this useful \TEX\
-%D extension, but implement our own alternatives.
-
-%D \CONTEXT\ was one of the first systems that had support for \ETEX\
-%D built in. In the process we found out that the extensions were not
-%D as bug free as the rest of \TEX. Especially the bugs in \type
-%D {lastnode}, flushing of token lists with an index in the extension
-%D range, and spurious box behaviour of boxes adressed in the extended
-%D box space made us a bit careful. It's hard to to track down such
-%D bugs, especially if one has a mind set of \TEX\ being bug free. If
-%D you encounter unexpected behaviour let me know. Currently the
-%D scantokens mechanism can handle only one||liners, but Taco will
-%D provide an alternative some day.
-%D
-%D \starttyping
-%D \bgroup
-%D \lccode`a=12\lowercase{\xdef\whatever{a}}\egroup
-%D \def\whatever{test \whatever test}
-%D \scantokens\expandafter{\whatever}
-%D \egroup
-%D \stoptyping
-
-\unprotect
-
-%D \ETEX\ has a not so handy way of telling you the version number,
-%D i.e. the revision number has a period in it:
-
-\long\def\gobbleoneargument#1{}
-
-\beginETEX
- \mathchardef\etexversion=\numexpr\eTeXversion*100+\expandafter\gobbleoneargument\eTeXrevision\relax
-\endETEX
-
-\beginTEX
- \mathchardef\etexversion=0
-\endTEX
-
-%D Constants to be used with \type {\grouptype}.
-
-\chardef\@@bottomlevelgroup = 0
-\chardef\@@simplegroup = 1
-\chardef\@@hboxgroup = 2
-\chardef\@@adjustedhboxgroup = 3
-\chardef\@@vboxgroup = 4
-\chardef\@@vtopgroup = 5
-\chardef\@@aligngroup = 6
-\chardef\@@noaligngroup = 7
-\chardef\@@outputgroup = 8
-\chardef\@@mathgroup = 9
-\chardef\@@discretionarygroup = 10
-\chardef\@@insertgroup = 11
-\chardef\@@vcentergroup = 12
-\chardef\@@mathchoicegroup = 13
-\chardef\@@semisimplegroup = 14
-\chardef\@@mathshiftgroup = 15
-\chardef\@@mathleftgroup = 16
-
-\chardef\@@vadjustgroup = \@@insertgroup
-
-%D Constants to be used with \type {\interactionmode}.
-
-\chardef\@@batchmode = 0
-\chardef\@@nonstopmode = 1
-\chardef\@@scrollmode = 2
-\chardef\@@errorstopmode = 3
-
-%D Constants to be used with \type {\lastnodetype}.
-
-\chardef\@@charnode = 0
-\chardef\@@hlistnode = 1
-\chardef\@@vlistnode = 2
-\chardef\@@rulenode = 3
-\chardef\@@insertnode = 4
-\chardef\@@marknode = 5
-\chardef\@@adjustnode = 6
-\chardef\@@ligaturenode = 7
-\chardef\@@discretionarynode = 8
-\chardef\@@whatsitnode = 9
-\chardef\@@mathnode = 10
-\chardef\@@gluenode = 11
-\chardef\@@kernnode = 12
-\chardef\@@penaltynode = 13
-\chardef\@@unsetnode = 14
-\chardef\@@mathsnode = 15
-
-%D Constants to be used with \type {\iftype}.
-
-\chardef\@@charif = 1
-\chardef\@@catif = 2
-\chardef\@@numif = 3
-\chardef\@@dimif = 4
-\chardef\@@oddif = 5
-\chardef\@@vmodeif = 6
-\chardef\@@hmodeif = 7
-\chardef\@@mmodeif = 8
-\chardef\@@innerif = 9
-\chardef\@@voidif = 10
-\chardef\@@hboxif = 11
-\chardef\@@vboxif = 12
-\chardef\@@xif = 13
-\chardef\@@eofif = 14
-\chardef\@@trueif = 15
-\chardef\@@falseif = 16
-\chardef\@@caseif = 17
-\chardef\@@definedif = 18
-\chardef\@@csnameif = 19
-\chardef\@@fontcharif = 20
-
-%D Just in case we are not using \ETEX, we define some out of
-%D range constants.
-
-\beginTEX
-
-\chardef\grouptype = 255
-\chardef\interactionmode = 255
-\chardef\nodetype = 255
-\chardef\iftype = 255
-
-\endTEX
-
-%D Of course we want even bigger log files, so we copied this
-%D from the \ETEX\ source files.
-
-\beginETEX \tracing...
-
-\def\tracingall
- {\tracingonline \@ne
- \tracingcommands \thr@@
- \tracingstats \tw@
- \tracingpages \@ne
- \tracingoutput \@ne
- \tracinglostchars \tw@
- \tracingmacros \tw@
- \tracingparagraphs\@ne
- \tracingrestores \@ne
- \showboxbreadth \maxdimen
- \showboxdepth \maxdimen
- \tracinggroups \@ne
- \tracingifs \@ne
- \tracingscantokens\@ne
- \tracingnesting \@ne
- \tracingassigns \tw@
- \errorstopmode}
-
-\def\loggingall
- {\tracingall
- \tracingonline \z@}
-
-\def\tracingnone
- {\tracingassigns \z@
- \tracingnesting \z@
- \tracingscantokens\z@
- \tracingifs \z@
- \tracinggroups \z@
- \showboxdepth \thr@@
- \showboxbreadth 5
- \tracingrestores \z@
- \tracingparagraphs\z@
- \tracingmacros \z@
- \tracinglostchars \@ne
- \tracingoutput \z@
- \tracingpages \z@
- \tracingstats \z@
- \tracingcommands \z@
- \tracingonline \z@ }
-
-\endETEX
-
-%D Just to be sure:
-
-\ifx\eTeX\undefined
-
- \def\eTeX{$\varepsilon$-\TeX}
-
-\fi
-
-%D In \ETEX\ we have lots of registers, so we redefine a few
-%D low level macros. We reserve some extra space for inserts
-%D and as soon as we near the end of the first register
-%D memory bank (often some 10 less than 255), we switch to the
-%D slower range \type {\@@medallocation}||\type {\@@maxallocation}.
-
-\beginETEX \new...
-
-%D First we redefine the plain \TEX\ register allocation macros.
-
-\def\newcount {\myalloc@0\count \countdef \@@maxallocation}
-\def\newdimen {\myalloc@1\dimen \dimendef \@@maxallocation}
-\def\newskip {\myalloc@2\skip \skipdef \@@maxallocation}
-\def\newmuskip {\myalloc@3\muskip \muskipdef \@@maxallocation}
-\def\newbox {\myalloc@4\box \mathchardef\@@maxallocation}
-\def\newtoks {\myalloc@5\toks \toksdef \@@maxallocation}
-\def\newread {\myalloc@6\read \chardef \@@minallocation}
-\def\newwrite {\myalloc@7\write \chardef \@@minallocation}
-\def\newmarks {\myalloc@8\marks \mathchardef\@@maxallocation}
-\def\newlanguage{\myalloc@9\language\chardef \@@minallocation}
-
-\def\topofboxstack{\number\count24 }
-
-%D Since in \CONTEXT\ we only have one math family left we
-%D redefine \type {\newfam}.
-
-\def\newfam#1{\chardef#1=15 }
-
-%D Therefore we should reset the related counter.
-
-\count18=1
-
-%D We use some constants in the tests.
-
-\mathchardef\@@minallocation = 16
-\mathchardef\@@medallocation = 256
-\mathchardef\@@maxallocation = 32767
-
-%D I cannot imagine that more than~8 extra insert classes
-%D are needed, but, for critical editions, we may need many
-%D more, so:
-
-\chardef\@@insallocation = 32
-
-%D However, there's a bug in \ETEX\ versions smaller than 2.2,
-%D so we need to play safe:
-
-\ifnum\etexversion<202 \chardef\@@insallocation=8 \fi
-
-%D My low level allocation macro now comes down to:
-
-\def\myalloc@#1#2#3#4#5%
- {\global\advance\count1#1by\@ne
- \ifnum\count1#1>\@@medallocation \else
- \ifnum\count1#1<\numexpr\@@medallocation-\@@insallocation\relax\else
- \global\count1#1=\numexpr\@@medallocation+\@ne\relax % \wait
- \fi
- \fi
- \ifnum\count1#1>#4%
- \global\count1#1=#4%
- \errmessage{No room for (\string#2) \string#5}%
- \fi
- \allocationnumber=\count1#1%
- \global#3#5=\allocationnumber
- \wlog{\string#5=\string#2\the\allocationnumber}}
-
-\def\newinsert#1%
- {\ifnum\insc@unt>\numexpr\@@medallocation-\@@insallocation\relax
- \global\advance\insc@unt by\m@ne
- \allocationnumber=\insc@unt
- \global\chardef#1=\allocationnumber
- \wlog{\string#1=\string\insert\the\allocationnumber}%
- \else
- \errmessage{No room for a new insert \string#1 (\number\insc@unt)}%
- \fi}
-
-\endETEX
-
-%D These macros can be checked by tests like:
-%D
-%D \starttyping
-%D \let\wlog\message \dorecurse{1000}{\newcount\dummy}
-%D \stoptyping
-
-%D A few bonus bindings.
-
-\ifx\normalprotected \undefined \let\normalprotected \protected \fi
-\ifx\normalunexpanded\undefined \let\normalunexpanded\unexpanded \fi
-\ifx\normalexpanded \undefined \let\normalexpanded \expanded \fi
-
-%D \macros
-%D {begcsname}
-%D
-%D Handy for \ETEX-only usage:
-
-\beginETEX \ifcsname
-
- \def\begcsname#1\endcsname{\ifcsname#1\endcsname\csname#1\endcsname\fi}
-
-\endETEX
-
-\beginTEX
-
- \def\begcsname#1\endcsname{\csname#1\endcsname}
-
-\endTEX
-
-\protect \endinput
diff --git a/tex/context/base/syst-ext.tex b/tex/context/base/syst-ext.tex
index 5d3afce3a..bd1c02050 100644
--- a/tex/context/base/syst-ext.tex
+++ b/tex/context/base/syst-ext.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context System Macro's / Extras}
+\writestatus{loading}{ConTeXt System Macros / Extras}
%D In this second system module, we continue the definition of
%D some handy commands.
@@ -110,8 +110,8 @@
%D are needed:
\def\newif#1%
- {\count@\escapechar
- \escapechar\m@ne
+ {\scratchcounter\escapechar
+ \escapechar\minusone
\expandafter\expandafter\expandafter
\redoglobal\expandafter\expandafter\expandafter
\edef\@if#1{true}{\let\noexpand#1\noexpand\iftrue}%
@@ -119,7 +119,7 @@
\redoglobal\expandafter\expandafter\expandafter
\edef\@if#1{false}{\let\noexpand#1\noexpand\iffalse}%
\dodoglobal\@if#1{false}%
- \escapechar\count@}
+ \escapechar\scratchcounter}
%D Also new:
@@ -437,7 +437,7 @@
%D Slower but better:
\ifx\letterbackslash\undefined
- {\catcode`.=0 .catcode`.\ 12 .xdef.letterbackslash{.string\}} % hack
+ {\catcode`.=0 .catcode`.\ 12 .xdef.letterbackslash{.string\}} % hack
\fi
\def\strippedcsname#1% this permits \strippedcsname{\xxx} and \strippedcsname{xxx}
@@ -1013,6 +1013,27 @@
\let\endofloop\dodoloop
\dodoloop1} % no \plusone else \recurselevel wrong
+%D For special purposes:
+
+\newcount\fastrecursecounter
+\newcount\lastrecursecounter
+\newcount\steprecursecounter
+
+\def\dofastrecurse#1#2#3#4%
+ {\def\fastrecursebody{#4}%
+ \fastrecursecounter#1\relax
+ \lastrecursecounter#2\relax
+ \steprecursecounter#3\relax
+ \def\recurselevel{\number\fastrecursecounter}%
+ \dodofastrecurse}
+
+\def\dodofastrecurse
+ {\ifnum\fastrecursecounter>\lastrecursecounter\else
+ \fastrecursebody
+ \advance\fastrecursecounter\steprecursecounter
+ \expandafter\dodofastrecurse
+ \fi}
+
%D This alternative looks a bit different and uses a
%D pseudo counter. When this macro is nested, we have to use
%D different counters. This time we use keywords.
@@ -1073,6 +1094,7 @@
%D \def\EveryLine%
%D {\afterassignment\doEveryLine\scratchtoks}
%D \stoptyping
+%D
%D The real implementation is a bit more complicated but we
%D prefer something more versatile.
@@ -1471,7 +1493,7 @@
\def\ExpandFirstAfter#1%
{\let\ExpandCommand#1%
- \doifnextcharelse[\complexExpandFirstAfter\simpleExpandFirstAfter}
+ \doifnextoptionalelse\complexExpandFirstAfter\simpleExpandFirstAfter}
\def\ExpandSecondAfter#1#2#3%
{\scratchtoks{#2}%
@@ -1832,12 +1854,10 @@
% compatible ?
\long\unexpanded\def\groupedcommand#1#2%
- {\doifnextcharelse\bgroup
- {\HandleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
+ {\doifnextbgroupelse{\HandleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
\long\unexpanded\def\simplegroupedcommand#1#2%
- {\doifnextcharelse\bgroup
- {\HandleSimpleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
+ {\doifnextbgroupelse{\HandleSimpleGroup{#1}{#2}}{\HandleNoGroup{#1}{#2}}}
%D Users should be aware of the fact that grouping can
%D interfere with ones paragraph settings that are executed
@@ -2069,7 +2089,7 @@
%D \def\dowithpargument#1%
%D {\def\nextpar##1 \par{#1{##1}}%
%D \def\nextarg##1{#1{##1}}%
-%D \doifnextcharelse{\bgroup}
+%D \doifnextcharelse\bgroup
%D {\nextarg}
%D {\nextpar}}
%D \stoptyping
@@ -2081,7 +2101,7 @@
%\def\dowithpargument#1%
% {\def\nextpar##1 \par{#1{##1}}%
% \def\nextarg##1{#1{##1}}%
-% \doifnextcharelse{\bgroup}
+% \doifnextcharelse\bgroup
% {\nextarg}
% {\doifnextcharelse{\par}
% {#1{}}
@@ -2090,7 +2110,7 @@
\def\dowithpargument#1%
{\def\nextpar##1 \par{#1{##1}}%
\def\nextarg##1{#1{##1}}%
- \doifnextcharelse\bgroup\nextarg{\doifnextcharelse\par{#1{}}\nextpar}}
+ \doifnextbgroupelse\nextarg{\doifnextcharelse\par{#1{}}\nextpar}}
%D The \type{p} in the previous command stands for paragraph.
%D When we want to act upon words we can use the \type{w}
@@ -2133,14 +2153,14 @@
%\def\dowithwargument#1%
% {\def\nextwar##1 {#1{##1}}%
% \def\nextarg##1{#1{##1}}%
-% \doifnextcharelse{\bgroup}
+% \doifnextcharelse\bgroup
% {\nextarg}
% {\nextwar}}
\def\dowithwargument#1%
{\def\nextwar##1 {#1{##1}}%
\def\nextarg##1{#1{##1}}%
- \doifnextcharelse\bgroup\nextarg\nextwar}
+ \doifnextbgroupelse\nextarg\nextwar}
%D \macros
%D {dorepeat,dorepeatwithcommand}
@@ -2368,6 +2388,8 @@
% A slightly (but in the case of large arguments
% significantly) faster alternative is given below:
+\newtoks\@@toks
+
\def\dodoappendtoks
{\dodoglobal\@@toks\@EAEAEA{\@EA\the\@EA\@@toks\the\@@scratchtoks}}
@@ -3016,8 +3038,7 @@
\expandafter\globalprocesscommaitem#1,],}
%D \macros
-%D {withoutunit,withoutpt,
-%D PtToCm,
+%D {withoutpt,PtToCm,
%D numberofpoints,dimensiontocount}
%D
%D We can convert point into centimeters with:
@@ -3025,24 +3046,6 @@
%D \starttyping
%D \PtToCm{dimension}
%D \stoptyping
-%D
-%D Splitting the value and the unit is done by:
-
-\def\withoutunit#1#2%
- {\begingroup
- \scratchdimen#1\relax
- \@EA\convertargument\the\scratchdimen\to\asciia
- \@EA\convertargument#2\to\asciib
- %\@EA\@EA\@EA\beforesplitstring\@EA\asciia\@EA\at\asciib\to\!!stringa
- \@EA\beforesplitstring\@EA\asciia\@EA\at\asciib\to\!!stringa
- \!!stringa
- \endgroup}
-
-\def\withoutpt#1{\withoutunit{#1}{pt}}
-\def\withoutcm#1{\withoutunit{#1}{cm}}
-
-%D A bit faster and more robust alternative is one that
-%D manipulates the \CATCODES.
{\catcode`\.=\@@other
\catcode`\p=\@@other
@@ -3076,18 +3079,11 @@
%D
%D Both macros return a rounded number.
-% todo: etex version
+% \dimensiontocount{10.49pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.49pt}
+% \dimensiontocount{10.51pt}\scratchcounter \the\scratchcounter / \numberofpoints{10.51pt}
-\def\numberofpoints#1%
- {\scratchdimen#1%
- \advance\scratchdimen .5pt
- \withoutpt\the\scratchdimen}
-
-\def\dimensiontocount#1#2%
- {\scratchdimen#1%
- \advance\scratchdimen .5pt
- #2\scratchdimen
- \divide#2 \maxcard}
+\def\dimensiontocount#1#2{#2\numexpr\dimexpr#1\relax/\maxcard\relax}
+\def\numberofpoints #1{\the\numexpr\dimexpr#1\relax/\maxcard\relax}
%D \macros
%D {swapdimens,swapmacros}
@@ -3946,7 +3942,7 @@
% %D handle the special case.
%
% \def\dohonorgroupedargument#1[%
-% {\doifnextcharelse\bgroup{\dodohonorgroupedargument#1}{#1[}}
+% {\doifnextbgroupelse{\dodohonorgroupedargument#1}{#1[}}
%
% \def\dodohonorgroupedargument#1#2%
% {#1[{{#2}}}
@@ -4470,24 +4466,43 @@
\beginTEX
- \let\integerrounding \firstofoneargument
- \let\onedigitrounding\firstofoneargument
- \let\twodigitrounding\firstofoneargument
+ \let\integerrounding \firstofoneargument
+ \let\onedigitrounding \firstofoneargument
+ \let\twodigitrounding \firstofoneargument
+ \let\threedigitrounding\firstofoneargument
\endTEX
\beginETEX \dimexpr
- \def\dointegerrounding #1.#2\relax {#1}
- \def\doonedigitrounding#1.#2#3\relax {\ifx#2*#1\else#1.#2\fi}
- \def\dotwodigitrounding#1.#2#3#4\relax{\ifx#2*#1\else#1.#2#3\fi}
+ \def\dointegerrounding #1.#2\relax {#1}
+ \def\doonedigitrounding #1.#2#3\relax {\ifx#2*#1\else#1.#2\fi}
+ \def\dotwodigitrounding #1.#2#3#4\relax {\ifx#2*#1\else#1.#2#3\fi}
+ \def\dothreedigitrounding#1.#2#3#4#5\relax{\ifx#2*#1\else#1.#2#3#4\fi}
\def\integerrounding#1%
- {\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.5\points\relax.\relax}
+ {\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.5\points \relax .\relax}
\def\onedigitrounding#1%
- {\@EA\@EA\@EA\doonedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.05\points\relax00.*0\relax}
+ {\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.05\points \relax 00.*0\relax}
\def\twodigitrounding#1%
- {\@EA\@EA\@EA\dotwodigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.005\points\relax000.*00\relax}
+ {\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr#1\points+.005\points \relax 000.*00\relax}
+ \def\threedigitrounding#1%
+ {\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax0000.*00\relax}
+
+% \def\dointegerrounding #1.#2\relax {#1}
+% \def\doonedigitrounding #1.#2#3\relax {#1.#2}
+% \def\dotwodigitrounding #1.#2#3#4\relax {#1.#2#3}
+% \def\dothreedigitrounding#1.#2#3#4#5\relax{#1.#2#3#4}
+
+% \def\integerrounding #1{\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.5\points\relax \relax}
+% \def\onedigitrounding #1{\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.05\points\relax 0\relax}
+% \def\twodigitrounding #1{\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr #1\points+.005\points\relax 00\relax}
+% \def\threedigitrounding#1{\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1\points+.0005\points\relax000\relax}
+
+% \def\integerroundeddimen #1{\@EA\@EA\@EA\dointegerrounding \@EA\WITHOUTPT\the\dimexpr #1+.5\points\relax \relax}
+% \def\onedigitroundeddimen #1{\@EA\@EA\@EA\doonedigitrounding \@EA\WITHOUTPT\the\dimexpr #1+.05\points\relax 0\relax}
+% \def\twodigitroundeddimen #1{\@EA\@EA\@EA\dotwodigitrounding \@EA\WITHOUTPT\the\dimexpr #1+.005\points\relax 00\relax}
+% \def\threedigitroundeddimen#1{\@EA\@EA\@EA\dothreedigitrounding\@EA\WITHOUTPT\the\dimexpr#1+.0005\points\relax000\relax}
\endETEX
@@ -4642,44 +4657,6 @@
{\comparedresult\plusone}}
%D \macros
-%D {@saveprimitive}
-%D
-%D The next definition originates in the \type {amsgen} package. In
-%D case some preceding package redefined a primitive that we also
-%D want to redefine, we had better do some checking to make sure
-%D that we are able to save the primitive meaning for internal use.
-%D Primitive control sequences can be distinguished by the fact that
-%D \type {\string} and \type {\meaning} return the same information.
-
-\def\@saveprimitive#1#2%
- {\begingroup
- \edef\@tempa{\string#1}%
- \edef\@tempb{\meaning#1}%
- \ifx\@tempa\@tempb
- \global\let#2#1%
- %\debuggerinfo{prim}{Saving \string#1 as \string#2}%
- \else
- \edef\@tempb{\meaning#2}%
- %\ifx\@tempa\@tempb
- % \debuggerinfo{prim}{Saving \string#1 as \string#2}%
- %\else
- % \debuggerinfo{prim}{Can't define \string#2 properly;
- % primitive \noexpand#1 is no longer primitive}%
- %\fi
- \fi
- \endgroup}
-
-\def\saveprimitive#1%
- {\begingroup
- \@EA\edef\@EA\@tempa\@EA{\@EA\gobbleoneargument\string#1}%
- \@EA\let\csname normal\@tempa\endcsname\relax
- \@EA\@saveprimitive\@EA#1\csname normal\@tempa\endcsname
- \endgroup }
-
-%D In this macro, the message only shows up when the debugging
-%D is turned on.
-
-%D \macros
%D {@True, @False, @Not, @And}
%D
%D Some predicate logic functions, used in for instance the
diff --git a/tex/context/base/syst-fnt.mkii b/tex/context/base/syst-fnt.mkii
new file mode 100644
index 000000000..66439c194
--- /dev/null
+++ b/tex/context/base/syst-fnt.mkii
@@ -0,0 +1,46 @@
+%D \module
+%D [ file=syst-fnt,
+%D version=2006.08.11,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Font Things,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% formal names cf the tb \& tbt
+
+\unprotect
+
+\def\fontslantperpoint {\fontdimen\plusone }
+\def\fontinterwordspace {\fontdimen\plustwo }
+\def\fontinterwordstretch{\fontdimen\plusthree}
+\def\fontinterwordshrink {\fontdimen\plusfour }
+\def\fontexheight {\fontdimen\plusfive }
+\def\fontemwidth {\fontdimen\plussix }
+\def\fontextraspace {\fontdimen\plusseven}
+
+\def\slantperpoint {\fontdimen\plusone \font}
+\def\interwordspace {\fontdimen\plustwo \font}
+\def\interwordstretch {\fontdimen\plusthree\font}
+\def\interwordshrink {\fontdimen\plusfour \font}
+\def\exheight {\fontdimen\plusfive \font}
+\def\emwidth {\fontdimen\plussix \font}
+\def\extraspace {\fontdimen\plusseven\font}
+
+\def\mathsupdisplay {\fontdimen13 }
+\def\mathsupnormal {\fontdimen14 }
+\def\mathsupcramped {\fontdimen15 }
+\def\mathsubnormal {\fontdimen16 }
+\def\mathsubcombined {\fontdimen17 }
+\def\mathaxisheight {\fontdimen22 }
+
+\def\currentspaceskip {\interwordspace\!!plus\interwordstretch\!!minus\interwordshrink\relax}
+
+\def\mathstacktotal {\dimexpr\fontdimen10\scriptfont\plustwo+\fontdimen12\scriptfont\plustwo\relax}
+\def\mathstackvgap {\plusthree\fontdimen8\scriptfont\plusthree}
+
+\protect \endinput
diff --git a/tex/context/base/syst-fnt.mkiv b/tex/context/base/syst-fnt.mkiv
new file mode 100644
index 000000000..8ba0dd2a3
--- /dev/null
+++ b/tex/context/base/syst-fnt.mkiv
@@ -0,0 +1,46 @@
+%D \module
+%D [ file=syst-fnt,
+%D version=2006.08.11,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Font Things,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% formal names cf the tb \& tbt
+
+\unprotect
+
+\def\fontslantperpoint {\fontdimen\plusone }
+\def\fontinterwordspace {\fontdimen\plustwo }
+\def\fontinterwordstretch{\fontdimen\plusthree}
+\def\fontinterwordshrink {\fontdimen\plusfour }
+\def\fontexheight {\fontdimen\plusfive }
+\def\fontemwidth {\fontdimen\plussix }
+\def\fontextraspace {\fontdimen\plusseven}
+
+\def\slantperpoint {\fontdimen\plusone \font}
+\def\interwordspace {\fontdimen\plustwo \font}
+\def\interwordstretch {\fontdimen\plusthree\font}
+\def\interwordshrink {\fontdimen\plusfour \font}
+\def\exheight {\fontdimen\plusfive \font}
+\def\emwidth {\fontdimen\plussix \font}
+\def\extraspace {\fontdimen\plusseven\font}
+
+\def\mathsupdisplay {\fontdimen13 } % to be remapped
+\def\mathsupnormal {\fontdimen14 } % to be remapped
+\def\mathsupcramped {\fontdimen15 } % to be remapped
+\def\mathsubnormal {\fontdimen16 } % to be remapped
+\def\mathsubcombined {\fontdimen17 } % to be remapped
+\def\mathaxisheight {\fontdimen22 } % to be remapped
+
+\def\currentspaceskip {\interwordspace\!!plus\interwordstretch\!!minus\interwordshrink\relax}
+
+\def\mathstacktotal {\dimexpr\Umathstacknumup\scriptstyle+\Umathstackdenomdown\scriptstyle\relax}
+\def\mathstackvgap {\Umathstackvgap\scriptstyle}
+
+\protect \endinput
diff --git a/tex/context/base/syst-fnt.tex b/tex/context/base/syst-fnt.tex
deleted file mode 100644
index 7ffc6464e..000000000
--- a/tex/context/base/syst-fnt.tex
+++ /dev/null
@@ -1,43 +0,0 @@
-%D \module
-%D [ file=syst-fnt,
-%D version=2006.08.11,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Font Things,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-% formal names cf the tb \& tbt
-
-\unprotect
-
-\def\fontslantperpoint {\fontdimen1 }
-\def\fontinterwordspace {\fontdimen2 }
-\def\fontinterwordstretch{\fontdimen3 }
-\def\fontinterwordshrink {\fontdimen4 }
-\def\fontexheight {\fontdimen5 }
-\def\fontemwidth {\fontdimen6 }
-\def\fontextraspace {\fontdimen7 }
-
-\def\slantperpoint {\fontdimen1\font}
-\def\interwordspace {\fontdimen2\font}
-\def\interwordstretch {\fontdimen3\font}
-\def\interwordshrink {\fontdimen4\font}
-\def\exheight {\fontdimen5\font}
-\def\emwidth {\fontdimen6\font}
-\def\extraspace {\fontdimen7\font}
-
-\def\mathsupdisplay {\fontdimen13 }
-\def\mathsupnormal {\fontdimen14 }
-\def\mathsupcramped {\fontdimen15 }
-\def\mathsubnormal {\fontdimen16 }
-\def\mathsubcombined {\fontdimen17 }
-\def\mathaxisheight {\fontdimen22 }
-
-\def\currentspaceskip {\interwordspace\!!plus\interwordstretch\!!minus\interwordshrink\relax}
-
-\protect \endinput
diff --git a/tex/context/base/syst-gen.tex b/tex/context/base/syst-gen.tex
index 78311de38..993512b74 100644
--- a/tex/context/base/syst-gen.tex
+++ b/tex/context/base/syst-gen.tex
@@ -123,7 +123,7 @@
%D defined.
%D
%D \starttyping
-%D \writestatus{laden}{Context Systeem Macro's (a)}
+%D \writestatus{laden}{Context Systeem Macros (a)}
%D \stoptyping
%D The next few macros are needed in case this module is
@@ -132,10 +132,6 @@
\ifx\beginTEX\undefined
\let\beginTEX\relax\let\endTEX\relax
\long\def\beginETEX #1\endETEX {}
- \long\def\beginOMEGA #1\endOMEGA{}
-% \long\def\onlyTEX #1{#1}
-% \long\def\onlyETEX #1{}
-% \long\def\onlyOMEGA#1{}
\fi
%D \macros
@@ -311,6 +307,9 @@
\newabove \newtoks \scratchtoks \newabove \newtoks \globalscratchtoks
\newbox \scratchbox \newbox \globalscratchbox
+\newdimen\scratchdimenone \newbox\scratchboxone \newcount\scratchcounterone
+\newdimen\scratchdimentwo \newbox\scratchboxtwo \newcount\scratchcountertwo
+
%D \macros
%D {ifdone}
@@ -361,23 +360,21 @@
%D Beware: we don't reuse plain counters, too dangerous
%D when <= 20 (e.g. in supp-pdf this messed up things).
-\newdimen \zeropoint
-\newcount \zerocount
-\newcount \minusone
- \minusone = -1
-\newcount \minustwo
- \minustwo = -2
-
-\chardef \plusone = 1
-\chardef \plustwo = 2
-\chardef \plusthree = 3
-\chardef \plusfour = 4
-\chardef \plusfive = 5
-
-\mathchardef \plusten = 10
-\mathchardef \plushundred = 100
-\mathchardef \plusthousand = 1000
-\mathchardef \plustenthousand = 10000
+\ifx\undefined\zeroskip \newskip \zeroskip \fi
+\ifx\undefined\zeropoint \newdimen \zeropoint \fi
+\ifx\undefined\zerocount \newcount \zerocount \fi
+\ifx\undefined\minusone \newcount \minusone \fi \minusone = -1
+\ifx\undefined\minustwo \newcount \minustwo \fi \minustwo = -2
+\ifx\undefined\plusone \chardef \plusone = 1 \fi
+\ifx\undefined\plustwo \chardef \plustwo = 2 \fi
+\ifx\undefined\plusthree \chardef \plusthree = 3 \fi
+\ifx\undefined\plusfour \chardef \plusfour = 4 \fi
+\ifx\undefined\plusfive \chardef \plusfive = 5 \fi
+\ifx\undefined\plusten \mathchardef \plusten = 10 \fi
+\ifx\undefined\plushundred \mathchardef \plushundred = 100 \fi
+\ifx\undefined\plusthousand \mathchardef \plusthousand = 1000 \fi
+\ifx\undefined\plustenthousand \mathchardef \plustenthousand = 10000 \fi
+\ifx\undefined\plustwentythousand \mathchardef \plustwentythousand = 20000 \fi
%D \macros
%D {s!,c!,e!,p!,v!,@@,??}
@@ -397,6 +394,8 @@
\def\s!complex {complex} \def\s!start {start}
\def\s!simple {simple} \def\s!stop {stop}
+\def\s!empty {empty}
+
%D \macros
%D {@EA,@EAEA,@EAEAEA,@EAEAEAEAEAEA,expanded,startexpanded}
%D
@@ -544,10 +543,43 @@
\@EAEAEA\!!stringb
\fi\fi}
-%\let\endoflinetoken=^^M
-%
-%\long\def\reinspectaftercharacter#1%
-% {\futurelet\nexttoken\inspectnextcharacter}
+%D Because we will mostly use this macro for testing if the next
+%D character is \type {[}, we also make a slightly faster variant
+%D as it is not uncommon to have tens of thousands of calls to this
+%D test in a run. Of course it also is more convenient to read a
+%D trace then.
+
+\let\nextoptionalcharactertoken=[
+
+\long\def\doifnextoptionalelse#1#2%
+ {\def\nextoptionalcommandyes{#1}%
+ \def\nextoptionalcommandnop{#2}%
+ \futurelet\nexttoken\inspectnextoptionalcharacter}
+
+\def\inspectnextoptionalcharacter
+ {\ifx\nexttoken\blankspace
+ \@EA\reinspectnextoptionalcharacter
+ \else\ifx\nexttoken\nextoptionalcharactertoken
+ \@EAEAEA\nextoptionalcommandyes
+ \else
+ \@EAEAEA\nextoptionalcommandnop
+ \fi\fi}
+
+\let\nextbgroupcharactertoken\bgroup
+
+\long\def\doifnextbgroupelse#1#2%
+ {\def\nextbgroupcommandyes{#1}%
+ \def\nextbgroupcommandnop{#2}%
+ \futurelet\nexttoken\inspectnextbgroupcharacter}
+
+\def\inspectnextbgroupcharacter
+ {\ifx\nexttoken\blankspace
+ \@EA\reinspectnextbgroupcharacter
+ \else\ifx\nexttoken\nextbgroupcharactertoken
+ \@EAEAEA\nextbgroupcommandyes
+ \else
+ \@EAEAEA\nextbgroupcommandnop
+ \fi\fi}
%D This macro uses some auxiliary macros. Although we were able
%D to program quite complicated things, I only understood these
@@ -579,9 +611,14 @@
\def\:{\let\blankspace= } \:
\def\:{\reinspectnextcharacter}
-
\expandafter\def\: {\futurelet\nexttoken\inspectnextcharacter}
+\def\:{\reinspectnextoptionalcharacter}
+\expandafter\def\: {\futurelet\nexttoken\inspectnextoptionalcharacter}
+
+\def\:{\reinspectnextbgroupcharacter}
+\expandafter\def\: {\futurelet\nexttoken\inspectnextbgroupcharacter}
+
\let\:\next
%D \macros
@@ -963,6 +1000,11 @@
\def\letbeundefined#1% potential stack buildup when used \global
{\expandafter\let\csname#1\endcsname\undefined}
+\def\localundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\let\csname#1\endcsname\undefined\fi}
+\def\globalundefine#1% conditional
+ {\ifcsname#1\endcsname\expandafter\global\let\csname#1\endcsname\undefined\fi}
+
\endETEX
%D Beware, being \type {\undefined} in \ETEX\ means that the macro
@@ -1604,6 +1646,8 @@
% \expandafter\firstofoneargument
% \fi}
+% todo: use dedicated done
+
\def\p!dodocommoncheck#1%
{\edef\!!stringb{#1}%
\ifx\!!stringa\!!stringb
@@ -2331,6 +2375,14 @@
%D run time, simply because the less tokens we pass, the faster
%D \TEX\ runs. So finally the definition became:
+% \long\def\rawdoifinstringelse#1#2% ##2 can be {abc}
+% {\long\def\pp!doifinstringelse##1#1##2##3\war{\if##2@}%
+% \pp!doifinstringelse#2#1@@\war
+% \expandafter\secondoftwoarguments
+% \else
+% \expandafter\firstoftwoarguments
+% \fi}
+
\long\def\doifinstringelse#1%
{\edef\@@@instring{#1}% expand #1 here
\ifx\@@@instring\empty
@@ -3033,30 +3085,55 @@
\let\currentvalue\empty
-\def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@% normal
- {\ifx#5\empty
+% \def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@% normal
+% {\ifx#5\empty
+% \@EA\xshowassignerror
+% \else\ifx#5=%
+% \@EAEAEA#1%
+% \else
+% \@EAEAEA\xshowassignerror
+% \fi\fi
+% {#2}{#3}{#4}}
+
+\def\p!n!doassign#1#2\@relax@#3=#4=#5#6\@relax@
+ {\ifx\empty#3\empty
\@EA\xshowassignerror
- \else\ifx#5=%
- \@EAEAEA#1%
- \else
+ \else\ifx#5\empty
\@EAEAEA\xshowassignerror
+ \else
+ \@EAEAEA#1%
\fi\fi
{#2}{#3}{#4}}
\beginTEX
+% \def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@
+% {\ifx#5\empty
+% \@EA\xshowassignerror
+% \else\ifx#5=%
+% \@EA\ifx\csname#2#3\endcsname\relax
+% \let\currentvalue\empty
+% \else
+% \@EA\let\@EA\currentvalue\csname#2#3\endcsname
+% \fi
+% \@EAEAEA#1%
+% \else
+% \@EAEAEA\xshowassignerror
+% \fi\fi
+% {#2}{#3}{#4}}
+
\def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@
- {\ifx#5\empty
+ {\ifx\empty#3\empty
\@EA\xshowassignerror
- \else\ifx#5=%
+ \else\ifx#5\empty
+ \@EAEAEA\xshowassignerror
+ \else
\@EA\ifx\csname#2#3\endcsname\relax
\let\currentvalue\empty
\else
\@EA\let\@EA\currentvalue\csname#2#3\endcsname
\fi
\@EAEAEA#1%
- \else
- \@EAEAEA\xshowassignerror
\fi\fi
{#2}{#3}{#4}}
@@ -3064,18 +3141,33 @@
\beginETEX
+% \def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@
+% {\ifx#5\empty
+% \@EA\xshowassignerror
+% \else\ifx#5=%
+% \ifcsname#2#3\endcsname
+% \@EA\let\@EA\currentvalue\csname#2#3\endcsname
+% \else
+% \let\currentvalue\empty
+% \fi
+% \@EAEAEA#1%
+% \else
+% \@EAEAEA\xshowassignerror
+% \fi\fi
+% {#2}{#3}{#4}}
+
\def\p!e!doassign#1#2\@relax@#3=#4=#5#6\@relax@
- {\ifx#5\empty
+ {\ifx\empty#3\empty
\@EA\xshowassignerror
- \else\ifx#5=%
+ \else\ifx#5\empty
+ \@EAEAEA\xshowassignerror
+ \else
\ifcsname#2#3\endcsname
\@EA\let\@EA\currentvalue\csname#2#3\endcsname
\else
\let\currentvalue\empty
\fi
\@EAEAEA#1%
- \else
- \@EAEAEA\xshowassignerror
\fi\fi
{#2}{#3}{#4}}
@@ -3464,7 +3556,7 @@
\chardef\expectedarguments =0
\def\showargumenterror#1#2%
- {\writestatus{system}{#1 argument(s) expected in line #2}}
+ {\writestatus{systems}{#1 argument(s) expected in line #2}}
% \long\def\dogetargument#1#2#3#4% redefined in mult-ini
% {\doifnextcharelse{#1}
@@ -3608,19 +3700,19 @@
\def\dosingleempty#1%
{\noshowargumenterror % \relax % prevents lookahead, brr
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\firstargumenttrue#1}
{\dosinglefakeempty#1}}
\def\dodoubleempty#1%
{\noshowargumenterror % \relax % prevents lookahead, brr
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\dodoubletestempty#1}
{\dodoublefakeempty#1}}
\def\dotripleempty#1%
{\noshowargumenterror % \relax % prevents lookahead, brr
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\dotripletestempty#1}
{\dotriplefakeempty#1}}
@@ -3635,20 +3727,20 @@
\long\def\dodoubletestempty#1[#2]%
{\firstargumenttrue
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\secondargumenttrue #1[{#2}]}
{\secondargumentfalse#1[{#2}][]}}
\long\def\dotripletestempty#1[#2]%
{\firstargumenttrue
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\dotripletestemptyx #1[{#2}]}
{\secondargumentfalse
\thirdargumentfalse #1[{#2}][][]}}
\long\def\dotripletestemptyx#1[#2][#3]%
{\secondargumenttrue
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\thirdargumenttrue #1[{#2}][{#3}]}
{\thirdargumentfalse#1[{#2}][{#3}][]}}
@@ -3736,13 +3828,13 @@
\def\complexorsimple#1%
{% \relax % prevents lookahead, brrr
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
{\firstargumentfalse\csname\s!simple \strippedcsname#1\endcsname}}
\def\complexorsimpleempty#1%
{% \relax % prevents lookahead, brrr
- \doifnextcharelse[%
+ \doifnextoptionalelse
{\firstargumenttrue \csname\s!complex\strippedcsname#1\endcsname}
{\firstargumentfalse\csname\s!complex\strippedcsname#1\endcsname[]}}
@@ -3793,10 +3885,10 @@
% faster, since no \strippedcsname needed in call, but more spacy
\def\docomplexorsimple#1#2%
- {\doifnextcharelse[{\firstargumenttrue#1}{\firstargumentfalse#2}}
+ {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#2}}
\def\docomplexorsimpleempty#1%
- {\doifnextcharelse[{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
+ {\doifnextoptionalelse{\firstargumenttrue#1}{\firstargumentfalse#1[]}}
\def\definecomplexorsimple#1%
{\unexpanded\edef#1%
@@ -3926,35 +4018,6 @@
%D \type {\if} and friends, in practice we will use a
%D slightly more complicated macro.
-\let\normalif \if
-\let\normalifcat \ifcat
-\let\normalifnum \ifnum
-\let\normalifdim \ifdim
-\let\normalifodd \ifodd
-\let\normalifvmode \ifvmode
-\let\normalifhmode \ifhmode
-\let\normalifmmode \ifmmode
-\let\normalifinner \ifinner
-\let\normalifvoid \ifvoid
-\let\normalifhbox \ifhbox
-\let\normalifvbox \ifvbox
-\let\normalifx \ifx
-\let\normalifeof \ifeof
-\let\normaliftrue \iftrue
-\let\normaliffalse \iffalse
-\let\normalifcase \ifcase
-\let\normalifdefined \ifdefined
-\let\normalifcsname \ifcsname
-\let\normaliffontchar \iffontchar
-\let\normalifincsname \ifincsname
-\let\normalifprimitive\ifprimitive
-\let\normalifabsnum \ifabsnum
-\let\normalifabsdim \ifabsdim
-
-\let\normalelse \else
-\let\normalor \or
-\let\normalfi \fi
-
\newtoks \everyrobusttest
\everyrobusttest
@@ -4000,34 +4063,65 @@
\dontpermitspacesbetweengroups
+% \def\dogetgroupargument#1#2%
+% {\def\nextnextargument%
+% {\normalifx\nextargument\bgroup
+% \endrobusttest
+% \noshowargumenterror
+% \def\nextargument{#1\dodogetargument}%
+% \normalelse
+% \normalifcase\@@permitspacesbetweengroups
+% \normalifx\nextargument\lineending
+% \endrobusttest
+% \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
+% \normalelse\normalifx\nextargument\blankspace
+% \endrobusttest
+% \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
+% \normalelse
+% \endrobusttest
+% \doshowargumenterror
+% \def\nextargument{#2\dodogetargument{}}%
+% \normalfi\normalfi
+% \normalelse
+% \endrobusttest
+% \doshowargumenterror
+% \def\nextargument{#2\dodogetargument{}}%
+% \normalfi
+% \normalfi
+% \nextargument}%
+% \beginrobusttest
+% \futurelet\nextargument\nextnextargument}
+
+\def\dodogetgroupargument
+ {\normalifx\nextargument\bgroup
+ \endrobusttest
+ \noshowargumenterror
+ \def\nextargument{\dogroupargumentyes\dodogetargument}%
+ \normalelse
+ \normalifcase\@@permitspacesbetweengroups
+ \normalifx\nextargument\lineending
+ \endrobusttest
+ \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument\dogroupargumentyes\dogroupargumentnop}\\}%
+ \normalelse\normalifx\nextargument\blankspace
+ \endrobusttest
+ \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument\dogroupargumentyes\dogroupargumentnop}\\}%
+ \normalelse
+ \endrobusttest
+ \doshowargumenterror
+ \def\nextargument{\dogroupargumentnop\dodogetargument{}}%
+ \normalfi\normalfi
+ \normalelse
+ \endrobusttest
+ \doshowargumenterror
+ \def\nextargument{\dogroupargumentnop\dodogetargument{}}%
+ \normalfi
+ \normalfi
+ \nextargument}%
+
\def\dogetgroupargument#1#2%
- {\def\nextnextargument%
- {\normalifx\nextargument\bgroup
- \endrobusttest
- \noshowargumenterror
- \def\nextargument{#1\dodogetargument}%
- \normalelse
- \normalifcase\@@permitspacesbetweengroups
- \normalifx\nextargument\lineending
- \endrobusttest
- \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
- \normalelse\normalifx\nextargument\blankspace
- \endrobusttest
- \def\nextargument{\begingroup\def\\ {\endgroup\dogetgroupargument#1#2}\\}%
- \normalelse
- \endrobusttest
- \doshowargumenterror
- \def\nextargument{#2\dodogetargument{}}%
- \normalfi\normalfi
- \normalelse
- \endrobusttest
- \doshowargumenterror
- \def\nextargument{#2\dodogetargument{}}%
- \normalfi
- \normalfi
- \nextargument}%
- \beginrobusttest
- \futurelet\nextargument\nextnextargument}
+ {\let\dogroupargumentyes#1%
+ \let\dogroupargumentnop#2%
+ \beginrobusttest\futurelet\nextargument\dodogetgroupargument}
\def\dosinglegroupempty#1%
{\def\dodogetargument%
@@ -4107,21 +4201,32 @@
%D used to select arguments. Their names explain their
%D functionality.
-\long\def\firstofoneargument #1{#1}
-\long\def\firstoftwoarguments #1#2{#1}
-\long\def\firstofthreearguments #1#2#3{#1}
-\long\def\firstoffourarguments #1#2#3#4{#1}
-\long\def\firstoffivearguments #1#2#3#4#5{#1}
-\long\def\secondoftwoarguments #1#2{#2}
-\long\def\secondofthreearguments #1#2#3{#2}
-\long\def\secondoffourarguments #1#2#3#4{#2}
-\long\def\secondoffivearguments #1#2#3#4#5{#2}
-\long\def\thirdofthreearguments #1#2#3{#3}
-\long\def\thirdoffourarguments #1#2#3#4{#3}
-\long\def\thirdoffivearguments #1#2#3#4#5{#3}
-\long\def\fourthoffourarguments #1#2#3#4{#4}
-\long\def\fourthoffivearguments #1#2#3#4#5{#4}
-\long\def\fifthoffivearguments #1#2#3#4#5{#5}
+\long\def\firstofoneargument#1{#1}
+
+\long\def\firstoftwoarguments #1#2{#1}
+\long\def\secondoftwoarguments#1#2{#2}
+
+\long\def\firstofthreearguments #1#2#3{#1}
+\long\def\secondofthreearguments#1#2#3{#2}
+\long\def\thirdofthreearguments #1#2#3{#3}
+
+\long\def\firstoffourarguments #1#2#3#4{#1}
+\long\def\secondoffourarguments#1#2#3#4{#2}
+\long\def\thirdoffourarguments #1#2#3#4{#3}
+\long\def\fourthoffourarguments#1#2#3#4{#4}
+
+\long\def\firstoffivearguments #1#2#3#4#5{#1}
+\long\def\secondoffivearguments#1#2#3#4#5{#2}
+\long\def\thirdoffivearguments #1#2#3#4#5{#3}
+\long\def\fourthoffivearguments#1#2#3#4#5{#4}
+\long\def\fifthoffivearguments #1#2#3#4#5{#5}
+
+\long\def\firstofsixarguments #1#2#3#4#5#6{#1}
+\long\def\secondofsixarguments#1#2#3#4#5#6{#2}
+\long\def\thirdofsixarguments #1#2#3#4#5#6{#3}
+\long\def\fourthofsixarguments#1#2#3#4#5#6{#4}
+\long\def\fifthofsixarguments #1#2#3#4#5#6{#5}
+\long\def\sixthofsixarguments #1#2#3#4#5#6{#6}
%D \macros
%D {globalletempty,letempty,letvalueempty,letgvalueempty}
@@ -4301,10 +4406,13 @@
%D Finally we do what from now on will be done at the top of
%D the files: we tell the user what we are loading.
-\ifx\writestatus\undefined \let\writestatus\normalwritestatus \fi
-\ifx\writebanner\undefined \def\writebanner{\writestring} \fi
+% \ifx\writestatus\undefined \let\writestatus\normalwritestatus \fi
+% \ifx\writebanner\undefined \def\writebanner{\writestring} \fi
+
+\let\writestatus\normalwritestatus
+\def\writebanner{\writestring}
-\writestatus{loading}{Context System Macros / General}
+\writestatus{loading}{ConTeXt System Macros / General}
%D Well, the real final command is the one that resets the
%D unprotected characters \type{@}, \type{?} and \type{!}.
diff --git a/tex/context/base/syst-ini.tex b/tex/context/base/syst-ini.tex
new file mode 100644
index 000000000..c334b1cf6
--- /dev/null
+++ b/tex/context/base/syst-ini.tex
@@ -0,0 +1,879 @@
+%D \module
+%D [ file=syst-ini,
+%D version=2008.11.04, % 2001.11.16, % 1999.03.17, % an oldie: 1995.10.10
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Bootstrapping \TEX,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We used to load plain \TEX\ in a special way, but redefining
+%D a couple of primitives so that for instance font loading was
+%D ignored. For those interested, this loader is found in
+%D \type {syst-tex.tex}. Some of the comment's are Don Knuth's
+%D and more of it can be found in the plain \TEX\ format.
+
+%D Characters can have special states, that can be triggered
+%D by setting their category coded. Some are preset, others
+%D are to be set as soon as possible, otherwise we cannot
+%D define any useful macros.
+
+%catcode`\^^@ = 9 % ascii null is ignored
+%catcode`\\ = 0 % backslash is TeX escape character
+
+\catcode`\{ = 1 % left brace is begin-group character
+\catcode`\} = 2 % right brace is end-group character
+\catcode`\$ = 3 % dollar sign is math shift
+\catcode`\& = 4 % ampersand is alignment tab
+\catcode`\# = 6 % hash mark is macro parameter character
+\catcode`\^ = 7 % circumflex and uparrow are for superscripts
+\catcode`\_ = 8 % underline and downarrow are for subscripts
+\catcode`\^^I = 10 % ascii tab is a blank space
+
+%catcode`\^^M = 5 % ascii return is end-line
+%catcode`\% = 14 % percent sign is comment character
+%catcode`\ = 10 % ascii space is blank space
+%catcode`\^^? = 15 % ascii delete is invalid
+
+\catcode`\~ = 13 % tilde is active
+\catcode`\^^L = 13 % ascii form-feed
+
+%catcode`\A = 11
+%.......
+%catcode`\Z = 11
+
+%catcode`\a = 11
+%.......
+%catcode`\z = 11
+
+\chardef\active = 13
+
+\def ^^L{\par}
+\def\^^M{\ } % control <return> = control <space>
+\def\^^I{\ } % same for <tab>
+
+%D In \CONTEXT, we simply ignore end||of||file tokens:
+
+\catcode`\^^Z=9
+
+%D It makes sense to know what engine we're running so let's
+%D try to deduce it.
+
+\chardef\unknownengine = 0
+\chardef\pdftexengine = 1
+\chardef\xetexengine = 2
+\chardef\luatexengine = 3
+
+\ifx\directlua\undefined
+ \ifx\XeTeXversion\undefined
+ \ifx\pdftexversion\undefined
+ \let\texengine\unknownengine
+ \else
+ \let\texengine\pdftexengine
+ \fi
+ \else
+ \let\texengine\xetexengine
+ \fi
+\else
+ \let\texengine\luatexengine
+\fi
+
+\ifnum\texengine=\unknownengine
+ \immediate\write16{>>>}
+ \immediate\write16{>>> only pdftex, xetex and luatex are supported}
+ \immediate\write16{>>>}
+ \let\dump\relax
+ \expandafter\end
+\fi
+
+% todo: pdfsave pdfrestore pdfcolor... don't initialize them
+
+\ifnum\texengine=\luatexengine
+ \directlua 0 { % this info is stored in the format
+ if lua.name then
+ lua.name[0] = "main ctx instance"
+ end
+ if tex.extraprimitives then
+ local core = tex.extraprimitives('core')
+ local btex = tex.extraprimitives('tex')
+ local etex = tex.extraprimitives('etex')
+ local pdftex = tex.extraprimitives('pdftex')
+ local luatex = tex.extraprimitives('luatex')
+ local omega = {
+ "textdir", "pagedir", "mathdir", "pardir", "bodydir",
+ "leftghost", "rightghost", "localleftbox", "localrightbox",
+ "localinterlinepenalty", "localbrokenpenalty",
+ }
+ local aleph = {
+ "boxdir", "pagebottomoffset", "pagerightoffset",
+ }
+ for _, subset in pairs { etex, pdftex, luatex, omega, aleph } do
+ tex.enableprimitives('',subset)
+ end
+ for _, subset in pairs { core, btex, etex, pdftex, luatex, omega, aleph } do
+ tex.enableprimitives('normal',subset)
+ end
+ end
+ }
+\fi
+
+%D \ETEX\ has a not so handy way of telling you the version number,
+%D i.e. the revision number has a period in it:
+
+\long\def\gobbleoneargument#1{} % will be defined later on anyway
+
+\mathchardef\etexversion =
+ \numexpr\eTeXversion*100+\expandafter\gobbleoneargument\eTeXrevision\relax
+
+%D First we define a simplified version of the \CONTEXT\
+%D protection mechanism.
+
+\def\unprotect{\catcode`@=11 }
+\def\protect {\catcode`@=12 }
+
+\unprotect
+
+%D Some pretty important definitions:
+
+\let\bgroup={
+\let\egroup=}
+
+%D Allocation of registers is done slightly different than in plain
+%D \TEX. First of all we use different reserved counters. We also
+%D don't implement a family handler because users are not supposed
+%D to implement their own math. We reserve the lowest 31 registers
+%D for scratch purposes. Keep in mind that in the core engine
+%D some registers are reserved: counters 0 upto 9, and counter 255.
+%D
+%D As with plain \TEX\ we recommend that macro designers always use
+%D \type {\global} assignments with respect to registers numbered 1,
+%D 3, 5 \unknown\ 31, and always non||\type {\global} assignments
+%D with respect to registers 0, 2, 4, \unknown\ 30. This will prevent
+%D \quote {save stack buildup} that might otherwise occur.
+%D
+%D We reserve some registers for special (management) purposes:
+
+\countdef \minallocatedregister = 52 \minallocatedregister = 256
+\countdef \maxallocatedregister = 53 \maxallocatedregister = 32767
+\countdef \minallocatediochannel = 54 \minallocatediochannel = -1
+\countdef \maxallocatediochannel = 55 \maxallocatediochannel = 16
+\countdef \minallocatedlanguage = 56 \minallocatedlanguage = 0
+\countdef \maxallocatedlanguage = 57 \maxallocatedlanguage = 255
+\countdef \maxallocatedinsert = 58 \maxallocatedinsert = 254
+\countdef \minallocatedinsert = 59 \minallocatedinsert = 128
+\countdef \minallocatedfamily = 60 \minallocatedfamily = 128
+\countdef \maxallocatedfamily = 61 \maxallocatedfamily = 255
+
+\countdef \lastallocatedcount = 32 \lastallocatedcount = \minallocatedregister
+\countdef \lastallocateddimen = 33 \lastallocateddimen = \minallocatedregister
+\countdef \lastallocatedskip = 34 \lastallocatedskip = \minallocatedregister
+\countdef \lastallocatedmuskip = 35 \lastallocatedmuskip = \minallocatedregister
+\countdef \lastallocatedbox = 36 \lastallocatedbox = \minallocatedregister
+\countdef \lastallocatedtoks = 37 \lastallocatedtoks = \minallocatedregister
+\countdef \lastallocatedread = 38 \lastallocatedread = \minallocatediochannel
+\countdef \lastallocatedwrite = 39 \lastallocatedwrite = \minallocatediochannel
+\countdef \lastallocatedmarks = 40 \lastallocatedmarks = \minallocatedregister
+\countdef \lastallocatedlanguage = 41 \lastallocatedlanguage = \minallocatedlanguage
+\countdef \lastallocatedinsertion = 42 \lastallocatedinsertion = \minallocatedinsert
+\countdef \lastallocatedfamily = 43 \lastallocatedfamily = \minallocatedfamily
+\countdef \lastallocatedattribute = 44 \lastallocatedattribute = \minallocatedregister
+
+\countdef \mincountervalue = 125 \mincountervalue = -"7FFFFFFF
+\countdef \maxcountervalue = 126 \maxcountervalue = "7FFFFFFF
+\countdef \minusone = 127 \minusone = -1
+\chardef \zerocount = 0
+\chardef \plusone = 1
+
+\chardef \normalpagebox = 255 % hardcoded in the engine
+
+% A few traditional allocations:
+
+\countdef \count@ = 255 % hm, used in \newif
+\dimendef \dimen@ = 0
+\dimendef \dimen@i = 1 % global only
+\dimendef \dimen@ii = 2
+
+%D So, effectively we start allocating from 256 and upwards. The
+%D inserts sit in the range 128 upto 254. Page numbers use the
+%D counters 0 upto 9 and the pagebox is 255. Users can use the
+%D scratch registers upto 31 without problem but all others are
+%D reserved.
+
+\def\wlog#1{} % \def\wlog{\immediate\write\minusone} % write on log file (only)
+
+%D The allocators share a common helper macro.
+
+\def\newcount {\allocateregister\lastallocatedcount \count \countdef \maxallocatedregister}
+\def\newdimen {\allocateregister\lastallocateddimen \dimen \dimendef \maxallocatedregister}
+\def\newskip {\allocateregister\lastallocatedskip \skip \skipdef \maxallocatedregister}
+\def\newmuskip {\allocateregister\lastallocatedmuskip \muskip \muskipdef \maxallocatedregister}
+\def\newbox {\allocateregister\lastallocatedbox \box \mathchardef\maxallocatedregister}
+\def\newtoks {\allocateregister\lastallocatedtoks \toks \toksdef \maxallocatedregister}
+\def\newread {\allocateregister\lastallocatedread \read \chardef \maxallocatediochannel}
+\def\newwrite {\allocateregister\lastallocatedwrite \write \chardef \maxallocatediochannel}
+\def\newmarks {\allocateregister\lastallocatedmarks \marks \mathchardef\maxallocatedregister}
+\def\newlanguage{\allocateregister\lastallocatedlanguage \language\chardef \maxallocatedlanguage}
+\def\newinsert {\allocateregister\lastallocatedinsertion\insert \chardef \maxallocatedinsert}
+\def\newfamily {\allocateregister\lastallocatedfamily \fam \chardef \maxallocatedfamily}
+
+\let\newfam\newfamily
+
+% %D The next definitions are really needed (in \CONTEXT):
+
+%newlinechar=10 \def\outputnewlinechar{\rawcharacter{10}}
+\newlinechar=10 \edef\outputnewlinechar{^^J}
+
+%D One reason to start high with allocation is that it permits us to
+%D allocate consecutive ranges more easily, for instance in \MPLIB\
+%D we want to allocate a continuous range of boxes. It also permits us
+%D to do a proper upward allocation for inserts. The current code
+%D evolved from code that dealt with older engines but as all engines
+%D now provide many registers we removed all traces.
+
+\def\writestatus#1#2{\immediate\write16{#1: #2}} \def\space { }
+
+\def\allocateregisteryes#1#2#3#4#5% last class method max name
+ {\ifnum#1<#4\relax
+ \global\advance#1\plusone
+ \global#3#5=#1\relax
+ \else
+ \writestatus{warning}{no room for \string#2\space \string#5\space (max: \number#4)}%
+ \fi}
+
+\def\allocateregisternop#1#2#3#4#5% last class method max name
+ {\writestatus{warning}{\string#2 \string#5 is already defined (\string\relax\space it first)}}
+
+\def\allocateregister#1#2#3#4#5% last class method max name
+ {\ifx#5\undefined
+ \expandafter\allocateregisteryes
+ \else\ifx#5\relax
+ \expandafter\expandafter\expandafter\allocateregisteryes
+ \else
+ \expandafter\expandafter\expandafter\allocateregisternop
+ \fi\fi
+ #1#2#3#4#5}
+
+%D Since the number of chars exceed 256 now, we can use \type
+%D {\chardef} instead of the more limited \type {\mathchardef}.
+
+\ifnum\texengine>\pdftexengine
+ \def\newbox {\allocateregister\lastallocatedbox \box \chardef\maxallocatedregister}
+ \def\newmarks{\allocateregister\lastallocatedmarks\marks\chardef\maxallocatedregister}
+\fi
+
+%D Attributes are something very \LUATEX. In \CONTEXT\ you are not
+%D supposed to use the attributes directly but always allocate then
+%D first. For instance attribute~0 is reserved for special purposes
+%D (this might change).
+
+\ifnum\texengine=\luatexengine
+ \let\attributeunsetvalue\mincountervalue % used to be \minusone
+ \def\newattribute{\allocateregister\lastallocatedattribute\attribute\attributedef\maxallocatedregister}
+\fi
+
+%D Not used by \CONTEXT\ but for instance \PICTEX\ needs it. It's a
+%D trick to force strings instead of tokens that take more memory.
+%D It's a trick to trick to force strings.
+
+\def\newhelp#1#2{\newtoks#1#1\expandafter{\csname#2\endcsname}}
+
+%D \macros
+%D {scratchcounter,
+%D scratchdimen,scratchskip,scratchmuskip,
+%D scratchbox,
+%D scratchtoks}
+%D
+%D We now define a few scratch registers, so that successive
+%D loads at least have some available.
+
+\newcount \scratchcounter \newcount \globalscratchcounter
+\newdimen \scratchdimen \newdimen \globalscratchdimen
+\newskip \scratchskip \newskip \globalscratchskip
+\newmuskip \scratchmuskip \newmuskip \globalscratchmuskip
+\newtoks \scratchtoks \newtoks \globalscratchtoks
+\newbox \scratchbox \newbox \globalscratchbox
+
+\newcount\scratchcounterone \newcount\scratchcountertwo \newcount\scratchcounterthree
+\newdimen \scratchdimenone \newdimen \scratchdimentwo \newdimen \scratchdimenthree
+\newdimen \scratchskipone \newdimen \scratchskiptwo \newdimen \scratchskipthree
+\newbox \scratchmuskipone \newbox \scratchmuskiptwo \newbox \scratchmuskipthree
+\newtoks \scratchtoksone \newtoks \scratchtokstwo \newtoks \scratchtoksthree
+\newbox \scratchboxone \newbox \scratchboxtwo \newbox \scratchboxthree
+
+%D More allocations:
+
+\newskip \zeroskip \zeroskip = 0pt plus 0pt minus 0pt
+\newdimen\zeropoint \zeropoint = 0pt
+\newdimen\onepoint \onepoint = 1pt
+\newdimen\maxdimen \maxdimen = 16383.99999pt
+\newdimen\onebasepoint \onebasepoint = 1bp
+\chardef \scaledpoint = 1
+\newdimen\thousandpoint\thousandpoint= 1000pt
+
+\let\points\onepoint
+
+\newtoks \emptytoks
+
+%D And even more:
+
+%newcount \minusone \minusone = -1
+\newcount \minustwo \minustwo = -2
+%chardef \zerocount = 0
+%chardef \plusone = 1
+\chardef \plustwo = 2
+\chardef \plusthree = 3
+\chardef \plusfour = 4
+\chardef \plusfive = 5
+\chardef \plussix = 6
+\chardef \plusseven = 7
+\chardef \pluseight = 8
+\chardef \plusnine = 9
+\chardef \plusten = 10
+\chardef \plussixteen = 16
+\chardef \plushundred = 100
+\chardef \pluscxxvii = 127
+\chardef \pluscxxviii = 128
+\chardef \pluscclv = 255
+
+\ifnum\texengine=\luatexengine
+ \chardef \pluscclvi = 256
+ \chardef \plusthousand = 1000
+ \chardef \plustenthousand = 10000
+ \chardef \plustwentythousand = 20000
+ \chardef \medcard = 32768
+ \chardef \maxcard = 65536 % pdftex has less mathchars
+\else
+ \mathchardef\pluscclvi = 256
+ \mathchardef\plusthousand = 1000
+ \mathchardef\plustenthousand = 10000
+ \mathchardef\plustwentythousand = 20000
+ \newcount \medcard \medcard = 32768 % pdftex has less mathchars
+ \newcount \maxcard \maxcard = 65536 % pdftex has less mathchars
+\fi
+
+%D We prefer the more readable variant than in plain
+%D \TEX. User should only use \type {\emptybox}:
+
+\newbox\voidbox
+
+\def\emptybox {\box \voidbox}
+\def\unvoidbox{\unhbox\voidbox}
+
+\let\leavevmode\unvoidbox % we prefer to use \dontleavehmode
+
+%D Some expected plain variants follow. We don't reuse registers
+%D because we don't want clashes.
+
+\newdimen\p@ \p@ \onepoint
+\newcount\m@ne \m@ne \minusone
+\newdimen\z@ \z@ \zeropoint
+\let \@ne \plusone
+\let \tw@ \plustwo
+\let \thr@@ \plusthree
+\let \sixt@@n \sixteen
+\let \@cclv \pluscclv
+\let \@cclvi \pluscclvi
+\newbox \voidb@x
+\newtoks \toks@
+
+%D We define \type {\newif} a la plain \TEX, but will
+%D redefine it later. As Knuth says:
+%D
+%D \startnarrower
+%D And here's a different sort of allocation: for example,
+%D
+%D \starttyping
+%D \newif\iffoo
+%D \stoptyping
+%D
+%D creates \type {\footrue}, \type {\foofalse} to go
+%D with \type {\iffoo}.
+%D \stopnarrower
+
+\def\newif#1%
+ {\count@\escapechar
+ \escapechar\minusone
+ \expandafter\expandafter\expandafter\def\@if #1{true}{\let#1\iftrue }%
+ \expandafter\expandafter\expandafter\def\@if#1{false}{\let#1\iffalse}%
+ \@if#1{false}% the condition starts out false
+ \escapechar\count@}
+
+\def\@if#1#2%
+ {\csname\expandafter\if@\string#1#2\endcsname}
+
+\bgroup % `if' is required
+
+ \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}}
+
+\egroup
+
+%D Let's test this one:
+
+\newif\ifdone
+
+%D \macros
+%D {@@escape,@@begingroup,@@endgroup,@@mathshift,@@alignment,
+%D @@endofline,@@parameter,@@superscript,@@subscript,
+%D @@ignore,@@space,@@letter,@@other,@@active,@@comment}
+%D
+%D In \CONTEXT\ we sometimes manipulate the \CATCODES\ of certain
+%D characters. Because we are not that good at remembering numbers,
+%D we introduce some symbolic names.
+
+\chardef\@@escape = 0
+\chardef\@@begingroup = 1
+\chardef\@@endgroup = 2
+\chardef\@@mathshift = 3
+\chardef\@@alignment = 4
+\chardef\@@endofline = 5
+\chardef\@@parameter = 6
+\chardef\@@superscript = 7
+\chardef\@@subscript = 8
+\chardef\@@ignore = 9
+\chardef\@@space = 10
+\chardef\@@letter = 11
+\chardef\@@other = 12 \chardef\other = 12
+\chardef\@@active = 13 \chardef\active = 13
+\chardef\@@comment = 14
+
+%D Constants to be used with \type {\grouptype}.
+
+\chardef\@@bottomlevelgroup = 0
+\chardef\@@simplegroup = 1
+\chardef\@@hboxgroup = 2
+\chardef\@@adjustedhboxgroup = 3
+\chardef\@@vboxgroup = 4
+\chardef\@@vtopgroup = 5
+\chardef\@@aligngroup = 6
+\chardef\@@noaligngroup = 7
+\chardef\@@outputgroup = 8
+\chardef\@@mathgroup = 9
+\chardef\@@discretionarygroup = 10
+\chardef\@@insertgroup = 11
+\chardef\@@vcentergroup = 12
+\chardef\@@mathchoicegroup = 13
+\chardef\@@semisimplegroup = 14
+\chardef\@@mathshiftgroup = 15
+\chardef\@@mathleftgroup = 16
+
+\chardef\@@vadjustgroup = \@@insertgroup
+
+%D Constants to be used with \type {\interactionmode}.
+
+\chardef\@@batchmode = 0
+\chardef\@@nonstopmode = 1
+\chardef\@@scrollmode = 2
+\chardef\@@errorstopmode = 3
+
+%D Constants to be used with \type {\lastnodetype}.
+
+\chardef\@@charnode = 0
+\chardef\@@hlistnode = 1
+\chardef\@@vlistnode = 2
+\chardef\@@rulenode = 3
+\chardef\@@insertnode = 4
+\chardef\@@marknode = 5
+\chardef\@@adjustnode = 6
+\chardef\@@ligaturenode = 7
+\chardef\@@discretionarynode = 8
+\chardef\@@whatsitnode = 9
+\chardef\@@mathnode = 10
+\chardef\@@gluenode = 11
+\chardef\@@kernnode = 12
+\chardef\@@penaltynode = 13
+\chardef\@@unsetnode = 14
+\chardef\@@mathsnode = 15
+
+%D Constants to be used with \type {\currentiftype}.
+
+\chardef\@@charif = 1
+\chardef\@@catif = 2
+\chardef\@@numif = 3
+\chardef\@@dimif = 4
+\chardef\@@oddif = 5
+\chardef\@@vmodeif = 6
+\chardef\@@hmodeif = 7
+\chardef\@@mmodeif = 8
+\chardef\@@innerif = 9
+\chardef\@@voidif = 10
+\chardef\@@hboxif = 11
+\chardef\@@vboxif = 12
+\chardef\@@xif = 13
+\chardef\@@eofif = 14
+\chardef\@@trueif = 15
+\chardef\@@falseif = 16
+\chardef\@@caseif = 17
+\chardef\@@definedif = 18
+\chardef\@@csnameif = 19
+\chardef\@@fontcharif = 20
+
+%D Of course we want even bigger log files, so we copied this
+%D from the \ETEX\ source files.
+%D
+%D When watching such logs, beware of nasty side effects of
+%D \type {\scantokens}, as in:
+%D
+%D \starttyping
+%D \bgroup
+%D \lccode`a=12\lowercase{\xdef\whatever{a}}\egroup
+%D \def\whatever{test \whatever test}
+%D \scantokens\expandafter{\whatever}
+%D \egroup
+%D \stoptyping
+%D
+%D In \LUATEX\ we have ways around this.
+
+\def\tracingall
+ {\tracingonline \plusone
+ \tracingcommands \plusthree
+ \tracingstats \plustwo
+ \tracingpages \plusone
+ \tracingoutput \plusone
+ \tracinglostchars \plustwo
+ \tracingmacros \plustwo
+ \tracingparagraphs\plusone
+ \tracingrestores \plusone
+ \showboxbreadth \maxdimen
+ \showboxdepth \maxdimen
+ \tracinggroups \plusone
+ \tracingifs \plusone
+ \tracingscantokens\plusone
+ \tracingnesting \plusone
+ \tracingassigns \plustwo
+ \errorstopmode}
+
+\def\loggingall
+ {\tracingall
+ \tracingonline \zerocount}
+
+\def\tracingnone
+ {\tracingassigns \zerocount
+ \tracingnesting \zerocount
+ \tracingscantokens\zerocount
+ \tracingifs \zerocount
+ \tracinggroups \zerocount
+ \showboxdepth \plusthree
+ \showboxbreadth \plusfive
+ \tracingrestores \zerocount
+ \tracingparagraphs\zerocount
+ \tracingmacros \zerocount
+ \tracinglostchars \plusone
+ \tracingoutput \zerocount
+ \tracingpages \zerocount
+ \tracingstats \zerocount
+ \tracingcommands \zerocount
+ \tracingonline \zerocount}
+
+%D Just for tracing purposes we set:
+
+\tracingstats\plusone
+
+%D Here we also save \input, more will be saved later.
+
+\ifdefined\normalinput \else \let\normalinput\input \fi
+
+%D We don't like outer commands, and we always want access
+%D to the original \type {\input} primitive.
+
+\let\normalouter\outer \def\outer{} % no longer \relax
+
+%D To circumvent dependencies, we can postpone certain
+%D initializations to dumping time, by appending them to the
+%D \type {\everydump} token register.
+
+\ifdefined\normaldump \else \let\normaldump\dump \fi
+
+\newtoks\everydump
+
+\def\dump{\the\everydump\normaldump}
+
+%D The same applies for the startup actions.
+
+\ifdefined\normaleveryjob \else \let\normaleveryjob\everyjob \fi
+
+\let\everyjob\relax \newtoks\everyjob
+
+\normaleveryjob{\the\everyjob}
+
+\def\appendtotoks #1{\def\temp{#1}\afterassignment\doappendtotoks \scratchtoks=}
+\def\prependtotoks#1{\def\temp{#1}\afterassignment\doprependtotoks\scratchtoks=}
+
+\def\doappendtotoks {\expandafter\expandafter\expandafter{\expandafter\the\expandafter\temp\the\scratchtoks}}
+\def\doprependtotoks{\expandafter\expandafter\expandafter{\expandafter\the\expandafter\scratchtoks\the\temp}}
+
+%D \macros
+%D {begcsname}
+%D
+%D Handy for \ETEX-only usage (avoids making \type {\relax}'s:
+
+\def\begcsname#1\endcsname{\ifcsname#1\endcsname\csname#1\endcsname\fi}
+
+%D Now come a few macros that might be needed in successive loading:
+
+\let\endgraf\par
+\let\endline\cr
+
+\def\space{ }
+\def\empty{}
+\def\null {\hbox{}}
+
+%D The following two might be overloaded later on but some modules need
+%D then earlier. These functionality is reflected in the name and will not
+%D change.
+
+\bgroup
+ \catcode`\^^M=\active%
+ \gdef\obeylines{\catcode`\^^M\active \let^^M\par}%
+ \global\let^^M\par%
+\egroup
+
+\bgroup
+ \gdef\obeyspaces{\catcode`\ \active}%
+ \obeyspaces\global\let =\space%
+\egroup
+
+%D Also needed might be a simple loop structure and we borrow
+%D plain \TEX's one as it is often expected to be present and
+%D it is about the fastest you can get. Beware: this macro
+%D does not support nested loops. We use a namespace prefix
+%D \type {@@pln}.
+
+\long\def\loop#1\repeat{\long\def\@@plnbody{#1}\@@plniterate}
+
+%D The following makes \type {\loop} \unknown\ \type {\if}
+%D \unknown\ \type {\repeat} skippable (clever trick):
+
+\let\repeat\fi % so both \loop and \repeat are reserved words!
+
+%D The original (no \type {@@pln} there):
+%D
+%D \starttyping
+%D \def\@@plniterate{\@@plnbody\let\next\@@plniterate\else\let\next\relax\fi\next}
+%D \stoptyping
+%D
+%D A more efficient alternative:
+%D
+%D \starttyping
+%D \def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\expandafter\relax\fi}
+%D \stoptyping
+%D
+%D An even more efficient one:
+
+\def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\fi}
+
+%D We don't define a real output routine yet but at least get rid
+%D of pages:
+
+\output{\shipout\box\normalpagebox}
+
+%D Although we don't add pagenumbers yet we alias the default
+%D register used for counting pages:
+
+\countdef\pageno=0 \pageno=1 % first page is number 1
+
+%D Beside the raw counter \type {\pageno} the \type {\folio}
+%D macro provides the value.
+
+\def\folio{\the\pageno} % kind of expected and therefore reserved
+
+%D The following registers are kind of standard and (for the moment)
+%D we define them here. This might change.
+
+\newskip \bigskipamount \bigskipamount = 12pt plus 4pt minus 4pt
+\newskip \medskipamount \medskipamount = 6pt plus 2pt minus 2pt
+\newskip \smallskipamount \smallskipamount = 3pt plus 1pt minus 1pt
+
+\baselineskip = 12pt
+\lineskip = 1pt
+\lineskiplimit = 0pt
+
+%D Again a few kind-of-extensions the core:
+
+\newskip \hideskip \hideskip = -1000pt plus 1fill
+\newskip \centering \centering = 0pt plus 1000pt minus 1000pt
+
+\def\hidewidth % for alignment entries that can stick out
+ {\hskip\hideskip}
+
+\def\ialign % initialized \halign
+ {\everycr{}%
+ \tabskip\zeroskip
+ \halign}
+
+\newcount \mscount
+
+\def\spanomit{\span\omit} % bypass error message
+
+\def\multispan#1%
+ {\omit
+ \mscount#1\relax
+ \loop
+ \ifnum\mscount>\plusone
+ \spanomit \advance\mscount\minusone
+ \repeat}
+
+%D The next section deals with selective definitions in
+%D later modules. One can of course use the \type {\texengine}
+%D number that we defined earlier instead.
+
+\bgroup \obeylines
+ \gdef\pickupSOMETEX#1%
+ {\expandafter\gdef\csname begin#1\endcsname{\bgroup\obeylines\dopickupSOMETEX{#1}}}
+ \gdef\dopickupSOMETEX#1#2
+ % {\egroup\immediate\write16{special code for #1 -> [line \the\inputlineno] \detokenize{#2}}}
+ {\egroup}
+\egroup
+
+\let\endTEX \relax \long\def\beginTEX #1\endTEX {}
+\let\endETEX \relax \long\def\beginETEX #1\endETEX {}
+\let\endXETEX \relax \long\def\beginXETEX #1\endXETEX {}
+\let\endLUATEX\relax \long\def\beginLUATEX#1\endLUATEX{}
+\let\endOLDTEX\relax \long\def\beginOLDTEX#1\endOLDTEX{}
+\let\endNEWTEX\relax \long\def\beginNEWTEX#1\endNEWTEX{}
+
+\pickupSOMETEX{ETEX}
+
+\ifnum\texengine=\xetexengine
+ \pickupSOMETEX{XETEX}
+\fi
+\ifnum\texengine=\luatexengine
+ \pickupSOMETEX{LUATEX}
+\fi
+\ifnum\texengine<\xetexengine
+ \pickupSOMETEX{OLDTEX}
+\else
+ \pickupSOMETEX{NEWTEX}
+\fi
+
+%D \macros
+%D {bindprimitive}
+%D
+%D We can remap primitives (which is needed because of changes in
+%D for instance \PDFTEX).
+
+\def\bindprimitive#1 #2 % new old
+ {\ifcsname#1\endcsname \else \ifcsname#2\endcsname
+ \expandafter\let\csname#1\expandafter\endcsname\csname#2\endcsname
+ \fi \fi}
+
+%D Because \XETEX\ also implements some \PDFTEX\ functionality, we take
+%D care of this here instead of a dedicated module. Later modules need
+%D to handle the undefined cases.
+
+%D These messy checks will disappear.
+
+% new after 1.10, watch the change in prefix
+
+\bindprimitive quitvmode ptexquitvmode
+\bindprimitive noligatures ptexnoligatures
+\bindprimitive setrandomseed ptexsetrandomseed
+\bindprimitive uniformdeviate ptexuniformdeviate
+
+\bindprimitive quitvmode pdfquitvmode
+\bindprimitive noligatures pdfnoligatures
+\bindprimitive setrandomseed pdfsetrandomseed
+\bindprimitive uniformdeviate pdfuniformdeviate
+
+\bindprimitive resettimer pdfresettimer
+\bindprimitive elapsedtime pdfelapsedtime
+
+% new per 1.40
+
+\bindprimitive ifprimitive ifpdfprimitive
+\bindprimitive primitive pdfprimitive
+\bindprimitive ifabsdim ifpdfabsdim
+\bindprimitive ifabsnum ifpdfabsnum
+
+\ifnum\texengine=\xetexengine \else % this test might disappear some day
+
+ \pdfminorversion \plusfive
+
+ \ifdefined\pdfcompresslevel \else \newcount\pdfcompresslevel \fi
+ \ifdefined\pdfobjcompresslevel \else \newcount\pdfobjcompresslevel \fi
+ \ifdefined\pdfgentounicode \else \newcount\pdfgentounicode \fi \pdfgentounicode\plusone
+
+ \def\nopdfcompression {\pdfobjcompresslevel\zerocount \pdfcompresslevel\zerocount}
+ \def\maximumpdfcompression{\pdfobjcompresslevel\plusone \pdfcompresslevel\plusnine }
+ \def\normalpdfcompression {\pdfobjcompresslevel\plusone \pdfcompresslevel\plusthree}
+
+ \normalpdfcompression
+
+ \let\normalsetrandomseed \setrandomseed
+ \let\normaluniformdeviate\uniformdeviate
+
+\fi
+
+%D Handy.
+
+\ifnum\texengine=\luatexengine
+ \ifdefined\suppresslongerror % for the moment test
+ \suppresslongerror\plusone
+ \fi
+\fi
+
+%D Basic status stuff.
+
+\newif\ifproductionrun
+
+%D We need to make sure that we start up in \DVI\ mode, so,
+%D after testing for running \PDFTEX, we default to \DVI.
+
+\ifx\pdftexversion\undefined \newcount\pdfoutput \fi \pdfoutput=0
+
+%D For those who expect this \unknown
+
+\ifx\fmtname \undefined \def\fmtname {ConTeXt Minimized Plain TeX} \fi
+\ifx\fmtversion\undefined \def\fmtversion{3.1415926} \fi
+
+\let\normalfmtversion\fmtversion
+
+%D A few bonus macros:
+
+\def\modulonumber#1#2{\the\numexpr#2-((((#2+(#1/2))/#1)-1)*#1)\relax}
+\def\dividonumber#1#2{\the\numexpr(#2-(#1/2))/#1\relax}
+
+\ifnum\texengine=\xetexengine
+ \edef\xetexversion {\numexpr\XeTeXversion*100+(\expandafter\gobbleoneargument\XeTeXrevision-5)/10\relax}
+ \edef\xetexrevision {\the\numexpr(\expandafter\gobbleoneargument\XeTeXrevision-50)/100\relax}
+\fi
+
+\ifcase\texengine
+ \def\texenginename {impossible}
+ \edef\texengineversion{0}
+\or
+ \def\texenginename {pdfTeX}
+ \edef\texengineversion{\dividonumber{100}\pdftexversion.\modulonumber{100}\pdftexversion.\pdftexrevision}
+\or
+ \def\texenginename {XeTeX}
+ \edef\texengineversion{\dividonumber{100}\xetexversion .\modulonumber{100}\xetexversion .\xetexrevision}
+\or
+ \def\texenginename {LuaTeX}
+ \edef\texengineversion{\dividonumber{100}\luatexversion.\modulonumber{100}\luatexversion.\luatexrevision}
+\else
+ \def\texenginename {impossible}
+ \edef\texengineversion{0}
+\fi
+
+%D While cleaning this code up a bit I was listening to Heather
+%D Nova's \CD\ Redbird. The first song on that \CD\ ends with
+%D a few lines suitable for ending this initialization module:
+%D
+%D \startlines
+%D And there's so much I can do for you
+%D Given time I know that I can prove
+%D Now my world is opened up to you
+%D Come inside
+%D
+%D Welcome to my life
+%D Welcome to my world
+%D Come inside
+%D \stoplines
+%D
+%D So let's see what \TEX\ can do now that we've opened up
+%D the basic machinery.
+
+\protect \endinput
diff --git a/tex/context/base/syst-lua.lua b/tex/context/base/syst-lua.lua
new file mode 100644
index 000000000..e3d3ce01a
--- /dev/null
+++ b/tex/context/base/syst-lua.lua
@@ -0,0 +1,91 @@
+if not modules then modules = { } end modules ['syst-lua'] = {
+ version = 1.001,
+ comment = "companion to syst-lua.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, texprint, texwrite, texiowrite_nl = tex.sprint, tex.print, tex.write, texio.write_nl
+local format = string.format
+
+local ctxcatcodes = tex.ctxcatcodes
+
+commands = commands or { } cs = commands -- shorter
+
+ctx = ctx or { } -- special context namespace, code might move from there
+
+function commands.writestatus(a,b,c,...)
+ if c then
+ texiowrite_nl(format("%-16s: %s\n",a,format(b,c,...)))
+ else
+ texiowrite_nl(format("%-16s: %s\n",a,b)) -- b can have %'s
+ end
+end
+
+function commands.doifelse(b)
+ if b then -- faster with if than with expression
+ texsprint(ctxcatcodes,"\\firstoftwoarguments")
+ else
+ texsprint(ctxcatcodes,"\\secondoftwoarguments")
+ end
+end
+function commands.doif(b)
+ if b then
+ texsprint(ctxcatcodes,"\\firstofoneargument")
+ else
+ texsprint(ctxcatcodes,"\\gobbleoneargument")
+ end
+end
+function commands.doifnot(b)
+ if b then
+ texsprint(ctxcatcodes,"\\gobbleoneargument")
+ else
+ texsprint(ctxcatcodes,"\\firstofoneargument")
+ end
+end
+
+commands.testcase = commands.doifelse
+
+function commands.boolcase(b)
+ if b then texwrite(1) else texwrite(0) end
+end
+
+function commands.doifelsespaces(str)
+ return commands.doifelse(str:find("^ +$"))
+end
+
+local s = lpeg.Ct(lpeg.splitat(","))
+local h = { }
+
+function commands.doifcommonelse(a,b)
+ local ha = h[a]
+ local hb = h[b]
+ if not ha then ha = s:match(a) h[a] = ha end
+ if not hb then hb = s:match(b) h[b] = hb end
+ for i=1,#ha do
+ for j=1,#hb do
+ if ha[i] == hb[j] then
+ return commands.testcase(true)
+ end
+ end
+ end
+ return commands.testcase(false)
+end
+
+function commands.doifinsetelse(a,b)
+ local hb = h[b]
+ if not hb then hb = s:match(b) h[b] = hb end
+ for i=1,#hb do
+ if a == hb[i] then
+ return commands.testcase(true)
+ end
+ end
+ return commands.testcase(false)
+end
+
+function commands. def (cs,value) texsprint(ctxcatcodes,format( "\\def\\%s{%s}",cs,value)) end
+function commands.edef (cs,value) texsprint(ctxcatcodes,format("\\edef\\%s{%s}",cs,value)) end
+function commands.gdef (cs,value) texsprint(ctxcatcodes,format("\\gdef\\%s{%s}",cs,value)) end
+function commands.xdef (cs,value) texsprint(ctxcatcodes,format("\\xdef\\%s{%s}",cs,value)) end
+function commands.chardef(cs,value) texsprint(ctxcatcodes,format("\\chardef\\%s=%s\\relax",cs,value)) end
diff --git a/tex/context/base/syst-lua.tex b/tex/context/base/syst-lua.tex
new file mode 100644
index 000000000..40cd9f756
--- /dev/null
+++ b/tex/context/base/syst-lua.tex
@@ -0,0 +1,37 @@
+%D \module
+%D [ file=syst-lua,
+%D version=2008.01.25,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=Helper macros based on \LUA,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\registerctxluafile{syst-lua}{1.001}
+
+\unprotect
+
+\def\expdoifelse#1#2{\ctxlua{commands.doifelse(\!!bs#1\!!es==\!!bs#2\!!es)}}
+\def\expdoif #1#2{\ctxlua{commands.doif (\!!bs#1\!!es==\!!bs#2\!!es)}}
+\def\expdoifnot #1#2{\ctxlua{commands.doifnot (\!!bs#1\!!es==\!!bs#2\!!es)}}
+
+% \testfeatureonce{100000}{\doifelse{hello world}{here i am}{}} % 0.3
+% \testfeatureonce{100000}{\expandabledoifelse{hello world}{here i am}{}} % 1.5
+
+\def\expdoifcommonelse#1#2{\ctxlua{commands.doifcommonelse("#1","#2")}}
+\def\expdoifinsetelse #1#2{\ctxlua{commands.doifinsetelse("#1","#2")}}
+
+% we define these here, just in case ...
+
+\def\luastringsep{===} % this permits \typefile{self} otherwise nested b/e sep problems
+
+\edef\!!bs{[\luastringsep[}
+\edef\!!es{]\luastringsep]}
+
+\def\writestatus#1#2{\ctxlua{commands.writestatus(\!!bs#1\!!es,\!!bs#2\!!es)}}
+
+\protect \endinput
diff --git a/tex/context/base/syst-mtx.tex b/tex/context/base/syst-mtx.tex
deleted file mode 100644
index e2a978671..000000000
--- a/tex/context/base/syst-mtx.tex
+++ /dev/null
@@ -1,80 +0,0 @@
-%D \module
-%D [ file=syst-mtx,
-%D version=2006.08.11,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=\METATEX\ specifics,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\ifx\directlua\undefined \endinput \fi
-
-\unprotect
-
-\ifnum\contextmarkmode=2
-
- \input enco-utf.tex
-
- % patch needed for turkish
-
- \setcclcuc 201C 201C 201C
- \setcclcuc 201D 201D 201D
-
-\fi
-
-
-%D Since the number of chars exceed 256 now, we can use \type
-%D {\chardef} instead of the more limited \type {\mathchardef}.
-
-\def\newcount {\myalloc@0\count \countdef \@@maxallocation}
-\def\newdimen {\myalloc@1\dimen \dimendef \@@maxallocation}
-\def\newskip {\myalloc@2\skip \skipdef \@@maxallocation}
-\def\newmuskip {\myalloc@3\muskip \muskipdef \@@maxallocation}
-\def\newbox {\myalloc@4\box \chardef \@@maxallocation}
-\def\newtoks {\myalloc@5\toks \toksdef \@@maxallocation}
-\def\newread {\myalloc@6\read \chardef \@@minallocation}
-\def\newwrite {\myalloc@7\write \chardef \@@minallocation}
-\def\newmarks {\myalloc@8\marks \chardef \@@maxallocation}
-\def\newlanguage{\myalloc@9\language\chardef \@@minallocation}
-
-\def\newfam#1{\chardef#1=15 }
-
-\def\topofboxstack{\number\count24 }
-
-\count18=1
-
-\mathchardef\@@minallocation = 16
-\mathchardef\@@medallocation = 256
-\mathchardef\@@maxallocation = 32767
-\chardef \@@insallocation = 128 % was 32, but if we want continuous ranges (mplib) we need to pass 256 soon 32
-
-\def\myalloc@#1#2#3#4#5%
- {\global\advance\count1#1by\@ne
- \ifnum\count1#1>\@@medallocation \else
- \ifnum\count1#1<\numexpr\@@medallocation-\@@insallocation\relax\else
- \global\count1#1=\numexpr\@@medallocation+\@ne\relax % \wait
- \fi
- \fi
- \ifnum\count1#1>#4%
- \global\count1#1=#4%
- \errmessage{No room for (\string#2) \string#5}%
- \fi
- \allocationnumber=\count1#1%
- \global#3#5=\allocationnumber
- \wlog{\string#5=\string#2\the\allocationnumber}}
-
-\def\newinsert#1%
- {\ifnum\insc@unt>\numexpr\@@medallocation-\@@insallocation\relax
- \global\advance\insc@unt by\m@ne
- \allocationnumber=\insc@unt
- \global\chardef#1=\allocationnumber
- \wlog{\string#1=\string\insert\the\allocationnumber}%
- \else
- \errmessage{No room for a new insert \string#1 (\number\insc@unt)}%
- \fi}
-
-\protect \endinput
diff --git a/tex/context/base/syst-new.tex b/tex/context/base/syst-new.tex
index 92d1ea192..53ba18ffd 100644
--- a/tex/context/base/syst-new.tex
+++ b/tex/context/base/syst-new.tex
@@ -814,25 +814,6 @@
\def\ignoreimplicitspaces
{\doifnextcharelse\relax\relax\relax}
-%D \macros
-%D {newconstant}
-
-\beginETEX
-
-\def\newconstant#1%
- {\def\donewconstant{\xdef#1{\numexpr\the\scratchcounter\relax}}%
- \afterassignment\donewconstant\scratchcounter}
-
-\endETEX
-
-\beginTEX
-
-\def\newconstant#1%
- {\def\donewconstant{\xdef#1{\the\scratchcounter\space}}
- \afterassignment\donewconstant\scratchcounter}
-
-\endTEX
-
% new
%
% \startnointerference
@@ -847,7 +828,7 @@
\def\stopnointerference
{\egroup
- \setbox\nointerferencebox\box\voidb@x}
+ \setbox\nointerferencebox\emptybox}
\protect \endinput
diff --git a/tex/context/base/syst-omg.tex b/tex/context/base/syst-omg.tex
deleted file mode 100644
index 01f140dac..000000000
--- a/tex/context/base/syst-omg.tex
+++ /dev/null
@@ -1,79 +0,0 @@
-%D \module
-%D [ file=syst-omg,
-%D version=2000.09.09,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=A couple of Omega goodies,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-%D This module will become obsolete as soon as Omega
-%D supports \ETEX\ functionality.
-
-\ifx\OmegaVersion\undefined \endinput \fi
-
-\unprotect
-
-\def\newcount {\myalloc@0\count \countdef \@@maxallocation}
-\def\newdimen {\myalloc@1\dimen \dimendef \@@maxallocation}
-\def\newskip {\myalloc@2\skip \skipdef \@@maxallocation}
-\def\newmuskip {\myalloc@3\muskip \muskipdef \@@maxallocation}
-\def\newbox {\myalloc@4\box \mathchardef\@@maxallocation}
-\def\newtoks {\myalloc@5\toks \toksdef \@@maxallocation}
-\def\newread {\myalloc@6\read \chardef \@@minallocation}
-\def\newwrite {\myalloc@7\write \chardef \@@minallocation}
-\def\newmarks {\myalloc@8\marks \mathchardef\@@maxallocation}
-\def\newlanguage{\myalloc@9\language\chardef \@@minallocation}
-
-\def\newfam#1{\chardef#1=15 }
-
-\def\topofboxstack{\number\count24 }
-
-\count18=1
-
-\mathchardef\@@minallocation = 16
-\mathchardef\@@medallocation = 256
-\mathchardef\@@maxallocation = 32767
-\chardef \@@insallocation = 32
-
-\def\myalloc@#1#2#3#4#5%
- {\global\advance\count1#1by\@ne
- \ifnum\count1#1>\@@medallocation \else
- \ifnum\count1#1<\numexpr\@@medallocation-\@@insallocation\relax\else
- \global\count1#1=\numexpr\@@medallocation+\@ne\relax % \wait
- \fi
- \fi
- \ifnum\count1#1>#4%
- \global\count1#1=#4%
- \errmessage{No room for (\string#2) \string#5}%
- \fi
- \allocationnumber=\count1#1%
- \global#3#5=\allocationnumber
- \wlog{\string#5=\string#2\the\allocationnumber}}
-
-\def\newinsert#1%
- {\ifnum\insc@unt>\numexpr\@@medallocation-\@@insallocation\relax
- \global\advance\insc@unt by\m@ne
- \allocationnumber=\insc@unt
- \global\chardef#1=\allocationnumber
- \wlog{\string#1=\string\insert\the\allocationnumber}%
- \else
- \errmessage{No room for a new insert \string#1 (\number\insc@unt)}%
- \fi}
-
-%D We need to catch a (rather crappy) automatic OMEGA
-%D mechanism. Unfortunately loading of the SGML vectors
-%D happens automatically without control over the regime
-%D under which it takes place.
-
-\ifx\SGMLFontEntity\undefined \else
-
- \errmessage{This version of Omega is way to buggy (+ \string\SGMLFontEntity\space mess)!}
-
-\fi
-
-\protect \endinput
diff --git a/tex/context/base/syst-pdt.tex b/tex/context/base/syst-pdt.tex
deleted file mode 100644
index e241a9a2b..000000000
--- a/tex/context/base/syst-pdt.tex
+++ /dev/null
@@ -1,50 +0,0 @@
-%D \module
-%D [ file=syst-pdt,
-%D version=2006.08.11,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=\PDFTEX\ specifics,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\ifx\pdftexversion\undefined \endinput \fi
-
-\unprotect
-
-% new after 1.10, watch the change in prefix
-
-\bindprimitive quitvmode ptexquitvmode
-\bindprimitive noligatures ptexnoligatures
-\bindprimitive setrandomseed ptexsetrandomseed
-\bindprimitive uniformdeviate ptexuniformdeviate
-
-\bindprimitive quitvmode pdfquitvmode
-\bindprimitive noligatures pdfnoligatures
-\bindprimitive setrandomseed pdfsetrandomseed
-\bindprimitive uniformdeviate pdfuniformdeviate
-
-\bindprimitive resettimer pdfresettimer
-\bindprimitive elapsedtime pdfelapsedtime
-
-% new per 1.40
-
-\bindprimitive ifprimitive ifpdfprimitive
-\bindprimitive primitive pdfprimitive
-\bindprimitive ifabsdim ifpdfabsdim
-\bindprimitive ifabsnum ifpdfabsnum
-
-\def\nopdfcompression {\pdfobjcompresslevel 0 \pdfcompresslevel 0 }
-\def\maximumpdfcompression{\pdfobjcompresslevel 1 \pdfcompresslevel 9 }
-\def\normalpdfcompression {\pdfobjcompresslevel 1 \pdfcompresslevel 3 }
-
-\ifx\pdfobjcompresslevel\undefined \newcount\pdfobjcompresslevel \fi \normalpdfcompression
-\ifx\pdfgentounicode \undefined \newcount\pdfgentounicode \fi \pdfgentounicode=1
-
-\let\normalquitvmode \quitvmode
-\let\normalnoligatures\noligatures
-
-\protect
diff --git a/tex/context/base/syst-pln.tex b/tex/context/base/syst-pln.tex
index 9582c6508..f2b6129ff 100644
--- a/tex/context/base/syst-pln.tex
+++ b/tex/context/base/syst-pln.tex
@@ -11,259 +11,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D We used to load plain \TEX\ in a special way, but redefining
-%D a couple of primitives so that for instance font loading was
-%D ignored. For those interested, this loader is found in
-%D \type {syst-tex.tex}.
-
-%D This is a stripped down version of plain \TEX. We need this
-%D module to get started. Whole sections are missing here,
-%D like font loading and math. Thise are taken care of in
-%D dedicated modules. A few definitions are added (and
-%D marked as such).
-
-%D Characters can have special states, that can be triggered
-%D by setting their category coded. Some are preset, others
-%D are to be set as soon as possible, otherwise we cannot
-%D define any useful macros.
-
-%catcode`\^^@ = 9 % ascii null is ignored
-%catcode`\\ = 0 % backslash is TeX escape character
-
-\catcode`\{ = 1 % left brace is begin-group character
-\catcode`\} = 2 % right brace is end-group character
-\catcode`\$ = 3 % dollar sign is math shift
-\catcode`\& = 4 % ampersand is alignment tab
-\catcode`\# = 6 % hash mark is macro parameter character
-\catcode`\^ = 7 % circumflex and uparrow are for superscripts
-\catcode`\_ = 8 % underline and downarrow are for subscripts
-\catcode`\^^I = 10 % ascii tab is a blank space
-
-%catcode`\^^M = 5 % ascii return is end-line
-%catcode`\% = 14 % percent sign is comment character
-%catcode`\ = 10 % ascii space is blank space
-%catcode`\^^? = 15 % ascii delete is invalid
-
-\catcode`\~ = 13 % tilde is active
-\catcode`\^^L = 13 % ascii form-feed
-
-%catcode`\A = 11
-%.......
-%catcode`\Z = 11
-
-%catcode`\a = 11
-%.......
-%catcode`\z = 11
-
-\chardef\active = 13
-
-\def ^^L{\par}
-\def\^^M{\ } % control <return> = control <space>
-\def\^^I{\ } % same for <tab>
-
-%D In \CONTEXT, we simply ignore end||of||file tokens:
-
-\catcode`\^^Z=9
-
-%D First we define a simplified version of the \CONTEXT\
-%D protection mechanism.
-
-\def\unprotect{\catcode`@=11 }
-\def\protect {\catcode`@=12 }
-
\unprotect
-%D We do not set up mathcodes here, but postpone that to the
-%D math modules.
-
-\mathcode`\ = "8000 % \space
-\mathcode`\' = "8000 % ^\prime
-\mathcode`\_ = "8000 % \_
-\mathcode`\^^? = "1273 % \smallint
-
-\sfcode`\)=0
-\sfcode`\'=0
-\sfcode`\]=0
-
-\chardef\@ne = 1
-\chardef\tw@ = 2
-\chardef\thr@@ = 3
-\chardef\sixt@@n = 16
-\chardef\@cclv = 255
-
-\mathchardef\@cclvi = 256
-\mathchardef\@m = 1000
-\mathchardef\@M = 10000
-\mathchardef\@MM = 20000
-
-%D Pretty important definitions:
-
-\let\bgroup={
-\let\egroup=}
-
-%D In plain \TEX\ the following explanation about the register
-%D allocation mechanism is given:
-%D
-%D \startnarrower
-%D The following counters are reserved:
-%D
-%D \starttabulate
-%D \NC 0--9 \NC page numbering \NC \NR
-%D \NC 10 \NC count allocation \NC \NR
-%D \NC 11 \NC dimen allocation \NC \NR
-%D \NC 12 \NC skip allocation \NC \NR
-%D \NC 13 \NC muskip allocation \NC \NR
-%D \NC 14 \NC box allocation \NC \NR
-%D \NC 15 \NC toks allocation \NC \NR
-%D \NC 16 \NC read file allocation \NC \NR
-%D \NC 17 \NC write file allocation \NC \NR
-%D \NC 18 \NC math family allocation \NC \NR
-%D \NC 19 \NC language allocation \NC \NR
-%D \NC 20 \NC insert allocation \NC \NR
-%D \NC 21 \NC the most recently allocated number \NC \NR
-%D \NC 22 \NC constant $-1$ \NC \NR
-%D \stoptabulate
-%D
-%D New counters are allocated starting with 23, 24, etc. Other
-%D registers are allocated starting with 10. This leaves 0
-%D through 9 for the user to play with safely, except that
-%D counts 0 to 9 are considered to be the page and subpage
-%D numbers (since they are displayed during output). In this
-%D scheme, \type {\count10} always contains the number of the
-%D highest||numbered counter that has been allocated, \type
-%D {\count14} the highest||numbered box, etc. Inserts are given
-%D numbers 254, 253, etc., since they require a \type
-%D {\count}, \type {\dimen}, \type {\skip}, and \type {\box}
-%D all with the same number; \type {\count20} contains the
-%D lowest-numbered insert that has been allocated. Of course,
-%D \type {\box255} is reserved for \type {\output}; \type
-%D {\count255}, \type {\dimen255}, and \type {\skip255} can be
-%D used freely.
-%D
-%D It is recommended that macro designers always use \type
-%D {\globa}l assignments with respect to registers numbered 1,
-%D 3, 5, 7, 9, and always non||\type {\global} assignments
-%D with respect to registers 0, 2, 4, 6, 8, 255. This will
-%D prevent \quote {save stack buildup} that might otherwise
-%D occur.
-%D \stopnarrower
-%D
-%D We will overload some macros in \ETEX\ mode.
-
-\count10 = 22 % allocates \count registers 23, 24, ...
-\count11 = 9 % allocates \dimen registers 10, 11, ...
-\count12 = 9 % allocates \skip registers 10, 11, ...
-\count13 = 9 % allocates \muskip registers 10, 11, ...
-\count14 = 9 % allocates \box registers 10, 11, ...
-\count15 = 9 % allocates \toks registers 10, 11, ...
-\count16 = -1 % allocates input streams 0, 1, ...
-\count17 = -1 % allocates output streams 0, 1, ...
-\count18 = 3 % allocates math families 4, 5, ...
-\count19 = 0 % allocates \language codes 1, 2, ...
-\count20 =255 % allocates insertion classes 254, 253, ...
-
-\countdef\insc@unt = 20 % the insertion counter
-\countdef\allocationnumber= 21 % the most recent allocation
-\countdef\m@ne = 22 % a handy constant
- \m@ne = -1
-
-\def\wlog{\immediate\write\m@ne} % write on log file (only)
-
-%D \startnarrower
-%D Here are abbreviations for the names of scratch registers
-%D that don't need to be allocated.
-%D \stopnarrower
-
-\countdef \count@ = 255
-\dimendef \dimen@ = 0
-\dimendef \dimen@i = 1 % global only
-\dimendef \dimen@ii = 2
-\skipdef \skip@ = 0
-\toksdef \toks@ = 0
-
-%D \startnarrower
-%D Now, we define \type {\newcount}, \type {\newbox}, etc. so
-%D that you can say \newcount\foo and \type {\foo} will be
-%D defined (with \type {\countdef}) to be the next counter. To
-%D find out which counter \type {\foo} is, you can look at
-%D \type {\allocationnumber}. Since there's no \type {\boxdef}
-%D command, \type {\chardef} is used to define a \type
-%D {\newbox}, \type {\newinsert}, \type {\newfam}, and so on.
-%D \stopnarrower
-
-\def\newcount {\alloc@0\count \countdef \insc@unt}
-\def\newdimen {\alloc@1\dimen \dimendef \insc@unt}
-\def\newskip {\alloc@2\skip \skipdef \insc@unt}
-\def\newmuskip {\alloc@3\muskip \muskipdef\@cclvi }
-\def\newbox {\alloc@4\box \chardef \insc@unt}
-\def\newtoks {\alloc@5\toks \toksdef \@cclvi }
-\def\newread {\alloc@6\read \chardef \sixt@@n }
-\def\newwrite {\alloc@7\write \chardef \sixt@@n }
-\def\newfam {\alloc@8\fam \chardef \sixt@@n }
-\def\newlanguage{\alloc@9\language\chardef \@cclvi }
-
-\def\newhelp#1#2{\newtoks#1#1\expandafter{\csname#2\endcsname}}
-
-\def\alloc@#1#2#3#4#5%
- {\global\advance\count1#1by\@ne
- \ch@ck#1#4#2% make sure there's still room
- \allocationnumber=\count1#1%
- \global#3#5=\allocationnumber
- \wlog{\string#5=\string#2\the\allocationnumber}}
-
-\def\newinsert#1%
- {\global\advance\insc@unt by\m@ne
- \ch@ck0\insc@unt\count
- \ch@ck1\insc@unt\dimen
- \ch@ck2\insc@unt\skip
- \ch@ck4\insc@unt\box
- \allocationnumber=\insc@unt
- \global\chardef#1=\allocationnumber
- \wlog{\string#1=\string\insert\the\allocationnumber}}
-
-\def\ch@ck#1#2#3%
- {\ifnum\count1#1<#2\else
- \errmessage{No room for a new #3}
- \fi}
-
-\newdimen\maxdimen \maxdimen = 16383.99999pt
-\newskip \hideskip \hideskip = -1000pt plus 1fill
-\newskip \centering \centering = 0pt plus 1000pt minus 1000pt
-\newdimen\p@ \p@ = 1pt
-\newdimen\z@ \z@ = 0pt
-\newskip \z@skip \z@skip = 0pt plus 0pt minus 0pt
-\newbox \voidb@x % permanently void box register
-
-%D We define \type {\newif} a la plain \TEX, but will
-%D redefine it later. As Knuth says:
-%D
-%D \startnarrower
-%D And here's a different sort of allocation: for example,
-%D
-%D \starttyping
-%D \newif\iffoo
-%D \stoptyping
-%D
-%D creates \type {\footrue}, \type {\foofalse} to go
-%D with \type {\iffoo}.
-%D \stopnarrower
-
-\def\newif#1%
- {\count@\escapechar
- \escapechar\m@ne
- \expandafter\expandafter\expandafter\def\@if #1{true}{\let#1\iftrue }%
- \expandafter\expandafter\expandafter\def\@if#1{false}{\let#1\iffalse}%
- \@if#1{false}% the condition starts out false
- \escapechar\count@}
-
-\def\@if#1#2%
- {\csname\expandafter\if@\string#1#2\endcsname}
-
-\bgroup % `if' is required
-
- \uccode`1=`i \uccode`2=`f \uppercase{\gdef\if@12{}}
-
-\egroup
+%D This module set a couple of variables to the plain \TEX\
+%D values. Later they might be overloaded.
%D Build||in numeric variables.
@@ -297,7 +48,7 @@
%mag = 1000
%maxdeadcycles = 25
%month = 0
-\newlinechar = -1
+%newlinechar = -1 % commented i.e. no plain value
%outputpenalty = 0
%pausing = 0
%postdisplaypenalty = 0
@@ -323,14 +74,6 @@
\widowpenalty = 150
%year = 0
-%D Extra numeric variables.
-
-\newcount \interdisplaylinepenalty
-\newcount \interfootnotelinepenalty
-
-\interdisplaylinepenalty = 100
-\interfootnotelinepenalty = 100
-
%D Build in dimension variables.
\abovedisplayshortskip = 0pt plus 3pt
@@ -372,251 +115,4 @@
\vsize = 8.9in
%xspaceskip = 0pt
-%D Extra dimension parameters.
-
-\newskip \bigskipamount \bigskipamount = 12pt plus 4pt minus 4pt
-\newskip \medskipamount \medskipamount = 6pt plus 2pt minus 2pt
-\newskip \smallskipamount \smallskipamount = 3pt plus 1pt minus 1pt
-
-\newskip \normalbaselineskip \normalbaselineskip = 12pt
-\newskip \normallineskip \normallineskip = 1pt
-\newdimen \normallineskiplimit \normallineskiplimit = 0pt
-
-\newdimen \jot \jot = 3pt
-
-%D The following shortcuts are rather standard:
-
-\def\lq{`}
-\def\rq{'}
-
-\def\lbrack{[}
-\def\rbrack{]}
-
-\let\endgraf\par
-\let\endline\cr
-
-\def\space{ }
-\def\empty{}
-\def\null {\hbox{}}
-
-%D The next loop construct is about the fastest you can get.
-%D Beware: this macro does not support nested loops. We use
-%D a namespace prefix \type {@@pln}.
-
-\long\def\loop#1\repeat{\long\def\@@plnbody{#1}\@@plniterate}
-
-%D The following makes \type {\loop} \unknown\ \type {\if}
-%D \unknown\ \type {\repeat} skippable (clever trick):
-
-\let\repeat=\fi
-
-%D The original (no \type {@@pln} there):
-%D
-%D \starttyping
-%D \def\@@plniterate{\@@plnbody\let\next\@@plniterate\else\let\next\relax\fi\next}
-%D \stoptyping
-%D
-%D A more efficient alternative:
-%D
-%D \starttyping
-%D \def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\expandafter\relax\fi}
-%D \stoptyping
-%D
-%D An even more efficient one:
-
-\def\@@plniterate{\@@plnbody\expandafter\@@plniterate\else\fi}
-
-%D Counter 0 is normally used as page counter:
-
-\countdef\pageno=0 \pageno=1 % first page is number 1
-
-%D Beside the raw counter \type {\pageno} the \type {\folio}
-%D macro provides the value.
-
-\def\folio{\the\pageno}
-
-%D Indeed, we don't define a real output routine yet:
-
-\output{\box255}
-
-%D We don't support \type {\magnification} and just consume
-%D the value.
-
-\let\magnification\count@
-
-%D The following macro will be overloaded in \ETEX.
-
-\def\tracingall
- {\tracingonline \@ne
- \tracingcommands \tw@
- \tracingstats \tw@
- \tracingpages \@ne
- \tracingoutput \@ne
- \tracinglostchars \@ne
- \tracingmacros \tw@
- \tracingparagraphs\@ne
- \tracingrestores \@ne
- \showboxbreadth \maxdimen
- \showboxdepth \maxdimen
- \errorstopmode}
-
-%D Some users expect this macro to be present. This one
-%D sends the hyphenated word to the terminal.
-
-\def\showhyphens#1%
- {\setbox0\vbox
- {\parfillskip\z@skip
- \hsize\maxdimen\tenrm
- \pretolerance\m@ne
- \tolerance\m@ne
- \hbadness0
- \showboxdepth0
- \ #1}}
-
-%D The following bunch of macros deals with basic alignment.
-%D We just include them here so that they can be used if
-%D needed. Normally, \CONTEXT\ users will fall back on one of
-%D the three table environments.
-
-\newcount \mscount
-\newif \ifus@
-\newif \if@cr
-\newbox \tabs
-\newbox \tabsyet
-\newbox \tabsdone
-
-\def\hidewidth % for alignment entries that can stick out
- {\hskip\hideskip}
-
-\def\ialign % initialized \halign
- {\everycr{}
- \tabskip\z@skip
- \halign}
-
-\def\multispan#1%
- {\omit
- \mscount#1\relax
- \loop
- \ifnum\mscount>\@ne \sp@n
- \repeat}
-
-\def\sp@n
- {\span
- \omit
- \advance\mscount\m@ne}
-
-% begin of tab code
-
-\def\cleartabs
- {\global\setbox\tabsyet\null
- \setbox\tabs\null}
-
-\def\settabs
- {\setbox\tabs\null
- \futurelet\next\sett@b}
-
-\def\sett@b
- {\ifx\next\+%
- \def\nxt{\afterassignment\s@tt@b\let\nxt}%
- \else
- \let\nxt\s@tcols
- \fi
- \let\next\relax
- \nxt}
-
-\def\s@tt@b
- {\let\nxt\relax
- \us@false\m@ketabbox}
-
-\def\tabalign
- {\us@true\m@ketabbox}
-
-\let\+\tabalign % no outer here
-
-\def\s@tcols#1\columns
- {\count@#1%
- \dimen@\hsize
- \loop
- \ifnum\count@>\z@ \@nother
- \repeat}
-
-\def\@nother
- {\dimen@ii\dimen@
- \divide\dimen@ii\count@
- \setbox\tabs\hbox{\hbox to\dimen@ii{}\unhbox\tabs}%
- \advance\dimen@-\dimen@ii
- \advance\count@\m@ne}
-
-\def\m@ketabbox
- {\begingroup
- \global\setbox\tabsyet\copy\tabs
- \global\setbox\tabsdone\null
- \def\cr
- {\@crtrue\crcr\egroup\egroup
- \ifus@\unvbox\z@\lastbox\fi\endgroup
- \setbox\tabs\hbox{\unhbox\tabsyet\unhbox\tabsdone}}%
- \setbox\z@\vbox\bgroup\@crfalse
- \ialign\bgroup&\t@bbox##\t@bb@x\crcr}
-
-\def\t@bbox
- {\setbox\z@\hbox\bgroup}
-
-\def\t@bb@x
- {\if@cr
- \egroup % now \box\z@ holds the column
- \else
- \hss\egroup
- \global\setbox\tabsyet\hbox
- {\unhbox\tabsyet\global\setbox\@ne\lastbox}% now \box\@ne holds its size
- \ifvoid\@ne
- \global\setbox\@ne\hbox to\wd\z@{}%
- \else
- \setbox\z@\hbox to\wd\@ne{\unhbox\z@}%
- \fi
- \global\setbox\tabsdone\hbox{\box\@ne\unhbox\tabsdone}%
- \fi
- \box\z@}
-
-% end to tab code
-
-%D Useful, used too, but sometimes dangerous:
-
-\def\leavevmode{\unhbox\voidb@x}
-
-%D We will overload these, but may need them beforehand:
-
-\bgroup
- \catcode`\^^M=\active%
- \gdef\obeylines{\catcode`\^^M\active \let^^M\par}%
- \global\let^^M\par%
-\egroup
-
-\def\obeyspaces{\catcode`\ \active}
-
-{\obeyspaces\global\let =\space}
-
-%D Useful and expected:
-
-\def~{\penalty\@M \ } % tie
-
-\chardef\%=`\%
-\chardef\&=`\&
-\chardef\#=`\#
-\chardef\$=`\$
-
-%def\_{\leavevmode \kern.06em \vbox{\hrule width.3em}}
-\def\_{\dontleavehmode \kern.06em \vbox{\hrule width.3em}}
-
-%D Replaced later on:
-
-\def\line {\hbox to\hsize}
-\def\leftline #1{\line{#1\hss}}
-\def\rightline #1{\line{\hss#1}}
-\def\centerline#1{\line{\hss#1\hss}}
-
-%D Let's end in the plain way:
-
-\ifx\fmtname \undefined \def\fmtname {ConTeXt Minimized Plain TeX} \fi
-\ifx\fmtversion\undefined \def\fmtversion{3.1415926} \fi
-
\protect \endinput
diff --git a/tex/context/base/syst-prm.tex b/tex/context/base/syst-prm.tex
deleted file mode 100644
index dc259dff7..000000000
--- a/tex/context/base/syst-prm.tex
+++ /dev/null
@@ -1,227 +0,0 @@
-%D \module
-%D [ file=syst-prm,
-%D version=1999.03.17,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Primitive Behavior,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\unprotect
-
-%D Saved primitives are preceded by \type {\normal}, as in:
-
-\let\normalfmtversion\fmtversion
-
-%D When applicable, we also load the \ETEX\ source and
-%D definition files.
-
-\bgroup \obeylines
-
-\ifx\eTeXversion\undefined
-
- \long\gdef\beginETEX#1\endETEX%
- {}
-
- \gdef\beginTEX%
- {\bgroup\obeylines\dobeginTEX}
-
- \gdef\dobeginTEX#1
- {\egroup}
-
- \global\let\endTEX\relax
-
-\else
-
- \long\gdef\beginTEX#1\endTEX%
- {}
-
- \gdef\beginETEX%
- {\bgroup\obeylines\dobeginETEX}
-
-% \gdef\dobeginETEX#1
-% {\egroup\immediate\write16%
-% {system (E-TEX) : [line \the\inputlineno] \detokenize{#1}}}
-
- \gdef\dobeginETEX#1
- {\egroup}
-
- \global\let\endETEX\relax
-
-\fi
-
-\ifx\OmegaVersion\undefined
-
- \long\gdef\beginOMEGA#1\endOMEGA%
- {}
-
-\else
-
- \gdef\beginOMEGA%
- {\bgroup\obeylines\dobeginOMEGA}
-
- \ifx\detokenize\undefined
-
- \gdef\dobeginOMEGA#1
- {\egroup\immediate\write16%
- {system (OMEGA) : [line \the\inputlineno] \string#1 }} % we assume an argument
-
- \else
-
- \gdef\dobeginOMEGA#1
- {\egroup\immediate\write16%
- {system (OMEGA) : [line \the\inputlineno] \detokenize{#1}}} % we assume aleph
-
- \fi
-
- \global\let\endOMEGA\relax
-
-\fi
-
-\ifx\XeTeXversion\undefined
-
- \long\gdef\beginXETEX#1\endXETEX%
- {}
-
-\else
-
- \gdef\beginXETEX%
- {\bgroup\obeylines\dobeginXETEX}
-
- \gdef\dobeginXETEX#1
- {\egroup\immediate\write16%
- {system (XETEX) : [line \the\inputlineno] \detokenize{#1}}}
-
- \global\let\endXETEX\relax
-
-\fi
-
-\ifx\directlua\undefined
-
- \long\gdef\beginLUATEX#1\endLUATEX%
- {}
-
-\else
-
- \gdef\beginLUATEX%
- {\bgroup\obeylines\dobeginLUATEX}
-
- \gdef\dobeginLUATEX#1
- {\egroup\immediate\write16%
- {system (LUATEX) : [line \the\inputlineno] \detokenize{#1}}}
-
- \global\let\endLUATEX\relax
-
-\fi
-
-% traditional tex's vs de utf tex's
-
-\ifx\XeTeXversion\undefined \ifx\directlua\undefined
-
- \gdef\beginOLDTEX%
- {\bgroup\obeylines\dobeginOLDTEX}
-
- \gdef\dobeginOLDTEX#1
- {\egroup\immediate\write16%
- {system (OLDTEX) : [line \the\inputlineno] \detokenize{#1}}}
-
- \global\let\endOLDTEX\relax
-
- \long\gdef\beginNEWTEX#1\endNEWTEX%
- {}
-
-\fi \fi \ifx\beginOLDTEX\undefined
-
- \long\gdef\beginOLDTEX#1\endOLDTEX%
- {}
-
- \gdef\beginNEWTEX%
- {\bgroup\obeylines\dobeginNEWTEX}
-
- \gdef\dobeginNEWTEX#1
- {\egroup\immediate\write16%
- {system (NEWTEX) : [line \the\inputlineno] \detokenize{#1}}}
-
- \global\let\endNEWTEX\relax
-
-\fi
-
-\egroup
-
-%D Let's get rid of this one:
-
-\def\wlog#1{}
-
-%D Just for tracing purposes we set:
-
-\tracingstats=1
-
-%D We don't like outer commands, and we always want access
-%D to the original \type {\input} primitive.
-
-\let\normalouter = \outer \let\outer\relax
-\let\normalinput = \input
-
-%D We need to make sure that we start up in \DVI\ mode, so,
-%D after testing for running \PDFTEX, we default to \DVI.
-
-\ifx\pdftexversion\undefined \newcount\pdfoutput \fi \pdfoutput=0
-
-%D To circumvent dependencies, we can postpone certain
-%D initializations to dumping time, by appending them to the
-%D \type {\everydump} token register.
-
-\newtoks \everydump
-
-\let\normaldump \dump
-
-\def\dump{\the\everydump\normaldump}
-
-%D \macros
-%D {bindprimitive}
-
-\beginTEX
-
-\def\bindprimitive#1 #2 % new old
- {\expandafter\ifx\csname#1\endcsname\relax \expandafter\ifx\csname#2\endcsname\relax \else
- \expandafter\let\csname#1\expandafter\endcsname\csname#2\endcsname
- \fi\fi}
-
-\endTEX
-
-\beginETEX
-
-\def\bindprimitive#1 #2 % new old
- {\ifcsname#1\endcsname \else\ifcsname#2\endcsname
- \expandafter\let\csname#1\expandafter\endcsname\csname#2\endcsname
- \fi\fi}
-
-\endETEX
-
-% %D Ligature prevention (for instance, ec encoding has ligatures
-% %D in mono spaced fonts). Alas, we need to do some testing in order
-% %D to get to the ptex'd one.
-
-% \def\checkpdftexprimitive #1
-% {\expandafter\ifx\csname #1\endcsname\relax
-% \expandafter\ifx\csname pdf#1\endcsname\relax
-% \expandafter\ifx\csname ptex#1\endcsname\relax
-% \expandafter\let\csname normal#1\endcsname \undefined \else
-% \expandafter\let\csname normal#1\expandafter\endcsname\csname ptex#1\endcsname \fi \else
-% \expandafter\let\csname normal#1\expandafter\endcsname\csname pdf#1\endcsname \fi \else
-% \expandafter\let\csname normal#1\expandafter\endcsname\csname #1\endcsname \fi}
-
-% \checkpdftexprimitive quitvmode
-% \checkpdftexprimitive noligatures
-% \checkpdftexprimitive setrandomseed
-% \checkpdftexprimitive uniformdeviate
-
-%D We preserve \TEX's ending:
-
-\ifx\normalend\undefined \let\normalend\end \fi
-
-\protect \endinput
diff --git a/tex/context/base/syst-rtp.tex b/tex/context/base/syst-rtp.tex
deleted file mode 100644
index 958265f13..000000000
--- a/tex/context/base/syst-rtp.tex
+++ /dev/null
@@ -1,22 +0,0 @@
-%D \module
-%D [ file=syst-rtp, % copied from core-job
-%D version=1997.03.31,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Run Time Processes,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context Core Macros / Run Time Processes}
-
-\unprotect
-
-\let\executesystemcommand\gobbleoneargument
-
-\loadmarkfile{syst-rtp}
-
-\protect \endinput
diff --git a/tex/context/base/syst-str.mkii b/tex/context/base/syst-str.mkii
index e50df0103..3e6d043e3 100644
--- a/tex/context/base/syst-str.mkii
+++ b/tex/context/base/syst-str.mkii
@@ -64,7 +64,12 @@
\the\withuppercharacters
\relax}
-%D The string macros:
+%D I got tired of making dedicated clean up macros using the
+%D same mechanism again and again, so now we have:
+%D
+%D \starttyping
+%D \def\xxxx{abc.d} \replacecharacters\xxxx{a.}{-} \xxxx
+%D \stoptyping
\def\replacecharacters#1#2#3% macro characters replacement
{\bgroup
diff --git a/tex/context/base/syst-str.mkiv b/tex/context/base/syst-str.mkiv
index db3389ec0..57d76dc03 100644
--- a/tex/context/base/syst-str.mkiv
+++ b/tex/context/base/syst-str.mkiv
@@ -13,8 +13,17 @@
\unprotect
+% nb: these macros might go away !
+%
% todo: escape special chars in expr (\luaescapeexpression)
+%D I got tired of making dedicated clean up macros using the
+%D same mechanism again and again, so now we have:
+%D
+%D \starttyping
+%D \def\xxxx{abc.d} \replacecharacters\xxxx{a.}{-} \xxxx
+%D \stoptyping
+
\def\replacecharacters#1#2#3% macro characters replacement
{\dodoglobal\edef#1{\ctxlua{tex.sprint((string.gsub(\!!bs#1\!!es,\!!bs#2\!!es,"#3")))}}}
diff --git a/tex/context/base/syst-str.tex b/tex/context/base/syst-str.tex
deleted file mode 100644
index 15db004a3..000000000
--- a/tex/context/base/syst-str.tex
+++ /dev/null
@@ -1,40 +0,0 @@
-%D \module
-%D [ file=syst-str,
-%D version=2006.09.18,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=String Processing,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context System Macro's / Strings}
-
-%D These macros were defined elsewhere but for practical reasons
-%D we moved them here. This way we can more easily provide Mk IV
-%D support.
-
-\unprotect
-
-%D I got tired of making dedicated clean up macros using the
-%D same mechanism again and again, so now we have:
-%D
-%D \starttyping
-%D \def\xxxx{abc.d} \replacecharacters\xxxx{a.}{-} \xxxx
-%D \stoptyping
-
-\let\replacecharacters\gobblethreearguments % macro characters replacement
-
-%D Hm?
-
-\def\separatestring #1\to#2{}
-\def\unspacefilename#1\to#2{}
-
-%D Plugins:
-
-\loadmarkfile{syst-str}
-
-\protect \endinput
diff --git a/tex/context/base/syst-var.tex b/tex/context/base/syst-var.tex
deleted file mode 100644
index 8753017b5..000000000
--- a/tex/context/base/syst-var.tex
+++ /dev/null
@@ -1,18 +0,0 @@
-%D \module
-%D [ file=syst-var,
-%D version=2005.07.04, % moved code
-%D title=\CONTEXT\ System Macros,
-%D subtitle=Variables,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\writestatus{loading}{Context System Macro's / Variables}
-
-% will be used some day
-
-\endinput
diff --git a/tex/context/base/syst-xtx.tex b/tex/context/base/syst-xtx.tex
deleted file mode 100644
index a10173117..000000000
--- a/tex/context/base/syst-xtx.tex
+++ /dev/null
@@ -1,36 +0,0 @@
-%D \module
-%D [ file=syst-xtx,
-%D version=2004.09.11,
-%D title=\CONTEXT\ System Macros,
-%D subtitle=\XETEX\ specifics,
-%D author=Hans Hagen,
-%D date=\currentdate,
-%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
-%C
-%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
-
-\ifx\XeTeXversion\undefined \endinput \fi
-
-\unprotect
-
-%D For the moment, the only thing needed is to load are the
-%D mappings from lower to uppercase characters.
-
-\input enco-utf.tex
-
-% patch needed for turkish
-
-\setcclcucx 201C 201C 201C
-\setcclcucx 201D 201D 201D
-
-% patch needed for greek
-
-% \setcclcucx 1FFD 1FFD 1FFD
-
-\ifx\XeTeXuseglyphmetrics\undefined \else
- \XeTeXuseglyphmetrics=1
-\fi
-
-\protect \endinput
diff --git a/tex/context/base/core-ltb.tex b/tex/context/base/tabl-ltb.tex
index 3ebd16379..e45fb1bc1 100644
--- a/tex/context/base/core-ltb.tex
+++ b/tex/context/base/tabl-ltb.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=core-ltb,
%D version=2002.10.31,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Table Macros,
%D subtitle=Line Tables,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -55,7 +55,7 @@
% - clip on prev run
% - flush real widths
-\writestatus{loading}{Context Core Macros / Line Tables}
+\writestatus{loading}{ConTeXt Table Macros / Line Tables}
\unprotect
diff --git a/tex/context/base/core-ntb.tex b/tex/context/base/tabl-ntb.mkii
index 5bfba05ad..1f9a9d574 100644
--- a/tex/context/base/core-ntb.tex
+++ b/tex/context/base/tabl-ntb.mkii
@@ -1,7 +1,7 @@
%D \module
%D [ file=core-ntb,
%D version=2000.04.18,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Table Macros,
%D subtitle=Natural Tables,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -23,7 +23,7 @@
% optie=rek beschrijven
-\writestatus{loading}{Context Core Macros / Natural Tables}
+\writestatus{loading}{ConTeXt Table Macros / Natural Tables}
%D As always, this is the nth version. Much time went in
%D trying to speed up the many cell calculations, some
@@ -461,7 +461,6 @@
\def\parseTR[#1][#2]% [#2] is dummy that kills spaces / no #3 argument
{\currentcol\zerocount
\advance\maximumrow\plusone
- \let\eTR\relax % handy in \expanded
\iffirstargument\setTABLEparameters[\c!y\number\maximumrow][#1]\fi}
\def\settblref#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:x\endcsname}
@@ -637,16 +636,17 @@
% to be done: head <raw> foot, dus state var
-\long\def\bTABLEhead{\dosingleempty\doTABLEhead}
-\long\def\bTABLEnext{\dosingleempty\doTABLEnext}
-\long\def\bTABLEbody{\dosingleempty\doTABLEbody}
-\long\def\bTABLEfoot{\dosingleempty\doTABLEfoot}
+\unexpanded\def\bTABLEhead{\dosingleempty\doTABLEhead} \let\eTABLEhead\relax
+\unexpanded\def\bTABLEnext{\dosingleempty\doTABLEnext} \let\eTABLEnext\relax
+\unexpanded\def\bTABLEbody{\dosingleempty\doTABLEbody} \let\eTABLEbody\relax
+\unexpanded\def\bTABLEfoot{\dosingleempty\doTABLEfoot} \let\eTABLEfoot\relax
\long\def\doTABLEhead[#1]#2\eTABLEhead{\appendtoks\doTABLEsection[#1]{#2}\to\TBLhead}
\long\def\doTABLEnext[#1]#2\eTABLEnext{\appendtoks\doTABLEsection[#1]{#2}\to\TBLnext}
\long\def\doTABLEbody[#1]#2\eTABLEbody{\appendtoks\doTABLEsection[#1]{#2}\to\TBLbody}
\long\def\doTABLEfoot[#1]#2\eTABLEfoot{\appendtoks\doTABLEsection[#1]{#2}\to\TBLfoot}
+
\long\def\doTABLEsection[#1]#2%
{\def\setupTBLsection{\getparameters[\@@tbl\@@tbl][#1]}%
#2%
@@ -698,17 +698,22 @@
\maximumrowspan\plusone
\maximumcol\zerocount
\maximumrow\zerocount
- \def\bTR{\dodoubleempty\parseTR}%
- \def\bTD{\dodoubleempty\parseTD}%
- \def\bTH{\dodoubleempty\parseTH}%
- \def\bTN{\dodoubleempty\parseTN}}
+ \let\bTR\dobTR
+ \let\bTD\dobTD
+ \let\bTH\dobTH
+ \let\bTN\dobTN}
+
+\unexpanded\def\dobTR{\dodoubleempty\parseTR}
+\unexpanded\def\dobTD{\dodoubleempty\parseTD}
+\unexpanded\def\dobTH{\dodoubleempty\parseTH}
+\unexpanded\def\dobTN{\dodoubleempty\parseTN}
% permits \expanded{\bTD ... \eTD}
-\unexpanded\def\eTR{}
-\unexpanded\def\eTD{}
-\unexpanded\def\eTH{}
-\unexpanded\def\eTN{}
+\unexpanded\def\eTR{\ignorespaces}
+\unexpanded\def\eTD{\ignorespaces}
+\unexpanded\def\eTH{\ignorespaces}
+\unexpanded\def\eTN{\ignorespaces}
\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
{% tricky and dirty order -)
@@ -1478,15 +1483,21 @@
\presetlocalframed % breedte hoogte diepte offset
[\@@tbl\@@tbl]% % achtergrond, achtergrondraster, achtergrondkleur
% not ok yet
- \setupTABLE
- [\c!frameoffset=.5\linewidth,
+ \setupTABLE [%
+ \c!frameoffset=.5\linewidth,
\c!backgroundoffset=\v!frame,
\c!framecolor=\s!black,
+ \c!width=fit,
+ \c!height=fit,
+\c!autowidth=\v!yes,
+% \c!rulethickness=\linewidth,
+% \c!strut=\v!no,
+\c!strut=\v!yes, % needed for mathml, but ... maybe we need another resetTABLEmode
+\c!autostrut=\v!no,
\c!color=,
\c!style=,
\c!headstyle=,
\c!headcolor=,
- \c!strut=\v!no,
\c!aligncharacter=\v!no,
\c!alignmentcharacter={,},
\c!maxwidth=8em]%
diff --git a/tex/context/base/tabl-ntb.mkiv b/tex/context/base/tabl-ntb.mkiv
new file mode 100644
index 000000000..ca932a5d9
--- /dev/null
+++ b/tex/context/base/tabl-ntb.mkiv
@@ -0,0 +1,1571 @@
+%D \module
+%D [ file=core-ntb,
+%D version=2000.04.18,
+%D title=\CONTEXT\ Table Macros,
+%D subtitle=Natural Tables,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D This is an unfinished, preliminary module. At least two
+%D runs are needed to get the table fixed. Ugly code.
+
+% todo: special parsetb for argless variant
+% todo: protect \tbl...
+% todo: tblnx also count
+% todo: get rid of recurse
+% todo: fast if
+% todo: avoid halign (just do it manual) and thereby globals
+
+% optie=rek beschrijven
+
+\writestatus{loading}{ConTeXt Table Macros / Natural Tables}
+
+%D As always, this is the nth version. Much time went in
+%D trying to speed up the many cell calculations, some
+%D optimizations were rejected in order not to complicate this
+%D module too much (and in order to prevail extensibility).
+
+% shapebox fails here in mkii
+%
+% \setupcolors[state=start]
+% \bTABLE
+% \bTR [align=middle]\bTH Range\eTH{}\bTH Value\eTH{}\eTR
+% \bTR \bTD \type{<} 12\eTD{}\bTD 3\eTD{}\eTR
+% \bTR \bTD 12--16\eTD{}\bTD 2\eTD{}\eTR
+% \bTR \bTD \type{>}16\eTD{}\bTD 1\eTD{}\eTR
+% \eTABLE
+
+% \starttext
+% \placefigure[left]{}{}
+% \startlinecorrection \dontleavehmode \bTABLE
+% \bTR \bTD oeps \eTD \eTR
+% \eTABLE
+% \stoplinecorrection
+% \placefigure[right]{}{}
+% \startlinecorrection \dontleavehmode \bTABLE
+% \bTR \bTD oeps \eTD \eTR
+% \eTABLE
+% \stoplinecorrection
+% \stoptext
+
+%D To Do:
+%D
+%D \starttyping
+%D splitsen = ja | herhaal => als nofTH>1 then ja als herhaal
+%D \stoptyping
+
+%D To Do:
+%D
+%D \starttyping
+%D break over pagina
+%D kop herhalen
+%D reset settings
+%D
+%D \setupTABLE [c|column|x] [nx|odd|even|first|last][a=b]
+%D \setupTABLE [r|row |y] [nx|odd|even|first|last][a=b]
+%D \setupTABLE [nx|odd|even|first|last][ny|odd|even|first|last][a=b]
+%D \setupTABLE [nx|odd|even|first|last] [a=b]
+%D \setupTABLE [a=b]
+%D
+%D \bTH \eTH
+%D \stoptyping
+
+% the section setup does not work yet, data needs to be stored,
+% i.e.each row should know if it's a head/body/foot, and there
+% should be \setupTABLE[head]... and alike
+
+\unprotect
+
+%D A simple way to force equal line spacing is to say:
+%D
+%D \starttyping
+%D \def\bTBLCELL{\begstrut}
+%D \def\eTBLCELL{\endstrut}
+%D \stoptyping
+%D
+%D The next alternative also takes care of preceding and following
+%D white space.
+%D
+%D \startbuffer
+%D \bTABLE[left={(},right={)},top=\startnarrower,bottom=\stopnarrower]
+%D \bTR \bTD something \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\def\bTBLCELL % why not \doinhibitblank
+ {\inhibitblank
+ \doconvertfont\tbltblstyle\empty
+ \everypar{\tbltblleft\delayedbegstrut}}
+
+\def\eTBLCELL
+ {\ifhmode
+ \delayedendstrut
+ \tbltblright
+ \par % added 13/4/2006
+ \else
+ % not sure yet:\tbltblright
+ \par
+ \ifdim\prevdepth<\zeropoint % =-1000pt ?
+ \vskip-\strutdp
+ \else
+ \removebottomthings
+ \fi
+ \fi}
+
+\newcount\currenttbl
+
+\def\@@tbl{tbl} \def\tblcell{1} \def\tblnone{2}
+
+\def\@@tblprefix{tbl:} \let\@@rawtblprefix\@@tblprefix
+
+%D This should be done more efficient: soon
+
+% \let as well as \expandafter\edef's
+
+\newcounter\TBLlevel
+
+\def\@@tblprefix{\@@tbl:\ifnum\TBLlevel>1 :\TBLlevel:\fi}
+
+% \def\tblsetprefix % not yet used, figure out when .. may interfere with setup
+% {\edef\@@tblprefix{\@@tbl:\ifnum\TBLlevel>1 :\TBLlevel:\fi}}
+
+\def\settblnob#1{\expandafter\let\csname\@@tblprefix\number#1:b\endcsname\plusone}
+\def\gettblnob#1{\ifcsname\@@tblprefix\number#1:b\endcsname\plusone\else\zerocount\fi}
+
+\def\settbltag#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:s\endcsname}
+\def\settblcol#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:c\endcsname}
+\def\settblrow#1#2{\expandafter\edef\csname\@@tblprefix\number#1:\number#2:r\endcsname}
+
+\def\lettbltag#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:s\endcsname}
+\def\lettblcol#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:c\endcsname}
+\def\lettblrow#1#2{\expandafter\let\csname\@@tblprefix\number#1:\number#2:r\endcsname}
+
+\def\settblwd#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:wd\endcsname} % global !
+\def\settblht#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:ht\endcsname} % global !
+\def\lettblwd#1#2{\global\expandafter\let\csname\@@tblprefix\number#1:\number#2:wd\endcsname} % global !
+\def\lettblht#1#2{\global\expandafter\let\csname\@@tblprefix\number#1:\number#2:ht\endcsname} % global !
+
+\def\gettbltag#1#2{\csname\@@tblprefix\number#1:\number#2:s\endcsname}
+\def\gettblcol#1#2{\csname\@@tblprefix\number#1:\number#2:c\endcsname}
+\def\gettblrow#1#2{\csname\@@tblprefix\number#1:\number#2:r\endcsname}
+
+\def\gettblwd #1#2{\csname\@@tblprefix\number#1:\number#2:wd\endcsname}
+\def\gettblht #1#2{\csname\@@tblprefix\number#1:\number#2:ht\endcsname}
+
+\def\settblwid#1{\expandafter\xdef\csname\@@tblprefix\number#1:w\endcsname} % {#2} global !
+\def\settblhei#1{\expandafter\xdef\csname\@@tblprefix\number#1:h\endcsname} % {#2} global !
+\def\settbldis#1{\expandafter\xdef\csname\@@tblprefix\number#1:d\endcsname} % {#2} global !
+\def\settblaut#1{\expandafter\xdef\csname\@@tblprefix\number#1:a\endcsname} % {#2} global !
+
+\def\lettblwid#1{\global\expandafter\let\csname\@@tblprefix\number#1:w\endcsname} % {#2} global !
+\def\lettblhei#1{\global\expandafter\let\csname\@@tblprefix\number#1:h\endcsname} % {#2} global !
+\def\lettbldis#1{\global\expandafter\let\csname\@@tblprefix\number#1:d\endcsname} % {#2} global !
+\def\lettblaut#1{\global\expandafter\let\csname\@@tblprefix\number#1:a\endcsname} % {#2} global !
+
+\def\gettblwid#1{\ifcsname\@@tblprefix\number#1:w\endcsname\csname\@@tblprefix\number#1:w\endcsname\else\zeropoint\fi}
+\def\gettblhei#1{\ifcsname\@@tblprefix\number#1:h\endcsname\csname\@@tblprefix\number#1:h\endcsname\else\zeropoint\fi}
+\def\gettbldis#1{\ifcsname\@@tblprefix\number#1:d\endcsname\csname\@@tblprefix\number#1:d\endcsname\else\zeropoint\fi}
+\def\gettblaut#1{\csname \@@tblprefix\number#1:a\endcsname}
+
+\def\doiftbltag #1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument \fi}
+\def\doifnottbltag #1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\gobbleoneargument \else\@EA\firstofoneargument \fi}
+\def\doifelsetbltag#1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\@EA\firstoftwoarguments\else\@EA\secondoftwoarguments\fi}
+\def\doiftblrow #1#2{\ifcsname\@@tblprefix\number#1:\number#2:r\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument \fi}
+\def\doiftblcol #1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\@EA\firstofoneargument \else\@EA\gobbleoneargument \fi}
+\def\doifnottblcol #1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\@EA\gobbleoneargument \else\@EA\firstofoneargument \fi}
+
+\def\tbltagstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:s\endcsname\zerocount\else\plusone\fi}
+\def\tblrowstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:r\endcsname\zerocount\else\plusone\fi}
+\def\tblcolstate#1#2{\ifcsname\@@tblprefix\number#1:\number#2:c\endcsname\zerocount\else\plusone\fi}
+
+\def\settblspn #1{\expandafter\let\csname\@@tblprefix\number#1:s\endcsname \!!plusone}
+\def\doifelsetblspn#1{\doifelse {\csname\@@tblprefix\number#1:s\endcsname}\!!plusone}
+% \def\doifelsetblspn#1{\@EA\ifx\csname\@@tblprefix\number#1:s\endcsname\plusone\@EA\firstoftwoarguments\else\@EA\secondoftwoarguments\fi}
+
+\def\settblspn #1{\setvalue {\@@tblprefix\number#1:s}{1}}
+\def\doifelsetblspn#1{\doifelsevalue{\@@tblprefix\number#1:s}{1}}
+
+\long\def\settbltxt#1#2#3%
+ {\long\@EA\def\csname\@@tblprefix\number#1:\number#2:t\@EA\endcsname\@EA{\@EA\def\@EA\TBLlevel\@EA{\TBLlevel}#3}}
+
+\def\gettbltxt#1#2%
+ {\csname\@@tblprefix\number#1:\number#2:t\endcsname}
+
+\newtoks\tbltoks
+\newtoks\tblrowtoks
+
+\let\pushTBLparameters\relax
+\let\popTBLparameters \relax
+
+\newif\ifsqueezeTBLspan \squeezeTBLspantrue % spans one column cell over multi column par cells
+\newif\ifautosqueezeTBLspan \autosqueezeTBLspantrue % unless explicit widths are given
+\newif\ifautoTBLspread \autoTBLspreadfalse
+\newif\ifautoTBLhsize \autoTBLhsizetrue
+\newif\ifautoTBLrowspan \autoTBLrowspantrue
+\newif\ifautoTBLemptycell \autoTBLemptycelltrue
+\newif\ifautoTBLcheckwidth \autoTBLcheckwidthtrue
+\newif\ifappendTBLsetups \appendTBLsetupstrue
+\newif\ifenableTBLbreak \enableTBLbreakfalse
+\newif\ifmultipleTBLheads \multipleTBLheadsfalse
+
+\newif\iftraceTABLE \traceTABLEfalse
+
+\def\noftblheadlines{0}
+\def\noftblnextlines{0}
+\def\noftblhdnxlines{0}
+
+\long\def\handleTBLcell#1#2[#3]{}
+
+\long\def\bTC#1\eTC{\bTD#1\eTD}
+\long\def\bTX#1\eTX{\bTD#1\eTD}
+\long\def\bTY#1\eTY{\bTR#1\eTR}
+
+\let\getTABLEparameters\getparameters
+
+\unexpanded\def\setupTABLE
+ {\dotripleempty\dosetupTABLE}
+
+\def\dosetupTABLE[#1][#2][#3]%
+ {\ifthirdargument
+ \processaction
+ [#1]
+ [ \v!row=>{\dosetupTABLExy[\c!y][#2][#3]},%
+ \v!column=>{\dosetupTABLExy[\c!x][#2][#3]},%
+ r=>{\dosetupTABLExy[\c!y][#2][#3]},%
+ c=>{\dosetupTABLExy[\c!x][#2][#3]},%
+ y=>{\dosetupTABLExy[\c!y][#2][#3]},%
+ x=>{\dosetupTABLExy[\c!x][#2][#3]},%
+ \v!start=>{\dosetupTABLExy[#1][#2][#3]},%
+ \v!header=>{\dosetupTABLExy[#1][#2][#3]},%
+ \s!unknown=>{\dosetupTABLEzz[#1][#2][#3]}]%
+ \else\ifsecondargument
+ \processaction
+ [#1]
+ [ \v!row=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
+ \v!column=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
+ r=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
+ c=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
+ y=>{\dosetupTABLExy[\c!y][\v!each][#2]},%
+ x=>{\dosetupTABLExy[\c!x][\v!each][#2]},%
+ \v!start=>{\dosetupTABLExy[#1][\v!each][#2]},%
+ \v!header=>{\dosetupTABLExy[#1][\v!each][#2]},%
+ \s!unknown=>{\dosetupTABLEzz[\c!x][#1][#2]}]%
+ \else
+ \getparameters[\@@tbl\@@tbl][#1]%
+ \fi\fi}
+
+\def\dosetupTABLExy[#1][#2][#3]%
+ {\def\dodosetupTABLE##1{\setTABLEparameters[#1##1][#3]}%
+ \processcommalist[#2]\dodosetupTABLE}
+
+\def\dosetupTABLEzz[#1][#2][#3]%
+ {\def\dodosetupTABLE##1%
+ {\def\dododosetupTABLE####1{\setTABLEparameters[\c!x##1\c!y####1][#3]}%
+ \processcommalist[#2]\dododosetupTABLE}%
+ \processcommalist[#1]\dodosetupTABLE}
+
+\def\nopTABLEparameters[#1][#2]%
+ {\letvalue{\@@tblprefix#1}\empty}
+
+\def\setTABLEparameters[#1][#2]%
+ {\pushTBLparameters
+ \ifappendTBLsetups
+ \doifdefinedelse{\@@tblprefix#1}
+ {\def\getTABLEparameters[##1][##2]%
+ {\setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][##2,#2]}}%
+ \getvalue{\@@tblprefix#1}%
+ \let\getTABLEparameters\getparameters}
+ {\setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][#2]}}%
+ \else
+ \setvalue{\@@tblprefix#1}{\getTABLEparameters[\@@tbl\@@tbl][#2]}%
+ \fi
+ \popTBLparameters}
+
+\let\setupTBLsection\relax
+
+% % \setupTABLE [y] [first][background=color,backgroundcolor=blue,frame=off,bottomframe=on,topframe=on,framecolor=white]
+% \setupTABLE [first][first][backgroundcorner=2,corner=10,frame=on]
+% \setupTABLE [last] [first][backgroundcorner=4,corner=12,frame=on]
+%
+% \setupTABLE [row] [each] [background=color,backgroundcolor=blue,frame=on,framecolor=white]
+% \setupTABLE [first][2] [corner=8]
+% \setupTABLE [last] [2] [corner=5]
+% \setupTABLE [first][last] [corner=7]
+% \setupTABLE [last] [last] [corner=6]
+%
+% \startTEXpage
+% \bTABLE[frame=off,align=middle]
+% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR
+% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
+% \bTR \bTD alpha \eTD \bTD beta \eTD \bTD gamma \eTD \eTR
+% \eTABLE
+% \stopTEXpage
+%
+% \setupTABLE [first] [two][corner=2] % special case
+% \setupTABLE [last] [two][corner=4] % special case
+%
+% % % \setupTABLE [one] [first] ... special case of span
+%
+% \startTEXpage
+% \bTABLE[frame=off,align=middle]
+% \bTR \bTD one \eTD \bTD two \eTD \bTD three \eTD \eTR
+% \bTR \bTD first \eTD \bTD second \eTD \bTD third \eTD \eTR
+% \eTABLE
+% \stopTEXpage
+
+\def\setupTBLcell#1#2% cell over col over row
+ {\setupTBLsection % already forgotten
+ \edef\positiverow{\number#1}%
+ \edef\positivecol{\number#2}%
+ \edef\negativerow{\the\numexpr-\maximumrow+#1+\minusone\relax}%
+ \edef\negativecol{\the\numexpr-\maximumcol+#2+\minusone\relax}%
+ % each each
+ \csname\@@tblprefix\c!x\v!each\c!y\v!each\endcsname
+ \csname\@@tblprefix\c!y\v!each\endcsname
+ \csname\@@tblprefix\c!x\v!each\endcsname
+ % odd even
+ \csname\@@tblprefix\c!y\v!oddeven\positiverow\endcsname
+ \csname\@@tblprefix\c!x\v!oddeven\positivecol\endcsname
+ \csname\@@tblprefix\c!x\v!oddeven\positivecol\c!y\v!oddeven\positiverow\endcsname
+ % row/col number combinations
+ \ifcsname\@@tblprefix\c!y\positiverow\endcsname\csname\@@tblprefix\c!y\positiverow\endcsname\fi
+ \ifcsname\@@tblprefix\c!y\negativerow\endcsname\csname\@@tblprefix\c!y\negativerow\endcsname\fi
+ \csname\@@tbl\@@tbl\c!extras\endcsname
+ \@EA\let\csname\@@tbl\@@tbl\c!extras\endcsname\relax % new, see x-fo
+ \ifcsname\@@tblprefix\c!x\positivecol\endcsname\csname\@@tblprefix\c!x\positivecol\endcsname\fi
+ \ifcsname\@@tblprefix\c!x\negativecol\endcsname\csname\@@tblprefix\c!x\negativecol\endcsname\fi
+ \csname\@@tbl\@@tbl\c!extras\endcsname
+ \@EA\let\csname\@@tbl\@@tbl\c!extras\endcsname\relax % new, see x-fo
+ % first/last combinations
+ \ifnum\positiverow=\plusone
+ \csname\@@tblprefix\c!y\v!first\endcsname
+ \ifcsname\@@tblprefix\c!x\positivecol\c!y\v!first\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\v!first\endcsname\fi
+ \fi
+ \ifnum\positivecol=\plusone
+ \csname\@@tblprefix\c!x\v!first\endcsname
+ \ifcsname\@@tblprefix\c!x\v!first\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\v!first\c!y\positiverow\endcsname\fi
+ \fi
+ \ifnum\positiverow=\maximumrow\relax
+ \csname\@@tblprefix\c!y\v!last\endcsname
+ \ifcsname\@@tblprefix\c!x\positivecol\c!y\v!last\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\v!last\endcsname\fi
+ \fi
+ \ifnum\positivecol=\maximumcol\relax
+ \csname\@@tblprefix\c!x\v!last\endcsname
+ \ifcsname\@@tblprefix\c!x\v!last\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\v!last\c!y\positiverow\endcsname\fi
+ \fi
+ \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\maximumcol\relax
+ \csname\@@tblprefix\c!x\v!last\c!y\v!last\endcsname
+ \fi\fi
+ \ifnum\positiverow=\plusone \ifnum\positivecol=\plusone
+ \csname\@@tblprefix\c!x\v!first\c!y\v!first\endcsname
+ \fi\fi
+ \ifnum\positiverow=\plusone \ifnum\positivecol=\maximumcol\relax
+ \csname\@@tblprefix\c!x\v!last\c!y\v!first\endcsname
+ \fi\fi
+ \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\plusone
+ \csname\@@tblprefix\c!x\v!first\c!y\v!last\endcsname
+ \fi\fi
+ % special case: two rows and last row : two&first and two&last (round corners)
+ \ifnum\maximumrow=\plustwo\relax
+ \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\plusone
+ \csname\@@tblprefix\c!x\v!first\c!y\v!two\endcsname
+ \fi\fi
+ \ifnum\positiverow=\maximumrow\relax \ifnum\positivecol=\maximumcol\relax
+ \csname\@@tblprefix\c!x\v!last\c!y\v!two\endcsname
+ \fi\fi
+ \fi
+ \ifnum\gettblcol\positiverow\positivecol=\maximumcol\relax % top span over whole width
+ \ifnum\positiverow=\plusone
+ \csname\@@tblprefix\c!x\v!one\c!y\v!first\endcsname
+ \fi
+ \ifnum\positiverow=\maximumrow\relax
+ \csname\@@tblprefix\c!x\v!one\c!y\v!last\endcsname
+ \fi
+ \fi
+ % header things
+ \ifnum#1>\noftblhdnxlines\else
+ \ifcsname\@@tblprefix\v!header\v!each \endcsname\csname\@@tblprefix\v!header\v!each \endcsname\fi
+ \ifcsname\@@tblprefix\v!header\positivecol\endcsname\csname\@@tblprefix\v!header\positivecol\endcsname\fi
+ \fi
+ % explicit cells
+ \ifcsname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\csname\@@tblprefix\c!x\positivecol\c!y\positiverow\endcsname\fi
+ \ifcsname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\csname\@@tblprefix\c!x\negativecol\c!y\negativerow\endcsname\fi
+ % local
+ \ifcsname\@@tblprefix\c!y++\positiverow\endcsname\csname\@@tblprefix\c!y++\positiverow\endcsname\fi
+ % done
+ \global\letcscsname\@@tblsplitafter\csname\@@tbl\@@tbl\c!after\endcsname
+ \relax}
+
+% we cannot use +n (checking on number/last/first would slow down too much)
+%
+% \setupTABLE[r] [2][color=red]
+% \setupTABLE[r] [-2][color=red]
+% \setupTABLE[c] [2][color=green]
+% \setupTABLE[c] [-2][color=green]
+% \setupTABLE[4] [4][color=blue]
+% \setupTABLE[-4][-4][color=blue]
+%
+% \bTABLE
+% \dorecurse{10}{\bTR \dorecurse{6}{\bTD xxx \eTD} \eTR}
+% \eTABLE
+
+\globallet\@@tblsplitafter\relax
+
+% split + page:
+%
+% \bTABLE[split=yes]
+% \bTR \bTD left \eTD\bTD right \eTD\eTR
+% \bTR[after=\page] \bTD left \eTD\bTD right \eTD\eTR
+% \bTR \bTD left \eTD\bTD right \eTD\eTR
+% \eTABLE
+
+% todo: protect counters
+
+\newcount\row \newcount\col
+\newcount\xrow \newcount\xcol
+\newcount\xxrow \newcount\xxcol
+\newcount\maximumrow \newcount\maximumcol \newcount\maximumrowspan
+ \newcount\currentcol
+\newcount\tblspn
+
+\def\parseTR[#1][#2]% [#2] is dummy that kills spaces / no #3 argument
+ {\currentcol\zerocount
+ \advance\maximumrow\plusone
+ \iffirstargument
+ \setvalue{\@@tblprefix\c!y++\number\maximumrow}{\getparameters[\@@tbl\@@tbl][#1]}% maybe also in mkii
+ \fi}
+
+\def\settblref#1#2{\expandafter\xdef\csname\@@tblprefix\number#1:\number#2:x\endcsname}
+\def\gettblref#1#2{\ifcsname\@@tblprefix\number#1:\number#2:x\endcsname\csname\@@tblprefix\number#1:\number#2:x\endcsname\fi}
+
+\long\def\parseTD[#1][#2]#3\eTD % [#2] is dummy that kills spaces
+ {\def\tblny{\tblnr}%
+ \def\tblnx{\tblnc}%
+ \let\tblnc\plusone
+ \let\tblnr\plusone
+ \let\tbln\currentcol
+ \let\tblm\empty
+ \iffirstargument
+ \getparameters[\@@tbl][#1]%
+ \fi
+ % goto first cell % NEW, n/m=cellnumber
+ \edef\@@tblnindeed{\csname\@@tbl\c!n\endcsname}%
+ \ifx\@@tblnindeed\empty
+ \global\advance\tblspn\tblnx\relax
+ \else\ifnum\@@tblnindeed=\currentcol\else
+ \scratchcounter\numexpr\@@tblnindeed-\currentcol+\minusone-\tblspn\relax
+ \ifnum\scratchcounter>\zerocount
+ \normalexpanded{\noexpand\parseTD[\c!nx=\the\scratchcounter,\c!n=,\c!m=,*sq=\v!no][]}\eTD
+ \fi
+ % can also be made faster
+ \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]%
+ \fi\fi
+ \edef\@@tblmindeed{\csname\@@tbl\c!m\endcsname}%
+ \ifx\@@tblmindeed\empty \else
+ \ifnum\@@tblmindeed=\currentcol \else
+ \scratchcounter\numexpr\@@tblmindeed-\currentcol+\minusone-\tblspn\relax
+ \dorecurse\scratchcounter{\normalexpanded{\noexpand\parseTD[\c!n=,\c!m=][]}\eTD}%
+ % can be sped up
+ \getparameters[\@@tbl][\c!ny=\tblnr,\c!nx=\tblnc,nc=1,nr=1,#1,\c!n=,\c!m=]% kind of double, see prev
+ \fi
+ \fi
+ \doloop % skip over columns that result from earlier span
+ {\advance\currentcol\plusone
+ \doifnottbltag\maximumrow\currentcol\exitloop}%
+ % == \def\next{\advance\currentcol\plusone\doiftbltag\maximumrow\currentcol\next}\next
+ % fill r*c cells and set span
+ \ifnum\tblnx=\plusone
+ \ifnum\tblny=\plusone
+ \ifnum\currentcol>\maximumcol\relax
+ \maximumcol\currentcol
+ \fi
+ \else
+ \presetTBLcell
+ \fi
+ \else
+ \presetTBLcell
+ \fi
+ % set values
+ \lettbltag\maximumrow\currentcol\tblcell
+ \settblcol\maximumrow\currentcol{\number\tblnx}%
+ \settblrow\maximumrow\currentcol{\number\tblny}%
+ \settblref\maximumrow\currentcol{\ifcsname\@@tbl\c!action\endcsname\csname\@@tbl\c!action\endcsname\fi}%
+ % save text
+ \edef\celltag{{\number\maximumrow}{\number\currentcol}}%
+ \@EA\settbltxt\@EA\maximumrow\@EA\currentcol\@EA{\@EA\handleTBLcell\celltag[#1]{#3}}}
+
+\def\presetTBLcell
+ {\row\maximumrow
+ \col\currentcol
+ \dorecurse\tblny
+ {\col\currentcol
+ \settblcol\row\col{\number\tblnx}%
+ \ifnum\tblnx>\maximumrowspan\relax
+ \maximumrowspan\tblnx
+ \fi
+ \dorecurse\tblnx
+ {\lettbltag\row\col\tblnone
+ \advance\col\plusone}%
+ \advance\row\plusone}%
+ % check max column
+ \advance\col\minusone
+ \ifnum\col>\maximumcol\relax
+ \maximumcol\col
+ \fi}
+
+%D The usage of n and m:
+%D
+%D \startbuffer
+%D \bTABLE[width=3em]
+%D \bTR\bTD d1 \eTD\bTD[n=2] d2 \eTD\bTD[n=5] d5 \eTD\bTD[n=7] d7 \eTD\eTR
+%D \bTR\bTD f1 \eTD\bTD[n=4] f4 \eTD\bTD[n=5] f5 \eTD\bTD[n=7] f7 \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \bTABLE[width=3em]
+%D \bTR\bTD d1 \eTD\bTD[m=2] d2 \eTD\bTD[m=5] d5 \eTD\bTD[m=7] d7 \eTD\eTR
+%D \bTR\bTD f1 \eTD\bTD[m=4] f4 \eTD\bTD[m=5] f5 \eTD\bTD[m=7] f7 \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+%D
+%D \startbuffer
+%D \bTABLE[frame=on]
+%D \bTR \bTH[nc=3] One \eTH \bTH[m=4] Four \eTH\eTR
+%D \bTR \bTD a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \eTABLE
+%D
+%D \bTABLE[frame=on]
+%D \bTR \bTH[nr=2] One \eTH \bTH[m=3] Three \eTH\eTR
+%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \bTR \bTD[m=3] a \eTD\bTD b \eTD\bTD c \eTD\bTD d \eTD\eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \getbuffer
+
+\long\def\parseTH[#1]#2\eTH
+ {\parseTD[#1,\c!color=\tbltblheadcolor,\c!style=\tbltblheadstyle,\c!aligncharacter=\v!no]#2\eTD}
+
+%D new
+
+\long\def\parseTN[#1]#2\eTN
+ {\parseTD[#1]\digits#2\relax\eTD}
+
+%D Vit Zyka needed the option to create a distance between columns, so I
+%D added support for individual column distances.
+%D
+%D \startbuffer
+%D % \setupTABLE[c][each][distance=2em]
+%D \setupTABLE[c][1][distance=2em]
+%D \setupTABLE[c][2][distance=3em]
+%D
+%D \bTABLE
+%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR
+%D \eTABLE
+%D
+%D \bTABLE[option=stretch]
+%D \bTR \bTD test \eTD \bTD test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD[nx=2] test \eTD \bTD test \eTD \eTR
+%D \bTR \bTD test \eTD \bTD[nx=2] test \eTD \eTR
+%D \eTABLE
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+%D
+%D and he provided patches for the global left and right margin distances
+%D as well as the columndistance (although i changed the names -). Here
+%D is his testcase:
+%D
+%D \startbuffer
+%D \framed[offset=overlay]\bgroup
+%D \setupTABLE[column][2][align=left]%
+%D \setupTABLE[column][3][align=right]%
+%D \bTABLE[columndistance=2cm,leftmargindistance=.3cm,rightmargindistance=.5cm]
+%D \bTR \bTH[nc=3] Table head\eTH \eTR
+%D \bTR \bTD[nc=2] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD[nc=2,align=left] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD[nc=2,align=middle] AB\eTD \bTD C\eTD \eTR
+%D \bTR \bTD A\eTD \bTD B\eTD \bTD C\eTD \eTR
+%D \bTR \bTD Aa\eTD \bTD Bb\eTD \bTD Cccc\eTD \eTR
+%D \bTR \bTD[nc=3,align=middle] ABC\eTD \eTR
+%D \eTABLE
+%D \egroup
+%D \stopbuffer
+%D
+%D \typebuffer \startlinecorrection \getbuffer \stoplinecorrection
+
+\newtoks\TBLhead
+\newtoks\TBLnext
+\newtoks\TBLbody
+\newtoks\TBLfoot
+
+% to be done: head <raw> foot, dus state var
+
+\unexpanded\def\bTABLEhead{\dosingleempty\doTABLEhead} \let\eTABLEhead\relax
+\unexpanded\def\bTABLEnext{\dosingleempty\doTABLEnext} \let\eTABLEnext\relax
+\unexpanded\def\bTABLEbody{\dosingleempty\doTABLEbody} \let\eTABLEbody\relax
+\unexpanded\def\bTABLEfoot{\dosingleempty\doTABLEfoot} \let\eTABLEfoot\relax
+
+\long\def\doTABLEhead[#1]#2\eTABLEhead{\appendtoks\doTABLEsection[#1]{#2}\to\TBLhead}
+\long\def\doTABLEnext[#1]#2\eTABLEnext{\appendtoks\doTABLEsection[#1]{#2}\to\TBLnext}
+\long\def\doTABLEbody[#1]#2\eTABLEbody{\appendtoks\doTABLEsection[#1]{#2}\to\TBLbody}
+\long\def\doTABLEfoot[#1]#2\eTABLEfoot{\appendtoks\doTABLEsection[#1]{#2}\to\TBLfoot}
+
+\long\def\doTABLEsection[#1]#2%
+ {\def\setupTBLsection{\getparameters[\@@tbl\@@tbl][#1]}%
+ #2%
+ \let\setupTBLsection\relax}
+
+\let\pushTBL\relax
+\let\popTBL \relax
+
+\chardef\tblpass=0
+
+\def\presetallTABLEparameters% each odd|even level / can be sped up but only once per table
+ {\executeifdefined{\@@rawtblprefix\v!start\v!each}\relax
+ \executeifdefined{\@@rawtblprefix\v!start\v!oddeven\TBLlevel}\relax
+ \executeifdefined{\@@rawtblprefix\v!start\number\TBLlevel}\relax}
+
+\def\bTABLE
+ {\dosingleempty\dobTABLE}
+
+\def\dobTABLE[#1]%
+ {\pushTBL
+ % box not here
+ \bgroup
+ \TBLhead\emptytoks
+ \TBLnext\emptytoks
+ \TBLbody\emptytoks
+ \TBLfoot\emptytoks
+ \ifhmode\kern\zeropoint\fi % blocks \removeunwantedspaces: check this on icare handelingsschema
+ \resetcharacteralign % new
+ \getparameters
+ [\@@tbl\@@tbl]
+ [\c!align={\v!right,\v!broad,\v!high},#1]%
+ \hsize\tbltbltextwidth
+ \processaction
+ [\tbltblsplit]
+ [ \v!yes=>\enableTBLbreaktrue,
+ \v!repeat=>\enableTBLbreaktrue\multipleTBLheadstrue,
+ \v!auto=>\ifinsidesplitfloat\enableTBLbreaktrue\fi]
+ \processaction
+ [\tbltblheader]
+ [\v!repeat=>\multipleTBLheadstrue]%
+ \localcolortrue
+ \presetallTABLEparameters
+ \ExpandFirstAfter\processallactionsinset
+ [\tbltbloption]
+ [\v!stretch=>\autoTBLspreadtrue]%
+ \linewidth\tbltblrulethickness % needs to be frozen
+ \dontcomplain
+ \currentcol\zerocount
+ \maximumrowspan\plusone
+ \maximumcol\zerocount
+ \maximumrow\zerocount
+ \let\bTR\dobTR
+ \let\bTD\dobTD
+ \let\bTH\dobTH
+ \let\bTN\dobTN}
+
+\unexpanded\def\dobTR{\dodoubleempty\parseTR}
+\unexpanded\def\dobTD{\dodoubleempty\parseTD}
+\unexpanded\def\dobTH{\dodoubleempty\parseTH}
+\unexpanded\def\dobTN{\dodoubleempty\parseTN}
+
+% permits \expanded{\bTD ... \eTD}
+
+\unexpanded\def\eTR{\ignorespaces} % handy in case we use a macro to generate rows
+\unexpanded\def\eTD{\ignorespaces}
+\unexpanded\def\eTH{\ignorespaces}
+\unexpanded\def\eTN{\ignorespaces}
+
+\def\eTABLE % beware, we need to get rid of spurious spaces when in hmode
+ {% tricky and dirty order -)
+ \doifsometokselse\TBLhead % slow, better a flag
+ {\the\TBLhead
+ \edef\noftblheadlines{\number\maximumrow}%
+ \doifsometokselse\TBLnext
+ {\the\TBLnext
+ \edef\noftblnextlines{\number\numexpr\maximumrow-\noftblheadlines\relax}}%
+ {\let\noftblnextlines\zerocount}% was 1
+ \edef\noftblhdnxlines{\number\maximumrow}}
+ {\let\noftblheadlines\zerocount % was 1
+ \let\noftblnextlines\zerocount
+ \let\noftblhdnxlines\zerocount}%
+ \the\TBLbody
+ \the\TBLfoot
+ \removeunwantedspaces % only if hmode
+ % finish cells
+ \dorecurse\maximumrow
+ {\row\recurselevel\relax
+ \dorecurse\maximumcol
+ {\col\recurselevel\relax
+ \doifnottbltag\row\col
+ {\xxcol\col
+ \xxrow\row
+ \xrow\row
+ \doloop
+ {\xcol\col
+ \doloop
+ {\doifelsetbltag\xrow\xcol \exitloop
+ {\advance\xcol\plusone
+ \ifnum\xcol>\maximumcol\relax \exitloop \fi}}%
+ \doifelsetbltag\xrow\xcol \exitloop
+ {\xxrow\xrow \xxcol\xcol \advance\xrow\plusone
+ \ifnum\xrow>\maximumrow \exitloop \fi}}%
+ \ifnum\xxrow>\maximumrow\xxrow\maximumrow\fi
+ \ifnum\xxcol>\maximumcol\xxcol\maximumcol\fi
+ \xxrow\numexpr\xxrow-\row+\plusone\relax
+ \xxcol\numexpr\xxcol-\col+\plusone\relax
+ \xrow\row
+ \dorecurse\xxrow
+ {\xcol\col \settblcol\xrow\xcol{\number\xxcol}%
+ \dorecurse\xxcol
+ {\lettbltag\xrow\xcol\tblnone \advance\xcol\plusone}%
+ \advance\xrow\plusone}%
+ \lettbltag\row\col\tblcell
+ \settblcol\row\col{\the\xxcol}%
+ \settblrow\row\col{\the\xxrow}%
+ \ifautoTBLemptycell
+ \edef\celltag{{\number\row}{\number\col}}%
+ \@EA\settbltxt\@EA\row\@EA\col\@EA{\@EA\handleTBLcell\celltag[]{\strut}}%
+ \fi}}}%
+ % to be sure
+ \dorecurse\maximumrow
+ {\row\recurselevel\relax
+ \dorecurse\maximumcol
+ {\col\recurselevel\relax
+ \doiftblrow\row\col
+ {\scratchcounter\numexpr\maximumrow-\row+\plusone\relax
+ \ifnum\gettblrow\row\col>\scratchcounter
+ \settblrow\row\col{\the\scratchcounter}%
+ \fi}%
+ \lettblht\row\col\zeropoint
+ \lettblwd\row\col\zeropoint
+ \doifnottblcol\row\col{\lettblcol\row\col\zerocount}%
+ \doifnottbltag\row\col{\lettbltag\row\col\tblnone}}}%
+ % check and do
+ \ifcase\maximumcol\else
+ \startTBLprocessing
+ \begTBL
+ \dorecurse\maximumrow
+ {\bTBL
+ \row\recurselevel\relax
+ \dorecurse\maximumcol
+ {\col\recurselevel\relax
+ \normalexpanded{\noexpand\doTBL{\number\row}{\number\col}}}%
+ \eTBL}%
+ \removeunwantedspaces % only if hmode
+ \endTBL
+ \stopTBLprocessing
+ % wrong ! ! ! better to have an auto-offset-overlay
+ % \ifnum\TBLlevel>1
+ % \vskip-\strutdp
+ % \fi
+ \fi
+ \egroup
+ \popTBL}
+
+\let\startTBLprocessing\relax
+\let\stopTBLprocessing \relax
+
+\newcount\prelocatedTBLrows % \prelocateTBLrows{1000} may speed up large tables
+
+\def\bTBL{\tblrowtoks\emptytoks}
+\def\eTBL{\tbltoks\@EA\@EA\@EA{\@EA\the\@EA\tbltoks\@EA\begintblrow\the\tblrowtoks\endtblrow}}%
+
+\def\prelocateTBLerror
+ {\writestatus\m!systems{fatal error: use \string\prelocateTBLrows\space to increase table memory (now: \number\prelocatedTBLrows)}}
+
+\def\prelocateTBLrows#1% we start at zero so we have one to much, better play safe anyway
+ {\dostepwiserecurse\prelocatedTBLrows{#1}\plusone{\expandafter\newtoks\csname tbl:\recurselevel\endcsname}%
+ \def\bTBL
+ {\ifnum\tblrow<\prelocatedTBLrows\relax
+ \@EA\let\@EA\tblrowtoks\csname tbl:\the\tblrow\endcsname\tblrowtoks\emptytoks
+ \else
+ \prelocateTBLerror
+ \fi}%
+ \def\eTBL
+ {\tbltoks\@EA\@EA\@EA{\@EA\the\@EA\tbltoks\@EA\begintblrow\@EA\the\csname tbl:\the\tblrow\endcsname\endtblrow}}%
+ \global\prelocatedTBLrows#1\relax}
+
+% \prelocateTBLrows{1000} % may speed up large tables
+
+% We use aligments to handle the empty (skipped) columns, so
+% that we don't have to (re|)|calculate these.
+
+\def\skiptblcol
+ {\global\advance\tblcol\plusone}
+
+\def\nexttblcol
+ {\global\advance\tblcol\plusone
+ \kern\tbltblcolumndistance
+ &}
+
+\def\spantblcol
+ {\span}
+
+\newcount\tblrow
+\newcount\tblcol
+
+\let\savedtblrow\!!zerocount
+\let\savedtblcol\!!zerocount
+
+\def\begintblrow
+ {\noalign
+ {\global\advance\tblrow\plusone
+ \global\tblcol\zerocount
+ \global\tblspn\zerocount}%
+ \nexttblcol
+ \kern\dimexpr\tbltblleftmargindistance-\tbltblcolumndistance\relax}
+
+\def\endtblrow
+ {\kern\dimexpr\tbltblrightmargindistance-\tbltblcolumndistance\relax
+ \crcr
+ \noalign
+ {\nointerlineskip
+ \ifnum\gettblnob\tblrow=\zerocount
+ \allowbreak
+ \fi
+ \bgroup % protect local vars
+ \@@tblsplitafter
+ \egroup
+ \bgroup % protect local vars
+ \scratchcounter\numexpr\tblrow+\plusone\relax
+ \ifnum\scratchcounter>\noftblhdnxlines\relax
+ \ifnum\scratchcounter<\maximumrow\relax
+ \doifsomething\tbltblspaceinbetween{\blank[\tbltblspaceinbetween]}%
+ \fi
+ \fi
+ \egroup}}
+
+\def\begintbl
+ {\global\tblspn\zerocount
+ \global\tblcol\zerocount
+ \global\tblrow\zerocount
+ \global\advance\tblrow\minusone
+ \tabskip\zeropoint
+ \halign\bgroup
+ \registerparoptions % new
+ \ignorespaces##\unskip&&\ignorespaces##\unskip\cr}
+
+\def\endtbl
+ {\egroup}
+
+\setvalue{\tblnone TBL}#1#2%
+ {\spanTBL{#1}{#2}}
+
+\setvalue{\tblcell TBL}#1#2%
+ {\tblrowtoks\expandafter{\the\tblrowtoks\makeTBL #1 #2 }% space delimited -> less tokens
+ \spanTBL{#1}{#2}}
+
+\def\spanTBL#1#2%
+ {\scratchcounter\gettblcol{#1}{#2}\relax
+ \ifnum\scratchcounter>\zerocount
+ \advance\scratchcounter \minusone
+ \dorecurse\scratchcounter{\tblrowtoks\expandafter{\the\tblrowtoks\spantblcol}}%
+ \dorecurse\scratchcounter{\tblrowtoks\expandafter{\the\tblrowtoks\skiptblcol}}%
+ \tblrowtoks\expandafter{\the\tblrowtoks\nexttblcol}%
+ \fi}
+
+\def\doTBL#1#2%
+ {\csname\gettbltag{#1}{#2}TBL\endcsname{#1}{#2}}
+
+\def\begTBL
+ {\global\tblspn\zerocount
+ \global\tblrow\zerocount
+ \global\tblcol\zerocount
+ \chardef\tblpass\zerocount
+ \tbltoks\emptytoks}
+
+\def\flushtbltoks{\begintbl\the\tbltoks\endtbl}
+
+\def\domakeTBLone#1 #2 %
+ {\gettbltxt{#1}{#2}}%
+
+\def\domakeTBLtwo#1 #2 % meer in cellD
+ {\scratchdimen\zeropoint
+ \scratchcounter\tblcol
+ \!!counta\gettblcol{#1}{#2}\relax
+ \dorecurse\!!counta
+ {\advance\scratchdimen\dimexpr\gettblwid\scratchcounter+\tbltblcolumndistance\relax
+ \ifnum\recurselevel<\!!counta \advance\scratchdimen \gettbldis\scratchcounter\fi
+ \advance\scratchcounter\plusone}%
+ \edef\widthTBL{\the\dimexpr\scratchdimen-\tbltblcolumndistance\relax}%
+ \setbox\scratchbox\hbox{\gettbltxt{#1}{#2}}%
+ \settblht{#1}{#2}{\the\ht\scratchbox}%
+ \settblwd{#1}{#2}{\the\wd\scratchbox}%
+ \ifdim\ht\scratchbox>\gettblhei{#1}\relax
+ \settblhei{#1}{\the\ht\scratchbox}%
+ \fi}%
+
+\def\domakeTBLthree#1 #2 %
+ {% height
+ \!!counta \gettblcol{#1}{#2}\relax
+ \!!countb \gettblrow{#1}{#2}\relax
+ \!!heighta\gettblht {#1}{#2}\relax
+ \scratchdimen\zeropoint
+ \ifnum\!!counta=\maximumcol\relax
+ % case: nc=maxcolumns
+ \else
+ \scratchcounter#1\relax
+ \dorecurse\!!countb
+ {\advance\scratchdimen
+ \gettblhei\scratchcounter
+ \advance\scratchcounter\plusone}%
+ \ifdim\scratchdimen<\!!heighta\relax
+ \scratchdimen\!!heighta
+ \fi
+ \fi
+ \edef\heightTBL{\the\scratchdimen}%
+ % width
+ \scratchdimen\zeropoint
+ \scratchcounter\tblcol
+ \dorecurse\!!counta
+ {\advance\scratchdimen\dimexpr\gettblwid\scratchcounter+\tbltblcolumndistance\relax
+ \ifnum\recurselevel<\!!counta \advance\scratchdimen \gettbldis\scratchcounter\fi
+ \advance\scratchcounter\plusone}%
+ \edef\widthTBL{\the\dimexpr\scratchdimen-\tbltblcolumndistance\relax}%
+ % cell
+ \setbox\scratchbox\hbox{\gettbltxt{#1}{#2}}%
+ \ifnum\!!counta=\maximumcol\relax
+ % case: nc=maxcolumns
+ \else
+ \scratchdimen\gettblhei{#1}%
+ \setbox\scratchbox\hbox
+ {\lower\ht\scratchbox\hbox{\raise\scratchdimen\box\scratchbox}}%
+ \ht\scratchbox\scratchdimen
+ \fi
+ \dp\scratchbox\zeropoint
+ \edef\!!stringa{\gettblref{#1}{#2}}%
+ \ifx\!!stringa\empty
+ \box\scratchbox
+ \else
+ \normalexpanded{\noexpand\gotobox{\box\scratchbox}[\!!stringa]}%
+ \fi
+ \box\scratchbox}
+
+\def\inTBLcell#1#2% hm, do we need #1 #2 ? we use tblcol anyway
+ {\ExpandBothAfter\doifinsetelse\localwidth{\v!fit,\v!broad} % user set
+ {}
+ {\scratchdimen\gettblaut\tblcol\relax
+ \ifdim\localwidth>\scratchdimen
+ \settblaut\tblcol{\the\dimexpr\localwidth\relax}%
+ \fi}}%
+
+\def\endTBL
+ {\setbox\scratchbox\hbox
+ {\localframed
+ [\@@tbl\@@tbl]
+ [\c!frame=\v!off,\c!background=,\c!align=\v!no]
+ {\strut}}%
+ \edef\minimalcellheight{\the\ht\scratchbox}%
+ \dorecurse\maximumcol
+ {\lettblaut\recurselevel\zeropoint
+ % new
+ \xcol\recurselevel\relax
+ \dorecurse\maximumrow
+ {\lettblwd\recurselevel\xcol\zeropoint
+ \lettblht\recurselevel\xcol\zeropoint}%
+ % till here
+ \lettblwid\recurselevel\zeropoint
+ \lettbldis\recurselevel\zeropoint}%
+ \dorecurse\maximumrow
+ {\lettblhei\recurselevel\maxdimen}%
+ \chardef\tblpass\plusone
+ \let\makeTBL\domakeTBLone
+ \let\handleTBLcell\dohandleTBLcellA
+ \setbox0\vbox{\trialtypesettingtrue \flushtbltoks}%
+% \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
+ \lettbldis\maximumcol\zeropoint
+ \ifautoTBLspread
+ % experimental, stretch non fixed cells to \hsize
+ \checktblwidthsone % trial run
+ \checktblwidthstwo % real run
+ \stretchtblwidths
+ \let\handleTBLcell\dohandleTBLcellB
+ \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
+ \else\ifdim\wd0>\hsize
+ \ifautoTBLhsize
+ \checktblwidthsone % trial run
+ \checktblwidthstwo % real run
+ \let\handleTBLcell\dohandleTBLcellB
+ \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
+ \fi
+ \else\ifautoTBLrowspan\ifnum\maximumrowspan>1 % max ?
+ % added jan 2002 because nx=* did no longer work
+ \edef\savedhsize{\the\hsize}%
+ \hsize\wd0\relax % new per 17/04/2006
+ \checktblwidthsone % trial run
+ \checktblwidthstwo % real run
+ \hsize\savedhsize
+ %
+ \let\handleTBLcell\dohandleTBLcellC
+ \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
+ \fi\fi\fi\fi
+ \let\handleTBLcell\dohandleTBLcellD
+ \chardef\tblpass\plustwo
+ \let\makeTBL\domakeTBLtwo
+ \setbox\scratchbox\vbox{\trialtypesettingtrue \flushtbltoks}%
+ \checktblheightsone
+ \checktblheightstwo
+ \let\handleTBLcell\dohandleTBLcellE
+ \chardef\tblpass\plusthree
+ \let\makeTBL\domakeTBLthree
+ \ifnum\TBLlevel>\plusone
+ \@EA\notsplittblbox
+ \else\ifenableTBLbreak
+ \@EAEAEA\splittblbox
+ \else
+ \@EAEAEA\notsplittblbox
+ \fi\fi{\flushtbltoks}}
+
+\def\stretchtblwidths % more variants, e.g. a max to \dimend
+ {\ifcase\maximumcol\else % else division by zero
+ \!!dimend\zeropoint
+ \!!dimene\hsize
+ \dorecurse\maximumcol
+ {\advance\!!dimend\dimexpr\gettblwid\recurselevel+\tbltblcolumndistance\relax
+ \advance\!!dimene-\gettbldis\recurselevel}%
+ \advance\!!dimend\dimexpr-\tbltblcolumndistance+\tbltblleftmargindistance+\tbltblrightmargindistance\relax
+ % distribute width (stretch)
+ \ifdim\!!dimend<\!!dimene
+ \advance\!!dimend-\!!dimene
+ \!!dimend-\!!dimend
+ \divide\!!dimend\maximumcol
+ \dorecurse\maximumcol
+ {\settblwid\recurselevel{\the\dimexpr\gettblwid\recurselevel+\!!dimend\relax}}%
+ \fi
+ \fi}
+
+\newbox\finaltblbox
+
+\def\notsplittblbox#1%
+ {\setbox\finaltblbox\vbox{#1}%
+ \postprocessTABLEbox\finaltblbox
+ \beforeTABLEbox
+ \box\finaltblbox
+ \afterTABLEbox}
+
+\def\splittblbox#1%
+ {\ifinsidesplitfloat
+ \donetrue
+ \else\ifinsidefloat
+ \donefalse
+ \else
+ \donetrue
+ \fi\fi
+ \ifdone
+ \executeifdefined{dosplittblbox\tbltblsplitmethod}\dosplittblbox{#1}%
+ \else
+ \notsplittblbox{#1}%
+ \fi}
+
+\newbox\TABLEsplitbox % public, don't change
+
+\let\extratblsplitheight\zeropoint % additional space taken by before/afterTABLEsplitbox
+
+\def\dosplittblbox#1%
+ {\resettsplit
+ \def\tsplitminimumfreelines{2}%
+ \def\tsplitminimumfreespace{\dimexpr\extratblsplitheight+\tbltblsplitoffset\relax}%
+ \def\tsplitbeforeresult {\beforeTABLEsplitbox}%
+ \def\tsplitafterresult {\afterTABLEsplitbox}%
+ \def\tsplitafter {\@@tblsplitafter}%
+ \setbox\tsplitcontent\vbox{#1}%
+ \ifmultipleTBLheads
+ \dorecurse\noftblheadlines
+ {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
+ \setbox\tsplithead\vbox{\unvcopy\tsplithead\unvcopy\scratchbox}}%
+ \dorecurse\noftblnextlines
+ {\setbox\scratchbox\vsplit\tsplitcontent to \lineheight
+ \setbox\tsplitnext\vbox{\unvcopy\tsplitnext\unvcopy\scratchbox}}%
+ \fi
+ \doifsomething\tbltblspaceinbetween
+ {\def\tsplitinbetween{\blank[\tbltblspaceinbetween]}}%
+ \def\postprocesstsplit{\postprocessTABLEsplitbox{\box\tsplitresult}}%
+ \handletsplit}
+
+% ! ! ! ! TODO: naast \postprocessTABLEsplitbox ook evt \postprocessTABLEbox voor niet split
+
+\let\postprocessTABLEsplitbox\gobbleoneargument
+\let\postprocessTABLEbox \gobbleoneargument
+
+\let\beforeTABLEsplitbox\relax
+\let\afterTABLEsplitbox \relax
+\let\beforeTABLEbox \relax
+\let\afterTABLEbox \relax
+
+\def\checktblwidthsone{\dochecktblwidths0} % 0 = trial run
+\def\checktblwidthstwo{\dochecktblwidths1} % 1 = real run
+
+\def\dochecktblwidths#1%
+ {\iftraceTABLE\showtblwids{B#1}\fi
+ \!!counta\zerocount
+ \!!dimena\dimexpr\hsize-\tbltblleftmargindistance-\tbltblrightmargindistance-\tbltblcolumndistance\relax
+ \dorecurse\maximumcol
+ {\scratchdimen\gettblaut\recurselevel\relax
+ \advance\!!dimena-\gettbldis\recurselevel\relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \advance\!!dimena -\scratchdimen
+ \else
+ \scratchdimen\gettblwid\recurselevel\relax
+ \ifdim\scratchdimen>\tbltblmaxwidth\relax
+ \ifcase#1\else\lettblwid\recurselevel\zeropoint\fi
+ \advance\!!counta \plusone
+ \else
+ \ifdim\scratchdimen>\zeropoint\relax
+ \advance\!!dimena -\scratchdimen
+ \else
+ % eigenlijk moet dit alleen als de kolom wordt overspannen door een
+ % vorige, maw extra dubbele loop en status var
+ \advance\!!counta \plusone
+ \fi
+ \fi
+ \fi}%
+ \ifcase\!!counta \else \divide\!!dimena \!!counta \fi
+ \dorecurse\maximumcol
+ {\scratchdimen\gettblwid\recurselevel\relax
+ \ifcase#1\relax
+ \ifdim\scratchdimen<\!!dimena % take natural width
+ \settblaut\recurselevel{\the\scratchdimen}%
+ \fi
+ \else
+ \ifdim\scratchdimen=\zeropoint % auto set width
+ \settblwid\recurselevel{\the\!!dimena}%
+ \fi
+ \fi}%
+ \iftraceTABLE\showtblwids{E#1}\fi}
+
+\newcount\xrowTBL
+\newcount\xcolTBL
+\newcount\xxrowTBL
+
+% dikke arg naar recurse wegwerken
+
+\def\dochecktblheightsone
+ {\!!countb\gettblrow\xrowTBL\xcolTBL\relax
+ % check row span
+ \ifnum\!!countb>\plusone
+ % current height in row
+ \dimen0=\gettblht\xrowTBL\xcolTBL
+ % find nearest height in row
+ \dimen2=\zeropoint
+ \dorecurse\maximumcol
+ {\ifnum\recurselevel=\xcolTBL\else
+ \doiftblrow\xrowTBL\recurselevel
+ {\!!countc=\gettblrow\xrowTBL\recurselevel\relax
+ \ifnum\!!countc=\plusone
+ \dimen4=\gettblht\xrowTBL\recurselevel\relax
+ \ifdim\dimen2<\dimen4
+ \dimen2=\dimen4
+ \fi
+ \fi}%
+ \fi}%
+ \xxrowTBL\xrowTBL
+ % calculate cummulative height
+ \dimen4=\dimen2
+ \!!countc\xrowTBL
+ \advance\!!countc\minusone
+ \dorecurse\!!countb
+ {\ifnum\xxrowTBL=\xrowTBL\else
+ \advance\dimen4 \gettblhei\xxrowTBL
+ \fi
+ \ifnum\recurselevel=\!!countb\else
+ \settblnob\!!countc
+ \advance\!!countc\plusone
+ \fi
+ \advance\xxrowTBL\plusone}%
+ % distribute overshoot equally
+ \ifdim\dimen4<\dimen0
+ \advance\dimen0 -\dimen4
+ \divide\dimen0 \!!countb
+ \xxrowTBL\xrowTBL
+ \settblhei\xrowTBL{\the\dimen2}%
+ \dorecurse\!!countb
+ {\dorecurse\maximumcol
+ {\ifnum\recurselevel=\xcolTBL\else
+ \scratchdimen\dimexpr\gettblht\xxrowTBL\recurselevel+\dimen0\relax
+ \settblht\xxrowTBL\recurselevel{\the\scratchdimen}%
+ \ifdim\gettblhei\xxrowTBL<\scratchdimen
+ \settblhei\xxrowTBL{\the\scratchdimen}%
+ \fi
+ \fi}%
+ \advance\xxrowTBL\plusone}%
+ \else\ifdim\dimen4>\dimen0
+ \settblhei\xrowTBL{\the\dimen2}%
+ \fi\fi
+ \fi}
+
+\def\checktblheightsone
+ {\dorecurse\maximumrow
+ {\xrowTBL\recurselevel\relax
+ \dorecurse\maximumcol
+ {\xcolTBL\recurselevel\relax
+ \doiftblrow\xrowTBL\xcolTBL\dochecktblheightsone}}}
+
+\def\checktblheightstwo
+ {}
+
+\def\showtblwids#1%
+ {\vbox
+ {\forgetall\tttf[#1]\dorecurse\maximumcol
+ {\scratchdimen\gettblwid\recurselevel\relax
+ [\recurselevel:\the\scratchdimen]}}}
+
+\def\TBLcharalign
+ {\doifelse\tbltblaligncharacter\v!yes
+ \doTBLcharalign\gobbleoneargument}
+
+\long\def\doTBLcharalign#1#2% column data
+ {\edef\alignmentclass{#1}%
+ \edef\alignmentcharacter{\tbltblalignmentcharacter}%
+ \ifcase\tblpass\or
+ \setfirstpasscharacteralign\checkalignment{#2}% {\strut#2\unskip}%
+ \fi % force hsize, so always a second
+ \setsecondpasscharacteralign \checkalignment{#2}% {\strut#2\unskip}%
+ \ignorespaces}
+
+% new, needed for icare first col of 'doeltabel', experimental
+
+\long\def\dohandleTBLcellA#1#2[#3]#4% grouping added ! ! !
+ {\bgroup
+ \setupTBLcell{#1}{#2}%
+ \setbox\scratchbox\hbox
+ {\scratchdimen\tbltbldistance\relax
+ \ifdim\scratchdimen>\gettbldis{#2}\relax
+ \settbldis{#2}{\the\scratchdimen}%
+ \fi
+ \localframed
+ [\@@tbl\@@tbl]
+ [#3,\c!background=,\c!frame=\v!off]% 25% faster
+ {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL\inTBLcell{#1}{#2}}}%
+ \scratchdimen\gettblwid\tblcol\relax
+ \ifdim\wd\scratchbox>\scratchdimen
+ \ifsqueezeTBLspan
+ \ifautosqueezeTBLspan
+ \doifinsetelse\tbltblwidth{\v!fit,\v!fixed,\v!broad,\v!local}
+ \donetrue \donefalse
+ \else
+ \donetrue
+ \fi
+ \ifdone % brr, 0
+ \ifnum\number\gettblcol{#1}{#2}>\plusone \settblspn\tblcol\fi
+ \fi
+ \fi
+ \doifelsetblspn\tblcol
+ \donothing
+ {\ifdim\gettblwid\tblcol<\wd\scratchbox
+ \settblwid\tblcol{\the\wd\scratchbox}%
+ \fi}% auto set
+ \fi
+ \scratchcounter\numexpr\tblrow+\plusone\relax
+ \scratchdimen\gettblhei\scratchcounter\relax
+ \ifdim\ht\scratchbox<\scratchdimen
+ \settblhei\scratchcounter{\the\ht\scratchbox}% auto set
+ \fi
+ \settblht{#1}{#2}{\the\ht\scratchbox}%
+ \settblwd{#1}{#2}{\the\wd\scratchbox}%
+ \ifautoTBLcheckwidth
+ \ifdim\wd\scratchbox<.75\hsize
+ \ifdim\ht\scratchbox>2\openlineheight % honor width since this
+ \scratchdimen\gettblaut\tblcol\relax % can be a figure or so
+ \ifdim\scratchdimen=\zeropoint
+ % side effect: when width is set to 0pt,
+ % we can force a span that fits the sum of spans widths
+ \settblaut\tblcol{\the\scratchdimen}%
+ \else\ifdim\wd\scratchbox>\scratchdimen
+ % unless span
+ \settblaut\tblcol{\the\wd\scratchbox}%
+ % to be translated
+ \writestatus\m!TABLE
+ {no auto width in (\number#1,\number#2)\space\the\wd\scratchbox/\the\hsize}%
+ \fi\fi
+ \fi
+ \fi
+ \fi
+ \setbox2\null
+ \wd2\wd\scratchbox \ht2\ht\scratchbox \dp2\dp\scratchbox
+ \box2
+ \egroup}
+
+\long\def\dohandleTBLcellBC#1#2#3[#4]#5%
+ {\setbox\scratchbox\hbox
+ {\setupTBLcell{#2}{#3}%
+ \localframed
+ [\@@tbl\@@tbl]
+ [#4,#1,\c!frame=\v!off,\c!background=]
+ {\bTBLCELL#5\eTBLCELL}}%
+ \setbox2\null
+ \wd2\wd\scratchbox \ht2\ht\scratchbox \dp2\dp\scratchbox
+ \ifautoTBLrowspan
+ \scratchcounter\numexpr\tblrow+\plusone\relax
+ \doiftblrow\scratchcounter\tblcol
+ {\scratchdimen\gettblhei\scratchcounter\relax % moved inside test
+ \ifnum\gettblrow\scratchcounter\tblcol>\plusone \ifdim\ht\scratchbox>\scratchdimen
+ \scratchdimen-\scratchdimen \advance\scratchdimen -\ht\scratchbox
+ \ht2\scratchdimen
+ \fi \fi}%
+ \fi
+ \box2 }
+
+\long\def\dohandleTBLcellB#1#2[#3]#4%
+ {\scratchdimen\gettblaut\tblcol\relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \let\tblwidthkey\c!width
+ \edef\tblwidth{\the\scratchdimen}%
+ \else
+ \scratchdimen\gettblwid\tblcol\relax
+ \ifdim\scratchdimen>\zeropoint\relax
+ \ifnum\gettblcol{#1}{#2}=\maximumcol\relax
+ \scratchdimen\hsize
+ \fi
+ \let\tblwidthkey\c!width
+ \edef\tblwidth{\the\scratchdimen}%
+ \else
+ \let\tblwidthkey\s!unknown
+ \let\tblwidth\zeropoint
+ \fi
+ \fi
+ \dohandleTBLcellBC{\tblwidthkey=\tblwidth}{#1}{#2}[#3]{\TBLcharalign{#2}{#4}}}
+
+\long\def\dohandleTBLcellC
+ {\dohandleTBLcellBC{}}
+
+\long\def\dohandleTBLcellD#1#2[#3]#4%
+ {\setupTBLcell{#1}{#2}%
+ \bgroup
+ \localframed
+ [\@@tbl\@@tbl]
+ [#3,\c!width=\widthTBL,\c!background=,\c!frame=\v!off]% 25% faster
+ {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
+ \egroup}
+
+\long\def\dohandleTBLcellE#1#2[#3]#4%
+ {\setupTBLcell{#1}{#2}%
+ \getparameters[\@@tbl\@@tbl][#3]% to get the color right, the way we
+ \color % handle color here prevents interference due to whatsit nodes
+ [\tbltblcolor] % as well as permits local colors to take precedence
+ {\ifdim\heightTBL=\zeropoint\relax % case: nc=maxcolumns
+ \localframed
+ [\@@tbl\@@tbl]
+ [\c!color=,\c!width=\widthTBL]
+ {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
+ \else
+ \localframed
+ [\@@tbl\@@tbl]
+ [\c!color=,\c!width=\widthTBL,\c!height=\heightTBL]
+ {\bTBLCELL\TBLcharalign{#2}{#4}\eTBLCELL}%
+ \fi}%
+ \hskip\gettbldis{#2}}
+
+\presetlocalframed
+ [\@@tbl\@@tbl]
+
+\setupTABLE [%
+ \c!frameoffset=.5\linewidth,
+ \c!backgroundoffset=\v!frame,
+ \c!framecolor=\s!black,
+ \c!width=\v!fit,
+ \c!height=\v!fit,
+ \c!autowidth=\v!yes,
+ \c!rulethickness=\linewidth,
+ \c!strut=\v!yes,
+ \c!autostrut=\v!no,
+ %
+ \c!color=,
+ \c!style=,
+ \c!headstyle=\v!bold,
+ \c!headcolor=,
+ \c!aligncharacter=\v!no,
+ \c!alignmentcharacter={,},
+ \c!option=, % \v!stretch
+ \c!header=,
+ \c!spaceinbetween=,
+ \c!maxwidth=8em,
+ \c!textwidth=\hsize,
+ \c!split=\v!auto,
+ \c!splitoffset=0pt,
+ \c!distance=\zeropoint, % individual column
+ \c!columndistance=\zeropoint, % each column (whole table)
+ \c!leftmargindistance=\zeropoint, % whole table
+ \c!rightmargindistance=\zeropoint,% whole table
+ \c!left=,
+ \c!right=,
+ \c!splitmethod=a%
+]
+
+%D We have already prepared the previous macros for nesting,
+%D so we only have to pop in the right ones:
+
+%D New:
+
+\def\pushTBLparameters
+ {\globalpushmacro\TBLlevel
+ \ifcase\tblpass
+ % we're just after \bTABLE
+ \else\ifnum\TBLlevel>\zerocount
+ \doglobal\increment\TBLlevel\relax
+ \fi\fi}
+
+\def\popTBLparameters
+ {\globalpopmacro\TBLlevel}
+
+\def\pushTBL
+ {\ifnum\TBLlevel=\zerocount
+ \global\advance\currenttbl\plusone
+ \fi
+ \doglobal\increment\TBLlevel\relax
+ \ifnum\TBLlevel>\plusone
+ \resetallTABLEparameters
+ % we need a proper count push/pop
+ \xdef\savedtblrow{\the\tblrow}\globalpushmacro\savedtblrow
+ \xdef\savedtblcol{\the\tblcol}\globalpushmacro\savedtblcol
+ \else
+ \global\intabletrue
+ \fi}
+
+\def\popTBL
+ {\ifnum\TBLlevel>\plusone
+ \globalpopmacro\savedtblrow\global\tblrow\savedtblrow
+ \globalpopmacro\savedtblcol\global\tblcol\savedtblcol
+ \else
+ \global\intablefalse
+ \fi
+ \doglobal\decrement\TBLlevel\relax}
+
+% \bgroup
+% \setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
+% \bTABLE
+% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,2 \eTD \bTD
+% {\setupTABLE[column][1][aligncharacter=yes, alignmentcharacter={,}]
+% \bTABLE
+% \bTR \bTD 1,2 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR
+% \bTR \bTD 11,2 \eTD \bTD 2 \eTD \eTR \eTABLE} \eTD \eTR
+% \bTR \bTD 11,22 \eTD \bTD 2 \eTD \eTR
+% \eTABLE
+% \egroup
+
+\newconditional\resetTABLEmode \settrue\resetTABLEmode
+
+\def\resetallTABLEparameters% moet genest wel werken
+ {\ifnum\TBLlevel>\plusone % in ieder geval
+ \ifconditional\resetTABLEmode
+% \presetlocalframed % breedte hoogte diepte offset
+% [\@@tbl\@@tbl]% % achtergrond, achtergrondraster, achtergrondkleur
+ % not ok yet
+ \setupTABLE [%
+ \c!frameoffset=.5\linewidth,
+ \c!backgroundoffset=\v!frame,
+ \c!framecolor=\s!black,
+ \c!width=fit,
+ \c!height=fit,
+\c!autowidth=\v!yes,
+% \c!rulethickness=\linewidth,
+ \c!strut=\v!no,
+\c!strut=\v!yes, % needed for mathml, but ... maybe we need another resetTABLEmode
+\c!autostrut=\v!no,
+ \c!color=,
+ \c!style=,
+ \c!headstyle=,
+ \c!headcolor=,
+ \c!aligncharacter=\v!no,
+ \c!alignmentcharacter={,},
+ \c!maxwidth=8em]%
+ \else
+ \setupTABLE
+ [\c!width=\v!fit,
+ \c!height=\v!fit]%
+ \fi
+ \fi}
+
+%D Spacing:
+%
+% \starttabulate
+% \NC text \NC text \NC \NR
+% \TB[small]
+% \NC text \NC text \NC \NR
+% \TB[4*big]
+% \NC text \NC text \NC \NR
+% \stoptabulate
+%
+% \starttable[|||]
+% \VL text \VL text \VL \AR
+% \TB[small]
+% \VL text \VL text \VL \AR
+% \TB[4*big]
+% \VL text \VL text \VL \AR
+% \stoptable
+
+\def\complexTableTB[#1]{\TABLEnoalign{\blank[#1]}}
+\def\simpleTableTB {\TABLEnoalign{\blank}}
+
+\def\TabulateTB
+ {\complexorsimpleTable{TB}}
+
+\def\doTableinterline% #1
+ {\ifnum\currentTABLEcolumn>\maxTABLEcolumn
+ \chuckTABLEautorow
+ \else\ifnum\currentTABLEcolumn=\zerocount
+ \TABLEnoalign
+ {\globalletempty\checkTABLEautorow
+ \globalletempty\chuckTABLEautorow}%
+ \else
+ \setTABLEerror\TABLEmissingcolumn
+ \handleTABLEerror
+ \fi\fi
+ \complexorsimpleTable} % {#1}
+
+\def\TableHL{\doTableinterline{HL}}
+\def\TableTB{\doTableinterline{TB}}
+
+\appendtoks\let\TB\TableTB \to\everytable
+\appendtoks\let\TB\TabulateTB\to\everytabulate % strange place
+
+\appendtoks \chardef\recodeverbatimmode\plustwo \to \everytable
+
+% new (for Olivier Turlier)
+%
+% \defineTABLEsetup [xx] [foregroundcolor=red]
+%
+% \bTABLE
+% \bTR \bTD oeps \eTD \bTD oeps \eTD \eTR
+% \bTR \bTDs[xx] oeps \eTDs \bTD oeps \eTD \eTR
+% \bTRs[xx] \bTD oeps \eTD \bTD oeps \eTD \eTRs
+% \eTABLE
+
+\def\defineTABLEsetup
+ {\dodoubleargument\dodefineTABLEsetup}
+
+\def\dodefineTABLEsetup[#1][#2]%
+ {\setvalue{\@@tbl:set:#1}{#2}}
+
+\long\def\bTDs[#1]#2\eTDs
+ {\doifdefinedelse{\@@tbl:set:#1}
+ {\@EA\@EA\@EA\bTD\@EA\@EA\@EA[\csname\@@tbl:set:#1\endcsname]#2\eTD}
+ {\bTD[]#2\eTD}}
+
+\long\def\bTRs[#1]#2\eTRs
+ {\doifdefinedelse{\@@tbl:set:#1}
+ {\@EA\@EA\@EA\bTR\@EA\@EA\@EA[\csname\@@tbl:set:#1\endcsname]#2\eTR}
+ {\bTR[]#2\eTR}}
+
+\protect \endinput
+
+% todo: mode: first|next (of niets)
diff --git a/tex/context/base/tabl-nte.tex b/tex/context/base/tabl-nte.tex
new file mode 100644
index 000000000..cde64a033
--- /dev/null
+++ b/tex/context/base/tabl-nte.tex
@@ -0,0 +1,107 @@
+%D \module
+%D [ file=core-nte,
+%D version=2009.03.08,
+%D title=\CONTEXT\ Table Macros,
+%D subtitle=Natural Tables Extensions,
+%D author=Hans Hagen \& Wolfgang Schuster,
+%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.
+
+\writestatus{loading}{ConTeXt Table Module / Natural Tables Extensions}
+
+\unprotect
+
+%D This module is suggested by Wolfgang Schuster who also prototyped
+%D it and came up with the rationale:
+%D
+%D This module provides an easy way to use natural in a similiar
+%D way as the older table module (based on the \TABLE\ macros) and
+%D the newer tabulate module.
+%D
+%D You can see the advantage in the following table, once created
+%D with the new macros and once with the normal macros provided
+%D with the natural table module.
+%D
+%D Let us start with the original macros:
+%D
+%D \starttyping
+%D \bTABLE
+%D \bTR
+%D \bTD Text 1 \eTD
+%D \bTD Text 2 \eTD
+%D \eTR
+%D \bTR
+%D \bTD Text 3 \eTD
+%D \bTD Text 4 \eTD
+%D \eTR
+%D \eTABLE
+%D \stoptyping
+%D
+%D Watch how the new macros use less code:
+%D
+%D \starttyping
+%D \startTABLE
+%D \NC Text 1 \NC Text 2 \NC\NR
+%D \NC Text 3 \NC Text 4 \NC\NR
+%D \stopTABLE
+%D \stoptyping
+%D
+%D The actual code differs from the prototype that it does not need
+%D to collect whole rows and parse them but looks ahead instead.
+
+\def\startTABLE
+ {\dosingleempty\dostartTABLE}
+
+\def\dostartTABLE[#1]%
+ {\bgroup
+ \bTABLE[#1]%
+ \let\NC\doTABLENC
+ \let\NR\doTABLENR
+ \let\bTR\relax
+ \let\bTD\relax
+ \let\bTH\relax
+ \let\bTN\relax}
+
+\def\stopTABLE
+ {\eTABLE
+ \egroup}
+
+\newconditional\inTABLEnc
+
+\unexpanded\def\doTABLENR
+ {\eTR
+ \setfalse\inTABLEnc}
+
+\unexpanded\def\doTABLENC
+ {\futurelet\next\dodoTABLENC}
+
+\def\dodoTABLENC
+ {\ifx\next\doTABLENR \else
+ \expandafter\dododoTABLENC
+ \fi}
+
+% \long\def\dododoTABLENC#1\NC
+% {\ifconditional\inTABLEnc\else\settrue\inTABLEnc\parseTR[][]\fi
+% \parseTD[][]#1\eTD\NC}
+
+\long\def\dododoTABLENC#1\NC
+ {\ifconditional\inTABLEnc\else\settrue\inTABLEnc\parseTR[][]\fi
+ \dodoubleempty\parseTD#1\eTD\NC}
+
+%D The related structure commands are also available:
+
+\unexpanded\def\startTABLEhead{\dosingleempty\dostartTABLEhead} \let\stopTABLEhead\relax
+\unexpanded\def\startTABLEnext{\dosingleempty\dostartTABLEnext} \let\stopTABLEnext\relax
+\unexpanded\def\startTABLEbody{\dosingleempty\dostartTABLEbody} \let\stopTABLEbody\relax
+\unexpanded\def\startTABLEfoot{\dosingleempty\dostartTABLEfoot} \let\stopTABLEfoot\relax
+
+\long\def\dostartTABLEhead[#1]#2\stopTABLEhead{\appendtoks\doTABLEsection[#1]{#2}\to\TBLhead}
+\long\def\dostartTABLEnext[#1]#2\stopTABLEnext{\appendtoks\doTABLEsection[#1]{#2}\to\TBLnext}
+\long\def\dostartTABLEbody[#1]#2\stopTABLEbody{\appendtoks\doTABLEsection[#1]{#2}\to\TBLbody}
+\long\def\dostartTABLEfoot[#1]#2\stopTABLEfoot{\appendtoks\doTABLEsection[#1]{#2}\to\TBLfoot}
+
+\protect \endinput
diff --git a/tex/context/base/tabl-pln.tex b/tex/context/base/tabl-pln.tex
new file mode 100644
index 000000000..39bb50f23
--- /dev/null
+++ b/tex/context/base/tabl-pln.tex
@@ -0,0 +1,91 @@
+%D The following bunch of macros come from plain \TEX\ by
+%D Don Knuth and deal with basic alignment. We just include
+%D them here so that they can be used if needed. Normally,
+%D \CONTEXT\ users will fall back on one of the three table
+%D environments.
+%D
+%D The hidden names are somewhat adapted and we use other
+%D local variables.
+
+\writestatus{loading}{ConTeXt Table Macros / Plain Tabular}
+
+\unprotect
+
+\newif \if@@plnusetab
+\newif \if@@plncr
+\newbox \@@plntabs
+\newbox \@@plntabsyet
+\newbox \@@plntabsdone
+\newdimen \@@plntabdimen
+
+\def\cleartabs % visible
+ {\global\setbox\@@plntabsyet\null
+ \setbox\@@plntabs\null}
+
+\def\settabs % visible
+ {\setbox\@@plntabs\null
+ \futurelet\next\@@plnsettabs}
+
+\def\tabalign % visible
+ {\@@plnusetabtrue\@@plnmaketabbox}
+
+\let\+\tabalign % no outer here (can be overloaded)
+
+\def\@@plnsettabs
+ {\ifx\next\+%
+ \def\nxt{\afterassignment\@@plnsettab\let\nxt}%
+ \else
+ \let\nxt\@@plnsetcols
+ \fi
+ \let\next\relax
+ \nxt}
+
+\def\@@plnsettab
+ {\let\nxt\relax
+ \@@plnusetabfalse\@@plnmaketabbox}
+
+\def\@@plnsetcols#1\columns
+ {\scratchcounter#1%
+ \@@plntabdimen\hsize
+ \loop
+ \ifnum\scratchcounter>\zerocount \@nother
+ \repeat}
+
+\def\@nother
+ {\scratchdimen\@@plntabdimen
+ \divide\scratchdimen\scratchcounter
+ \setbox\@@plntabs\hbox{\hbox to\scratchdimen{}\unhbox\@@plntabs}%
+ \advance\@@plntabdimen-\scratchdimen
+ \advance\scratchcounter\minusone}
+
+\def\@@plnmaketabbox
+ {\begingroup
+ \global\setbox\@@plntabsyet\copy\@@plntabs
+ \global\setbox\@@plntabsdone\null
+ \def\cr
+ {\@@plncrtrue\crcr\egroup\egroup
+ \if@@plnusetab\unvbox\zerocount\lastbox\fi\endgroup
+ \setbox\@@plntabs\hbox{\unhbox\@@plntabsyet\unhbox\@@plntabsdone}}%
+ \setbox\zerocount\vbox\bgroup\@@plncrfalse
+ \ialign\bgroup&\@@plnbegintabbox##\@@plnendtabbox\crcr}
+
+\def\@@plnbegintabbox
+ {\setbox\zerocount\hbox\bgroup}
+
+\def\@@plnendtabbox
+ {\if@@plncr
+ \egroup % now \box\zerocount holds the column
+ \else
+ \hss\egroup
+ \global\setbox\@@plntabsyet\hbox
+ {\unhbox\@@plntabsyet\global\setbox\plusone\lastbox}% now \box\plusone holds its size
+ \ifvoid\plusone
+ \global\setbox\plusone\hbox to\wd\zerocount{}%
+ \else
+ \setbox\zerocount\hbox to\wd\plusone{\unhbox\zerocount}%
+ \fi
+ \global\setbox\@@plntabsdone\hbox{\box\plusone\unhbox\@@plntabsdone}%
+ \fi
+ \box\zerocount}
+
+\protect \endinput
diff --git a/tex/context/base/core-tab.tex b/tex/context/base/tabl-tab.tex
index 2e843eae8..361369ea2 100644
--- a/tex/context/base/core-tab.tex
+++ b/tex/context/base/tabl-tab.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=core-tab,
%D version=1997.10.10,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Table Macros,
%D subtitle=\TABLE\ Embedding,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / TaBlE Embedding}
+\writestatus{loading}{ConTeXt Table Macros / TaBlE Embedding}
% By now it makes more sense to merge the patches into the original
% and clean that one up too.
@@ -462,6 +462,8 @@
\def\BeginTableParBox#1%
{\setbox\scratchbox\vtop\bgroup % \setbox added
\hsize#1\relax
+ \dontcomplain
+ \restoretablelineskips
\normalbaselines
\let~\!ttTie
\let\-\!ttDH
@@ -469,18 +471,18 @@
\the\EveryTableParBox}
\def\EndTableParBox
- {\removelastskip % itemize or so
+ {\removelastskip % itemize or so
\endgraf
- \ifnum\prevgraf>\zerocount % we want at least
- \verticalstrut \nowhitespace \vskip-\struttotal% one line of text
+ \ifnum\prevgraf>\zerocount % we want at least
+ \verticalstrut \nowhitespace \vskip-\struttotal % one line of text
\egroup
- \ifdim\dp\scratchbox>\lineheight % see (*) for an
- \getnoflines{\dp\scratchbox}% % example of where
- \dp\scratchbox\zeropoint % saving can go
- \setbox\scratchbox % terrible wrong
+ \ifdim\dp\scratchbox>\lineheight % see (*) for an
+ \getnoflines{\dp\scratchbox}% % example of where
+ \dp\scratchbox\zeropoint % saving can go
+ \setbox\scratchbox % terrible wrong
\vtop to \noflines\lineheight{\box\scratchbox}%
- \fi % esp between rows
- \else % of paragraphs
+ \fi % esp between rows
+ \else % of paragraphs
\egroup
\fi
% \getboxheight\scratchdimen\of\box\scratchbox\relax% compensate for
@@ -698,10 +700,10 @@
\ifx\!ttemp\empty
\!taDimenC\zeropoint
\else
- \setbox0\hbox{\m@th #1,#3#1}%
+ \setbox0\hbox{\mathsurround\zeropoint #1,#3#1}%
\!taDimenC\wd0
\fi
- \setbox0\hbox{\m@th #1#2#1}%
+ \setbox0\hbox{\mathsurround\zeropoint #1#2#1}%
\!thToksEdef\!taDataColumnTemplate
={\noexpand\!tqSetQuantityItem{\the\wd0 }{\the\!taDimenC}{#1}%
\the\!taDataColumnTemplate}%
@@ -714,8 +716,8 @@
\def\!tqSetQuantityItemA #1#2#3#4,#5,#6!%
{\def\!ttemp{#6}%
- \hbox to #1{\hss\m@th#3#4#3}%
- \hbox to #2{\ifx\!ttemp\empty\else\m@th#3,#5#3\fi\hss}}
+ \hbox to #1{\hss\mathsurround\zeropoint#3#4#3}%
+ \hbox to #2{\ifx\!ttemp\empty\else\mathsurround\zeropoint#3,#5#3\fi\hss}}
%D Here ends the Q||extension. Did you watch the clever use
%D of aftergroup in \type{\!tqConvertCode}.
@@ -916,7 +918,7 @@
\advance\mscount \mscount
\!thLoop
\ifnum\mscount>\plusone
- \sp@n % from Plain (\span\omit \advance\mscount\m@ne)
+ \spanomit \advance\mscount\minusone
\repeat
\span}%
\fi % added
@@ -980,7 +982,7 @@
{\doifelsenothing\@@tiframe
{\ifinsidefloat\else\startbaselinecorrection\fi}
{\startframedcontent[\@@tiframe]}%
- \postponefootnotes
+ \postponenotes
\firststagestartTABLE}}
\def\stoptable
@@ -1223,6 +1225,7 @@
\ifconditional\tablerepeattail\else\insertTABLEtail\fi
\finishTABLE
\egroup
+\dontcomplain
\dosplittablebox\tablecontentbox
\flushnotes
\egroup}
@@ -1661,7 +1664,12 @@
\egroup
\def\!ttDoHalign
- {\baselineskip \zeropoint
+ {\edef\restoretablelineskips
+ {\baselineskip \the\baselineskip
+ \lineskiplimit\the\lineskiplimit
+ \lineskip \the\lineskip
+ \tabskip \the\tabskip}%
+ \baselineskip \zeropoint
\lineskiplimit\zeropoint
\lineskip \zeropoint
\tabskip \zeropoint
diff --git a/tex/context/base/core-tbl.tex b/tex/context/base/tabl-tbl.tex
index a5d5a37da..bc57a3abd 100644
--- a/tex/context/base/core-tbl.tex
+++ b/tex/context/base/tabl-tbl.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=core-tbl,
%D version=1998.11.03,
-%D title=\CONTEXT\ Core Macros,
+%D title=\CONTEXT\ Table Macros,
%D subtitle=Text Flow Tabulation,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Core Macros / Tabulation}
+\writestatus{loading}{ConTeXt Table Macros / Tabulation}
% \processbetween gebruiken in head/tail macros
@@ -205,7 +205,7 @@
\def\initializetablebox#1% also used elsewhere
{\ifcsname\@@tabbox@@\number#1\endcsname
- \global\setbox\csname\@@tabbox@@\number#1\endcsname\box\voidb@x
+ \global\setbox\csname\@@tabbox@@\number#1\endcsname\emptybox
\else
\expandafter\newbox\csname\@@tabbox@@\number#1\endcsname
\fi}
@@ -348,10 +348,10 @@
\let\nextnext\relax % == \expandafter\gobbleoneargument
\else
\let\nextnext\settabulatepreamble
- \ifx x\next \chardef\tabulatealign\zerocount % internal
- \else\ifx l\next \chardef\tabulatealign\plusone
- \else\ifx r\next \chardef\tabulatealign\plustwo
- \else\ifx c\next \chardef\tabulatealign\plusthree
+ \ifx x\next \let\tabulatealign\zerocount % internal
+ \else\ifx l\next \let\tabulatealign\plusone
+ \else\ifx r\next \let\tabulatealign\plustwo
+ \else\ifx c\next \let\tabulatealign\plusthree
\else\ifx p\next \let\nextnext\gettabulateparagraph
\else\ifx s\next \let\nextnext\gettabulatesetups
\else\ifx w\next \let\nextnext\gettabulatewidth
@@ -436,17 +436,17 @@
\settabulatepreamble}
\def\gettabulatewidth
- {\chardef\tabulatemodus\zerocount
- \chardef\tabulatedimen\zerocount
+ {\let\tabulatemodus\zerocount
+ \let\tabulatedimen\zerocount
\doifnextcharelse(\dogettabulatewidth\settabulatepreamble}
\def\gettabulateparagraph
{\doifnextcharelse{(}
- {\chardef\tabulatemodus\plusone
- \chardef\tabulatedimen\plusone
+ {\let\tabulatemodus\plusone
+ \let\tabulatedimen\plusone
\dogettabulatewidth}
- {\chardef\tabulatemodus\plustwo
- \chardef\tabulatedimen\zerocount
+ {\let\tabulatemodus\plustwo
+ \let\tabulatedimen\zerocount
\settabulatepreamble}}
% \def\dogettabulatewidth(#1)%
@@ -458,7 +458,7 @@
% \def\dogettabulatewidth(#1)%
% {\doifelse{#1}\v!passend
-% {\chardef\tabulatemodus\plusthree}
+% {\let\tabulatemodus\plusthree}
% {\tabulatewidth#1\relax}%
% \ifnum\tabulatedimen=\plusone
% \global\advance\tabulatepwidth\tabulatewidth
@@ -478,8 +478,8 @@
\def\dogettabulatewidth(#1)%
{\processallactionsinset
[#1]%
- [ \v!fit=>\chardef\tabulatemodus\plusthree,
- \v!fixed=>\chardef\tabulatemodus\plusthree
+ [ \v!fit=>\let\tabulatemodus\plusthree,
+ \v!fixed=>\let\tabulatemodus\plusthree
\tabulatenopbreaktrue,
\s!unknown=>\tabulatewidth#1\relax]%
\ifnum\tabulatedimen=\plusone
@@ -494,14 +494,14 @@
\def\tabulateraggedcenter{\ifnum\tabulatetype=\plusone \else\raggedcenter\fi}
\def\tabulateraggedleft {\ifnum\tabulatetype=\plusone \else\raggedleft \fi}
\def\tabulatenotragged {\ifnum\tabulatetype=\plusone \else\notragged \fi}
-\def\tabulatehss {\ifnum\tabulatetype=\plusone \else\hss \fi}
+\def\tabulatehss {\ifnum\tabulatetype=\plusone \else\hss \fi} % never change this to a fill
\bgroup \catcode`\|=\@@other
\gdef\nexttabulate#1|%
- {\chardef\tabulatealign\@@tabulatealign
- \chardef\tabulatemodus\zerocount
- \chardef\tabulatedimen\zerocount
+ {\let\tabulatealign\@@tabulatealign
+ \let\tabulatemodus\zerocount
+ \let\tabulatedimen\zerocount
\tabulatebefore \emptytoks
\tabulateafter \emptytoks
\tabulatebmath \emptytoks
@@ -730,8 +730,8 @@
% An example of its usage:
-\appendtoks \optimizeverbatimfalse \to \everytabulate
-\appendtoks \chardef\recodeverbatimmode\plustwo \to \everytabulate
+\appendtoks \optimizeverbatimfalse \to \everytabulate
+\appendtoks \let\recodeverbatimmode\plustwo \to \everytabulate
% A status variable:
@@ -762,10 +762,9 @@
\v!no=>\splittabulatefalse,
\v!auto=>\ifinsidefloat\ifinsidesplitfloat\else\splittabulatefalse\fi\fi]%
\doifvaluesomething{\??tt\currenttabulate\c!bodyfont}
- {\expanded{\switchtobodyfont
- [\tabulateparameter\c!bodyfont]}}%
- \postponefootnotes % new, to be tested / will be configurable
- \chardef\tabulatepass\plusone
+ {\expanded{\switchtobodyfont[\tabulateparameter\c!bodyfont]}}%
+ \postponenotes % new, to be tested / will be configurable
+ \let\tabulatepass\plusone
\widowpenalty\zerocount % otherwise lines are not broken
\clubpenalty \zerocount % but overlap in funny ways
\the\everytabulate
@@ -990,8 +989,8 @@
\chardef\tabulaterepeathead\executeifdefined{\??tt:\c!header:\tabulateparameter\c!header}\zerocount
% \processaction
% [\tabulateparameter\c!header]
-% [\v!repeat=>\chardef\tabulaterepeathead\plusone,
-% \v!text=>\chardef\tabulaterepeathead\plustwo]%
+% [\v!repeat=>\let\tabulaterepeathead\plusone,
+% \v!text=>\let\tabulaterepeathead\plustwo]%
\fi
\unexpanded \def\NC{\tabulatenormalcolumn0}%
\unexpanded \def\RC{\tabulatenormalcolumn1}%
@@ -1062,7 +1061,7 @@
% \dorecurse\tabulatecolumns % can be made faster
% {\doifundefinedelse{\@@tabbox@@\recurselevel}
% {\expandafter\newbox\csname\@@tabbox@@\recurselevel\endcsname}%
- % {\global\setbox\csname\@@tabbox@@\recurselevel\endcsname\box\voidb@x}}%
+ % {\global\setbox\csname\@@tabbox@@\recurselevel\endcsname\emptybox}}%
\initializetableboxes\tabulatecolumns
\appendtoks&##\to\!!toksa
\appendtoks\global\advance\tabulatecolumn\plusone\to\!!toksa
@@ -1235,7 +1234,7 @@
\verticalstrut
\vskip-\struttotal}%
\fi}}%
- \chardef\tabulatepass\plustwo
+ \let\tabulatepass\plustwo
%
\ifcase\tabulaterepeathead
\ifinsidesplitfloat
diff --git a/tex/context/base/core-tsp.tex b/tex/context/base/tabl-tsp.tex
index e9f0e7d58..49bb7ad90 100644
--- a/tex/context/base/core-tsp.tex
+++ b/tex/context/base/tabl-tsp.tex
@@ -1,8 +1,8 @@
%D \module
-%D [ file=core-tsp,
+%D [ file=tabl-tsp,
%D version=2000.10.20,
-%D title=\CONTEXT\ Core Macros,
-%D subtitle=Splitting Tables,
+%D title=\CONTEXT\ Table Macros,
+%D subtitle=Splitting,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context OTR Macros / Floating Bodies}
+\writestatus{loading}{ConTeXt Table Macros / Splitting}
%D The code in this file is move here from other places.
diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua
new file mode 100644
index 000000000..0049cf512
--- /dev/null
+++ b/tex/context/base/task-ini.lua
@@ -0,0 +1,45 @@
+if not modules then modules = { } end modules ['task-ini'] = {
+ version = 1.001,
+ comment = "companion to task-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is a temporary solution, we need to isolate some modules and then
+-- the load order can determine the trickery to be applied to node lists
+
+tasks.appendaction("processors", "normalizers", "fonts.collections.process", nil)
+tasks.appendaction("processors", "normalizers", "fonts.checkers.missing", nil)
+
+tasks.appendaction("processors", "characters", "chars.handle_mirroring", nil, "notail")
+tasks.appendaction("processors", "characters", "chars.handle_casing", nil, "notail")
+tasks.appendaction("processors", "characters", "chars.handle_breakpoints", nil, "notail")
+tasks.appendaction("processors", "characters", "scripts.preprocess", nil, "notail") -- this will be more generalized
+
+tasks.appendaction("processors", "words", "kernel.hyphenation", nil)
+tasks.appendaction("processors", "words", "languages.words.check", nil, "notail")
+
+tasks.appendaction("processors", "fonts", "nodes.process_characters", nil, "notail")
+tasks.appendaction("processors", "fonts", "nodes.inject_kerns", nil, "nohead")
+tasks.appendaction("processors", "fonts", "nodes.protect_glyphs", nil, "nohead")
+tasks.appendaction("processors", "fonts", "kernel.ligaturing", nil)
+tasks.appendaction("processors", "fonts", "kernel.kerning", nil)
+
+tasks.appendaction("processors", "lists", "lists.handle_spacing", nil, "notail")
+tasks.appendaction("processors", "lists", "lists.handle_kerning", nil, "notail")
+
+tasks.appendaction("shipouts", "normalizers", "nodes.cleanup_page", nil, "notail")
+
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_color", nil, "notail")
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_transparency", nil, "notail")
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_overprint", nil, "notail")
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_negative", nil, "notail")
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_effect", nil, "notail")
+tasks.appendaction("shipouts", "finishers", "shipouts.handle_viewerlayer", nil, "notail")
+
+tasks.appendaction("math", "normalizers", "noads.relocate_characters", nil, "nohead")
+tasks.appendaction("math", "normalizers", "noads.resize_characters", nil, "nohead")
+tasks.appendaction("math", "normalizers", "noads.respace_characters", nil, "nohead")
+
+tasks.appendaction("math", "builders", "noads.mlist_to_hlist", nil, "notail")
diff --git a/tex/context/base/task-ini.tex b/tex/context/base/task-ini.tex
new file mode 100644
index 000000000..ef32ee87d
--- /dev/null
+++ b/tex/context/base/task-ini.tex
@@ -0,0 +1,22 @@
+%D \module
+%D [ file=task-ini,
+%D version=2007.06.06,
+%D title=\CONTEXT\ Task Handler,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=PRAGMA-ADE]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Task Handler / initialization}
+
+\unprotect
+
+%D Maybe we will make things configureable (speed up and such).
+
+\registerctxluafile{task-ini}{1.001}
+
+\protect \endinput
diff --git a/tex/context/base/thrd-ran.tex b/tex/context/base/thrd-ran.tex
index 7a186204b..276a4f624 100644
--- a/tex/context/base/thrd-ran.tex
+++ b/tex/context/base/thrd-ran.tex
@@ -50,7 +50,7 @@
% \catcode`\@=11
%
% \def\nextrandom{\begingroup
-% \ifnum\randomi<\@ne % then initialize with time
+% \ifnum\randomi<\plusone % then initialize with time
% \global\randomi\time
% \global\multiply\randomi388 \global\advance\randomi\year
% \global\multiply\randomi31 \global\advance\randomi\day
@@ -115,7 +115,7 @@
\newcount\randomi % the random number seed (while executing)
\newcount\ranval
-\ifx\m!systems\undefined \def\m!systems{system} \fi
+\ifx\m!systems\undefined \def\m!systems{systems} \fi
\def\nextrandom
{\begingroup
diff --git a/tex/context/base/thrd-tab.tex b/tex/context/base/thrd-tab.tex
index 8ca90665e..dd3838ce2 100644
--- a/tex/context/base/thrd-tab.tex
+++ b/tex/context/base/thrd-tab.tex
@@ -442,17 +442,17 @@
% DO VCS
\def\!thDoVCS#1{%
- \setbox\z@\hbox{#1}%
+ \setbox\zerocount\hbox{#1}%
\!thFinishVCS}
% DO MATH VCS
\def\!thDoMathVCS#1#2{%
- \setbox\z@\hbox{$\m@th#1{#2}$}%
+ \setbox\zerocount\hbox{$\mathsurround\zeropoint#1{#2}$}%
\!thFinishVCS}
% FINISH VCS
\def\!thFinishVCS{%
- \vbox to\z@{\vss\box\z@\vss}}
+ \vbox to\zeropoint{\vss\box\zerocount\vss}}
% ***************************************************************
@@ -505,20 +505,20 @@
% DO SIMPLE RAISE
\def\!thDoSimpleRaise#1{%
- \setbox\z@\hbox{\raise \!taDimenA\hbox{#1}}%
+ \setbox\zerocount\hbox{\raise \!taDimenA\hbox{#1}}%
\!thFinishRaise} % From Plain TeX: \ht0=0pt \dp0=0pt \box0
% DO MATH RAISE
\def\!thDoMathRaise#1#2{%
- \setbox\z@\hbox{\raise \!taDimenA\hbox{$\m@th#1{#2}$}}%
+ \setbox\zerocount\hbox{\raise \!taDimenA\hbox{$\mathsurround\zeropoint#1{#2}$}}%
\!thFinishRaise}
% FINISH RAISE. This is the same as Plain's \finsm@sh; some macro
% packages redefine \finsm@sh.
\def\!thFinishRaise{%
- \ht\z@\z@
- \dp\z@\z@
- \box\z@}
+ \ht\zerocount\zeropoint
+ \dp\zerocount\zeropoint
+ \box\zerocount}
% ***************************************************************
@@ -1481,10 +1481,10 @@
\ifx\!ttemp\empty
\!taDimenC=0pt
\else
- \setbox0=\hbox{\m@th #1.#3#1}%
+ \setbox0=\hbox{\mathsurround\zeropoint #1.#3#1}%
\!taDimenC=\wd0
\fi
- \setbox0 =\hbox{\m@th #1#2#1}%
+ \setbox0 =\hbox{\mathsurround\zeropoint #1#2#1}%
\!thToksEdef\!taDataColumnTemplate={%
\noexpand\!tnSetNumericItem
{\the\wd0 }%
@@ -1499,11 +1499,11 @@
\def\!tnSetNumericItemA #1#2#3#4.#5.#6!{%
\def\!ttemp{#6}%
- \hbox to #1{\hss \m@th #3#4#3}%
+ \hbox to #1{\hss \mathsurround\zeropoint #3#4#3}%
\hbox to #2{%
\ifx\!ttemp\empty
\else
- \m@th #3.#5#3%
+ \mathsurround\zeropoint #3.#5#3%
\fi
\hss}}
@@ -1563,25 +1563,25 @@
\def\!TsEnlargeOther#1{%
\ifhmode
- \setbox\z@=\hbox{#1%
+ \setbox\zerocount\hbox{#1%
\xdef\!TsSpaceFactor{\spacefactor=\the\spacefactor}}%
\else
- \setbox\z@=\hbox{#1}%
+ \setbox\zerocount\hbox{#1}%
\fi
\!TsFinishEnlarge}
\def\!TsEnlargeMath#1#2{%
- \setbox\z@=\hbox{$\m@th#1{#2}$}%
+ \setbox\zerocount\hbox{$\mathsurround\zeropoint#1{#2}$}%
\!TsFinishEnlarge}
\def\!TsFinishEnlarge{%
- \dimen@=\ht\z@
+ \dimen@\ht\zerocount
\advance \dimen@ \!taDimenA
- \ht\z@=\dimen@
- \dimen@=\dp\z@
+ \ht\zerocount\dimen@
+ \dimen@\dp\zerocount
\advance \dimen@ \!taDimenB
- \dp\z@=\dimen@
- \box\z@ \!TsSpaceFactor{}}
+ \dp\zerocount\dimen@
+ \box\zerocount \!TsSpaceFactor{}}
% ENLARGE BY MULTIPLES OF StrutUnit
@@ -1883,15 +1883,17 @@
% USE
% \use <number> spans the next <number> data columns.
+
\def\!ttuse#1{%
- \ifnum #1>\@ne
+ \ifnum #1>\plusone
\omit
\mscount=#1 % \mscount is in Plain
- \advance\mscount by \m@ne
+ \advance\mscount by \minusone
\advance\mscount by \mscount
\!thLoop
- \ifnum\mscount>\@ne
- \sp@n % from Plain (\span\omit \advance\mscount\m@ne)
+ \ifnum\mscount>\plusone
+ % \sp@n: from plain
+ \spanomit \advance\mscount\minusone
\repeat
\span
\fi}
diff --git a/tex/context/base/thrd-trg.tex b/tex/context/base/thrd-trg.tex
index dda81a8af..c0106f5a3 100644
--- a/tex/context/base/thrd-trg.tex
+++ b/tex/context/base/thrd-trg.tex
@@ -10,7 +10,7 @@
%
% so we need:
-\def\realnumber#1{\withoutpt\the\dimexpr#1\s!pt\relax} % brrr
+\def\realnumber#1{\withoutpt\the\dimexpr#1\points\relax} % brrr
\chardef \@iv = 4
\chardef \@xc = 90 % was \nin@ty
@@ -95,6 +95,13 @@
\def\calculatedcos#1{\executeifdefined{cos \realnumber{#1}}\!!plusone }
\def\calculatedtan#1{\executeifdefined{tan \realnumber{#1}}\!!zerocount}
+%D The following permits cleaner overloading (\MKIV\ will only have
+%D these):
+
+\def\setcalculatedsin#1#2{\calculatesin{#2}\edef#1{\calculatedsin{#2}}}
+\def\setcalculatedcos#1#2{\calculatecos{#2}\edef#1{\calculatedcos{#2}}}
+\def\setcalculatedtan#1#2{\calculatetan{#2}\edef#1{\calculatedtan{#2}}}
+
%D A few values are predefined, although, on todays systems there
%D is no real reason for that. I've added the 270 ones and changed
%D the -90 tan. Also, I prefer text (\type {\!!..} instead of
diff --git a/tex/context/base/toks-ini.lua b/tex/context/base/toks-ini.lua
index 46cf17080..1313b04a2 100644
--- a/tex/context/base/toks-ini.lua
+++ b/tex/context/base/toks-ini.lua
@@ -5,15 +5,16 @@ if not modules then modules = { } end modules ['toks-ini'] = {
license = "see context related readme files"
}
-local format, texsprint = string.format, tex.sprint
+local utf = unicode.utf8
+local format, gsub, texsprint = string.format, string.gsub, tex.sprint
-utf = utf or unicode.utf8 -- todo: local
+local ctxcatcodes = tex.ctxcatcodes
--[[ldx--
-<p>This code is experimental.</p>
+<p>This code is experimental and needs a cleanup. The visualizers will move to
+a module.</p>
--ldx]]--
-
-- 1 = command, 2 = modifier (char), 3 = controlsequence id
--
-- callback.register('token_filter', token.get_next)
@@ -196,14 +197,13 @@ function collectors.trace()
end
collectors.show_methods.a = function(data) -- no need to store the table, just pass directly
- local ct = tex.ctxcatcodes
local template = "\\NC %s\\NC %s\\NC %s\\NC %s\\NC %s\\NC\\NR "
- texsprint(ct, "\\starttabulate[|T|Tr|cT|Tr|T|]")
- texsprint(ct, template:format("cmd","chr","","id","name"))
- texsprint(ct, "\\HL")
+ texsprint(ctxcatcodes, "\\starttabulate[|T|Tr|cT|Tr|T|]")
+ texsprint(ctxcatcodes, format(template,"cmd","chr","","id","name"))
+ texsprint(ctxcatcodes, "\\HL")
for _,v in pairs(data) do
local cmd, chr, id, cs, sym = v[1], v[2], v[3], "", ""
- local name = (token.command_name(v) or ""):gsub("_","\\_")
+ local name = gsub(token.command_name(v) or "","_","\\_")
if id > 0 then
cs = token.csname_name(v) or ""
if cs ~= "" then cs = "\\string " .. cs end
@@ -214,27 +214,26 @@ collectors.show_methods.a = function(data) -- no need to store the table, just p
sym = "\\char " .. chr
end
if tonumber(chr) < 0 then
- texsprint(ct, template:format(name, "", sym, id, cs))
+ texsprint(ctxcatcodes, format(template, name, "", sym, id, cs))
else
- texsprint(ct, template:format(name, chr, sym, id, cs))
+ texsprint(ctxcatcodes, format(template, name, chr, sym, id, cs))
end
end
- texsprint(ct, "\\stoptabulate")
+ texsprint(ctxcatcodes, "\\stoptabulate")
end
collectors.show_methods.b_c = function(data,swap) -- no need to store the table, just pass directly
- local ct = tex.ctxcatcodes
local template = "\\NC %s\\NC %s\\NC %s\\NC\\NR"
if swap then
- texsprint(ct, "\\starttabulate[|Tl|Tl|Tr|]")
+ texsprint(ctxcatcodes, "\\starttabulate[|Tl|Tl|Tr|]")
else
- texsprint(ct, "\\starttabulate[|Tl|Tr|Tl|]")
+ texsprint(ctxcatcodes, "\\starttabulate[|Tl|Tr|Tl|]")
end
- texsprint(ct, template:format("cmd","chr","name"))
- texsprint(ct, "\\HL")
+ texsprint(ctxcatcodes, format(template,"cmd","chr","name"))
+ texsprint(ctxcatcodes, "\\HL")
for _,v in pairs(data) do
local cmd, chr, id, cs, sym = v[1], v[2], v[3], "", ""
- local name = (token.command_name(v) or ""):gsub("_","\\_")
+ local name = gsub(token.command_name(v) or "","_","\\_")
if id > 0 then
cs = token.csname_name(v) or ""
end
@@ -248,14 +247,14 @@ collectors.show_methods.b_c = function(data,swap) -- no need to store the table,
end
end
if swap then
- texsprint(ct, template:format(name, sym, chr))
+ texsprint(ctxcatcodes, format(template, name, sym, chr))
elseif tonumber(chr) < 0 then
- texsprint(ct, template:format(name, "", sym))
+ texsprint(ctxcatcodes, format(template, name, "", sym))
else
- texsprint(ct, template:format(name, chr, sym))
+ texsprint(ctxcatcodes, format(template, name, chr, sym))
end
end
- texsprint(ct, "\\stoptabulate")
+ texsprint(ctxcatcodes, "\\stoptabulate")
end
-- Even more experimental ...
diff --git a/tex/context/base/toks-ini.tex b/tex/context/base/toks-ini.tex
index 90311eb13..932c05f32 100644
--- a/tex/context/base/toks-ini.tex
+++ b/tex/context/base/toks-ini.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=toks-ini,
%D version=2007.03.03,
-%D title=\CONTEXT\ Character Macros,
-%D subtitle=Token Support (Initialization),
+%D title=\CONTEXT\ Token Support,
+%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Token Support (initialization)}
+\writestatus{loading}{ConTeXt Token Support / Initialization}
\registerctxluafile{toks-ini}{1.001}
diff --git a/tex/context/base/luat-deb.lua b/tex/context/base/trac-deb.lua
index a32d923bd..f476169c3 100644
--- a/tex/context/base/luat-deb.lua
+++ b/tex/context/base/trac-deb.lua
@@ -1,10 +1,11 @@
--- filename : luat-deb.lua
--- comment : companion to luat-deb.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['trac-deb'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['luat-deb'] = 1.001
if not lmx then lmx = { } end
if not lmx.variables then lmx.variables = { } end
@@ -21,6 +22,9 @@ lmx.variables['color-background-two'] = lmx.variables['color-background-blue'
lmx.variables['title-default'] = 'ConTeXt Status Information'
lmx.variables['title'] = lmx.variables['title-default']
+lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
+lmx.lmxfile = function(name) return resolvers.find_file(name,'tex') end
+
if not tracers then tracers = { } end
if not tracers.list then tracers.list = { } end
if not tracers.strings then tracers.strings = { } end
@@ -133,9 +137,6 @@ function tracers.showerror()
end
function tracers.overloaderror()
---~ callback.register('show_error_hook', function(identifier, filename, linenumber)
---~ tracers.showerror(identifier, filename, linenumber)
---~ end )
callback.register('show_error_hook', tracers.showerror)
end
@@ -152,3 +153,54 @@ tracers.list['context'] = {
'd:lineheight',
'c:realpageno', 'c:pageno', 'c:subpageno'
}
+
+-- dumping the hash
+
+-- \starttext
+-- \ctxlua{tracers.dump_hash()}
+-- \stoptext
+
+local saved = { }
+
+function tracers.save_hash()
+ saved = tex.hashtokens()
+end
+
+function tracers.dump_hash(filename,delta)
+ filename = filename or tex.jobname .. "-hash.log"
+ local list = { }
+ local hash = tex.hashtokens()
+ local command_name = token.command_name
+ for name, token in pairs(hash) do
+ if not delta or not saved[name] then
+ -- token: cmd, chr, csid -- combination cmd,chr determines name
+ local kind = command_name(token)
+ local dk = list[kind]
+ if not dk then
+ -- a bit funny names but this sorts better (easier to study)
+ dk = { names = { }, found = 0, code = token[1] }
+ list[kind] = dk
+ end
+ dk.names[name] = { token[2], token[3] }
+ dk.found = dk.found + 1
+ end
+ end
+ io.savedata(filename,table.serialize(list,true))
+end
+
+function tracers.register_dump_hash(delta)
+ if delta then
+ tracers.save_hash()
+ end
+ main.register_stop_actions(1,function() tracers.dump_hash(nil,true) end) -- at front
+end
+
+-- trackers (maybe group the show by class)
+
+function trackers.show()
+ commands.writestatus("","")
+ for k,v in ipairs(trackers.list()) do
+ commands.writestatus("tracker",v)
+ end
+ commands.writestatus("","")
+end
diff --git a/tex/context/base/luat-deb.tex b/tex/context/base/trac-deb.tex
index 55686ac11..870c452ad 100644
--- a/tex/context/base/luat-deb.tex
+++ b/tex/context/base/trac-deb.tex
@@ -1,8 +1,8 @@
%D \module
-%D [ file=luat-deb,
+%D [ file=trac-deb,
%D version=2005.11.06,
-%D title=\CONTEXT\ Communication Macros,
-%D subtitle=Initialization,
+%D title=\CONTEXT\ Tracing Macros,
+%D subtitle=Debugger,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,24 +11,15 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Communication Support (initialization)}
+\writestatus{loading}{ConTeXt Tracing Macros / Debugger}
-\registerctxluafile{luat-deb}{1.001}
-
-\startruntimeluacode
- \ctxlua {
- lmx.htmfile = function(name) return environment.jobname .. "-status.html" end
- lmx.lmxfile = function(name) return environment.texfile(name) end
- }
-\stopruntimeluacode
+\registerctxluafile{trac-deb}{1.001}
\def\showdebuginfo{\ctxlua{tracers.showdebuginfo()}}
\def\overloaderror{\ctxlua{tracers.overloaderror()}}
\def\breakpoint{\showdebuginfo\wait}
-\registerctxluafile{luat-tra}{1.001}
-
\appendtoks
\ctxlua {
if debugger.tracing() then
@@ -46,4 +37,7 @@
}%
\to \everybye
-\endinput
+\def\showtrackers {\ctxlua{trackers.show()}}
+\def\resettrackers {\ctxlua{trackers.reset()}}
+\def\enabletrackers [#1]{\ctxlua{trackers.enable("#1")}}
+\def\disabletrackers[#1]{\ctxlua{trackers.disable("#1")}}
diff --git a/tex/context/base/trac-inf.lua b/tex/context/base/trac-inf.lua
new file mode 100644
index 000000000..41a9e7b48
--- /dev/null
+++ b/tex/context/base/trac-inf.lua
@@ -0,0 +1,149 @@
+if not modules then modules = { } end modules ['trac-inf'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format = string.format
+
+local statusinfo, n, registered = { }, 0, { }
+
+statistics = statistics or { }
+
+statistics.enable = true
+statistics.threshold = 0.05
+
+-- timing functions
+
+local clock = os.gettimeofday or os.clock
+
+function statistics.hastimer(instance)
+ return instance and instance.starttime
+end
+
+function statistics.starttiming(instance)
+ if instance then
+ local it = instance.timing
+ if not it then
+ it = 0
+ end
+ if it == 0 then
+ instance.starttime = clock()
+ if not instance.loadtime then
+ instance.loadtime = 0
+ end
+ end
+ instance.timing = it + 1
+ end
+end
+
+function statistics.stoptiming(instance, report)
+ if instance then
+ local it = instance.timing
+ if it > 1 then
+ instance.timing = it - 1
+ else
+ local starttime = instance.starttime
+ if starttime then
+ local stoptime = clock()
+ local loadtime = stoptime - starttime
+ instance.stoptime = stoptime
+ instance.loadtime = instance.loadtime + loadtime
+ if report then
+ statistics.report("load time %0.3f",loadtime)
+ end
+ instance.timing = 0
+ return loadtime
+ end
+ end
+ end
+ return 0
+end
+
+function statistics.elapsedtime(instance)
+ return format("%0.3f",(instance and instance.loadtime) or 0)
+end
+
+function statistics.elapsedindeed(instance)
+ local t = (instance and instance.loadtime) or 0
+ return t > statistics.threshold
+end
+
+-- general function
+
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc) == "function" then
+ local rt = registered[tag] or (#statusinfo + 1)
+ statusinfo[rt] = { tag, fnc }
+ registered[tag] = rt
+ if #tag > n then n = #tag end
+ end
+end
+
+function statistics.show(reporter)
+ if statistics.enable then
+ if not reporter then reporter = function(tag,data,n) texio.write_nl(tag .. " " .. data) end end
+ -- this code will move
+ local register = statistics.register
+ register("luatex banner", function()
+ return string.lower(status.banner)
+ end)
+ register("control sequences", function()
+ return format("%s of %s", status.cs_count, status.hash_size+status.hash_extra)
+ end)
+ register("callbacks", function()
+ local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
+ return format("direct: %s, indirect: %s, total: %s", total-indirect, indirect, total)
+ end)
+ register("current memory usage", statistics.memused)
+ register("runtime",statistics.runtime)
+-- --
+ for i=1,#statusinfo do
+ local s = statusinfo[i]
+ local r = s[2]()
+ if r then
+ reporter(s[1],r,n)
+ end
+ end
+ statistics.enable = false
+ end
+end
+
+function statistics.show_job_stat(tag,data,n)
+ texio.write_nl(format("%-15s: %s - %s","mkiv lua stats",tag:rpadd(n," "),data))
+end
+
+function statistics.memused() -- no math.round yet -)
+ local round = math.round or math.floor
+ return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000), round(status.luastate_bytes/1000000))
+end
+
+if statistics.runtime then
+ -- already loaded and set
+elseif luatex and luatex.starttime then
+ statistics.starttime = luatex.starttime
+ statistics.loadtime = 0
+ statistics.timing = 0
+else
+ statistics.starttiming(statistics)
+end
+
+function statistics.runtime()
+ statistics.stoptiming(statistics)
+ return statistics.formatruntime(statistics.elapsedtime(statistics))
+end
+
+function statistics.formatruntime(runtime)
+ return format("%s seconds", statistics.elapsedtime(statistics))
+end
+
+function statistics.timed(action,report)
+ local timer = { }
+ report = report or logs.simple
+ statistics.starttiming(timer)
+ action()
+ statistics.stoptiming(timer)
+ report("total runtime: %s",statistics.elapsedtime(timer))
+end
diff --git a/tex/context/base/luat-lmx.lua b/tex/context/base/trac-lmx.lua
index b9bab7df1..07f5ae291 100644
--- a/tex/context/base/luat-lmx.lua
+++ b/tex/context/base/trac-lmx.lua
@@ -1,14 +1,16 @@
--- filename : luat-lmx.lua
--- comment : companion to luat-lmx.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['trac-lmx'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-if not versions then versions = { } end versions['luat-mlx'] = 1.001
+local gsub, format, concat = string.gsub, string.format, table.concat
-- we can now use l-xml, and we can also use lpeg
-lmx = { }
+lmx = lmx or { }
lmx.escapes = {
['&'] = '&amp;',
@@ -27,26 +29,32 @@ lmx.variables['title'] = lmx.variables['title-default']
-- demonstrates: local, *all, gsub using tables, nil or value, loadstring
function lmx.loadedfile(filename)
- return input.texdatablob(filename)
+ return io.loaddata(resolvers.find_file(filename))
end
lmx.converting = false
+local templates = { }
+
function lmx.convert(template,result) -- todo: use lpeg instead
if not lmx.converting then -- else, if error then again tex error and loop
- local data = input.texdatablob(template)
- local f = false
- if result then
- f = io.open(result,"w")
- function lmx.print(str) f:write(str) end
- else
- lmx.print = io.write
+ local data = templates[template]
+ if not data then
+ data = lmx.loadedfile(template)
+ templates[template] = data
+ end
+ local text = { }
+ function lmx.print(...)
+ text[#text+1] = concat({...})
end
function lmx.variable(str)
return lmx.variables[str] or ""
end
function lmx.escape(str)
- return string.gsub(str:gsub('&','&amp;'),'[<>"]',lmx.escapes)
+ str = tostring(str)
+ str = gsub(str,'&','&amp;')
+ str = gsub(str,'[<>"]',lmx.escapes)
+ return str
end
function lmx.type(str)
if str then lmx.print("<tt>" .. lmx.escape(str) .. "</tt>") end
@@ -57,41 +65,44 @@ function lmx.convert(template,result) -- todo: use lpeg instead
function lmx.tv(str)
lmx.type(lmx.variable(str))
end
- data = data:gsub("<%?lmx%-include%s+(.-)%s-%?>", function(filename)
+ data = gsub(data,"<%?lmx%-include%s+(.-)%s-%?>", function(filename)
return lmx.loadedfile(filename)
end)
local definitions = { }
- data = data:gsub("<%?lmx%-define%-begin%s+(%S-)%s-%?>(.-)<%?lmx%-define%-end%s-%?>", function(tag,content)
+ data = gsub(data,"<%?lmx%-define%-begin%s+(%S-)%s-%?>(.-)<%?lmx%-define%-end%s-%?>", function(tag,content)
definitions[tag] = content
return ""
end)
- data = data:gsub("<%?lmx%-resolve%s+(%S-)%s-%?>", function(tag)
+ data = gsub(data,"<%?lmx%-resolve%s+(%S-)%s-%?>", function(tag)
return definitions[tag] or ""
end)
- data = data:gsub("%c%s-(<%?lua .-%?>)%s-%c", function(lua)
+ data = gsub(data,"%c%s-(<%?lua .-%?>)%s-%c", function(lua)
return "\n" .. lua .. " "
end)
- data = string.gsub(data .. "<?lua ?>","(.-)<%?lua%s+(.-)%?>", function(txt, lua)
- txt = txt:gsub("%c+", "\\n")
- txt = txt:gsub('"' , '\\"')
- txt = txt:gsub("'" , "\\'")
- -- txt = string.gsub(txt, "([\'\"])", { ["'"] = '\\"', ['"'] = "\\'" } )
+ data = gsub(data .. "<?lua ?>","(.-)<%?lua%s+(.-)%?>", function(txt, lua)
+ txt = gsub(txt,"%c+", "\\n")
+ txt = gsub(txt,'"' , '\\"')
+ txt = gsub(txt,"'" , "\\'")
+ -- txt = gsub(txt,"([\'\"])", { ["'"] = '\\"', ['"'] = "\\'" } )
return "p(\"" .. txt .. "\")\n" .. lua .. "\n"
end)
lmx.converting = true
data = "local p,v,e,t,pv,tv = lmx.print,lmx.variable,lmx.escape,lmx.type,lmx.pv,lmx.tv " .. data
assert(loadstring(data))()
lmx.converting = false
- if f then
- f:close()
+ text = concat(text)
+ if result then
+ io.savedata(result,text)
+ else
+ return text
end
end
end
-- these can be overloaded; we assume that the os handles filename associations
-lmx.lmxfile = function(filename) return filename end
-lmx.htmfile = function(filename) return filename end
+lmx.lmxfile = function(filename) return filename end
+lmx.htmfile = function(filename) return filename end
if os.platform == "windows" then
lmx.popupfile = function(filename) os.execute("start " .. filename) end
@@ -99,14 +110,20 @@ else
lmx.popupfile = function(filename) os.execute(filename) end
end
-function lmx.show(name)
+function lmx.make(name)
local lmxfile = lmx.lmxfile(name)
local htmfile = lmx.htmfile(name)
if lmxfile == htmfile then
- htmfile = string.gsub(lmxfile, "%.%a+$", "html")
+ htmfile = gsub(lmxfile, "%.%a+$", "html")
end
lmx.convert(lmxfile, htmfile)
+ return htmfile
+end
+
+function lmx.show(name)
+ local htmfile = lmx.make(name)
lmx.popupfile(htmfile)
+ return htmfile
end
-- kind of private
diff --git a/tex/context/base/luat-lmx.tex b/tex/context/base/trac-lmx.tex
index cc7fa448f..a47d2b8bb 100644
--- a/tex/context/base/luat-lmx.tex
+++ b/tex/context/base/trac-lmx.tex
@@ -1,8 +1,8 @@
%D \module
-%D [ file=luat-lmx,
+%D [ file=trac-lmx,
%D version=2005.09.02,
-%D title=\CONTEXT\ Lua Macros,
-%D subtitle=LMX Support,
+%D title=\CONTEXT\ Tracing Macros,
+%D subtitle=LMX,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright=PRAGMA]
@@ -11,6 +11,6 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Lua Support Macros (lmx)}
+\writestatus{loading}{ConTeXt Tracing Macros / LMX}
-\registerctxluafile{luat-lmx}{1.001}
+\registerctxluafile{trac-lmx}{1.001}
diff --git a/tex/context/base/trac-log.lua b/tex/context/base/trac-log.lua
new file mode 100644
index 000000000..1fb25c5c7
--- /dev/null
+++ b/tex/context/base/trac-log.lua
@@ -0,0 +1,285 @@
+if not modules then modules = { } end modules ['luat-log'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is old code that needs an overhaul
+
+local write_nl, write, format = texio.write_nl or print, texio.write or io.write, string.format
+
+if texlua then
+ write_nl = print
+ write = io.write
+end
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. For the sake
+of parsing log files, in addition to the standard logging we will
+provide an <l n='xml'/> structured file. Actually, any logging that
+is hooked into callbacks will be \XML\ by default.</p>
+--ldx]]--
+
+logs = logs or { }
+logs.xml = logs.xml or { }
+logs.tex = logs.tex or { }
+
+--[[ldx--
+<p>This looks pretty ugly but we need to speed things up a bit.</p>
+--ldx]]--
+
+logs.moreinfo = [[
+more information about ConTeXt and the tools that come with it can be found at:
+
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+logs.levels = {
+ ['error'] = 1,
+ ['warning'] = 2,
+ ['info'] = 3,
+ ['debug'] = 4,
+}
+
+logs.functions = {
+ 'report', 'start', 'stop', 'push', 'pop', 'line', 'direct',
+ 'start_run', 'stop_run',
+ 'start_page_number', 'stop_page_number',
+ 'report_output_pages', 'report_output_log',
+ 'report_tex_stat', 'report_job_stat',
+ 'show_open', 'show_close', 'show_load',
+}
+
+logs.tracers = {
+}
+
+logs.level = 0
+logs.mode = string.lower((os.getenv("MTX.LOG.MODE") or os.getenv("MTX_LOG_MODE") or "tex"))
+
+function logs.set_level(level)
+ logs.level = logs.levels[level] or level
+end
+
+function logs.set_method(method)
+ for _, v in next, logs.functions do
+ logs[v] = logs[method][v] or function() end
+ end
+end
+
+-- tex logging
+
+function logs.tex.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(category .. " | " .. format(fmt,...))
+ else
+ write_nl(category .. " |")
+ end
+end
+
+function logs.tex.line(fmt,...) -- new
+ if fmt then
+ write_nl(format(fmt,...))
+ else
+ write_nl("")
+ end
+end
+
+local texcount = tex and tex.count
+
+function logs.tex.start_page_number()
+ local real, user, sub = texcount[0], texcount[1], texcount[2]
+ if real > 0 then
+ if user > 0 then
+ if sub > 0 then
+ write(format("[%s.%s.%s",real,user,sub))
+ else
+ write(format("[%s.%s",real,user))
+ end
+ else
+ write(format("[%s",real))
+ end
+ else
+ write("[-")
+ end
+end
+
+function logs.tex.stop_page_number()
+ write("]")
+end
+
+logs.tex.report_job_stat = statistics.show_job_stat
+
+-- xml logging
+
+function logs.xml.report(category,fmt,...) -- new
+ if fmt then
+ write_nl(format("<r category='%s'>%s</r>",category,format(fmt,...)))
+ else
+ write_nl(format("<r category='%s'/>",category))
+ end
+end
+function logs.xml.line(fmt,...) -- new
+ if fmt then
+ write_nl(format("<r>%s</r>",format(fmt,...)))
+ else
+ write_nl("<r/>")
+ end
+end
+
+function logs.xml.start() if logs.level > 0 then tw("<%s>" ) end end
+function logs.xml.stop () if logs.level > 0 then tw("</%s>") end end
+function logs.xml.push () if logs.level > 0 then tw("<!-- ") end end
+function logs.xml.pop () if logs.level > 0 then tw(" -->" ) end end
+
+function logs.xml.start_run()
+ write_nl("<?xml version='1.0' standalone='yes'?>")
+ write_nl("<job>") -- xmlns='www.pragma-ade.com/luatex/schemas/context-job.rng'
+ write_nl("")
+end
+
+function logs.xml.stop_run()
+ write_nl("</job>")
+end
+
+function logs.xml.start_page_number()
+ write_nl(format("<p real='%s' page='%s' sub='%s'", texcount[0], texcount[1], texcount[2]))
+end
+
+function logs.xml.stop_page_number()
+ write("/>")
+ write_nl("")
+end
+
+function logs.xml.report_output_pages(p,b)
+ write_nl(format("<v k='pages' v='%s'/>", p))
+ write_nl(format("<v k='bytes' v='%s'/>", b))
+ write_nl("")
+end
+
+function logs.xml.report_output_log()
+end
+
+function logs.xml.report_tex_stat(k,v)
+ texiowrite_nl("log","<v k='"..k.."'>"..tostring(v).."</v>")
+end
+
+local level = 0
+
+function logs.xml.show_open(name)
+ level = level + 1
+ texiowrite_nl(format("<f l='%s' n='%s'>",level,name))
+end
+
+function logs.xml.show_close(name)
+ texiowrite("</f> ")
+ level = level - 1
+end
+
+function logs.xml.show_load(name)
+ texiowrite_nl(format("<f l='%s' n='%s'/>",level+1,name))
+end
+
+--
+
+local name, banner = 'report', 'context'
+
+local function report(category,fmt,...)
+ if fmt then
+ write_nl(format("%s | %s: %s",name,category,format(fmt,...)))
+ elseif category then
+ write_nl(format("%s | %s",name,category))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+local function simple(fmt,...)
+ if fmt then
+ write_nl(format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl(format("%s |",name))
+ end
+end
+
+function logs.setprogram(_name_,_banner_,_verbose_)
+ name, banner = _name_, _banner_
+ if _verbose_ then
+ trackers.enable("resolvers.verbose")
+ end
+ logs.set_method("tex")
+ logs.report = report -- also used in libraries
+ logs.simple = simple -- only used in scripts !
+ if utils then
+ utils.report = simple
+ end
+ logs.verbose = _verbose_
+end
+
+function logs.setverbose(what)
+ if what then
+ trackers.enable("resolvers.verbose")
+ else
+ trackers.disable("resolvers.verbose")
+ end
+ logs.verbose = what or false
+end
+
+function logs.extendbanner(_banner_,_verbose_)
+ banner = banner .. " | ".. _banner_
+ if _verbose_ ~= nil then
+ logs.setverbose(what)
+ end
+end
+
+logs.verbose = false
+logs.report = logs.tex.report
+logs.simple = logs.tex.report
+
+function logs.reportlines(str) -- todo: <lines></lines>
+ for line in str:gmatch("(.-)[\n\r]") do
+ logs.report(line)
+ end
+end
+
+function logs.reportline() -- for scripts too
+ logs.report()
+end
+
+logs.simpleline = logs.reportline
+
+function logs.help(message,option)
+ logs.report(banner)
+ logs.reportline()
+ logs.reportlines(message)
+ local moreinfo = logs.moreinfo or ""
+ if moreinfo ~= "" and option ~= "nomoreinfo" then
+ logs.reportline()
+ logs.reportlines(moreinfo)
+ end
+end
+
+logs.set_level('error')
+logs.set_method('tex')
+
+function logs.system(whereto,process,jobname,category,...)
+ for i=1,10 do
+ local f = io.open(whereto,"a")
+ if f then
+ f:write(format("%s %s => %s => %s => %s\r",os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)))
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+--~ local syslogname = "oeps.xxx"
+--~
+--~ for i=1,10 do
+--~ logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+--~ end
diff --git a/tex/context/base/trac-tim.lua b/tex/context/base/trac-tim.lua
new file mode 100644
index 000000000..82c03f4c7
--- /dev/null
+++ b/tex/context/base/trac-tim.lua
@@ -0,0 +1,163 @@
+if not modules then modules = { } end modules ['trac-tim'] = {
+ version = 1.001,
+ comment = "companion to m-timing.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+goodies = goodies or { }
+goodies.progress = goodies.progress or { }
+
+local progress = goodies.progress
+
+progress = progress or { }
+
+progress.defaultfilename = ((tex and tex.jobname) or "whatever") .. "-luatex-progress"
+
+local params = {
+ "cs_count",
+ "dyn_used",
+ "elapsed_time",
+ "luabytecode_bytes",
+ "luastate_bytes",
+ "max_buf_stack",
+ "obj_ptr",
+ "pdf_mem_ptr",
+ "pdf_mem_size",
+ "pdf_os_cntr",
+ "pool_ptr",
+ "str_ptr",
+}
+
+-- storage
+
+local last = os.clock()
+local data = { }
+
+function progress.save()
+ local f = io.open((name or progress.defaultfilename) .. ".lut","w")
+ if f then
+ f:write(table.serialize(data,true))
+ f:close()
+ data = { }
+ end
+end
+
+function progress.store()
+ local c = os.clock()
+ local t = {
+ elapsed_time = c - last,
+ node_memory = nodes.usage(),
+ }
+ for k, v in pairs(params) do
+ if status[v] then t[v] = status[v] end
+ end
+ data[#data+1] = t
+ last = c
+end
+
+-- conversion
+
+local processed = { }
+
+function progress.bot(name,tag)
+ local d = progress.convert(name)
+ return d.bot[tag] or 0
+end
+function progress.top(name,tag)
+ local d = progress.convert(name)
+ return d.top[tag] or 0
+end
+function progress.pages(name,tag)
+ local d = progress.convert(name)
+ return d.pages or 0
+end
+function progress.path(name,tag)
+ local d = progress.convert(name)
+ return d.paths[tag] or "origin"
+end
+function progress.nodes(name)
+ local d = progress.convert(name)
+ return d.names or { }
+end
+function progress.parameters(name)
+ local d = progress.convert(name)
+ return params -- shared
+end
+
+function progress.convert(name)
+ name = ((name ~= "") and name) or progress.defaultfilename
+ if not processed[name] then
+ local names, top, bot, pages, paths, keys = { }, { }, { }, 0, { }, { }
+ local data = io.loaddata(name .. ".lut")
+ if data then data = loadstring(data) end
+ if data then data = data() end
+ if data then
+ pages = #data
+ if pages > 1 then
+ local factor = 100
+ for k,v in ipairs(data) do
+ for k,v in pairs(v.node_memory) do
+ keys[k] = true
+ end
+ end
+ for k,v in ipairs(data) do
+ local m = v.node_memory
+ for k, _ in pairs(keys) do
+ if not m[k] then m[k] = 0 end
+ end
+ end
+ local function path(tag,subtag)
+ local b, t, s = nil, nil, { }
+ for k,v in ipairs(data) do
+ local v = (subtag and v[tag][subtag]) or v[tag]
+ if v then
+ v = tonumber(v)
+ if b then
+ if v > t then t = v end
+ if v < b then b = v end
+ else
+ t = v
+ b = v
+ end
+ s[k] = v
+ else
+ s[k] = 0
+ end
+ end
+ local tagname = subtag or tag
+ top[tagname] = (string.format("%.3f",t)):gsub("%.000$","")
+ bot[tagname] = (string.format("%.3f",b)):gsub("%.000$","")
+ local delta = t-b
+ if delta == 0 then
+ delta = 1
+ else
+ delta = factor/delta
+ end
+ for k, v in ipairs(s) do
+ s[k] = "(" .. k .. "," .. (v-b)*delta .. ")"
+ end
+ paths[tagname] = table.concat(s,"--")
+ end
+ for _, tag in pairs(params) do
+ path(tag)
+ end
+ for tag, _ in pairs(keys) do
+ path("node_memory",tag)
+ names[#names+1] = tag
+ end
+ pages = pages - 1
+ end
+ end
+ table.sort(names)
+ processed[name] = {
+ names = names,
+ top = top,
+ bot = bot,
+ pages = pages,
+ paths = paths,
+ }
+ end
+ return processed[name]
+end
diff --git a/tex/context/base/luat-tra.lua b/tex/context/base/trac-tra.lua
index 5314b48c6..8a51d33b9 100644
--- a/tex/context/base/luat-tra.lua
+++ b/tex/context/base/trac-tra.lua
@@ -1,21 +1,21 @@
--- filename : luat-tra.lua
--- comment : companion to luat-lib.tex
--- author : Hans Hagen, PRAGMA-ADE, Hasselt NL
--- copyright: PRAGMA ADE / ConTeXt Development Team
--- license : see context related readme files
+if not modules then modules = { } end modules ['trac-tra'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
-- the <anonymous> tag is kind of generic and used for functions that are not
-- bound to a variable, like node.new, node.copy etc (contrary to for instance
-- node.has_attribute which is bound to a has_attribute local variable in mkiv)
-if not versions then versions = { } end versions['luat-tra'] = 1.001
-
-debugger = { }
+debugger = debugger or { }
local counters = { }
-local names = { }
-local getinfo = debug.getinfo
-local format = string.format
+local names = { }
+local getinfo = debug.getinfo
+local format, find, lower, gmatch = string.format, string.find, string.lower, string.gmatch
-- one
@@ -143,3 +143,79 @@ end
--~ print("")
--~ debugger.showstats(print,3)
+trackers = trackers or { }
+
+local data, done = { }, { }
+
+local function set(what,value)
+ for w in gmatch(lower(what),"[^, ]+") do
+ for d, f in next, data do
+ if done[d] then
+ -- prevent recursion due to wildcards
+ elseif find(d,w) then
+ done[d] = true
+ for i=1,#f do
+ f[i](value)
+ end
+ end
+ end
+ end
+end
+
+local function reset()
+ for d, f in next, data do
+ for i=1,#f do
+ f[i](false)
+ end
+ end
+end
+
+function trackers.register(what,...)
+ what = lower(what)
+ local w = data[what]
+ if not w then
+ w = { }
+ data[what] = w
+ end
+ for _, fnc in next, { ... } do
+ local typ = type(fnc)
+ if typ == "function" then
+ w[#w+1] = fnc
+ elseif typ == "string" then
+ w[#w+1] = function(value) set(fnc,value,nesting) end
+ end
+ end
+end
+
+function trackers.enable(what)
+ done = { }
+ set(what,true)
+end
+
+function trackers.disable(what)
+ done = { }
+ if not what or what == "" then
+ trackers.reset(what)
+ else
+ set(what,false)
+ end
+end
+
+function trackers.reset(what)
+ done = { }
+ reset()
+end
+
+function trackers.list() -- pattern
+ local list = table.sortedkeys(data)
+ local user, system = { }, { }
+ for l=1,#list do
+ local what = list[l]
+ if find(what,"^%*") then
+ system[#system+1] = what
+ else
+ user[#user+1] = what
+ end
+ end
+ return user, system
+end
diff --git a/tex/context/base/type-cow.tex b/tex/context/base/type-cow.tex
index bda8489a5..507386443 100644
--- a/tex/context/base/type-cow.tex
+++ b/tex/context/base/type-cow.tex
@@ -70,14 +70,14 @@
\definetypeface [cow] [rm][serif][cow] [default][encoding=default]
\definetypeface [cow] [ss][serif][cow] [default][encoding=default]
\definetypeface [cow] [mm][math] [cow] [default][encoding=default]
- \definetypeface [cow] [tt][mono] [modern][default][encoding=default,rscale=.85]
+ \definetypeface [cow] [tt][mono] [modern][default][encoding=default,rscale=0.85]
\stoptypescript
\starttypescript [sheep] [default]
\definetypeface [sheep][rm][serif][sheep] [default][encoding=default]
\definetypeface [sheep][ss][serif][sheep] [default][encoding=default]
\definetypeface [sheep][mm][math] [sheep] [default][encoding=default]
- \definetypeface [sheep][tt][mono] [modern][default][encoding=default,rscale=.85]
+ \definetypeface [sheep][tt][mono] [modern][default][encoding=default,rscale=0.85]
\stoptypescript
\stoptypescriptcollection
diff --git a/tex/context/base/type-gyr.tex b/tex/context/base/type-gyr.tex
deleted file mode 100644
index ee21cc784..000000000
--- a/tex/context/base/type-gyr.tex
+++ /dev/null
@@ -1,252 +0,0 @@
-%D \module
-%D [ file=type-gyr,
-%D version=2006.06.28,
-%D title=\CONTEXT\ Typescript Macros,
-%D subtitle=TeXGyre Collection,
-%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.
-
-% \beginNEWTEX already-otf-gyre
-% \endinput
-% \endNEWTEX
-
-%D These definitions will eventually replace the ones in \type {type-one}!
-
-% \usetypescriptfile[type-gyr]
-% \definetypeface[pagella][rm][serif][pagella][default][encoding=t5]
-% \setupbodyfont[pagella]
-% \starttext
-% \startlines
-% hello world 123
-% {hello \Var[sc] world 123}
-% {\it hello \Var[sc]world \Var[reset] 123}
-% {\bf hello \Var[osf] {\Var[reset] world} 123}
-% {\bi hello world \Var[osf]123}
-% {\sc hello \Var[sc] world \Var[reset] 123}
-% \stoplines
-% \showfont[SerifItalicCaps]
-% \stoptext
-
-% Beware, because tetex demanded a different map file naming scheme, we ship
-% alternatively named files as well, just to make sure that older installations
-% still work (where users may load their own instances). In due time we will
-% follow that scheme (well, in due time we will drop map files anyway).
-
-\starttypescriptcollection[gyre]
-
-%D First we define the new ones. Watch how we use the systematic name composition.
-
-\definetypescriptprefix [n:pagella] [TeXGyrePagella]
-\definetypescriptprefix [n:termes] [TeXGyreTermes]
-\definetypescriptprefix [n:heros] [TeXGyreHeros]
-\definetypescriptprefix [n:bonum] [TeXGyreBonum]
-\definetypescriptprefix [n:schola] [TeXGyreSchola]
-\definetypescriptprefix [n:adventor][TeXGyreAdventor]
-\definetypescriptprefix [n:cursor] [TeXGyreCursor]
-
-\definetypescriptprefix [f:pagella] [pl]
-\definetypescriptprefix [f:termes] [tm]
-\definetypescriptprefix [f:heros] [hv]
-\definetypescriptprefix [f:bonum] [bk]
-\definetypescriptprefix [f:schola] [cs]
-\definetypescriptprefix [f:adventor][ag]
-\definetypescriptprefix [f:cursor] [cr]
-
-\starttypescript [serif,sans,mono] [pagella,termes,heros,bonum,schola,adventor,cursor] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}r] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}ri] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}b] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}bi] [encoding=\typescriptthree]
-
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Caps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}r-sc] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}ri-sc] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}b-sc] [encoding=\typescriptthree]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}bi-sc] [encoding=\typescriptthree]
-
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Slanted] [\typescriptprefix{n:\typescripttwo}-Italic]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
-
- \loadmapfile[q\typescriptprefix{f:\typescripttwo}-\typescriptthree.map]
-\stoptypescript
-
-\starttypescript [serif] [pagella,termes,bonum,schola] [name]
- \definefontsynonym [Serif] [\typescriptprefix{n:\typescripttwo}-Regular]
- \definefontsynonym [SerifItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
- \definefontsynonym [SerifBold] [\typescriptprefix{n:\typescripttwo}-Bold]
- \definefontsynonym [SerifBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
- \definefontsynonym [SerifCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SerifSlanted] [\typescriptprefix{n:\typescripttwo}-Slanted]
- \definefontsynonym [SerifBoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldSlanted]
-
- \definefontvariant [Serif][osf][Caps]
- \definefontvariant [Serif][sc] [Caps]
-
- \definefontsynonym [SerifRegular] [\typescriptprefix{n:\typescripttwo}-Regular]
- \definefontsynonym [SerifRegularCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SerifItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
- \definefontsynonym [SerifBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps]
- \definefontsynonym [SerifBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
- \definefontsynonym [SerifCapsCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SerifSlantedCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
- \definefontsynonym [SerifBoldSlantedCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
-\stoptypescript
-
-\starttypescript [sans] [heros,adventor] [name]
- \definefontsynonym [Sans] [\typescriptprefix{n:\typescripttwo}-Regular]
- \definefontsynonym [SansItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
- \definefontsynonym [SansBold] [\typescriptprefix{n:\typescripttwo}-Bold]
- \definefontsynonym [SansBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
- \definefontsynonym [SansCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SansSlanted] [\typescriptprefix{n:\typescripttwo}-Slanted]
- \definefontsynonym [SansBoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldSlanted]
-
- \definefontvariant [Sans][osf][Caps]
- \definefontvariant [Sans][sc] [Caps]
-
- \definefontsynonym [SansRegular] [\typescriptprefix{n:\typescripttwo}-Regular]
- \definefontsynonym [SansRegularCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SansItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
- \definefontsynonym [SansBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps]
- \definefontsynonym [SansBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
- \definefontsynonym [SansCapsCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
- \definefontsynonym [SansSlantedCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
- \definefontsynonym [SansBoldSlantedCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
-\stoptypescript
-
-%D Here we overload the older (URW) fonts.
-
-% TeXGyrePagella
-%
-% qplr TeXGyrePagella-Regular
-% qplri TeXGyrePagella-Italic
-% qplb TeXGyrePagella-Bold
-% qplbi TeXGyrePagella-BoldItalic
-
-\starttypescript [serif] [palatino] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Palatino] [\typescriptthree-qplr] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Italic] [\typescriptthree-qplri] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Bold] [\typescriptthree-qplb] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-BoldItalic] [\typescriptthree-qplbi] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Caps] [\typescriptthree-qplr-sc] [encoding=\typescriptthree]
-
- \definefontsynonym [Palatino-Slanted] [Palatino-Italic]
- \definefontsynonym [Palatino-BoldSlanted] [Palatino-BoldItalic]
-
- \loadmapfile[qpl-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-palatino.map]
-\stoptypescript
-
-% TeXGyreTermes
-%
-% qtmr TeXGyreTermes-Regular
-% qtmri TeXGyreTermes-Italic
-% qtmb TeXGyreTermes-Bold
-% qtmbi TeXGyreTermes-BoldItalic
-
-\starttypescript [serif] [times] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Times-Roman] [\typescriptthree-qtmr] [encoding=\typescriptthree]
- \definefontsynonym [Times-Italic] [\typescriptthree-qtmri] [encoding=\typescriptthree]
- \definefontsynonym [Times-Bold] [\typescriptthree-qtmb] [encoding=\typescriptthree]
- \definefontsynonym [Times-BoldItalic] [\typescriptthree-qtmbi] [encoding=\typescriptthree]
- \definefontsynonym [Times-Caps] [\typescriptthree-qtmr-sc] [encoding=\typescriptthree]
-
- \definefontsynonym [Times-Slanted] [Times-Italic]
- \definefontsynonym [Times-BoldSlanted] [Times-BoldItalic]
-
- \loadmapfile[qtm-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-times.map]
-\stoptypescript
-
-% TeXGyreHeros
-%
-% qtmr TeXGyreHeros-Regular
-% qtmri TeXGyreHeros-Italic
-% qtmb TeXGyreHeros-Bold
-% qtmbi TeXGyreHeros-BoldItalic
-
-\starttypescript [sans] [heros,helvetica] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Helvetica] [\typescriptthree-qhvr] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Oblique] [\typescriptthree-qhvri] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Bold] [\typescriptthree-qhvb] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-BoldOblique] [\typescriptthree-qhvbi] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Caps] [\typescriptthree-qhvr-sc] [encoding=\typescriptthree]
-
- \loadmapfile[qhv-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-helvetica.map]
-\stoptypescript
-
-% TeXGyreCursor
-%
-% qcrr TeXGyreCursor-Regular
-% qcrri TeXGyreCursor-Italic
-% qcrb TeXGyreCursor-Bold
-% qcrbi TeXGyreCursor-BoldItalic
-
-\starttypescript [mono] [cursor,courier] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Courier] [\typescriptthree-qcrr] [encoding=\typescriptthree]
- \definefontsynonym [Courier-Bold] [\typescriptthree-qcrri] [encoding=\typescriptthree]
- \definefontsynonym [Courier-Oblique] [\typescriptthree-qcrb] [encoding=\typescriptthree]
- \definefontsynonym [Courier-BoldOblique] [\typescriptthree-qcrbi] [encoding=\typescriptthree]
- \fakecontrolspace
-
- \loadmapfile[qcr-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-courier.map]
-\stoptypescript
-
-% TeXGyreBonum
-%
-% qtmr TeXGyreBonum-Regular
-% qtmri TeXGyreBonum-Italic
-% qtmb TeXGyreBonum-Bold
-% qtmbi TeXGyreBonum-BoldItalic
-
-\starttypescript [serif] [bookman] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Bookman-Light] [\typescriptthree-qbkr] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-LightItalic] [\typescriptthree-qbkri] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-DemiBold] [\typescriptthree-qbkb] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-DemiBoldItalic] [\typescriptthree-qbkbi] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-Light-Caps] [\typescriptthree-qbkr-sc] [encoding=\typescriptthree]
-
- \definefontsynonym [Bookman-LightSlanted] [Bookman-LightItalic]
- \definefontsynonym [Bookman-DemiBoldSlanted] [Bookman-DemiBoldItalic]
-
- \loadmapfile[qbk-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-bookman.map]
-\stoptypescript
-
-% TeXGyreScola
-%
-% qcsr TeXGyreSchola-Regular
-% qcsri TeXGyreSchola-Italic
-% qcsb TeXGyreSchola-Bold
-% qcsbi TeXGyreSchola-BoldItalic
-
-\starttypescript [serif] [schoolbook] [ec,texnansi,cs,el,qx,rm,t5,t2a,t2b,t2c,l7x]
- \definefontsynonym [Schoolbook-Roman] [\typescriptthree-qcsr] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Italic] [\typescriptthree-qcsri] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Bold] [\typescriptthree-qcsb] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-BoldItalic] [\typescriptthree-qcsbi] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Roman-Caps] [\typescriptthree-qcsr-sc] [encoding=\typescriptthree]
-
- \definefontsynonym [Schoolbook-Slanted] [Schoolbook-Italic]
- \definefontsynonym [Schoolbook-BoldSlanted] [Schoolbook-BoldItalic]
-
- \loadmapfile[qcs-\typescriptthree.map]
- \unloadmapfile[\typescriptthree-urw-ncntrsbk.map]
-\stoptypescript
-
-% TeXGyreAdventor
-%
-% qagr TeXGyreAdventor-Regular
-% qagri TeXGyreAdventor-Italic
-% qagb TeXGyreAdventor-Bold
-% qagbi TeXGyreAdventor-BoldItalic
-
-% not previously defined
-
-\stoptypescriptcollection
diff --git a/tex/context/base/type-ini.tex b/tex/context/base/type-ini.mkii
index 17b1c2088..fa7b7934f 100644
--- a/tex/context/base/type-ini.tex
+++ b/tex/context/base/type-ini.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Typescript Macros (ini)}
+\writestatus{loading}{ConTeXt Typescript Macros / Initialization}
%D The default fontclass is empty. We could demand always using fontclasses,
%D and then make the calling macros simplier (always assume fontclass) but
@@ -76,35 +76,17 @@
{\splitfiletype{#1}%
\addtocommalist\splitoffname\typescriptfiles}}
-% \usetypescriptfile[\f!typeprefix exa] % some examples
-% \usetypescriptfile[\f!typeprefix syn] % font file synonyms
-% \usetypescriptfile[\f!typeprefix enc] % files and encodings
-% %usetypescriptfile[\f!typeprefix dis] % funny name remappings, obsolete
-% \usetypescriptfile[\f!typeprefix siz] % specific font sizes
-% \usetypescriptfile[\f!typeprefix map] % pdftex mapping
-% \usetypescriptfile[\f!typeprefix spe] % special macros
-% \usetypescriptfile[\f!typeprefix akb] % adobe karl berry names
-%
-% \beginXETEX \font
-% \usetypescriptfile[\f!typeprefix xtx] % xetex definitions
-% \endXETEX
-
\usetypescriptfile[\f!typeprefix tmf]
\usetypescriptfile[\f!typeprefix siz]
-\beginOLDTEX \font
+\ifnum\texengine=\xetexengine
+ \usetypescriptfile[\f!typeprefix otf]
+ \usetypescriptfile[\f!typeprefix xtx]
+\else
\usetypescriptfile[\f!typeprefix one]
%usetypescriptfile[\f!typeprefix gyr] % to be merged into one
\usetypescriptfile[\f!typeprefix akb] % will go away when gyre is merged
-\endOLDTEX
-
-\beginNEWTEX \font
- \usetypescriptfile[\f!typeprefix otf]
-\endNEWTEX
-
-\beginXETEX \font
- \usetypescriptfile[\f!typeprefix xtx]
-\endXETEX
+\fi
\usetypescriptfile[\f!typeprefix loc]
@@ -184,11 +166,9 @@
\@EAEAEA\newtoks\loadedtypescripts
\bgroup
\long\def\starttypescript##1\stoptypescript
- {\global\loadedtypescripts\@EA{\the\loadedtypescripts
- \starttypescript##1\stoptypescript}}%
+ {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescript##1\stoptypescript}}%
\long\def\starttypescriptcollection##1\stoptypescriptcollection
- {\global\loadedtypescripts\@EA{\the\loadedtypescripts
- \starttypescriptcollection##1\stoptypescriptcollection}}%
+ {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescriptcollection##1\stoptypescriptcollection}}%
\startreadingfile
\pushendofline
\unprotect
@@ -217,6 +197,75 @@
\setfalse\quittingtypescript
\fi}
+% % not faster, unless maybe toks
+%
+% \newcount\nofloadedtypescripts
+%
+% \def\startloadedtypescript
+% {\dotripleempty\dostartloadedtypescript}
+%
+% \let\stoploadedtypescript\relax
+%
+% \long\def\dostartloadedtypescript[#1][#2][#3]#4\stoptypescript
+% {\global\advance\nofloadedtypescripts\plusone
+% \long\setgvalue{\??ts=>\the\nofloadedtypescripts}{#4}%
+% \edef\temp%
+% {\iffirstargument [#1]\fi
+% \ifsecondargument[#2]\fi
+% \ifthirdargument [#3]\fi
+% \noexpand\csname\??ts=>\the\nofloadedtypescripts\noexpand\endcsname}%
+% \global\loadedtypescripts\@EA\@EA\@EA{\@EA\the\@EA\loadedtypescripts\@EA\starttypescript\temp\stoptypescript}}
+%
+% \def\startloadedtypescriptcollection
+% {\dosingleempty\dostartloadedtypescriptcollection}
+%
+% \def\dostartloadedtypescriptcollection[#1]{}
+% \def\stoploadedtypescriptcollection {}
+%
+% \def\dododousetypescript#1%
+% {\setfalse\quittingtypescript
+% \pushmacro\currenttypefile
+% \def\currenttypefile{#1}%
+% \ifconditional\preloadingtypescripts
+% % load files once, and use saved data
+% \def\loadedtypescripts{\csname\??ts:\c!file:#1\endcsname}%
+% \@EAEAEA\ifx\loadedtypescripts\relax
+% \@EAEAEA\newtoks\loadedtypescripts
+% \bgroup
+% %
+% \let\starttypescript \startloadedtypescript
+% \let\stoptypescript \stoploadedtypescript
+% \let\starttypescriptcollection\startloadedtypescriptcollection
+% \let\stoptypescriptcollection \stoploadedtypescriptcollection
+% %
+% \startreadingfile
+% \pushendofline
+% \unprotect
+% \readfile\currenttypefile\donothing\donothing
+% \protect
+% \popendofline
+% \stopreadingfile
+% \egroup
+% \fi
+% %\message{[\space\currenttypefile}%
+% \the\loadedtypescripts
+% %\message{\ifconditional\quittingtypescript quit\space\fi]}%
+% \else
+% % process files each time
+% \startreadingfile
+% \pushendofline
+% \unprotect
+% \readfile\currenttypefile\donothing\donothing
+% \protect
+% \popendofline
+% \stopreadingfile
+% \fi
+% \popmacro\currenttypefile
+% \ifconditional\quittingtypescript
+% \quitcommalist
+% \setfalse\quittingtypescript
+% \fi}
+
\def\usetypescriptonce
{\dotripleempty\dousetypescriptonce}
@@ -278,7 +327,7 @@
\let\typescripttwo \@@typescripttwo
\let\typescriptthree\@@typescriptthree
\let\typescriptmatch\empty
- \doifnextcharelse[\dostarttypescriptone\dostarttypescriptall}
+ \doifnextoptionalelse\dostarttypescriptone\dostarttypescriptall}
\long\def\dostarttypescriptall
{\iffirsttypescriptpass
@@ -309,10 +358,10 @@
{\dochecktypescript\@@typescriptthree\typescriptthree\redostarttypescriptthree}
\long\def\redostarttypescriptone
- {\doifnextcharelse[\dostarttypescripttwo\dostarttypescriptyes}
+ {\doifnextoptionalelse\dostarttypescripttwo\dostarttypescriptyes}
\long\def\redostarttypescripttwo
- {\doifnextcharelse[\dostarttypescriptthree\dostarttypescriptyes}
+ {\doifnextoptionalelse\dostarttypescriptthree\dostarttypescriptyes}
\long\def\redostarttypescriptthree
{\dostarttypescriptyes}
@@ -411,10 +460,6 @@
\def\doregisterloadedmapfile#1%
{\immediatewriteutilitycommand{\usedmapfile{=}{#1}}}
-\beginLUATEX
- \let\doregisterloadedmapfile\gobbleoneargument
-\endLUATEX
-
\def\doloadfontmapfile#1%
{\ifundefined{#1\c!state}%
\writestatus\m!fonts{using map file: #1}%
@@ -512,7 +557,7 @@
{\dodoubleargument\dodefinetypescriptprefix}
\def\dodefinetypescriptprefix[#1][#2]%
- {\setvalue{\??ts::#1}{#2}}
+ {\setgvalue{\??ts::#1}{#2}} % made global
% without testing:
%
@@ -577,40 +622,15 @@
\getparameters[\??tf#1#2][#3]%
\fi\fi\fi}
-% eventually we will split this module (no time now)
-
-% hm, math needs encoding
-
-% \beginLUATEX
-% \def\dodefinetypeface[#1][#2][#3][#4][#5][#6]%
-% {\dododefinetypeface[#1][#2]%
-% \iffifthargument % sixth is optional
-% % we need to expand since in #6 there can be a \typescripttwo
-% \expanded{\getparameters[\??ts][\s!rscale=\plusone,\s!features=,\s!fallbacks=,\s!text=,#6]}% \geteparameters
-% \pushmacro\relativefontsize
-% \pushmacro\fontclass
-% \let\relativefontsize\@@tsrscale
-% \setcurrentfontclass{#1}%
-% \letvalue{\fontclass\s!features }\@@tsfeatures % new per 16/6/2007
-% \letvalue{\fontclass\s!fallbacks}\@@tsfallbacks % new per 12/10/2008
-% \saverelativefontsize{#2}\relativefontsize % fall back
-% \savemathtextstyle\@@tstext % math text style (new per 28/4/2006)
-% \iftracetypescripts\writestatus\m!fonts{define: [#1] [#2] [#3] [#4]}\fi
-% \usetypescript[#3][#4][\t!name,\t!default,\t!special]%
-% \usetypescript[#3][#5][\t!size]%
-% \popmacro\fontclass
-% \popmacro\relativefontsize
-% \else\iffourthargument
-% \definetypeface[#1][#2][#3][#4][\s!default]%
-% \else\ifthirdargument
-% \getparameters[\??tf#1#2][#3]%
-% \fi\fi\fi}
-% \endLUATEX
-
\def\dododefinetypeface[#1][#2]% saveguard against redefinition
{\doifsomething{#1}
- {\doifundefined{\??tf#1\s!default}{\setgvalue{\??tf#1\s!default}{#2}}%
- \doifundefined{#1}{\unexpanded\setgvalue{#1}{\switchtotypeface[#1][#2]}}}}
+ {\ifcsname\??tf#1\s!default\endcsname \else
+ \registerfontclass{#1}%
+ \setgvalue{\??tf#1\s!default}{#2}%
+ \fi
+ \ifcsname#1\endcsname \else
+ \unexpanded\setgvalue{#1}{\switchtotypeface[#1][#2]}%
+ \fi}}
\def\setuptypeface% [class] [settings]
{\doquadrupleempty\doswitchtotypeface[\setupbodyfont][\fontclass]}
@@ -697,7 +717,13 @@
% new and obeying fontclasses (but still obsolete)
\def\doreadfontdefinitionfile#1#2% #1 = set/switch state
- {\ifundefined{\??tf#2\c!default}%
+ {\ifcsname\??tf#2\c!default\endcsname
+ \ifcase#1\relax
+ \switchtotypeface[#2]%
+ \else
+ \setuptypeface[#2]%
+ \fi
+ \else
\pushmacro\starttypescript
\scratchtoks\emptytoks
% locate downward compatibility definitions, one argument !
@@ -708,11 +734,7 @@
\stopreadingfile
\popmacro\starttypescript
\the\scratchtoks
- \else\ifcase#1\relax
- \switchtotypeface[#2]%
- \else
- \setuptypeface[#2]%
- \fi\fi}
+ \fi}
\fetchruntimecommand \typetypescript {\f!typeprefix\s!run}
diff --git a/tex/context/base/type-ini.mkiv b/tex/context/base/type-ini.mkiv
new file mode 100644
index 000000000..42c45bdaa
--- /dev/null
+++ b/tex/context/base/type-ini.mkiv
@@ -0,0 +1,705 @@
+%D \module
+%D [ file=type-ini,
+%D version=2001.03.05,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Initialization,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\writestatus{loading}{ConTeXt Typescript Macros / Initialization}
+
+%D The default fontclass is empty. We could demand always using fontclasses,
+%D and then make the calling macros simplier (always assume fontclass) but
+%D apart from downward compatibility issues, it would make global, class
+%D spanning definitions a pain. Some day we will introduce a default class.
+
+% torture test : proper typefaces (and namespace)
+%
+% \starttext
+% \usetypescript[modern][default] default: \setupbodyfont[modern] \eacute \eogonek \zcaron \acircumflexgrave
+% \usetypescript[modern][texnansi] texnansi: \setupbodyfont[modern] \eacute \eogonek \zcaron \acircumflexgrave
+% \usetypescript[modern][ec] ec: \setupbodyfont[modern] \eacute \eogonek \zcaron \acircumflexgrave
+% \usetypescript[modern][qx] qx: \setupbodyfont[modern] \eacute \eogonek \zcaron \acircumflexgrave
+% \usetypescript[modern][t5] t5: \setupbodyfont[modern] \eacute \eogonek \zcaron \acircumflexgrave
+% \stoptext
+%
+% torture test : no typeface, just definitions
+%
+% \starttext
+% {\setupbodyfont[reset] \setupbodyfont[cmr] cmr: \eacute \eogonek \zcaron \acircumflexgrave \endgraf}
+% {\setupbodyfont[reset] \setupbodyfont[plr] plr: \eacute \eogonek \zcaron \acircumflexgrave \endgraf}
+% {\setupbodyfont[reset] \setupbodyfont[csr] csr: \eacute \eogonek \zcaron \acircumflexgrave \endgraf}
+% {\setupbodyfont[reset] \setupbodyfont[vnr] vnr: \eacute \eogonek \zcaron \acircumflexgrave \endgraf}
+% {\setupbodyfont[reset] \setupbodyfont[aer] aer: \eacute \eogonek \zcaron \acircumflexgrave \endgraf}
+% \stoptext
+
+% \usetypescript [modern] [texnansi]
+%
+% normal : 1450 ms
+% exa quit : 1300 ms (150 ms)
+% preload : 825 ms (635 ms) (40-50%)
+%
+% \usetypescript [modern] [texnansi]
+% \usetypescript [palatino][texnansi]
+% \usetypescript [times] [texnansi]
+%
+% normal : 3200 ms
+% exa quit : 2700 ms ( 500 ms)
+% preload : 1300 ms (1900 ms) (60-70%)
+
+% \usetypescript [modern][\defaultencoding]
+% \usetypescript [map] [latin-modern-os] [\defaultencoding]
+% \setupbodyfont[modern]
+% test 1234 test
+
+\unprotect
+
+\def\starttypescriptcollection
+ {\dosingleempty\dostarttypescriptcollection}
+
+\def\dostarttypescriptcollection[#1]%
+ {}
+
+\def\stoptypescriptcollection
+ {}
+
+\let\typescriptfiles\empty
+
+\unexpanded\def\usetypescriptfile[#1]%
+ {\doifelse{#1}\v!reset
+ {\let\typescriptfiles\empty}
+ {\splitfiletype{#1}%
+ \addtocommalist\splitoffname\typescriptfiles}}
+
+% \usetypescriptfile[\f!typeprefix exa] % some examples
+% \usetypescriptfile[\f!typeprefix syn] % font file synonyms
+% \usetypescriptfile[\f!typeprefix enc] % files and encodings
+% %usetypescriptfile[\f!typeprefix dis] % funny name remappings, obsolete
+% \usetypescriptfile[\f!typeprefix siz] % specific font sizes
+% \usetypescriptfile[\f!typeprefix map] % pdftex mapping
+% \usetypescriptfile[\f!typeprefix spe] % special macros
+% \usetypescriptfile[\f!typeprefix akb] % adobe karl berry names
+
+\usetypescriptfile[\f!typeprefix tmf]
+\usetypescriptfile[\f!typeprefix siz]
+\usetypescriptfile[\f!typeprefix otf]
+\usetypescriptfile[\f!typeprefix loc]
+
+% SO FAR
+
+\let\currenttypescripts\empty
+
+\newif\iftypescriptfound
+
+\let\@@typescriptone \empty \let\typescriptone \empty
+\let\@@typescripttwo \empty \let\typescripttwo \empty
+\let\@@typescriptthree\empty \let\typescriptthree\empty
+
+% method 2 is for Hans van der Meer
+
+\newtoks\documenttypescripts
+
+\chardef\typescriptmethod\plusone % 1: empty==all==true 2: empty==false
+\chardef\typescriptstate \plustwo % 1: process 2: store
+
+\unexpanded\def\usetypescript {\let\typescriptmethod\plusone\dotripleempty\dousetypescript}
+\unexpanded\def\usetypescriptexact{\let\typescriptmethod\plustwo\dotripleempty\dousetypescript}
+
+\def\dousetypescript[#1][#2][#3]%
+ {\normalexpanded{\noexpand\dodousetypescript[#1][#2][#3]}}
+
+\def\dodousetypescript[#1][#2][#3]% also loads type-loc, a user file
+ {\pushmacro\@@typescriptone \edef\@@typescriptone {\truetypescript{#1}}%
+ \pushmacro\@@typescripttwo \edef\@@typescripttwo {\truetypescript{#2}}%
+ \pushmacro\@@typescriptthree\edef\@@typescriptthree{\truetypescript{#3}}%
+ \pushmacro\typescriptone
+ \pushmacro\typescripttwo
+ \pushmacro\typescriptthree
+ \pushmacro\typescriptmethod
+ \pushmacro\typescriptstate \let\typescriptstate\plusone % process
+ \pushmacro\stoptypescript
+ \typescriptfoundfalse
+ \iftracetypescripts\writestatus\m!fonts{request: [\@@typescriptone] [\@@typescripttwo] [\@@typescriptthree]}\fi
+ \processcommacommand[\typescriptfiles]\dododousetypescript
+ \the\documenttypescripts
+ \firsttypescriptpassfalse % testen
+ \popmacro\stoptypescript
+ \popmacro\typescriptstate
+ \popmacro\typescriptmethod
+ \popmacro\typescriptthree
+ \popmacro\typescripttwo
+ \popmacro\typescriptone
+ \popmacro\@@typescriptthree
+ \popmacro\@@typescripttwo
+ \popmacro\@@typescriptone}
+
+% simple version:
+%
+% \def\dododousetypescript#1%
+% {\startreadingfile
+% \pushmacro\currenttypefile
+% \def\currenttypefile{#1}%
+% \def\currenttypefile{#1}%
+% \readfile\currenttypefile\donothing\donothing
+% \popmacro\currenttypefile
+% \stopreadingfile}
+%
+% tricky version:
+
+\newconditional\preloadingtypescripts
+
+\def\preloadtypescripts{\ifproductionrun\settrue\preloadingtypescripts\fi}
+
+\long\def\xxstarttypescript#1\stoptypescript
+ {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescript#1\stoptypescript}}
+
+\long\def\xxstarttypescriptcollection#1\stoptypescriptcollection
+ {\global\loadedtypescripts\@EA{\the\loadedtypescripts\starttypescriptcollection#1\stoptypescriptcollection}}
+
+\def\dododousetypescript#1%
+ {\setfalse\quittingtypescript
+ \pushmacro\currenttypefile
+ \def\currenttypefile{#1}%
+ \ifconditional\preloadingtypescripts
+ % load files once, and use saved data
+ \def\loadedtypescripts{\csname\??ts:\c!file:#1\endcsname}%
+ \@EAEAEA\ifx\loadedtypescripts\relax
+ \@EAEAEA\newtoks\loadedtypescripts
+ \bgroup
+ \let\starttypescript\xxstarttypescript
+ \let\starttypescriptcollection\xxstarttypescriptcollection
+ \startreadingfile
+ \pushendofline
+ \unprotect
+ \readfile\currenttypefile\donothing\donothing
+ \protect
+ \popendofline
+ \stopreadingfile
+ \egroup
+ \fi
+ %\message{[\space\currenttypefile}%
+ \the\loadedtypescripts
+ %\message{\ifconditional\quittingtypescript quit\space\fi]}%
+ \else
+ % process files each time
+ \startreadingfile
+ \pushendofline
+ \unprotect
+ \readfile\currenttypefile\donothing\donothing
+ \protect
+ \popendofline
+ \stopreadingfile
+ \fi
+ \popmacro\currenttypefile
+ \ifconditional\quittingtypescript
+ \quitcommalist
+ \setfalse\quittingtypescript
+ \fi}
+
+% % not faster, unless maybe toks
+%
+% \newcount\nofloadedtypescripts
+%
+% \def\startloadedtypescript
+% {\dotripleempty\dostartloadedtypescript}
+%
+% \let\stoploadedtypescript\relax
+%
+% \long\def\dostartloadedtypescript[#1][#2][#3]#4\stoptypescript
+% {\global\advance\nofloadedtypescripts\plusone
+% \long\setgvalue{\??ts=>\the\nofloadedtypescripts}{#4}%
+% \edef\temp%
+% {\iffirstargument [#1]\fi
+% \ifsecondargument[#2]\fi
+% \ifthirdargument [#3]\fi
+% \noexpand\csname\??ts=>\the\nofloadedtypescripts\noexpand\endcsname}%
+% \global\loadedtypescripts\@EA\@EA\@EA{\@EA\the\@EA\loadedtypescripts\@EA\starttypescript\temp\stoptypescript}}
+%
+% \def\startloadedtypescriptcollection
+% {\dosingleempty\dostartloadedtypescriptcollection}
+%
+% \def\dostartloadedtypescriptcollection[#1]{}
+% \def\stoploadedtypescriptcollection {}
+%
+% \def\dododousetypescript#1%
+% {\setfalse\quittingtypescript
+% \pushmacro\currenttypefile
+% \def\currenttypefile{#1}%
+% \ifconditional\preloadingtypescripts
+% % load files once, and use saved data
+% \def\loadedtypescripts{\csname\??ts:\c!file:#1\endcsname}%
+% \@EAEAEA\ifx\loadedtypescripts\relax
+% \@EAEAEA\newtoks\loadedtypescripts
+% \bgroup
+% %
+% \let\starttypescript \startloadedtypescript
+% \let\stoptypescript \stoploadedtypescript
+% \let\starttypescriptcollection\startloadedtypescriptcollection
+% \let\stoptypescriptcollection \stoploadedtypescriptcollection
+% %
+% \startreadingfile
+% \pushendofline
+% \unprotect
+% \readfile\currenttypefile\donothing\donothing
+% \protect
+% \popendofline
+% \stopreadingfile
+% \egroup
+% \fi
+% %\message{[\space\currenttypefile}%
+% \the\loadedtypescripts
+% %\message{\ifconditional\quittingtypescript quit\space\fi]}%
+% \else
+% % process files each time
+% \startreadingfile
+% \pushendofline
+% \unprotect
+% \readfile\currenttypefile\donothing\donothing
+% \protect
+% \popendofline
+% \stopreadingfile
+% \fi
+% \popmacro\currenttypefile
+% \ifconditional\quittingtypescript
+% \quitcommalist
+% \setfalse\quittingtypescript
+% \fi}
+
+\def\usetypescriptonce
+ {\dotripleempty\dousetypescriptonce}
+
+\def\dousetypescriptonce[#1][#2][#3]%
+ {\doifelseflagged{ts:#1:#2:#3}%
+ {\writestatus\m!fonts{once (#1) (#2) (#3)}}
+ {\setflag{ts:#1:#2:#3}%
+ \normalexpanded{\noexpand\dodousetypescript[#1][#2][#3]}}}
+
+% \definetypescriptsynonym[lbr][cmr]
+
+\def\definetypescriptsynonym
+ {\dodoubleempty\dodefinetypescriptsynonym}
+
+\def\dodefinetypescriptsynonym[#1][#2]%
+ {\ifsecondargument\setevalue{\??tm#1}{#2}\fi}
+
+\def\truetypescript#1%
+ {\ifcsname\??tm#1\endcsname
+ \@EA\truetypescript\csname\??tm#1\endcsname\else#1%
+ \fi}
+
+% script [serif] [default] [size]
+% script [serif] [computer-modern] [size]
+% script [serif] [computer-modern] [ec]
+% script [serif] [computer-modern] [name]
+% script [serif] [computer-modern] [special]
+
+% todo, make firsttypescriptpass conditional
+
+\newif\iffirsttypescriptpass \firsttypescriptpasstrue
+
+\prependtoks\firsttypescriptpasstrue\to\everyjob
+
+\def\typescript@@all{all}
+
+\newif\iftracetypescripts
+
+\def\starttypescript
+ {\ifcase\typescriptstate
+ % 0 = skip
+ \@EA\gobbleuntil\@EA\stoptypescript
+ \or
+ % 1 = process
+ \expandafter\dostarttypescript
+ \or
+ % 2 = store
+ \expandafter\nostarttypescript
+ \else
+ % ? = skip
+ \@EA\gobbleuntil\@EA\stoptypescript
+ \fi}
+
+\long\def\nostarttypescript#1\stoptypescript
+ {\appendtoks\starttypescript#1\stoptypescript\to\documenttypescripts}
+
+\def\dostarttypescript
+ {\let\typescriptone \@@typescriptone
+ \let\typescripttwo \@@typescripttwo
+ \let\typescriptthree\@@typescriptthree
+ \let\typescriptmatch\empty
+ \doifnextoptionalelse\dostarttypescriptone\dostarttypescriptall}
+
+\long\def\dostarttypescriptall
+ {\iffirsttypescriptpass
+ \expandafter\doprocesstypescript
+ \else
+ % skip this since it may do unwanted resets, like
+ % setting symbolic font names to unknown, especially
+ % in run time user type scripts
+ \expandafter\noprocesstypescript
+ \fi}
+
+\long\def\dostarttypescriptyes
+ {\ifdone
+ \typescriptfoundtrue
+ \iftracetypescripts\writestatus\m!fonts{match:\ifx\currenttypefile\relax\space *\fi \typescriptmatch}\fi
+ \expandafter\doprocesstypescript
+ \else
+ \expandafter\noprocesstypescript
+ \fi}
+
+\long\def\dostarttypescriptone
+ {\dochecktypescript\@@typescriptone\typescriptone\redostarttypescriptone}
+
+\long\def\dostarttypescripttwo
+ {\dochecktypescript\@@typescripttwo\typescripttwo\redostarttypescripttwo}
+
+\long\def\dostarttypescriptthree
+ {\dochecktypescript\@@typescriptthree\typescriptthree\redostarttypescriptthree}
+
+\long\def\redostarttypescriptone
+ {\doifnextoptionalelse\dostarttypescripttwo\dostarttypescriptyes}
+
+\long\def\redostarttypescripttwo
+ {\doifnextoptionalelse\dostarttypescriptthree\dostarttypescriptyes}
+
+\long\def\redostarttypescriptthree
+ {\dostarttypescriptyes}
+
+\def\doprocesstypescript
+ {\pushmacro\fontclass}
+
+\def\stoptypescript
+ {\popmacro\fontclass}
+
+\long\def\noprocesstypescript#1\stoptypescript
+ {}
+
+\let\typescriptmatch\empty
+
+\def\dochecktypescript#1#2#3[#4]% script use value next
+ {\donefalse
+ \def\@@typescriptcheck{#4}%
+ \ifx\@@typescriptcheck\empty % no longer needed / met
+ \ifcase\typescriptmethod\or\donetrue\fi
+ \else\ifx#1\typescript@@all
+ \donetrue
+ \else\ifx\@@typescriptcheck\typescript@@all
+ \donetrue
+ \else\ifx#1\@@typescriptcheck % saves 10% trace so probably faster too
+ \donetrue
+ \let#2\@@typescriptcheck
+ \else
+ \normalexpanded{\noexpand\doifcommonelse{\@@typescriptcheck}{#1}}\donetrue\donefalse
+ \ifdone
+ \let#2\commalistelement
+ \fi
+ \fi\fi\fi\fi
+ \ifdone
+ \edef\typescriptmatch{\typescriptmatch\space[#4]}%
+ \expandafter#3%
+ \else
+ \expandafter\noprocesstypescript
+ \fi}
+
+%D Yet another speed up: when issued inside typescript, the call
+%D
+%D \starttyping
+%D \quittypescriptscanning
+%D \stoptyping
+%D
+%D quits further loading. For an example, see type-exa:
+
+\newconditional\quittingtypescript \setfalse\quittingtypescript
+
+\def\quittypescriptscanning{\settrue\quittingtypescript}
+
+% status
+%
+% 1 loaded
+% 2 reported
+% 3 preloaded
+
+% flags ipv \c!state, more flag values
+
+\def\dopreloadmapfile#1%
+ {\splitfiletype{#1}%
+ \writestatus\m!fonts{assuming map file: \splitoffname}%
+ \setxvalue{\splitoffname \c!state}{3}%
+ \doglobal\removefromcommalist\splitoffname\allfontmapsfiles}
+
+\def\preloadmapfile[#1]{\processcommacommand[#1]\dopreloadmapfile}
+\def\loadmapfile [#1]{\processcommacommand[#1]\loadthemapfile}
+\def\unloadmapfile [#1]{\processcommacommand[#1]\unloadthemapfile}
+
+% too soon, no driver known, \ifproductionrun \loadallfontmapfiles \fi
+
+\def\loadthemapfile#1%
+ {\splitfiletype{#1}%
+ \doglobal\addtocommalist\splitoffname\allfontmapsfiles}
+
+\def\unloadthemapfile#1%
+ {\splitfiletype{#1}%
+ \doglobal\removefromcommalist\splitoffname\allfontmapsfiles}
+
+\let\usedmapfile \gobbletwoarguments
+\let\usedmapline \gobbletwoarguments
+\let\doregisterloadedmapfile\gobbleoneargument
+
+\def\doloadfontmapfile#1%
+ {\ifcsname#1\c!state\endcsname\else
+ \writestatus\m!fonts{using map file: #1}%
+ \doregisterloadedmapfile{#1}%
+ \doloadmapfile{=}{#1.\f!fontmapextension}% +/add =/replace -/remove
+ \setxvalue{#1\c!state}{1}%
+ \fi}
+
+\def\doreportfontmapfile#1%
+ {\ifcsname#1\c!state\endcsname\else
+ \writestatus\m!fonts{needs map file: #1}%
+ \setxvalue{#1\c!state}{2}%
+ \fi}
+
+\def\loadallfontmapfiles
+ {%\message{[\allfontmapsfiles]}%
+ \ifconditional\resettingmapfile
+ \writestatus\m!fonts{resetting map file list}%
+ \doresetmapfilelist
+ \global\setfalse\resettingmapfile
+ \fi
+ \ifx\allfontmapsfiles\empty \else
+ \ifautoloadmapfiles
+ \processcommacommand[\allfontmapsfiles]\doloadfontmapfile
+ \else
+ \processcommacommand[\allfontmapsfiles]\doreportfontmapfile
+ \fi
+ \forgetmapfiles
+ \fi}
+
+\def\loadmapline
+ {\dodoubleempty\dodoloadmapline}
+
+\def\dodoloadmapline[#1][#2]%
+ {\loadallfontmapfiles % ! ! !
+ \ifsecondargument
+ \immediatewriteutilitycommand{\usedmapline{#1}{#2}}%
+ \doloadmapline{#1}{#2}% special
+ \else
+ \loadmapline[=][#1]%
+ %\immediatewriteutilitycommand{\usedmapline{=}{#2}}%
+ %\doloadmapline{=}{#1}% special
+ \fi}
+
+% since this is driver dependent, and since we may set map files
+% before an output format is defined, we need to postpone it; we
+% cannot use starttext as hook because an output switch can be part
+% of a style; an alternative is to no longer permit driver switching
+% after the first \starttext, but that will break compatibility
+% because \startcomponent ... \environment ... is pretty legal.
+
+% the map directives need to end up in the right place in the stream
+
+% hm, the timing of when pdftex needs the map file info keeps changing;
+% it's really time to move to map line support
+
+% \appendtoks \loadallfontmapfiles \to \everyPDFximage
+% \appendtoks \loadallfontmapfiles \to \everystarttext
+% \appendtoks \loadallfontmapfiles \to \everybeforepagebody
+
+\everybeforeshipout \expandafter
+ {\expandafter\appendtoks
+ \expandafter\loadallfontmapfiles
+ \expandafter\to
+ \expandafter\pageboundsettings
+ \the\everybeforeshipout}
+
+\newif\ifautoloadmapfiles
+
+\let\allfontmapsfiles\empty
+
+\def\forgetmapfiles
+ {\globallet\allfontmapsfiles\empty}
+
+\newconditional\resettingmapfile
+
+\def\resetmapfiles
+ {\global\settrue\resettingmapfile}
+
+\def\disablemapfiles
+ {\resetmapfiles
+ \forgetmapfiles}
+
+%D A handy shortcut:
+
+% \definetypescriptprefix[serif][Serif]
+% \definetypescriptprefix[sans] [Sans]
+% \definetypescriptprefix[mono] [Mono]
+%
+%\starttypescript [serif,sans,mono] [handling,hanging,hz] [pure,normal,hz,quality]
+% \setupfontsynonym [\typescriptprefix\typescriptone] [handling=\typescriptthree]
+% \stoptypescript
+
+\def\definetypescriptprefix
+ {\dodoubleargument\dodefinetypescriptprefix}
+
+\def\dodefinetypescriptprefix[#1][#2]%
+ {\setgvalue{\??ts::#1}{#2}} % made global
+
+% without testing:
+%
+% \def\typescriptprefix#1%
+% {\csname\??ts::#1\endcsname}
+%
+% with testing:
+
+\def\typescriptprefix#1%
+ {\executeifdefined{\??ts::#1}{#1}}
+
+% defining typefaces:
+%
+% \definetypeface [#1:joke] [#2:rm]
+% \definetypeface [#1:joke] [#2:rm] [#3:...]
+% \definetypeface [#1:joke] [#2:rm] [#3:serif] [#4:lucida] [#5:size] [#6:...]
+
+\def\definetypeface
+ {\dosixtupleargument\dodefinetypeface}
+
+\def\tsvar#1#2% \executeifdefined{\??ts#1}{#2}
+ {\@EA\ifx\csname\??ts#1\endcsname\empty
+ #2%
+ \else
+ \csname\??ts#1\endcsname
+ \fi}
+
+% #1=main #2=rm #3=serif #4=fontname #5=size #6=settings
+
+\def\typefaceencoding{\defaultencoding}
+
+% we can use \rawgetparameters or \rawgeteparameters
+
+\ifx\mkdodefinetypeface\undefined
+ \let\mkdodefinetypeface\gobblefivearguments
+\fi
+
+\def\dodefinetypeface[#1][#2][#3][#4][#5][#6]%
+ {\dododefinetypeface[#1][#2]%
+ \iffifthargument % sixth is optional
+ % we need to expand since in #6 there can be a \typescripttwo
+ \normalexpanded{\noexpand\getparameters[\??ts][\s!rscale=\plusone,\s!encoding=\defaultencoding,\s!features=,\s!fallbacks=,\s!text=,#6]}% \geteparameters
+ \pushmacro\relativefontsize
+ \pushmacro\typefaceencoding
+ \pushmacro\fontclass
+ \let\relativefontsize\@@tsrscale
+ \let\typefaceencoding\@@tsencoding
+ \setcurrentfontclass{#1}%
+ \letvalue{\fontclass\s!features }\@@tsfeatures % new per 16/6/2007
+ \letvalue{\fontclass\s!fallbacks}\@@tsfallbacks % new per 12/10/2008
+ \saverelativefontsize{#2}\relativefontsize % fall back
+ \savemathtextstyle\@@tstext % math text style (new per 28/4/2006)
+ \iftracetypescripts\writestatus\m!fonts{define: [#1] [#2] [#3] [#4] / \typefaceencoding}\fi
+% \usetypescript[#3,\t!map][#4][\t!name,\t!default,\typefaceencoding,\t!special]% map is needed for backward cmp
+ \usetypescript[#3][#4][\t!name,\t!default,\typefaceencoding]% typefaceencoding=empty forces [#3][#4]
+ \usetypescript[#3][#5][\t!size]%
+ \popmacro\fontclass
+ \popmacro\typefaceencoding
+ \popmacro\relativefontsize
+ \else\iffourthargument
+ \definetypeface[#1][#2][#3][#4][\s!default]%
+ \else\ifthirdargument
+ \getparameters[\??tf#1#2][#3]%
+ \fi\fi\fi}
+
+\def\dododefinetypeface[#1][#2]% saveguard against redefinition
+ {\doifsomething{#1}
+ {\ifcsname\??tf#1\s!default\endcsname \else
+ \registerfontclass{#1}%
+ \setgvalue{\??tf#1\s!default}{#2}%
+ \fi
+ \ifcsname#1\endcsname \else
+ \unexpanded\setgvalue{#1}{\switchtotypeface[#1][#2]}%
+ \fi}}
+
+\def\setuptypeface% [class] [settings]
+ {\doquadrupleempty\doswitchtotypeface[\setupbodyfont][\fontclass]}
+
+\unexpanded\def\switchtotypeface% [class] [settings]
+ {\doquadrupleempty\doswitchtotypeface[\switchtobodyfont][\globalfontclass]}
+
+\def\doswitchtotypeface[#1][#2][#3][#4]%
+ {%\doifinsetelse{\s!default,\v!reset}{#3}
+ % {\setcurrentfontclass\empty}
+ % {\setcurrentfontclass{#3}}%
+ \setcurrentfontclass{#3}%
+ \let\globalfontclass#2%
+ \iffourthargument
+ #1[#4]%
+ \else\ifx\fontclass\empty
+ #1[\c!rm]%
+ \else
+ \doifdefinedelse{\??tf\fontclass\s!default}
+ {#1[\getvalue{\??tf\fontclass\s!default}]}
+ {#1[\c!rm]}%
+ \fi \fi
+ \ifmmode\mr\else\tf\fi} % needed ?
+
+\def\usetypefile[#1]% recurses on path !
+ {\readfile{\f!typeprefix#1}\donothing\donothing}
+
+%D For Taco:
+%D
+%D \starttyping
+%D \inherittypeface[palatino][rm][postscript]
+%D \inherittypeface[palatino][rm][\fontclass]
+%D \inherittypeface[palatino][rm] % == \fontclass
+%D \inherittypeface[palatino] % == [rm,ss,tt,mm]
+%D \stoptyping
+
+\def\inherittypeface
+ {\dotripleempty\doinherittypeface}
+
+\def\doinherittypeface[#1][#2][#3]%
+ {\doifelsenothing{#2}
+ {\doinherittypeface[#1][\c!rm,\c!ss,\c!tt,\c!mm][\fontclass]}
+ {\doifnot{#1}{#3}
+ {\def\docommand##1{\setevalue{#1-##1}{#3}}%
+ \processcommalist[#2]\docommand}}}
+
+%D This hook sinto the font mechanism with:
+
+\def\checkfontclass#1%
+ {\edef\fontclass{\executeifdefined{\fontclass-#1}{\fontclass}}}
+
+%D For backward compatibility we reimplement the font file
+%D loading macro.
+
+\ifx\normaldoreadfontdefinitionfile\undefined
+ \let\normaldoreadfontdefinitionfile\doreadfontdefinitionfile
+\fi
+
+\def\doreadfontdefinitionfile#1#2% #1 = set/switch state
+ {\ifcsname\??tf#2\c!default\endcsname
+ \ifcase#1\relax
+ \switchtotypeface[#2]%
+ \else
+ \setuptypeface[#2]%
+ \fi
+ \else
+ \pushmacro\starttypescript
+ \scratchtoks\emptytoks
+ % locate downward compatibility definitions, one argument !
+ \long\def\starttypescript[##1]##2\stoptypescript
+ {\doif{##1}{#2}{\scratchtoks{##2}}}
+ \startreadingfile
+ \readfile{\f!typeprefix pre}\donothing\donothing
+ \stopreadingfile
+ \popmacro\starttypescript
+ \the\scratchtoks
+ \fi}
+
+\fetchruntimecommand \typetypescript {\f!typeprefix\s!run}
+
+\protect \endinput
diff --git a/tex/context/base/type-mac.mkii b/tex/context/base/type-mac.mkii
new file mode 100644
index 000000000..feedcd43d
--- /dev/null
+++ b/tex/context/base/type-mac.mkii
@@ -0,0 +1,220 @@
+%D \module
+%D [ file=type-mac,
+%D version=2009.03.10,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Mac OS X Definitions,
+%D author=Wolfgang Schuster,
+%D date=\currentdate,
+%D copyright=Wolfgang Schuster]
+%C
+%C This module is part of the \CONTEXT\ macro||package. See
+%C mreadme.pdf for details.
+
+\definetypescriptprefix [f:andalemono] [Andale Mono]
+\definetypescriptprefix [f:chalkboard] [Chalkboard]
+\definetypescriptprefix [f:cochin] [Cochin]
+\definetypescriptprefix [f:comicsans] [Comic Sans MS]
+\definetypescriptprefix [f:couriernew] [Courier New]
+\definetypescriptprefix [f:georgia] [Georgia]
+\definetypescriptprefix [f:lucidagrande] [Lucida Grande]
+\definetypescriptprefix [f:monaco] [Monaco]
+\definetypescriptprefix [f:tahoma] [Tahoma]
+\definetypescriptprefix [f:timesnewroman] [Times New Roman]
+\definetypescriptprefix [f:trebuchet] [Trebuchet MS]
+\definetypescriptprefix [f:verdana] [Verdana]
+
+% American Typewriter
+
+\starttypescript [serif] [americantypewriter-light-condensed,americantypewriter-condensed,americantypewriter-light,americantypewriter]
+ \definefontsynonym [AmericanTypewriter-Light] [name:American Typewriter Light] [features=default]
+ \definefontsynonym [AmericanTypewriter-Regular] [name:American Typewriter] [features=default]
+ \definefontsynonym [AmericanTypewriter-Bold] [name:American Typewriter Bold] [features=default]
+ \definefontsynonym [AmericanTypewriter-LightCond] [name:American Typewriter Condensed Light] [features=default]
+ \definefontsynonym [AmericanTypewriter-Condensed] [name:American Typewriter Condensed] [features=default]
+ \definefontsynonym [AmericanTypewriter-BoldCond] [name:American Typewriter Condensed Bold] [features=default]
+\stoptypescript
+
+% Arial / Arial Narrow / Arial Rounded / Arial Unicode
+
+\starttypescript [sans] [arial-narrow,arial-condensed,arial,arial-rounded,arial-unicode]
+ \definefontsynonym [Arial-Condensed] [name:Arial Narrow] [features=default]
+ \definefontsynonym [Arial-ItalicCond] [name:Arial Narrow Italic] [features=default]
+ \definefontsynonym [Arial-BoldCond] [name:Arial Narrow Bold] [features=default]
+ \definefontsynonym [Arial-BoldItalicCond] [name:Arial Narrow Bold Italic] [features=default]
+ \definefontsynonym [Arial-Regular] [name:Arial] [features=default]
+ \definefontsynonym [Arial-Italic] [name:Arial Italic] [features=default]
+ \definefontsynonym [Arial-Bold] [name:Arial Bold] [features=default]
+ \definefontsynonym [Arial-BoldItalic] [name:Arial Bold Italic] [features=default]
+ \definefontsynonym [Arial-Black] [name:Arial Black] [features=default]
+ \definefontsynonym [Arial-Unicode] [name:Arial Unicode MS] [features=default]
+ \definefontsynonym [Arial-Rounded] [name:Arial Rounded MT Bold] [features=default]
+\stoptypescript
+
+% Baskerville
+
+\starttypescript [serif] [baskerville]
+ \definefontsynonym [Baskerville-Regular] [name:Baskerville] [features=default]
+ \definefontsynonym [Baskerville-Italic] [name:Baskerville Italic] [features=default]
+ \definefontsynonym [Baskerville-Medium] [name:Baskerville SemiBold] [features=default]
+ \definefontsynonym [Baskerville-MediumItalic] [name:Baskerville SemiBold Italic] [features=default]
+ \definefontsynonym [Baskerville-Bold] [name:Baskerville Bold] [features=default]
+ \definefontsynonym [Baskerville-BoldItalic] [name:Baskerville Bold Italic] [features=default]
+\stoptypescript
+
+% Big Caslon
+
+\starttypescript [serif] [caslon,bigcaslon]
+ \definefontsynonym [BigCaslon-Medium] [name:Big Caslon Medium] [features=default]
+\stoptypescript
+
+% Copperplate
+
+\starttypescript [sans] [copperplate-light,copperplate]
+ \definefontsynonym [Copperplate-Light] [name:Copperplate Light] [features=default]
+ \definefontsynonym [Copperplate-Regular] [name:Copperplate] [features=default]
+ \definefontsynonym [Copperplate-Bold] [name:Copperplate Bold] [features=default]
+\stoptypescript
+
+% Futura
+
+\starttypescript [sans] [futura-condensed,futura]
+ \definefontsynonym [Futura-MediumCond] [name:Futura Condensed Medium] [features=default]
+ \definefontsynonym [Futura-Medium] [name:Futura Medium] [features=default]
+ \definefontsynonym [Futura-MediumItalic] [name:Futura Medium Italic] [features=default]
+ \definefontsynonym [Futura-BoldCond] [name:Futura Condensed ExtraBold] [features=default]
+\stoptypescript
+
+% Gill Sans
+
+\starttypescript [sans] [gillsans-light,gillsans]
+ \definefontsynonym [GillSans-Light] [name:Gill Sans Light] [features=default]
+ \definefontsynonym [GillSans-LightItalic] [name:Gill Sans Light Italic] [features=default]
+ \definefontsynonym [GillSans-Regular] [name:Gill Sans] [features=default]
+ \definefontsynonym [GillSans-Italic] [name:Gill Sans Italic] [features=default]
+ \definefontsynonym [GillSans-Bold] [name:Gill Sans Bold] [features=default]
+ \definefontsynonym [GillSans-BoldItalic] [name:Gill Sans Bold Italic] [features=default]
+\stoptypescript
+
+% Helvetica Neuse
+
+\starttypescript [sans] [helvetica-neue-ultralight,helvetica-neue-light,helvetica-neue,helvetica-neue-boldcondensed]
+ \definefontsynonym [HelveticaNeue-UltraLight] [name:Helvetica Neue UltraLight] [features=default]
+ \definefontsynonym [HelveticaNeue-UltraLightItalic] [name:Helvetica Neue UltraLight Italic] [features=default]
+ \definefontsynonym [HelveticaNeue-Light] [name:Helvetica Neue Light] [features=default]
+ \definefontsynonym [HelveticaNeue-LightItalic] [name:Helvetica Neue Light Italic] [features=default]
+ \definefontsynonym [HelveticaNeue-Regular] [name:Helvetica Neue] [features=default]
+ \definefontsynonym [HelveticaNeue-Italic] [name:Helvetica Neue Italic] [features=default]
+ \definefontsynonym [HelveticaNeue-Bold] [name:Helvetica Neue Bold] [features=default]
+ \definefontsynonym [HelveticaNeue-BoldItalic] [name:Helvetica Neue Bold Italic] [features=default]
+ \definefontsynonym [HelveticaNeue-BoldCond] [name:Helvetica Neue Condensed Bold] [features=default]
+ \definefontsynonym [HelveticaNeue-BlackCond] [name:Helvetica Neue Condensed Black] [features=default]
+\stoptypescript
+
+% Hiragino Mincho
+
+\starttypescript [serif] [hiragino-mincho]
+ \definefontsynonym [HiraginoMinchoPro-Regular] [name:Hiragino Mincho Pro W3] [features=japanese]
+ \definefontsynonym [HiraginoMinchoPro-Bold] [name:Hiragino Mincho Pro W6] [features=japanese]
+ \definefontsynonym [HiraginoMinchoProN-Regular] [name:Hiragino Mincho ProN W3] [features=japanese]
+ \definefontsynonym [HiraginoMinchoProN-Bold] [name:Hiragino Mincho ProN W6] [features=japanese]
+\stoptypescript
+
+% Hiragino Maru
+
+\starttypescript [sans] [hiragino-maru]
+ \definefontsynonym [HiraginoMaruGothicPro-Regular] [name:Hiragino Maru Gothic Pro W4] [features=japanese]
+ \definefontsynonym [HiraginoMaruGothicProN-Regular] [name:Hiragino Maru Gothic ProN W4] [features=japanese]
+\stoptypescript
+
+% Hiragino Kaku
+
+\starttypescript [sans] [hiragino-kaku]
+ \definefontsynonym [HiraginoKakuGothicPro-Regular] [name:Hiragino Kaku Gothic Pro W3] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicPro-Bold] [name:Hiragino Kaku Gothic Pro W6] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicStd-Black] [name:Hiragino Kaku Gothic Std W8] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicProN-Regular] [name:Hiragino Kaku Gothic Pron W3] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicProN-Bold] [name:Hiragino Kaku Gothic ProN W6] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicStdN-Black] [name:Hiragino Kaku Gothic StdN W8] [features=japanese]
+\stoptypescript
+
+% Hoefler Text
+
+\starttypescript [serif] [hoefler]
+ \definefontsynonym [HoeflerText-Regular] [name:Hoefler Text] [features=default]
+ \definefontsynonym [HoeflerText-Italic] [name:Hoefler Text Italic] [features=default]
+ \definefontsynonym [HoeflerText-Black] [name:Hoefler Text Black] [features=default]
+ \definefontsynonym [HoeflerText-BlackItalic] [name:Hoefler Text Black Italic] [features=default]
+ \definefontsynonym [HoeflerText-Ornaments] [name:Hoefler Text Ornaments] [features=default]
+\stoptypescript
+
+% Impact
+
+\starttypescript [sans] [impact]
+ \definefontsynonym [Impact-Regular] [name:Impact] [features=default]
+\stoptypescript
+
+% Andale Mono / Monaco
+
+\starttypescript [mono] [andalemono,monaco]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+\stoptypescript
+
+% Optima
+
+\starttypescript [sans] [optima,optima-bold]
+ \definefontsynonym [Optima-Regular] [name:Optima Regular] [features=default]
+ \definefontsynonym [Optima-Italic] [name:Optima Italic] [features=default]
+ \definefontsynonym [Optima-Bold] [name:Optima Bold] [features=default]
+ \definefontsynonym [Optima-BoldItalic] [name:Optima Bold Italic] [features=default]
+ \definefontsynonym [Optima-Black] [name:Optima ExtraBlack] [features=default]
+\stoptypescript
+
+% Papyrus
+
+\starttypescript [sans] [papyrus]
+ \definefontsynonym [Papyrus-Regular] [name:Papyrus] [features=default]
+ \definefontsynonym [Papyrus-Condensed] [name:Papyrus Condensed] [features=default]
+\stoptypescript
+
+% STFangsong
+
+\starttypescript [serif] [stfangsong]
+ \definefontsynonym [STFangsong-Regular] [name:STFangsong] [features=chinese]
+\stoptypescript
+
+% STHeiti
+
+\starttypescript [sans] [stheiti]
+ \definefontsynonym [STXihei-Light] [name:STHeiti Light] [features=chinese]
+ \definefontsynonym [STHeiti-Regular] [name:STHeiti Regular] [features=chinese]
+\stoptypescript
+
+% STKaiti
+
+\starttypescript [serif] [stkaiti]
+ \definefontsynonym [STKaiti-Regular] [name:STKaiti] [features=chinese]
+\stoptypescript
+
+% STSong
+
+\starttypescript [serif] [stsong]
+ \definefontsynonym [STSong-Regular] [name:STSong] [features=chinese]
+\stoptypescript
+
+% Chalkboard / Comic Sans / Tahoma
+
+\starttypescript [sans] [chalkboard,comicsans,lucidagrande,tahoma]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [name:\typescriptprefix{f:\typescripttwo} Bold] [features=default]
+\stoptypescript
+
+% Cochin / Courier New / Georgia / Times New Roman / Trebuchet / Verdana
+
+\starttypescript [serif,sans,mono] [cochin,georgia,timesnewroman,trebuchet,verdana,couriernew]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [name:\typescriptprefix{f:\typescripttwo} Italic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [name:\typescriptprefix{f:\typescripttwo} Bold] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [name:\typescriptprefix{f:\typescripttwo} Bold Italic] [features=default]
+\stoptypescript
+
+\endinput
diff --git a/tex/context/base/type-mac.mkiv b/tex/context/base/type-mac.mkiv
new file mode 100644
index 000000000..10a415883
--- /dev/null
+++ b/tex/context/base/type-mac.mkiv
@@ -0,0 +1,220 @@
+%D \module
+%D [ file=type-mac,
+%D version=2009.03.10,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Mac OS X Definitions,
+%D author=Wolfgang Schuster,
+%D date=\currentdate,
+%D copyright=Wolfgang Schuster]
+%C
+%C This module is part of the \CONTEXT\ macro||package. See
+%C mreadme.pdf for details.
+
+\definetypescriptprefix [f:andalemono] [andalemono]
+\definetypescriptprefix [f:chalkboard] [chalkboard]
+\definetypescriptprefix [f:cochin] [cochin]
+\definetypescriptprefix [f:comicsans] [comicsansms]
+\definetypescriptprefix [f:couriernew] [couriernew]
+\definetypescriptprefix [f:georgia] [georgia]
+\definetypescriptprefix [f:lucidagrande] [lucidagrande]
+\definetypescriptprefix [f:monaco] [monaco]
+\definetypescriptprefix [f:tahoma] [tahoma]
+\definetypescriptprefix [f:timesnewroman] [timesnewroman]
+\definetypescriptprefix [f:trebuchet] [trebuchetms]
+\definetypescriptprefix [f:verdana] [verdana]
+
+% American Typewriter
+
+\starttypescript [serif] [americantypewriter-light-condensed,americantypewriter-condensed,americantypewriter-light,americantypewriter]
+ \definefontsynonym [AmericanTypewriter-Light] [name:americantypewriterlight] [features=default]
+ \definefontsynonym [AmericanTypewriter-Regular] [name:americantypewriter] [features=default]
+ \definefontsynonym [AmericanTypewriter-Bold] [name:americantypewriterbold] [features=default]
+ \definefontsynonym [AmericanTypewriter-LightCond] [name:americantypewritercondensedlight] [features=default]
+ \definefontsynonym [AmericanTypewriter-Condensed] [name:americantypewritercondensed] [features=default]
+ \definefontsynonym [AmericanTypewriter-BoldCond] [name:americantypewritercondensedbold] [features=default]
+\stoptypescript
+
+% Arial / Arial Narrow / Arial Rounded / Arial Unicode
+
+\starttypescript [sans] [arial-narrow,arial-condensed,arial,arial-rounded,arial-unicode]
+ \definefontsynonym [Arial-Condensed] [name:arialnarrow] [features=default]
+ \definefontsynonym [Arial-ItalicCond] [name:arialnarrowitalic] [features=default]
+ \definefontsynonym [Arial-BoldCond] [name:arialnarrowbold] [features=default]
+ \definefontsynonym [Arial-BoldItalicCond] [name:arialnarrowbolditalic] [features=default]
+ \definefontsynonym [Arial-Regular] [name:arial] [features=default]
+ \definefontsynonym [Arial-Italic] [name:arialitalic] [features=default]
+ \definefontsynonym [Arial-Bold] [name:arialbold] [features=default]
+ \definefontsynonym [Arial-BoldItalic] [name:arialbolditalic] [features=default]
+ \definefontsynonym [Arial-Black] [name:arialblack] [features=default]
+ \definefontsynonym [Arial-Unicode] [name:arialunicodems] [features=default]
+ \definefontsynonym [Arial-Rounded] [name:arialroundedmtbold] [features=default]
+\stoptypescript
+
+% Baskerville
+
+\starttypescript [serif] [baskerville]
+ \definefontsynonym [Baskerville-Regular] [name:baskerville] [features=default]
+ \definefontsynonym [Baskerville-Italic] [name:baskervilleitalic] [features=default]
+ \definefontsynonym [Baskerville-Medium] [name:baskervillesemibold] [features=default]
+ \definefontsynonym [Baskerville-MediumItalic] [name:baskervillesemibolditalic] [features=default]
+ \definefontsynonym [Baskerville-Bold] [name:baskervillebold] [features=default]
+ \definefontsynonym [Baskerville-BoldItalic] [name:baskervillebolditalic] [features=default]
+\stoptypescript
+
+% Big Caslon
+
+\starttypescript [serif] [caslon,bigcaslon]
+ \definefontsynonym [BigCaslon-Medium] [name:bigcaslonmedium] [features=default]
+\stoptypescript
+
+% Copperplate
+
+\starttypescript [sans] [copperplate-light,copperplate]
+ \definefontsynonym [Copperplate-Light] [name:copperplatelight] [features=default]
+ \definefontsynonym [Copperplate-Regular] [name:copperplate] [features=default]
+ \definefontsynonym [Copperplate-Bold] [name:copperplatebold] [features=default]
+\stoptypescript
+
+% Futura
+
+\starttypescript [sans] [futura-condensed,futura]
+ \definefontsynonym [Futura-MediumCond] [name:futuracondensedmedium] [features=default]
+ \definefontsynonym [Futura-Medium] [name:futuramedium] [features=default]
+ \definefontsynonym [Futura-MediumItalic] [name:futuramediumitalic] [features=default]
+ \definefontsynonym [Futura-BoldCond] [name:futuracondensedextrabold] [features=default]
+\stoptypescript
+
+% Gill Sans
+
+\starttypescript [sans] [gillsans-light,gillsans]
+ \definefontsynonym [GillSans-Light] [name:gillsanslight] [features=default]
+ \definefontsynonym [GillSans-LightItalic] [name:gillsanslightitalic] [features=default]
+ \definefontsynonym [GillSans-Regular] [name:gillsans] [features=default]
+ \definefontsynonym [GillSans-Italic] [name:gillsansitalic] [features=default]
+ \definefontsynonym [GillSans-Bold] [name:gillsansbold] [features=default]
+ \definefontsynonym [GillSans-BoldItalic] [name:gillsansbolditalic] [features=default]
+\stoptypescript
+
+% Helvetica Neuse
+
+\starttypescript [sans] [helvetica-neue-ultralight,helvetica-neue-light,helvetica-neue,helvetica-neue-boldcondensed]
+ \definefontsynonym [HelveticaNeue-UltraLight] [name:helveticaneueultralight] [features=default]
+ \definefontsynonym [HelveticaNeue-UltraLightItalic] [name:helveticaneueultralightitalic] [features=default]
+ \definefontsynonym [HelveticaNeue-Light] [name:helveticaneuelight] [features=default]
+ \definefontsynonym [HelveticaNeue-LightItalic] [name:helveticaneuelightitalic] [features=default]
+ \definefontsynonym [HelveticaNeue-Regular] [name:helveticaneue] [features=default]
+ \definefontsynonym [HelveticaNeue-Italic] [name:helveticaneueitalic] [features=default]
+ \definefontsynonym [HelveticaNeue-Bold] [name:helveticaneuebold] [features=default]
+ \definefontsynonym [HelveticaNeue-BoldItalic] [name:helveticaneuebolditalic] [features=default]
+ \definefontsynonym [HelveticaNeue-BoldCond] [name:helveticaneuecondensedbold] [features=default]
+ \definefontsynonym [HelveticaNeue-BlackCond] [name:helveticaneuecondensedblack] [features=default]
+\stoptypescript
+
+% Hiragino Mincho
+
+\starttypescript [serif] [hiragino-mincho]
+ \definefontsynonym [HiraginoMinchoPro-Regular] [name:hiraminprow3] [features=japanese]
+ \definefontsynonym [HiraginoMinchoPro-Bold] [name:hiraminprow6] [features=japanese]
+ \definefontsynonym [HiraginoMinchoProN-Regular] [name:hiraminpronw3] [features=japanese]
+ \definefontsynonym [HiraginoMinchoProN-Bold] [name:hiraminpronw6] [features=japanese]
+\stoptypescript
+
+% Hiragino Maru
+
+\starttypescript [sans] [hiragino-maru]
+ \definefontsynonym [HiraginoMaruGothicPro-Regular] [name:hiramaruprow4] [features=japanese]
+ \definefontsynonym [HiraginoMaruGothicProN-Regular] [name:hiramarupronw4] [features=japanese]
+\stoptypescript
+
+% Hiragino Kaku
+
+\starttypescript [sans] [hiragino-kaku]
+ \definefontsynonym [HiraginoKakuGothicPro-Regular] [name:hirakakuprow3] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicPro-Bold] [name:hirakakuprow6] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicStd-Black] [name:hirakakustdw8] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicProN-Regular] [name:hirakakupronw3] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicProN-Bold] [name:hirakakupronw6] [features=japanese]
+ \definefontsynonym [HiraginoKakuGothicStdN-Black] [name:hirakakustdnw8] [features=japanese]
+\stoptypescript
+
+% Hoefler Text
+
+\starttypescript [serif] [hoefler]
+ \definefontsynonym [HoeflerText-Regular] [name:hoeflertext] [features=default]
+ \definefontsynonym [HoeflerText-Italic] [name:hoeflertextitalic] [features=default]
+ \definefontsynonym [HoeflerText-Black] [name:hoeflertextblack] [features=default]
+ \definefontsynonym [HoeflerText-BlackItalic] [name:hoeflertextblackitalic] [features=default]
+ \definefontsynonym [HoeflerText-Ornaments] [name:hoeflertextornaments] [features=default]
+\stoptypescript
+
+% Impact
+
+\starttypescript [sans] [impact]
+ \definefontsynonym [Impact-Regular] [name:impact] [features=default]
+\stoptypescript
+
+% Andale Mono / Monaco
+
+\starttypescript [mono] [andalemono,monaco]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+\stoptypescript
+
+% Optima
+
+\starttypescript [sans] [optima,optima-bold]
+ \definefontsynonym [Optima-Regular] [name:optimaregular] [features=default]
+ \definefontsynonym [Optima-Italic] [name:optimaitalic] [features=default]
+ \definefontsynonym [Optima-Bold] [name:optimabold] [features=default]
+ \definefontsynonym [Optima-BoldItalic] [name:optimabolditalic] [features=default]
+ \definefontsynonym [Optima-Black] [name:optimaextrablack] [features=default]
+\stoptypescript
+
+% Papyrus
+
+\starttypescript [sans] [papyrus]
+ \definefontsynonym [Papyrus-Regular] [name:papyrus] [features=default]
+ \definefontsynonym [Papyrus-Condensed] [name:papyruscondensed] [features=default]
+\stoptypescript
+
+% STFangsong
+
+\starttypescript [serif] [stfangsong]
+ \definefontsynonym [STFangsong-Regular] [name:stfangsong] [features=chinese]
+\stoptypescript
+
+% STHeiti
+
+\starttypescript [sans] [stheiti]
+ \definefontsynonym [STXihei-Light] [name:stxihei] [features=chinese]
+ \definefontsynonym [STHeiti-Regular] [name:stheiti] [features=chinese]
+\stoptypescript
+
+% STKaiti
+
+\starttypescript [serif] [stkaiti]
+ \definefontsynonym [STKaiti-Regular] [name:stkaiti] [features=chinese]
+\stoptypescript
+
+% STSong
+
+\starttypescript [serif] [stsong]
+ \definefontsynonym [STSong-Regular] [name:stsong] [features=chinese]
+\stoptypescript
+
+% Chalkboard / Comic Sans / Tahoma
+
+\starttypescript [sans] [chalkboard,comicsans,tahoma]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [name:\typescriptprefix{f:\typescripttwo}bold] [features=default]
+\stoptypescript
+
+% Cochin / Courier New / Georgia / Times New Roman / Trebuchet / Verdana
+
+\starttypescript [serif,sans,mono] [cochin,georgia,timesnewroman,trebuchet,verdana,couriernew]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [name:\typescriptprefix{f:\typescripttwo}italic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [name:\typescriptprefix{f:\typescripttwo}bold] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [name:\typescriptprefix{f:\typescripttwo}bolditalic] [features=default]
+\stoptypescript
+
+\endinput
diff --git a/tex/context/base/type-mac.tex b/tex/context/base/type-mac.tex
new file mode 100644
index 000000000..04ac6139b
--- /dev/null
+++ b/tex/context/base/type-mac.tex
@@ -0,0 +1,434 @@
+%D \module
+%D [ file=type-mac,
+%D version=2009.03.10,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Mac OS X Definitions,
+%D author=Wolfgang Schuster,
+%D date=\currentdate,
+%D copyright=Wolfgang Schuster]
+%C
+%C This module is part of the \CONTEXT\ macro||package. See
+%C mreadme.pdf for details.
+
+\starttypescriptcollection [macosx]
+
+\definetypescriptprefix [n:andalemono] [AndaleMono]
+\definetypescriptprefix [n:chalkboard] [Chalkboard]
+\definetypescriptprefix [n:cochin] [Cochin]
+\definetypescriptprefix [n:comicsans] [ComicSans]
+\definetypescriptprefix [n:couriernew] [CourierNew]
+\definetypescriptprefix [n:georgia] [Georgia]
+\definetypescriptprefix [n:lucidagrande] [LucidaGrande]
+\definetypescriptprefix [n:monaco] [Monaco]
+\definetypescriptprefix [n:tahoma] [Tahoma]
+\definetypescriptprefix [n:timesnewroman] [TimesNewRoman]
+\definetypescriptprefix [n:trebuchet] [Trebuchet]
+\definetypescriptprefix [n:verdana] [Verdana]
+
+% American Typewriter
+
+\starttypescript [serif] [americantypewriter-light-condensed]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [AmericanTypewriter-LightCond] [features=default]
+ \definefontsynonym [SerifBold] [AmericanTypewriter-Condensed] [features=default]
+\stoptypescript
+
+\starttypescript [serif] [americantypewriter-condensed]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [AmericanTypewriter-Condensed] [features=default]
+ \definefontsynonym [SerifBold] [AmericanTypewriter-BoldCond] [features=default]
+\stoptypescript
+
+\starttypescript [serif] [americantypewriter-light]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [AmericanTypewriter-Light] [features=default]
+ \definefontsynonym [SerifBold] [AmericanTypewriter-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [serif] [americantypewriter]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [AmericanTypewriter-Regular] [features=default]
+ \definefontsynonym [SerifBold] [AmericanTypewriter-Bold] [features=default]
+\stoptypescript
+
+\starttypescript [americantypewriter-light-condensed,americantypewriter-condensed,americantypewriter-light,americantypewriter]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Arial / Arial Narrow / Arial Rounded / Arial Unicode
+
+\starttypescript [sans] [arial-narrow,arial-condensed]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Arial-Condensed] [features=default]
+ \definefontsynonym [SansItalic] [Arial-ItalicCond] [features=default]
+ \definefontsynonym [SansBold] [Arial-BoldCond] [features=default]
+ \definefontsynonym [SansBoldItalic] [Arial-BoldItalicCond] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arial]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Arial-Regular] [features=default]
+ \definefontsynonym [SansItalic] [Arial-Italic] [features=default]
+ \definefontsynonym [SansBold] [Arial-Bold] [features=default]
+ \definefontsynonym [SansBoldItalic] [Arial-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arial-rounded]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Arial-Rounded] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arial-unicode]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Arial-Unicode] [features=default]
+\stoptypescript
+
+\starttypescript [arial-narrow,arial-condensed,arial,arial-rounded,arial-unicode]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Baskerville
+
+\starttypescript [serif] [baskerville]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [Baskerville-Regular] [features=default]
+ \definefontsynonym [SerifItalic] [Baskerville-Italic] [features=default]
+ \definefontsynonym [SerifBold] [Baskerville-Medium] [features=default]
+ \definefontsynonym [SerifBoldItalic] [Baskerville-MediumItalic] [features=default]
+\stoptypescript
+
+\starttypescript [baskerville]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Big Caslon
+
+\starttypescript [serif] [caslon,bigcaslon]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [BigCaslon-Medium] [features=default]
+\stoptypescript
+
+\starttypescript [caslon,bigcaslon]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Copperplate
+
+\starttypescript [sans] [copperplate-light]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Copperplate-Light] [features=default]
+ \definefontsynonym [SansBold] [Copperplate-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [copperplate]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Copperplate-Regular] [features=default]
+ \definefontsynonym [SansBold] [Copperplate-Bold] [features=default]
+\stoptypescript
+
+\starttypescript [copperplate-light,copperplate]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Courier New
+
+\starttypescript [mono] [couriernew]
+ \setups[font:fallback:mono]
+ \definefontsynonym [Mono] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
+ \definefontsynonym [MonoItalic] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
+ \definefontsynonym [MonoBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
+ \definefontsynonym [MonoBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [couriernew]
+ \definetypeface [\typescriptone] [tt] [mono] [\typescriptone] [default]
+\stoptypescript
+
+% Futura
+
+\starttypescript [sans] [futura-condensed]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Futura-MediumCond] [features=default]
+ \definefontsynonym [SansBold] [Futura-BoldCond] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [futura]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Futura-Medium] [features=default]
+ \definefontsynonym [SansItalic] [Futura-MediumItalic] [features=default]
+\stoptypescript
+
+\starttypescript [futura-condensed,futura]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Gill Sans
+
+\starttypescript [sans] [gillsans-light]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [GillSans-Light] [features=default]
+ \definefontsynonym [SansItalic] [GillSans-LightItalic] [features=default]
+ \definefontsynonym [SansBold] [GillSans-Regular] [features=default]
+ \definefontsynonym [SansBoldItalic] [GillSans-Italic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [gillsans]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [GillSans-Regular] [features=default]
+ \definefontsynonym [SansItalic] [GillSans-Italic] [features=default]
+ \definefontsynonym [SansBold] [GillSans-Bold] [features=default]
+ \definefontsynonym [SansBoldItalic] [GillSans-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [gillsans-light,gillsans]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Helvetica Neuse
+
+\starttypescript [sans] [helvetica-neue-ultralight]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HelveticaNeue-UltraLight] [features=default]
+ \definefontsynonym [SansItalic] [HelveticaNeue-UltraLightItalic] [features=default]
+ \definefontsynonym [SansBold] [HelveticaNeue-Light] [features=default]
+ \definefontsynonym [SansBoldItalic] [HelveticaNeue-LightItalic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [helvetica-neue-light]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HelveticaNeue-Light] [features=default]
+ \definefontsynonym [SansItalic] [HelveticaNeue-LightItalic] [features=default]
+ \definefontsynonym [SansBold] [HelveticaNeue-Regular] [features=default]
+ \definefontsynonym [SansBoldItalic] [HelveticaNeue-Italic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [helvetica-neue]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HelveticaNeue-Regular] [features=default]
+ \definefontsynonym [SansItalic] [HelveticaNeue-Italic] [features=default]
+ \definefontsynonym [SansBold] [HelveticaNeue-Bold] [features=default]
+ \definefontsynonym [SansBoldItalic] [HelveticaNeue-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [helvetica-neue-boldcondensed]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HelveticaNeue-BoldCond] [features=default]
+ \definefontsynonym [SansBold] [HelveticaNeue-BlackCond] [features=default]
+\stoptypescript
+
+\starttypescript [helvetica-neue-ultralight,helvetica-neue-light,helvetica-neue,helvetica-neue-boldcondensed]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Hiragino Mincho
+
+\starttypescript [serif] [hiragino-mincho]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [HiraginoMinchoPro-Regular] [features=japanese]
+ \definefontsynonym [SerifBold] [HiraginoMinchoPro-Bold] [features=japanese]
+\stoptypescript
+
+% \starttypescript [serif] [hiragino-mincho]
+% \setups[font:fallback:serif]
+% \definefontsynonym [Serif] [HiraginoMinchoProN-Regular] [features=japanese]
+% \definefontsynonym [SerifBold] [HiraginoMinchoProN-Bold] [features=japanese]
+% \stoptypescript
+
+\starttypescript [hiragino-mincho]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Hiragino Maru
+
+\starttypescript [sans] [hiragino-maru]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HiraginoMaruGothicPro-Regular] [features=japanese]
+\stoptypescript
+
+% \starttypescript [sans] [hiragino-maru]
+% \setups[font:fallback:sans]
+% \definefontsynonym [Sans] [HiraginoMaruGothicProN-Regular] [features=japanese]
+% \stoptypescript
+
+\starttypescript [hiragino-maru]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Hiragino Kaku
+
+\starttypescript [sans] [hiragino-kaku]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [HiraginoKakuGothicPro-Regular] [features=japanese]
+ \definefontsynonym [SansBold] [HiraginoKakuGothicPro-Bold] [features=japanese]
+\stoptypescript
+
+% \starttypescript [sans] [hiragino-kaku]
+% \setups[font:fallback:sans]
+% \definefontsynonym [Sans] [HiraginoKakuGothicProN-Regular] [features=japanese]
+% \definefontsynonym [SansBold] [HiraginoKakuGothicProN-Bold] [features=japanese]
+% \stoptypescript
+
+\starttypescript [hiragino-kaku]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Hoefler Text
+
+\starttypescript [serif] [hoefler]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [HoeflerText-Regular] [features=default]
+ \definefontsynonym [SerifItalic] [HoeflerText-Italic] [features=default]
+ \definefontsynonym [SerifBold] [HoeflerText-Black] [features=default]
+ \definefontsynonym [SerifBoldItalic] [HoeflerText-BlackItalic] [features=default]
+\stoptypescript
+
+\starttypescript [hoefler]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Impact
+
+\starttypescript [sans] [impact]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Impact-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [impact]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Andale Mono / Monaco
+
+\starttypescript [mono] [andalemono,monaco]
+ \setups[font:fallback:mono]
+ \definefontsynonym [Mono] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [andalemono,monaco]
+ \definetypeface [\typescriptone] [tt] [mono] [\typescriptone] [default]
+\stoptypescript
+
+% Optima
+
+\starttypescript [sans] [optima]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Optima-Regular] [features=default]
+ \definefontsynonym [SansItalic] [Optima-Italic] [features=default]
+ \definefontsynonym [SansBold] [Optima-Bold] [features=default]
+ \definefontsynonym [SansBoldItalic] [Optima-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [optima-bold]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Optima-Bold] [features=default]
+ \definefontsynonym [SansItalic] [Optima-BoldItalic] [features=default]
+ \definefontsynonym [SansBold] [Optima-Black] [features=default]
+\stoptypescript
+
+\starttypescript [optima,optima-bold]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Papyrus
+
+\starttypescript [sans] [papyrus]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [Papyrus-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [papyrus]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% STFangsong
+
+\starttypescript [serif] [stfangsong]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Serif] [STFangsong-Regular] [features=chinese]
+\stoptypescript
+
+\starttypescript [stfangsong]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% STHeiti
+
+\starttypescript [sans] [stheiti]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [STXihei-Light] [features=chinese]
+ \definefontsynonym [SansBold] [STKaiti-Regular] [features=chinese]
+\stoptypescript
+
+\starttypescript [stheiti]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% STKaiti
+
+\starttypescript [serif] [stkaiti]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Serif] [STKaiti-Regular] [features=chinese]
+\stoptypescript
+
+\starttypescript [stkaiti]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% STSong
+
+\starttypescript [serif] [stsong]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Serif] [STSong-Regular] [features=chinese]
+\stoptypescript
+
+\starttypescript [stsong]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Chalkboard / Comic Sans / Tahoma
+
+\starttypescript [sans] [chalkboard,comicsans,lucidagrande,tahoma]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
+ \definefontsynonym [SansBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
+\stoptypescript
+
+\starttypescript [chalkboard,comicsans,tahoma]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+% Cochin / Georgia / Times New Roman
+
+\starttypescript [serif] [cochin,georgia,timesnewroman]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
+ \definefontsynonym [SerifItalic] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
+ \definefontsynonym [SerifBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
+ \definefontsynonym [SerifBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [cochin,georgia,timesnewroman]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+% Trebuchet / Verdana
+
+\starttypescript [sans] [trebuchet,verdana]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
+ \definefontsynonym [SansItalic] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
+ \definefontsynonym [SansBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
+ \definefontsynonym [SansBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [trebuchet,verdana]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+\stoptypescriptcollection
+
+% XeTeX / LuaTeX font names
+
+\loadmarkfile{type-mac}
+
+\endinput
diff --git a/tex/context/base/type-map.tex b/tex/context/base/type-map.tex
index 37eef0ed5..5a581a78b 100644
--- a/tex/context/base/type-map.tex
+++ b/tex/context/base/type-map.tex
@@ -28,7 +28,7 @@
\loadmapfile[original-ams-base.map]
%loadmapfile[original-ams-cmr.map]
\loadmapfile[original-ams-euler.map]
- \loadmapfile[original-public-lm.map]
+ %loadmapfile[original-public-lm.map]
\stoptypescript
% This is the base map file, load it to be sure.
@@ -47,7 +47,7 @@
% cmr and related
\starttypescript [map] [cmr,lm,lmr]
- \loadmapfile[original-public-lm.map]
+ %loadmapfile[original-public-lm.map]
\loadmapfile[original-ams-base.map]
\loadmapfile[original-ams-euler.map]
\stoptypescript
@@ -145,34 +145,34 @@
\loadmapfile[kurier-ex.map]
\stoptypescript
-\starttypescript [map] [bookman] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-bookman.map]
-\stoptypescript
+% \starttypescript [map] [bookman] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-bookman.map]
+% \stoptypescript
-\starttypescript [map] [courier] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-courier.map]
-\stoptypescript
+% \starttypescript [map] [courier] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-courier.map]
+% \stoptypescript
-\starttypescript [map] [helvetica] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-helvetica.map]
-\stoptypescript
+% \starttypescript [map] [helvetica] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-helvetica.map]
+% \stoptypescript
-\starttypescript [map] [palatino] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-palatino.map]
- %loadmapfile[\typescriptthree-public-pfl.map]
-\stoptypescript
+% \starttypescript [map] [palatino] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-palatino.map]
+% %loadmapfile[\typescriptthree-public-pfl.map]
+% \stoptypescript
-\starttypescript [map] [times] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-times.map]
-\stoptypescript
+% \starttypescript [map] [times] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-times.map]
+% \stoptypescript
-\starttypescript [map] [chancery] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-zapfchan.map]
-\stoptypescript
+% \starttypescript [map] [chancery] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-zapfchan.map]
+% \stoptypescript
-\starttypescript [map] [schoolbook] [ec,texnansi,t5,8r]
- \loadmapfile[\typescriptthree-urw-ncntrsbk.map]
-\stoptypescript
+% \starttypescript [map] [schoolbook] [ec,texnansi,t5,8r]
+% \loadmapfile[\typescriptthree-urw-ncntrsbk.map]
+% \stoptypescript
% once i can be sure that the map files are in the tree, i will
% use those instead of original (too many variants anyway)
diff --git a/tex/context/base/type-one.tex b/tex/context/base/type-one.tex
index 5ca09b30a..b456d7e64 100644
--- a/tex/context/base/type-one.tex
+++ b/tex/context/base/type-one.tex
@@ -58,30 +58,27 @@
\quittypescriptscanning
\stoptypescript
-\starttypescript [postscript] [texnansi,ec,qx,t5,uc,8r]
+\starttypescript [postscript] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
\definetypeface [postscript] [rm] [serif] [times] [default] [encoding=\typescripttwo]
- \definetypeface [postscript] [ss] [sans] [helvetica] [default] [rscale=.9,encoding=\typescripttwo]
- \definetypeface [postscript] [tt] [mono] [courier] [default] [rscale=1.1,encoding=\typescripttwo]
- \definetypeface [postscript] [mm] [math] [times] [default]
- \usemathcollection[default]
+ \definetypeface [postscript] [ss] [sans] [helvetica] [default] [encoding=\typescripttwo,rscale=0.9]
+ \definetypeface [postscript] [tt] [mono] [courier] [default] [encoding=\typescripttwo,rscale=1.1]
+ \definetypeface [postscript] [mm] [math] [times] [default] [encoding=\typescripttwo]
\quittypescriptscanning
\stoptypescript
-\starttypescript [times] [texnansi,ec,qx,8r,t5,uc]
- \definetypeface [times] [rm] [serif] [times] [default] [encoding=\typescripttwo]
- \definetypeface [times] [ss] [sans] [helvetica] [default] [encoding=\typescripttwo,rscale=0.9]
- \definetypeface [times] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.05]
- \definetypeface [times] [mm] [math] [times] [default] [encoding=\typescripttwo]
- \usemathcollection[default]
+\starttypescript [times,termes] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [helvetica] [default] [encoding=\typescripttwo,rscale=0.9]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.05]
+ \definetypeface [\typescriptone] [mm] [math] [times] [default] [encoding=\typescripttwo]
\quittypescriptscanning
\stoptypescript
-\starttypescript [palatino] [texnansi,ec,qx,8r,t5,uc]
- \definetypeface [palatino] [rm] [serif] [palatino] [default] [encoding=\typescripttwo]
- \definetypeface [palatino] [ss] [sans] [modern] [default] [encoding=\typescripttwo,rscale=1.075]
- \definetypeface [palatino] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.075]
- \definetypeface [palatino] [mm] [math] [palatino] [default] [encoding=default]
- \usemathcollection[default]
+\starttypescript [palatino,pagella] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [encoding=\typescripttwo,rscale=1.075]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.075]
+ \definetypeface [\typescriptone] [mm] [math] [palatino] [default] [encoding=default]
\quittypescriptscanning
\stoptypescript
@@ -90,7 +87,6 @@
\definetypeface [fourier] [ss] [sans] [modern] [default] [encoding=ec,rscale=1.07]
\definetypeface [fourier] [tt] [mono] [modern] [default] [encoding=ec,rscale=1.07]
\definetypeface [fourier] [mm] [math] [fourier] [default] [encoding=default]
- \usemathcollection[fou]
\quittypescriptscanning
\stoptypescript
@@ -117,7 +113,7 @@
\quittypescriptscanning
\stoptypescript
-\starttypescript [antykwa-torunska] [texnansi,ec,8r,uc,t2a]
+\starttypescript [antykwa-torunska] [texnansi,ec,8r,uc,t5,t2a]
\definetypeface[antykwa][rm][serif][antykwa-torunska] [default][encoding=\typescripttwo]
\definetypeface[antykwa][ss][sans] [modern] [default][encoding=\typescripttwo,rscale=1.05]
\definetypeface[antykwa][tt][mono] [modern] [default][encoding=\typescripttwo,rscale=1.1]
@@ -125,6 +121,30 @@
\quittypescriptscanning
\stoptypescript
+\starttypescript [schoolbook,schola] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default]
+ \quittypescriptscanning
+\stoptypescript
+
+\starttypescript [bookman,bonum] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default]
+ \quittypescriptscanning
+\stoptypescript
+
+\starttypescript [chancery,chorus] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default]
+ \quittypescriptscanning
+\stoptypescript
+
\starttypescript [iwona,iwona-light,iwona-heavy,iwona-medium] [texnansi,ec,8r,uc,t2a]
\definetypeface[\typescriptone][ss][sans] [\typescriptone] [default][encoding=\typescripttwo]
\definetypeface[\typescriptone][rm][serif][modern] [default][encoding=\typescripttwo]
@@ -133,6 +153,30 @@
\quittypescriptscanning
\stoptypescript
+\starttypescript [helvetica,heros] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default] [encoding=\typescripttwo,rscale=1.15]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.15]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default,rscale=1.15]
+ \quittypescriptscanning
+\stoptypescript
+
+\starttypescript [avantgarde,adventor] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [ss] [sans] [adventor] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default] [encoding=\typescripttwo,rscale=1.15]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [encoding=\typescripttwo,rscale=1.15]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default]
+ \quittypescriptscanning
+\stoptypescript
+
+\starttypescript [courier,cursor] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definetypeface [\typescriptone] [tt] [mono] [\typescriptone] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [encoding=\typescripttwo]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [encoding=default]
+ \quittypescriptscanning
+\stoptypescript
+
\stoptypescriptcollection
\starttypescriptcollection[typeone]
@@ -143,9 +187,7 @@
\stoptypescript
\starttypescript[all][modern,latin-modern][all]
-
% fallbacks, no math in latin modern
-
\definefontsynonym[lmdunh10][cmdunh10]
\definefontsynonym[lmff10] [cmff10]
\definefontsynonym[lmfi10] [cmfi10]
@@ -153,7 +195,6 @@
\definefontsynonym[lmtex10] [cmtex10]
\definefontsynonym[lmtex8] [cmtex8]
\definefontsynonym[lmtex9] [cmtex9]
-
\loadmapfile[original-public-lm.map]
\stoptypescript
@@ -192,7 +233,6 @@
\definefontsynonym [LMRoman10-Dunhill] [\typescriptthree-lmdunh10] [encoding=\typescriptthree]
\definefontsynonym [LMRoman10-DunhillOblique] [\typescriptthree-lmduno10] [encoding=\typescriptthree]
-
\loadmapfile[lm-\typescriptthree.map]
\stoptypescript
@@ -215,7 +255,6 @@
\definefontsynonym [LMSansQuotation8-Bold] [\typescriptthree-lmssqbx8] [encoding=\typescriptthree]
\definefontsynonym [LMSansQuotation8-Oblique] [\typescriptthree-lmssqo8] [encoding=\typescriptthree]
\definefontsynonym [LMSansQuotation8-BoldOblique] [\typescriptthree-lmssqbo8] [encoding=\typescriptthree]
-
\loadmapfile[lm-\typescriptthree.map]
\stoptypescript
@@ -234,16 +273,13 @@
\definefontsynonym [LMTypewriter10-LightCondensedOblique] [\typescriptthree-lmtlco10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriter10-Dark] [\typescriptthree-lmtk10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriter10-DarkOblique] [\typescriptthree-lmtko10] [encoding=\typescriptthree]
-
\definefontsynonym [LMTypewriter10-Unslanted] [\typescriptthree-lmu10] [encoding=\typescriptthree]
-
\definefontsynonym [LMTypewriterVarWd10-Regular] [\typescriptthree-lmvtt10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriterVarWd10-Oblique] [\typescriptthree-lmvtto10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriterVarWd10-Light] [\typescriptthree-lmvtl10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriterVarWd10-LightOblique] [\typescriptthree-lmvtlo10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriterVarWd10-Dark] [\typescriptthree-lmvtk10] [encoding=\typescriptthree]
\definefontsynonym [LMTypewriterVarWd10-DarkOblique] [\typescriptthree-lmvtko10] [encoding=\typescriptthree]
-
\loadmapfile[lm-\typescriptthree.map]
\stoptypescript
@@ -283,7 +319,7 @@
\definefontsynonym [LMMathItalic5-BoldItalic] [lmmib5]
\definefontsynonym [LMMathItalic7-BoldItalic] [lmmib7]
\definefontsynonym [LMMathItalic10-BoldItalic] [lmmib10]
-
+ \usemathcollection[default]
\loadmapfile[lm-math.map]
\loadmapfile[lm-rm.map]
\stoptypescript
@@ -589,7 +625,7 @@
\definefontsynonym [Euler-Extension] [zeuex10]
\definefontsynonym [Euler-Symbol] [zeusm10]
\definefontsynonym [Euler-Fraktur] [eufm10]
-
+ \usemathcollection[eul]
\loadmapfile[original-ams-euler.map]
\stoptypescript
@@ -598,15 +634,16 @@
\definefontsynonym [Euler-Extension] [zeuex10]
\definefontsynonym [Euler-Symbol-Bold] [zeusb10]
\definefontsynonym [Euler-Fraktur-Bold] [eufb10]
-
+ \usemathcollection[eul]
\loadmapfile[original-ams-euler.map]
\stoptypescript
% AMS (AMS)
\starttypescript [math] [modern,computer-modern,latin-modern,ams] [default]
- \definefontsynonym [AMS-SymbolA] [msam10]
- \definefontsynonym [AMS-SymbolB] [msbm10]
+ \definefontsynonym [AMS-SymbolA] [msam10]
+ \definefontsynonym [AMS-SymbolB] [msbm10]
+ \usemathcollection[default]
\stoptypescript
% Fourier (Utopia)
@@ -617,7 +654,7 @@
\definefontsynonym [Fourier-Math-Letters-Italic] [futmii]
\definefontsynonym [Fourier-Math-Symbols] [futsy]
\definefontsynonym [Fourier-Math-Extension] [fourier-mex]
-
+ \usemathcollection[fou]
\loadmapfile[fourier.map]
\stoptypescript
@@ -630,7 +667,6 @@
\definefontsynonym [Fourier-BoldSlanted] [futbo8t] [encoding=ec]
\definefontsynonym [Fourier-BoldItalic] [futbi8t] [encoding=ec]
\definefontsynonym [Fourier-BoldCaps] [futbc8t] [encoding=ec]
-
\definefontsynonym [Fourier-Regular-Expert] [futr9e] [encoding=ec]
\definefontsynonym [Fourier-Slanted-Expert] [futro9e] [encoding=ec]
\definefontsynonym [Fourier-Italic-Expert] [futri9e] [encoding=ec]
@@ -643,7 +679,6 @@
\definefontsynonym [Fourier-BoldSlanted-Expert] [futbo9e] [encoding=ec]
\definefontsynonym [Fourier-BoldItalic-Expert] [futbi9e] [encoding=ec]
\definefontsynonym [Fourier-Black-Expert] [futc9e] [encoding=ec]
-
\definefontsynonym [Fourier-Regular-OldStyle] [futr9d] [encoding=ec]
\definefontsynonym [Fourier-Slanted-OldStyle] [futro9d] [encoding=ec]
\definefontsynonym [Fourier-Italic-OldStyle] [futri9d] [encoding=ec]
@@ -656,97 +691,10 @@
\definefontsynonym [Fourier-BoldSlanted-OldStyle] [futbo9d] [encoding=ec]
\definefontsynonym [Fourier-BoldItalic-OldStyle] [futbi9d] [encoding=ec]
\definefontsynonym [Fourier-Black-OldStyle] [futc9d] [encoding=ec]
-
\loadmapfile[fourier.map]
\loadmapfile[fourier-utopia-expert.map]
\stoptypescript
-% Courier (URW)
-
-\starttypescript [mono] [courier] [qx]
- \definefontsynonym [qx-ucrr8a] [qcrr] [encoding=qx]
- \definefontsynonym [qx-ucrb8a] [qcrb] [encoding=qx]
- \definefontsynonym [qx-ucrro8a] [qcrri] [encoding=qx]
- \definefontsynonym [qx-ucrbo8a] [qcrbi] [encoding=qx]
-\stoptypescript
-
-\starttypescript [mono] [courier] [texnansi,ec,8r,t5]
- \definefontsynonym [Courier] [\typescriptthree-ucrr8a] [encoding=\typescriptthree]
- \definefontsynonym [Courier-Bold] [\typescriptthree-ucrb8a] [encoding=\typescriptthree]
- \definefontsynonym [Courier-Oblique] [\typescriptthree-ucrro8a] [encoding=\typescriptthree]
- \definefontsynonym [Courier-BoldOblique] [\typescriptthree-ucrbo8a] [encoding=\typescriptthree]
-
- \loadmapfile[\typescriptthree-urw-courier.map]
-\stoptypescript
-
-% Helvetica (URW)
-
-\starttypescript [sans] [helvetica] [qx]
- \definefontsynonym [qx-uhvr8a] [qhvr] [encoding=qx]
- \definefontsynonym [qx-uhvri8a] [qhvri] [encoding=qx]
- \definefontsynonym [qx-uhvro8a] [qhvri] [encoding=qx]
- \definefontsynonym [qx-uhvb8a] [qhvb] [encoding=qx]
- \definefontsynonym [qx-uhvbi8a] [qhvbi] [encoding=qx]
- \definefontsynonym [qx-uhvbo8a] [qhvbi] [encoding=qx]
-\stoptypescript
-
-\starttypescript [sans] [helvetica] [texnansi,ec,8r,t5]
- \definefontsynonym [Helvetica] [\typescriptthree-uhvr8a] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Italic] [\typescriptthree-uhvri8a] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Oblique] [\typescriptthree-uhvro8a] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-Bold] [\typescriptthree-uhvb8a] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-BoldItalic] [\typescriptthree-uhvbi8a] [encoding=\typescriptthree]
- \definefontsynonym [Helvetica-BoldOblique] [\typescriptthree-uhvbo8a] [encoding=\typescriptthree]
-
- \loadmapfile[\typescriptthree-urw-helvetica.map]
-\stoptypescript
-
-% Times Roman (URW)
-
-\starttypescript [serif] [times] [qx]
- \definefontsynonym [qx-utmr8a] [qtmr] [encoding=qx]
- \definefontsynonym [qx-utmri8a] [qtmri] [encoding=qx]
- \definefontsynonym [qx-utmb8a] [qtmb] [encoding=qx]
- \definefontsynonym [qx-utmbi8a] [qtmbi] [encoding=qx]
- \definefontsynonym [qx-utmr8a-slanted-167] [qtmri] [encoding=qx]
- \definefontsynonym [qx-utmb8a-slanted-167] [qtmbi] [encoding=qx]
-\stoptypescript
-
-\starttypescript [serif] [times] [texnansi,ec,8r,t5]
- \definefontsynonym [Times-Roman] [\typescriptthree-utmr8a] [encoding=\typescriptthree]
- \definefontsynonym [Times-Italic] [\typescriptthree-utmri8a] [encoding=\typescriptthree]
- \definefontsynonym [Times-Bold] [\typescriptthree-utmb8a] [encoding=\typescriptthree]
- \definefontsynonym [Times-BoldItalic] [\typescriptthree-utmbi8a] [encoding=\typescriptthree]
- \definefontsynonym [Times-Slanted] [\typescriptthree-utmr8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Times-BoldSlanted] [\typescriptthree-utmb8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Times-Caps] [Times-Roman]
- \definefontsynonym [Times] [Times-Roman]
-
- \loadmapfile[\typescriptthree-urw-times.map]
-\stoptypescript
-
-% Math Times (tx)
-
-\starttypescript [math] [times] [all]
- \definefontsynonym [Times-Roman-Upright] [txr]
- \definefontsynonym [Times-Roman-Italic] [txi]
- \definefontsynonym [Times-Roman-Slanted] [txsl]
- \definefontsynonym [Times-Roman-Caps] [txsc]
- \definefontsynonym [Times-Companion-Upright] [tcxr]
- \definefontsynonym [Times-Companion-Italic] [tcxi]
- \definefontsynonym [Times-Companion-Slanted] [tcxsl]
- \definefontsynonym [Times-Math-Italic] [txmi]
- \definefontsynonym [Times-Math-Symbols] [txsy]
- \definefontsynonym [Times-Math-Extension] [txex]
- \definefontsynonym [Times-Math-SymbolsA] [txsya]
- \definefontsynonym [Times-Math-SymbolsB] [txsyb]
- \definefontsynonym [Times-Math-SymbolsC] [txsyc]
- \definefontsynonym [Times-Math-Italic-A] [txmia]
- \definefontsynonym [Times-Math-Extension-A] [txexa]
-
- \loadmapfile[original-youngryu-tx.map]
-\stoptypescript
-
% Antykwa Torunska (GUST)
% \starttypescript [serif] [antykwa-torunska] [texnansi,ec,8r]
@@ -772,7 +720,6 @@
\definefontsynonym [AntykwaTorunska-CondLightItalic][\typescriptthree-anttcli] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondMedium] [\typescriptthree-anttcm] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondMedItalic] [\typescriptthree-anttcmi] [encoding=\typescriptthree]
-
\loadmapfile[antt-\typescriptthree.map]
\stoptypescript
@@ -793,7 +740,6 @@
\definefontsynonym [AntykwaTorunska-CondLightItalicCap][\typescriptthree-anttclicap] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondMediumCap] [\typescriptthree-anttcmcap] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondMedItalicCap] [\typescriptthree-anttcmicap] [encoding=\typescriptthree]
-
\loadmapfile[antt-\typescriptthree.map]
\stoptypescript
@@ -817,7 +763,6 @@
\definefontsynonym [AntykwaTorunska-CondMedItalicCap] [\typescriptthree-anttcmi] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondCap] [\typescriptthree-anttcr] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondItalicCap] [\typescriptthree-anttcri] [encoding=\typescriptthree]
-
\loadmapfile[antt-\typescriptthree.map]
\stoptypescript
@@ -838,7 +783,6 @@
\definefontsynonym [AntykwaTorunska-CondMedItalicCap] [\typescriptthree-anttcmi] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondCap] [\typescriptthree-anttcr] [encoding=\typescriptthree]
\definefontsynonym [AntykwaTorunska-CondItalicCap] [\typescriptthree-anttcri] [encoding=\typescriptthree]
-
\loadmapfile[antt-\typescriptthree.map]
\stoptypescript
@@ -874,6 +818,7 @@
\stoptypescript
\starttypescript [math] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond] [default]
+ \usemathcollection[default]
\loadmapfile[antt-rm.map]
\loadmapfile[antt-mi.map]
\loadmapfile[antt-sy.map]
@@ -887,7 +832,6 @@
\definefontsynonym [AntykwaPoltawskiego-Bold] [\typescriptthree-antpb] [encoding=\typescriptthree]
\definefontsynonym [AntykwaPoltawskiego-Italic] [\typescriptthree-antpri] [encoding=\typescriptthree]
\definefontsynonym [AntykwaPoltawskiego-BoldItalic] [\typescriptthree-antpbi] [encoding=\typescriptthree]
-
\loadmapfile[\typescriptthree-public-antp.map]
\stoptypescript
@@ -896,7 +840,6 @@
% maybe this will change in Iwona-Math-Letters and Iwona-Math-Letters-Italic
\starttypescript [sans] [iwona-light,iwona,iwona-medium,iwona-heavy,iwona-light-cond,iwona-cond,iwona-medium-cond,iwona-heavy-cond] [texnansi,ec,el,qx,t5]
-
\definefontsynonym[Iwona-Regular] [\typescriptthree-iwonar] [encoding=\typescriptthree]
\definefontsynonym[Iwona-Italic] [\typescriptthree-iwonari] [encoding=\typescriptthree]
\definefontsynonym[Iwona-Bold] [\typescriptthree-iwonab] [encoding=\typescriptthree]
@@ -907,7 +850,6 @@
\definefontsynonym[Iwona-Medium-Italic] [\typescriptthree-iwonami] [encoding=\typescriptthree]
\definefontsynonym[Iwona-Heavy-Regular] [\typescriptthree-iwonah] [encoding=\typescriptthree]
\definefontsynonym[Iwona-Heavy-Italic] [\typescriptthree-iwonahi] [encoding=\typescriptthree]
-
\definefontsynonym[Iwona-CapsRegular] [\typescriptthree-iwonarcap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsItalic] [\typescriptthree-iwonaricap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsBold] [\typescriptthree-iwonabcap] [encoding=\typescriptthree]
@@ -918,7 +860,6 @@
\definefontsynonym[Iwona-CapsMedium-Italic] [\typescriptthree-iwonamicap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsHeavy-Regular] [\typescriptthree-iwonahcap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsHeavy-Italic] [\typescriptthree-iwonahicap] [encoding=\typescriptthree]
-
\definefontsynonym[Iwona-CondRegular] [\typescriptthree-iwonacr] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CondItalic] [\typescriptthree-iwonacri] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CondBold] [\typescriptthree-iwonacb] [encoding=\typescriptthree]
@@ -929,7 +870,6 @@
\definefontsynonym[Iwona-CondMedium-Italic] [\typescriptthree-iwonacmi] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CondHeavy-Regular] [\typescriptthree-iwonach] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CondHeavy-Italic] [\typescriptthree-iwonachi] [encoding=\typescriptthree]
-
\definefontsynonym[Iwona-CapsCondRegular] [\typescriptthree-iwonacrcap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsCondItalic] [\typescriptthree-iwonacricap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsCondBold] [\typescriptthree-iwonacbcap] [encoding=\typescriptthree]
@@ -940,7 +880,6 @@
\definefontsynonym[Iwona-CapsCondMedium-Italic] [\typescriptthree-iwonacmicap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsCondHeavy-Regular] [\typescriptthree-iwonachcap] [encoding=\typescriptthree]
\definefontsynonym[Iwona-CapsCondHeavy-Italic] [\typescriptthree-iwonachicap] [encoding=\typescriptthree]
-
\loadmapfile[iwona-\typescriptthree.map]
\stoptypescript
@@ -973,6 +912,7 @@
\stoptypescript
\starttypescript [math] [iwona,iwona-light,iwona-medium,iwona-heavy] [default]
+ \usemathcollection[default]
\loadmapfile[iwona-rm.map]
\loadmapfile[iwona-mi.map]
\loadmapfile[iwona-sy.map]
@@ -981,21 +921,6 @@
% Kurier (JMN)
-% \starttypescript [sans] [kurier-light,kurier,kurier-medium] [texnansi,ec,qx,t5]
-% \definefontsynonym[Kurier-Regular] [\typescriptthree-kurierr] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Italic] [\typescriptthree-kurierri] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Bold] [\typescriptthree-kurierb] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-BoldItalic] [\typescriptthree-kurierbi] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Light-Regular] [\typescriptthree-kurierl] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Light-Italic] [\typescriptthree-kurierli] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Medium-Regular][\typescriptthree-kurierm] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Medium-Italic] [\typescriptthree-kuriermi] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Heavy-Regular] [\typescriptthree-kurierh] [encoding=\typescriptthree]
-% \definefontsynonym[Kurier-Heavy-Italic] [\typescriptthree-kurierhi] [encoding=\typescriptthree]
-
-% \loadmapfile[kurier-\typescriptthree.map]
-% \stoptypescript
-
\starttypescript [sans] [kurier-light,kurier,kurier-medium] [texnansi,ec,qx,t5]
\definefontsynonym[Kurier-Regular] [\typescriptthree-kurierr] [encoding=\typescriptthree]
\definefontsynonym[Kurier-Italic] [\typescriptthree-kurierri] [encoding=\typescriptthree]
@@ -1008,7 +933,6 @@
\definefontsynonym[Kurier-MediumItalic] [\typescriptthree-kuriermi] [encoding=\typescriptthree]
\definefontsynonym[Kurier-Heavy] [\typescriptthree-kurierh] [encoding=\typescriptthree]
\definefontsynonym[Kurier-HeavyItalic] [\typescriptthree-kurierhi] [encoding=\typescriptthree]
-
\loadmapfile[kurier-\typescriptthree.map]
\stoptypescript
@@ -1034,54 +958,105 @@
\stoptypescript
\starttypescript [math] [kurier,kurier-light,kurier-medium] [default]
+ \usemathcollection[default]
\loadmapfile[kurier-rm.map]
\loadmapfile[kurier-mi.map]
\loadmapfile[kurier-sy.map]
\loadmapfile[kurier-ex.map]
\stoptypescript
-% Palatino (URW)
-
-\starttypescript [serif] [palatino] [qx]
- \definefontsynonym [qx-uplr8a] [qplr] [encoding=qx]
- \definefontsynonym [qx-uplri8a] [qplri] [encoding=qx]
- \definefontsynonym [qx-uplb8a] [qplb] [encoding=qx]
- \definefontsynonym [qx-uplbi8a] [qplbi] [encoding=qx]
- \definefontsynonym [qx-uplr8a-slanted-167] [qplri] [encoding=qx]
- \definefontsynonym [qx-uplb8a-slanted-167] [qplbi] [encoding=qx]
- \definefontsynonym [qx-uplr8a-capitalized-800] [qplr] [encoding=qx]
+\starttypescript [kurier-light,kurier,kurier-medium] [texnansi,ec,qx,t5]
+ \definetypeface[\typescriptone][ss][sans] [\typescriptone] [default][encoding=\typescripttwo]
+ \definetypeface[\typescriptone][rm][serif][modern] [default][encoding=\typescripttwo]
+ \definetypeface[\typescriptone][tt][mono] [modern] [default][encoding=\typescripttwo,rscale=1.05]
+ \definetypeface[\typescriptone][mm][math] [\typescriptone] [default][encoding=\typescripttwo,text=ss]
+ \quittypescriptscanning
\stoptypescript
-\starttypescript [serif] [palatino] [texnansi,ec,8r,t5]
- \definefontsynonym [Palatino] [\typescriptthree-uplr8a] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Italic] [\typescriptthree-uplri8a] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Bold] [\typescriptthree-uplb8a] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-BoldItalic] [\typescriptthree-uplbi8a] [encoding=\typescriptthree]
+% Utopia (Adobe)
- \definefontsynonym [Palatino-Slanted] [\typescriptthree-uplr8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-BoldSlanted] [\typescriptthree-uplb8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Palatino-Caps] [\typescriptthree-uplr8a-capitalized-800] [encoding=\typescriptthree]
+\starttypescript [serif] [utopia] [ec,texnansi]
+ \definefontsynonym [Utopia-Regular] [\typescriptthree-putr8a] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-Italic] [\typescriptthree-putri8a] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-Bold] [\typescriptthree-putb8a] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-BoldItalic] [\typescriptthree-putbi8a] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-Slanted] [\typescriptthree-putr8a-slanted-167] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-BoldSlanted] [\typescriptthree-putb8a-slanted-167] [encoding=\typescriptthree]
+ \definefontsynonym [Utopia-Regular-Caps][\typescriptthree-putr8a-capitalized-800] [encoding=\typescriptthree]
+ \loadmapfile[\typescriptthree-adobe-utopia.map]
+\stoptypescript
- \loadmapfile[\typescriptthree-urw-palatino.map]
+% Charter (Bitstream)
+
+\starttypescript [serif] [charter] [ec,texnansi,8r]
+ \definefontsynonym [Charter-Roman] [\typescriptthree-bchr8a] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-Italic] [\typescriptthree-bchri8a] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-Bold] [\typescriptthree-bchb8a] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-BoldItalic] [\typescriptthree-bchbi8a] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-Slanted] [\typescriptthree-bchr8a-slanted-167] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-BoldSlanted][\typescriptthree-bchb8a-slanted-167] [encoding=\typescriptthree]
+ \definefontsynonym [Charter-Roman-Caps] [\typescriptthree-bchr8a-capitalized-800] [encoding=\typescriptthree]
+ \loadmapfile[\typescriptthree-bitstrea-charter.map]
\stoptypescript
-% bonus definitions
+% Whatever else we need:
+
+\starttypescript
+ \definefontsynonym [ZapfDingbats] [uzdr]
+ \definefontsynonym [RalfSmithFormalScript] [rsfs10]
+ \definefontsynonym [MartinVogel] [fmvr8x]
+\stoptypescript
-% when these fonts are in tex live ...
%
-% \definefontsynonym [Palatino-Caps] [TeXPalladioL-SC] [encoding=\typescriptthree]
+% TeXGyre
+%
+% We now use tex-gyre fonts by default ...
+
+\definetypescriptprefix [f:pagella] [pl] \definetypescriptprefix [f:palatino] [pl]
+\definetypescriptprefix [f:termes] [tm] \definetypescriptprefix [f:times] [tm]
+\definetypescriptprefix [f:heros] [hv] \definetypescriptprefix [f:helvetica] [hv]
+\definetypescriptprefix [f:bonum] [bk] \definetypescriptprefix [f:bookman] [bk]
+\definetypescriptprefix [f:schola] [cs] \definetypescriptprefix [f:schoolbook] [cs]
+\definetypescriptprefix [f:adventor][ag] %definetypescriptprefix [f:adventor] [ag]
+\definetypescriptprefix [f:cursor] [cr] \definetypescriptprefix [f:courier] [cr]
+\definetypescriptprefix [f:chorus] [zc] \definetypescriptprefix [f:chancery] [zc] % not the full set
-\starttypescript [serif] [palatino] [ec,texnansi,8r]
+\starttypescript [serif,sans,mono] [pagella,palatino,termes,times,adventor,bonum,bookman,cursor,courier,heros,helvetica,schola,schoolbook] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}r] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}ri] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}b] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}bi] [encoding=\typescriptthree]
+ \loadmapfile[q\typescriptprefix{f:\typescripttwo}-\typescriptthree.map]
+\stoptypescript
- \definefontsynonym[TeXPalladioL-BoldItalicOsF][\typescriptthree-fplbij8a][encoding=\typescriptthree]
- \definefontsynonym[TeXPalladioL-BoldOsF] [\typescriptthree-fplbj8a] [encoding=\typescriptthree]
- \definefontsynonym[TeXPalladioL-SC] [\typescriptthree-fplrc8a] [encoding=\typescriptthree]
- \definefontsynonym[TeXPalladioL-ItalicOsF] [\typescriptthree-fplrij8a][encoding=\typescriptthree]
+\starttypescript [serif,sans,mono] [pagella,palatino,termes,times,adventor,bonum,bookman,cursor,courier,heros,helvetica,schola,schoolbook] [ec,texnansi,cs,qx,rm,t5,l7x]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Caps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}r-sc] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}ri-sc] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}b-sc] [encoding=\typescriptthree]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [\typescriptthree-q\typescriptprefix{f:\typescripttwo}bi-sc] [encoding=\typescriptthree]
+ \loadmapfile[q\typescriptprefix{f:\typescripttwo}-\typescriptthree.map]
+\stoptypescript
- \loadmapfile[\typescriptthree-urw-palatino.map]
+\starttypescript [serif] [chorus,chancery] [ec,texnansi,cs,qx,rm,t5,t2a,t2b,t2c,l7x]
+ \definefontsynonym [TeXGyreChorus-MediumItalic] [\typescriptthree-qzcmi] [encoding=\typescriptthree]
+ \loadmapfile[qzc-\typescriptthree.map]
\stoptypescript
-% Palatino Math (PX)
+% bonus definitions
+
+% when these fonts are in tex live ...
+%
+% \definefontsynonym [Palatino-Caps] [TeXPalladioL-SC] [encoding=\typescriptthree]
+%
+% \starttypescript [serif] [palatino] [ec,texnansi]
+% \definefontsynonym[TeXPalladioL-BoldItalicOsF][\typescriptthree-fplbij8a][encoding=\typescriptthree]
+% \definefontsynonym[TeXPalladioL-BoldOsF] [\typescriptthree-fplbj8a] [encoding=\typescriptthree]
+% \definefontsynonym[TeXPalladioL-SC] [\typescriptthree-fplrc8a] [encoding=\typescriptthree]
+% \definefontsynonym[TeXPalladioL-ItalicOsF] [\typescriptthree-fplrij8a][encoding=\typescriptthree]
+% \loadmapfile[\typescriptthree-urw-palatino.map]
+% \stoptypescript
+
+% Palatino Math (px)
\starttypescript [math] [palatino] [all]
\definefontsynonym [Palatino-Roman-Upright] [pxr]
@@ -1099,93 +1074,110 @@
\definefontsynonym [Palatino-Math-SymbolsC] [pxsyc]
\definefontsynonym [Palatino-Math-Italic-A] [pxmia]
\definefontsynonym [Palatino-Math-Extension-A] [pxexa]
-
+ \usemathcollection[default]
\loadmapfile[original-youngryu-px.map]
\stoptypescript
-% Bookman (URW)
+% Times Math (tx)
-\starttypescript [serif] [bookman] [qx]
- \definefontsynonym [qx-ubkl8a] [qbkr] [encoding=qx]
- \definefontsynonym [qx-ubkli8a] [qbkri] [encoding=qx]
- \definefontsynonym [qx-ubkd8a] [qbkb] [encoding=qx]
- \definefontsynonym [qx-ubkdi8a] [qbkbi] [encoding=qx]
- \definefontsynonym [qx-ubkl8a-slanted-167] [qbkri] [encoding=qx]
- \definefontsynonym [qx-ubkd8a-slanted-167] [qbkbi] [encoding=qx]
- \definefontsynonym [qx-ubkl8a-capitalized-800] [qbkr] [encoding=qx]
+\starttypescript [math] [times] [all]
+ \definefontsynonym [Times-Roman-Upright] [txr]
+ \definefontsynonym [Times-Roman-Italic] [txi]
+ \definefontsynonym [Times-Roman-Slanted] [txsl]
+ \definefontsynonym [Times-Roman-Caps] [txsc]
+ \definefontsynonym [Times-Companion-Upright] [tcxr]
+ \definefontsynonym [Times-Companion-Italic] [tcxi]
+ \definefontsynonym [Times-Companion-Slanted] [tcxsl]
+ \definefontsynonym [Times-Math-Italic] [txmi]
+ \definefontsynonym [Times-Math-Symbols] [txsy]
+ \definefontsynonym [Times-Math-Extension] [txex]
+ \definefontsynonym [Times-Math-SymbolsA] [txsya]
+ \definefontsynonym [Times-Math-SymbolsB] [txsyb]
+ \definefontsynonym [Times-Math-SymbolsC] [txsyc]
+ \definefontsynonym [Times-Math-Italic-A] [txmia]
+ \definefontsynonym [Times-Math-Extension-A] [txexa]
+ \usemathcollection[default]
+ \loadmapfile[original-youngryu-tx.map]
\stoptypescript
-\starttypescript [serif] [bookman] [ec,texnansi,8r,t5]
- \definefontsynonym [Bookman-Light] [\typescriptthree-ubkl8a] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-LightItalic] [\typescriptthree-ubkli8a] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-DemiBold] [\typescriptthree-ubkd8a] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-DemiBoldItalic] [\typescriptthree-ubkdi8a] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-LightSlanted] [\typescriptthree-ubkl8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-DemiBoldSlanted] [\typescriptthree-ubkd8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Bookman-Light-Caps] [\typescriptthree-ubkl8a-capitalized-800] [encoding=\typescriptthree]
+%D These are just fallbacks in case anyone stil uses the old names (might also be removed?).
- \loadmapfile[\typescriptthree-urw-bookman.map]
+%
+% TeXGyrePagella
+%
+\starttypescript [serif] [palatino]
+ \definefontsynonym [Palatino] [TeXGyrePagella-Regular]
+ \definefontsynonym [Palatino-Italic] [TeXGyrePagella-Italic]
+ \definefontsynonym [Palatino-Bold] [TeXGyrePagella-Bold]
+ \definefontsynonym [Palatino-BoldItalic] [TeXGyrePagella-BoldItalic]
+ \definefontsynonym [Palatino-Slanted] [TeXGyrePagella-Italic]
+ \definefontsynonym [Palatino-BoldSlanted] [TeXGyrePagella-BoldItalic]
+ \definefontsynonym [Palatino-Caps] [TeXGyrePagella-Caps]
\stoptypescript
-
-% Chancery (URW)
-
-\starttypescript [calligraphy] [chancery] [qx]
- \definefontsynonym [qx-uzcmi8a] [qzcmi] [encoding=qx]
+%
+% TeXGyreTermes
+%
+\starttypescript [serif] [times]
+ \definefontsynonym [Times-Roman] [TeXGyreTermes-Regular]
+ \definefontsynonym [Times-Italic] [TeXGyreTermes-Italic]
+ \definefontsynonym [Times-Bold] [TeXGyreTermes-Bold]
+ \definefontsynonym [Times-BoldItalic] [TeXGyreTermes-BoldItalic]
+ \definefontsynonym [Times-Slanted] [TeXGyreTermes-Italic]
+ \definefontsynonym [Times-BoldSlanted] [TeXGyreTermes-BoldItalic]
+ \definefontsynonym [Times-Caps] [TeXGyreTermes-Caps]
\stoptypescript
-
-\starttypescript [calligraphy] [chancery] [ec,texnansi,8r]
- \definefontsynonym [Chancery] [\typescriptthree-uzcmi8a] [encoding=\typescriptthree]
- \loadmapfile[\typescriptthree-urw-zapfchan.map]
+%
+% TeXGyreHeros
+%
+\starttypescript [sans] [helvetica]
+ \definefontsynonym [Helvetica] [TeXGyreHeros-Regular]
+ \definefontsynonym [Helvetica-Oblique] [TeXGyreHeros-Italic]
+ \definefontsynonym [Helvetica-Bold] [TeXGyreHeros-Bold]
+ \definefontsynonym [Helvetica-BoldOblique] [TeXGyreHeros-BoldItalic]
+ \definefontsynonym [Helvetica-Caps] [TeXGyreHeros-Caps]
\stoptypescript
-
-% New Century Schoolbook (URW)
-
-\starttypescript [serif] [schoolbook] [ec,texnansi,8r,t5]
- \definefontsynonym [Schoolbook-Roman] [\typescriptthree-uncr8a] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Italic] [\typescriptthree-uncri8a] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Bold] [\typescriptthree-uncb8a] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-BoldItalic] [\typescriptthree-uncbi8a] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-RomanSlanted] [\typescriptthree-uncr8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-BoldSlanted] [\typescriptthree-uncb8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Schoolbook-Roman-Caps] [\typescriptthree-uncr8a-capitalized-800] [encoding=\typescriptthree]
-
- \loadmapfile[\typescriptthree-urw-ncntrsbk.map]
+%
+% TeXGyreBonum
+%
+\starttypescript [serif] [bookman]
+ \definefontsynonym [Bookman-Light] [TeXGyreBonum-Regular]
+ \definefontsynonym [Bookman-LightItalic] [TeXGyreBonum-Italic]
+ \definefontsynonym [Bookman-DemiBold] [TeXGyreBonum-Bold]
+ \definefontsynonym [Bookman-DemiBoldItalic] [TeXGyreBonum-BoldItalic]
+ \definefontsynonym [Bookman-LightSlanted] [TeXGyreBonum-Italic]
+ \definefontsynonym [Bookman-DemiBoldSlanted] [TeXGyreBonum-BoldItalic]
+ \definefontsynonym [Bookman-Light-Caps] [TeXGyreBonum-Caps]
\stoptypescript
-
-% Utopia (Adobe)
-
-\starttypescript [serif] [utopia] [ec,texnansi]
- \definefontsynonym [Utopia-Regular] [\typescriptthree-putr8a] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-Italic] [\typescriptthree-putri8a] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-Bold] [\typescriptthree-putb8a] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-BoldItalic] [\typescriptthree-putbi8a] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-Slanted] [\typescriptthree-putr8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-BoldSlanted] [\typescriptthree-putb8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Utopia-Regular-Caps][\typescriptthree-putr8a-capitalized-800] [encoding=\typescriptthree]
-
- \loadmapfile[\typescriptthree-adobe-utopia.map]
+%
+% TeXGyreScola
+%
+\starttypescript [serif] [schoolbook]
+ \definefontsynonym [Schoolbook-Roman] [TeXGyreScola-Regular]
+ \definefontsynonym [Schoolbook-Italic] [TeXGyreScola-Italic]
+ \definefontsynonym [Schoolbook-Bold] [TeXGyreScola-Bold]
+ \definefontsynonym [Schoolbook-BoldItalic] [TeXGyreScola-BoldItalic]
+ \definefontsynonym [Schoolbook-Slanted] [TeXGyreScola-Italic]
+ \definefontsynonym [Schoolbook-BoldSlanted] [TeXGyreScola-BoldItalic]
+ \definefontsynonym [Schoolbook-Roman-Caps] [TeXGyreScola-Caps]
\stoptypescript
-
-% Charter (Bitstream)
-
-\starttypescript [serif] [charter] [ec,texnansi,8r]
- \definefontsynonym [Charter-Roman] [\typescriptthree-bchr8a] [encoding=\typescriptthree]
- \definefontsynonym [Charter-Italic] [\typescriptthree-bchri8a] [encoding=\typescriptthree]
- \definefontsynonym [Charter-Bold] [\typescriptthree-bchb8a] [encoding=\typescriptthree]
- \definefontsynonym [Charter-BoldItalic] [\typescriptthree-bchbi8a] [encoding=\typescriptthree]
- \definefontsynonym [Charter-Slanted] [\typescriptthree-bchr8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Charter-BoldSlanted][\typescriptthree-bchb8a-slanted-167] [encoding=\typescriptthree]
- \definefontsynonym [Charter-Roman-Caps] [\typescriptthree-bchr8a-capitalized-800] [encoding=\typescriptthree]
-
- \loadmapfile[\typescriptthree-bitstrea-charter.map]
+%
+% TeXGyreAdventor
+%
+%
+% TeXGyreCursor
+%
+\starttypescript [mono] [courier]
+ \definefontsynonym [Courier] [TeXGyreCursor-Regular]
+ \definefontsynonym [Courier-Bold] [TeXGyreCursor-Bold]
+ \definefontsynonym [Courier-Oblique] [TeXGyreCursor-Italic]
+ \definefontsynonym [Courier-BoldOblique] [TeXGyreCursor-BoldItalic]
+ \fakecontrolspace
\stoptypescript
-
-% Whatever else we need:
-
-\starttypescript
- \definefontsynonym [ZapfDingbats] [uzdr]
- \definefontsynonym [RalfSmithFormalScript] [rsfs10]
- \definefontsynonym [MartinVogel] [fmvr8x]
+%
+% TeXGyreChorus
+%
+\starttypescript [calligraphy] [chancery]
+ \definefontsynonym [Chancery] [TeXGyreChorus-MediumItalic]
\stoptypescript
\stoptypescriptcollection
diff --git a/tex/context/base/type-otf.mkii b/tex/context/base/type-otf.mkii
new file mode 100644
index 000000000..869555688
--- /dev/null
+++ b/tex/context/base/type-otf.mkii
@@ -0,0 +1,535 @@
+%D \module
+%D [ file=type-otf,
+%D version=2007.07.30,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Opentype Definitions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Actually, \LUATEX\ does not need all these definitions since it can
+%D consult its database. However, here we use the names that we used
+%D in good old \TEX, and these may differ a bit. Here we also see
+%D some oldstyle definitions which normally are done with features.
+
+% if a fontname equals the filename, then use
+%
+% \setupfontsynonym [LMRoman10-DemiOblique] [features=default] % file is lowercase, so fails
+% \definefontsynonym [LMRoman10-DemiOblique] [name:LMRoman10-DemiOblique] [features=default]
+% \definefontsynonym [LMRoman10-DemiOblique] [lmroman10-demioblique] [features=default]
+
+\starttypescriptcollection[opentype]
+
+%D The names have changed (again) ... but I will not change the symbolic names
+%D any more. Filename changes will be catched in luatex (fallbacks) but not in
+%D other tex's.
+
+\starttypescript [serif] [modern,latin-modern]
+ \definefontsynonym [LMRoman5-Regular] [file:lmroman5-regular] [features=default]
+ \definefontsynonym [LMRoman6-Regular] [file:lmroman6-regular] [features=default]
+ \definefontsynonym [LMRoman7-Regular] [file:lmroman7-regular] [features=default]
+ \definefontsynonym [LMRoman8-Regular] [file:lmroman8-regular] [features=default]
+ \definefontsynonym [LMRoman9-Regular] [file:lmroman9-regular] [features=default]
+ \definefontsynonym [LMRoman10-Regular] [file:lmroman10-regular] [features=default]
+ \definefontsynonym [LMRoman12-Regular] [file:lmroman12-regular] [features=default]
+ \definefontsynonym [LMRoman17-Regular] [file:lmroman17-regular] [features=default]
+ \definefontsynonym [LMRoman5-Bold] [file:lmroman5-bold] [features=default]
+ \definefontsynonym [LMRoman6-Bold] [file:lmroman6-bold] [features=default]
+ \definefontsynonym [LMRoman7-Bold] [file:lmroman7-bold] [features=default]
+ \definefontsynonym [LMRoman8-Bold] [file:lmroman8-bold] [features=default]
+ \definefontsynonym [LMRoman9-Bold] [file:lmroman9-bold] [features=default]
+ \definefontsynonym [LMRoman10-Bold] [file:lmroman10-bold] [features=default]
+ \definefontsynonym [LMRoman12-Bold] [file:lmroman12-bold] [features=default]
+ \definefontsynonym [LMRoman7-Italic] [file:lmroman7-italic] [features=default]
+ \definefontsynonym [LMRoman8-Italic] [file:lmroman8-italic] [features=default]
+ \definefontsynonym [LMRoman9-Italic] [file:lmroman9-italic] [features=default]
+ \definefontsynonym [LMRoman10-Italic] [file:lmroman10-italic] [features=default]
+ \definefontsynonym [LMRoman12-Italic] [file:lmroman12-italic] [features=default]
+ \definefontsynonym [LMRoman10-BoldItalic] [file:lmroman10-bolditalic] [features=default]
+ \definefontsynonym [LMRoman8-Oblique] [file:lmromanslant8-regular] [features=default]
+ \definefontsynonym [LMRoman9-Oblique] [file:lmromanslant9-regular] [features=default]
+ \definefontsynonym [LMRoman10-Oblique] [file:lmromanslant10-regular][features=default]
+ \definefontsynonym [LMRoman12-Oblique] [file:lmromanslant12-regular][features=default]
+ \definefontsynonym [LMRoman17-Oblique] [file:lmromanslant17-regular][features=default]
+ \definefontsynonym [LMRoman10-BoldOblique] [file:lmromanslant10-bold] [features=default]
+ \definefontsynonym [LMRoman10-Demi] [file:lmromandemi10-regular] [features=default]
+ \definefontsynonym [LMRoman10-DemiOblique] [file:lmromandemi10-oblique] [features=default]
+ \definefontsynonym [LMRoman10-CapsRegular] [file:lmromancaps10-regular] [features=default] % features=smallcaps?
+ \definefontsynonym [LMRoman10-CapsOblique] [file:lmromancaps10-oblique] [features=default]
+
+ \definefontsynonym [LMRoman10-Dunhill] [file:lmromandunh10-regular] [features=default]
+ \definefontsynonym [LMRoman10-DunhillOblique] [file:lmromandunh10-oblique] [features=default]
+ \definefontsynonym [LMRoman10-Unslanted] [file:lmromanunsl10-regular] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [modern,latin-modern]
+ \definefontsynonym [LMSans8-Regular] [file:lmsans8-regular] [features=default]
+ \definefontsynonym [LMSans9-Regular] [file:lmsans9-regular] [features=default]
+ \definefontsynonym [LMSans10-Regular] [file:lmsans10-regular] [features=default]
+ \definefontsynonym [LMSans12-Regular] [file:lmsans12-regular] [features=default]
+ \definefontsynonym [LMSans17-Regular] [file:lmsans17-regular] [features=default]
+ \definefontsynonym [LMSans10-Bold] [file:lmsans10-bold] [features=default]
+ \definefontsynonym [LMSans8-Oblique] [file:lmsans8-oblique] [features=default]
+ \definefontsynonym [LMSans9-Oblique] [file:lmsans9-oblique] [features=default]
+ \definefontsynonym [LMSans10-Oblique] [file:lmsans10-oblique] [features=default]
+ \definefontsynonym [LMSans12-Oblique] [file:lmsans12-oblique] [features=default]
+ \definefontsynonym [LMSans17-Oblique] [file:lmsans17-oblique] [features=default]
+ \definefontsynonym [LMSans10-BoldOblique] [file:lmsans10-boldoblique] [features=default]
+
+ \definefontsynonym [LMSans10-DemiCondensed] [file:lmsansdemicond10-regular] [features=default]
+ \definefontsynonym [LMSans10-DemiCondensedOblique] [file:lmsansdemicond10-oblique] [features=default]
+
+ \definefontsynonym [LMSansQuotation8-Regular] [file:lmsansquot8-regular] [features=default]
+ \definefontsynonym [LMSansQuotation8-Bold] [file:lmsansquot8-bold] [features=default]
+ \definefontsynonym [LMSansQuotation8-Oblique] [file:lmsansquot8-oblique] [features=default]
+ \definefontsynonym [LMSansQuotation8-BoldOblique] [file:lmsansquot8-boldoblique] [features=default]
+\stoptypescript
+
+\starttypescript [mono] [modern,latin-modern,modern-vari,latin-modern-vari,modern-cond,latin-modern-cond]
+ \definefontsynonym [LMTypewriter8-Regular] [file:lmmono8-regular] [features=none]
+ \definefontsynonym [LMTypewriter9-Regular] [file:lmmono9-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-Regular] [file:lmmono10-regular] [features=none]
+ \definefontsynonym [LMTypewriter12-Regular] [file:lmmono12-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-Italic] [file:lmmono10-italic] [features=none]
+ \definefontsynonym [LMTypewriter10-Oblique] [file:lmmonoslant10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-CapsRegular] [file:lmmonocaps10-regular] [features=none] % features=smallcaps?
+ \definefontsynonym [LMTypewriter10-CapsOblique] [file:lmmonocaps10-oblique] [features=none]
+
+ \definefontsynonym [LMTypewriter10-Light] [file:lmmonolt10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-LightOblique] [file:lmmonolt10-oblique] [features=none]
+ \definefontsynonym [LMTypewriter10-LightCondensed] [file:lmmonoltcond10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-LightCondensedOblique] [file:lmmonoltcond10-oblique] [features=none]
+
+ \definefontsynonym [LMTypewriter10-Dark] [file:lmmonolt10-bold] [features=none]
+ \definefontsynonym [LMTypewriter10-DarkOblique] [file:lmmonolt10-boldoblique] [features=none]
+
+ \definefontsynonym [LMTypewriterVarWd10-Regular] [file:lmmonoproplt10-regular] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Oblique] [file:lmmonoproplt10-oblique] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Light] [file:lmmonoprop10-regular] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-LightOblique] [file:lmmonoprop10-oblique] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Dark] [file:lmmonoproplt10-bold] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-DarkOblique] [file:lmmonoproplt10-boldoblique] [features=default]
+\stoptypescript
+
+\starttypescript [math] [modern,latin-modern]
+ \definefontsynonym [LMMathRoman5-Regular] [rm-lmr5]
+ \definefontsynonym [LMMathRoman6-Regular] [rm-lmr6]
+ \definefontsynonym [LMMathRoman7-Regular] [rm-lmr7]
+ \definefontsynonym [LMMathRoman8-Regular] [rm-lmr8]
+ \definefontsynonym [LMMathRoman9-Regular] [rm-lmr9]
+ \definefontsynonym [LMMathRoman10-Regular] [rm-lmr10]
+ \definefontsynonym [LMMathRoman12-Regular] [rm-lmr12]
+ \definefontsynonym [LMMathRoman17-Regular] [rm-lmr17]
+ \definefontsynonym [LMMathRoman5-Bold] [rm-lmbx5]
+ \definefontsynonym [LMMathRoman6-Bold] [rm-lmbx6]
+ \definefontsynonym [LMMathRoman7-Bold] [rm-lmbx7]
+ \definefontsynonym [LMMathRoman8-Bold] [rm-lmbx8]
+ \definefontsynonym [LMMathRoman9-Bold] [rm-lmbx9]
+ \definefontsynonym [LMMathRoman10-Bold] [rm-lmbx10]
+ \definefontsynonym [LMMathRoman12-Bold] [rm-lmbx12]
+ \definefontsynonym [LMMathSymbols5-BoldItalic] [lmbsy5]
+ \definefontsynonym [LMMathSymbols7-BoldItalic] [lmbsy7]
+ \definefontsynonym [LMMathSymbols10-BoldItalic][lmbsy10]
+ \definefontsynonym [LMMathSymbols5-Italic] [lmsy5]
+ \definefontsynonym [LMMathSymbols6-Italic] [lmsy6]
+ \definefontsynonym [LMMathSymbols7-Italic] [lmsy7]
+ \definefontsynonym [LMMathSymbols8-Italic] [lmsy8]
+ \definefontsynonym [LMMathSymbols9-Italic] [lmsy9]
+ \definefontsynonym [LMMathSymbols10-Italic] [lmsy10]
+ \definefontsynonym [LMMathExtension10-Regular] [lmex10]
+ \definefontsynonym [LMMathItalic5-Italic] [lmmi5]
+ \definefontsynonym [LMMathItalic6-Italic] [lmmi6]
+ \definefontsynonym [LMMathItalic7-Italic] [lmmi7]
+ \definefontsynonym [LMMathItalic8-Italic] [lmmi8]
+ \definefontsynonym [LMMathItalic9-Italic] [lmmi9]
+ \definefontsynonym [LMMathItalic10-Italic] [lmmi10]
+ \definefontsynonym [LMMathItalic12-Italic] [lmmi12]
+ \definefontsynonym [LMMathItalic5-BoldItalic] [lmmib5]
+ \definefontsynonym [LMMathItalic7-BoldItalic] [lmmib7]
+ \definefontsynonym [LMMathItalic10-BoldItalic] [lmmib10]
+
+ \loadmapfile[lm-math.map]
+ \loadmapfile[lm-rm.map]
+\stoptypescript
+
+\starttypescript [math] [modern,computer-modern,latin-modern]
+ \definefontsynonym [ComputerModernMath-Roman] [rm-lmr10]
+ \definefontsynonym [ComputerModernMath-Extension] [lmex10]
+ \definefontsynonym [ComputerModernMath-Italic] [lmmi10]
+ \definefontsynonym [ComputerModernMath-Symbol] [lmsy10]
+\stoptypescript
+
+\starttypescript [boldmath,bfmath] [modern,computer-modern,latin-modern]
+ \definefontsynonym [ComputerModernMath-Roman-Bold] [rm-lmb10]
+ \definefontsynonym [ComputerModernMath-Extension] [lmex10]
+ \definefontsynonym [ComputerModernMath-Italic-Bold] [lmmib10]
+ \definefontsynonym [ComputerModernMath-Symbol-Bold] [lmbsy10]
+\stoptypescript
+
+% Computer Concrete (AMS)
+
+\starttypescript [serif] [concrete]
+ \definefontsynonym [ComputerConcrete] [ccr10]
+ \definefontsynonym [ComputerConcrete-Italic] [ccti10]
+ \definefontsynonym [ComputerConcrete-Slanted] [ccsl10]
+ \definefontsynonym [ComputerConcrete-Bold] [ComputerConcrete]
+ \definefontsynonym [ComputerConcrete-BoldItalic] [ComputerConcrete-Italic]
+ \definefontsynonym [ComputerConcrete-BoldSlanted] [ComputerConcrete-Slanted]
+ \definefontsynonym [ComputerConcrete-Caps] [cccsc10]
+\stoptypescript
+
+% Euler (AMS)
+
+\starttypescript [math] [euler]
+ \definefontsynonym [Euler-Roman] [zeurm10]
+ \definefontsynonym [Euler-Extension] [zeuex10]
+ \definefontsynonym [Euler-Symbol] [zeusm10]
+ \definefontsynonym [Euler-Fraktur] [eufm10]
+
+ \loadmapfile[original-ams-euler.map]
+\stoptypescript
+
+\starttypescript [boldmath,bfmath] [euler]
+ \definefontsynonym [Euler-Roman-Bold] [zeurb10]
+ \definefontsynonym [Euler-Extension] [zeuex10]
+ \definefontsynonym [Euler-Symbol-Bold] [zeusb10]
+ \definefontsynonym [Euler-Fraktur-Bold] [eufb10]
+
+ \loadmapfile[original-ams-euler.map]
+\stoptypescript
+
+% AMS (AMS)
+
+\starttypescript [math] [modern,computer-modern,latin-modern,ams]
+ \definefontsynonym [AMS-SymbolA] [msam10]
+ \definefontsynonym [AMS-SymbolB] [msbm10]
+\stoptypescript
+
+% TeXGyre
+
+\definetypescriptprefix [f:pagella] [pagella] \definetypescriptprefix [f:palatino] [pagella]
+\definetypescriptprefix [f:termes] [termes] \definetypescriptprefix [f:times] [termes]
+\definetypescriptprefix [f:heros] [heros] \definetypescriptprefix [f:helvetica] [heros]
+\definetypescriptprefix [f:bonum] [bonum] \definetypescriptprefix [f:bookman] [bonum]
+\definetypescriptprefix [f:schola] [schola] \definetypescriptprefix [f:schoolbook] [schola]
+\definetypescriptprefix [f:adventor][adventor] %definetypescriptprefix [f:adventor] [adventor]
+\definetypescriptprefix [f:cursor] [cursor] \definetypescriptprefix [f:courier] [cursor]
+\definetypescriptprefix [f:chorus] [chorus] \definetypescriptprefix [f:chancery] [chorus] % not the full set
+
+% name definitions & prefixes
+% \starttypescript [serif,sans,mono] [adventor,bonum,cursor,heros,pagella,palatino,schola,termes]
+% \starttypescript [serif] [pagella,palatino,termes,times,bonum,bookman,schola,schoolbook] [name]
+
+\starttypescript [serif,sans,mono] [adventor,bonum,bookman,cursor,courier,heros,helvetica,pagella,palatino,schola,schoolbook,termes,times]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Caps] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=smallcaps]
+\stoptypescript
+
+\starttypescript [serif,calligraphy] [chorus,chancery]
+ \definefontsynonym [TeXGyreChorus-MediumItalic] [file:texgyrechorus-mediumitalic] [features=default]
+\stoptypescript
+
+% Times Math (tx)
+
+\starttypescript [math] [times] [all]
+ \definefontsynonym [Times-Roman-Upright] [txr]
+ \definefontsynonym [Times-Roman-Italic] [txi]
+ \definefontsynonym [Times-Roman-Slanted] [txsl]
+ \definefontsynonym [Times-Roman-Caps] [txsc]
+ \definefontsynonym [Times-Companion-Upright] [tcxr]
+ \definefontsynonym [Times-Companion-Italic] [tcxi]
+ \definefontsynonym [Times-Companion-Slanted] [tcxsl]
+ \definefontsynonym [Times-Math-Italic] [txmi]
+ \definefontsynonym [Times-Math-Symbols] [txsy]
+ \definefontsynonym [Times-Math-Extension] [txex]
+ \definefontsynonym [Times-Math-SymbolsA] [txsya]
+ \definefontsynonym [Times-Math-SymbolsB] [txsyb]
+ \definefontsynonym [Times-Math-SymbolsC] [txsyc]
+ \definefontsynonym [Times-Math-Italic-A] [txmia]
+ \definefontsynonym [Times-Math-Extension-A] [txexa]
+
+ \loadmapfile[original-youngryu-tx.map]
+ \usemathcollection[default]
+\stoptypescript
+
+% Palatino Math (px)
+
+\starttypescript [math] [palatino] [all]
+ \definefontsynonym [Palatino-Roman-Upright] [pxr]
+ \definefontsynonym [Palatino-Roman-Italic] [pxi]
+ \definefontsynonym [Palatino-Roman-Slanted] [pxsl]
+ \definefontsynonym [Palatino-Roman-Caps] [pxsc]
+ \definefontsynonym [Palatino-Companion-Upright] [pcxr]
+ \definefontsynonym [Palatino-Companion-Italic] [pcxi]
+ \definefontsynonym [Palatino-Companion-Slanted] [pcxsl]
+ \definefontsynonym [Palatino-Math-Italic] [pxmi]
+ \definefontsynonym [Palatino-Math-Symbols] [pxsy]
+ \definefontsynonym [Palatino-Math-Extension] [pxex]
+ \definefontsynonym [Palatino-Math-SymbolsA] [pxsya]
+ \definefontsynonym [Palatino-Math-SymbolsB] [pxsyb]
+ \definefontsynonym [Palatino-Math-SymbolsC] [pxsyc]
+ \definefontsynonym [Palatino-Math-Italic-A] [pxmia]
+ \definefontsynonym [Palatino-Math-Extension-A] [pxexa]
+
+ \loadmapfile[original-youngryu-px.map]
+ \usemathcollection[default]
+\stoptypescript
+
+% Antykwa Torunska (GUST)
+
+\starttypescript [serif] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
+ \definefontsynonym [AntykwaTorunska-Regular] [file:AntykwaTorunska-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-Italic] [file:AntykwaTorunska-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Bold] [file:AntykwaTorunska-Bold] [features=default]
+ \definefontsynonym [AntykwaTorunska-BoldItalic] [file:AntykwaTorunska-BoldItalic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Light] [file:AntykwaTorunskaLight-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-LightItalic] [file:AntykwaTorunskaLight-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Medium] [file:AntykwaTorunskaMed-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-MedItalic] [file:AntykwaTorunskaMed-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondRegular] [file:AntykwaTorunskaCond-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondItalic] [file:AntykwaTorunskaCond-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondBold] [file:AntykwaTorunskaCond-Bold] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondBoldItalic] [file:AntykwaTorunskaCond-BoldItalic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondLight] [file:AntykwaTorunskaCondLight-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondLightItalic] [file:AntykwaTorunskaCondLight-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondMedium] [file:AntykwaTorunskaCondMed-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondMedItalic] [file:AntykwaTorunskaCondMed-Italic] [features=default]
+
+ \definefontsynonym [AntykwaTorunska-Cap] [file:AntykwaTorunska-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-ItalicCap] [file:AntykwaTorunska-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-BoldCap] [file:AntykwaTorunska-Bold] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-BoldItalicCap] [file:AntykwaTorunska-BoldItalic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-LightCap] [file:AntykwaTorunskaLight-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-LightItalicCap] [file:AntykwaTorunskaLight-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-MediumCap] [file:AntykwaTorunskaMed-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-MedItalicCap] [file:AntykwaTorunskaMed-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondCap] [file:AntykwaTorunskaCond-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondItalicCap] [file:AntykwaTorunskaCond-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondBoldCap] [file:AntykwaTorunskaCond-Bold] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondBoldItalicCap] [file:AntykwaTorunskaCond-BoldItalic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondLightCap] [file:AntykwaTorunskaCondLight-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondLightItalicCap][file:AntykwaTorunskaCondLight-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondMediumCap] [file:AntykwaTorunskaCondMed-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondMedItalicCap] [file:AntykwaTorunskaCondMed-Italic] [features=smallcaps]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Regular] [rm-anttr]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Italic] [mi-anttri]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-Regular] [sy-anttrz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-Regular] [ex-anttr]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-light] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Light] [rm-anttl]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-LightItalic] [mi-anttli]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-Light] [sy-anttlz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-Light] [ex-anttl]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-cond] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondRegular] [rm-anttcr]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondItalic] [mi-anttcri]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-CondRegular] [sy-anttcrz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-CondRegular] [ex-anttcr]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-lightcond] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondLight] [rm-anttcl]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondLightItalic] [mi-anttcli]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-CondLight] [sy-anttclz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-CondLight] [ex-anttcl]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
+ \usemathcollection[default]
+ \loadmapfile[antt-rm.map]
+ \loadmapfile[antt-mi.map]
+ \loadmapfile[antt-sy.map]
+ \loadmapfile[antt-ex.map]
+\stoptypescript
+
+% Antykwa Poltawskiego (GUST)
+
+\starttypescript [serif] [antykwa-poltawskiego]
+ \definefontsynonym [AntykwaPoltawskiego-Regular] [antpr]
+ \definefontsynonym [AntykwaPoltawskiego-Bold] [antpb]
+ \definefontsynonym [AntykwaPoltawskiego-Italic] [antpri]
+ \definefontsynonym [AntykwaPoltawskiego-BoldItalic] [antpbi]
+\stoptypescript
+
+% Iwona (JMN)
+
+% maybe this will change in Iwona-Math-Letters and Iwona-Math-Letters-Italic
+
+% These names are a depressing mess. They have changed over time and are
+% still not consistent. I'd expect Bold-Regular and Bold-Italic.
+
+\starttypescript [sans] [iwona-light,iwona,iwona-medium,iwona-heavy,iwona-light-cond,iwona-cond,iwona-medium-cond,iwona-heavy-cond]
+
+ \definefontsynonym [Iwona-Regular] [file:Iwona-Regular] [features=default]
+ \definefontsynonym [Iwona-Italic] [file:Iwona-Italic] [features=default]
+ \definefontsynonym [Iwona-Bold] [file:Iwona-Bold] [features=default]
+ \definefontsynonym [Iwona-BoldItalic] [file:Iwona-BoldItalic] [features=default]
+ \definefontsynonym [Iwona-Light-Regular] [file:IwonaLight-Regular] [features=default]
+ \definefontsynonym [Iwona-Light-Italic] [file:IwonaLight-Italic] [features=default]
+ \definefontsynonym [Iwona-Medium-Regular] [file:IwonaMedium-Regular] [features=default]
+ \definefontsynonym [Iwona-Medium-Italic] [file:IwonaMedium-Italic] [features=default]
+ \definefontsynonym [Iwona-Heavy-Regular] [file:IwonaHeavy-Regular] [features=default]
+ \definefontsynonym [Iwona-Heavy-Italic] [file:IwonaHeavy-Italic] [features=default]
+
+ \definefontsynonym [Iwona-CapsRegular] [file:Iwona-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsItalic] [file:Iwona-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsBold] [file:Iwona-Bold] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsBoldItalic] [file:Iwona-BoldItalic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsLight] [file:IwonaLight-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsLight-Italic] [file:IwonaLight-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsMedium] [file:IwonaMedium-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsMedium-Italic] [file:IwonaMedium-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsHeavy] [file:IwonaHeavy-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsHeavy-Italic] [file:IwonaHeavy-Italic] [features=smallcaps]
+
+ \definefontsynonym [Iwona-CondRegular] [file:IwonaCond-Regular] [features=default]
+ \definefontsynonym [Iwona-CondItalic] [file:IwonaCond-Italic] [features=default]
+ \definefontsynonym [Iwona-CondBold] [file:IwonaCond-Bold] [features=default]
+ \definefontsynonym [Iwona-CondBoldItalic] [file:IwonaCond-BoldItalic] [features=default]
+ \definefontsynonym [Iwona-CondLight-Regular] [file:IwonaCondLight-Regular] [features=default]
+ \definefontsynonym [Iwona-CondLight-Italic] [file:IwonaCondLight-Italic] [features=default]
+ \definefontsynonym [Iwona-CondMedium-Regular] [file:IwonaCondMedium-Regular] [features=default]
+ \definefontsynonym [Iwona-CondMedium-Italic] [file:IwonaCondMedium-Italic] [features=default]
+ \definefontsynonym [Iwona-CondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=default]
+ \definefontsynonym [Iwona-CondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=default]
+
+ \definefontsynonym [Iwona-CapsCondRegular] [file:IwonaCond-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondItalic] [file:IwonaCond-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondBold] [file:IwonaCond-Bold] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondBoldItalic] [file:IwonaCond-BoldItalic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondLight-Regular] [file:IwonaCondLight-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondLight-Italic] [file:IwonaCondLight-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondMedium-Regular][file:IwonaCondMedium-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondMedium-Italic] [file:IwonaCondMedium-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=smallcaps]
+
+\stoptypescript
+
+\starttypescript [math] [iwona] [default]
+ \definefontsynonym [Iwona-Math-Letters-Regular] [rm-iwonar]
+ \definefontsynonym [Iwona-Math-Letters-Italic] [mi-iwonari]
+ \definefontsynonym [Iwona-Math-Symbols-Regular] [sy-iwonarz]
+ \definefontsynonym [Iwona-Math-Extension-Regular] [ex-iwonar]
+\stoptypescript
+
+\starttypescript [math] [iwona-light] [default]
+ \definefontsynonym [Iwona-Math-Letters-Light-Regular] [rm-iwonal]
+ \definefontsynonym [Iwona-Math-Letters-Light-Italic] [mi-iwonali]
+ \definefontsynonym [Iwona-Math-Symbols-Light] [sy-iwonalz]
+ \definefontsynonym [Iwona-Math-Extension-Light] [ex-iwonal]
+\stoptypescript
+
+\starttypescript [math] [iwona-medium] [default]
+ \definefontsynonym [Iwona-Math-Letters-Medium-Regular][rm-iwonam]
+ \definefontsynonym [Iwona-Math-Letters-Medium-Italic] [mi-iwonami]
+ \definefontsynonym [Iwona-Math-Symbols-Medium] [sy-iwonamz]
+ \definefontsynonym [Iwona-Math-Extension-Medium] [ex-iwonam]
+\stoptypescript
+
+\starttypescript [math] [iwona-heavy] [default]
+ \definefontsynonym [Iwona-Math-Letters-Heavy-Regular] [rm-iwonah]
+ \definefontsynonym [Iwona-Math-Letters-Heavy-Italic] [mi-iwonahi]
+ \definefontsynonym [Iwona-Math-Symbols-Heavy] [sy-iwonahz]
+ \definefontsynonym [Iwona-Math-Extension-Heavy] [ex-iwonah]
+\stoptypescript
+
+\starttypescript [math] [iwona,iwona-light,iwona-medium,iwona-heavy] [default]
+ \usemathcollection[default]
+ \loadmapfile[iwona-rm.map]
+ \loadmapfile[iwona-mi.map]
+ \loadmapfile[iwona-sy.map]
+ \loadmapfile[iwona-ex.map]
+\stoptypescript
+
+% Kurier (JMN) / no open type fonts
+
+\starttypescript [sans] [kurier-light,kurier,kurier-medium]
+ \definefontsynonym[Kurier-Light] [kurierl]
+ \definefontsynonym[Kurier-Regular] [kurierr]
+ \definefontsynonym[Kurier-Medium] [kurierm]
+ \definefontsynonym[Kurier-Bold] [kurierb]
+ \definefontsynonym[Kurier-Heavy] [kurierh]
+ \definefontsynonym[Kurier-LightItalic] [kurierli]
+ \definefontsynonym[Kurier-Italic] [kurierri]
+ \definefontsynonym[Kurier-MediumItalic] [kuriermi]
+ \definefontsynonym[Kurier-BoldItalic] [kurierbi]
+ \definefontsynonym[Kurier-HeavyItalic] [kurierhi]
+\stoptypescript
+
+\starttypescript [math] [kurier] [default]
+ \definefontsynonym [Kurier-Math-Letters-Regular] [rm-kurierr]
+ \definefontsynonym [Kurier-Math-Letters-Italic] [mi-kurierri]
+ \definefontsynonym [Kurier-Math-Symbols-Regular] [sy-kurierrz]
+ \definefontsynonym [Kurier-Math-Extension-Regular] [ex-kurierr]
+\stoptypescript
+
+\starttypescript [math] [kurier-light] [default]
+ \definefontsynonym [Kurier-Math-Letters-Light-Regular] [rm-kurierl]
+ \definefontsynonym [Kurier-Math-Letters-Light-Italic] [mi-kurierli]
+ \definefontsynonym [Kurier-Math-Symbols-Light] [sy-kurierlz]
+ \definefontsynonym [Kurier-Math-Extension-Light] [ex-kurierl]
+\stoptypescript
+
+\starttypescript [math] [kurier-medium] [default]
+ \definefontsynonym [Kurier-Math-Letters-Medium-Regular] [rm-kurierm]
+ \definefontsynonym [Kurier-Math-Letters-Medium-Italic] [mi-kuriermi]
+ \definefontsynonym [Kurier-Math-Symbols-Medium-Regular] [sy-kuriermz]
+ \definefontsynonym [Kurier-Math-Extension-Medium] [ex-kurierm]
+\stoptypescript
+
+\starttypescript [math] [kurier,kurier-light,kurier-medium] [default]
+ \loadmapfile[kurier-rm.map]
+ \loadmapfile[kurier-mi.map]
+ \loadmapfile[kurier-sy.map]
+ \loadmapfile[kurier-ex.map]
+\stoptypescript
+
+\starttypescript [iwona,iwona-light,iwona-medium,iwona-heavy]
+ \definetypeface[\typescriptone][ss][sans] [\typescriptone] [default]
+ \definetypeface[\typescriptone][rm][serif][modern] [default]
+ \definetypeface[\typescriptone][tt][mono] [modern] [default][rscale=1.05]
+ \definetypeface[\typescriptone][mm][math] [\typescriptone] [default][text=ss]
+ \quittypescriptscanning
+\stoptypescript
+
+% Whatever else we need:
+
+\starttypescript
+ \definefontsynonym [ZapfDingbats] [uzdr]
+ \definefontsynonym [RalfSmithFormalScript] [rsfs10]
+ \definefontsynonym [MartinVogel] [fmvr8x]
+\stoptypescript
+
+% Temp here
+
+\starttypescript [serif] [charter]
+ \definefontsynonym [Charter-Roman] [name:CharterBT-Roman] % or: [bchr8a]
+ \definefontsynonym [Charter-Italic] [name:CharterBT-Italic] % or: [bchri8a]
+ \definefontsynonym [Charter-Bold] [name:CharterBT-Bold] % or: [bchb8a]
+ \definefontsynonym [Charter-BoldItalic] [name:CharterBT-BoldItalic] % or: [bchbi8a]
+ \definefontsynonym [Charter-Slanted] [name:CharterBT-Italic] % or: [bchri8a]
+ \definefontsynonym [Charter-BoldSlanted] [name:CharterBT-BoldItalic] % or: [bchbi8a]
+ \definefontsynonym [Charter-Roman-Caps] [Charter-Roman] % not present
+\stoptypescript
+
+\stoptypescriptcollection
+
+\endinput
diff --git a/tex/context/base/type-otf.mkiv b/tex/context/base/type-otf.mkiv
new file mode 100644
index 000000000..09ec22856
--- /dev/null
+++ b/tex/context/base/type-otf.mkiv
@@ -0,0 +1,628 @@
+%D \module
+%D [ file=type-otf,
+%D version=2007.07.30,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Opentype Definitions,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D Actually, \LUATEX\ does not need all these definitions since it can
+%D consult its database. However, here we use the names that we used
+%D in good old \TEX, and these may differ a bit. Here we also see
+%D some oldstyle definitions which normally are done with features.
+
+% if a fontname equals the filename, then use
+%
+% \setupfontsynonym [LMRoman10-DemiOblique] [features=default] % file is lowercase, so fails
+% \definefontsynonym [LMRoman10-DemiOblique] [name:LMRoman10-DemiOblique] [features=default]
+% \definefontsynonym [LMRoman10-DemiOblique] [lmroman10-demioblique] [features=default]
+
+\starttypescriptcollection[opentype]
+
+%D The names have changed (again) ... but I will not change the symbolic names
+%D any more. Filename changes will be catched in luatex (fallbacks) but not in
+%D other tex's.
+
+\starttypescript [serif] [modern,latin-modern]
+ \definefontsynonym [LMRoman5-Regular] [file:lmroman5-regular] [features=default]
+ \definefontsynonym [LMRoman6-Regular] [file:lmroman6-regular] [features=default]
+ \definefontsynonym [LMRoman7-Regular] [file:lmroman7-regular] [features=default]
+ \definefontsynonym [LMRoman8-Regular] [file:lmroman8-regular] [features=default]
+ \definefontsynonym [LMRoman9-Regular] [file:lmroman9-regular] [features=default]
+ \definefontsynonym [LMRoman10-Regular] [file:lmroman10-regular] [features=default]
+ \definefontsynonym [LMRoman12-Regular] [file:lmroman12-regular] [features=default]
+ \definefontsynonym [LMRoman17-Regular] [file:lmroman17-regular] [features=default]
+ \definefontsynonym [LMRoman5-Bold] [file:lmroman5-bold] [features=default]
+ \definefontsynonym [LMRoman6-Bold] [file:lmroman6-bold] [features=default]
+ \definefontsynonym [LMRoman7-Bold] [file:lmroman7-bold] [features=default]
+ \definefontsynonym [LMRoman8-Bold] [file:lmroman8-bold] [features=default]
+ \definefontsynonym [LMRoman9-Bold] [file:lmroman9-bold] [features=default]
+ \definefontsynonym [LMRoman10-Bold] [file:lmroman10-bold] [features=default]
+ \definefontsynonym [LMRoman12-Bold] [file:lmroman12-bold] [features=default]
+ \definefontsynonym [LMRoman7-Italic] [file:lmroman7-italic] [features=default]
+ \definefontsynonym [LMRoman8-Italic] [file:lmroman8-italic] [features=default]
+ \definefontsynonym [LMRoman9-Italic] [file:lmroman9-italic] [features=default]
+ \definefontsynonym [LMRoman10-Italic] [file:lmroman10-italic] [features=default]
+ \definefontsynonym [LMRoman12-Italic] [file:lmroman12-italic] [features=default]
+ \definefontsynonym [LMRoman10-BoldItalic] [file:lmroman10-bolditalic] [features=default]
+ \definefontsynonym [LMRoman8-Oblique] [file:lmromanslant8-regular] [features=default]
+ \definefontsynonym [LMRoman9-Oblique] [file:lmromanslant9-regular] [features=default]
+ \definefontsynonym [LMRoman10-Oblique] [file:lmromanslant10-regular][features=default]
+ \definefontsynonym [LMRoman12-Oblique] [file:lmromanslant12-regular][features=default]
+ \definefontsynonym [LMRoman17-Oblique] [file:lmromanslant17-regular][features=default]
+ \definefontsynonym [LMRoman10-BoldOblique] [file:lmromanslant10-bold] [features=default]
+ \definefontsynonym [LMRoman10-Demi] [file:lmromandemi10-regular] [features=default]
+ \definefontsynonym [LMRoman10-DemiOblique] [file:lmromandemi10-oblique] [features=default]
+ \definefontsynonym [LMRoman10-CapsRegular] [file:lmromancaps10-regular] [features=default] % features=smallcaps?
+ \definefontsynonym [LMRoman10-CapsOblique] [file:lmromancaps10-oblique] [features=default]
+
+ \definefontsynonym [LMRoman10-Dunhill] [file:lmromandunh10-regular] [features=default]
+ \definefontsynonym [LMRoman10-DunhillOblique] [file:lmromandunh10-oblique] [features=default]
+ \definefontsynonym [LMRoman10-Unslanted] [file:lmromanunsl10-regular] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [modern,latin-modern]
+ \definefontsynonym [LMSans8-Regular] [file:lmsans8-regular] [features=default]
+ \definefontsynonym [LMSans9-Regular] [file:lmsans9-regular] [features=default]
+ \definefontsynonym [LMSans10-Regular] [file:lmsans10-regular] [features=default]
+ \definefontsynonym [LMSans12-Regular] [file:lmsans12-regular] [features=default]
+ \definefontsynonym [LMSans17-Regular] [file:lmsans17-regular] [features=default]
+ \definefontsynonym [LMSans10-Bold] [file:lmsans10-bold] [features=default]
+ \definefontsynonym [LMSans8-Oblique] [file:lmsans8-oblique] [features=default]
+ \definefontsynonym [LMSans9-Oblique] [file:lmsans9-oblique] [features=default]
+ \definefontsynonym [LMSans10-Oblique] [file:lmsans10-oblique] [features=default]
+ \definefontsynonym [LMSans12-Oblique] [file:lmsans12-oblique] [features=default]
+ \definefontsynonym [LMSans17-Oblique] [file:lmsans17-oblique] [features=default]
+ \definefontsynonym [LMSans10-BoldOblique] [file:lmsans10-boldoblique] [features=default]
+
+ \definefontsynonym [LMSans10-DemiCondensed] [file:lmsansdemicond10-regular] [features=default]
+ \definefontsynonym [LMSans10-DemiCondensedOblique] [file:lmsansdemicond10-oblique] [features=default]
+
+ \definefontsynonym [LMSansQuotation8-Regular] [file:lmsansquot8-regular] [features=default]
+ \definefontsynonym [LMSansQuotation8-Bold] [file:lmsansquot8-bold] [features=default]
+ \definefontsynonym [LMSansQuotation8-Oblique] [file:lmsansquot8-oblique] [features=default]
+ \definefontsynonym [LMSansQuotation8-BoldOblique] [file:lmsansquot8-boldoblique] [features=default]
+\stoptypescript
+
+\starttypescript [mono] [modern,latin-modern,modern-vari,latin-modern-vari,modern-cond,latin-modern-cond]
+ \definefontsynonym [LMTypewriter8-Regular] [file:lmmono8-regular] [features=none]
+ \definefontsynonym [LMTypewriter9-Regular] [file:lmmono9-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-Regular] [file:lmmono10-regular] [features=none]
+ \definefontsynonym [LMTypewriter12-Regular] [file:lmmono12-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-Italic] [file:lmmono10-italic] [features=none]
+ \definefontsynonym [LMTypewriter10-Oblique] [file:lmmonoslant10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-CapsRegular] [file:lmmonocaps10-regular] [features=none] % features=smallcaps?
+ \definefontsynonym [LMTypewriter10-CapsOblique] [file:lmmonocaps10-oblique] [features=none]
+
+ \definefontsynonym [LMTypewriter10-Light] [file:lmmonolt10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-LightOblique] [file:lmmonolt10-oblique] [features=none]
+ \definefontsynonym [LMTypewriter10-LightCondensed] [file:lmmonoltcond10-regular] [features=none]
+ \definefontsynonym [LMTypewriter10-LightCondensedOblique] [file:lmmonoltcond10-oblique] [features=none]
+
+ \definefontsynonym [LMTypewriter10-Dark] [file:lmmonolt10-bold] [features=none]
+ \definefontsynonym [LMTypewriter10-DarkOblique] [file:lmmonolt10-boldoblique] [features=none]
+
+ \definefontsynonym [LMTypewriterVarWd10-Regular] [file:lmmonoproplt10-regular] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Oblique] [file:lmmonoproplt10-oblique] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Light] [file:lmmonoprop10-regular] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-LightOblique] [file:lmmonoprop10-oblique] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-Dark] [file:lmmonoproplt10-bold] [features=default]
+ \definefontsynonym [LMTypewriterVarWd10-DarkOblique] [file:lmmonoproplt10-boldoblique] [features=default]
+\stoptypescript
+
+% \starttypescript [math] [modern,latin-modern]
+% \definefontsynonym [LMMathRoman5-Regular] [rm-lmr5]
+% \definefontsynonym [LMMathRoman6-Regular] [rm-lmr6]
+% \definefontsynonym [LMMathRoman7-Regular] [rm-lmr7]
+% \definefontsynonym [LMMathRoman8-Regular] [rm-lmr8]
+% \definefontsynonym [LMMathRoman9-Regular] [rm-lmr9]
+% \definefontsynonym [LMMathRoman10-Regular] [rm-lmr10]
+% \definefontsynonym [LMMathRoman12-Regular] [rm-lmr12]
+% \definefontsynonym [LMMathRoman17-Regular] [rm-lmr17]
+% \definefontsynonym [LMMathRoman5-Bold] [rm-lmbx5]
+% \definefontsynonym [LMMathRoman6-Bold] [rm-lmbx6]
+% \definefontsynonym [LMMathRoman7-Bold] [rm-lmbx7]
+% \definefontsynonym [LMMathRoman8-Bold] [rm-lmbx8]
+% \definefontsynonym [LMMathRoman9-Bold] [rm-lmbx9]
+% \definefontsynonym [LMMathRoman10-Bold] [rm-lmbx10]
+% \definefontsynonym [LMMathRoman12-Bold] [rm-lmbx12]
+% \definefontsynonym [LMMathSymbols5-BoldItalic] [lmbsy5]
+% \definefontsynonym [LMMathSymbols7-BoldItalic] [lmbsy7]
+% \definefontsynonym [LMMathSymbols10-BoldItalic][lmbsy10]
+% \definefontsynonym [LMMathSymbols5-Italic] [lmsy5]
+% \definefontsynonym [LMMathSymbols6-Italic] [lmsy6]
+% \definefontsynonym [LMMathSymbols7-Italic] [lmsy7]
+% \definefontsynonym [LMMathSymbols8-Italic] [lmsy8]
+% \definefontsynonym [LMMathSymbols9-Italic] [lmsy9]
+% \definefontsynonym [LMMathSymbols10-Italic] [lmsy10]
+% \definefontsynonym [LMMathExtension10-Regular] [lmex10]
+% \definefontsynonym [LMMathItalic5-Italic] [lmmi5]
+% \definefontsynonym [LMMathItalic6-Italic] [lmmi6]
+% \definefontsynonym [LMMathItalic7-Italic] [lmmi7]
+% \definefontsynonym [LMMathItalic8-Italic] [lmmi8]
+% \definefontsynonym [LMMathItalic9-Italic] [lmmi9]
+% \definefontsynonym [LMMathItalic10-Italic] [lmmi10]
+% \definefontsynonym [LMMathItalic12-Italic] [lmmi12]
+% \definefontsynonym [LMMathItalic5-BoldItalic] [lmmib5]
+% \definefontsynonym [LMMathItalic7-BoldItalic] [lmmib7]
+% \definefontsynonym [LMMathItalic10-BoldItalic] [lmmib10]
+% \loadmapfile[lm-math.map]
+% \loadmapfile[lm-rm.map]
+% \stoptypescript
+
+% \starttypescript [math] [modern,computer-modern,latin-modern]
+% \definefontsynonym [ComputerModernMath-Roman] [rm-lmr10]
+% \definefontsynonym [ComputerModernMath-Extension] [lmex10]
+% \definefontsynonym [ComputerModernMath-Italic] [lmmi10]
+% \definefontsynonym [ComputerModernMath-Symbol] [lmsy10]
+% \stoptypescript
+
+% \starttypescript [boldmath,bfmath] [modern,computer-modern,latin-modern]
+% \definefontsynonym [ComputerModernMath-Roman-Bold] [rm-lmb10]
+% \definefontsynonym [ComputerModernMath-Extension] [lmex10]
+% \definefontsynonym [ComputerModernMath-Italic-Bold] [lmmib10]
+% \definefontsynonym [ComputerModernMath-Symbol-Bold] [lmbsy10]
+% \stoptypescript
+
+\starttypescript [math] [modern,latin-modern,computer-modern]
+ \definefontsynonym[LMMathRoman5-Regular] [LMMath5-Regular@lmroman5-math]
+ \definefontsynonym[LMMathRoman6-Regular] [LMMath6-Regular@lmroman6-math]
+ \definefontsynonym[LMMathRoman7-Regular] [LMMath7-Regular@lmroman7-math]
+ \definefontsynonym[LMMathRoman8-Regular] [LMMath8-Regular@lmroman8-math]
+ \definefontsynonym[LMMathRoman9-Regular] [LMMath9-Regular@lmroman9-math]
+ \definefontsynonym[LMMathRoman10-Regular][LMMath10-Regular@lmroman10-math]
+ \definefontsynonym[LMMathRoman12-Regular][LMMath12-Regular@lmroman12-math]
+ \definefontsynonym[LMMathRoman17-Regular][LMMath17-Regular@lmroman17-math]
+
+% \definefontsynonym[LMMathRoman-Regular] [LMMath10-Regular@lmroman10-math]
+
+ \definefontsynonym[MathRoman] [LMMath10-Regular@lmroman10-math]
+
+ \definefontsynonym[xcmr12][LMMath12-Regular@lmroman12-math]
+ \definefontsynonym[xcmr10][LMMath10-Regular@lmroman10-math]
+ \definefontsynonym[xcmr9] [LMMath9-Regular@lmroman9-math]
+ \definefontsynonym[xcmr8] [LMMath8-Regular@lmroman8-math]
+ \definefontsynonym[xcmr7] [LMMath7-Regular@lmroman7-math]
+ \definefontsynonym[xcmr6] [LMMath6-Regular@lmroman6-math]
+ \definefontsynonym[xcmr5] [LMMath5-Regular@lmroman5-math]
+
+ \loadmapfile[lm-math.map]
+ \loadmapfile[lm-rm.map]
+\stoptypescript
+
+% Euler (AMS)
+
+\starttypescript [math] [euler]
+ \definefontsynonym [Euler-Roman] [zeurm10]
+ \definefontsynonym [Euler-Extension] [zeuex10]
+ \definefontsynonym [Euler-Symbol] [zeusm10]
+ \definefontsynonym [Euler-Fraktur] [eufm10]
+
+ \loadmapfile[original-ams-euler.map]
+\stoptypescript
+
+\starttypescript [boldmath,bfmath] [euler]
+ \definefontsynonym [Euler-Roman-Bold] [zeurb10]
+ \definefontsynonym [Euler-Extension] [zeuex10]
+ \definefontsynonym [Euler-Symbol-Bold] [zeusb10]
+ \definefontsynonym [Euler-Fraktur-Bold] [eufb10]
+
+ \loadmapfile[original-ams-euler.map]
+\stoptypescript
+
+% AMS (AMS)
+
+\starttypescript [math] [modern,computer-modern,latin-modern,ams]
+ \definefontsynonym [AMS-SymbolA] [msam10]
+ \definefontsynonym [AMS-SymbolB] [msbm10]
+\stoptypescript
+
+% TeXGyre
+
+\definetypescriptprefix [f:pagella] [pagella] \definetypescriptprefix [f:palatino] [pagella]
+\definetypescriptprefix [f:termes] [termes] \definetypescriptprefix [f:times] [termes]
+\definetypescriptprefix [f:heros] [heros] \definetypescriptprefix [f:helvetica] [heros]
+\definetypescriptprefix [f:bonum] [bonum] \definetypescriptprefix [f:bookman] [bonum]
+\definetypescriptprefix [f:schola] [schola] \definetypescriptprefix [f:schoolbook] [schola]
+\definetypescriptprefix [f:adventor][adventor] %definetypescriptprefix [f:adventor] [adventor]
+\definetypescriptprefix [f:cursor] [cursor] \definetypescriptprefix [f:courier] [cursor]
+\definetypescriptprefix [f:chorus] [chorus] \definetypescriptprefix [f:chancery] [chorus] % not the full set
+
+% name definitions & prefixes
+% \starttypescript [serif,sans,mono] [adventor,bonum,cursor,heros,pagella,palatino,schola,termes]
+% \starttypescript [serif] [pagella,palatino,termes,times,bonum,bookman,schola,schoolbook] [name]
+
+\starttypescript [serif,sans,mono] [adventor,bonum,bookman,cursor,courier,heros,helvetica,pagella,palatino,schola,schoolbook,termes,times]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=default]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Caps] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=smallcaps]
+ \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=smallcaps]
+\stoptypescript
+
+\starttypescript [serif,calligraphy] [chorus,chancery]
+ \definefontsynonym [TeXGyreChorus-MediumItalic] [file:texgyrechorus-mediumitalic] [features=default]
+\stoptypescript
+
+% Times Math (tx)
+
+% \starttypescript [math] [times] [all]
+% \definefontsynonym [Times-Roman-Upright] [txr]
+% \definefontsynonym [Times-Roman-Italic] [txi]
+% \definefontsynonym [Times-Roman-Slanted] [txsl]
+% \definefontsynonym [Times-Roman-Caps] [txsc]
+% \definefontsynonym [Times-Companion-Upright] [tcxr]
+% \definefontsynonym [Times-Companion-Italic] [tcxi]
+% \definefontsynonym [Times-Companion-Slanted] [tcxsl]
+% \definefontsynonym [Times-Math-Italic] [txmi]
+% \definefontsynonym [Times-Math-Symbols] [txsy]
+% \definefontsynonym [Times-Math-Extension] [txex]
+% \definefontsynonym [Times-Math-SymbolsA] [txsya]
+% \definefontsynonym [Times-Math-SymbolsB] [txsyb]
+% \definefontsynonym [Times-Math-SymbolsC] [txsyc]
+% \definefontsynonym [Times-Math-Italic-A] [txmia]
+% \definefontsynonym [Times-Math-Extension-A] [txexa]
+% \loadmapfile[original-youngryu-tx.map]
+% \usemathcollection[default]
+% \stoptypescript
+
+\starttypescript [math][times][all]
+ \definefontsynonym[MathRoman][txmath@tx-math]
+ \loadmapfile[original-youngryu-tx.map]
+\stoptypescript
+
+% Palatino Math (px)
+
+% \starttypescript [math] [palatino] [all]
+% \definefontsynonym [Palatino-Roman-Upright] [pxr]
+% \definefontsynonym [Palatino-Roman-Italic] [pxi]
+% \definefontsynonym [Palatino-Roman-Slanted] [pxsl]
+% \definefontsynonym [Palatino-Roman-Caps] [pxsc]
+% \definefontsynonym [Palatino-Companion-Upright] [pcxr]
+% \definefontsynonym [Palatino-Companion-Italic] [pcxi]
+% \definefontsynonym [Palatino-Companion-Slanted] [pcxsl]
+% \definefontsynonym [Palatino-Math-Italic] [pxmi]
+% \definefontsynonym [Palatino-Math-Symbols] [pxsy]
+% \definefontsynonym [Palatino-Math-Extension] [pxex]
+% \definefontsynonym [Palatino-Math-SymbolsA] [pxsya]
+% \definefontsynonym [Palatino-Math-SymbolsB] [pxsyb]
+% \definefontsynonym [Palatino-Math-SymbolsC] [pxsyc]
+% \definefontsynonym [Palatino-Math-Italic-A] [pxmia]
+% \definefontsynonym [Palatino-Math-Extension-A] [pxexa]
+% \loadmapfile[original-youngryu-px.map]
+% \usemathcollection[default]
+% \stoptypescript
+
+\starttypescript [math][palatino][all]
+ \definefontsynonym[MathRoman][pxmath@px-math]
+ \loadmapfile[original-youngryu-px.map]
+\stoptypescript
+
+% Antykwa Torunska (GUST)
+
+\starttypescript [serif] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
+ \definefontsynonym [AntykwaTorunska-Regular] [file:AntykwaTorunska-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-Italic] [file:AntykwaTorunska-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Bold] [file:AntykwaTorunska-Bold] [features=default]
+ \definefontsynonym [AntykwaTorunska-BoldItalic] [file:AntykwaTorunska-BoldItalic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Light] [file:AntykwaTorunskaLight-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-LightItalic] [file:AntykwaTorunskaLight-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-Medium] [file:AntykwaTorunskaMed-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-MedItalic] [file:AntykwaTorunskaMed-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondRegular] [file:AntykwaTorunskaCond-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondItalic] [file:AntykwaTorunskaCond-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondBold] [file:AntykwaTorunskaCond-Bold] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondBoldItalic] [file:AntykwaTorunskaCond-BoldItalic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondLight] [file:AntykwaTorunskaCondLight-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondLightItalic] [file:AntykwaTorunskaCondLight-Italic] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondMedium] [file:AntykwaTorunskaCondMed-Regular] [features=default]
+ \definefontsynonym [AntykwaTorunska-CondMedItalic] [file:AntykwaTorunskaCondMed-Italic] [features=default]
+
+ \definefontsynonym [AntykwaTorunska-Cap] [file:AntykwaTorunska-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-ItalicCap] [file:AntykwaTorunska-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-BoldCap] [file:AntykwaTorunska-Bold] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-BoldItalicCap] [file:AntykwaTorunska-BoldItalic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-LightCap] [file:AntykwaTorunskaLight-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-LightItalicCap] [file:AntykwaTorunskaLight-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-MediumCap] [file:AntykwaTorunskaMed-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-MedItalicCap] [file:AntykwaTorunskaMed-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondCap] [file:AntykwaTorunskaCond-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondItalicCap] [file:AntykwaTorunskaCond-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondBoldCap] [file:AntykwaTorunskaCond-Bold] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondBoldItalicCap] [file:AntykwaTorunskaCond-BoldItalic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondLightCap] [file:AntykwaTorunskaCondLight-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondLightItalicCap][file:AntykwaTorunskaCondLight-Italic] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondMediumCap] [file:AntykwaTorunskaCondMed-Regular] [features=smallcaps]
+ \definefontsynonym [AntykwaTorunska-CondMedItalicCap] [file:AntykwaTorunskaCondMed-Italic] [features=smallcaps]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Regular] [rm-anttr]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Italic] [mi-anttri]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-Regular] [sy-anttrz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-Regular] [ex-anttr]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-light] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-Light] [rm-anttl]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-LightItalic] [mi-anttli]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-Light] [sy-anttlz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-Light] [ex-anttl]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-cond] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondRegular] [rm-anttcr]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondItalic] [mi-anttcri]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-CondRegular] [sy-anttcrz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-CondRegular] [ex-anttcr]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska-lightcond] [default]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondLight] [rm-anttcl]
+ \definefontsynonym [AntykwaTorunska-Math-Letters-CondLightItalic] [mi-anttcli]
+ \definefontsynonym [AntykwaTorunska-Math-Symbols-CondLight] [sy-anttclz]
+ \definefontsynonym [AntykwaTorunska-Math-Extension-CondLight] [ex-anttcl]
+\stoptypescript
+
+\starttypescript [math] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
+ \usemathcollection[default]
+ \loadmapfile[antt-rm.map]
+ \loadmapfile[antt-mi.map]
+ \loadmapfile[antt-sy.map]
+ \loadmapfile[antt-ex.map]
+\stoptypescript
+
+% Antykwa Poltawskiego (GUST)
+
+\starttypescript [serif] [antykwa-poltawskiego]
+ \definefontsynonym [AntykwaPoltawskiego-Regular] [antpr]
+ \definefontsynonym [AntykwaPoltawskiego-Bold] [antpb]
+ \definefontsynonym [AntykwaPoltawskiego-Italic] [antpri]
+ \definefontsynonym [AntykwaPoltawskiego-BoldItalic] [antpbi]
+\stoptypescript
+
+% Iwona (JMN)
+
+% maybe this will change in Iwona-Math-Letters and Iwona-Math-Letters-Italic
+
+% These names are a depressing mess. They have changed over time and are
+% still not consistent. I'd expect Bold-Regular and Bold-Italic.
+
+\starttypescript [sans] [iwona-light,iwona,iwona-medium,iwona-heavy,iwona-light-cond,iwona-cond,iwona-medium-cond,iwona-heavy-cond]
+
+ \definefontsynonym [Iwona-Regular] [file:Iwona-Regular] [features=default]
+ \definefontsynonym [Iwona-Italic] [file:Iwona-Italic] [features=default]
+ \definefontsynonym [Iwona-Bold] [file:Iwona-Bold] [features=default]
+ \definefontsynonym [Iwona-BoldItalic] [file:Iwona-BoldItalic] [features=default]
+ \definefontsynonym [Iwona-Light-Regular] [file:IwonaLight-Regular] [features=default]
+ \definefontsynonym [Iwona-Light-Italic] [file:IwonaLight-Italic] [features=default]
+ \definefontsynonym [Iwona-Medium-Regular] [file:IwonaMedium-Regular] [features=default]
+ \definefontsynonym [Iwona-Medium-Italic] [file:IwonaMedium-Italic] [features=default]
+ \definefontsynonym [Iwona-Heavy-Regular] [file:IwonaHeavy-Regular] [features=default]
+ \definefontsynonym [Iwona-Heavy-Italic] [file:IwonaHeavy-Italic] [features=default]
+
+ \definefontsynonym [Iwona-CapsRegular] [file:Iwona-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsItalic] [file:Iwona-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsBold] [file:Iwona-Bold] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsBoldItalic] [file:Iwona-BoldItalic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsLight] [file:IwonaLight-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsLight-Italic] [file:IwonaLight-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsMedium] [file:IwonaMedium-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsMedium-Italic] [file:IwonaMedium-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsHeavy] [file:IwonaHeavy-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsHeavy-Italic] [file:IwonaHeavy-Italic] [features=smallcaps]
+
+ \definefontsynonym [Iwona-CondRegular] [file:IwonaCond-Regular] [features=default]
+ \definefontsynonym [Iwona-CondItalic] [file:IwonaCond-Italic] [features=default]
+ \definefontsynonym [Iwona-CondBold] [file:IwonaCond-Bold] [features=default]
+ \definefontsynonym [Iwona-CondBoldItalic] [file:IwonaCond-BoldItalic] [features=default]
+ \definefontsynonym [Iwona-CondLight-Regular] [file:IwonaCondLight-Regular] [features=default]
+ \definefontsynonym [Iwona-CondLight-Italic] [file:IwonaCondLight-Italic] [features=default]
+ \definefontsynonym [Iwona-CondMedium-Regular] [file:IwonaCondMedium-Regular] [features=default]
+ \definefontsynonym [Iwona-CondMedium-Italic] [file:IwonaCondMedium-Italic] [features=default]
+ \definefontsynonym [Iwona-CondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=default]
+ \definefontsynonym [Iwona-CondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=default]
+
+ \definefontsynonym [Iwona-CapsCondRegular] [file:IwonaCond-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondItalic] [file:IwonaCond-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondBold] [file:IwonaCond-Bold] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondBoldItalic] [file:IwonaCond-BoldItalic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondLight-Regular] [file:IwonaCondLight-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondLight-Italic] [file:IwonaCondLight-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondMedium-Regular][file:IwonaCondMedium-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondMedium-Italic] [file:IwonaCondMedium-Italic] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=smallcaps]
+ \definefontsynonym [Iwona-CapsCondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=smallcaps]
+
+\stoptypescript
+
+% \starttypescript [math] [iwona] [default]
+% \definefontsynonym [Iwona-Math-Letters-Regular] [rm-iwonar]
+% \definefontsynonym [Iwona-Math-Letters-Italic] [mi-iwonari]
+% \definefontsynonym [Iwona-Math-Symbols-Regular] [sy-iwonarz]
+% \definefontsynonym [Iwona-Math-Extension-Regular] [ex-iwonar]
+% \stoptypescript
+
+% \starttypescript [math] [iwona-light] [default]
+% \definefontsynonym [Iwona-Math-Letters-Light-Regular] [rm-iwonal]
+% \definefontsynonym [Iwona-Math-Letters-Light-Italic] [mi-iwonali]
+% \definefontsynonym [Iwona-Math-Symbols-Light] [sy-iwonalz]
+% \definefontsynonym [Iwona-Math-Extension-Light] [ex-iwonal]
+% \stoptypescript
+
+% \starttypescript [math] [iwona-medium] [default]
+% \definefontsynonym [Iwona-Math-Letters-Medium-Regular][rm-iwonam]
+% \definefontsynonym [Iwona-Math-Letters-Medium-Italic] [mi-iwonami]
+% \definefontsynonym [Iwona-Math-Symbols-Medium] [sy-iwonamz]
+% \definefontsynonym [Iwona-Math-Extension-Medium] [ex-iwonam]
+% \stoptypescript
+
+% \starttypescript [math] [iwona-heavy] [default]
+% \definefontsynonym [Iwona-Math-Letters-Heavy-Regular] [rm-iwonah]
+% \definefontsynonym [Iwona-Math-Letters-Heavy-Italic] [mi-iwonahi]
+% \definefontsynonym [Iwona-Math-Symbols-Heavy] [sy-iwonahz]
+% \definefontsynonym [Iwona-Math-Extension-Heavy] [ex-iwonah]
+% \stoptypescript
+
+% [all] is redundant
+
+\starttypescript [math][iwona][all]
+ \definefontsynonym[MathRoman][iwonamath@iwona-math]
+\stoptypescript
+\starttypescript [math][iwona-light][all]
+ \definefontsynonym[MathRoman][iwonalightmath@iwona-light-math]
+\stoptypescript
+\starttypescript [math][iwona-medium][all]
+ \definefontsynonym[MathRoman][iwonamediummath@iwona-medium-math]
+\stoptypescript
+\starttypescript [math][iwona-heavy][all]
+ \definefontsynonym[MathRoman][iwonaheavymath@iwona-heavy-math]
+\stoptypescript
+
+\starttypescript [math] [iwona,iwona-light,iwona-medium,iwona-heavy] [all]
+ \loadmapfile[iwona-rm.map]
+ \loadmapfile[iwona-mi.map]
+ \loadmapfile[iwona-sy.map]
+ \loadmapfile[iwona-ex.map]
+\stoptypescript
+
+% Kurier (JMN) / no open type fonts
+
+\starttypescript [sans] [kurier-light,kurier,kurier-medium]
+ \definefontsynonym[Kurier-Light] [kurierl]
+ \definefontsynonym[Kurier-Regular] [kurierr]
+ \definefontsynonym[Kurier-Medium] [kurierm]
+ \definefontsynonym[Kurier-Bold] [kurierb]
+ \definefontsynonym[Kurier-Heavy] [kurierh]
+ \definefontsynonym[Kurier-LightItalic] [kurierli]
+ \definefontsynonym[Kurier-Italic] [kurierri]
+ \definefontsynonym[Kurier-MediumItalic] [kuriermi]
+ \definefontsynonym[Kurier-BoldItalic] [kurierbi]
+ \definefontsynonym[Kurier-HeavyItalic] [kurierhi]
+\stoptypescript
+
+\starttypescript [math] [kurier] [default]
+ \definefontsynonym [Kurier-Math-Letters-Regular] [rm-kurierr]
+ \definefontsynonym [Kurier-Math-Letters-Italic] [mi-kurierri]
+ \definefontsynonym [Kurier-Math-Symbols-Regular] [sy-kurierrz]
+ \definefontsynonym [Kurier-Math-Extension-Regular] [ex-kurierr]
+\stoptypescript
+
+\starttypescript [math] [kurier-light] [default]
+ \definefontsynonym [Kurier-Math-Letters-Light-Regular] [rm-kurierl]
+ \definefontsynonym [Kurier-Math-Letters-Light-Italic] [mi-kurierli]
+ \definefontsynonym [Kurier-Math-Symbols-Light] [sy-kurierlz]
+ \definefontsynonym [Kurier-Math-Extension-Light] [ex-kurierl]
+\stoptypescript
+
+\starttypescript [math] [kurier-medium] [default]
+ \definefontsynonym [Kurier-Math-Letters-Medium-Regular] [rm-kurierm]
+ \definefontsynonym [Kurier-Math-Letters-Medium-Italic] [mi-kuriermi]
+ \definefontsynonym [Kurier-Math-Symbols-Medium-Regular] [sy-kuriermz]
+ \definefontsynonym [Kurier-Math-Extension-Medium] [ex-kurierm]
+\stoptypescript
+
+\starttypescript [math] [kurier,kurier-light,kurier-medium] [default]
+ \loadmapfile[kurier-rm.map]
+ \loadmapfile[kurier-mi.map]
+ \loadmapfile[kurier-sy.map]
+ \loadmapfile[kurier-ex.map]
+\stoptypescript
+
+\starttypescript [iwona,iwona-light,iwona-medium,iwona-heavy]
+ \definetypeface[\typescriptone][ss][sans] [\typescriptone] [default]
+ \definetypeface[\typescriptone][rm][serif][modern] [default]
+ \definetypeface[\typescriptone][tt][mono] [modern] [default][rscale=1.05]
+ \definetypeface[\typescriptone][mm][math] [\typescriptone] [default][text=ss]
+ \quittypescriptscanning
+\stoptypescript
+
+% Whatever else we need:
+
+\starttypescript
+ \definefontsynonym [ZapfDingbats] [uzdr]
+ \definefontsynonym [RalfSmithFormalScript] [rsfs10]
+ \definefontsynonym [MartinVogel] [fmvr8x]
+\stoptypescript
+
+% Temp here
+
+\starttypescript [serif] [charter]
+ \definefontsynonym [Charter-Roman] [name:CharterBT-Roman] % or: [bchr8a]
+ \definefontsynonym [Charter-Italic] [name:CharterBT-Italic] % or: [bchri8a]
+ \definefontsynonym [Charter-Bold] [name:CharterBT-Bold] % or: [bchb8a]
+ \definefontsynonym [Charter-BoldItalic] [name:CharterBT-BoldItalic] % or: [bchbi8a]
+ \definefontsynonym [Charter-Slanted] [name:CharterBT-Italic] % or: [bchri8a]
+ \definefontsynonym [Charter-BoldSlanted] [name:CharterBT-BoldItalic] % or: [bchbi8a]
+ \definefontsynonym [Charter-Roman-Caps] [Charter-Roman] % not present
+\stoptypescript
+
+% new
+
+% cambria.ttc cambriab.ttf cambriai.ttf cambriaz.ttf
+
+\starttypescript [math] [cambria] [name]
+ \definefontsynonym [MathRoman] [name:cambriamath] [features=math\mathsizesuffix]
+\stoptypescript
+\starttypescript [math] [cambria-x] [name]
+ \definefontsynonym [MathRoman] [name:cambriamath] [features=math]
+\stoptypescript
+\starttypescript [math] [cambria-y] [name]
+ \definefontsynonym [MathRoman] [name:cambriamath] [features=math-nostack\mathsizesuffix]
+\stoptypescript
+
+\starttypescript [serif] [cambria] [name]
+ \usetypescript[fallback:serif]
+ \definefontsynonym [Serif] [name:cambria] [features=default]
+ \definefontsynonym [SerifBold] [name:cambriabold] [features=default]
+ \definefontsynonym [SerifItalic] [name:cambriaitalic] [features=default]
+ \definefontsynonym [SerifBoldItalic] [name:cambriabolditalic] [features=default]
+\stoptypescript
+
+\starttypescript [cambria]
+ \definetypeface [cambria] [rm] [serif] [cambria] [default]
+ \definetypeface [cambria] [tt] [mono] [modern] [default]
+ \definetypeface [cambria] [mm] [math] [cambria] [default]
+\stoptypescript
+
+\starttypescript [cambria-x]
+ \definetypeface [cambria-x] [rm] [serif] [cambria] [default]
+ \definetypeface [cambria-x] [tt] [mono] [modern] [default]
+ \definetypeface [cambria-x] [mm] [math] [cambria-x] [default]
+\stoptypescript
+
+\starttypescript [cambria-y]
+ \definetypeface [cambria-y] [rm] [serif] [cambria] [default]
+ \definetypeface [cambria-y] [tt] [mono] [modern] [default]
+ \definetypeface [cambria-y] [mm] [math] [cambria-y] [default]
+\stoptypescript
+
+% math times
+
+\starttypescript [math] [mathtimes] [all]
+ \definefontsynonym[MathRoman][mathtimes@mathtimes-math]
+ \loadmapfile[mathtime.map]
+% \pdfmapline{=mtsyn < mtsyn.pfb}
+% \pdfmapline{=mtmiz < mtmiz.pfb}
+% \pdfmapline{=mtex < mtex.pfb}
+\stoptypescript
+
+\starttypescript [mathtimes]
+ \definetypeface [mathtimes] [rm] [serif] [times] [default]
+ \definetypeface [mathtimes] [ss] [sans] [helvetica] [default] [rscale=0.9]
+ \definetypeface [mathtimes] [tt] [mono] [modern] [default] [rscale=1.05]
+ \definetypeface [mathtimes] [mm] [math] [mathtimes] [default]
+ \quittypescriptscanning
+\stoptypescript
+
+\stoptypescriptcollection
+
+\endinput
diff --git a/tex/context/base/type-otf.tex b/tex/context/base/type-otf.tex
index 29dee2e74..720ffbaf9 100644
--- a/tex/context/base/type-otf.tex
+++ b/tex/context/base/type-otf.tex
@@ -26,6 +26,16 @@
\quittypescriptscanning
\stoptypescript
+% faster
+%
+% \starttypescript [fallback]
+% \definetypeface [] [rm] [serif] [modern] [default]
+% \definetypeface [] [ss] [sans] [modern] [default]
+% \definetypeface [] [tt] [mono] [modern] [default]
+% \definetypeface [] [mm] [math] [modern] [default]
+% \quittypescriptscanning
+% \stoptypescript
+
\starttypescript [modern]
\definetypeface [modern] [rm] [serif] [modern] [computer-modern]
\definetypeface [modern] [ss] [sans] [modern] [computer-modern]
@@ -44,25 +54,25 @@
\starttypescript [postscript]
\definetypeface [postscript] [rm] [serif] [times] [default]
- \definetypeface [postscript] [ss] [sans] [helvetica] [default] [rscale=.9]
+ \definetypeface [postscript] [ss] [sans] [helvetica] [default] [rscale=0.9]
\definetypeface [postscript] [tt] [mono] [courier] [default] [rscale=1.1]
\definetypeface [postscript] [mm] [math] [times] [default]
\quittypescriptscanning
\stoptypescript
-\starttypescript [times]
- \definetypeface [times] [rm] [serif] [times] [default]
- \definetypeface [times] [ss] [sans] [helvetica] [default] [rscale=0.9]
- \definetypeface [times] [tt] [mono] [modern] [default] [rscale=1.05]
- \definetypeface [times] [mm] [math] [times] [default]
+\starttypescript [times,termes]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [helvetica] [default] [rscale=0.9]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [rscale=1.05]
+ \definetypeface [\typescriptone] [mm] [math] [times] [default]
\quittypescriptscanning
\stoptypescript
-\starttypescript [palatino]
- \definetypeface [palatino] [rm] [serif] [palatino] [default]
- \definetypeface [palatino] [ss] [sans] [modern] [default] [rscale=1.075]
- \definetypeface [palatino] [tt] [mono] [modern] [default] [rscale=1.075]
- \definetypeface [palatino] [mm] [math] [palatino] [default]
+\starttypescript [palatino,pagella]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default] [rscale=1.075]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [rscale=1.075]
+ \definetypeface [\typescriptone] [mm] [math] [palatino] [default]
\quittypescriptscanning
\stoptypescript
@@ -82,685 +92,64 @@
\quittypescriptscanning
\stoptypescript
-\starttypescript [iwona,iwona-light,iwona-heavy,iwona-medium]
- \definetypeface[\typescriptone][ss][sans] [\typescriptone] [default]
- \definetypeface[\typescriptone][rm][serif][modern] [default]
- \definetypeface[\typescriptone][tt][mono] [modern] [default]
- \definetypeface[\typescriptone][mm][math] [\typescriptone] [default][text=ss]
+\starttypescript [schoolbook,schola]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default]
\quittypescriptscanning
\stoptypescript
-\stoptypescriptcollection
-
-% if a fontname equals the filename, then use
-%
-% \setupfontsynonym [LMRoman10-DemiOblique] [features=default] % file is lowercase, so fails
-% \definefontsynonym [LMRoman10-DemiOblique] [name:LMRoman10-DemiOblique] [features=default]
-% \definefontsynonym [LMRoman10-DemiOblique] [lmroman10-demioblique] [features=default]
-
-\starttypescriptcollection[opentype]
-
-%D The names have changed (again) ... but I will not change the symbolic names
-%D any more. Filename changes will be catched in luatex (fallbacks) but not in
-%D other tex's.
-
-\starttypescript [serif] [modern,latin-modern]
- \definefontsynonym [LMRoman5-Regular] [file:lmroman5-regular] [features=default]
- \definefontsynonym [LMRoman6-Regular] [file:lmroman6-regular] [features=default]
- \definefontsynonym [LMRoman7-Regular] [file:lmroman7-regular] [features=default]
- \definefontsynonym [LMRoman8-Regular] [file:lmroman8-regular] [features=default]
- \definefontsynonym [LMRoman9-Regular] [file:lmroman9-regular] [features=default]
- \definefontsynonym [LMRoman10-Regular] [file:lmroman10-regular] [features=default]
- \definefontsynonym [LMRoman12-Regular] [file:lmroman12-regular] [features=default]
- \definefontsynonym [LMRoman17-Regular] [file:lmroman17-regular] [features=default]
- \definefontsynonym [LMRoman5-Bold] [file:lmroman5-bold] [features=default]
- \definefontsynonym [LMRoman6-Bold] [file:lmroman6-bold] [features=default]
- \definefontsynonym [LMRoman7-Bold] [file:lmroman7-bold] [features=default]
- \definefontsynonym [LMRoman8-Bold] [file:lmroman8-bold] [features=default]
- \definefontsynonym [LMRoman9-Bold] [file:lmroman9-bold] [features=default]
- \definefontsynonym [LMRoman10-Bold] [file:lmroman10-bold] [features=default]
- \definefontsynonym [LMRoman12-Bold] [file:lmroman12-bold] [features=default]
- \definefontsynonym [LMRoman7-Italic] [file:lmroman7-italic] [features=default]
- \definefontsynonym [LMRoman8-Italic] [file:lmroman8-italic] [features=default]
- \definefontsynonym [LMRoman9-Italic] [file:lmroman9-italic] [features=default]
- \definefontsynonym [LMRoman10-Italic] [file:lmroman10-italic] [features=default]
- \definefontsynonym [LMRoman12-Italic] [file:lmroman12-italic] [features=default]
- \definefontsynonym [LMRoman10-BoldItalic] [file:lmroman10-bolditalic] [features=default]
- \definefontsynonym [LMRoman8-Oblique] [file:lmromanslant8-regular] [features=default]
- \definefontsynonym [LMRoman9-Oblique] [file:lmromanslant9-regular] [features=default]
- \definefontsynonym [LMRoman10-Oblique] [file:lmromanslant10-regular][features=default]
- \definefontsynonym [LMRoman12-Oblique] [file:lmromanslant12-regular][features=default]
- \definefontsynonym [LMRoman17-Oblique] [file:lmromanslant17-regular][features=default]
- \definefontsynonym [LMRoman10-BoldOblique] [file:lmromanslant10-bold] [features=default]
- \definefontsynonym [LMRoman10-Demi] [file:lmromandemi10-regular] [features=default]
- \definefontsynonym [LMRoman10-DemiOblique] [file:lmromandemi10-oblique] [features=default]
- \definefontsynonym [LMRoman10-CapsRegular] [file:lmromancaps10-regular] [features=default] % features=smallcaps?
- \definefontsynonym [LMRoman10-CapsOblique] [file:lmromancaps10-oblique] [features=default]
-
- \definefontsynonym [LMRoman10-Dunhill] [file:lmromandunh10-regular] [features=default]
- \definefontsynonym [LMRoman10-DunhillOblique] [file:lmromandunh10-oblique] [features=default]
- \definefontsynonym [LMRoman10-Unslanted] [file:lmromanunsl10-regular] [features=default]
-\stoptypescript
-
-\starttypescript [sans] [modern,latin-modern]
- \definefontsynonym [LMSans8-Regular] [file:lmsans8-regular] [features=default]
- \definefontsynonym [LMSans9-Regular] [file:lmsans9-regular] [features=default]
- \definefontsynonym [LMSans10-Regular] [file:lmsans10-regular] [features=default]
- \definefontsynonym [LMSans12-Regular] [file:lmsans12-regular] [features=default]
- \definefontsynonym [LMSans17-Regular] [file:lmsans17-regular] [features=default]
- \definefontsynonym [LMSans10-Bold] [file:lmsans10-bold] [features=default]
- \definefontsynonym [LMSans8-Oblique] [file:lmsans8-oblique] [features=default]
- \definefontsynonym [LMSans9-Oblique] [file:lmsans9-oblique] [features=default]
- \definefontsynonym [LMSans10-Oblique] [file:lmsans10-oblique] [features=default]
- \definefontsynonym [LMSans12-Oblique] [file:lmsans12-oblique] [features=default]
- \definefontsynonym [LMSans17-Oblique] [file:lmsans17-oblique] [features=default]
- \definefontsynonym [LMSans10-BoldOblique] [file:lmsans10-boldoblique] [features=default]
-
- \definefontsynonym [LMSans10-DemiCondensed] [file:lmsansdemicond10-regular] [features=default]
- \definefontsynonym [LMSans10-DemiCondensedOblique] [file:lmsansdemicond10-oblique] [features=default]
-
- \definefontsynonym [LMSansQuotation8-Regular] [file:lmsansquot8-regular] [features=default]
- \definefontsynonym [LMSansQuotation8-Bold] [file:lmsansquot8-bold] [features=default]
- \definefontsynonym [LMSansQuotation8-Oblique] [file:lmsansquot8-oblique] [features=default]
- \definefontsynonym [LMSansQuotation8-BoldOblique] [file:lmsansquot8-boldoblique] [features=default]
-\stoptypescript
-
-\starttypescript [mono] [modern,latin-modern,modern-vari,latin-modern-vari,modern-cond,latin-modern-cond]
- \definefontsynonym [LMTypewriter8-Regular] [file:lmmono8-regular]
- \definefontsynonym [LMTypewriter9-Regular] [file:lmmono9-regular]
- \definefontsynonym [LMTypewriter10-Regular] [file:lmmono10-regular]
- \definefontsynonym [LMTypewriter12-Regular] [file:lmmono12-regular]
- \definefontsynonym [LMTypewriter10-Italic] [file:lmmono10-italic]
- \definefontsynonym [LMTypewriter10-Oblique] [file:lmmonoslant10-regular]
- \definefontsynonym [LMTypewriter10-CapsRegular] [file:lmmonocaps10-regular] % features=smallcaps?
- \definefontsynonym [LMTypewriter10-CapsOblique] [file:lmmonocaps10-oblique]
-
- \definefontsynonym [LMTypewriter10-Light] [file:lmmonolt10-regular]
- \definefontsynonym [LMTypewriter10-LightOblique] [file:lmmonolt10-oblique]
- \definefontsynonym [LMTypewriter10-LightCondensed] [file:lmmonoltcond10-regular]
- \definefontsynonym [LMTypewriter10-LightCondensedOblique] [file:lmmonoltcond10-oblique]
-
- \definefontsynonym [LMTypewriter10-Dark] [file:lmmonolt10-bold]
- \definefontsynonym [LMTypewriter10-DarkOblique] [file:lmmonolt10-boldoblique]
-
- \definefontsynonym [LMTypewriterVarWd10-Regular] [file:lmmonoproplt10-regular] [features=default]
- \definefontsynonym [LMTypewriterVarWd10-Oblique] [file:lmmonoproplt10-oblique] [features=default]
- \definefontsynonym [LMTypewriterVarWd10-Light] [file:lmmonoprop10-regular] [features=default]
- \definefontsynonym [LMTypewriterVarWd10-LightOblique] [file:lmmonoprop10-oblique] [features=default]
- \definefontsynonym [LMTypewriterVarWd10-Dark] [file:lmmonoproplt10-bold] [features=default]
- \definefontsynonym [LMTypewriterVarWd10-DarkOblique] [file:lmmonoproplt10-boldoblique] [features=default]
-\stoptypescript
-
-\starttypescript [math] [modern,latin-modern]
- \definefontsynonym [LMMathRoman5-Regular] [rm-lmr5]
- \definefontsynonym [LMMathRoman6-Regular] [rm-lmr6]
- \definefontsynonym [LMMathRoman7-Regular] [rm-lmr7]
- \definefontsynonym [LMMathRoman8-Regular] [rm-lmr8]
- \definefontsynonym [LMMathRoman9-Regular] [rm-lmr9]
- \definefontsynonym [LMMathRoman10-Regular] [rm-lmr10]
- \definefontsynonym [LMMathRoman12-Regular] [rm-lmr12]
- \definefontsynonym [LMMathRoman17-Regular] [rm-lmr17]
- \definefontsynonym [LMMathRoman5-Bold] [rm-lmbx5]
- \definefontsynonym [LMMathRoman6-Bold] [rm-lmbx6]
- \definefontsynonym [LMMathRoman7-Bold] [rm-lmbx7]
- \definefontsynonym [LMMathRoman8-Bold] [rm-lmbx8]
- \definefontsynonym [LMMathRoman9-Bold] [rm-lmbx9]
- \definefontsynonym [LMMathRoman10-Bold] [rm-lmbx10]
- \definefontsynonym [LMMathRoman12-Bold] [rm-lmbx12]
- \definefontsynonym [LMMathSymbols5-BoldItalic] [lmbsy5]
- \definefontsynonym [LMMathSymbols7-BoldItalic] [lmbsy7]
- \definefontsynonym [LMMathSymbols10-BoldItalic][lmbsy10]
- \definefontsynonym [LMMathSymbols5-Italic] [lmsy5]
- \definefontsynonym [LMMathSymbols6-Italic] [lmsy6]
- \definefontsynonym [LMMathSymbols7-Italic] [lmsy7]
- \definefontsynonym [LMMathSymbols8-Italic] [lmsy8]
- \definefontsynonym [LMMathSymbols9-Italic] [lmsy9]
- \definefontsynonym [LMMathSymbols10-Italic] [lmsy10]
- \definefontsynonym [LMMathExtension10-Regular] [lmex10]
- \definefontsynonym [LMMathItalic5-Italic] [lmmi5]
- \definefontsynonym [LMMathItalic6-Italic] [lmmi6]
- \definefontsynonym [LMMathItalic7-Italic] [lmmi7]
- \definefontsynonym [LMMathItalic8-Italic] [lmmi8]
- \definefontsynonym [LMMathItalic9-Italic] [lmmi9]
- \definefontsynonym [LMMathItalic10-Italic] [lmmi10]
- \definefontsynonym [LMMathItalic12-Italic] [lmmi12]
- \definefontsynonym [LMMathItalic5-BoldItalic] [lmmib5]
- \definefontsynonym [LMMathItalic7-BoldItalic] [lmmib7]
- \definefontsynonym [LMMathItalic10-BoldItalic] [lmmib10]
-
- \loadmapfile[lm-math.map]
- \loadmapfile[lm-rm.map]
-\stoptypescript
-
-\starttypescript [math] [modern,computer-modern,latin-modern]
- \definefontsynonym [ComputerModernMath-Roman] [rm-lmr10]
- \definefontsynonym [ComputerModernMath-Extension] [lmex10]
- \definefontsynonym [ComputerModernMath-Italic] [lmmi10]
- \definefontsynonym [ComputerModernMath-Symbol] [lmsy10]
-\stoptypescript
-
-\starttypescript [boldmath,bfmath] [modern,computer-modern,latin-modern]
- \definefontsynonym [ComputerModernMath-Roman-Bold] [rm-lmb10]
- \definefontsynonym [ComputerModernMath-Extension] [lmex10]
- \definefontsynonym [ComputerModernMath-Italic-Bold] [lmmib10]
- \definefontsynonym [ComputerModernMath-Symbol-Bold] [lmbsy10]
-\stoptypescript
-
-% Computer Concrete (AMS)
-
-\starttypescript [serif] [concrete]
- \definefontsynonym [ComputerConcrete] [ccr10]
- \definefontsynonym [ComputerConcrete-Italic] [ccti10]
- \definefontsynonym [ComputerConcrete-Slanted] [ccsl10]
- \definefontsynonym [ComputerConcrete-Bold] [ComputerConcrete]
- \definefontsynonym [ComputerConcrete-BoldItalic] [ComputerConcrete-Italic]
- \definefontsynonym [ComputerConcrete-BoldSlanted] [ComputerConcrete-Slanted]
- \definefontsynonym [ComputerConcrete-Caps] [cccsc10]
-\stoptypescript
-
-% Euler (AMS)
-
-\starttypescript [math] [euler]
- \definefontsynonym [Euler-Roman] [zeurm10]
- \definefontsynonym [Euler-Extension] [zeuex10]
- \definefontsynonym [Euler-Symbol] [zeusm10]
- \definefontsynonym [Euler-Fraktur] [eufm10]
-
- \loadmapfile[original-ams-euler.map]
-\stoptypescript
-
-\starttypescript [boldmath,bfmath] [euler]
- \definefontsynonym [Euler-Roman-Bold] [zeurb10]
- \definefontsynonym [Euler-Extension] [zeuex10]
- \definefontsynonym [Euler-Symbol-Bold] [zeusb10]
- \definefontsynonym [Euler-Fraktur-Bold] [eufb10]
-
- \loadmapfile[original-ams-euler.map]
-\stoptypescript
-
-% AMS (AMS)
-
-\starttypescript [math] [modern,computer-modern,latin-modern,ams]
- \definefontsynonym [AMS-SymbolA] [msam10]
- \definefontsynonym [AMS-SymbolB] [msbm10]
-\stoptypescript
-
-% TeXGyre
-
-\definetypescriptprefix [n:pagella] [TeXGyrePagella] \definetypescriptprefix [f:pagella] [pagella]
-\definetypescriptprefix [n:termes] [TeXGyreTermes] \definetypescriptprefix [f:termes] [termes]
-\definetypescriptprefix [n:heros] [TeXGyreHeros] \definetypescriptprefix [f:heros] [heros]
-\definetypescriptprefix [n:bonum] [TeXGyreBonum] \definetypescriptprefix [f:bonum] [bonum]
-\definetypescriptprefix [n:schola] [TeXGyreSchola] \definetypescriptprefix [f:schola] [schola]
-\definetypescriptprefix [n:adventor][TeXGyreAdventor] \definetypescriptprefix [f:adventor][adventor]
-\definetypescriptprefix [n:cursor] [TeXGyreCursor] \definetypescriptprefix [f:cursor] [cursor]
-\definetypescriptprefix [n:chorus] [TeXGyreChorus] \definetypescriptprefix [f:chorus] [chorus] % not the full set
-
-\starttypescript [serif,sans,mono] [adventor,bonum,cursor,heros,pagella,schola,termes]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Regular] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=default]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Italic] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=default]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Bold] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=default]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalic] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=default]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Caps] [file:texgyre\typescriptprefix{f:\typescripttwo}-regular] [features=oldstyle]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-italic] [features=oldstyle]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bold] [features=oldstyle]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [file:texgyre\typescriptprefix{f:\typescripttwo}-bolditalic] [features=oldstyle]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-Slanted] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
- \definefontsynonym [\typescriptprefix{n:\typescripttwo}-BoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
-\stoptypescript
-
-\starttypescript [serif] [pagella,termes,bonum,schola,chorus] [name]
- \definefontsynonym [Serif] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
- \definefontsynonym [SerifItalic] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
- \definefontsynonym [SerifBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
- \definefontsynonym [SerifBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
- \definefontsynonym [SerifCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SerifSlanted] [\typescriptprefix{n:\typescripttwo}-Slanted] [features=default]
- \definefontsynonym [SerifBoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldSlanted] [features=default]
-
- \definefontvariant [Serif][osf][Caps]
- \definefontvariant [Serif][sc] [Caps]
-
- \definefontsynonym [SerifRegular] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
- \definefontsynonym [SerifRegularCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SerifItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [features=smallcaps]
- \definefontsynonym [SerifBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps] [features=smallcaps]
- \definefontsynonym [SerifBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [features=smallcaps]
- \definefontsynonym [SerifCapsCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SerifSlantedCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [features=smallcaps]
- \definefontsynonym [SerifBoldSlantedCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [features=smallcaps]
-\stoptypescript
-
-\starttypescript [sans] [heros,adventor] [name]
- \definefontsynonym [Sans] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
- \definefontsynonym [SansItalic] [\typescriptprefix{n:\typescripttwo}-Italic] [features=default]
- \definefontsynonym [SansBold] [\typescriptprefix{n:\typescripttwo}-Bold] [features=default]
- \definefontsynonym [SansBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic] [features=default]
- \definefontsynonym [SansCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SansSlanted] [\typescriptprefix{n:\typescripttwo}-Slanted] [features=default]
- \definefontsynonym [SansBoldSlanted] [\typescriptprefix{n:\typescripttwo}-BoldSlanted] [features=default]
-
- \definefontvariant [Sans][osf][Caps]
- \definefontvariant [Sans][sc] [Caps]
-
- \definefontsynonym [SansRegular] [\typescriptprefix{n:\typescripttwo}-Regular] [features=default]
- \definefontsynonym [SansRegularCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SansItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [features=smallcaps]
- \definefontsynonym [SansBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps] [features=smallcaps]
- \definefontsynonym [SansBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [features=smallcaps]
- \definefontsynonym [SansCapsCaps] [\typescriptprefix{n:\typescripttwo}-Caps] [features=smallcaps]
- \definefontsynonym [SansSlantedCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps] [features=smallcaps]
- \definefontsynonym [SansBoldSlantedCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps] [features=smallcaps]
-\stoptypescript
-
-\starttypescript [mono] [cursor] [name]
- \definefontsynonym [Mono] [\typescriptprefix{n:\typescripttwo}-Regular]
- \definefontsynonym [MonoItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
- \definefontsynonym [MonoBold] [\typescriptprefix{n:\typescripttwo}-Bold]
- \definefontsynonym [MonoBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
- \definefontsynonym [MonoSlanted] [MonoItalic]
- \definefontsynonym [MonoBoldSlanted] [MonoBoldItalic]
-\stoptypescript
-
-%D Here we overload the older (URW) fonts.
-
-% TeXGyrePagella
-%
-% qplr TeXGyrePagella-Regular
-% qplri TeXGyrePagella-Italic
-% qplb TeXGyrePagella-Bold
-% qplbi TeXGyrePagella-BoldItalic
-
-\starttypescript [serif] [palatino,pagella]
- \definefontsynonym [Palatino] [file:texgyrepagella-regular] [features=default]
- \definefontsynonym [Palatino-Italic] [file:texgyrepagella-italic] [features=default]
- \definefontsynonym [Palatino-Bold] [file:texgyrepagella-bold] [features=default]
- \definefontsynonym [Palatino-BoldItalic] [file:texgyrepagella-bolditalic] [features=default]
- \definefontsynonym [Palatino-Caps] [file:texgyrepagella-regular] [features=smallcaps]
- \definefontsynonym [Palatino-Slanted] [Palatino-Italic]
- \definefontsynonym [Palatino-BoldSlanted] [Palatino-BoldItalic]
-\stoptypescript
-
-% TeXGyreTermes
-%
-% qtmr TeXGyreTermes-Regular
-% qtmri TeXGyreTermes-Italic
-% qtmb TeXGyreTermes-Bold
-% qtmbi TeXGyreTermes-BoldItalic
-
-\starttypescript [serif] [times]
- \definefontsynonym [Times-Roman] [file:texgyretermes-regular] [features=default]
- \definefontsynonym [Times-Italic] [file:texgyretermes-italic] [features=default]
- \definefontsynonym [Times-Bold] [file:texgyretermes-bold] [features=default]
- \definefontsynonym [Times-BoldItalic] [file:texgyretermes-bolditalic] [features=default]
- \definefontsynonym [Times-Caps] [file:texgyretermes-regular] [features=smallcaps]
- \definefontsynonym [Times-Slanted] [Times-Italic]
- \definefontsynonym [Times-BoldSlanted] [Times-BoldItalic]
-\stoptypescript
-
-% TeXGyreHeros
-%
-% qtmr TeXGyreHeros-Regular
-% qtmri TeXGyreHeros-Italic
-% qtmb TeXGyreHeros-Bold
-% qtmbi TeXGyreHeros-BoldItalic
-
-\starttypescript [sans] [helvetica]
- \definefontsynonym [Helvetica] [file:texgyreheros-regular] [features=default]
- \definefontsynonym [Helvetica-Oblique] [file:texgyreheros-italic] [features=default]
- \definefontsynonym [Helvetica-Bold] [file:texgyreheros-bold] [features=default]
- \definefontsynonym [Helvetica-BoldOblique] [file:texgyreheros-bolditalic] [features=default]
- \definefontsynonym [Helvetica-Caps] [file:texgyreheros-regular] [features=smallcaps]
-\stoptypescript
-
-% TeXGyreBonum
-%
-% qtmr TeXGyreBonum-Regular
-% qtmri TeXGyreBonum-Italic
-% qtmb TeXGyreBonum-Bold
-% qtmbi TeXGyreBonum-BoldItalic
-
-\starttypescript [serif] [bookman]
- \definefontsynonym [Bookman-Light] [file:texgyrebonum-regular] [features=default]
- \definefontsynonym [Bookman-LightItalic] [file:texgyrebonum-italic] [features=default]
- \definefontsynonym [Bookman-DemiBold] [file:texgyrebonum-bold] [features=default]
- \definefontsynonym [Bookman-DemiBoldItalic] [file:texgyrebonum-bolditalic] [features=default]
- \definefontsynonym [Bookman-Light-Caps] [file:texgyrebonum-regular] [features=smallcaps]
- \definefontsynonym [Bookman-LightSlanted] [Bookman-LightItalic] [features=default]
- \definefontsynonym [Bookman-DemiBoldSlanted] [Bookman-DemiBoldItalic] [features=default]
-\stoptypescript
-
-% TeXGyreScola
-%
-% qcsr TeXGyreSchola-Regular
-% qcsri TeXGyreSchola-Italic
-% qcsb TeXGyreSchola-Bold
-% qcsbi TeXGyreSchola-BoldItalic
-
-\starttypescript [serif] [schoolbook]
- \definefontsynonym [Schoolbook-Roman] [file:texgyreschola-regular] [features=default]
- \definefontsynonym [Schoolbook-Italic] [file:texgyreschola-italic] [features=default]
- \definefontsynonym [Schoolbook-Bold] [file:texgyreschola-bold] [features=default]
- \definefontsynonym [Schoolbook-BoldItalic] [file:texgyreschola-bolditalic] [features=default]
- \definefontsynonym [Schoolbook-Roman-Caps] [file:texgyreschola-regular] [features=smallcaps]
- \definefontsynonym [Schoolbook-Slanted] [Schoolbook-Italic] [features=default]
- \definefontsynonym [Schoolbook-BoldSlanted] [Schoolbook-BoldItalic] [features=default]
-\stoptypescript
-
-% TeXGyreAdventor
-%
-% qagr TeXGyreAdventor-Regular
-% qagri TeXGyreAdventor-Italic
-% qagb TeXGyreAdventor-Bold
-% qagbi TeXGyreAdventor-BoldItalic
-
-% TeXGyreCursor
-%
-% crgr TeXGyreCursor-Regular
-% crgri TeXGyreCursor-Italic
-% crgb TeXGyreCursor-Bold
-% crgbi TeXGyreCursor-BoldItalic
-
-\starttypescript [mono] [courier] [name]
- \definefontsynonym [Courier] [file:texgyrecursor-regular] [features=default]
- \definefontsynonym [Courier-Bold] [file:texgyrecursor-bold] [features=default]
- \definefontsynonym [Courier-Oblique] [file:texgyrecursor-italic] [features=default]
- \definefontsynonym [Courier-BoldOblique] [file:texgyrecursor-bolditalic] [features=default]
- \fakecontrolspace
-\stoptypescript
-
-% TeXGyreChorus
-%
-% qzcr TeXGyreChorus-Regular
-
-\starttypescript [calligraphy] [chancery]
- \definefontsynonym [Chancery] [file:texgyrechorus-mediumitalic] [features=default]
- \definefontsynonym [texgyrechorus-regular] [file:texgyrechorus-mediumitalic]
-\stoptypescript
-
-% Math Times (tx)
-
-\starttypescript [math] [times] [all]
- \definefontsynonym [Times-Roman-Upright] [txr]
- \definefontsynonym [Times-Roman-Italic] [txi]
- \definefontsynonym [Times-Roman-Slanted] [txsl]
- \definefontsynonym [Times-Roman-Caps] [txsc]
- \definefontsynonym [Times-Companion-Upright] [tcxr]
- \definefontsynonym [Times-Companion-Italic] [tcxi]
- \definefontsynonym [Times-Companion-Slanted] [tcxsl]
- \definefontsynonym [Times-Math-Italic] [txmi]
- \definefontsynonym [Times-Math-Symbols] [txsy]
- \definefontsynonym [Times-Math-Extension] [txex]
- \definefontsynonym [Times-Math-SymbolsA] [txsya]
- \definefontsynonym [Times-Math-SymbolsB] [txsyb]
- \definefontsynonym [Times-Math-SymbolsC] [txsyc]
- \definefontsynonym [Times-Math-Italic-A] [txmia]
- \definefontsynonym [Times-Math-Extension-A] [txexa]
-
- \loadmapfile[original-youngryu-tx.map]
- \usemathcollection[default]
-\stoptypescript
-
-% Palatino Math (PX)
-
-\starttypescript [math] [palatino] [all]
- \definefontsynonym [Palatino-Roman-Upright] [pxr]
- \definefontsynonym [Palatino-Roman-Italic] [pxi]
- \definefontsynonym [Palatino-Roman-Slanted] [pxsl]
- \definefontsynonym [Palatino-Roman-Caps] [pxsc]
- \definefontsynonym [Palatino-Companion-Upright] [pcxr]
- \definefontsynonym [Palatino-Companion-Italic] [pcxi]
- \definefontsynonym [Palatino-Companion-Slanted] [pcxsl]
- \definefontsynonym [Palatino-Math-Italic] [pxmi]
- \definefontsynonym [Palatino-Math-Symbols] [pxsy]
- \definefontsynonym [Palatino-Math-Extension] [pxex]
- \definefontsynonym [Palatino-Math-SymbolsA] [pxsya]
- \definefontsynonym [Palatino-Math-SymbolsB] [pxsyb]
- \definefontsynonym [Palatino-Math-SymbolsC] [pxsyc]
- \definefontsynonym [Palatino-Math-Italic-A] [pxmia]
- \definefontsynonym [Palatino-Math-Extension-A] [pxexa]
-
- \loadmapfile[original-youngryu-px.map]
- \usemathcollection[default]
-\stoptypescript
-
-% Antykwa Torunska (GUST)
-
-\starttypescript [serif] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
- \definefontsynonym [AntykwaTorunska-Regular] [file:AntykwaTorunska-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-Italic] [file:AntykwaTorunska-Italic] [features=default]
- \definefontsynonym [AntykwaTorunska-Bold] [file:AntykwaTorunska-Bold] [features=default]
- \definefontsynonym [AntykwaTorunska-BoldItalic] [file:AntykwaTorunska-BoldItalic] [features=default]
- \definefontsynonym [AntykwaTorunska-Light] [file:AntykwaTorunskaLight-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-LightItalic] [file:AntykwaTorunskaLight-Italic] [features=default]
- \definefontsynonym [AntykwaTorunska-Medium] [file:AntykwaTorunskaMed-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-MedItalic] [file:AntykwaTorunskaMed-Italic] [features=default]
- \definefontsynonym [AntykwaTorunska-CondRegular] [file:AntykwaTorunskaCond-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-CondItalic] [file:AntykwaTorunskaCond-Italic] [features=default]
- \definefontsynonym [AntykwaTorunska-CondBold] [file:AntykwaTorunskaCond-Bold] [features=default]
- \definefontsynonym [AntykwaTorunska-CondBoldItalic] [file:AntykwaTorunskaCond-BoldItalic] [features=default]
- \definefontsynonym [AntykwaTorunska-CondLight] [file:AntykwaTorunskaCondLight-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-CondLightItalic] [file:AntykwaTorunskaCondLight-Italic] [features=default]
- \definefontsynonym [AntykwaTorunska-CondMedium] [file:AntykwaTorunskaCondMed-Regular] [features=default]
- \definefontsynonym [AntykwaTorunska-CondMedItalic] [file:AntykwaTorunskaCondMed-Italic] [features=default]
-
- \definefontsynonym [AntykwaTorunska-Cap] [file:AntykwaTorunska-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-ItalicCap] [file:AntykwaTorunska-Italic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-BoldCap] [file:AntykwaTorunska-Bold] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-BoldItalicCap] [file:AntykwaTorunska-BoldItalic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-LightCap] [file:AntykwaTorunskaLight-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-LightItalicCap] [file:AntykwaTorunskaLight-Italic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-MediumCap] [file:AntykwaTorunskaMed-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-MedItalicCap] [file:AntykwaTorunskaMed-Italic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondCap] [file:AntykwaTorunskaCond-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondItalicCap] [file:AntykwaTorunskaCond-Italic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondBoldCap] [file:AntykwaTorunskaCond-Bold] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondBoldItalicCap] [file:AntykwaTorunskaCond-BoldItalic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondLightCap] [file:AntykwaTorunskaCondLight-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondLightItalicCap][file:AntykwaTorunskaCondLight-Italic] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondMediumCap] [file:AntykwaTorunskaCondMed-Regular] [features=smallcaps]
- \definefontsynonym [AntykwaTorunska-CondMedItalicCap] [file:AntykwaTorunskaCondMed-Italic] [features=smallcaps]
-\stoptypescript
-
-\starttypescript [math] [antykwa-torunska] [default]
- \definefontsynonym [AntykwaTorunska-Math-Letters-Regular] [rm-anttr]
- \definefontsynonym [AntykwaTorunska-Math-Letters-Italic] [mi-anttri]
- \definefontsynonym [AntykwaTorunska-Math-Symbols-Regular] [sy-anttrz]
- \definefontsynonym [AntykwaTorunska-Math-Extension-Regular] [ex-anttr]
-\stoptypescript
-
-\starttypescript [math] [antykwa-torunska-light] [default]
- \definefontsynonym [AntykwaTorunska-Math-Letters-Light] [rm-anttl]
- \definefontsynonym [AntykwaTorunska-Math-Letters-LightItalic] [mi-anttli]
- \definefontsynonym [AntykwaTorunska-Math-Symbols-Light] [sy-anttlz]
- \definefontsynonym [AntykwaTorunska-Math-Extension-Light] [ex-anttl]
-\stoptypescript
-
-\starttypescript [math] [antykwa-torunska-cond] [default]
- \definefontsynonym [AntykwaTorunska-Math-Letters-CondRegular] [rm-anttcr]
- \definefontsynonym [AntykwaTorunska-Math-Letters-CondItalic] [mi-anttcri]
- \definefontsynonym [AntykwaTorunska-Math-Symbols-CondRegular] [sy-anttcrz]
- \definefontsynonym [AntykwaTorunska-Math-Extension-CondRegular] [ex-anttcr]
-\stoptypescript
-
-\starttypescript [math] [antykwa-torunska-lightcond] [default]
- \definefontsynonym [AntykwaTorunska-Math-Letters-CondLight] [rm-anttcl]
- \definefontsynonym [AntykwaTorunska-Math-Letters-CondLightItalic] [mi-anttcli]
- \definefontsynonym [AntykwaTorunska-Math-Symbols-CondLight] [sy-anttclz]
- \definefontsynonym [AntykwaTorunska-Math-Extension-CondLight] [ex-anttcl]
-\stoptypescript
-
-\starttypescript [math] [antykwa-torunska,antykwa-torunska-light,antykwa-torunska-cond,antykwa-torunska-lightcond]
- \usemathcollection[default]
- \loadmapfile[antt-rm.map]
- \loadmapfile[antt-mi.map]
- \loadmapfile[antt-sy.map]
- \loadmapfile[antt-ex.map]
-\stoptypescript
-
-% Antykwa Poltawskiego (GUST)
-
-\starttypescript [serif] [antykwa-poltawskiego]
- \definefontsynonym [AntykwaPoltawskiego-Regular] [antpr]
- \definefontsynonym [AntykwaPoltawskiego-Bold] [antpb]
- \definefontsynonym [AntykwaPoltawskiego-Italic] [antpri]
- \definefontsynonym [AntykwaPoltawskiego-BoldItalic] [antpbi]
-\stoptypescript
-
-% Iwona (JMN)
-
-% maybe this will change in Iwona-Math-Letters and Iwona-Math-Letters-Italic
-
-% These names are a depressing mess. They have changed over time and are
-% still not consistent. I'd expect Bold-Regular and Bold-Italic.
-
-\starttypescript [sans] [iwona-light,iwona,iwona-medium,iwona-heavy,iwona-light-cond,iwona-cond,iwona-medium-cond,iwona-heavy-cond]
-
- \definefontsynonym [Iwona-Regular] [file:Iwona-Regular] [features=default]
- \definefontsynonym [Iwona-Italic] [file:Iwona-Italic] [features=default]
- \definefontsynonym [Iwona-Bold] [file:Iwona-Bold] [features=default]
- \definefontsynonym [Iwona-BoldItalic] [file:Iwona-BoldItalic] [features=default]
- \definefontsynonym [Iwona-Light-Regular] [file:IwonaLight-Regular] [features=default]
- \definefontsynonym [Iwona-Light-Italic] [file:IwonaLight-Italic] [features=default]
- \definefontsynonym [Iwona-Medium-Regular] [file:IwonaMedium-Regular] [features=default]
- \definefontsynonym [Iwona-Medium-Italic] [file:IwonaMedium-Italic] [features=default]
- \definefontsynonym [Iwona-Heavy-Regular] [file:IwonaHeavy-Regular] [features=default]
- \definefontsynonym [Iwona-Heavy-Italic] [file:IwonaHeavy-Italic] [features=default]
-
- \definefontsynonym [Iwona-CapsRegular] [file:Iwona-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsItalic] [file:Iwona-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsBold] [file:Iwona-Bold] [features=smallcaps]
- \definefontsynonym [Iwona-CapsBoldItalic] [file:Iwona-BoldItalic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsLight] [file:IwonaLight-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsLight-Italic] [file:IwonaLight-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsMedium] [file:IwonaMedium-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsMedium-Italic] [file:IwonaMedium-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsHeavy] [file:IwonaHeavy-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsHeavy-Italic] [file:IwonaHeavy-Italic] [features=smallcaps]
-
- \definefontsynonym [Iwona-CondRegular] [file:IwonaCond-Regular] [features=default]
- \definefontsynonym [Iwona-CondItalic] [file:IwonaCond-Italic] [features=default]
- \definefontsynonym [Iwona-CondBold] [file:IwonaCond-Bold] [features=default]
- \definefontsynonym [Iwona-CondBoldItalic] [file:IwonaCond-BoldItalic] [features=default]
- \definefontsynonym [Iwona-CondLight-Regular] [file:IwonaCondLight-Regular] [features=default]
- \definefontsynonym [Iwona-CondLight-Italic] [file:IwonaCondLight-Italic] [features=default]
- \definefontsynonym [Iwona-CondMedium-Regular] [file:IwonaCondMedium-Regular] [features=default]
- \definefontsynonym [Iwona-CondMedium-Italic] [file:IwonaCondMedium-Italic] [features=default]
- \definefontsynonym [Iwona-CondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=default]
- \definefontsynonym [Iwona-CondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=default]
-
- \definefontsynonym [Iwona-CapsCondRegular] [file:IwonaCond-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondItalic] [file:IwonaCond-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondBold] [file:IwonaCond-Bold] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondBoldItalic] [file:IwonaCond-BoldItalic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondLight-Regular] [file:IwonaCondLight-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondLight-Italic] [file:IwonaCondLight-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondMedium-Regular][file:IwonaCondMedium-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondMedium-Italic] [file:IwonaCondMedium-Italic] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondHeavy-Regular] [file:IwonaCondHeavy-Regular] [features=smallcaps]
- \definefontsynonym [Iwona-CapsCondHeavy-Italic] [file:IwonaCondHeavy-Italic] [features=smallcaps]
-
-\stoptypescript
-
-\starttypescript [math] [iwona] [default]
- \definefontsynonym [Iwona-Math-Letters-Regular] [rm-iwonar]
- \definefontsynonym [Iwona-Math-Letters-Italic] [mi-iwonari]
- \definefontsynonym [Iwona-Math-Symbols-Regular] [sy-iwonarz]
- \definefontsynonym [Iwona-Math-Extension-Regular] [ex-iwonar]
-\stoptypescript
-
-\starttypescript [math] [iwona-light] [default]
- \definefontsynonym [Iwona-Math-Letters-Light-Regular] [rm-iwonal]
- \definefontsynonym [Iwona-Math-Letters-Light-Italic] [mi-iwonali]
- \definefontsynonym [Iwona-Math-Symbols-Light] [sy-iwonalz]
- \definefontsynonym [Iwona-Math-Extension-Light] [ex-iwonal]
-\stoptypescript
-
-\starttypescript [math] [iwona-medium] [default]
- \definefontsynonym [Iwona-Math-Letters-Medium-Regular][rm-iwonam]
- \definefontsynonym [Iwona-Math-Letters-Medium-Italic] [mi-iwonami]
- \definefontsynonym [Iwona-Math-Symbols-Medium] [sy-iwonamz]
- \definefontsynonym [Iwona-Math-Extension-Medium] [ex-iwonam]
-\stoptypescript
-
-\starttypescript [math] [iwona-heavy] [default]
- \definefontsynonym [Iwona-Math-Letters-Heavy-Regular] [rm-iwonah]
- \definefontsynonym [Iwona-Math-Letters-Heavy-Italic] [mi-iwonahi]
- \definefontsynonym [Iwona-Math-Symbols-Heavy] [sy-iwonahz]
- \definefontsynonym [Iwona-Math-Extension-Heavy] [ex-iwonah]
-\stoptypescript
-
-\starttypescript [math] [iwona,iwona-light,iwona-medium,iwona-heavy] [default]
- \usemathcollection[default]
- \loadmapfile[iwona-rm.map]
- \loadmapfile[iwona-mi.map]
- \loadmapfile[iwona-sy.map]
- \loadmapfile[iwona-ex.map]
-\stoptypescript
-
-% Kurier (JMN) / no open type fonts
-
-\starttypescript [sans] [kurier-light,kurier,kurier-medium]
- \definefontsynonym[Kurier-Light] [kurierl]
- \definefontsynonym[Kurier-Regular] [kurierr]
- \definefontsynonym[Kurier-Medium] [kurierm]
- \definefontsynonym[Kurier-Bold] [kurierb]
- \definefontsynonym[Kurier-Heavy] [kurierh]
- \definefontsynonym[Kurier-LightItalic] [kurierli]
- \definefontsynonym[Kurier-Italic] [kurierri]
- \definefontsynonym[Kurier-MediumItalic] [kuriermi]
- \definefontsynonym[Kurier-BoldItalic] [kurierbi]
- \definefontsynonym[Kurier-HeavyItalic] [kurierhi]
-\stoptypescript
-
-\starttypescript [math] [kurier] [default]
- \definefontsynonym [Kurier-Math-Letters-Regular] [rm-kurierr]
- \definefontsynonym [Kurier-Math-Letters-Italic] [mi-kurierri]
- \definefontsynonym [Kurier-Math-Symbols-Regular] [sy-kurierrz]
- \definefontsynonym [Kurier-Math-Extension-Regular] [ex-kurierr]
+\starttypescript [bookman,bonum]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default]
+ \quittypescriptscanning
\stoptypescript
-\starttypescript [math] [kurier-light] [default]
- \definefontsynonym [Kurier-Math-Letters-Light-Regular] [rm-kurierl]
- \definefontsynonym [Kurier-Math-Letters-Light-Italic] [mi-kurierli]
- \definefontsynonym [Kurier-Math-Symbols-Light] [sy-kurierlz]
- \definefontsynonym [Kurier-Math-Extension-Light] [ex-kurierl]
+\starttypescript [chancery,chorus]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default]
+ \quittypescriptscanning
\stoptypescript
-\starttypescript [math] [kurier-medium] [default]
- \definefontsynonym [Kurier-Math-Letters-Medium-Regular] [rm-kurierm]
- \definefontsynonym [Kurier-Math-Letters-Medium-Italic] [mi-kuriermi]
- \definefontsynonym [Kurier-Math-Symbols-Medium-Regular] [sy-kuriermz]
- \definefontsynonym [Kurier-Math-Extension-Medium] [ex-kurierm]
+\starttypescript [iwona,iwona-light,iwona-heavy,iwona-medium]
+ \definetypeface[\typescriptone][ss][sans] [\typescriptone] [default]
+ \definetypeface[\typescriptone][rm][serif][modern] [default]
+ \definetypeface[\typescriptone][tt][mono] [modern] [default]
+ \definetypeface[\typescriptone][mm][math] [\typescriptone] [default][text=ss]
+ \quittypescriptscanning
\stoptypescript
-\starttypescript [math] [kurier,kurier-light,kurier-medium] [default]
- \loadmapfile[kurier-rm.map]
- \loadmapfile[kurier-mi.map]
- \loadmapfile[kurier-sy.map]
- \loadmapfile[kurier-ex.map]
+\starttypescript [helvetica,heros]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default] [rscale=1.15]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [rscale=1.15]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default] [rscale=1.15]
+ \quittypescriptscanning
\stoptypescript
-% Whatever else we need:
-
-\starttypescript
- \definefontsynonym [ZapfDingbats] [uzdr]
- \definefontsynonym [RalfSmithFormalScript] [rsfs10]
- \definefontsynonym [MartinVogel] [fmvr8x]
+\starttypescript [avantgarde,adventor]
+ \definetypeface [\typescriptone] [ss] [sans] [adventor] [default]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default] [rscale=1.15]
+ \definetypeface [\typescriptone] [tt] [mono] [modern] [default] [rscale=1.15]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default]
+ \quittypescriptscanning
\stoptypescript
-% Temp here
-
-\starttypescript [serif] [charter]
- \definefontsynonym [Charter-Roman] [name:CharterBT-Roman] % or: [bchr8a]
- \definefontsynonym [Charter-Italic] [name:CharterBT-Italic] % or: [bchri8a]
- \definefontsynonym [Charter-Bold] [name:CharterBT-Bold] % or: [bchb8a]
- \definefontsynonym [Charter-BoldItalic] [name:CharterBT-BoldItalic] % or: [bchbi8a]
- \definefontsynonym [Charter-Slanted] [name:CharterBT-Italic] % or: [bchri8a]
- \definefontsynonym [Charter-BoldSlanted] [name:CharterBT-BoldItalic] % or: [bchbi8a]
- \definefontsynonym [Charter-Roman-Caps] [Charter-Roman] % not present
+\starttypescript [courier,cursor]
+ \definetypeface [\typescriptone] [tt] [mono] [\typescriptone] [default]
+ \definetypeface [\typescriptone] [rm] [serif] [modern] [default]
+ \definetypeface [\typescriptone] [ss] [sans] [modern] [default]
+ \definetypeface [\typescriptone] [mm] [math] [modern] [default]
+ \quittypescriptscanning
\stoptypescript
\stoptypescriptcollection
+\loadmarkfile{type-otf}
+
\endinput
diff --git a/tex/context/base/type-siz.mkii b/tex/context/base/type-siz.mkii
new file mode 100644
index 000000000..0ad737cf2
--- /dev/null
+++ b/tex/context/base/type-siz.mkii
@@ -0,0 +1,583 @@
+%D \module
+%D [ file=type-siz,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Sizing scripts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\starttypescriptcollection[size-mkii]
+
+% todo: instead of assuming designsize we will set it explicitly (saves these
+% -1000 problems at the lua end)
+
+% cmr
+
+\starttypescript [serif] [computer-modern] [size]
+
+ \definebodyfont [12pt] [rm]
+ [tf=cmr12,
+ bf=cmbx12,
+ it=cmti12,
+ sl=cmsl12,
+ bi=cmbxti10 at 12pt,
+ bs=cmbxsl10 at 12pt,
+ sc=cmcsc10 at 12pt]
+
+ \definebodyfont [11pt] [rm]
+ [tf=cmr10 at 11pt,
+ bf=cmbx10 at 11pt,
+ sl=cmsl10 at 11pt,
+ it=cmti10 at 11pt,
+ bi=cmbxti10 at 11pt,
+ bs=cmbxsl10 at 11pt,
+ sc=cmcsc10 at 11pt]
+
+ \definebodyfont [10pt] [rm]
+ [tf=cmr10,
+ bf=cmbx10,
+ it=cmti10,
+ sl=cmsl10,
+ bi=cmbxti10,
+ bs=cmbxsl10,
+ sc=cmcsc10]
+
+ \definebodyfont [9pt] [rm]
+ [tf=cmr9,
+ bf=cmbx9,
+ it=cmti9,
+ sl=cmsl9,
+ bi=cmbxti10 at 9pt,
+ bs=cmbxsl10 at 9pt,
+ sc=cmcsc10 at 9pt]
+
+ \definebodyfont [8pt] [rm]
+ [tf=cmr8,
+ bf=cmbx8,
+ it=cmti8,
+ sl=cmsl8,
+ bi=cmbxti10 at 8pt,
+ bs=cmbxsl10 at 8pt,
+ sc=cmcsc10 at 8pt]
+
+ \definebodyfont [7pt] [rm]
+ [tf=cmr7,
+ bf=cmbx7,
+ it=cmti10 at 7pt,
+ sl=cmsl10 at 7pt,
+ bi=cmbxti10 at 7pt,
+ bs=cmbxsl10 at 7pt,
+ sc=cmcsc10 at 7pt]
+
+ \definebodyfont [6pt] [rm]
+ [tf=cmr6,
+ bf=cmbx6,
+ it=cmti10 at 6pt,
+ sl=cmsl10 at 6pt,
+ bi=cmbxti10 at 6pt,
+ bs=cmbxsl10 at 6pt,
+ sc=cmcsc10 at 6pt]
+
+ \definebodyfont [5pt] [rm]
+ [tf=cmr5,
+ bf=cmbx5,
+ it=cmti10 at 5pt,
+ sl=cmsl10 at 5pt,
+ bi=cmbxti10 at 5pt,
+ bs=cmbxsl10 at 5pt,
+ sc=cmcsc10 at 5pt]
+
+ \definebodyfont [4pt] [rm]
+ [tf=cmr10 at 4pt,
+ bf=cmbx10 at 4pt,
+ it=cmti10 at 4pt,
+ sl=cmsl10 at 4pt,
+ bi=cmbxti10 at 4pt,
+ bs=cmbxsl10 at 4pt,
+ sc=cmr10 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [rm]
+ [tf=cmr12 sa 1,
+ bf=cmbx12 sa 1,
+ it=cmti12 sa 1,
+ sl=cmsl12 sa 1,
+ bi=cmbxti10 sa 1,
+ bs=cmbxsl10 sa 1,
+ sc=cmcsc10 sa 1]
+
+\stoptypescript
+
+\starttypescript [sans] [computer-modern] [size]
+
+ \definebodyfont [12pt] [ss]
+ [tf=cmss12,
+ bf=cmssbx10 at 12pt,
+ it=cmssi12,
+ sl=cmssi12,
+ bi=cmssbx10 at 12pt,
+ bs=cmssbx10 at 12pt,
+ sc=cmss10 at 12pt]
+
+ \definebodyfont [11pt] [ss]
+ [tf=cmss10 at 11pt,
+ bf=cmssbx10 at 11pt,
+ it=cmssi10 at 11pt,
+ sl=cmssi10 at 11pt,
+ bi=cmssbx10 at 11pt,
+ bs=cmssbx10 at 11pt,
+ sc=cmss10 at 11pt]
+
+ \definebodyfont [10pt] [ss]
+ [tf=cmss10,
+ bf=cmssbx10,
+ it=cmssi10,
+ sl=cmssi10,
+ bi=cmssbx10,
+ bs=cmssbx10,
+ sc=cmss10]
+
+ \definebodyfont [9pt] [ss]
+ [tf=cmss9,
+ bf=cmssbx10 at 9pt,
+ it=cmssi9,
+ sl=cmssi9,
+ bi=cmssbx10 at 9pt,
+ bs=cmssbx10 at 9pt,
+ sc=cmss9]
+
+ \definebodyfont [8pt] [ss]
+ [tf=cmss8,
+ bf=cmssbx10 at 8pt,
+ it=cmssi8,
+ sl=cmssi8,
+ bi=cmssbx10 at 8pt,
+ bs=cmssbx10 at 8pt,
+ sc=cmss8]
+
+ \definebodyfont [7pt] [ss]
+ [tf=cmss10 at 7pt,
+ bf=cmssbx10 at 7pt,
+ it=cmssi10 at 7pt,
+ sl=cmssi10 at 7pt,
+ bs=cmssbx10 at 7pt,
+ bi=cmssbx10 at 7pt,
+ sc=cmss10 at 7pt]
+
+ \definebodyfont [6pt] [ss]
+ [tf=cmss10 at 6pt,
+ bf=cmssbx10 at 6pt,
+ it=cmssi10 at 6pt,
+ sl=cmssi10 at 6pt,
+ bs=cmssbx10 at 6pt,
+ bi=cmssbx10 at 6pt,
+ sc=cmss10 at 6pt]
+
+ \definebodyfont [5pt] [ss]
+ [tf=cmss10 at 5pt,
+ bf=cmssbx10 at 5pt,
+ it=cmssi10 at 5pt,
+ sl=cmssi10 at 5pt,
+ bs=cmssbx10 at 5pt,
+ bi=cmssbx10 at 5pt,
+ sc=cmss10 at 5pt]
+
+ \definebodyfont [4pt] [ss]
+ [tf=cmss10 at 4pt,
+ bf=cmssbx10 at 4pt,
+ it=cmssi10 at 4pt,
+ sl=cmssi10 at 4pt,
+ bs=cmssbx10 at 4pt,
+ bi=cmssbx10 at 4pt,
+ sc=cmss10 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [ss]
+ [tf=cmss12 sa 1,
+ bf=cmssbx10 sa 1,
+ it=cmssi12 sa 1,
+ sl=cmssi12 sa 1,
+ bi=cmssbx10 sa 1,
+ bs=cmssbx10 sa 1,
+ sc=cmss12 sa 1]
+
+\stoptypescript
+
+\starttypescript [mono] [computer-modern] [size]
+
+ \definebodyfont [12pt] [tt]
+ [tf=cmtt12,
+ sl=cmsltt10 at 12pt,
+ it=cmitt10 at 12pt,
+ sc=cmtcsc10 at 12pt]
+
+ \definebodyfont [9pt] [tt]
+ [tf=cmtt9,
+ sl=cmsltt10 at 9pt,
+ it=cmitt10 at 9pt,
+ sc=cmtcsc10 at 9pt]
+
+ \definebodyfont [8pt] [tt]
+ [tf=cmtt8,
+ sl=cmsltt10 at 8pt,
+ it=cmitt10 at 8pt,
+ sc=cmtcsc10 at 8pt]
+
+ \definebodyfont [11pt,10pt,7pt,6pt,5pt,4pt] [tt]
+ [tf=cmtt10 sa 1,
+ sl=cmsltt10 sa 1,
+ it=cmitt10 sa 1,
+ sc=cmtcsc10 sa 1]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [tt]
+ [tf=cmtt12 sa 1,
+ sl=cmsltt10 sa 1,
+ it=cmitt10 sa 1,
+ sc=cmtcsc10 sa 1]
+
+\stoptypescript
+
+\starttypescript [math] [modern,computer-modern,latin-modern] [size]
+
+ % hack to prevent mapping of filenames, watch the space! before
+ % latin modern came aroudn we needed this trick to make sure that
+ % we loaded the raw cmr12 etc instead of the ones mapped onto
+ % an encoding
+
+ % \definefontsynonym[xcmr12][cmr12 ]
+ % \definefontsynonym[xcmr10][cmr10 ]
+ % \definefontsynonym[xcmr9] [cmr9 ]
+ % \definefontsynonym[xcmr8] [cmr8 ]
+ % \definefontsynonym[xcmr7] [cmr7 ]
+ % \definefontsynonym[xcmr6] [cmr6 ]
+ % \definefontsynonym[xcmr5] [cmr5 ]
+
+ \definebodyfont [12pt] [mm]
+ [mr=xcmr12,
+ ex=cmex10 at 12pt,
+ mi=cmmi12,
+ sy=cmsy10 at 12pt]
+
+ \definebodyfont [11pt] [mm]
+ [mr=xcmr10 at 11pt,
+ ex=cmex10 at 11pt,
+ mi=cmmi10 at 11pt,
+ sy=cmsy10 at 11pt]
+
+ \definebodyfont [10pt] [mm]
+ [mr=xcmr10,
+ ex=cmex10,
+ mi=cmmi10,
+ sy=cmsy10]
+
+ \definebodyfont [9pt] [mm]
+ [mr=xcmr9,
+ ex=cmex10 at 9pt,
+ mi=cmmi9,
+ sy=cmsy9]
+
+ \definebodyfont [8pt] [mm]
+ [mr=xcmr8,
+ ex=cmex10 at 8pt,
+ mi=cmmi8,
+ sy=cmsy8]
+
+ \definebodyfont [7pt] [mm]
+ [mr=xcmr7,
+ ex=cmex10 at 7pt,
+ mi=cmmi7,
+ sy=cmsy7]
+
+ \definebodyfont [6pt] [mm]
+ [mr=xcmr6,
+ ex=cmex10 at 6pt,
+ mi=cmmi6,
+ sy=cmsy6]
+
+ \definebodyfont [5pt] [mm]
+ [mr=xcmr5,
+ ex=cmex10 at 5pt,
+ mi=cmmi5,
+ sy=cmsy5]
+
+ \definebodyfont [4pt] [mm]
+ [mr=xcmr5 at 4pt,
+ ex=cmex10 at 4pt,
+ mi=cmmi5 at 4pt,
+ sy=cmsy5 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
+ [mr=xcmr12 sa 1,
+ ex=cmex10 sa 1,
+ mi=cmmi12 sa 1,
+ sy=cmsy10 sa 1]
+
+\stoptypescript
+
+\starttypescript [boldmath] [modern,computer-modern,latin-modern] [size]
+
+% hack to prevent mapping of filenames, watch the space!
+
+ \definefontsynonym[xcmb12][cmbx12 ]
+ \definefontsynonym[xcmb10][cmbx10 ]
+ \definefontsynonym[xcmb9] [cmbx9 ]
+ \definefontsynonym[xcmb8] [cmbx8 ]
+ \definefontsynonym[xcmb7] [cmbx7 ]
+ \definefontsynonym[xcmb6] [cmbx6 ]
+ \definefontsynonym[xcmb5] [cmbx5 ]
+
+ \definebodyfont [12pt] [mm]
+ [mr=xcmb12,
+ ex=cmex10 at 12pt,
+ mi=cmmib10 at 12pt,
+ sy=cmbsy10 at 12pt]
+
+ \definebodyfont [11pt] [mm]
+ [mr=xcmb10 at 11pt,
+ ex=cmex10 at 11pt,
+ mi=cmmib10 at 11pt,
+ sy=cmbsy10 at 11pt]
+
+ \definebodyfont [10pt] [mm]
+ [mr=xcmb10,
+ ex=cmex10,
+ mi=cmmib10,
+ sy=cmbsy10]
+
+ \definebodyfont [9pt] [mm]
+ [mr=xcmb9,
+ ex=cmex10 at 9pt,
+ mi=cmmib10 at 9pt,
+ sy=cmbsy10 at 9pt]
+
+ \definebodyfont [8pt] [mm]
+ [mr=xcmb8,
+ ex=cmex10 at 8pt,
+ mi=cmmib7 at 8pt,
+ sy=cmbsy7 at 8pt]
+
+ \definebodyfont [7pt] [mm]
+ [mr=xcmb7,
+ ex=cmex10 at 7pt,
+ mi=cmmib7,
+ sy=cmbsy7]
+
+ \definebodyfont [6pt] [mm]
+ [mr=xcmb6,
+ ex=cmex10 at 6pt,
+ mi=cmmib5 at 6pt,
+ sy=cmbsy5 at 6pt]
+
+ \definebodyfont [5pt] [mm]
+ [mr=xcmb5,
+ ex=cmex10 at 5pt,
+ mi=cmmib5,
+ sy=cmbsy5]
+
+ \definebodyfont [4pt] [mm]
+ [mr=xcmb5 at 4pt,
+ ex=cmex10 at 4pt,
+ mi=cmmib5 at 4pt,
+ sy=cmbsy5 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
+ [mr=xcmb12 sa 1,
+ ex=cmex10 sa 1,
+ mi=cmmib10 sa 1,
+ sy=cmbsy10 sa 1]
+
+\stoptypescript
+
+\starttypescript [bfmath] [modern,computer-modern,latin-modern] [size]
+
+% hack to prevent mapping of filenames, watch the space!
+
+ \definefontsynonym[xcmb12][cmbx12 ]
+ \definefontsynonym[xcmb10][cmbx10 ]
+ \definefontsynonym[xcmb9] [cmbx9 ]
+ \definefontsynonym[xcmb8] [cmbx8 ]
+ \definefontsynonym[xcmb7] [cmbx7 ]
+ \definefontsynonym[xcmb6] [cmbx6 ]
+ \definefontsynonym[xcmb5] [cmbx5 ]
+
+ \definebodyfont [12pt] [mm]
+ [mrbf=xcmb12,
+ exbf=cmex10 at 12pt,
+ mibf=cmmib10 at 12pt,
+ sybf=cmbsy10 at 12pt]
+
+ \definebodyfont [11pt] [mm]
+ [mrbf=xcmb10 at 11pt,
+ exbf=cmex10 at 11pt,
+ mibf=cmmib10 at 11pt,
+ sybf=cmbsy10 at 11pt]
+
+ \definebodyfont [10pt] [mm]
+ [mrbf=xcmb10,
+ exbf=cmex10,
+ mibf=cmmib10,
+ sybf=cmbsy10]
+
+ \definebodyfont [9pt] [mm]
+ [mrbf=xcmb9,
+ exbf=cmex10 at 9pt,
+ mibf=cmmib10 at 9pt,
+ sybf=cmbsy10 at 9pt]
+
+ \definebodyfont [8pt] [mm]
+ [mrbf=xcmb8,
+ exbf=cmex10 at 8pt,
+ mibf=cmmib7 at 8pt,
+ sybf=cmbsy7 at 8pt]
+
+ \definebodyfont [7pt] [mm]
+ [mrbf=xcmb7,
+ exbf=cmex10 at 7pt,
+ mibf=cmmib7,
+ sybf=cmbsy7]
+
+ \definebodyfont [6pt] [mm]
+ [mrbf=xcmb6,
+ exbf=cmex10 at 6pt,
+ mibf=cmmib5 at 6pt,
+ sybf=cmbsy5 at 6pt]
+
+ \definebodyfont [5pt] [mm]
+ [mrbf=xcmb5,
+ exbf=cmex10 at 5pt,
+ mibf=cmmib5,
+ sybf=cmbsy5]
+
+ \definebodyfont [4pt] [mm]
+ [mrbf=xcmb5 at 4pt,
+ exbf=cmex10 at 4pt,
+ mibf=cmmib5 at 4pt,
+ sybf=cmbsy5 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
+ [mrbf=xcmb12 sa 1,
+ exbf=cmex10 sa 1,
+ mibf=cmmib10 sa 1,
+ sybf=cmbsy10 sa 1]
+
+\stoptypescript
+
+\starttypescript [serif] [concrete] [size]
+
+ \definebodyfont [10pt,11pt,12pt,14.4pt,17.3pt] [rm]
+ [tf=ccr10 sa 1,
+ it=ccti10 sa 1,
+ sl=ccsl10 sa 1,
+ sc=cccsc10 sa 1]
+
+ \definebodyfont [5pt,6pt,7pt,8pt,9pt] [rm]
+ [it=ccr9 sa 1,
+ sl=ccr9 sa 1,
+ sc=ccr9 sa 1]
+
+ \definebodyfont [9pt] [rm] [tf=ccr9]
+ \definebodyfont [8pt] [rm] [tf=ccr8]
+ \definebodyfont [7pt] [rm] [tf=ccr7]
+ \definebodyfont [6pt] [rm] [tf=ccr6]
+ \definebodyfont [5pt] [rm] [tf=ccr5]
+
+\stoptypescript
+
+\starttypescript [math] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mr=zeurm10 sa 1,
+ ex=zeuex10 sa 1,
+ sy=zeusm10 sa 1,
+ mi=eufm10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mr=zeurm7 sa 1,
+ sy=zeusm7 sa 1,
+ mi=eufm7 sa 1,
+ ex=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mr=zeurm5,
+ sy=zeusm5,
+ mi=eufm5,
+ ex=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [bfmath] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mrbf=zeurb10 sa 1,
+ exbf=zeuex10 sa 1,
+ sybf=zeusb10 sa 1,
+ mibf=eufb10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mrbf=zeurb7 sa 1,
+ sybf=zeusb7 sa 1,
+ mibf=eufb7 sa 1,
+ exbf=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mrbf=zeurb5,
+ sybf=zeusb5,
+ mibf=eufb5,
+ exbf=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [boldmath] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mr=zeurb10 sa 1,
+ ex=zeuex10 sa 1,
+ sy=zeusb10 sa 1,
+ mi=eufb10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mr=zeurb7 sa 1,
+ sy=zeusb7 sa 1,
+ mi=eufb7 sa 1,
+ ex=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mr=zeurb5,
+ sy=zeusb5,
+ mi=eufb5,
+ ex=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [math] [modern,computer-modern,latin-modern,ams] [size]
+ \definebodyfont [17.3pt,14.4pt,12pt,11pt,10pt,9pt] [mm]
+ [ma=msam10 sa 1,
+ mb=msbm10 sa 1]
+ \definebodyfont [8pt,7pt] [mm]
+ [ma=msam7 sa 1,
+ mb=msbm7 sa 1]
+ \definebodyfont [6pt,5pt,4pt] [mm]
+ [ma=msam5 sa 1,
+ mb=msbm5 sa 1]
+\stoptypescript
+
+\starttypescript [math] [times] [size]
+
+ \mapfontsize [5pt] [6.0pt]
+ \mapfontsize [6pt] [6.8pt]
+ \mapfontsize [7pt] [7.6pt]
+ \mapfontsize [8pt] [8.4pt]
+ \mapfontsize [9pt] [9.2pt]
+ \mapfontsize [10pt] [10pt]
+ \mapfontsize [11pt] [10.8pt]
+ \mapfontsize [12pt] [11.6pt]
+ \mapfontsize [14.4pt] [13.2pt]
+
+\stoptypescript
+
+\stoptypescriptcollection
+
+\endinput
diff --git a/tex/context/base/type-siz.mkiv b/tex/context/base/type-siz.mkiv
new file mode 100644
index 000000000..2c234e86a
--- /dev/null
+++ b/tex/context/base/type-siz.mkiv
@@ -0,0 +1,375 @@
+%D \module
+%D [ file=type-siz,
+%D version=2001.04.12,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=Sizing scripts,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+\starttypescriptcollection[size-mkiv]
+
+% todo: instead of assuming designsize we will set it explicitly (saves these
+% -1000 problems at the lua end)
+
+% cmr
+
+\starttypescript [serif] [computer-modern] [size]
+
+ \definebodyfont [12pt] [rm]
+ [tf=cmr12,
+ bf=cmbx12,
+ it=cmti12,
+ sl=cmsl12,
+ bi=cmbxti10 at 12pt,
+ bs=cmbxsl10 at 12pt,
+ sc=cmcsc10 at 12pt]
+
+ \definebodyfont [11pt] [rm]
+ [tf=cmr10 at 11pt,
+ bf=cmbx10 at 11pt,
+ sl=cmsl10 at 11pt,
+ it=cmti10 at 11pt,
+ bi=cmbxti10 at 11pt,
+ bs=cmbxsl10 at 11pt,
+ sc=cmcsc10 at 11pt]
+
+ \definebodyfont [10pt] [rm]
+ [tf=cmr10,
+ bf=cmbx10,
+ it=cmti10,
+ sl=cmsl10,
+ bi=cmbxti10,
+ bs=cmbxsl10,
+ sc=cmcsc10]
+
+ \definebodyfont [9pt] [rm]
+ [tf=cmr9,
+ bf=cmbx9,
+ it=cmti9,
+ sl=cmsl9,
+ bi=cmbxti10 at 9pt,
+ bs=cmbxsl10 at 9pt,
+ sc=cmcsc10 at 9pt]
+
+ \definebodyfont [8pt] [rm]
+ [tf=cmr8,
+ bf=cmbx8,
+ it=cmti8,
+ sl=cmsl8,
+ bi=cmbxti10 at 8pt,
+ bs=cmbxsl10 at 8pt,
+ sc=cmcsc10 at 8pt]
+
+ \definebodyfont [7pt] [rm]
+ [tf=cmr7,
+ bf=cmbx7,
+ it=cmti10 at 7pt,
+ sl=cmsl10 at 7pt,
+ bi=cmbxti10 at 7pt,
+ bs=cmbxsl10 at 7pt,
+ sc=cmcsc10 at 7pt]
+
+ \definebodyfont [6pt] [rm]
+ [tf=cmr6,
+ bf=cmbx6,
+ it=cmti10 at 6pt,
+ sl=cmsl10 at 6pt,
+ bi=cmbxti10 at 6pt,
+ bs=cmbxsl10 at 6pt,
+ sc=cmcsc10 at 6pt]
+
+ \definebodyfont [5pt] [rm]
+ [tf=cmr5,
+ bf=cmbx5,
+ it=cmti10 at 5pt,
+ sl=cmsl10 at 5pt,
+ bi=cmbxti10 at 5pt,
+ bs=cmbxsl10 at 5pt,
+ sc=cmcsc10 at 5pt]
+
+ \definebodyfont [4pt] [rm]
+ [tf=cmr10 at 4pt,
+ bf=cmbx10 at 4pt,
+ it=cmti10 at 4pt,
+ sl=cmsl10 at 4pt,
+ bi=cmbxti10 at 4pt,
+ bs=cmbxsl10 at 4pt,
+ sc=cmr10 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [rm]
+ [tf=cmr12 sa 1,
+ bf=cmbx12 sa 1,
+ it=cmti12 sa 1,
+ sl=cmsl12 sa 1,
+ bi=cmbxti10 sa 1,
+ bs=cmbxsl10 sa 1,
+ sc=cmcsc10 sa 1]
+
+\stoptypescript
+
+\starttypescript [sans] [computer-modern] [size]
+
+ \definebodyfont [12pt] [ss]
+ [tf=cmss12,
+ bf=cmssbx10 at 12pt,
+ it=cmssi12,
+ sl=cmssi12,
+ bi=cmssbx10 at 12pt,
+ bs=cmssbx10 at 12pt,
+ sc=cmss10 at 12pt]
+
+ \definebodyfont [11pt] [ss]
+ [tf=cmss10 at 11pt,
+ bf=cmssbx10 at 11pt,
+ it=cmssi10 at 11pt,
+ sl=cmssi10 at 11pt,
+ bi=cmssbx10 at 11pt,
+ bs=cmssbx10 at 11pt,
+ sc=cmss10 at 11pt]
+
+ \definebodyfont [10pt] [ss]
+ [tf=cmss10,
+ bf=cmssbx10,
+ it=cmssi10,
+ sl=cmssi10,
+ bi=cmssbx10,
+ bs=cmssbx10,
+ sc=cmss10]
+
+ \definebodyfont [9pt] [ss]
+ [tf=cmss9,
+ bf=cmssbx10 at 9pt,
+ it=cmssi9,
+ sl=cmssi9,
+ bi=cmssbx10 at 9pt,
+ bs=cmssbx10 at 9pt,
+ sc=cmss9]
+
+ \definebodyfont [8pt] [ss]
+ [tf=cmss8,
+ bf=cmssbx10 at 8pt,
+ it=cmssi8,
+ sl=cmssi8,
+ bi=cmssbx10 at 8pt,
+ bs=cmssbx10 at 8pt,
+ sc=cmss8]
+
+ \definebodyfont [7pt] [ss]
+ [tf=cmss10 at 7pt,
+ bf=cmssbx10 at 7pt,
+ it=cmssi10 at 7pt,
+ sl=cmssi10 at 7pt,
+ bs=cmssbx10 at 7pt,
+ bi=cmssbx10 at 7pt,
+ sc=cmss10 at 7pt]
+
+ \definebodyfont [6pt] [ss]
+ [tf=cmss10 at 6pt,
+ bf=cmssbx10 at 6pt,
+ it=cmssi10 at 6pt,
+ sl=cmssi10 at 6pt,
+ bs=cmssbx10 at 6pt,
+ bi=cmssbx10 at 6pt,
+ sc=cmss10 at 6pt]
+
+ \definebodyfont [5pt] [ss]
+ [tf=cmss10 at 5pt,
+ bf=cmssbx10 at 5pt,
+ it=cmssi10 at 5pt,
+ sl=cmssi10 at 5pt,
+ bs=cmssbx10 at 5pt,
+ bi=cmssbx10 at 5pt,
+ sc=cmss10 at 5pt]
+
+ \definebodyfont [4pt] [ss]
+ [tf=cmss10 at 4pt,
+ bf=cmssbx10 at 4pt,
+ it=cmssi10 at 4pt,
+ sl=cmssi10 at 4pt,
+ bs=cmssbx10 at 4pt,
+ bi=cmssbx10 at 4pt,
+ sc=cmss10 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [ss]
+ [tf=cmss12 sa 1,
+ bf=cmssbx10 sa 1,
+ it=cmssi12 sa 1,
+ sl=cmssi12 sa 1,
+ bi=cmssbx10 sa 1,
+ bs=cmssbx10 sa 1,
+ sc=cmss12 sa 1]
+
+\stoptypescript
+
+\starttypescript [mono] [computer-modern] [size]
+
+ \definebodyfont [12pt] [tt]
+ [tf=cmtt12,
+ sl=cmsltt10 at 12pt,
+ it=cmitt10 at 12pt,
+ sc=cmtcsc10 at 12pt]
+
+ \definebodyfont [9pt] [tt]
+ [tf=cmtt9,
+ sl=cmsltt10 at 9pt,
+ it=cmitt10 at 9pt,
+ sc=cmtcsc10 at 9pt]
+
+ \definebodyfont [8pt] [tt]
+ [tf=cmtt8,
+ sl=cmsltt10 at 8pt,
+ it=cmitt10 at 8pt,
+ sc=cmtcsc10 at 8pt]
+
+ \definebodyfont [11pt,10pt,7pt,6pt,5pt,4pt] [tt]
+ [tf=cmtt10 sa 1,
+ sl=cmsltt10 sa 1,
+ it=cmitt10 sa 1,
+ sc=cmtcsc10 sa 1]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [tt]
+ [tf=cmtt12 sa 1,
+ sl=cmsltt10 sa 1,
+ it=cmitt10 sa 1,
+ sc=cmtcsc10 sa 1]
+
+\stoptypescript
+
+\starttypescript [math] [modern,computer-modern,latin-modern] [size]
+
+ \definebodyfont [12pt] [mm]
+ [mr=xcmr12]
+
+ \definebodyfont [11pt] [mm]
+ [mr=xcmr10 at 11pt]
+
+ \definebodyfont [10pt] [mm]
+ [mr=xcmr10]
+
+ \definebodyfont [9pt] [mm]
+ [mr=xcmr9]
+
+ \definebodyfont [8pt] [mm]
+ [mr=xcmr8]
+
+ \definebodyfont [7pt] [mm]
+ [mr=xcmr7]
+
+ \definebodyfont [6pt] [mm]
+ [mr=xcmr6]
+
+ \definebodyfont [5pt] [mm]
+ [mr=xcmr5]
+
+ \definebodyfont [4pt] [mm]
+ [mr=xcmr5 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
+ [mr=xcmr12 sa 1]
+
+\stoptypescript
+
+\starttypescript [boldmath] [modern,computer-modern,latin-modern] [size]
+
+ \definebodyfont [12pt] [mm] [mr=xcmb12]
+ \definebodyfont [11pt] [mm] [mr=xcmb10 at 11pt]
+ \definebodyfont [10pt] [mm] [mr=xcmb10]
+ \definebodyfont [9pt] [mm] [mr=xcmb9]
+ \definebodyfont [8pt] [mm] [mr=xcmb8]
+ \definebodyfont [7pt] [mm] [mr=xcmb7]
+ \definebodyfont [6pt] [mm] [mr=xcmb6]
+ \definebodyfont [5pt] [mm] [mr=xcmb5]
+ \definebodyfont [4pt] [mm] [mr=xcmb5 at 4pt]
+
+ \definebodyfont [14.4pt,17.3pt,20.7pt] [mm] [mr=xcmb12 sa 1]
+
+\stoptypescript
+
+\starttypescript [math] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mr=zeurm10 sa 1,
+ ex=zeuex10 sa 1,
+ sy=zeusm10 sa 1,
+ mi=eufm10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mr=zeurm7 sa 1,
+ sy=zeusm7 sa 1,
+ mi=eufm7 sa 1,
+ ex=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mr=zeurm5,
+ sy=zeusm5,
+ mi=eufm5,
+ ex=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [bfmath] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mrbf=zeurb10 sa 1,
+ exbf=zeuex10 sa 1,
+ sybf=zeusb10 sa 1,
+ mibf=eufb10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mrbf=zeurb7 sa 1,
+ sybf=zeusb7 sa 1,
+ mibf=eufb7 sa 1,
+ exbf=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mrbf=zeurb5,
+ sybf=zeusb5,
+ mibf=eufb5,
+ exbf=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [boldmath] [euler] [size]
+
+ \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
+ [mr=zeurb10 sa 1,
+ ex=zeuex10 sa 1,
+ sy=zeusb10 sa 1,
+ mi=eufb10 sa 1]
+
+ \definebodyfont [6pt,7pt,8pt] [mm]
+ [mr=zeurb7 sa 1,
+ sy=zeusb7 sa 1,
+ mi=eufb7 sa 1,
+ ex=zeuex10 sa 1]
+
+ \definebodyfont [5pt] [mm]
+ [mr=zeurb5,
+ sy=zeusb5,
+ mi=eufb5,
+ ex=zeuex10 at 5pt]
+
+\stoptypescript
+
+\starttypescript [math] [times] [size]
+
+ \mapfontsize [5pt] [6.0pt]
+ \mapfontsize [6pt] [6.8pt]
+ \mapfontsize [7pt] [7.6pt]
+ \mapfontsize [8pt] [8.4pt]
+ \mapfontsize [9pt] [9.2pt]
+ \mapfontsize [10pt] [10pt]
+ \mapfontsize [11pt] [10.8pt]
+ \mapfontsize [12pt] [11.6pt]
+ \mapfontsize [14.4pt] [13.2pt]
+
+\stoptypescript
+
+\stoptypescriptcollection
+
+\endinput
diff --git a/tex/context/base/type-siz.tex b/tex/context/base/type-siz.tex
index c5a8753ca..56b54b301 100644
--- a/tex/context/base/type-siz.tex
+++ b/tex/context/base/type-siz.tex
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% we need to use proper verbose names, which saves us a resolve
+
\unprotect
\starttypescriptcollection[size]
@@ -168,688 +170,10 @@
[mm] [default]
\stoptypescript
-% todo: instead of assuming designsize we will set it explicitly (saves these
-% -1000 problems at the lua end)
-
-% cmr
-
-\starttypescript [serif] [computer-modern] [size]
-
- \definebodyfont [12pt] [rm]
- [tf=cmr12,
- bf=cmbx12,
- it=cmti12,
- sl=cmsl12,
- bi=cmbxti10 at 12pt,
- bs=cmbxsl10 at 12pt,
- sc=cmcsc10 at 12pt]
-
- \definebodyfont [11pt] [rm]
- [tf=cmr10 at 11pt,
- bf=cmbx10 at 11pt,
- sl=cmsl10 at 11pt,
- it=cmti10 at 11pt,
- bi=cmbxti10 at 11pt,
- bs=cmbxsl10 at 11pt,
- sc=cmcsc10 at 11pt]
-
- \definebodyfont [10pt] [rm]
- [tf=cmr10,
- bf=cmbx10,
- it=cmti10,
- sl=cmsl10,
- bi=cmbxti10,
- bs=cmbxsl10,
- sc=cmcsc10]
-
- \definebodyfont [9pt] [rm]
- [tf=cmr9,
- bf=cmbx9,
- it=cmti9,
- sl=cmsl9,
- bi=cmbxti10 at 9pt,
- bs=cmbxsl10 at 9pt,
- sc=cmcsc10 at 9pt]
-
- \definebodyfont [8pt] [rm]
- [tf=cmr8,
- bf=cmbx8,
- it=cmti8,
- sl=cmsl8,
- bi=cmbxti10 at 8pt,
- bs=cmbxsl10 at 8pt,
- sc=cmcsc10 at 8pt]
-
- \definebodyfont [7pt] [rm]
- [tf=cmr7,
- bf=cmbx7,
- it=cmti10 at 7pt,
- sl=cmsl10 at 7pt,
- bi=cmbxti10 at 7pt,
- bs=cmbxsl10 at 7pt,
- sc=cmcsc10 at 7pt]
-
- \definebodyfont [6pt] [rm]
- [tf=cmr6,
- bf=cmbx6,
- it=cmti10 at 6pt,
- sl=cmsl10 at 6pt,
- bi=cmbxti10 at 6pt,
- bs=cmbxsl10 at 6pt,
- sc=cmcsc10 at 6pt]
-
- \definebodyfont [5pt] [rm]
- [tf=cmr5,
- bf=cmbx5,
- it=cmti10 at 5pt,
- sl=cmsl10 at 5pt,
- bi=cmbxti10 at 5pt,
- bs=cmbxsl10 at 5pt,
- sc=cmcsc10 at 5pt]
-
- \definebodyfont [4pt] [rm]
- [tf=cmr10 at 4pt,
- bf=cmbx10 at 4pt,
- it=cmti10 at 4pt,
- sl=cmsl10 at 4pt,
- bi=cmbxti10 at 4pt,
- bs=cmbxsl10 at 4pt,
- sc=cmr10 at 4pt]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [rm]
- [tf=cmr12 sa 1,
- bf=cmbx12 sa 1,
- it=cmti12 sa 1,
- sl=cmsl12 sa 1,
- bi=cmbxti10 sa 1,
- bs=cmbxsl10 sa 1,
- sc=cmcsc10 sa 1]
-
-\stoptypescript
-
-\starttypescript [sans] [computer-modern] [size]
-
- \definebodyfont [12pt] [ss]
- [tf=cmss12,
- bf=cmssbx10 at 12pt,
- it=cmssi12,
- sl=cmssi12,
- bi=cmssbx10 at 12pt,
- bs=cmssbx10 at 12pt,
- sc=cmss10 at 12pt]
-
- \definebodyfont [11pt] [ss]
- [tf=cmss10 at 11pt,
- bf=cmssbx10 at 11pt,
- it=cmssi10 at 11pt,
- sl=cmssi10 at 11pt,
- bi=cmssbx10 at 11pt,
- bs=cmssbx10 at 11pt,
- sc=cmss10 at 11pt]
-
- \definebodyfont [10pt] [ss]
- [tf=cmss10,
- bf=cmssbx10,
- it=cmssi10,
- sl=cmssi10,
- bi=cmssbx10,
- bs=cmssbx10,
- sc=cmss10]
-
- \definebodyfont [9pt] [ss]
- [tf=cmss9,
- bf=cmssbx10 at 9pt,
- it=cmssi9,
- sl=cmssi9,
- bi=cmssbx10 at 9pt,
- bs=cmssbx10 at 9pt,
- sc=cmss9]
-
- \definebodyfont [8pt] [ss]
- [tf=cmss8,
- bf=cmssbx10 at 8pt,
- it=cmssi8,
- sl=cmssi8,
- bi=cmssbx10 at 8pt,
- bs=cmssbx10 at 8pt,
- sc=cmss8]
-
- \definebodyfont [7pt] [ss]
- [tf=cmss10 at 7pt,
- bf=cmssbx10 at 7pt,
- it=cmssi10 at 7pt,
- sl=cmssi10 at 7pt,
- bs=cmssbx10 at 7pt,
- bi=cmssbx10 at 7pt,
- sc=cmss10 at 7pt]
-
- \definebodyfont [6pt] [ss]
- [tf=cmss10 at 6pt,
- bf=cmssbx10 at 6pt,
- it=cmssi10 at 6pt,
- sl=cmssi10 at 6pt,
- bs=cmssbx10 at 6pt,
- bi=cmssbx10 at 6pt,
- sc=cmss10 at 6pt]
-
- \definebodyfont [5pt] [ss]
- [tf=cmss10 at 5pt,
- bf=cmssbx10 at 5pt,
- it=cmssi10 at 5pt,
- sl=cmssi10 at 5pt,
- bs=cmssbx10 at 5pt,
- bi=cmssbx10 at 5pt,
- sc=cmss10 at 5pt]
-
- \definebodyfont [4pt] [ss]
- [tf=cmss10 at 4pt,
- bf=cmssbx10 at 4pt,
- it=cmssi10 at 4pt,
- sl=cmssi10 at 4pt,
- bs=cmssbx10 at 4pt,
- bi=cmssbx10 at 4pt,
- sc=cmss10 at 4pt]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [ss]
- [tf=cmss12 sa 1,
- bf=cmssbx10 sa 1,
- it=cmssi12 sa 1,
- sl=cmssi12 sa 1,
- bi=cmssbx10 sa 1,
- bs=cmssbx10 sa 1,
- sc=cmss12 sa 1]
-
-\stoptypescript
-
-\starttypescript [mono] [computer-modern] [size]
-
- \definebodyfont [12pt] [tt]
- [tf=cmtt12,
- sl=cmsltt10 at 12pt,
- it=cmitt10 at 12pt,
- sc=cmtcsc10 at 12pt]
-
- \definebodyfont [9pt] [tt]
- [tf=cmtt9,
- sl=cmsltt10 at 9pt,
- it=cmitt10 at 9pt,
- sc=cmtcsc10 at 9pt]
-
- \definebodyfont [8pt] [tt]
- [tf=cmtt8,
- sl=cmsltt10 at 8pt,
- it=cmitt10 at 8pt,
- sc=cmtcsc10 at 8pt]
-
- \definebodyfont [11pt,10pt,7pt,6pt,5pt,4pt] [tt]
- [tf=cmtt10 sa 1,
- sl=cmsltt10 sa 1,
- it=cmitt10 sa 1,
- sc=cmtcsc10 sa 1]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [tt]
- [tf=cmtt12 sa 1,
- sl=cmsltt10 sa 1,
- it=cmitt10 sa 1,
- sc=cmtcsc10 sa 1]
-
-\stoptypescript
-
-\starttypescript [math] [modern,computer-modern,latin-modern] [size]
-
- % hack to prevent mapping of filenames, watch the space! before
- % latin modern came aroudn we needed this trick to make sure that
- % we loaded the raw cmr12 etc instead of the ones mapped onto
- % an encoding
-
- % \definefontsynonym[xcmr12][cmr12 ]
- % \definefontsynonym[xcmr10][cmr10 ]
- % \definefontsynonym[xcmr9] [cmr9 ]
- % \definefontsynonym[xcmr8] [cmr8 ]
- % \definefontsynonym[xcmr7] [cmr7 ]
- % \definefontsynonym[xcmr6] [cmr6 ]
- % \definefontsynonym[xcmr5] [cmr5 ]
-
- \definebodyfont [12pt] [mm]
- [mr=xcmr12,
- ex=cmex10 at 12pt,
- mi=cmmi12,
- sy=cmsy10 at 12pt]
-
- \definebodyfont [11pt] [mm]
- [mr=xcmr10 at 11pt,
- ex=cmex10 at 11pt,
- mi=cmmi10 at 11pt,
- sy=cmsy10 at 11pt]
-
- \definebodyfont [10pt] [mm]
- [mr=xcmr10,
- ex=cmex10,
- mi=cmmi10,
- sy=cmsy10]
-
- \definebodyfont [9pt] [mm]
- [mr=xcmr9,
- ex=cmex10 at 9pt,
- mi=cmmi9,
- sy=cmsy9]
-
- \definebodyfont [8pt] [mm]
- [mr=xcmr8,
- ex=cmex10 at 8pt,
- mi=cmmi8,
- sy=cmsy8]
-
- \definebodyfont [7pt] [mm]
- [mr=xcmr7,
- ex=cmex10 at 7pt,
- mi=cmmi7,
- sy=cmsy7]
-
- \definebodyfont [6pt] [mm]
- [mr=xcmr6,
- ex=cmex10 at 6pt,
- mi=cmmi6,
- sy=cmsy6]
-
- \definebodyfont [5pt] [mm]
- [mr=xcmr5,
- ex=cmex10 at 5pt,
- mi=cmmi5,
- sy=cmsy5]
-
- \definebodyfont [4pt] [mm]
- [mr=xcmr5 at 4pt,
- ex=cmex10 at 4pt,
- mi=cmmi5 at 4pt,
- sy=cmsy5 at 4pt]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
- [mr=xcmr12 sa 1,
- ex=cmex10 sa 1,
- mi=cmmi12 sa 1,
- sy=cmsy10 sa 1]
-
-\stoptypescript
-
-\starttypescript [boldmath] [modern,computer-modern,latin-modern] [size]
-
-% hack to prevent mapping of filenames, watch the space!
-
- \definefontsynonym[xcmb12][cmbx12 ]
- \definefontsynonym[xcmb10][cmbx10 ]
- \definefontsynonym[xcmb9] [cmbx9 ]
- \definefontsynonym[xcmb8] [cmbx8 ]
- \definefontsynonym[xcmb7] [cmbx7 ]
- \definefontsynonym[xcmb6] [cmbx6 ]
- \definefontsynonym[xcmb5] [cmbx5 ]
-
- \definebodyfont [12pt] [mm]
- [mr=xcmb12,
- ex=cmex10 at 12pt,
- mi=cmmib10 at 12pt,
- sy=cmbsy10 at 12pt]
-
- \definebodyfont [11pt] [mm]
- [mr=xcmb10 at 11pt,
- ex=cmex10 at 11pt,
- mi=cmmib10 at 11pt,
- sy=cmbsy10 at 11pt]
-
- \definebodyfont [10pt] [mm]
- [mr=xcmb10,
- ex=cmex10,
- mi=cmmib10,
- sy=cmbsy10]
-
- \definebodyfont [9pt] [mm]
- [mr=xcmb9,
- ex=cmex10 at 9pt,
- mi=cmmib10 at 9pt,
- sy=cmbsy10 at 9pt]
-
- \definebodyfont [8pt] [mm]
- [mr=xcmb8,
- ex=cmex10 at 8pt,
- mi=cmmib7 at 8pt,
- sy=cmbsy7 at 8pt]
-
- \definebodyfont [7pt] [mm]
- [mr=xcmb7,
- ex=cmex10 at 7pt,
- mi=cmmib7,
- sy=cmbsy7]
-
- \definebodyfont [6pt] [mm]
- [mr=xcmb6,
- ex=cmex10 at 6pt,
- mi=cmmib5 at 6pt,
- sy=cmbsy5 at 6pt]
-
- \definebodyfont [5pt] [mm]
- [mr=xcmb5,
- ex=cmex10 at 5pt,
- mi=cmmib5,
- sy=cmbsy5]
-
- \definebodyfont [4pt] [mm]
- [mr=xcmb5 at 4pt,
- ex=cmex10 at 4pt,
- mi=cmmib5 at 4pt,
- sy=cmbsy5 at 4pt]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
- [mr=xcmb12 sa 1,
- ex=cmex10 sa 1,
- mi=cmmib10 sa 1,
- sy=cmbsy10 sa 1]
-
-\stoptypescript
-
-\starttypescript [bfmath] [modern,computer-modern,latin-modern] [size]
-
-% hack to prevent mapping of filenames, watch the space!
-
- \definefontsynonym[xcmb12][cmbx12 ]
- \definefontsynonym[xcmb10][cmbx10 ]
- \definefontsynonym[xcmb9] [cmbx9 ]
- \definefontsynonym[xcmb8] [cmbx8 ]
- \definefontsynonym[xcmb7] [cmbx7 ]
- \definefontsynonym[xcmb6] [cmbx6 ]
- \definefontsynonym[xcmb5] [cmbx5 ]
-
- \definebodyfont [12pt] [mm]
- [mrbf=xcmb12,
- exbf=cmex10 at 12pt,
- mibf=cmmib10 at 12pt,
- sybf=cmbsy10 at 12pt]
-
- \definebodyfont [11pt] [mm]
- [mrbf=xcmb10 at 11pt,
- exbf=cmex10 at 11pt,
- mibf=cmmib10 at 11pt,
- sybf=cmbsy10 at 11pt]
-
- \definebodyfont [10pt] [mm]
- [mrbf=xcmb10,
- exbf=cmex10,
- mibf=cmmib10,
- sybf=cmbsy10]
-
- \definebodyfont [9pt] [mm]
- [mrbf=xcmb9,
- exbf=cmex10 at 9pt,
- mibf=cmmib10 at 9pt,
- sybf=cmbsy10 at 9pt]
-
- \definebodyfont [8pt] [mm]
- [mrbf=xcmb8,
- exbf=cmex10 at 8pt,
- mibf=cmmib7 at 8pt,
- sybf=cmbsy7 at 8pt]
-
- \definebodyfont [7pt] [mm]
- [mrbf=xcmb7,
- exbf=cmex10 at 7pt,
- mibf=cmmib7,
- sybf=cmbsy7]
-
- \definebodyfont [6pt] [mm]
- [mrbf=xcmb6,
- exbf=cmex10 at 6pt,
- mibf=cmmib5 at 6pt,
- sybf=cmbsy5 at 6pt]
-
- \definebodyfont [5pt] [mm]
- [mrbf=xcmb5,
- exbf=cmex10 at 5pt,
- mibf=cmmib5,
- sybf=cmbsy5]
-
- \definebodyfont [4pt] [mm]
- [mrbf=xcmb5 at 4pt,
- exbf=cmex10 at 4pt,
- mibf=cmmib5 at 4pt,
- sybf=cmbsy5 at 4pt]
-
- \definebodyfont [14.4pt,17.3pt,20.7pt] [mm]
- [mrbf=xcmb12 sa 1,
- exbf=cmex10 sa 1,
- mibf=cmmib10 sa 1,
- sybf=cmbsy10 sa 1]
-
-\stoptypescript
-
-\starttypescript [serif] [concrete] [size]
-
- \definebodyfont [10pt,11pt,12pt,14.4pt,17.3pt] [rm]
- [tf=ccr10 sa 1,
- it=ccti10 sa 1,
- sl=ccsl10 sa 1,
- sc=cccsc10 sa 1]
-
- \definebodyfont [5pt,6pt,7pt,8pt,9pt] [rm]
- [it=ccr9 sa 1,
- sl=ccr9 sa 1,
- sc=ccr9 sa 1]
-
- \definebodyfont [9pt] [rm] [tf=ccr9]
- \definebodyfont [8pt] [rm] [tf=ccr8]
- \definebodyfont [7pt] [rm] [tf=ccr7]
- \definebodyfont [6pt] [rm] [tf=ccr6]
- \definebodyfont [5pt] [rm] [tf=ccr5]
-
-\stoptypescript
-
-% \starttypescript [serif] [fourier] [size] % experimental
-
-% \definebodyfont
-% [17.3pt,14.4pt,12pt,11pt,10pt,9pt,8pt,7pt,6pt,5pt,4pt]
-% [rm]
-% [bc=SerifBoldCaps sa 1,
-% bca=SerifBoldCaps sa a,
-% bcb=SerifBoldCaps sa b,
-% bcc=SerifBoldCaps sa c,
-% bcd=SerifBoldCaps sa d,
-% bcx=SerifBoldCaps sa x,
-% bcxx=SerifBoldCaps sa xx]
-
-% \stoptypescript
-
-% \starttypescript [serif] [fourier-expert] [size] % experimental
-
-% \definebodyfont
-% [17.3pt,14.4pt,12pt,11pt,10pt,9pt,8pt,7pt,6pt,5pt,4pt]
-% [rm]
-% [tf=Serif-Expert sa 1,
-% it=SerifItalic-Expert sa 1,
-% sl=SerifSlanted-Expert sa 1,
-% sc=SerifCaps-Expert sa 1,
-% db=SerifSemiBold-Expert sa 1,
-% dba=SerifSemiBold-Expert sa a,
-% dbb=SerifSemiBold-Expert sa b,
-% dbc=SerifSemiBold-Expert sa c,
-% dbd=SerifSemiBold-Expert sa d,
-% dbx=SerifSemiBold-Expert sa x,
-% dbxx=SerifSemiBold-Expert sa xx,
-% di=SerifSemiItalic-Expert sa 1,
-% dia=SerifSemiItalic-Expert sa a,
-% dib=SerifSemiItalic-Expert sa b,
-% dic=SerifSemiItalic-Expert sa c,
-% did=SerifSemiItalic-Expert sa d,
-% dix=SerifSemiItalic-Expert sa x,
-% dixx=SerifSemiItalic-Expert sa xx,
-% ds=SerifSemiSlanted-Expert sa 1,
-% dsa=SerifSemiSlanted-Expert sa a,
-% dsb=SerifSemiSlanted-Expert sa b,
-% dsc=SerifSemiSlanted-Expert sa c,
-% dsd=SerifSemiSlanted-Expert sa d,
-% dsx=SerifSemiSlanted-Expert sa x,
-% dsxx=SerifSemiSlanted-Expert sa xx,
-% dc=SerifSemiCaps-Expert sa 1,
-% dca=SerifSemiCaps-Expert sa a,
-% dcb=SerifSemiCaps-Expert sa b,
-% dcc=SerifSemiCaps-Expert sa c,
-% dcd=SerifSemiCaps-Expert sa d,
-% dcx=SerifSemiCaps-Expert sa x,
-% dcxx=SerifSemiCaps-Expert sa xx,
-% bf=SerifBold-Expert sa 1,
-% bi=SerifBoldItalic-Expert sa 1,
-% bs=SerifBoldSlanted-Expert sa 1,
-% eb=SerifBlack-Expert sa 1,
-% eba=SerifBlack-Expert sa a,
-% ebb=SerifBlack-Expert sa b,
-% ebc=SerifBlack-Expert sa c,
-% ebd=SerifBlack-Expert sa d,
-% ebx=SerifBlack-Expert sa x,
-% ebxx=SerifBlack-Expert sa xx]
-
-% \stoptypescript
-
-% \starttypescript [serif] [fourier-oldstyle] [size] % experimental
-
-% \definebodyfont
-% [17.3pt,14.4pt,12pt,11pt,10pt,9pt,8pt,7pt,6pt,5pt,4pt]
-% [rm]
-% [tf=Serif-OldStyle sa 1,
-% it=SerifItalic-OldStyle sa 1,
-% sl=SerifSlanted-OldStyle sa 1,
-% sc=SerifCaps-OldStyle sa 1,
-% db=SerifSemiBold-OldStyle sa 1,
-% dba=SerifSemiBold-OldStyle sa a,
-% dbb=SerifSemiBold-OldStyle sa b,
-% dbc=SerifSemiBold-OldStyle sa c,
-% dbd=SerifSemiBold-OldStyle sa d,
-% dbx=SerifSemiBold-OldStyle sa x,
-% dbxx=SerifSemiBold-OldStyle sa xx,
-% di=SerifSemiItalic-OldStyle sa 1,
-% dia=SerifSemiItalic-OldStyle sa a,
-% dib=SerifSemiItalic-OldStyle sa b,
-% dic=SerifSemiItalic-OldStyle sa c,
-% did=SerifSemiItalic-OldStyle sa d,
-% dix=SerifSemiItalic-OldStyle sa x,
-% dixx=SerifSemiItalic-OldStyle sa xx,
-% ds=SerifSemiSlanted-OldStyle sa 1,
-% dsa=SerifSemiSlanted-OldStyle sa a,
-% dsb=SerifSemiSlanted-OldStyle sa b,
-% dsc=SerifSemiSlanted-OldStyle sa c,
-% dsd=SerifSemiSlanted-OldStyle sa d,
-% dsx=SerifSemiSlanted-OldStyle sa x,
-% dsxx=SerifSemiSlanted-OldStyle sa xx,
-% dc=SerifSemiCaps-OldStyle sa 1,
-% dca=SerifSemiCaps-OldStyle sa a,
-% dcb=SerifSemiCaps-OldStyle sa b,
-% dcc=SerifSemiCaps-OldStyle sa c,
-% dcd=SerifSemiCaps-OldStyle sa d,
-% dcx=SerifSemiCaps-OldStyle sa x,
-% dcxx=SerifSemiCaps-OldStyle sa xx,
-% eb=SerifBlack-OldStyle sa 1,
-% eba=SerifBlack-OldStyle sa a,
-% ebb=SerifBlack-OldStyle sa b,
-% ebc=SerifBlack-OldStyle sa c,
-% ebd=SerifBlack-OldStyle sa d,
-% ebx=SerifBlack-OldStyle sa x,
-% ebxx=SerifBlack-OldStyle sa xx,
-% bf=SerifBold-OldStyle sa 1,
-% bi=SerifBoldItalic-OldStyle sa 1,
-% bs=SerifBoldSlanted-OldStyle sa 1]
-
-% \stoptypescript
-
-\starttypescript [math] [euler] [size]
-
- \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
- [mr=zeurm10 sa 1,
- ex=zeuex10 sa 1,
- sy=zeusm10 sa 1,
- mi=eufm10 sa 1]
-
- \definebodyfont [6pt,7pt,8pt] [mm]
- [mr=zeurm7 sa 1,
- sy=zeusm7 sa 1,
- mi=eufm7 sa 1,
- ex=zeuex10 sa 1]
-
- \definebodyfont [5pt] [mm]
- [mr=zeurm5,
- sy=zeusm5,
- mi=eufm5,
- ex=zeuex10 at 5pt]
-
-\stoptypescript
-
-\starttypescript [bfmath] [euler] [size]
-
- \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
- [mrbf=zeurb10 sa 1,
- exbf=zeuex10 sa 1,
- sybf=zeusb10 sa 1,
- mibf=eufb10 sa 1]
-
- \definebodyfont [6pt,7pt,8pt] [mm]
- [mrbf=zeurb7 sa 1,
- sybf=zeusb7 sa 1,
- mibf=eufb7 sa 1,
- exbf=zeuex10 sa 1]
-
- \definebodyfont [5pt] [mm]
- [mrbf=zeurb5,
- sybf=zeusb5,
- mibf=eufb5,
- exbf=zeuex10 at 5pt]
-
-\stoptypescript
-
-\starttypescript [boldmath] [euler] [size]
-
- \definebodyfont [9pt,10pt,11pt,12pt,14.4pt,17.3pt,20.7pt] [mm]
- [mr=zeurb10 sa 1,
- ex=zeuex10 sa 1,
- sy=zeusb10 sa 1,
- mi=eufb10 sa 1]
-
- \definebodyfont [6pt,7pt,8pt] [mm]
- [mr=zeurb7 sa 1,
- sy=zeusb7 sa 1,
- mi=eufb7 sa 1,
- ex=zeuex10 sa 1]
-
- \definebodyfont [5pt] [mm]
- [mr=zeurb5,
- sy=zeusb5,
- mi=eufb5,
- ex=zeuex10 at 5pt]
-
-\stoptypescript
-
-\starttypescript [math] [modern,computer-modern,latin-modern,ams] [size]
- \definebodyfont [17.3pt,14.4pt,12pt,11pt,10pt,9pt] [mm]
- [ma=msam10 sa 1,
- mb=msbm10 sa 1]
- \definebodyfont [8pt,7pt] [mm]
- [ma=msam7 sa 1,
- mb=msbm7 sa 1]
- \definebodyfont [6pt,5pt,4pt] [mm]
- [ma=msam5 sa 1,
- mb=msbm5 sa 1]
-\stoptypescript
-
-% math times
-
-\starttypescript [math] [times] [size]
+\stoptypescriptcollection
- \mapfontsize [5pt] [6.0pt]
- \mapfontsize [6pt] [6.8pt]
- \mapfontsize [7pt] [7.6pt]
- \mapfontsize [8pt] [8.4pt]
- \mapfontsize [9pt] [9.2pt]
- \mapfontsize [10pt] [10pt]
- \mapfontsize [11pt] [10.8pt]
- \mapfontsize [12pt] [11.6pt]
- \mapfontsize [14.4pt] [13.2pt]
+\protect
-\stoptypescript
-
-\stoptypescriptcollection
+\loadmarkfile{type-siz}
-\protect \endinput
+\endinput
diff --git a/tex/context/base/type-syn.tex b/tex/context/base/type-syn.tex
index b7e9335df..554694c6e 100644
--- a/tex/context/base/type-syn.tex
+++ b/tex/context/base/type-syn.tex
@@ -13,7 +13,6 @@
\starttypescriptcollection[synonyms]
-
% Computer Modern Roman : Donald Knuth
% Latin Modern: LM Font Revision Team
diff --git a/tex/context/base/type-tmf.tex b/tex/context/base/type-tmf.tex
index ec3178a34..c2deb8187 100644
--- a/tex/context/base/type-tmf.tex
+++ b/tex/context/base/type-tmf.tex
@@ -90,16 +90,6 @@
% maybe we can by now just use: (to be tested first)
-% \starttypescript [math] [modern,computer-modern,latin-modern] [name]
-% \definefontsynonym[xcmr12][LMRoman-Regular12]
-% \definefontsynonym[xcmr10][LMRoman-Regular10]
-% \definefontsynonym[xcmr9] [LMRoman-Regular9]
-% \definefontsynonym[xcmr8] [LMRoman-Regular8]
-% \definefontsynonym[xcmr7] [LMRoman-Regular7]
-% \definefontsynonym[xcmr6] [LMRoman-Regular6]
-% \definefontsynonym[xcmr5] [LMRoman-Regular5]
-% \stoptypescript
-
\starttypescript [math] [modern,computer-modern,latin-modern] [name]
\definefontsynonym[xcmr12][rm-lmr12]
\definefontsynonym[xcmr10][rm-lmr10]
@@ -1085,6 +1075,99 @@
\definefontsynonym [SerifCapsOsF] [TeXPalladioL-SC]
\stoptypescript
+% TeXGyre
+
+% name definitions & prefixes
+
+\definetypescriptprefix [n:pagella] [TeXGyrePagella] \definetypescriptprefix [n:palatino] [TeXGyrePagella]
+\definetypescriptprefix [n:termes] [TeXGyreTermes] \definetypescriptprefix [n:times] [TeXGyreTermes]
+\definetypescriptprefix [n:heros] [TeXGyreHeros] \definetypescriptprefix [n:helvetica] [TeXGyreHeros]
+\definetypescriptprefix [n:bonum] [TeXGyreBonum] \definetypescriptprefix [n:bookman] [TeXGyreBonum]
+\definetypescriptprefix [n:schola] [TeXGyreSchola] \definetypescriptprefix [n:schoolbook] [TeXGyreSchola]
+\definetypescriptprefix [n:adventor] [TeXGyreAdventor] %definetypescriptprefix [n:adventor] [TeXGyreAdventor]
+\definetypescriptprefix [n:cursor] [TeXGyreCursor] \definetypescriptprefix [n:courier] [TeXGyreCursor]
+\definetypescriptprefix [n:chorus] [TeXGyreChorus] \definetypescriptprefix [n:chancery] [TeXGyreChorus] % not the full set
+
+\starttypescript [serif] [pagella,palatino,termes,times,bonum,bookman,schola,schoolbook] [name]
+ \definefontsynonym [Serif] [\typescriptprefix{n:\typescripttwo}-Regular]
+ \definefontsynonym [SerifItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
+ \definefontsynonym [SerifBold] [\typescriptprefix{n:\typescripttwo}-Bold]
+ \definefontsynonym [SerifBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
+ \definefontsynonym [SerifSlanted] [SerifItalic]
+ \definefontsynonym [SerifBoldSlanted] [SerifBoldItalic]
+ \definefontsynonym [SerifCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
+
+ \definefontvariant [Serif][osf][Caps]
+ \definefontvariant [Serif][sc] [Caps]
+
+ \definefontsynonym [SerifRegular] [Serif]
+ \definefontsynonym [SerifRegularCaps] [SerifCaps]
+ \definefontsynonym [SerifItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
+ \definefontsynonym [SerifBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps]
+ \definefontsynonym [SerifBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
+ \definefontsynonym [SerifSlantedCaps] [SerifItalicCaps]
+ \definefontsynonym [SerifBoldSlantedCaps] [SerifBoldItalicCaps]
+ \definefontsynonym [SerifCapsCaps] [SerifCaps]
+\stoptypescript
+
+\starttypescript [serif] [chorus,chancery] [name]
+ \definefontsynonym [SerifMediumItalic] [TeXGyreChorus-MediumItalic]
+ \definefontsynonym [Serif] [SerifMediumItalic]
+ \definefontsynonym [SerifItalic] [SerifMediumItalic]
+ \definefontsynonym [SerifBold] [SerifMediumItalic]
+ \definefontsynonym [SerifBoldItalic] [SerifMediumItalic]
+ \definefontsynonym [SerifSlanted] [SerifMediumItalic]
+ \definefontsynonym [SerifBoldSlanted] [SerifMediumItalic]
+ \definefontsynonym [SerifCaps] [SerifMediumItalic]
+\stoptypescript
+
+\starttypescript [calligraphy] [chorus,chancery] [name]
+ \definefontsynonym [Calligraphy] [TeXGyreChorus-MediumItalic]
+\stoptypescript
+
+\starttypescript [sans] [heros,helvetica,adventor] [name]
+ \definefontsynonym [Sans] [\typescriptprefix{n:\typescripttwo}-Regular]
+ \definefontsynonym [SansItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
+ \definefontsynonym [SansBold] [\typescriptprefix{n:\typescripttwo}-Bold]
+ \definefontsynonym [SansBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
+ \definefontsynonym [SansSlanted] [SansItalic]
+ \definefontsynonym [SansBoldSlanted] [SansBoldItalic]
+ \definefontsynonym [SansCaps] [\typescriptprefix{n:\typescripttwo}-Caps]
+
+ \definefontvariant [Sans][osf][Caps]
+ \definefontvariant [Sans][sc] [Caps]
+
+ \definefontsynonym [SansRegular] [Sans]
+ \definefontsynonym [SansRegularCaps] [SansCaps]
+ \definefontsynonym [SansItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
+ \definefontsynonym [SansBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps]
+ \definefontsynonym [SansBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
+ \definefontsynonym [SansSlantedCaps] [SansItalicCaps]
+ \definefontsynonym [SansBoldSlantedCaps] [SansBoldItalicCaps]
+ \definefontsynonym [SansCapsCaps] [SansCaps]
+\stoptypescript
+
+\starttypescript [mono] [cursor,courier] [name]
+ \definefontsynonym [Mono] [\typescriptprefix{n:\typescripttwo}-Regular]
+ \definefontsynonym [MonoItalic] [\typescriptprefix{n:\typescripttwo}-Italic]
+ \definefontsynonym [MonoBold] [\typescriptprefix{n:\typescripttwo}-Bold]
+ \definefontsynonym [MonoBoldItalic] [\typescriptprefix{n:\typescripttwo}-BoldItalic]
+ \definefontsynonym [MonoSlanted] [MonoItalic]
+ \definefontsynonym [MonoBoldSlanted] [MonoBoldItalic]
+
+ \definefontvariant [Mono][osf][Caps]
+ \definefontvariant [Mono][sc] [Caps]
+
+ \definefontsynonym [MonoRegular] [Mono]
+ \definefontsynonym [MonoRegularCaps] [MonoCaps]
+ \definefontsynonym [MonoItalicCaps] [\typescriptprefix{n:\typescripttwo}-ItalicCaps]
+ \definefontsynonym [MonoBoldCaps] [\typescriptprefix{n:\typescripttwo}-BoldCaps]
+ \definefontsynonym [MonoBoldItalicCaps] [\typescriptprefix{n:\typescripttwo}-BoldItalicCaps]
+ \definefontsynonym [MonoSlantedCaps] [MonoItalicCaps]
+ \definefontsynonym [MonoBoldSlantedCaps] [MonoBoldItalicCaps]
+ \definefontsynonym [MonoCapsCaps] [MonoCaps]
+\stoptypescript
+
\stoptypescriptcollection
\endinput
diff --git a/tex/context/base/type-win.tex b/tex/context/base/type-win.tex
new file mode 100644
index 000000000..bae89471f
--- /dev/null
+++ b/tex/context/base/type-win.tex
@@ -0,0 +1,120 @@
+%D \module
+%D [ file=type-win,
+%D version=2009.03.10,
+%D title=\CONTEXT\ Typescript Macros,
+%D subtitle=MS Windows Definitions,
+%D author=Vyatcheslav Yatskovsky,
+%D date=\currentdate,
+%D copyright=Vyatcheslav Yatskovsky]
+%C
+%C This module is part of the \CONTEXT\ macro||package. See
+%C mreadme.pdf for details.
+
+\starttypescriptcollection[windows]
+
+\starttypescript [serif] [georgia,palatino,times]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [\typescripttwo-Regular] [features=default]
+ \definefontsynonym [SerifBold] [\typescripttwo-Bold] [features=default]
+ \definefontsynonym [SerifItalic] [\typescripttwo-Italic] [features=default]
+ \definefontsynonym [SerifBoldItalic] [\typescripttwo-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [serif] [sylfaen]
+ \setups[font:fallback:serif]
+ \definefontsynonym [Serif] [\typescripttwo-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arial,trebuchet,verdana]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescripttwo-Regular] [features=default]
+ \definefontsynonym [SansBold] [\typescripttwo-Bold] [features=default]
+ \definefontsynonym [SansItalic] [\typescripttwo-Italic] [features=default]
+ \definefontsynonym [SansBoldItalic] [\typescripttwo-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arialblack,impact,lucidasans,microsans]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescripttwo-Regular] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [comic,tahoma]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescripttwo-Regular] [features=default]
+ \definefontsynonym [SansBold] [\typescripttwo-Bold] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [franklin]
+ \setups[font:fallback:sans]
+ \definefontsynonym [Sans] [\typescripttwo-Regular] [features=default]
+ \definefontsynonym [SansItalic] [\typescripttwo-Italic] [features=default]
+\stoptypescript
+
+\starttypescript [mono] [courier]
+ \setups[font:fallback:mono]
+ \definefontsynonym [Mono] [\typescripttwo-Regular] [features=default]
+ \definefontsynonym [MonoBold] [\typescripttwo-Bold] [features=default]
+ \definefontsynonym [MonoItalic] [\typescripttwo-Italic] [features=default]
+ \definefontsynonym [MonoBoldItalic] [\typescripttwo-BoldItalic] [features=default]
+\stoptypescript
+
+\starttypescript [mono] [lucidaconsole]
+ \setups[font:fallback:mono]
+ \definefontsynonym [Mono] [\typescripttwo-Regular] [features=default]
+\stoptypescript
+
+
+\definetypescriptprefix [f:arial] [Arial]
+\definetypescriptprefix [f:arialblack] [Arial Black]
+\definetypescriptprefix [f:comic] [Comic Sans MS]
+\definetypescriptprefix [f:courier] [Courier New]
+\definetypescriptprefix [f:franklin] [Franklin Gothic Medium]
+\definetypescriptprefix [f:georgia] [Georgia]
+\definetypescriptprefix [f:impact] [Impact]
+\definetypescriptprefix [f:lucidaconsole] [Lucida Console]
+\definetypescriptprefix [f:lucidasans] [Lucida Sans Unicode]
+\definetypescriptprefix [f:microsans] [Microsoft Sans Serif]
+\definetypescriptprefix [f:palatino] [Palatino Linotype]
+\definetypescriptprefix [f:sylfaen] [Sylfaen]
+\definetypescriptprefix [f:tahoma] [Tahoma]
+\definetypescriptprefix [f:times] [Times New Roman]
+\definetypescriptprefix [f:trebuchet] [Trebuchet MS]
+\definetypescriptprefix [f:verdana] [Verdana]
+
+\starttypescript [serif] [georgia,palatino,sylfaen,times]
+ \definefontsynonym [\typescripttwo-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescripttwo-Bold] [name:\typescriptprefix{f:\typescripttwo} Bold] [features=default]
+ \definefontsynonym [\typescripttwo-Italic] [name:\typescriptprefix{f:\typescripttwo} Italic] [features=default]
+ \definefontsynonym [\typescripttwo-BoldItalic] [name:\typescriptprefix{f:\typescripttwo} Bold Italic] [features=default]
+\stoptypescript
+
+\starttypescript [sans] [arial,arialblack,comic,franklin,impact,lucidasans,microsans,tahoma,trebuchet,verdana]
+ \definefontsynonym [\typescripttwo-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescripttwo-Bold] [name:\typescriptprefix{f:\typescripttwo} Bold] [features=default]
+ \definefontsynonym [\typescripttwo-Italic] [name:\typescriptprefix{f:\typescripttwo} Italic] [features=default]
+ \definefontsynonym [\typescripttwo-BoldItalic] [name:\typescriptprefix{f:\typescripttwo} Bold Italic] [features=default]
+\stoptypescript
+
+\starttypescript [mono] [courier,lucidaconsole]
+ \definefontsynonym [\typescripttwo-Regular] [name:\typescriptprefix{f:\typescripttwo}] [features=default]
+ \definefontsynonym [\typescripttwo-Bold] [name:\typescriptprefix{f:\typescripttwo} Bold] [features=default]
+ \definefontsynonym [\typescripttwo-Italic] [name:\typescriptprefix{f:\typescripttwo} Italic] [features=default]
+ \definefontsynonym [\typescripttwo-BoldItalic] [name:\typescriptprefix{f:\typescripttwo} Bold Italic] [features=default]
+\stoptypescript
+
+
+\starttypescript [georgia,palatino,sylfaen,times]
+ \definetypeface [\typescriptone] [rm] [serif] [\typescriptone] [default]
+\stoptypescript
+
+\starttypescript [arial,arialblack,comic,franklin,impact,lucidasans,microsans,tahoma,trebuchet,verdana]
+ \definetypeface [\typescriptone] [ss] [sans] [\typescriptone] [default]
+\stoptypescript
+
+\starttypescript [courier,lucidaconsole]
+ \definetypeface [\typescriptone] [tt] [mono] [\typescriptone] [default]
+\stoptypescript
+
+\stoptypescriptcollection
+
+\endinput
diff --git a/tex/context/base/type-xtx.tex b/tex/context/base/type-xtx.tex
index 32ff858d1..450beb6f2 100644
--- a/tex/context/base/type-xtx.tex
+++ b/tex/context/base/type-xtx.tex
@@ -36,7 +36,7 @@
%D
%D \starttyping
%D \definetypeface[basic][rm][Xserif][Baskerville]
-%D \definetypeface[basic][ss][Xsans] [Optima Regular][default][features=default,rscale=.87]
+%D \definetypeface[basic][ss][Xsans] [Optima Regular][default][features=default,rscale=0.87]
%D \definetypeface[basic][tt][Xmono] [Courier] [default]
%D \stoptyping
%D
diff --git a/tex/context/base/typo-brk.lua b/tex/context/base/typo-brk.lua
new file mode 100644
index 000000000..d01b9d653
--- /dev/null
+++ b/tex/context/base/typo-brk.lua
@@ -0,0 +1,186 @@
+if not modules then modules = { } end modules ['typo-brk'] = {
+ version = 1.001,
+ comment = "companion to typo-brk.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this code dates from the beginning and is kind of experimental; it
+-- will be optimized and improved soon
+
+local next, type = next, type
+local format = string.format
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local copy_node = node.copy
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local make_penalty_node = nodes.penalty
+local make_glue_node = nodes.glue
+local make_disc_node = nodes.disc
+
+local glyph = node.id("glyph")
+local kern = node.id("kern")
+
+breakpoints = breakpoints or { }
+breakpoints.mapping = breakpoints.mapping or { }
+breakpoints.methods = breakpoints.methods or { }
+breakpoints.enabled = false
+
+storage.register("breakpoints/mapping", breakpoints.mapping, "breakpoints.mapping")
+
+local mapping = breakpoints.mapping
+
+function breakpoints.setreplacement(id,char,kind,before,after,language)
+ local map = mapping[id]
+ if not map then
+ map = { }
+ mapping[id] = map
+ end
+ local cmap = map[char]
+ if not cmap then
+ cmap = { }
+ map[char] = cmap
+ end
+ cmap[language or ""] = { kind or 1, before or 1, after or 1 }
+end
+
+breakpoints.methods[1] = function(head,start)
+ if start.prev and start.next then
+ insert_node_before(head,start,make_penalty_node(10000))
+ insert_node_before(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_penalty_node(0))
+ end
+ return head, start
+end
+breakpoints.methods[2] = function(head,start) -- ( => (-
+ if start.prev and start.next then
+ local tmp = start
+ start = make_disc_node()
+ start.prev, start.next = tmp.prev, tmp.next
+ tmp.prev.next, tmp.next.prev = start, start
+ tmp.prev, tmp.next = nil, nil
+ start.replace = tmp
+ local tmp, hyphen = copy_node(tmp), copy_node(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.next, hyphen.prev = hyphen, tmp
+ start.post = tmp
+ insert_node_before(head,start,make_penalty_node(10000))
+ insert_node_before(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_penalty_node(10000))
+ end
+ return head, start
+end
+breakpoints.methods[3] = function(head,start) -- ) => -)
+ if start.prev and start.next then
+ local tmp = start
+ start = make_disc_node()
+ start.prev, start.next = tmp.prev, tmp.next
+ tmp.prev.next, tmp.next.prev = start, start
+ tmp.prev, tmp.next = nil, nil
+ start.replace = tmp
+ local tmp, hyphen = copy_node(tmp), copy_node(tmp)
+ hyphen.char = languages.prehyphenchar(tmp.lang)
+ tmp.prev, hyphen.next = hyphen, tmp
+ start.pre = hyphen
+ insert_node_before(head,start,make_penalty_node(10000))
+ insert_node_before(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_penalty_node(10000))
+ end
+ return head, start
+end
+breakpoints.methods[4] = function(head,start) -- - => - - -
+ if start.prev and start.next then
+ local tmp = start
+ start = make_disc_node()
+ start.prev, start.next = tmp.prev, tmp.next
+ tmp.prev.next, tmp.next.prev = start, start
+ tmp.prev, tmp.next = nil, nil
+ -- maybe prehyphenchar etc
+ start.pre = copy_node(tmp)
+ start.post = copy_node(tmp)
+ start.replace = tmp
+ insert_node_before(head,start,make_penalty_node(10000))
+ insert_node_before(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_glue_node(0))
+ insert_node_after(head,start,make_penalty_node(10000))
+ end
+ return head, start
+end
+
+function breakpoints.process(namespace,attribute,head)
+ local done, numbers = false, languages.numbers
+ local start, n = head, 0
+ while start do
+ local id = start.id
+ if id == glyph then
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ unset_attribute(start,attribute) -- maybe test for subtype > 256 (faster)
+ -- look ahead and back n chars
+ local map = mapping[attr]
+ if map then
+ local cmap = map[start.char]
+ if cmap then
+ local smap = cmap[numbers[start.lang]] or cmap[""]
+ if smap then
+ if n >= smap[2] then
+ local m = smap[3]
+ local next = start.next
+ while next do -- gamble on same attribute
+ local id = next.id
+ if id == glyph then -- gamble on same attribute
+ if map[next.char] then
+ break
+ elseif m == 1 then
+ local method = breakpoints.methods[smap[1]]
+ if method then
+ head, start = method(head,start)
+ done = true
+ end
+ break
+ else
+ m = m - 1
+ next = next.next
+ end
+ elseif id == kern and next.subtype == 0 then
+ next = next.next
+ -- ignore intercharacter kerning, will go way
+ else
+ -- we can do clever and set n and jump ahead but ... not now
+ break
+ end
+ end
+ end
+ n = 0
+ else
+ n = n + 1
+ end
+ else
+ n = n + 1
+ end
+ else
+ n = 0
+ end
+ end
+ elseif id == kern and start.subtype == 0 then
+ -- ignore intercharacter kerning, will go way
+ else
+ n = 0
+ end
+ start = start.next
+ end
+ return head, done
+end
+
+chars.handle_breakpoints = nodes.install_attribute_handler {
+ name = "breakpoint",
+ namespace = breakpoints,
+ processor = breakpoints.process,
+ }
diff --git a/tex/context/base/typo-brk.tex b/tex/context/base/typo-brk.tex
new file mode 100644
index 000000000..90561fc9e
--- /dev/null
+++ b/tex/context/base/typo-brk.tex
@@ -0,0 +1,77 @@
+%D \module
+%D [ file=typo-brk,
+%D version=2009.03.27, % code moved from core-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Breakpoints,
+%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.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Breakpoints}
+
+\unprotect
+
+\registerctxluafile{typo-brk}{1.001}
+
+\definesystemattribute[breakpoint]
+
+% compound stuff (under construction)
+
+\newbox\breakpointbox
+
+\definesystemvariable {bp} % BreakPoint
+
+\exhyphenchar=\minusone % we use a different order then base tex, so we really need this
+
+\newcount \maxbreakpointsid
+
+\def\definebreakpoints
+ {\dosingleargument\dodefinebreakpoints}
+
+\def\dodefinebreakpoints[#1]%
+ {\ifcsname\??bp:#1\endcsname \else
+ \global\advance\maxbreakpointsid\plusone
+ \setxvalue{\??bp:#1}{\the\maxbreakpointsid}%
+ \fi}
+
+\def\installbreakpoint
+ {\dotripleempty\doinstallbreakpoint}
+
+% hm, we cannot prebuild lists, font dependent
+
+\def\doinstallbreakpoint[#1][#2][#3]%
+ {\ifcsname\??bp:#1\endcsname
+ \begingroup
+ \getparameters[\??bp][\c!type=1,\c!nleft=3,\c!nright=3,\s!language=,#3]%
+ \ctxlua{breakpoints.setreplacement(\csname\??bp:#1\endcsname,#2,\@@bptype,\@@bpnleft,\@@bpnright,"\@@bplanguage")}%
+ \endgroup
+ \fi}
+
+\def\setbreakpoints
+ {\ctxlua{breakpoints.enabled=true}%
+ \gdef\setbreakpoints[##1]{\dosetattribute{breakpoint}{\csname\??bp:##1\endcsname}}%
+ \setbreakpoints}
+
+\letvalue{\??bp:\s!reset}\attributeunsetvalue
+
+\definebreakpoints[compound]
+
+\installbreakpoint [compound] [\number`+] [\c!left=3,\c!right=3,\c!type=1]
+\installbreakpoint [compound] [\number`-] [\c!left=3,\c!right=3,\c!type=1]
+\installbreakpoint [compound] [\number`/] [\c!left=3,\c!right=3,\c!type=1]
+\installbreakpoint [compound] [\number`(] [\c!left=3,\c!right=3,\c!type=2]
+\installbreakpoint [compound] [\number`)] [\c!left=3,\c!right=3,\c!type=3]
+
+% \mainlanguage[czech]
+% \installbreakpoint [compound] [\number`-] [language=cs,left=3,right=3,type=4]
+% \setbreakpoints[compound]
+% \start \hsize 1mm test-test \par \stop
+
+% \setbreakpoints[compound]
+
+\protect \endinput
+
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua
new file mode 100644
index 000000000..b6eedb330
--- /dev/null
+++ b/tex/context/base/typo-cap.lua
@@ -0,0 +1,203 @@
+if not modules then modules = { } end modules ['typo-cap'] = {
+ version = 1.001,
+ comment = "companion to typo-cap.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+local format, insert = string.format, table.insert
+
+local trace_casing = false trackers.register("nodes.casing", function(v) trace_casing = v end)
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local traverse_id = node.traverse_id
+
+local glyph = node.id("glyph")
+local kern = node.id("kern")
+
+local fontdata = fonts.ids
+local chardata = characters.data
+
+cases = cases or { }
+cases.enabled = false
+cases.actions = { }
+
+local actions = cases.actions
+local lastfont = nil
+
+-- we use char0 as placeholder for the larger font
+
+local function helper(start, code, codes, special, attribute, once)
+ local char = start.char
+ local dc = chardata[char]
+ if dc then
+ local fnt = start.font
+ if special then
+ if start.char == 0 then
+ lastfont = fnt
+ local prev, next = start.prev, start.next
+ prev.next = next
+ if next then
+ next.prev = prev
+ end
+ return prev, true
+ elseif lastfont and start.prev.id ~= glyph then
+ fnt = lastfont
+ start.font = lastfont
+ end
+ end
+ local ifc = fontdata[fnt].characters
+ local ucs = dc[codes]
+ if ucs then
+ local ok = true
+ for i=1,#ucs do
+ ok = ok and ifc[ucs[i]]
+ end
+ if ok then
+ local prev, original = start, start
+ for i=1,#ucs do
+ local chr = ucs[i]
+ prev = start
+ if i == 1 then
+ start.char = chr
+ else
+ local g = copy_node(original)
+ g.char = chr
+ local next = start.next
+ g.prev = start
+ if next then
+ g.next = next
+ start.next = g
+ next.prev = g
+ end
+ start = g
+ end
+ end
+ if once then lastfont = nil end
+ return prev, true
+ end
+ if once then lastfont = nil end
+ return start, false
+ end
+ local uc = dc[code]
+ if uc and ifc[uc] then
+ start.char = uc
+ if once then lastfont = nil end
+ return start, true
+ end
+ end
+ if once then lastfont = nil end
+ return start, false
+end
+
+actions[1] = function(start,attribute)
+ lastfont = nil
+ return helper(start,'uccode','uccodes')
+end
+
+actions[2] = function(start,attribute)
+ lastfont = nil
+ return helper(start,'lccode','lccodes')
+end
+
+actions[3] = function(start,attribute)
+ lastfont = nil
+ local prev = start.prev
+ if prev and prev.id == kern and prev.subtype == 0 then
+ prev = prev.prev
+ end
+ if not prev or prev.id ~= glyph then
+ --- only the first character is treated
+ for n in traverse_id(glyph,start.next) do
+ if has_attribute(n,attribute) then
+ unset_attribute(n,attribute)
+ end
+ end
+ return helper(start,'uccode','uccodes')
+ else
+ return start, false
+ end
+end
+
+actions[4] = function(start,attribute)
+ lastfont = nil
+ local prev = start.prev
+ if prev and prev.id == kern and prev.subtype == 0 then
+ prev = prev.prev
+ end
+ if not prev or prev.id ~= glyph then
+ return helper(start,'uccode','uccodes')
+ else
+ return start, false
+ end
+end
+
+actions[5] = function(start,attribute) -- 3
+ return helper(start,'uccode','uccodes',true,attribute,true)
+end
+
+actions[6] = function(start,attribute) -- 4
+ return helper(start,'uccode','uccodes',true,attribute,false)
+end
+
+actions[8] = function(start)
+ lastfont = nil
+ local ch = start.char
+ local mr = math.random
+ local tfm = fontdata[start.font].characters
+ if chardata[ch].lccode then
+ while true do
+ local d = chardata[mr(1,0xFFFF)]
+ if d then
+ local uc = d.uccode
+ if uc and tfm[uc] then
+ start.char = uc
+ return start, true
+ end
+ end
+ end
+ elseif chardata[ch].uccode then
+ while true do
+ local d = chardata[mr(1,0xFFFF)]
+ if d then
+ local lc = d.lccode
+ if lc and tfm[lc] then
+ start.char = lc
+ return start, true
+ end
+ end
+ end
+ else
+ return start, false
+ end
+end
+
+-- node.traverse_id_attr
+
+function cases.process(namespace,attribute,head) -- not real fast but also not used on much data
+ lastfont = nil
+ local done = false
+ for start in traverse_id(glyph,head) do
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ unset_attribute(start,attribute)
+ local action = actions[attr]
+ if action then
+ local _, ok = action(start,attribute)
+ done = done and ok
+ end
+ end
+ end
+ lastfont = nil
+ return head, done
+end
+
+chars.handle_casing = nodes.install_attribute_handler {
+ name = "case",
+ namespace = cases,
+ processor = cases.process,
+}
diff --git a/tex/context/base/typo-cap.tex b/tex/context/base/typo-cap.tex
new file mode 100644
index 000000000..49ca64957
--- /dev/null
+++ b/tex/context/base/typo-cap.tex
@@ -0,0 +1,214 @@
+%D \module
+%D [ file=typo-cap,
+%D version=2009.03.27, % code moved from core-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Mirroring,
+%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.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Caps}
+
+\unprotect
+
+\registerctxluafile{typo-cap}{1.001}
+
+\definesystemattribute[case]
+
+%D \macros
+%D {Word, Words, WORD, WORDS, doprocesswords}
+%D
+%D This is probably not the right place to present the next set
+%D of macros.
+%D
+%D \starttyping
+%D \Word {far too many words}
+%D \Words{far too many words}
+%D \WORD {far too many words}
+%D \WORDS{far too many words}
+%D \stoptyping
+%D
+%D \typebuffer
+%D
+%D This calls result in:
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D \showsetup{Word}
+%D \showsetup{Words}
+%D \showsetup{WORD}
+%D \showsetup{WORDS}
+
+% \def\doprocesswords#1 #2\od
+% {\ConvertToConstant\doifnot{#1}{}
+% {\processword{#1} %
+% \doprocesswords#2 \od}}
+%
+% \def\processwords#1%
+% {\doprocesswords#1 \od\unskip}
+%
+% \let\processword\relax
+
+% test \WORD{test TEST \TeX} test
+% test \word{test TEST \TeX} test
+% test \Word{test TEST \TeX} test
+
+\def\setcharactercasing
+ {\ctxlua{cases.enabled=true}%
+ \gdef\setcharactercasing[##1]{\dosetattribute{case}{\number##1}}%
+ \setcharactercasing}
+
+\unexpanded\def\WORD {\groupedcommand{\setcharactercasing[\plusone ]}{}}
+\unexpanded\def\word {\groupedcommand{\setcharactercasing[\plustwo ]}{}}
+\unexpanded\def\Word {\groupedcommand{\setcharactercasing[\plusthree]}{}}
+\unexpanded\def\Words{\groupedcommand{\setcharactercasing[\plusfour ]}{}}
+
+\let\WORDS\WORD
+\let\words\word
+
+%D \macros
+%D {kap,KAP,Kap,Kaps,nokap,userealcaps,usepseudocaps}
+%D
+%D We already introduced \type{\cap} as way to capitalize
+%D words. This command comes in several versions:
+%D
+%D \startbuffer
+%D \cap {let's put on a \cap{cap}}
+%D \cap {let's put on a \nocap{cap}}
+%D \CAP {let's put on a \\{cap}}
+%D \Cap {let's put on a \\{cap}}
+%D \Caps{let's put on a cap}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D Note the use of \type{\nocap}, \type{\\} and the nested
+%D \type{\cap}.
+%D
+%D \startvoorbeeld
+%D \startlines
+%D \getbuffer
+%D \stoplines
+%D \stopvoorbeeld
+%D
+%D These macros show te main reason why we introduced the
+%D smaller \type{\tx} and \type{\txx}.
+%D
+%D \starttyping
+%D \cap\romannumerals{1995}
+%D \stoptyping
+%D
+%D This at first sight unusual capitilization is completely
+%D legal.
+%D
+%D \showsetup{smallcapped}
+%D \showsetup{notsmallcapped}
+%D \showsetup{CAPPED}
+%D \showsetup{SmallCapped}
+%D \showsetup{SmallCaps}
+%D
+%D The difference between pseudo and real caps is demonstrated
+%D below:
+%D
+%D \startbuffer
+%D \usepseudocaps \cap{Hans Hagen}
+%D \userealcaps \cap{Hans Hagen}
+%D \stopbuffer
+%D
+%D \typebuffer
+%D
+%D \getbuffer
+%D
+%D The \type {\bgroup} trickery below is needed because of
+%D \type {\groupedcommand}.
+
+\let\disablepseudocaps\relax % maybe used elsewhere
+
+\newconditional\pseudocapsenabled
+
+\def\usepseudocaps{\settrue \pseudocapsenabled}
+\def\userealcaps {\setfalse\pseudocapsenabled}
+
+\usepseudocaps
+
+% we use char0 as placeholder for the larger font
+
+\unexpanded\def\pseudosmallcapped{\groupedcommand{\setcharactercasing[\plusone ]\char\zerocount\tx}{}} % all upper
+\unexpanded\def\pseudoSmallcapped{\groupedcommand{\setcharactercasing[\plusfive]\char\zerocount\tx}{}} % one upper + font
+\unexpanded\def\pseudoSmallCapped{\groupedcommand{\setcharactercasing[\plussix ]\char\zerocount\tx}{}} % some upper + font
+
+\unexpanded\def\realsmallcapped {\groupedcommand{\sc\setcharactercasing[\plusone ]}{}} % all lower
+\unexpanded\def\realSmallcapped {\groupedcommand{\sc\setcharactercasing[\plusthree]}{}} % one upper + font
+\unexpanded\def\realSmallCapped {\groupedcommand{\sc\setcharactercasing[\plusfour ]}{}} % some upper
+
+\unexpanded\def\dohandlesmallcaps
+ {\ifconditional\pseudocapsenabled
+ \expandafter\firstoftwoarguments
+ \else
+ \expandafter\secondoftwoarguments
+ \fi}
+
+\unexpanded\def\smallcapped{\dohandlesmallcaps\pseudosmallcapped\realsmallcapped}
+\unexpanded\def\Smallcapped{\dohandlesmallcaps\pseudoSmallcapped\realSmallcapped}
+\unexpanded\def\SmallCapped{\dohandlesmallcaps\pseudoSmallCapped\realSmallCapped}
+
+\unexpanded\def\autocap{\ifmmode\expandafter\normalcap\else\expandafter\smallcapped\fi}
+
+\appendtoks
+ \let\normalcap\cap % mathmode cap
+ \let\cap\autocap
+\to \everydump
+
+\let\kap\cap % for old times sake
+\let\Caps\SmallCapped % for old times sake
+
+\let\normalsmallcapped\smallcapped
+\let\normalWORD \WORD
+\let\normalword \word
+
+%D \macros
+%D {setupcapitals}
+%D
+%D By default we use pseudo small caps in titles. This can be
+%D set up with:
+%D
+%D \showsetup{setupcapitals}
+
+\let\normalsmallcapped\smallcapped
+
+\def\setupcapitals
+ {\dosingleempty\dosetupcapitals}
+
+\def\dosetupcapitals[#1]%
+ {\getparameters[\??kk][#1]%
+ \doifelse\@@kktitle\v!yes
+ {\definealternativestyle[\v!capital][\normalsmallcapped][\normalsmallcapped]%
+ \definealternativestyle[\v!smallcaps][\sc][\sc]}
+ {\definealternativestyle[\v!capital][\normalsmallcapped][\normalWORD]%
+ \definealternativestyle[\v!smallcaps][\sc][\normalWORD]}%
+ \doifelse\@@kksc\v!yes\userealcaps\usepseudocaps}
+
+\let\uppercased\normalWORD
+\let\lowercased\normalword
+
+\setupcapitals
+ [\c!title=\v!yes,
+ \c!sc=\v!no]
+
+% \definestartstop is not yet in available at core-spa time
+%
+% \startrandomized \input tufte \stoprandomized
+%
+% \definestartstop[randomized][\c!before=\dosetattribute{case}{8},\c!after=]
+
+\def\randomizetext{\groupedcommand{\dosetattribute{case}{8}}{}}
+
+\protect \endinput
diff --git a/tex/context/base/typo-ini.tex b/tex/context/base/typo-ini.tex
index e249b51e0..1317021ef 100644
--- a/tex/context/base/typo-ini.tex
+++ b/tex/context/base/typo-ini.tex
@@ -18,7 +18,7 @@
%D typographic extensions in modules. The first language that
%D demands this is Chinese, and more will follow.
-\writestatus{loading}{Context Typographic Macros (ini)}
+\writestatus{loading}{ConTeXt Typographic Macros / Initialization}
\unprotect
diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua
new file mode 100644
index 000000000..598db6c27
--- /dev/null
+++ b/tex/context/base/typo-krn.lua
@@ -0,0 +1,218 @@
+if not modules then modules = { } end modules ['typo-krn'] = {
+ version = 1.001,
+ comment = "companion to typo-krn.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local next, type = next, type
+local utfchar = utf.char
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local slide_node_list = node.slide
+local free_node = node.free
+local copy_node = node.copy
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local make_glue_spec = nodes.glue_spec
+local make_kern_node = nodes.kern
+
+local glyph = node.id("glyph")
+local kern = node.id("kern")
+local disc = node.id('disc')
+local glue = node.id('glue')
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+
+local fontdata = fonts.ids
+local chardata = characters.data
+
+kerns = kerns or { }
+kerns.mapping = kerns.mapping or { }
+kerns.enabled = false
+
+storage.register("kerns/mapping", kerns.mapping, "kerns.mapping")
+
+function kerns.setspacing(id,factor)
+ kerns.mapping[id] = factor
+end
+
+-- one must use liga=no and mode=base and kern=yes
+-- use more helpers
+-- make sure it runs after all others
+-- there will be a width adaptor field in nodes so this will change
+-- todo: interchar kerns / disc nodes / can be made faster
+-- todo: cache quad and so
+
+local mapping = kerns.mapping
+
+local function process(namespace,attribute,head,force)
+ local scale = tex.scale
+ local start, done, lastfont = head, false, nil
+ while start do
+ -- faster to test for attr first
+ local attr = force or has_attribute(start,attribute)
+ if attr and attr > 0 then
+ unset_attribute(start,attribute)
+ local krn = mapping[attr]
+ if krn and krn ~= 0 then
+ local id = start.id
+ if id == glyph then
+ lastfont = start.font
+ local c = start.components
+ if c then
+ local s = start
+ local tail = slide_node_list(c)
+ if s.prev then
+ s.prev.next = c
+ c.prev = s.prev
+ else
+ head = c
+ end
+ if s.next then
+ s.next.prev = tail
+ end
+ tail.next = s.next
+ start = c
+ start.attr = s.attr
+ s.attr = nil
+ s.components = nil
+ free_node(s)
+ done = true
+ end
+ local prev = start.prev
+ if prev then
+ local pid = prev.id
+ if not pid then
+ -- nothing
+ elseif pid == kern and prev.subtype == 0 then
+ prev.subtype = 1
+ prev.kern = prev.kern + scale(fontdata[lastfont].parameters.quad,krn)
+ done = true
+ elseif pid == glyph then
+ -- fontdata access can be done more efficient
+ if prev.font == lastfont then
+ local prevchar, lastchar = prev.char, start.char
+ local tfm = fontdata[lastfont].characters[prevchar]
+ local ickern = tfm.kerns
+ if ickern and ickern[lastchar] then
+ krn = scale(ickern[lastchar]+fontdata[lastfont].parameters.quad,krn)
+ else
+ krn = scale(fontdata[lastfont].parameters.quad,krn)
+ end
+ else
+ krn = scale(fontdata[lastfont].parameters.quad,krn)
+ end
+ insert_node_before(head,start,make_kern_node(krn))
+ done = true
+ elseif pid == disc then
+ -- a bit too complicated, we can best not copy and just calculate
+ -- but we could have multiple glyphs involved so ...
+ local disc = prev -- disc
+ local pre, post, replace = disc.pre, disc.post, disc.replace
+ if pre then -- must pair with start.prev
+ -- this one happens in most cases
+ local before = copy_node(disc.prev)
+ pre.prev = before
+ before.next = pre
+ before.prev = nil
+ pre = process(namespace,attribute,before,attr)
+ pre = pre.next
+ pre.prev = nil
+ disc.pre = pre
+ free_node(before)
+ end
+ if post then -- must pair with start
+ local after = copy_node(disc.next)
+ local tail = slide_node_list(post)
+ tail.next = after
+ after.prev = tail
+ after.next = nil
+ post = process(namespace,attribute,post,attr)
+ tail.next = nil
+ disc.post = post
+ free_node(after)
+ end
+ if replace then -- must pair with start and start.prev
+ local before = copy_node(disc.prev)
+ local after = copy_node(disc.next)
+ local tail = slide_node_list(replace)
+ replace.prev = before
+ before.next = replace
+ before.prev = nil
+ tail.next = after
+ after.prev = tail
+ after.next = nil
+ replace = process(namespace,attribute,before,attr)
+ replace = replace.next
+ replace.prev = nil
+ tail.next = nil
+ disc.replace = replace
+ free_node(after)
+ free_node(before)
+ else
+ if disc.prev.font == lastfont then
+ local prevchar, lastchar = disc.prev.char, start.char
+ local tfm = fontdata[lastfont].characters[prevchar]
+ local ickern = tfm.kerns
+ if ickern and ickern[lastchar] then
+ krn = scale(ickern[lastchar]+fontdata[lastfont].parameters.quad,krn)
+ else
+ krn = scale(fontdata[lastfont].parameters.quad,krn)
+ end
+ else
+ krn = scale(fontdata[lastfont].parameters.quad,krn)
+ end
+ disc.replace = make_kern_node(krn)
+ end
+ end
+ end
+ elseif id == glue and start.subtype == 0 then
+ local s = start.spec
+ local w = s.width
+ if w > 0 then
+ local width, stretch, shrink = w+2*scale(w,krn), s.stretch, s.shrink
+ start.spec = make_glue_spec(width,scale(stretch,width/w),scale(shrink,width/w))
+ -- local width, stretch, shrink = w+2*w*krn, s.stretch, s.shrink
+ -- start.spec = make_glue_spec(width,stretch*width/w,shrink*width/w))
+ done = true
+ end
+ elseif false and id == kern and start.subtype == 0 then -- handle with glyphs
+ local sk = start.kern
+ if sk > 0 then
+ -- start.kern = scale(sk,krn)
+ start.kern = sk*krn
+ done = true
+ end
+ elseif lastfont and (id == hlist or id == vlist) then -- todo: lookahead
+ if start.prev then
+ insert_node_before(head,start,make_kern_node(scale(fontdata[lastfont].parameters.quad,krn)))
+ done = true
+ end
+ if start.next then
+ insert_node_after(head,start,make_kern_node(scale(fontdata[lastfont].parameters.quad,krn)))
+ done = true
+ end
+ end
+ end
+ end
+ if start then
+ start = start.next
+ end
+ end
+ return head, done
+end
+
+kerns.process = function(namespace,attribute,head)
+ return process(namespace,attribute,head) -- no direct map, because else fourth argument is tail == true
+end
+
+lists.handle_kerning = nodes.install_attribute_handler {
+ name = "kern",
+ namespace = kerns,
+ processor = kerns.process,
+}
diff --git a/tex/context/base/typo-krn.tex b/tex/context/base/typo-krn.tex
new file mode 100644
index 000000000..e2f10d806
--- /dev/null
+++ b/tex/context/base/typo-krn.tex
@@ -0,0 +1,59 @@
+%D \module
+%D [ file=typo-krn,
+%D version=2009.03.27, % code moved from core-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Spacing,
+%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.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Kerning}
+
+\unprotect
+
+\registerctxluafile{typo-krn}{1.001}
+
+\definesystemattribute[kern]
+
+% more
+%
+% {\setcharacterkerning[extrakerning]\input davis\relax}
+
+\newcount \maxcharacterkerningid
+
+\def\definecharacterkerning
+ {\dosingleargument\dodefinecharacterkerning}
+
+\def\dodefinecharacterkerning[#1]%
+ {\ifcsname\??ck#1\endcsname \else
+ \global\advance\maxcharacterkerningid\plusone
+ \setxvalue{\??ck:#1}{\the\maxcharacterkerningid}%
+ \fi}
+
+\def\setupcharacterkerning
+ {\dodoubleargument\dosetupcharacterkerning}
+
+\def\dosetupcharacterkerning[#1][#2]%
+ {\ifcsname\??ck:#1\endcsname
+ \begingroup
+ \getparameters[\??ck][\c!factor=0,#2]%
+ \ctxlua{kerns.setspacing(\getvalue{\??ck:#1},\@@ckfactor)}%
+ \endgroup
+ \fi}
+
+\def\setcharacterkerning
+ {\ctxlua{kerns.enabled=true}%
+ \gdef\setcharacterkerning[##1]{\dosetattribute{kern}{\csname\??ck:##1\endcsname}}%
+ \setcharacterkerning}
+
+\letvalue{\??ck:\s!reset}\attributeunsetvalue
+
+\definecharacterkerning[extrakerning]
+
+\setupcharacterkerning[extrakerning][\c!factor=.125]
+
+\protect \endinput
diff --git a/tex/context/base/typo-mir.lua b/tex/context/base/typo-mir.lua
new file mode 100644
index 000000000..fb575d093
--- /dev/null
+++ b/tex/context/base/typo-mir.lua
@@ -0,0 +1,409 @@
+if not modules then modules = { } end modules ['typo-mir'] = {
+ version = 1.001,
+ comment = "companion to typo-mir.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local next, type = next, type
+local format, insert = string.format, table.insert
+local utfchar = utf.char
+
+-- vertical space handler
+
+local trace_mirroring = false trackers.register("nodes.mirroring", function(v) trace_mirroring = v end)
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local set_attribute = node.set_attribute
+local traverse_id = node.traverse_id
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local remove_node = nodes.remove
+
+local glyph = node.id("glyph")
+local whatsit = node.id("whatsit")
+local mthnode = node.id('math')
+
+local fontdata = fonts.ids
+local chardata = characters.data
+
+--~ Analysis by Idris:
+--~
+--~ 1. Assuming the reading- vs word-order distinction (bidi-char types) is governing;
+--~ 2. Assuming that 'ARAB' represents an actual arabic string in raw input order, not word-order;
+--~ 3. Assuming that 'BARA' represent the correct RL word order;
+--~
+--~ Then we have, with input: LATIN ARAB
+--~
+--~ \textdir TLT LATIN ARAB => LATIN BARA
+--~ \textdir TRT LATIN ARAB => LATIN BARA
+--~ \textdir TRT LRO LATIN ARAB => LATIN ARAB
+--~ \textdir TLT LRO LATIN ARAB => LATIN ARAB
+--~ \textdir TLT RLO LATIN ARAB => NITAL ARAB
+--~ \textdir TRT RLO LATIN ARAB => NITAL ARAB
+
+-- elseif d == "es" then -- European Number Separator
+-- elseif d == "et" then -- European Number Terminator
+-- elseif d == "cs" then -- Common Number Separator
+-- elseif d == "nsm" then -- Non-Spacing Mark
+-- elseif d == "bn" then -- Boundary Neutral
+-- elseif d == "b" then -- Paragraph Separator
+-- elseif d == "s" then -- Segment Separator
+-- elseif d == "ws" then -- Whitespace
+-- elseif d == "on" then -- Other Neutrals
+
+mirror = mirror or { }
+mirror.enabled = false
+mirror.strip = false
+
+local state = attributes.private('state')
+local mirrora = attributes.private('mirror')
+
+local directions = characters.directions -- maybe make a special mirror table
+
+-- todo: delayed inserts here
+-- todo: get rid of local functions here
+
+-- beware, math adds whatsits afterwards so that will mess things up
+
+local skipmath = true
+
+local finish, autodir, embedded, override, done = nil, 0, 0, 0, false
+local list, glyphs = nil, false
+local finished, finidir, finipos = nil, nil, 1
+local head, current, inserted = nil, nil, nil
+
+local function finish_auto_before()
+ head, inserted = insert_node_before(head,current,nodes.textdir("-"..finish))
+ finished, finidir = inserted, finish
+ if trace_mirroring then
+ insert(list,#list,format("finish %s",finish))
+ finipos = #list-1
+ end
+ finish, autodir, done = nil, 0, true
+end
+
+local function finish_auto_after()
+ head, current = insert_node_after(head,current,nodes.textdir("-"..finish))
+ finished, finidir = current, finish
+ if trace_mirroring then
+ list[#list+1] = format("finish %s",finish)
+ finipos = #list
+ end
+ finish, autodir, done = nil, 0, true
+end
+
+local function force_auto_left_before()
+ if finish then
+ finish_auto_before()
+ end
+ if embedded >= 0 then
+ finish, autodir, done = "TLT", 1, true
+ else
+ finish, autodir, done = "TRT", -1, true
+ end
+ if finidir == finish then
+ remove_node(head,finished,true)
+ if trace_mirroring then
+ list[finipos] = list[finipos].." (deleted)"
+ insert(list,#list,format("start %s (deleted)",finish))
+ end
+ else
+ head, inserted = insert_node_before(head,current,nodes.textdir("+"..finish))
+ if trace_mirroring then
+ insert(list,#list,format("start %s",finish))
+ end
+ end
+end
+
+local function force_auto_right_before()
+ if finish then
+ finish_auto_before()
+ end
+ if embedded <= 0 then
+ finish, autodir, done = "TRT", -1, true
+ else
+ finish, autodir, done = "TLT", 1, true
+ end
+ if finidir == finish then
+ remove_node(head,finished,true)
+ if trace_mirroring then
+ list[finipos] = list[finipos].." (deleted)"
+ insert(list,#list,format("start %s (deleted)",finish))
+ end
+ else
+ head, inserted = insert_node_before(head,current,nodes.textdir("+"..finish))
+ if trace_mirroring then
+ insert(list,#list,format("start %s",finish))
+ end
+ end
+end
+
+function mirror.process(namespace,attribute,start) -- todo: make faster
+ if not start.next then
+ return start, false
+ end
+ head, current, inserted = start, start, nil
+ finish, autodir, embedded, override, done = nil, 0, 0, 0, false
+ list, glyphs = trace_mirroring and { }, false
+ finished, finidir, finipos = nil, nil, 1
+ local stack, top, obsolete = { }, 0, { }
+ local lro, rlo, prevattr, inmath = false, false, 0, false
+ while current do
+ local id = current.id
+ if skipmath and id == mthnode then
+ local subtype = current.subtype
+ if subtype == 0 then
+ -- begin math
+ inmath = true
+ elseif subtype == 1 then
+ inmath = false
+ else
+ -- todo
+ end
+ current = current.next
+ elseif inmath then
+ current = current.next
+ else
+ local attr = has_attribute(current,attribute)
+ if attr and attr > 0 then
+ unset_attribute(current,attribute) -- slow, needed?
+ --~ set_attribute(current,attribute,0) -- might be faster
+ if attr == 1 then
+ -- bidi parsing mode
+ elseif attr ~= prevattr then
+ -- no pop, grouped driven (2=normal,3=lro,4=rlo)
+ if attr == 3 then
+ if trace_mirroring then
+ list[#list+1] = format("override right -> left (lro) (bidi=%s)",attr)
+ end
+ lro, rlo = true, false
+ elseif attr == 4 then
+ if trace_mirroring then
+ list[#list+1] = format("override left -> right (rlo) (bidi=%s)",attr)
+ end
+ lro, rlo = false, true
+ else
+ if trace_mirroring and
+ current ~= head then list[#list+1] = format("override reset (bidi=%s)",attr)
+ end
+ lro, rlo = false, false
+ end
+ prevattr = attr
+ end
+ end
+ if id == glyph then
+ glyphs = true
+ if attr and attr > 0 then
+ local char = current.char
+ local d = directions[char]
+ if rlo or override > 0 then
+ if d == "l" then
+ if trace_mirroring then
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s overidden to r (bidi=%s)",utfchar(char),char,char,d,attr)
+ end
+ d = "r"
+ elseif trace_mirroring then
+ if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
+ list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
+ else -- todo: rle lre
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s (bidi=%s)",utfchar(char),char,char,d,attr)
+ end
+ end
+ elseif lro or override < 0 then
+ if d == "r" or d == "al" then
+ set_attribute(current,state,4) -- maybe better have a special bidi attr value -> override (9) -> todo
+ if trace_mirroring then
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s overidden to l (bidi=%s) (state=isol)",utfchar(char),char,char,d,attr)
+ end
+ d = "l"
+ elseif trace_mirroring then
+ if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
+ list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
+ else -- todo: rle lre
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s (bidi=%s)",utfchar(char),char,char,d,attr)
+ end
+ end
+ elseif trace_mirroring then
+ if d == "lro" or d == "rlo" or d == "pdf" then -- else side effects on terminal
+ list[#list+1] = format("override char of class %s (bidi=%s)",d,attr)
+ else -- todo: rle lre
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s (bidi=%s)",utfchar(char),char,char,d,attr)
+ end
+ end
+ if d == "on" then
+ local mirror = chardata[char].mirror -- maybe make a special mirror table
+ if mirror and fontdata[current.font].characters[mirror] then
+ -- todo: set attribute
+ if autodir < 0 then
+ current.char = mirror
+ done = true
+ --~ elseif left or autodir > 0 then
+ --~ if not is_right(current.prev) then
+ --~ current.char = mirror
+ --~ done = true
+ --~ end
+ end
+ end
+ elseif d == "l" or d == "en" then -- european number
+ if autodir <= 0 then
+ force_auto_left_before()
+ end
+ elseif d == "r" or d == "al" or d == "an" then -- arabic left, arabic number
+ if autodir >= 0 then
+ force_auto_right_before()
+ end
+ elseif d == "lro" then -- Left-to-Right Override -> right becomes left
+ if trace_mirroring then
+ list[#list+1] = "override right -> left"
+ end
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = -1
+ obsolete[#obsolete+1] = current
+ elseif d == "rlo" then -- Right-to-Left Override -> left becomes right
+ if trace_mirroring then
+ list[#list+1] = "override left -> right"
+ end
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = 1
+ obsolete[#obsolete+1] = current
+ elseif d == "lre" then -- Left-to-Right Embedding -> TLT
+ if trace_mirroring then
+ list[#list+1] = "embedding left -> right"
+ end
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = 1
+ obsolete[#obsolete+1] = current
+ elseif d == "rle" then -- Right-to-Left Embedding -> TRT
+ if trace_mirroring then
+ list[#list+1] = "embedding right -> left"
+ end
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = 1
+ obsolete[#obsolete+1] = current
+ elseif d == "pdf" then -- Pop Directional Format
+ -- override = 0
+ if top > 0 then
+ local s = stack[top]
+ override, embedded = s[1], s[2]
+ top = top - 1
+ if trace_mirroring then
+ list[#list+1] = format("state: override: %s, embedded: %s, autodir: %s",override,embedded,autodir)
+ end
+ else
+ if trace_mirroring then
+ list[#list+1] = "pop (error, too many pops)"
+ end
+ end
+ obsolete[#obsolete+1] = current
+ end
+ else
+ if trace_mirroring then
+ local char = current.char
+ local d = directions[char]
+ list[#list+1] = format("char %s (%s / U+%04X) of class %s (no bidi)",utfchar(char),char,char,d)
+ end
+ end
+ elseif id == whatsit then
+ if finish then
+ finish_auto_before()
+ end
+ local subtype = current.subtype
+ if subtype == 6 then
+ local dir = current.dir
+ local d = dir:sub(2,2)
+ if dir:find(".R.") then
+ autodir = -1
+ else
+ autodir = 1
+ end
+ embeddded = autodir
+ if trace_mirroring then
+ list[#list+1] = format("pardir %s",dir)
+ end
+ elseif subtype == 7 then
+ local dir = current.dir
+ local sign = dir:sub(1,1)
+ local dire = dir:sub(3,3)
+ if dire == "R" then
+ if sign == "+" then
+ finish, autodir = "TRT", -1
+ else
+ finish, autodir = nil, 0
+ end
+ else
+ if sign == "+" then
+ finish, autodir = "TLT", 1
+ else
+ finish, autodir = nil, 0
+ end
+ end
+ if trace_mirroring then
+ list[#list+1] = format("textdir %s",dir)
+ end
+ end
+ else
+ if trace_mirroring then
+ list[#list+1] = format("node %s (subtype %s)",node.type(id),current.subtype)
+ end
+ if finish then
+ finish_auto_before()
+ end
+ end
+ local cn = current.next
+ if not cn then
+ if finish then
+ finish_auto_after()
+ end
+ end
+ current = cn
+ end
+ end
+ if trace_mirroring and glyphs then
+ logs.report("bidi","start log")
+ for i=1,#list do
+ logs.report("bidi","%02i: %s",i,list[i])
+ end
+ logs.report("bidi","stop log")
+ end
+ if done and mirror.strip then
+ local n = #obsolete
+ if n > 0 then
+ for i=1,n do
+ remove_node(head,obsolete[i],true)
+ end
+ logs.report("bidi","%s character nodes removed",n)
+ end
+ end
+ return head, done
+end
+
+--~ local function is_right(n) -- keep !
+--~ if n then
+--~ local id = n.id
+--~ if id == glyph then
+--~ local attr = has_attribute(n,attribute)
+--~ if attr and attr > 0 then
+--~ local d = directions[n.char]
+--~ if d == "r" or d == "al" then -- override
+--~ return true
+--~ end
+--~ end
+--~ end
+--~ end
+--~ return false
+--~ end
+
+chars.handle_mirroring = nodes.install_attribute_handler {
+ name = "mirror",
+ namespace = mirror,
+ processor = mirror.process,
+}
diff --git a/tex/context/base/typo-mir.tex b/tex/context/base/typo-mir.tex
new file mode 100644
index 000000000..fe9d793e0
--- /dev/null
+++ b/tex/context/base/typo-mir.tex
@@ -0,0 +1,144 @@
+%D \module
+%D [ file=typo-mir,
+%D version=2009.03.27, % code moved from core-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Mirroring,
+%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.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Mirroring}
+
+\unprotect
+
+\registerctxluafile{typo-mir}{1.001}
+
+\definesystemattribute[mirror]
+
+% experimental mirroring
+
+\def\setcharactermirroring
+ {\ctxlua{mirror.enabled=true}%
+ \gdef\setcharactermirroring[##1]{\dosetattribute{mirror}{\number##1}}%
+ \setcharactermirroring}
+
+\def\resetcharactermirroring
+ {\doresetattribute{mirror}}
+
+\newtoks\everysetupdirections
+
+\def\setupdirections[#1]% there will be more like setting up directions themselves
+ {\getparameters[\??di][#1]%
+ \the\everysetupdirections}
+
+\chardef\directionsbidimode=0
+
+\letvalue{\??di:bidi:\v!off }\zerocount
+\letvalue{\??di:bidi:\v!global}\plusone
+\letvalue{\??di:bidi:\v!local }\plustwo
+\letvalue{\??di:bidi:\v!on }\plustwo
+
+\appendtoks
+ \chardef\directionsbidimode\executeifdefined{\??di:bidi:\@@dibidi}\zerocount\relax
+ \ifcase\directionsbidimode
+ \resetcharactermirroring
+ \or
+ \setcharactermirroring[1]% global, chars
+ \or
+ \setcharactermirroring[2]% local, attributes
+ \or
+ \setcharactermirroring[1]% default
+ \fi
+\to \everysetupdirections
+
+% bidi: local=obey grouping, global=ignore grouping (unicode has no grouping)
+
+\setupdirections % maybe start/stop
+ [bidi=\v!off]
+
+\unexpanded\def\bidilre{\utfchar{"0x202A}}
+\unexpanded\def\bidirle{\utfchar{"0x202B}}
+\unexpanded\def\bidipop{\utfchar{"0x202C}}
+\unexpanded\def\bidilro{\utfchar{"0x202D}}
+\unexpanded\def\bidirlo{\utfchar{"0x202E}}
+
+\unexpanded\def\dirlre{\ifcase\directionsbidimode\or\bidilre\or\textdir TLT\fi}
+\unexpanded\def\dirrle{\ifcase\directionsbidimode\or\bidirle\or\textdir TRT\fi}
+\unexpanded\def\dirlro{\ifcase\directionsbidimode\or\bidilro\or\setcharactermirroring[3]\fi}
+\unexpanded\def\dirrlo{\ifcase\directionsbidimode\or\bidirlo\or\setcharactermirroring[4]\fi}
+
+% for the moment: \setcharactermirroring[\plusone]
+
+\protect \endinput
+
+% bidi test
+
+\definefontfeature
+ [arab]
+ [mode=node,language=dflt,script=arab,
+ init=yes,medi=yes,fina=yes,isol=yes,
+ liga=yes,dlig=yes,rlig=yes,clig=yes,
+ mark=yes,mkmk=yes,kern=yes,curs=yes]
+
+\font\Arabic=arabtype*arab at 20pt
+
+\def\LATIN{LATIN} {\setcharactermirroring[1]} % enable this
+\def\ARAB {محمد}
+
+\startluacode
+ function document.split_tokens(str)
+ for s in str:bytes() do
+ tex.sprint(tex.ctxcatcodes,string.format("\\hbox{\\char %s}",s))
+ end
+ end
+\stopluacode
+
+\def\biditest#1#2#3% font text raw
+ {\dontleavehmode\hbox
+ {\framed[offset=overlay]{\tttf#2}\quad
+ \ctxlua{mirror.trace = true}%
+ \framed[offset=overlay]{#1#3}\quad
+ \ctxlua{mirror.trace = false}
+ \tttf\ctxlua{document.split_tokens([[\detokenize{#3}]])}}}
+
+\startbuffer[bidi-sample]
+\biditest\Arabic{LATIN BARA}{\textdir TLT\relax \LATIN\ \ARAB}\par
+\biditest\Arabic{BARA LATIN}{\textdir TRT\relax \LATIN\ \ARAB}\par
+\biditest\Arabic{LATIN ARAB}{\textdir TLT{\bidilro \LATIN\ \ARAB}}\par % right -> left
+\biditest\Arabic{LATIN ARAB}{\textdir TRT{\bidilro \LATIN\ \ARAB}}\par % right -> left
+\biditest\Arabic{BARA NITAL}{\textdir TLT{\bidirlo \LATIN\ \ARAB}}\par % left -> right
+\biditest\Arabic{BARA NITAL}{\textdir TRT{\bidirlo \LATIN\ \ARAB}}\par % left -> right
+\stopbuffer
+
+\startbuffer[bidi-sample]
+\biditest\Arabic{LATIN BARA}{\textdir TLT\relax \LATIN\ \ARAB}\par
+\biditest\Arabic{BARA LATIN}{\textdir TRT\relax \LATIN\ \ARAB}\par
+\biditest\Arabic{LATIN ARAB}{\textdir TLT\bidilro \LATIN\ \ARAB}\par % right -> left
+\biditest\Arabic{LATIN ARAB}{\textdir TRT\bidilro \LATIN\ \ARAB}\par % right -> left
+\biditest\Arabic{BARA NITAL}{\textdir TLT\bidirlo \LATIN\ \ARAB}\par % left -> right
+\biditest\Arabic{BARA NITAL}{\textdir TRT\bidirlo \LATIN\ \ARAB}\par % left -> right
+\stopbuffer
+
+\startbuffer[bidi-setup]
+\setupdirections[bidi=off]
+\stopbuffer
+
+{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
+
+\startbuffer[bidi-setup]
+\setupdirections[bidi=global]
+\stopbuffer
+
+{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
+
+\startbuffer[bidi-setup]
+\setupdirections[bidi=local]
+\stopbuffer
+
+{\typebuffer[bidi-setup] \getbuffer[bidi-setup] \getbuffer[bidi-sample]}
+
+\stoptext
diff --git a/tex/context/base/typo-spa.lua b/tex/context/base/typo-spa.lua
new file mode 100644
index 000000000..c134fc281
--- /dev/null
+++ b/tex/context/base/typo-spa.lua
@@ -0,0 +1,149 @@
+if not modules then modules = { } end modules ['typo-spa'] = {
+ version = 1.001,
+ comment = "companion to typo-spa.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local next, type = next, type
+local utfchar = utf.char
+
+local trace_hspacing = false trackers.register("nodes.hspacing", function(v) trace_hspacing = v end)
+
+local has_attribute = node.has_attribute
+local unset_attribute = node.unset_attribute
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+local remove_node = nodes.remove
+local make_penalty_node = nodes.penalty
+local make_glue_node = nodes.glue
+local glyph = node.id("glyph")
+local fontdata = fonts.ids
+
+spacings = spacings or { }
+spacings.mapping = spacings.mapping or { }
+spacings.enabled = false
+
+storage.register("spacings/mapping", spacings.mapping, "spacings.mapping")
+
+function spacings.setspacing(id,char,left,right,alternative)
+ local mapping = spacings.mapping[id]
+ if not mapping then
+ mapping = { }
+ spacings.mapping[id] = mapping
+ end
+ local map = mapping[char]
+ if not map then
+ map = { }
+ mapping[char] = map
+ end
+ map.left, map.right, map.alternative = left, right, alternative
+end
+
+function spacings.process(namespace,attribute,head)
+ local done, mapping = false, spacings.mapping
+ local start = head
+ -- head is always begin of par (whatsit), so we have at least two prev nodes
+ -- penalty followed by glue
+ while start do
+ if start.id == glyph then
+ local attr = has_attribute(start,attribute)
+ if attr and attr > 0 then
+ local map = mapping[attr]
+ if map then
+ map = map[start.char]
+ unset_attribute(start,attribute)
+ if map then
+ local left, right, alternative = map.left, map.right, map.alternative
+ local quad = fontdata[start.font].parameters.quad
+ local prev = start.prev
+ if left and left ~= 0 and prev then
+ local ok = false
+ if alternative == 1 then
+ local somespace = nodes.somespace(prev,true)
+ if somespace then
+ local prevprev = prev.prev
+ local somepenalty = nodes.somepenalty(prevprev,10000)
+ if somepenalty then
+ if trace_hspacing then
+ logs.report("spacing","removing penalty and space before %s", utfchar(start.char))
+ end
+ head, _ = remove_node(head,prev,true)
+ head, _ = remove_node(head,prevprev,true)
+ else
+ local somespace = nodes.somespace(prev,true)
+ if somespace then
+ if trace_hspacing then
+ logs.report("spacing","removing space before %s", utfchar(start.char))
+ end
+ head, _ = remove_node(head,prev,true)
+ end
+ end
+ end
+ ok = true
+ else
+ ok = not (nodes.somespace(prev,true) and nodes.somepenalty(prev.prev,true)) or nodes.somespace(prev,true)
+ end
+ if ok then
+ if trace_hspacing then
+ logs.report("spacing","inserting penalty and space before %s", utfchar(start.char))
+ end
+ insert_node_before(head,start,make_penalty_node(10000))
+ insert_node_before(head,start,make_glue_node(tex.scale(quad,left)))
+ done = true
+ end
+ end
+ local next = start.next
+ if right and right ~= 0 and next then
+ local ok = false
+ if alternative == 1 then
+ local somepenalty = nodes.somepenalty(next,10000)
+ if somepenalty then
+ local nextnext = next.next
+ local somespace = nodes.somespace(nextnext,true)
+ if somespace then
+ if trace_hspacing then
+ logs.report("spacing","removing penalty and space after %s", utfchar(start.char))
+ end
+ head, _ = remove_node(head,next,true)
+ head, _ = remove_node(head,nextnext,true)
+ end
+ else
+ local somespace = nodes.somespace(next,true)
+ if somespace then
+ if trace_hspacing then
+ logs.report("spacing","removing space after %s", utfchar(start.char))
+ end
+ head, _ = remove_node(head,next,true)
+ end
+ end
+ ok = true
+ else
+ ok = not (nodes.somepenalty(next,10000) and nodes.somespace(next.next,true)) or nodes.somespace(next,true)
+ end
+ if ok then
+ if trace_hspacing then
+ logs.report("spacing","inserting penalty and space after %s", utfchar(start.char))
+ end
+ insert_node_after(head,start,make_glue_node(tex.scale(quad,right)))
+ insert_node_after(head,start,make_penalty_node(10000))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ end
+ start = start.next
+ end
+ return head, done
+end
+
+lists.handle_spacing = nodes.install_attribute_handler {
+ name = "spacing",
+ namespace = spacings,
+ processor = spacings.process,
+}
diff --git a/tex/context/base/typo-spa.tex b/tex/context/base/typo-spa.tex
new file mode 100644
index 000000000..d1b855edd
--- /dev/null
+++ b/tex/context/base/typo-spa.tex
@@ -0,0 +1,69 @@
+%D \module
+%D [ file=typo-spa,
+%D version=2009.03.27, % code moved from cors-spa.mkiv
+%D title=\CONTEXT\ Typesetting Macros,
+%D subtitle=Spacing,
+%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.
+
+\writestatus{loading}{ConTeXt Typesetting Macros / Spacing}
+
+\unprotect
+
+\registerctxluafile{typo-spa}{1.001}
+
+\definesystemattribute[spacing]
+
+% experimental spacing
+%
+% test: oeps {\setcharacterspacing[frenchpunctuation]x: xx \bfd x: xx} oeps: test
+
+\newcount \maxcharacterspacingid
+
+\def\definecharacterspacing[#1]%
+ {\ifcsname\??ch#1\endcsname \else
+ \global\advance\maxcharacterspacingid\plusone
+ \setxvalue{\??ch:#1}{\the\maxcharacterspacingid}%
+ \fi}
+
+\def\setupcharacterspacing
+ {\dotripleargument\dosetupcharacterspacing}
+
+\def\dosetupcharacterspacing[#1][#2][#3]%
+ {\ifcsname\??ch:#1\endcsname
+ \begingroup % for the moment we use modes, in ordere to avoid interface translation
+ \getparameters[\??ch][\c!left=0,\c!right=0,\c!alternative=0,#3]%
+ \ctxlua{spacings.setspacing(\getvalue{\??ch:#1},\number#2,\@@chleft,\@@chright,\@@chalternative)}%
+ \endgroup
+ \fi}
+
+\def\setcharacterspacing
+ {\ctxlua{spacings.enabled=true}%
+ \gdef\setcharacterspacing[##1]{\dosetattribute{spacing}{\csname\??ch:##1\endcsname}}%
+ \setcharacterspacing}
+
+\def\resetcharacterspacing
+ {\doresetattribute{spacing}}
+
+\letvalue{\??ch:\s!reset}\attributeunsetvalue
+
+% \setcharacterspacing[frenchpunctuation]
+% «\type{bla}»\crlf « \type{bla}»\crlf
+% «bla »\crlf « bla»\crlf « bla »\crlf
+% bla: bla\crlf bla : bla
+
+\definecharacterspacing [frenchpunctuation] % name may change / unit is em
+
+\setupcharacterspacing [frenchpunctuation] ["003A] [\c!left =.25,\c!alternative=1] % : % strip preceding space(char)
+\setupcharacterspacing [frenchpunctuation] ["003B] [\c!left =.25,\c!alternative=1] % ; % strip preceding space(char)
+\setupcharacterspacing [frenchpunctuation] ["003F] [\c!left =.25,\c!alternative=1] % ? % strip preceding space(char)
+\setupcharacterspacing [frenchpunctuation] ["0021] [\c!left =.25,\c!alternative=1] % ! % strip preceding space(char)
+\setupcharacterspacing [frenchpunctuation] ["00AB] [\c!right=.25,\c!alternative=1] % guillemotleft/leftguillemot % strip following space(char)
+\setupcharacterspacing [frenchpunctuation] ["00BB] [\c!left =.25,\c!alternative=1] % guillemotright/rightguillemot % strip preceding space(char)
+
+\protect \endinput
diff --git a/tex/context/base/unic-035.tex b/tex/context/base/unic-035.tex
new file mode 100644
index 000000000..272799512
--- /dev/null
+++ b/tex/context/base/unic-035.tex
@@ -0,0 +1,32 @@
+%D \module
+%D [ file=unic-035,
+%D version=2009.05.25,
+%D title=\CONTEXT\ \UNICODE\ Macros,
+%D subtitle=Vector 35,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+
+\unprotect
+
+\startunicodevector 35
+ \expandafter\strippedcsname
+ \ifcase\numexpr#1\relax
+ \varnothing \or % DIAMETER SIGN
+ \unknownchar \or % ELECTRIC ARROW
+ \unknownchar \or % HOUSE
+ \unknownchar \or % UP ARROWHEAD
+ \unknownchar \or % DOWN ARROWHEAD
+ \unknownchar \or % PROJECTIVE
+ \unknownchar \or % PERSPECTIVE
+ \unknownchar \or % WAVY LINE
+ \lceil \or % LEFT CEILING
+ \rceil \or % RIGHT CEILING
+ \lfloor \or % LEFT FLOOR
+ \rfloor \or % RIGHT FLOOR
+ \unknownchar \else
+ \unknownchar %
+ \fi
+\stopunicodevector
+
+\protect \endinput
diff --git a/tex/context/base/unic-exp.tex b/tex/context/base/unic-exp.tex
index 7d7f9f0c5..027aedab8 100644
--- a/tex/context/base/unic-exp.tex
+++ b/tex/context/base/unic-exp.tex
@@ -2,7 +2,7 @@
%D [ file=unic-exp,
%D version=2002.12.05,
%D title=\CONTEXT\ \UNICODE\ Support,
-%D subtitle=\UNICODE\ vector expansion,
+%D subtitle=Expansion,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context UNICODE Macros (expansion)}
+\writestatus{loading}{ConTeXt Unicode Support / Expansion)}
%D \macros
%D {expandunivector}
diff --git a/tex/context/base/unic-ini.mkii b/tex/context/base/unic-ini.mkii
index 27ef38620..0e4d9d391 100644
--- a/tex/context/base/unic-ini.mkii
+++ b/tex/context/base/unic-ini.mkii
@@ -2,7 +2,7 @@
%D [ file=unic-ini,
%D version=2002.12.03,
%D title=\CONTEXT\ \UNICODE\ Support,
-%D subtitle=\UNICODE\ \& UTF-8 support,
+%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context UNICODE Macros (ini)}
+\writestatus{loading}{ConTeXt Unicode Support / Initialization}
%D Sorry, we only support his in \ETEX.
@@ -725,9 +725,9 @@
\def\numbertohexstring#1{0x\uchexnumbers{\utfdiv{#1}}\uchexnumbers{\utfmod{#1}}}
-\beginXETEX
+\ifnum\texengine=\xetexengine
\let\numbertoutf\numbertohexstring
-\endXETEX
+\fi
\def\uchartoutf#1#2%
{\expandafter\numbertoutf\expandafter{\the\numexpr#1*\utf@h+#2\relax}}
@@ -767,7 +767,7 @@
%D Well, let's at least preload a few familiar ones. Here we
%D also load the \UTF\ regime.
-\useunicodevector[0,1,2,3,4,5,30,31,32,33,34,37,39,251]
+\useunicodevector[0,1,2,3,4,5,30,31,32,33,34,35,37,39,251]
\useunicodevector[cjk]
\useregime[utf]
diff --git a/tex/context/base/unic-ini.mkiv b/tex/context/base/unic-ini.mkiv
index a174f7a39..8b0c819d9 100644
--- a/tex/context/base/unic-ini.mkiv
+++ b/tex/context/base/unic-ini.mkiv
@@ -11,23 +11,14 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context UNICODE Macros (ini)}
+\writestatus{loading}{ConTeXt Unicode Support / Initialization}
%D Much of this is not needed at all in \LUATEX\ and we can save some
%D 50K on the compressed format.
\unprotect
-\def\keeputfcharacters {}
-\def\registerprivateunicodechar#1 {}
-\def\defineunicodecommand #1 #2{}
-\def\doifunicodevector #1{\firstofoneargument}
-\def\useunicodevector [#1]{}
-\def\startunicodevector #1\stopunicodevector{}
-\def\unicodeinfoline #1#2#3{}
-\def\cleanunicodechar #1{#1}
-\def\unicodeunknowncharacter {\unknownchar}
-
+\let \keeputfcharacters\relax
\chardef\utfunicodetracer \zerocount
\chardef\utfunicommandmode\zerocount
@@ -39,10 +30,4 @@
\ifx\zwnbsp\undefined \let\zwnbsp\relax \fi % zerowidthnonbreakablespace
-\def\showunicodevector[#1]{}
-\def\showunicodetable [#1]{}
-
-% \fetchruntimecommand \showunicodevector {\f!unicprefix\s!run}
-% \fetchruntimecommand \showunicodetable {\f!unicprefix\s!run}
-
\protect \endinput
diff --git a/tex/context/base/verb-c.tex b/tex/context/base/verb-c.tex
index d2f708a8d..1ecb0afc2 100644
--- a/tex/context/base/verb-c.tex
+++ b/tex/context/base/verb-c.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Support Macros / Pretty C Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty C Verbatim}
% HH:
%
diff --git a/tex/context/base/verb-eif.tex b/tex/context/base/verb-eif.tex
index 16ee611e1..5904abc6e 100644
--- a/tex/context/base/verb-eif.tex
+++ b/tex/context/base/verb-eif.tex
@@ -8,13 +8,13 @@
%D copyright={Berend de Boer \& Hans Hagen}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
% This module will be cleaned up a bit in the process of more
% flexible verbatim options.
-\writestatus{loading}{Context Support Macros / Pretty EIFFEL Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty EIFFEL Verbatim}
%D \startbuffer
%D \startEIFFEL
@@ -32,7 +32,7 @@
%D
%D end
%D \stopEIFFEL
-%D \stopbuffer
+%D \stopbuffer
%D
%D
%D If a variable in a comment is quoted with `..', it is typeset
@@ -41,18 +41,18 @@
%D \startbuffer
%D \startEIFFEL
%D class TEST
-%D
+%D
%D feature
-%D
+%D
%D say (something: STRING) is
%D -- say `something' to stdout
%D do
%D print (something)
%D end
-%D
+%D
%D end -- class TEST
%D \stopEIFFEL
-%D \stopbuffer
+%D \stopbuffer
%D
%D
%D Recommended, OOSC2 style setting is:
@@ -71,7 +71,7 @@
%D \EIFFEL\ has only the one line comment sequence \type{--}.
\gdef\EIFsetspecials%
- {\PLsetspecials
+ {\PLsetspecials
\setpretty`\#=32
\setpretty`\{=33 \setpretty`\}=33
\setpretty`\[=33 \setpretty`\]=33 \setpretty`\(=33 \setpretty`\)=33
@@ -80,7 +80,7 @@
\setpretty`\==33 \setpretty`\~=33 \setpretty`\<=33 \setpretty`\>=33
\setpretty`\-=33 \setpretty`\+=33 \setpretty`\/=33 \setpretty`\*=33
\setpretty`\^=33
- \setpretty`\%=41 \setpretty`\-=45
+ \setpretty`\%=41 \setpretty`\-=45
\setpretty`\`=81 \setpretty`\'=82 }
\gdef\EIFsethandlers%
@@ -119,7 +119,7 @@
{\endPLtypesix
\ifinPLcomment
\getpretty{#1}%
- \else
+ \else
{\prettynaturalfont\/%
\beginofpretty[\!!prettythree]\getpretty{#1}\endofpretty}%
\fi}
@@ -208,4 +208,4 @@
\useprettyidentifiers \EIFvariables \EIFsetspecials
not-yet-defined
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/verb-ini.tex b/tex/context/base/verb-ini.tex
index 27c30d20e..4726d0eac 100644
--- a/tex/context/base/verb-ini.tex
+++ b/tex/context/base/verb-ini.tex
@@ -41,7 +41,7 @@
%D \TEX\ supposed to do when it encounters a \type{$} or an
%D \type{#}? This module deals with these matters.
-\writestatus{loading}{Context Verbatim Macros / Initialization}
+\writestatus{loading}{ConTeXt Verbatim Macros / Initialization}
%D The verbatim environment has some features, like coloring
%D \TEX\ text, seldom found in other environments. Especially
diff --git a/tex/context/base/verb-js.tex b/tex/context/base/verb-js.tex
index e8c2e6b5d..3d1b69f8b 100644
--- a/tex/context/base/verb-js.tex
+++ b/tex/context/base/verb-js.tex
@@ -8,26 +8,26 @@
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-\writestatus{loading}{Context Support Macros / Pretty JavaScript Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty JavaScript Verbatim}
%D In \CONTEXT\ we support \JAVASCRIPT\ inclusion in \PDF\
%D documents and thereby enter the field of authoring. Of
%D course we also want to pretty print such scripts, that look
-%D like:
-%D
+%D like:
+%D
%D \startJS
-%D alfa = beta*2 ; // both alfa and beta are numbers // indeed
+%D alfa = beta*2 ; // both alfa and beta are numbers // indeed
%D if (odd(alfa))
-%D { do_something() }
+%D { do_something() }
%D else
%D { do_nothing() } /* As we can see /* in this example */ there
%D how_about(alfa) ; is no fi needed. Also no semicolons are
%D or_about(beta) ; needed after a right brace. */
%D \stopJS
-%D
+%D
%D Because \JAVASCRIPT\ looks much like \PERL, we will use
%D a slightly adapted \PERL\ visualization. First we load the
%D \PERL\ module:
@@ -168,4 +168,4 @@
\useprettyidentifiers \JSvariables \JSsetspecials
not-yet-defined
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/verb-jv.tex b/tex/context/base/verb-jv.tex
index d55394d2c..197b37ee7 100644
--- a/tex/context/base/verb-jv.tex
+++ b/tex/context/base/verb-jv.tex
@@ -8,19 +8,19 @@
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-\writestatus{loading}{Context Support Macros / Pretty Java Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty Java Verbatim}
%D This module differs from the \JAVASCRIPT\ driver in its
%D handling of comments. We also need a few more handlers: one
%D for \type {//} and \type {/*} and one for \type {*/} as
-%D well as the \JAVA doc trigger \type {/**}.
+%D well as the \JAVA doc trigger \type {/**}.
%D We build this driver on top of the \PERL\ one. Since this
-%D driver looks much like the \JAVASCRIPT\ one, we don't
-%D comment it extensively.
+%D driver looks much like the \JAVASCRIPT\ one, we don't
+%D comment it extensively.
\ifx\undefined\setupprettyPLtype \input verb-pl \relax \fi
@@ -32,14 +32,14 @@
{\PLsetspecials
\setpretty`\#=32
\setpretty`\%=41
- \setpretty`\-=45
+ \setpretty`\-=45
\setpretty`\/=43
\setpretty`\*=44 }
\gdef\JVsethandlers
{\PLsethandlers
\installprettyhandler 43 \JVtypefourthree
- \installprettyhandler 44 \JVtypefourfour
+ \installprettyhandler 44 \JVtypefourfour
\installprettyhandler 45 \JVtypefourfive }
\gdef\JVsetcontrols
@@ -128,7 +128,7 @@
\global\advance\JVcommentlevel -1
\ifcase\JVcommentlevel \global\inPLcommentfalse \fi
\else
- \ifPLdocdone
+ \ifPLdocdone
\getpretty{#1}%
\else
\beginofpretty[\!!prettyone]\getpretty{#1}\endofpretty
@@ -150,7 +150,7 @@
\expandafter#2%
\fi}
-\gdef\JVtypefourfive % permit - in javadoc @tags
+\gdef\JVtypefourfive % permit - in javadoc @tags
{\ifinPLdoc
\@EA\PLtypesixtwo
\else
@@ -164,35 +164,35 @@
int interface long native new null package private protected
public return short static strictfp super switch synchronized
this throw throws transient true try void volatile while
-
+
\useprettyidentifiers \JVvariables \JVsetspecials
- @author @docRoot @deprecated @exception @inheritDoc @link
- @linkplain @param @return @see @serial @serialData @serialField
- @since @throws @value @version
-
-%D The \JAVA doc feature was requested by Robert F.~Beeger,
-%D who also provided this test class:
-%D
-%D \startJV
+ @author @docRoot @deprecated @exception @inheritDoc @link
+ @linkplain @param @return @see @serial @serialData @serialField
+ @since @throws @value @version
+
+%D The \JAVA doc feature was requested by Robert F.~Beeger,
+%D who also provided this test class:
+%D
+%D \startJV
%D package de.jwamalpha.handling.web.rbdipl;
-%D
+%D
%D import java.io.IOException;
%D import java.io.PrintWriter;
%D import javax.servlet.http.HttpServlet;
%D import javax.servlet.http.HttpServletRequest;
%D import javax.servlet.http.HttpServletResponse;
%D import javax.servlet.ServletException;
-%D
+%D
%D /**
%D * The simple login servlet
%D *
%D * @author Robert F. Beeger
%D * @version 1.0
%D */
-%D
+%D
%D public class LoginServlet extends HttpServlet
%D {
-%D //
+%D //
%D // public interface
%D //
%D /**
@@ -217,6 +217,6 @@
%D writer.flush();
%D }
%D }
-%D \stopJV
+%D \stopJV
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/verb-lua.lua b/tex/context/base/verb-lua.lua
index ba0e24460..9ba22c1f2 100644
--- a/tex/context/base/verb-lua.lua
+++ b/tex/context/base/verb-lua.lua
@@ -6,6 +6,12 @@
-- BROKEN : result is now table
+local utf = unicode.utf8
+
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
+local ctxcatcodes = tex.ctxcatcodes
+
if not buffers then buffers = { } end
if not buffers.visualizers then buffers.visualizers = { } end
if not buffers.visualizers.lua then buffers.visualizers.lua = { } end
@@ -146,7 +152,7 @@ function buffers.visualizers.lua.flush_line(str, nested)
--~ end
--~ end
--~ -- bla bla1 bla.bla
---~ for c in code:utfcharacters() do
+--~ for c in utfcharacters(code) do
--~ if instr then
--~ if c == s then
--~ if inesc then
@@ -205,6 +211,6 @@ function buffers.visualizers.lua.flush_line(str, nested)
--~ else
--~ state, result = buffers.finish_state(state,result)
--~ end
---~ tex.sprint(tex.ctxcatcodes,result)
+--~ tex.sprint(ctxcatcodes,result)
return "not yet finished"
end
diff --git a/tex/context/base/verb-mp.lua b/tex/context/base/verb-mp.lua
index 1182888b0..4ff957b41 100644
--- a/tex/context/base/verb-mp.lua
+++ b/tex/context/base/verb-mp.lua
@@ -4,6 +4,10 @@
-- copyright: PRAGMA ADE / ConTeXt Development Team
-- license : see context related readme files
+local utf = unicode.utf8
+
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
if not buffers then buffers = { } end
if not buffers.visualizers then buffers.visualizers = { } end
if not buffers.visualizers.mp then buffers.visualizers.mp = { } end
@@ -177,7 +181,7 @@ function buffers.visualizers.mp.flush_line_(str,nested)
local byte, find = utf.byte, utf.find
local finish, change = buffers.finish_state, buffers.change_state
buffers.currentcolors = buffers.visualizers.mp.colors
- for c in str:utfcharacters() do
+ for c in utfcharacters(str) do
if incomment then
result[#result+1] = buffers.escaped_chr(c)
elseif c == '%' then
diff --git a/tex/context/base/verb-mp.tex b/tex/context/base/verb-mp.tex
index 318da96bf..7affaf0c4 100644
--- a/tex/context/base/verb-mp.tex
+++ b/tex/context/base/verb-mp.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Support Macros / Pretty METAPOST Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty METAPOST Verbatim}
% bug: in mp-char.mp the char should not be highlighted
diff --git a/tex/context/base/verb-pas.tex b/tex/context/base/verb-pas.tex
index b7b041700..0c9850abf 100644
--- a/tex/context/base/verb-pas.tex
+++ b/tex/context/base/verb-pas.tex
@@ -14,7 +14,7 @@
% This module will be cleaned up a bit in the process of more
% flexible verbatim options.
-\writestatus{loading}{Context Support Macros / Pretty PASCAL Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty PASCAL Verbatim}
%D Typeset Pascal(-like) code:
%D
@@ -87,14 +87,14 @@
\PASsetspecials
\PLsetdiagnostics}
-
% the // and /* comments
\gdef\PAStypefourthree%
{\handlenextnextpretty\doPAStypefourthree\PLtypefourtwo}
\gdef\doPAStypefourthree#1#2%
- {\ifinPLcomment
+ {\endPLtypesix
+ \ifinPLcomment
\let\next=\PLtypefourtwo
\else
\ifinPLsingle
diff --git a/tex/context/base/verb-pl.tex b/tex/context/base/verb-pl.tex
index cbe82d49f..47ce9a54f 100644
--- a/tex/context/base/verb-pl.tex
+++ b/tex/context/base/verb-pl.tex
@@ -8,46 +8,46 @@
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
-%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
-%C details.
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
-\writestatus{loading}{Context Support Macros / Pretty PERL Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty PERL Verbatim}
-%D When I rewrote \TEXUTIL\ in \PERL\ I decided to write a
-%D pretty \PERL\ interpreter too. In fact, this was the main
-%D reason for rewriting the pretty verbatim mechanisms to
-%D handle more that \TEX.
+%D When I rewrote \TEXUTIL\ in \PERL\ I decided to write a
+%D pretty \PERL\ interpreter too. In fact, this was the main
+%D reason for rewriting the pretty verbatim mechanisms to
+%D handle more that \TEX.
%D
-%D \startPL
+%D \startPL
%D $alfa = $beta{gamma};
-%D if ($alfa="delta")
+%D if ($alfa="delta")
%D { print "epsilon" }
%D \stopPL
-%D
-%D When looking at the macros, watch the \type{\doglobal}'s!
-%D They're something \CONTEXT\ specific.
+%D
+%D When looking at the macros, watch the \type{\doglobal}'s!
+%D They're something \CONTEXT\ specific.
\unprotect
%D \macros
%D {prettyPLvariables}
%D
-%D Identifiers and system variables get a special treatment.
-%D One can disable this option for the variables by resetting
+%D Identifiers and system variables get a special treatment.
+%D One can disable this option for the variables by resetting
%D the next switch.
-\doglobal\newif\ifprettyPLvariables
+\doglobal\newif\ifprettyPLvariables
\global\prettyPLvariablestrue
-%D As said before, the global assignment is needed in
-%D \CONTEXT\ (for once||only loading on demand).
+%D As said before, the global assignment is needed in
+%D \CONTEXT\ (for once||only loading on demand).
\doglobal\newif\ifinPLsingle
\doglobal\newif\ifinPLdouble
\doglobal\newif\ifinPLcomment
-\doglobal\newif\ifinPLdoc % only used in java filter
-\doglobal\newif\ifPLdocdone % only used in java filter
+\doglobal\newif\ifinPLdoc % only used in java filter
+\doglobal\newif\ifPLdocdone % only used in java filter
\doglobal\newif\ifPLverbose
\newcount\PLverboseskipped
@@ -56,7 +56,7 @@
{\ifnum\PLverboseskipped>0
\obeyedspace
\advance\PLverboseskipped -1
- \@EA\PLverbosecorrection
+ \@EA\PLverbosecorrection
\fi}
\gdef\PLsetcontrols%
@@ -73,7 +73,7 @@
\global\inPLcommentfalse}%
\def\obeyedline%
{\PLverbosefalse
- \PLverboseskipped=0
+ \PLverboseskipped=0
\PLdocdonefalse
\oldobeyedline}%
\let\obeytabs=\ignoretabs}
@@ -189,7 +189,7 @@
% \beginofpretty[\!!prettytwo]\getpretty{#1}\endofpretty
% \fi\fi\fi}
-\gdef\PLtypetwo#1%
+\gdef\PLtypetwo#1%
{\endPLtypesix
\ifinPLdoc
\xdef\PLsequence{\PLsequence\getpretty{#1}}%
@@ -352,7 +352,7 @@
\global\let\PLprefix\empty
\fi}
-\gdef\doendPLtypesix#1%
+\gdef\doendPLtypesix#1%
{\doifprettyidentifierelse{\PLsequence}{\PLverboses}
{\PLverbosetrue\PLverboseskipped=3 }
{\doifprettyidentifierelse{\PLsequence}{\PLidentifiers}
@@ -369,7 +369,7 @@
\PLsequence
\fi}}}
-\gdef\doendPLtypesixvar#1%
+\gdef\doendPLtypesixvar#1%
{\doifprettyidentifierelse{\PLprefix\PLsequence}{\PLvariables}
{\beginofpretty[#1]%
{\prettyvariablefont\PLsequence}%
@@ -398,7 +398,7 @@
% \xdef\PLsequence{\PLsequence\getpretty{#1}}%
% \fi\fi\fi}
-\gdef\PLtypesixtwo#1%
+\gdef\PLtypesixtwo#1%
{\ifinPLdoc
\xdef\PLsequence{\PLsequence\getpretty{#1}}%
\else\ifinPLcomment
@@ -468,7 +468,7 @@
\else
\global\inPLcommenttrue
\PLverbosecorrection
- \ifnaturaltextext % non tested yet
+ \ifnaturaltextext % non tested yet
\let\next\naturaltextext
\else
\def\next{\beginofpretty[\!!prettythree]\getpretty{#1}\endofpretty}%
@@ -537,11 +537,11 @@
&GetOptions
%D A funny hack. When prefixes by \type{TEX}, a \type{\csname}
-%D is typeset as \TEX\ sequence.
+%D is typeset as \TEX\ sequence.
\useprettyidentifiers \PLverboses \PLsetspecials
TEX
-\protect
+\protect
-\endinput
+\endinput
diff --git a/tex/context/base/verb-sql.tex b/tex/context/base/verb-sql.tex
index ddac5cd25..a00841d73 100644
--- a/tex/context/base/verb-sql.tex
+++ b/tex/context/base/verb-sql.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Support Macros / Pretty SQL Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty SQL Verbatim}
%D \quotation {He, I want pretty pretting too!}, Berend cried out
%D one day, \quotation {But now for \SQL.}. This query language
diff --git a/tex/context/base/verb-tex.lua b/tex/context/base/verb-tex.lua
index ad72fb211..98e6eccb4 100644
--- a/tex/context/base/verb-tex.lua
+++ b/tex/context/base/verb-tex.lua
@@ -4,6 +4,10 @@
-- copyright: PRAGMA ADE / ConTeXt Development Team
-- license : see context related readme files
+local utf = unicode.utf8
+
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
if not buffers then buffers = { } end
if not buffers.visualizers then buffers.visualizers = { } end
if not buffers.visualizers.tex then buffers.visualizers.tex = { } end
@@ -32,7 +36,7 @@ function buffers.visualizers.tex.flush_line(str,nested)
local byte, find = utf.byte, utf.find
local finish, change = buffers.finish_state, buffers.change_state
buffers.currentcolors = buffers.visualizers.tex.colors
- for c in str:utfcharacters() do
+ for c in utfcharacters(str) do
if c == " " then
if escaping then
result[#result+1] = " "
diff --git a/tex/context/base/verb-tex.tex b/tex/context/base/verb-tex.tex
index a70edd353..75e99fcef 100644
--- a/tex/context/base/verb-tex.tex
+++ b/tex/context/base/verb-tex.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context Support Macros / Pretty TEX Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty TEX Verbatim}
%D The original module \type{supp-ver} had the \TEX\
%D interpreter built in. The current implementation is more
diff --git a/tex/context/base/verb-xml.tex b/tex/context/base/verb-xml.tex
index 7b0237315..dbf6635f6 100644
--- a/tex/context/base/verb-xml.tex
+++ b/tex/context/base/verb-xml.tex
@@ -14,7 +14,7 @@
% This module will be cleaned up a bit in the process of more
% flexible verbatim options.
-\writestatus{loading}{Context Support Macros / Pretty XML Verbatim}
+\writestatus{loading}{ConTeXt Verbatim Macros / Pretty XML Verbatim}
\unprotect
diff --git a/tex/context/base/x-calcmath.lua b/tex/context/base/x-calcmath.lua
index 24ef130be..fcb6b7470 100644
--- a/tex/context/base/x-calcmath.lua
+++ b/tex/context/base/x-calcmath.lua
@@ -6,58 +6,60 @@ if not modules then modules = { } end modules ['x-calcmath'] = {
license = "see context related readme files"
}
+local format, lower, upper, gsub = string.format, string.lower, string.upper, string.gsub
tex = tex or { }
texsprint = tex.sprint or function(catcodes,str) print(str) end
--- ancient stuff, pre-lpeg so i need to redo it
-
calcmath = { }
-calcmath.list_1 = {
+local list_1 = {
"median", "min", "max", "round", "ln", "log",
"sin", "cos", "tan", "sinh", "cosh", "tanh"
}
-calcmath.list_2 = {
+local list_2 = {
"int", "sum", "prod"
}
-calcmath.list_3 = {
+local list_3 = {
"f", "g"
}
-calcmath.list_4 = {
+local list_4 = {
"pi", "inf"
}
-calcmath.list_1_1 = { }
-calcmath.list_2_1 = { }
-calcmath.list_2_2 = { }
-calcmath.list_2_3 = { }
-calcmath.list_4_1 = { }
+local list_1_1 = { }
+local list_2_1 = { }
+local list_2_2 = { }
+local list_2_3 = { }
+local list_4_1 = { }
-calcmath.frozen = false -- we can add stuff and unfreeze
+local frozen = false
-function calcmath.freeze()
- for _,v in ipairs(calcmath.list_1) do
- calcmath.list_1_1[v] = "\\".. v:upper() .." "
+local function freeze()
+ for k=1,#list_1 do
+ local v = list_1[k]
+ list_1_1[v] = "\\".. upper(v) .." "
end
- for _,v in ipairs(calcmath.list_2) do
- calcmath.list_2_1[v .. "%((.-),(.-),(.-)%)"] = "\\" .. v:upper() .. "^{%1}_{%2}{%3}"
- calcmath.list_2_2[v .. "%((.-),(.-)%)"] = "\\" .. v:upper() .. "^{%1}{%2}"
- calcmath.list_2_3[v .. "%((.-)%)"] = "\\" .. v:upper() .. "{%1}"
+ for k=1,#list_2 do
+ local v = list_2[k]
+ list_2_1[v .. "%((.-),(.-),(.-)%)"] = "\\" .. upper(v) .. "^{%1}_{%2}{%3}"
+ list_2_2[v .. "%((.-),(.-)%)"] = "\\" .. upper(v) .. "^{%1}{%2}"
+ list_2_3[v .. "%((.-)%)"] = "\\" .. upper(v) .. "{%1}"
end
- for _,v in ipairs(calcmath.list_4) do
- calcmath.list_4_1[v] = "\\" .. v:upper()
+ for k=1,#list_4 do
+ local v = list_4[k]
+ list_4_1[v] = "\\" .. upper(v)
end
- calcmath.frozen = true
+ frozen = true
end
-calcmath.entities = {
+local entities = {
['gt'] = '>',
['lt'] = '<',
}
-calcmath.symbols = {
+local symbols = {
["<="] = "\\LE ",
[">="] = "\\GE ",
["=<"] = "\\LE ",
@@ -68,120 +70,19 @@ calcmath.symbols = {
["="] = "\\EQ ",
}
---~ function calcmath.nsub(str,tag,pre,post)
---~ return (string.gsub(str, tag .. "(%b())", function(body)
---~ return pre .. calcmath.nsub(string.sub(body,2,-2),tag,pre,post) .. post
---~ end))
---~ end
-
---~ function calcmath.tex(str,mode)
---~ if not calcmath.frozen then calcmath.freeze() end
---~ local n = 0
---~ local ssub = string.gsub
---~ local nsub = calcmath.nsub
---~ local strp = string.sub
---~ -- crap
---~ str = ssub(str,"%s+" , ' ')
---~ -- xml
---~ str = ssub(str,"&(.-);", calcmath.entities)
---~ -- ...E...
---~ str = ssub(str,"([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}")
---~ -- ^-..
---~ str = ssub(str, "%^([%-%+]*%d+)", "^{%1}")
---~ -- ^(...)
---~ str = nsub(str, "%^", "^{", "}")
---~ -- 1/x^2
---~ repeat
---~ str, n = ssub(str, "([%d%w%.]+)/([%d%w%.]+%^{[%d%w%.]+})", "\\frac{%1}{%2}")
---~ until n == 0
---~ -- todo: autoparenthesis
---~ -- int(a,b,c)
---~ for k,v in pairs(calcmath.list_2_1) do -- for i=1,...
---~ repeat str, n = ssub(str, k, v) until n == 0
---~ end
---~ -- int(a,b)
---~ for k,v in pairs(calcmath.list_2_2) do
---~ repeat str, n = ssub(str, k, v) until n == 0
---~ end
---~ -- int(a)
---~ for k,v in pairs(calcmath.list_2_3) do
---~ repeat str, n = ssub(str, k, v) until n == 0
---~ end
---~ -- sin(x) => {\\sin(x)}
---~ for k,v in pairs(calcmath.list_1_1) do
---~ repeat str, n = ssub(str, k, v) until n == 0
---~ end
---~ -- mean
---~ str = nsub(str, "mean", "\\OVERLINE{", "}")
---~ -- (1+x)/(1+x) => \\FRAC{1+x}{1+x}
---~ repeat
---~ str, n = ssub(str, "(%b())/(%b())", function(a,b)
---~ return "\\FRAC{" .. strp(a,2,-2) .. "}{" .. strp(b,2,-2) .. "}"
---~ end )
---~ until n == 0
---~ -- (1+x)/x => \\FRAC{1+x}{x}
---~ repeat
---~ str, n = ssub(str, "(%b())/([%+%-]?[%.%d%w]+)", function(a,b)
---~ return "\\FRAC{" .. strp(a,2,-2) .. "}{" .. b .. "}"
---~ end )
---~ until n == 0
---~ -- 1/(1+x) => \\FRAC{1}{1+x}
---~ repeat
---~ str, n = ssub(str, "([%.%d%w]+)/(%b())", function(a,b)
---~ return "\\FRAC{" .. a .. "}{" .. strp(b,2,-2) .. "}"
---~ end )
---~ until n == 0
---~ -- 1/x => \\FRAC{1}{x}
---~ repeat
---~ str, n = ssub(str, "([%.%d%w]+)/([%+%-]?[%.%d%w]+)", "\\FRAC{%1}{%2}")
---~ until n == 0
---~ -- times
---~ str = ssub(str, "%*", " ")
---~ -- symbols -- we can use a table substitution here
---~ str = ssub(str, "([<>=][<>=]*)", calcmath.symbols)
---~ -- functions
---~ str = nsub(str, "sqrt", "\\SQRT{", "}")
---~ str = nsub(str, "exp", "e^{", "}")
---~ str = nsub(str, "abs", "\\left|", "\\right|")
---~ -- d/D
---~ str = nsub(str, "D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}")
---~ str = ssub(str, "D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}")
---~ -- f/g
---~ for k,v in pairs(calcmath.list_3) do -- todo : prepare k,v
---~ str = nsub(str, "D"..v,"{\\RM "..v.."}^{\\PRIME}(",")")
---~ str = nsub(str, v,"{\\RM "..v.."}(",")")
---~ end
---~ -- more symbols
---~ for k,v in pairs(calcmath.list_4_1) do
---~ str = ssub(str, k, v)
---~ end
---~ -- parenthesis (optional)
---~ if mode == 2 then
---~ str = ssub(str, "%(", "\\left\(")
---~ str = ssub(str, "%)", "\\right\)")
---~ end
---~ -- csnames
---~ str = ssub(str, "(\\[A-Z]+)", function(a) return a:lower() end)
---~ -- report
---~ texsprint(tex.texcatcodes,str)
---~ end
-
--- 5% faster
-
-function calcmath.nsub(str,tag,pre,post)
+local function nsub(str,tag,pre,post)
return (str:gsub(tag .. "(%b())", function(body)
- return pre .. calcmath.nsub(body:sub(2,-2),tag,pre,post) .. post
+ return pre .. nsub(body:sub(2,-2),tag,pre,post) .. post
end))
end
-function calcmath.totex(str,mode) -- 5% faster
- if not calcmath.frozen then calcmath.freeze() end
+function calcmath.totex(str,mode)
+ if not frozen then freeze() end
local n = 0
- local nsub = calcmath.nsub
-- crap
str = str:gsub("%s+" , ' ')
-- xml
- str = str:gsub("&(.-);", calcmath.entities)
+ str = str:gsub("&(.-);", entities)
-- ...E...
str = str:gsub("([%-%+]?[%d%.%+%-]+)E([%-%+]?[%d%.]+)", "{\\SCINOT{%1}{%2}}")
-- ^-..
@@ -194,19 +95,19 @@ function calcmath.totex(str,mode) -- 5% faster
until n == 0
-- todo: autoparenthesis
-- int(a,b,c)
- for k,v in pairs(calcmath.list_2_1) do
- repeat str, n = str:gsub(k, v) until n == 0
+ for k, v in next, list_2_1 do
+ repeat str, n = str:gsub(k,v) until n == 0
end
-- int(a,b)
- for k,v in pairs(calcmath.list_2_2) do
+ for k, v in next, list_2_2 do
repeat str, n = str:gsub(k, v) until n == 0
end
-- int(a)
- for k,v in pairs(calcmath.list_2_3) do
+ for k, v in next, list_2_3 do
repeat str, n = str:gsub(k, v) until n == 0
end
-- sin(x) => {\\sin(x)}
- for k,v in pairs(calcmath.list_1_1) do
+ for k, v in next, list_1_1 do
repeat str, n = str:gsub(k, v) until n == 0
end
-- mean
@@ -236,7 +137,7 @@ function calcmath.totex(str,mode) -- 5% faster
-- times
str = str:gsub("%*", " ")
-- symbols -- we can use a table substitution here
- str = str:gsub("([<>=][<>=]*)", calcmath.symbols)
+ str = str:gsub("([<>=][<>=]*)", symbols)
-- functions
str = nsub(str, "sqrt", "\\SQRT{", "}")
str = nsub(str, "exp", "e^{", "}")
@@ -245,12 +146,12 @@ function calcmath.totex(str,mode) -- 5% faster
str = nsub(str, "D", "{\\FRAC{\\MBOX{d}}{\\MBOX{d}x}{(", ")}}")
str = str:gsub("D([xy])", "\\FRAC{{\\RM d}%1}{{\\RM d}x}")
-- f/g
- for k,v in pairs(calcmath.list_3) do -- todo : prepare k,v
+ for k,v in next, list_3 do -- todo : prepare k,v
str = nsub(str, "D"..v,"{\\RM "..v.."}^{\\PRIME}(",")")
str = nsub(str, v,"{\\RM "..v.."}(",")")
end
-- more symbols
- for k,v in pairs(calcmath.list_4_1) do
+ for k,v in next, list_4_1 do
str = str:gsub(k, v)
end
-- parenthesis (optional)
@@ -259,7 +160,9 @@ function calcmath.totex(str,mode) -- 5% faster
str = str:gsub("%)", "\\right\)")
end
-- csnames
- str = str:gsub("(\\[A-Z]+)", function(a) return a:lower() end)
+ str = str:gsub("(\\[A-Z]+)", lower)
+ -- trace
+--~ print(str)
-- report
return str
end
@@ -299,7 +202,6 @@ if false then
local real = Cc("real") * C(real_x) * space
local float = Cc("float") * C(real_x) * lpeg.P("E") * lpeg.C(number_x) * space
local identifier = Cc("identifier") * C(R("az","AZ")^1) * space
- -- compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;")/">" + P("&lt;")/"<") * space
local compareop = P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;") + P("&lt;")
local factorop = Cc("factor") * C(S("+-^,") + compareop ) * space
local termop = Cc("term") * C(S("*/")) * space
@@ -310,7 +212,6 @@ if false then
local grammar = P {
"expression",
- --~ comparison = Ct(V("expression") * (compareop * V("expression"))^0),
expression = Ct(V("factor" ) * (factorop * V("factor" ))^0),
factor = Ct(V("term" ) * (termop * V("term" ))^0),
term = Ct(
@@ -323,8 +224,6 @@ if false then
local parser = space * grammar * -1
- local format = string.format
-
function totex(t)
if t then
local one, two, three = t[1], t[2], t[3]
@@ -423,9 +322,13 @@ if false then
return parser:match(str)
end
- function calcmath.totex(str)
+ function calcmath.tex(str)
str = totex(parser:match(str))
+ print(str)
return (str == "" and "[error]") or str
end
end
+
+--~ compareop = Cc("compare") * C(P("<") + P("=") + P(">") + P(">=") + P("<=") + P("&gt;")/">" + P("&lt;")/"<") * space
+--~ comparison = Ct(V("expression") * (compareop * V("expression"))^0),
diff --git a/tex/context/base/x-cals.mkiv b/tex/context/base/x-cals.mkiv
index daa9f2477..3d2644045 100644
--- a/tex/context/base/x-cals.mkiv
+++ b/tex/context/base/x-cals.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (cals tables)}
+\writestatus{loading}{ConTeXt XML Macros / Cals Tables}
\startluacode
do
@@ -103,12 +103,11 @@ do
sum = sum + v
end
end
--- local delta = sum - tex.hsize:todimen()
-local hsize = tex.hsize
-if type(hsize) == "string" then
- hsize = hsize:todimen()
-end
-local delta = sum - hsize
+ local hsize = tex.hsize
+ if type(hsize) == "string" then
+ hsize = hsize:todimen()
+ end
+ local delta = sum - hsize
if shrink_widths and delta > 0 then
adapt(shrink_widths,w,delta,sum,n,"shrink")
elseif stretch_widths and delta < 0 then
@@ -201,6 +200,7 @@ local delta = sum - hsize
for r, d, k in xml.elements(lxml.id(root),tgroupspec) do
local tgroup = d[k]
+ texsprint(tex.ctxcatcodes, "\\directsetup{cals:table:before}")
lxml.directives.before(root,"cdx") -- "cals:table"
texsprint(tex.ctxcatcodes, "\\bgroup")
lxml.directives.setup(root,"cdx") -- "cals:table"
@@ -211,6 +211,7 @@ local delta = sum - hsize
texsprint(tex.ctxcatcodes, "\\eTABLE")
texsprint(tex.ctxcatcodes, "\\egroup")
lxml.directives.after(root,"cdx") -- "cals:table"
+ texsprint(tex.ctxcatcodes, "\\directsetup{cals:table:after}")
end
end
diff --git a/tex/context/base/x-chemml.mkiv b/tex/context/base/x-chemml.mkiv
index 372165092..e0da353fc 100644
--- a/tex/context/base/x-chemml.mkiv
+++ b/tex/context/base/x-chemml.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (chemml mkiv)}
+\writestatus{loading}{ConTeXt XML Macros / Chemistry}
\usemodule[pictex,chemic] % someday we will do structural fomulas in mp
diff --git a/tex/context/base/x-ct.mkiv b/tex/context/base/x-ct.mkiv
index cf7bb64fb..17ea25408 100644
--- a/tex/context/base/x-ct.mkiv
+++ b/tex/context/base/x-ct.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (context)}
+\writestatus{loading}{ConTeXt XML Macros / Basics}
\startluacode
do
diff --git a/tex/context/base/x-fo.tex b/tex/context/base/x-fo.tex
index 396225546..1f9e55259 100644
--- a/tex/context/base/x-fo.tex
+++ b/tex/context/base/x-fo.tex
@@ -26,7 +26,9 @@
% beware: aftergroup vs egroup/endgroup
-\input xtag-run
+\useXMLfilter[prs,run]
+
+% \input xtag-run
\unprotect
@@ -3369,7 +3371,7 @@ text-indent=0pt, % yes
\setbox \FOitembox \iftracingFO \ruledvtop \else \vtop \fi \bgroup
\forgetall
- \postponefootnotes
+ \postponenotes
\hsize\FOlistitemlabelhsize
\directsetup{fo:list-item-label:setup}
\XMLflush{fo:list-item-label}
@@ -3508,7 +3510,7 @@ text-indent=0pt, % yes
\startsetups fo:marker:process
- \doifmarkingelse{fo:\XMLop{marker-class-name}}
+ \doifelsemarking{fo:\XMLop{marker-class-name}}
{} {\definerawmarking[fo:\XMLop{marker-class-name}]}
\expanded{\marking[fo:\XMLop{marker-class-name}]{\XMLflushself}}
diff --git a/tex/context/base/x-mathml.lua b/tex/context/base/x-mathml.lua
index 0e279dfe8..aa2e4e716 100644
--- a/tex/context/base/x-mathml.lua
+++ b/tex/context/base/x-mathml.lua
@@ -6,19 +6,29 @@ if not modules then modules = { } end modules ['x-mathml'] = {
license = "see context related readme files"
}
+local utf = unicode.utf8
+
lxml = lxml or { }
lxml.mml = lxml.mml or { }
local texsprint = tex.sprint
local format = string.format
-local utfchar = unicode.utf8.char
+local lower = string.lower
+local utfchar = utf.char
+local utffind = utf.find
local xmlsprint = xml.sprint
local xmlcprint = xml.cprint
+local utfcharacters, utfvalues = string.utfcharacters, string.utfvalues
+
-- an alternative is to remap to private codes, where we can have
-- different properties .. to be done; this will move and become
-- generic
+-- todo: handle opening/closing mo's here ... presentation mml is such a mess ...
+
+local doublebar = utfchar(0x2016)
+
local n_replacements = {
-- [" "] = utfchar(0x2002), -- "&textspace;" -> tricky, no &; in mkiv
["."] = "{.}",
@@ -26,12 +36,30 @@ local n_replacements = {
[" "] = "",
}
+local l_replacements = { -- in main table
+ ["|"] = "\\mmlleftdelimiter\\vert",
+ ["{"] = "\\mmlleftdelimiter\\lbrace",
+ ["("] = "\\mmlleftdelimiter(",
+ ["["] = "\\mmlleftdelimiter[",
+ ["<"] = "\\mmlleftdelimiter<",
+ [doublebar] = "\\mmlleftdelimiter\\Vert",
+}
+local r_replacements = { -- in main table
+ ["|"] = "\\mmlrightdelimiter\\vert",
+ ["}"] = "\\mmlrightdelimiter\\rbrace",
+ [")"] = "\\mmlrightdelimiter)",
+ ["]"] = "\\mmlrightdelimiter]",
+ [">"] = "\\mmlrightdelimiter>",
+ [doublebar] = "\\mmlrightdelimiter\\Vert",
+}
+
local o_replacements = { -- in main table
["@l"] = "\\mmlleftdelimiter.",
["@r"] = "\\mmlrightdelimiter.",
["{"] = "\\mmlleftdelimiter\\lbrace",
["}"] = "\\mmlrightdelimiter\\rbrace",
--- ["|"] = "\\mmlmiddledelimiter\\vert",
+ ["|"] = "\\mmlleftorrightdelimiter\\vert",
+ [doublebar] = "\\mmlleftorrightdelimiter\\Vert",
["("] = "\\mmlleftdelimiter(",
[")"] = "\\mmlrightdelimiter)",
["["] = "\\mmlleftdelimiter[",
@@ -48,9 +76,9 @@ local o_replacements = { -- in main table
[" "] = "",
["°"] = "^\\circ", -- hack
-[utf.char(0xF103C)] = "\\mmlleftdelimiter<",
-[utf.char(0xF1026)] = "\\mmlchar{38}",
-[utf.char(0xF103E)] = "\\mmlleftdelimiter>",
+ [utfchar(0xF103C)] = "\\mmlleftdelimiter<",
+ [utfchar(0xF1026)] = "\\mmlchar{38}",
+ [utfchar(0xF103E)] = "\\mmlleftdelimiter>",
}
@@ -424,6 +452,10 @@ function lxml.mml.checked_operator(str)
texsprint(tex.ctxcatcodes,(utf.gsub(str,".",o_replacements)))
end
+function lxml.mml.stripped(str)
+ tex.sprint(tex.ctxcatcodes,str:strip())
+end
+
function lxml.mml.mn(id,pattern)
-- maybe at some point we need to interpret the number, but
-- currently we assume an upright font
@@ -453,13 +485,24 @@ function lxml.mml.mi(id,pattern)
end
end
+function table.keys_as_string(t)
+ local k = { }
+ for k,_ in pairs(t) do
+ k[#k+1] = k
+ end
+ return concat(k,"")
+end
+
+--~ local leftdelimiters = "[" .. table.keys_as_string(l_replacements) .. "]"
+--~ local rightdelimiters = "[" .. table.keys_as_string(r_replacements) .. "]"
+
function lxml.mml.mfenced(id,pattern) -- multiple separators
id = lxml.id(id)
local left, right, separators = id.at.open or "(", id.at.close or ")", id.at.separators or ","
- local l, r = left:find("[%(%{%<%[]"), right:find("[%)%}%>%]]")
+ local l, r = l_replacements[left], r_replacements[right]
texsprint(tex.ctxcatcodes,"\\enabledelimiter")
if l then
- texsprint(tex.ctxcatcodes,o_replacements[left])
+ texsprint(tex.ctxcatcodes,l_replacements[left] or o_replacements[left] or "")
else
texsprint(tex.ctxcatcodes,o_replacements["@l"])
texsprint(tex.ctxcatcodes,left)
@@ -481,6 +524,8 @@ function lxml.mml.mfenced(id,pattern) -- multiple separators
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
@@ -492,7 +537,7 @@ function lxml.mml.mfenced(id,pattern) -- multiple separators
end
texsprint(tex.ctxcatcodes,"\\enabledelimiter")
if r then
- texsprint(tex.ctxcatcodes,o_replacements[right])
+ texsprint(tex.ctxcatcodes,r_replacements[right] or o_replacements[right] or "")
else
texsprint(tex.ctxcatcodes,right)
texsprint(tex.ctxcatcodes,o_replacements["@r"])
@@ -578,7 +623,7 @@ function lxml.mml.mcolumn(root)
local tag = dk.tg
if tag == "mi" or tag == "mn" or tag == "mo" or tag == "mtext" then
local str = xml.content(dk)
- for s in str:utfcharacters() do -- utf.gmatch(str,".") btw, the gmatch was bugged
+ for s in utfcharacters(str) do -- utf.gmatch(str,".") btw, the gmatch was bugged
m[#m+1] = { tag, s }
end
if tag == "mn" then
@@ -589,7 +634,7 @@ function lxml.mml.mcolumn(root)
end
elseif tag == "mspace" or tag == "mline" then
local str = dk.at.spacing or ""
- for s in str:utfcharacters() do -- utf.gmatch(str,".") btw, the gmatch was bugged
+ for s in utfcharacters(str) do -- utf.gmatch(str,".") btw, the gmatch was bugged
m[#m+1] = { tag, s }
end
elseif tag == "mline" then
@@ -653,7 +698,7 @@ function lxml.mml.mcolumn(root)
--~ end
chr = "\\hrulefill"
elseif tag == "mspace" then
- chr = "\\mmlmcolumndigitspace" -- utf.char(0x2007)
+ chr = "\\mmlmcolumndigitspace" -- utfchar(0x2007)
end
if j == numbers + 1 then
tex.sprint(tex.ctxcatcodes,"&")
@@ -666,6 +711,8 @@ function lxml.mml.mcolumn(root)
tex.sprint(tex.ctxcatcodes,"\\egroup")
end
+local spacesplitter = lpeg.Ct(lpeg.splitat(" "))
+
function lxml.mml.mtable(root)
root = lxml.id(root)
@@ -675,9 +722,9 @@ function lxml.mml.mtable(root)
local rowalign = at.rowalign
local columnalign = at.columnalign
local frame = at.frame
- local rowaligns = rowalign and rowalign :split(" ") -- we have a faster one
- local columnaligns = columnalign and columnalign:split(" ") -- we have a faster one
- local frames = frame and frame :split(" ") -- we have a faster one
+ local rowaligns = rowalign and spacesplitter:match(rowalign)
+ local columnaligns = columnalign and spacesplitter:match(columnalign)
+ local frames = frame and spacesplitter:match(frame)
local framespacing = at.framespacing or "0pt"
local framespacing = at.framespacing or "-\\ruledlinewidth" -- make this an option
@@ -722,7 +769,7 @@ end
function lxml.mml.csymbol(root)
root = lxml.id(root)
local encoding = root.at.encoding or ""
- local hash = url.hashed((root.at.definitionUrl or ""):lower())
+ local hash = url.hashed(lower(root.at.definitionUrl or ""))
local full = hash.original or ""
local base = hash.path or ""
local text = string.strip(xml.content(root) or "")
diff --git a/tex/context/base/x-mathml.mkiv b/tex/context/base/x-mathml.mkiv
index e5f39975c..6630a4901 100644
--- a/tex/context/base/x-mathml.mkiv
+++ b/tex/context/base/x-mathml.mkiv
@@ -15,7 +15,7 @@
% This module is under construction and will be cleaned up.
-\writestatus{loading}{Context XML Macros (MathML Renderer)}
+\writestatus{loading}{ConTeXt XML Macros / MathML Renderer}
\unprotect
@@ -66,15 +66,24 @@
\startformula\MMLhack\xmlfirst{#1}{/mml:math}\stopformula
\stopxmlsetups
+\setfalse\mmlignoredelimiter
+\settrue \mmlsomeleftdelimiter
+
+\def\MMLleftorright
+ {\ifconditional\mmlsomeleftdelimiter
+ \setfalse\mmlsomeleftdelimiter\expandafter\MMLleft
+ \else
+ \settrue \mmlsomeleftdelimiter\expandafter\MMLright
+ \fi}
+
\ifx\MMLleft \undefined \let\MMLleft \firstofoneargument \fi
\ifx\MMLright \undefined \let\MMLright \firstofoneargument \fi
\ifx\MMLmiddle\undefined \let\MMLmiddle\firstofoneargument \fi
-\setfalse\mmlignoredelimiter
-
-\def\mmlleftdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLleft #1}\fi}
-\def\mmlrightdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLright #1}\fi}
-\def\mmlmiddledelimiter#1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLmiddle#1}\fi}
+\def\mmlleftdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLleft #1}\fi}
+\def\mmlrightdelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLright #1}\fi}
+\def\mmlmiddledelimiter #1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLmiddle #1}\fi}
+\def\mmlleftorrightdelimiter#1{\ifconditional\mmlignoredelimiter#1\else\normalordelimiter{#1}{\MMLleftorright#1}\fi}
\def\mmlchar#1{\char#1 } % used in lua code
@@ -93,7 +102,7 @@
%D some namespace limitations. Here we do it the \MKV\ way.
\def\widevec#1%
- {\vbox{\m@th\ialign{##\crcr
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
\rightarrowfill\crcr\noalign{\nointerlineskip}%
$\hfil\displaystyle{#1}\hfil$\crcr}}}
@@ -1778,8 +1787,10 @@
\xmlmapvalue {mml} {sans-serif-bold-italic} {\ss\bi}
\xmlmapvalue {mml} {monospace} {\tt}
+% todo: displaystyle=true/false (or whatever else shows up)
+
\starttexdefinition setmmlmathstyle #1
- \xmlval {mml} {\xmlatt{#1}{mathvariant}} \mmmr
+ \xmlval {mml} {\xmlatt{#1}{mathvariant}} \empty % was: \mmmr
\stoptexdefinition
\starttexdefinition applymmlmathcolor #1#2
@@ -1802,7 +1813,7 @@
\fi
\stoptexdefinition
-\newsignal\mmltextsignal
+\newsignal\mmltextsignal % not used
\starttexdefinition applymmlsometext #1#2
\applymmlmathbackground {#1} {
@@ -1862,23 +1873,6 @@
\ctxlua{lxml.mml.mfenced("#1","/*")}
\stopxmlsetups
-% \startxmlsetups mml:menclose % notation=.....
-% \edef\mmlmenclosenotation{\xmlattdef{#1}{notation}{longdiv}}
-% \doifelse \mmlmenclosenotation {longdiv} {
-% \overline{\left)\strut\xmlflush{#1}\right.}
-% } {
-% \doifelse \mmlmenclosenotation {actuarial} {
-% \overline{\left.\strut\xmlflush{#1}\right|}
-% } {
-% \doifelse \mmlmenclosenotation {radical} {
-% \sqrt{\xmlflush{#1}}
-% } {
-% \xmlflush{#1}
-% }
-% }
-% }
-% \stopxmlsetups
-
\defineoverlay [mml:enclose:box] [\useMPgraphic{mml:enclose:box}]
\defineoverlay [mml:enclose:roundedbox] [\useMPgraphic{mml:enclose:roundedbox}]
\defineoverlay [mml:enclose:circle] [\useMPgraphic{mml:enclose:circle}]
@@ -1951,23 +1945,26 @@
\doifelse \mmlmenclosenotation {mml:enclose:radical} {
\sqrt{\xmlflush{#1}}
} {
- \framed
- [frame=off,background={\mmlmenclosenotation}]
- {$
- \expanded{\doifinsetelse {mml:enclose:longdiv} {\mmlmenclosenotation}} {
- \overline{\left)\strut\xmlflush{#1}\right.}
- } {
- \expanded{\doifinsetelse {mml:enclose:actuarial} {\mmlmenclosenotation}} {
- \overline{\left.\strut\xmlflush{#1}\right|}
+ % todo: no framed when longdiv, actuarial or radical ? spec ?
+ \vcenter {
+ \framed
+ [frame=off,strut=no,background={\mmlmenclosenotation}] % offset is kind of undefined
+ {$
+ \expanded{\doifinsetelse {mml:enclose:longdiv} {\mmlmenclosenotation}} {
+ \overline{\left)\strut\xmlflush{#1}\right.}
} {
- \expanded{\doifinsetelse {mml:enclose:radical} {\mmlmenclosenotation}} {
- \sqrt{\xmlflush{#1}}
+ \expanded{\doifinsetelse {mml:enclose:actuarial} {\mmlmenclosenotation}} {
+ \overline{\left.\strut\xmlflush{#1}\right|}
} {
- \xmlflush{#1}
+ \expanded{\doifinsetelse {mml:enclose:radical} {\mmlmenclosenotation}} {
+ \sqrt{\xmlflush{#1}}
+ } {
+ \xmlflush{#1}
+ }
}
}
- }
- $}
+ $}
+ }
}
}
}
@@ -2020,9 +2017,20 @@
\endgroup
\stopxmlsetups
+\setupMMLappearance[text][\c!alternative=\v!a] % a=normal, b=keep spaces
+
\startxmlsetups mml:mtext
\domathtext {
- \applymmlsometext{#1}{\xmlflush{#1}}
+ \applymmlsometext{#1}{
+ \doifelse\MMLscriptsalternative\v!a {
+ %\ctxlua{lxml.mml.stripped(\!!bs\xmlflush{#1}\!!es)}
+ \ignorespaces
+ \xmlflush{#1}
+ \unskip
+ } {
+ \xmlflush{#1}
+ }
+ }
}
\stopxmlsetups
diff --git a/tex/context/base/x-newcml.tex b/tex/context/base/x-newcml.tex
index c5f999615..76d69ed51 100644
--- a/tex/context/base/x-newcml.tex
+++ b/tex/context/base/x-newcml.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=x-newmml,
%D version=2006.04.09, % reimplementation
-%D title=\CONTEXT\ XML Modules,
-%D subtitle=ChemML renderer,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=ChemML,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA ADE}]
@@ -14,7 +14,9 @@
%D This used to be an xtag filter using remapping but the
%D following is nore in sync with the new mathml methods.
-\writestatus{loading}{Context XML Macros (chem ml)}
+\writestatus{loading}{ConTeXt XML Macros / ChemML}
+
+\useXMLfilter[stk]
\unprotect
diff --git a/tex/context/base/x-newmme.tex b/tex/context/base/x-newmme.tex
index 5a7705963..5e17ea7a4 100644
--- a/tex/context/base/x-newmme.tex
+++ b/tex/context/base/x-newmme.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=m-newmme,
%D version=2005.06.10, % 1999.12.20,
-%D title=\CONTEXT\ XML Modules,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=MathML Entities,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (MathML Entities)}
+\writestatus{loading}{ConTeXt XML Macros / MathML Entities}
\unprotect
diff --git a/tex/context/base/x-newmml.mkii b/tex/context/base/x-newmml.mkii
index f4847eeb9..17eda5276 100644
--- a/tex/context/base/x-newmml.mkii
+++ b/tex/context/base/x-newmml.mkii
@@ -1,8 +1,8 @@
%D \module
%D [ file=x-newmml,
%D version=2005.06.10, % 1999.12.20,
-%D title=\CONTEXT\ XML Modules,
-%D subtitle=MathML Renderer,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=MathML,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA ADE}]
@@ -17,6 +17,8 @@
%D no namespace support yet, but eventually we will use a \MKIV\
%D version.
+\useXMLfilter[stk]
+
\ifx\inlinemathematics\undefined
\def\inlinemathematics {\dontleavehmode\mathematics} % already in kernel
\long\def\inlinemath #1{\dontleavehmode\relax\ifmmode#1\else $#1$\fi}
@@ -28,7 +30,7 @@
%D Then we start defining the rendering macros:
-\writestatus{loading}{Context XML Macros (MathML Renderer)}
+\writestatus{loading}{ConTeXt XML Macros / MathML}
\startmodule [mathml]
@@ -570,7 +572,7 @@
{{\bbd#1}}
\def\widevec#1%
- {\vbox{\m@th\ialign{##\crcr
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
\rightarrowfill\crcr\noalign{\nointerlineskip}%
$\hfil\displaystyle{#1}\hfil$\crcr}}}
@@ -1960,9 +1962,6 @@
{\getXMLentity\flattenedXMLcontent}
{\ignorespaces#1\removeunwantedspaces}}
-\let\normalright=\right
-\let\normalleft =\left
-
\def\doMMLleft #1{\pushmacro\left \let\left \empty\normalleft #1\popmacro\left}
\def\doMMLright#1{\pushmacro\right\let\right\empty\normalright#1\popmacro\right}
@@ -2267,9 +2266,9 @@
\startsetups mmp:mover:stop
\stopsavingXMLelements
- \mathop{\vbox{\m@th\ialign{\hss##\hss\crcr\noalign{\kern3\p@}%
+ \mathop{\vbox{\mathsurround\zeropoint\ialign{\hss##\hss\crcr\noalign{\kern3\points}%
\disabledelimiter\doMMLfiller{\getXMLstackdata\plustwo}
- \crcr\noalign{\kern3\p@\nointerlineskip}%
+ \crcr\noalign{\kern3\points\nointerlineskip}%
\disabledelimiter\doMMLfiller{\getXMLstackdata\plusone}
\crcr}}}
\limits
@@ -2283,11 +2282,11 @@
\startsetups mmp:munder:stop
\stopsavingXMLelements
- \mathop{\vtop{\m@th\ialign{\hss##\hss\crcr
+ \mathop{\vtop{\mathsurround\zeropoint\ialign{\hss##\hss\crcr
\disabledelimiter\doMMLfiller{\getXMLstackdata\plusone}
- \crcr\noalign{\kern3\p@\nointerlineskip}%
+ \crcr\noalign{\kern3\points\nointerlineskip}%
\disabledelimiter\doMMLfiller{\getXMLstackdata\plustwo}
- \crcr\noalign{\kern3\p@}}}}
+ \crcr\noalign{\kern3\points}}}}
\limits
\endgroup
\stopsetups
diff --git a/tex/context/base/x-newmml.tex b/tex/context/base/x-newmml.tex
index f08e91b26..9eb994021 100644
--- a/tex/context/base/x-newmml.tex
+++ b/tex/context/base/x-newmml.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=x-newmml,
%D version=2005.06.10, % 1999.12.20,
-%D title=\CONTEXT\ XML Modules,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=MathML Renderer,
%D author=Hans Hagen,
%D date=\currentdate,
diff --git a/tex/context/base/x-newmmo.tex b/tex/context/base/x-newmmo.tex
index 076f3f82c..c3b56cc16 100644
--- a/tex/context/base/x-newmmo.tex
+++ b/tex/context/base/x-newmmo.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=x-newmmo,
%D version=2006.05.17,
-%D title=\CONTEXT\ XML Modules,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=MathML Renderer/Open Math Extensions,
%D author=Hans Hagen,
%D date=\currentdate,
diff --git a/tex/context/base/x-newpml.tex b/tex/context/base/x-newpml.tex
index 30b520610..d69231e3f 100644
--- a/tex/context/base/x-newpml.tex
+++ b/tex/context/base/x-newpml.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (units)}
+\writestatus{loading}{ConTeXt XML Macros / Units}
\usemodule[newmml]
diff --git a/tex/context/base/x-set-02.tex b/tex/context/base/x-set-02.tex
index da531f6cb..bb0b7583c 100644
--- a/tex/context/base/x-set-02.tex
+++ b/tex/context/base/x-set-02.tex
@@ -12,14 +12,10 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-%D This file is obsolete.
-
\unprotect \bgroup \catcode`\<=\@@other
\def\setinterfacecomponent#1#2#3%
- {\doifelse{#3}\nointerfaceobject
- {\setgvalue{\string<#1\string:#2\string>}{#2}}
- {\setgvalue{\string<#1\string:#2\string>}{#3}}}
+ {\setgvalue{\string<#1\string:#2\string>}{#3}}
\gdef\getinterfacecomponent#1#2%
{\executeifdefined{\string<#1\string:#2\string>}{#2}}
@@ -29,9 +25,6 @@
\def\setinterfaceelement {\setinterfacecomponent{string}} % element
\def\setinterfacecommand {\setinterfacecomponent{string}} % command
-\input mult-con.tex
-\input mult-com.tex
-
-% we need to replace the y! by just the name
+\input mult-\userinterfacetag
\egroup \protect \endinput
diff --git a/tex/context/base/x-set-11.mkii b/tex/context/base/x-set-11.mkii
index 397c2c71c..434b18647 100644
--- a/tex/context/base/x-set-11.mkii
+++ b/tex/context/base/x-set-11.mkii
@@ -31,7 +31,7 @@
\defineXMLenvironmentsave [cd:define] [name=]
{}
- {\setevalue{cd:def:\XMLop{name}}{\XMLflush{cd:define}}}
+ {\setxvalue{cd:def:\XMLop{name}}{\XMLflush{cd:define}}}
\defineXMLsingular [cd:resolve] [name=]
{\getvalue{cd:def:\XMLop{name}}}
diff --git a/tex/context/base/x-set-11.mkiv b/tex/context/base/x-set-11.mkiv
index dcfef384f..499d531e5 100644
--- a/tex/context/base/x-set-11.mkiv
+++ b/tex/context/base/x-set-11.mkiv
@@ -11,7 +11,7 @@
}
function document.setups.load(filename)
- filename = input.find_file(filename) or ""
+ filename = resolvers.find_file(filename) or ""
if filename ~= "" and not document.setups.loaded[filename] then
local loaded = xml.load(filename)
if loaded then
diff --git a/tex/context/base/x-set-11.tex b/tex/context/base/x-set-11.tex
index 19ce18a75..6fcc7f934 100644
--- a/tex/context/base/x-set-11.tex
+++ b/tex/context/base/x-set-11.tex
@@ -571,7 +571,7 @@
\blank[\v!halfline]
\ignorespaces}
-\defineXMLenvironmentsave [cd:keywords]
+\defineXMLenvironmentsave [cd:keywords] [optional=no]
{}
{\startfirstSETUPcolumn{\showSETUPnumber}%
\doifelseXMLempty{cd:keywords}
diff --git a/tex/context/base/xetx-chr.tex b/tex/context/base/xetx-chr.tex
new file mode 100644
index 000000000..31f15a0cb
--- /dev/null
+++ b/tex/context/base/xetx-chr.tex
@@ -0,0 +1,1167 @@
+% filename : xetx-chr.tex
+% comment : generated by mtxrun --script chars --xtx
+% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+% copyright: PRAGMA ADE / ConTeXt Development Team
+% license : see context related readme files
+
+% named characters mapped onto utf (\\char is needed for accents)
+
+\def\textbackslash {\char"0005C } % REVERSE SOLIDUS: \
+\def\textasciicircum {\char"0005E } % CIRCUMFLEX ACCENT: ^
+\def\textunderscore {\char"0005F } % LOW LINE: _
+\def\textgrave {\char"00060 } % GRAVE ACCENT: `
+\def\idotaccent {\char"00069 } % LATIN SMALL LETTER I: i
+\def\textbraceleft {\char"0007B } % LEFT CURLY BRACKET: {
+\def\textbar {\char"0007C } % VERTICAL LINE: |
+\def\textbraceright {\char"0007D } % RIGHT CURLY BRACKET: }
+\def\textasciitilde {\char"0007E } % TILDE: ~
+\def\nobreakspace {\char"000A0 } % NO-BREAK SPACE:  
+\def\exclamdown {\char"000A1 } % INVERTED EXCLAMATION MARK: ¡
+\def\textcent {\char"000A2 } % CENT SIGN: ¢
+\def\textsterling {\char"000A3 } % POUND SIGN: £
+\def\textcurrency {\char"000A4 } % CURRENCY SIGN: ¤
+\def\textyen {\char"000A5 } % YEN SIGN: ¥
+\def\textbrokenbar {\char"000A6 } % BROKEN BAR: ¦
+\def\sectionmark {\char"000A7 } % SECTION SIGN: §
+\def\textdiaeresis {\char"000A8 } % DIAERESIS: ¨
+\def\copyright {\char"000A9 } % COPYRIGHT SIGN: ©
+\def\ordfeminine {\char"000AA } % FEMININE ORDINAL INDICATOR: ª
+\def\leftguillemot {\char"000AB } % LEFT-POINTING DOUBLE ANGLE QUOTATION MARK: «
+\def\textlognot {\char"000AC } % NOT SIGN: ¬
+\def\softhyphen {\char"000AD } % SOFT HYPHEN: ­
+\def\registered {\char"000AE } % REGISTERED SIGN: ®
+\def\textmacron {\char"000AF } % MACRON: ¯
+\def\textdegree {\char"000B0 } % DEGREE SIGN: °
+\def\textpm {\char"000B1 } % PLUS-MINUS SIGN: ±
+\def\twosuperior {\char"000B2 } % SUPERSCRIPT TWO: ²
+\def\threesuperior {\char"000B3 } % SUPERSCRIPT THREE: ³
+\def\textacute {\char"000B4 } % ACUTE ACCENT: ´
+\def\textmu {\char"000B5 } % MICRO SIGN: µ
+\def\paragraphmark {\char"000B6 } % PILCROW SIGN: ¶
+\def\periodcentered {\char"000B7 } % MIDDLE DOT: ·
+\def\textcedilla {\char"000B8 } % CEDILLA: ¸
+\def\onesuperior {\char"000B9 } % SUPERSCRIPT ONE: ¹
+\def\ordmasculine {\char"000BA } % MASCULINE ORDINAL INDICATOR: º
+\def\rightguillemot {\char"000BB } % RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK: »
+\def\onequarter {\char"000BC } % VULGAR FRACTION ONE QUARTER: ¼
+\def\onehalf {\char"000BD } % VULGAR FRACTION ONE HALF: ½
+\def\threequarter {\char"000BE } % VULGAR FRACTION THREE QUARTERS: ¾
+\def\questiondown {\char"000BF } % INVERTED QUESTION MARK: ¿
+\def\Agrave {\char"000C0 } % LATIN CAPITAL LETTER A WITH GRAVE: À
+\def\Aacute {\char"000C1 } % LATIN CAPITAL LETTER A WITH ACUTE: Á
+\def\Acircumflex {\char"000C2 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX: Â
+\def\Atilde {\char"000C3 } % LATIN CAPITAL LETTER A WITH TILDE: Ã
+\def\Adiaeresis {\char"000C4 } % LATIN CAPITAL LETTER A WITH DIAERESIS: Ä
+\def\Aring {\char"000C5 } % LATIN CAPITAL LETTER A WITH RING ABOVE: Å
+\def\AEligature {\char"000C6 } % LATIN CAPITAL LETTER AE: Æ
+\def\Ccedilla {\char"000C7 } % LATIN CAPITAL LETTER C WITH CEDILLA: Ç
+\def\Egrave {\char"000C8 } % LATIN CAPITAL LETTER E WITH GRAVE: È
+\def\Eacute {\char"000C9 } % LATIN CAPITAL LETTER E WITH ACUTE: É
+\def\Ecircumflex {\char"000CA } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX: Ê
+\def\Ediaeresis {\char"000CB } % LATIN CAPITAL LETTER E WITH DIAERESIS: Ë
+\def\Igrave {\char"000CC } % LATIN CAPITAL LETTER I WITH GRAVE: Ì
+\def\Iacute {\char"000CD } % LATIN CAPITAL LETTER I WITH ACUTE: Í
+\def\Icircumflex {\char"000CE } % LATIN CAPITAL LETTER I WITH CIRCUMFLEX: Î
+\def\Idiaeresis {\char"000CF } % LATIN CAPITAL LETTER I WITH DIAERESIS: Ï
+\def\Eth {\char"000D0 } % LATIN CAPITAL LETTER ETH: Ð
+\def\Ntilde {\char"000D1 } % LATIN CAPITAL LETTER N WITH TILDE: Ñ
+\def\Ograve {\char"000D2 } % LATIN CAPITAL LETTER O WITH GRAVE: Ò
+\def\Oacute {\char"000D3 } % LATIN CAPITAL LETTER O WITH ACUTE: Ó
+\def\Ocircumflex {\char"000D4 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX: Ô
+\def\Otilde {\char"000D5 } % LATIN CAPITAL LETTER O WITH TILDE: Õ
+\def\Odiaeresis {\char"000D6 } % LATIN CAPITAL LETTER O WITH DIAERESIS: Ö
+\def\textmultiply {\char"000D7 } % MULTIPLICATION SIGN: ×
+\def\Ostroke {\char"000D8 } % LATIN CAPITAL LETTER O WITH STROKE: Ø
+\def\Ugrave {\char"000D9 } % LATIN CAPITAL LETTER U WITH GRAVE: Ù
+\def\Uacute {\char"000DA } % LATIN CAPITAL LETTER U WITH ACUTE: Ú
+\def\Ucircumflex {\char"000DB } % LATIN CAPITAL LETTER U WITH CIRCUMFLEX: Û
+\def\Udiaeresis {\char"000DC } % LATIN CAPITAL LETTER U WITH DIAERESIS: Ü
+\def\Yacute {\char"000DD } % LATIN CAPITAL LETTER Y WITH ACUTE: Ý
+\def\Thorn {\char"000DE } % LATIN CAPITAL LETTER THORN: Þ
+\def\ssharp {\char"000DF } % LATIN SMALL LETTER SHARP S: ß
+\def\agrave {\char"000E0 } % LATIN SMALL LETTER A WITH GRAVE: à
+\def\aacute {\char"000E1 } % LATIN SMALL LETTER A WITH ACUTE: á
+\def\acircumflex {\char"000E2 } % LATIN SMALL LETTER A WITH CIRCUMFLEX: â
+\def\atilde {\char"000E3 } % LATIN SMALL LETTER A WITH TILDE: ã
+\def\adiaeresis {\char"000E4 } % LATIN SMALL LETTER A WITH DIAERESIS: ä
+\def\aring {\char"000E5 } % LATIN SMALL LETTER A WITH RING ABOVE: å
+\def\aeligature {\char"000E6 } % LATIN SMALL LETTER AE: æ
+\def\ccedilla {\char"000E7 } % LATIN SMALL LETTER C WITH CEDILLA: ç
+\def\egrave {\char"000E8 } % LATIN SMALL LETTER E WITH GRAVE: è
+\def\eacute {\char"000E9 } % LATIN SMALL LETTER E WITH ACUTE: é
+\def\ecircumflex {\char"000EA } % LATIN SMALL LETTER E WITH CIRCUMFLEX: ê
+\def\ediaeresis {\char"000EB } % LATIN SMALL LETTER E WITH DIAERESIS: ë
+\def\igrave {\char"000EC } % LATIN SMALL LETTER I WITH GRAVE: ì
+\def\iacute {\char"000ED } % LATIN SMALL LETTER I WITH ACUTE: í
+\def\icircumflex {\char"000EE } % LATIN SMALL LETTER I WITH CIRCUMFLEX: î
+\def\idiaeresis {\char"000EF } % LATIN SMALL LETTER I WITH DIAERESIS: ï
+\def\ntilde {\char"000F1 } % LATIN SMALL LETTER N WITH TILDE: ñ
+\def\ograve {\char"000F2 } % LATIN SMALL LETTER O WITH GRAVE: ò
+\def\oacute {\char"000F3 } % LATIN SMALL LETTER O WITH ACUTE: ó
+\def\ocircumflex {\char"000F4 } % LATIN SMALL LETTER O WITH CIRCUMFLEX: ô
+\def\otilde {\char"000F5 } % LATIN SMALL LETTER O WITH TILDE: õ
+\def\odiaeresis {\char"000F6 } % LATIN SMALL LETTER O WITH DIAERESIS: ö
+\def\textdiv {\char"000F7 } % DIVISION SIGN: ÷
+\def\ostroke {\char"000F8 } % LATIN SMALL LETTER O WITH STROKE: ø
+\def\ugrave {\char"000F9 } % LATIN SMALL LETTER U WITH GRAVE: ù
+\def\uacute {\char"000FA } % LATIN SMALL LETTER U WITH ACUTE: ú
+\def\ucircumflex {\char"000FB } % LATIN SMALL LETTER U WITH CIRCUMFLEX: û
+\def\udiaeresis {\char"000FC } % LATIN SMALL LETTER U WITH DIAERESIS: ü
+\def\yacute {\char"000FD } % LATIN SMALL LETTER Y WITH ACUTE: ý
+\def\thorn {\char"000FE } % LATIN SMALL LETTER THORN: þ
+\def\ydiaeresis {\char"000FF } % LATIN SMALL LETTER Y WITH DIAERESIS: ÿ
+\def\Amacron {\char"00100 } % LATIN CAPITAL LETTER A WITH MACRON: Ā
+\def\amacron {\char"00101 } % LATIN SMALL LETTER A WITH MACRON: ā
+\def\Abreve {\char"00102 } % LATIN CAPITAL LETTER A WITH BREVE: Ă
+\def\abreve {\char"00103 } % LATIN SMALL LETTER A WITH BREVE: ă
+\def\Aogonek {\char"00104 } % LATIN CAPITAL LETTER A WITH OGONEK: Ą
+\def\aogonek {\char"00105 } % LATIN SMALL LETTER A WITH OGONEK: ą
+\def\Cacute {\char"00106 } % LATIN CAPITAL LETTER C WITH ACUTE: Ć
+\def\cacute {\char"00107 } % LATIN SMALL LETTER C WITH ACUTE: ć
+\def\Ccircumflex {\char"00108 } % LATIN CAPITAL LETTER C WITH CIRCUMFLEX: Ĉ
+\def\ccircumflex {\char"00109 } % LATIN SMALL LETTER C WITH CIRCUMFLEX: ĉ
+\def\Cdotaccent {\char"0010A } % LATIN CAPITAL LETTER C WITH DOT ABOVE: Ċ
+\def\cdotaccent {\char"0010B } % LATIN SMALL LETTER C WITH DOT ABOVE: ċ
+\def\Ccaron {\char"0010C } % LATIN CAPITAL LETTER C WITH CARON: Č
+\def\ccaron {\char"0010D } % LATIN SMALL LETTER C WITH CARON: č
+\def\Dcaron {\char"0010E } % LATIN CAPITAL LETTER D WITH CARON: Ď
+\def\dcaron {\char"0010F } % LATIN SMALL LETTER D WITH CARON: ď
+\def\Dstroke {\char"00110 } % LATIN CAPITAL LETTER D WITH STROKE: Đ
+\def\dstroke {\char"00111 } % LATIN SMALL LETTER D WITH STROKE: đ
+\def\Emacron {\char"00112 } % LATIN CAPITAL LETTER E WITH MACRON: Ē
+\def\emacron {\char"00113 } % LATIN SMALL LETTER E WITH MACRON: ē
+\def\Ebreve {\char"00114 } % LATIN CAPITAL LETTER E WITH BREVE: Ĕ
+\def\ebreve {\char"00115 } % LATIN SMALL LETTER E WITH BREVE: ĕ
+\def\Edotaccent {\char"00116 } % LATIN CAPITAL LETTER E WITH DOT ABOVE: Ė
+\def\edotaccent {\char"00117 } % LATIN SMALL LETTER E WITH DOT ABOVE: ė
+\def\Eogonek {\char"00118 } % LATIN CAPITAL LETTER E WITH OGONEK: Ę
+\def\eogonek {\char"00119 } % LATIN SMALL LETTER E WITH OGONEK: ę
+\def\Ecaron {\char"0011A } % LATIN CAPITAL LETTER E WITH CARON: Ě
+\def\ecaron {\char"0011B } % LATIN SMALL LETTER E WITH CARON: ě
+\def\Gcircumflex {\char"0011C } % LATIN CAPITAL LETTER G WITH CIRCUMFLEX: Ĝ
+\def\gcircumflex {\char"0011D } % LATIN SMALL LETTER G WITH CIRCUMFLEX: ĝ
+\def\Gbreve {\char"0011E } % LATIN CAPITAL LETTER G WITH BREVE: Ğ
+\def\gbreve {\char"0011F } % LATIN SMALL LETTER G WITH BREVE: ğ
+\def\Gdotaccent {\char"00120 } % LATIN CAPITAL LETTER G WITH DOT ABOVE: Ġ
+\def\gdotaccent {\char"00121 } % LATIN SMALL LETTER G WITH DOT ABOVE: ġ
+\def\Gcommaaccent {\char"00122 } % LATIN CAPITAL LETTER G WITH CEDILLA: Ģ
+\def\gcommaaccent {\char"00123 } % LATIN SMALL LETTER G WITH CEDILLA: ģ
+\def\Hcircumflex {\char"00124 } % LATIN CAPITAL LETTER H WITH CIRCUMFLEX: Ĥ
+\def\hcircumflex {\char"00125 } % LATIN SMALL LETTER H WITH CIRCUMFLEX: ĥ
+\def\Hstroke {\char"00126 } % LATIN CAPITAL LETTER H WITH STROKE: Ħ
+\def\hstroke {\char"00127 } % LATIN SMALL LETTER H WITH STROKE: ħ
+\def\Itilde {\char"00128 } % LATIN CAPITAL LETTER I WITH TILDE: Ĩ
+\def\itilde {\char"00129 } % LATIN SMALL LETTER I WITH TILDE: ĩ
+\def\Imacron {\char"0012A } % LATIN CAPITAL LETTER I WITH MACRON: Ī
+\def\imacron {\char"0012B } % LATIN SMALL LETTER I WITH MACRON: ī
+\def\Ibreve {\char"0012C } % LATIN CAPITAL LETTER I WITH BREVE: Ĭ
+\def\ibreve {\char"0012D } % LATIN SMALL LETTER I WITH BREVE: ĭ
+\def\Iogonek {\char"0012E } % LATIN CAPITAL LETTER I WITH OGONEK: Į
+\def\iogonek {\char"0012F } % LATIN SMALL LETTER I WITH OGONEK: į
+\def\Idotaccent {\char"00130 } % LATIN CAPITAL LETTER I WITH DOT ABOVE: İ
+\def\dotlessi {\char"00131 } % LATIN SMALL LETTER DOTLESS I: ı
+\def\IJligature {\char"00132 } % LATIN CAPITAL LIGATURE IJ: IJ
+\def\ijligature {\char"00133 } % LATIN SMALL LIGATURE IJ: ij
+\def\Jcircumflex {\char"00134 } % LATIN CAPITAL LETTER J WITH CIRCUMFLEX: Ĵ
+\def\jcircumflex {\char"00135 } % LATIN SMALL LETTER J WITH CIRCUMFLEX: ĵ
+\def\Kcommaaccent {\char"00136 } % LATIN CAPITAL LETTER K WITH CEDILLA: Ķ
+\def\kcommaaccent {\char"00137 } % LATIN SMALL LETTER K WITH CEDILLA: ķ
+\def\kkra {\char"00138 } % LATIN SMALL LETTER KRA: ĸ
+\def\Lacute {\char"00139 } % LATIN CAPITAL LETTER L WITH ACUTE: Ĺ
+\def\lacute {\char"0013A } % LATIN SMALL LETTER L WITH ACUTE: ĺ
+\def\Lcommaaccent {\char"0013B } % LATIN CAPITAL LETTER L WITH CEDILLA: Ļ
+\def\lcommaaccent {\char"0013C } % LATIN SMALL LETTER L WITH CEDILLA: ļ
+\def\Lcaron {\char"0013D } % LATIN CAPITAL LETTER L WITH CARON: Ľ
+\def\lcaron {\char"0013E } % LATIN SMALL LETTER L WITH CARON: ľ
+\def\Ldotmiddle {\char"0013F } % LATIN CAPITAL LETTER L WITH MIDDLE DOT: Ŀ
+\def\ldotmiddle {\char"00140 } % LATIN SMALL LETTER L WITH MIDDLE DOT: ŀ
+\def\Lstroke {\char"00141 } % LATIN CAPITAL LETTER L WITH STROKE: Ł
+\def\lstroke {\char"00142 } % LATIN SMALL LETTER L WITH STROKE: ł
+\def\Nacute {\char"00143 } % LATIN CAPITAL LETTER N WITH ACUTE: Ń
+\def\nacute {\char"00144 } % LATIN SMALL LETTER N WITH ACUTE: ń
+\def\Ncommaaccent {\char"00145 } % LATIN CAPITAL LETTER N WITH CEDILLA: Ņ
+\def\ncommaaccent {\char"00146 } % LATIN SMALL LETTER N WITH CEDILLA: ņ
+\def\Ncaron {\char"00147 } % LATIN CAPITAL LETTER N WITH CARON: Ň
+\def\ncaron {\char"00148 } % LATIN SMALL LETTER N WITH CARON: ň
+\def\napostrophe {\char"00149 } % LATIN SMALL LETTER N PRECEDED BY APOSTROPHE: ʼn
+\def\Neng {\char"0014A } % LATIN CAPITAL LETTER ENG: Ŋ
+\def\neng {\char"0014B } % LATIN SMALL LETTER ENG: ŋ
+\def\Omacron {\char"0014C } % LATIN CAPITAL LETTER O WITH MACRON: Ō
+\def\omacron {\char"0014D } % LATIN SMALL LETTER O WITH MACRON: ō
+\def\Obreve {\char"0014E } % LATIN CAPITAL LETTER O WITH BREVE: Ŏ
+\def\obreve {\char"0014F } % LATIN SMALL LETTER O WITH BREVE: ŏ
+\def\Ohungarumlaut {\char"00150 } % LATIN CAPITAL LETTER O WITH DOUBLE ACUTE: Ő
+\def\ohungarumlaut {\char"00151 } % LATIN SMALL LETTER O WITH DOUBLE ACUTE: ő
+\def\OEligature {\char"00152 } % LATIN CAPITAL LIGATURE OE: Œ
+\def\oeligature {\char"00153 } % LATIN SMALL LIGATURE OE: œ
+\def\Racute {\char"00154 } % LATIN CAPITAL LETTER R WITH ACUTE: Ŕ
+\def\racute {\char"00155 } % LATIN SMALL LETTER R WITH ACUTE: ŕ
+\def\Rcommaaccent {\char"00156 } % LATIN CAPITAL LETTER R WITH CEDILLA: Ŗ
+\def\rcommaaccent {\char"00157 } % LATIN SMALL LETTER R WITH CEDILLA: ŗ
+\def\Rcaron {\char"00158 } % LATIN CAPITAL LETTER R WITH CARON: Ř
+\def\rcaron {\char"00159 } % LATIN SMALL LETTER R WITH CARON: ř
+\def\Sacute {\char"0015A } % LATIN CAPITAL LETTER S WITH ACUTE: Ś
+\def\sacute {\char"0015B } % LATIN SMALL LETTER S WITH ACUTE: ś
+\def\Scircumflex {\char"0015C } % LATIN CAPITAL LETTER S WITH CIRCUMFLEX: Ŝ
+\def\scircumflex {\char"0015D } % LATIN SMALL LETTER S WITH CIRCUMFLEX: ŝ
+\def\Scedilla {\char"0015E } % LATIN CAPITAL LETTER S WITH CEDILLA: Ş
+\def\scedilla {\char"0015F } % LATIN SMALL LETTER S WITH CEDILLA: ş
+\def\Scaron {\char"00160 } % LATIN CAPITAL LETTER S WITH CARON: Š
+\def\scaron {\char"00161 } % LATIN SMALL LETTER S WITH CARON: š
+\def\Tcedilla {\char"00162 } % LATIN CAPITAL LETTER T WITH CEDILLA: Ţ
+\def\tcedilla {\char"00163 } % LATIN SMALL LETTER T WITH CEDILLA: ţ
+\def\Tcaron {\char"00164 } % LATIN CAPITAL LETTER T WITH CARON: Ť
+\def\tcaron {\char"00165 } % LATIN SMALL LETTER T WITH CARON: ť
+\def\Tstroke {\char"00166 } % LATIN CAPITAL LETTER T WITH STROKE: Ŧ
+\def\tstroke {\char"00167 } % LATIN SMALL LETTER T WITH STROKE: ŧ
+\def\Utilde {\char"00168 } % LATIN CAPITAL LETTER U WITH TILDE: Ũ
+\def\utilde {\char"00169 } % LATIN SMALL LETTER U WITH TILDE: ũ
+\def\Umacron {\char"0016A } % LATIN CAPITAL LETTER U WITH MACRON: Ū
+\def\umacron {\char"0016B } % LATIN SMALL LETTER U WITH MACRON: ū
+\def\Ubreve {\char"0016C } % LATIN CAPITAL LETTER U WITH BREVE: Ŭ
+\def\ubreve {\char"0016D } % LATIN SMALL LETTER U WITH BREVE: ŭ
+\def\Uring {\char"0016E } % LATIN CAPITAL LETTER U WITH RING ABOVE: Ů
+\def\uring {\char"0016F } % LATIN SMALL LETTER U WITH RING ABOVE: ů
+\def\Uhungarumlaut {\char"00170 } % LATIN CAPITAL LETTER U WITH DOUBLE ACUTE: Ű
+\def\uhungarumlaut {\char"00171 } % LATIN SMALL LETTER U WITH DOUBLE ACUTE: ű
+\def\Uogonek {\char"00172 } % LATIN CAPITAL LETTER U WITH OGONEK: Ų
+\def\uogonek {\char"00173 } % LATIN SMALL LETTER U WITH OGONEK: ų
+\def\Wcircumflex {\char"00174 } % LATIN CAPITAL LETTER W WITH CIRCUMFLEX: Ŵ
+\def\wcircumflex {\char"00175 } % LATIN SMALL LETTER W WITH CIRCUMFLEX: ŵ
+\def\Ycircumflex {\char"00176 } % LATIN CAPITAL LETTER Y WITH CIRCUMFLEX: Ŷ
+\def\ycircumflex {\char"00177 } % LATIN SMALL LETTER Y WITH CIRCUMFLEX: ŷ
+\def\Ydiaeresis {\char"00178 } % LATIN CAPITAL LETTER Y WITH DIAERESIS: Ÿ
+\def\Zacute {\char"00179 } % LATIN CAPITAL LETTER Z WITH ACUTE: Ź
+\def\zacute {\char"0017A } % LATIN SMALL LETTER Z WITH ACUTE: ź
+\def\Zdotaccent {\char"0017B } % LATIN CAPITAL LETTER Z WITH DOT ABOVE: Ż
+\def\zdotaccent {\char"0017C } % LATIN SMALL LETTER Z WITH DOT ABOVE: ż
+\def\Zcaron {\char"0017D } % LATIN CAPITAL LETTER Z WITH CARON: Ž
+\def\zcaron {\char"0017E } % LATIN SMALL LETTER Z WITH CARON: ž
+\def\slong {\char"0017F } % LATIN SMALL LETTER LONG S: ſ
+\def\bstroke {\char"00180 } % LATIN SMALL LETTER B WITH STROKE: ƀ
+\def\Bhook {\char"00181 } % LATIN CAPITAL LETTER B WITH HOOK: Ɓ
+\def\Chook {\char"00187 } % LATIN CAPITAL LETTER C WITH HOOK: Ƈ
+\def\chook {\char"00188 } % LATIN SMALL LETTER C WITH HOOK: ƈ
+\def\Dafrican {\char"00189 } % LATIN CAPITAL LETTER AFRICAN D: Ɖ
+\def\Dhook {\char"0018A } % LATIN CAPITAL LETTER D WITH HOOK: Ɗ
+\def\Schwa {\char"0018F } % LATIN CAPITAL LETTER SCHWA: Ə
+\def\Fhook {\char"00191 } % LATIN CAPITAL LETTER F WITH HOOK: Ƒ
+\def\fhook {\char"00192 } % LATIN SMALL LETTER F WITH HOOK: ƒ
+\def\Ghook {\char"00193 } % LATIN CAPITAL LETTER G WITH HOOK: Ɠ
+\def\Istroke {\char"00197 } % LATIN CAPITAL LETTER I WITH STROKE: Ɨ
+\def\Khook {\char"00198 } % LATIN CAPITAL LETTER K WITH HOOK: Ƙ
+\def\khook {\char"00199 } % LATIN SMALL LETTER K WITH HOOK: ƙ
+\def\lbar {\char"0019A } % LATIN SMALL LETTER L WITH BAR: ƚ
+\def\Ohorn {\char"001A0 } % LATIN CAPITAL LETTER O WITH HORN: Ơ
+\def\ohorn {\char"001A1 } % LATIN SMALL LETTER O WITH HORN: ơ
+\def\Phook {\char"001A4 } % LATIN CAPITAL LETTER P WITH HOOK: Ƥ
+\def\phook {\char"001A5 } % LATIN SMALL LETTER P WITH HOOK: ƥ
+\def\Thook {\char"001AC } % LATIN CAPITAL LETTER T WITH HOOK: Ƭ
+\def\thook {\char"001AD } % LATIN SMALL LETTER T WITH HOOK: ƭ
+\def\Uhorn {\char"001AF } % LATIN CAPITAL LETTER U WITH HORN: Ư
+\def\uhorn {\char"001B0 } % LATIN SMALL LETTER U WITH HORN: ư
+\def\Uhook {\char"001B2 } % LATIN CAPITAL LETTER V WITH HOOK: Ʋ
+\def\Yhook {\char"001B3 } % LATIN CAPITAL LETTER Y WITH HOOK: Ƴ
+\def\yhook {\char"001B4 } % LATIN SMALL LETTER Y WITH HOOK: ƴ
+\def\Zstroke {\char"001B5 } % LATIN CAPITAL LETTER Z WITH STROKE: Ƶ
+\def\zstroke {\char"001B6 } % LATIN SMALL LETTER Z WITH STROKE: ƶ
+\def\DZcaronligature {\char"001C4 } % LATIN CAPITAL LETTER DZ WITH CARON: DŽ
+\def\Dzcaronligature {\char"001C5 } % LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON: Dž
+\def\dzcaronligature {\char"001C6 } % LATIN SMALL LETTER DZ WITH CARON: dž
+\def\LJligature {\char"001C7 } % LATIN CAPITAL LETTER LJ: LJ
+\def\Ljligature {\char"001C8 } % LATIN CAPITAL LETTER L WITH SMALL LETTER J: Lj
+\def\ljligature {\char"001C9 } % LATIN SMALL LETTER LJ: lj
+\def\NJligature {\char"001CA } % LATIN CAPITAL LETTER NJ: NJ
+\def\Njligature {\char"001CB } % LATIN CAPITAL LETTER N WITH SMALL LETTER J: Nj
+\def\njligature {\char"001CC } % LATIN SMALL LETTER NJ: nj
+\def\Acaron {\char"001CD } % LATIN CAPITAL LETTER A WITH CARON: Ǎ
+\def\acaron {\char"001CE } % LATIN SMALL LETTER A WITH CARON: ǎ
+\def\Icaron {\char"001CF } % LATIN CAPITAL LETTER I WITH CARON: Ǐ
+\def\icaron {\char"001D0 } % LATIN SMALL LETTER I WITH CARON: ǐ
+\def\Ocaron {\char"001D1 } % LATIN CAPITAL LETTER O WITH CARON: Ǒ
+\def\ocaron {\char"001D2 } % LATIN SMALL LETTER O WITH CARON: ǒ
+\def\Ucaron {\char"001D3 } % LATIN CAPITAL LETTER U WITH CARON: Ǔ
+\def\ucaron {\char"001D4 } % LATIN SMALL LETTER U WITH CARON: ǔ
+\def\Udiaeresismacron {\char"001D5 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON: Ǖ
+\def\udiaeresismacron {\char"001D6 } % LATIN SMALL LETTER U WITH DIAERESIS AND MACRON: ǖ
+\def\Udiaeresisacute {\char"001D7 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE: Ǘ
+\def\udiaeresisacute {\char"001D8 } % LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE: ǘ
+\def\Udiaeresiscaron {\char"001D9 } % LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON: Ǚ
+\def\udiaeresiscaron {\char"001DA } % LATIN SMALL LETTER U WITH DIAERESIS AND CARON: ǚ
+\def\Udiaeresisgrave {\char"001DB } % LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE: Ǜ
+\def\udiaeresisgrave {\char"001DC } % LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE: ǜ
+\def\Adiaeresismacron {\char"001DE } % LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON: Ǟ
+\def\adiaeresismacron {\char"001DF } % LATIN SMALL LETTER A WITH DIAERESIS AND MACRON: ǟ
+\def\Adotaccentmacron {\char"001E0 } % LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON: Ǡ
+\def\adotaccentmacron {\char"001E1 } % LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON: ǡ
+\def\AEmacron {\char"001E2 } % LATIN CAPITAL LETTER AE WITH MACRON: Ǣ
+\def\aemacron {\char"001E3 } % LATIN SMALL LETTER AE WITH MACRON: ǣ
+\def\Gstroke {\char"001E4 } % LATIN CAPITAL LETTER G WITH STROKE: Ǥ
+\def\gstroke {\char"001E5 } % LATIN SMALL LETTER G WITH STROKE: ǥ
+\def\Gcaron {\char"001E6 } % LATIN CAPITAL LETTER G WITH CARON: Ǧ
+\def\gcaron {\char"001E7 } % LATIN SMALL LETTER G WITH CARON: ǧ
+\def\Kcaron {\char"001E8 } % LATIN CAPITAL LETTER K WITH CARON: Ǩ
+\def\kcaron {\char"001E9 } % LATIN SMALL LETTER K WITH CARON: ǩ
+\def\Oogonek {\char"001EA } % LATIN CAPITAL LETTER O WITH OGONEK: Ǫ
+\def\oogonek {\char"001EB } % LATIN SMALL LETTER O WITH OGONEK: ǫ
+\def\Oogonekmacron {\char"001EC } % LATIN CAPITAL LETTER O WITH OGONEK AND MACRON: Ǭ
+\def\oogonekmacron {\char"001ED } % LATIN SMALL LETTER O WITH OGONEK AND MACRON: ǭ
+\def\jcaron {\char"001F0 } % LATIN SMALL LETTER J WITH CARON: ǰ
+\def\DZligature {\char"001F1 } % LATIN CAPITAL LETTER DZ: DZ
+\def\Dzligature {\char"001F2 } % LATIN CAPITAL LETTER D WITH SMALL LETTER Z: Dz
+\def\dzligature {\char"001F3 } % LATIN SMALL LETTER DZ: dz
+\def\Gacute {\char"001F4 } % LATIN CAPITAL LETTER G WITH ACUTE: Ǵ
+\def\gacute {\char"001F5 } % LATIN SMALL LETTER G WITH ACUTE: ǵ
+\def\Ngrave {\char"001F8 } % LATIN CAPITAL LETTER N WITH GRAVE: Ǹ
+\def\ngrave {\char"001F9 } % LATIN SMALL LETTER N WITH GRAVE: ǹ
+\def\Aringacute {\char"001FA } % LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE: Ǻ
+\def\aringacute {\char"001FB } % LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE: ǻ
+\def\AEacute {\char"001FC } % LATIN CAPITAL LETTER AE WITH ACUTE: Ǽ
+\def\aeacute {\char"001FD } % LATIN SMALL LETTER AE WITH ACUTE: ǽ
+\def\Ostrokeacute {\char"001FE } % LATIN CAPITAL LETTER O WITH STROKE AND ACUTE: Ǿ
+\def\ostrokeacute {\char"001FF } % LATIN SMALL LETTER O WITH STROKE AND ACUTE: ǿ
+\def\Adoublegrave {\char"00200 } % LATIN CAPITAL LETTER A WITH DOUBLE GRAVE: Ȁ
+\def\adoublegrave {\char"00201 } % LATIN SMALL LETTER A WITH DOUBLE GRAVE: ȁ
+\def\Ainvertedbreve {\char"00202 } % LATIN CAPITAL LETTER A WITH INVERTED BREVE: Ȃ
+\def\ainvertedbreve {\char"00203 } % LATIN SMALL LETTER A WITH INVERTED BREVE: ȃ
+\def\Edoublegrave {\char"00204 } % LATIN CAPITAL LETTER E WITH DOUBLE GRAVE: Ȅ
+\def\edoublegrave {\char"00205 } % LATIN SMALL LETTER E WITH DOUBLE GRAVE: ȅ
+\def\Einvertedbreve {\char"00206 } % LATIN CAPITAL LETTER E WITH INVERTED BREVE: Ȇ
+\def\einvertedbreve {\char"00207 } % LATIN SMALL LETTER E WITH INVERTED BREVE: ȇ
+\def\Idoublegrave {\char"00208 } % LATIN CAPITAL LETTER I WITH DOUBLE GRAVE: Ȉ
+\def\idoublegrave {\char"00209 } % LATIN SMALL LETTER I WITH DOUBLE GRAVE: ȉ
+\def\Iinvertedbreve {\char"0020A } % LATIN CAPITAL LETTER I WITH INVERTED BREVE: Ȋ
+\def\iinvertedbreve {\char"0020B } % LATIN SMALL LETTER I WITH INVERTED BREVE: ȋ
+\def\Odoublegrave {\char"0020C } % LATIN CAPITAL LETTER O WITH DOUBLE GRAVE: Ȍ
+\def\odoublegrave {\char"0020D } % LATIN SMALL LETTER O WITH DOUBLE GRAVE: ȍ
+\def\Oinvertedbreve {\char"0020E } % LATIN CAPITAL LETTER O WITH INVERTED BREVE: Ȏ
+\def\oinvertedbreve {\char"0020F } % LATIN SMALL LETTER O WITH INVERTED BREVE: ȏ
+\def\Rdoublegrave {\char"00210 } % LATIN CAPITAL LETTER R WITH DOUBLE GRAVE: Ȑ
+\def\rdoublegrave {\char"00211 } % LATIN SMALL LETTER R WITH DOUBLE GRAVE: ȑ
+\def\Rinvertedbreve {\char"00212 } % LATIN CAPITAL LETTER R WITH INVERTED BREVE: Ȓ
+\def\rinvertedbreve {\char"00213 } % LATIN SMALL LETTER R WITH INVERTED BREVE: ȓ
+\def\Udoublegrave {\char"00214 } % LATIN CAPITAL LETTER U WITH DOUBLE GRAVE: Ȕ
+\def\udoublegrave {\char"00215 } % LATIN SMALL LETTER U WITH DOUBLE GRAVE: ȕ
+\def\Uinvertedbreve {\char"00216 } % LATIN CAPITAL LETTER U WITH INVERTED BREVE: Ȗ
+\def\uinvertedbreve {\char"00217 } % LATIN SMALL LETTER U WITH INVERTED BREVE: ȗ
+\def\Scommaaccent {\char"00218 } % LATIN CAPITAL LETTER S WITH COMMA BELOW: Ș
+\def\scommaaccent {\char"00219 } % LATIN SMALL LETTER S WITH COMMA BELOW: ș
+\def\Tcommaaccent {\char"0021A } % LATIN CAPITAL LETTER T WITH COMMA BELOW: Ț
+\def\tcommaaccent {\char"0021B } % LATIN SMALL LETTER T WITH COMMA BELOW: ț
+\def\Hcaron {\char"0021E } % LATIN CAPITAL LETTER H WITH CARON: Ȟ
+\def\hcaron {\char"0021F } % LATIN SMALL LETTER H WITH CARON: ȟ
+\def\dcurl {\char"00221 } % LATIN SMALL LETTER D WITH CURL: ȡ
+\def\Zhook {\char"00224 } % LATIN CAPITAL LETTER Z WITH HOOK: Ȥ
+\def\zhook {\char"00225 } % LATIN SMALL LETTER Z WITH HOOK: ȥ
+\def\Adotaccent {\char"00226 } % LATIN CAPITAL LETTER A WITH DOT ABOVE: Ȧ
+\def\adotaccent {\char"00227 } % LATIN SMALL LETTER A WITH DOT ABOVE: ȧ
+\def\Ecedilla {\char"00228 } % LATIN CAPITAL LETTER E WITH CEDILLA: Ȩ
+\def\ecedilla {\char"00229 } % LATIN SMALL LETTER E WITH CEDILLA: ȩ
+\def\Odiaeresismacron {\char"0022A } % LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON: Ȫ
+\def\odiaeresismacron {\char"0022B } % LATIN SMALL LETTER O WITH DIAERESIS AND MACRON: ȫ
+\def\Otildemacron {\char"0022C } % LATIN CAPITAL LETTER O WITH TILDE AND MACRON: Ȭ
+\def\otildemacron {\char"0022D } % LATIN SMALL LETTER O WITH TILDE AND MACRON: ȭ
+\def\Odotaccent {\char"0022E } % LATIN CAPITAL LETTER O WITH DOT ABOVE: Ȯ
+\def\odotaccent {\char"0022F } % LATIN SMALL LETTER O WITH DOT ABOVE: ȯ
+\def\Odotaccentmacron {\char"00230 } % LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON: Ȱ
+\def\odotaccentmacron {\char"00231 } % LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON: ȱ
+\def\Ymacron {\char"00232 } % LATIN CAPITAL LETTER Y WITH MACRON: Ȳ
+\def\ymacron {\char"00233 } % LATIN SMALL LETTER Y WITH MACRON: ȳ
+\def\lcurl {\char"00234 } % LATIN SMALL LETTER L WITH CURL: ȴ
+\def\ncurl {\char"00235 } % LATIN SMALL LETTER N WITH CURL: ȵ
+\def\tcurl {\char"00236 } % LATIN SMALL LETTER T WITH CURL: ȶ
+\def\dotlessj {\char"00237 } % LATIN SMALL LETTER DOTLESS J: ȷ
+\def\Astroke {\char"0023A } % LATIN CAPITAL LETTER A WITH STROKE: Ⱥ
+\def\Cstroke {\char"0023B } % LATIN CAPITAL LETTER C WITH STROKE: Ȼ
+\def\cstroke {\char"0023C } % LATIN SMALL LETTER C WITH STROKE: ȼ
+\def\Lbar {\char"0023D } % LATIN CAPITAL LETTER L WITH BAR: Ƚ
+\def\bhook {\char"00253 } % LATIN SMALL LETTER B WITH HOOK: ɓ
+\def\ccurl {\char"00255 } % LATIN SMALL LETTER C WITH CURL: ɕ
+\def\dtail {\char"00256 } % LATIN SMALL LETTER D WITH TAIL: ɖ
+\def\dhook {\char"00257 } % LATIN SMALL LETTER D WITH HOOK: ɗ
+\def\schwa {\char"00259 } % LATIN SMALL LETTER SCHWA: ə
+\def\schwahook {\char"0025A } % LATIN SMALL LETTER SCHWA WITH HOOK: ɚ
+\def\dotlessjstroke {\char"0025F } % LATIN SMALL LETTER DOTLESS J WITH STROKE: ɟ
+\def\textcircumflex {\char"002C6 } % MODIFIER LETTER CIRCUMFLEX ACCENT: ˆ
+\def\textcaron {\char"002C7 } % CARON: ˇ
+\def\textbreve {\char"002D8 } % BREVE: ˘
+\def\textdotaccent {\char"002D9 } % DOT ABOVE: ˙
+\def\textring {\char"002DA } % RING ABOVE: ˚
+\def\textogonek {\char"002DB } % OGONEK: ˛
+\def\texttilde {\char"002DC } % SMALL TILDE: ˜
+\def\texthungarumlaut {\char"002DD } % DOUBLE ACUTE ACCENT: ˝
+\def\textbottomdot {\char"00323 } % COMBINING DOT BELOW: ̣
+\def\textbottomcomma {\char"00326 } % COMBINING COMMA BELOW: ̦
+\def\greektonos {\char"00384 } % GREEK TONOS: ΄
+\def\greekdialytikatonos {\char"00385 } % GREEK DIALYTIKA TONOS: ΅
+\def\greekAlphatonos {\char"00386 } % GREEK CAPITAL LETTER ALPHA WITH TONOS: Ά
+\def\greekEpsilontonos {\char"00388 } % GREEK CAPITAL LETTER EPSILON WITH TONOS: Έ
+\def\greekEtatonos {\char"00389 } % GREEK CAPITAL LETTER ETA WITH TONOS: Ή
+\def\greekIotatonos {\char"0038A } % GREEK CAPITAL LETTER IOTA WITH TONOS: Ί
+\def\greekOmicrontonos {\char"0038C } % GREEK CAPITAL LETTER OMICRON WITH TONOS: Ό
+\def\greekUpsilontonos {\char"0038E } % GREEK CAPITAL LETTER UPSILON WITH TONOS: Ύ
+\def\greekOmegatonos {\char"0038F } % GREEK CAPITAL LETTER OMEGA WITH TONOS: Ώ
+\def\greekiotadialytikatonos {\char"00390 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS: ΐ
+\def\greekAlpha {\char"00391 } % GREEK CAPITAL LETTER ALPHA: Α
+\def\greekBeta {\char"00392 } % GREEK CAPITAL LETTER BETA: Β
+\def\greekGamma {\char"00393 } % GREEK CAPITAL LETTER GAMMA: Γ
+\def\greekDelta {\char"00394 } % GREEK CAPITAL LETTER DELTA: Δ
+\def\greekEpsilon {\char"00395 } % GREEK CAPITAL LETTER EPSILON: Ε
+\def\greekZeta {\char"00396 } % GREEK CAPITAL LETTER ZETA: Ζ
+\def\greekEta {\char"00397 } % GREEK CAPITAL LETTER ETA: Η
+\def\greekTheta {\char"00398 } % GREEK CAPITAL LETTER THETA: Θ
+\def\greekIota {\char"00399 } % GREEK CAPITAL LETTER IOTA: Ι
+\def\greekKappa {\char"0039A } % GREEK CAPITAL LETTER KAPPA: Κ
+\def\greekLambda {\char"0039B } % GREEK CAPITAL LETTER LAMDA: Λ
+\def\greekMu {\char"0039C } % GREEK CAPITAL LETTER MU: Μ
+\def\greekNu {\char"0039D } % GREEK CAPITAL LETTER NU: Ν
+\def\greekXi {\char"0039E } % GREEK CAPITAL LETTER XI: Ξ
+\def\greekOmicron {\char"0039F } % GREEK CAPITAL LETTER OMICRON: Ο
+\def\greekPi {\char"003A0 } % GREEK CAPITAL LETTER PI: Π
+\def\greekRho {\char"003A1 } % GREEK CAPITAL LETTER RHO: Ρ
+\def\greekSigma {\char"003A3 } % GREEK CAPITAL LETTER SIGMA: Σ
+\def\greekTau {\char"003A4 } % GREEK CAPITAL LETTER TAU: Τ
+\def\greekUpsilon {\char"003A5 } % GREEK CAPITAL LETTER UPSILON: Υ
+\def\greekPhi {\char"003A6 } % GREEK CAPITAL LETTER PHI: Φ
+\def\greekChi {\char"003A7 } % GREEK CAPITAL LETTER CHI: Χ
+\def\greekPsi {\char"003A8 } % GREEK CAPITAL LETTER PSI: Ψ
+\def\greekOmega {\char"003A9 } % GREEK CAPITAL LETTER OMEGA: Ω
+\def\greekIotadialytika {\char"003AA } % GREEK CAPITAL LETTER IOTA WITH DIALYTIKA: Ϊ
+\def\greekUpsilondialytika {\char"003AB } % GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA: Ϋ
+\def\greekalphatonos {\char"003AC } % GREEK SMALL LETTER ALPHA WITH TONOS: ά
+\def\greekepsilontonos {\char"003AD } % GREEK SMALL LETTER EPSILON WITH TONOS: έ
+\def\greeketatonos {\char"003AE } % GREEK SMALL LETTER ETA WITH TONOS: ή
+\def\greekiotatonos {\char"003AF } % GREEK SMALL LETTER IOTA WITH TONOS: ί
+\def\greekupsilondialytikatonos {\char"003B0 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS: ΰ
+\def\greekalpha {\char"003B1 } % GREEK SMALL LETTER ALPHA: α
+\def\greekbeta {\char"003B2 } % GREEK SMALL LETTER BETA: β
+\def\greekgamma {\char"003B3 } % GREEK SMALL LETTER GAMMA: γ
+\def\greekdelta {\char"003B4 } % GREEK SMALL LETTER DELTA: δ
+\def\greekepsilon {\char"003B5 } % GREEK SMALL LETTER EPSILON: ε
+\def\greekzeta {\char"003B6 } % GREEK SMALL LETTER ZETA: ζ
+\def\greeketa {\char"003B7 } % GREEK SMALL LETTER ETA: η
+\def\greektheta {\char"003B8 } % GREEK SMALL LETTER THETA: θ
+\def\greekiota {\char"003B9 } % GREEK SMALL LETTER IOTA: ι
+\def\greekkappa {\char"003BA } % GREEK SMALL LETTER KAPPA: κ
+\def\greeklambda {\char"003BB } % GREEK SMALL LETTER LAMDA: λ
+\def\greekmu {\char"003BC } % GREEK SMALL LETTER MU: μ
+\def\greeknu {\char"003BD } % GREEK SMALL LETTER NU: ν
+\def\greekxi {\char"003BE } % GREEK SMALL LETTER XI: ξ
+\def\greekomicron {\char"003BF } % GREEK SMALL LETTER OMICRON: ο
+\def\greekpi {\char"003C0 } % GREEK SMALL LETTER PI: π
+\def\greekrho {\char"003C1 } % GREEK SMALL LETTER RHO: ρ
+\def\greekfinalsigma {\char"003C2 } % GREEK SMALL LETTER FINAL SIGMA: ς
+\def\greeksigma {\char"003C3 } % GREEK SMALL LETTER SIGMA: σ
+\def\greektau {\char"003C4 } % GREEK SMALL LETTER TAU: τ
+\def\greekupsilon {\char"003C5 } % GREEK SMALL LETTER UPSILON: υ
+\def\greekphi {\char"003C6 } % GREEK SMALL LETTER PHI: φ
+\def\greekchi {\char"003C7 } % GREEK SMALL LETTER CHI: χ
+\def\greekpsi {\char"003C8 } % GREEK SMALL LETTER PSI: ψ
+\def\greekomega {\char"003C9 } % GREEK SMALL LETTER OMEGA: ω
+\def\greekiotadialytika {\char"003CA } % GREEK SMALL LETTER IOTA WITH DIALYTIKA: ϊ
+\def\greekupsilondiaeresis {\char"003CB } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA: ϋ
+\def\greekomicrontonos {\char"003CC } % GREEK SMALL LETTER OMICRON WITH TONOS: ό
+\def\greekupsilontonos {\char"003CD } % GREEK SMALL LETTER UPSILON WITH TONOS: ύ
+\def\greekomegatonos {\char"003CE } % GREEK SMALL LETTER OMEGA WITH TONOS: ώ
+\def\greekthetaalt {\char"003D1 } % GREEK THETA SYMBOL: ϑ
+\def\greekphialt {\char"003D5 } % GREEK PHI SYMBOL: ϕ
+\def\greekpialt {\char"003D6 } % GREEK PI SYMBOL: ϖ
+\def\greekkoppa {\char"003D9 } % GREEK SMALL LETTER ARCHAIC KOPPA: ϙ
+\def\greekstigma {\char"003DB } % GREEK SMALL LETTER STIGMA: ϛ
+\def\greekdigamma {\char"003DD } % GREEK SMALL LETTER DIGAMMA: ϝ
+\def\greeknumkoppa {\char"003DF } % GREEK SMALL LETTER KOPPA: ϟ
+\def\greeksampi {\char"003E1 } % GREEK SMALL LETTER SAMPI: ϡ
+\def\greekrhoalt {\char"003F1 } % GREEK RHO SYMBOL: ϱ
+\def\greeksigmalunate {\char"003F2 } % GREEK LUNATE SIGMA SYMBOL: ϲ
+\def\greekepsilonalt {\char"003F5 } % GREEK LUNATE EPSILON SYMBOL: ϵ
+\def\greekSigmalunate {\char"003F9 } % GREEK CAPITAL LUNATE SIGMA SYMBOL: Ϲ
+\def\cyrillicEgrave {\char"00400 } % CYRILLIC CAPITAL LETTER IE WITH GRAVE: Ѐ
+\def\cyrillicYO {\char"00401 } % CYRILLIC CAPITAL LETTER IO: Ё
+\def\cyrillicDJE {\char"00402 } % CYRILLIC CAPITAL LETTER DJE: Ђ
+\def\cyrillicGJE {\char"00403 } % CYRILLIC CAPITAL LETTER GJE: Ѓ
+\def\cyrillicIE {\char"00404 } % CYRILLIC CAPITAL LETTER UKRAINIAN IE: Є
+\def\cyrillicDZE {\char"00405 } % CYRILLIC CAPITAL LETTER DZE: Ѕ
+\def\cyrillicII {\char"00406 } % CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I: І
+\def\cyrillicYI {\char"00407 } % CYRILLIC CAPITAL LETTER YI: Ї
+\def\cyrillicJE {\char"00408 } % CYRILLIC CAPITAL LETTER JE: Ј
+\def\cyrillicLJE {\char"00409 } % CYRILLIC CAPITAL LETTER LJE: Љ
+\def\cyrillicNJE {\char"0040A } % CYRILLIC CAPITAL LETTER NJE: Њ
+\def\cyrillicTSHE {\char"0040B } % CYRILLIC CAPITAL LETTER TSHE: Ћ
+\def\cyrillicKJE {\char"0040C } % CYRILLIC CAPITAL LETTER KJE: Ќ
+\def\cyrillicIgrave {\char"0040D } % CYRILLIC CAPITAL LETTER I WITH GRAVE: Ѝ
+\def\cyrillicUSHRT {\char"0040E } % CYRILLIC CAPITAL LETTER SHORT U: Ў
+\def\cyrillicDZHE {\char"0040F } % CYRILLIC CAPITAL LETTER DZHE: Џ
+\def\cyrillicA {\char"00410 } % CYRILLIC CAPITAL LETTER A: А
+\def\cyrillicB {\char"00411 } % CYRILLIC CAPITAL LETTER BE: Б
+\def\cyrillicV {\char"00412 } % CYRILLIC CAPITAL LETTER VE: В
+\def\cyrillicG {\char"00413 } % CYRILLIC CAPITAL LETTER GHE: Г
+\def\cyrillicD {\char"00414 } % CYRILLIC CAPITAL LETTER DE: Д
+\def\cyrillicE {\char"00415 } % CYRILLIC CAPITAL LETTER IE: Е
+\def\cyrillicZH {\char"00416 } % CYRILLIC CAPITAL LETTER ZHE: Ж
+\def\cyrillicZ {\char"00417 } % CYRILLIC CAPITAL LETTER ZE: З
+\def\cyrillicI {\char"00418 } % CYRILLIC CAPITAL LETTER I: И
+\def\cyrillicISHRT {\char"00419 } % CYRILLIC CAPITAL LETTER SHORT I: Й
+\def\cyrillicK {\char"0041A } % CYRILLIC CAPITAL LETTER KA: К
+\def\cyrillicL {\char"0041B } % CYRILLIC CAPITAL LETTER EL: Л
+\def\cyrillicM {\char"0041C } % CYRILLIC CAPITAL LETTER EM: М
+\def\cyrillicN {\char"0041D } % CYRILLIC CAPITAL LETTER EN: Н
+\def\cyrillicO {\char"0041E } % CYRILLIC CAPITAL LETTER O: О
+\def\cyrillicP {\char"0041F } % CYRILLIC CAPITAL LETTER PE: П
+\def\cyrillicR {\char"00420 } % CYRILLIC CAPITAL LETTER ER: Р
+\def\cyrillicS {\char"00421 } % CYRILLIC CAPITAL LETTER ES: С
+\def\cyrillicT {\char"00422 } % CYRILLIC CAPITAL LETTER TE: Т
+\def\cyrillicU {\char"00423 } % CYRILLIC CAPITAL LETTER U: У
+\def\cyrillicF {\char"00424 } % CYRILLIC CAPITAL LETTER EF: Ф
+\def\cyrillicH {\char"00425 } % CYRILLIC CAPITAL LETTER HA: Х
+\def\cyrillicC {\char"00426 } % CYRILLIC CAPITAL LETTER TSE: Ц
+\def\cyrillicCH {\char"00427 } % CYRILLIC CAPITAL LETTER CHE: Ч
+\def\cyrillicSH {\char"00428 } % CYRILLIC CAPITAL LETTER SHA: Ш
+\def\cyrillicSHCH {\char"00429 } % CYRILLIC CAPITAL LETTER SHCHA: Щ
+\def\cyrillicHRDSN {\char"0042A } % CYRILLIC CAPITAL LETTER HARD SIGN: Ъ
+\def\cyrillicERY {\char"0042B } % CYRILLIC CAPITAL LETTER YERU: Ы
+\def\cyrillicSFTSN {\char"0042C } % CYRILLIC CAPITAL LETTER SOFT SIGN: Ь
+\def\cyrillicEREV {\char"0042D } % CYRILLIC CAPITAL LETTER E: Э
+\def\cyrillicYU {\char"0042E } % CYRILLIC CAPITAL LETTER YU: Ю
+\def\cyrillicYA {\char"0042F } % CYRILLIC CAPITAL LETTER YA: Я
+\def\cyrillica {\char"00430 } % CYRILLIC SMALL LETTER A: а
+\def\cyrillicb {\char"00431 } % CYRILLIC SMALL LETTER BE: б
+\def\cyrillicv {\char"00432 } % CYRILLIC SMALL LETTER VE: в
+\def\cyrillicg {\char"00433 } % CYRILLIC SMALL LETTER GHE: г
+\def\cyrillicd {\char"00434 } % CYRILLIC SMALL LETTER DE: д
+\def\cyrillice {\char"00435 } % CYRILLIC SMALL LETTER IE: е
+\def\cyrilliczh {\char"00436 } % CYRILLIC SMALL LETTER ZHE: ж
+\def\cyrillicz {\char"00437 } % CYRILLIC SMALL LETTER ZE: з
+\def\cyrillici {\char"00438 } % CYRILLIC SMALL LETTER I: и
+\def\cyrillicishrt {\char"00439 } % CYRILLIC SMALL LETTER SHORT I: й
+\def\cyrillick {\char"0043A } % CYRILLIC SMALL LETTER KA: к
+\def\cyrillicl {\char"0043B } % CYRILLIC SMALL LETTER EL: л
+\def\cyrillicm {\char"0043C } % CYRILLIC SMALL LETTER EM: м
+\def\cyrillicn {\char"0043D } % CYRILLIC SMALL LETTER EN: н
+\def\cyrillico {\char"0043E } % CYRILLIC SMALL LETTER O: о
+\def\cyrillicp {\char"0043F } % CYRILLIC SMALL LETTER PE: п
+\def\cyrillicr {\char"00440 } % CYRILLIC SMALL LETTER ER: р
+\def\cyrillics {\char"00441 } % CYRILLIC SMALL LETTER ES: с
+\def\cyrillict {\char"00442 } % CYRILLIC SMALL LETTER TE: т
+\def\cyrillicu {\char"00443 } % CYRILLIC SMALL LETTER U: у
+\def\cyrillicf {\char"00444 } % CYRILLIC SMALL LETTER EF: ф
+\def\cyrillich {\char"00445 } % CYRILLIC SMALL LETTER HA: х
+\def\cyrillicc {\char"00446 } % CYRILLIC SMALL LETTER TSE: ц
+\def\cyrillicch {\char"00447 } % CYRILLIC SMALL LETTER CHE: ч
+\def\cyrillicsh {\char"00448 } % CYRILLIC SMALL LETTER SHA: ш
+\def\cyrillicshch {\char"00449 } % CYRILLIC SMALL LETTER SHCHA: щ
+\def\cyrillichrdsn {\char"0044A } % CYRILLIC SMALL LETTER HARD SIGN: ъ
+\def\cyrillicery {\char"0044B } % CYRILLIC SMALL LETTER YERU: ы
+\def\cyrillicsftsn {\char"0044C } % CYRILLIC SMALL LETTER SOFT SIGN: ь
+\def\cyrillicerev {\char"0044D } % CYRILLIC SMALL LETTER E: э
+\def\cyrillicyu {\char"0044E } % CYRILLIC SMALL LETTER YU: ю
+\def\cyrillicya {\char"0044F } % CYRILLIC SMALL LETTER YA: я
+\def\cyrillicegrave {\char"00450 } % CYRILLIC SMALL LETTER IE WITH GRAVE: ѐ
+\def\cyrillicyo {\char"00451 } % CYRILLIC SMALL LETTER IO: ё
+\def\cyrillicdje {\char"00452 } % CYRILLIC SMALL LETTER DJE: ђ
+\def\cyrillicgje {\char"00453 } % CYRILLIC SMALL LETTER GJE: ѓ
+\def\cyrillicie {\char"00454 } % CYRILLIC SMALL LETTER UKRAINIAN IE: є
+\def\cyrillicdze {\char"00455 } % CYRILLIC SMALL LETTER DZE: ѕ
+\def\cyrillicii {\char"00456 } % CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I: і
+\def\cyrillicyi {\char"00457 } % CYRILLIC SMALL LETTER YI: ї
+\def\cyrillicje {\char"00458 } % CYRILLIC SMALL LETTER JE: ј
+\def\cyrilliclje {\char"00459 } % CYRILLIC SMALL LETTER LJE: љ
+\def\cyrillicnje {\char"0045A } % CYRILLIC SMALL LETTER NJE: њ
+\def\cyrillictshe {\char"0045B } % CYRILLIC SMALL LETTER TSHE: ћ
+\def\cyrillickje {\char"0045C } % CYRILLIC SMALL LETTER KJE: ќ
+\def\cyrillicigrave {\char"0045D } % CYRILLIC SMALL LETTER I WITH GRAVE: ѝ
+\def\cyrillicushrt {\char"0045E } % CYRILLIC SMALL LETTER SHORT U: ў
+\def\cyrillicdzhe {\char"0045F } % CYRILLIC SMALL LETTER DZHE: џ
+\def\cyrillicOMEGA {\char"00460 } % CYRILLIC CAPITAL LETTER OMEGA: Ѡ
+\def\cyrillicomega {\char"00461 } % CYRILLIC SMALL LETTER OMEGA: ѡ
+\def\cyrillicYAT {\char"00462 } % CYRILLIC CAPITAL LETTER YAT: Ѣ
+\def\cyrillicyat {\char"00463 } % CYRILLIC SMALL LETTER YAT: ѣ
+\def\cyrillicEiotified {\char"00464 } % CYRILLIC CAPITAL LETTER IOTIFIED E: Ѥ
+\def\cyrilliceiotified {\char"00465 } % CYRILLIC SMALL LETTER IOTIFIED E: ѥ
+\def\cyrillicLITTLEYUS {\char"00466 } % CYRILLIC CAPITAL LETTER LITTLE YUS: Ѧ
+\def\cyrilliclittleyus {\char"00467 } % CYRILLIC SMALL LETTER LITTLE YUS: ѧ
+\def\cyrillicLITTLEYUSiotified {\char"00468 } % CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS: Ѩ
+\def\cyrilliclittleyusiotified {\char"00469 } % CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS: ѩ
+\def\cyrillicBIGYUS {\char"0046A } % CYRILLIC CAPITAL LETTER BIG YUS: Ѫ
+\def\cyrillicbigyus {\char"0046B } % CYRILLIC SMALL LETTER BIG YUS: ѫ
+\def\cyrillicBIGYUSiotified {\char"0046C } % CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS: Ѭ
+\def\cyrillicbigyusiotified {\char"0046D } % CYRILLIC SMALL LETTER IOTIFIED BIG YUS: ѭ
+\def\cyrillicKSI {\char"0046E } % CYRILLIC CAPITAL LETTER KSI: Ѯ
+\def\cyrillicksi {\char"0046F } % CYRILLIC SMALL LETTER KSI: ѯ
+\def\cyrillicPSI {\char"00470 } % CYRILLIC CAPITAL LETTER PSI: Ѱ
+\def\cyrillicpsi {\char"00471 } % CYRILLIC SMALL LETTER PSI: ѱ
+\def\cyrillicFITA {\char"00472 } % CYRILLIC CAPITAL LETTER FITA: Ѳ
+\def\cyrillicfita {\char"00473 } % CYRILLIC SMALL LETTER FITA: ѳ
+\def\cyrillicIZHITSA {\char"00474 } % CYRILLIC CAPITAL LETTER IZHITSA: Ѵ
+\def\cyrillicizhitsa {\char"00475 } % CYRILLIC SMALL LETTER IZHITSA: ѵ
+\def\cyrillicIZHITSAdoublegrave {\char"00476 } % CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT: Ѷ
+\def\cyrillicizhitsadoublegrave {\char"00477 } % CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT: ѷ
+\def\cyrillicUK {\char"00478 } % CYRILLIC CAPITAL LETTER UK: Ѹ
+\def\cyrillicuk {\char"00479 } % CYRILLIC SMALL LETTER UK: ѹ
+\def\cyrillicOMEGAround {\char"0047A } % CYRILLIC CAPITAL LETTER ROUND OMEGA: Ѻ
+\def\cyrillicomegaround {\char"0047B } % CYRILLIC SMALL LETTER ROUND OMEGA: ѻ
+\def\cyrillicOMEGAtitlo {\char"0047C } % CYRILLIC CAPITAL LETTER OMEGA WITH TITLO: Ѽ
+\def\cyrillicomegatitlo {\char"0047D } % CYRILLIC SMALL LETTER OMEGA WITH TITLO: ѽ
+\def\cyrillicOT {\char"0047E } % CYRILLIC CAPITAL LETTER OT: Ѿ
+\def\cyrillicot {\char"0047F } % CYRILLIC SMALL LETTER OT: ѿ
+\def\cyrillicKOPPA {\char"00480 } % CYRILLIC CAPITAL LETTER KOPPA: Ҁ
+\def\cyrillickoppa {\char"00481 } % CYRILLIC SMALL LETTER KOPPA: ҁ
+\def\cyrillicTITLO {\char"00483 } % COMBINING CYRILLIC TITLO: ҃
+\def\cyrillicPALATALIZATION {\char"00484 } % COMBINING CYRILLIC PALATALIZATION: ҄
+\def\cyrillicDASIAPNEUMATA {\char"00485 } % COMBINING CYRILLIC DASIA PNEUMATA: ҅
+\def\cyrillicPSILIPNEUMATA {\char"00486 } % COMBINING CYRILLIC PSILI PNEUMATA: ҆
+\def\cyrillicISHRTtail {\char"0048A } % CYRILLIC CAPITAL LETTER SHORT I WITH TAIL: Ҋ
+\def\cyrillicishrttail {\char"0048B } % CYRILLIC SMALL LETTER SHORT I WITH TAIL: ҋ
+\def\cyrillicSEMISOFT {\char"0048C } % CYRILLIC CAPITAL LETTER SEMISOFT SIGN: Ҍ
+\def\cyrillicsemisoft {\char"0048D } % CYRILLIC SMALL LETTER SEMISOFT SIGN: ҍ
+\def\cyrillicERtick {\char"0048E } % CYRILLIC CAPITAL LETTER ER WITH TICK: Ҏ
+\def\cyrillicertick {\char"0048F } % CYRILLIC SMALL LETTER ER WITH TICK: ҏ
+\def\cyrillicGHEupturn {\char"00490 } % CYRILLIC CAPITAL LETTER GHE WITH UPTURN: Ґ
+\def\cyrillicgheupturn {\char"00491 } % CYRILLIC SMALL LETTER GHE WITH UPTURN: ґ
+\def\cyrillicGHEstroke {\char"00492 } % CYRILLIC CAPITAL LETTER GHE WITH STROKE: Ғ
+\def\cyrillicghestroke {\char"00493 } % CYRILLIC SMALL LETTER GHE WITH STROKE: ғ
+\def\cyrillicGHEmidhook {\char"00494 } % CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK: Ҕ
+\def\cyrillicghemidhook {\char"00495 } % CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK: ҕ
+\def\cyrillicZHEdescender {\char"00496 } % CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER: Җ
+\def\cyrilliczhedescender {\char"00497 } % CYRILLIC SMALL LETTER ZHE WITH DESCENDER: җ
+\def\cyrillicZDSC {\char"00498 } % CYRILLIC CAPITAL LETTER ZE WITH DESCENDER: Ҙ
+\def\cyrilliczdsc {\char"00499 } % CYRILLIC SMALL LETTER ZE WITH DESCENDER: ҙ
+\def\cyrillicKADC {\char"0049A } % CYRILLIC CAPITAL LETTER KA WITH DESCENDER: Қ
+\def\cyrillickadc {\char"0049B } % CYRILLIC SMALL LETTER KA WITH DESCENDER: қ
+\def\cyrillicKAvertstroke {\char"0049C } % CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE: Ҝ
+\def\cyrillickavertstroke {\char"0049D } % CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE: ҝ
+\def\cyrillicKAstroke {\char"0049E } % CYRILLIC CAPITAL LETTER KA WITH STROKE: Ҟ
+\def\cyrillickastroke {\char"0049F } % CYRILLIC SMALL LETTER KA WITH STROKE: ҟ
+\def\cyrillicKAbashkir {\char"004A0 } % CYRILLIC CAPITAL LETTER BASHKIR KA: Ҡ
+\def\cyrillickabashkir {\char"004A1 } % CYRILLIC SMALL LETTER BASHKIR KA: ҡ
+\def\cyrillicENDC {\char"004A2 } % CYRILLIC CAPITAL LETTER EN WITH DESCENDER: Ң
+\def\cyrillicendc {\char"004A3 } % CYRILLIC SMALL LETTER EN WITH DESCENDER: ң
+\def\cyrillicENGHE {\char"004A4 } % CYRILLIC CAPITAL LIGATURE EN GHE: Ҥ
+\def\cyrillicenghe {\char"004A5 } % CYRILLIC SMALL LIGATURE EN GHE: ҥ
+\def\cyrillicPEmidhook {\char"004A6 } % CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK: Ҧ
+\def\cyrillicpemidhook {\char"004A7 } % CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK: ҧ
+\def\cyrillicHA {\char"004A8 } % CYRILLIC CAPITAL LETTER ABKHASIAN HA: Ҩ
+\def\cyrillicha {\char"004A9 } % CYRILLIC SMALL LETTER ABKHASIAN HA: ҩ
+\def\cyrillicSDSC {\char"004AA } % CYRILLIC CAPITAL LETTER ES WITH DESCENDER: Ҫ
+\def\cyrillicsdsc {\char"004AB } % CYRILLIC SMALL LETTER ES WITH DESCENDER: ҫ
+\def\cyrillicTEDC {\char"004AC } % CYRILLIC CAPITAL LETTER TE WITH DESCENDER: Ҭ
+\def\cyrillictedc {\char"004AD } % CYRILLIC SMALL LETTER TE WITH DESCENDER: ҭ
+\def\cyrillicYstr {\char"004AE } % CYRILLIC CAPITAL LETTER STRAIGHT U: Ү
+\def\cyrillicystr {\char"004AF } % CYRILLIC SMALL LETTER STRAIGHT U: ү
+\def\cyrillicYstrstroke {\char"004B0 } % CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE: Ұ
+\def\cyrillicystrstroke {\char"004B1 } % CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE: ұ
+\def\cyrillicHADC {\char"004B2 } % CYRILLIC CAPITAL LETTER HA WITH DESCENDER: Ҳ
+\def\cyrillichadc {\char"004B3 } % CYRILLIC SMALL LETTER HA WITH DESCENDER: ҳ
+\def\cyrillicTETSE {\char"004B4 } % CYRILLIC CAPITAL LIGATURE TE TSE: Ҵ
+\def\cyrillictetse {\char"004B5 } % CYRILLIC SMALL LIGATURE TE TSE: ҵ
+\def\cyrillicCHEDC {\char"004B6 } % CYRILLIC CAPITAL LETTER CHE WITH DESCENDER: Ҷ
+\def\cyrillicchedc {\char"004B7 } % CYRILLIC SMALL LETTER CHE WITH DESCENDER: ҷ
+\def\cyrillicCHEvertstroke {\char"004B8 } % CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE: Ҹ
+\def\cyrillicchevertstroke {\char"004B9 } % CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE: ҹ
+\def\cyrillicSHHA {\char"004BA } % CYRILLIC CAPITAL LETTER SHHA: Һ
+\def\cyrillicshha {\char"004BB } % CYRILLIC SMALL LETTER SHHA: һ
+\def\cyrillicCHEabkhasian {\char"004BC } % CYRILLIC CAPITAL LETTER ABKHASIAN CHE: Ҽ
+\def\cyrilliccheabkhasian {\char"004BD } % CYRILLIC SMALL LETTER ABKHASIAN CHE: ҽ
+\def\cyrillicCHEDCabkhasian {\char"004BE } % CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER: Ҿ
+\def\cyrillicchedcabkhasian {\char"004BF } % CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER: ҿ
+\def\cyrillicPALOCHKA {\char"004C0 } % CYRILLIC LETTER PALOCHKA: Ӏ
+\def\cyrillicZHEbreve {\char"004C1 } % CYRILLIC CAPITAL LETTER ZHE WITH BREVE: Ӂ
+\def\cyrilliczhebreve {\char"004C2 } % CYRILLIC SMALL LETTER ZHE WITH BREVE: ӂ
+\def\cyrillicKAhook {\char"004C3 } % CYRILLIC CAPITAL LETTER KA WITH HOOK: Ӄ
+\def\cyrillickahook {\char"004C4 } % CYRILLIC SMALL LETTER KA WITH HOOK: ӄ
+\def\cyrillicELtail {\char"004C5 } % CYRILLIC CAPITAL LETTER EL WITH TAIL: Ӆ
+\def\cyrilliceltail {\char"004C6 } % CYRILLIC SMALL LETTER EL WITH TAIL: ӆ
+\def\cyrillicENhook {\char"004C7 } % CYRILLIC CAPITAL LETTER EN WITH HOOK: Ӈ
+\def\cyrillicenhook {\char"004C8 } % CYRILLIC SMALL LETTER EN WITH HOOK: ӈ
+\def\cyrillicENtail {\char"004C9 } % CYRILLIC CAPITAL LETTER EN WITH TAIL: Ӊ
+\def\cyrillicentail {\char"004CA } % CYRILLIC SMALL LETTER EN WITH TAIL: ӊ
+\def\cyrillicCHEkhakassian {\char"004CB } % CYRILLIC CAPITAL LETTER KHAKASSIAN CHE: Ӌ
+\def\cyrillicchekhakassian {\char"004CC } % CYRILLIC SMALL LETTER KHAKASSIAN CHE: ӌ
+\def\cyrillicEMtail {\char"004CD } % CYRILLIC CAPITAL LETTER EM WITH TAIL: Ӎ
+\def\cyrillicemtail {\char"004CE } % CYRILLIC SMALL LETTER EM WITH TAIL: ӎ
+\def\cyrillicAbreve {\char"004D0 } % CYRILLIC CAPITAL LETTER A WITH BREVE: Ӑ
+\def\cyrillicabreve {\char"004D1 } % CYRILLIC SMALL LETTER A WITH BREVE: ӑ
+\def\cyrillicAdiaeresis {\char"004D2 } % CYRILLIC CAPITAL LETTER A WITH DIAERESIS: Ӓ
+\def\cyrillicadiaeresis {\char"004D3 } % CYRILLIC SMALL LETTER A WITH DIAERESIS: ӓ
+\def\cyrillicAE {\char"004D4 } % CYRILLIC CAPITAL LIGATURE A IE: Ӕ
+\def\cyrillicae {\char"004D5 } % CYRILLIC SMALL LIGATURE A IE: ӕ
+\def\cyrillicEbreve {\char"004D6 } % CYRILLIC CAPITAL LETTER IE WITH BREVE: Ӗ
+\def\cyrillicebreve {\char"004D7 } % CYRILLIC SMALL LETTER IE WITH BREVE: ӗ
+\def\cyrillicSCHWA {\char"004D8 } % CYRILLIC CAPITAL LETTER SCHWA: Ә
+\def\cyrillicschwa {\char"004D9 } % CYRILLIC SMALL LETTER SCHWA: ә
+\def\cyrillicSCHWAdiaeresis {\char"004DA } % CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS: Ӛ
+\def\cyrillicschwadiaeresis {\char"004DB } % CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS: ӛ
+\def\cyrillicZHEdiaeresis {\char"004DC } % CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS: Ӝ
+\def\cyrilliczhediaeresis {\char"004DD } % CYRILLIC SMALL LETTER ZHE WITH DIAERESIS: ӝ
+\def\cyrillicZEdiaeresis {\char"004DE } % CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS: Ӟ
+\def\cyrilliczediaeresis {\char"004DF } % CYRILLIC SMALL LETTER ZE WITH DIAERESIS: ӟ
+\def\cyrillicDZEabkhasian {\char"004E0 } % CYRILLIC CAPITAL LETTER ABKHASIAN DZE: Ӡ
+\def\cyrillicdzeabkhasian {\char"004E1 } % CYRILLIC SMALL LETTER ABKHASIAN DZE: ӡ
+\def\cyrillicImacron {\char"004E2 } % CYRILLIC CAPITAL LETTER I WITH MACRON: Ӣ
+\def\cyrillicimacron {\char"004E3 } % CYRILLIC SMALL LETTER I WITH MACRON: ӣ
+\def\cyrillicIdiaeresis {\char"004E4 } % CYRILLIC CAPITAL LETTER I WITH DIAERESIS: Ӥ
+\def\cyrillicidiaeresis {\char"004E5 } % CYRILLIC SMALL LETTER I WITH DIAERESIS: ӥ
+\def\cyrillicOdiaeresis {\char"004E6 } % CYRILLIC CAPITAL LETTER O WITH DIAERESIS: Ӧ
+\def\cyrillicodiaeresis {\char"004E7 } % CYRILLIC SMALL LETTER O WITH DIAERESIS: ӧ
+\def\cyrillicObarred {\char"004E8 } % CYRILLIC CAPITAL LETTER BARRED O: Ө
+\def\cyrillicobarred {\char"004E9 } % CYRILLIC SMALL LETTER BARRED O: ө
+\def\cyrillicObarreddiaeresis {\char"004EA } % CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS: Ӫ
+\def\cyrillicobarreddiaeresis {\char"004EB } % CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS: ӫ
+\def\cyrillicEdiaeresis {\char"004EC } % CYRILLIC CAPITAL LETTER E WITH DIAERESIS: Ӭ
+\def\cyrillicediaeresis {\char"004ED } % CYRILLIC SMALL LETTER E WITH DIAERESIS: ӭ
+\def\cyrillicUmacron {\char"004EE } % CYRILLIC CAPITAL LETTER U WITH MACRON: Ӯ
+\def\cyrillicumacron {\char"004EF } % CYRILLIC SMALL LETTER U WITH MACRON: ӯ
+\def\cyrillicUdiaeresis {\char"004F0 } % CYRILLIC CAPITAL LETTER U WITH DIAERESIS: Ӱ
+\def\cyrillicudiaeresis {\char"004F1 } % CYRILLIC SMALL LETTER U WITH DIAERESIS: ӱ
+\def\cyrillicUdoubleacute {\char"004F2 } % CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE: Ӳ
+\def\cyrillicudoubleacute {\char"004F3 } % CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE: ӳ
+\def\cyrillicCHEdiaeresis {\char"004F4 } % CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS: Ӵ
+\def\cyrillicchediaeresis {\char"004F5 } % CYRILLIC SMALL LETTER CHE WITH DIAERESIS: ӵ
+\def\cyrillicYERUdiaeresis {\char"004F8 } % CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS: Ӹ
+\def\cyrillicyerudiaeresis {\char"004F9 } % CYRILLIC SMALL LETTER YERU WITH DIAERESIS: ӹ
+\def\hebrewAlef {\char"005D0 } % HEBREW LETTER ALEF: א
+\def\hebrewBet {\char"005D1 } % HEBREW LETTER BET: ב
+\def\hebrewGimel {\char"005D2 } % HEBREW LETTER GIMEL: ג
+\def\hebrewDalet {\char"005D3 } % HEBREW LETTER DALET: ד
+\def\hebrewHe {\char"005D4 } % HEBREW LETTER HE: ה
+\def\hebrewVav {\char"005D5 } % HEBREW LETTER VAV: ו
+\def\hebrewZayin {\char"005D6 } % HEBREW LETTER ZAYIN: ז
+\def\hebrewHet {\char"005D7 } % HEBREW LETTER HET: ח
+\def\hebrewTet {\char"005D8 } % HEBREW LETTER TET: ט
+\def\hebrewYod {\char"005D9 } % HEBREW LETTER YOD: י
+\def\hebrewKaffinal {\char"005DA } % HEBREW LETTER FINAL KAF: ך
+\def\hebrewKaf {\char"005DB } % HEBREW LETTER KAF: כ
+\def\hebrewLamed {\char"005DC } % HEBREW LETTER LAMED: ל
+\def\hebrewMemfinal {\char"005DD } % HEBREW LETTER FINAL MEM: ם
+\def\hebrewMem {\char"005DE } % HEBREW LETTER MEM: מ
+\def\hebrewNunfinal {\char"005DF } % HEBREW LETTER FINAL NUN: ן
+\def\hebrewNun {\char"005E0 } % HEBREW LETTER NUN: נ
+\def\hebrewSamekh {\char"005E1 } % HEBREW LETTER SAMEKH: ס
+\def\hebrewAyin {\char"005E2 } % HEBREW LETTER AYIN: ע
+\def\hebrewPefinal {\char"005E3 } % HEBREW LETTER FINAL PE: ף
+\def\hebrewPe {\char"005E4 } % HEBREW LETTER PE: פ
+\def\hebrewTsadifinal {\char"005E5 } % HEBREW LETTER FINAL TSADI: ץ
+\def\hebrewTsadi {\char"005E6 } % HEBREW LETTER TSADI: צ
+\def\hebrewQof {\char"005E7 } % HEBREW LETTER QOF: ק
+\def\hebrewResh {\char"005E8 } % HEBREW LETTER RESH: ר
+\def\hebrewShin {\char"005E9 } % HEBREW LETTER SHIN: ש
+\def\hebrewTav {\char"005EA } % HEBREW LETTER TAV: ת
+\def\Adotbelow {\char"01EA0 } % LATIN CAPITAL LETTER A WITH DOT BELOW: Ạ
+\def\adotbelow {\char"01EA1 } % LATIN SMALL LETTER A WITH DOT BELOW: ạ
+\def\Ahook {\char"01EA2 } % LATIN CAPITAL LETTER A WITH HOOK ABOVE: Ả
+\def\ahook {\char"01EA3 } % LATIN SMALL LETTER A WITH HOOK ABOVE: ả
+\def\Acircumflexacute {\char"01EA4 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE: Ấ
+\def\acircumflexacute {\char"01EA5 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE: ấ
+\def\Acircumflexgrave {\char"01EA6 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE: Ầ
+\def\acircumflexgrave {\char"01EA7 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE: ầ
+\def\Acircumflexhook {\char"01EA8 } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE: Ẩ
+\def\acircumflexhook {\char"01EA9 } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE: ẩ
+\def\Acircumflextilde {\char"01EAA } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE: Ẫ
+\def\acircumflextilde {\char"01EAB } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE: ẫ
+\def\Acircumflexdotbelow {\char"01EAC } % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW: Ậ
+\def\acircumflexdotbelow {\char"01EAD } % LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW: ậ
+\def\Abreveacute {\char"01EAE } % LATIN CAPITAL LETTER A WITH BREVE AND ACUTE: Ắ
+\def\abreveacute {\char"01EAF } % LATIN SMALL LETTER A WITH BREVE AND ACUTE: ắ
+\def\Abrevegrave {\char"01EB0 } % LATIN CAPITAL LETTER A WITH BREVE AND GRAVE: Ằ
+\def\abrevegrave {\char"01EB1 } % LATIN SMALL LETTER A WITH BREVE AND GRAVE: ằ
+\def\Abrevehook {\char"01EB2 } % LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE: Ẳ
+\def\abrevehook {\char"01EB3 } % LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE: ẳ
+\def\Abrevetilde {\char"01EB4 } % LATIN CAPITAL LETTER A WITH BREVE AND TILDE: Ẵ
+\def\abrevetilde {\char"01EB5 } % LATIN SMALL LETTER A WITH BREVE AND TILDE: ẵ
+\def\Abrevedotbelow {\char"01EB6 } % LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW: Ặ
+\def\abrevedotbelow {\char"01EB7 } % LATIN SMALL LETTER A WITH BREVE AND DOT BELOW: ặ
+\def\Edotbelow {\char"01EB8 } % LATIN CAPITAL LETTER E WITH DOT BELOW: Ẹ
+\def\edotbelow {\char"01EB9 } % LATIN SMALL LETTER E WITH DOT BELOW: ẹ
+\def\Ehook {\char"01EBA } % LATIN CAPITAL LETTER E WITH HOOK ABOVE: Ẻ
+\def\ehook {\char"01EBB } % LATIN SMALL LETTER E WITH HOOK ABOVE: ẻ
+\def\Etilde {\char"01EBC } % LATIN CAPITAL LETTER E WITH TILDE: Ẽ
+\def\etilde {\char"01EBD } % LATIN SMALL LETTER E WITH TILDE: ẽ
+\def\Ecircumflexacute {\char"01EBE } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE: Ế
+\def\ecircumflexacute {\char"01EBF } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE: ế
+\def\Ecircumflexgrave {\char"01EC0 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE: Ề
+\def\ecircumflexgrave {\char"01EC1 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE: ề
+\def\Ecircumflexhook {\char"01EC2 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE: Ể
+\def\ecircumflexhook {\char"01EC3 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE: ể
+\def\Ecircumflextilde {\char"01EC4 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE: Ễ
+\def\ecircumflextilde {\char"01EC5 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE: ễ
+\def\Ecircumflexdotbelow {\char"01EC6 } % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW: Ệ
+\def\ecircumflexdotbelow {\char"01EC7 } % LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW: ệ
+\def\Ihook {\char"01EC8 } % LATIN CAPITAL LETTER I WITH HOOK ABOVE: Ỉ
+\def\ihook {\char"01EC9 } % LATIN SMALL LETTER I WITH HOOK ABOVE: ỉ
+\def\Idotbelow {\char"01ECA } % LATIN CAPITAL LETTER I WITH DOT BELOW: Ị
+\def\idotbelow {\char"01ECB } % LATIN SMALL LETTER I WITH DOT BELOW: ị
+\def\Odotbelow {\char"01ECC } % LATIN CAPITAL LETTER O WITH DOT BELOW: Ọ
+\def\odotbelow {\char"01ECD } % LATIN SMALL LETTER O WITH DOT BELOW: ọ
+\def\Ohook {\char"01ECE } % LATIN CAPITAL LETTER O WITH HOOK ABOVE: Ỏ
+\def\ohook {\char"01ECF } % LATIN SMALL LETTER O WITH HOOK ABOVE: ỏ
+\def\Ocircumflexacute {\char"01ED0 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE: Ố
+\def\ocircumflexacute {\char"01ED1 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE: ố
+\def\Ocircumflexgrave {\char"01ED2 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE: Ồ
+\def\ocircumflexgrave {\char"01ED3 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE: ồ
+\def\Ocircumflexhook {\char"01ED4 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE: Ổ
+\def\ocircumflexhook {\char"01ED5 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE: ổ
+\def\Ocircumflextilde {\char"01ED6 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE: Ỗ
+\def\ocircumflextilde {\char"01ED7 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE: ỗ
+\def\Ocircumflexdotbelow {\char"01ED8 } % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW: Ộ
+\def\ocircumflexdotbelow {\char"01ED9 } % LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW: ộ
+\def\Ohornacute {\char"01EDA } % LATIN CAPITAL LETTER O WITH HORN AND ACUTE: Ớ
+\def\ohornacute {\char"01EDB } % LATIN SMALL LETTER O WITH HORN AND ACUTE: ớ
+\def\Ohorngrave {\char"01EDC } % LATIN CAPITAL LETTER O WITH HORN AND GRAVE: Ờ
+\def\ohorngrave {\char"01EDD } % LATIN SMALL LETTER O WITH HORN AND GRAVE: ờ
+\def\Ohornhook {\char"01EDE } % LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE: Ở
+\def\ohornhook {\char"01EDF } % LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE: ở
+\def\Ohorntilde {\char"01EE0 } % LATIN CAPITAL LETTER O WITH HORN AND TILDE: Ỡ
+\def\ohorntilde {\char"01EE1 } % LATIN SMALL LETTER O WITH HORN AND TILDE: ỡ
+\def\Ohorndotbelow {\char"01EE2 } % LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW: Ợ
+\def\ohorndotbelow {\char"01EE3 } % LATIN SMALL LETTER O WITH HORN AND DOT BELOW: ợ
+\def\Udotbelow {\char"01EE4 } % LATIN CAPITAL LETTER U WITH DOT BELOW: Ụ
+\def\udotbelow {\char"01EE5 } % LATIN SMALL LETTER U WITH DOT BELOW: ụ
+\def\Uhook {\char"01EE6 } % LATIN CAPITAL LETTER U WITH HOOK ABOVE: Ủ
+\def\uhook {\char"01EE7 } % LATIN SMALL LETTER U WITH HOOK ABOVE: ủ
+\def\Uhornacute {\char"01EE8 } % LATIN CAPITAL LETTER U WITH HORN AND ACUTE: Ứ
+\def\uhornacute {\char"01EE9 } % LATIN SMALL LETTER U WITH HORN AND ACUTE: ứ
+\def\Uhorngrave {\char"01EEA } % LATIN CAPITAL LETTER U WITH HORN AND GRAVE: Ừ
+\def\uhorngrave {\char"01EEB } % LATIN SMALL LETTER U WITH HORN AND GRAVE: ừ
+\def\Uhornhook {\char"01EEC } % LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE: Ử
+\def\uhornhook {\char"01EED } % LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE: ử
+\def\Uhorntilde {\char"01EEE } % LATIN CAPITAL LETTER U WITH HORN AND TILDE: Ữ
+\def\uhorntilde {\char"01EEF } % LATIN SMALL LETTER U WITH HORN AND TILDE: ữ
+\def\Uhorndotbelow {\char"01EF0 } % LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW: Ự
+\def\uhorndotbelow {\char"01EF1 } % LATIN SMALL LETTER U WITH HORN AND DOT BELOW: ự
+\def\Ygrave {\char"01EF2 } % LATIN CAPITAL LETTER Y WITH GRAVE: Ỳ
+\def\ygrave {\char"01EF3 } % LATIN SMALL LETTER Y WITH GRAVE: ỳ
+\def\Ydotbelow {\char"01EF4 } % LATIN CAPITAL LETTER Y WITH DOT BELOW: Ỵ
+\def\ydotbelow {\char"01EF5 } % LATIN SMALL LETTER Y WITH DOT BELOW: ỵ
+\def\Yhook {\char"01EF6 } % LATIN CAPITAL LETTER Y WITH HOOK ABOVE: Ỷ
+\def\yhook {\char"01EF7 } % LATIN SMALL LETTER Y WITH HOOK ABOVE: ỷ
+\def\Ytilde {\char"01EF8 } % LATIN CAPITAL LETTER Y WITH TILDE: Ỹ
+\def\ytilde {\char"01EF9 } % LATIN SMALL LETTER Y WITH TILDE: ỹ
+\def\greekalphapsili {\char"01F00 } % GREEK SMALL LETTER ALPHA WITH PSILI: ἀ
+\def\greekalphadasia {\char"01F01 } % GREEK SMALL LETTER ALPHA WITH DASIA: ἁ
+\def\greekalphapsilivaria {\char"01F02 } % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA: ἂ
+\def\greekalphadasiavaria {\char"01F03 } % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA: ἃ
+\def\greekalphapsilitonos {\char"01F04 } % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA: ἄ
+\def\greekalphadasiatonos {\char"01F05 } % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA: ἅ
+\def\greekalphapsiliperispomeni {\char"01F06 } % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI: ἆ
+\def\greekalphadasiaperispomeni {\char"01F07 } % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI: ἇ
+\def\greekAlphapsili {\char"01F08 } % GREEK CAPITAL LETTER ALPHA WITH PSILI: Ἀ
+\def\greekAlphadasia {\char"01F09 } % GREEK CAPITAL LETTER ALPHA WITH DASIA: Ἁ
+\def\greekAlphapsilivaria {\char"01F0A } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA: Ἂ
+\def\greekAlphadasiavaria {\char"01F0B } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA: Ἃ
+\def\greekAlphapsilitonos {\char"01F0C } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA: Ἄ
+\def\greekAlphadasiatonos {\char"01F0D } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA: Ἅ
+\def\greekAlphapsiliperispomeni {\char"01F0E } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI: Ἆ
+\def\greekAlphadasiaperispomeni {\char"01F0F } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI: Ἇ
+\def\greekepsilonpsili {\char"01F10 } % GREEK SMALL LETTER EPSILON WITH PSILI: ἐ
+\def\greekepsilondasia {\char"01F11 } % GREEK SMALL LETTER EPSILON WITH DASIA: ἑ
+\def\greekepsilonpsilivaria {\char"01F12 } % GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA: ἒ
+\def\greekepsilondasiavaria {\char"01F13 } % GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA: ἓ
+\def\greekepsilonpsilitonos {\char"01F14 } % GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA: ἔ
+\def\greekepsilondasiatonos {\char"01F15 } % GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA: ἕ
+\def\greekEpsilonpsili {\char"01F18 } % GREEK CAPITAL LETTER EPSILON WITH PSILI: Ἐ
+\def\greekEpsilondasia {\char"01F19 } % GREEK CAPITAL LETTER EPSILON WITH DASIA: Ἑ
+\def\greekEpsilonpsilivaria {\char"01F1A } % GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA: Ἒ
+\def\greekEpsilondasiavaria {\char"01F1B } % GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA: Ἓ
+\def\greekEpsilonpsilitonos {\char"01F1C } % GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA: Ἔ
+\def\greekEpsilondasiatonos {\char"01F1D } % GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA: Ἕ
+\def\greeketapsili {\char"01F20 } % GREEK SMALL LETTER ETA WITH PSILI: ἠ
+\def\greeketadasia {\char"01F21 } % GREEK SMALL LETTER ETA WITH DASIA: ἡ
+\def\greeketapsilivaria {\char"01F22 } % GREEK SMALL LETTER ETA WITH PSILI AND VARIA: ἢ
+\def\greeketadasiavaria {\char"01F23 } % GREEK SMALL LETTER ETA WITH DASIA AND VARIA: ἣ
+\def\greeketapsilitonos {\char"01F24 } % GREEK SMALL LETTER ETA WITH PSILI AND OXIA: ἤ
+\def\greeketadasiatonos {\char"01F25 } % GREEK SMALL LETTER ETA WITH DASIA AND OXIA: ἥ
+\def\greeketapsiliperispomeni {\char"01F26 } % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI: ἦ
+\def\greeketadasiaperispomeni {\char"01F27 } % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI: ἧ
+\def\greekEtapsili {\char"01F28 } % GREEK CAPITAL LETTER ETA WITH PSILI: Ἠ
+\def\greekEtadasia {\char"01F29 } % GREEK CAPITAL LETTER ETA WITH DASIA: Ἡ
+\def\greekEtapsilivaria {\char"01F2A } % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA: Ἢ
+\def\greekEtadasiavaria {\char"01F2B } % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA: Ἣ
+\def\greekEtapsilitonos {\char"01F2C } % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA: Ἤ
+\def\greekEtadasiatonos {\char"01F2D } % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA: Ἥ
+\def\greekEtapsiliperispomeni {\char"01F2E } % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI: Ἦ
+\def\greekEtadasiaperispomeni {\char"01F2F } % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI: Ἧ
+\def\greekiotapsili {\char"01F30 } % GREEK SMALL LETTER IOTA WITH PSILI: ἰ
+\def\greekiotadasia {\char"01F31 } % GREEK SMALL LETTER IOTA WITH DASIA: ἱ
+\def\greekiotapsilivaria {\char"01F32 } % GREEK SMALL LETTER IOTA WITH PSILI AND VARIA: ἲ
+\def\greekiotadasiavaria {\char"01F33 } % GREEK SMALL LETTER IOTA WITH DASIA AND VARIA: ἳ
+\def\greekiotapsilitonos {\char"01F34 } % GREEK SMALL LETTER IOTA WITH PSILI AND OXIA: ἴ
+\def\greekiotadasiatonos {\char"01F35 } % GREEK SMALL LETTER IOTA WITH DASIA AND OXIA: ἵ
+\def\greekiotapsiliperispomeni {\char"01F36 } % GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI: ἶ
+\def\greekiotadasiaperispomeni {\char"01F37 } % GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI: ἷ
+\def\greekIotapsili {\char"01F38 } % GREEK CAPITAL LETTER IOTA WITH PSILI: Ἰ
+\def\greekIotadasia {\char"01F39 } % GREEK CAPITAL LETTER IOTA WITH DASIA: Ἱ
+\def\greekIotapsilivaria {\char"01F3A } % GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA: Ἲ
+\def\greekIotadasiavaria {\char"01F3B } % GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA: Ἳ
+\def\greekIotapsilitonos {\char"01F3C } % GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA: Ἴ
+\def\greekIotadasiatonos {\char"01F3D } % GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA: Ἵ
+\def\greekIotapsiliperispomeni {\char"01F3E } % GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI: Ἶ
+\def\greekIotadasiaperispomeni {\char"01F3F } % GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI: Ἷ
+\def\greekomicronpsili {\char"01F40 } % GREEK SMALL LETTER OMICRON WITH PSILI: ὀ
+\def\greekomicrondasia {\char"01F41 } % GREEK SMALL LETTER OMICRON WITH DASIA: ὁ
+\def\greekomicronpsilivaria {\char"01F42 } % GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA: ὂ
+\def\greekomicrondasiavaria {\char"01F43 } % GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA: ὃ
+\def\greekomicronpsilitonos {\char"01F44 } % GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA: ὄ
+\def\greekomicrondasiatonos {\char"01F45 } % GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA: ὅ
+\def\greekOmicronpsili {\char"01F48 } % GREEK CAPITAL LETTER OMICRON WITH PSILI: Ὀ
+\def\greekOmicrondasia {\char"01F49 } % GREEK CAPITAL LETTER OMICRON WITH DASIA: Ὁ
+\def\greekOmicronpsilivaria {\char"01F4A } % GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA: Ὂ
+\def\greekOmicrondasiavaria {\char"01F4B } % GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA: Ὃ
+\def\greekOmicronpsilitonos {\char"01F4C } % GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA: Ὄ
+\def\greekOmicrondasiatonos {\char"01F4D } % GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA: Ὅ
+\def\greekupsilonpsili {\char"01F50 } % GREEK SMALL LETTER UPSILON WITH PSILI: ὐ
+\def\greekupsilondasia {\char"01F51 } % GREEK SMALL LETTER UPSILON WITH DASIA: ὑ
+\def\greekupsilonpsilivaria {\char"01F52 } % GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA: ὒ
+\def\greekupsilondasiavaria {\char"01F53 } % GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA: ὓ
+\def\greekupsilonpsilitonos {\char"01F54 } % GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA: ὔ
+\def\greekupsilondasiatonos {\char"01F55 } % GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA: ὕ
+\def\greekupsilonpsiliperispomeni {\char"01F56 } % GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI: ὖ
+\def\greekupsilondasiaperispomeni {\char"01F57 } % GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI: ὗ
+\def\greekUpsilondasia {\char"01F59 } % GREEK CAPITAL LETTER UPSILON WITH DASIA: Ὑ
+\def\greekUpsilondasiavaria {\char"01F5B } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA: Ὓ
+\def\greekUpsilondasiatonos {\char"01F5D } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA: Ὕ
+\def\greekUpsilondasiaperispomeni {\char"01F5F } % GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI: Ὗ
+\def\greekomegapsili {\char"01F60 } % GREEK SMALL LETTER OMEGA WITH PSILI: ὠ
+\def\greekomegadasia {\char"01F61 } % GREEK SMALL LETTER OMEGA WITH DASIA: ὡ
+\def\greekomegapsilivaria {\char"01F62 } % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA: ὢ
+\def\greekomegadasiavaria {\char"01F63 } % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA: ὣ
+\def\greekomegapsilitonos {\char"01F64 } % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA: ὤ
+\def\greekomegadasiatonos {\char"01F65 } % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA: ὥ
+\def\greekomegapsiliperispomeni {\char"01F66 } % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI: ὦ
+\def\greekomegadasiaperispomeni {\char"01F67 } % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI: ὧ
+\def\greekOmegapsili {\char"01F68 } % GREEK CAPITAL LETTER OMEGA WITH PSILI: Ὠ
+\def\greekOmegadasia {\char"01F69 } % GREEK CAPITAL LETTER OMEGA WITH DASIA: Ὡ
+\def\greekOmegapsilivaria {\char"01F6A } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA: Ὢ
+\def\greekOmegadasiavaria {\char"01F6B } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA: Ὣ
+\def\greekOmegapsilitonos {\char"01F6C } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA: Ὤ
+\def\greekOmegadasiatonos {\char"01F6D } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA: Ὥ
+\def\greekOmegapsiliperispomeni {\char"01F6E } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI: Ὦ
+\def\greekOmegadasiaperispomeni {\char"01F6F } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI: Ὧ
+\def\greekalphavaria {\char"01F70 } % GREEK SMALL LETTER ALPHA WITH VARIA: ὰ
+\def\greekalphaoxia {\char"01F71 } % GREEK SMALL LETTER ALPHA WITH OXIA: ά
+\def\greekepsilonvaria {\char"01F72 } % GREEK SMALL LETTER EPSILON WITH VARIA: ὲ
+\def\greekepsilonoxia {\char"01F73 } % GREEK SMALL LETTER EPSILON WITH OXIA: έ
+\def\greeketavaria {\char"01F74 } % GREEK SMALL LETTER ETA WITH VARIA: ὴ
+\def\greeketaoxia {\char"01F75 } % GREEK SMALL LETTER ETA WITH OXIA: ή
+\def\greekiotavaria {\char"01F76 } % GREEK SMALL LETTER IOTA WITH VARIA: ὶ
+\def\greekiotaoxia {\char"01F77 } % GREEK SMALL LETTER IOTA WITH OXIA: ί
+\def\greekomicronvaria {\char"01F78 } % GREEK SMALL LETTER OMICRON WITH VARIA: ὸ
+\def\greekomicronoxia {\char"01F79 } % GREEK SMALL LETTER OMICRON WITH OXIA: ό
+\def\greekupsilonvaria {\char"01F7A } % GREEK SMALL LETTER UPSILON WITH VARIA: ὺ
+\def\greekupsilonoxia {\char"01F7B } % GREEK SMALL LETTER UPSILON WITH OXIA: ύ
+\def\greekomegavaria {\char"01F7C } % GREEK SMALL LETTER OMEGA WITH VARIA: ὼ
+\def\greekomegaoxia {\char"01F7D } % GREEK SMALL LETTER OMEGA WITH OXIA: ώ
+\def\greekalphaiotasubpsili {\char"01F80 } % GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI: ᾀ
+\def\greekalphaiotasubdasia {\char"01F81 } % GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI: ᾁ
+\def\greekalphaiotasubpsilivaria {\char"01F82 } % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾂ
+\def\greekalphaiotasubdasiavaria {\char"01F83 } % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾃ
+\def\greekalphaiotasubpsilitonos {\char"01F84 } % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾄ
+\def\greekalphaiotasubdasiatonos {\char"01F85 } % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾅ
+\def\greekalphaiotasubpsiliperispomeni{\char"01F86 } % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾆ
+\def\greekalphaiotasubdasiaperispomeni{\char"01F87 } % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾇ
+\def\greekAlphaiotasubpsili {\char"01F88 } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI: ᾈ
+\def\greekAlphaiotasubdasia {\char"01F89 } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI: ᾉ
+\def\greekAlphaiotasubpsilivaria {\char"01F8A } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾊ
+\def\greekAlphaiotasubdasiavaria {\char"01F8B } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾋ
+\def\greekAlphaiotasubpsilitonos {\char"01F8C } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾌ
+\def\greekAlphaiotasubdasiatonos {\char"01F8D } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾍ
+\def\greekAlphaiotasubpsiliperispomeni{\char"01F8E } % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾎ
+\def\greekAlphaiotasubdasiaperispomeni{\char"01F8F } % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾏ
+\def\greeketaiotasubpsili {\char"01F90 } % GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI: ᾐ
+\def\greeketaiotasubdasia {\char"01F91 } % GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI: ᾑ
+\def\greeketaiotasubpsilivaria {\char"01F92 } % GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾒ
+\def\greeketaiotasubdasiavaria {\char"01F93 } % GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾓ
+\def\greeketaiotasubpsilitonos {\char"01F94 } % GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾔ
+\def\greeketaiotasubdasiatonos {\char"01F95 } % GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾕ
+\def\greeketaiotasubpsiliperispomeni {\char"01F96 } % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾖ
+\def\greeketaiotasubdasiaperispomeni {\char"01F97 } % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾗ
+\def\greekEtaiotasubpsili {\char"01F98 } % GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI: ᾘ
+\def\greekEtaiotasubdasia {\char"01F99 } % GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI: ᾙ
+\def\greekEtaiotasubpsilivaria {\char"01F9A } % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾚ
+\def\greekEtaiotasubdasiavaria {\char"01F9B } % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾛ
+\def\greekEtaiotasubpsilitonos {\char"01F9C } % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾜ
+\def\greekEtaiotasubdasiatonos {\char"01F9D } % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾝ
+\def\greekEtaiotasubpsiliperispomeni {\char"01F9E } % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾞ
+\def\greekEtaiotasubdasiaperispomeni {\char"01F9F } % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾟ
+\def\greekomegaiotasubpsili {\char"01FA0 } % GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI: ᾠ
+\def\greekomegaiotasubdasia {\char"01FA1 } % GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI: ᾡ
+\def\greekomegaiotasubpsilivaria {\char"01FA2 } % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI: ᾢ
+\def\greekomegaiotasubdasiavaria {\char"01FA3 } % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI: ᾣ
+\def\greekomegaiotasubpsilitonos {\char"01FA4 } % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI: ᾤ
+\def\greekomegaiotasubdasiatonos {\char"01FA5 } % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI: ᾥ
+\def\greekomegaiotasubpsiliperispomeni{\char"01FA6 } % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI: ᾦ
+\def\greekomegaiotasubdasiaperispomeni{\char"01FA7 } % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI: ᾧ
+\def\greekOmegaiotasubpsili {\char"01FA8 } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI: ᾨ
+\def\greekOmegaiotasubdasia {\char"01FA9 } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI: ᾩ
+\def\greekOmegaiotasubpsilivaria {\char"01FAA } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI: ᾪ
+\def\greekOmegaiotasubdasiavaria {\char"01FAB } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI: ᾫ
+\def\greekOmegaiotasubpsilitonos {\char"01FAC } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI: ᾬ
+\def\greekOmegaiotasubdasiatonos {\char"01FAD } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI: ᾭ
+\def\greekOmegaiotasubpsiliperispomeni{\char"01FAE } % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI: ᾮ
+\def\greekOmegaiotasubdasiaperispomeni{\char"01FAF } % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI: ᾯ
+\def\greekalphavrachy {\char"01FB0 } % GREEK SMALL LETTER ALPHA WITH VRACHY: ᾰ
+\def\greekalphamacron {\char"01FB1 } % GREEK SMALL LETTER ALPHA WITH MACRON: ᾱ
+\def\greekalphaiotasubvaria {\char"01FB2 } % GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI: ᾲ
+\def\greekalphaiotasub {\char"01FB3 } % GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI: ᾳ
+\def\greekalphaiotasubtonos {\char"01FB4 } % GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI: ᾴ
+\def\greekalphaperispomeni {\char"01FB6 } % GREEK SMALL LETTER ALPHA WITH PERISPOMENI: ᾶ
+\def\greekalphaiotasubperispomeni {\char"01FB7 } % GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI: ᾷ
+\def\greekAlphavrachy {\char"01FB8 } % GREEK CAPITAL LETTER ALPHA WITH VRACHY: Ᾰ
+\def\greekAlphamacron {\char"01FB9 } % GREEK CAPITAL LETTER ALPHA WITH MACRON: Ᾱ
+\def\greekAlphavaria {\char"01FBA } % GREEK CAPITAL LETTER ALPHA WITH VARIA: Ὰ
+\def\greekAlphatonos {\char"01FBB } % GREEK CAPITAL LETTER ALPHA WITH OXIA: Ά
+\def\greekAlphaiotasub {\char"01FBC } % GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI: ᾼ
+\def\greekCoronis {\char"01FBD } % GREEK KORONIS: ᾽
+\def\greekprosgegrammeni {\char"01FBE } % GREEK PROSGEGRAMMENI: ι
+\def\greekpsili {\char"01FBF } % GREEK PSILI: ᾿
+\def\greekperispomeni {\char"01FC0 } % GREEK PERISPOMENI: ῀
+\def\greekdialytikaperispomeni {\char"01FC1 } % GREEK DIALYTIKA AND PERISPOMENI: ῁
+\def\greeketaiotasubvaria {\char"01FC2 } % GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI: ῂ
+\def\greeketaiotasub {\char"01FC3 } % GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI: ῃ
+\def\greeketaiotasubtonos {\char"01FC4 } % GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI: ῄ
+\def\greeketaperispomeni {\char"01FC6 } % GREEK SMALL LETTER ETA WITH PERISPOMENI: ῆ
+\def\greeketaiotasubperispomeni {\char"01FC7 } % GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI: ῇ
+\def\greekEpsilonvaria {\char"01FC8 } % GREEK CAPITAL LETTER EPSILON WITH VARIA: Ὲ
+\def\greekEpsilontonos {\char"01FC9 } % GREEK CAPITAL LETTER EPSILON WITH OXIA: Έ
+\def\greekEtavaria {\char"01FCA } % GREEK CAPITAL LETTER ETA WITH VARIA: Ὴ
+\def\greekEtatonos {\char"01FCB } % GREEK CAPITAL LETTER ETA WITH OXIA: Ή
+\def\greekEtaiotasub {\char"01FCC } % GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI: ῌ
+\def\greekpsilivaria {\char"01FCD } % GREEK PSILI AND VARIA: ῍
+\def\greekpsilitonos {\char"01FCE } % GREEK PSILI AND OXIA: ῎
+\def\greekpsiliperispomeni {\char"01FCF } % GREEK PSILI AND PERISPOMENI: ῏
+\def\greekiotavrachy {\char"01FD0 } % GREEK SMALL LETTER IOTA WITH VRACHY: ῐ
+\def\greekiotamacron {\char"01FD1 } % GREEK SMALL LETTER IOTA WITH MACRON: ῑ
+\def\greekiotadialytikavaria {\char"01FD2 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA: ῒ
+\def\greekiotadialytikatonos {\char"01FD3 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA: ΐ
+\def\greekiotaperispomeni {\char"01FD6 } % GREEK SMALL LETTER IOTA WITH PERISPOMENI: ῖ
+\def\greekiotadialytikaperispomeni {\char"01FD7 } % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI: ῗ
+\def\greekIotavrachy {\char"01FD8 } % GREEK CAPITAL LETTER IOTA WITH VRACHY: Ῐ
+\def\greekIotamacron {\char"01FD9 } % GREEK CAPITAL LETTER IOTA WITH MACRON: Ῑ
+\def\greekIotavaria {\char"01FDA } % GREEK CAPITAL LETTER IOTA WITH VARIA: Ὶ
+\def\greekIotatonos {\char"01FDB } % GREEK CAPITAL LETTER IOTA WITH OXIA: Ί
+\def\greekdasiavaria {\char"01FDD } % GREEK DASIA AND VARIA: ῝
+\def\greekdasiatonos {\char"01FDE } % GREEK DASIA AND OXIA: ῞
+\def\greekdasiaperispomeni {\char"01FDF } % GREEK DASIA AND PERISPOMENI: ῟
+\def\greekupsilonvrachy {\char"01FE0 } % GREEK SMALL LETTER UPSILON WITH VRACHY: ῠ
+\def\greekupsilonmacron {\char"01FE1 } % GREEK SMALL LETTER UPSILON WITH MACRON: ῡ
+\def\greekupsilondialytikavaria {\char"01FE2 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA: ῢ
+\def\greekupsilondialytikatonos {\char"01FE3 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA: ΰ
+\def\greekrhopsili {\char"01FE4 } % GREEK SMALL LETTER RHO WITH PSILI: ῤ
+\def\greekrhodasia {\char"01FE5 } % GREEK SMALL LETTER RHO WITH DASIA: ῥ
+\def\greekupsilonperispomeni {\char"01FE6 } % GREEK SMALL LETTER UPSILON WITH PERISPOMENI: ῦ
+\def\greekupsilondialytikaperispomeni {\char"01FE7 } % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI: ῧ
+\def\greekUpsilonvrachy {\char"01FE8 } % GREEK CAPITAL LETTER UPSILON WITH VRACHY: Ῠ
+\def\greekUpsilonmacron {\char"01FE9 } % GREEK CAPITAL LETTER UPSILON WITH MACRON: Ῡ
+\def\greekUpsilonvaria {\char"01FEA } % GREEK CAPITAL LETTER UPSILON WITH VARIA: Ὺ
+\def\greekUpsilontonos {\char"01FEB } % GREEK CAPITAL LETTER UPSILON WITH OXIA: Ύ
+\def\greekRhodasia {\char"01FEC } % GREEK CAPITAL LETTER RHO WITH DASIA: Ῥ
+\def\greekdialytikavaria {\char"01FED } % GREEK DIALYTIKA AND VARIA: ῭
+\def\greekdialytikatonos {\char"01FEE } % GREEK DIALYTIKA AND OXIA: ΅
+\def\greekvaria {\char"01FEF } % GREEK VARIA: `
+\def\greekomegaiotasubvaria {\char"01FF2 } % GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI: ῲ
+\def\greekomegaiotasub {\char"01FF3 } % GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI: ῳ
+\def\greekomegaiotasubtonos {\char"01FF4 } % GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI: ῴ
+\def\greekomegaperispomeni {\char"01FF6 } % GREEK SMALL LETTER OMEGA WITH PERISPOMENI: ῶ
+\def\greekomegaiotasubperispomeni {\char"01FF7 } % GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI: ῷ
+\def\greekOmicronvaria {\char"01FF8 } % GREEK CAPITAL LETTER OMICRON WITH VARIA: Ὸ
+\def\greekOmicrontonos {\char"01FF9 } % GREEK CAPITAL LETTER OMICRON WITH OXIA: Ό
+\def\greekOmegavaria {\char"01FFA } % GREEK CAPITAL LETTER OMEGA WITH VARIA: Ὼ
+\def\greekOmegatonos {\char"01FFB } % GREEK CAPITAL LETTER OMEGA WITH OXIA: Ώ
+\def\greekOmegaiotasub {\char"01FFC } % GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI: ῼ
+\def\greekoxia {\char"01FFD } % GREEK OXIA: ´
+\def\greekdasia {\char"01FFE } % GREEK DASIA: ῾
+\def\enspace {\char"02002 } % EN SPACE:  
+\def\emspace {\char"02003 } % EM SPACE:  
+\def\threeperemspace {\char"02004 } % THREE-PER-EM SPACE:  
+\def\fourperemspace {\char"02005 } % FOUR-PER-EM SPACE:  
+\def\sixperemspace {\char"02006 } % SIX-PER-EM SPACE:  
+\def\figurespace {\char"02007 } % FIGURE SPACE:  
+\def\punctuationspace {\char"02008 } % PUNCTUATION SPACE:  
+\def\thinspace {\char"02009 } % THIN SPACE:  
+\def\figurespace {\char"0200A } % HAIR SPACE:  
+\def\zerowidthspace {\char"0200B } % ZERO WIDTH SPACE: ​
+\def\textminus {\char"02012 } % FIGURE DASH: ‒
+\def\endash {\char"02013 } % EN DASH: –
+\def\emdash {\char"02014 } % EM DASH: —
+\def\texthorizontalbar {\char"02015 } % HORIZONTAL BAR: ―
+\def\quoteleft {\char"02018 } % LEFT SINGLE QUOTATION MARK: ‘
+\def\quoteright {\char"02019 } % RIGHT SINGLE QUOTATION MARK: ’
+\def\quotesinglebase {\char"0201A } % SINGLE LOW-0x0009 QUOTATION MARK: ‚
+\def\quotedblleft {\char"0201C } % LEFT DOUBLE QUOTATION MARK: “
+\def\quotedblright {\char"0201D } % RIGHT DOUBLE QUOTATION MARK: ”
+\def\quotedblbase {\char"0201E } % DOUBLE LOW-0x0009 QUOTATION MARK: „
+\def\textdag {\char"02020 } % DAGGER: †
+\def\textddag {\char"02021 } % DOUBLE DAGGER: ‡
+\def\textbullet {\char"02022 } % BULLET: •
+\def\textellipsis {\char"02026 } % HORIZONTAL ELLIPSIS: …
+\def\narrownobreakspace {\char"0202F } % NARROW NO-BREAK SPACE:  
+\def\perthousand {\char"02030 } % PER MILLE SIGN: ‰
+\def\guilsingleleft {\char"02039 } % SINGLE LEFT-POINTING ANGLE QUOTATION MARK: ‹
+\def\guilsingleright {\char"0203A } % SINGLE RIGHT-POINTING ANGLE QUOTATION MARK: ›
+\def\textfraction {\char"02044 } % FRACTION SLASH: ⁄
+\def\medspace {\char"0205F } % MEDIUM MATHEMATICAL SPACE:  
+\def\textdong {\char"020AB } % DONG SIGN: ₫
+\def\texteuro {\char"020AC } % EURO SIGN: €
+\def\textcelsius {\char"02103 } % DEGREE CELSIUS: ℃
+\def\textnumero {\char"02116 } % NUMERO SIGN: №
+\def\textcircledP {\char"02117 } % SOUND RECORDING COPYRIGHT: ℗
+\def\trademark {\char"02122 } % TRADE MARK SIGN: ™
+\def\textounce {\char"02125 } % OUNCE SIGN: ℥
+\def\textohm {\char"02126 } % OHM SIGN: Ω
+\def\textmho {\char"02127 } % INVERTED OHM SIGN: ℧
+\def\textkelvin {\char"0212A } % KELVIN SIGN: K
+\def\textAngstrom {\char"0212B } % ANGSTROM SIGN: Å
+\def\onethird {\char"02153 } % VULGAR FRACTION ONE THIRD: ⅓
+\def\twothirds {\char"02154 } % VULGAR FRACTION TWO THIRDS: ⅔
+\def\onefifth {\char"02155 } % VULGAR FRACTION ONE FIFTH: ⅕
+\def\twofifths {\char"02156 } % VULGAR FRACTION TWO FIFTHS: ⅖
+\def\threefifths {\char"02157 } % VULGAR FRACTION THREE FIFTHS: ⅗
+\def\fourfifths {\char"02158 } % VULGAR FRACTION FOUR FIFTHS: ⅘
+\def\onesixth {\char"02159 } % VULGAR FRACTION ONE SIXTH: ⅙
+\def\fivesixths {\char"0215A } % VULGAR FRACTION FIVE SIXTHS: ⅚
+\def\oneeighth {\char"0215B } % VULGAR FRACTION ONE EIGHTH: ⅛
+\def\threeeighths {\char"0215C } % VULGAR FRACTION THREE EIGHTHS: ⅜
+\def\fiveeighths {\char"0215D } % VULGAR FRACTION FIVE EIGHTHS: ⅝
+\def\seveneighths {\char"0215E } % VULGAR FRACTION SEVEN EIGHTHS: ⅞
+\def\romanI {\char"02160 } % ROMAN NUMERAL ONE: Ⅰ
+\def\romanII {\char"02161 } % ROMAN NUMERAL TWO: Ⅱ
+\def\romanIII {\char"02162 } % ROMAN NUMERAL THREE: Ⅲ
+\def\romanIV {\char"02163 } % ROMAN NUMERAL FOUR: Ⅳ
+\def\romanV {\char"02164 } % ROMAN NUMERAL FIVE: Ⅴ
+\def\romanVI {\char"02165 } % ROMAN NUMERAL SIX: Ⅵ
+\def\romanVII {\char"02166 } % ROMAN NUMERAL SEVEN: Ⅶ
+\def\romanVIII {\char"02167 } % ROMAN NUMERAL EIGHT: Ⅷ
+\def\romanIX {\char"02168 } % ROMAN NUMERAL NINE: Ⅸ
+\def\romanX {\char"02169 } % ROMAN NUMERAL TEN: Ⅹ
+\def\romanXI {\char"0216A } % ROMAN NUMERAL ELEVEN: Ⅺ
+\def\romanXII {\char"0216B } % ROMAN NUMERAL TWELVE: Ⅻ
+\def\romanL {\char"0216C } % ROMAN NUMERAL FIFTY: Ⅼ
+\def\romanC {\char"0216D } % ROMAN NUMERAL ONE HUNDRED: Ⅽ
+\def\romanD {\char"0216E } % ROMAN NUMERAL FIVE HUNDRED: Ⅾ
+\def\romanM {\char"0216F } % ROMAN NUMERAL ONE THOUSAND: Ⅿ
+\def\romani {\char"02170 } % SMALL ROMAN NUMERAL ONE: ⅰ
+\def\romanii {\char"02171 } % SMALL ROMAN NUMERAL TWO: ⅱ
+\def\romaniii {\char"02172 } % SMALL ROMAN NUMERAL THREE: ⅲ
+\def\romaniv {\char"02173 } % SMALL ROMAN NUMERAL FOUR: ⅳ
+\def\romanv {\char"02174 } % SMALL ROMAN NUMERAL FIVE: ⅴ
+\def\romanvi {\char"02175 } % SMALL ROMAN NUMERAL SIX: ⅵ
+\def\romanvii {\char"02176 } % SMALL ROMAN NUMERAL SEVEN: ⅶ
+\def\romanviii {\char"02177 } % SMALL ROMAN NUMERAL EIGHT: ⅷ
+\def\romanix {\char"02178 } % SMALL ROMAN NUMERAL NINE: ⅸ
+\def\romanx {\char"02179 } % SMALL ROMAN NUMERAL TEN: ⅹ
+\def\romanxi {\char"0217A } % SMALL ROMAN NUMERAL ELEVEN: ⅺ
+\def\romanxii {\char"0217B } % SMALL ROMAN NUMERAL TWELVE: ⅻ
+\def\romanl {\char"0217C } % SMALL ROMAN NUMERAL FIFTY: ⅼ
+\def\romanc {\char"0217D } % SMALL ROMAN NUMERAL ONE HUNDRED: ⅽ
+\def\romand {\char"0217E } % SMALL ROMAN NUMERAL FIVE HUNDRED: ⅾ
+\def\romanm {\char"0217F } % SMALL ROMAN NUMERAL ONE THOUSAND: ⅿ
+\def\carriagereturn {\char"021B5 } % DOWNWARDS ARROW WITH CORNER LEFTWARDS: ↵
+\def\ideographicspace {\char"03000 } % IDEOGRAPHIC SPACE:  
+\def\ideographichalffillspace {\char"0303F } % IDEOGRAPHIC HALF FILL SPACE: 〿
+\def\ffligature {\char"0FB00 } % LATIN SMALL LIGATURE FF: ff
+\def\filigature {\char"0FB01 } % LATIN SMALL LIGATURE FI: fi
+\def\flligature {\char"0FB02 } % LATIN SMALL LIGATURE FL: fl
+\def\ffiligature {\char"0FB03 } % LATIN SMALL LIGATURE FFI: ffi
+\def\fflligature {\char"0FB04 } % LATIN SMALL LIGATURE FFL: ffl
+\def\stligature {\char"0FB06 } % LATIN SMALL LIGATURE ST: st
+\def\zerowidthnobreakspace {\char"0FEFF } % ZERO WIDTH NO-BREAK SPACE: 
+
+\endinput
diff --git a/tex/context/base/xetx-cls.tex b/tex/context/base/xetx-cls.tex
new file mode 100644
index 000000000..6ce696f71
--- /dev/null
+++ b/tex/context/base/xetx-cls.tex
@@ -0,0 +1,378 @@
+% filename : xetx-cls.tex
+% comment : generated by mtxrun --script chars --xtx
+% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+% copyright: PRAGMA ADE / ConTeXt Development Team
+% license : see context related readme files
+
+% some character classes for xetex; seems to be rather hard coded, these numbers
+% and also a mix of several classes; here we do linebreaks
+
+\defineXTXcharinjectionclass[lb:cl]
+\defineXTXcharinjectionclass[lb:ex]
+\defineXTXcharinjectionclass[lb:ns]
+\defineXTXcharinjectionclass[lb:id]
+\defineXTXcharinjectionclass[lb:op]
+\defineXTXcharinjectionclass[lb:cm]
+\defineXTXcharinjectionclass[lb:is]
+
+\dofastrecurse{"00000}{"00008}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0000E}{"0001F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00021}{lb:ex}
+\dosetXTXcharacterclass{"00028}{lb:op}
+\dosetXTXcharacterclass{"00029}{lb:cl}
+\dosetXTXcharacterclass{"0002C}{lb:is}
+\dosetXTXcharacterclass{"0002E}{lb:is}
+\dofastrecurse{"0003A}{"0003B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:is}}
+\dosetXTXcharacterclass{"0003F}{lb:ex}
+\dosetXTXcharacterclass{"0005B}{lb:op}
+\dosetXTXcharacterclass{"0005D}{lb:cl}
+\dosetXTXcharacterclass{"0007B}{lb:op}
+\dosetXTXcharacterclass{"0007D}{lb:cl}
+\dofastrecurse{"0007F}{"00084}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00086}{"0009F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00300}{"0034E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00350}{"0035B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00363}{"0036F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0037E}{lb:is}
+\dofastrecurse{"00483}{"00489}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00589}{lb:is}
+\dofastrecurse{"00591}{"005BD}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"005BF}{lb:cm}
+\dofastrecurse{"005C1}{"005C2}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"005C4}{"005C5}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"005C6}{lb:ex}
+\dosetXTXcharacterclass{"005C7}{lb:cm}
+\dosetXTXcharacterclass{"0060C}{lb:ex}
+\dosetXTXcharacterclass{"0060D}{lb:is}
+\dofastrecurse{"00610}{"00615}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0061B}{"0061F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dofastrecurse{"0064B}{"0065E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0066A}{lb:ex}
+\dosetXTXcharacterclass{"00670}{lb:cm}
+\dosetXTXcharacterclass{"006D4}{lb:ex}
+\dofastrecurse{"006D6}{"006DC}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"006DE}{"006E4}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"006E7}{"006E8}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"006EA}{"006ED}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00711}{lb:cm}
+\dofastrecurse{"00730}{"0074A}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"007A6}{"007B0}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"007EB}{"007F3}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"007F8}{lb:is}
+\dosetXTXcharacterclass{"007F9}{lb:ex}
+\dofastrecurse{"00901}{"00903}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0093C}{lb:cm}
+\dofastrecurse{"0093E}{"0094D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00951}{"00954}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00962}{"00963}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00981}{"00983}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"009BC}{lb:cm}
+\dofastrecurse{"009BE}{"009CD}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"009D7}{lb:cm}
+\dofastrecurse{"009E2}{"009E3}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00A01}{"00A03}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00A3C}{"00A4D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00A70}{"00A71}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00A81}{"00A83}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00ABC}{lb:cm}
+\dofastrecurse{"00ABE}{"00ACD}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00AE2}{"00AE3}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00B01}{"00B03}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00B3C}{lb:cm}
+\dofastrecurse{"00B3E}{"00B57}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00B82}{lb:cm}
+\dofastrecurse{"00BBE}{"00BD7}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00C01}{"00C03}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00C3E}{"00C56}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00C82}{"00C83}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00CBC}{lb:cm}
+\dofastrecurse{"00CBE}{"00CD6}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00CE2}{"00CE3}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00D02}{"00D03}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00D3E}{"00D57}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00D82}{"00D83}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00DCA}{"00DF3}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00F0D}{"00F11}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dosetXTXcharacterclass{"00F14}{lb:ex}
+\dofastrecurse{"00F18}{"00F19}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00F35}{lb:cm}
+\dosetXTXcharacterclass{"00F37}{lb:cm}
+\dosetXTXcharacterclass{"00F39}{lb:cm}
+\dosetXTXcharacterclass{"00F3A}{lb:op}
+\dosetXTXcharacterclass{"00F3B}{lb:cl}
+\dosetXTXcharacterclass{"00F3C}{lb:op}
+\dosetXTXcharacterclass{"00F3D}{lb:cl}
+\dofastrecurse{"00F3E}{"00F3F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00F71}{"00F7E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00F80}{"00F84}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00F86}{"00F87}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"00F90}{"00FBC}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"00FC6}{lb:cm}
+\dosetXTXcharacterclass{"0135F}{lb:cm}
+\dosetXTXcharacterclass{"0169B}{lb:op}
+\dosetXTXcharacterclass{"0169C}{lb:cl}
+\dofastrecurse{"01712}{"01714}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01732}{"01734}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01752}{"01753}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01772}{"01773}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"017D6}{lb:ns}
+\dofastrecurse{"0180B}{"0180D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"018A9}{lb:cm}
+\dofastrecurse{"01920}{"0193B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01944}{"01945}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dofastrecurse{"01A17}{"01A1B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01B00}{"01B04}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01B34}{"01B44}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01B6B}{"01B73}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"01DC0}{"01DFF}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0200C}{"0200F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0201A}{lb:op}
+\dosetXTXcharacterclass{"0201E}{lb:op}
+\dofastrecurse{"0202A}{"0202E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0203C}{"0203D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dosetXTXcharacterclass{"02044}{lb:is}
+\dosetXTXcharacterclass{"02045}{lb:op}
+\dosetXTXcharacterclass{"02046}{lb:cl}
+\dofastrecurse{"02047}{"02049}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0206A}{"0206F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0207D}{lb:op}
+\dosetXTXcharacterclass{"0207E}{lb:cl}
+\dosetXTXcharacterclass{"0208D}{lb:op}
+\dosetXTXcharacterclass{"0208E}{lb:cl}
+\dofastrecurse{"020D0}{"020EF}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"02329}{lb:op}
+\dosetXTXcharacterclass{"0232A}{lb:cl}
+\dofastrecurse{"02762}{"02763}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dosetXTXcharacterclass{"02768}{lb:op}
+\dosetXTXcharacterclass{"02769}{lb:cl}
+\dosetXTXcharacterclass{"0276A}{lb:op}
+\dosetXTXcharacterclass{"0276B}{lb:cl}
+\dosetXTXcharacterclass{"0276C}{lb:op}
+\dosetXTXcharacterclass{"0276D}{lb:cl}
+\dosetXTXcharacterclass{"0276E}{lb:op}
+\dosetXTXcharacterclass{"0276F}{lb:cl}
+\dosetXTXcharacterclass{"02770}{lb:op}
+\dosetXTXcharacterclass{"02771}{lb:cl}
+\dosetXTXcharacterclass{"02772}{lb:op}
+\dosetXTXcharacterclass{"02773}{lb:cl}
+\dosetXTXcharacterclass{"02774}{lb:op}
+\dosetXTXcharacterclass{"02775}{lb:cl}
+\dosetXTXcharacterclass{"027C5}{lb:op}
+\dosetXTXcharacterclass{"027C6}{lb:cl}
+\dosetXTXcharacterclass{"027E6}{lb:op}
+\dosetXTXcharacterclass{"027E7}{lb:cl}
+\dosetXTXcharacterclass{"027E8}{lb:op}
+\dosetXTXcharacterclass{"027E9}{lb:cl}
+\dosetXTXcharacterclass{"027EA}{lb:op}
+\dosetXTXcharacterclass{"027EB}{lb:cl}
+\dosetXTXcharacterclass{"02983}{lb:op}
+\dosetXTXcharacterclass{"02984}{lb:cl}
+\dosetXTXcharacterclass{"02985}{lb:op}
+\dosetXTXcharacterclass{"02986}{lb:cl}
+\dosetXTXcharacterclass{"02987}{lb:op}
+\dosetXTXcharacterclass{"02988}{lb:cl}
+\dosetXTXcharacterclass{"02989}{lb:op}
+\dosetXTXcharacterclass{"0298A}{lb:cl}
+\dosetXTXcharacterclass{"0298B}{lb:op}
+\dosetXTXcharacterclass{"0298C}{lb:cl}
+\dosetXTXcharacterclass{"0298D}{lb:op}
+\dosetXTXcharacterclass{"0298E}{lb:cl}
+\dosetXTXcharacterclass{"0298F}{lb:op}
+\dosetXTXcharacterclass{"02990}{lb:cl}
+\dosetXTXcharacterclass{"02991}{lb:op}
+\dosetXTXcharacterclass{"02992}{lb:cl}
+\dosetXTXcharacterclass{"02993}{lb:op}
+\dosetXTXcharacterclass{"02994}{lb:cl}
+\dosetXTXcharacterclass{"02995}{lb:op}
+\dosetXTXcharacterclass{"02996}{lb:cl}
+\dosetXTXcharacterclass{"02997}{lb:op}
+\dosetXTXcharacterclass{"02998}{lb:cl}
+\dosetXTXcharacterclass{"029D8}{lb:op}
+\dosetXTXcharacterclass{"029D9}{lb:cl}
+\dosetXTXcharacterclass{"029DA}{lb:op}
+\dosetXTXcharacterclass{"029DB}{lb:cl}
+\dosetXTXcharacterclass{"029FC}{lb:op}
+\dosetXTXcharacterclass{"029FD}{lb:cl}
+\dofastrecurse{"02E80}{"03000}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"03001}{"03002}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cl}}
+\dofastrecurse{"03003}{"03004}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03005}{lb:ns}
+\dofastrecurse{"03006}{"03007}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03008}{lb:op}
+\dosetXTXcharacterclass{"03009}{lb:cl}
+\dosetXTXcharacterclass{"0300A}{lb:op}
+\dosetXTXcharacterclass{"0300B}{lb:cl}
+\dosetXTXcharacterclass{"0300C}{lb:op}
+\dosetXTXcharacterclass{"0300D}{lb:cl}
+\dosetXTXcharacterclass{"0300E}{lb:op}
+\dosetXTXcharacterclass{"0300F}{lb:cl}
+\dosetXTXcharacterclass{"03010}{lb:op}
+\dosetXTXcharacterclass{"03011}{lb:cl}
+\dofastrecurse{"03012}{"03013}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03014}{lb:op}
+\dosetXTXcharacterclass{"03015}{lb:cl}
+\dosetXTXcharacterclass{"03016}{lb:op}
+\dosetXTXcharacterclass{"03017}{lb:cl}
+\dosetXTXcharacterclass{"03018}{lb:op}
+\dosetXTXcharacterclass{"03019}{lb:cl}
+\dosetXTXcharacterclass{"0301A}{lb:op}
+\dosetXTXcharacterclass{"0301B}{lb:cl}
+\dosetXTXcharacterclass{"0301C}{lb:ns}
+\dosetXTXcharacterclass{"0301D}{lb:op}
+\dofastrecurse{"0301E}{"0301F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cl}}
+\dofastrecurse{"03020}{"03029}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"0302A}{"0302F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"03030}{"0303A}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"0303B}{"0303C}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0303D}{"0303F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03041}{lb:ns}
+\dosetXTXcharacterclass{"03042}{lb:id}
+\dosetXTXcharacterclass{"03043}{lb:ns}
+\dosetXTXcharacterclass{"03044}{lb:id}
+\dosetXTXcharacterclass{"03045}{lb:ns}
+\dosetXTXcharacterclass{"03046}{lb:id}
+\dosetXTXcharacterclass{"03047}{lb:ns}
+\dosetXTXcharacterclass{"03048}{lb:id}
+\dosetXTXcharacterclass{"03049}{lb:ns}
+\dofastrecurse{"0304A}{"03062}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03063}{lb:ns}
+\dofastrecurse{"03064}{"03082}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"03083}{lb:ns}
+\dosetXTXcharacterclass{"03084}{lb:id}
+\dosetXTXcharacterclass{"03085}{lb:ns}
+\dosetXTXcharacterclass{"03086}{lb:id}
+\dosetXTXcharacterclass{"03087}{lb:ns}
+\dofastrecurse{"03088}{"0308D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0308E}{lb:ns}
+\dofastrecurse{"0308F}{"03094}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"03095}{"03096}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"03099}{"0309A}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0309B}{"0309E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dosetXTXcharacterclass{"0309F}{lb:id}
+\dofastrecurse{"030A0}{"030A1}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dosetXTXcharacterclass{"030A2}{lb:id}
+\dosetXTXcharacterclass{"030A3}{lb:ns}
+\dosetXTXcharacterclass{"030A4}{lb:id}
+\dosetXTXcharacterclass{"030A5}{lb:ns}
+\dosetXTXcharacterclass{"030A6}{lb:id}
+\dosetXTXcharacterclass{"030A7}{lb:ns}
+\dosetXTXcharacterclass{"030A8}{lb:id}
+\dosetXTXcharacterclass{"030A9}{lb:ns}
+\dofastrecurse{"030AA}{"030C2}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"030C3}{lb:ns}
+\dofastrecurse{"030C4}{"030E2}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"030E3}{lb:ns}
+\dosetXTXcharacterclass{"030E4}{lb:id}
+\dosetXTXcharacterclass{"030E5}{lb:ns}
+\dosetXTXcharacterclass{"030E6}{lb:id}
+\dosetXTXcharacterclass{"030E7}{lb:ns}
+\dofastrecurse{"030E8}{"030ED}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"030EE}{lb:ns}
+\dofastrecurse{"030EF}{"030F4}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"030F5}{"030F6}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"030F7}{"030FA}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"030FB}{"030FE}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"030FF}{"031CF}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"031F0}{"031FF}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"03200}{"03400}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"04E00}{"0A014}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0A015}{lb:ns}
+\dofastrecurse{"0A016}{"0A4C6}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0A802}{lb:cm}
+\dosetXTXcharacterclass{"0A806}{lb:cm}
+\dosetXTXcharacterclass{"0A80B}{lb:cm}
+\dofastrecurse{"0A823}{"0A827}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0A876}{"0A877}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dofastrecurse{"0F900}{"0FAD9}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FB1E}{lb:cm}
+\dosetXTXcharacterclass{"0FD3E}{lb:op}
+\dosetXTXcharacterclass{"0FD3F}{lb:cl}
+\dofastrecurse{"0FE00}{"0FE0F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dosetXTXcharacterclass{"0FE10}{lb:is}
+\dofastrecurse{"0FE11}{"0FE12}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cl}}
+\dofastrecurse{"0FE13}{"0FE14}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:is}}
+\dofastrecurse{"0FE15}{"0FE16}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dosetXTXcharacterclass{"0FE17}{lb:op}
+\dosetXTXcharacterclass{"0FE18}{lb:cl}
+\dofastrecurse{"0FE20}{"0FE23}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"0FE30}{"0FE34}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FE35}{lb:op}
+\dosetXTXcharacterclass{"0FE36}{lb:cl}
+\dosetXTXcharacterclass{"0FE37}{lb:op}
+\dosetXTXcharacterclass{"0FE38}{lb:cl}
+\dosetXTXcharacterclass{"0FE39}{lb:op}
+\dosetXTXcharacterclass{"0FE3A}{lb:cl}
+\dosetXTXcharacterclass{"0FE3B}{lb:op}
+\dosetXTXcharacterclass{"0FE3C}{lb:cl}
+\dosetXTXcharacterclass{"0FE3D}{lb:op}
+\dosetXTXcharacterclass{"0FE3E}{lb:cl}
+\dosetXTXcharacterclass{"0FE3F}{lb:op}
+\dosetXTXcharacterclass{"0FE40}{lb:cl}
+\dosetXTXcharacterclass{"0FE41}{lb:op}
+\dosetXTXcharacterclass{"0FE42}{lb:cl}
+\dosetXTXcharacterclass{"0FE43}{lb:op}
+\dosetXTXcharacterclass{"0FE44}{lb:cl}
+\dofastrecurse{"0FE45}{"0FE46}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FE47}{lb:op}
+\dosetXTXcharacterclass{"0FE48}{lb:cl}
+\dofastrecurse{"0FE49}{"0FE4F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FE50}{lb:cl}
+\dosetXTXcharacterclass{"0FE51}{lb:id}
+\dosetXTXcharacterclass{"0FE52}{lb:cl}
+\dofastrecurse{"0FE54}{"0FE55}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0FE56}{"0FE57}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ex}}
+\dosetXTXcharacterclass{"0FE58}{lb:id}
+\dosetXTXcharacterclass{"0FE59}{lb:op}
+\dosetXTXcharacterclass{"0FE5A}{lb:cl}
+\dosetXTXcharacterclass{"0FE5B}{lb:op}
+\dosetXTXcharacterclass{"0FE5C}{lb:cl}
+\dosetXTXcharacterclass{"0FE5D}{lb:op}
+\dosetXTXcharacterclass{"0FE5E}{lb:cl}
+\dofastrecurse{"0FE5F}{"0FE68}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FE6B}{lb:id}
+\dosetXTXcharacterclass{"0FF01}{lb:ex}
+\dofastrecurse{"0FF02}{"0FF03}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"0FF06}{"0FF07}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FF08}{lb:op}
+\dosetXTXcharacterclass{"0FF09}{lb:cl}
+\dofastrecurse{"0FF0A}{"0FF0B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FF0C}{lb:cl}
+\dosetXTXcharacterclass{"0FF0D}{lb:id}
+\dosetXTXcharacterclass{"0FF0E}{lb:cl}
+\dofastrecurse{"0FF0F}{"0FF19}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"0FF1A}{"0FF1B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0FF1C}{"0FF1E}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FF1F}{lb:ex}
+\dofastrecurse{"0FF20}{"0FF3A}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FF3B}{lb:op}
+\dosetXTXcharacterclass{"0FF3C}{lb:id}
+\dosetXTXcharacterclass{"0FF3D}{lb:cl}
+\dofastrecurse{"0FF3E}{"0FF5A}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dosetXTXcharacterclass{"0FF5B}{lb:op}
+\dosetXTXcharacterclass{"0FF5C}{lb:id}
+\dosetXTXcharacterclass{"0FF5D}{lb:cl}
+\dosetXTXcharacterclass{"0FF5E}{lb:id}
+\dosetXTXcharacterclass{"0FF5F}{lb:op}
+\dofastrecurse{"0FF60}{"0FF61}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cl}}
+\dosetXTXcharacterclass{"0FF62}{lb:op}
+\dofastrecurse{"0FF63}{"0FF64}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cl}}
+\dosetXTXcharacterclass{"0FF65}{lb:ns}
+\dofastrecurse{"0FF67}{"0FF70}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0FF9E}{"0FF9F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:ns}}
+\dofastrecurse{"0FFE2}{"0FFE4}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"0FFF9}{"0FFFB}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"10A01}{"10A0F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"10A38}{"10A3F}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"1D165}{"1D169}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"1D16D}{"1D182}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"1D185}{"1D18B}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"1D1AA}{"1D1AD}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"1D242}{"1D244}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+\dofastrecurse{"20000}{"2FA1D}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"E0001}{"E01EF}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:cm}}
+
+\dofastrecurse{"03400}{"04DB5}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"04E00}{"09FBB}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+\dofastrecurse{"20000}{"2A6D6}{1}{\dosetXTXcharacterclass\fastrecursecounter{lb:id}}
+
+\endinput
diff --git a/tex/context/base/xetx-ini.tex b/tex/context/base/xetx-ini.tex
new file mode 100644
index 000000000..db3cccabd
--- /dev/null
+++ b/tex/context/base/xetx-ini.tex
@@ -0,0 +1,132 @@
+%D \module
+%D [ file=xetx-ini,
+%D version=2004.09.11,
+%D title=\CONTEXT\ System Macros,
+%D subtitle=\XETEX\ Initializations,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+%D We moved some code around and now have reorganized the xetex
+%D code in the \type {xetx} module namespace.
+
+\unprotect
+
+%D Some defaults.
+
+\ifdefined\XeTeXuseglyphmetrics
+ \XeTeXuseglyphmetrics\plusone
+\fi
+
+%D Character classes.
+
+\newcount\nofXTXcharinjections
+
+\def\defineXTXcharinjectionclass[#1]%
+ {\global\advance\nofXTXcharinjections\plusone
+ \setxvalue{@xtx@cc@#1}{\number\nofXTXcharinjections}}
+
+\setxvalue{@xtx@cc@\s!default}{0}
+
+\def\getXTXcharinjectionclass#1%
+ {\csname @xtx@cc@\ifcsname @xtx@cc@#1\endcsname#1\else\s!default\fi\endcsname}
+
+\let\currentXTXcharinjection\s!default
+
+\def\startXTXcharinjecxtions[#1]%
+ {\pushmacro\currentXTXcharinjection
+ \def\currentXTXcharinjection{#1}}
+
+\def\stopXTXcharinjections
+ {\popmacro\currentXTXcharinjection}
+
+\def\defineXTXcharinjection #1 #2 %
+ {\doifnumberelse{#1}{\edef\XTXclassone{\number#1}}{\edef\XTXclassone{\getXTXcharinjectionclas{#1}}}%
+ \doifnumberelse{#2}{\edef\XTXclasstwo{\number#2}}{\edef\XTXclasstwo{\getXTXcharinjectionclas{#2}}}%
+ \expanded{\dodefineXTXcharinjection{\XTXclassone}{\XTXclasstwo}}}
+
+\def\setXTXcharcodes #1 #2 #3 % encoding syntax
+ {\catcode#1=11 \lccode #1=#2 \uccode #1=#3 }
+
+\def\dosetXTXcharcodes#1#2#3% compact syntax
+ {\catcode#1=11 \lccode #1=#2 \uccode #1=#3 }
+
+\ifdefined\XeTeXinterchartoks
+
+ \long\def\dodefineXTXcharinjection#1#2#3%
+ {\XeTeXinterchartoks #1 #2 {\XTXcharinjection{#1}{#2}}%
+ \setvalue{@xtx@ch@\currentXTXcharinjection @#1@#2@}{#3}}
+
+ \def\setXTXcharacterclass #1 #2 %
+ {\doifnumberelse{#2}
+ {\XeTeXcharclass#1=#2\relax}
+ {\XeTeXcharclass#1=\getXTXcharinjectionclass{#2}\relax}}
+
+ \def\dosetXTXcharacterclass#1% #2 fast one
+ {\XeTeXcharclass#1=\getXTXcharinjectionclass}
+
+\else
+
+ \long\def\dodefineXTXcharinjection#1#2#3%
+ {\setvalue{@xtx@ch@\currentXTXcharinjection @#1@#2@}{#3}}
+
+ \def\setXTXcharacterclass #1 #2 %
+ {}
+
+\fi
+
+\chardef\XTXcharinjectionsmode=1
+
+\letvalue{@xtx@ch@\s!empty}\empty
+
+\def\XTXcharinjection#1#2%
+ {\csname @xtx@ch@%
+ \ifcase\XTXcharinjectionsmode
+ \s!empty
+ \or
+ \ifcsname @xtx@ch@\currentXTXcharinjection @#1@#2@\endcsname \currentXTXcharinjection @#1@#2@\fi
+ \or
+ \ifcsname @xtx@ch@\currentXTXcharinjection @#1@#2@\endcsname \currentXTXcharinjection @#1@#2@\else
+ \ifcsname @xtx@ch@\s!default @#1@#2@\endcsname \s!default @#1@#2@\else
+ \s!empty
+ \fi\fi
+ \else
+ \s!empty
+ \fi
+ \endcsname}
+
+\def\enableXTXcharinjections[#1]%
+ {\def\currentXTXcharinjection{#1}}
+
+\protect \endinput
+
+\starttext
+
+\startXTXcharinjecxtions[default]
+ \defineXTXcharinjection 10 40 {[default]}
+\stopXTXcharinjections
+
+\startXTXcharinjecxtions[whatever]
+ \defineXTXcharinjection 20 40 {[whatever]}
+\stopXTXcharinjections
+
+\chardef\XTXcharinjectionsmode=0
+
+\enableXTXcharinjections[default] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+\enableXTXcharinjections[whatever] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+
+\chardef\XTXcharinjectionsmode=1
+
+\enableXTXcharinjections[default] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+\enableXTXcharinjections[whatever] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+
+\chardef\XTXcharinjectionsmode=2
+
+\enableXTXcharinjections[default] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+\enableXTXcharinjections[whatever] A\XTXcharinjection{10}{40}B\XTXcharinjection{20}{40}C
+
+\stoptext
diff --git a/tex/context/base/xetx-utf.tex b/tex/context/base/xetx-utf.tex
new file mode 100644
index 000000000..79bd00745
--- /dev/null
+++ b/tex/context/base/xetx-utf.tex
@@ -0,0 +1,1989 @@
+% filename : xetx-utf.tex
+% comment : generated by mtxrun --script chars --xtx
+% author : Hans Hagen, PRAGMA-ADE, Hasselt NL
+% copyright: PRAGMA ADE / ConTeXt Development Team
+% license : see context related readme files
+
+% lc/uc/catcode mappings
+
+\setXTXcharcodes "00041 "00061 "00041 % LATIN CAPITAL LETTER A
+\setXTXcharcodes "00042 "00062 "00042 % LATIN CAPITAL LETTER B
+\setXTXcharcodes "00043 "00063 "00043 % LATIN CAPITAL LETTER C
+\setXTXcharcodes "00044 "00064 "00044 % LATIN CAPITAL LETTER D
+\setXTXcharcodes "00045 "00065 "00045 % LATIN CAPITAL LETTER E
+\setXTXcharcodes "00046 "00066 "00046 % LATIN CAPITAL LETTER F
+\setXTXcharcodes "00047 "00067 "00047 % LATIN CAPITAL LETTER G
+\setXTXcharcodes "00048 "00068 "00048 % LATIN CAPITAL LETTER H
+\setXTXcharcodes "00049 "00069 "00049 % LATIN CAPITAL LETTER I
+\setXTXcharcodes "0004A "0006A "0004A % LATIN CAPITAL LETTER J
+\setXTXcharcodes "0004B "0006B "0004B % LATIN CAPITAL LETTER K
+\setXTXcharcodes "0004C "0006C "0004C % LATIN CAPITAL LETTER L
+\setXTXcharcodes "0004D "0006D "0004D % LATIN CAPITAL LETTER M
+\setXTXcharcodes "0004E "0006E "0004E % LATIN CAPITAL LETTER N
+\setXTXcharcodes "0004F "0006F "0004F % LATIN CAPITAL LETTER O
+\setXTXcharcodes "00050 "00070 "00050 % LATIN CAPITAL LETTER P
+\setXTXcharcodes "00051 "00071 "00051 % LATIN CAPITAL LETTER Q
+\setXTXcharcodes "00052 "00072 "00052 % LATIN CAPITAL LETTER R
+\setXTXcharcodes "00053 "00073 "00053 % LATIN CAPITAL LETTER S
+\setXTXcharcodes "00054 "00074 "00054 % LATIN CAPITAL LETTER T
+\setXTXcharcodes "00055 "00075 "00055 % LATIN CAPITAL LETTER U
+\setXTXcharcodes "00056 "00076 "00056 % LATIN CAPITAL LETTER V
+\setXTXcharcodes "00057 "00077 "00057 % LATIN CAPITAL LETTER W
+\setXTXcharcodes "00058 "00078 "00058 % LATIN CAPITAL LETTER X
+\setXTXcharcodes "00059 "00079 "00059 % LATIN CAPITAL LETTER Y
+\setXTXcharcodes "0005A "0007A "0005A % LATIN CAPITAL LETTER Z
+\setXTXcharcodes "00061 "00061 "00041 % LATIN SMALL LETTER A
+\setXTXcharcodes "00062 "00062 "00042 % LATIN SMALL LETTER B
+\setXTXcharcodes "00063 "00063 "00043 % LATIN SMALL LETTER C
+\setXTXcharcodes "00064 "00064 "00044 % LATIN SMALL LETTER D
+\setXTXcharcodes "00065 "00065 "00045 % LATIN SMALL LETTER E
+\setXTXcharcodes "00066 "00066 "00046 % LATIN SMALL LETTER F
+\setXTXcharcodes "00067 "00067 "00047 % LATIN SMALL LETTER G
+\setXTXcharcodes "00068 "00068 "00048 % LATIN SMALL LETTER H
+\setXTXcharcodes "00069 "00069 "00049 % LATIN SMALL LETTER I
+\setXTXcharcodes "0006A "0006A "0004A % LATIN SMALL LETTER J
+\setXTXcharcodes "0006B "0006B "0004B % LATIN SMALL LETTER K
+\setXTXcharcodes "0006C "0006C "0004C % LATIN SMALL LETTER L
+\setXTXcharcodes "0006D "0006D "0004D % LATIN SMALL LETTER M
+\setXTXcharcodes "0006E "0006E "0004E % LATIN SMALL LETTER N
+\setXTXcharcodes "0006F "0006F "0004F % LATIN SMALL LETTER O
+\setXTXcharcodes "00070 "00070 "00050 % LATIN SMALL LETTER P
+\setXTXcharcodes "00071 "00071 "00051 % LATIN SMALL LETTER Q
+\setXTXcharcodes "00072 "00072 "00052 % LATIN SMALL LETTER R
+\setXTXcharcodes "00073 "00073 "00053 % LATIN SMALL LETTER S
+\setXTXcharcodes "00074 "00074 "00054 % LATIN SMALL LETTER T
+\setXTXcharcodes "00075 "00075 "00055 % LATIN SMALL LETTER U
+\setXTXcharcodes "00076 "00076 "00056 % LATIN SMALL LETTER V
+\setXTXcharcodes "00077 "00077 "00057 % LATIN SMALL LETTER W
+\setXTXcharcodes "00078 "00078 "00058 % LATIN SMALL LETTER X
+\setXTXcharcodes "00079 "00079 "00059 % LATIN SMALL LETTER Y
+\setXTXcharcodes "0007A "0007A "0005A % LATIN SMALL LETTER Z
+\setXTXcharcodes "000AA "000AA "000AA % FEMININE ORDINAL INDICATOR
+\setXTXcharcodes "000B5 "000B5 "0039C % MICRO SIGN
+\setXTXcharcodes "000BA "000BA "000BA % MASCULINE ORDINAL INDICATOR
+\setXTXcharcodes "000C0 "000E0 "000C0 % LATIN CAPITAL LETTER A WITH GRAVE
+\setXTXcharcodes "000C1 "000E1 "000C1 % LATIN CAPITAL LETTER A WITH ACUTE
+\setXTXcharcodes "000C2 "000E2 "000C2 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX
+\setXTXcharcodes "000C3 "000E3 "000C3 % LATIN CAPITAL LETTER A WITH TILDE
+\setXTXcharcodes "000C4 "000E4 "000C4 % LATIN CAPITAL LETTER A WITH DIAERESIS
+\setXTXcharcodes "000C5 "000E5 "000C5 % LATIN CAPITAL LETTER A WITH RING ABOVE
+\setXTXcharcodes "000C6 "000E6 "000C6 % LATIN CAPITAL LETTER AE
+\setXTXcharcodes "000C7 "000E7 "000C7 % LATIN CAPITAL LETTER C WITH CEDILLA
+\setXTXcharcodes "000C8 "000E8 "000C8 % LATIN CAPITAL LETTER E WITH GRAVE
+\setXTXcharcodes "000C9 "000E9 "000C9 % LATIN CAPITAL LETTER E WITH ACUTE
+\setXTXcharcodes "000CA "000EA "000CA % LATIN CAPITAL LETTER E WITH CIRCUMFLEX
+\setXTXcharcodes "000CB "000EB "000CB % LATIN CAPITAL LETTER E WITH DIAERESIS
+\setXTXcharcodes "000CC "000EC "000CC % LATIN CAPITAL LETTER I WITH GRAVE
+\setXTXcharcodes "000CD "000ED "000CD % LATIN CAPITAL LETTER I WITH ACUTE
+\setXTXcharcodes "000CE "000EE "000CE % LATIN CAPITAL LETTER I WITH CIRCUMFLEX
+\setXTXcharcodes "000CF "000EF "000CF % LATIN CAPITAL LETTER I WITH DIAERESIS
+\setXTXcharcodes "000D0 "000F0 "000D0 % LATIN CAPITAL LETTER ETH
+\setXTXcharcodes "000D1 "000F1 "000D1 % LATIN CAPITAL LETTER N WITH TILDE
+\setXTXcharcodes "000D2 "000F2 "000D2 % LATIN CAPITAL LETTER O WITH GRAVE
+\setXTXcharcodes "000D3 "000F3 "000D3 % LATIN CAPITAL LETTER O WITH ACUTE
+\setXTXcharcodes "000D4 "000F4 "000D4 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX
+\setXTXcharcodes "000D5 "000F5 "000D5 % LATIN CAPITAL LETTER O WITH TILDE
+\setXTXcharcodes "000D6 "000F6 "000D6 % LATIN CAPITAL LETTER O WITH DIAERESIS
+\setXTXcharcodes "000D8 "000F8 "000D8 % LATIN CAPITAL LETTER O WITH STROKE
+\setXTXcharcodes "000D9 "000F9 "000D9 % LATIN CAPITAL LETTER U WITH GRAVE
+\setXTXcharcodes "000DA "000FA "000DA % LATIN CAPITAL LETTER U WITH ACUTE
+\setXTXcharcodes "000DB "000FB "000DB % LATIN CAPITAL LETTER U WITH CIRCUMFLEX
+\setXTXcharcodes "000DC "000FC "000DC % LATIN CAPITAL LETTER U WITH DIAERESIS
+\setXTXcharcodes "000DD "000FD "000DD % LATIN CAPITAL LETTER Y WITH ACUTE
+\setXTXcharcodes "000DE "000FE "000DE % LATIN CAPITAL LETTER THORN
+\setXTXcharcodes "000DF "000DF "000DF % LATIN SMALL LETTER SHARP S
+\setXTXcharcodes "000E0 "000E0 "000C0 % LATIN SMALL LETTER A WITH GRAVE
+\setXTXcharcodes "000E1 "000E1 "000C1 % LATIN SMALL LETTER A WITH ACUTE
+\setXTXcharcodes "000E2 "000E2 "000C2 % LATIN SMALL LETTER A WITH CIRCUMFLEX
+\setXTXcharcodes "000E3 "000E3 "000C3 % LATIN SMALL LETTER A WITH TILDE
+\setXTXcharcodes "000E4 "000E4 "000C4 % LATIN SMALL LETTER A WITH DIAERESIS
+\setXTXcharcodes "000E5 "000E5 "000C5 % LATIN SMALL LETTER A WITH RING ABOVE
+\setXTXcharcodes "000E6 "000E6 "000C6 % LATIN SMALL LETTER AE
+\setXTXcharcodes "000E7 "000E7 "000C7 % LATIN SMALL LETTER C WITH CEDILLA
+\setXTXcharcodes "000E8 "000E8 "000C8 % LATIN SMALL LETTER E WITH GRAVE
+\setXTXcharcodes "000E9 "000E9 "000C9 % LATIN SMALL LETTER E WITH ACUTE
+\setXTXcharcodes "000EA "000EA "000CA % LATIN SMALL LETTER E WITH CIRCUMFLEX
+\setXTXcharcodes "000EB "000EB "000CB % LATIN SMALL LETTER E WITH DIAERESIS
+\setXTXcharcodes "000EC "000EC "000CC % LATIN SMALL LETTER I WITH GRAVE
+\setXTXcharcodes "000ED "000ED "000CD % LATIN SMALL LETTER I WITH ACUTE
+\setXTXcharcodes "000EE "000EE "000CE % LATIN SMALL LETTER I WITH CIRCUMFLEX
+\setXTXcharcodes "000EF "000EF "000CF % LATIN SMALL LETTER I WITH DIAERESIS
+\setXTXcharcodes "000F0 "000F0 "000D0 % LATIN SMALL LETTER ETH
+\setXTXcharcodes "000F1 "000F1 "000D1 % LATIN SMALL LETTER N WITH TILDE
+\setXTXcharcodes "000F2 "000F2 "000D2 % LATIN SMALL LETTER O WITH GRAVE
+\setXTXcharcodes "000F3 "000F3 "000D3 % LATIN SMALL LETTER O WITH ACUTE
+\setXTXcharcodes "000F4 "000F4 "000D4 % LATIN SMALL LETTER O WITH CIRCUMFLEX
+\setXTXcharcodes "000F5 "000F5 "000D5 % LATIN SMALL LETTER O WITH TILDE
+\setXTXcharcodes "000F6 "000F6 "000D6 % LATIN SMALL LETTER O WITH DIAERESIS
+\setXTXcharcodes "000F8 "000F8 "000D8 % LATIN SMALL LETTER O WITH STROKE
+\setXTXcharcodes "000F9 "000F9 "000D9 % LATIN SMALL LETTER U WITH GRAVE
+\setXTXcharcodes "000FA "000FA "000DA % LATIN SMALL LETTER U WITH ACUTE
+\setXTXcharcodes "000FB "000FB "000DB % LATIN SMALL LETTER U WITH CIRCUMFLEX
+\setXTXcharcodes "000FC "000FC "000DC % LATIN SMALL LETTER U WITH DIAERESIS
+\setXTXcharcodes "000FD "000FD "000DD % LATIN SMALL LETTER Y WITH ACUTE
+\setXTXcharcodes "000FE "000FE "000DE % LATIN SMALL LETTER THORN
+\setXTXcharcodes "000FF "000FF "00178 % LATIN SMALL LETTER Y WITH DIAERESIS
+\setXTXcharcodes "00100 "00101 "00100 % LATIN CAPITAL LETTER A WITH MACRON
+\setXTXcharcodes "00101 "00101 "00100 % LATIN SMALL LETTER A WITH MACRON
+\setXTXcharcodes "00102 "00103 "00102 % LATIN CAPITAL LETTER A WITH BREVE
+\setXTXcharcodes "00103 "00103 "00102 % LATIN SMALL LETTER A WITH BREVE
+\setXTXcharcodes "00104 "00105 "00104 % LATIN CAPITAL LETTER A WITH OGONEK
+\setXTXcharcodes "00105 "00105 "00104 % LATIN SMALL LETTER A WITH OGONEK
+\setXTXcharcodes "00106 "00107 "00106 % LATIN CAPITAL LETTER C WITH ACUTE
+\setXTXcharcodes "00107 "00107 "00106 % LATIN SMALL LETTER C WITH ACUTE
+\setXTXcharcodes "00108 "00109 "00108 % LATIN CAPITAL LETTER C WITH CIRCUMFLEX
+\setXTXcharcodes "00109 "00109 "00108 % LATIN SMALL LETTER C WITH CIRCUMFLEX
+\setXTXcharcodes "0010A "0010B "0010A % LATIN CAPITAL LETTER C WITH DOT ABOVE
+\setXTXcharcodes "0010B "0010B "0010A % LATIN SMALL LETTER C WITH DOT ABOVE
+\setXTXcharcodes "0010C "0010D "0010C % LATIN CAPITAL LETTER C WITH CARON
+\setXTXcharcodes "0010D "0010D "0010C % LATIN SMALL LETTER C WITH CARON
+\setXTXcharcodes "0010E "0010F "0010E % LATIN CAPITAL LETTER D WITH CARON
+\setXTXcharcodes "0010F "0010F "0010E % LATIN SMALL LETTER D WITH CARON
+\setXTXcharcodes "00110 "00111 "00110 % LATIN CAPITAL LETTER D WITH STROKE
+\setXTXcharcodes "00111 "00111 "00110 % LATIN SMALL LETTER D WITH STROKE
+\setXTXcharcodes "00112 "00113 "00112 % LATIN CAPITAL LETTER E WITH MACRON
+\setXTXcharcodes "00113 "00113 "00112 % LATIN SMALL LETTER E WITH MACRON
+\setXTXcharcodes "00114 "00115 "00114 % LATIN CAPITAL LETTER E WITH BREVE
+\setXTXcharcodes "00115 "00115 "00114 % LATIN SMALL LETTER E WITH BREVE
+\setXTXcharcodes "00116 "00117 "00116 % LATIN CAPITAL LETTER E WITH DOT ABOVE
+\setXTXcharcodes "00117 "00117 "00116 % LATIN SMALL LETTER E WITH DOT ABOVE
+\setXTXcharcodes "00118 "00119 "00118 % LATIN CAPITAL LETTER E WITH OGONEK
+\setXTXcharcodes "00119 "00119 "00118 % LATIN SMALL LETTER E WITH OGONEK
+\setXTXcharcodes "0011A "0011B "0011A % LATIN CAPITAL LETTER E WITH CARON
+\setXTXcharcodes "0011B "0011B "0011A % LATIN SMALL LETTER E WITH CARON
+\setXTXcharcodes "0011C "0011D "0011C % LATIN CAPITAL LETTER G WITH CIRCUMFLEX
+\setXTXcharcodes "0011D "0011D "0011C % LATIN SMALL LETTER G WITH CIRCUMFLEX
+\setXTXcharcodes "0011E "0011F "0011E % LATIN CAPITAL LETTER G WITH BREVE
+\setXTXcharcodes "0011F "0011F "0011E % LATIN SMALL LETTER G WITH BREVE
+\setXTXcharcodes "00120 "00121 "00120 % LATIN CAPITAL LETTER G WITH DOT ABOVE
+\setXTXcharcodes "00121 "00121 "00120 % LATIN SMALL LETTER G WITH DOT ABOVE
+\setXTXcharcodes "00122 "00123 "00122 % LATIN CAPITAL LETTER G WITH CEDILLA
+\setXTXcharcodes "00123 "00123 "00122 % LATIN SMALL LETTER G WITH CEDILLA
+\setXTXcharcodes "00124 "00125 "00124 % LATIN CAPITAL LETTER H WITH CIRCUMFLEX
+\setXTXcharcodes "00125 "00125 "00124 % LATIN SMALL LETTER H WITH CIRCUMFLEX
+\setXTXcharcodes "00126 "00127 "00126 % LATIN CAPITAL LETTER H WITH STROKE
+\setXTXcharcodes "00127 "00127 "00126 % LATIN SMALL LETTER H WITH STROKE
+\setXTXcharcodes "00128 "00129 "00128 % LATIN CAPITAL LETTER I WITH TILDE
+\setXTXcharcodes "00129 "00129 "00128 % LATIN SMALL LETTER I WITH TILDE
+\setXTXcharcodes "0012A "0012B "0012A % LATIN CAPITAL LETTER I WITH MACRON
+\setXTXcharcodes "0012B "0012B "0012A % LATIN SMALL LETTER I WITH MACRON
+\setXTXcharcodes "0012C "0012D "0012C % LATIN CAPITAL LETTER I WITH BREVE
+\setXTXcharcodes "0012D "0012D "0012C % LATIN SMALL LETTER I WITH BREVE
+\setXTXcharcodes "0012E "0012F "0012E % LATIN CAPITAL LETTER I WITH OGONEK
+\setXTXcharcodes "0012F "0012F "0012E % LATIN SMALL LETTER I WITH OGONEK
+\setXTXcharcodes "00130 "00069 "00130 % LATIN CAPITAL LETTER I WITH DOT ABOVE
+\setXTXcharcodes "00131 "00131 "00049 % LATIN SMALL LETTER DOTLESS I
+\setXTXcharcodes "00132 "00133 "00132 % LATIN CAPITAL LIGATURE IJ
+\setXTXcharcodes "00133 "00133 "00132 % LATIN SMALL LIGATURE IJ
+\setXTXcharcodes "00134 "00135 "00134 % LATIN CAPITAL LETTER J WITH CIRCUMFLEX
+\setXTXcharcodes "00135 "00135 "00134 % LATIN SMALL LETTER J WITH CIRCUMFLEX
+\setXTXcharcodes "00136 "00137 "00136 % LATIN CAPITAL LETTER K WITH CEDILLA
+\setXTXcharcodes "00137 "00137 "00136 % LATIN SMALL LETTER K WITH CEDILLA
+\setXTXcharcodes "00138 "00138 "00138 % LATIN SMALL LETTER KRA
+\setXTXcharcodes "00139 "0013A "00139 % LATIN CAPITAL LETTER L WITH ACUTE
+\setXTXcharcodes "0013A "0013A "00139 % LATIN SMALL LETTER L WITH ACUTE
+\setXTXcharcodes "0013B "0013C "0013B % LATIN CAPITAL LETTER L WITH CEDILLA
+\setXTXcharcodes "0013C "0013C "0013B % LATIN SMALL LETTER L WITH CEDILLA
+\setXTXcharcodes "0013D "0013E "0013D % LATIN CAPITAL LETTER L WITH CARON
+\setXTXcharcodes "0013E "0013E "0013D % LATIN SMALL LETTER L WITH CARON
+\setXTXcharcodes "0013F "00140 "0013F % LATIN CAPITAL LETTER L WITH MIDDLE DOT
+\setXTXcharcodes "00140 "00140 "0013F % LATIN SMALL LETTER L WITH MIDDLE DOT
+\setXTXcharcodes "00141 "00142 "00141 % LATIN CAPITAL LETTER L WITH STROKE
+\setXTXcharcodes "00142 "00142 "00141 % LATIN SMALL LETTER L WITH STROKE
+\setXTXcharcodes "00143 "00144 "00143 % LATIN CAPITAL LETTER N WITH ACUTE
+\setXTXcharcodes "00144 "00144 "00143 % LATIN SMALL LETTER N WITH ACUTE
+\setXTXcharcodes "00145 "00146 "00145 % LATIN CAPITAL LETTER N WITH CEDILLA
+\setXTXcharcodes "00146 "00146 "00145 % LATIN SMALL LETTER N WITH CEDILLA
+\setXTXcharcodes "00147 "00148 "00147 % LATIN CAPITAL LETTER N WITH CARON
+\setXTXcharcodes "00148 "00148 "00147 % LATIN SMALL LETTER N WITH CARON
+\setXTXcharcodes "00149 "00149 "00149 % LATIN SMALL LETTER N PRECEDED BY APOSTROPHE
+\setXTXcharcodes "0014A "0014B "0014A % LATIN CAPITAL LETTER ENG
+\setXTXcharcodes "0014B "0014B "0014A % LATIN SMALL LETTER ENG
+\setXTXcharcodes "0014C "0014D "0014C % LATIN CAPITAL LETTER O WITH MACRON
+\setXTXcharcodes "0014D "0014D "0014C % LATIN SMALL LETTER O WITH MACRON
+\setXTXcharcodes "0014E "0014F "0014E % LATIN CAPITAL LETTER O WITH BREVE
+\setXTXcharcodes "0014F "0014F "0014E % LATIN SMALL LETTER O WITH BREVE
+\setXTXcharcodes "00150 "00151 "00150 % LATIN CAPITAL LETTER O WITH DOUBLE ACUTE
+\setXTXcharcodes "00151 "00151 "00150 % LATIN SMALL LETTER O WITH DOUBLE ACUTE
+\setXTXcharcodes "00152 "00153 "00152 % LATIN CAPITAL LIGATURE OE
+\setXTXcharcodes "00153 "00153 "00152 % LATIN SMALL LIGATURE OE
+\setXTXcharcodes "00154 "00155 "00154 % LATIN CAPITAL LETTER R WITH ACUTE
+\setXTXcharcodes "00155 "00155 "00154 % LATIN SMALL LETTER R WITH ACUTE
+\setXTXcharcodes "00156 "00157 "00156 % LATIN CAPITAL LETTER R WITH CEDILLA
+\setXTXcharcodes "00157 "00157 "00156 % LATIN SMALL LETTER R WITH CEDILLA
+\setXTXcharcodes "00158 "00159 "00158 % LATIN CAPITAL LETTER R WITH CARON
+\setXTXcharcodes "00159 "00159 "00158 % LATIN SMALL LETTER R WITH CARON
+\setXTXcharcodes "0015A "0015B "0015A % LATIN CAPITAL LETTER S WITH ACUTE
+\setXTXcharcodes "0015B "0015B "0015A % LATIN SMALL LETTER S WITH ACUTE
+\setXTXcharcodes "0015C "0015D "0015C % LATIN CAPITAL LETTER S WITH CIRCUMFLEX
+\setXTXcharcodes "0015D "0015D "0015C % LATIN SMALL LETTER S WITH CIRCUMFLEX
+\setXTXcharcodes "0015E "0015F "0015E % LATIN CAPITAL LETTER S WITH CEDILLA
+\setXTXcharcodes "0015F "0015F "0015E % LATIN SMALL LETTER S WITH CEDILLA
+\setXTXcharcodes "00160 "00161 "00160 % LATIN CAPITAL LETTER S WITH CARON
+\setXTXcharcodes "00161 "00161 "00160 % LATIN SMALL LETTER S WITH CARON
+\setXTXcharcodes "00162 "00163 "00162 % LATIN CAPITAL LETTER T WITH CEDILLA
+\setXTXcharcodes "00163 "00163 "00162 % LATIN SMALL LETTER T WITH CEDILLA
+\setXTXcharcodes "00164 "00165 "00164 % LATIN CAPITAL LETTER T WITH CARON
+\setXTXcharcodes "00165 "00165 "00164 % LATIN SMALL LETTER T WITH CARON
+\setXTXcharcodes "00166 "00167 "00166 % LATIN CAPITAL LETTER T WITH STROKE
+\setXTXcharcodes "00167 "00167 "00166 % LATIN SMALL LETTER T WITH STROKE
+\setXTXcharcodes "00168 "00169 "00168 % LATIN CAPITAL LETTER U WITH TILDE
+\setXTXcharcodes "00169 "00169 "00168 % LATIN SMALL LETTER U WITH TILDE
+\setXTXcharcodes "0016A "0016B "0016A % LATIN CAPITAL LETTER U WITH MACRON
+\setXTXcharcodes "0016B "0016B "0016A % LATIN SMALL LETTER U WITH MACRON
+\setXTXcharcodes "0016C "0016D "0016C % LATIN CAPITAL LETTER U WITH BREVE
+\setXTXcharcodes "0016D "0016D "0016C % LATIN SMALL LETTER U WITH BREVE
+\setXTXcharcodes "0016E "0016F "0016E % LATIN CAPITAL LETTER U WITH RING ABOVE
+\setXTXcharcodes "0016F "0016F "0016E % LATIN SMALL LETTER U WITH RING ABOVE
+\setXTXcharcodes "00170 "00171 "00170 % LATIN CAPITAL LETTER U WITH DOUBLE ACUTE
+\setXTXcharcodes "00171 "00171 "00170 % LATIN SMALL LETTER U WITH DOUBLE ACUTE
+\setXTXcharcodes "00172 "00173 "00172 % LATIN CAPITAL LETTER U WITH OGONEK
+\setXTXcharcodes "00173 "00173 "00172 % LATIN SMALL LETTER U WITH OGONEK
+\setXTXcharcodes "00174 "00175 "00174 % LATIN CAPITAL LETTER W WITH CIRCUMFLEX
+\setXTXcharcodes "00175 "00175 "00174 % LATIN SMALL LETTER W WITH CIRCUMFLEX
+\setXTXcharcodes "00176 "00177 "00176 % LATIN CAPITAL LETTER Y WITH CIRCUMFLEX
+\setXTXcharcodes "00177 "00177 "00176 % LATIN SMALL LETTER Y WITH CIRCUMFLEX
+\setXTXcharcodes "00178 "000FF "00178 % LATIN CAPITAL LETTER Y WITH DIAERESIS
+\setXTXcharcodes "00179 "0017A "00179 % LATIN CAPITAL LETTER Z WITH ACUTE
+\setXTXcharcodes "0017A "0017A "00179 % LATIN SMALL LETTER Z WITH ACUTE
+\setXTXcharcodes "0017B "0017C "0017B % LATIN CAPITAL LETTER Z WITH DOT ABOVE
+\setXTXcharcodes "0017C "0017C "0017B % LATIN SMALL LETTER Z WITH DOT ABOVE
+\setXTXcharcodes "0017D "0017E "0017D % LATIN CAPITAL LETTER Z WITH CARON
+\setXTXcharcodes "0017E "0017E "0017D % LATIN SMALL LETTER Z WITH CARON
+\setXTXcharcodes "0017F "0017F "00053 % LATIN SMALL LETTER LONG S
+\setXTXcharcodes "00180 "00180 "00243 % LATIN SMALL LETTER B WITH STROKE
+\setXTXcharcodes "00181 "00253 "00181 % LATIN CAPITAL LETTER B WITH HOOK
+\setXTXcharcodes "00182 "00183 "00182 % LATIN CAPITAL LETTER B WITH TOPBAR
+\setXTXcharcodes "00183 "00183 "00182 % LATIN SMALL LETTER B WITH TOPBAR
+\setXTXcharcodes "00184 "00185 "00184 % LATIN CAPITAL LETTER TONE SIX
+\setXTXcharcodes "00185 "00185 "00184 % LATIN SMALL LETTER TONE SIX
+\setXTXcharcodes "00186 "00254 "00186 % LATIN CAPITAL LETTER OPEN O
+\setXTXcharcodes "00187 "00188 "00187 % LATIN CAPITAL LETTER C WITH HOOK
+\setXTXcharcodes "00188 "00188 "00187 % LATIN SMALL LETTER C WITH HOOK
+\setXTXcharcodes "00189 "00256 "00189 % LATIN CAPITAL LETTER AFRICAN D
+\setXTXcharcodes "0018A "00257 "0018A % LATIN CAPITAL LETTER D WITH HOOK
+\setXTXcharcodes "0018B "0018C "0018B % LATIN CAPITAL LETTER D WITH TOPBAR
+\setXTXcharcodes "0018C "0018C "0018B % LATIN SMALL LETTER D WITH TOPBAR
+\setXTXcharcodes "0018D "0018D "0018D % LATIN SMALL LETTER TURNED DELTA
+\setXTXcharcodes "0018E "001DD "0018E % LATIN CAPITAL LETTER REVERSED E
+\setXTXcharcodes "0018F "00259 "0018F % LATIN CAPITAL LETTER SCHWA
+\setXTXcharcodes "00190 "0025B "00190 % LATIN CAPITAL LETTER OPEN E
+\setXTXcharcodes "00191 "00192 "00191 % LATIN CAPITAL LETTER F WITH HOOK
+\setXTXcharcodes "00192 "00192 "00191 % LATIN SMALL LETTER F WITH HOOK
+\setXTXcharcodes "00193 "00260 "00193 % LATIN CAPITAL LETTER G WITH HOOK
+\setXTXcharcodes "00194 "00263 "00194 % LATIN CAPITAL LETTER GAMMA
+\setXTXcharcodes "00195 "00195 "001F6 % LATIN SMALL LETTER HV
+\setXTXcharcodes "00196 "00269 "00196 % LATIN CAPITAL LETTER IOTA
+\setXTXcharcodes "00197 "00268 "00197 % LATIN CAPITAL LETTER I WITH STROKE
+\setXTXcharcodes "00198 "00199 "00198 % LATIN CAPITAL LETTER K WITH HOOK
+\setXTXcharcodes "00199 "00199 "00198 % LATIN SMALL LETTER K WITH HOOK
+\setXTXcharcodes "0019A "0019A "0023D % LATIN SMALL LETTER L WITH BAR
+\setXTXcharcodes "0019B "0019B "0019B % LATIN SMALL LETTER LAMBDA WITH STROKE
+\setXTXcharcodes "0019C "0026F "0019C % LATIN CAPITAL LETTER TURNED M
+\setXTXcharcodes "0019D "00272 "0019D % LATIN CAPITAL LETTER N WITH LEFT HOOK
+\setXTXcharcodes "0019E "0019E "00220 % LATIN SMALL LETTER N WITH LONG RIGHT LEG
+\setXTXcharcodes "0019F "00275 "0019F % LATIN CAPITAL LETTER O WITH MIDDLE TILDE
+\setXTXcharcodes "001A0 "001A1 "001A0 % LATIN CAPITAL LETTER O WITH HORN
+\setXTXcharcodes "001A1 "001A1 "001A0 % LATIN SMALL LETTER O WITH HORN
+\setXTXcharcodes "001A2 "001A3 "001A2 % LATIN CAPITAL LETTER OI
+\setXTXcharcodes "001A3 "001A3 "001A2 % LATIN SMALL LETTER OI
+\setXTXcharcodes "001A4 "001A5 "001A4 % LATIN CAPITAL LETTER P WITH HOOK
+\setXTXcharcodes "001A5 "001A5 "001A4 % LATIN SMALL LETTER P WITH HOOK
+\setXTXcharcodes "001A6 "00280 "001A6 % LATIN LETTER YR
+\setXTXcharcodes "001A7 "001A8 "001A7 % LATIN CAPITAL LETTER TONE TWO
+\setXTXcharcodes "001A8 "001A8 "001A7 % LATIN SMALL LETTER TONE TWO
+\setXTXcharcodes "001A9 "00283 "001A9 % LATIN CAPITAL LETTER ESH
+\setXTXcharcodes "001AA "001AA "001AA % LATIN LETTER REVERSED ESH LOOP
+\setXTXcharcodes "001AB "001AB "001AB % LATIN SMALL LETTER T WITH PALATAL HOOK
+\setXTXcharcodes "001AC "001AD "001AC % LATIN CAPITAL LETTER T WITH HOOK
+\setXTXcharcodes "001AD "001AD "001AC % LATIN SMALL LETTER T WITH HOOK
+\setXTXcharcodes "001AE "00288 "001AE % LATIN CAPITAL LETTER T WITH RETROFLEX HOOK
+\setXTXcharcodes "001AF "001B0 "001AF % LATIN CAPITAL LETTER U WITH HORN
+\setXTXcharcodes "001B0 "001B0 "001AF % LATIN SMALL LETTER U WITH HORN
+\setXTXcharcodes "001B1 "0028A "001B1 % LATIN CAPITAL LETTER UPSILON
+\setXTXcharcodes "001B2 "0028B "001B2 % LATIN CAPITAL LETTER V WITH HOOK
+\setXTXcharcodes "001B3 "001B4 "001B3 % LATIN CAPITAL LETTER Y WITH HOOK
+\setXTXcharcodes "001B4 "001B4 "001B3 % LATIN SMALL LETTER Y WITH HOOK
+\setXTXcharcodes "001B5 "001B6 "001B5 % LATIN CAPITAL LETTER Z WITH STROKE
+\setXTXcharcodes "001B6 "001B6 "001B5 % LATIN SMALL LETTER Z WITH STROKE
+\setXTXcharcodes "001B7 "00292 "001B7 % LATIN CAPITAL LETTER EZH
+\setXTXcharcodes "001B8 "001B9 "001B8 % LATIN CAPITAL LETTER EZH REVERSED
+\setXTXcharcodes "001B9 "001B9 "001B8 % LATIN SMALL LETTER EZH REVERSED
+\setXTXcharcodes "001BA "001BA "001BA % LATIN SMALL LETTER EZH WITH TAIL
+\setXTXcharcodes "001BC "001BD "001BC % LATIN CAPITAL LETTER TONE FIVE
+\setXTXcharcodes "001BD "001BD "001BC % LATIN SMALL LETTER TONE FIVE
+\setXTXcharcodes "001BE "001BE "001BE % LATIN LETTER INVERTED GLOTTAL STOP WITH STROKE
+\setXTXcharcodes "001BF "001BF "001F7 % LATIN LETTER WYNN
+\setXTXcharcodes "001C4 "001C6 "001C5 % LATIN CAPITAL LETTER DZ WITH CARON
+\setXTXcharcodes "001C5 "001C6 "001C4 % LATIN CAPITAL LETTER D WITH SMALL LETTER Z WITH CARON
+\setXTXcharcodes "001C6 "001C6 "001C4 % LATIN SMALL LETTER DZ WITH CARON
+\setXTXcharcodes "001C7 "001C9 "001C8 % LATIN CAPITAL LETTER LJ
+\setXTXcharcodes "001C8 "001C9 "001C7 % LATIN CAPITAL LETTER L WITH SMALL LETTER J
+\setXTXcharcodes "001C9 "001C9 "001C7 % LATIN SMALL LETTER LJ
+\setXTXcharcodes "001CA "001CC "001CB % LATIN CAPITAL LETTER NJ
+\setXTXcharcodes "001CB "001CC "001CA % LATIN CAPITAL LETTER N WITH SMALL LETTER J
+\setXTXcharcodes "001CC "001CC "001CA % LATIN SMALL LETTER NJ
+\setXTXcharcodes "001CD "001CE "001CD % LATIN CAPITAL LETTER A WITH CARON
+\setXTXcharcodes "001CE "001CE "001CD % LATIN SMALL LETTER A WITH CARON
+\setXTXcharcodes "001CF "001D0 "001CF % LATIN CAPITAL LETTER I WITH CARON
+\setXTXcharcodes "001D0 "001D0 "001CF % LATIN SMALL LETTER I WITH CARON
+\setXTXcharcodes "001D1 "001D2 "001D1 % LATIN CAPITAL LETTER O WITH CARON
+\setXTXcharcodes "001D2 "001D2 "001D1 % LATIN SMALL LETTER O WITH CARON
+\setXTXcharcodes "001D3 "001D4 "001D3 % LATIN CAPITAL LETTER U WITH CARON
+\setXTXcharcodes "001D4 "001D4 "001D3 % LATIN SMALL LETTER U WITH CARON
+\setXTXcharcodes "001D5 "001D6 "001D5 % LATIN CAPITAL LETTER U WITH DIAERESIS AND MACRON
+\setXTXcharcodes "001D6 "001D6 "001D5 % LATIN SMALL LETTER U WITH DIAERESIS AND MACRON
+\setXTXcharcodes "001D7 "001D8 "001D7 % LATIN CAPITAL LETTER U WITH DIAERESIS AND ACUTE
+\setXTXcharcodes "001D8 "001D8 "001D7 % LATIN SMALL LETTER U WITH DIAERESIS AND ACUTE
+\setXTXcharcodes "001D9 "001DA "001D9 % LATIN CAPITAL LETTER U WITH DIAERESIS AND CARON
+\setXTXcharcodes "001DA "001DA "001D9 % LATIN SMALL LETTER U WITH DIAERESIS AND CARON
+\setXTXcharcodes "001DB "001DC "001DB % LATIN CAPITAL LETTER U WITH DIAERESIS AND GRAVE
+\setXTXcharcodes "001DC "001DC "001DB % LATIN SMALL LETTER U WITH DIAERESIS AND GRAVE
+\setXTXcharcodes "001DD "001DD "0018E % LATIN SMALL LETTER TURNED E
+\setXTXcharcodes "001DE "001DF "001DE % LATIN CAPITAL LETTER A WITH DIAERESIS AND MACRON
+\setXTXcharcodes "001DF "001DF "001DE % LATIN SMALL LETTER A WITH DIAERESIS AND MACRON
+\setXTXcharcodes "001E0 "001E1 "001E0 % LATIN CAPITAL LETTER A WITH DOT ABOVE AND MACRON
+\setXTXcharcodes "001E1 "001E1 "001E0 % LATIN SMALL LETTER A WITH DOT ABOVE AND MACRON
+\setXTXcharcodes "001E2 "001E3 "001E2 % LATIN CAPITAL LETTER AE WITH MACRON
+\setXTXcharcodes "001E3 "001E3 "001E2 % LATIN SMALL LETTER AE WITH MACRON
+\setXTXcharcodes "001E4 "001E5 "001E4 % LATIN CAPITAL LETTER G WITH STROKE
+\setXTXcharcodes "001E5 "001E5 "001E4 % LATIN SMALL LETTER G WITH STROKE
+\setXTXcharcodes "001E6 "001E7 "001E6 % LATIN CAPITAL LETTER G WITH CARON
+\setXTXcharcodes "001E7 "001E7 "001E6 % LATIN SMALL LETTER G WITH CARON
+\setXTXcharcodes "001E8 "001E9 "001E8 % LATIN CAPITAL LETTER K WITH CARON
+\setXTXcharcodes "001E9 "001E9 "001E8 % LATIN SMALL LETTER K WITH CARON
+\setXTXcharcodes "001EA "001EB "001EA % LATIN CAPITAL LETTER O WITH OGONEK
+\setXTXcharcodes "001EB "001EB "001EA % LATIN SMALL LETTER O WITH OGONEK
+\setXTXcharcodes "001EC "001ED "001EC % LATIN CAPITAL LETTER O WITH OGONEK AND MACRON
+\setXTXcharcodes "001ED "001ED "001EC % LATIN SMALL LETTER O WITH OGONEK AND MACRON
+\setXTXcharcodes "001EE "001EF "001EE % LATIN CAPITAL LETTER EZH WITH CARON
+\setXTXcharcodes "001EF "001EF "001EE % LATIN SMALL LETTER EZH WITH CARON
+\setXTXcharcodes "001F0 "001F0 "001F0 % LATIN SMALL LETTER J WITH CARON
+\setXTXcharcodes "001F1 "001F3 "001F2 % LATIN CAPITAL LETTER DZ
+\setXTXcharcodes "001F2 "001F3 "001F1 % LATIN CAPITAL LETTER D WITH SMALL LETTER Z
+\setXTXcharcodes "001F3 "001F3 "001F1 % LATIN SMALL LETTER DZ
+\setXTXcharcodes "001F4 "001F5 "001F4 % LATIN CAPITAL LETTER G WITH ACUTE
+\setXTXcharcodes "001F5 "001F5 "001F4 % LATIN SMALL LETTER G WITH ACUTE
+\setXTXcharcodes "001F6 "00195 "001F6 % LATIN CAPITAL LETTER HWAIR
+\setXTXcharcodes "001F7 "001BF "001F7 % LATIN CAPITAL LETTER WYNN
+\setXTXcharcodes "001F8 "001F9 "001F8 % LATIN CAPITAL LETTER N WITH GRAVE
+\setXTXcharcodes "001F9 "001F9 "001F8 % LATIN SMALL LETTER N WITH GRAVE
+\setXTXcharcodes "001FA "001FB "001FA % LATIN CAPITAL LETTER A WITH RING ABOVE AND ACUTE
+\setXTXcharcodes "001FB "001FB "001FA % LATIN SMALL LETTER A WITH RING ABOVE AND ACUTE
+\setXTXcharcodes "001FC "001FD "001FC % LATIN CAPITAL LETTER AE WITH ACUTE
+\setXTXcharcodes "001FD "001FD "001FC % LATIN SMALL LETTER AE WITH ACUTE
+\setXTXcharcodes "001FE "001FF "001FE % LATIN CAPITAL LETTER O WITH STROKE AND ACUTE
+\setXTXcharcodes "001FF "001FF "001FE % LATIN SMALL LETTER O WITH STROKE AND ACUTE
+\setXTXcharcodes "00200 "00201 "00200 % LATIN CAPITAL LETTER A WITH DOUBLE GRAVE
+\setXTXcharcodes "00201 "00201 "00200 % LATIN SMALL LETTER A WITH DOUBLE GRAVE
+\setXTXcharcodes "00202 "00203 "00202 % LATIN CAPITAL LETTER A WITH INVERTED BREVE
+\setXTXcharcodes "00203 "00203 "00202 % LATIN SMALL LETTER A WITH INVERTED BREVE
+\setXTXcharcodes "00204 "00205 "00204 % LATIN CAPITAL LETTER E WITH DOUBLE GRAVE
+\setXTXcharcodes "00205 "00205 "00204 % LATIN SMALL LETTER E WITH DOUBLE GRAVE
+\setXTXcharcodes "00206 "00207 "00206 % LATIN CAPITAL LETTER E WITH INVERTED BREVE
+\setXTXcharcodes "00207 "00207 "00206 % LATIN SMALL LETTER E WITH INVERTED BREVE
+\setXTXcharcodes "00208 "00209 "00208 % LATIN CAPITAL LETTER I WITH DOUBLE GRAVE
+\setXTXcharcodes "00209 "00209 "00208 % LATIN SMALL LETTER I WITH DOUBLE GRAVE
+\setXTXcharcodes "0020A "0020B "0020A % LATIN CAPITAL LETTER I WITH INVERTED BREVE
+\setXTXcharcodes "0020B "0020B "0020A % LATIN SMALL LETTER I WITH INVERTED BREVE
+\setXTXcharcodes "0020C "0020D "0020C % LATIN CAPITAL LETTER O WITH DOUBLE GRAVE
+\setXTXcharcodes "0020D "0020D "0020C % LATIN SMALL LETTER O WITH DOUBLE GRAVE
+\setXTXcharcodes "0020E "0020F "0020E % LATIN CAPITAL LETTER O WITH INVERTED BREVE
+\setXTXcharcodes "0020F "0020F "0020E % LATIN SMALL LETTER O WITH INVERTED BREVE
+\setXTXcharcodes "00210 "00211 "00210 % LATIN CAPITAL LETTER R WITH DOUBLE GRAVE
+\setXTXcharcodes "00211 "00211 "00210 % LATIN SMALL LETTER R WITH DOUBLE GRAVE
+\setXTXcharcodes "00212 "00213 "00212 % LATIN CAPITAL LETTER R WITH INVERTED BREVE
+\setXTXcharcodes "00213 "00213 "00212 % LATIN SMALL LETTER R WITH INVERTED BREVE
+\setXTXcharcodes "00214 "00215 "00214 % LATIN CAPITAL LETTER U WITH DOUBLE GRAVE
+\setXTXcharcodes "00215 "00215 "00214 % LATIN SMALL LETTER U WITH DOUBLE GRAVE
+\setXTXcharcodes "00216 "00217 "00216 % LATIN CAPITAL LETTER U WITH INVERTED BREVE
+\setXTXcharcodes "00217 "00217 "00216 % LATIN SMALL LETTER U WITH INVERTED BREVE
+\setXTXcharcodes "00218 "00219 "00218 % LATIN CAPITAL LETTER S WITH COMMA BELOW
+\setXTXcharcodes "00219 "00219 "00218 % LATIN SMALL LETTER S WITH COMMA BELOW
+\setXTXcharcodes "0021A "0021B "0021A % LATIN CAPITAL LETTER T WITH COMMA BELOW
+\setXTXcharcodes "0021B "0021B "0021A % LATIN SMALL LETTER T WITH COMMA BELOW
+\setXTXcharcodes "0021C "0021D "0021C % LATIN CAPITAL LETTER YOGH
+\setXTXcharcodes "0021D "0021D "0021C % LATIN SMALL LETTER YOGH
+\setXTXcharcodes "0021E "0021F "0021E % LATIN CAPITAL LETTER H WITH CARON
+\setXTXcharcodes "0021F "0021F "0021E % LATIN SMALL LETTER H WITH CARON
+\setXTXcharcodes "00220 "0019E "00220 % LATIN CAPITAL LETTER N WITH LONG RIGHT LEG
+\setXTXcharcodes "00221 "00221 "00221 % LATIN SMALL LETTER D WITH CURL
+\setXTXcharcodes "00222 "00223 "00222 % LATIN CAPITAL LETTER OU
+\setXTXcharcodes "00223 "00223 "00222 % LATIN SMALL LETTER OU
+\setXTXcharcodes "00224 "00225 "00224 % LATIN CAPITAL LETTER Z WITH HOOK
+\setXTXcharcodes "00225 "00225 "00224 % LATIN SMALL LETTER Z WITH HOOK
+\setXTXcharcodes "00226 "00227 "00226 % LATIN CAPITAL LETTER A WITH DOT ABOVE
+\setXTXcharcodes "00227 "00227 "00226 % LATIN SMALL LETTER A WITH DOT ABOVE
+\setXTXcharcodes "00228 "00229 "00228 % LATIN CAPITAL LETTER E WITH CEDILLA
+\setXTXcharcodes "00229 "00229 "00228 % LATIN SMALL LETTER E WITH CEDILLA
+\setXTXcharcodes "0022A "0022B "0022A % LATIN CAPITAL LETTER O WITH DIAERESIS AND MACRON
+\setXTXcharcodes "0022B "0022B "0022A % LATIN SMALL LETTER O WITH DIAERESIS AND MACRON
+\setXTXcharcodes "0022C "0022D "0022C % LATIN CAPITAL LETTER O WITH TILDE AND MACRON
+\setXTXcharcodes "0022D "0022D "0022C % LATIN SMALL LETTER O WITH TILDE AND MACRON
+\setXTXcharcodes "0022E "0022F "0022E % LATIN CAPITAL LETTER O WITH DOT ABOVE
+\setXTXcharcodes "0022F "0022F "0022E % LATIN SMALL LETTER O WITH DOT ABOVE
+\setXTXcharcodes "00230 "00231 "00230 % LATIN CAPITAL LETTER O WITH DOT ABOVE AND MACRON
+\setXTXcharcodes "00231 "00231 "00230 % LATIN SMALL LETTER O WITH DOT ABOVE AND MACRON
+\setXTXcharcodes "00232 "00233 "00232 % LATIN CAPITAL LETTER Y WITH MACRON
+\setXTXcharcodes "00233 "00233 "00232 % LATIN SMALL LETTER Y WITH MACRON
+\setXTXcharcodes "00234 "00234 "00234 % LATIN SMALL LETTER L WITH CURL
+\setXTXcharcodes "00235 "00235 "00235 % LATIN SMALL LETTER N WITH CURL
+\setXTXcharcodes "00236 "00236 "00236 % LATIN SMALL LETTER T WITH CURL
+\setXTXcharcodes "00237 "00237 "00237 % LATIN SMALL LETTER DOTLESS J
+\setXTXcharcodes "00238 "00238 "00238 % LATIN SMALL LETTER DB DIGRAPH
+\setXTXcharcodes "00239 "00239 "00239 % LATIN SMALL LETTER QP DIGRAPH
+\setXTXcharcodes "0023A "02C65 "0023A % LATIN CAPITAL LETTER A WITH STROKE
+\setXTXcharcodes "0023B "0023C "0023B % LATIN CAPITAL LETTER C WITH STROKE
+\setXTXcharcodes "0023C "0023C "0023B % LATIN SMALL LETTER C WITH STROKE
+\setXTXcharcodes "0023D "0019A "0023D % LATIN CAPITAL LETTER L WITH BAR
+\setXTXcharcodes "0023E "02C66 "0023E % LATIN CAPITAL LETTER T WITH DIAGONAL STROKE
+\setXTXcharcodes "0023F "0023F "0023F % LATIN SMALL LETTER S WITH SWASH TAIL
+\setXTXcharcodes "00240 "00240 "00240 % LATIN SMALL LETTER Z WITH SWASH TAIL
+\setXTXcharcodes "00241 "00242 "00241 % LATIN CAPITAL LETTER GLOTTAL STOP
+\setXTXcharcodes "00242 "00242 "00241 % LATIN SMALL LETTER GLOTTAL STOP
+\setXTXcharcodes "00243 "00180 "00243 % LATIN CAPITAL LETTER B WITH STROKE
+\setXTXcharcodes "00244 "00289 "00244 % LATIN CAPITAL LETTER U BAR
+\setXTXcharcodes "00245 "0028C "00245 % LATIN CAPITAL LETTER TURNED V
+\setXTXcharcodes "00246 "00247 "00246 % LATIN CAPITAL LETTER E WITH STROKE
+\setXTXcharcodes "00247 "00247 "00246 % LATIN SMALL LETTER E WITH STROKE
+\setXTXcharcodes "00248 "00249 "00248 % LATIN CAPITAL LETTER J WITH STROKE
+\setXTXcharcodes "00249 "00249 "00248 % LATIN SMALL LETTER J WITH STROKE
+\setXTXcharcodes "0024A "0024B "0024A % LATIN CAPITAL LETTER SMALL Q WITH HOOK TAIL
+\setXTXcharcodes "0024B "0024B "0024A % LATIN SMALL LETTER Q WITH HOOK TAIL
+\setXTXcharcodes "0024C "0024D "0024C % LATIN CAPITAL LETTER R WITH STROKE
+\setXTXcharcodes "0024D "0024D "0024C % LATIN SMALL LETTER R WITH STROKE
+\setXTXcharcodes "0024E "0024F "0024E % LATIN CAPITAL LETTER Y WITH STROKE
+\setXTXcharcodes "0024F "0024F "0024E % LATIN SMALL LETTER Y WITH STROKE
+\setXTXcharcodes "00250 "00250 "00250 % LATIN SMALL LETTER TURNED A
+\setXTXcharcodes "00251 "00251 "00251 % LATIN SMALL LETTER ALPHA
+\setXTXcharcodes "00252 "00252 "00252 % LATIN SMALL LETTER TURNED ALPHA
+\setXTXcharcodes "00253 "00253 "00181 % LATIN SMALL LETTER B WITH HOOK
+\setXTXcharcodes "00254 "00254 "00186 % LATIN SMALL LETTER OPEN O
+\setXTXcharcodes "00255 "00255 "00255 % LATIN SMALL LETTER C WITH CURL
+\setXTXcharcodes "00256 "00256 "00189 % LATIN SMALL LETTER D WITH TAIL
+\setXTXcharcodes "00257 "00257 "0018A % LATIN SMALL LETTER D WITH HOOK
+\setXTXcharcodes "00258 "00258 "00258 % LATIN SMALL LETTER REVERSED E
+\setXTXcharcodes "00259 "00259 "0018F % LATIN SMALL LETTER SCHWA
+\setXTXcharcodes "0025A "0025A "0025A % LATIN SMALL LETTER SCHWA WITH HOOK
+\setXTXcharcodes "0025B "0025B "00190 % LATIN SMALL LETTER OPEN E
+\setXTXcharcodes "0025C "0025C "0025C % LATIN SMALL LETTER REVERSED OPEN E
+\setXTXcharcodes "0025D "0025D "0025D % LATIN SMALL LETTER REVERSED OPEN E WITH HOOK
+\setXTXcharcodes "0025E "0025E "0025E % LATIN SMALL LETTER CLOSED REVERSED OPEN E
+\setXTXcharcodes "0025F "0025F "0025F % LATIN SMALL LETTER DOTLESS J WITH STROKE
+\setXTXcharcodes "00260 "00260 "00193 % LATIN SMALL LETTER G WITH HOOK
+\setXTXcharcodes "00261 "00261 "00261 % LATIN SMALL LETTER SCRIPT G
+\setXTXcharcodes "00262 "00262 "00262 % LATIN LETTER SMALL CAPITAL G
+\setXTXcharcodes "00263 "00263 "00194 % LATIN SMALL LETTER GAMMA
+\setXTXcharcodes "00264 "00264 "00264 % LATIN SMALL LETTER RAMS HORN
+\setXTXcharcodes "00265 "00265 "00265 % LATIN SMALL LETTER TURNED H
+\setXTXcharcodes "00266 "00266 "00266 % LATIN SMALL LETTER H WITH HOOK
+\setXTXcharcodes "00267 "00267 "00267 % LATIN SMALL LETTER HENG WITH HOOK
+\setXTXcharcodes "00268 "00268 "00197 % LATIN SMALL LETTER I WITH STROKE
+\setXTXcharcodes "00269 "00269 "00196 % LATIN SMALL LETTER IOTA
+\setXTXcharcodes "0026A "0026A "0026A % LATIN LETTER SMALL CAPITAL I
+\setXTXcharcodes "0026B "0026B "02C62 % LATIN SMALL LETTER L WITH MIDDLE TILDE
+\setXTXcharcodes "0026C "0026C "0026C % LATIN SMALL LETTER L WITH BELT
+\setXTXcharcodes "0026D "0026D "0026D % LATIN SMALL LETTER L WITH RETROFLEX HOOK
+\setXTXcharcodes "0026E "0026E "0026E % LATIN SMALL LETTER LEZH
+\setXTXcharcodes "0026F "0026F "0019C % LATIN SMALL LETTER TURNED M
+\setXTXcharcodes "00270 "00270 "00270 % LATIN SMALL LETTER TURNED M WITH LONG LEG
+\setXTXcharcodes "00271 "00271 "00271 % LATIN SMALL LETTER M WITH HOOK
+\setXTXcharcodes "00272 "00272 "0019D % LATIN SMALL LETTER N WITH LEFT HOOK
+\setXTXcharcodes "00273 "00273 "00273 % LATIN SMALL LETTER N WITH RETROFLEX HOOK
+\setXTXcharcodes "00274 "00274 "00274 % LATIN LETTER SMALL CAPITAL N
+\setXTXcharcodes "00275 "00275 "0019F % LATIN SMALL LETTER BARRED O
+\setXTXcharcodes "00276 "00276 "00276 % LATIN LETTER SMALL CAPITAL OE
+\setXTXcharcodes "00277 "00277 "00277 % LATIN SMALL LETTER CLOSED OMEGA
+\setXTXcharcodes "00278 "00278 "00278 % LATIN SMALL LETTER PHI
+\setXTXcharcodes "00279 "00279 "00279 % LATIN SMALL LETTER TURNED R
+\setXTXcharcodes "0027A "0027A "0027A % LATIN SMALL LETTER TURNED R WITH LONG LEG
+\setXTXcharcodes "0027B "0027B "0027B % LATIN SMALL LETTER TURNED R WITH HOOK
+\setXTXcharcodes "0027C "0027C "0027C % LATIN SMALL LETTER R WITH LONG LEG
+\setXTXcharcodes "0027D "0027D "02C64 % LATIN SMALL LETTER R WITH TAIL
+\setXTXcharcodes "0027E "0027E "0027E % LATIN SMALL LETTER R WITH FISHHOOK
+\setXTXcharcodes "0027F "0027F "0027F % LATIN SMALL LETTER REVERSED R WITH FISHHOOK
+\setXTXcharcodes "00280 "00280 "001A6 % LATIN LETTER SMALL CAPITAL R
+\setXTXcharcodes "00281 "00281 "00281 % LATIN LETTER SMALL CAPITAL INVERTED R
+\setXTXcharcodes "00282 "00282 "00282 % LATIN SMALL LETTER S WITH HOOK
+\setXTXcharcodes "00283 "00283 "001A9 % LATIN SMALL LETTER ESH
+\setXTXcharcodes "00284 "00284 "00284 % LATIN SMALL LETTER DOTLESS J WITH STROKE AND HOOK
+\setXTXcharcodes "00285 "00285 "00285 % LATIN SMALL LETTER SQUAT REVERSED ESH
+\setXTXcharcodes "00286 "00286 "00286 % LATIN SMALL LETTER ESH WITH CURL
+\setXTXcharcodes "00287 "00287 "00287 % LATIN SMALL LETTER TURNED T
+\setXTXcharcodes "00288 "00288 "001AE % LATIN SMALL LETTER T WITH RETROFLEX HOOK
+\setXTXcharcodes "00289 "00289 "00244 % LATIN SMALL LETTER U BAR
+\setXTXcharcodes "0028A "0028A "001B1 % LATIN SMALL LETTER UPSILON
+\setXTXcharcodes "0028B "0028B "001B2 % LATIN SMALL LETTER V WITH HOOK
+\setXTXcharcodes "0028C "0028C "00245 % LATIN SMALL LETTER TURNED V
+\setXTXcharcodes "0028D "0028D "0028D % LATIN SMALL LETTER TURNED W
+\setXTXcharcodes "0028E "0028E "0028E % LATIN SMALL LETTER TURNED Y
+\setXTXcharcodes "0028F "0028F "0028F % LATIN LETTER SMALL CAPITAL Y
+\setXTXcharcodes "00290 "00290 "00290 % LATIN SMALL LETTER Z WITH RETROFLEX HOOK
+\setXTXcharcodes "00291 "00291 "00291 % LATIN SMALL LETTER Z WITH CURL
+\setXTXcharcodes "00292 "00292 "001B7 % LATIN SMALL LETTER EZH
+\setXTXcharcodes "00293 "00293 "00293 % LATIN SMALL LETTER EZH WITH CURL
+\setXTXcharcodes "00295 "00295 "00295 % LATIN LETTER PHARYNGEAL VOICED FRICATIVE
+\setXTXcharcodes "00296 "00296 "00296 % LATIN LETTER INVERTED GLOTTAL STOP
+\setXTXcharcodes "00297 "00297 "00297 % LATIN LETTER STRETCHED C
+\setXTXcharcodes "00298 "00298 "00298 % LATIN LETTER BILABIAL CLICK
+\setXTXcharcodes "00299 "00299 "00299 % LATIN LETTER SMALL CAPITAL B
+\setXTXcharcodes "0029A "0029A "0029A % LATIN SMALL LETTER CLOSED OPEN E
+\setXTXcharcodes "0029B "0029B "0029B % LATIN LETTER SMALL CAPITAL G WITH HOOK
+\setXTXcharcodes "0029C "0029C "0029C % LATIN LETTER SMALL CAPITAL H
+\setXTXcharcodes "0029D "0029D "0029D % LATIN SMALL LETTER J WITH CROSSED-TAIL
+\setXTXcharcodes "0029E "0029E "0029E % LATIN SMALL LETTER TURNED K
+\setXTXcharcodes "0029F "0029F "0029F % LATIN LETTER SMALL CAPITAL L
+\setXTXcharcodes "002A0 "002A0 "002A0 % LATIN SMALL LETTER Q WITH HOOK
+\setXTXcharcodes "002A1 "002A1 "002A1 % LATIN LETTER GLOTTAL STOP WITH STROKE
+\setXTXcharcodes "002A2 "002A2 "002A2 % LATIN LETTER REVERSED GLOTTAL STOP WITH STROKE
+\setXTXcharcodes "002A3 "002A3 "002A3 % LATIN SMALL LETTER DZ DIGRAPH
+\setXTXcharcodes "002A4 "002A4 "002A4 % LATIN SMALL LETTER DEZH DIGRAPH
+\setXTXcharcodes "002A5 "002A5 "002A5 % LATIN SMALL LETTER DZ DIGRAPH WITH CURL
+\setXTXcharcodes "002A6 "002A6 "002A6 % LATIN SMALL LETTER TS DIGRAPH
+\setXTXcharcodes "002A7 "002A7 "002A7 % LATIN SMALL LETTER TESH DIGRAPH
+\setXTXcharcodes "002A8 "002A8 "002A8 % LATIN SMALL LETTER TC DIGRAPH WITH CURL
+\setXTXcharcodes "002A9 "002A9 "002A9 % LATIN SMALL LETTER FENG DIGRAPH
+\setXTXcharcodes "002AA "002AA "002AA % LATIN SMALL LETTER LS DIGRAPH
+\setXTXcharcodes "002AB "002AB "002AB % LATIN SMALL LETTER LZ DIGRAPH
+\setXTXcharcodes "002AC "002AC "002AC % LATIN LETTER BILABIAL PERCUSSIVE
+\setXTXcharcodes "002AD "002AD "002AD % LATIN LETTER BIDENTAL PERCUSSIVE
+\setXTXcharcodes "002AE "002AE "002AE % LATIN SMALL LETTER TURNED H WITH FISHHOOK
+\setXTXcharcodes "002AF "002AF "002AF % LATIN SMALL LETTER TURNED H WITH FISHHOOK AND TAIL
+\setXTXcharcodes "0037B "0037B "003FD % GREEK SMALL REVERSED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "0037C "0037C "003FE % GREEK SMALL DOTTED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "0037D "0037D "003FF % GREEK SMALL REVERSED DOTTED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "00386 "003AC "00386 % GREEK CAPITAL LETTER ALPHA WITH TONOS
+\setXTXcharcodes "00388 "003AD "00388 % GREEK CAPITAL LETTER EPSILON WITH TONOS
+\setXTXcharcodes "00389 "003AE "00389 % GREEK CAPITAL LETTER ETA WITH TONOS
+\setXTXcharcodes "0038A "003AF "0038A % GREEK CAPITAL LETTER IOTA WITH TONOS
+\setXTXcharcodes "0038C "003CC "0038C % GREEK CAPITAL LETTER OMICRON WITH TONOS
+\setXTXcharcodes "0038E "003CD "0038E % GREEK CAPITAL LETTER UPSILON WITH TONOS
+\setXTXcharcodes "0038F "003CE "0038F % GREEK CAPITAL LETTER OMEGA WITH TONOS
+\setXTXcharcodes "00390 "00390 "00390 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND TONOS
+\setXTXcharcodes "00391 "003B1 "00391 % GREEK CAPITAL LETTER ALPHA
+\setXTXcharcodes "00392 "003B2 "00392 % GREEK CAPITAL LETTER BETA
+\setXTXcharcodes "00393 "003B3 "00393 % GREEK CAPITAL LETTER GAMMA
+\setXTXcharcodes "00394 "003B4 "00394 % GREEK CAPITAL LETTER DELTA
+\setXTXcharcodes "00395 "003B5 "00395 % GREEK CAPITAL LETTER EPSILON
+\setXTXcharcodes "00396 "003B6 "00396 % GREEK CAPITAL LETTER ZETA
+\setXTXcharcodes "00397 "003B7 "00397 % GREEK CAPITAL LETTER ETA
+\setXTXcharcodes "00398 "003B8 "00398 % GREEK CAPITAL LETTER THETA
+\setXTXcharcodes "00399 "003B9 "00399 % GREEK CAPITAL LETTER IOTA
+\setXTXcharcodes "0039A "003BA "0039A % GREEK CAPITAL LETTER KAPPA
+\setXTXcharcodes "0039B "003BB "0039B % GREEK CAPITAL LETTER LAMDA
+\setXTXcharcodes "0039C "003BC "0039C % GREEK CAPITAL LETTER MU
+\setXTXcharcodes "0039D "003BD "0039D % GREEK CAPITAL LETTER NU
+\setXTXcharcodes "0039E "003BE "0039E % GREEK CAPITAL LETTER XI
+\setXTXcharcodes "0039F "003BF "0039F % GREEK CAPITAL LETTER OMICRON
+\setXTXcharcodes "003A0 "003C0 "003A0 % GREEK CAPITAL LETTER PI
+\setXTXcharcodes "003A1 "003C1 "003A1 % GREEK CAPITAL LETTER RHO
+\setXTXcharcodes "003A3 "003C3 "003A3 % GREEK CAPITAL LETTER SIGMA
+\setXTXcharcodes "003A4 "003C4 "003A4 % GREEK CAPITAL LETTER TAU
+\setXTXcharcodes "003A5 "003C5 "003A5 % GREEK CAPITAL LETTER UPSILON
+\setXTXcharcodes "003A6 "003C6 "003A6 % GREEK CAPITAL LETTER PHI
+\setXTXcharcodes "003A7 "003C7 "003A7 % GREEK CAPITAL LETTER CHI
+\setXTXcharcodes "003A8 "003C8 "003A8 % GREEK CAPITAL LETTER PSI
+\setXTXcharcodes "003A9 "003C9 "003A9 % GREEK CAPITAL LETTER OMEGA
+\setXTXcharcodes "003AA "003CA "003AA % GREEK CAPITAL LETTER IOTA WITH DIALYTIKA
+\setXTXcharcodes "003AB "003CB "003AB % GREEK CAPITAL LETTER UPSILON WITH DIALYTIKA
+\setXTXcharcodes "003AC "003AC "00386 % GREEK SMALL LETTER ALPHA WITH TONOS
+\setXTXcharcodes "003AD "003AD "00388 % GREEK SMALL LETTER EPSILON WITH TONOS
+\setXTXcharcodes "003AE "003AE "00389 % GREEK SMALL LETTER ETA WITH TONOS
+\setXTXcharcodes "003AF "003AF "0038A % GREEK SMALL LETTER IOTA WITH TONOS
+\setXTXcharcodes "003B0 "003B0 "003B0 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND TONOS
+\setXTXcharcodes "003B1 "003B1 "00391 % GREEK SMALL LETTER ALPHA
+\setXTXcharcodes "003B2 "003B2 "00392 % GREEK SMALL LETTER BETA
+\setXTXcharcodes "003B3 "003B3 "00393 % GREEK SMALL LETTER GAMMA
+\setXTXcharcodes "003B4 "003B4 "00394 % GREEK SMALL LETTER DELTA
+\setXTXcharcodes "003B5 "003B5 "00395 % GREEK SMALL LETTER EPSILON
+\setXTXcharcodes "003B6 "003B6 "00396 % GREEK SMALL LETTER ZETA
+\setXTXcharcodes "003B7 "003B7 "00397 % GREEK SMALL LETTER ETA
+\setXTXcharcodes "003B8 "003B8 "00398 % GREEK SMALL LETTER THETA
+\setXTXcharcodes "003B9 "003B9 "00399 % GREEK SMALL LETTER IOTA
+\setXTXcharcodes "003BA "003BA "0039A % GREEK SMALL LETTER KAPPA
+\setXTXcharcodes "003BB "003BB "0039B % GREEK SMALL LETTER LAMDA
+\setXTXcharcodes "003BC "003BC "0039C % GREEK SMALL LETTER MU
+\setXTXcharcodes "003BD "003BD "0039D % GREEK SMALL LETTER NU
+\setXTXcharcodes "003BE "003BE "0039E % GREEK SMALL LETTER XI
+\setXTXcharcodes "003BF "003BF "0039F % GREEK SMALL LETTER OMICRON
+\setXTXcharcodes "003C0 "003C0 "003A0 % GREEK SMALL LETTER PI
+\setXTXcharcodes "003C1 "003C1 "003A1 % GREEK SMALL LETTER RHO
+\setXTXcharcodes "003C2 "003C2 "003A3 % GREEK SMALL LETTER FINAL SIGMA
+\setXTXcharcodes "003C3 "003C3 "003A3 % GREEK SMALL LETTER SIGMA
+\setXTXcharcodes "003C4 "003C4 "003A4 % GREEK SMALL LETTER TAU
+\setXTXcharcodes "003C5 "003C5 "003A5 % GREEK SMALL LETTER UPSILON
+\setXTXcharcodes "003C6 "003C6 "003A6 % GREEK SMALL LETTER PHI
+\setXTXcharcodes "003C7 "003C7 "003A7 % GREEK SMALL LETTER CHI
+\setXTXcharcodes "003C8 "003C8 "003A8 % GREEK SMALL LETTER PSI
+\setXTXcharcodes "003C9 "003C9 "003A9 % GREEK SMALL LETTER OMEGA
+\setXTXcharcodes "003CA "003CA "003AA % GREEK SMALL LETTER IOTA WITH DIALYTIKA
+\setXTXcharcodes "003CB "003CB "003AB % GREEK SMALL LETTER UPSILON WITH DIALYTIKA
+\setXTXcharcodes "003CC "003CC "0038C % GREEK SMALL LETTER OMICRON WITH TONOS
+\setXTXcharcodes "003CD "003CD "0038E % GREEK SMALL LETTER UPSILON WITH TONOS
+\setXTXcharcodes "003CE "003CE "0038F % GREEK SMALL LETTER OMEGA WITH TONOS
+\setXTXcharcodes "003D0 "003D0 "00392 % GREEK BETA SYMBOL
+\setXTXcharcodes "003D1 "003D1 "00398 % GREEK THETA SYMBOL
+\setXTXcharcodes "003D2 "003D2 "003D2 % GREEK UPSILON WITH HOOK SYMBOL
+\setXTXcharcodes "003D3 "003D3 "003D3 % GREEK UPSILON WITH ACUTE AND HOOK SYMBOL
+\setXTXcharcodes "003D4 "003D4 "003D4 % GREEK UPSILON WITH DIAERESIS AND HOOK SYMBOL
+\setXTXcharcodes "003D5 "003D5 "003A6 % GREEK PHI SYMBOL
+\setXTXcharcodes "003D6 "003D6 "003A0 % GREEK PI SYMBOL
+\setXTXcharcodes "003D7 "003D7 "003D7 % GREEK KAI SYMBOL
+\setXTXcharcodes "003D8 "003D9 "003D8 % GREEK LETTER ARCHAIC KOPPA
+\setXTXcharcodes "003D9 "003D9 "003D8 % GREEK SMALL LETTER ARCHAIC KOPPA
+\setXTXcharcodes "003DA "003DB "003DA % GREEK LETTER STIGMA
+\setXTXcharcodes "003DB "003DB "003DA % GREEK SMALL LETTER STIGMA
+\setXTXcharcodes "003DC "003DD "003DC % GREEK LETTER DIGAMMA
+\setXTXcharcodes "003DD "003DD "003DC % GREEK SMALL LETTER DIGAMMA
+\setXTXcharcodes "003DE "003DF "003DE % GREEK LETTER KOPPA
+\setXTXcharcodes "003DF "003DF "003DE % GREEK SMALL LETTER KOPPA
+\setXTXcharcodes "003E0 "003E1 "003E0 % GREEK LETTER SAMPI
+\setXTXcharcodes "003E1 "003E1 "003E0 % GREEK SMALL LETTER SAMPI
+\setXTXcharcodes "003E2 "003E3 "003E2 % COPTIC CAPITAL LETTER SHEI
+\setXTXcharcodes "003E3 "003E3 "003E2 % COPTIC SMALL LETTER SHEI
+\setXTXcharcodes "003E4 "003E5 "003E4 % COPTIC CAPITAL LETTER FEI
+\setXTXcharcodes "003E5 "003E5 "003E4 % COPTIC SMALL LETTER FEI
+\setXTXcharcodes "003E6 "003E7 "003E6 % COPTIC CAPITAL LETTER KHEI
+\setXTXcharcodes "003E7 "003E7 "003E6 % COPTIC SMALL LETTER KHEI
+\setXTXcharcodes "003E8 "003E9 "003E8 % COPTIC CAPITAL LETTER HORI
+\setXTXcharcodes "003E9 "003E9 "003E8 % COPTIC SMALL LETTER HORI
+\setXTXcharcodes "003EA "003EB "003EA % COPTIC CAPITAL LETTER GANGIA
+\setXTXcharcodes "003EB "003EB "003EA % COPTIC SMALL LETTER GANGIA
+\setXTXcharcodes "003EC "003ED "003EC % COPTIC CAPITAL LETTER SHIMA
+\setXTXcharcodes "003ED "003ED "003EC % COPTIC SMALL LETTER SHIMA
+\setXTXcharcodes "003EE "003EF "003EE % COPTIC CAPITAL LETTER DEI
+\setXTXcharcodes "003EF "003EF "003EE % COPTIC SMALL LETTER DEI
+\setXTXcharcodes "003F0 "003F0 "0039A % GREEK KAPPA SYMBOL
+\setXTXcharcodes "003F1 "003F1 "003A1 % GREEK RHO SYMBOL
+\setXTXcharcodes "003F2 "003F2 "003F9 % GREEK LUNATE SIGMA SYMBOL
+\setXTXcharcodes "003F3 "003F3 "003F3 % GREEK LETTER YOT
+\setXTXcharcodes "003F4 "003B8 "003F4 % GREEK CAPITAL THETA SYMBOL
+\setXTXcharcodes "003F5 "003F5 "00395 % GREEK LUNATE EPSILON SYMBOL
+\setXTXcharcodes "003F7 "003F8 "003F7 % GREEK CAPITAL LETTER SHO
+\setXTXcharcodes "003F8 "003F8 "003F7 % GREEK SMALL LETTER SHO
+\setXTXcharcodes "003F9 "003F2 "003F9 % GREEK CAPITAL LUNATE SIGMA SYMBOL
+\setXTXcharcodes "003FA "003FB "003FA % GREEK CAPITAL LETTER SAN
+\setXTXcharcodes "003FB "003FB "003FA % GREEK SMALL LETTER SAN
+\setXTXcharcodes "003FC "003FC "003FC % GREEK RHO WITH STROKE SYMBOL
+\setXTXcharcodes "003FD "0037B "003FD % GREEK CAPITAL REVERSED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "003FE "0037C "003FE % GREEK CAPITAL DOTTED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "003FF "0037D "003FF % GREEK CAPITAL REVERSED DOTTED LUNATE SIGMA SYMBOL
+\setXTXcharcodes "00400 "00450 "00400 % CYRILLIC CAPITAL LETTER IE WITH GRAVE
+\setXTXcharcodes "00401 "00451 "00401 % CYRILLIC CAPITAL LETTER IO
+\setXTXcharcodes "00402 "00452 "00402 % CYRILLIC CAPITAL LETTER DJE
+\setXTXcharcodes "00403 "00453 "00403 % CYRILLIC CAPITAL LETTER GJE
+\setXTXcharcodes "00404 "00454 "00404 % CYRILLIC CAPITAL LETTER UKRAINIAN IE
+\setXTXcharcodes "00405 "00455 "00405 % CYRILLIC CAPITAL LETTER DZE
+\setXTXcharcodes "00406 "00456 "00406 % CYRILLIC CAPITAL LETTER BYELORUSSIAN-UKRAINIAN I
+\setXTXcharcodes "00407 "00457 "00407 % CYRILLIC CAPITAL LETTER YI
+\setXTXcharcodes "00408 "00458 "00408 % CYRILLIC CAPITAL LETTER JE
+\setXTXcharcodes "00409 "00459 "00409 % CYRILLIC CAPITAL LETTER LJE
+\setXTXcharcodes "0040A "0045A "0040A % CYRILLIC CAPITAL LETTER NJE
+\setXTXcharcodes "0040B "0045B "0040B % CYRILLIC CAPITAL LETTER TSHE
+\setXTXcharcodes "0040C "0045C "0040C % CYRILLIC CAPITAL LETTER KJE
+\setXTXcharcodes "0040D "0045D "0040D % CYRILLIC CAPITAL LETTER I WITH GRAVE
+\setXTXcharcodes "0040E "0045E "0040E % CYRILLIC CAPITAL LETTER SHORT U
+\setXTXcharcodes "0040F "0045F "0040F % CYRILLIC CAPITAL LETTER DZHE
+\setXTXcharcodes "00410 "00430 "00410 % CYRILLIC CAPITAL LETTER A
+\setXTXcharcodes "00411 "00431 "00411 % CYRILLIC CAPITAL LETTER BE
+\setXTXcharcodes "00412 "00432 "00412 % CYRILLIC CAPITAL LETTER VE
+\setXTXcharcodes "00413 "00433 "00413 % CYRILLIC CAPITAL LETTER GHE
+\setXTXcharcodes "00414 "00434 "00414 % CYRILLIC CAPITAL LETTER DE
+\setXTXcharcodes "00415 "00435 "00415 % CYRILLIC CAPITAL LETTER IE
+\setXTXcharcodes "00416 "00436 "00416 % CYRILLIC CAPITAL LETTER ZHE
+\setXTXcharcodes "00417 "00437 "00417 % CYRILLIC CAPITAL LETTER ZE
+\setXTXcharcodes "00418 "00438 "00418 % CYRILLIC CAPITAL LETTER I
+\setXTXcharcodes "00419 "00439 "00419 % CYRILLIC CAPITAL LETTER SHORT I
+\setXTXcharcodes "0041A "0043A "0041A % CYRILLIC CAPITAL LETTER KA
+\setXTXcharcodes "0041B "0043B "0041B % CYRILLIC CAPITAL LETTER EL
+\setXTXcharcodes "0041C "0043C "0041C % CYRILLIC CAPITAL LETTER EM
+\setXTXcharcodes "0041D "0043D "0041D % CYRILLIC CAPITAL LETTER EN
+\setXTXcharcodes "0041E "0043E "0041E % CYRILLIC CAPITAL LETTER O
+\setXTXcharcodes "0041F "0043F "0041F % CYRILLIC CAPITAL LETTER PE
+\setXTXcharcodes "00420 "00440 "00420 % CYRILLIC CAPITAL LETTER ER
+\setXTXcharcodes "00421 "00441 "00421 % CYRILLIC CAPITAL LETTER ES
+\setXTXcharcodes "00422 "00442 "00422 % CYRILLIC CAPITAL LETTER TE
+\setXTXcharcodes "00423 "00443 "00423 % CYRILLIC CAPITAL LETTER U
+\setXTXcharcodes "00424 "00444 "00424 % CYRILLIC CAPITAL LETTER EF
+\setXTXcharcodes "00425 "00445 "00425 % CYRILLIC CAPITAL LETTER HA
+\setXTXcharcodes "00426 "00446 "00426 % CYRILLIC CAPITAL LETTER TSE
+\setXTXcharcodes "00427 "00447 "00427 % CYRILLIC CAPITAL LETTER CHE
+\setXTXcharcodes "00428 "00448 "00428 % CYRILLIC CAPITAL LETTER SHA
+\setXTXcharcodes "00429 "00449 "00429 % CYRILLIC CAPITAL LETTER SHCHA
+\setXTXcharcodes "0042A "0044A "0042A % CYRILLIC CAPITAL LETTER HARD SIGN
+\setXTXcharcodes "0042B "0044B "0042B % CYRILLIC CAPITAL LETTER YERU
+\setXTXcharcodes "0042C "0044C "0042C % CYRILLIC CAPITAL LETTER SOFT SIGN
+\setXTXcharcodes "0042D "0044D "0042D % CYRILLIC CAPITAL LETTER E
+\setXTXcharcodes "0042E "0044E "0042E % CYRILLIC CAPITAL LETTER YU
+\setXTXcharcodes "0042F "0044F "0042F % CYRILLIC CAPITAL LETTER YA
+\setXTXcharcodes "00430 "00430 "00410 % CYRILLIC SMALL LETTER A
+\setXTXcharcodes "00431 "00431 "00411 % CYRILLIC SMALL LETTER BE
+\setXTXcharcodes "00432 "00432 "00412 % CYRILLIC SMALL LETTER VE
+\setXTXcharcodes "00433 "00433 "00413 % CYRILLIC SMALL LETTER GHE
+\setXTXcharcodes "00434 "00434 "00414 % CYRILLIC SMALL LETTER DE
+\setXTXcharcodes "00435 "00435 "00415 % CYRILLIC SMALL LETTER IE
+\setXTXcharcodes "00436 "00436 "00416 % CYRILLIC SMALL LETTER ZHE
+\setXTXcharcodes "00437 "00437 "00417 % CYRILLIC SMALL LETTER ZE
+\setXTXcharcodes "00438 "00438 "00418 % CYRILLIC SMALL LETTER I
+\setXTXcharcodes "00439 "00439 "00419 % CYRILLIC SMALL LETTER SHORT I
+\setXTXcharcodes "0043A "0043A "0041A % CYRILLIC SMALL LETTER KA
+\setXTXcharcodes "0043B "0043B "0041B % CYRILLIC SMALL LETTER EL
+\setXTXcharcodes "0043C "0043C "0041C % CYRILLIC SMALL LETTER EM
+\setXTXcharcodes "0043D "0043D "0041D % CYRILLIC SMALL LETTER EN
+\setXTXcharcodes "0043E "0043E "0041E % CYRILLIC SMALL LETTER O
+\setXTXcharcodes "0043F "0043F "0041F % CYRILLIC SMALL LETTER PE
+\setXTXcharcodes "00440 "00440 "00420 % CYRILLIC SMALL LETTER ER
+\setXTXcharcodes "00441 "00441 "00421 % CYRILLIC SMALL LETTER ES
+\setXTXcharcodes "00442 "00442 "00422 % CYRILLIC SMALL LETTER TE
+\setXTXcharcodes "00443 "00443 "00423 % CYRILLIC SMALL LETTER U
+\setXTXcharcodes "00444 "00444 "00424 % CYRILLIC SMALL LETTER EF
+\setXTXcharcodes "00445 "00445 "00425 % CYRILLIC SMALL LETTER HA
+\setXTXcharcodes "00446 "00446 "00426 % CYRILLIC SMALL LETTER TSE
+\setXTXcharcodes "00447 "00447 "00427 % CYRILLIC SMALL LETTER CHE
+\setXTXcharcodes "00448 "00448 "00428 % CYRILLIC SMALL LETTER SHA
+\setXTXcharcodes "00449 "00449 "00429 % CYRILLIC SMALL LETTER SHCHA
+\setXTXcharcodes "0044A "0044A "0042A % CYRILLIC SMALL LETTER HARD SIGN
+\setXTXcharcodes "0044B "0044B "0042B % CYRILLIC SMALL LETTER YERU
+\setXTXcharcodes "0044C "0044C "0042C % CYRILLIC SMALL LETTER SOFT SIGN
+\setXTXcharcodes "0044D "0044D "0042D % CYRILLIC SMALL LETTER E
+\setXTXcharcodes "0044E "0044E "0042E % CYRILLIC SMALL LETTER YU
+\setXTXcharcodes "0044F "0044F "0042F % CYRILLIC SMALL LETTER YA
+\setXTXcharcodes "00450 "00450 "00400 % CYRILLIC SMALL LETTER IE WITH GRAVE
+\setXTXcharcodes "00451 "00451 "00401 % CYRILLIC SMALL LETTER IO
+\setXTXcharcodes "00452 "00452 "00402 % CYRILLIC SMALL LETTER DJE
+\setXTXcharcodes "00453 "00453 "00403 % CYRILLIC SMALL LETTER GJE
+\setXTXcharcodes "00454 "00454 "00404 % CYRILLIC SMALL LETTER UKRAINIAN IE
+\setXTXcharcodes "00455 "00455 "00405 % CYRILLIC SMALL LETTER DZE
+\setXTXcharcodes "00456 "00456 "00406 % CYRILLIC SMALL LETTER BYELORUSSIAN-UKRAINIAN I
+\setXTXcharcodes "00457 "00457 "00407 % CYRILLIC SMALL LETTER YI
+\setXTXcharcodes "00458 "00458 "00408 % CYRILLIC SMALL LETTER JE
+\setXTXcharcodes "00459 "00459 "00409 % CYRILLIC SMALL LETTER LJE
+\setXTXcharcodes "0045A "0045A "0040A % CYRILLIC SMALL LETTER NJE
+\setXTXcharcodes "0045B "0045B "0040B % CYRILLIC SMALL LETTER TSHE
+\setXTXcharcodes "0045C "0045C "0040C % CYRILLIC SMALL LETTER KJE
+\setXTXcharcodes "0045D "0045D "0040D % CYRILLIC SMALL LETTER I WITH GRAVE
+\setXTXcharcodes "0045E "0045E "0040E % CYRILLIC SMALL LETTER SHORT U
+\setXTXcharcodes "0045F "0045F "0040F % CYRILLIC SMALL LETTER DZHE
+\setXTXcharcodes "00460 "00461 "00460 % CYRILLIC CAPITAL LETTER OMEGA
+\setXTXcharcodes "00461 "00461 "00460 % CYRILLIC SMALL LETTER OMEGA
+\setXTXcharcodes "00462 "00463 "00462 % CYRILLIC CAPITAL LETTER YAT
+\setXTXcharcodes "00463 "00463 "00462 % CYRILLIC SMALL LETTER YAT
+\setXTXcharcodes "00464 "00465 "00464 % CYRILLIC CAPITAL LETTER IOTIFIED E
+\setXTXcharcodes "00465 "00465 "00464 % CYRILLIC SMALL LETTER IOTIFIED E
+\setXTXcharcodes "00466 "00467 "00466 % CYRILLIC CAPITAL LETTER LITTLE YUS
+\setXTXcharcodes "00467 "00467 "00466 % CYRILLIC SMALL LETTER LITTLE YUS
+\setXTXcharcodes "00468 "00469 "00468 % CYRILLIC CAPITAL LETTER IOTIFIED LITTLE YUS
+\setXTXcharcodes "00469 "00469 "00468 % CYRILLIC SMALL LETTER IOTIFIED LITTLE YUS
+\setXTXcharcodes "0046A "0046B "0046A % CYRILLIC CAPITAL LETTER BIG YUS
+\setXTXcharcodes "0046B "0046B "0046A % CYRILLIC SMALL LETTER BIG YUS
+\setXTXcharcodes "0046C "0046D "0046C % CYRILLIC CAPITAL LETTER IOTIFIED BIG YUS
+\setXTXcharcodes "0046D "0046D "0046C % CYRILLIC SMALL LETTER IOTIFIED BIG YUS
+\setXTXcharcodes "0046E "0046F "0046E % CYRILLIC CAPITAL LETTER KSI
+\setXTXcharcodes "0046F "0046F "0046E % CYRILLIC SMALL LETTER KSI
+\setXTXcharcodes "00470 "00471 "00470 % CYRILLIC CAPITAL LETTER PSI
+\setXTXcharcodes "00471 "00471 "00470 % CYRILLIC SMALL LETTER PSI
+\setXTXcharcodes "00472 "00473 "00472 % CYRILLIC CAPITAL LETTER FITA
+\setXTXcharcodes "00473 "00473 "00472 % CYRILLIC SMALL LETTER FITA
+\setXTXcharcodes "00474 "00475 "00474 % CYRILLIC CAPITAL LETTER IZHITSA
+\setXTXcharcodes "00475 "00475 "00474 % CYRILLIC SMALL LETTER IZHITSA
+\setXTXcharcodes "00476 "00477 "00476 % CYRILLIC CAPITAL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+\setXTXcharcodes "00477 "00477 "00476 % CYRILLIC SMALL LETTER IZHITSA WITH DOUBLE GRAVE ACCENT
+\setXTXcharcodes "00478 "00479 "00478 % CYRILLIC CAPITAL LETTER UK
+\setXTXcharcodes "00479 "00479 "00478 % CYRILLIC SMALL LETTER UK
+\setXTXcharcodes "0047A "0047B "0047A % CYRILLIC CAPITAL LETTER ROUND OMEGA
+\setXTXcharcodes "0047B "0047B "0047A % CYRILLIC SMALL LETTER ROUND OMEGA
+\setXTXcharcodes "0047C "0047D "0047C % CYRILLIC CAPITAL LETTER OMEGA WITH TITLO
+\setXTXcharcodes "0047D "0047D "0047C % CYRILLIC SMALL LETTER OMEGA WITH TITLO
+\setXTXcharcodes "0047E "0047F "0047E % CYRILLIC CAPITAL LETTER OT
+\setXTXcharcodes "0047F "0047F "0047E % CYRILLIC SMALL LETTER OT
+\setXTXcharcodes "00480 "00481 "00480 % CYRILLIC CAPITAL LETTER KOPPA
+\setXTXcharcodes "00481 "00481 "00480 % CYRILLIC SMALL LETTER KOPPA
+\setXTXcharcodes "0048A "0048B "0048A % CYRILLIC CAPITAL LETTER SHORT I WITH TAIL
+\setXTXcharcodes "0048B "0048B "0048A % CYRILLIC SMALL LETTER SHORT I WITH TAIL
+\setXTXcharcodes "0048C "0048D "0048C % CYRILLIC CAPITAL LETTER SEMISOFT SIGN
+\setXTXcharcodes "0048D "0048D "0048C % CYRILLIC SMALL LETTER SEMISOFT SIGN
+\setXTXcharcodes "0048E "0048F "0048E % CYRILLIC CAPITAL LETTER ER WITH TICK
+\setXTXcharcodes "0048F "0048F "0048E % CYRILLIC SMALL LETTER ER WITH TICK
+\setXTXcharcodes "00490 "00491 "00490 % CYRILLIC CAPITAL LETTER GHE WITH UPTURN
+\setXTXcharcodes "00491 "00491 "00490 % CYRILLIC SMALL LETTER GHE WITH UPTURN
+\setXTXcharcodes "00492 "00493 "00492 % CYRILLIC CAPITAL LETTER GHE WITH STROKE
+\setXTXcharcodes "00493 "00493 "00492 % CYRILLIC SMALL LETTER GHE WITH STROKE
+\setXTXcharcodes "00494 "00495 "00494 % CYRILLIC CAPITAL LETTER GHE WITH MIDDLE HOOK
+\setXTXcharcodes "00495 "00495 "00494 % CYRILLIC SMALL LETTER GHE WITH MIDDLE HOOK
+\setXTXcharcodes "00496 "00497 "00496 % CYRILLIC CAPITAL LETTER ZHE WITH DESCENDER
+\setXTXcharcodes "00497 "00497 "00496 % CYRILLIC SMALL LETTER ZHE WITH DESCENDER
+\setXTXcharcodes "00498 "00499 "00498 % CYRILLIC CAPITAL LETTER ZE WITH DESCENDER
+\setXTXcharcodes "00499 "00499 "00498 % CYRILLIC SMALL LETTER ZE WITH DESCENDER
+\setXTXcharcodes "0049A "0049B "0049A % CYRILLIC CAPITAL LETTER KA WITH DESCENDER
+\setXTXcharcodes "0049B "0049B "0049A % CYRILLIC SMALL LETTER KA WITH DESCENDER
+\setXTXcharcodes "0049C "0049D "0049C % CYRILLIC CAPITAL LETTER KA WITH VERTICAL STROKE
+\setXTXcharcodes "0049D "0049D "0049C % CYRILLIC SMALL LETTER KA WITH VERTICAL STROKE
+\setXTXcharcodes "0049E "0049F "0049E % CYRILLIC CAPITAL LETTER KA WITH STROKE
+\setXTXcharcodes "0049F "0049F "0049E % CYRILLIC SMALL LETTER KA WITH STROKE
+\setXTXcharcodes "004A0 "004A1 "004A0 % CYRILLIC CAPITAL LETTER BASHKIR KA
+\setXTXcharcodes "004A1 "004A1 "004A0 % CYRILLIC SMALL LETTER BASHKIR KA
+\setXTXcharcodes "004A2 "004A3 "004A2 % CYRILLIC CAPITAL LETTER EN WITH DESCENDER
+\setXTXcharcodes "004A3 "004A3 "004A2 % CYRILLIC SMALL LETTER EN WITH DESCENDER
+\setXTXcharcodes "004A4 "004A5 "004A4 % CYRILLIC CAPITAL LIGATURE EN GHE
+\setXTXcharcodes "004A5 "004A5 "004A4 % CYRILLIC SMALL LIGATURE EN GHE
+\setXTXcharcodes "004A6 "004A7 "004A6 % CYRILLIC CAPITAL LETTER PE WITH MIDDLE HOOK
+\setXTXcharcodes "004A7 "004A7 "004A6 % CYRILLIC SMALL LETTER PE WITH MIDDLE HOOK
+\setXTXcharcodes "004A8 "004A9 "004A8 % CYRILLIC CAPITAL LETTER ABKHASIAN HA
+\setXTXcharcodes "004A9 "004A9 "004A8 % CYRILLIC SMALL LETTER ABKHASIAN HA
+\setXTXcharcodes "004AA "004AB "004AA % CYRILLIC CAPITAL LETTER ES WITH DESCENDER
+\setXTXcharcodes "004AB "004AB "004AA % CYRILLIC SMALL LETTER ES WITH DESCENDER
+\setXTXcharcodes "004AC "004AD "004AC % CYRILLIC CAPITAL LETTER TE WITH DESCENDER
+\setXTXcharcodes "004AD "004AD "004AC % CYRILLIC SMALL LETTER TE WITH DESCENDER
+\setXTXcharcodes "004AE "004AF "004AE % CYRILLIC CAPITAL LETTER STRAIGHT U
+\setXTXcharcodes "004AF "004AF "004AE % CYRILLIC SMALL LETTER STRAIGHT U
+\setXTXcharcodes "004B0 "004B1 "004B0 % CYRILLIC CAPITAL LETTER STRAIGHT U WITH STROKE
+\setXTXcharcodes "004B1 "004B1 "004B0 % CYRILLIC SMALL LETTER STRAIGHT U WITH STROKE
+\setXTXcharcodes "004B2 "004B3 "004B2 % CYRILLIC CAPITAL LETTER HA WITH DESCENDER
+\setXTXcharcodes "004B3 "004B3 "004B2 % CYRILLIC SMALL LETTER HA WITH DESCENDER
+\setXTXcharcodes "004B4 "004B5 "004B4 % CYRILLIC CAPITAL LIGATURE TE TSE
+\setXTXcharcodes "004B5 "004B5 "004B4 % CYRILLIC SMALL LIGATURE TE TSE
+\setXTXcharcodes "004B6 "004B7 "004B6 % CYRILLIC CAPITAL LETTER CHE WITH DESCENDER
+\setXTXcharcodes "004B7 "004B7 "004B6 % CYRILLIC SMALL LETTER CHE WITH DESCENDER
+\setXTXcharcodes "004B8 "004B9 "004B8 % CYRILLIC CAPITAL LETTER CHE WITH VERTICAL STROKE
+\setXTXcharcodes "004B9 "004B9 "004B8 % CYRILLIC SMALL LETTER CHE WITH VERTICAL STROKE
+\setXTXcharcodes "004BA "004BB "004BA % CYRILLIC CAPITAL LETTER SHHA
+\setXTXcharcodes "004BB "004BB "004BA % CYRILLIC SMALL LETTER SHHA
+\setXTXcharcodes "004BC "004BD "004BC % CYRILLIC CAPITAL LETTER ABKHASIAN CHE
+\setXTXcharcodes "004BD "004BD "004BC % CYRILLIC SMALL LETTER ABKHASIAN CHE
+\setXTXcharcodes "004BE "004BF "004BE % CYRILLIC CAPITAL LETTER ABKHASIAN CHE WITH DESCENDER
+\setXTXcharcodes "004BF "004BF "004BE % CYRILLIC SMALL LETTER ABKHASIAN CHE WITH DESCENDER
+\setXTXcharcodes "004C0 "004CF "004C0 % CYRILLIC LETTER PALOCHKA
+\setXTXcharcodes "004C1 "004C2 "004C1 % CYRILLIC CAPITAL LETTER ZHE WITH BREVE
+\setXTXcharcodes "004C2 "004C2 "004C1 % CYRILLIC SMALL LETTER ZHE WITH BREVE
+\setXTXcharcodes "004C3 "004C4 "004C3 % CYRILLIC CAPITAL LETTER KA WITH HOOK
+\setXTXcharcodes "004C4 "004C4 "004C3 % CYRILLIC SMALL LETTER KA WITH HOOK
+\setXTXcharcodes "004C5 "004C6 "004C5 % CYRILLIC CAPITAL LETTER EL WITH TAIL
+\setXTXcharcodes "004C6 "004C6 "004C5 % CYRILLIC SMALL LETTER EL WITH TAIL
+\setXTXcharcodes "004C7 "004C8 "004C7 % CYRILLIC CAPITAL LETTER EN WITH HOOK
+\setXTXcharcodes "004C8 "004C8 "004C7 % CYRILLIC SMALL LETTER EN WITH HOOK
+\setXTXcharcodes "004C9 "004CA "004C9 % CYRILLIC CAPITAL LETTER EN WITH TAIL
+\setXTXcharcodes "004CA "004CA "004C9 % CYRILLIC SMALL LETTER EN WITH TAIL
+\setXTXcharcodes "004CB "004CC "004CB % CYRILLIC CAPITAL LETTER KHAKASSIAN CHE
+\setXTXcharcodes "004CC "004CC "004CB % CYRILLIC SMALL LETTER KHAKASSIAN CHE
+\setXTXcharcodes "004CD "004CE "004CD % CYRILLIC CAPITAL LETTER EM WITH TAIL
+\setXTXcharcodes "004CE "004CE "004CD % CYRILLIC SMALL LETTER EM WITH TAIL
+\setXTXcharcodes "004CF "004CF "004C0 % CYRILLIC SMALL LETTER PALOCHKA
+\setXTXcharcodes "004D0 "004D1 "004D0 % CYRILLIC CAPITAL LETTER A WITH BREVE
+\setXTXcharcodes "004D1 "004D1 "004D0 % CYRILLIC SMALL LETTER A WITH BREVE
+\setXTXcharcodes "004D2 "004D3 "004D2 % CYRILLIC CAPITAL LETTER A WITH DIAERESIS
+\setXTXcharcodes "004D3 "004D3 "004D2 % CYRILLIC SMALL LETTER A WITH DIAERESIS
+\setXTXcharcodes "004D4 "004D5 "004D4 % CYRILLIC CAPITAL LIGATURE A IE
+\setXTXcharcodes "004D5 "004D5 "004D4 % CYRILLIC SMALL LIGATURE A IE
+\setXTXcharcodes "004D6 "004D7 "004D6 % CYRILLIC CAPITAL LETTER IE WITH BREVE
+\setXTXcharcodes "004D7 "004D7 "004D6 % CYRILLIC SMALL LETTER IE WITH BREVE
+\setXTXcharcodes "004D8 "004D9 "004D8 % CYRILLIC CAPITAL LETTER SCHWA
+\setXTXcharcodes "004D9 "004D9 "004D8 % CYRILLIC SMALL LETTER SCHWA
+\setXTXcharcodes "004DA "004DB "004DA % CYRILLIC CAPITAL LETTER SCHWA WITH DIAERESIS
+\setXTXcharcodes "004DB "004DB "004DA % CYRILLIC SMALL LETTER SCHWA WITH DIAERESIS
+\setXTXcharcodes "004DC "004DD "004DC % CYRILLIC CAPITAL LETTER ZHE WITH DIAERESIS
+\setXTXcharcodes "004DD "004DD "004DC % CYRILLIC SMALL LETTER ZHE WITH DIAERESIS
+\setXTXcharcodes "004DE "004DF "004DE % CYRILLIC CAPITAL LETTER ZE WITH DIAERESIS
+\setXTXcharcodes "004DF "004DF "004DE % CYRILLIC SMALL LETTER ZE WITH DIAERESIS
+\setXTXcharcodes "004E0 "004E1 "004E0 % CYRILLIC CAPITAL LETTER ABKHASIAN DZE
+\setXTXcharcodes "004E1 "004E1 "004E0 % CYRILLIC SMALL LETTER ABKHASIAN DZE
+\setXTXcharcodes "004E2 "004E3 "004E2 % CYRILLIC CAPITAL LETTER I WITH MACRON
+\setXTXcharcodes "004E3 "004E3 "004E2 % CYRILLIC SMALL LETTER I WITH MACRON
+\setXTXcharcodes "004E4 "004E5 "004E4 % CYRILLIC CAPITAL LETTER I WITH DIAERESIS
+\setXTXcharcodes "004E5 "004E5 "004E4 % CYRILLIC SMALL LETTER I WITH DIAERESIS
+\setXTXcharcodes "004E6 "004E7 "004E6 % CYRILLIC CAPITAL LETTER O WITH DIAERESIS
+\setXTXcharcodes "004E7 "004E7 "004E6 % CYRILLIC SMALL LETTER O WITH DIAERESIS
+\setXTXcharcodes "004E8 "004E9 "004E8 % CYRILLIC CAPITAL LETTER BARRED O
+\setXTXcharcodes "004E9 "004E9 "004E8 % CYRILLIC SMALL LETTER BARRED O
+\setXTXcharcodes "004EA "004EB "004EA % CYRILLIC CAPITAL LETTER BARRED O WITH DIAERESIS
+\setXTXcharcodes "004EB "004EB "004EA % CYRILLIC SMALL LETTER BARRED O WITH DIAERESIS
+\setXTXcharcodes "004EC "004ED "004EC % CYRILLIC CAPITAL LETTER E WITH DIAERESIS
+\setXTXcharcodes "004ED "004ED "004EC % CYRILLIC SMALL LETTER E WITH DIAERESIS
+\setXTXcharcodes "004EE "004EF "004EE % CYRILLIC CAPITAL LETTER U WITH MACRON
+\setXTXcharcodes "004EF "004EF "004EE % CYRILLIC SMALL LETTER U WITH MACRON
+\setXTXcharcodes "004F0 "004F1 "004F0 % CYRILLIC CAPITAL LETTER U WITH DIAERESIS
+\setXTXcharcodes "004F1 "004F1 "004F0 % CYRILLIC SMALL LETTER U WITH DIAERESIS
+\setXTXcharcodes "004F2 "004F3 "004F2 % CYRILLIC CAPITAL LETTER U WITH DOUBLE ACUTE
+\setXTXcharcodes "004F3 "004F3 "004F2 % CYRILLIC SMALL LETTER U WITH DOUBLE ACUTE
+\setXTXcharcodes "004F4 "004F5 "004F4 % CYRILLIC CAPITAL LETTER CHE WITH DIAERESIS
+\setXTXcharcodes "004F5 "004F5 "004F4 % CYRILLIC SMALL LETTER CHE WITH DIAERESIS
+\setXTXcharcodes "004F6 "004F7 "004F6 % CYRILLIC CAPITAL LETTER GHE WITH DESCENDER
+\setXTXcharcodes "004F7 "004F7 "004F6 % CYRILLIC SMALL LETTER GHE WITH DESCENDER
+\setXTXcharcodes "004F8 "004F9 "004F8 % CYRILLIC CAPITAL LETTER YERU WITH DIAERESIS
+\setXTXcharcodes "004F9 "004F9 "004F8 % CYRILLIC SMALL LETTER YERU WITH DIAERESIS
+\setXTXcharcodes "004FA "004FB "004FA % CYRILLIC CAPITAL LETTER GHE WITH STROKE AND HOOK
+\setXTXcharcodes "004FB "004FB "004FA % CYRILLIC SMALL LETTER GHE WITH STROKE AND HOOK
+\setXTXcharcodes "004FC "004FD "004FC % CYRILLIC CAPITAL LETTER HA WITH HOOK
+\setXTXcharcodes "004FD "004FD "004FC % CYRILLIC SMALL LETTER HA WITH HOOK
+\setXTXcharcodes "004FE "004FF "004FE % CYRILLIC CAPITAL LETTER HA WITH STROKE
+\setXTXcharcodes "004FF "004FF "004FE % CYRILLIC SMALL LETTER HA WITH STROKE
+\setXTXcharcodes "00500 "00501 "00500 % CYRILLIC CAPITAL LETTER KOMI DE
+\setXTXcharcodes "00501 "00501 "00500 % CYRILLIC SMALL LETTER KOMI DE
+\setXTXcharcodes "00502 "00503 "00502 % CYRILLIC CAPITAL LETTER KOMI DJE
+\setXTXcharcodes "00503 "00503 "00502 % CYRILLIC SMALL LETTER KOMI DJE
+\setXTXcharcodes "00504 "00505 "00504 % CYRILLIC CAPITAL LETTER KOMI ZJE
+\setXTXcharcodes "00505 "00505 "00504 % CYRILLIC SMALL LETTER KOMI ZJE
+\setXTXcharcodes "00506 "00507 "00506 % CYRILLIC CAPITAL LETTER KOMI DZJE
+\setXTXcharcodes "00507 "00507 "00506 % CYRILLIC SMALL LETTER KOMI DZJE
+\setXTXcharcodes "00508 "00509 "00508 % CYRILLIC CAPITAL LETTER KOMI LJE
+\setXTXcharcodes "00509 "00509 "00508 % CYRILLIC SMALL LETTER KOMI LJE
+\setXTXcharcodes "0050A "0050B "0050A % CYRILLIC CAPITAL LETTER KOMI NJE
+\setXTXcharcodes "0050B "0050B "0050A % CYRILLIC SMALL LETTER KOMI NJE
+\setXTXcharcodes "0050C "0050D "0050C % CYRILLIC CAPITAL LETTER KOMI SJE
+\setXTXcharcodes "0050D "0050D "0050C % CYRILLIC SMALL LETTER KOMI SJE
+\setXTXcharcodes "0050E "0050F "0050E % CYRILLIC CAPITAL LETTER KOMI TJE
+\setXTXcharcodes "0050F "0050F "0050E % CYRILLIC SMALL LETTER KOMI TJE
+\setXTXcharcodes "00510 "00511 "00510 % CYRILLIC CAPITAL LETTER REVERSED ZE
+\setXTXcharcodes "00511 "00511 "00510 % CYRILLIC SMALL LETTER REVERSED ZE
+\setXTXcharcodes "00512 "00513 "00512 % CYRILLIC CAPITAL LETTER EL WITH HOOK
+\setXTXcharcodes "00513 "00513 "00512 % CYRILLIC SMALL LETTER EL WITH HOOK
+\setXTXcharcodes "00531 "00561 "00531 % ARMENIAN CAPITAL LETTER AYB
+\setXTXcharcodes "00532 "00562 "00532 % ARMENIAN CAPITAL LETTER BEN
+\setXTXcharcodes "00533 "00563 "00533 % ARMENIAN CAPITAL LETTER GIM
+\setXTXcharcodes "00534 "00564 "00534 % ARMENIAN CAPITAL LETTER DA
+\setXTXcharcodes "00535 "00565 "00535 % ARMENIAN CAPITAL LETTER ECH
+\setXTXcharcodes "00536 "00566 "00536 % ARMENIAN CAPITAL LETTER ZA
+\setXTXcharcodes "00537 "00567 "00537 % ARMENIAN CAPITAL LETTER EH
+\setXTXcharcodes "00538 "00568 "00538 % ARMENIAN CAPITAL LETTER ET
+\setXTXcharcodes "00539 "00569 "00539 % ARMENIAN CAPITAL LETTER TO
+\setXTXcharcodes "0053A "0056A "0053A % ARMENIAN CAPITAL LETTER ZHE
+\setXTXcharcodes "0053B "0056B "0053B % ARMENIAN CAPITAL LETTER INI
+\setXTXcharcodes "0053C "0056C "0053C % ARMENIAN CAPITAL LETTER LIWN
+\setXTXcharcodes "0053D "0056D "0053D % ARMENIAN CAPITAL LETTER XEH
+\setXTXcharcodes "0053E "0056E "0053E % ARMENIAN CAPITAL LETTER CA
+\setXTXcharcodes "0053F "0056F "0053F % ARMENIAN CAPITAL LETTER KEN
+\setXTXcharcodes "00540 "00570 "00540 % ARMENIAN CAPITAL LETTER HO
+\setXTXcharcodes "00541 "00571 "00541 % ARMENIAN CAPITAL LETTER JA
+\setXTXcharcodes "00542 "00572 "00542 % ARMENIAN CAPITAL LETTER GHAD
+\setXTXcharcodes "00543 "00573 "00543 % ARMENIAN CAPITAL LETTER CHEH
+\setXTXcharcodes "00544 "00574 "00544 % ARMENIAN CAPITAL LETTER MEN
+\setXTXcharcodes "00545 "00575 "00545 % ARMENIAN CAPITAL LETTER YI
+\setXTXcharcodes "00546 "00576 "00546 % ARMENIAN CAPITAL LETTER NOW
+\setXTXcharcodes "00547 "00577 "00547 % ARMENIAN CAPITAL LETTER SHA
+\setXTXcharcodes "00548 "00578 "00548 % ARMENIAN CAPITAL LETTER VO
+\setXTXcharcodes "00549 "00579 "00549 % ARMENIAN CAPITAL LETTER CHA
+\setXTXcharcodes "0054A "0057A "0054A % ARMENIAN CAPITAL LETTER PEH
+\setXTXcharcodes "0054B "0057B "0054B % ARMENIAN CAPITAL LETTER JHEH
+\setXTXcharcodes "0054C "0057C "0054C % ARMENIAN CAPITAL LETTER RA
+\setXTXcharcodes "0054D "0057D "0054D % ARMENIAN CAPITAL LETTER SEH
+\setXTXcharcodes "0054E "0057E "0054E % ARMENIAN CAPITAL LETTER VEW
+\setXTXcharcodes "0054F "0057F "0054F % ARMENIAN CAPITAL LETTER TIWN
+\setXTXcharcodes "00550 "00580 "00550 % ARMENIAN CAPITAL LETTER REH
+\setXTXcharcodes "00551 "00581 "00551 % ARMENIAN CAPITAL LETTER CO
+\setXTXcharcodes "00552 "00582 "00552 % ARMENIAN CAPITAL LETTER YIWN
+\setXTXcharcodes "00553 "00583 "00553 % ARMENIAN CAPITAL LETTER PIWR
+\setXTXcharcodes "00554 "00584 "00554 % ARMENIAN CAPITAL LETTER KEH
+\setXTXcharcodes "00555 "00585 "00555 % ARMENIAN CAPITAL LETTER OH
+\setXTXcharcodes "00556 "00586 "00556 % ARMENIAN CAPITAL LETTER FEH
+\setXTXcharcodes "00561 "00561 "00531 % ARMENIAN SMALL LETTER AYB
+\setXTXcharcodes "00562 "00562 "00532 % ARMENIAN SMALL LETTER BEN
+\setXTXcharcodes "00563 "00563 "00533 % ARMENIAN SMALL LETTER GIM
+\setXTXcharcodes "00564 "00564 "00534 % ARMENIAN SMALL LETTER DA
+\setXTXcharcodes "00565 "00565 "00535 % ARMENIAN SMALL LETTER ECH
+\setXTXcharcodes "00566 "00566 "00536 % ARMENIAN SMALL LETTER ZA
+\setXTXcharcodes "00567 "00567 "00537 % ARMENIAN SMALL LETTER EH
+\setXTXcharcodes "00568 "00568 "00538 % ARMENIAN SMALL LETTER ET
+\setXTXcharcodes "00569 "00569 "00539 % ARMENIAN SMALL LETTER TO
+\setXTXcharcodes "0056A "0056A "0053A % ARMENIAN SMALL LETTER ZHE
+\setXTXcharcodes "0056B "0056B "0053B % ARMENIAN SMALL LETTER INI
+\setXTXcharcodes "0056C "0056C "0053C % ARMENIAN SMALL LETTER LIWN
+\setXTXcharcodes "0056D "0056D "0053D % ARMENIAN SMALL LETTER XEH
+\setXTXcharcodes "0056E "0056E "0053E % ARMENIAN SMALL LETTER CA
+\setXTXcharcodes "0056F "0056F "0053F % ARMENIAN SMALL LETTER KEN
+\setXTXcharcodes "00570 "00570 "00540 % ARMENIAN SMALL LETTER HO
+\setXTXcharcodes "00571 "00571 "00541 % ARMENIAN SMALL LETTER JA
+\setXTXcharcodes "00572 "00572 "00542 % ARMENIAN SMALL LETTER GHAD
+\setXTXcharcodes "00573 "00573 "00543 % ARMENIAN SMALL LETTER CHEH
+\setXTXcharcodes "00574 "00574 "00544 % ARMENIAN SMALL LETTER MEN
+\setXTXcharcodes "00575 "00575 "00545 % ARMENIAN SMALL LETTER YI
+\setXTXcharcodes "00576 "00576 "00546 % ARMENIAN SMALL LETTER NOW
+\setXTXcharcodes "00577 "00577 "00547 % ARMENIAN SMALL LETTER SHA
+\setXTXcharcodes "00578 "00578 "00548 % ARMENIAN SMALL LETTER VO
+\setXTXcharcodes "00579 "00579 "00549 % ARMENIAN SMALL LETTER CHA
+\setXTXcharcodes "0057A "0057A "0054A % ARMENIAN SMALL LETTER PEH
+\setXTXcharcodes "0057B "0057B "0054B % ARMENIAN SMALL LETTER JHEH
+\setXTXcharcodes "0057C "0057C "0054C % ARMENIAN SMALL LETTER RA
+\setXTXcharcodes "0057D "0057D "0054D % ARMENIAN SMALL LETTER SEH
+\setXTXcharcodes "0057E "0057E "0054E % ARMENIAN SMALL LETTER VEW
+\setXTXcharcodes "0057F "0057F "0054F % ARMENIAN SMALL LETTER TIWN
+\setXTXcharcodes "00580 "00580 "00550 % ARMENIAN SMALL LETTER REH
+\setXTXcharcodes "00581 "00581 "00551 % ARMENIAN SMALL LETTER CO
+\setXTXcharcodes "00582 "00582 "00552 % ARMENIAN SMALL LETTER YIWN
+\setXTXcharcodes "00583 "00583 "00553 % ARMENIAN SMALL LETTER PIWR
+\setXTXcharcodes "00584 "00584 "00554 % ARMENIAN SMALL LETTER KEH
+\setXTXcharcodes "00585 "00585 "00555 % ARMENIAN SMALL LETTER OH
+\setXTXcharcodes "00586 "00586 "00556 % ARMENIAN SMALL LETTER FEH
+\setXTXcharcodes "00587 "00587 "00587 % ARMENIAN SMALL LIGATURE ECH YIWN
+\setXTXcharcodes "010A0 "02D00 "010A0 % GEORGIAN CAPITAL LETTER AN
+\setXTXcharcodes "010A1 "02D01 "010A1 % GEORGIAN CAPITAL LETTER BAN
+\setXTXcharcodes "010A2 "02D02 "010A2 % GEORGIAN CAPITAL LETTER GAN
+\setXTXcharcodes "010A3 "02D03 "010A3 % GEORGIAN CAPITAL LETTER DON
+\setXTXcharcodes "010A4 "02D04 "010A4 % GEORGIAN CAPITAL LETTER EN
+\setXTXcharcodes "010A5 "02D05 "010A5 % GEORGIAN CAPITAL LETTER VIN
+\setXTXcharcodes "010A6 "02D06 "010A6 % GEORGIAN CAPITAL LETTER ZEN
+\setXTXcharcodes "010A7 "02D07 "010A7 % GEORGIAN CAPITAL LETTER TAN
+\setXTXcharcodes "010A8 "02D08 "010A8 % GEORGIAN CAPITAL LETTER IN
+\setXTXcharcodes "010A9 "02D09 "010A9 % GEORGIAN CAPITAL LETTER KAN
+\setXTXcharcodes "010AA "02D0A "010AA % GEORGIAN CAPITAL LETTER LAS
+\setXTXcharcodes "010AB "02D0B "010AB % GEORGIAN CAPITAL LETTER MAN
+\setXTXcharcodes "010AC "02D0C "010AC % GEORGIAN CAPITAL LETTER NAR
+\setXTXcharcodes "010AD "02D0D "010AD % GEORGIAN CAPITAL LETTER ON
+\setXTXcharcodes "010AE "02D0E "010AE % GEORGIAN CAPITAL LETTER PAR
+\setXTXcharcodes "010AF "02D0F "010AF % GEORGIAN CAPITAL LETTER ZHAR
+\setXTXcharcodes "010B0 "02D10 "010B0 % GEORGIAN CAPITAL LETTER RAE
+\setXTXcharcodes "010B1 "02D11 "010B1 % GEORGIAN CAPITAL LETTER SAN
+\setXTXcharcodes "010B2 "02D12 "010B2 % GEORGIAN CAPITAL LETTER TAR
+\setXTXcharcodes "010B3 "02D13 "010B3 % GEORGIAN CAPITAL LETTER UN
+\setXTXcharcodes "010B4 "02D14 "010B4 % GEORGIAN CAPITAL LETTER PHAR
+\setXTXcharcodes "010B5 "02D15 "010B5 % GEORGIAN CAPITAL LETTER KHAR
+\setXTXcharcodes "010B6 "02D16 "010B6 % GEORGIAN CAPITAL LETTER GHAN
+\setXTXcharcodes "010B7 "02D17 "010B7 % GEORGIAN CAPITAL LETTER QAR
+\setXTXcharcodes "010B8 "02D18 "010B8 % GEORGIAN CAPITAL LETTER SHIN
+\setXTXcharcodes "010B9 "02D19 "010B9 % GEORGIAN CAPITAL LETTER CHIN
+\setXTXcharcodes "010BA "02D1A "010BA % GEORGIAN CAPITAL LETTER CAN
+\setXTXcharcodes "010BB "02D1B "010BB % GEORGIAN CAPITAL LETTER JIL
+\setXTXcharcodes "010BC "02D1C "010BC % GEORGIAN CAPITAL LETTER CIL
+\setXTXcharcodes "010BD "02D1D "010BD % GEORGIAN CAPITAL LETTER CHAR
+\setXTXcharcodes "010BE "02D1E "010BE % GEORGIAN CAPITAL LETTER XAN
+\setXTXcharcodes "010BF "02D1F "010BF % GEORGIAN CAPITAL LETTER JHAN
+\setXTXcharcodes "010C0 "02D20 "010C0 % GEORGIAN CAPITAL LETTER HAE
+\setXTXcharcodes "010C1 "02D21 "010C1 % GEORGIAN CAPITAL LETTER HE
+\setXTXcharcodes "010C2 "02D22 "010C2 % GEORGIAN CAPITAL LETTER HIE
+\setXTXcharcodes "010C3 "02D23 "010C3 % GEORGIAN CAPITAL LETTER WE
+\setXTXcharcodes "010C4 "02D24 "010C4 % GEORGIAN CAPITAL LETTER HAR
+\setXTXcharcodes "010C5 "02D25 "010C5 % GEORGIAN CAPITAL LETTER HOE
+\setXTXcharcodes "01D00 "01D00 "01D00 % LATIN LETTER SMALL CAPITAL A
+\setXTXcharcodes "01D01 "01D01 "01D01 % LATIN LETTER SMALL CAPITAL AE
+\setXTXcharcodes "01D02 "01D02 "01D02 % LATIN SMALL LETTER TURNED AE
+\setXTXcharcodes "01D03 "01D03 "01D03 % LATIN LETTER SMALL CAPITAL BARRED B
+\setXTXcharcodes "01D04 "01D04 "01D04 % LATIN LETTER SMALL CAPITAL C
+\setXTXcharcodes "01D05 "01D05 "01D05 % LATIN LETTER SMALL CAPITAL D
+\setXTXcharcodes "01D06 "01D06 "01D06 % LATIN LETTER SMALL CAPITAL ETH
+\setXTXcharcodes "01D07 "01D07 "01D07 % LATIN LETTER SMALL CAPITAL E
+\setXTXcharcodes "01D08 "01D08 "01D08 % LATIN SMALL LETTER TURNED OPEN E
+\setXTXcharcodes "01D09 "01D09 "01D09 % LATIN SMALL LETTER TURNED I
+\setXTXcharcodes "01D0A "01D0A "01D0A % LATIN LETTER SMALL CAPITAL J
+\setXTXcharcodes "01D0B "01D0B "01D0B % LATIN LETTER SMALL CAPITAL K
+\setXTXcharcodes "01D0C "01D0C "01D0C % LATIN LETTER SMALL CAPITAL L WITH STROKE
+\setXTXcharcodes "01D0D "01D0D "01D0D % LATIN LETTER SMALL CAPITAL M
+\setXTXcharcodes "01D0E "01D0E "01D0E % LATIN LETTER SMALL CAPITAL REVERSED N
+\setXTXcharcodes "01D0F "01D0F "01D0F % LATIN LETTER SMALL CAPITAL O
+\setXTXcharcodes "01D10 "01D10 "01D10 % LATIN LETTER SMALL CAPITAL OPEN O
+\setXTXcharcodes "01D11 "01D11 "01D11 % LATIN SMALL LETTER SIDEWAYS O
+\setXTXcharcodes "01D12 "01D12 "01D12 % LATIN SMALL LETTER SIDEWAYS OPEN O
+\setXTXcharcodes "01D13 "01D13 "01D13 % LATIN SMALL LETTER SIDEWAYS O WITH STROKE
+\setXTXcharcodes "01D14 "01D14 "01D14 % LATIN SMALL LETTER TURNED OE
+\setXTXcharcodes "01D15 "01D15 "01D15 % LATIN LETTER SMALL CAPITAL OU
+\setXTXcharcodes "01D16 "01D16 "01D16 % LATIN SMALL LETTER TOP HALF O
+\setXTXcharcodes "01D17 "01D17 "01D17 % LATIN SMALL LETTER BOTTOM HALF O
+\setXTXcharcodes "01D18 "01D18 "01D18 % LATIN LETTER SMALL CAPITAL P
+\setXTXcharcodes "01D19 "01D19 "01D19 % LATIN LETTER SMALL CAPITAL REVERSED R
+\setXTXcharcodes "01D1A "01D1A "01D1A % LATIN LETTER SMALL CAPITAL TURNED R
+\setXTXcharcodes "01D1B "01D1B "01D1B % LATIN LETTER SMALL CAPITAL T
+\setXTXcharcodes "01D1C "01D1C "01D1C % LATIN LETTER SMALL CAPITAL U
+\setXTXcharcodes "01D1D "01D1D "01D1D % LATIN SMALL LETTER SIDEWAYS U
+\setXTXcharcodes "01D1E "01D1E "01D1E % LATIN SMALL LETTER SIDEWAYS DIAERESIZED U
+\setXTXcharcodes "01D1F "01D1F "01D1F % LATIN SMALL LETTER SIDEWAYS TURNED M
+\setXTXcharcodes "01D20 "01D20 "01D20 % LATIN LETTER SMALL CAPITAL V
+\setXTXcharcodes "01D21 "01D21 "01D21 % LATIN LETTER SMALL CAPITAL W
+\setXTXcharcodes "01D22 "01D22 "01D22 % LATIN LETTER SMALL CAPITAL Z
+\setXTXcharcodes "01D23 "01D23 "01D23 % LATIN LETTER SMALL CAPITAL EZH
+\setXTXcharcodes "01D24 "01D24 "01D24 % LATIN LETTER VOICED LARYNGEAL SPIRANT
+\setXTXcharcodes "01D25 "01D25 "01D25 % LATIN LETTER AIN
+\setXTXcharcodes "01D26 "01D26 "01D26 % GREEK LETTER SMALL CAPITAL GAMMA
+\setXTXcharcodes "01D27 "01D27 "01D27 % GREEK LETTER SMALL CAPITAL LAMDA
+\setXTXcharcodes "01D28 "01D28 "01D28 % GREEK LETTER SMALL CAPITAL PI
+\setXTXcharcodes "01D29 "01D29 "01D29 % GREEK LETTER SMALL CAPITAL RHO
+\setXTXcharcodes "01D2A "01D2A "01D2A % GREEK LETTER SMALL CAPITAL PSI
+\setXTXcharcodes "01D2B "01D2B "01D2B % CYRILLIC LETTER SMALL CAPITAL EL
+\setXTXcharcodes "01D62 "01D62 "01D62 % LATIN SUBSCRIPT SMALL LETTER I
+\setXTXcharcodes "01D63 "01D63 "01D63 % LATIN SUBSCRIPT SMALL LETTER R
+\setXTXcharcodes "01D64 "01D64 "01D64 % LATIN SUBSCRIPT SMALL LETTER U
+\setXTXcharcodes "01D65 "01D65 "01D65 % LATIN SUBSCRIPT SMALL LETTER V
+\setXTXcharcodes "01D66 "01D66 "01D66 % GREEK SUBSCRIPT SMALL LETTER BETA
+\setXTXcharcodes "01D67 "01D67 "01D67 % GREEK SUBSCRIPT SMALL LETTER GAMMA
+\setXTXcharcodes "01D68 "01D68 "01D68 % GREEK SUBSCRIPT SMALL LETTER RHO
+\setXTXcharcodes "01D69 "01D69 "01D69 % GREEK SUBSCRIPT SMALL LETTER PHI
+\setXTXcharcodes "01D6A "01D6A "01D6A % GREEK SUBSCRIPT SMALL LETTER CHI
+\setXTXcharcodes "01D6B "01D6B "01D6B % LATIN SMALL LETTER UE
+\setXTXcharcodes "01D6C "01D6C "01D6C % LATIN SMALL LETTER B WITH MIDDLE TILDE
+\setXTXcharcodes "01D6D "01D6D "01D6D % LATIN SMALL LETTER D WITH MIDDLE TILDE
+\setXTXcharcodes "01D6E "01D6E "01D6E % LATIN SMALL LETTER F WITH MIDDLE TILDE
+\setXTXcharcodes "01D6F "01D6F "01D6F % LATIN SMALL LETTER M WITH MIDDLE TILDE
+\setXTXcharcodes "01D70 "01D70 "01D70 % LATIN SMALL LETTER N WITH MIDDLE TILDE
+\setXTXcharcodes "01D71 "01D71 "01D71 % LATIN SMALL LETTER P WITH MIDDLE TILDE
+\setXTXcharcodes "01D72 "01D72 "01D72 % LATIN SMALL LETTER R WITH MIDDLE TILDE
+\setXTXcharcodes "01D73 "01D73 "01D73 % LATIN SMALL LETTER R WITH FISHHOOK AND MIDDLE TILDE
+\setXTXcharcodes "01D74 "01D74 "01D74 % LATIN SMALL LETTER S WITH MIDDLE TILDE
+\setXTXcharcodes "01D75 "01D75 "01D75 % LATIN SMALL LETTER T WITH MIDDLE TILDE
+\setXTXcharcodes "01D76 "01D76 "01D76 % LATIN SMALL LETTER Z WITH MIDDLE TILDE
+\setXTXcharcodes "01D77 "01D77 "01D77 % LATIN SMALL LETTER TURNED G
+\setXTXcharcodes "01D79 "01D79 "01D79 % LATIN SMALL LETTER INSULAR G
+\setXTXcharcodes "01D7A "01D7A "01D7A % LATIN SMALL LETTER TH WITH STRIKETHROUGH
+\setXTXcharcodes "01D7B "01D7B "01D7B % LATIN SMALL CAPITAL LETTER I WITH STROKE
+\setXTXcharcodes "01D7C "01D7C "01D7C % LATIN SMALL LETTER IOTA WITH STROKE
+\setXTXcharcodes "01D7D "01D7D "02C63 % LATIN SMALL LETTER P WITH STROKE
+\setXTXcharcodes "01D7E "01D7E "01D7E % LATIN SMALL CAPITAL LETTER U WITH STROKE
+\setXTXcharcodes "01D7F "01D7F "01D7F % LATIN SMALL LETTER UPSILON WITH STROKE
+\setXTXcharcodes "01D80 "01D80 "01D80 % LATIN SMALL LETTER B WITH PALATAL HOOK
+\setXTXcharcodes "01D81 "01D81 "01D81 % LATIN SMALL LETTER D WITH PALATAL HOOK
+\setXTXcharcodes "01D82 "01D82 "01D82 % LATIN SMALL LETTER F WITH PALATAL HOOK
+\setXTXcharcodes "01D83 "01D83 "01D83 % LATIN SMALL LETTER G WITH PALATAL HOOK
+\setXTXcharcodes "01D84 "01D84 "01D84 % LATIN SMALL LETTER K WITH PALATAL HOOK
+\setXTXcharcodes "01D85 "01D85 "01D85 % LATIN SMALL LETTER L WITH PALATAL HOOK
+\setXTXcharcodes "01D86 "01D86 "01D86 % LATIN SMALL LETTER M WITH PALATAL HOOK
+\setXTXcharcodes "01D87 "01D87 "01D87 % LATIN SMALL LETTER N WITH PALATAL HOOK
+\setXTXcharcodes "01D88 "01D88 "01D88 % LATIN SMALL LETTER P WITH PALATAL HOOK
+\setXTXcharcodes "01D89 "01D89 "01D89 % LATIN SMALL LETTER R WITH PALATAL HOOK
+\setXTXcharcodes "01D8A "01D8A "01D8A % LATIN SMALL LETTER S WITH PALATAL HOOK
+\setXTXcharcodes "01D8B "01D8B "01D8B % LATIN SMALL LETTER ESH WITH PALATAL HOOK
+\setXTXcharcodes "01D8C "01D8C "01D8C % LATIN SMALL LETTER V WITH PALATAL HOOK
+\setXTXcharcodes "01D8D "01D8D "01D8D % LATIN SMALL LETTER X WITH PALATAL HOOK
+\setXTXcharcodes "01D8E "01D8E "01D8E % LATIN SMALL LETTER Z WITH PALATAL HOOK
+\setXTXcharcodes "01D8F "01D8F "01D8F % LATIN SMALL LETTER A WITH RETROFLEX HOOK
+\setXTXcharcodes "01D90 "01D90 "01D90 % LATIN SMALL LETTER ALPHA WITH RETROFLEX HOOK
+\setXTXcharcodes "01D91 "01D91 "01D91 % LATIN SMALL LETTER D WITH HOOK AND TAIL
+\setXTXcharcodes "01D92 "01D92 "01D92 % LATIN SMALL LETTER E WITH RETROFLEX HOOK
+\setXTXcharcodes "01D93 "01D93 "01D93 % LATIN SMALL LETTER OPEN E WITH RETROFLEX HOOK
+\setXTXcharcodes "01D94 "01D94 "01D94 % LATIN SMALL LETTER REVERSED OPEN E WITH RETROFLEX HOOK
+\setXTXcharcodes "01D95 "01D95 "01D95 % LATIN SMALL LETTER SCHWA WITH RETROFLEX HOOK
+\setXTXcharcodes "01D96 "01D96 "01D96 % LATIN SMALL LETTER I WITH RETROFLEX HOOK
+\setXTXcharcodes "01D97 "01D97 "01D97 % LATIN SMALL LETTER OPEN O WITH RETROFLEX HOOK
+\setXTXcharcodes "01D98 "01D98 "01D98 % LATIN SMALL LETTER ESH WITH RETROFLEX HOOK
+\setXTXcharcodes "01D99 "01D99 "01D99 % LATIN SMALL LETTER U WITH RETROFLEX HOOK
+\setXTXcharcodes "01D9A "01D9A "01D9A % LATIN SMALL LETTER EZH WITH RETROFLEX HOOK
+\setXTXcharcodes "01E00 "01E01 "01E00 % LATIN CAPITAL LETTER A WITH RING BELOW
+\setXTXcharcodes "01E01 "01E01 "01E00 % LATIN SMALL LETTER A WITH RING BELOW
+\setXTXcharcodes "01E02 "01E03 "01E02 % LATIN CAPITAL LETTER B WITH DOT ABOVE
+\setXTXcharcodes "01E03 "01E03 "01E02 % LATIN SMALL LETTER B WITH DOT ABOVE
+\setXTXcharcodes "01E04 "01E05 "01E04 % LATIN CAPITAL LETTER B WITH DOT BELOW
+\setXTXcharcodes "01E05 "01E05 "01E04 % LATIN SMALL LETTER B WITH DOT BELOW
+\setXTXcharcodes "01E06 "01E07 "01E06 % LATIN CAPITAL LETTER B WITH LINE BELOW
+\setXTXcharcodes "01E07 "01E07 "01E06 % LATIN SMALL LETTER B WITH LINE BELOW
+\setXTXcharcodes "01E08 "01E09 "01E08 % LATIN CAPITAL LETTER C WITH CEDILLA AND ACUTE
+\setXTXcharcodes "01E09 "01E09 "01E08 % LATIN SMALL LETTER C WITH CEDILLA AND ACUTE
+\setXTXcharcodes "01E0A "01E0B "01E0A % LATIN CAPITAL LETTER D WITH DOT ABOVE
+\setXTXcharcodes "01E0B "01E0B "01E0A % LATIN SMALL LETTER D WITH DOT ABOVE
+\setXTXcharcodes "01E0C "01E0D "01E0C % LATIN CAPITAL LETTER D WITH DOT BELOW
+\setXTXcharcodes "01E0D "01E0D "01E0C % LATIN SMALL LETTER D WITH DOT BELOW
+\setXTXcharcodes "01E0E "01E0F "01E0E % LATIN CAPITAL LETTER D WITH LINE BELOW
+\setXTXcharcodes "01E0F "01E0F "01E0E % LATIN SMALL LETTER D WITH LINE BELOW
+\setXTXcharcodes "01E10 "01E11 "01E10 % LATIN CAPITAL LETTER D WITH CEDILLA
+\setXTXcharcodes "01E11 "01E11 "01E10 % LATIN SMALL LETTER D WITH CEDILLA
+\setXTXcharcodes "01E12 "01E13 "01E12 % LATIN CAPITAL LETTER D WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E13 "01E13 "01E12 % LATIN SMALL LETTER D WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E14 "01E15 "01E14 % LATIN CAPITAL LETTER E WITH MACRON AND GRAVE
+\setXTXcharcodes "01E15 "01E15 "01E14 % LATIN SMALL LETTER E WITH MACRON AND GRAVE
+\setXTXcharcodes "01E16 "01E17 "01E16 % LATIN CAPITAL LETTER E WITH MACRON AND ACUTE
+\setXTXcharcodes "01E17 "01E17 "01E16 % LATIN SMALL LETTER E WITH MACRON AND ACUTE
+\setXTXcharcodes "01E18 "01E19 "01E18 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E19 "01E19 "01E18 % LATIN SMALL LETTER E WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E1A "01E1B "01E1A % LATIN CAPITAL LETTER E WITH TILDE BELOW
+\setXTXcharcodes "01E1B "01E1B "01E1A % LATIN SMALL LETTER E WITH TILDE BELOW
+\setXTXcharcodes "01E1C "01E1D "01E1C % LATIN CAPITAL LETTER E WITH CEDILLA AND BREVE
+\setXTXcharcodes "01E1D "01E1D "01E1C % LATIN SMALL LETTER E WITH CEDILLA AND BREVE
+\setXTXcharcodes "01E1E "01E1F "01E1E % LATIN CAPITAL LETTER F WITH DOT ABOVE
+\setXTXcharcodes "01E1F "01E1F "01E1E % LATIN SMALL LETTER F WITH DOT ABOVE
+\setXTXcharcodes "01E20 "01E21 "01E20 % LATIN CAPITAL LETTER G WITH MACRON
+\setXTXcharcodes "01E21 "01E21 "01E20 % LATIN SMALL LETTER G WITH MACRON
+\setXTXcharcodes "01E22 "01E23 "01E22 % LATIN CAPITAL LETTER H WITH DOT ABOVE
+\setXTXcharcodes "01E23 "01E23 "01E22 % LATIN SMALL LETTER H WITH DOT ABOVE
+\setXTXcharcodes "01E24 "01E25 "01E24 % LATIN CAPITAL LETTER H WITH DOT BELOW
+\setXTXcharcodes "01E25 "01E25 "01E24 % LATIN SMALL LETTER H WITH DOT BELOW
+\setXTXcharcodes "01E26 "01E27 "01E26 % LATIN CAPITAL LETTER H WITH DIAERESIS
+\setXTXcharcodes "01E27 "01E27 "01E26 % LATIN SMALL LETTER H WITH DIAERESIS
+\setXTXcharcodes "01E28 "01E29 "01E28 % LATIN CAPITAL LETTER H WITH CEDILLA
+\setXTXcharcodes "01E29 "01E29 "01E28 % LATIN SMALL LETTER H WITH CEDILLA
+\setXTXcharcodes "01E2A "01E2B "01E2A % LATIN CAPITAL LETTER H WITH BREVE BELOW
+\setXTXcharcodes "01E2B "01E2B "01E2A % LATIN SMALL LETTER H WITH BREVE BELOW
+\setXTXcharcodes "01E2C "01E2D "01E2C % LATIN CAPITAL LETTER I WITH TILDE BELOW
+\setXTXcharcodes "01E2D "01E2D "01E2C % LATIN SMALL LETTER I WITH TILDE BELOW
+\setXTXcharcodes "01E2E "01E2F "01E2E % LATIN CAPITAL LETTER I WITH DIAERESIS AND ACUTE
+\setXTXcharcodes "01E2F "01E2F "01E2E % LATIN SMALL LETTER I WITH DIAERESIS AND ACUTE
+\setXTXcharcodes "01E30 "01E31 "01E30 % LATIN CAPITAL LETTER K WITH ACUTE
+\setXTXcharcodes "01E31 "01E31 "01E30 % LATIN SMALL LETTER K WITH ACUTE
+\setXTXcharcodes "01E32 "01E33 "01E32 % LATIN CAPITAL LETTER K WITH DOT BELOW
+\setXTXcharcodes "01E33 "01E33 "01E32 % LATIN SMALL LETTER K WITH DOT BELOW
+\setXTXcharcodes "01E34 "01E35 "01E34 % LATIN CAPITAL LETTER K WITH LINE BELOW
+\setXTXcharcodes "01E35 "01E35 "01E34 % LATIN SMALL LETTER K WITH LINE BELOW
+\setXTXcharcodes "01E36 "01E37 "01E36 % LATIN CAPITAL LETTER L WITH DOT BELOW
+\setXTXcharcodes "01E37 "01E37 "01E36 % LATIN SMALL LETTER L WITH DOT BELOW
+\setXTXcharcodes "01E38 "01E39 "01E38 % LATIN CAPITAL LETTER L WITH DOT BELOW AND MACRON
+\setXTXcharcodes "01E39 "01E39 "01E38 % LATIN SMALL LETTER L WITH DOT BELOW AND MACRON
+\setXTXcharcodes "01E3A "01E3B "01E3A % LATIN CAPITAL LETTER L WITH LINE BELOW
+\setXTXcharcodes "01E3B "01E3B "01E3A % LATIN SMALL LETTER L WITH LINE BELOW
+\setXTXcharcodes "01E3C "01E3D "01E3C % LATIN CAPITAL LETTER L WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E3D "01E3D "01E3C % LATIN SMALL LETTER L WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E3E "01E3F "01E3E % LATIN CAPITAL LETTER M WITH ACUTE
+\setXTXcharcodes "01E3F "01E3F "01E3E % LATIN SMALL LETTER M WITH ACUTE
+\setXTXcharcodes "01E40 "01E41 "01E40 % LATIN CAPITAL LETTER M WITH DOT ABOVE
+\setXTXcharcodes "01E41 "01E41 "01E40 % LATIN SMALL LETTER M WITH DOT ABOVE
+\setXTXcharcodes "01E42 "01E43 "01E42 % LATIN CAPITAL LETTER M WITH DOT BELOW
+\setXTXcharcodes "01E43 "01E43 "01E42 % LATIN SMALL LETTER M WITH DOT BELOW
+\setXTXcharcodes "01E44 "01E45 "01E44 % LATIN CAPITAL LETTER N WITH DOT ABOVE
+\setXTXcharcodes "01E45 "01E45 "01E44 % LATIN SMALL LETTER N WITH DOT ABOVE
+\setXTXcharcodes "01E46 "01E47 "01E46 % LATIN CAPITAL LETTER N WITH DOT BELOW
+\setXTXcharcodes "01E47 "01E47 "01E46 % LATIN SMALL LETTER N WITH DOT BELOW
+\setXTXcharcodes "01E48 "01E49 "01E48 % LATIN CAPITAL LETTER N WITH LINE BELOW
+\setXTXcharcodes "01E49 "01E49 "01E48 % LATIN SMALL LETTER N WITH LINE BELOW
+\setXTXcharcodes "01E4A "01E4B "01E4A % LATIN CAPITAL LETTER N WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E4B "01E4B "01E4A % LATIN SMALL LETTER N WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E4C "01E4D "01E4C % LATIN CAPITAL LETTER O WITH TILDE AND ACUTE
+\setXTXcharcodes "01E4D "01E4D "01E4C % LATIN SMALL LETTER O WITH TILDE AND ACUTE
+\setXTXcharcodes "01E4E "01E4F "01E4E % LATIN CAPITAL LETTER O WITH TILDE AND DIAERESIS
+\setXTXcharcodes "01E4F "01E4F "01E4E % LATIN SMALL LETTER O WITH TILDE AND DIAERESIS
+\setXTXcharcodes "01E50 "01E51 "01E50 % LATIN CAPITAL LETTER O WITH MACRON AND GRAVE
+\setXTXcharcodes "01E51 "01E51 "01E50 % LATIN SMALL LETTER O WITH MACRON AND GRAVE
+\setXTXcharcodes "01E52 "01E53 "01E52 % LATIN CAPITAL LETTER O WITH MACRON AND ACUTE
+\setXTXcharcodes "01E53 "01E53 "01E52 % LATIN SMALL LETTER O WITH MACRON AND ACUTE
+\setXTXcharcodes "01E54 "01E55 "01E54 % LATIN CAPITAL LETTER P WITH ACUTE
+\setXTXcharcodes "01E55 "01E55 "01E54 % LATIN SMALL LETTER P WITH ACUTE
+\setXTXcharcodes "01E56 "01E57 "01E56 % LATIN CAPITAL LETTER P WITH DOT ABOVE
+\setXTXcharcodes "01E57 "01E57 "01E56 % LATIN SMALL LETTER P WITH DOT ABOVE
+\setXTXcharcodes "01E58 "01E59 "01E58 % LATIN CAPITAL LETTER R WITH DOT ABOVE
+\setXTXcharcodes "01E59 "01E59 "01E58 % LATIN SMALL LETTER R WITH DOT ABOVE
+\setXTXcharcodes "01E5A "01E5B "01E5A % LATIN CAPITAL LETTER R WITH DOT BELOW
+\setXTXcharcodes "01E5B "01E5B "01E5A % LATIN SMALL LETTER R WITH DOT BELOW
+\setXTXcharcodes "01E5C "01E5D "01E5C % LATIN CAPITAL LETTER R WITH DOT BELOW AND MACRON
+\setXTXcharcodes "01E5D "01E5D "01E5C % LATIN SMALL LETTER R WITH DOT BELOW AND MACRON
+\setXTXcharcodes "01E5E "01E5F "01E5E % LATIN CAPITAL LETTER R WITH LINE BELOW
+\setXTXcharcodes "01E5F "01E5F "01E5E % LATIN SMALL LETTER R WITH LINE BELOW
+\setXTXcharcodes "01E60 "01E61 "01E60 % LATIN CAPITAL LETTER S WITH DOT ABOVE
+\setXTXcharcodes "01E61 "01E61 "01E60 % LATIN SMALL LETTER S WITH DOT ABOVE
+\setXTXcharcodes "01E62 "01E63 "01E62 % LATIN CAPITAL LETTER S WITH DOT BELOW
+\setXTXcharcodes "01E63 "01E63 "01E62 % LATIN SMALL LETTER S WITH DOT BELOW
+\setXTXcharcodes "01E64 "01E65 "01E64 % LATIN CAPITAL LETTER S WITH ACUTE AND DOT ABOVE
+\setXTXcharcodes "01E65 "01E65 "01E64 % LATIN SMALL LETTER S WITH ACUTE AND DOT ABOVE
+\setXTXcharcodes "01E66 "01E67 "01E66 % LATIN CAPITAL LETTER S WITH CARON AND DOT ABOVE
+\setXTXcharcodes "01E67 "01E67 "01E66 % LATIN SMALL LETTER S WITH CARON AND DOT ABOVE
+\setXTXcharcodes "01E68 "01E69 "01E68 % LATIN CAPITAL LETTER S WITH DOT BELOW AND DOT ABOVE
+\setXTXcharcodes "01E69 "01E69 "01E68 % LATIN SMALL LETTER S WITH DOT BELOW AND DOT ABOVE
+\setXTXcharcodes "01E6A "01E6B "01E6A % LATIN CAPITAL LETTER T WITH DOT ABOVE
+\setXTXcharcodes "01E6B "01E6B "01E6A % LATIN SMALL LETTER T WITH DOT ABOVE
+\setXTXcharcodes "01E6C "01E6D "01E6C % LATIN CAPITAL LETTER T WITH DOT BELOW
+\setXTXcharcodes "01E6D "01E6D "01E6C % LATIN SMALL LETTER T WITH DOT BELOW
+\setXTXcharcodes "01E6E "01E6F "01E6E % LATIN CAPITAL LETTER T WITH LINE BELOW
+\setXTXcharcodes "01E6F "01E6F "01E6E % LATIN SMALL LETTER T WITH LINE BELOW
+\setXTXcharcodes "01E70 "01E71 "01E70 % LATIN CAPITAL LETTER T WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E71 "01E71 "01E70 % LATIN SMALL LETTER T WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E72 "01E73 "01E72 % LATIN CAPITAL LETTER U WITH DIAERESIS BELOW
+\setXTXcharcodes "01E73 "01E73 "01E72 % LATIN SMALL LETTER U WITH DIAERESIS BELOW
+\setXTXcharcodes "01E74 "01E75 "01E74 % LATIN CAPITAL LETTER U WITH TILDE BELOW
+\setXTXcharcodes "01E75 "01E75 "01E74 % LATIN SMALL LETTER U WITH TILDE BELOW
+\setXTXcharcodes "01E76 "01E77 "01E76 % LATIN CAPITAL LETTER U WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E77 "01E77 "01E76 % LATIN SMALL LETTER U WITH CIRCUMFLEX BELOW
+\setXTXcharcodes "01E78 "01E79 "01E78 % LATIN CAPITAL LETTER U WITH TILDE AND ACUTE
+\setXTXcharcodes "01E79 "01E79 "01E78 % LATIN SMALL LETTER U WITH TILDE AND ACUTE
+\setXTXcharcodes "01E7A "01E7B "01E7A % LATIN CAPITAL LETTER U WITH MACRON AND DIAERESIS
+\setXTXcharcodes "01E7B "01E7B "01E7A % LATIN SMALL LETTER U WITH MACRON AND DIAERESIS
+\setXTXcharcodes "01E7C "01E7D "01E7C % LATIN CAPITAL LETTER V WITH TILDE
+\setXTXcharcodes "01E7D "01E7D "01E7C % LATIN SMALL LETTER V WITH TILDE
+\setXTXcharcodes "01E7E "01E7F "01E7E % LATIN CAPITAL LETTER V WITH DOT BELOW
+\setXTXcharcodes "01E7F "01E7F "01E7E % LATIN SMALL LETTER V WITH DOT BELOW
+\setXTXcharcodes "01E80 "01E81 "01E80 % LATIN CAPITAL LETTER W WITH GRAVE
+\setXTXcharcodes "01E81 "01E81 "01E80 % LATIN SMALL LETTER W WITH GRAVE
+\setXTXcharcodes "01E82 "01E83 "01E82 % LATIN CAPITAL LETTER W WITH ACUTE
+\setXTXcharcodes "01E83 "01E83 "01E82 % LATIN SMALL LETTER W WITH ACUTE
+\setXTXcharcodes "01E84 "01E85 "01E84 % LATIN CAPITAL LETTER W WITH DIAERESIS
+\setXTXcharcodes "01E85 "01E85 "01E84 % LATIN SMALL LETTER W WITH DIAERESIS
+\setXTXcharcodes "01E86 "01E87 "01E86 % LATIN CAPITAL LETTER W WITH DOT ABOVE
+\setXTXcharcodes "01E87 "01E87 "01E86 % LATIN SMALL LETTER W WITH DOT ABOVE
+\setXTXcharcodes "01E88 "01E89 "01E88 % LATIN CAPITAL LETTER W WITH DOT BELOW
+\setXTXcharcodes "01E89 "01E89 "01E88 % LATIN SMALL LETTER W WITH DOT BELOW
+\setXTXcharcodes "01E8A "01E8B "01E8A % LATIN CAPITAL LETTER X WITH DOT ABOVE
+\setXTXcharcodes "01E8B "01E8B "01E8A % LATIN SMALL LETTER X WITH DOT ABOVE
+\setXTXcharcodes "01E8C "01E8D "01E8C % LATIN CAPITAL LETTER X WITH DIAERESIS
+\setXTXcharcodes "01E8D "01E8D "01E8C % LATIN SMALL LETTER X WITH DIAERESIS
+\setXTXcharcodes "01E8E "01E8F "01E8E % LATIN CAPITAL LETTER Y WITH DOT ABOVE
+\setXTXcharcodes "01E8F "01E8F "01E8E % LATIN SMALL LETTER Y WITH DOT ABOVE
+\setXTXcharcodes "01E90 "01E91 "01E90 % LATIN CAPITAL LETTER Z WITH CIRCUMFLEX
+\setXTXcharcodes "01E91 "01E91 "01E90 % LATIN SMALL LETTER Z WITH CIRCUMFLEX
+\setXTXcharcodes "01E92 "01E93 "01E92 % LATIN CAPITAL LETTER Z WITH DOT BELOW
+\setXTXcharcodes "01E93 "01E93 "01E92 % LATIN SMALL LETTER Z WITH DOT BELOW
+\setXTXcharcodes "01E94 "01E95 "01E94 % LATIN CAPITAL LETTER Z WITH LINE BELOW
+\setXTXcharcodes "01E95 "01E95 "01E94 % LATIN SMALL LETTER Z WITH LINE BELOW
+\setXTXcharcodes "01E96 "01E96 "01E96 % LATIN SMALL LETTER H WITH LINE BELOW
+\setXTXcharcodes "01E97 "01E97 "01E97 % LATIN SMALL LETTER T WITH DIAERESIS
+\setXTXcharcodes "01E98 "01E98 "01E98 % LATIN SMALL LETTER W WITH RING ABOVE
+\setXTXcharcodes "01E99 "01E99 "01E99 % LATIN SMALL LETTER Y WITH RING ABOVE
+\setXTXcharcodes "01E9A "01E9A "01E9A % LATIN SMALL LETTER A WITH RIGHT HALF RING
+\setXTXcharcodes "01E9B "01E9B "01E60 % LATIN SMALL LETTER LONG S WITH DOT ABOVE
+\setXTXcharcodes "01EA0 "01EA1 "01EA0 % LATIN CAPITAL LETTER A WITH DOT BELOW
+\setXTXcharcodes "01EA1 "01EA1 "01EA0 % LATIN SMALL LETTER A WITH DOT BELOW
+\setXTXcharcodes "01EA2 "01EA3 "01EA2 % LATIN CAPITAL LETTER A WITH HOOK ABOVE
+\setXTXcharcodes "01EA3 "01EA3 "01EA2 % LATIN SMALL LETTER A WITH HOOK ABOVE
+\setXTXcharcodes "01EA4 "01EA5 "01EA4 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01EA5 "01EA5 "01EA4 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01EA6 "01EA7 "01EA6 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01EA7 "01EA7 "01EA6 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01EA8 "01EA9 "01EA8 % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01EA9 "01EA9 "01EA8 % LATIN SMALL LETTER A WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01EAA "01EAB "01EAA % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01EAB "01EAB "01EAA % LATIN SMALL LETTER A WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01EAC "01EAD "01EAC % LATIN CAPITAL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01EAD "01EAD "01EAC % LATIN SMALL LETTER A WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01EAE "01EAF "01EAE % LATIN CAPITAL LETTER A WITH BREVE AND ACUTE
+\setXTXcharcodes "01EAF "01EAF "01EAE % LATIN SMALL LETTER A WITH BREVE AND ACUTE
+\setXTXcharcodes "01EB0 "01EB1 "01EB0 % LATIN CAPITAL LETTER A WITH BREVE AND GRAVE
+\setXTXcharcodes "01EB1 "01EB1 "01EB0 % LATIN SMALL LETTER A WITH BREVE AND GRAVE
+\setXTXcharcodes "01EB2 "01EB3 "01EB2 % LATIN CAPITAL LETTER A WITH BREVE AND HOOK ABOVE
+\setXTXcharcodes "01EB3 "01EB3 "01EB2 % LATIN SMALL LETTER A WITH BREVE AND HOOK ABOVE
+\setXTXcharcodes "01EB4 "01EB5 "01EB4 % LATIN CAPITAL LETTER A WITH BREVE AND TILDE
+\setXTXcharcodes "01EB5 "01EB5 "01EB4 % LATIN SMALL LETTER A WITH BREVE AND TILDE
+\setXTXcharcodes "01EB6 "01EB7 "01EB6 % LATIN CAPITAL LETTER A WITH BREVE AND DOT BELOW
+\setXTXcharcodes "01EB7 "01EB7 "01EB6 % LATIN SMALL LETTER A WITH BREVE AND DOT BELOW
+\setXTXcharcodes "01EB8 "01EB9 "01EB8 % LATIN CAPITAL LETTER E WITH DOT BELOW
+\setXTXcharcodes "01EB9 "01EB9 "01EB8 % LATIN SMALL LETTER E WITH DOT BELOW
+\setXTXcharcodes "01EBA "01EBB "01EBA % LATIN CAPITAL LETTER E WITH HOOK ABOVE
+\setXTXcharcodes "01EBB "01EBB "01EBA % LATIN SMALL LETTER E WITH HOOK ABOVE
+\setXTXcharcodes "01EBC "01EBD "01EBC % LATIN CAPITAL LETTER E WITH TILDE
+\setXTXcharcodes "01EBD "01EBD "01EBC % LATIN SMALL LETTER E WITH TILDE
+\setXTXcharcodes "01EBE "01EBF "01EBE % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01EBF "01EBF "01EBE % LATIN SMALL LETTER E WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01EC0 "01EC1 "01EC0 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01EC1 "01EC1 "01EC0 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01EC2 "01EC3 "01EC2 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01EC3 "01EC3 "01EC2 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01EC4 "01EC5 "01EC4 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01EC5 "01EC5 "01EC4 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01EC6 "01EC7 "01EC6 % LATIN CAPITAL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01EC7 "01EC7 "01EC6 % LATIN SMALL LETTER E WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01EC8 "01EC9 "01EC8 % LATIN CAPITAL LETTER I WITH HOOK ABOVE
+\setXTXcharcodes "01EC9 "01EC9 "01EC8 % LATIN SMALL LETTER I WITH HOOK ABOVE
+\setXTXcharcodes "01ECA "01ECB "01ECA % LATIN CAPITAL LETTER I WITH DOT BELOW
+\setXTXcharcodes "01ECB "01ECB "01ECA % LATIN SMALL LETTER I WITH DOT BELOW
+\setXTXcharcodes "01ECC "01ECD "01ECC % LATIN CAPITAL LETTER O WITH DOT BELOW
+\setXTXcharcodes "01ECD "01ECD "01ECC % LATIN SMALL LETTER O WITH DOT BELOW
+\setXTXcharcodes "01ECE "01ECF "01ECE % LATIN CAPITAL LETTER O WITH HOOK ABOVE
+\setXTXcharcodes "01ECF "01ECF "01ECE % LATIN SMALL LETTER O WITH HOOK ABOVE
+\setXTXcharcodes "01ED0 "01ED1 "01ED0 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01ED1 "01ED1 "01ED0 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND ACUTE
+\setXTXcharcodes "01ED2 "01ED3 "01ED2 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01ED3 "01ED3 "01ED2 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND GRAVE
+\setXTXcharcodes "01ED4 "01ED5 "01ED4 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01ED5 "01ED5 "01ED4 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND HOOK ABOVE
+\setXTXcharcodes "01ED6 "01ED7 "01ED6 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01ED7 "01ED7 "01ED6 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND TILDE
+\setXTXcharcodes "01ED8 "01ED9 "01ED8 % LATIN CAPITAL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01ED9 "01ED9 "01ED8 % LATIN SMALL LETTER O WITH CIRCUMFLEX AND DOT BELOW
+\setXTXcharcodes "01EDA "01EDB "01EDA % LATIN CAPITAL LETTER O WITH HORN AND ACUTE
+\setXTXcharcodes "01EDB "01EDB "01EDA % LATIN SMALL LETTER O WITH HORN AND ACUTE
+\setXTXcharcodes "01EDC "01EDD "01EDC % LATIN CAPITAL LETTER O WITH HORN AND GRAVE
+\setXTXcharcodes "01EDD "01EDD "01EDC % LATIN SMALL LETTER O WITH HORN AND GRAVE
+\setXTXcharcodes "01EDE "01EDF "01EDE % LATIN CAPITAL LETTER O WITH HORN AND HOOK ABOVE
+\setXTXcharcodes "01EDF "01EDF "01EDE % LATIN SMALL LETTER O WITH HORN AND HOOK ABOVE
+\setXTXcharcodes "01EE0 "01EE1 "01EE0 % LATIN CAPITAL LETTER O WITH HORN AND TILDE
+\setXTXcharcodes "01EE1 "01EE1 "01EE0 % LATIN SMALL LETTER O WITH HORN AND TILDE
+\setXTXcharcodes "01EE2 "01EE3 "01EE2 % LATIN CAPITAL LETTER O WITH HORN AND DOT BELOW
+\setXTXcharcodes "01EE3 "01EE3 "01EE2 % LATIN SMALL LETTER O WITH HORN AND DOT BELOW
+\setXTXcharcodes "01EE4 "01EE5 "01EE4 % LATIN CAPITAL LETTER U WITH DOT BELOW
+\setXTXcharcodes "01EE5 "01EE5 "01EE4 % LATIN SMALL LETTER U WITH DOT BELOW
+\setXTXcharcodes "01EE6 "01EE7 "01EE6 % LATIN CAPITAL LETTER U WITH HOOK ABOVE
+\setXTXcharcodes "01EE7 "01EE7 "01EE6 % LATIN SMALL LETTER U WITH HOOK ABOVE
+\setXTXcharcodes "01EE8 "01EE9 "01EE8 % LATIN CAPITAL LETTER U WITH HORN AND ACUTE
+\setXTXcharcodes "01EE9 "01EE9 "01EE8 % LATIN SMALL LETTER U WITH HORN AND ACUTE
+\setXTXcharcodes "01EEA "01EEB "01EEA % LATIN CAPITAL LETTER U WITH HORN AND GRAVE
+\setXTXcharcodes "01EEB "01EEB "01EEA % LATIN SMALL LETTER U WITH HORN AND GRAVE
+\setXTXcharcodes "01EEC "01EED "01EEC % LATIN CAPITAL LETTER U WITH HORN AND HOOK ABOVE
+\setXTXcharcodes "01EED "01EED "01EEC % LATIN SMALL LETTER U WITH HORN AND HOOK ABOVE
+\setXTXcharcodes "01EEE "01EEF "01EEE % LATIN CAPITAL LETTER U WITH HORN AND TILDE
+\setXTXcharcodes "01EEF "01EEF "01EEE % LATIN SMALL LETTER U WITH HORN AND TILDE
+\setXTXcharcodes "01EF0 "01EF1 "01EF0 % LATIN CAPITAL LETTER U WITH HORN AND DOT BELOW
+\setXTXcharcodes "01EF1 "01EF1 "01EF0 % LATIN SMALL LETTER U WITH HORN AND DOT BELOW
+\setXTXcharcodes "01EF2 "01EF3 "01EF2 % LATIN CAPITAL LETTER Y WITH GRAVE
+\setXTXcharcodes "01EF3 "01EF3 "01EF2 % LATIN SMALL LETTER Y WITH GRAVE
+\setXTXcharcodes "01EF4 "01EF5 "01EF4 % LATIN CAPITAL LETTER Y WITH DOT BELOW
+\setXTXcharcodes "01EF5 "01EF5 "01EF4 % LATIN SMALL LETTER Y WITH DOT BELOW
+\setXTXcharcodes "01EF6 "01EF7 "01EF6 % LATIN CAPITAL LETTER Y WITH HOOK ABOVE
+\setXTXcharcodes "01EF7 "01EF7 "01EF6 % LATIN SMALL LETTER Y WITH HOOK ABOVE
+\setXTXcharcodes "01EF8 "01EF9 "01EF8 % LATIN CAPITAL LETTER Y WITH TILDE
+\setXTXcharcodes "01EF9 "01EF9 "01EF8 % LATIN SMALL LETTER Y WITH TILDE
+\setXTXcharcodes "01F00 "01F00 "01F08 % GREEK SMALL LETTER ALPHA WITH PSILI
+\setXTXcharcodes "01F01 "01F01 "01F09 % GREEK SMALL LETTER ALPHA WITH DASIA
+\setXTXcharcodes "01F02 "01F02 "01F0A % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA
+\setXTXcharcodes "01F03 "01F03 "01F0B % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA
+\setXTXcharcodes "01F04 "01F04 "01F0C % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA
+\setXTXcharcodes "01F05 "01F05 "01F0D % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA
+\setXTXcharcodes "01F06 "01F06 "01F0E % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F07 "01F07 "01F0F % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F08 "01F00 "01F08 % GREEK CAPITAL LETTER ALPHA WITH PSILI
+\setXTXcharcodes "01F09 "01F01 "01F09 % GREEK CAPITAL LETTER ALPHA WITH DASIA
+\setXTXcharcodes "01F0A "01F02 "01F0A % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA
+\setXTXcharcodes "01F0B "01F03 "01F0B % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA
+\setXTXcharcodes "01F0C "01F04 "01F0C % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA
+\setXTXcharcodes "01F0D "01F05 "01F0D % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA
+\setXTXcharcodes "01F0E "01F06 "01F0E % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F0F "01F07 "01F0F % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F10 "01F10 "01F18 % GREEK SMALL LETTER EPSILON WITH PSILI
+\setXTXcharcodes "01F11 "01F11 "01F19 % GREEK SMALL LETTER EPSILON WITH DASIA
+\setXTXcharcodes "01F12 "01F12 "01F1A % GREEK SMALL LETTER EPSILON WITH PSILI AND VARIA
+\setXTXcharcodes "01F13 "01F13 "01F1B % GREEK SMALL LETTER EPSILON WITH DASIA AND VARIA
+\setXTXcharcodes "01F14 "01F14 "01F1C % GREEK SMALL LETTER EPSILON WITH PSILI AND OXIA
+\setXTXcharcodes "01F15 "01F15 "01F1D % GREEK SMALL LETTER EPSILON WITH DASIA AND OXIA
+\setXTXcharcodes "01F18 "01F10 "01F18 % GREEK CAPITAL LETTER EPSILON WITH PSILI
+\setXTXcharcodes "01F19 "01F11 "01F19 % GREEK CAPITAL LETTER EPSILON WITH DASIA
+\setXTXcharcodes "01F1A "01F12 "01F1A % GREEK CAPITAL LETTER EPSILON WITH PSILI AND VARIA
+\setXTXcharcodes "01F1B "01F13 "01F1B % GREEK CAPITAL LETTER EPSILON WITH DASIA AND VARIA
+\setXTXcharcodes "01F1C "01F14 "01F1C % GREEK CAPITAL LETTER EPSILON WITH PSILI AND OXIA
+\setXTXcharcodes "01F1D "01F15 "01F1D % GREEK CAPITAL LETTER EPSILON WITH DASIA AND OXIA
+\setXTXcharcodes "01F20 "01F20 "01F28 % GREEK SMALL LETTER ETA WITH PSILI
+\setXTXcharcodes "01F21 "01F21 "01F29 % GREEK SMALL LETTER ETA WITH DASIA
+\setXTXcharcodes "01F22 "01F22 "01F2A % GREEK SMALL LETTER ETA WITH PSILI AND VARIA
+\setXTXcharcodes "01F23 "01F23 "01F2B % GREEK SMALL LETTER ETA WITH DASIA AND VARIA
+\setXTXcharcodes "01F24 "01F24 "01F2C % GREEK SMALL LETTER ETA WITH PSILI AND OXIA
+\setXTXcharcodes "01F25 "01F25 "01F2D % GREEK SMALL LETTER ETA WITH DASIA AND OXIA
+\setXTXcharcodes "01F26 "01F26 "01F2E % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F27 "01F27 "01F2F % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F28 "01F20 "01F28 % GREEK CAPITAL LETTER ETA WITH PSILI
+\setXTXcharcodes "01F29 "01F21 "01F29 % GREEK CAPITAL LETTER ETA WITH DASIA
+\setXTXcharcodes "01F2A "01F22 "01F2A % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA
+\setXTXcharcodes "01F2B "01F23 "01F2B % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA
+\setXTXcharcodes "01F2C "01F24 "01F2C % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA
+\setXTXcharcodes "01F2D "01F25 "01F2D % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA
+\setXTXcharcodes "01F2E "01F26 "01F2E % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F2F "01F27 "01F2F % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F30 "01F30 "01F38 % GREEK SMALL LETTER IOTA WITH PSILI
+\setXTXcharcodes "01F31 "01F31 "01F39 % GREEK SMALL LETTER IOTA WITH DASIA
+\setXTXcharcodes "01F32 "01F32 "01F3A % GREEK SMALL LETTER IOTA WITH PSILI AND VARIA
+\setXTXcharcodes "01F33 "01F33 "01F3B % GREEK SMALL LETTER IOTA WITH DASIA AND VARIA
+\setXTXcharcodes "01F34 "01F34 "01F3C % GREEK SMALL LETTER IOTA WITH PSILI AND OXIA
+\setXTXcharcodes "01F35 "01F35 "01F3D % GREEK SMALL LETTER IOTA WITH DASIA AND OXIA
+\setXTXcharcodes "01F36 "01F36 "01F3E % GREEK SMALL LETTER IOTA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F37 "01F37 "01F3F % GREEK SMALL LETTER IOTA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F38 "01F30 "01F38 % GREEK CAPITAL LETTER IOTA WITH PSILI
+\setXTXcharcodes "01F39 "01F31 "01F39 % GREEK CAPITAL LETTER IOTA WITH DASIA
+\setXTXcharcodes "01F3A "01F32 "01F3A % GREEK CAPITAL LETTER IOTA WITH PSILI AND VARIA
+\setXTXcharcodes "01F3B "01F33 "01F3B % GREEK CAPITAL LETTER IOTA WITH DASIA AND VARIA
+\setXTXcharcodes "01F3C "01F34 "01F3C % GREEK CAPITAL LETTER IOTA WITH PSILI AND OXIA
+\setXTXcharcodes "01F3D "01F35 "01F3D % GREEK CAPITAL LETTER IOTA WITH DASIA AND OXIA
+\setXTXcharcodes "01F3E "01F36 "01F3E % GREEK CAPITAL LETTER IOTA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F3F "01F37 "01F3F % GREEK CAPITAL LETTER IOTA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F40 "01F40 "01F48 % GREEK SMALL LETTER OMICRON WITH PSILI
+\setXTXcharcodes "01F41 "01F41 "01F49 % GREEK SMALL LETTER OMICRON WITH DASIA
+\setXTXcharcodes "01F42 "01F42 "01F4A % GREEK SMALL LETTER OMICRON WITH PSILI AND VARIA
+\setXTXcharcodes "01F43 "01F43 "01F4B % GREEK SMALL LETTER OMICRON WITH DASIA AND VARIA
+\setXTXcharcodes "01F44 "01F44 "01F4C % GREEK SMALL LETTER OMICRON WITH PSILI AND OXIA
+\setXTXcharcodes "01F45 "01F45 "01F4D % GREEK SMALL LETTER OMICRON WITH DASIA AND OXIA
+\setXTXcharcodes "01F48 "01F40 "01F48 % GREEK CAPITAL LETTER OMICRON WITH PSILI
+\setXTXcharcodes "01F49 "01F41 "01F49 % GREEK CAPITAL LETTER OMICRON WITH DASIA
+\setXTXcharcodes "01F4A "01F42 "01F4A % GREEK CAPITAL LETTER OMICRON WITH PSILI AND VARIA
+\setXTXcharcodes "01F4B "01F43 "01F4B % GREEK CAPITAL LETTER OMICRON WITH DASIA AND VARIA
+\setXTXcharcodes "01F4C "01F44 "01F4C % GREEK CAPITAL LETTER OMICRON WITH PSILI AND OXIA
+\setXTXcharcodes "01F4D "01F45 "01F4D % GREEK CAPITAL LETTER OMICRON WITH DASIA AND OXIA
+\setXTXcharcodes "01F50 "01F50 "01F50 % GREEK SMALL LETTER UPSILON WITH PSILI
+\setXTXcharcodes "01F51 "01F51 "01F59 % GREEK SMALL LETTER UPSILON WITH DASIA
+\setXTXcharcodes "01F52 "01F52 "01F52 % GREEK SMALL LETTER UPSILON WITH PSILI AND VARIA
+\setXTXcharcodes "01F53 "01F53 "01F5B % GREEK SMALL LETTER UPSILON WITH DASIA AND VARIA
+\setXTXcharcodes "01F54 "01F54 "01F54 % GREEK SMALL LETTER UPSILON WITH PSILI AND OXIA
+\setXTXcharcodes "01F55 "01F55 "01F5D % GREEK SMALL LETTER UPSILON WITH DASIA AND OXIA
+\setXTXcharcodes "01F56 "01F56 "01F56 % GREEK SMALL LETTER UPSILON WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F57 "01F57 "01F5F % GREEK SMALL LETTER UPSILON WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F59 "01F51 "01F59 % GREEK CAPITAL LETTER UPSILON WITH DASIA
+\setXTXcharcodes "01F5B "01F53 "01F5B % GREEK CAPITAL LETTER UPSILON WITH DASIA AND VARIA
+\setXTXcharcodes "01F5D "01F55 "01F5D % GREEK CAPITAL LETTER UPSILON WITH DASIA AND OXIA
+\setXTXcharcodes "01F5F "01F57 "01F5F % GREEK CAPITAL LETTER UPSILON WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F60 "01F60 "01F68 % GREEK SMALL LETTER OMEGA WITH PSILI
+\setXTXcharcodes "01F61 "01F61 "01F69 % GREEK SMALL LETTER OMEGA WITH DASIA
+\setXTXcharcodes "01F62 "01F62 "01F6A % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA
+\setXTXcharcodes "01F63 "01F63 "01F6B % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA
+\setXTXcharcodes "01F64 "01F64 "01F6C % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA
+\setXTXcharcodes "01F65 "01F65 "01F6D % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA
+\setXTXcharcodes "01F66 "01F66 "01F6E % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F67 "01F67 "01F6F % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F68 "01F60 "01F68 % GREEK CAPITAL LETTER OMEGA WITH PSILI
+\setXTXcharcodes "01F69 "01F61 "01F69 % GREEK CAPITAL LETTER OMEGA WITH DASIA
+\setXTXcharcodes "01F6A "01F62 "01F6A % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA
+\setXTXcharcodes "01F6B "01F63 "01F6B % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA
+\setXTXcharcodes "01F6C "01F64 "01F6C % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA
+\setXTXcharcodes "01F6D "01F65 "01F6D % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA
+\setXTXcharcodes "01F6E "01F66 "01F6E % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI
+\setXTXcharcodes "01F6F "01F67 "01F6F % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI
+\setXTXcharcodes "01F70 "01F70 "01FBA % GREEK SMALL LETTER ALPHA WITH VARIA
+\setXTXcharcodes "01F71 "01F71 "01FBB % GREEK SMALL LETTER ALPHA WITH OXIA
+\setXTXcharcodes "01F72 "01F72 "01FC8 % GREEK SMALL LETTER EPSILON WITH VARIA
+\setXTXcharcodes "01F73 "01F73 "01FC9 % GREEK SMALL LETTER EPSILON WITH OXIA
+\setXTXcharcodes "01F74 "01F74 "01FCA % GREEK SMALL LETTER ETA WITH VARIA
+\setXTXcharcodes "01F75 "01F75 "01FCB % GREEK SMALL LETTER ETA WITH OXIA
+\setXTXcharcodes "01F76 "01F76 "01FDA % GREEK SMALL LETTER IOTA WITH VARIA
+\setXTXcharcodes "01F77 "01F77 "01FDB % GREEK SMALL LETTER IOTA WITH OXIA
+\setXTXcharcodes "01F78 "01F78 "01FF8 % GREEK SMALL LETTER OMICRON WITH VARIA
+\setXTXcharcodes "01F79 "01F79 "01FF9 % GREEK SMALL LETTER OMICRON WITH OXIA
+\setXTXcharcodes "01F7A "01F7A "01FEA % GREEK SMALL LETTER UPSILON WITH VARIA
+\setXTXcharcodes "01F7B "01F7B "01FEB % GREEK SMALL LETTER UPSILON WITH OXIA
+\setXTXcharcodes "01F7C "01F7C "01FFA % GREEK SMALL LETTER OMEGA WITH VARIA
+\setXTXcharcodes "01F7D "01F7D "01FFB % GREEK SMALL LETTER OMEGA WITH OXIA
+\setXTXcharcodes "01F80 "01F80 "01F88 % GREEK SMALL LETTER ALPHA WITH PSILI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F81 "01F81 "01F89 % GREEK SMALL LETTER ALPHA WITH DASIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F82 "01F82 "01F8A % GREEK SMALL LETTER ALPHA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F83 "01F83 "01F8B % GREEK SMALL LETTER ALPHA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F84 "01F84 "01F8C % GREEK SMALL LETTER ALPHA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F85 "01F85 "01F8D % GREEK SMALL LETTER ALPHA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F86 "01F86 "01F8E % GREEK SMALL LETTER ALPHA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F87 "01F87 "01F8F % GREEK SMALL LETTER ALPHA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F88 "01F80 "01F88 % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PROSGEGRAMMENI
+\setXTXcharcodes "01F89 "01F81 "01F89 % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8A "01F82 "01F8A % GREEK CAPITAL LETTER ALPHA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8B "01F83 "01F8B % GREEK CAPITAL LETTER ALPHA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8C "01F84 "01F8C % GREEK CAPITAL LETTER ALPHA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8D "01F85 "01F8D % GREEK CAPITAL LETTER ALPHA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8E "01F86 "01F8E % GREEK CAPITAL LETTER ALPHA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01F8F "01F87 "01F8F % GREEK CAPITAL LETTER ALPHA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01F90 "01F90 "01F98 % GREEK SMALL LETTER ETA WITH PSILI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F91 "01F91 "01F99 % GREEK SMALL LETTER ETA WITH DASIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F92 "01F92 "01F9A % GREEK SMALL LETTER ETA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F93 "01F93 "01F9B % GREEK SMALL LETTER ETA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F94 "01F94 "01F9C % GREEK SMALL LETTER ETA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F95 "01F95 "01F9D % GREEK SMALL LETTER ETA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01F96 "01F96 "01F9E % GREEK SMALL LETTER ETA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F97 "01F97 "01F9F % GREEK SMALL LETTER ETA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01F98 "01F90 "01F98 % GREEK CAPITAL LETTER ETA WITH PSILI AND PROSGEGRAMMENI
+\setXTXcharcodes "01F99 "01F91 "01F99 % GREEK CAPITAL LETTER ETA WITH DASIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9A "01F92 "01F9A % GREEK CAPITAL LETTER ETA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9B "01F93 "01F9B % GREEK CAPITAL LETTER ETA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9C "01F94 "01F9C % GREEK CAPITAL LETTER ETA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9D "01F95 "01F9D % GREEK CAPITAL LETTER ETA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9E "01F96 "01F9E % GREEK CAPITAL LETTER ETA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01F9F "01F97 "01F9F % GREEK CAPITAL LETTER ETA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01FA0 "01FA0 "01FA8 % GREEK SMALL LETTER OMEGA WITH PSILI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA1 "01FA1 "01FA9 % GREEK SMALL LETTER OMEGA WITH DASIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA2 "01FA2 "01FAA % GREEK SMALL LETTER OMEGA WITH PSILI AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA3 "01FA3 "01FAB % GREEK SMALL LETTER OMEGA WITH DASIA AND VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA4 "01FA4 "01FAC % GREEK SMALL LETTER OMEGA WITH PSILI AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA5 "01FA5 "01FAD % GREEK SMALL LETTER OMEGA WITH DASIA AND OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA6 "01FA6 "01FAE % GREEK SMALL LETTER OMEGA WITH PSILI AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA7 "01FA7 "01FAF % GREEK SMALL LETTER OMEGA WITH DASIA AND PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FA8 "01FA0 "01FA8 % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PROSGEGRAMMENI
+\setXTXcharcodes "01FA9 "01FA1 "01FA9 % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAA "01FA2 "01FAA % GREEK CAPITAL LETTER OMEGA WITH PSILI AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAB "01FA3 "01FAB % GREEK CAPITAL LETTER OMEGA WITH DASIA AND VARIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAC "01FA4 "01FAC % GREEK CAPITAL LETTER OMEGA WITH PSILI AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAD "01FA5 "01FAD % GREEK CAPITAL LETTER OMEGA WITH DASIA AND OXIA AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAE "01FA6 "01FAE % GREEK CAPITAL LETTER OMEGA WITH PSILI AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01FAF "01FA7 "01FAF % GREEK CAPITAL LETTER OMEGA WITH DASIA AND PERISPOMENI AND PROSGEGRAMMENI
+\setXTXcharcodes "01FB0 "01FB0 "01FB8 % GREEK SMALL LETTER ALPHA WITH VRACHY
+\setXTXcharcodes "01FB1 "01FB1 "01FB9 % GREEK SMALL LETTER ALPHA WITH MACRON
+\setXTXcharcodes "01FB2 "01FB2 "01FB2 % GREEK SMALL LETTER ALPHA WITH VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FB3 "01FB3 "01FBC % GREEK SMALL LETTER ALPHA WITH YPOGEGRAMMENI
+\setXTXcharcodes "01FB4 "01FB4 "01FB4 % GREEK SMALL LETTER ALPHA WITH OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FB6 "01FB6 "01FB6 % GREEK SMALL LETTER ALPHA WITH PERISPOMENI
+\setXTXcharcodes "01FB7 "01FB7 "01FB7 % GREEK SMALL LETTER ALPHA WITH PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FB8 "01FB0 "01FB8 % GREEK CAPITAL LETTER ALPHA WITH VRACHY
+\setXTXcharcodes "01FB9 "01FB1 "01FB9 % GREEK CAPITAL LETTER ALPHA WITH MACRON
+\setXTXcharcodes "01FBA "01F70 "01FBA % GREEK CAPITAL LETTER ALPHA WITH VARIA
+\setXTXcharcodes "01FBB "01F71 "01FBB % GREEK CAPITAL LETTER ALPHA WITH OXIA
+\setXTXcharcodes "01FBC "01FB3 "01FBC % GREEK CAPITAL LETTER ALPHA WITH PROSGEGRAMMENI
+\setXTXcharcodes "01FBE "01FBE "00399 % GREEK PROSGEGRAMMENI
+\setXTXcharcodes "01FC2 "01FC2 "01FC2 % GREEK SMALL LETTER ETA WITH VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FC3 "01FC3 "01FCC % GREEK SMALL LETTER ETA WITH YPOGEGRAMMENI
+\setXTXcharcodes "01FC4 "01FC4 "01FC4 % GREEK SMALL LETTER ETA WITH OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FC6 "01FC6 "01FC6 % GREEK SMALL LETTER ETA WITH PERISPOMENI
+\setXTXcharcodes "01FC7 "01FC7 "01FC7 % GREEK SMALL LETTER ETA WITH PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FC8 "01F72 "01FC8 % GREEK CAPITAL LETTER EPSILON WITH VARIA
+\setXTXcharcodes "01FC9 "01F73 "01FC9 % GREEK CAPITAL LETTER EPSILON WITH OXIA
+\setXTXcharcodes "01FCA "01F74 "01FCA % GREEK CAPITAL LETTER ETA WITH VARIA
+\setXTXcharcodes "01FCB "01F75 "01FCB % GREEK CAPITAL LETTER ETA WITH OXIA
+\setXTXcharcodes "01FCC "01FC3 "01FCC % GREEK CAPITAL LETTER ETA WITH PROSGEGRAMMENI
+\setXTXcharcodes "01FD0 "01FD0 "01FD8 % GREEK SMALL LETTER IOTA WITH VRACHY
+\setXTXcharcodes "01FD1 "01FD1 "01FD9 % GREEK SMALL LETTER IOTA WITH MACRON
+\setXTXcharcodes "01FD2 "01FD2 "01FD2 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND VARIA
+\setXTXcharcodes "01FD3 "01FD3 "01FD3 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND OXIA
+\setXTXcharcodes "01FD6 "01FD6 "01FD6 % GREEK SMALL LETTER IOTA WITH PERISPOMENI
+\setXTXcharcodes "01FD7 "01FD7 "01FD7 % GREEK SMALL LETTER IOTA WITH DIALYTIKA AND PERISPOMENI
+\setXTXcharcodes "01FD8 "01FD0 "01FD8 % GREEK CAPITAL LETTER IOTA WITH VRACHY
+\setXTXcharcodes "01FD9 "01FD1 "01FD9 % GREEK CAPITAL LETTER IOTA WITH MACRON
+\setXTXcharcodes "01FDA "01F76 "01FDA % GREEK CAPITAL LETTER IOTA WITH VARIA
+\setXTXcharcodes "01FDB "01F77 "01FDB % GREEK CAPITAL LETTER IOTA WITH OXIA
+\setXTXcharcodes "01FE0 "01FE0 "01FE8 % GREEK SMALL LETTER UPSILON WITH VRACHY
+\setXTXcharcodes "01FE1 "01FE1 "01FE9 % GREEK SMALL LETTER UPSILON WITH MACRON
+\setXTXcharcodes "01FE2 "01FE2 "01FE2 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND VARIA
+\setXTXcharcodes "01FE3 "01FE3 "01FE3 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND OXIA
+\setXTXcharcodes "01FE4 "01FE4 "01FE4 % GREEK SMALL LETTER RHO WITH PSILI
+\setXTXcharcodes "01FE5 "01FE5 "01FEC % GREEK SMALL LETTER RHO WITH DASIA
+\setXTXcharcodes "01FE6 "01FE6 "01FE6 % GREEK SMALL LETTER UPSILON WITH PERISPOMENI
+\setXTXcharcodes "01FE7 "01FE7 "01FE7 % GREEK SMALL LETTER UPSILON WITH DIALYTIKA AND PERISPOMENI
+\setXTXcharcodes "01FE8 "01FE0 "01FE8 % GREEK CAPITAL LETTER UPSILON WITH VRACHY
+\setXTXcharcodes "01FE9 "01FE1 "01FE9 % GREEK CAPITAL LETTER UPSILON WITH MACRON
+\setXTXcharcodes "01FEA "01F7A "01FEA % GREEK CAPITAL LETTER UPSILON WITH VARIA
+\setXTXcharcodes "01FEB "01F7B "01FEB % GREEK CAPITAL LETTER UPSILON WITH OXIA
+\setXTXcharcodes "01FEC "01FE5 "01FEC % GREEK CAPITAL LETTER RHO WITH DASIA
+\setXTXcharcodes "01FF2 "01FF2 "01FF2 % GREEK SMALL LETTER OMEGA WITH VARIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FF3 "01FF3 "01FFC % GREEK SMALL LETTER OMEGA WITH YPOGEGRAMMENI
+\setXTXcharcodes "01FF4 "01FF4 "01FF4 % GREEK SMALL LETTER OMEGA WITH OXIA AND YPOGEGRAMMENI
+\setXTXcharcodes "01FF6 "01FF6 "01FF6 % GREEK SMALL LETTER OMEGA WITH PERISPOMENI
+\setXTXcharcodes "01FF7 "01FF7 "01FF7 % GREEK SMALL LETTER OMEGA WITH PERISPOMENI AND YPOGEGRAMMENI
+\setXTXcharcodes "01FF8 "01F78 "01FF8 % GREEK CAPITAL LETTER OMICRON WITH VARIA
+\setXTXcharcodes "01FF9 "01F79 "01FF9 % GREEK CAPITAL LETTER OMICRON WITH OXIA
+\setXTXcharcodes "01FFA "01F7C "01FFA % GREEK CAPITAL LETTER OMEGA WITH VARIA
+\setXTXcharcodes "01FFB "01F7D "01FFB % GREEK CAPITAL LETTER OMEGA WITH OXIA
+\setXTXcharcodes "01FFC "01FF3 "01FFC % GREEK CAPITAL LETTER OMEGA WITH PROSGEGRAMMENI
+\setXTXcharcodes "02071 "02071 "02071 % SUPERSCRIPT LATIN SMALL LETTER I
+\setXTXcharcodes "0207F "0207F "0207F % SUPERSCRIPT LATIN SMALL LETTER N
+\setXTXcharcodes "02102 "02102 "02102 % DOUBLE-STRUCK CAPITAL C
+\setXTXcharcodes "02107 "02107 "02107 % EULER CONSTANT
+\setXTXcharcodes "0210A "0210A "0210A % SCRIPT SMALL G
+\setXTXcharcodes "0210B "0210B "0210B % SCRIPT CAPITAL H
+\setXTXcharcodes "0210C "0210C "0210C % BLACK-LETTER CAPITAL H
+\setXTXcharcodes "0210D "0210D "0210D % DOUBLE-STRUCK CAPITAL H
+\setXTXcharcodes "0210E "0210E "0210E % PLANCK CONSTANT
+\setXTXcharcodes "0210F "0210F "0210F % PLANCK CONSTANT OVER TWO PI
+\setXTXcharcodes "02110 "02110 "02110 % SCRIPT CAPITAL I
+\setXTXcharcodes "02111 "02111 "02111 % BLACK-LETTER CAPITAL I
+\setXTXcharcodes "02112 "02112 "02112 % SCRIPT CAPITAL L
+\setXTXcharcodes "02113 "02113 "02113 % SCRIPT SMALL L
+\setXTXcharcodes "02115 "02115 "02115 % DOUBLE-STRUCK CAPITAL N
+\setXTXcharcodes "02119 "02119 "02119 % DOUBLE-STRUCK CAPITAL P
+\setXTXcharcodes "0211A "0211A "0211A % DOUBLE-STRUCK CAPITAL Q
+\setXTXcharcodes "0211B "0211B "0211B % SCRIPT CAPITAL R
+\setXTXcharcodes "0211C "0211C "0211C % BLACK-LETTER CAPITAL R
+\setXTXcharcodes "0211D "0211D "0211D % DOUBLE-STRUCK CAPITAL R
+\setXTXcharcodes "02124 "02124 "02124 % DOUBLE-STRUCK CAPITAL Z
+\setXTXcharcodes "02126 "003C9 "02126 % OHM SIGN
+\setXTXcharcodes "02128 "02128 "02128 % BLACK-LETTER CAPITAL Z
+\setXTXcharcodes "0212A "0006B "0212A % KELVIN SIGN
+\setXTXcharcodes "0212B "000E5 "0212B % ANGSTROM SIGN
+\setXTXcharcodes "0212C "0212C "0212C % SCRIPT CAPITAL B
+\setXTXcharcodes "0212D "0212D "0212D % BLACK-LETTER CAPITAL C
+\setXTXcharcodes "0212F "0212F "0212F % SCRIPT SMALL E
+\setXTXcharcodes "02130 "02130 "02130 % SCRIPT CAPITAL E
+\setXTXcharcodes "02131 "02131 "02131 % SCRIPT CAPITAL F
+\setXTXcharcodes "02132 "0214E "02132 % TURNED CAPITAL F
+\setXTXcharcodes "02133 "02133 "02133 % SCRIPT CAPITAL M
+\setXTXcharcodes "02134 "02134 "02134 % SCRIPT SMALL O
+\setXTXcharcodes "02139 "02139 "02139 % INFORMATION SOURCE
+\setXTXcharcodes "0213C "0213C "0213C % DOUBLE-STRUCK SMALL PI
+\setXTXcharcodes "0213D "0213D "0213D % DOUBLE-STRUCK SMALL GAMMA
+\setXTXcharcodes "0213E "0213E "0213E % DOUBLE-STRUCK CAPITAL GAMMA
+\setXTXcharcodes "0213F "0213F "0213F % DOUBLE-STRUCK CAPITAL PI
+\setXTXcharcodes "02145 "02145 "02145 % DOUBLE-STRUCK ITALIC CAPITAL D
+\setXTXcharcodes "02146 "02146 "02146 % DOUBLE-STRUCK ITALIC SMALL D
+\setXTXcharcodes "02147 "02147 "02147 % DOUBLE-STRUCK ITALIC SMALL E
+\setXTXcharcodes "02148 "02148 "02148 % DOUBLE-STRUCK ITALIC SMALL I
+\setXTXcharcodes "02149 "02149 "02149 % DOUBLE-STRUCK ITALIC SMALL J
+\setXTXcharcodes "0214E "0214E "02132 % TURNED SMALL F
+\setXTXcharcodes "02183 "02184 "02183 % ROMAN NUMERAL REVERSED ONE HUNDRED
+\setXTXcharcodes "02184 "02184 "02183 % LATIN SMALL LETTER REVERSED C
+\setXTXcharcodes "02C00 "02C30 "02C00 % GLAGOLITIC CAPITAL LETTER AZU
+\setXTXcharcodes "02C01 "02C31 "02C01 % GLAGOLITIC CAPITAL LETTER BUKY
+\setXTXcharcodes "02C02 "02C32 "02C02 % GLAGOLITIC CAPITAL LETTER VEDE
+\setXTXcharcodes "02C03 "02C33 "02C03 % GLAGOLITIC CAPITAL LETTER GLAGOLI
+\setXTXcharcodes "02C04 "02C34 "02C04 % GLAGOLITIC CAPITAL LETTER DOBRO
+\setXTXcharcodes "02C05 "02C35 "02C05 % GLAGOLITIC CAPITAL LETTER YESTU
+\setXTXcharcodes "02C06 "02C36 "02C06 % GLAGOLITIC CAPITAL LETTER ZHIVETE
+\setXTXcharcodes "02C07 "02C37 "02C07 % GLAGOLITIC CAPITAL LETTER DZELO
+\setXTXcharcodes "02C08 "02C38 "02C08 % GLAGOLITIC CAPITAL LETTER ZEMLJA
+\setXTXcharcodes "02C09 "02C39 "02C09 % GLAGOLITIC CAPITAL LETTER IZHE
+\setXTXcharcodes "02C0A "02C3A "02C0A % GLAGOLITIC CAPITAL LETTER INITIAL IZHE
+\setXTXcharcodes "02C0B "02C3B "02C0B % GLAGOLITIC CAPITAL LETTER I
+\setXTXcharcodes "02C0C "02C3C "02C0C % GLAGOLITIC CAPITAL LETTER DJERVI
+\setXTXcharcodes "02C0D "02C3D "02C0D % GLAGOLITIC CAPITAL LETTER KAKO
+\setXTXcharcodes "02C0E "02C3E "02C0E % GLAGOLITIC CAPITAL LETTER LJUDIJE
+\setXTXcharcodes "02C0F "02C3F "02C0F % GLAGOLITIC CAPITAL LETTER MYSLITE
+\setXTXcharcodes "02C10 "02C40 "02C10 % GLAGOLITIC CAPITAL LETTER NASHI
+\setXTXcharcodes "02C11 "02C41 "02C11 % GLAGOLITIC CAPITAL LETTER ONU
+\setXTXcharcodes "02C12 "02C42 "02C12 % GLAGOLITIC CAPITAL LETTER POKOJI
+\setXTXcharcodes "02C13 "02C43 "02C13 % GLAGOLITIC CAPITAL LETTER RITSI
+\setXTXcharcodes "02C14 "02C44 "02C14 % GLAGOLITIC CAPITAL LETTER SLOVO
+\setXTXcharcodes "02C15 "02C45 "02C15 % GLAGOLITIC CAPITAL LETTER TVRIDO
+\setXTXcharcodes "02C16 "02C46 "02C16 % GLAGOLITIC CAPITAL LETTER UKU
+\setXTXcharcodes "02C17 "02C47 "02C17 % GLAGOLITIC CAPITAL LETTER FRITU
+\setXTXcharcodes "02C18 "02C48 "02C18 % GLAGOLITIC CAPITAL LETTER HERU
+\setXTXcharcodes "02C19 "02C49 "02C19 % GLAGOLITIC CAPITAL LETTER OTU
+\setXTXcharcodes "02C1A "02C4A "02C1A % GLAGOLITIC CAPITAL LETTER PE
+\setXTXcharcodes "02C1B "02C4B "02C1B % GLAGOLITIC CAPITAL LETTER SHTA
+\setXTXcharcodes "02C1C "02C4C "02C1C % GLAGOLITIC CAPITAL LETTER TSI
+\setXTXcharcodes "02C1D "02C4D "02C1D % GLAGOLITIC CAPITAL LETTER CHRIVI
+\setXTXcharcodes "02C1E "02C4E "02C1E % GLAGOLITIC CAPITAL LETTER SHA
+\setXTXcharcodes "02C1F "02C4F "02C1F % GLAGOLITIC CAPITAL LETTER YERU
+\setXTXcharcodes "02C20 "02C50 "02C20 % GLAGOLITIC CAPITAL LETTER YERI
+\setXTXcharcodes "02C21 "02C51 "02C21 % GLAGOLITIC CAPITAL LETTER YATI
+\setXTXcharcodes "02C22 "02C52 "02C22 % GLAGOLITIC CAPITAL LETTER SPIDERY HA
+\setXTXcharcodes "02C23 "02C53 "02C23 % GLAGOLITIC CAPITAL LETTER YU
+\setXTXcharcodes "02C24 "02C54 "02C24 % GLAGOLITIC CAPITAL LETTER SMALL YUS
+\setXTXcharcodes "02C25 "02C55 "02C25 % GLAGOLITIC CAPITAL LETTER SMALL YUS WITH TAIL
+\setXTXcharcodes "02C26 "02C56 "02C26 % GLAGOLITIC CAPITAL LETTER YO
+\setXTXcharcodes "02C27 "02C57 "02C27 % GLAGOLITIC CAPITAL LETTER IOTATED SMALL YUS
+\setXTXcharcodes "02C28 "02C58 "02C28 % GLAGOLITIC CAPITAL LETTER BIG YUS
+\setXTXcharcodes "02C29 "02C59 "02C29 % GLAGOLITIC CAPITAL LETTER IOTATED BIG YUS
+\setXTXcharcodes "02C2A "02C5A "02C2A % GLAGOLITIC CAPITAL LETTER FITA
+\setXTXcharcodes "02C2B "02C5B "02C2B % GLAGOLITIC CAPITAL LETTER IZHITSA
+\setXTXcharcodes "02C2C "02C5C "02C2C % GLAGOLITIC CAPITAL LETTER SHTAPIC
+\setXTXcharcodes "02C2D "02C5D "02C2D % GLAGOLITIC CAPITAL LETTER TROKUTASTI A
+\setXTXcharcodes "02C2E "02C5E "02C2E % GLAGOLITIC CAPITAL LETTER LATINATE MYSLITE
+\setXTXcharcodes "02C30 "02C30 "02C00 % GLAGOLITIC SMALL LETTER AZU
+\setXTXcharcodes "02C31 "02C31 "02C01 % GLAGOLITIC SMALL LETTER BUKY
+\setXTXcharcodes "02C32 "02C32 "02C02 % GLAGOLITIC SMALL LETTER VEDE
+\setXTXcharcodes "02C33 "02C33 "02C03 % GLAGOLITIC SMALL LETTER GLAGOLI
+\setXTXcharcodes "02C34 "02C34 "02C04 % GLAGOLITIC SMALL LETTER DOBRO
+\setXTXcharcodes "02C35 "02C35 "02C05 % GLAGOLITIC SMALL LETTER YESTU
+\setXTXcharcodes "02C36 "02C36 "02C06 % GLAGOLITIC SMALL LETTER ZHIVETE
+\setXTXcharcodes "02C37 "02C37 "02C07 % GLAGOLITIC SMALL LETTER DZELO
+\setXTXcharcodes "02C38 "02C38 "02C08 % GLAGOLITIC SMALL LETTER ZEMLJA
+\setXTXcharcodes "02C39 "02C39 "02C09 % GLAGOLITIC SMALL LETTER IZHE
+\setXTXcharcodes "02C3A "02C3A "02C0A % GLAGOLITIC SMALL LETTER INITIAL IZHE
+\setXTXcharcodes "02C3B "02C3B "02C0B % GLAGOLITIC SMALL LETTER I
+\setXTXcharcodes "02C3C "02C3C "02C0C % GLAGOLITIC SMALL LETTER DJERVI
+\setXTXcharcodes "02C3D "02C3D "02C0D % GLAGOLITIC SMALL LETTER KAKO
+\setXTXcharcodes "02C3E "02C3E "02C0E % GLAGOLITIC SMALL LETTER LJUDIJE
+\setXTXcharcodes "02C3F "02C3F "02C0F % GLAGOLITIC SMALL LETTER MYSLITE
+\setXTXcharcodes "02C40 "02C40 "02C10 % GLAGOLITIC SMALL LETTER NASHI
+\setXTXcharcodes "02C41 "02C41 "02C11 % GLAGOLITIC SMALL LETTER ONU
+\setXTXcharcodes "02C42 "02C42 "02C12 % GLAGOLITIC SMALL LETTER POKOJI
+\setXTXcharcodes "02C43 "02C43 "02C13 % GLAGOLITIC SMALL LETTER RITSI
+\setXTXcharcodes "02C44 "02C44 "02C14 % GLAGOLITIC SMALL LETTER SLOVO
+\setXTXcharcodes "02C45 "02C45 "02C15 % GLAGOLITIC SMALL LETTER TVRIDO
+\setXTXcharcodes "02C46 "02C46 "02C16 % GLAGOLITIC SMALL LETTER UKU
+\setXTXcharcodes "02C47 "02C47 "02C17 % GLAGOLITIC SMALL LETTER FRITU
+\setXTXcharcodes "02C48 "02C48 "02C18 % GLAGOLITIC SMALL LETTER HERU
+\setXTXcharcodes "02C49 "02C49 "02C19 % GLAGOLITIC SMALL LETTER OTU
+\setXTXcharcodes "02C4A "02C4A "02C1A % GLAGOLITIC SMALL LETTER PE
+\setXTXcharcodes "02C4B "02C4B "02C1B % GLAGOLITIC SMALL LETTER SHTA
+\setXTXcharcodes "02C4C "02C4C "02C1C % GLAGOLITIC SMALL LETTER TSI
+\setXTXcharcodes "02C4D "02C4D "02C1D % GLAGOLITIC SMALL LETTER CHRIVI
+\setXTXcharcodes "02C4E "02C4E "02C1E % GLAGOLITIC SMALL LETTER SHA
+\setXTXcharcodes "02C4F "02C4F "02C1F % GLAGOLITIC SMALL LETTER YERU
+\setXTXcharcodes "02C50 "02C50 "02C20 % GLAGOLITIC SMALL LETTER YERI
+\setXTXcharcodes "02C51 "02C51 "02C21 % GLAGOLITIC SMALL LETTER YATI
+\setXTXcharcodes "02C52 "02C52 "02C22 % GLAGOLITIC SMALL LETTER SPIDERY HA
+\setXTXcharcodes "02C53 "02C53 "02C23 % GLAGOLITIC SMALL LETTER YU
+\setXTXcharcodes "02C54 "02C54 "02C24 % GLAGOLITIC SMALL LETTER SMALL YUS
+\setXTXcharcodes "02C55 "02C55 "02C25 % GLAGOLITIC SMALL LETTER SMALL YUS WITH TAIL
+\setXTXcharcodes "02C56 "02C56 "02C26 % GLAGOLITIC SMALL LETTER YO
+\setXTXcharcodes "02C57 "02C57 "02C27 % GLAGOLITIC SMALL LETTER IOTATED SMALL YUS
+\setXTXcharcodes "02C58 "02C58 "02C28 % GLAGOLITIC SMALL LETTER BIG YUS
+\setXTXcharcodes "02C59 "02C59 "02C29 % GLAGOLITIC SMALL LETTER IOTATED BIG YUS
+\setXTXcharcodes "02C5A "02C5A "02C2A % GLAGOLITIC SMALL LETTER FITA
+\setXTXcharcodes "02C5B "02C5B "02C2B % GLAGOLITIC SMALL LETTER IZHITSA
+\setXTXcharcodes "02C5C "02C5C "02C2C % GLAGOLITIC SMALL LETTER SHTAPIC
+\setXTXcharcodes "02C5D "02C5D "02C2D % GLAGOLITIC SMALL LETTER TROKUTASTI A
+\setXTXcharcodes "02C5E "02C5E "02C2E % GLAGOLITIC SMALL LETTER LATINATE MYSLITE
+\setXTXcharcodes "02C60 "02C61 "02C60 % LATIN CAPITAL LETTER L WITH DOUBLE BAR
+\setXTXcharcodes "02C61 "02C61 "02C60 % LATIN SMALL LETTER L WITH DOUBLE BAR
+\setXTXcharcodes "02C62 "0026B "02C62 % LATIN CAPITAL LETTER L WITH MIDDLE TILDE
+\setXTXcharcodes "02C63 "01D7D "02C63 % LATIN CAPITAL LETTER P WITH STROKE
+\setXTXcharcodes "02C64 "0027D "02C64 % LATIN CAPITAL LETTER R WITH TAIL
+\setXTXcharcodes "02C65 "02C65 "0023A % LATIN SMALL LETTER A WITH STROKE
+\setXTXcharcodes "02C66 "02C66 "0023E % LATIN SMALL LETTER T WITH DIAGONAL STROKE
+\setXTXcharcodes "02C67 "02C68 "02C67 % LATIN CAPITAL LETTER H WITH DESCENDER
+\setXTXcharcodes "02C68 "02C68 "02C67 % LATIN SMALL LETTER H WITH DESCENDER
+\setXTXcharcodes "02C69 "02C6A "02C69 % LATIN CAPITAL LETTER K WITH DESCENDER
+\setXTXcharcodes "02C6A "02C6A "02C69 % LATIN SMALL LETTER K WITH DESCENDER
+\setXTXcharcodes "02C6B "02C6C "02C6B % LATIN CAPITAL LETTER Z WITH DESCENDER
+\setXTXcharcodes "02C6C "02C6C "02C6B % LATIN SMALL LETTER Z WITH DESCENDER
+\setXTXcharcodes "02C74 "02C74 "02C74 % LATIN SMALL LETTER V WITH CURL
+\setXTXcharcodes "02C75 "02C76 "02C75 % LATIN CAPITAL LETTER HALF H
+\setXTXcharcodes "02C76 "02C76 "02C75 % LATIN SMALL LETTER HALF H
+\setXTXcharcodes "02C77 "02C77 "02C77 % LATIN SMALL LETTER TAILLESS PHI
+\setXTXcharcodes "02C80 "02C81 "02C80 % COPTIC CAPITAL LETTER ALFA
+\setXTXcharcodes "02C81 "02C81 "02C80 % COPTIC SMALL LETTER ALFA
+\setXTXcharcodes "02C82 "02C83 "02C82 % COPTIC CAPITAL LETTER VIDA
+\setXTXcharcodes "02C83 "02C83 "02C82 % COPTIC SMALL LETTER VIDA
+\setXTXcharcodes "02C84 "02C85 "02C84 % COPTIC CAPITAL LETTER GAMMA
+\setXTXcharcodes "02C85 "02C85 "02C84 % COPTIC SMALL LETTER GAMMA
+\setXTXcharcodes "02C86 "02C87 "02C86 % COPTIC CAPITAL LETTER DALDA
+\setXTXcharcodes "02C87 "02C87 "02C86 % COPTIC SMALL LETTER DALDA
+\setXTXcharcodes "02C88 "02C89 "02C88 % COPTIC CAPITAL LETTER EIE
+\setXTXcharcodes "02C89 "02C89 "02C88 % COPTIC SMALL LETTER EIE
+\setXTXcharcodes "02C8A "02C8B "02C8A % COPTIC CAPITAL LETTER SOU
+\setXTXcharcodes "02C8B "02C8B "02C8A % COPTIC SMALL LETTER SOU
+\setXTXcharcodes "02C8C "02C8D "02C8C % COPTIC CAPITAL LETTER ZATA
+\setXTXcharcodes "02C8D "02C8D "02C8C % COPTIC SMALL LETTER ZATA
+\setXTXcharcodes "02C8E "02C8F "02C8E % COPTIC CAPITAL LETTER HATE
+\setXTXcharcodes "02C8F "02C8F "02C8E % COPTIC SMALL LETTER HATE
+\setXTXcharcodes "02C90 "02C91 "02C90 % COPTIC CAPITAL LETTER THETHE
+\setXTXcharcodes "02C91 "02C91 "02C90 % COPTIC SMALL LETTER THETHE
+\setXTXcharcodes "02C92 "02C93 "02C92 % COPTIC CAPITAL LETTER IAUDA
+\setXTXcharcodes "02C93 "02C93 "02C92 % COPTIC SMALL LETTER IAUDA
+\setXTXcharcodes "02C94 "02C95 "02C94 % COPTIC CAPITAL LETTER KAPA
+\setXTXcharcodes "02C95 "02C95 "02C94 % COPTIC SMALL LETTER KAPA
+\setXTXcharcodes "02C96 "02C97 "02C96 % COPTIC CAPITAL LETTER LAULA
+\setXTXcharcodes "02C97 "02C97 "02C96 % COPTIC SMALL LETTER LAULA
+\setXTXcharcodes "02C98 "02C99 "02C98 % COPTIC CAPITAL LETTER MI
+\setXTXcharcodes "02C99 "02C99 "02C98 % COPTIC SMALL LETTER MI
+\setXTXcharcodes "02C9A "02C9B "02C9A % COPTIC CAPITAL LETTER NI
+\setXTXcharcodes "02C9B "02C9B "02C9A % COPTIC SMALL LETTER NI
+\setXTXcharcodes "02C9C "02C9D "02C9C % COPTIC CAPITAL LETTER KSI
+\setXTXcharcodes "02C9D "02C9D "02C9C % COPTIC SMALL LETTER KSI
+\setXTXcharcodes "02C9E "02C9F "02C9E % COPTIC CAPITAL LETTER O
+\setXTXcharcodes "02C9F "02C9F "02C9E % COPTIC SMALL LETTER O
+\setXTXcharcodes "02CA0 "02CA1 "02CA0 % COPTIC CAPITAL LETTER PI
+\setXTXcharcodes "02CA1 "02CA1 "02CA0 % COPTIC SMALL LETTER PI
+\setXTXcharcodes "02CA2 "02CA3 "02CA2 % COPTIC CAPITAL LETTER RO
+\setXTXcharcodes "02CA3 "02CA3 "02CA2 % COPTIC SMALL LETTER RO
+\setXTXcharcodes "02CA4 "02CA5 "02CA4 % COPTIC CAPITAL LETTER SIMA
+\setXTXcharcodes "02CA5 "02CA5 "02CA4 % COPTIC SMALL LETTER SIMA
+\setXTXcharcodes "02CA6 "02CA7 "02CA6 % COPTIC CAPITAL LETTER TAU
+\setXTXcharcodes "02CA7 "02CA7 "02CA6 % COPTIC SMALL LETTER TAU
+\setXTXcharcodes "02CA8 "02CA9 "02CA8 % COPTIC CAPITAL LETTER UA
+\setXTXcharcodes "02CA9 "02CA9 "02CA8 % COPTIC SMALL LETTER UA
+\setXTXcharcodes "02CAA "02CAB "02CAA % COPTIC CAPITAL LETTER FI
+\setXTXcharcodes "02CAB "02CAB "02CAA % COPTIC SMALL LETTER FI
+\setXTXcharcodes "02CAC "02CAD "02CAC % COPTIC CAPITAL LETTER KHI
+\setXTXcharcodes "02CAD "02CAD "02CAC % COPTIC SMALL LETTER KHI
+\setXTXcharcodes "02CAE "02CAF "02CAE % COPTIC CAPITAL LETTER PSI
+\setXTXcharcodes "02CAF "02CAF "02CAE % COPTIC SMALL LETTER PSI
+\setXTXcharcodes "02CB0 "02CB1 "02CB0 % COPTIC CAPITAL LETTER OOU
+\setXTXcharcodes "02CB1 "02CB1 "02CB0 % COPTIC SMALL LETTER OOU
+\setXTXcharcodes "02CB2 "02CB3 "02CB2 % COPTIC CAPITAL LETTER DIALECT-P ALEF
+\setXTXcharcodes "02CB3 "02CB3 "02CB2 % COPTIC SMALL LETTER DIALECT-P ALEF
+\setXTXcharcodes "02CB4 "02CB5 "02CB4 % COPTIC CAPITAL LETTER OLD COPTIC AIN
+\setXTXcharcodes "02CB5 "02CB5 "02CB4 % COPTIC SMALL LETTER OLD COPTIC AIN
+\setXTXcharcodes "02CB6 "02CB7 "02CB6 % COPTIC CAPITAL LETTER CRYPTOGRAMMIC EIE
+\setXTXcharcodes "02CB7 "02CB7 "02CB6 % COPTIC SMALL LETTER CRYPTOGRAMMIC EIE
+\setXTXcharcodes "02CB8 "02CB9 "02CB8 % COPTIC CAPITAL LETTER DIALECT-P KAPA
+\setXTXcharcodes "02CB9 "02CB9 "02CB8 % COPTIC SMALL LETTER DIALECT-P KAPA
+\setXTXcharcodes "02CBA "02CBB "02CBA % COPTIC CAPITAL LETTER DIALECT-P NI
+\setXTXcharcodes "02CBB "02CBB "02CBA % COPTIC SMALL LETTER DIALECT-P NI
+\setXTXcharcodes "02CBC "02CBD "02CBC % COPTIC CAPITAL LETTER CRYPTOGRAMMIC NI
+\setXTXcharcodes "02CBD "02CBD "02CBC % COPTIC SMALL LETTER CRYPTOGRAMMIC NI
+\setXTXcharcodes "02CBE "02CBF "02CBE % COPTIC CAPITAL LETTER OLD COPTIC OOU
+\setXTXcharcodes "02CBF "02CBF "02CBE % COPTIC SMALL LETTER OLD COPTIC OOU
+\setXTXcharcodes "02CC0 "02CC1 "02CC0 % COPTIC CAPITAL LETTER SAMPI
+\setXTXcharcodes "02CC1 "02CC1 "02CC0 % COPTIC SMALL LETTER SAMPI
+\setXTXcharcodes "02CC2 "02CC3 "02CC2 % COPTIC CAPITAL LETTER CROSSED SHEI
+\setXTXcharcodes "02CC3 "02CC3 "02CC2 % COPTIC SMALL LETTER CROSSED SHEI
+\setXTXcharcodes "02CC4 "02CC5 "02CC4 % COPTIC CAPITAL LETTER OLD COPTIC SHEI
+\setXTXcharcodes "02CC5 "02CC5 "02CC4 % COPTIC SMALL LETTER OLD COPTIC SHEI
+\setXTXcharcodes "02CC6 "02CC7 "02CC6 % COPTIC CAPITAL LETTER OLD COPTIC ESH
+\setXTXcharcodes "02CC7 "02CC7 "02CC6 % COPTIC SMALL LETTER OLD COPTIC ESH
+\setXTXcharcodes "02CC8 "02CC9 "02CC8 % COPTIC CAPITAL LETTER AKHMIMIC KHEI
+\setXTXcharcodes "02CC9 "02CC9 "02CC8 % COPTIC SMALL LETTER AKHMIMIC KHEI
+\setXTXcharcodes "02CCA "02CCB "02CCA % COPTIC CAPITAL LETTER DIALECT-P HORI
+\setXTXcharcodes "02CCB "02CCB "02CCA % COPTIC SMALL LETTER DIALECT-P HORI
+\setXTXcharcodes "02CCC "02CCD "02CCC % COPTIC CAPITAL LETTER OLD COPTIC HORI
+\setXTXcharcodes "02CCD "02CCD "02CCC % COPTIC SMALL LETTER OLD COPTIC HORI
+\setXTXcharcodes "02CCE "02CCF "02CCE % COPTIC CAPITAL LETTER OLD COPTIC HA
+\setXTXcharcodes "02CCF "02CCF "02CCE % COPTIC SMALL LETTER OLD COPTIC HA
+\setXTXcharcodes "02CD0 "02CD1 "02CD0 % COPTIC CAPITAL LETTER L-SHAPED HA
+\setXTXcharcodes "02CD1 "02CD1 "02CD0 % COPTIC SMALL LETTER L-SHAPED HA
+\setXTXcharcodes "02CD2 "02CD3 "02CD2 % COPTIC CAPITAL LETTER OLD COPTIC HEI
+\setXTXcharcodes "02CD3 "02CD3 "02CD2 % COPTIC SMALL LETTER OLD COPTIC HEI
+\setXTXcharcodes "02CD4 "02CD5 "02CD4 % COPTIC CAPITAL LETTER OLD COPTIC HAT
+\setXTXcharcodes "02CD5 "02CD5 "02CD4 % COPTIC SMALL LETTER OLD COPTIC HAT
+\setXTXcharcodes "02CD6 "02CD7 "02CD6 % COPTIC CAPITAL LETTER OLD COPTIC GANGIA
+\setXTXcharcodes "02CD7 "02CD7 "02CD6 % COPTIC SMALL LETTER OLD COPTIC GANGIA
+\setXTXcharcodes "02CD8 "02CD9 "02CD8 % COPTIC CAPITAL LETTER OLD COPTIC DJA
+\setXTXcharcodes "02CD9 "02CD9 "02CD8 % COPTIC SMALL LETTER OLD COPTIC DJA
+\setXTXcharcodes "02CDA "02CDB "02CDA % COPTIC CAPITAL LETTER OLD COPTIC SHIMA
+\setXTXcharcodes "02CDB "02CDB "02CDA % COPTIC SMALL LETTER OLD COPTIC SHIMA
+\setXTXcharcodes "02CDC "02CDD "02CDC % COPTIC CAPITAL LETTER OLD NUBIAN SHIMA
+\setXTXcharcodes "02CDD "02CDD "02CDC % COPTIC SMALL LETTER OLD NUBIAN SHIMA
+\setXTXcharcodes "02CDE "02CDF "02CDE % COPTIC CAPITAL LETTER OLD NUBIAN NGI
+\setXTXcharcodes "02CDF "02CDF "02CDE % COPTIC SMALL LETTER OLD NUBIAN NGI
+\setXTXcharcodes "02CE0 "02CE1 "02CE0 % COPTIC CAPITAL LETTER OLD NUBIAN NYI
+\setXTXcharcodes "02CE1 "02CE1 "02CE0 % COPTIC SMALL LETTER OLD NUBIAN NYI
+\setXTXcharcodes "02CE2 "02CE3 "02CE2 % COPTIC CAPITAL LETTER OLD NUBIAN WAU
+\setXTXcharcodes "02CE3 "02CE3 "02CE2 % COPTIC SMALL LETTER OLD NUBIAN WAU
+\setXTXcharcodes "02CE4 "02CE4 "02CE4 % COPTIC SYMBOL KAI
+\setXTXcharcodes "02D00 "02D00 "010A0 % GEORGIAN SMALL LETTER AN
+\setXTXcharcodes "02D01 "02D01 "010A1 % GEORGIAN SMALL LETTER BAN
+\setXTXcharcodes "02D02 "02D02 "010A2 % GEORGIAN SMALL LETTER GAN
+\setXTXcharcodes "02D03 "02D03 "010A3 % GEORGIAN SMALL LETTER DON
+\setXTXcharcodes "02D04 "02D04 "010A4 % GEORGIAN SMALL LETTER EN
+\setXTXcharcodes "02D05 "02D05 "010A5 % GEORGIAN SMALL LETTER VIN
+\setXTXcharcodes "02D06 "02D06 "010A6 % GEORGIAN SMALL LETTER ZEN
+\setXTXcharcodes "02D07 "02D07 "010A7 % GEORGIAN SMALL LETTER TAN
+\setXTXcharcodes "02D08 "02D08 "010A8 % GEORGIAN SMALL LETTER IN
+\setXTXcharcodes "02D09 "02D09 "010A9 % GEORGIAN SMALL LETTER KAN
+\setXTXcharcodes "02D0A "02D0A "010AA % GEORGIAN SMALL LETTER LAS
+\setXTXcharcodes "02D0B "02D0B "010AB % GEORGIAN SMALL LETTER MAN
+\setXTXcharcodes "02D0C "02D0C "010AC % GEORGIAN SMALL LETTER NAR
+\setXTXcharcodes "02D0D "02D0D "010AD % GEORGIAN SMALL LETTER ON
+\setXTXcharcodes "02D0E "02D0E "010AE % GEORGIAN SMALL LETTER PAR
+\setXTXcharcodes "02D0F "02D0F "010AF % GEORGIAN SMALL LETTER ZHAR
+\setXTXcharcodes "02D10 "02D10 "010B0 % GEORGIAN SMALL LETTER RAE
+\setXTXcharcodes "02D11 "02D11 "010B1 % GEORGIAN SMALL LETTER SAN
+\setXTXcharcodes "02D12 "02D12 "010B2 % GEORGIAN SMALL LETTER TAR
+\setXTXcharcodes "02D13 "02D13 "010B3 % GEORGIAN SMALL LETTER UN
+\setXTXcharcodes "02D14 "02D14 "010B4 % GEORGIAN SMALL LETTER PHAR
+\setXTXcharcodes "02D15 "02D15 "010B5 % GEORGIAN SMALL LETTER KHAR
+\setXTXcharcodes "02D16 "02D16 "010B6 % GEORGIAN SMALL LETTER GHAN
+\setXTXcharcodes "02D17 "02D17 "010B7 % GEORGIAN SMALL LETTER QAR
+\setXTXcharcodes "02D18 "02D18 "010B8 % GEORGIAN SMALL LETTER SHIN
+\setXTXcharcodes "02D19 "02D19 "010B9 % GEORGIAN SMALL LETTER CHIN
+\setXTXcharcodes "02D1A "02D1A "010BA % GEORGIAN SMALL LETTER CAN
+\setXTXcharcodes "02D1B "02D1B "010BB % GEORGIAN SMALL LETTER JIL
+\setXTXcharcodes "02D1C "02D1C "010BC % GEORGIAN SMALL LETTER CIL
+\setXTXcharcodes "02D1D "02D1D "010BD % GEORGIAN SMALL LETTER CHAR
+\setXTXcharcodes "02D1E "02D1E "010BE % GEORGIAN SMALL LETTER XAN
+\setXTXcharcodes "02D1F "02D1F "010BF % GEORGIAN SMALL LETTER JHAN
+\setXTXcharcodes "02D20 "02D20 "010C0 % GEORGIAN SMALL LETTER HAE
+\setXTXcharcodes "02D21 "02D21 "010C1 % GEORGIAN SMALL LETTER HE
+\setXTXcharcodes "02D22 "02D22 "010C2 % GEORGIAN SMALL LETTER HIE
+\setXTXcharcodes "02D23 "02D23 "010C3 % GEORGIAN SMALL LETTER WE
+\setXTXcharcodes "02D24 "02D24 "010C4 % GEORGIAN SMALL LETTER HAR
+\setXTXcharcodes "02D25 "02D25 "010C5 % GEORGIAN SMALL LETTER HOE
+\setXTXcharcodes "0FB00 "0FB00 "0FB00 % LATIN SMALL LIGATURE FF
+\setXTXcharcodes "0FB01 "0FB01 "0FB01 % LATIN SMALL LIGATURE FI
+\setXTXcharcodes "0FB02 "0FB02 "0FB02 % LATIN SMALL LIGATURE FL
+\setXTXcharcodes "0FB03 "0FB03 "0FB03 % LATIN SMALL LIGATURE FFI
+\setXTXcharcodes "0FB04 "0FB04 "0FB04 % LATIN SMALL LIGATURE FFL
+\setXTXcharcodes "0FB05 "0FB05 "0FB05 % LATIN SMALL LIGATURE LONG S T
+\setXTXcharcodes "0FB06 "0FB06 "0FB06 % LATIN SMALL LIGATURE ST
+\setXTXcharcodes "0FB13 "0FB13 "0FB13 % ARMENIAN SMALL LIGATURE MEN NOW
+\setXTXcharcodes "0FB14 "0FB14 "0FB14 % ARMENIAN SMALL LIGATURE MEN ECH
+\setXTXcharcodes "0FB15 "0FB15 "0FB15 % ARMENIAN SMALL LIGATURE MEN INI
+\setXTXcharcodes "0FB16 "0FB16 "0FB16 % ARMENIAN SMALL LIGATURE VEW NOW
+\setXTXcharcodes "0FB17 "0FB17 "0FB17 % ARMENIAN SMALL LIGATURE MEN XEH
+\setXTXcharcodes "0FF21 "0FF41 "0FF21 % FULLWIDTH LATIN CAPITAL LETTER A
+\setXTXcharcodes "0FF22 "0FF42 "0FF22 % FULLWIDTH LATIN CAPITAL LETTER B
+\setXTXcharcodes "0FF23 "0FF43 "0FF23 % FULLWIDTH LATIN CAPITAL LETTER C
+\setXTXcharcodes "0FF24 "0FF44 "0FF24 % FULLWIDTH LATIN CAPITAL LETTER D
+\setXTXcharcodes "0FF25 "0FF45 "0FF25 % FULLWIDTH LATIN CAPITAL LETTER E
+\setXTXcharcodes "0FF26 "0FF46 "0FF26 % FULLWIDTH LATIN CAPITAL LETTER F
+\setXTXcharcodes "0FF27 "0FF47 "0FF27 % FULLWIDTH LATIN CAPITAL LETTER G
+\setXTXcharcodes "0FF28 "0FF48 "0FF28 % FULLWIDTH LATIN CAPITAL LETTER H
+\setXTXcharcodes "0FF29 "0FF49 "0FF29 % FULLWIDTH LATIN CAPITAL LETTER I
+\setXTXcharcodes "0FF2A "0FF4A "0FF2A % FULLWIDTH LATIN CAPITAL LETTER J
+\setXTXcharcodes "0FF2B "0FF4B "0FF2B % FULLWIDTH LATIN CAPITAL LETTER K
+\setXTXcharcodes "0FF2C "0FF4C "0FF2C % FULLWIDTH LATIN CAPITAL LETTER L
+\setXTXcharcodes "0FF2D "0FF4D "0FF2D % FULLWIDTH LATIN CAPITAL LETTER M
+\setXTXcharcodes "0FF2E "0FF4E "0FF2E % FULLWIDTH LATIN CAPITAL LETTER N
+\setXTXcharcodes "0FF2F "0FF4F "0FF2F % FULLWIDTH LATIN CAPITAL LETTER O
+\setXTXcharcodes "0FF30 "0FF50 "0FF30 % FULLWIDTH LATIN CAPITAL LETTER P
+\setXTXcharcodes "0FF31 "0FF51 "0FF31 % FULLWIDTH LATIN CAPITAL LETTER Q
+\setXTXcharcodes "0FF32 "0FF52 "0FF32 % FULLWIDTH LATIN CAPITAL LETTER R
+\setXTXcharcodes "0FF33 "0FF53 "0FF33 % FULLWIDTH LATIN CAPITAL LETTER S
+\setXTXcharcodes "0FF34 "0FF54 "0FF34 % FULLWIDTH LATIN CAPITAL LETTER T
+\setXTXcharcodes "0FF35 "0FF55 "0FF35 % FULLWIDTH LATIN CAPITAL LETTER U
+\setXTXcharcodes "0FF36 "0FF56 "0FF36 % FULLWIDTH LATIN CAPITAL LETTER V
+\setXTXcharcodes "0FF37 "0FF57 "0FF37 % FULLWIDTH LATIN CAPITAL LETTER W
+\setXTXcharcodes "0FF38 "0FF58 "0FF38 % FULLWIDTH LATIN CAPITAL LETTER X
+\setXTXcharcodes "0FF39 "0FF59 "0FF39 % FULLWIDTH LATIN CAPITAL LETTER Y
+\setXTXcharcodes "0FF3A "0FF5A "0FF3A % FULLWIDTH LATIN CAPITAL LETTER Z
+\setXTXcharcodes "0FF41 "0FF41 "0FF21 % FULLWIDTH LATIN SMALL LETTER A
+\setXTXcharcodes "0FF42 "0FF42 "0FF22 % FULLWIDTH LATIN SMALL LETTER B
+\setXTXcharcodes "0FF43 "0FF43 "0FF23 % FULLWIDTH LATIN SMALL LETTER C
+\setXTXcharcodes "0FF44 "0FF44 "0FF24 % FULLWIDTH LATIN SMALL LETTER D
+\setXTXcharcodes "0FF45 "0FF45 "0FF25 % FULLWIDTH LATIN SMALL LETTER E
+\setXTXcharcodes "0FF46 "0FF46 "0FF26 % FULLWIDTH LATIN SMALL LETTER F
+\setXTXcharcodes "0FF47 "0FF47 "0FF27 % FULLWIDTH LATIN SMALL LETTER G
+\setXTXcharcodes "0FF48 "0FF48 "0FF28 % FULLWIDTH LATIN SMALL LETTER H
+\setXTXcharcodes "0FF49 "0FF49 "0FF29 % FULLWIDTH LATIN SMALL LETTER I
+\setXTXcharcodes "0FF4A "0FF4A "0FF2A % FULLWIDTH LATIN SMALL LETTER J
+\setXTXcharcodes "0FF4B "0FF4B "0FF2B % FULLWIDTH LATIN SMALL LETTER K
+\setXTXcharcodes "0FF4C "0FF4C "0FF2C % FULLWIDTH LATIN SMALL LETTER L
+\setXTXcharcodes "0FF4D "0FF4D "0FF2D % FULLWIDTH LATIN SMALL LETTER M
+\setXTXcharcodes "0FF4E "0FF4E "0FF2E % FULLWIDTH LATIN SMALL LETTER N
+\setXTXcharcodes "0FF4F "0FF4F "0FF2F % FULLWIDTH LATIN SMALL LETTER O
+\setXTXcharcodes "0FF50 "0FF50 "0FF30 % FULLWIDTH LATIN SMALL LETTER P
+\setXTXcharcodes "0FF51 "0FF51 "0FF31 % FULLWIDTH LATIN SMALL LETTER Q
+\setXTXcharcodes "0FF52 "0FF52 "0FF32 % FULLWIDTH LATIN SMALL LETTER R
+\setXTXcharcodes "0FF53 "0FF53 "0FF33 % FULLWIDTH LATIN SMALL LETTER S
+\setXTXcharcodes "0FF54 "0FF54 "0FF34 % FULLWIDTH LATIN SMALL LETTER T
+\setXTXcharcodes "0FF55 "0FF55 "0FF35 % FULLWIDTH LATIN SMALL LETTER U
+\setXTXcharcodes "0FF56 "0FF56 "0FF36 % FULLWIDTH LATIN SMALL LETTER V
+\setXTXcharcodes "0FF57 "0FF57 "0FF37 % FULLWIDTH LATIN SMALL LETTER W
+\setXTXcharcodes "0FF58 "0FF58 "0FF38 % FULLWIDTH LATIN SMALL LETTER X
+\setXTXcharcodes "0FF59 "0FF59 "0FF39 % FULLWIDTH LATIN SMALL LETTER Y
+\setXTXcharcodes "0FF5A "0FF5A "0FF3A % FULLWIDTH LATIN SMALL LETTER Z
+
+\dofastrecurse{"03400}{"04DB5}{1}{\dosetXTXcharcodes\recurselevel\recurselevel\recurselevel}
+\dofastrecurse{"04E00}{"09FBB}{1}{\dosetXTXcharcodes\recurselevel\recurselevel\recurselevel}
+\dofastrecurse{"0AC00}{"0D7A3}{1}{\dosetXTXcharcodes\recurselevel\recurselevel\recurselevel}
+\dofastrecurse{"20000}{"2A6D6}{1}{\dosetXTXcharcodes\recurselevel\recurselevel\recurselevel}
+
+% patch needed for turkish
+
+\setXTXcharcodes "201C "201C "201C
+\setXTXcharcodes "201D "201D "201D
+
+\endinput
diff --git a/tex/context/base/xtag-cml.tex b/tex/context/base/xtag-cml.tex
index 203218ceb..6da7fd26f 100644
--- a/tex/context/base/xtag-cml.tex
+++ b/tex/context/base/xtag-cml.tex
@@ -2,6 +2,8 @@
% will be rewritten avoiding the mapper
+\useXMLfilter[map]
+
\unprotect
\def\setupCMLappearance[#1]{\dodoubleargument\getparameters[@@CML#1]}
diff --git a/tex/context/base/xtag-ent.tex b/tex/context/base/xtag-ent.tex
index a34fbab28..f4c3e4b06 100644
--- a/tex/context/base/xtag-ent.tex
+++ b/tex/context/base/xtag-ent.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-ent,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=A bunch of Entities,
%D author=Hans Hagen,
%D date=\currentdate,
diff --git a/tex/context/base/xtag-exp.tex b/tex/context/base/xtag-exp.tex
index af49782d9..72e956199 100644
--- a/tex/context/base/xtag-exp.tex
+++ b/tex/context/base/xtag-exp.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-exp,
%D version=2001.08.20,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=Expansion Related Things,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Expansion,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (expansion)}
+\writestatus{loading}{ConTeXt XML Macros / Expansion}
\unprotect
diff --git a/tex/context/base/xtag-ext.tex b/tex/context/base/xtag-ext.tex
index a0f43ff4e..1a9e3e058 100644
--- a/tex/context/base/xtag-ext.tex
+++ b/tex/context/base/xtag-ext.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-ext,
%D version=2001.03.21,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Extra Macros,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (extras)}
+\writestatus{loading}{ConTeXt XML Macros / Extras}
\unprotect
diff --git a/tex/context/base/xtag-hyp.tex b/tex/context/base/xtag-hyp.tex
index 821705f7b..573b546c7 100644
--- a/tex/context/base/xtag-hyp.tex
+++ b/tex/context/base/xtag-hyp.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-hyp,
%D version=2003.11.24,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=hyphenation support,
+%D title=\CONTEXT\ XML MAcros,
+%D subtitle=Hyphenation,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (hyphenation)}
+\writestatus{loading}{ConTeXt XML Macros / Hyphenation}
%D This filter is kind of obsolete, since \UTF\ is not
%D limited to \XML. So, here we only enable \UTF\ support.
diff --git a/tex/context/base/xtag-ini.mkii b/tex/context/base/xtag-ini.mkii
deleted file mode 100644
index 994ff6d9e..000000000
--- a/tex/context/base/xtag-ini.mkii
+++ /dev/null
@@ -1,6 +0,0 @@
-\def\mksetXMLtokensreduction % mkii
- {\ifcase\XMLtokensreduction
- \setcatcodetable\xmlcatcodese \or
- \setcatcodetable\xmlcatcodesr \else
- \setcatcodetable\xmlcatcodesn
- \fi}
diff --git a/tex/context/base/xtag-ini.mkiv b/tex/context/base/xtag-ini.mkiv
deleted file mode 100644
index 974f0439b..000000000
--- a/tex/context/base/xtag-ini.mkiv
+++ /dev/null
@@ -1,2 +0,0 @@
-\def\mksetXMLtokensreduction % mkiv
- {\setcatcodetable\xmlcatcodesn}
diff --git a/tex/context/base/xtag-ini.tex b/tex/context/base/xtag-ini.tex
index ca1fa9a05..495f4ea07 100644
--- a/tex/context/base/xtag-ini.tex
+++ b/tex/context/base/xtag-ini.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-ini,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Initialization,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (initialization)}
+\writestatus{loading}{ConTeXt XML Macros / Initialization}
%D Beware: don't rely on \longempty things, since this may
%D change!
@@ -35,8 +35,6 @@
% csnames
% XMLelse -> elseXML
-\loadmarkfile{xtag-ini}
-
%D Remark: some hard coded character things will be replaced
%D by named glyphs as soon as the upgraded encoding modules
%D are released. At that moment, unicode support will be
@@ -417,6 +415,22 @@
% we speed things up by explicitly setting the active char's < &
+\doifmodeelse {mkiv} {
+
+ \def\mksetXMLtokensreduction % mkiv
+ {\setcatcodetable\xmlcatcodesn}
+
+} {
+
+ \def\mksetXMLtokensreduction % mkii
+ {\ifcase\XMLtokensreduction
+ \setcatcodetable\xmlcatcodese \or
+ \setcatcodetable\xmlcatcodesr \else
+ \setcatcodetable\xmlcatcodesn
+ \fi}
+
+}
+
\bgroup \catcode`\<=13 \catcode`\&=13
\gdef\enableXML
@@ -1427,7 +1441,7 @@
%\unexpanded\def\getXMLentity#1%
% {\csname\@@XMLentity:#1\endcsname}
-\newif\ifautoXMLentities % fall back on context commands
+\doifundefined{autoXMLentitiestrue}{\expandafter\newif\csname ifautoXMLentities\endcsname} % fall back on context commands
\def\expandedXMLentity#1%
{\ifcsname\@@XMLentity:#1\endcsname \@EA \execXMLentity
diff --git a/tex/context/base/xtag-map.tex b/tex/context/base/xtag-map.tex
index af6ca6112..f8471d6a7 100644
--- a/tex/context/base/xtag-map.tex
+++ b/tex/context/base/xtag-map.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-map,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Remapping,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -16,7 +16,7 @@
%D We also need something that lets content as-is, like for
%D instance XML embedded in a chemical caption.
-\writestatus{loading}{Context XML Macros (remapping)}
+\writestatus{loading}{ConTeXt XML Macros / Remapping}
%D A fundamental characteristic of \TEX\ is that much
%D processing depends on picking up one or more arguments and
diff --git a/tex/context/base/xtag-mmc.tex b/tex/context/base/xtag-mmc.tex
index d4ee14c59..27e2c42ea 100644
--- a/tex/context/base/xtag-mmc.tex
+++ b/tex/context/base/xtag-mmc.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-mmc,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=Math ML,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Content MathML,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (content math ml)}
+\writestatus{loading}{ConTeXt XML Macros / Content MathML}
% this is the first, experimental, shabby implementation, as
% always, the third will do -)
@@ -113,7 +113,7 @@ complex-cartesian=>\let\next\MMLccartesian,
{{\bbd#1}}
\def\widevec#1%
- {\vbox{\m@th\ialign{##\crcr
+ {\vbox{\mathsurround\zeropoint\ialign{##\crcr
\rightarrowfill\crcr\noalign{\nointerlineskip}%
$\hfil\displaystyle{#1}\hfil$\crcr}}}
diff --git a/tex/context/base/xtag-mml.tex b/tex/context/base/xtag-mml.tex
index e627e05b0..051d15b00 100644
--- a/tex/context/base/xtag-mml.tex
+++ b/tex/context/base/xtag-mml.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-mml,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=Math ML,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=MathML,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,11 +11,13 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (math ml)}
+\writestatus{loading}{ConTeXt XML Macros / MathML}
% I will reimplement this one without mapping since we now have more
% tricks available
+\useXMLfilter[map]
+
%\enablemathpunctuation
% First some general formula element definitions.
diff --git a/tex/context/base/xtag-mmp.tex b/tex/context/base/xtag-mmp.tex
index 01328cd40..ef1479ee6 100644
--- a/tex/context/base/xtag-mmp.tex
+++ b/tex/context/base/xtag-mmp.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-mmp,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=Math ML,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Presentation MathML,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% \points should become \bodyfontsize
+
% under reconstruction
%
% \starttext
@@ -31,18 +33,18 @@
% \def\doMMLpUNDER
% {\doifelse{\XMLpar{munder}{accent}{}}{true}
% {\secondXMLRelement\firstXMLRelement}
-% {\mathop{\vtop{\m@th\ialign{\hss##\hss\crcr
+% {\mathop{\vtop{\mathsurround\zeropoint\ialign{\hss##\hss\crcr
% \disabledelimiter\doMMLfiller\firstXMLRelement
-% \crcr\noalign{\kern3\p@\nointerlineskip}%
+% \crcr\noalign{\kern3\points\nointerlineskip}%
% \disabledelimiter\doMMLfiller\secondXMLRelement
-% \crcr\noalign{\kern3\p@}}}}\limits}}
+% \crcr\noalign{\kern3\points}}}}\limits}}
%
% \def\doMMLpOVER
% {\doifelse{\XMLpar{mover}{accent}{}}{true}
% {\secondXMLRelement\firstXMLRelement}
-% {\mathop{\vbox{\m@th\ialign{\hss##\hss\crcr\noalign{\kern3\p@}%
+% {\mathop{\vbox{\mathsurround\zeropoint\ialign{\hss##\hss\crcr\noalign{\kern3\points}%
% \disabledelimiter\doMMLfiller\secondXMLRelement
-% \crcr\noalign{\kern3\p@\nointerlineskip}%
+% \crcr\noalign{\kern3\points\nointerlineskip}%
% \disabledelimiter\doMMLfiller\firstXMLRelement
% \crcr}}}\limits}}
%
@@ -53,7 +55,7 @@
%
% \stoptext
-\writestatus{loading}{Context XML Macros (presentational math ml)}
+\writestatus{loading}{ConTeXt XML Macros / Presentational MathML}
\unprotect
@@ -90,9 +92,6 @@
\remapXMLsequence [mfenced] [CPA] \MMLpFENCED
-\let\normalright=\right
-\let\normalleft =\left
-
\def\doMMLleft #1{\pushmacro\left \let\left \empty\normalleft #1\popmacro\left}
\def\doMMLright#1{\pushmacro\right\let\right\empty\normalright#1\popmacro\right}
@@ -304,16 +303,16 @@
\dodoMMLfiller}
\def\doMMLpUNDER
- {\mathop{\vtop{\m@th\ialign{\hss##\hss\crcr
+ {\mathop{\vtop{\mathsurround\zeropoint\ialign{\hss##\hss\crcr
\disabledelimiter\doMMLfiller\firstXMLRelement
- \crcr\noalign{\kern3\p@\nointerlineskip}%
+ \crcr\noalign{\kern3\points\nointerlineskip}%
\disabledelimiter\doMMLfiller\secondXMLRelement
- \crcr\noalign{\kern3\p@}}}}\limits}
+ \crcr\noalign{\kern3\points}}}}\limits}
\def\doMMLpOVER
- {\mathop{\vbox{\m@th\ialign{\hss##\hss\crcr\noalign{\kern3\p@}%
+ {\mathop{\vbox{\mathsurround\zeropoint\ialign{\hss##\hss\crcr\noalign{\kern3\points}%
\disabledelimiter\doMMLfiller\secondXMLRelement
- \crcr\noalign{\kern3\p@\nointerlineskip}%
+ \crcr\noalign{\kern3\points\nointerlineskip}%
\disabledelimiter\doMMLfiller\firstXMLRelement
\crcr}}}\limits}
diff --git a/tex/context/base/xtag-pml.tex b/tex/context/base/xtag-pml.tex
index b11d3d68d..53d22c52a 100644
--- a/tex/context/base/xtag-pml.tex
+++ b/tex/context/base/xtag-pml.tex
@@ -11,11 +11,12 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (phys ml)}
+\writestatus{loading}{ConTeXt XML Macros / PhysML}
%D This is a reimplmentation of the old filter. This module
%D runs on top of the mathml and units modules.
+\useXMLfilter[map]
\useXMLfilter[mml,mmp,mmc]
\defineXMLargument [phys] \doXMLphys
diff --git a/tex/context/base/xtag-pmu.tex b/tex/context/base/xtag-pmu.tex
index 0b9509f13..b913475f5 100644
--- a/tex/context/base/xtag-pmu.tex
+++ b/tex/context/base/xtag-pmu.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-pmu,
%D version=2001.06.10,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Units,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (units)}
+\writestatus{loading}{ConTeXt XML Macros / Units}
%D Quick and dirty in||line units:
%D
diff --git a/tex/context/base/xtag-pre.tex b/tex/context/base/xtag-pre.tex
index 173e7d298..3f1d4dca0 100644
--- a/tex/context/base/xtag-pre.tex
+++ b/tex/context/base/xtag-pre.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-pre,
%D version=2000.12.20,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Predefined Things,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (predefined)}
+\writestatus{loading}{ConTeXt XML Macros / Predefined}
%D Here we predefine some escapes, processing instructions,
%D entities and other handy things.
diff --git a/tex/context/base/xtag-prs.tex b/tex/context/base/xtag-prs.tex
index b3eb681fc..02bdcf21c 100644
--- a/tex/context/base/xtag-prs.tex
+++ b/tex/context/base/xtag-prs.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-prs,
%D version=2004.08.18,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Parsing,
%D author=Hans Hagen,
%D date=\currentdate,
diff --git a/tex/context/base/xtag-raw.tex b/tex/context/base/xtag-raw.tex
index 8c190d943..e6dfdea41 100644
--- a/tex/context/base/xtag-raw.tex
+++ b/tex/context/base/xtag-raw.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-raw,
%D version=2002.03.21,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=reducing specials,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Raw Specials,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (raw specials)}
+\writestatus{loading}{ConTeXt XML Macros / Raw Specials}
%D Some day this module will be obsolete.
diff --git a/tex/context/base/xtag-rng.tex b/tex/context/base/xtag-rng.tex
index 524bba2d1..254282424 100644
--- a/tex/context/base/xtag-rng.tex
+++ b/tex/context/base/xtag-rng.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-rng,
%D version=2002.10.29,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=Relax NG,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=Relax NG,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,18 +11,18 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\unprotect
+\unprotect
%D The following commands picks up a named block from the
-%D given file and pretty prints it.
+%D given file and pretty prints it.
%D
-%D \starttyping
+%D \starttyping
%D \showRNGcomponent [eximple.rng] [request]
%D \stoptyping
%D
%D If needed, you adapt the colors used by redefining the
-%D \type {xtag} color palet.
+%D \type {xtag} color palet.
\fetchruntimecommand\showRNGcomponent {\f!xtagprefix\s!run}
-\protect \endinput
+\protect \endinput
diff --git a/tex/context/base/xtag-run.tex b/tex/context/base/xtag-run.tex
index 8075bfbe4..9a4603731 100644
--- a/tex/context/base/xtag-run.tex
+++ b/tex/context/base/xtag-run.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-run,
%D version=2001.01.10,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Visualization,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -13,7 +13,7 @@
% TODO: make this mkiv compliant, catcode tables etc
-\writestatus{loading}{Context XML Macros (visualization)}
+\writestatus{loading}{ConTeXt XML Macros / Visualization}
\unprotect
diff --git a/tex/context/base/xtag-stk.tex b/tex/context/base/xtag-stk.tex
index b5fcb7e9d..e126ae5c7 100644
--- a/tex/context/base/xtag-stk.tex
+++ b/tex/context/base/xtag-stk.tex
@@ -1,7 +1,7 @@
%D \module
%D [ file=xtag-exp,
%D version=2006.01.19,
-%D title=\CONTEXT\ XML Support,
+%D title=\CONTEXT\ XML Macros,
%D subtitle=Stacking Data,
%D author=Hans Hagen,
%D date=\currentdate,
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (stacks)}
+\writestatus{loading}{ConTeXt XML Macros / Stacks}
%D This module is experimental. Don't use it (yet). It needs a
%D clean-up. The stack handler is used in the third MathML renderer.
diff --git a/tex/context/base/xtag-utf.tex b/tex/context/base/xtag-utf.tex
index b978c3339..fec84d279 100644
--- a/tex/context/base/xtag-utf.tex
+++ b/tex/context/base/xtag-utf.tex
@@ -1,8 +1,8 @@
%D \module
%D [ file=xtag-utf,
%D version=2002.06.24,
-%D title=\CONTEXT\ XML Support,
-%D subtitle=UTF-8 support,
+%D title=\CONTEXT\ XML Macros,
+%D subtitle=UTF,
%D author=Hans Hagen,
%D date=\currentdate,
%D copyright={PRAGMA / Hans Hagen \& Ton Otten}]
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{Context XML Macros (UTF-8)}
+\writestatus{loading}{ConTeXt XML Macros / UTF}
%D This filter is kind of obsolete, since \UTF\ is not
%D limited to \XML. So, here we only enable \UTF\ support.
diff --git a/tex/context/bib/bibl-apa-fr.tex b/tex/context/bib/bibl-apa-fr.tex
index d2a1efb8a..654a36441 100644
--- a/tex/context/bib/bibl-apa-fr.tex
+++ b/tex/context/bib/bibl-apa-fr.tex
@@ -108,7 +108,7 @@
\def\insertchap#1#2#3%
{\insertchapter
- {#1\insertbibtype{}{\ }{chapter\ }}{#2}%
+ {#1\insertbibtype{}{\ }{chapitre\ }}{#2}%
{#3}}
\def\insertpublisher#1#2#3%
diff --git a/tex/context/bib/bibl-apa.tex b/tex/context/bib/bibl-apa.tex
index c6085c3c3..20bbccb95 100644
--- a/tex/context/bib/bibl-apa.tex
+++ b/tex/context/bib/bibl-apa.tex
@@ -154,7 +154,7 @@
{\insertcrossref{In }{}{}}%
\insertvolume
{\bgroup \it, }
- {\insertissue{\egroup\/(}{)}{}\insertpages{, }{.}{.}}
+ {\egroup\insertissue{\/(}{)}{}\insertpages{, }{.}{.}}
{\insertpages{, pp. }{.}{.}}%
\insertnote{ }{.}{}%
\insertcomment{}{.}{}%
@@ -283,7 +283,7 @@
\insertchap{\unskip, }{ }{ }%
\insertpages{\unskip, pages~}{. }{\unskip. }%
\insertedition{ }{ edition}{}%
- \insertpublisher{. }{.}{.}%
+ \insertpublisher{ }{.}{.}%
}%
{In \insertcrossref{}{}{}%
\insertchap{\unskip, }{ }{ }%
@@ -381,7 +381,7 @@
\insertauthors{}{ }{}%
\insertpubyear{(}{). }{}%
\inserttitle{\bgroup }{\egroup \insertseries{ (}{)}{}. }{}%
- \insertpublisher{ }{.}{.}%
+% \insertpublisher{ }{.}{.}%
\insertpages{ }{p. }{}%
\insertbibtype{(}{)}{}%
\insertnote{ }{.}{}%
diff --git a/tex/context/bib/t-bib.mkii b/tex/context/bib/t-bib.mkii
new file mode 100644
index 000000000..ac3494725
--- /dev/null
+++ b/tex/context/bib/t-bib.mkii
@@ -0,0 +1,5 @@
+% some code will move here
+
+\unprotect
+
+\protect \endinput
diff --git a/tex/context/bib/t-bib.mkiv b/tex/context/bib/t-bib.mkiv
new file mode 100644
index 000000000..4316d380e
--- /dev/null
+++ b/tex/context/bib/t-bib.mkiv
@@ -0,0 +1,64 @@
+%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
+
+\unprotect
+
+% 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
index 2cf79c3be..35a3de6ca 100644
--- a/tex/context/bib/t-bib.tex
+++ b/tex/context/bib/t-bib.tex
@@ -1,6 +1,6 @@
%D \module
%D [ file=t-bib,
-%D version=2008.10.23,
+%D version=2009.04.27,
%D title=\CONTEXT\ Publication Module,
%D subtitle=Publications,
%D author=Taco Hoekwater,
@@ -34,7 +34,7 @@
%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 Mnster (30/12/2005)
+%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)
@@ -104,7 +104,7 @@
%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 Wchter) (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)
@@ -116,6 +116,23 @@
%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 \stopitemize
%D
%D \subject{WISHLIST}
@@ -129,13 +146,22 @@
\unprotect
-%D start with a temp hack the file will still work with pre-Oct 20078
+%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:
@@ -300,6 +326,7 @@
\setupheadtext[it][pubs=Bibliografia]
\setupheadtext[sl][pubs=Literatura]
\setupheadtext[fr][pubs=Bibliographie]
+\setupheadtext[ca][pubs=Referències]
%D \macros{bibdoif,bibdoifnot,bibdoifelse}
%D
@@ -380,7 +407,9 @@
\write \scratchwrite {\string\bibdata{\@@pbdatabase}}%
\closeout\scratchwrite
\showmessage\m!bib{3}{}%
- \expanded{\installprogram{\@@pbbibtex\space\jobname}}}}
+ \doifmodeelse{*mkiv}
+ {\ctxlua{os.execute('\@@pbbibtex\space\jobname')}}
+ {\expanded{\installprogram{\@@pbbibtex\space\jobname}}}}}
%D \macros{ifsortbycite,iftypesetall,ifautohang,ifbibcitecompress}
%D
@@ -915,9 +944,11 @@
\fi
\def\filllocalpublist%
- {\let\dosetfilterlevel\patcheddosetfilterlevel
- \dosettoclevel\??li{pubs}%
- \let\dosetfilterlevel\normaldosetfilterlevel
+ {\doifdefinedelse{\alltoclevels}
+ {\let\dosetfilterlevel\patcheddosetfilterlevel
+ \dosettoclevel\??li{pubs}%
+ \let\dosetfilterlevel\normaldosetfilterlevel }%
+ {\dosettoclevel\??li{pubs}}%
\global\let\glocalpublist\empty
\doloop
{\doifdefinedelse
@@ -1375,11 +1406,32 @@
\or
\expanded{\docurrentbibauthor#1}%
\else
- % this can't happen/
- \def\currentbibauthor{}%
+ \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.
@@ -1858,6 +1910,8 @@
\setuppublications
[\v!month\v!conversion=,\c!alternative=apa]
+\loadmarkfile{t-bib}
+
\preloadbiblist
\protect \endinput
diff --git a/tex/context/config/cont-usr.tex b/tex/context/config/cont-usr.tex
index dab420e3e..5a3070362 100644
--- a/tex/context/config/cont-usr.tex
+++ b/tex/context/config/cont-usr.tex
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\writestatus{loading}{User Settings}
+\writestatus{loading}{ConTeXt User Settings}
\unprotect
diff --git a/tex/context/interface/cont-cs.xml b/tex/context/interface/cont-cs.xml
index a0095af10..d53a71a6f 100644
--- a/tex/context/interface/cont-cs.xml
+++ b/tex/context/interface/cont-cs.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="nastavzakladnifont" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="nastavzakladnifont" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="nastavzakladnifont" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="nastavmeziradkovoumezeru"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="prizpusobive"/>
</cd:parameter>
+ <cd:parameter name="metoda">
+ <cd:constant type="normalni"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tolerantni"/>
<cd:constant type="velmitolerantni"/>
<cd:constant type="natahnout"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definujsynonumumfontu"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-cz.xml b/tex/context/interface/cont-cz.xml
deleted file mode 100644
index d1b2de2ee..000000000
--- a/tex/context/interface/cont-cz.xml
+++ /dev/null
@@ -1,10033 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?><!-- versions:
-
- comment : user interface definitions of ConTeXt
-
- authors : Hans Hagen, Taco Hoekwater, Patrick Gundlach
-
- versions : 2004.11.17 : initial version
- 2006.08.02 : define + resolve
-
--->
-<cd:interface xmlns:cd="http://www.pragma-ade.com/commands" name="context" language="cz" version="2006.08.02">
-
- <cd:define name="align">
- <cd:constant type="uvnitr"/>
- <cd:constant type="vnejsi"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="flushleft"/>
- <cd:constant type="flushright"/>
- <cd:constant type="nastred"/>
- <cd:constant type="center"/>
- <cd:constant type="normalni"/>
- <cd:constant type="ne"/>
- <cd:constant type="ano"/>
- </cd:define>
-
- <cd:define name="symalign">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="flushleft"/>
- <cd:constant type="flushright"/>
- <cd:constant type="nastred"/>
- <cd:constant type="center"/>
- </cd:define>
-
- <cd:define name="indenting">
- <cd:constant type="nikdy"/>
- <cd:constant type="zadny"/>
- <cd:constant type="ne"/>
- <cd:constant type="ne"/>
- <cd:constant type="ano"/>
- <cd:constant type="vzdy"/>
- <cd:constant type="prvni"/>
- <cd:constant type="dalsi"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="normalni"/>
- <cd:constant type="liche"/>
- <cd:constant type="sude"/>
- <cd:constant type="cd:dimension"/>
- </cd:define>
-
- <cd:define name="indentnext">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:define>
-
- <cd:define name="style">
- <cd:constant type="normalni"/>
- <cd:constant type="tucne"/>
- <cd:constant type="sklonene"/>
- <cd:constant type="tucnesklonene"/>
- <cd:constant type="opis"/>
- <cd:constant type="kap"/>
- <cd:constant type="small..."/>
- <cd:constant type="cd:command"/>
- </cd:define>
-
- <cd:define name="language">
- <cd:constant type="nl"/>
- <cd:constant type="fr"/>
- <cd:constant type="en"/>
- <cd:constant type="uk"/>
- <cd:constant type="de"/>
- <cd:constant type="es"/>
- <cd:constant type="cz"/>
- <cd:constant type=".."/>
- </cd:define>
-
- <cd:define name="texts">
- <cd:constant type="cd:text"/>
- <cd:constant type="cd:section"/>
- <cd:constant type="datum"/>
- <cd:constant type="cd:mark"/>
- <cd:constant type="cislostranky"/>
- </cd:define>
-
- <cd:define name="layout-h">
- <cd:constant type="text" default="yes"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="hrana"/>
- </cd:define>
-
- <cd:define name="layout-v">
- <cd:constant type="vrsek"/>
- <cd:constant type="zahlavi"/>
- <cd:constant type="text" default="yes"/>
- <cd:constant type="upati"/>
- <cd:constant type="spodek"/>
- </cd:define>
-
- <cd:define name="bodyfont">
- <cd:constant type="5pt"/>
- <cd:constant type="..."/>
- <cd:constant type="12pt"/>
- <cd:constant type="male"/>
- <cd:constant type="velke"/>
- </cd:define>
-
- <cd:command name="installlanguage" file="lang-ini.tex" category="language">
- <cd:sequence>
- <cd:string value="instalacejazyka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="mezerovani">
- <cd:constant type="zhustene" default="yes"/>
- <cd:constant type="siroky"/>
- </cd:parameter>
- <cd:parameter name="lefthyphenmin">
- <cd:constant type="cd:number" default="2"/>
- </cd:parameter>
- <cd:parameter name="righthyphenmin">
- <cd:constant type="cd:number" default="2"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="vetavlevo">
- <cd:constant type="cd:command" default="---"/>
- </cd:parameter>
- <cd:parameter name="vetavpravo">
- <cd:constant type="cd:command" default="---"/>
- </cd:parameter>
- <cd:parameter name="podvetavlevo">
- <cd:constant type="cd:command" default="---"/>
- </cd:parameter>
- <cd:parameter name="podvetavpravo">
- <cd:constant type="cd:command" default="---"/>
- </cd:parameter>
- <cd:parameter name="citovatvlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="citovatvpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="citacevlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="citacevpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="leftspeech">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="middlespeech">
- <cd:constant type="cd:command" default=""/>
- </cd:parameter>
- <cd:parameter name="rightspeech">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="limittext">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="datum">
- <cd:constant type="cd:text"/> <!-- TODO -->
- </cd:parameter>
- <cd:parameter name="compoundhyphen">
- <cd:constant type="cd:command" default="\compoundhyphen"/>
- </cd:parameter>
- <cd:parameter name="leftcompoundhyphen">
- <cd:constant type="cd:command" default="\compoundhyphen"/>
- </cd:parameter>
- <cd:parameter name="rightcompoundhyphen">
- <cd:constant type="cd:command" default=""/>
- </cd:parameter>
- <cd:parameter name="implicitni">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplanguage" file="lang-ini.tex" category="language">
- <cd:sequence>
- <cd:string value="nastavjazyk"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:resolve name="language"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="instalacejazyka" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="language" file="lang-ini.tex" category="language">
- <cd:sequence>
- <cd:string value="jazyk"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:resolve name="language"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="mainlanguage" file="lang-ini.tex" category="language">
- <cd:sequence>
- <cd:string value="hlavnijazyk"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:resolve name="language"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="translate" file="lang-lab.tex" category="language">
- <cd:sequence>
- <cd:string value="prelozit"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="cd:name">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useencoding" file="enco-ini.tex" category="encoding"> <!-- engine="pdftex" -->
- <cd:sequence>
- <cd:string value="uzijkodovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usespecials" file="spec-ini.tex">
- <cd:sequence>
- <cd:string value="uzijspeciality"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="reset"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineoutput" file="spec-ini.tex">
- <cd:sequence>
- <cd:string value="definujvystup"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupoutput" file="spec-ini.tex">
- <cd:sequence>
- <cd:string value="nastavvystup"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definebodyfontenvironment" file="font-ini.tex" category="fonts">
- <cd:sequence>
- <cd:string value="definujprostredizakladnihofontu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes"> <!-- it's possible to use 1+2+3, 2+3, what about 1+2? -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="no"> <!-- have to force no, otherwise \showsetup is wrong ! -->
- <cd:constant type="5pt"/> <!-- TODO: maybe <cd:resolve name="bodyfont"/> -->
- <cd:constant type="..."/>
- <cd:constant type="12pt"/>
- <cd:constant type="implicitni"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:parameter name="text">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="script">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="scriptscript">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="x">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="xx">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="male">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="velky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="meziradkovamezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="em">
- <cd:resolve name="style"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbodyfontenvironment" file="font-ini.tex" category="fonts">
- <cd:sequence>
- <cd:string value="nastavprostredizakladnihofontu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes"> <!-- same as definebodyfontenvironment; you can define the whole commant to inherit, not only parameters-->
- <cd:inherit name="definujprostredizakladnihofontu" n="1"/>
- </cd:keywords>
- <cd:keywords n="2" optional="no">
- <cd:inherit name="definujprostredizakladnihofontu" n="2" optional="no"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="definujprostredizakladnihofontu" n="3"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showbodyfontenvironment" file="font-run.tex" category="fonts"> <!-- and debug -->
- <cd:sequence>
- <cd:string value="ukazpostredizakladnihofontu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:inherit name="nastavzakladnifont" n="1"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definebodyfont" file="font-ini.tex" category="fonts">
- <cd:sequence>
- <cd:string value="definujzakladnifont"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes"> <!-- <cd:constant type="implicitni"/> -->
- <cd:resolve name="bodyfont"/> <!-- TODO: check this -->
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="rm"/>
- <cd:constant type="ss"/>
- <cd:constant type="tt"/>
- <cd:constant type="mm"/>
- <cd:constant type="hw"/>
- <cd:constant type="cg"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="tf">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="bf">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="sl">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="it">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="bs">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="bi">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="sc">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="ex">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="mi">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="sy">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="ma">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="mb">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="mc">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showbodyfont" file="font-run.tex" category="fonts"> <!-- visual debugging -->
- <cd:sequence>
- <cd:string value="ukazzakladnifont"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:inherit name="nastavzakladnifont" n="1"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbodyfont" file="font-run.tex" category="fonts">
- <cd:sequence>
- <cd:string value="nastavzakladnifont"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes"> <!-- TODO: many missing, maybe also <cd:resolve name="bodyfont"/> -->
- <cd:constant type="cd:name"/>
- <cd:constant type="serif"/>
- <cd:constant type="pravidelne"/>
- <cd:constant type="antikva"/>
- <cd:constant type="sans"/>
- <cd:constant type="podpora"/>
- <cd:constant type="bezserifu"/>
- <cd:constant type="mono"/>
- <cd:constant type="opis"/>
- <cd:constant type="strojopis"/>
- <cd:constant type="rukopisne"/>
- <cd:constant type="kaligraficke"/>
- <cd:constant type="5pt"/>
- <cd:constant type="..."/>
- <cd:constant type="12pt"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="switchtobodyfont" file="font-ini.tex" category="fonts">
- <cd:sequence>
- <cd:string value="prepninazakladnifont"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:resolve name="bodyfont"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefont" file="font-ini.tex" category="fonts">
- <cd:sequence>
- <cd:string value="definujfont"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcolor" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="nastavbarvu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcolors" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="nastavbarvy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="globalne"/>
- <cd:constant type="lokalne"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="vzdy"/>
- </cd:parameter>
- <cd:parameter name="redukce">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="rgb">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="cmyk">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="mpcmyk">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="mpspot">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="barvatextu">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="split">
- <cd:constant type="c"/>
- <cd:constant type="m"/>
- <cd:constant type="y"/>
- <cd:constant type="k"/>
- <cd:constant type="p"/>
- <cd:constant type="s"/>
- <cd:constant type="ne"/>
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="vse"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definecolor" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="definujbarvu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="r">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="g">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="b">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="c">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="m">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="y">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="k">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="s">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="h">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="t">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="a">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="p">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="e">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="color" type="environment" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="barva"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="color" file="colo-ini.tex">
- <cd:sequence>
- <cd:string value="barva"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="graycolor" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="sedabarva"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showcolor" file="colo-run.tex" category="colors"> <!-- and debug -->
- <cd:sequence>
- <cd:string value="ukazbarvu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definepalet" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="definujpaletu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="cd:name">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppalet" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="nastavpaletu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definecolorgroup" file="colo-ini.tex" category="colors">
- <cd:sequence>
- <cd:string value="definujskupinubarev"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="rgb" default="yes"/>
- <cd:constant type="cmyk"/>
- <cd:constant type="seda"/>
- <cd:constant type="s"/>
- </cd:keywords>
- <cd:triplet n="3" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showpalet" file="colo-run.tex" category="colors"> <!-- and debug -->
- <cd:sequence>
- <cd:string value="ukazpaletu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="horizontalne"/>
- <cd:constant type="vertikalne"/>
- <cd:constant type="jmeno"/>
- <cd:constant type="hodnota"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showcolorgroup" file="colo-run.tex" category="colors"> <!-- and debug-->
- <cd:sequence>
- <cd:string value="ukazskupinubarev"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="horizontalne"/>
- <cd:constant type="vertikalne"/>
- <cd:constant type="jmeno"/>
- <cd:constant type="hodnota"/>
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="comparepalet" file="colo-run.tex" category="colors"> <!-- and debug? -->
- <cd:sequence>
- <cd:string value="porovnejpaletu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="comparecolorgroup" file="colo-run.tex" category="colors">
- <cd:sequence>
- <cd:string value="porovnejskupinubarev"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showmakeup" file="supp-vis.tex" category="debug">
- <cd:sequence>
- <cd:string value="ukazupravu"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="definetype" file="core-ver.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="definetype"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavtype" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptype" file="core-ver.tex" category="verbatim"> <!-- TODO -->
- <cd:sequence>
- <cd:string value="nastavtype"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="mezera">
- <cd:constant type="zap"/>
- <cd:constant type="vyp" default="yes"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="sklonene"/>
- <cd:constant type="normalni"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="type" file="verb-ini.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="opis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="typ" file="core-ver.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="pis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="tex" file="core-ver.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="tex"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <!-- cd:command name="arg" file="core-ver.tex"> command broken
- <cd:sequence>
- <cd:string value="arg"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content/>
- </cd:arguments>
-</cd:command -->
-
- <cd:command name="definetyping" file="core-ver.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="definujopis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:inherit name="nastavopis" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavopis" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptyping" file="core-ver.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="nastavopis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="soubor"/>
- <cd:constant type="typing"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="mezera">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="sklonene"/>
- <cd:constant type="normalni"/>
- <cd:constant type="prikazy"/>
- <cd:constant type="barevne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="iprikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vprikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="cprikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command" default="\blank"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command" default="\blank"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="standardni"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="sudamarginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="lichyokraj">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="prazdny">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="standardni"/>
- <cd:constant type="pulradku"/>
- <cd:constant type="radek"/>
- </cd:parameter>
- <cd:parameter name="escape">
- <cd:constant type="cd:character"/>
- </cd:parameter>
- <cd:parameter name="mezera">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="tab">
- <cd:constant type="cd:number"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="paleta">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="radky">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="hyphenated"/>
- </cd:parameter>
- <cd:parameter name="prazdne">
- <cd:constant type="ano"/>
- <cd:constant type="vse"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="cislovani">
- <cd:constant type="radek"/>
- <cd:constant type="soubor"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="typing" type="environment" generated="yes" file="verb-ini.tex"
- category="verbatim">
- <cd:sequence>
- <cd:variable value="typing"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="typefile" file="verb-ini.tex" category="verbatim">
- <cd:sequence>
- <cd:string value="opissoubor"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfootnotes" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="nastavpoznamkypodcarou"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- </cd:parameter>
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="stranka"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="sloupce"/>
- <cd:constant type="firstcolumn"/>
- <cd:constant type="lastcolumn"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="linka">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostsloupcu">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostokraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ciselnyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="textovyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="split">
- <cd:constant type="tolerantni"/>
- <cd:constant type="striktni"/>
- <cd:constant type="velmistriktni"/>
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="styltextu">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barvatextu">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="interakce">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfootnotedefinition" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="nastavdefinicipoznamekpodcarou"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:inherit name="nastavpopisy" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="footnote" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="poznamkapodcarou"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="footnotetext" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="footnotetext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="note" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="poznamka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" interactive="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="localfootnotes" type="environment" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="localfootnotes"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="placelocalfootnotes" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="umistilokalnipoznamkypodcarou"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavpoznamkypodcarou" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placefootnotes" file="core-not.tex" category="footnotes">
- <cd:sequence>
- <cd:string value="umistipoznamkypodcarou"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavpoznamkypodcarou" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupunderbar" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="nastavpodtrzeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetspodku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetvrsku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barvalinky">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="underbar" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="podtrzeno"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="underbars" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="podtrzeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overbar" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="nadtrzeno"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overbars" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="nadtrzeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overstrike" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="preskrtnuto"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overstrikes" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="preskrtnuti"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="romannumerals" file="core-con.tex">
- <cd:sequence>
- <cd:string value="rimskecislice"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Romannumerals" file="core-con.tex">
- <cd:sequence>
- <cd:string value="Rimskecislice"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="numbers" file="core-con.tex">
- <cd:sequence>
- <cd:string value="cisla"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="character" file="core-con.tex">
- <cd:sequence>
- <cd:string value="znak"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Character" file="core-con.tex">
- <cd:sequence>
- <cd:string value="Znak"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="characters" file="core-con.tex">
- <cd:sequence>
- <cd:string value="znaky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Characters" file="core-con.tex">
- <cd:sequence>
- <cd:string value="Znaky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="mediaeval" file="core-con.tex">
- <cd:sequence>
- <cd:string value="mediaeval"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="month" file="core-con.tex">
- <cd:sequence>
- <cd:string value="mesic"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="MONTH" file="core-con.tex">
- <cd:sequence>
- <cd:string value="MESIC"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="weekday" file="core-con.tex">
- <cd:sequence>
- <cd:string value="vsedniden"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="WEEKDAY" file="core-con.tex">
- <cd:sequence>
- <cd:string value="VSEDNIDEN"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcapitals" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="nastavkapitalky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="titul">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="sc">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="cap" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="cap"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nocap" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="nocap"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="CAP" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="CAP"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Cap" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="Cap"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Caps" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="Caps"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="WORD" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="SLOVO"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="WORDS" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="SLOVA"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Word" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="Slovo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="Words" file="core-fnt.tex" category="Fonts">
- <cd:sequence>
- <cd:string value="Slova"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="stretched" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="roztazene"/>
- </cd:sequence>
- <cd:arguments>
- <cd:word n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definesymbol" file="symb-ini.tex">
- <cd:sequence>
- <cd:string value="definujsymbol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefiguresymbol" file="symb-ini.tex">
- <cd:sequence>
- <cd:string value="definujobrazeksymbol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavexterniobrazy" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="symbol" file="symb-ini.tex">
- <cd:sequence>
- <cd:string value="symbol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="symbolset" type="environment" file="symb-ini.tex" category="symbols">
- <cd:sequence>
- <cd:string value="symbolset"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsymbolset" file="symb-ini.tex" category="symbols">
- <cd:sequence>
- <cd:string value="nastavsadusymbolu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usesymbols" file="symb-ini.tex" category="symbols">
- <cd:sequence>
- <cd:string value="uzijsymbol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showsymbolset" file="symb-run.tex" category="symbols"> <!-- and symbols -->
- <cd:sequence>
- <cd:string value="ukazsadusymbolu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineconversion" file="core-con.tex">
- <cd:sequence>
- <cd:string value="definujkonverzi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:command"/>
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="convertnumber" file="core-con.tex">
- <cd:sequence>
- <cd:string value="konvertujcislo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupheadtext" file="lang-lab.tex">
- <cd:sequence>
- <cd:string value="nastavtexthlavicky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="language"/>
- </cd:keywords>
- <cd:assignments n="2">
- <cd:parameter name="cd:name">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplabeltext" file="lang-lab.tex">
- <cd:sequence>
- <cd:string value="nastavtextpopisku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="language"/>
- </cd:keywords>
- <cd:assignments n="2">
- <cd:parameter name="cd:name">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="headtext" file="lang-lab.tex">
- <cd:sequence>
- <cd:string value="texthlavicky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="labeltext" file="lang-lab.tex">
- <cd:sequence>
- <cd:string value="textpopisku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupmarginrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavmarginalnilinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1">
- <cd:parameter name="uroven">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="marginrule" type="environment" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="marginalnilinka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="marginrule" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="marginalnilinka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplinewidth" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavsirkucary"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:dimension"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupframed" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavoramovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/> <!-- defines a command with that name -->
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="vyska">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="fixne"/>
- <cd:constant type="lokalne"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="autosirka">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="sila"/>
- </cd:parameter>
- <cd:parameter name="offset">
- <cd:constant type="zadny"/>
- <cd:constant type="prekryv"/>
- <cd:constant type="implicitni"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="podlehloubky"/>
- <cd:constant type="visici"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="nivy"/>
- <cd:constant type="nizko"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="nastred"/>
- <cd:constant type="spodek"/>
- <cd:constant type="drzet"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="zadny"/>
- <cd:constant type="prazdne"/>
- </cd:parameter>
- <cd:parameter name="strut">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="globalne"/>
- <cd:constant type="lokalne"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="spodek">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vrsek">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="ramecek">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- <cd:constant type="zadny"/>
- <cd:constant type="prekryv"/>
- </cd:parameter>
- <cd:parameter name="rameceknahore">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="ramecekdole">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="ramecekvlevo">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="ramecekvpravo">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="offsetramecku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="hloubkaramecku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="rohramecku">
- <cd:constant type="zaobleny"/>
- <cd:constant type="pravouhly"/>
- </cd:parameter>
- <cd:parameter name="polomerramecku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barvaramecku">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="pozadi">
- <cd:constant type="rastr"/>
- <cd:constant type="barevne"/>
- <cd:constant type="zadny"/>
- <cd:constant type="popredi"/>
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="rastrpozadi">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="barvapozadi">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="offsetpozadi">
- <cd:constant type="ramecek"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="hloubkapozadi">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="rohpozadi">
- <cd:constant type="zaobleny"/>
- <cd:constant type="pravouhly"/>
- </cd:parameter>
- <cd:parameter name="polomerpozadi">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="roh">
- <cd:constant type="zaobleny"/>
- <cd:constant type="pravouhly"/>
- </cd:parameter>
- <cd:parameter name="polomer">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="prazdne">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="foregroundcolor">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="foregroundstyle">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="framed" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="oramovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inframed" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="zaramovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="thinrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="tenkelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes">
- <cd:inherit name="nastavtenkelinky" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupthinrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavtenkelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1">
- <cd:parameter name="meziradkovamezera">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="barvapozadi">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- <cd:constant type="d"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="pozadi">
- <cd:constant type="barevne"/>
- </cd:parameter>
- <cd:parameter name="barvapozadi">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="hairline" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="vlasovalinka"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="thinrule" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="tenkalinka"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="defineframedtext" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="definujoramovanytext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavoramovanetexty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineframed" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="definujoramovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavoramovanetexty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupframedtexts" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavoramovanetexty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vnitrni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="korekceradku">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="korekcehloubky">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="standardni"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="odsazovani">
- <cd:resolve name="indenting"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="framedtext" type="environment" generated="yes" file="core-rul.tex">
- <cd:sequence>
- <cd:variable value="oramovanytext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="zadny"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavoramovanetexty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="framedtext" generated="yes" file="core-rul.tex">
- <cd:sequence>
- <cd:variable value="oramovanytext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavoramovanetexty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="background" type="environment" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="pozadi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="background" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="pozadi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbackground" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavpozadi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="levyoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravyoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetvrsku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetspodku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fillinrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="vyplnovelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavvyplnovelinky" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- <cd:content n="3" optional="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fillintext" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="vyplnenytext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavvyplnovelinky" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- <cd:content n="3" optional="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfillinrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavvyplnovelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="meziradkovamezera">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fillinline" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="vyplnovyradek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavvyplnoveradky" n="1"/>
- </cd:assignments>
- <cd:nothing n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfillinlines" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavvyplnoveradky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptextrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavtextovelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="naokraji"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barvalinky">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="textrule" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="textovalinka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- </cd:keywords>
- <cd:content n="2" optional="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="textrule" type="environment" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="textovalinka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- </cd:keywords>
- <cd:content n="2" optional="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="blackrule" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="cernalinka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavcernelinky" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="blackrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="cernelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:inherit name="nastavcernelinky" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupblackrules" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavcernelinky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension" default="1em"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension" default="1ex"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="a" default="yes"/>
- <cd:constant type="b"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension" default=".25ex"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number" default="3"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineoverlay" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="definujprekryv"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:command"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usemodule" file="core-fil.tex"> <!-- TODO -->
- <cd:sequence>
- <cd:string value="uzijmodul"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="reset" file="core-num.tex">
- <cd:sequence>
- <cd:string value="reset"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <!-- <cd:command name="donttest">
- <cd:sequence>
- <cd:string value="zadnytest"/>
- </cd:sequence>
-</cd:command> -->
-
- <cd:command name="localenvironment" type="environment" file="core-job.tex">
- <cd:sequence>
- <cd:string value="localenvironment"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupsystem" file="core-sys.tex">
- <cd:sequence>
- <cd:string value="nastavsystem"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="rozliseni">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="soubor">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="adresar">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="nahodne">
- <cd:constant type="normalni"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usedirectory" file="core-job.mkii"> <!-- usepath, todo: more than one file -->
- <cd:sequence>
- <cd:string value="usedirectory"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- <cd:constant type="reset"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="low" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="nizky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="high" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="vysoky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="lohi" file="core-fnt.tex">
- <cd:sequence>
- <cd:string value="nivy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showframe" file="page-run.tex">
- <cd:sequence>
- <cd:string value="ukazramecek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="hrana"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="leftaligned" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zarovnanovlevo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="rightaligned" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zarovnanovpravo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="midaligned" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zarovnanonastred"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="wordright" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="slovovpravo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inmargin" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="naokraj"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inothermargin" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="nadruhyokraj"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inleft" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="vlevo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inright" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="vpravo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="ininner" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="ininner"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inouter" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="inouter"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="column" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="sloupec"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="showstruts" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="ukazpodpery"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="showsetups" file="page-run.tex">
- <cd:sequence>
- <cd:string value="ukaznastaveni"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="showlayout" file="page-run.tex">
- <cd:sequence>
- <cd:string value="ukazvzhled"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="margintext" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="marginalnitext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="nizko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupmarginblocks" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="nastavmarginalniblok"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="naokraji"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="vrsek">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="spodek">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="marginblock" type="environment" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="marginblock"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="part" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="part"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="title" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="title"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="chapter" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="chapter"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="section" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="section"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="subsection" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="subsection"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="subsubsection" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="subsubsection"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="subject" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="subject"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="subsubject" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="subsubject"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="subsubsubject" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="subsubsubject"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="appendix" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="appendix"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="in" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="tref"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="yes"/>
- <cd:content n="2" interactive="yes"/>
- <cd:reference n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="at" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="pref"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="yes"/>
- <cd:content n="2" interactive="yes"/>
- <cd:reference n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="about" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="oref"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="yes"/>
- <cd:reference n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="somewhere" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="nekde"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- <cd:reference n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="atpage" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="nastrane"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="ref" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="ref"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="t"/>
- <cd:constant type="p"/>
- <cd:constant type="r"/>
- <cd:constant type="s"/>
- <cd:constant type="e"/>
- </cd:keywords>
- <cd:reference n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="textreference" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="odkaznatext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="pagereference" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="odkaznastranu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="reference" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="odkaz"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usereferences" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="uzijodkazy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definereference" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="definujodkaz"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:reference n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definereferenceformat" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="definujformatodkazu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="vlevo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="popisek">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="hl" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="hl"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="vl" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="vl"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="godown" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="jdidolu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:dimension"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="whitespace" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="bilemisto"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="nowhitespace" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zadnebilemisto"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="crlf" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="crlf"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="space" file="syst-pln.tex">
- <cd:sequence>
- <cd:string value="mezera"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="fixedspaces" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="tvrdemezery"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="emptylines" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="emptylines"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nospace" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zadnamezera"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="packed" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zhustene"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupdescriptions" file="core-des.tex">
- <cd:sequence>
- <cd:string value="nastavpopisy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/> <!-- TODO: style=normal -->
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="cd:dimension" default="8em"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="vzor">
- <cd:constant type="cd:text" default=""/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="closesymbol">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="closecommand">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="closesymbol">
- <cd:constant type="cd:text" default=""/>
- </cd:parameter>
- <cd:parameter name="titleleft">
- <cd:constant type="cd:text" default="("/>
- </cd:parameter>
- <cd:parameter name="titleright">
- <cd:constant type="cd:text" default=")"/>
- </cd:parameter>
- <cd:parameter name="vzdalenosttitulek">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="styltitulek">
- <cd:resolve name="style"/> <!-- TODO: default=bold -->
- </cd:parameter>
- <cd:parameter name="barvatitulek">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="standardni"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne" default="yes"/> <!-- TODO: this is default; conflicting syntax? -->
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo" default="yes"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="semknuto"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="visici"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/> <!-- TODO: default=bold -->
- </cd:parameter>
- <cd:parameter name="barvahlavicky">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- <cd:parameter name="headcommand">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="zaveseni">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command" default="\blank"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command" default="\blank"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command" default="\blank"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/> <!-- default=yes -->
- </cd:parameter>
- <cd:parameter name="odsazovani">
- <cd:resolve name="indenting"/> <!-- default=never -->
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupenumerations" file="core-des.tex">
- <cd:sequence>
- <cd:string value="nastavvycty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavpopisy" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineenumeration" file="core-des.tex">
- <cd:sequence>
- <cd:string value="definujvycet"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavvycty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="enumeration" generated="yes" file="core-des.tex">
- <cd:sequence>
- <cd:variable value="vycet"/>
- </cd:sequence>
- <cd:arguments>
- <cd:nothing n="1" interactive="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="enumeration" type="environment" generated="yes" file="core-des.tex">
- <cd:sequence>
- <cd:variable value="vycet"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="definedescription" file="core-des.tex">
- <cd:sequence>
- <cd:string value="definujpopis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavpopisy" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="description" generated="yes" file="core-des.tex">
- <cd:sequence>
- <cd:variable value="popis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:nothing n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="description" type="environment" generated="yes" file="core-des.tex">
- <cd:sequence>
- <cd:variable value="popis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupindentations" file="core-des.tex">
- <cd:sequence>
- <cd:string value="nastavodsazeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vzor">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineindenting" file="core-des.tex">
- <cd:sequence>
- <cd:string value="definujodsazovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavodsazeni" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="indentation" generated="yes" file="core-spa.tex">
- <cd:sequence>
- <cd:variable value="indentation"/>
- </cd:sequence>
- <cd:arguments>
- <cd:nothing n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definelabel" file="core-des.tex">
- <cd:sequence>
- <cd:string value="definujpopisek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="text">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="naokraji"/>
- <cd:constant type="dotextu"/>
- </cd:parameter>
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="dobloku">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barvahlavicky">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="labeling" generated="yes" file="core-des.tex">
- <cd:sequence>
- <cd:variable value="labeling"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcolumns" file="page-mul.tex">
- <cd:sequence>
- <cd:string value="nastavsloupce"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes"> <!-- no idea why it is optional -->
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="nvrsek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="linka">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/> <!-- default and unknown missing -->
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="tolerance">
- <cd:constant type="velmistriktni"/>
- <cd:constant type="striktni"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- <cd:constant type="natahnout"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="rovnovaha">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:constant type="text"/>
- <!-- cd:constant type="yes"/ -->
- <!-- cd:constant type="no"/ -->
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="prazdny">
- <cd:constant type="fixne"/>
- <cd:constant type="pulradku"/>
- <cd:constant type="radek"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="velke"/>
- <cd:constant type="stredni"/>
- <cd:constant type="male"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="pozadi"/>
- </cd:parameter>
- <cd:parameter name="smer">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="columns" type="environment" file="page-mul.tex">
- <cd:sequence>
- <cd:string value="columns"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavsloupce" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definetext" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="definujtext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="zahlavi"/>
- <cd:constant type="upati"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="4" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="5" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupheader" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavzahlavi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text" default="yes"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="hrana"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="status">
- <cd:constant type="normalni"/>
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="zadny"/>
- <cd:constant type="zadneznaceni"/>
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="strut">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylvlevo">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylvpravo">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="sirkavlevo">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirkavpravo">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfooter" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavupati"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:inherit name="nastavzahlavi" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavzahlavi" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptext" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavtext"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:inherit name="nastavzahlavi" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavzahlavi" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptop" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavhorejsek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:inherit name="nastavzahlavi" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavzahlavi" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbottom" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavspodek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:inherit name="nastavzahlavi" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavzahlavi" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="noheaderandfooterlines" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="zadnezahlaviaupati"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="notopandbottomlines" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="zadnehorniadolniradky"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupheadertexts" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavtextyzahlavi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfootertexts" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavtextyupati"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptexttexts" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavtexttexty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptoptexts" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavhornitexty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbottomtexts" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="nastavdolnitexty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="settextcontent" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="settextcontent"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:resolve name="layout-v"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="4" optional="yes">
- <cd:resolve name="texts"/>
- </cd:keywords>
- <cd:keywords n="5" optional="yes">
- <cd:resolve name="texts"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="resettextcontent" file="page-txt.tex">
- <cd:sequence>
- <cd:string value="resettextcontent"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:resolve name="layout-v"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:resolve name="layout-h"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes">
- <cd:constant type="lefttext"/>
- <cd:constant type="middletext"/>
- <cd:constant type="righttext"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definemarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="definujznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="couplemarking" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="propojeneznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="decouplemarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="rozpojeneznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="resetmarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="resetznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupmarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="nastavznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="marking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="znaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="getmarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="ziskejznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="prvni"/>
- <cd:constant type="posledni"/>
- <cd:constant type="predchozi"/>
- <cd:constant type="obe"/>
- <cd:constant type="vse"/>
- <cd:constant type="aktualni"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nomarking" file="core-mar.tex">
- <cd:sequence>
- <cd:string value="zadneznaceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplayout" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="nastavvzhled"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="nastred"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="nastred"/>
- </cd:parameter>
- <cd:parameter name="zpetnamezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="svrchnimezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="levyokraj">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravyokraj">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zahlavi">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="upati">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vrsek">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="spodek">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="levahrana">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravahrana">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostzahlavi">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostupati">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostvrsku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostspodku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostlevehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostpravehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostlevehrany">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostpravehrany">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="horoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsethlavicky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="znaceni">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- <cd:constant type="barevne"/>
- <cd:constant type="rastr"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="spodek"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="jednostranne"/>
- <cd:constant type="dvoustranny"/>
- </cd:parameter>
- <cd:parameter name="meritko">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="nx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ny">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="dx">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="dy">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="radky">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="sloupce">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostsloupcu">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="mrizka">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="bottomspace">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="cutspace">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="textdistance">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirkatextu">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="textmargin">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="clipoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="papir">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="adaptlayout" file="page-lay.tex">
- <cd:sequence>
- <cd:string value="prizpusobvzhled"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="radky">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showgrid" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="ukazmrizku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="reset"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="zadny"/>
- <cd:constant type="vse"/>
- <cd:constant type="radky"/>
- <cd:constant type="ramecek"/>
- <cd:constant type="nonumber"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vlevo"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placeongrid" file="core-grd.tex">
- <cd:sequence>
- <cd:string value="umistinamrizku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:inherit name="premistinamrizku" n="1"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="moveongrid" file="core-grd.tex">
- <cd:sequence>
- <cd:string value="premistinamrizku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="standardni" default="yes"/> <!-- also 'normal', 'yes' and 'force' -->
- <cd:constant type="vrsek"/>
- <cd:constant type="obe"/>
- <cd:constant type="spodek"/>
- <cd:constant type="-top"/>
- <cd:constant type="-both"/>
- <cd:constant type="-bottom"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="nastred"/>
- <cd:constant type="nizko"/>
- <cd:constant type="stranka"/>
- <cd:constant type="siroky"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="podlehloubky"/>
- <cd:constant type="radek"/>
- <cd:constant type="reset"/>
- <cd:constant type="zadny"/>
- <cd:constant type="cd:dimension"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="project" type="environment" file="core-job.tex">
- <cd:sequence>
- <cd:string value="projekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:file n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="environment" type="environment" file="core-job.tex">
- <cd:sequence>
- <cd:string value="prostredi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:file n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="product" type="environment" file="core-job.tex">
- <cd:sequence>
- <cd:string value="produkt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:file n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="component" type="environment" file="core-job.tex">
- <cd:sequence>
- <cd:string value="komponenta"/>
- </cd:sequence>
- <cd:arguments>
- <cd:file n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nomorefiles" file="core-job.tex">
- <cd:sequence>
- <cd:string value="zadnedalsisoubory"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupinterlinespace" variant="1" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="nastavmeziradkovoumezeru"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="reset"/>
- <cd:constant type="male" default="yes"/>
- <cd:constant type="stredni"/>
- <cd:constant type="auto"/>
- <cd:constant type="velke"/>
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
- <!-- attached a 2 to make this definition usable with \showsetup -->
- <cd:sequence>
- <cd:string value="nastavmeziradkovoumezeru"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="vyska">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="radek">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vrsek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="spodek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppagenumbering" file="page-num.tex">
- <cd:sequence>
- <cd:string value="nastavcislovanistran"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="jednostranne"/>
- <cd:constant type="dvoustranny"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="zahlavi"/>
- <cd:constant type="upati"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="textovahrana"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="oddelovaccisla">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="oddelovactextu">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="cd:sectionnumber">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="strut">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupnarrower" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="nastavzuzeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="vlevo">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stredni">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="define" file="syst-ext.tex">
- <cd:sequence>
- <cd:string value="definuj"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- <cd:csname n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usecommands" file="core-sys.tex">
- <cd:sequence>
- <cd:string value="uzijprikazy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definestartstop" file="core-sys.tex">
- <cd:sequence>
- <cd:string value="definujstartstop"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="prikazy">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupheads" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="nastavnadpisy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="cislooddilu">
- <cd:constant type="ano"/>
- <cd:constant type="cd:number"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="normalni"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="nastred"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="odstavec"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="predel">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="zarovnejtitul">
- <cd:constant type="ano"/>
- <cd:constant type="plvouciobjekt"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="tolerance">
- <cd:constant type="velmistriktni"/>
- <cd:constant type="striktni"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- <cd:constant type="natahnout"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:twoarguments"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcaptions" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="nastavpopisky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="zadny"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="nizko"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="lefthanging"/>
- <cd:constant type="righthanging"/>
- <cd:constant type="levyokraj"/>
- <cd:constant type="pravyokraj"/>
- <cd:constant type="innermargin"/>
- <cd:constant type="outermargin"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="max"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="minsirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="cislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- </cd:parameter>
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="predel">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcaption" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="nastavpopisek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavpopisky" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfloats" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="nastavplvouciobjekty"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="mezerapred">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="mezeraza">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="bocnimezerapred">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="bocnimezeraza">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/>
- </cd:parameter>
- <cd:parameter name="nvrsek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="nspodek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="nradky">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="implicitni">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="tolerance">
- <cd:constant type="0"/>
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostlevehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostpravehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sidealign">
- <cd:constant type="normalni"/>
- <cd:constant type="radek"/>
- </cd:parameter>
- <cd:parameter name="cislovani">
- <cd:constant type="ano"/>
- <cd:constant type="nocheck"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfloatsplitting" file="core-tsp.tex">
- <cd:sequence>
- <cd:string value="nastavdeleniplvoucichobjektu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- </cd:parameter>
- <cd:parameter name="radky">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="splitfloat" file="core-tsp.tex">
- <cd:sequence>
- <cd:string value="rozdelplvouciobjekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavdeleniplvoucichobjektu" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupoppositeplacing" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="nastavumisteniprotejsku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="opposite" type="environment" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="opposite"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setuphyphenmark" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavdelitko"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1">
- <cd:parameter name="znak">
- <cd:constant type="--"/>
- <cd:constant type="---"/>
- <cd:constant type="-"/>
- <cd:constant type="~"/>
- <cd:constant type="("/>
- <cd:constant type=")"/>
- <cd:constant type="="/>
- <cd:constant type="/"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppositioning" file="page-lyr.tex">
- <cd:sequence>
- <cd:string value="nastavumistovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="prekryv"/>
- </cd:parameter>
- <cd:parameter name="jednotka">
- <cd:constant type="cm"/>
- <cd:constant type="pt"/>
- <cd:constant type="em"/>
- <cd:constant type="mm"/>
- <cd:constant type="ex"/>
- <cd:constant type="es"/>
- <cd:constant type="in"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="meritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="offset">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="xkrok">
- <cd:constant type="absolutni"/>
- <cd:constant type="relativni"/>
- </cd:parameter>
- <cd:parameter name="ykrok">
- <cd:constant type="absolutni"/>
- <cd:constant type="relativni"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="positioning" type="environment" file="page-lyr.tex">
- <cd:sequence>
- <cd:string value="positioning"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="grid" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="mrizka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="x">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="y">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="nx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ny">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="dx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="dy">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="xkrok">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ykrok">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="offset">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="meritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="jednotka">
- <cd:constant type="cm"/>
- <cd:constant type="pt"/>
- <cd:constant type="em"/>
- <cd:constant type="mm"/>
- <cd:constant type="ex"/>
- <cd:constant type="es"/>
- <cd:constant type="in"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="page" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="strana"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="ano" default="yes"/>
- <cd:constant type="zlom"/>
- <cd:constant type="ne"/>
- <cd:constant type="nastaveni"/>
- <cd:constant type="vysokapriorita"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="zablokovat"/>
- <cd:constant type="posledni"/>
- <cd:constant type="ctyrnasobny"/>
- <cd:constant type="sude"/>
- <cd:constant type="liche"/>
- <cd:constant type="prazdny"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="reset"/>
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupreferencing" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="nastavodkazovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="cd:sectionnumber">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="interakce">
- <cd:constant type="popisek"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="vse"/>
- <cd:constant type="symbol"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="konverzesouboru">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="male"/>
- <cd:constant type="velke"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="autofile">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="stranka"/>
- </cd:parameter>
- <cd:parameter name="globalne">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupurl" file="core-ref.tex" category="references">
- <cd:sequence>
- <cd:string value="nastavurl"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="urlalternativa">
- <cd:constant type="zadny"/>
- <cd:constant type="obe"/>
- <cd:constant type="pred"/>
- <cd:constant type="po"/>
- </cd:parameter>
- <cd:parameter name="prostorurl">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="writetoreferencelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="zapisdoseznamuodkazu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placereferencelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="placereferencelist"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definereferencelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="definujseznamodkazu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavseznamodkazu" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupreferencelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="nastavseznamodkazu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="cd:section"/>
- <cd:constant type="lokalne"/>
- <cd:constant type="predchozi"/>
- <cd:constant type="vse"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="writetolist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="zapisdoseznamu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:section"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="writebetweenlist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="zapismeziseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:section"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nolist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="zadnyseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="listsymbol" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="listsymbol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="umistiseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="determinelistcharacteristics" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="stanovcharakteristickuseznamu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placecombinedlist" variant="1" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="umistikombinovanyseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavkombinovanyseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definelist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="definujseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes"> <!-- inherits from -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="nastavseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- <cd:constant type="..."/>
- <cd:constant type="zadny"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- <cd:parameter name="propojeni">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="cd:section"/>
- <cd:constant type="lokalne"/>
- <cd:constant type="predchozi"/>
- <cd:constant type="aktualni"/>
- <cd:constant type="vse"/>
- </cd:parameter>
- <cd:parameter name="hranicestranky">
- <cd:constant type="cd:list"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylcisla">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="styltextu">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylstranky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:threearguments"/>
- </cd:parameter>
- <cd:parameter name="ciselnyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="textovyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="strankovyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="interakce">
- <cd:constant type="cd:sectionnumber"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="cislostranky"/>
- <cd:constant type="vse"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="popisek">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="cislostranky">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="cislonadpisu">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="cd:sectionnumber">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zarovnejtitul">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="predel">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="zadny"/>
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- <cd:constant type="3"/>
- <cd:constant type="..."/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- <cd:parameter name="maxsirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplistalternative" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="setuplistalternative"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="no">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- <!-- cd:constant type="cd:name"/ -->
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="natahnout">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definecombinedlist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="definujkombinovanyseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:list"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavkombinovanyseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcombinedlist" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="nastavkombinovanyseznam"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="uroven">
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- <cd:constant type="3"/>
- <cd:constant type="4"/>
- <cd:constant type="cd:section"/>
- <cd:constant type="aktualni"/>
- </cd:parameter>
- <cd:inherit name="nastavseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placecombinedlist" variant="2" generated="yes" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="umisti"/>
- <cd:variable value="combinedlist"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavkombinovanyseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="completecombinedlist" generated="yes" file="core-lst.tex">
- <cd:sequence>
- <cd:string value="uplny"/>
- <cd:variable value="combinedlist"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavkombinovanyseznam" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupnumbering" file="core-num.tex">
- <cd:sequence>
- <cd:string value="nastavcislovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupformulas" file="core-mat.tex">
- <cd:sequence>
- <cd:string value="nastavrovnice"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="nastred"/>
- </cd:parameter>
- <cd:parameter name="strut">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="standardni"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:constant type="flushleft"/>
- <cd:constant type="flushright"/>
- <cd:constant type="nastred"/>
- <cd:constant type="center"/>
- </cd:parameter>
- <cd:parameter name="levyokraj">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravyokraj">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="mezerapred">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="publication" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="publikace"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppublications" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavpublikace"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="apa"/>
- <cd:constant type="normalni"/>
- </cd:parameter>
- <cd:inherit name="nastavvycty" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplines" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="nastavradky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="odsazovani">
- <cd:resolve name="indenting"/>
- </cd:parameter>
- <cd:parameter name="mezera">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="lines" type="environment">
- <cd:sequence>
- <cd:string value="lines"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupparagraphnumbering" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="nastavcislovaniodstavcu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="reset"/>
- <cd:constant type="radek"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplinenumbering" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="nastavcislovaniradku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="start">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="krok">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="dotextu"/>
- <cd:constant type="naokraji"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="odkazujici">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="linenumbering" type="environment" file="page-lin.tex"> <!-- mkii/mkiv -->
- <cd:sequence>
- <cd:string value="linenumbering"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="pokracovat"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="line" type="environment">
- <cd:sequence>
- <cd:string value="line"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="someline" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="nejakyradek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="inline" file="page-lin.tex">
- <cd:sequence>
- <cd:string value="vradku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinmargin" file="page-mar.tex">
- <cd:sequence>
- <cd:string value="nastavmarginalie"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="cd:number"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="obe"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="radek">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="oddelovac">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stack">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppagenumber" file="page-num.tex">
- <cd:sequence>
- <cd:string value="nastavcislostrany"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="cislo">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="drzet"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsubpagenumber" file="page-num.tex">
- <cd:sequence>
- <cd:string value="nastavpodcislostrany"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="zpusob">
- <cd:constant type="bytext"/>
- <cd:constant type="bycd:section"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupblank" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="nastavpreskok"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="normalni" default="yes"/>
- <cd:constant type="implicitni"/>
- <cd:constant type="standardni"/>
- <cd:constant type="radek"/>
- <cd:constant type="pulradku"/>
- <cd:constant type="cd:dimension"/>
- <cd:constant type="velke"/>
- <cd:constant type="stredni"/>
- <cd:constant type="male"/>
- <cd:constant type="fixne"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="globalne"/>
- <cd:constant type="neznamy"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineblank" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="definujpreskok"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:inherit name="nastavpreskok" n="1"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definepapersize" file="page-lay.tex">
- <cd:sequence>
- <cd:string value="definujvelikostpapiru"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="meritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppaper" file="page-lay.tex">
- <cd:sequence>
- <cd:string value="setuppaper"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="papir">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="nx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ny">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="svrchnimezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zpetnamezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="max"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuppapersize" file="page-lay.tex">
- <cd:sequence>
- <cd:string value="nastavvelikostpapiru"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="A3"/>
- <cd:constant type="A4" default="yes"/>
- <cd:constant type="A5"/>
- <cd:constant type="A6"/>
- <cd:constant type="letter"/>
- <cd:constant type="..."/>
- <cd:constant type="CD"/>
- <cd:constant type="cd:name"/>
- <cd:constant type="nasirku"/>
- <cd:constant type="zrcadleno"/>
- <cd:constant type="otoceno"/>
- <cd:constant type="90"/>
- <cd:constant type="180"/>
- <cd:constant type="270"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="negativ"/>
- <cd:inherit name="nastavvelikostpapiru" n="1"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuparranging" file="page-imp.tex">
- <cd:sequence>
- <cd:string value="nastavusporadani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="zablokovat"/>
- <cd:constant type="2*16"/>
- <cd:constant type="2*8"/>
- <cd:constant type="2*4"/>
- <cd:constant type="2*2"/>
- <cd:constant type="2**2"/>
- <cd:constant type="2*2*4"/>
- <cd:constant type="2*4*2"/>
- <cd:constant type="2UP"/>
- <cd:constant type="2DOWN"/>
- <cd:constant type="2SIDE"/>
- <cd:constant type="2TOP"/>
- <cd:constant type="zrcadleno"/>
- <cd:constant type="otoceno"/>
- <cd:constant type="dvoustranny"/>
- <cd:constant type="negativ"/>
- <cd:constant type="pozadi"/>
- <cd:constant type="90"/>
- <cd:constant type="180"/>
- <cd:constant type="270"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showprint" file="page-run.tex"> <!-- page-lay.tex -->
- <cd:sequence>
- <cd:string value="ukazvytisk"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:inherit name="nastavvelikostpapiru" n="1"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:inherit name="nastavvelikostpapiru" n="2"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:inherit name="nastavvzhled" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definelogo" file="page-log.tex">
- <cd:sequence>
- <cd:string value="definujlogo"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="vrsek"/>
- <cd:constant type="zahlavi"/>
- <cd:constant type="upati"/>
- <cd:constant type="spodek"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="zadny"/>
- <cd:constant type="stranka"/>
- <cd:constant type="levahrana"/>
- <cd:constant type="levyokraj"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="pravyokraj"/>
- <cd:constant type="pravahrana"/>
- </cd:keywords>
- <cd:assignments n="4" list="yes">
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placelogos" file="page-log.tex">
- <cd:sequence>
- <cd:string value="umistiloga"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupwhitespace">
- <cd:sequence>
- <cd:string value="nastavbilamista"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="zadny" default="yes"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="radek"/>
- <cd:constant type="fixne"/>
- <cd:constant type="fixuj"/>
- <cd:constant type="cd:dimension"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupindenting">
- <cd:sequence>
- <cd:string value="nastavodsazovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:resolve name="indenting"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definesectionblock" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="definujbloksekce"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:inherit name="nastavbloksekce" n="1"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavbloksekce" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsectionblock" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="nastavbloksekce"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="cislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="ano"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definesection" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="definujsekci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsection" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="nastavsekci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="konverze">
- <cd:constant type="cisla"/>
- <cd:constant type="pismena"/>
- <cd:constant type="Pismena"/>
- <cd:constant type="rimskecislice"/>
- <cd:constant type="Rimskecislice"/>
- </cd:parameter>
- <cd:parameter name="predchozicislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuphead" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="nastavnadpis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:section"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="styltextu">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylcisla">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="barvatextu">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="barvacisla">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="cislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="vlastnicislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- <cd:parameter name="pokracovat">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zahlavi">
- <cd:constant type="zadny"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="zadny"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="upati">
- <cd:constant type="zadny"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="normalni"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="nastred"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="zaveseni">
- <cd:constant type="zadny"/>
- <cd:constant type="siroky"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="radek"/>
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:twoarguments"/>
- </cd:parameter>
- <cd:parameter name="ciselnyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="textovyprikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="deepnumbercommand">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="deeptextcommand">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="+"/>
- <cd:constant type="-"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="umistihlavicku">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prazdne"/>
- </cd:parameter>
- <cd:parameter name="zvysujicicislo">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="cd:list"/>
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="resetnumber">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="soubor">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- <cd:parameter name="textmarginalie">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:inherit name="nastavnadpisy" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupheadnumber" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="nastavcislonadpisu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:section"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:number"/>
- <cd:constant type="+cd:number"/>
- <cd:constant type="-cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="headnumber">
- <cd:sequence>
- <cd:string value="cislonadpisu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:section"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="determineheadnumber" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="stanovcislonadpisu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:section"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="currentheadnumber" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="aktualnicislonadpisu"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="nextsection" generated="yes" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="dalsi"/>
- <cd:variable value="sekce"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="definehead" file="core-sec.tex">
- <cd:sequence>
- <cd:string value="definujnadpis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:section"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupitemgroup" file="core-itm.tex">
- <cd:sequence>
- <cd:string value="setupitemgroup"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:number"/>
- <cd:constant type="kazdy"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes" list="yes">
- <cd:constant type="standardni" default="yes"/>
- <cd:constant type="siroky"/>
- <cd:constant type="semknuto"/>
- <cd:constant type="zhustene"/>
- <cd:constant type="rozbalene"/>
- <cd:constant type="zadnabila"/>
- <cd:constant type="pred"/>
- <cd:constant type="po"/>
- <cd:constant type="predel"/>
- <cd:constant type="spojeno"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="autouvod"/>
- <cd:constant type="uvolnene"/>
- <cd:constant type="opakovat"/>
- <cd:constant type="cd:section"/>
- <cd:constant type="odstavec"/>
- <cd:constant type="dotextu"/>
- <cd:constant type="nahodny"/>
- <cd:constant type="reverse"/>
- </cd:keywords>
- <cd:assignments n="4" optional="yes" list="yes">
- <cd:parameter name="marginalie">
- <cd:constant type="ne"/>
- <cd:constant type="standardni"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="levyokraj">
- <cd:constant type="ne"/>
- <cd:constant type="standardni"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravyokraj">
- <cd:constant type="ne"/>
- <cd:constant type="standardni"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="polozky">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="start">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="predhlavickou">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pohlavicce">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylsnacky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylsymboly">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="predel">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="symzarovnani">
- <cd:resolve name="symalign"/>
- </cd:parameter>
- <cd:parameter name="odsadpristi">
- <cd:resolve name="indentnext"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="itemgroup" type="environment" generated="yes" file="core-itm.tex">
- <cd:sequence>
- <cd:variable value="itemgroup"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="a"/>
- <cd:constant type="A"/>
- <cd:constant type="KA"/>
- <cd:constant type="n"/>
- <cd:constant type="N"/>
- <cd:constant type="m"/>
- <cd:constant type="r"/>
- <cd:constant type="R"/>
- <cd:constant type="KR"/>
- <cd:constant type="cd:number"/>
- <cd:constant type="pokracovat"/>
- <cd:constant type="standardni" default="yes"/>
- <cd:constant type="siroky"/>
- <cd:constant type="semknuto"/>
- <cd:constant type="zhustene"/>
- <cd:constant type="predel"/>
- <cd:constant type="spojeno"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="uvod"/>
- <cd:constant type="sloupce"/>
- <cd:constant type="text"/>
- <cd:constant type="odstavec"/>
- <cd:constant type="opakovat"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="setupitemgroup" n="4"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="item" file="core-itm.tex">
- <cd:sequence>
- <cd:string value="polozka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="noitem" file="core-itm.tex">
- <cd:sequence>
- <cd:string value="polozka"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="but">
- <cd:sequence>
- <cd:string value="spodek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" interactive="exclusive"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="its">
- <cd:sequence>
- <cd:string value="pol"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="ran">
- <cd:sequence>
- <cd:string value="ran"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="head">
- <cd:sequence>
- <cd:string value="nadpis"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="mar">
- <cd:sequence>
- <cd:string value="okr"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="sub">
- <cd:sequence>
- <cd:string value="sub"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="sym" file="core-itm.tex">
- <cd:sequence>
- <cd:string value="sym"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nop">
- <cd:sequence>
- <cd:string value="nop"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="defineregister" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="definujrejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:plural"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupregister" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="nastavrejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="rovnovaha">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylstranky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="styltextu">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="indikator">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="propojeni">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="cd:sectionnumber">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="cd:section"/>
- <cd:constant type="lokalne"/>
- <cd:constant type="vse"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- <cd:constant type="..."/>
- <cd:constant type="n"/>
- <cd:constant type="a"/>
- <cd:constant type="..."/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="interakce">
- <cd:constant type="cislostranky"/>
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- <cd:parameter name="odkazujici">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="maxsirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="neznamyodkaz">
- <cd:constant type="prazdne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="A"/>
- <cd:constant type="B"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="obe"/>
- <cd:constant type="prvni"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="compress">
- <cd:constant type="ne"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- <cd:parameter name="deeptextcommand">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="register" generated="yes" file="core-reg.tex">
- <cd:sequence>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:index n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="startregister" generated="yes" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="start"/>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:index n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="writetoregister" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="zapisdorejstriku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:index n="3" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="coupledregister" generated="yes">
- <cd:sequence>
- <cd:string value="propojene"/>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:index n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="coupleregister" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="propojenyrejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placeregister" variant="1" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="umistirejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavrejstrik" n="3"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="seeregister" generated="yes">
- <cd:sequence>
- <cd:string value="viz"/>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:index n="3" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="completeregister" generated="yes" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="uplny"/>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="yes" optional="yes" list="yes">
- <cd:inherit name="nastavrejstrik" n="3"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placeregister" variant="2" generated="yes" file="core-reg.tex">
- <cd:sequence>
- <cd:string value="umisti"/>
- <cd:variable value="rejstrik"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="yes" optional="yes" list="yes">
- <cd:inherit name="nastavrejstrik" n="3"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definesynonyms" file="core-syn.tex">
- <cd:sequence>
- <cd:string value="definujsynonyma"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:plural"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:command"/>
- </cd:keywords>
- <cd:keywords n="4" optional="yes">
- <cd:constant type="cd:command"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsynonyms" file="core-syn.tex">
- <cd:sequence>
- <cd:string value="nastavsynonyma"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="styltextu">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="stylsynonyma">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="semknuto"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="vse"/>
- <cd:constant type="uzito"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:threearguments"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="synonym" generated="yes">
- <cd:sequence>
- <cd:variable value="synonym"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="completelistofsynonyms" generated="yes">
- <cd:sequence>
- <cd:string value="completelistof"/>
- <cd:variable value="synonyms"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="placelistofsynonyms" generated="yes">
- <cd:sequence>
- <cd:string value="placelistof"/>
- <cd:variable value="synonyms"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="loadsynonyms" generated="yes">
- <cd:sequence>
- <cd:string value="nacist"/>
- <cd:variable value="synonyms"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="definesorting" file="core-syn.tex">
- <cd:sequence>
- <cd:string value="definujtrideni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:plural"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes">
- <cd:constant type="cd:command"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsorting" file="core-syn.tex">
- <cd:sequence>
- <cd:string value="nastavtrideni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:oneargument"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="kriterium">
- <cd:constant type="vse"/>
- <cd:constant type="uzito"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="expanzen">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prikaz"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="sort" generated="yes">
- <cd:sequence>
- <cd:variable value="sort"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="completelistofsorts" generated="yes">
- <cd:sequence>
- <cd:string value="completelistof"/>
- <cd:variable value="sorts"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="placelistofsorts" generated="yes">
- <cd:sequence>
- <cd:string value="placelistof"/>
- <cd:variable value="sorts"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="loadsorts" generated="yes">
- <cd:sequence>
- <cd:string value="nacist"/>
- <cd:variable value="sorts"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="definemakeup" file="page-mak.tex">
- <cd:sequence>
- <cd:string value="definujupravu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:inherit name="nastavupravu" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="makeup" type="environment">
- <cd:sequence>
- <cd:string value="zlom"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavupravu" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupmakeup" file="page-mak.tex">
- <cd:sequence>
- <cd:string value="nastavupravu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="voffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="hoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="vlevo"/>
- <cd:constant type="ano"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="prikazy">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="oboustranne">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="prazdne"/>
- </cd:parameter>
- <cd:parameter name="statuszahlavi">
- <cd:constant type="normalni"/>
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="zadny"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="statusupati">
- <cd:constant type="normalni"/>
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="zadny"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="statustextu">
- <cd:constant type="normalni"/>
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="zadny"/>
- <cd:constant type="zadneznaceni"/>
- </cd:parameter>
- <cd:parameter name="statusvrsku">
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- </cd:parameter>
- <cd:parameter name="statusspodku">
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- </cd:parameter>
- <cd:parameter name="pagestate">
- <cd:constant type="stop"/>
- <cd:constant type="start"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="namemakeup" type="environment" generated="yes">
- <cd:sequence>
- <cd:variable value="jmeno"/>
- <cd:string value="zlom"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="version">
- <cd:sequence>
- <cd:string value="verze"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="finalni" default="yes"/>
- <cd:constant type="koncept"/>
- <cd:constant type="docasne"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="currentdate">
- <cd:sequence>
- <cd:string value="aktualnidatum"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:inherit name="datum" n="2"/> <!-- or vice versa :) -->
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="date" file="core-con.tex">
- <cd:sequence>
- <cd:string value="datum"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes"> <!-- if not given, current date is used -->
- <cd:parameter name="d">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="m">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="y">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="den"/>
- <cd:constant type="mesic"/>
- <cd:constant type="rok"/>
- <cd:constant type="vsedniden"/>
- <cd:constant type="d"/>
- <cd:constant type="m"/>
- <cd:constant type="y"/> <!-- also j -->
- <cd:constant type="w"/>
- <cd:constant type="dd"/>
- <cd:constant type="mm"/>
- <cd:constant type="yy"/> <!-- also jj -->
- <cd:constant type="mezera"/>
- <cd:constant type="--"/>
- <cd:constant type="day+"/>
- <cd:constant type="d+"/>
- <cd:constant type="dd+"/>
- <cd:constant type="znacka"/>
- <cd:constant type="cd:text"/> <!-- any other text -->
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="referraldate" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="odkaznadatum"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="indenting" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="odsazovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:resolve name="indenting"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="noindenting" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zadneodsazovani"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="blank" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="preskoc"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke" default="yes"/>
- <cd:constant type="zadnabila"/>
- <cd:constant type="zpet"/>
- <cd:constant type="bily"/>
- <cd:constant type="zablokovat"/>
- <cd:constant type="sila"/>
- <cd:constant type="reset"/>
- <cd:constant type="radek"/>
- <cd:constant type="pulradku"/>
- <cd:constant type="cd:formula"/>
- <cd:constant type="fixne"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="zadny"/>
- <cd:constant type="vzdy"/>
- <cd:constant type="vnejsi"/>
- <cd:constant type="spojeno"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="packed" type="environment" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="zhustene"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="prazdny"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="unpacked" type="environment">
- <cd:sequence>
- <cd:string value="unpacked"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="linecorrection" type="environment">
- <cd:sequence>
- <cd:string value="linecorrection"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="correctwhitespace" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="korekcebilehomista"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="postponing" type="environment">
- <cd:sequence>
- <cd:string value="postponing"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="local" type="environment">
- <cd:sequence>
- <cd:string value="lokalne"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="narrower" type="environment">
- <cd:sequence>
- <cd:string value="narrower"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred" default="yes"/>
- <cd:constant type="vpravo"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="hiding" type="environment">
- <cd:sequence>
- <cd:string value="hiding"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupalign" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="nastavzarovnani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="sirka"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="uvnitr"/>
- <cd:constant type="vnejsi"/>
- <cd:constant type="siroce"/>
- <cd:constant type="siroky"/>
- <cd:constant type="vyska"/>
- <cd:constant type="spodek"/>
- <cd:constant type="radek"/>
- <cd:constant type="reset"/>
- <cd:constant type="visici"/>
- <cd:constant type="nothanging"/>
- <cd:constant type="hyphenated"/>
- <cd:constant type="nothyphenated"/>
- <cd:constant type="lesshyphenation"/>
- <cd:constant type="morehyphenation"/>
- <cd:constant type="novy"/>
- <cd:constant type="old"/>
- <cd:constant type="normalni"/>
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- <cd:constant type="flushleft"/>
- <cd:constant type="flushright"/>
- <cd:constant type="flushouter"/>
- <cd:constant type="flushinner"/>
- <cd:constant type="center"/>
- <cd:constant type="hz"/>
- <cd:constant type="nohz"/>
- <cd:constant type="mezerovani"/>
- <cd:constant type="nospacing"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- <cd:constant type="natahnout"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
-
- <cd:command name="alignment" type="environment" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="alignment"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:inherit name="nastavzarovnani" n="1"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupspacing">
- <cd:sequence>
- <cd:string value="nastavradkovani"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="siroky"/>
- <cd:constant type="zhustene"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptolerance" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="nastavtoleranci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="horizontalne"/>
- <cd:constant type="vertikalne"/>
- <cd:constant type="natahnout"/>
- <cd:constant type="mezera"/>
- <cd:constant type="velmistriktni" default="yes"/>
- <cd:constant type="striktni"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="pagetype" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="typstrany"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="processpage" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="zpracujstranu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="ano" default="yes"/>
- <cd:constant type="ne"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="couplepage" file="page-ini.tex">
- <cd:sequence>
- <cd:string value="parovastrana"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="volba">
- <cd:constant type="dvoustranny"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="position" file="page-lyr.tex">
- <cd:sequence>
- <cd:string value="pozice"/>
- </cd:sequence>
- <cd:arguments>
- <cd:position n="1" list="yes"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupscreens" file="core-rul.tex">
- <cd:sequence>
- <cd:string value="nastavrastr"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="metoda">
- <cd:constant type="tecka"/>
- <cd:constant type="linka"/>
- <cd:constant type="externi"/>
- </cd:parameter>
- <cd:parameter name="rozliseni">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="rastr">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbackgrounds" file="page-bck.tex">
- <cd:sequence>
- <cd:string value="nastavpozadi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vrsek"/>
- <cd:constant type="zahlavi"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="upati"/>
- <cd:constant type="spodek"/>
- <cd:constant type="stranka"/>
- <cd:constant type="papir"/>
- <cd:constant type="levastranka"/>
- <cd:constant type="pravastranka"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="levahrana"/>
- <cd:constant type="levyokraj"/>
- <cd:constant type="cd:text"/>
- <cd:constant type="pravyokraj"/>
- <cd:constant type="pravahrana"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="cd:repeat"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="buffer" type="environment" generated="yes" file="core-buf.tex">
- <cd:sequence>
- <cd:variable value="buffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="buffer" type="environment" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="buffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="getbuffer">
- <cd:sequence>
- <cd:string value="ziskejbuffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="typebuffer" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="typebuffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definebuffer" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="definujbuffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbuffer" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="nastavbuffer"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="odstavec">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineblock" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="definujblok"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="nomoreblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="zadnedalsibloky"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="hideblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="schovejbloky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="keepblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="zachovejbloky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="vse"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="uzijbloky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="processblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="zpracujbloky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="bypassblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="bypassblocks"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="forceblocks">
- <cd:sequence>
- <cd:string value="forceblocks"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="selectblocks" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="vyberbloky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes">
- <cd:parameter name="kriterium">
- <cd:constant type="vse"/>
- <cd:constant type="cd:section"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupblock" file="core-buf.tex">
- <cd:sequence>
- <cd:string value="nastavblok"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vnitrni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="soubor">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="formula" type="environment" generated="yes">
- <cd:sequence>
- <cd:variable value="rovnice"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="mathematics" file="supp-mat.tex">
- <cd:sequence>
- <cd:string value="matematika"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placeformula" file="core-mat.tex">
- <cd:sequence>
- <cd:string value="umistirovnici"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2" optional="yes"/>
- <cd:displaymath n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placesubformula" file="core-mat.tex">
- <cd:sequence>
- <cd:string value="umistipodrovnici"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" optional="yes" list="yes"/>
- <cd:content n="2" optional="yes"/>
- <cd:displaymath n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placefloat" generated="yes" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="umisti"/>
- <cd:variable value="plvouciobjekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="zde" default="yes"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="marginalie"/>
- <cd:constant type="levyokraj"/>
- <cd:constant type="pravyokraj"/>
- <cd:constant type="levahrana"/>
- <cd:constant type="pravahrana"/>
- <cd:constant type="innermargin"/>
- <cd:constant type="outermargin"/>
- <cd:constant type="inneredge"/>
- <cd:constant type="outeredge"/>
- <cd:constant type="uvnitr"/>
- <cd:constant type="vnejsi"/>
- <cd:constant type="radek"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="nizko"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="stranka"/>
- <cd:constant type="levastranka"/>
- <cd:constant type="pravastranka"/>
- <cd:constant type="naproti"/>
- <cd:constant type="vzdy"/>
- <cd:constant type="auto"/>
- <cd:constant type="sila"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="reset"/>
- <cd:constant type="radek"/>
- <cd:constant type="vyska"/>
- <cd:constant type="podlehloubky"/>
- <cd:constant type="split"/>
- <cd:constant type="90"/>
- <cd:constant type="180"/>
- <cd:constant type="270"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes" list="yes"/>
- <cd:content n="3"/>
- <cd:content n="4"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="reservefloat" generated="yes">
- <cd:sequence>
- <cd:string value="rezervovat"/>
- <cd:variable value="plvouciobjekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="ramecek">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- </cd:assignments>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:reference n="3" optional="yes" list="yes"/>
- <cd:content n="4"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefloat" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="definujplvouciobjekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:singular"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:plural"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfloat" file="page-flt.tex">
- <cd:sequence>
- <cd:string value="nastavplvouciobjekt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="maxvyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="maxsirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="minsirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="implicitni">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="hranicestranky">
- <cd:constant type="cd:list"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostlevehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenostpravehookraje">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="floattext" type="environment" generated="yes">
- <cd:sequence>
- <cd:variable value="plvouciobjekt"/>
- <cd:string value="text"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="nastred"/>
- <cd:constant type="nizko"/>
- <cd:constant type="offset"/>
- <cd:constant type="vysoko"/>
- </cd:keywords>
- <cd:reference n="2" optional="yes"/>
- <cd:content n="3"/>
- <cd:content n="4"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placelistoffloats" generated="yes">
- <cd:sequence>
- <cd:string value="placelistof"/>
- <cd:variable value="floats"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="completelistoffloats" generated="yes">
- <cd:sequence>
- <cd:string value="completelistof"/>
- <cd:variable value="floats"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="referral" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="odkaz"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="bet">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="ken">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="dat">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="van">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="aan">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="ref">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="selectpaper">
- <cd:sequence>
- <cd:string value="vyberpapir"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="rodina">
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="couplepaper">
- <cd:sequence>
- <cd:string value="dvoustrannypapir"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="chem" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="chem"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fraction" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="zlomek"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="periods" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="tecky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="items">
- <cd:sequence>
- <cd:string value="polozky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavpolozky" n="1"/>
- </cd:assignments>
- <cd:content n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupitems" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavpolozky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="naokraji"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="1"/>
- <cd:constant type="2"/>
- <cd:constant type="..."/>
- <cd:constant type="n"/>
- <cd:constant type="a"/>
- <cd:constant type="..."/>
- <cd:constant type="cd:text"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- <cd:constant type="neznamy"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="quotation" type="environment" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="citace"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="nastred" default="yes"/>
- <cd:constant type="vpravo"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="quotation" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="citace"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="quote" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="citovat"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupquote" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavcitaci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="cd:text"/>
- <cd:constant type="marginalie"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineparagraphs" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="definujodstavce"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="linka">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="prizpusobive"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vnitrni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="tolerance">
- <cd:constant type="velmistriktni"/>
- <cd:constant type="striktni"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- <cd:constant type="natahnout"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="paragraph" generated="yes">
- <cd:sequence>
- <cd:variable value="odstavec"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="paragraph" type="environment" generated="yes">
- <cd:sequence>
- <cd:variable value="odstavec"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupparagraphs" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavodstavce"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:number"/>
- <cd:constant type="kazdy"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="tolerance">
- <cd:constant type="velmistriktni"/>
- <cd:constant type="striktni"/>
- <cd:constant type="tolerantni"/>
- <cd:constant type="velmitolerantni"/>
- <cd:constant type="natahnout"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vnitrni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="prikaz">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="linka">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptab" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavtab"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="vzor">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stylhlavicky">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="tab">
- <cd:sequence>
- <cd:string value="tab"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:nothing n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="document" type="environment">
- <cd:sequence>
- <cd:string value="document"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="labels">
- <cd:sequence>
- <cd:string value="popisky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definetabulate" file="core-tbl.tex">
- <cd:sequence>
- <cd:string value="definujtabelaci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="tabulate" type="environment" generated="yes">
- <cd:sequence>
- <cd:variable value="tabelator"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavexterniobrazy" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptabulate" file="core-tbl.tex">
- <cd:sequence>
- <cd:string value="nastavtabelaci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="jednotka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="odsazovani">
- <cd:resolve name="indenting"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vnitrni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="EQ">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="barvalinky">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="prazdny"/>
- <cd:constant type="mrizka"/>
- <cd:constant type="podlehloubky"/>
- <cd:constant type="cd:dimension"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="linka">
- <cd:constant type="normalni"/>
- <cd:constant type="radek"/>
- </cd:parameter>
- <cd:parameter name="split">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuptables" file="core-tab.tex">
- <cd:sequence>
- <cd:string value="nastavtabulky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="vzdalenost">
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="HL">
- <cd:constant type="cd:number"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="VL">
- <cd:constant type="cd:number"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:number"/>
- <cd:constant type="strut"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:number"/>
- <cd:constant type="strut"/>
- </cd:parameter>
- <cd:parameter name="tloustkalinky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barvalinky">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="prikazy">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="pozadi">
- <cd:constant type="rastr"/>
- <cd:constant type="barevne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="rastrpozadi">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="barvapozadi">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="table" type="environment">
- <cd:sequence>
- <cd:string value="table"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="tables" type="environment">
- <cd:sequence>
- <cd:string value="tables"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definetabletemplate" file="core-tab.tex">
- <cd:sequence>
- <cd:string value="definujsablonutabulky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="4" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useexternalfiles" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="uzijexternisoubory"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- <cd:parameter name="soubor">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useexternalfile" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="uzijexternisoubor"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- <cd:assignments n="4" list="yes">
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useexternalfigure" file="core-fig.tex">
- <cd:sequence>
- <cd:string value="uzijexterniobraz"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- <cd:keywords n="3" optional="yes">
- <cd:constant type="cd:name"/> <!-- parent -->
- </cd:keywords>
- <cd:assignments n="4" optional="yes" list="yes">
- <cd:inherit name="nastavexterniobrazy" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="externalfigure" file="core-fig.tex">
- <cd:sequence>
- <cd:string value="externiobraz"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavexterniobrazy" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupexternalfigures" file="core-fig.tex">
- <cd:sequence>
- <cd:string value="nastavexterniobrazy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1">
- <cd:parameter name="meritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ymeritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ymeritko">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="faktor">
- <cd:constant type="max"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- </cd:parameter>
- <cd:parameter name="sfaktor">
- <cd:constant type="cd:number"/>
- <cd:constant type="max"/>
- <cd:constant type="siroky"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="vfaktor">
- <cd:constant type="cd:number"/>
- <cd:constant type="max"/>
- <cd:constant type="siroky"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="ramecek">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="prednastaveni">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="obrazovka">
- <cd:constant type="cd:file"/>
- </cd:parameter>
- <cd:parameter name="nahled">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="opakovat">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="objekt">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="typ">
- <cd:constant type="eps"/>
- <cd:constant type="mps"/>
- <cd:constant type="pdf"/>
- <cd:constant type="tif"/>
- <cd:constant type="png"/>
- <cd:constant type="jpg"/>
- <cd:constant type="mov"/>
- <cd:constant type="cd:tex"/>
- </cd:parameter>
- <cd:parameter name="metoda">
- <cd:constant type="eps"/>
- <cd:constant type="mps"/>
- <cd:constant type="pdf"/>
- <cd:constant type="tif"/>
- <cd:constant type="png"/>
- <cd:constant type="jpg"/>
- <cd:constant type="mov"/>
- <cd:constant type="cd:tex"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="ramecek"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="test"/>
- </cd:parameter>
- <cd:parameter name="ramecky">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="ymax">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="xmax">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="adresar">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="lokalne"/>
- <cd:constant type="globalne"/>
- <cd:constant type="implicitni"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="maxsirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="maxvyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="konverze">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="prefix">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showexternalfigures" file="core-fig.tex">
- <cd:sequence>
- <cd:string value="ukazexterniobrazy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useexternalsoundtrack" file="core-fig.tex">
- <cd:sequence>
- <cd:string value="uzijexternizvuk"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="name" file="syst-gen.tex">
- <cd:sequence>
- <cd:string value="name"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="legend" type="environment">
- <cd:sequence>
- <cd:string value="legend"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="dve"/>
- </cd:keywords>
- <cd:tex n="2" command="leg"/>
- <cd:nothing n="3"/>
- <cd:nothing n="4" separator="backslash"/>
- <cd:nothing n="5" separator="backslash"/>
- <cd:tex n="6" separator="backslash" command="leg"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fact" type="environment">
- <cd:sequence>
- <cd:string value="fakt"/>
- </cd:sequence>
- <cd:arguments>
- <cd:tex n="1" command="fact"/>
- <cd:nothing n="2"/>
- <cd:nothing n="3" separator="backslash"/>
- <cd:nothing n="4" separator="backslash"/>
- <cd:tex n="5" separator="backslash" command="fact"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="rotate" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="otocit"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavotoceni" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuprotate" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavotoceni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="rotace">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="normalni"/>
- <cd:constant type="vysoko"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="siroky"/>
- <cd:constant type="podlehloubky"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="mirror" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="zrcadlit"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="scale" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="meritko"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:parameter name="sx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="sy">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- </cd:assignments>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupcombinations" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="nastavspojeni"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vrsek"/>
- <cd:constant type="nastred"/>
- <cd:constant type="spodek"/>
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="combination" type="environment">
- <cd:sequence>
- <cd:string value="combination"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:matrix"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placesidebyside" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="umistivedlesebe"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placeontopofeachother" file="core-mis.tex">
- <cd:sequence>
- <cd:string value="umistinadsebe"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overlay" type="environment">
- <cd:sequence>
- <cd:string value="overlay"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="overview" type="environment">
- <cd:sequence>
- <cd:string value="overview"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinteractionscreen" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavinterakcniobrazovku"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="max"/>
- </cd:parameter>
- <cd:parameter name="zpetnamezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="svrchnimezera">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="horoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsethlavicky">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="max"/>
- <cd:constant type="prizpusobive"/>
- <cd:constant type="dvoustranny"/>
- <cd:constant type="zalozka"/>
- </cd:parameter>
- <cd:parameter name="prodleva">
- <cd:constant type="cd:number"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="screen" file="core-int.tex">
- <cd:sequence>
- <cd:string value="obrazovka"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setuppagetransitions" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavprechodstrany"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="reset"/>
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinteraction" file="core-nav.tex">
- <cd:sequence>
- <cd:string value="nastavinterakci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="menu">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- <cd:parameter name="stranka">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="klik">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="split">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="obrazovka">
- <cd:constant type="novy"/>
- </cd:parameter>
- <cd:parameter name="otevriakci">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="zavriakci">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="akceotevrenistranky">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="akcezavrenistranky">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="pocitat">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="strut">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="kontrastnibarva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="sadasymbolu">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="titul">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="podtitulek">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="autor">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="datum">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="keyword">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <!-- maybe this will move elsewhere -->
- <cd:parameter name="fieldlayer">
- <cd:constant type="auto"/>
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinteractionmenu" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavinterakcnimenu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vlevo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="vpravo">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="stredni">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- <cd:constant type="zadny"/>
- <cd:constant type="lokalne"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="kontrastnibarva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="prekryv"/>
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="stejnastranka">
- <cd:constant type="ano"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="ne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="neznamyodkaz">
- <cd:constant type="ano"/>
- <cd:constant type="prazdne"/>
- <cd:constant type="ne"/>
- <cd:constant type="zadny"/>
- </cd:parameter>
- <cd:parameter name="levyoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pravyoffset">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetvrsku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="offsetspodku">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="position">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/> <!-- maybe not all parameters from framed -->
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineinteractionmenu" variant="1" file="core-int.tex">
- <cd:sequence>
- <cd:string value="definujinterakcnimenu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive" list="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavinterakcnimenu" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineinteractionmenu" variant="2" file="core-int.tex">
- <cd:sequence>
- <cd:string value="definujinterakcnimenu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavinterakcnimenu" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="interactionmenu" type="environment">
- <cd:sequence>
- <cd:string value="interaktivnimenu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="disableinteractionmenu" file="core-int.tex">
- <cd:sequence>
- <cd:string value="zablokujinterakcnimenu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="vrsek"/>
- <cd:constant type="spodek"/>
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:reference n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useexternaldocument" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="uzijexternidokument"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="soubor"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="useURL" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="uzijURL"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="soubor"/>
- </cd:keywords>
- <cd:keywords n="4">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="coupledocument" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="propojenydokument"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="soubor"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="from" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="zref"/>
- </cd:sequence>
- <cd:arguments>
- <cd:reference n="1" interactive="exclusive"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="interactionbar">
- <cd:sequence>
- <cd:string value="interakcnilista"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:inherit name="nastavinterakcnilistu" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="interactionbuttons" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="interakcnitlacitka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" optional="yes" list="yes">
- <cd:inherit name="nastavinterakcnilistu" n="1"/>
- </cd:assignments>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupinteractionbar" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavinterakcnilistu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="alternativa">
- <cd:constant type="a"/>
- <cd:constant type="b"/>
- <cd:constant type="c"/>
- <cd:constant type="d"/>
- <cd:constant type="e"/>
- <cd:constant type="f"/>
- <cd:constant type="g"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="vyska"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="vyska"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="hloubka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="krok">
- <cd:constant type="cd:number"/>
- <cd:constant type="male"/>
- <cd:constant type="stredni"/>
- <cd:constant type="velke"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="synchronize" file="core-int.tex">
- <cd:sequence>
- <cd:string value="synchronizovat"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="synchronization" type="environment">
- <cd:sequence>
- <cd:string value="synchronization"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupsynchronizationbar" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavsynchronizacnilistu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="stranka"/>
- <cd:constant type="lokalne"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- <cd:constant type="vyska"/>
- <cd:constant type="prizpusobive"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="synchronizationbar" file="core-int.tex">
- <cd:sequence>
- <cd:string value="synchronizacnilista"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="alternativa">
- <cd:constant type="stranka"/>
- <cd:constant type="lokalne"/>
- </cd:parameter>
- <cd:inherit name="nastavsynchronizacnilistu" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupsynchronization" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavsynchronizaci"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineprofile" file="core-int.tex">
- <cd:sequence>
- <cd:string value="definujprofil"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupprofiles" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavprofily"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="volba">
- <cd:constant type="test"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="profile" type="environment">
- <cd:sequence>
- <cd:string value="profile"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="followprofile" file="core-int.tex">
- <cd:sequence>
- <cd:string value="dodrzujprofil"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="exclusive"/>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placebookmarks" file="core-int.tex">
- <cd:sequence>
- <cd:string value="umistizalozky"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- <cd:constant type="vse"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="bookmark" file="core-int.tex">
- <cd:sequence>
- <cd:string value="zalozka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="version" type="environment">
- <cd:sequence>
- <cd:string value="verze"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive" list="yes">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupversions" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavverze"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="cislo">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="markversion" file="core-int.tex">
- <cd:sequence>
- <cd:string value="oznacverzi"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="selectversion" file="core-int.tex">
- <cd:sequence>
- <cd:string value="vyberverzi"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="defineversion" file="core-int.tex">
- <cd:sequence>
- <cd:string value="definujverzi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:number"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="followversion" file="core-int.tex">
- <cd:sequence>
- <cd:string value="dodrzujverzi"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="exclusive"/>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="followprofileversion" file="core-int.tex">
- <cd:sequence>
- <cd:string value="dodrzujverziprofilu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="exclusive"/>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="defineprogram" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="definujprogram"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupprograms" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="nastavprogramy"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" list="yes">
- <cd:parameter name="adresar">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="program" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="program"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="figure" type="environment">
- <cd:sequence>
- <cd:string value="figure"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" interactive="exclusive">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:file"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:parameter name="faktor">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ramecek">
- <cd:constant type="zap"/>
- <cd:constant type="vyp"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <!-- referring*figure skipped -->
-
- <!-- marking*figure skipped -->
-
- <!-- remark skipped -->
-
- <cd:command name="goto" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="jdina"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="exclusive"/>
- <cd:content n="2" interactive="exclusive"/>
- <cd:reference n="3" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="gotobox" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="jdinabox"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1" interactive="exclusive"/>
- <cd:reference n="2" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="button" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="tlacitko"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" interactive="exclusive" optional="yes" list="yes">
- <cd:inherit name="nastavtlacitka" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- <cd:reference n="3" list="yes"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupbuttons" file="core-ref.tex">
- <cd:sequence>
- <cd:string value="nastavtlacitka"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <!-- menubutton skipped -->
-
- <cd:command name="setupcomment" file="core-int.tex">
- <cd:sequence>
- <cd:string value="nastavkomentar"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="titul">
- <cd:constant type="cd:text"/>
- </cd:parameter>
- <cd:parameter name="mezera">
- <cd:constant type="ano"/>
- <cd:constant type="ne"/>
- </cd:parameter>
- <cd:parameter name="symbol">
- <cd:constant type="normalni"/>
- <cd:constant type="Novy"/>
- <cd:constant type="Bublinka"/>
- <cd:constant type="Pridavek"/>
- <cd:constant type="Napoveda"/>
- <cd:constant type="Odstavec"/>
- <cd:constant type="Klavesa"/>
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="max"/>
- <cd:constant type="buffer"/>
- </cd:parameter>
- <cd:parameter name="marginalie">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="comment" type="environment">
- <cd:sequence>
- <cd:string value="komentar"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavkomentar" n="1"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="comment">
- <cd:sequence>
- <cd:string value="komentar"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="2" optional="yes" list="yes">
- <cd:inherit name="nastavkomentar" n="1"/>
- </cd:assignments>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="definujpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1"> <!-- name -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2"> <!-- type -->
- <cd:constant type="text"/>
- <cd:constant type="radek"/> <!-- equal to text -->
- <cd:constant type="push"/>
- <cd:constant type="check"/>
- <cd:constant type="radio"/>
- <cd:constant type="combo"/>
- <cd:constant type="choice"/> <!-- equal to combo -->
- <cd:constant type="popup"/> <!-- equal to combo -->
- </cd:keywords>
- <cd:keywords n="3"> <!-- group -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="4" list="yes"> <!-- optional for text? -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="5" optional="yes"> <!-- default -->
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definesubfield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="definujpodpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="3" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="copyfield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="kopirujpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="clonefield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="klonujpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="4" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="field" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="pole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fitfield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="prizpusobivepole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fillinfield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="vyplnovepole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="tooltip" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="bublinkovanapoveda"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes">
- <cd:constant type="vlevo"/>
- <cd:constant type="vpravo"/>
- <cd:constant type="nastred"/>
- </cd:keywords>
- <cd:content n="2"/>
- <cd:content n="3"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="showfields" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="ukazpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="logfields" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="zaznamovepole"/>
- </cd:sequence>
- </cd:command>
-
- <cd:command name="setupfield" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="nastavpole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="popisek"/>
- <cd:constant type="horizontalne"/>
- <cd:constant type="vertikalne"/>
- <cd:constant type="ramecek"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:inherit name="nastavvsechnapole" n="2"/>
- </cd:assignments>
- <cd:assignments n="4" list="yes"> </cd:assignments>
- <cd:assignments n="5" list="yes"> </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupfields" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="nastavvsechnapole"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1" list="yes"> <!-- TODO: if it's reset, only a single argument, no list -->
- <cd:constant type="reset"/>
- <cd:constant type="popisek"/>
- <cd:constant type="horizontalne"/>
- <cd:constant type="vertikalne"/>
- <cd:constant type="ramecek"/>
- </cd:keywords>
- <cd:assignments n="2" list="yes">
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="pred">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="po">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="barva">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="pismeno">
- <cd:resolve name="style"/>
- </cd:parameter>
- <cd:parameter name="zarovnani">
- <cd:resolve name="align"/>
- </cd:parameter>
- <cd:parameter name="volba">
- <cd:constant type="pouzeprocteni"/>
- <cd:constant type="pozadovane"/>
- <cd:constant type="chranene"/>
- <cd:constant type="tridene"/>
- <cd:constant type="nedostupne"/>
- <cd:constant type="skryte"/>
- <cd:constant type="tisknutelne"/>
- </cd:parameter>
- <cd:parameter name="klikuvnitr">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="klikvne">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="oblastuvnitr">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="oblastvne">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="klavesapo">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="formatovat">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="validovat">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="pocitat">
- <cd:constant type="cd:reference"/>
- </cd:parameter>
- <cd:parameter name="offsetpole">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="barvarameckupole">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="barvapozadipole">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:inherit name="nastavoramovani" n="2"/>
- </cd:assignments>
- <cd:assignments n="3" list="yes">
- <cd:inherit name="nastavvsechnapole" n="2"/>
- </cd:assignments>
- <cd:assignments n="4" list="yes">
- <cd:inherit name="nastavvsechnapole" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupforms" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="setupforms"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="metoda">
- <cd:constant type="HTML"/>
- <cd:constant type="FDF"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefieldstack" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="definujzasobnikpoli"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" list="yes">
- <cd:inherit name="nastavvsechnapole" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="fieldstack" file="core-fld.tex">
- <cd:sequence>
- <cd:string value="zasobnikpoli"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes" list="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="yes" list="yes">
- <cd:inherit name="nastavvsechnapole" n="2"/>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="clip" file="core-trf.tex">
- <cd:sequence>
- <cd:string value="orez"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" optional="yes" list="yes">
- <cd:inherit name="nastavorez" n="1"/>
- </cd:assignments>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupclipping" file="core-trf.tex">
- <cd:sequence>
- <cd:string value="nastavorez"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="status">
- <cd:constant type="start"/>
- <cd:constant type="stop"/>
- </cd:parameter>
- <cd:parameter name="n">
- <cd:constant type="cd:number" default="1"/>
- </cd:parameter>
- <cd:parameter name="nx">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="ny">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="x">
- <cd:constant type="cd:number" default="1"/>
- </cd:parameter>
- <cd:parameter name="y">
- <cd:constant type="cd:number" default="1"/>
- </cd:parameter>
- <cd:parameter name="sx">
- <cd:constant type="cd:number" default="1"/>
- </cd:parameter>
- <cd:parameter name="sy">
- <cd:constant type="cd:number" default="1"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="hoffset">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="voffset">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="offset">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="levyoffset">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="pravyoffset">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="offsetvrsku">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="offsetspodku">
- <cd:constant type="cd:dimension" default="0pt"/>
- </cd:parameter>
- <cd:parameter name="mp">
- <cd:constant type="cd:name" default=""/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="placelegend">
- <cd:sequence>
- <cd:string value="umistilegendu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:content n="1"/>
- <cd:content n="2"/>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setuplegend">
- <cd:sequence>
- <cd:string value="nastavlegendu"/>
- </cd:sequence>
- <cd:arguments>
- <cd:assignments n="1" list="yes">
- <cd:parameter name="n">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="vzdalenost">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="mezi">
- <cd:constant type="cd:command"/>
- </cd:parameter>
- <cd:parameter name="sirka">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="vyska">
- <cd:constant type="cd:dimension"/>
- </cd:parameter>
- <cd:parameter name="misto">
- <cd:constant type="vpravo"/>
- <cd:constant type="spodek"/>
- </cd:parameter>
- <cd:parameter name="zakladnifont">
- <cd:resolve name="bodyfont"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="setupstrut" file="core-spa.tex">
- <cd:sequence>
- <cd:string value="setupstrut"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="ano" default="yes"/>
- <cd:constant type="ne"/>
- <cd:constant type="kap"/>
- <cd:constant type="cd:text"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usetypescriptfile" file="type-ini.tex">
- <cd:sequence>
- <cd:string value="usetypescriptfile"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="usetypescript" file="type-ini.tex">
- <cd:sequence>
- <cd:string value="usetypescript"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definetypeface" file="type-ini.tex">
- <cd:sequence>
- <cd:string value="definetypeface"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="2">
- <cd:constant type="rm"/>
- <cd:constant type="ss"/>
- <cd:constant type="tt"/>
- <cd:constant type="mm"/>
- <cd:constant type="hw"/>
- <cd:constant type="cg"/>
- </cd:keywords>
- <cd:keywords n="3">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="4">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:keywords n="5" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="6" optional="yes">
- <cd:parameter name="features">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="rscale">
- <cd:constant type="cd:number"/>
- </cd:parameter>
- <cd:parameter name="encoding">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="text">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
- <cd:command name="definefontfeature" file="type-ini.tex">
- <cd:sequence>
- <cd:string value="definefontfeature"/>
- </cd:sequence>
- <cd:arguments>
- <cd:keywords n="1">
- <cd:constant type="cd:text"/>
- </cd:keywords>
- <cd:keywords n="2" optional="yes">
- <cd:constant type="cd:name"/>
- </cd:keywords>
- <cd:assignments n="3" optional="no">
- <cd:parameter name="compose">
- <cd:constant type="ne" default="yes"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- <cd:parameter name="mode">
- <cd:constant type="node"/>
- <cd:constant type="base" default="yes"/>
- </cd:parameter>
- <cd:parameter name="tlig">
- <cd:constant type="ne" default="yes"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- <cd:parameter name="trep">
- <cd:constant type="ne" default="yes"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- <cd:parameter name="script">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="language">
- <cd:constant type="cd:name"/>
- </cd:parameter>
- <cd:parameter name="..tag.."> <!-- can't use &gt; here, \showsetup gives an error -->
- <cd:constant type="ne" default="yes"/>
- <cd:constant type="ano"/>
- </cd:parameter>
- </cd:assignments>
- </cd:arguments>
- </cd:command>
-
-
-</cd:interface>
diff --git a/tex/context/interface/cont-de.xml b/tex/context/interface/cont-de.xml
index 6f3927090..73c823766 100644
--- a/tex/context/interface/cont-de.xml
+++ b/tex/context/interface/cont-de.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="stellefliesstextein" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="stellefliesstextein" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="stellefliesstextein" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="stellezeilenabstandein"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="passend"/>
</cd:parameter>
+ <cd:parameter name="methode">
+ <cd:constant type="normal"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tolerant"/>
<cd:constant type="sehrtolerant"/>
<cd:constant type="strecken"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="defineschriftsynonym"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-en.xml b/tex/context/interface/cont-en.xml
index d4c9283d9..1484bab20 100644
--- a/tex/context/interface/cont-en.xml
+++ b/tex/context/interface/cont-en.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="setupbodyfont" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="setupbodyfont" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="setupbodyfont" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="setupinterlinespace"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="fit"/>
</cd:parameter>
+ <cd:parameter name="method">
+ <cd:constant type="normal"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tolerant"/>
<cd:constant type="verytolerant"/>
<cd:constant type="stretch"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definefontsynonym"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-fr.xml b/tex/context/interface/cont-fr.xml
index 291574bff..0f07b22ee 100644
--- a/tex/context/interface/cont-fr.xml
+++ b/tex/context/interface/cont-fr.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="reglepolicecorps" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="reglepolicecorps" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="reglepolicecorps" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="regleespacementinterligne"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="adapte"/>
</cd:parameter>
+ <cd:parameter name="methode">
+ <cd:constant type="normal"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tolerant"/>
<cd:constant type="trestolerant"/>
<cd:constant type="etire"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definitsynonymepolice"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-it.xml b/tex/context/interface/cont-it.xml
index c59511b61..34b703d58 100644
--- a/tex/context/interface/cont-it.xml
+++ b/tex/context/interface/cont-it.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="impostafontdeltesto" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="impostafontdeltesto" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="impostafontdeltesto" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="impostainterlinea"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="adatta"/>
</cd:parameter>
+ <cd:parameter name="metodo">
+ <cd:constant type="normale"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tollerante"/>
<cd:constant type="moltotollerante"/>
<cd:constant type="dilata"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definiscisinonimofont"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-nl.xml b/tex/context/interface/cont-nl.xml
index 9daaadbd5..127c076f5 100644
--- a/tex/context/interface/cont-nl.xml
+++ b/tex/context/interface/cont-nl.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="stelkorpsin" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="stelkorpsin" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="stelkorpsin" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="stelinterliniein"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="passend"/>
</cd:parameter>
+ <cd:parameter name="methode">
+ <cd:constant type="normaal"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="soepel"/>
<cd:constant type="zeersoepel"/>
<cd:constant type="rek"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="gebruiktypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="gebruiktypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definieerfontsynoniem"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-pe.xml b/tex/context/interface/cont-pe.xml
index 4dcda95ed..a91800797 100644
--- a/tex/context/interface/cont-pe.xml
+++ b/tex/context/interface/cont-pe.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="بارگذاری‌قلم‌متن" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="بارگذاری‌قلم‌متن" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="بارگذاری‌قلم‌متن" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="بارگذاری‌فاصله‌بین‌خط"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="بیشترین"/>
<cd:constant type="پرکردن"/>
</cd:parameter>
+ <cd:parameter name="روش">
+ <cd:constant type="نرمال"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="بردبار"/>
<cd:constant type="خیلی‌بردبار"/>
<cd:constant type="بکش"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="استفاده‌پرونده‌دستخط‌تایپ"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="استفاده‌دستخط‌تایپ"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="تعریف‌مترادف‌قلم"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/cont-ro.xml b/tex/context/interface/cont-ro.xml
index 67d25d6f7..442fb18e1 100644
--- a/tex/context/interface/cont-ro.xml
+++ b/tex/context/interface/cont-ro.xml
@@ -441,12 +441,12 @@
</cd:sequence>
<cd:arguments>
<cd:keywords n="1">
- <cd:constant type="cd:name"/>
+ <cd:constant type="cd:name"/>
</cd:keywords>
<cd:keywords n="2">
<cd:inherit name="seteazafonttext" n="2"/>
</cd:keywords>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:inherit name="seteazafonttext" n="3"/>
</cd:keywords>
</cd:arguments>
@@ -463,7 +463,7 @@
<cd:keywords n="2">
<cd:inherit name="seteazafonttext" n="2"/>
</cd:keywords>
- <cd:keywords n="3">
+ <cd:keywords n="3">
<cd:constant type="cd:name"/>
</cd:keywords>
</cd:arguments>
@@ -4096,7 +4096,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
+ <cd:command name="setupinterlinespace2" variant="2" file="core-spa.tex">
<!-- attached a 2 to make this definition usable with \showsetup -->
<cd:sequence>
<cd:string value="seteazaspatiuinterliniar"/>
@@ -5647,6 +5647,10 @@
<cd:constant type="max"/>
<cd:constant type="ajustat"/>
</cd:parameter>
+ <cd:parameter name="metoda">
+ <cd:constant type="normal"/>
+ <cd:constant type="cd:name"/>
+ </cd:parameter>
</cd:assignments>
</cd:arguments>
</cd:command>
@@ -7083,6 +7087,8 @@
<cd:constant type="tolerant"/>
<cd:constant type="foartetolerant"/>
<cd:constant type="dilatat"/>
+ <cd:constant type="lefttoright"/>
+ <cd:constant type="righttoleft"/>
</cd:keywords>
</cd:arguments>
</cd:command>
@@ -9986,7 +9992,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescriptfile" file="type-ini.tex">
+ <cd:command name="usetypescriptfile" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescriptfile"/>
</cd:sequence>
@@ -9997,7 +10003,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="usetypescript" file="type-ini.tex">
+ <cd:command name="usetypescript" file="type-ini.tex">
<cd:sequence>
<cd:string value="usetypescript"/>
</cd:sequence>
@@ -10014,7 +10020,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definetypeface" file="type-ini.tex">
+ <cd:command name="definetypeface" file="type-ini.tex">
<cd:sequence>
<cd:string value="definetypeface"/>
</cd:sequence>
@@ -10056,7 +10062,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontfeature" file="type-ini.tex">
+ <cd:command name="definefontfeature" file="type-ini.tex">
<cd:sequence>
<cd:string value="definefontfeature"/>
</cd:sequence>
@@ -10098,7 +10104,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefonthandling" file="hand-ini.mkii">
+ <cd:command name="definefonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="definefonthandling"/>
</cd:sequence>
@@ -10138,7 +10144,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfonthandling" file="hand-ini.mkii">
+ <cd:command name="setupfonthandling" file="hand-ini.mkii">
<cd:sequence>
<cd:string value="setupfonthandling"/>
</cd:sequence>
@@ -10152,7 +10158,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="definefontsynonym" file="font-ini.tex">
+ <cd:command name="definefontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="definestesinonimfont"/>
</cd:sequence>
@@ -10180,7 +10186,7 @@
</cd:arguments>
</cd:command>
- <cd:command name="setupfontsynonym" file="font-ini.tex">
+ <cd:command name="setupfontsynonym" file="font-ini.tex">
<cd:sequence>
<cd:string value="setupfontsynonym"/>
</cd:sequence>
@@ -10199,7 +10205,7 @@
<cd:string value="mapfontsize"/>
</cd:sequence>
<cd:arguments>
- <cd:keywords n="1">
+ <cd:keywords n="1">
<cd:constant type="cd:dimension"/>
</cd:keywords>
<cd:keywords n="2">
diff --git a/tex/context/interface/keys-cs.xml b/tex/context/interface/keys-cs.xml
index 25200070e..bbbfdaf48 100644
--- a/tex/context/interface/keys-cs.xml
+++ b/tex/context/interface/keys-cs.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='po'/>
<cd:variable name='all' value='vse'/>
<cd:variable name='always' value='vzdy'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='dodatky'/>
<cd:variable name='appendix' value='dodatek'/>
<cd:variable name='april' value='duben'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='levyokraj'/>
<cd:variable name='leftpage' value='levastranka'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legenda'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='radek'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normalni'/>
<cd:variable name='nospacing' value='nospacing'/>
<cd:variable name='not' value='ne'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nothanging'/>
<cd:variable name='nothyphenated' value='nothyphenated'/>
<cd:variable name='november' value='listopad'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='pravyokraj'/>
<cd:variable name='rightpage' value='pravastranka'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='antikva'/>
<cd:variable name='romannumerals' value='rimskecislice'/>
<cd:variable name='rotate' value='otoc'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='podpodpodpodtema'/>
<cd:variable name='subsubsubsubsubsection' value='podpodpodpodpodsekce'/>
<cd:variable name='subsubsubsubsubsubject' value='podpodpodpodpodtema'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='podpodpodpodpodpodsekce'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='podpodpodpodpodpodtema'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='podpodpodpodpodpodpodsekce'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='podpodpodpodpodpodpodtema'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='podpodpodpodpodpodpodpodsekce'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='podpodpodpodpodpodpodpodtema'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='podpodpodpodpodpodpodpodpodsekce'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='podpodpodpodpodpodpodpodpodtema'/>
<cd:variable name='sunday' value='nedele'/>
<cd:variable name='support' value='podpora'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='zakladnifont'/>
<cd:constant name='bookmark' value='zalozka'/>
<cd:constant name='bottom' value='spodek'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='vzdalenostspodku'/>
<cd:constant name='bottomframe' value='ramecekdole'/>
<cd:constant name='bottomoffset' value='offsetspodku'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='pokracovat'/>
<cd:constant name='contrastcolor' value='kontrastnibarva'/>
<cd:constant name='controls' value='controls'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='fieldlayer'/>
<cd:constant name='fieldoffset' value='offsetpole'/>
<cd:constant name='file' value='soubor'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='zaostreni'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='vyska'/>
<cd:constant name='hfactor' value='vfaktor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='horoffset'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='cislo'/>
<cd:constant name='numbercolor' value='barvacisla'/>
<cd:constant name='numbercommand' value='ciselnyprikaz'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='cislovani'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='oddelovaccisla'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='stylcisla'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='hranicestranky'/>
<cd:constant name='pagecolor' value='barvastranky'/>
<cd:constant name='pagecommand' value='strankovyprikaz'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='cislostranky'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='pagestate'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='stylstranky'/>
<cd:constant name='palet' value='paleta'/>
<cd:constant name='paper' value='papir'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='predelmista'/>
<cd:constant name='position' value='position'/>
<cd:constant name='prefix' value='prefix'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='prednastaveni'/>
<cd:constant name='preview' value='nahled'/>
<cd:constant name='previous' value='predchozi'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='redukce'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='odkaz'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='odkazujici'/>
<cd:constant name='regionin' value='oblastuvnitr'/>
<cd:constant name='regionout' value='oblastvne'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='tloustkalinky'/>
<cd:constant name='samepage' value='stejnastranka'/>
<cd:constant name='sample' value='vzor'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='meritko'/>
<cd:constant name='scope' value='rozsah'/>
<cd:constant name='screen' value='rastr'/>
<cd:constant name='section' value='oddil'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='cislooddilu'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='oddelovac'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language cs -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='zacatek'/>
<cd:element name='complete' value='uplny'/>
<cd:element name='coupled' value='propojene'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settextcontent'/>
<cd:command name='settextvariable' value='settextvariable'/>
<cd:command name='setupalign' value='nastavzarovnani'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='nastavusporadani'/>
<cd:command name='setupbackground' value='nastavpozadi'/>
<cd:command name='setupbackgrounds' value='nastavpozadi'/>
diff --git a/tex/context/interface/keys-de.xml b/tex/context/interface/keys-de.xml
index 44945cd74..2c28adcb6 100644
--- a/tex/context/interface/keys-de.xml
+++ b/tex/context/interface/keys-de.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='nach'/>
<cd:variable name='all' value='alles'/>
<cd:variable name='always' value='immer'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='anhaenge'/>
<cd:variable name='appendix' value='anhang'/>
<cd:variable name='april' value='April'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='linkerrand'/>
<cd:variable name='leftpage' value='linkerseite'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legende'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='zeile'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normal'/>
<cd:variable name='nospacing' value='nospacing'/>
<cd:variable name='not' value='nicht'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nothanging'/>
<cd:variable name='nothyphenated' value='nothyphenated'/>
<cd:variable name='november' value='November'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='rechterrand'/>
<cd:variable name='rightpage' value='rechterseite'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='antiqua'/>
<cd:variable name='romannumerals' value='roemischezahlen'/>
<cd:variable name='rotate' value='drehe'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='unterunterunterunterthema'/>
<cd:variable name='subsubsubsubsubsection' value='unterunterunterunterunterabsatz'/>
<cd:variable name='subsubsubsubsubsubject' value='unterunterunterunterunterthema'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='unterunterunterunterunterunterabsatz'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='unterunterunterunterunterunterthema'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='unterunterunterunterunterunterunterabsatz'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='unterunterunterunterunterunterunterthema'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='unterunterunterunterunterunterunterunterabsatz'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='unterunterunterunterunterunterunterunterthema'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='unterunterunterunterunterunterunterunterunterabsatz'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='unterunterunterunterunterunterunterunterunterthema'/>
<cd:variable name='sunday' value='sonntag'/>
<cd:variable name='support' value='support'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='fliesstext'/>
<cd:constant name='bookmark' value='bookmark'/>
<cd:constant name='bottom' value='unten'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='abstandunten'/>
<cd:constant name='bottomframe' value='untenrahmen'/>
<cd:constant name='bottomoffset' value='untenoffset'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='fortsetzen'/>
<cd:constant name='contrastcolor' value='kontrastfarbe'/>
<cd:constant name='controls' value='controls'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='fieldlayer'/>
<cd:constant name='fieldoffset' value='feldoffset'/>
<cd:constant name='file' value='datei'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='hoehe'/>
<cd:constant name='hfactor' value='hfaktor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='rumpfabstand'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='nummer'/>
<cd:constant name='numbercolor' value='nummernfarbe'/>
<cd:constant name='numbercommand' value='nummerbefehl'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='nummerierung'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='nummernseperator'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='nummernstil'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='seitenbegrenzung'/>
<cd:constant name='pagecolor' value='seitenfarbe'/>
<cd:constant name='pagecommand' value='seitenbefehl'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='seitennummer'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='pagestate'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='seitenstil'/>
<cd:constant name='palet' value='palette'/>
<cd:constant name='paper' value='papier'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='setzetrenner'/>
<cd:constant name='position' value='position'/>
<cd:constant name='prefix' value='prefix'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='voreinstellung'/>
<cd:constant name='preview' value='vorschau'/>
<cd:constant name='previous' value='vorige'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='reduktion'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='referenz'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='referieren'/>
<cd:constant name='regionin' value='regionin'/>
<cd:constant name='regionout' value='regionaus'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='liniendicke'/>
<cd:constant name='samepage' value='selbeseite'/>
<cd:constant name='sample' value='muster'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='format'/>
<cd:constant name='scope' value='bereich'/>
<cd:constant name='screen' value='raster'/>
<cd:constant name='section' value='abschnitt'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='abschnittsnummer'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='seperator'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language de -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='anfang'/>
<cd:element name='complete' value='vollende'/>
<cd:element name='coupled' value='verknuepft'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settext'/>
<cd:command name='settextvariable' value='settextvariable'/>
<cd:command name='setupalign' value='stelleausrichtungein'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='stelleanordnenein'/>
<cd:command name='setupbackground' value='stellehintergrundein'/>
<cd:command name='setupbackgrounds' value='stellehintergruendeein'/>
diff --git a/tex/context/interface/keys-en.xml b/tex/context/interface/keys-en.xml
index 4bc9311e7..db9181646 100644
--- a/tex/context/interface/keys-en.xml
+++ b/tex/context/interface/keys-en.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='after'/>
<cd:variable name='all' value='all'/>
<cd:variable name='always' value='always'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='appendices'/>
<cd:variable name='appendix' value='appendix'/>
<cd:variable name='april' value='April'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='leftmargin'/>
<cd:variable name='leftpage' value='leftpage'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legend'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='line'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normal'/>
<cd:variable name='nospacing' value='nospacing'/>
<cd:variable name='not' value='not'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nothanging'/>
<cd:variable name='nothyphenated' value='nothyphenated'/>
<cd:variable name='november' value='November'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='rightmargin'/>
<cd:variable name='rightpage' value='rightpage'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='roman'/>
<cd:variable name='romannumerals' value='romannumerals'/>
<cd:variable name='rotate' value='rotate'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='subsubsubsubsubject'/>
<cd:variable name='subsubsubsubsubsection' value='subsubsubsubsubsection'/>
<cd:variable name='subsubsubsubsubsubject' value='subsubsubsubsubsubject'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='subsubsubsubsubsubsection'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='subsubsubsubsubsubsubject'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubject'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubsection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubsubject'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubsubsection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubsubsubject'/>
<cd:variable name='sunday' value='sunday'/>
<cd:variable name='support' value='support'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='bodyfont'/>
<cd:constant name='bookmark' value='bookmark'/>
<cd:constant name='bottom' value='bottom'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='bottomdistance'/>
<cd:constant name='bottomframe' value='bottomframe'/>
<cd:constant name='bottomoffset' value='bottomoffset'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='continue'/>
<cd:constant name='contrastcolor' value='contrastcolor'/>
<cd:constant name='controls' value='controls'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='fieldlayer'/>
<cd:constant name='fieldoffset' value='fieldoffset'/>
<cd:constant name='file' value='file'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='height'/>
<cd:constant name='hfactor' value='hfactor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='horoffset'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='number'/>
<cd:constant name='numbercolor' value='numbercolor'/>
<cd:constant name='numbercommand' value='numbercommand'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='numbering'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='numberseparator'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='numberstyle'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='pageboundaries'/>
<cd:constant name='pagecolor' value='pagecolor'/>
<cd:constant name='pagecommand' value='pagecommand'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='pagenumber'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='pagestate'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='pagestyle'/>
<cd:constant name='palet' value='palet'/>
<cd:constant name='paper' value='paper'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='placestopper'/>
<cd:constant name='position' value='position'/>
<cd:constant name='prefix' value='prefix'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='preset'/>
<cd:constant name='preview' value='preview'/>
<cd:constant name='previous' value='previous'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='reduction'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='reference'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='referencing'/>
<cd:constant name='regionin' value='regionin'/>
<cd:constant name='regionout' value='regionout'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='rulethickness'/>
<cd:constant name='samepage' value='samepage'/>
<cd:constant name='sample' value='sample'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='scale'/>
<cd:constant name='scope' value='scope'/>
<cd:constant name='screen' value='screen'/>
<cd:constant name='section' value='section'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='sectionnumber'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='separator'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language en -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='begin'/>
<cd:element name='complete' value='complete'/>
<cd:element name='coupled' value='coupled'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settextcontent'/>
<cd:command name='settextvariable' value='settextvariable'/>
<cd:command name='setupalign' value='setupalign'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='setuparranging'/>
<cd:command name='setupbackground' value='setupbackground'/>
<cd:command name='setupbackgrounds' value='setupbackgrounds'/>
diff --git a/tex/context/interface/keys-fr.xml b/tex/context/interface/keys-fr.xml
index 8815a94bf..faf884c38 100644
--- a/tex/context/interface/keys-fr.xml
+++ b/tex/context/interface/keys-fr.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='apres'/>
<cd:variable name='all' value='tout'/>
<cd:variable name='always' value='toujours'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='annexes'/>
<cd:variable name='appendix' value='annexe'/>
<cd:variable name='april' value='avril'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='margegauche'/>
<cd:variable name='leftpage' value='pagegauche'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legende'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='ligne'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normal'/>
<cd:variable name='nospacing' value='sansespacement'/>
<cd:variable name='not' value='pas'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nonsuspendu'/>
<cd:variable name='nothyphenated' value='nothyphenated'/>
<cd:variable name='november' value='novembre'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='margedroite'/>
<cd:variable name='rightpage' value='pagedroite'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='roman'/>
<cd:variable name='romannumerals' value='chiffresromains'/>
<cd:variable name='rotate' value='oriente'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='soussoussoussoussujet'/>
<cd:variable name='subsubsubsubsubsection' value='soussoussoussoussoussection'/>
<cd:variable name='subsubsubsubsubsubject' value='soussoussoussoussoussujet'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='soussoussoussoussoussoussection'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='soussoussoussoussoussoussujet'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='soussoussoussoussoussoussoussection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='soussoussoussoussoussoussoussujet'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='soussoussoussoussoussoussoussoussection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='soussoussoussoussoussoussoussoussujet'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='soussoussoussoussoussoussoussoussoussection'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='soussoussoussoussoussoussoussoussoussujet'/>
<cd:variable name='sunday' value='dimanche'/>
<cd:variable name='support' value='support'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='policecorps'/>
<cd:constant name='bookmark' value='marquepage'/>
<cd:constant name='bottom' value='inf'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='distanceinf'/>
<cd:constant name='bottomframe' value='cadreinf'/>
<cd:constant name='bottomoffset' value='decalageinf'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='composant'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='continue'/>
<cd:constant name='contrastcolor' value='coleurcontraste'/>
<cd:constant name='controls' value='controles'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='calquechamp'/>
<cd:constant name='fieldoffset' value='offsetchamp'/>
<cd:constant name='file' value='fichier'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='hauteur'/>
<cd:constant name='hfactor' value='facteurhauteur'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='decalagehauteur'/>
<cd:constant name='horoffset' value='horoffset'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='numero'/>
<cd:constant name='numbercolor' value='couleurnumero'/>
<cd:constant name='numbercommand' value='commandenumero'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='numerotation'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='separateurnumbero'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='stylenumero'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='limitespage'/>
<cd:constant name='pagecolor' value='couleurpage'/>
<cd:constant name='pagecommand' value='commandepage'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='numeropage'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='etatpage'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='stylepage'/>
<cd:constant name='palet' value='palette'/>
<cd:constant name='paper' value='papier'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='emplacementstopper'/>
<cd:constant name='position' value='position'/>
<cd:constant name='prefix' value='prefixe'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='prereglage'/>
<cd:constant name='preview' value='previsualisation'/>
<cd:constant name='previous' value='precedent'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='reduction'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='reference'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='referencing'/>
<cd:constant name='regionin' value='entreregion'/>
<cd:constant name='regionout' value='regionexterieure'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='epaisseurligne'/>
<cd:constant name='samepage' value='memepage'/>
<cd:constant name='sample' value='echantillon'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='echelle'/>
<cd:constant name='scope' value='scope'/>
<cd:constant name='screen' value='ecran'/>
<cd:constant name='section' value='section'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='numerosection'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='separateur'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='reglages'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language fr -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='debut'/>
<cd:element name='complete' value='complete'/>
<cd:element name='coupled' value='couple'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settext'/>
<cd:command name='settextvariable' value='affectevariabletexte'/>
<cd:command name='setupalign' value='reglealignement'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='reglearrangement'/>
<cd:command name='setupbackground' value='reglearriereplan'/>
<cd:command name='setupbackgrounds' value='reglearriereplans'/>
diff --git a/tex/context/interface/keys-it.xml b/tex/context/interface/keys-it.xml
index 885fddb28..69dcdfbe0 100644
--- a/tex/context/interface/keys-it.xml
+++ b/tex/context/interface/keys-it.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='dopo'/>
<cd:variable name='all' value='tutti'/>
<cd:variable name='always' value='sempre'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='appendici'/>
<cd:variable name='appendix' value='appendice'/>
<cd:variable name='april' value='aprile'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='marginesinistro'/>
<cd:variable name='leftpage' value='paginasinistra'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legenda'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='riga'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normale'/>
<cd:variable name='nospacing' value='nospacing'/>
<cd:variable name='not' value='non'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nonsospeso'/>
<cd:variable name='nothyphenated' value='nonsillabato'/>
<cd:variable name='november' value='novembre'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='marginedestro'/>
<cd:variable name='rightpage' value='paginadestra'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='roman'/>
<cd:variable name='romannumerals' value='numeriromani'/>
<cd:variable name='rotate' value='ruota'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='sottosottosottosottoargomento'/>
<cd:variable name='subsubsubsubsubsection' value='sottosottosottosottosottocapoverso'/>
<cd:variable name='subsubsubsubsubsubject' value='sottosottosottosottosottoargomento'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='sottosottosottosottosottosottocapoverso'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='sottosottosottosottosottosottoargomento'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='sottosottosottosottosottosottosottocapoverso'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='sottosottosottosottosottosottosottoargomento'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='sottosottosottosottosottosottosottosottocapoverso'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='sottosottosottosottosottosottosottosottoargomento'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='sottosottosottosottosottosottosottosottosottocapoverso'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='sottosottosottosottosottosottosottosottosottoargomento'/>
<cd:variable name='sunday' value='domenica'/>
<cd:variable name='support' value='supporto'/>
<cd:variable name='sym' value='sim'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='fonttesto'/>
<cd:constant name='bookmark' value='segnalibro'/>
<cd:constant name='bottom' value='fondo'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='distanzafondo'/>
<cd:constant name='bottomframe' value='cornicefondo'/>
<cd:constant name='bottomoffset' value='offsetfondo'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='continua'/>
<cd:constant name='contrastcolor' value='colorecontrasto'/>
<cd:constant name='controls' value='controlli'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='fieldlayer'/>
<cd:constant name='fieldoffset' value='offsetcampo'/>
<cd:constant name='file' value='file'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='altezza'/>
<cd:constant name='hfactor' value='hfactor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='horoffset'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='numero'/>
<cd:constant name='numbercolor' value='colorenumero'/>
<cd:constant name='numbercommand' value='comandonumero'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='numerazione'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='separatorenumero'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='stilenumero'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='limitipagina'/>
<cd:constant name='pagecolor' value='colorepagina'/>
<cd:constant name='pagecommand' value='comandopagina'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='numeropagina'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='statopagina'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='stilepagina'/>
<cd:constant name='palet' value='tavolozza'/>
<cd:constant name='paper' value='carta'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='mettistopper'/>
<cd:constant name='position' value='posizione'/>
<cd:constant name='prefix' value='prefisso'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='preimpostato'/>
<cd:constant name='preview' value='anteprima'/>
<cd:constant name='previous' value='precedente'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='riduzione'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='riferimento'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='referencing'/>
<cd:constant name='regionin' value='entraregione'/>
<cd:constant name='regionout' value='esciregione'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='spessorelinea'/>
<cd:constant name='samepage' value='stessapagina'/>
<cd:constant name='sample' value='campione'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='scala'/>
<cd:constant name='scope' value='scope'/>
<cd:constant name='screen' value='schermo'/>
<cd:constant name='section' value='sezione'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='numerosezione'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='separatore'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language it -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='inizio'/>
<cd:element name='complete' value='completo'/>
<cd:element name='coupled' value='accoppiato'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settext'/>
<cd:command name='settextvariable' value='setvariabiletesto'/>
<cd:command name='setupalign' value='impostaallineamento'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='impostaparranging'/>
<cd:command name='setupbackground' value='impostasfondo'/>
<cd:command name='setupbackgrounds' value='impostasfondi'/>
diff --git a/tex/context/interface/keys-nl.xml b/tex/context/interface/keys-nl.xml
index deee34508..32e60c364 100644
--- a/tex/context/interface/keys-nl.xml
+++ b/tex/context/interface/keys-nl.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='na'/>
<cd:variable name='all' value='alles'/>
<cd:variable name='always' value='altijd'/>
+ <cd:variable name='answerarea' value='antwoordgebied'/>
<cd:variable name='appendices' value='bijlagen'/>
<cd:variable name='appendix' value='bijlage'/>
<cd:variable name='april' value='april'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='linkshangend'/>
<cd:variable name='leftmargin' value='linkermarge'/>
<cd:variable name='leftpage' value='linkerpagina'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legenda'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='regel'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normaal'/>
<cd:variable name='nospacing' value='geenspatiering'/>
<cd:variable name='not' value='niet'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='niethangend'/>
<cd:variable name='nothyphenated' value='nietafgebroken'/>
<cd:variable name='november' value='november'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='rechtshangend'/>
<cd:variable name='rightmargin' value='rechtermarge'/>
<cd:variable name='rightpage' value='rechterpagina'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='romaan'/>
<cd:variable name='romannumerals' value='romeins'/>
<cd:variable name='rotate' value='roteer'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='subsubsubsubonderwerp'/>
<cd:variable name='subsubsubsubsubsection' value='subsubsubsubsubparagraaf'/>
<cd:variable name='subsubsubsubsubsubject' value='subsubsubsubsubonderwerp'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='subsubsubsubsubsubparagraaf'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='subsubsubsubsubsubonderwerp'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubparagraaf'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubonderwerp'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubparagraaf'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubonderwerp'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubsubparagraaf'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubsubonderwerp'/>
<cd:variable name='sunday' value='zondag'/>
<cd:variable name='support' value='support'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='korps'/>
<cd:constant name='bookmark' value='bookmark'/>
<cd:constant name='bottom' value='onder'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='onderafstand'/>
<cd:constant name='bottomframe' value='onderkader'/>
<cd:constant name='bottomoffset' value='onderoffset'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='koppelteken'/>
<cd:constant name='compress' value='comprimeren'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='doorgaan'/>
<cd:constant name='contrastcolor' value='contrastkleur'/>
<cd:constant name='controls' value='sturing'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='veldlaag'/>
<cd:constant name='fieldoffset' value='veldoffset'/>
<cd:constant name='file' value='file'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusuit'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='hoogte'/>
<cd:constant name='hfactor' value='hfactor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='rugoffset'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='nummer'/>
<cd:constant name='numbercolor' value='nummerkleur'/>
<cd:constant name='numbercommand' value='nummercommando'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='nummerafstand'/>
<cd:constant name='numbering' value='nummeren'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='nummerscheider'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='nummerletter'/>
<cd:constant name='numberwidth' value='nummerbreedte'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='paginaovergangen'/>
<cd:constant name='pagecolor' value='paginakleur'/>
<cd:constant name='pagecommand' value='paginacommando'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='paginanummer'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='paginastatus'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='paginaletter'/>
<cd:constant name='palet' value='palet'/>
<cd:constant name='paper' value='papier'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='plaatsafsluiter'/>
<cd:constant name='position' value='positie'/>
<cd:constant name='prefix' value='prefix'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='preset'/>
<cd:constant name='preview' value='preview'/>
<cd:constant name='previous' value='vorige'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='reductie'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='verwijzing'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='refereren'/>
<cd:constant name='regionin' value='gebiedin'/>
<cd:constant name='regionout' value='gebieduit'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='lijndikte'/>
<cd:constant name='samepage' value='zelfdepagina'/>
<cd:constant name='sample' value='monster'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='schaal'/>
<cd:constant name='scope' value='scope'/>
<cd:constant name='screen' value='raster'/>
<cd:constant name='section' value='sectie'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='sectienummer'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='scheider'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language nl -->
<cd:elements>
+ <cd:element name='answerlines' value='antwoordregels'/>
+ <cd:element name='answerspace' value='antwoordruimte'/>
<cd:element name='begin' value='beginvan'/>
<cd:element name='complete' value='volledige'/>
<cd:element name='coupled' value='gekoppelde'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='steltekstinhoudin'/>
<cd:command name='settextvariable' value='kentekstvariabeletoe'/>
<cd:command name='setupalign' value='steluitlijnenin'/>
+ <cd:command name='setupanswerarea' value='stelantwoordgebiedin'/>
<cd:command name='setuparranging' value='stelarrangerenin'/>
<cd:command name='setupbackground' value='stelachtergrondin'/>
<cd:command name='setupbackgrounds' value='stelachtergrondenin'/>
diff --git a/tex/context/interface/keys-pe.xml b/tex/context/interface/keys-pe.xml
index 0ac2bc83c..34acdeecc 100644
--- a/tex/context/interface/keys-pe.xml
+++ b/tex/context/interface/keys-pe.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='بعداز'/>
<cd:variable name='all' value='همه'/>
<cd:variable name='always' value='همواره'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='پیوستها'/>
<cd:variable name='appendix' value='پیوست'/>
<cd:variable name='april' value='آوریل'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='آویزان‌چپ'/>
<cd:variable name='leftmargin' value='حاشیه‌چپ'/>
<cd:variable name='leftpage' value='صفحه‌چپ'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='راهنما'/>
<cd:variable name='lesshyphenation' value='شکست‌کلمات‌کمتر'/>
<cd:variable name='line' value='خط'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='نرمال'/>
<cd:variable name='nospacing' value='بدون‌فضاگذاری'/>
<cd:variable name='not' value='بدون'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='بدون‌آویزان‌کردن'/>
<cd:variable name='nothyphenated' value='بدون‌شکست'/>
<cd:variable name='november' value='نوامبر'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='آویزان‌کردن‌راست'/>
<cd:variable name='rightmargin' value='حاشیه‌راست'/>
<cd:variable name='rightpage' value='صفحه‌راست'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='رومن'/>
<cd:variable name='romannumerals' value='شماره‌لاتین'/>
<cd:variable name='rotate' value='دوران'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='زیرزیرزیرزیرموضوع'/>
<cd:variable name='subsubsubsubsubsection' value='زیرزیرزیرزیرزیربخش'/>
<cd:variable name='subsubsubsubsubsubject' value='زیرزیرزیرزیرزیرموضوع'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='زیرزیرزیرزیرزیرزیربخش'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='زیرزیرزیرزیرزیرزیرموضوع'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='زیرزیرزیرزیرزیرزیرزیربخش'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='زیرزیرزیرزیرزیرزیرزیرموضوع'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='زیرزیرزیرزیرزیرزیرزیرزیربخش'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='زیرزیرزیرزیرزیرزیرزیرزیرموضوع'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='زیرزیرزیرزیرزیرزیرزیرزیرزیربخش'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='زیرزیرزیرزیرزیرزیرزیرزیرزیرموضوع'/>
<cd:variable name='sunday' value='یک‌شنبه'/>
<cd:variable name='support' value='حمایت'/>
<cd:variable name='sym' value='نم'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='قلم‌بدنه'/>
<cd:constant name='bookmark' value='چوبخط'/>
<cd:constant name='bottom' value='پایین'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='فاصله‌پایین'/>
<cd:constant name='bottomframe' value='قالب‌پایین'/>
<cd:constant name='bottomoffset' value='آفست‌پایین'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='مولفه'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='فشردن'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='ادامه'/>
<cd:constant name='contrastcolor' value='contrastcolor'/>
<cd:constant name='controls' value='کنترلها'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='لایه‌میدان'/>
<cd:constant name='fieldoffset' value='آفست‌میدان'/>
<cd:constant name='file' value='پرونده'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='تمرکز'/>
<cd:constant name='focusin' value='تمرکزدرون'/>
<cd:constant name='focusout' value='تمرکزبیرون'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='ارتفاع'/>
<cd:constant name='hfactor' value='عامل‌ارتفاع'/>
<cd:constant name='hfil' value='پرکردن‌ارتفاع'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='آفست‌ا'/>
<cd:constant name='horoffset' value='آفست‌افق'/>
<cd:constant name='hyphen' value='شکستن'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='شماره'/>
<cd:constant name='numbercolor' value='رنگ‌شماره'/>
<cd:constant name='numbercommand' value='فرمان‌شماره'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='فاصله‌شماره'/>
<cd:constant name='numbering' value='شماره‌گذاری'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='جداکننده‌شماره'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='سبک‌شماره'/>
<cd:constant name='numberwidth' value='عرض‌شماره'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='مرزهای‌صفحه'/>
<cd:constant name='pagecolor' value='رنگ‌صفحه'/>
<cd:constant name='pagecommand' value='فرمان‌صفحه'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='شماره‌صفحه'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='وضعیت‌صفحه'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='سبک‌صفحه'/>
<cd:constant name='palet' value='لوح'/>
<cd:constant name='paper' value='برگ'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='بگذارایست'/>
<cd:constant name='position' value='موقعیت'/>
<cd:constant name='prefix' value='پیشوند'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='preset'/>
<cd:constant name='preview' value='پیش‌دید'/>
<cd:constant name='previous' value='قبلی'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='کاهش'/>
<cd:constant name='ref' value='رج'/>
<cd:constant name='reference' value='مرجع'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='مراجعه'/>
<cd:constant name='regionin' value='ناحیه‌درون'/>
<cd:constant name='regionout' value='ناحیه‌بیرون'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='ضخامت‌خط'/>
<cd:constant name='samepage' value='همان‌صفحه'/>
<cd:constant name='sample' value='نمونه'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='مقیاس'/>
<cd:constant name='scope' value='طرح'/>
<cd:constant name='screen' value='پرده'/>
<cd:constant name='section' value='بخش'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='شماره‌بخش'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='جداکننده'/>
<cd:constant name='set' value='قراربده'/>
<cd:constant name='setups' value='بارگذاریها'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language pe -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='عنصرها'/>
<cd:element name='complete' value='کامل'/>
<cd:element name='coupled' value='مزدوج'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='تعیین‌محتوای‌متن'/>
<cd:command name='settextvariable' value='تعیین‌متغیر‌متن'/>
<cd:command name='setupalign' value='بارگذاری‌تنظیم'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='بارگذاری‌ترتیب'/>
<cd:command name='setupbackground' value='بارگذاری‌پس‌زمینه'/>
<cd:command name='setupbackgrounds' value='بارگذاری‌پس‌زمینه‌ها'/>
diff --git a/tex/context/interface/keys-ro.xml b/tex/context/interface/keys-ro.xml
index a93a06957..77ed534ab 100644
--- a/tex/context/interface/keys-ro.xml
+++ b/tex/context/interface/keys-ro.xml
@@ -71,6 +71,7 @@
<cd:variable name='after' value='dupa'/>
<cd:variable name='all' value='tot'/>
<cd:variable name='always' value='totdeauna'/>
+ <cd:variable name='answerarea' value='answerarea'/>
<cd:variable name='appendices' value='apendixuri'/>
<cd:variable name='appendix' value='apendix'/>
<cd:variable name='april' value='aprilie'/>
@@ -240,6 +241,7 @@
<cd:variable name='lefthanging' value='lefthanging'/>
<cd:variable name='leftmargin' value='marginestanga'/>
<cd:variable name='leftpage' value='paginastanga'/>
+ <cd:variable name='lefttoright' value='lefttoright'/>
<cd:variable name='legend' value='legenda'/>
<cd:variable name='lesshyphenation' value='lesshyphenation'/>
<cd:variable name='line' value='linie'/>
@@ -298,6 +300,7 @@
<cd:variable name='normal' value='normal'/>
<cd:variable name='nospacing' value='nospacing'/>
<cd:variable name='not' value='nu'/>
+ <cd:variable name='note' value='note'/>
<cd:variable name='nothanging' value='nothanging'/>
<cd:variable name='nothyphenated' value='nedespsilabe'/>
<cd:variable name='november' value='noiembrie'/>
@@ -362,6 +365,7 @@
<cd:variable name='righthanging' value='righthanging'/>
<cd:variable name='rightmargin' value='marginedreapta'/>
<cd:variable name='rightpage' value='paginadreapta'/>
+ <cd:variable name='righttoleft' value='righttoleft'/>
<cd:variable name='roman' value='roman'/>
<cd:variable name='romannumerals' value='numereromane'/>
<cd:variable name='rotate' value='rotit'/>
@@ -431,6 +435,14 @@
<cd:variable name='subsubsubsubsubject' value='subsubsubsubsubiect'/>
<cd:variable name='subsubsubsubsubsection' value='subsubsubsubsubsectiune'/>
<cd:variable name='subsubsubsubsubsubject' value='subsubsubsubsubsubiect'/>
+ <cd:variable name='subsubsubsubsubsubsection' value='subsubsubsubsubsubsectiune'/>
+ <cd:variable name='subsubsubsubsubsubsubject' value='subsubsubsubsubsubsubiect'/>
+ <cd:variable name='subsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsectiune'/>
+ <cd:variable name='subsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubiect'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubsectiune'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubsubiect'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsection' value='subsubsubsubsubsubsubsubsubsectiune'/>
+ <cd:variable name='subsubsubsubsubsubsubsubsubsubject' value='subsubsubsubsubsubsubsubsubsubiect'/>
<cd:variable name='sunday' value='duminica'/>
<cd:variable name='support' value='suport'/>
<cd:variable name='sym' value='sym'/>
@@ -526,6 +538,8 @@
<cd:constant name='bodyfont' value='fonttext'/>
<cd:constant name='bookmark' value='semncarte'/>
<cd:constant name='bottom' value='jos'/>
+ <cd:constant name='bottomafter' value='bottomafter'/>
+ <cd:constant name='bottombefore' value='bottombefore'/>
<cd:constant name='bottomdistance' value='distantajos'/>
<cd:constant name='bottomframe' value='framejos'/>
<cd:constant name='bottomoffset' value='offsetjos'/>
@@ -553,6 +567,7 @@
<cd:constant name='component' value='component'/>
<cd:constant name='compoundhyphen' value='compoundhyphen'/>
<cd:constant name='compress' value='compress'/>
+ <cd:constant name='connector' value='connector'/>
<cd:constant name='continue' value='continua'/>
<cd:constant name='contrastcolor' value='culoarecontrast'/>
<cd:constant name='controls' value='controale'/>
@@ -599,6 +614,7 @@
<cd:constant name='fieldlayer' value='fieldlayer'/>
<cd:constant name='fieldoffset' value='offsetcamp'/>
<cd:constant name='file' value='fisier'/>
+ <cd:constant name='filtercommand' value='filtercommand'/>
<cd:constant name='focus' value='focus'/>
<cd:constant name='focusin' value='focusin'/>
<cd:constant name='focusout' value='focusout'/>
@@ -632,6 +648,7 @@
<cd:constant name='height' value='inaltime'/>
<cd:constant name='hfactor' value='hfactor'/>
<cd:constant name='hfil' value='hfil'/>
+ <cd:constant name='hidenumber' value='hidenumber'/>
<cd:constant name='hoffset' value='hoffset'/>
<cd:constant name='horoffset' value='offsetoriz'/>
<cd:constant name='hyphen' value='hyphen'/>
@@ -720,9 +737,17 @@
<cd:constant name='number' value='numar'/>
<cd:constant name='numbercolor' value='culoarenumar'/>
<cd:constant name='numbercommand' value='comandanumar'/>
+ <cd:constant name='numberconversion' value='numberconversion'/>
+ <cd:constant name='numberconversionset' value='numberconversionset'/>
<cd:constant name='numberdistance' value='numberdistance'/>
<cd:constant name='numbering' value='numerotare'/>
+ <cd:constant name='numberorder' value='numberorder'/>
+ <cd:constant name='numberprefix' value='numberprefix'/>
+ <cd:constant name='numbersegments' value='numbersegments'/>
<cd:constant name='numberseparator' value='separatornumar'/>
+ <cd:constant name='numberseparatorset' value='numberseparatorset'/>
+ <cd:constant name='numberset' value='numberset'/>
+ <cd:constant name='numberstopper' value='numberstopper'/>
<cd:constant name='numberstyle' value='stilnumar'/>
<cd:constant name='numberwidth' value='numberwidth'/>
<cd:constant name='nx' value='nx'/>
@@ -742,8 +767,22 @@
<cd:constant name='pageboundaries' value='marginipagina'/>
<cd:constant name='pagecolor' value='culoarepagina'/>
<cd:constant name='pagecommand' value='comandapagina'/>
+ <cd:constant name='pageconversion' value='pageconversion'/>
+ <cd:constant name='pageconversionset' value='pageconversionset'/>
<cd:constant name='pagenumber' value='numarpagina'/>
+ <cd:constant name='pageprefix' value='pageprefix'/>
+ <cd:constant name='pageprefixconnector' value='pageprefixconnector'/>
+ <cd:constant name='pageprefixconversion' value='pageprefixconversion'/>
+ <cd:constant name='pageprefixconversionset' value='pageprefixconversionset'/>
+ <cd:constant name='pageprefixsegments' value='pageprefixsegments'/>
+ <cd:constant name='pageprefixseparatorset' value='pageprefixseparatorset'/>
+ <cd:constant name='pageprefixset' value='pageprefixset'/>
+ <cd:constant name='pageprefixstopper' value='pageprefixstopper'/>
+ <cd:constant name='pagesegments' value='pagesegments'/>
+ <cd:constant name='pageseparatorset' value='pageseparatorset'/>
+ <cd:constant name='pageset' value='pageset'/>
<cd:constant name='pagestate' value='pagestate'/>
+ <cd:constant name='pagestopper' value='pagestopper'/>
<cd:constant name='pagestyle' value='stilpagina'/>
<cd:constant name='palet' value='paleta'/>
<cd:constant name='paper' value='hartie'/>
@@ -753,6 +792,13 @@
<cd:constant name='placestopper' value='punestopper'/>
<cd:constant name='position' value='pozitie'/>
<cd:constant name='prefix' value='prefix'/>
+ <cd:constant name='prefixconnector' value='prefixconnector'/>
+ <cd:constant name='prefixconversion' value='prefixconversion'/>
+ <cd:constant name='prefixconversionset' value='prefixconversionset'/>
+ <cd:constant name='prefixsegments' value='prefixsegments'/>
+ <cd:constant name='prefixseparatorset' value='prefixseparatorset'/>
+ <cd:constant name='prefixset' value='prefixset'/>
+ <cd:constant name='prefixstopper' value='prefixstopper'/>
<cd:constant name='preset' value='preset'/>
<cd:constant name='preview' value='previzualizare'/>
<cd:constant name='previous' value='precendent'/>
@@ -763,6 +809,7 @@
<cd:constant name='reduction' value='reducere'/>
<cd:constant name='ref' value='ref'/>
<cd:constant name='reference' value='referinta'/>
+ <cd:constant name='referenceprefix' value='referenceprefix'/>
<cd:constant name='referencing' value='referinta'/>
<cd:constant name='regionin' value='regiuneintrare'/>
<cd:constant name='regionout' value='regiuneiesire'/>
@@ -794,11 +841,18 @@
<cd:constant name='rulethickness' value='grosimerigla'/>
<cd:constant name='samepage' value='aceeasipagina'/>
<cd:constant name='sample' value='exemplu'/>
+ <cd:constant name='saveinlist' value='saveinlist'/>
<cd:constant name='scale' value='scala'/>
<cd:constant name='scope' value='scop'/>
<cd:constant name='screen' value='ecran'/>
<cd:constant name='section' value='sectiune'/>
+ <cd:constant name='sectionconversion' value='sectionconversion'/>
+ <cd:constant name='sectionconversionset' value='sectionconversionset'/>
<cd:constant name='sectionnumber' value='numarsectiune'/>
+ <cd:constant name='sectionsegments' value='sectionsegments'/>
+ <cd:constant name='sectionseparatorset' value='sectionseparatorset'/>
+ <cd:constant name='sectionset' value='sectionset'/>
+ <cd:constant name='sectionstopper' value='sectionstopper'/>
<cd:constant name='separator' value='separator'/>
<cd:constant name='set' value='set'/>
<cd:constant name='setups' value='setups'/>
@@ -901,6 +955,8 @@
<!-- definitions for interface elements for language ro -->
<cd:elements>
+ <cd:element name='answerlines' value='answerlines'/>
+ <cd:element name='answerspace' value='answerspace'/>
<cd:element name='begin' value='inceput'/>
<cd:element name='complete' value='complet'/>
<cd:element name='coupled' value='cuplat'/>
@@ -1289,6 +1345,7 @@
<cd:command name='settextcontent' value='settextcontent'/>
<cd:command name='settextvariable' value='setvariabilatext'/>
<cd:command name='setupalign' value='seteazaalinierea'/>
+ <cd:command name='setupanswerarea' value='setupanswerarea'/>
<cd:command name='setuparranging' value='seteazaaranjareapag'/>
<cd:command name='setupbackground' value='seteazafundal'/>
<cd:command name='setupbackgrounds' value='seteazafundaluri'/>
diff --git a/tex/context/interface/t-bib.xml b/tex/context/interface/t-bib.xml
index 93cf9f285..faa728fa6 100644
--- a/tex/context/interface/t-bib.xml
+++ b/tex/context/interface/t-bib.xml
@@ -199,6 +199,9 @@
<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>
diff --git a/tex/context/patterns/lang-de.hyp b/tex/context/patterns/lang-de.hyp
index 23691aeb2..15485d1e1 100644
--- a/tex/context/patterns/lang-de.hyp
+++ b/tex/context/patterns/lang-de.hyp
@@ -2,7 +2,7 @@
% for comment and copyright, see ./lang-de.rme
-% used:
+% used:
\hyphenation{
-} \ No newline at end of file
+}
diff --git a/tex/context/patterns/lang-de.pat b/tex/context/patterns/lang-de.pat
index 2058b3e72..836fa7080 100644
--- a/tex/context/patterns/lang-de.pat
+++ b/tex/context/patterns/lang-de.pat
@@ -7,50 +7,53 @@
\patterns{
.a6
.ab3b
+.aben2
.ab5l
.abo4
.ab3ol
.ab1or
+.ab5r
.ab3s
.ag4r
.ag2u
-.aid4
+.aid2
.ai2s
.al3br
.al2e
.al3l4en
.al3ph
+.al4tei
.alt3s
.amt4
-.amts3
+.amt6s3
.an3alg
.an3d
.ang4
.an1gl
-.ang6s2
+.angs4
.angst3
.an3k
.an3s
.an4si.
.ans2p
.an3z
-.ao5
.ap3s2
.ar3k2a
.ar4m3ac
-.ar2s
+.ar4s
.ar4t3ei
-.ata1
+.as1t
+.as4ta
.au3d
.au2f5
.au4s1
.ausch3
-.au6stes
-.ax2
-.ä6
-.äm3
+.aus5s
+.ä4
+.äm5
.ät2s
.b6
+.bau1s
.be3erb
.bei6ge.
.be3ra
@@ -62,18 +65,21 @@
.bo4s3k
.c4
.ch2
+.con3
.d4
.dab6
.da2r1
.dar3in
-.dar2m1
+.dar2m
.da4te.
.da4tes
.de4al
.de1i
.de3o2
.de3r4en
+.de1s
.de3sk
+.de3s2t
.deut2
.dien4
.do3b
@@ -90,121 +96,114 @@
.ei5ner
.ei5nes
.ei4sp
-.ei4s1t
+.ei4st
.ei2tr
.el2bi
+.elb3s
+.els7t
.em3m2
.en1
.en4d3er
.en4d3r
-.enn4
+.enn2
.en4t3
-.epi1
.er4dei
.er4der
.er1e
.er1i
-.ers2
.er8stein
+.es3k
.es3p
-.es2t
-.est4e
-.et2s
+.es1ta
+.es5t4e
+.es1th
+.es3tr
+.et4s
.eu3
.eug4
.ext4
.f6
-.fa2c
-.fe6sta
+.fi3est
.fi4le.
.fi4len
+.fin6s
.fi2s
.frau3
-.fs2
-.fus2
+.fs4
.fu2sc
-.g6
-.gang5
-.ga2t
+.g4
+.ga4t
.gd2
.gel2d
.ge5nar
.ge3ne
.ge3r2a
.ge3r2e
-.ge5s4
-.ge7sta
+.ge3s4a
.ge1u
-.grif8fes
-.gros2
+.gros4
.gs2
-.gus2
-.guss3
+.gus4s3
.gu4ter
.h4
.ha3bi
.haft5s
-.hal4s
-.hal3te
+.hal5te
.haup4
-.hau2t1
+.hau4t1
.he2
+.he3cke
.he3ri
.he6r5inn
.he5xe
+.his1
.ho4met
.i6
.ia4
-.il3
-.illu5
.im2a
.in3
.ink4
.inu3
-.is4a
+.is2a
+.is3tr
.jor5
-.k4
+.k6
.ka2b5l
.ka2i
.kamp2
-.ka4t3io
-.ken6num
-.ker5s
+.ka6t3io
.ki4e
.klan4
.ks2
.kü1b
.l4
.la3b
-.lat5s
.le4a
-.lea7se
.le5ni
+.lib6
.lo4g3in
.lo3ver
-.lu4str
.m4
.ma3d
.ma3ge
.ma3le
-.ma4str
+.ma4st
.me3l4a
.me3ne
.men8schw
.ment2
-.mi2sc
+.mi2s
.mi4t
.n4
-.näs1c
+.näs3c
+.ne6s
.nich2
.ni4e
-.ni3ka
.nob4
-.no2c
.no2th
-.nul2
-.nus6
+.nus4
.o6
+.oa3
.ob1a
.obe2
.oben3
@@ -212,10 +211,12 @@
.ob3l
.oper4
.or2a
-.ort4
+.ort2
+.ort6s
.orts3e
.oste2
-.ost7ende
+.os4tel
+.os8t7ende
.oste6r5e
.ost3r
.ozo4
@@ -228,35 +229,35 @@
.pf6
.ph4
.poka2
-.po4str
+.po4st
.ps2
-.pu3s
-.r4
-.reb5s2
+.r6
+.reb3s2
.re3cha
.rein4t
.reli1
.reli3e
+.res4tr
.rich5t6e
.ro3be
.ro2h
-.ro3m
-.rom4a
-.rö4s1c
+.ro3m2a
+.rö4s
+.rös3c
.rut2
.ru3th
.rü1b
+.rü6cker
.s6
-.sa2c
-.sali1
+.sali3e
.sch4
-.sen3s
+.sen5s
.ser2u
.se2t
.sha2
.si2e
.sim3p4
-.si2te
+.si4te
.ski1e
.spra2
.st6
@@ -269,15 +270,18 @@
.te2e
.tehe3
.te3no
-.te6ster
+.te4st
.th4
.ti4a
.ti2s
+.ti3ta
.to2n
.to4ni
+.ton3s
.to4pl
+.to4st
.to2w
-.tri3e4s
+.tri3es
.ts2
.tu3ra
.tu3ri
@@ -292,9 +296,11 @@
.unen2
.un3g
.uni4t
+.un3s
+.un5s4t
.ur1
.urin4
-.ur3o2m
+.ur5o2m
.uro2p
.ur3s2
.ut2a
@@ -303,16 +309,19 @@
.v2
.ve5n2e
.ve4r
+.vol2
.vo4r
.w2
.wah2
.wah4l
-.wa5re
+.wa3re
.we2
+.weg3
.welt3
.wi4e
.wor2
.wor6t5en
+.wor4tu
.wun4sc
.x4
.xe3
@@ -320,11 +329,13 @@
.ya4l
.z2
.zah2n
+.za4s
.zi2e
-.zin4st
+.zin6s5t
.zuch2
+.zwe4
6a.
-2aa
+4aa
a1ab
aa2be
aa1c
@@ -348,20 +359,22 @@ ab1ar
ab1auf
ab1ä
ab2äu
-3abd
+1abd
a1be
ab1eb
abe1e
+abei3
ab1eil
4a3bel
abe2la
+abe4na
2aber
+a3beri
ab1erk
ab1err
ab1erz
ab3esse
-ab1eß
-2abet
+4abet
2abew
1abf
3abfi
@@ -388,44 +401,42 @@ a2bo.
ab4of
3a2bon
ab3r
-ab5re
+ab5rec
1abs
2abs.
abs2a
2absar
-ab5s2i
-ab5sp
-abs4t6
+ab3s2i
+ab3sp
+abst6
2abst.
-ab7sta
-ab7ste
+ab5sta
+ab5ste
ab3sz
1abtei
2a1bu
ab3ur
2abü
-ab5üb
-3abw
+ab3üb
+1abw
2aby
1abz
2ac.
a2ce.
a1cem
-a3cet
ach1a
ach3ak
-a3chal
+a1chal
ach3au
a1che
a2ch1e2c
ach1ei
-a3chen
-a3cher.
a4cherf
ach3erw
a3ches
4achf
a1chi
+a3chis
ach5l
ach5m
ach3n
@@ -437,7 +448,6 @@ ach1ö
ach3r
ach3spr
ach3su
-a4cht
ach6t5erg
ach4th
ach2t1o
@@ -447,14 +457,14 @@ ach3ü
4achv
2ach3w
ac1in
-4ack.
+2ack.
+a1ckar
ack2en
-ackmu6
-ackmus3
+a3cki
+a4ckin
ack2se
ack3sl
-ack7sta4
-a3co
+ack5sta4
acon4n
2acu
a1ç
@@ -465,32 +475,34 @@ a4d1ac
ad1ama
a2d1an
3a4d5ap
-a3dar
+a3dar3
3a2dä
ade4al
adefi4
ad1ein
ade1ra
-4ades4
-ade3sp
+4ades
+ade3s2p
ades6s
4adi
adi3en
ad2ob
+ado3c
a2dr
ad5rah
4ad3rec
ad4res
ad5ru
-ads2
+ad1s2
ad3sä
ad3sp
+ad3st
ad3sz
-ad2t1
+ad4t1
adt3a
2ae
a1e2b
-a1ec
+a1e2c
a1e2d
a1ei
a1el.
@@ -502,7 +514,8 @@ ae2o3
a1e2p
ae1r
3a2er2o
-a3estri
+a1e2s1
+aes3t
a1e2x
a2f1a
a3fah
@@ -515,7 +528,7 @@ a2f1ec
a2fent
af1erl
af4f5l
-2afi
+2a3fi
2af3l
af3ra
af3rä
@@ -524,15 +537,19 @@ af3rö
af3ru
af3s2a
af2sp
-afs2t
+afs4t
+af3ste
+2aft
af2t1a
+af3tab
+af2tei
af4t3erl
af2t3r
-aft5re
+af4t5re
af2tur
a2f1ur
a1g
-4aga
+2aga
ag1a2b
ag3a2d
ag1ar
@@ -546,8 +563,9 @@ age2nu
age2se
age4si
age4s3p
-ages5s
+ages3s
a4g5esse
+age4s3ti
ag3gl
2agi
3a2git
@@ -569,14 +587,17 @@ a2g3re
a2g3ri
ag4ro
a3gru
-ag4s
+2ags
agsa2
-ag7sat
-ag5säu
-ag6s3p
+ag4sam
+ag4set
+ag6s5p
ag7spi
-ag5sta
-ag5ste
+ag3sta
+ag3ste
+ags4tei
+2agt
+2agu
a2g1und
2ah.
2a1ha
@@ -599,8 +620,9 @@ a2h1ö
ahr1a
ah3re
ah4rei
+ahre6s3
ah1ri
-2ah2s
+2ahs
aht3sp
a1hu
ah1w
@@ -608,12 +630,12 @@ a1hy
2ai
ai1a
aib3l
-aids1t
ai1er
aif2
ai3g4
-a1ik.
+a3ik.
ai3ku
+a2il
ai2lo
a1ind
ai3n4e
@@ -623,21 +645,20 @@ ai2nu
ai3o
ai2sa
a3isch.
-ai3s2e
-ai5se.
-ais4se
-ais5st
+ai5s2e
+ais3s
a2it
a3iv.
a3ivl
a3ivs
a1j
+aje4
2ak.
a2kad
-2a3kam
+2akam
2akar
ak4at
-aka4ta
+aka2ta
2akb
2akc
2akd
@@ -645,7 +666,7 @@ aka4ta
a2kef
a2kes
a2keu
-4a1ki
+2a1ki
2ak3l
ak4la
ak4li
@@ -657,16 +678,15 @@ ak3res
2aks
ak3sh
2akta
-akt2an
+ak3t2an
2aktb
-ak3te
-ak4tei
+ak5ten
2aktik
akt2o
ak4t5r
ak5t6ri
2aktst
-a1ku
+2a1ku
a2kun
4a3kü
1akz
@@ -706,9 +726,12 @@ al2b3l
al2boh
al2br
alb3ru
+alb3s
al2da
al2dä
al3dri
+alds2
+ald3st
al3du
2ale
3a2l1e2b
@@ -717,7 +740,6 @@ a4l1eh
a2l1ei
a4lein
a2l1el
-ale2n
al3ends
a2leng
al2ent
@@ -735,8 +757,8 @@ al3eta
al3eth
a4l1eu
3alex
+al1exi
al2gli
-1algo
2ali
ali4e3ne
ali4nal
@@ -745,19 +767,18 @@ a2l1ins
a2linv
al2k1ar
1alkoh
-alk5s2
+alk3s4
al2lan
al2l3a6r
-al4län
+al2lau
al4lec
al3lend
all5erfa
al3les
alli5er.
alli7ers.
-2allo
+2alo
a2l1ob
-2alog
alo2ga
al1ope
al1orc
@@ -768,10 +789,11 @@ al2ös
al3skl
al3sp
al4spal
+al5s6terb
al2ta
+al3tam
alt3eig
-al2te4l
-al3ter
+al4te4l
al4t3erf
al2tö
al2tri
@@ -800,28 +822,28 @@ a3mie
a3mil
2a3mir
amit2a
-ami3te
-am2mac
+ami5ti
2ammal
am2min
-am4mod
-am2mus
+ammu2
2amo
a2mö
+2amp
amp2f3a2
am3pr
-2ams
+am2s
am3sa
-am4sc
am3so
-1amt.
+am3sp
+am3str
+3amt.
am2t1a
am2t1ä
-am2tel
+am4tel
am4t3ern
am2to
am2tö
-am2t3r
+am4t3r
am2tu
4amu
am3unt
@@ -833,21 +855,21 @@ anadi3
a3nak
2anan
an3ara
-2anas
+2anas2
2anat
an1äs
1anb
-an3cht
+3anbr
+an5cht
4and.
an5de6s
-an2dex
+an2d1ex
2ando
an4d5rü
and4sas
-and6s5paß
an2d1ur
4ane
-an3ec
+an3e4c
a3nee
an3eif
an1e2k
@@ -869,9 +891,10 @@ an2glä
ang5le.
2ango
ang3ra
-1angri
4angs.
-ang6s3po
+ang5sc
+ang6s5po
+1anh
4a3ni
ani3els
ani5ers.
@@ -887,7 +910,7 @@ ank3ra
ank3rä
ank5ti
an2ky
-3anl
+1anl
2anmu
2ann
3an3na
@@ -896,18 +919,19 @@ an5n4e
an3od
an1or
a1nö
-3anr
-anrö5
+1anr
2ans.
3ansä
1ansc
-an3s2en
-an2seu
-2ansk
+an5se
+ans2en
+an6seu
an3skr
an2s1pa
1anspr
-an5s2te
+an3s2t
+an5stei
+an5str
an3s2z
2ant.
ant2a
@@ -919,7 +943,7 @@ an3th
ant2he
1anthr
2anto
-3antr
+1antr
an2tro
3antw
4a3nu
@@ -932,16 +956,15 @@ a1nü
3anzah
3anzei
anz5erst
-4anzg
an2z1i4n
3anzu
3anzü
an2zw
-ao1i4
+ao1i
a1op
a1or
-a1o2s
-aot4
+a1o4s5
+aot2
a3ot.
ao3ts
a1ö
@@ -949,13 +972,14 @@ a1p
2ap.
4apa
2ape
-3a2pé
+a2pé
ap2fa
a3pfl
a3phä
ap1hel
2a2p3l
ap2n
+apo1s
a2pot
ap3pl
2apr
@@ -963,7 +987,7 @@ ap3pl
2ar.
2a1ra
a3ra.
-ar2a1b4
+ar2ab4
ar3abt
ara3d2
a2r3al
@@ -971,6 +995,7 @@ ar1ang
ar1ans
ar3anz
a2r3app
+ara4st
a2r1au
a1rä
2arb.
@@ -985,7 +1010,6 @@ ar2b5l
2arbr
ar2bre
2arbs2
-arb5se
arb3sp
2arbt
2arbu
@@ -999,7 +1023,7 @@ a2rea
are5b
a2ref
ar1eff
-are3g
+a4re3g
ar1ehr
a2rein
a5ren
@@ -1029,7 +1053,7 @@ ar1ins
ar1int
a3riu
2ark
-ark3amt
+ark5amt
ar2k1ar
ark3aue
ar2kl
@@ -1037,16 +1061,17 @@ ark3lag
ar2kor
ark1r
ar4kri
-arks4
+arks2
ark3sa
ark3sh
ar4les
2arma
arm2ä
+arm3erk
arm2or
2arn
ar5n2e
-4a1ro
+2a1ro
ar1ob
ar3o2d
a3rodo
@@ -1061,12 +1086,15 @@ ar2r3ad
arre4n
ar2rh
arr3he
-2ars
+2ar2s
+ar3sa
ar4schl
ar4schr
-ar3se
+ar5se
ar3s2h
ars3k
+ar3sta
+ar3su
ar2tau
1artd
ar4t3erl
@@ -1074,8 +1102,7 @@ art2ho
artin2
2arto
ar2t3r
-ar3tres
-4arts
+2arts
2a1ru
ar1ums
ar3ü
@@ -1087,33 +1114,25 @@ ar2zä
1arzt
ar2z1w
2as
-as2a
-as3ab
-as1ala
+as2al
+as3ala
a4s3au
-asaus1
a2s1ä
-a2sca
+a6sca
a4schec
asch3la
a2schm
-4a3se
-a4seb
+4as2e
+a2seb
ase3le
aseli5
-a4s1e2m
-a5s2en
-as2er
-a5s2es
-a4sex
+a2s3e2m
+a3ses
4ash
a3s2hi
a5si.
-4a5sis
-asi4st
+4asis
a3skop
-as3m
-aso1
as1o2f
a3sol
a3som
@@ -1125,54 +1144,52 @@ as3pe
as2ph
as2po
as2pu
-as3s4a
-as4sä
-as3se
-as4sei
+as3s2a
+as5se
+as6sei
asse3le
as3s2i
-as3so
+as5so
as2s1p
-as4st
-as6s1to
-as5str
-4asta
-as2te
-as3tec
-a4s3tep
-as4ti
-as2to
-4as2tr
+as2st
+ass3ti
+as4sto
+as3str
+a2st
+4a4s1ta
+a5s4tas
+as2tau
+a5stä
+as3te
+as3ti
+4a3str
ast3rau
-a4st3rä
-a4st3re
-a4strol
-a2stum
-a3su
+ast3rä
+as4t3re
a2sü
3asy
+a1ß
aße2
2a1t
-4ata
+4ata1
a2t1ab
ata2be
-at2a1f
+at2af
at4a5g
at1akt
-ata1la
a3tam
at1apf
-a5tas
a2t1au2
-a5tau.
+a3tau.
at1än
at2c
-4ate
-a2teb
+4a3te
+a4teb
at1eig
a4teli
-a2tep
-a2tew
+a4tep
+ater3st
+a4tew
4atf
4atg
at2he
@@ -1182,7 +1199,6 @@ a4thr
at1int
3atm
4atmus
-a3to.
ato4man
a2t1ort
a2t1ö
@@ -1194,29 +1210,25 @@ at3re
at3rom
at2s
at3sc
-at5sche
-at5schü
-ats1e
at4set
-ats1in
ats1p
-at4st
-at5stä
3attac
att3ang
at2t1au
at2tei
at5thä
+att3rau
+at4t3rä
atts4
-at3tu
4atu
a3tub
atu4n
atu3ren
atu4rer
at3w
+4atz
atz1er
-at2z1i
+at2z1in
atzt2
atz3th
a2u
@@ -1235,7 +1247,7 @@ aue2b
aue3re
au5erein
au5erl
-aue2s
+aue4s
au3et
au2fa
auf1an
@@ -1248,13 +1260,13 @@ au2fo
2aug
au3g6e
4augeh
-2auh
2au1i
au2is
4auj
au2kl
aule2s
aul3ese
+aul4s
au3lü
4aum
au2mal
@@ -1263,7 +1275,8 @@ au2mau
au2mer
au2m1o
aum3p2
-aum5str
+aums2
+aum3st
aum3sz
4au3n2
au4nio
@@ -1275,21 +1288,18 @@ aup2
2au3r2
au2s1ah
ausan8ne.
-2au2sc
+4au2sc
au3schl
au3schw
+2ause
aus3erp
au4s3erw
au2so
au2sp
-auss4
-aus7sa
+aus3s4
3aussag
aus4se.
-aus3so
-au4st
-au6stec
-aus3tie
+au2st
aus3tri
2aut.
au3tan
@@ -1297,9 +1307,8 @@ au2tä
aut1äu
2aute
au4t3erh
-au3tes
3auto
-2auts
+2auts4
aut5st
2aux
auz2w
@@ -1308,16 +1317,17 @@ auz2w
av4a
ava3t
a2vr
-av2s
2a1w
awi3e
a1x
-ax2am
+ax2a
+ax3an
ax2e
-axi4s
2a1ya
a1yeu
+ays2
aysi1e
+ay3ste
2a1z
az4a
azo3
@@ -1332,27 +1342,27 @@ az2u
äch3l
ä2chr
äch2sp
+äch4st
ä1chu
+ä1ck
ä1d
-ä2da
-ä2d1ia
+ä3di
+ä4d1ia
+ä3do
ä2d3r
-äd2s
-2ä1e
+2ä3e
äf2fl
äf5l
äf3r
äf2s
-äft4s
+äft4s3
ä1g
äge1i
+äges4
ä2g3l
ä3g2n
ä2g3r
-äg4s2
-äg5sa
-äg5ste
-äg5str
+äg3s2tr
1ä2gy
äh1a
2ä3he
@@ -1364,10 +1374,10 @@ az2u
2ähm
äh5ne
äh5ri
-2äh2s
+2ähs
2äht4
äh3tr
-ä1hu
+ä3hu
äh1w
ä1im
ä1is.
@@ -1383,37 +1393,35 @@ az2u
äle3ru
äl2l1a
äl2p3
-äl2s
-äl3se
+äl2sc
ä1lu
ä3me
ämi3en
2äml
-äm4ma
-äm2s
ämt2e
2än.
än2dr
-2äne
+2ä3ne
äne2n1
än2f3
2änge
än2gl
än2gr
-äng5se
-äng5ste
+äng3se
2ä3ni
än5k2e
än2k3l
än2kr
+änk2s
än5n4e2
2äns
-än4s1c
+än4s3c
änse3h
ä1on
ä1pa
äp2pr
-äp4s1c
+äp4s3c
+äp2st
1äq
ä2r3a2
är4af
@@ -1427,61 +1435,57 @@ az2u
ä1ri
är1int
är2k5l
-ärme5s
+ärk2s
är1o2
ä1rö
ärse2
-är2seb
-är4si
+är6si
+är2st
ärt4e
-ärt4s3
+ärt2s3
ä1ru
är3ü
är2z1w
äs2a
-ä3s4e
+äs4e
äse3g
äse3re
äser4ei
äse4ren
äse3r2i
äse3t
-ä3si
äskop2
ä3s2kr
ä2s1p
-äs4s1c
-äs3se
+äs4s3c
äs4s3erk
-äs6st
-äs2te
-ä4str
+äs4st
+ä4s3t
+äs5ti
+äs4tr
ä3su
ä1ß
äß1erk
2ät
-ä2t3a2
+ä4t3a2
ä3te
äte1i
äte2n
-ä2th
ät2ha
-ä1ti
ä1to
ät1ob
ät3r
ät2sä
ät4schl
ät4schr
-äts1ei
ät2s1i
äts3l
ät3so
äts1p
-ät4st
-äts3te
+ät2st
+äts3ti
ät2tr
-ä1tu
+ä3tu
ät5ze
äu2br
äu1c
@@ -1492,26 +1496,27 @@ az2u
2äul
2äum
äu2ma
-äum4s
+äum2s
äums1p
ä2u3n2
2äu5r
2ä3us.
äu2sc
+äu6schä
äu4schm
-äu3se
+äu5se
ä1usg
ä1usk
ä1usn
äu2sp
-äus4s1c
+äus4s3c
1äuß
äu2tr
4ä1v
1äx
ä1z
â1t
-4b.
+6b.
1ba
2babs
ba3char
@@ -1522,8 +1527,7 @@ backs4
3bah
bah2nu
bah5re
-bai1
-bais2
+bais4
ba2ka
ba2k3er
ba2k1i
@@ -1531,9 +1535,8 @@ bak5l
ba2kra
3bal
ba1la
-bal4leh
+bal4l3eh
bal6lerg
-bal6lig
bal3th
2b1am
ban2a
@@ -1552,22 +1555,19 @@ bar3b
b2ard
bar3de
ba2rei
-ba3r2en
+bar2en
bar3zw
3bas
-ba7sa
+ba5sa
ba2sc
-ba6str
+ba4st
ba2to
-ba3tor
bau3b
bau3g
-bau3s2k
-bau3sp
-bau5str
+bau3s
+bau1s2k
ba1yo
-3b2äc
-bä1ch
+3b2ä1c
1bäe
1b2är
1b2äs
@@ -1575,10 +1575,10 @@ bä1ch
b1äug
bäu3s
4b1b
-b5ba
-bbau3sc
+b3ba
+bben3s2
bbe4p
-b5bi
+b3bi
bb5ler
b2bli
bb3lin
@@ -1587,16 +1587,18 @@ b3blö
bbru2
bb2s
bbu1
-2b5c
+b7by
+2b3c
2b5d
+bde1st
+bdo3
bdu3s
1be.
3be3a
be5an
be4au.
b2ebe
-1bec
-be1ch
+1be1c
be2del
bedi4
be1eh
@@ -1615,18 +1617,16 @@ be1ind
be1in4h
bei3sc
beis2e
-bei5st
+bei3st
beit2s
3bek
be3las
-be5le
be3lec
be3lei
-be6l1en
-be6let
+be2l1en
+be2let
be3li
-bel5la
-bel5li
+bel3la
bel3sp
bel3sz
belt4
@@ -1634,17 +1634,18 @@ bel3ta
bel3tr
1bem
1ben.
-be4na
+be3na
+be4nal
ben3ar
+be4nau
be3ne
ben4erg
-be4nerl
be4ners
ben3g
be3ni
-ben2se
+ben4se
ben2sp
-ben2su
+ben4su
ben4th
3b2enti
b1ents
@@ -1666,21 +1667,21 @@ ber3iss
ber3na
b1ernt
be1rop
-ber5st4a
+ber3st4a
ber3th
be3rum
-1be3s
-be4s1er
-be4sk
-be5slo
+1be1s
+be3sa
+be2s1er
+be3slo
+be3spo
+be3spr
bes5s4e
b3esst.
bes3sz
-bes2t
+bes2to2
be4s3tol
-be4stor
-be4sum
-be1s2ze
+be3s4ze
3bet
be2tap
be3tha
@@ -1690,20 +1691,19 @@ be1ur
1bez
2b5f4
bfal2
-bfrä5
-4b5g4
-bga4s1
-bgas3t
+4b3g4
+b5ga
bge3
bge5n
-bge5s
-2b5h
+bges4
+2b3h
1bi
bi1ak
bibe4
bi2e
bi3ens
bi3ent
+bie2s
bi3k2a
bi2ke.
bi2kes
@@ -1719,47 +1719,44 @@ bi3n2e
bi2o3
bi3on
biri1
-bi3se
+bi5se
bi2sol
-bis4s1c
-bi2s1t
-bi4stü
+bis4s3c
+bi4st
bi2t
b2i3ta
bi3te
-bi3ti
bi3to
bi3tr
-bit5st
-2bitu
-bi3tum
-b2i3tus
+bit3st
+2bi4tu
+bi5tum
+b2i5tus
biz2
bi3za
4b3j
bjek4to
-2b5k2
+2b3k4
b2l2
2bl.
-b4la.
bla3b6
4b5lad
b6lanc
6blasser
b6latt
b3law
-1ble.
-3ble2a
+3b4le2a
b3leb
2b5leg
b3leh
2b3leid
b5lein
+blei3sc
ble3l
-1b4lem
+b4lem
b4ler
b5lese
-ble3sz
+ble5sz
3b4let
2b3lich
3blick
@@ -1771,15 +1768,17 @@ b4lit
b6loc
b5lok
2b3lun
+blu4ter
3blü
-2b5m
-4b5n2
-bni4
-bnis1
+2b3m
+6b3n2
+bni2
+bnis3
1bo
bo5as
bo2b3l
bo3b4r
+bo2c
bo3ch2
bo3d2
bo2e3i
@@ -1797,6 +1796,7 @@ bo4rä
bor2d1i
bor2d3r
bo2rei
+bor2s
b1ort
bor4tei
bor2t3r
@@ -1806,20 +1806,20 @@ bo4s3p
3bot
bote5n4e
bo3th
-bot4st
+bot2st
bö2b3
2b3öf
bö3sc
-2b5p2
+2b3p2
bpa4g
-2b5q
+2b3q
b2r4
2br.
b4ra.
2b3rad
-b4rah
-b4ra3k
-bra5st4
+b6rah
+b6ra3k
+bra1st4
2bre.
6b5rechte
2b3ref
@@ -1828,39 +1828,45 @@ b3reif
b3rek
3brem
2b3rep
-b6rer
-2b3riem
+b4rer
+b4ri
+2b5riem
bri2er
-2brig
-b4rio
-bro1
+2b5rig
+b5ris
b5roh
2b3rol
b4ruc
-bru6s
brust1
4b1s
bs3ad
+bs1an
b3sand
bs3ar
-b5sat2
+bsat2
b3sä
-b5sc
-b6schan
+b4sär
+b3sc
+b4schan
b7schl
+bs4cu
b3se
b5se.
bs1e2b
-bs1ein
b5sel.
bs1ele
bse2n
+b5sen.
bs1ent
bs1er
-bs3e4r3in
+bs5e4r3in
b5ses
b5set
-bsi2t
+bs1ex
+bsi4t
+bs5ko
+bs2ku
+b4sl
b2s1of
bs1op
bso2r
@@ -1868,42 +1874,44 @@ b2sö
bs1par
bs2pl
b3s2pu
-bs3s2
+bs5s2
bs2t
bst1a2b
bst1ac
bst1ak
bst3ank
-b5stä
bs3tät
+bs4tem
bst1er
-b4stern
bst1h
-bs3tip
-b5stra
-b4s3trä
+b3sto
+b2s3trä
bs3treu
b3stu
-bs3ty
+b3stü
+b4stüb
b2s1un
-bs3w
4b1t
-b5ta
+b3ta
btal3
-bta4st3r
+bta4s
+btast3r
b3tä
b5te
b2t1h
+b3ti
bti2s
b3to
-b5tr
-b5tu
+b3tr
+bts2
+b3tu
btü1
b2u
bu2chi
bu2e3
bu2f
bu5li
+bul2la
2b3umk
bu3na
bunde6s
@@ -1915,8 +1923,6 @@ bus3cha
bu3se
bu4s1er
bus1p
-bu6sterm
-bu4s1tr
bus1u
bu3ße
1b2ü
@@ -1925,18 +1931,19 @@ büge4
bügel3e
2b3v
2b5w
-bwa5re
-1by1
+1by
+by1a
by3p
-by2t
-by3th
-2b5z2
+by4t
+by5th
+2b3z2
+b5ze
bzei2t1
2c.
1c4a
-2ca1b4
+2ca1b
ca1ch
-cae3
+ca2e3
3caf
ca3g4
ca1h
@@ -1949,7 +1956,8 @@ ca3pel
3car
car3n
carri1
-ca3s4a3
+ca3s2a3
+ca4st
ca3th
ca1y2
cä3
@@ -1968,14 +1976,15 @@ cen3ta
ce3n1u
1cer
ce1ro
-ce5sh
+ce3sh
+ce1st
1cet
-4ceta
+2ceta
cet3am
ce3ty
ce1u
1cé
-c1f
+2c1f
c4h
4ch.
2chab
@@ -1983,30 +1992,29 @@ ch3abi
ch1ah
ch1ak
ch2anb
-3chanc
+5chanc
ch1ang
ch3anst
-2chanz
-1chao
+4chanz
+3chao
ch1ap
-2char.
+4char.
ch3arm.
3charta
cha2sc
chasi1
-1chato
+3chato
+4chatu
ch1ärm
ch1äs
1châ
2chb
-2chc
+4chc
2chd
ch3e4ben
ch3echt
-1chef
-3chef.
+3chef
che2fe
-3chefs
4chei
ch1eim
che4ler
@@ -2015,16 +2023,17 @@ che4ler
cher3a
che3rei
6chergeb
+2cherö
ch1ess
2ch3eta
-ch1ex
+2ch1ex
1ché
2chf
2chg
2chh
ch1ia
-1chia.
-1chias
+3chia.
+3chias
6chind
3chines
ch1inf
@@ -2040,72 +2049,103 @@ ch3lein
2ch2m
ch4mu
2chn4
+2chob
+cho6cker
cho2f
ch1off
ch1oh
ch1orc
2chp
ch2r2
-2chre
-chre5s
+4chre
ch3rh
3chron
4chs
-2cht
-ch5tes
+4cht
2chuf
2chuh
2chum
2ch1unf
-chus4si
-2chü
+2chunt
+4chü
2chv
2chw
2chz
1ci
ci1c
-cil3l
ci2s
c1j
-2c4k
+c4k
+4ck.
ck1a
-ck3aa
-ck3am
-ck3an
+3cka.
+ck5aa
+2ckac
+2ckal
+ck5am
+2ck3an
cka4r1
+2ckau
ck1ä
+4ckb
+2ckc
+2ckd
+1cke
+3cked
+4ckeff
+4ckeh
ck1ehe
-ck3ei
-ck3ense
+4ck3ei
+3ckel
+3cken
+4ck3ense
ck1ent
+4ckentw
cke2ra
cke5reig
-ck1err
+4ckerhö
+4ckerke
+2ckero
+2ck1err
cke2s
-ck1ese
-ck1id
+2ck1ese
+2ckex
+4ckf
+4ckg
+2ckh
+1cki
+2ck1id
ck1im
ck1in
-ck5l
-ck3n
-ck1o2
+3ckis
+2ckk
+2ck5l
+2ckm
+2ck3n
+2ck1o2
ck1ö
-ck5r
+2ckp
+2ck5r
+4cks
ck3spo
-ck5ste
-ck4stro
-ck3t2e
+4ckt
+ck5t2e
ck3ther
-ck1um
-ck1up
+3cku
+4ck1um3
+4ckunt
+4ck1up
+2ckv
+4ckw
+1cky
+4ckz
3c6l2
-clet2
+clet4
clo1c
c2m
-1co
-3coa
-3coc
-co1ch
+3co
+co2c
+co3ch
co2d
co4der.
co3di
@@ -2123,27 +2163,30 @@ co1ra
co4re
cor5t
cos4
-co4st
-co2te
+co4te
+cô4
2cp
-c1q
+2c1q
c4r2
cre2
cre4mes
cry2
-2cs2
-c2si
+2c2s
+cs2a
+c3se
cst4
+c3s2tr
2c1t
cte3e
-cti4
-ction5
+c3ti4
+c3to
ctur6
-1cu
+3cu
cu2p3
cup1e
cussi4
1cy
+2cz
4d.
3da.
da1a
@@ -2161,10 +2204,10 @@ da3dr
da1er
2d1af
d1ag
-dagi4o
+dagi4
dah3l
da1ho
-3d4ai4
+3d4ai
da1in
da1is
da1l2a
@@ -2175,7 +2218,6 @@ da1lö
2d1amma
2d1ammä
damo3
-d2amp
damp7f8erf
2d1amt
d2an.
@@ -2196,21 +2238,22 @@ d2aph
4dapp
da2r3a
2darb6
-dar3bl
3d2arl
dar2ma
dar2m1i
da2ro
2darr
+dar3s
2dart
d1artg
da2ru
d2arw
+das4
da3s2h
+da5s2t
3dat
da3ta
dat2e4
-da3tei
4d3atl
4datm
3dau3e4
@@ -2219,26 +2262,27 @@ da3tei
2d1äh
2d1ämt
2d1änd
-2d1äng5
+2d1äng
2d1äp
2d1ärz
dä2um
dä1us
-2d7b
+2d7b6
dbu2
2d1c
4d3d2
+ddar2
ddar4m
d5de
1de
de3am
de3an
de3as
-de5a2t
-de3b4
+de5a4t
+de3b6
4d1e4ben
-3dec
-de1ch
+3de1c
+de2cka
deco3
de1e2
2d1eff
@@ -2250,7 +2294,6 @@ de3ho
d2eic
3d2e1im
de2l1a4g
-delat5
de4l3aug
de4l1än
del1ec
@@ -2260,37 +2303,38 @@ de3l2ei
de2len
2d1elfm
3delik
-del4la
delle2
+del4leb
del4lei
-del2lö
de2l1ob
de3lor
de2lö
-del2s1e
+del2s5e
del2so
del2s1p
+del5ster
delt4
del3ta
-del3te
del3tr
de6ments
2d1emp
d2en.
+dend2
+dend4s
de4n3end
den3g
de2ni
den4k5li
-4densem
+den3sc
den4sen
-den6s5tau
+dens5tau
den3th
2dentw
de2ob
2deol
de1on
deo4no
-depi4so
+depi2
d4er.
de1rad
de2r3ap
@@ -2302,7 +2346,6 @@ de3r4erb
de3r4erf
de4r3ero
4d3erhöh
-d4eri
de5ric
de3rik
4d3erklä
@@ -2311,6 +2354,7 @@ de2rop
d3ersat
dert2a
der6t5end
+dert2s
de3ru
de4ruh
de4rum
@@ -2324,14 +2368,17 @@ de3se
des1en
des1in
des1o
-des3p
-des5s4
+des1p
+des3pot
+des3s4
+des5se
dest5alt
de5stang
-de5ste
-de6s3tei
-de5sti
-de7stin
+de5star
+de5stat
+de7stel
+de4sto
+de3str
dest5rat
de5stri
de5stro
@@ -2345,12 +2392,14 @@ de2xis
2dexp
2d3f
2d1g
+dga2
d2ge.
d3gem
dge2ta
dge6t5e
d3gl
2d1h2
+dhas2
d2his
d3hu
1di
@@ -2366,16 +2415,16 @@ dich3te
di2de
di2e
di3e2d
-die5ner
+die3ner
di3eni
di3ens.
dienst5r
-die4s1c
+die4s3c
die2t5
-dige6s
+dige4s
di3gn
di3ka
-dil4s1
+dil2s3
2d1imb
din2a
2d1ind
@@ -2395,7 +2444,10 @@ di2ris
2d1irl
2d1isr
dist4
+di4ste
di2ta
+di3te
+di4tei
di4teng
di4t3erl
di4t3erm
@@ -2403,6 +2455,7 @@ di4t3ers
di2t3r
di2tu
diz2
+di3zi
2d1j
2d1k4
4d1l
@@ -2422,7 +2475,8 @@ d1o2be
dob4l
3dobr
3doby
-do1chi
+do2c
+do3chi
3dog
do3ha
3dok
@@ -2430,7 +2484,7 @@ dol3l2
do2mar
3don
do5n4a
-doni1
+doni1e
do2o
4d1opf
d2opp
@@ -2446,9 +2500,10 @@ do2rie
d2orp
d2os.
do3sp
-dos3s4
+dos3s
dost3
-do6sta
+do4sta
+do3str
3dot
dot4h
do3un
@@ -2457,12 +2512,13 @@ do1y2
d1öf
d1öl1
3dör
-dö4s1c
+dö4s3c
2d3p2
2d1q
d2r4
3d4ra.
2d3rad
+drag4
d4rah
2d5rahm
3d4ram
@@ -2497,18 +2553,16 @@ d3rieg
d4rif
d3rind
3drisc
-2driß
3d4rit
4dritu
2drob
d3roc
2d3rod
d4roi
-dro3ma
2d3rot
d3rou
2d3rov
-drö4s1
+drö4s3
3d4ru
d5rub
4d5ruf
@@ -2516,20 +2570,21 @@ d5rub
4d5rut
3d4rü
drü1b
-2d1s
+drü5cke
+2ds
ds3ab
-d4s1amt
+d4s3amt
d2s3an
ds3assi
-d2sau2
+d2s1au2
d2s1än
4dsb
d4schin
d2s1e2b
d3sec
d2s1ef
-d3s2eig
-d2s1ein
+d5s4eig
+d2sein
d2s1eng
d2s1ent
d2s1erf
@@ -2541,12 +2596,12 @@ d4s1eta
d3s2ha
ds3han
d3sho
+ds3hu
d2s1im
ds2inf
d3s2kan
d3skul
4dsl
-ds3m
d2s1op
dso2r
ds1ori
@@ -2557,28 +2612,33 @@ d2s1pä
d3s2po
d4spro
dss2
-ds5st
+ds3st
dst4
-d4s1tab
+d2s1tab
d4s3täti
-d6stea
-ds2til
-d5stip
-d4s1tis
-d2stod
+d5stei
+d5stell
+d3s4tern
+ds1th
+d1s2ti
+ds4til
+d3stip
+d1str
d5stre
+ds2tri
+d1s2tu
ds1ums
d2sun
+d1sy
ds2zen
4dt
d1ta
dt3a2d
d1tä
-d1te
-d3tea
+d5tea
dte5na
dt3ha
-d1ti
+d3ti
d1to4
d1tö
dt3r
@@ -2589,7 +2649,6 @@ dt5sc
dt3sp
dt5str
dt3t
-d1tu
d1tü
1du
du1alv
@@ -2599,7 +2658,7 @@ du3e
du2f
2d1ufe
2d1uh
-du1i4
+du1i
3dum.
d1umb
2dumd
@@ -2618,33 +2677,39 @@ dun3d
dun3ke
dun2kl
2dunr
+dun2st
2dunt
du1os
dup4
-dur2c
+dur2
2d1url
-3dus
-du2sc
+3du2s
du3scha
+du3se
+dus1t
2düb
3düf
3dün
3dür
+dürn3
2d1v2
2d1w
+dwa4
dwa2l
-dwe4s
+dwes4
dwest1
dy3n
2d1z
-6e.
+4e.
2e1a
e3a2b
+ea2c
eadli4
e2ag4
ea2ge
ea3gl
eakt4
+eak3to
e2al
e3al.
e3alb
@@ -2665,7 +2730,6 @@ eam3a
e4ame
eam1o
eam3to
-eam3tu
ea2na
e5and
e4ano
@@ -2678,9 +2742,7 @@ e4are
e5a6rene
e3arm
e3art
-ea6se.
-eas5s
-ea4st
+eas3s
e4at.
eat4e2
eate4r
@@ -2692,7 +2754,6 @@ eau3b
e3au2f
e3aug
e3ä4
-eäng5
e1b
2eba
e3b2ak
@@ -2700,7 +2761,7 @@ eba3ra
ebe2i
eb4en
e3beng
-eben4s3e
+eben6s5e
2ebet
2ebl
eb5ler
@@ -2714,23 +2775,22 @@ ebö4s
e3bra
eb3rei
eb2s
-eb6sche
+ebs1au
eb4se2
ebs1i
ebs1o
ebs1p
ebs3pa
-eb6stät
-eb4stec
-ebs3tei
+eb4stät
+ebs5tem
ebs3th
ebs3ti
-ebs3tot
+eb3str
ebs1u
e3bu
ebu2t1
eb3üb
-2eca
+2e3ca
e1ce
ech1ä
2e3che
@@ -2749,19 +2809,22 @@ e1chu
ech1uh
ech3w
eci6a
+e1cka
eck3se
2eckt
2ecl
-e1cr
+2eco
+e5cr
+ecs1
2ect
e1d
ed4dr
ed4e
-ede4c
e3dei
ede3n2e
+eden2s
eden4se
-eden4s3p
+edens3p
ede2r
ed2ge
edi4a
@@ -2771,29 +2834,29 @@ ed3s2ä
ed2s1es
ed2s1o
ed2s1p
-ed5sta
-ed4s1tr
+ed2s1tr
ed2su
e3dy
-4ee
+6ee
ee5a2
eeb4l
ee2ce
ee1ch
+ee2cho
+ee2ck
eede3
-eeds2
+eed3s2
ee1e
ee3ei
e1eff
-eef5s
+eef3s
eeg4
e1ei2
eei3e
ee1im
ee3ing
-eei3se
eel2e
-e1elek
+e1e2lek
ee3len
e1emp
e1en
@@ -2806,23 +2869,25 @@ e1e2pi
e2e1ra
e1erbt
e1erd
-eerde3c
ee3r2e
ee4r3eng
-eere4s5
+eere4s
ee4ret
e2e1ro
-ee1r2ö5
+ee1r2ö
eer3öf
eert2
e1ertr
e2erü
e1erz
-ee5sh
+ees2
+ee3sh
+ees3k
ee3st
ee2tat
ee2th
ee1u2
+eewa4r
e1e2x
e1f
2ef.
@@ -2859,7 +2924,7 @@ ef1rol
ef3rom
ef3rot
efs2
-ef7sc
+ef5sc
ef3so
ef3sp
ef2tan
@@ -2871,21 +2936,22 @@ e1g
e3ge
ege4n1a
ege2ra
-ege4s3to
-ege4str
ege1u
-eg3la
eg4li
eg3lo
eg3lu
e2gn
eg3ni
-eg6sal
-egser1
-eg3spe
-egst6
-eg6sto
+eg4sal
+eg6ser1
+egs2pe
+egs2t6
+eg1ste
+eg4sto
+eg1str
+egs3trä
2e3gu
+egus1
2e1ha
eh1ach
eh3aka
@@ -2899,6 +2965,7 @@ ehen2t3
1e2hep
ehe1ra
eher4an
+ehe3str
e3h2i
eh3int
eh1lam
@@ -2916,17 +2983,15 @@ e1ho
e3hol
ehr1a
ehr1ä
-ehr3ec
+ehr3e2c
eh2r3ei
eh1ri
eh1ro
ehr1ob
ehr1of
-eh2s2
-eh3se
+ehr5sch
+ehs2
eh3sh
-eh3si
-eh3so
eh3sp
eh3te
e1hu
@@ -2939,10 +3004,9 @@ e1hy
2ei3a2
4eib
ei2b3l
-eibu2t
+eibu4t
ei4b3ute
ei2cho
-eichs7test
eich5te
e2id
ei2d1a
@@ -2953,7 +3017,8 @@ ei3dra
ei1e
ei3el
2eien
-eie4s
+eien3st
+ei3erv
ei3et
1eifr
ei3g2a
@@ -3016,15 +3081,13 @@ ei2sä
ei4s3erw
ei3sp
eis2pe
-ei4str
-ei2sum
+ei3sto
ei2ta
2eitä
-ei3ten
-ei2t1h
+eit1h
ei2tro
eit3t2
-eit3um
+ei4t3um
2eiu
2e1j
e1k
@@ -3040,16 +3103,18 @@ ek4l
ek5lip
ek4n
2ek2o
+ek3s4t
2ekt
ekt4ant
ekt3erf
ekt3erg
ek4t3erz
-ekt2o
+ek3t2o
e3k2w
2e1la
e3lab
el3aben
+ela2c
el1af
el3agi
ela2h
@@ -3062,12 +3127,13 @@ e2l3anz
el1ap
e2l1a2r
el5ari
+ela4s
el3asi
el3asp
e3law
2e1lä
-elb4
1elbis
+elb4l
el2da
eld5erst
eld3erw
@@ -3075,7 +3141,8 @@ el3des
el3dr
elds2
e5le.
-elea4
+elea2
+ele4c
2elei
e3leie
e6l5eier.
@@ -3104,6 +3171,7 @@ e3let.
e2l3e4ta
2elev
ele2x
+el1exi
el3fe
elf3ein
elf4l
@@ -3114,16 +3182,15 @@ e3lie
e2lim
eli4n
el1ita
-elks2
-el3l2a
-el4läu
+ell2a
+el3lan
el5le.
ell3ebe
el4l3ein
ell3eis
el3les
-el2lic
-el3l2in
+el5lin
+ell5sp
elm2a
2eln
el5na
@@ -3141,20 +3208,20 @@ e1lö
el2san
el2ser
el2spr
+els6tern
el2su
el2ta
-el3t2ak
+el3tak
elte2k
elt3eng
-el3tes
-elt3in
+el4t3in
el2to2
el2t3r
el3tri
el3tro
elts2
elt3sk
-elt3sp
+elt5sp
2e1lu
e2l1um
e3lung
@@ -3167,7 +3234,8 @@ el3zwe
2ema
e2m3ad
ema2k
-e2m1anf
+em1anf
+e3mann
em1ans
3emanz
e5mä
@@ -3176,13 +3244,13 @@ em4d3a2
eme4n
emen4t3h
e2m1erw
+eme2s
3e2meti
em1ex
em1im
em1int
-emi3te
+emi5ti
2emm
-em2map
emma3u
e3mon
e2mop
@@ -3197,7 +3265,7 @@ em3t2
e2na
4ena.
e4na2b
-2e5nac
+2e3nac
e3nad
e4naf
4enah
@@ -3207,6 +3275,7 @@ ena3l2i
4en1am
en4ame
e4nand
+e5nann
en3anz
en1ap
e4nar
@@ -3221,16 +3290,18 @@ e3näc
en1är
en1äu
en2ce
-en4d3ess
+en3del
+end3ess
en3do
end4ort
end3ras
-end5si
+end7si
end3s2p
end3sz
en3dum
2ene
-en1ec
+en1e2c
+ene4ck
e2nef
en1ehr
en3ei.
@@ -3243,7 +3314,6 @@ e5n4entr
en1epo
4ener.
e4n1erd
-e4nerf
3e2n3erg
e4n3erh
4e3neri
@@ -3256,12 +3326,10 @@ en1ers
e2n3ert
e2n3eru
e4n1erw
-en3erwe
-e6n3erz
+en3erz
e4n3ess
en3eta
en3eth
-ene3tr
en1eup
e4nex
en3fa
@@ -3272,8 +3340,8 @@ en5g2i
en2gl
en3glo
1engp
-eng5s
-eng7sc
+eng5sc
+eng3se
2eni
e3nic
e4n1id
@@ -3287,8 +3355,8 @@ e5nit
en3k2ü
e2n1ob
enob4le
-e2n1oh
-e3nol
+e2n3oh
+e3n4ol
eno2ma
en1on
e2n1op
@@ -3303,19 +3371,17 @@ e6nr
en2san
en5sche
en7schen
-en2seb
+en4seb
1ensem
ens3eng
en3sho
en2sid
-en3ska
+en3s2ka
en3s2po
enst5alt
en4s3tät
-en6s5test
4ensto
-en7stric
-ens5trie
+en3stoc
en5t4ag
en3tanz
1entd
@@ -3368,9 +3434,9 @@ e3ord
eorgi1
e3ort
e3orw
-eos2
+eo3s2
e3os.
-eo5st
+eo1st
eo3ul
e1o2v
e1ö2
@@ -3381,13 +3447,13 @@ e3p2f6
1episo
ep3le
e2poc
-epor5te
ep2pa
ep4pl
ep2pr
ept2
ep3ta
ep4tal
+ep5ti
e1q
er1a
e5ra.
@@ -3447,7 +3513,7 @@ erd3erw
4e5re.
e3rech
er3echs
-er1eck
+er1e4ck
ere4dit
er1eff
er1e2h
@@ -3483,7 +3549,6 @@ e2r1erw
4eres
e5res.
er1ess
-er1eß
er3e4ti
er1eul
ere3us
@@ -3493,16 +3558,18 @@ er3fä
3ergebn
4ergehä
erg3ise
+erg3s4
e2r3h
3erhab
-2e1ri
+4e1ri
e2riat
e3rib
-4e3rie
+6e3rie
eri5e4n3
+erien5e
e5rif
erik6
-4e3rin.
+6e3rin.
er1inb
er1ind
e4r1ini
@@ -3512,8 +3579,8 @@ e4r1int
e3rio
er1ita
2erkol
-erk3te
-erk3tr
+erk5te
+erk5tr
4erl.
3erlebn
4erln
@@ -3521,7 +3588,7 @@ erm2
er3ma
erm3ers
er3nan
-er2n1os
+er2n1o4s
e1ro.
er3oa
er1ob
@@ -3541,18 +3608,19 @@ e1row
e1roz
er1ö2
e1röh
-2erök
-erö4s
+4erök
er5p
er3ra
+er5rä
2errü
er3sa
-ers4au
-er3se
-er5s2i
+ers2au
+er5sen
+er7s2i
er3sk
er3smo
er3sn
+er3sum
er3s2z
ert3abe
ert2ak
@@ -3565,7 +3633,6 @@ ert3ins
er3to
erts2e
2e1ru
-eruf6s
er1uhr
er1u2m
er1uns
@@ -3574,35 +3641,36 @@ er1uz
e1rü
er3ü2b
e5rüg
+2erv
3erweck
6erweis
2erzy
-es2a
e4s3ab
+es4ach
es3ad
es3ak
-es3alt
-es3ar
-e5s4as
+e5s4a4s
+es3aus
es3av
+esä2c
2esb
e3sc
es3cap
-es4ce
+e5s4ce
esch4
e6schan
esch2n
-e4sco
e6scu
es1ebe
es3ehr
-es1ein
+es3ein
es1eis
es1eta
es3eva
2esf
-6e4sh
+6esh
es2har
+es3he
es2hu
e3sid
e5sie
@@ -3611,71 +3679,71 @@ es1ini
es3int
e3sir
e7sis
-e5sit
-es5ke
+es3ke
es3ki
+es3kl
+es3ku
e4s3ky
-e4sl
-es2log
-2e4sm
-e4sn
+es3l
+es4log
+2esm
e3sof
e3sol
eso2r
es2ort
es4pei
-e3s4pek
-e5spi
+e3spek
es2po
-e5s4por
-es2pr
+e5spor
e5s4pra
2esr
-es6saa
1essay
-es3sec
+es3sc
+es5sec
+6essem
ess4e3re
es4s3erg
-es4sit
2esso
es2sof
es2sp
ess1pa
-es4st
+es2st
ess3tie
-es5str
-es5su
-e2st
-estab6b
+es3str
+e5staa
+e2stab
+estab4b
est1ak
+e3star
e4starb
-es6tau
-es7taum
-es2te
-es6te.
+es2tau
+es3taum
+e3stec
est5eink
-e7stel
-e4st3eng
-e4st3erh
-e7stern
-e7sters
-e4st3ess
-es4ti
-es5tip
+e5stel
+es4t3eng
+es4t3erh
+es4t3ess
+e1stil
estmo6de
-est3o4ri
+est3ori
+e1s2tr
es3trop
-e3stu
-es4tü
+e1s2tu
+es3tus
+e3s4tü
e2s1um
+es3ums
es1ur
+es3w
e3sy
+es3z
+e1ß
eße3r2e
2et
e1ta
eta3b6
et1am
-etari1
et4at
e1tä
et1äh
@@ -3696,6 +3764,8 @@ eti2ta
e3to
eto4b
e4t1of
+etons4
+eto4s
e1tö
4e1tr
e4t3raum
@@ -3703,23 +3773,25 @@ et3rec
e2t3res
et4ri
et4ro
+et2s
+et3sc
+et5schu
etsch3w
+et3se
et3so
et3sp
+et3sto
+et3str
et3su
et2ta2
et4tang
ett3au
-et2tä
et2tei
ette4n1
ett1h
et4t3r
ett3sz
-et2t1um
-et2tur
-et2tü
-e1tu
+et4t1um
et1ups
e1tü
et4z3ent
@@ -3727,7 +3799,7 @@ et3zo
eu1a
eu3ere
eu3erz
-eu2e5sc
+eu2esc
eu2ga
eug6er
eug3l
@@ -3741,26 +3813,26 @@ e1um
e3um.
e3umb
e3uml
-e3um6s
+e3um4s
eums1p
eum5st
-eum7str
2eun
eu3n2e
e3ung
eu4nio
-eun3ka
eu1o2
eu3p
eu2rau
eu3r2e
eur4er
-1eu3ro1
+1eu3ro
eu4sk
eu3sp
e4ust4
+eu1str
2eut
-eu3te
+eu5te
+eu3to
2eux
eu2zw
e3ü
@@ -3768,7 +3840,6 @@ e3ü
4eve
e2vela
e2vent
-ev2s
e1w
2e3wa
ewa3s
@@ -3780,24 +3851,25 @@ ew3et.
e3wir
ewi2s
e3wit
+e5wo
ew2s
2ex.
+1exam
ex3at
1e6xem
e4x1er
e2x1in
-1exis
3exp
2ext.
-ex2tin
-2exu
-2e1xy
+e1xy
2ey
ey4n
+ey3st
e1z
-e5z2a
+e3z2a
e2z1enn
e3zi
+ezin4
ezi2s
é1b
é1c
@@ -3817,17 +3889,16 @@ ezi2s
è1n
è1r
ê1p
+ê4t
6f.
1fa
3fa.
-fa1b4
+fa1b
fa2ben
-f3abf
-fab5s
3fac
-fa3che.
-fa3chem
+fa4cheb
fa2ch1i
+fa2cho
2fad
fa2da
3fa1e
@@ -3838,13 +3909,11 @@ fa2ke
f2al
fa1l2a
fal2kl
-fal6lenk
fal6l5erk
-fal2li
fal2s
+fal3te
falt4s
fal2z1
-3fam
2fanb
fan3da
2fanf
@@ -3856,13 +3925,14 @@ fan2gr
2f1ap
far2b3r
3fari
+farr3s
3f2art
fa5ru
f1arz
3fas
-fa3s4a
+fa3s2a
+fa5se
fa3sh
-3faß
2fat
fa2to5
2f1auf
@@ -3882,7 +3952,9 @@ fä2ßer
f3ds
1fe
3fe.
+fe4c
f2ech
+fe5che
4f3eck
fe2dr
fe2ei
@@ -3890,7 +3962,6 @@ fe1em
f4eie
4feinh
fei2nu
-fei5st
fek2ta
3fel
fe2l1a
@@ -3898,12 +3969,9 @@ fel4dr
fel5eise
4f1e2lek
fe2l1er
-fel5lä
fe2l1o
fel4soh
fel3to
-fel3tr
-fel3tu
3f2em.
2femi
fem4m
@@ -3915,8 +3983,7 @@ fe2ni
fe2no
fen3sa
fen7sc
-fens2t2
-fen5ste
+fenst2
f1ent
f2er.
fe1r2a
@@ -3933,10 +4000,10 @@ f4erpa
f2ers.
f2ert
f1erw
-fes2t
+fe2s
fe4st1a
-fe4st3ei
-fe4str
+fes3tat
+fest3ei
2f3e4ta
3fete
fet4t1a
@@ -3945,10 +4012,8 @@ fet4t1a
4fexp
3fez
1fé
-6f1f
-ff2ab
+4f1f
ff1ar
-ff2arb
ff3at
ff1au
ff2e
@@ -3960,7 +4025,6 @@ ffe2m
ff3emi
f5fen
f5fer
-f2fetz
fff4
ffi3k
ff6lei
@@ -3978,10 +4042,12 @@ ff3sho
fft2
fft3h
2f3g4
+fge1
2f1h
1fi
3fi.
fi3at
+fien3
fi1er2f
fi2ki
fi3kl
@@ -3996,18 +4062,20 @@ fi6lin
fil2ip
fin4a
fi3ni
+fin4s3
2f1int
fi3ol
fi2r
fi3ra
3fis
fi3s4a
-fi4scha
fisch3o
fi3so
fi5s2p
+fi4s3t
+fi3te
fi2t1o2
-fit5st
+fit3st
fi3tu
5fiz
2f1j
@@ -4035,11 +4103,12 @@ flug1a
f4lü
2f1m
2f3n2
-fni2
+fni2s
1fo
fob4l
2f1of
fo2na
+fon3st
fo2nu
2f1op
fo1ra
@@ -4048,17 +4117,17 @@ fo3rin
3form
for4m3a4g
forni7er.
-for4sta
+for4st
for2t
for4te
for4th
fort3r
for3tu
-fo5st
2fo2x
2f1öf
2f1ök
2f1öl
+förs3
2f3p2
fper1
2f1q
@@ -4068,7 +4137,6 @@ f5rad
fra4m
f3rand
1f4rän
-frä5st
2f5re.
f5ref
2freg
@@ -4082,30 +4150,30 @@ fri2e
2frig
fri3k
1f4ris
-fri6ster
-f4riß
f3roc
1f4ron
-fro2sc
+fro2s
fru2h
4fs
-f2san
+fs1all
+f2s1an
fs3ar
f2s3as
+fs1auf
f2saut
f3sc
-f4sce
f4schan
+f5schl
+fs4co
fs1e2b
fs3ehr
-fs1ein
f2s1em
f4s1ent
f2s1er
fse4t
f4s1eta
f3si
-f2si2d
+fsi2d
f2s1o2
fs3ol
f3span
@@ -4117,18 +4185,19 @@ f2s1pr
fs2pra
fs2pri
fs3s2
-fs1tak
-f4stas
-fs2tau
-fs1tät
+f1s2t
+fs3tak
+fs3tät
f4stäti
f4stech
+f3stei
f5stel
-f4stemp
-f4s1tis
-fst4r
+f3stern
+fs3th
+f3st4r
f4s3tres
-fs2tro
+fs4tro
+f3stü
f4s3tüte
f2s1un
f2sü
@@ -4147,7 +4216,8 @@ ft1e2h
ft1eig
ft1ein
ft1eis
-f2t1ent
+fte3ma
+f4t1ent
f2t3e4ti
f2t1h
f4t3hei
@@ -4158,13 +4228,14 @@ f2t3ro
ft3rö
f3t4ru
ft2s1
-ft4sa2
+ft4s3a2
ft3sc
+ft6sche
ftse2
-ft4stä
-ft5s4ten
-ft5s2ti
-ft3sü
+ft3st
+fts3tan
+ft4s3tä
+ft5sti
ft3t
ft1url
ft3z2
@@ -4177,14 +4248,12 @@ fun4ko
fun2k3r
2f1unm
2funt
-furch2
+furch4
fu4re.
fu5ru
-fus3se
-fus6senk
-fus4ser
-fuss1p
-fus4s1t
+fus2sa
+fus2s1p
+fus2st
fu2ß1er
3fut
1fü
@@ -4201,12 +4270,13 @@ fz4s
6g.
1ga
5ga.
+gabe4n
2gabf
-ga2b5l
-ga1b4r
+gab5l
+ga1br
ga3bu
2gabz
-ga1ch
+ga1c
ga3di
ga1e
ga1fl
@@ -4222,11 +4292,11 @@ g1anf
gan2g1a
4gangeb
gan2gr
-2g1anh
+2ganh
2g3anku
2ganl
+g3anla
3gano
-g4ant
2ganw
ga1ny
2g1arb
@@ -4236,18 +4306,15 @@ ga1ny
ga3r2o
g1arti
2garz
-ga2s
-gas3a
+ga2s1a
ga4sal
-ga3sc
-ga5se.
-gas1ei
-gas5s
-ga4sta
-gas3tan
-ga4st3el
-ga4stra
-gas1tu
+gas3ei
+ga2si
+ga2so
+gas3s
+ga4st
+gas4t3el
+gas4tra
ga3t2a
ga3th
2gatm
@@ -4260,10 +4327,9 @@ g2auk
1gä
2g1äp
g1ärz
-3gäs4
-gä5st
+3gäs
gä4u
-6g1b
+4g1b
g5be
gber2
g5bo
@@ -4290,21 +4356,20 @@ ge3a2
ge3ba
gebe4am
geb4r
-ge1c
+ge3c
ge3d
ge1e2
ge3ec
ge2es
gef4
-geg4l
ge3ha
ge1im
ge1ins
ge1inv
ge1ir
+ge2is
4geise
gei3sh
-gei4sta
g2el
gel6ders
ge3le
@@ -4313,9 +4378,9 @@ ge4less
ge3lor
gel3sa
gels2t
+gel3ste
gel3sz
gel3t2a
-gel3to
ge3lum
ge3lü
gel3z2
@@ -4332,8 +4397,9 @@ gen3eid
gen3ern
gen3g
gen3k
-genmes4
ge3nor
+gens3am
+gen7stern
gen3sz
g1entf
gen3th
@@ -4358,26 +4424,30 @@ ge1ro
ge1r2ö
ger4sto
3gerw
-g6es
+ges2
+ge5s4am
ges3auf
-ge5s2c
+ge5s4c
ges3elt
-ge2s1er
+ge2s3er
ge3ses
-ge3s2i
+ge3si
ge3sp
-gess2t
-ge3st
+ges4pi
+gess4t
+ge1st
+ge3ste
+ge5stei
+ges4tem
+ge4s3ter
get2a
-ge3tan
4getap
ge3t2u
ge1ul
-gewa5re
4g5ex
2g3f2
-2g1g
-gga2t
+4g1g
+gga4t
g5ge
gge2ne
g2g3l
@@ -4385,7 +4455,6 @@ gg4lo
g2g3n
gg4r
g3grä
-gg4s
2g1h
4gh.
3g2het
@@ -4418,6 +4487,7 @@ gi2o
gi3ro
2gisel
git2a
+gi3tu
gi2us
2g1j
2g5k
@@ -4428,13 +4498,9 @@ g2l
3glad
2g3lag
3glanz
-gla4s5ti
-gla4stu
3g4laub
2g3lauf
1glä
-3gläs
-g3läß
3glät
2gläuf
1gl4e
@@ -4455,11 +4521,12 @@ g3li
g4lia
2glib
3g4lid
-5g6lie
+5g4lie
2glif
1g4lik
g5lin
-1g6lio
+1g4lio
+gli2s
4glisc
1g4lit
1g4liz
@@ -4474,12 +4541,11 @@ g4lom
1g4lot
g3lö
2gls
-2glu2
-glu3te
+2glu
+glu2t
3glü
3gly
-2g1m2
-gmi3te
+4g1m2
gn2
4gn.
g2na
@@ -4493,7 +4559,7 @@ g5neh
g2nie
g2nif
g4nin
-4g5ni4s1
+4g5nis1
g2no
gno1r
2g3not
@@ -4511,7 +4577,7 @@ goa3li
go3be
2g1of
2g1oh
-go1i4
+go1i
gol2a
3gon
2g1ope
@@ -4519,6 +4585,7 @@ gol2a
3g2o1ra
3gos
go2si
+go3st
go3t2h
got6t5erg
3gou
@@ -4562,8 +4629,6 @@ gro3be
gron4
g4ros
gross5el
-gros8seri
-g4roß
gro4u
2g3röh
g4ruf
@@ -4575,135 +4640,116 @@ g4ruf
grü1b
2g3rüc
3g4rün
-4g2s
-gs1ac
+4g2s1
gs3ad
-gs1af
-gs1a2g
-g5sah
+g4sa2g
+g3s2ah
gs5a2k
-g5sal
-gs1ama
-gs1amb
+g3sal
+gs3ama
+gs3amb
gs3an
gs3ar
gs3as
g5sat
gs3aug
-gs1ä
-g7sät
-g5sc
+g5sät
+g3sc
+g6sca
+g6sce
gsch4
-g6schan
-g7schä
+g4schan
g6schef
-g7s2chi
-g7schl
-g7schö
-g7schu
-g7schü
-gs1cr
-gs1e2
-g5s2eil
-g5sel.
-g5seln
-gs3ene
-g4s3er
+gs4chi
+gs3cr
+gse2
+g3s2eil
+g3sel.
+g3seln
+g4s5er
gse4t
-gs1i
gsi2d
-g7sil
-gs3l
-gs1o2
+g5sil
+g4s3l
+gso2
g3sol
-g7soz
-gs1ö
-gs1p
-g5spek
+g5soz
+g3spek
gs2pi
-gs3pin
-g5s2por
-g4spu
-gs3s2
-g3st
-gs1ta
-g5s2tar
+gs6pie
+g4s3pin
+g5s4por
+gsrü2
+gs5s4
+g3star
+gs4tati
gst1au
-gs1tä
-g5ste.
-gs3teil
-g7stel
-g5sten
+g4stä
+g5stäm
+gs3te
+g3s4tel
gst3ent
-g5ster.
gst3err
-gs3test
gs4teu
-g5sti
-gs3tier
-gs1tis
-g5sto
-g6ston
-g6s1tor
-gs1tot
-g5stö
-gs1tr
-gst4ri
-gst3ros
-g5stuf
-g5stun
-gs1tü
+g3stir
+g3s2to
+g4s3tor
+gs2tö
+gs4tör
+g1stre
+gs4t3ros
+gs3trü
+g3stu
gs2tüc
-gs1u
-g5sub
-g5sy
-2g1t
+g4s5w
+g3sy
+2g1t2
g5te
-g2t1h
+g2t3h
g5ti
gti2m
-g5tr
-gt4se
+gts3
+gt3t
+gt3w
1gu
gu1an.
gu1ant
+gu1c
gu2e
-guet2
+guet4
2g1u2f
2g1uh
gu3ins
gu1is
gu5me
-3gumm
gun2e
2g1unf
g2ung.
-gunge2
+gunge6
4gungew
2g1ungl
-3g2uns
+3g2un4s
4gunt
gu3re
2g1url
-gu4s3a
+gu4s
+gus3a
+gu5sc
guschi5
-gus6saa
-gus6sam
-gus4st
-gu2ß1
+gu5se
+gus5se.
+gus2st
5gu2t1
-gu3te
1gü
2güb
gür1
-gü5st
+güs1
2g1v
4g5w
-gwa5re
1gy
gy3n
2g3z2
-6h.
+4h.
2ha.
hab2a
hab2e
@@ -4722,6 +4768,7 @@ ha3go
ha3ha
hai1es
h2aka
+haki3
ha1kl
4h2al.
ha1la
@@ -4731,10 +4778,12 @@ ha2lau
hal2ba
hal4bei
halb3r
-2hale
-hal4leh
+halb5s
+2ha3le
+ha3li
hal6lerf
h1alp
+hal4st
halt3r
h1amt
h2an.
@@ -4743,7 +4792,7 @@ h2and
h4ann
2hanr
2hant
-haos5
+ha3os
2hap
ha2pr
h4a3ra
@@ -4755,25 +4804,25 @@ har4mes
har5te
har4th
h1arti
-h2arts
2has.
-2ha3sa
-ha2ß1
+4ha3sa
+ha5sta
hau3f4li
2h1aufm
h1aukt
hau2sa
hau4sc
-hau6s3ti
+hau5stei
hau2ta
2hauto
hau2tr
h1äff
+3häp
h1ärz
hä6s5chen
-häu4s1c
+häu4s3c
hä1usp
-2h5b
+2h5b6
hba2r3a
2h1c
2h1d
@@ -4811,8 +4860,8 @@ heine2
hei4neh
h1eink
he3ism
-he3i4st
-heit4s3
+he3ist
+heit6s3
h1eiw
hekt5a
he2l3au
@@ -4832,13 +4881,14 @@ he3mi
h2en.
he6n3a2
he4nä
+hend4s
h4ene
he2n1e2b
hen3end
he2net
he2ni
he2no
-hen5st2
+henst2
h1ents
he2nu
hen3z
@@ -4866,12 +4916,12 @@ h1erö
hert2
her3th
her2z1w
-hes4t
+he2s3tr
he2tap
heter2
he3th
he5ti
-he3t4s
+he3t6s
he2u
heu3g
he3x
@@ -4882,6 +4932,8 @@ he1y2
hfel2l1
hfi2s
2h5g2
+hge1
+hgin4s
2h1h
2hi.
2hi2a
@@ -4892,22 +4944,21 @@ hi2e
hi3ens
hie4r3in
hif3f6r
-h2ig
hi2kr
h2il
-hi4l5a4
+hi2l5a4
hil2fr
hi2n
hi3nel
hin2en
hi5n4i
hi3no
-hin2t3a
+hin4t3a
2hio
hi4on
hi3or
hi3os
-2hi2p
+4hi2p
hi3pe
hip1h
hip1i
@@ -4920,7 +4971,9 @@ hi3ro
his2a
hi4se
hi5s2p
-hi3ti
+hi4st
+hi1th
+hi5ti
h1j
2h1k4
2hl
@@ -4932,7 +4985,6 @@ h5land
hl3anz
hl1ar
h3las
-h3laß
h3lat
h3laug
h3laut
@@ -4940,7 +4992,6 @@ h3law
h3läd
hl1är
h3läs
-h3läß
h3läu
hlb4
hl3d4
@@ -4970,8 +5021,7 @@ h2li
h3lic
h3lik
hl1ind
-h3list
-hl3l2
+hll2
hlm2
h2lo
h5loc
@@ -4988,11 +5038,11 @@ hl2ser
hl3sku
hl3slo
hl3sp
-hl2sto
hlt2
h3luf
h3luk
h3lüf
+hlzu5
2h1m
h2ma
h4mab
@@ -5007,8 +5057,7 @@ h4mäu
h3me.
hme1e
hme1in
-h3meist
-hmen2s
+hmen4s
hmen6sc
hme2ra
h2mi
@@ -5057,17 +5106,22 @@ hn3k4
h3nof
hn3s2k
hn4th
+hnts2
h2nul
hn1unf
h3nunge
ho3be
ho2bl
ho2c
-hoch5
+ho4ch5
+ho3ck
+ho4cka
+ho7cker.
hoe4
ho2ef
ho4fa
ho2f3r
+hohen3
hol1au
ho2l1ei
hol3g4
@@ -5082,32 +5136,30 @@ ho2mec
ho2med
ho5mu
h2on
+hon3str
2hoo
2hop
ho1ra
hor3d
h1org
-ho5ri
ho3sl
ho4sp
ho4st
-ho6sta
-ho5ste
-2hot.
+4hot.
ho5th
-2hot3s2
-1hou
+4hot3s2
+1hou2
3hov
-2ho2w
+4ho2w
how1e
h1o2x
ho1y2
-hô1
1hö
hö2c
+hö3ck
h2ör
hö4s
-hös1c
+hös3c
h1öst
2h3p2
h1q
@@ -5134,14 +5186,12 @@ h3rep
h4r3erla
h3rerle
h6rerleb
-h3re4s5
-hre6su
+h3re4s1
hre2t
h2r3eta
h3rev
hrf2
hrg4
-hrga4
h3ric
hri4e
h3riesl
@@ -5154,29 +5204,27 @@ h2rob
h3roh
h3rol
h4rom
-hro3man
h4ron
h2ror
h3rou
-hr2s3ac
+hr2s1ac
hr2s3an
-hrs3au
-hr5sch
+hrs1au
+hr4se
hr2s1en
hr2ser
-hr4set
-hr4s1in
+hr2set
+hr6s1in
hrs3k
-hr2s1of
+hr4s1of
hrst2
hr2su
-hr6sw
+hr4sw
hr4tab
hr2tan
hr2t3ri
hr2tro
hrt2se
-hrt4ste
h1ru
h3ruh
hr1ums
@@ -5185,17 +5233,20 @@ h3rü
hr3üb
h2ry
hrz2
-4h1s
+4hs
h2s1ach
-h2san
-h2sau
-h3sc
+h2s1an
+h2s1au
h4schan
-hs1ec
+hs1e4c
+hs2ei
hs3eins
-hs1eis
-h2s1erl
-h3s2ex
+hs3eis
+h3sel
+h3sen
+h3ser
+h4s1erl
+h3sex
h2s1ing
hs3l
h2s1of
@@ -5204,26 +5255,23 @@ h2sper
h3s2por
h2sprä
hs3s2
-h4stal
+h2stal
hst3alt
-h4starb
-h4stau
-h4stäl
-h5ste.
-h5stem
-h5sten
-h4sterm
-h2steu
-h4s1tie
-h4stin
-h4s1tor
+h2stau
+h1stec
+h3s4terb
+hs1the
+h1s2ti
+h2s3tie
+hs4tief
+h2stor
+h1s2tr
hst3ran
-h4st3ri
-h2s1tu
-h3stun
+hst3ri
+h1stun
h2s1un
hs2ung
-h3sy
+h1sy
4h1t
h2t1a
htab2s
@@ -5231,28 +5279,26 @@ h3t4akt.
h3takts
h3t2al
h4t3alt
+h4tam
ht3a4n
ht5ane
h3t4ank
-h3tas
h4t3ass
h4tasy
ht3a2t
h2t1är
h5te.
-h2t1ec
+h2t1e4c
h3tech
h2t1ef
ht1e2h
h3teha
-h3tehä
h2teif
h4t1eim
ht1ein
h2t1eis
h4t3elit
-h2temp
-h3ten
+h4temp
h4tentf
h4t3ents
ht3erfo
@@ -5260,45 +5306,40 @@ ht3erfü
h2t1erh
h2t1erk
ht4erko
-ht3erre
+h4t3erre
ht3ersc
h6t5erspa
h4t3erst
h2t1erz
hte2s
-h2t3ese
-h6t3ess
+h4t3ese
+h4t3ess
h5tet
-h2t1eu
+ht1eu
h2t1ex
h2t1h
h3ti
h4t1in
hti2s
-htni4
h2t3oly
h2top
-h2torg
h2tö
h3töp
-ht3rak
+h4t3rak
ht3rand
h2t3rat
ht3raus
+h4tref
ht4ri
h2t5rin
h2t3rol
h2t3ros
-ht3roß
h2t3rö
h2t3ru
h2t3rü
ht2sen
-ht4s3ess
ht3spri
ht4stab
-ht4ster
-hts2ti
ht4s3tur
ht4s3tür
ht3t
@@ -5310,13 +5351,15 @@ htwa5re
ht3z4
hu2b
hub1a
-hu4bei
+hu4b3ei
hu4b1en
hub3l
-hub3r
+hub5r
+hu1c
hu2h1a
hu2h1i
-huk3t4
+huko3
+huk3t6
hu2l3a
hu2lä
hu2l3ei
@@ -5325,7 +5368,6 @@ hu4lent
hu2ler
hu2let
hu2l1in
-hul3l
hu2lo
hu3ma
h1ums
@@ -5339,6 +5381,7 @@ hur3g
hu3sa
hu2sc
hu2so
+hus4sa
hu2tab
hu3t2h
hu2ti
@@ -5352,12 +5395,13 @@ h4übs
hüf2
hüh3
hühne4
+hüs3
2h1v
hvi2
hvil4
2hw
h2wal
-hwa5re
+hwas7
hwe1c
h1weib
h1wet
@@ -5368,13 +5412,12 @@ h1z
hz4s
2i.
2ia.
-i4aa
ia1b4
iab5s
2iac
i5ad.
i3adn
-ia1f4l
+iaf4l
i4a3g
i3ak.
i1akt
@@ -5397,7 +5440,7 @@ i3alh
i3a2lia
i3alj
i3al3k2
-i5al5l
+i5al3l
i3alm
i3aln
ia2lor
@@ -5409,7 +5452,6 @@ ia2lu
i3alv
i3alw
i3al3z2
-iam4
2ian
i5an.
i1ana
@@ -5426,34 +5468,37 @@ ia3p2f
ia1q
i3ar
ia2ra
+iard2
2i3as
i5as.
i4asc
ia3sh
i4asi
i4a3sp
-ia4st4
-ia5str
+iast4
+ia5sta
+ia1str
i5at.
-ia6ta
+ia4ta
i3at2h
1iatr
i3ats
i3au
ia3un
-iaus1
2iav
i1äm
+iär2
i1är.
i1ärs
i3ät.
-i3ät3s4
+iä5te
+i3ät3s
i1b
i2b1ar
i2b1auf
ib2bl
i2b1ei
-ibe6n1
+ibe4n1
ibi4k
i3b4la
i3b4le
@@ -5463,16 +5508,17 @@ ib3ren
ib2s
ib3sa
ib3sp
+ib3sta
ib4ste
i2bunk
i2b3unt
-ibus1c
-ibwa5
+ibus3
2ic
ich1a
ich3ä
i1che
ich3ei
+i3cher
i1chi
i2chin
ich3l
@@ -5483,7 +5529,9 @@ i2ch3r
ich2t3r
i1chu
ich3w
-ick2e
+i2cka
+i3ck2e
+icks2
i1cr
i5cu
i1d
@@ -5514,6 +5562,7 @@ ieb4sto
ieb4str
ie1c
ie2cho
+ie4ck
ied3g
ie2dr
ie1e2
@@ -5524,12 +5573,11 @@ ie3fer
ief3f4
ie2f3l
ie2f1r
-ie2g7l
+ie2g5l
ie3g4n
ie2g3r
ieg4ra
-iegs1c
-ieg4st
+iegs3c
ie3her
i1ei
ie2l1a2
@@ -5547,7 +5595,6 @@ iel3sp
iel3sz
ielt4
iel3ta
-iel3to
i1en
i3en.
i3ena
@@ -5556,7 +5603,8 @@ i3e4nä
i3end
ie2n1e2b
ien2er
-ie6nerg
+ie4nerg
+ie3nern
i3enf
i3en3g
i3enh
@@ -5568,9 +5616,9 @@ i3e2no
i3enö
i3enp
i3enr
-iens2
-ien3se
-ien6sto
+ien5s2e
+ien2st
+iens4tr
ienst5rä
ien3sz
i3env
@@ -5587,15 +5635,16 @@ ier4ert
ie4r3erz
ie3res
i3ereu
-i4eri
-ier3k4
+ier3k2
i1ern
i3ern.
ier5ni
iers2e
ier4s3eh
-ier5sta
-i3e4stas
+ier7sei
+ier3sta
+ier3ste
+iesen3s4
ie3su
ie2t1a
ie4tei
@@ -5604,24 +5653,22 @@ ie4t3ert
ie2th
iet3ho
ie4t1o
-ie2t3ö6
-iet2se
+ie2t3ö2
+iet4se
i3ett
ieu2e
ie1un
i1eura
-iewa5r
i1ex
-2if
-if1an
+4if
i2f1arm
-if1au
+if3au
i3fe
i5f2en
+ifen3st
if1erg
if1erh
-if2fa
-if6feste
+ife4s
if2fl
i3fi
if3l
@@ -5645,9 +5692,9 @@ if2top
if2t3ri
ift3sp
ift3sz
-i1g
+2i1g
ig2ab
-iga1i
+iga3i
i2g1ang
ig1art
iga5s
@@ -5665,21 +5712,22 @@ ig4le
ig5lein
i4gli
ig1lu
-2igm
ig4na
i4gnä
i3g4neu
ig4no
i3g4ra
-ig6sal
-ig3sau
-ig3sä
+ig4sal
+ig5sä
ig4se
ig3so
-ig6sti
-ig6s1to
-ig6stö
+ig3spr
+ig3s4tei
+ig4s3to
+ig4stö
+ig3str
ig4stre
+ig5stu
2i1h
i2h1am
i2h1ar
@@ -5690,20 +5738,20 @@ ih3l
ih3m
ih3n
ih1r
-ih2s
i2h1um
ihu3s
ih1w
2i1i4
i2i5a4
+i3ig
i3in
i2is.
i2i5t
i1j
i1k
i4k3a4k
-ik3amt
-i4kanl
+ik5amt
+i4k3anl
i2k1ano
ik3ansa
i2k3anz
@@ -5726,16 +5774,17 @@ i3k4la
i3k4lä
ik1lö
i2k3n
-ik2o3p4
+ik2o3p6
ikot3t
ik3ra
ik3rä
ik3re
i3kri
+ik1s
ik3so
iks2p
ik3s2z
-ik3t2e
+ikt2e
ikt3erk
ik2t3r
i2kun
@@ -5747,7 +5796,6 @@ i2l1ak
i2l3a4m
il1ans
il3asp
-i3lat
i2l1au
il4aufb
il5aus
@@ -5759,10 +5807,9 @@ il3de
il4d3ent
ild2er
il2d1o
-il1ec
+il1e4c
ile2h
il1ehe
-ileid4
il1ein
i2l1el
i3len
@@ -5774,16 +5821,15 @@ il2f3l
il2f3re
ilf4s
ilg4r
-ili5en
+ili5en3
iliga2
ili4g3ab
i2l1ind
i2l1ip
i3lip.
i3lips
-il3l4a
-il4lad
-il2leg
+il3l2a
+ill4an
il3l2er
il5l2i
il2mak
@@ -5809,7 +5855,6 @@ i2manw
i2m1arm
ima2tr
ima4tur
-1imbi
i2m1ele
i2m1elf
i2m1erf
@@ -5818,25 +5863,21 @@ i2meti
im1ex
2imi
i2m1inf
-iming7
i2m1ins
-imi3te
-immei4
im4m3ent
3immo
-imni4
im1org
1impo
imp2s
im3pse
1impu
-im4str
+im2str
2imt
2imu
im3unt
2in.
2ina
-in1ac
+in1a4c
in3ad
in2af
in3a2m
@@ -5847,12 +5888,10 @@ ina4s
in3asi
inasy3
i2n3au
-inaus1
in1äs
in1äu
in3dau
in4dene
-indes4t
1index
in3do
2indr
@@ -5875,58 +5914,60 @@ in3erz
i2n1eu
ine3un
ine2x
+inf4
1info.
4inga
ing1af
in2g1a4g
-ings2c
-ing7sch
-ing3ska
-ing5ste
+ing5sc
1inhab
2inhar
2inhau
-2inhe
+4inhe
i3ni3d
2inig
in3ins
in2ir
2inis
+ini5se
i3nitz
3inkarn
-ink4st
+ink4ste
2inn.
in4n3erm
2innl
-inn6sta
1innta
2ino
in3od
in3ole
in3ols
in1or
-ino5st
+inos2
+ino3st
ino3t
i1nö
in1ö2d
2inp
2inr
+ins2
2ins.
-ins2am
+ins4am
+ins3än
insch4
in7schl
-in2seb
-in3sel
+in4seb
2insen
+ins3erg
ins3ert
in3skan
+in5spe
+in3st
3instal
in4s3tät
-in5sto
-in3s2u
+in5s4tr
+in5su
1insuf
-in4s3um
-ins2z
+in6s3um
in3sze
1integ
in3t2h
@@ -5951,17 +5992,16 @@ io2i3d
i4ok4
io3kr
i3ol.
-i3om.
-i3oms
+i5om.
+i5oms
ion4
i3on.
io3na
ional3a
io4n5au
ion5d
-i3ons1
+i3ons3
ion6sc
-ions3p
io2nu
i2ony
i2o1p
@@ -5980,7 +6020,7 @@ i2os2
i3os.
io3sh
io3sp
-io5st
+io3st
i3ot.
i3ots
i2ov
@@ -5991,6 +6031,7 @@ i3ön
i1ös.
2ip.
i1pa
+ip4an
i1pä
i1pe
ipen3
@@ -6000,13 +6041,13 @@ iph4
2i1pi
ipi3el
ipi3en
+ipi2s
ip4l
i1pr
2ips
-ip3ta
2i1pu
i1q
-i1r2a
+i1r6a
i3ra.
1irak
i3ras
@@ -6022,7 +6063,6 @@ ir2g5l
irg6s
ir2he
i1r2i
-iri3a
2irig
2irk
ir2k5l
@@ -6038,26 +6078,24 @@ ir2no
i1ro
1i2ron
iro2s
-iro5st
i1rö
irpla4
-ir4rei
-ir2s
-ir3sh
-irt4st
+ir4s
+ir5se
+ir5sh
+irt2st
i1ru
iru2s1
-i1s
i3sac
-i4s1amt
+i4s3amt
+is1an
is2ap
is3are
-i2sau
+i2s1au
is1än
2isb
i2sca
isch3ar
-is2che
i4sch3e4h
i4sch3ei
isch6er
@@ -6068,39 +6106,35 @@ i2schm
isch3ob
isch3re
isch3ru
-i4schwa
-i6schwir
-i4schwo
-i4sch3wu
-is1chy
-i2s1cr
-2ise
-i3sec
+isch3wu
+is3chy
+i2s3cr
+2i3se
ise3e
ise3ha
ise5hi
ise3il
-is1ein
ise3inf
i4seint
ise2n
ise4nal
is2end
ise1ra
-i2s1erm
+i4s1erm
iser2u
-i2s1ess
+i4s1ess
is4et
i4s5etat
+i4sex
isi2a
i2s1id
is3la
-is3m
+ismu2
i2s1of
iso2n
iso6nend
is1op
-3i2sot
+5i2sot
i2sp
is1pa
i4spar
@@ -6111,35 +6145,38 @@ i4spl
i4spo
i4spro
is3sa
-is6saa
-is4s3ac
+is4s1ac
is4sau
-is3sä
is4s3che
-is4st
+is2st
iss1tr
-is2sum
-ist2a
-i4st3ab
-i4staf
-i4stam
-is2te4n
-is2ter
-is2ti
-ist3re
-is2tro
-is1trü
-i2stur
+i2st
+is1t2a
+is2t3ab
+is2tat
+is3tec
+i3stel
+iste4n
+is1th
+i1stil
+is1to
+is2toc
+is1tr
+is2t3re
+i3stru
+i3stü
isum3p
i2sü
+i1sy
+i1ß
i2ß1ers
+ißler3
2it.
i1ta
it1ab.
it1ac
i3tak
ital1a
-ital3l
it1alt
it1am
it1ang
@@ -6152,33 +6189,30 @@ i4t1ax
2i3tä
i4t1äs
ität4
-2i1te
-it1eig
+2ite
+i2t1eig
it1ein
6i3tel
ite2n
iten3g
itens2
+iten3st
i2t1epo
-i2tex
+i4tex
it1he
i5thr
it1hu
-i1ti
+i3ti
1itia
-i2t1id
+i4t1id
1itii
iti4kan
-i2t1in
-i3tis
-i3tiv
+i4t1in
i1to
-i3to.
i5toc
i2t1of
i1tö
i1tr
-i5tra.
it3raf
it3rah
i2t3ran
@@ -6190,39 +6224,34 @@ it3ric
it3rom
i3tru
it3run
-it4s1ag
+it4s3ag
it2sä
it2s1e2
-it4s3er1
+it6s5er1
its1pe
it4staf
-it4stec
-it4s3tem
-its3tes
-it4sti
-it4sto
-it4str
-it2teb
-it4temp
+its3tie
+it2sto
+it2str
+it3te
+it4teb
itt3hä
it2tr
-i1tu
it1uh
i2t1um
i2tuns
itu5re.
it1urg
-itut4
+itut6
i1tü
i3tül
i3ty
2itz
it4z3erg
-2i1u6
-ium1
+2i1u4
ium3a
+ium1i
i3un
-ius1t
i1ü
2i1v
iv1ak
@@ -6237,7 +6266,6 @@ i3vol
i2vr
i2v1ur
2i1w
-iwa5r
iwur2
ix2em
i3xi
@@ -6259,28 +6287,33 @@ iz3th
i2z1w
í1l
2j.
+ja1c
jahr3ei
jahr4s
ja3la3
ja3ne
jani1
ja5sa
+ja3st
2jat
je2a
-jean4s
+jean6s
+je1c
je2g5
jek4ter
jekto2
jek4tr
je3na
je2p
-je3s
+jes1t
je2t
jet1a
jet3h
jet3r
+jet3st
jet5t
jet1u4
+je5v
jit3
ji2v
j2o
@@ -6290,20 +6323,23 @@ job3r
jo2i
joni1
jo1ra
-jord4
+jord2
jo2sc
jou2
jou4l
+joy3
4jö
2js
j2u
ju2bl
+juden3
jugen6
jugend5
ju2k
-jung7s
+jung5s4
jur2o
-ju3te1
+ju2s
+jute1
2j1v
4k.
1ka
@@ -6318,14 +6354,13 @@ ka1bl
2kablä
kab4le
2k3a2bo
-ka3b6r
+ka3b4r
4k3abs
2k1abt
ka1c
2kada
ka3dab
2k3adr
-ka1e
ka1f4l
ka1fr
kaf3t
@@ -6334,19 +6369,18 @@ ka1in
ka3ka
kaken4
ka1la
-2kala.
ka2lan
kal3bl
ka3lei
ka3len.
ka4lens
-kal3eri
+kal5eri
kal2ka
kal2kr
2kall
kal4tr
-k2am
-k3a2ma
+3k4am
+4k5a2ma
ka3mar
kamme2
ka4n3a4s
@@ -6365,6 +6399,7 @@ kan4th
k4anz.
ka2o
2kapf
+3kara
2karb
k1arc
k2ard
@@ -6376,13 +6411,14 @@ kari3es
kar4p3
k2ar3ta
2karti
-kar3to
karu2
k2arw
-ka5se
+3kas
+ka3se
kasi1
ka4sp
-ka3ta
+kas3s
+ka4s1t
ka3th
ka2t3r
2katt
@@ -6390,7 +6426,6 @@ kau4f1o
4kaufr
kauf4sp
2kaus
-kau5st
kau3t4
2kauto
1kä
@@ -6398,16 +6433,16 @@ kau3t4
2käh
k1ämi
kär2
-kä4s1c
+kä4s3c
kä5se
-kä3th
+kä1th
2k1b4
k5be
kbo4n
2k3c
2k3d
kdamp2
-2kec
+2ke1c
ke3d
k3eff
kefi4
@@ -6416,13 +6451,11 @@ ke2gl
ke2he.
kehr4s
kehrs3o
-ke2i
2k1eic
2k1eig
2kein
-ke3ind
+ke1ind
2k1eise
-keit4s
ke2la
kel1ac
ke3lag
@@ -6432,13 +6465,10 @@ kel3b
2k1e2lek
ke2len
2ke3let
-kel3s2k
+kel3sk
2k1emp
ken3a
4kengag
-kens2k
-ken5st
-ken7s4te
ken3sz
k2ente
k3enten
@@ -6473,10 +6503,11 @@ keu6schl
2k5f
kfi2s
2k1g4
+kge1
2k1h4
kho3m
ki3a6
-ki1ch
+ki1c
ki2d
ki3da
2k1ide
@@ -6486,7 +6517,6 @@ ki2el
kie2l3o
ki2en
kif4
-kif2a
ki1fl
ki1fr
ki3k4
@@ -6505,6 +6535,7 @@ kin3sh
ki3o
3kirc
ki5s2p
+kis2to
2kiz
ki3zi
2k5j
@@ -6561,15 +6592,16 @@ kol4k5
3kom
ko2min
ko4mu
-k2on
-kon3d
-ko3n2e
+k2on3
+ko3n4e
+kon4i
kons4
ko3nu
2kop.
ko1pe
kop4f3en
kopf5err
+kop2t
ko3r2a
4k1orc
kor6derg
@@ -6577,6 +6609,8 @@ ko3ri
kor3m
3kort
k2os
+ko3str
+3kot
ko3ta
kots2
kot3sp
@@ -6609,14 +6643,14 @@ k3reih
k3ries
2krip
k4ron
-kro5st
+kro3st
2kruf
krü1b
4ks
-ks1amt
-k2san
-k2sau
-ks2än
+ks3amt
+k2s1an
+k2s1au
+ks4än
ksch4
ks1e2b
k2s1em
@@ -6624,23 +6658,28 @@ k2sent
ks1erl
k2s1ers
k2s1erw
+ks1ex
k2s1id
k2s1in
k2s1o2
k3sof
-k5son
ks1pa
k3spe
ks2por
ks3s2
-kst4
+ks2t4
k5stab
ks3tanz
kstat4
-k4s1tis
-k4s1tor
-k4strä
-k2s1tum
+k1ste
+k5stei
+k6steil
+k1sti
+k2stor
+k1str
+k2strä
+k1stu
+k2stum
k2s1u
k1sy
ks2zen
@@ -6657,17 +6696,19 @@ kt5a4re
k5tat
k2t1au
ktä3s
+k3te
kte3en
-k2t1ei
-k2temp
-k2tent
+k4t1ei
+k4temp
+k4tent
k4t3erfo
-k2t1erh
+k4t1erh
k5ters.
-k2tex
+k4tex
k2t1h
k2t1id
-k2t1im
+ktien3
+kt1im
k2t1ing
kt1ins
k2t1of
@@ -6680,27 +6721,28 @@ k3t4ra
kt5ras
kt5rau
kt4ro
+ktro5s
kt3run
kts4
kt3se
kt3sp
-kt5st
+kt3st
kt3su
-kt3sz
+kt3s2z
kt3t2
k2tuns
kt3z
ku1c
-kuh5
+kuh3
2k1uhr
ku3la
ku3l2e
ku3l2i
-2kulp
+4kulp
2k3uml
-kum2s
+kum2s1
k2u3n2a
-kun6s
+kun6s4
kunst3
2kunt
2k1up.
@@ -6709,22 +6751,20 @@ kuri2e
kuri4er
ku2ro
kur4sp
-kur4s3t
kur4zen
ku4schl
ku2so
ku2sp
-ku5s4t
+ku2s1t
ku2su
-ku2ß
1kü
2küb
kü1bel
kü1c
-kür2s
+kür4s
2k1v
2k1w
-kwa5re
+3kys
ky3t
2k5z2
6l.
@@ -6734,9 +6774,11 @@ la3ba
4labb
4la2ben
3labi
-6l1abl
+4l1abl
3la3b2o
3l2a1b4r
+lab5re
+lab6ri
4l3abs
4labw
la1ce
@@ -6745,11 +6787,10 @@ la3den
la3d2i
l3adl
4ladm
-4l3adr
+2l3adr
5ladu
l3adv
1la1e
-laf3ta
la2ga
la3ge
lag5eis
@@ -6757,10 +6798,9 @@ la2gn
lago4
la4g1ob
la2gr
-lag5se
+lahn3
2la1ho
1lai
-lai4s1t
1laj
la3ke
la2k1i
@@ -6772,11 +6812,10 @@ la1k4l
l2a3ma
l2ami
la3min
-lam4ma
3lammf
l4amp
2l1amt
-lamt4s
+lamt6s
la4mun
la2na
la3nac
@@ -6790,12 +6829,13 @@ lan6d5erz
land5inn
lan2dr
2l1anf
-lang5s2
-l1anh
+lang3s4
4lanl
+l3anli
2l3ann
l1anp
2lans
+4lansä
4lanw
lanz1w
3lao
@@ -6808,37 +6848,30 @@ la2r1ei
la6rene
l4ar3g
lar3ini
+lar3st
2l1art
lar3th
l3arti
la3ru
-la5se
+la3se
2lash
la2so
2la4sp
5lasseri
5lassern
5lassers
-la4sta
-la5ste
-las3tei
+la4st
last1o
-la4str
-las3tur
-la4stü
-la2ß
-laß3th
lat2a
-la3te
la4tel
-4l3ath
+2l3ath
la2t3ra
lat4s
2latta
lat4tan
lat4t3in
lat4t3r
-laub4se
+laub6se
lau4fer
lau4fo
l2aufz
@@ -6846,10 +6879,10 @@ l1ausg
2l1ausl
2l1ausr
2l1auss
-lau5str
l1ausz
2lauto
2law
+lawa4
1lax
la3xa
lä1c
@@ -6858,7 +6891,7 @@ lä1c
3länd
lär2m1a
l1ärz
-lä4s1c
+lä4s3c
4lät
4läub
4läuc
@@ -6871,12 +6904,11 @@ lb3af
lb3am
lb3ang
lb3arb
-lb5b
+lb3b
l2b3ede
-lbe4n
l4b3eta
l2b3id
-l2b5ins
+l2b3ins
lb4lat
l3blä
lb3le
@@ -6884,14 +6916,18 @@ l2b5li
l3blo
lb3ohn
l4bre.
-lb3rit
+lb5rit
lb4ro
l3brü
-lb5sa
-lb5sp
+lbs4
+lb3sa
+lb4sk
+lb3sp
+lbs6t
lbst1e
-l2b5uf
-lb5v
+lb4sto
+lb4stu
+l2b3uf
4l1c
l3che
l5chi
@@ -6899,10 +6935,9 @@ lch3l
lch3r
lch3ü
lch1w
-l3co
4l1d
ld3a2b
-ld1ack
+ld1a2ck
l4d3ad
lda2g
l2d1ak
@@ -6925,7 +6960,6 @@ l3dern
l2d1erp
l2d1e4se
l2dex
-ldi2c
l2d1id
l2d1im
ldo2r
@@ -6943,15 +6977,14 @@ ld1rö
ld3sa
ld3ska
ld3sp
-lds2t
+ld1st
ld1t4
l2d1um
l2dü
1le
3le.
le3ar
-lea5s
-3le3ba
+le3ba
leben4s3
le2bl
2lec
@@ -6967,7 +7000,8 @@ le3f4a
le2g3as
le2gä
le2g5l
-3le3gr
+le3gr
+legs4
3lehr
leh3r4e
3lei.
@@ -6979,10 +7013,14 @@ l2ein.
l2eind
l2eine
l2eint
+lei2s
+lei3so
leis6s5er
l4eist
+lei3su
l2eit
lei8t7ersc
+leit3st
lekt2a
2lektr
3lela
@@ -6999,8 +7037,6 @@ le2m1o2
l2en.
le4nad
le4nä
-4lendet
-2lendu
3lene
le4n3end
4lenerg
@@ -7010,7 +7046,7 @@ le3ni
len3kl
2l1enni
l2e2no
-len5st
+len3st
len3sz
2l1ents
4lentw
@@ -7028,7 +7064,7 @@ ler5b6
4l3ereig
le4r3eim
le4rers
-2l1erfo
+l1erfo
l2erfr
l2erfü
3lergeh
@@ -7044,23 +7080,27 @@ le1ro
3l2erra
l4ers.
lers4k
+ler3ste
le2ru
le3rung
l1erz
l2erza
+les4am
les4e
2lesel
-le3ser
-le5sh
+le5ser
+le3sh
lesi1
le3s2k
-les7sa
+les2t
leste3
4lesw
2lesy
+le4sz
le2tat
2le3th
2leto
+let4tu
le2u
4leud
2leuro
@@ -7070,6 +7110,7 @@ le2u
3lexd
le5xe
le2xis
+3ley
2l1f
l3fa
l5fah
@@ -7081,9 +7122,8 @@ lf3lo
l3flu
lf3ram
lf2s
-lfs1e
lfs3tau
-lfs1tr
+lfs3tr
lf2tr
lf4u
lfur1
@@ -7093,14 +7133,11 @@ l2geti
lg3lo
lg3re
l3gro
-lg4sc
-lg6st
-2l1h2
+2l1h
l3he
3lhi.
1li
3li.
-l4ia
li1ac
li1ak
li3bi
@@ -7116,12 +7153,12 @@ liebe4s
lie2n
li3ene
li5enp
-lie4s1c
+lie4s3c
+lie2st
li3fa
li4fe
5lig
li3g4n
-lig3s2
li3ke
li3ki
li3kli
@@ -7144,7 +7181,7 @@ li4neh
li2nep
li4nes
2l1inf
-ling6s
+ling4s
2l1inh
li5ni
2l1i6nit
@@ -7158,8 +7195,7 @@ l2insc
l1inv
4linz
li2o
-lion5s
-li2p5a
+li2p3a
5lipt
3lis.
li3s2a
@@ -7168,13 +7204,15 @@ li4schu
2l1isl
2l1i2so
liss4
+3list
li2tal
li3te
li1t2h
lits2
-lit5st
+lit3st
lit3sz
-li2tur
+li3tu
+li4tur
3liu
2lixi
li2za
@@ -7182,11 +7220,13 @@ lizei5
4l3j
2l1k
lk1alp
-l3k4an
+l3k2an
l3kar.
lk1arm
+l3ke
lken3t
l2kep
+lkir5
lk3lo
l3k6lu
lk3nu
@@ -7194,33 +7234,31 @@ lkor2b1
l3k4ra
lk3ro
l2k3ru
-lk4s1
-lk5sä
-lk5ste
+lk2s3
+lk3sä
+lk4stä
l3k2ü
lkü1b
-2l1l
+4l1l
ll1abb
ll1abe
-ll5aben
+ll3aben
ll1abt
l3labu
ll1aff
ll1akt
l3l2al
-l4l3a4m
+l2l3a4m
l2l3anz
l3lap
ll1arm
-l4l3art
-l2l1au
-ll4aufe
+ll3art
+ll1au
ll3aug
-l4l3aus
+l2l3aus
l2l1äm
llb4
ll3d
-l2leb
l3lec
ll1ech
l2l1ef
@@ -7228,34 +7266,38 @@ ll1eim
llei4ne
l3l2em
l3len.
-lle6n1a
+lle4n1a
ll3endl
ll3endu
llen3g
l3ler.
lle2r3a
+l3lere
l4l3ergo
ll3ernt
l2lerz
ll2es
llg4
-l6lieg
+ll1imb
ll1imp
l2l1ind
lli5ne
l2l1ins
+ll3l4
ll5m
-l2l1ob
+l2l1ob6
l2l1of
ll1opf
l2l1o2r
l2l3ou
ll1ov
+l3low
l4l1öf
-ll3ö6se
+ll3ö2se
ll3sh
ll3s2k
-ll4s3tor
+ll3sp
+ll4spr
llt4
ll3th
llti2m
@@ -7264,8 +7306,9 @@ llt5s2
ll1ur
l3lus
llust6
+llus5tr
ll3z2
-4l1m
+2l1m
lm3a2b
lm1aka
l2m1arc
@@ -7280,6 +7323,8 @@ lm1orc
l2möl
lm3p
lmpf4
+lm1s2t
+lm3ste
lm3sz
lm3th
4ln
@@ -7295,7 +7340,7 @@ l1nü
2lobj
2lo2bl
l2obr
-lo3b4ri
+lo3bri
lof4
4l1o2fe
lo1fl
@@ -7307,8 +7352,8 @@ lo2k3r
lol2a
l3oly
lo2min
-l4on
lo4n1o
+lon3st
lo2o
2lope
2lopf
@@ -7323,12 +7368,10 @@ lo3ro
3los.
lo4sa
3lose
-los3se
+los5se
lost4
-lo4steu
-lo4s3to
-lo4s3tr
-lo2ßu
+lo4ste
+los1tr
lo2ta
lo3th
loti4o
@@ -7342,6 +7385,7 @@ lö3du
l3öhr
2l1öl
5lösc
+5lösu
4löß
2l1p
lpe2n3
@@ -7354,29 +7398,28 @@ lp3t4
lque3r
2l5r2
lrat6s
-lro3m
lru3t2
lrü1b
-4l1s
-l3s2ac
+4ls
+l3sac
l2s3a2d
-l7s2al
-l4s1amb
-l2sann
+l5s2al
+l4s3amb
+ls3amp
+ls1anf
+ls1ang
+l2s1ann
l3sare
-l2sau2
+l2s1au2
l4schin
-l5se.
l2s1e2b
ls1ec
-ls1ein
l2s1em
ls3ere
ls1erg
ls1erl
l2s1ers
l2s1erw
-l5ses
l3sex
l4sha
lsho2
@@ -7386,66 +7429,66 @@ ls3ohne
l4s3ort.
ls2pi
l3s2po
+l3spri
l3s2pu
ls3s2
lst2a
l5s2taf
ls3täti
+l1stec
l5stei
l5stel
-l5ster
-l4s1tis
-l4stit
+l5steu
+l1sti
+ls2tie
+l2stit
+ls2tol
+l1s2tr
+l1s2tu
ls1um
l3sur
-l3sus
+l1sy
ls2zen
-6l1t
+4l1t
lt1ac
lt1ak
lt1am
-l3tami
-l3tan.
+l4tame
lt3and
lt1ang
l3tar
lt1art
-l3tas
l3tat
l4t3ato
lt1au
-l3te.
l5tef
lt1eh
lt1ein
l2t1eis
lte5lei
-l3t2en
-l5ten.
+lt2en
lter3a
l3t4erg
lt2erö
lter4sp
-l2t3esk
-lte5str
-l3tet.
+l4t3es3k
+lte3str
lt3e2th
-l2t1eu
+lt1eu
l2t1h
l4t5hei
l3thu
+l3ti
ltimo4
l2tob
l3toc
lt1of
-l3ton
l2t1op
l2t1o2ri
lto3we
lt1öl
lt1ös
lt3öt
-lt4rak
ltra1l
l3trä
lt3räu
@@ -7456,11 +7499,10 @@ lt3ros
l2t3rö
lt5sc
lt2se
-lts1ei
lt3spa
lt3spr
+lt4spre
lt4stab
-lt5ste
lt4stoc
lt3t
lt1uh
@@ -7495,6 +7537,7 @@ lu2go
lu2g3r
lug3sa
lug3sp
+lugs4t
lu2gu
2l1uh
lu1id.
@@ -7518,33 +7561,33 @@ l1urn
l1urt
2luse
lu2sp
-lus4sä
+lus4s3a
+lus2s3c
lus4ser
-lus4si
lus2s1o
-lus2s3p
-lus6st
-lus8suc
-5lus2t
-lu4st3a
-lu6stä
+lus4s3p
+lus4st
+5lu4st
+lus2t3a
lust3re
lu2s1u
-lu2ß1
lu2t1a
+lu2tä
lut3erg
+lu5terk
lut1o2f
lu2top
-lu2t5r
+lu4t5r
3lux
2lüb
5lüd
lüh1l
+lü2s
2l1v
+l3vo
l2vr
2l3w
l5wa
-lwa5re
1ly
ly1ar
ly3c
@@ -7564,7 +7607,6 @@ l2zö
lzt2
lz3th
l2z1u4fe
-lzug4s
l2z1w
lz2wec
6m.
@@ -7581,7 +7623,6 @@ ma3da
ma3de
ma4d2s
ma1e
-ma2es
ma1f
2m1agg
magi5er.
@@ -7592,7 +7633,7 @@ ma5g6n
ma3ha
mah4ler
mah3li
-mai4se
+mai6se
2m1akt
ma1la
ma2l1ak
@@ -7604,7 +7645,7 @@ mal3d
mali3er
mal3lo
2mallt
-malu2
+malu4
ma2l3ut
mam3m
2m1anal
@@ -7618,14 +7659,13 @@ man3ers
ma2net
mang2
2mangr
+m2anh
2manl
m4ann
-2mans
-2mantw
manu3
2manz
ma2or
-m4app
+5m4app
2m1arb
mar3g2
ma3ri
@@ -7638,15 +7678,15 @@ mar5te
ma3ru
3m4as
ma3s2p
-mas4t
+ma3sto
+ma1s2tr
3maß
m4at
ma2tan
ma2tä
mat4c
-ma2tel
+ma4tel
ma4t3erd
-mats2
mat3se
mat3sp
3maue
@@ -7663,11 +7703,12 @@ mä1i2
m1ärg
mät4
mä1tr
-mäu4s1c
+mäu4s3c
2m1b4
mb2a
mbe2e
-m3br
+mbe4n
+m3b6r
2m3c
2m1d
md1ar
@@ -7680,7 +7721,7 @@ mdu3s
meb6
me1c
medi3
-medi5e6
+medi5e4
medien3
2medy
me1ef
@@ -7690,13 +7731,14 @@ mega5
2m1eif
m2eil
me1i2so
-m2eist
+3meist
2mej
me3lant
3meld
me2lek
-melet2
+melet4
2m1elf.
+mell2
melt4
6m5eltern
mel3tr
@@ -7708,10 +7750,13 @@ men3au
m3endl
men3gl
me3nor
-men4sk
-men2so
+men4s3k
+men4so
+men3st
men3ta
+men6tanz
4m3entn
+ment6sc
4mentw
me1o
2me3ou
@@ -7729,18 +7774,15 @@ mer2kl
me3run
mer3z4en
3mes
-me2s3a
+me2s1a
me2sä
mes2e
-4me5sh
+4me3sh
4mes2sa
-mes6sig
mes2s1o
mess1p
meste2
-me4str
4mesu
-3me2ß1
me3t4a
mete2
me3th
@@ -7750,13 +7792,14 @@ meu1
2m3f
mfi4l
4m1g2
+mge1
2m1h
1mi
3mi.
mi1ak
mi3an
mibi3e
-mi1ch
+mi1c
mi3da
mie3dr
mi2e1i
@@ -7773,45 +7816,45 @@ min5de
min2e
mi3neu
min2ga
+mings4
+ming3st
mi3ni
mi3n2o
3miri
3mirs
-mir3sc
+mir5sc
3mirw
mi2sa
mise1
mi3sp
-mis2s1c
-mis6st
-mi2ß1
+mis2s3c
+mi4ste
3mi2t1
-mi3te.
mit3es
mit3h
-mi3ti
-mit5s2
+mit3s4
+mit5sa
mi5tsu
4mitz
2m1j
-6m1k4
+2m1k4
m3ka
mk5re.
-6m1l
+2m1l
m3la
m3le
m5li
mlö3
-4m1m
+2m1m
mma4ge.
m2m1ak
m2m1al
m2m1ang
-mm1ans
+m2m1ans
mm1anz
+mma3s4t
m2m1au
m2m1ei
-mmeis3t
mme4lin
mme4na
mme2ra
@@ -7823,9 +7866,9 @@ mm1inh
mm1ins
mm1int
mmi3sc
+mmi3s2t
+mm3m2
mm3p
-mm2s2
-mm3si
mm3sp
m2m3um
mmül2
@@ -7837,7 +7880,7 @@ mo4a3
2mobj
3mod
mo2dr
-2mog.
+4mog.
mo2gal
3moh
mo2i
@@ -7849,7 +7892,8 @@ mo5m4e
m2on
mo3ne
mo4n1er
-mon3su
+mons1
+mon5su
3mo2o
2mo1pe
mo2per
@@ -7858,8 +7902,11 @@ mo1r4a
mor5ar
2morc
mor4d3a
+morgens6
mo4sk
mo3sp
+mo5s2ta
+mo3to
m1o2x
mo1y
1mö
@@ -7879,32 +7926,35 @@ mp3lu
mp3ta
2m1q
4m3r
-4m1s
+4ms
msa3l
-m2san
+m2s1an
ms3and
m4sap
ms3as
-m5sat
-m2sau
-m3sc
-m5sche
-m4sco
-m2s1ef
-ms1erf
+m2s1au
+m3se
+m4s1ef
ms1erw
+m4s1ex
ms1ini
mso2r
ms1ori
m2spä
ms2po
ms3s2
-m4stal
-m4strä
-m3stu
+m6stag
+m2stal
+ms2tau
+m1stec
+m1s2ti
+ms2to
+m1s2tr
+m2strä
+m1s2tu
+m3s2tü
ms1um
m2sü
-m3süc
m3sy
ms2ze
4m1t
@@ -7919,24 +7969,26 @@ m2t1erf
m2t1erg
m2t1erl
m2t1ers
-m2t1ert
-m2t3eta
-m2t1eu
+m4t1ert
+m4t3eta
+mt1eu
m2t1h
mt5ho
-m2t1im
-m2t1ins
+m3ti
+m4t1im
+m4t1ins
mt1int
mti2s
mt1ös
mt2s
mt3sc
-mt7sco
+mt5sco
mts1e
mt3s2ka
mts1p
mt3spa
mt3st
+mts3ti
mt3t
mt1um
mtu3re
@@ -7944,6 +7996,7 @@ mt1urt
mt3z2
1m2u
mu1a
+mu3cke
2m3uh
mu3la
2muls
@@ -7956,19 +8009,17 @@ mu3ne
4m3ungeb
m4unk
mu3no
+mu3ra
mur3ma
mu3ru2
mu4r1uf
-mu4s1a
+mu4s3a
mu2s1o
mu2sp
-mus4st
-mu6s1to
-mu4str
+mu2s1t
mu2su
-mu2t1au
-mut4s3
-mut5sc
+mut1au
+mut2s3
1mü
2müb
3mün
@@ -7976,11 +8027,12 @@ mut5sc
2m1v
mvol2l1
2m1w2
+mwa4
mwel4
-1my3
-my4an
+1my
+my4s3
+my3t
2m1z
-mzug4
6n.
1na
5na.
@@ -7990,8 +8042,10 @@ na3ber
4nabw
na2c
nach1
+na3chen
nachs2
5nachw
+na3cke
4n3add
4n3adr
na1e
@@ -8031,22 +8085,23 @@ n4am.
5nami
na3m4n
3namo
-nam2s
-2n3amt
-namt4s
+n3amp
+nam4sp
+4n3amt
+namt6s
n1an
+4nan.
4na2na
4n3anb
n2anc
4n3ang4
4nani
4nank
-4nanl
-5nann
+4n3anl
na3no
-4nanr
-2n3ans
-4nantr
+4n3anr
+4n3ans
+4n3antr
2n3anw
n1ar
5n4ar.
@@ -8062,17 +8117,16 @@ na3ru
3nas
na4schw
4n3asp
+na5sta
4nasy
-nasyl2
-3naß
3nat
5nat.
5nate
na3t2h
-5nats
+5nats1
nat4sa
-nat6s3c
-nat5st
+nat6sc
+nat3st
4natt
n1au
4nauf
@@ -8086,7 +8140,7 @@ nau3sc
n3ausl
4n3auss
4n3ausw
-nau3te
+nau5te
navi5er.
navi5ers
1nä
@@ -8096,17 +8150,14 @@ n2äc
n1ähn
2n1ä2m
2n3än
-näng5
+när4s1
n1ärz
-2nä2s
+2näs
nä4sc
-3näß
2näu
5nä1um
-4n7b4
-nbau3sc
+4n7b6
nbe2in
-nbe5n
nber2e
4n1c
nc5ab
@@ -8116,8 +8167,9 @@ n3ces.
n3che
nch3m
n3chu
+n2ck
n5cu
-6n1d
+4n1d
nd1ab
n3daf
nd2ag
@@ -8130,22 +8182,26 @@ nd1arb
nd3arr
nda3ru
n2d1au
+n3de.
nde4al.
nde3alt
nd1ei
nd3ei.
ndel4st
+n3den.
n4d3ents
nde3o
n5der.
n5deri
nde4rob
-n3de4s
+nder5ste
+nde4s
ndes1e
-ndni4
+ndo1c
n3dol
nd1op
n2d1or
+ndo3st
nd3rat
nd3räu
n2d3re
@@ -8158,8 +8214,8 @@ n4d5run
nd2sor
nd2spr
nds3tau
-nd5ste
-nd2sum
+nd3te
+nd1th
nd1t4r
n2dum
nd2ums
@@ -8177,8 +8233,9 @@ ne2bl
2n1ebn
2nec
3neca
-2ne2e
-nee1i4
+4nech
+2ne2e1
+nee3i4
ne3ein
ne3en
nee3t
@@ -8194,6 +8251,7 @@ n3ehe
n2eid
6neif
3neigt
+5neigu
4nein
6n3eing
6n3eink
@@ -8231,10 +8289,10 @@ nen3ei
ne4nene
ne2ni
nen3k
+5nenn
ne2no
-nen5s4e
+nen7s4e
nen3sk
-nen5st
5n2en5t2a
n1entb
4n3entl
@@ -8258,7 +8316,7 @@ ne2r3ap
ne2rau
4n3erbi
2n1erf
-6n3erfo
+4n3erfo
nerfor4
4n3erfü
n1erg
@@ -8269,7 +8327,6 @@ n1erk
n3ermä
ner4mit
2nermo
-3nern.
4n3ernt
ne1rös
n2ers.
@@ -8278,13 +8335,12 @@ ner8schle
3n4ert.
4n3ertr
ne2rup
-n2erv
4n1erz
3n2es
n4es.
ne3san
ne2sä
-nes2c
+nes4c
nesi1e
nes2k
ne3ska
@@ -8292,7 +8348,8 @@ ne2s1o
ne2s1p
4n3essi
5nest
-nes3tei
+ne2ste
+nes3ti
net1ak
net1an
ne2tap
@@ -8301,6 +8358,7 @@ net1au
ne2th
net3ha
ne2tre
+nett6sc
2n3e2tu
net2zi
ne2u
@@ -8318,7 +8376,8 @@ nfi3le
nf3läd
nf3lin
n3f2o
-nf4r
+nfo3s
+nf3st
nft2o
nft4s3
4ng
@@ -8349,10 +8408,11 @@ ng5ho
ng5hu
n2g1i2d
ng4lad
+n3gläs
ng3lein
ng3lo
ng3lu
-n4g5m
+ng5m
ng3ne
n2g1or
ng3rat
@@ -8360,11 +8420,11 @@ ng3räu
ng3rein
ng3rev
ng3roc
-ng4s
-ng6s1c
-ngs3e4h
-ng3send
-ngs3pa
+ng4sau
+ng4s3c
+ng4s3e4h
+ng5stel
+ng5stö
ng3ts
n2gue
n2gum
@@ -8384,7 +8444,7 @@ nib3b
ni3de.
ni3di
ni3dr
-n2ie
+n4ie
nie3b
nie3fr
ni1el
@@ -8398,6 +8458,7 @@ nifi3
nig2a
4n3i2gel
ni2g3r
+nig4sp
3nik
nik1al
ni2kä
@@ -8408,11 +8469,11 @@ ni2kr
n2imm
nim2o
4n3imp
-3nin.
+3n4in.
nin2a
4n3ind
2ninf
-3n2ing6
+3n2ing4
4n3inh
nin1i
4n1ins
@@ -8423,28 +8484,25 @@ ni2ob
ni5ok
ni3ol
ni3os
-3n2is
+3n4is
ni4schw
-nis1e
+ni4s1e
+ni5se.
niso2
nis1p
-nis5s2
-nis3sz
-ni2stu
+nis3s2
+nis3tr
ni2s1u
2nit
-ni3ta
ni1th
-ni2ti
-ni3to
+ni4ti
ni3t4r
nit2s
ni3tsc
-nit4tec
-nitt6sa
+nitt4sa
ni3tu
3niu
-3ni3v
+3niv
3nix
2n1j
4n1k
@@ -8456,10 +8514,10 @@ nk1apf
nk1arb
nk1arm
nk3arti
-nk1au6s
+nk1aus
nk1äh
n2k1är
-nk1ec
+nk1e2c
nk1ein
n4k3erfa
nk1inh
@@ -8483,10 +8541,10 @@ n4kre.
nk3rede
n3kri
nk3ro
-nk2sal
+nk2s1al
+nks2ei
nk2spa
nk3spo
-nk5sti
nk3s2z
nk2ta
nk3ti
@@ -8514,14 +8572,18 @@ n4n3er4wa
nn3er2z
nne2s
nnes1e
+nne4st
n5neu
nn3f
nn3g
n3ni
+nnis3t
nno3b
nn1o2r
-nn5se
+nn5sc
nn3s2p
+nn3ste
+nns2tr
nn4th
n4n1uf
n2n1unf
@@ -8537,12 +8599,13 @@ no1c
no3dr
2n1of
4n3o2fe
+n4oi
2nole
no2leu
-n4om
nom4e
n2on.
no3n4a
+non3s
3n2opa
2nopt
2nor
@@ -8558,14 +8621,14 @@ n1ort
3n2os.
no5se
no3sh
-3n2oste
+3n2o3ste
n1osth
-nost4r
+no3st4r
no5tab
no2tä
no4t1ei
-no2t1el
-no2t3in
+no4t1el
+no4t3in
no2t1op
no2tr
3nov
@@ -8577,16 +8640,25 @@ n1ök
4n1öl
4n5p2
npa4g
+npir5
+npro3
npsy3
2n1q
4n3r2
nre3sz
-nrö4s1
+nrö4s3
n5ru
4n1s
+ns3ab
n2s3a2d
-n2sall
+ns3ak
+n2s1all
+ns1an
n3sand
+ns3ans
+ns3art
+ns1au
+ns3auf
n2s1än
n2s1äus
n5sche.
@@ -8596,61 +8668,81 @@ n6schlic
n5schr
n6schro
nsch7werd
+n3se
ns1e2b
-n3sec
+ns3ebe
ns1e2d
nseh5ere
nseh3i
-n3senk
+n5senk
nsen4sp
-n2s1ent
-n2s1ep
+n4s1ent
+n4s1ep
ns1erf
-n2s1erg
-n2s1erk
-n2s1erö
-n2s1ers
-n2s1erw
-n2s1erz
+n4s1erg
+ns3erh
+n4s1erk
+n4s1erö
+n4s1ers
+n4s3erw
+n4s1erz
nse2t
n4s1eta
-n3sex
+ns3h
nsho2f
+n3sil
n2simp
n2s1ini
-nsi2te
+ns3int
+nsi4te
ns2kal
-n2s1op
+ns3ko
+ns3ku
+ns3ky
+ns3l
+n3so
+ns3ob
+n4s1op
n4s3ort.
-n2spat
+ns3park
ns4pei
-n3spek
+n3s4pek
+ns3ph
ns2pi
n2sprä
n4s3prie
n4spro
+nsrü2
ns3s2
nst1ak
-n6stat.
-n6s3tate
-n4stau
-n5s2te.
-n4stech
+n3star
+n4s3tate
+ns2tau
+n2ste
+n3stei
nst3eif
-n5stel
-ns4tem.
-n5s4ten.
-n4stent
-ns2ter
-n5s4tes.
+n3stel
+n4stem
+n5stemm
+ns4tent
+n3step
+n5s6terbe
+n5s6terne
+n5s6terns
n5steu
-n4stor
+ns2tie
+ns2to
n4strac
+n4strie
+ns2tu
nst4ü
nstü1b
+n4sty
+n3su
ns2um
-n2s1un
+n4s1un
ns2unr
+n3sy
ns3zi
4n1t
nt3abs
@@ -8696,33 +8788,35 @@ nt1ho
n3thol
n5thr
n5t4hu
+n3ti
+nti3c
nti3k4l
-n2tinf
-n2t1inh
+n4tinf
+n4t1inh
ntini1
-n5tit
+n5ti1t
ntmo2
n5to
nto5me
nton4s1
+ntons3c
n3tö
nt3rec
n5tree
nt3reif
n5t4rep
-nt4rig
n2t3rin
n5trop
n2t3rü
+n4ts
nt3sa
nt3s2o
nt3s2p
nt4s3par
-nts2t
-nt4sto
+nt2sto
nt3t
n3tu
-ntum2
+ntum4
nt3z2
1nu
nu1a
@@ -8730,7 +8824,7 @@ nu4ale
nu3ar
nu3as
nubi3
-2nuc
+2nu1c
3nue
nu2es
nu3et
@@ -8760,10 +8854,8 @@ nu3sc
nu3se
nu3sl
nu3spo
-nu6s1t
-nu2ß
nu2ta
-nu3te
+nu5te
nu2t3r
5nü.
2nü2b
@@ -8773,11 +8865,8 @@ nür1c
4n1v2
n3ver
n3vi
-nvol7ler
4n1w
n3wa
-nwa5re
-2nx
1ny.
1nyh
2nymu
@@ -8786,9 +8875,9 @@ n1yo
1nys
1nyw
4n1z
-nza2
n2zad
-n2z1ag
+n2z1a2g
+nz3am
n2zan
n2z1ar
n2z1au
@@ -8799,12 +8888,10 @@ n4zense
n4zentz
nz3erwe
nzi2ga
-n2zinh
nz1ini
nz1of
n2z1or
nz3th
-nzug4
n2z1wa
n2z1wä
nz1wer
@@ -8824,16 +8911,15 @@ oa3de
o4ah
o4a3i
oa3ke
-oak5l
+oa4k5l
o4a3la
o4a3mi
oanne4
o4ar
-o4a3s
-3oase
-o5a4si
+o4as
+3oa3se
+o5asi
o4at
-oa3te
o1b
ob2al
o3bar
@@ -8843,7 +8929,7 @@ ob2e
2o3be.
ob3ein
2oben
-oben3se
+oben5se
o2ber
obe4ris
obe6sp
@@ -8855,16 +8941,17 @@ o2b5li
1obm
2obo
o2b3re
-ob2s2
-ob3sh
+ob6ris
+ob2s
+ob3s2h
ob3sk
ob3so
-ob3sp
-ob4sta
-ob3sü
+ob3s2p
+ob3str
2o3bu
2o3bü
2oc
+o3ca
o1ce
och1a
ocha2b
@@ -8883,10 +8970,13 @@ och3to
o1chu
ochu2f
och3w
-ock2e
+o3ci
+o1ck
+o2ckar
+o3ck2e
+o3cki
ock3sz
-o3co
-o1cr
+o3cr
o1ç
2o1d
o3dar
@@ -8911,7 +9001,7 @@ o3et.
o3ets
o1ë
2ofa
-of1ac
+of1a2c
of1am
of1au
o2f1ei
@@ -8920,10 +9010,8 @@ o3fer
ofes3
of2f1a
of2f1in
-of2fir
1offiz
of2f3l
-of2fo
of2f3r
offs2
of2fu
@@ -8935,14 +9023,15 @@ of1la
o1f1r
of3ra
of3rä
-of4s1a
-of2se
-of2sp
-of2s1u
+of2s
+of4s3a
+of3sä
+of3st
+ofs1u
2oft
of2tei
of3th
-2o1g
+4o1g
o2g1ab
oga3d
og1ala
@@ -8957,10 +9046,8 @@ og3ins
o2gl
o3glo
o3g6n
-ogoi5
-og4s2
-og5sp
-og5ste
+ogs4
+og3sp
o1ha
o1hä
o1he
@@ -8985,9 +9072,10 @@ ohl3erh
oh5les
oh3li
oh3lo
-ohls2
+ohls2e
oh2lu
oh3m
+2ohn
ohn3a
oh2ni
oh2n1o
@@ -8997,10 +9085,10 @@ oh1o2p
o2h1ö
ohr1a
oh4rin
+oh1s
oh3ta
o1hu
oh1w
-ohwa5
2o1hy
2oi
o1i2d
@@ -9012,9 +9100,8 @@ o4i3ne
oi4r
o2isc
o3isch.
-oi5se
o1ism
-oi4st
+oi1th
2o1j
2o1k
oka3i
@@ -9025,18 +9112,22 @@ o3ki
oki4o
ok3lau
ok3lä
+okna3
ok2s1p
-okt4
+ok3t4
2ol
o1la
o2l1ak
ol2ar
ol1auf
o1lä
+4olc
ol4dam
ol4d5r
+oldwa5s
ol1eie
ol1eis
+ole3s
ol1ex
o1lé
ol4fa
@@ -9048,19 +9139,17 @@ olge4ne
ol2gl
ol2gr
ol2i
+olib6
oli5en
oli5f
-oli3tu
+oli5tu
ol2kl
ol2k3r
-ol2lad
ol2lak
-oll3ans
-ol2las
-ol2läd
-ol4l1ec
+ol2lau
+ol4l1e2c
ol2l1ei
-ol2l1el
+oll1el
oll5ends
ol4l3erk
oll5erwe
@@ -9073,17 +9162,17 @@ olo3p2
ol1ort
o1lö
ol2pr
-ols2
-ol4str
+ol2str
o1lu
ol2z1a
ol6z3ern
ol2zin
-2om
+4om
oma4ner
om2anw
om1art
o2m1au
+o3me.
o2meb
ome3c
o2m1ei
@@ -9095,12 +9184,10 @@ o2mep
o2meru
om1erz
omie4t1
-omil3l
o2m1ind
om1ing
o3mini
om1int
-omi3te
om3ma
om3me
omme4r
@@ -9109,6 +9196,7 @@ om3pf
omp6l
oms2
om3sp
+om1st
o4m3un
o5m4ung
omy1
@@ -9120,22 +9208,24 @@ o3nal
on3ap
o2n3ar
on4are
+on4at
on3aus
2o3nä
onbe3
2onc
2one
on4eh
-one2n1
+on4e2n1
onen3g
+onens2
o2n1erb
on1erd
on1erö
o3nett
on5f
-ong4
+4ong4
on3gl
-ong7sc
+ong5sc
ong5st
4o3ni
o5ni.
@@ -9144,20 +9234,22 @@ o4ni4kr
o4n1im
on3ing
on5k4
-onli4n
+onli4
onlo2c
on3nan
o3no3
o4noke
on1orc
-ons1a2
-ons3as
-on2seb
+on4os
+on2s
+ons3a2
+on3sch
+on4seb
onse2l
-onsi2d
-ons3l
+onsi2
ons1p
-on3t2a
+ont2a
+ont3ant
on6t5end
ont5erw
on2t1ri
@@ -9166,6 +9258,7 @@ on5v
1ony
on5z
o1ñ
+oof4
oo2k
ook3l
o1op
@@ -9173,12 +9266,13 @@ o1or
oor3f
oo4sk
oo2tr
-oot4st
+oot2st
2o1ö
o1pa
opa1b4
o2p3ad
op1akt
+opa5st
o1pä
o1ped
o1pei
@@ -9225,7 +9319,7 @@ o2ranh
orani1
or3arb
o1ras
-or3att
+or3au
o3r2ä
or3änd
or3ät
@@ -9233,7 +9327,7 @@ or2bar
or1c
2orca
or2ce
-2or2da
+4or2da
ord1am
ord3ele
or4d3eng
@@ -9242,10 +9336,11 @@ or2d1ir
1ordn
or2do
2ords
+ord3s2t
2ordw
4ore
ore4a
-o2r1eck
+o2r1e2ck
o5ree
o2r1ef
ore2h
@@ -9255,7 +9350,7 @@ o2r1er
or3eth
2orf
or2fle
-or3g4a
+or3ga
2orget
or3g2h
2orgia
@@ -9265,18 +9360,18 @@ or3gle
o1ri
2o3ric
o3rier
-4o5ril
+4oril
4orin
or1ins
2orit
-o5riz
or3k2a
or4k3ar
-ork1s
+ork2s
2orm
or2mor
or3na
or3n2o
+orn3st
2o1ro
or3oly
oro3n4a
@@ -9284,24 +9379,25 @@ oro3n4a
2orq
2orr
or3rh
-2ors4
+2ors2
or5sa
+ors4c
orsch5li
or3sh
or3sz
or2ta
or3tad
or4t1ak
-ort3an
+or4t3an
ort1au
ort3eig
ort3ein
+or4tem
or4t3ent
or4t3ere
or4t3erf
or4t5ev
or4the
-or3ti
or4tin
ort3ins
or4t3off
@@ -9310,7 +9406,7 @@ or4t3rau
or4t3räu
ort3re
ort3ric
-ort3sc
+ort5sch
or2t1um
o3ru
or2uf
@@ -9319,16 +9415,15 @@ o5rus
or3ü
2orw
o2rya
-o1s
o3s2a
os3ad
os4an
-os2c
-2o3s2e
+osa3s
+os4co
+2o3se
ose3ei
-o4s3ei
+o4s1ei
ose2n
-o2sé
o3s2hi
o3sho
2osi
@@ -9342,38 +9437,38 @@ os2lo
o2s1p
o4sper
o3s2po
-os2s3a
-os2sä
-os2seg
-os2sei
+os2sa
+oss3and
+os4sä
+os5se.
+os4sei
oss3enk
-os3sent
+os5sent
oss3enz
-os2seu
os4s3o
os4s3p
-os6st
+os4st
oss1ta
-oss1to
oss1tr
-os2t
-o4s4t1a
+o2st
+os4t1a
+os5ta.
osta2b
-o5stal.
-o4sterd
+os5tali
+os5tarr
+os2tau
oster3e
-ost5er6we
-ost3h
-o5stie
-o4stin
-ost1ob
-os3ton.
-o5stons
-o4st3rä
+os6t5er6we
+ost1h
+os3til
+os1to
+os2t1ob
+ost3rä
ost3re
ost3rot
ost1uf
osu4
+o1sy
o3s2ze
o2ß1el
o2ß1enk
@@ -9381,30 +9476,28 @@ o2ß1enz
oße2r
o2ß3ere
o2ß1erf
-oß3th
2o1t
ota3m
o3tark
o2t1au
ot3aug
-otau6s
ot1är
-4ote
-o2teb
-o3te1i
+4o3te
+o4teb
+ote1i
ote3i6n
ote4l1a
ot4em3
otemp2
-o2t1erw
+o4t1erw
4oth
ot2he
ot3hel
o4t1hi
ot1hos
o4thr
-ot2i
-o2t3i2m
+o3t2i
+o4t3i2m
o4tl
otli4
4oto
@@ -9417,9 +9510,7 @@ ot3rut
ots1p
ot4spa
ot3spe
-ots2t
-ot5stra
-ots3tri
+ot3stra
ot2tau
ot3te
ot4t3erk
@@ -9436,22 +9527,19 @@ o3uh
ou4le.
o3um
o3unds
-oung5
oun4ge.
-oung7s2
-ouri4e
+ouri4
our6ne.
+our3st
ou3s2i
-ou5s2t
-ou3te
outu4
2o1ü
o1v
+ove3s
oviso3
2o3vo
2ow
o1wa
-owa5re
o1wä
o1we
o3wec
@@ -9465,6 +9553,8 @@ o1xo
o2xu
1oxy
o1yo
+oys2
+oy3st
2o1z2
oz4e
o3zi
@@ -9474,15 +9564,14 @@ ozon3a
öbe4li
ö2ble
ö2b3r
-2öc
-ö1ch
+öb2s5
+2ö1c
ö4ch3l
ö2chr
-öchs2t
-öch4str
-ö4cht4
+öch2s
+öchs4tu
+öcht4
ö1d
-ödel5l
ödi3en
ö2du
ö1e
@@ -9499,13 +9588,11 @@ ozon3a
öh3l2e
öh3m
öh1ri
-öh2s
ö1hu
ö2k
ö3ke
-öko5
+öko3
ök3r
-ök2s
ö6l
3öl.
öl1a
@@ -9516,24 +9603,25 @@ ozon3a
öl1im
öl1in
öl2k5l
-öl5la
+öl3la
öl4nar
öl1o2
-öls2
öl3sa
-öl3sz
+öl3s2z
öl1u
öl2ung
öl3z2w
-öm2s
2ön
ön3d
ön2e
ö3ni
+ön2s
+ön3sc
öo1
ö1pe
öpf3l
-ör3a
+öp2s3t
+ör3a2
ör1c
örden3
ör2dr
@@ -9550,22 +9638,22 @@ ozon3a
ör1o2
örs2e
ör3sk
+ör2st
ör2tr
ö1ru6
ö2r1une
-ö1s
ö2sa
ö2sc
ö4sch3ei
ösch3m
-2ö5se
-ö6s1ei
+2öse
+ö2s1ei
ö2sp
-ös4s1c
-ös4st
-ös2t
-ö4sta
-ö5stet
+ös4s3c
+ös2st
+ö2st
+ös3te
+ös1tr
ö1ß
2ö1t
ö2t3a
@@ -9578,7 +9666,7 @@ ozon3a
öwe4
ö1z
öze3
-özes4
+özes2
4p.
1pa.
1paa
@@ -9590,13 +9678,12 @@ pa3g2
pa1ho
1pak
pa1kl
-pak2to
1pa1la
pala3t
1palä
pa5li
2palt
-p4an
+p2an
pa2nar
pan3d
pan4ds
@@ -9605,13 +9692,15 @@ pa2neu
pan3k4
2panl
3pano
+pans4
pan3sl
3panz4
-1pap
+3pap
papie8r7end
-1parad
+3parad
pa2r3af
par3akt
+pa5reg
2par2er
2parg
1park.
@@ -9625,8 +9714,14 @@ pa2ro
1partn
1party
par3z2
-pa3s2p
-pa2ßu
+pa4s
+pa5sa
+pa5sc
+pa5se
+pa5si
+pa5s2p
+pa5str
+2paß
p4at
pa5ta
pat4c
@@ -9636,27 +9731,29 @@ pat2e2
1pau3
p1auf
pa3uni
+pau4st
+pä2
1päc
+pä3cke
1päd
+pä3de
1pärc
+pä3ß
pä4t1e2h
pä4t3ent
pät1h
-pä2to
-pät5s
+pät3s
2p1b
-pbe1
2p3c
4p1d
-pda2
+pda4
1pe.
pe4a2
pea4r
1ped4a
-peed3
+peed1
2pef
pei1
-4peic
pe1im
3peit
2pek
@@ -9667,36 +9764,31 @@ pel5d
pe2let
pe3lin
pe4l3ink
-pel5lä
-pel3l4e
-pel3li
-pel3to
+pell4e
1pem
pena6
pe3n4al
pen3da
pe4nen
1penn
-pens2
3pensi
1pensu
pe2nu
pen3z2
pe1ra
per4an
+pere2
1perle
per6na
perne4
-per4ra
-perr3an
-per2rä
-per4rie
+per4r3a
5pers
-perwa6
+perwa4
pe3sa
pes4e
pese2n
-pes5s4
+pes5s2
+pe2st
3pet
1pé
2pf
@@ -9742,13 +9834,13 @@ pf3th
pgra2
1ph
4ph.
+ph2a
2phab
2phä
2phb
4phd
2p1hei
-phen3d4
-phen3s
+phen3
2ph1ers
2phf
4phg
@@ -9766,18 +9858,20 @@ ph4r
phu4s
4p1hü
2phz
-pi4a5
+pi4a3
+pia5l
+pia5s
pi3chl
p4id
pie3fr
pi2el
pie4la
-5pi2er
+3pi2er
1pil
pil4zer
pi2na
pin2e
-ping5s
+ping3s
3pinse
pi2n1u
pi2o
@@ -9787,9 +9881,8 @@ pi2pe
pi5ri
1pis
2piso
-pis2t
-pi5sto
pit2a
+pi1th
pit2s
pi2z1in
p1je
@@ -9810,10 +9903,9 @@ p4leg
p5lic
p5lif
4plig
+p4lis
p4lo
-plü2
2p1m
-pma1
2p1n
1p2o
po3b4
@@ -9821,11 +9913,11 @@ po1c
2p3oh
po2i
po3id
+3poin
3pol
po2lau
po5li
po3ly
-pont4
po1ob
po2p1ak
po2p1ar
@@ -9837,15 +9929,19 @@ po1rau
2porn
por5s
por4tri
-po5s4e
+po5s2e
po3sp
+po4sta
post3ag
po4stä
-po4st3ei
+post3ei
+po4sti
+po3s4tr
post3ra
po3ta
3pote
pot2h
+3poti
po2t1u
po2w
po1x
@@ -9853,9 +9949,10 @@ pö2bl
pö2c
4p1p
p2p1ab
-pp5anl
+pp3anl
p3pe
ppe1e
+ppe4ler
ppe2n1
pp1f4
p2p1h
@@ -9867,11 +9964,11 @@ pp4li
p2p3ra
p2p3re
p2pri
-pps2
pp3sa
pp3sp
ppt2
pp3ta
+pp3to
p2r2
3prak
3prax
@@ -9887,32 +9984,32 @@ pre2e1
3preis
2p3rer
3pres
-1preß
pri4e
1prinz
2prit
-1p4ro1
+1p4ro
3prob
pro3be
2proc
3prod
3prog
3proj
+pro3st
3proto
1prüf
2prün
2ps
4ps.
-ps4an
+ps2an
p3s2h
4psi
p2s1id
p2s1ö
-ps2t
-p5ste
-p4st3r
-p2stu
-ps3tur
+ps2po
+p3stea
+p1s2ti
+pst3r
+ps2tu
3psy
ps2ze
2p1t
@@ -9932,7 +10029,8 @@ p4t1erw
p4t1erz
p5tes
p2t1h
-pt1in
+p3ti
+p4t1in
pto5me
p2tos
p2t3r
@@ -9944,7 +10042,6 @@ pt3st
pt3su
pt3t
pt1um
-p3tung
pt1urs
p2tü
3p2ty
@@ -9958,12 +10055,14 @@ pul4sp
1pulv
1pum
1pun
-2pund
+4pund
pun2s
2punt
1pup
pu3ri
-pu2sc
+pur3st
+pu2s
+pu4s3t
1put
3put2s
3putz
@@ -9971,19 +10070,18 @@ pu2sc
2pül
2p1v
2p1w
-3py1
-py3t
+pwa4r
+3py3
4p1z
q2u4
3quen
que3rel
1queu
-qui5s
6r.
1ra.
ra2ab
-2r3aac
-r3aal
+2r5aac
+r5aal
ra1ar
r1ab
ra2bar
@@ -9993,15 +10091,19 @@ ra3ber
2rabf
2rabg
r4abi
-ra1b4le
+ra1bl
+rab4le
+ra2bli
+rab5r
2rabs
2rabt
-2rabw
+2r3abw
1raby
ra1ce
2r1acet
ra3che.
ra4cheb
+ra3chen
ra3chet
rach4t3r
ra2chu
@@ -10013,7 +10115,7 @@ ra2dam
ra3di
3radle
ra4d3r
-rad3t
+rad5t
1rae
ra1er
r2af
@@ -10063,8 +10165,9 @@ ram6m5ers
ram4m3u
r3amn
ram2p3l
+ram3ste
2r3amt
-ramt4s
+ramt6s
r2an.
4ranc
r2and
@@ -10075,7 +10178,7 @@ ran4d3er
4r5anei
2r3anf
1rangi
-4ranl
+4r3anl
2r1anm
r1anp
2ranr
@@ -10100,7 +10203,6 @@ ra4schl
r4at.
ra2ta
ra2t1ä
-ra3te
2ratm
rat4r
2ratta
@@ -10118,12 +10220,10 @@ ra3umsa
2rausg
rau4sp
raus5se
-raus3tr
+rau4sti
raut5s
1raü
r2ax
-raxis1
-räch4s
r2äd
4räf
4räg
@@ -10134,8 +10234,7 @@ r2äd
2r1är
rä3ra
r3ärz
-rä4s1c
-rä4st
+rä4s3c
3rätse
rä2u
4räut
@@ -10160,27 +10259,29 @@ r2b5le.
rb5ler
rb2o
rb3res
-rb4ri
+rb6ri
rb2s
+rbs1a
rb4sei
rb4ser
rb3ska
rbs1o
-rb6stä
-rb5ste
+rb4stä
+rb3str
4rc
r1ce
+rcha2
r1che.
r1chen
r1chi
rch3l
-rch5lö
rch3m
rch3r
-rchs2
+rch1s4
rch3sp
rch3ta
rch1w
+r2ck1
r1cr
r1ç
2r1d
@@ -10197,25 +10298,23 @@ r2d1elb
rde7me
r3den
rde5nar
-rdend4
rden4gl
rde3r2e
r4d3ernt
-rdes4
rde3sp
-rdga4
+rde3sta
rdi3a2
rdi5a6l
r2d1inn
r2d1it
rd1os
-rdo4st
rd1ös
rd3rat
rd3rau
+rd1st
rdt4
+rd1th
rd1tr
-rdwe5ste
1re
3re.
re3ad
@@ -10232,6 +10331,7 @@ re2bü
rech3ar
4rechs
2reck.
+re2cka
3reda
4redd
3rede.
@@ -10242,8 +10342,9 @@ re3er
4reff
3refl
3refo
-3refr
+3refro
3reg
+5reg.
rege4l3ä
re2gl
4reh
@@ -10265,7 +10366,6 @@ rein6sta
rein8s7tre
re1in2v
2reis.
-reis5tro
2reiwe
re2ke
re3la
@@ -10290,7 +10390,6 @@ re4n3end
ren4gl
2rengp
re2ni
-ren4nes
2r1entl
2r1ents
2rentw
@@ -10338,16 +10437,15 @@ r1er5t
2r1erz
3r2es.
re2sa
-res3au
+res1au
3rese
3resol
re3sp
2ress
ress2e
res6s5erw
-re4stu
+re2stu
3resu
-4re2ß1
re2thy
re2u
reu3g2
@@ -10358,27 +10456,26 @@ re3uni
r1e2w
rewa4
re3we
-re3wo
4r3e2x1
3rez
4rezi
1ré
2r1f
-rfall6s
rf1ält
r2fent
r3f2es
rfi4le.
+rfin6s
rf3lic
rf3lin
r3flü
r3fre
-rf2sa
-rf2s1ä
-rf2se
+rf2s
+rfs1ä
rf3sen
rf4s1id
rfs3pr
+rf3sto
rf2ta
rf3tau
rf3t4r
@@ -10388,7 +10485,6 @@ rg2ab
r2g1ah
r2g1ak
rg2an
-rga5ste
r3ge
rge4an
rge2bl
@@ -10397,7 +10493,6 @@ rg5e4tap
r4geto
rgi4sel
r2glan
-rgleich8s
r2gleu
r2glig
rg3lo
@@ -10411,7 +10506,8 @@ r2g3res
rg3ret
rg3rin
rg3s2p
-rgs2t
+rg3str
+rgt4
rg3th
r1h4
2rh.
@@ -10435,10 +10531,9 @@ ri1cha
rich3te
4rick
rid2
-ri2dan
+ri2d3an
2ridol
r2ie
-rieb4st
ri1el
ri3els
riene4
@@ -10447,29 +10542,30 @@ rie2nu
ri1er.
ri4e3re
ri3ers.
-ri3e4sti
+ri3esti
rie5te
ri1eu
-ri2fa
+ri2f1a
ri4f1ei
ri4fer
ri2f1o
ri2f5r
+rif3st
rif4ter
-3r2ig
+3rig
ri4g5ene
+4rigg
5rigj
rig1l
4rigr
-rigs2
r2ik
ri4k5l
ri5kle
ri3ma
r2imb
2rimp
-rim4s
-rim6sc
+rim2s
+rim4sc
rin4a
2rind
ri5n4e
@@ -10502,22 +10598,22 @@ ri3so
ri4s3p
3riss
ris4sa
-rist5ers
-ristes4
-3ri2ß1
+ri4st
+ris6t5ers
r2it
r3i2tal
-ri3ti
-rit4r
+riten3
+ri5ti
+ri3t4r
5ritu
ri2x1
-4riz
1rí
2r1j
2r1k
rk1all
rk1aus
rk1äh
+rke2s
r3kla
r5klau
rk3li
@@ -10531,11 +10627,12 @@ r2k3rea
r3kri
rk3rin
rk2s1e
+rk3sen
rk3shi
rk2sp
rkstati6
rk4stec
-rks1ti
+rks3ti
rk2ta
rk4t3eng
rk4t3erf
@@ -10544,43 +10641,41 @@ rk4t3erw
rk2tin
rk2t1o2
rkto4b
-rk2t3r
+rk4t3r
+rk5tra
r2k1uh
rk2um
rku4n
rk1uni
-rku6s5t
2r1l
r3la
r3le
rle2a
r3l2i
-rlös5s
+rli2s
+rlon3
+rlös3s
rl2s1p
-rl4s1to
+rl2sto
rl3th
-rlu4str
4r1m
r2m1ald
-rm1ans
+r2m1ans
rm3anz
r4m3a2p
-r5mapp
rm1aus
rm3d
r3me.
r2m1ef
rmen4sc
r2meo
-rm2es
r2mide
r2m1im
-rmi3te
rm1ope
rm1o2ri
+rmo3s
rm3sa
-rms2t
-rm5sta
+rm3sta
rmt2
rmt3h
rm3ums
@@ -10595,8 +10690,9 @@ rn3are
rn5ari
r2n3au
rn4aue
+rnd4
rn3do
-rn3d4r
+rn3dr
r3ne
r5ne.
rn3e4ben
@@ -10612,7 +10708,7 @@ r4nerg
rn4erhi
r4nerk
r4n1ert
-r5nes
+r5ne2s
rn4e2t
r4nex
rn3g2
@@ -10636,7 +10732,7 @@ ro4bei
2robj
1robo
2robs
-ro1ch
+ro1c
3rock.
r4o3de
r4odo
@@ -10648,36 +10744,41 @@ roh5n
3r2ohr
3roi
ro3in
+ro1ir
ro3le
-rol3l4en
+roll4en
2roly
ro2mad
ro2mer
4romm
r2on
+ronen3
3ronn
rons2
+ron3sp
+ron3str
ron4tan
ro1ny
ro1pe
2ropf
ro3ph
+rop2s
r1or
-r2ora
-ror3al
+r2or3a
ro2rat
+ro1rau
ro2rei
ro2r1o
ror5th
-ro3sé
+ro1sé
ro3sh
ro3s2i
ro5sk
ro3smo
ro3sp
-ros4s1c
-ros4sie
-ro4str
+ros4s3c
+ro4ste
+4roß
ro2ßu
ro2tho
ro2tri
@@ -10700,6 +10801,7 @@ rö7le
r1ör
r2ös.
rö3sc
+rö3se
3rötu
2r3p2
r5pa
@@ -10708,47 +10810,51 @@ rpe2re
rpe4r3in
rpf4
r4pli
-rpo4str
+rpo4st
+rpro1
r4ps
rp3se
-r4p3t
+r4pt
r1q
4r1r
rr2a
r3rar
-r5räh
rr1äm
rrb2
rr1c
r3r2e
rrer4
+rre2st
r4rew
rr2h
rr3hö
-r5ries
rri3k
rr2na
rr2o
r2r3ob
rro3m
+rr2st
r3ru
r5rü
rrü1b
4r1s
-rs2a
-r4s3ab
+r4sab
r2s3a2d
rsa4ler
r2s3amp
r4s3amt
-r4s3ang
-rs3anp
-r4s3ar
-rsch2e
+r4s1ang
+rs1anp
+r4sar
+r3sc
+r5sch2e
r6scherl
rsch4l
-rs1ebe
-r2s1ein
+r5schu
+r3se
+r5sei
+r6sein
+r5sel
rse3le
rse2n
rs2end
@@ -10759,7 +10865,7 @@ rs1ers
rs1erz
rs1eta
r3sho
-r3si
+r5si
rs2ka
r5skal
r5skan
@@ -10771,24 +10877,30 @@ r4skr
r4sku
rs3l
rs4no
-r2s1op
+r3so
+r4s1op
r4s3ort.
r3s2p
r4s3ph
-rs5s2
+rs3s2
+rs2t
r4stant
-rs2tau
-rs2te
rst5eing
-r4st3erw
-rs2th
-r4stin
+rs4temp
+r3sterb
+rst3erw
+r3stie
+r2stin
rst3ing
-r5s2tob
-r4s1tot
+r3sto
+r4stot
+r3str
r4st3ran
-r5s2wi
-6r1t
+r3stu
+r3stü
+r3s2wi
+r3sy
+4r1t
r3tab
rt1ac
r2tad
@@ -10799,10 +10911,8 @@ r4t1alm
rtals1
rt1am
rt1an
-rt3anz
rt1ar
rt3a6re
-r3tas
r3tat
r2t3att
rt1auf
@@ -10812,10 +10922,12 @@ r5te.
rtee2
rt2ei
rtei3la
+rtei3s2
rte5m4e
rte2n1
r7ten.
-r5ter.
+rtens2
+rten3st
rte1ra
rte4ran
rt3erei
@@ -10826,7 +10938,6 @@ r5terli
r4t3ernä
rter4re
r4t3ersc
-rtes2
rte3sk
r2th
rt1he
@@ -10835,36 +10946,38 @@ r3tho
rt1hol
r3thu
r3thy
+r3ti
r4t1id
r4t1ima
rt1int
-rt5le
rto3p
r2t1o2r
+r4trak
rt3rec
-r4treis
r2t3res
+rtrü2
rt4sam
-rt5scha
+rt3sch
+rt7scha
rts1eh
-rts1ei
rt3spe
rtt4
r2t1urt
r3tün
-rt5w
+rt3w
r3ty
rt3z2
ru1a
ru3a2r
rube2
+ru3cker
+ru4cku
ru3de
rude2a
ru2dr
3ruf
ru2fa
ruf4s
-ruf5sc
4rug
2ruhr
5ruin
@@ -10904,13 +11017,15 @@ r3ur1e
5ru3ro
ru2si
rus2s1p
-rus6st
+rus4st
+ru4st
+ru5s2ta
ru2th
rut1he
ru2t1o2
ru2t3r
rut2s
-4ruz
+6ruz
ru2z1w
r2ü
4rüb
@@ -10920,15 +11035,13 @@ rü1ch
4rümm
2r1v
rve4n1e
-rv2s
2r1w
-rwa5re
4r1x
1ry
ry2c
ry3t
2r1z
-rz1ac
+rz1a2c
rz2ach
rz2an
r2z1ar
@@ -10950,27 +11063,27 @@ rzu3g2u
rz1urs
r3z2wä
r3z2wec
-8s.
+6s.
1sa
5sa.
-5s4aa
+5saa
2s1ab
sa2be
3sabet
sa1b4le
4sabs
-sa3che
-sacho6
-sa3cr
+sa2chi
+sa2cho2
+sa1cr
2sada
s3adm
2s3adr
sa3fa
sa4fe
-4s3aff
+4s1aff
sa1f4r
3sag
-s3a2gr
+s1a2gr
5s4ai
sa1ik
sail4
@@ -10978,63 +11091,57 @@ sail4
sa2ka
3saki
s4akr
-4s3akt
-3sal.
+4sakt
+3s2al.
3s2a1la
sal3erb
sa2l1id
-s1all
5s4alo
sal2se
-6s1alt
+4s1alt
5s4alz
-3sam
-5sam.
-5same
+3s2am
s3ameri
-5samf
-5samk
5s4amm
6s5amma
-4s1amn
+4s3amn
4samp
-5sams
-5samu
-s1an
-3s4an.
-2s3a2na
-2s3anb
+3s2an.
+2s1a2na
+2sanb
s2an2c
s2and
san4d3ri
-5sang.
+3sang.
2s3anh
-3sani
-2sanl
-2s3ans
+5sani
+2s3anl
+2s1ans
san4sk
san3sp
-4s3anw
+4sanw
2s3anz
2s1ap
sa2po
3sapr
2s1ar
-3s4ar.
+3sar.
3sara
-4s5arb
+4s3arb
3s2ard
3sari
-s3arl
s3arm
s3arr
-3s4ars
-4s3art
+3sars
+4sart
+s3arz
s3a4sp
+sa3stu
6s5asy
+s2aß
3sat
sat2a
-5sa3te
+5sate
4s3ath
4s3atl
4satm
@@ -11043,57 +11150,54 @@ sa3ts
5satz
sat4z3en
sat4zer
-s1au
3sau.
3saue
2sauf
-4s5aufb
+4s3aufb
3saug
sau2gr
3saum
+5saur
sauri1
-2s3aus
-4s5ausb
-3s4ause
-s3auß
+2s1aus
+4s3ausb
+3sause
+s3ausf
+s3ausg
+s1auß
sa2vo
-3sax
+3s2ax
3say
1sä
-3säb
3säc
s3ähn
3säle
s1ält
2s1äm
-2s1änd
+2s3änd
3sänge
2s1är
-sä2s
3sät
3säul
2säuß
-6s3b4
+4s5b6
sba4n
sber2
sbe3re
-sby3
-1sc
+sby5
+1s2c
2sc.
-s2ca
-2scam
6scar
-2s1ce
+4s3ce
6sch.
-7s2ch2al
+2schak
+5s4ch2al
4schanc
-7schanz
+5schanz
6schao
-s2chau
-s2chä
-3schäd
+5s4chä
4schb
-2schc
+4schc
3sche
4schef
sch3ei.
@@ -11103,65 +11207,70 @@ sch5erla
4schess
4schex
4schf
-2schg
-2schh
+4schg
+4schh
3schi
+7schic
schi4e
s4chim
4schiru
4schk
+s4chl
4schle.
6schlein
sch6lit
4schn.
-s2chö
-2schp
-2schq
+5s4chö
+6schöl
+4schp
4schre.
sch5rom
-6schs4
-sch3sk
-sch5ste
-sch5sti
+6schs
+schs4e
+sch3s2k
+sch3sti
6scht
sch3t4a
sch5te
3s4chu
4schunt
sch2up
-2schv
+5schü
+4schv
4schwet
-2schz
-s2ci
+4schz
2scj
-6scl
-6sco
-7s2cop
+4scl
+4sco
+5s4cop
2scs
2scu
-4s1d
-s3da
+4s3d
sda3me
-s3do
+sde3s
+sdi1st
1se
-3se.
se3a
se4al
se5al.
se5at.
-2s1e2ben
+4s1e2ben
se3b4r
2sec
4s1echo
-4s1echt
-3secl
-3seco
-2sede
-5see
+sech2s
+s1echt
+se2ck
+5secl
+5seco
+4sede
+7see
se1ec
se2e1i4
+see3ig
se1er
2s1eff
+3seg
se2gal
se2gl
seg4r
@@ -11175,27 +11284,26 @@ se4hin
seh1l
seh1ra
seh3re
-seh3s
+seh1s
se2hü
2s3ei.
3sei3b
-2s1eig
-5s4ein.
-2s1einb
-s1eind
+4s3eig
+s1ein
+7s4ein.
+4seinb
sei5n4e
-2seing
-2s1einh
-4s1eink
-4seinl
-2s1einn
-2seinr
-s3einsa
-s3einsä
-4s3einst
-2s1einw
-2seis
-7s4eit
+4seing
+2s3einh
+4s3eink
+2seinl
+4s3einn
+4seinr
+s4eins.
+4seinst
+2seinw
+4seis
+7s2eit
5s2ek
s2el.
se2l1a2
@@ -11203,7 +11311,7 @@ se3lad
sela4g
se3lam
sel1ec
-2selem
+4selem
se2ler
sel3erl
sel3ers
@@ -11212,27 +11320,26 @@ se4l1ö
s2els
sel3sz
sel3tr
-3sem.
-se3ma
-2s1emp
-5s2en.
+5sem.
+s4e3ma
+4s1emp
+s2en.
3sena
se4nag
se3nal
-2s1endl
+4s1endl
se4ners
sen3gl
-7seni
+5s4eni
sen3ob
3s2ens
-sen6stri
s2ent.
-2s1entf
-6s3entg
+4s1entf
+2s3entg
s2enti
4s3ents
-2sentw
-4sentz
+4sentw
+2sentz
se2n1u
seo2r
4s1e2pos
@@ -11245,77 +11352,81 @@ s3ereig
se4r3eim
se4r3enk
ser2er
-2s3erfo
+4s3erfo
s2erfr
-4s3erfü
+6s3erfü
ser3g
s1ergä
s2ergr
-2s1erh
-3seri
+4s1erh
+5seri
s1erkl
s1ernä
-2s3ernt
+4s3ernt
se1rot
-2s3eröf
s2ers.
s4ert.
ser3the
seru2
se4r1uf
se3rum
-5s6erv
+7s6erv
5ses.
se3su
3set
s3eta
-4se2tap
+4s5e4tap
se2tat
4s3e2th
-5setz
-3seum
se1u4n
-2s1ex
-se2xe
+2sex
+4sexa
+s1e2xe
4sexp
sex3t
-6s3f
+4s3f
sfal6l5er
+s5fi
sfi3le
+s5fü
4s3g4
-sges4
-sge3sa
+sge3s4a
2s1h
3sha.
sha2k
4shan
+1shas
+s3hä
3shi.
3shid
1shi4r
sh3n
+s3hoc
4shof
-3shop
-sho6r
-5show
+3s4hop
+sho4r
+3show
+s3hö
sh4r
-s3hü
1si
si3ach.
5siak
si1am.
-2siat
si3b4
3si1c
s1ideo
s2ido
3s2ie
+siege4s
si3ene
si3err
+sie2s
3si1f4
-5s2ig
-si2g1a
+5sig
+si2g1a2
si3g4n
si2g3r
+sig4s
si2k1ab
si4k3ere
si4k3erl
@@ -11328,37 +11439,37 @@ si2ku
si5l2e
3silo
2s1imm
+3sin.
si3n4a
2s1ind
-4s1inf
+6s1inf
sin2g1a
sin3gh
sin3g4l
sin2gr
-sing5sa
-4s1inh
-sin1i1
-3sinn.
-3sinnl
+sing3sa
+6s1inh
+sin1i
+sini1e
2s1inq
2s1ins
2s1int
-4s1inv
+6s1inv
3s4io
si3od
si3os
-3s2is
+5s2is
si2sa
si4schu
-si2s1e
+si4s1e
si2s1o
sis1p
-sis5s
-si2stu
-3s2it
+sis3s
+7s2it
si2tau
+si3te
si2t3r
-sit5s
+sit3s
si3tu
5siu
si2va
@@ -11368,18 +11479,24 @@ six3
2s1k4
4sk.
s3kad
-4s3kam
-4skanz
-4s3kas
+s2kala
+4skam
+4s3kanz
+s3kar
+4skas
ska4te.
ska4tes
+s3kä
4skb
4ske
3s2ki.
3s2kik
4skir
+ski3s
3skiz
s3klas
+s3kn
+skna3
4skom
4skor
4skö
@@ -11388,8 +11505,9 @@ s3kra
4sk5t
3skulp
2s1l2
-3slal
+3s4lal
4slan
+s3lä
sl3b
s5le
s5li
@@ -11397,8 +11515,7 @@ s5li
s3lo.
slo3be
s3loe
-2s1m2
-s3mu
+2s3m2
2s3n2
4sna
sna1b4
@@ -11407,10 +11524,13 @@ sni3er.
sni3ers
4s5not
4snö
+s5ny
1so
3so.
3so4a
-2s1o2b
+4s1o2b
+6sobj
+so1c
so3et
3soft
3sog
@@ -11418,7 +11538,7 @@ so3gl
so2h
s1ohe
so3hi
-6s5ohng
+4s5ohng
so3ho
2s1ohr
3sol.
@@ -11437,13 +11557,12 @@ s1opf
3sor.
so1ral
s1orc
-2s1ord
+4s3ord
so2rei
so3ren
-2s1orga
-2s1o2rie
+4s1orga
+4s1o2rie
so2r1o
-5sorp
3sors
so4ru
3s2os
@@ -11456,11 +11575,13 @@ so3unt
3sov
s1o2ve
s1ox
+s4oz
1sö
+sö2c
sö2f
2s1ök
2söl
-s1ö4s
+s1ös
1sp2
4sp.
4spaa
@@ -11471,14 +11592,14 @@ spani7er.
4spano
4spap
4spara
-2sparo
spar5sc
-3s4paß
+3spaß
+2spat
2spau
s2paz
-4spär
+2spär
2sped
-s2pee
+3s2pee
3s2pei
4spel
2s1peri
@@ -11492,11 +11613,11 @@ s2pee
3sphä
s3phe
3spi
-5s4pi4e
+5s2pi4e
7spiel
spier4
spi2k
-6s3pil
+4s3pil
4spip
4s3pis
2spl
@@ -11511,15 +11632,13 @@ spi2k
4s3pok
4spol
4s3pos
-s2pott
4spr.
-3s2prac
+s2prac
4sprax
4spräm
4spräs
5s4prec
2spred
-4sprei
4spres
2spro
4sprob
@@ -11528,296 +11647,292 @@ s2pott
2sprüf
3sprün
4s3ps
-2spun
+4spun
2spup
5s2pur
4sput
3spü
4spy
2s1q
-6s3r4
+4s3r4
srat6s
sret3
-sro3m
srö4s
-srös1c
+srös3c
srü2d
-6s1s
-ss2a
-ss3ab
-ssa3be
+4s1s
ssa3bo
-ss1ack
-ss4ag
-ss3aj
-s3s4al
-s4s5ala
-s4s5alb
-ss4am
-s4s5ang
-ss3ano
-s4s5anz
-s3s4as
-ss3auf
-ss2ä
-ss1ech
-ss1eck
-ssee2
-s2s1ega
+ss1a2ck
+ss1aj
+s3sal
+s4s3ala
+s4s1alb
+s4s1amt
+s4s3ang
+ss1ano
+s4s3ans
+s4sanz
+s3sas2
+ss3att
+ss1au
+s3s2ä
+s3se
+s4s1ec
+sse4ck
+s4s1ega
sse3ha
-ss1ein
sse3inf
sse3int
ss1eis
+s5sen.
ss2er
-s3ser.
sse6r5att
-s3serh
ss3erhö
+s4s3erö
s4s3erse
s5s4es
ss4et
sse3ta
+ss5g
+s5sie
s3skala
+ss3la
ss1off
-s4s1op
+s6s1op
s2s1ori
s3spe
s3s2po
ss5re
-ss3s2
-s5st2a
-s7stad
-s5stä
-ss1t6e
-s4ste.
-s5stel
-ss2th
-s5stil
-ss1tis
-s5sto
-s5stu
-s5stü
+ss3s4
+s3st2a
+s5stad
+sst6e
+ss3tec
+s3stel
+ss2ti
+s3stip
+s3sto
+s3stu
+ss2tur
+s3stü
ss1ums
-ss2zen
-1st
-6st.
-3sta
-s4ta.
-5staa
-4stabb
-4stabh
-4stabl
-stab6s
-4stabt
-4stabz
-5s4tad
-6stada
-6stadr
+4st.
+1sta
+2sta.
+3staa
+stab4s
+3s2tad
5staff
-6stag
-5stah
-4stak
-4stal.
-5sta5li
-4stalk
+4stag
+3stah
+2stak
+s5tal.
+sta5li
+2stalk
st1alp
st3ami
-4stamt
+4stan.
st3ana
-5stand
-4stanl
-6stann
-4stanw
-5star.
-5stars
-5st2art
-sta2s
+3s4tand
+2stani
+4stann
+2stans
+s3tans.
+2stanw
+s2tar
+3s4tar.
+3s4tars
+st2art
+2sta2s
st3a4si
-5stat
+3stat
4stat.
-s2tati
-5stau.
-5staub
-4st1auf
-4staum
+3stau.
+2st1auf
+2staum
5staur
-4staus
-5staus.
-4stax
+2staus
+3staus.
+2stax
3stä
4stäg
4stält
-4stämt
-5stär
-2stäti
5stätt
-4stäus
4stb
2stc
st3ch
2std
-3ste
-4stea
-5stean
-7steck
-4stee
+4ste.
+2stea
+s2tec
+3steck
+1s2teg
ste2g5r
-ste2i
-5s4teig
-6steil
-s4tein
+3steh
+1s2te2i
+3steig
+2steil
4steing
-s2tel
-s3telem
+1s2tel
+2stel.
+2stele
stel4l3ä
+2stels
+2stem
+4stem.
ste4mar
-4stempf
-4st3ends
+4sten
+s4t3ends
ste2ne
-st3engl
-st4ens
-6st3entf
-4stentw
-4stepi
-5st6erb
-st2erg
-5sterj
-s2tern
-s2ters
-6st3ese
-4stesse
-ste4stä
-4stests
-5steß
-s2teu
+s4t3engl
+s5t4ens
+s4t3entf
+s2tep
+2ster
+6ster.
+s3tera
+st6erb
+4sterk
+3sternc
+s3ters
+4stes
+s4t3ese
+stes6se.
+ste4st
+2stet
+4stet.
+3s4tett
+3steu
+5steue
4steuf
st3ev
-6stex
-4stf
-4stg
-6sth
+4stex
+2stf
+2stg
+4sth
st3ha
-st1hi
+s2t1hi
st3ho
st1hu
-3sti
-5stic
-5stif
-5stil.
-5stile
-5stim
-4stinf
+2stia
+2stib
+2stie.
+1s2tiel
+2stien
+3s2tif
+5stift
+4stig
+2stik
+3s2til
+3s4tim
st1ins
st1int
-4stip
-sti2r
+2stio
+2stip
+1s2tir
+2stis
st3iso
+1stitu
+2stiv
2stj
4stk
-4stl
+4s4tl
st5le
4stm
-4stn
-3sto
-4stob
-7stock
+2stn
+1sto
+4sto.
4stod
-5s4to3de
-5stof
-4st3om
+sto3de
+s2toff
+s2t5om
4ston
-4stopo
-4storg
-sto5rin
+2stopo
+2stor.
+2store
+2storg
+2stori
+2s3tose
+stos2t
+3stoß
4stou
-s4tow
+4stow
+4stoz
3stö
4stöch
-7s2tör
-4s3töt
+4stön
+4stöt
4stp
2stq
-3str
-5s2traf
-4strag
-5strah
+2strad
+5straf
+2strag
+3s2trah
6strai
-5s2tral
+4strak
+4stral
4strans
5s2tras
-7straß
-6sträg
+5straß
+4sträg
4sträne
-4stre.
-4strech
4stref
5streif
st3renn
-4strev
-4stri.
-5s4tria
-4strib
-6strig
-stri2k
-2strin
-2stris
-4strisi
-4stroc
-5s2trof
-5s2trok
+s2tric
+2s2trig
+3s2tri2k
+s2trip
+2s3tris
st3roll
-stro4ma
-s2tros
-5s2trö
-5struk
-s2trum
+stro2m
+2strop
+1stru
+4strua
+3struk
4st3run
-4strup
-6st3s4
+4st3s4
st1sk
st1sl
st1sz
2st3t2
5stub
-6stuc
-5s2tud
-2stue
+4stuc
+5stud
+4stue
+3stuf
3stuh
-4stuk
-4stumr
-stum4s
-4stumz
-s2tu4n
-6stun.
-2stunf
-3stung
-2st1uni
-2s3tuns
-2stunt
+stum2s
+stu4n
+4stun.
+3stund
+s2t1uni
+4s3tuns
+4stunt
stu5re
st1url
-2sturn
-2st1urt
-3st2ü
+4sturn
+stur4s
+4st1urt
+2stus
+1st2ü
+3stüc
4stüch
-s2tück
-4stür.
-s2tüt
-2stüte
-6stv
+3stüh
+2stür.
+3s2tüt
+4stv
4stw
-2sty
-3styl
+5styl
4st3z2
1su
-su1an5
+su1an
3su2b5
su4ba
-6su3bi
-7su1c
+4su3bi
+5su1c
2s1u2f
-2s1uh
+4s1uh
3sui
su1is
su3it.
@@ -11828,130 +11943,125 @@ su2mau
3sume
su2m1el
su6m5ents
-s3umfa
+2sumf
s3umfe
+2sumk
+2suml
3summ
sumo2
su2m1or
+2sums
s3umsa
s3umst
su4n
-3sun.
+5sun.
sun6derh
s1unf
2s1uni
-4s3unt
-3s2up
+6s3unt
+5s2up
su2ra
2s1url
s1urt
-su2s1
+3su2s1
su3sa
su3sh
su3si
-sus3s
+3suv
1sü
-4sü2b
+2s3ü2b
+3süc
3sü2d1
-5sün
-4s1v
-4s1w
-swa5re
+3sün
+4s3v
+s5va
+2s1w
+s3wa
+s3we
sweh2
-6s3wie
-6s3wil
+4s3wie
+4s3wil
s3wir
s3wis
s2y
3sy.
-sy2l1
+sy2l
sy4n1
-1sys
-sy5st
+1sys5
sy3t
2s1z
-4s3za
+s3za
4s3zei
3s2zena
-5s2zene
+5s4zene
4s3zent
s2zes
-s2zeß
s2zis
-s3zö
4s3zu
+s3zü
s3zw
2ß.
-ß3a2
-ß1ä
-ß1b
-2ß1c
-ß1d
+2ß3a2
+2ß1b
+4ß1c
+2ß1d
1ße
2ß1ec
2ß1e2g
2ß1ei
-ße2l
-ßel1a
-ße3lu
+ße2l1a
ßen3a
+ßene4
ßen3g
ße2ni
-ßen5st
+ßen3st
ßen3sz
ße2nu
ße3rin
3ß2ers.
-ße2t
-ß1ex
-ß1f
-ß3g2
+2ß1f
+2ß5g2
ßge2bl
2ß1h
1ßi
-ßi2g1a
+ßi2g1a2
+ßig4s
2ß1in
ß1j
2ß1k4
+ßkir5
2ß1l
-ß3la
2ß1m
-ß5n2
+2ß5n2
ß1o2
-ß1ö
-ß3p2
-ß1q
+2ß3p2
2ß3r2
2ß3s2
ßst2
2ß1t
-ß2t1h
-ßts4
-1ßu4
-ß1uf
-2ß1um
-ß1uni
-ß1ü
+ß3ti
+1ßu
+2ß1um1
+2ß1ü
2ß1v
2ß1w
-ßwa5r
-ßwa3s
+ßwa3
2ß1z
-6t.
+4t.
3ta.
2taa
-tab4
+3taan
2tab.
-ta2b5an
+ta2b1an
2t1abb
-1tabel
+3tabel
4taben
ta4bend
-2tabf
+4tabf
4tabg
4tabh
4tabk
-ta1bl
+ta1b4l
1table
2tabn
4tabs
@@ -11959,12 +12069,15 @@ ta1bl
ta2bü
2tabw
4tabz
+ta1c
tach3te
t3ada
tadi3
t3adr
+1taf.
1taf2e
3tafel
+4taff
t1afg
t1af4r
3t2ag
@@ -11973,11 +12086,11 @@ ta2ga
ta2g5ei
4t3agent
ta3ges
-ta3gl
+2ta3gl
ta3gn
4t3a4go
-tag6s
-tag7sc
+tag4s
+tag5sc
tah4
tah3le
tahl5sk
@@ -11987,11 +12100,11 @@ tai2l
ta1ins
tai4r
ta1ir.
-4t3a2ka
+4t1a2ka
ta3kes
3takr
ta2kro
-tak2ta
+tak4ta
3taktb
3t2aktu
3t2al.
@@ -11999,44 +12112,47 @@ ta1lag
ta1lak
1talbu
tal3d
-3t4ale
+1t4ale
ta3len
ta4lens
-tal4leg
+1talia
+5talis
tal2lö
+1talo
ta2l1op
ta3lum
2ta2m
3tam.
ta3ma
+3tame
3tamg
ta3mo
-t1ampl
+t3ampl
t1amt
-t2an.
+3t2an.
t1a2na
ta4nat
-4tanb
-t2and
+2t2and
tan3da
tand4st
ta3ne
4t1anf
+3tanis
t2ank
tan4kl
tan3kr
-2tanl
+4tanl
2t1anme
4t1anna
1tanne
t1ans
-4t3ansi
+1tans.
+2t3ansi
2t3ansp
ta4nu
2tanwa
2tanwä
t4anz.
-4tanzei
tan6zerh
t1anzu
ta3or
@@ -12046,6 +12162,7 @@ ta2pes
t4ar.
2t1arb
t1arc
+3tard
ta6rens
3ta3ri
2tark
@@ -12054,15 +12171,20 @@ ta6rens
t3arti
ta2ru
2t1arz
+3tas
+1tas.
ta3sa
1ta3sc
+2ta3se
4t3asp
-1tas2t
+1tast
+ta3sta
+ta1str
1tat.
ta2tan
-tat1ei
-ta2tem
-ta2t1er
+ta4t1ei
+ta4tem
+ta4t1er
ta2th
tat3he
t3atl
@@ -12073,15 +12195,14 @@ ta2t1um
tau4fer
tau3f4li
2taufw
-1taug
t1auk
2taur
1taus
-2taus.
t1ausb
+3tausc
tau6schw
t1ausd
-3t2ause
+3tause
t1ausf
t3ausg
t1ausk
@@ -12090,112 +12211,135 @@ t1ausr
2t3auss
t1ausü
4t1ausw
+1tav
ta3va
3tax
ta3xi
+1taz
tä1c
1täg
2tägy
2täh
-3täle
4t1ält
2täm
t1ämt
t1ängs
-1tänz
+3tänz
t2är.
tä2ru
tä2s4
-tä4st
-2tätt
+4tätt
t1äug
1täu3s
4täx
1tà
-2t5b
+4t3b
tbe3r2e
tblock7en
-2t1c
+4t1c
t3cha
t3che
tch2i
tch3l
t2chu
tch1w
+t2ck
t3cr
2t3d4
tdun2
tdu3s
-1te2a4
+1te
+3te.
+te2a2
+2teak
te3al
+3team
te3an
+5teba
5t4ebb
2t1e2ben
-1t2ech
-te1cha
+t2ech
+te5cha
3techn
-2teck
+4teck
+te2cka
+te2cki
3tee
te1ele
te1em
te2e4n1
te1erw
4tefe
-2teff
+4teff
te2fl
teg4
teg3re
2teh
te3han
+3tehä
+5tei.
t2eie
-2teig
-1teil
-3teiln
-3teilz
+3teil
+4teilhe
2tein
-tein3ec
+tein3e4c
t3einge
t3einla
4t1einn
4teinr
+4teinz
t1eis.
t1eisb
-tei5st
-tek3te
-te2la4
+tek5te
+5tel.
+3te2la
te4l1ab
tel1ac
te3lan
tel1au
+3telb
+3tele
tel1e2b
tel1ec
-3telef
-3teleg
+5telef
te4l1eh
-1te3lem
+te3lem
tel1en
te3lep
te3lex
+3telf
4t1elf.
+3telg
tel1in
te2lit
+3telk
t4ell
tel3l2e
+5teln
te2lo
te2l1ö
+3telp
+5tels
tel3s2k
+3telt4
tel3ta
-tel3t4r
+3tem
+5tem.
+te2man
te2m1ei
te2mi
te3mis
-4temo
+4temm
+2temme
te2m1o2r
-3temper
-1tempo
+5temper
+4tempf
+tem1st
te4m3u
-t6en.
+3ten
+5t6en.
te4n3a2
+te5nac
t4enb
ten3da
6t5endf
@@ -12214,9 +12358,10 @@ t2enl
t2enm
t2eno
t2ens
+tens2e
4t3ensem
ten3si
-ten5st
+tens3th
t1entb
4tentd
t1entn
@@ -12227,7 +12372,7 @@ ten3zw
te2o
te3ob
t1e2pi
-t6er.
+5t6er.
te1raf
ter3am
te3ran.
@@ -12235,32 +12380,35 @@ te2r3as
t2erb
6t5erbs
6t5erbt
-t3erde.
+4t3erde.
+3tere.
te2r1e2b
te4r3eif
te2rel
+3terem
+3teren
ter3end
-t4erfr
+3terer
+3teres
+5t4erfr
4terfül
ter3g
t6ergru
-2t1ergu
-2tergü
te3ria
ter3k4
-t2erka
+3t2erka
4t3erklä
+3terkr
t4erli
4t1erlö
t4erlu
-1term
+3term
ter4mer
-3termi
ter4n3ar
t3erneu
t1erö
+3terr
ter4re.
-1terro
t6ers.
t6erscha
ter4ser
@@ -12268,37 +12416,43 @@ ter4sk
terst4
t4erst.
t4erste
-t4ersti
+5t4ersti
+ter5sto
ter5str
-t4erstu
-tert4a
-teru2
+5t4erstu
+3tert2
+3teru2
te4r1uf
ter3z2a
-4t1erzb
-t2es
-tes3ac
+2t1erzb
+3t2es
+tesa2
+tes1ac
te2sel
-3tesse.
tes3si
-tes2t
+5te2st
+tes3tan
tes3tät
-te4st3ei
-te7ster.
-te4str
-1tests
-te4stu
+test3ei
+tes6terg
te2su
+3tet
te2tat
+4teth
+4teti
6tetl
+2teu
3teuf
+3teum
te1un
+3teur.
teu2r5a4
t5euro
te2vi
-1te2x
+5tewo
+te2x
te3xa
-t1exe
+2t1exe
4t1exi
4texp
3text
@@ -12306,7 +12460,7 @@ t1exe
1té
2t3f
tfi4l
-2t1g4
+4t1g4
tg2a
t3ge
tger2
@@ -12320,10 +12474,9 @@ t3hap
t2har
4t3hau
4t1hä
-4thc
-1the
+2thc
t2he.
-3thea
+3t4hea
4theb
t2hec
2t1hei
@@ -12332,14 +12485,13 @@ t1hel
3t2hem
5thema
5theme
+1then
3theo
t2hera
t1herd
-2t1herr
+t1herr
t1herz
-t2hes
-3these
-1thi.
+1these
3thia
2t1hil
t1him
@@ -12355,7 +12507,6 @@ t2hol.
4tholz
t2hon
4t3hot
-thou4
4t3hö
2thp
3thr2
@@ -12365,77 +12516,86 @@ thou4
4thun
t1hü
2thv
+1ti
ti2a
ti3a2m
ti3an
tib4
+3tibe
+3tibl
+2tic
ti1ce
-ti3chr
ti4d3end
t2ie
tie3br
-5tief.
-tieg6
+3tief.
+2tieg4
+2tieh
ti1el
ti2el.
ti3e2n1
ti2er
-1tierr
-2tieß
+3tiera
+4tieß
ti3et
ti1eu
-5tif.
+3tif.
ti3fa
-tif3f
ti1fr
-tihi4
-ti2kam
+3tig
+3tik
+ti4kam
ti3k2an
ti2kr
-ti2la
-ti3las
+tik5t
ti2lei
til1ep
-1tilg
+3tilg
ti3lo
ti4lö
tilt4
ti2lu
+2tim
ti2mag
tim2m1a
4t1imp
+5tin.
ti3na
t1inb
4t1ind
ti5n4e
-t1inf
+2t1inf
tin2g1a
tin2g3l
tings2
-ting5st
+ting3st
t1init
4t1inj
tin2k3l
t2inn
+3tins.
4t1inse
4tint
4t1inv
-3tio
+5tio
ti3or
-3tiö
3tip.
ti3pl
-1tipp
-1tips
+3tipp
+3tips
+ti2rak
ti1rh
-t2is
+5t2is
tisch3w
-ti2sei
+ti4sei
ti2sol
t4it
3tite
-5titel
-tium4
+tit2h
+2ti3tu
+tiu6
+tium2
+5tiv
ti2van
ti2vel
ti4v3erl
@@ -12444,8 +12604,6 @@ ti4v1r
ti2za
2t1j
2t3k4
-tklat5
-t5kr
tkü1b
2t3l2
tl4e
@@ -12453,37 +12611,44 @@ tle2r5a
4t5li
tli5f
tlings3
-tli5s
-t5lo
tlö3s
-2t5m2
+2t1m2
+t5ma
tmen2s
tmen6t
+tmin4s
tmo4des
t3mu
tmüll4s3
2t5n4
tna5me
-tnes6
+tnes4
+3to.
+toa4
to5ar
-to5a4t
+to5at
1tob
to3be
2tobj
tob4l
-to1ch
+to2c
+to3ch
3tocht
+to6ckent
3tod
tode4
-to2d1er
-tode6s1
+4to2d1er
+tode6s
to4d1u
-tok4
+1tok4
+1tol
to3la
+3tole
+2tolz
tome2
to4men
2tomg
-1ton
+3ton
to5nik
to3ny
3too
@@ -12494,70 +12659,81 @@ t3opfer
to3phe
to2pl
1topo
+2topp
+1tor
+3tor.
to1ra
to2rau
to4rän
4torc
t1ord
-1tore.
+3tore
to2r1el
to3ren
-t1org
+2t1org
t3orga
3torh
tor3int
to2rö
-1tort
+3tors
t1ort.
to4ru
-to7sc
-to5se
+2tory
+to5sc
+1to5se
to4sk
-to3s2p
-tost4
-to5sta
-1toten
+to5s2p
+2toss
+1to3st4
+2toß
+3to5te
to2tho
-3t4ou
+1totr
+5t4ou
touil4
to3un
3tow
-tö2c
-1töch
+1toz
+3töch
2t1öf
2t1ök
3tön
-tö4s
+tör3ste
t1öst
1töt
4t3p2
-t5pf4
+tpf4
2t1q
t2r4
2tr.
+5tra.
tra3bl
-t4rac
-1trach
+1t4rac
+3trach
tra3cha
t3rad.
tra4dem
-1trag
-3tragö
+3trag
2t3rahm
5t4rai
+3trak
+3tral
3t4ran.
2trand
3trank
t3rann
-3trans
+5trans
t3rase
t3rasi
+tra4st
2traß
1traum
-1träc
+3träc
t3räd
-1träg
-1träne
+3träg
+3träne
+2träs
+2träß
4t5re.
2treb
2trec
@@ -12565,66 +12741,74 @@ t3rech
t4reck
2t3red
t4ree
-1tref
-2trefe
-2trefo
+3tref
+4trefe
+4trefo
2treg
t4rei.
-1t4reib
+3t4reib
+2treic
2treif
t3reig
2t3reih
t3rein
-t3reis
+2t3reis
+4treit
t3reiz
2t3rek
2t3rel
t4rem
t4ren.
-1trend
+3trend
+4trendi
t3rent
2trepe
2trepo
-1trepp
t4rer
-t4res.
-1t4ret
+3t4res.
+t4ret
tre2t5r
t4reu
+3treuh
t3rev
2trez
5t4ré
2t3rh
-1trib
+1tri
t4riche
-3trieb.
-3triebs
+3trieb
tri4er
+3trigg
t3rind
tri3ni
3trio
t4rip
-1triu
trizi1
+1tro.
tro3b
-1troc
-t4roi
+1troe
+3t4roi
tro2ke
+2trom.
tro2mi
+2troml
+1tron
2t3roo
t4rop
3tropf
-2troß
+1tros
+3troy
t3röc
3trög
+1trös
2tröt
+1trua
3trug
2truk
trum2
trums1
-1trunk
+3trunk
3t4rup
-t3ruß
trü1be
trü1bu
2t3rüc
@@ -12632,39 +12816,41 @@ trü1bu
try1
2ts
4ts.
-t2sa
+t2s1a
t4s3ab
-t5s2ac
+t5s4ac
ts3ad
t3saf
-ts1ah
-ts1al
-t4s1amt
+ts2ag
+t4s3amt6
t4s3ar
ts3as
t4sau
t5sau.
t2s1än
-ts2c
+t2sca
t4schar
-tsch2e
+t5sch2e
tsch4li
t4schro
+ts4cor
t2s1e2b
-t3seg
+tse4c
+ts1eck
t4s3e4h
t3seil
t4seind
-ts3einl
ts1em
tse2n
+t3sen.
ts1eng
t2s1ent
t2s1er
+t4s3esse
+ts1ex
t2s1i2d
ts1ini
t2s1ir
-t7sit
t3skala
ts3kr
t2s1o2
@@ -12682,42 +12868,38 @@ t3spek
ts2pi
t3s2pon
t3s2por
-ts5s2
-ts1tak
-ts2tat
+ts3s2
+t1s2t
+ts3taf
+ts3tak
ts3täti
-t4s1tep
-t5s4ter.
-t4sterm
-t5stero
-ts3terr
-t5s4tes.
+ts3tep
+t3stero
t5steu
-ts1tie
-t4s3tis
+ts3th
+ts4til
t6stit
-ts2to
ts3toc
ts3tor
-t4s3trad
-t4strau
-t4s1trä
-t4s1tri
-ts2tro
-t4strop
+ts3trad
+t4s3trau
+t2s3trä
+t2s3tri
+t3strö
ts3trü
+t3stu
+t3stü
t2s1u
1tsub
t3sy
4t1t
tt1ab
tt3ad
-ttag7ess
t2t1ak
t3tal
t3tan
+t4tanb
tt1art
-tta5st
tt1auf
tt1ebe
tt1eif
@@ -12726,7 +12908,6 @@ tt1eis
t3te2l
tte4la
tte4l1o
-t3t2er
tte2s
tte4s1ä
t2teti
@@ -12735,7 +12916,9 @@ tt3ha
tt2häu
tt1ho
tt1hu
+t3ti
t3tra
+t2trau
t3trä
t3t4ro
tt5rom
@@ -12746,30 +12929,33 @@ tt3sec
tt5se5h
tt3sel
tts1p
-tt4s3tem
-tt4ster
-tt4sti
+tt2s3ti
ttt4
-t2tuc
+t3tu
tt3z2
+1tu
tu1alm
tu3an
2tub
-1tuc
+3tuch
tu2chi
-1tue
+2tud
+3tue
tue3re
tu3et
+2tuf
tuf2e
tu3fen
t1u2fer
2tuh
-tu2k
+2tu2k
tu3ka
t1ukr
tu3la
-t2um.
+3t2um.
+5tume
2tumf
+2tumg
2tumk
tum2si
tum2so
@@ -12779,14 +12965,14 @@ tum2so
2tund
3tu3ne
2t1unf
+3tung
t1unga
tun2gl
-tung8s
+tung6s
2tunif
2t1u4nio
-3tunn
-1tuns
2tunt
+3tuö
t1up.
tu2ra
tur3a4g
@@ -12799,7 +12985,7 @@ tu2r1er
tur3ere
tu4res
tu2r3e4t
-1turn
+3turn
tu2ro
tu3rol
tur3s2
@@ -12809,58 +12995,61 @@ tu2sa
tu4schl
tu4so
tu3ta
-tuts3c
2tüb
t3übe
-1tüch
-tück4s
+3tüch
+tück2s
1tüf
+1tüm
1tür.
tür1c
1türe
1türg
-1türs
+1tür3s
3tüten
2t1v
t5vo
4t1w
+twa4r
twi4e
1ty
2tyl
ty4le
+3typ
ty2pa
+ty3st
2t1z
t2z1a2
tz3an
tz3as
t2z1ä
t5ze.
-t2z1ec
+t2z1e4c
t2z1eie
t2z1eis
tze4n
tz4ene
tz3ents
t2z1erl
-t3ze4s
+t3ze2s
tz1imp
+tz1ind
tz1int
t2zo
tz1of
t3zon
tz1or
-tz2tin
+tz4tin
t2z1w
2u.
u3a2b
-u1a4c
+u1a2c
ua3d
uad4r
u1al.
u3alet
u1alf
-ual3l
-ua2lo
+u3a2lo
u1alr
u1als
ual3t
@@ -12880,7 +13069,6 @@ u1äm
u1äu
2u1b
u3be
-ub3ein
ub6i
ub3lic
ub5los
@@ -12888,21 +13076,20 @@ u3blö
ub3lu
u2bop
ub3rä
-ub3rit
+ub5rit
ub2sa
ub2s1o
ub2spa
ub3um
u2b3üb
-2uc
-u1ce4
-uces3
+4uc
+u1ce2
u2ch1a
u3cha.
uch3an
uch1ä
u1che
-u2ch1ec
+u2ch1e2c
uch1ei
u3ches
u1chi
@@ -12913,28 +13100,30 @@ uch5m
uch3n
u2ch3r
uch2so
+uch4spr
uchst4
-uch5str
uch4tor
uch2t3r
u1chu
uch3ü
uch3w
+u2ckem
+u4ckent
uck2er
-uck3erl
+u4ck3erl
+u2cki
uck4sta
u1cr
2u1d
u5d2a
+udens2
ude3r2e
-ude5sa
udi3en
uditi4
u4don
ud3ra
-ud2s
-ud3sc
u1e
+ue4ck
u2ed
ue2en
u2eg
@@ -12954,10 +13143,11 @@ u5eremp
u5erent
ue4rerg
uer3g2
-u3erinf
-u3erint
+u5erinf
+u5erint
uerk4
uer4ne
+uern3s4t
uer3o
u3err
uert2
@@ -12965,13 +13155,11 @@ u3erum
u3erunf
u3erunt
u3erur
+u3erv
uer3z
-ue4s
-ue5se
-ue5sp
ue2ta
ue4tek
-uet2s
+uet4s
uf3ad
u3fah
uf1ak
@@ -12986,7 +13174,6 @@ u3fen.
u2fent
u2f1erh
uf2ern
-u2f1eß
2uff
uf3fe
uff4l
@@ -12997,12 +13184,8 @@ uf1ori
u1fö
uf3r
uf5sä
-uf4s3tem
-ufs3ten
-uf4ster
uft1eb
-uf3ten
-uft3s2
+uft3s4
uft5sa
2u1g
u4gabte
@@ -13017,6 +13200,7 @@ u2g5ent
ug5erf
ug5erl
uge7sc
+ugge4st
ug3hu
u2g1l
ug3lä
@@ -13031,25 +13215,25 @@ u4g3reis
ug3ro
ug3rum
ug3rüs
-ug3sau
-ug7sc
+ug5sc
ug3s2e
ug3si
ug3spa
ug4spr
ugs2t
-ugs3te
+ug5stä
+ug3str
ugut2
u2gü
u1h
2uh.
uhe1ra
+uhe1s4
+uhe3st
uh1la
uh1lä
uh3ma
-uh5me6
-uh3mi
-uh3na
+uh5me4
uhr1a
uhr3er
uh1ri
@@ -13059,17 +13243,16 @@ uhr3tr
uh2ru
uh1w
4ui
-ui2c
+ui2ch
u1ie
ui1em
-u1ig
-u2ige
+u3ig
+u4ige
u3in.
-ui5ne
u3isch.
u3ischs
uisi4n
-ui4st
+ui4s3t
u1j
ukä2
u3käu
@@ -13080,7 +13263,6 @@ u3kla
ukle1i
u3klo
u3klö
-u3ko
u5kö
u1k4r
uk2ta
@@ -13092,6 +13274,7 @@ u1l
ul1ab
ul1am
ul2ar
+ula2s
ul1äm
ulb4
uld2se
@@ -13100,9 +13283,10 @@ ule4n
ul1erf
ul1erh
ul1erw
-ules3a
+ules1a
ule2t
ul3eta
+ul3fe
ulg4
uli2k
uli5ne
@@ -13110,17 +13294,17 @@ ul1ins
ul3ka
ul2kn
ull2a
-ul3len
ul2les
-ul2lö
+ull1s
ulm3ein
ulo2i
ul1or
ulö3s
ul2p1h
-ul2s1a
+ul2sa
+ul2sei
ul3sp
-uls2t
+ulsu3
uls3z
ul4tar
ul2tau
@@ -13129,9 +13313,10 @@ ul2tri
u2lü
ulz2
ul3zw
-u2m1a2k
+u2m3a2k
um1all
um2an
+uman4s
um1anz
um1ar
um1aus
@@ -13158,9 +13343,10 @@ um2pl
ump3le
1umr
1umsat
-um2ser
+um4ser
um2sim
um2s1pe
+um1st
um2su
umt2
um3th
@@ -13209,14 +13395,14 @@ un1gl
un2g1r
ung3ra
ung3ri
-ung6s1
+ung4s3
u3ni
un1ide
1u4nif
un1in
un1ir
2unis
-un3isl
+un5isl
1u4niv
un2k1a
un2kn
@@ -13229,6 +13415,7 @@ unk4t3r
un2n3a2d
un5n4e
un3no
+unn3s
un1o
uno4r
un2os
@@ -13236,10 +13423,11 @@ un2os
uns2
2uns.
unsch5el
-un3se
+un5se
1unsi
un3sk
un3sp
+un2stu
1unt
un3ta
unte2
@@ -13268,12 +13456,13 @@ up2pr
u1pr
up1ru
up1sl
-upt3a2
+up4t3a2
upt3erg
upt1o
+up4tr
u1pu
u1q
-2ur.
+4ur.
u1ra
u3ra.
u3raba
@@ -13300,8 +13489,9 @@ urb2
ur3ba
ur2ble
urch1
-urch5s
-ur3d2i
+urch3s
+urd2
+ur3di
2ure
ur1eff
ure3g
@@ -13315,6 +13505,8 @@ ur1erw
urg2a
ur2gri
urgros4
+urgs2
+urg3st
u1r2i
uri2c
u2r3im
@@ -13323,42 +13515,49 @@ ur1ini
ur3ins
ur1int
ur3inv
+urk2s
1urlau
+urm2a
+urm3ang
2u1ro
-uro5st
+uro3st
u1rö
2urr
+ur3sac
ur2san
-urs3au
-ur2sei
-ur2ser
-ur4sin
+urs1au
+ur6sei
+ur4ser
+ur6sin
+ur2st
ur5st4r
-ur6sw
-urt4
-ur5te
+ur4sw
+urt2
+ur5t4e
ur3th
u1ru
+urü2
ur2za
ur2zä
ur2zi
ur2zo
ur2z1w
u4saf
+us1an
us4ann
-u2sau
+u2s1au
u6schent
usch5wer
us1ec
u2s1ei
u3seid
-u7sep
+u5sep
use1ra
u2serp
us4et
usi3er.
usi5ers.
-us3li
+u3sik
us3oc
u3soh
u3sol
@@ -13372,70 +13571,55 @@ u3spek
us1pic
u5s2piz
us2por
-us2sac
-us6sat
-us2sei
-us3sel
+us4sei
usse4n
uss5erfa
uss3erk
-us5sers
-us2sez
-us2sir
+uss5ersu
+us4sez
+us2sof
uss3tät
-us2sü
-u4st1a2b
-u5stal
-us2tat
-u5stä
-u5ste
-us2ten
-us2ter
-us2th
-u5stis
-u5stop
-us1tor
-u4strä
-u5s4trop
-u5stu
-u6s1tur
-u5stüc
+ust1a2b
+u3stal
+u3stel
+us1tr
+us4tris
+u3stu
+u4stun
+u4stur
us2ur
u2sü
u1sy
-u4sz
-uß3et
-u2ß1u
+u1ß
+ußen3
2u1t
u3taf
ut1alt
ut1a4m
-u2tanz
u2t1ap
u2t3ar
ut1är
u3tät
-u3te.
-u2t1e4g
+u3te
+u5te.
+u4t1e4g
ute2l
ut2em
ute2n1
-u3ten.
uten3e
-u2tent
-u5ter.
+u4tent
ute5r4er
-u4t3ersa
-u3tet
-u2tev
+u5tern
+ut3ersa
+u5tet
+u4tev
u4t1ex
u2t1hi
u2t1ho
u2t1hu
uti2q
-u3to.
uto4ber
-uto3c
+uto5c
uto3n4
ut1opf
u2tops
@@ -13446,6 +13630,7 @@ ut3rü
ut5sa
ut2s1ä
ut4schl
+ut6schö
ut3sp
ut4spa
ut3te
@@ -13467,46 +13652,50 @@ u1x2
ux3t
u1ya
u1z
-uze4
+uze2
uz3ot
uz1we
uz3z4
1üb
2übd
-übe4
-über1
+übe2
+übe3c
+übe4r1
ü2b5l
-3üb3r
+3üb5r
+üb2st
3übu
2üc
ü1che
üch3l
-üch4s1c
+üch4s3c
üch5t4e
ück1er
-ück3e4ri
+ück5e4ri
+ü4ckers
+ück4spe
ü4d3a4
-üdau5
ü3den.
üden4g
ü3d2ens
üd1o4
-üd1ö4
+üd1ö
ü4d5r
-üd3s
+üd3s2
üdsa1
üd1t4
-ü4f3a
+ü2f3a
ü2f1ei
ü2f1erg
üf2fl
ü2f1i
üf3l
-üf3te
ü1g
+ü3ge
ü2g3l
ü2gn
üg3s
+üg4st
üh1a
ü1he
ü2h1ei
@@ -13514,6 +13703,7 @@ uz3z4
ü2h1erk
ü2h1erz
üh1i
+ühla2
ühl1ac
ühl1ag
üh5l2e
@@ -13526,13 +13716,12 @@ uz3z4
ühr5ei.
üh5ro
ühr5ta
-ühs2
-üh3sp
-üh3stu
-üh3te
+üh1s
+üh3s2p
+üh5te
ü1hu
üh1w
-ü1k2
+ü1k
2ül
ül1a
ül2c
@@ -13543,17 +13732,25 @@ uz3z4
ül4lö
ü1lu
ü4ment
+2ün
ü2n1a
ün2c
ün2da
ün2dr
+ünd1s
ün2f1
ün4f3ei
ün3fl
ün4fli
-ünf5r
+ünf3r
ün2g3l
-üng5s
+ünn4s
+ün2s
+ün3sc
+ün3sp
+ün4st
+ün5sta
+ün5str
ün3th
ün2za
ü1pe
@@ -13565,37 +13762,34 @@ uz3z4
ür4f3r
ür4g5eng
ü1ri
-ü1r2o1
+ü1r2o
üro3b
ü3rofe
-ür4ster
-ür5sti
+üro1r
+üro3st
+ürr2
+ür2s
+ürs3tin
ürt2h
ür3the
ü1ru
-üs2a
ü2schl
üse3h
üse3l
-üs4sa
-üs4s1c
-üs3se
-üs4st
-ü4sta
+üs4s3c
+üs5se
+üs2st
+ü2st
üste3ne
-ü4str
ü1ß
ü1ta
ü2t1al
-ü1te
-ü1ti
üt3r
üt2s1
üt2tr
-ü1tu
ü1v
ü1z
-4v.
+2v.
3va.
2v1ab
va3c
@@ -13603,21 +13797,22 @@ va3ge
val2s
2vang
2v1arb
+va3st
v4at
va2t3a6
+va4tei
va2t3h
va4t1in
vati8ons.
va2t3r
-vat5s4
+vat3s2
vat3t
va2t1u
-vat3z
2v1au
-vä1
2v1b
2v1d
ve2
+3vea
ve3ar
ve3b
ve3c
@@ -13625,7 +13820,8 @@ ve3d
ve3g
ve3h
veit4
-veits1
+veits3
+vek3
ve3la
ve4l1au
ve3le
@@ -13656,12 +13852,11 @@ verg4
ve3ri
ve5ris
ve5rit
-ver5sta
-ve3s
+ver3st
2vesc
-2vese
-ve4s1p
-ves2t
+2ve3se
+ves1p
+ves3ti
ve3ta
vete1
vete3r
@@ -13678,6 +13873,7 @@ vi3an
vi4a3t
vi4c
vi3de
+vid3s2t
vie2h3a
vi2el
vi2er
@@ -13687,7 +13883,6 @@ vi3ka
vi2l1a
vi2leh
vi2l1in
-vil3l
2v1i2m
vi4na
vin2s
@@ -13695,8 +13890,8 @@ vin2s
3vio
vi3sa
vise4
-vi3s2o
-vis2u
+vi5s2o
+vi3s2u
vize5
2v1k
2v1l2
@@ -13704,9 +13899,9 @@ vize5
2v1n
2v1ob
vo2gu
-vol6l5end
-vol6lerw
-vol2li
+voll1a
+voll5end
+von3
2v1op
vo2r1
vor3a
@@ -13715,14 +13910,15 @@ vor3g
vo3ri
vo5rig
vor3o
-vorö4
3voy
+vö2c
2v1p
v3pf
v1ra
3vri
v1ro
-2v1s
+2vs
+vs2e
v3s2z
2v1t
2vumf
@@ -13732,10 +13928,11 @@ v3s2z
4w.
w2a
wab2bl
+wa5che
wa3d
waffe2
1wag
-wa3ge
+wa5ge
wa2g5n
wa2gr
wa3gra
@@ -13746,49 +13943,58 @@ wai2b
1wal
3wald
wal4da
-wal2to
walt4st
+wa5na
+wang6s
+wan4s
wa2p
-wa4r
-wa5ra
-1wa3r2e
+wa2r
+wa3ra
+1war2e
ware1i
-wa5ri
+wa3ri
+war3ste
wart4e
-wa5ru
+wa3ru
1wa2s
wa3sa
+wa3se
wa3sh
wa3si
-was5s4
+wass4
+was7se
1wäh
1wäl
-wäm3
1wäs
-wäs2c
+wäs4c
wä5sche
+wäs5se
w1b
2w1c
w1d
weat3
we3be
4webeb
+we3cke
+we5cke.
+we5cken.
+we5ckes
we3d
we2e2
weed1
we2fl
3weg
-we2g5a
+we2g1a
we2g5l
we4g3r
-wegs2
+wegs4
weg3sp
1weh
we3he
wei4bl
2weie
weis4s3p
-wei5str
+wei3str
wei3ße
wei4tr
weit3s
@@ -13815,43 +14021,39 @@ we4r1io
1werke
wer2kl
wer2ku
-wer4sta
-wer2ta
+wer2s
+wer2t3a
wer4tei
wer6t5erm
wer4to
1werts
-1we5se
-wesen4s3
+1we3se
we3si
we2s1p
-wes2t
-we4st1a
-we4st3ei
-we5sten.
-we5stens
-we6steu
-we6sti
-we4st1o2
-we4stö
-we4st3r
-we4stu
-wet2s
+we4st
+west1a
+west3ei
+wes2t1o2
+west3r
+wes4tu
+wet4s
+wet4ta
wett3s
2w1g
-w3ho
+w5ho
+wi3cka
3wid
wi2e
wie3l
wie5ne
-wie4st
+wie2st
wi3k2
+wim2ma
wim4m3u
-win4d3ec
+win4d3e4c
win2dr
win2e
win8n7ersc
-win4num
wi4r
1wirt
wi5s4e
@@ -13862,7 +14064,6 @@ wi3th
2wk
2w1l
2w1m
-2wn
wn3sh
1wo1c
wo2cha
@@ -13871,7 +14072,6 @@ woche4
woh4l
1wolf
wolf4s
-wol4la
wol4ler
wor3a
wo2r3i
@@ -13885,25 +14085,30 @@ wör3the
1wr
w1ro
2ws
-w3s2k
+w3s4k
+w1s2t
2w1t
-wti2
+w3ti2
w2u
1wuc
-wuls2
+wul2
+wul3se
wun2s
4wur.
wur2fa
+wur4s
1wurst
-wus4
-1wu2t1
+wus2
+wus3te
+1wu4t1
1wüh
-wüs4
+wül2
+wün3
2w1w
6x.
x1a
1xa.
-2xab
+2x3ab
1xad
1xae
xa1fl
@@ -13912,6 +14117,7 @@ xa4m
xa3me
xa5mer
2xan
+x4anz
3xas
2x1b
x1c
@@ -13925,7 +14131,7 @@ x1em
7x2em.
xemp6
3x2en
-xens2
+xens4
xen3sa
x2er.
5xere
@@ -13934,6 +14140,7 @@ xers2
2x3eu
2x1f
2x1g
+xge1
2x3h
1xi
xib4
@@ -13947,18 +14154,18 @@ xie3l
xi3g4
xi2lo
xi2l1u
-xins2
xin3sk
-x2is
-xi2s1e
-xi2s1o2
-xis5s
-xi5stä
-xi2su
+x2i2s1
+xi3sc
+xi4se
+xiso2
+xis3s
+xis2tä
x1i2tu
x1j
x1k4
2x3l
+xlib6
x1m
2x1n
x1or
@@ -13969,13 +14176,13 @@ x1r
4x1t
x2t1a
xt3an
-x3t4as
+xt4as
x2t1ä
x3tät
+xtblo4
x2t1e2d
x2t1ei
-x3teil
-x2tent
+x4tent
x2t1erf
xtra1b6
x2t3ran
@@ -13985,7 +14192,7 @@ x3tur
1xu
xu1a
x1u4n
-xu2s
+xu2s1
x1v
2x1w
1xy.
@@ -13998,6 +14205,7 @@ y1a2m
yan2g
y3ät
y1b
+yb6r
y1c
y2chi
y3chis
@@ -14007,9 +14215,9 @@ y3d4r
y1e
y2ef
yen4n
-y2es2
+y2es
ye3sp
-y3e4st
+y3est
ye2th
y1f
y1g
@@ -14023,15 +14231,17 @@ yk5s
y1l
yl3a2m
y3lant.
-y3l4ante
+y3lante
yl3c
y5len
y5ler
yli4n
yloni1
+yls2
+yl1st
y2l1u
-yma2t
-ym3p2
+yma4t
+ym3p4
ympi3e
y2ne
y2n3o
@@ -14043,7 +14253,7 @@ y1ont
y3ou
y1p
ypa2
-yp5an
+yp3an
ype2
yper3t
y3ph
@@ -14055,19 +14265,16 @@ y1r
y3r2e
y3ri
yri1e
-y3ro
-y1s2
-y5sc
-y3sh
-ys3k
-y3sp
-ys3s
-yst4
-y3sty
-y3sz
+y5s4c
+y1sé
+ys2h
+y3s2p
+y2st4
+ys1tr
+y3s2ty
+y3s2z
y1t
y2t2h
-yto5s
yu2r
yure3
y1v
@@ -14076,47 +14283,46 @@ y1y
y1z2
6z.
2z3a2b
-za1cha
-za1chä
+za1c
z3a2d
za3de
2z1af
za3gr
3z2ah
2z3a2k
-za3li
2z1all
2z1am
z3ambik
3zambiq
z1an
+za2na
2z3anf
3zani
+z3anl
3zar.
2z1arb
3za3re
z1arm
-3za3ro
-za5st4
+3zaro
+za3st4
2z3at
3zaub
z1au2f
z3aug
3zaun
-za3v
zä2
2z1äc
3z2äh
2z1äm
-zäng5
z1ärg
z1ärm
-4z3b4
+4z3b6
zbü1b
zbübe5
4z3c
2z3d
zdä1
+zdi1st
1ze
ze3a
2zeck
@@ -14125,8 +14331,8 @@ ze1e
zei3la
zeile4
2z1ein
-zei5s2
-zei3sk
+zei3s2
+zei5sp
zeist4
zeit1a
zei4tak
@@ -14138,19 +14344,15 @@ ze4l1a2
zel3ad
zel1er
zel1in
-zel5l4a
-zel5lä
-zel4leh
-zel4lin
-zel3spr
+zel5la
zel3sz
zel3th
zelu2
ze5m4e
2z1emp
5zen.
-ze6n1ac
-zen3s2e
+ze4n1ac
+zen5s2e
zen2ta
5zentr
zent3sk
@@ -14184,13 +14386,12 @@ zer6t5rau
3zerza
z1erzi
ze2sä
-ze5sc
ze2s1i
ze3sku
-ze2s3p
-zes4ser
-zes1tr
-ze2ß1
+ze2sp
+zes6s5end
+ze2st
+zes3tr
ze2tr
2z1ex
2z3f
@@ -14198,19 +14399,18 @@ ze2tr
zger2a
2z1h
z2hen
-3zi.
+zhir5
+zi3alo
zid5r
zi1erh
zi1es.
-3z2ig
+zig4s
zil2e
-zil3l
-z2imm
2zimp
3zine
zin4er
2z1inf
-z1inh
+2z1inh
zin4ser
4zinsuf
2z1inv
@@ -14219,7 +14419,7 @@ zi3op
zirk4
zirk6s
zi3s2z
-zit2h
+zi1t2h
2z1j
2z3k4
zkü1b
@@ -14227,6 +14427,7 @@ zkü1b
z3la
2z1m
2z3n2
+znei3
2zob
2zof
z1oh
@@ -14250,19 +14451,21 @@ zö7li
z2t1au
z3te
z4tehe
+zte3ma
zte3o
-zte5str
+zte3str
z2t1h
z4t3hei
z3t2her
zt3ho
+z3ti
zt1ins
zt3rec
-zt3s2
+zt3s
zu1
zu3a
zub4
-zu2c
+zu5cke
zud4
zu3f4
zu2g1ar
@@ -14285,7 +14488,7 @@ zu3r2a
2z1url
2zurs
2z1urt
-zu3s2
+zu3s4
zu3t
zuz2
2züb
@@ -14309,8 +14512,9 @@ z2wit
z1wur
2z1wü
zy1ank
-6z1z
+4z1z
z3z4a
z3zi
+zzi3s2
z3zo
-zzoll2} \ No newline at end of file
+zzoll2}
diff --git a/tex/context/patterns/lang-de.rme b/tex/context/patterns/lang-de.rme
index 3997cda14..8bfa03fdb 100644
--- a/tex/context/patterns/lang-de.rme
+++ b/tex/context/patterns/lang-de.rme
@@ -1,13 +1,13 @@
% generated by mtxrun --script pattern --convert
-% dehypht-x-2008-06-18.pat
+% dehyphn-x-2008-06-18.pat
-\message{German Hyphenation Patterns (Traditional Orthography) `dehypht-x' 2008-06-18 (WL)}
+\message{German Hyphenation Patterns (Reformed Orthography, 2006) `dehyphn-x' 2008-06-18 (WL)}
-% TeX-Trennmuster für die traditionelle deutsche Rechtschreibung
+% TeX-Trennmuster für die reformierte (2006) deutsche Rechtschreibung
%
%
-% Copyright (C) 2008 Werner Lemberg <wl@gnu.org>
+% Copyright (C) 2007, 2008 Werner Lemberg <wl@gnu.org>
%
% This program can be redistributed and/or modified under the terms
% of the LaTeX Project Public License Distributed from CTAN
diff --git a/tex/context/patterns/lang-deo.hyp b/tex/context/patterns/lang-deo.hyp
index deff1a4bc..0ca53c25f 100644
--- a/tex/context/patterns/lang-deo.hyp
+++ b/tex/context/patterns/lang-deo.hyp
@@ -2,7 +2,7 @@
% for comment and copyright, see ./lang-deo.rme
-% used:
+% used:
\hyphenation{
-} \ No newline at end of file
+}
diff --git a/tex/context/patterns/lang-deo.pat b/tex/context/patterns/lang-deo.pat
index d97382d21..a82b144ce 100644
--- a/tex/context/patterns/lang-deo.pat
+++ b/tex/context/patterns/lang-deo.pat
@@ -7,53 +7,50 @@
\patterns{
.a6
.ab3b
-.aben2
.ab5l
.abo4
.ab3ol
.ab1or
-.ab5r
.ab3s
.ag4r
.ag2u
-.aid2
+.aid4
.ai2s
.al3br
.al2e
.al3l4en
.al3ph
-.al4tei
.alt3s
.amt4
-.amt6s3
+.amts3
.an3alg
.an3d
.ang4
.an1gl
-.angs4
+.ang6s2
.angst3
.an3k
.an3s
.an4si.
.ans2p
.an3z
+.ao5
.ap3s2
.ar3k2a
.ar4m3ac
-.ar4s
+.ar2s
.ar4t3ei
-.as1t
-.as4ta
+.ata1
.au3d
.au2f5
.au4s1
.ausch3
-.aus5s
-.ä4
-.äm5
+.au6stes
+.ax2
+.ä6
+.äm3
.ät2s
.b6
-.bau1s
.be3erb
.bei6ge.
.be3ra
@@ -65,21 +62,18 @@
.bo4s3k
.c4
.ch2
-.con3
.d4
.dab6
.da2r1
.dar3in
-.dar2m
+.dar2m1
.da4te.
.da4tes
.de4al
.de1i
.de3o2
.de3r4en
-.de1s
.de3sk
-.de3s2t
.deut2
.dien4
.do3b
@@ -96,114 +90,121 @@
.ei5ner
.ei5nes
.ei4sp
-.ei4st
+.ei4s1t
.ei2tr
.el2bi
-.elb3s
-.els7t
.em3m2
.en1
.en4d3er
.en4d3r
-.enn2
+.enn4
.en4t3
+.epi1
.er4dei
.er4der
.er1e
.er1i
+.ers2
.er8stein
-.es3k
.es3p
-.es1ta
-.es5t4e
-.es1th
-.es3tr
-.et4s
+.es2t
+.est4e
+.et2s
.eu3
.eug4
.ext4
.f6
-.fi3est
+.fa2c
+.fe6sta
.fi4le.
.fi4len
-.fin6s
.fi2s
.frau3
-.fs4
+.fs2
+.fus2
.fu2sc
-.g4
-.ga4t
+.g6
+.gang5
+.ga2t
.gd2
.gel2d
.ge5nar
.ge3ne
.ge3r2a
.ge3r2e
-.ge3s4a
+.ge5s4
+.ge7sta
.ge1u
-.gros4
+.grif8fes
+.gros2
.gs2
-.gus4s3
+.gus2
+.guss3
.gu4ter
.h4
.ha3bi
.haft5s
-.hal5te
+.hal4s
+.hal3te
.haup4
-.hau4t1
+.hau2t1
.he2
-.he3cke
.he3ri
.he6r5inn
.he5xe
-.his1
.ho4met
.i6
.ia4
+.il3
+.illu5
.im2a
.in3
.ink4
.inu3
-.is2a
-.is3tr
+.is4a
.jor5
-.k6
+.k4
.ka2b5l
.ka2i
.kamp2
-.ka6t3io
+.ka4t3io
+.ken6num
+.ker5s
.ki4e
.klan4
.ks2
.kü1b
.l4
.la3b
+.lat5s
.le4a
+.lea7se
.le5ni
-.lib6
.lo4g3in
.lo3ver
+.lu4str
.m4
.ma3d
.ma3ge
.ma3le
-.ma4st
+.ma4str
.me3l4a
.me3ne
.men8schw
.ment2
-.mi2s
+.mi2sc
.mi4t
.n4
-.näs3c
-.ne6s
+.näs1c
.nich2
.ni4e
+.ni3ka
.nob4
+.no2c
.no2th
-.nus4
+.nul2
+.nus6
.o6
-.oa3
.ob1a
.obe2
.oben3
@@ -211,12 +212,10 @@
.ob3l
.oper4
.or2a
-.ort2
-.ort6s
+.ort4
.orts3e
.oste2
-.os4tel
-.os8t7ende
+.ost7ende
.oste6r5e
.ost3r
.ozo4
@@ -229,35 +228,35 @@
.pf6
.ph4
.poka2
-.po4st
+.po4str
.ps2
-.r6
-.reb3s2
+.pu3s
+.r4
+.reb5s2
.re3cha
.rein4t
.reli1
.reli3e
-.res4tr
.rich5t6e
.ro3be
.ro2h
-.ro3m2a
-.rö4s
-.rös3c
+.ro3m
+.rom4a
+.rö4s1c
.rut2
.ru3th
.rü1b
-.rü6cker
.s6
-.sali3e
+.sa2c
+.sali1
.sch4
-.sen5s
+.sen3s
.ser2u
.se2t
.sha2
.si2e
.sim3p4
-.si4te
+.si2te
.ski1e
.spra2
.st6
@@ -270,18 +269,15 @@
.te2e
.tehe3
.te3no
-.te4st
+.te6ster
.th4
.ti4a
.ti2s
-.ti3ta
.to2n
.to4ni
-.ton3s
.to4pl
-.to4st
.to2w
-.tri3es
+.tri3e4s
.ts2
.tu3ra
.tu3ri
@@ -296,11 +292,9 @@
.unen2
.un3g
.uni4t
-.un3s
-.un5s4t
.ur1
.urin4
-.ur5o2m
+.ur3o2m
.uro2p
.ur3s2
.ut2a
@@ -309,19 +303,16 @@
.v2
.ve5n2e
.ve4r
-.vol2
.vo4r
.w2
.wah2
.wah4l
-.wa3re
+.wa5re
.we2
-.weg3
.welt3
.wi4e
.wor2
.wor6t5en
-.wor4tu
.wun4sc
.x4
.xe3
@@ -329,13 +320,11 @@
.ya4l
.z2
.zah2n
-.za4s
.zi2e
-.zin6s5t
+.zin4st
.zuch2
-.zwe4
6a.
-4aa
+2aa
a1ab
aa2be
aa1c
@@ -359,22 +348,20 @@ ab1ar
ab1auf
ab1ä
ab2äu
-1abd
+3abd
a1be
ab1eb
abe1e
-abei3
ab1eil
4a3bel
abe2la
-abe4na
2aber
-a3beri
ab1erk
ab1err
ab1erz
ab3esse
-4abet
+ab1eß
+2abet
2abew
1abf
3abfi
@@ -401,42 +388,44 @@ a2bo.
ab4of
3a2bon
ab3r
-ab5rec
+ab5re
1abs
2abs.
abs2a
2absar
-ab3s2i
-ab3sp
-abst6
+ab5s2i
+ab5sp
+abs4t6
2abst.
-ab5sta
-ab5ste
+ab7sta
+ab7ste
ab3sz
1abtei
2a1bu
ab3ur
2abü
-ab3üb
-1abw
+ab5üb
+3abw
2aby
1abz
2ac.
a2ce.
a1cem
+a3cet
ach1a
ach3ak
-a1chal
+a3chal
ach3au
a1che
a2ch1e2c
ach1ei
+a3chen
+a3cher.
a4cherf
ach3erw
a3ches
4achf
a1chi
-a3chis
ach5l
ach5m
ach3n
@@ -448,6 +437,7 @@ ach1ö
ach3r
ach3spr
ach3su
+a4cht
ach6t5erg
ach4th
ach2t1o
@@ -457,14 +447,14 @@ ach3ü
4achv
2ach3w
ac1in
-2ack.
-a1ckar
+4ack.
ack2en
-a3cki
-a4ckin
+ackmu6
+ackmus3
ack2se
ack3sl
-ack5sta4
+ack7sta4
+a3co
acon4n
2acu
a1ç
@@ -475,34 +465,32 @@ a4d1ac
ad1ama
a2d1an
3a4d5ap
-a3dar3
+a3dar
3a2dä
ade4al
adefi4
ad1ein
ade1ra
-4ades
-ade3s2p
+4ades4
+ade3sp
ades6s
4adi
adi3en
ad2ob
-ado3c
a2dr
ad5rah
4ad3rec
ad4res
ad5ru
-ad1s2
+ads2
ad3sä
ad3sp
-ad3st
ad3sz
-ad4t1
+ad2t1
adt3a
2ae
a1e2b
-a1e2c
+a1ec
a1e2d
a1ei
a1el.
@@ -514,8 +502,7 @@ ae2o3
a1e2p
ae1r
3a2er2o
-a1e2s1
-aes3t
+a3estri
a1e2x
a2f1a
a3fah
@@ -528,7 +515,7 @@ a2f1ec
a2fent
af1erl
af4f5l
-2a3fi
+2afi
2af3l
af3ra
af3rä
@@ -537,19 +524,15 @@ af3rö
af3ru
af3s2a
af2sp
-afs4t
-af3ste
-2aft
+afs2t
af2t1a
-af3tab
-af2tei
af4t3erl
af2t3r
-af4t5re
+aft5re
af2tur
a2f1ur
a1g
-2aga
+4aga
ag1a2b
ag3a2d
ag1ar
@@ -563,9 +546,8 @@ age2nu
age2se
age4si
age4s3p
-ages3s
+ages5s
a4g5esse
-age4s3ti
ag3gl
2agi
3a2git
@@ -587,17 +569,14 @@ a2g3re
a2g3ri
ag4ro
a3gru
-2ags
+ag4s
agsa2
-ag4sam
-ag4set
-ag6s5p
+ag7sat
+ag5säu
+ag6s3p
ag7spi
-ag3sta
-ag3ste
-ags4tei
-2agt
-2agu
+ag5sta
+ag5ste
a2g1und
2ah.
2a1ha
@@ -620,9 +599,8 @@ a2h1ö
ahr1a
ah3re
ah4rei
-ahre6s3
ah1ri
-2ahs
+2ah2s
aht3sp
a1hu
ah1w
@@ -630,12 +608,12 @@ a1hy
2ai
ai1a
aib3l
+aids1t
ai1er
aif2
ai3g4
-a3ik.
+a1ik.
ai3ku
-a2il
ai2lo
a1ind
ai3n4e
@@ -645,20 +623,21 @@ ai2nu
ai3o
ai2sa
a3isch.
-ai5s2e
-ais3s
+ai3s2e
+ai5se.
+ais4se
+ais5st
a2it
a3iv.
a3ivl
a3ivs
a1j
-aje4
2ak.
a2kad
-2akam
+2a3kam
2akar
ak4at
-aka2ta
+aka4ta
2akb
2akc
2akd
@@ -666,7 +645,7 @@ aka2ta
a2kef
a2kes
a2keu
-2a1ki
+4a1ki
2ak3l
ak4la
ak4li
@@ -678,15 +657,16 @@ ak3res
2aks
ak3sh
2akta
-ak3t2an
+akt2an
2aktb
-ak5ten
+ak3te
+ak4tei
2aktik
akt2o
ak4t5r
ak5t6ri
2aktst
-2a1ku
+a1ku
a2kun
4a3kü
1akz
@@ -726,12 +706,9 @@ al2b3l
al2boh
al2br
alb3ru
-alb3s
al2da
al2dä
al3dri
-alds2
-ald3st
al3du
2ale
3a2l1e2b
@@ -740,6 +717,7 @@ a4l1eh
a2l1ei
a4lein
a2l1el
+ale2n
al3ends
a2leng
al2ent
@@ -757,8 +735,8 @@ al3eta
al3eth
a4l1eu
3alex
-al1exi
al2gli
+1algo
2ali
ali4e3ne
ali4nal
@@ -767,18 +745,19 @@ a2l1ins
a2linv
al2k1ar
1alkoh
-alk3s4
+alk5s2
al2lan
al2l3a6r
-al2lau
+al4län
al4lec
al3lend
all5erfa
al3les
alli5er.
alli7ers.
-2alo
+2allo
a2l1ob
+2alog
alo2ga
al1ope
al1orc
@@ -789,11 +768,10 @@ al2ös
al3skl
al3sp
al4spal
-al5s6terb
al2ta
-al3tam
alt3eig
-al4te4l
+al2te4l
+al3ter
al4t3erf
al2tö
al2tri
@@ -822,28 +800,28 @@ a3mie
a3mil
2a3mir
amit2a
-ami5ti
+ami3te
+am2mac
2ammal
am2min
-ammu2
+am4mod
+am2mus
2amo
a2mö
-2amp
amp2f3a2
am3pr
-am2s
+2ams
am3sa
+am4sc
am3so
-am3sp
-am3str
-3amt.
+1amt.
am2t1a
am2t1ä
-am4tel
+am2tel
am4t3ern
am2to
am2tö
-am4t3r
+am2t3r
am2tu
4amu
am3unt
@@ -855,21 +833,21 @@ anadi3
a3nak
2anan
an3ara
-2anas2
+2anas
2anat
an1äs
1anb
-3anbr
-an5cht
+an3cht
4and.
an5de6s
-an2d1ex
+an2dex
2ando
an4d5rü
and4sas
+and6s5paß
an2d1ur
4ane
-an3e4c
+an3ec
a3nee
an3eif
an1e2k
@@ -891,10 +869,9 @@ an2glä
ang5le.
2ango
ang3ra
+1angri
4angs.
-ang5sc
-ang6s5po
-1anh
+ang6s3po
4a3ni
ani3els
ani5ers.
@@ -910,7 +887,7 @@ ank3ra
ank3rä
ank5ti
an2ky
-1anl
+3anl
2anmu
2ann
3an3na
@@ -919,19 +896,18 @@ an5n4e
an3od
an1or
a1nö
-1anr
+3anr
+anrö5
2ans.
3ansä
1ansc
-an5se
-ans2en
-an6seu
+an3s2en
+an2seu
+2ansk
an3skr
an2s1pa
1anspr
-an3s2t
-an5stei
-an5str
+an5s2te
an3s2z
2ant.
ant2a
@@ -943,7 +919,7 @@ an3th
ant2he
1anthr
2anto
-1antr
+3antr
an2tro
3antw
4a3nu
@@ -956,15 +932,16 @@ a1nü
3anzah
3anzei
anz5erst
+4anzg
an2z1i4n
3anzu
3anzü
an2zw
-ao1i
+ao1i4
a1op
a1or
-a1o4s5
-aot2
+a1o2s
+aot4
a3ot.
ao3ts
a1ö
@@ -972,14 +949,13 @@ a1p
2ap.
4apa
2ape
-a2pé
+3a2pé
ap2fa
a3pfl
a3phä
ap1hel
2a2p3l
ap2n
-apo1s
a2pot
ap3pl
2apr
@@ -987,7 +963,7 @@ ap3pl
2ar.
2a1ra
a3ra.
-ar2ab4
+ar2a1b4
ar3abt
ara3d2
a2r3al
@@ -995,7 +971,6 @@ ar1ang
ar1ans
ar3anz
a2r3app
-ara4st
a2r1au
a1rä
2arb.
@@ -1010,6 +985,7 @@ ar2b5l
2arbr
ar2bre
2arbs2
+arb5se
arb3sp
2arbt
2arbu
@@ -1023,7 +999,7 @@ a2rea
are5b
a2ref
ar1eff
-a4re3g
+are3g
ar1ehr
a2rein
a5ren
@@ -1053,7 +1029,7 @@ ar1ins
ar1int
a3riu
2ark
-ark5amt
+ark3amt
ar2k1ar
ark3aue
ar2kl
@@ -1061,17 +1037,16 @@ ark3lag
ar2kor
ark1r
ar4kri
-arks2
+arks4
ark3sa
ark3sh
ar4les
2arma
arm2ä
-arm3erk
arm2or
2arn
ar5n2e
-2a1ro
+4a1ro
ar1ob
ar3o2d
a3rodo
@@ -1086,15 +1061,12 @@ ar2r3ad
arre4n
ar2rh
arr3he
-2ar2s
-ar3sa
+2ars
ar4schl
ar4schr
-ar5se
+ar3se
ar3s2h
ars3k
-ar3sta
-ar3su
ar2tau
1artd
ar4t3erl
@@ -1102,7 +1074,8 @@ art2ho
artin2
2arto
ar2t3r
-2arts
+ar3tres
+4arts
2a1ru
ar1ums
ar3ü
@@ -1114,25 +1087,33 @@ ar2zä
1arzt
ar2z1w
2as
-as2al
-as3ala
+as2a
+as3ab
+as1ala
a4s3au
+asaus1
a2s1ä
-a6sca
+a2sca
a4schec
asch3la
a2schm
-4as2e
-a2seb
+4a3se
+a4seb
ase3le
aseli5
-a2s3e2m
-a3ses
+a4s1e2m
+a5s2en
+as2er
+a5s2es
+a4sex
4ash
a3s2hi
a5si.
-4asis
+4a5sis
+asi4st
a3skop
+as3m
+aso1
as1o2f
a3sol
a3som
@@ -1144,52 +1125,54 @@ as3pe
as2ph
as2po
as2pu
-as3s2a
-as5se
-as6sei
+as3s4a
+as4sä
+as3se
+as4sei
asse3le
as3s2i
-as5so
+as3so
as2s1p
-as2st
-ass3ti
-as4sto
-as3str
-a2st
-4a4s1ta
-a5s4tas
-as2tau
-a5stä
-as3te
-as3ti
-4a3str
+as4st
+as6s1to
+as5str
+4asta
+as2te
+as3tec
+a4s3tep
+as4ti
+as2to
+4as2tr
ast3rau
-ast3rä
-as4t3re
+a4st3rä
+a4st3re
+a4strol
+a2stum
+a3su
a2sü
3asy
-a1ß
aße2
2a1t
-4ata1
+4ata
a2t1ab
ata2be
-at2af
+at2a1f
at4a5g
at1akt
+ata1la
a3tam
at1apf
+a5tas
a2t1au2
-a3tau.
+a5tau.
at1än
at2c
-4a3te
-a4teb
+4ate
+a2teb
at1eig
a4teli
-a4tep
-ater3st
-a4tew
+a2tep
+a2tew
4atf
4atg
at2he
@@ -1199,6 +1182,7 @@ a4thr
at1int
3atm
4atmus
+a3to.
ato4man
a2t1ort
a2t1ö
@@ -1210,25 +1194,29 @@ at3re
at3rom
at2s
at3sc
+at5sche
+at5schü
+ats1e
at4set
+ats1in
ats1p
+at4st
+at5stä
3attac
att3ang
at2t1au
at2tei
at5thä
-att3rau
-at4t3rä
atts4
+at3tu
4atu
a3tub
atu4n
atu3ren
atu4rer
at3w
-4atz
atz1er
-at2z1in
+at2z1i
atzt2
atz3th
a2u
@@ -1247,7 +1235,7 @@ aue2b
aue3re
au5erein
au5erl
-aue4s
+aue2s
au3et
au2fa
auf1an
@@ -1260,13 +1248,13 @@ au2fo
2aug
au3g6e
4augeh
+2auh
2au1i
au2is
4auj
au2kl
aule2s
aul3ese
-aul4s
au3lü
4aum
au2mal
@@ -1275,8 +1263,7 @@ au2mau
au2mer
au2m1o
aum3p2
-aums2
-aum3st
+aum5str
aum3sz
4au3n2
au4nio
@@ -1288,18 +1275,21 @@ aup2
2au3r2
au2s1ah
ausan8ne.
-4au2sc
+2au2sc
au3schl
au3schw
-2ause
aus3erp
au4s3erw
au2so
au2sp
-aus3s4
+auss4
+aus7sa
3aussag
aus4se.
-au2st
+aus3so
+au4st
+au6stec
+aus3tie
aus3tri
2aut.
au3tan
@@ -1307,8 +1297,9 @@ au2tä
aut1äu
2aute
au4t3erh
+au3tes
3auto
-2auts4
+2auts
aut5st
2aux
auz2w
@@ -1317,17 +1308,16 @@ auz2w
av4a
ava3t
a2vr
+av2s
2a1w
awi3e
a1x
-ax2a
-ax3an
+ax2am
ax2e
+axi4s
2a1ya
a1yeu
-ays2
aysi1e
-ay3ste
2a1z
az4a
azo3
@@ -1342,27 +1332,27 @@ az2u
äch3l
ä2chr
äch2sp
-äch4st
ä1chu
-ä1ck
ä1d
-ä3di
-ä4d1ia
-ä3do
+ä2da
+ä2d1ia
ä2d3r
-2ä3e
+äd2s
+2ä1e
äf2fl
äf5l
äf3r
äf2s
-äft4s3
+äft4s
ä1g
äge1i
-äges4
ä2g3l
ä3g2n
ä2g3r
-äg3s2tr
+äg4s2
+äg5sa
+äg5ste
+äg5str
1ä2gy
äh1a
2ä3he
@@ -1374,10 +1364,10 @@ az2u
2ähm
äh5ne
äh5ri
-2ähs
+2äh2s
2äht4
äh3tr
-ä3hu
+ä1hu
äh1w
ä1im
ä1is.
@@ -1393,35 +1383,37 @@ az2u
äle3ru
äl2l1a
äl2p3
-äl2sc
+äl2s
+äl3se
ä1lu
ä3me
ämi3en
2äml
+äm4ma
+äm2s
ämt2e
2än.
än2dr
-2ä3ne
+2äne
äne2n1
än2f3
2änge
än2gl
än2gr
-äng3se
+äng5se
+äng5ste
2ä3ni
än5k2e
än2k3l
än2kr
-änk2s
än5n4e2
2äns
-än4s3c
+än4s1c
änse3h
ä1on
ä1pa
äp2pr
-äp4s3c
-äp2st
+äp4s1c
1äq
ä2r3a2
är4af
@@ -1435,57 +1427,61 @@ az2u
ä1ri
är1int
är2k5l
-ärk2s
+ärme5s
är1o2
ä1rö
ärse2
-är6si
-är2st
+är2seb
+är4si
ärt4e
-ärt2s3
+ärt4s3
ä1ru
är3ü
är2z1w
äs2a
-äs4e
+ä3s4e
äse3g
äse3re
äser4ei
äse4ren
äse3r2i
äse3t
+ä3si
äskop2
ä3s2kr
ä2s1p
-äs4s3c
+äs4s1c
+äs3se
äs4s3erk
-äs4st
-ä4s3t
-äs5ti
-äs4tr
+äs6st
+äs2te
+ä4str
ä3su
ä1ß
äß1erk
2ät
-ä4t3a2
+ä2t3a2
ä3te
äte1i
äte2n
+ä2th
ät2ha
+ä1ti
ä1to
ät1ob
ät3r
ät2sä
ät4schl
ät4schr
+äts1ei
ät2s1i
äts3l
ät3so
äts1p
-ät2st
-äts3ti
+ät4st
+äts3te
ät2tr
-ä3tu
+ä1tu
ät5ze
äu2br
äu1c
@@ -1496,27 +1492,26 @@ az2u
2äul
2äum
äu2ma
-äum2s
+äum4s
äums1p
ä2u3n2
2äu5r
2ä3us.
äu2sc
-äu6schä
äu4schm
-äu5se
+äu3se
ä1usg
ä1usk
ä1usn
äu2sp
-äus4s3c
+äus4s1c
1äuß
äu2tr
4ä1v
1äx
ä1z
â1t
-6b.
+4b.
1ba
2babs
ba3char
@@ -1527,7 +1522,8 @@ backs4
3bah
bah2nu
bah5re
-bais4
+bai1
+bais2
ba2ka
ba2k3er
ba2k1i
@@ -1535,8 +1531,9 @@ bak5l
ba2kra
3bal
ba1la
-bal4l3eh
+bal4leh
bal6lerg
+bal6lig
bal3th
2b1am
ban2a
@@ -1555,19 +1552,22 @@ bar3b
b2ard
bar3de
ba2rei
-bar2en
+ba3r2en
bar3zw
3bas
-ba5sa
+ba7sa
ba2sc
-ba4st
+ba6str
ba2to
+ba3tor
bau3b
bau3g
-bau3s
-bau1s2k
+bau3s2k
+bau3sp
+bau5str
ba1yo
-3b2ä1c
+3b2äc
+bä1ch
1bäe
1b2är
1b2äs
@@ -1575,10 +1575,10 @@ ba1yo
b1äug
bäu3s
4b1b
-b3ba
-bben3s2
+b5ba
+bbau3sc
bbe4p
-b3bi
+b5bi
bb5ler
b2bli
bb3lin
@@ -1587,18 +1587,16 @@ b3blö
bbru2
bb2s
bbu1
-b7by
-2b3c
+2b5c
2b5d
-bde1st
-bdo3
bdu3s
1be.
3be3a
be5an
be4au.
b2ebe
-1be1c
+1bec
+be1ch
be2del
bedi4
be1eh
@@ -1617,16 +1615,18 @@ be1ind
be1in4h
bei3sc
beis2e
-bei3st
+bei5st
beit2s
3bek
be3las
+be5le
be3lec
be3lei
-be2l1en
-be2let
+be6l1en
+be6let
be3li
-bel3la
+bel5la
+bel5li
bel3sp
bel3sz
belt4
@@ -1634,18 +1634,17 @@ bel3ta
bel3tr
1bem
1ben.
-be3na
-be4nal
+be4na
ben3ar
-be4nau
be3ne
ben4erg
+be4nerl
be4ners
ben3g
be3ni
-ben4se
+ben2se
ben2sp
-ben4su
+ben2su
ben4th
3b2enti
b1ents
@@ -1667,21 +1666,21 @@ ber3iss
ber3na
b1ernt
be1rop
-ber3st4a
+ber5st4a
ber3th
be3rum
-1be1s
-be3sa
-be2s1er
-be3slo
-be3spo
-be3spr
+1be3s
+be4s1er
+be4sk
+be5slo
bes5s4e
b3esst.
bes3sz
-bes2to2
+bes2t
be4s3tol
-be3s4ze
+be4stor
+be4sum
+be1s2ze
3bet
be2tap
be3tha
@@ -1691,19 +1690,20 @@ be1ur
1bez
2b5f4
bfal2
-4b3g4
-b5ga
+bfrä5
+4b5g4
+bga4s1
+bgas3t
bge3
bge5n
-bges4
-2b3h
+bge5s
+2b5h
1bi
bi1ak
bibe4
bi2e
bi3ens
bi3ent
-bie2s
bi3k2a
bi2ke.
bi2kes
@@ -1719,44 +1719,47 @@ bi3n2e
bi2o3
bi3on
biri1
-bi5se
+bi3se
bi2sol
-bis4s3c
-bi4st
+bis4s1c
+bi2s1t
+bi4stü
bi2t
b2i3ta
bi3te
+bi3ti
bi3to
bi3tr
-bit3st
-2bi4tu
-bi5tum
-b2i5tus
+bit5st
+2bitu
+bi3tum
+b2i3tus
biz2
bi3za
4b3j
bjek4to
-2b3k4
+2b5k2
b2l2
2bl.
+b4la.
bla3b6
4b5lad
b6lanc
6blasser
b6latt
b3law
-3b4le2a
+1ble.
+3ble2a
b3leb
2b5leg
b3leh
2b3leid
b5lein
-blei3sc
ble3l
-b4lem
+1b4lem
b4ler
b5lese
-ble5sz
+ble3sz
3b4let
2b3lich
3blick
@@ -1768,17 +1771,15 @@ b4lit
b6loc
b5lok
2b3lun
-blu4ter
3blü
-2b3m
-6b3n2
-bni2
-bnis3
+2b5m
+4b5n2
+bni4
+bnis1
1bo
bo5as
bo2b3l
bo3b4r
-bo2c
bo3ch2
bo3d2
bo2e3i
@@ -1796,7 +1797,6 @@ bo4rä
bor2d1i
bor2d3r
bo2rei
-bor2s
b1ort
bor4tei
bor2t3r
@@ -1806,20 +1806,20 @@ bo4s3p
3bot
bote5n4e
bo3th
-bot2st
+bot4st
bö2b3
2b3öf
bö3sc
-2b3p2
+2b5p2
bpa4g
-2b3q
+2b5q
b2r4
2br.
b4ra.
2b3rad
-b6rah
-b6ra3k
-bra1st4
+b4rah
+b4ra3k
+bra5st4
2bre.
6b5rechte
2b3ref
@@ -1828,45 +1828,39 @@ b3reif
b3rek
3brem
2b3rep
-b4rer
-b4ri
-2b5riem
+b6rer
+2b3riem
bri2er
-2b5rig
-b5ris
+2brig
+b4rio
+bro1
b5roh
2b3rol
b4ruc
+bru6s
brust1
4b1s
bs3ad
-bs1an
b3sand
bs3ar
-bsat2
+b5sat2
b3sä
-b4sär
-b3sc
-b4schan
+b5sc
+b6schan
b7schl
-bs4cu
b3se
b5se.
bs1e2b
+bs1ein
b5sel.
bs1ele
bse2n
-b5sen.
bs1ent
bs1er
-bs5e4r3in
+bs3e4r3in
b5ses
b5set
-bs1ex
-bsi4t
-bs5ko
-bs2ku
-b4sl
+bsi2t
b2s1of
bs1op
bso2r
@@ -1874,44 +1868,42 @@ b2sö
bs1par
bs2pl
b3s2pu
-bs5s2
+bs3s2
bs2t
bst1a2b
bst1ac
bst1ak
bst3ank
+b5stä
bs3tät
-bs4tem
bst1er
+b4stern
bst1h
-b3sto
-b2s3trä
+bs3tip
+b5stra
+b4s3trä
bs3treu
b3stu
-b3stü
-b4stüb
+bs3ty
b2s1un
+bs3w
4b1t
-b3ta
+b5ta
btal3
-bta4s
-btast3r
+bta4st3r
b3tä
b5te
b2t1h
-b3ti
bti2s
b3to
-b3tr
-bts2
-b3tu
+b5tr
+b5tu
btü1
b2u
bu2chi
bu2e3
bu2f
bu5li
-bul2la
2b3umk
bu3na
bunde6s
@@ -1923,6 +1915,8 @@ bus3cha
bu3se
bu4s1er
bus1p
+bu6sterm
+bu4s1tr
bus1u
bu3ße
1b2ü
@@ -1931,19 +1925,18 @@ büge4
bügel3e
2b3v
2b5w
-1by
-by1a
+bwa5re
+1by1
by3p
-by4t
-by5th
-2b3z2
-b5ze
+by2t
+by3th
+2b5z2
bzei2t1
2c.
1c4a
-2ca1b
+2ca1b4
ca1ch
-ca2e3
+cae3
3caf
ca3g4
ca1h
@@ -1956,8 +1949,7 @@ ca3pel
3car
car3n
carri1
-ca3s2a3
-ca4st
+ca3s4a3
ca3th
ca1y2
cä3
@@ -1976,15 +1968,14 @@ cen3ta
ce3n1u
1cer
ce1ro
-ce3sh
-ce1st
+ce5sh
1cet
-2ceta
+4ceta
cet3am
ce3ty
ce1u
1cé
-2c1f
+c1f
c4h
4ch.
2chab
@@ -1992,29 +1983,30 @@ ch3abi
ch1ah
ch1ak
ch2anb
-5chanc
+3chanc
ch1ang
ch3anst
-4chanz
-3chao
+2chanz
+1chao
ch1ap
-4char.
+2char.
ch3arm.
3charta
cha2sc
chasi1
-3chato
-4chatu
+1chato
ch1ärm
ch1äs
1châ
2chb
-4chc
+2chc
2chd
ch3e4ben
ch3echt
-3chef
+1chef
+3chef.
che2fe
+3chefs
4chei
ch1eim
che4ler
@@ -2023,17 +2015,16 @@ che4ler
cher3a
che3rei
6chergeb
-2cherö
ch1ess
2ch3eta
-2ch1ex
+ch1ex
1ché
2chf
2chg
2chh
ch1ia
-3chia.
-3chias
+1chia.
+1chias
6chind
3chines
ch1inf
@@ -2049,103 +2040,72 @@ ch3lein
2ch2m
ch4mu
2chn4
-2chob
-cho6cker
cho2f
ch1off
ch1oh
ch1orc
2chp
ch2r2
-4chre
+2chre
+chre5s
ch3rh
3chron
4chs
-4cht
+2cht
+ch5tes
2chuf
2chuh
2chum
2ch1unf
-2chunt
-4chü
+chus4si
+2chü
2chv
2chw
2chz
1ci
ci1c
+cil3l
ci2s
c1j
-c4k
-4ck.
+2c4k
ck1a
-3cka.
-ck5aa
-2ckac
-2ckal
-ck5am
-2ck3an
+ck3aa
+ck3am
+ck3an
cka4r1
-2ckau
ck1ä
-4ckb
-2ckc
-2ckd
-1cke
-3cked
-4ckeff
-4ckeh
ck1ehe
-4ck3ei
-3ckel
-3cken
-4ck3ense
+ck3ei
+ck3ense
ck1ent
-4ckentw
cke2ra
cke5reig
-4ckerhö
-4ckerke
-2ckero
-2ck1err
+ck1err
cke2s
-2ck1ese
-2ckex
-4ckf
-4ckg
-2ckh
-1cki
-2ck1id
+ck1ese
+ck1id
ck1im
ck1in
-3ckis
-2ckk
-2ck5l
-2ckm
-2ck3n
-2ck1o2
+ck5l
+ck3n
+ck1o2
ck1ö
-2ckp
-2ck5r
-4cks
+ck5r
ck3spo
-4ckt
-ck5t2e
+ck5ste
+ck4stro
+ck3t2e
ck3ther
-3cku
-4ck1um3
-4ckunt
-4ck1up
-2ckv
-4ckw
-1cky
-4ckz
+ck1um
+ck1up
3c6l2
-clet4
+clet2
clo1c
c2m
-3co
-co2c
-co3ch
+1co
+3coa
+3coc
+co1ch
co2d
co4der.
co3di
@@ -2163,30 +2123,27 @@ co1ra
co4re
cor5t
cos4
-co4te
-cô4
+co4st
+co2te
2cp
-2c1q
+c1q
c4r2
cre2
cre4mes
cry2
-2c2s
-cs2a
-c3se
+2cs2
+c2si
cst4
-c3s2tr
2c1t
cte3e
-c3ti4
-c3to
+cti4
+ction5
ctur6
-3cu
+1cu
cu2p3
cup1e
cussi4
1cy
-2cz
4d.
3da.
da1a
@@ -2204,10 +2161,10 @@ da3dr
da1er
2d1af
d1ag
-dagi4
+dagi4o
dah3l
da1ho
-3d4ai
+3d4ai4
da1in
da1is
da1l2a
@@ -2218,6 +2175,7 @@ da1lö
2d1amma
2d1ammä
damo3
+d2amp
damp7f8erf
2d1amt
d2an.
@@ -2238,22 +2196,21 @@ d2aph
4dapp
da2r3a
2darb6
+dar3bl
3d2arl
dar2ma
dar2m1i
da2ro
2darr
-dar3s
2dart
d1artg
da2ru
d2arw
-das4
da3s2h
-da5s2t
3dat
da3ta
dat2e4
+da3tei
4d3atl
4datm
3dau3e4
@@ -2262,27 +2219,26 @@ dat2e4
2d1äh
2d1ämt
2d1änd
-2d1äng
+2d1äng5
2d1äp
2d1ärz
dä2um
dä1us
-2d7b6
+2d7b
dbu2
2d1c
4d3d2
-ddar2
ddar4m
d5de
1de
de3am
de3an
de3as
-de5a4t
-de3b6
+de5a2t
+de3b4
4d1e4ben
-3de1c
-de2cka
+3dec
+de1ch
deco3
de1e2
2d1eff
@@ -2294,6 +2250,7 @@ de3ho
d2eic
3d2e1im
de2l1a4g
+delat5
de4l3aug
de4l1än
del1ec
@@ -2303,38 +2260,37 @@ de3l2ei
de2len
2d1elfm
3delik
+del4la
delle2
-del4leb
del4lei
+del2lö
de2l1ob
de3lor
de2lö
-del2s5e
+del2s1e
del2so
del2s1p
-del5ster
delt4
del3ta
+del3te
del3tr
de6ments
2d1emp
d2en.
-dend2
-dend4s
de4n3end
den3g
de2ni
den4k5li
-den3sc
+4densem
den4sen
-dens5tau
+den6s5tau
den3th
2dentw
de2ob
2deol
de1on
deo4no
-depi2
+depi4so
d4er.
de1rad
de2r3ap
@@ -2346,6 +2302,7 @@ de3r4erb
de3r4erf
de4r3ero
4d3erhöh
+d4eri
de5ric
de3rik
4d3erklä
@@ -2354,7 +2311,6 @@ de2rop
d3ersat
dert2a
der6t5end
-dert2s
de3ru
de4ruh
de4rum
@@ -2368,17 +2324,14 @@ de3se
des1en
des1in
des1o
-des1p
-des3pot
-des3s4
-des5se
+des3p
+des5s4
dest5alt
de5stang
-de5star
-de5stat
-de7stel
-de4sto
-de3str
+de5ste
+de6s3tei
+de5sti
+de7stin
dest5rat
de5stri
de5stro
@@ -2392,14 +2345,12 @@ de2xis
2dexp
2d3f
2d1g
-dga2
d2ge.
d3gem
dge2ta
dge6t5e
d3gl
2d1h2
-dhas2
d2his
d3hu
1di
@@ -2415,16 +2366,16 @@ dich3te
di2de
di2e
di3e2d
-die3ner
+die5ner
di3eni
di3ens.
dienst5r
-die4s3c
+die4s1c
die2t5
-dige4s
+dige6s
di3gn
di3ka
-dil2s3
+dil4s1
2d1imb
din2a
2d1ind
@@ -2444,10 +2395,7 @@ di2ris
2d1irl
2d1isr
dist4
-di4ste
di2ta
-di3te
-di4tei
di4teng
di4t3erl
di4t3erm
@@ -2455,7 +2403,6 @@ di4t3ers
di2t3r
di2tu
diz2
-di3zi
2d1j
2d1k4
4d1l
@@ -2475,8 +2422,7 @@ d1o2be
dob4l
3dobr
3doby
-do2c
-do3chi
+do1chi
3dog
do3ha
3dok
@@ -2484,7 +2430,7 @@ dol3l2
do2mar
3don
do5n4a
-doni1e
+doni1
do2o
4d1opf
d2opp
@@ -2500,10 +2446,9 @@ do2rie
d2orp
d2os.
do3sp
-dos3s
+dos3s4
dost3
-do4sta
-do3str
+do6sta
3dot
dot4h
do3un
@@ -2512,13 +2457,12 @@ do1y2
d1öf
d1öl1
3dör
-dö4s3c
+dö4s1c
2d3p2
2d1q
d2r4
3d4ra.
2d3rad
-drag4
d4rah
2d5rahm
3d4ram
@@ -2553,16 +2497,18 @@ d3rieg
d4rif
d3rind
3drisc
+2driß
3d4rit
4dritu
2drob
d3roc
2d3rod
d4roi
+dro3ma
2d3rot
d3rou
2d3rov
-drö4s3
+drö4s1
3d4ru
d5rub
4d5ruf
@@ -2570,21 +2516,20 @@ d5rub
4d5rut
3d4rü
drü1b
-drü5cke
-2ds
+2d1s
ds3ab
-d4s3amt
+d4s1amt
d2s3an
ds3assi
-d2s1au2
+d2sau2
d2s1än
4dsb
d4schin
d2s1e2b
d3sec
d2s1ef
-d5s4eig
-d2sein
+d3s2eig
+d2s1ein
d2s1eng
d2s1ent
d2s1erf
@@ -2596,12 +2541,12 @@ d4s1eta
d3s2ha
ds3han
d3sho
-ds3hu
d2s1im
ds2inf
d3s2kan
d3skul
4dsl
+ds3m
d2s1op
dso2r
ds1ori
@@ -2612,33 +2557,28 @@ d2s1pä
d3s2po
d4spro
dss2
-ds3st
+ds5st
dst4
-d2s1tab
+d4s1tab
d4s3täti
-d5stei
-d5stell
-d3s4tern
-ds1th
-d1s2ti
-ds4til
-d3stip
-d1str
+d6stea
+ds2til
+d5stip
+d4s1tis
+d2stod
d5stre
-ds2tri
-d1s2tu
ds1ums
d2sun
-d1sy
ds2zen
4dt
d1ta
dt3a2d
d1tä
-d5tea
+d1te
+d3tea
dte5na
dt3ha
-d3ti
+d1ti
d1to4
d1tö
dt3r
@@ -2649,6 +2589,7 @@ dt5sc
dt3sp
dt5str
dt3t
+d1tu
d1tü
1du
du1alv
@@ -2658,7 +2599,7 @@ du3e
du2f
2d1ufe
2d1uh
-du1i
+du1i4
3dum.
d1umb
2dumd
@@ -2677,39 +2618,33 @@ dun3d
dun3ke
dun2kl
2dunr
-dun2st
2dunt
du1os
dup4
-dur2
+dur2c
2d1url
-3du2s
+3dus
+du2sc
du3scha
-du3se
-dus1t
2düb
3düf
3dün
3dür
-dürn3
2d1v2
2d1w
-dwa4
dwa2l
-dwes4
+dwe4s
dwest1
dy3n
2d1z
-4e.
+6e.
2e1a
e3a2b
-ea2c
eadli4
e2ag4
ea2ge
ea3gl
eakt4
-eak3to
e2al
e3al.
e3alb
@@ -2730,6 +2665,7 @@ eam3a
e4ame
eam1o
eam3to
+eam3tu
ea2na
e5and
e4ano
@@ -2742,7 +2678,9 @@ e4are
e5a6rene
e3arm
e3art
-eas3s
+ea6se.
+eas5s
+ea4st
e4at.
eat4e2
eate4r
@@ -2754,6 +2692,7 @@ eau3b
e3au2f
e3aug
e3ä4
+eäng5
e1b
2eba
e3b2ak
@@ -2761,7 +2700,7 @@ eba3ra
ebe2i
eb4en
e3beng
-eben6s5e
+eben4s3e
2ebet
2ebl
eb5ler
@@ -2775,22 +2714,23 @@ ebö4s
e3bra
eb3rei
eb2s
-ebs1au
+eb6sche
eb4se2
ebs1i
ebs1o
ebs1p
ebs3pa
-eb4stät
-ebs5tem
+eb6stät
+eb4stec
+ebs3tei
ebs3th
ebs3ti
-eb3str
+ebs3tot
ebs1u
e3bu
ebu2t1
eb3üb
-2e3ca
+2eca
e1ce
ech1ä
2e3che
@@ -2809,22 +2749,19 @@ e1chu
ech1uh
ech3w
eci6a
-e1cka
eck3se
2eckt
2ecl
-2eco
-e5cr
-ecs1
+e1cr
2ect
e1d
ed4dr
ed4e
+ede4c
e3dei
ede3n2e
-eden2s
eden4se
-edens3p
+eden4s3p
ede2r
ed2ge
edi4a
@@ -2834,29 +2771,29 @@ ed3s2ä
ed2s1es
ed2s1o
ed2s1p
-ed2s1tr
+ed5sta
+ed4s1tr
ed2su
e3dy
-6ee
+4ee
ee5a2
eeb4l
ee2ce
ee1ch
-ee2cho
-ee2ck
eede3
-eed3s2
+eeds2
ee1e
ee3ei
e1eff
-eef3s
+eef5s
eeg4
e1ei2
eei3e
ee1im
ee3ing
+eei3se
eel2e
-e1e2lek
+e1elek
ee3len
e1emp
e1en
@@ -2869,25 +2806,23 @@ e1e2pi
e2e1ra
e1erbt
e1erd
+eerde3c
ee3r2e
ee4r3eng
-eere4s
+eere4s5
ee4ret
e2e1ro
-ee1r2ö
+ee1r2ö5
eer3öf
eert2
e1ertr
e2erü
e1erz
-ees2
-ee3sh
-ees3k
+ee5sh
ee3st
ee2tat
ee2th
ee1u2
-eewa4r
e1e2x
e1f
2ef.
@@ -2924,7 +2859,7 @@ ef1rol
ef3rom
ef3rot
efs2
-ef5sc
+ef7sc
ef3so
ef3sp
ef2tan
@@ -2936,22 +2871,21 @@ e1g
e3ge
ege4n1a
ege2ra
+ege4s3to
+ege4str
ege1u
+eg3la
eg4li
eg3lo
eg3lu
e2gn
eg3ni
-eg4sal
-eg6ser1
-egs2pe
-egs2t6
-eg1ste
-eg4sto
-eg1str
-egs3trä
+eg6sal
+egser1
+eg3spe
+egst6
+eg6sto
2e3gu
-egus1
2e1ha
eh1ach
eh3aka
@@ -2965,7 +2899,6 @@ ehen2t3
1e2hep
ehe1ra
eher4an
-ehe3str
e3h2i
eh3int
eh1lam
@@ -2983,15 +2916,17 @@ e1ho
e3hol
ehr1a
ehr1ä
-ehr3e2c
+ehr3ec
eh2r3ei
eh1ri
eh1ro
ehr1ob
ehr1of
-ehr5sch
-ehs2
+eh2s2
+eh3se
eh3sh
+eh3si
+eh3so
eh3sp
eh3te
e1hu
@@ -3004,9 +2939,10 @@ e1hy
2ei3a2
4eib
ei2b3l
-eibu4t
+eibu2t
ei4b3ute
ei2cho
+eichs7test
eich5te
e2id
ei2d1a
@@ -3017,8 +2953,7 @@ ei3dra
ei1e
ei3el
2eien
-eien3st
-ei3erv
+eie4s
ei3et
1eifr
ei3g2a
@@ -3081,13 +3016,15 @@ ei2sä
ei4s3erw
ei3sp
eis2pe
-ei3sto
+ei4str
+ei2sum
ei2ta
2eitä
-eit1h
+ei3ten
+ei2t1h
ei2tro
eit3t2
-ei4t3um
+eit3um
2eiu
2e1j
e1k
@@ -3103,18 +3040,16 @@ ek4l
ek5lip
ek4n
2ek2o
-ek3s4t
2ekt
ekt4ant
ekt3erf
ekt3erg
ek4t3erz
-ek3t2o
+ekt2o
e3k2w
2e1la
e3lab
el3aben
-ela2c
el1af
el3agi
ela2h
@@ -3127,13 +3062,12 @@ e2l3anz
el1ap
e2l1a2r
el5ari
-ela4s
el3asi
el3asp
e3law
2e1lä
+elb4
1elbis
-elb4l
el2da
eld5erst
eld3erw
@@ -3141,8 +3075,7 @@ el3des
el3dr
elds2
e5le.
-elea2
-ele4c
+elea4
2elei
e3leie
e6l5eier.
@@ -3171,7 +3104,6 @@ e3let.
e2l3e4ta
2elev
ele2x
-el1exi
el3fe
elf3ein
elf4l
@@ -3182,15 +3114,16 @@ e3lie
e2lim
eli4n
el1ita
-ell2a
-el3lan
+elks2
+el3l2a
+el4läu
el5le.
ell3ebe
el4l3ein
ell3eis
el3les
-el5lin
-ell5sp
+el2lic
+el3l2in
elm2a
2eln
el5na
@@ -3208,20 +3141,20 @@ e1lö
el2san
el2ser
el2spr
-els6tern
el2su
el2ta
-el3tak
+el3t2ak
elte2k
elt3eng
-el4t3in
+el3tes
+elt3in
el2to2
el2t3r
el3tri
el3tro
elts2
elt3sk
-elt5sp
+elt3sp
2e1lu
e2l1um
e3lung
@@ -3234,8 +3167,7 @@ el3zwe
2ema
e2m3ad
ema2k
-em1anf
-e3mann
+e2m1anf
em1ans
3emanz
e5mä
@@ -3244,13 +3176,13 @@ em4d3a2
eme4n
emen4t3h
e2m1erw
-eme2s
3e2meti
em1ex
em1im
em1int
-emi5ti
+emi3te
2emm
+em2map
emma3u
e3mon
e2mop
@@ -3265,7 +3197,7 @@ em3t2
e2na
4ena.
e4na2b
-2e3nac
+2e5nac
e3nad
e4naf
4enah
@@ -3275,7 +3207,6 @@ ena3l2i
4en1am
en4ame
e4nand
-e5nann
en3anz
en1ap
e4nar
@@ -3290,18 +3221,16 @@ e3näc
en1är
en1äu
en2ce
-en3del
-end3ess
+en4d3ess
en3do
end4ort
end3ras
-end7si
+end5si
end3s2p
end3sz
en3dum
2ene
-en1e2c
-ene4ck
+en1ec
e2nef
en1ehr
en3ei.
@@ -3314,6 +3243,7 @@ e5n4entr
en1epo
4ener.
e4n1erd
+e4nerf
3e2n3erg
e4n3erh
4e3neri
@@ -3326,10 +3256,12 @@ en1ers
e2n3ert
e2n3eru
e4n1erw
-en3erz
+en3erwe
+e6n3erz
e4n3ess
en3eta
en3eth
+ene3tr
en1eup
e4nex
en3fa
@@ -3340,8 +3272,8 @@ en5g2i
en2gl
en3glo
1engp
-eng5sc
-eng3se
+eng5s
+eng7sc
2eni
e3nic
e4n1id
@@ -3355,8 +3287,8 @@ e5nit
en3k2ü
e2n1ob
enob4le
-e2n3oh
-e3n4ol
+e2n1oh
+e3nol
eno2ma
en1on
e2n1op
@@ -3371,17 +3303,19 @@ e6nr
en2san
en5sche
en7schen
-en4seb
+en2seb
1ensem
ens3eng
en3sho
en2sid
-en3s2ka
+en3ska
en3s2po
enst5alt
en4s3tät
+en6s5test
4ensto
-en3stoc
+en7stric
+ens5trie
en5t4ag
en3tanz
1entd
@@ -3434,9 +3368,9 @@ e3ord
eorgi1
e3ort
e3orw
-eo3s2
+eos2
e3os.
-eo1st
+eo5st
eo3ul
e1o2v
e1ö2
@@ -3447,13 +3381,13 @@ e3p2f6
1episo
ep3le
e2poc
+epor5te
ep2pa
ep4pl
ep2pr
ept2
ep3ta
ep4tal
-ep5ti
e1q
er1a
e5ra.
@@ -3513,7 +3447,7 @@ erd3erw
4e5re.
e3rech
er3echs
-er1e4ck
+er1eck
ere4dit
er1eff
er1e2h
@@ -3549,6 +3483,7 @@ e2r1erw
4eres
e5res.
er1ess
+er1eß
er3e4ti
er1eul
ere3us
@@ -3558,18 +3493,16 @@ er3fä
3ergebn
4ergehä
erg3ise
-erg3s4
e2r3h
3erhab
-4e1ri
+2e1ri
e2riat
e3rib
-6e3rie
+4e3rie
eri5e4n3
-erien5e
e5rif
erik6
-6e3rin.
+4e3rin.
er1inb
er1ind
e4r1ini
@@ -3579,8 +3512,8 @@ e4r1int
e3rio
er1ita
2erkol
-erk5te
-erk5tr
+erk3te
+erk3tr
4erl.
3erlebn
4erln
@@ -3588,7 +3521,7 @@ erm2
er3ma
erm3ers
er3nan
-er2n1o4s
+er2n1os
e1ro.
er3oa
er1ob
@@ -3608,19 +3541,18 @@ e1row
e1roz
er1ö2
e1röh
-4erök
+2erök
+erö4s
er5p
er3ra
-er5rä
2errü
er3sa
-ers2au
-er5sen
-er7s2i
+ers4au
+er3se
+er5s2i
er3sk
er3smo
er3sn
-er3sum
er3s2z
ert3abe
ert2ak
@@ -3633,6 +3565,7 @@ ert3ins
er3to
erts2e
2e1ru
+eruf6s
er1uhr
er1u2m
er1uns
@@ -3641,36 +3574,35 @@ er1uz
e1rü
er3ü2b
e5rüg
-2erv
3erweck
6erweis
2erzy
+es2a
e4s3ab
-es4ach
es3ad
es3ak
-e5s4a4s
-es3aus
+es3alt
+es3ar
+e5s4as
es3av
-esä2c
2esb
e3sc
es3cap
-e5s4ce
+es4ce
esch4
e6schan
esch2n
+e4sco
e6scu
es1ebe
es3ehr
-es3ein
+es1ein
es1eis
es1eta
es3eva
2esf
-6esh
+6e4sh
es2har
-es3he
es2hu
e3sid
e5sie
@@ -3679,71 +3611,71 @@ es1ini
es3int
e3sir
e7sis
-es3ke
+e5sit
+es5ke
es3ki
-es3kl
-es3ku
e4s3ky
-es3l
-es4log
-2esm
+e4sl
+es2log
+2e4sm
+e4sn
e3sof
e3sol
eso2r
es2ort
es4pei
-e3spek
+e3s4pek
+e5spi
es2po
-e5spor
+e5s4por
+es2pr
e5s4pra
2esr
+es6saa
1essay
-es3sc
-es5sec
-6essem
+es3sec
ess4e3re
es4s3erg
+es4sit
2esso
es2sof
es2sp
ess1pa
-es2st
+es4st
ess3tie
-es3str
-e5staa
-e2stab
-estab4b
+es5str
+es5su
+e2st
+estab6b
est1ak
-e3star
e4starb
-es2tau
-es3taum
-e3stec
+es6tau
+es7taum
+es2te
+es6te.
est5eink
-e5stel
-es4t3eng
-es4t3erh
-es4t3ess
-e1stil
+e7stel
+e4st3eng
+e4st3erh
+e7stern
+e7sters
+e4st3ess
+es4ti
+es5tip
estmo6de
-est3ori
-e1s2tr
+est3o4ri
es3trop
-e1s2tu
-es3tus
-e3s4tü
+e3stu
+es4tü
e2s1um
-es3ums
es1ur
-es3w
e3sy
-es3z
-e1ß
eße3r2e
2et
e1ta
eta3b6
et1am
+etari1
et4at
e1tä
et1äh
@@ -3764,8 +3696,6 @@ eti2ta
e3to
eto4b
e4t1of
-etons4
-eto4s
e1tö
4e1tr
e4t3raum
@@ -3773,25 +3703,23 @@ et3rec
e2t3res
et4ri
et4ro
-et2s
-et3sc
-et5schu
etsch3w
-et3se
et3so
et3sp
-et3sto
-et3str
et3su
et2ta2
et4tang
ett3au
+et2tä
et2tei
ette4n1
ett1h
et4t3r
ett3sz
-et4t1um
+et2t1um
+et2tur
+et2tü
+e1tu
et1ups
e1tü
et4z3ent
@@ -3799,7 +3727,7 @@ et3zo
eu1a
eu3ere
eu3erz
-eu2esc
+eu2e5sc
eu2ga
eug6er
eug3l
@@ -3813,26 +3741,26 @@ e1um
e3um.
e3umb
e3uml
-e3um4s
+e3um6s
eums1p
eum5st
+eum7str
2eun
eu3n2e
e3ung
eu4nio
+eun3ka
eu1o2
eu3p
eu2rau
eu3r2e
eur4er
-1eu3ro
+1eu3ro1
eu4sk
eu3sp
e4ust4
-eu1str
2eut
-eu5te
-eu3to
+eu3te
2eux
eu2zw
e3ü
@@ -3840,6 +3768,7 @@ e3ü
4eve
e2vela
e2vent
+ev2s
e1w
2e3wa
ewa3s
@@ -3851,25 +3780,24 @@ ew3et.
e3wir
ewi2s
e3wit
-e5wo
ew2s
2ex.
-1exam
ex3at
1e6xem
e4x1er
e2x1in
+1exis
3exp
2ext.
-e1xy
+ex2tin
+2exu
+2e1xy
2ey
ey4n
-ey3st
e1z
-e3z2a
+e5z2a
e2z1enn
e3zi
-ezin4
ezi2s
é1b
é1c
@@ -3889,16 +3817,17 @@ ezi2s
è1n
è1r
ê1p
-ê4t
6f.
1fa
3fa.
-fa1b
+fa1b4
fa2ben
+f3abf
+fab5s
3fac
-fa4cheb
+fa3che.
+fa3chem
fa2ch1i
-fa2cho
2fad
fa2da
3fa1e
@@ -3909,11 +3838,13 @@ fa2ke
f2al
fa1l2a
fal2kl
+fal6lenk
fal6l5erk
+fal2li
fal2s
-fal3te
falt4s
fal2z1
+3fam
2fanb
fan3da
2fanf
@@ -3925,14 +3856,13 @@ fan2gr
2f1ap
far2b3r
3fari
-farr3s
3f2art
fa5ru
f1arz
3fas
-fa3s2a
-fa5se
+fa3s4a
fa3sh
+3faß
2fat
fa2to5
2f1auf
@@ -3952,9 +3882,7 @@ fä2ßer
f3ds
1fe
3fe.
-fe4c
f2ech
-fe5che
4f3eck
fe2dr
fe2ei
@@ -3962,6 +3890,7 @@ fe1em
f4eie
4feinh
fei2nu
+fei5st
fek2ta
3fel
fe2l1a
@@ -3969,9 +3898,12 @@ fel4dr
fel5eise
4f1e2lek
fe2l1er
+fel5lä
fe2l1o
fel4soh
fel3to
+fel3tr
+fel3tu
3f2em.
2femi
fem4m
@@ -3983,7 +3915,8 @@ fe2ni
fe2no
fen3sa
fen7sc
-fenst2
+fens2t2
+fen5ste
f1ent
f2er.
fe1r2a
@@ -4000,10 +3933,10 @@ f4erpa
f2ers.
f2ert
f1erw
-fe2s
+fes2t
fe4st1a
-fes3tat
-fest3ei
+fe4st3ei
+fe4str
2f3e4ta
3fete
fet4t1a
@@ -4012,8 +3945,10 @@ fet4t1a
4fexp
3fez
1fé
-4f1f
+6f1f
+ff2ab
ff1ar
+ff2arb
ff3at
ff1au
ff2e
@@ -4025,6 +3960,7 @@ ffe2m
ff3emi
f5fen
f5fer
+f2fetz
fff4
ffi3k
ff6lei
@@ -4042,12 +3978,10 @@ ff3sho
fft2
fft3h
2f3g4
-fge1
2f1h
1fi
3fi.
fi3at
-fien3
fi1er2f
fi2ki
fi3kl
@@ -4062,20 +3996,18 @@ fi6lin
fil2ip
fin4a
fi3ni
-fin4s3
2f1int
fi3ol
fi2r
fi3ra
3fis
fi3s4a
+fi4scha
fisch3o
fi3so
fi5s2p
-fi4s3t
-fi3te
fi2t1o2
-fit3st
+fit5st
fi3tu
5fiz
2f1j
@@ -4103,12 +4035,11 @@ flug1a
f4lü
2f1m
2f3n2
-fni2s
+fni2
1fo
fob4l
2f1of
fo2na
-fon3st
fo2nu
2f1op
fo1ra
@@ -4117,17 +4048,17 @@ fo3rin
3form
for4m3a4g
forni7er.
-for4st
+for4sta
for2t
for4te
for4th
fort3r
for3tu
+fo5st
2fo2x
2f1öf
2f1ök
2f1öl
-förs3
2f3p2
fper1
2f1q
@@ -4137,6 +4068,7 @@ f5rad
fra4m
f3rand
1f4rän
+frä5st
2f5re.
f5ref
2freg
@@ -4150,30 +4082,30 @@ fri2e
2frig
fri3k
1f4ris
+fri6ster
+f4riß
f3roc
1f4ron
-fro2s
+fro2sc
fru2h
4fs
-fs1all
-f2s1an
+f2san
fs3ar
f2s3as
-fs1auf
f2saut
f3sc
+f4sce
f4schan
-f5schl
-fs4co
fs1e2b
fs3ehr
+fs1ein
f2s1em
f4s1ent
f2s1er
fse4t
f4s1eta
f3si
-fsi2d
+f2si2d
f2s1o2
fs3ol
f3span
@@ -4185,19 +4117,18 @@ f2s1pr
fs2pra
fs2pri
fs3s2
-f1s2t
-fs3tak
-fs3tät
+fs1tak
+f4stas
+fs2tau
+fs1tät
f4stäti
f4stech
-f3stei
f5stel
-f3stern
-fs3th
-f3st4r
+f4stemp
+f4s1tis
+fst4r
f4s3tres
-fs4tro
-f3stü
+fs2tro
f4s3tüte
f2s1un
f2sü
@@ -4216,8 +4147,7 @@ ft1e2h
ft1eig
ft1ein
ft1eis
-fte3ma
-f4t1ent
+f2t1ent
f2t3e4ti
f2t1h
f4t3hei
@@ -4228,14 +4158,13 @@ f2t3ro
ft3rö
f3t4ru
ft2s1
-ft4s3a2
+ft4sa2
ft3sc
-ft6sche
ftse2
-ft3st
-fts3tan
-ft4s3tä
-ft5sti
+ft4stä
+ft5s4ten
+ft5s2ti
+ft3sü
ft3t
ft1url
ft3z2
@@ -4248,12 +4177,14 @@ fun4ko
fun2k3r
2f1unm
2funt
-furch4
+furch2
fu4re.
fu5ru
-fus2sa
-fus2s1p
-fus2st
+fus3se
+fus6senk
+fus4ser
+fuss1p
+fus4s1t
fu2ß1er
3fut
1fü
@@ -4270,13 +4201,12 @@ fz4s
6g.
1ga
5ga.
-gabe4n
2gabf
-gab5l
-ga1br
+ga2b5l
+ga1b4r
ga3bu
2gabz
-ga1c
+ga1ch
ga3di
ga1e
ga1fl
@@ -4292,11 +4222,11 @@ g1anf
gan2g1a
4gangeb
gan2gr
-2ganh
+2g1anh
2g3anku
2ganl
-g3anla
3gano
+g4ant
2ganw
ga1ny
2g1arb
@@ -4306,15 +4236,18 @@ ga1ny
ga3r2o
g1arti
2garz
-ga2s1a
+ga2s
+gas3a
ga4sal
-gas3ei
-ga2si
-ga2so
-gas3s
-ga4st
-gas4t3el
-gas4tra
+ga3sc
+ga5se.
+gas1ei
+gas5s
+ga4sta
+gas3tan
+ga4st3el
+ga4stra
+gas1tu
ga3t2a
ga3th
2gatm
@@ -4327,9 +4260,10 @@ g2auk
1gä
2g1äp
g1ärz
-3gäs
+3gäs4
+gä5st
gä4u
-4g1b
+6g1b
g5be
gber2
g5bo
@@ -4356,20 +4290,21 @@ ge3a2
ge3ba
gebe4am
geb4r
-ge3c
+ge1c
ge3d
ge1e2
ge3ec
ge2es
gef4
+geg4l
ge3ha
ge1im
ge1ins
ge1inv
ge1ir
-ge2is
4geise
gei3sh
+gei4sta
g2el
gel6ders
ge3le
@@ -4378,9 +4313,9 @@ ge4less
ge3lor
gel3sa
gels2t
-gel3ste
gel3sz
gel3t2a
+gel3to
ge3lum
ge3lü
gel3z2
@@ -4397,9 +4332,8 @@ gen3eid
gen3ern
gen3g
gen3k
+genmes4
ge3nor
-gens3am
-gen7stern
gen3sz
g1entf
gen3th
@@ -4424,30 +4358,26 @@ ge1ro
ge1r2ö
ger4sto
3gerw
-ges2
-ge5s4am
+g6es
ges3auf
-ge5s4c
+ge5s2c
ges3elt
-ge2s3er
+ge2s1er
ge3ses
-ge3si
+ge3s2i
ge3sp
-ges4pi
-gess4t
-ge1st
-ge3ste
-ge5stei
-ges4tem
-ge4s3ter
+gess2t
+ge3st
get2a
+ge3tan
4getap
ge3t2u
ge1ul
+gewa5re
4g5ex
2g3f2
-4g1g
-gga4t
+2g1g
+gga2t
g5ge
gge2ne
g2g3l
@@ -4455,6 +4385,7 @@ gg4lo
g2g3n
gg4r
g3grä
+gg4s
2g1h
4gh.
3g2het
@@ -4487,7 +4418,6 @@ gi2o
gi3ro
2gisel
git2a
-gi3tu
gi2us
2g1j
2g5k
@@ -4498,9 +4428,13 @@ g2l
3glad
2g3lag
3glanz
+gla4s5ti
+gla4stu
3g4laub
2g3lauf
1glä
+3gläs
+g3läß
3glät
2gläuf
1gl4e
@@ -4521,12 +4455,11 @@ g3li
g4lia
2glib
3g4lid
-5g4lie
+5g6lie
2glif
1g4lik
g5lin
-1g4lio
-gli2s
+1g6lio
4glisc
1g4lit
1g4liz
@@ -4541,11 +4474,12 @@ g4lom
1g4lot
g3lö
2gls
-2glu
-glu2t
+2glu2
+glu3te
3glü
3gly
-4g1m2
+2g1m2
+gmi3te
gn2
4gn.
g2na
@@ -4559,7 +4493,7 @@ g5neh
g2nie
g2nif
g4nin
-4g5nis1
+4g5ni4s1
g2no
gno1r
2g3not
@@ -4577,7 +4511,7 @@ goa3li
go3be
2g1of
2g1oh
-go1i
+go1i4
gol2a
3gon
2g1ope
@@ -4585,7 +4519,6 @@ gol2a
3g2o1ra
3gos
go2si
-go3st
go3t2h
got6t5erg
3gou
@@ -4629,6 +4562,8 @@ gro3be
gron4
g4ros
gross5el
+gros8seri
+g4roß
gro4u
2g3röh
g4ruf
@@ -4640,116 +4575,135 @@ g4ruf
grü1b
2g3rüc
3g4rün
-4g2s1
+4g2s
+gs1ac
gs3ad
-g4sa2g
-g3s2ah
+gs1af
+gs1a2g
+g5sah
gs5a2k
-g3sal
-gs3ama
-gs3amb
+g5sal
+gs1ama
+gs1amb
gs3an
gs3ar
gs3as
g5sat
gs3aug
-g5sät
-g3sc
-g6sca
-g6sce
+gs1ä
+g7sät
+g5sc
gsch4
-g4schan
+g6schan
+g7schä
g6schef
-gs4chi
-gs3cr
-gse2
-g3s2eil
-g3sel.
-g3seln
-g4s5er
+g7s2chi
+g7schl
+g7schö
+g7schu
+g7schü
+gs1cr
+gs1e2
+g5s2eil
+g5sel.
+g5seln
+gs3ene
+g4s3er
gse4t
+gs1i
gsi2d
-g5sil
-g4s3l
-gso2
+g7sil
+gs3l
+gs1o2
g3sol
-g5soz
-g3spek
+g7soz
+gs1ö
+gs1p
+g5spek
gs2pi
-gs6pie
-g4s3pin
-g5s4por
-gsrü2
-gs5s4
-g3star
-gs4tati
+gs3pin
+g5s2por
+g4spu
+gs3s2
+g3st
+gs1ta
+g5s2tar
gst1au
-g4stä
-g5stäm
-gs3te
-g3s4tel
+gs1tä
+g5ste.
+gs3teil
+g7stel
+g5sten
gst3ent
+g5ster.
gst3err
+gs3test
gs4teu
-g3stir
-g3s2to
-g4s3tor
-gs2tö
-gs4tör
-g1stre
-gs4t3ros
-gs3trü
-g3stu
+g5sti
+gs3tier
+gs1tis
+g5sto
+g6ston
+g6s1tor
+gs1tot
+g5stö
+gs1tr
+gst4ri
+gst3ros
+g5stuf
+g5stun
+gs1tü
gs2tüc
-g4s5w
-g3sy
-2g1t2
+gs1u
+g5sub
+g5sy
+2g1t
g5te
-g2t3h
+g2t1h
g5ti
gti2m
-gts3
-gt3t
-gt3w
+g5tr
+gt4se
1gu
gu1an.
gu1ant
-gu1c
gu2e
-guet4
+guet2
2g1u2f
2g1uh
gu3ins
gu1is
gu5me
+3gumm
gun2e
2g1unf
g2ung.
-gunge6
+gunge2
4gungew
2g1ungl
-3g2un4s
+3g2uns
4gunt
gu3re
2g1url
-gu4s
-gus3a
-gu5sc
+gu4s3a
guschi5
-gu5se
-gus5se.
-gus2st
+gus6saa
+gus6sam
+gus4st
+gu2ß1
5gu2t1
+gu3te
1gü
2güb
gür1
-güs1
+gü5st
2g1v
4g5w
+gwa5re
1gy
gy3n
2g3z2
-4h.
+6h.
2ha.
hab2a
hab2e
@@ -4768,7 +4722,6 @@ ha3go
ha3ha
hai1es
h2aka
-haki3
ha1kl
4h2al.
ha1la
@@ -4778,12 +4731,10 @@ ha2lau
hal2ba
hal4bei
halb3r
-halb5s
-2ha3le
-ha3li
+2hale
+hal4leh
hal6lerf
h1alp
-hal4st
halt3r
h1amt
h2an.
@@ -4792,7 +4743,7 @@ h2and
h4ann
2hanr
2hant
-ha3os
+haos5
2hap
ha2pr
h4a3ra
@@ -4804,25 +4755,25 @@ har4mes
har5te
har4th
h1arti
+h2arts
2has.
-4ha3sa
-ha5sta
+2ha3sa
+ha2ß1
hau3f4li
2h1aufm
h1aukt
hau2sa
hau4sc
-hau5stei
+hau6s3ti
hau2ta
2hauto
hau2tr
h1äff
-3häp
h1ärz
hä6s5chen
-häu4s3c
+häu4s1c
hä1usp
-2h5b6
+2h5b
hba2r3a
2h1c
2h1d
@@ -4860,8 +4811,8 @@ heine2
hei4neh
h1eink
he3ism
-he3ist
-heit6s3
+he3i4st
+heit4s3
h1eiw
hekt5a
he2l3au
@@ -4881,14 +4832,13 @@ he3mi
h2en.
he6n3a2
he4nä
-hend4s
h4ene
he2n1e2b
hen3end
he2net
he2ni
he2no
-henst2
+hen5st2
h1ents
he2nu
hen3z
@@ -4916,12 +4866,12 @@ h1erö
hert2
her3th
her2z1w
-he2s3tr
+hes4t
he2tap
heter2
he3th
he5ti
-he3t6s
+he3t4s
he2u
heu3g
he3x
@@ -4932,8 +4882,6 @@ he1y2
hfel2l1
hfi2s
2h5g2
-hge1
-hgin4s
2h1h
2hi.
2hi2a
@@ -4944,21 +4892,22 @@ hi2e
hi3ens
hie4r3in
hif3f6r
+h2ig
hi2kr
h2il
-hi2l5a4
+hi4l5a4
hil2fr
hi2n
hi3nel
hin2en
hi5n4i
hi3no
-hin4t3a
+hin2t3a
2hio
hi4on
hi3or
hi3os
-4hi2p
+2hi2p
hi3pe
hip1h
hip1i
@@ -4971,9 +4920,7 @@ hi3ro
his2a
hi4se
hi5s2p
-hi4st
-hi1th
-hi5ti
+hi3ti
h1j
2h1k4
2hl
@@ -4985,6 +4932,7 @@ h5land
hl3anz
hl1ar
h3las
+h3laß
h3lat
h3laug
h3laut
@@ -4992,6 +4940,7 @@ h3law
h3läd
hl1är
h3läs
+h3läß
h3läu
hlb4
hl3d4
@@ -5021,7 +4970,8 @@ h2li
h3lic
h3lik
hl1ind
-hll2
+h3list
+hl3l2
hlm2
h2lo
h5loc
@@ -5038,11 +4988,11 @@ hl2ser
hl3sku
hl3slo
hl3sp
+hl2sto
hlt2
h3luf
h3luk
h3lüf
-hlzu5
2h1m
h2ma
h4mab
@@ -5057,7 +5007,8 @@ h4mäu
h3me.
hme1e
hme1in
-hmen4s
+h3meist
+hmen2s
hmen6sc
hme2ra
h2mi
@@ -5106,22 +5057,17 @@ hn3k4
h3nof
hn3s2k
hn4th
-hnts2
h2nul
hn1unf
h3nunge
ho3be
ho2bl
ho2c
-ho4ch5
-ho3ck
-ho4cka
-ho7cker.
+hoch5
hoe4
ho2ef
ho4fa
ho2f3r
-hohen3
hol1au
ho2l1ei
hol3g4
@@ -5136,30 +5082,32 @@ ho2mec
ho2med
ho5mu
h2on
-hon3str
2hoo
2hop
ho1ra
hor3d
h1org
+ho5ri
ho3sl
ho4sp
ho4st
-4hot.
+ho6sta
+ho5ste
+2hot.
ho5th
-4hot3s2
-1hou2
+2hot3s2
+1hou
3hov
-4ho2w
+2ho2w
how1e
h1o2x
ho1y2
+hô1
1hö
hö2c
-hö3ck
h2ör
hö4s
-hös3c
+hös1c
h1öst
2h3p2
h1q
@@ -5186,12 +5134,14 @@ h3rep
h4r3erla
h3rerle
h6rerleb
-h3re4s1
+h3re4s5
+hre6su
hre2t
h2r3eta
h3rev
hrf2
hrg4
+hrga4
h3ric
hri4e
h3riesl
@@ -5204,27 +5154,29 @@ h2rob
h3roh
h3rol
h4rom
+hro3man
h4ron
h2ror
h3rou
-hr2s1ac
+hr2s3ac
hr2s3an
-hrs1au
-hr4se
+hrs3au
+hr5sch
hr2s1en
hr2ser
-hr2set
-hr6s1in
+hr4set
+hr4s1in
hrs3k
-hr4s1of
+hr2s1of
hrst2
hr2su
-hr4sw
+hr6sw
hr4tab
hr2tan
hr2t3ri
hr2tro
hrt2se
+hrt4ste
h1ru
h3ruh
hr1ums
@@ -5233,20 +5185,17 @@ h3rü
hr3üb
h2ry
hrz2
-4hs
+4h1s
h2s1ach
-h2s1an
-h2s1au
+h2san
+h2sau
+h3sc
h4schan
-hs1e4c
-hs2ei
+hs1ec
hs3eins
-hs3eis
-h3sel
-h3sen
-h3ser
-h4s1erl
-h3sex
+hs1eis
+h2s1erl
+h3s2ex
h2s1ing
hs3l
h2s1of
@@ -5255,23 +5204,26 @@ h2sper
h3s2por
h2sprä
hs3s2
-h2stal
+h4stal
hst3alt
-h2stau
-h1stec
-h3s4terb
-hs1the
-h1s2ti
-h2s3tie
-hs4tief
-h2stor
-h1s2tr
+h4starb
+h4stau
+h4stäl
+h5ste.
+h5stem
+h5sten
+h4sterm
+h2steu
+h4s1tie
+h4stin
+h4s1tor
hst3ran
-hst3ri
-h1stun
+h4st3ri
+h2s1tu
+h3stun
h2s1un
hs2ung
-h1sy
+h3sy
4h1t
h2t1a
htab2s
@@ -5279,26 +5231,28 @@ h3t4akt.
h3takts
h3t2al
h4t3alt
-h4tam
ht3a4n
ht5ane
h3t4ank
+h3tas
h4t3ass
h4tasy
ht3a2t
h2t1är
h5te.
-h2t1e4c
+h2t1ec
h3tech
h2t1ef
ht1e2h
h3teha
+h3tehä
h2teif
h4t1eim
ht1ein
h2t1eis
h4t3elit
-h4temp
+h2temp
+h3ten
h4tentf
h4t3ents
ht3erfo
@@ -5306,40 +5260,45 @@ ht3erfü
h2t1erh
h2t1erk
ht4erko
-h4t3erre
+ht3erre
ht3ersc
h6t5erspa
h4t3erst
h2t1erz
hte2s
-h4t3ese
-h4t3ess
+h2t3ese
+h6t3ess
h5tet
-ht1eu
+h2t1eu
h2t1ex
h2t1h
h3ti
h4t1in
hti2s
+htni4
h2t3oly
h2top
+h2torg
h2tö
h3töp
-h4t3rak
+ht3rak
ht3rand
h2t3rat
ht3raus
-h4tref
ht4ri
h2t5rin
h2t3rol
h2t3ros
+ht3roß
h2t3rö
h2t3ru
h2t3rü
ht2sen
+ht4s3ess
ht3spri
ht4stab
+ht4ster
+hts2ti
ht4s3tur
ht4s3tür
ht3t
@@ -5351,15 +5310,13 @@ htwa5re
ht3z4
hu2b
hub1a
-hu4b3ei
+hu4bei
hu4b1en
hub3l
-hub5r
-hu1c
+hub3r
hu2h1a
hu2h1i
-huko3
-huk3t6
+huk3t4
hu2l3a
hu2lä
hu2l3ei
@@ -5368,6 +5325,7 @@ hu4lent
hu2ler
hu2let
hu2l1in
+hul3l
hu2lo
hu3ma
h1ums
@@ -5381,7 +5339,6 @@ hur3g
hu3sa
hu2sc
hu2so
-hus4sa
hu2tab
hu3t2h
hu2ti
@@ -5395,13 +5352,12 @@ h4übs
hüf2
hüh3
hühne4
-hüs3
2h1v
hvi2
hvil4
2hw
h2wal
-hwas7
+hwa5re
hwe1c
h1weib
h1wet
@@ -5412,12 +5368,13 @@ h1z
hz4s
2i.
2ia.
+i4aa
ia1b4
iab5s
2iac
i5ad.
i3adn
-iaf4l
+ia1f4l
i4a3g
i3ak.
i1akt
@@ -5440,7 +5397,7 @@ i3alh
i3a2lia
i3alj
i3al3k2
-i5al3l
+i5al5l
i3alm
i3aln
ia2lor
@@ -5452,6 +5409,7 @@ ia2lu
i3alv
i3alw
i3al3z2
+iam4
2ian
i5an.
i1ana
@@ -5468,37 +5426,34 @@ ia3p2f
ia1q
i3ar
ia2ra
-iard2
2i3as
i5as.
i4asc
ia3sh
i4asi
i4a3sp
-iast4
-ia5sta
-ia1str
+ia4st4
+ia5str
i5at.
-ia4ta
+ia6ta
i3at2h
1iatr
i3ats
i3au
ia3un
+iaus1
2iav
i1äm
-iär2
i1är.
i1ärs
i3ät.
-iä5te
-i3ät3s
+i3ät3s4
i1b
i2b1ar
i2b1auf
ib2bl
i2b1ei
-ibe4n1
+ibe6n1
ibi4k
i3b4la
i3b4le
@@ -5508,17 +5463,16 @@ ib3ren
ib2s
ib3sa
ib3sp
-ib3sta
ib4ste
i2bunk
i2b3unt
-ibus3
+ibus1c
+ibwa5
2ic
ich1a
ich3ä
i1che
ich3ei
-i3cher
i1chi
i2chin
ich3l
@@ -5529,9 +5483,7 @@ i2ch3r
ich2t3r
i1chu
ich3w
-i2cka
-i3ck2e
-icks2
+ick2e
i1cr
i5cu
i1d
@@ -5562,7 +5514,6 @@ ieb4sto
ieb4str
ie1c
ie2cho
-ie4ck
ied3g
ie2dr
ie1e2
@@ -5573,11 +5524,12 @@ ie3fer
ief3f4
ie2f3l
ie2f1r
-ie2g5l
+ie2g7l
ie3g4n
ie2g3r
ieg4ra
-iegs3c
+iegs1c
+ieg4st
ie3her
i1ei
ie2l1a2
@@ -5595,6 +5547,7 @@ iel3sp
iel3sz
ielt4
iel3ta
+iel3to
i1en
i3en.
i3ena
@@ -5603,8 +5556,7 @@ i3e4nä
i3end
ie2n1e2b
ien2er
-ie4nerg
-ie3nern
+ie6nerg
i3enf
i3en3g
i3enh
@@ -5616,9 +5568,9 @@ i3e2no
i3enö
i3enp
i3enr
-ien5s2e
-ien2st
-iens4tr
+iens2
+ien3se
+ien6sto
ienst5rä
ien3sz
i3env
@@ -5635,16 +5587,15 @@ ier4ert
ie4r3erz
ie3res
i3ereu
-ier3k2
+i4eri
+ier3k4
i1ern
i3ern.
ier5ni
iers2e
ier4s3eh
-ier7sei
-ier3sta
-ier3ste
-iesen3s4
+ier5sta
+i3e4stas
ie3su
ie2t1a
ie4tei
@@ -5653,22 +5604,24 @@ ie4t3ert
ie2th
iet3ho
ie4t1o
-ie2t3ö2
-iet4se
+ie2t3ö6
+iet2se
i3ett
ieu2e
ie1un
i1eura
+iewa5r
i1ex
-4if
+2if
+if1an
i2f1arm
-if3au
+if1au
i3fe
i5f2en
-ifen3st
if1erg
if1erh
-ife4s
+if2fa
+if6feste
if2fl
i3fi
if3l
@@ -5692,9 +5645,9 @@ if2top
if2t3ri
ift3sp
ift3sz
-2i1g
+i1g
ig2ab
-iga3i
+iga1i
i2g1ang
ig1art
iga5s
@@ -5712,22 +5665,21 @@ ig4le
ig5lein
i4gli
ig1lu
+2igm
ig4na
i4gnä
i3g4neu
ig4no
i3g4ra
-ig4sal
-ig5sä
+ig6sal
+ig3sau
+ig3sä
ig4se
ig3so
-ig3spr
-ig3s4tei
-ig4s3to
-ig4stö
-ig3str
+ig6sti
+ig6s1to
+ig6stö
ig4stre
-ig5stu
2i1h
i2h1am
i2h1ar
@@ -5738,20 +5690,20 @@ ih3l
ih3m
ih3n
ih1r
+ih2s
i2h1um
ihu3s
ih1w
2i1i4
i2i5a4
-i3ig
i3in
i2is.
i2i5t
i1j
i1k
i4k3a4k
-ik5amt
-i4k3anl
+ik3amt
+i4kanl
i2k1ano
ik3ansa
i2k3anz
@@ -5774,17 +5726,16 @@ i3k4la
i3k4lä
ik1lö
i2k3n
-ik2o3p6
+ik2o3p4
ikot3t
ik3ra
ik3rä
ik3re
i3kri
-ik1s
ik3so
iks2p
ik3s2z
-ikt2e
+ik3t2e
ikt3erk
ik2t3r
i2kun
@@ -5796,6 +5747,7 @@ i2l1ak
i2l3a4m
il1ans
il3asp
+i3lat
i2l1au
il4aufb
il5aus
@@ -5807,9 +5759,10 @@ il3de
il4d3ent
ild2er
il2d1o
-il1e4c
+il1ec
ile2h
il1ehe
+ileid4
il1ein
i2l1el
i3len
@@ -5821,15 +5774,16 @@ il2f3l
il2f3re
ilf4s
ilg4r
-ili5en3
+ili5en
iliga2
ili4g3ab
i2l1ind
i2l1ip
i3lip.
i3lips
-il3l2a
-ill4an
+il3l4a
+il4lad
+il2leg
il3l2er
il5l2i
il2mak
@@ -5855,6 +5809,7 @@ i2manw
i2m1arm
ima2tr
ima4tur
+1imbi
i2m1ele
i2m1elf
i2m1erf
@@ -5863,21 +5818,25 @@ i2meti
im1ex
2imi
i2m1inf
+iming7
i2m1ins
+imi3te
+immei4
im4m3ent
3immo
+imni4
im1org
1impo
imp2s
im3pse
1impu
-im2str
+im4str
2imt
2imu
im3unt
2in.
2ina
-in1a4c
+in1ac
in3ad
in2af
in3a2m
@@ -5888,10 +5847,12 @@ ina4s
in3asi
inasy3
i2n3au
+inaus1
in1äs
in1äu
in3dau
in4dene
+indes4t
1index
in3do
2indr
@@ -5914,60 +5875,58 @@ in3erz
i2n1eu
ine3un
ine2x
-inf4
1info.
4inga
ing1af
in2g1a4g
-ing5sc
+ings2c
+ing7sch
+ing3ska
+ing5ste
1inhab
2inhar
2inhau
-4inhe
+2inhe
i3ni3d
2inig
in3ins
in2ir
2inis
-ini5se
i3nitz
3inkarn
-ink4ste
+ink4st
2inn.
in4n3erm
2innl
+inn6sta
1innta
2ino
in3od
in3ole
in3ols
in1or
-inos2
-ino3st
+ino5st
ino3t
i1nö
in1ö2d
2inp
2inr
-ins2
2ins.
-ins4am
-ins3än
+ins2am
insch4
in7schl
-in4seb
+in2seb
+in3sel
2insen
-ins3erg
ins3ert
in3skan
-in5spe
-in3st
3instal
in4s3tät
-in5s4tr
-in5su
+in5sto
+in3s2u
1insuf
-in6s3um
+in4s3um
+ins2z
in3sze
1integ
in3t2h
@@ -5992,16 +5951,17 @@ io2i3d
i4ok4
io3kr
i3ol.
-i5om.
-i5oms
+i3om.
+i3oms
ion4
i3on.
io3na
ional3a
io4n5au
ion5d
-i3ons3
+i3ons1
ion6sc
+ions3p
io2nu
i2ony
i2o1p
@@ -6020,7 +5980,7 @@ i2os2
i3os.
io3sh
io3sp
-io3st
+io5st
i3ot.
i3ots
i2ov
@@ -6031,7 +5991,6 @@ i3ön
i1ös.
2ip.
i1pa
-ip4an
i1pä
i1pe
ipen3
@@ -6041,13 +6000,13 @@ iph4
2i1pi
ipi3el
ipi3en
-ipi2s
ip4l
i1pr
2ips
+ip3ta
2i1pu
i1q
-i1r6a
+i1r2a
i3ra.
1irak
i3ras
@@ -6063,6 +6022,7 @@ ir2g5l
irg6s
ir2he
i1r2i
+iri3a
2irig
2irk
ir2k5l
@@ -6078,24 +6038,26 @@ ir2no
i1ro
1i2ron
iro2s
+iro5st
i1rö
irpla4
-ir4s
-ir5se
-ir5sh
-irt2st
+ir4rei
+ir2s
+ir3sh
+irt4st
i1ru
iru2s1
+i1s
i3sac
-i4s3amt
-is1an
+i4s1amt
is2ap
is3are
-i2s1au
+i2sau
is1än
2isb
i2sca
isch3ar
+is2che
i4sch3e4h
i4sch3ei
isch6er
@@ -6106,35 +6068,39 @@ i2schm
isch3ob
isch3re
isch3ru
-isch3wu
-is3chy
-i2s3cr
-2i3se
+i4schwa
+i6schwir
+i4schwo
+i4sch3wu
+is1chy
+i2s1cr
+2ise
+i3sec
ise3e
ise3ha
ise5hi
ise3il
+is1ein
ise3inf
i4seint
ise2n
ise4nal
is2end
ise1ra
-i4s1erm
+i2s1erm
iser2u
-i4s1ess
+i2s1ess
is4et
i4s5etat
-i4sex
isi2a
i2s1id
is3la
-ismu2
+is3m
i2s1of
iso2n
iso6nend
is1op
-5i2sot
+3i2sot
i2sp
is1pa
i4spar
@@ -6145,38 +6111,35 @@ i4spl
i4spo
i4spro
is3sa
-is4s1ac
+is6saa
+is4s3ac
is4sau
+is3sä
is4s3che
-is2st
+is4st
iss1tr
-i2st
-is1t2a
-is2t3ab
-is2tat
-is3tec
-i3stel
-iste4n
-is1th
-i1stil
-is1to
-is2toc
-is1tr
-is2t3re
-i3stru
-i3stü
+is2sum
+ist2a
+i4st3ab
+i4staf
+i4stam
+is2te4n
+is2ter
+is2ti
+ist3re
+is2tro
+is1trü
+i2stur
isum3p
i2sü
-i1sy
-i1ß
i2ß1ers
-ißler3
2it.
i1ta
it1ab.
it1ac
i3tak
ital1a
+ital3l
it1alt
it1am
it1ang
@@ -6189,30 +6152,33 @@ i4t1ax
2i3tä
i4t1äs
ität4
-2ite
-i2t1eig
+2i1te
+it1eig
it1ein
6i3tel
ite2n
iten3g
itens2
-iten3st
i2t1epo
-i4tex
+i2tex
it1he
i5thr
it1hu
-i3ti
+i1ti
1itia
-i4t1id
+i2t1id
1itii
iti4kan
-i4t1in
+i2t1in
+i3tis
+i3tiv
i1to
+i3to.
i5toc
i2t1of
i1tö
i1tr
+i5tra.
it3raf
it3rah
i2t3ran
@@ -6224,34 +6190,39 @@ it3ric
it3rom
i3tru
it3run
-it4s3ag
+it4s1ag
it2sä
it2s1e2
-it6s5er1
+it4s3er1
its1pe
it4staf
-its3tie
-it2sto
-it2str
-it3te
-it4teb
+it4stec
+it4s3tem
+its3tes
+it4sti
+it4sto
+it4str
+it2teb
+it4temp
itt3hä
it2tr
+i1tu
it1uh
i2t1um
i2tuns
itu5re.
it1urg
-itut6
+itut4
i1tü
i3tül
i3ty
2itz
it4z3erg
-2i1u4
+2i1u6
+ium1
ium3a
-ium1i
i3un
+ius1t
i1ü
2i1v
iv1ak
@@ -6266,6 +6237,7 @@ i3vol
i2vr
i2v1ur
2i1w
+iwa5r
iwur2
ix2em
i3xi
@@ -6287,33 +6259,28 @@ iz3th
i2z1w
í1l
2j.
-ja1c
jahr3ei
jahr4s
ja3la3
ja3ne
jani1
ja5sa
-ja3st
2jat
je2a
-jean6s
-je1c
+jean4s
je2g5
jek4ter
jekto2
jek4tr
je3na
je2p
-jes1t
+je3s
je2t
jet1a
jet3h
jet3r
-jet3st
jet5t
jet1u4
-je5v
jit3
ji2v
j2o
@@ -6323,23 +6290,20 @@ job3r
jo2i
joni1
jo1ra
-jord2
+jord4
jo2sc
jou2
jou4l
-joy3
4jö
2js
j2u
ju2bl
-juden3
jugen6
jugend5
ju2k
-jung5s4
+jung7s
jur2o
-ju2s
-jute1
+ju3te1
2j1v
4k.
1ka
@@ -6354,13 +6318,14 @@ ka1bl
2kablä
kab4le
2k3a2bo
-ka3b4r
+ka3b6r
4k3abs
2k1abt
ka1c
2kada
ka3dab
2k3adr
+ka1e
ka1f4l
ka1fr
kaf3t
@@ -6369,18 +6334,19 @@ ka1in
ka3ka
kaken4
ka1la
+2kala.
ka2lan
kal3bl
ka3lei
ka3len.
ka4lens
-kal5eri
+kal3eri
kal2ka
kal2kr
2kall
kal4tr
-3k4am
-4k5a2ma
+k2am
+k3a2ma
ka3mar
kamme2
ka4n3a4s
@@ -6399,7 +6365,6 @@ kan4th
k4anz.
ka2o
2kapf
-3kara
2karb
k1arc
k2ard
@@ -6411,14 +6376,13 @@ kari3es
kar4p3
k2ar3ta
2karti
+kar3to
karu2
k2arw
-3kas
-ka3se
+ka5se
kasi1
ka4sp
-kas3s
-ka4s1t
+ka3ta
ka3th
ka2t3r
2katt
@@ -6426,6 +6390,7 @@ kau4f1o
4kaufr
kauf4sp
2kaus
+kau5st
kau3t4
2kauto
1kä
@@ -6433,16 +6398,16 @@ kau3t4
2käh
k1ämi
kär2
-kä4s3c
+kä4s1c
kä5se
-kä1th
+kä3th
2k1b4
k5be
kbo4n
2k3c
2k3d
kdamp2
-2ke1c
+2kec
ke3d
k3eff
kefi4
@@ -6451,11 +6416,13 @@ ke2gl
ke2he.
kehr4s
kehrs3o
+ke2i
2k1eic
2k1eig
2kein
-ke1ind
+ke3ind
2k1eise
+keit4s
ke2la
kel1ac
ke3lag
@@ -6465,10 +6432,13 @@ kel3b
2k1e2lek
ke2len
2ke3let
-kel3sk
+kel3s2k
2k1emp
ken3a
4kengag
+kens2k
+ken5st
+ken7s4te
ken3sz
k2ente
k3enten
@@ -6503,11 +6473,10 @@ keu6schl
2k5f
kfi2s
2k1g4
-kge1
2k1h4
kho3m
ki3a6
-ki1c
+ki1ch
ki2d
ki3da
2k1ide
@@ -6517,6 +6486,7 @@ ki2el
kie2l3o
ki2en
kif4
+kif2a
ki1fl
ki1fr
ki3k4
@@ -6535,7 +6505,6 @@ kin3sh
ki3o
3kirc
ki5s2p
-kis2to
2kiz
ki3zi
2k5j
@@ -6592,16 +6561,15 @@ kol4k5
3kom
ko2min
ko4mu
-k2on3
-ko3n4e
-kon4i
+k2on
+kon3d
+ko3n2e
kons4
ko3nu
2kop.
ko1pe
kop4f3en
kopf5err
-kop2t
ko3r2a
4k1orc
kor6derg
@@ -6609,8 +6577,6 @@ ko3ri
kor3m
3kort
k2os
-ko3str
-3kot
ko3ta
kots2
kot3sp
@@ -6643,14 +6609,14 @@ k3reih
k3ries
2krip
k4ron
-kro3st
+kro5st
2kruf
krü1b
4ks
-ks3amt
-k2s1an
-k2s1au
-ks4än
+ks1amt
+k2san
+k2sau
+ks2än
ksch4
ks1e2b
k2s1em
@@ -6658,28 +6624,23 @@ k2sent
ks1erl
k2s1ers
k2s1erw
-ks1ex
k2s1id
k2s1in
k2s1o2
k3sof
+k5son
ks1pa
k3spe
ks2por
ks3s2
-ks2t4
+kst4
k5stab
ks3tanz
kstat4
-k1ste
-k5stei
-k6steil
-k1sti
-k2stor
-k1str
-k2strä
-k1stu
-k2stum
+k4s1tis
+k4s1tor
+k4strä
+k2s1tum
k2s1u
k1sy
ks2zen
@@ -6696,19 +6657,17 @@ kt5a4re
k5tat
k2t1au
ktä3s
-k3te
kte3en
-k4t1ei
-k4temp
-k4tent
+k2t1ei
+k2temp
+k2tent
k4t3erfo
-k4t1erh
+k2t1erh
k5ters.
-k4tex
+k2tex
k2t1h
k2t1id
-ktien3
-kt1im
+k2t1im
k2t1ing
kt1ins
k2t1of
@@ -6721,28 +6680,27 @@ k3t4ra
kt5ras
kt5rau
kt4ro
-ktro5s
kt3run
kts4
kt3se
kt3sp
-kt3st
+kt5st
kt3su
-kt3s2z
+kt3sz
kt3t2
k2tuns
kt3z
ku1c
-kuh3
+kuh5
2k1uhr
ku3la
ku3l2e
ku3l2i
-4kulp
+2kulp
2k3uml
-kum2s1
+kum2s
k2u3n2a
-kun6s4
+kun6s
kunst3
2kunt
2k1up.
@@ -6751,20 +6709,22 @@ kuri2e
kuri4er
ku2ro
kur4sp
+kur4s3t
kur4zen
ku4schl
ku2so
ku2sp
-ku2s1t
+ku5s4t
ku2su
+ku2ß
1kü
2küb
kü1bel
kü1c
-kür4s
+kür2s
2k1v
2k1w
-3kys
+kwa5re
ky3t
2k5z2
6l.
@@ -6774,11 +6734,9 @@ la3ba
4labb
4la2ben
3labi
-4l1abl
+6l1abl
3la3b2o
3l2a1b4r
-lab5re
-lab6ri
4l3abs
4labw
la1ce
@@ -6787,10 +6745,11 @@ la3den
la3d2i
l3adl
4ladm
-2l3adr
+4l3adr
5ladu
l3adv
1la1e
+laf3ta
la2ga
la3ge
lag5eis
@@ -6798,9 +6757,10 @@ la2gn
lago4
la4g1ob
la2gr
-lahn3
+lag5se
2la1ho
1lai
+lai4s1t
1laj
la3ke
la2k1i
@@ -6812,10 +6772,11 @@ la1k4l
l2a3ma
l2ami
la3min
+lam4ma
3lammf
l4amp
2l1amt
-lamt6s
+lamt4s
la4mun
la2na
la3nac
@@ -6829,13 +6790,12 @@ lan6d5erz
land5inn
lan2dr
2l1anf
-lang3s4
+lang5s2
+l1anh
4lanl
-l3anli
2l3ann
l1anp
2lans
-4lansä
4lanw
lanz1w
3lao
@@ -6848,30 +6808,37 @@ la2r1ei
la6rene
l4ar3g
lar3ini
-lar3st
2l1art
lar3th
l3arti
la3ru
-la3se
+la5se
2lash
la2so
2la4sp
5lasseri
5lassern
5lassers
-la4st
+la4sta
+la5ste
+las3tei
last1o
+la4str
+las3tur
+la4stü
+la2ß
+laß3th
lat2a
+la3te
la4tel
-2l3ath
+4l3ath
la2t3ra
lat4s
2latta
lat4tan
lat4t3in
lat4t3r
-laub6se
+laub4se
lau4fer
lau4fo
l2aufz
@@ -6879,10 +6846,10 @@ l1ausg
2l1ausl
2l1ausr
2l1auss
+lau5str
l1ausz
2lauto
2law
-lawa4
1lax
la3xa
lä1c
@@ -6891,7 +6858,7 @@ lä1c
3länd
lär2m1a
l1ärz
-lä4s3c
+lä4s1c
4lät
4läub
4läuc
@@ -6904,11 +6871,12 @@ lb3af
lb3am
lb3ang
lb3arb
-lb3b
+lb5b
l2b3ede
+lbe4n
l4b3eta
l2b3id
-l2b3ins
+l2b5ins
lb4lat
l3blä
lb3le
@@ -6916,18 +6884,14 @@ l2b5li
l3blo
lb3ohn
l4bre.
-lb5rit
+lb3rit
lb4ro
l3brü
-lbs4
-lb3sa
-lb4sk
-lb3sp
-lbs6t
+lb5sa
+lb5sp
lbst1e
-lb4sto
-lb4stu
-l2b3uf
+l2b5uf
+lb5v
4l1c
l3che
l5chi
@@ -6935,9 +6899,10 @@ lch3l
lch3r
lch3ü
lch1w
+l3co
4l1d
ld3a2b
-ld1a2ck
+ld1ack
l4d3ad
lda2g
l2d1ak
@@ -6960,6 +6925,7 @@ l3dern
l2d1erp
l2d1e4se
l2dex
+ldi2c
l2d1id
l2d1im
ldo2r
@@ -6977,14 +6943,15 @@ ld1rö
ld3sa
ld3ska
ld3sp
-ld1st
+lds2t
ld1t4
l2d1um
l2dü
1le
3le.
le3ar
-le3ba
+lea5s
+3le3ba
leben4s3
le2bl
2lec
@@ -7000,8 +6967,7 @@ le3f4a
le2g3as
le2gä
le2g5l
-le3gr
-legs4
+3le3gr
3lehr
leh3r4e
3lei.
@@ -7013,14 +6979,10 @@ l2ein.
l2eind
l2eine
l2eint
-lei2s
-lei3so
leis6s5er
l4eist
-lei3su
l2eit
lei8t7ersc
-leit3st
lekt2a
2lektr
3lela
@@ -7037,6 +6999,8 @@ le2m1o2
l2en.
le4nad
le4nä
+4lendet
+2lendu
3lene
le4n3end
4lenerg
@@ -7046,7 +7010,7 @@ le3ni
len3kl
2l1enni
l2e2no
-len3st
+len5st
len3sz
2l1ents
4lentw
@@ -7064,7 +7028,7 @@ ler5b6
4l3ereig
le4r3eim
le4rers
-l1erfo
+2l1erfo
l2erfr
l2erfü
3lergeh
@@ -7080,27 +7044,23 @@ le1ro
3l2erra
l4ers.
lers4k
-ler3ste
le2ru
le3rung
l1erz
l2erza
-les4am
les4e
2lesel
-le5ser
-le3sh
+le3ser
+le5sh
lesi1
le3s2k
-les2t
+les7sa
leste3
4lesw
2lesy
-le4sz
le2tat
2le3th
2leto
-let4tu
le2u
4leud
2leuro
@@ -7110,7 +7070,6 @@ le2u
3lexd
le5xe
le2xis
-3ley
2l1f
l3fa
l5fah
@@ -7122,8 +7081,9 @@ lf3lo
l3flu
lf3ram
lf2s
+lfs1e
lfs3tau
-lfs3tr
+lfs1tr
lf2tr
lf4u
lfur1
@@ -7133,11 +7093,14 @@ l2geti
lg3lo
lg3re
l3gro
-2l1h
+lg4sc
+lg6st
+2l1h2
l3he
3lhi.
1li
3li.
+l4ia
li1ac
li1ak
li3bi
@@ -7153,12 +7116,12 @@ liebe4s
lie2n
li3ene
li5enp
-lie4s3c
-lie2st
+lie4s1c
li3fa
li4fe
5lig
li3g4n
+lig3s2
li3ke
li3ki
li3kli
@@ -7181,7 +7144,7 @@ li4neh
li2nep
li4nes
2l1inf
-ling4s
+ling6s
2l1inh
li5ni
2l1i6nit
@@ -7195,7 +7158,8 @@ l2insc
l1inv
4linz
li2o
-li2p3a
+lion5s
+li2p5a
5lipt
3lis.
li3s2a
@@ -7204,15 +7168,13 @@ li4schu
2l1isl
2l1i2so
liss4
-3list
li2tal
li3te
li1t2h
lits2
-lit3st
+lit5st
lit3sz
-li3tu
-li4tur
+li2tur
3liu
2lixi
li2za
@@ -7220,13 +7182,11 @@ lizei5
4l3j
2l1k
lk1alp
-l3k2an
+l3k4an
l3kar.
lk1arm
-l3ke
lken3t
l2kep
-lkir5
lk3lo
l3k6lu
lk3nu
@@ -7234,31 +7194,33 @@ lkor2b1
l3k4ra
lk3ro
l2k3ru
-lk2s3
-lk3sä
-lk4stä
+lk4s1
+lk5sä
+lk5ste
l3k2ü
lkü1b
-4l1l
+2l1l
ll1abb
ll1abe
-ll3aben
+ll5aben
ll1abt
l3labu
ll1aff
ll1akt
l3l2al
-l2l3a4m
+l4l3a4m
l2l3anz
l3lap
ll1arm
-ll3art
-ll1au
+l4l3art
+l2l1au
+ll4aufe
ll3aug
-l2l3aus
+l4l3aus
l2l1äm
llb4
ll3d
+l2leb
l3lec
ll1ech
l2l1ef
@@ -7266,38 +7228,34 @@ ll1eim
llei4ne
l3l2em
l3len.
-lle4n1a
+lle6n1a
ll3endl
ll3endu
llen3g
l3ler.
lle2r3a
-l3lere
l4l3ergo
ll3ernt
l2lerz
ll2es
llg4
-ll1imb
+l6lieg
ll1imp
l2l1ind
lli5ne
l2l1ins
-ll3l4
ll5m
-l2l1ob6
+l2l1ob
l2l1of
ll1opf
l2l1o2r
l2l3ou
ll1ov
-l3low
l4l1öf
-ll3ö2se
+ll3ö6se
ll3sh
ll3s2k
-ll3sp
-ll4spr
+ll4s3tor
llt4
ll3th
llti2m
@@ -7306,9 +7264,8 @@ llt5s2
ll1ur
l3lus
llust6
-llus5tr
ll3z2
-2l1m
+4l1m
lm3a2b
lm1aka
l2m1arc
@@ -7323,8 +7280,6 @@ lm1orc
l2möl
lm3p
lmpf4
-lm1s2t
-lm3ste
lm3sz
lm3th
4ln
@@ -7340,7 +7295,7 @@ l1nü
2lobj
2lo2bl
l2obr
-lo3bri
+lo3b4ri
lof4
4l1o2fe
lo1fl
@@ -7352,8 +7307,8 @@ lo2k3r
lol2a
l3oly
lo2min
+l4on
lo4n1o
-lon3st
lo2o
2lope
2lopf
@@ -7368,10 +7323,12 @@ lo3ro
3los.
lo4sa
3lose
-los5se
+los3se
lost4
-lo4ste
-los1tr
+lo4steu
+lo4s3to
+lo4s3tr
+lo2ßu
lo2ta
lo3th
loti4o
@@ -7385,7 +7342,6 @@ lö3du
l3öhr
2l1öl
5lösc
-5lösu
4löß
2l1p
lpe2n3
@@ -7398,28 +7354,29 @@ lp3t4
lque3r
2l5r2
lrat6s
+lro3m
lru3t2
lrü1b
-4ls
-l3sac
+4l1s
+l3s2ac
l2s3a2d
-l5s2al
-l4s3amb
-ls3amp
-ls1anf
-ls1ang
-l2s1ann
+l7s2al
+l4s1amb
+l2sann
l3sare
-l2s1au2
+l2sau2
l4schin
+l5se.
l2s1e2b
ls1ec
+ls1ein
l2s1em
ls3ere
ls1erg
ls1erl
l2s1ers
l2s1erw
+l5ses
l3sex
l4sha
lsho2
@@ -7429,66 +7386,66 @@ ls3ohne
l4s3ort.
ls2pi
l3s2po
-l3spri
l3s2pu
ls3s2
lst2a
l5s2taf
ls3täti
-l1stec
l5stei
l5stel
-l5steu
-l1sti
-ls2tie
-l2stit
-ls2tol
-l1s2tr
-l1s2tu
+l5ster
+l4s1tis
+l4stit
ls1um
l3sur
-l1sy
+l3sus
ls2zen
-4l1t
+6l1t
lt1ac
lt1ak
lt1am
-l4tame
+l3tami
+l3tan.
lt3and
lt1ang
l3tar
lt1art
+l3tas
l3tat
l4t3ato
lt1au
+l3te.
l5tef
lt1eh
lt1ein
l2t1eis
lte5lei
-lt2en
+l3t2en
+l5ten.
lter3a
l3t4erg
lt2erö
lter4sp
-l4t3es3k
-lte3str
+l2t3esk
+lte5str
+l3tet.
lt3e2th
-lt1eu
+l2t1eu
l2t1h
l4t5hei
l3thu
-l3ti
ltimo4
l2tob
l3toc
lt1of
+l3ton
l2t1op
l2t1o2ri
lto3we
lt1öl
lt1ös
lt3öt
+lt4rak
ltra1l
l3trä
lt3räu
@@ -7499,10 +7456,11 @@ lt3ros
l2t3rö
lt5sc
lt2se
+lts1ei
lt3spa
lt3spr
-lt4spre
lt4stab
+lt5ste
lt4stoc
lt3t
lt1uh
@@ -7537,7 +7495,6 @@ lu2go
lu2g3r
lug3sa
lug3sp
-lugs4t
lu2gu
2l1uh
lu1id.
@@ -7561,33 +7518,33 @@ l1urn
l1urt
2luse
lu2sp
-lus4s3a
-lus2s3c
+lus4sä
lus4ser
+lus4si
lus2s1o
-lus4s3p
-lus4st
-5lu4st
-lus2t3a
+lus2s3p
+lus6st
+lus8suc
+5lus2t
+lu4st3a
+lu6stä
lust3re
lu2s1u
+lu2ß1
lu2t1a
-lu2tä
lut3erg
-lu5terk
lut1o2f
lu2top
-lu4t5r
+lu2t5r
3lux
2lüb
5lüd
lüh1l
-lü2s
2l1v
-l3vo
l2vr
2l3w
l5wa
+lwa5re
1ly
ly1ar
ly3c
@@ -7607,6 +7564,7 @@ l2zö
lzt2
lz3th
l2z1u4fe
+lzug4s
l2z1w
lz2wec
6m.
@@ -7623,6 +7581,7 @@ ma3da
ma3de
ma4d2s
ma1e
+ma2es
ma1f
2m1agg
magi5er.
@@ -7633,7 +7592,7 @@ ma5g6n
ma3ha
mah4ler
mah3li
-mai6se
+mai4se
2m1akt
ma1la
ma2l1ak
@@ -7645,7 +7604,7 @@ mal3d
mali3er
mal3lo
2mallt
-malu4
+malu2
ma2l3ut
mam3m
2m1anal
@@ -7659,13 +7618,14 @@ man3ers
ma2net
mang2
2mangr
-m2anh
2manl
m4ann
+2mans
+2mantw
manu3
2manz
ma2or
-5m4app
+m4app
2m1arb
mar3g2
ma3ri
@@ -7678,15 +7638,15 @@ mar5te
ma3ru
3m4as
ma3s2p
-ma3sto
-ma1s2tr
+mas4t
3maß
m4at
ma2tan
ma2tä
mat4c
-ma4tel
+ma2tel
ma4t3erd
+mats2
mat3se
mat3sp
3maue
@@ -7703,12 +7663,11 @@ mä1i2
m1ärg
mät4
mä1tr
-mäu4s3c
+mäu4s1c
2m1b4
mb2a
mbe2e
-mbe4n
-m3b6r
+m3br
2m3c
2m1d
md1ar
@@ -7721,7 +7680,7 @@ mdu3s
meb6
me1c
medi3
-medi5e4
+medi5e6
medien3
2medy
me1ef
@@ -7731,14 +7690,13 @@ mega5
2m1eif
m2eil
me1i2so
-3meist
+m2eist
2mej
me3lant
3meld
me2lek
-melet4
+melet2
2m1elf.
-mell2
melt4
6m5eltern
mel3tr
@@ -7750,13 +7708,10 @@ men3au
m3endl
men3gl
me3nor
-men4s3k
-men4so
-men3st
+men4sk
+men2so
men3ta
-men6tanz
4m3entn
-ment6sc
4mentw
me1o
2me3ou
@@ -7774,15 +7729,18 @@ mer2kl
me3run
mer3z4en
3mes
-me2s1a
+me2s3a
me2sä
mes2e
-4me3sh
+4me5sh
4mes2sa
+mes6sig
mes2s1o
mess1p
meste2
+me4str
4mesu
+3me2ß1
me3t4a
mete2
me3th
@@ -7792,14 +7750,13 @@ meu1
2m3f
mfi4l
4m1g2
-mge1
2m1h
1mi
3mi.
mi1ak
mi3an
mibi3e
-mi1c
+mi1ch
mi3da
mie3dr
mi2e1i
@@ -7816,45 +7773,45 @@ min5de
min2e
mi3neu
min2ga
-mings4
-ming3st
mi3ni
mi3n2o
3miri
3mirs
-mir5sc
+mir3sc
3mirw
mi2sa
mise1
mi3sp
-mis2s3c
-mi4ste
+mis2s1c
+mis6st
+mi2ß1
3mi2t1
+mi3te.
mit3es
mit3h
-mit3s4
-mit5sa
+mi3ti
+mit5s2
mi5tsu
4mitz
2m1j
-2m1k4
+6m1k4
m3ka
mk5re.
-2m1l
+6m1l
m3la
m3le
m5li
mlö3
-2m1m
+4m1m
mma4ge.
m2m1ak
m2m1al
m2m1ang
-m2m1ans
+mm1ans
mm1anz
-mma3s4t
m2m1au
m2m1ei
+mmeis3t
mme4lin
mme4na
mme2ra
@@ -7866,9 +7823,9 @@ mm1inh
mm1ins
mm1int
mmi3sc
-mmi3s2t
-mm3m2
mm3p
+mm2s2
+mm3si
mm3sp
m2m3um
mmül2
@@ -7880,7 +7837,7 @@ mo4a3
2mobj
3mod
mo2dr
-4mog.
+2mog.
mo2gal
3moh
mo2i
@@ -7892,8 +7849,7 @@ mo5m4e
m2on
mo3ne
mo4n1er
-mons1
-mon5su
+mon3su
3mo2o
2mo1pe
mo2per
@@ -7902,11 +7858,8 @@ mo1r4a
mor5ar
2morc
mor4d3a
-morgens6
mo4sk
mo3sp
-mo5s2ta
-mo3to
m1o2x
mo1y
1mö
@@ -7926,35 +7879,32 @@ mp3lu
mp3ta
2m1q
4m3r
-4ms
+4m1s
msa3l
-m2s1an
+m2san
ms3and
m4sap
ms3as
-m2s1au
-m3se
-m4s1ef
+m5sat
+m2sau
+m3sc
+m5sche
+m4sco
+m2s1ef
+ms1erf
ms1erw
-m4s1ex
ms1ini
mso2r
ms1ori
m2spä
ms2po
ms3s2
-m6stag
-m2stal
-ms2tau
-m1stec
-m1s2ti
-ms2to
-m1s2tr
-m2strä
-m1s2tu
-m3s2tü
+m4stal
+m4strä
+m3stu
ms1um
m2sü
+m3süc
m3sy
ms2ze
4m1t
@@ -7969,26 +7919,24 @@ m2t1erf
m2t1erg
m2t1erl
m2t1ers
-m4t1ert
-m4t3eta
-mt1eu
+m2t1ert
+m2t3eta
+m2t1eu
m2t1h
mt5ho
-m3ti
-m4t1im
-m4t1ins
+m2t1im
+m2t1ins
mt1int
mti2s
mt1ös
mt2s
mt3sc
-mt5sco
+mt7sco
mts1e
mt3s2ka
mts1p
mt3spa
mt3st
-mts3ti
mt3t
mt1um
mtu3re
@@ -7996,7 +7944,6 @@ mt1urt
mt3z2
1m2u
mu1a
-mu3cke
2m3uh
mu3la
2muls
@@ -8009,17 +7956,19 @@ mu3ne
4m3ungeb
m4unk
mu3no
-mu3ra
mur3ma
mu3ru2
mu4r1uf
-mu4s3a
+mu4s1a
mu2s1o
mu2sp
-mu2s1t
+mus4st
+mu6s1to
+mu4str
mu2su
-mut1au
-mut2s3
+mu2t1au
+mut4s3
+mut5sc
1mü
2müb
3mün
@@ -8027,12 +7976,11 @@ mut2s3
2m1v
mvol2l1
2m1w2
-mwa4
mwel4
-1my
-my4s3
-my3t
+1my3
+my4an
2m1z
+mzug4
6n.
1na
5na.
@@ -8042,10 +7990,8 @@ na3ber
4nabw
na2c
nach1
-na3chen
nachs2
5nachw
-na3cke
4n3add
4n3adr
na1e
@@ -8085,23 +8031,22 @@ n4am.
5nami
na3m4n
3namo
-n3amp
-nam4sp
-4n3amt
-namt6s
+nam2s
+2n3amt
+namt4s
n1an
-4nan.
4na2na
4n3anb
n2anc
4n3ang4
4nani
4nank
-4n3anl
+4nanl
+5nann
na3no
-4n3anr
-4n3ans
-4n3antr
+4nanr
+2n3ans
+4nantr
2n3anw
n1ar
5n4ar.
@@ -8117,16 +8062,17 @@ na3ru
3nas
na4schw
4n3asp
-na5sta
4nasy
+nasyl2
+3naß
3nat
5nat.
5nate
na3t2h
-5nats1
+5nats
nat4sa
-nat6sc
-nat3st
+nat6s3c
+nat5st
4natt
n1au
4nauf
@@ -8140,7 +8086,7 @@ nau3sc
n3ausl
4n3auss
4n3ausw
-nau5te
+nau3te
navi5er.
navi5ers
1nä
@@ -8150,14 +8096,17 @@ n2äc
n1ähn
2n1ä2m
2n3än
-när4s1
+näng5
n1ärz
-2näs
+2nä2s
nä4sc
+3näß
2näu
5nä1um
-4n7b6
+4n7b4
+nbau3sc
nbe2in
+nbe5n
nber2e
4n1c
nc5ab
@@ -8167,9 +8116,8 @@ n3ces.
n3che
nch3m
n3chu
-n2ck
n5cu
-4n1d
+6n1d
nd1ab
n3daf
nd2ag
@@ -8182,26 +8130,22 @@ nd1arb
nd3arr
nda3ru
n2d1au
-n3de.
nde4al.
nde3alt
nd1ei
nd3ei.
ndel4st
-n3den.
n4d3ents
nde3o
n5der.
n5deri
nde4rob
-nder5ste
-nde4s
+n3de4s
ndes1e
-ndo1c
+ndni4
n3dol
nd1op
n2d1or
-ndo3st
nd3rat
nd3räu
n2d3re
@@ -8214,8 +8158,8 @@ n4d5run
nd2sor
nd2spr
nds3tau
-nd3te
-nd1th
+nd5ste
+nd2sum
nd1t4r
n2dum
nd2ums
@@ -8233,9 +8177,8 @@ ne2bl
2n1ebn
2nec
3neca
-4nech
-2ne2e1
-nee3i4
+2ne2e
+nee1i4
ne3ein
ne3en
nee3t
@@ -8251,7 +8194,6 @@ n3ehe
n2eid
6neif
3neigt
-5neigu
4nein
6n3eing
6n3eink
@@ -8289,10 +8231,10 @@ nen3ei
ne4nene
ne2ni
nen3k
-5nenn
ne2no
-nen7s4e
+nen5s4e
nen3sk
+nen5st
5n2en5t2a
n1entb
4n3entl
@@ -8316,7 +8258,7 @@ ne2r3ap
ne2rau
4n3erbi
2n1erf
-4n3erfo
+6n3erfo
nerfor4
4n3erfü
n1erg
@@ -8327,6 +8269,7 @@ n1erk
n3ermä
ner4mit
2nermo
+3nern.
4n3ernt
ne1rös
n2ers.
@@ -8335,12 +8278,13 @@ ner8schle
3n4ert.
4n3ertr
ne2rup
+n2erv
4n1erz
3n2es
n4es.
ne3san
ne2sä
-nes4c
+nes2c
nesi1e
nes2k
ne3ska
@@ -8348,8 +8292,7 @@ ne2s1o
ne2s1p
4n3essi
5nest
-ne2ste
-nes3ti
+nes3tei
net1ak
net1an
ne2tap
@@ -8358,7 +8301,6 @@ net1au
ne2th
net3ha
ne2tre
-nett6sc
2n3e2tu
net2zi
ne2u
@@ -8376,8 +8318,7 @@ nfi3le
nf3läd
nf3lin
n3f2o
-nfo3s
-nf3st
+nf4r
nft2o
nft4s3
4ng
@@ -8408,11 +8349,10 @@ ng5ho
ng5hu
n2g1i2d
ng4lad
-n3gläs
ng3lein
ng3lo
ng3lu
-ng5m
+n4g5m
ng3ne
n2g1or
ng3rat
@@ -8420,11 +8360,11 @@ ng3räu
ng3rein
ng3rev
ng3roc
-ng4sau
-ng4s3c
-ng4s3e4h
-ng5stel
-ng5stö
+ng4s
+ng6s1c
+ngs3e4h
+ng3send
+ngs3pa
ng3ts
n2gue
n2gum
@@ -8444,7 +8384,7 @@ nib3b
ni3de.
ni3di
ni3dr
-n4ie
+n2ie
nie3b
nie3fr
ni1el
@@ -8458,7 +8398,6 @@ nifi3
nig2a
4n3i2gel
ni2g3r
-nig4sp
3nik
nik1al
ni2kä
@@ -8469,11 +8408,11 @@ ni2kr
n2imm
nim2o
4n3imp
-3n4in.
+3nin.
nin2a
4n3ind
2ninf
-3n2ing4
+3n2ing6
4n3inh
nin1i
4n1ins
@@ -8484,25 +8423,28 @@ ni2ob
ni5ok
ni3ol
ni3os
-3n4is
+3n2is
ni4schw
-ni4s1e
-ni5se.
+nis1e
niso2
nis1p
-nis3s2
-nis3tr
+nis5s2
+nis3sz
+ni2stu
ni2s1u
2nit
+ni3ta
ni1th
-ni4ti
+ni2ti
+ni3to
ni3t4r
nit2s
ni3tsc
-nitt4sa
+nit4tec
+nitt6sa
ni3tu
3niu
-3niv
+3ni3v
3nix
2n1j
4n1k
@@ -8514,10 +8456,10 @@ nk1apf
nk1arb
nk1arm
nk3arti
-nk1aus
+nk1au6s
nk1äh
n2k1är
-nk1e2c
+nk1ec
nk1ein
n4k3erfa
nk1inh
@@ -8541,10 +8483,10 @@ n4kre.
nk3rede
n3kri
nk3ro
-nk2s1al
-nks2ei
+nk2sal
nk2spa
nk3spo
+nk5sti
nk3s2z
nk2ta
nk3ti
@@ -8572,18 +8514,14 @@ n4n3er4wa
nn3er2z
nne2s
nnes1e
-nne4st
n5neu
nn3f
nn3g
n3ni
-nnis3t
nno3b
nn1o2r
-nn5sc
+nn5se
nn3s2p
-nn3ste
-nns2tr
nn4th
n4n1uf
n2n1unf
@@ -8599,13 +8537,12 @@ no1c
no3dr
2n1of
4n3o2fe
-n4oi
2nole
no2leu
+n4om
nom4e
n2on.
no3n4a
-non3s
3n2opa
2nopt
2nor
@@ -8621,14 +8558,14 @@ n1ort
3n2os.
no5se
no3sh
-3n2o3ste
+3n2oste
n1osth
-no3st4r
+nost4r
no5tab
no2tä
no4t1ei
-no4t1el
-no4t3in
+no2t1el
+no2t3in
no2t1op
no2tr
3nov
@@ -8640,25 +8577,16 @@ n1ök
4n1öl
4n5p2
npa4g
-npir5
-npro3
npsy3
2n1q
4n3r2
nre3sz
-nrö4s3
+nrö4s1
n5ru
4n1s
-ns3ab
n2s3a2d
-ns3ak
-n2s1all
-ns1an
+n2sall
n3sand
-ns3ans
-ns3art
-ns1au
-ns3auf
n2s1än
n2s1äus
n5sche.
@@ -8668,81 +8596,61 @@ n6schlic
n5schr
n6schro
nsch7werd
-n3se
ns1e2b
-ns3ebe
+n3sec
ns1e2d
nseh5ere
nseh3i
-n5senk
+n3senk
nsen4sp
-n4s1ent
-n4s1ep
+n2s1ent
+n2s1ep
ns1erf
-n4s1erg
-ns3erh
-n4s1erk
-n4s1erö
-n4s1ers
-n4s3erw
-n4s1erz
+n2s1erg
+n2s1erk
+n2s1erö
+n2s1ers
+n2s1erw
+n2s1erz
nse2t
n4s1eta
-ns3h
+n3sex
nsho2f
-n3sil
n2simp
n2s1ini
-ns3int
-nsi4te
+nsi2te
ns2kal
-ns3ko
-ns3ku
-ns3ky
-ns3l
-n3so
-ns3ob
-n4s1op
+n2s1op
n4s3ort.
-ns3park
+n2spat
ns4pei
-n3s4pek
-ns3ph
+n3spek
ns2pi
n2sprä
n4s3prie
n4spro
-nsrü2
ns3s2
nst1ak
-n3star
-n4s3tate
-ns2tau
-n2ste
-n3stei
+n6stat.
+n6s3tate
+n4stau
+n5s2te.
+n4stech
nst3eif
-n3stel
-n4stem
-n5stemm
-ns4tent
-n3step
-n5s6terbe
-n5s6terne
-n5s6terns
+n5stel
+ns4tem.
+n5s4ten.
+n4stent
+ns2ter
+n5s4tes.
n5steu
-ns2tie
-ns2to
+n4stor
n4strac
-n4strie
-ns2tu
nst4ü
nstü1b
-n4sty
-n3su
ns2um
-n4s1un
+n2s1un
ns2unr
-n3sy
ns3zi
4n1t
nt3abs
@@ -8788,35 +8696,33 @@ nt1ho
n3thol
n5thr
n5t4hu
-n3ti
-nti3c
nti3k4l
-n4tinf
-n4t1inh
+n2tinf
+n2t1inh
ntini1
-n5ti1t
+n5tit
ntmo2
n5to
nto5me
nton4s1
-ntons3c
n3tö
nt3rec
n5tree
nt3reif
n5t4rep
+nt4rig
n2t3rin
n5trop
n2t3rü
-n4ts
nt3sa
nt3s2o
nt3s2p
nt4s3par
-nt2sto
+nts2t
+nt4sto
nt3t
n3tu
-ntum4
+ntum2
nt3z2
1nu
nu1a
@@ -8824,7 +8730,7 @@ nu4ale
nu3ar
nu3as
nubi3
-2nu1c
+2nuc
3nue
nu2es
nu3et
@@ -8854,8 +8760,10 @@ nu3sc
nu3se
nu3sl
nu3spo
+nu6s1t
+nu2ß
nu2ta
-nu5te
+nu3te
nu2t3r
5nü.
2nü2b
@@ -8865,8 +8773,11 @@ nür1c
4n1v2
n3ver
n3vi
+nvol7ler
4n1w
n3wa
+nwa5re
+2nx
1ny.
1nyh
2nymu
@@ -8875,9 +8786,9 @@ n1yo
1nys
1nyw
4n1z
+nza2
n2zad
-n2z1a2g
-nz3am
+n2z1ag
n2zan
n2z1ar
n2z1au
@@ -8888,10 +8799,12 @@ n4zense
n4zentz
nz3erwe
nzi2ga
+n2zinh
nz1ini
nz1of
n2z1or
nz3th
+nzug4
n2z1wa
n2z1wä
nz1wer
@@ -8911,15 +8824,16 @@ oa3de
o4ah
o4a3i
oa3ke
-oa4k5l
+oak5l
o4a3la
o4a3mi
oanne4
o4ar
-o4as
-3oa3se
-o5asi
+o4a3s
+3oase
+o5a4si
o4at
+oa3te
o1b
ob2al
o3bar
@@ -8929,7 +8843,7 @@ ob2e
2o3be.
ob3ein
2oben
-oben5se
+oben3se
o2ber
obe4ris
obe6sp
@@ -8941,17 +8855,16 @@ o2b5li
1obm
2obo
o2b3re
-ob6ris
-ob2s
-ob3s2h
+ob2s2
+ob3sh
ob3sk
ob3so
-ob3s2p
-ob3str
+ob3sp
+ob4sta
+ob3sü
2o3bu
2o3bü
2oc
-o3ca
o1ce
och1a
ocha2b
@@ -8970,13 +8883,10 @@ och3to
o1chu
ochu2f
och3w
-o3ci
-o1ck
-o2ckar
-o3ck2e
-o3cki
+ock2e
ock3sz
-o3cr
+o3co
+o1cr
o1ç
2o1d
o3dar
@@ -9001,7 +8911,7 @@ o3et.
o3ets
o1ë
2ofa
-of1a2c
+of1ac
of1am
of1au
o2f1ei
@@ -9010,8 +8920,10 @@ o3fer
ofes3
of2f1a
of2f1in
+of2fir
1offiz
of2f3l
+of2fo
of2f3r
offs2
of2fu
@@ -9023,15 +8935,14 @@ of1la
o1f1r
of3ra
of3rä
-of2s
-of4s3a
-of3sä
-of3st
-ofs1u
+of4s1a
+of2se
+of2sp
+of2s1u
2oft
of2tei
of3th
-4o1g
+2o1g
o2g1ab
oga3d
og1ala
@@ -9046,8 +8957,10 @@ og3ins
o2gl
o3glo
o3g6n
-ogs4
-og3sp
+ogoi5
+og4s2
+og5sp
+og5ste
o1ha
o1hä
o1he
@@ -9072,10 +8985,9 @@ ohl3erh
oh5les
oh3li
oh3lo
-ohls2e
+ohls2
oh2lu
oh3m
-2ohn
ohn3a
oh2ni
oh2n1o
@@ -9085,10 +8997,10 @@ oh1o2p
o2h1ö
ohr1a
oh4rin
-oh1s
oh3ta
o1hu
oh1w
+ohwa5
2o1hy
2oi
o1i2d
@@ -9100,8 +9012,9 @@ o4i3ne
oi4r
o2isc
o3isch.
+oi5se
o1ism
-oi1th
+oi4st
2o1j
2o1k
oka3i
@@ -9112,22 +9025,18 @@ o3ki
oki4o
ok3lau
ok3lä
-okna3
ok2s1p
-ok3t4
+okt4
2ol
o1la
o2l1ak
ol2ar
ol1auf
o1lä
-4olc
ol4dam
ol4d5r
-oldwa5s
ol1eie
ol1eis
-ole3s
ol1ex
o1lé
ol4fa
@@ -9139,17 +9048,19 @@ olge4ne
ol2gl
ol2gr
ol2i
-olib6
oli5en
oli5f
-oli5tu
+oli3tu
ol2kl
ol2k3r
+ol2lad
ol2lak
-ol2lau
-ol4l1e2c
+oll3ans
+ol2las
+ol2läd
+ol4l1ec
ol2l1ei
-oll1el
+ol2l1el
oll5ends
ol4l3erk
oll5erwe
@@ -9162,17 +9073,17 @@ olo3p2
ol1ort
o1lö
ol2pr
-ol2str
+ols2
+ol4str
o1lu
ol2z1a
ol6z3ern
ol2zin
-4om
+2om
oma4ner
om2anw
om1art
o2m1au
-o3me.
o2meb
ome3c
o2m1ei
@@ -9184,10 +9095,12 @@ o2mep
o2meru
om1erz
omie4t1
+omil3l
o2m1ind
om1ing
o3mini
om1int
+omi3te
om3ma
om3me
omme4r
@@ -9196,7 +9109,6 @@ om3pf
omp6l
oms2
om3sp
-om1st
o4m3un
o5m4ung
omy1
@@ -9208,24 +9120,22 @@ o3nal
on3ap
o2n3ar
on4are
-on4at
on3aus
2o3nä
onbe3
2onc
2one
on4eh
-on4e2n1
+one2n1
onen3g
-onens2
o2n1erb
on1erd
on1erö
o3nett
on5f
-4ong4
+ong4
on3gl
-ong5sc
+ong7sc
ong5st
4o3ni
o5ni.
@@ -9234,22 +9144,20 @@ o4ni4kr
o4n1im
on3ing
on5k4
-onli4
+onli4n
onlo2c
on3nan
o3no3
o4noke
on1orc
-on4os
-on2s
-ons3a2
-on3sch
-on4seb
+ons1a2
+ons3as
+on2seb
onse2l
-onsi2
+onsi2d
+ons3l
ons1p
-ont2a
-ont3ant
+on3t2a
on6t5end
ont5erw
on2t1ri
@@ -9258,7 +9166,6 @@ on5v
1ony
on5z
o1ñ
-oof4
oo2k
ook3l
o1op
@@ -9266,13 +9173,12 @@ o1or
oor3f
oo4sk
oo2tr
-oot2st
+oot4st
2o1ö
o1pa
opa1b4
o2p3ad
op1akt
-opa5st
o1pä
o1ped
o1pei
@@ -9319,7 +9225,7 @@ o2ranh
orani1
or3arb
o1ras
-or3au
+or3att
o3r2ä
or3änd
or3ät
@@ -9327,7 +9233,7 @@ or2bar
or1c
2orca
or2ce
-4or2da
+2or2da
ord1am
ord3ele
or4d3eng
@@ -9336,11 +9242,10 @@ or2d1ir
1ordn
or2do
2ords
-ord3s2t
2ordw
4ore
ore4a
-o2r1e2ck
+o2r1eck
o5ree
o2r1ef
ore2h
@@ -9350,7 +9255,7 @@ o2r1er
or3eth
2orf
or2fle
-or3ga
+or3g4a
2orget
or3g2h
2orgia
@@ -9360,18 +9265,18 @@ or3gle
o1ri
2o3ric
o3rier
-4oril
+4o5ril
4orin
or1ins
2orit
+o5riz
or3k2a
or4k3ar
-ork2s
+ork1s
2orm
or2mor
or3na
or3n2o
-orn3st
2o1ro
or3oly
oro3n4a
@@ -9379,25 +9284,24 @@ oro3n4a
2orq
2orr
or3rh
-2ors2
+2ors4
or5sa
-ors4c
orsch5li
or3sh
or3sz
or2ta
or3tad
or4t1ak
-or4t3an
+ort3an
ort1au
ort3eig
ort3ein
-or4tem
or4t3ent
or4t3ere
or4t3erf
or4t5ev
or4the
+or3ti
or4tin
ort3ins
or4t3off
@@ -9406,7 +9310,7 @@ or4t3rau
or4t3räu
ort3re
ort3ric
-ort5sch
+ort3sc
or2t1um
o3ru
or2uf
@@ -9415,15 +9319,16 @@ o5rus
or3ü
2orw
o2rya
+o1s
o3s2a
os3ad
os4an
-osa3s
-os4co
-2o3se
+os2c
+2o3s2e
ose3ei
-o4s1ei
+o4s3ei
ose2n
+o2sé
o3s2hi
o3sho
2osi
@@ -9437,38 +9342,38 @@ os2lo
o2s1p
o4sper
o3s2po
-os2sa
-oss3and
-os4sä
-os5se.
-os4sei
+os2s3a
+os2sä
+os2seg
+os2sei
oss3enk
-os5sent
+os3sent
oss3enz
+os2seu
os4s3o
os4s3p
-os4st
+os6st
oss1ta
+oss1to
oss1tr
-o2st
-os4t1a
-os5ta.
+os2t
+o4s4t1a
osta2b
-os5tali
-os5tarr
-os2tau
+o5stal.
+o4sterd
oster3e
-os6t5er6we
-ost1h
-os3til
-os1to
-os2t1ob
-ost3rä
+ost5er6we
+ost3h
+o5stie
+o4stin
+ost1ob
+os3ton.
+o5stons
+o4st3rä
ost3re
ost3rot
ost1uf
osu4
-o1sy
o3s2ze
o2ß1el
o2ß1enk
@@ -9476,28 +9381,30 @@ o2ß1enz
oße2r
o2ß3ere
o2ß1erf
+oß3th
2o1t
ota3m
o3tark
o2t1au
ot3aug
+otau6s
ot1är
-4o3te
-o4teb
-ote1i
+4ote
+o2teb
+o3te1i
ote3i6n
ote4l1a
ot4em3
otemp2
-o4t1erw
+o2t1erw
4oth
ot2he
ot3hel
o4t1hi
ot1hos
o4thr
-o3t2i
-o4t3i2m
+ot2i
+o2t3i2m
o4tl
otli4
4oto
@@ -9510,7 +9417,9 @@ ot3rut
ots1p
ot4spa
ot3spe
-ot3stra
+ots2t
+ot5stra
+ots3tri
ot2tau
ot3te
ot4t3erk
@@ -9527,19 +9436,22 @@ o3uh
ou4le.
o3um
o3unds
+oung5
oun4ge.
-ouri4
+oung7s2
+ouri4e
our6ne.
-our3st
ou3s2i
+ou5s2t
+ou3te
outu4
2o1ü
o1v
-ove3s
oviso3
2o3vo
2ow
o1wa
+owa5re
o1wä
o1we
o3wec
@@ -9553,8 +9465,6 @@ o1xo
o2xu
1oxy
o1yo
-oys2
-oy3st
2o1z2
oz4e
o3zi
@@ -9564,14 +9474,15 @@ ozon3a
öbe4li
ö2ble
ö2b3r
-öb2s5
-2ö1c
+2öc
+ö1ch
ö4ch3l
ö2chr
-öch2s
-öchs4tu
-öcht4
+öchs2t
+öch4str
+ö4cht4
ö1d
+ödel5l
ödi3en
ö2du
ö1e
@@ -9588,11 +9499,13 @@ ozon3a
öh3l2e
öh3m
öh1ri
+öh2s
ö1hu
ö2k
ö3ke
-öko3
+öko5
ök3r
+ök2s
ö6l
3öl.
öl1a
@@ -9603,25 +9516,24 @@ ozon3a
öl1im
öl1in
öl2k5l
-öl3la
+öl5la
öl4nar
öl1o2
+öls2
öl3sa
-öl3s2z
+öl3sz
öl1u
öl2ung
öl3z2w
+öm2s
2ön
ön3d
ön2e
ö3ni
-ön2s
-ön3sc
öo1
ö1pe
öpf3l
-öp2s3t
-ör3a2
+ör3a
ör1c
örden3
ör2dr
@@ -9638,22 +9550,22 @@ ozon3a
ör1o2
örs2e
ör3sk
-ör2st
ör2tr
ö1ru6
ö2r1une
+ö1s
ö2sa
ö2sc
ö4sch3ei
ösch3m
-2öse
-ö2s1ei
+2ö5se
+ö6s1ei
ö2sp
-ös4s3c
-ös2st
-ö2st
-ös3te
-ös1tr
+ös4s1c
+ös4st
+ös2t
+ö4sta
+ö5stet
ö1ß
2ö1t
ö2t3a
@@ -9666,7 +9578,7 @@ ozon3a
öwe4
ö1z
öze3
-özes2
+özes4
4p.
1pa.
1paa
@@ -9678,12 +9590,13 @@ pa3g2
pa1ho
1pak
pa1kl
+pak2to
1pa1la
pala3t
1palä
pa5li
2palt
-p2an
+p4an
pa2nar
pan3d
pan4ds
@@ -9692,15 +9605,13 @@ pa2neu
pan3k4
2panl
3pano
-pans4
pan3sl
3panz4
-3pap
+1pap
papie8r7end
-3parad
+1parad
pa2r3af
par3akt
-pa5reg
2par2er
2parg
1park.
@@ -9714,14 +9625,8 @@ pa2ro
1partn
1party
par3z2
-pa4s
-pa5sa
-pa5sc
-pa5se
-pa5si
-pa5s2p
-pa5str
-2paß
+pa3s2p
+pa2ßu
p4at
pa5ta
pat4c
@@ -9731,29 +9636,27 @@ pat2e2
1pau3
p1auf
pa3uni
-pau4st
-pä2
1päc
-pä3cke
1päd
-pä3de
1pärc
-pä3ß
pä4t1e2h
pä4t3ent
pät1h
-pät3s
+pä2to
+pät5s
2p1b
+pbe1
2p3c
4p1d
-pda4
+pda2
1pe.
pe4a2
pea4r
1ped4a
-peed1
+peed3
2pef
pei1
+4peic
pe1im
3peit
2pek
@@ -9764,31 +9667,36 @@ pel5d
pe2let
pe3lin
pe4l3ink
-pell4e
+pel5lä
+pel3l4e
+pel3li
+pel3to
1pem
pena6
pe3n4al
pen3da
pe4nen
1penn
+pens2
3pensi
1pensu
pe2nu
pen3z2
pe1ra
per4an
-pere2
1perle
per6na
perne4
-per4r3a
+per4ra
+perr3an
+per2rä
+per4rie
5pers
-perwa4
+perwa6
pe3sa
pes4e
pese2n
-pes5s2
-pe2st
+pes5s4
3pet
1pé
2pf
@@ -9834,13 +9742,13 @@ pf3th
pgra2
1ph
4ph.
-ph2a
2phab
2phä
2phb
4phd
2p1hei
-phen3
+phen3d4
+phen3s
2ph1ers
2phf
4phg
@@ -9858,20 +9766,18 @@ ph4r
phu4s
4p1hü
2phz
-pi4a3
-pia5l
-pia5s
+pi4a5
pi3chl
p4id
pie3fr
pi2el
pie4la
-3pi2er
+5pi2er
1pil
pil4zer
pi2na
pin2e
-ping3s
+ping5s
3pinse
pi2n1u
pi2o
@@ -9881,8 +9787,9 @@ pi2pe
pi5ri
1pis
2piso
+pis2t
+pi5sto
pit2a
-pi1th
pit2s
pi2z1in
p1je
@@ -9903,9 +9810,10 @@ p4leg
p5lic
p5lif
4plig
-p4lis
p4lo
+plü2
2p1m
+pma1
2p1n
1p2o
po3b4
@@ -9913,11 +9821,11 @@ po1c
2p3oh
po2i
po3id
-3poin
3pol
po2lau
po5li
po3ly
+pont4
po1ob
po2p1ak
po2p1ar
@@ -9929,19 +9837,15 @@ po1rau
2porn
por5s
por4tri
-po5s2e
+po5s4e
po3sp
-po4sta
post3ag
po4stä
-post3ei
-po4sti
-po3s4tr
+po4st3ei
post3ra
po3ta
3pote
pot2h
-3poti
po2t1u
po2w
po1x
@@ -9949,10 +9853,9 @@ pö2bl
pö2c
4p1p
p2p1ab
-pp3anl
+pp5anl
p3pe
ppe1e
-ppe4ler
ppe2n1
pp1f4
p2p1h
@@ -9964,11 +9867,11 @@ pp4li
p2p3ra
p2p3re
p2pri
+pps2
pp3sa
pp3sp
ppt2
pp3ta
-pp3to
p2r2
3prak
3prax
@@ -9984,32 +9887,32 @@ pre2e1
3preis
2p3rer
3pres
+1preß
pri4e
1prinz
2prit
-1p4ro
+1p4ro1
3prob
pro3be
2proc
3prod
3prog
3proj
-pro3st
3proto
1prüf
2prün
2ps
4ps.
-ps2an
+ps4an
p3s2h
4psi
p2s1id
p2s1ö
-ps2po
-p3stea
-p1s2ti
-pst3r
-ps2tu
+ps2t
+p5ste
+p4st3r
+p2stu
+ps3tur
3psy
ps2ze
2p1t
@@ -10029,8 +9932,7 @@ p4t1erw
p4t1erz
p5tes
p2t1h
-p3ti
-p4t1in
+pt1in
pto5me
p2tos
p2t3r
@@ -10042,6 +9944,7 @@ pt3st
pt3su
pt3t
pt1um
+p3tung
pt1urs
p2tü
3p2ty
@@ -10055,14 +9958,12 @@ pul4sp
1pulv
1pum
1pun
-4pund
+2pund
pun2s
2punt
1pup
pu3ri
-pur3st
-pu2s
-pu4s3t
+pu2sc
1put
3put2s
3putz
@@ -10070,18 +9971,19 @@ pu4s3t
2pül
2p1v
2p1w
-pwa4r
-3py3
+3py1
+py3t
4p1z
q2u4
3quen
que3rel
1queu
+qui5s
6r.
1ra.
ra2ab
-2r5aac
-r5aal
+2r3aac
+r3aal
ra1ar
r1ab
ra2bar
@@ -10091,19 +9993,15 @@ ra3ber
2rabf
2rabg
r4abi
-ra1bl
-rab4le
-ra2bli
-rab5r
+ra1b4le
2rabs
2rabt
-2r3abw
+2rabw
1raby
ra1ce
2r1acet
ra3che.
ra4cheb
-ra3chen
ra3chet
rach4t3r
ra2chu
@@ -10115,7 +10013,7 @@ ra2dam
ra3di
3radle
ra4d3r
-rad5t
+rad3t
1rae
ra1er
r2af
@@ -10165,9 +10063,8 @@ ram6m5ers
ram4m3u
r3amn
ram2p3l
-ram3ste
2r3amt
-ramt6s
+ramt4s
r2an.
4ranc
r2and
@@ -10178,7 +10075,7 @@ ran4d3er
4r5anei
2r3anf
1rangi
-4r3anl
+4ranl
2r1anm
r1anp
2ranr
@@ -10203,6 +10100,7 @@ ra4schl
r4at.
ra2ta
ra2t1ä
+ra3te
2ratm
rat4r
2ratta
@@ -10220,10 +10118,12 @@ ra3umsa
2rausg
rau4sp
raus5se
-rau4sti
+raus3tr
raut5s
1raü
r2ax
+raxis1
+räch4s
r2äd
4räf
4räg
@@ -10234,7 +10134,8 @@ r2äd
2r1är
rä3ra
r3ärz
-rä4s3c
+rä4s1c
+rä4st
3rätse
rä2u
4räut
@@ -10259,29 +10160,27 @@ r2b5le.
rb5ler
rb2o
rb3res
-rb6ri
+rb4ri
rb2s
-rbs1a
rb4sei
rb4ser
rb3ska
rbs1o
-rb4stä
-rb3str
+rb6stä
+rb5ste
4rc
r1ce
-rcha2
r1che.
r1chen
r1chi
rch3l
+rch5lö
rch3m
rch3r
-rch1s4
+rchs2
rch3sp
rch3ta
rch1w
-r2ck1
r1cr
r1ç
2r1d
@@ -10298,23 +10197,25 @@ r2d1elb
rde7me
r3den
rde5nar
+rdend4
rden4gl
rde3r2e
r4d3ernt
+rdes4
rde3sp
-rde3sta
+rdga4
rdi3a2
rdi5a6l
r2d1inn
r2d1it
rd1os
+rdo4st
rd1ös
rd3rat
rd3rau
-rd1st
rdt4
-rd1th
rd1tr
+rdwe5ste
1re
3re.
re3ad
@@ -10331,7 +10232,6 @@ re2bü
rech3ar
4rechs
2reck.
-re2cka
3reda
4redd
3rede.
@@ -10342,9 +10242,8 @@ re3er
4reff
3refl
3refo
-3refro
+3refr
3reg
-5reg.
rege4l3ä
re2gl
4reh
@@ -10366,6 +10265,7 @@ rein6sta
rein8s7tre
re1in2v
2reis.
+reis5tro
2reiwe
re2ke
re3la
@@ -10390,6 +10290,7 @@ re4n3end
ren4gl
2rengp
re2ni
+ren4nes
2r1entl
2r1ents
2rentw
@@ -10437,15 +10338,16 @@ r1er5t
2r1erz
3r2es.
re2sa
-res1au
+res3au
3rese
3resol
re3sp
2ress
ress2e
res6s5erw
-re2stu
+re4stu
3resu
+4re2ß1
re2thy
re2u
reu3g2
@@ -10456,26 +10358,27 @@ re3uni
r1e2w
rewa4
re3we
+re3wo
4r3e2x1
3rez
4rezi
1ré
2r1f
+rfall6s
rf1ält
r2fent
r3f2es
rfi4le.
-rfin6s
rf3lic
rf3lin
r3flü
r3fre
-rf2s
-rfs1ä
+rf2sa
+rf2s1ä
+rf2se
rf3sen
rf4s1id
rfs3pr
-rf3sto
rf2ta
rf3tau
rf3t4r
@@ -10485,6 +10388,7 @@ rg2ab
r2g1ah
r2g1ak
rg2an
+rga5ste
r3ge
rge4an
rge2bl
@@ -10493,6 +10397,7 @@ rg5e4tap
r4geto
rgi4sel
r2glan
+rgleich8s
r2gleu
r2glig
rg3lo
@@ -10506,8 +10411,7 @@ r2g3res
rg3ret
rg3rin
rg3s2p
-rg3str
-rgt4
+rgs2t
rg3th
r1h4
2rh.
@@ -10531,9 +10435,10 @@ ri1cha
rich3te
4rick
rid2
-ri2d3an
+ri2dan
2ridol
r2ie
+rieb4st
ri1el
ri3els
riene4
@@ -10542,30 +10447,29 @@ rie2nu
ri1er.
ri4e3re
ri3ers.
-ri3esti
+ri3e4sti
rie5te
ri1eu
-ri2f1a
+ri2fa
ri4f1ei
ri4fer
ri2f1o
ri2f5r
-rif3st
rif4ter
-3rig
+3r2ig
ri4g5ene
-4rigg
5rigj
rig1l
4rigr
+rigs2
r2ik
ri4k5l
ri5kle
ri3ma
r2imb
2rimp
-rim2s
-rim4sc
+rim4s
+rim6sc
rin4a
2rind
ri5n4e
@@ -10598,22 +10502,22 @@ ri3so
ri4s3p
3riss
ris4sa
-ri4st
-ris6t5ers
+rist5ers
+ristes4
+3ri2ß1
r2it
r3i2tal
-riten3
-ri5ti
-ri3t4r
+ri3ti
+rit4r
5ritu
ri2x1
+4riz
1rí
2r1j
2r1k
rk1all
rk1aus
rk1äh
-rke2s
r3kla
r5klau
rk3li
@@ -10627,12 +10531,11 @@ r2k3rea
r3kri
rk3rin
rk2s1e
-rk3sen
rk3shi
rk2sp
rkstati6
rk4stec
-rks3ti
+rks1ti
rk2ta
rk4t3eng
rk4t3erf
@@ -10641,41 +10544,43 @@ rk4t3erw
rk2tin
rk2t1o2
rkto4b
-rk4t3r
-rk5tra
+rk2t3r
r2k1uh
rk2um
rku4n
rk1uni
+rku6s5t
2r1l
r3la
r3le
rle2a
r3l2i
-rli2s
-rlon3
-rlös3s
+rlös5s
rl2s1p
-rl2sto
+rl4s1to
rl3th
+rlu4str
4r1m
r2m1ald
-r2m1ans
+rm1ans
rm3anz
r4m3a2p
+r5mapp
rm1aus
rm3d
r3me.
r2m1ef
rmen4sc
r2meo
+rm2es
r2mide
r2m1im
+rmi3te
rm1ope
rm1o2ri
-rmo3s
rm3sa
-rm3sta
+rms2t
+rm5sta
rmt2
rmt3h
rm3ums
@@ -10690,9 +10595,8 @@ rn3are
rn5ari
r2n3au
rn4aue
-rnd4
rn3do
-rn3dr
+rn3d4r
r3ne
r5ne.
rn3e4ben
@@ -10708,7 +10612,7 @@ r4nerg
rn4erhi
r4nerk
r4n1ert
-r5ne2s
+r5nes
rn4e2t
r4nex
rn3g2
@@ -10732,7 +10636,7 @@ ro4bei
2robj
1robo
2robs
-ro1c
+ro1ch
3rock.
r4o3de
r4odo
@@ -10744,41 +10648,36 @@ roh5n
3r2ohr
3roi
ro3in
-ro1ir
ro3le
-roll4en
+rol3l4en
2roly
ro2mad
ro2mer
4romm
r2on
-ronen3
3ronn
rons2
-ron3sp
-ron3str
ron4tan
ro1ny
ro1pe
2ropf
ro3ph
-rop2s
r1or
-r2or3a
+r2ora
+ror3al
ro2rat
-ro1rau
ro2rei
ro2r1o
ror5th
-ro1sé
+ro3sé
ro3sh
ro3s2i
ro5sk
ro3smo
ro3sp
-ros4s3c
-ro4ste
-4roß
+ros4s1c
+ros4sie
+ro4str
ro2ßu
ro2tho
ro2tri
@@ -10801,7 +10700,6 @@ rö7le
r1ör
r2ös.
rö3sc
-rö3se
3rötu
2r3p2
r5pa
@@ -10810,51 +10708,47 @@ rpe2re
rpe4r3in
rpf4
r4pli
-rpo4st
-rpro1
+rpo4str
r4ps
rp3se
-r4pt
+r4p3t
r1q
4r1r
rr2a
r3rar
+r5räh
rr1äm
rrb2
rr1c
r3r2e
rrer4
-rre2st
r4rew
rr2h
rr3hö
+r5ries
rri3k
rr2na
rr2o
r2r3ob
rro3m
-rr2st
r3ru
r5rü
rrü1b
4r1s
-r4sab
+rs2a
+r4s3ab
r2s3a2d
rsa4ler
r2s3amp
r4s3amt
-r4s1ang
-rs1anp
-r4sar
-r3sc
-r5sch2e
+r4s3ang
+rs3anp
+r4s3ar
+rsch2e
r6scherl
rsch4l
-r5schu
-r3se
-r5sei
-r6sein
-r5sel
+rs1ebe
+r2s1ein
rse3le
rse2n
rs2end
@@ -10865,7 +10759,7 @@ rs1ers
rs1erz
rs1eta
r3sho
-r5si
+r3si
rs2ka
r5skal
r5skan
@@ -10877,30 +10771,24 @@ r4skr
r4sku
rs3l
rs4no
-r3so
-r4s1op
+r2s1op
r4s3ort.
r3s2p
r4s3ph
-rs3s2
-rs2t
+rs5s2
r4stant
+rs2tau
+rs2te
rst5eing
-rs4temp
-r3sterb
-rst3erw
-r3stie
-r2stin
+r4st3erw
+rs2th
+r4stin
rst3ing
-r3sto
-r4stot
-r3str
+r5s2tob
+r4s1tot
r4st3ran
-r3stu
-r3stü
-r3s2wi
-r3sy
-4r1t
+r5s2wi
+6r1t
r3tab
rt1ac
r2tad
@@ -10911,8 +10799,10 @@ r4t1alm
rtals1
rt1am
rt1an
+rt3anz
rt1ar
rt3a6re
+r3tas
r3tat
r2t3att
rt1auf
@@ -10922,12 +10812,10 @@ r5te.
rtee2
rt2ei
rtei3la
-rtei3s2
rte5m4e
rte2n1
r7ten.
-rtens2
-rten3st
+r5ter.
rte1ra
rte4ran
rt3erei
@@ -10938,6 +10826,7 @@ r5terli
r4t3ernä
rter4re
r4t3ersc
+rtes2
rte3sk
r2th
rt1he
@@ -10946,38 +10835,36 @@ r3tho
rt1hol
r3thu
r3thy
-r3ti
r4t1id
r4t1ima
rt1int
+rt5le
rto3p
r2t1o2r
-r4trak
rt3rec
+r4treis
r2t3res
-rtrü2
rt4sam
-rt3sch
-rt7scha
+rt5scha
rts1eh
+rts1ei
rt3spe
rtt4
r2t1urt
r3tün
-rt3w
+rt5w
r3ty
rt3z2
ru1a
ru3a2r
rube2
-ru3cker
-ru4cku
ru3de
rude2a
ru2dr
3ruf
ru2fa
ruf4s
+ruf5sc
4rug
2ruhr
5ruin
@@ -11017,15 +10904,13 @@ r3ur1e
5ru3ro
ru2si
rus2s1p
-rus4st
-ru4st
-ru5s2ta
+rus6st
ru2th
rut1he
ru2t1o2
ru2t3r
rut2s
-6ruz
+4ruz
ru2z1w
r2ü
4rüb
@@ -11035,13 +10920,15 @@ rü1ch
4rümm
2r1v
rve4n1e
+rv2s
2r1w
+rwa5re
4r1x
1ry
ry2c
ry3t
2r1z
-rz1a2c
+rz1ac
rz2ach
rz2an
r2z1ar
@@ -11063,27 +10950,27 @@ rzu3g2u
rz1urs
r3z2wä
r3z2wec
-6s.
+8s.
1sa
5sa.
-5saa
+5s4aa
2s1ab
sa2be
3sabet
sa1b4le
4sabs
-sa2chi
-sa2cho2
-sa1cr
+sa3che
+sacho6
+sa3cr
2sada
s3adm
2s3adr
sa3fa
sa4fe
-4s1aff
+4s3aff
sa1f4r
3sag
-s1a2gr
+s3a2gr
5s4ai
sa1ik
sail4
@@ -11091,57 +10978,63 @@ sail4
sa2ka
3saki
s4akr
-4sakt
-3s2al.
+4s3akt
+3sal.
3s2a1la
sal3erb
sa2l1id
+s1all
5s4alo
sal2se
-4s1alt
+6s1alt
5s4alz
-3s2am
+3sam
+5sam.
+5same
s3ameri
+5samf
+5samk
5s4amm
6s5amma
-4s3amn
+4s1amn
4samp
-3s2an.
-2s1a2na
-2sanb
+5sams
+5samu
+s1an
+3s4an.
+2s3a2na
+2s3anb
s2an2c
s2and
san4d3ri
-3sang.
+5sang.
2s3anh
-5sani
-2s3anl
-2s1ans
+3sani
+2sanl
+2s3ans
san4sk
san3sp
-4sanw
+4s3anw
2s3anz
2s1ap
sa2po
3sapr
2s1ar
-3sar.
+3s4ar.
3sara
-4s3arb
+4s5arb
3s2ard
3sari
+s3arl
s3arm
s3arr
-3sars
-4sart
-s3arz
+3s4ars
+4s3art
s3a4sp
-sa3stu
6s5asy
-s2aß
3sat
sat2a
-5sate
+5sa3te
4s3ath
4s3atl
4satm
@@ -11150,54 +11043,57 @@ sa3ts
5satz
sat4z3en
sat4zer
+s1au
3sau.
3saue
2sauf
-4s3aufb
+4s5aufb
3saug
sau2gr
3saum
-5saur
sauri1
-2s1aus
-4s3ausb
-3sause
-s3ausf
-s3ausg
-s1auß
+2s3aus
+4s5ausb
+3s4ause
+s3auß
sa2vo
-3s2ax
+3sax
3say
1sä
+3säb
3säc
s3ähn
3säle
s1ält
2s1äm
-2s3änd
+2s1änd
3sänge
2s1är
+sä2s
3sät
3säul
2säuß
-4s5b6
+6s3b4
sba4n
sber2
sbe3re
-sby5
-1s2c
+sby3
+1sc
2sc.
+s2ca
+2scam
6scar
-4s3ce
+2s1ce
6sch.
-2schak
-5s4ch2al
+7s2ch2al
4schanc
-5schanz
+7schanz
6schao
-5s4chä
+s2chau
+s2chä
+3schäd
4schb
-4schc
+2schc
3sche
4schef
sch3ei.
@@ -11207,70 +11103,65 @@ sch5erla
4schess
4schex
4schf
-4schg
-4schh
+2schg
+2schh
3schi
-7schic
schi4e
s4chim
4schiru
4schk
-s4chl
4schle.
6schlein
sch6lit
4schn.
-5s4chö
-6schöl
-4schp
+s2chö
+2schp
+2schq
4schre.
sch5rom
-6schs
-schs4e
-sch3s2k
-sch3sti
+6schs4
+sch3sk
+sch5ste
+sch5sti
6scht
sch3t4a
sch5te
3s4chu
4schunt
sch2up
-5schü
-4schv
+2schv
4schwet
-4schz
+2schz
+s2ci
2scj
-4scl
-4sco
-5s4cop
+6scl
+6sco
+7s2cop
2scs
2scu
-4s3d
+4s1d
+s3da
sda3me
-sde3s
-sdi1st
+s3do
1se
+3se.
se3a
se4al
se5al.
se5at.
-4s1e2ben
+2s1e2ben
se3b4r
2sec
4s1echo
-sech2s
-s1echt
-se2ck
-5secl
-5seco
-4sede
-7see
+4s1echt
+3secl
+3seco
+2sede
+5see
se1ec
se2e1i4
-see3ig
se1er
2s1eff
-3seg
se2gal
se2gl
seg4r
@@ -11284,26 +11175,27 @@ se4hin
seh1l
seh1ra
seh3re
-seh1s
+seh3s
se2hü
2s3ei.
3sei3b
-4s3eig
-s1ein
-7s4ein.
-4seinb
+2s1eig
+5s4ein.
+2s1einb
+s1eind
sei5n4e
-4seing
-2s3einh
-4s3eink
-2seinl
-4s3einn
-4seinr
-s4eins.
-4seinst
-2seinw
-4seis
-7s2eit
+2seing
+2s1einh
+4s1eink
+4seinl
+2s1einn
+2seinr
+s3einsa
+s3einsä
+4s3einst
+2s1einw
+2seis
+7s4eit
5s2ek
s2el.
se2l1a2
@@ -11311,7 +11203,7 @@ se3lad
sela4g
se3lam
sel1ec
-4selem
+2selem
se2ler
sel3erl
sel3ers
@@ -11320,26 +11212,27 @@ se4l1ö
s2els
sel3sz
sel3tr
-5sem.
-s4e3ma
-4s1emp
-s2en.
+3sem.
+se3ma
+2s1emp
+5s2en.
3sena
se4nag
se3nal
-4s1endl
+2s1endl
se4ners
sen3gl
-5s4eni
+7seni
sen3ob
3s2ens
+sen6stri
s2ent.
-4s1entf
-2s3entg
+2s1entf
+6s3entg
s2enti
4s3ents
-4sentw
-2sentz
+2sentw
+4sentz
se2n1u
seo2r
4s1e2pos
@@ -11352,81 +11245,77 @@ s3ereig
se4r3eim
se4r3enk
ser2er
-4s3erfo
+2s3erfo
s2erfr
-6s3erfü
+4s3erfü
ser3g
s1ergä
s2ergr
-4s1erh
-5seri
+2s1erh
+3seri
s1erkl
s1ernä
-4s3ernt
+2s3ernt
se1rot
+2s3eröf
s2ers.
s4ert.
ser3the
seru2
se4r1uf
se3rum
-7s6erv
+5s6erv
5ses.
se3su
3set
s3eta
-4s5e4tap
+4se2tap
se2tat
4s3e2th
+5setz
+3seum
se1u4n
-2sex
-4sexa
-s1e2xe
+2s1ex
+se2xe
4sexp
sex3t
-4s3f
+6s3f
sfal6l5er
-s5fi
sfi3le
-s5fü
4s3g4
-sge3s4a
+sges4
+sge3sa
2s1h
3sha.
sha2k
4shan
-1shas
-s3hä
3shi.
3shid
1shi4r
sh3n
-s3hoc
4shof
-3s4hop
-sho4r
-3show
-s3hö
+3shop
+sho6r
+5show
sh4r
+s3hü
1si
si3ach.
5siak
si1am.
+2siat
si3b4
3si1c
s1ideo
s2ido
3s2ie
-siege4s
si3ene
si3err
-sie2s
3si1f4
-5sig
-si2g1a2
+5s2ig
+si2g1a
si3g4n
si2g3r
-sig4s
si2k1ab
si4k3ere
si4k3erl
@@ -11439,37 +11328,37 @@ si2ku
si5l2e
3silo
2s1imm
-3sin.
si3n4a
2s1ind
-6s1inf
+4s1inf
sin2g1a
sin3gh
sin3g4l
sin2gr
-sing3sa
-6s1inh
-sin1i
-sini1e
+sing5sa
+4s1inh
+sin1i1
+3sinn.
+3sinnl
2s1inq
2s1ins
2s1int
-6s1inv
+4s1inv
3s4io
si3od
si3os
-5s2is
+3s2is
si2sa
si4schu
-si4s1e
+si2s1e
si2s1o
sis1p
-sis3s
-7s2it
+sis5s
+si2stu
+3s2it
si2tau
-si3te
si2t3r
-sit3s
+sit5s
si3tu
5siu
si2va
@@ -11479,24 +11368,18 @@ six3
2s1k4
4sk.
s3kad
-s2kala
-4skam
-4s3kanz
-s3kar
-4skas
+4s3kam
+4skanz
+4s3kas
ska4te.
ska4tes
-s3kä
4skb
4ske
3s2ki.
3s2kik
4skir
-ski3s
3skiz
s3klas
-s3kn
-skna3
4skom
4skor
4skö
@@ -11505,9 +11388,8 @@ s3kra
4sk5t
3skulp
2s1l2
-3s4lal
+3slal
4slan
-s3lä
sl3b
s5le
s5li
@@ -11515,7 +11397,8 @@ s5li
s3lo.
slo3be
s3loe
-2s3m2
+2s1m2
+s3mu
2s3n2
4sna
sna1b4
@@ -11524,13 +11407,10 @@ sni3er.
sni3ers
4s5not
4snö
-s5ny
1so
3so.
3so4a
-4s1o2b
-6sobj
-so1c
+2s1o2b
so3et
3soft
3sog
@@ -11538,7 +11418,7 @@ so3gl
so2h
s1ohe
so3hi
-4s5ohng
+6s5ohng
so3ho
2s1ohr
3sol.
@@ -11557,12 +11437,13 @@ s1opf
3sor.
so1ral
s1orc
-4s3ord
+2s1ord
so2rei
so3ren
-4s1orga
-4s1o2rie
+2s1orga
+2s1o2rie
so2r1o
+5sorp
3sors
so4ru
3s2os
@@ -11575,13 +11456,11 @@ so3unt
3sov
s1o2ve
s1ox
-s4oz
1sö
-sö2c
sö2f
2s1ök
2söl
-s1ös
+s1ö4s
1sp2
4sp.
4spaa
@@ -11592,14 +11471,14 @@ spani7er.
4spano
4spap
4spara
+2sparo
spar5sc
-3spaß
-2spat
+3s4paß
2spau
s2paz
-2spär
+4spär
2sped
-3s2pee
+s2pee
3s2pei
4spel
2s1peri
@@ -11613,11 +11492,11 @@ s2paz
3sphä
s3phe
3spi
-5s2pi4e
+5s4pi4e
7spiel
spier4
spi2k
-4s3pil
+6s3pil
4spip
4s3pis
2spl
@@ -11632,13 +11511,15 @@ spi2k
4s3pok
4spol
4s3pos
+s2pott
4spr.
-s2prac
+3s2prac
4sprax
4spräm
4spräs
5s4prec
2spred
+4sprei
4spres
2spro
4sprob
@@ -11647,292 +11528,296 @@ s2prac
2sprüf
3sprün
4s3ps
-4spun
+2spun
2spup
5s2pur
4sput
3spü
4spy
2s1q
-4s3r4
+6s3r4
srat6s
sret3
+sro3m
srö4s
-srös3c
+srös1c
srü2d
-4s1s
+6s1s
+ss2a
+ss3ab
+ssa3be
ssa3bo
-ss1a2ck
-ss1aj
-s3sal
-s4s3ala
-s4s1alb
-s4s1amt
-s4s3ang
-ss1ano
-s4s3ans
-s4sanz
-s3sas2
-ss3att
-ss1au
-s3s2ä
-s3se
-s4s1ec
-sse4ck
-s4s1ega
+ss1ack
+ss4ag
+ss3aj
+s3s4al
+s4s5ala
+s4s5alb
+ss4am
+s4s5ang
+ss3ano
+s4s5anz
+s3s4as
+ss3auf
+ss2ä
+ss1ech
+ss1eck
+ssee2
+s2s1ega
sse3ha
+ss1ein
sse3inf
sse3int
ss1eis
-s5sen.
ss2er
+s3ser.
sse6r5att
+s3serh
ss3erhö
-s4s3erö
s4s3erse
s5s4es
ss4et
sse3ta
-ss5g
-s5sie
s3skala
-ss3la
ss1off
-s6s1op
+s4s1op
s2s1ori
s3spe
s3s2po
ss5re
-ss3s4
-s3st2a
-s5stad
-sst6e
-ss3tec
-s3stel
-ss2ti
-s3stip
-s3sto
-s3stu
-ss2tur
-s3stü
+ss3s2
+s5st2a
+s7stad
+s5stä
+ss1t6e
+s4ste.
+s5stel
+ss2th
+s5stil
+ss1tis
+s5sto
+s5stu
+s5stü
ss1ums
-4st.
-1sta
-2sta.
-3staa
-stab4s
-3s2tad
+ss2zen
+1st
+6st.
+3sta
+s4ta.
+5staa
+4stabb
+4stabh
+4stabl
+stab6s
+4stabt
+4stabz
+5s4tad
+6stada
+6stadr
5staff
-4stag
-3stah
-2stak
-s5tal.
-sta5li
-2stalk
+6stag
+5stah
+4stak
+4stal.
+5sta5li
+4stalk
st1alp
st3ami
-4stan.
+4stamt
st3ana
-3s4tand
-2stani
-4stann
-2stans
-s3tans.
-2stanw
-s2tar
-3s4tar.
-3s4tars
-st2art
-2sta2s
+5stand
+4stanl
+6stann
+4stanw
+5star.
+5stars
+5st2art
+sta2s
st3a4si
-3stat
+5stat
4stat.
-3stau.
-2st1auf
-2staum
+s2tati
+5stau.
+5staub
+4st1auf
+4staum
5staur
-2staus
-3staus.
-2stax
+4staus
+5staus.
+4stax
3stä
4stäg
4stält
+4stämt
+5stär
+2stäti
5stätt
+4stäus
4stb
2stc
st3ch
2std
-4ste.
-2stea
-s2tec
-3steck
-1s2teg
+3ste
+4stea
+5stean
+7steck
+4stee
ste2g5r
-3steh
-1s2te2i
-3steig
-2steil
+ste2i
+5s4teig
+6steil
+s4tein
4steing
-1s2tel
-2stel.
-2stele
+s2tel
+s3telem
stel4l3ä
-2stels
-2stem
-4stem.
ste4mar
-4sten
-s4t3ends
+4stempf
+4st3ends
ste2ne
-s4t3engl
-s5t4ens
-s4t3entf
-s2tep
-2ster
-6ster.
-s3tera
-st6erb
-4sterk
-3sternc
-s3ters
-4stes
-s4t3ese
-stes6se.
-ste4st
-2stet
-4stet.
-3s4tett
-3steu
-5steue
+st3engl
+st4ens
+6st3entf
+4stentw
+4stepi
+5st6erb
+st2erg
+5sterj
+s2tern
+s2ters
+6st3ese
+4stesse
+ste4stä
+4stests
+5steß
+s2teu
4steuf
st3ev
-4stex
-2stf
-2stg
-4sth
+6stex
+4stf
+4stg
+6sth
st3ha
-s2t1hi
+st1hi
st3ho
st1hu
-2stia
-2stib
-2stie.
-1s2tiel
-2stien
-3s2tif
-5stift
-4stig
-2stik
-3s2til
-3s4tim
+3sti
+5stic
+5stif
+5stil.
+5stile
+5stim
+4stinf
st1ins
st1int
-2stio
-2stip
-1s2tir
-2stis
+4stip
+sti2r
st3iso
-1stitu
-2stiv
2stj
4stk
-4s4tl
+4stl
st5le
4stm
-2stn
-1sto
-4sto.
+4stn
+3sto
+4stob
+7stock
4stod
-sto3de
-s2toff
-s2t5om
+5s4to3de
+5stof
+4st3om
4ston
-2stopo
-2stor.
-2store
-2storg
-2stori
-2s3tose
-stos2t
-3stoß
+4stopo
+4storg
+sto5rin
4stou
-4stow
-4stoz
+s4tow
3stö
4stöch
-4stön
-4stöt
+7s2tör
+4s3töt
4stp
2stq
-2strad
-5straf
-2strag
-3s2trah
+3str
+5s2traf
+4strag
+5strah
6strai
-4strak
-4stral
+5s2tral
4strans
5s2tras
-5straß
-4sträg
+7straß
+6sträg
4sträne
+4stre.
+4strech
4stref
5streif
st3renn
-s2tric
-2s2trig
-3s2tri2k
-s2trip
-2s3tris
+4strev
+4stri.
+5s4tria
+4strib
+6strig
+stri2k
+2strin
+2stris
+4strisi
+4stroc
+5s2trof
+5s2trok
st3roll
-stro2m
-2strop
-1stru
-4strua
-3struk
+stro4ma
+s2tros
+5s2trö
+5struk
+s2trum
4st3run
-4st3s4
+4strup
+6st3s4
st1sk
st1sl
st1sz
2st3t2
5stub
-4stuc
-5stud
-4stue
-3stuf
+6stuc
+5s2tud
+2stue
3stuh
-stum2s
-stu4n
-4stun.
-3stund
-s2t1uni
-4s3tuns
-4stunt
+4stuk
+4stumr
+stum4s
+4stumz
+s2tu4n
+6stun.
+2stunf
+3stung
+2st1uni
+2s3tuns
+2stunt
stu5re
st1url
-4sturn
-stur4s
-4st1urt
-2stus
-1st2ü
-3stüc
+2sturn
+2st1urt
+3st2ü
4stüch
-3stüh
-2stür.
-3s2tüt
-4stv
+s2tück
+4stür.
+s2tüt
+2stüte
+6stv
4stw
-5styl
+2sty
+3styl
4st3z2
1su
-su1an
+su1an5
3su2b5
su4ba
-4su3bi
-5su1c
+6su3bi
+7su1c
2s1u2f
-4s1uh
+2s1uh
3sui
su1is
su3it.
@@ -11943,125 +11828,130 @@ su2mau
3sume
su2m1el
su6m5ents
-2sumf
+s3umfa
s3umfe
-2sumk
-2suml
3summ
sumo2
su2m1or
-2sums
s3umsa
s3umst
su4n
-5sun.
+3sun.
sun6derh
s1unf
2s1uni
-6s3unt
-5s2up
+4s3unt
+3s2up
su2ra
2s1url
s1urt
-3su2s1
+su2s1
su3sa
su3sh
su3si
-3suv
+sus3s
1sü
-2s3ü2b
-3süc
+4sü2b
3sü2d1
-3sün
-4s3v
-s5va
-2s1w
-s3wa
-s3we
+5sün
+4s1v
+4s1w
+swa5re
sweh2
-4s3wie
-4s3wil
+6s3wie
+6s3wil
s3wir
s3wis
s2y
3sy.
-sy2l
+sy2l1
sy4n1
-1sys5
+1sys
+sy5st
sy3t
2s1z
-s3za
+4s3za
4s3zei
3s2zena
-5s4zene
+5s2zene
4s3zent
s2zes
+s2zeß
s2zis
+s3zö
4s3zu
-s3zü
s3zw
2ß.
-2ß3a2
-2ß1b
-4ß1c
-2ß1d
+ß3a2
+ß1ä
+ß1b
+2ß1c
+ß1d
1ße
2ß1ec
2ß1e2g
2ß1ei
-ße2l1a
+ße2l
+ßel1a
+ße3lu
ßen3a
-ßene4
ßen3g
ße2ni
-ßen3st
+ßen5st
ßen3sz
ße2nu
ße3rin
3ß2ers.
-2ß1f
-2ß5g2
+ße2t
+ß1ex
+ß1f
+ß3g2
ßge2bl
2ß1h
1ßi
-ßi2g1a2
-ßig4s
+ßi2g1a
2ß1in
ß1j
2ß1k4
-ßkir5
2ß1l
+ß3la
2ß1m
-2ß5n2
+ß5n2
ß1o2
-2ß3p2
+ß1ö
+ß3p2
+ß1q
2ß3r2
2ß3s2
ßst2
2ß1t
-ß3ti
-1ßu
-2ß1um1
-2ß1ü
+ß2t1h
+ßts4
+1ßu4
+ß1uf
+2ß1um
+ß1uni
+ß1ü
2ß1v
2ß1w
-ßwa3
+ßwa5r
+ßwa3s
2ß1z
-4t.
+6t.
3ta.
2taa
-3taan
+tab4
2tab.
-ta2b1an
+ta2b5an
2t1abb
-3tabel
+1tabel
4taben
ta4bend
-4tabf
+2tabf
4tabg
4tabh
4tabk
-ta1b4l
+ta1bl
1table
2tabn
4tabs
@@ -12069,15 +11959,12 @@ ta1b4l
ta2bü
2tabw
4tabz
-ta1c
tach3te
t3ada
tadi3
t3adr
-1taf.
1taf2e
3tafel
-4taff
t1afg
t1af4r
3t2ag
@@ -12086,11 +11973,11 @@ ta2ga
ta2g5ei
4t3agent
ta3ges
-2ta3gl
+ta3gl
ta3gn
4t3a4go
-tag4s
-tag5sc
+tag6s
+tag7sc
tah4
tah3le
tahl5sk
@@ -12100,11 +11987,11 @@ tai2l
ta1ins
tai4r
ta1ir.
-4t1a2ka
+4t3a2ka
ta3kes
3takr
ta2kro
-tak4ta
+tak2ta
3taktb
3t2aktu
3t2al.
@@ -12112,47 +11999,44 @@ ta1lag
ta1lak
1talbu
tal3d
-1t4ale
+3t4ale
ta3len
ta4lens
-1talia
-5talis
+tal4leg
tal2lö
-1talo
ta2l1op
ta3lum
2ta2m
3tam.
ta3ma
-3tame
3tamg
ta3mo
-t3ampl
+t1ampl
t1amt
-3t2an.
+t2an.
t1a2na
ta4nat
-2t2and
+4tanb
+t2and
tan3da
tand4st
ta3ne
4t1anf
-3tanis
t2ank
tan4kl
tan3kr
-4tanl
+2tanl
2t1anme
4t1anna
1tanne
t1ans
-1tans.
-2t3ansi
+4t3ansi
2t3ansp
ta4nu
2tanwa
2tanwä
t4anz.
+4tanzei
tan6zerh
t1anzu
ta3or
@@ -12162,7 +12046,6 @@ ta2pes
t4ar.
2t1arb
t1arc
-3tard
ta6rens
3ta3ri
2tark
@@ -12171,20 +12054,15 @@ ta6rens
t3arti
ta2ru
2t1arz
-3tas
-1tas.
ta3sa
1ta3sc
-2ta3se
4t3asp
-1tast
-ta3sta
-ta1str
+1tas2t
1tat.
ta2tan
-ta4t1ei
-ta4tem
-ta4t1er
+tat1ei
+ta2tem
+ta2t1er
ta2th
tat3he
t3atl
@@ -12195,14 +12073,15 @@ ta2t1um
tau4fer
tau3f4li
2taufw
+1taug
t1auk
2taur
1taus
+2taus.
t1ausb
-3tausc
tau6schw
t1ausd
-3tause
+3t2ause
t1ausf
t3ausg
t1ausk
@@ -12211,135 +12090,112 @@ t1ausr
2t3auss
t1ausü
4t1ausw
-1tav
ta3va
3tax
ta3xi
-1taz
tä1c
1täg
2tägy
2täh
+3täle
4t1ält
2täm
t1ämt
t1ängs
-3tänz
+1tänz
t2är.
tä2ru
tä2s4
-4tätt
+tä4st
+2tätt
t1äug
1täu3s
4täx
1tà
-4t3b
+2t5b
tbe3r2e
tblock7en
-4t1c
+2t1c
t3cha
t3che
tch2i
tch3l
t2chu
tch1w
-t2ck
t3cr
2t3d4
tdun2
tdu3s
-1te
-3te.
-te2a2
-2teak
+1te2a4
te3al
-3team
te3an
-5teba
5t4ebb
2t1e2ben
-t2ech
-te5cha
+1t2ech
+te1cha
3techn
-4teck
-te2cka
-te2cki
+2teck
3tee
te1ele
te1em
te2e4n1
te1erw
4tefe
-4teff
+2teff
te2fl
teg4
teg3re
2teh
te3han
-3tehä
-5tei.
t2eie
-3teil
-4teilhe
+2teig
+1teil
+3teiln
+3teilz
2tein
-tein3e4c
+tein3ec
t3einge
t3einla
4t1einn
4teinr
-4teinz
t1eis.
t1eisb
-tek5te
-5tel.
-3te2la
+tei5st
+tek3te
+te2la4
te4l1ab
tel1ac
te3lan
tel1au
-3telb
-3tele
tel1e2b
tel1ec
-5telef
+3telef
+3teleg
te4l1eh
-te3lem
+1te3lem
tel1en
te3lep
te3lex
-3telf
4t1elf.
-3telg
tel1in
te2lit
-3telk
t4ell
tel3l2e
-5teln
te2lo
te2l1ö
-3telp
-5tels
tel3s2k
-3telt4
tel3ta
-3tem
-5tem.
-te2man
+tel3t4r
te2m1ei
te2mi
te3mis
-4temm
-2temme
+4temo
te2m1o2r
-5temper
-4tempf
-tem1st
+3temper
+1tempo
te4m3u
-3ten
-5t6en.
+t6en.
te4n3a2
-te5nac
t4enb
ten3da
6t5endf
@@ -12358,10 +12214,9 @@ t2enl
t2enm
t2eno
t2ens
-tens2e
4t3ensem
ten3si
-tens3th
+ten5st
t1entb
4tentd
t1entn
@@ -12372,7 +12227,7 @@ ten3zw
te2o
te3ob
t1e2pi
-5t6er.
+t6er.
te1raf
ter3am
te3ran.
@@ -12380,35 +12235,32 @@ te2r3as
t2erb
6t5erbs
6t5erbt
-4t3erde.
-3tere.
+t3erde.
te2r1e2b
te4r3eif
te2rel
-3terem
-3teren
ter3end
-3terer
-3teres
-5t4erfr
+t4erfr
4terfül
ter3g
t6ergru
+2t1ergu
+2tergü
te3ria
ter3k4
-3t2erka
+t2erka
4t3erklä
-3terkr
t4erli
4t1erlö
t4erlu
-3term
+1term
ter4mer
+3termi
ter4n3ar
t3erneu
t1erö
-3terr
ter4re.
+1terro
t6ers.
t6erscha
ter4ser
@@ -12416,43 +12268,37 @@ ter4sk
terst4
t4erst.
t4erste
-5t4ersti
-ter5sto
+t4ersti
ter5str
-5t4erstu
-3tert2
-3teru2
+t4erstu
+tert4a
+teru2
te4r1uf
ter3z2a
-2t1erzb
-3t2es
-tesa2
-tes1ac
+4t1erzb
+t2es
+tes3ac
te2sel
+3tesse.
tes3si
-5te2st
-tes3tan
+tes2t
tes3tät
-test3ei
-tes6terg
+te4st3ei
+te7ster.
+te4str
+1tests
+te4stu
te2su
-3tet
te2tat
-4teth
-4teti
6tetl
-2teu
3teuf
-3teum
te1un
-3teur.
teu2r5a4
t5euro
te2vi
-5tewo
-te2x
+1te2x
te3xa
-2t1exe
+t1exe
4t1exi
4texp
3text
@@ -12460,7 +12306,7 @@ te3xa
1té
2t3f
tfi4l
-4t1g4
+2t1g4
tg2a
t3ge
tger2
@@ -12474,9 +12320,10 @@ t3hap
t2har
4t3hau
4t1hä
-2thc
+4thc
+1the
t2he.
-3t4hea
+3thea
4theb
t2hec
2t1hei
@@ -12485,13 +12332,14 @@ t1hel
3t2hem
5thema
5theme
-1then
3theo
t2hera
t1herd
-t1herr
+2t1herr
t1herz
-1these
+t2hes
+3these
+1thi.
3thia
2t1hil
t1him
@@ -12507,6 +12355,7 @@ t2hol.
4tholz
t2hon
4t3hot
+thou4
4t3hö
2thp
3thr2
@@ -12516,86 +12365,77 @@ t2hon
4thun
t1hü
2thv
-1ti
ti2a
ti3a2m
ti3an
tib4
-3tibe
-3tibl
-2tic
ti1ce
+ti3chr
ti4d3end
t2ie
tie3br
-3tief.
-2tieg4
-2tieh
+5tief.
+tieg6
ti1el
ti2el.
ti3e2n1
ti2er
-3tiera
-4tieß
+1tierr
+2tieß
ti3et
ti1eu
-3tif.
+5tif.
ti3fa
+tif3f
ti1fr
-3tig
-3tik
-ti4kam
+tihi4
+ti2kam
ti3k2an
ti2kr
-tik5t
+ti2la
+ti3las
ti2lei
til1ep
-3tilg
+1tilg
ti3lo
ti4lö
tilt4
ti2lu
-2tim
ti2mag
tim2m1a
4t1imp
-5tin.
ti3na
t1inb
4t1ind
ti5n4e
-2t1inf
+t1inf
tin2g1a
tin2g3l
tings2
-ting3st
+ting5st
t1init
4t1inj
tin2k3l
t2inn
-3tins.
4t1inse
4tint
4t1inv
-5tio
+3tio
ti3or
+3tiö
3tip.
ti3pl
-3tipp
-3tips
-ti2rak
+1tipp
+1tips
ti1rh
-5t2is
+t2is
tisch3w
-ti4sei
+ti2sei
ti2sol
t4it
3tite
-tit2h
-2ti3tu
-tiu6
-tium2
-5tiv
+5titel
+tium4
ti2van
ti2vel
ti4v3erl
@@ -12604,6 +12444,8 @@ ti4v1r
ti2za
2t1j
2t3k4
+tklat5
+t5kr
tkü1b
2t3l2
tl4e
@@ -12611,44 +12453,37 @@ tle2r5a
4t5li
tli5f
tlings3
+tli5s
+t5lo
tlö3s
-2t1m2
-t5ma
+2t5m2
tmen2s
tmen6t
-tmin4s
tmo4des
t3mu
tmüll4s3
2t5n4
tna5me
-tnes4
-3to.
-toa4
+tnes6
to5ar
-to5at
+to5a4t
1tob
to3be
2tobj
tob4l
-to2c
-to3ch
+to1ch
3tocht
-to6ckent
3tod
tode4
-4to2d1er
-tode6s
+to2d1er
+tode6s1
to4d1u
-1tok4
-1tol
+tok4
to3la
-3tole
-2tolz
tome2
to4men
2tomg
-3ton
+1ton
to5nik
to3ny
3too
@@ -12659,81 +12494,70 @@ t3opfer
to3phe
to2pl
1topo
-2topp
-1tor
-3tor.
to1ra
to2rau
to4rän
4torc
t1ord
-3tore
+1tore.
to2r1el
to3ren
-2t1org
+t1org
t3orga
3torh
tor3int
to2rö
-3tors
+1tort
t1ort.
to4ru
-2tory
-to5sc
-1to5se
+to7sc
+to5se
to4sk
-to5s2p
-2toss
-1to3st4
-2toß
-3to5te
+to3s2p
+tost4
+to5sta
+1toten
to2tho
-1totr
-5t4ou
+3t4ou
touil4
to3un
3tow
-1toz
-3töch
+tö2c
+1töch
2t1öf
2t1ök
3tön
-tör3ste
+tö4s
t1öst
1töt
4t3p2
-tpf4
+t5pf4
2t1q
t2r4
2tr.
-5tra.
tra3bl
-1t4rac
-3trach
+t4rac
+1trach
tra3cha
t3rad.
tra4dem
-3trag
+1trag
+3tragö
2t3rahm
5t4rai
-3trak
-3tral
3t4ran.
2trand
3trank
t3rann
-5trans
+3trans
t3rase
t3rasi
-tra4st
2traß
1traum
-3träc
+1träc
t3räd
-3träg
-3träne
-2träs
-2träß
+1träg
+1träne
4t5re.
2treb
2trec
@@ -12741,74 +12565,66 @@ t3rech
t4reck
2t3red
t4ree
-3tref
-4trefe
-4trefo
+1tref
+2trefe
+2trefo
2treg
t4rei.
-3t4reib
-2treic
+1t4reib
2treif
t3reig
2t3reih
t3rein
-2t3reis
-4treit
+t3reis
t3reiz
2t3rek
2t3rel
t4rem
t4ren.
-3trend
-4trendi
+1trend
t3rent
2trepe
2trepo
+1trepp
t4rer
-3t4res.
-t4ret
+t4res.
+1t4ret
tre2t5r
t4reu
-3treuh
t3rev
2trez
5t4ré
2t3rh
-1tri
+1trib
t4riche
-3trieb
+3trieb.
+3triebs
tri4er
-3trigg
t3rind
tri3ni
3trio
t4rip
+1triu
trizi1
-1tro.
tro3b
-1troe
-3t4roi
+1troc
+t4roi
tro2ke
-2trom.
tro2mi
-2troml
-1tron
2t3roo
t4rop
3tropf
-1tros
-3troy
+2troß
t3röc
3trög
-1trös
2tröt
-1trua
3trug
2truk
trum2
trums1
-3trunk
+1trunk
3t4rup
+t3ruß
trü1be
trü1bu
2t3rüc
@@ -12816,41 +12632,39 @@ trü1bu
try1
2ts
4ts.
-t2s1a
+t2sa
t4s3ab
-t5s4ac
+t5s2ac
ts3ad
t3saf
-ts2ag
-t4s3amt6
+ts1ah
+ts1al
+t4s1amt
t4s3ar
ts3as
t4sau
t5sau.
t2s1än
-t2sca
+ts2c
t4schar
-t5sch2e
+tsch2e
tsch4li
t4schro
-ts4cor
t2s1e2b
-tse4c
-ts1eck
+t3seg
t4s3e4h
t3seil
t4seind
+ts3einl
ts1em
tse2n
-t3sen.
ts1eng
t2s1ent
t2s1er
-t4s3esse
-ts1ex
t2s1i2d
ts1ini
t2s1ir
+t7sit
t3skala
ts3kr
t2s1o2
@@ -12868,38 +12682,42 @@ t3spek
ts2pi
t3s2pon
t3s2por
-ts3s2
-t1s2t
-ts3taf
-ts3tak
+ts5s2
+ts1tak
+ts2tat
ts3täti
-ts3tep
-t3stero
+t4s1tep
+t5s4ter.
+t4sterm
+t5stero
+ts3terr
+t5s4tes.
t5steu
-ts3th
-ts4til
+ts1tie
+t4s3tis
t6stit
+ts2to
ts3toc
ts3tor
-ts3trad
-t4s3trau
-t2s3trä
-t2s3tri
-t3strö
+t4s3trad
+t4strau
+t4s1trä
+t4s1tri
+ts2tro
+t4strop
ts3trü
-t3stu
-t3stü
t2s1u
1tsub
t3sy
4t1t
tt1ab
tt3ad
+ttag7ess
t2t1ak
t3tal
t3tan
-t4tanb
tt1art
+tta5st
tt1auf
tt1ebe
tt1eif
@@ -12908,6 +12726,7 @@ tt1eis
t3te2l
tte4la
tte4l1o
+t3t2er
tte2s
tte4s1ä
t2teti
@@ -12916,9 +12735,7 @@ tt3ha
tt2häu
tt1ho
tt1hu
-t3ti
t3tra
-t2trau
t3trä
t3t4ro
tt5rom
@@ -12929,33 +12746,30 @@ tt3sec
tt5se5h
tt3sel
tts1p
-tt2s3ti
+tt4s3tem
+tt4ster
+tt4sti
ttt4
-t3tu
+t2tuc
tt3z2
-1tu
tu1alm
tu3an
2tub
-3tuch
+1tuc
tu2chi
-2tud
-3tue
+1tue
tue3re
tu3et
-2tuf
tuf2e
tu3fen
t1u2fer
2tuh
-2tu2k
+tu2k
tu3ka
t1ukr
tu3la
-3t2um.
-5tume
+t2um.
2tumf
-2tumg
2tumk
tum2si
tum2so
@@ -12965,14 +12779,14 @@ tum2so
2tund
3tu3ne
2t1unf
-3tung
t1unga
tun2gl
-tung6s
+tung8s
2tunif
2t1u4nio
+3tunn
+1tuns
2tunt
-3tuö
t1up.
tu2ra
tur3a4g
@@ -12985,7 +12799,7 @@ tu2r1er
tur3ere
tu4res
tu2r3e4t
-3turn
+1turn
tu2ro
tu3rol
tur3s2
@@ -12995,61 +12809,58 @@ tu2sa
tu4schl
tu4so
tu3ta
+tuts3c
2tüb
t3übe
-3tüch
-tück2s
+1tüch
+tück4s
1tüf
-1tüm
1tür.
tür1c
1türe
1türg
-1tür3s
+1türs
3tüten
2t1v
t5vo
4t1w
-twa4r
twi4e
1ty
2tyl
ty4le
-3typ
ty2pa
-ty3st
2t1z
t2z1a2
tz3an
tz3as
t2z1ä
t5ze.
-t2z1e4c
+t2z1ec
t2z1eie
t2z1eis
tze4n
tz4ene
tz3ents
t2z1erl
-t3ze2s
+t3ze4s
tz1imp
-tz1ind
tz1int
t2zo
tz1of
t3zon
tz1or
-tz4tin
+tz2tin
t2z1w
2u.
u3a2b
-u1a2c
+u1a4c
ua3d
uad4r
u1al.
u3alet
u1alf
-u3a2lo
+ual3l
+ua2lo
u1alr
u1als
ual3t
@@ -13069,6 +12880,7 @@ u1äm
u1äu
2u1b
u3be
+ub3ein
ub6i
ub3lic
ub5los
@@ -13076,20 +12888,21 @@ u3blö
ub3lu
u2bop
ub3rä
-ub5rit
+ub3rit
ub2sa
ub2s1o
ub2spa
ub3um
u2b3üb
-4uc
-u1ce2
+2uc
+u1ce4
+uces3
u2ch1a
u3cha.
uch3an
uch1ä
u1che
-u2ch1e2c
+u2ch1ec
uch1ei
u3ches
u1chi
@@ -13100,30 +12913,28 @@ uch5m
uch3n
u2ch3r
uch2so
-uch4spr
uchst4
+uch5str
uch4tor
uch2t3r
u1chu
uch3ü
uch3w
-u2ckem
-u4ckent
uck2er
-u4ck3erl
-u2cki
+uck3erl
uck4sta
u1cr
2u1d
u5d2a
-udens2
ude3r2e
+ude5sa
udi3en
uditi4
u4don
ud3ra
+ud2s
+ud3sc
u1e
-ue4ck
u2ed
ue2en
u2eg
@@ -13143,11 +12954,10 @@ u5eremp
u5erent
ue4rerg
uer3g2
-u5erinf
-u5erint
+u3erinf
+u3erint
uerk4
uer4ne
-uern3s4t
uer3o
u3err
uert2
@@ -13155,11 +12965,13 @@ u3erum
u3erunf
u3erunt
u3erur
-u3erv
uer3z
+ue4s
+ue5se
+ue5sp
ue2ta
ue4tek
-uet4s
+uet2s
uf3ad
u3fah
uf1ak
@@ -13174,6 +12986,7 @@ u3fen.
u2fent
u2f1erh
uf2ern
+u2f1eß
2uff
uf3fe
uff4l
@@ -13184,8 +12997,12 @@ uf1ori
u1fö
uf3r
uf5sä
+uf4s3tem
+ufs3ten
+uf4ster
uft1eb
-uft3s4
+uf3ten
+uft3s2
uft5sa
2u1g
u4gabte
@@ -13200,7 +13017,6 @@ u2g5ent
ug5erf
ug5erl
uge7sc
-ugge4st
ug3hu
u2g1l
ug3lä
@@ -13215,25 +13031,25 @@ u4g3reis
ug3ro
ug3rum
ug3rüs
-ug5sc
+ug3sau
+ug7sc
ug3s2e
ug3si
ug3spa
ug4spr
ugs2t
-ug5stä
-ug3str
+ugs3te
ugut2
u2gü
u1h
2uh.
uhe1ra
-uhe1s4
-uhe3st
uh1la
uh1lä
uh3ma
-uh5me4
+uh5me6
+uh3mi
+uh3na
uhr1a
uhr3er
uh1ri
@@ -13243,16 +13059,17 @@ uhr3tr
uh2ru
uh1w
4ui
-ui2ch
+ui2c
u1ie
ui1em
-u3ig
-u4ige
+u1ig
+u2ige
u3in.
+ui5ne
u3isch.
u3ischs
uisi4n
-ui4s3t
+ui4st
u1j
ukä2
u3käu
@@ -13263,6 +13080,7 @@ u3kla
ukle1i
u3klo
u3klö
+u3ko
u5kö
u1k4r
uk2ta
@@ -13274,7 +13092,6 @@ u1l
ul1ab
ul1am
ul2ar
-ula2s
ul1äm
ulb4
uld2se
@@ -13283,10 +13100,9 @@ ule4n
ul1erf
ul1erh
ul1erw
-ules1a
+ules3a
ule2t
ul3eta
-ul3fe
ulg4
uli2k
uli5ne
@@ -13294,17 +13110,17 @@ ul1ins
ul3ka
ul2kn
ull2a
+ul3len
ul2les
-ull1s
+ul2lö
ulm3ein
ulo2i
ul1or
ulö3s
ul2p1h
-ul2sa
-ul2sei
+ul2s1a
ul3sp
-ulsu3
+uls2t
uls3z
ul4tar
ul2tau
@@ -13313,10 +13129,9 @@ ul2tri
u2lü
ulz2
ul3zw
-u2m3a2k
+u2m1a2k
um1all
um2an
-uman4s
um1anz
um1ar
um1aus
@@ -13343,10 +13158,9 @@ um2pl
ump3le
1umr
1umsat
-um4ser
+um2ser
um2sim
um2s1pe
-um1st
um2su
umt2
um3th
@@ -13395,14 +13209,14 @@ un1gl
un2g1r
ung3ra
ung3ri
-ung4s3
+ung6s1
u3ni
un1ide
1u4nif
un1in
un1ir
2unis
-un5isl
+un3isl
1u4niv
un2k1a
un2kn
@@ -13415,7 +13229,6 @@ unk4t3r
un2n3a2d
un5n4e
un3no
-unn3s
un1o
uno4r
un2os
@@ -13423,11 +13236,10 @@ un2os
uns2
2uns.
unsch5el
-un5se
+un3se
1unsi
un3sk
un3sp
-un2stu
1unt
un3ta
unte2
@@ -13456,13 +13268,12 @@ up2pr
u1pr
up1ru
up1sl
-up4t3a2
+upt3a2
upt3erg
upt1o
-up4tr
u1pu
u1q
-4ur.
+2ur.
u1ra
u3ra.
u3raba
@@ -13489,9 +13300,8 @@ urb2
ur3ba
ur2ble
urch1
-urch3s
-urd2
-ur3di
+urch5s
+ur3d2i
2ure
ur1eff
ure3g
@@ -13505,8 +13315,6 @@ ur1erw
urg2a
ur2gri
urgros4
-urgs2
-urg3st
u1r2i
uri2c
u2r3im
@@ -13515,49 +13323,42 @@ ur1ini
ur3ins
ur1int
ur3inv
-urk2s
1urlau
-urm2a
-urm3ang
2u1ro
-uro3st
+uro5st
u1rö
2urr
-ur3sac
ur2san
-urs1au
-ur6sei
-ur4ser
-ur6sin
-ur2st
+urs3au
+ur2sei
+ur2ser
+ur4sin
ur5st4r
-ur4sw
-urt2
-ur5t4e
+ur6sw
+urt4
+ur5te
ur3th
u1ru
-urü2
ur2za
ur2zä
ur2zi
ur2zo
ur2z1w
u4saf
-us1an
us4ann
-u2s1au
+u2sau
u6schent
usch5wer
us1ec
u2s1ei
u3seid
-u5sep
+u7sep
use1ra
u2serp
us4et
usi3er.
usi5ers.
-u3sik
+us3li
us3oc
u3soh
u3sol
@@ -13571,55 +13372,70 @@ u3spek
us1pic
u5s2piz
us2por
-us4sei
+us2sac
+us6sat
+us2sei
+us3sel
usse4n
uss5erfa
uss3erk
-uss5ersu
-us4sez
-us2sof
+us5sers
+us2sez
+us2sir
uss3tät
-ust1a2b
-u3stal
-u3stel
-us1tr
-us4tris
-u3stu
-u4stun
-u4stur
+us2sü
+u4st1a2b
+u5stal
+us2tat
+u5stä
+u5ste
+us2ten
+us2ter
+us2th
+u5stis
+u5stop
+us1tor
+u4strä
+u5s4trop
+u5stu
+u6s1tur
+u5stüc
us2ur
u2sü
u1sy
-u1ß
-ußen3
+u4sz
+uß3et
+u2ß1u
2u1t
u3taf
ut1alt
ut1a4m
+u2tanz
u2t1ap
u2t3ar
ut1är
u3tät
-u3te
-u5te.
-u4t1e4g
+u3te.
+u2t1e4g
ute2l
ut2em
ute2n1
+u3ten.
uten3e
-u4tent
+u2tent
+u5ter.
ute5r4er
-u5tern
-ut3ersa
-u5tet
-u4tev
+u4t3ersa
+u3tet
+u2tev
u4t1ex
u2t1hi
u2t1ho
u2t1hu
uti2q
+u3to.
uto4ber
-uto5c
+uto3c
uto3n4
ut1opf
u2tops
@@ -13630,7 +13446,6 @@ ut3rü
ut5sa
ut2s1ä
ut4schl
-ut6schö
ut3sp
ut4spa
ut3te
@@ -13652,50 +13467,46 @@ u1x2
ux3t
u1ya
u1z
-uze2
+uze4
uz3ot
uz1we
uz3z4
1üb
2übd
-übe2
-übe3c
-übe4r1
+übe4
+über1
ü2b5l
-3üb5r
-üb2st
+3üb3r
3übu
2üc
ü1che
üch3l
-üch4s3c
+üch4s1c
üch5t4e
ück1er
-ück5e4ri
-ü4ckers
-ück4spe
+ück3e4ri
ü4d3a4
+üdau5
ü3den.
üden4g
ü3d2ens
üd1o4
-üd1ö
+üd1ö4
ü4d5r
-üd3s2
+üd3s
üdsa1
üd1t4
-ü2f3a
+ü4f3a
ü2f1ei
ü2f1erg
üf2fl
ü2f1i
üf3l
+üf3te
ü1g
-ü3ge
ü2g3l
ü2gn
üg3s
-üg4st
üh1a
ü1he
ü2h1ei
@@ -13703,7 +13514,6 @@ uz3z4
ü2h1erk
ü2h1erz
üh1i
-ühla2
ühl1ac
ühl1ag
üh5l2e
@@ -13716,12 +13526,13 @@ uz3z4
ühr5ei.
üh5ro
ühr5ta
-üh1s
-üh3s2p
-üh5te
+ühs2
+üh3sp
+üh3stu
+üh3te
ü1hu
üh1w
-ü1k
+ü1k2
2ül
ül1a
ül2c
@@ -13732,25 +13543,17 @@ uz3z4
ül4lö
ü1lu
ü4ment
-2ün
ü2n1a
ün2c
ün2da
ün2dr
-ünd1s
ün2f1
ün4f3ei
ün3fl
ün4fli
-ünf3r
+ünf5r
ün2g3l
-ünn4s
-ün2s
-ün3sc
-ün3sp
-ün4st
-ün5sta
-ün5str
+üng5s
ün3th
ün2za
ü1pe
@@ -13762,34 +13565,37 @@ uz3z4
ür4f3r
ür4g5eng
ü1ri
-ü1r2o
+ü1r2o1
üro3b
ü3rofe
-üro1r
-üro3st
-ürr2
-ür2s
-ürs3tin
+ür4ster
+ür5sti
ürt2h
ür3the
ü1ru
+üs2a
ü2schl
üse3h
üse3l
-üs4s3c
-üs5se
-üs2st
-ü2st
+üs4sa
+üs4s1c
+üs3se
+üs4st
+ü4sta
üste3ne
+ü4str
ü1ß
ü1ta
ü2t1al
+ü1te
+ü1ti
üt3r
üt2s1
üt2tr
+ü1tu
ü1v
ü1z
-2v.
+4v.
3va.
2v1ab
va3c
@@ -13797,22 +13603,21 @@ va3ge
val2s
2vang
2v1arb
-va3st
v4at
va2t3a6
-va4tei
va2t3h
va4t1in
vati8ons.
va2t3r
-vat3s2
+vat5s4
vat3t
va2t1u
+vat3z
2v1au
+vä1
2v1b
2v1d
ve2
-3vea
ve3ar
ve3b
ve3c
@@ -13820,8 +13625,7 @@ ve3d
ve3g
ve3h
veit4
-veits3
-vek3
+veits1
ve3la
ve4l1au
ve3le
@@ -13852,11 +13656,12 @@ verg4
ve3ri
ve5ris
ve5rit
-ver3st
+ver5sta
+ve3s
2vesc
-2ve3se
-ves1p
-ves3ti
+2vese
+ve4s1p
+ves2t
ve3ta
vete1
vete3r
@@ -13873,7 +13678,6 @@ vi3an
vi4a3t
vi4c
vi3de
-vid3s2t
vie2h3a
vi2el
vi2er
@@ -13883,6 +13687,7 @@ vi3ka
vi2l1a
vi2leh
vi2l1in
+vil3l
2v1i2m
vi4na
vin2s
@@ -13890,8 +13695,8 @@ vin2s
3vio
vi3sa
vise4
-vi5s2o
-vi3s2u
+vi3s2o
+vis2u
vize5
2v1k
2v1l2
@@ -13899,9 +13704,9 @@ vize5
2v1n
2v1ob
vo2gu
-voll1a
-voll5end
-von3
+vol6l5end
+vol6lerw
+vol2li
2v1op
vo2r1
vor3a
@@ -13910,15 +13715,14 @@ vor3g
vo3ri
vo5rig
vor3o
+vorö4
3voy
-vö2c
2v1p
v3pf
v1ra
3vri
v1ro
-2vs
-vs2e
+2v1s
v3s2z
2v1t
2vumf
@@ -13928,11 +13732,10 @@ v3s2z
4w.
w2a
wab2bl
-wa5che
wa3d
waffe2
1wag
-wa5ge
+wa3ge
wa2g5n
wa2gr
wa3gra
@@ -13943,58 +13746,49 @@ wai2b
1wal
3wald
wal4da
+wal2to
walt4st
-wa5na
-wang6s
-wan4s
wa2p
-wa2r
-wa3ra
-1war2e
+wa4r
+wa5ra
+1wa3r2e
ware1i
-wa3ri
-war3ste
+wa5ri
wart4e
-wa3ru
+wa5ru
1wa2s
wa3sa
-wa3se
wa3sh
wa3si
-wass4
-was7se
+was5s4
1wäh
1wäl
+wäm3
1wäs
-wäs4c
+wäs2c
wä5sche
-wäs5se
w1b
2w1c
w1d
weat3
we3be
4webeb
-we3cke
-we5cke.
-we5cken.
-we5ckes
we3d
we2e2
weed1
we2fl
3weg
-we2g1a
+we2g5a
we2g5l
we4g3r
-wegs4
+wegs2
weg3sp
1weh
we3he
wei4bl
2weie
weis4s3p
-wei3str
+wei5str
wei3ße
wei4tr
weit3s
@@ -14021,39 +13815,43 @@ we4r1io
1werke
wer2kl
wer2ku
-wer2s
-wer2t3a
+wer4sta
+wer2ta
wer4tei
wer6t5erm
wer4to
1werts
-1we3se
+1we5se
+wesen4s3
we3si
we2s1p
-we4st
-west1a
-west3ei
-wes2t1o2
-west3r
-wes4tu
-wet4s
-wet4ta
+wes2t
+we4st1a
+we4st3ei
+we5sten.
+we5stens
+we6steu
+we6sti
+we4st1o2
+we4stö
+we4st3r
+we4stu
+wet2s
wett3s
2w1g
-w5ho
-wi3cka
+w3ho
3wid
wi2e
wie3l
wie5ne
-wie2st
+wie4st
wi3k2
-wim2ma
wim4m3u
-win4d3e4c
+win4d3ec
win2dr
win2e
win8n7ersc
+win4num
wi4r
1wirt
wi5s4e
@@ -14064,6 +13862,7 @@ wi3th
2wk
2w1l
2w1m
+2wn
wn3sh
1wo1c
wo2cha
@@ -14072,6 +13871,7 @@ woche4
woh4l
1wolf
wolf4s
+wol4la
wol4ler
wor3a
wo2r3i
@@ -14085,30 +13885,25 @@ wör3the
1wr
w1ro
2ws
-w3s4k
-w1s2t
+w3s2k
2w1t
-w3ti2
+wti2
w2u
1wuc
-wul2
-wul3se
+wuls2
wun2s
4wur.
wur2fa
-wur4s
1wurst
-wus2
-wus3te
-1wu4t1
+wus4
+1wu2t1
1wüh
-wül2
-wün3
+wüs4
2w1w
6x.
x1a
1xa.
-2x3ab
+2xab
1xad
1xae
xa1fl
@@ -14117,7 +13912,6 @@ xa4m
xa3me
xa5mer
2xan
-x4anz
3xas
2x1b
x1c
@@ -14131,7 +13925,7 @@ x1em
7x2em.
xemp6
3x2en
-xens4
+xens2
xen3sa
x2er.
5xere
@@ -14140,7 +13934,6 @@ xers2
2x3eu
2x1f
2x1g
-xge1
2x3h
1xi
xib4
@@ -14154,18 +13947,18 @@ xie3l
xi3g4
xi2lo
xi2l1u
+xins2
xin3sk
-x2i2s1
-xi3sc
-xi4se
-xiso2
-xis3s
-xis2tä
+x2is
+xi2s1e
+xi2s1o2
+xis5s
+xi5stä
+xi2su
x1i2tu
x1j
x1k4
2x3l
-xlib6
x1m
2x1n
x1or
@@ -14176,13 +13969,13 @@ x1r
4x1t
x2t1a
xt3an
-xt4as
+x3t4as
x2t1ä
x3tät
-xtblo4
x2t1e2d
x2t1ei
-x4tent
+x3teil
+x2tent
x2t1erf
xtra1b6
x2t3ran
@@ -14192,7 +13985,7 @@ x3tur
1xu
xu1a
x1u4n
-xu2s1
+xu2s
x1v
2x1w
1xy.
@@ -14205,7 +13998,6 @@ y1a2m
yan2g
y3ät
y1b
-yb6r
y1c
y2chi
y3chis
@@ -14215,9 +14007,9 @@ y3d4r
y1e
y2ef
yen4n
-y2es
+y2es2
ye3sp
-y3est
+y3e4st
ye2th
y1f
y1g
@@ -14231,17 +14023,15 @@ yk5s
y1l
yl3a2m
y3lant.
-y3lante
+y3l4ante
yl3c
y5len
y5ler
yli4n
yloni1
-yls2
-yl1st
y2l1u
-yma4t
-ym3p4
+yma2t
+ym3p2
ympi3e
y2ne
y2n3o
@@ -14253,7 +14043,7 @@ y1ont
y3ou
y1p
ypa2
-yp3an
+yp5an
ype2
yper3t
y3ph
@@ -14265,16 +14055,19 @@ y1r
y3r2e
y3ri
yri1e
-y5s4c
-y1sé
-ys2h
-y3s2p
-y2st4
-ys1tr
-y3s2ty
-y3s2z
+y3ro
+y1s2
+y5sc
+y3sh
+ys3k
+y3sp
+ys3s
+yst4
+y3sty
+y3sz
y1t
y2t2h
+yto5s
yu2r
yure3
y1v
@@ -14283,46 +14076,47 @@ y1y
y1z2
6z.
2z3a2b
-za1c
+za1cha
+za1chä
z3a2d
za3de
2z1af
za3gr
3z2ah
2z3a2k
+za3li
2z1all
2z1am
z3ambik
3zambiq
z1an
-za2na
2z3anf
3zani
-z3anl
3zar.
2z1arb
3za3re
z1arm
-3zaro
-za3st4
+3za3ro
+za5st4
2z3at
3zaub
z1au2f
z3aug
3zaun
+za3v
zä2
2z1äc
3z2äh
2z1äm
+zäng5
z1ärg
z1ärm
-4z3b6
+4z3b4
zbü1b
zbübe5
4z3c
2z3d
zdä1
-zdi1st
1ze
ze3a
2zeck
@@ -14331,8 +14125,8 @@ ze1e
zei3la
zeile4
2z1ein
-zei3s2
-zei5sp
+zei5s2
+zei3sk
zeist4
zeit1a
zei4tak
@@ -14344,15 +14138,19 @@ ze4l1a2
zel3ad
zel1er
zel1in
-zel5la
+zel5l4a
+zel5lä
+zel4leh
+zel4lin
+zel3spr
zel3sz
zel3th
zelu2
ze5m4e
2z1emp
5zen.
-ze4n1ac
-zen5s2e
+ze6n1ac
+zen3s2e
zen2ta
5zentr
zent3sk
@@ -14386,12 +14184,13 @@ zer6t5rau
3zerza
z1erzi
ze2sä
+ze5sc
ze2s1i
ze3sku
-ze2sp
-zes6s5end
-ze2st
-zes3tr
+ze2s3p
+zes4ser
+zes1tr
+ze2ß1
ze2tr
2z1ex
2z3f
@@ -14399,18 +14198,19 @@ ze2tr
zger2a
2z1h
z2hen
-zhir5
-zi3alo
+3zi.
zid5r
zi1erh
zi1es.
-zig4s
+3z2ig
zil2e
+zil3l
+z2imm
2zimp
3zine
zin4er
2z1inf
-2z1inh
+z1inh
zin4ser
4zinsuf
2z1inv
@@ -14419,7 +14219,7 @@ zi3op
zirk4
zirk6s
zi3s2z
-zi1t2h
+zit2h
2z1j
2z3k4
zkü1b
@@ -14427,7 +14227,6 @@ zkü1b
z3la
2z1m
2z3n2
-znei3
2zob
2zof
z1oh
@@ -14451,21 +14250,19 @@ zö7li
z2t1au
z3te
z4tehe
-zte3ma
zte3o
-zte3str
+zte5str
z2t1h
z4t3hei
z3t2her
zt3ho
-z3ti
zt1ins
zt3rec
-zt3s
+zt3s2
zu1
zu3a
zub4
-zu5cke
+zu2c
zud4
zu3f4
zu2g1ar
@@ -14488,7 +14285,7 @@ zu3r2a
2z1url
2zurs
2z1urt
-zu3s4
+zu3s2
zu3t
zuz2
2züb
@@ -14512,9 +14309,8 @@ z2wit
z1wur
2z1wü
zy1ank
-4z1z
+6z1z
z3z4a
z3zi
-zzi3s2
z3zo
-zzoll2} \ No newline at end of file
+zzoll2}
diff --git a/tex/context/patterns/lang-deo.rme b/tex/context/patterns/lang-deo.rme
index 8bfa03fdb..3997cda14 100644
--- a/tex/context/patterns/lang-deo.rme
+++ b/tex/context/patterns/lang-deo.rme
@@ -1,13 +1,13 @@
% generated by mtxrun --script pattern --convert
-% dehyphn-x-2008-06-18.pat
+% dehypht-x-2008-06-18.pat
-\message{German Hyphenation Patterns (Reformed Orthography, 2006) `dehyphn-x' 2008-06-18 (WL)}
+\message{German Hyphenation Patterns (Traditional Orthography) `dehypht-x' 2008-06-18 (WL)}
-% TeX-Trennmuster für die reformierte (2006) deutsche Rechtschreibung
+% TeX-Trennmuster für die traditionelle deutsche Rechtschreibung
%
%
-% Copyright (C) 2007, 2008 Werner Lemberg <wl@gnu.org>
+% Copyright (C) 2008 Werner Lemberg <wl@gnu.org>
%
% This program can be redistributed and/or modified under the terms
% of the LaTeX Project Public License Distributed from CTAN
diff --git a/tex/context/patterns/lang-uk.hyp b/tex/context/patterns/lang-uk.hyp
new file mode 100644
index 000000000..faa79bb74
--- /dev/null
+++ b/tex/context/patterns/lang-uk.hyp
@@ -0,0 +1,8 @@
+% generated by mtxrun --script pattern --convert
+
+% for comment and copyright, see e:/tmp/patterns/lang-uk.rme
+
+% used:
+
+\hyphenation{
+} \ No newline at end of file
diff --git a/tex/context/patterns/lang-uk.pat b/tex/context/patterns/lang-uk.pat
new file mode 100644
index 000000000..2a876540e
--- /dev/null
+++ b/tex/context/patterns/lang-uk.pat
@@ -0,0 +1,1905 @@
+% generated by mtxrun --script pattern --convert
+
+% for comment and copyright, see e:/tmp/patterns/lang-uk.rme
+
+% used: а б в г д е ж з и й к л м н о п р с т у ф х ц ч ш щ ь ю я є і ї ґ
+
+\patterns{
+2а1
+а3а
+а3е
+а3і
+а3о
+а3у
+а3ю
+а3я
+а3є
+а3ї
+2е1
+е3а
+е3е
+е3і
+е3о
+е3у
+е3ю
+е3я
+е3є
+е3ї
+2и1
+и3а
+и3е
+и3і
+и3о
+и3у
+и3ю
+и3я
+и3є
+и3ї
+2і1
+і3а
+і3е
+і3и
+і3о
+і3у
+і3ю
+і3я
+і3є
+і3ї
+2о1
+о3а
+о3е
+о3і
+о3о
+о3у
+о3ю
+о3я
+о3є
+о3ї
+2у1
+у3а
+у3е
+у3і
+у3о
+у3у
+у3ю
+у3я
+у3є
+у3ї
+2ю1
+ю3а
+ю3е
+ю3і
+ю3о
+ю3у
+ю3ю
+ю3я
+ю3є
+ю3ї
+2я1
+я3а
+я3е
+я3о
+я3у
+я3ю
+я3я
+я3є
+я3ї
+2є1
+є3у
+є3ю
+є3є
+є3ї
+2ї1
+ї3е
+ї3о
+ї3ю
+2б1к
+2б1п
+2б1с
+2б1т
+2б1ф
+2б1х
+2б1ц
+2б1ч
+2б1ш
+2б1щ
+2в1б
+2в1г
+2в1д
+2в1ж
+2в1з
+2в1к
+2в1л
+2в1м
+2в1н
+2в1п
+2в1р
+2в1с
+2в1т
+2в1ф
+2в1х
+2в1ц
+2в1ч
+2в1ш
+2в1щ
+2в1й
+2г1к
+2г1п
+2г1с
+2г1т
+2г1ф
+2г1ц
+2г1ч
+2г1ш
+2д1к
+2д1п
+2д1с
+2д1т
+2д1ф
+2д1х
+2д1ц
+2д1ч
+2д1ш
+2д1щ
+2ж1к
+2ж1п
+2ж1с
+2ж1т
+2ж1ф
+2ж1х
+2ж1ц
+2ж1ч
+2ж1ш
+2з1к
+2з1п
+2з1с
+2з1т
+2з1ф
+2з1х
+2з1ц
+2з1ч
+2з1ш
+2з1щ
+2к1б
+2к1г
+2к1д
+2к1з
+2л1б
+2л1в
+2л1г
+2л1ґ
+2л1д
+2л1ж
+2л1з
+2л1к
+2л1м
+2л1н
+2л1п
+2л1р
+2л1с
+2л1т
+2л1ф
+2л1х
+2л1ц
+2л1ч
+2м1б
+2м1в
+2м1г
+2м1д
+2м1ж
+2м1з
+2м1к
+2м1л
+2м1н
+2м1п
+2м1р
+2м1с
+2м1т
+2м1ф
+2м1х
+2м1ц
+2м1ч
+2м1ш
+2м1щ
+2н1б
+2н1в
+2н1г
+2н1д
+2н1ж
+2н1з
+2н1к
+2н1л
+2н1м
+2н1п
+2н1р
+2н1с
+2н1т
+2н1ф
+2н1х
+2н1ц
+2н1ч
+2н1ш
+2н1щ
+2п1б
+2п1д
+2п1з
+2р1б
+2р1в
+2р1г
+2р1ґ
+2р1д
+2р1ж
+2р1з
+2р1к
+2р1л
+2р1м
+2р1н
+2р1п
+2р1с
+2р1т
+2р1ф
+2р1х
+2р1ц
+2р1ч
+2р1ш
+2р1щ
+2р1й
+2с1б
+2с1г
+2с1д
+2т1б
+2т1г
+2т1д
+2т1ж
+2т1з
+2ф1б
+2ф1г
+2ф1з
+2х1г
+2х1д
+2ц1б
+2ц1г
+2ц1д
+2ц1з
+2ч1б
+2ч1д
+2ч1ж
+2ш1б
+2ш1г
+2й1б
+2й1в
+2й1г
+2й1д
+2й1ж
+2й1з
+2й1к
+2й1л
+2й1м
+2й1н
+2й1п
+2й1р
+2й1с
+2й1т
+2й1ф
+2й1х
+2й1ц
+2й1ч
+2й1ш
+2й1щ
+2дь1к
+2дь1с
+2дь1т
+2дь1ц
+2зь1к
+2зь1с
+2зь1т
+2ль1б
+2ль1в
+2ль1г
+2ль1д
+2ль1ж
+2ль1з
+2ль1к
+2ль1м
+2ль1н
+2ль1п
+2ль1р
+2ль1с
+2ль1т
+2ль1ф
+2ль1х
+2ль1ц
+2ль1ч
+2ль1ш
+2ль1щ
+2ль1й
+2нь1б
+2нь1г
+2нь1з
+2нь1к
+2нь1л
+2нь1м
+2нь1с
+2нь1т
+2нь1х
+2нь1ц
+2нь1ч
+2нь1ш
+2нь1й
+2рь1к
+2рь1ц
+2сь1б
+2сь1д
+2ть1б
+2к1сп
+2к1ст
+2к1ськ
+2п1сп
+2п1ст
+2п1ськ
+2с1пк
+2с1пп
+2с1пс
+2с1пт
+2с1пх
+2с1пч
+2с1ськ
+2с1тк
+2с1тп
+2с1тс
+2с1тсь
+2с1тт
+2с1тф
+2с1тц
+2с1шт
+2сь1кк
+2сь1кс
+2сь1кт
+2т1ск
+2т1сп
+2т1ст
+2т1ськ
+2т1шк
+2ф1сп
+2ф1ст
+2ф1ськ
+2ф1шт
+2х1ст
+2х1ськ
+2ц1ст
+2ц1шк
+2ш1тк
+2ш1тсь
+2б1б
+2в1в
+2г1г
+2ґ1ґ
+2д1д
+2ж1ж
+2з1з
+2к1к
+2л1л
+2м1м
+2н1н
+2п1п
+2р1р
+2с1с
+2т1т
+2ф1ф
+2х1х
+2ц1ц
+2ч1ч
+2ш1ш
+2щ1щ
+2й1й
+3ння
+3ття
+3ттю
+3лля
+3ллє
+3ллю
+3ддя
+д4ж
+д4з
+а2й
+е2й
+и2й
+і2й
+о2й
+у2й
+ю2й
+я2й
+є2й
+ї2й
+3й6о
+ь6о
+6ь
+.бд6
+.бр6
+.вб6
+.вг6
+.вд6
+.вж6
+.вз6
+.вз6д6
+.вк6
+.вл6
+.вм6
+.вп6
+.вп6х6
+.вс6
+.вс6т6
+.вт6
+.вш6к6
+.дж6
+.дз6
+.дл6
+.дс6
+.зб6
+.зг6
+.зд6
+.зд6з6
+.зл6
+.зс6
+.зс6к6
+.зс6т6
+.зч6
+.зш6
+.зш6к6
+.зґ6
+.йш6
+.кл6
+.кп6
+.кс6
+.кх6
+.кш6
+.лк6с6
+.лс6
+.ль6
+.мс6
+.мф6
+.нб6
+.пр6
+.пс6
+.пх6
+.рт6
+.ск6
+.ск6л6
+.сл6
+.сп6
+.сп6л6
+.сп6х6
+.ст6
+.сх6
+.сх6л6
+.тк6
+.тр6
+.тх6
+.ть6
+.фл6
+.хл6
+.ць6
+.чх6
+.шк6
+.шл6
+.шп6
+.шт6
+6бв.
+6бз.
+6бй.
+6бл.
+6б6ль.
+6бн.
+6бр.
+6бс.
+6б6ст.
+6б6с6тв.
+6б6с6тр.
+6б6с6ьк.
+6б6ць.
+6вб.
+6вв.
+6вд.
+6в6др.
+6в6дь.
+6вж.
+6вз.
+6в6зь.
+6вй.
+6вк.
+6вл.
+6в6ль.
+6вм.
+6вн.
+6вп.
+6вр.
+6вс.
+6в6с6тв.
+6в6с6ть.
+6в6сь.
+6в6с6ьк.
+6вт.
+6вх.
+6в6ць.
+6вч.
+6вш.
+6вщ.
+6гв.
+6гг.
+6гд.
+6гл.
+6г6ль.
+6гм.
+6гн.
+6гр.
+6гс.
+6г6с6тв.
+6г6сь.
+6гт.
+6дж.
+6дз.
+6д6зь.
+6дл.
+6дм.
+6дн.
+6др.
+6д6с6тв.
+6д6с6ьк.
+6дт.
+6дь.
+6д6ь6сь.
+6жб.
+6жв.
+6ж6дь.
+6ж6сь.
+6зв.
+6зг.
+6зд.
+6з6дв.
+6з6дн.
+6з6дь.
+6зк.
+6зл.
+6зм.
+6зн.
+6з6нь.
+6зр.
+6з6сь.
+6зь.
+6з6ьб.
+6з6ьк.
+6йб.
+6йв.
+6йг.
+6йд.
+6йз.
+6йк.
+6й6кл.
+6йл.
+6й6ль.
+6йм.
+6й6мс.
+6йн.
+6й6нс.
+6йп.
+6йр.
+6йс.
+6й6ст.
+6й6с6тв.
+6й6с6тр.
+6й6сь.
+6й6с6ьк.
+6йт.
+6й6тс.
+6йф.
+6йх.
+6йц.
+6йч.
+6йш.
+6кв.
+6кк.
+6кл.
+6к6ль.
+6кр.
+6кс.
+6к6ст.
+6к6сь.
+6кт.
+6к6тр.
+6кх.
+6кш.
+6лб.
+6лг.
+6лд.
+6лк.
+6лл.
+6л6ль.
+6лм.
+6л6мс.
+6лн.
+6лп.
+6лс.
+6лт.
+6л6хв.
+6ль.
+6л6ьб.
+6л6ьв.
+6л6ьг.
+6л6ьд.
+6л6ь6дс.
+6л6ьз.
+6л6ьк.
+6л6ьм.
+6л6ьн.
+6л6ьп.
+6л6ьс.
+6л6ь6ств.
+6л6ь6сь.
+6л6ь6ськ.
+6л6ьт.
+6л6ь6тр.
+6л6ьф.
+6л6ьх.
+6л6ьц.
+6л6ьч.
+6л6ьш.
+6л6ьщ.
+6мб.
+6м6б6ль.
+6м6бр.
+6мг.
+6мж.
+6мк.
+6мл.
+6м6ль.
+6мм.
+6мн.
+6мп.
+6мр.
+6мс.
+6м6с6тв.
+6м6сь.
+6м6с6ьк.
+6мт.
+6мф.
+6мх.
+6мш.
+6нв.
+6нг.
+6н6гл.
+6н6г6ль.
+6н6гр.
+6н6гс.
+6нд.
+6н6дж.
+6н6дз.
+6н6дп.
+6н6др.
+6нж.
+6нз.
+6нк.
+6н6кс.
+6н6кт.
+6нм.
+6нн.
+6нр.
+6нс.
+6н6ск.
+6н6ст.
+6н6с6тв.
+6н6с6тр.
+6н6с6ьк.
+6н6с6ькй.
+6нт.
+6н6тк.
+6н6тр.
+6н6т6ств.
+6н6ть.
+6нф.
+6нх.
+6нц.
+6н6ць.
+6нч.
+6нш.
+6нь.
+6н6ьб.
+6н6ьг.
+6н6ьк.
+6н6ь6сь.
+6пд.
+6пл.
+6пр.
+6пс.
+6п6с6тв.
+6п6сь.
+6пт.
+6п6тр.
+6пф.
+6пц.
+6рб.
+6рв.
+6рг.
+6рд.
+6р6дв.
+6р6дж.
+6р6дь.
+6рж.
+6рз.
+6р6зн.
+6р6зь.
+6рк.
+6р6кс.
+6р6кт.
+6рл.
+6р6ль.
+6р6л6ьз.
+6рм.
+6рн.
+6р6нс.
+6р6н6ст.
+6р6нь.
+6рп.
+6рр.
+6рс.
+6р6ср.
+6р6ст.
+6р6с6тв.
+6р6с6ть.
+6р6сь.
+6р6с6ьк.
+6рт.
+6р6тв.
+6р6тр.
+6р6ть.
+6рф.
+6рх.
+6рц.
+6р6ць.
+6рч.
+6рш.
+6рщ.
+6р6щ6сь.
+6рь.
+6с6дп.
+6с6д6рп.
+6ск.
+6сл.
+6с6ль.
+6см.
+6сн.
+6сп.
+6сс.
+6ст.
+6с6тв.
+6с6тй.
+6с6тм.
+6с6тр.
+6с6т6рь.
+6с6ть.
+6с6ць.
+6сь.
+6с6ьб.
+6с6ьк.
+6с6ьм.
+6тв.
+6т6вт.
+6т6зт.
+6тл.
+6т6ль.
+6тм.
+6т6мр.
+6тр.
+6тс.
+6т6с6тв.
+6т6с6ьк.
+6тт.
+6тц.
+6тч.
+6ть.
+6т6ь6сь.
+6фм.
+6фр.
+6ф6с6тв.
+6фт.
+6ф6ть.
+6фф.
+6фь.
+6хв.
+6хм.
+6хн.
+6хр.
+6хт.
+6хш.
+6ц6тв.
+6ць.
+6ц6ьк.
+6чб.
+6чм.
+6чн.
+6чт.
+6шв.
+6ш6ль.
+6шм.
+6шн.
+6ш6нл.
+6ш6сь.
+6шт.
+6ш6тв.
+6щ6сь.
+.бе4з3
+.безу4
+.бе5з4о3д
+.без5о4соб
+.безві4д3
+.без3ро4з3
+виї4
+.ві5д4ом
+.ві5д4озв
+.ві5д4ун
+віду4ч
+.ві5д4а
+.ві5д4ер
+.ві5д4і
+.ві4д3
+.мі4ж3
+безві4д3
+ові4д3
+ді4єві4д3
+за4вві4д3
+неві4д3
+про4ф3ві4д3
+спе4ц3ві4д3
+співві4д3
+те4х3ві4д3
+.пере4д3бач
+.пере4д3виб
+.пере4д3г
+.пере4д3д
+.пере4д3м
+.пере4д3ост
+.пере4д3пла
+.пере4д3пок
+.пере4д3р
+.пере4д3св
+.пере4д3умов
+.пере4д3усі
+.пере4д3фр
+.пере4д3ч
+.пере3
+.пона4д3
+.пона5д4і
+.пона5д4и
+.пона5д4я
+3п4ре
+3п4ри
+приї4
+3п4ро
+3п4рі
+.пі5д4о
+.пі5д4і
+.пі4д3
+.пі5д4е
+.пі5д4и
+.пі5д4у
+.пі4в3
+.спі4в3
+.напі4в3
+.ро5з4і
+.ро5з4е
+ро5з4йом
+.ро5з4а
+.ро4з3
+.чере4з3
+оо4б
+ооб3м
+ооб3ро
+за5о4р
+до5о4р
+по5о4р
+пере5о4р
+пі6д5о4р
+бе4з5і4дей
+за3ю4ш
+за3я4ло
+коу4роч
+зу4роч
+наду4роч
+позау4роч
+поу4роч
+приу4роч
+на4й3у4бог
+нао4р
+прио4р
+неу4к
+3в4б4лаг
+3в4к4лад
+3в4п4лив
+3в4п4равн
+3в4р4одлив
+3в4т4рут
+3в4т4руч
+3з4б4рой
+3з4б4рою
+3з4б4роє
+3й4ш4л
+3м4к4не
+3м4к4ну
+3м4к4ні
+3п4с4ков
+3с4к4лад
+3с4к4ле
+3с4к4лит
+3с4к4ло
+3с4к4рипт
+3с4п4лав
+3с4п4лат
+3с4п4лач
+3с4п4рав
+3с4п4ритн
+3с4п4рият
+3с4п4ромо
+3с4т4вор
+3с4т4ражд
+3с4т4рах
+3с4т4риб
+3с4т4риж
+3с4т4рой
+3с4т4рок
+3с4т4ром
+3с4т4роф
+3с4т4роч
+3с4т4рою
+3с4т4роя
+3с4т4роє
+3с4т4рої
+3с4т4рукт
+3с4т4рукц
+3с4т4рій
+3с4т4ріл
+3с4т4річ
+3т4к4нен
+3т4ь4мар
+3т4ь4мяні
+3у4п4рав
+3блаж
+3ближ
+3близ
+3блиск
+3блок
+3блоці
+3бран
+3брати
+3брест
+3бризк
+3британ
+3бруд
+3в4бив
+3в4веден
+3в4дал
+3в4довз
+3в4довол
+3в4живан
+3в4лад
+3в4ласн
+3в4лашт
+3в4лов
+3в4певн
+3в4поряд
+3в4разлив
+3в4рожай
+3в4сюд
+3в4тіл
+3глад
+3глиб
+3глин
+3глоб
+3глуз
+3глуш
+3гляд
+3глян
+3гнан
+3гнил
+3гноз
+3гнучк
+3грав
+3град
+3грай
+3грам
+3гран
+3грати
+3граф
+3граш
+3граю
+3грає
+3грес
+3грець
+3гроб
+3грож
+3гроз
+3громад
+3груван
+3грунт
+3груп
+3грів
+3гріт
+3гріш
+3г4ідро
+3д4ан
+3д4бав
+3д4бал
+3д4бан
+3д4бат
+3д4бає
+3двиг
+3двою
+3двоє
+3двій
+3двір
+3двічі
+3драж
+3дром
+3друж
+3друк
+3дряп
+3дріб
+3дріма
+3жвав
+3жміть
+3жріть
+3з4бага
+3з4баланс
+3з4був
+3з4бут
+3зваж
+3зван
+3звед
+3звел
+3звест
+3звись
+3звич
+3звищ
+3зворуш
+3звук
+3звуч
+3звіт
+3з4год
+3з4дат
+3з4довж
+3з4доров
+3з4дійсн
+3змін
+3зйом
+3зміш
+3знав
+3знай
+3знак
+3знал
+3знан
+3знат
+3знаход
+3знач
+3знаю
+3знає
+3зниж
+3знім
+3зрозум
+3зрюв
+3зрів
+3зріл
+3зрін
+3з4чеп
+3й4ма
+3й4менн
+3й4мищ
+3й4мовірн
+3й4му.
+3й4муть
+3й4міть
+3й4шов
+3м4нож
+3м4ріть
+3м4щен
+3п4сов
+3п4сон
+3п4сув
+3р4вав
+3р4вати
+3р4віть
+3с4кид
+3с4кок
+3с4коп
+3с4кор
+3с4короч
+3с4коч
+3с4кіль
+3с4кіпл
+3с4пад
+3с4пект
+3с4перм
+3с4пин
+3с4повід
+3с4пожив
+3с4постер
+3с4пі
+3с4піть
+3с4піш
+3с4табіл
+3с4тав
+3с4тад
+3с4таз
+3с4тайн
+3с4тал
+3с4тан
+3с4тар
+3с4тара
+3с4тат
+3с4тач
+3с4тає
+3с4теп
+3с4тереж
+3с4теріг
+3с4тиг
+3с4тиж
+3с4тисл
+3с4титу
+3с4товб
+3с4той
+3с4торон
+3с4торін
+3с4тосо
+3с4тосу
+3с4тою
+3с4тоян
+3с4туп
+3с4тяг
+3с4тіб
+3с4тій
+3с4тіль
+3с4тір
+3с4фер
+3с4хил
+3с4хов
+3с4хід
+3т4кан
+3х4то
+3ш4код
+3ш4кол
+3ш4кідл
+3ш4кіл
+3ш4кір
+3ш4таб
+3ш4туч
+3ґрунт
+3а4вторит
+3а4гент
+3а4грес
+3а4декват
+3а4дитив
+3а4зарт
+3а4ктив
+3а4ктуал
+3а4курат
+3а4куст
+3а4кцепт
+3а4кциз
+3а4лергі
+3а4матор
+3а4наліз
+3а4натом
+3а4парат
+3а4пеляц
+3а4постол
+3а4птеч
+3а4ргумен
+3а4ромат
+3а4соці
+3а4спект
+3а4тлет
+3а4халі
+3е4колог
+3е4коном
+3е4легант
+3е4лектр
+3е4лемент
+3е4моці
+3е4мігр
+3е4нерг
+3е4стакад
+3е4стет
+3е4тап
+3о4береж
+3о4бира
+3о4борон
+3о4бід
+3о4біц
+3о4даль
+3о4дяг
+3о4збро
+3о4крем
+3о4перат
+3о4плат
+3о4птим
+3о4пуст
+3о4пуше
+3о4пуще
+3о4рдинац
+3о4ренд
+3о4соб
+3о4сяжн
+3о4холо
+3о4хорон
+3о4хоч
+3о4чисн
+3о4чищ
+3у4ваг
+3у4важ
+3у4гав
+3у4згод
+3у4клад
+3у4компл
+3у4крупн
+3у4люблен
+3у4мит
+3у4міл
+3у4перед
+3у4разлив
+3у4рбан
+3у4рочист
+3у4ряд
+3у4рядов
+3у4спіш
+3у4станов
+3у4стпіш
+3у4сувати
+3у4твор
+3у4тробн
+3я4дерн
+3я4зик
+3я4кіс
+3я4рус
+3я4скрав
+3є4д3н
+3є4дин
+3є4писк
+3є4рей
+3і4зотоп
+3і4люстр
+3і4мовір
+3і4нтенс
+3і4нформ
+3і4ніціат
+3і4снув
+3ї4ждж
+3ї4зд
+3ї4ст
+3ї4хав
+3ї4хат
+.заї4к
+.заї4ц
+.заї4ч
+.наї4д
+аві4а
+авої4д
+ае4тил
+альбі5он
+ахої4д
+ауді4о
+ай4с3берг
+бактері4о
+ба4с3енер
+ба4с3антра
+.бе5зе.
+бей4сбол
+бе5кон
+бйор4нс
+бі4о3
+бо4г3дан
+бран4д
+брі4дж3порт
+без5і4мен
+бо4є3гол
+бо4є3гот
+бо4є3зап
+бо4є3здат
+бо4є3комп
+бо4є3пост
+бо4є3прип
+бори4с5п
+4в3антрац
+вер4х3н
+ви3й4д
+вина3й4д
+ви3й4т
+вина3й4т
+від7зна
+ві5д4ен
+ві5д4е4о
+ві5д4ом
+від5о4браж
+від5о4браз
+во4с5ко
+водо5с4ток
+водо5з4бір
+воль4т3метр
+воль4т3ампер
+ге2ть3ман
+ге4о
+го4с4п5роз
+гі4д5ро5мет
+4д7зем
+дер4ж5а4том
+дер4ж5а4дм
+дер4ж5бюдж
+дер4ж5вид
+дер4ж5дум
+дер4ж5замов
+дер4ж5ком
+дер4ж5нафт
+дер4ж5реєс
+дер4ж3без
+дер4ж3резерв
+дер4ж5стр
+дер4ж5служ
+двох4а5том
+джен4тль
+дисбаланс
+ди4с3гарм
+ди4с3квал
+ди4с3комф
+ди4с3конт
+ди4с3кред
+ди4с3крет
+ди4с3крец
+ди4с3крим
+ди4с3кусі
+ди4с3куту
+ди4с3лок
+ди4с3парит
+ди4с3перс
+ди4с3петч
+ди4с3пле
+ди4с3плей
+ди4с3пози
+ди4с3проп
+ди4с3пут
+ди4с3тил
+ди4с3триб
+ди4с3троф
+ди4с3функц
+ді3й4т
+ді3й4д
+д4ні3п4р
+.дої4в
+.дої4л
+.дої5ль
+дої4д
+дої4м
+дої4х
+дої4ж
+дої4ст
+до3з4вол
+до3з4віл
+дорого5в4каз
+еу4стр
+ео4сві
+енерго3з4береж
+енерго3з4беріг
+ек2с1к
+ек2с1п
+ек2с1т
+ек2с1ц
+єв4р3атом
+єпі4с5коп
+єпи4с5коп
+за4п3част
+заї4д
+заї4ж
+заї4з
+заї4л
+заї4м
+заї4х
+зе4кономити
+зна3й4д
+зна3й4т
+зо4ка
+зо4ке
+зо4ки
+зо4ку
+зо4кі
+игої4д
+ий4ти
+іе4тил
+і4л3е4тил
+ій4ти
+інфор4м3аген
+йо4сві
+каза4х3стан
+квої4д
+корої4д
+квар4т3плат
+киї4венер
+кон4трре
+кон4тр3арг
+жко4м5а4том
+кому4ненерг
+мі4н5е4ко
+мі4н5е4нер
+мо4к5рий
+на3б4лиз
+на3в4ряд
+на3в4ча
+на3з4в
+на4д7з4в
+наї4вс
+наї4вш
+наї4ж
+наї4з
+наї4л
+наї4м
+наї4с
+наї4х
+на4й3а
+на4й3е
+на4й3обереж
+на4й7о4бер
+на4й7о4гид
+на4й7о4гол
+на4й7о4гряд
+на4й7о4пук
+на4й7о4хай
+на4й3масл
+на4й3спри
+на4й3якіс
+на3в4чен
+на3в4чіть
+не3в4том
+не3д4бан
+на3д4бан
+не3з4вич
+не3з4важ
+нео4пал
+недої4
+неї4ст
+на5п4лив
+ні4т5рат
+оної4д
+оо4пал
+ео4пал
+обі3д4ран
+обі3й4д
+обі3й4т
+об5у4мов
+онаї4д
+оо4сві
+оо4к
+оу4стр
+оа4том
+об4лдер4ж
+об4л3а4дмін
+переї4д
+переї4ж
+переї4з
+переї4л
+переї4с
+переї4х
+пере5п4лив
+пере3й4д
+пре4й4с
+пере3й4т
+перег4ній
+перед5о4бід
+пере3в4том
+пере4д5см
+перед5у4мов
+під5о4дин
+пів5о4с4тр
+пі5в4ень
+по3б4лизу
+по3в4тор
+поч4не
+поч4ни
+поч4ну
+поя4в
+по3в4чен
+по3в4чіть
+по3д4роб
+по3д4раз
+по3д4во
+по5ж4ніть
+по5з4бав
+.пої4
+пої4д
+прої4
+пої4зд
+по4с4т5радян
+по4с4т5кому
+по4с4т3декр
+по4с4т3контра
+по4с4т3менопауз
+по4с4тприват
+по4с4т3раді
+по4с4т5соці
+пос4т3кап
+пос4т3ком
+пос4т3нат
+пос4т3проц
+пос4т3соц
+пос4т3фікс
+при3й4т
+про3с4тирад
+про4ф3с
+полі4т5екон
+пор4т3н
+пор4т3рет
+пор4т3фел
+при3й4д
+при4нцип
+про4ект3н
+про3б4лем
+про4м3май
+пр4о5плат
+раді4о
+рай3в4но
+ро4з5д4во
+ро4з5мінний
+роз5у4чен
+роз5і4мен
+роз5вант
+роз5вин
+роз5вит
+ро4з5діл
+ро4з5гор
+ро4з5вер
+ро4з5чеп
+руко5с4тиск
+ро5з4ум
+ро4з3гром
+ро4з3лив
+рмої4д
+сан4к4т3
+сеї4д
+серцеї4д
+спе4ц3кур
+спе4ц3мон
+спе4цпр
+спе4ц3с
+спор4т3вир
+спор4т3зал
+спор4т3ком
+спор4т3клуб
+спор4т3май
+спор4т4с3ме
+сор4тн
+3с4промож
+сь4квуг
+стат5упр
+тор4г3пред
+тран4с3
+тур4к3мен
+цук3ро
+у4к4р
+укр3а4вт
+укр3а4гр
+укр3е4кс
+укр3і4н4банк
+убої4д
+чорно3б4рив
+цен4т4р3енерг
+ясої4д
+ви3у4ч
+за3у4ч
+на3у4ч
+недо3у4ч
+не3у4ч
+під3у4ч
+пед3у4чи
+пере3у4ч
+само3у4ч
+вия4в
+зая4в
+ная4в
+уя4в
+во4євод
+во4єнач
+сво4єчас
+сво4єкорис
+сво4єрід
+хво4є3г4риз
+гелі4о
+ді4о
+еті4о
+мі4о
+і4он
+полі4о
+соці4о
+фізі4о
+хімі4о
+гоме4о
+ді4алог
+ді4оген
+дея4к
+оо4динок
+ао4пік
+ао4ха
+ео4ха
+зо6о
+ка5нал
+оі4зол
+міжу4соб
+мете4о
+абия4к
+нія4к
+вия4сн
+най3я4сн
+нея4сн
+поя4сн
+проя4сн
+ро5з4ора.
+ро5з4о5рам
+ро5з4орах
+ро5з4ори
+ро5з4оро
+ро5з4ору
+ро5з4оря
+ро5з4орю
+ро5з4орі
+ро6з5о4ри.
+розо4ра
+розо4ре
+розо4реш
+розо4рн
+напоу4м
+неа4би
+ео4цін
+оо4цін
+доу4к
+доу4м
+ео4бур
+ео4голош
+ео4зор
+бальне4о
+не4оліт
+не4омальт
+не4оклас
+не4окомун
+не4оландш
+не4олог
+не4олібер
+не4онац
+не4офіт
+нею4н
+нея4к
+нея4рок
+но4к3а4ут
+пі5в4оні
+піво4с
+пале4о
+па4н3о4тець
+.пе4ом.
+д3у4сім
+п4о5бере
+ао4хот
+ое4ко
+ео4хот
+ео4щад
+ао4щад
+оо4чищ
+поя4с
+те4одоліт
+те4олог
+те4ософ
+оо4біг
+оу4сун
+оу4ком
+пів3о4вал
+а3у4дар
+о3у4дар
+з3у4дар
+в3у4дар
+контр3у4дар
+о3о4кисл
+и3о4кисл
+ень7о4кисл
+е3о4кисл
+х3о4кисл
+и3і4стор
+о3і4стор
+і3і4стор
+а3і4стор
+я3і4стор
+е3і4стор
+наді4стор
+най3і4стор
+пів3і4стор
+перед3і4стор
+пост3і4стор
+ар4т3афіш
+ар4т3взвод
+ар4т3десант
+ар4т3кафе
+ар4т3майс
+ар4т3медіа
+ар4т3мейс
+ар4т3мін
+ар4т3о4бстр
+ар4т3о4дин
+ар4т3о4збр
+ар4т3під
+ар4т3рин
+ар4т3у4стан
+ар4т3факт
+ар4т3хім
+ар4т3центр
+наді4стот
+найі4стот
+еі4стот
+оі4стот
+ау4т3екол
+оо4чист
+з3а4кт
+оа4кт
+еа4кт
+гіпер3а4кт
+найа4кт
+піва4кт
+ао4браз
+ео4браз
+оо4браз
+граф3о4браз
+най3о4браз
+супер3о4браз
+ар4т3мейст
+баге4р3мейст
+бале4т3мейст
+бран4д3мейст
+ва4ль4д3мейст
+ве4ль4т3мейст
+го4ф3мейст
+гро4с3мейст
+декре4т3мейст
+до4к3мейст
+капе4ль3мейст
+кварти4р3мейст
+конце4р4т3мейст
+кра4н3мейст
+полі4ц3мейст
+по4ш4т3мейст
+фо4р4с4т3мейст
+хо4р3мейст
+шапі4т3мейст
+шта4л3мейст
+єге4р3мейст
+иа4варі
+яа4варі
+оа4варі
+еа4варі
+беза4варі
+між3а4варі
+над3а4варі
+пост3а4варі
+напів3а4варі
+перед3а4варі
+супер3а4варі
+аа4дрес
+еа4дрес
+оа4дрес
+іа4дрес
+без3а4дрес
+ае4фект
+ее4фект
+ое4фект
+най3е4фект
+супер3е4фект
+ое4місі
+ие4місі
+яе4місі
+ее4місі
+безе4місі
+гіпер3е4місі
+еу4бог
+й3у4бог
+ий4ня
+зай4ня
+здій4ня
+най4ня
+обій4ня
+перей4ня
+підій4ня
+прий4м
+пій4м
+дій4ма
+вий4м
+най4ма
+зай4м
+д4о3й4м
+обой4м
+прой4м
+обій4м
+перей4м
+безу4гл
+безу4пин
+бло4к3пост
+.блі4ц3ана
+.блі4ц3криг
+.блі4ц3опит
+.блі4ц3торг
+.блі4ц3тур
+.блі4ц3і4спит
+о3а4наліз
+бак3а4наліз
+ц3а4наліз
+ген3а4наліз
+з3а4наліз
+м3а4наліз
+нт3а4наліз
+між3а4наліз
+полі3а4наліз
+ре3а4наліз
+оу4год
+ау4год
+еу4год
+пів3у4год
+роз3у4год
+гос4п3у4год
+ео4пис
+оо4пис
+ао4пис
+бо4р4т3мех
+бо4р4т3о4пер
+бо4р4т3про
+бо4р4т3рад
+бо4р4т3і4нж
+оа4каці
+оу4с
+оо4держ
+оа4на
+біблі4о
+.на3в4ч
+.ви3в4ч
+.до3в4ч
+.за3в4ч
+.по3в4ч
+.при3в4ч
+ана3в4ч
+ена3в4ч
+мона3в4ч
+жона3в4ч
+іона3в4ч
+ови3в4ч
+еви3в4ч
+едо3в4ч
+оза3в4ч
+по3в4ча
+.ом4рі
+е3м4рій
+.ви3м4р
+.віді3м4р
+.зав3м4р
+.за3м4р
+.зі3м4р
+.на3м4р
+.пере3м4р
+.по3м4р
+.при3м4р
+.роз3м4р
+.ум4ри
+.ум4рі
+.ум4ру
+.ум4ре
+во4станнє
+най3о4станн
+перед3о4станн
+ие4стет
+ое4стет
+ее4стет
+й3е4стет
+пан3е4стет
+пар3е4стет
+оо4ктан
+іо4ктан
+оо4плачув
+ео4плачув
+перед3о4пла
+виу4ди
+о3в4каз
+е3в4каз} \ No newline at end of file
diff --git a/tex/context/patterns/lang-uk.rme b/tex/context/patterns/lang-uk.rme
new file mode 100644
index 000000000..9d6e5ee88
--- /dev/null
+++ b/tex/context/patterns/lang-uk.rme
@@ -0,0 +1,70 @@
+% generated by mtxrun --script pattern --convert
+
+% This file is part of hyph-utf8 package and resulted from
+% semi-manual conversions of hyphenation patterns into UTF-8 in June 2008.
+%
+% Source: TODO:WRITEME (yyyy-mm-dd)
+% Author: Maksym Polyakov <polyama at auburn.edu>, <mpoliak at i.com.ua>
+%
+% The above mentioned file should become obsolete,
+% and the author of the original file should preferaby modify this file instead.
+%
+% Modificatios were needed in order to support native UTF-8 engines,
+% but functionality (hopefully) didn't change in any way, at least not intentionally.
+% This file is no longer stand-alone; at least for 8-bit engines
+% you probably want to use loadhyph-foo.tex (which will load this file) instead.
+%
+% Modifications were done by Jonathan Kew, Mojca Miklavec & Arthur Reutenauer
+% with help & support from:
+% - Karl Berry, who gave us free hands and all resources
+% - Taco Hoekwater, with useful macros
+% - Hans Hagen, who did the unicodifisation of patterns already long before
+% and helped with testing, suggestions and bug reports
+% - Norbert Preining, who tested & integrated patterns into TeX Live
+%
+% However, the "copyright/copyleft" owner of patterns remains the original author.
+%
+% The copyright statement of this file is thus:
+%
+% Do with this file whatever needs to be done in future for the sake of
+% "a better world" as long as you respect the copyright of original file.
+% If you're the original author of patterns or taking over a new revolution,
+% plese remove all of the TUG comments & credits that we added here -
+% you are the Queen / the King, we are only the servants.
+%
+% If you want to change this file, rather than uploading directly to CTAN,
+% we would be grateful if you could send it to us (http://tug.org/tex-hyphen)
+% or ask for credentials for SVN repository and commit it yourself;
+% we will then upload the whole "package" to CTAN.
+%
+% Before a new "pattern-revolution" starts,
+% please try to follow some guidelines if possible:
+%
+% - \lccode is *forbidden*, and I really mean it
+% - all the patterns should be in UTF-8
+% - the only "allowed" TeX commands in this file are: \patterns, \hyphenation,
+% and if you really cannot do without, also \input and \message
+% - in particular, please no \catcode or \lccode changes,
+% they belong to loadhyph-foo.tex,
+% and no \lefthyphenmin and \righthyphenmin,
+% they have no influence here and belong elsewhere
+% - \begingroup and/or \endinput is not needed
+% - feel free to do whatever you want inside comments
+%
+% We know that TeX is extremely powerful, but give a stupid parser
+% at least a chance to read your patterns.
+%
+% For more unformation see
+%
+% http://tug.org/tex-hyphen
+%
+%------------------------------------------------------------------------------
+%
+% Ukrainian hyphenation patterns in LCY (cp866nav) encoding.
+% Copyright 1998-2001 Maksym Polyakov.
+% Released 2001/05/10.
+% This file can be redistributed and/or modified
+% under the terms of the LaTeX Project Public License (lppl).
+% Please, send bug reports via e-mail:
+% polyama@auburn.edu
+% mpoliak@i.com.ua \ No newline at end of file
diff --git a/tex/context/test/context-test.tex b/tex/context/test/context-test.tex
new file mode 100644
index 000000000..3cf002baf
--- /dev/null
+++ b/tex/context/test/context-test.tex
@@ -0,0 +1,27 @@
+\starttext
+
+\startmode[mkiv]
+
+ \startluacode
+ tex.sprint("hello")
+ \stopluacode
+
+ \startMPcode
+ draw textext("hello") rotated 45 ;
+ \stopMPcode
+
+ \framed{hello}
+
+\stopmode
+
+\startnotmode[mkiv]
+
+ \startMPcode
+ draw textext("hello") rotated -45 ;
+ \stopMPcode
+
+ \framed{hello}
+
+\stopnotmode
+
+\stoptext
diff --git a/tex/context/user/cont-sys.rme b/tex/context/user/cont-sys.rme
index 335a7d984..11c0141e7 100644
--- a/tex/context/user/cont-sys.rme
+++ b/tex/context/user/cont-sys.rme
@@ -14,8 +14,8 @@
\unprotect
% Speed up typescript loading, but at the cost of much memory:
-%
-% \preloadtypescripts
+
+\preloadtypescripts
% If you want another default font:
%
@@ -121,7 +121,6 @@
% When you have your own fonts installed, you may want to predefine:
%
% \usetypescriptfile[type-buy]
-% \usetypescriptfile [type-gyr]
% Some styles default to Lucida Bright. You can overload
% Lucida by Times cum suis. Watch out, the pos collection
@@ -158,8 +157,8 @@
% Enabling run time \METAPOST\ (also enable \write18 in
% texmf.cnf):
-% \runMPgraphicstrue
-% \runMPTEXgraphicstrue
+\runMPgraphicstrue
+\runMPTEXgraphicstrue
% This saves some runtime, but needs a format, which you can
% make with 'texexec --make --alone metafun'. Make sure that
diff --git a/tex/generic/context/luatex-basics.tex b/tex/generic/context/luatex-basics.tex
new file mode 100644
index 000000000..8308204d5
--- /dev/null
+++ b/tex/generic/context/luatex-basics.tex
@@ -0,0 +1,21 @@
+%D \module
+%D [ file=luatex-basics,
+%D version=2009.12.01,
+%D title=\LUATEX\ Support Macros,
+%D subtitle=Attribute Allocation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=public domain]
+
+%D As soon as we feel the need this file will file will contain an extension
+%D to the standard plain register allocation. For the moment we stick to a
+%D rather dumb attribute allocator. We start at 256 because we don't want
+%D any interference with the attributes used in the font handler.
+
+\newcount \lastallocatedattribute \lastallocatedattribute=255
+
+\def\newattribute#1%
+ {\global\advance\lastallocatedattribute 1
+ \attributedef#1\lastallocatedattribute}
+
+\endinput
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
new file mode 100644
index 000000000..15d12a584
--- /dev/null
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -0,0 +1,11070 @@
+-- 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 : 05/28/09 11:25:26
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-string'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local sub, gsub, find, match, gmatch, format, char, byte, rep = string.sub, string.gsub, string.find, string.match, string.gmatch, string.format, string.char, string.byte, string.rep
+
+if not string.split then
+
+ -- this will be overloaded by a faster lpeg variant
+
+ function string:split(pattern)
+ if #self > 0 then
+ local t = { }
+ for s in gmatch(self..pattern,"(.-)"..pattern) do
+ t[#t+1] = s
+ end
+ return t
+ else
+ return { }
+ end
+ end
+
+end
+
+local chr_to_esc = {
+ ["%"] = "%%",
+ ["."] = "%.",
+ ["+"] = "%+", ["-"] = "%-", ["*"] = "%*",
+ ["^"] = "%^", ["$"] = "%$",
+ ["["] = "%[", ["]"] = "%]",
+ ["("] = "%(", [")"] = "%)",
+ ["{"] = "%{", ["}"] = "%}"
+}
+
+string.chr_to_esc = chr_to_esc
+
+function string:esc() -- variant 2
+ return (gsub(self,"(.)",chr_to_esc))
+end
+
+function string:unquote()
+ return (gsub(self,"^([\"\'])(.*)%1$","%2"))
+end
+
+function string:quote() -- we could use format("%q")
+ return '"' .. self:unquote() .. '"'
+end
+
+function string:count(pattern) -- variant 3
+ local n = 0
+ for _ in gmatch(self,pattern) do
+ n = n + 1
+ end
+ return n
+end
+
+function string:limit(n,sentinel)
+ if #self > n then
+ sentinel = sentinel or " ..."
+ return sub(self,1,(n-#sentinel)) .. sentinel
+ else
+ return self
+ end
+end
+
+function string:strip()
+ return (gsub(self,"^%s*(.-)%s*$", "%1"))
+end
+
+function string:is_empty()
+ return not find(find,"%S")
+end
+
+function string:enhance(pattern,action)
+ local ok, n = true, 0
+ while ok do
+ ok = false
+ self = gsub(self,pattern, function(...)
+ ok, n = true, n + 1
+ return action(...)
+ end)
+ end
+ return self, n
+end
+
+local chr_to_hex, hex_to_chr = { }, { }
+
+for i=0,255 do
+ local c, h = char(i), format("%02X",i)
+ chr_to_hex[c], hex_to_chr[h] = h, c
+end
+
+function string:to_hex()
+ return (gsub(self or "","(.)",chr_to_hex))
+end
+
+function string:from_hex()
+ return (gsub(self or "","(..)",hex_to_chr))
+end
+
+if not string.characters then
+
+ local function nextchar(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, str:sub(index,index)
+ end
+ function string:characters()
+ return nextchar, self, 0
+ end
+ local function nextbyte(str, index)
+ index = index + 1
+ return (index <= #str) and index or nil, byte(str:sub(index,index))
+ end
+ function string:bytes()
+ return nextbyte, self, 0
+ end
+
+end
+
+-- we can use format for this (neg n)
+
+function string:rpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self .. self.rep(chr or " ",m)
+ else
+ return self
+ end
+end
+
+function string:lpadd(n,chr)
+ local m = n-#self
+ if m > 0 then
+ return self.rep(chr or " ",m) .. self
+ else
+ return self
+ end
+end
+
+string.padd = string.rpadd
+
+function is_number(str) -- tonumber
+ return find(str,"^[%-%+]?[%d]-%.?[%d+]$") == 1
+end
+
+--~ print(is_number("1"))
+--~ print(is_number("1.1"))
+--~ print(is_number(".1"))
+--~ print(is_number("-0.1"))
+--~ print(is_number("+0.1"))
+--~ print(is_number("-.1"))
+--~ print(is_number("+.1"))
+
+function string:split_settings() -- no {} handling, see l-aux for lpeg variant
+ if find(self,"=") then
+ local t = { }
+ for k,v in gmatch(self,"(%a+)=([^%,]*)") do
+ t[k] = v
+ end
+ return t
+ else
+ return nil
+ end
+end
+
+local patterns_escapes = {
+ ["-"] = "%-",
+ ["."] = "%.",
+ ["+"] = "%+",
+ ["*"] = "%*",
+ ["%"] = "%%",
+ ["("] = "%)",
+ [")"] = "%)",
+ ["["] = "%[",
+ ["]"] = "%]",
+}
+
+function string:pattesc()
+ return (gsub(self,".",patterns_escapes))
+end
+
+function string:tohash()
+ local t = { }
+ for s in gmatch(self,"([^, ]+)") do -- lpeg
+ t[s] = true
+ end
+ return t
+end
+
+local pattern = lpeg.Ct(lpeg.C(1)^0)
+
+function string:totable()
+ return pattern:match(self)
+end
+
+--~ for _, str in ipairs {
+--~ "1234567123456712345671234567",
+--~ "a\tb\tc",
+--~ "aa\tbb\tcc",
+--~ "aaa\tbbb\tccc",
+--~ "aaaa\tbbbb\tcccc",
+--~ "aaaaa\tbbbbb\tccccc",
+--~ "aaaaaa\tbbbbbb\tcccccc",
+--~ } do print(string.tabtospace(str)) end
+
+function string.tabtospace(str,tab)
+ -- we don't handle embedded newlines
+ while true do
+ local s = find(str,"\t")
+ if s then
+ if not tab then tab = 7 end -- only when found
+ local d = tab-(s-1)%tab
+ if d > 0 then
+ str = gsub(str,"\t",rep(" ",d),1)
+ else
+ str = gsub(str,"\t","",1)
+ end
+ else
+ break
+ end
+ end
+ return str
+end
+
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-lpeg'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local P, S, Ct, C, Cs, Cc = lpeg.P, lpeg.S, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc
+
+--~ l-lpeg.lua :
+
+--~ lpeg.digit = lpeg.R('09')^1
+--~ lpeg.sign = lpeg.S('+-')^1
+--~ lpeg.cardinal = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.integer = lpeg.P(lpeg.sign^0 * lpeg.digit^1)
+--~ lpeg.float = lpeg.P(lpeg.sign^0 * lpeg.digit^0 * lpeg.P('.') * lpeg.digit^1)
+--~ lpeg.number = lpeg.float + lpeg.integer
+--~ lpeg.oct = lpeg.P("0") * lpeg.R('07')^1
+--~ lpeg.hex = lpeg.P("0x") * (lpeg.R('09') + lpeg.R('AF'))^1
+--~ lpeg.uppercase = lpeg.P("AZ")
+--~ lpeg.lowercase = lpeg.P("az")
+
+--~ lpeg.eol = lpeg.S('\r\n\f')^1 -- includes formfeed
+--~ lpeg.space = lpeg.S(' ')^1
+--~ lpeg.nonspace = lpeg.P(1-lpeg.space)^1
+--~ lpeg.whitespace = lpeg.S(' \r\n\f\t')^1
+--~ lpeg.nonwhitespace = lpeg.P(1-lpeg.whitespace)^1
+
+local hash = { }
+
+function lpeg.anywhere(pattern) --slightly adapted from website
+ return P { P(pattern) + 1 * lpeg.V(1) }
+end
+
+function lpeg.startswith(pattern) --slightly adapted
+ return P(pattern)
+end
+
+function lpeg.splitter(pattern, action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+
+-- variant:
+
+--~ local parser = lpeg.Ct(lpeg.splitat(newline))
+
+local crlf = P("\r\n")
+local cr = P("\r")
+local lf = P("\n")
+local space = S(" \t\f\v") -- + string.char(0xc2, 0xa0) if we want utf (cf mail roberto)
+local newline = crlf + cr + lf
+local spacing = space^0 * newline
+
+local empty = spacing * Cc("")
+local nonempty = Cs((1-spacing)^1) * spacing^-1
+local content = (empty + nonempty)^1
+
+local capture = Ct(content^0)
+
+function string:splitlines()
+ return capture:match(self)
+end
+
+lpeg.linebyline = content -- better make a sublibrary
+
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps->what->more")) -- oeps what more
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps->what->more")) -- oeps what->more
+--~ local p = lpeg.splitat("->",false) print(p:match("oeps")) -- oeps
+--~ local p = lpeg.splitat("->",true) print(p:match("oeps")) -- oeps
+
+local splitters_s, splitters_m = { }, { }
+
+local function splitat(separator,single)
+ local splitter = (single and splitters_s[separator]) or splitters_m[separator]
+ if not splitter then
+ separator = P(separator)
+ if single then
+ local other, any = C((1 - separator)^0), P(1)
+ splitter = other * (separator * C(any^0) + "")
+ splitters_s[separator] = splitter
+ else
+ local other = C((1 - separator)^0)
+ splitter = other * (separator * other)^0
+ splitters_m[separator] = splitter
+ end
+ end
+ return splitter
+end
+
+lpeg.splitat = splitat
+
+local cache = { }
+
+function string:split(separator)
+ local c = cache[separator]
+ if not c then
+ c = Ct(splitat(separator))
+ cache[separator] = c
+ end
+ return c:match(self)
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-boolean'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+boolean = boolean or { }
+
+local type, tonumber = type, tonumber
+
+function boolean.tonumber(b)
+ if b then return 1 else return 0 end
+end
+
+function toboolean(str,tolerant)
+ if tolerant then
+ local tstr = type(str)
+ if tstr == "string" then
+ return str == "true" or str == "yes" or str == "on" or str == "1" or str == "t"
+ elseif tstr == "number" then
+ return tonumber(str) ~= 0
+ elseif tstr == "nil" then
+ return false
+ else
+ return str
+ end
+ elseif str == "true" then
+ return true
+ elseif str == "false" then
+ return false
+ else
+ return str
+ end
+end
+
+function string.is_boolean(str)
+ if type(str) == "string" then
+ if str == "true" or str == "yes" or str == "on" or str == "t" then
+ return true
+ elseif str == "false" or str == "no" or str == "off" or str == "f" then
+ return false
+ end
+ end
+ return nil
+end
+
+function boolean.alwaystrue()
+ return true
+end
+
+function boolean.falsetrue()
+ return false
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-math'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
+
+if not math.round then
+ function math.round(x)
+ return floor(x + 0.5)
+ end
+end
+
+if not math.div then
+ function math.div(n,m)
+ return floor(n/m)
+ end
+end
+
+if not math.mod then
+ function math.mod(n,m)
+ return n % m
+ end
+end
+
+local pipi = 2*math.pi/360
+
+function math.sind(d)
+ return sin(d*pipi)
+end
+
+function math.cosd(d)
+ return cos(d*pipi)
+end
+
+function math.tand(d)
+ return tan(d*pipi)
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-table'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+table.join = table.concat
+
+local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
+local format, find, gsub, lower, dump = string.format, string.find, string.gsub, string.lower, string.dump
+local getmetatable, setmetatable = getmetatable, setmetatable
+local type, next, tostring, ipairs = type, next, tostring, ipairs
+
+function table.strip(tab)
+ local lst = { }
+ for i=1,#tab do
+ local s = gsub(tab[i],"^%s*(.-)%s*$","%1")
+ if s == "" then
+ -- skip this one
+ else
+ lst[#lst+1] = s
+ end
+ end
+ return lst
+end
+
+local function sortedkeys(tab)
+ local srt, kind = { }, 0 -- 0=unknown 1=string, 2=number 3=mixed
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ if kind == 3 then
+ -- no further check
+ else
+ local tkey = type(key)
+ if tkey == "string" then
+ -- if kind == 2 then kind = 3 else kind = 1 end
+ kind = (kind == 2 and 3) or 1
+ elseif tkey == "number" then
+ -- if kind == 1 then kind = 3 else kind = 2 end
+ kind = (kind == 1 and 3) or 2
+ else
+ kind = 3
+ end
+ end
+ end
+ if kind == 0 or kind == 3 then
+ sort(srt,function(a,b) return (tostring(a) < tostring(b)) end)
+ else
+ sort(srt)
+ end
+ return srt
+end
+
+local function sortedhashkeys(tab) -- fast one
+ local srt = { }
+ for key,_ in next, tab do
+ srt[#srt+1] = key
+ end
+ sort(srt)
+ return srt
+end
+
+table.sortedkeys = sortedkeys
+table.sortedhashkeys = sortedhashkeys
+
+function table.sortedpairs(t)
+ local s = sortedhashkeys(t) -- maybe just sortedkeys
+ local n = 0
+ local function kv(s)
+ n = n + 1
+ local k = s[n]
+ return k, t[k]
+ end
+ return kv, s
+end
+
+function table.append(t, list)
+ for _,v in next, list do
+ insert(t,v)
+ end
+end
+
+function table.prepend(t, list)
+ for k,v in next, list do
+ insert(t,k,v)
+ end
+end
+
+function table.merge(t, ...) -- first one is target
+ t = t or {}
+ local lst = {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ t[k] = v
+ end
+ end
+ return t
+end
+
+function table.merged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ for k, v in next, lst[i] do
+ tmp[k] = v
+ end
+ end
+ return tmp
+end
+
+function table.imerge(t, ...)
+ local lst = {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ t[#t+1] = nst[j]
+ end
+ end
+ return t
+end
+
+function table.imerged(...)
+ local tmp, lst = { }, {...}
+ for i=1,#lst do
+ local nst = lst[i]
+ for j=1,#nst do
+ tmp[#tmp+1] = nst[j]
+ end
+ end
+ return tmp
+end
+
+local function fastcopy(old) -- fast one
+ if old then
+ local new = { }
+ for k,v in next, old do
+ if type(v) == "table" then
+ new[k] = fastcopy(v) -- was just table.copy
+ else
+ new[k] = v
+ end
+ end
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
+ return new
+ else
+ return { }
+ end
+end
+
+local function copy(t, tables) -- taken from lua wiki, slightly adapted
+ tables = tables or { }
+ local tcopy = {}
+ if not tables[t] then
+ tables[t] = tcopy
+ end
+ for i,v in next, t do -- brrr, what happens with sparse indexed
+ if type(i) == "table" then
+ if tables[i] then
+ i = tables[i]
+ else
+ i = copy(i, tables)
+ end
+ end
+ if type(v) ~= "table" then
+ tcopy[i] = v
+ elseif tables[v] then
+ tcopy[i] = tables[v]
+ else
+ tcopy[i] = copy(v, tables)
+ end
+ end
+ local mt = getmetatable(t)
+ if mt then
+ setmetatable(tcopy,mt)
+ end
+ return tcopy
+end
+
+table.fastcopy = fastcopy
+table.copy = copy
+
+-- rougly: copy-loop : unpack : sub == 0.9 : 0.4 : 0.45 (so in critical apps, use unpack)
+
+function table.sub(t,i,j)
+ return { unpack(t,i,j) }
+end
+
+function table.replace(a,b)
+ for k,v in next, b do
+ a[k] = v
+ end
+end
+
+-- slower than #t on indexed tables (#t only returns the size of the numerically indexed slice)
+
+function table.is_empty(t)
+ return not t or not next(t)
+end
+
+function table.one_entry(t)
+ local n = next(t)
+ return n and not next(t,n)
+end
+
+function table.starts_at(t)
+ return ipairs(t,1)(t,0)
+end
+
+function table.tohash(t,value)
+ local h = { }
+ if t then
+ if value == nil then value = true end
+ for _, v in next, t do -- no ipairs here
+ h[v] = value
+ end
+ end
+ return h
+end
+
+function table.fromhash(t)
+ local h = { }
+ for k, v in next, t do -- no ipairs here
+ if v then h[#h+1] = k end
+ end
+ return h
+end
+
+--~ print(table.serialize(t), "\n")
+--~ print(table.serialize(t,"name"), "\n")
+--~ print(table.serialize(t,false), "\n")
+--~ print(table.serialize(t,true), "\n")
+--~ print(table.serialize(t,"name",true), "\n")
+--~ print(table.serialize(t,"name",true,true), "\n")
+
+table.serialize_functions = true
+table.serialize_compact = true
+table.serialize_inline = true
+
+local noquotes, hexify, handle, reduce, compact, inline, functions
+
+local reserved = table.tohash { -- intercept a language flaw, no reserved words as key
+ 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if',
+ 'in', 'local', 'nil', 'not', 'or', 'repeat', 'return', 'then', 'true', 'until', 'while',
+}
+
+local function simple_table(t)
+ if #t > 0 then
+ local n = 0
+ for _,v in next, t do
+ n = n + 1
+ end
+ if n == #t then
+ local tt = { }
+ for i=1,#t do
+ local v = t[i]
+ local tv = type(v)
+ if tv == "number" then
+ if hexify then
+ tt[#tt+1] = format("0x%04X",v)
+ else
+ tt[#tt+1] = tostring(v) -- tostring not needed
+ end
+ elseif tv == "boolean" then
+ tt[#tt+1] = tostring(v)
+ elseif tv == "string" then
+ tt[#tt+1] = format("%q",v)
+ else
+ tt = nil
+ break
+ end
+ end
+ return tt
+ end
+ end
+ return nil
+end
+
+-- Because this is a core function of mkiv I moved some function calls
+-- inline.
+--
+-- twice as fast in a test:
+--
+-- local propername = lpeg.P(lpeg.R("AZ","az","__") * lpeg.R("09","AZ","az", "__")^0 * lpeg.P(-1) )
+
+local function do_serialize(root,name,depth,level,indexed)
+ if level > 0 then
+ depth = depth .. " "
+ if indexed then
+ handle(format("%s{",depth))
+ elseif name then
+ --~ handle(format("%s%s={",depth,key(name)))
+ if type(name) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s[0x%04X]={",depth,name))
+ else
+ handle(format("%s[%s]={",depth,name))
+ end
+ elseif noquotes and not reserved[name] and find(name,"^%a[%w%_]*$") then
+ handle(format("%s%s={",depth,name))
+ else
+ handle(format("%s[%q]={",depth,name))
+ end
+ else
+ handle(format("%s{",depth))
+ end
+ end
+ if root and next(root) then
+ local first, last = nil, 0 -- #root cannot be trusted here
+ if compact then
+ -- NOT: for k=1,#root do (we need to quit at nil)
+ for k,v in ipairs(root) do -- can we use next?
+ if not first then first = k end
+ last = last + 1
+ end
+ end
+ local sk = sortedkeys(root)
+ for i=1,#sk do
+ local k = sk[i]
+ local v = root[k]
+ --~ if v == root then
+ -- circular
+ --~ else
+ local t = type(v)
+ if compact and first and type(k) == "number" and k >= first and k <= last then
+ if t == "number" then
+ if hexify then
+ handle(format("%s 0x%04X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ handle(format("%s %s,",depth,v))
+ else
+ handle(format("%s %q,",depth,v))
+ end
+ elseif t == "table" then
+ if not next(v) then
+ handle(format("%s {},",depth))
+ elseif inline then -- and #t > 0
+ local st = simple_table(v)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif t == "boolean" then
+ handle(format("%s %s,",depth,tostring(v)))
+ elseif t == "function" then
+ if functions then
+ handle(format('%s loadstring(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k == "__p__" then -- parent
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif t == "number" then
+ --~ if hexify then
+ --~ handle(format("%s %s=0x%04X,",depth,key(k),v))
+ --~ else
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ --~ end
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ if hexify then
+ handle(format("%s %s=0x%04X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%04X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif t == "string" then
+ if reduce and (find(v,"^[%-%+]?[%d]-%.?[%d+]$") == 1) then
+ --~ handle(format("%s %s=%s,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),v))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ end
+ elseif t == "table" then
+ if not next(v) then
+ --~ handle(format("%s %s={},",depth,key(k)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st = simple_table(v)
+ if st then
+ --~ handle(format("%s %s={ %s },",depth,key(k),concat(st,", ")))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif t == "boolean" then
+ --~ handle(format("%s %s=%s,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%s,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%s,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%s,",depth,k,tostring(v)))
+ end
+ elseif t == "function" then
+ if functions then
+ --~ handle(format('%s %s=loadstring(%q),',depth,key(k),dump(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%s]=loadstring(%q),",depth,k,dump(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=loadstring(%q),",depth,k,dump(v)))
+ else
+ handle(format("%s [%q]=loadstring(%q),",depth,k,dump(v)))
+ end
+ end
+ else
+ --~ handle(format("%s %s=%q,",depth,key(k),tostring(v)))
+ if type(k) == "number" then -- or find(k,"^%d+$") then
+ if hexify then
+ handle(format("%s [0x%04X]=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%s]=%q,",depth,k,tostring(v)))
+ end
+ elseif noquotes and not reserved[k] and find(k,"^%a[%w%_]*$") then
+ handle(format("%s %s=%q,",depth,k,tostring(v)))
+ else
+ handle(format("%s [%q]=%q,",depth,k,tostring(v)))
+ end
+ end
+ --~ end
+ end
+ end
+ if level > 0 then
+ handle(format("%s},",depth))
+ end
+end
+
+-- replacing handle by a direct t[#t+1] = ... (plus test) is not much
+-- faster (0.03 on 1.00 for zapfino.tma)
+
+local function serialize(root,name,_handle,_reduce,_noquotes,_hexify)
+ noquotes = _noquotes
+ hexify = _hexify
+ handle = _handle or print
+ reduce = _reduce or false
+ compact = table.serialize_compact
+ inline = compact and table.serialize_inline
+ functions = table.serialize_functions
+ local tname = type(name)
+ if tname == "string" then
+ if name == "return" then
+ handle("return {")
+ else
+ handle(name .. "={")
+ end
+ elseif tname == "number" then
+ if hexify then
+ handle(format("[0x%04X]={",name))
+ else
+ handle("[" .. name .. "]={")
+ end
+ elseif tname == "boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root and next(root) then
+ do_serialize(root,name,"",0,indexed)
+ end
+ handle("}")
+end
+
+--~ name:
+--~
+--~ true : return { }
+--~ false : { }
+--~ nil : t = { }
+--~ string : string = { }
+--~ 'return' : return { }
+--~ number : [number] = { }
+
+function table.serialize(root,name,reduce,noquotes,hexify)
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ return concat(t,"\n")
+end
+
+function table.tohandle(handle,root,name,reduce,noquotes,hexify)
+ serialize(root,name,handle,reduce,noquotes,hexify)
+end
+
+-- sometimes tables are real use (zapfino extra pro is some 85M) in which
+-- case a stepwise serialization is nice; actually, we could consider:
+--
+-- for line in table.serializer(root,name,reduce,noquotes) do
+-- ...(line)
+-- end
+--
+-- so this is on the todo list
+
+table.tofile_maxtab = 2*1024
+
+function table.tofile(filename,root,name,reduce,noquotes,hexify)
+ local f = io.open(filename,'w')
+ if f then
+ local maxtab = table.tofile_maxtab
+ if maxtab > 1 then
+ local t = { }
+ local function flush(s)
+ t[#t+1] = s
+ if #t > maxtab then
+ f:write(concat(t,"\n"),"\n") -- hm, write(sometable) should be nice
+ t = { }
+ end
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ f:write(concat(t,"\n"),"\n")
+ else
+ local function flush(s)
+ f:write(s,"\n")
+ end
+ serialize(root,name,flush,reduce,noquotes,hexify)
+ end
+ f:close()
+ end
+end
+
+local function flatten(t,f,complete)
+ for i=1,#t do
+ local v = t[i]
+ if type(v) == "table" then
+ if complete or type(v[1]) == "table" then
+ flatten(v,f,complete)
+ else
+ f[#f+1] = v
+ end
+ else
+ f[#f+1] = v
+ end
+ end
+end
+
+function table.flatten(t)
+ local f = { }
+ flatten(t,f,true)
+ return f
+end
+
+function table.unnest(t) -- bad name
+ local f = { }
+ flatten(t,f,false)
+ return f
+end
+
+table.flatten_one_level = table.unnest
+
+-- the next three may disappear
+
+function table.remove_value(t,value) -- todo: n
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ remove(t,i)
+ -- remove all, so no: return
+ end
+ end
+ end
+end
+
+function table.insert_before_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i,str)
+ return
+ end
+ end
+ end
+ insert(t,1,str)
+ elseif value then
+ insert(t,1,value)
+ end
+end
+
+function table.insert_after_value(t,value,str)
+ if str then
+ if value then
+ for i=1,#t do
+ if t[i] == value then
+ insert(t,i+1,str)
+ return
+ end
+ end
+ end
+ t[#t+1] = str
+ elseif value then
+ t[#t+1] = value
+ end
+end
+
+local function are_equal(a,b,n,m) -- indexed
+ if #a == #b then
+ n = n or 1
+ m = m or #a
+ for i=n,m do
+ local ai, bi = a[i], b[i]
+ if ai==bi then
+ -- same
+ elseif type(ai)=="table" and type(bi)=="table" then
+ if not are_equal(ai,bi) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+ else
+ return false
+ end
+end
+
+local function identical(a,b) -- assumes same structure
+ for ka, va in next, a do
+ local vb = b[k]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
+ return false
+ end
+ end
+ return true
+end
+
+table.are_equal = are_equal
+table.identical = identical
+
+-- maybe also make a combined one
+
+function table.compact(t)
+ if t then
+ for k,v in next, t do
+ if not next(v) then
+ t[k] = nil
+ end
+ end
+ end
+end
+
+function table.contains(t, v)
+ if t then
+ for i=1, #t do
+ if t[i] == v then
+ return i
+ end
+ end
+ end
+ return false
+end
+
+function table.count(t)
+ local n, e = 0, next(t)
+ while e do
+ n, e = n + 1, next(t,e)
+ end
+ return n
+end
+
+function table.swapped(t)
+ local s = { }
+ for k, v in next, t do
+ s[v] = k
+ end
+ return s
+end
+
+--~ function table.are_equal(a,b)
+--~ return table.serialize(a) == table.serialize(b)
+--~ end
+
+function table.clone(t,p) -- t is optional or nil or table
+ if not p then
+ t, p = { }, t or { }
+ elseif not t then
+ t = { }
+ end
+ setmetatable(t, { __index = function(_,key) return p[key] end })
+ return t
+end
+
+function table.hexed(t,seperator)
+ local tt = { }
+ for i=1,#t do tt[i] = format("0x%04X",t[i]) end
+ return concat(tt,seperator or " ")
+end
+
+function table.reverse_hash(h)
+ local r = { }
+ for k,v in next, h do
+ r[v] = lower(gsub(k," ",""))
+ end
+ return r
+end
+
+function table.reverse(t)
+ local tt = { }
+ if #t > 0 then
+ for i=#t,1,-1 do
+ tt[#tt+1] = t[i]
+ end
+ end
+ 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
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-file'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- needs a cleanup
+
+file = file or { }
+
+local concat = table.concat
+local find, gmatch, match, gsub = string.find, string.gmatch, string.match, string.gsub
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
+end
+
+function file.addsuffix(filename, suffix)
+ if not find(filename,"%.[%a%d]+$") then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+end
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
+
+function file.dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
+end
+
+function file.basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
+end
+
+function file.nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+end
+
+function file.extname(name)
+ return match(name,"^.+%.([^/\\]-)$") or ""
+end
+
+file.suffix = file.extname
+
+--~ print(file.join("x/","/y"))
+--~ print(file.join("http://","/y"))
+--~ print(file.join("http://a","/y"))
+--~ print(file.join("http:///a","/y"))
+--~ print(file.join("//nas-1","/y"))
+
+function file.join(...)
+ local pth = concat({...},"/")
+ pth = gsub(pth,"\\","/")
+ local a, b = match(pth,"^(.*://)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ a, b = match(pth,"^(//)(.*)$")
+ if a and b then
+ return a .. gsub(b,"//+","/")
+ end
+ return (gsub(pth,"//+","/"))
+end
+
+function file.iswritable(name)
+ local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
+ return a and a.permissions:sub(2,2) == "w"
+end
+
+function file.isreadable(name)
+ local a = lfs.attributes(name)
+ return a and a.permissions:sub(1,1) == "r"
+end
+
+file.is_readable = file.isreadable
+file.is_writable = file.iswritable
+
+-- todo: lpeg
+
+function file.split_path(str)
+ local t = { }
+ str = gsub(str,"\\", "/")
+ str = gsub(str,"(%a):([;/])", "%1\001%2")
+ for name in gmatch(str,"([^;:]+)") do
+ if name ~= "" then
+ t[#t+1] = gsub(name,"\001",":")
+ end
+ end
+ return t
+end
+
+function file.join_path(tab)
+ return concat(tab,io.pathseparator) -- can have trailing //
+end
+
+function file.collapse_path(str)
+ str = gsub(str,"/%./","/")
+ local n, m = 1, 1
+ while n > 0 or m > 0 do
+ str, n = gsub(str,"[^/%.]+/%.%.$","")
+ str, m = gsub(str,"[^/%.]+/%.%./","")
+ end
+ str = gsub(str,"([^/])/$","%1")
+ str = gsub(str,"^%./","")
+ str = gsub(str,"/%.$","")
+ if str == "" then str = "." end
+ return str
+end
+
+--~ print(file.collapse_path("a/./b/.."))
+--~ print(file.collapse_path("a/aa/../b/bb"))
+--~ print(file.collapse_path("a/../.."))
+--~ print(file.collapse_path("a/.././././b/.."))
+--~ print(file.collapse_path("a/./././b/.."))
+--~ print(file.collapse_path("a/b/c/../.."))
+
+function file.robustname(str)
+ return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
+end
+
+file.readdata = io.loaddata
+file.savedata = io.savedata
+
+function file.copy(oldname,newname)
+ file.savedata(newname,io.loaddata(oldname))
+end
+
+-- lpeg variants, slightly faster, not always
+
+--~ local period = lpeg.P(".")
+--~ local slashes = lpeg.S("\\/")
+--~ local noperiod = 1-period
+--~ local noslashes = 1-slashes
+--~ local name = noperiod^1
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+
+--~ function file.extname(name)
+--~ return pattern:match(name) or ""
+--~ end
+
+--~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+
+--~ function file.removesuffix(name)
+--~ return pattern:match(name)
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+
+--~ function file.basename(name)
+--~ return pattern:match(name) or name
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+
+--~ function file.dirname(name)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2)
+--~ else
+--~ return ""
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.addsuffix(name, suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+
+--~ function file.replacesuffix(name,suffix)
+--~ local p = pattern:match(name)
+--~ if p then
+--~ return name:sub(1,p-2) .. "." .. suffix
+--~ else
+--~ return name .. "." .. suffix
+--~ end
+--~ end
+
+--~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+
+--~ function file.nameonly(name)
+--~ local a, b = pattern:match(name)
+--~ if b then
+--~ return name:sub(a,b-2)
+--~ elseif a then
+--~ return name:sub(a)
+--~ else
+--~ return name
+--~ end
+--~ end
+
+--~ local test = file.extname
+--~ local test = file.basename
+--~ local test = file.dirname
+--~ local test = file.addsuffix
+--~ local test = file.replacesuffix
+--~ local test = file.nameonly
+
+--~ print(1,test("./a/b/c/abd.def.xxx","!!!"))
+--~ print(2,test("./../b/c/abd.def.xxx","!!!"))
+--~ print(3,test("a/b/c/abd.def.xxx","!!!"))
+--~ print(4,test("a/b/c/def.xxx","!!!"))
+--~ print(5,test("a/b/c/def","!!!"))
+--~ print(6,test("def","!!!"))
+--~ print(7,test("def.xxx","!!!"))
+
+--~ local tim = os.clock() for i=1,250000 do local ext = test("abd.def.xxx","!!!") end print(os.clock()-tim)
+
+-- also rewrite previous
+
+local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
+local separator = lpeg.P("://")
+
+local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
+local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+
+-- ./name ../name /name c: :// name/name
+
+function file.is_qualified_path(filename)
+ return qualified:match(filename)
+end
+
+function file.is_rootbased_path(filename)
+ return rootbased:match(filename)
+end
+
+local slash = lpeg.S("\\/")
+local period = lpeg.P(".")
+local drive = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":")
+local path = lpeg.C(((1-slash)^0 * slash)^0)
+local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1))
+local base = lpeg.C((1-suffix)^0)
+
+local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc(""))
+
+function file.splitname(str) -- returns drive, path, base, suffix
+ return pattern:match(str)
+end
+
+-- function test(t) for k, v in pairs(t) do print(v, "=>", file.splitname(v)) end end
+--
+-- test { "c:", "c:/aa", "c:/aa/bb", "c:/aa/bb/cc", "c:/aa/bb/cc.dd", "c:/aa/bb/cc.dd.ee" }
+-- test { "c:", "c:aa", "c:aa/bb", "c:aa/bb/cc", "c:aa/bb/cc.dd", "c:aa/bb/cc.dd.ee" }
+-- test { "/aa", "/aa/bb", "/aa/bb/cc", "/aa/bb/cc.dd", "/aa/bb/cc.dd.ee" }
+-- test { "aa", "aa/bb", "aa/bb/cc", "aa/bb/cc.dd", "aa/bb/cc.dd.ee" }
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['l-io'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local byte = string.byte
+
+if string.find(os.getenv("PATH"),";") then
+ io.fileseparator, io.pathseparator = "\\", ";"
+else
+ io.fileseparator, io.pathseparator = "/" , ":"
+end
+
+function io.loaddata(filename,textmode)
+ local f = io.open(filename,(textmode and 'r') or 'rb')
+ if f then
+ local data = f:read('*all')
+ -- garbagecollector.check(data)
+ f:close()
+ return data
+ else
+ return nil
+ end
+end
+
+function io.savedata(filename,data,joiner)
+ local f = io.open(filename,"wb")
+ if f then
+ if type(data) == "table" then
+ f:write(table.join(data,joiner or ""))
+ elseif type(data) == "function" then
+ data(f)
+ else
+ f:write(data)
+ end
+ f:close()
+ return true
+ else
+ return false
+ end
+end
+
+function io.exists(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return false
+ else
+ assert(f:close())
+ return true
+ end
+end
+
+function io.size(filename)
+ local f = io.open(filename)
+ if f == nil then
+ return 0
+ else
+ local s = f:seek("end")
+ assert(f:close())
+ return s
+ end
+end
+
+function io.noflines(f)
+ local n = 0
+ for _ in f:lines() do
+ n = n + 1
+ end
+ f:seek('set',0)
+ return n
+end
+
+local nextchar = {
+ [ 4] = function(f)
+ return f:read(1,1,1,1)
+ end,
+ [ 2] = function(f)
+ return f:read(1,1)
+ end,
+ [ 1] = function(f)
+ return f:read(1)
+ end,
+ [-2] = function(f)
+ local a, b = f:read(1,1)
+ return b, a
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ return d, c, b, a
+ end
+}
+
+function io.characters(f,n)
+ if f then
+ return nextchar[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+local nextbyte = {
+ [4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(a), byte(b), byte(c), byte(d)
+ else
+ return nil, nil, nil, nil
+ end
+ end,
+ [2] = function(f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(a), byte(b)
+ else
+ return nil, nil
+ end
+ end,
+ [1] = function (f)
+ local a = f:read(1)
+ if a then
+ return byte(a)
+ else
+ return nil
+ end
+ end,
+ [-2] = function (f)
+ local a, b = f:read(1,1)
+ if b then
+ return byte(b), byte(a)
+ else
+ return nil, nil
+ end
+ end,
+ [-4] = function(f)
+ local a, b, c, d = f:read(1,1,1,1)
+ if d then
+ return byte(d), byte(c), byte(b), byte(a)
+ else
+ return nil, nil, nil, nil
+ end
+ end
+}
+
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1], f
+ else
+ return nil, nil
+ end
+end
+
+function io.ask(question,default,options)
+ while true do
+ io.write(question)
+ if options then
+ io.write(string.format(" [%s]",table.concat(options,"|")))
+ end
+ if default then
+ io.write(string.format(" [%s]",default))
+ end
+ io.write(string.format(" "))
+ local answer = io.read()
+ answer = answer:gsub("^%s*(.*)%s*$","%1")
+ if answer == "" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for _,v in pairs(options) do
+ if v == answer then
+ return answer
+ end
+ end
+ local pattern = "^" .. answer
+ for _,v in pairs(options) do
+ if v:find(pattern) then
+ return v
+ end
+ end
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['luat-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local dummyfunction = function() end
+
+statistics = {
+ register = dummyfunction,
+ starttiming = dummyfunction,
+ stoptiming = dummyfunction,
+}
+trackers = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
+storage = {
+ register = dummyfunction,
+ shared = { },
+}
+logs = {
+ report = dummyfunction,
+ simple = dummyfunction,
+}
+tasks = {
+ new = dummyfunction,
+ actions = dummyfunction,
+ appendaction = dummyfunction,
+ prependaction = dummyfunction,
+}
+
+-- we need to cheat a bit here
+
+texconfig.kpse_init = true
+
+resolvers = resolvers or { } -- no fancy file helpers used
+
+local remapper = {
+ otf = "opentype fonts",
+ ttf = "truetype fonts",
+ ttc = "truetype fonts",
+ cid = "other text files", -- will become "cid files"
+}
+
+function resolvers.find_file(name,kind)
+ name = string.gsub(name,"\\","\/")
+ kind = string.lower(kind)
+ return kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or "tex")
+end
+
+function resolvers.findbinfile(name,kind)
+ if not kind or kind == "" then
+ kind = file.extname(name) -- string.match(name,"%.([^%.]-)$")
+ end
+ return resolvers.find_file(name,(kind and remapper[kind]) or kind)
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['data-con'] = {
+ version = 1.001,
+ comment = "companion to luat-lib.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, lower, gsub = string.format, string.lower, string.gsub
+
+local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
+local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
+local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
+local trace_verbose = false trackers.register("resolvers.verbose", function(v) trace_verbose = v end)
+local trace_locating = false trackers.register("resolvers.locating", function(v) trace_locating = v trackers.enable("resolvers.verbose") end)
+
+--[[ldx--
+<p>Once we found ourselves defining similar cache constructs
+several times, containers were introduced. Containers are used
+to collect tables in memory and reuse them when possible based
+on (unique) hashes (to be provided by the calling function).</p>
+
+<p>Caching to disk is disabled by default. Version numbers are
+stored in the saved table which makes it possible to change the
+table structures without bothering about the disk cache.</p>
+
+<p>Examples of usage can be found in the font related code.</p>
+--ldx]]--
+
+containers = containers or { }
+
+containers.usecache = true
+
+local function report(container,tag,name)
+ if trace_cache or trace_containers then
+ logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid')
+ end
+end
+
+local allocated = { }
+
+-- tracing
+
+function containers.define(category, subcategory, version, enabled)
+ return function()
+ if category and subcategory then
+ local c = allocated[category]
+ if not c then
+ c = { }
+ allocated[category] = c
+ end
+ local s = c[subcategory]
+ if not s then
+ s = {
+ category = category,
+ subcategory = subcategory,
+ storage = { },
+ enabled = enabled,
+ version = version or 1.000,
+ trace = false,
+ path = caches and caches.setpath and caches.setpath(category,subcategory),
+ }
+ c[subcategory] = s
+ end
+ return s
+ else
+ return nil
+ end
+ end
+end
+
+function containers.is_usable(container, name)
+ return container.enabled and caches and caches.iswritable(container.path, name)
+end
+
+function containers.is_valid(container, name)
+ if name and name ~= "" then
+ local storage = container.storage[name]
+ return storage and not table.is_empty(storage) and storage.cache_version == container.version
+ else
+ return false
+ end
+end
+
+function containers.read(container,name)
+ if container.enabled and caches and not container.storage[name] and containers.usecache then
+ container.storage[name] = caches.loaddata(container.path,name)
+ if containers.is_valid(container,name) then
+ report(container,"loaded",name)
+ else
+ container.storage[name] = nil
+ end
+ end
+ if container.storage[name] then
+ report(container,"reusing",name)
+ end
+ return container.storage[name]
+end
+
+function containers.write(container, name, data)
+ if data then
+ data.cache_version = container.version
+ if container.enabled and caches then
+ local unique, shared = data.unique, data.shared
+ data.unique, data.shared = nil, nil
+ caches.savedata(container.path, name, data)
+ report(container,"saved",name)
+ data.unique, data.shared = unique, shared
+ end
+ report(container,"stored",name)
+ container.storage[name] = data
+ end
+ return data
+end
+
+function containers.content(container,name)
+ return container.storage[name]
+end
+
+function containers.cleanname(name)
+ return (gsub(lower(name),"[^%w%d]+","-"))
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['node-ini'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>Most of the code that had accumulated here is now separated in
+modules.</p>
+--ldx]]--
+
+-- this module is being reconstructed
+
+local utf = unicode.utf8
+local next, type = next, type
+local format, concat, match, utfchar = string.format, table.concat, string.match, utf.char
+
+local chardata = characters and characters.data
+
+--[[ldx--
+<p>We start with a registration system for atributes so that we can use the
+symbolic names later on.</p>
+--ldx]]--
+
+attributes = attributes or { }
+
+attributes.names = attributes.names or { }
+attributes.numbers = attributes.numbers or { }
+attributes.list = attributes.list or { }
+attributes.unsetvalue = -0x7FFFFFFF
+
+storage.register("attributes/names", attributes.names, "attributes.names")
+storage.register("attributes/numbers", attributes.numbers, "attributes.numbers")
+storage.register("attributes/list", attributes.list, "attributes.list")
+
+local names, numbers, list = attributes.names, attributes.numbers, attributes.list
+
+function attributes.define(name,number) -- at the tex end
+ if not numbers[name] then
+ numbers[name], names[number], list[number] = number, name, { }
+ end
+end
+
+--[[ldx--
+<p>We can use the attributes in the range 127-255 (outside user space). These
+are only used when no attribute is set at the \TEX\ end which normally
+happens in <l n='context'/>.</p>
+--ldx]]--
+
+storage.shared.attributes_last_private = storage.shared.attributes_last_private or 127
+
+function attributes.private(name) -- at the lua end (hidden from user)
+ local number = numbers[name]
+ if not number then
+ local last = storage.shared.attributes_last_private or 127
+ if last < 255 then
+ last = last + 1
+ storage.shared.attributes_last_private = last
+ end
+ number = last
+ numbers[name], names[number], list[number] = number, name, { }
+ end
+ return number
+end
+
+--[[ldx--
+<p>Access to nodes is what gives <l n='luatex'/> its power. Here we
+implement a few helper functions. These functions are rather optimized.</p>
+--ldx]]--
+
+--[[ldx--
+<p>When manipulating node lists in <l n='context'/>, we will remove
+nodes and insert new ones. While node access was implemented, we did
+quite some experiments in order to find out if manipulating nodes
+in <l n='lua'/> was feasible from the perspective of performance.</p>
+
+<p>First of all, we noticed that the bottleneck is more with excessive
+callbacks (some gets called very often) and the conversion from and to
+<l n='tex'/>'s datastructures. However, at the <l n='lua'/> end, we
+found that inserting and deleting nodes in a table could become a
+bottleneck.</p>
+
+<p>This resulted in two special situations in passing nodes back to
+<l n='tex'/>: a table entry with value <type>false</type> is ignored,
+and when instead of a table <type>true</type> is returned, the
+original table is used.</p>
+
+<p>Insertion is handled (at least in <l n='context'/> as follows. When
+we need to insert a node at a certain position, we change the node at
+that position by a dummy node, tagged <type>inline</type> which itself
+has_attribute the original node and one or more new nodes. Before we pass
+back the list we collapse the list. Of course collapsing could be built
+into the <l n='tex'/> engine, but this is a not so natural extension.</p>
+
+<p>When we collapse (something that we only do when really needed), we
+also ignore the empty nodes. [This is obsolete!]</p>
+--ldx]]--
+
+nodes = nodes or { }
+
+local hlist = node.id('hlist')
+local vlist = node.id('vlist')
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+local kern = node.id('kern')
+local whatsit = node.id('whatsit')
+
+local traverse_id = node.traverse_id
+local traverse = node.traverse
+local slide_nodes = node.slide
+local free_node = node.free
+local remove_node = node.remove
+
+function nodes.remove(head, current, free_too)
+ local t = current
+ head, current = remove_node(head,current)
+ if t then
+ if free_too then
+ free_node(t)
+ t = nil
+ else
+ t.next, t.prev = nil, nil
+ end
+ end
+ return head, current, t
+end
+
+function nodes.delete(head,current)
+ return nodes.remove(head,current,true)
+end
+
+nodes.before = node.insert_before -- broken
+nodes.after = node.insert_after
+
+-- we need to test this, as it might be fixed
+
+function nodes.before(h,c,n)
+ if c then
+ if c == h then
+ n.next = h
+ n.prev = nil
+ h.prev = n
+ else
+ local cp = c.prev
+ n.next = c
+ n.prev = cp
+ if cp then
+ cp.next = n
+ end
+ c.prev = n
+ return h, n
+ end
+ end
+ return n, n
+end
+
+function nodes.after(h,c,n)
+ if c then
+ local cn = c.next
+ if cn then
+ n.next = cn
+ cn.prev = n
+ else
+ n.next = nil
+ end
+ c.next = n
+ n.prev = c
+ return h, n
+ end
+ return n, n
+end
+
+function nodes.replace(head,current,new)
+ if current and next then
+ local p, n = current.prev, current.next
+ new.prev, new.next = p, n
+ if p then
+ p.next = new
+ else
+ head = new
+ end
+ if n then
+ n.prev = new
+ end
+ free_node(current)
+ end
+ return head, current
+end
+
+-- will move
+
+local function count(stack,flat)
+ local n = 0
+ while stack do
+ local id = stack.id
+ if not flat and id == hlist or id == vlist then
+ local list = stack.list
+ if list then
+ n = n + 1 + count(list) -- self counts too
+ else
+ n = n + 1
+ end
+ else
+ n = n + 1
+ end
+ stack = stack.next
+ end
+ return n
+end
+
+nodes.count = count
+
+-- new
+
+function attributes.ofnode(n)
+ local a = n.attr
+ if a then
+ local names = attributes.names
+ a = a.next
+ while a do
+ local number, value = a.number, a.value
+ texio.write_nl(format("%s : attribute %3i, value %4i, name %s",tostring(n),number,value,names[number] or '?'))
+ a = a.next
+ end
+ end
+end
+
+local left, space = lpeg.P("<"), lpeg.P(" ")
+
+nodes.filterkey = left * (1-left)^0 * left * space^0 * lpeg.C((1-space)^0)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['node-res'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local gmatch, format = string.gmatch, string.format
+local copy_node, free_node, new_node = node.copy, node.free, node.new
+
+--[[ldx--
+<p>The next function is not that much needed but in <l n='context'/> we use
+for debugging <l n='luatex'/> node management.</p>
+--ldx]]--
+
+nodes = nodes or { }
+
+local reserved = { }
+
+function nodes.register(n)
+ reserved[#reserved+1] = n
+ return n
+end
+
+function nodes.cleanup_reserved(nofboxes) -- todo
+ nodes.tracers.steppers.reset() -- todo: make a registration subsystem
+ local nr, nl = #reserved, 0
+ for i=1,nr do
+ free_node(reserved[i])
+ end
+ if nofboxes then
+ local tb = tex.box
+ for i=0,nofboxes do
+ local l = tb[i]
+ if l then
+ free_node(tb[i])
+ nl = nl + 1
+ end
+ end
+ end
+ reserved = { }
+ return nr, nl, nofboxes -- can be nil
+end
+
+function nodes.usage()
+ local t = { }
+ for n, tag in gmatch(status.node_mem_usage,"(%d+) ([a-z_]+)") do
+ t[tag] = n
+ end
+ return t
+end
+
+local pdfliteral = nodes.register(new_node("whatsit",8)) pdfliteral.mode = 1
+local disc = nodes.register(new_node("disc"))
+local kern = nodes.register(new_node("kern",1))
+local penalty = nodes.register(new_node("penalty"))
+local glue = nodes.register(new_node("glue"))
+local glue_spec = nodes.register(new_node("glue_spec"))
+local glyph = nodes.register(new_node("glyph",0))
+local textdir = nodes.register(new_node("whatsit",7))
+
+function nodes.glyph(fnt,chr)
+ local n = copy_node(glyph)
+ if fnt then n.font = fnt end
+ if chr then n.char = chr end
+ return n
+end
+function nodes.penalty(p)
+ local n = copy_node(penalty)
+ n.penalty = p
+ return n
+end
+function nodes.kern(k)
+ local n = copy_node(kern)
+ n.kern = k
+ return n
+end
+function nodes.glue(width,stretch,shrink)
+ local n, s = copy_node(glue), copy_node(glue_spec)
+ s.width, s.stretch, s.shrink = width, stretch, shrink
+ n.spec = s
+ return n
+end
+function nodes.glue_spec(width,stretch,shrink)
+ local s = copy_node(glue_spec)
+ s.width, s.stretch, s.shrink = width, stretch, shrink
+ return s
+end
+function nodes.disc()
+ return copy_node(disc)
+end
+function nodes.pdfliteral(str)
+ local t = copy_node(pdfliteral)
+ t.data = str
+ return t
+end
+function nodes.textdir(dir)
+ local t = copy_node(textdir)
+ t.dir = dir
+ return t
+end
+
+statistics.register("cleaned up reserved nodes", function()
+ return format("%s nodes, %s lists of %s", nodes.cleanup_reserved(tex.count["lastallocatedbox"]))
+end) -- \topofboxstack
+
+statistics.register("node memory usage", function() -- comes after cleanup !
+ return status.node_mem_usage
+end)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['node-inj'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- tricky ... fonts.ids is not yet defined .. to be solved (maybe general tex ini)
+
+-- This is very experimental (this will change when we have luatex > .50 and
+-- a few pending thingies are available. Also, Idris needs to make a few more
+-- test fonts.
+
+local next = next
+
+local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local fontdata = fonts.ids
+
+local glyph = node.id('glyph')
+local kern = node.id('kern')
+
+local traverse_id = node.traverse_id
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+
+local newkern = nodes.kern
+
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local cursives = { }
+local marks = { }
+local kerns = { }
+
+-- currently we do gpos/kern in a bit inofficial way but when we
+-- have the extra fields in glyphnodes to manipulate ht/dp/wd
+-- explicitly i will provide an alternative; also, we can share
+-- tables
+
+function nodes.set_cursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+ local ws, wn = tfmstart.width, tfmnext.width
+ local bound = #cursives + 1
+ set_attribute(start,cursbase,bound)
+ set_attribute(nxt,curscurs,bound)
+ cursives[bound] = { rlmode, dx, dy, ws, wn }
+ return dx, dy, bound
+end
+
+function nodes.set_pair(current,factor,rlmode,spec,tfmchr)
+ local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
+ -- dy = y - h
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
+ local bound = has_attribute(current,kernpair)
+ if bound then
+ local kb = kerns[bound]
+ kb[2], kb[3], kb[4], kb[5] = kb[2] + x, kb[3] + y, kb[4] + w, kb[5] + h
+ else
+ bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, x, y, w, h }
+ end
+ return x, y, w, h, bound
+ end
+ return x, y, w, h -- no bound
+end
+
+function nodes.set_kern(current,factor,rlmode,x,tfmchr)
+ local dx = factor*x
+ if dx ~= 0 then
+ local bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, dx }
+ end
+ return dx, bound
+end
+
+function nodes.set_mark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
+ local bound = has_attribute(base,markbase)
+ if bound then
+ local mb = marks[bound]
+ if mb then
+ if not index then index = #mb + 1 end
+ mb[index] = { dx, dy }
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ return dx, dy, bound
+ else
+ logs.report("nodes mark", "possible problem, U+%04X is base without data (id: %s)",base.char,bound)
+ end
+ end
+ index = index or 1
+ bound = #marks + 1
+ set_attribute(base,markbase,bound)
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ marks[bound] = { [index] = { dx, dy } }
+ return dx, dy, bound
+end
+
+function nodes.trace_injection(head)
+ local function dir(n)
+ return (n<0 and "r-to-l") or (n>0 and "l-to-r") or ("unset")
+ end
+ local function report(...)
+ logs.report("nodes finisher",...)
+ end
+ report("begin run")
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ local kp = has_attribute(n,kernpair)
+ local mb = has_attribute(n,markbase)
+ local mm = has_attribute(n,markmark)
+ local md = has_attribute(n,markdone)
+ local cb = has_attribute(n,cursbase)
+ local cc = has_attribute(n,curscurs)
+ report("char U+%05X, font=%s",n.char,n.font)
+ if kp then
+ local k = kerns[kp]
+ if k[3] then
+ report(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2],k[3],k[4],k[5])
+ else
+ report(" kern: dir=%s, dx=%s",dir(k[1]),k[2])
+ end
+ end
+ if mb then
+ report(" markbase: bound=%s",mb)
+ end
+ if mm then
+ local m = marks[mm]
+ if mb then
+ local m = m[mb]
+ if m then
+ report(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,j,m[1],m[2])
+ else
+ report(" markmark: bound=%s, missing index",mm)
+ end
+ else
+ m = m[1]
+ report(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1],m[2])
+ end
+ end
+ if cb then
+ report(" cursbase: bound=%s",cb)
+ end
+ if cc then
+ local c = cursives[cc]
+ report(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2],c[3])
+ end
+ end
+ end
+ report("end run")
+end
+
+-- todo: reuse tables (i.e. no collection), but will be extra fields anyway
+
+function nodes.inject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, rl, valid, cx, wx = false, { }, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ rl[n] = kk[1] -- could move in test
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+ cx[n] = dx
+ rl[n] = rlmode
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ -- local rlmode = d[3] -- not used
+ -- if rlmode and rlmode < 0 then
+ -- n.xoffset = p.xoffset + d[1]
+ -- else
+ n.xoffset = p.xoffset - d[1]
+ -- end
+ n.yoffset = p.yoffset + d[2]
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ if k ~= 0 then
+ local rln = rl[n]
+ if rln and rln < 0 then
+ insert_node_before(head,n,newkern(-k))
+ else
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end
+
+-- -- -- KEEP OLD ONE, THE NEXT IS JUST OPTIMIZED -- -- --
+
+function nodes.XXXXXXXxinject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, valid, cx, wx = false, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+if rlmode < 0 then
+ cx[n] = -dx
+else
+ cx[n] = dx
+end
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ local d1, d2 = d[1], d[2]
+ if d1 ~= 0 then
+ n.xoffset = p.xoffset - d[1]
+ end
+ if d2 ~= 0 then
+ n.yoffset = p.yoffset + d[2]
+ end
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['node-fnt'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local next, type = next, type
+
+local trace_characters = false trackers.register("nodes.characters", function(v) trace_characters = v end)
+
+local glyph = node.id('glyph')
+
+local traverse_id = node.traverse_id
+local has_attribute = node.has_attribute
+
+local starttiming, stoptiming = statistics.starttiming, statistics.stoptiming
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local fontdata = fonts.ids
+
+-- some tests with using an array of dynamics[id] and processes[id] demonstrated
+-- that there was nothing to gain (unless we also optimize other parts)
+--
+-- maybe getting rid of the intermediate shared can save some time
+
+-- potential speedup: check for subtype < 256 so that we can remove that test
+-- elsewhere, danger: injected nodes will not be dealt with but that does not
+-- happen often; we could consider processing sublists but that might need mor
+-- checking later on; the current approach also permits variants
+
+if tex.attribute[0] < 0 then
+
+ texio.write_nl("log","!")
+ texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be")
+ texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special")
+ texio.write_nl("log","! purposed so setting them at the TeX end might break the font handler.")
+ texio.write_nl("log","!")
+
+ tex.attribute[0] = 0 -- else no features
+
+end
+
+function nodes.process_characters(head)
+ -- either next or not, but definitely no already processed list
+ starttiming(nodes)
+ local usedfonts, attrfonts, done = { }, { }, false
+ local a, u, prevfont, prevattr = 0, 0, nil, 0
+ for n in traverse_id(glyph,head) do
+ local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts, preset to 0 is faster (first match)
+ if attr and attr > 0 then
+ if font ~= prevfont or attr ~= prevattr then
+ local used = attrfonts[font]
+ if not used then
+ used = { }
+ attrfonts[font] = used
+ end
+ if not used[attr] then
+ -- we do some testing outside the function
+ local tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ if shared then
+ local dynamics = shared.dynamics
+ if dynamics then
+ local d = shared.set_dynamics(font,dynamics,attr) -- still valid?
+ if d then
+ used[attr] = d
+ a = a + 1
+ end
+ end
+ end
+ end
+ prevfont, prevattr = font, attr
+ end
+ elseif font ~= prevfont then
+ prevfont, prevattr = font, 0
+ local used = usedfonts[font]
+ if not used then
+ local tfmdata = fontdata[font]
+ if tfmdata then
+ local shared = tfmdata.shared -- we need to check shared, only when same features
+ if shared then
+ local processors = shared.processes
+ if processors and #processors > 0 then
+ usedfonts[font] = processors
+ u = u + 1
+ end
+ end
+ else
+ -- probably nullfont
+ end
+ end
+ else
+ prevattr = attr
+ end
+ end
+ -- we could combine these and just make the attribute nil
+ if u == 1 then
+ local font, processors = next(usedfonts)
+ local n = #processors
+ if n > 0 then
+ local h, d = processors[1](head,font,false)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,0) -- false)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ elseif u > 0 then
+ for font, processors in next, usedfonts do
+ local n = #processors
+ local h, d = processors[1](head,font,false)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,0) -- false)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ end
+ if a == 1 then
+ local font, dynamics = next(attrfonts)
+ for attribute, processors in next, dynamics do -- attr can switch in between
+ local n = #processors
+ local h, d = processors[1](head,font,attribute)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,attribute)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ elseif a > 0 then
+ for font, dynamics in next, attrfonts do
+ for attribute, processors in next, dynamics do -- attr can switch in between
+ local n = #processors
+ local h, d = processors[1](head,font,attribute)
+ head, done = h or head, done or d
+ if n > 1 then
+ for i=2,n do
+ local h, d = processors[i](head,font,attribute)
+ head, done = h or head, done or d
+ end
+ end
+ end
+ end
+ end
+ stoptiming(nodes)
+ if trace_characters then
+ nodes.report(head,done)
+ end
+ return head, true
+end
+
+if node.protect_glyphs then
+
+ nodes.protect_glyphs = node.protect_glyphs
+ nodes.unprotect_glyphs = node.unprotect_glyphs
+
+else do
+
+ -- initial value subtype : X000 0001 = 1 = 0x01 = char
+ --
+ -- expected before linebreak : X000 0000 = 0 = 0x00 = glyph
+ -- X000 0010 = 2 = 0x02 = ligature
+ -- X000 0100 = 4 = 0x04 = ghost
+ -- X000 1010 = 10 = 0x0A = leftboundary lig
+ -- X001 0010 = 18 = 0x12 = rightboundary lig
+ -- X001 1010 = 26 = 0x1A = both boundaries lig
+ -- 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
+ local s = g.subtype
+ if s == 1 then
+ done, g.subtype = true, 256
+ elseif s <= 256 then
+ done, g.subtype = true, 256 + s
+ end
+ end
+ return done
+ end
+
+ function nodes.unprotect_glyphs(head)
+ local done = false
+ for g in traverse_id(glyph,head) do
+ local s = g.subtype
+ if s > 256 then
+ done, g.subtype = true, s - 256
+ end
+ end
+ return done
+ end
+
+end end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['node-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+nodes = nodes or { }
+
+function nodes.simple_font_dummy(head,tail)
+ return tail
+end
+
+function nodes.simple_font_handler(head)
+ local tail = node.slide(head)
+-- lang.hyphenate(head,tail)
+ head = nodes.process_characters(head,tail)
+ nodes.inject_kerns(head)
+ nodes.protect_glyphs(head)
+ tail = node.ligaturing(head,tail)
+ tail = node.kerning(head,tail)
+ return head
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-ini'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+--[[ldx--
+<p>Not much is happening here.</p>
+--ldx]]--
+
+local utf = unicode.utf8
+
+if not fontloader then fontloader = fontforge end
+
+fontloader.totable = fontloader.to_table
+
+-- vtf comes first
+-- fix comes last
+
+fonts = fonts or { }
+fonts.ids = fonts.ids or { } -- aka fontdata
+fonts.tfm = fonts.tfm or { }
+
+fonts.mode = 'base'
+fonts.private = 0xF0000 -- 0x10FFFF
+fonts.verbose = false -- more verbose cache tables
+
+fonts.methods = fonts.methods or {
+ base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+ node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+}
+
+fonts.initializers = fonts.initializers or {
+ base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
+ node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } }
+}
+
+fonts.triggers = fonts.triggers or {
+ 'mode',
+ 'language',
+ 'script',
+ 'strategy',
+}
+
+fonts.processors = fonts.processors or {
+}
+
+fonts.manipulators = fonts.manipulators or {
+}
+
+fonts.define = fonts.define or { }
+fonts.define.specify = fonts.define.specify or { }
+fonts.define.specify.synonyms = fonts.define.specify.synonyms or { }
+
+-- tracing
+
+fonts.color = fonts.color or { }
+
+local attribute = attributes.private('color')
+local mapping = (attributes and attributes.list[attribute]) or { }
+
+local set_attribute = node.set_attribute
+local unset_attribute = node.unset_attribute
+
+function fonts.color.set(n,c)
+ local mc = mapping[c]
+ if not mc then
+ unset_attribute(n,attribute)
+ else
+ set_attribute(n,attribute,mc)
+ end
+end
+function fonts.color.reset(n)
+ unset_attribute(n,attribute)
+end
+
+-- this will change ...
+
+function fonts.show_char_data(n)
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata then
+ if type(n) == "string" then
+ n = utf.byte(n)
+ end
+ local chr = tfmdata.characters[n]
+ if chr then
+ texio.write_nl(table.serialize(chr,string.format("U_%04X",n)))
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-tfm'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local next, format, match, lower = next, string.format, string.match, string.lower
+local concat, sortedkeys, utfbyte, serialize = table.concat, table.sortedkeys, utf.byte, table.serialize
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+
+-- tfmdata has also fast access to indices and unicodes
+-- to be checked: otf -> tfm -> tfmscaled
+--
+-- watch out: no negative depths and negative eights permitted in regular fonts
+
+--[[ldx--
+<p>Here we only implement a few helper functions.</p>
+--ldx]]--
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local tfm = fonts.tfm
+
+fonts.loaded = fonts.loaded or { }
+fonts.dontembed = fonts.dontembed or { }
+fonts.triggers = fonts.triggers or { } -- brrr
+fonts.initializers = fonts.initializers or { }
+fonts.initializers.common = fonts.initializers.common or { }
+
+local fontdata = fonts.ids
+local glyph = node.id('glyph')
+local set_attribute = node.set_attribute
+
+--[[ldx--
+<p>The next function encapsulates the standard <l n='tfm'/> loader as
+supplied by <l n='luatex'/>.</p>
+--ldx]]--
+
+tfm.resolve_vf = true -- false
+tfm.share_base_kerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
+tfm.mathactions = { }
+
+function tfm.enhance(tfmdata,specification)
+ local name, size = specification.name, specification.size
+ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if filename and encoding and fonts.enc.known[encoding] then
+ local data = fonts.enc.load(encoding)
+ if data then
+ local characters = tfmdata.characters
+ tfmdata.encoding = encoding
+ local vector = data.vector
+ local original = { }
+ for k, v in next, characters do
+ v.name = vector[k]
+ v.index = k
+ original[k] = v
+ end
+ for k,v in next, data.unicodes do
+ if k ~= v then
+ if trace_defining then
+ logs.report("define font","mapping %s onto %s",k,v)
+ end
+ characters[k] = original[v]
+ end
+ end
+ end
+ end
+end
+
+function tfm.read_from_tfm(specification)
+ local fname, tfmdata = specification.filename or "", nil
+ if fname ~= "" then
+ if trace_defining then
+ logs.report("define font","loading tfm file %s at size %s",fname,specification.size)
+ end
+ tfmdata = font.read_tfm(fname,specification.size) -- not cached, fast enough
+ if tfmdata then
+ tfmdata.descriptions = tfmdata.descriptions or { }
+ if tfm.resolve_vf then
+ fonts.logger.save(tfmdata,file.extname(fname),specification) -- strange, why here
+ fname = resolvers.findbinfile(specification.name, 'ovf')
+ if fname and fname ~= "" then
+ local vfdata = font.read_vf(fname,specification.size) -- not cached, fast enough
+ if vfdata then
+ local chars = tfmdata.characters
+ for k,v in next, vfdata.characters do
+ chars[k].commands = v.commands
+ end
+ tfmdata.type = 'virtual'
+ tfmdata.fonts = vfdata.fonts
+ end
+ end
+ end
+ tfm.enhance(tfmdata,specification)
+ end
+ elseif trace_defining then
+ logs.report("define font","loading tfm with name %s fails",specification.name)
+ end
+ return tfmdata
+end
+
+--[[ldx--
+<p>We need to normalize the scale factor (in scaled points). This has to
+do with the fact that <l n='tex'/> uses a negative multiple of 1000 as
+a signal for a font scaled based on the design size.</p>
+--ldx]]--
+
+local factors = {
+ pt = 65536.0,
+ bp = 65781.8,
+}
+
+function tfm.setfactor(f)
+ tfm.factor = factors[f or 'pt'] or factors.pt
+end
+
+tfm.setfactor()
+
+function tfm.scaled(scaledpoints, designsize) -- handles designsize in sp as well
+ if scaledpoints < 0 then
+ if designsize then
+ if designsize > tfm.factor then -- or just 1000 / when? mp?
+ return (- scaledpoints/1000) * designsize -- sp's
+ else
+ return (- scaledpoints/1000) * designsize * tfm.factor
+ end
+ else
+ return (- scaledpoints/1000) * 10 * tfm.factor
+ end
+ else
+ return scaledpoints
+ end
+end
+
+--[[ldx--
+<p>Before a font is passed to <l n='tex'/> we scale it. Here we also need
+to scale virtual characters.</p>
+--ldx]]--
+
+function tfm.get_virtual_id(tfmdata)
+ -- since we don't know the id yet, we use 0 as signal
+ if not tfmdata.fonts then
+ tfmdata.type = "virtual"
+ tfmdata.fonts = { { id = 0 } }
+ return 1
+ else
+ tfmdata.fonts[#tfmdata.fonts+1] = { id = 0 }
+ return #tfmdata.fonts
+ end
+end
+
+function tfm.check_virtual_id(tfmdata, id)
+ if tfmdata and tfmdata.type == "virtual" then
+ if not tfmdata.fonts or #tfmdata.fonts == 0 then
+ tfmdata.type, tfmdata.fonts = "real", nil
+ else
+ local vfonts = tfmdata.fonts
+ for f=1,#vfonts do
+ local fnt = vfonts[f]
+ if fnt.id and fnt.id == 0 then
+ fnt.id = id
+ end
+ end
+ end
+ end
+end
+
+--[[ldx--
+<p>Beware, the boundingbox is passed as reference so we may not overwrite it
+in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to
+excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p>
+--ldx]]--
+
+fonts.trace_scaling = false
+
+-- the following hack costs a bit of runtime but safes memory
+--
+-- basekerns are scaled and will be hashed by table id
+-- sharedkerns are unscaled and are be hashed by concatenated indexes
+
+function tfm.check_base_kerns(tfmdata)
+ if tfm.share_base_kerns then
+ local sharedkerns = tfmdata.sharedkerns
+ if sharedkerns then
+ local basekerns = { }
+ tfmdata.basekerns = basekerns
+ return sharedkerns, basekerns
+ end
+ end
+ return nil, nil
+end
+
+function tfm.prepare_base_kerns(tfmdata)
+ if tfm.share_base_kerns and not tfmdata.sharedkerns then
+ local sharedkerns = { }
+ tfmdata.sharedkerns = sharedkerns
+ for u, chr in next, tfmdata.characters do
+ local kerns = chr.kerns
+ if kerns then
+ local hash = concat(sortedkeys(kerns), " ")
+ local base = sharedkerns[hash]
+ if not base then
+ sharedkerns[hash] = kerns
+ else
+ chr.kerns = base
+ end
+ end
+ end
+ end
+end
+
+-- we can have cache scaled characters when we are in node mode and don't have
+-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
+-- but in practice (except from mk) the otf hash will be enough already so it
+-- makes no sense to mess up the code now
+
+local charactercache = { }
+
+-- The scaler is only used for otf and afm and virtual fonts. If
+-- a virtual font has italic correction make sur eto set the
+-- has_italic flag. Some more flags will be added in the future.
+
+function tfm.do_scale(tfmtable, scaledpoints)
+ tfm.prepare_base_kerns(tfmtable) -- optimalization
+ if scaledpoints < 0 then
+ scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
+ end
+ local delta = scaledpoints/(tfmtable.units or 1000) -- brr, some open type fonts have 2048
+ local t = { }
+ -- unicoded unique descriptions shared cidinfo characters changed parameters indices
+ for k,v in next, tfmtable do
+ if type(v) == "table" then
+ -- print(k)
+ else
+ t[k] = v
+ end
+ end
+ -- status
+ local isvirtual = tfmtable.type == "virtual" or tfmtable.virtualized
+ local hasmath = tfmtable.math_parameters ~= nil or tfmtable.MathConstants ~= nil
+ local nodemode = tfmtable.mode == "node"
+ local hasquality = tfmtable.auto_expand or tfmtable.auto_protrude
+ local hasitalic = tfmtable.has_italic
+ --
+ t.parameters = { }
+ t.characters = { }
+ t.MathConstants = { }
+ -- fast access
+ local descriptions = tfmtable.descriptions or { }
+ t.unicodes = tfmtable.unicodes
+ t.indices = tfmtable.indices
+ t.marks = tfmtable.marks
+ t.descriptions = descriptions
+ if tfmtable.fonts then
+ t.fonts = table.fastcopy(tfmtable.fonts) -- hm also at the end
+ end
+ local tp = t.parameters
+ local mp = t.math_parameters
+ local tfmp = tfmtable.parameters -- let's check for indexes
+ --
+ tp.slant = (tfmp.slant or tfmp[1] or 0)
+ tp.space = (tfmp.space or tfmp[2] or 0)*delta
+ tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*delta
+ tp.space_shrink = (tfmp.space_shrink or tfmp[4] or 0)*delta
+ tp.x_height = (tfmp.x_height or tfmp[5] or 0)*delta
+ tp.quad = (tfmp.quad or tfmp[6] or 0)*delta
+ tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*delta
+ local protrusionfactor = (tp.quad ~= 0 and 1000/tp.quad) or 0
+ local tc = t.characters
+ local characters = tfmtable.characters
+ local nameneeded = not tfmtable.shared.otfdata --hack
+ local changed = tfmtable.changed or { } -- for base mode
+ local ischanged = not table.is_empty(changed)
+ local indices = tfmtable.indices
+ local luatex = tfmtable.luatex
+ local tounicode = luatex and luatex.tounicode
+ local defaultwidth = luatex and luatex.defaultwidth or 0
+ local defaultheight = luatex and luatex.defaultheight or 0
+ local defaultdepth = luatex and luatex.defaultdepth or 0
+ -- experimental, sharing kerns (unscaled and scaled) saves memory
+ local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
+ -- loop over descriptions (afm and otf have descriptions, tfm not)
+ -- there is no need (yet) to assign a value to chr.tonunicode
+ local scaledwidth = defaultwidth * delta
+ local scaledheight = defaultheight * delta
+ local scaleddepth = defaultdepth * delta
+ local stackmath = tfmtable.ignore_stack_math ~= true
+ for k,v in next, characters do
+ local chr, description, index
+ if ischanged then
+ -- basemode hack
+ local c = changed[k]
+ if c then
+ description = descriptions[c] or v
+ v = characters[c] or v
+ index = (indices and indices[c]) or c
+ else
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
+ else
+ description = descriptions[k] or v
+ index = (indices and indices[k]) or k
+ end
+ local width = description.width
+ local height = description.height
+ local depth = description.depth
+ if width then width = delta*width else width = scaledwidth end
+ if height then height = delta*height else height = scaledheight end
+ -- if depth then depth = delta*depth else depth = scaleddepth end
+ if depth and depth ~= 0 then
+ depth = delta*depth
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ depth = depth,
+ width = width,
+ }
+ end
+ else
+ -- this saves a little bit of memory time and memory, esp for big cjk fonts
+ if nameneeded then
+ chr = {
+ name = description.name,
+ index = index,
+ height = height,
+ width = width,
+ }
+ else
+ chr = {
+ index = index,
+ height = height,
+ width = width,
+ }
+ end
+ end
+ -- if trace_scaling then
+ -- logs.report("define font","t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or k,description.index,description.name or '-',description.class or '-')
+ -- end
+ if tounicode then
+ local tu = tounicode[index]
+ if tu then
+ chr.tounicode = tu
+ end
+ end
+ if hasquality then
+ local ve = v.expansion_factor
+ if ve then
+ chr.expansion_factor = ve*1000 -- expansionfactor, hm, can happen elsewhere
+ end
+ local vl = v.left_protruding
+ if vl then
+ chr.left_protruding = protrusionfactor*width*vl
+ end
+ local vr = v.right_protruding
+ if vr then
+ chr.right_protruding = protrusionfactor*width*vr
+ end
+ end
+ -- todo: hasitalic
+ if hasitalic then
+ local vi = description.italic or v.italic
+ if vi and vi ~= 0 then
+ chr.italic = vi*delta
+ end
+ end
+ -- to be tested
+ if hasmath then
+ -- todo, just operate on descriptions.math
+ local vn = v.next
+ if vn then
+ chr.next = vn
+ else
+ local vv = v.vert_variants
+ if vv then
+ local t = { }
+ for i=1,#vv do
+ local vvi = vv[i]
+ t[i] = {
+ ["start"] = (vvi["start"] or 0)*delta,
+ ["end"] = (vvi["end"] or 0)*delta,
+ ["advance"] = (vvi["advance"] or 0)*delta,
+ ["extender"] = vvi["extender"],
+ ["glyph"] = vvi["glyph"],
+ }
+ end
+ chr.vert_variants = t
+ else
+ local hv = v.horiz_variants
+ if hv then
+ local t = { }
+ for i=1,#hv do
+ local hvi = hv[i]
+ t[i] = {
+ ["start"] = (hvi["start"] or 0)*delta,
+ ["end"] = (hvi["end"] or 0)*delta,
+ ["advance"] = (hvi["advance"] or 0)*delta,
+ ["extender"] = hvi["extender"],
+ ["glyph"] = hvi["glyph"],
+ }
+ end
+ chr.horiz_variants = t
+ end
+ end
+ end
+ local vt = description.top_accent
+ if vt then
+ chr.top_accent = delta*vt
+ end
+ if stackmath then
+ local mk = v.mathkerns
+ if mk then
+ local kerns = { }
+ -- for k, v in next, mk do
+ -- local kk = { }
+ -- for i=1,#v do
+ -- local vi = v[i]
+ -- kk[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ -- end
+ -- kerns[k] = kk
+ -- end
+ local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.top_right = k end
+ local v = mk.top_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.top_left = k end
+ local v = mk.bottom_left if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.bottom_left = k end
+ local v = mk.bottom_right if v then local k = { } for i=1,#v do local vi = v[i]
+ k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ end kerns.bottom_right = k end
+ chr.mathkern = kerns -- singular
+ end
+ end
+ end
+ if not nodemode then
+ local vk = v.kerns
+ if vk then
+ if sharedkerns then
+ local base = basekerns[vk] -- hashed by table id, not content
+ if not base then
+ base = {}
+ for k,v in next, vk do base[k] = v*delta end
+ basekerns[vk] = base
+ end
+ chr.kerns = base
+ else
+ local tt = {}
+ for k,v in next, vk do tt[k] = v*delta end
+ chr.kerns = tt
+ end
+ end
+ local vl = v.ligatures
+ if vl then
+ if true then
+ chr.ligatures = vl -- shared
+ else
+ local tt = { }
+ for i,l in next, vl do
+ tt[i] = l
+ end
+ chr.ligatures = tt
+ end
+ end
+ end
+ if isvirtual then
+ local vc = v.commands
+ if vc then
+ -- we assume non scaled commands here
+ local ok = false
+ for i=1,#vc do
+ local key = vc[i][1]
+ if key == "right" or key == "down" then
+ ok = true
+ break
+ end
+ end
+ if ok then
+ local tt = { }
+ for i=1,#vc do
+ local ivc = vc[i]
+ local key = ivc[1]
+ if key == "right" or key == "down" then
+ tt[#tt+1] = { key, ivc[2]*delta }
+ else -- not comment
+ tt[#tt+1] = ivc -- shared since in cache and untouched
+ end
+ end
+ chr.commands = tt
+ else
+ chr.commands = vc
+ end
+ end
+ end
+ tc[k] = chr
+ end
+ -- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
+ t.size = scaledpoints
+ t.factor = delta
+ if t.fonts then
+ t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
+ end
+ if hasmath then
+ -- mathematics.extras.copy(t) -- can be done elsewhere if needed
+ local ma = tfm.mathactions
+ for i=1,#ma do
+ ma[i](t,tfmtable,delta)
+ end
+ end
+ -- needed for \high cum suis
+ local tpx = tp.x_height
+ if not tp[13] then tp[13] = .86*tpx end -- mathsupdisplay
+ if not tp[14] then tp[14] = .86*tpx end -- mathsupnormal
+ if not tp[15] then tp[15] = .86*tpx end -- mathsupcramped
+ if not tp[16] then tp[16] = .48*tpx end -- mathsubnormal
+ if not tp[17] then tp[17] = .48*tpx end -- mathsubcombined
+ if not tp[22] then tp[22] = 0 end -- mathaxisheight
+ if t.MathConstants then t.MathConstants.AccentBaseHeight = nil end -- safeguard
+ t.tounicode = 1
+ -- we have t.name=metricfile and t.fullname=RealName and t.filename=diskfilename
+ -- when collapsing fonts, luatex looks as both t.name and t.fullname as ttc files
+ -- can have multiple subfonts
+--~ collectgarbage("collect")
+ return t, delta
+end
+
+--[[ldx--
+<p>The reason why the scaler is split, is that for a while we experimented
+with a helper function. However, in practice the <l n='api'/> calls are too slow to
+make this profitable and the <l n='lua'/> based variant was just faster. A days
+wasted day but an experience richer.</p>
+--ldx]]--
+
+tfm.auto_cleanup = true
+
+local lastfont = nil
+
+-- we can get rid of the tfm instance when we have fast access to the
+-- scaled character dimensions at the tex end, e.g. a fontobject.width
+--
+-- flushing the kern and ligature tables from memory saves a lot (only
+-- base mode) but it complicates vf building where the new characters
+-- demand this data
+
+--~ for id, f in pairs(fonts.ids) do -- or font.fonts
+--~ local ffi = font.fonts[id]
+--~ f.characters = ffi.characters
+--~ f.kerns = ffi.kerns
+--~ f.ligatures = ffi.ligatures
+--~ end
+
+function tfm.cleanup_table(tfmdata) -- we need a cleanup callback, now we miss the last one
+ if tfm.auto_cleanup then -- ok, we can hook this into everyshipout or so ... todo
+ if tfmdata.type == 'virtual' or tfmdata.virtualized then
+ for k, v in next, tfmdata.characters do
+ if v.commands then v.commands = nil end
+ end
+ end
+ end
+end
+
+function tfm.cleanup(tfmdata) -- we need a cleanup callback, now we miss the last one
+end
+
+function tfm.scale(tfmtable, scaledpoints)
+ local t, factor = tfm.do_scale(tfmtable, scaledpoints)
+ t.factor = factor
+ t.ascender = factor*(tfmtable.ascender or 0)
+ t.descender = factor*(tfmtable.descender or 0)
+ t.shared = tfmtable.shared or { }
+ t.unique = table.fastcopy(tfmtable.unique or {})
+--~ print("scaling", t.name, t.factor) -- , tfm.hash_features(tfmtable.specification))
+ tfm.cleanup(t)
+ return t
+end
+
+--[[ldx--
+<p>Analyzers run per script and/or language and are needed in order to
+process features right.</p>
+--ldx]]--
+
+fonts.analyzers = fonts.analyzers or { }
+fonts.analyzers.aux = fonts.analyzers.aux or { }
+fonts.analyzers.methods = fonts.analyzers.methods or { }
+fonts.analyzers.initializers = fonts.analyzers.initializers or { }
+
+-- todo: analyzers per script/lang, cross font, so we need an font id hash -> script
+-- e.g. latin -> hyphenate, arab -> 1/2/3 analyze
+
+-- an example analyzer (should move to font-ota.lua)
+
+local state = attributes.private('state')
+
+function fonts.analyzers.aux.setstate(head,font)
+ local tfmdata = fontdata[font]
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
+ while current do
+ if current.id == glyph and current.font == font then
+ local d = descriptions[current.char]
+ if d then
+ if d.class == "mark" then
+ done = true
+ set_attribute(current,state,5) -- mark
+ elseif n == 0 then
+ first, last, n = current, current, 1
+ set_attribute(current,state,1) -- init
+ else
+ last, n = current, n+1
+ set_attribute(current,state,2) -- medi
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ else -- finish
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ first, last, n = nil, nil, 0
+ end
+ current = current.next
+ end
+ if first and first == last then
+ set_attribute(last,state,4) -- isol
+ elseif last then
+ set_attribute(last,state,3) -- fina
+ end
+ return head, done
+end
+
+function tfm.replacements(tfm,value)
+ -- tfm.characters[0x0022] = table.fastcopy(tfm.characters[0x201D])
+ -- tfm.characters[0x0027] = table.fastcopy(tfm.characters[0x2019])
+ -- tfm.characters[0x0060] = table.fastcopy(tfm.characters[0x2018])
+ -- tfm.characters[0x0022] = tfm.characters[0x201D]
+ tfm.characters[0x0027] = tfm.characters[0x2019]
+ -- tfm.characters[0x0060] = tfm.characters[0x2018]
+end
+
+-- auto complete font with missing composed characters
+
+table.insert(fonts.manipulators,"compose")
+
+function fonts.initializers.common.compose(tfmdata,value)
+ if value then
+ fonts.vf.aux.compose_characters(tfmdata)
+ end
+end
+
+-- tfm features, experimental
+
+tfm.features = tfm.features or { }
+tfm.features.list = tfm.features.list or { }
+tfm.features.default = tfm.features.default or { }
+
+function tfm.enhance(tfmdata,specification)
+ -- we don't really share tfm data because we always reload
+ -- but this is more in sycn with afm and such
+ local features = (specification.features and specification.features.normal ) or { }
+ tfmdata.shared = tfmdata.shared or { }
+ tfmdata.shared.features = features
+ -- tfmdata.shared.tfmdata = tfmdata -- circular
+tfmdata.filename = specification.name
+ if not features.encoding then
+ local name, size = specification.name, specification.size
+ local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if filename and encoding and fonts.enc.known[encoding] then
+ features.encoding = encoding
+ end
+ end
+ tfm.set_features(tfmdata)
+end
+
+function tfm.set_features(tfmdata)
+ -- todo: no local functions
+ local shared = tfmdata.shared
+-- local tfmdata = shared.tfmdata
+ local features = shared.features
+ if not table.is_empty(features) then
+ local mode = tfmdata.mode or fonts.mode
+ local fi = fonts.initializers[mode]
+ if fi and fi.tfm then
+ local function initialize(list) -- using tex lig and kerning
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ local value = features[f]
+ if value and fi.tfm[f] then -- brr
+ if tfm.trace_features then
+ logs.report("define tfm","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
+ end
+ fi.tfm[f](tfmdata,value)
+ mode = tfmdata.mode or fonts.mode
+ fi = fonts.initializers[mode]
+ end
+ end
+ end
+ end
+ initialize(fonts.triggers)
+ initialize(tfm.features.list)
+ initialize(fonts.manipulators)
+ end
+ local fm = fonts.methods[mode]
+ if fm and fm.tfm then
+ local function register(list) -- node manipulations
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ if features[f] and fm.tfm[f] then -- brr
+ if not shared.processors then -- maybe also predefine
+ shared.processors = { fm.tfm[f] }
+ else
+ shared.processors[#shared.processors+1] = fm.tfm[f]
+ end
+ end
+ end
+ end
+ end
+ register(tfm.features.list)
+ end
+ end
+end
+
+function tfm.features.register(name,default)
+ tfm.features.list[#tfm.features.list+1] = name
+ tfm.features.default[name] = default
+end
+
+function tfm.reencode(tfmdata,encoding)
+ if encoding and fonts.enc.known[encoding] then
+ local data = fonts.enc.load(encoding)
+ if data then
+ local characters, original, vector = tfmdata.characters, { }, data.vector
+ tfmdata.encoding = encoding -- not needed
+ for k, v in next, characters do
+ v.name, v.index, original[k] = vector[k], k, v
+ end
+ for k,v in next, data.unicodes do
+ if k ~= v then
+ if trace_defining then
+ logs.report("define font","reencoding U+%04X to U+%04X",k,v)
+ end
+ characters[k] = original[v]
+ end
+ end
+ end
+ end
+end
+
+tfm.features.register('reencode')
+
+fonts.initializers.base.tfm.reencode = tfm.reencode
+fonts.initializers.node.tfm.reencode = tfm.reencode
+
+fonts.enc = fonts.enc or { }
+fonts.enc.remappings = fonts.enc.remappings or { }
+
+function tfm.remap(tfmdata,remapping)
+ local vector = remapping and fonts.enc.remappings[remapping]
+ if vector then
+ local characters, original = tfmdata.characters, { }
+ for k, v in next, characters do
+ original[k], characters[k] = v, nil
+ end
+ for k,v in next, vector do
+ if k ~= v then
+ if trace_defining then
+ logs.report("define font","remapping U+%04X to U+%04X",k,v)
+ end
+ local c = original[k]
+ characters[v] = c
+ c.index = k
+ end
+ end
+ tfmdata.encodingbytes = 2
+ tfmdata.format = 'type1'
+ end
+end
+
+tfm.features.register('remap')
+
+fonts.initializers.base.tfm.remap = tfm.remap
+fonts.initializers.node.tfm.remap = tfm.remap
+
+-- status info
+
+statistics.register("fonts load time", function()
+ if statistics.elapsedindeed(fonts) then
+ return format("%s seconds",statistics.elapsedtime(fonts))
+ end
+end)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-cid'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (cidmaps)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, match = string.format, string.match
+local tonumber = tonumber
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+fonts = fonts or { }
+fonts.cid = fonts.cid or { }
+fonts.cid.map = fonts.cid.map or { }
+fonts.cid.max = fonts.cid.max or 10
+
+
+-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
+--
+-- 18964 18964 (leader)
+-- 0 /.notdef
+-- 1..95 0020
+-- 99 3000
+
+local number = lpeg.C(lpeg.R("09","af","AF")^1)
+local space = lpeg.S(" \n\r\t")
+local spaces = space^0
+local period = lpeg.P(".")
+local periods = period * period
+local name = lpeg.P("/") * lpeg.C((1-space)^1)
+
+local unicodes, names = { }, { }
+
+local function do_one(a,b)
+ unicodes[tonumber(a)] = tonumber(b,16)
+end
+
+local function do_range(a,b,c)
+ c = tonumber(c,16)
+ for i=tonumber(a),tonumber(b) do
+ unicodes[i] = c
+ c = c + 1
+ end
+end
+
+local function do_name(a,b)
+ names[tonumber(a)] = b
+end
+
+local grammar = lpeg.P { "start",
+ start = number * spaces * number * lpeg.V("series"),
+ series = (spaces * (lpeg.V("one") + lpeg.V("range") + lpeg.V("named")) )^1,
+ one = (number * spaces * number) / do_one,
+ range = (number * periods * number * spaces * number) / do_range,
+ named = (number * spaces * name) / do_name
+}
+
+function fonts.cid.load(filename)
+ local data = io.loaddata(filename)
+ if data then
+ unicodes, names = { }, { }
+ grammar:match(data)
+ local supplement, registry, ordering = match(filename,"^(.-)%-(.-)%-()%.(.-)$")
+ return {
+ supplement = supplement,
+ registry = registry,
+ ordering = ordering,
+ filename = filename,
+ unicodes = unicodes,
+ names = names
+ }
+ else
+ return nil
+ end
+end
+
+local template = "%s-%s-%s.cidmap"
+
+local function locate(registry,ordering,supplement)
+ local filename = string.lower(format(template,registry,ordering,supplement))
+ local cidmap = fonts.cid.map[filename]
+ if not cidmap then
+ if trace_loading then
+ logs.report("load otf","checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
+ end
+ local fullname = resolvers.find_file(filename,'cid') or ""
+ if fullname ~= "" then
+ cidmap = fonts.cid.load(fullname)
+ if cidmap then
+ if trace_loading then
+ logs.report("load otf","using cidmap file %s",filename)
+ end
+ fonts.cid.map[filename] = cidmap
+ return cidmap
+ end
+ end
+ end
+ return cidmap
+end
+
+function fonts.cid.getmap(registry,ordering,supplement)
+ -- cf Arthur R. we can safely scan upwards since cids are downward compatible
+ local supplement = tonumber(supplement)
+ if trace_loading then
+ logs.report("load otf","needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
+ end
+ local cidmap = locate(registry,ordering,supplement)
+ if not cidmap then
+ local cidnum = nil
+ -- next highest (alternatively we could start high)
+ if supplement < fonts.cid.max then
+ for supplement=supplement+1,fonts.cid.max do
+ local c = locate(registry,ordering,supplement)
+ if c then
+ cidmap, cidnum = c, supplement
+ break
+ end
+ end
+ end
+ -- next lowest (least worse fit)
+ if not cidmap and supplement > 0 then
+ for supplement=supplement-1,0,-1 do
+ local c = locate(registry,ordering,supplement)
+ if c then
+ cidmap, cidnum = c, supplement
+ break
+ end
+ end
+ end
+ -- prevent further lookups
+ if cidmap and cidnum > 0 then
+ for s=0,cidnum-1 do
+ filename = format(template,registry,ordering,s)
+ if not fonts.cid.map[filename] then
+ fonts.cid.map[filename] = cidmap -- copy of ref
+ end
+ end
+ end
+ end
+ return cidmap
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otf'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (tables)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+local gsub, lower = string.gsub, string.lower
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+
+otf.tables = otf.tables or { }
+otf.meanings = otf.meanings or { }
+
+otf.tables.scripts = {
+ ['dflt'] = 'Default',
+
+ ['arab'] = 'Arabic',
+ ['armn'] = 'Armenian',
+ ['bali'] = 'Balinese',
+ ['beng'] = 'Bengali',
+ ['bopo'] = 'Bopomofo',
+ ['brai'] = 'Braille',
+ ['bugi'] = 'Buginese',
+ ['buhd'] = 'Buhid',
+ ['byzm'] = 'Byzantine Music',
+ ['cans'] = 'Canadian Syllabics',
+ ['cher'] = 'Cherokee',
+ ['copt'] = 'Coptic',
+ ['cprt'] = 'Cypriot Syllabary',
+ ['cyrl'] = 'Cyrillic',
+ ['deva'] = 'Devanagari',
+ ['dsrt'] = 'Deseret',
+ ['ethi'] = 'Ethiopic',
+ ['geor'] = 'Georgian',
+ ['glag'] = 'Glagolitic',
+ ['goth'] = 'Gothic',
+ ['grek'] = 'Greek',
+ ['gujr'] = 'Gujarati',
+ ['guru'] = 'Gurmukhi',
+ ['hang'] = 'Hangul',
+ ['hani'] = 'CJK Ideographic',
+ ['hano'] = 'Hanunoo',
+ ['hebr'] = 'Hebrew',
+ ['ital'] = 'Old Italic',
+ ['jamo'] = 'Hangul Jamo',
+ ['java'] = 'Javanese',
+ ['kana'] = 'Hiragana and Katakana',
+ ['khar'] = 'Kharosthi',
+ ['khmr'] = 'Khmer',
+ ['knda'] = 'Kannada',
+ ['lao' ] = 'Lao',
+ ['latn'] = 'Latin',
+ ['limb'] = 'Limbu',
+ ['linb'] = 'Linear B',
+ ['math'] = 'Mathematical Alphanumeric Symbols',
+ ['mlym'] = 'Malayalam',
+ ['mong'] = 'Mongolian',
+ ['musc'] = 'Musical Symbols',
+ ['mymr'] = 'Myanmar',
+ ['nko' ] = "N'ko",
+ ['ogam'] = 'Ogham',
+ ['orya'] = 'Oriya',
+ ['osma'] = 'Osmanya',
+ ['phag'] = 'Phags-pa',
+ ['phnx'] = 'Phoenician',
+ ['runr'] = 'Runic',
+ ['shaw'] = 'Shavian',
+ ['sinh'] = 'Sinhala',
+ ['sylo'] = 'Syloti Nagri',
+ ['syrc'] = 'Syriac',
+ ['tagb'] = 'Tagbanwa',
+ ['tale'] = 'Tai Le',
+ ['talu'] = 'Tai Lu',
+ ['taml'] = 'Tamil',
+ ['telu'] = 'Telugu',
+ ['tfng'] = 'Tifinagh',
+ ['tglg'] = 'Tagalog',
+ ['thaa'] = 'Thaana',
+ ['thai'] = 'Thai',
+ ['tibt'] = 'Tibetan',
+ ['ugar'] = 'Ugaritic Cuneiform',
+ ['xpeo'] = 'Old Persian Cuneiform',
+ ['xsux'] = 'Sumero-Akkadian Cuneiform',
+ ['yi' ] = 'Yi'
+}
+
+otf.tables.languages = {
+ ['dflt'] = 'Default',
+
+ ['aba'] = 'Abaza',
+ ['abk'] = 'Abkhazian',
+ ['ady'] = 'Adyghe',
+ ['afk'] = 'Afrikaans',
+ ['afr'] = 'Afar',
+ ['agw'] = 'Agaw',
+ ['als'] = 'Alsatian',
+ ['alt'] = 'Altai',
+ ['amh'] = 'Amharic',
+ ['ara'] = 'Arabic',
+ ['ari'] = 'Aari',
+ ['ark'] = 'Arakanese',
+ ['asm'] = 'Assamese',
+ ['ath'] = 'Athapaskan',
+ ['avr'] = 'Avar',
+ ['awa'] = 'Awadhi',
+ ['aym'] = 'Aymara',
+ ['aze'] = 'Azeri',
+ ['bad'] = 'Badaga',
+ ['bag'] = 'Baghelkhandi',
+ ['bal'] = 'Balkar',
+ ['bau'] = 'Baule',
+ ['bbr'] = 'Berber',
+ ['bch'] = 'Bench',
+ ['bcr'] = 'Bible Cree',
+ ['bel'] = 'Belarussian',
+ ['bem'] = 'Bemba',
+ ['ben'] = 'Bengali',
+ ['bgr'] = 'Bulgarian',
+ ['bhi'] = 'Bhili',
+ ['bho'] = 'Bhojpuri',
+ ['bik'] = 'Bikol',
+ ['bil'] = 'Bilen',
+ ['bkf'] = 'Blackfoot',
+ ['bli'] = 'Balochi',
+ ['bln'] = 'Balante',
+ ['blt'] = 'Balti',
+ ['bmb'] = 'Bambara',
+ ['bml'] = 'Bamileke',
+ ['bos'] = 'Bosnian',
+ ['bre'] = 'Breton',
+ ['brh'] = 'Brahui',
+ ['bri'] = 'Braj Bhasha',
+ ['brm'] = 'Burmese',
+ ['bsh'] = 'Bashkir',
+ ['bti'] = 'Beti',
+ ['cat'] = 'Catalan',
+ ['ceb'] = 'Cebuano',
+ ['che'] = 'Chechen',
+ ['chg'] = 'Chaha Gurage',
+ ['chh'] = 'Chattisgarhi',
+ ['chi'] = 'Chichewa',
+ ['chk'] = 'Chukchi',
+ ['chp'] = 'Chipewyan',
+ ['chr'] = 'Cherokee',
+ ['chu'] = 'Chuvash',
+ ['cmr'] = 'Comorian',
+ ['cop'] = 'Coptic',
+ ['cos'] = 'Corsican',
+ ['cre'] = 'Cree',
+ ['crr'] = 'Carrier',
+ ['crt'] = 'Crimean Tatar',
+ ['csl'] = 'Church Slavonic',
+ ['csy'] = 'Czech',
+ ['dan'] = 'Danish',
+ ['dar'] = 'Dargwa',
+ ['dcr'] = 'Woods Cree',
+ ['deu'] = 'German',
+ ['dgr'] = 'Dogri',
+ ['div'] = 'Divehi',
+ ['djr'] = 'Djerma',
+ ['dng'] = 'Dangme',
+ ['dnk'] = 'Dinka',
+ ['dri'] = 'Dari',
+ ['dun'] = 'Dungan',
+ ['dzn'] = 'Dzongkha',
+ ['ebi'] = 'Ebira',
+ ['ecr'] = 'Eastern Cree',
+ ['edo'] = 'Edo',
+ ['efi'] = 'Efik',
+ ['ell'] = 'Greek',
+ ['eng'] = 'English',
+ ['erz'] = 'Erzya',
+ ['esp'] = 'Spanish',
+ ['eti'] = 'Estonian',
+ ['euq'] = 'Basque',
+ ['evk'] = 'Evenki',
+ ['evn'] = 'Even',
+ ['ewe'] = 'Ewe',
+ ['fan'] = 'French Antillean',
+ ['far'] = 'Farsi',
+ ['fin'] = 'Finnish',
+ ['fji'] = 'Fijian',
+ ['fle'] = 'Flemish',
+ ['fne'] = 'Forest Nenets',
+ ['fon'] = 'Fon',
+ ['fos'] = 'Faroese',
+ ['fra'] = 'French',
+ ['fri'] = 'Frisian',
+ ['frl'] = 'Friulian',
+ ['fta'] = 'Futa',
+ ['ful'] = 'Fulani',
+ ['gad'] = 'Ga',
+ ['gae'] = 'Gaelic',
+ ['gag'] = 'Gagauz',
+ ['gal'] = 'Galician',
+ ['gar'] = 'Garshuni',
+ ['gaw'] = 'Garhwali',
+ ['gez'] = "Ge'ez",
+ ['gil'] = 'Gilyak',
+ ['gmz'] = 'Gumuz',
+ ['gon'] = 'Gondi',
+ ['grn'] = 'Greenlandic',
+ ['gro'] = 'Garo',
+ ['gua'] = 'Guarani',
+ ['guj'] = 'Gujarati',
+ ['hai'] = 'Haitian',
+ ['hal'] = 'Halam',
+ ['har'] = 'Harauti',
+ ['hau'] = 'Hausa',
+ ['haw'] = 'Hawaiin',
+ ['hbn'] = 'Hammer-Banna',
+ ['hil'] = 'Hiligaynon',
+ ['hin'] = 'Hindi',
+ ['hma'] = 'High Mari',
+ ['hnd'] = 'Hindko',
+ ['ho'] = 'Ho',
+ ['hri'] = 'Harari',
+ ['hrv'] = 'Croatian',
+ ['hun'] = 'Hungarian',
+ ['hye'] = 'Armenian',
+ ['ibo'] = 'Igbo',
+ ['ijo'] = 'Ijo',
+ ['ilo'] = 'Ilokano',
+ ['ind'] = 'Indonesian',
+ ['ing'] = 'Ingush',
+ ['inu'] = 'Inuktitut',
+ ['iri'] = 'Irish',
+ ['irt'] = 'Irish Traditional',
+ ['isl'] = 'Icelandic',
+ ['ism'] = 'Inari Sami',
+ ['ita'] = 'Italian',
+ ['iwr'] = 'Hebrew',
+ ['jan'] = 'Japanese',
+ ['jav'] = 'Javanese',
+ ['jii'] = 'Yiddish',
+ ['jud'] = 'Judezmo',
+ ['jul'] = 'Jula',
+ ['kab'] = 'Kabardian',
+ ['kac'] = 'Kachchi',
+ ['kal'] = 'Kalenjin',
+ ['kan'] = 'Kannada',
+ ['kar'] = 'Karachay',
+ ['kat'] = 'Georgian',
+ ['kaz'] = 'Kazakh',
+ ['keb'] = 'Kebena',
+ ['kge'] = 'Khutsuri Georgian',
+ ['kha'] = 'Khakass',
+ ['khk'] = 'Khanty-Kazim',
+ ['khm'] = 'Khmer',
+ ['khs'] = 'Khanty-Shurishkar',
+ ['khv'] = 'Khanty-Vakhi',
+ ['khw'] = 'Khowar',
+ ['kik'] = 'Kikuyu',
+ ['kir'] = 'Kirghiz',
+ ['kis'] = 'Kisii',
+ ['kkn'] = 'Kokni',
+ ['klm'] = 'Kalmyk',
+ ['kmb'] = 'Kamba',
+ ['kmn'] = 'Kumaoni',
+ ['kmo'] = 'Komo',
+ ['kms'] = 'Komso',
+ ['knr'] = 'Kanuri',
+ ['kod'] = 'Kodagu',
+ ['koh'] = 'Korean Old Hangul',
+ ['kok'] = 'Konkani',
+ ['kon'] = 'Kikongo',
+ ['kop'] = 'Komi-Permyak',
+ ['kor'] = 'Korean',
+ ['koz'] = 'Komi-Zyrian',
+ ['kpl'] = 'Kpelle',
+ ['kri'] = 'Krio',
+ ['krk'] = 'Karakalpak',
+ ['krl'] = 'Karelian',
+ ['krm'] = 'Karaim',
+ ['krn'] = 'Karen',
+ ['krt'] = 'Koorete',
+ ['ksh'] = 'Kashmiri',
+ ['ksi'] = 'Khasi',
+ ['ksm'] = 'Kildin Sami',
+ ['kui'] = 'Kui',
+ ['kul'] = 'Kulvi',
+ ['kum'] = 'Kumyk',
+ ['kur'] = 'Kurdish',
+ ['kuu'] = 'Kurukh',
+ ['kuy'] = 'Kuy',
+ ['kyk'] = 'Koryak',
+ ['lad'] = 'Ladin',
+ ['lah'] = 'Lahuli',
+ ['lak'] = 'Lak',
+ ['lam'] = 'Lambani',
+ ['lao'] = 'Lao',
+ ['lat'] = 'Latin',
+ ['laz'] = 'Laz',
+ ['lcr'] = 'L-Cree',
+ ['ldk'] = 'Ladakhi',
+ ['lez'] = 'Lezgi',
+ ['lin'] = 'Lingala',
+ ['lma'] = 'Low Mari',
+ ['lmb'] = 'Limbu',
+ ['lmw'] = 'Lomwe',
+ ['lsb'] = 'Lower Sorbian',
+ ['lsm'] = 'Lule Sami',
+ ['lth'] = 'Lithuanian',
+ ['ltz'] = 'Luxembourgish',
+ ['lub'] = 'Luba',
+ ['lug'] = 'Luganda',
+ ['luh'] = 'Luhya',
+ ['luo'] = 'Luo',
+ ['lvi'] = 'Latvian',
+ ['maj'] = 'Majang',
+ ['mak'] = 'Makua',
+ ['mal'] = 'Malayalam Traditional',
+ ['man'] = 'Mansi',
+ ['map'] = 'Mapudungun',
+ ['mar'] = 'Marathi',
+ ['maw'] = 'Marwari',
+ ['mbn'] = 'Mbundu',
+ ['mch'] = 'Manchu',
+ ['mcr'] = 'Moose Cree',
+ ['mde'] = 'Mende',
+ ['men'] = "Me'en",
+ ['miz'] = 'Mizo',
+ ['mkd'] = 'Macedonian',
+ ['mle'] = 'Male',
+ ['mlg'] = 'Malagasy',
+ ['mln'] = 'Malinke',
+ ['mlr'] = 'Malayalam Reformed',
+ ['mly'] = 'Malay',
+ ['mnd'] = 'Mandinka',
+ ['mng'] = 'Mongolian',
+ ['mni'] = 'Manipuri',
+ ['mnk'] = 'Maninka',
+ ['mnx'] = 'Manx Gaelic',
+ ['moh'] = 'Mohawk',
+ ['mok'] = 'Moksha',
+ ['mol'] = 'Moldavian',
+ ['mon'] = 'Mon',
+ ['mor'] = 'Moroccan',
+ ['mri'] = 'Maori',
+ ['mth'] = 'Maithili',
+ ['mts'] = 'Maltese',
+ ['mun'] = 'Mundari',
+ ['nag'] = 'Naga-Assamese',
+ ['nan'] = 'Nanai',
+ ['nas'] = 'Naskapi',
+ ['ncr'] = 'N-Cree',
+ ['ndb'] = 'Ndebele',
+ ['ndg'] = 'Ndonga',
+ ['nep'] = 'Nepali',
+ ['new'] = 'Newari',
+ ['ngr'] = 'Nagari',
+ ['nhc'] = 'Norway House Cree',
+ ['nis'] = 'Nisi',
+ ['niu'] = 'Niuean',
+ ['nkl'] = 'Nkole',
+ ['nko'] = "N'ko",
+ ['nld'] = 'Dutch',
+ ['nog'] = 'Nogai',
+ ['nor'] = 'Norwegian',
+ ['nsm'] = 'Northern Sami',
+ ['nta'] = 'Northern Tai',
+ ['nto'] = 'Esperanto',
+ ['nyn'] = 'Nynorsk',
+ ['oci'] = 'Occitan',
+ ['ocr'] = 'Oji-Cree',
+ ['ojb'] = 'Ojibway',
+ ['ori'] = 'Oriya',
+ ['oro'] = 'Oromo',
+ ['oss'] = 'Ossetian',
+ ['paa'] = 'Palestinian Aramaic',
+ ['pal'] = 'Pali',
+ ['pan'] = 'Punjabi',
+ ['pap'] = 'Palpa',
+ ['pas'] = 'Pashto',
+ ['pgr'] = 'Polytonic Greek',
+ ['pil'] = 'Pilipino',
+ ['plg'] = 'Palaung',
+ ['plk'] = 'Polish',
+ ['pro'] = 'Provencal',
+ ['ptg'] = 'Portuguese',
+ ['qin'] = 'Chin',
+ ['raj'] = 'Rajasthani',
+ ['rbu'] = 'Russian Buriat',
+ ['rcr'] = 'R-Cree',
+ ['ria'] = 'Riang',
+ ['rms'] = 'Rhaeto-Romanic',
+ ['rom'] = 'Romanian',
+ ['roy'] = 'Romany',
+ ['rsy'] = 'Rusyn',
+ ['rua'] = 'Ruanda',
+ ['rus'] = 'Russian',
+ ['sad'] = 'Sadri',
+ ['san'] = 'Sanskrit',
+ ['sat'] = 'Santali',
+ ['say'] = 'Sayisi',
+ ['sek'] = 'Sekota',
+ ['sel'] = 'Selkup',
+ ['sgo'] = 'Sango',
+ ['shn'] = 'Shan',
+ ['sib'] = 'Sibe',
+ ['sid'] = 'Sidamo',
+ ['sig'] = 'Silte Gurage',
+ ['sks'] = 'Skolt Sami',
+ ['sky'] = 'Slovak',
+ ['sla'] = 'Slavey',
+ ['slv'] = 'Slovenian',
+ ['sml'] = 'Somali',
+ ['smo'] = 'Samoan',
+ ['sna'] = 'Sena',
+ ['snd'] = 'Sindhi',
+ ['snh'] = 'Sinhalese',
+ ['snk'] = 'Soninke',
+ ['sog'] = 'Sodo Gurage',
+ ['sot'] = 'Sotho',
+ ['sqi'] = 'Albanian',
+ ['srb'] = 'Serbian',
+ ['srk'] = 'Saraiki',
+ ['srr'] = 'Serer',
+ ['ssl'] = 'South Slavey',
+ ['ssm'] = 'Southern Sami',
+ ['sur'] = 'Suri',
+ ['sva'] = 'Svan',
+ ['sve'] = 'Swedish',
+ ['swa'] = 'Swadaya Aramaic',
+ ['swk'] = 'Swahili',
+ ['swz'] = 'Swazi',
+ ['sxt'] = 'Sutu',
+ ['syr'] = 'Syriac',
+ ['tab'] = 'Tabasaran',
+ ['taj'] = 'Tajiki',
+ ['tam'] = 'Tamil',
+ ['tat'] = 'Tatar',
+ ['tcr'] = 'TH-Cree',
+ ['tel'] = 'Telugu',
+ ['tgn'] = 'Tongan',
+ ['tgr'] = 'Tigre',
+ ['tgy'] = 'Tigrinya',
+ ['tha'] = 'Thai',
+ ['tht'] = 'Tahitian',
+ ['tib'] = 'Tibetan',
+ ['tkm'] = 'Turkmen',
+ ['tmn'] = 'Temne',
+ ['tna'] = 'Tswana',
+ ['tne'] = 'Tundra Nenets',
+ ['tng'] = 'Tonga',
+ ['tod'] = 'Todo',
+ ['trk'] = 'Turkish',
+ ['tsg'] = 'Tsonga',
+ ['tua'] = 'Turoyo Aramaic',
+ ['tul'] = 'Tulu',
+ ['tuv'] = 'Tuvin',
+ ['twi'] = 'Twi',
+ ['udm'] = 'Udmurt',
+ ['ukr'] = 'Ukrainian',
+ ['urd'] = 'Urdu',
+ ['usb'] = 'Upper Sorbian',
+ ['uyg'] = 'Uyghur',
+ ['uzb'] = 'Uzbek',
+ ['ven'] = 'Venda',
+ ['vit'] = 'Vietnamese',
+ ['wa' ] = 'Wa',
+ ['wag'] = 'Wagdi',
+ ['wcr'] = 'West-Cree',
+ ['wel'] = 'Welsh',
+ ['wlf'] = 'Wolof',
+ ['xbd'] = 'Tai Lue',
+ ['xhs'] = 'Xhosa',
+ ['yak'] = 'Yakut',
+ ['yba'] = 'Yoruba',
+ ['ycr'] = 'Y-Cree',
+ ['yic'] = 'Yi Classic',
+ ['yim'] = 'Yi Modern',
+ ['zhh'] = 'Chinese Hong Kong',
+ ['zhp'] = 'Chinese Phonetic',
+ ['zhs'] = 'Chinese Simplified',
+ ['zht'] = 'Chinese Traditional',
+ ['znd'] = 'Zande',
+ ['zul'] = 'Zulu'
+}
+
+otf.tables.features = {
+ ['aalt'] = 'Access All Alternates',
+ ['abvf'] = 'Above-Base Forms',
+ ['abvm'] = 'Above-Base Mark Positioning',
+ ['abvs'] = 'Above-Base Substitutions',
+ ['afrc'] = 'Alternative Fractions',
+ ['akhn'] = 'Akhands',
+ ['blwf'] = 'Below-Base Forms',
+ ['blwm'] = 'Below-Base Mark Positioning',
+ ['blws'] = 'Below-Base Substitutions',
+ ['c2pc'] = 'Petite Capitals From Capitals',
+ ['c2sc'] = 'Small Capitals From Capitals',
+ ['calt'] = 'Contextual Alternates',
+ ['case'] = 'Case-Sensitive Forms',
+ ['ccmp'] = 'Glyph Composition/Decomposition',
+ ['cjct'] = 'Conjunct Forms',
+ ['clig'] = 'Contextual Ligatures',
+ ['cpsp'] = 'Capital Spacing',
+ ['cswh'] = 'Contextual Swash',
+ ['curs'] = 'Cursive Positioning',
+ ['dflt'] = 'Default Processing',
+ ['dist'] = 'Distances',
+ ['dlig'] = 'Discretionary Ligatures',
+ ['dnom'] = 'Denominators',
+ ['dtls'] = 'Dotless Forms', -- math
+ ['expt'] = 'Expert Forms',
+ ['falt'] = 'Final glyph Alternates',
+ ['fin2'] = 'Terminal Forms #2',
+ ['fin3'] = 'Terminal Forms #3',
+ ['fina'] = 'Terminal Forms',
+ ['flac'] = 'Flattened Accents Over Capitals', -- math
+ ['frac'] = 'Fractions',
+ ['fwid'] = 'Full Width',
+ ['half'] = 'Half Forms',
+ ['haln'] = 'Halant Forms',
+ ['halt'] = 'Alternate Half Width',
+ ['hist'] = 'Historical Forms',
+ ['hkna'] = 'Horizontal Kana Alternates',
+ ['hlig'] = 'Historical Ligatures',
+ ['hngl'] = 'Hangul',
+ ['hojo'] = 'Hojo Kanji Forms',
+ ['hwid'] = 'Half Width',
+ ['init'] = 'Initial Forms',
+ ['isol'] = 'Isolated Forms',
+ ['ital'] = 'Italics',
+ ['jalt'] = 'Justification Alternatives',
+ ['jp04'] = 'JIS2004 Forms',
+ ['jp78'] = 'JIS78 Forms',
+ ['jp83'] = 'JIS83 Forms',
+ ['jp90'] = 'JIS90 Forms',
+ ['kern'] = 'Kerning',
+ ['lfbd'] = 'Left Bounds',
+ ['liga'] = 'Standard Ligatures',
+ ['ljmo'] = 'Leading Jamo Forms',
+ ['lnum'] = 'Lining Figures',
+ ['locl'] = 'Localized Forms',
+ ['mark'] = 'Mark Positioning',
+ ['med2'] = 'Medial Forms #2',
+ ['medi'] = 'Medial Forms',
+ ['mgrk'] = 'Mathematical Greek',
+ ['mkmk'] = 'Mark to Mark Positioning',
+ ['mset'] = 'Mark Positioning via Substitution',
+ ['nalt'] = 'Alternate Annotation Forms',
+ ['nlck'] = 'NLC Kanji Forms',
+ ['nukt'] = 'Nukta Forms',
+ ['numr'] = 'Numerators',
+ ['onum'] = 'Old Style Figures',
+ ['opbd'] = 'Optical Bounds',
+ ['ordn'] = 'Ordinals',
+ ['ornm'] = 'Ornaments',
+ ['palt'] = 'Proportional Alternate Width',
+ ['pcap'] = 'Petite Capitals',
+ ['pnum'] = 'Proportional Figures',
+ ['pref'] = 'Pre-base Forms',
+ ['pres'] = 'Pre-base Substitutions',
+ ['pstf'] = 'Post-base Forms',
+ ['psts'] = 'Post-base Substitutions',
+ ['pwid'] = 'Proportional Widths',
+ ['qwid'] = 'Quarter Widths',
+ ['rand'] = 'Randomize',
+ ['rkrf'] = 'Rakar Forms',
+ ['rlig'] = 'Required Ligatures',
+ ['rphf'] = 'Reph Form',
+ ['rtbd'] = 'Right Bounds',
+ ['rtla'] = 'Right-To-Left Alternates',
+ ['ruby'] = 'Ruby Notation Forms',
+ ['salt'] = 'Stylistic Alternates',
+ ['sinf'] = 'Scientific Inferiors',
+ ['size'] = 'Optical Size',
+ ['smcp'] = 'Small Capitals',
+ ['smpl'] = 'Simplified Forms',
+ ['ss01'] = 'Stylistic Set 1',
+ ['ss02'] = 'Stylistic Set 2',
+ ['ss03'] = 'Stylistic Set 3',
+ ['ss04'] = 'Stylistic Set 4',
+ ['ss05'] = 'Stylistic Set 5',
+ ['ss06'] = 'Stylistic Set 6',
+ ['ss07'] = 'Stylistic Set 7',
+ ['ss08'] = 'Stylistic Set 8',
+ ['ss09'] = 'Stylistic Set 9',
+ ['ss10'] = 'Stylistic Set 10',
+ ['ss11'] = 'Stylistic Set 11',
+ ['ss12'] = 'Stylistic Set 12',
+ ['ss13'] = 'Stylistic Set 13',
+ ['ss14'] = 'Stylistic Set 14',
+ ['ss15'] = 'Stylistic Set 15',
+ ['ss16'] = 'Stylistic Set 16',
+ ['ss17'] = 'Stylistic Set 17',
+ ['ss18'] = 'Stylistic Set 18',
+ ['ss19'] = 'Stylistic Set 19',
+ ['ss20'] = 'Stylistic Set 20',
+ ['ssty'] = 'Script Style', -- math
+ ['subs'] = 'Subscript',
+ ['sups'] = 'Superscript',
+ ['swsh'] = 'Swash',
+ ['titl'] = 'Titling',
+ ['tjmo'] = 'Trailing Jamo Forms',
+ ['tnam'] = 'Traditional Name Forms',
+ ['tnum'] = 'Tabular Figures',
+ ['trad'] = 'Traditional Forms',
+ ['twid'] = 'Third Widths',
+ ['unic'] = 'Unicase',
+ ['valt'] = 'Alternate Vertical Metrics',
+ ['vatu'] = 'Vattu Variants',
+ ['vert'] = 'Vertical Writing',
+ ['vhal'] = 'Alternate Vertical Half Metrics',
+ ['vjmo'] = 'Vowel Jamo Forms',
+ ['vkna'] = 'Vertical Kana Alternates',
+ ['vkrn'] = 'Vertical Kerning',
+ ['vpal'] = 'Proportional Alternate Vertical Metrics',
+ ['vrt2'] = 'Vertical Rotation',
+ ['zero'] = 'Slashed Zero',
+
+ ['trep'] = 'Traditional TeX Replacements',
+ ['tlig'] = 'Traditional TeX Ligatures',
+}
+
+otf.tables.baselines = {
+ ['hang'] = 'Hanging baseline',
+ ['icfb'] = 'Ideographic character face bottom edge baseline',
+ ['icft'] = 'Ideographic character face tope edige baseline',
+ ['ideo'] = 'Ideographic em-box bottom edge baseline',
+ ['idtp'] = 'Ideographic em-box top edge baseline',
+ ['math'] = 'Mathmatical centered baseline',
+ ['romn'] = 'Roman baseline'
+}
+
+-- can be sped up by local tables
+
+function otf.tables.to_tag(id)
+ return stringformat("%4s",lower(id))
+end
+
+local function resolve(tab,id)
+ if tab and id then
+ id = lower(id)
+ return tab[id] or tab[gsub(id," ","")] or tab['dflt'] or ''
+ else
+ return "unknown"
+ end
+end
+
+function otf.meanings.script(id)
+ return resolve(otf.tables.scripts,id)
+end
+function otf.meanings.language(id)
+ return resolve(otf.tables.languages,id)
+end
+function otf.meanings.feature(id)
+ return resolve(otf.tables.features,id)
+end
+function otf.meanings.baseline(id)
+ return resolve(otf.tables.baselines,id)
+end
+
+otf.tables.to_scripts = table.reverse_hash(otf.tables.scripts )
+otf.tables.to_languages = table.reverse_hash(otf.tables.languages)
+otf.tables.to_features = table.reverse_hash(otf.tables.features )
+
+local scripts = otf.tables.scripts
+local languages = otf.tables.languages
+local features = otf.tables.features
+
+local to_scripts = otf.tables.to_scripts
+local to_languages = otf.tables.to_languages
+local to_features = otf.tables.to_features
+
+function otf.meanings.normalize(features)
+ local h = { }
+ for k,v in next, features do
+ k = lower(k)
+ if k == "language" or k == "lang" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ k = language
+ if not languages[v] then
+ h.language = to_languages[v] or "dflt"
+ else
+ h.language = v
+ end
+ elseif k == "script" then
+ v = gsub(lower(v),"[^a-z0-9%-]","")
+ if not scripts[v] then
+ h.script = to_scripts[v] or "dflt"
+ else
+ h.script = v
+ end
+ else
+ if type(v) == "string" then
+ local b = v:is_boolean()
+ if type(b) == "nil" then
+ v = tonumber(v) or lower(v)
+ else
+ v = b
+ end
+ end
+ h[to_features[k] or k] = v
+ end
+ end
+ return h
+end
+
+-- When I feel the need ...
+
+--~ otf.tables.aat = {
+--~ [ 0] = {
+--~ name = "allTypographicFeaturesType",
+--~ [ 0] = "allTypeFeaturesOnSelector",
+--~ [ 1] = "allTypeFeaturesOffSelector",
+--~ },
+--~ [ 1] = {
+--~ name = "ligaturesType",
+--~ [0 ] = "requiredLigaturesOnSelector",
+--~ [1 ] = "requiredLigaturesOffSelector",
+--~ [2 ] = "commonLigaturesOnSelector",
+--~ [3 ] = "commonLigaturesOffSelector",
+--~ [4 ] = "rareLigaturesOnSelector",
+--~ [5 ] = "rareLigaturesOffSelector",
+--~ [6 ] = "logosOnSelector ",
+--~ [7 ] = "logosOffSelector ",
+--~ [8 ] = "rebusPicturesOnSelector",
+--~ [9 ] = "rebusPicturesOffSelector",
+--~ [10] = "diphthongLigaturesOnSelector",
+--~ [11] = "diphthongLigaturesOffSelector",
+--~ [12] = "squaredLigaturesOnSelector",
+--~ [13] = "squaredLigaturesOffSelector",
+--~ [14] = "abbrevSquaredLigaturesOnSelector",
+--~ [15] = "abbrevSquaredLigaturesOffSelector",
+--~ },
+--~ [ 2] = {
+--~ name = "cursiveConnectionType",
+--~ [ 0] = "unconnectedSelector",
+--~ [ 1] = "partiallyConnectedSelector",
+--~ [ 2] = "cursiveSelector ",
+--~ },
+--~ [ 3] = {
+--~ name = "letterCaseType",
+--~ [ 0] = "upperAndLowerCaseSelector",
+--~ [ 1] = "allCapsSelector ",
+--~ [ 2] = "allLowerCaseSelector",
+--~ [ 3] = "smallCapsSelector ",
+--~ [ 4] = "initialCapsSelector",
+--~ [ 5] = "initialCapsAndSmallCapsSelector",
+--~ },
+--~ [ 4] = {
+--~ name = "verticalSubstitutionType",
+--~ [ 0] = "substituteVerticalFormsOnSelector",
+--~ [ 1] = "substituteVerticalFormsOffSelector",
+--~ },
+--~ [ 5] = {
+--~ name = "linguisticRearrangementType",
+--~ [ 0] = "linguisticRearrangementOnSelector",
+--~ [ 1] = "linguisticRearrangementOffSelector",
+--~ },
+--~ [ 6] = {
+--~ name = "numberSpacingType",
+--~ [ 0] = "monospacedNumbersSelector",
+--~ [ 1] = "proportionalNumbersSelector",
+--~ },
+--~ [ 7] = {
+--~ name = "appleReserved1Type",
+--~ },
+--~ [ 8] = {
+--~ name = "smartSwashType",
+--~ [ 0] = "wordInitialSwashesOnSelector",
+--~ [ 1] = "wordInitialSwashesOffSelector",
+--~ [ 2] = "wordFinalSwashesOnSelector",
+--~ [ 3] = "wordFinalSwashesOffSelector",
+--~ [ 4] = "lineInitialSwashesOnSelector",
+--~ [ 5] = "lineInitialSwashesOffSelector",
+--~ [ 6] = "lineFinalSwashesOnSelector",
+--~ [ 7] = "lineFinalSwashesOffSelector",
+--~ [ 8] = "nonFinalSwashesOnSelector",
+--~ [ 9] = "nonFinalSwashesOffSelector",
+--~ },
+--~ [ 9] = {
+--~ name = "diacriticsType",
+--~ [ 0] = "showDiacriticsSelector",
+--~ [ 1] = "hideDiacriticsSelector",
+--~ [ 2] = "decomposeDiacriticsSelector",
+--~ },
+--~ [10] = {
+--~ name = "verticalPositionType",
+--~ [ 0] = "normalPositionSelector",
+--~ [ 1] = "superiorsSelector ",
+--~ [ 2] = "inferiorsSelector ",
+--~ [ 3] = "ordinalsSelector ",
+--~ },
+--~ [11] = {
+--~ name = "fractionsType",
+--~ [ 0] = "noFractionsSelector",
+--~ [ 1] = "verticalFractionsSelector",
+--~ [ 2] = "diagonalFractionsSelector",
+--~ },
+--~ [12] = {
+--~ name = "appleReserved2Type",
+--~ },
+--~ [13] = {
+--~ name = "overlappingCharactersType",
+--~ [ 0] = "preventOverlapOnSelector",
+--~ [ 1] = "preventOverlapOffSelector",
+--~ },
+--~ [14] = {
+--~ name = "typographicExtrasType",
+--~ [0 ] = "hyphensToEmDashOnSelector",
+--~ [1 ] = "hyphensToEmDashOffSelector",
+--~ [2 ] = "hyphenToEnDashOnSelector",
+--~ [3 ] = "hyphenToEnDashOffSelector",
+--~ [4 ] = "unslashedZeroOnSelector",
+--~ [5 ] = "unslashedZeroOffSelector",
+--~ [6 ] = "formInterrobangOnSelector",
+--~ [7 ] = "formInterrobangOffSelector",
+--~ [8 ] = "smartQuotesOnSelector",
+--~ [9 ] = "smartQuotesOffSelector",
+--~ [10] = "periodsToEllipsisOnSelector",
+--~ [11] = "periodsToEllipsisOffSelector",
+--~ },
+--~ [15] = {
+--~ name = "mathematicalExtrasType",
+--~ [ 0] = "hyphenToMinusOnSelector",
+--~ [ 1] = "hyphenToMinusOffSelector",
+--~ [ 2] = "asteriskToMultiplyOnSelector",
+--~ [ 3] = "asteriskToMultiplyOffSelector",
+--~ [ 4] = "slashToDivideOnSelector",
+--~ [ 5] = "slashToDivideOffSelector",
+--~ [ 6] = "inequalityLigaturesOnSelector",
+--~ [ 7] = "inequalityLigaturesOffSelector",
+--~ [ 8] = "exponentsOnSelector",
+--~ [ 9] = "exponentsOffSelector",
+--~ },
+--~ [16] = {
+--~ name = "ornamentSetsType",
+--~ [ 0] = "noOrnamentsSelector",
+--~ [ 1] = "dingbatsSelector ",
+--~ [ 2] = "piCharactersSelector",
+--~ [ 3] = "fleuronsSelector ",
+--~ [ 4] = "decorativeBordersSelector",
+--~ [ 5] = "internationalSymbolsSelector",
+--~ [ 6] = "mathSymbolsSelector",
+--~ },
+--~ [17] = {
+--~ name = "characterAlternativesType",
+--~ [ 0] = "noAlternatesSelector",
+--~ },
+--~ [18] = {
+--~ name = "designComplexityType",
+--~ [ 0] = "designLevel1Selector",
+--~ [ 1] = "designLevel2Selector",
+--~ [ 2] = "designLevel3Selector",
+--~ [ 3] = "designLevel4Selector",
+--~ [ 4] = "designLevel5Selector",
+--~ },
+--~ [19] = {
+--~ name = "styleOptionsType",
+--~ [ 0] = "noStyleOptionsSelector",
+--~ [ 1] = "displayTextSelector",
+--~ [ 2] = "engravedTextSelector",
+--~ [ 3] = "illuminatedCapsSelector",
+--~ [ 4] = "titlingCapsSelector",
+--~ [ 5] = "tallCapsSelector ",
+--~ },
+--~ [20] = {
+--~ name = "characterShapeType",
+--~ [0 ] = "traditionalCharactersSelector",
+--~ [1 ] = "simplifiedCharactersSelector",
+--~ [2 ] = "jis1978CharactersSelector",
+--~ [3 ] = "jis1983CharactersSelector",
+--~ [4 ] = "jis1990CharactersSelector",
+--~ [5 ] = "traditionalAltOneSelector",
+--~ [6 ] = "traditionalAltTwoSelector",
+--~ [7 ] = "traditionalAltThreeSelector",
+--~ [8 ] = "traditionalAltFourSelector",
+--~ [9 ] = "traditionalAltFiveSelector",
+--~ [10] = "expertCharactersSelector",
+--~ },
+--~ [21] = {
+--~ name = "numberCaseType",
+--~ [ 0] = "lowerCaseNumbersSelector",
+--~ [ 1] = "upperCaseNumbersSelector",
+--~ },
+--~ [22] = {
+--~ name = "textSpacingType",
+--~ [ 0] = "proportionalTextSelector",
+--~ [ 1] = "monospacedTextSelector",
+--~ [ 2] = "halfWidthTextSelector",
+--~ [ 3] = "normallySpacedTextSelector",
+--~ },
+--~ [23] = {
+--~ name = "transliterationType",
+--~ [ 0] = "noTransliterationSelector",
+--~ [ 1] = "hanjaToHangulSelector",
+--~ [ 2] = "hiraganaToKatakanaSelector",
+--~ [ 3] = "katakanaToHiraganaSelector",
+--~ [ 4] = "kanaToRomanizationSelector",
+--~ [ 5] = "romanizationToHiraganaSelector",
+--~ [ 6] = "romanizationToKatakanaSelector",
+--~ [ 7] = "hanjaToHangulAltOneSelector",
+--~ [ 8] = "hanjaToHangulAltTwoSelector",
+--~ [ 9] = "hanjaToHangulAltThreeSelector",
+--~ },
+--~ [24] = {
+--~ name = "annotationType",
+--~ [ 0] = "noAnnotationSelector",
+--~ [ 1] = "boxAnnotationSelector",
+--~ [ 2] = "roundedBoxAnnotationSelector",
+--~ [ 3] = "circleAnnotationSelector",
+--~ [ 4] = "invertedCircleAnnotationSelector",
+--~ [ 5] = "parenthesisAnnotationSelector",
+--~ [ 6] = "periodAnnotationSelector",
+--~ [ 7] = "romanNumeralAnnotationSelector",
+--~ [ 8] = "diamondAnnotationSelector",
+--~ },
+--~ [25] = {
+--~ name = "kanaSpacingType",
+--~ [ 0] = "fullWidthKanaSelector",
+--~ [ 1] = "proportionalKanaSelector",
+--~ },
+--~ [26] = {
+--~ name = "ideographicSpacingType",
+--~ [ 0] = "fullWidthIdeographsSelector",
+--~ [ 1] = "proportionalIdeographsSelector",
+--~ },
+--~ [103] = {
+--~ name = "cjkRomanSpacingType",
+--~ [ 0] = "halfWidthCJKRomanSelector",
+--~ [ 1] = "proportionalCJKRomanSelector",
+--~ [ 2] = "defaultCJKRomanSelector",
+--~ [ 3] = "fullWidthCJKRomanSelector",
+--~ },
+--~ }
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otf'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local utf = unicode.utf8
+
+local concat, getn, utfbyte = table.concat, table.getn, utf.byte
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
+local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
+
+--~ trackers.enable("otf.loading")
+
+local zwnj = 0x200C
+local zwj = 0x200D
+
+--[[ldx--
+<p>The fontforge table has organized lookups in a certain way. A first implementation
+of this code was organized featurewise: information related to features was
+collected and processing boiled down to a run over the features. The current
+implementation honors the order in the main feature table. Since we can reorder this
+table as we want, we can eventually support several models of processing. We kept
+the static as well as dynamic feature processing, because it had proved to be
+rather useful. The formerly three loop variants have beem discarded but will
+reapear at some time.</p>
+
+<itemize>
+<item>we loop over all lookups</item>
+<item>for each lookup we do a run over the list of glyphs</item>
+<item>but we only process them for features that are enabled</item>
+<item>if we're dealing with a contextual lookup, we loop over all contexts</item>
+<item>in that loop we quit at a match and then process the list of sublookups</item>
+<item>we always continue after the match</item>
+</itemize>
+
+<p>In <l n='context'/> we do this for each font that is used in a list, so in
+practice we have quite some nested loops.</p>
+
+<p>We process the whole list and then consult the glyph nodes. An alternative approach
+is to collect strings of characters using the same font including spaces (because some
+lookups involve spaces). However, we then need to reconstruct the list which is no fun.
+Also, we need to carry quite some information, like attributes, so eventually we don't
+gain much (if we gain something at all).</p>
+
+<p>Another consideration has been to operate on sublists (subhead, subtail) but again
+this would complicate matters as we then neext to keep track of a changing subhead
+and subtail. On the other hand, this might save some runtime. The number of changes
+involved is not that large. This only makes sense when we have many fonts in a list
+and don't change to frequently.</p>
+--ldx]]--
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+fonts.tfm = fonts.tfm or { }
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local fontdata = fonts.ids
+
+otf.tables = otf.tables or { } -- defined in font-ott.lua
+otf.meanings = otf.meanings or { } -- defined in font-ott.lua
+otf.tables.features = otf.tables.features or { } -- defined in font-ott.lua
+otf.tables.languages = otf.tables.languages or { } -- defined in font-ott.lua
+otf.tables.scripts = otf.tables.scripts or { } -- defined in font-ott.lua
+
+otf.features = otf.features or { }
+otf.features.list = otf.features.list or { }
+otf.features.default = otf.features.default or { }
+
+otf.enhancers = otf.enhancers or { }
+otf.glists = { "gsub", "gpos" }
+
+otf.version = 2.626 -- beware: also sync font-mis.lua
+otf.pack = true -- beware: also sync font-mis.lua
+otf.syncspace = true
+otf.notdef = false
+otf.cache = containers.define("fonts", "otf", otf.version, true)
+otf.cleanup_aat = false -- only context
+
+--[[ldx--
+<p>We start with a lot of tables and related functions.</p>
+--ldx]]--
+
+otf.tables.global_fields = table.tohash {
+ "lookups",
+ "glyphs",
+ "subfonts",
+ "luatex",
+ "pfminfo",
+ "cidinfo",
+ "tables",
+ "names",
+ "unicodes",
+ "names",
+ "anchor_classes",
+ "kern_classes",
+ "gpos",
+ "gsub"
+}
+
+otf.tables.valid_fields = {
+ "anchor_classes",
+ "ascent",
+ "cache_version",
+ "cidinfo",
+ "copyright",
+ "creationtime",
+ "descent",
+ "design_range_bottom",
+ "design_range_top",
+ "design_size",
+ "encodingchanged",
+ "extrema_bound",
+ "familyname",
+ "fontname",
+ "fontstyle_id",
+ "fontstyle_name",
+ "fullname",
+ "glyphs",
+ "hasvmetrics",
+ "head_optimized_for_cleartype",
+ "horiz_base",
+ "issans",
+ "isserif",
+ "italicangle",
+ "kerns",
+ "lookups",
+ -- "luatex",
+ "macstyle",
+ "modificationtime",
+ "onlybitmaps",
+ "origname",
+ "os2_version",
+ "pfminfo",
+ "private",
+ "serifcheck",
+ "sfd_version",
+ -- "size",
+ "strokedfont",
+ "strokewidth",
+ "subfonts",
+ "table_version",
+ -- "tables",
+ -- "ttf_tab_saved",
+ "ttf_tables",
+ "uni_interp",
+ "uniqueid",
+ "units_per_em",
+ "upos",
+ "use_typo_metrics",
+ "uwidth",
+ "validation_state",
+ "verbose",
+ "version",
+ "vert_base",
+ "weight",
+ "weight_width_slope_only",
+ "xuid",
+}
+
+--[[ldx--
+<p>Here we go.</p>
+--ldx]]--
+
+local function load_featurefile(ff,featurefile)
+ if featurefile then
+ featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES"
+ if featurefile and featurefile ~= "" then
+ if trace_loading then
+ logs.report("load otf", "featurefile: %s", featurefile)
+ end
+ fontloader.apply_featurefile(ff, featurefile)
+ end
+ end
+end
+
+function otf.enhance(name,data,filename,verbose)
+ local enhancer = otf.enhancers[name]
+ if enhancer then
+ if (verbose ~= nil and verbose) or trace_loading then
+ logs.report("load otf","enhance: %s",name)
+ end
+ enhancer(data,filename)
+ end
+end
+
+local enhancers = {
+ -- pack and unpack are handled separately; they might even be moved
+ -- away from the enhancers namespace
+ "patch bugs",
+ "merge cid fonts", "prepare unicode", "cleanup ttf tables", "compact glyphs", "reverse coverage",
+ "cleanup aat", "enrich with features", "add some missing characters",
+ "reorganize kerns", -- moved here
+ "flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
+ "prepare luatex tables",
+ "analyse features", "rehash features",
+ "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",
+ "check italic correction","check math",
+ "share widths",
+ "strip not needed data",
+ "migrate metadata",
+}
+
+function otf.load(filename,format,sub,featurefile)
+ local name = file.basename(file.removesuffix(filename))
+ if featurefile then
+ name = name .. "@" .. file.removesuffix(file.basename(featurefile))
+ end
+ if sub == "" then sub = false end
+ local hash = name
+ if sub then
+ hash = hash .. "-" .. sub
+ end
+ hash = containers.cleanname(hash)
+ local data = containers.read(otf.cache(), hash)
+ local size = lfs.attributes(filename,"size") or 0
+ if not data or data.verbose ~= fonts.verbose or data.size ~= size then
+ logs.report("load otf","loading: %s",filename)
+ local ff, messages
+ if sub then
+ ff, messages = fontloader.open(filename,sub)
+ else
+ ff, messages = fontloader.open(filename)
+ end
+ if trace_loading and messages and #messages > 0 then
+ for m=1,#messages do
+ logs.report("load otf","warning: %s",messages[m])
+ end
+ end
+ if ff then
+ load_featurefile(ff,featurefile)
+ data = fontloader.to_table(ff)
+ fontloader.close(ff)
+ if data then
+ logs.report("load otf","file size: %s", size)
+ logs.report("load otf","enhancing ...")
+ for e=1,#enhancers do
+ otf.enhance(enhancers[e],data,filename)
+ end
+ if otf.pack and not fonts.verbose then
+ otf.enhance("pack",data,filename)
+ end
+ data.size = size
+ data.verbose = fonts.verbose
+ logs.report("load otf","saving in cache: %s",filename)
+ data = containers.write(otf.cache(), hash, data)
+ collectgarbage("collect")
+ data = containers.read(otf.cache(), hash) -- this frees the old table and load the sparse one
+ collectgarbage("collect")
+ else
+ logs.report("load otf","loading failed (table conversion error)")
+ end
+ else
+ logs.report("load otf","loading failed (file read error)")
+ end
+ end
+ if data then
+ otf.enhance("unpack",data,filename,false) -- no message here
+ otf.add_dimensions(data)
+ if trace_sequences then
+ otf.show_feature_order(data,filename)
+ end
+ end
+ return data
+end
+
+function otf.add_dimensions(data)
+ -- todo: forget about the width if it's the defaultwidth (saves mem)
+ -- we could also build the marks hash here (instead of storing it)
+ if data then
+ local force = otf.notdef
+ local luatex = data.luatex
+ local defaultwidth = luatex.defaultwidth or 0
+ local defaultheight = luatex.defaultheight or 0
+ local defaultdepth = luatex.defaultdepth or 0
+ for _, d in next, data.glyphs do
+ local bb, wd = d.boundingbox, d.width
+ if not wd then
+ d.width = defaultwidth
+ elseif wd ~= 0 and d.class == "mark" then
+ d.width = -wd
+ end
+ if force and not d.name then
+ d.name = ".notdef"
+ end
+ if bb then
+ local ht, dp = bb[4], -bb[2]
+ if ht == 0 or ht < 0 then
+ -- no need to set it and no negative heights, nil == 0
+ else
+ d.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- no negative depths and no negative depths, nil == 0
+ else
+ d.depth = dp
+ end
+ end
+ end
+ end
+end
+
+function otf.show_feature_order(otfdata,filename)
+ local sequences = otfdata.luatex.sequences
+ if sequences and #sequences > 0 then
+ if trace_loading then
+ logs.report("otf check","font %s has %s sequences",filename,#sequences)
+ logs.report("otf check"," ")
+ end
+ for nos=1,#sequences do
+ local sequence = sequences[nos]
+ local typ = sequence.type or "no-type"
+ local name = sequence.name or "no-name"
+ local subtables = sequence.subtables or { "no-subtables" }
+ local features = sequence.features
+ if trace_loading then
+ logs.report("otf check","%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,","))
+ end
+ if features then
+ for feature, scripts in next, features do
+ local tt = { }
+ for script, languages in next, scripts do
+ local ttt = { }
+ for language, _ in next, languages do
+ ttt[#ttt+1] = language
+ end
+ tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
+ end
+ if trace_loading then
+ logs.report("otf check"," %s: %s",feature,concat(tt," "))
+ end
+ end
+ end
+ end
+ if trace_loading then
+ logs.report("otf check","\n")
+ end
+ elseif trace_loading then
+ logs.report("otf check","font %s has no sequences",filename)
+ end
+end
+
+-- todo: normalize, design_size => designsize
+
+otf.enhancers["prepare luatex tables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ luatex.filename = filename
+ luatex.version = otf.version
+ luatex.creator = "context mkiv"
+end
+
+otf.enhancers["cleanup aat"] = function(data,filename)
+ if otf.cleanup_aat then
+ end
+end
+
+local function analyze_features(g, features)
+ if g then
+ local t, done = { }, { }
+ for k=1,#g do
+ local f = features or g[k].features
+ if f then
+ for k=1,#f do
+ -- scripts and tag
+ local tag = f[k].tag
+ if not done[tag] then
+ t[#t+1] = tag
+ done[tag] = true
+ end
+ end
+ end
+ end
+ if #t > 0 then
+ return t
+ end
+ end
+ return nil
+end
+
+otf.enhancers["analyse features"] = function(data,filename)
+ -- local luatex = data.luatex
+ -- luatex.gposfeatures = analyze_features(data.gpos)
+ -- luatex.gsubfeatures = analyze_features(data.gsub)
+end
+
+otf.enhancers["rehash features"] = function(data,filename)
+ local features = { }
+ data.luatex.features = features
+ for k, what in next, otf.glists do
+ local dw = data[what]
+ if dw then
+ local f = { }
+ features[what] = f
+ for i=1,#dw do
+ local d= dw[i]
+ local dfeatures = d.features
+ if dfeatures then
+ for i=1,#dfeatures do
+ local df = dfeatures[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dscripts = df.scripts
+ for script, languages in next, dscripts do
+ script = strip(lower(script))
+ local fts = ft[script] if not fts then fts = {} ft[script] = fts end
+ for i=1,#languages do
+ fts[strip(lower(languages[i]))] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["analyse anchors"] = function(data,filename)
+ local classes = data.anchor_classes
+ local luatex = data.luatex
+ local anchor_to_lookup, lookup_to_anchor = { }, { }
+ luatex.anchor_to_lookup, luatex.lookup_to_anchor = anchor_to_lookup, lookup_to_anchor
+ if classes then
+ for c=1,#classes do
+ local class = classes[c]
+ local anchor = class.name
+ local lookups = class.lookup
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ local a = anchor_to_lookup[anchor]
+ if not a then a = { } anchor_to_lookup[anchor] = a end
+ for l=1,#lookups do
+ local lookup = lookups[l]
+ local l = lookup_to_anchor[lookup]
+ if not l then l = { } lookup_to_anchor[lookup] = l end
+ l[anchor] = true
+ a[lookup] = true
+ end
+ end
+ end
+end
+
+otf.enhancers["analyse marks"] = function(data,filename)
+ local glyphs = data.glyphs
+ local marks = { }
+ data.luatex.marks = marks
+ for unicode, index in next, data.luatex.indices do
+ local glyph = glyphs[index]
+ if glyph.class == "mark" then
+ marks[unicode] = true
+ end
+ end
+end
+
+local other = lpeg.C((1 - lpeg.S("_."))^0)
+local ligsplitter = lpeg.Ct(other * (lpeg.P("_") * other)^0)
+
+--~ print(splitter:match("this"))
+--~ print(splitter:match("this.that"))
+--~ print(splitter:match("such_so_more"))
+--~ print(splitter:match("such_so_more.that"))
+
+otf.enhancers["analyse unicodes"] = function(data,filename)
+ local unicodes = data.luatex.unicodes
+ -- we need to move this code
+ unicodes['space'] = unicodes['space'] or 32 -- handly later on
+ unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on
+ unicodes['zwj'] = unicodes['zwj'] or zwj -- handly later on
+ unicodes['zwnj'] = unicodes['zwnj'] or zwnj -- handly later on
+ -- the tounicode mapping is sparse and only needed for alternatives
+ local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
+ data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ for index, glyph in next, data.glyphs do
+ local name, unic = glyph.name, glyph.unicode or -1 -- play safe
+ if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then
+ -- a.whatever or a_b_c.whatever or a_b_c
+ local split = ligsplitter:match(name)
+ if #split == 0 then
+ -- skip
+ elseif #split == 1 then
+ local u = unicodes[split[1]]
+ if u then
+ if type(u) == "table" then
+ u = u[1]
+ end
+ if u < 0x10000 then
+ originals[index], tounicode[index] = u, format("%04X",u)
+ else
+ originals[index], tounicode[index] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00)
+ end
+ ns = ns + 1
+ else
+ originals[index], tounicode[index] = 0xFFFD, "FFFD"
+ end
+ else
+ local as = { }
+ for l=1,#split do
+ local u = unicodes[split[l]]
+ if not u then
+ as[l], split[l] = 0xFFFD, "FFFD"
+ else
+ if type(u) == "table" then
+ u = u[1]
+ end
+ if u < 0x10000 then
+ as[l], split[l] = u, format("%04X",u)
+ else
+ as[l], split[l] = u, format("%04X%04X",u/1024+0xD800,u%1024+0xDC00)
+ end
+ end
+ end
+ split = concat(split)
+ if split ~= "" then
+ originals[index], tounicode[index] = as, split
+ nl = nl + 1
+ else
+ originals[index], tounicode[index] = 0xFFFD, "FFFD"
+ end
+ end
+ end
+ end
+ if trace_loading and (ns > 0 or nl > 0) then
+ logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ end
+end
+
+otf.enhancers["analyse subtables"] = function(data,filename)
+ data.luatex = data.luatex or { }
+ local luatex = data.luatex
+ local sequences = { }
+ local lookups = { }
+ luatex.sequences = sequences
+ luatex.lookups = lookups
+ for _, g in next, { data.gsub, data.gpos } do
+ for k=1,#g do
+ local gk = g[k]
+
+local typ = gk.type
+if typ == "gsub_contextchain" or typ == "gpos_contextchain" then
+ gk.chain = 1
+elseif typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain" then
+ gk.chain = -1
+else
+ gk.chain = 0
+end
+
+ local features = gk.features
+ if features then
+ sequences[#sequences+1] = gk
+ -- scripts, tag, ismac
+ local t = { }
+ for f=1,#features do
+ local feature = features[f]
+ local hash = { }
+ -- only script and langs matter
+ for s, languages in next, feature.scripts do
+ s = lower(s)
+ local h = hash[s]
+ if not h then h = { } hash[s] = h end
+ for l=1,#languages do
+ h[strip(lower(languages[l]))] = true
+ end
+ end
+ t[feature.tag] = hash
+ end
+ gk.features = t
+ else
+ lookups[gk.name] = gk
+ gk.name = nil
+ end
+ local subtables = gk.subtables
+ if subtables then
+ local t = { }
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local name = subtable.name
+ t[#t+1] = name
+ end
+ gk.subtables = t
+ 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
+ }
+ end
+ end
+ end
+end
+
+otf.enhancers["merge cid fonts"] = function(data,filename)
+ -- we can also move the names to data.luatex.names which might
+ -- save us some more memory (at the cost of harder tracing)
+ if data.subfonts and table.is_empty(data.glyphs) then
+ local cidinfo = data.cidinfo
+ local verbose = fonts.verbose
+ if cidinfo.registry then
+ local cidmap = fonts.cid.getmap and fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ if cidmap then
+ local glyphs, uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, { }, 0, 0
+ local unicodes, names = cidmap.unicodes, cidmap.names
+ for n, subfont in next, data.subfonts do
+ for index, g in next, subfont.glyphs do
+ if not next(g) then
+ -- dummy entry
+ else
+ local unicode, name = unicodes[index], names[index]
+ g.cidindex = n
+ g.boundingbox = g.boundingbox -- or zerobox
+ g.name = g.name or name or "unknown"
+ if unicode then
+ uni_to_int[unicode] = index
+ int_to_uni[index] = unicode
+ nofunicodes = nofunicodes + 1
+ g.unicode = unicode
+ elseif name then
+ nofnames = nofnames + 1
+ g.unicode = -1
+ end
+ glyphs[index] = g
+ end
+ end
+ subfont.glyphs = nil
+ end
+ if trace_loading then
+ logs.report("load otf","cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ end
+ data.glyphs = glyphs
+ data.map = data.map or { }
+ data.map.map = uni_to_int
+ data.map.backmap = int_to_uni
+ elseif trace_loading then
+ logs.report("load otf","unable to remap cid font, missing cid file for %s",filename)
+ end
+ elseif trace_loading then
+ logs.report("load otf","font %s has no glyphs",filename)
+ end
+ end
+end
+
+otf.enhancers["prepare unicode"] = function(data,filename)
+ local luatex = data.luatex
+ if not luatex then luatex = { } data.luatex = luatex end
+ local indices, unicodes, multiples, internals = { }, { }, { }, { }
+ local glyphs = data.glyphs
+ local mapmap = data.map
+ if not mapmap then
+ logs.report("load otf","no map in %s",filename)
+ mapmap = { }
+ data.map = { map = mapmap }
+ elseif not mapmap.map then
+ logs.report("load otf","no unicode map in %s",filename)
+ mapmap = { }
+ data.map.map = mapmap
+ else
+ mapmap = mapmap.map
+ end
+ local criterium = fonts.private
+ local private = fonts.private
+ for index, glyph in next, glyphs do
+ if index > 0 then
+ local name = glyph.name
+ if name then
+ local unicode = glyph.unicode
+ if unicode == -1 or unicode >= criterium then
+ glyph.unicode = private
+ indices[private] = index
+ unicodes[name] = private
+ internals[index] = true
+ if trace_private then
+ logs.report("load otf","enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private)
+ end
+ private = private + 1
+ else
+ indices[unicode] = index
+ unicodes[name] = unicode
+ end
+ end
+ end
+ end
+ -- beware: the indeces table is used to initialize the tfm table
+ for unicode, index in next, mapmap do
+ if not internals[index] then
+ local name = glyphs[index].name
+ if name then
+ local un = unicodes[name]
+ if not un then
+ unicodes[name] = unicode -- or 0
+ elseif type(un) == "number" then
+ if un ~= unicode then
+ multiples[#multiples+1] = name
+ unicodes[name] = { un, unicode }
+ indices[unicode] = index
+ end
+ else
+ local ok = false
+ for u=1,#un do
+ if un[u] == unicode then
+ ok = true
+ break
+ end
+ end
+ if not ok then
+ multiples[#multiples+1] = name
+ un[#un+1] = unicode
+ indices[unicode] = index
+ end
+ end
+ end
+ end
+ end
+ if trace_loading then
+ if #multiples > 0 then
+ logs.report("load otf","%s glyph are reused: %s",#multiples, concat(multiples," "))
+ else
+ logs.report("load otf","no glyph are reused")
+ end
+ end
+ luatex.indices = indices
+ luatex.unicodes = unicodes
+ luatex.private = private
+end
+
+otf.enhancers["cleanup ttf tables"] = function(data,filename)
+ local ttf_tables = data.ttf_tables
+ if ttf_tables then
+ for k=1,#ttf_tables do
+ if ttf_tables[k].data then ttf_tables[k].data = "deleted" end
+ end
+ end
+ data.ttf_tab_saved = nil
+end
+
+otf.enhancers["compact glyphs"] = function(data,filename)
+ table.compact(data.glyphs) -- needed?
+ if data.subfonts then
+ for _, subfont in next, data.subfonts do
+ table.compact(subfont.glyphs) -- needed?
+ end
+ end
+end
+
+otf.enhancers["reverse coverage"] = function(data,filename)
+ -- we prefer the before lookups in a normal order
+ if data.lookups then
+ for _, v in next, data.lookups do
+ if v.rules then
+ for _, vv in next, v.rules do
+ local c = vv.coverage
+ if c and c.before then
+ c.before = table.reverse(c.before)
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["check italic correction"] = function(data,filename)
+ local glyphs = data.glyphs
+ local ok = false
+ for index, glyph in next, glyphs do
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ glyph.italic = ic
+ end
+ glyph.italic_correction = nil
+ ok = true
+ end
+ end
+ -- we can use this to avoid calculations
+ otf.tables.valid_fields[#otf.tables.valid_fields+1] = "has_italic"
+ data.has_italic = true
+end
+
+otf.enhancers["check math"] = function(data,filename)
+ if data.math then
+ -- we move the math stuff into a math subtable because we then can
+ -- test faster in the tfm copy
+ local glyphs = data.glyphs
+ local unicodes = data.luatex.unicodes
+ for index, glyph in next, glyphs do
+ local mk = glyph.mathkern
+ local hv = glyph.horiz_variants
+ local vv = glyph.vert_variants
+ if mk or hv or vv then
+ local math = { }
+ glyph.math = math
+ if mk then
+ for k, v in next, mk do
+ if not next(v) then
+ mk[k] = nil
+ end
+ end
+ math.kerns = mk
+ glyph.mathkern = nil
+ end
+ if hv then
+ math.horiz_variants = hv.variants
+ local p = hv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.horiz_parts = p
+ end
+ end
+ local ic = hv.italic_correction
+ if ic and ic ~= 0 then
+ math.horiz_italic_correction = ic
+ end
+ glyph.horiz_variants = nil
+ end
+ if vv then
+ local uc = unicodes[index]
+ math.vert_variants = vv.variants
+ local p = vv.parts
+ if p then
+ if #p>0 then
+ for i=1,#p do
+ local pi = p[i]
+ pi.glyph = unicodes[pi.component] or 0
+ end
+ math.vert_parts = p
+ end
+ end
+ local ic = vv.italic_correction
+ if ic and ic ~= 0 then
+ math.vert_italic_correction = ic
+ end
+ glyph.vert_variants = nil
+ end
+ local ic = glyph.italic_correction
+ if ic then
+ if ic ~= 0 then
+ math.italic_correction = ic
+ end
+ glyph.italic_correction = nil
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["share widths"] = function(data,filename)
+ local glyphs = data.glyphs
+ local widths = { }
+ for index, glyph in next, glyphs do
+ local width = glyph.width
+ widths[width] = (widths[width] or 0) + 1
+ end
+ -- share width for cjk fonts
+ local wd, most = 0, 1
+ for k,v in next, widths do
+ if v > most then
+ wd, most = k, v
+ end
+ end
+ if most > 1000 then
+ if trace_loading then
+ logs.report("load otf", "most common width: %s (%s times), sharing (cjk font)",wd,most)
+ end
+ for k, v in next, glyphs do
+ if v.width == wd then
+ v.width = nil
+ end
+ end
+ data.luatex.defaultwidth = wd
+ end
+end
+
+-- kern: ttf has a table with kerns
+
+otf.enhancers["reorganize kerns"] = function(data,filename)
+ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+ local mkdone = false
+ for index, glyph in next, data.glyphs do
+ if glyph.kerns then
+ local mykerns = { }
+ for k,v in next, glyph.kerns do
+ local vc, vo, vl = v.char, v.off, v.lookup
+ if vc and vo and vl then -- brrr, wrong! we miss the non unicode ones
+ local uvc = unicodes[vc]
+ if not uvc then
+ if trace_loading then
+ logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index)
+ end
+ else
+ if type(vl) ~= "table" then
+ vl = { vl }
+ end
+ for l=1,#vl do
+ local vll = vl[l]
+ local mkl = mykerns[vll]
+ if not mkl then
+ mkl = { }
+ mykerns[vll] = mkl
+ end
+ if type(uvc) == "table" then
+ for u=1,#uvc do
+ mkl[uvc[u]] = vo
+ end
+ else
+ mkl[uvc] = vo
+ end
+ end
+ end
+ end
+ end
+ glyph.mykerns = mykerns
+ glyph.kerns = nil -- saves space and time
+ mkdone = true
+ end
+ end
+ if trace_loading and mkdone then
+ logs.report("load otf", "replacing 'kerns' tables by 'mykerns' tables")
+ end
+ if data.kerns then
+ if trace_loading then
+ logs.report("load otf", "removing global 'kern' table")
+ end
+ data.kerns = nil
+ end
+ local dgpos = data.gpos
+ if dgpos then
+ for gp=1,#dgpos do
+ local gpos = dgpos[gp]
+ local subtables = gpos.subtables
+ if subtables then
+ for s=1,#subtables do
+ local subtable = subtables[s]
+ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
+ if kernclass then
+ for k=1,#kernclass do
+ local kcl = kernclass[k]
+ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+ if type(lookups) ~= "table" then
+ lookups = { lookups }
+ end
+ for l=1,#lookups do
+ local lookup = lookups[l]
+ local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+ if trace_loading then
+ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
+ end
+ for fk, fv in next, firsts do
+ for first in gmatch(fv,"[^ ]+") do
+ local first_unicode = unicodes[first]
+ if type(first_unicode) == "number" then
+ first_unicode = { first_unicode }
+ end
+ for f=1,#first_unicode do
+ local glyph = glyphs[mapmap[first_unicode[f]]]
+ if glyph then
+ local mykerns = glyph.mykerns
+ if not mykerns then
+ mykerns = { } -- unicode indexed !
+ glyph.mykerns = mykerns
+ end
+ local lookupkerns = mykerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ mykerns[lookup] = lookupkerns
+ end
+ for sk, sv in next, seconds do
+ local offset = offsets[(fk-1) * maxseconds + sk]
+ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+ for second in gmatch(sv,"[^ ]+") do
+ local second_unicode = unicodes[second]
+ if type(second_unicode) == "number" then
+ lookupkerns[second_unicode] = offset
+ else
+ for s=1,#second_unicode do
+ lookupkerns[second_unicode[s]] = offset
+ end
+ end
+ end
+ end
+ elseif trace_loading then
+ logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
+ end
+ end
+ end
+ end
+ end
+ end
+ subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
+ subtable.kernclass = { }
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["strip not needed data"] = function(data,filename)
+ local verbose = fonts.verbose
+ local int_to_uni = data.luatex.unicodes
+ for k, v in next, data.glyphs do
+ local d = v.dependents
+ if d then v.dependents = nil end
+ local a = v.altuni
+ if a then v.altuni = nil end
+ if verbose then
+ local code = int_to_uni[k]
+ -- looks like this is done twice ... bug?
+ if code then
+ local vu = v.unicode
+ if not vu then
+ v.unicode = code
+ elseif type(vu) == "table" then
+ if vu[#vu] == code then
+ -- weird
+ else
+ vu[#vu+1] = code
+ end
+ elseif vu ~= code then
+ v.unicode = { vu, code }
+ end
+ end
+ else
+ v.unicode = nil
+ v.index = nil
+ end
+ end
+ data.luatex.comment = "Glyph tables have their original index. When present, mykern tables are indexed by unicode."
+ data.map = nil
+ data.names = nil -- funny names for editors
+ data.glyphcnt = nil
+ data.glyphmax = nil
+ if true then
+ data.gpos = nil
+ data.gsub = nil
+ data.anchor_classes = nil
+ end
+end
+
+otf.enhancers["migrate metadata"] = function(data,filename)
+ local global_fields = otf.tables.global_fields
+ local metadata = { }
+ for k,v in next, data do
+ if not global_fields[k] then
+ metadata[k] = v
+ data[k] = nil
+ end
+ end
+ data.metadata = metadata
+ -- goodies
+ local pfminfo = data.pfminfo
+ metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose["proportion"] == "Monospaced")
+ metadata.charwidth = pfminfo and pfminfo.avgwidth
+end
+
+otf.enhancers["flatten glyph lookups"] = function(data,filename)
+ for k, v in next, data.glyphs do
+ if v.lookups then
+ for kk, vv in next, v.lookups do
+ for kkk=1,#vv do
+ local vvv = vv[kkk]
+ local s = vvv.specification
+ if s then
+ local t = vvv.type
+ if t == "ligature" then
+ vv[kkk] = { "ligature", s.components, s.char }
+ elseif t == "alternate" then
+ vv[kkk] = { "alternate", s.components }
+ elseif t == "substitution" then
+ vv[kkk] = { "substitution", s.variant }
+ elseif t == "multiple" then
+ vv[kkk] = { "multiple", s.components }
+ elseif t == "position" then
+ vv[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
+ elseif t == "pair" then
+ local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
+ if one then
+ if two then
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0 } }
+ else
+ vv[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
+ end
+ else
+ if two then
+ vv[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
+ else
+ vv[kkk] = { "pair", paired }
+ end
+ end
+ else
+ if trace_loading then
+ logs.report("load otf", "flattening needed, report to context list")
+ end
+ for a, b in next, s do
+ if trace_loading and vvv[a] then
+ logs.report("load otf", "flattening conflict, report to context list")
+ end
+ vvv[a] = b
+ end
+ vvv.specification = nil
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["flatten anchor tables"] = function(data,filename)
+ for k, v in next, data.glyphs do
+ if v.anchors then
+ for kk, vv in next, v.anchors do
+ for kkk, vvv in next, vv do
+ if vvv.x or vvv.y then
+ vv[kkk] = { vvv.x or 0, vvv.y or 0 }
+ else
+ for kkkk=1,#vvv do
+ local vvvv = vvv[kkkk]
+ vvv[kkkk] = { vvvv.x or 0, vvvv.y or 0 }
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers["flatten feature tables"] = function(data,filename)
+ -- is this needed? do we still use them at all?
+ for _, tag in next, otf.glists do
+ if data[tag] then
+ if trace_loading then
+ logs.report("load otf", "flattening %s table", tag)
+ end
+ for k, v in next, data[tag] do
+ local features = v.features
+ if features then
+ for kk=1,#features do
+ local vv = features[kk]
+ local t = { }
+ local scripts = vv.scripts
+ for kkk=1,#scripts do
+ local vvv = scripts[kkk]
+ t[vvv.script] = vvv.langs
+ end
+ vv.scripts = t
+ end
+ end
+ end
+ end
+ end
+end
+
+otf.enhancers.patches = otf.enhancers.patches or { }
+
+otf.enhancers["patch bugs"] = function(data,filename)
+ local basename = file.basename(lower(filename))
+ for pattern, action in next, otf.enhancers.patches do
+ if find(basename,pattern) then
+ action(data,filename)
+ end
+ end
+end
+
+-- tex features
+
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- later, ctx only
+end
+
+function otf.features.register(name,default)
+ otf.features.list[#otf.features.list+1] = name
+ otf.features.default[name] = default
+end
+
+function otf.set_features(tfmdata,features)
+ local processes = { }
+ if not table.is_empty(features) then
+ local lists = {
+ fonts.triggers,
+ fonts.processors,
+ fonts.manipulators,
+ }
+ local mode = tfmdata.mode or fonts.mode -- or features.mode
+ local initializers = fonts.initializers
+ local fi = initializers[mode]
+ if fi then
+ local fiotf = fi.otf
+ if fiotf then
+ local done = { }
+ for l=1,4 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ local value = features[f]
+ if value and fiotf[f] then -- brr
+ if not done[f] then -- so, we can move some to triggers
+ if trace_features then
+ logs.report("define otf","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown', tfmdata.fullname or 'unknown')
+ end
+ fiotf[f](tfmdata,value) -- can set mode (no need to pass otf)
+ mode = tfmdata.mode or fonts.mode -- keep this, mode can be set local !
+ local im = initializers[mode]
+ if im then
+ fiotf = initializers[mode].otf
+ end
+ done[f] = true
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ local fm = fonts.methods[mode]
+ if fm then
+ local fmotf = fm.otf
+ if fmotf then
+ for l=1,4 do
+ local list = lists[l]
+ if list then
+ for i=1,#list do
+ local f = list[i]
+ if fmotf[f] then -- brr
+ if trace_features then
+ logs.report("define otf","installing feature handler %s for mode %s for font %s",f,mode or 'unknown', tfmdata.fullname or 'unknown')
+ end
+ processes[#processes+1] = fmotf[f]
+ end
+ end
+ end
+ end
+ end
+ else
+ -- message
+ end
+ end
+ return processes, features
+end
+
+function otf.otf_to_tfm(specification)
+ local name = specification.name
+ local sub = specification.sub
+ local filename = specification.filename
+ local format = specification.format
+ local features = specification.features.normal
+ local cache_id = specification.hash
+ local tfmdata = containers.read(tfm.cache(),cache_id)
+--~ print(cache_id)
+ if not tfmdata then
+ local otfdata = otf.load(filename,format,sub,features and features.featurefile)
+ if not table.is_empty(otfdata) then
+ otfdata.shared = otfdata.shared or {
+ featuredata = { },
+ anchorhash = { },
+ initialized = false,
+ }
+ tfmdata = otf.copy_to_tfm(otfdata,cache_id)
+ if not table.is_empty(tfmdata) then
+ tfmdata.unique = tfmdata.unique or { }
+ tfmdata.shared = tfmdata.shared or { } -- combine
+ local shared = tfmdata.shared
+ shared.otfdata = otfdata
+ shared.features = features -- default
+ shared.dynamics = { }
+ shared.processes = { }
+ shared.set_dynamics = otf.set_dynamics -- fast access and makes other modules independent
+ -- this will be done later anyway, but it's convenient to have
+ -- them already for fast access
+ tfmdata.luatex = otfdata.luatex
+ tfmdata.indices = otfdata.luatex.indices
+ tfmdata.unicodes = otfdata.luatex.unicodes
+ tfmdata.marks = otfdata.luatex.marks
+ tfmdata.originals = otfdata.luatex.originals
+ tfmdata.changed = { }
+ tfmdata.has_italic = otfdata.metadata.has_italic
+ if not tfmdata.language then tfmdata.language = 'dflt' end
+ if not tfmdata.script then tfmdata.script = 'dflt' end
+ shared.processes, shared.features = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+ end
+ end
+ containers.write(tfm.cache(),cache_id,tfmdata)
+ end
+ return tfmdata
+end
+
+--~ {
+--~ ['boundingbox']={ 95, -458, 733, 1449 },
+--~ ['class']="base",
+--~ ['name']="braceleft",
+--~ ['unicode']=123,
+--~ ['vert_variants']={
+--~ ['italic_correction']=0,
+--~ ['parts']={
+--~ { ['component']="uni23A9", ['endConnectorLength']=1000, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=0, }, -- bot
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A8", ['endConnectorLength']=1000, ['fullAdvance']=4688, ['is_extender']=0, ['startConnectorLength']=1000, }, -- mid
+--~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
+--~ { ['component']="uni23A7", ['endConnectorLength']=0, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=1000, }, -- top
+--~ },
+--~ ['variants']="braceleft braceleft.vsize1 braceleft.vsize2 braceleft.vsize3 braceleft.vsize4 braceleft.vsize5 braceleft.vsize6 braceleft.vsize7",
+--~ },
+--~ ['width']=793,
+--~ },
+
+-- the first version made a top/mid/not extensible table, now we just pass on the variants data
+-- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
+
+-- we cannot share descriptions as virtual fonts might extend them (ok, we could
+-- use a cache with a hash
+
+function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
+ if data then
+ local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
+ local luatex = data.luatex
+ local unicodes = luatex.unicodes -- names to unicodes
+ local indices = luatex.indices
+ local characters, parameters, math_parameters, descriptions = { }, { }, { }, { }
+ local tfm = {
+ characters = characters,
+ parameters = parameters,
+ math_parameters = math_parameters,
+ descriptions = descriptions,
+ indices = indices,
+ unicodes = unicodes,
+ }
+ -- indices maps from unicodes to indices
+ for u, i in next, indices do
+ characters[u] = { } -- we need this because for instance we add protruding info
+ descriptions[u] = glyphs[i]
+ end
+ -- math
+ if metadata.math then
+ -- parameters
+ for name, value in next, metadata.math do
+ math_parameters[name] = value
+ end
+ -- we could use a subset
+ for u, char in next, characters do
+ local d = descriptions[u]
+ local m = d.math
+ -- we have them shared because that packs nicer
+ -- we could prepare the variants and keep 'm in descriptions
+ if m then
+ local variants = m.horiz_variants
+ if variants then
+ local c = char
+ for n in variants:gmatch("[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
+ end
+ end
+ c.horiz_variants = m.horiz_parts
+ else
+ local variants = m.vert_variants
+ if variants then
+ local c = char
+ for n in variants:gmatch("[^ ]+") do
+ local un = unicodes[n]
+ if un and u ~= un then
+ c.next = un
+ c = characters[un]
+ end
+ end
+ c.vert_variants = m.vert_parts
+ end
+ end
+ local kerns = m.kerns
+ if kerns then
+ char.mathkerns = kerns
+ end
+ end
+ end
+ end
+ -- end math
+ local designsize = metadata.designsize or metadata.design_size or 100
+ if designsize == 0 then
+ designsize = 100
+ end
+ local spaceunits = 500
+ tfm.units = metadata.units_per_em or 1000
+ -- we need a runtime lookup because of running from cdrom or zip, brrr
+ tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename
+ tfm.fullname = metadata.fontname or metadata.fullname
+ tfm.encodingbytes = 2
+ tfm.cidinfo = data.cidinfo
+ tfm.cidinfo.registry = tfm.cidinfo.registry or ""
+ tfm.type = "real"
+ tfm.stretch = 0 -- stretch
+ tfm.slant = 0 -- slant
+ tfm.direction = 0
+ tfm.boundarychar_label = 0
+ tfm.boundarychar = 65536
+ tfm.designsize = (designsize/10)*65536
+ tfm.spacer = "500 units"
+ local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
+ if metadata.isfixedpitch then
+ if descriptions[endash] then
+ spaceunits, tfm.spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+ end
+ else
+ if descriptions[endash] then
+ spaceunits, tfm.spacer = descriptions[endash].width, "space"
+ end
+ if not spaceunits and descriptions[emdash] then
+ spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
+ end
+ if not spaceunits and metadata.charwidth then
+ spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
+ end
+ end
+ spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr
+ parameters.slant = 0
+ parameters.space = spaceunits -- 3.333 (cmr10)
+ parameters.space_stretch = tfm.units/2 -- 500 -- 1.666 (cmr10)
+ parameters.space_shrink = 1*tfm.units/3 -- 333 -- 1.111 (cmr10)
+ parameters.x_height = 2*tfm.units/5 -- 400
+ parameters.quad = tfm.units -- 1000
+ if spaceunits < 2*tfm.units/5 then
+ -- todo: warning
+ end
+ local italicangle = metadata.italicangle
+ tfm.ascender = math.abs(metadata.ascent or 0)
+ tfm.descender = math.abs(metadata.descent or 0)
+ if italicangle then -- maybe also in afm _
+ tfm.italicangle = italicangle
+ parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
+ end
+ if metadata.isfixedpitch then
+ parameters.space_stretch = 0
+ parameters.space_shrink = 0
+ elseif otf.syncspace then --
+ parameters.space_stretch = spaceunits/2
+ parameters.space_shrink = spaceunits/3
+ end
+ parameters.extra_space = parameters.space_shrink -- 1.111 (cmr10)
+ if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
+ parameters.x_height = pfminfo.os2_xheight
+ else
+ local x = 0x78 -- unicodes['x']
+ if x then
+ local x = descriptions[x]
+ if x then
+ parameters.x_height = x.height
+ end
+ end
+ end
+ -- [6]
+ return tfm
+ else
+ return nil
+ end
+end
+
+otf.features.register('mathsize')
+
+function tfm.read_from_open_type(specification)
+ local tfmtable = otf.otf_to_tfm(specification)
+ if tfmtable then
+ local otfdata = tfmtable.shared.otfdata
+ tfmtable.name = specification.name
+ tfmtable.sub = specification.sub
+ local s = specification.size
+ local m = otfdata.metadata.math
+ if m then
+ local f = specification.features
+ if f then
+ local f = f.normal
+ if f and f.mathsize then
+ local mathsize = specification.mathsize or 0
+ if mathsize == 2 then
+ local p = m.ScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ elseif mathsize == 3 then
+ local p = m.ScriptScriptPercentScaleDown
+ if p then
+ local ps = p * specification.textsize / 100
+ if trace_math then
+ logs.report("define font","asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100)
+ end
+ s = ps
+ end
+ end
+ end
+ end
+ end
+ tfmtable = tfm.scale(tfmtable,s)
+ -- here we resolve the name; file can be relocated, so this info is not in the cache
+ local filename = (otfdata and otfdata.luatex and otfdata.luatex.filename) or specification.filename
+ if not filename then
+ -- try to locate anyway and set otfdata.luatex.filename
+ end
+ if filename then
+ tfmtable.encodingbytes = 2
+ tfmtable.filename = resolvers.findbinfile(filename,"") or filename
+ tfmtable.fullname = otfdata.metadata.fontname or otfdata.metadata.fullname
+ local order = otfdata and otfdata.metadata.order2
+ if order == 0 then
+ tfmtable.format = 'opentype'
+ elseif order == 1 then
+ tfmtable.format = 'truetype'
+ else
+ tfmtable.format = specification.format
+ end
+ tfmtable.name = tfmtable.filename or tfmtable.fullname
+ end
+ fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
+ end
+ return tfmtable
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otd'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
+
+fonts = fonts or { }
+fonts.otf = fonts.otf or { }
+
+local otf = fonts.otf
+local fontdata = fonts.ids
+
+otf.features = otf.features or { }
+otf.features.default = otf.features.default or { }
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+
+local a_to_script = { } otf.a_to_script = a_to_script
+local a_to_language = { } otf.a_to_language = a_to_language
+
+function otf.set_dynamics(font,dynamics,attribute)
+ features = context_setups[context_numbers[attribute]] -- can be moved to caller
+ if features then
+ local script = features.script or 'dflt'
+ local language = features.language or 'dflt'
+ local ds = dynamics[script]
+ if not ds then
+ ds = { }
+ dynamics[script] = ds
+ end
+ local dsl = ds[language]
+ if not dsl then
+ dsl = { }
+ ds[language] = dsl
+ end
+ local dsla = dsl[attribute]
+ if dsla then
+ -- if trace_dynamics then
+ -- logs.report("otf define","using dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ -- end
+ return dsla
+ else
+ local tfmdata = fontdata[font]
+ a_to_script [attribute] = script
+ a_to_language[attribute] = language
+ -- we need to save some values
+ local saved = {
+ script = tfmdata.script,
+ language = tfmdata.language,
+ mode = tfmdata.mode,
+ features = tfmdata.shared.features
+ }
+ tfmdata.mode = "node"
+ tfmdata.language = language
+ tfmdata.script = script
+ tfmdata.shared.features = { }
+ -- end of save
+ dsla = otf.set_features(tfmdata,fonts.define.check(features,otf.features.default))
+ if trace_dynamics then
+ logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s",context_numbers[attribute],attribute,script,language)
+ end
+ -- we need to restore some values
+ tfmdata.script = saved.script
+ tfmdata.language = saved.language
+ tfmdata.mode = saved.mode
+ tfmdata.shared.features = saved.features
+ -- end of restore
+ dynamics[script][language][attribute] = dsla -- cache
+ return dsla
+ end
+ end
+ return nil -- { }
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-oti'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- i need to check features=yes|no also in relation to hashing
+
+local lower = string.lower
+
+local otf = fonts.otf
+
+otf.default_language = 'latn'
+otf.default_script = 'dflt'
+
+local languages = otf.tables.languages
+local scripts = otf.tables.scripts
+
+function otf.features.language(tfmdata,value)
+ if value then
+ value = lower(value)
+ if languages[value] then
+ tfmdata.language = value
+ end
+ end
+end
+
+function otf.features.script(tfmdata,value)
+ if value then
+ value = lower(value)
+ if scripts[value] then
+ tfmdata.script = value
+ end
+ end
+end
+
+function otf.features.mode(tfmdata,value)
+ if value then
+ tfmdata.mode = lower(value)
+ end
+end
+
+fonts.initializers.base.otf.language = otf.features.language
+fonts.initializers.base.otf.script = otf.features.script
+fonts.initializers.base.otf.mode = otf.features.mode
+fonts.initializers.base.otf.method = otf.features.mode
+
+fonts.initializers.node.otf.language = otf.features.language
+fonts.initializers.node.otf.script = otf.features.script
+fonts.initializers.node.otf.mode = otf.features.mode
+fonts.initializers.node.otf.method = otf.features.mode
+
+otf.features.register("features",true) -- we always do features
+table.insert(fonts.processors,"features") -- we need a proper function for doing this
+
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otb'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_baseinit = false trackers.register("otf.baseinit", function(v) trace_baseinit = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local pcache, fcache = { }, { } -- could be weak
+
+local function gref(descriptions,n)
+ if type(n) == "number" then
+ local name = descriptions[n].name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X")
+ end
+ elseif n then
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[i] = format("U+%04X",ni)
+ nam[i] = descriptions[ni].name or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ else
+ return "?"
+ end
+end
+
+local function cref(kind,lookupname)
+ if lookupname then
+ return format("feature %s, lookup %s",kind,lookupname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function resolve_ligatures(tfmdata,ligatures,kind)
+ kind = kind or "unknown"
+ local unicodes = tfmdata.unicodes
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ local done = { }
+ while true do
+ local ok = false
+ for k,v in next, ligatures do
+ local lig = v[1]
+ if not done[lig] then
+ local ligs = split_at_space:match(lig)
+ if #ligs == 2 then
+ local uc = v[2]
+ local c, f, s = characters[uc], ligs[1], ligs[2]
+ local uft, ust = unicodes[f] or 0, unicodes[s] or 0
+ if not uft or not ust then
+ logs.report("define otf","%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust))
+ -- some kind of error
+ else
+ if type(uft) == "number" then uft = { uft } end
+ if type(ust) == "number" then ust = { ust } end
+ for ufi=1,#uft do
+ local uf = uft[ufi]
+ for usi=1,#ust do
+ local us = ust[usi]
+ if changed[uf] or changed[us] then
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us))
+ end
+ else
+ local first, second = characters[uf], us
+ if first and second then
+ local t = first.ligatures
+ if not t then
+ t = { }
+ first.ligatures = t
+ end
+ if type(uc) == "number" then
+ t[second] = { type = 0, char = uc }
+ else
+ t[second] = { type = 0, char = uc[1] } -- can this still happen?
+ end
+ if trace_baseinit and trace_ligatures then
+ logs.report("define otf","%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc))
+ end
+ end
+ end
+ end
+ end
+ end
+ ok, done[lig] = true, descriptions[uc].name
+ end
+ end
+ end
+ if ok then
+ -- done has "a b c" = "a_b_c" and ligatures the already set ligatures: "a b" = 123
+ -- and here we add extras (f i i = fi + i and alike)
+ --
+ -- we could use a hash for fnc and pattern
+ --
+ -- this might be interfering !
+ for d,n in next, done do
+ local pattern = pcache[d] if not pattern then pattern = "^(" .. d .. ") " pcache[d] = pattern end
+ local fnc = fcache[n] if not fnc then fnc = function() return n .. " " end fcache[n] = fnc end
+ for k,v in next, ligatures do
+ v[1] = gsub(v[1],pattern,fnc)
+ end
+ end
+ else
+ break
+ end
+ end
+end
+
+local function collect_lookups(otfdata,kind,script,language)
+ -- maybe store this in the font
+ local sequences = otfdata.luatex.sequences
+ if sequences then
+ local featuremap, featurelist = { }, { }
+ for s=1,#sequences do
+ local sequence = sequences[s]
+ local features = sequence.features
+ features = features and features[kind]
+ features = features and (features[script] or features[default] or features[wildcard])
+ features = features and (features[language] or features[default] or features[wildcard])
+ if features then
+ local subtables = sequence.subtables
+ if subtables then
+ for s=1,#subtables do
+ local ss = subtables[s]
+ if not featuremap[s] then
+ featuremap[ss] = true
+ featurelist[#featurelist+1] = ss
+ end
+ end
+ end
+ end
+ end
+ if #featurelist > 0 then
+ return featuremap, featurelist
+ end
+ end
+ return nil, nil
+end
+
+local splitter = lpeg.splitat(" ")
+
+function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local ligatures = { }
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ local changed = tfmdata.changed
+ for k,c in next, characters do
+ local glyph = descriptions[k]
+ local lookups = glyph.lookups
+ if lookups then
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local ps = lookups[lookup]
+ if ps then
+ for i=1,#ps do
+ local p = ps[i]
+ local t = p[1]
+ if t == 'substitution' then
+ local pv = p[2] -- p.variant
+ if pv then
+ local upv = unicodes[pv]
+ if upv then
+ if type(upv) == "table" then
+ upv = upv[1]
+ end
+ if characters[upv] then
+ if trace_baseinit and trace_singles then
+ logs.report("define otf","%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv))
+ end
+ changed[k] = upv
+ end
+ end
+ end
+ elseif t == 'alternate' then
+ local pc = p[2] -- p.components
+ if pc then
+ -- a bit optimized ugliness
+ if value == 1 then
+ pc = splitter:match(pc)
+ elseif value == 2 then
+ local a, b = splitter:match(pc)
+ pc = b or a
+ else
+ pc = { splitter:match(pc) }
+ pc = pc[value] or pc[#pc]
+ end
+ if pc then
+ local upc = unicodes[pc]
+ if upc then
+ if type(upc) == "table" then
+ upc = upc[1]
+ end
+ if characters[upc] then
+ if trace_baseinit and trace_alternatives then
+ logs.report("define otf","%s: base alternate %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upc))
+ end
+ changed[k] = upc
+ end
+ end
+ end
+ end
+ elseif t == 'ligature' and not changed[k] then
+ local pc = p[2]
+ if pc then
+ if trace_baseinit and trace_ligatures then
+ local upc = { splitter:match(pc) }
+ for i=1,#upc do upc[i] = unicodes[upc[i]] end
+ -- we assume that it's no table
+ logs.report("define otf","%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k))
+ end
+ ligatures[#ligatures+1] = { pc, k }
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ resolve_ligatures(tfmdata,ligatures,kind)
+ end
+ else
+ tfmdata.ligatures = tfmdata.ligatures or { } -- left over from what ?
+ end
+end
+
+local function prepare_base_kerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
+ if value then
+ local otfdata = tfmdata.shared.otfdata
+ local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ if validlookups then
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local characters = tfmdata.characters
+ local descriptions = tfmdata.descriptions
+ for u, chr in next, characters do
+ local d = descriptions[u]
+ if d then
+ local dk = d.mykerns
+ if dk then
+ local t, done = chr.kerns or { }, false
+ for l=1,#lookuplist do
+ local lookup = lookuplist[l]
+ local kerns = dk[lookup]
+ if kerns then
+ for k, v in next, kerns do
+ if v ~= 0 and not t[k] then -- maybe no 0 test here
+ t[k], done = v, true
+ if trace_baseinit and trace_kerns then
+ logs.report("define otf","%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v)
+ end
+ end
+ end
+ end
+ end
+ if done then
+ chr.kerns = t -- no empty assignments
+ end
+ -- elseif d.kerns then
+ -- logs.report("define otf","%s: invalid mykerns for %s",cref(kind),gref(descriptions,u))
+ end
+ end
+ end
+ end
+ end
+end
+
+-- In principle we could register each feature individually which was
+-- what we did in earlier versions. However, after the rewrite it
+-- made more sense to collect them in an overall features initializer
+-- just as with the node variant. There it was needed because we need
+-- to do complete mixed runs and not run featurewise (as we did before).
+
+local supported_gsub = {
+ 'liga','dlig','rlig','hlig',
+ 'pnum','onum','tnum','lnum',
+ 'zero',
+ 'smcp','cpsp','c2sc','ornm','aalt',
+ 'hwid','fwid',
+ 'ssty', -- math
+}
+
+local supported_gpos = {
+ 'kern'
+}
+
+function otf.features.register_base_substitution(tag)
+ supported_gsub[#supported_gsub+1] = tag
+end
+function otf.features.register_base_kern(tag)
+ supported_gsub[#supported_gpos+1] = tag
+end
+
+local basehash, basehashes = { }, 1
+
+function fonts.initializers.base.otf.features(tfmdata,value)
+ if true then -- value then
+ -- not shared
+ local t = trace_preparing and os.clock()
+ local features = tfmdata.shared.features
+ if features then
+ local h = { }
+ for f=1,#supported_gsub do
+ local feature = supported_gsub[f]
+ prepare_base_substitutions(tfmdata,feature,features[feature])
+ h[#h+1] = feature
+ end
+ for f=1,#supported_gpos do
+ local feature = supported_gpos[f]
+ prepare_base_kerns(tfmdata,feature,features[feature])
+ h[#h+1] = feature
+ end
+ local hash = concat(h," ")
+ local base = basehash[hash]
+ if not base then
+ basehashes = basehashes + 1
+ base = basehashes
+ basehash[hash] = base
+ end
+ -- We need to make sure that luatex sees the difference between
+ -- base fonts that have different glyphs in the same slots in fonts
+ -- that have the same fullname (or filename). LuaTeX will merge fonts
+ -- eventually (and subset later on). If needed we can use a more
+ -- verbose name as long as we don't use <()<>[]{}/%> and the length
+ -- is < 128.
+ tfmdata.fullname = tfmdata.fullname .. base
+ end
+ if trace_preparing then
+ logs.report("otf define","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otn'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this is still somewhat preliminary and it will get better in due time;
+-- much functionality could only be implemented thanks to the husayni font
+-- of Idris Samawi Hamid to who we dedicate this module.
+
+-- we can use more lpegs when lpeg is extended with function args and so
+-- resolving to unicode does not gain much
+
+-- in retrospect it always looks easy but believe it or not, it took a lot
+-- of work to get proper open type support done: buggy fonts, fuzzy specs,
+-- special made testfonts, many skype sessions between taco, idris and me,
+-- torture tests etc etc ... unfortunately the code does not show how much
+-- time it took ...
+
+-- todo:
+--
+-- kerning is probably not yet ok for latin around dics nodes
+-- extension infrastructure (for usage out of context)
+-- sorting features according to vendors/renderers
+-- alternative loop quitters
+-- check cursive and r2l
+-- find out where ignore-mark-classes went
+-- remove unused tables
+-- slide tail (always glue at the end so only needed once
+-- default features (per language, script)
+-- cleanup kern(class) code, remove double info
+-- handle positions (we need example fonts)
+-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere)
+
+--[[ldx--
+<p>This module is a bit more split up that I'd like but since we also want to test
+with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/>
+and discussion about improvements and functionality mostly happens on the
+<l n='context'/> mailing list.</p>
+
+<p>The specification of OpenType is kind of vague. Apart from a lack of a proper
+free specifications there's also the problem that Microsoft and Adobe
+may have their own interpretation of how and in what order to apply features.
+In general the Microsoft website has more detailed specifications and is a
+better reference. There is also some information in the FontForge help files.</p>
+
+<p>Because there is so much possible, fonts might contain bugs and/or be made to
+work with certain rederers. These may evolve over time which may have the side
+effect that suddenly fonts behave differently.</p>
+
+<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another
+implementation. Of course all errors are mine and of course the code can be
+improved. There are quite some optimizations going on here and processing speed
+is currently acceptable. Not all functions are implemented yet, often because I
+lack the fonts for testing. Many scripts are not yet supported either, but I will
+look into them as soon as <l n='context'/> users ask for it.</p>
+
+<p>Because there are different interpretations possible, I will extend the code
+with more (configureable) variants. I can also add hooks for users so that they can
+write their own extensions.</p>
+
+<p>Glyphs are indexed not by unicode but in their own way. This is because there is no
+relationship with unicode at all, apart from the fact that a font might cover certain
+ranges of characters. One character can have multiple shapes. However, at the
+<l n='tex'/> end we use unicode so and all extra glyphs are mapped into a private
+space. This is needed because we need to access them and <l n='tex'/> has to include
+then in the output eventually.</p>
+
+<p>The raw table as it coms from <l n='fontforge'/> gets reorganized in to fit out needs.
+In <l n='context'/> that table is packed (similar tables are shared) and cached on disk
+so that successive runs can use the optimized table (after loading the table is
+unpacked). The flattening code used later is a prelude to an even more compact table
+format (and as such it keeps evolving).</p>
+
+<p>This module is sparsely documented because it is a moving target. The table format
+of the reader changes and we experiment a lot with different methods for supporting
+features.</p>
+
+<p>As with the <l n='afm'/> code, we may decide to store more information in the
+<l n='otf'/> table.</p>
+
+<p>Incrementing the version number will force a re-cache. We jump the number by one
+when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that
+results in different tables.</p>
+--ldx]]--
+
+-- action handler chainproc chainmore comment
+--
+-- gsub_single ok ok ok
+-- gsub_multiple ok ok not implemented yet
+-- gsub_alternate ok ok not implemented yet
+-- gsub_ligature ok ok ok
+-- gsub_context ok --
+-- gsub_contextchain ok --
+-- gsub_reversecontextchain ok --
+-- chainsub -- ok
+-- reversesub -- ok
+-- gpos_mark2base ok ok
+-- gpos_mark2ligature ok ok
+-- gpos_mark2mark ok ok
+-- gpos_cursive ok untested
+-- gpos_single ok ok
+-- gpos_pair ok ok
+-- gpos_context ok --
+-- gpos_contextchain ok --
+--
+-- actions:
+--
+-- handler : actions triggered by lookup
+-- chainproc : actions triggered by contextual lookup
+-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij)
+--
+-- remark: the 'not implemented yet' variants will be done when we have fonts that use them
+-- remark: we need to check what to do with discretionaries
+
+local concat = table.concat
+local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
+local type, next, tonumber, tostring = type, next, tonumber, tostring
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local trace_lookups = false trackers.register("otf.lookups", function(v) trace_lookups = v end)
+local trace_singles = false trackers.register("otf.singles", function(v) trace_singles = v end)
+local trace_multiples = false trackers.register("otf.multiples", function(v) trace_multiples = v end)
+local trace_alternatives = false trackers.register("otf.alternatives", function(v) trace_alternatives = v end)
+local trace_ligatures = false trackers.register("otf.ligatures", function(v) trace_ligatures = v end)
+local trace_contexts = false trackers.register("otf.contexts", function(v) trace_contexts = v end)
+local trace_marks = false trackers.register("otf.marks", function(v) trace_marks = v end)
+local trace_kerns = false trackers.register("otf.kerns", function(v) trace_kerns = v end)
+local trace_cursive = false trackers.register("otf.cursive", function(v) trace_cursive = v end)
+local trace_preparing = false trackers.register("otf.preparing", function(v) trace_preparing = v end)
+local trace_bugs = false trackers.register("otf.bugs", function(v) trace_bugs = v end)
+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)
+
+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)
+
+trackers.register("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures")
+trackers.register("otf.positions","otf.marks,otf.kerns,otf.cursive")
+trackers.register("otf.actions","otf.replacements,otf.positions")
+trackers.register("otf.injections","nodes.injections")
+
+trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing")
+
+local insert_node_after = node.insert_after
+local delete_node = nodes.delete
+local copy_node = node.copy
+local slide_node_list = node.slide
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+
+local zwnj = 0x200C
+local zwj = 0x200D
+local wildcard = "*"
+local default = "dflt"
+
+local split_at_space = lpeg.Ct(lpeg.splitat(" ")) -- no trailing or multiple spaces anyway
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local kern = node.id('kern')
+local disc = node.id('disc')
+local whatsit = node.id('whatsit')
+
+local state = attributes.private('state')
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local set_mark = nodes.set_mark
+local set_cursive = nodes.set_cursive
+local set_kern = nodes.set_kern
+local set_pair = nodes.set_pair
+
+local markonce = true
+local cursonce = true
+local kernonce = true
+
+local fontdata = fonts.ids
+
+otf.features.process = { }
+
+-- we share some vars here, after all, we have no nested lookups and
+-- less code
+
+local tfmdata = false
+local otfdata = false
+local characters = false
+local descriptions = false
+local marks = false
+local indices = false
+local unicodes = false
+local currentfont = false
+local lookuptable = false
+local anchorlookups = false
+local handlers = { }
+local rlmode = 0
+local featurevalue = false
+
+-- we cheat a bit and assume that a font,attr combination are kind of ranged
+
+local context_setups = fonts.define.specify.context_setups
+local context_numbers = fonts.define.specify.context_numbers
+local context_merged = fonts.define.specify.context_merged
+
+-- we cannot optimize with "start = first_character(head)" because then we don't
+-- know which rlmode we're in which messes up cursive handling later on
+--
+-- head is always a whatsit so we can safely assume that head is not changed
+
+local special_attributes = {
+ init = 1,
+ medi = 2,
+ fina = 3,
+ isol = 4
+}
+
+-- we use this for special testing and documentation
+
+local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
+local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
+local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf direct",...)
+end
+local function logwarning(...)
+ logs.report("otf direct",...)
+end
+
+local function gref(n)
+ if type(n) == "number" then
+ local description = descriptions[n]
+ local name = description and description.name
+ if name then
+ return format("U+%04X (%s)",n,name)
+ else
+ return format("U+%04X",n)
+ end
+ elseif not n then
+ return "<error in tracing>"
+ else
+ local num, nam = { }, { }
+ for i=1,#n do
+ local ni = n[i]
+ num[#num+1] = format("U+%04X",ni)
+ local dni = descriptions[ni]
+ nam[#num] = (dni and dni.name) or "?"
+ end
+ return format("%s (%s)",concat(num," "), concat(nam," "))
+ end
+end
+
+local function cref(kind,chainname,chainlookupname,lookupname,index)
+ if index then
+ return format("feature %s, chain %s, sub %s, lookup %s, index %s",kind,chainname,chainlookupname,lookupname,index)
+ elseif lookupname then
+ return format("feature %s, chain %s, sub %s, lookup %s",kind,chainname or "?",chainlookupname or "?",lookupname)
+ elseif chainlookupname then
+ return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname)
+ elseif chainname then
+ return format("feature %s, chain %s",kind,chainname)
+ else
+ return format("feature %s",kind)
+ end
+end
+
+local function pref(kind,lookupname)
+ return format("feature %s, lookup %s",kind,lookupname)
+end
+
+-- we can assume that languages that use marks are not hyphenated
+-- we can also assume that at most one discretionary is present
+
+local function markstoligature(kind,lookupname,start,stop,char)
+ local n = copy_node(start)
+ local keep = start
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ return keep
+end
+
+local function toligature(kind,lookupname,start,stop,char,markflag,discfound) -- brr head
+ if start ~= stop then
+ if discfound then
+ local lignode = copy_node(start)
+ lignode.font = start.font
+ lignode.char = char
+ lignode.subtype = 2
+ start = node.do_ligature_n(start, stop, lignode)
+ if start.id == disc then
+ local prev = start.prev
+ start = start.next
+ end
+ else -- start is the ligature
+ local deletemarks = markflag ~= "mark"
+ local n = copy_node(start)
+ local current
+ current, start = insert_node_after(start,start,n)
+ local snext = stop.next
+ current.next = snext
+ if snext then
+ snext.prev = current
+ end
+ start.prev, stop.next = nil, nil
+ current.char, current.subtype, current.components = char, 2, start
+ local head = current
+ if deletemarks then
+ if trace_marks then
+ while start do
+ if marks[start.char] then
+ logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char))
+ end
+ start = start.next
+ end
+ end
+ else
+ local i = 0
+ while start do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ head, current = insert_node_after(head,current,copy_node(start))
+ else
+ i = i + 1
+ end
+ start = start.next
+ end
+ start = current.next
+ while start and start.id == glyph do
+ if marks[start.char] then
+ set_attribute(start,markdone,i)
+ if trace_marks then
+ logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i)
+ end
+ else
+ break
+ end
+ start = start.next
+ end
+ end
+ return head
+ end
+ else
+ start.char = char
+ end
+ return start
+end
+
+function handlers.gsub_single(start,kind,lookupname,replacement)
+ if trace_singles then
+ logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+end
+
+local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) -- chainname and chainlookupname optional
+ local value, choice, n = featurevalue or tfmdata.shared.features[kind], nil, #alternatives -- global value, brrr
+ if value == "random" then
+ local r = math.random(1,n)
+ value, choice = format("random, choice %s",r), alternatives[r]
+ elseif value == "first" then
+ value, choice = format("first, choice %s",1), alternatives[1]
+ elseif value == "last" then
+ value, choice = format("last, choice %s",n), alternatives[n]
+ elseif type(value) ~= "number" then
+ value, choice = "default, choice 1", alternatives[1]
+ elseif value > n then
+ value, choice = format("no %s variants, taking %s",value,n), alternatives[n]
+ elseif value == 0 then
+ value, choice = format("choice %s (no change)",value), start.char
+ elseif value < 1 then
+ value, choice = format("no %s variants, taking %s",value,1), alternatives[1]
+ else
+ value, choice = format("choice %s",value), alternatives[value]
+ end
+ if not choice then
+ logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(start.char))
+ choice, value = start.char, format("no replacement instead of %s",value)
+ end
+ return choice, value
+end
+
+function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence)
+ local choice, index = alternative_glyph(start,alternative,kind,lookupname)
+ if trace_alternatives then
+ logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),index)
+ end
+ start.char = choice
+ return start, true
+end
+
+function handlers.gsub_multiple(start,kind,lookupname,multiple)
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple))
+ end
+ start.char = multiple[1]
+ if #multiple > 1 then
+ for k=2,#multiple do
+ local n = copy_node(start)
+ n.char = multiple[k]
+ local sn = start.next
+ n.next = sn
+ n.prev = start
+ if sn then
+ sn.prev = n
+ end
+ start.next = n
+ start = n
+ end
+ end
+ return start, true
+end
+
+function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
+ local s, stop, discfound = start.next, nil, false
+ if marks[start.char] then
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local startchar, stopchar = start.char, stop.char
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = markstoligature(kind,lookupname,start,stop,ligature[2])
+ end
+ return start, true
+ end
+ else
+ local skipmark = sequence.flags[1]
+ while s do
+ local id = s.id
+ if id == glyph and s.subtype<256 then
+ if s.font == currentfont then
+ local char = s.char
+ if skipmark and marks[char] then
+ s = s.next
+ else
+ local lg = ligature[1][char]
+ if not lg then
+ break
+ else
+ stop = s
+ ligature = lg
+ s = s.next
+ end
+ end
+ else
+ break
+ end
+ elseif id == disc then
+ discfound = true
+ s = s.next
+ else
+ break
+ end
+ end
+ if stop and ligature[2] then
+ if trace_ligatures then
+ local startchar, stopchar = start.char, stop.char
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char))
+ else
+ start = toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound)
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>We get hits on a mark, but we're not sure if the it has to be applied so
+we need to explicitly test for basechar, baselig and basemark entries.</p>
+--ldx]]--
+
+function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ end
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence)
+ -- check chainpos variant
+ local markchar = start.char
+ if marks[markchar] then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",pref(kind,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar]
+ if baseanchors then
+ baseanchors = baseanchors.anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start,true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar))
+ fonts.register_message(currentfont,basechar,"no base anchors")
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",pref(kind,lookupname))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar))
+ end
+ return start,false
+end
+
+function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) -- to be checked
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local done = false
+ local startchar = start.char
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+end
+
+function handlers.gpos_single(start,kind,lookupname,kerns,sequence)
+ local startchar = start.char
+ local dx, dy = set_pair(start,tfmdata.factor,rlmode,kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy)
+ end
+ return start, false
+end
+
+function handlers.gpos_pair(start,kind,lookupname,kerns,sequence)
+ -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too
+ -- todo: kerns in components of ligatures
+ local snext = start.next
+ if not snext then
+ return start, false
+ else
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+ local krn = kerns[nextchar]
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",pref(kind,lookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+end
+
+--[[ldx--
+<p>I will implement multiple chain replacements once I run into a font that uses
+it. It's not that complex to handle.</p>
+--ldx]]--
+
+local chainmores = { }
+local chainprocs = { }
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf subchain",...)
+end
+local function logwarning(...)
+ logs.report("otf subchain",...)
+end
+
+-- ['coverage']={
+-- ['after']={ "r" },
+-- ['before']={ "q" },
+-- ['current']={ "a", "b", "c" },
+-- },
+-- ['lookups']={ "ls_l_1", "ls_l_1", "ls_l_1" },
+
+function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n)
+ logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+ logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- handled later:
+--
+-- function chainmores.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- return chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n)
+-- end
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf chain",...)
+end
+local function logwarning(...)
+ logs.report("otf chain",...)
+end
+
+-- We could share functions but that would lead to extra function calls with many
+-- arguments, redundant tests and confusing messages.
+
+function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname)
+ logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname))
+ return start, false
+end
+
+-- The reversesub is a special case, which is why we need to store the replacements
+-- in a bit weird way. There is no lookup and the replacement comes from the lookup
+-- itself. It is meant mostly for dealing with Urdu.
+
+function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements)
+ local char = start.char
+ local replacement = replacements[char]
+ if replacement then
+ if trace_singles then
+ logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement))
+ end
+ start.char = replacement
+ return start, true
+ else
+ return start, false
+ end
+end
+
+--[[ldx--
+<p>This chain stuff is somewhat tricky since we can have a sequence of actions to be
+applied: single, alternate, multiple or ligature where ligature can be an invalid
+one in the sense that it will replace multiple by one but not neccessary one that
+looks like the combination (i.e. it is the counterpart of multiple then). For
+example, the following is valid:</p>
+
+<typing>
+<line>xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx</line>
+</typing>
+
+<p>Therefore we we don't really do the replacement here already unless we have the
+single lookup case. The efficiency of the replacements can be improved by deleting
+as less as needed but that would also mke the code even more messy.</p>
+--ldx]]--
+
+local function delete_till_stop(start,stop,ignoremarks)
+ if start ~= stop then
+ -- todo keep marks
+ local done = false
+ while not done do
+ done = start == stop
+ delete_node(start,start.next)
+ end
+ end
+end
+
+--[[ldx--
+<p>Here we replace start by a single variant, First we delete the rest of the
+match.</p>
+--ldx]]--
+
+function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ -- todo: marks ?
+ if not chainindex then
+ delete_till_stop(start,stop) -- ,currentlookup.flags[1])
+ end
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local replacement = cache.gsub_single[lookupname]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ replacement = replacement[currentchar]
+ if not replacement then
+ if trace_bugs then
+ logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar))
+ end
+ else
+ if trace_singles then
+ logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement))
+ end
+ current.char = replacement
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+chainmores.gsub_single = chainprocs.gsub_single
+
+--[[ldx--
+<p>Here we replace start by a sequence of new glyphs. First we delete the rest of
+the match.</p>
+--ldx]]--
+
+function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ delete_till_stop(start,stop)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local replacements = cache.gsub_multiple[lookupname]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ replacements = replacements[startchar]
+ if not replacements then
+ if trace_bugs then
+ logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar))
+ end
+ else
+ if trace_multiples then
+ logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements))
+ end
+ local sn = start.next
+ for k=1,#replacements do
+ if k == 1 then
+ start.char = replacements[k]
+ else
+ local n = copy_node(start) -- maybe delete the components and such
+ n.char = replacements[k]
+ n.next, n.prev = sn, start
+ if sn then
+ sn.prev = n
+ end
+ start.next, start = n, n
+ end
+ end
+ return start, true
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>Here we replace start by new glyph. First we delete the rest of the match.</p>
+--ldx]]--
+
+function chainprocs.gsub_alternate(start,stop,kind,lookupname,currentcontext,cache,currentlookup)
+ -- todo: marks ?
+ delete_till_stop(start,stop)
+ local current = start
+ local subtables = currentlookup.subtables
+ while current do
+ if current.id == glyph then
+ local currentchar = current.char
+ local lookupname = subtables[1]
+ local alternatives = cache.gsub_alternate[lookupname]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ else
+ alternatives = alternatives[currentchar]
+ if not alternatives then
+ if trace_bugs then
+ logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar))
+ end
+ else
+ local choice, index = alternative_glyph(current,alternatives,kind,chainname,chainlookupname,lookupname)
+ current.char = choice
+ if trace_alternatives then
+ logprocess("%s: replacing single %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),index,gref(currentchar),gref(choice),index)
+ end
+ end
+ end
+ return start, true
+ elseif current == stop then
+ break
+ else
+ current = current.next
+ end
+ end
+ return start, false
+end
+
+--[[ldx--
+<p>When we replace ligatures we use a helper that handles the marks. I might change
+this function (move code inline and handle the marks by a separate function). We
+assume rather stupid ligatures (no complex disc nodes).</p>
+--ldx]]--
+
+function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex)
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local ligatures = cache.gsub_ligature[lookupname]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex))
+ end
+ else
+ ligatures = ligatures[startchar]
+ if not ligatures then
+ if trace_bugs then
+ logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ end
+ else
+ local s, discfound, last, nofreplacements = start.next, false, stop, 0
+ while s do
+ local id = s.id
+ if id == disc then
+ s = s.next
+ discfound = true
+ else
+ local schar = s.char
+ if marks[schar] then -- marks
+ s = s.next
+ else
+ local lg = ligatures[1][schar]
+ if not lg then
+ break
+ else
+ ligatures, last, nofreplacements = lg, s, nofreplacements + 1
+ if s == stop then
+ break
+ else
+ s = s.next
+ end
+ end
+ end
+ end
+ end
+ local l2 = ligatures[2]
+ if l2 then
+ if chainindex then
+ stop = last
+ end
+ if trace_ligatures then
+ if start == stop then
+ logprocess("%s: replacing character %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2))
+ else
+ logprocess("%s: replacing character %s upto %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2))
+ end
+ end
+ start = toligature(kind,lookup,start,stop,l2,currentlookup.flags[1],discfound)
+ return start, true, nofreplacements
+ elseif trace_bugs then
+ if start == stop then
+ logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar))
+ else
+ logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char))
+ end
+ end
+ end
+ end
+ return start, false, 0
+end
+
+chainmores.gsub_ligature = chainprocs.gsub_ligature
+
+function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2base[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if not marks[basechar] then
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar))
+ end
+ return start, false
+ end
+ end
+ end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['basechar']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2ligature[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [optional marks] [start=mark]
+ local index = 1
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ local basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ while true do
+ base = base.prev
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then
+ basechar = base.char
+ if marks[basechar] then
+ index = index + 1
+ else
+ break
+ end
+ else
+ if trace_bugs then
+ logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar)
+ end
+ return start, false
+ end
+ end
+ end
+ -- todo: like marks a ligatures hash
+ local i = has_attribute(start,markdone)
+ if i then index = i end
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ local baseanchors = baseanchors['baselig']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ ba = ba[index]
+ if ba then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname)
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local markchar = start.char
+ if marks[markchar] then
+--~ local alreadydone = markonce and has_attribute(start,markmark)
+--~ if not alreadydone then
+ -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local markanchors = cache.gpos_mark2mark[lookupname]
+ if markanchors then
+ markanchors = markanchors[markchar]
+ end
+ if markanchors then
+ local base = start.prev -- [glyph] [basemark] [start=mark]
+ if base and base.id == glyph and base.subtype<256 and base.font == currentfont then -- subtype test can go
+ local basechar = base.char
+ local baseanchors = descriptions[basechar].anchors
+ if baseanchors then
+ baseanchors = baseanchors['basemark']
+ if baseanchors then
+ local al = anchorlookups[lookupname]
+ for anchor,ba in next, baseanchors do
+ if al[anchor] then
+ local ma = markanchors[anchor]
+ if ma then
+ local dx, dy, bound = set_mark(start,base,tfmdata.factor,rlmode,ba,ma)
+ if trace_marks then
+ logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)",
+ cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy)
+ end
+ return start, true
+ end
+ end
+ end
+ if trace_bugs then
+ logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar))
+ end
+ end
+ end
+ elseif trace_bugs then
+ logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname))
+ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar))
+ end
+--~ elseif trace_marks and trace_details then
+--~ logprocess("%s, mark %s is already bound (n=%s), ignoring mark2mark",pref(kind,lookupname),gref(markchar),alreadydone)
+--~ end
+ elseif trace_bugs then
+ logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar))
+ end
+ return start, false
+end
+
+-- ! ! ! untested ! ! !
+
+function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ local alreadydone = cursonce and has_attribute(start,cursbase)
+ if not alreadydone then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local exitanchors = cache.gpos_cursive[lookupname]
+ if exitanchors then
+ exitanchors = exitanchors[startchar]
+ end
+ if exitanchors then
+ local done = false
+ if marks[startchar] then
+ if trace_cursive then
+ logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar))
+ end
+ else
+ local nxt = start.next
+ while not done and nxt and nxt.id == glyph and nxt.subtype<256 and nxt.font == currentfont do
+ local nextchar = nxt.char
+ if marks[nextchar] then
+ -- should not happen (maybe warning)
+ nxt = nxt.next
+ else
+ local entryanchors = descriptions[nextchar]
+ if entryanchors then
+ entryanchors = entryanchors.anchors
+ if entryanchors then
+ entryanchors = entryanchors['centry']
+ if entryanchors then
+ local al = anchorlookups[lookupname]
+ for anchor, entry in next, entryanchors do
+ if al[anchor] then
+ local exit = exitanchors[anchor]
+ if exit then
+ local dx, dy, bound = set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar])
+ if trace_cursive then
+ logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound)
+ end
+ done = true
+ break
+ end
+ end
+ end
+ end
+ end
+ else -- if trace_bugs then
+ -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar))
+ fonts.register_message(currentfont,startchar,"no entry anchors")
+ end
+ break
+ end
+ end
+ end
+ return start, done
+ else
+ if trace_cursive and trace_details then
+ logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone)
+ end
+ return start, false
+ end
+ end
+ return start, false
+end
+
+function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+ -- untested
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_single[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local dx, dy = set_pair(start,tfmdata.factor,rlmode,kerns,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting single %s by (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy)
+ end
+ end
+ end
+ return start, false
+end
+
+-- when machines become faster i will make a shared function
+
+function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname)
+-- logwarning("%s: gpos_pair not yet supported",cref(kind,chainname,chainlookupname))
+ local snext = start.next
+ if snext then
+ local startchar = start.char
+ local subtables = currentlookup.subtables
+ local lookupname = subtables[1]
+ local kerns = cache.gpos_pair[lookupname]
+ if kerns then
+ kerns = kerns[startchar]
+ if kerns then
+ local prev, done = start, false
+ local factor = tfmdata.factor
+ while snext and snext.id == glyph and snext.subtype<256 and snext.font == currentfont do
+ local nextchar = snext.char
+local krn = kerns[nextchar]
+ if not krn and marks[nextchar] then
+ prev = snext
+ snext = snext.next
+ else
+--~ local krn = kerns[nextchar]
+ if not krn then
+ -- skip
+ elseif type(krn) == "table" then
+ if krn[1] == "pair" then
+ local a, b = krn[3], krn[4]
+ if a and #a > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(start,factor,rlmode,a,characters[startchar])
+ if trace_kerns then
+ logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ if b and #b > 0 then
+ local startchar = start.char
+ local x, y, w, h = set_pair(snext,factor,rlmode,b,characters[nextchar])
+ if trace_kerns then
+ logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h)
+ end
+ end
+ else
+ logs.report("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname))
+ local a, b = krn[3], krn[7]
+ if a and a ~= 0 then
+ local k = set_kern(snext,factor,rlmode,a)
+ if trace_kerns then
+ logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ end
+ if b and b ~= 0 then
+ logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor)
+ end
+ end
+ done = true
+ elseif krn ~= 0 then
+ local k = set_kern(snext,factor,rlmode,krn)
+ if trace_kerns then
+ logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar))
+ end
+ done = true
+ end
+ break
+ end
+ end
+ return start, done
+ end
+ end
+ end
+ return start, false
+end
+
+-- what pointer to return, spec says stop
+-- to be discussed ... is bidi changer a space?
+-- elseif char == zwnj and sequence[n][32] then -- brrr
+
+-- somehow l or f is global
+-- 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 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 !)
+ for k=1,#contexts do
+ local match, current, last = true, start, start
+ local ck = contexts[k]
+ local sequence = ck[3]
+ local s = #sequence
+ if s == 1 then
+ -- never happens
+ match = current.id == glyph and current.subtype<256 and current.font == currentfont and sequence[1][current.char]
+ else
+ -- todo: better space check (maybe check for glue)
+ local f, l = ck[4], ck[5]
+ if f == l then
+ -- already a hit
+ match = true
+ else
+ -- no need to test first hit (to be optimized)
+ local n = f + 1
+ last = last.next
+ -- we cannot optimize for n=2 because there can be disc nodes
+ -- if not someskip and n == l then
+ -- -- n=2 and no skips then faster loop
+ -- match = last and last.id == glyph and last.subtype<256 and last.font == currentfont and sequence[n][last.char]
+ -- else
+ while n <= l do
+ if last then
+ local id = last.id
+ if id == glyph then
+ if last.subtype<256 and last.font == currentfont then
+ local char = last.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ last = last.next
+ elseif sequence[n][char] then
+ if n < l then
+ last = last.next
+ end
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then -- what to do with kerns?
+ last = last.next
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ end
+ -- end
+ end
+ if match and f > 1 then
+ local prev = start.prev
+ if prev then
+ local n = f-1
+ while n >= 1 do
+ if prev then
+ local id = prev.id
+ if id == glyph then
+ if prev.subtype<256 and prev.font == currentfont then -- normal char
+ local char = prev.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ elseif sequence[n][char] then
+ n = n -1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif sequence[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ prev = prev.prev
+ elseif sequence[n][32] then
+ n = n -1
+ else
+ match = false break
+ end
+ end
+ elseif f == 2 then
+ match = sequence[1][32]
+ else
+ for n=f-1,1 do
+ if not sequence[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ if match and s > l then
+ local current = last.next
+ if current then
+ -- removed optimiziation for s-l == 1, we have to deal with marks anyway
+ local n = l + 1
+ while n <= s do
+ if current then
+ local id = current.id
+ if id == glyph then
+ if current.subtype<256 and current.font == currentfont then -- normal char
+ local char = current.char
+ local ccd = descriptions[char]
+ if ccd then
+ local class = ccd.class
+ if class == skipmark or class == skipligature or class == skipbase then
+--~ if someskip and class == skipmark or class == skipligature or class == skipbase then
+ -- skip 'm
+ elseif sequence[n][char] then
+ n = n + 1
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ else
+ match = false break
+ end
+ elseif id == disc then
+ -- skip 'm
+ elseif sequence[n][32] then -- brrr
+ n = n + 1
+ else
+ match = false break
+ end
+ current = current.next
+ elseif sequence[n][32] then
+ n = n + 1
+ else
+ match = false break
+ end
+ end
+ elseif s-l == 1 then
+ match = sequence[s][32]
+ else
+ for n=l+1,s do
+ if not sequence[n][32] then
+ match = false break
+ end
+ end
+ end
+ end
+ end
+ if match then
+ -- ck == currentcontext
+ if trace_contexts then
+ local rule, lookuptype, sequence, f, l = ck[1], ck[2] ,ck[3], ck[4], ck[5]
+ local char = start.char
+ if ck[9] then
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s (%s=>%s)",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10])
+ else
+ logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype)
+ end
+ end
+ local chainlookups = ck[6]
+ if chainlookups then
+ local nofchainlookups = #chainlookups
+ -- we can speed this up if needed
+ if nofchainlookups == 1 then
+ local chainlookupname = chainlookups[1]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainprocs[chainlookup.type]
+ if cp then
+ start, done = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname)
+ else
+ logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ else
+ -- actually this needs a more complex treatment for which we will use chainmores
+ local i = 1
+ repeat
+ local chainlookupname = chainlookups[i]
+ local chainlookup = lookuptable[chainlookupname]
+ local cp = chainmores[chainlookup.type]
+ if cp then
+ local ok, n
+ start, ok, n = cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i)
+ -- messy since last can be changed !
+ if ok then
+ done = true
+ start = start.next
+ if n then
+ -- skip next one(s) if ligature
+ i = i + n - 1
+ end
+ end
+ else
+ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+ end
+ i = i + 1
+ until i > nofchainlookups
+ end
+ else
+ local replacements = ck[7]
+ if replacements then
+ start, done = chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements)
+ else
+ done = true -- can be meant to be skipped
+ if trace_contexts then
+ logprocess("%s: skipping match",cref(kind,chainname))
+ end
+ end
+ end
+ end
+ end
+ return start, done
+end
+
+-- Because we want to keep this elsewhere (an because speed is less an issue) we
+-- pass the font id so that the verbose variant can access the relevant helper tables.
+
+local verbose_handle_contextchain = function(font,...)
+ logwarning("no verbose handler installed, reverting to 'normal'")
+ otf.setcontextchain()
+ return normal_handle_contextchain(...)
+end
+
+otf.chainhandlers = {
+ normal = normal_handle_contextchain,
+ verbose = verbose_handle_contextchain,
+}
+
+function otf.setcontextchain(method)
+ if not method or method == "normal" or not otf.chainhandlers[method] then
+ if handlers.contextchain then -- no need for a message while making the format
+ logwarning("installing normal contextchain handler")
+ end
+ handlers.contextchain = normal_handle_contextchain
+ else
+ logwarning("installing contextchain handler '%s'",method)
+ local handler = otf.chainhandlers[method]
+ handlers.contextchain = function(...)
+ return handler(currentfont,...)
+ end
+ end
+ handlers.gsub_context = handlers.contextchain
+ handlers.gsub_contextchain = handlers.contextchain
+ handlers.gsub_reversecontextchain = handlers.contextchain
+ handlers.gpos_contextchain = handlers.contextchain
+ handlers.gpos_context = handlers.contextchain
+end
+
+otf.setcontextchain()
+
+local missing = { } -- we only report once
+
+local function logprocess(...)
+ if trace_steps then
+ registermessage(...)
+ end
+ logs.report("otf process",...)
+end
+local function logwarning(...)
+ logs.report("otf process",...)
+end
+
+local function report_missing_cache(typ,lookup)
+ local f = missing[currentfont] if not f then f = { } missing[currentfont] = f end
+ local t = f[typ] if not t then t = { } f[typ] = t end
+ if not t[lookup] then
+ t[lookup] = true
+ logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname)
+ end
+end
+
+local resolved = { } -- we only resolve a font,script,language pair once
+
+function fonts.methods.node.otf.features(head,font,attr)
+ if trace_steps then
+ checkstep(head)
+ end
+ tfmdata = fontdata[font]
+ local shared = tfmdata.shared
+ otfdata = shared.otfdata
+ local luatex = otfdata.luatex
+ descriptions = tfmdata.descriptions
+ characters = tfmdata.characters
+ indices = tfmdata.indices
+ unicodes = tfmdata.unicodes
+ marks = tfmdata.marks
+ anchorlookups = luatex.lookup_to_anchor
+ currentfont = font
+ rlmode = 0
+ local featuredata = otfdata.shared.featuredata -- can be made local to closure
+ local sequences = luatex.sequences
+ lookuptable = luatex.lookups
+ local done = false
+ local script, language, s_enabled, a_enabled, dyn
+ local attribute_driven = attr and attr ~= 0
+ if attribute_driven then
+ local features = context_setups[context_numbers[attr]] -- could be a direct list
+ dyn = context_merged[attr] or 0
+ language, script = features.language or "dflt", features.script or "dflt"
+ a_enabled = features -- shared.features -- can be made local to the resolver
+ if dyn == 2 or dyn == -2 then
+ -- font based
+ s_enabled = shared.features
+ end
+ else
+ language, script = tfmdata.language or "dflt", tfmdata.script or "dflt"
+ s_enabled = shared.features -- can be made local to the resolver
+ dyn = 0
+ end
+ -- we can save some runtime by caching feature tests
+ local res = resolved[font] if not res then res = { } resolved[font] = res end
+ local rs = res [script] if not rs then rs = { } res [script] = rs end
+ local rl = rs [language] if not rl then rl = { } rs [language] = rl end
+ local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
+ -- sequences always > 1 so no need for optimization
+ for s=1,#sequences do
+ local success = false
+ local sequence = sequences[s]
+ local r = ra[s] -- cache
+ if r == nil then
+ --
+ -- this bit will move to font-ctx and become a function
+ ---
+ local chain = sequence.chain or 0
+ local features = sequence.features
+ if not features then
+ -- indirect lookup, part of chain (todo: make this a separate table)
+ r = false -- { false, false, chain }
+ else
+ local valid, attribute, kind, what = false, false
+ for k,v in next, features do
+ -- we can quit earlier but for the moment we want the tracing
+ local s_e = s_enabled and s_enabled[k]
+ local a_e = a_enabled and a_enabled[k]
+ if s_e or a_e then
+ local l = v[script] or v[wildcard]
+ if l then
+ -- not l[language] or l[default] or l[wildcard] because we want tracing
+ -- only first attribute match check, so we assume simple fina's
+ -- default can become a font feature itself
+ if l[language] then
+--~ valid, what = true, language
+ valid, what = s_e or a_e, language
+ -- elseif l[default] then
+ -- valid, what = true, default
+ elseif l[wildcard] then
+--~ valid, what = true, wildcard
+ valid, what = s_e or a_e, wildcard
+ end
+ if valid then
+ kind, attribute = k, special_attributes[k] or false
+ if a_e and dyn < 0 then
+ valid = false
+ end
+ if trace_applied then
+ local typ, action = match(sequence.type,"(.*)_(.*)")
+ logs.report("otf node mode",
+ "%s font: %03i, dynamic: %03i, kind: %s, lookup: %3i, script: %-4s, language: %-4s (%-4s), type: %s, action: %s, name: %s",
+ (valid and "+") or "-",font,attr or 0,kind,s,script,language,what,typ,action,sequence.name)
+ end
+ break
+ end
+ end
+ end
+ end
+ if valid then
+ r = { valid, attribute, chain, kind }
+ else
+ r = false -- { valid, attribute, chain, "generic" } -- false anyway, could be flag instead of table
+ end
+ end
+ ra[s] = r
+ end
+featurevalue = r and r[1] -- toto: pass to function instead
+ if featurevalue then
+ local attribute, chain, typ, subtables = r[2], r[3], sequence.type, sequence.subtables
+ if chain < 0 then
+ -- this is a limited case, no special treatments like 'init' etc
+ local handler = handlers[typ]
+ local thecache = featuredata[typ] or { }
+ -- we need to get rid of this slide !
+ start = slide_node_list(head) -- slow (we can store tail because there's always a skip at the end): todo
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
+ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
+ for i=1,#subtables do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ start, success = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if success then
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.prev end
+ else
+ start = start.prev
+ end
+ else
+ start = start.prev
+ end
+ end
+ else
+ local handler = handlers[typ]
+ local ns = #subtables
+ local thecache = featuredata[typ] or { }
+ start = head -- local ?
+ rlmode = 0
+ if ns == 1 then
+ local lookupname = subtables[1]
+ local lookupcache = thecache[lookupname]
+ if not lookupcache then
+ report_missing_cache(typ,lookupname)
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- sequence kan weg
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
+ if ok then
+ success = true
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" then
+ rlmode = -1
+ elseif dir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlmode = -1
+ elseif dir == "TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+
+ end
+ else
+ while start do
+ local id = start.id
+ if id == glyph then
+--~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ for i=1,ns do
+ local lookupname = subtables[i]
+ local lookupcache = thecache[lookupname]
+ if lookupcache then
+ local lookupmatch = lookupcache[start.char]
+ if lookupmatch then
+ -- we could move all code inline but that makes things even more unreadable
+ local ok
+ start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i)
+ if ok then
+ success = true
+ break
+ end
+ end
+ else
+ report_missing_cache(typ,lookupname)
+ end
+ end
+ if start then start = start.next end
+ else
+ start = start.next
+ end
+ -- elseif id == glue then
+ -- if p[5] then -- chain
+ -- local pc = pp[32]
+ -- if pc then
+ -- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4])
+ -- if ok then
+ -- done = true
+ -- end
+ -- if start then start = start.next end
+ -- else
+ -- start = start.next
+ -- end
+ -- else
+ -- start = start.next
+ -- end
+ elseif id == whatsit then
+ local subtype = start.subtype
+ if subtype == 7 then
+ local dir = start.dir
+ if dir == "+TRT" then
+ rlmode = -1
+ elseif dir == "+TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ elseif subtype == 6 then
+ local dir = start.dir
+ if dir == "TRT" then
+ rlmode = -1
+ elseif dir == "TLT" then
+ rlmode = 1
+ else
+ rlmode = 0
+ end
+ end
+ start = start.next
+ else
+ start = start.next
+ end
+ end
+ end
+ end
+ if success then
+ done = true
+ end
+ if trace_steps then -- ?
+ registerstep(head)
+ end
+ end
+ end
+ return head, done
+end
+
+otf.features.prepare = { }
+
+-- we used to share code in the following functions but that costs a lot of
+-- memory due to extensive calls to functions (easily hundreds of thousands per
+-- document)
+
+local function split(replacement,original,cache,unicodes)
+ -- we can cache this too, but not the same
+ local o, t, n = { }, { }, 0
+ for s in gmatch(original,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then
+ o[#o+1] = us
+ else
+ o[#o+1] = us[1]
+ end
+ end
+ for s in gmatch(replacement,"[^ ]+") do
+ n = n + 1
+ local us = unicodes[s]
+ if type(us) == "number" then
+ t[o[n]] = us
+ else
+ t[o[n]] = us[1]
+ end
+ end
+ return t
+end
+
+local function uncover(covers,result,cache,unicodes)
+ -- lpeg hardly faster (.005 sec on mk)
+ for n=1,#covers do
+ local c = covers[n]
+ local cc = cache[c]
+ if not cc then
+ local t = { }
+ for s in gmatch(c,"[^ ]+") do
+ local us = unicodes[s]
+ if type(us) == "number" then
+ t[us] = true
+ else
+ for i=1,#us do
+ t[us[i]] = true
+ end
+ end
+ end
+ cache[c] = t
+ result[#result+1] = t
+ else
+ result[#result+1] = cc
+ end
+ end
+end
+
+local function prepare_lookups(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ local anchor_to_lookup = otfdata.luatex.anchor_to_lookup
+ local lookup_to_anchor = otfdata.luatex.lookup_to_anchor
+ --
+ local multiple = featuredata.gsub_multiple
+ local alternate = featuredata.gsub_alternate
+ local single = featuredata.gsub_single
+ local ligature = featuredata.gsub_ligature
+ local pair = featuredata.gpos_pair
+ local position = featuredata.gpos_single
+ local kerns = featuredata.gpos_pair
+ local mark = featuredata.gpos_mark2mark
+ local cursive = featuredata.gpos_cursive
+ --
+ local unicodes = tfmdata.unicodes -- names to unicodes
+ local indices = tfmdata.indices
+ local descriptions = tfmdata.descriptions
+ --
+ -- we can change the otf table after loading but then we need to adapt base mode
+ -- as well (no big deal)
+ --
+ for unicode, glyph in next, descriptions do
+ local lookups = glyph.lookups
+ if lookups then
+ for lookup, whatever in next, lookups do
+ for i=1,#whatever do -- normaly one
+ local p = whatever[i]
+ local what = p[1]
+ if what == 'substitution' then
+ local old, new = unicode, unicodes[p[2]]
+ if type(new) == "table" then
+ new = new[1]
+ end
+ local s = single[lookup]
+ if not s then s = { } single[lookup] = s end
+ s[old] = new
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: substitution %s => %s",lookup,old,new)
+--~ end
+ break
+ elseif what == 'multiple' then
+ local old, new = unicode, { }
+ local m = multiple[lookup]
+ if not m then m = { } multiple[lookup] = m end
+ m[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: multiple %s => %s",lookup,old,concat(new," "))
+--~ end
+ break
+ elseif what == 'alternate' then
+ local old, new = unicode, { }
+ local a = alternate[lookup]
+ if not a then a = { } alternate[lookup] = a end
+ a[old] = new
+ for pc in gmatch(p[2],"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ new[#new+1] = upc
+ else
+ new[#new+1] = upc[1]
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
+--~ end
+ break
+ elseif what == "ligature" then
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
+--~ end
+ local first = true
+ local t = ligature[lookup]
+ if not t then t = { } ligature[lookup] = t end
+ for s in gmatch(p[2],"[^ ]+") do
+ if first then
+ local u = unicodes[s]
+ if not u then
+ logs.report("define otf","lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name)
+ break
+ elseif type(u) == "number" then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ t = t[u]
+ else
+ local tt = t
+ local tu
+ for i=1,#u do
+ local u = u[i]
+ if i==1 then
+ if not t[u] then
+ t[u] = { { } }
+ end
+ tu = t[u]
+ t = tu
+ else
+ if not t[u] then
+ tt[u] = tu
+ end
+ end
+ end
+ end
+ first = false
+ else
+ s = unicodes[s]
+ local t1 = t[1]
+ if not t1[s] then
+ t1[s] = { { } }
+ end
+ t = t1[s]
+ end
+ end
+ t[2] = unicode
+ elseif what == 'position' then
+ -- not used
+ local s = position[lookup]
+ if not s then s = { } position[lookup] = s end
+ s[unicode] = p[2] -- direct pointer to kern spec
+ elseif what == 'pair' then
+ local s = pair[lookup]
+ if not s then s = { } pair[lookup] = s end
+ local others = s[unicode]
+ if not others then others = { } s[unicode] = others end
+ -- todo: fast check for space
+ local two = p[2]
+ local upc = unicodes[two]
+ if not upc then
+ for pc in gmatch(two,"[^ ]+") do
+ local upc = unicodes[pc]
+ if type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+ end
+ elseif type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: pair for U+%04X",lookup,unicode)
+--~ end
+ end
+ end
+ end
+ end
+ local list = glyph.mykerns
+ if list then
+ for lookup, krn in next, list do
+ local k = kerns[lookup]
+ if not k then k = { } kerns[lookup] = k end
+ k[unicode] = krn -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: kern for U+%04X",lookup,unicode)
+--~ end
+ end
+ end
+ local oanchor = glyph.anchors
+ if oanchor then
+ for typ, anchors in next, oanchor do -- types
+ if typ == "mark" then
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = mark[lookup]
+ if not f then f = { } mark[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
+--~ end
+ end
+ end
+ end
+ elseif typ == "cexit" then -- or entry?
+ for name, anchor in next, anchors do
+ local lookups = anchor_to_lookup[name]
+ if lookups then
+ for lookup, _ in next, lookups do
+ local f = cursive[lookup]
+ if not f then f = { } cursive[lookup] = f end
+ f[unicode] = anchors -- ref to glyph, saves lookup
+--~ if trace_lookups then
+--~ logs.report("define otf","lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
+--~ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+-- local cache = { }
+luatex = luatex or {} -- this has to change ... we need a better one
+
+function prepare_contextchains(tfmdata)
+ local otfdata = tfmdata.shared.otfdata
+ local lookups = otfdata.lookups
+ if lookups then
+ local featuredata = otfdata.shared.featuredata
+ local contextchain = featuredata.gsub_contextchain -- shared with gpos
+ local reversecontextchain = featuredata.gsub_reversecontextchain -- shared with gpos
+ local characters = tfmdata.characters
+ local unicodes = tfmdata.unicodes
+ local indices = tfmdata.indices
+ local cache = luatex.covers
+ if not cache then
+ cache = { }
+ luatex.covers = cache
+ end
+ --
+ for lookupname, lookupdata in next, otfdata.lookups do
+ local lookuptype = lookupdata.type
+ if not lookuptype then
+ logs.report("otf process","missing lookuptype for %s",lookupname)
+ else
+ local rules = lookupdata.rules
+ if rules then
+ local fmt = lookupdata.format
+ -- contextchain[lookupname][unicode]
+ if fmt == "coverage" then
+ if lookuptype ~= "chainsub" and lookuptype ~= "chainpos" then
+ logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = contextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ contextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do -- does #rules>1 happen often?
+ local rule = rules[nofrules]
+ local coverage = rule.coverage
+ if coverage and coverage.current then
+ local current, before, after, sequence = coverage.current, coverage.before, coverage.after, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if sequence[1] then
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ elseif fmt == "reversecoverage" then
+ if lookuptype ~= "reversesub" then
+ logs.report("otf process","unsupported reverse coverage %s for %s",lookuptype,lookupname)
+ else
+ local contexts = reversecontextchain[lookupname]
+ if not contexts then
+ contexts = { }
+ reversecontextchain[lookupname] = contexts
+ end
+ local t = { }
+ for nofrules=1,#rules do
+ local rule = rules[nofrules]
+ local reversecoverage = rule.reversecoverage
+ if reversecoverage and reversecoverage.current then
+ local current, before, after, replacements, sequence = reversecoverage.current, reversecoverage.before, reversecoverage.after, reversecoverage.replacements, { }
+ if before then
+ uncover(before,sequence,cache,unicodes)
+ end
+ local start = #sequence + 1
+ uncover(current,sequence,cache,unicodes)
+ local stop = #sequence
+ if after then
+ uncover(after,sequence,cache,unicodes)
+ end
+ if replacements then
+ replacements = split(replacements,current[1],cache,unicodes)
+ end
+ if sequence[1] then
+ -- this is different from normal coverage, we assume only replacements
+ t[#t+1] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements }
+ for unic, _ in next, sequence[start] do
+ local cu = contexts[unic]
+ if not cu then
+ contexts[unic] = t
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+function fonts.initializers.node.otf.features(tfmdata,value)
+ if true then -- value then
+ if not tfmdata.shared.otfdata.shared.initialized then
+ local t = trace_preparing and os.clock()
+ local otfdata = tfmdata.shared.otfdata
+ local featuredata = otfdata.shared.featuredata
+ -- caches
+ featuredata.gsub_multiple = { }
+ featuredata.gsub_alternate = { }
+ featuredata.gsub_single = { }
+ featuredata.gsub_ligature = { }
+ featuredata.gsub_contextchain = { }
+ featuredata.gsub_reversecontextchain = { }
+ featuredata.gpos_pair = { }
+ featuredata.gpos_single = { }
+ featuredata.gpos_mark2base = { }
+ featuredata.gpos_mark2ligature = featuredata.gpos_mark2base
+ featuredata.gpos_mark2mark = featuredata.gpos_mark2base
+ featuredata.gpos_cursive = { }
+ featuredata.gpos_contextchain = featuredata.gsub_contextchain
+ featuredata.gpos_reversecontextchain = featuredata.gsub_reversecontextchain
+ --
+ prepare_contextchains(tfmdata)
+ prepare_lookups(tfmdata)
+ otfdata.shared.initialized = true
+ if trace_preparing then
+ logs.report("otf process","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?")
+ end
+ end
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-ota'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (analysing)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- this might become scrp-*.lua
+
+local type, tostring, match, format, concat = type, tostring, string.match, string.format, table.concat
+
+if not trackers then trackers = { register = function() end } end
+
+local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+local trace_cjk = false trackers.register("cjk.injections", function(v) trace_cjk = v end)
+
+trackers.register("cjk.analyzing","otf.analyzing")
+
+fonts = fonts or { }
+fonts.analyzers = fonts.analyzers or { }
+fonts.analyzers.initializers = fonts.analyzers.initializers or { node = { otf = { } } }
+fonts.analyzers.methods = fonts.analyzers.methods or { node = { otf = { } } }
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+local initializers = fonts.analyzers.initializers
+local methods = fonts.analyzers.methods
+
+local glyph = node.id('glyph')
+local glue = node.id('glue')
+local penalty = node.id('penalty')
+
+local set_attribute = node.set_attribute
+local has_attribute = node.has_attribute
+local traverse_id = node.traverse_id
+local delete_node = nodes.delete
+local replace_node = nodes.replace
+local insert_node_after = node.insert_after
+local insert_node_before = node.insert_before
+local traverse_node_list = node.traverse
+
+local fontdata = fonts.ids
+local state = attributes.private('state')
+
+local fcs = (fonts.color and fonts.color.set) or function() end
+local fcr = (fonts.color and fonts.color.reset) or function() end
+
+local a_to_script = otf.a_to_script
+local a_to_language = otf.a_to_language
+
+-- in the future we will use language/script attributes instead of the
+-- font related value, but then we also need dynamic features which is
+-- somewhat slower; and .. we need a chain of them
+
+
+function fonts.initializers.node.otf.analyze(tfmdata,value,attr)
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = initializers[script]
+ if action then
+ if type(action) == "function" then
+ return action(tfmdata,value)
+ else
+ local action = action[language]
+ if action then
+ return action(tfmdata,value)
+ end
+ end
+ end
+ return nil
+end
+
+function fonts.methods.node.otf.analyze(head,font,attr)
+ local tfmdata = fontdata[font]
+ local script, language
+ if attr and attr > 0 then
+ script, language = a_to_script[attr], a_to_language[attr]
+ else
+ script, language = tfmdata.script, tfmdata.language
+ end
+ local action = methods[script]
+ if action then
+ if type(action) == "function" then
+ return action(head,font,attr)
+ else
+ action = action[language]
+ if action then
+ return action(head,font,attr)
+ end
+ end
+ end
+ return head, false
+end
+
+otf.features.register("analyze",true) -- we always analyze
+table.insert(fonts.triggers,"analyze") -- we need a proper function for doing this
+
+-- latin
+
+fonts.analyzers.methods.latn = fonts.analyzers.aux.setstate
+
+-- this info eventually will go into char-def
+
+local zwnj = 0x200C
+local zwj = 0x200D
+
+local isol = {
+ [0x0600] = true, [0x0601] = true, [0x0602] = true, [0x0603] = true,
+ [0x0608] = true, [0x060B] = true, [0x0621] = true, [0x0674] = true,
+ [0x06DD] = true, [zwnj] = true,
+}
+
+local isol_fina = {
+ [0x0622] = true, [0x0623] = true, [0x0624] = true, [0x0625] = true,
+ [0x0627] = true, [0x0629] = true, [0x062F] = true, [0x0630] = true,
+ [0x0631] = true, [0x0632] = true, [0x0648] = true, [0x0671] = true,
+ [0x0672] = true, [0x0673] = true, [0x0675] = true, [0x0676] = true,
+ [0x0677] = true, [0x0688] = true, [0x0689] = true, [0x068A] = true,
+ [0x068B] = true, [0x068C] = true, [0x068D] = true, [0x068E] = true,
+ [0x068F] = true, [0x0690] = true, [0x0691] = true, [0x0692] = true,
+ [0x0693] = true, [0x0694] = true, [0x0695] = true, [0x0696] = true,
+ [0x0697] = true, [0x0698] = true, [0x0699] = true, [0x06C0] = true,
+ [0x06C3] = true, [0x06C4] = true, [0x06C5] = true, [0x06C6] = true,
+ [0x06C7] = true, [0x06C8] = true, [0x06C9] = true, [0x06CA] = true,
+ [0x06CB] = true, [0x06CD] = true, [0x06CF] = true, [0x06D2] = true,
+ [0x06D3] = true, [0x06D5] = true, [0x06EE] = true, [0x06EF] = true,
+ [0x0759] = true, [0x075A] = true, [0x075B] = true, [0x076B] = true,
+ [0x076C] = true, [0x0771] = true, [0x0773] = true, [0x0774] = true,
+ [0x0778] = true, [0x0779] = true,
+}
+
+local isol_fina_medi_init = {
+ [0x0626] = true, [0x0628] = true, [0x062A] = true, [0x062B] = true,
+ [0x062C] = true, [0x062D] = true, [0x062E] = true, [0x0633] = true,
+ [0x0634] = true, [0x0635] = true, [0x0636] = true, [0x0637] = true,
+ [0x0638] = true, [0x0639] = true, [0x063A] = true, [0x063B] = true,
+ [0x063C] = true, [0x063D] = true, [0x063E] = true, [0x063F] = true,
+ [0x0640] = true, [0x0641] = true, [0x0642] = true, [0x0643] = true,
+ [0x0644] = true, [0x0645] = true, [0x0646] = true, [0x0647] = true,
+ [0x0649] = true, [0x064A] = true, [0x066E] = true, [0x066F] = true,
+ [0x0678] = true, [0x0679] = true, [0x067A] = true, [0x067B] = true,
+ [0x067C] = true, [0x067D] = true, [0x067E] = true, [0x067F] = true,
+ [0x0680] = true, [0x0681] = true, [0x0682] = true, [0x0683] = true,
+ [0x0684] = true, [0x0685] = true, [0x0686] = true, [0x0687] = true,
+ [0x069A] = true, [0x069B] = true, [0x069C] = true, [0x069D] = true,
+ [0x069E] = true, [0x069F] = true, [0x06A0] = true, [0x06A1] = true,
+ [0x06A2] = true, [0x06A3] = true, [0x06A4] = true, [0x06A5] = true,
+ [0x06A6] = true, [0x06A7] = true, [0x06A8] = true, [0x06A9] = true,
+ [0x06AA] = true, [0x06AB] = true, [0x06AC] = true, [0x06AD] = true,
+ [0x06AE] = true, [0x06AF] = true, [0x06B0] = true, [0x06B1] = true,
+ [0x06B2] = true, [0x06B3] = true, [0x06B4] = true, [0x06B5] = true,
+ [0x06B6] = true, [0x06B7] = true, [0x06B8] = true, [0x06B9] = true,
+ [0x06BA] = true, [0x06BB] = true, [0x06BC] = true, [0x06BD] = true,
+ [0x06BE] = true, [0x06BF] = true, [0x06C1] = true, [0x06C2] = true,
+ [0x06CC] = true, [0x06CE] = true, [0x06D0] = true, [0x06D1] = true,
+ [0x06FA] = true, [0x06FB] = true, [0x06FC] = true, [0x06FF] = true,
+ [0x0750] = true, [0x0751] = true, [0x0752] = true, [0x0753] = true,
+ [0x0754] = true, [0x0755] = true, [0x0756] = true, [0x0757] = true,
+ [0x0758] = true, [0x075C] = true, [0x075D] = true, [0x075E] = true,
+ [0x075F] = true, [0x0760] = true, [0x0761] = true, [0x0762] = true,
+ [0x0763] = true, [0x0764] = true, [0x0765] = true, [0x0766] = true,
+ [0x0767] = true, [0x0768] = true, [0x0769] = true, [0x076A] = true,
+ [0x076D] = true, [0x076E] = true, [0x076F] = true, [0x0770] = true,
+ [0x0772] = true, [0x0775] = true, [0x0776] = true, [0x0777] = true,
+ [0x077A] = true, [0x077B] = true, [0x077C] = true, [0x077D] = true,
+ [0x077E] = true, [0x077F] = true, [zwj] = true,
+}
+
+local arab_warned = { }
+
+-- todo: gref
+
+local function warning(current,what)
+ local char = current.char
+ if not arab_warned[char] then
+ log.report("analyze","arab: character %s (U+%04X) has no %s class", char, char, what)
+ arab_warned[char] = true
+ end
+end
+
+function fonts.analyzers.methods.nocolor(head,font,attr)
+ for n in traverse_node_list(head,glyph) do
+ if not font or n.font == font then
+ fcr(n)
+ end
+ end
+ return head, true
+end
+
+otf.remove_joiners = false -- true -- for idris who want it as option
+
+local function finish(first,last)
+ if last then
+ if first == last then
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ else
+ local lc = last.char
+ if isol_fina_medi_init[lc] or isol_fina[lc] then -- why isol here ?
+ -- if laststate == 1 or laststate == 2 or laststate == 4 then
+ set_attribute(last,state,3) -- fina
+ if trace_analyzing then fcs(last,"font:fina") end
+ else
+ warning(last,"fina")
+ set_attribute(last,state,0) -- error
+ if trace_analyzing then fcr(last) end
+ end
+ end
+ first, last = nil, nil
+ elseif first then
+ -- first and last are either both set so we never com here
+ local fc = first.char
+ if isol_fina_medi_init[fc] or isol_fina[fc] then
+ set_attribute(first,state,4) -- isol
+ if trace_analyzing then fcs(first,"font:isol") end
+ else
+ warning(first,"isol")
+ set_attribute(first,state,0) -- error
+ if trace_analyzing then fcr(first) end
+ end
+ first = nil
+ end
+ return first, last
+end
+
+function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special version with no trace
+ local tfmdata = fontdata[font]
+ local marks = tfmdata.marks
+ local first, last, current, done = nil, nil, head, false
+ local joiners, nonjoiners
+ local removejoiners = tfmdata.remove_joiners -- or otf.remove_joiners
+ if removejoiners then
+ joiners, nonjoiners = { }, { }
+ end
+ while current do
+ if current.id == glyph and current.subtype<256 and current.font == font and not has_attribute(current,state) then
+ done = true
+ local char = current.char
+ if removejoiners then
+ if char == zwj then
+ joiners[#joiners+1] = current
+ elseif char == zwnj then
+ nonjoiners[#nonjoiners+1] = current
+ end
+ end
+ if marks[char] then
+ set_attribute(current,state,5) -- mark
+ if trace_analyzing then fcs(current,"font:mark") end
+ elseif isol[char] then -- can be zwj or zwnj too
+ first, last = finish(first,last)
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ elseif not first then
+ if isol_fina_medi_init[char] then
+ set_attribute(current,state,1) -- init
+ if trace_analyzing then fcs(current,"font:init") end
+ first, last = first or current, current
+ elseif isol_fina[char] then
+ set_attribute(current,state,4) -- isol
+ if trace_analyzing then fcs(current,"font:isol") end
+ first, last = nil, nil
+ else -- no arab
+ first, last = finish(first,last)
+ end
+ elseif isol_fina_medi_init[char] then
+ first, last = first or current, current
+ set_attribute(current,state,2) -- medi
+ if trace_analyzing then fcs(current,"font:medi") end
+ elseif isol_fina[char] then
+ if not has_attribute(last,state,1) then
+ -- tricky, we need to check what last may be !
+ set_attribute(last,state,2) -- medi
+ if trace_analyzing then fcs(last,"font:medi") end
+ end
+ set_attribute(current,state,3) -- fina
+ if trace_analyzing then fcs(current,"font:fina") end
+ first, last = nil, nil
+ elseif char >= 0x0600 and char <= 0x06FF then
+ if trace_analyzing then fcs(current,"font:rest") end
+ first, last = finish(first,last)
+ else --no
+ first, last = finish(first,last)
+ end
+ else
+ first, last = finish(first,last)
+ end
+ current = current.next
+ end
+ first, last = finish(first,last)
+ if removejoiners then
+ for i=1,#joiners do
+ head = delete_node(head,joiners[i])
+ end
+ for i=1,#nonjoiners do
+ head = replace_node(head,nonjoiners[i],nodes.glue(0)) -- or maybe a kern
+ end
+ end
+ return head, done
+end
+
+table.insert(fonts.manipulators,"joiners")
+
+function fonts.initializers.node.otf.joiners(tfmdata,value)
+ if value == "strip" then
+ tfmdata.remove_joiners = true
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-otc'] = {
+ version = 1.001,
+ comment = "companion to font-otf.lua (context)",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, insert = string.format, table.insert
+local type, next = type, next
+
+local ctxcatcodes = tex.ctxcatcodes
+
+-- we assume that the other otf stuff is loaded already
+
+local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
+
+local otf = fonts.otf
+local tfm = fonts.tfm
+
+-- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
+-- have always); some day we can write a "force always when true" trick for other
+-- features as well
+
+local extra_lists = {
+ tlig = {
+ {
+ endash = "hyphen hyphen",
+ emdash = "hyphen hyphen hyphen",
+ -- quotedblleft = "quoteleft quoteleft",
+ -- quotedblright = "quoteright quoteright",
+ -- quotedblleft = "grave grave",
+ -- quotedblright = "quotesingle quotesingle",
+ -- quotedblbase = "comma comma",
+ },
+ },
+ trep = {
+ {
+ -- [0x0022] = 0x201D,
+ [0x0027] = 0x2019,
+ -- [0x0060] = 0x2018,
+ },
+ },
+ anum = {
+ { -- arabic
+ [0x0030] = 0x0660,
+ [0x0031] = 0x0661,
+ [0x0032] = 0x0662,
+ [0x0033] = 0x0663,
+ [0x0034] = 0x0664,
+ [0x0035] = 0x0665,
+ [0x0036] = 0x0666,
+ [0x0037] = 0x0667,
+ [0x0038] = 0x0668,
+ [0x0039] = 0x0669,
+ },
+ { -- persian
+ [0x0030] = 0x06F0,
+ [0x0031] = 0x06F1,
+ [0x0032] = 0x06F2,
+ [0x0033] = 0x06F3,
+ [0x0034] = 0x06F4,
+ [0x0035] = 0x06F5,
+ [0x0036] = 0x06F6,
+ [0x0037] = 0x06F7,
+ [0x0038] = 0x06F8,
+ [0x0039] = 0x06F9,
+ },
+ },
+}
+
+local extra_features = { -- maybe just 1..n so that we prescribe order
+ tlig = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, },
+ name = "ctx_tlig_1",
+ subtables = { { name = "ctx_tlig_1_s" } },
+ type = "gsub_ligature",
+ flags = { },
+ },
+ },
+ trep = {
+ {
+ features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, },
+ name = "ctx_trep_1",
+ subtables = { { name = "ctx_trep_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+ anum = {
+ {
+ features = { { scripts = { { script = "arab", langs = { "dflt", "FAR" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_1",
+ subtables = { { name = "ctx_anum_1_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ {
+ features = { { scripts = { { script = "arab", langs = { "URD" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ name = "ctx_anum_2",
+ subtables = { { name = "ctx_anum_2_s" } },
+ type = "gsub_single",
+ flags = { },
+ },
+ },
+}
+
+fonts.otf.enhancers["add some missing characters"] = function(data,filename)
+ -- todo
+end
+
+fonts.otf.enhancers["enrich with features"] = function(data,filename)
+ -- could be done elsewhere (true can be #)
+ local used = { }
+ for i=1,#otf.glists do
+ local g = data[otf.glists[i]]
+ if g then
+ for i=1,#g do
+ local f = g[i].features
+ if f then
+ for i=1,#f do
+ local t = f[i].tag
+ if t then used[t] = true end
+ end
+ end
+ end
+ end
+ end
+ --
+ local glyphs = data.glyphs
+ local indices = data.map.map
+ data.gsub = data.gsub or { }
+ for kind, specifications in next, extra_features do
+ if not used[kind] then
+ local done = 0
+ for s=1,#specifications do
+ local added = false
+ local specification = specifications[s]
+ local list = extra_lists[kind][s]
+ local name = specification.name .. "_s"
+ if specification.type == "gsub_ligature" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local ligature = list[glyph.name]
+ if ligature then
+ local o = glyph.lookups or { }
+ -- o[name] = { "ligature", ligature, glyph.name }
+ o[name] = {
+ {
+ ["type"] = "ligature",
+ ["specification"] = {
+ char = glyph.name,
+ components = ligature,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ elseif specification.type == "gsub_single" then
+ for unicode, index in next, indices do
+ local glyph = glyphs[index]
+ local r = list[unicode]
+ if r then
+ local replacement = indices[r]
+ if replacement and glyphs[replacement] then
+ local o = glyph.lookups or { }
+ -- o[name] = { { "substitution", glyphs[replacement].name } }
+ o[name] = {
+ {
+ ["type"] = "substitution",
+ ["specification"] = {
+ variant = glyphs[replacement].name,
+ }
+ }
+ }
+ glyph.lookups, done, added = o, done+1, true
+ end
+ end
+ end
+ end
+ if added then
+ insert(data.gsub,s,table.fastcopy(specification)) -- right order
+ end
+ end
+ if done > 0 then
+ if trace_loading then
+ logs.report("load otf","enhance: registering %s feature (%s glyphs affected)",kind,done)
+ end
+ end
+ end
+ end
+end
+
+otf.tables.features['tlig'] = 'TeX Ligatures'
+otf.tables.features['trep'] = 'TeX Replacements'
+otf.tables.features['anum'] = 'Arabic Digits'
+
+otf.features.register_base_substitution('tlig')
+otf.features.register_base_substitution('trep')
+otf.features.register_base_substitution('anum')
+
+-- the functionality is defined elsewhere
+
+fonts.initializers.base.otf.equaldigits = fonts.initializers.common.equaldigits
+fonts.initializers.node.otf.equaldigits = fonts.initializers.common.equaldigits
+
+fonts.initializers.base.otf.lineheight = fonts.initializers.common.lineheight
+fonts.initializers.node.otf.lineheight = fonts.initializers.common.lineheight
+
+fonts.initializers.base.otf.compose = fonts.initializers.common.compose
+fonts.initializers.node.otf.compose = fonts.initializers.common.compose
+
+-- bonus function
+
+function otf.name_to_slot(name) -- todo: afm en tfm
+ local tfmdata = fonts.ids[font.current()]
+ if tfmdata and tfmdata.shared then
+ local otfdata = tfmdata.shared.otfdata
+ local unicode = otfdata.luatex.unicodes[name]
+ if type(unicode) == "number" then
+ return unicode
+ else
+ return unicode[1]
+ end
+ end
+ return nil
+end
+
+function otf.char(n) -- todo: afm en tfm
+ if type(n) == "string" then
+ n = otf.name_to_slot(n)
+ end
+ if n then
+ tex.sprint(ctxcatcodes,format("\\char%s ",n))
+ end
+end
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-def'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading")
+trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*")
+
+--[[ldx--
+<p>Here we deal with defining fonts. We do so by intercepting the
+default loader that only handles <l n='tfm'/>.</p>
+--ldx]]--
+
+fonts = fonts or { }
+fonts.define = fonts.define or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+fonts.vf = fonts.vf or { }
+fonts.used = fonts.used or { }
+
+local tfm = fonts.tfm
+local vf = fonts.vf
+local define = fonts.define
+
+tfm.version = 1.01
+tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
+
+define.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
+define.specify = fonts.define.specify or { }
+define.methods = fonts.define.methods or { }
+
+tfm.fonts = tfm.fonts or { }
+tfm.readers = tfm.readers or { }
+tfm.internalized = tfm.internalized or { } -- internal tex numbers
+
+tfm.readers.sequence = { 'otf', 'ttf', 'afm', 'tfm' }
+
+local readers = tfm.readers
+local sequence = readers.sequence
+
+--[[ldx--
+<p>We hardly gain anything when we cache the final (pre scaled)
+<l n='tfm'/> table. But it can be handy for debugging.</p>
+--ldx]]--
+
+fonts.version = 1.05
+fonts.cache = containers.define("fonts", "def", fonts.version, false)
+
+--[[ldx--
+<p>We can prefix a font specification by <type>name:</type> or
+<type>file:</type>. The first case will result in a lookup in the
+synonym table.</p>
+
+<typing>
+[ name: | file: ] identifier [ separator [ specification ] ]
+</typing>
+
+<p>The following function split the font specification into components
+and prepares a table that will move along as we proceed.</p>
+--ldx]]--
+
+-- beware, we discard additional specs
+--
+-- method:name method:name(sub) method:name(sub)*spec method:name*spec
+-- name name(sub) name(sub)*spec name*spec
+-- name@spec*oeps
+
+local splitter, specifiers = nil, ""
+
+function define.add_specifier(symbol)
+ specifiers = specifiers .. symbol
+ local left = lpeg.P("(")
+ local right = lpeg.P(")")
+ local colon = lpeg.P(":")
+ local method = lpeg.S(specifiers)
+ local lookup = lpeg.C(lpeg.P("file")+lpeg.P("name")) * colon -- hard test, else problems with : method
+ local sub = left * lpeg.C(lpeg.P(1-left-right-method)^1) * right
+--~ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1)
+ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1)^1)
+ local name = lpeg.C((1-sub-specification)^1)
+ splitter = lpeg.P((lookup + lpeg.Cc("")) * name * (sub + lpeg.Cc("")) * (specification + lpeg.Cc("")))
+end
+
+function define.get_specification(str)
+ return splitter:match(str)
+end
+
+function define.register_split(symbol,action)
+ define.add_specifier(symbol)
+ define.specify[symbol] = action
+end
+
+function define.makespecification(specification, lookup, name, sub, method, detail, size)
+ size = size or 655360
+ if trace_defining then
+ logs.report("define font","%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s",
+ specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-",
+ (sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-")
+ end
+--~ if specification.lookup then
+--~ lookup = specification.lookup -- can come from xetex [] syntax
+--~ specification.lookup = nil
+--~ end
+ if lookup ~= 'name' then -- for the moment only two lookups, maybe some day also system:
+ lookup = 'file'
+ end
+ local t = {
+ lookup = lookup, -- forced type
+ specification = specification, -- full specification
+ size = size, -- size in scaled points or -1000*n
+ name = name, -- font or filename
+ sub = sub, -- subfont (eg in ttc)
+ method = method, -- specification method
+ detail = detail, -- specification
+ resolved = "", -- resolved font name
+ forced = "", -- forced loader
+ features = { }, -- preprocessed features
+ }
+ return t
+end
+
+function define.analyze(specification, size)
+ -- can be optimized with locals
+ local lookup, name, sub, method, detail = define.get_specification(specification or "")
+ return define.makespecification(specification,lookup, name, sub, method, detail, size)
+end
+
+--[[ldx--
+<p>A unique hash value is generated by:</p>
+--ldx]]--
+
+local sortedhashkeys = table.sortedhashkeys
+
+function tfm.hash_features(specification)
+ local features = specification.features
+ if features then
+ local t = { }
+ local normal = features.normal
+ if normal and next(normal) then
+ local f = sortedhashkeys(normal)
+ for i=1,#f do
+ local v = f[i]
+ if v ~= "number" and v ~= "features" then -- i need to figure this out, features
+ t[#t+1] = v .. '=' .. tostring(normal[v])
+ end
+ end
+ end
+ local vtf = features.vtf
+ if vtf and next(vtf) then
+ local f = sortedhashkeys(vtf)
+ for i=1,#f do
+ local v = f[i]
+ t[#t+1] = v .. '=' .. tostring(vtf[v])
+ end
+ end
+--~ if specification.mathsize then
+--~ t[#t] = "mathsize=" .. specification.mathsize
+--~ end
+ if #t > 0 then
+ return concat(t,"+")
+ end
+ end
+ return "unknown"
+end
+
+fonts.designsizes = { }
+
+--[[ldx--
+<p>In principle we can share tfm tables when we are in node for a font, but then
+we need to define a font switch as an id/attr switch which is no fun, so in that
+case users can best use dynamic features ... so, we will not use that speedup. Okay,
+when we get rid of base mode we can optimize even further by sharing, but then we
+loose our testcases for <l n='luatex'/>.</p>
+--ldx]]--
+
+function tfm.hash_instance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
+ if force or not hash then
+ hash = tfm.hash_features(specification)
+ specification.hash = hash
+ end
+ if size < 1000 and fonts.designsizes[hash] then
+ size = math.round(tfm.scaled(size, fonts.designsizes[hash]))
+ specification.size = size
+ end
+--~ local mathsize = specification.mathsize or 0
+--~ if mathsize > 0 then
+--~ local textsize = specification.textsize
+--~ if fallbacks then
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks
+--~ else
+--~ return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]'
+--~ end
+--~ else
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+--~ end
+end
+
+--[[ldx--
+<p>We can resolve the filename using the next function:</p>
+--ldx]]--
+
+function define.resolve(specification)
+ if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash
+ if specification.lookup == 'name' then
+ specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
+ if specification.resolved then
+ specification.forced = file.extname(specification.resolved)
+ specification.name = file.removesuffix(specification.resolved)
+ end
+ elseif specification.lookup == 'file' then
+ specification.forced = file.extname(specification.name)
+ specification.name = file.removesuffix(specification.name)
+ end
+ end
+ if specification.forced == "" then
+ specification.forced = nil
+ else
+ specification.forced = specification.forced
+ end
+--~ specification.hash = specification.name .. ' @ ' .. tfm.hash_features(specification)
+ specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
+ if specification.sub and specification.sub ~= "" then
+ specification.hash = specification.sub .. ' @ ' .. specification.hash
+ end
+ return specification
+end
+
+--[[ldx--
+<p>The main read function either uses a forced reader (as determined by
+a lookup) or tries to resolve the name using the list of readers.</p>
+
+<p>We need to cache when possible. We do cache raw tfm data (from <l
+n='tfm'/>, <l n='afm'/> or <l n='otf'/>). After that we can cache based
+on specificstion (name) and size, that is, <l n='tex'/> only needs a number
+for an already loaded fonts. However, it may make sense to cache fonts
+before they're scaled as well (store <l n='tfm'/>'s with applied methods
+and features). However, there may be a relation between the size and
+features (esp in virtual fonts) so let's not do that now.</p>
+
+<p>Watch out, here we do load a font, but we don't prepare the
+specification yet.</p>
+--ldx]]--
+
+function tfm.read(specification)
+ local hash = tfm.hash_instance(specification)
+ local tfmtable = tfm.fonts[hash] -- hashes by size !
+ if not tfmtable then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = readers[lower(forced)](specification)
+ if not tfmtable then
+ logs.report("define font","forced type %s of %s not found",forced,specification.name)
+ end
+ else
+ for s=1,#sequence do -- reader sequence
+ local reader = sequence[s]
+ if readers[reader] then -- not really needed
+ if trace_defining then
+ logs.report("define font","trying type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
+ end
+ tfmtable = readers[reader](specification)
+ if tfmtable then break end
+ end
+ end
+ end
+ if tfmtable then
+ if tfmtable.filename and fonts.dontembed[tfmtable.filename] then
+ tfmtable.embedding = "no"
+ else
+ tfmtable.embedding = "subset"
+ end
+ tfm.fonts[hash] = tfmtable
+ fonts.designsizes[specification.hash] = tfmtable.designsize -- we only know this for sure after loading once
+ --~ tfmtable.mode = specification.features.normal.mode or "base"
+ end
+ end
+ if not tfmtable then
+ logs.report("define font","font with name %s is not found",specification.name)
+ end
+ return tfmtable
+end
+
+--[[ldx--
+<p>For virtual fonts we need a slightly different approach:</p>
+--ldx]]--
+
+function tfm.read_and_define(name,size) -- no id
+ local specification = define.analyze(name,size)
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
+ end
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ local id = define.registered(hash)
+ if not id then
+ local fontdata = tfm.read(specification)
+ if fontdata then
+ fontdata.hash = hash
+ id = font.define(fontdata)
+ define.register(fontdata,id)
+ tfm.cleanup_table(fontdata)
+ else
+ id = 0 -- signal
+ end
+ end
+ return fonts.ids[id], id
+end
+
+--[[ldx--
+<p>Next follow the readers. This code was written while <l n='luatex'/>
+evolved. Each one has its own way of dealing with its format.</p>
+--ldx]]--
+
+local function check_tfm(specification,fullname)
+ -- ofm directive blocks local path search unless set
+ fullname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, "ofm"
+ return tfm.read_from_tfm(specification)
+ end
+end
+
+local function check_afm(specification,fullname)
+ fullname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, "afm"
+ return tfm.read_from_afm(specification)
+ end
+end
+
+function readers.tfm(specification)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_tfm(specification,specification.name .. "." .. forced)
+ end
+ if not tfmtable then
+ tfmtable = check_tfm(specification,specification.name)
+ end
+ else
+ tfmtable = check_tfm(specification,fullname)
+ end
+ return tfmtable
+end
+
+function readers.afm(specification,method)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_afm(specification,specification.name .. "." .. forced)
+ end
+ if not tfmtable then
+ method = method or define.method or "afm or tfm"
+ if method == "tfm" then
+ tfmtable = check_tfm(specification,specification.name)
+ elseif method == "afm" then
+ tfmtable = check_afm(specification,specification.name)
+ elseif method == "tfm or afm" then
+ tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
+ else -- method == "afm or tfm" or method == "" then
+ tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
+ end
+ end
+ else
+ tfmtable = check_afm(specification,fullname)
+ end
+ return tfmtable
+end
+
+local function check_otf(specification,suffix,what)
+ local fullname, tfmtable = resolvers.findbinfile(specification.name,suffix) or "", nil
+ if fullname == "" then
+ local fb = fonts.names.old_to_new[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
+ end
+ if fullname == "" then
+ local fb = fonts.names.new_to_old[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
+ end
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
+ tfmtable = tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
+ end
+ return tfmtable
+end
+
+function readers.opentype(specification,suffix,what)
+ local forced = specification.forced or ""
+ if forced == "otf" then
+ return check_otf(specification,forced,"opentype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
+ else
+ return check_otf(specification,suffix,what)
+ end
+end
+
+function readers.otf(specification) return readers.opentype(specification,"otf","opentype") end
+function readers.ttf(specification) return readers.opentype(specification,"ttf","truetype") end
+function readers.ttc(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+
+--[[ldx--
+<p>We need to check for default features. For this we provide
+a helper function.</p>
+--ldx]]--
+
+function define.check(features,defaults) -- nb adapts features !
+ local done = false
+ if table.is_empty(features) then
+ features, done = table.fastcopy(defaults), true
+ else
+ for k,v in next, defaults do
+ if features[k] == nil then
+ features[k], done = v, true
+ end
+ end
+ end
+ return features, done -- done signals a change
+end
+
+--[[ldx--
+<p>So far the specifyers. Now comes the real definer. Here we cache
+based on id's. Here we also intercept the virtual font handler. Since
+it evolved stepwise I may rewrite this bit (combine code).</p>
+
+In the previously defined reader (the one resulting in a <l n='tfm'/>
+table) we cached the (scaled) instances. Here we cache them again, but
+this time based on id. We could combine this in one cache but this does
+not gain much. By the way, passing id's back to in the callback was
+introduced later in the development.</p>
+--ldx]]--
+
+define.last = nil
+
+function define.register(fontdata,id)
+ if fontdata and id then
+ local hash = fontdata.hash
+ if not tfm.internalized[hash] then
+ if trace_defining then
+ logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?")
+ end
+ fonts.ids[id] = fontdata
+ tfm.internalized[hash] = id
+ end
+ end
+end
+
+function define.registered(hash)
+ local id = tfm.internalized[hash]
+ return id, id and fonts.ids[id]
+end
+
+local cache_them = false
+
+function tfm.make(specification)
+ -- currently fonts are scaled while constructing the font, so we
+ -- have to do scaling of commands in the vf at that point using
+ -- e.g. "local scale = g.factor or 1" after all, we need to work
+ -- with copies anyway and scaling needs to be done at some point;
+ -- however, when virtual tricks are used as feature (makes more
+ -- sense) we scale the commands in fonts.tfm.scale (and set the
+ -- factor there)
+ local fvm = define.methods[specification.features.vtf.preset]
+ if fvm then
+ return fvm(specification)
+ else
+ return nil
+ end
+end
+
+function define.read(specification,size,id) -- id can be optional, name can already be table
+ statistics.starttiming(fonts)
+ if type(specification) == "string" then
+ specification = define.analyze(specification,size)
+ end
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
+ end
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ if cache_them then
+ local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
+ end
+ local fontdata = define.registered(hash) -- id
+ if not fontdata then
+ if specification.features.vtf and specification.features.vtf.preset then
+ fontdata = tfm.make(specification)
+ else
+ fontdata = tfm.read(specification)
+ if fontdata then
+ tfm.check_virtual_id(fontdata)
+ end
+ end
+ if cache_them then
+ fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes
+ end
+ if fontdata then
+ fontdata.hash = hash
+ fontdata.cache = "no"
+ if id then
+ define.register(fontdata,id)
+ end
+ end
+ end
+ define.last = fontdata or id -- todo ! ! ! ! !
+ if not fontdata then
+ logs.report("define font", "unknown font %s, loading aborted",specification.name)
+ elseif trace_defining and type(fontdata) == "table" then
+ logs.report("define font","using %s font with id %s, n:%s s:%s b:%s e:%s p:%s f:%s",
+ fontdata.type or "unknown",
+ id or "?",
+ fontdata.name or "?",
+ fontdata.size or "default",
+ fontdata.encodingbytes or "?",
+ fontdata.encodingname or "unicode",
+ fontdata.fullname or "?",
+ file.basename(fontdata.filename or "?"))
+ end
+ statistics.stoptiming(fonts)
+ return fontdata
+end
+
+function vf.find(name)
+ name = file.removesuffix(file.basename(name))
+ if tfm.resolve_vf then
+ local format = fonts.logger.format(name)
+ if format == 'tfm' or format == 'ofm' then
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
+ end
+ return resolvers.findbinfile(name,"ovf")
+ else
+ if trace_defining then
+ logs.report("define font","vf for %s is already taken care of",name)
+ end
+ return nil -- ""
+ end
+ else
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
+ end
+ return resolvers.findbinfile(name,"ovf")
+ end
+end
+
+--[[ldx--
+<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
+--ldx]]--
+
+callback.register('define_font' , define.read)
+callback.register('find_vf_file', vf.find ) -- not that relevant any more
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-xtx'] = {
+ version = 1.001,
+ comment = "companion to font-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local texsprint, count = tex.sprint, tex.count
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+--[[ldx--
+<p>Choosing a font by name and specififying its size is only part of the
+game. In order to prevent complex commands, <l n='xetex'/> introduced
+a method to pass feature information as part of the font name. At the
+risk of introducing nasty parsing and compatinility problems, this
+syntax was expanded over time.</p>
+
+<p>For the sake of users who have defined fonts using that syntax, we
+will support it, but we will provide additional methods as well.
+Normally users will not use this direct way, but use a more abstract
+interface.</p>
+
+<p>The next one is the official one. However, in the plain
+variant we need to support the crappy [] specification as
+well and that does not work too well with the general design
+of the specifier.</p>
+--ldx]]--
+
+--~ function fonts.define.specify.colonized(specification) -- xetex mode
+--~ local list = { }
+--~ if specification.detail and specification.detail ~= "" then
+--~ for v in gmatch(specification.detail,"%s*([^;]+)%s*") do
+--~ local a, b = match(v,"^(%S*)%s*=%s*(%S*)$")
+--~ if a and b then
+--~ list[a] = b:is_boolean()
+--~ if type(list[a]) == "nil" then
+--~ list[a] = b
+--~ end
+--~ else
+--~ local a, b = match(v,"^([%+%-]?)%s*(%S+)$")
+--~ if a and b then
+--~ list[b] = a ~= "-"
+--~ end
+--~ end
+--~ end
+--~ end
+--~ specification.features.normal = list
+--~ return specification
+--~ end
+
+--~ check("oeps/BI:+a;-b;c=d")
+--~ check("[oeps]/BI:+a;-b;c=d")
+--~ check("file:oeps/BI:+a;-b;c=d")
+--~ check("name:oeps/BI:+a;-b;c=d")
+
+local list = { }
+
+fonts.define.specify.colonized_default_lookup = "file"
+
+local function issome () list.lookup = fonts.define.specify.colonized_default_lookup end
+local function isfile () list.lookup = 'file' end
+local function isname () list.lookup = 'name' end
+local function thename(s) list.name = s end
+local function issub (v) list.sub = v end
+local function iscrap (s) list.crap = string.lower(s) end
+local function istrue (s) list[s] = 'yes' end
+local function isfalse(s) list[s] = 'no' end
+local function iskey (k,v) list[k] = v end
+
+local spaces = lpeg.P(" ")^0
+local namespec = (1-lpeg.S("/: ("))^0
+local crapspec = spaces * lpeg.P("/") * (((1-lpeg.P(":"))^0)/iscrap) * spaces
+local filename = (lpeg.P("file:")/isfile * (namespec/thename)) + (lpeg.P("[") * lpeg.P(true)/isname * (((1-lpeg.P("]"))^0)/thename) * lpeg.P("]"))
+local fontname = (lpeg.P("name:")/isname * (namespec/thename)) + lpeg.P(true)/issome * (namespec/thename)
+local sometext = (lpeg.R("az") + lpeg.R("AZ") + lpeg.R("09"))^1
+local truevalue = lpeg.P("+") * spaces * (sometext/istrue)
+local falsevalue = lpeg.P("-") * spaces * (sometext/isfalse)
+local keyvalue = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(sometext))/iskey
+local somevalue = sometext/istrue
+local subvalue = lpeg.P("(") * (lpeg.C(lpeg.P(1-lpeg.S("()"))^1)/issub) * lpeg.P(")") -- for Kim
+local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
+local options = lpeg.P(":") * spaces * (lpeg.P(";")^0 * option)^0
+local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
+
+function fonts.define.specify.colonized(specification) -- xetex mode
+ list = { }
+ pattern:match(specification.specification)
+ for k, v in next, list do
+ list[k] = v:is_boolean()
+ if type(list[a]) == "nil" then
+ list[k] = v
+ end
+ end
+ list.crap = nil -- style not supported, maybe some day
+ if list.name then
+ specification.name = list.name
+ list.name = nil
+ end
+ if list.lookup then
+ specification.lookup = list.lookup
+ list.lookup = nil
+ end
+ if list.sub then
+ specification.sub = list.sub
+ list.sub = nil
+ end
+ specification.features.normal = list
+ return specification
+end
+
+fonts.define.register_split(":", fonts.define.specify.colonized)
+
+end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules = { } end modules ['font-dum'] = {
+ version = 1.001,
+ comment = "companion to luatex-*.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+fonts = fonts or { }
+
+-- general
+
+fonts.otf.pack = false
+fonts.tfm.resolve_vf = false -- no sure about this
+
+-- readers
+
+fonts.tfm.readers = fonts.tfm.readers or { }
+fonts.tfm.readers.sequence = { 'otf', 'ttf', 'tfm' }
+fonts.tfm.readers.afm = nil
+
+-- define
+
+fonts.define = fonts.define or { }
+
+--~ fonts.define.method = "tfm"
+
+fonts.define.specify.colonized_default_lookup = "name"
+
+function fonts.define.get_specification(str)
+ return "", str, "", ":", str
+end
+
+-- logger
+
+fonts.logger = fonts.logger or { }
+
+function fonts.logger.save()
+end
+
+-- names
+
+fonts.names = fonts.names or { }
+
+fonts.names.basename = "luatex-fonts-names.lua"
+fonts.names.new_to_old = { }
+fonts.names.old_to_new = { }
+
+local data, loaded = nil, false
+
+function fonts.names.resolve(name,sub)
+ if not loaded then
+ local basename = fonts.names.basename
+ if basename and basename ~= "" then
+ for _, format in ipairs { "lua", "tex", "other text files" } do
+ local foundname = resolvers.find_file(basename,format) or ""
+ if foundname ~= "" then
+ data = dofile(foundname)
+ if data then
+ local d = { }
+ for k, v in pairs(data.mapping) do
+ local t = v[1]
+ if t == "ttf" or t == "otf" or t == "ttc" then
+ d[k] = v
+ end
+ end
+ data.mapping = d
+ end
+ break
+ end
+ end
+ end
+ loaded = true
+ end
+ if type(data) == "table" and data.version == 1.08 then
+ local condensed = string.gsub(name,"[^%a%d]","")
+ local found = data.mapping and data.mapping[condensed]
+ if found then
+ local filename, is_sub = found[3], found[4]
+ if is_sub then is_sub = found[2] end
+ return filename, is_sub
+ else
+ return name, false -- fallback to filename
+ end
+ end
+end
+
+-- For the moment we put this (adapted) pseudo feature here.
+
+table.insert(fonts.triggers,"itlc")
+
+local function itlc(tfmdata,value)
+ if value then
+ -- the magic 40 and it formula come from Dohyun Kim
+ local metadata = tfmdata.shared.otfdata.metadata
+ if metadata then
+ local italicangle = metadata.italicangle
+ if italicangle and italicangle ~= 0 then
+ local uwidth = (metadata.uwidth or 40)/2
+ for unicode, d in next, tfmdata.descriptions do
+ local it = d.boundingbox[3] - d.width + uwidth
+ if it ~= 0 then
+ d.italic = it
+ end
+ end
+ tfmdata.has_italic = true
+ end
+ end
+ end
+end
+
+fonts.initializers.base.otf.itlc = itlc
+fonts.initializers.node.otf.itlc = itlc
+
+end -- closure
diff --git a/tex/generic/context/luatex-fonts.lua b/tex/generic/context/luatex-fonts.lua
new file mode 100644
index 000000000..be565c7b3
--- /dev/null
+++ b/tex/generic/context/luatex-fonts.lua
@@ -0,0 +1,139 @@
+if not modules then modules = { } end modules ['luatex-fonts'] = {
+ version = 1.001,
+ comment = "companion to luatex-fonts.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- We keep track of load time by storing the current time. That
+-- way we cannot be accused of slowing down luading too much.
+
+local starttime = os.gettimeofday()
+
+-- As we don't use the ConTeXt file searching, we need to
+-- initialize the kpse library. As the progname can be anything
+-- we will temporary switch to the ConTeXt namespace if needed.
+-- Just adding the context paths to the path specification is
+-- somewhat faster
+
+-- kpse.set_program_name("luatex")
+
+local ctxkpse = nil
+local verbose = true
+
+local function loadmodule(name,continue)
+ local foundname = kpse.find_file(name,"tex") or ""
+ if not foundname then
+ if not ctxkpse then
+ ctxkpse = kpse.new("luatex","context")
+ end
+ foundname = ctxkpse:find_file(name,"tex") or ""
+ end
+ if foundname == "" then
+ if not continue then
+ texio.write_nl(string.format(" <luatex-fonts: unable to locate %s>",name))
+ os.exit()
+ end
+ else
+ if verbose then
+ texio.write(string.format(" <%s>",string.match(name,"([a-z%-]-%.[a-z]-)$"))) -- no file.basename yet
+ end
+ dofile(foundname)
+ end
+end
+
+loadmodule('luatex-fonts-merged.lua',true) -- you might comment this line
+
+if fonts then
+
+ -- We're using the merged version. That one could be outdated so
+ -- remove it from your system when you want to use the files from
+ -- from the ConTeXt tree, or keep your copy of the merged version
+ -- up to date.
+
+ texio.write_nl("log",[[
+
+I am using the merged version of 'luatex-fonts.lua' here. If
+you run into problems or experience unexpected behaviour, and
+if you have ConTeXt installed you can try to delete the file
+'luatex-font-merged.lua' as I might then use the possibly
+updated libraries. The merged version is not supported as it
+is a frozen instance.
+
+ ]])
+
+else
+
+ -- The following helpers are a bit overkill but I don't want to
+ -- mess up ConTeXt code for the sake of general generality. Around
+ -- version 1.0 there will be an official api defined.
+
+ loadmodule('l-string.lua')
+ loadmodule('l-lpeg.lua')
+ loadmodule('l-boolean.lua')
+ loadmodule('l-math.lua')
+ loadmodule('l-table.lua')
+ loadmodule('l-file.lua')
+ loadmodule('l-io.lua')
+
+ -- The following modules contain code that is either not used
+ -- at all outside ConTeXt or will fail when enabled due to
+ -- lack of other modules.
+
+ -- First we load a few helper modules. This is about the miminum
+ -- needed to let the font modules do theuir work.
+
+ loadmodule('luat-dum.lua') -- not used in context at all
+ loadmodule('data-con.lua') -- maybe some day we don't need this one
+
+ -- We do need some basic node support although the following
+ -- modules contain a little bit of code that is not used. It's
+ -- not worth weeding.
+
+ loadmodule('node-ini.lua')
+ loadmodule('node-res.lua') -- will be stripped
+ loadmodule('node-inj.lua') -- will be replaced (luatex > .50)
+ loadmodule('node-fnt.lua')
+ loadmodule('node-dum.lua')
+
+ -- Now come the font modules that deal with traditional TeX fonts
+ -- as well as open type fonts. We don't load the afm related code
+ -- from font-enc.lua and font-afm.lua as only ConTeXt deals with
+ -- it.
+ --
+ -- The font database file (if used at all) must be put someplace
+ -- visible for kpse and is not shared with ConTeXt. The mtx-fonts
+ -- script can be used to genate this file (using the --names
+ -- option).
+
+ loadmodule('font-ini.lua')
+ loadmodule('font-tfm.lua') -- will be split (we may need font-log)
+ loadmodule('font-cid.lua')
+ loadmodule('font-ott.lua') -- might be split
+ loadmodule('font-otf.lua')
+ loadmodule('font-otd.lua')
+ loadmodule('font-oti.lua')
+ loadmodule('font-otb.lua')
+ loadmodule('font-otn.lua')
+ loadmodule('font-ota.lua') -- might be split
+ loadmodule('font-otc.lua')
+ loadmodule('font-def.lua')
+ loadmodule('font-xtx.lua')
+ loadmodule('font-dum.lua')
+
+end
+
+-- In order to deal with the fonts we need to initialize some
+-- callbacks. One can overload them later on if needed.
+
+callback.register('ligaturing', nodes.simple_font_dummy)
+callback.register('kerning', nodes.simple_font_dummy)
+callback.register('pre_linebreak_filter', nodes.simple_font_handler)
+callback.register('hpack_filter', nodes.simple_font_handler)
+callback.register('define_font' , fonts.define.read)
+callback.register('find_vf_file', nil) -- reset to normal
+
+-- We're done.
+
+texio.write(string.format(" <luatex-fonts.lua loaded in %0.3f seconds>", os.gettimeofday()-starttime))
diff --git a/tex/generic/context/luatex-fonts.tex b/tex/generic/context/luatex-fonts.tex
new file mode 100644
index 000000000..644d168f5
--- /dev/null
+++ b/tex/generic/context/luatex-fonts.tex
@@ -0,0 +1,139 @@
+%D \module
+%D [ file=luatex-fonts,
+%D version=2009.12.01,
+%D title=\LUATEX\ Support Macros,
+%D subtitle=Generic \OPENTYPE\ Font Handler,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=public domain]
+
+%D \subject{Welcome}
+%D
+%D This file is one of a set of basic functionality enhancements
+%D for \LUATEX\ derived from the \CONTEXT\ \MKIV\ code base. Please
+%D don't polute the \type {luatex-*} namespace with code not coming
+%D from the \CONTEXT\ development team as we may add more files.
+%D
+%D As this is an experimental setup, it might not always work out as
+%D expected. Around \LUATEX\ version 0.50 we expect the code to be
+%D more or less okay.
+%D
+%D This file implements a basic font system for a bare \LUATEX\
+%D system. By default \LUATEX\ only knows about the classic \TFM\
+%D fonts but it can read other font formats and pass them to \LUA.
+%D With some glue code one can then construct a suitable \TFM\
+%D representation that \LUATEX\ can work with. For more advanced font
+%D support a bit more code is needed that needs to be hooked
+%D into the callback mechanism.
+%D
+%D This file is currently rather simple: it just loads the \LUA\ file
+%D with the same name. An example of a \type {luatex.tex} file that is
+%D just plain \TEX:
+%D
+%D \starttyping
+%D \catcode`\{=1 % left brace is begin-group character
+%D \catcode`\}=2 % right brace is end-group character
+%D
+%D \input plain
+%D
+%D \everyjob\expandafter{\the\everyjob\input luatex-fonts\relax}
+%D
+%D \dump
+%D \stoptyping
+%D
+%D We could load the \LUA\ file in \type {\everyjob} but maybe some
+%D day we need more here.
+%D
+%D When defining a font you can use two prefixes. A \type {file:}
+%D prefix forced a file search, while a \type {name:} prefix will
+%D result in consulting the names database. Such a database can be
+%D generated with:
+%D
+%D \starttyping
+%D mtxrun --usekpse --script fonts --names
+%D \stoptyping
+%D
+%D This will generate a file \type {luatex-fonts-names.lua} that has
+%D to be placed in a location where it can be found by \KPSE. Beware:
+%D the \type {--kpseonly} flag is only used outside \CONTEXT\ and
+%D provides very limited functionality, just enough for this task.
+%D
+%D The code loaded here does not come out of thin air, but is mostly
+%D shared with \CONTEXT, however, in that macropackage we go beyond
+%D what is provided here. When you use the code packaged here you
+%D need to keep a few things in mind:
+%D
+%D \startitemize
+%D
+%D \item This subsystem will be extended, improved etc. in about the
+%D same pace as \CONTEXT\ \MKIV. However, because \CONTEXT\ provides a
+%D rather high level of integration not all features will be supported
+%D in the same quality. Use \CONTEXT\ if you want more goodies.
+%D
+%D \item There is no official \API\ yet, which means that using
+%D functions implemented here is at your own risk, in the sense that
+%D names and namespaces might change. There will be a minimal \API\
+%D defined once \LUATEX\ version 1.0 is out. Instead of patching the
+%D files it's better to overload functions if needed.
+%D
+%D \item The modules are not stripped too much, which makes it
+%D possible to benefit from improvements in the code that take place
+%D in the perspective of \CONTEXT\ development. They might be split a
+%D bit more in due time so the baseline might become smaller.
+%D
+%D \item The code is maintained and tested by the \CONTEXT\
+%D development team. As such it might be better suited for this macro
+%D package and integration in other systems might demand some
+%D additional wrapping. Problems can be reported to the team but as we
+%D use \CONTEXT\ \MKIV\ as baseline, you'd better check if the problem
+%D is a general \CONTEXT\ problem too.
+%D
+%D \item The more high level support for features that is provided in
+%D \CONTEXT\ is not part of the code loaded here as it makes no sense
+%D elsewhere. Some experimental features are not part of this code
+%D either but some might show up later.
+%D
+%D \item Math font support will be added but only in its basic form
+%D once that the Latin Modern and \TEX\ Gyre math fonts are
+%D available.
+%D
+%D \item At this moment the more nifty speed-ups are not enabled
+%D because they work in tandem with the alternative file handling
+%D that \CONTEXT\ uses. Maybe around \LUATEX\ 1.0 we will bring some
+%D speedup into this code too (if it pays off at all).
+%D
+%D \item The code defines a few global tables. If this code is used
+%D in a larger perspective then you can best make sure that no
+%D conflicts occur. The \CONTEXT\ package expects users to work in
+%D their own namespace (\type {userdata}, \type {thirddata}, \type
+%D {moduledata} or \type {document}. The team takes all freedom to
+%D use any table at the global level but will not use tables that are
+%D named after macro packages. Later the \CONTEXT\ might operate in
+%D a more controlled namespace but it has a low priority.
+%D
+%D \item There is some tracing code present but this is not enabled
+%D and not supported outside \CONTEXT\ either as it integrates quite
+%D tightly into \CONTEXT. In case of problems you can use \CONTEXT\
+%D for tracking down problems.
+%D
+%D \item Patching the code in distributions is dangerous as it might
+%D fix your problem but introduce new ones for \CONTEXT. So, best keep
+%D the original code as it is.
+%D
+%D \item Attributes are (automatically) taken from the range 127-255 so
+%D you'd best not use these yourself.
+%D
+%D \stopitemize
+%D
+%D If this all sounds a bit tricky, keep in mind that it makes no sense
+%D for us to maintain multiple code bases and we happen to use \CONTEXT.
+%D
+%D For more details about how the font subsystem works we refer to
+%D publications in \TEX\ related journals, the \CONTEXT\ documentation,
+%D and the \CONTEXT\ wiki.
+
+\directlua {
+ dofile(kpse.find_file("luatex-fonts.lua","tex"))
+}
+
+\endinput
diff --git a/tex/generic/context/luatex-mplib.lua b/tex/generic/context/luatex-mplib.lua
new file mode 100644
index 000000000..6f9bdc7ef
--- /dev/null
+++ b/tex/generic/context/luatex-mplib.lua
@@ -0,0 +1,469 @@
+if not modules then modules = { } end modules ['supp-mpl'] = {
+ version = 1.001,
+ comment = "companion to supp-mpl.tex",
+ author = "Hans Hagen & Taco Hoekwater",
+ copyright = "ConTeXt Development Team",
+ license = "public domain",
+}
+
+--[[ldx--
+<p>This module is a stripped down version of libraries that are used
+by <l n='context'/>. It can be used in other macro packages and/or
+serve as an example. Embedding in a macro package is upto others and
+normally boils down to inputting <t>supp-mpl.tex</t>.</p>
+--ldx]]--
+
+if metapost and metapost.version then
+
+ --[[ldx--
+ <p>Let's silently quit and make sure that no one loads it
+ manually in <l n='context'/>.</p>
+ --ldx]]--
+
+else
+
+ local format, concat, abs = string.format, table.concat, math.abs
+
+ local mplib = require ('mplib')
+ local kpse = require ('kpse')
+
+ --[[ldx--
+ <p>We create a namespace and some variables to it. If a namespace is
+ already defined it wil not be initialized. This permits hooking
+ in code beforehand.</p>
+
+ <p>We don't make a format automatically. After all, distributions
+ might have their own preferences and normally a format (mem) file will
+ have some special place in the <l n='tex'/> tree. Also, there can already
+ be format files, different memort settings and other nasty pitfalls that
+ we don't want to interfere with. If you want, you can define a function
+ <t>metapost.make(name,mem_name) that does the job.</t></p>
+ --ldx]]--
+
+ metapost = metapost or { }
+ metapost.version = 1.00
+ metapost.showlog = metapost.showlog or false
+ metapost.lastlog = ""
+
+ --[[ldx--
+ <p>A few helpers, taken from <t>l-file.lua</t>.</p>
+ --ldx]]--
+
+ local file = file or { }
+
+ function file.replacesuffix(filename, suffix)
+ return (string.gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+ end
+
+ function file.stripsuffix(filename)
+ return (string.gsub(filename,"%.[%a%d]+$",""))
+ end
+
+ --[[ldx--
+ <p>We use the <l n='kpse'/> library unless a finder is already
+ defined.</p>
+ --ldx]]--
+
+ local mpkpse = kpse.new("luatex","mpost")
+
+ metapost.finder = metapost.finder or function(name, mode, ftype)
+ if mode == "w" then
+ return name
+ else
+ return mpkpse:find_file(name,ftype)
+ end
+ end
+
+ --[[ldx--
+ <p>You can use your own reported if needed, as long as it handles multiple
+ arguments and formatted strings.</p>
+ --ldx]]--
+
+ metapost.report = metapost.report or function(...)
+ texio.write(format("<mplib: %s>",format(...)))
+ end
+
+ --[[ldx--
+ <p>The rest of this module is not documented. More info can be found in the
+ <l n='luatex'/> manual, articles in user group journals and the files that
+ ship with <l n='context'/>.</p>
+ --ldx]]--
+
+ function metapost.resetlastlog()
+ metapost.lastlog = ""
+ end
+
+ metapost.make = metapost.make or function(name,mem_name,dump)
+ if false then
+ metapost.report("no format %s made for %s",mem_name,name)
+ return false
+ else
+ local t = os.clock()
+ local mpx = mplib.new {
+ ini_version = true,
+ find_file = metapost.finder,
+ job_name = file.stripsuffix(name)
+ }
+ mpx:execute(string.format("input %s ;",name))
+ if dump then
+ mpx:execute("dump ;")
+ metapost.report("format %s made and dumped for %s in %0.3f seconds",mem_name,name,os.clock()-t)
+ else
+ metapost.report("%s read in %0.3f seconds",name,os.clock()-t)
+ end
+ return mpx
+ end
+ end
+
+ function metapost.load(name)
+ local mem_name = file.replacesuffix(name,"mem")
+ local mpx = mplib.new {
+ ini_version = false,
+ mem_name = mem_name,
+ find_file = metapost.finder
+ }
+ if not mpx and type(metapost.make) == "function" then
+ -- when i have time i'll locate the format and dump
+ mpx = metapost.make(name,mem_name)
+ end
+ if mpx then
+ metapost.report("using format %s",mem_name,false)
+ return mpx, nil
+ else
+ return nil, { status = 99, error = "out of memory or invalid format" }
+ end
+ end
+
+ function metapost.unload(mpx)
+ if mpx then
+ mpx:finish()
+ end
+ end
+
+ function metapost.reporterror(result)
+ if not result then
+ metapost.report("mp error: no result object returned")
+ elseif result.status > 0 then
+ local t, e, l = result.term, result.error, result.log
+ if t then
+ metapost.report("mp terminal: %s",t)
+ end
+ if e then
+ metapost.report("mp error: %s", e)
+ end
+ if not t and not e and l then
+ metapost.lastlog = metapost.lastlog .. "\n " .. l
+ metapost.report("mp log: %s",l)
+ else
+ metapost.report("mp error: unknown, no error, terminal or log messages")
+ end
+ else
+ return false
+ end
+ return true
+ end
+
+ function metapost.process(mpx, data)
+ local converted, result = false, {}
+ mpx = metapost.load(mpx)
+ if mpx and data then
+ local result = mpx:execute(data)
+ if not result then
+ metapost.report("mp error: no result object returned")
+ elseif result.status > 0 then
+ metapost.report("mp error: %s",(result.term or "no-term") .. "\n" .. (result.error or "no-error"))
+ elseif metapost.showlog then
+ metapost.lastlog = metapost.lastlog .. "\n" .. result.term
+ metapost.report("mp info: %s",result.term or "no-term")
+ elseif result.fig then
+ converted = metapost.convert(result)
+ else
+ metapost.report("mp error: unknown error, maybe no beginfig/endfig")
+ end
+ else
+ metapost.report("mp error: mem file not found")
+ end
+ return converted, result
+ end
+
+ local function getobjects(result,figure,f)
+ return figure:objects()
+ end
+
+ function metapost.convert(result, flusher)
+ metapost.flush(result, flusher)
+ return true -- done
+ end
+
+ --[[ldx--
+ <p>We removed some message and tracing code. We might even remove the flusher</p>
+ --ldx]]--
+
+ local function pdf_startfigure(n,llx,lly,urx,ury)
+ tex.sprint(format("\\startMPLIBtoPDF{%s}{%s}{%s}{%s}",llx,lly,urx,ury))
+ end
+
+ local function pdf_stopfigure()
+ tex.sprint("\\stopMPLIBtoPDF")
+ end
+
+ function pdf_literalcode(fmt,...) -- table
+ tex.sprint(format("\\MPLIBtoPDF{%s}",format(fmt,...)))
+ end
+
+ function pdf_textfigure(font,size,text,width,height,depth)
+ text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost
+ tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-( 7200/ 7227)/65536*depth))
+ end
+
+ local bend_tolerance = 131/65536
+
+ local rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+
+ local function pen_characteristics(object)
+ if mplib.pen_info then
+ local t = mplib.pen_info(object)
+ rx, ry, sx, sy, tx, ty = t.rx, t.ry, t.sx, t.sy, t.tx, t.ty
+ divider = sx*sy - rx*ry
+ return not (sx==1 and rx==0 and ry==0 and sy==1 and tx==0 and ty==0), t.width
+ else
+ rx, sx, sy, ry, tx, ty, divider = 1, 0, 0, 1, 0, 0, 1
+ return false, 1
+ end
+ end
+
+ local function concat(px, py) -- no tx, ty here
+ return (sy*px-ry*py)/divider,(sx*py-rx*px)/divider
+ end
+
+ local function curved(ith,pth)
+ local d = pth.left_x - ith.right_x
+ if abs(ith.right_x - ith.x_coord - d) <= bend_tolerance and abs(pth.x_coord - pth.left_x - d) <= bend_tolerance then
+ d = pth.left_y - ith.right_y
+ if abs(ith.right_y - ith.y_coord - d) <= bend_tolerance and abs(pth.y_coord - pth.left_y - d) <= bend_tolerance then
+ return false
+ end
+ end
+ return true
+ end
+
+ local function flushnormalpath(path,open)
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ pdf_literalcode("%f %f m",pth.x_coord,pth.y_coord)
+ elseif curved(ith,pth) then
+ pdf_literalcode("%f %f %f %f %f %f c",ith.right_x,ith.right_y,pth.left_x,pth.left_y,pth.x_coord,pth.y_coord)
+ else
+ pdf_literalcode("%f %f l",pth.x_coord,pth.y_coord)
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ pdf_literalcode("%f %f %f %f %f %f c",pth.right_x,pth.right_y,one.left_x,one.left_y,one.x_coord,one.y_coord )
+ else
+ pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
+ end
+ elseif #path == 1 then
+ -- special case .. draw point
+ local one = path[1]
+ pdf_literalcode("%f %f l",one.x_coord,one.y_coord)
+ end
+ return t
+ end
+
+ local function flushconcatpath(path,open)
+ pdf_literalcode("%f %f %f %f %f %f cm", sx, rx, ry, sy, tx ,ty)
+ local pth, ith
+ for i=1,#path do
+ pth = path[i]
+ if not ith then
+ pdf_literalcode("%f %f m",concat(pth.x_coord,pth.y_coord))
+ elseif curved(ith,pth) then
+ local a, b = concat(ith.right_x,ith.right_y)
+ local c, d = concat(pth.left_x,pth.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(pth.x_coord, pth.y_coord))
+ else
+ pdf_literalcode("%f %f l",concat(pth.x_coord, pth.y_coord))
+ end
+ ith = pth
+ end
+ if not open then
+ local one = path[1]
+ if curved(pth,one) then
+ local a, b = concat(pth.right_x,pth.right_y)
+ local c, d = concat(one.left_x,one.left_y)
+ pdf_literalcode("%f %f %f %f %f %f c",a,b,c,d,concat(one.x_coord, one.y_coord))
+ else
+ pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ end
+ elseif #path == 1 then
+ -- special case .. draw point
+ local one = path[1]
+ pdf_literalcode("%f %f l",concat(one.x_coord,one.y_coord))
+ end
+ return t
+ end
+
+ --[[ldx--
+ <p>Support for specials has been removed.</p>
+ --ldx]]--
+
+ function metapost.flush(result,flusher)
+ if result then
+ local figures = result.fig
+ if figures then
+ for f=1, #figures do
+ metapost.report("flushing figure %s",f)
+ local figure = figures[f]
+ local objects = getobjects(result,figure,f)
+ local fignum = tonumber((figure:filename()):match("([%d]+)$") or figure:charcode() or 0)
+ local miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ local bbox = figure:boundingbox()
+ local llx, lly, urx, ury = bbox[1], bbox[2], bbox[3], bbox[4] -- faster than unpack
+ if urx < llx then
+ -- invalid
+ pdf_startfigure(fignum,0,0,0,0)
+ pdf_stopfigure()
+ else
+ pdf_startfigure(fignum,llx,lly,urx,ury)
+ pdf_literalcode("q")
+ if objects then
+ for o=1,#objects do
+ local object = objects[o]
+ local objecttype = object.type
+ if objecttype == "start_bounds" or objecttype == "stop_bounds" then
+ -- skip
+ elseif objecttype == "start_clip" then
+ pdf_literalcode("q")
+ flushnormalpath(object.path,t,false)
+ pdf_literalcode("W n")
+ elseif objecttype == "stop_clip" then
+ pdf_literalcode("Q")
+ miterlimit, linecap, linejoin, dashed = -1, -1, -1, false
+ elseif objecttype == "special" then
+ -- not supported
+ elseif objecttype == "text" then
+ local ot = object.transform -- 3,4,5,6,1,2
+ pdf_literalcode("q %f %f %f %f %f %f cm",ot[3],ot[4],ot[5],ot[6],ot[1],ot[2])
+ pdf_textfigure(object.font,object.dsize,object.text,object.width,object.height,object.depth)
+ pdf_literalcode("Q")
+ else
+ local cs = object.color
+ if cs and #cs > 0 then
+ pdf_literalcode(metapost.colorconverter(cs))
+ end
+ local ml = object.miterlimit
+ if ml and ml ~= miterlimit then
+ miterlimit = ml
+ pdf_literalcode("%f M",ml)
+ end
+ local lj = object.linejoin
+ if lj and lj ~= linejoin then
+ linejoin = lj
+ pdf_literalcode("%i j",lj)
+ end
+ local lc = object.linecap
+ if lc and lc ~= linecap then
+ linecap = lc
+ pdf_literalcode("%i J",lc)
+ end
+ local dl = object.dash
+ if dl then
+ local d = format("[%s] %i d",concat(dl.dashes or {}," "),dl.offset)
+ if d ~= dashed then
+ dashed = d
+ pdf_literalcode(dashed)
+ end
+ elseif dashed then
+ pdf_literalcode("[] 0 d")
+ dashed = false
+ end
+ local path = object.path
+ local transformed, penwidth = false, 1
+ local open = path and path[1].left_type and path[#path].right_type
+ local pen = object.pen
+ if pen then
+ if pen.type == 'elliptical' then
+ transformed, penwidth = pen_characteristics(object) -- boolean, value
+ pdf_literalcode("%f w",penwidth)
+ if objecttype == 'fill' then
+ objecttype = 'both'
+ end
+ else -- calculated by mplib itself
+ objecttype = 'fill'
+ end
+ end
+ if transformed then
+ pdf_literalcode("q")
+ end
+ if path then
+ if transformed then
+ flushconcatpath(path,open)
+ else
+ flushnormalpath(path,open)
+ end
+ if objecttype == "fill" then
+ pdf_literalcode("h f")
+ elseif objecttype == "outline" then
+ pdf_literalcode((open and "S") or "h S")
+ elseif objecttype == "both" then
+ pdf_literalcode("h B")
+ end
+ end
+ if transformed then
+ pdf_literalcode("Q")
+ end
+ local path = object.htap
+ if path then
+ if transformed then
+ pdf_literalcode("q")
+ end
+ if transformed then
+ flushconcatpath(path,open)
+ else
+ flushnormalpath(path,open)
+ end
+ if objecttype == "fill" then
+ pdf_literalcode("h f")
+ elseif objecttype == "outline" then
+ pdf_literalcode((open and "S") or "h S")
+ elseif objecttype == "both" then
+ pdf_literalcode("h B")
+ end
+ if transformed then
+ pdf_literalcode("Q")
+ end
+ end
+ if cr then
+ pdf_literalcode(cr)
+ end
+ end
+ end
+ end
+ pdf_literalcode("Q")
+ pdf_stopfigure()
+ end
+ end
+ end
+ end
+ end
+
+ function metapost.colorconverter(cr)
+ local n = #cr
+ if n == 4 then
+ local c, m, y, k = cr[1], cr[2], cr[3], cr[4]
+ return format("%.3f %.3f %.3f %.3f k %.3f %.3f %.3f %.3f K",c,m,y,k,c,m,y,k), "0 g 0 G"
+ elseif n == 3 then
+ local r, g, b = cr[1], cr[2], cr[3]
+ return format("%.3f %.3f %.3f rg %.3f %.3f %.3f RG",r,g,b,r,g,b), "0 g 0 G"
+ else
+ local s = cr[1]
+ return format("%.3f g %.3f G",s,s), "0 g 0 G"
+ end
+ end
+
+end
diff --git a/tex/generic/context/luatex-mplib.tex b/tex/generic/context/luatex-mplib.tex
new file mode 100644
index 000000000..206518d7d
--- /dev/null
+++ b/tex/generic/context/luatex-mplib.tex
@@ -0,0 +1,118 @@
+%D \module
+%D [ file=luatex-mplib,
+%D version=2009.12.01,
+%D title=\LUATEX\ Support Macros,
+%D subtitle=\METAPOST\ to \PDF\ conversion,
+%D author=Taco Hoekwater \& Hans Hagen,
+%D date=\currentdate,
+%D copyright=public domain]
+
+%D This is the companion to the \LUA\ module \type {supp-mpl.lua}. Further
+%D embedding is up to others. A simple example of usage in plain \TEX\ is:
+%D
+%D \starttyping
+%D \pdfoutput=1
+%D
+%D \input luatex-mplib.tex
+%D
+%D \setmplibformat{plain}
+%D
+%D \mplibcode
+%D beginfig(1);
+%D draw fullcircle
+%D scaled 10cm
+%D withcolor red
+%D withpen pencircle xscaled 4mm yscaled 2mm rotated 30 ;
+%D endfig;
+%D \endmplibcode
+%D
+%D \end
+%D \stoptyping
+
+\def\setmplibformat#1{\def\mplibformat{#1}}
+
+\def\setupmplibcatcodes
+ {\catcode`\{=12 \catcode`\}=12 \catcode`\#=12 \catcode`\^=12 \catcode`\~=12
+ \catcode`\_=12 \catcode`\%=12 \catcode`\&=12 \catcode`\$=12 }
+
+\def\mplibcode
+ {\bgroup
+ \setupmplibcatcodes
+ \domplibcode}
+
+\long\def\domplibcode#1\endmplibcode
+ {\egroup
+ \directlua{metapost.process('\mplibformat',[[#1]])}}
+
+%D We default to \type {plain} \METAPOST:
+
+\def\mplibformat{plain}
+
+%D We use a dedicated scratchbox:
+
+\ifx\mplibscratchbox\undefined \newbox\mplibscratchbox \fi
+
+%D Now load the needed \LUA\ code.
+
+\directlua{dofile(kpse.find_file('luatex-mplib.lua'))}
+
+%D The following code takes care of encapsulating the literals:
+
+\def\startMPLIBtoPDF#1#2#3#4%
+ {\hbox\bgroup
+ \xdef\MPllx{#1}\xdef\MPlly{#2}%
+ \xdef\MPurx{#3}\xdef\MPury{#4}%
+ \xdef\MPwidth{\the\dimexpr#3bp-#1bp\relax}%
+ \xdef\MPheight{\the\dimexpr#4bp-#2bp\relax}%
+ \parskip0pt%
+ \leftskip0pt%
+ \parindent0pt%
+ \everypar{}%
+ \setbox\mplibscratchbox\vbox\bgroup
+ \noindent}
+
+\def\stopMPLIBtoPDF
+ {\egroup
+ \setbox\mplibscratchbox\hbox
+ {\hskip-\MPllx bp%
+ \raise-\MPlly bp%
+ \box\mplibscratchbox}%
+ \setbox\mplibscratchbox\vbox to \MPheight
+ {\vfill
+ \hsize\MPwidth
+ \wd\mplibscratchbox0pt%
+ \ht\mplibscratchbox0pt%
+ \dp\mplibscratchbox0pt%
+ \box\mplibscratchbox}%
+ \wd\mplibscratchbox\MPwidth
+ \ht\mplibscratchbox\MPheight
+ \box\mplibscratchbox
+ \egroup}
+
+%D The body of picture, except for text items, is taken care of by:
+
+\ifnum\pdfoutput>0
+ \let\MPLIBtoPDF\pdfliteral
+\else
+ \def\MPLIBtoPDF#1{\special{pdf:literal direct #1}} % not ok yet
+\fi
+
+%D Text items have a special handler:
+
+\def\MPLIBtextext#1#2#3#4#5%
+ {\begingroup
+ \setbox\mplibscratchbox\hbox
+ {\font\temp=#1 at #2bp%
+ \temp
+ #3}%
+ \setbox\mplibscratchbox\hbox
+ {\hskip#4 bp%
+ \raise#5 bp%
+ \box\mplibscratchbox}%
+ \wd\mplibscratchbox0pt%
+ \ht\mplibscratchbox0pt%
+ \dp\mplibscratchbox0pt%
+ \box\mplibscratchbox
+ \endgroup}
+
+\endinput
diff --git a/tex/generic/context/luatex-plain.tex b/tex/generic/context/luatex-plain.tex
new file mode 100644
index 000000000..ae2588327
--- /dev/null
+++ b/tex/generic/context/luatex-plain.tex
@@ -0,0 +1,25 @@
+%D \module
+%D [ file=luatex-basics,
+%D version=2009.12.01,
+%D title=\LUATEX\ Support Macros,
+%D subtitle=Attribute Allocation,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=public domain]
+
+\input plain
+
+\directlua {tex.enableprimitives('', tex.extraprimitives())}
+
+\pdfoutput=1
+
+\everyjob \expandafter {%
+ \the\everyjob
+ \input luatex-basics\relax
+ \input luatex-fonts\relax
+ \input luatex-mplib\relax
+}
+
+\edef\fmtversion{\fmtversion+luatex}
+
+\dump
diff --git a/tex/generic/context/luatex-test.tex b/tex/generic/context/luatex-test.tex
new file mode 100644
index 000000000..1c423ec5b
--- /dev/null
+++ b/tex/generic/context/luatex-test.tex
@@ -0,0 +1,47 @@
+%D \module
+%D [ file=luatex-test,
+%D version=2009.12.01,
+%D title=\LUATEX\ Support Macros,
+%D subtitle=Simple Test File,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright=public domain]
+
+%D See \type {luatex-plain.tex} (or on my machine \type {luatex.tex}
+%D for how to make a format.
+
+\pdfoutput=1
+
+\font\testa=file:lmroman10-regular at 12pt \testa \input tufte \par
+\font\testb=file:lmroman12-regular:+liga; at 24pt \testb effe flink fietsen \par
+\font\testc=file:lmroman12-regular:mode=node;+liga; at 24pt \testc effe flink fietsen \par
+\font\testd=name:lmroman10bold at 12pt \testd a bit bold \par
+
+\font\oeps=[lmroman12-regular]:+liga at 30pt \oeps crap
+\font\oeps=[lmroman12-regular] at 40pt \oeps more crap
+
+\font\oeps=cmr10
+
+\font\testx=ptmr8t \testx abc
+
+\font\cidtest=adobesongstd-light
+
+\font\mathtest=cambria(math) {\mathtest 123}
+
+% \font\testy=file:IranNastaliq.ttf:mode=node;script=arab;language=dflt;+calt;+ccmp;+init;+isol;+medi;+fina;+liga;+rlig;+kern;+mark;+mkmk at 14pt
+% \testy این یک متن نمونه است با قلم ذر که درست آمده است.
+% \font\testz=name:linlibertineo \testz
+
+\setmplibformat{plain}
+
+\mplibcode
+ beginfig(1) ;
+ draw fullcircle
+ scaled 10cm
+ withcolor red
+ withpen pencircle xscaled 4mm yscaled 2mm rotated 30 ;
+ endfig ;
+\endmplibcode
+
+\end
+
diff --git a/tex/generic/context/ppchtex.noc b/tex/generic/context/ppchtex.noc
index 3ab92d8f3..8819de024 100644
--- a/tex/generic/context/ppchtex.noc
+++ b/tex/generic/context/ppchtex.noc
@@ -32,7 +32,7 @@
\input supp-mis.tex \let\writestatus\undefined
\input syst-gen.tex
-\input syst-fnt.tex
+\input syst-fnt.mkii
%D after which we can go on with:
@@ -174,7 +174,7 @@
%D After those definitions we actually load \PPCHTEX:
-\input ppchtex.tex
+\input ppchtex.mkii
%D We also change some setup values. Let's hope that the next
%D setups forever suits \LATEX.
diff --git a/tpm/t-bib.tpm b/tpm/t-bib.tpm
index f8e0bec08..9f426e53e 100644
--- a/tpm/t-bib.tpm
+++ b/tpm/t-bib.tpm
@@ -11,9 +11,9 @@
A bibliographic subsystem for ConTeXt
</TPM:Description>
<TPM:Author>Taco Hoekwater</TPM:Author>
- <TPM:Size>566841</TPM:Size>
+ <TPM:Size>575117</TPM:Size>
<TPM:Build/>
- <TPM:RunFiles size="253818">
+ <TPM:RunFiles size="258315">
tex/context/bib/bibl-ams.tex
tex/context/bib/bibl-apa-de.tex
tex/context/bib/bibl-apa-fr.tex
@@ -23,6 +23,8 @@ tex/context/bib/bibl-num-fr.tex
tex/context/bib/bibl-num.tex
tex/context/bib/bibl-ssa.tex
tex/context/bib/t-bib.tex
+tex/context/bib/t-bib.mkii
+tex/context/bib/t-bib.mkiv
tex/context/bib/t-bibltx.tex
tex/context/interface/t-bib.xml
bibtex/bst/context/cont-ab.bst
@@ -31,7 +33,7 @@ bibtex/bst/context/cont-no.bst
bibtex/bst/context/cont-ti.bst
tpm/t-bib.tpm
</TPM:RunFiles>
- <TPM:DocFiles size="313023">
+ <TPM:DocFiles size="316802">
doc/context/bib/bibmod-doc.pdf
doc/context/bib/bibmod-doc.tex
</TPM:DocFiles>
diff --git a/web2c/context.cnf b/web2c/context.cnf
index 6cb8ca806..13c385ba4 100644
--- a/web2c/context.cnf
+++ b/web2c/context.cnf
@@ -47,39 +47,42 @@ OSFONTDIR =
TEXPSHEADERS = .;$TEXMF/{fonts/{enc,map,type1,truetype},dvips,pdftex,tex}//;$TEXMF/{etex,tex,pdftex,dvips,fonts/type1}//
-TEXFONTMAPS.dvipdfm = .;$TEXMF/fonts/map/{dvipdfm,dvips,}//
-TEXFONTMAPS.dvipdfmx = .;$TEXMF/fonts/map/{dvipdfm,pdftex,dvips,}//
-TEXFONTMAPS.pdftex = .;$TEXMF/fonts/map/{pdftex,dvips,}//
-TEXFONTMAPS.pdfetex = .;$TEXMF/fonts/map/{pdftex,dvips,}//
-TEXFONTMAPS.luatex = .;$TEXMF/fonts/map/{pdftex,dvips,}//
-TEXFONTMAPS.xetex = .;$TEXMF/fonts/map/{xetex,pdftex,dvips,}//
-TEXFONTMAPS.dvips = .;$TEXMF/fonts/map/{dvips,pdftex,}//
+TEXFONTMAPS.dvipdfm = .;$TEXMF/fonts/{data,map}/{dvipdfm,dvips,}//
+TEXFONTMAPS.dvipdfmx = .;$TEXMF/fonts/{data,map}/{dvipdfm,pdftex,dvips,}//
+TEXFONTMAPS.pdftex = .;$TEXMF/fonts/{data,map}/{pdftex,dvips,}//
+TEXFONTMAPS.pdfetex = .;$TEXMF/fonts/{data,map}/{pdftex,dvips,}//
+TEXFONTMAPS.luatex = .;$TEXMF/fonts/{data,map}/{pdftex,dvips,}//
+TEXFONTMAPS.xetex = .;$TEXMF/fonts/{data,map}/{xetex,pdftex,dvips,}//
+TEXFONTMAPS.dvips = .;$TEXMF/fonts/{data,map}/{dvips,pdftex,}//
# TEXFONTMAPS = .;$TEXMF/fonts/map/{$backend,pdftex,dvips,}//;$TEXMF/{$progname,pdftex,dvips}/{config,}//
-TEXFONTMAPS = .;$TEXMF/fonts/map/{$progname,$engine,pdftex,dvips,}//;$TEXMF/{$progname,$engine,pdftex,dvips}/{config,}//
-
-VFFONTS = .;$TEXMF/fonts/vf//
-TFMFONTS = .;$TEXMF/fonts/tfm//
-T1FONTS = .;$TEXMF/fonts/{data,type1,pfb}//;$TEXMF/fonts/misc/hbf//;$OSFONTDIR;
-AFMFONTS = .;$TEXMF/fonts/{data,afm}//;$OSFONTDIR;
-LIGFONTS = .;$TEXMF/fonts/lig//
-TTFONTS = .;$TEXMF/fonts/{data,truetype,ttf}//;$OSFONTDIR;
-TTF2TFMINPUTS = .;$TEXMF/ttf2pk//
-T42FONTS = .;$TEXMF/fonts/type42//
-MISCFONTS = .;$TEXMF/fonts/misc//
-% ENCFONTS = .;$TEXMF/fonts/enc//
-ENCFONTS = .;$TEXMF/{fonts/{data,enc},dvips,pdftex,dvipdfm}//
-CMAPFONTS = .;$TEXMF/fonts/cmap//
-SFDFONTS = .;$TEXMF/fonts/sfd//
-OPENTYPEFONTS = .;$TEXMF/fonts/{data,opentype}//;$OSFONTDIR
-
-OFMFONTS = .;$TEXMF/fonts/{ofm,tfm}//
-OPLFONTS = .;$TEXMF/fonts/opl//;
-OVFFONTS = .;$TEXMF/fonts/{ovf,vf}//
-OVPFONTS = .;$TEXMF/fonts/ovp//;
-OTPINPUTS = .;$TEXMF/omega/otp//
-OCPINPUTS = .;$TEXMF/omega/ocp//
-OTFFONTS = .;$TEXMF/fonts/otf/{xetex,}//;
+TEXFONTMAPS = .;$TEXMF/fonts/{data,map}/{$progname,$engine,pdftex,dvips,}//;$TEXMF/{$progname,$engine,pdftex,dvips}/{config,}//
+
+VFFONTS = $TEXMF/fonts/{data,vf}//
+TFMFONTS = $TEXMF/fonts/{data,tfm}//
+T1FONTS = $TEXMF/fonts/{data,type1,pfb}//;$TEXMF/fonts/misc/hbf//;$OSFONTDIR;
+AFMFONTS = $TEXMF/fonts/{data,afm}//;$OSFONTDIR;
+LIGFONTS = $TEXMF/fonts/lig//
+TTFONTS = $TEXMF/fonts/{data,truetype,ttf}//;$OSFONTDIR;
+TTF2TFMINPUTS = $TEXMF/ttf2pk//
+T42FONTS = $TEXMF/fonts/type42//
+MISCFONTS = $TEXMF/fonts/misc//
+% ENCFONTS = $TEXMF/fonts/enc//
+ENCFONTS = $TEXMF/{fonts/{data,enc},dvips,pdftex,dvipdfm}//
+CMAPFONTS = $TEXMF/fonts/cmap//
+SFDFONTS = $TEXMF/fonts/sfd//
+OPENTYPEFONTS = $TEXMF/fonts/{data,opentype}//;$OSFONTDIR
+
+FONTFEATURES = $TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS
+FONTCIDMAPS = $TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS
+
+OFMFONTS = $TEXMF/fonts/{data,ofm,tfm}//
+OPLFONTS = $TEXMF/fonts/opl//;
+OVFFONTS = $TEXMF/fonts/{data,ovf,vf}//
+OVPFONTS = $TEXMF/fonts/ovp//;
+OTPINPUTS = $TEXMF/omega/otp//
+OCPINPUTS = $TEXMF/omega/ocp//
+OTFFONTS = $TEXMF/fonts/otf/{data,xetex,}//;$OSFONTDIR
% configurations
@@ -107,9 +110,9 @@ MPINPUTS = .;{$MFRESOURCES}//;{$CTXDEVMPPATH};$TEXMF/metapost/{context,
MFINPUTS = .;{$MPRESOURCES}//;{$CTXDEVMFPATH};$TEXMF/metafont/{context,base,}//;$TEXMF/fonts/source//
BSTINPUTS = .;{$TXRESOURCES}//;{$CTXDEVTXPATH};$TEXMF/bibtex/bst//
-TEXCONFIG = .;$TEXMF/{fonts/map,dvips,pdftex,dvipdfmx,dvipdfm}//
-PDFTEXCONFIG = .;$TEXMF/pdftex/{$progname,}//
-DVIPDFMINPUTS = .;$TEXMF/{fonts/{map,enc,lig}/dvipdfm,fonts/type1,dvips,pdftex,dvipdfmx,dvipdfm}//
+TEXCONFIG = $TEXMF/{fonts/map,dvips,pdftex,dvipdfmx,dvipdfm}//
+PDFTEXCONFIG = $TEXMF/pdftex/{$progname,}//
+DVIPDFMINPUTS = $TEXMF/{fonts/{map,enc,lig}/dvipdfm,fonts/type1,dvips,pdftex,dvipdfmx,dvipdfm}//
% this way we can hook in development paths
@@ -145,6 +148,9 @@ openin_any = a
parse_first_line = f
allow_multiple_suffixes = f
+shell_escape.context = t
+shell_escape_commands.context = mtxrun,luatools,texmfstart,texexec,mpost
+
% auto generation
MKTEXTEX = 0
@@ -233,18 +239,23 @@ mpost_buf_size = 30000
max_print_line.pdftex = 255
max_print_line.luatex = 255
+max_print_line.xetex = 255
max_print_line.mpost = 255
max_print_line.metafun = 255
extra_mem_top.mptopdf = 1000000
extra_mem_bot.mptopdf = 1000000
-ocp_buf_size = 500000
-ocp_stack_size = 10000
-ocp_list_size = 1000
+% ocp_buf_size = 500000
+% ocp_stack_size = 10000
+% ocp_list_size = 1000
+
+ocp_buf_size = 1
+ocp_stack_size = 1
+ocp_list_size = 1
% Just for xetex:
FONTCONFIG_FILE = fonts.conf
FONTCONFIG_PATH = $TEXMFLOCAL/fonts/conf
-FC_CACHEDIR = $TMP/fonts/cache
+FC_CACHEDIR = $TEXMFLOCAL/fonts/cache